Add RenderTask::RenderUntil() 44/310044/10
authorjmm <j0064423.lee@samsung.com>
Fri, 19 Apr 2024 11:52:19 +0000 (20:52 +0900)
committerjmm <j0064423.lee@samsung.com>
Thu, 2 May 2024 05:54:21 +0000 (14:54 +0900)
Change-Id: I264e29303deedaf0f8539137b26e7d0c3e8454ce

automated-tests/src/dali/utc-Dali-RenderTask.cpp
dali/internal/event/render-tasks/render-task-impl.cpp
dali/internal/event/render-tasks/render-task-impl.h
dali/internal/update/manager/render-task-processor.cpp
dali/internal/update/render-tasks/scene-graph-render-task-messages.h
dali/internal/update/render-tasks/scene-graph-render-task.cpp
dali/internal/update/render-tasks/scene-graph-render-task.h
dali/public-api/render-tasks/render-task.cpp
dali/public-api/render-tasks/render-task.h

index cf7bd97..a2d870e 100644 (file)
@@ -692,6 +692,89 @@ int UtcDaliRenderTaskGetSourceActorN(void)
   END_TEST;
 }
 
+int UtcDaliRenderTaskGetStopperActorP(void)
+{
+  TestApplication application;
+
+  tet_infoline("Testing RenderTask::GetStopperActor() Create a new render task, Add a new actor to the stage and set RenderTask::RenderUntil(actor). Get its stopper actor and check it is equivalent to what was set.");
+
+  RenderTaskList taskList = application.GetScene().GetRenderTaskList();
+  RenderTask     task     = taskList.CreateTask();
+  Actor          actor    = Actor::New();
+  application.GetScene().Add(actor);
+  task.RenderUntil(actor);
+
+  DALI_TEST_EQUALS(actor, task.GetStopperActor(), TEST_LOCATION);
+
+  END_TEST;
+}
+
+int UtcDaliRenderTaskGetStopperActorN(void)
+{
+  TestApplication application;
+
+  tet_infoline("Testing RenderTask::GetStopperActor() Try with empty handle");
+
+  RenderTask task;
+
+  try
+  {
+    Actor actor = task.GetStopperActor();
+  }
+  catch(Dali::DaliException& e)
+  {
+    DALI_TEST_PRINT_ASSERT(e);
+    DALI_TEST_ASSERT(e, "RenderTask handle is empty", TEST_LOCATION);
+  }
+
+  END_TEST;
+}
+
+int UtcDaliRenderTaskRenderUntil(void)
+{
+  TestApplication application;
+  tet_infoline("Testing RenderTask::RenderUntil(actor) Check that rendering stops at the actor.");
+
+  // Make a new render task and compose a tree.
+  RenderTaskList taskList = application.GetScene().GetRenderTaskList();
+  RenderTask     task     = taskList.GetTask(0u);
+
+  Integration::Scene stage = application.GetScene();
+
+  Actor secondChild;
+  for(int i = 0; i < 5; i++)
+  {
+    Actor parent = CreateRenderableActor();
+    parent.SetProperty(Actor::Property::SIZE, Vector2(1.0f, 1.0f));
+    parent.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
+    Actor  child = CreateRenderableActor();
+    child.SetProperty(Actor::Property::SIZE, Vector2(1.0f, 1.0f));
+
+    stage.Add(parent);
+    parent.Add(child);
+
+    if (i == 1)
+    {
+      secondChild = child;
+    }
+  }
+  task.RenderUntil(secondChild);
+
+  // Update & Render with the actor on-stage
+  TestGlAbstraction& gl        = application.GetGlAbstraction();
+  TraceCallStack&    drawTrace = gl.GetDrawTrace();
+  drawTrace.Enable(true);
+
+  // Update & Render
+  application.SendNotification();
+  application.Render();
+
+  // Check that rendering was cut.
+  DALI_TEST_EQUALS(drawTrace.CountMethod("DrawElements"), 3, TEST_LOCATION);
+
+  END_TEST;
+}
+
 int UtcDaliRenderTaskSetExclusive(void)
 {
   TestApplication application;
index 25ca2dc..b28f64c 100644 (file)
@@ -117,6 +117,11 @@ Actor* RenderTask::GetSourceActor() const
   return mSourceActor.GetActor();
 }
 
+Actor* RenderTask::GetStopperActor() const
+{
+  return mStopperActor.GetActor();
+}
+
 void RenderTask::SetExclusive(bool exclusive)
 {
   if(mExclusive != exclusive)
@@ -640,6 +645,27 @@ uint32_t RenderTask::GetRenderTaskId() const
   return mRenderTaskId;
 }
 
