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