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