From e3ef4d1855ed7cca17b171267048fbba3a8ce435 Mon Sep 17 00:00:00 2001 From: David Steele Date: Fri, 22 Aug 2014 11:01:37 +0100 Subject: [PATCH] Moved FrameTime from Core to Adaptor [Problem] Core::Update was second-guessing VSyncMonitor. [Solution] Moved FrameTime from Core to Adaptor; now passes in elapsed time and last/next vsync times to Core::Update(). Updated test harness Change-Id: I9852d240c9d152219f00f6d217ab8e8b265435af Signed-off-by: David Steele --- adaptors/base/file.list | 1 + adaptors/base/frame-time.cpp | 229 +++++++++++++++++++++ adaptors/base/frame-time.h | 139 +++++++++++++ adaptors/base/render-thread.cpp | 10 +- adaptors/base/update-render-controller.cpp | 10 +- adaptors/base/update-render-controller.h | 6 + adaptors/base/update-render-synchronization.cpp | 37 +++- adaptors/base/update-render-synchronization.h | 35 +++- adaptors/base/update-thread.cpp | 9 +- adaptors/base/vsync-notifier.cpp | 8 +- adaptors/common/adaptor-impl.cpp | 10 + adaptors/x11/ecore-x-render-surface.cpp | 1 + .../dali-test-suite-utils/test-application.cpp | 30 +-- .../dali-test-suite-utils/test-application.h | 6 +- 14 files changed, 493 insertions(+), 38 deletions(-) create mode 100644 adaptors/base/frame-time.cpp create mode 100644 adaptors/base/frame-time.h diff --git a/adaptors/base/file.list b/adaptors/base/file.list index 5f29336..9e38a94 100644 --- a/adaptors/base/file.list +++ b/adaptors/base/file.list @@ -1,6 +1,7 @@ # Add local source files here base_adaptor_src_files = \ + $(base_adaptor_src_dir)/frame-time.cpp \ $(base_adaptor_src_dir)/render-thread.cpp \ $(base_adaptor_src_dir)/update-thread.cpp \ $(base_adaptor_src_dir)/update-render-synchronization.cpp \ diff --git a/adaptors/base/frame-time.cpp b/adaptors/base/frame-time.cpp new file mode 100644 index 0000000..e726992 --- /dev/null +++ b/adaptors/base/frame-time.cpp @@ -0,0 +1,229 @@ +/* + * Copyright (c) 2014 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +// CLASS HEADER +#include "frame-time.h" + +// INTERNAL INCLUDES +#include +#include + +namespace Dali +{ + +using Integration::PlatformAbstraction; + +namespace Internal +{ +namespace Adaptor +{ + +namespace +{ +#if defined(DEBUG_ENABLED) +Integration::Log::Filter* gLogFilter = Integration::Log::Filter::New(Debug::NoLogging, false, "LOG_FRAME_TIME"); +#endif + +const unsigned int DEFAULT_MINIMUM_FRAME_TIME_INTERVAL( 16667u ); + +const unsigned int MICROSECONDS_PER_SECOND( 1000000u ); +const unsigned int MICROSECONDS_PER_MILLISECOND( 1000u ); + +const float MICROSECONDS_TO_SECONDS( 0.000001f ); + +const unsigned int HISTORY_SIZE(3); +} // unnamed namespace + + +FrameTime::FrameTime( PlatformAbstraction& platform ) +: mPlatform( platform ), + mMinimumFrameTimeInterval( DEFAULT_MINIMUM_FRAME_TIME_INTERVAL ), + mLastVSyncTime( 0u ), + mLastVSyncTimeAtUpdate( 0u ), + mLastVSyncFrameNumber( 0u ), + mLastUpdateFrameNumber( 0u ), + mRunning( true ), + mFirstFrame( true ), + writePos( 0u ), + mExtraUpdatesSinceVSync( 0u ) +{ + // Clear buffer + for ( unsigned int i = 0; i < HISTORY_SIZE; ++i ) + { + mPreviousUpdateFrames[i] = 0; + } + + SetLastVSyncTime(); + mLastVSyncTimeAtUpdate = mLastVSyncTime; + + DALI_LOG_INFO( gLogFilter, Debug::Concise, "FrameTime Initialized\n" ); +} + +FrameTime::~FrameTime() +{ +} + +void FrameTime::SetMinimumFrameTimeInterval( unsigned int interval ) +{ + mMinimumFrameTimeInterval = interval; +} + +void FrameTime::SetVSyncTime( unsigned int frameNumber ) +{ + // Only set the render time if we are running + if ( mRunning ) + { + SetLastVSyncTime(); + + mLastVSyncFrameNumber = frameNumber; + + DALI_LOG_INFO( gLogFilter, Debug::General, "FrameTime: Frame: %u: Time: %u\n", mLastVSyncFrameNumber, (unsigned int) ( mLastVSyncTime / MICROSECONDS_PER_MILLISECOND ) ); + } +} + +void FrameTime::Suspend() +{ + mRunning = false; + + // Reset members + mLastVSyncFrameNumber = 0; + mLastUpdateFrameNumber = 0; + writePos = 0; + mExtraUpdatesSinceVSync = 0; + + // Clear buffer + for ( unsigned int i = 0; i < HISTORY_SIZE; ++i ) + { + mPreviousUpdateFrames[i] = 0; + } + + DALI_LOG_INFO( gLogFilter, Debug::Concise, "FrameTime: Suspended\n" ); +} + +void FrameTime::Resume() +{ + DALI_LOG_INFO( gLogFilter, Debug::Concise, "FrameTime: Resuming\n" ); + + SetLastVSyncTime(); // Should only update the last VSync time so the elapsed time during suspension is taken into consideration when we next update. + mFirstFrame = true; + + mRunning = true; +} + +void FrameTime::Sleep() +{ + DALI_LOG_INFO( gLogFilter, Debug::Concise, "FrameTime: Sleeping\n" ); + + // Mimic Suspend behaviour + Suspend(); +} + +void FrameTime::WakeUp() +{ + DALI_LOG_INFO( gLogFilter, Debug::Concise, "FrameTime: Waking Up\n" ); + + SetLastVSyncTime(); + mLastVSyncTimeAtUpdate = mLastVSyncTime; // We do not want any animations to progress as we have just been woken up. + mFirstFrame = true; + + mRunning = true; +} + +void FrameTime::PredictNextVSyncTime( float& lastFrameDeltaSeconds, unsigned int& lastVSyncTimeMilliseconds, unsigned int& nextVSyncTimeMilliseconds ) +{ + if ( mRunning ) + { + const unsigned int minimumFrameTimeInterval( mMinimumFrameTimeInterval ); + const uint64_t lastVSyncTime( mLastVSyncTime ); + const unsigned int lastVSyncFrameNumber( mLastVSyncFrameNumber ); + + float lastFrameDelta( 0.0f ); // Assume the last update frame delta is 0. + unsigned int framesTillNextVSync( 1 ); // Assume next render will be in one VSync frame time. + + unsigned int framesInLastUpdate( lastVSyncFrameNumber - mLastUpdateFrameNumber ); + lastFrameDelta = lastVSyncTime - mLastVSyncTimeAtUpdate; + + // We should only evaluate the previous frame values if this is not the first frame. + if ( !mFirstFrame ) + { + // Check whether we have had any VSyncs since we last did an Update. + if ( framesInLastUpdate == 0 ) + { + // We have had another update before a VSync, increment counter. + ++mExtraUpdatesSinceVSync; + + // This update frame will be rendered mUpdatesSinceVSync later. + framesTillNextVSync += mExtraUpdatesSinceVSync; + } + else + { + mExtraUpdatesSinceVSync = 0; + } + + // If more than one frame elapsed since last Update, then check if this is a recurring theme so we can accurately predict when this Update is rendered. + if ( framesInLastUpdate > 1 ) + { + unsigned int average(0); + for ( unsigned int i = 0; i < HISTORY_SIZE; ++i ) + { + average += mPreviousUpdateFrames[i]; + } + average /= HISTORY_SIZE; + + if ( average > 1 ) + { + // Our average shows a recurring theme, we are missing frames when rendering so calculate number of frames this will take. + framesTillNextVSync = average; + } + } + + // Write the number of frames the last update took to the array. + mPreviousUpdateFrames[writePos] = framesInLastUpdate; + writePos = ( writePos + 1 ) % HISTORY_SIZE; + } + + mLastUpdateFrameNumber = lastVSyncFrameNumber; + mLastVSyncTimeAtUpdate = lastVSyncTime; + mFirstFrame = false; + + // Calculate the time till the next render + unsigned int timeTillNextRender( minimumFrameTimeInterval * framesTillNextVSync ); + + // Set the input variables + lastFrameDeltaSeconds = lastFrameDelta * MICROSECONDS_TO_SECONDS; + lastVSyncTimeMilliseconds = lastVSyncTime / MICROSECONDS_PER_MILLISECOND; + nextVSyncTimeMilliseconds = ( lastVSyncTime + timeTillNextRender ) / MICROSECONDS_PER_MILLISECOND; + + DALI_LOG_INFO( gLogFilter, Debug::General, "FrameTime: Frame: %u, Time: %u, NextTime: %u, LastDelta: %f\n", mLastUpdateFrameNumber, lastVSyncTimeMilliseconds, nextVSyncTimeMilliseconds, lastFrameDeltaSeconds ); + DALI_LOG_INFO( gLogFilter, Debug::Verbose, " FramesInLastUpdate: %u, FramesTillNextVSync: %u\n", framesInLastUpdate, framesTillNextVSync ); + } +} + +inline void FrameTime::SetLastVSyncTime() +{ + unsigned int seconds( 0u ); + unsigned int microseconds( 0u ); + + mPlatform.GetTimeMicroseconds( seconds, microseconds ); + + mLastVSyncTime = seconds; + mLastVSyncTime = ( mLastVSyncTime * MICROSECONDS_PER_SECOND ) + microseconds; +} + +} // namespace Adaptor +} // namespace Internal +} // namespace Dali diff --git a/adaptors/base/frame-time.h b/adaptors/base/frame-time.h new file mode 100644 index 0000000..5c0d7a9 --- /dev/null +++ b/adaptors/base/frame-time.h @@ -0,0 +1,139 @@ +#ifndef __DALI_INTERNAL_ADAPTOR_FRAME_TIME_H__ +#define __DALI_INTERNAL_ADAPTOR_FRAME_TIME_H__ + +/* + * Copyright (c) 2014 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include + +namespace Dali +{ + +namespace Integration +{ +class PlatformAbstraction; +} + +namespace Internal +{ +namespace Adaptor +{ + +/** + * FrameTime stores the time of the last VSync. It can then be used by the update thread to predict + * the current update will be rendered. + */ +class FrameTime +{ +public: + + // Called from Event thread + + /** + * Constructor + * @param[in] platform The platform used to retrieve the current time + */ + FrameTime( Integration::PlatformAbstraction& platform ); + + /** + * Destructor, non virtual + */ + ~FrameTime(); + + /** + * Sets the expected minimum frame time interval. + * @param[in] interval The interval in microseconds. + */ + void SetMinimumFrameTimeInterval( unsigned int interval ); + + /** + * Suspends the FrameTime object when the application state changes + */ + void Suspend(); + + /** + * Resumes the FrameTime object when the application state changes + */ + void Resume(); + + // Called from Update thread + + /** + * Sets the FrameTime object to sleep, i.e. when there are no more updates required. + */ + void Sleep(); + + /** + * Wakes the FrameTime object from a sleep state. + */ + void WakeUp(); + + /** + * Predicts when the next render time will occur. + * + * @param[out] lastFrameDeltaSeconds The delta, in seconds (with float precision), between the last two renders. + * @param[out] lastVSyncTimeMilliseconds The time, in milliseconds, of the last VSync. + * @param[out] nextVSyncTimeMilliseconds The estimated time, in milliseconds, at the next VSync. + * + * @note Should only be called once per tick, from the update thread. + */ + void PredictNextVSyncTime( float& lastFrameDeltaSeconds, unsigned int& lastVSyncTimeMilliseconds, unsigned int& nextVSyncTimeMilliseconds ); + + // Called from VSync thread + + /** + * Tells the FrameTime object that a VSync has occurred. + * + * @param[in] frameNumber The frame number of the current VSync. + * + * @note Should only be called from the VSync thread. + */ + void SetVSyncTime( unsigned int frameNumber ); + +private: + + /** + * Sets the current time to be the last Vsync time. + */ + inline void SetLastVSyncTime(); + +private: + + Integration::PlatformAbstraction& mPlatform; ///< The platform abstraction. + + unsigned int mMinimumFrameTimeInterval; ///< The minimum frame time interval, set by Adaptor. + + uint64_t mLastVSyncTime; ///< The last VSync time (in microseconds). + uint64_t mLastVSyncTimeAtUpdate; ///< The last VSync time at Update (in microseconds). + + unsigned int mLastVSyncFrameNumber; ///< The last VSync frame number + unsigned int mLastUpdateFrameNumber; ///< The last VSync frame number handled in Update. + + bool mRunning:1; ///< The state of the FrameTime object. + bool mFirstFrame:1; ///< Whether the current update is the first frame (after initialisation, resume or wake up). + + unsigned int mPreviousUpdateFrames[3]; ///< Array holding the number of frames Update took in the last three iterations. + unsigned int writePos; ///< The current write position in the array. + + unsigned int mExtraUpdatesSinceVSync; ///< The number of extra updates since the last VSync. +}; + +} // namespace Adaptor +} // namespace Internal +} // namespace Dali + +#endif // __DALI_INTERNAL_ADAPTOR_FRAME_TIME_H__ diff --git a/adaptors/base/render-thread.cpp b/adaptors/base/render-thread.cpp index 6b0fe14..cb100be 100644 --- a/adaptors/base/render-thread.cpp +++ b/adaptors/base/render-thread.cpp @@ -71,15 +71,15 @@ void RenderThread::Start() // initialise GL and kick off render thread DALI_ASSERT_ALWAYS( !mEGL && "Egl already initialized" ); - // Tell core what the minimum frame interval is - mCore.SetMinimumFrameTimeInterval( mCurrent.syncMode * TIME_PER_FRAME_IN_MICROSECONDS ); + // Tell frame timer what the minimum frame interval is + mUpdateRenderSync.SetMinimumFrameTimeInterval( mCurrent.syncMode * TIME_PER_FRAME_IN_MICROSECONDS ); // create the render thread, initially we are rendering mThread = new boost::thread(boost::bind(&RenderThread::Run, this)); // Inform surface to block waiting for RenderSync mCurrent.surface->SetSyncMode( RenderSurface::SYNC_MODE_WAIT ); - } +} void RenderThread::Stop() { @@ -237,6 +237,8 @@ void RenderThread::InitializeEgl() mEGL->MakeContextCurrent(); // set the initial sync mode + + //@todo This needs to call the render surface instead mEGL->SetRefreshSync( mCurrent.syncMode ); // tell core it has a context @@ -265,6 +267,8 @@ void RenderThread::CheckForUpdates() if( mCurrent.syncMode != mNewValues.syncMode ) { mCurrent.syncMode = mNewValues.syncMode; + + //@todo This needs to call the render surface instead mEGL->SetRefreshSync( mCurrent.syncMode ); } diff --git a/adaptors/base/update-render-controller.cpp b/adaptors/base/update-render-controller.cpp index 6011942..cdbbcb5 100644 --- a/adaptors/base/update-render-controller.cpp +++ b/adaptors/base/update-render-controller.cpp @@ -37,12 +37,12 @@ namespace Adaptor { UpdateRenderController::UpdateRenderController( AdaptorInternalServices& adaptorInterfaces, - const EnvironmentOptions& environmentOptions ): mUpdateThread( NULL ), + const EnvironmentOptions& environmentOptions ) +: mUpdateThread( NULL ), mRenderThread( NULL ), mVSyncNotifier( NULL ), mUpdateRenderSync( NULL ) { - mUpdateRenderSync = new UpdateRenderSynchronization( adaptorInterfaces ); mUpdateThread = new UpdateThread( *mUpdateRenderSync, adaptorInterfaces, environmentOptions ); @@ -73,10 +73,16 @@ void UpdateRenderController::Start() void UpdateRenderController::Pause() { mUpdateRenderSync->Pause(); + // if update thread is napping, wake it up to get it to pause in correct place mUpdateRenderSync->UpdateRequested(); } +void UpdateRenderController::ResumeFrameTime() +{ + mUpdateRenderSync->ResumeFrameTime(); +} + void UpdateRenderController::Resume() { mUpdateRenderSync->Resume(); diff --git a/adaptors/base/update-render-controller.h b/adaptors/base/update-render-controller.h index fd602cd..7e49c2d 100644 --- a/adaptors/base/update-render-controller.h +++ b/adaptors/base/update-render-controller.h @@ -73,6 +73,12 @@ public: void Stop(); /** + * Ensure the frame time values are reset before the next call to Core::Update() + * following a Resume application state change. + */ + void ResumeFrameTime(); + + /** * Called by the adaptor when core requires another update */ void RequestUpdate(); diff --git a/adaptors/base/update-render-synchronization.cpp b/adaptors/base/update-render-synchronization.cpp index 1464445..de2ebfc 100644 --- a/adaptors/base/update-render-synchronization.cpp +++ b/adaptors/base/update-render-synchronization.cpp @@ -51,7 +51,7 @@ UpdateRenderSynchronization::UpdateRenderSynchronization( AdaptorInternalService mVSyncFrameNumber( 0u ), mVSyncSeconds( 0u ), mVSyncMicroseconds( 0u ), - mCore( adaptorInterfaces.GetCore() ), + mFrameTime( adaptorInterfaces.GetPlatformAbstractionInterface() ), mPerformanceInterface( adaptorInterfaces.GetPerformanceInterface() ) { } @@ -81,6 +81,8 @@ void UpdateRenderSynchronization::Stop() mRenderFinishedCondition.notify_one(); mVSyncSleepCondition.notify_one(); mVSyncReceivedCondition.notify_one(); + + mFrameTime.Suspend(); } void UpdateRenderSynchronization::Pause() @@ -88,7 +90,12 @@ void UpdateRenderSynchronization::Pause() mPaused = true; AddPerformanceMarker( PerformanceMarker::PAUSED ); + mFrameTime.Suspend(); +} +void UpdateRenderSynchronization::ResumeFrameTime() +{ + mFrameTime.Resume(); } void UpdateRenderSynchronization::Resume() @@ -215,8 +222,8 @@ bool UpdateRenderSynchronization::UpdateTryToSleep() // 1. put VSync thread to sleep. mVSyncSleep = true; - // 2. inform Core - mCore.Sleep(); + // 2. inform frame time + mFrameTime.Sleep(); // 3. block thread and wait for wakeup event mUpdateSleepCondition.wait( lock ); @@ -225,8 +232,8 @@ bool UpdateRenderSynchronization::UpdateTryToSleep() // Woken up // - // 1. inform Core - mCore.WakeUp(); + // 1. inform frame timer + mFrameTime.WakeUp(); // 2. wake VSync thread. mVSyncSleep = false; @@ -299,8 +306,13 @@ void UpdateRenderSynchronization::WaitVSync() mAllowUpdateWhilePaused = false; } -bool UpdateRenderSynchronization::VSyncNotifierSyncWithUpdateAndRender( unsigned int frameNumber, unsigned int seconds, unsigned int microseconds ) +bool UpdateRenderSynchronization::VSyncNotifierSyncWithUpdateAndRender( bool validSync, unsigned int frameNumber, unsigned int seconds, unsigned int microseconds ) { + if( validSync ) + { + mFrameTime.SetVSyncTime( frameNumber ); + } + boost::unique_lock< boost::mutex > lock( mMutex ); mVSyncFrameNumber = frameNumber; @@ -351,6 +363,19 @@ inline void UpdateRenderSynchronization::AddPerformanceMarker( PerformanceMarker } } +void UpdateRenderSynchronization::SetMinimumFrameTimeInterval( unsigned int timeInterval ) +{ + mFrameTime.SetMinimumFrameTimeInterval( timeInterval ); +} + +void UpdateRenderSynchronization::PredictNextVSyncTime( + float& lastFrameDeltaSeconds, + unsigned int& lastVSyncTimeMilliseconds, + unsigned int& nextVSyncTimeMilliseconds ) +{ + mFrameTime.PredictNextVSyncTime( lastFrameDeltaSeconds, lastVSyncTimeMilliseconds, nextVSyncTimeMilliseconds ); +} + } // namespace Adaptor } // namespace Internal diff --git a/adaptors/base/update-render-synchronization.h b/adaptors/base/update-render-synchronization.h index 1ab55b1..fd0ff24 100644 --- a/adaptors/base/update-render-synchronization.h +++ b/adaptors/base/update-render-synchronization.h @@ -20,6 +20,7 @@ // INTERNAL INCLUDES #include +#include // EXTERNAL INCLUDES #include @@ -87,6 +88,11 @@ public: void Resume(); /** + * Resume the frame time predictor + */ + void ResumeFrameTime(); + + /** * Wake update thread if sleeping. If the update thread is not sleeping * this becomes a noop. * Called when an update is requested by Core. @@ -148,9 +154,32 @@ public: /** * Called by the VSync notifier thread so it can sleep if Update/Render threads are sleeping/paused + * @param[in] validSync True if the sync was valid (@see VSyncMonitor::DoSync) + * @param[in] frameNumber The current frame number + * @param[in] seconds The current time + * @param[in] microseconds The current time * @return true if VSync monitoring/notifications should continue. */ - bool VSyncNotifierSyncWithUpdateAndRender( unsigned int frameNumber, unsigned int seconds, unsigned int microseconds ); + bool VSyncNotifierSyncWithUpdateAndRender( bool validSync, unsigned int frameNumber, unsigned int seconds, unsigned int microseconds ); + + /** + * Sets the expected minimum frame time interval. + * @param[in] interval The interval in microseconds. + */ + void SetMinimumFrameTimeInterval( unsigned int timeInterval ); + + /** + * Predicts when the next render time will occur. + * + * @param[out] lastFrameDeltaSeconds The delta, in seconds (with float precision), between the last two renders. + * @param[out] lastVSyncTimeMilliseconds The time, in milliseconds, of the last VSync. + * @param[out] nextVSyncTimeMilliseconds The estimated time, in milliseconds, at the next VSync. + * + * @note Should only be called once per tick, from the update thread. + */ + void PredictNextVSyncTime( float& lastFrameDeltaSeconds, + unsigned int& lastVSyncTimeMilliseconds, + unsigned int& nextVSyncTimeMilliseconds ); /** * Retrieves the last VSync frame number @@ -201,8 +230,8 @@ private: boost::condition_variable mVSyncSleepCondition; ///< The vsync thread waits for this condition boost::condition_variable mPausedCondition; ///< The controller waits for this condition while paused - Dali::Integration::Core& mCore; ///< Dali core reference - PerformanceInterface* mPerformanceInterface;///< The performance logging interface + FrameTime mFrameTime; ///< Frame timer predicts next vsync time + PerformanceInterface* mPerformanceInterface; ///< The performance logging interface }; // class UpdateRenderSynchronization diff --git a/adaptors/base/update-thread.cpp b/adaptors/base/update-thread.cpp index ac2c27c..33ee373 100644 --- a/adaptors/base/update-thread.cpp +++ b/adaptors/base/update-thread.cpp @@ -111,8 +111,13 @@ bool UpdateThread::Run() // Inform synchronization object update is ready to run, this will pause update thread if required. mUpdateRenderSync.UpdateReadyToRun(); - // Do the update - mCore.Update( status ); + // get the last delta and the predict when this update will be rendered + float lastFrameDelta( 0.0f ); + unsigned int lastVSyncTime( 0 ); + unsigned int nextVSyncTime( 0 ); + mUpdateRenderSync.PredictNextVSyncTime( lastFrameDelta, lastVSyncTime, nextVSyncTime ); + + mCore.Update( lastFrameDelta, lastVSyncTime, nextVSyncTime, status ); if( mFpsTrackingSeconds > 0 ) { diff --git a/adaptors/base/vsync-notifier.cpp b/adaptors/base/vsync-notifier.cpp index 33125fe..82296e4 100644 --- a/adaptors/base/vsync-notifier.cpp +++ b/adaptors/base/vsync-notifier.cpp @@ -153,13 +153,7 @@ void VSyncNotifier::Run() } } - if( validSync ) - { - // call Core::VSync with frame number and time stamp - mCore.VSync( ++frameNumber, currentSeconds, currentMicroseconds ); - } - - running = mUpdateRenderSync.VSyncNotifierSyncWithUpdateAndRender( frameNumber, currentSeconds, currentMicroseconds ); + running = mUpdateRenderSync.VSyncNotifierSyncWithUpdateAndRender( validSync, ++frameNumber, currentSeconds, currentMicroseconds ); } // uninstall a function for logging diff --git a/adaptors/common/adaptor-impl.cpp b/adaptors/common/adaptor-impl.cpp index 8701c81..3482250 100644 --- a/adaptors/common/adaptor-impl.cpp +++ b/adaptors/common/adaptor-impl.cpp @@ -378,8 +378,18 @@ void Adaptor::Resume() // Only resume the adaptor if we are in the suspended state. if( PAUSED == mState ) { + // We put ResumeFrameTime first, as this was originally called at the start of mCore->Resume() + // If there were events pending, mCore->Resume() will call + // RenderController->RequestUpdate() + // UpdateRenderController->RequestUpdate() + // UpdateRenderSynchronization->RequestUpdate() + // and we should have reset the frame timers before allowing Core->Update() to be called. + //@todo Should we call UpdateRenderController->Resume before mCore->Resume()? + + mUpdateRenderController->ResumeFrameTime(); mCore->Resume(); mUpdateRenderController->Resume(); + mState = RUNNING; // Reset the event handler when adaptor resumed diff --git a/adaptors/x11/ecore-x-render-surface.cpp b/adaptors/x11/ecore-x-render-surface.cpp index 79ba5da..f831dbf 100644 --- a/adaptors/x11/ecore-x-render-surface.cpp +++ b/adaptors/x11/ecore-x-render-surface.cpp @@ -338,6 +338,7 @@ void RenderSurface::DoRenderSync( unsigned int timeDelta, SyncMode syncMode ) else if( mRenderMode > Dali::RenderSurface::RENDER_SYNC ) { unsigned int syncPeriod( MICROSECONDS_PER_SECOND / static_cast< unsigned int >( mRenderMode ) - MILLISECONDS_PER_SECOND ); + if( timeDelta < syncPeriod ) { usleep( syncPeriod - timeDelta ); diff --git a/automated-tests/src/dali-adaptor/dali-test-suite-utils/test-application.cpp b/automated-tests/src/dali-adaptor/dali-test-suite-utils/test-application.cpp index ea7e48e..c2680b2 100644 --- a/automated-tests/src/dali-adaptor/dali-test-suite-utils/test-application.cpp +++ b/automated-tests/src/dali-adaptor/dali-test-suite-utils/test-application.cpp @@ -29,7 +29,8 @@ TestApplication::TestApplication( size_t surfaceWidth, mSurfaceWidth( surfaceWidth ), mSurfaceHeight( surfaceHeight ), mFrame( 0u ), - mDpi( horizontalDpi, verticalDpi ) + mDpi( horizontalDpi, verticalDpi ), + mLastVSyncTime(0u) { Initialize(); } @@ -142,15 +143,23 @@ void TestApplication::SetSurfaceWidth( unsigned int width, unsigned height ) mCore->SurfaceResized( mSurfaceWidth, mSurfaceHeight ); } -bool TestApplication::Render( unsigned int intervalMilliseconds ) +void TestApplication::DoUpdate( unsigned int intervalMilliseconds ) { - // Update Time values - mPlatformAbstraction.IncrementGetTimeResult( intervalMilliseconds ); unsigned int seconds(0u), microseconds(0u); mPlatformAbstraction.GetTimeMicroseconds( seconds, microseconds ); + mLastVSyncTime = ( seconds * 1e3 ) + ( microseconds / 1e3 ); + unsigned int nextVSyncTime = mLastVSyncTime + 16; + + // Update Time values + mPlatformAbstraction.IncrementGetTimeResult( intervalMilliseconds ); + + float elapsedSeconds = intervalMilliseconds / 1e3f; + mCore->Update( elapsedSeconds, mLastVSyncTime, nextVSyncTime, mStatus ); +} - mCore->VSync( mFrame, seconds, microseconds ); - mCore->Update( mStatus ); +bool TestApplication::Render( unsigned int intervalMilliseconds ) +{ + DoUpdate( intervalMilliseconds ); mCore->Render( mRenderStatus ); mFrame++; @@ -165,14 +174,7 @@ unsigned int TestApplication::GetUpdateStatus() bool TestApplication::UpdateOnly( unsigned int intervalMilliseconds ) { - // Update Time values - mPlatformAbstraction.IncrementGetTimeResult( intervalMilliseconds ); - unsigned int seconds(0u), microseconds(0u); - mPlatformAbstraction.GetTimeMicroseconds( seconds, microseconds ); - - mCore->VSync( mFrame, seconds, microseconds ); - mCore->Update( mStatus ); - + DoUpdate( intervalMilliseconds ); return mStatus.KeepUpdating(); } diff --git a/automated-tests/src/dali-adaptor/dali-test-suite-utils/test-application.h b/automated-tests/src/dali-adaptor/dali-test-suite-utils/test-application.h index 4084f2d..8107b35 100644 --- a/automated-tests/src/dali-adaptor/dali-test-suite-utils/test-application.h +++ b/automated-tests/src/dali-adaptor/dali-test-suite-utils/test-application.h @@ -76,7 +76,10 @@ public: bool RenderOnly( ); void ResetContext(); -protected: +private: + void DoUpdate( unsigned int intervalMilliseconds ); + + protected: TestPlatformAbstraction mPlatformAbstraction; TestRenderController mRenderController; TestGlAbstraction mGlAbstraction; @@ -93,6 +96,7 @@ protected: unsigned int mFrame; Vector2 mDpi; + unsigned int mLastVSyncTime; }; } // Dali -- 2.7.4