namespace Adaptor
{
-ThreadController::ThreadController( AdaptorInternalServices& adaptorInterfaces,
- const EnvironmentOptions& environmentOptions )
+ThreadController::ThreadController( AdaptorInternalServices& adaptorInterfaces, const EnvironmentOptions& environmentOptions )
: mAdaptorInterfaces( adaptorInterfaces ),
mUpdateThread( NULL ),
mRenderThread( NULL ),
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()
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();
mVSyncThreadStop( FALSE ),
mRenderThreadStop( FALSE ),
mRenderThreadReplacingSurface( FALSE ),
+ mRenderThreadSurfaceRendered( FALSE ),
mEventThreadSurfaceReplaced( FALSE ),
mVSyncThreadInitialised( FALSE ),
mRenderThreadInitialised( FALSE ),
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
{
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
///////////////////////////////////////////////////////////////////////////////////////////////////
// EXTERNAL INCLUDES
// INTERNAL INCLUDES
+#include <integration-api/thread-synchronization-interface.h>
#include <base/interfaces/performance-interface.h>
#include <base/conditional-wait.h>
#include <trigger-event-interface.h>
* 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:
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
/////////////////////////////////////////////////////////////////////////////////////////////////
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).
class EglInterface;
class DisplayConnection;
+class ThreadSynchronizationInterface;
namespace Integration
{
*/
virtual void ReleaseLock() = 0;
+ /**
+ * @brief Sets the ThreadSynchronizationInterface
+ *
+ * @param threadSynchronization The thread-synchronization implementation.
+ */
+ virtual void SetThreadSynchronization( ThreadSynchronizationInterface& threadSynchronization ) = 0;
+
private:
/**
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 \
--- /dev/null
+#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__
*/
virtual void StopRender();
+ /**
+ * @copydoc Dali::RenderSurface::SetThreadSynchronization
+ */
+ virtual void SetThreadSynchronization( ThreadSynchronizationInterface& threadSynchronization );
+
private:
enum SyncMode
{
*/
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.
// FIXME
}
+void PixmapRenderSurface::SetThreadSynchronization( ThreadSynchronizationInterface& threadSynchronization )
+{
+ // Nothing to do
+}
+
void PixmapRenderSurface::CreateWlRenderable()
{
// check we're creating one with a valid size
mWlWindow = AnyCast< Ecore_Wl_Window* >( surfaceId );
}
+void WindowRenderSurface::SetThreadSynchronization( ThreadSynchronizationInterface& /* threadSynchronization */ )
+{
+ // Nothing to do.
+}
+
void WindowRenderSurface::ReleaseLock()
{
// Nothing to do.
virtual void StopRender();
/**
+ * @copydoc Dali::RenderSurface::SetThreadSynchronization
+ */
+ virtual void SetThreadSynchronization( ThreadSynchronizationInterface& threadSynchronization );
+
+ /**
* @copydoc Dali::RenderSurface::ReleaseLock()
*/
virtual void ReleaseLock();
// INTERNAL INCLUDES
+#include <integration-api/thread-synchronization-interface.h>
#include <ecore-x-types.h>
#include <trigger-event.h>
#include <gl/egl-implementation.h>
#include <base/display-connection.h>
#include <base/conditional-wait.h>
-
namespace Dali
{
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,
: EcoreXRenderSurface( positionSize, surface, name, isTransparent ),
mImpl( new Impl )
{
- mImpl->mSyncMode = SYNC_MODE_NONE;
- mImpl->mSyncReceived = false;
+ mImpl->mThreadSynchronization = NULL;
Init( surface );
}
void PixmapRenderSurface::StartRender()
{
-
}
bool PixmapRenderSurface::PreRender( EglInterface&, Integration::GlAbstraction& )
// 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 )
}
}
- 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
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
mX11Window = static_cast< Ecore_X_Window >( surfaceId );
}
+void WindowRenderSurface::SetThreadSynchronization( ThreadSynchronizationInterface& /* threadSynchronization */ )
+{
+ // Nothing to do.
+}
+
void WindowRenderSurface::ReleaseLock()
{
// Nothing to do.
virtual void StopRender();
/**
+ * @copydoc Dali::RenderSurface::SetThreadSynchronization
+ */
+ virtual void SetThreadSynchronization( ThreadSynchronizationInterface& threadSynchronization );
+
+ /**
* @copydoc Dali::RenderSurface::ReleaseLock()
*/
virtual void ReleaseLock();