Remove de-funct Bullet dynamics plugin
[platform/core/uifw/dali-adaptor.git] / adaptors / base / render-thread.cpp
1 /*
2  * Copyright (c) 2014 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  */
17
18 // CLASS HEADER
19 #include "render-thread.h"
20
21 // EXTERNAL INCLUDES
22 #include <dali/integration-api/debug.h>
23
24 // INTERNAL INCLUDES
25 #include <base/interfaces/adaptor-internal-services.h>
26 #include <base/update-render-synchronization.h>
27 #include <base/environment-options.h>
28 #include <base/display-connection.h>
29
30 namespace Dali
31 {
32
33 namespace Internal
34 {
35
36 namespace Adaptor
37 {
38
39 namespace
40 {
41 #if defined(DEBUG_ENABLED)
42 Integration::Log::Filter* gRenderLogFilter = Integration::Log::Filter::New(Debug::NoLogging, false, "LOG_RENDER_THREAD");
43 #endif
44 }
45
46 RenderRequest::RenderRequest(RenderRequest::Request type)
47 : mRequestType(type)
48 {
49 }
50
51 RenderRequest::Request RenderRequest::GetType()
52 {
53   return mRequestType;
54 }
55
56 ReplaceSurfaceRequest::ReplaceSurfaceRequest()
57 : RenderRequest(RenderRequest::REPLACE_SURFACE),
58   mNewSurface( NULL ),
59   mReplaceCompleted(false)
60 {
61 }
62
63 void ReplaceSurfaceRequest::SetSurface(RenderSurface* newSurface)
64 {
65   mNewSurface = newSurface;
66 }
67
68 RenderSurface* ReplaceSurfaceRequest::GetSurface()
69 {
70   return mNewSurface;
71 }
72
73 void ReplaceSurfaceRequest::ReplaceCompleted()
74 {
75   mReplaceCompleted = true;
76 }
77
78 bool ReplaceSurfaceRequest::GetReplaceCompleted()
79 {
80   return mReplaceCompleted != 0u;
81 }
82
83
84 RenderThread::RenderThread( UpdateRenderSynchronization& sync,
85                             AdaptorInternalServices& adaptorInterfaces,
86                             const EnvironmentOptions& environmentOptions )
87 : mUpdateRenderSync( sync ),
88   mCore( adaptorInterfaces.GetCore() ),
89   mGLES( adaptorInterfaces.GetGlesInterface() ),
90   mEglFactory( &adaptorInterfaces.GetEGLFactoryInterface()),
91   mEGL( NULL ),
92   mThread( NULL ),
93   mEnvironmentOptions( environmentOptions ),
94   mSurfaceReplaced(false)
95 {
96   // set the initial values before render thread starts
97   mSurface = adaptorInterfaces.GetRenderSurfaceInterface();
98
99   mDisplayConnection = Dali::DisplayConnection::New();
100 }
101
102 RenderThread::~RenderThread()
103 {
104   if (mDisplayConnection)
105   {
106     delete mDisplayConnection;
107     mDisplayConnection = NULL;
108   }
109
110   DALI_ASSERT_ALWAYS( mThread == NULL && "RenderThread is still alive");
111   mEglFactory->Destroy();
112 }
113
114 void RenderThread::Start()
115 {
116   DALI_LOG_INFO( gRenderLogFilter, Debug::Verbose, "RenderThread::Start()\n");
117
118   // initialise GL and kick off render thread
119   DALI_ASSERT_ALWAYS( !mEGL && "Egl already initialized" );
120
121   // create the render thread, initially we are rendering
122   mThread = new pthread_t();
123   int error = pthread_create( mThread, NULL, InternalThreadEntryFunc, this );
124   DALI_ASSERT_ALWAYS( !error && "Return code from pthread_create() in RenderThread" );
125
126   mSurface->StartRender();
127 }
128
129 void RenderThread::Stop()
130 {
131   DALI_LOG_INFO( gRenderLogFilter, Debug::Verbose, "RenderThread::Stop()\n");
132
133   // shutdown the render thread and destroy the opengl context
134   if( mThread )
135   {
136     // Tell surface we have stopped rendering
137     mSurface->StopRender();
138
139     // wait for the thread to finish
140     pthread_join(*mThread, NULL);
141
142     delete mThread;
143     mThread = NULL;
144   }
145 }
146
147 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
148 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
149 // The following methods are all executed inside render thread !!!
150 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
151 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
152
153 bool RenderThread::Run()
154 {
155   // install a function for logging
156   mEnvironmentOptions.InstallLogFunction();
157
158   InitializeEgl();
159
160   bool running( true );
161
162   Dali::Integration::RenderStatus renderStatus;
163
164   uint64_t currentTime( 0 );
165
166   // render loop, we stay inside here when rendering
167   while( running )
168   {
169     // Sync with update thread and get any outstanding requests from UpdateRenderSynchronization
170     DALI_LOG_INFO( gRenderLogFilter, Debug::Verbose, "RenderThread::Run. 1 - RenderSyncWithUpdate()\n");
171     RenderRequest* request = NULL;
172     running = mUpdateRenderSync.RenderSyncWithUpdate( request );
173
174     DALI_LOG_INFO( gRenderLogFilter, Debug::Verbose, "RenderThread::Run. 2 - Process requests\n");
175
176     // Consume any pending events to avoid memory leaks
177     mDisplayConnection->ConsumeEvents();
178
179     bool processRequests = true;
180     bool requestProcessed = false;
181     while( processRequests && running)
182     {
183       // Check if we've got any requests from the main thread (e.g. replace surface)
184       requestProcessed = ProcessRequest( request );
185
186       // perform any pre-render operations
187       DALI_LOG_INFO( gRenderLogFilter, Debug::Verbose, "RenderThread::Run. 3 - PreRender\n");
188       bool preRendered = PreRender(); // Returns false if no surface onto which to render
189       if( preRendered )
190       {
191         processRequests = false;
192       }
193       else
194       {
195         // Block until new surface... - cleared by ReplaceSurface code in UpdateRenderController
196         running = mUpdateRenderSync.RenderSyncWithRequest(request);
197       }
198     }
199
200     if( running )
201     {
202        // Render
203       DALI_LOG_INFO( gRenderLogFilter, Debug::Verbose, "RenderThread::Run. 4 - Core.Render()\n");
204       mCore.Render( renderStatus );
205
206       // Notify the update-thread that a render has completed
207       DALI_LOG_INFO( gRenderLogFilter, Debug::Verbose, "RenderThread::Run. 5 - Sync.RenderFinished()\n");
208       mUpdateRenderSync.RenderFinished( renderStatus.NeedsUpdate(), requestProcessed );
209
210       uint64_t newTime( mUpdateRenderSync.GetTimeMicroseconds() );
211
212       // perform any post-render operations
213       if ( renderStatus.HasRendered() )
214       {
215         DALI_LOG_INFO( gRenderLogFilter, Debug::Verbose, "RenderThread::Run. 6 - PostRender()\n");
216         PostRender( static_cast< unsigned int >(newTime - currentTime) );
217       }
218
219       currentTime = newTime;
220     }
221   }
222
223   // shut down egl
224   ShutdownEgl();
225
226   // install a function for logging
227   mEnvironmentOptions.UnInstallLogFunction();
228
229   return true;
230 }
231
232 void RenderThread::InitializeEgl()
233 {
234   mEGL = mEglFactory->Create();
235
236   DALI_ASSERT_ALWAYS( mSurface && "NULL surface" );
237
238   // initialize egl & OpenGL
239   mDisplayConnection->InitializeEgl( *mEGL );
240   mSurface->InitializeEgl( *mEGL );
241
242   // create the OpenGL context
243   mEGL->CreateContext();
244
245   // create the OpenGL surface
246   mSurface->CreateEglSurface(*mEGL);
247
248   // Make it current
249   mEGL->MakeContextCurrent();
250
251   // set the initial sync mode
252
253   // tell core it has a context
254   mCore.ContextCreated();
255
256 }
257
258 bool RenderThread::ProcessRequest( RenderRequest* request )
259 {
260   bool processedRequest = false;
261
262   if( request != NULL )
263   {
264     switch(request->GetType())
265     {
266       case RenderRequest::REPLACE_SURFACE:
267       {
268         // change the surface
269         ReplaceSurfaceRequest* replaceSurfaceRequest = static_cast<ReplaceSurfaceRequest*>(request);
270         ReplaceSurface( replaceSurfaceRequest->GetSurface() );
271         replaceSurfaceRequest->ReplaceCompleted();
272         processedRequest = true;
273         break;
274       }
275     }
276   }
277   return processedRequest;
278 }
279
280 void RenderThread::ReplaceSurface( RenderSurface* newSurface )
281 {
282   // This is designed for replacing pixmap surfaces, but should work for window as well
283   // we need to delete the egl surface and renderable (pixmap / window)
284   // Then create a new pixmap/window and new egl surface
285   // If the new surface has a different display connection, then the context will be lost
286   DALI_ASSERT_ALWAYS(newSurface && "NULL surface");
287
288   mDisplayConnection->InitializeEgl(*mEGL);
289
290   bool contextLost = newSurface->ReplaceEGLSurface(*mEGL);
291   if( contextLost )
292   {
293     DALI_LOG_WARNING("Context lost\n");
294     mCore.ContextDestroyed();
295     mCore.ContextCreated();
296   }
297
298   // use the new surface from now on
299   mSurface = newSurface;
300   mSurfaceReplaced = true;
301 }
302
303
304 void RenderThread::ShutdownEgl()
305 {
306   // inform core of context destruction
307   mCore.ContextDestroyed();
308
309   // give a chance to destroy the OpenGL surface that created externally
310   mSurface->DestroyEglSurface( *mEGL );
311
312   // delete the GL context / egl surface
313   mEGL->TerminateGles();
314 }
315
316 bool RenderThread::PreRender()
317 {
318   bool success = mSurface->PreRender( *mEGL, mGLES );
319   if( success )
320   {
321     mGLES.PreRender();
322   }
323   return success;
324 }
325
326 void RenderThread::PostRender( unsigned int timeDelta )
327 {
328   // Inform the gl implementation that rendering has finished before informing the surface
329   mGLES.PostRender(timeDelta);
330
331   // Inform the surface that rendering this frame has finished.
332   mSurface->PostRender( *mEGL, mGLES, mDisplayConnection, timeDelta, mSurfaceReplaced );
333   mSurfaceReplaced = false;
334 }
335
336
337 } // namespace Adaptor
338
339 } // namespace Internal
340
341 } // namespace Dali