Merge "DALi Version 1.2.50" into devel/master
[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( "Starting to resize the surface, event-thread blocked" );
293
294   // Start resizing the surface.
295   {
296     ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
297     mPostRendering = FALSE; // Clear the post-rendering flag as Update/Render thread will resize the surface now
298     mSurfaceResized = TRUE;
299     mUpdateRenderThreadWaitCondition.Notify( lock );
300   }
301
302   // Wait until the surface has been resized
303   sem_wait( &mEventThreadSemaphore );
304
305   LOG_EVENT( "Surface resized, event-thread continuing" );
306 }
307
308 void CombinedUpdateRenderController::SetRenderRefreshRate( unsigned int numberOfFramesPerRender )
309 {
310   // Not protected by lock, but written to rarely so not worth adding a lock when reading
311   mDefaultFrameDelta                  = numberOfFramesPerRender * DEFAULT_FRAME_DURATION_IN_SECONDS;
312   mDefaultFrameDurationMilliseconds   = uint64_t( numberOfFramesPerRender ) * DEFAULT_FRAME_DURATION_IN_MILLISECONDS;
313   mDefaultFrameDurationNanoseconds    = uint64_t( numberOfFramesPerRender ) * DEFAULT_FRAME_DURATION_IN_NANOSECONDS;
314   mDefaultHalfFrameNanoseconds        = mDefaultFrameDurationNanoseconds / 2u;
315
316   LOG_EVENT( "mDefaultFrameDelta(%.6f), mDefaultFrameDurationMilliseconds(%lld), mDefaultFrameDurationNanoseconds(%lld)", mDefaultFrameDelta, mDefaultFrameDurationMilliseconds, mDefaultFrameDurationNanoseconds );
317 }
318
319 ///////////////////////////////////////////////////////////////////////////////////////////////////
320 // EVENT THREAD
321 ///////////////////////////////////////////////////////////////////////////////////////////////////
322
323 void CombinedUpdateRenderController::RunUpdateRenderThread( int numberOfCycles, bool useElapsedTime )
324 {
325   ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
326   mUpdateRenderRunCount = numberOfCycles;
327   mUpdateRenderThreadCanSleep = FALSE;
328   mUseElapsedTimeAfterWait = useElapsedTime;
329   LOG_COUNTER_EVENT( "mUpdateRenderRunCount: %d, mUseElapsedTimeAfterWait: %d", mUpdateRenderRunCount, mUseElapsedTimeAfterWait );
330   mUpdateRenderThreadWaitCondition.Notify( lock );
331 }
332
333 void CombinedUpdateRenderController::PauseUpdateRenderThread()
334 {
335   ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
336   mUpdateRenderRunCount = 0;
337 }
338
339 void CombinedUpdateRenderController::StopUpdateRenderThread()
340 {
341   ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
342   mDestroyUpdateRenderThread = TRUE;
343   mUpdateRenderThreadWaitCondition.Notify( lock );
344 }
345
346 bool CombinedUpdateRenderController::IsUpdateRenderThreadPaused()
347 {
348   ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
349   return ( mUpdateRenderRunCount != CONTINUOUS ) || // Report paused if NOT continuously running
350          mUpdateRenderThreadCanSleep;               // Report paused if sleeping
351 }
352
353 void CombinedUpdateRenderController::ProcessSleepRequest()
354 {
355   LOG_EVENT_TRACE;
356
357   // Decrement Update request count
358   if( mUpdateRequestCount > 0 )
359   {
360     --mUpdateRequestCount;
361   }
362
363   // Can sleep if our update-request count is 0
364   // Update/Render thread can choose to carry on updating if it determines more update/renders are required
365   if( mUpdateRequestCount == 0 )
366   {
367     LOG_EVENT( "Going to sleep" );
368
369     ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
370     mUpdateRenderThreadCanSleep = TRUE;
371   }
372 }
373
374 ///////////////////////////////////////////////////////////////////////////////////////////////////
375 // UPDATE/RENDER THREAD
376 ///////////////////////////////////////////////////////////////////////////////////////////////////
377
378 void CombinedUpdateRenderController::UpdateRenderThread()
379 {
380   // Install a function for logging
381   mEnvironmentOptions.InstallLogFunction();
382
383   LOG_UPDATE_RENDER( "THREAD CREATED" );
384
385   mRenderHelper.InitializeEgl();
386
387   // tell core it has a context
388   mCore.ContextCreated();
389
390   NotifyThreadInitialised();
391
392   // Update time
393   uint64_t lastFrameTime;
394   TimeService::GetNanoseconds( lastFrameTime );
395
396   LOG_UPDATE_RENDER( "THREAD INITIALISED" );
397
398   bool useElapsedTime = true;
399   bool updateRequired = true;
400   uint64_t timeToSleepUntil = 0;
401   int extraFramesDropped = 0;
402
403   while( UpdateRenderReady( useElapsedTime, updateRequired, timeToSleepUntil ) )
404   {
405     LOG_UPDATE_RENDER_TRACE;
406
407     // Performance statistics are logged upon a VSYNC tick so use this point for a VSync marker
408     AddPerformanceMarker( PerformanceInterface::VSYNC );
409
410     uint64_t currentFrameStartTime = 0;
411     TimeService::GetNanoseconds( currentFrameStartTime );
412
413     const uint64_t timeSinceLastFrame = currentFrameStartTime - lastFrameTime;
414
415     // Optional FPS Tracking when continuously rendering
416     if( useElapsedTime && mFpsTracker.Enabled() )
417     {
418       float absoluteTimeSinceLastRender = timeSinceLastFrame * NANOSECONDS_TO_SECOND;
419       mFpsTracker.Track( absoluteTimeSinceLastRender );
420     }
421
422     lastFrameTime = currentFrameStartTime; // Store frame start time
423
424     //////////////////////////////
425     // REPLACE SURFACE
426     //////////////////////////////
427
428     RenderSurface* newSurface = ShouldSurfaceBeReplaced();
429     if( DALI_UNLIKELY( newSurface ) )
430     {
431       LOG_UPDATE_RENDER_TRACE_FMT( "Replacing Surface" );
432       mRenderHelper.ReplaceSurface( newSurface );
433       SurfaceReplaced();
434     }
435
436     //////////////////////////////
437     // RESIZE SURFACE
438     //////////////////////////////
439
440     // The resizing will be applied in the next loop
441     bool surfaceResized = ShouldSurfaceBeResized();
442     if( DALI_UNLIKELY( surfaceResized ) )
443     {
444       LOG_UPDATE_RENDER_TRACE_FMT( "Resizing Surface" );
445       mRenderHelper.ResizeSurface();
446       SurfaceResized();
447     }
448
449     //////////////////////////////
450     // UPDATE
451     //////////////////////////////
452
453     const unsigned int currentTime = currentFrameStartTime / NANOSECONDS_PER_MILLISECOND;
454     const unsigned int nextFrameTime = currentTime + mDefaultFrameDurationMilliseconds;
455
456     uint64_t noOfFramesSinceLastUpdate = 1;
457     float frameDelta = 0.0f;
458     if( useElapsedTime )
459     {
460       // If using the elapsed time, then calculate frameDelta as a multiple of mDefaultFrameDelta
461       noOfFramesSinceLastUpdate += extraFramesDropped;
462
463       frameDelta = mDefaultFrameDelta * noOfFramesSinceLastUpdate;
464     }
465     LOG_UPDATE_RENDER( "timeSinceLastFrame(%llu) noOfFramesSinceLastUpdate(%u) frameDelta(%.6f)", timeSinceLastFrame, noOfFramesSinceLastUpdate, frameDelta );
466
467     Integration::UpdateStatus updateStatus;
468
469     AddPerformanceMarker( PerformanceInterface::UPDATE_START );
470     mCore.Update( frameDelta, currentTime, nextFrameTime, updateStatus );
471     AddPerformanceMarker( PerformanceInterface::UPDATE_END );
472
473     unsigned int keepUpdatingStatus = updateStatus.KeepUpdating();
474
475     // Tell the event-thread to wake up (if asleep) and send a notification event to Core if required
476     if( updateStatus.NeedsNotification() )
477     {
478       mNotificationTrigger.Trigger();
479       LOG_UPDATE_RENDER( "Notification Triggered" );
480     }
481
482     // Optional logging of update/render status
483     mUpdateStatusLogger.Log( keepUpdatingStatus );
484
485     //////////////////////////////
486     // RENDER
487     //////////////////////////////
488
489     mRenderHelper.ConsumeEvents();
490     mRenderHelper.PreRender();
491
492     Integration::RenderStatus renderStatus;
493
494     AddPerformanceMarker( PerformanceInterface::RENDER_START );
495     mCore.Render( renderStatus );
496     AddPerformanceMarker( PerformanceInterface::RENDER_END );
497
498     if( renderStatus.NeedsPostRender() )
499     {
500       mRenderHelper.PostRender();
501     }
502
503     // Trigger event thread to request Update/Render thread to sleep if update not required
504     if( ( Integration::KeepUpdating::NOT_REQUESTED == keepUpdatingStatus ) &&
505         ! renderStatus.NeedsUpdate() )
506     {
507       mSleepTrigger->Trigger();
508       updateRequired = false;
509       LOG_UPDATE_RENDER( "Sleep Triggered" );
510     }
511     else
512     {
513       updateRequired = true;
514     }
515
516     //////////////////////////////
517     // FRAME TIME
518     //////////////////////////////
519
520     extraFramesDropped = 0;
521
522     if (timeToSleepUntil == 0)
523     {
524       // If this is the first frame after the thread is initialized or resumed, we
525       // use the actual time the current frame starts from to calculate the time to
526       // sleep until the next frame.
527       timeToSleepUntil = currentFrameStartTime + mDefaultFrameDurationNanoseconds;
528     }
529     else
530     {
531       // Otherwise, always use the sleep-until time calculated in the last frame to
532       // calculate the time to sleep until the next frame. In this way, if there is
533       // any time gap between the current frame and the next frame, or if update or
534       // rendering in the current frame takes too much time so that the specified
535       // sleep-until time has already passed, it will try to keep the frames syncing
536       // by shortening the duration of the next frame.
537       timeToSleepUntil += mDefaultFrameDurationNanoseconds;
538
539       // Check the current time at the end of the frame
540       uint64_t currentFrameEndTime = 0;
541       TimeService::GetNanoseconds( currentFrameEndTime );
542       while ( currentFrameEndTime > timeToSleepUntil + mDefaultFrameDurationNanoseconds )
543       {
544          // We are more than one frame behind already, so just drop the next frames
545          // until the sleep-until time is later than the current time so that we can
546          // catch up.
547          timeToSleepUntil += mDefaultFrameDurationNanoseconds;
548          extraFramesDropped++;
549       }
550     }
551
552     // Sleep until at least the the default frame duration has elapsed. This will return immediately if the specified end-time has already passed.
553     TimeService::SleepUntil( timeToSleepUntil );
554   }
555
556   // Inform core of context destruction & shutdown EGL
557   mCore.ContextDestroyed();
558   mRenderHelper.ShutdownEgl();
559
560   LOG_UPDATE_RENDER( "THREAD DESTROYED" );
561
562   // Uninstall the logging function
563   mEnvironmentOptions.UnInstallLogFunction();
564 }
565
566 bool CombinedUpdateRenderController::UpdateRenderReady( bool& useElapsedTime, bool updateRequired, uint64_t& timeToSleepUntil )
567 {
568   useElapsedTime = true;
569
570   ConditionalWait::ScopedLock updateLock( mUpdateRenderThreadWaitCondition );
571   while( ( ! mUpdateRenderRunCount || // Should try to wait if event-thread has paused the Update/Render thread
572            ( mUpdateRenderThreadCanSleep && ! updateRequired && ! mPendingRequestUpdate ) ) && // Ensure we wait if we're supposed to be sleeping AND do not require another update
573          ! mDestroyUpdateRenderThread && // Ensure we don't wait if the update-render-thread is supposed to be destroyed
574          ! mNewSurface &&  // Ensure we don't wait if we need to replace the surface
575          ! mSurfaceResized ) // Ensure we don't wait if we need to resize the surface
576   {
577     LOG_UPDATE_RENDER( "WAIT: mUpdateRenderRunCount:       %d", mUpdateRenderRunCount );
578     LOG_UPDATE_RENDER( "      mUpdateRenderThreadCanSleep: %d, updateRequired: %d, mPendingRequestUpdate: %d", mUpdateRenderThreadCanSleep, updateRequired, mPendingRequestUpdate );
579     LOG_UPDATE_RENDER( "      mDestroyUpdateRenderThread:  %d", mDestroyUpdateRenderThread );
580     LOG_UPDATE_RENDER( "      mNewSurface:                 %d", mNewSurface );
581     LOG_UPDATE_RENDER( "      mSurfaceResized:             %d", mSurfaceResized );
582
583     // Reset the time when the thread is waiting, so the sleep-until time for
584     // the first frame after resuming should be based on the actual start time
585     // of the first frame.
586     timeToSleepUntil = 0;
587
588     mUpdateRenderThreadWaitCondition.Wait( updateLock );
589
590     if( ! mUseElapsedTimeAfterWait )
591     {
592       useElapsedTime = false;
593     }
594   }
595
596   LOG_COUNTER_UPDATE_RENDER( "mUpdateRenderRunCount:       %d", mUpdateRenderRunCount );
597   LOG_COUNTER_UPDATE_RENDER( "mUpdateRenderThreadCanSleep: %d, updateRequired: %d, mPendingRequestUpdate: %d", mUpdateRenderThreadCanSleep, updateRequired, mPendingRequestUpdate );
598   LOG_COUNTER_UPDATE_RENDER( "mDestroyUpdateRenderThread:  %d", mDestroyUpdateRenderThread );
599   LOG_COUNTER_UPDATE_RENDER( "mNewSurface:                 %d", mNewSurface );
600   LOG_COUNTER_UPDATE_RENDER( "mSurfaceResized:             %d", mSurfaceResized );
601
602   mUseElapsedTimeAfterWait = FALSE;
603   mUpdateRenderThreadCanSleep = FALSE;
604   mPendingRequestUpdate = FALSE;
605
606   // If we've been asked to run Update/Render cycles a finite number of times then decrement so we wait after the
607   // requested number of cycles
608   if( mUpdateRenderRunCount > 0 )
609   {
610     --mUpdateRenderRunCount;
611   }
612
613   // Keep the update-render thread alive if this thread is NOT to be destroyed
614   return ! mDestroyUpdateRenderThread;
615 }
616
617 RenderSurface* CombinedUpdateRenderController::ShouldSurfaceBeReplaced()
618 {
619   ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
620
621   RenderSurface* newSurface = mNewSurface;
622   mNewSurface = NULL;
623
624   return newSurface;
625 }
626
627 void CombinedUpdateRenderController::SurfaceReplaced()
628 {
629   // Just increment the semaphore
630   sem_post( &mEventThreadSemaphore );
631 }
632
633 bool CombinedUpdateRenderController::ShouldSurfaceBeResized()
634 {
635   ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
636
637   bool surfaceSized = mSurfaceResized;
638   mSurfaceResized = FALSE;
639
640   return surfaceSized;
641 }
642
643 void CombinedUpdateRenderController::SurfaceResized()
644 {
645   // Just increment the semaphore
646   sem_post( &mEventThreadSemaphore );
647 }
648
649 ///////////////////////////////////////////////////////////////////////////////////////////////////
650 // ALL THREADS
651 ///////////////////////////////////////////////////////////////////////////////////////////////////
652
653 void CombinedUpdateRenderController::NotifyThreadInitialised()
654 {
655   // Just increment the semaphore
656   sem_post( &mEventThreadSemaphore );
657 }
658
659 void CombinedUpdateRenderController::AddPerformanceMarker( PerformanceInterface::MarkerType type )
660 {
661   if( mPerformanceInterface )
662   {
663     mPerformanceInterface->AddMarker( type );
664   }
665 }
666
667 /////////////////////////////////////////////////////////////////////////////////////////////////
668 // POST RENDERING: EVENT THREAD
669 /////////////////////////////////////////////////////////////////////////////////////////////////
670
671 void CombinedUpdateRenderController::PostRenderComplete()
672 {
673   ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
674   mPostRendering = FALSE;
675   mUpdateRenderThreadWaitCondition.Notify( lock );
676 }
677
678 ///////////////////////////////////////////////////////////////////////////////////////////////////
679 // POST RENDERING: RENDER THREAD
680 ///////////////////////////////////////////////////////////////////////////////////////////////////
681
682 void CombinedUpdateRenderController::PostRenderStarted()
683 {
684   ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
685   mPostRendering = TRUE;
686 }
687
688 void CombinedUpdateRenderController::PostRenderWaitForCompletion()
689 {
690   ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
691   while( mPostRendering &&
692          ! mNewSurface &&                // We should NOT wait if we're replacing the surface
693          ! mSurfaceResized &&            // We should NOT wait if we're resizing the surface
694          ! mDestroyUpdateRenderThread )
695   {
696     mUpdateRenderThreadWaitCondition.Wait( lock );
697   }
698 }
699
700 } // namespace Adaptor
701
702 } // namespace Internal
703
704 } // namespace Dali