2 // Copyright (c) 2014 Samsung Electronics Co., Ltd.
4 // Licensed under the Flora License, Version 1.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
8 // http://floralicense.org/license/
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.
18 #include "update-render-synchronization.h"
21 #include <dali/integration-api/debug.h>
22 #include <base/interfaces/adaptor-internal-services.h>
36 const unsigned int MICROSECONDS_PER_SECOND( 1000000 );
37 const unsigned int INPUT_EVENT_UPDATE_PERIOD( MICROSECONDS_PER_SECOND / 90 ); // period between ecore x event updates
39 } // unnamed namespace
41 UpdateRenderSynchronization::UpdateRenderSynchronization( AdaptorInternalServices& adaptorInterfaces )
42 : mMaximumUpdateCount( adaptorInterfaces.GetCore().GetMaximumUpdateCount()),
43 mUpdateReadyCount( 0u ),
45 mUpdateRequired( false ),
47 mUpdateRequested( false ),
48 mAllowUpdateWhilePaused( false ),
50 mVSyncFrameNumber( 0u ),
52 mVSyncMicroseconds( 0u ),
53 mCore( adaptorInterfaces.GetCore() ),
54 mPerformanceInterface( adaptorInterfaces.GetPerformanceInterface() ),
55 mSkipNextVSync( false )
59 UpdateRenderSynchronization::~UpdateRenderSynchronization()
63 void UpdateRenderSynchronization::Start()
68 void UpdateRenderSynchronization::Stop()
75 // we may be paused so need to resume
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();
86 void UpdateRenderSynchronization::Pause()
90 AddPerformanceMarker( PerformanceMarker::PAUSED );
94 void UpdateRenderSynchronization::Resume()
99 mPausedCondition.notify_one();
100 mVSyncSleepCondition.notify_one();
102 AddPerformanceMarker( PerformanceMarker::RESUME);
105 void UpdateRenderSynchronization::UpdateRequested()
107 mUpdateRequested = true;
109 // Wake update thread if sleeping
110 mUpdateSleepCondition.notify_one();
113 void UpdateRenderSynchronization::UpdateWhilePaused()
116 boost::unique_lock< boost::mutex > lock( mMutex );
118 mAllowUpdateWhilePaused = true;
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();
129 void UpdateRenderSynchronization::UpdateReadyToRun()
131 bool wokenFromPause( false );
133 // atomic check first to avoid mutex lock in 99.99% of cases
136 boost::unique_lock< boost::mutex > lock( mMutex );
139 while( mPaused && !mAllowUpdateWhilePaused )
141 // this will automatically unlock mMutex
142 mPausedCondition.wait( lock );
144 wokenFromPause = true;
148 if ( !wokenFromPause && !mSkipNextVSync)
150 // Wait for the next VSync
154 mSkipNextVSync = false;
156 AddPerformanceMarker( PerformanceMarker::UPDATE_START );
159 bool UpdateRenderSynchronization::UpdateSyncWithRender( bool& renderNeedsUpdate )
162 AddPerformanceMarker( PerformanceMarker::UPDATE_END );
164 boost::unique_lock< boost::mutex > lock( mMutex );
166 // Another frame was prepared for rendering; increment counter
168 DALI_ASSERT_DEBUG( mUpdateReadyCount <= mMaximumUpdateCount );
170 // Notify the render-thread that an update has completed
171 mUpdateFinishedCondition.notify_one();
173 // The update-thread must wait until a frame has been rendered, when mMaximumUpdateCount is reached
174 while( mRunning && ( mMaximumUpdateCount == mUpdateReadyCount ) )
176 // Wait will atomically add the thread to the set of threads waiting on
177 // the condition variable mRenderFinishedCondition and unlock the mutex.
178 mRenderFinishedCondition.wait( lock );
181 renderNeedsUpdate = mUpdateRequired;
183 // Flag is used to during UpdateThread::Stop() to exit the update/render loops
187 void UpdateRenderSynchronization::UpdateWaitForAllRenderingToFinish()
189 boost::unique_lock< boost::mutex > lock( mMutex );
191 // Wait for all of the prepared frames to be rendered
192 while ( mRunning && ( 0u != mUpdateReadyCount ) && !mUpdateRequested )
194 // Wait will atomically add the thread to the set of threads waiting on
195 // the condition variable mRenderFinishedCondition and unlock the mutex.
196 mRenderFinishedCondition.wait( lock );
200 bool UpdateRenderSynchronization::UpdateTryToSleep()
202 if ( !mUpdateRequired && !mUpdateRequested )
204 // there's nothing to update in the scene, so wait for render to finish processing
205 UpdateWaitForAllRenderingToFinish();
208 boost::mutex sleepMutex;
209 boost::unique_lock< boost::mutex > lock( sleepMutex );
211 while( mRunning && !mUpdateRequired && !mUpdateRequested )
217 // 1. put VSync thread to sleep.
223 // 3. block thread and wait for wakeup event
224 mUpdateSleepCondition.wait( lock );
233 // 2. wake VSync thread.
235 mVSyncSleepCondition.notify_one();
237 // 3. Update shouldn't wait for next VSync
238 mSkipNextVSync = true;
241 mUpdateRequested = false;
246 void UpdateRenderSynchronization::RenderFinished( bool updateRequired )
249 boost::unique_lock< boost::mutex > lock( mMutex );
251 // Set the flag to say if update needs to run again.
252 mUpdateRequired = updateRequired;
254 // A frame has been rendered; decrement counter
256 DALI_ASSERT_DEBUG( mUpdateReadyCount < mMaximumUpdateCount );
259 // Notify the update-thread that a render has completed
260 mRenderFinishedCondition.notify_one();
262 AddPerformanceMarker( PerformanceMarker::RENDER_END );
265 bool UpdateRenderSynchronization::RenderSyncWithUpdate()
267 boost::unique_lock< boost::mutex > lock( mMutex );
269 // Wait for update to produce a buffer, or for the mRunning state to change
270 while ( mRunning && ( 0u == mUpdateReadyCount ) )
272 // Wait will atomically add the thread to the set of threads waiting on
273 // the condition variable mUpdateFinishedCondition and unlock the mutex.
274 mUpdateFinishedCondition.wait( lock );
279 AddPerformanceMarker( PerformanceMarker::RENDER_START );
281 // Flag is used to during UpdateThread::Stop() to exit the update/render loops
285 void UpdateRenderSynchronization::WaitVSync()
287 // Block until the start of a new vsync.
288 // If we're experiencing slowdown and are behind by more than a frame
289 // then we should wait for the next frame as the Video output will also
290 // do this (lock-step to 60Hz)
292 unsigned int updateFrameNumber = mVSyncFrameNumber;
294 boost::unique_lock< boost::mutex > lock( mMutex );
296 while ( mRunning && ( updateFrameNumber == mVSyncFrameNumber ) )
298 // Wait will atomically add the thread to the set of threads waiting on
299 // the condition variable mVSyncReceivedCondition and unlock the mutex.
300 mVSyncReceivedCondition.wait( lock );
303 // reset update while paused flag
304 mAllowUpdateWhilePaused = false;
307 bool UpdateRenderSynchronization::VSyncNotifierSyncWithUpdateAndRender( unsigned int frameNumber, unsigned int seconds, unsigned int microseconds )
309 boost::unique_lock< boost::mutex > lock( mMutex );
311 mVSyncFrameNumber = frameNumber;
312 mVSyncSeconds = seconds;
313 mVSyncMicroseconds = microseconds;
315 mVSyncReceivedCondition.notify_all();
317 AddPerformanceMarker( PerformanceMarker::V_SYNC );
319 while( mRunning && // sleep on condition variable WHILE still running
320 !mAllowUpdateWhilePaused && // AND NOT allowing updates while paused
321 ( mVSyncSleep || mPaused ) ) // AND sleeping OR paused
323 // Wait will atomically add the thread to the set of threads waiting on
324 // the condition variable mVSyncSleepCondition and unlock the mutex.
325 mVSyncSleepCondition.wait( lock );
331 unsigned int UpdateRenderSynchronization::GetFrameNumber() const
333 return mVSyncFrameNumber;
336 uint64_t UpdateRenderSynchronization::GetTimeMicroseconds()
338 uint64_t currentTime(0);
341 boost::unique_lock< boost::mutex > lock( mMutex );
343 currentTime = mVSyncSeconds;
344 currentTime *= MICROSECONDS_PER_SECOND;
345 currentTime += mVSyncMicroseconds;
351 inline void UpdateRenderSynchronization::AddPerformanceMarker( PerformanceMarker::MarkerType type )
353 if( mPerformanceInterface )
355 mPerformanceInterface->AddMarker( type );
359 } // namespace Adaptor
361 } // namespace Internal