Add OrderIndex to RenderTask to control rendering order between RenderTask 49/305249/8
authorseungho baek <sbsh.baek@samsung.com>
Tue, 30 Jan 2024 09:14:19 +0000 (18:14 +0900)
committerseungho baek <sbsh.baek@samsung.com>
Mon, 5 Feb 2024 05:28:22 +0000 (14:28 +0900)
Change-Id: I7aa9bec7a27c04878d1842751ea64813068d582f
Signed-off-by: seungho baek <sbsh.baek@samsung.com>
automated-tests/src/dali/utc-Dali-RenderTask.cpp
automated-tests/src/dali/utc-Dali-Scene.cpp
dali/internal/event/common/scene-impl.cpp
dali/internal/event/render-tasks/render-task-impl.cpp
dali/internal/event/render-tasks/render-task-impl.h
dali/internal/event/render-tasks/render-task-list-impl.cpp
dali/internal/event/render-tasks/render-task-list-impl.h
dali/internal/update/render-tasks/scene-graph-render-task-list.cpp
dali/internal/update/render-tasks/scene-graph-render-task-list.h
dali/public-api/render-tasks/render-task.cpp
dali/public-api/render-tasks/render-task.h

index b92b19c..1d08d66 100644 (file)
@@ -4261,3 +4261,126 @@ int UtcDaliRenderTaskWithWrongShaderData(void)
 
   END_TEST;
 }
