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;
+}
// 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);
actor->RebuildDepthTree();
mDepthTreeDirty = false;
}
+ mRenderTaskList->SortTasks();
}
void Scene::SetBackgroundColor(const Vector4& color)
// 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);
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);
*/
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.
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.
{
namespace Internal
{
+namespace
+{
+static constexpr uint32_t ORDER_INDEX_OVERLAY_RENDER_TASK = INT32_MAX;
+}
+
RenderTaskListPtr RenderTaskList::New()
{
RenderTaskListPtr taskList = new RenderTaskList();
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
{
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;
}
}
}
+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()),
* @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.
}
/**
+ * @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
RenderTaskContainer mTasks; ///< Reference counted render-tasks
ExclusivesContainer mExclusives; ///< List of rendertasks with exclusively owned source actors.
RenderTaskPtr mOverlayRenderTask{nullptr};
+
+ bool mIsRequestedToSortTask{false};
};
} // namespace Internal
RenderTaskList::RenderTaskList()
: mNotificationObject(nullptr),
mResetterManager(nullptr),
- mRenderMessageDispatcher(nullptr),
- mOverlayRenderTask(nullptr)
+ mRenderMessageDispatcher(nullptr)
{
}
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)
{
if(*iter == task)
{
- if(mOverlayRenderTask == task)
- {
- mOverlayRenderTask = nullptr;
- }
-
// Destroy the task
mRenderTasks.Erase(iter);
}
}
+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());
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.
*/
*/
static uint32_t GetMemoryPoolCapacity();
+ /**
+ * @brief Sort RenderTasks along OrderIndex
+ */
+ void SortTasks(OwnerPointer<std::vector<const SceneGraph::RenderTask*>>& sortedTasks);
+
protected:
/**
* Protected constructor. See New()
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
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
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)
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)
{
*/
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.