DALI_ASSERT_DEBUG( defaultWindow->GetSurface() && "Surface not initialized" );
- mGraphics = &( graphicsFactory.Create() );
+ mGraphics = std::unique_ptr< GraphicsInterface >( &graphicsFactory.Create() );
mGraphics->Initialize( mEnvironmentOptions );
- auto eglGraphics = static_cast<EglGraphics *>( mGraphics ); // This interface is temporary until Core has been updated to match
+ GraphicsInterface* graphics = mGraphics.get(); // This interface is temporary until Core has been updated to match
+ auto eglGraphics = static_cast<EglGraphics *>( graphics );
// This will only be created once
eglGraphics->Create();
}
}
+void Adaptor::DeleteSurface( Dali::RenderSurfaceInterface& surface )
+{
+ // Flush the event queue to give the update-render thread chance
+ // to start processing messages for new camera setup etc as soon as possible
+ ProcessCoreEvents();
+
+ // This method blocks until the render thread has finished rendering the current surface.
+ mThreadController->DeleteSurface( &surface );
+}
+
Dali::RenderSurfaceInterface& Adaptor::GetSurface() const
{
return *mWindows.front()->GetSurface();
GraphicsInterface& Adaptor::GetGraphicsInterface()
{
DALI_ASSERT_DEBUG( mGraphics && "Graphics interface not created" );
- return *mGraphics;
+ return *( mGraphics.get() );
}
Dali::Integration::PlatformAbstraction& Adaptor::GetPlatformAbstractionInterface()
if (mGraphics)
{
- auto eglGraphics = static_cast<EglGraphics *>( mGraphics ); // This interface is temporary until Core has been updated to match
+ GraphicsInterface* graphics = mGraphics.get(); // This interface is temporary until Core has been updated to match
+ auto eglGraphics = static_cast<EglGraphics *>( graphics );
EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
display = eglImpl.GetDisplay();
return mConfigurationManager->IsMultipleWindowSupported();
}
-bool Adaptor::IsRenderingWindows() const
-{
- return ( mThreadController && mThreadController->IsRenderingWindows() );
-}
-
void Adaptor::RequestUpdateOnce()
{
if( mThreadController )
mPendingRequestUpdate( FALSE ),
mUseElapsedTimeAfterWait( FALSE ),
mNewSurface( NULL ),
+ mDeletedSurface( nullptr ),
mPostRendering( FALSE ),
mSurfaceResized( FALSE ),
mForceClear( FALSE ),
mUploadWithoutRendering( FALSE ),
- mFirstFrameAfterResume( FALSE ),
- mIsRenderingWindows( false )
+ mFirstFrameAfterResume( FALSE )
{
LOG_EVENT_TRACE;
}
}
+void CombinedUpdateRenderController::DeleteSurface( Dali::RenderSurfaceInterface* surface )
+{
+ LOG_EVENT_TRACE;
+
+ if( mUpdateRenderThread )
+ {
+ LOG_EVENT( "Starting to delete the surface, event-thread blocked" );
+
+ // Start replacing the surface.
+ {
+ ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
+ mPostRendering = FALSE; // Clear the post-rendering flag as Update/Render thread will delete the surface now
+ mDeletedSurface = surface;
+ mUpdateRenderThreadWaitCondition.Notify( lock );
+ }
+
+ // Wait until the surface has been deleted
+ sem_wait( &mEventThreadSemaphore );
+
+ LOG_EVENT( "Surface deleted, event-thread continuing" );
+ }
+}
+
void CombinedUpdateRenderController::WaitForGraphicsInitialization()
{
LOG_EVENT_TRACE;
AddPerformanceMarker( PerformanceInterface::RENDER_START );
- mIsRenderingWindows = true;
-
// Upload shared resources
mCore.PreRender( renderStatus, mForceClear, mUploadWithoutRendering );
for( auto&& window : windows )
{
- if ( window && !window->IsBeingDeleted() )
- {
- Dali::Integration::Scene scene = window->GetScene();
- Dali::RenderSurfaceInterface* windowSurface = window->GetSurface();
+ Dali::Integration::Scene scene = window->GetScene();
+ Dali::RenderSurfaceInterface* windowSurface = window->GetSurface();
- if ( scene && windowSurface )
- {
- windowSurface->InitializeGraphics();
+ if ( scene && windowSurface )
+ {
+ windowSurface->InitializeGraphics();
- // Render off-screen frame buffers first if any
- mCore.RenderScene( scene, true );
+ // Render off-screen frame buffers first if any
+ mCore.RenderScene( scene, true );
- // Switch to the EGL context of the surface
- windowSurface->PreRender( surfaceResized ); // Switch GL context
+ // Switch to the EGL context of the surface
+ windowSurface->PreRender( surfaceResized ); // Switch GL context
- // Render the surface
- mCore.RenderScene( scene, false );
+ // Render the surface
+ mCore.RenderScene( scene, false );
- windowSurface->PostRender( false, false, surfaceResized ); // Swap Buffer
- }
+ windowSurface->PostRender( false, false, surfaceResized ); // Swap Buffer
}
}
}
mCore.PostRender( mUploadWithoutRendering );
- mIsRenderingWindows = false;
+ //////////////////////////////
+ // DELETE SURFACE
+ //////////////////////////////
+
+ Dali::RenderSurfaceInterface* deletedSurface = ShouldSurfaceBeDeleted();
+ if( DALI_UNLIKELY( deletedSurface ) )
+ {
+ LOG_UPDATE_RENDER_TRACE_FMT( "Deleting Surface" );
+
+ deletedSurface->DestroySurface();
+
+ SurfaceDeleted();
+ }
AddPerformanceMarker( PerformanceInterface::RENDER_END );
}
}
- // Inform core of context destruction & shutdown EGL
+ // Inform core of context destruction
mCore.ContextDestroyed();
currentSurface = mAdaptorInterfaces.GetRenderSurfaceInterface();
if( currentSurface )
currentSurface = nullptr;
}
+ // Shutdown EGL
+ eglInterface->TerminateGles();
+
LOG_UPDATE_RENDER( "THREAD DESTROYED" );
// Uninstall the logging function
( mUpdateRenderThreadCanSleep && ! updateRequired && ! mPendingRequestUpdate ) ) && // Ensure we wait if we're supposed to be sleeping AND do not require another update
! mDestroyUpdateRenderThread && // Ensure we don't wait if the update-render-thread is supposed to be destroyed
! mNewSurface && // Ensure we don't wait if we need to replace the surface
+ ! mDeletedSurface && // Ensure we don't wait if we need to delete the surface
! mSurfaceResized ) // Ensure we don't wait if we need to resize the surface
{
LOG_UPDATE_RENDER( "WAIT: mUpdateRenderRunCount: %d", mUpdateRenderRunCount );
LOG_UPDATE_RENDER( " mUpdateRenderThreadCanSleep: %d, updateRequired: %d, mPendingRequestUpdate: %d", mUpdateRenderThreadCanSleep, updateRequired, mPendingRequestUpdate );
LOG_UPDATE_RENDER( " mDestroyUpdateRenderThread: %d", mDestroyUpdateRenderThread );
LOG_UPDATE_RENDER( " mNewSurface: %d", mNewSurface );
+ LOG_UPDATE_RENDER( " mDeletedSurface: %d", mDeletedSurface );
LOG_UPDATE_RENDER( " mSurfaceResized: %d", mSurfaceResized );
// Reset the time when the thread is waiting, so the sleep-until time for
LOG_COUNTER_UPDATE_RENDER( "mUpdateRenderThreadCanSleep: %d, updateRequired: %d, mPendingRequestUpdate: %d", mUpdateRenderThreadCanSleep, updateRequired, mPendingRequestUpdate );
LOG_COUNTER_UPDATE_RENDER( "mDestroyUpdateRenderThread: %d", mDestroyUpdateRenderThread );
LOG_COUNTER_UPDATE_RENDER( "mNewSurface: %d", mNewSurface );
+ LOG_COUNTER_UPDATE_RENDER( "mDeletedSurface: %d", mDeletedSurface );
LOG_COUNTER_UPDATE_RENDER( "mSurfaceResized: %d", mSurfaceResized );
mUseElapsedTimeAfterWait = FALSE;
sem_post( &mEventThreadSemaphore );
}
+Dali::RenderSurfaceInterface* CombinedUpdateRenderController::ShouldSurfaceBeDeleted()
+{
+ ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
+
+ Dali::RenderSurfaceInterface* deletedSurface = mDeletedSurface;
+ mDeletedSurface = NULL;
+
+ return deletedSurface;
+}
+
+void CombinedUpdateRenderController::SurfaceDeleted()
+{
+ // Just increment the semaphore
+ sem_post( &mEventThreadSemaphore );
+}
+
bool CombinedUpdateRenderController::ShouldSurfaceBeResized()
{
ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
while( mPostRendering &&
! mNewSurface && // We should NOT wait if we're replacing the surface
+ ! mDeletedSurface && // We should NOT wait if we're deleting the surface
! mDestroyUpdateRenderThread )
{
mUpdateRenderThreadWaitCondition.Wait( lock );
virtual void ReplaceSurface( Dali::RenderSurfaceInterface* surface );
/**
+ * @copydoc ThreadControllerInterface::DeleteSurface()
+ */
+ virtual void DeleteSurface( Dali::RenderSurfaceInterface* surface );
+
+ /**
* @copydoc ThreadControllerInterface::ResizeSurface()
*/
virtual void ResizeSurface();
*/
virtual void AddSurface( Dali::RenderSurfaceInterface* surface );
- /**
- * @copydoc ThreadControllerInterface::IsRenderingWindows()
- */
- bool IsRenderingWindows() const override { return mIsRenderingWindows; }
-
private:
// Undefined copy constructor.
void SurfaceReplaced();
/**
+ * Checks to see if the surface needs to be deleted.
+ * This will lock the mutex in mUpdateRenderThreadWaitCondition.
+ *
+ * @return Pointer to the deleted surface, nullptr otherwise
+ */
+ Dali::RenderSurfaceInterface* ShouldSurfaceBeDeleted();
+
+ /**
+ * Called by the Update/Render thread after a surface has been deleted.
+ *
+ * This will lock the mutex in mEventThreadWaitCondition
+ */
+ void SurfaceDeleted();
+
+ /**
* Checks to see if the surface needs to be resized.
* This will lock the mutex in mUpdateRenderThreadWaitCondition.
*
volatile unsigned int mUseElapsedTimeAfterWait; ///< Whether we should use the elapsed time after waiting (set by the event-thread, read by the update-render-thread).
Dali::RenderSurfaceInterface* volatile mNewSurface; ///< Will be set to the new-surface if requested (set by the event-thread, read & cleared by the update-render thread).
+ Dali::RenderSurfaceInterface* volatile mDeletedSurface; ///< Will be set to the deleted surface if requested (set by the event-thread, read & cleared by the update-render thread).
volatile unsigned int mPostRendering; ///< Whether post-rendering is taking place (set by the event & render threads, read by the render-thread).
volatile unsigned int mSurfaceResized; ///< Will be set to resize the surface (set by the event-thread, read & cleared by the update-render thread).
volatile unsigned int mUploadWithoutRendering; ///< Will be set to upload the resource only (with no rendering)
volatile unsigned int mFirstFrameAfterResume; ///< Will be set to check the first frame after resume (for log)
-
- std::atomic<bool> mIsRenderingWindows; ///< This is set only from the render thread and read only from the event thread
};
} // namespace Adaptor