// Consume any pending events
ConsumeEvents();
- // Check if we've got any requests from the main thread (e.g. replace surface)
- bool requestProcessed = ProcessRequest( request );
+ bool processRequests = true;
+ bool requestProcessed = false;
+ while( processRequests && running)
+ {
+ // Check if we've got any requests from the main thread (e.g. replace surface)
+ requestProcessed = ProcessRequest( request );
+
+ // perform any pre-render operations
+ DALI_LOG_INFO( gRenderLogFilter, Debug::Verbose, "RenderThread::Run. 3 - PreRender\n");
+ bool preRendered = PreRender(); // Returns false if no surface onto which to render
+ if( preRendered )
+ {
+ processRequests = false;
+ }
+ else
+ {
+ // Block until new surface... - cleared by ReplaceSurface code in UpdateRenderController
+ running = mUpdateRenderSync.RenderSyncWithRequest(request);
+ }
+ }
- // perform any pre-render operations
- DALI_LOG_INFO( gRenderLogFilter, Debug::Verbose, "RenderThread::Run. 3 - PreRender\n");
- if( running && PreRender() == true)
+ if( running )
{
// Render
DALI_LOG_INFO( gRenderLogFilter, Debug::Verbose, "RenderThread::Run. 4 - Core.Render()\n");
mUpdateRenderSync->ReplaceSurface( newSurface );
}
+void UpdateRenderController::NewSurface( RenderSurface* newSurface )
+{
+ // This API shouldn't be used when there is a current surface, but check anyway.
+ RenderSurface* currentSurface = mAdaptorInterfaces.GetRenderSurfaceInterface();
+ if( currentSurface )
+ {
+ currentSurface->StopRender();
+ }
+
+ mUpdateRenderSync->NewSurface( newSurface );
+}
+
void UpdateRenderController::SetRenderRefreshRate(unsigned int numberOfVSyncsPerRender )
{
mNumberOfVSyncsPerRender = numberOfVSyncsPerRender;
void ReplaceSurface( RenderSurface* surface );
/**
+ * Provides a new surface. Should be used if the old surface has been lost
+ * for any reason.
+ * @param surface new surface
+ */
+ void NewSurface( RenderSurface* surface );
+
+ /**
* @copydoc Dali::Adaptor::SetRenderRefreshRate()
*/
void SetRenderRefreshRate( unsigned int numberOfVSyncsPerRender );
mRenderFinishedCondition.notify_one();
mVSyncSleepCondition.notify_one();
mVSyncReceivedCondition.notify_one();
+ mRenderRequestSleepCondition.notify_one();
mFrameTime.Suspend();
}
mReplaceSurfaceRequest.SetSurface(newSurface);
mReplaceSurfaceRequested = true;
- mRequestFinishedCondition.wait(lock); // wait unlocks the mutex on entry, and locks again on exit.
+ mRenderRequestFinishedCondition.wait(lock); // wait unlocks the mutex on entry, and locks again on exit.
mReplaceSurfaceRequested = false;
result = mReplaceSurfaceRequest.GetReplaceCompleted();
return result;
}
+bool UpdateRenderSynchronization::NewSurface( RenderSurface* newSurface )
+{
+ bool result=false;
+
+ UpdateRequested();
+ UpdateWhilePaused();
+ {
+ boost::unique_lock< boost::mutex > lock( mMutex );
+
+ mReplaceSurfaceRequest.SetSurface(newSurface);
+ mReplaceSurfaceRequested = true;
+
+ // Unlock the render thread sleeping on requests
+ mRenderRequestSleepCondition.notify_one();
+
+ // Lock event thread until request has been processed
+ mRenderRequestFinishedCondition.wait(lock);// wait unlocks the mutex on entry, and locks again on exit.
+
+ mReplaceSurfaceRequested = false;
+ result = mReplaceSurfaceRequest.GetReplaceCompleted();
+ }
+
+ return result;
+}
+
+
void UpdateRenderSynchronization::UpdateReadyToRun()
{
bool wokenFromPause( false );
return mRunning;
}
+bool UpdateRenderSynchronization::RenderSyncWithRequest(RenderRequest*& requestPtr)
+{
+ boost::unique_lock< boost::mutex > lock( mMutex );
+
+ // Wait for a replace surface request
+ mRenderRequestSleepCondition.wait(lock);
+
+ // write any new requests
+ if( mReplaceSurfaceRequested )
+ {
+ requestPtr = &mReplaceSurfaceRequest;
+ }
+ mReplaceSurfaceRequested = false;
+ return mRunning;
+}
+
bool UpdateRenderSynchronization::RenderSyncWithUpdate(RenderRequest*& requestPtr)
{
boost::unique_lock< boost::mutex > lock( mMutex );
if( requestProcessed )
{
// Notify the event thread that a request has completed
- mRequestFinishedCondition.notify_one();
+ mRenderRequestFinishedCondition.notify_one();
}
AddPerformanceMarker( PerformanceInterface::RENDER_END );
void UpdateWhilePaused();
/**
- * Inform the render thread that there is a new surface.
+ * Inform the render thread that there is a new surface, and that
+ * it should replace the current surface.
* @param[in] newSurface The new surface for rendering.
*/
bool ReplaceSurface( RenderSurface* newSurface );
/**
+ * Inform the render thread that there is a new surface. Should be used
+ * after SurfaceLost() has been used to inform RenderThread that the surface
+ * has gone.
+ *
+ * @param[in] newSurface The new surface for rendering.
+ */
+ bool NewSurface( RenderSurface* newSurface );
+
+ /**
* Called by Update thread before it runs the update. This is the point where we can pause
*/
void UpdateReadyToRun();
bool UpdateTryToSleep();
/**
+ * Block the render thread whilst waiting for requests e.g. providing a new
+ * surface.
+ * @param[in] request Pointer to set if there are any requests
+ */
+ bool RenderSyncWithRequest(RenderRequest*& request );
+
+ /**
* Called by the render-thread to wait for a buffer to read from and then render.
* @pre Called by render thread only.
* @param[in] request Pointer to set if there are any requests
boost::condition_variable mVSyncReceivedCondition; ///< The render thread waits on this condition
boost::condition_variable mVSyncSleepCondition; ///< The vsync thread waits for this condition
boost::condition_variable mPausedCondition; ///< The controller waits for this condition while paused
- boost::condition_variable mRequestFinishedCondition;///< The controller waits for this condition
+ boost::condition_variable mRenderRequestSleepCondition; ///< The render thread waits for this condition
+ boost::condition_variable mRenderRequestFinishedCondition;///< The controller waits for this condition
FrameTime mFrameTime; ///< Frame timer predicts next vsync time
TriggerEventInterface& mNotificationTrigger; ///< Reference to notification event trigger
/**
* Invoked by render thread before Core::Render
+ * If the operation fails, then Core::Render should not be called until there is
+ * a surface to render onto.
* @param[in] egl The Egl interface
* @param[in] glAbstraction OpenGLES abstraction interface
- * @return True if the operation is successful
+ * @return True if the operation is successful, False if the operation failed
*/
virtual bool PreRender( EglInterface& egl, Integration::GlAbstraction& glAbstraction ) = 0;