Add view offscreen rendering 96/315396/15
authorjmm <j0064423.lee@samsung.com>
Mon, 2 Dec 2024 01:58:29 +0000 (10:58 +0900)
committerjmm <j0064423.lee@samsung.com>
Tue, 10 Dec 2024 02:46:59 +0000 (11:46 +0900)
Change-Id: I4e5b4378a3e953d2382ccb931a54a754c5368ab4
Signed-off-by: jmm <j0064423.lee@samsung.com>
13 files changed:
automated-tests/src/dali/utc-Dali-CustomActor.cpp
dali/internal/event/actors/actor-impl.cpp
dali/internal/event/actors/actor-impl.h
dali/internal/event/actors/actor-property-handler.cpp
dali/internal/event/actors/custom-actor-internal.cpp
dali/internal/event/actors/custom-actor-internal.h
dali/internal/update/manager/render-task-processor.cpp
dali/internal/update/manager/update-manager.cpp
dali/internal/update/manager/update-manager.h
dali/internal/update/nodes/node.cpp
dali/internal/update/nodes/node.h
dali/public-api/actors/custom-actor-impl.cpp
dali/public-api/actors/custom-actor-impl.h

index 6398dcfc189752137aaa0f4df47f25dad3978bf4..bcccf1e5952eaeed9ef9c22f61bacb0c7bce17e4 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2022 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2024 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.
@@ -29,6 +29,8 @@
 #include "dali-test-suite-utils/dali-test-suite-utils.h"
 #include "test-custom-actor.h"
 
+#include <mesh-builder.h>
+
 using namespace Dali;
 
 namespace Test
@@ -1716,7 +1718,6 @@ int UtcDaliCustomActorComponentPropertyConstraintsP(void)
 
 namespace Impl
 {
-
 class OffScreenCustomActor : public UnregisteredCustomActor
 {
 public:
@@ -1725,11 +1726,11 @@ public:
     Dali::Integration::Scene scene = Dali::Integration::Scene::Get(Self());
     if(scene)
     {
-      mScene                  = scene;
-      RenderTaskList taskList = scene.GetRenderTaskList();
-      mForwardRenderTask      = taskList.CreateTask();
-      mBackwardRenderTask     = taskList.CreateTask();
-      FrameBuffer forwardFrameBuffer = FrameBuffer::New(1, 1);
+      mScene                          = scene;
+      RenderTaskList taskList         = scene.GetRenderTaskList();
+      mForwardRenderTask              = taskList.CreateTask();
+      mBackwardRenderTask             = taskList.CreateTask();
+      FrameBuffer forwardFrameBuffer  = FrameBuffer::New(1, 1);
       FrameBuffer backwardFrameBuffer = FrameBuffer::New(1, 1);
 
       mForwardRenderTask.SetFrameBuffer(forwardFrameBuffer);
@@ -1839,15 +1840,15 @@ int UtcDaliCustomActorReordering(void)
    * G(Forward) - F(Backward) - E(Forward) - J(BACKWARD) - B(BACKWARD) - E(BACKWARD)
    */
 
-  Layer A_layer = Layer::New();
+  Layer                A_layer                = Layer::New();
   OffScreenCustomActor B_offScreenCustomActor = OffScreenCustomActor::New(OffScreenRenderable::Type::BACKWARD);
-  Layer C_layer = Layer::New();
-  Actor D_actor = Actor::New();
+  Layer                C_layer                = Layer::New();
+  Actor                D_actor                = Actor::New();
   OffScreenCustomActor E_offScreenCustomActor = OffScreenCustomActor::New(OffScreenRenderable::Type::BOTH);
   OffScreenCustomActor F_offScreenCustomActor = OffScreenCustomActor::New(OffScreenRenderable::Type::BACKWARD);
   OffScreenCustomActor G_offScreenCustomActor = OffScreenCustomActor::New(OffScreenRenderable::Type::FORWARD);
-  Actor H_actor = Actor::New();
-  Actor I_actor = Actor::New();
+  Actor                H_actor                = Actor::New();
+  Actor                I_actor                = Actor::New();
   OffScreenCustomActor J_offScreenCustomActor = OffScreenCustomActor::New(OffScreenRenderable::Type::BACKWARD);
 
   A_layer.Add(B_offScreenCustomActor);
@@ -1915,7 +1916,7 @@ int UtcDaliCustomActorReordering2(void)
    * C(Backward) - B(Backward)
    */
 
-  Layer A_layer = Layer::New();
+  Layer                A_layer                = Layer::New();
   OffScreenCustomActor B_offScreenCustomActor = OffScreenCustomActor::New(OffScreenRenderable::Type::BACKWARD);
   OffScreenCustomActor C_offScreenCustomActor = OffScreenCustomActor::New(OffScreenRenderable::Type::BACKWARD);
 
@@ -1972,4 +1973,39 @@ int UtcDaliCustomActorReordering2(void)
   DALI_TEST_CHECK(B_offScreenCustomActor.GetBackwardRenderTask().GetOrderIndex() < C_offScreenCustomActor.GetBackwardRenderTask().GetOrderIndex());
 
   END_TEST;
-}
\ No newline at end of file
+}
+
+int UtcDaliCustomActorImplSetRemoveCacheRenderer(void)
+{
+  TestApplication application;
+  DALI_TEST_EQUALS(application.GetScene().GetRenderTaskList().GetTaskCount(), 1, TEST_LOCATION);
+
+  DerivedCustomActor customActor = DerivedCustomActor::New();
+
+  Geometry geometry  = CreateQuadGeometry();
+  Shader   shader    = CreateShader();
+  Renderer renderer  = Renderer::New(geometry, shader);
+  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.RemoveRenderer(0u);
+  customActor.GetImplementation().SetCacheRenderer(renderer);
+
+  application.SendNotification();
+  application.Render();
+
+  customActor.GetImplementation().RemoveCacheRenderer();
+  customActor.GetImplementation().RemoveCacheRenderer();
+  application.SendNotification();
+  application.Render();
+
+  customActor.GetImplementation().SetCacheRenderer(renderer2);
+
+  tet_result(TET_PASS);
+  END_TEST;
+}
index 88e77414d876519f4c4c360c7398af913a4a78c1..f476f6bb5ed15ff10c2deeeb6a448dfa52e60318 100644 (file)
@@ -1133,6 +1133,37 @@ void Actor::RequestRenderTaskReorder()
   }
 }
 
