END_TEST;
}
+int UtcDaliSceneDeleteSurface(void)
+{
+ TestApplication application;
+
+ // Create a Scene
+ Dali::Integration::Scene scene = Dali::Integration::Scene::New( Vector2( 480.0f, 800.0f ) );
+ DALI_TEST_CHECK( scene );
+
+ // Create the render surface for the scene
+ TestRenderSurface* renderSurface = new TestRenderSurface( Dali::PositionSize( 0, 0, 480.0f, 800.0f ) );
+ scene.SetSurface( *renderSurface );
+
+ // Render and notify.
+ application.SendNotification();
+ application.Render(0);
+
+ // Add a renderable actor to the scene
+ auto actor = CreateRenderableActor();
+ scene.Add( actor );
+
+ // Render and notify.
+ application.SendNotification();
+ application.Render(0);
+
+ // Notify the Core that the render surface will be deleted.
+ application.GetCore().SurfaceDeleted( renderSurface );
+
+ // Delete the render surface
+ delete renderSurface;
+ renderSurface = nullptr;
+
+ // Render and notify.
+ application.SendNotification();
+ application.Render(0);
+
+ END_TEST;
+}
+
int UtcDaliSceneEventProcessingFinishedP(void)
{
TestApplication application;
mImpl->SurfaceResized(surface);
}
+void Core::SurfaceDeleted( Integration::RenderSurface* surface )
+{
+ mImpl->SurfaceDeleted(surface);
+}
+
void Core::SceneCreated()
{
mImpl->SceneCreated();
*/
void SurfaceResized( Integration::RenderSurface* surface );
+ /**
+ * Notify the Core that the GL surface has been deleted.
+ * Multi-threading note: this method should be called from the main thread
+ * @param[in] surface The deleted surface
+ */
+ void SurfaceDeleted( Integration::RenderSurface* surface );
+
// Core Lifecycle
/**
}
}
+void Core::SurfaceDeleted( Integration::RenderSurface* surface )
+{
+ for( auto scene : mScenes )
+ {
+ if( scene->GetSurface() == surface )
+ {
+ scene->SurfaceDeleted();
+ break;
+ }
+ }
+}
+
void Core::Update( float elapsedSeconds, uint32_t lastVSyncTimeMilliseconds, uint32_t nextVSyncTimeMilliseconds, Integration::UpdateStatus& status, bool renderToFboEnabled, bool isRenderingToFbo )
{
// set the time delta so adaptor can easily print FPS with a release build with 0 as
void SurfaceResized( Integration::RenderSurface* surface );
/**
+ * @copydoc Dali::Integration::Core::SurfaceDeleted(Integration::RenderSurface*)
+ */
+ void SurfaceDeleted( Integration::RenderSurface* surface );
+
+ /**
* @copydoc Dali::Integration::Core::SetMinimumFrameTimeInterval(uint32_t)
*/
void SetMinimumFrameTimeInterval(uint32_t interval);
mRenderTaskList.Reset();
}
+ if ( mFrameBuffer )
+ {
+ mFrameBuffer.Reset();
+ }
+
// Discard this Scene from the Core
Discard();
}
}
}
+void Scene::SurfaceDeleted()
+{
+ if ( mFrameBuffer )
+ {
+ // The frame buffer doesn't have a valid render surface any more.
+ mFrameBuffer->MarkSurfaceAsInvalid();
+ }
+}
+
Integration::RenderSurface* Scene::GetSurface() const
{
return mSurface;
void Scene::EmitKeyEventSignal(const KeyEvent& event)
{
- mKeyEventSignal.Emit( event );
+ if ( !mKeyEventSignal.Empty() )
+ {
+ Dali::Integration::Scene handle( this );
+ mKeyEventSignal.Emit( event );
+ }
}
void Scene::EmitEventProcessingFinishedSignal()
{
- mEventProcessingFinishedSignal.Emit();
+ if ( !mEventProcessingFinishedSignal.Empty() )
+ {
+ Dali::Integration::Scene handle( this );
+ mEventProcessingFinishedSignal.Emit();
+ }
}
void Scene::EmitTouchedSignal( const TouchEvent& touchEvent, const Dali::TouchData& touch )
{
- mTouchedSignal.Emit( touchEvent );
- mTouchSignal.Emit( touch );
+ Dali::Integration::Scene handle( this );
+ if ( !mTouchedSignal.Empty() )
+ {
+ mTouchedSignal.Emit( touchEvent );
+ }
+ if ( !mTouchSignal.Empty() )
+ {
+ mTouchSignal.Emit( touch );
+ }
}
void Scene::EmitWheelEventSignal(const WheelEvent& event)
{
- mWheelEventSignal.Emit( event );
+ if ( !mWheelEventSignal.Empty() )
+ {
+ Dali::Integration::Scene handle( this );
+ mWheelEventSignal.Emit( event );
+ }
}
Integration::Scene::KeyEventSignalType& Scene::KeyEventSignal()
void SurfaceResized();
/**
+ * Notify the surface has been deleted.
+ */
+ void SurfaceDeleted();
+
+ /**
* @copydoc Dali::Integration::Scene::Discard
*/
void Discard();
}
}
+void FrameBuffer::MarkSurfaceAsInvalid()
+{
+ if ( mIsSurfaceBacked )
+ {
+ Render::SurfaceFrameBuffer* renderObject = static_cast<Render::SurfaceFrameBuffer*>( mRenderObject );
+ renderObject->MarkSurfaceAsInvalid();
+ }
+}
+
FrameBuffer::~FrameBuffer()
{
if( EventThreadServices::IsCoreRunning() && mRenderObject )
#define DALI_INTERNAL_FRAME_BUFFER_H
/*
- * Copyright (c) 2018 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2019 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.
*/
void SetBackgroundColor( const Vector4& color );
+ /**
+ * @brief Mark the render surface as invalid
+ *
+ * The render surface is maked as invalid when it is deleted.
+ *
+ * @note Only for FrameBuffer backed by a render surface.
+ * @return True if the FrameBuffer is backed by a render surface
+ */
+ void MarkSurfaceAsInvalid();
+
private: // implementation
/**
mWidth( mSurface->GetPositionSize().width ),
mHeight( mSurface->GetPositionSize().height ),
mBackgroundColor( 0.f, 0.f, 0.f, 1.f ),
- mSizeChanged( false )
+ mSizeChanged( false ),
+ mIsSurfaceInvalid( false )
{
}
void SurfaceFrameBuffer::Destroy( Context& context )
{
+ if ( mSurface && !mIsSurfaceInvalid )
+ {
+ mSurface->DestroySurface();
+ mSurface = nullptr;
+ }
}
void SurfaceFrameBuffer::GlContextDestroyed()
{
mContext->GlContextDestroyed();
}
+
+ if ( mSurface && !mIsSurfaceInvalid )
+ {
+ mSurface->DestroySurface();
+ mSurface = nullptr;
+ }
}
void SurfaceFrameBuffer::Initialize(Context& context)
{
mContext = &context;
mContext->GlContextCreated();
- mSurface->InitializeGraphics();
+
+ if ( mSurface && !mIsSurfaceInvalid )
+ {
+ mSurface->InitializeGraphics();
+ }
}
void SurfaceFrameBuffer::Bind( Context& context )
{
- mSurface->PreRender( mSizeChanged );
+ if ( mSurface && !mIsSurfaceInvalid )
+ {
+ mSurface->PreRender( mSizeChanged );
- context.BindFramebuffer( GL_FRAMEBUFFER, 0u );
+ context.BindFramebuffer( GL_FRAMEBUFFER, 0u );
+ }
}
uint32_t SurfaceFrameBuffer::GetWidth() const
void SurfaceFrameBuffer::PostRender()
{
- mSurface->PostRender( false, false, mSizeChanged );
+ if ( mSurface && !mIsSurfaceInvalid )
+ {
+ mSurface->PostRender( false, false, mSizeChanged );
+ }
mSizeChanged = false;
}
Integration::DepthBufferAvailable SurfaceFrameBuffer::GetDepthBufferRequired()
{
- return mSurface->GetDepthBufferRequired();
+ return mSurface && !mIsSurfaceInvalid ? Integration::DepthBufferAvailable::FALSE : mSurface->GetDepthBufferRequired();
}
Integration::StencilBufferAvailable SurfaceFrameBuffer::GetStencilBufferRequired()
{
- return mSurface->GetStencilBufferRequired();
+ return mSurface && !mIsSurfaceInvalid ? Integration::StencilBufferAvailable::TRUE : mSurface->GetStencilBufferRequired();
}
Vector4 SurfaceFrameBuffer::GetBackgroundColor()
* limitations under the License.
*/
+// EXTERNAL INCLUDES
+#include <atomic>
+
// INTERNAL INCLUDES
#include <dali/internal/update/manager/update-manager.h>
#include <dali/internal/render/renderers/render-frame-buffer.h>
*/
void SetBackgroundColor( const Vector4& color );
+ /**
+ * @copydoc Dali::Internal::FrameBuffer::MarkSurfaceAsInvalid()
+ */
+ void MarkSurfaceAsInvalid() { mIsSurfaceInvalid = true; };
+
public:
/**
uint32_t mHeight;
Vector4 mBackgroundColor;
bool mSizeChanged;
+ std::atomic<bool> mIsSurfaceInvalid; ///< This is set only from the event thread and read only from the render thread
};
// Messages for FrameBuffer