Reducing message spam for baked properties 08/288208/4
authorDavid Steele <david.steele@samsung.com>
Mon, 13 Feb 2023 23:07:01 +0000 (23:07 +0000)
committerDavid Steele <david.steele@samsung.com>
Fri, 17 Feb 2023 10:25:37 +0000 (10:25 +0000)
Adding custom message to bake property and create
resetter in update side.

Switched resetters to use std::list for faster erasure.

Change-Id: I8783ad293458f97cce45ebe00b6ef47ac3aed8fb

dali/internal/event/rendering/renderer-impl.cpp
dali/internal/update/common/animatable-property-messages.h
dali/internal/update/manager/resetter-container.h [new file with mode: 0644]
dali/internal/update/manager/update-manager.cpp

index 5dbcab4697ef2381391f43bbca64c474ef04c6fc..0865182dab43a021cb9d2c357a6b7b4bd96ed890 100644 (file)
@@ -667,12 +667,6 @@ void Renderer::SetDefaultProperty(Property::Index        index,
           mOpacity         = opacity;
           auto sceneObject = const_cast<SceneGraph::Renderer*>(&GetRendererSceneObject());
           SceneGraph::BakeOpacityMessage(GetEventThreadServices(), *sceneObject, mOpacity);
-
-          OwnerPointer<SceneGraph::PropertyResetterBase> resetter(
-            new SceneGraph::BakerResetter(sceneObject,
-                                          &sceneObject->mOpacity,
-                                          SceneGraph::BakerResetter::Lifetime::BAKE));
-          AddResetterMessage(GetEventThreadServices().GetUpdateManager(), resetter);
         }
       }
       break;
