END_TEST;
}
+
+int UtcDaliSceneGetOverlayLayer(void)
+{
+ TestApplication application;
+ tet_infoline("Testing Dali::Integration::Scene::GetOverlayLayer");
+
+ Dali::Integration::Scene scene = application.GetScene();
+
+ // Check we get a valid instance.
+ RenderTaskList tasks = scene.GetRenderTaskList();
+
+ // There should be 1 task by default.
+ DALI_TEST_EQUALS(tasks.GetTaskCount(), 1u, TEST_LOCATION);
+ RenderTask defaultTask = tasks.GetTask(0u);
+ DALI_TEST_EQUALS(scene.GetRootLayer(), defaultTask.GetSourceActor(), TEST_LOCATION);
+
+ Layer layer = scene.GetOverlayLayer();
+ // There should be 2 task by default.
+ DALI_TEST_EQUALS(tasks.GetTaskCount(), 2u, TEST_LOCATION);
+ RenderTask overlayTask = tasks.GetTask(1u);
+ DALI_TEST_EQUALS(overlayTask, tasks.GetOverlayTask(), TEST_LOCATION);
+ DALI_TEST_CHECK(scene.GetRootLayer() != overlayTask.GetSourceActor());
+ DALI_TEST_CHECK(overlayTask != defaultTask);
+ DALI_TEST_EQUALS(overlayTask.GetClearEnabled(), false, TEST_LOCATION);
+ DALI_TEST_EQUALS(overlayTask.IsExclusive(), true, TEST_LOCATION);
+
+ // If new render task is created, the last task is overlayTask
+ RenderTask newTask = scene.GetRenderTaskList().CreateTask();
+ 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);
+
+ // Render
+ application.SendNotification();
+ application.Render();
+
+ tasks.RemoveTask(overlayTask);
+ DALI_TEST_EQUALS(tasks.GetTaskCount(), 2u, TEST_LOCATION);
+ DALI_TEST_EQUALS(tasks.GetTask(0u), defaultTask, TEST_LOCATION);
+ DALI_TEST_EQUALS(tasks.GetTask(1u), newTask, TEST_LOCATION);
+
+ END_TEST;
+}
+
+int UtcDaliSceneSurfaceResizedWithOverlayLayer(void)
+{
+ tet_infoline("Ensure resizing of the surface is handled properly");
+
+ TestApplication application;
+
+ auto scene = application.GetScene();
+ DALI_TEST_CHECK(scene);
+
+ const RenderTaskList& tasks = scene.GetRenderTaskList();
+ DALI_TEST_EQUALS(tasks.GetTaskCount(), 1u, TEST_LOCATION);
+ RenderTask defaultTask = tasks.GetTask(0u);
+ DALI_TEST_EQUALS(scene.GetRootLayer(), defaultTask.GetSourceActor(), TEST_LOCATION);
+
+ // Ensure stage size matches the scene size
+ auto stage = Stage::GetCurrent();
+ Vector2 sceneSize = stage.GetSize();
+ Viewport sceneViewport(0, 0, sceneSize.x, sceneSize.y);
+ DALI_TEST_EQUALS(stage.GetSize(), scene.GetSize(), TEST_LOCATION);
+ Viewport defaultViewport = defaultTask.GetViewport();
+ DALI_TEST_EQUALS(defaultViewport, sceneViewport, TEST_LOCATION);
+
+ Layer layer = scene.GetOverlayLayer();
+ // There should be 2 task by default.
+ DALI_TEST_EQUALS(tasks.GetTaskCount(), 2u, TEST_LOCATION);
+ RenderTask overlayTask = tasks.GetTask(1u);
+ Viewport overlayViewport = defaultTask.GetViewport();
+ DALI_TEST_EQUALS(defaultViewport, overlayViewport, TEST_LOCATION);
+
+ // Resize the scene
+ Vector2 newSize(1000.0f, 2000.0f);
+ DALI_TEST_CHECK(stage.GetSize() != newSize);
+ scene.SurfaceResized(newSize.width, newSize.height);
+ Viewport newViewport(0, 0, newSize.x, newSize.y);
+ DALI_TEST_EQUALS(newViewport, defaultTask.GetViewport(), TEST_LOCATION);
+ DALI_TEST_EQUALS(newViewport, defaultTask.GetViewport(), TEST_LOCATION);
+
+ END_TEST;
+}
return GetImplementation(*this).GetRootLayer();
}
+Layer Scene::GetOverlayLayer()
+{
+ return GetImplementation(*this).GetOverlayLayer();
+}
+
uint32_t Scene::GetLayerCount() const
{
return GetImplementation(*this).GetLayerCount();
*/
Layer GetRootLayer() const;
+ /**
+ * @brief Returns the Scene's Overlay Layer.
+ * If there is no overlay layer yet, this creates the layer and an associated render task.
+ *
+ * @return The overlay layer
+ */
+ Layer GetOverlayLayer();
+
/**
* @brief Queries the number of on-stage layers.
*
mRootLayer.Reset();
}
+ if(mOverlayLayer)
+ {
+ mOverlayLayer.Reset();
+ }
+
if(mRenderTaskList)
{
mRenderTaskList.Reset();
return Dali::Layer(mRootLayer.Get());
}
+Dali::Layer Scene::GetOverlayLayer()
+{
+ if(!mOverlayLayer)
+ {
+ // Creates overlay layer.
+ mOverlayLayer = Layer::New();
+ mOverlayLayer->SetName("OverlayLayer");
+ mOverlayLayer->SetResizePolicy(ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS);
+ mOverlayLayer->SetParentOrigin(Dali::ParentOrigin::TOP_LEFT);
+ mOverlayLayer->SetAnchorPoint(Dali::AnchorPoint::TOP_LEFT);
+ mRootLayer->Add(*mOverlayLayer);
+
+ // Create the overlay render-task and set exclusive to true.
+ RenderTaskPtr renderTask = mRenderTaskList->CreateOverlayTask(mOverlayLayer.Get(), mDefaultCamera.Get());
+ renderTask->SetExclusive(true);
+ renderTask->SetInputEnabled(true);
+ }
+ return Dali::Layer(mOverlayLayer.Get());
+}
+
LayerList& Scene::GetLayerList() const
{
return *mLayerList;
// set default render-task viewport parameters
RenderTaskPtr defaultRenderTask = mRenderTaskList->GetTask(0u);
defaultRenderTask->SetViewport(newSize);
+ // set overlay render-task viewport parameters
+ RenderTaskPtr overlayRenderTask = mRenderTaskList->GetOverlayTask();
+ if(overlayRenderTask)
+ {
+ overlayRenderTask->SetViewport(newSize);
+ }
}
bool Scene::IsSurfaceRectChanged() const
*/
Dali::Layer GetRootLayer() const;
+ /**
+ * @copydoc Dali::Integration::Scene::GetOverlayLayer
+ */
+ Dali::Layer GetOverlayLayer();
+
/**
* @copydoc Dali::Integration::Scene::GetLayerCount
*/
LayerPtr mRootLayer;
+ LayerPtr mOverlayLayer;
+
// Ordered list of currently on-stage layers
OwnerPointer<LayerList> mLayerList;
} // Unnamed namespace
-RenderTaskPtr RenderTask::New(Actor* sourceActor, CameraActor* cameraActor, RenderTaskList& renderTaskList)
+RenderTaskPtr RenderTask::New(Actor* sourceActor, CameraActor* cameraActor, RenderTaskList& renderTaskList, bool isOverlayTask)
{
// create scene object first so it's guaranteed to exist for the event side
auto sceneObject = SceneGraph::RenderTask::New();
// transfer scene object ownership to update manager
const SceneGraph::RenderTaskList& parentSceneObject = renderTaskList.GetSceneObject();
OwnerPointer<SceneGraph::RenderTask> transferOwnership(sceneObject);
- AddTaskMessage(task->GetEventThreadServices(), parentSceneObject, transferOwnership);
+ if(isOverlayTask)
+ {
+ AddOverlayTaskMessage(task->GetEventThreadServices(), parentSceneObject, transferOwnership);
+ }
+ else
+ {
+ AddTaskMessage(task->GetEventThreadServices(), parentSceneObject, transferOwnership);
+ }
// Set the default source & camera actors
task->SetSourceActor(sourceActor);
* @param[in] sourceActor The source actor.
* @param[in] cameraActor The camera actor.
* @param[in] renderTaskList The render task list.
+ * @param[in] isOverlayTask True if this render task is overlay task. default is false.
* @return The created render task
*/
- static RenderTaskPtr New(Actor* sourceActor, CameraActor* cameraActor, RenderTaskList& renderTaskList);
+ static RenderTaskPtr New(Actor* sourceActor, CameraActor* cameraActor, RenderTaskList& renderTaskList, bool isOverlayTask = false);
/**
* @copydoc Dali::RenderTask::SetSourceActor()
{
namespace Internal
{
+
RenderTaskListPtr RenderTaskList::New()
{
RenderTaskListPtr taskList = new RenderTaskList();
RenderTaskPtr RenderTaskList::CreateTask(Actor* sourceActor, CameraActor* cameraActor)
{
RenderTaskPtr task = RenderTask::New(sourceActor, cameraActor, *this);
-
- mTasks.push_back(task);
+ if(mOverlayRenderTask && mTasks.back() == mOverlayRenderTask)
+ {
+ mTasks.insert(mTasks.end() - 1, task);
+ }
+ else
+ {
+ mTasks.push_back(task);
+ }
return task;
}
+RenderTaskPtr RenderTaskList::CreateOverlayTask(Actor* sourceActor, CameraActor* cameraActor)
+{
+ if(!mOverlayRenderTask)
+ {
+ mOverlayRenderTask = RenderTask::New(sourceActor, cameraActor, *this, true);
+ mTasks.push_back(mOverlayRenderTask);
+ }
+ return mOverlayRenderTask;
+}
+
void RenderTaskList::RemoveTask(Internal::RenderTask& task)
{
for(RenderTaskContainer::iterator iter = mTasks.begin(); mTasks.end() != iter; ++iter)
// send a message to remove the scene-graph RenderTask
RemoveTaskMessage(mEventThreadServices, *mSceneObject, sceneObject);
- for(auto exclusiveIt = mExclusives.begin(); exclusiveIt != mExclusives.end(); ++exclusiveIt)
+ Exclusive exclusive{ptr, ActorObserver()};
+ ExclusivesContainer::iterator exclusiveIter = find(mExclusives.begin(), mExclusives.end(), exclusive);
+ if(exclusiveIter != mExclusives.end())
{
- if(exclusiveIt->renderTaskPtr == ptr)
- {
- mExclusives.erase(exclusiveIt);
- break;
- }
+ mExclusives.erase(exclusiveIter);
}
break; // we're finished
}
return mTasks[index];
}
+RenderTaskPtr RenderTaskList::GetOverlayTask() const
+{
+ RenderTaskPtr overlayRenderTask;
+ if(mOverlayRenderTask)
+ {
+ overlayRenderTask = mOverlayRenderTask;
+ }
+ return overlayRenderTask;
+}
+
void RenderTaskList::SetExclusive(RenderTask* task, bool exclusive)
{
// Check to see if this rendertask has an entry?
{
RenderTask* renderTaskPtr; ///< Pointer for comparison with current rendertask.
ActorObserver actor; ///< For comparison with current actor.
+
+ bool operator==(const Exclusive& other) const
+ {
+ return renderTaskPtr == other.renderTaskPtr;
+ }
};
using ExclusivesContainer = std::vector<Exclusive>;
+ using ExclusiveIter = ExclusivesContainer::iterator;
/**
* Create a RenderTaskList.
*/
RenderTaskPtr CreateTask(Actor* sourceActor, CameraActor* cameraActor);
+ /**
+ * @brief Creates a new RenderTask for overlay.
+ * This will be appended to the end of render-task list.
+ * @param[in] sourceActor The actor and its children to be rendered for this render task.
+ * @param[in] cameraActor The actor from which the scene is viewed for this render task.
+ * @return A valid handle to a new overlay RenderTask
+ * @note The Overlay RenderTask will be rendered after all the other render tasks are rendered.
+ */
+ RenderTaskPtr CreateOverlayTask(Actor* sourceActor, CameraActor* cameraActor);
+
/**
* @copydoc Dali::RenderTaskList::RemoveTask()
*/
*/
RenderTaskPtr GetTask(uint32_t index) const;
+ /**
+ * @copydoc Dali::RenderTaskList::GetOverlayTask()
+ */
+ RenderTaskPtr GetOverlayTask() const;
+
/**
* Retrieve the container of render-tasks.
* @return The container.
RenderTaskContainer mTasks; ///< Reference counted render-tasks
ExclusivesContainer mExclusives; ///< List of rendertasks with exclusively owned source actors.
+ RenderTaskPtr mOverlayRenderTask{nullptr};
};
} // namespace Internal
RenderTaskList::RenderTaskList()
: mNotificationObject(nullptr),
- mRenderMessageDispatcher(nullptr)
+ mRenderMessageDispatcher(nullptr),
+ mOverlayRenderTask(nullptr)
{
}
DALI_ASSERT_DEBUG(mRenderMessageDispatcher != NULL && "RenderMessageDispatcher is null");
newTask->Initialize(*mRenderMessageDispatcher);
- // mRenderTasks container takes ownership
- mRenderTasks.PushBack(newTask.Release());
+
+ 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];
}
void RenderTaskList::RemoveTask(RenderTask* task)
*/
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.
CompleteNotificationInterface* mNotificationObject; ///< object to pass in to the complete notification
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)
+{
+ // Message has ownership of the RenderTask while in transit from event -> update
+ using LocalType = MessageValue1<RenderTaskList, OwnerPointer<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);
+}
+
inline void RemoveTaskMessage(EventThreadServices& eventThreadServices, const RenderTaskList& list, const RenderTask& constTask)
{
// Scene graph thread can destroy this object.
return RenderTask(GetImplementation(*this).GetTask(index).Get());
}
+RenderTask RenderTaskList::GetOverlayTask() const
+{
+ return RenderTask(GetImplementation(*this).GetOverlayTask().Get());
+}
+
RenderTaskList::RenderTaskList(Internal::RenderTaskList* internal)
: BaseHandle(internal)
{
*/
RenderTask GetTask(uint32_t index) const;
+ /**
+ * @brief Retrieves a RenderTask for Overlay
+ * @SINCE_2_2.10
+ * @return A handle to the overlay RenderTask.
+ * If the scene has not created an overlay render task, this returns empty handle.
+ */
+ RenderTask GetOverlayTask() const;
+
public: // Not intended for application developers
/// @cond internal
/**