Ensure we render once more when we remove all renderers from the scene 02/208202/7
authorAdeel Kazmi <adeel.kazmi@samsung.com>
Wed, 19 Jun 2019 16:06:43 +0000 (17:06 +0100)
committerAdeel Kazmi <adeel.kazmi@samsung.com>
Thu, 20 Jun 2019 15:00:10 +0000 (16:00 +0100)
Change-Id: I3d67c6ceee6bcf4424c8cb3c2fcf3452f82f07e0

automated-tests/src/dali/utc-Dali-Actor.cpp
dali/internal/render/common/render-manager.cpp
dali/internal/update/manager/update-manager.cpp

index fad466a..b8c7e95 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * 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.
@@ -7172,3 +7172,30 @@ int utcDaliActorCulled(void)
 
   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;
+}
index ee70d89..2d550b5 100644 (file)
@@ -50,6 +50,13 @@ namespace Internal
 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
  */
@@ -451,9 +458,17 @@ void RenderManager::Render( Integration::RenderStatus& status, bool forceClear )
   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 );
 
index 9fd71a1..e98f8b7 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * 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.
@@ -87,6 +87,10 @@ mImpl->frameCounter++;
 
 #if defined(DEBUG_ENABLED)
 extern Debug::Filter* gRenderTaskLogFilter;
+namespace
+{
+Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_UPDATE_MANAGER" );
+} // unnamed namespace
 #endif
 
 
@@ -189,7 +193,8 @@ struct UpdateManager::Impl
     previousUpdateScene( false ),
     renderTaskWaiting( false ),
     renderersAdded( false ),
-    surfaceRectChanged( false )
+    surfaceRectChanged( false ),
+    nodeDisconnected( false )
   {
     sceneController = new SceneControllerImpl( renderMessageDispatcher, renderQueue, discardQueue );
 
@@ -295,6 +300,7 @@ struct UpdateManager::Impl
   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:
 
@@ -369,6 +375,8 @@ void UpdateManager::AddNode( OwnerPointer<Node>& node )
 
   // 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 )
   {
@@ -387,6 +395,8 @@ void UpdateManager::ConnectNode( Node* parent, Node* node )
   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
@@ -398,6 +408,10 @@ void UpdateManager::ConnectNode( Node* parent, Node* node )
 
 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
@@ -416,6 +430,8 @@ void UpdateManager::DestroyNode( Node* node )
   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)
@@ -573,6 +589,8 @@ void UpdateManager::SetShaderSaver( ShaderSaver& upstream )
 
 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;
@@ -580,6 +598,8 @@ void UpdateManager::AddRenderer( OwnerPointer< Renderer >& renderer )
 
 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
@@ -913,6 +933,19 @@ uint32_t UpdateManager::Update( float elapsedSeconds,
                                               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;
     }
   }