[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 <david.steele@partner.samsung.com>
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 )
mPreviousUpdateFrames[i] = 0;
}
- SetLastVSyncTime();
- mLastVSyncTimeAtUpdate = mLastVSyncTime;
+ SetLastSyncTime();
+ mLastSyncTimeAtUpdate = mLastSyncTime;
DALI_LOG_INFO( gLogFilter, Debug::Concise, "FrameTime Initialized\n" );
}
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 ) );
}
}
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 )
{
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;
{
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 )
{
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;
}
}
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
* 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:
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).
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
*/
// INTERNAL INCLUDES
-#include <slp-platform-abstraction.h>
#include <dali/integration-api/core.h>
#include <dali/integration-api/gl-abstraction.h>
#include <base/interfaces/egl-factory-interface.h>
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
*/
virtual void TerminateGles() = 0;
- /**
- * Sets the refresh sync mode.
- * @see SyncMode
- */
- virtual bool SetRefreshSync( SyncMode mode ) = 0;
-
/**
* Performs an OpenGL swap buffers command
*/
} // namespace Dali
#endif // __DALI_INTERNAL_ADAPTOR_BASE_EGL_INTERFACE_H__
-
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;
// INTERNAL INCLUDES
#include <base/environment-options.h>
+#include <dali/integration-api/platform-abstraction.h>
namespace Dali
{
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,
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 )
{
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" );
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<boost::mutex> lock( mSurfaceChangedMutex );
// if already completed no need to wait
}
}
-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 !!!
// 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();
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() );
// 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) );
}
currentTime = newTime;
}
+ DALI_LOG_INFO( gRenderLogFilter, Debug::Verbose, "RenderThread::Run. 6 - RenderSyncWithUpdate()\n");
+
// Wait until another frame has been updated
running = mUpdateRenderSync.RenderSyncWithUpdate();
}
// 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();
// 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 )
{
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
*/
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
*/
*/
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
};
: 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 );
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
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:
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
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 ),
mUpdateRequested( false ),
mAllowUpdateWhilePaused( false ),
mVSyncSleep( false ),
- mVSyncFrameNumber( 0u ),
- mVSyncSeconds( 0u ),
- mVSyncMicroseconds( 0u ),
+ mSyncFrameNumber( 0u ),
+ mSyncSeconds( 0u ),
+ mSyncMicroseconds( 0u ),
mFrameTime( adaptorInterfaces.GetPlatformAbstractionInterface() ),
mPerformanceInterface( adaptorInterfaces.GetPerformanceInterface() )
{
void UpdateRenderSynchronization::Start()
{
+ mFrameTime.SetMinimumFrameTimeInterval( mNumberOfVSyncsPerRender * TIME_PER_FRAME_IN_MICROSECONDS );
mRunning = true;
}
if ( !wokenFromPause )
{
- // Wait for the next VSync
- WaitVSync();
+ // Wait for the next Sync
+ WaitSync();
}
AddPerformanceMarker( PerformanceMarker::UPDATE_START );
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.
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();
unsigned int UpdateRenderSynchronization::GetFrameNumber() const
{
- return mVSyncFrameNumber;
+ return mSyncFrameNumber;
}
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 )
}
}
-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
* 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
{
/**
* 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();
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
* @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.
* 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;
*/
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.
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
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
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,
void UpdateThread::Start()
{
+ DALI_LOG_INFO( gUpdateLogFilter, Debug::Verbose, "UpdateThread::Start()\n");
if ( !mThread )
{
// Create and run the update-thread
void UpdateThread::Stop()
{
+ DALI_LOG_INFO( gUpdateLogFilter, Debug::Verbose, "UpdateThread::Stop()\n");
if( mThread )
{
// wait for the thread to finish
bool UpdateThread::Run()
{
+ DALI_LOG_INFO( gUpdateLogFilter, Debug::Verbose, "UpdateThread::Run()\n");
Integration::UpdateStatus status;
// install a function for logging
// 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 )
{
// 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 )
{
if( !runUpdate )
{
+ DALI_LOG_INFO( gUpdateLogFilter, Debug::Verbose, "UpdateThread::Run. 5 - Nothing to update, trying to sleep\n");
+
running = mUpdateRenderSync.UpdateTryToSleep();
}
}
*/
// EXTERNAL INCLUDES
-#include <xf86drm.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
#include <boost/thread.hpp>
#include <dali/integration-api/core.h>
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
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 )
{
void VSyncNotifier::Stop()
{
- DALI_LOG_INFO( gLogFilter, Debug::General, "%s\n", __func__ );
+ DALI_LOG_INFO( gSyncLogFilter, Debug::General, "%s\n", __func__ );
if( mThread )
{
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; i<mNumberOfVSyncsPerRender; ++i )
+ {
+ // Yes..wait for N hardware VSync ticks
+ validSync = mVSyncMonitor->DoSync( currentSequenceNumber, currentSeconds, currentMicroseconds );
+ }
}
else
{
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
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
{
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
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)
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)
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.
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.
// 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 );
*/
bool IsGlesInitialized() const;
- /**
- * Sets the refresh sync mode.
- * @see SyncMode
- */
- virtual bool SetRefreshSync( SyncMode mode );
-
/**
* Performs an OpenGL swap buffers command
*/
bool mGlesInitialized;
bool mIsOwnSurface;
- SyncMode mSyncMode;
bool mContextCurrent;
bool mIsWindow;
ColorDepth mColorDepth;
#include <render-surface.h>
#include <dali/public-api/common/dali-common.h>
#include <dali/public-api/common/view-mode.h>
+#include <base/interfaces/egl-interface.h>
namespace Dali
{
*/
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:
/**
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;
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
* @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
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
* 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
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
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();
*/
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.
*
NATIVE_BUFFER ///< Native Buffer
};
- /**
- * @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
*
*/
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:
/**
// - 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" );
}
VSyncMonitor::VSyncMonitor()
: mFileDescriptor( FD_NONE ),
- mUseHardware( true )
+ mUseHardwareVSync( true ),
+ mHardwareVSyncAvailable( false )
{
vconf_notify_key_changed( VCONFKEY_PM_STATE, ScreenStatusChanged, this );
}
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()
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" );
VSyncMonitor::VSyncMonitor()
: mFileDescriptor( FD_NONE ),
- mUseHardware( false )
+ mUseHardwareVSync( false ),
+ mHardwareVsyncAvailable( false )
{
}
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()
void VSyncMonitor::Terminate()
{
- if( mFileDescriptor != FD_NONE )
- {
- close( mFileDescriptor );
- mFileDescriptor = FD_NONE;
- }
}
bool VSyncMonitor::UseHardware()
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 );
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
{
}
-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 )
{
}
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
*/
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
/**
*/
virtual void ConsumeEvents();
- /**
- * @copydoc Dali::Internal::Adaptor::RenderSurface::RenderSync()
- */
- virtual void RenderSync();
-
/**
* @copydoc Dali::Internal::Adaptor::RenderSurface::SetViewMode()
*/
/**
* @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:
*/
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
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
mEglSurface(0),
mGlesInitialized(false),
mIsOwnSurface(true),
- mSyncMode(FULL_SYNC),
mContextCurrent(false),
mIsWindow(true),
mColorDepth(COLOR_DEPTH_24)
eglQueryString(mEglDisplay, EGL_CLIENT_APIS),
eglQueryString(mEglDisplay, EGL_EXTENSIONS));
- if ( mIsWindow )
- {
- SetRefreshSync( mSyncMode );
- }
}
void EglImplementation::MakeContextNull()
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 );
} // namespace Internal
} // namespace Dali
-
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();
}
// Do render synchronisation
- DoRenderSync( timeDelta, syncMode );
+ // AcquireLock( replacingSurface ? SYNC_MODE_NONE : SYNC_MODE_WAIT );
+}
+
+void PixmapRenderSurface::StopRender()
+{
}
void PixmapRenderSurface::CreateWlRenderable()
{
}
-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
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()
/**
* @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
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<EglImplementation&>( egl );
eglImpl.SwapBuffers();
}
}
+void WindowRenderSurface::StopRender()
+{
+}
+
void WindowRenderSurface::SetViewMode( ViewMode viewMode )
{
}
mWlWindow = AnyCast< Ecore_Wl_Window* >( surfaceId );
}
+void WindowRenderSurface::ReleaseLock()
+{
+ // Nothing to do.
+}
+
} // namespace ECore
} // namespace Adaptor
*/
virtual void Map();
+ /**
+ * @copydoc Dali::Internal::Adaptor::RenderSurface::StartRender()
+ */
+ virtual void StartRender();
+
/**
* @copydoc Dali::Internal::Adaptor::RenderSurface::PreRender()
*/
/**
* @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:
/**
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 );
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
}
}
-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 )
{
}
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
*/
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
/**
*/
virtual void ConsumeEvents();
- /**
- * @copydoc Dali::Internal::Adaptor::RenderSurface::RenderSync()
- */
- virtual void RenderSync();
-
/**
* @copydoc Dali::Internal::Adaptor::RenderSurface::SetViewMode()
*/
/**
* @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:
*/
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
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
mEglSurface(0),
mGlesInitialized(false),
mIsOwnSurface(true),
- mSyncMode(FULL_SYNC),
mContextCurrent(false),
mIsWindow(true),
mColorDepth(COLOR_DEPTH_24)
eglQueryString(mEglDisplay, EGL_VERSION),
eglQueryString(mEglDisplay, EGL_CLIENT_APIS),
eglQueryString(mEglDisplay, EGL_EXTENSIONS));
-
- if ( mIsWindow )
- {
- SetRefreshSync( mSyncMode );
- }
}
void EglImplementation::MakeContextNull()
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 );
} // namespace Internal
} // namespace Dali
-
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 );
}
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();
}
}
- // 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()
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 );
mSyncNotify.notify_all();
}
+
} // namespace ECore
} // namespace Adaptor
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()
/**
* @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
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
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<EglImplementation&>( egl );
eglImpl.SwapBuffers();
}
}
+void WindowRenderSurface::StopRender()
+{
+}
+
void WindowRenderSurface::SetViewMode( ViewMode viewMode )
{
Ecore_X_Atom viewModeAtom( ecore_x_atom_get( "_E_COMP_3D_APP_WIN" ) );
mX11Window = static_cast< Ecore_X_Window >( surfaceId );
}
+void WindowRenderSurface::ReleaseLock()
+{
+ // Nothing to do.
+}
+
} // namespace ECore
} // namespace Adaptor
*/
virtual void Map();
+ /**
+ * @copydoc Dali::Internal::Adaptor::RenderSurface::StartRender()
+ */
+ virtual void StartRender();
+
/**
* @copydoc Dali::Internal::Adaptor::RenderSurface::PreRender()
*/
/**
* @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:
/**