+void Actor::SetCacheRenderer(Renderer& renderer)
+{
+  const SceneGraph::Node& node = GetNode();
+
+  if(mCacheRenderer)
+  {
+    if(mCacheRenderer == RendererPtr(&renderer))
+    {
+      return;
+    }
+    RemoveCacheRenderer();
+  }
+
+  if(mIsBlendEquationSet)
+  {
+    renderer.SetBlendEquation(mBlendEquation);
+  }
+  mCacheRenderer = RendererPtr(&renderer);
+  AttachCacheRendererMessage(GetEventThreadServices().GetUpdateManager(), node, renderer.GetRendererSceneObject());
+}
+
+void Actor::RemoveCacheRenderer()
+{
+  if(DALI_LIKELY(mCacheRenderer))
+  {
+    const SceneGraph::Node& node = GetNode();
+    DetachCacheRendererMessage(GetEventThreadServices(), node, mCacheRenderer->GetRendererSceneObject());
+    mCacheRenderer.Reset();
+  }
+}
+
 Actor::Actor(DerivedType derivedType, const SceneGraph::Node& node)
 : Object(&node),
   mParentImpl(*this),
@@ -1223,6 +1254,10 @@ Actor::~Actor()
       // Detach all renderers before delete container.
       mRenderers->RemoveAll(GetNode());
     }
+    if(mCacheRenderer)
+    {
+      RemoveCacheRenderer();
+    }
 
     // Root layer will destroy its node in its own destructor
     if(!mIsRoot)
@@ -1596,7 +1631,7 @@ void Actor::SetParent(ActorParent* parent, bool notify)
       // Instruct each actor to create a corresponding node in the scene graph
       ConnectToScene(parentActor->GetHierarchyDepth(), parentActor->GetLayer3DParentCount(), notify);
 
-      Actor* actor         = this;
+      Actor* actor = this;
       // OnScene should be checked, this actor can be removed during OnSceneConnection.
       emitInheritedVisible = OnScene() && mScene->IsVisible();
       while(emitInheritedVisible && actor)
index 99dcf9c7ec18ec89394b281aba4994978dcc503b..a48eadbfdb00606ed535da8abbc60254333de037 100644 (file)
@@ -1615,6 +1615,21 @@ public:
    */
   void RequestRenderTaskReorder();
 
