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