5ae0eccd721867a9ce2b7f3fa81ab0ff7de5ab11
[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->InitializeGraphics( mAdaptorInterfaces.GetGraphicsInterface(), mAdaptorInterfaces.GetDisplayConnectionInterface() );
477       newSurface->ReplaceGraphicsSurface();
478       SurfaceReplaced();
479     }
480
481     const bool isRenderingToFbo = renderToFboEnabled && ( ( 0u == frameCount ) || ( 0u != frameCount % renderToFboInterval ) );
482     ++frameCount;
483
484     //////////////////////////////
485     // UPDATE
486     //////////////////////////////
487
488     const unsigned int currentTime = currentFrameStartTime / NANOSECONDS_PER_MILLISECOND;
489     const unsigned int nextFrameTime = currentTime + mDefaultFrameDurationMilliseconds;
490
491     uint64_t noOfFramesSinceLastUpdate = 1;
492     float frameDelta = 0.0f;
493     if( useElapsedTime )
494     {
495       // If using the elapsed time, then calculate frameDelta as a multiple of mDefaultFrameDelta
496       noOfFramesSinceLastUpdate += extraFramesDropped;
497
498       frameDelta = mDefaultFrameDelta * noOfFramesSinceLastUpdate;
499     }
500     LOG_UPDATE_RENDER( "timeSinceLastFrame(%llu) noOfFramesSinceLastUpdate(%u) frameDelta(%.6f)", timeSinceLastFrame, noOfFramesSinceLastUpdate, frameDelta );
501
502     Integration::UpdateStatus updateStatus;
503
504     AddPerformanceMarker( PerformanceInterface::UPDATE_START );
505     mCore.Update( frameDelta,
506                   currentTime,
507                   nextFrameTime,
508                   updateStatus,
509                   renderToFboEnabled,
510                   isRenderingToFbo );
511     AddPerformanceMarker( PerformanceInterface::UPDATE_END );
512
513     unsigned int keepUpdatingStatus = updateStatus.KeepUpdating();
514
515     // Tell the event-thread to wake up (if asleep) and send a notification event to Core if required
516     if( updateStatus.NeedsNotification() )
517     {
518       mNotificationTrigger.Trigger();
519       LOG_UPDATE_RENDER( "Notification Triggered" );
520     }
521
522     // Check resize
523     bool surfaceResized = false;
524     bool shouldSurfaceBeResized = ShouldSurfaceBeResized();
525     if( DALI_UNLIKELY( shouldSurfaceBeResized ) )
526     {
527       if( updateStatus.SurfaceRectChanged() )
528       {
529         LOG_UPDATE_RENDER_TRACE_FMT( "Resizing Surface" );
530         SurfaceResized();
531         surfaceResized = true;
532       }
533     }
534
535     // Optional logging of update/render status
536     mUpdateStatusLogger.Log( keepUpdatingStatus );
537
538     //////////////////////////////
539     // RENDER
540     //////////////////////////////
541
542     mAdaptorInterfaces.GetDisplayConnectionInterface().ConsumeEvents();
543
544     if( mPreRenderCallback != NULL )
545     {
546       bool keepCallback = CallbackBase::ExecuteReturn<bool>(*mPreRenderCallback);
547       if( ! keepCallback )
548       {
549         delete mPreRenderCallback;
550         mPreRenderCallback = NULL;
551       }
552     }
553
554     currentSurface = mAdaptorInterfaces.GetRenderSurfaceInterface();
555     if( currentSurface )
556     {
557       currentSurface->PreRender( surfaceResized );
558     }
559
560     Integration::RenderStatus renderStatus;
561
562     AddPerformanceMarker( PerformanceInterface::RENDER_START );
563     mCore.Render( renderStatus, mForceClear );
564     AddPerformanceMarker( PerformanceInterface::RENDER_END );
565
566     mForceClear = false;
567
568     if( renderStatus.NeedsPostRender() )
569     {
570       if( currentSurface )
571       {
572         currentSurface->PostRender( isRenderingToFbo, ( mNewSurface != NULL ), surfaceResized );
573       }
574     }
575
576     // Trigger event thread to request Update/Render thread to sleep if update not required
577     if( ( Integration::KeepUpdating::NOT_REQUESTED == keepUpdatingStatus ) && !renderStatus.NeedsUpdate() )
578     {
579       mSleepTrigger->Trigger();
580       updateRequired = false;
581       LOG_UPDATE_RENDER( "Sleep Triggered" );
582     }
583     else
584     {
585       updateRequired = true;
586     }
587
588     //////////////////////////////
589     // FRAME TIME
590     //////////////////////////////
591
592     extraFramesDropped = 0;
593
594     if (timeToSleepUntil == 0)
595     {
596       // If this is the first frame after the thread is initialized or resumed, we
597       // use the actual time the current frame starts from to calculate the time to
598       // sleep until the next frame.
599       timeToSleepUntil = currentFrameStartTime + mDefaultFrameDurationNanoseconds;
600     }
601     else
602     {
603       // Otherwise, always use the sleep-until time calculated in the last frame to
604       // calculate the time to sleep until the next frame. In this way, if there is
605       // any time gap between the current frame and the next frame, or if update or
606       // rendering in the current frame takes too much time so that the specified
607       // sleep-until time has already passed, it will try to keep the frames syncing
608       // by shortening the duration of the next frame.
609       timeToSleepUntil += mDefaultFrameDurationNanoseconds;
610
611       // Check the current time at the end of the frame
612       uint64_t currentFrameEndTime = 0;
613       TimeService::GetNanoseconds( currentFrameEndTime );
614       while ( currentFrameEndTime > timeToSleepUntil + mDefaultFrameDurationNanoseconds )
615       {
616          // We are more than one frame behind already, so just drop the next frames
617          // until the sleep-until time is later than the current time so that we can
618          // catch up.
619          timeToSleepUntil += mDefaultFrameDurationNanoseconds;
620          extraFramesDropped++;
621       }
622     }
623
624     // Render to FBO is intended to measure fps above 60 so sleep is not wanted.
625     if( 0u == renderToFboInterval )
626     {
627       // Sleep until at least the the default frame duration has elapsed. This will return immediately if the specified end-time has already passed.
628       TimeService::SleepUntil( timeToSleepUntil );
629     }
630   }
631
632   // Inform core of context destruction & shutdown EGL
633   mCore.ContextDestroyed();
634   currentSurface = mAdaptorInterfaces.GetRenderSurfaceInterface();
635   if( currentSurface )
636   {
637     currentSurface->DestroySurface();
638     currentSurface = nullptr;
639   }
640
641   LOG_UPDATE_RENDER( "THREAD DESTROYED" );
642
643   // Uninstall the logging function
644   mEnvironmentOptions.UnInstallLogFunction();
645 }
646
647 bool CombinedUpdateRenderController::UpdateRenderReady( bool& useElapsedTime, bool updateRequired, uint64_t& timeToSleepUntil )
648 {
649   useElapsedTime = true;
650
651   ConditionalWait::ScopedLock updateLock( mUpdateRenderThreadWaitCondition );
652   while( ( ! mUpdateRenderRunCount || // Should try to wait if event-thread has paused the Update/Render thread
653            ( mUpdateRenderThreadCanSleep && ! updateRequired && ! mPendingRequestUpdate ) ) && // Ensure we wait if we're supposed to be sleeping AND do not require another update
654          ! mDestroyUpdateRenderThread && // Ensure we don't wait if the update-render-thread is supposed to be destroyed
655          ! mNewSurface &&  // Ensure we don't wait if we need to replace the surface
656          ! mSurfaceResized ) // Ensure we don't wait if we need to resize the surface
657   {
658     LOG_UPDATE_RENDER( "WAIT: mUpdateRenderRunCount:       %d", mUpdateRenderRunCount );
659     LOG_UPDATE_RENDER( "      mUpdateRenderThreadCanSleep: %d, updateRequired: %d, mPendingRequestUpdate: %d", mUpdateRenderThreadCanSleep, updateRequired, mPendingRequestUpdate );
660     LOG_UPDATE_RENDER( "      mDestroyUpdateRenderThread:  %d", mDestroyUpdateRenderThread );
661     LOG_UPDATE_RENDER( "      mNewSurface:                 %d", mNewSurface );
662     LOG_UPDATE_RENDER( "      mSurfaceResized:             %d", mSurfaceResized );
663
664     // Reset the time when the thread is waiting, so the sleep-until time for
665     // the first frame after resuming should be based on the actual start time
666     // of the first frame.
667     timeToSleepUntil = 0;
668
669     mUpdateRenderThreadWaitCondition.Wait( updateLock );
670
671     if( ! mUseElapsedTimeAfterWait )
672     {
673       useElapsedTime = false;
674     }
675   }
676
677   LOG_COUNTER_UPDATE_RENDER( "mUpdateRenderRunCount:       %d", mUpdateRenderRunCount );
678   LOG_COUNTER_UPDATE_RENDER( "mUpdateRenderThreadCanSleep: %d, updateRequired: %d, mPendingRequestUpdate: %d", mUpdateRenderThreadCanSleep, updateRequired, mPendingRequestUpdate );
679   LOG_COUNTER_UPDATE_RENDER( "mDestroyUpdateRenderThread:  %d", mDestroyUpdateRenderThread );
680   LOG_COUNTER_UPDATE_RENDER( "mNewSurface:                 %d", mNewSurface );
681   LOG_COUNTER_UPDATE_RENDER( "mSurfaceResized:             %d", mSurfaceResized );
682
683   mUseElapsedTimeAfterWait = FALSE;
684   mUpdateRenderThreadCanSleep = FALSE;
685   mPendingRequestUpdate = FALSE;
686
687   // If we've been asked to run Update/Render cycles a finite number of times then decrement so we wait after the
688   // requested number of cycles
689   if( mUpdateRenderRunCount > 0 )
690   {
691     --mUpdateRenderRunCount;
692   }
693
694   // Keep the update-render thread alive if this thread is NOT to be destroyed
695   return ! mDestroyUpdateRenderThread;
696 }
697
698 RenderSurface* CombinedUpdateRenderController::ShouldSurfaceBeReplaced()
699 {
700   ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
701
702   RenderSurface* newSurface = mNewSurface;
703   mNewSurface = NULL;
704
705   return newSurface;
706 }
707
708 void CombinedUpdateRenderController::SurfaceReplaced()
709 {
710   // Just increment the semaphore
711   sem_post( &mEventThreadSemaphore );
712 }
713
714 bool CombinedUpdateRenderController::ShouldSurfaceBeResized()
715 {
716   ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
717   return mSurfaceResized;
718 }
719
720 void CombinedUpdateRenderController::SurfaceResized()
721 {
722   ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
723   mSurfaceResized = FALSE;
724 }
725
726 ///////////////////////////////////////////////////////////////////////////////////////////////////
727 // ALL THREADS
728 ///////////////////////////////////////////////////////////////////////////////////////////////////
729
730 void CombinedUpdateRenderController::NotifyThreadInitialised()
731 {
732   // Just increment the semaphore
733   sem_post( &mEventThreadSemaphore );
734 }
735
736 void CombinedUpdateRenderController::AddPerformanceMarker( PerformanceInterface::MarkerType type )
737 {
738   if( mPerformanceInterface )
739   {
740     mPerformanceInterface->AddMarker( type );
741   }
742 }
743
744 /////////////////////////////////////////////////////////////////////////////////////////////////
745 // POST RENDERING: EVENT THREAD
746 /////////////////////////////////////////////////////////////////////////////////////////////////
747
748 void CombinedUpdateRenderController::PostRenderComplete()
749 {
750   ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
751   mPostRendering = FALSE;
752   mUpdateRenderThreadWaitCondition.Notify( lock );
753 }
754
755 ///////////////////////////////////////////////////////////////////////////////////////////////////
756 // POST RENDERING: RENDER THREAD
757 ///////////////////////////////////////////////////////////////////////////////////////////////////
758
759 void CombinedUpdateRenderController::PostRenderStarted()
760 {
761   ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
762   mPostRendering = TRUE;
763 }
764
765 void CombinedUpdateRenderController::PostRenderWaitForCompletion()
766 {
767   ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
768   while( mPostRendering &&
769          ! mNewSurface &&                // We should NOT wait if we're replacing the surface
770          ! mSurfaceResized &&            // We should NOT wait if we're resizing the surface
771          ! mDestroyUpdateRenderThread )
772   {
773     mUpdateRenderThreadWaitCondition.Wait( lock );
774   }
775 }
776
777 } // namespace Adaptor
778
779 } // namespace Internal
780
781 } // namespace Dali