Share partial update data info to RenderItem 75/318475/18
authorEunki, Hong <eunkiki.hong@samsung.com>
Fri, 17 Jan 2025 07:26:55 +0000 (16:26 +0900)
committerEunki Hong <eunkiki.hong@samsung.com>
Fri, 14 Feb 2025 10:47:45 +0000 (10:47 +0000)
Let we make RenderItem use Node's PartialUpdateData directly,
instead copy the matrix and etc.

It will reduce each item's memory, and memory copy time.

Change-Id: I42e12b24a6429734f7754db5880524b8bc4e4f32
Signed-off-by: Eunki, Hong <eunkiki.hong@samsung.com>
12 files changed:
dali/internal/render/common/render-algorithms.cpp
dali/internal/render/common/render-item.cpp
dali/internal/render/common/render-item.h
dali/internal/render/common/render-manager.cpp
dali/internal/render/renderers/render-renderer.cpp
dali/internal/render/renderers/render-renderer.h
dali/internal/update/common/scene-graph-scene.h
dali/internal/update/manager/render-instruction-processor.cpp
dali/internal/update/nodes/node.cpp
dali/internal/update/nodes/node.h
dali/internal/update/nodes/partial-rendering-data.h
dali/internal/update/rendering/scene-graph-visual-renderer.cpp

index 529598a59b324b1ceb4aadc98b1f43e34b0cb0f8..8fc3459fb30f8ce257a8ab35d4bb807155c85ae6 100644 (file)
@@ -457,7 +457,7 @@ inline void RenderAlgorithms::SetupScissorClipping(
       // This is a clipping node. We generate the AABB for this node and intersect it with the previous intersection further up the tree.
 
       // Get the AABB bounding box for the current render item.
-      const ClippingBox scissorBox(RenderItem::CalculateViewportSpaceAABB(item.mModelViewMatrix, Vector3::ZERO, item.mSize, mViewportRectangle.width, mViewportRectangle.height));
+      const ClippingBox scissorBox(RenderItem::CalculateViewportSpaceAABB(item.mModelViewMatrix, Vector3::ZERO, item.GetPartialRenderingDataNodeInfomations().size, mViewportRectangle.width, mViewportRectangle.height));
 
       // Get the AABB for the parent item that we must intersect with.
       const ClippingBox& parentBox(mScissorStack.back());
@@ -499,7 +499,7 @@ inline void RenderAlgorithms::SetupScissorClipping(
     {
       // store clipping box inside the render callback input structure
       auto& input       = item.mRenderer->GetRenderCallbackInput();
-      input.clippingBox = ClippingBox(RenderItem::CalculateViewportSpaceAABB(item.mModelViewMatrix, Vector3::ZERO, item.mSize, mViewportRectangle.width, mViewportRectangle.height));
+      input.clippingBox = ClippingBox(RenderItem::CalculateViewportSpaceAABB(item.mModelViewMatrix, Vector3::ZERO, item.GetPartialRenderingDataNodeInfomations().size, mViewportRectangle.width, mViewportRectangle.height));
     }
   }
 }
