From: Richard Huang Date: Thu, 15 Jun 2017 16:16:11 +0000 (+0100) Subject: Fix the frame sync issue in COMBINED_UPDATE_RENDER mode X-Git-Tag: dali_1.2.46~3^2 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=refs%2Fchanges%2F61%2F134461%2F3;p=platform%2Fcore%2Fuifw%2Fdali-adaptor.git Fix the frame sync issue in COMBINED_UPDATE_RENDER mode There could be a small gap between the start time of the current frame and the sleep-until time calculated in the previous frame. In addition, the update or rendering in the current frame could take too much time so that the calculated sleep-until time has already passed. In order to make the frames keep syncing to the default frame duration (i.e. 16 ms) in these cases, we should keep tracking any extra time taken by the current frame and shorten the duration of the next frame accordingly. Change-Id: Ic3dcbfbc5b8aded6514310ee17843839daf12f03 --- diff --git a/adaptors/base/combined-update-render/combined-update-render-controller.cpp b/adaptors/base/combined-update-render/combined-update-render-controller.cpp index 5f9e700..ab9ed37 100644 --- a/adaptors/base/combined-update-render/combined-update-render-controller.cpp +++ b/adaptors/base/combined-update-render/combined-update-render-controller.cpp @@ -376,8 +376,10 @@ void CombinedUpdateRenderController::UpdateRenderThread() bool useElapsedTime = true; bool updateRequired = true; + uint64_t timeToSleepUntil = 0; + int extraFramesDropped = 0; - while( UpdateRenderReady( useElapsedTime, updateRequired ) ) + while( UpdateRenderReady( useElapsedTime, updateRequired, timeToSleepUntil ) ) { LOG_UPDATE_RENDER_TRACE; @@ -422,8 +424,8 @@ void CombinedUpdateRenderController::UpdateRenderThread() if( useElapsedTime ) { // If using the elapsed time, then calculate frameDelta as a multiple of mDefaultFrameDelta - // Round up if remainder is more than half the default frame time - noOfFramesSinceLastUpdate = ( timeSinceLastFrame + mDefaultHalfFrameNanoseconds) / mDefaultFrameDurationNanoseconds; + noOfFramesSinceLastUpdate += extraFramesDropped; + frameDelta = mDefaultFrameDelta * noOfFramesSinceLastUpdate; } LOG_UPDATE_RENDER( "timeSinceLastFrame(%llu) noOfFramesSinceLastUpdate(%u) frameDelta(%.6f)", timeSinceLastFrame, noOfFramesSinceLastUpdate, frameDelta ); @@ -478,8 +480,40 @@ void CombinedUpdateRenderController::UpdateRenderThread() // FRAME TIME ////////////////////////////// + extraFramesDropped = 0; + + if (timeToSleepUntil == 0) + { + // If this is the first frame after the thread is initialized or resumed, we + // use the actual time the current frame starts from to calculate the time to + // sleep until the next frame. + timeToSleepUntil = currentFrameStartTime + mDefaultFrameDurationNanoseconds; + } + else + { + // Otherwise, always use the sleep-until time calculated in the last frame to + // calculate the time to sleep until the next frame. In this way, if there is + // any time gap between the current frame and the next frame, or if update or + // rendering in the current frame takes too much time so that the specified + // sleep-until time has already passed, it will try to keep the frames syncing + // by shortening the duration of the next frame. + timeToSleepUntil += mDefaultFrameDurationNanoseconds; + + // Check the current time at the end of the frame + uint64_t currentFrameEndTime = 0; + TimeService::GetNanoseconds( currentFrameEndTime ); + while ( currentFrameEndTime > timeToSleepUntil + mDefaultFrameDurationNanoseconds ) + { + // We are more than one frame behind already, so just drop the next frames + // until the sleep-until time is later than the current time so that we can + // catch up. + timeToSleepUntil += mDefaultFrameDurationNanoseconds; + extraFramesDropped++; + } + } + // Sleep until at least the the default frame duration has elapsed. This will return immediately if the specified end-time has already passed. - TimeService::SleepUntil( currentFrameStartTime + mDefaultFrameDurationNanoseconds ); + TimeService::SleepUntil( timeToSleepUntil ); } // Inform core of context destruction & shutdown EGL @@ -492,7 +526,7 @@ void CombinedUpdateRenderController::UpdateRenderThread() mEnvironmentOptions.UnInstallLogFunction(); } -bool CombinedUpdateRenderController::UpdateRenderReady( bool& useElapsedTime, bool updateRequired ) +bool CombinedUpdateRenderController::UpdateRenderReady( bool& useElapsedTime, bool updateRequired, uint64_t& timeToSleepUntil ) { useElapsedTime = true; @@ -507,6 +541,11 @@ bool CombinedUpdateRenderController::UpdateRenderReady( bool& useElapsedTime, bo LOG_UPDATE_RENDER( " mDestroyUpdateRenderThread: %d", mDestroyUpdateRenderThread ); LOG_UPDATE_RENDER( " mNewSurface: %d", mNewSurface ); + // Reset the time when the thread is waiting, so the sleep-until time for + // the first frame after resuming should be based on the actual start time + // of the first frame. + timeToSleepUntil = 0; + mUpdateRenderThreadWaitCondition.Wait( updateLock ); if( ! mUseElapsedTimeAfterWait ) diff --git a/adaptors/base/combined-update-render/combined-update-render-controller.h b/adaptors/base/combined-update-render/combined-update-render-controller.h index 9179c6b..8cde53e 100644 --- a/adaptors/base/combined-update-render/combined-update-render-controller.h +++ b/adaptors/base/combined-update-render/combined-update-render-controller.h @@ -192,12 +192,13 @@ private: /** * Called by the Update/Render Thread which ensures a wait if required. * - * @param[out] useElapsedTime If true when returned, then the actual elapsed time will be used for animation. - * If false when returned, then there should NOT be any animation progression in the next Update. - * @param[in] updateRequired Whether another update is required. + * @param[out] useElapsedTime If true when returned, then the actual elapsed time will be used for animation. + * If false when returned, then there should NOT be any animation progression in the next Update. + * @param[in] updateRequired Whether another update is required. + * @param[out] timeToSleepUntil The time in nanoseconds to put the thread to sleep until. * @return false, if the thread should stop. */ - bool UpdateRenderReady( bool& useElapsedTime, bool updateRequired ); + bool UpdateRenderReady( bool& useElapsedTime, bool updateRequired, uint64_t& timeToSleepUntil ); /** * Checks to see if the surface needs to be replaced.