From: Adeel Kazmi Date: Thu, 27 Aug 2015 16:07:31 +0000 (+0100) Subject: Pixmap render surface synchronization moved to thread-synchronization X-Git-Tag: dali_1.1.2~5^2 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=refs%2Fchanges%2F83%2F46983%2F5;p=platform%2Fcore%2Fuifw%2Fdali-adaptor.git Pixmap render surface synchronization moved to thread-synchronization Change-Id: If4d63d53795047a4ddb65e09cb080ab7316fa35e --- diff --git a/adaptors/base/thread-controller.cpp b/adaptors/base/thread-controller.cpp index ad31ad8..1640c8d 100644 --- a/adaptors/base/thread-controller.cpp +++ b/adaptors/base/thread-controller.cpp @@ -35,8 +35,7 @@ namespace Internal namespace Adaptor { -ThreadController::ThreadController( AdaptorInternalServices& adaptorInterfaces, - const EnvironmentOptions& environmentOptions ) +ThreadController::ThreadController( AdaptorInternalServices& adaptorInterfaces, const EnvironmentOptions& environmentOptions ) : mAdaptorInterfaces( adaptorInterfaces ), mUpdateThread( NULL ), mRenderThread( NULL ), @@ -51,6 +50,13 @@ ThreadController::ThreadController( AdaptorInternalServices& adaptorInterfaces, mRenderThread = new RenderThread( *mThreadSync, adaptorInterfaces, environmentOptions ); mVSyncNotifier = new VSyncNotifier( *mThreadSync, adaptorInterfaces, environmentOptions ); + + // Set the thread-synchronization interface on the render-surface + RenderSurface* currentSurface = mAdaptorInterfaces.GetRenderSurfaceInterface(); + if( currentSurface ) + { + currentSurface->SetThreadSynchronization( *mThreadSync ); + } } ThreadController::~ThreadController() @@ -110,6 +116,9 @@ void ThreadController::RequestUpdateOnce() void ThreadController::ReplaceSurface( RenderSurface* newSurface ) { + // Set the thread-syncronization on the new surface + newSurface->SetThreadSynchronization( *mThreadSync ); + // tell render thread to start the replace. This call will block until the replace // has completed. RenderSurface* currentSurface = mAdaptorInterfaces.GetRenderSurfaceInterface(); diff --git a/adaptors/base/thread-synchronization.cpp b/adaptors/base/thread-synchronization.cpp index f925a27..933346e 100644 --- a/adaptors/base/thread-synchronization.cpp +++ b/adaptors/base/thread-synchronization.cpp @@ -60,6 +60,7 @@ ThreadSynchronization::ThreadSynchronization( AdaptorInternalServices& adaptorIn mVSyncThreadStop( FALSE ), mRenderThreadStop( FALSE ), mRenderThreadReplacingSurface( FALSE ), + mRenderThreadSurfaceRendered( FALSE ), mEventThreadSurfaceReplaced( FALSE ), mVSyncThreadInitialised( FALSE ), mRenderThreadInitialised( FALSE ), @@ -475,8 +476,11 @@ bool ThreadSynchronization::RenderReady( RenderRequest*& requestPtr ) ConditionalWait::ScopedLock renderLock( mRenderThreadWaitCondition ); if( mUpdateAheadOfRender <= 0 && ! mRenderThreadStop ) { - LOG_UPDATE_COUNTER_RENDER( "updateAheadOfRender(%d) WAIT", mUpdateAheadOfRender ); - mRenderThreadWaitCondition.Wait( renderLock ); + do + { + LOG_UPDATE_COUNTER_RENDER( "updateAheadOfRender(%d) WAIT", mUpdateAheadOfRender ); + mRenderThreadWaitCondition.Wait( renderLock ); + } while( mUpdateAheadOfRender <= 0 && ! mRenderThreadStop && ! mRenderThreadReplacingSurface ); } else { @@ -576,6 +580,46 @@ bool ThreadSynchronization::VSyncReady( bool validSync, unsigned int frameNumber return IsVSyncThreadRunning(); // Call to this function locks so should not be called if we have a scoped-lock } +///////////////////////////////////////////////////////////////////////////////////////////////// +// POST RENDERING: EVENT THREAD +///////////////////////////////////////////////////////////////////////////////////////////////// + +void ThreadSynchronization::PostRenderComplete() +{ + LOG_EVENT_TRACE; + + { + ConditionalWait::ScopedLock lock( mRenderThreadWaitCondition ); + mRenderThreadSurfaceRendered = TRUE; + } + mRenderThreadWaitCondition.Notify(); +} + +/////////////////////////////////////////////////////////////////////////////////////////////////// +// POST RENDERING: RENDER THREAD +/////////////////////////////////////////////////////////////////////////////////////////////////// + +void ThreadSynchronization::PostRenderStarted() +{ + LOG_RENDER_TRACE; + + ConditionalWait::ScopedLock lock( mRenderThreadWaitCondition ); + mRenderThreadSurfaceRendered = FALSE; +} + +void ThreadSynchronization::PostRenderWaitForCompletion() +{ + LOG_RENDER_TRACE; + + ConditionalWait::ScopedLock lock( mRenderThreadWaitCondition ); + if( !mRenderThreadSurfaceRendered && + !mRenderThreadReplacingSurface ) + { + LOG_RENDER( "WAIT" ); + mRenderThreadWaitCondition.Wait( lock ); + } +} + /////////////////////////////////////////////////////////////////////////////////////////////////// // ALL THREADS: Performance Marker /////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/adaptors/base/thread-synchronization.h b/adaptors/base/thread-synchronization.h index 5f2ebfc..eea45c7 100644 --- a/adaptors/base/thread-synchronization.h +++ b/adaptors/base/thread-synchronization.h @@ -21,6 +21,7 @@ // EXTERNAL INCLUDES // INTERNAL INCLUDES +#include #include #include #include @@ -47,7 +48,7 @@ class AdaptorInternalServices; * However the Core::Update() for frame N+2 may not be called, until the Core::Render() method for frame N has returned. * */ -class ThreadSynchronization +class ThreadSynchronization : public Dali::ThreadSynchronizationInterface { public: @@ -202,6 +203,33 @@ public: bool VSyncReady( bool validSync, unsigned int frameNumber, unsigned int seconds, unsigned int microseconds, unsigned int& numberOfVSyncsPerRender ); ///////////////////////////////////////////////////////////////////////////////////////////////// + // POST RENDERING + ///////////////////////////////////////////////////////////////////////////////////////////////// + + ///////////////////////////////////////////////////////////////////////////////////////////////// + //// Called by the Event Thread if post-rendering is required + ///////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * @copydoc ThreadSynchronizationInterface::PostRenderComplete() + */ + void PostRenderComplete(); + + ///////////////////////////////////////////////////////////////////////////////////////////////// + //// Called by the Render Thread if post-rendering is required + ///////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * @copydoc ThreadSynchronizationInterface::PostRenderStarted() + */ + void PostRenderStarted(); + + /** + * @copydoc ThreadSynchronizationInterface::PostRenderStarted() + */ + void PostRenderWaitForCompletion(); + + ///////////////////////////////////////////////////////////////////////////////////////////////// // Called by ALL Threads ///////////////////////////////////////////////////////////////////////////////////////////////// @@ -383,6 +411,8 @@ private: volatile unsigned int mRenderThreadStop; ///< Whether the render-thread should be stopped (set by the update-thread, read by the render-thread). volatile unsigned int mRenderThreadReplacingSurface;///< Whether the render-thread should replace the surface (set by the event & render threads, read by the render-thread). + volatile unsigned int mRenderThreadSurfaceRendered; ///< Whether the render-surface has rendered our surface (set by the event & render threads, read by the render-thread). + volatile unsigned int mEventThreadSurfaceReplaced; ///< Checked by the event-thread & set by the render-thread when the surface has been replaced (set by the event & render threads, read by the event-thread). unsigned int mVSyncThreadInitialised; ///< Whether the V-Sync thread has been initialised (only used by v-sync-thread). diff --git a/adaptors/devel-api/adaptor-framework/render-surface.h b/adaptors/devel-api/adaptor-framework/render-surface.h index b23728d..2844105 100644 --- a/adaptors/devel-api/adaptor-framework/render-surface.h +++ b/adaptors/devel-api/adaptor-framework/render-surface.h @@ -31,6 +31,7 @@ namespace Dali class EglInterface; class DisplayConnection; +class ThreadSynchronizationInterface; namespace Integration { @@ -149,6 +150,13 @@ public: */ virtual void ReleaseLock() = 0; + /** + * @brief Sets the ThreadSynchronizationInterface + * + * @param threadSynchronization The thread-synchronization implementation. + */ + virtual void SetThreadSynchronization( ThreadSynchronizationInterface& threadSynchronization ) = 0; + private: /** diff --git a/adaptors/integration-api/file.list b/adaptors/integration-api/file.list index 9287572..2779d84 100644 --- a/adaptors/integration-api/file.list +++ b/adaptors/integration-api/file.list @@ -1,6 +1,7 @@ adaptor_integration_api_header_files = \ $(adaptor_integration_api_dir)/adaptor.h \ $(adaptor_integration_api_dir)/egl-interface.h \ + $(adaptor_integration_api_dir)/thread-synchronization-interface.h \ $(adaptor_integration_api_dir)/trigger-event-interface.h \ $(adaptor_integration_api_dir)/trigger-event-factory-interface.h \ $(adaptor_integration_api_dir)/trigger-event-factory.h \ diff --git a/adaptors/integration-api/thread-synchronization-interface.h b/adaptors/integration-api/thread-synchronization-interface.h new file mode 100644 index 0000000..15164be --- /dev/null +++ b/adaptors/integration-api/thread-synchronization-interface.h @@ -0,0 +1,86 @@ +#ifndef __DALI_INTEGRATION_THREAD_SYNCHRONIZATION_INTERFACE_H__ +#define __DALI_INTEGRATION_THREAD_SYNCHRONIZATION_INTERFACE_H__ + +/* + * Copyright (c) 2015 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. + * + */ + + +namespace Dali +{ + +/** + * @brief Interface for the ThreadSyncrhonization handler. + * + * This handler ensure the threads are synchronized properly. + */ +class ThreadSynchronizationInterface +{ +public: + + ///////////////////////////////////////////////////////////////////////////////////////////////// + // Called by the Event Thread if post-rendering is required + ///////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * @brief Surface informs that the post-render has been completed. + * + * @note Should only be called by the Event Thread if post-rendering is required. + */ + virtual void PostRenderComplete() = 0; + + ///////////////////////////////////////////////////////////////////////////////////////////////// + // Called by the Render Thread if post-rendering is required + ///////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * @brief Called just before the post rendering is done by the surface. + * + * @note Should only be called by the Render Thread if post-rendering is required. + */ + virtual void PostRenderStarted() = 0; + + /** + * @brief Blocks the render thread until the post rendering has been completed by the surface. + * + * @note Should only be called by the Render Thread if post-rendering is required. + */ + virtual void PostRenderWaitForCompletion() = 0; + +protected: + + /** + * @brief Protected constructor, no creation through this interface + */ + ThreadSynchronizationInterface( ) { } + + /** + * Virtual protected destructor, no deletion through this interface + */ + virtual ~ThreadSynchronizationInterface() { } + +private: + + // Undefined copy constructor. + ThreadSynchronizationInterface( const ThreadSynchronizationInterface& ); + + // Undefined assignment operator. + ThreadSynchronizationInterface& operator=( const ThreadSynchronizationInterface& ); +}; + +} // namespace Dali + +#endif // __DALI_INTEGRATION_THREAD_SYNCHRONIZATION_INTERFACE_H__ diff --git a/adaptors/integration-api/wayland/pixmap-render-surface.h b/adaptors/integration-api/wayland/pixmap-render-surface.h index ebe2532..190e1ae 100644 --- a/adaptors/integration-api/wayland/pixmap-render-surface.h +++ b/adaptors/integration-api/wayland/pixmap-render-surface.h @@ -107,6 +107,11 @@ public: // from Dali::RenderSurface */ virtual void StopRender(); + /** + * @copydoc Dali::RenderSurface::SetThreadSynchronization + */ + virtual void SetThreadSynchronization( ThreadSynchronizationInterface& threadSynchronization ); + private: enum SyncMode { diff --git a/adaptors/integration-api/x11/pixmap-render-surface.h b/adaptors/integration-api/x11/pixmap-render-surface.h index b90e324..471462f 100644 --- a/adaptors/integration-api/x11/pixmap-render-surface.h +++ b/adaptors/integration-api/x11/pixmap-render-surface.h @@ -107,25 +107,12 @@ public: // from Dali::RenderSurface */ virtual void StopRender(); -private: - enum SyncMode - { - SYNC_MODE_NONE, - SYNC_MODE_WAIT - }; - /** - * Set the sync mode. - * @param[in] syncMode The sync mode + * @copydoc Dali::RenderSurface::SetThreadSynchronization */ - void SetSyncMode( SyncMode syncMode ); + virtual void SetThreadSynchronization( ThreadSynchronizationInterface& threadSynchronization ); - /** - * 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. - */ - void AcquireLock(); +private: /** * Release any locks. diff --git a/adaptors/wayland/pixmap-render-surface-wl.cpp b/adaptors/wayland/pixmap-render-surface-wl.cpp index f104850..cc76c24 100644 --- a/adaptors/wayland/pixmap-render-surface-wl.cpp +++ b/adaptors/wayland/pixmap-render-surface-wl.cpp @@ -140,6 +140,11 @@ void PixmapRenderSurface::StopRender() // FIXME } +void PixmapRenderSurface::SetThreadSynchronization( ThreadSynchronizationInterface& threadSynchronization ) +{ + // Nothing to do +} + void PixmapRenderSurface::CreateWlRenderable() { // check we're creating one with a valid size diff --git a/adaptors/wayland/window-render-surface-wl.cpp b/adaptors/wayland/window-render-surface-wl.cpp index cd565c9..38a2d44 100644 --- a/adaptors/wayland/window-render-surface-wl.cpp +++ b/adaptors/wayland/window-render-surface-wl.cpp @@ -228,6 +228,11 @@ void WindowRenderSurface::UseExistingRenderable( unsigned int surfaceId ) mWlWindow = AnyCast< Ecore_Wl_Window* >( surfaceId ); } +void WindowRenderSurface::SetThreadSynchronization( ThreadSynchronizationInterface& /* threadSynchronization */ ) +{ + // Nothing to do. +} + void WindowRenderSurface::ReleaseLock() { // Nothing to do. diff --git a/adaptors/wayland/window-render-surface.h b/adaptors/wayland/window-render-surface.h index 9a27b8b..7aea88b 100644 --- a/adaptors/wayland/window-render-surface.h +++ b/adaptors/wayland/window-render-surface.h @@ -134,6 +134,11 @@ public: // from Dali::RenderSurface virtual void StopRender(); /** + * @copydoc Dali::RenderSurface::SetThreadSynchronization + */ + virtual void SetThreadSynchronization( ThreadSynchronizationInterface& threadSynchronization ); + + /** * @copydoc Dali::RenderSurface::ReleaseLock() */ virtual void ReleaseLock(); diff --git a/adaptors/x11/pixmap-render-surface-x.cpp b/adaptors/x11/pixmap-render-surface-x.cpp index fa26edb..7f32b6e 100644 --- a/adaptors/x11/pixmap-render-surface-x.cpp +++ b/adaptors/x11/pixmap-render-surface-x.cpp @@ -32,13 +32,13 @@ // INTERNAL INCLUDES +#include #include #include #include #include #include - namespace Dali { @@ -49,14 +49,10 @@ extern Debug::Filter* gRenderSurfaceLogFilter; namespace ECore { - struct PixmapRenderSurface::Impl { - Internal::Adaptor::ConditionalWait mSyncNotify; ///< condition to notify main thread that pixmap was flushed to onscreen - Dali::Mutex mSyncMutex; ///< mutex to lock during waiting sync - Ecore_X_Pixmap mX11Pixmap; ///< X-Pixmap - SyncMode mSyncMode; ///< Stores whether the post render should block waiting for compositor - bool mSyncReceived; ///< true, when a pixmap sync has occurred, (cleared after reading) + Ecore_X_Pixmap mX11Pixmap; ///< X-Pixmap + ThreadSynchronizationInterface* mThreadSynchronization; ///< A pointer to the thread-synchronization }; PixmapRenderSurface::PixmapRenderSurface(Dali::PositionSize positionSize, @@ -66,8 +62,7 @@ PixmapRenderSurface::PixmapRenderSurface(Dali::PositionSize positionSize, : EcoreXRenderSurface( positionSize, surface, name, isTransparent ), mImpl( new Impl ) { - mImpl->mSyncMode = SYNC_MODE_NONE; - mImpl->mSyncReceived = false; + mImpl->mThreadSynchronization = NULL; Init( surface ); } @@ -138,7 +133,6 @@ bool PixmapRenderSurface::ReplaceEGLSurface( EglInterface& egl ) void PixmapRenderSurface::StartRender() { - } bool PixmapRenderSurface::PreRender( EglInterface&, Integration::GlAbstraction& ) @@ -152,7 +146,10 @@ void PixmapRenderSurface::PostRender( EglInterface& egl, Integration::GlAbstract // flush gl instruction queue glAbstraction.Flush(); - mImpl->mSyncReceived = false; + if( mImpl->mThreadSynchronization ) + { + mImpl->mThreadSynchronization->PostRenderStarted(); + } // create damage for client applications which wish to know the update timing if( mRenderNotification ) @@ -188,18 +185,22 @@ void PixmapRenderSurface::PostRender( EglInterface& egl, Integration::GlAbstract } } - if( !replacingSurface && mImpl->mSyncMode != SYNC_MODE_NONE ) + if( mImpl->mThreadSynchronization ) { - AcquireLock(); + mImpl->mThreadSynchronization->PostRenderWaitForCompletion(); } } void PixmapRenderSurface::StopRender() { - SetSyncMode(SYNC_MODE_NONE); ReleaseLock(); } +void PixmapRenderSurface::SetThreadSynchronization( ThreadSynchronizationInterface& threadSynchronization ) +{ + mImpl->mThreadSynchronization = &threadSynchronization; +} + void PixmapRenderSurface::CreateXRenderable() { // check we're creating one with a valid size @@ -233,26 +234,12 @@ void PixmapRenderSurface::UseExistingRenderable( unsigned int surfaceId ) mImpl->mX11Pixmap = static_cast< Ecore_X_Pixmap >( surfaceId ); } -void PixmapRenderSurface::SetSyncMode( SyncMode syncMode ) -{ - mImpl->mSyncMode = syncMode; -} - -void PixmapRenderSurface::AcquireLock() +void PixmapRenderSurface::ReleaseLock() { - if( !mImpl->mSyncReceived ) + if( mImpl->mThreadSynchronization ) { - mImpl->mSyncNotify.Wait(); + mImpl->mThreadSynchronization->PostRenderComplete(); } - mImpl->mSyncReceived = false; -} - -void PixmapRenderSurface::ReleaseLock() -{ - mImpl->mSyncReceived = true; - - // wake render thread if it was waiting for the notify - mImpl->mSyncNotify.Notify(); } } // namespace ECore diff --git a/adaptors/x11/window-render-surface-x.cpp b/adaptors/x11/window-render-surface-x.cpp index 18b8d14..0580f54 100644 --- a/adaptors/x11/window-render-surface-x.cpp +++ b/adaptors/x11/window-render-surface-x.cpp @@ -297,6 +297,11 @@ void WindowRenderSurface::UseExistingRenderable( unsigned int surfaceId ) mX11Window = static_cast< Ecore_X_Window >( surfaceId ); } +void WindowRenderSurface::SetThreadSynchronization( ThreadSynchronizationInterface& /* threadSynchronization */ ) +{ + // Nothing to do. +} + void WindowRenderSurface::ReleaseLock() { // Nothing to do. diff --git a/adaptors/x11/window-render-surface.h b/adaptors/x11/window-render-surface.h index 77b5e0a..f9b5b41 100644 --- a/adaptors/x11/window-render-surface.h +++ b/adaptors/x11/window-render-surface.h @@ -135,6 +135,11 @@ public: // from Dali::RenderSurface virtual void StopRender(); /** + * @copydoc Dali::RenderSurface::SetThreadSynchronization + */ + virtual void SetThreadSynchronization( ThreadSynchronizationInterface& threadSynchronization ); + + /** * @copydoc Dali::RenderSurface::ReleaseLock() */ virtual void ReleaseLock();