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