mPendingRequestUpdate( FALSE ),
mUseElapsedTimeAfterWait( FALSE ),
mNewSurface( NULL ),
+ mDeletedSurface( nullptr ),
mPostRendering( FALSE ),
mSurfaceResized( FALSE ),
mForceClear( FALSE )
{
LOG_EVENT_TRACE;
- // Set the ThreadSyncronizationInterface on the new surface
- newSurface->SetThreadSynchronization( *this );
+ if( mUpdateRenderThread )
+ {
+ // Set the ThreadSyncronizationInterface on the new surface
+ newSurface->SetThreadSynchronization( *this );
- LOG_EVENT( "Starting to replace the surface, event-thread blocked" );
+ LOG_EVENT( "Starting to replace 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 replace the surface now
- mNewSurface = newSurface;
- mUpdateRenderThreadWaitCondition.Notify( lock );
+ // Start replacing the surface.
+ {
+ ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
+ mPostRendering = FALSE; // Clear the post-rendering flag as Update/Render thread will replace the surface now
+ mNewSurface = newSurface;
+ mUpdateRenderThreadWaitCondition.Notify( lock );
+ }
+
+ // Wait until the surface has been replaced
+ sem_wait( &mEventThreadSemaphore );
+
+ LOG_EVENT( "Surface replaced, event-thread continuing" );
}
+}
- // Wait until the surface has been replaced
- sem_wait( &mEventThreadSemaphore );
+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 replaced, event-thread continuing" );
+ LOG_EVENT( "Surface deleted, event-thread continuing" );
+ }
}
void CombinedUpdateRenderController::ResizeSurface()
AddPerformanceMarker( PerformanceInterface::RENDER_START );
mCore.Render( renderStatus, mForceClear );
+
+ //////////////////////////////
+ // DELETE SURFACE
+ //////////////////////////////
+
+ Integration::RenderSurface* deletedSurface = ShouldSurfaceBeDeleted();
+ if( DALI_UNLIKELY( deletedSurface ) )
+ {
+ LOG_UPDATE_RENDER_TRACE_FMT( "Deleting Surface" );
+
+ mCore.SurfaceDeleted( deletedSurface );
+
+ SurfaceDeleted();
+ }
+
AddPerformanceMarker( PerformanceInterface::RENDER_END );
mForceClear = false;
( 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 );
}
+Integration::RenderSurface* CombinedUpdateRenderController::ShouldSurfaceBeDeleted()
+{
+ ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
+
+ Integration::RenderSurface* 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
! mSurfaceResized && // We should NOT wait if we're resizing the surface
! mDestroyUpdateRenderThread )
{
virtual void ReplaceSurface( Dali::RenderSurfaceInterface* surface );
/**
+ * @copydoc ThreadControllerInterface::DeleteSurface()
+ */
+ virtual void DeleteSurface( Dali::RenderSurfaceInterface* surface );
+
+ /**
* @copydoc ThreadControllerInterface::ResizeSurface()
*/
virtual void ResizeSurface();
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
+ */
+ Integration::RenderSurface* 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).
Integration::RenderSurface* volatile mNewSurface; ///< Will be set to the new-surface if requested (set by the event-thread, read & cleared by the update-render thread).
+ Integration::RenderSurface* 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).
return CreateVoidPixelBuffer( parameters );
}
+ // Choose the pixel format to be used.
+ //
+ // @note Behdad wrote "Upper 8 bits maps to the fourth byte in a little-endian machine like the intels."
+ // https://lists.cairographics.org/archives/cairo/2006-March/006563.html
+ //
+ // Here in practice Cairo's ARGB32 is like DALi's RGBA8888.
+ //
+ const bool isDstRgba = TextAbstraction::TextRenderer::Parameters::RGBA8888 == parameters.pixelFormat;
+ const Pixel::Format pixelFormat = isDstRgba ? Pixel::Format::RGBA8888 : Pixel::Format::A8;
+ const cairo_format_t cairoFormat = isDstRgba ? CAIRO_FORMAT_ARGB32 : CAIRO_FORMAT_A8;
+
+ const int bpp = Pixel::GetBytesPerPixel( pixelFormat );
+ if( 0u == bpp )
+ {
+ // return a pixel buffer with all pixels set to transparent.
+ return CreateVoidPixelBuffer( parameters );
+ }
+
+ // This function provides a stride value that will respect all alignment requirements of the
+ // accelerated image-rendering code within cairo.
+ const int stride = cairo_format_stride_for_width( cairoFormat,
+ static_cast<int>( parameters.width ) );
+ const int strideWidth = stride / bpp;
+
// Convert from DALi glyphs to Cairo glyphs.
std::vector<cairo_glyph_t> cairoGlyphs;
cairoGlyphs.resize( numberOfGlyphs );
glyphRuns.push_back( currentGlyphRun );
}
- // Choose the pixel format to be used.
- //
- // @note Behdad wrote "Upper 8 bits maps to the fourth byte in a little-endian machine like the intels."
- // https://lists.cairographics.org/archives/cairo/2006-March/006563.html
- //
- // Here in practice Cairo's ARGB32 is like DALi's RGBA8888.
- //
- const bool isDstRgba = TextAbstraction::TextRenderer::Parameters::RGBA8888 == parameters.pixelFormat;
- const Pixel::Format pixelFormat = isDstRgba ? Pixel::Format::RGBA8888 : Pixel::Format::A8;
- const cairo_format_t cairoFormat = isDstRgba ? CAIRO_FORMAT_ARGB32 : CAIRO_FORMAT_A8;
-
- // This function provides a stride value that will respect all alignment requirements of the
- // accelerated image-rendering code within cairo.
- const int stride = cairo_format_stride_for_width( cairoFormat,
- static_cast<int>( parameters.width ) );
- const int strideWidth = stride / Pixel::GetBytesPerPixel( pixelFormat );
-
// Creates the pixel buffer and retrieves the buffer pointer used to create the Cairo's surface.
Devel::PixelBuffer pixelBuffer = Devel::PixelBuffer::New( strideWidth, parameters.height, pixelFormat );