index 57ce8d0a1c3ede6258b51f4ff2be336a95385f87..e18a3fd096cde643788a8fc6d27d73695c3266f2 100644 (file)
 
 namespace Dali::Internal
 {
-// Messages for AnimatableProperty<T>
 
-template<class T>
+/**
+ * Special message to first bake a property, then create a resetter for the
+ * property in the update thread to reduce load on event thread.
+ * @tparam T The type of the property
+ * @tparam P2 The type of the parameter to the second object method
+ */
+template<class T, typename P>
+class MessageBakeReset : public MessageBase
+{
+public:
+  using MemberFunction = void (T::*)(BufferIndex, typename ParameterType<P>::PassingType);
+
+  /**
+   * Create a message.
+   * @note The object is expected to be const in the thread which sends this message.
+   * However it can be modified when Process() is called in a different thread.
+   * @param[in] updateManager
+   * @param[in] propertyOwner The owner of the property
+   * @param[in] property The property to update
+   * @param[in] member The member function of the property object (bake/set)
+   * @param[in] p The value to update the property to
+   */
+  MessageBakeReset(SceneGraph::UpdateManager&             updateManager,
+                   const SceneGraph::PropertyOwner&       propertyOwner,
+                   const T*                               property,
+                   MemberFunction                         member,
+                   typename ParameterType<P>::PassingType p)
+  : MessageBase(),
+    mUpdateManager(updateManager),
+    mPropertyOwner(propertyOwner),
+    object(const_cast<T*>(property)),
+    memberFunction(member),
+    param(p)
+  {
+    DALI_ASSERT_DEBUG(property && "nullptr passed into message as property");
+  }
+
+  /**
+   * Virtual destructor
+   */
+  ~MessageBakeReset() override = default;
+
+  /**
+   * @copydoc MessageBase::Process
+   */
+  void Process(BufferIndex bufferIndex) override
+  {
+    // Bake/set the property
+    (object->*memberFunction)(bufferIndex, param);
+
+    // Create the resetter in the Update thread.
+    OwnerPointer<SceneGraph::PropertyResetterBase> resetter(
+      new SceneGraph::BakerResetter(const_cast<SceneGraph::PropertyOwner*>(&mPropertyOwner),
+                                    object,
+                                    SceneGraph::BakerResetter::Lifetime::BAKE));
+    mUpdateManager.AddPropertyResetter(resetter);
+  }
+
+private:
+  SceneGraph::UpdateManager&            mUpdateManager;
+  const SceneGraph::PropertyOwner&      mPropertyOwner;
+  T*                                    object;
+  MemberFunction                        memberFunction;
+  typename ParameterType<P>::HolderType param;
+};
+
+template<typename T>
 void BakeMessage(EventThreadServices&                     eventThreadServices,
                  const SceneGraph::PropertyOwner&         propertyOwner,
                  const SceneGraph::AnimatableProperty<T>& property,
                  typename ParameterType<T>::PassingType   newValue)
 {
-  using LocalType = MessageDoubleBuffered1<SceneGraph::AnimatableProperty<T>, T>;
+  using LocalType = MessageBakeReset<SceneGraph::AnimatableProperty<T>, T>;
 
   // Reserve some memory inside the message queue
   uint32_t* slot = eventThreadServices.ReserveMessageSlot(sizeof(LocalType));
 
   // Construct message in the message queue memory; note that delete should not be called on the return value
-  new(slot) LocalType(&property,
+  new(slot) LocalType(eventThreadServices.GetUpdateManager(),
+                      propertyOwner,
+                      &property,
                       &SceneGraph::AnimatableProperty<T>::Bake,
                       newValue);
-
-  OwnerPointer<SceneGraph::PropertyResetterBase> resetter(
-    new SceneGraph::BakerResetter(const_cast<SceneGraph::PropertyOwner*>(&propertyOwner),
-                                  const_cast<SceneGraph::AnimatableProperty<T>*>(&property),
-                                  SceneGraph::BakerResetter::Lifetime::BAKE));
-  AddResetterMessage(eventThreadServices.GetUpdateManager(), resetter);
 }
 
 template<class T>
@@ -57,21 +118,17 @@ void BakeRelativeMessage(EventThreadServices&                     eventThreadSer
                          const SceneGraph::AnimatableProperty<T>& property,
                          const T&                                 delta)
 {
-  using LocalType = MessageDoubleBuffered1<SceneGraph::AnimatableProperty<T>, const T&>;
+  using LocalType = MessageBakeReset<SceneGraph::AnimatableProperty<T>, T>;
 
   // Reserve some memory inside the message queue
   uint32_t* slot = eventThreadServices.ReserveMessageSlot(sizeof(LocalType));
 
   // Construct message in the message queue memory; note that delete should not be called on the return value
-  new(slot) LocalType(&property,
+  new(slot) LocalType(eventThreadServices.GetUpdateManager(),
+                      propertyOwner,
+                      &property,
                       &SceneGraph::AnimatableProperty<T>::BakeRelative,
                       delta);
-
-  OwnerPointer<SceneGraph::PropertyResetterBase> resetter(
-    new SceneGraph::BakerResetter(const_cast<SceneGraph::PropertyOwner*>(&propertyOwner),
-                                  const_cast<SceneGraph::AnimatableProperty<T>*>(&property),
-                                  SceneGraph::BakerResetter::Lifetime::BAKE));
-  AddResetterMessage(eventThreadServices.GetUpdateManager(), resetter);
 }
 
 template<class T>
@@ -80,21 +137,17 @@ void SetXComponentMessage(EventThreadServices&                       eventThread
                           const SceneGraph::AnimatableProperty<T>&   property,
                           typename ParameterType<float>::PassingType newValue)
 {
-  using LocalType = MessageDoubleBuffered1<SceneGraph::AnimatableProperty<T>, float>;
+  using LocalType = MessageBakeReset<SceneGraph::AnimatableProperty<T>, float>;
 
   // Reserve some memory inside the message queue
   uint32_t* slot = eventThreadServices.ReserveMessageSlot(sizeof(LocalType));
 
   // Construct message in the message queue memory; note that delete should not be called on the return value
-  new(slot) LocalType(&property,
+  new(slot) LocalType(eventThreadServices.GetUpdateManager(),
+                      propertyOwner,
+                      &property,
                       &SceneGraph::AnimatableProperty<T>::BakeX,
                       newValue);
-
-  OwnerPointer<SceneGraph::PropertyResetterBase> resetter(
-    new SceneGraph::BakerResetter(const_cast<SceneGraph::PropertyOwner*>(&propertyOwner),
-                                  const_cast<SceneGraph::AnimatableProperty<T>*>(&property),
-                                  SceneGraph::BakerResetter::Lifetime::BAKE));
-  AddResetterMessage(eventThreadServices.GetUpdateManager(), resetter);
 }
 
 template<class T>
@@ -103,21 +156,17 @@ void SetYComponentMessage(EventThreadServices&                       eventThread
                           const SceneGraph::AnimatableProperty<T>&   property,
                           typename ParameterType<float>::PassingType newValue)
 {
-  using LocalType = MessageDoubleBuffered1<SceneGraph::AnimatableProperty<T>, float>;
+  using LocalType = MessageBakeReset<SceneGraph::AnimatableProperty<T>, float>;
 
   // Reserve some memory inside the message queue
   uint32_t* slot = eventThreadServices.ReserveMessageSlot(sizeof(LocalType));
 
   // Construct message in the message queue memory; note that delete should not be called on the return value
-  new(slot) LocalType(&property,
+  new(slot) LocalType(eventThreadServices.GetUpdateManager(),
+                      propertyOwner,
+                      &property,
                       &SceneGraph::AnimatableProperty<T>::BakeY,
                       newValue);
-
-  OwnerPointer<SceneGraph::PropertyResetterBase> resetter(
-    new SceneGraph::BakerResetter(const_cast<SceneGraph::PropertyOwner*>(&propertyOwner),
-                                  const_cast<SceneGraph::AnimatableProperty<T>*>(&property),
-                                  SceneGraph::BakerResetter::Lifetime::BAKE));
-  AddResetterMessage(eventThreadServices.GetUpdateManager(), resetter);
 }
 
 template<class T>
@@ -126,21 +175,17 @@ void SetZComponentMessage(EventThreadServices&                       eventThread
                           const SceneGraph::AnimatableProperty<T>&   property,
                           typename ParameterType<float>::PassingType newValue)
 {
-  using LocalType = MessageDoubleBuffered1<SceneGraph::AnimatableProperty<T>, float>;
+  using LocalType = MessageBakeReset<SceneGraph::AnimatableProperty<T>, float>;
 
   // Reserve some memory inside the message queue
   uint32_t* slot = eventThreadServices.ReserveMessageSlot(sizeof(LocalType));
 
   // Construct message in the message queue memory; note that delete should not be called on the return value
-  new(slot) LocalType(&property,
+  new(slot) LocalType(eventThreadServices.GetUpdateManager(),
+                      propertyOwner,
+                      &property,
                       &SceneGraph::AnimatableProperty<T>::BakeZ,
                       newValue);
-
-  OwnerPointer<SceneGraph::PropertyResetterBase> resetter(
-    new SceneGraph::BakerResetter(const_cast<SceneGraph::PropertyOwner*>(&propertyOwner),
-                                  const_cast<SceneGraph::AnimatableProperty<T>*>(&property),
-                                  SceneGraph::BakerResetter::Lifetime::BAKE));
-  AddResetterMessage(eventThreadServices.GetUpdateManager(), resetter);
 }
 
 template<class T>
@@ -149,23 +194,19 @@ void SetWComponentMessage(EventThreadServices&                       eventThread
                           const SceneGraph::AnimatableProperty<T>&   property,
                           typename ParameterType<float>::PassingType newValue)
 {
-  using LocalType = MessageDoubleBuffered1<SceneGraph::AnimatableProperty<T>, float>;
+  using LocalType = MessageBakeReset<SceneGraph::AnimatableProperty<T>, float>;
 
   // Reserve some memory inside the message queue
   uint32_t* slot = eventThreadServices.ReserveMessageSlot(sizeof(LocalType));
 
   // Construct message in the message queue memory; note that delete should not be called on the return value
-  new(slot) LocalType(&property,
+  new(slot) LocalType(eventThreadServices.GetUpdateManager(),
+                      propertyOwner,
+                      &property,
                       &SceneGraph::AnimatableProperty<T>::BakeW,
                       newValue);
-
-  OwnerPointer<SceneGraph::PropertyResetterBase> resetter(
-    new SceneGraph::BakerResetter(const_cast<SceneGraph::PropertyOwner*>(&propertyOwner),
-                                  const_cast<SceneGraph::AnimatableProperty<T>*>(&property),
-                                  SceneGraph::BakerResetter::Lifetime::BAKE));
-  AddResetterMessage(eventThreadServices.GetUpdateManager(), resetter);
 }
 
 } // namespace Dali::Internal
 
-#endif //DALI_INTERNAL_COMMON_ANIMATABLE_PROPERTY_MESSAGES_H
+#endif // DALI_INTERNAL_COMMON_ANIMATABLE_PROPERTY_MESSAGES_H
diff --git a/dali/internal/update/manager/resetter-container.h b/dali/internal/update/manager/resetter-container.h
new file mode 100644 (file)
index 0000000..9c042b1
--- /dev/null
@@ -0,0 +1,183 @@
+#ifndef DALI_INTERNAL_UPDATE_RESETTER_CONTAINER_H
+#define DALI_INTERNAL_UPDATE_RESETTER_CONTAINER_H
+
+/*
+ * Copyright (c) 2023 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.
+ */
+
+namespace Dali::Internal::SceneGraph
+{
+
+/**
+ * Template class to manage node/property resetters
+ */
+template<class ResetterType>
+class ResetterContainer
+{
+public:
+  // std::list offers fast delete and fast iteration.
+  using ContainerType = std::list<ResetterType*>;
+  using Iterator      = typename ContainerType::iterator;
+  using ConstIterator = typename ContainerType::const_iterator;
+
+  ResetterContainer() = default;
+
+  ResetterContainer(const ResetterContainer&) = delete;
+  ResetterContainer(ResetterContainer&&)      = delete;
+
+  /**
+   * Ensure all resetters are destroyed when the container is destroyed
+   */
+  ~ResetterContainer()
+  {
+    Clear();
+  }
+
+  /**
+   * Add a resetter to the container
+   * @param[in] resetterPtr A pointer to the resetter.
+   * The container takes ownership.
+   */
+  void PushBack(ResetterType* resetterPtr)
+  {
+    mContainer.push_back(resetterPtr);
+  }
+
+  /**
+   * @return true if the container is empty
+   */
+  bool Empty()
+  {
+    return mContainer.empty();
+  }
+
+  /**
+   * Clear the container, destroying all extant resetters.
+   */
+  void Clear()
+  {
+    auto iter = Begin();
+    while(iter != End())
+    {
+      iter = EraseObject(iter);
+    }
+  }
+
+  /**
+   * @return an iterator to the start of the container
+   */
+  Iterator Begin()
+  {
+    return mContainer.begin();
+  }
+  /**
+   * Support for C++11 Range-based for loop
+   * @return an iterator to the start of the container.
+   */
+  Iterator begin()
+  {
+    return mContainer.begin();
+  }
+  /**
+   * @return an iterator to the start of the container
+   */
+  ConstIterator Begin() const
+  {
+    return mContainer.begin();
+  }
+  /**
+   * Support for C++11 Range-based for loop
+   * @return an iterator to the start of the container.
+   */
+  ConstIterator begin() const
+  {
+    return mContainer.begin();
+  }
+
+  /**
+   * @return an iterator to the end of the container.
+   */
+  Iterator End()
+  {
+    return mContainer.end();
+  }
+  /**
+   * Support for C++11 Range-based for loop
+   * @return an iterator to the end of the container.
+   */
+  Iterator end()
+  {
+    return mContainer.end();
+  }
+  /**
+   * @return an iterator to the end of the container.
+   */
+  ConstIterator End() const
+  {
+    return mContainer.end();
+  }
+  /**
+   * Support for C++11 Range-based for loop
+   * @return an iterator to the end of the container.
+   */
+  ConstIterator end() const
+  {
+    return mContainer.end();
+  }
+
+  /**
+   * Erase a resetter from the container
+   */
+  Iterator EraseObject(Iterator iter)
+  {
+    delete *iter;
+    return mContainer.erase(iter);
+  }
+
+  /**
+   * Iterate over the container, resetting all the referenced
+   * properties. If a resetter has finished (e.g. it's animation /
+   * constraint has ended, or it's baked 2 values), then it is removed
+   * from the list.
+   * @param[in] bufferIndex The buffer index of the property to be reset
+   */
+  void ResetToBaseValues(BufferIndex bufferIndex)
+  {
+    if(!mContainer.empty())
+    {
+      auto end  = mContainer.end();
+      auto iter = mContainer.begin();
+      while(iter != end)
+      {
+        (*iter)->ResetToBaseValue(bufferIndex);
+        if((*iter)->IsFinished())
+        {
+          iter = EraseObject(iter);
+        }
+        else // Skip to next element
+        {
+          ++iter;
+        }
+      }
+    }
+  }
+
+private:
+  ContainerType mContainer; ///< The list of resetters
+};
+
+} // namespace Dali::Internal::SceneGraph
+
+#endif // DALI_INTERNAL_UPDATE_RESETTER_CONTAINER_H
index 72304ef3e4f28ac408f5679b4a2591d20f30cde8..184573bfef420a9074e676d90c2498fabf9cd008 100644 (file)
@@ -33,6 +33,7 @@
 #include <dali/internal/update/controllers/scene-controller-impl.h>
 #include <dali/internal/update/manager/frame-callback-processor.h>
 #include <dali/internal/update/manager/render-task-processor.h>
+#include <dali/internal/update/manager/resetter-container.h>
 #include <dali/internal/update/manager/transform-manager.h>
 #include <dali/internal/update/manager/update-algorithms.h>
 #include <dali/internal/update/manager/update-manager-debug.h>
@@ -145,11 +146,11 @@ struct UpdateManager::Impl
     {
     }
 
-    ~SceneInfo()               = default;                ///< Default non-virtual destructor
-    SceneInfo(SceneInfo&& rhs) = default;                ///< Move constructor
-    SceneInfo& operator=(SceneInfo&& rhs) = default;     ///< Move assignment operator
-    SceneInfo& operator=(const SceneInfo& rhs) = delete; ///< Assignment operator
-    SceneInfo(const SceneInfo& rhs)            = delete; ///< Copy constructor
+    ~SceneInfo()                               = default; ///< Default non-virtual destructor
+    SceneInfo(SceneInfo&& rhs)                 = default; ///< Move constructor
+    SceneInfo& operator=(SceneInfo&& rhs)      = default; ///< Move assignment operator
+    SceneInfo& operator=(const SceneInfo& rhs) = delete;  ///< Assignment operator
+    SceneInfo(const SceneInfo& rhs)            = delete;  ///< Copy constructor
 
     Layer*                       root{nullptr};   ///< Root node (root is a layer). The layer is not stored in the node memory pool.
     OwnerPointer<RenderTaskList> taskList;        ///< Scene graph render task list
@@ -278,13 +279,14 @@ struct UpdateManager::Impl
 
   OwnerContainer<PropertyOwner*> customObjects; ///< A container of owned objects (with custom properties)
 
-  OwnerContainer<PropertyResetterBase*> propertyResetters;     ///< A container of property resetters
-  OwnerContainer<NodeResetter*>         nodeResetters;         ///< A container of node resetters
-  OwnerContainer<Animation*>            animations;            ///< A container of owned animations
-  PropertyNotificationContainer         propertyNotifications; ///< A container of owner property notifications.
-  OwnerKeyContainer<Renderer>           renderers;             ///< A container of owned renderers
-  OwnerContainer<TextureSet*>           textureSets;           ///< A container of owned texture sets
-  OwnerContainer<Shader*>               shaders;               ///< A container of owned shaders
+  ResetterContainer<PropertyResetterBase> propertyResetters; ///< A container of property resetters
+  ResetterContainer<NodeResetter>         nodeResetters;     ///< A container of node resetters
+
+  OwnerContainer<Animation*>    animations;            ///< A container of owned animations
+  PropertyNotificationContainer propertyNotifications; ///< A container of owner property notifications.
+  OwnerKeyContainer<Renderer>   renderers;             ///< A container of owned renderers
+  OwnerContainer<TextureSet*>   textureSets;           ///< A container of owned texture sets
+  OwnerContainer<Shader*>       shaders;               ///< A container of owned shaders
 
   DiscardQueue<Node*, OwnerContainer<Node*>>                         nodeDiscardQueue; ///< Nodes are added here when disconnected from the scene-graph.
   DiscardQueue<Shader*, OwnerContainer<Shader*>>                     shaderDiscardQueue;
@@ -348,7 +350,8 @@ void UpdateManager::InstallRoot(OwnerPointer<Layer>& layer)
 
   Layer* rootLayer = layer.Release();
 
-  DALI_ASSERT_DEBUG(std::find_if(mImpl->scenes.begin(), mImpl->scenes.end(), [rootLayer](Impl::SceneInfoPtr& scene) { return scene && scene->root == rootLayer; }) == mImpl->scenes.end() &&
+  DALI_ASSERT_DEBUG(std::find_if(mImpl->scenes.begin(), mImpl->scenes.end(), [rootLayer](Impl::SceneInfoPtr& scene)
+                                 { return scene && scene->root == rootLayer; }) == mImpl->scenes.end() &&
                     "Root Node already installed");
 
   rootLayer->CreateTransform(&mImpl->transformManager);
@@ -731,38 +734,10 @@ void UpdateManager::ResetProperties(BufferIndex bufferIndex)
   mImpl->animationFinishedDuringUpdate = false;
 
   // Reset node properties
-  std::vector<NodeResetter*> nodeResetterToDelete;
-  for(auto&& element : mImpl->nodeResetters)
-  {
-    element->ResetToBaseValue(bufferIndex);
-    if(element->IsFinished())
-    {
-      nodeResetterToDelete.push_back(element);
-    }
-  }
-
-  // If a node resetter is no longer required, delete it.
-  for(auto&& elementPtr : nodeResetterToDelete)
-  {
-    mImpl->nodeResetters.EraseObject(elementPtr);
-  }
+  mImpl->nodeResetters.ResetToBaseValues(bufferIndex);
 
   // Reset all animating / constrained properties
-  std::vector<PropertyResetterBase*> propertyResettertoDelete;
-  for(auto&& element : mImpl->propertyResetters)
-  {
-    element->ResetToBaseValue(bufferIndex);
-    if(element->IsFinished())
-    {
-      propertyResettertoDelete.push_back(element);
-    }
-  }
-
-  // If a property resetter is no longer required (the animator or constraint has been removed), delete it.
-  for(auto&& elementPtr : propertyResettertoDelete)
-  {
-    mImpl->propertyResetters.EraseObject(elementPtr);
-  }
+  mImpl->propertyResetters.ResetToBaseValues(bufferIndex);
 
   // Clear all root nodes dirty flags
   for(auto& scene : mImpl->scenes)
@@ -1273,7 +1248,8 @@ void UpdateManager::SetDepthIndices(OwnerPointer<NodeDepths>& nodeDepths)
     {
       // Reorder children container only if sibiling order changed.
       NodeContainer& container = node->GetChildren();
-      std::sort(container.Begin(), container.End(), [](Node* a, Node* b) { return a->GetDepthIndex() < b->GetDepthIndex(); });
+      std::sort(container.Begin(), container.End(), [](Node* a, Node* b)
+                { return a->GetDepthIndex() < b->GetDepthIndex(); });
     }
   }
 }