Simplifying UniformMap updating 86/261286/14
authorDavid Steele <david.steele@samsung.com>
Mon, 12 Jul 2021 18:18:25 +0000 (19:18 +0100)
committerDavid Steele <david.steele@samsung.com>
Mon, 25 Apr 2022 11:45:22 +0000 (12:45 +0100)
Removed scene-graph ConnectionChangePropagator - now only need to know
if shader is attached to renderer, and that is already done through a
different mechanism.

Changed CollectedUniformMap into it's own struct. Now has a change
counter that increments any time the map is altered.

Instead of having lots of flags indicating if uniform maps have
changed, UniformMap now updates it's change counter whenever a
property is registered with the PropertyOwner (e.g. Node, Renderer or
Shader).

During Update, SceneGraph::Renderer collects the uniform maps into one
only if the renderer is added to a RenderList, i.e. if it's going to
be rendered. At this point, the change counter is updated.
Nothing is done if the renderer is not visible.

During Render, the Render::Renderer checks if the node uniform map
change counter or the renderer data provider's uniform map change
counter are different, if so, then it knows it needs to update the
uniform locations for newly registered properties.

Change-Id: I0ff861a7e97736dae059d94f54618195d0471343

19 files changed:
dali/internal/file.list
dali/internal/render/data-providers/node-data-provider.h
dali/internal/render/data-providers/uniform-map-data-provider.h
dali/internal/render/renderers/render-renderer.cpp
dali/internal/render/renderers/render-renderer.h
dali/internal/render/shaders/render-shader.cpp
dali/internal/render/shaders/render-shader.h
dali/internal/update/common/collected-uniform-map.cpp [new file with mode: 0644]
dali/internal/update/common/collected-uniform-map.h [new file with mode: 0644]
dali/internal/update/common/scene-graph-connection-change-propagator.cpp [deleted file]
dali/internal/update/common/scene-graph-connection-change-propagator.h [deleted file]
dali/internal/update/common/uniform-map.cpp
dali/internal/update/common/uniform-map.h
dali/internal/update/manager/render-instruction-processor.cpp
dali/internal/update/manager/update-algorithms.cpp
dali/internal/update/nodes/node.cpp
dali/internal/update/nodes/node.h
dali/internal/update/rendering/scene-graph-renderer.cpp
dali/internal/update/rendering/scene-graph-renderer.h

