Separating integration-devel from devel package for 2nd party to use adaptor #2 ...
[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 boost::thread(boost::bind(&RenderThread::Run, this));
123
124   mSurface->StartRender();
125 }
126
127 void RenderThread::Stop()
128 {
129   DALI_LOG_INFO( gRenderLogFilter, Debug::Verbose, "RenderThread::Stop()\n");
130
131   // shutdown the render thread and destroy the opengl context
132   if( mThread )
133   {
134     // Tell surface we have stopped rendering
135     mSurface->StopRender();
136
137     // wait for the thread to finish
138     mThread->join();
139
140     delete mThread;
141     mThread = NULL;
142   }
143 }
144
145 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
146 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
147 // The following methods are all executed inside render thread !!!
148 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
149 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
150
151 bool RenderThread::Run()
152 {
153   // install a function for logging
154   mEnvironmentOptions.InstallLogFunction();
155
156   InitializeEgl();
157
158   bool running( true );
159
160   Dali::Integration::RenderStatus renderStatus;
161
162   uint64_t currentTime( 0 );
163
164   // render loop, we stay inside here when rendering
165   while( running )
166   {
167     // Sync with update thread and get any outstanding requests from UpdateRenderSynchronization
168     DALI_LOG_INFO( gRenderLogFilter, Debug::Verbose, "RenderThread::Run. 1 - RenderSyncWithUpdate()\n");
169     RenderRequest* request = NULL;
170     running = mUpdateRenderSync.RenderSyncWithUpdate( request );
171
172     DALI_LOG_INFO( gRenderLogFilter, Debug::Verbose, "RenderThread::Run. 2 - Process requests\n");
173
174     // Consume any pending events to avoid memory leaks
175     mDisplayConnection->ConsumeEvents();
176
177     bool processRequests = true;
178     bool requestProcessed = false;
179     while( processRequests && running)
180     {
181       // Check if we've got any requests from the main thread (e.g. replace surface)
182       requestProcessed = ProcessRequest( request );
183
184       // perform any pre-render operations
185       DALI_LOG_INFO( gRenderLogFilter, Debug::Verbose, "RenderThread::Run. 3 - PreRender\n");
186       bool preRendered = PreRender(); // Returns false if no surface onto which to render
187       if( preRendered )
188       {
189         processRequests = false;
190       }
191       else
192       {
193         // Block until new surface... - cleared by ReplaceSurface code in UpdateRenderController
194         running = mUpdateRenderSync.RenderSyncWithRequest(request);
195       }
196     }
197
198     if( running )
199     {
200        // Render
201       DALI_LOG_INFO( gRenderLogFilter, Debug::Verbose, "RenderThread::Run. 4 - Core.Render()\n");
202       mCore.Render( renderStatus );
203
204       // Notify the update-thread that a render has completed
205       DALI_LOG_INFO( gRenderLogFilter, Debug::Verbose, "RenderThread::Run. 5 - Sync.RenderFinished()\n");
206       mUpdateRenderSync.RenderFinished( renderStatus.NeedsUpdate(), requestProcessed );
207
208       uint64_t newTime( mUpdateRenderSync.GetTimeMicroseconds() );
209
210       // perform any post-render operations
211       if ( renderStatus.HasRendered() )
212       {
213         DALI_LOG_INFO( gRenderLogFilter, Debug::Verbose, "RenderThread::Run. 6 - PostRender()\n");
214         PostRender( static_cast< unsigned int >(newTime - currentTime) );
215       }
216
217       currentTime = newTime;
218     }
219   }
220
221   // shut down egl
222   ShutdownEgl();
223
224   // install a function for logging
225   mEnvironmentOptions.UnInstallLogFunction();
226
227   return true;
228 }
229
230 void RenderThread::InitializeEgl()
231 {
232   mEGL = mEglFactory->Create();
233
234   DALI_ASSERT_ALWAYS( mSurface && "NULL surface" );
235
236   // initialize egl & OpenGL
237   mDisplayConnection->InitializeEgl( *mEGL );
238   mSurface->InitializeEgl( *mEGL );
239
240   // create the OpenGL context
241   mEGL->CreateContext();
242
243   // create the OpenGL surface
244   mSurface->CreateEglSurface(*mEGL);
245
246   // Make it current
247   mEGL->MakeContextCurrent();
248
249   // set the initial sync mode
250
251   // tell core it has a context
252   mCore.ContextCreated();
253
254 }
255
256 bool RenderThread::ProcessRequest( RenderRequest* request )
257 {
258   bool processedRequest = false;
259
260   if( request != NULL )
261   {
262     switch(request->GetType())
263     {
264       case RenderRequest::REPLACE_SURFACE:
265       {
266         // change the surface
267         ReplaceSurfaceRequest* replaceSurfaceRequest = static_cast<ReplaceSurfaceRequest*>(request);
268         ReplaceSurface( replaceSurfaceRequest->GetSurface() );
269         replaceSurfaceRequest->ReplaceCompleted();
270         processedRequest = true;
271         break;
272       }
273     }
274   }
275   return processedRequest;
276 }
277
278 void RenderThread::ReplaceSurface( RenderSurface* newSurface )
279 {
280   // This is designed for replacing pixmap surfaces, but should work for window as well
281   // we need to delete the egl surface and renderable (pixmap / window)
282   // Then create a new pixmap/window and new egl surface
283   // If the new surface has a different display connection, then the context will be lost
284   DALI_ASSERT_ALWAYS(newSurface && "NULL surface");
285
286   mDisplayConnection->InitializeEgl(*mEGL);
287
288   bool contextLost = newSurface->ReplaceEGLSurface(*mEGL);
289   if( contextLost )
290   {
291     DALI_LOG_WARNING("Context lost\n");
292     mCore.ContextDestroyed();
293     mCore.ContextCreated();
294   }
295
296   // use the new surface from now on
297   mSurface = newSurface;
298   mSurfaceReplaced = true;
299 }
300
301
302 void RenderThread::ShutdownEgl()
303 {
304   // inform core of context destruction
305   mCore.ContextDestroyed();
306
307   // give a chance to destroy the OpenGL surface that created externally
308   mSurface->DestroyEglSurface( *mEGL );
309
310   // delete the GL context / egl surface
311   mEGL->TerminateGles();
312 }
313
314 bool RenderThread::PreRender()
315 {
316   bool success = mSurface->PreRender( *mEGL, mGLES );
317   if( success )
318   {
319     mGLES.PreRender();
320   }
321   return success;
322 }
323
324 void RenderThread::PostRender( unsigned int timeDelta )
325 {
326   // Inform the gl implementation that rendering has finished before informing the surface
327   mGLES.PostRender(timeDelta);
328
329   // Inform the surface that rendering this frame has finished.
330   mSurface->PostRender( *mEGL, mGLES, mDisplayConnection, timeDelta, mSurfaceReplaced );
331   mSurfaceReplaced = false;
332 }
333
334
335 } // namespace Adaptor
336
337 } // namespace Internal
338
339 } // namespace Dali