+
+int UtcDaliRenderTaskOrderIndex01(void)
+{
+  TestApplication application;
+  tet_infoline("Testing RenderTask with OrderIndex");
+
+  Stage   stage = Stage::GetCurrent();
+  Vector2 stageSize(stage.GetSize());
+
+  RenderTaskList renderTaskList = stage.GetRenderTaskList();
+  RenderTask     renderTask1    = renderTaskList.CreateTask();
+
+  application.SendNotification();
+  uint32_t       answer1[2]     = {0u, 0u};
+  DALI_TEST_EQUALS(2, renderTaskList.GetTaskCount(), TEST_LOCATION);
+  for(uint32_t i = 0; i < 2; ++i)
+  {
+    DALI_TEST_EQUALS(answer1[i], renderTaskList.GetTask(i).GetOrderIndex(), TEST_LOCATION);
+  }
+
+  RenderTask renderTask2 = renderTaskList.CreateTask();
+  application.SendNotification();
+  int32_t answer2[3] = {0u, 0u, 0u};
+  DALI_TEST_EQUALS(3, renderTaskList.GetTaskCount(), TEST_LOCATION);
+  for(uint32_t i = 0; i < 3; ++i)
+  {
+    DALI_TEST_EQUALS(answer2[i], renderTaskList.GetTask(i).GetOrderIndex(), TEST_LOCATION);
+  }
+
+  RenderTask renderTask3 = renderTaskList.CreateTask();
+  application.SendNotification();
+  int32_t answer3[4] = {0u, 0u, 0u, 0u};
+  DALI_TEST_EQUALS(4, renderTaskList.GetTaskCount(), TEST_LOCATION);
+  for(uint32_t i = 0; i < 4; ++i)
+  {
+    DALI_TEST_EQUALS(answer3[i], renderTaskList.GetTask(i).GetOrderIndex(), TEST_LOCATION);
+  }
+
+  renderTask1.SetOrderIndex(3);
+  application.SendNotification();
+  int32_t answer4[4] = {0u, 0u, 0u, 3u};
+  for(uint32_t i = 0; i < 4; ++i)
+  {
+    DALI_TEST_EQUALS(answer4[i], renderTaskList.GetTask(i).GetOrderIndex(), TEST_LOCATION);
+  }
+
+  renderTask2.SetOrderIndex(7);
+  application.SendNotification();
+  int32_t answer5[4] = {0u, 0u, 3u, 7u};
+  for(uint32_t i = 0; i < 4; ++i)
+  {
+    DALI_TEST_EQUALS(answer5[i], renderTaskList.GetTask(i).GetOrderIndex(), TEST_LOCATION);
+  }
+
+  Dali::Integration::Scene scene = application.GetScene();
+  scene.GetOverlayLayer();
+  application.SendNotification();
+  DALI_TEST_EQUALS(5, renderTaskList.GetTaskCount(), TEST_LOCATION);
+  int32_t answer6[5] = {0u, 0u, 3u, 7u, INT32_MAX};
+  for(uint32_t i = 0; i < 5; ++i)
+  {
+    DALI_TEST_EQUALS(answer6[i], renderTaskList.GetTask(i).GetOrderIndex(), TEST_LOCATION);
+  }
+
+  renderTask3.SetOrderIndex(4);
+  application.SendNotification();
+  int32_t answer7[5] = {0u, 3u, 4u, 7u, INT32_MAX};
+  for(uint32_t i = 0; i < 5; ++i)
+  {
+    DALI_TEST_EQUALS(answer7[i], renderTaskList.GetTask(i).GetOrderIndex(), TEST_LOCATION);
+  }
+
+  renderTask2.SetOrderIndex(2);
+  application.SendNotification();
+  int32_t answer8[5] = {0u, 2u, 3u, 4u, INT32_MAX};
+  for(uint32_t i = 0; i < 5; ++i)
+  {
+    DALI_TEST_EQUALS(answer8[i], renderTaskList.GetTask(i).GetOrderIndex(), TEST_LOCATION);
+  }
+
+  END_TEST;
+}
+
+int UtcDaliRenderTaskOrderIndex02(void)
+{
+  TestApplication application;
+  tet_infoline("Testing RenderTask with OrderIndex");
+
+  Stage   stage = Stage::GetCurrent();
+  Vector2 stageSize(stage.GetSize());
+
+  RenderTaskList renderTaskList = stage.GetRenderTaskList();
+  RenderTask     renderTask1    = renderTaskList.CreateTask();
+  application.SendNotification();
+  DALI_TEST_EQUALS(renderTask1, renderTaskList.GetTask(1u), TEST_LOCATION);
+  
+  RenderTask     renderTask2    = renderTaskList.CreateTask();
+  application.SendNotification();
+  DALI_TEST_EQUALS(renderTask1, renderTaskList.GetTask(1u), TEST_LOCATION);
+  DALI_TEST_EQUALS(renderTask2, renderTaskList.GetTask(2u), TEST_LOCATION);
+
+  RenderTask     renderTask3    = renderTaskList.CreateTask();
+  application.SendNotification();
+  DALI_TEST_EQUALS(renderTask1, renderTaskList.GetTask(1u), TEST_LOCATION);
+  DALI_TEST_EQUALS(renderTask2, renderTaskList.GetTask(2u), TEST_LOCATION);
+  DALI_TEST_EQUALS(renderTask3, renderTaskList.GetTask(3u), TEST_LOCATION);
+
+  RenderTask     renderTask4    = renderTaskList.CreateTask();
+  application.SendNotification();
+  DALI_TEST_EQUALS(renderTask1, renderTaskList.GetTask(1u), TEST_LOCATION);
+  DALI_TEST_EQUALS(renderTask2, renderTaskList.GetTask(2u), TEST_LOCATION);
+  DALI_TEST_EQUALS(renderTask3, renderTaskList.GetTask(3u), TEST_LOCATION);
+  DALI_TEST_EQUALS(renderTask4, renderTaskList.GetTask(4u), TEST_LOCATION);
+
+  renderTask2.SetOrderIndex(2);
+  application.SendNotification();
+  DALI_TEST_EQUALS(renderTask1, renderTaskList.GetTask(1u), TEST_LOCATION);
+  DALI_TEST_EQUALS(renderTask3, renderTaskList.GetTask(2u), TEST_LOCATION);
+  DALI_TEST_EQUALS(renderTask4, renderTaskList.GetTask(3u), TEST_LOCATION);
+  DALI_TEST_EQUALS(renderTask2, renderTaskList.GetTask(4u), TEST_LOCATION);
+
+  END_TEST;
+}
index e80063d..d98c869 100644 (file)
@@ -2673,6 +2673,7 @@ int UtcDaliSceneGetOverlayLayer(void)
 
   // If new render task is created, the last task is overlayTask
   RenderTask newTask = scene.GetRenderTaskList().CreateTask();
