From c0cefe16f3321581dfaeb88bb6e60bcb7801d355 Mon Sep 17 00:00:00 2001 From: David Steele Date: Fri, 22 Aug 2014 18:40:12 +0100 Subject: [PATCH] Redesigning render sync to handle reduced frequency [Problem] Update and render timers are out of step with expected results. [Solution] Manage frame skipping and synchronisation with VSync in a single place. Moved all compositor syncing to reside in PixmapRenderSurface only. Change-Id: I5577fc2c4c4d2ac7fb514a01c4956e402a31a038 Signed-off-by: David Steele --- adaptors/base/frame-time.cpp | 78 +++++++++++----------- adaptors/base/frame-time.h | 24 +++---- .../base/interfaces/adaptor-internal-services.h | 1 - adaptors/base/interfaces/egl-interface.h | 15 ----- adaptors/base/interfaces/vsync-monitor-interface.h | 4 +- .../performance-logging/performance-server.cpp | 1 + adaptors/base/render-thread.cpp | 64 +++++++----------- adaptors/base/render-thread.h | 8 --- adaptors/base/update-render-controller.cpp | 14 ++-- adaptors/base/update-render-controller.h | 10 +-- adaptors/base/update-render-synchronization.cpp | 69 ++++++++++--------- adaptors/base/update-render-synchronization.h | 45 ++++++++----- adaptors/base/update-thread.cpp | 23 +++++-- adaptors/base/vsync-notifier.cpp | 52 +++++++++------ adaptors/base/vsync-notifier.h | 5 +- adaptors/common/adaptor-impl.cpp | 17 +++-- adaptors/common/adaptor-impl.h | 17 +++-- adaptors/common/application-impl.cpp | 2 +- adaptors/common/gl/egl-implementation.h | 7 -- adaptors/common/render-surface-impl.h | 25 +++---- adaptors/common/vsync-monitor.h | 12 +++- adaptors/public-api/adaptor-framework/adaptor.cpp | 15 +++++ adaptors/public-api/adaptor-framework/adaptor.h | 29 ++++++++ .../public-api/adaptor-framework/render-surface.h | 26 -------- adaptors/tizen/vsync-monitor-tizen.cpp | 17 +++-- adaptors/ubuntu/vsync-monitor-ubuntu.cpp | 17 ++--- adaptors/wayland/ecore-wl-render-surface.cpp | 57 +--------------- adaptors/wayland/ecore-wl-render-surface.h | 43 +----------- adaptors/wayland/egl-implementation-wl.cpp | 32 --------- adaptors/wayland/pixmap-render-surface-wl.cpp | 27 +++++--- adaptors/wayland/pixmap-render-surface.h | 31 ++++++++- adaptors/wayland/window-render-surface-wl.cpp | 15 ++++- adaptors/wayland/window-render-surface.h | 17 ++++- adaptors/x11/ecore-x-render-surface.cpp | 59 +--------------- adaptors/x11/ecore-x-render-surface.h | 43 +----------- adaptors/x11/egl-implementation-x.cpp | 33 --------- adaptors/x11/pixmap-render-surface-x.cpp | 42 ++++++++++-- adaptors/x11/pixmap-render-surface.h | 40 +++++++++-- adaptors/x11/window-render-surface-x.cpp | 15 ++++- adaptors/x11/window-render-surface.h | 17 ++++- 40 files changed, 500 insertions(+), 568 deletions(-) diff --git a/adaptors/base/frame-time.cpp b/adaptors/base/frame-time.cpp index e726992..6c08241 100644 --- a/adaptors/base/frame-time.cpp +++ b/adaptors/base/frame-time.cpp @@ -52,14 +52,14 @@ const unsigned int HISTORY_SIZE(3); FrameTime::FrameTime( PlatformAbstraction& platform ) : mPlatform( platform ), mMinimumFrameTimeInterval( DEFAULT_MINIMUM_FRAME_TIME_INTERVAL ), - mLastVSyncTime( 0u ), - mLastVSyncTimeAtUpdate( 0u ), - mLastVSyncFrameNumber( 0u ), + mLastSyncTime( 0u ), + mLastSyncTimeAtUpdate( 0u ), + mLastSyncFrameNumber( 0u ), mLastUpdateFrameNumber( 0u ), mRunning( true ), mFirstFrame( true ), writePos( 0u ), - mExtraUpdatesSinceVSync( 0u ) + mExtraUpdatesSinceSync( 0u ) { // Clear buffer for ( unsigned int i = 0; i < HISTORY_SIZE; ++i ) @@ -67,8 +67,8 @@ FrameTime::FrameTime( PlatformAbstraction& platform ) mPreviousUpdateFrames[i] = 0; } - SetLastVSyncTime(); - mLastVSyncTimeAtUpdate = mLastVSyncTime; + SetLastSyncTime(); + mLastSyncTimeAtUpdate = mLastSyncTime; DALI_LOG_INFO( gLogFilter, Debug::Concise, "FrameTime Initialized\n" ); } @@ -82,16 +82,16 @@ void FrameTime::SetMinimumFrameTimeInterval( unsigned int interval ) mMinimumFrameTimeInterval = interval; } -void FrameTime::SetVSyncTime( unsigned int frameNumber ) +void FrameTime::SetSyncTime( unsigned int frameNumber ) { // Only set the render time if we are running if ( mRunning ) { - SetLastVSyncTime(); + SetLastSyncTime(); - mLastVSyncFrameNumber = frameNumber; + mLastSyncFrameNumber = frameNumber; - DALI_LOG_INFO( gLogFilter, Debug::General, "FrameTime: Frame: %u: Time: %u\n", mLastVSyncFrameNumber, (unsigned int) ( mLastVSyncTime / MICROSECONDS_PER_MILLISECOND ) ); + DALI_LOG_INFO( gLogFilter, Debug::General, "FrameTime: SetSyncTime(): Frame: %u: Time: %u\n", mLastSyncFrameNumber, (unsigned int) ( mLastSyncTime / MICROSECONDS_PER_MILLISECOND ) ); } } @@ -100,10 +100,10 @@ void FrameTime::Suspend() mRunning = false; // Reset members - mLastVSyncFrameNumber = 0; + mLastSyncFrameNumber = 0; mLastUpdateFrameNumber = 0; writePos = 0; - mExtraUpdatesSinceVSync = 0; + mExtraUpdatesSinceSync = 0; // Clear buffer for ( unsigned int i = 0; i < HISTORY_SIZE; ++i ) @@ -118,7 +118,7 @@ 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. + SetLastSyncTime(); // Should only update the last Sync time so the elapsed time during suspension is taken into consideration when we next update. mFirstFrame = true; mRunning = true; @@ -136,47 +136,48 @@ 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. + SetLastSyncTime(); + mLastSyncTimeAtUpdate = mLastSyncTime; // 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 ) +void FrameTime::PredictNextSyncTime( float& lastFrameDeltaSeconds, unsigned int& lastSyncTimeMilliseconds, unsigned int& nextSyncTimeMilliseconds ) { if ( mRunning ) { const unsigned int minimumFrameTimeInterval( mMinimumFrameTimeInterval ); - const uint64_t lastVSyncTime( mLastVSyncTime ); - const unsigned int lastVSyncFrameNumber( mLastVSyncFrameNumber ); + const uint64_t lastSyncTime( mLastSyncTime ); + const unsigned int lastSyncFrameNumber( mLastSyncFrameNumber ); 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 framesTillNextSync( 1 ); // Assume next render will be in one Sync frame time. - unsigned int framesInLastUpdate( lastVSyncFrameNumber - mLastUpdateFrameNumber ); - lastFrameDelta = lastVSyncTime - mLastVSyncTimeAtUpdate; + unsigned int framesInLastUpdate( lastSyncFrameNumber - mLastUpdateFrameNumber ); + lastFrameDelta = lastSyncTime - mLastSyncTimeAtUpdate; // 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. + // Check whether we have had any Syncs since we last did an Update. if ( framesInLastUpdate == 0 ) { - // We have had another update before a VSync, increment counter. - ++mExtraUpdatesSinceVSync; + // We have had another update before a Sync, increment counter. + ++mExtraUpdatesSinceSync; - // This update frame will be rendered mUpdatesSinceVSync later. - framesTillNextVSync += mExtraUpdatesSinceVSync; + // This update frame will be rendered mUpdatesSinceSync later. + framesTillNextSync += mExtraUpdatesSinceSync; + DALI_LOG_INFO(gLogFilter, Debug::Concise, "PredictNextSyncTime UpdateBeforeSync\n"); } else { - mExtraUpdatesSinceVSync = 0; + mExtraUpdatesSinceSync = 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 ) { + DALI_LOG_INFO(gLogFilter, Debug::Concise, "PredictNextSyncTime framesInLastUpdate:%u\n", framesInLastUpdate); unsigned int average(0); for ( unsigned int i = 0; i < HISTORY_SIZE; ++i ) { @@ -187,7 +188,7 @@ void FrameTime::PredictNextVSyncTime( float& lastFrameDeltaSeconds, unsigned int 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; + framesTillNextSync = average; } } @@ -196,32 +197,31 @@ void FrameTime::PredictNextVSyncTime( float& lastFrameDeltaSeconds, unsigned int writePos = ( writePos + 1 ) % HISTORY_SIZE; } - mLastUpdateFrameNumber = lastVSyncFrameNumber; - mLastVSyncTimeAtUpdate = lastVSyncTime; + mLastUpdateFrameNumber = lastSyncFrameNumber; + mLastSyncTimeAtUpdate = lastSyncTime; mFirstFrame = false; // Calculate the time till the next render - unsigned int timeTillNextRender( minimumFrameTimeInterval * framesTillNextVSync ); + unsigned int timeTillNextRender( minimumFrameTimeInterval * framesTillNextSync ); // Set the input variables lastFrameDeltaSeconds = lastFrameDelta * MICROSECONDS_TO_SECONDS; - lastVSyncTimeMilliseconds = lastVSyncTime / MICROSECONDS_PER_MILLISECOND; - nextVSyncTimeMilliseconds = ( lastVSyncTime + timeTillNextRender ) / MICROSECONDS_PER_MILLISECOND; + lastSyncTimeMilliseconds = lastSyncTime / MICROSECONDS_PER_MILLISECOND; + nextSyncTimeMilliseconds = ( lastSyncTime + 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 ); + DALI_LOG_INFO( gLogFilter, Debug::General, "FrameTime: Frame: %u, Time: %u, NextTime: %u, LastDelta: %f\n", mLastUpdateFrameNumber, lastSyncTimeMilliseconds, nextSyncTimeMilliseconds, lastFrameDeltaSeconds ); + DALI_LOG_INFO( gLogFilter, Debug::Verbose, " FramesInLastUpdate: %u, FramesTillNextSync: %u\n", framesInLastUpdate, framesTillNextSync ); } } -inline void FrameTime::SetLastVSyncTime() +inline void FrameTime::SetLastSyncTime() { unsigned int seconds( 0u ); unsigned int microseconds( 0u ); mPlatform.GetTimeMicroseconds( seconds, microseconds ); - mLastVSyncTime = seconds; - mLastVSyncTime = ( mLastVSyncTime * MICROSECONDS_PER_SECOND ) + microseconds; + mLastSyncTime = ( seconds * MICROSECONDS_PER_SECOND ) + microseconds; } } // namespace Adaptor diff --git a/adaptors/base/frame-time.h b/adaptors/base/frame-time.h index 5c0d7a9..06881d8 100644 --- a/adaptors/base/frame-time.h +++ b/adaptors/base/frame-time.h @@ -86,30 +86,30 @@ public: * 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. + * @param[out] lastSyncTimeMilliseconds The time, in milliseconds, of the last Sync. + * @param[out] nextSyncTimeMilliseconds The estimated time, in milliseconds, at the next Sync. * * @note Should only be called once per tick, from the update thread. */ - void PredictNextVSyncTime( float& lastFrameDeltaSeconds, unsigned int& lastVSyncTimeMilliseconds, unsigned int& nextVSyncTimeMilliseconds ); + void PredictNextSyncTime( float& lastFrameDeltaSeconds, unsigned int& lastVSyncTimeMilliseconds, unsigned int& nextVSyncTimeMilliseconds ); // Called from VSync thread /** - * Tells the FrameTime object that a VSync has occurred. + * Tells the FrameTime object that a Sync has occurred. * - * @param[in] frameNumber The frame number of the current VSync. + * @param[in] frameNumber The frame number of the current Sync. * * @note Should only be called from the VSync thread. */ - void SetVSyncTime( unsigned int frameNumber ); + void SetSyncTime( unsigned int frameNumber ); private: /** * Sets the current time to be the last Vsync time. */ - inline void SetLastVSyncTime(); + inline void SetLastSyncTime(); private: @@ -117,11 +117,11 @@ private: 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). + uint64_t mLastSyncTime; ///< The last Sync time (in microseconds). + uint64_t mLastSyncTimeAtUpdate; ///< The last Sync time at Update (in microseconds). - unsigned int mLastVSyncFrameNumber; ///< The last VSync frame number - unsigned int mLastUpdateFrameNumber; ///< The last VSync frame number handled in Update. + unsigned int mLastSyncFrameNumber; ///< The last Sync frame number + unsigned int mLastUpdateFrameNumber; ///< The last Sync 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). @@ -129,7 +129,7 @@ private: 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. + unsigned int mExtraUpdatesSinceSync; ///< The number of extra updates since the last Sync. }; } // namespace Adaptor diff --git a/adaptors/base/interfaces/adaptor-internal-services.h b/adaptors/base/interfaces/adaptor-internal-services.h index 5ed86a6..8585a92 100644 --- a/adaptors/base/interfaces/adaptor-internal-services.h +++ b/adaptors/base/interfaces/adaptor-internal-services.h @@ -19,7 +19,6 @@ */ // INTERNAL INCLUDES -#include #include #include #include diff --git a/adaptors/base/interfaces/egl-interface.h b/adaptors/base/interfaces/egl-interface.h index 9eaffaa..9eb006f 100644 --- a/adaptors/base/interfaces/egl-interface.h +++ b/adaptors/base/interfaces/egl-interface.h @@ -31,14 +31,6 @@ namespace Adaptor class EglInterface { public: - enum SyncMode - { - NO_SYNC = 0, ///< not synchronised to display (driver might over-ride?) - FULL_SYNC = 1, ///< redraw at display refresh rate - HALF_SYNC = 2, ///< redraw at half display refresh rate - QUARTER_SYNC = 4 ///< redraw at quarter display refresh rate - }; - /** * Create the OpenGL context. * @return true if successful @@ -56,12 +48,6 @@ public: virtual void TerminateGles() = 0; /** - * Sets the refresh sync mode. - * @see SyncMode - */ - virtual bool SetRefreshSync( SyncMode mode ) = 0; - - /** * Performs an OpenGL swap buffers command */ virtual void SwapBuffers() = 0; @@ -90,4 +76,3 @@ protected: } // namespace Dali #endif // __DALI_INTERNAL_ADAPTOR_BASE_EGL_INTERFACE_H__ - diff --git a/adaptors/base/interfaces/vsync-monitor-interface.h b/adaptors/base/interfaces/vsync-monitor-interface.h index 9e90cb4..2fc1145 100644 --- a/adaptors/base/interfaces/vsync-monitor-interface.h +++ b/adaptors/base/interfaces/vsync-monitor-interface.h @@ -49,8 +49,8 @@ public: virtual void Terminate() = 0; /** - * Checks if hardware syncs are available - * @return true if hardware syncs are available + * Checks if hardware sync is available and enabled + * @return true if hardware sync is available and enabled */ virtual bool UseHardware() = 0; diff --git a/adaptors/base/performance-logging/performance-server.cpp b/adaptors/base/performance-logging/performance-server.cpp index 03202aa..6634eec 100644 --- a/adaptors/base/performance-logging/performance-server.cpp +++ b/adaptors/base/performance-logging/performance-server.cpp @@ -20,6 +20,7 @@ // INTERNAL INCLUDES #include +#include namespace Dali { diff --git a/adaptors/base/render-thread.cpp b/adaptors/base/render-thread.cpp index cb100be..35566bf 100644 --- a/adaptors/base/render-thread.cpp +++ b/adaptors/base/render-thread.cpp @@ -37,10 +37,10 @@ namespace Adaptor namespace { - -const unsigned int TIME_PER_FRAME_IN_MICROSECONDS = 16667; - -} // unnamed namespace +#if defined(DEBUG_ENABLED) +Integration::Log::Filter* gRenderLogFilter = Integration::Log::Filter::New(Debug::NoLogging, false, "LOG_RENDER_THREAD"); +#endif +} RenderThread::RenderThread( UpdateRenderSynchronization& sync, AdaptorInternalServices& adaptorInterfaces, @@ -68,21 +68,21 @@ RenderThread::~RenderThread() void RenderThread::Start() { + DALI_LOG_INFO( gRenderLogFilter, Debug::Verbose, "RenderThread::Start()\n"); + // initialise GL and kick off render thread DALI_ASSERT_ALWAYS( !mEGL && "Egl already initialized" ); - // 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 ); + mCurrent.surface->StartRender(); } void RenderThread::Stop() { + DALI_LOG_INFO( gRenderLogFilter, Debug::Verbose, "RenderThread::Stop()\n"); + // shutdown the render thread and destroy the opengl context if( mThread ) { @@ -99,6 +99,8 @@ void RenderThread::Stop() void RenderThread::ReplaceSurface( RenderSurface* surface ) { + DALI_LOG_INFO( gRenderLogFilter, Debug::Verbose, "RenderThread::ReplaceSurface()\n"); + // Make sure it's a new surface. Note! we are reading the current value of render thread here, but reading is ok DALI_ASSERT_ALWAYS( surface != mCurrent.surface && "Trying to replace surface with itself" ); @@ -116,15 +118,14 @@ void RenderThread::ReplaceSurface( RenderSurface* surface ) mNewValues.surface = surface; } - /* - * Reset the mPixmapFlushed condition if surface was changed. - * : in this case, client can not handle the previous damage because surface was changed. - */ - RenderSync(); + // Ensure the current surface releases any locks. + mCurrent.surface->StopRender(); } void RenderThread::WaitForSurfaceReplaceComplete() { + DALI_LOG_INFO( gRenderLogFilter, Debug::Verbose, "RenderThread::WaitForSurfaceReplaceComplete()\n"); + boost::unique_lock lock( mSurfaceChangedMutex ); // if already completed no need to wait @@ -134,19 +135,6 @@ void RenderThread::WaitForSurfaceReplaceComplete() } } -void RenderThread::SetVSyncMode( EglInterface::SyncMode syncMode ) -{ - // lock cache and set update flag at the end of function - SendMessageGuard msg( *this ); - // set new values to cache - mNewValues.syncMode = syncMode; -} - -void RenderThread::RenderSync() -{ - mCurrent.surface->RenderSync(); -} - ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // The following methods are all executed inside render thread !!! @@ -172,6 +160,8 @@ bool RenderThread::Run() // render loop, we stay inside here when rendering while( running ) { + DALI_LOG_INFO( gRenderLogFilter, Debug::Verbose, "RenderThread::Run. 1 - Begin loop\n"); + // Consume any pending events ConsumeEvents(); @@ -179,12 +169,15 @@ bool RenderThread::Run() CheckForUpdates(); // perform any pre-render operations + DALI_LOG_INFO( gRenderLogFilter, Debug::Verbose, "RenderThread::Run. 2 - PreRender\n"); if(PreRender() == true) { // Render + DALI_LOG_INFO( gRenderLogFilter, Debug::Verbose, "RenderThread::Run. 3 - Core.Render()\n"); mCore.Render( renderStatus ); // Notify the update-thread that a render has completed + DALI_LOG_INFO( gRenderLogFilter, Debug::Verbose, "RenderThread::Run. 4 - Sync.RenderFinished()\n"); mUpdateRenderSync.RenderFinished( renderStatus.NeedsUpdate() ); uint64_t newTime( mUpdateRenderSync.GetTimeMicroseconds() ); @@ -192,6 +185,7 @@ bool RenderThread::Run() // perform any post-render operations if ( renderStatus.HasRendered() ) { + DALI_LOG_INFO( gRenderLogFilter, Debug::Verbose, "RenderThread::Run. 5 - PostRender()\n"); PostRender( static_cast< unsigned int >(newTime - currentTime) ); } @@ -205,6 +199,8 @@ bool RenderThread::Run() currentTime = newTime; } + DALI_LOG_INFO( gRenderLogFilter, Debug::Verbose, "RenderThread::Run. 6 - RenderSyncWithUpdate()\n"); + // Wait until another frame has been updated running = mUpdateRenderSync.RenderSyncWithUpdate(); } @@ -238,8 +234,6 @@ void RenderThread::InitializeEgl() // set the initial sync mode - //@todo This needs to call the render surface instead - mEGL->SetRefreshSync( mCurrent.syncMode ); // tell core it has a context mCore.ContextCreated(); @@ -263,15 +257,6 @@ void RenderThread::CheckForUpdates() // need to lock to access new values boost::unique_lock< boost::mutex > lock( mThreadDataLock ); - // did the sync mode change - if( mCurrent.syncMode != mNewValues.syncMode ) - { - mCurrent.syncMode = mNewValues.syncMode; - - //@todo This needs to call the render surface instead - mEGL->SetRefreshSync( mCurrent.syncMode ); - } - // check if the surface needs replacing if( mNewValues.replaceSurface ) { @@ -350,8 +335,7 @@ void RenderThread::PostRender( unsigned int timeDelta ) mGLES.PostRender(timeDelta); // Inform the surface that rendering this frame has finished. - mCurrent.surface->PostRender( *mEGL, mGLES, timeDelta, - mSurfaceReplacing ? RenderSurface::SYNC_MODE_NONE : RenderSurface::SYNC_MODE_WAIT ); + mCurrent.surface->PostRender( *mEGL, mGLES, timeDelta, mSurfaceReplacing ); } } // namespace Adaptor diff --git a/adaptors/base/render-thread.h b/adaptors/base/render-thread.h index 9e706c2..ff1a4a6 100644 --- a/adaptors/base/render-thread.h +++ b/adaptors/base/render-thread.h @@ -94,12 +94,6 @@ public: void WaitForSurfaceReplaceComplete(); /** - * Sets the EGL VSync mode synchronisation with the display. - * @param syncMode to use - */ - void SetVSyncMode( EglInterface::SyncMode syncMode ); - - /** * Offscreen was posted to onscreen */ void RenderSync(); @@ -187,13 +181,11 @@ private: // Data */ RenderData() : replaceSurface( false ), - syncMode( EglInterface::FULL_SYNC ), surface( NULL ) { } volatile int replaceSurface; ///< whether the surface needs replacing - EglInterface::SyncMode syncMode; ///< sync mode for EGL RenderSurface* surface; ///< Current surface }; diff --git a/adaptors/base/update-render-controller.cpp b/adaptors/base/update-render-controller.cpp index cdbbcb5..4d0ef66 100644 --- a/adaptors/base/update-render-controller.cpp +++ b/adaptors/base/update-render-controller.cpp @@ -41,9 +41,10 @@ UpdateRenderController::UpdateRenderController( AdaptorInternalServices& adaptor : mUpdateThread( NULL ), mRenderThread( NULL ), mVSyncNotifier( NULL ), - mUpdateRenderSync( NULL ) + mUpdateRenderSync( NULL ), + mNumberOfVSyncsPerRender( 1 ) { - mUpdateRenderSync = new UpdateRenderSynchronization( adaptorInterfaces ); + mUpdateRenderSync = new UpdateRenderSynchronization( adaptorInterfaces, mNumberOfVSyncsPerRender ); mUpdateThread = new UpdateThread( *mUpdateRenderSync, adaptorInterfaces, environmentOptions ); @@ -125,15 +126,12 @@ void UpdateRenderController::ReplaceSurface( RenderSurface* surface ) mRenderThread->WaitForSurfaceReplaceComplete(); } -void UpdateRenderController::RenderSync() +void UpdateRenderController::SetRenderRefreshRate(unsigned int numberOfVSyncsPerRender ) { - mRenderThread->RenderSync(); + mNumberOfVSyncsPerRender = numberOfVSyncsPerRender; + mUpdateRenderSync->SetRenderRefreshRate(numberOfVSyncsPerRender); } -void UpdateRenderController::DisableVSync() -{ - mRenderThread->SetVSyncMode( EglInterface::NO_SYNC ); -} } // namespace Adaptor diff --git a/adaptors/base/update-render-controller.h b/adaptors/base/update-render-controller.h index 7e49c2d..aaf5f30 100644 --- a/adaptors/base/update-render-controller.h +++ b/adaptors/base/update-render-controller.h @@ -96,14 +96,9 @@ public: void ReplaceSurface( RenderSurface* surface ); /** - * @copydoc Dali::Adaptor::RenderSync() + * @copydoc Dali::Adaptor::SetRenderRefreshRate() */ - void RenderSync(); - - /** - * @copydoc Dali::Internal::Adaptor::RenderSync() - */ - void DisableVSync(); + void SetRenderRefreshRate( unsigned int numberOfVSyncsPerRender ); private: @@ -117,6 +112,7 @@ private: RenderThread* mRenderThread; ///< The render-thread owned by UpdateRenderController VSyncNotifier* mVSyncNotifier; ///< The vsync-thread owned by UpdateRenderController UpdateRenderSynchronization* mUpdateRenderSync; ///< Used to synchronize the update & render threads; also owned by UpdateRenderController + unsigned int mNumberOfVSyncsPerRender; ///< Frame skipping count }; } // namespace Adaptor diff --git a/adaptors/base/update-render-synchronization.cpp b/adaptors/base/update-render-synchronization.cpp index de2ebfc..2cae3de 100644 --- a/adaptors/base/update-render-synchronization.cpp +++ b/adaptors/base/update-render-synchronization.cpp @@ -33,14 +33,16 @@ namespace Adaptor namespace { - +const unsigned int TIME_PER_FRAME_IN_MICROSECONDS = 16667; const unsigned int MICROSECONDS_PER_SECOND( 1000000 ); const unsigned int INPUT_EVENT_UPDATE_PERIOD( MICROSECONDS_PER_SECOND / 90 ); // period between ecore x event updates } // unnamed namespace -UpdateRenderSynchronization::UpdateRenderSynchronization( AdaptorInternalServices& adaptorInterfaces ) +UpdateRenderSynchronization::UpdateRenderSynchronization( AdaptorInternalServices& adaptorInterfaces, + unsigned int numberOfVSyncsPerRender) : mMaximumUpdateCount( adaptorInterfaces.GetCore().GetMaximumUpdateCount()), + mNumberOfVSyncsPerRender( numberOfVSyncsPerRender ), mUpdateReadyCount( 0u ), mRunning( false ), mUpdateRequired( false ), @@ -48,9 +50,9 @@ UpdateRenderSynchronization::UpdateRenderSynchronization( AdaptorInternalService mUpdateRequested( false ), mAllowUpdateWhilePaused( false ), mVSyncSleep( false ), - mVSyncFrameNumber( 0u ), - mVSyncSeconds( 0u ), - mVSyncMicroseconds( 0u ), + mSyncFrameNumber( 0u ), + mSyncSeconds( 0u ), + mSyncMicroseconds( 0u ), mFrameTime( adaptorInterfaces.GetPlatformAbstractionInterface() ), mPerformanceInterface( adaptorInterfaces.GetPerformanceInterface() ) { @@ -62,6 +64,7 @@ UpdateRenderSynchronization::~UpdateRenderSynchronization() void UpdateRenderSynchronization::Start() { + mFrameTime.SetMinimumFrameTimeInterval( mNumberOfVSyncsPerRender * TIME_PER_FRAME_IN_MICROSECONDS ); mRunning = true; } @@ -154,8 +157,8 @@ void UpdateRenderSynchronization::UpdateReadyToRun() if ( !wokenFromPause ) { - // Wait for the next VSync - WaitVSync(); + // Wait for the next Sync + WaitSync(); } AddPerformanceMarker( PerformanceMarker::UPDATE_START ); @@ -284,18 +287,17 @@ bool UpdateRenderSynchronization::RenderSyncWithUpdate() return mRunning; } -void UpdateRenderSynchronization::WaitVSync() +void UpdateRenderSynchronization::WaitSync() { - // Block until the start of a new vsync. + // Block until the start of a new sync. // If we're experiencing slowdown and are behind by more than a frame - // then we should wait for the next frame as the Video output will also - // do this (lock-step to 60Hz) + // then we should wait for the next frame - unsigned int updateFrameNumber = mVSyncFrameNumber; + unsigned int updateFrameNumber = mSyncFrameNumber; boost::unique_lock< boost::mutex > lock( mMutex ); - while ( mRunning && ( updateFrameNumber == mVSyncFrameNumber ) ) + while ( mRunning && ( updateFrameNumber == mSyncFrameNumber ) ) { // Wait will atomically add the thread to the set of threads waiting on // the condition variable mVSyncReceivedCondition and unlock the mutex. @@ -306,18 +308,25 @@ void UpdateRenderSynchronization::WaitVSync() mAllowUpdateWhilePaused = false; } -bool UpdateRenderSynchronization::VSyncNotifierSyncWithUpdateAndRender( bool validSync, unsigned int frameNumber, unsigned int seconds, unsigned int microseconds ) +bool UpdateRenderSynchronization::VSyncNotifierSyncWithUpdateAndRender( bool validSync, unsigned int frameNumber, unsigned int seconds, unsigned int microseconds, unsigned int& numberOfVSyncsPerRender ) { + // This may have changed since the last sync. Update VSyncNotifier's copy here if so. + if( numberOfVSyncsPerRender != mNumberOfVSyncsPerRender ) + { + numberOfVSyncsPerRender = mNumberOfVSyncsPerRender; // save it back + mFrameTime.SetMinimumFrameTimeInterval( mNumberOfVSyncsPerRender * TIME_PER_FRAME_IN_MICROSECONDS ); + } + if( validSync ) { - mFrameTime.SetVSyncTime( frameNumber ); + mFrameTime.SetSyncTime( frameNumber ); } boost::unique_lock< boost::mutex > lock( mMutex ); - mVSyncFrameNumber = frameNumber; - mVSyncSeconds = seconds; - mVSyncMicroseconds = microseconds; + mSyncFrameNumber = frameNumber; + mSyncSeconds = seconds; + mSyncMicroseconds = microseconds; mVSyncReceivedCondition.notify_all(); @@ -337,7 +346,7 @@ bool UpdateRenderSynchronization::VSyncNotifierSyncWithUpdateAndRender( bool val unsigned int UpdateRenderSynchronization::GetFrameNumber() const { - return mVSyncFrameNumber; + return mSyncFrameNumber; } uint64_t UpdateRenderSynchronization::GetTimeMicroseconds() @@ -347,14 +356,19 @@ uint64_t UpdateRenderSynchronization::GetTimeMicroseconds() { boost::unique_lock< boost::mutex > lock( mMutex ); - currentTime = mVSyncSeconds; + currentTime = mSyncSeconds; currentTime *= MICROSECONDS_PER_SECOND; - currentTime += mVSyncMicroseconds; + currentTime += mSyncMicroseconds; } return currentTime; } +void UpdateRenderSynchronization::SetRenderRefreshRate( unsigned int numberOfVSyncsPerRender ) +{ + mNumberOfVSyncsPerRender = numberOfVSyncsPerRender; +} + inline void UpdateRenderSynchronization::AddPerformanceMarker( PerformanceMarker::MarkerType type ) { if( mPerformanceInterface ) @@ -363,17 +377,12 @@ inline void UpdateRenderSynchronization::AddPerformanceMarker( PerformanceMarker } } -void UpdateRenderSynchronization::SetMinimumFrameTimeInterval( unsigned int timeInterval ) -{ - mFrameTime.SetMinimumFrameTimeInterval( timeInterval ); -} - -void UpdateRenderSynchronization::PredictNextVSyncTime( +void UpdateRenderSynchronization::PredictNextSyncTime( float& lastFrameDeltaSeconds, - unsigned int& lastVSyncTimeMilliseconds, - unsigned int& nextVSyncTimeMilliseconds ) + unsigned int& lastSyncTimeMilliseconds, + unsigned int& nextSyncTimeMilliseconds ) { - mFrameTime.PredictNextVSyncTime( lastFrameDeltaSeconds, lastVSyncTimeMilliseconds, nextVSyncTimeMilliseconds ); + mFrameTime.PredictNextSyncTime( lastFrameDeltaSeconds, lastSyncTimeMilliseconds, nextSyncTimeMilliseconds ); } } // namespace Adaptor diff --git a/adaptors/base/update-render-synchronization.h b/adaptors/base/update-render-synchronization.h index fd0ff24..dc2d37d 100644 --- a/adaptors/base/update-render-synchronization.h +++ b/adaptors/base/update-render-synchronization.h @@ -51,6 +51,7 @@ class AdaptorInternalServices; * The Core::GetMaximumUpdateCount() method determines how many frames may be prepared, ahead of the rendering. * For example if the maximum update count is 2, then Core::Update() for frame N+1 may be processed whilst frame N is being rendered. * However the Core::Update() for frame N+2 may not be called, until the Core::Render() method for frame N has returned. + * */ class UpdateRenderSynchronization { @@ -59,11 +60,12 @@ public: /** * Create an update/render synchronization object. * @param[in] adaptorInterfaces base adaptor interface + * @param[in] numberOfVSyncsPerRender The number of frames per render */ - UpdateRenderSynchronization( AdaptorInternalServices& adaptorInterfaces ); + UpdateRenderSynchronization( AdaptorInternalServices& adaptorInterfaces, unsigned int numberOfVSyncsPerRender ); /** - * Non virtual destructor. Not inteded as base class. + * Non virtual destructor. Not intended as base class. */ ~UpdateRenderSynchronization(); @@ -148,9 +150,9 @@ public: bool RenderSyncWithUpdate(); /** - * Called by the render/update threads to wait for a VSync. + * Called by the render/update threads to wait for a Synchronization */ - void WaitVSync(); + void WaitSync(); /** * Called by the VSync notifier thread so it can sleep if Update/Render threads are sleeping/paused @@ -158,9 +160,10 @@ public: * @param[in] frameNumber The current frame number * @param[in] seconds The current time * @param[in] microseconds The current time + * @param[out] numberOfVSyncsPerRender The number of frames per render. * @return true if VSync monitoring/notifications should continue. */ - bool VSyncNotifierSyncWithUpdateAndRender( bool validSync, unsigned int frameNumber, unsigned int seconds, unsigned int microseconds ); + bool VSyncNotifierSyncWithUpdateAndRender( bool validSync, unsigned int frameNumber, unsigned int seconds, unsigned int microseconds, unsigned int& numberOfVSyncsPerRender ); /** * Sets the expected minimum frame time interval. @@ -172,18 +175,21 @@ public: * 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. + * @param[out] lastSyncTimeMilliseconds The time, in milliseconds, of the last Sync. + * @param[out] nextSyncTimeMilliseconds The estimated time, in milliseconds, at the next Sync. * * @note Should only be called once per tick, from the update thread. */ - void PredictNextVSyncTime( float& lastFrameDeltaSeconds, - unsigned int& lastVSyncTimeMilliseconds, - unsigned int& nextVSyncTimeMilliseconds ); + void PredictNextSyncTime( float& lastFrameDeltaSeconds, + unsigned int& lastSyncTimeMilliseconds, + unsigned int& nextSyncTimeMilliseconds ); /** - * Retrieves the last VSync frame number - * @return The VSync frame number. + * Retrieves the last sync frame number. + * This is a count of the number of synchronised update/render + * frames, not a count of hardware VSync frames. + * + * @return The sync frame number. */ unsigned int GetFrameNumber() const; @@ -193,6 +199,12 @@ public: */ uint64_t GetTimeMicroseconds(); + /** + * Set the refresh rate for rendering + * @param[in] numberOfVSyncsPerRender The number of vsync frames per render + */ + void SetRenderRefreshRate( unsigned int numberOfVSyncsPerRender ); + private: // Undefined copy constructor. @@ -210,6 +222,9 @@ private: private: const unsigned int mMaximumUpdateCount; ///< How many frames may be prepared, ahead of the rendering. + + unsigned int mNumberOfVSyncsPerRender; ///< How many frames for each update/render cycle. + volatile unsigned int mUpdateReadyCount; ///< Incremented after each update, decremented after each render (protected by mMutex) // ARM CPUs perform aligned 32 bit read/writes atomically, so the following variables do not require mutex protection on modification volatile int mRunning; ///< Used during UpdateThread::Stop() to exit the update & render loops @@ -218,9 +233,9 @@ private: volatile int mUpdateRequested; ///< An update has been requested volatile int mAllowUpdateWhilePaused; ///< whether to allow (one) update while paused volatile int mVSyncSleep; ///< Set true when the VSync thread should sleep - volatile unsigned int mVSyncFrameNumber; ///< Frame number of latest VSync - volatile unsigned int mVSyncSeconds; ///< Timestamp (seconds) of latest VSync - volatile unsigned int mVSyncMicroseconds; ///< Timestamp (microseconds) of latest VSync + volatile unsigned int mSyncFrameNumber; ///< Frame number of latest Sync + volatile unsigned int mSyncSeconds; ///< Timestamp (seconds) of latest Sync + volatile unsigned int mSyncMicroseconds; ///< Timestamp (microseconds) of latest Sync boost::mutex mMutex; ///< This mutex must be locked before reading/writing mUpdateReadyCount boost::condition_variable mUpdateFinishedCondition; ///< The render thread waits for this condition diff --git a/adaptors/base/update-thread.cpp b/adaptors/base/update-thread.cpp index 33ee373..5a45d4b 100644 --- a/adaptors/base/update-thread.cpp +++ b/adaptors/base/update-thread.cpp @@ -41,9 +41,11 @@ namespace Adaptor namespace { - const unsigned int MICROSECONDS_PER_MILLISECOND( 1000 ); +#if defined(DEBUG_ENABLED) +Integration::Log::Filter* gUpdateLogFilter = Integration::Log::Filter::New(Debug::NoLogging, false, "LOG_UPDATE_THREAD"); +#endif } // unnamed namespace UpdateThread::UpdateThread( UpdateRenderSynchronization& sync, @@ -77,6 +79,7 @@ UpdateThread::~UpdateThread() void UpdateThread::Start() { + DALI_LOG_INFO( gUpdateLogFilter, Debug::Verbose, "UpdateThread::Start()\n"); if ( !mThread ) { // Create and run the update-thread @@ -86,6 +89,7 @@ void UpdateThread::Start() void UpdateThread::Stop() { + DALI_LOG_INFO( gUpdateLogFilter, Debug::Verbose, "UpdateThread::Stop()\n"); if( mThread ) { // wait for the thread to finish @@ -98,6 +102,7 @@ void UpdateThread::Stop() bool UpdateThread::Run() { + DALI_LOG_INFO( gUpdateLogFilter, Debug::Verbose, "UpdateThread::Run()\n"); Integration::UpdateStatus status; // install a function for logging @@ -108,16 +113,21 @@ bool UpdateThread::Run() // Update loop, we stay inside here while the update-thread is running while ( running ) { + DALI_LOG_INFO( gUpdateLogFilter, Debug::Verbose, "UpdateThread::Run. 1 - Sync()\n"); + // Inform synchronization object update is ready to run, this will pause update thread if required. mUpdateRenderSync.UpdateReadyToRun(); + DALI_LOG_INFO( gUpdateLogFilter, Debug::Verbose, "UpdateThread::Run. 2 - Ready()\n"); // 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 ); + unsigned int lastSyncTime( 0 ); + unsigned int nextSyncTime( 0 ); + mUpdateRenderSync.PredictNextSyncTime( lastFrameDelta, lastSyncTime, nextSyncTime ); - mCore.Update( lastFrameDelta, lastVSyncTime, nextVSyncTime, status ); + DALI_LOG_INFO( gUpdateLogFilter, Debug::Verbose, "UpdateThread::Run. 3 - Update(delta:%f, lastSync:%u, nextSync:%u)\n", lastFrameDelta, lastSyncTime, nextSyncTime); + + mCore.Update( lastFrameDelta, lastSyncTime, nextSyncTime, status ); if( mFpsTrackingSeconds > 0 ) { @@ -136,6 +146,7 @@ bool UpdateThread::Run() // tell the synchronisation class that a buffer has been written to, // and to wait until there is a free buffer to write to running = mUpdateRenderSync.UpdateSyncWithRender( renderNeedsUpdate ); + DALI_LOG_INFO( gUpdateLogFilter, Debug::Verbose, "UpdateThread::Run. 4 - UpdateSyncWithRender complete\n"); if( running ) { @@ -154,6 +165,8 @@ bool UpdateThread::Run() if( !runUpdate ) { + DALI_LOG_INFO( gUpdateLogFilter, Debug::Verbose, "UpdateThread::Run. 5 - Nothing to update, trying to sleep\n"); + running = mUpdateRenderSync.UpdateTryToSleep(); } } diff --git a/adaptors/base/vsync-notifier.cpp b/adaptors/base/vsync-notifier.cpp index 82296e4..ebf7c0e 100644 --- a/adaptors/base/vsync-notifier.cpp +++ b/adaptors/base/vsync-notifier.cpp @@ -16,10 +16,6 @@ */ // EXTERNAL INCLUDES -#include -#include -#include -#include #include #include @@ -43,11 +39,11 @@ namespace Adaptor namespace { -const unsigned int MICROSECONDS_PER_SECOND( 100000u ); +const unsigned int MICROSECONDS_PER_SECOND( 1000000u ); const unsigned int TIME_PER_FRAME_IN_MICROSECONDS( 16667u ); #if defined(DEBUG_ENABLED) -Integration::Log::Filter* gLogFilter = Integration::Log::Filter::New(Debug::Concise, false, "LOG_VSYNC_NOTIFIER"); +Integration::Log::Filter* gSyncLogFilter = Integration::Log::Filter::New(Debug::NoLogging, false, "LOG_VSYNC_NOTIFIER"); #endif } // unnamed namespace @@ -60,20 +56,21 @@ VSyncNotifier::VSyncNotifier( UpdateRenderSynchronization& sync, mPlatformAbstraction( adaptorInterfaces.GetPlatformAbstractionInterface() ), mVSyncMonitor( adaptorInterfaces.GetVSyncMonitorInterface() ), mThread( NULL ), - mEnvironmentOptions( environmentOptions ) + mEnvironmentOptions( environmentOptions ), + mNumberOfVSyncsPerRender(1) { } VSyncNotifier::~VSyncNotifier() { - DALI_LOG_INFO( gLogFilter, Debug::General, "%s\n", __func__ ); + DALI_LOG_INFO( gSyncLogFilter, Debug::General, "%s\n", __func__ ); Stop(); } void VSyncNotifier::Start() { - DALI_LOG_INFO( gLogFilter, Debug::General, "%s\n", __func__ ); + DALI_LOG_INFO( gSyncLogFilter, Debug::General, "%s\n", __func__ ); if ( !mThread ) { @@ -85,7 +82,7 @@ void VSyncNotifier::Start() void VSyncNotifier::Stop() { - DALI_LOG_INFO( gLogFilter, Debug::General, "%s\n", __func__ ); + DALI_LOG_INFO( gSyncLogFilter, Debug::General, "%s\n", __func__ ); if( mThread ) { @@ -112,21 +109,28 @@ void VSyncNotifier::Run() unsigned int frameNumber( 0u ); // frameCount, updated when the thread is paused unsigned int currentSequenceNumber( 0u ); // platform specific vsync sequence number (increments with each vsync) - unsigned int currentSeconds( 0u ); // timestamp at latest vsync - unsigned int currentMicroseconds( 0u ); // timestamp at latest vsync + unsigned int currentSeconds( 0u ); // timestamp at latest sync + unsigned int currentMicroseconds( 0u ); // timestamp at latest sync unsigned int seconds( 0u ); unsigned int microseconds( 0u ); bool running( true ); while( running ) { + DALI_LOG_INFO( gSyncLogFilter, Debug::General, "VSyncNotifier::Run. 1 Start loop \n"); + bool validSync( true ); // Hardware VSyncs available? if( mVSyncMonitor->UseHardware() ) { - // Yes..wait for hardware VSync - validSync = mVSyncMonitor->DoSync( currentSequenceNumber, currentSeconds, currentMicroseconds ); + DALI_LOG_INFO( gSyncLogFilter, Debug::General, "VSyncNotifier::Run. 2 Start hardware sync (%d frames) \n", mNumberOfVSyncsPerRender); + + for( unsigned int i=0; iDoSync( currentSequenceNumber, currentSeconds, currentMicroseconds ); + } } else { @@ -143,17 +147,25 @@ void VSyncNotifier::Run() timeDelta += microseconds - currentMicroseconds; } + currentSeconds = seconds; + currentMicroseconds = microseconds; + + unsigned int sleepTimeInMicroseconds = 0; + if( timeDelta < TIME_PER_FRAME_IN_MICROSECONDS ) { - usleep( TIME_PER_FRAME_IN_MICROSECONDS - timeDelta ); - } - else - { - usleep( TIME_PER_FRAME_IN_MICROSECONDS ); + sleepTimeInMicroseconds = TIME_PER_FRAME_IN_MICROSECONDS - timeDelta; } + sleepTimeInMicroseconds += mNumberOfVSyncsPerRender * TIME_PER_FRAME_IN_MICROSECONDS; + + DALI_LOG_INFO( gSyncLogFilter, Debug::General, "VSyncNotifier::Run. 2 Start software sync (%d frames, %u microseconds) \n", mNumberOfVSyncsPerRender, sleepTimeInMicroseconds); + usleep( sleepTimeInMicroseconds ); } - running = mUpdateRenderSync.VSyncNotifierSyncWithUpdateAndRender( validSync, ++frameNumber, currentSeconds, currentMicroseconds ); + DALI_LOG_INFO( gSyncLogFilter, Debug::General, "VSyncNotifier::Run. 3 SyncWithUpdateAndRender(frame#:%d, current Sec:%u current uSec:%u)\n", frameNumber+1, currentSeconds, currentMicroseconds); + + running = mUpdateRenderSync.VSyncNotifierSyncWithUpdateAndRender( validSync, ++frameNumber, currentSeconds, currentMicroseconds, mNumberOfVSyncsPerRender ); + // The number of vsyncs per render may have been modified by this call. } // uninstall a function for logging diff --git a/adaptors/base/vsync-notifier.h b/adaptors/base/vsync-notifier.h index 87bb0fe..e2e28c4 100644 --- a/adaptors/base/vsync-notifier.h +++ b/adaptors/base/vsync-notifier.h @@ -48,8 +48,8 @@ class EnvironmentOptions; class AdaptorInternalServices; /** - * Implements a simple class that monitors vertical blanks from libdrm - * and sends a notification to Core. + * Implements a simple class that either monitors vertical blanks from libdrm, or manages + * a software timer to handle syncing. */ class VSyncNotifier { @@ -97,6 +97,7 @@ private: VSyncMonitorInterface* mVSyncMonitor; ///< VSyncMonitor interface boost::thread* mThread; ///< The actual thread. const EnvironmentOptions& mEnvironmentOptions; ///< Environment options + unsigned int mNumberOfVSyncsPerRender;///< How many frames for each update/render cycle. }; // class VSyncNotifier diff --git a/adaptors/common/adaptor-impl.cpp b/adaptors/common/adaptor-impl.cpp index 3482250..59039d2 100644 --- a/adaptors/common/adaptor-impl.cpp +++ b/adaptors/common/adaptor-impl.cpp @@ -509,14 +509,14 @@ void Adaptor::ReplaceSurface( Dali::RenderSurface& surface ) mUpdateRenderController->ReplaceSurface(internalSurface); } -void Adaptor::RenderSync() +Dali::RenderSurface& Adaptor::GetSurface() const { - mUpdateRenderController->RenderSync(); + return *mSurface; } -Dali::RenderSurface& Adaptor::GetSurface() const +void Adaptor::ReleaseSurfaceLock() { - return *mSurface; + mSurface->ReleaseLock(); } Dali::TtsPlayer Adaptor::GetTtsPlayer(Dali::TtsPlayer::Mode mode) @@ -572,9 +572,14 @@ Dali::Integration::Core& Adaptor::GetCore() return *mCore; } -void Adaptor::DisableVSync() +void Adaptor::SetRenderRefreshRate( unsigned int numberOfVSyncsPerRender ) +{ + mUpdateRenderController->SetRenderRefreshRate( numberOfVSyncsPerRender ); +} + +void Adaptor::SetUseHardwareVSync( bool useHardware ) { - mUpdateRenderController->DisableVSync(); + mVSyncMonitor->SetUseHardwareVSync( useHardware ); } void Adaptor::SetDpi(size_t hDpi, size_t vDpi) diff --git a/adaptors/common/adaptor-impl.h b/adaptors/common/adaptor-impl.h index fa068e2..dbb2431 100644 --- a/adaptors/common/adaptor-impl.h +++ b/adaptors/common/adaptor-impl.h @@ -175,14 +175,14 @@ public: // AdaptorInternalServices implementation virtual void ReplaceSurface( Dali::RenderSurface& surface ); /** - * @copydoc AdaptorInterface::RenderSync() + * @copydoc Dali::Adaptor::GetSurface() */ - virtual void RenderSync(); + virtual Dali::RenderSurface& GetSurface() const; /** - * @copydoc Dali::Adaptor::GetSurface() + * @copydoc Dali::Adaptor::ReleaseSurfaceLock() */ - virtual Dali::RenderSurface& GetSurface() const; + virtual void ReleaseSurfaceLock(); /** * Retrieve the TtsPlayer. @@ -219,9 +219,14 @@ public: virtual Dali::Integration::Core& GetCore(); /** - * Disables GL draw synchronisation with the display. + * @copydoc Dali::Adaptor::SetRenderRefreshRate() + */ + void SetRenderRefreshRate( unsigned int numberOfVSyncsPerRender ); + + /** + * @copydoc Dali::Adaptor::SetUseHardwareVSync() */ - DALI_IMPORT_API void DisableVSync(); + void SetUseHardwareVSync(bool useHardware); /** * Overrides DPI. diff --git a/adaptors/common/application-impl.cpp b/adaptors/common/application-impl.cpp index 79a666a..21fda5e 100644 --- a/adaptors/common/application-impl.cpp +++ b/adaptors/common/application-impl.cpp @@ -182,7 +182,7 @@ void Application::OnInit() // Check if user requires no vsyncing and set on X11 Adaptor if (mCommandLineOptions->noVSyncOnRender) { - Internal::Adaptor::Adaptor::GetImplementation( *mAdaptor ).DisableVSync(); + mAdaptor->SetUseHardwareVSync(false); } Internal::Adaptor::Adaptor::GetImplementation( *mAdaptor ).SetStereoBase( mCommandLineOptions->stereoBase ); diff --git a/adaptors/common/gl/egl-implementation.h b/adaptors/common/gl/egl-implementation.h index 972b441..b74830b 100644 --- a/adaptors/common/gl/egl-implementation.h +++ b/adaptors/common/gl/egl-implementation.h @@ -105,12 +105,6 @@ public: bool IsGlesInitialized() const; /** - * Sets the refresh sync mode. - * @see SyncMode - */ - virtual bool SetRefreshSync( SyncMode mode ); - - /** * Performs an OpenGL swap buffers command */ virtual void SwapBuffers(); @@ -193,7 +187,6 @@ private: bool mGlesInitialized; bool mIsOwnSurface; - SyncMode mSyncMode; bool mContextCurrent; bool mIsWindow; ColorDepth mColorDepth; diff --git a/adaptors/common/render-surface-impl.h b/adaptors/common/render-surface-impl.h index ef71e86..b3d94a8 100644 --- a/adaptors/common/render-surface-impl.h +++ b/adaptors/common/render-surface-impl.h @@ -22,6 +22,7 @@ #include #include #include +#include namespace Dali { @@ -48,14 +49,6 @@ class DALI_IMPORT_API RenderSurface : public Dali::RenderSurface { public: - enum SyncMode - { - SYNC_MODE_NONE, ///< Do not wait for RenderSync - SYNC_MODE_WAIT ///< Wait for RenderSync - }; - -public: - /** * Constructor */ @@ -81,7 +74,7 @@ public: // API virtual void CreateEglSurface( EglInterface& egl ) = 0; /** - * Destroyes EGL Surface + * Destroys EGL Surface * @param egl implementation to use for the destruction */ virtual void DestroyEglSurface( EglInterface& egl ) = 0; @@ -129,9 +122,9 @@ public: // API virtual void SetViewMode( ViewMode viewMode ) = 0; /** - * Called after offscreen is posted to onscreen + * Called when Render thread has started */ - virtual void RenderSync() = 0; + virtual void StartRender() = 0; /** * Invoked by render thread before Core::Render @@ -146,10 +139,9 @@ public: // API * @param[in] egl The Egl interface * @param[in] glAbstraction OpenGLES abstraction interface * @param[in] deltaTime Time (in microseconds) since PostRender was last called. - * @param[in] syncMode Wait for render sync flag. - * RenderSync will be skipped if this or SetSyncMode() is set to SYNC_MODE_NONE. + * @param[in] replacingSurface True if the surface is being replaced. */ - virtual void PostRender( EglInterface& egl, Integration::GlAbstraction& glAbstraction, unsigned int deltaTime, SyncMode syncMode ) = 0; + virtual void PostRender( EglInterface& egl, Integration::GlAbstraction& glAbstraction, unsigned int deltaTime, bool replacingSurface ) = 0; /** * Invoked by render thread when the thread should be stop @@ -157,10 +149,9 @@ public: // API virtual void StopRender() = 0; /** - * Set whether the surface should wait for RenderSync notifications - * @param[in] syncMode Wait for render sync flag. A member of SyncMode + * Invoked by Event Thread when the compositor lock should be released and rendering should resume. */ - virtual void SetSyncMode( SyncMode syncMode ) = 0; + virtual void ReleaseLock() = 0; }; } // namespace Adaptor diff --git a/adaptors/common/vsync-monitor.h b/adaptors/common/vsync-monitor.h index df148c5..601a584 100644 --- a/adaptors/common/vsync-monitor.h +++ b/adaptors/common/vsync-monitor.h @@ -55,7 +55,13 @@ public: * Set the use hardware flag * @param[in] useHardware The new state for the use hardware flag. */ - void SetUseHardware( bool useHardware ); + void SetUseHardwareVSync( bool useHardware ); + + /** + * Set whether the vsync hardware is available. + * (This is public to allow callback method to work...) + */ + void SetHardwareVSyncAvailable(bool available); private: // From Dali::Internal::Adaptor::VSyncMonitorInterface @@ -83,8 +89,8 @@ private: int mFileDescriptor; ///< DRM dev node file descriptor drmVBlank mVBlankInfo; - bool mUseHardware; ///< Hardware VSyncs available flag - + bool mUseHardwareVSync; ///< Whether to use hardware vsync + bool mHardwareVSyncAvailable; ///< Whether hardware vsync is available }; } // namespace Adaptor diff --git a/adaptors/public-api/adaptor-framework/adaptor.cpp b/adaptors/public-api/adaptor-framework/adaptor.cpp index 1f54f67..6f4c1ca 100644 --- a/adaptors/public-api/adaptor-framework/adaptor.cpp +++ b/adaptors/public-api/adaptor-framework/adaptor.cpp @@ -91,6 +91,21 @@ RenderSurface& Adaptor::GetSurface() return mImpl->GetSurface(); } +void Adaptor::ReleaseSurfaceLock() +{ + mImpl->ReleaseSurfaceLock(); +} + +void Adaptor::SetRenderRefreshRate( unsigned int numberOfVSyncsPerRender ) +{ + mImpl->SetRenderRefreshRate( numberOfVSyncsPerRender ); +} + +void Adaptor::SetUseHardwareVSync(bool useHardware) +{ + mImpl->SetUseHardwareVSync( useHardware ); +} + Adaptor& Adaptor::Get() { return Internal::Adaptor::Adaptor::Get(); diff --git a/adaptors/public-api/adaptor-framework/adaptor.h b/adaptors/public-api/adaptor-framework/adaptor.h index 0f8c255..70d3be2 100644 --- a/adaptors/public-api/adaptor-framework/adaptor.h +++ b/adaptors/public-api/adaptor-framework/adaptor.h @@ -173,6 +173,35 @@ public: RenderSurface& GetSurface(); /** + * @brief Release any locks the surface may hold. + * + * For example, after compositing an offscreen surface, use this method to allow + * rendering to continue. + */ + void ReleaseSurfaceLock(); + + /** + * @brief Set the number of frames per render. + * + * This enables an application to deliberately render with a reduced FPS. + * @param[in] numberOfVSyncsPerRender The number of vsyncs between successive renders. + * Suggest this is a power of two: + * 1 - render each vsync frame + * 2 - render every other vsync frame + * 4 - render every fourth vsync frame + * 8 - render every eighth vsync frame + */ + void SetRenderRefreshRate( unsigned int numberOfVSyncsPerRender ); + + /** + * @brief Set whether the frame count per render is managed using the hardware VSync or + * manually timed. + * + * @param[in] useHardware True if the hardware VSync should be used + */ + void SetUseHardwareVSync(bool useHardware); + + /** * @brief Returns a reference to the instance of the adaptor used by the current thread. * * @return A reference to the adaptor. diff --git a/adaptors/public-api/adaptor-framework/render-surface.h b/adaptors/public-api/adaptor-framework/render-surface.h index d08e6c0..c746754 100644 --- a/adaptors/public-api/adaptor-framework/render-surface.h +++ b/adaptors/public-api/adaptor-framework/render-surface.h @@ -58,21 +58,6 @@ public: }; /** - * @brief When application uses pixmap surface, it can select rendering mode. - * - * RENDER_SYNC : application should call RenderSync() after posting the offscreen to onscreen - * RENDER_#FPS : the maximum performance will be limited designated number of frame - */ - enum RenderMode - { - RENDER_DEFAULT = -1, - RENDER_SYNC = 0, - RENDER_24FPS = 24, - RENDER_30FPS = 30, - RENDER_60FPS = 60 - }; - - /** * @brief Constructor * * Application or Adaptor needs to create the appropriate concrete RenderSurface type. @@ -109,17 +94,6 @@ public: */ virtual PositionSize GetPositionSize() const = 0; - /** - * @brief Set frame update rate for pixmap surface type - */ - virtual void SetRenderMode(RenderMode mode) = 0; - - /** - * @brief Get current fps for pixmap surface type - * @return The render mode - */ - virtual RenderMode GetRenderMode() const = 0; - private: /** diff --git a/adaptors/tizen/vsync-monitor-tizen.cpp b/adaptors/tizen/vsync-monitor-tizen.cpp index 0bb4f99..ea38d94 100644 --- a/adaptors/tizen/vsync-monitor-tizen.cpp +++ b/adaptors/tizen/vsync-monitor-tizen.cpp @@ -61,7 +61,7 @@ void ScreenStatusChanged(keynode_t* node, void* data) // - VCONFKEY_PM_STATE_SLEEP : turn vsync off const bool screenOn( VCONFKEY_PM_STATE_NORMAL == status ); - vsyncMonitor->SetUseHardware( screenOn ); + vsyncMonitor->SetHardwareVSyncAvailable( screenOn ); DALI_LOG_INFO( gLogFilter, Debug::Concise, "%s, Screen %s.\n", __PRETTY_FUNCTION__, screenOn ? "On" : "Off" ); } @@ -70,7 +70,8 @@ void ScreenStatusChanged(keynode_t* node, void* data) VSyncMonitor::VSyncMonitor() : mFileDescriptor( FD_NONE ), - mUseHardware( true ) + mUseHardwareVSync( true ), + mHardwareVSyncAvailable( false ) { vconf_notify_key_changed( VCONFKEY_PM_STATE, ScreenStatusChanged, this ); } @@ -82,9 +83,14 @@ VSyncMonitor::~VSyncMonitor() vconf_ignore_key_changed( VCONFKEY_PM_STATE, ScreenStatusChanged ); } -void VSyncMonitor::SetUseHardware( bool useHardware ) +void VSyncMonitor::SetUseHardwareVSync( bool useHardware ) { - mUseHardware = useHardware; + mUseHardwareVSync = useHardware; +} + +void VSyncMonitor::SetHardwareVSyncAvailable( bool hardwareVSyncAvailable ) +{ + mHardwareVSyncAvailable = hardwareVSyncAvailable; } void VSyncMonitor::Initialize() @@ -120,10 +126,9 @@ void VSyncMonitor::Terminate() bool VSyncMonitor::UseHardware() { - return mUseHardware && (FD_NONE != mFileDescriptor ); + return mUseHardwareVSync && mHardwareVSyncAvailable && (FD_NONE != mFileDescriptor ); } - bool VSyncMonitor::DoSync( unsigned int& frameNumber, unsigned int& seconds, unsigned int& microseconds ) { DALI_ASSERT_DEBUG( mFileDescriptor != FD_NONE && "ECoreX::VSyncMonitor is not initialized" ); diff --git a/adaptors/ubuntu/vsync-monitor-ubuntu.cpp b/adaptors/ubuntu/vsync-monitor-ubuntu.cpp index 13592a7..d91aa71 100644 --- a/adaptors/ubuntu/vsync-monitor-ubuntu.cpp +++ b/adaptors/ubuntu/vsync-monitor-ubuntu.cpp @@ -48,7 +48,8 @@ const int FD_NONE( -1 ); VSyncMonitor::VSyncMonitor() : mFileDescriptor( FD_NONE ), - mUseHardware( false ) + mUseHardwareVSync( false ), + mHardwareVsyncAvailable( false ) { } @@ -57,9 +58,14 @@ VSyncMonitor::~VSyncMonitor() Terminate(); } -void VSyncMonitor::SetUseHardware( bool useHardware ) +void VSyncMonitor::SetUseHardwareVsync( bool useHardware ) { - mUseHardware = useHardware; + mUseHardwareVSync = useHardware; +} + +void VSyncMonitor::SetHardwareVSyncAvailable( bool hardwareVSyncAvailable ) +{ + mHardwareVsyncAvailable = hardwareVSyncAvailable; } void VSyncMonitor::Initialize() @@ -80,11 +86,6 @@ void VSyncMonitor::Initialize() void VSyncMonitor::Terminate() { - if( mFileDescriptor != FD_NONE ) - { - close( mFileDescriptor ); - mFileDescriptor = FD_NONE; - } } bool VSyncMonitor::UseHardware() diff --git a/adaptors/wayland/ecore-wl-render-surface.cpp b/adaptors/wayland/ecore-wl-render-surface.cpp index 0345024..158323e 100644 --- a/adaptors/wayland/ecore-wl-render-surface.cpp +++ b/adaptors/wayland/ecore-wl-render-surface.cpp @@ -63,12 +63,9 @@ RenderSurface::RenderSurface( SurfaceType type, mPosition(positionSize), mTitle(name), mColorDepth(isTransparent ? COLOR_DEPTH_32 : COLOR_DEPTH_24), - mRenderMode((type == PIXMAP) ? RENDER_SYNC : RENDER_DEFAULT), mRenderNotification( NULL ), - mSyncReceived( false ), mOwnSurface(false), - mOwnDisplay(false), - mIsStopped( false ) + mOwnDisplay(false) { // see if there is a display in Any display SetDisplay( display ); @@ -154,16 +151,6 @@ PositionSize RenderSurface::GetPositionSize() const return mPosition; } -void RenderSurface::SetRenderMode(RenderMode mode) -{ - mRenderMode = mode; -} - -Dali::RenderSurface::RenderMode RenderSurface::GetRenderMode() const -{ - return mRenderMode; -} - void RenderSurface::MoveResize( Dali::PositionSize positionSize ) { // nothing to do in base class @@ -211,16 +198,6 @@ void RenderSurface::ConsumeEvents() { } -void RenderSurface::StopRender() -{ - // Stop blocking waiting for sync - SetSyncMode( RenderSurface::SYNC_MODE_NONE ); - // Simulate a RenderSync in case render-thread is currently blocked - RenderSync(); - - mIsStopped = true; -} - void RenderSurface::SetViewMode( ViewMode ) { } @@ -267,38 +244,6 @@ unsigned int RenderSurface::GetSurfaceId( Any surface ) const return surfaceId; } -void RenderSurface::RenderSync() -{ - // nothing to do -} - -void RenderSurface::DoRenderSync( unsigned int timeDelta, SyncMode syncMode ) -{ - // Should block waiting for RenderSync? - if( mRenderMode == Dali::RenderSurface::RENDER_SYNC ) - { - boost::unique_lock< boost::mutex > lock( mSyncMutex ); - - // wait for sync - if( syncMode != SYNC_MODE_NONE && - mSyncMode != SYNC_MODE_NONE && - !mSyncReceived ) - { - mSyncNotify.wait( lock ); - } - mSyncReceived = false; - } - // Software sync based on a timed delay? - 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 ); - } - } -} - } // namespace ECore } // namespace Adaptor diff --git a/adaptors/wayland/ecore-wl-render-surface.h b/adaptors/wayland/ecore-wl-render-surface.h index 6467ad8..a2aac02 100644 --- a/adaptors/wayland/ecore-wl-render-surface.h +++ b/adaptors/wayland/ecore-wl-render-surface.h @@ -126,16 +126,6 @@ public: // from Dali::RenderSurface */ virtual PositionSize GetPositionSize() const; - /** - * @copydoc Dali::RenderSurface::SetRenderMode() - */ - virtual void SetRenderMode(RenderMode mode); - - /** - * @copydoc Dali::RenderSurface::GetRenderMode() - */ - virtual RenderMode GetRenderMode() const; - public: // from Internal::Adaptor::RenderSurface /** @@ -179,11 +169,6 @@ public: // from Internal::Adaptor::RenderSurface virtual void ConsumeEvents(); /** - * @copydoc Dali::Internal::Adaptor::RenderSurface::RenderSync() - */ - virtual void RenderSync(); - - /** * @copydoc Dali::Internal::Adaptor::RenderSurface::SetViewMode() */ void SetViewMode( ViewMode ); @@ -196,17 +181,7 @@ public: // from Internal::Adaptor::RenderSurface /** * @copydoc Dali::Internal::Adaptor::RenderSurface::PostRender() */ - virtual void PostRender( EglInterface& egl, Integration::GlAbstraction& glAbstraction, unsigned int timeDelta, SyncMode syncMode ) = 0; - - /** - * @copydoc Dali::Internal::Adaptor::RenderSurface::StopRender() - */ - virtual void StopRender(); - - /** - * @copydoc Dali::Internal::Adaptor::RenderSurface::SetSyncMode() - */ - virtual void SetSyncMode( SyncMode syncMode ) { mSyncMode = syncMode; } + virtual void PostRender( EglInterface& egl, Integration::GlAbstraction& glAbstraction, unsigned int timeDelta, bool replacingSurface ) = 0; private: @@ -236,13 +211,6 @@ protected: */ virtual void UseExistingRenderable( unsigned int surfaceId ) = 0; - /** - * Perform render sync - * @param[in] currentTime Current time in microseconds - * @param[in] syncMode Wait for RenderSync (from Adaptor) flag. A member of SyncMode - */ - void DoRenderSync( unsigned int timeDelta, SyncMode syncMode ); - protected: // Data WlDisplay* mMainDisplay; ///< Wayland-connection for rendering @@ -250,15 +218,10 @@ protected: // Data PositionSize mPosition; ///< Position std::string mTitle; ///< Title of window which shows from "xinfo -topvwins" command ColorDepth mColorDepth; ///< Color depth of surface (32 bit or 24 bit) - RenderMode mRenderMode; ///< Render mode for pixmap surface type - TriggerEvent* mRenderNotification; ///< Render notificatin trigger - boost::mutex mSyncMutex; ///< mutex to lock during waiting sync - boost::condition_variable mSyncNotify; ///< condition to notify main thread that pixmap was flushed to onscreen - SyncMode mSyncMode; - bool mSyncReceived; ///< true, when a pixmap sync has occurred, (cleared after reading) + TriggerEvent* mRenderNotification; ///< Render notification trigger + bool mOwnSurface; ///< Whether we own the surface (responsible for deleting it) bool mOwnDisplay; ///< Whether we own the display (responsible for deleting it) - bool mIsStopped; ///< Render should be stopped }; } // namespace ECore diff --git a/adaptors/wayland/egl-implementation-wl.cpp b/adaptors/wayland/egl-implementation-wl.cpp index e154306..72e9696 100644 --- a/adaptors/wayland/egl-implementation-wl.cpp +++ b/adaptors/wayland/egl-implementation-wl.cpp @@ -56,7 +56,6 @@ EglImplementation::EglImplementation() mEglSurface(0), mGlesInitialized(false), mIsOwnSurface(true), - mSyncMode(FULL_SYNC), mContextCurrent(false), mIsWindow(true), mColorDepth(COLOR_DEPTH_24) @@ -232,10 +231,6 @@ void EglImplementation::MakeContextCurrent() eglQueryString(mEglDisplay, EGL_CLIENT_APIS), eglQueryString(mEglDisplay, EGL_EXTENSIONS)); - if ( mIsWindow ) - { - SetRefreshSync( mSyncMode ); - } } void EglImplementation::MakeContextNull() @@ -276,32 +271,6 @@ bool EglImplementation::IsGlesInitialized() const return mGlesInitialized; } -bool EglImplementation::SetRefreshSync( SyncMode mode ) -{ - if ( mIsWindow == false ) - { - return false; - } - mSyncMode = mode; - - // eglSwapInterval specifies the minimum number of video frame periods - // per buffer swap for the window associated with the current context. - - if ( !mContextCurrent ) - { - return true; - } - - EGLBoolean ok = eglSwapInterval( mEglDisplay, mode ); - if ( !ok ) - { - TEST_EGL_ERROR("eglSwapInterval"); - return false; - } - - return true; -} - void EglImplementation::SwapBuffers() { eglSwapBuffers( mEglDisplay, mEglSurface ); @@ -576,4 +545,3 @@ EGLDisplay EglImplementation::GetContext() const } // namespace Internal } // namespace Dali - diff --git a/adaptors/wayland/pixmap-render-surface-wl.cpp b/adaptors/wayland/pixmap-render-surface-wl.cpp index b2b5378..0ccba73 100644 --- a/adaptors/wayland/pixmap-render-surface-wl.cpp +++ b/adaptors/wayland/pixmap-render-surface-wl.cpp @@ -114,13 +114,17 @@ bool PixmapRenderSurface::ReplaceEGLSurface( EglInterface& eglIf ) return false; } +void PixmapRenderSurface::StartRender() +{ +} + bool PixmapRenderSurface::PreRender( EglInterface&, Integration::GlAbstraction& ) { // nothing to do for pixmaps return true; } -void PixmapRenderSurface::PostRender( EglInterface& egl, Integration::GlAbstraction& glAbstraction, unsigned int timeDelta, SyncMode syncMode ) +void PixmapRenderSurface::PostRender( EglInterface& egl, Integration::GlAbstraction& glAbstraction, unsigned int timeDelta, bool replacingSurface ) { // flush gl instruction queue glAbstraction.Flush(); @@ -140,7 +144,11 @@ void PixmapRenderSurface::PostRender( EglInterface& egl, Integration::GlAbstract } // Do render synchronisation - DoRenderSync( timeDelta, syncMode ); + // AcquireLock( replacingSurface ? SYNC_MODE_NONE : SYNC_MODE_WAIT ); +} + +void PixmapRenderSurface::StopRender() +{ } void PixmapRenderSurface::CreateWlRenderable() @@ -155,15 +163,16 @@ void PixmapRenderSurface::UseExistingRenderable( unsigned int surfaceId ) { } -void PixmapRenderSurface::RenderSync() +void PixmapRenderSurface::SetSyncMode( SyncMode syncMode ) { - { - boost::unique_lock< boost::mutex > lock( mSyncMutex ); - mSyncReceived = true; - } +} + +void PixmapRenderSurface::AcquireLock( SyncMode syncMode ) +{ +} - // wake render thread if it was waiting for the notify - mSyncNotify.notify_all(); +void PixmapRenderSurface::ReleaseLock() +{ } } // namespace ECore diff --git a/adaptors/wayland/pixmap-render-surface.h b/adaptors/wayland/pixmap-render-surface.h index ce8cb5c..87a81bf 100644 --- a/adaptors/wayland/pixmap-render-surface.h +++ b/adaptors/wayland/pixmap-render-surface.h @@ -97,9 +97,9 @@ public: // from Internal::Adaptor::RenderSurface virtual bool ReplaceEGLSurface( EglInterface& egl ); /** - * @copydoc Dali::Internal::Adaptor::RenderSurface::RenderSync() + * @copydoc Dali::Internal::Adaptor::RenderSurface::StartRender() */ - virtual void RenderSync(); + virtual void StartRender(); /** * @copydoc Dali::Internal::Adaptor::RenderSurface::PreRender() @@ -109,9 +109,34 @@ public: // from Internal::Adaptor::RenderSurface /** * @copydoc Dali::Internal::Adaptor::RenderSurface::PostRender() */ - virtual void PostRender( EglInterface& egl, Integration::GlAbstraction& glAbstraction, unsigned int timeDelta, SyncMode syncMode ); + virtual void PostRender( EglInterface& egl, Integration::GlAbstraction& glAbstraction, unsigned int timeDelta, bool replacingSurface ); + + /** + * @copydoc Dali::Internal::Adaptor::RenderSurface::StopRender() + */ + virtual void StopRender(); private: + enum SyncMode + { + SYNC_MODE_NONE, + SYNC_MODE_WAIT + }; + + void SetSyncMode( SyncMode syncMode ); + + /** + * If sync mode is WAIT, then acquire a lock. This prevents render thread from + * continuing until the pixmap has been drawn by the compositor. + * It must be released for rendering to continue. + * @param[in] syncMode The current sync mode + */ + void AcquireLock( SyncMode syncMode ); + + /** + * Release any locks. + */ + void ReleaseLock(); /** * Create XPixmap diff --git a/adaptors/wayland/window-render-surface-wl.cpp b/adaptors/wayland/window-render-surface-wl.cpp index fcd2725..a9c0505 100644 --- a/adaptors/wayland/window-render-surface-wl.cpp +++ b/adaptors/wayland/window-render-surface-wl.cpp @@ -178,13 +178,17 @@ void WindowRenderSurface::Map() ecore_wl_window_show(mWlWindow); } +void WindowRenderSurface::StartRender() +{ +} + bool WindowRenderSurface::PreRender( EglInterface&, Integration::GlAbstraction& ) { // nothing to do for windows return true; } -void WindowRenderSurface::PostRender( EglInterface& egl, Integration::GlAbstraction& glAbstraction, unsigned int, SyncMode ) +void WindowRenderSurface::PostRender( EglInterface& egl, Integration::GlAbstraction& glAbstraction, unsigned int, bool ) { EglImplementation& eglImpl = static_cast( egl ); eglImpl.SwapBuffers(); @@ -199,6 +203,10 @@ void WindowRenderSurface::PostRender( EglInterface& egl, Integration::GlAbstract } } +void WindowRenderSurface::StopRender() +{ +} + void WindowRenderSurface::SetViewMode( ViewMode viewMode ) { } @@ -228,6 +236,11 @@ void WindowRenderSurface::UseExistingRenderable( unsigned int surfaceId ) mWlWindow = AnyCast< Ecore_Wl_Window* >( surfaceId ); } +void WindowRenderSurface::ReleaseLock() +{ + // Nothing to do. +} + } // namespace ECore } // namespace Adaptor diff --git a/adaptors/wayland/window-render-surface.h b/adaptors/wayland/window-render-surface.h index 980e273..81a1026 100644 --- a/adaptors/wayland/window-render-surface.h +++ b/adaptors/wayland/window-render-surface.h @@ -124,6 +124,11 @@ public: // from Internal::Adaptor::RenderSurface virtual void Map(); /** + * @copydoc Dali::Internal::Adaptor::RenderSurface::StartRender() + */ + virtual void StartRender(); + + /** * @copydoc Dali::Internal::Adaptor::RenderSurface::PreRender() */ virtual bool PreRender( EglInterface& egl, Integration::GlAbstraction& glAbstraction ); @@ -131,13 +136,23 @@ public: // from Internal::Adaptor::RenderSurface /** * @copydoc Dali::Internal::Adaptor::RenderSurface::PostRender() */ - virtual void PostRender( EglInterface& egl, Integration::GlAbstraction& glAbstraction, unsigned int timeDelta, SyncMode syncMode ); + virtual void PostRender( EglInterface& egl, Integration::GlAbstraction& glAbstraction, unsigned int timeDelta, bool replacingSurface ); + + /** + * @copydoc Dali::Internal::Adaptor::RenderSurface::StopRender() + */ + virtual void StopRender(); /** * @copydoc Dali::Internal::Adaptor::RenderSurface::SetViewMode() */ void SetViewMode( ViewMode viewMode ); + /** + * @copydoc Dali::Internal::Adaptor::RenderSurface::ReleaseLock() + */ + virtual void ReleaseLock(); + protected: /** diff --git a/adaptors/x11/ecore-x-render-surface.cpp b/adaptors/x11/ecore-x-render-surface.cpp index f831dbf..6bdb5b3 100644 --- a/adaptors/x11/ecore-x-render-surface.cpp +++ b/adaptors/x11/ecore-x-render-surface.cpp @@ -70,13 +70,9 @@ RenderSurface::RenderSurface( SurfaceType type, mPosition(positionSize), mTitle(name), mColorDepth(isTransparent ? COLOR_DEPTH_32 : COLOR_DEPTH_24), - mRenderMode((type == PIXMAP) ? RENDER_SYNC : RENDER_DEFAULT), mRenderNotification( NULL ), - mSyncMode(SYNC_MODE_NONE), - mSyncReceived( false ), mOwnSurface(false), - mOwnDisplay(false), - mIsStopped( false ) + mOwnDisplay(false) { // see if there is a display in Any display SetDisplay( display ); @@ -164,16 +160,6 @@ PositionSize RenderSurface::GetPositionSize() const return mPosition; } -void RenderSurface::SetRenderMode(RenderMode mode) -{ - mRenderMode = mode; -} - -Dali::RenderSurface::RenderMode RenderSurface::GetRenderMode() const -{ - return mRenderMode; -} - void RenderSurface::MoveResize( Dali::PositionSize positionSize ) { // nothing to do in base class @@ -242,16 +228,6 @@ void RenderSurface::ConsumeEvents() } } -void RenderSurface::StopRender() -{ - // Stop blocking waiting for sync - SetSyncMode( RenderSurface::SYNC_MODE_NONE ); - // Simulate a RenderSync in case render-thread is currently blocked - RenderSync(); - - mIsStopped = true; -} - void RenderSurface::SetViewMode( ViewMode ) { } @@ -313,39 +289,6 @@ unsigned int RenderSurface::GetSurfaceId( Any surface ) const return surfaceId; } -void RenderSurface::RenderSync() -{ - // nothing to do -} - -void RenderSurface::DoRenderSync( unsigned int timeDelta, SyncMode syncMode ) -{ - // Should block waiting for RenderSync? - if( mRenderMode == Dali::RenderSurface::RENDER_SYNC ) - { - boost::unique_lock< boost::mutex > lock( mSyncMutex ); - - // wait for sync - if( syncMode != SYNC_MODE_NONE && - mSyncMode != SYNC_MODE_NONE && - !mSyncReceived ) - { - mSyncNotify.wait( lock ); - } - mSyncReceived = false; - } - // Software sync based on a timed delay? - 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 ); - } - } -} - } // namespace ECore } // namespace Adaptor diff --git a/adaptors/x11/ecore-x-render-surface.h b/adaptors/x11/ecore-x-render-surface.h index 7e2ed2f..d1434af 100644 --- a/adaptors/x11/ecore-x-render-surface.h +++ b/adaptors/x11/ecore-x-render-surface.h @@ -125,16 +125,6 @@ public: // from Dali::RenderSurface */ virtual PositionSize GetPositionSize() const; - /** - * @copydoc Dali::RenderSurface::SetRenderMode() - */ - virtual void SetRenderMode(RenderMode mode); - - /** - * @copydoc Dali::RenderSurface::GetRenderMode() - */ - virtual RenderMode GetRenderMode() const; - public: // from Internal::Adaptor::RenderSurface /** @@ -178,11 +168,6 @@ public: // from Internal::Adaptor::RenderSurface virtual void ConsumeEvents(); /** - * @copydoc Dali::Internal::Adaptor::RenderSurface::RenderSync() - */ - virtual void RenderSync(); - - /** * @copydoc Dali::Internal::Adaptor::RenderSurface::SetViewMode() */ void SetViewMode( ViewMode ); @@ -195,17 +180,7 @@ public: // from Internal::Adaptor::RenderSurface /** * @copydoc Dali::Internal::Adaptor::RenderSurface::PostRender() */ - virtual void PostRender( EglInterface& egl, Integration::GlAbstraction& glAbstraction, unsigned int timeDelta, SyncMode syncMode ) = 0; - - /** - * @copydoc Dali::Internal::Adaptor::RenderSurface::StopRender() - */ - virtual void StopRender(); - - /** - * @copydoc Dali::Internal::Adaptor::RenderSurface::SetSyncMode() - */ - virtual void SetSyncMode( SyncMode syncMode ) { mSyncMode = syncMode; } + virtual void PostRender( EglInterface& egl, Integration::GlAbstraction& glAbstraction, unsigned int timeDelta, bool replacingSurface ) = 0; private: @@ -235,13 +210,6 @@ protected: */ virtual void UseExistingRenderable( unsigned int surfaceId ) = 0; - /** - * Perform render sync - * @param[in] currentTime Current time in microseconds - * @param[in] syncMode Wait for RenderSync (from Adaptor) flag. A member of SyncMode - */ - void DoRenderSync( unsigned int timeDelta, SyncMode syncMode ); - protected: // Data XDisplay* mMainDisplay; ///< X-connection for rendering @@ -250,15 +218,10 @@ protected: // Data PositionSize mPosition; ///< Position std::string mTitle; ///< Title of window which shows from "xinfo -topvwins" command ColorDepth mColorDepth; ///< Color depth of surface (32 bit or 24 bit) - RenderMode mRenderMode; ///< Render mode for pixmap surface type - TriggerEvent* mRenderNotification; ///< Render notificatin trigger - boost::mutex mSyncMutex; ///< mutex to lock during waiting sync - boost::condition_variable mSyncNotify; ///< condition to notify main thread that pixmap was flushed to onscreen - SyncMode mSyncMode; - bool mSyncReceived; ///< true, when a pixmap sync has occurred, (cleared after reading) + TriggerEvent* mRenderNotification; ///< Render notification trigger + bool mOwnSurface; ///< Whether we own the surface (responsible for deleting it) bool mOwnDisplay; ///< Whether we own the display (responsible for deleting it) - bool mIsStopped; ///< Render should be stopped }; } // namespace ECore diff --git a/adaptors/x11/egl-implementation-x.cpp b/adaptors/x11/egl-implementation-x.cpp index e8610ae..d007347 100644 --- a/adaptors/x11/egl-implementation-x.cpp +++ b/adaptors/x11/egl-implementation-x.cpp @@ -57,7 +57,6 @@ EglImplementation::EglImplementation() mEglSurface(0), mGlesInitialized(false), mIsOwnSurface(true), - mSyncMode(FULL_SYNC), mContextCurrent(false), mIsWindow(true), mColorDepth(COLOR_DEPTH_24) @@ -238,11 +237,6 @@ void EglImplementation::MakeContextCurrent() eglQueryString(mEglDisplay, EGL_VERSION), eglQueryString(mEglDisplay, EGL_CLIENT_APIS), eglQueryString(mEglDisplay, EGL_EXTENSIONS)); - - if ( mIsWindow ) - { - SetRefreshSync( mSyncMode ); - } } void EglImplementation::MakeContextNull() @@ -283,32 +277,6 @@ bool EglImplementation::IsGlesInitialized() const return mGlesInitialized; } -bool EglImplementation::SetRefreshSync( SyncMode mode ) -{ - if ( mIsWindow == false ) - { - return false; - } - mSyncMode = mode; - - // eglSwapInterval specifies the minimum number of video frame periods - // per buffer swap for the window associated with the current context. - - if ( !mContextCurrent ) - { - return true; - } - - EGLBoolean ok = eglSwapInterval( mEglDisplay, mode ); - if ( !ok ) - { - TEST_EGL_ERROR("eglSwapInterval"); - return false; - } - - return true; -} - void EglImplementation::SwapBuffers() { eglSwapBuffers( mEglDisplay, mEglSurface ); @@ -586,4 +554,3 @@ EGLDisplay EglImplementation::GetContext() const } // namespace Internal } // namespace Dali - diff --git a/adaptors/x11/pixmap-render-surface-x.cpp b/adaptors/x11/pixmap-render-surface-x.cpp index f950648..1cfd6ff 100644 --- a/adaptors/x11/pixmap-render-surface-x.cpp +++ b/adaptors/x11/pixmap-render-surface-x.cpp @@ -54,7 +54,9 @@ PixmapRenderSurface::PixmapRenderSurface( Dali::PositionSize positionSize, Any display, const std::string& name, bool isTransparent) -: RenderSurface( Dali::RenderSurface::PIXMAP, positionSize, surface, display, name, isTransparent ) +: RenderSurface( Dali::RenderSurface::PIXMAP, positionSize, surface, display, name, isTransparent ), + mSyncMode(SYNC_MODE_NONE), + mSyncReceived(false) { Init( surface ); } @@ -129,13 +131,18 @@ bool PixmapRenderSurface::ReplaceEGLSurface( EglInterface& eglIf ) reinterpret_cast< EGLNativeDisplayType >( mMainDisplay ) ); } +void PixmapRenderSurface::StartRender() +{ + mSyncMode = SYNC_MODE_WAIT; +} + bool PixmapRenderSurface::PreRender( EglInterface&, Integration::GlAbstraction& ) { // nothing to do for pixmaps return true; } -void PixmapRenderSurface::PostRender( EglInterface& egl, Integration::GlAbstraction& glAbstraction, unsigned int timeDelta, SyncMode syncMode ) +void PixmapRenderSurface::PostRender( EglInterface& egl, Integration::GlAbstraction& glAbstraction, unsigned int timeDelta, bool replacingSurface ) { // flush gl instruction queue glAbstraction.Flush(); @@ -173,8 +180,13 @@ void PixmapRenderSurface::PostRender( EglInterface& egl, Integration::GlAbstract } } - // Do render synchronisation - DoRenderSync( timeDelta, syncMode ); + AcquireLock( replacingSurface ? SYNC_MODE_NONE : SYNC_MODE_WAIT ); +} + +void PixmapRenderSurface::StopRender() +{ + SetSyncMode(SYNC_MODE_NONE); + ReleaseLock(); } void PixmapRenderSurface::CreateXRenderable() @@ -207,7 +219,26 @@ void PixmapRenderSurface::UseExistingRenderable( unsigned int surfaceId ) mX11Pixmap = static_cast< Ecore_X_Pixmap >( surfaceId ); } -void PixmapRenderSurface::RenderSync() +void PixmapRenderSurface::SetSyncMode( SyncMode syncMode ) +{ + mSyncMode = syncMode; +} + +void PixmapRenderSurface::AcquireLock( SyncMode syncMode ) +{ + boost::unique_lock< boost::mutex > lock( mSyncMutex ); + + // wait for sync + if( syncMode != SYNC_MODE_NONE && + mSyncMode != SYNC_MODE_NONE && + !mSyncReceived ) + { + mSyncNotify.wait( lock ); + } + mSyncReceived = false; +} + +void PixmapRenderSurface::ReleaseLock() { { boost::unique_lock< boost::mutex > lock( mSyncMutex ); @@ -218,6 +249,7 @@ void PixmapRenderSurface::RenderSync() mSyncNotify.notify_all(); } + } // namespace ECore } // namespace Adaptor diff --git a/adaptors/x11/pixmap-render-surface.h b/adaptors/x11/pixmap-render-surface.h index 641e8a8..b4af9c8 100644 --- a/adaptors/x11/pixmap-render-surface.h +++ b/adaptors/x11/pixmap-render-surface.h @@ -102,9 +102,9 @@ public: // from Internal::Adaptor::RenderSurface virtual bool ReplaceEGLSurface( EglInterface& egl ); /** - * @copydoc Dali::Internal::Adaptor::RenderSurface::RenderSync() + * @copydoc Dali::Internal::Adaptor::RenderSurface::StartRender() */ - virtual void RenderSync(); + virtual void StartRender(); /** * @copydoc Dali::Internal::Adaptor::RenderSurface::PreRender() @@ -114,9 +114,38 @@ public: // from Internal::Adaptor::RenderSurface /** * @copydoc Dali::Internal::Adaptor::RenderSurface::PostRender() */ - virtual void PostRender( EglInterface& egl, Integration::GlAbstraction& glAbstraction, unsigned int timeDelta, SyncMode syncMode ); + virtual void PostRender( EglInterface& egl, Integration::GlAbstraction& glAbstraction, unsigned int timeDelta, bool replacingSurface ); + + /** + * @copydoc Dali::Internal::Adaptor::RenderSurface::StopRender() + */ + virtual void StopRender(); private: + enum SyncMode + { + SYNC_MODE_NONE, + SYNC_MODE_WAIT + }; + + /** + * Set the sync mode. + * @param[in] syncMode The sync mode + */ + void SetSyncMode( SyncMode syncMode ); + + /** + * If sync mode is WAIT, then acquire a lock. This prevents render thread from + * continuing until the pixmap has been drawn by the compositor. + * It must be released for rendering to continue. + * @param[in] syncMode The sync mode + */ + void AcquireLock( SyncMode syncMode ); + + /** + * Release any locks. + */ + void ReleaseLock(); /** * Create XPixmap @@ -131,7 +160,10 @@ private: private: // Data Ecore_X_Pixmap mX11Pixmap; ///< X-Pixmap - + SyncMode mSyncMode; ///< Stores whether the post render should block waiting for compositor + boost::mutex mSyncMutex; ///< mutex to lock during waiting sync + boost::condition_variable mSyncNotify; ///< condition to notify main thread that pixmap was flushed to onscreen + bool mSyncReceived; ///< true, when a pixmap sync has occurred, (cleared after reading) }; } // namespace ECore diff --git a/adaptors/x11/window-render-surface-x.cpp b/adaptors/x11/window-render-surface-x.cpp index 8006eee..1cf78e1 100644 --- a/adaptors/x11/window-render-surface-x.cpp +++ b/adaptors/x11/window-render-surface-x.cpp @@ -188,13 +188,17 @@ void WindowRenderSurface::Map() ecore_x_window_show(mX11Window); } +void WindowRenderSurface::StartRender() +{ +} + bool WindowRenderSurface::PreRender( EglInterface&, Integration::GlAbstraction& ) { // nothing to do for windows return true; } -void WindowRenderSurface::PostRender( EglInterface& egl, Integration::GlAbstraction& glAbstraction, unsigned int, SyncMode ) +void WindowRenderSurface::PostRender( EglInterface& egl, Integration::GlAbstraction& glAbstraction, unsigned int, bool ) { EglImplementation& eglImpl = static_cast( egl ); eglImpl.SwapBuffers(); @@ -220,6 +224,10 @@ void WindowRenderSurface::PostRender( EglInterface& egl, Integration::GlAbstract } } +void WindowRenderSurface::StopRender() +{ +} + void WindowRenderSurface::SetViewMode( ViewMode viewMode ) { Ecore_X_Atom viewModeAtom( ecore_x_atom_get( "_E_COMP_3D_APP_WIN" ) ); @@ -288,6 +296,11 @@ void WindowRenderSurface::UseExistingRenderable( unsigned int surfaceId ) mX11Window = static_cast< Ecore_X_Window >( surfaceId ); } +void WindowRenderSurface::ReleaseLock() +{ + // Nothing to do. +} + } // namespace ECore } // namespace Adaptor diff --git a/adaptors/x11/window-render-surface.h b/adaptors/x11/window-render-surface.h index e8fc702..3074aeb 100644 --- a/adaptors/x11/window-render-surface.h +++ b/adaptors/x11/window-render-surface.h @@ -123,6 +123,11 @@ public: // from Internal::Adaptor::RenderSurface virtual void Map(); /** + * @copydoc Dali::Internal::Adaptor::RenderSurface::StartRender() + */ + virtual void StartRender(); + + /** * @copydoc Dali::Internal::Adaptor::RenderSurface::PreRender() */ virtual bool PreRender( EglInterface& egl, Integration::GlAbstraction& glAbstraction ); @@ -130,13 +135,23 @@ public: // from Internal::Adaptor::RenderSurface /** * @copydoc Dali::Internal::Adaptor::RenderSurface::PostRender() */ - virtual void PostRender( EglInterface& egl, Integration::GlAbstraction& glAbstraction, unsigned int timeDelta, SyncMode syncMode ); + virtual void PostRender( EglInterface& egl, Integration::GlAbstraction& glAbstraction, unsigned int timeDelta, bool replacingSurface ); + + /** + * @copydoc Dali::Internal::Adaptor::RenderSurface::StopRender() + */ + virtual void StopRender(); /** * @copydoc Dali::Internal::Adaptor::RenderSurface::SetViewMode() */ void SetViewMode( ViewMode viewMode ); + /** + * @copydoc Dali::Internal::Adaptor::RenderSurface::ReleaseLock() + */ + virtual void ReleaseLock(); + protected: /** -- 2.7.4