@@ -668,6 +668,9 @@ inline void RenderAlgorithms::ProcessRenderList(const RenderList&
   // Prepare Render::Renderer Render for this secondary command buffer.
   Renderer::PrepareCommandBuffer();
 
+  const SceneGraph::Node* lastRenderedNode = nullptr;
+  Vector3                 nodeScale        = Vector3::ONE;
+
   // Modify by the clip matrix if necessary (transforms from GL clip space to alternative clip space)
   Matrix clippedProjectionMatrix(projectionMatrix);
   if(mGraphicsController.HasClipMatrix())
@@ -680,11 +683,14 @@ inline void RenderAlgorithms::ProcessRenderList(const RenderList&
   {
     const RenderItem& item = renderList.GetItem(index);
 
+    // Get NodeInformation as const l-value, to reduce memory access operations.
+    const SceneGraph::PartialRenderingData::NodeInfomations& nodeInfo = item.GetPartialRenderingDataNodeInfomations();
+
     // Discard renderers outside the root clipping rect
     bool skip = true;
     if(!rootClippingRect.IsEmpty())
     {
-      Vector4 updateArea = item.mRenderer ? item.mRenderer->GetVisualTransformedUpdateArea(bufferIndex, item.mUpdateArea) : item.mUpdateArea;
+      Vector4 updateArea = item.mRenderer ? item.mRenderer->GetVisualTransformedUpdateArea(bufferIndex, nodeInfo.updatedPositionSize) : nodeInfo.updatedPositionSize;
       auto    rect       = RenderItem::CalculateViewportSpaceAABB(item.mModelViewMatrix, Vector3(updateArea.x, updateArea.y, 0.0f), Vector3(updateArea.z, updateArea.w, 0.0f), mViewportRectangle.width, mViewportRectangle.height);
 
       if(rect.Intersect(rootClippingRect))
@@ -722,11 +728,18 @@ inline void RenderAlgorithms::ProcessRenderList(const RenderList&
       // It is similar to the multi-pass rendering.
       if(!skip)
       {
+        if(lastRenderedNode != item.mNode)
+        {
+          lastRenderedNode = item.mNode;
+
+          nodeScale = nodeInfo.modelMatrix.GetScale();
+        }
+
         auto const MAX_QUEUE = item.mRenderer->GetDrawCommands().empty() ? 1 : DevelRenderer::RENDER_QUEUE_MAX;
         for(auto queue = 0u; queue < MAX_QUEUE; ++queue)
         {
           // Render the item. It will write into the command buffer everything it has to render
-          item.mRenderer->Render(secondaryCommandBuffer, bufferIndex, *item.mNode, item.mModelMatrix, item.mModelViewMatrix, viewMatrix, clippedProjectionMatrix, item.mScale, item.mSize, !item.mIsOpaque, instruction, renderTarget, queue);
+          item.mRenderer->Render(secondaryCommandBuffer, bufferIndex, *item.mNode, nodeInfo.modelMatrix, item.mModelViewMatrix, viewMatrix, clippedProjectionMatrix, nodeInfo.worldColor, nodeScale, nodeInfo.size, !item.mIsOpaque, instruction, renderTarget, queue);
         }
       }
     }
@@ -753,8 +766,7 @@ void RenderAlgorithms::ProcessRenderInstruction(const RenderInstruction&
                                                 Graphics::RenderTarget*             renderTarget,
                                                 Graphics::CommandBuffer*            commandBuffer)
 {
-  DALI_TRACE_BEGIN_WITH_MESSAGE_GENERATOR(gTraceFilter, "DALI_RENDER_INSTRUCTION_PROCESS", [&](std::ostringstream& oss)
-                                          { oss << "[" << instruction.RenderListCount() << "]"; });
+  DALI_TRACE_BEGIN_WITH_MESSAGE_GENERATOR(gTraceFilter, "DALI_RENDER_INSTRUCTION_PROCESS", [&](std::ostringstream& oss) { oss << "[" << instruction.RenderListCount() << "]"; });
 
   DALI_PRINT_RENDER_INSTRUCTION(instruction, bufferIndex);
 
index 4a09ea1aa2ce13bf0072d6830d09bd0b66601129..f073717811ba9511f0ed36c1f52b291de07dcb8e 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * 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.
@@ -58,10 +58,7 @@ void RenderItem::ResetMemoryPool()
 }
 
 RenderItem::RenderItem()
-: mModelMatrix(false),
-  mModelViewMatrix(false),
-  mScale(),
-  mSize(),
+: mModelViewMatrix(false),
   mRenderer{},
   mNode(nullptr),
   mTextureSet(nullptr),
@@ -208,7 +205,7 @@ bool RenderItem::UsesDepthBuffer(bool depthTestEnabled)
   return enableDepthTest || enableDepthWrite;
 }
 
-bool RenderItem::UsesStencilBuffer()
+bool RenderItem::UsesStencilBuffer() const
 {
   RenderMode::Type renderMode  = RenderMode::AUTO;
   bool             usesStencil = false;
index b109f9d590cc6435411aff610b183651d7e46d37..d4de1efa46e66ff406b25b8d65533bca0b2f7edc 100644 (file)
@@ -2,7 +2,7 @@
 #define DALI_INTERNAL_SCENE_GRAPH_RENDER_ITEM_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.
@@ -130,7 +130,16 @@ struct RenderItem
    * @brief Returns true if this node/renderer uses the stencil buffer (read or write)
    * @return true if this node/renderer pair uses the stencil buffer
    */
-  bool UsesStencilBuffer();
+  bool UsesStencilBuffer() const;
+
+  /**
+   * @brief Get PartialRenderingData::NodeInfomations from node
+   * @return Node infomations from node's partial rendering data.
+   */
+  const PartialRenderingData::NodeInfomations& GetPartialRenderingDataNodeInfomations() const
+  {
+    return mNode->GetPartialRenderingData().mNodeInfomations;
+  }
 
   /**
    * Overriden delete operator.
@@ -139,17 +148,14 @@ struct RenderItem
    */
   void operator delete(void* ptr);
 
-  Matrix              mModelMatrix;
   Matrix              mModelViewMatrix;
-  Vector3             mScale;
-  Vector3             mSize;
-  Vector4             mUpdateArea; ///< Update area hint is provided for damaged area calculation. (x, y, width, height)
   Render::RendererKey mRenderer;
-  Node*               mNode;
+  const Node*         mNode;
   const void*         mTextureSet; ///< Used for sorting only
   int                 mDepthIndex;
-  bool                mIsOpaque : 1;
-  bool                mIsUpdated : 1;
+
+  bool mIsOpaque : 1;
+  bool mIsUpdated : 1;
 
   /**
    * Get the capacity of the global pool.
@@ -168,7 +174,7 @@ private:
   RenderItem();
 
   // RenderItems should not be copied as they are heavy
-  RenderItem(const RenderItem& item)            = delete;
+  RenderItem(const RenderItem& item) = delete;
   RenderItem& operator=(const RenderItem& item) = delete;
 };
 
index 9c147538cbce3f04d459254b8f5e1c83d2e6b7c5..0708d68982e5c12a6ec8e2a490d6d25d04519819 100644 (file)
@@ -128,7 +128,7 @@ inline Graphics::Rect2D RecalculateScissorArea(const Graphics::Rect2D& scissorAr
   return newScissorArea;
 }
 
-inline Rect<int32_t> CalculateUpdateArea(RenderItem& item, BufferIndex renderBufferIndex, const Rect<int32_t>& viewportRect)
+inline Rect<int32_t> CalculateUpdateArea(const RenderItem& item, const Vector4& updatedPositionSize, BufferIndex renderBufferIndex, const Rect<int32_t>& viewportRect)
 {
   Vector4 updateArea;
   if(item.mNode && item.mNode->IsTextureUpdateAreaUsed() && item.mRenderer)
@@ -137,7 +137,7 @@ inline Rect<int32_t> CalculateUpdateArea(RenderItem& item, BufferIndex renderBuf
   }
   else
   {
-    updateArea = item.mRenderer ? item.mRenderer->GetVisualTransformedUpdateArea(renderBufferIndex, item.mUpdateArea) : item.mUpdateArea;
+    updateArea = item.mRenderer ? item.mRenderer->GetVisualTransformedUpdateArea(renderBufferIndex, updatedPositionSize) : updatedPositionSize;
   }
 
   return RenderItem::CalculateViewportSpaceAABB(item.mModelViewMatrix, Vector3(updateArea.x, updateArea.y, 0.0f), Vector3(updateArea.z, updateArea.w, 0.0f), viewportRect.width, viewportRect.height);
@@ -841,8 +841,12 @@ bool RenderManager::PreRender(Integration::Scene& scene, std::vector<Rect<int>>&
             for(uint32_t listIndex = 0u; listIndex < listCount; ++listIndex)
             {
               RenderItem& item = renderList->GetItem(listIndex);
+
+              // Get NodeInformation as const l-value, to reduce memory access operations.
+              const SceneGraph::PartialRenderingData::NodeInfomations& nodeInfo = item.GetPartialRenderingDataNodeInfomations();
+
               // If the item does 3D transformation, make full update
-              if(item.mUpdateArea == Vector4::ZERO)
+              if(nodeInfo.updatedPositionSize == Vector4::ZERO)
               {
                 cleanDamagedRect = true;
 
@@ -870,9 +874,9 @@ bool RenderManager::PreRender(Integration::Scene& scene, std::vector<Rect<int>>&
                  (item.mNode &&
                   (item.mNode->Updated() || (item.mRenderer && item.mRenderer->Updated()))))
               {
-                item.mIsUpdated = false;
+                item.mIsUpdated = false; /// DevNote : Reset flag here, since RenderItem could be reused by renderList.ReuseCachedItems().
 
-                rect = CalculateUpdateArea(item, mImpl->renderBufferIndex, viewportRect);
+                rect = CalculateUpdateArea(item, nodeInfo.updatedPositionSize, mImpl->renderBufferIndex, viewportRect);
                 if(rect.IsValid() && rect.Intersect(viewportRect) && !rect.IsEmpty())
                 {
                   AlignDamagedRect(rect);
@@ -911,7 +915,7 @@ bool RenderManager::PreRender(Integration::Scene& scene, std::vector<Rect<int>>&
                 else
                 {
                   // The item is not in the list for some reason. Add the current rect!
-                  rect = CalculateUpdateArea(item, mImpl->renderBufferIndex, viewportRect);
+                  rect = CalculateUpdateArea(item, nodeInfo.updatedPositionSize, mImpl->renderBufferIndex, viewportRect);
                   if(rect.IsValid() && rect.Intersect(viewportRect) && !rect.IsEmpty())
                   {
                     AlignDamagedRect(rect);
@@ -1029,11 +1033,11 @@ void RenderManager::RenderScene(Integration::RenderStatus& status, Integration::
         bool        usesStencilBuffer = false;
         for(auto k = 0u; k < renderList->Count(); ++k)
         {
-          auto& item = renderList->GetItem(k);
-          usesStencilBuffer |= item.UsesStencilBuffer();
+          auto& item        = renderList->GetItem(k);
+          usesStencilBuffer = usesStencilBuffer || item.UsesStencilBuffer();
           if(item.mRenderer && item.mRenderer->NeedsProgram())
           {
-            usesDepthBuffer |= item.UsesDepthBuffer(autoDepthTestMode);
+            usesDepthBuffer = usesDepthBuffer || item.UsesDepthBuffer(autoDepthTestMode);
 
             // Prepare and store used programs for further processing
             auto program = item.mRenderer->PrepareProgram(instruction);
index eb4b44b60ecd1067ff7e23f6c6ba72166ac871a3..d28c51c40c9b03df9a9fbffeed4f98188b527122 100644 (file)
@@ -486,6 +486,7 @@ bool Renderer::Render(Graphics::CommandBuffer&                             comma
                       const Matrix&                                        modelViewMatrix,
                       const Matrix&                                        viewMatrix,
                       const Matrix&                                        projectionMatrix,
+                      const Vector4&                                       worldColor,
                       const Vector3&                                       scale,
                       const Vector3&                                       size,
                       bool                                                 blend,
@@ -597,7 +598,7 @@ bool Renderer::Render(Graphics::CommandBuffer&                             comma
     if(queueIndex == 0)
     {
       std::size_t nodeIndex = BuildUniformIndexMap(bufferIndex, node, *program);
-      WriteUniformBuffer(bufferIndex, commandBuffer, program, instruction, node, modelMatrix, modelViewMatrix, viewMatrix, projectionMatrix, scale, size, nodeIndex);
+      WriteUniformBuffer(bufferIndex, commandBuffer, program, instruction, modelMatrix, modelViewMatrix, viewMatrix, projectionMatrix, worldColor, scale, size, nodeIndex);
     }
     // @todo We should detect this case much earlier to prevent unnecessary work
     // Reuse latest bound vertex attributes location, or Bind buffers to attribute locations.
@@ -738,11 +739,11 @@ void Renderer::WriteUniformBuffer(
   Graphics::CommandBuffer&             commandBuffer,
   Program*                             program,
   const SceneGraph::RenderInstruction& instruction,
-  const SceneGraph::NodeDataProvider&  node,
   const Matrix&                        modelMatrix,
   const Matrix&                        modelViewMatrix,
   const Matrix&                        viewMatrix,
   const Matrix&                        projectionMatrix,
+  const Vector4&                       worldColor,
   const Vector3&                       scale,
   const Vector3&                       size,
   std::size_t                          nodeIndex)
@@ -805,9 +806,8 @@ void Renderer::WriteUniformBuffer(
 
     WriteDefaultUniformV2(program->GetDefaultUniform(Program::DefaultUniformIndex::SCALE), uboViews, scale);
 
-    const Vector4& color      = node.GetRenderColor(bufferIndex);              ///< Actor's original color
     const Vector4& mixColor   = mRenderDataProvider->GetMixColor(bufferIndex); ///< Renderer's mix color
-    Vector4        finalColor = color * mixColor;                              ///< Applied renderer's mix color
+    Vector4        finalColor = worldColor * mixColor;                         ///< Applied Actor's original color to renderer's mix color
     if(mPremultipliedAlphaEnabled)
     {
       const float alpha = finalColor.a;
@@ -816,7 +816,7 @@ void Renderer::WriteUniformBuffer(
       finalColor.b *= alpha;
     }
     WriteDefaultUniformV2(program->GetDefaultUniform(Program::DefaultUniformIndex::COLOR), uboViews, finalColor);
-    WriteDefaultUniformV2(program->GetDefaultUniform(Program::DefaultUniformIndex::ACTOR_COLOR), uboViews, color);
+    WriteDefaultUniformV2(program->GetDefaultUniform(Program::DefaultUniformIndex::ACTOR_COLOR), uboViews, worldColor);
 
     // Write uniforms from the uniform map
     FillUniformBuffer(*program, instruction, uboViews, bufferIndex, nodeIndex);
index 3f638a3b6ed74985b36422f2afc6a1f73adf2df9..d793b87a108ec1a29e44061724fe144294e97245 100644 (file)
@@ -2,7 +2,7 @@
 #define DALI_INTERNAL_RENDER_RENDERER_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.
@@ -408,6 +408,7 @@ public:
    * @param[in] modelViewMatrix The model-view matrix.
    * @param[in] viewMatrix The view matrix.
    * @param[in] projectionMatrix The projection matrix.
+   * @param[in] worldColor The world color of the node.
    * @param[in] scale Scale factor of the render item
    * @param[in] size Size of the render item
    * @param[in] blend If true, blending is enabled
@@ -424,6 +425,7 @@ public:
               const Matrix&                                        modelViewMatrix,
               const Matrix&                                        viewMatrix,
               const Matrix&                                        projectionMatrix,
+              const Vector4&                                       worldColor,
               const Vector3&                                       scale,
               const Vector3&                                       size,
               bool                                                 blend,
@@ -599,6 +601,7 @@ private:
    * @param[in] modelViewMatrix The model-view matrix.
    * @param[in] viewMatrix The view matrix.
    * @param[in] projectionMatrix The projection matrix.
+   * @param[in] worldColor The world color of the node.
    * @param[in] scale Scale factor of the render item
    * @param[in] size Size of the render item
    * @param[in] blend If true, blending is enabled
@@ -609,11 +612,11 @@ private:
                           Graphics::CommandBuffer&             commandBuffer,
                           Program*                             program,
                           const SceneGraph::RenderInstruction& instruction,
-                          const SceneGraph::NodeDataProvider&  node,
                           const Matrix&                        modelMatrix,
                           const Matrix&                        modelViewMatrix,
                           const Matrix&                        viewMatrix,
                           const Matrix&                        projectionMatrix,
+                          const Vector4&                       worldColor,
                           const Vector3&                       scale,
                           const Vector3&                       size,
                           std::size_t                          nodeIndex);
index 1f5dae9d63b9588891fa6229e54f8135c59b5772..b66c2cdbc8466fb01d751607ff10a23273394614 100644 (file)
@@ -48,7 +48,7 @@ class Node;
 
 struct DirtyRectKey
 {
-  DirtyRectKey(Node* node, Render::RendererKey renderer)
+  DirtyRectKey(const Node* node, Render::RendererKey renderer)
   : node(node),
     renderer(renderer)
   {
@@ -91,7 +91,7 @@ struct DirtyRectKey
   };
 #endif
 
-  Node*               node{nullptr};
+  const Node*         node{nullptr};
   Render::RendererKey renderer{};
 };
 
index 45c2c9cebe5f0d9dd03fdf77a4198e5d03ca2f40..16c1625aabec9a6120ab8d96738082cd14ec2701 100644 (file)
@@ -143,44 +143,6 @@ bool CompareItems3DWithClipping(const RenderInstructionProcessor::SortAttributes
   return lhs.renderItem->mNode->mClippingSortModifier < rhs.renderItem->mNode->mClippingSortModifier;
 }
 
-/**
- * Set the update area of the node
- * @param[in] node The node of the renderer
- * @param[in] isLayer3d Whether we are processing a 3D layer or not
- * @param[in,out] nodeWorldMatrix The world matrix of the node
- * @param[in,out] nodeSize The size of the node
- * @param[in,out] nodeUpdateArea The update area of the node
- *
- * @return True if node use it's own UpdateAreaHint, or z transform occured. False if we use nodeUpdateArea equal with Vector4(0, 0, nodeSize.width, nodeSize.height).
- */
-inline bool SetNodeUpdateArea(Node* node, bool isLayer3d, Matrix& nodeWorldMatrix, Vector3& nodeSize, Vector4& nodeUpdateArea)
-{
-  node->GetWorldMatrixAndSize(nodeWorldMatrix, nodeSize);
-
-  if(node->GetUpdateAreaHint() == Vector4::ZERO)
-  {
-    if(isLayer3d)
-    {
-      return true;
-    }
-    // RenderItem::CalculateViewportSpaceAABB cannot cope with z transform
-    // I don't use item.mModelMatrix.GetTransformComponents() for z transform, would be too slow
-    Vector3 zaxis = nodeWorldMatrix.GetZAxis();
-    if(EqualsZero(zaxis.x) && EqualsZero(zaxis.y))
-    {
-      nodeUpdateArea = Vector4(0.0f, 0.0f, nodeSize.width, nodeSize.height);
-      return false;
-    }
-    // Keep nodeUpdateArea as Vector4::ZERO, and return true.
-    return true;
-  }
-  else
-  {
-    nodeUpdateArea = node->GetUpdateAreaHint();
-    return true;
-  }
-}
-
 /**
  * Add a renderer to the list
  * @param updateBufferIndex to read the model matrix from
@@ -209,15 +171,15 @@ inline void AddRendererToRenderList(BufferIndex               updateBufferIndex,
                                     bool                      cullingEnabled,
                                     Node*                     stopperNode)
 {
-  bool    inside(true);
-  Node*   node = renderable.mNode;
-  Matrix  nodeWorldMatrix(false);
-  Vector3 nodeScale;
-  Vector3 nodeSize;
-  Vector4 nodeUpdateArea;
-  bool    nodeUpdateAreaSet(false);
-  Matrix  nodeModelViewMatrix(false);
-  bool    nodeModelViewMatrixSet(false);
+  bool  inside(true);
+  Node* node = renderable.mNode;
+
+  bool nodePartialRenderingDataUpdateChecked(false);
+
+  Matrix nodeModelViewMatrix(false);
+  bool   nodeModelViewMatrixSet(false);
+
+  auto& nodePartialRenderingData = node->GetPartialRenderingData();
 
   const bool rendererExist(renderable.mRenderer);
 
@@ -246,16 +208,18 @@ inline void AddRendererToRenderList(BufferIndex               updateBufferIndex,
 
     if(inside && !isLayer3d && viewportSet)
     {
-      SetNodeUpdateArea(node, isLayer3d, nodeWorldMatrix, nodeSize, nodeUpdateArea);
-      nodeUpdateAreaSet = true;
+      node->UpdatePartialRenderingData(updateBufferIndex, isLayer3d);
+
+      const Vector4& nodeUpdateArea = nodePartialRenderingData.mNodeInfomations.updatedPositionSize;
+      const Vector3& nodeScale      = nodePartialRenderingData.mNodeInfomations.modelMatrix.GetScale();
 
-      nodeScale = nodeWorldMatrix.GetScale();
+      nodePartialRenderingDataUpdateChecked = true;
 
       const Vector3& size = Vector3(nodeUpdateArea.z, nodeUpdateArea.w, 0.0f) * nodeScale;
 
       if(size.LengthSquared() > Math::MACHINE_EPSILON_1000)
       {
-        MatrixUtils::MultiplyTransformMatrix(nodeModelViewMatrix, nodeWorldMatrix, viewMatrix);
+        MatrixUtils::MultiplyTransformMatrix(nodeModelViewMatrix, nodePartialRenderingData.mNodeInfomations.modelMatrix, viewMatrix);
         nodeModelViewMatrixSet = true;
 
         // Assume actors are at z=0, compute AABB in view space & test rect intersection
@@ -267,7 +231,8 @@ inline void AddRendererToRenderList(BufferIndex               updateBufferIndex,
         //  - If then, It must use math calculate like tan(fov) internally. So, we might need calculate it only one times, and cache.
         ClippingBox boundingBox = RenderItem::CalculateTransformSpaceAABB(nodeModelViewMatrix, Vector3(nodeUpdateArea.x, nodeUpdateArea.y, 0.0f), Vector3(nodeUpdateArea.z, nodeUpdateArea.w, 0.0f));
         ClippingBox clippingBox = camera.GetOrthographicClippingBox(updateBufferIndex);
-        inside                  = clippingBox.Intersects(boundingBox);
+
+        inside = clippingBox.Intersects(boundingBox);
       }
     }
     /*
@@ -299,7 +264,7 @@ inline void AddRendererToRenderList(BufferIndex               updateBufferIndex,
       // Get the next free RenderItem.
       RenderItem& item = renderList.GetNextFreeItem();
 
-      item.mNode       = node;
+      item.mNode       = static_cast<const Node*>(node);
       item.mIsOpaque   = isOpaque;
       item.mDepthIndex = isLayer3d ? 0 : node->GetDepthIndex();
 
@@ -316,37 +281,19 @@ inline void AddRendererToRenderList(BufferIndex               updateBufferIndex,
 
       item.mIsUpdated = (viewMatrixChanged || isLayer3d);
 
-      if(!nodeUpdateAreaSet)
+      if(!nodePartialRenderingDataUpdateChecked)
       {
-        SetNodeUpdateArea(node, isLayer3d, nodeWorldMatrix, nodeSize, nodeUpdateArea);
-        nodeScale = nodeWorldMatrix.GetScale();
+        node->UpdatePartialRenderingData(updateBufferIndex, isLayer3d);
       }
 
       if(!nodeModelViewMatrixSet)
       {
-        MatrixUtils::MultiplyTransformMatrix(nodeModelViewMatrix, nodeWorldMatrix, viewMatrix);
+        MatrixUtils::MultiplyTransformMatrix(nodeModelViewMatrix, nodePartialRenderingData.mNodeInfomations.modelMatrix, viewMatrix);
       }
 
-      item.mScale           = nodeScale;
-      item.mSize            = nodeSize;
-      item.mUpdateArea      = nodeUpdateArea;
-      item.mModelMatrix     = std::move(nodeWorldMatrix);
       item.mModelViewMatrix = std::move(nodeModelViewMatrix);
 
-      auto& nodePartialRenderingData = node->GetPartialRenderingData();
-
-      if(nodePartialRenderingData.mUpdateDecay == PartialRenderingData::Decay::UPDATED_CURRENT_FRAME)
-      {
-        item.mIsUpdated = nodePartialRenderingData.mUpdated;
-      }
-      else
-      {
-        // Update current node's partial update data as latest.
-        if(nodePartialRenderingData.UpdateNodeInfomations(item.mModelMatrix, node->GetWorldColor(updateBufferIndex), item.mUpdateArea, item.mSize))
-        {
-          item.mIsUpdated = true;
-        }
-      }
+      item.mIsUpdated = item.mIsUpdated || nodePartialRenderingData.mUpdated;
     }
 
     node->SetCulled(updateBufferIndex, false);
index 15bbd978d707370b621aef1229324e451803c5de..e183746945c9edd6ba26737cf4ecae93efcff920 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * 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.
@@ -115,6 +115,7 @@ Node::Node()
   mPositionUsesAnchorPoint(true),
   mTransparent(false),
   mUpdateAreaChanged(false),
+  mUpdateAreaUseSize(true),
   mUseTextureUpdateArea(false)
 {
 #ifdef DEBUG_ENABLED
@@ -364,6 +365,57 @@ uint32_t Node::GetMemoryPoolCapacity()
   return GetNodeMemoryPool().GetCapacity();
 }
 
+void Node::UpdatePartialRenderingData(BufferIndex updateBufferIndex, bool isLayer3d)
+{
+  if(mPartialRenderingData.mUpdateDecay == PartialRenderingData::Decay::UPDATED_CURRENT_FRAME)
+  {
+    // Fast-out if we're already updated this frame
+    return;
+  }
+
+  if(Updated())
+  {
+    // If the node was updated, then mark the partial rendering data as expired
+    // So we can skip data comparision.
+    mPartialRenderingData.MakeExpired();
+  }
+
+  const Vector4& worldColor = GetWorldColor(updateBufferIndex);
+
+  // TODO : Can't we get modelMatrix and size as const l-value at onces?
+  const auto&    transformId = mTransformManagerData.Id();
+  const Matrix&  modelMatrix = transformId == INVALID_TRANSFORM_ID ? Matrix::IDENTITY : mWorldMatrix.Get(0);
+  const Vector3& size        = transformId == INVALID_TRANSFORM_ID ? Vector3::ZERO : mSize.Get(0);
+
+  const Vector4& updatedPositionSize = CalculateNodeUpdateArea(isLayer3d, modelMatrix, size);
+
+  mPartialRenderingData.UpdateNodeInfomations(modelMatrix, worldColor, updatedPositionSize, size);
+}
+
+Vector4 Node::CalculateNodeUpdateArea(bool isLayer3d, const Matrix& nodeWorldMatrix, const Vector3& nodeSize) const
+{
+  if(DALI_LIKELY(mUpdateAreaUseSize))
+  {
+    if(isLayer3d)
+    {
+      return Vector4::ZERO;
+    }
+    // RenderItem::CalculateViewportSpaceAABB cannot cope with z transform
+    // I don't use item.mModelMatrix.GetTransformComponents() for z transform, would be too slow
+    // Instead, use [8] and [9] of world matrix, which are z-axis's x and z-axis's y value.
+    if(EqualsZero(nodeWorldMatrix.AsFloat()[8]) && EqualsZero(nodeWorldMatrix.AsFloat()[9]))
+    {
+      return Vector4(0.0f, 0.0f, nodeSize.width, nodeSize.height);
+    }
+    // Keep nodeUpdateArea as Vector4::ZERO.
+    return Vector4::ZERO;
+  }
+  else
+  {
+    return GetUpdateAreaHint();
+  }
+}
+
 } // namespace SceneGraph
 
 } // namespace Internal
index c0a956d4edf5addfacaa654cdfa16afcd1813b16..9fe8399c531bfd9c39e816c972767a64e43231b6 100644 (file)
@@ -2,7 +2,7 @@
 #define DALI_INTERNAL_SCENE_GRAPH_NODE_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.
@@ -717,6 +717,8 @@ public:
       mUpdateAreaHint    = updateAreaHint;
       mUpdateAreaChanged = true;
     }
+
+    mUpdateAreaUseSize = (mUpdateAreaHint == Vector4::ZERO);
     mDirtyFlags |= NodePropertyFlags::TRANSFORM;
   }
 
@@ -997,6 +999,11 @@ public:
    */
   static uint32_t GetMemoryPoolCapacity();
 
+  /**
+   * @brief Update partial rendering data from the latest node infomations.
+   */
+  void UpdatePartialRenderingData(BufferIndex bufferIndex, bool isLayer3d);
+
   /**
    * @brief Returns partial rendering data associated with the node.
    * @return The partial rendering data
@@ -1006,6 +1013,15 @@ public:
     return mPartialRenderingData;
   }
 
+  /**
+   * @brief Returns partial rendering data associated with the node.
+   * @return The partial rendering data
+   */
+  const PartialRenderingData& GetPartialRenderingData() const
+  {
+    return mPartialRenderingData;
+  }
+
 public:
   /**
    * @copydoc Dali::Internal::SceneGraph::PropertyOwner::IsAnimationPossible
@@ -1080,6 +1096,17 @@ private:
    */
   void RecursiveDisconnectFromSceneGraph(BufferIndex updateBufferIndex);
 
+  /**
+   * @brief Calculates the update area of the node. Or Vector4::ZERO if partial update area is not 2D scale.
+   * @param[in] isLayer3d Whether we are processing a 3D layer or not
+   * @param[in] nodeWorldMatrix The world matrix of the node
+   * @param[in] nodeSize The size of the node
+   *
+   * @return It's own UpdateAreaHint, or if we use nodeUpdateArea equal with Vector4(0, 0, nodeSize.width, nodeSize.height),
+   *         or Vector4::ZERO if z transform occured.
+   */
+  Vector4 CalculateNodeUpdateArea(bool isLayer3d, const Matrix& nodeWorldMatrix, const Vector3& nodeSize) const;
+
 public: // Default properties
   // Define a base offset for the following wrappers. The wrapper macros calculate offsets from the previous
   // element such that each wrapper type generates a compile time offset to the transform manager data.
@@ -1144,6 +1171,7 @@ protected:
   bool               mPositionUsesAnchorPoint : 1; ///< True if the node should use the anchor-point when calculating the position
   bool               mTransparent : 1;             ///< True if this node is transparent. This value do not affect children.
   bool               mUpdateAreaChanged : 1;       ///< True if the update area of the node is changed.
+  bool               mUpdateAreaUseSize : 1;       ///< True if the update area of the node is same as node size.
   bool               mUseTextureUpdateArea : 1;    ///< Whether the actor uses the update area of the texture instead of its own.
 
   // Changes scope, should be at end of class
index 6eb4c87fff2cd9fca4277aa87866d9cf837234e8..2412f73aabf7bfe08cf359e6238d87ffee905543 100644 (file)
@@ -29,6 +29,71 @@ namespace Dali::Internal::SceneGraph
  */
 struct PartialRenderingData
 {
+  struct NodeInfomations
+  {
+    Matrix  modelMatrix{};         /// Model matrix
+    Vector4 worldColor{};          /// World Color
+    Vector4 updatedPositionSize{}; /// Updated position/size (x, y, width, height)
+    Vector3 size{};                /// Size
+
+    mutable size_t hash{0u}; /// Last frame's hash
+
+    static size_t CalculateHash(const Vector4& worldColor, const Vector4& updatedPositionSize, const Vector3& size, const Matrix& matrix)
+    {
+      size_t hash = Dali::Internal::HashUtils::INITIAL_HASH_VALUE;
+      Dali::Internal::HashUtils::HashRawBuffer<float>(worldColor.AsFloat(), 4, hash);
+      Dali::Internal::HashUtils::HashRawBuffer<float>(updatedPositionSize.AsFloat(), 4, hash);
+      Dali::Internal::HashUtils::HashRawBuffer<float>(size.AsFloat(), 3, hash);
+      Dali::Internal::HashUtils::HashRawBuffer<float>(matrix.AsFloat(), 16, hash);
+      return hash;
+    }
+
+    size_t GetHash() const
+    {
+      if(hash == 0u)
+      {
+        hash = CalculateHash(worldColor, updatedPositionSize, size, modelMatrix);
+      }
+      return hash;
+    }
+
+  public:
+    NodeInfomations() = default; // Default constructor
+
+    NodeInfomations(const Matrix& modelMatrix, const Vector4& worldColor, const Vector4& updatedPositionSize, const Vector3& size, size_t hash = 0u)
+    : modelMatrix(modelMatrix),
+      worldColor(worldColor),
+      updatedPositionSize(updatedPositionSize),
+      size(size),
+      hash(hash)
+    {
+    }
+    NodeInfomations(NodeInfomations&& rhs)
+    {
+      (*this) = std::move(rhs);
+    }
+
+    NodeInfomations& operator=(NodeInfomations&& rhs)
+    {
+      if(this != &rhs)
+      {
+        modelMatrix         = std::move(rhs.modelMatrix);
+        worldColor          = std::move(rhs.worldColor);
+        updatedPositionSize = std::move(rhs.updatedPositionSize);
+        size                = std::move(rhs.size);
+
+        hash     = rhs.hash;
+        rhs.hash = 0u;
+      }
+      return *this;
+    }
+
+  private:
+    // Let we don't allow to copy the matrix values.
+    NodeInfomations(const NodeInfomations&) = delete;
+    NodeInfomations& operator=(const NodeInfomations&) = delete;
+  } mNodeInfomations;
+
   bool mVisible : 1; /// Visible state. It is depends on node's visibility (Not hashed)
   bool mUpdated : 1; /// IsUpdated return true at this frame. Will be reset at UpdateNodes time. (Not hashed)
 
@@ -62,37 +127,27 @@ struct PartialRenderingData
     {
       mUpdated = true;
 
-      mNodeInfomations = {modelMatrix, worldColor, updatedPositionSize, size, 0u, 0u};
+      mNodeInfomations = NodeInfomations(modelMatrix, worldColor, updatedPositionSize, size, 0u);
     }
     else
     {
-      mUpdated = true;
+      size_t hash = NodeInfomations::CalculateHash(worldColor, updatedPositionSize, size, modelMatrix);
 
-      size_t hash1 = NodeInfomations::CalculateHash1(worldColor, updatedPositionSize, size);
-      size_t hash2 = 0u;
-      if(mNodeInfomations.GetHash1() == hash1)
-      {
-        hash2 = NodeInfomations::CalculateHash2(modelMatrix); // Hash2 is expensive, so we calculate it only when necessary
-        if(mNodeInfomations.GetHash2() == hash2)
-        {
-          // Full comparision one more time.
-          mUpdated = !(mNodeInfomations.matrix == modelMatrix &&
-                       mNodeInfomations.color == worldColor &&
-                       mNodeInfomations.updatedPositionSize == updatedPositionSize &&
-                       mNodeInfomations.size == size);
-        }
-      }
+      mUpdated = !(mNodeInfomations.GetHash() == hash &&        ///< Hash comparision first
+                   mNodeInfomations.worldColor == worldColor && ///< Full comparision one more time.
+                   mNodeInfomations.updatedPositionSize == updatedPositionSize &&
+                   mNodeInfomations.size == size &&
+                   mNodeInfomations.modelMatrix == modelMatrix); ///< Compare matrix last order
 
       if(mUpdated)
       {
-        mNodeInfomations = {modelMatrix, worldColor, updatedPositionSize, size, hash1, hash2};
-
-        // Don't change mVisible.
+        mNodeInfomations = NodeInfomations(modelMatrix, worldColor, updatedPositionSize, size, hash);
       }
     }
 
     mUpdateDecay = Decay::UPDATED_CURRENT_FRAME;
 
+    // Don't change mVisible.
     return mUpdated;
   }
 
@@ -111,51 +166,6 @@ struct PartialRenderingData
   {
     mUpdateDecay = Decay::EXPIRED;
   }
-
-private:
-  struct NodeInfomations
-  {
-    Matrix  matrix{};              /// Model matrix
-    Vector4 color{};               /// Color
-    Vector4 updatedPositionSize{}; /// Updated position/size (x, y, width, height)
-    Vector3 size{};                /// Size
-
-    mutable size_t hash1{0u}; /// Last frame's hash for non-matrix
-    mutable size_t hash2{0u}; /// Last frame's hash for matrix
-
-    static size_t CalculateHash1(const Vector4& color, const Vector4& updatedPositionSize, const Vector3& size)
-    {
-      size_t hash = Dali::Internal::HashUtils::INITIAL_HASH_VALUE;
-      Dali::Internal::HashUtils::HashRawBuffer<float>(color.AsFloat(), 4, hash);
-      Dali::Internal::HashUtils::HashRawBuffer<float>(updatedPositionSize.AsFloat(), 4, hash);
-      Dali::Internal::HashUtils::HashRawBuffer<float>(size.AsFloat(), 3, hash);
-      return hash;
-    }
-
-    static size_t CalculateHash2(const Matrix& matrix)
-    {
-      size_t hash = Dali::Internal::HashUtils::INITIAL_HASH_VALUE;
-      Dali::Internal::HashUtils::HashRawBuffer<float>(matrix.AsFloat(), 16, hash);
-      return hash;
-    }
-
-    size_t GetHash1() const
-    {
-      if(hash1 == 0u)
-      {
-        hash1 = CalculateHash1(color, updatedPositionSize, size);
-      }
-      return hash1;
-    }
-    size_t GetHash2() const
-    {
-      if(hash2 == 0u)
-      {
-        hash2 = CalculateHash2(matrix);
-      }
-      return hash2;
-    }
-  } mNodeInfomations;
 };
 
 } // namespace Dali::Internal::SceneGraph
index 1e8cd5fbb14f4d3d1167690b89def5058002e635..a72ea4a53b646c6c5244754700c9f450259560e4 100644 (file)
@@ -74,7 +74,7 @@ Vector4 AnimatableVisualProperties::GetVisualTransformedUpdateArea(BufferIndex u
     // const float decoratedBorderlineWidth = std::max((1.0f + Dali::Clamp(borderlineOffset, -1.0f, 1.0f)) * borderlineWidth, 2.0f * blurRadius);
     // const Vector2 decoratedVisualSize    = visualSize + Vector2(decoratedBorderlineWidth, decoratedBorderlineWidth);
 
-    // Note : vertexPositoin.xy = aPosition * decoratedVisualSize
+    // Note : vertexPosition.xy = aPosition * decoratedVisualSize
     //                          + anchorPoint * visualSize
     //                          + origin * uSize.xy
     //                          + visualOffset;