+  application.SendNotification();
   DALI_TEST_EQUALS(tasks.GetTaskCount(), 3u, TEST_LOCATION);
   DALI_TEST_EQUALS(newTask, tasks.GetTask(1u), TEST_LOCATION);
   DALI_TEST_EQUALS(overlayTask, tasks.GetTask(2u), TEST_LOCATION);
index 7bb3ffd..7fab6c9 100644 (file)
@@ -286,6 +286,7 @@ void Scene::RebuildDepthTree()
     actor->RebuildDepthTree();
     mDepthTreeDirty = false;
   }
+  mRenderTaskList->SortTasks();
 }
 
 void Scene::SetBackgroundColor(const Vector4& color)
index c292d96..72c65b6 100644 (file)
@@ -81,14 +81,7 @@ RenderTaskPtr RenderTask::New(Actor* sourceActor, CameraActor* cameraActor, Rend
   // transfer scene object ownership to update manager
   const SceneGraph::RenderTaskList&    parentSceneObject = renderTaskList.GetSceneObject();
   OwnerPointer<SceneGraph::RenderTask> transferOwnership(sceneObject);
-  if(isOverlayTask)
-  {
-    AddOverlayTaskMessage(task->GetEventThreadServices(), parentSceneObject, transferOwnership);
-  }
-  else
-  {
-    AddTaskMessage(task->GetEventThreadServices(), parentSceneObject, transferOwnership);
-  }
+  AddTaskMessage(task->GetEventThreadServices(), parentSceneObject, transferOwnership);
 
   // Set the default source & camera actors
   task->SetSourceActor(sourceActor);
@@ -619,6 +612,20 @@ uint32_t RenderTask::GetRenderPassTag() const
   return mRenderPassTag;
 }
 
