2 * Copyright (c) 2014 Samsung Electronics Co., Ltd.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
19 #include "update-render-synchronization.h"
22 #include <dali/integration-api/debug.h>
23 #include <base/interfaces/adaptor-internal-services.h>
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
40 } // unnamed namespace
42 UpdateRenderSynchronization::UpdateRenderSynchronization( AdaptorInternalServices& adaptorInterfaces )
43 : mMaximumUpdateCount( adaptorInterfaces.GetCore().GetMaximumUpdateCount()),
44 mUpdateReadyCount( 0u ),
46 mUpdateRequired( false ),
48 mUpdateRequested( false ),
49 mAllowUpdateWhilePaused( false ),
51 mVSyncFrameNumber( 0u ),
53 mVSyncMicroseconds( 0u ),
54 mCore( adaptorInterfaces.GetCore() ),
55 mPerformanceInterface( adaptorInterfaces.GetPerformanceInterface() )
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 )
150 // Wait for the next VSync
154 AddPerformanceMarker( PerformanceMarker::UPDATE_START );
157 bool UpdateRenderSynchronization::UpdateSyncWithRender( bool& renderNeedsUpdate )
160 AddPerformanceMarker( PerformanceMarker::UPDATE_END );
162 boost::unique_lock< boost::mutex > lock( mMutex );
164 // Another frame was prepared for rendering; increment counter
166 DALI_ASSERT_DEBUG( mUpdateReadyCount <= mMaximumUpdateCount );
168 // Notify the render-thread that an update has completed
169 mUpdateFinishedCondition.notify_one();
171 // The update-thread must wait until a frame has been rendered, when mMaximumUpdateCount is reached
172 while( mRunning && ( mMaximumUpdateCount == mUpdateReadyCount ) )
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 );
179 renderNeedsUpdate = mUpdateRequired;
181 // Flag is used to during UpdateThread::Stop() to exit the update/render loops
185 void UpdateRenderSynchronization::UpdateWaitForAllRenderingToFinish()
187 boost::unique_lock< boost::mutex > lock( mMutex );
189 // Wait for all of the prepared frames to be rendered
190 while ( mRunning && ( 0u != mUpdateReadyCount ) && !mUpdateRequested )
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 );
198 bool UpdateRenderSynchronization::UpdateTryToSleep()
200 if ( !mUpdateRequired && !mUpdateRequested )
202 // there's nothing to update in the scene, so wait for render to finish processing
203 UpdateWaitForAllRenderingToFinish();
206 boost::mutex sleepMutex;
207 boost::unique_lock< boost::mutex > lock( sleepMutex );
209 while( mRunning && !mUpdateRequired && !mUpdateRequested )
215 // 1. put VSync thread to sleep.
221 // 3. block thread and wait for wakeup event
222 mUpdateSleepCondition.wait( lock );
231 // 2. wake VSync thread.
233 mVSyncSleepCondition.notify_one();
236 mUpdateRequested = false;
241 void UpdateRenderSynchronization::RenderFinished( bool updateRequired )
244 boost::unique_lock< boost::mutex > lock( mMutex );
246 // Set the flag to say if update needs to run again.
247 mUpdateRequired = updateRequired;
249 // A frame has been rendered; decrement counter
251 DALI_ASSERT_DEBUG( mUpdateReadyCount < mMaximumUpdateCount );
254 // Notify the update-thread that a render has completed
255 mRenderFinishedCondition.notify_one();
257 AddPerformanceMarker( PerformanceMarker::RENDER_END );
260 bool UpdateRenderSynchronization::RenderSyncWithUpdate()
262 boost::unique_lock< boost::mutex > lock( mMutex );
264 // Wait for update to produce a buffer, or for the mRunning state to change
265 while ( mRunning && ( 0u == mUpdateReadyCount ) )
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 );
274 AddPerformanceMarker( PerformanceMarker::RENDER_START );
276 // Flag is used to during UpdateThread::Stop() to exit the update/render loops
280 void UpdateRenderSynchronization::WaitVSync()
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)
287 unsigned int updateFrameNumber = mVSyncFrameNumber;
289 boost::unique_lock< boost::mutex > lock( mMutex );
291 while ( mRunning && ( updateFrameNumber == mVSyncFrameNumber ) )
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 );
298 // reset update while paused flag
299 mAllowUpdateWhilePaused = false;
302 bool UpdateRenderSynchronization::VSyncNotifierSyncWithUpdateAndRender( unsigned int frameNumber, unsigned int seconds, unsigned int microseconds )
304 boost::unique_lock< boost::mutex > lock( mMutex );
306 mVSyncFrameNumber = frameNumber;
307 mVSyncSeconds = seconds;
308 mVSyncMicroseconds = microseconds;
310 mVSyncReceivedCondition.notify_all();
312 AddPerformanceMarker( PerformanceMarker::V_SYNC );
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
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 );
326 unsigned int UpdateRenderSynchronization::GetFrameNumber() const
328 return mVSyncFrameNumber;
331 uint64_t UpdateRenderSynchronization::GetTimeMicroseconds()
333 uint64_t currentTime(0);
336 boost::unique_lock< boost::mutex > lock( mMutex );
338 currentTime = mVSyncSeconds;
339 currentTime *= MICROSECONDS_PER_SECOND;
340 currentTime += mVSyncMicroseconds;
346 inline void UpdateRenderSynchronization::AddPerformanceMarker( PerformanceMarker::MarkerType type )
348 if( mPerformanceInterface )
350 mPerformanceInterface->AddMarker( type );
354 } // namespace Adaptor
356 } // namespace Internal