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;
return mSourceActor.GetActor();
}
+Actor* RenderTask::GetStopperActor() const
+{
+ return mStopperActor.GetActor();
+}
+
void RenderTask::SetExclusive(bool exclusive)
{
if(mExclusive != exclusive)
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);
*/
Actor* GetSourceActor() const;
+ Actor* GetStopperActor() const;
+
/**
* @copydoc Dali::RenderTask::SetExclusive()
*/
*/
uint32_t GetRenderTaskId() const;
+ void RenderUntil(Actor* actor);
+
public: // Used by RenderTaskList, which owns the SceneGraph::RenderTasks
/**
* Retrieve the scene-graph RenderTask object.
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
* @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,
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))
{
// 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);
}
}
sortedLayer->ClearRenderables();
}
+ bool stopRendering = false;
+
AddRenderablesForTask(updateBufferIndex,
*sourceNode,
false,
0u,
0u,
hasClippingNodes,
- keepRendering);
+ keepRendering,
+ stopRendering);
renderInstructionProcessor.Prepare(updateBufferIndex,
sortedLayers,
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*>;
return mSourceNode;
}
+void RenderTask::SetStopperNode(Node* node)
+{
+ mStopperNode = node;
+}
+
+Node* RenderTask::GetStopperNode() const
+{
+ return mStopperNode;
+}
+
void RenderTask::SetViewportGuideNode(Node* node)
{
mViewportGuideNode = node;
*/
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.
RenderMessageDispatcher* mRenderMessageDispatcher;
Render::RenderTracker* mRenderSyncTracker;
Node* mSourceNode;
+ Node* mStopperNode;
SceneGraph::Camera* mCameraNode;
Node* mViewportGuideNode;
Render::FrameBuffer* mFrameBuffer;
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);
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)
{
*/
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
*/
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.