index c7ec680..f1dcd94 100644 (file)
@@ -131,6 +131,7 @@ SET( internal_src_files
 
   ${internal_src_dir}/update/animation/scene-graph-animation.cpp
   ${internal_src_dir}/update/animation/scene-graph-constraint-base.cpp
+  ${internal_src_dir}/update/common/collected-uniform-map.cpp
   ${internal_src_dir}/update/common/discard-queue.cpp
   ${internal_src_dir}/update/common/property-base.cpp
   ${internal_src_dir}/update/common/property-owner-messages.cpp
@@ -139,7 +140,6 @@ SET( internal_src_files
   ${internal_src_dir}/update/common/property-condition-variable-step-functions.cpp
   ${internal_src_dir}/update/common/property-owner.cpp
   ${internal_src_dir}/update/common/scene-graph-buffers.cpp
-  ${internal_src_dir}/update/common/scene-graph-connection-change-propagator.cpp
   ${internal_src_dir}/update/common/scene-graph-property-notification.cpp
   ${internal_src_dir}/update/common/scene-graph-scene.cpp
   ${internal_src_dir}/update/common/uniform-map.cpp
index c0a143f..636528d 100644 (file)
@@ -121,7 +121,7 @@ protected:
 /**
  * An interface to provide data for a Renderer
  */
-class NodeDataProvider : UniformMapDataProvider, public PartialRenderingDataProvider
+class NodeDataProvider : public PartialRenderingDataProvider
 {
 public:
   /**
@@ -142,14 +142,9 @@ public:
   virtual const Vector4& GetRenderColor(BufferIndex bufferIndex) const = 0;
 
   /**
-   * @copydoc Dali::Internal::SceneGraph::UniformMapDataProvider::GetUniformMapChanged()
+   * Get the map of uniforms to property value addresses (for node only)
    */
-  bool GetUniformMapChanged(BufferIndex bufferIndex) const override = 0;
-
-  /**
-   * @copydoc Dali::Internal::SceneGraph::UniformMapDataProvider::GetUniformMap()
-   */
-  const CollectedUniformMap& GetUniformMap(BufferIndex bufferIndex) const override = 0;
+  virtual const UniformMap& GetNodeUniformMap() const = 0;
 
 protected:
   /**
index 5d9d83d..5c1ec23 100644 (file)
@@ -17,8 +17,8 @@
  * limitations under the License.
  */
 #include <dali/internal/common/buffer-index.h>
-#include <dali/internal/update/common/uniform-map.h>
-#include <dali/public-api/common/dali-vector.h>
+#include <dali/internal/update/common/collected-uniform-map.h>
+#include <dali/public-api/common/vector-wrapper.h>
 
 namespace Dali
 {
@@ -26,11 +26,6 @@ namespace Internal
 {
 namespace SceneGraph
 {
-class UniformMap;
-class UniformPropertyMapping;
-
-using CollectedUniformMap = Dali::Vector<UniformPropertyMapping>;
-
 /**
  * This class maps uniform names to property value pointers.
  */
@@ -43,23 +38,11 @@ public:
   UniformMapDataProvider() = default;
 
   /**
-   * Return true if the uniform map has been changed this frame
-   * Note, this only informs if the uniform mappings have changed,
-   * not if any actual property value has changed.
-   *
-   * @param[in] bufferIndex The buffer index
-   * @return true if the uniform map has changed
-   */
-  [[nodiscard]] virtual bool GetUniformMapChanged(BufferIndex bufferIndex) const = 0;
-
-  /**
-   * Get the complete map of uniforms to property value addresses
-   * (The map is double buffered - it can be retrieved through this interface)
+   * Get the collected map of uniforms to property value addresses
    *
-   * @param[in] bufferIndex The bufferIndex
    * @return the uniform map
    */
-  [[nodiscard]] virtual const CollectedUniformMap& GetUniformMap(BufferIndex bufferIndex) const = 0;
+  [[nodiscard]] virtual const CollectedUniformMap& GetCollectedUniformMap() const = 0;
 
 protected:
   /**
index 40490fb..dd6c207 100644 (file)
@@ -175,8 +175,6 @@ Renderer::Renderer(SceneGraph::RenderDataProvider* dataProvider,
   mRenderDataProvider(dataProvider),
   mGeometry(geometry),
   mProgramCache(nullptr),
-  mUniformIndexMap(),
-  mUniformsHash(),
   mStencilParameters(stencilParameters),
   mBlendingOptions(),
   mIndexedDrawFirstElement(0),
@@ -531,9 +529,9 @@ bool Renderer::Render(Graphics::CommandBuffer&                             comma
 
   BindTextures(commandBuffer, boundTextures);
 
-  BuildUniformIndexMap(bufferIndex, node, size, *program);
+  int nodeIndex = BuildUniformIndexMap(bufferIndex, node, size, *program);
 
-  WriteUniformBuffer(bufferIndex, commandBuffer, program, instruction, node, modelMatrix, modelViewMatrix, viewMatrix, projectionMatrix, size);
+  WriteUniformBuffer(bufferIndex, commandBuffer, program, instruction, node, modelMatrix, modelViewMatrix, viewMatrix, projectionMatrix, size, nodeIndex);
 
   bool drawn = false; // Draw can fail if there are no vertex buffers or they haven't been uploaded yet
                       // @todo We should detect this case much earlier to prevent unnecessary work
@@ -554,39 +552,69 @@ bool Renderer::Render(Graphics::CommandBuffer&                             comma
   return drawn;
 }
 
-void Renderer::BuildUniformIndexMap(BufferIndex bufferIndex, const SceneGraph::NodeDataProvider& node, const Vector3& size, Program& program)
+int Renderer::BuildUniformIndexMap(BufferIndex bufferIndex, const SceneGraph::NodeDataProvider& node, const Vector3& size, Program& program)
 {
   // Check if the map has changed
   DALI_ASSERT_DEBUG(mRenderDataProvider && "No Uniform map data provider available");
 
   const SceneGraph::UniformMapDataProvider& uniformMapDataProvider = mRenderDataProvider->GetUniformMapDataProvider();
+  const SceneGraph::CollectedUniformMap&    uniformMap             = uniformMapDataProvider.GetCollectedUniformMap();
+  const SceneGraph::UniformMap&             uniformMapNode         = node.GetNodeUniformMap();
 
-  if(uniformMapDataProvider.GetUniformMapChanged(bufferIndex) ||
-     node.GetUniformMapChanged(bufferIndex) ||
-     mUniformIndexMap.Count() == 0 ||
-     mShaderChanged)
+  bool updateMaps;
+
+  // Usual case is to only have 1 node, however we do allow multiple nodes to reuse the same
+  // renderer, so we have to cache uniform map per render item (node / renderer pair).
+
+  const void* nodePtr = static_cast<const void*>(&node);
+  auto        iter    = std::find_if(mNodeIndexMap.begin(), mNodeIndexMap.end(), [nodePtr](RenderItemLookup& element) { return element.node == nodePtr; });
+
+  int renderItemMapIndex;
+  if(iter == mNodeIndexMap.end())
+  {
+    renderItemMapIndex = mUniformIndexMaps.size();
+    RenderItemLookup renderItemLookup;
+    renderItemLookup.node                       = &node;
+    renderItemLookup.index                      = renderItemMapIndex;
+    renderItemLookup.nodeChangeCounter          = uniformMapNode.GetChangeCounter();
+    renderItemLookup.renderItemMapChangeCounter = uniformMap.GetChangeCounter();
+    mNodeIndexMap.emplace_back(renderItemLookup);
+
+    updateMaps = true;
+    mUniformIndexMaps.resize(mUniformIndexMaps.size() + 1);
+  }
+  else
+  {
+    renderItemMapIndex = iter->index;
+
+    updateMaps = (uniformMapNode.GetChangeCounter() != iter->nodeChangeCounter) ||
+                 (uniformMap.GetChangeCounter() != iter->renderItemMapChangeCounter) ||
+                 (mUniformIndexMaps[renderItemMapIndex].size() == 0);
+
+    iter->nodeChangeCounter          = uniformMapNode.GetChangeCounter();
+    iter->renderItemMapChangeCounter = uniformMap.GetChangeCounter();
+  }
+
+  if(updateMaps || mShaderChanged)
   {
     // Reset shader pointer
     mShaderChanged = false;
 
-    const SceneGraph::CollectedUniformMap& uniformMap     = uniformMapDataProvider.GetUniformMap(bufferIndex);
-    const SceneGraph::CollectedUniformMap& uniformMapNode = node.GetUniformMap(bufferIndex);
-
     const uint32_t mapCount     = uniformMap.Count();
     const uint32_t mapNodeCount = uniformMapNode.Count();
 
-    mUniformIndexMap.Clear(); // Clear contents, but keep memory if we don't change size
-    mUniformIndexMap.Resize(mapCount + mapNodeCount);
+    mUniformIndexMaps[renderItemMapIndex].clear(); // Clear contents, but keep memory if we don't change size
+    mUniformIndexMaps[renderItemMapIndex].resize(mapCount + mapNodeCount);
 
     // Copy uniform map into mUniformIndexMap
     uint32_t mapIndex = 0;
     for(; mapIndex < mapCount; ++mapIndex)
     {
-      mUniformIndexMap[mapIndex].propertyValue          = uniformMap[mapIndex].propertyPtr;
-      mUniformIndexMap[mapIndex].uniformName            = uniformMap[mapIndex].uniformName;
-      mUniformIndexMap[mapIndex].uniformNameHash        = uniformMap[mapIndex].uniformNameHash;
-      mUniformIndexMap[mapIndex].uniformNameHashNoArray = uniformMap[mapIndex].uniformNameHashNoArray;
-      mUniformIndexMap[mapIndex].arrayIndex             = uniformMap[mapIndex].arrayIndex;
+      mUniformIndexMaps[renderItemMapIndex][mapIndex].propertyValue          = uniformMap.mUniformMap[mapIndex].propertyPtr;
+      mUniformIndexMaps[renderItemMapIndex][mapIndex].uniformName            = uniformMap.mUniformMap[mapIndex].uniformName;
+      mUniformIndexMaps[renderItemMapIndex][mapIndex].uniformNameHash        = uniformMap.mUniformMap[mapIndex].uniformNameHash;
+      mUniformIndexMaps[renderItemMapIndex][mapIndex].uniformNameHashNoArray = uniformMap.mUniformMap[mapIndex].uniformNameHashNoArray;
+      mUniformIndexMaps[renderItemMapIndex][mapIndex].arrayIndex             = uniformMap.mUniformMap[mapIndex].arrayIndex;
     }
 
     for(uint32_t nodeMapIndex = 0; nodeMapIndex < mapNodeCount; ++nodeMapIndex)
@@ -596,28 +624,29 @@ void Renderer::BuildUniformIndexMap(BufferIndex bufferIndex, const SceneGraph::N
       bool  found(false);
       for(uint32_t i = 0; i < mapCount; ++i)
       {
-        if(mUniformIndexMap[i].uniformNameHash == hash &&
-           mUniformIndexMap[i].uniformName == name)
+        if(mUniformIndexMaps[renderItemMapIndex][i].uniformNameHash == hash &&
+           mUniformIndexMaps[renderItemMapIndex][i].uniformName == name)
         {
-          mUniformIndexMap[i].propertyValue = uniformMapNode[nodeMapIndex].propertyPtr;
-          found                             = true;
+          mUniformIndexMaps[renderItemMapIndex][i].propertyValue = uniformMapNode[nodeMapIndex].propertyPtr;
+          found                                                  = true;
           break;
         }
       }
 
       if(!found)
       {
-        mUniformIndexMap[mapIndex].propertyValue          = uniformMapNode[nodeMapIndex].propertyPtr;
-        mUniformIndexMap[mapIndex].uniformName            = uniformMapNode[nodeMapIndex].uniformName;
-        mUniformIndexMap[mapIndex].uniformNameHash        = uniformMapNode[nodeMapIndex].uniformNameHash;
-        mUniformIndexMap[mapIndex].uniformNameHashNoArray = uniformMapNode[nodeMapIndex].uniformNameHashNoArray;
-        mUniformIndexMap[mapIndex].arrayIndex             = uniformMapNode[nodeMapIndex].arrayIndex;
+        mUniformIndexMaps[renderItemMapIndex][mapIndex].propertyValue          = uniformMapNode[nodeMapIndex].propertyPtr;
+        mUniformIndexMaps[renderItemMapIndex][mapIndex].uniformName            = uniformMapNode[nodeMapIndex].uniformName;
+        mUniformIndexMaps[renderItemMapIndex][mapIndex].uniformNameHash        = uniformMapNode[nodeMapIndex].uniformNameHash;
+        mUniformIndexMaps[renderItemMapIndex][mapIndex].uniformNameHashNoArray = uniformMapNode[nodeMapIndex].uniformNameHashNoArray;
+        mUniformIndexMaps[renderItemMapIndex][mapIndex].arrayIndex             = uniformMapNode[nodeMapIndex].arrayIndex;
         ++mapIndex;
       }
     }
 
-    mUniformIndexMap.Resize(mapIndex);
+    mUniformIndexMaps[renderItemMapIndex].resize(mapIndex);
   }
+  return renderItemMapIndex;
 }
 
 void Renderer::WriteUniformBuffer(
@@ -630,7 +659,8 @@ void Renderer::WriteUniformBuffer(
   const Matrix&                        modelViewMatrix,
   const Matrix&                        viewMatrix,
   const Matrix&                        projectionMatrix,
-  const Vector3&                       size)
+  const Vector3&                       size,
+  int                                  nodeIndex)
 {
   // Create the UBO
   uint32_t uboOffset{0u};
@@ -697,7 +727,7 @@ void Renderer::WriteUniformBuffer(
     WriteDefaultUniform(program->GetDefaultUniform(Program::DefaultUniformIndex::ACTOR_COLOR), *uboView, color);
 
     // Write uniforms from the uniform map
-    FillUniformBuffer(*program, instruction, *uboView, bindings, uboOffset, bufferIndex);
+    FillUniformBuffer(*program, instruction, *uboView, bindings, uboOffset, bufferIndex, nodeIndex);
 
     // Write uSize in the end, as it shouldn't be overridable by dynamic properties.
     WriteDefaultUniform(program->GetDefaultUniform(Program::DefaultUniformIndex::SIZE), *uboView, size);
@@ -733,7 +763,8 @@ void Renderer::FillUniformBuffer(Program&                                      p
                                  Render::UniformBufferView&                    ubo,
                                  std::vector<Graphics::UniformBufferBinding>*& outBindings,
                                  uint32_t&                                     offset,
-                                 BufferIndex                                   updateBufferIndex)
+                                 BufferIndex                                   updateBufferIndex,
+                                 int                                           nodeIndex)
 {
   auto& reflection = mGraphicsController->GetProgramReflection(program.GetGraphicsProgram());
   auto  uboCount   = reflection.GetUniformBlockCount();
@@ -748,8 +779,8 @@ void Renderer::FillUniformBuffer(Program&                                      p
     dataOffset += GetUniformBufferDataAlignment(mUniformBufferBindings[i].dataSize);
     mUniformBufferBindings[i].buffer = ubo.GetBuffer(&mUniformBufferBindings[i].offset);
 
-    for(UniformIndexMappings::Iterator iter = mUniformIndexMap.Begin(),
-                                       end  = mUniformIndexMap.End();
+    for(auto iter = mUniformIndexMaps[nodeIndex].begin(),
+             end  = mUniformIndexMaps[nodeIndex].end();
         iter != end;
         ++iter)
     {
@@ -839,18 +870,19 @@ bool Renderer::Updated(BufferIndex bufferIndex, const SceneGraph::NodeDataProvid
     }
   }
 
-  uint64_t                               hash           = 0xc70f6907UL;
-  const SceneGraph::CollectedUniformMap& uniformMapNode = node->GetUniformMap(bufferIndex);
-  for(const auto& uniformProperty : uniformMapNode)
+  // Hash the property values. If the values are different, then rendering is required.
+  uint64_t                      hash           = 0xc70f6907UL;
+  const SceneGraph::UniformMap& uniformMapNode = node->GetNodeUniformMap();
+  for(uint32_t i = 0u, count = uniformMapNode.Count(); i < count; ++i)
   {
-    hash = uniformProperty.propertyPtr->Hash(bufferIndex, hash);
+    hash = uniformMapNode[i].propertyPtr->Hash(bufferIndex, hash);
   }
 
   const SceneGraph::UniformMapDataProvider& uniformMapDataProvider = mRenderDataProvider->GetUniformMapDataProvider();
-  const SceneGraph::CollectedUniformMap&    uniformMap             = uniformMapDataProvider.GetUniformMap(bufferIndex);
-  for(const auto& uniformProperty : uniformMap)
+  const SceneGraph::CollectedUniformMap&    collectedUniformMap    = uniformMapDataProvider.GetCollectedUniformMap();
+  for(uint32_t i = 0u, count = collectedUniformMap.Count(); i < count; ++i)
   {
-    hash = uniformProperty.propertyPtr->Hash(bufferIndex, hash);
+    hash = collectedUniformMap.mUniformMap[i].propertyPtr->Hash(bufferIndex, hash);
   }
 
   if(mUniformsHash != hash)
index 9d578a2..4156671 100644 (file)
@@ -19,6 +19,7 @@
  */
 
 // INTERNAL INCLUDES
+#include <dali/public-api/common/vector-wrapper.h>
 #include <dali/public-api/math/matrix.h>
 #include <dali/public-api/math/vector4.h>
 #include <dali/public-api/rendering/texture-set.h>
@@ -455,8 +456,10 @@ private:
    * @param[in] node The node using the renderer
    * @param[in] size The size of the renderer
    * @param[in] program The shader program on which to set the uniforms.
+   *
+   * @return the index of the node in change counters store / uniform maps store.
    */
-  void BuildUniformIndexMap(BufferIndex bufferIndex, const SceneGraph::NodeDataProvider& node, const Vector3& size, Program& program);
+  int BuildUniformIndexMap(BufferIndex bufferIndex, const SceneGraph::NodeDataProvider& node, const Vector3& size, Program& program);
 
   /**
    * Bind the textures and setup the samplers
@@ -491,6 +494,7 @@ private:
    * @param[in] size Size of the render item
    * @param[in] blend If true, blending is enabled
    * @param[in] instruction The render instruction
+   * @param[in] The node index
    */
   void WriteUniformBuffer(BufferIndex                          bufferIndex,
                           Graphics::CommandBuffer&             commandBuffer,
@@ -501,7 +505,8 @@ private:
                           const Matrix&                        modelViewMatrix,
                           const Matrix&                        viewMatrix,
                           const Matrix&                        projectionMatrix,
-                          const Vector3&                       size);
+                          const Vector3&                       size,
+                          int                                  nodeIndex);
 
   /**
    * @brief Fill uniform buffer at index. Writes uniforms into given memory address
@@ -517,7 +522,8 @@ private:
                          Render::UniformBufferView&                    ubo,
                          std::vector<Graphics::UniformBufferBinding>*& outBindings,
                          uint32_t&                                     offset,
-                         BufferIndex                                   updateBufferIndex);
+                         BufferIndex                                   updateBufferIndex,
+                         int                                           nodeIndex);
 
 private:
   Graphics::Controller*           mGraphicsController;
@@ -551,27 +557,27 @@ private:
     FuncGetter uniformFunc{0};
   };
 
-  using UniformIndexMappings = Dali::Vector<UniformIndexMap>;
-
-  UniformIndexMappings mUniformIndexMap;
-  uint64_t             mUniformsHash;
-
-  struct HashedPipeline
-  {
-    uint64_t                                mHash{0u};
-    Graphics::UniquePtr<Graphics::Pipeline> mGraphicsPipeline{nullptr};
-    inline static uint64_t                  GetHash(const void* node, const void* instruction, bool blend)
-    {
-      return (reinterpret_cast<uint64_t>(node) << 32) | ((reinterpret_cast<uint64_t>(instruction) & 0xFFFFFFF) << 1) | blend;
-    }
-  };
-
   StencilParameters mStencilParameters; ///< Struct containing all stencil related options
   BlendingOptions   mBlendingOptions;   ///< Blending options including blend color, blend func and blend equation
 
   uint32_t mIndexedDrawFirstElement;  ///< Offset of first element to draw
   uint32_t mIndexedDrawElementsCount; ///< Number of elements to draw
 
+  /** Struct to map node to index into mNodeMapCounters and mUniformIndexMaps */
+  struct RenderItemLookup
+  {
+    const SceneGraph::NodeDataProvider* node{nullptr}; ///<Node key
+
+    std::size_t index{0};                       ///<Index into mUniformIndexMap
+    std::size_t nodeChangeCounter{0};           ///<The last known change counter for this node's uniform map
+    std::size_t renderItemMapChangeCounter{0u}; ///< Change counter of the renderer & shader collected uniform map for this render item (node/renderer pair)
+  };
+  std::vector<RenderItemLookup> mNodeIndexMap; ///< usually only 1 element.
+  using UniformIndexMappings = std::vector<UniformIndexMap>;
+  std::vector<UniformIndexMappings> mUniformIndexMaps; ///< Cached map per node/renderer/shader.
+
+  uint64_t mUniformsHash{0}; ///< Hash of uniform map property values
+
   DepthFunction::Type   mDepthFunction : 4;             ///< The depth function
   FaceCullingMode::Type mFaceCullingMode : 3;           ///< The mode of face culling
   DepthWriteMode::Type  mDepthWriteMode : 3;            ///< The depth write mode
index 51f997e..3b26fd5 100644 (file)
@@ -32,15 +32,12 @@ namespace Internal
 namespace SceneGraph
 {
 Shader::Shader(Dali::Shader::Hint::Value& hints)
-: mHints(hints),
-  mConnectionObservers()
+: mHints(hints)
 {
-  AddUniformMapObserver(*this);
 }
 
 Shader::~Shader()
 {
-  mConnectionObservers.Destroy(*this);
 }
 
 void Shader::SetShaderData(ShaderDataPtr shaderData)
@@ -48,8 +45,6 @@ void Shader::SetShaderData(ShaderDataPtr shaderData)
   DALI_LOG_TRACE_METHOD_FMT(Debug::Filter::gShader, "%d\n", shaderData->GetHashValue());
 
   mShaderData = shaderData;
-
-  mConnectionObservers.ConnectionsChanged(*this);
 }
 
 ShaderDataPtr Shader::GetShaderData() const
@@ -57,23 +52,6 @@ ShaderDataPtr Shader::GetShaderData() const
   return mShaderData;
 }
 
-void Shader::AddConnectionObserver(ConnectionChangePropagator::Observer& observer)
-{
-  mConnectionObservers.Add(observer);
-}
-
-void Shader::RemoveConnectionObserver(ConnectionChangePropagator::Observer& observer)
-{
-  mConnectionObservers.Remove(observer);
-}
-
-void Shader::UniformMappingsChanged(const UniformMap& mappings)
-{
-  // Our uniform map, or that of one of the watched children has changed.
-  // Inform connected observers.
-  mConnectionObservers.ConnectedUniformMapChanged();
-}
-
 } // namespace SceneGraph
 
 } // namespace Internal
index 9ddbb6a..ff768e5 100644 (file)
@@ -22,7 +22,6 @@
 #include <dali/internal/common/shader-data.h>
 #include <dali/internal/event/common/event-thread-services.h>
 #include <dali/internal/update/common/property-owner.h>
-#include <dali/internal/update/common/scene-graph-connection-change-propagator.h>
 
 namespace Dali
 {
@@ -36,9 +35,19 @@ namespace SceneGraph
 class SceneController;
 
 /**
- * A holder class for Program; also enables sharing of uniform properties
+ * This PropertyOwner enables registration of properties as uniforms.
+ * It holds a ShaderData, which can be read from Render side.
+ *
+ * Any renderer that uses this shader also registers to it's UniformMap
+ * observer, so that it can be notified when properties are registered
+ * after being linked. (DALi public API allows Renderer to be created
+ * with a shader, or a shader to be set on a renderer _before_ uniform
+ * properties are defined on a shader. This connection ensures that
+ * all the uniforms are loaded into GPU at render time).
+ *
+ * //@todo Move back to scene graph
  */
-class Shader : public PropertyOwner, public UniformMap::Observer
+class Shader : public PropertyOwner
 {
 public:
   /**
@@ -78,29 +87,10 @@ public:
    */
   [[nodiscard]] ShaderDataPtr GetShaderData() const;
 
-public:
-  /**
-   * @copydoc ConnectionChangePropagator::AddObserver
-   */
-  void AddConnectionObserver(ConnectionChangePropagator::Observer& observer);
-
-  /**
-   * @copydoc ConnectionChangePropagator::RemoveObserver
-   */
-  void RemoveConnectionObserver(ConnectionChangePropagator::Observer& observer);
-
-public: // UniformMap::Observer
-  /**
-   * @copydoc UniformMap::Observer::UniformMappingsChanged
-   */
-  void UniformMappingsChanged(const UniformMap& mappings) override;
-
 private: // Data
   Dali::Shader::Hint::Value mHints;
 
   ShaderDataPtr mShaderData;
-
-  ConnectionChangePropagator mConnectionObservers;
 };
 
 inline void SetShaderDataMessage(EventThreadServices& eventThreadServices, const Shader& shader, ShaderDataPtr shaderData)
diff --git a/dali/internal/update/common/collected-uniform-map.cpp b/dali/internal/update/common/collected-uniform-map.cpp
new file mode 100644 (file)
index 0000000..822dfcd
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2022 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// CLASS HEADER
+#include <dali/internal/update/common/collected-uniform-map.h>
+
+// INTERNAL HEADERS
+#include <dali/devel-api/common/hash.h>
+#include <dali/internal/render/data-providers/uniform-map-data-provider.h>
+
+// EXTERNAL HEADERS
+#include <algorithm>
+
+namespace Dali
+{
+namespace Internal
+{
+namespace SceneGraph
+{
+void CollectedUniformMap::AddMappings(const UniformMap& uniformMap)
+{
+  // Iterate thru uniformMap.
+  // Any maps that aren't in localMap should be added in a single step
+
+  // keep a static vector to avoid temporary heap allocation.
+  // As this function gets called only from update thread we don't have to
+  // make it thread safe (so no need to keep a thread_local variable).
+  static Dali::Vector<UniformPropertyMapping> newUniformMappings;
+
+  newUniformMappings.Clear();
+
+  for(UniformMap::SizeType i = 0, iCount = uniformMap.Count(); i < iCount; ++i)
+  {
+    bool found = false;
+
+    for(UniformMap::SizeType j = 0, jCount = mUniformMap.Count(); j < jCount; ++j)
+    {
+      if(mUniformMap[j].uniformName == uniformMap[i].uniformName)
+      {
+        found = true;
+        break;
+      }
+    }
+    if(!found)
+    {
+      newUniformMappings.PushBack(uniformMap[i]);
+    }
+  }
+
+  if(newUniformMappings.Count() > 0)
+  {
+    mUniformMap.Reserve(mUniformMap.Count() + newUniformMappings.Count());
+
+    for(UniformMap::SizeType i = 0, iCount = newUniformMappings.Count(); i < iCount; ++i)
+    {
+      mUniformMap.PushBack(newUniformMappings[i]);
+    }
+  }
+}
+
+} // namespace SceneGraph
+} // namespace Internal
+} // namespace Dali
diff --git a/dali/internal/update/common/collected-uniform-map.h b/dali/internal/update/common/collected-uniform-map.h
new file mode 100644 (file)
index 0000000..b0be489
--- /dev/null
@@ -0,0 +1,109 @@
+#ifndef DALI_INTERNAL_SCENE_GRAPH_COLLECTED_UNIFORM_MAP_H
+#define DALI_INTERNAL_SCENE_GRAPH_COLLECTED_UNIFORM_MAP_H
+
+/*
+ * Copyright (c) 2022 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <dali/internal/common/buffer-index.h>
+#include <dali/internal/update/common/uniform-map.h>
+#include <dali/public-api/common/dali-vector.h>
+
+namespace Dali
+{
+namespace Internal
+{
+namespace SceneGraph
+{
+class UniformMap;
+class UniformPropertyMapping;
+
+/**
+ * Class to collect uniform mappings together into a new map.
+ * Distinct from UniformMap, as it doesn't need the observation/lifecycle
+ * overhead.
+ *
+ * It has a counter that increments each time it's changed, which
+ * allows a client to know if it's been modified since the last time
+ * the client checked.
+ */
+struct CollectedUniformMap
+{
+  /**
+   * Constructor
+   */
+  CollectedUniformMap() = default;
+
+  /**
+   * Destructor
+   */
+  ~CollectedUniformMap() = default;
+
+  /**
+   * @brief Add mappings from a UniformMap.
+   * @param[in] uniformMap to copy
+   */
+  void AddMappings(const UniformMap& uniformMap);
+
+  /**
+   * Clear the mappings
+   */
+  inline void Clear()
+  {
+    mUniformMap.Clear();
+    UpdateChangeCounter();
+  }
+
+  /**
+   * Reserve space for mappings
+   * @param[in] size The number of mappings to reserve
+   */
+  inline void Reserve(std::size_t size)
+  {
+    mUniformMap.Reserve(size);
+  }
+
+  /**
+   * @return the count of the number of mappings
+   */
+  inline std::size_t Count() const
+  {
+    return mUniformMap.Size();
+  }
+
+  /**
+   * @brief Update the change counter if the map changes.
+   */
+  void UpdateChangeCounter()
+  {
+    ++mChangeCounter;
+  }
+
+  /**
+   * Return the currently calculated hash.
+   */
+  inline std::size_t GetChangeCounter() const
+  {
+    return mChangeCounter;
+  }
+
+  Dali::Vector<UniformPropertyMapping> mUniformMap;        ///< The mappings
+  std::size_t                          mChangeCounter{0u}; ///< The change counter
+};
+
+} // namespace SceneGraph
+} // namespace Internal
+} // namespace Dali
+
+#endif // DALI_INTERNAL_SCENE_GRAPH_COLLECTED_UNIFORM_MAP_H
diff --git a/dali/internal/update/common/scene-graph-connection-change-propagator.cpp b/dali/internal/update/common/scene-graph-connection-change-propagator.cpp
deleted file mode 100644 (file)
index 5ea73af..0000000
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * Copyright (c) 2015 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.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "scene-graph-connection-change-propagator.h"
-
-namespace Dali
-{
-namespace Internal
-{
-namespace SceneGraph
-{
-ConnectionChangePropagator::ConnectionChangePropagator() = default;
-
-ConnectionChangePropagator::~ConnectionChangePropagator() = default;
-
-void ConnectionChangePropagator::Add(Observer& observer)
-{
-  bool foundObserver = false;
-  for(ObserversIterator iter = mObservers.Begin(); iter != mObservers.End(); ++iter)
-  {
-    if(*iter == &observer)
-    {
-      foundObserver = true;
-      break;
-    }
-  }
-  if(!foundObserver)
-  {
-    mObservers.PushBack(&observer);
-  }
-}
-
-void ConnectionChangePropagator::Remove(Observer& observer)
-{
-  for(ObserversIterator iter = mObservers.Begin(); iter != mObservers.End(); ++iter)
-  {
-    if(*iter == &observer)
-    {
-      mObservers.Erase(iter);
-      return;
-    }
-  }
-}
-
-void ConnectionChangePropagator::ConnectionsChanged(PropertyOwner& object)
-{
-  // Inform observers that the object's children have changed
-  for(ObserversIterator iter = mObservers.Begin(); iter != mObservers.End(); ++iter)
-  {
-    Observer* observer = (*iter);
-    observer->ConnectionsChanged(object);
-  }
-}
-
-void ConnectionChangePropagator::ConnectedUniformMapChanged()
-{
-  // Inform observers that the object's uniform map has changed
-  for(ObserversIterator iter = mObservers.Begin(); iter != mObservers.End(); ++iter)
-  {
-    Observer* observer = (*iter);
-    observer->ConnectedUniformMapChanged();
-  }
-}
-
-void ConnectionChangePropagator::Destroy(PropertyOwner& object)
-{
-  // Inform observers that the object's children have changed
-  for(ObserversIterator iter = mObservers.Begin(); iter != mObservers.End(); ++iter)
-  {
-    Observer* observer = (*iter);
-    observer->ObservedObjectDestroyed(object);
-  }
-}
-
-} // namespace SceneGraph
-} // namespace Internal
-} // namespace Dali
diff --git a/dali/internal/update/common/scene-graph-connection-change-propagator.h b/dali/internal/update/common/scene-graph-connection-change-propagator.h
deleted file mode 100644 (file)
index 9fe165a..0000000
+++ /dev/null
@@ -1,115 +0,0 @@
-#ifndef DALI_INTERNAL_SCENE_GRAPH_CONNECTION_CHANGE_PROPAGATOR_H
-#define DALI_INTERNAL_SCENE_GRAPH_CONNECTION_CHANGE_PROPAGATOR_H
-
-/*
- * Copyright (c) 2015 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.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <dali/public-api/common/dali-vector.h>
-
-namespace Dali
-{
-namespace Internal
-{
-namespace SceneGraph
-{
-class PropertyOwner;
-
-/**
- * This class maintains a list of observers that are informed when
- * it's owner changes it's connections.
- */
-class ConnectionChangePropagator
-{
-public:
-  class Observer
-  {
-  public:
-    /**
-     * Inform the observer of the object that it's connections have changed
-     * @param[in] object The connection owner
-     */
-    virtual void ConnectionsChanged(PropertyOwner& object) = 0;
-
-    /**
-     * Inform the observer of the object that a connected object has
-     * changed it's uniform map in some way.
-     */
-    virtual void ConnectedUniformMapChanged() = 0;
-
-    /**
-     * Inform the observer of the object that the object is about to be destroyed
-     */
-    virtual void ObservedObjectDestroyed(PropertyOwner& object)
-    {
-    }
-
-  protected:
-    /**
-     * Virtual destructor, no deletion through this interface
-     */
-    virtual ~Observer() = default;
-  };
-
-  /**
-   * Constructor
-   */
-  ConnectionChangePropagator();
-
-  /**
-   * Destructor
-   */
-  ~ConnectionChangePropagator();
-
-  /**
-   * Add an observer
-   */
-  void Add(Observer& observer);
-
-  /**
-   * Remove an observer
-   */
-  void Remove(Observer& observer);
-
-  /**
-   * Inform the observers that the connections to the object have changed
-   * @param[in] object The connection owner
-   */
-  void ConnectionsChanged(PropertyOwner& object);
-
-  /**
-   * Inform the observers that the uniform map of this or a connected object
-   * has changed.
-   */
-  void ConnectedUniformMapChanged();
-
-  /**
-   * Inform the observers that the object is about to be destroyed
-   * @param[in] object The connection owner
-   */
-  void Destroy(PropertyOwner& object);
-
-private:
-  using Observers         = Dali::Vector<Observer*>;
-  using ObserversIterator = Observers::Iterator;
-
-  Observers mObservers;
-};
-
-} // namespace SceneGraph
-} // namespace Internal
-} // namespace Dali
-
-#endif // DALI_INTERNAL_SCENE_GRAPH_CONNECTION_CHANGE_PROPAGATOR_H
index a0155c7..2caba5e 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 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.
@@ -56,6 +56,7 @@ void UniformMap::RemoveObserver(Observer& observer)
 
 void UniformMap::MappingChanged()
 {
+  ++mChangeCounter;
   for(ObserversIter iter = mObservers.Begin(); iter != mObservers.End(); ++iter)
   {
     Observer* observer = (*iter);
index 0a505de..f625169 100644 (file)
 #include <string>
 
 // INTERNAL INCLUDES
+#include <dali/public-api/common/dali-vector.h>
+
 #include <dali/devel-api/common/hash.h>
-#include <dali/devel-api/common/owner-container.h>
+
 #include <dali/internal/common/const-string.h>
 
 namespace Dali
@@ -82,8 +84,7 @@ public:
 
 /**
  * The UniformMap class is used to map uniform names to property values. It is available
- * in all of the classes responsible for rendering:
- * Actor, Renderer, Geometry, TextureSet, Shader.
+ * in the following rendering classes: Node, Renderer, Shader.
  *
  * It can be observed for changes to the mapping table.
  */
@@ -147,6 +148,14 @@ public:
    */
   const UniformPropertyMapping& operator[](SizeType index) const;
 
+  /**
+   * Return the change counter
+   */
+  inline std::size_t GetChangeCounter() const
+  {
+    return mChangeCounter;
+  }
+
 private:
   /**
    * Helper to call the observers when the mappings have changed
@@ -159,9 +168,9 @@ private:
   using Observers           = Dali::Vector<Observer*>;
   using ObserversIter       = Observers::Iterator;
 
-  UniformMapContainer mUniformMaps; // Owner container of uniform maps
-
-  Observers mObservers;
+  UniformMapContainer mUniformMaps; ///< container of uniform maps
+  Observers           mObservers;
+  std::size_t         mChangeCounter{0u}; ///< Counter that is incremented when the map changes
 };
 
 } // namespace SceneGraph
index 0365d5b..d021083 100644 (file)
@@ -279,6 +279,9 @@ inline void AddRendererToRenderList(BufferIndex         updateBufferIndex,
         item.mRenderer   = &renderable.mRenderer->GetRenderer();
         item.mTextureSet = renderable.mRenderer->GetTextureSet();
         item.mDepthIndex += renderable.mRenderer->GetDepthIndex();
+
+        // Ensure collected map is up to date
+        item.mIsUpdated |= renderable.mRenderer->UpdateUniformMap();
       }
       else
       {
index 3ff66c4..98e5a93 100644 (file)
@@ -113,8 +113,7 @@ inline NodePropertyFlags UpdateNodes(Node&             node,
 
   UpdateNodeOpacity(node, nodeDirtyFlags, updateBufferIndex);
 
-  // Collect uniform maps
-  node.PrepareRender(updateBufferIndex);
+
 
   // For partial update, mark all children of an animating node as updated.
   if(updated) // Only set to updated if parent was updated.
index 60f1c44..5ae5e1c 100644 (file)
@@ -95,7 +95,6 @@ Node::Node()
   mScissorDepth(0u),
   mDepthIndex(0u),
   mDirtyFlags(NodePropertyFlags::ALL),
-  mRegenerateUniformMap(0),
   mDrawMode(DrawMode::NORMAL),
   mColorMode(DEFAULT_COLOR_MODE),
   mClippingMode(ClippingMode::DISABLED),
@@ -104,9 +103,6 @@ Node::Node()
   mPositionUsesAnchorPoint(true),
   mTransparent(false)
 {
-  mUniformMapChanged[0] = 0u;
-  mUniformMapChanged[1] = 0u;
-
 #ifdef DEBUG_ENABLED
   gNodeCount++;
 #endif
@@ -169,55 +165,11 @@ void Node::SetRoot(bool isRoot)
   mIsRoot = isRoot;
 }
 
-void Node::AddUniformMapping(const UniformPropertyMapping& map)
-{
-  PropertyOwner::AddUniformMapping(map);
-  mRegenerateUniformMap = 2;
-}
-
-void Node::RemoveUniformMapping(const ConstString& uniformName)
-{
-  PropertyOwner::RemoveUniformMapping(uniformName);
-  mRegenerateUniformMap = 2;
-}
-
 bool Node::IsAnimationPossible() const
 {
   return mIsConnectedToSceneGraph;
 }
 
-void Node::PrepareRender(BufferIndex bufferIndex)
-{
-  if(mRegenerateUniformMap != 0)
-  {
-    if(mRegenerateUniformMap == 2)
-    {
-      CollectedUniformMap& localMap = mCollectedUniformMap[bufferIndex];
-      localMap.Resize(0);
-
-      for(UniformMap::SizeType i = 0, count = mUniformMaps.Count(); i < count; ++i)
-      {
-        localMap.PushBack(mUniformMaps[i]);
-      }
-    }
-    else if(mRegenerateUniformMap == 1)
-    {
-      CollectedUniformMap& localMap = mCollectedUniformMap[bufferIndex];
-      CollectedUniformMap& oldMap   = mCollectedUniformMap[1 - bufferIndex];
-
-      localMap.Resize(oldMap.Count());
-
-      CollectedUniformMap::SizeType index = 0;
-      for(CollectedUniformMap::Iterator iter = oldMap.Begin(), end = oldMap.End(); iter != end; ++iter, ++index)
-      {
-        localMap[index] = *iter;
-      }
-    }
-    --mRegenerateUniformMap;
-    mUniformMapChanged[bufferIndex] = 1u;
-  }
-}
-
 void Node::ConnectChild(Node* childNode)
 {
   DALI_ASSERT_ALWAYS(this != childNode);
index a886a9b..7a1221c 100644 (file)
@@ -837,28 +837,11 @@ public:
 
 public:
   /**
-   * @copydoc UniformMap::Add
-   */
-  void AddUniformMapping(const UniformPropertyMapping& map) override;
-
-  /**
-   * @copydoc UniformMap::Remove
-   */
-  void RemoveUniformMapping(const ConstString& uniformName) override;
-
-  /**
    * @copydoc Dali::Internal::SceneGraph::PropertyOwner::IsAnimationPossible
    */
   bool IsAnimationPossible() const override;
 
   /**
-   * Prepare the node for rendering.
-   * This is called by the UpdateManager when an object is due to be rendered in the current frame.
-   * @param[in] updateBufferIndex The current update buffer index.
-   */
-  void PrepareRender(BufferIndex bufferIndex);
-
-  /**
    * Called by UpdateManager when the node is added.
    * Creates a new transform component in the transform manager and initialize all the properties
    * related to the transformation
@@ -907,21 +890,12 @@ private: // from NodeDataProvider
     return GetWorldColor(bufferIndex);
   }
 
-public: // From UniformMapDataProvider
-  /**
-   * @copydoc UniformMapDataProvider::GetUniformMapChanged
-   */
-  bool GetUniformMapChanged(BufferIndex bufferIndex) const override
-  {
-    return mUniformMapChanged[bufferIndex];
-  }
-
   /**
-   * @copydoc UniformMapDataProvider::GetUniformMap
+   * @copydoc NodeDataProvider::GetNodeUniformMap
    */
-  const CollectedUniformMap& GetUniformMap(BufferIndex bufferIndex) const override
+  const UniformMap& GetNodeUniformMap() const override
   {
-    return mCollectedUniformMap[bufferIndex];
+    return GetUniformMap();
   }
 
 private:
@@ -979,16 +953,13 @@ protected:
 
   NodeContainer mChildren; ///< Container of children; not owned
 
-  CollectedUniformMap mCollectedUniformMap[2]; ///< Uniform maps of the node
-  uint32_t            mUniformMapChanged[2];   ///< Records if the uniform map has been altered this frame
-  uint32_t            mClippingDepth;          ///< The number of stencil clipping nodes deep this node is
-  uint32_t            mScissorDepth;           ///< The number of scissor clipping nodes deep this node is
+  uint32_t mClippingDepth; ///< The number of stencil clipping nodes deep this node is
+  uint32_t mScissorDepth;  ///< The number of scissor clipping nodes deep this node is
 
   uint32_t mDepthIndex; ///< Depth index of the node
 
   // flags, compressed to bitfield
   NodePropertyFlags  mDirtyFlags;                  ///< Dirty flags for each of the Node properties
-  uint32_t           mRegenerateUniformMap : 2;    ///< Indicate if the uniform map has to be regenerated this frame
   DrawMode::Type     mDrawMode : 3;                ///< How the Node and its children should be drawn
   ColorMode          mColorMode : 3;               ///< Determines whether mWorldColor is inherited, 2 bits is enough
   ClippingMode::Type mClippingMode : 3;            ///< The clipping mode of this node
index 9e982a8..a0f4b4e 100644 (file)
@@ -40,59 +40,9 @@ namespace SceneGraph
 {
 namespace // unnamed namespace
 {
-const uint32_t UNIFORM_MAP_READY      = 0;
-const uint32_t COPY_UNIFORM_MAP       = 1;
-const uint32_t REGENERATE_UNIFORM_MAP = 2;
-
 //Memory pool used to allocate new renderers. Memory used by this pool will be released when shutting down DALi
 MemoryPoolObjectAllocator<Renderer> gRendererMemoryPool;
 
-void AddMappings(CollectedUniformMap& localMap, const UniformMap& uniformMap)
-{
-  // Iterate thru uniformMap.
-  // Any maps that aren't in localMap should be added in a single step
-
-  // keep a static vector to avoid temporary heap allocation.
-  // As this function gets called only from update thread we don't have to
-  // make it thread safe (so no need to keep a thread_local variable).
-  static CollectedUniformMap newUniformMappings;
-
-  newUniformMappings.Clear();
-
-  for(UniformMap::SizeType i = 0, count = uniformMap.Count(); i < count; ++i)
-  {
-    bool found = false;
-
-    for(CollectedUniformMap::Iterator iter = localMap.Begin(); iter != localMap.End(); ++iter)
-    {
-      const UniformPropertyMapping& map = (*iter);
-      if(map.uniformName == uniformMap[i].uniformName)
-      {
-        found = true;
-        break;
-      }
-    }
-    if(!found)
-    {
-      newUniformMappings.PushBack(uniformMap[i]);
-    }
-  }
-
-  if(newUniformMappings.Count() > 0)
-  {
-    localMap.Reserve(localMap.Count() + newUniformMappings.Count());
-
-    for(CollectedUniformMap::Iterator iter = newUniformMappings.Begin(),
-                                      end  = newUniformMappings.End();
-        iter != end;
-        ++iter)
-    {
-      const UniformPropertyMapping& map = (*iter);
-      localMap.PushBack(map);
-    }
-  }
-}
-
 // Flags for re-sending data to renderer.
 enum Flags
 {
@@ -138,7 +88,6 @@ Renderer::Renderer()
   mIndexedDrawFirstElement(0u),
   mIndexedDrawElementsCount(0u),
   mBlendBitmask(0u),
-  mRegenerateUniformMap(0u),
   mResendFlag(0u),
   mDepthFunction(DepthFunction::LESS),
   mFaceCullingMode(FaceCullingMode::NONE),
@@ -146,26 +95,21 @@ Renderer::Renderer()
   mDepthWriteMode(DepthWriteMode::AUTO),
   mDepthTestMode(DepthTestMode::AUTO),
   mRenderingBehavior(DevelRenderer::Rendering::IF_REQUIRED),
+  mUpdateDecay(Renderer::Decay::INITIAL),
+  mRegenerateUniformMap(false),
   mPremultipledAlphaEnabled(false),
   mOpacity(1.0f),
   mDepthIndex(0)
 {
-  mUniformMapChanged[0] = false;
-  mUniformMapChanged[1] = false;
-
-  // Observe our own PropertyOwner's uniform map
+  // Observe our own PropertyOwner's uniform map.
   AddUniformMapObserver(*this);
 }
 
 Renderer::~Renderer()
 {
-  if(mTextureSet)
-  {
-    mTextureSet = nullptr;
-  }
   if(mShader)
   {
-    mShader->RemoveConnectionObserver(*this);
+    mShader->RemoveUniformMapObserver(*this);
     mShader = nullptr;
   }
 }
@@ -177,55 +121,21 @@ void Renderer::operator delete(void* ptr)
 
 bool Renderer::PrepareRender(BufferIndex updateBufferIndex)
 {
-  if(mRegenerateUniformMap == UNIFORM_MAP_READY)
+  bool rendererUpdated = mResendFlag || mRenderingBehavior == DevelRenderer::Rendering::CONTINUOUSLY || mUpdateDecay > 0;
+
+  if(mUniformMapChangeCounter != mUniformMaps.GetChangeCounter())
   {
-    mUniformMapChanged[updateBufferIndex] = false;
+    // The map has changed since the last time we checked.
+    rendererUpdated          = true;
+    mRegenerateUniformMap    = true;
+    mUpdateDecay             = Renderer::Decay::INITIAL; // Render at least twice if the map has changed/actor has been added
+    mUniformMapChangeCounter = mUniformMaps.GetChangeCounter();
   }
-  else
+  if(mUpdateDecay > 0)
   {
-    if(mRegenerateUniformMap == REGENERATE_UNIFORM_MAP)
-    {
-      CollectedUniformMap& localMap = mCollectedUniformMap[updateBufferIndex];
-      localMap.Clear();
-
-      const UniformMap& rendererUniformMap = PropertyOwner::GetUniformMap();
-
-      auto size = rendererUniformMap.Count();
-      if(mShader)
-      {
-        size += mShader->GetUniformMap().Count();
-      }
-
-      localMap.Reserve(size);
-
-      AddMappings(localMap, rendererUniformMap);
-
-      if(mShader)
-      {
-        AddMappings(localMap, mShader->GetUniformMap());
-      }
-    }
-    else if(mRegenerateUniformMap == COPY_UNIFORM_MAP)
-    {
-      // Copy old map into current map
-      CollectedUniformMap& localMap = mCollectedUniformMap[updateBufferIndex];
-      CollectedUniformMap& oldMap   = mCollectedUniformMap[1 - updateBufferIndex];
-
-      localMap.Resize(oldMap.Count());
-
-      uint32_t index = 0;
-      for(CollectedUniformMap::Iterator iter = oldMap.Begin(), end = oldMap.End(); iter != end; ++iter, ++index)
-      {
-        localMap[index] = *iter;
-      }
-    }
-
-    mUniformMapChanged[updateBufferIndex] = true;
-    mRegenerateUniformMap--;
+    mUpdateDecay = static_cast<Renderer::Decay>(static_cast<int>(mUpdateDecay) - 1);
   }
 
-  bool rendererUpdated = mUniformMapChanged[updateBufferIndex] || mResendFlag || mRenderingBehavior == DevelRenderer::Rendering::CONTINUOUSLY;
-
   if(mResendFlag != 0)
   {
     if(mResendFlag & RESEND_GEOMETRY)
@@ -385,8 +295,7 @@ void Renderer::SetTextures(TextureSet* textureSet)
 {
   DALI_ASSERT_DEBUG(textureSet != NULL && "Texture set pointer is NULL");
 
-  mTextureSet           = textureSet;
-  mRegenerateUniformMap = REGENERATE_UNIFORM_MAP;
+  mTextureSet = textureSet;
 }
 
 const Vector<Render::Texture*>* Renderer::GetTextures() const
@@ -405,12 +314,12 @@ void Renderer::SetShader(Shader* shader)
 
   if(mShader)
   {
-    mShader->RemoveConnectionObserver(*this);
+    mShader->RemoveUniformMapObserver(*this);
   }
 
   mShader = shader;
-  mShader->AddConnectionObserver(*this);
-  mRegenerateUniformMap = REGENERATE_UNIFORM_MAP;
+  mShader->AddUniformMapObserver(*this);
+  mRegenerateUniformMap = true;
   mResendFlag |= RESEND_GEOMETRY | RESEND_SHADER;
 }
 
@@ -643,7 +552,7 @@ DevelRenderer::Rendering::Type Renderer::GetRenderingBehavior() const
 //Called when SceneGraph::Renderer is added to update manager ( that happens when an "event-thread renderer" is created )
 void Renderer::ConnectToSceneGraph(SceneController& sceneController, BufferIndex bufferIndex)
 {
-  mRegenerateUniformMap = REGENERATE_UNIFORM_MAP;
+  mRegenerateUniformMap = true;
   mSceneController      = &sceneController;
 
   mRenderer = Render::Renderer::New(this, mGeometry, mBlendBitmask, GetBlendColor(), static_cast<FaceCullingMode::Type>(mFaceCullingMode), mPremultipledAlphaEnabled, mDepthWriteMode, mDepthTestMode, mDepthFunction, mStencilParameters);
@@ -669,11 +578,6 @@ Render::Renderer& Renderer::GetRenderer()
   return *mRenderer;
 }
 
-const CollectedUniformMap& Renderer::GetUniformMap(BufferIndex bufferIndex) const
-{
-  return mCollectedUniformMap[bufferIndex];
-}
-
 Renderer::OpacityType Renderer::GetOpacityType(BufferIndex updateBufferIndex, const Node& node) const
 {
   Renderer::OpacityType opacityType = Renderer::OPAQUE;
@@ -741,30 +645,34 @@ Renderer::OpacityType Renderer::GetOpacityType(BufferIndex updateBufferIndex, co
   return opacityType;
 }
 
-void Renderer::ConnectionsChanged(PropertyOwner& object)
+bool Renderer::UpdateUniformMap()
 {
-  // One of our child objects has changed it's connections. Ensure the uniform
-  // map gets regenerated during PrepareRender
-  mRegenerateUniformMap = REGENERATE_UNIFORM_MAP;
-}
+  bool updated = false;
 
-void Renderer::ConnectedUniformMapChanged()
-{
-  mRegenerateUniformMap = REGENERATE_UNIFORM_MAP;
-}
+  if(mRegenerateUniformMap)
+  {
+    CollectedUniformMap& localMap = mCollectedUniformMap;
+    localMap.Clear();
 
-void Renderer::UniformMappingsChanged(const UniformMap& mappings)
-{
-  // The mappings are either from PropertyOwner base class, or the Actor
-  mRegenerateUniformMap = REGENERATE_UNIFORM_MAP;
-}
+    const UniformMap& rendererUniformMap = PropertyOwner::GetUniformMap();
 
-void Renderer::ObservedObjectDestroyed(PropertyOwner& owner)
-{
-  if(reinterpret_cast<PropertyOwner*>(mShader) == &owner)
-  {
-    mShader = nullptr;
+    auto size = rendererUniformMap.Count();
+    if(mShader)
+    {
+      size += mShader->GetUniformMap().Count();
+    }
+
+    localMap.Reserve(size);
+    localMap.AddMappings(rendererUniformMap);
+    if(mShader)
+    {
+      localMap.AddMappings(mShader->GetUniformMap());
+    }
+    localMap.UpdateChangeCounter();
+    mRegenerateUniformMap = false;
+    updated               = true;
   }
+  return updated;
 }
 
 void Renderer::SetDrawCommands(Dali::DevelRenderer::DrawCommand* pDrawCommands, uint32_t size)
@@ -774,6 +682,17 @@ void Renderer::SetDrawCommands(Dali::DevelRenderer::DrawCommand* pDrawCommands,
   mResendFlag |= RESEND_DRAW_COMMANDS;
 }
 
+void Renderer::UniformMappingsChanged(const UniformMap& mappings)
+{
+  // The mappings are either from PropertyOwner base class, or the Shader
+  mRegenerateUniformMap = true; // Should remain true until this renderer is added to a RenderList.
+}
+
+const CollectedUniformMap& Renderer::GetCollectedUniformMap() const
+{
+  return mCollectedUniformMap;
+}
+
 } // namespace SceneGraph
 } // namespace Internal
 } // namespace Dali
index b7c1aef..746ef1e 100644 (file)
@@ -26,7 +26,6 @@
 #include <dali/internal/render/renderers/render-renderer.h>
 #include <dali/internal/update/common/animatable-property.h>
 #include <dali/internal/update/common/property-owner.h>
-#include <dali/internal/update/common/scene-graph-connection-change-propagator.h>
 #include <dali/internal/update/common/uniform-map.h>
 #include <dali/public-api/rendering/geometry.h>
 #include <dali/public-api/rendering/renderer.h> // Dali::Renderer
@@ -56,8 +55,7 @@ class Geometry;
 class Renderer : public PropertyOwner,
                  public UniformMapDataProvider,
                  public RenderDataProvider,
-                 public UniformMap::Observer,
-                 public ConnectionChangePropagator::Observer
+                 public UniformMap::Observer
 {
 public:
   enum OpacityType
@@ -398,16 +396,19 @@ public:
     return mRenderCallback;
   }
 
-public: // Implementation of ConnectionChangePropagator
   /**
-   * @copydoc ConnectionChangePropagator::AddObserver
+   * Merge shader uniform map into renderer uniform map if any of the
+   * maps have changed.  Only update uniform map if added to render
+   * instructions.
+   *
+   * @return true if map has been updated, false otherwise
    */
-  void AddConnectionObserver(ConnectionChangePropagator::Observer& observer){};
+  bool UpdateUniformMap();
 
   /**
-   * @copydoc ConnectionChangePropagator::RemoveObserver
+   * Set the given external draw commands on this renderer.
    */
-  void RemoveConnectionObserver(ConnectionChangePropagator::Observer& observer){};
+  void SetDrawCommands(Dali::DevelRenderer::DrawCommand* pDrawCommands, uint32_t size);
 
 public: // UniformMap::Observer
   /**
@@ -415,22 +416,6 @@ public: // UniformMap::Observer
    */
   void UniformMappingsChanged(const UniformMap& mappings) override;
 
-public: // ConnectionChangePropagator::Observer
-  /**
-   * @copydoc ConnectionChangePropagator::ConnectionsChanged
-   */
-  void ConnectionsChanged(PropertyOwner& owner) override;
-
-  /**
-   * @copydoc ConnectionChangePropagator::ConnectedUniformMapChanged
-   */
-  void ConnectedUniformMapChanged() override;
-
-  /**
-   * @copydoc ConnectionChangePropagator::ConnectedUniformMapChanged
-   */
-  void ObservedObjectDestroyed(PropertyOwner& owner) override;
-
 public: // PropertyOwner implementation
   /**
    * @copydoc Dali::Internal::SceneGraph::PropertyOwner::ResetDefaultProperties()
@@ -439,19 +424,9 @@ public: // PropertyOwner implementation
 
 public: // From UniformMapDataProvider
   /**
-   * @copydoc UniformMapDataProvider::GetUniformMapChanged
+   * @copydoc UniformMapDataProvider::GetCollectedUniformMap
    */
-  bool GetUniformMapChanged(BufferIndex bufferIndex) const override
-  {
-    return mUniformMapChanged[bufferIndex];
-  }
-
-  /**
-   * @copydoc UniformMapDataProvider::GetUniformMap
-   */
-  const CollectedUniformMap& GetUniformMap(BufferIndex bufferIndex) const override;
-
-  void SetDrawCommands(Dali::DevelRenderer::DrawCommand* pDrawCommands, uint32_t size);
+  const CollectedUniformMap& GetCollectedUniformMap() const override;
 
 public: // For VisualProperties
   /**
@@ -477,7 +452,15 @@ private:
   Renderer();
 
 private:
-  CollectedUniformMap mCollectedUniformMap[2]; ///< Uniform maps collected by the renderer
+  enum Decay
+  {
+    DONE    = 0,
+    LAST    = 1,
+    INITIAL = 2
+  };
+
+private:
+  CollectedUniformMap mCollectedUniformMap; ///< Uniform maps collected by the renderer
 
   SceneController*                            mSceneController;           ///< Used for initializing renderers
   Render::Renderer*                           mRenderer;                  ///< Raw pointer to the renderer (that's owned by RenderManager)
@@ -489,21 +472,22 @@ private:
 
   Dali::Internal::Render::Renderer::StencilParameters mStencilParameters; ///< Struct containing all stencil related options
 
-  uint32_t mIndexedDrawFirstElement;  ///< first element index to be drawn using indexed draw
-  uint32_t mIndexedDrawElementsCount; ///< number of elements to be drawn using indexed draw
-  uint32_t mBlendBitmask;             ///< The bitmask of blending options
-  uint32_t mRegenerateUniformMap;     ///< 2 if the map should be regenerated, 1 if it should be copied.
-  uint32_t mResendFlag;               ///< Indicate whether data should be resent to the renderer
-
-  DepthFunction::Type            mDepthFunction : 4;            ///< Local copy of the depth function
-  FaceCullingMode::Type          mFaceCullingMode : 3;          ///< Local copy of the mode of face culling
-  BlendMode::Type                mBlendMode : 3;                ///< Local copy of the mode of blending
-  DepthWriteMode::Type           mDepthWriteMode : 3;           ///< Local copy of the depth write mode
-  DepthTestMode::Type            mDepthTestMode : 3;            ///< Local copy of the depth test mode
-  DevelRenderer::Rendering::Type mRenderingBehavior : 2;        ///< The rendering behavior
-  bool                           mUniformMapChanged[2];         ///< Records if the uniform map has been altered this frame
-  bool                           mPremultipledAlphaEnabled : 1; ///< Flag indicating whether the Pre-multiplied Alpha Blending is required
-
+  uint32_t mIndexedDrawFirstElement;     ///< first element index to be drawn using indexed draw
+  uint32_t mIndexedDrawElementsCount;    ///< number of elements to be drawn using indexed draw
+  uint32_t mBlendBitmask;                ///< The bitmask of blending options
+  uint32_t mResendFlag;                  ///< Indicate whether data should be resent to the renderer
+  uint32_t mUniformMapChangeCounter{0u}; ///< Value to check if uniform data should be updated
+
+  DepthFunction::Type            mDepthFunction : 4;     ///< Local copy of the depth function
+  FaceCullingMode::Type          mFaceCullingMode : 3;   ///< Local copy of the mode of face culling
+  BlendMode::Type                mBlendMode : 3;         ///< Local copy of the mode of blending
+  DepthWriteMode::Type           mDepthWriteMode : 3;    ///< Local copy of the depth write mode
+  DepthTestMode::Type            mDepthTestMode : 3;     ///< Local copy of the depth test mode
+  DevelRenderer::Rendering::Type mRenderingBehavior : 2; ///< The rendering behavior
+  Decay                          mUpdateDecay : 2;       ///< Update decay (aging)
+
+  bool                                          mRegenerateUniformMap : 1;     ///< true if the map should be regenerated
+  bool                                          mPremultipledAlphaEnabled : 1; ///< Flag indicating whether the Pre-multiplied Alpha Blending is required
   std::vector<Dali::DevelRenderer::DrawCommand> mDrawCommands;
   Dali::RenderCallback*                         mRenderCallback{nullptr};