+  // For offscreen rendering
+  /**
+   * @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();
+
 protected:
   enum DerivedType
   {
@@ -1997,14 +2012,15 @@ private:
   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
-  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
+  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
 
   // Signals
   Dali::Actor::TouchEventSignalType                 mInterceptTouchedSignal;
index 2815b29be6bae9aae8763515cda1546a6b3276a2..164022eeeef08c1d0b34c83857b73b3548118c19 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2023 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2024 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.
index 9321df13ebdac3ce424514a016e5d27dd7c04ad3..65afc68293af93d94833c2956751c42a4d7e7acd 100644 (file)
@@ -17,6 +17,8 @@
 
 // CLASS HEADER
 #include <dali/internal/event/actors/custom-actor-internal.h>
+
+// INTERNAL INCLUDES
 #include <dali/public-api/object/type-info.h>
 
 namespace Dali
index 969cb6955607223ec9022aa0e5eeb2026863d7c6..1ae54c908ca68c9f51c4fe32aa26c2bbefefd2f8 100644 (file)
@@ -2,7 +2,7 @@
 #define DALI_INTERNAL_CUSTOM_ACTOR_H
 
 /*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2024 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.
@@ -128,7 +128,7 @@ private:
     mImpl->OnSizeAnimation(animationHandle, targetSize);
   }
 
-  void GetOffScreenRenderTasks(std::vector<Dali::RenderTask>& tasks, bool isForward)
+  void GetOffScreenRenderTasks(std::vector<Dali::RenderTask>& tasks, bool isForward) override
   {
     mImpl->GetOffScreenRenderTasks(tasks, isForward);
   }
index 2d50db0dbb4824b22d62269581d2fd5cf7967135..6cb5573159bb78ca45a7568aeda07c6d8b869b0f 100644 (file)
@@ -114,8 +114,12 @@ void AddRenderablesForTask(BufferIndex updateBufferIndex,
     node.SetUpdated(true);
   }
 
+  RendererKey cacheRenderer                      = node.GetCacheRenderer();
+  const bool  isNodeExclusiveAtAnotherRenderTask = node.GetExclusiveRenderTaskCount() && !node.IsExclusiveRenderTask(&renderTask);
+
   // Check whether node is exclusive to a different render-task
-  if(node.GetExclusiveRenderTaskCount() && !node.IsExclusiveRenderTask(&renderTask))
+  // Check if node has pre-drawn cache to draw
+  if(isNodeExclusiveAtAnotherRenderTask && !cacheRenderer)
   {
     return;
   }
@@ -165,6 +169,13 @@ void AddRenderablesForTask(BufferIndex updateBufferIndex,
   node.SetClippingInformation(currentClippingId, clippingDepth, scissorDepth);
 
   RenderableContainer& target = DALI_LIKELY(inheritedDrawMode == DrawMode::NORMAL) ? layer->colorRenderables : layer->overlayRenderables;
+
+  if(isNodeExclusiveAtAnotherRenderTask && cacheRenderer)
+  {
+    target.PushBack(Renderable(&node, cacheRenderer));
+    return;
+  }
+
   for(uint32_t i = 0; i < count; ++i)
   {
     SceneGraph::RendererKey rendererKey = node.GetRendererAt(i);
index a7c5c31bb314547fa74e104867370879858b04e8..6926e64c9780fded132fe38b50c8fd87076ec78b 100644 (file)
@@ -846,6 +846,12 @@ void UpdateManager::AttachRenderer(Node* node, Renderer* renderer)
   mImpl->renderersAdded = true;
 }
 
+void UpdateManager::AttachCacheRenderer(Node* node, Renderer* renderer)
+{
+  node->SetCacheRenderer(Renderer::GetKey(renderer));
+  mImpl->renderersAdded = true;
+}
+
 void UpdateManager::SetPanGestureProcessor(PanGesture* panGestureProcessor)
 {
   DALI_ASSERT_DEBUG(NULL != panGestureProcessor);
index dc23eaf615261f6b82e99a8c68a7a2bfd28ab399..60207915efce9ac6f125a8dc05f61423e7e1d741 100644 (file)
@@ -358,6 +358,13 @@ public:
    */
   void AttachRenderer(Node* node, Renderer* renderer);
 
