Uses TextArray new type definition.
[platform/core/uifw/dali-adaptor.git] / adaptors / base / update-render-synchronization.cpp
1 /*
2  * Copyright (c) 2014 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 "update-render-synchronization.h"
20
21 // INTERNAL INCLUDES
22 #include <dali/integration-api/debug.h>
23 #include <base/interfaces/adaptor-internal-services.h>
24
25 namespace Dali
26 {
27
28 namespace Internal
29 {
30
31 namespace Adaptor
32 {
33
34 namespace
35 {
36
37 const unsigned int MICROSECONDS_PER_SECOND( 1000000 );
38 const unsigned int INPUT_EVENT_UPDATE_PERIOD( MICROSECONDS_PER_SECOND / 90 ); // period between ecore x event updates
39
40 } // unnamed namespace
41
42 UpdateRenderSynchronization::UpdateRenderSynchronization( AdaptorInternalServices& adaptorInterfaces )
43 : mMaximumUpdateCount( adaptorInterfaces.GetCore().GetMaximumUpdateCount()),
44   mUpdateReadyCount( 0u ),
45   mRunning( false ),
46   mUpdateRequired( false ),
47   mPaused( false ),
48   mUpdateRequested( false ),
49   mAllowUpdateWhilePaused( false ),
50   mVSyncSleep( false ),
51   mVSyncFrameNumber( 0u ),
52   mVSyncSeconds( 0u ),
53   mVSyncMicroseconds( 0u ),
54   mCore( adaptorInterfaces.GetCore() ),
55   mPerformanceInterface( adaptorInterfaces.GetPerformanceInterface() )
56 {
57 }
58
59 UpdateRenderSynchronization::~UpdateRenderSynchronization()
60 {
61 }
62
63 void UpdateRenderSynchronization::Start()
64 {
65   mRunning = true;
66 }
67
68 void UpdateRenderSynchronization::Stop()
69 {
70   mRunning = false;
71
72   // Wake if sleeping
73   UpdateRequested();
74
75   // we may be paused so need to resume
76   Resume();
77
78   // Notify all condition variables, so if threads are waiting
79   // they can break out, and check the running status.
80   mUpdateFinishedCondition.notify_one();
81   mRenderFinishedCondition.notify_one();
82   mVSyncSleepCondition.notify_one();
83   mVSyncReceivedCondition.notify_one();
84 }
85
86 void UpdateRenderSynchronization::Pause()
87 {
88   mPaused = true;
89
90   AddPerformanceMarker( PerformanceMarker::PAUSED );
91
92 }
93
94 void UpdateRenderSynchronization::Resume()
95 {
96   mPaused = false;
97   mVSyncSleep = false;
98
99   mPausedCondition.notify_one();
100   mVSyncSleepCondition.notify_one();
101
102   AddPerformanceMarker( PerformanceMarker::RESUME);
103 }
104
105 void UpdateRenderSynchronization::UpdateRequested()
106 {
107   mUpdateRequested = true;
108
109   // Wake update thread if sleeping
110   mUpdateSleepCondition.notify_one();
111 }
112
113 void UpdateRenderSynchronization::UpdateWhilePaused()
114 {
115   {
116     boost::unique_lock< boost::mutex > lock( mMutex );
117
118     mAllowUpdateWhilePaused = true;
119   }
120
121   // wake vsync if sleeping
122   mVSyncSleepCondition.notify_one();
123   // Wake update if sleeping
124   mUpdateSleepCondition.notify_one();
125   // stay paused but notify the pause condition
126   mPausedCondition.notify_one();
127 }
128
129 void UpdateRenderSynchronization::UpdateReadyToRun()
130 {
131   bool wokenFromPause( false );
132
133   // atomic check first to avoid mutex lock in 99.99% of cases
134   if( mPaused )
135   {
136     boost::unique_lock< boost::mutex > lock( mMutex );
137
138     // wait while paused
139     while( mPaused && !mAllowUpdateWhilePaused )
140     {
141       // this will automatically unlock mMutex
142       mPausedCondition.wait( lock );
143
144       wokenFromPause = true;
145     }
146   }
147
148   if ( !wokenFromPause )
149   {
150     // Wait for the next VSync
151     WaitVSync();
152   }
153
154   AddPerformanceMarker( PerformanceMarker::UPDATE_START );
155 }
156
157 bool UpdateRenderSynchronization::UpdateSyncWithRender( bool& renderNeedsUpdate )
158 {
159
160   AddPerformanceMarker( PerformanceMarker::UPDATE_END );
161
162   boost::unique_lock< boost::mutex > lock( mMutex );
163
164   // Another frame was prepared for rendering; increment counter
165   ++mUpdateReadyCount;
166   DALI_ASSERT_DEBUG( mUpdateReadyCount <= mMaximumUpdateCount );
167
168   // Notify the render-thread that an update has completed
169   mUpdateFinishedCondition.notify_one();
170
171   // The update-thread must wait until a frame has been rendered, when mMaximumUpdateCount is reached
172   while( mRunning && ( mMaximumUpdateCount == mUpdateReadyCount ) )
173   {
174     // Wait will atomically add the thread to the set of threads waiting on
175     // the condition variable mRenderFinishedCondition and unlock the mutex.
176     mRenderFinishedCondition.wait( lock );
177   }
178
179   renderNeedsUpdate = mUpdateRequired;
180
181   // Flag is used to during UpdateThread::Stop() to exit the update/render loops
182   return mRunning;
183 }
184
185 void UpdateRenderSynchronization::UpdateWaitForAllRenderingToFinish()
186 {
187   boost::unique_lock< boost::mutex > lock( mMutex );
188
189   // Wait for all of the prepared frames to be rendered
190   while ( mRunning && ( 0u != mUpdateReadyCount ) && !mUpdateRequested )
191   {
192     // Wait will atomically add the thread to the set of threads waiting on
193     // the condition variable mRenderFinishedCondition and unlock the mutex.
194     mRenderFinishedCondition.wait( lock );
195   }
196 }
197
198 bool UpdateRenderSynchronization::UpdateTryToSleep()
199 {
200   if ( !mUpdateRequired && !mUpdateRequested )
201   {
202     // there's nothing to update in the scene, so wait for render to finish processing
203     UpdateWaitForAllRenderingToFinish();
204   }
205
206   boost::mutex sleepMutex;
207   boost::unique_lock< boost::mutex > lock( sleepMutex );
208
209   while( mRunning && !mUpdateRequired && !mUpdateRequested )
210   {
211     //
212     // Going to sleep
213     //
214
215     // 1. put VSync thread to sleep.
216     mVSyncSleep = true;
217
218     // 2. inform Core
219     mCore.Sleep();
220
221     // 3. block thread and wait for wakeup event
222     mUpdateSleepCondition.wait( lock );
223
224     //
225     // Woken up
226     //
227
228     // 1. inform Core
229     mCore.WakeUp();
230
231     // 2. wake VSync thread.
232     mVSyncSleep = false;
233     mVSyncSleepCondition.notify_one();
234   }
235
236   mUpdateRequested = false;
237
238   return mRunning;
239 }
240
241 void UpdateRenderSynchronization::RenderFinished( bool updateRequired )
242 {
243   {
244     boost::unique_lock< boost::mutex > lock( mMutex );
245
246     // Set the flag to say if update needs to run again.
247     mUpdateRequired = updateRequired;
248
249     // A frame has been rendered; decrement counter
250     --mUpdateReadyCount;
251     DALI_ASSERT_DEBUG( mUpdateReadyCount < mMaximumUpdateCount );
252   }
253
254   // Notify the update-thread that a render has completed
255   mRenderFinishedCondition.notify_one();
256
257   AddPerformanceMarker( PerformanceMarker::RENDER_END );
258 }
259
260 bool UpdateRenderSynchronization::RenderSyncWithUpdate()
261 {
262   boost::unique_lock< boost::mutex > lock( mMutex );
263
264   // Wait for update to produce a buffer, or for the mRunning state to change
265   while ( mRunning && ( 0u == mUpdateReadyCount ) )
266   {
267     // Wait will atomically add the thread to the set of threads waiting on
268     // the condition variable mUpdateFinishedCondition and unlock the mutex.
269     mUpdateFinishedCondition.wait( lock );
270   }
271
272   if( mRunning )
273   {
274     AddPerformanceMarker( PerformanceMarker::RENDER_START );
275   }
276   // Flag is used to during UpdateThread::Stop() to exit the update/render loops
277   return mRunning;
278 }
279
280 void UpdateRenderSynchronization::WaitVSync()
281 {
282   // Block until the start of a new vsync.
283   // If we're experiencing slowdown and are behind by more than a frame
284   // then we should wait for the next frame as the Video output will also
285   // do this (lock-step to 60Hz)
286
287   unsigned int updateFrameNumber = mVSyncFrameNumber;
288
289   boost::unique_lock< boost::mutex > lock( mMutex );
290
291   while ( mRunning && ( updateFrameNumber == mVSyncFrameNumber ) )
292   {
293     // Wait will atomically add the thread to the set of threads waiting on
294     // the condition variable mVSyncReceivedCondition and unlock the mutex.
295     mVSyncReceivedCondition.wait( lock );
296   }
297
298   // reset update while paused flag
299   mAllowUpdateWhilePaused = false;
300 }
301
302 bool UpdateRenderSynchronization::VSyncNotifierSyncWithUpdateAndRender( unsigned int frameNumber, unsigned int seconds, unsigned int microseconds )
303 {
304   boost::unique_lock< boost::mutex > lock( mMutex );
305
306   mVSyncFrameNumber = frameNumber;
307   mVSyncSeconds = seconds;
308   mVSyncMicroseconds = microseconds;
309
310   mVSyncReceivedCondition.notify_all();
311
312   AddPerformanceMarker( PerformanceMarker::V_SYNC );
313
314   while( mRunning && // sleep on condition variable WHILE still running
315          !mAllowUpdateWhilePaused &&             // AND NOT allowing updates while paused
316          ( mVSyncSleep || mPaused ) )            // AND sleeping OR paused
317   {
318     // Wait will atomically add the thread to the set of threads waiting on
319     // the condition variable mVSyncSleepCondition and unlock the mutex.
320     mVSyncSleepCondition.wait( lock );
321   }
322
323   return mRunning;
324 }
325
326 unsigned int UpdateRenderSynchronization::GetFrameNumber() const
327 {
328   return mVSyncFrameNumber;
329 }
330
331 uint64_t UpdateRenderSynchronization::GetTimeMicroseconds()
332 {
333   uint64_t currentTime(0);
334
335   {
336     boost::unique_lock< boost::mutex > lock( mMutex );
337
338     currentTime = mVSyncSeconds;
339     currentTime *= MICROSECONDS_PER_SECOND;
340     currentTime += mVSyncMicroseconds;
341   }
342
343   return currentTime;
344 }
345
346 inline void UpdateRenderSynchronization::AddPerformanceMarker( PerformanceMarker::MarkerType type )
347 {
348   if( mPerformanceInterface )
349   {
350     mPerformanceInterface->AddMarker( type );
351   }
352 }
353
354 } // namespace Adaptor
355
356 } // namespace Internal
357
358 } // namespace Dali