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