+void RenderTask::RenderUntil(Actor* actor)
+{
+  Actor* target = mSourceActor.GetActor();
+  DALI_ASSERT_ALWAYS((target && actor)
+      && "RenderTask::RenderUntil() has empty actors.");
+  DALI_ASSERT_ALWAYS((target->GetHierarchyDepth() < actor->GetHierarchyDepth())
+      && "RenderTask::RenderUntil() has reversed hierarchy.");
+
+  Actor* parent = actor;
+  while(parent != target && !(parent->IsLayer()))
+  {
+    parent = parent->GetParent();
+  }
+
+  if(parent == target && GetRenderTaskSceneObject())
+  {
+    mStopperActor.SetActor(actor);
+    SetStopperNodeMessage(GetEventThreadServices(), *GetRenderTaskSceneObject(), &actor->GetNode());
+  }
+}
+
 const SceneGraph::RenderTask* RenderTask::GetRenderTaskSceneObject() const
 {
   return static_cast<const SceneGraph::RenderTask*>(mUpdateObject);
index f8897b0..7c57c3e 100644 (file)
@@ -71,6 +71,8 @@ public:
    */
   Actor* GetSourceActor() const;
 
+  Actor* GetStopperActor() const;
+
   /**
    * @copydoc Dali::RenderTask::SetExclusive()
    */
@@ -284,6 +286,8 @@ public:
    */
   uint32_t GetRenderTaskId() const;
 
+  void RenderUntil(Actor* actor);
+
 public: // Used by RenderTaskList, which owns the SceneGraph::RenderTasks
   /**
    * Retrieve the scene-graph RenderTask object.
@@ -388,6 +392,7 @@ private:
   ActorObserver           mSourceActor;        ///< Source actor
   ActorObserver           mCameraActor;        ///< Camera actor
   ActorObserver           mViewportGuideActor; ///< Actor to matching viewport of this render task to this Actor.
+  ActorObserver           mStopperActor;       ///< A child of mSourceActor. Actor to stop rendering.
   WeakHandle<Dali::Actor> mInputMappingActor;  /// used to mapping screen to frame buffer coordinate, not kept alive by rendertask
   RenderTaskList&         mRenderTaskList;     ///< The render task list
 
index b3c3d20..6059a12 100644 (file)
@@ -94,6 +94,7 @@ Layer* FindLayer(Node& node)
  * @param[in]  clippingDepth The current scissor clipping depth
  * @param[out] clippingUsed  Gets set to true if any clipping nodes have been found
  * @param[out] keepRendering Gets set to true if rendering should be kept.
+ * @param[out] renderStopped Gets set to true if rendering should be stopped.
  */
 void AddRenderablesForTask(BufferIndex updateBufferIndex,
                            Node&       node,
@@ -105,8 +106,14 @@ void AddRenderablesForTask(BufferIndex updateBufferIndex,
                            uint32_t    clippingDepth,
                            uint32_t    scissorDepth,
                            bool&       clippingUsed,
-                           bool&       keepRendering)
+                           bool&       keepRendering,
+                           bool&       renderStopped)
 {
+  if(renderStopped)
+  {
+    return;
+  }
+
   // Short-circuit for invisible nodes
   if(!node.IsVisible(updateBufferIndex))
   {
@@ -188,10 +195,15 @@ void AddRenderablesForTask(BufferIndex updateBufferIndex,
   // Recurse children.
   NodeContainer& children = node.GetChildren();
   const NodeIter endIter  = children.End();
-  for(NodeIter iter = children.Begin(); iter != endIter; ++iter)
+  for(NodeIter iter = children.Begin(); !renderStopped && iter != endIter; ++iter)
   {
     Node& child = **iter;
-    AddRenderablesForTask(updateBufferIndex, child, parentVisibilityChanged, *layer, renderTask, inheritedDrawMode, currentClippingId, clippingDepth, scissorDepth, clippingUsed, keepRendering);
+    if(child == renderTask.GetStopperNode())
+    {
+      renderStopped = true;
+      break;
+    }
+    AddRenderablesForTask(updateBufferIndex, child, parentVisibilityChanged, *layer, renderTask, inheritedDrawMode, currentClippingId, clippingDepth, scissorDepth, clippingUsed, keepRendering, renderStopped);
   }
 }
 
@@ -285,6 +297,8 @@ void ProcessTasks(BufferIndex                          updateBufferIndex,
         sortedLayer->ClearRenderables();
       }
 
+      bool stopRendering = false;
+
       AddRenderablesForTask(updateBufferIndex,
                             *sourceNode,
                             false,
@@ -295,7 +309,8 @@ void ProcessTasks(BufferIndex                          updateBufferIndex,
                             0u,
                             0u,
                             hasClippingNodes,
-                            keepRendering);
+                            keepRendering,
+                            stopRendering);
 
       renderInstructionProcessor.Prepare(updateBufferIndex,
                                          sortedLayers,
index b2de30a..f58a30c 100644 (file)
@@ -91,6 +91,20 @@ inline void SetSourceNodeMessage(EventThreadServices& eventThreadServices, const
   new(slot) LocalType(&task, &RenderTask::SetSourceNode, node);
 }
 
+inline void SetStopperNodeMessage(EventThreadServices& eventThreadServices, const RenderTask& task, const Node* constNode)
+{
+  // Scene graph thread can destroy this object.
+  Node* node = const_cast<Node*>(constNode);
+
+  using LocalType = MessageValue1<RenderTask, Node*>;
+
+  // Reserve some memory inside the message queue
+  uint32_t* slot = eventThreadServices.ReserveMessageSlot(sizeof(LocalType));
+
+  // Construct message in the message queue memory; note that delete should not be called on the return value
+  new(slot) LocalType(&task, &RenderTask::SetStopperNode, node);
+}
+
 inline void SetCameraMessage(EventThreadServices& eventThreadServices, const RenderTask& task, const Camera* constCamera)
 {
   using LocalType = MessageValue1<RenderTask, Camera*>;
index bfe2f5e..dd58a5f 100644 (file)
@@ -94,6 +94,16 @@ Node* RenderTask::GetSourceNode() const
   return mSourceNode;
 }
 
+void RenderTask::SetStopperNode(Node* node)
+{
+  mStopperNode = node;
+}
+
+Node* RenderTask::GetStopperNode() const
+{
+  return mStopperNode;
+}
+
 void RenderTask::SetViewportGuideNode(Node* node)
 {
   mViewportGuideNode = node;
index 3ff90fc..7e07b08 100644 (file)
@@ -87,6 +87,9 @@ public:
    */
   Node* GetSourceNode() const;
 
+  void SetStopperNode(Node* node);
+  Node* GetStopperNode() const;
+
   /**
    * Set the ViewportGuideNode.
    * @param[in] node This node is used to compute viewport of the render task.
@@ -406,6 +409,7 @@ private:
   RenderMessageDispatcher* mRenderMessageDispatcher;
   Render::RenderTracker*   mRenderSyncTracker;
   Node*                    mSourceNode;
+  Node*                    mStopperNode;
   SceneGraph::Camera*      mCameraNode;
   Node*                    mViewportGuideNode;
   Render::FrameBuffer*     mFrameBuffer;
index 4521f44..7b26b56 100644 (file)
@@ -85,6 +85,11 @@ Actor RenderTask::GetSourceActor() const
   return Dali::Actor(GetImplementation(*this).GetSourceActor());
 }
 
+Actor RenderTask::GetStopperActor() const
+{
+  return Dali::Actor(GetImplementation(*this).GetStopperActor());
+}
+
 void RenderTask::SetExclusive(bool exclusive)
 {
   GetImplementation(*this).SetExclusive(exclusive);
@@ -307,6 +312,13 @@ uint32_t RenderTask::GetRenderTaskId() const
   return GetImplementation(*this).GetRenderTaskId();
 }
 
+void RenderTask::RenderUntil(Actor actor)
+{
+  DALI_ASSERT_ALWAYS(actor && "RenderUntil() actor does not exist.");
+  Internal::Actor* actorImpl(&GetImplementation(actor));
+  return GetImplementation(*this).RenderUntil(actorImpl);
+}
+
 RenderTask::RenderTask(Internal::RenderTask* internal)
 : Handle(internal)
 {
index 6eab3d4..5d6be1a 100644 (file)
@@ -256,6 +256,8 @@ public:
    */
   Actor GetSourceActor() const;
 
+  Actor GetStopperActor() const;
+
   /**
    * @brief Sets whether the RenderTask has exclusive access to the source actors; the default is false.
    * @SINCE_1_0.0
@@ -579,6 +581,8 @@ public:
    */
   uint32_t GetRenderTaskId() const;
 
+  void RenderUntil(Actor actor);
+
 public: // Signals
   /**
    * @brief If the refresh rate is REFRESH_ONCE, connect to this signal to be notified when a RenderTask has finished.