+void RenderTask::SetOrderIndex(int32_t orderIndex)
+{
+  if(mOrderIndex != orderIndex)
+  {
+    mOrderIndex = orderIndex;
+    mRenderTaskList.RequestToSort();
+  }
+}
+
+int32_t RenderTask::GetOrderIndex() const
+{
+  return mOrderIndex;
+}
+
 const SceneGraph::RenderTask* RenderTask::GetRenderTaskSceneObject() const
 {
   return static_cast<const SceneGraph::RenderTask*>(mUpdateObject);
index 4be6c7f..62ddd86 100644 (file)
@@ -269,6 +269,16 @@ public:
    */
   uint32_t GetRenderPassTag() const;
 
+  /**
+   * @copydoc Dali::RenderTask::SetOrderIndex()
+   */
+  void SetOrderIndex(int32_t orderIndex);
+
+  /**
+   * @copydoc Dali::RenderTask::GetOrderIndex()
+   */
+  int32_t GetOrderIndex() const;
+
 public: // Used by RenderTaskList, which owns the SceneGraph::RenderTasks
   /**
    * Retrieve the scene-graph RenderTask object.
@@ -390,6 +400,7 @@ private:
   Dali::RenderTask::ScreenToFrameBufferFunction mScreenToFrameBufferFunction; ///< Used to convert screen to frame-buffer coordinates
 
   uint32_t mRenderPassTag{0u};
+  int32_t mOrderIndex{0u};
 
   bool mExclusive : 1;    ///< True if the render-task has exclusive access to the source Nodes.
   bool mInputEnabled : 1; ///< True if the render-task should be considered for input handling.
index 70cb524..34912a0 100644 (file)
@@ -42,6 +42,11 @@ namespace Dali
 {
 namespace Internal
 {
+namespace
+{
+static constexpr uint32_t ORDER_INDEX_OVERLAY_RENDER_TASK = INT32_MAX;
+}
+
 RenderTaskListPtr RenderTaskList::New()
 {
   RenderTaskListPtr taskList = new RenderTaskList();
@@ -56,16 +61,14 @@ RenderTaskPtr RenderTaskList::CreateTask()
   return CreateTask(&mDefaults.GetDefaultRootActor(), &mDefaults.GetDefaultCameraActor());
 }
 
-RenderTaskPtr RenderTaskList::CreateTask(Actor* sourceActor, CameraActor* cameraActor)
+RenderTaskPtr RenderTaskList::CreateTask(Actor* sourceActor, CameraActor* cameraActor, bool isOverlayTask)
 {
   RenderTaskPtr task = RenderTask::New(sourceActor, cameraActor, *this);
-  if(mOverlayRenderTask && mTasks.back() == mOverlayRenderTask)
-  {
-    mTasks.insert(mTasks.end() - 1, task);
-  }
-  else
+  mTasks.push_back(task);
+
+  if(isOverlayTask)
   {
-    mTasks.push_back(task);
+    task->SetOrderIndex(ORDER_INDEX_OVERLAY_RENDER_TASK);
   }
 
   // Setup mapping infomations between scenegraph rendertask
@@ -78,11 +81,7 @@ RenderTaskPtr RenderTaskList::CreateOverlayTask(Actor* sourceActor, CameraActor*
 {
   if(!mOverlayRenderTask)
   {
-    mOverlayRenderTask = RenderTask::New(sourceActor, cameraActor, *this, true);
-    mTasks.push_back(mOverlayRenderTask);
-
-    // Setup mapping infomations between scenegraph rendertask
-    this->MapNotifier(mOverlayRenderTask->GetRenderTaskSceneObject(), *mOverlayRenderTask);
+    mOverlayRenderTask = CreateTask(sourceActor, cameraActor, true);
   }
   return mOverlayRenderTask;
 }
@@ -170,6 +169,25 @@ void RenderTaskList::SetExclusive(RenderTask* task, bool exclusive)
   }
 }
 
+void RenderTaskList::SortTasks()
+{
+  if(!mIsRequestedToSortTask)
+  {
+    return;
+  }
+
+  std::stable_sort(mTasks.begin(), mTasks.end(), [](RenderTaskPtr first, RenderTaskPtr second) -> bool
+                   { return first->GetOrderIndex() < second->GetOrderIndex(); });
+
+  OwnerPointer<std::vector<const SceneGraph::RenderTask*>> sortedTasks(new std::vector<const SceneGraph::RenderTask*>());
+  for(auto && task : mTasks)
+  {
+    sortedTasks->push_back(task->GetRenderTaskSceneObject());
+  }
+  SortTasksMessage(mEventThreadServices, *mSceneObject, sortedTasks);
+  mIsRequestedToSortTask = false;
+}
+
 RenderTaskList::RenderTaskList()
 : mEventThreadServices(EventThreadServices::Get()),
   mDefaults(*Stage::GetCurrent()),
index 2be8177..8fce92f 100644 (file)
@@ -90,7 +90,7 @@ public:
    * @param[in] cameraActor The actor from which the scene is viewed for this render task.
    * @return A valid handle to a new RenderTask
    */
-  RenderTaskPtr CreateTask(Actor* sourceActor, CameraActor* cameraActor);
+  RenderTaskPtr CreateTask(Actor* sourceActor, CameraActor* cameraActor, bool isOverlayTask = false);
 
   /**
    * @brief Creates a new RenderTask for overlay.
@@ -150,6 +150,19 @@ public:
   }
 
   /**
+   * @brief Request to sort RenderTasks along OrderIndex
+   */
+  void RequestToSort()
+  {
+    mIsRequestedToSortTask = true;
+  }
+
+  /**
+   * @brief Sort RenderTasks along OrderIndex
+   */
+  void SortTasks();
+
+  /**
    * Provide notification signals for a "Finished" render task.
    * This method should be called in the event-thread
    * Queue NotifyFinishedMessage() from update-thread
@@ -200,6 +213,8 @@ private:
   RenderTaskContainer mTasks;      ///< Reference counted render-tasks
   ExclusivesContainer mExclusives; ///< List of rendertasks with exclusively owned source actors.
   RenderTaskPtr       mOverlayRenderTask{nullptr};
+
+  bool mIsRequestedToSortTask{false};
 };
 
 } // namespace Internal
index deb1795..128c858 100644 (file)
@@ -46,8 +46,7 @@ RenderTaskList* RenderTaskList::New()
 RenderTaskList::RenderTaskList()
 : mNotificationObject(nullptr),
   mResetterManager(nullptr),
-  mRenderMessageDispatcher(nullptr),
-  mOverlayRenderTask(nullptr)
+  mRenderMessageDispatcher(nullptr)
 {
 }
 
@@ -71,20 +70,7 @@ void RenderTaskList::AddTask(OwnerPointer<RenderTask>& newTask)
 
   newTask->Initialize(*mResetterManager, *mRenderMessageDispatcher);
 
-  if(mOverlayRenderTask && mRenderTasks[mRenderTasks.Size() - 1] == mOverlayRenderTask)
-  {
-    mRenderTasks.Insert(mRenderTasks.End() - 1, newTask.Release());
-  }
-  else
-  {
-    mRenderTasks.PushBack(newTask.Release());
-  }
-}
-
-void RenderTaskList::AddOverlayTask(OwnerPointer<RenderTask>& newTask)
-{
-  AddTask(newTask);
-  mOverlayRenderTask = mRenderTasks[mRenderTasks.Size() - 1];
+  mRenderTasks.PushBack(newTask.Release());
 }
 
 void RenderTaskList::RemoveTask(RenderTask* task)
@@ -94,11 +80,6 @@ void RenderTaskList::RemoveTask(RenderTask* task)
   {
     if(*iter == task)
     {
-      if(mOverlayRenderTask == task)
-      {
-        mOverlayRenderTask = nullptr;
-      }
-
       // Destroy the task
       mRenderTasks.Erase(iter);
 
@@ -107,6 +88,16 @@ void RenderTaskList::RemoveTask(RenderTask* task)
   }
 }
 
+void RenderTaskList::SortTasks(OwnerPointer<std::vector<const SceneGraph::RenderTask*>>& sortedTasks)
+{
+  for(uint32_t i = 0; i < sortedTasks->size(); ++i)
+  {
+    const SceneGraph::RenderTask* task = (*sortedTasks)[i];
+    SceneGraph::RenderTask* castedTask = const_cast<SceneGraph::RenderTask*>(task);
+    mRenderTasks[i]                    = castedTask;
+  }
+}
+
 uint32_t RenderTaskList::GetTaskCount()
 {
   return static_cast<uint32_t>(mRenderTasks.Count());
index dd78e0c..4df6ec2 100644 (file)
@@ -75,12 +75,6 @@ public:
   void AddTask(OwnerPointer<RenderTask>& newTask);
 
   /**
-   * Add a overlay RenderTask to the list.
-   * @param[in] newTask The RenderTaskList takes ownership of this overlay task.
-   */
-  void AddOverlayTask(OwnerPointer<RenderTask>& newTask);
-
-  /**
    * Remove a RenderTask from the list.
    * @param[in] task The RenderTaskList will destroy this task.
    */
@@ -120,6 +114,11 @@ public:
    */
   static uint32_t GetMemoryPoolCapacity();
 
+  /**
+   * @brief Sort RenderTasks along OrderIndex
+   */
+  void SortTasks(OwnerPointer<std::vector<const SceneGraph::RenderTask*>>& sortedTasks);
+
 protected:
   /**
    * Protected constructor. See New()
@@ -138,7 +137,6 @@ private:
   ResetterManager*               mResetterManager;         ///< for sending bake resetter if rendertask initalized
   RenderMessageDispatcher*       mRenderMessageDispatcher; ///< for sending messages to render thread
   RenderTaskContainer            mRenderTasks;             ///< A container of owned RenderTasks
-  RenderTask*                    mOverlayRenderTask;       ///< OverlayRenderTask.
 };
 
 // Messages for RenderTaskList
@@ -155,30 +153,29 @@ inline void AddTaskMessage(EventThreadServices& eventThreadServices, const Rende
   new(slot) LocalType(&list, &RenderTaskList::AddTask, task);
 }
 
-inline void AddOverlayTaskMessage(EventThreadServices& eventThreadServices, const RenderTaskList& list, OwnerPointer<RenderTask>& task)
+inline void RemoveTaskMessage(EventThreadServices& eventThreadServices, const RenderTaskList& list, const RenderTask& constTask)
 {
-  // Message has ownership of the RenderTask while in transit from event -> update
-  using LocalType = MessageValue1<RenderTaskList, OwnerPointer<RenderTask> >;
+  // Scene graph thread can destroy this object.
+  RenderTask& task = const_cast<RenderTask&>(constTask);
+
+  using LocalType = MessageValue1<RenderTaskList, RenderTask*>;
 
   // 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(&list, &RenderTaskList::AddOverlayTask, task);
+  new(slot) LocalType(&list, &RenderTaskList::RemoveTask, &task);
 }
 
-inline void RemoveTaskMessage(EventThreadServices& eventThreadServices, const RenderTaskList& list, const RenderTask& constTask)
+inline void SortTasksMessage(EventThreadServices& eventThreadServices, const RenderTaskList& list, OwnerPointer<std::vector<const SceneGraph::RenderTask*>>& sortedTasks)
 {
-  // Scene graph thread can destroy this object.
-  RenderTask& task = const_cast<RenderTask&>(constTask);
-
-  using LocalType = MessageValue1<RenderTaskList, RenderTask*>;
+  using LocalType = MessageValue1<RenderTaskList, OwnerPointer<std::vector<const SceneGraph::RenderTask*>>>;
 
   // 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(&list, &RenderTaskList::RemoveTask, &task);
+  new(slot) LocalType(&list, &RenderTaskList::SortTasks, sortedTasks);
 }
 
 } // namespace SceneGraph
index 9740581..aaa1328 100644 (file)
@@ -48,6 +48,9 @@ const bool     RenderTask::DEFAULT_CLEAR_ENABLED = false;
 const bool     RenderTask::DEFAULT_CULL_MODE     = true;
 const uint32_t RenderTask::DEFAULT_REFRESH_RATE  = REFRESH_ALWAYS;
 
+static constexpr int32_t MIN_ORDER_INDEX = -1000;
+static constexpr int32_t MAX_ORDER_INDEX = 1000;
+
 RenderTask::RenderTask() = default;
 
 RenderTask RenderTask::DownCast(BaseHandle handle)
@@ -283,6 +286,22 @@ uint32_t RenderTask::GetRenderPassTag() const
   return GetImplementation(*this).GetRenderPassTag();
 }
 
+void RenderTask::SetOrderIndex(int32_t orderIndex)
+{
+  if(orderIndex < MIN_ORDER_INDEX || orderIndex > MAX_ORDER_INDEX)
+  {
+    DALI_LOG_ERROR("OrderIndex value can be available between [-1000, 1000].\n");
+    orderIndex = std::min(orderIndex, MAX_ORDER_INDEX);
+    orderIndex = std::max(orderIndex, MIN_ORDER_INDEX);
+  }
+  GetImplementation(*this).SetOrderIndex(orderIndex);
+}
+
+int32_t RenderTask::GetOrderIndex() const
+{
+  return GetImplementation(*this).GetOrderIndex();
+}
+
 RenderTask::RenderTask(Internal::RenderTask* internal)
 : Handle(internal)
 {
index 8d0b356..ea4265f 100644 (file)
@@ -551,6 +551,26 @@ public:
    */
   uint32_t GetRenderPassTag() const;
 
+  /**
+   * Sets Order Index to define rendering order for this RenderTask.
+   * In the DALi, offscreen renderTasks are rendered earlier than onscreen renderTask.
+   * In each category of OffScreen RenderTask and OnScreen RenderTask,
+   * a RenderTask with a smaller orderIndex is rendered first.
+   * The RenderTasks in RenderTaskList is always sorted as acending order of the OrderIndex.
+   * The OrderIndex value is needed to be set between [-1000, 1000].
+   * Default orderIndex is 0.
+   * @param[in] orderIndex the order index for this render task.
+   * @note The order among RenderTasks whose OrderIndex has not changed follows the order in which they were created.
+   * @note Rendering order among RenderTasks those have same OrderIndex cannot be guaranteed after the OrderIndex is changed
+   */
+  void SetOrderIndex(int32_t orderIndex);
+
+  /**
+   * Gets Order Index for this RenderTask.
+   * @return OrderIndex value for this render task.
+   */
+  int32_t GetOrderIndex() const;
+
 public: // Signals
   /**
    * @brief If the refresh rate is REFRESH_ONCE, connect to this signal to be notified when a RenderTask has finished.