Merge remote-tracking branch 'origin/tizen' into new_text
[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
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
47 RenderRequest::RenderRequest(RenderRequest::Request type)
48 : mRequestType(type)
49 {
50 }
51
52 RenderRequest::Request RenderRequest::GetType()
53 {
54   return mRequestType;
55 }
56
57 ReplaceSurfaceRequest::ReplaceSurfaceRequest()
58 : RenderRequest(RenderRequest::REPLACE_SURFACE),
59   mNewSurface( NULL ),
60   mReplaceCompleted(false)
61 {
62 }
63
64 void ReplaceSurfaceRequest::SetSurface(RenderSurface* newSurface)
65 {
66   mNewSurface = newSurface;
67 }
68
69 RenderSurface* ReplaceSurfaceRequest::GetSurface()
70 {
71   return mNewSurface;
72 }
73
74 void ReplaceSurfaceRequest::ReplaceCompleted()
75 {
76   mReplaceCompleted = true;
77 }
78
79 bool ReplaceSurfaceRequest::GetReplaceCompleted()
80 {
81   return mReplaceCompleted != 0u;
82 }
83
84
85 RenderThread::RenderThread( UpdateRenderSynchronization& sync,
86                             AdaptorInternalServices& adaptorInterfaces,
87                             const EnvironmentOptions& environmentOptions )
88 : mUpdateRenderSync( sync ),
89   mCore( adaptorInterfaces.GetCore() ),
90   mGLES( adaptorInterfaces.GetGlesInterface() ),
91   mEglFactory( &adaptorInterfaces.GetEGLFactoryInterface()),
92   mEGL( NULL ),
93   mThread( NULL ),
94   mEnvironmentOptions( environmentOptions ),
95   mSurfaceReplaced(false)
96 {
97   // set the initial values before render thread starts
98   mSurface = adaptorInterfaces.GetRenderSurfaceInterface();
99 }
100
101 RenderThread::~RenderThread()
102 {
103   DALI_ASSERT_ALWAYS( mThread == NULL && "RenderThread is still alive");
104   mEglFactory->Destroy();
105 }
106
107 void RenderThread::Start()
108 {
109   DALI_LOG_INFO( gRenderLogFilter, Debug::Verbose, "RenderThread::Start()\n");
110
111   // initialise GL and kick off render thread
112   DALI_ASSERT_ALWAYS( !mEGL && "Egl already initialized" );
113
114   // create the render thread, initially we are rendering
115   mThread = new boost::thread(boost::bind(&RenderThread::Run, this));
116
117   mSurface->StartRender();
118 }
119
120 void RenderThread::Stop()
121 {
122   DALI_LOG_INFO( gRenderLogFilter, Debug::Verbose, "RenderThread::Stop()\n");
123
124   // shutdown the render thread and destroy the opengl context
125   if( mThread )
126   {
127     // Tell surface we have stopped rendering
128     mSurface->StopRender();
129
130     // wait for the thread to finish
131     mThread->join();
132
133     delete mThread;
134     mThread = NULL;
135   }
136 }
137
138 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
139 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
140 // The following methods are all executed inside render thread !!!
141 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
142 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
143
144 bool RenderThread::Run()
145 {
146   // install a function for logging
147   mEnvironmentOptions.InstallLogFunction();
148
149   InitializeEgl();
150
151   bool running( true );
152
153   Dali::Integration::RenderStatus renderStatus;
154
155   uint64_t currentTime( 0 );
156
157   // render loop, we stay inside here when rendering
158   while( running )
159   {
160     // Sync with update thread and get any outstanding requests from UpdateRenderSynchronization
161     DALI_LOG_INFO( gRenderLogFilter, Debug::Verbose, "RenderThread::Run. 1 - RenderSyncWithUpdate()\n");
162     RenderRequest* request = NULL;
163     running = mUpdateRenderSync.RenderSyncWithUpdate( request );
164
165     DALI_LOG_INFO( gRenderLogFilter, Debug::Verbose, "RenderThread::Run. 2 - Process requests\n");
166
167     // Consume any pending events
168     ConsumeEvents();
169
170     bool processRequests = true;
171     bool requestProcessed = false;
172     while( processRequests && running)
173     {
174       // Check if we've got any requests from the main thread (e.g. replace surface)
175       requestProcessed = ProcessRequest( request );
176
177       // perform any pre-render operations
178       DALI_LOG_INFO( gRenderLogFilter, Debug::Verbose, "RenderThread::Run. 3 - PreRender\n");
179       bool preRendered = PreRender(); // Returns false if no surface onto which to render
180       if( preRendered )
181       {
182         processRequests = false;
183       }
184       else
185       {
186         // Block until new surface... - cleared by ReplaceSurface code in UpdateRenderController
187         running = mUpdateRenderSync.RenderSyncWithRequest(request);
188       }
189     }
190
191     if( running )
192     {
193        // Render
194       DALI_LOG_INFO( gRenderLogFilter, Debug::Verbose, "RenderThread::Run. 4 - Core.Render()\n");
195       mCore.Render( renderStatus );
196
197       // Notify the update-thread that a render has completed
198       DALI_LOG_INFO( gRenderLogFilter, Debug::Verbose, "RenderThread::Run. 5 - Sync.RenderFinished()\n");
199       mUpdateRenderSync.RenderFinished( renderStatus.NeedsUpdate(), requestProcessed );
200
201       uint64_t newTime( mUpdateRenderSync.GetTimeMicroseconds() );
202
203       // perform any post-render operations
204       if ( renderStatus.HasRendered() )
205       {
206         DALI_LOG_INFO( gRenderLogFilter, Debug::Verbose, "RenderThread::Run. 6 - PostRender()\n");
207         PostRender( static_cast< unsigned int >(newTime - currentTime) );
208       }
209
210       currentTime = newTime;
211     }
212   }
213
214   // shut down egl
215   ShutdownEgl();
216
217   // install a function for logging
218   mEnvironmentOptions.UnInstallLogFunction();
219
220   return true;
221 }
222
223 void RenderThread::InitializeEgl()
224 {
225   mEGL = mEglFactory->Create();
226
227   DALI_ASSERT_ALWAYS( mSurface && "NULL surface" );
228
229   // initialize egl & OpenGL
230   mSurface->InitializeEgl( *mEGL );
231
232   // create the OpenGL context
233   mEGL->CreateContext();
234
235   // create the OpenGL surface
236   mSurface->CreateEglSurface( *mEGL );
237
238   // Make it current
239   mEGL->MakeContextCurrent();
240
241   // set the initial sync mode
242
243
244   // tell core it has a context
245   mCore.ContextCreated();
246
247 }
248
249 void RenderThread::ConsumeEvents()
250 {
251   // tell surface to consume any events to avoid memory leaks
252   mSurface->ConsumeEvents();
253 }
254
255 bool RenderThread::ProcessRequest( RenderRequest* request )
256 {
257   bool processedRequest = false;
258
259   if( request != NULL )
260   {
261     switch(request->GetType())
262     {
263       case RenderRequest::REPLACE_SURFACE:
264       {
265         // change the surface
266         ReplaceSurfaceRequest* replaceSurfaceRequest = static_cast<ReplaceSurfaceRequest*>(request);
267         ReplaceSurface( replaceSurfaceRequest->GetSurface() );
268         replaceSurfaceRequest->ReplaceCompleted();
269         processedRequest = true;
270         break;
271       }
272     }
273   }
274   return processedRequest;
275 }
276
277 void RenderThread::ReplaceSurface( RenderSurface* newSurface )
278 {
279   // This is designed for replacing pixmap surfaces, but should work for window as well
280   // we need to delete the egl surface and renderable (pixmap / window)
281   // Then create a new pixmap/window and new egl surface
282   // If the new surface has a different display connection, then the context will be lost
283   DALI_ASSERT_ALWAYS( newSurface && "NULL surface" );
284
285   bool contextLost = newSurface->ReplaceEGLSurface( *mEGL );
286
287   if( contextLost )
288   {
289     DALI_LOG_WARNING("Context lost\n");
290     mCore.ContextDestroyed();
291     mCore.ContextCreated();
292   }
293
294   // if both new and old surface are using the same display, and the display
295   // connection was created by Dali, then transfer
296   // display owner ship to the new surface.
297   mSurface->TransferDisplayOwner( *newSurface );
298
299   // use the new surface from now on
300   mSurface = newSurface;
301   mSurfaceReplaced = true;
302 }
303
304
305 void RenderThread::ShutdownEgl()
306 {
307   // inform core of context destruction
308   mCore.ContextDestroyed();
309
310   // give a chance to destroy the OpenGL surface that created externally
311   mSurface->DestroyEglSurface( *mEGL );
312
313   // delete the GL context / egl surface
314   mEGL->TerminateGles();
315 }
316
317 bool RenderThread::PreRender()
318 {
319   bool success = mSurface->PreRender( *mEGL, mGLES );
320   if( success )
321   {
322     mGLES.PreRender();
323   }
324   return success;
325 }
326
327 void RenderThread::PostRender( unsigned int timeDelta )
328 {
329   // Inform the gl implementation that rendering has finished before informing the surface
330   mGLES.PostRender(timeDelta);
331
332   // Inform the surface that rendering this frame has finished.
333   mSurface->PostRender( *mEGL, mGLES, timeDelta, mSurfaceReplaced );
334   mSurfaceReplaced = false;
335 }
336
337
338 } // namespace Adaptor
339
340 } // namespace Internal
341
342 } // namespace Dali