Removed GL and GL Sync implementations
[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     mRenderHelper.PreRender();
506
507     Integration::RenderStatus renderStatus;
508
509     AddPerformanceMarker( PerformanceInterface::RENDER_START );
510     mCore.Render( renderStatus, mForceClear );
511     AddPerformanceMarker( PerformanceInterface::RENDER_END );
512
513     mForceClear = false;
514
515     if( renderStatus.NeedsPostRender() )
516     {
517       mRenderHelper.PostRender( isRenderingToFbo );
518     }
519
520     // Trigger event thread to request Update/Render thread to sleep if update not required
521     if( ( Integration::KeepUpdating::NOT_REQUESTED == keepUpdatingStatus ) &&
522         ! renderStatus.NeedsUpdate() )
523     {
524       mSleepTrigger->Trigger();
525       updateRequired = false;
526       LOG_UPDATE_RENDER( "Sleep Triggered" );
527     }
528     else
529     {
530       updateRequired = true;
531     }
532
533     //////////////////////////////
534     // FRAME TIME
535     //////////////////////////////
536
537     extraFramesDropped = 0;
538
539     if (timeToSleepUntil == 0)
540     {
541       // If this is the first frame after the thread is initialized or resumed, we
542       // use the actual time the current frame starts from to calculate the time to
543       // sleep until the next frame.
544       timeToSleepUntil = currentFrameStartTime + mDefaultFrameDurationNanoseconds;
545     }
546     else
547     {
548       // Otherwise, always use the sleep-until time calculated in the last frame to
549       // calculate the time to sleep until the next frame. In this way, if there is
550       // any time gap between the current frame and the next frame, or if update or
551       // rendering in the current frame takes too much time so that the specified
552       // sleep-until time has already passed, it will try to keep the frames syncing
553       // by shortening the duration of the next frame.
554       timeToSleepUntil += mDefaultFrameDurationNanoseconds;
555
556       // Check the current time at the end of the frame
557       uint64_t currentFrameEndTime = 0;
558       TimeService::GetNanoseconds( currentFrameEndTime );
559       while ( currentFrameEndTime > timeToSleepUntil + mDefaultFrameDurationNanoseconds )
560       {
561          // We are more than one frame behind already, so just drop the next frames
562          // until the sleep-until time is later than the current time so that we can
563          // catch up.
564          timeToSleepUntil += mDefaultFrameDurationNanoseconds;
565          extraFramesDropped++;
566       }
567     }
568
569     // Render to FBO is intended to measure fps above 60 so sleep is not wanted.
570     if( 0u == renderToFboInterval )
571     {
572       // Sleep until at least the the default frame duration has elapsed. This will return immediately if the specified end-time has already passed.
573       TimeService::SleepUntil( timeToSleepUntil );
574     }
575   }
576
577   // Shutdown EGL
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