Added APIs to support Launchpad and set window transparency
[platform/core/uifw/dali-adaptor.git] / adaptors / base / separate-update-render / thread-synchronization.cpp
1 /*
2  * Copyright (c) 2015 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 "thread-synchronization.h"
20
21 // INTERNAL INCLUDES
22 #include <base/interfaces/adaptor-internal-services.h>
23 #include <base/separate-update-render/thread-synchronization-debug.h>
24
25 namespace Dali
26 {
27
28 namespace Internal
29 {
30
31 namespace Adaptor
32 {
33
34 namespace
35 {
36 const unsigned int TIME_PER_FRAME_IN_MICROSECONDS = 16667;
37 const int TOTAL_THREAD_COUNT = 3;
38 const unsigned int TRUE = 1u;
39 const unsigned int FALSE = 0u;
40 } // unnamed namespace
41
42 ThreadSynchronization::ThreadSynchronization( AdaptorInternalServices& adaptorInterfaces, unsigned int numberOfVSyncsPerRender)
43 : mFrameTime(),
44   mNotificationTrigger( adaptorInterfaces.GetProcessCoreEventsTrigger() ),
45   mPerformanceInterface( adaptorInterfaces.GetPerformanceInterface() ),
46   mReplaceSurfaceRequest(),
47   mUpdateThreadWaitCondition(),
48   mRenderThreadWaitCondition(),
49   mVSyncThreadWaitCondition(),
50   mEventThreadWaitCondition(),
51   mMaximumUpdateCount( adaptorInterfaces.GetCore().GetMaximumUpdateCount()),
52   mNumberOfVSyncsPerRender( numberOfVSyncsPerRender ),
53   mTryToSleepCount( 0u ),
54   mState( State::STOPPED ),
55   mVSyncAheadOfUpdate( 0u ),
56   mUpdateAheadOfRender( 0u ),
57   mNumberOfThreadsStarted( 0u ),
58   mUpdateThreadResuming( FALSE ),
59   mVSyncThreadRunning( FALSE ),
60   mVSyncThreadStop( FALSE ),
61   mRenderThreadStop( FALSE ),
62   mRenderThreadReplacingSurface( FALSE ),
63   mRenderThreadPostRendering( FALSE ),
64   mEventThreadSurfaceReplaced( FALSE ),
65   mVSyncThreadInitialised( FALSE ),
66   mRenderThreadInitialised( FALSE ),
67   mRenderThreadSurfaceReplaced( FALSE )
68 {
69 }
70
71 ThreadSynchronization::~ThreadSynchronization()
72 {
73 }
74
75 ///////////////////////////////////////////////////////////////////////////////////////////////////
76 // EVENT THREAD
77 ///////////////////////////////////////////////////////////////////////////////////////////////////
78
79 void ThreadSynchronization::Initialise()
80 {
81   LOG_EVENT_TRACE;
82
83   ConditionalWait::ScopedLock lock( mUpdateThreadWaitCondition );
84   if( mState == State::STOPPED )
85   {
86     LOG_EVENT( "INITIALISING" );
87     mState = State::INITIALISING;
88   }
89 }
90
91 void ThreadSynchronization::Start()
92 {
93   LOG_EVENT_TRACE;
94
95   bool start = false;
96   {
97     ConditionalWait::ScopedLock lock( mUpdateThreadWaitCondition );
98     if( mState == State::INITIALISING )
99     {
100       start = true;
101     }
102   }
103
104   // Not atomic, but does not matter here as we just want to ensure we only start from State::INITIALISING
105   if( start )
106   {
107     LOG_EVENT( "STARTING" );
108     mFrameTime.SetMinimumFrameTimeInterval( mNumberOfVSyncsPerRender * TIME_PER_FRAME_IN_MICROSECONDS );
109
110     {
111       ConditionalWait::ScopedLock lock( mEventThreadWaitCondition );
112       while( mNumberOfThreadsStarted < TOTAL_THREAD_COUNT )
113       {
114         mEventThreadWaitCondition.Wait( lock );
115       }
116     }
117
118     {
119       ConditionalWait::ScopedLock lock( mUpdateThreadWaitCondition );
120       mState = State::RUNNING;
121     }
122     mUpdateThreadWaitCondition.Notify();
123   }
124 }
125
126 void ThreadSynchronization::Stop()
127 {
128   LOG_EVENT_TRACE;
129
130   bool stop = false;
131   {
132     ConditionalWait::ScopedLock lock( mUpdateThreadWaitCondition );
133     if( mState != State::STOPPED )
134     {
135       stop = true;
136       mState = State::STOPPED;
137     }
138   }
139
140   // Not atomic, but does not matter here as we just want to ensure we do not stop more than once
141   if( stop )
142   {
143     LOG_EVENT( "STOPPING" );
144
145     // Notify update-thread so that it continues and sets up the other threads to stop as well
146     mUpdateThreadWaitCondition.Notify();
147
148     mFrameTime.Suspend();
149   }
150 }
151
152 void ThreadSynchronization::Pause()
153 {
154   LOG_EVENT_TRACE;
155
156   bool addPerformanceMarker = false;
157   {
158     // Only pause if we're RUNNING or SLEEPING
159     ConditionalWait::ScopedLock lock( mUpdateThreadWaitCondition );
160     if( ( mState == State::RUNNING ) ||
161         ( mState == State::SLEEPING ) )
162     {
163       LOG_EVENT( "PAUSING" );
164
165       mState = State::PAUSED;
166
167       mUpdateThreadResuming = FALSE;
168
169       mFrameTime.Suspend();
170
171       addPerformanceMarker = true;
172     }
173   }
174
175   if( addPerformanceMarker )
176   {
177     // Can lock so we do not want to have a lock when calling this to avoid deadlocks
178     AddPerformanceMarker( PerformanceInterface::PAUSED );
179   }
180 }
181
182 void ThreadSynchronization::Resume()
183 {
184   LOG_EVENT_TRACE;
185
186   // Only resume if we're PAUSED
187   bool resume = false;
188   {
189     ConditionalWait::ScopedLock lock( mUpdateThreadWaitCondition );
190     if( mState == State::PAUSED )
191     {
192       resume = true;
193       mState = State::RUNNING;
194       mUpdateThreadResuming = TRUE;
195     }
196   }
197
198   // Not atomic, but does not matter here as we just want to ensure we only resume if we're paused
199   if( resume )
200   {
201     LOG_EVENT( "RESUMING" );
202
203     mFrameTime.Resume();
204
205     // Start up Update thread again
206     mUpdateThreadWaitCondition.Notify();
207
208     // Can lock so we do not want to have a lock when calling this to avoid deadlocks
209     AddPerformanceMarker( PerformanceInterface::RESUME);
210   }
211 }
212
213 void ThreadSynchronization::UpdateRequest()
214 {
215   LOG_EVENT_TRACE;
216
217   bool update = false;
218   {
219     ConditionalWait::ScopedLock lock( mUpdateThreadWaitCondition );
220     if( mState == State::SLEEPING )
221     {
222       mState = State::RUNNING;
223       update = true;
224     }
225     mTryToSleepCount = 0;
226   }
227
228   if( update )
229   {
230     LOG_EVENT( "UPDATE REQUEST" );
231     mUpdateThreadWaitCondition.Notify();
232   }
233 }
234
235 void ThreadSynchronization::UpdateOnce()
236 {
237   LOG_EVENT_TRACE;
238   LOG_EVENT( "UPDATE ONCE" );
239
240   // If we're sleeping then change state to running as this will also wake up the v-sync-thread
241   {
242     ConditionalWait::ScopedLock lock( mUpdateThreadWaitCondition );
243     if( mState == State::SLEEPING )
244     {
245       mState = State::RUNNING;
246     }
247   }
248
249   mUpdateThreadWaitCondition.Notify();
250 }
251
252 void ThreadSynchronization::ReplaceSurface( RenderSurface* newSurface )
253 {
254   LOG_EVENT_TRACE;
255
256   State::Type previousState( State::STOPPED );
257   {
258     ConditionalWait::ScopedLock lock( mUpdateThreadWaitCondition );
259     previousState = mState;
260     mState = State::REPLACING_SURFACE;
261   }
262
263   {
264     ConditionalWait::ScopedLock lock( mEventThreadWaitCondition );
265     mEventThreadSurfaceReplaced = FALSE;
266   }
267
268   {
269     ConditionalWait::ScopedLock lock( mRenderThreadWaitCondition );
270     mReplaceSurfaceRequest.SetSurface( newSurface );
271     mRenderThreadReplacingSurface = TRUE;
272   }
273
274   // Notify the RenderThread in case it's waiting
275   mRenderThreadWaitCondition.Notify();
276
277   {
278     ConditionalWait::ScopedLock lock( mEventThreadWaitCondition );
279
280     // Wait for RenderThread to replace the surface
281     while( ! mEventThreadSurfaceReplaced )
282     {
283       LOG_EVENT( "Waiting for Surface to be Replaced" );
284
285       mEventThreadWaitCondition.Wait( lock );
286     }
287   }
288
289   {
290     ConditionalWait::ScopedLock lock( mUpdateThreadWaitCondition );
291     mState = previousState;
292   }
293   mUpdateThreadWaitCondition.Notify();
294 }
295
296 void ThreadSynchronization::SetRenderRefreshRate( unsigned int numberOfVSyncsPerRender )
297 {
298   LOG_EVENT_TRACE;
299   LOG_EVENT( "SET RENDER REFRESH RATE" );
300
301   mNumberOfVSyncsPerRender = numberOfVSyncsPerRender;
302 }
303
304 ///////////////////////////////////////////////////////////////////////////////////////////////////
305 // UPDATE THREAD
306 ///////////////////////////////////////////////////////////////////////////////////////////////////
307
308 bool ThreadSynchronization::UpdateReady( bool notifyEvent, bool runUpdate, float& lastFrameDeltaSeconds, unsigned int& lastSyncTimeMilliseconds, unsigned int& nextSyncTimeMilliseconds )
309 {
310   LOG_UPDATE_TRACE;
311
312   State::Type state = State::STOPPED;
313   {
314     ConditionalWait::ScopedLock updateLock( mUpdateThreadWaitCondition );
315     state = mState;
316   }
317
318   switch( state )
319   {
320     case State::STOPPED:
321     {
322       StopAllThreads();
323       return false; // Stop update-thread
324     }
325
326     case State::INITIALISING:
327     {
328       UpdateInitialising();
329       break;
330     }
331
332     case State::PAUSED:
333     {
334       LOG_UPDATE_TRACE_FMT( "PAUSED" );
335
336       // Just pause the VSyncThread, locks so we shouldn't have a scoped-lock when calling this
337       PauseVSyncThread();
338     }
339     // No break, fall through
340
341     case State::RUNNING:
342     {
343       LOG_UPDATE_TRACE_FMT( "RUNNING" );
344
345       if( IsUpdateThreadResuming() )
346       {
347         LOG_UPDATE( "Restarting VSyncThread" );
348
349         {
350           ConditionalWait::ScopedLock updateLock( mUpdateThreadWaitCondition );
351           mUpdateThreadResuming = FALSE;
352         }
353
354         // Restart the VSyncThread, locks so we shouldn't have a scoped-lock when calling this
355         RunVSyncThread();
356       }
357
358       if( notifyEvent )
359       {
360         LOG_UPDATE( "Notify Event Thread" );
361
362         // Do the notifications first so the event thread can start processing them
363         // Tell the event-thread to wake up (if asleep) and send a notification event to Core
364         mNotificationTrigger.Trigger();
365       }
366
367       // Inform render thread
368       {
369         ConditionalWait::ScopedLock lock( mRenderThreadWaitCondition );
370         ++mUpdateAheadOfRender;
371         DALI_ASSERT_ALWAYS( mUpdateAheadOfRender >= 0 );
372         DALI_ASSERT_ALWAYS( mUpdateAheadOfRender <= mMaximumUpdateCount );
373         LOG_UPDATE_COUNTER_UPDATE( "updateAheadOfRender(%d)", mUpdateAheadOfRender );
374       }
375       mRenderThreadWaitCondition.Notify();
376
377       // Wait if we've reached the maximum-ahead-of-render count.
378       while( MaximumUpdateAheadOfRenderReached() )
379       {
380         LOG_UPDATE( "Maximum Update Ahead of Render: WAIT" );
381
382         mRenderThreadWaitCondition.Notify(); // Notify the render thread in case it was waiting
383
384         {
385           // Ensure we did not stop while we were waiting previously.
386           ConditionalWait::ScopedLock updateLock( mUpdateThreadWaitCondition );
387           if( mState == State::STOPPED )
388           {
389             break; // Break out of while loop
390           }
391           mUpdateThreadWaitCondition.Wait( updateLock );
392         }
393       }
394
395       // Ensure we have had at least 1 V-Sync before we continue
396       // Ensure we didn't stop while we were previously waiting
397       {
398         ConditionalWait::ScopedLock updateLock( mUpdateThreadWaitCondition );
399         if( ( mState != State::STOPPED ) &&
400             ( mVSyncAheadOfUpdate == 0 ) &&
401             ( !mUpdateThreadResuming ) ) // Ensure we don't wait if the update-thread is JUST resuming
402         {
403           LOG_VSYNC_COUNTER_UPDATE( " vSyncAheadOfUpdate(%d) WAIT", mVSyncAheadOfUpdate );
404           mUpdateThreadWaitCondition.Wait( updateLock );
405         }
406         else
407         {
408           LOG_VSYNC_COUNTER_UPDATE( " vSyncAheadOfUpdate(%d)", mVSyncAheadOfUpdate );
409         }
410         mVSyncAheadOfUpdate = 0;
411       }
412
413       // Try to sleep if we do not require any more updates
414       UpdateTryToSleep( runUpdate );
415
416       break;
417     }
418
419     case State::SLEEPING:
420     case State::REPLACING_SURFACE:
421     {
422       break;
423     }
424   }
425
426   // Ensure we didn't stop while we were waiting
427   if( IsUpdateThreadStopping() )
428   {
429     // Locks so we shouldn't have a scoped-lock when calling this
430     StopAllThreads();
431     return false; // Stop update-thread
432   }
433
434   // Just wait if we're replacing the surface as the render-thread is busy
435   UpdateWaitIfReplacingSurface();
436
437   mFrameTime.PredictNextSyncTime( lastFrameDeltaSeconds, lastSyncTimeMilliseconds, nextSyncTimeMilliseconds );
438
439   return true; // Keep update-thread running
440 }
441
442 ///////////////////////////////////////////////////////////////////////////////////////////////////
443 // RENDER THREAD
444 ///////////////////////////////////////////////////////////////////////////////////////////////////
445
446 bool ThreadSynchronization::RenderReady( RenderRequest*& requestPtr )
447 {
448   LOG_RENDER_TRACE;
449
450   if( ! IsRenderThreadReplacingSurface() ) // Call to this function locks so should not be called if we have a scoped-lock
451   {
452     if( ! mRenderThreadInitialised )
453     {
454       LOG_RENDER( "Initialised" );
455
456       mRenderThreadInitialised = TRUE;
457
458       // Notify event thread that this thread is up and running, this locks so we should have a scoped-lock
459       NotifyThreadInitialised();
460     }
461     else
462     {
463       if( mRenderThreadSurfaceReplaced )
464       {
465         mRenderThreadSurfaceReplaced = FALSE;
466       }
467     }
468
469     // Check if we've had an update, if we haven't then we just wait
470     // Ensure we do not wait if we're supposed to stop
471     {
472       ConditionalWait::ScopedLock renderLock( mRenderThreadWaitCondition );
473       if( mUpdateAheadOfRender <= 0 && ! mRenderThreadStop )
474       {
475         do
476         {
477           LOG_UPDATE_COUNTER_RENDER( "updateAheadOfRender(%d) WAIT", mUpdateAheadOfRender );
478           mRenderThreadWaitCondition.Wait( renderLock );
479         } while( mUpdateAheadOfRender <= 0 && ! mRenderThreadStop && ! mRenderThreadReplacingSurface );
480       }
481       else
482       {
483         LOG_UPDATE_COUNTER_RENDER( "updateAheadOfRender(%d)", mUpdateAheadOfRender );
484       }
485     }
486   }
487
488   // We may have been asked to replace the surface while we were waiting so check again here
489   if( IsRenderThreadReplacingSurface() )
490   {
491     // Replacing surface
492     LOG_RENDER( "REPLACE SURFACE" );
493
494     ConditionalWait::ScopedLock renderLock( mRenderThreadWaitCondition );
495     requestPtr = &mReplaceSurfaceRequest;
496     mRenderThreadReplacingSurface = FALSE;
497     mRenderThreadSurfaceReplaced = FALSE;
498   }
499
500   return IsRenderThreadRunning(); // Call to this function locks so should not be called if we have a scoped-lock
501 }
502
503 void ThreadSynchronization::RenderFinished()
504 {
505   // A frame has been rendered; decrement counter
506   ConditionalWait::ScopedLock renderLock( mRenderThreadWaitCondition );
507   --mUpdateAheadOfRender;
508
509   LOG_RENDER( "mUpdateAheadOfRender %d\n", mUpdateAheadOfRender );
510   DALI_ASSERT_ALWAYS( mUpdateAheadOfRender < mMaximumUpdateCount );
511   DALI_ASSERT_ALWAYS( mUpdateAheadOfRender >= 0 );
512 }
513
514 void ThreadSynchronization::RenderInformSurfaceReplaced()
515 {
516   LOG_RENDER_TRACE;
517
518   mRenderThreadSurfaceReplaced = TRUE;
519   {
520     ConditionalWait::ScopedLock lock( mEventThreadWaitCondition );
521     mEventThreadSurfaceReplaced = TRUE;
522   }
523   mEventThreadWaitCondition.Notify();
524 }
525
526 ///////////////////////////////////////////////////////////////////////////////////////////////////
527 // V-SYNC THREAD
528 ///////////////////////////////////////////////////////////////////////////////////////////////////
529
530 bool ThreadSynchronization::VSyncReady( bool validSync, unsigned int frameNumber, unsigned int seconds, unsigned int microseconds, unsigned int& numberOfVSyncsPerRender )
531 {
532   LOG_VSYNC_TRACE;
533
534   // Ensure we do not process an invalid v-sync
535   if( validSync )
536   {
537     bool minimumFrameTimeIntervalChanged = false;
538     {
539       ConditionalWait::ScopedLock vSyncLock( mVSyncThreadWaitCondition );
540       if( numberOfVSyncsPerRender != mNumberOfVSyncsPerRender )
541       {
542         numberOfVSyncsPerRender = mNumberOfVSyncsPerRender; // save it back
543         minimumFrameTimeIntervalChanged = true;
544       }
545     }
546
547     if( minimumFrameTimeIntervalChanged )
548     {
549       mFrameTime.SetMinimumFrameTimeInterval( mNumberOfVSyncsPerRender * TIME_PER_FRAME_IN_MICROSECONDS );
550     }
551
552     mFrameTime.SetSyncTime( frameNumber );
553
554     if( ! mVSyncThreadInitialised )
555     {
556       LOG_VSYNC( "Initialised" );
557
558       mVSyncThreadInitialised = TRUE;
559
560       // Notify event thread that this thread is up and running, this locks so we should have a scoped-lock
561       NotifyThreadInitialised();
562     }
563     else
564     {
565       // Increment v-sync-ahead-of-update count and inform update-thread
566       {
567         ConditionalWait::ScopedLock lock( mUpdateThreadWaitCondition );
568         ++mVSyncAheadOfUpdate;
569         LOG_VSYNC_COUNTER_VSYNC( " vSyncAheadOfUpdate(%d)", mVSyncAheadOfUpdate );
570       }
571       mUpdateThreadWaitCondition.Notify();
572     }
573
574     // Ensure update-thread has set us to run before continuing
575     // Ensure we do not wait if we're supposed to stop
576     {
577       ConditionalWait::ScopedLock vSyncLock( mVSyncThreadWaitCondition );
578       while( ! mVSyncThreadRunning && ! mVSyncThreadStop )
579       {
580         LOG_VSYNC( "WAIT" );
581         mVSyncThreadWaitCondition.Wait( vSyncLock );
582       }
583     }
584   }
585   else
586   {
587     LOG_VSYNC( "INVALID SYNC" );
588
589     // Later we still check if the v-sync thread is supposed to keep running so we can still stop the thread if we are supposed to
590   }
591
592   return IsVSyncThreadRunning(); // Call to this function locks so should not be called if we have a scoped-lock
593 }
594
595 /////////////////////////////////////////////////////////////////////////////////////////////////
596 // POST RENDERING: EVENT THREAD
597 /////////////////////////////////////////////////////////////////////////////////////////////////
598
599 void ThreadSynchronization::PostRenderComplete()
600 {
601   LOG_EVENT_TRACE;
602
603   {
604     ConditionalWait::ScopedLock lock( mRenderThreadWaitCondition );
605     mRenderThreadPostRendering = FALSE;
606   }
607   mRenderThreadWaitCondition.Notify();
608 }
609
610 ///////////////////////////////////////////////////////////////////////////////////////////////////
611 // POST RENDERING: RENDER THREAD
612 ///////////////////////////////////////////////////////////////////////////////////////////////////
613
614 void ThreadSynchronization::PostRenderStarted()
615 {
616   LOG_RENDER_TRACE;
617
618   ConditionalWait::ScopedLock lock( mRenderThreadWaitCondition );
619   mRenderThreadPostRendering = TRUE;
620 }
621
622 void ThreadSynchronization::PostRenderWaitForCompletion()
623 {
624   LOG_RENDER_TRACE;
625
626   ConditionalWait::ScopedLock lock( mRenderThreadWaitCondition );
627   while( mRenderThreadPostRendering &&
628          ! mRenderThreadReplacingSurface ) // We should NOT wait if we're replacing the surface
629   {
630     LOG_RENDER( "WAIT" );
631     mRenderThreadWaitCondition.Wait( lock );
632   }
633 }
634
635 ///////////////////////////////////////////////////////////////////////////////////////////////////
636 // ALL THREADS: Performance Marker
637 ///////////////////////////////////////////////////////////////////////////////////////////////////
638
639 void ThreadSynchronization::AddPerformanceMarker( PerformanceInterface::MarkerType type )
640 {
641   if( mPerformanceInterface )
642   {
643     mPerformanceInterface->AddMarker( type );
644   }
645 }
646
647 ///////////////////////////////////////////////////////////////////////////////////////////////////
648 //
649 // PRIVATE METHODS
650 //
651 ///////////////////////////////////////////////////////////////////////////////////////////////////
652
653 ///////////////////////////////////////////////////////////////////////////////////////////////////
654 // Called by ALL Threads
655 ///////////////////////////////////////////////////////////////////////////////////////////////////
656
657 void ThreadSynchronization::NotifyThreadInitialised()
658 {
659   {
660     ConditionalWait::ScopedLock lock( mEventThreadWaitCondition );
661     ++mNumberOfThreadsStarted;
662   }
663   mEventThreadWaitCondition.Notify();
664 }
665
666 ///////////////////////////////////////////////////////////////////////////////////////////////////
667 // Called by Update Thread
668 ///////////////////////////////////////////////////////////////////////////////////////////////////
669
670 void ThreadSynchronization::UpdateInitialising()
671 {
672   LOG_UPDATE_TRACE;
673
674   // Notify event thread that this thread is up and running, locks so we shouldn't have a scoped-lock when calling this
675   NotifyThreadInitialised();
676
677   // Wait for first thread-sync point
678   {
679     ConditionalWait::ScopedLock updateLock( mUpdateThreadWaitCondition );
680
681     while( mState == State::INITIALISING )
682     {
683       mUpdateThreadWaitCondition.Wait( updateLock );
684     }
685   }
686
687   // Locks so we shouldn't have a scoped-lock when calling this
688   RunVSyncThread();
689 }
690
691 void ThreadSynchronization::UpdateTryToSleep( bool runUpdate )
692 {
693   LOG_UPDATE_TRACE;
694
695   if( ! runUpdate &&
696       ! IsUpdateThreadResuming() ) // Locks so we shouldn't have a lock, we shouldn't try to sleep if we're JUST resuming
697   {
698     LOG_UPDATE( "TryToSleep" );
699
700     if( ++mTryToSleepCount >= 3 )
701     {
702       LOG_UPDATE( "Going to sleep" );
703
704       // Locks so we shouldn't have a scoped-lock when calling this
705       PauseVSyncThread();
706
707       // Render thread will automatically wait as it relies on update-ahead-of-render count
708
709       // Change the state
710       {
711         ConditionalWait::ScopedLock updateLock( mUpdateThreadWaitCondition );
712
713         // Ensure we weren't stopped while we have been processing
714         if( mState != State::STOPPED )
715         {
716           mState = State::SLEEPING;
717         }
718       }
719
720       // Inform FrameTime that we're going to sleep
721       mFrameTime.Sleep();
722
723       // Wait while we're SLEEPING
724       {
725         ConditionalWait::ScopedLock updateLock( mUpdateThreadWaitCondition );
726         while( mState == State::SLEEPING )
727         {
728           mUpdateThreadWaitCondition.Wait( updateLock );
729         }
730       }
731
732       ////////////////////////
733       // WAKE UP
734       ////////////////////////
735
736       LOG_UPDATE( "Waking Up" );
737
738       // Clear V-Sync-ahead-of-update-count
739       {
740         ConditionalWait::ScopedLock updateLock( mUpdateThreadWaitCondition );
741         mVSyncAheadOfUpdate = 0;
742       }
743
744       // Restart the v-sync-thread, locks so we shouldn't have a scoped-lock
745       RunVSyncThread();
746
747       // Reset try-to-sleep count
748       mTryToSleepCount = 0;
749
750       // Inform frame timer that we've woken up
751       mFrameTime.WakeUp();
752     }
753   }
754   else
755   {
756     mTryToSleepCount = 0;
757   }
758 }
759
760 void ThreadSynchronization::UpdateWaitIfReplacingSurface()
761 {
762   bool replacingSurface = false;
763   {
764     ConditionalWait::ScopedLock updateLock( mUpdateThreadWaitCondition );
765     replacingSurface = ( mState == State::REPLACING_SURFACE );
766   }
767   while( replacingSurface )
768   {
769     LOG_UPDATE_TRACE_FMT( "REPLACING SURFACE" );
770
771     // Locks so should not be called while we have a scoped-lock
772     PauseVSyncThread();
773
774     // One last check before we actually wait in case the state has changed since we checked earlier
775     {
776       ConditionalWait::ScopedLock updateLock( mUpdateThreadWaitCondition );
777       replacingSurface = ( mState == State::REPLACING_SURFACE );
778       if( replacingSurface )
779       {
780         mUpdateThreadWaitCondition.Wait( updateLock );
781       }
782     }
783
784     {
785       ConditionalWait::ScopedLock updateLock( mUpdateThreadWaitCondition );
786       mVSyncAheadOfUpdate = 0;
787     }
788
789     // Locks so should not be called while we have a scoped-lock
790     RunVSyncThread();
791   }
792 }
793
794 bool ThreadSynchronization::IsUpdateThreadResuming()
795 {
796   ConditionalWait::ScopedLock updateLock( mUpdateThreadWaitCondition );
797   return mUpdateThreadResuming;
798 }
799
800 bool ThreadSynchronization::IsUpdateThreadStopping()
801 {
802   ConditionalWait::ScopedLock updateLock( mUpdateThreadWaitCondition );
803   return ( mState == State::STOPPED );
804 }
805
806 bool ThreadSynchronization::MaximumUpdateAheadOfRenderReached()
807 {
808   ConditionalWait::ScopedLock lock( mRenderThreadWaitCondition );
809   return mUpdateAheadOfRender >= mMaximumUpdateCount;
810 }
811
812 void ThreadSynchronization::StopAllThreads()
813 {
814   LOG_UPDATE_TRACE;
815
816   // Lock so we shouldn't have a scoped-lock when calling these methods
817   StopVSyncThread();
818   StopRenderThread();
819 }
820
821 void ThreadSynchronization::RunVSyncThread()
822 {
823   {
824     ConditionalWait::ScopedLock lock( mVSyncThreadWaitCondition );
825     mVSyncThreadRunning = TRUE;
826   }
827   mVSyncThreadWaitCondition.Notify();
828 }
829
830 void ThreadSynchronization::PauseVSyncThread()
831 {
832   ConditionalWait::ScopedLock lock( mVSyncThreadWaitCondition );
833   mVSyncThreadRunning = FALSE;
834 }
835
836 void ThreadSynchronization::StopVSyncThread()
837 {
838   {
839     ConditionalWait::ScopedLock lock( mVSyncThreadWaitCondition );
840     mVSyncThreadStop = TRUE;
841   }
842   mVSyncThreadWaitCondition.Notify();
843 }
844
845 void ThreadSynchronization::StopRenderThread()
846 {
847   {
848     ConditionalWait::ScopedLock lock( mRenderThreadWaitCondition );
849     mRenderThreadStop = TRUE;
850   }
851   mRenderThreadWaitCondition.Notify();
852 }
853
854 ///////////////////////////////////////////////////////////////////////////////////////////////////
855 // Called by V-Sync Thread
856 ///////////////////////////////////////////////////////////////////////////////////////////////////
857
858 bool ThreadSynchronization::IsVSyncThreadRunning()
859 {
860   ConditionalWait::ScopedLock lock( mVSyncThreadWaitCondition );
861   return ! mVSyncThreadStop;
862 }
863
864 ///////////////////////////////////////////////////////////////////////////////////////////////////
865 // Called by Render Thread
866 ///////////////////////////////////////////////////////////////////////////////////////////////////
867
868 bool ThreadSynchronization::IsRenderThreadRunning()
869 {
870   ConditionalWait::ScopedLock lock( mRenderThreadWaitCondition );
871   return ! mRenderThreadStop;
872 }
873
874 bool ThreadSynchronization::IsRenderThreadReplacingSurface()
875 {
876   ConditionalWait::ScopedLock lock( mRenderThreadWaitCondition );
877   return mRenderThreadReplacingSurface;
878 }
879
880 } // namespace Adaptor
881
882 } // namespace Internal
883
884 } // namespace Dali