Ensure XEvent queue for the render display is flushed
[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 Flora License, Version 1.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://floralicense.org/license/
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 // CLASS HEADER
18 #include "render-thread.h"
19
20
21 // INTERNAL INCLUDES
22 #include <dali/integration-api/debug.h>
23 #include <base/interfaces/adaptor-internal-services.h>
24 #include <base/update-render-synchronization.h>
25 #include <base/log-options.h>
26
27
28 namespace Dali
29 {
30
31 namespace Internal
32 {
33
34 namespace Adaptor
35 {
36
37 namespace
38 {
39
40 const unsigned int TIME_PER_FRAME_IN_MICROSECONDS = 16667;
41
42 } // unnamed namespace
43
44 RenderThread::RenderThread( UpdateRenderSynchronization& sync,
45                             AdaptorInternalServices& adaptorInterfaces,
46                             const LogOptions& logOptions )
47 : mUpdateRenderSync( sync ),
48   mCore( adaptorInterfaces.GetCore() ),
49   mGLES( adaptorInterfaces.GetGlesInterface() ),
50   mEglFactory( &adaptorInterfaces.GetEGLFactoryInterface()),
51   mEGL( NULL ),
52   mThread( NULL ),
53   mUsingPixmap( false ),
54   mSurfaceReplacing( false ),
55   mNewDataAvailable( false ),
56   mPixmapSyncReceived( false ),
57   mPixmapSyncRunning( false ),
58   mCurrentMicroSec(0),
59   mSurfaceReplaceCompleted( false ),
60   mLogOptions( logOptions )
61 {
62   // set the initial values before render thread starts
63   mCurrent.surface = adaptorInterfaces.GetRenderSurfaceInterface();
64
65   // set the pixmap flag, if we're using one
66   if( (mCurrent.surface->GetType() == Dali::RenderSurface::PIXMAP ) ||
67       (mCurrent.surface->GetType() == Dali::RenderSurface::NATIVE_BUFFER ) )
68   {
69     mUsingPixmap = true;
70   }
71 }
72
73 RenderThread::~RenderThread()
74 {
75   DALI_ASSERT_ALWAYS( mThread == NULL && "RenderThread is still alive");
76   mEglFactory->Destroy();
77 }
78
79 void RenderThread::Start()
80 {
81   // initialise GL and kick off render thread
82   DALI_ASSERT_ALWAYS( !mEGL && "Egl already initialized" );
83
84   // Tell core what the minimum frame interval is
85   mCore.SetMinimumFrameTimeInterval( mCurrent.syncMode * TIME_PER_FRAME_IN_MICROSECONDS );
86
87   // create the render thread, initially we are rendering
88   mThread = new boost::thread(boost::bind(&RenderThread::Run, this));
89
90   // Inform render thread to block waiting for PixmapSync
91   if( mUsingPixmap )
92   {
93     boost::unique_lock< boost::mutex > lock( mPixmapSyncMutex );
94     mPixmapSyncRunning = true;
95   }
96  }
97
98 void RenderThread::Stop()
99 {
100   // shutdown the render thread and destroy the opengl context
101   if( mThread )
102   {
103     // Inform render thread not to block waiting for PixmapSync
104     if( mUsingPixmap )
105     {
106       boost::unique_lock< boost::mutex > lock( mPixmapSyncMutex );
107       mPixmapSyncRunning = false;
108     }
109
110     mCurrent.surface->StopRender();
111
112     // need to simulate a RenderSync to get render-thread to finish
113     RenderSync();
114
115     // wait for the thread to finish
116     mThread->join();
117
118     delete mThread;
119     mThread = NULL;
120   }
121 }
122
123 void RenderThread::ReplaceSurface( RenderSurface* surface )
124 {
125   // Make sure it's a new surface. Note! we are reading the current value of render thread here, but reading is ok
126   DALI_ASSERT_ALWAYS( surface != mCurrent.surface && "Trying to replace surface with itself" );
127
128   // lock and set to false
129   {
130     boost::unique_lock<boost::mutex> lock( mSurfaceChangedMutex );
131     mSurfaceReplaceCompleted = false;
132   }
133
134   // lock cache and set update flag at the end of function
135   {
136     SendMessageGuard msg( *this );
137     // set new values to cache
138     mNewValues.replaceSurface = true;
139     mNewValues.surface = surface;
140   }
141
142   /*
143    * Reset the mPixmapFlushed condition if surface was changed.
144    * : in this case, client can not handle the previous damage because surface was changed.
145    */
146   RenderSync();
147 }
148
149 void RenderThread::WaitForSurfaceReplaceComplete()
150 {
151   boost::unique_lock<boost::mutex> lock( mSurfaceChangedMutex );
152
153   // if already completed no need to wait
154   while( !mSurfaceReplaceCompleted )
155   {
156     mSurfaceChangedNotify.wait( lock ); // Block the main thread here and releases mSurfaceChangedMutex so the render-thread can notify us
157   }
158 }
159
160 void RenderThread::SetVSyncMode( EglInterface::SyncMode syncMode )
161 {
162   // lock cache and set update flag at the end of function
163   SendMessageGuard msg( *this );
164   // set new values to cache
165   mNewValues.syncMode = syncMode;
166 }
167
168 void RenderThread::RenderSync()
169 {
170   if( !mUsingPixmap )
171   {
172     return;
173   }
174   {
175     boost::unique_lock< boost::mutex > lock( mPixmapSyncMutex );
176     mPixmapSyncReceived = true;
177   }
178
179   // awake render thread if it was waiting for the notify
180   mPixmapSyncNotify.notify_all();
181 }
182
183 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
184 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
185 // The following methods are all executed inside render thread !!!
186 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
187 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
188
189 bool RenderThread::Run()
190 {
191   // install a function for logging
192   mLogOptions.InstallLogFunction();
193
194   InitializeEgl();
195
196   bool running( true );
197
198   // Wait for first update
199   mUpdateRenderSync.RenderSyncWithUpdate();
200
201   Dali::Integration::RenderStatus renderStatus;
202
203   uint64_t currentTime( 0 );
204
205   // render loop, we stay inside here when rendering
206   while( running )
207   {
208     // Consume any pending events
209     ConsumeEvents();
210
211     // Check if we've got updates from the main thread
212     CheckForUpdates();
213
214     // perform any pre-render operations
215     if(PreRender() == true)
216     {
217        // Render
218       mCore.Render( renderStatus );
219
220       // Notify the update-thread that a render has completed
221       mUpdateRenderSync.RenderFinished( renderStatus.NeedsUpdate() );
222
223       uint64_t newTime( mUpdateRenderSync.GetTimeMicroseconds() );
224
225       // perform any post-render operations
226       if ( renderStatus.HasRendered() )
227       {
228         PostRender( static_cast< unsigned int >(newTime - currentTime) );
229       }
230
231       if(mSurfaceReplacing)
232       {
233         // Notify main thread that surface was changed so it can release the old one
234         NotifySurfaceChangeCompleted();
235         mSurfaceReplacing = false;
236       }
237
238       currentTime = newTime;
239     }
240
241     // Wait until another frame has been updated
242     running = mUpdateRenderSync.RenderSyncWithUpdate();
243   }
244
245   // shut down egl
246   ShutdownEgl();
247
248   // install a function for logging
249   mLogOptions.UnInstallLogFunction();
250
251   return true;
252 }
253
254 void RenderThread::InitializeEgl()
255 {
256   mEGL = mEglFactory->Create();
257
258   DALI_ASSERT_ALWAYS( mCurrent.surface && "NULL surface" );
259
260   // initialize egl & OpenGL
261   mCurrent.surface->InitializeEgl( *mEGL );
262
263   // create the OpenGL context
264   mEGL->CreateContext();
265
266   // create the OpenGL surface
267   mCurrent.surface->CreateEglSurface( *mEGL );
268
269   // Make it current
270   mEGL->MakeContextCurrent();
271
272   if( !mUsingPixmap )
273   {
274     // set the initial sync mode
275     mEGL->SetRefreshSync( mCurrent.syncMode );
276   }
277
278   // tell core it has a context
279   mCore.ContextCreated();
280
281   DALI_LOG_INFO(Debug::Filter::gShader, Debug::General, "*** GL_VENDOR : %s ***\n", mGLES.GetString(GL_VENDOR));
282   DALI_LOG_INFO(Debug::Filter::gShader, Debug::General, "*** GL_RENDERER : %s ***\n", mGLES.GetString(GL_RENDERER));
283   DALI_LOG_INFO(Debug::Filter::gShader, Debug::General, "*** GL_VERSION : %s ***\n", mGLES.GetString(GL_VERSION));
284   DALI_LOG_INFO(Debug::Filter::gShader, Debug::General, "*** GL_SHADING_LANGUAGE_VERSION : %s***\n", mGLES.GetString(GL_SHADING_LANGUAGE_VERSION));
285   DALI_LOG_INFO(Debug::Filter::gShader, Debug::General, "*** Supported Extensions ***\n%s\n\n", mGLES.GetString(GL_EXTENSIONS));
286 }
287
288 void RenderThread::ConsumeEvents()
289 {
290   // tell surface to consume any events to avoid memory leaks
291   mCurrent.surface->ConsumeEvents();
292 }
293
294 void RenderThread::CheckForUpdates()
295 {
296   // atomic check to see if we've got updates, resets the flag int
297   if( __sync_fetch_and_and( &mNewDataAvailable, 0 ) )
298   {
299     // scope for lock
300     // NOTE! This block is the only place in render side where mNewValues can be used inside render thread !!!
301     {
302       // need to lock to access new values
303       boost::unique_lock< boost::mutex > lock( mThreadDataLock );
304
305       // did the sync mode change
306       if( mCurrent.syncMode != mNewValues.syncMode )
307       {
308         mCurrent.syncMode = mNewValues.syncMode;
309         mEGL->SetRefreshSync( mCurrent.syncMode );
310       }
311
312       // check if the surface needs replacing
313       if( mNewValues.replaceSurface )
314       {
315         mNewValues.replaceSurface = false; // reset the flag
316         // change the surface
317         ChangeSurface( mNewValues.surface );
318         mNewValues.surface = NULL;
319       }
320     }
321   }
322 }
323
324 void RenderThread::ChangeSurface( RenderSurface* newSurface )
325 {
326   // This is designed for replacing pixmap surfaces, but should work for window as well
327   // we need to delete the egl surface and renderable (pixmap / window)
328   // Then create a new pixmap/window and new egl surface
329   // If the new surface has a different display connection, then the context will be lost
330   DALI_ASSERT_ALWAYS( newSurface && "NULL surface" )
331   bool contextLost = newSurface->ReplaceEGLSurface( *mEGL );
332
333   if( contextLost )
334   {
335     DALI_LOG_WARNING("Context lost\n");
336     mCore.ContextToBeDestroyed();
337     mCore.ContextCreated();
338   }
339
340   // if both new and old surface are using the same display, and the display
341   // connection was created by Dali, then transfer
342   // display owner ship to the new surface.
343   mCurrent.surface->TransferDisplayOwner( *newSurface );
344
345   // use the new surface from now on
346   mCurrent.surface = newSurface;
347
348   // after rendering, NotifySurfaceChangeCompleted will be called
349   mSurfaceReplacing = true;
350 }
351
352 void RenderThread::NotifySurfaceChangeCompleted()
353 {
354   {
355     boost::unique_lock< boost::mutex > lock( mSurfaceChangedMutex );
356     mSurfaceReplaceCompleted = true;
357   }
358   // notify main thread
359   mSurfaceChangedNotify.notify_all();
360 }
361
362 void RenderThread::ShutdownEgl()
363 {
364   // inform core the context is about to be destroyed,
365   mCore.ContextToBeDestroyed();
366
367   // give a chance to destroy the OpenGL surface that created externally
368   mCurrent.surface->DestroyEglSurface( *mEGL );
369
370   // delete the GL context / egl surface
371   mEGL->TerminateGles();
372 }
373
374 bool RenderThread::PreRender()
375 {
376   return mCurrent.surface->PreRender( *mEGL, mGLES );
377 }
378
379 void RenderThread::PostRender( unsigned int timeDelta )
380 {
381   const bool waitForSync = mCurrent.surface->PostRender( *mEGL, mGLES, timeDelta );
382
383   if( waitForSync )
384   {
385     boost::unique_lock< boost::mutex > lock( mPixmapSyncMutex );
386
387     // wait until synced,
388     // this blocks the thread here and releases the mPixmapSyncMutex (so the main thread can use it)
389     // if surface is replacing, forcely update without pixmap sync
390     if( mPixmapSyncRunning && !mPixmapSyncReceived && !mSurfaceReplacing )
391     {
392       mPixmapSyncNotify.wait( lock );
393     }
394     mPixmapSyncReceived = false;
395   }
396 }
397
398 } // namespace Adaptor
399
400 } // namespace Internal
401
402 } // namespace Dali