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