/*
- * 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.
END_TEST;
}
+
+int utcDaliEnsureRenderWhenRemovingLastRenderableActor(void)
+{
+ TestApplication application;
+ auto stage = Stage::GetCurrent();
+
+ tet_infoline( "Ensure we clear the screen when the last actor is removed" );
+
+ Actor actor = CreateRenderableActor();
+ actor.SetSize( 100.0f, 100.0f );
+ stage.Add( actor );
+
+ application.SendNotification();
+ application.Render();
+
+ auto& glAbstraction = application.GetGlAbstraction();
+ const auto clearCountBefore = glAbstraction.GetClearCountCalled();
+
+ actor.Unparent();
+
+ application.SendNotification();
+ application.Render();
+
+ DALI_TEST_EQUALS( glAbstraction.GetClearCountCalled(), clearCountBefore + 1, TEST_LOCATION );
+
+ END_TEST;
+}
END_TEST;
}
+int UtcDaliSceneDiscard(void)
+{
+ TestApplication application;
+ tet_infoline("Testing Dali::Scene::Discard");
+
+ // Create a new Scene
+ Dali::Integration::Scene scene = Dali::Integration::Scene::New( Vector2( 480.0f, 800.0f ) );
+ DALI_TEST_CHECK( scene );
+
+ // One reference of scene kept here and the other one kept in the Core
+ DALI_TEST_CHECK( scene.GetBaseObject().ReferenceCount() == 2 );
+
+ // Render and notify.
+ application.SendNotification();
+ application.Render(0);
+
+ // Keep the reference of the root layer handle so it will still be alive after the scene is deleted
+ Layer rootLayer = scene.GetRootLayer();
+ DALI_TEST_CHECK( rootLayer );
+ DALI_TEST_CHECK( rootLayer.GetBaseObject().ReferenceCount() == 2 );
+
+ // Request to discard the scene from the Core
+ scene.Discard();
+ DALI_TEST_CHECK( scene.GetBaseObject().ReferenceCount() == 1 );
+
+ // Reset the scene handle
+ scene.Reset();
+
+ // Render and notify.
+ application.SendNotification();
+ application.Render(0);
+
+ // At this point, the scene should have been automatically deleted
+ // To prove this, the ref count of the root layer handle should be decremented to 1
+ DALI_TEST_CHECK( rootLayer.GetBaseObject().ReferenceCount() == 1 );
+
+ // Delete the root layer handle
+ rootLayer.Reset();
+
+ // Render and notify.
+ application.SendNotification();
+ application.Render(0);
+
+ END_TEST;
+}
+
int UtcDaliSceneEventProcessingFinishedP(void)
{
TestApplication application;
return GetImplementation(*this).GetSurface();
}
+void Scene::Discard()
+{
+ GetImplementation(*this).Discard();
+}
+
Integration::Scene Scene::Get( Actor actor )
{
return Dali::Integration::Scene( &GetImplementation( actor ).GetScene() );
Integration::RenderSurface* GetSurface() const;
/**
+ * @brief Discards this Scene from the Core.
+ */
+ void Discard();
+
+ /**
* @brief Retrieve the Scene that the given actor belongs to.
* @return The Scene.
*/
// Guard to allow handle destruction after Core has been destroyed
if( EventThreadServices::IsCoreRunning() )
{
- DestroyNodeMessage( GetEventThreadServices().GetUpdateManager(), GetNode() );
+ // Root layer will destroy its node in its own destructor
+ if ( !mIsRoot )
+ {
+ DestroyNodeMessage( GetEventThreadServices().GetUpdateManager(), GetNode() );
- GetEventThreadServices().UnregisterObject( this );
+ GetEventThreadServices().UnregisterObject( this );
+ }
}
// Cleanup optional gesture data
return layer;
}
-LayerPtr Layer::NewRoot( LayerList& layerList, UpdateManager& manager )
+LayerPtr Layer::NewRoot( LayerList& layerList )
{
// create node, nodes are owned by UpdateManager
SceneGraph::Layer* rootLayer = SceneGraph::Layer::New();
OwnerPointer< SceneGraph::Layer > transferOwnership( rootLayer );
- InstallRootMessage( manager, transferOwnership );
+ InstallRootMessage( EventThreadServices::Get().GetUpdateManager(), transferOwnership );
LayerPtr root( new Layer( Actor::ROOT_LAYER, *rootLayer ) );
Layer::~Layer()
{
+ if ( mIsRoot )
+ {
+ // Guard to allow handle destruction after Core has been destroyed
+ if( EventThreadServices::IsCoreRunning() )
+ {
+ UninstallRootMessage( GetEventThreadServices().GetUpdateManager(), &GetSceneLayerOnStage() );
+
+ GetEventThreadServices().UnregisterObject( this );
+ }
+ }
}
unsigned int Layer::GetDepth() const
/**
* Create a new root layer; this is typically owned by the stage.
* @param[in] layerList The layer will be added to this ordered list.
- * @param[in] manager The update manager to install a root node with.
* @return A smart-pointer to the newly allocated Actor.
*/
- static LayerPtr NewRoot( LayerList& layerList, SceneGraph::UpdateManager& manager );
+ static LayerPtr NewRoot( LayerList& layerList );
/**
* @copydoc Dali::Internal::Actor::OnInitialize
mRenderTaskList.Reset();
}
- if( ThreadLocalStorage::Created() )
- {
- ThreadLocalStorage* tls = ThreadLocalStorage::GetInternal();
- tls->RemoveScene( this );
- }
+ // Discard this Scene from the Core
+ Discard();
}
void Scene::Initialize()
mLayerList = LayerList::New( updateManager );
// The scene owns the default layer
- mRootLayer = Layer::NewRoot( *mLayerList, updateManager );
+ mRootLayer = Layer::NewRoot( *mLayerList );
mRootLayer->SetName("RootLayer");
mRootLayer->SetScene( *this );
return mSurface;
}
+void Scene::Discard()
+{
+ if( ThreadLocalStorage::Created() )
+ {
+ ThreadLocalStorage* tls = ThreadLocalStorage::GetInternal();
+ tls->RemoveScene( this );
+ }
+}
+
void Scene::RequestRebuildDepthTree()
{
mDepthTreeDirty = true;
void SetSurface( Integration::RenderSurface& surface );
/**
+ * @copydoc Dali::Integration::Scene::Discard
+ */
+ void Discard();
+
+ /**
* Retrieve the render surface the scene is binded to.
* @return The render surface.
*/
mRenderObject = new Render::TextureFrameBuffer( mWidth, mHeight, mAttachments );
}
- AddFrameBuffer( mEventThreadServices.GetUpdateManager(), *mRenderObject );
+ OwnerPointer< Render::FrameBuffer > transferOwnership( mRenderObject );
+ AddFrameBuffer( mEventThreadServices.GetUpdateManager(), transferOwnership );
}
void FrameBuffer::AttachColorTexture( TexturePtr texture, uint32_t mipmapLevel, uint32_t layer )
namespace SceneGraph
{
+#if defined(DEBUG_ENABLED)
+namespace
+{
+Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_RENDER_MANAGER" );
+} // unnamed namespace
+#endif
+
/**
* Structure to contain internal data
*/
sampler->mTWrapMode = static_cast<Dali::WrapMode::Type>(tWrapMode);
}
-void RenderManager::AddFrameBuffer( Render::FrameBuffer* frameBuffer )
+void RenderManager::AddFrameBuffer( OwnerPointer< Render::FrameBuffer >& frameBuffer )
{
- mImpl->frameBufferContainer.PushBack( frameBuffer );
- if ( frameBuffer->IsSurfaceBacked() )
+ Render::FrameBuffer* frameBufferPtr = frameBuffer.Release();
+ mImpl->frameBufferContainer.PushBack( frameBufferPtr );
+ if ( frameBufferPtr->IsSurfaceBacked() )
{
- frameBuffer->Initialize( *mImpl->CreateSurfaceContext() );
+ frameBufferPtr->Initialize( *mImpl->CreateSurfaceContext() );
}
else
{
- frameBuffer->Initialize( mImpl->context );
+ frameBufferPtr->Initialize( mImpl->context );
}
}
const uint32_t count = mImpl->instructions.Count( mImpl->renderBufferIndex );
const bool haveInstructions = count > 0u;
+ DALI_LOG_INFO( gLogFilter, Debug::General,
+ "Render: haveInstructions(%s) || mImpl->lastFrameWasRendered(%s) || forceClear(%s)\n",
+ haveInstructions ? "true" : "false",
+ mImpl->lastFrameWasRendered ? "true" : "false",
+ forceClear ? "true" : "false" );
+
// Only render if we have instructions to render, or the last frame was rendered (and therefore a clear is required).
if( haveInstructions || mImpl->lastFrameWasRendered || forceClear )
{
+ DALI_LOG_INFO( gLogFilter, Debug::General, "Render: Processing\n" );
+
// Mark that we will require a post-render step to be performed (includes swap-buffers).
status.SetNeedsPostRender( true );
* Adds a framebuffer to the render manager
* @param[in] frameBuffer The framebuffer to add
*/
- void AddFrameBuffer( Render::FrameBuffer* frameBuffer );
+ void AddFrameBuffer( OwnerPointer< Render::FrameBuffer >& frameBuffer );
/**
* Removes a framebuffer from the render manager
/*
- * 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.
#if defined(DEBUG_ENABLED)
extern Debug::Filter* gRenderTaskLogFilter;
+namespace
+{
+Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_UPDATE_MANAGER" );
+} // unnamed namespace
#endif
previousUpdateScene( false ),
renderTaskWaiting( false ),
renderersAdded( false ),
- surfaceRectChanged( false )
+ surfaceRectChanged( false ),
+ nodeDisconnected( false )
{
sceneController = new SceneControllerImpl( renderMessageDispatcher, renderQueue, discardQueue );
for( auto root : roots )
{
root->OnDestroy();
+ Node::Delete(root);
}
delete sceneController;
OwnerContainer<RenderTaskList*> taskLists; ///< A container of scene graph render task lists
- OwnerContainer<Layer*> roots; ///< A container of root nodes (root is a layer). The layers are not stored in the node memory pool.
+ Vector<Layer*> roots; ///< A container of root nodes (root is a layer). The layers are not stored in the node memory pool.
Vector<Node*> nodes; ///< A container of all instantiated nodes
bool renderTaskWaiting; ///< A REFRESH_ONCE render task is waiting to be rendered
bool renderersAdded; ///< Flag to keep track when renderers have been added to avoid unnecessary processing
bool surfaceRectChanged; ///< True if the default surface rect is changed
+ bool nodeDisconnected; ///< True if a node is disconnected in the current update
private:
mImpl->roots.PushBack( rootLayer );
}
+void UpdateManager::UninstallRoot( Layer* layer )
+{
+ DALI_ASSERT_DEBUG( layer->IsLayer() );
+ DALI_ASSERT_DEBUG( layer->GetParent() == NULL );
+
+ for ( auto&& iter : mImpl->roots )
+ {
+ if( ( *iter ) == layer )
+ {
+ mImpl->roots.Erase( &iter );
+ break;
+ }
+ }
+
+ mImpl->discardQueue.Add( mSceneGraphBuffers.GetUpdateBufferIndex(), layer );
+
+ // Notify the layer about impending destruction
+ layer->OnDestroy();
+}
+
void UpdateManager::AddNode( OwnerPointer<Node>& node )
{
DALI_ASSERT_ALWAYS( NULL == node->GetParent() ); // Should not have a parent yet
// Nodes must be sorted by pointer
Node* rawNode = node.Release();
+ DALI_LOG_INFO( gLogFilter, Debug::General, "[%x] AddNode\n", rawNode );
+
Vector<Node*>::Iterator begin = mImpl->nodes.Begin();
for( Vector<Node*>::Iterator iter = mImpl->nodes.End()-1; iter >= begin; --iter )
{
DALI_ASSERT_ALWAYS( NULL != node );
DALI_ASSERT_ALWAYS( NULL == node->GetParent() ); // Should not have a parent yet
+ DALI_LOG_INFO( gLogFilter, Debug::General, "[%x] ConnectNode\n", node );
+
parent->ConnectChild( node );
// Inform the frame-callback-processor, if set, about the node-hierarchy changing
void UpdateManager::DisconnectNode( Node* node )
{
+ DALI_LOG_INFO( gLogFilter, Debug::General, "[%x] DisconnectNode\n", node );
+
+ mImpl->nodeDisconnected = true;
+
Node* parent = node->GetParent();
DALI_ASSERT_ALWAYS( NULL != parent );
parent->SetDirtyFlag( NodePropertyFlags::CHILD_DELETED ); // make parent dirty so that render items dont get reused
DALI_ASSERT_ALWAYS( NULL != node );
DALI_ASSERT_ALWAYS( NULL == node->GetParent() ); // Should have been disconnected
+ DALI_LOG_INFO( gLogFilter, Debug::General, "[%x] DestroyNode\n", node );
+
Vector<Node*>::Iterator iter = mImpl->nodes.Begin()+1;
Vector<Node*>::Iterator endIter = mImpl->nodes.End();
for(;iter!=endIter;++iter)
void UpdateManager::AddRenderer( OwnerPointer< Renderer >& renderer )
{
+ DALI_LOG_INFO( gLogFilter, Debug::General, "[%x] AddRenderer\n", renderer.Get() );
+
renderer->ConnectToSceneGraph( *mImpl->sceneController, mSceneGraphBuffers.GetUpdateBufferIndex() );
mImpl->renderers.PushBack( renderer.Release() );
mImpl->renderersAdded = true;
void UpdateManager::RemoveRenderer( Renderer* renderer )
{
+ DALI_LOG_INFO( gLogFilter, Debug::General, "[%x] RemoveRenderer\n", renderer );
+
// Find the renderer and destroy it
EraseUsingDiscardQueue( mImpl->renderers, renderer, mImpl->discardQueue, mSceneGraphBuffers.GetUpdateBufferIndex() );
// Need to remove the render object as well
isRenderingToFbo );
}
}
+
+ DALI_LOG_INFO( gLogFilter, Debug::General,
+ "Update: numberOfRenderTasks(%d), taskListCount(%d), Render Instructions(%d)\n",
+ numberOfRenderTasks, taskListCount, mImpl->renderInstructions.Count( bufferIndex ) );
+
+ // If a node has been disconnected in this update and we do not have any instructions to send, then generate a dummy instruction to force another render
+ if( mImpl->nodeDisconnected && ( mImpl->renderInstructions.Count( bufferIndex ) == 0 ) )
+ {
+ DALI_LOG_INFO( gLogFilter, Debug::General, "Node disconnected, creating dummy instruction\n" );
+ mImpl->renderInstructions.GetNextInstruction( bufferIndex ); // This creates and adds an empty instruction. We do not need to modify it.
+ }
+
+ mImpl->nodeDisconnected = false;
}
}
new (slot) DerivedType( &mImpl->renderManager, &RenderManager::GenerateMipmaps, texture );
}
-void UpdateManager::AddFrameBuffer( Render::FrameBuffer* frameBuffer )
+void UpdateManager::AddFrameBuffer( OwnerPointer< Render::FrameBuffer >& frameBuffer )
{
- typedef MessageValue1< RenderManager, Render::FrameBuffer* > DerivedType;
+ typedef MessageValue1< RenderManager, OwnerPointer< Render::FrameBuffer > > DerivedType;
// Reserve some memory inside the render queue
uint32_t* slot = mImpl->renderQueue.ReserveMessageSlot( mSceneGraphBuffers.GetUpdateBufferIndex(), sizeof( DerivedType ) );
/**
* Installs a new layer as the root node.
- * @pre The UpdateManager does not already have an installed root node.
* @pre The layer is of derived Node type Layer.
* @pre The layer does not have a parent.
* @param[in] layer The new root node.
void InstallRoot( OwnerPointer<Layer>& layer );
/**
+ * Uninstalls the root node.
+ * @pre The layer is of derived Node type Layer.
+ * @pre The layer does not have a parent.
+ * @param[in] layer The root node.
+ * @post The node is owned by UpdateManager.
+ */
+ void UninstallRoot( Layer* layer );
+
+ /**
* Add a Node; UpdateManager takes ownership.
* @pre The node does not have a parent.
* @note even though nodes are pool allocated, they also contain other heap allocated data, thus using OwnerPointer when transferring the data
* @param[in] frameBuffer The framebuffer to add
* The framebuffer will be owned by RenderManager
*/
- void AddFrameBuffer( Render::FrameBuffer* frameBuffer );
+ void AddFrameBuffer( OwnerPointer< Render::FrameBuffer >& frameBuffer );
/**
* Removes a FrameBuffer from the render manager
new (slot) LocalType( &manager, &UpdateManager::InstallRoot, root );
}
+inline void UninstallRootMessage( UpdateManager& manager, const Layer* constRoot )
+{
+ // Scene graph thread can destroy this object.
+ Layer* root = const_cast< Layer* >( constRoot );
+
+ typedef MessageValue1< UpdateManager, Layer* > LocalType;
+
+ // Reserve some memory inside the message queue
+ uint32_t* slot = manager.ReserveMessageSlot( sizeof( LocalType ) );
+
+ // Construct message in the message queue memory; note that delete should not be called on the return value
+ new (slot) LocalType( &manager, &UpdateManager::UninstallRoot, root );
+}
+
inline void AddNodeMessage( UpdateManager& manager, OwnerPointer<Node>& node )
{
// Message has ownership of Node while in transit from event -> update
}
-inline void AddFrameBuffer( UpdateManager& manager, Render::FrameBuffer& frameBuffer )
+inline void AddFrameBuffer( UpdateManager& manager, OwnerPointer< Render::FrameBuffer >& frameBuffer )
{
- typedef MessageValue1< UpdateManager, Render::FrameBuffer* > LocalType;
+ typedef MessageValue1< UpdateManager, OwnerPointer< Render::FrameBuffer > > LocalType;
// Reserve some memory inside the message queue
uint32_t* slot = manager.ReserveMessageSlot( sizeof( LocalType ) );
// Construct message in the message queue memory; note that delete should not be called on the return value
- new (slot) LocalType( &manager, &UpdateManager::AddFrameBuffer, &frameBuffer );
+ new (slot) LocalType( &manager, &UpdateManager::AddFrameBuffer, frameBuffer );
}
inline void RemoveFrameBuffer( UpdateManager& manager, Render::FrameBuffer& frameBuffer )
const uint32_t CORE_MAJOR_VERSION = 1;
const uint32_t CORE_MINOR_VERSION = 4;
-const uint32_t CORE_MICRO_VERSION = 24;
+const uint32_t CORE_MICRO_VERSION = 25;
const char * const CORE_BUILD_DATE = __DATE__ " " __TIME__;
#ifdef DEBUG_ENABLED
Name: dali
Summary: DALi 3D Engine
-Version: 1.4.24
+Version: 1.4.25
Release: 1
Group: System/Libraries
License: Apache-2.0 and BSD-3-Clause and MIT