+  /**
+   * Attach cache renderer to node
+   * @param[in] node target
+   * @param[in] renderer to attach
+   */
+  void AttachCacheRenderer(Node* node, Renderer* renderer);
+
   // Gestures
 
   /**
@@ -1244,6 +1251,16 @@ inline void AttachRendererMessage(UpdateManager& manager, const Node& node, cons
   new(slot) LocalType(&manager, &UpdateManager::AttachRenderer, const_cast<Node*>(&node), const_cast<Renderer*>(&renderer));
 }
 
+inline void AttachCacheRendererMessage(UpdateManager& manager, const Node& node, const Renderer& renderer)
+{
+  using LocalType = MessageValue2<UpdateManager, Node*, Renderer*>;
+
+  // Reserve some memory inside the message queue
+  uint32_t* slot = manager.ReserveMessageSlot(sizeof(LocalType));
+  // Construct message in the message queue memory; note that delete should not be called on the return value
+  new(slot) LocalType(&manager, &UpdateManager::AttachCacheRenderer, const_cast<Node*>(&node), const_cast<Renderer*>(&renderer));
+}
+
 // The render thread can safely change the Shader
 inline void AddTextureSetMessage(UpdateManager& manager, OwnerPointer<TextureSet>& textureSet)
 {
index 6992402c64c7128d57331e06888cadcad8b30836..15bbd978d707370b621aef1229324e451803c5de 100644 (file)
@@ -262,6 +262,26 @@ void Node::RemoveRenderer(const RendererKey& renderer)
   }
 }
 
+void Node::SetCacheRenderer(const RendererKey& renderer)
+{
+  if(DALI_UNLIKELY(mCacheRenderer))
+  {
+    mCacheRenderer->DetachFromNodeDataProvider(*this);
+  }
+  SetUpdated(true);
+  mCacheRenderer = renderer;
+}
+
+void Node::RemoveCacheRenderer()
+{
+  if(DALI_LIKELY(mCacheRenderer))
+  {
+    mCacheRenderer->DetachFromNodeDataProvider(*this);
+    SetUpdated(true);
+    mCacheRenderer = RendererKey{};
+  }
+}
+
 NodePropertyFlags Node::GetDirtyFlags() const
 {
   // get initial dirty flags, they are reset ResetDefaultProperties, but setters may have made the node dirty already
index 8ad2dc98be1d6e80b245c0b6cdd0f39f47ae3fb1..c0a956d4edf5addfacaa654cdfa16afcd1813b16 100644 (file)
@@ -267,6 +267,25 @@ public:
     return static_cast<uint32_t>(mRenderers.Size());
   }
 
+  /**
+   * Set cache renderer which draws output of offscreen rendering
+   * Draws only when mOffScreenRendering is true
+   */
+  void SetCacheRenderer(const RendererKey& renderer);
+
+  /**
+   * Remove cache renderer
+   */
+  void RemoveCacheRenderer();
+
+  /**
+   * Get cache renderer
+   */
+  RendererKey GetCacheRenderer() const
+  {
+    return mCacheRenderer;
+  }
+
   // Containment methods
 
   /**
@@ -1105,7 +1124,8 @@ protected:
   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
+  RendererContainer mRenderers;     ///< Container of renderers; not owned
+  RendererKey       mCacheRenderer; ///< Result of offscreen rendering
 
   NodeContainer mChildren; ///< Container of children; not owned
 
@@ -1231,6 +1251,17 @@ inline void DetachRendererMessage(EventThreadServices& eventThreadServices, cons
   new(slot) LocalType(&node, &Node::RemoveRenderer, Renderer::GetKey(renderer));
 }
 
+inline void DetachCacheRendererMessage(EventThreadServices& eventThreadServices, const Node& node, const Renderer& renderer)
+{
+  using LocalType = Message<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(&node, &Node::RemoveCacheRenderer);
+}
+
 inline void SetDepthIndexMessage(EventThreadServices& eventThreadServices, const Node& node, uint32_t depthIndex)
 {
   using LocalType = MessageValue1<Node, uint32_t>;
index 12a1d1f0656e2a28cb9c79afe60b53f7989af718..5319deec0eaad5b1f08f41b28407a17de902933f 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2024 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.
@@ -20,6 +20,7 @@
 
 // INTERNAL INCLUDES
 #include <dali/internal/event/actors/custom-actor-internal.h>
+#include <dali/internal/event/rendering/renderer-impl.h>
 #include <dali/public-api/common/dali-common.h>
 
 namespace Dali
@@ -48,6 +49,16 @@ void CustomActorImpl::RequestRenderTaskReorder()
   mOwner->RequestRenderTaskReorder();
 }
 
+void CustomActorImpl::SetCacheRenderer(Renderer& renderer)
+{
+  mOwner->SetCacheRenderer(GetImplementation(renderer));
+}
+
+void CustomActorImpl::RemoveCacheRenderer()
+{
+  mOwner->RemoveCacheRenderer();
+}
+
 CustomActorImpl::CustomActorImpl(ActorFlags flags)
 : mOwner(nullptr),
   mFlags(flags)
index 21af81865ea3981687d6c423e9b5c53b8e9a6fd2..28501a568f3e076803f8259c60b1be56ddc6fba1 100644 (file)
@@ -2,7 +2,7 @@
 #define DALI_CUSTOM_ACTOR_IMPL_H
 
 /*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2024 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.
@@ -215,6 +215,20 @@ public:
    */
   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.
    *