Revert "[Tizen] Revert "Support multiple window rendering""
[platform/core/uifw/dali-adaptor.git] / dali / internal / adaptor / common / combined-update-render-controller.cpp
1 /*
2  * Copyright (c) 2019 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 <dali/internal/adaptor/common/combined-update-render-controller.h>
20
21 // EXTERNAL INCLUDES
22 #include <errno.h>
23 #include <dali/integration-api/platform-abstraction.h>
24
25 // INTERNAL INCLUDES
26 #include <dali/integration-api/trigger-event-factory.h>
27 #include <dali/internal/adaptor/common/combined-update-render-controller-debug.h>
28 #include <dali/internal/system/common/environment-options.h>
29 #include <dali/internal/system/common/time-service.h>
30 #include <dali/internal/adaptor/common/adaptor-internal-services.h>
31 #include <dali/devel-api/adaptor-framework/thread-settings.h>
32 #include <dali/internal/graphics/gles/egl-graphics.h>
33 #include <dali/internal/graphics/gles/egl-implementation.h>
34 #include <dali/internal/graphics/common/graphics-interface.h>
35
36 namespace Dali
37 {
38
39 namespace Internal
40 {
41
42 namespace Adaptor
43 {
44
45 namespace
46 {
47
48 const unsigned int CREATED_THREAD_COUNT = 1u;
49
50 const int CONTINUOUS = -1;
51 const int ONCE = 1;
52
53 const unsigned int TRUE = 1u;
54 const unsigned int FALSE = 0u;
55
56 const unsigned int MILLISECONDS_PER_SECOND( 1e+3 );
57 const float        NANOSECONDS_TO_SECOND( 1e-9f );
58 const unsigned int NANOSECONDS_PER_SECOND( 1e+9 );
59 const unsigned int NANOSECONDS_PER_MILLISECOND( 1e+6 );
60
61 // The following values will get calculated at compile time
62 const float        DEFAULT_FRAME_DURATION_IN_SECONDS( 1.0f / 60.0f );
63 const uint64_t DEFAULT_FRAME_DURATION_IN_MILLISECONDS( DEFAULT_FRAME_DURATION_IN_SECONDS * MILLISECONDS_PER_SECOND );
64 const uint64_t DEFAULT_FRAME_DURATION_IN_NANOSECONDS( DEFAULT_FRAME_DURATION_IN_SECONDS * NANOSECONDS_PER_SECOND );
65
66 /**
67  * Handles the use case when an update-request is received JUST before we process a sleep-request. If we did not have an update-request count then
68  * there is a danger that, on the event-thread we could have:
69  *  1) An update-request where we do nothing as Update/Render thread still running.
70  *  2) Quickly followed by a sleep-request being handled where we pause the Update/Render Thread (even though we have an update to process).
71  *
72  * Using a counter means we increment the counter on an update-request, and decrement it on a sleep-request. This handles the above scenario because:
73  *  1) MAIN THREAD:           Update Request: COUNTER = 1
74  *  2) UPDATE/RENDER THREAD:  Do Update/Render, then no Updates required -> Sleep Trigger
75  *  3) MAIN THREAD:           Update Request: COUNTER = 2
76  *  4) MAIN THREAD:           Sleep Request:  COUNTER = 1 -> We do not sleep just yet
77  *
78  * Also ensures we preserve battery life by only doing ONE update when the above use case is not triggered.
79  *  1) MAIN THREAD:           Update Request: COUNTER = 1
80  *  2) UPDATE/RENDER THREAD:  Do Update/Render, then no Updates required -> Sleep Trigger
81  *  3) MAIN THREAD:           Sleep Request:  COUNTER = 0 -> Go to sleep
82  */
83 const unsigned int MAXIMUM_UPDATE_REQUESTS = 2;
84 } // unnamed namespace
85
86 ///////////////////////////////////////////////////////////////////////////////////////////////////
87 // EVENT THREAD
88 ///////////////////////////////////////////////////////////////////////////////////////////////////
89
90 CombinedUpdateRenderController::CombinedUpdateRenderController( AdaptorInternalServices& adaptorInterfaces, const EnvironmentOptions& environmentOptions )
91 : mFpsTracker( environmentOptions ),
92   mUpdateStatusLogger( environmentOptions ),
93   mEventThreadSemaphore(),
94   mUpdateRenderThreadWaitCondition(),
95   mAdaptorInterfaces( adaptorInterfaces ),
96   mPerformanceInterface( adaptorInterfaces.GetPerformanceInterface() ),
97   mCore( adaptorInterfaces.GetCore() ),
98   mEnvironmentOptions( environmentOptions ),
99   mNotificationTrigger( adaptorInterfaces.GetProcessCoreEventsTrigger() ),
100   mSleepTrigger( NULL ),
101   mPreRenderCallback( NULL ),
102   mUpdateRenderThread( NULL ),
103   mDefaultFrameDelta( 0.0f ),
104   mDefaultFrameDurationMilliseconds( 0u ),
105   mDefaultFrameDurationNanoseconds( 0u ),
106   mDefaultHalfFrameNanoseconds( 0u ),
107   mUpdateRequestCount( 0u ),
108   mRunning( FALSE ),
109   mUpdateRenderRunCount( 0 ),
110   mDestroyUpdateRenderThread( FALSE ),
111   mUpdateRenderThreadCanSleep( FALSE ),
112   mPendingRequestUpdate( FALSE ),
113   mUseElapsedTimeAfterWait( FALSE ),
114   mNewSurface( NULL ),
115   mPostRendering( FALSE ),
116   mSurfaceResized( FALSE ),
117   mForceClear( FALSE )
118 {
119   LOG_EVENT_TRACE;
120
121   // Initialise frame delta/duration variables first
122   SetRenderRefreshRate( environmentOptions.GetRenderRefreshRate() );
123
124   // Set the thread-synchronization interface on the render-surface
125   Dali::RenderSurfaceInterface* currentSurface = mAdaptorInterfaces.GetRenderSurfaceInterface();
126   if( currentSurface )
127   {
128     currentSurface->SetThreadSynchronization( *this );
129   }
130
131   TriggerEventFactoryInterface& triggerFactory = mAdaptorInterfaces.GetTriggerEventFactoryInterface();
132   mSleepTrigger = triggerFactory.CreateTriggerEvent( MakeCallback( this, &CombinedUpdateRenderController::ProcessSleepRequest ), TriggerEventInterface::KEEP_ALIVE_AFTER_TRIGGER );
133
134   sem_init( &mEventThreadSemaphore, 0, 0 ); // Initialize to 0 so that it just waits if sem_post has not been called
135 }
136
137 CombinedUpdateRenderController::~CombinedUpdateRenderController()
138 {
139   LOG_EVENT_TRACE;
140
141   Stop();
142
143   delete mPreRenderCallback;
144   delete mSleepTrigger;
145 }
146
147 void CombinedUpdateRenderController::Initialize()
148 {
149   LOG_EVENT_TRACE;
150
151   // Ensure Update/Render Thread not already created
152   DALI_ASSERT_ALWAYS( ! mUpdateRenderThread );
153
154   // Create Update/Render Thread
155   mUpdateRenderThread = new pthread_t();
156   int error = pthread_create( mUpdateRenderThread, NULL, InternalUpdateRenderThreadEntryFunc, this );
157   DALI_ASSERT_ALWAYS( !error && "Return code from pthread_create() when creating UpdateRenderThread" );
158
159   // The Update/Render thread will now run and initialise the graphics interface etc. and will then wait for Start to be called
160   // When this function returns, the application initialisation on the event thread should occur
161 }
162
163 void CombinedUpdateRenderController::Start()
164 {
165   LOG_EVENT_TRACE;
166
167   DALI_ASSERT_ALWAYS( !mRunning && mUpdateRenderThread );
168
169   // Wait until all threads created in Initialise are up and running
170   for( unsigned int i = 0; i < CREATED_THREAD_COUNT; ++i )
171   {
172     sem_wait( &mEventThreadSemaphore );
173   }
174
175   Integration::RenderSurface* currentSurface = mAdaptorInterfaces.GetRenderSurfaceInterface();
176   if( currentSurface )
177   {
178     currentSurface->StartRender();
179   }
180
181   mRunning = TRUE;
182
183   LOG_EVENT( "Startup Complete, starting Update/Render Thread" );
184
185   RunUpdateRenderThread( CONTINUOUS, false /* No animation progression */ );
186 }
187
188 void CombinedUpdateRenderController::Pause()
189 {
190   LOG_EVENT_TRACE;
191
192   mRunning = FALSE;
193
194   PauseUpdateRenderThread();
195
196   AddPerformanceMarker( PerformanceInterface::PAUSED );
197 }
198
199 void CombinedUpdateRenderController::Resume()
200 {
201   LOG_EVENT_TRACE;
202
203   if( !mRunning && IsUpdateRenderThreadPaused() )
204   {
205     LOG_EVENT( "Resuming" );
206
207     RunUpdateRenderThread( CONTINUOUS, true /* Animation progression required while we were paused */ );
208
209     AddPerformanceMarker( PerformanceInterface::RESUME );
210
211     mRunning = TRUE;
212     mForceClear = TRUE;
213   }
214 }
215
216 void CombinedUpdateRenderController::Stop()
217 {
218   LOG_EVENT_TRACE;
219
220   // Stop Rendering and the Update/Render Thread
221   Integration::RenderSurface* currentSurface = mAdaptorInterfaces.GetRenderSurfaceInterface();
222   if( currentSurface )
223   {
224     currentSurface->StopRender();
225   }
226
227   StopUpdateRenderThread();
228
229   if( mUpdateRenderThread )
230   {
231     LOG_EVENT( "Destroying UpdateRenderThread" );
232
233     // wait for the thread to finish
234     pthread_join( *mUpdateRenderThread, NULL );
235
236     delete mUpdateRenderThread;
237     mUpdateRenderThread = NULL;
238   }
239
240   mRunning = FALSE;
241 }
242
243 void CombinedUpdateRenderController::RequestUpdate()
244 {
245   LOG_EVENT_TRACE;
246
247   // Increment the update-request count to the maximum
248   if( mUpdateRequestCount < MAXIMUM_UPDATE_REQUESTS )
249   {
250     ++mUpdateRequestCount;
251   }
252
253   if( mRunning && IsUpdateRenderThreadPaused() )
254   {
255     LOG_EVENT( "Processing" );
256
257     RunUpdateRenderThread( CONTINUOUS, false /* No animation progression */ );
258   }
259
260   ConditionalWait::ScopedLock updateLock( mUpdateRenderThreadWaitCondition );
261   mPendingRequestUpdate = TRUE;
262 }
263
264 void CombinedUpdateRenderController::RequestUpdateOnce()
265 {
266   // Increment the update-request count to the maximum
267   if( mUpdateRequestCount < MAXIMUM_UPDATE_REQUESTS )
268   {
269     ++mUpdateRequestCount;
270   }
271
272   if( IsUpdateRenderThreadPaused() )
273   {
274     LOG_EVENT_TRACE;
275
276     // Run Update/Render once
277     RunUpdateRenderThread( ONCE, false /* No animation progression */ );
278   }
279 }
280
281 void CombinedUpdateRenderController::ReplaceSurface( Dali::RenderSurfaceInterface* newSurface )
282 {
283   LOG_EVENT_TRACE;
284
285   // Set the ThreadSyncronizationInterface on the new surface
286   newSurface->SetThreadSynchronization( *this );
287
288   LOG_EVENT( "Starting to replace the surface, event-thread blocked" );
289
290   // Start replacing the surface.
291   {
292     ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
293     mPostRendering = FALSE; // Clear the post-rendering flag as Update/Render thread will replace the surface now
294     mNewSurface = newSurface;
295     mUpdateRenderThreadWaitCondition.Notify( lock );
296   }
297
298   // Wait until the surface has been replaced
299   sem_wait( &mEventThreadSemaphore );
300
301   LOG_EVENT( "Surface replaced, event-thread continuing" );
302 }
303
304 void CombinedUpdateRenderController::ResizeSurface()
305 {
306   LOG_EVENT_TRACE;
307
308   LOG_EVENT( "Resize the surface" );
309
310   {
311     ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
312     mPostRendering = FALSE; // Clear the post-rendering flag as Update/Render thread will resize the surface now
313     mSurfaceResized = TRUE;
314     mUpdateRenderThreadWaitCondition.Notify( lock );
315   }
316 }
317
318 void CombinedUpdateRenderController::SetRenderRefreshRate( unsigned int numberOfFramesPerRender )
319 {
320   // Not protected by lock, but written to rarely so not worth adding a lock when reading
321   mDefaultFrameDelta                  = numberOfFramesPerRender * DEFAULT_FRAME_DURATION_IN_SECONDS;
322   mDefaultFrameDurationMilliseconds   = uint64_t( numberOfFramesPerRender ) * DEFAULT_FRAME_DURATION_IN_MILLISECONDS;
323   mDefaultFrameDurationNanoseconds    = uint64_t( numberOfFramesPerRender ) * DEFAULT_FRAME_DURATION_IN_NANOSECONDS;
324   mDefaultHalfFrameNanoseconds        = mDefaultFrameDurationNanoseconds / 2u;
325
326   LOG_EVENT( "mDefaultFrameDelta(%.6f), mDefaultFrameDurationMilliseconds(%lld), mDefaultFrameDurationNanoseconds(%lld)", mDefaultFrameDelta, mDefaultFrameDurationMilliseconds, mDefaultFrameDurationNanoseconds );
327 }
328
329 void CombinedUpdateRenderController::SetPreRenderCallback( CallbackBase* callback )
330 {
331   LOG_EVENT_TRACE;
332   LOG_EVENT( "Set PreRender Callback" );
333
334   ConditionalWait::ScopedLock updateLock( mUpdateRenderThreadWaitCondition );
335   if( mPreRenderCallback )
336   {
337     delete mPreRenderCallback;
338   }
339   mPreRenderCallback = callback;
340 }
341
342 ///////////////////////////////////////////////////////////////////////////////////////////////////
343 // EVENT THREAD
344 ///////////////////////////////////////////////////////////////////////////////////////////////////
345
346 void CombinedUpdateRenderController::RunUpdateRenderThread( int numberOfCycles, bool useElapsedTime )
347 {
348   ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
349   mUpdateRenderRunCount = numberOfCycles;
350   mUpdateRenderThreadCanSleep = FALSE;
351   mUseElapsedTimeAfterWait = useElapsedTime;
352   LOG_COUNTER_EVENT( "mUpdateRenderRunCount: %d, mUseElapsedTimeAfterWait: %d", mUpdateRenderRunCount, mUseElapsedTimeAfterWait );
353   mUpdateRenderThreadWaitCondition.Notify( lock );
354 }
355
356 void CombinedUpdateRenderController::PauseUpdateRenderThread()
357 {
358   ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
359   mUpdateRenderRunCount = 0;
360 }
361
362 void CombinedUpdateRenderController::StopUpdateRenderThread()
363 {
364   ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
365   mDestroyUpdateRenderThread = TRUE;
366   mUpdateRenderThreadWaitCondition.Notify( lock );
367 }
368
369 bool CombinedUpdateRenderController::IsUpdateRenderThreadPaused()
370 {
371   ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
372   return ( mUpdateRenderRunCount != CONTINUOUS ) || // Report paused if NOT continuously running
373          mUpdateRenderThreadCanSleep;               // Report paused if sleeping
374 }
375
376 void CombinedUpdateRenderController::ProcessSleepRequest()
377 {
378   LOG_EVENT_TRACE;
379
380   // Decrement Update request count
381   if( mUpdateRequestCount > 0 )
382   {
383     --mUpdateRequestCount;
384   }
385
386   // Can sleep if our update-request count is 0
387   // Update/Render thread can choose to carry on updating if it determines more update/renders are required
388   if( mUpdateRequestCount == 0 )
389   {
390     LOG_EVENT( "Going to sleep" );
391
392     ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
393     mUpdateRenderThreadCanSleep = TRUE;
394   }
395 }
396
397 ///////////////////////////////////////////////////////////////////////////////////////////////////
398 // UPDATE/RENDER THREAD
399 ///////////////////////////////////////////////////////////////////////////////////////////////////
400
401 void CombinedUpdateRenderController::UpdateRenderThread()
402 {
403   SetThreadName("RenderThread\0");
404
405   // Install a function for logging
406   mEnvironmentOptions.InstallLogFunction();
407
408   // Install a function for tracing
409   mEnvironmentOptions.InstallTraceFunction();
410
411   LOG_UPDATE_RENDER( "THREAD CREATED" );
412
413   // Initialize EGL & OpenGL
414   Dali::DisplayConnection& displayConnection = mAdaptorInterfaces.GetDisplayConnectionInterface();
415   displayConnection.Initialize();
416
417   RenderSurfaceInterface* currentSurface = nullptr;
418
419 #if DALI_GLES_VERSION >= 30
420
421   GraphicsInterface& graphics = mAdaptorInterfaces.GetGraphicsInterface();
422   EglGraphics* eglGraphics = static_cast<EglGraphics *>(&graphics);
423
424   // This will only be created once
425   EglInterface* eglInterface = &eglGraphics->GetEglInterface();
426
427   Internal::Adaptor::EglImplementation& eglImpl = static_cast<Internal::Adaptor::EglImplementation&>( *eglInterface );
428   eglImpl.ChooseConfig( true, COLOR_DEPTH_32 ); // Always use this for shared context???
429
430   // Create a surfaceless OpenGL context for shared resources
431   eglImpl.CreateContext();
432   eglImpl.MakeContextCurrent( EGL_NO_SURFACE, eglImpl.GetContext() );
433
434 #else // DALI_GLES_VERSION >= 30
435
436   currentSurface = mAdaptorInterfaces.GetRenderSurfaceInterface();
437   if( currentSurface )
438   {
439     currentSurface->InitializeGraphics();
440     currentSurface->MakeContextCurrent();
441   }
442
443 #endif
444
445   // Tell core it has a context
446   mCore.ContextCreated();
447
448   NotifyThreadInitialised();
449
450   // Update time
451   uint64_t lastFrameTime;
452   TimeService::GetNanoseconds( lastFrameTime );
453
454   LOG_UPDATE_RENDER( "THREAD INITIALISED" );
455
456   bool useElapsedTime = true;
457   bool updateRequired = true;
458   uint64_t timeToSleepUntil = 0;
459   int extraFramesDropped = 0;
460
461   const unsigned int renderToFboInterval = mEnvironmentOptions.GetRenderToFboInterval();
462   const bool renderToFboEnabled = 0u != renderToFboInterval;
463   unsigned int frameCount = 0u;
464
465   while( UpdateRenderReady( useElapsedTime, updateRequired, timeToSleepUntil ) )
466   {
467     LOG_UPDATE_RENDER_TRACE;
468
469     // Performance statistics are logged upon a VSYNC tick so use this point for a VSync marker
470     AddPerformanceMarker( PerformanceInterface::VSYNC );
471
472     uint64_t currentFrameStartTime = 0;
473     TimeService::GetNanoseconds( currentFrameStartTime );
474
475     const uint64_t timeSinceLastFrame = currentFrameStartTime - lastFrameTime;
476
477     // Optional FPS Tracking when continuously rendering
478     if( useElapsedTime && mFpsTracker.Enabled() )
479     {
480       float absoluteTimeSinceLastRender = timeSinceLastFrame * NANOSECONDS_TO_SECOND;
481       mFpsTracker.Track( absoluteTimeSinceLastRender );
482     }
483
484     lastFrameTime = currentFrameStartTime; // Store frame start time
485
486     //////////////////////////////
487     // REPLACE SURFACE
488     //////////////////////////////
489
490     Integration::RenderSurface* newSurface = ShouldSurfaceBeReplaced();
491     if( DALI_UNLIKELY( newSurface ) )
492     {
493       LOG_UPDATE_RENDER_TRACE_FMT( "Replacing Surface" );
494
495       // This is designed for replacing pixmap surfaces, but should work for window as well
496       // we need to delete the surface and renderable (pixmap / window)
497       // Then create a new pixmap/window and new surface
498       // If the new surface has a different display connection, then the context will be lost
499
500       mAdaptorInterfaces.GetDisplayConnectionInterface().Initialize();
501       newSurface->InitializeGraphics();
502       newSurface->ReplaceGraphicsSurface();
503       SurfaceReplaced();
504     }
505
506     const bool isRenderingToFbo = renderToFboEnabled && ( ( 0u == frameCount ) || ( 0u != frameCount % renderToFboInterval ) );
507     ++frameCount;
508
509     //////////////////////////////
510     // UPDATE
511     //////////////////////////////
512
513     const unsigned int currentTime = currentFrameStartTime / NANOSECONDS_PER_MILLISECOND;
514     const unsigned int nextFrameTime = currentTime + mDefaultFrameDurationMilliseconds;
515
516     uint64_t noOfFramesSinceLastUpdate = 1;
517     float frameDelta = 0.0f;
518     if( useElapsedTime )
519     {
520       // If using the elapsed time, then calculate frameDelta as a multiple of mDefaultFrameDelta
521       noOfFramesSinceLastUpdate += extraFramesDropped;
522
523       frameDelta = mDefaultFrameDelta * noOfFramesSinceLastUpdate;
524     }
525     LOG_UPDATE_RENDER( "timeSinceLastFrame(%llu) noOfFramesSinceLastUpdate(%u) frameDelta(%.6f)", timeSinceLastFrame, noOfFramesSinceLastUpdate, frameDelta );
526
527     Integration::UpdateStatus updateStatus;
528
529     AddPerformanceMarker( PerformanceInterface::UPDATE_START );
530     mCore.Update( frameDelta,
531                   currentTime,
532                   nextFrameTime,
533                   updateStatus,
534                   renderToFboEnabled,
535                   isRenderingToFbo );
536     AddPerformanceMarker( PerformanceInterface::UPDATE_END );
537
538     unsigned int keepUpdatingStatus = updateStatus.KeepUpdating();
539
540     // Tell the event-thread to wake up (if asleep) and send a notification event to Core if required
541     if( updateStatus.NeedsNotification() )
542     {
543       mNotificationTrigger.Trigger();
544       LOG_UPDATE_RENDER( "Notification Triggered" );
545     }
546
547     // Check resize
548     bool shouldSurfaceBeResized = ShouldSurfaceBeResized();
549     if( DALI_UNLIKELY( shouldSurfaceBeResized ) )
550     {
551       if( updateStatus.SurfaceRectChanged() )
552       {
553         LOG_UPDATE_RENDER_TRACE_FMT( "Resizing Surface" );
554         SurfaceResized();
555       }
556     }
557
558     // Optional logging of update/render status
559     mUpdateStatusLogger.Log( keepUpdatingStatus );
560
561     //////////////////////////////
562     // RENDER
563     //////////////////////////////
564
565     mAdaptorInterfaces.GetDisplayConnectionInterface().ConsumeEvents();
566
567     if( mPreRenderCallback != NULL )
568     {
569       bool keepCallback = CallbackBase::ExecuteReturn<bool>(*mPreRenderCallback);
570       if( ! keepCallback )
571       {
572         delete mPreRenderCallback;
573         mPreRenderCallback = NULL;
574       }
575     }
576
577 #if DALI_GLES_VERSION >= 30
578     // Make the shared surfaceless context as current before rendering
579     eglImpl.MakeContextCurrent( EGL_NO_SURFACE, eglImpl.GetContext() );
580 #endif
581
582     Integration::RenderStatus renderStatus;
583
584     AddPerformanceMarker( PerformanceInterface::RENDER_START );
585     mCore.Render( renderStatus, mForceClear );
586     AddPerformanceMarker( PerformanceInterface::RENDER_END );
587
588     mForceClear = false;
589
590     // Trigger event thread to request Update/Render thread to sleep if update not required
591     if( ( Integration::KeepUpdating::NOT_REQUESTED == keepUpdatingStatus ) && !renderStatus.NeedsUpdate() )
592     {
593       mSleepTrigger->Trigger();
594       updateRequired = false;
595       LOG_UPDATE_RENDER( "Sleep Triggered" );
596     }
597     else
598     {
599       updateRequired = true;
600     }
601
602     //////////////////////////////
603     // FRAME TIME
604     //////////////////////////////
605
606     extraFramesDropped = 0;
607
608     if (timeToSleepUntil == 0)
609     {
610       // If this is the first frame after the thread is initialized or resumed, we
611       // use the actual time the current frame starts from to calculate the time to
612       // sleep until the next frame.
613       timeToSleepUntil = currentFrameStartTime + mDefaultFrameDurationNanoseconds;
614     }
615     else
616     {
617       // Otherwise, always use the sleep-until time calculated in the last frame to
618       // calculate the time to sleep until the next frame. In this way, if there is
619       // any time gap between the current frame and the next frame, or if update or
620       // rendering in the current frame takes too much time so that the specified
621       // sleep-until time has already passed, it will try to keep the frames syncing
622       // by shortening the duration of the next frame.
623       timeToSleepUntil += mDefaultFrameDurationNanoseconds;
624
625       // Check the current time at the end of the frame
626       uint64_t currentFrameEndTime = 0;
627       TimeService::GetNanoseconds( currentFrameEndTime );
628       while ( currentFrameEndTime > timeToSleepUntil + mDefaultFrameDurationNanoseconds )
629       {
630          // We are more than one frame behind already, so just drop the next frames
631          // until the sleep-until time is later than the current time so that we can
632          // catch up.
633          timeToSleepUntil += mDefaultFrameDurationNanoseconds;
634          extraFramesDropped++;
635       }
636     }
637
638     // Render to FBO is intended to measure fps above 60 so sleep is not wanted.
639     if( 0u == renderToFboInterval )
640     {
641       // Sleep until at least the the default frame duration has elapsed. This will return immediately if the specified end-time has already passed.
642       TimeService::SleepUntil( timeToSleepUntil );
643     }
644   }
645
646   // Inform core of context destruction & shutdown EGL
647   mCore.ContextDestroyed();
648   currentSurface = mAdaptorInterfaces.GetRenderSurfaceInterface();
649   if( currentSurface )
650   {
651     currentSurface->DestroySurface();
652     currentSurface = nullptr;
653   }
654
655   LOG_UPDATE_RENDER( "THREAD DESTROYED" );
656
657   // Uninstall the logging function
658   mEnvironmentOptions.UnInstallLogFunction();
659 }
660
661 bool CombinedUpdateRenderController::UpdateRenderReady( bool& useElapsedTime, bool updateRequired, uint64_t& timeToSleepUntil )
662 {
663   useElapsedTime = true;
664
665   ConditionalWait::ScopedLock updateLock( mUpdateRenderThreadWaitCondition );
666   while( ( ! mUpdateRenderRunCount || // Should try to wait if event-thread has paused the Update/Render thread
667            ( mUpdateRenderThreadCanSleep && ! updateRequired && ! mPendingRequestUpdate ) ) && // Ensure we wait if we're supposed to be sleeping AND do not require another update
668          ! mDestroyUpdateRenderThread && // Ensure we don't wait if the update-render-thread is supposed to be destroyed
669          ! mNewSurface &&  // Ensure we don't wait if we need to replace the surface
670          ! mSurfaceResized ) // Ensure we don't wait if we need to resize the surface
671   {
672     LOG_UPDATE_RENDER( "WAIT: mUpdateRenderRunCount:       %d", mUpdateRenderRunCount );
673     LOG_UPDATE_RENDER( "      mUpdateRenderThreadCanSleep: %d, updateRequired: %d, mPendingRequestUpdate: %d", mUpdateRenderThreadCanSleep, updateRequired, mPendingRequestUpdate );
674     LOG_UPDATE_RENDER( "      mDestroyUpdateRenderThread:  %d", mDestroyUpdateRenderThread );
675     LOG_UPDATE_RENDER( "      mNewSurface:                 %d", mNewSurface );
676     LOG_UPDATE_RENDER( "      mSurfaceResized:             %d", mSurfaceResized );
677
678     // Reset the time when the thread is waiting, so the sleep-until time for
679     // the first frame after resuming should be based on the actual start time
680     // of the first frame.
681     timeToSleepUntil = 0;
682
683     mUpdateRenderThreadWaitCondition.Wait( updateLock );
684
685     if( ! mUseElapsedTimeAfterWait )
686     {
687       useElapsedTime = false;
688     }
689   }
690
691   LOG_COUNTER_UPDATE_RENDER( "mUpdateRenderRunCount:       %d", mUpdateRenderRunCount );
692   LOG_COUNTER_UPDATE_RENDER( "mUpdateRenderThreadCanSleep: %d, updateRequired: %d, mPendingRequestUpdate: %d", mUpdateRenderThreadCanSleep, updateRequired, mPendingRequestUpdate );
693   LOG_COUNTER_UPDATE_RENDER( "mDestroyUpdateRenderThread:  %d", mDestroyUpdateRenderThread );
694   LOG_COUNTER_UPDATE_RENDER( "mNewSurface:                 %d", mNewSurface );
695   LOG_COUNTER_UPDATE_RENDER( "mSurfaceResized:             %d", mSurfaceResized );
696
697   mUseElapsedTimeAfterWait = FALSE;
698   mUpdateRenderThreadCanSleep = FALSE;
699   mPendingRequestUpdate = FALSE;
700
701   // If we've been asked to run Update/Render cycles a finite number of times then decrement so we wait after the
702   // requested number of cycles
703   if( mUpdateRenderRunCount > 0 )
704   {
705     --mUpdateRenderRunCount;
706   }
707
708   // Keep the update-render thread alive if this thread is NOT to be destroyed
709   return ! mDestroyUpdateRenderThread;
710 }
711
712 Integration::RenderSurface* CombinedUpdateRenderController::ShouldSurfaceBeReplaced()
713 {
714   ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
715
716   Integration::RenderSurface* newSurface = mNewSurface;
717   mNewSurface = NULL;
718
719   return newSurface;
720 }
721
722 void CombinedUpdateRenderController::SurfaceReplaced()
723 {
724   // Just increment the semaphore
725   sem_post( &mEventThreadSemaphore );
726 }
727
728 bool CombinedUpdateRenderController::ShouldSurfaceBeResized()
729 {
730   ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
731   return mSurfaceResized;
732 }
733
734 void CombinedUpdateRenderController::SurfaceResized()
735 {
736   ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
737   mSurfaceResized = FALSE;
738 }
739
740 ///////////////////////////////////////////////////////////////////////////////////////////////////
741 // ALL THREADS
742 ///////////////////////////////////////////////////////////////////////////////////////////////////
743
744 void CombinedUpdateRenderController::NotifyThreadInitialised()
745 {
746   // Just increment the semaphore
747   sem_post( &mEventThreadSemaphore );
748 }
749
750 void CombinedUpdateRenderController::AddPerformanceMarker( PerformanceInterface::MarkerType type )
751 {
752   if( mPerformanceInterface )
753   {
754     mPerformanceInterface->AddMarker( type );
755   }
756 }
757
758 /////////////////////////////////////////////////////////////////////////////////////////////////
759 // POST RENDERING: EVENT THREAD
760 /////////////////////////////////////////////////////////////////////////////////////////////////
761
762 void CombinedUpdateRenderController::PostRenderComplete()
763 {
764   ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
765   mPostRendering = FALSE;
766   mUpdateRenderThreadWaitCondition.Notify( lock );
767 }
768
769 ///////////////////////////////////////////////////////////////////////////////////////////////////
770 // POST RENDERING: RENDER THREAD
771 ///////////////////////////////////////////////////////////////////////////////////////////////////
772
773 void CombinedUpdateRenderController::PostRenderStarted()
774 {
775   ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
776   mPostRendering = TRUE;
777 }
778
779 void CombinedUpdateRenderController::PostRenderWaitForCompletion()
780 {
781   ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
782   while( mPostRendering &&
783          ! mNewSurface &&                // We should NOT wait if we're replacing the surface
784          ! mSurfaceResized &&            // We should NOT wait if we're resizing the surface
785          ! mDestroyUpdateRenderThread )
786   {
787     mUpdateRenderThreadWaitCondition.Wait( lock );
788   }
789 }
790
791 } // namespace Adaptor
792
793 } // namespace Internal
794
795 } // namespace Dali