DALI_TEST_EQUALS(application.GetScene().GetRenderTaskList().GetTaskCount(), 1, TEST_LOCATION);
DerivedCustomActor customActor = DerivedCustomActor::New();
+ application.GetScene().Add(customActor);
Geometry geometry = CreateQuadGeometry();
Shader shader = CreateShader();
Renderer renderer2 = Renderer::New(geometry, shader);
customActor.AddRenderer(renderer);
- customActor.GetImplementation().SetCacheRenderer(renderer);
- customActor.GetImplementation().SetCacheRenderer(renderer2);
- customActor.GetImplementation().SetCacheRenderer(renderer2);
- DALI_TEST_EQUALS(customActor.GetRendererCount(), 1, TEST_LOCATION); // cache renderer is not counted.
+ customActor.AddCacheRenderer(renderer);
+ customActor.AddCacheRenderer(renderer2);
+ customActor.AddCacheRenderer(renderer2);
+ DALI_TEST_EQUALS(customActor.GetRendererCount(), 1, TEST_LOCATION);
+ DALI_TEST_EQUALS(customActor.GetCacheRendererCount(), 2, TEST_LOCATION);
customActor.RemoveRenderer(0u);
- customActor.GetImplementation().SetCacheRenderer(renderer);
+ customActor.AddCacheRenderer(renderer);
application.SendNotification();
application.Render();
- customActor.GetImplementation().RemoveCacheRenderer();
- customActor.GetImplementation().RemoveCacheRenderer();
+ DALI_TEST_EQUALS(customActor.GetRendererCount(), 0, TEST_LOCATION);
+ DALI_TEST_EQUALS(customActor.GetCacheRendererCount(), 2, TEST_LOCATION);
+
+ customActor.RemoveCacheRenderer(renderer);
+ customActor.RemoveCacheRenderer(renderer2);
application.SendNotification();
application.Render();
- customActor.GetImplementation().SetCacheRenderer(renderer2);
+ DALI_TEST_EQUALS(customActor.GetCacheRendererCount(), 0, TEST_LOCATION);
+
+ customActor.AddCacheRenderer(renderer2);
+
+ CameraActor camera = CameraActor::New();
+ application.GetScene().Add(camera);
+
+ RenderTaskList taskList = application.GetScene().GetRenderTaskList();
+ RenderTask newTask = taskList.CreateTask();
+ newTask.SetSourceActor(customActor);
+ newTask.SetExclusive(true);
+ newTask.SetCameraActor(camera);
+ newTask.SetInputEnabled(false);
+ newTask.SetClearColor(Color::TRANSPARENT);
+ newTask.SetClearEnabled(true);
+ newTask.SetFrameBuffer(FrameBuffer::New(10u, 10u));
+
+ RenderTask newTask2 = taskList.CreateTask();
+ newTask2.SetSourceActor(customActor);
+ newTask2.SetExclusive(true);
+ newTask2.SetCameraActor(camera);
+ newTask2.SetInputEnabled(false);
+ newTask2.SetClearColor(Color::TRANSPARENT);
+ newTask2.SetClearEnabled(true);
+ newTask2.SetFrameBuffer(FrameBuffer::New(10u, 10u));
+
+ application.SendNotification();
+ application.Render();
tet_result(TET_PASS);
END_TEST;
/*
- * Copyright (c) 2024 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2025 Samsung Electronics Co., Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
rootActor.SetProperty(Actor::Property::SIZE, Vector2(10.0f, 10.0f));
application.GetScene().Add(rootActor);
- RenderTaskList taskList = application.GetScene().GetRenderTaskList();
- Texture frameBufferTexture = Texture::New(TextureType::TEXTURE_2D, Pixel::Format::RGBA8888, 10, 10);
- FrameBuffer frameBuffer = FrameBuffer::New(frameBufferTexture.GetWidth(), frameBufferTexture.GetHeight());
+ RenderTaskList taskList = application.GetScene().GetRenderTaskList();
+ Texture frameBufferTexture = Texture::New(TextureType::TEXTURE_2D, Pixel::Format::RGBA8888, 10, 10);
+ FrameBuffer frameBuffer = FrameBuffer::New(frameBufferTexture.GetWidth(), frameBufferTexture.GetHeight());
frameBuffer.AttachColorTexture(frameBufferTexture);
RenderTask newTask = taskList.CreateTask();
{
if(!mRenderers)
{
- mRenderers = new RendererContainer(GetEventThreadServices());
+ mRenderers = new RendererContainer(GetEventThreadServices(), false);
}
return mRenderers->Add(GetNode(), renderer, mIsBlendEquationSet, mBlendEquation);
}
{
mRenderers->SetBlending(blendEquation);
}
+ if(mCacheRenderers)
+ {
+ mCacheRenderers->SetBlending(blendEquation);
+ }
}
mIsBlendEquationSet = true;
}
}
}
-void Actor::SetCacheRenderer(Renderer& renderer)
+uint32_t Actor::AddCacheRenderer(Renderer& renderer)
{
const SceneGraph::Node& node = GetNode();
- if(mCacheRenderer)
+ if(!mCacheRenderers)
{
- if(mCacheRenderer == RendererPtr(&renderer))
- {
- return;
- }
- RemoveCacheRenderer();
+ mCacheRenderers = new RendererContainer(GetEventThreadServices(), true);
}
+ return mCacheRenderers->Add(node, renderer, mIsBlendEquationSet, mBlendEquation);
+}
- if(mIsBlendEquationSet)
- {
- renderer.SetBlendEquation(mBlendEquation);
- }
- mCacheRenderer = RendererPtr(&renderer);
- AttachCacheRendererMessage(GetEventThreadServices().GetUpdateManager(), node, renderer.GetRendererSceneObject());
+uint32_t Actor::GetCacheRendererCount() const
+{
+ return mCacheRenderers ? mCacheRenderers->GetCount() : 0u;
}
-void Actor::RemoveCacheRenderer()
+void Actor::RemoveCacheRenderer(Renderer& renderer)
{
- if(DALI_LIKELY(mCacheRenderer))
+ if(mCacheRenderers)
{
- const SceneGraph::Node& node = GetNode();
- DetachCacheRendererMessage(GetEventThreadServices(), node, mCacheRenderer->GetRendererSceneObject());
- mCacheRenderer.Reset();
+ mCacheRenderers->Remove(GetNode(), renderer);
}
}
mParent(nullptr),
mScene(nullptr),
mRenderers(nullptr),
+ mCacheRenderers(nullptr),
mParentOrigin(nullptr),
mAnchorPoint(nullptr),
mGestureData(nullptr),
// Detach all renderers before delete container.
mRenderers->RemoveAll(GetNode());
}
- if(mCacheRenderer)
+ if(mCacheRenderers)
{
- RemoveCacheRenderer();
+ mCacheRenderers->RemoveAll(GetNode());
}
// Root layer will destroy its node in its own destructor
}
// Cleanup renderer list
delete mRenderers;
+ delete mCacheRenderers;
// Cleanup optional gesture data
delete mGestureData;
* @param[in] renderer Renderer to set to the Actor
* @pre The renderer must be initialized.
*/
- void SetCacheRenderer(Renderer& renderer);
+ uint32_t AddCacheRenderer(Renderer& renderer);
+
+ /**
+ * Retrieves the number of cache renderers in this actor.
+ * @return The number of cache renderers.
+ */
+ uint32_t GetCacheRendererCount() const;
/**
* @brief Removes cache renderer from the Actor.
+ * @param[in] renderer The cache renderer to remove.
*/
- void RemoveCacheRenderer();
+ void RemoveCacheRenderer(Renderer& renderer);
protected:
enum DerivedType
void SetUpdateAreaHint(const Vector4& updateAreaHint);
protected:
- ActorParentImpl mParentImpl; ///< Implementation of ActorParent;
- ActorSizer mSizer; ///< Implementation for managing actor size
- ActorParent* mParent; ///< Each actor (except the root) can have one parent
- Scene* mScene; ///< The scene the actor is added to
- RendererContainer* mRenderers; ///< Renderer container
- RendererPtr mCacheRenderer; ///< Result of offscreen rendering
- Vector3* mParentOrigin; ///< NULL means ParentOrigin::DEFAULT. ParentOrigin is non-animatable
- Vector3* mAnchorPoint; ///< NULL means AnchorPoint::DEFAULT. AnchorPoint is non-animatable
- ActorGestureData* mGestureData; ///< Optional Gesture data. Only created when actor requires gestures
+ ActorParentImpl mParentImpl; ///< Implementation of ActorParent;
+ ActorSizer mSizer; ///< Implementation for managing actor size
+ ActorParent* mParent; ///< Each actor (except the root) can have one parent
+ Scene* mScene; ///< The scene the actor is added to
+ RendererContainer* mRenderers; ///< Renderer container
+ RendererContainer* mCacheRenderers; ///< Renderers rendering offscreen rendering results
+ Vector3* mParentOrigin; ///< NULL means ParentOrigin::DEFAULT. ParentOrigin is non-animatable
+ Vector3* mAnchorPoint; ///< NULL means AnchorPoint::DEFAULT. AnchorPoint is non-animatable
+ ActorGestureData* mGestureData; ///< Optional Gesture data. Only created when actor requires gestures
// Signals
Dali::Actor::TouchEventSignalType mInterceptTouchedSignal;
/*
- * Copyright (c) 2024 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2025 Samsung Electronics Co., Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
namespace Dali::Internal
{
-RendererContainer::RendererContainer(EventThreadServices& eventThreadServices)
-: EventThreadServicesHolder(eventThreadServices)
+RendererContainer::RendererContainer(EventThreadServices& eventThreadServices, bool isCache)
+: EventThreadServicesHolder(eventThreadServices),
+ mIsCache(isCache)
{
}
}
RendererPtr rendererPtr = RendererPtr(&renderer);
mRenderers.push_back(rendererPtr);
- AttachRendererMessage(GetEventThreadServices().GetUpdateManager(), node, renderer.GetRendererSceneObject());
+
+ if(mIsCache)
+ {
+ AttachCacheRendererMessage(GetEventThreadServices().GetUpdateManager(), node, renderer.GetRendererSceneObject());
+ }
+ else
+ {
+ AttachRendererMessage(GetEventThreadServices().GetUpdateManager(), node, renderer.GetRendererSceneObject());
+ }
+
return index;
}
if((*iter).Get() == &renderer)
{
mRenderers.erase(iter);
- DetachRendererMessage(GetEventThreadServices(), node, renderer.GetRendererSceneObject());
+
+ if(mIsCache)
+ {
+ DetachCacheRendererMessage(GetEventThreadServices(), node, renderer.GetRendererSceneObject());
+ }
+ else
+ {
+ DetachRendererMessage(GetEventThreadServices(), node, renderer.GetRendererSceneObject());
+ }
break;
}
}
if(index < mRenderers.size())
{
RendererPtr renderer = mRenderers[index];
- DetachRendererMessage(GetEventThreadServices(), node, renderer->GetRendererSceneObject());
+
+ if(mIsCache)
+ {
+ DetachCacheRendererMessage(GetEventThreadServices(), node, renderer->GetRendererSceneObject());
+ }
+ else
+ {
+ DetachRendererMessage(GetEventThreadServices(), node, renderer->GetRendererSceneObject());
+ }
+
mRenderers.erase(mRenderers.begin() + index);
}
}
void RendererContainer::RemoveAll(const SceneGraph::Node& node)
{
- for(auto&& renderer : mRenderers)
+ if(mIsCache)
{
- DetachRendererMessage(GetEventThreadServices(), node, renderer->GetRendererSceneObject());
+ for(auto&& renderer : mRenderers)
+ {
+ DetachCacheRendererMessage(GetEventThreadServices(), node, renderer->GetRendererSceneObject());
+ }
+ }
+ else
+ {
+ for(auto&& renderer : mRenderers)
+ {
+ DetachRendererMessage(GetEventThreadServices(), node, renderer->GetRendererSceneObject());
+ }
}
mRenderers.clear();
}
#define DALI_INTERNAL_ACTORS_ACTOR_RENDERER_CONTAINER_H
/*
- * Copyright (c) 2024 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2025 Samsung Electronics Co., Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* Constructor.
*
* @param[in] eventThreadServices - thread services for sending messages
+ * @param[in] isCache - whether the container is for cache renderers(drawing offscreen rendering results)
*/
- RendererContainer(EventThreadServices& eventThreadServices);
+ RendererContainer(EventThreadServices& eventThreadServices, bool isCache);
/**
* Add a renderer to this actor & actor's node, with blending applied if necessary.
private:
std::vector<RendererPtr> mRenderers; ///< The contained renderers
+
+ bool mIsCache : 1; /// The container is for cache renderers
};
} // namespace Dali::Internal
node.SetUpdated(true);
}
- RendererKey cacheRenderer = node.GetCacheRenderer();
- const bool isNodeExclusiveAtAnotherRenderTask = node.GetExclusiveRenderTaskCount() && !node.IsExclusiveRenderTask(&renderTask);
+ const uint32_t cacheCount = node.GetCacheRendererCount();
+ const bool isNodeExclusiveAtAnotherRenderTask = node.GetExclusiveRenderTaskCount() && !node.IsExclusiveRenderTask(&renderTask);
// Check whether node is exclusive to a different render-task
// Check if node has pre-drawn cache to draw
- if(isNodeExclusiveAtAnotherRenderTask && !cacheRenderer)
+ if(isNodeExclusiveAtAnotherRenderTask && cacheCount == 0u)
{
return;
}
RenderableContainer& target = DALI_LIKELY(inheritedDrawMode == DrawMode::NORMAL) ? layer->colorRenderables : layer->overlayRenderables;
- if(isNodeExclusiveAtAnotherRenderTask && cacheRenderer)
+ if(isNodeExclusiveAtAnotherRenderTask && cacheCount)
{
- target.PushBack(Renderable(&node, cacheRenderer));
+ for(uint32_t i = 0; i < cacheCount; ++i)
+ {
+ SceneGraph::RendererKey rendererKey = node.GetCacheRendererAt(i);
+ target.PushBack(Renderable(&node, rendererKey));
+ }
return;
}
void UpdateManager::AttachCacheRenderer(Node* node, Renderer* renderer)
{
- node->SetCacheRenderer(Renderer::GetKey(renderer));
+ node->AddCacheRenderer(Renderer::GetKey(renderer));
mImpl->renderersAdded = true;
}
}
}
-void Node::SetCacheRenderer(const RendererKey& renderer)
+void Node::AddCacheRenderer(const RendererKey& renderer)
{
- if(DALI_UNLIKELY(mCacheRenderer))
+ for(auto&& existingRenderer : mCacheRenderers)
{
- mCacheRenderer->DetachFromNodeDataProvider(*this);
+ if(existingRenderer == renderer)
+ {
+ return;
+ }
}
+
SetUpdated(true);
- mCacheRenderer = renderer;
+
+ mCacheRenderers.PushBack(renderer);
}
-void Node::RemoveCacheRenderer()
+void Node::RemoveCacheRenderer(const RendererKey& renderer)
{
- if(DALI_LIKELY(mCacheRenderer))
+ RendererContainer::SizeType rendererCount(mCacheRenderers.Size());
+ for(RendererContainer::SizeType i = 0; i < rendererCount; ++i)
{
- mCacheRenderer->DetachFromNodeDataProvider(*this);
- SetUpdated(true);
- mCacheRenderer = RendererKey{};
+ if(mCacheRenderers[i] == renderer)
+ {
+ renderer->DetachFromNodeDataProvider(*this);
+
+ SetUpdated(true);
+ mCacheRenderers.Erase(mCacheRenderers.Begin() + i);
+ return;
+ }
}
}
}
/**
- * Set cache renderer which draws output of offscreen rendering
- * Draws only when mOffScreenRendering is true
+ * Add cache renderer which draws output of offscreen rendering
*/
- void SetCacheRenderer(const RendererKey& renderer);
+ void AddCacheRenderer(const RendererKey& renderer);
/**
* Remove cache renderer
*/
- void RemoveCacheRenderer();
+ void RemoveCacheRenderer(const RendererKey& renderer);
/**
* Get cache renderer
+ * @param[in] index The index of the renderer in the node's cache renderer container
+ * @return RendererKey of cache renderer with given index
*/
- RendererKey GetCacheRenderer() const
+ RendererKey GetCacheRendererAt(uint32_t index) const
{
- return mCacheRenderer;
+ return mCacheRenderers[index];
+ }
+
+ /**
+ * Retrieve the number of cache renderes for the node.
+ * @return The size of cache renderer container
+ */
+ uint32_t GetCacheRendererCount() const
+ {
+ return static_cast<uint32_t>(mCacheRenderers.Size());
}
// Containment methods
Node* mParent; ///< Pointer to parent node (a child is owned by its parent)
RenderTaskContainer mExclusiveRenderTasks; ///< Nodes can be marked as exclusive to multiple RenderTasks
- RendererContainer mRenderers; ///< Container of renderers; not owned
- RendererKey mCacheRenderer; ///< Result of offscreen rendering
+ RendererContainer mRenderers; ///< Container of renderers; not owned
+ RendererContainer mCacheRenderers; ///< Container of renderers drawing offscreen rendering results
NodeContainer mChildren; ///< Container of children; not owned
inline void DetachCacheRendererMessage(EventThreadServices& eventThreadServices, const Node& node, const Renderer& renderer)
{
- using LocalType = Message<Node>;
+ using LocalType = MessageValue1<Node, RendererKey>;
// 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(&node, &Node::RemoveCacheRenderer);
+ new(slot) LocalType(&node, &Node::RemoveCacheRenderer, Renderer::GetKey(renderer));
}
inline void SetDepthIndexMessage(EventThreadServices& eventThreadServices, const Node& node, uint32_t depthIndex)
/*
- * Copyright (c) 2024 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2025 Samsung Electronics Co., Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
GetImplementation(*this).RemoveRenderer(index);
}
+uint32_t Actor::AddCacheRenderer(Renderer& renderer)
+{
+ return GetImplementation(*this).AddCacheRenderer(GetImplementation(renderer));
+}
+
+uint32_t Actor::GetCacheRendererCount() const
+{
+ return GetImplementation(*this).GetCacheRendererCount();
+}
+
+void Actor::RemoveCacheRenderer(Renderer& renderer)
+{
+ GetImplementation(*this).RemoveCacheRenderer(GetImplementation(renderer));
+}
+
Actor::OnRelayoutSignalType& Actor::OnRelayoutSignal()
{
return GetImplementation(*this).OnRelayoutSignal();
#define DALI_ACTOR_H
/*
- * Copyright (c) 2024 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2025 Samsung Electronics Co., Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
*/
void RemoveRenderer(uint32_t index);
+ /**
+ * @brief Add renderer drawing cached output to this Actor.
+ * @SINCE_2_3.54
+ * @param[in] renderer Renderer to set to the Actor
+ * @return The index of the Renderer that was added
+ * @pre The renderer must be initialized.
+ */
+ uint32_t AddCacheRenderer(Renderer& renderer);
+
+ /**
+ * @brief Get total number of cache renderers.
+ * @SINCE_2_4.19
+ * @return The size of cache renderer container
+ */
+ uint32_t GetCacheRendererCount() const;
+
+ /**
+ * @brief Removes cache renderer from the Actor.
+ * @param[in] renderer Renderer to erase.
+ * @SINCE_2_3.54
+ */
+ void RemoveCacheRenderer(Renderer& renderer);
+
public: // Signals
/**
* @brief This signal is emitted when touch input is received.
mOwner->RequestRenderTaskReorder();
}
-void CustomActorImpl::SetCacheRenderer(Renderer& renderer)
-{
- mOwner->SetCacheRenderer(GetImplementation(renderer));
-}
-
-void CustomActorImpl::RemoveCacheRenderer()
-{
- mOwner->RemoveCacheRenderer();
-}
-
CustomActorImpl::CustomActorImpl(ActorFlags flags)
: mOwner(nullptr),
mFlags(flags)
*/
void RequestRenderTaskReorder();
- /**
- * @brief Set renderer drawing cached output to this Actor.
- * @SINCE_2_3.54
- * @param[in] renderer Renderer to set to the Actor
- * @pre The renderer must be initialized.
- */
- void SetCacheRenderer(Renderer& renderer);
-
- /**
- * @brief Removes cache renderer from the Actor.
- * @SINCE_2_3.54
- */
- void RemoveCacheRenderer();
-
/**
* @brief Called after the size negotiation has been finished for this control.
*