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