From 73be98e87b776b94bfe1e9961efea3cf0f7cd109 Mon Sep 17 00:00:00 2001 From: David Steele Date: Mon, 13 Feb 2023 23:07:01 +0000 Subject: [PATCH] Reducing message spam for baked properties 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 | 6 - .../update/common/animatable-property-messages.h | 143 ++++++++++------ dali/internal/update/manager/resetter-container.h | 183 +++++++++++++++++++++ dali/internal/update/manager/update-manager.cpp | 64 +++---- 4 files changed, 295 insertions(+), 101 deletions(-) create mode 100644 dali/internal/update/manager/resetter-container.h diff --git a/dali/internal/event/rendering/renderer-impl.cpp b/dali/internal/event/rendering/renderer-impl.cpp index 5dbcab4..0865182 100644 --- a/dali/internal/event/rendering/renderer-impl.cpp +++ b/dali/internal/event/rendering/renderer-impl.cpp @@ -667,12 +667,6 @@ void Renderer::SetDefaultProperty(Property::Index index, mOpacity = opacity; auto sceneObject = const_cast(&GetRendererSceneObject()); SceneGraph::BakeOpacityMessage(GetEventThreadServices(), *sceneObject, mOpacity); - - OwnerPointer resetter( - new SceneGraph::BakerResetter(sceneObject, - &sceneObject->mOpacity, - SceneGraph::BakerResetter::Lifetime::BAKE)); - AddResetterMessage(GetEventThreadServices().GetUpdateManager(), resetter); } } break; diff --git a/dali/internal/update/common/animatable-property-messages.h b/dali/internal/update/common/animatable-property-messages.h index 57ce8d0..e18a3fd 100644 --- a/dali/internal/update/common/animatable-property-messages.h +++ b/dali/internal/update/common/animatable-property-messages.h @@ -26,29 +26,90 @@ namespace Dali::Internal { -// Messages for AnimatableProperty -template +/** + * 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 MessageBakeReset : public MessageBase +{ +public: + using MemberFunction = void (T::*)(BufferIndex, typename ParameterType

::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

::PassingType p) + : MessageBase(), + mUpdateManager(updateManager), + mPropertyOwner(propertyOwner), + object(const_cast(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 resetter( + new SceneGraph::BakerResetter(const_cast(&mPropertyOwner), + object, + SceneGraph::BakerResetter::Lifetime::BAKE)); + mUpdateManager.AddPropertyResetter(resetter); + } + +private: + SceneGraph::UpdateManager& mUpdateManager; + const SceneGraph::PropertyOwner& mPropertyOwner; + T* object; + MemberFunction memberFunction; + typename ParameterType

::HolderType param; +}; + +template void BakeMessage(EventThreadServices& eventThreadServices, const SceneGraph::PropertyOwner& propertyOwner, const SceneGraph::AnimatableProperty& property, typename ParameterType::PassingType newValue) { - using LocalType = MessageDoubleBuffered1, T>; + using LocalType = MessageBakeReset, 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::Bake, newValue); - - OwnerPointer resetter( - new SceneGraph::BakerResetter(const_cast(&propertyOwner), - const_cast*>(&property), - SceneGraph::BakerResetter::Lifetime::BAKE)); - AddResetterMessage(eventThreadServices.GetUpdateManager(), resetter); } template @@ -57,21 +118,17 @@ void BakeRelativeMessage(EventThreadServices& eventThreadSer const SceneGraph::AnimatableProperty& property, const T& delta) { - using LocalType = MessageDoubleBuffered1, const T&>; + using LocalType = MessageBakeReset, 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::BakeRelative, delta); - - OwnerPointer resetter( - new SceneGraph::BakerResetter(const_cast(&propertyOwner), - const_cast*>(&property), - SceneGraph::BakerResetter::Lifetime::BAKE)); - AddResetterMessage(eventThreadServices.GetUpdateManager(), resetter); } template @@ -80,21 +137,17 @@ void SetXComponentMessage(EventThreadServices& eventThread const SceneGraph::AnimatableProperty& property, typename ParameterType::PassingType newValue) { - using LocalType = MessageDoubleBuffered1, float>; + using LocalType = MessageBakeReset, 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::BakeX, newValue); - - OwnerPointer resetter( - new SceneGraph::BakerResetter(const_cast(&propertyOwner), - const_cast*>(&property), - SceneGraph::BakerResetter::Lifetime::BAKE)); - AddResetterMessage(eventThreadServices.GetUpdateManager(), resetter); } template @@ -103,21 +156,17 @@ void SetYComponentMessage(EventThreadServices& eventThread const SceneGraph::AnimatableProperty& property, typename ParameterType::PassingType newValue) { - using LocalType = MessageDoubleBuffered1, float>; + using LocalType = MessageBakeReset, 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::BakeY, newValue); - - OwnerPointer resetter( - new SceneGraph::BakerResetter(const_cast(&propertyOwner), - const_cast*>(&property), - SceneGraph::BakerResetter::Lifetime::BAKE)); - AddResetterMessage(eventThreadServices.GetUpdateManager(), resetter); } template @@ -126,21 +175,17 @@ void SetZComponentMessage(EventThreadServices& eventThread const SceneGraph::AnimatableProperty& property, typename ParameterType::PassingType newValue) { - using LocalType = MessageDoubleBuffered1, float>; + using LocalType = MessageBakeReset, 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::BakeZ, newValue); - - OwnerPointer resetter( - new SceneGraph::BakerResetter(const_cast(&propertyOwner), - const_cast*>(&property), - SceneGraph::BakerResetter::Lifetime::BAKE)); - AddResetterMessage(eventThreadServices.GetUpdateManager(), resetter); } template @@ -149,23 +194,19 @@ void SetWComponentMessage(EventThreadServices& eventThread const SceneGraph::AnimatableProperty& property, typename ParameterType::PassingType newValue) { - using LocalType = MessageDoubleBuffered1, float>; + using LocalType = MessageBakeReset, 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::BakeW, newValue); - - OwnerPointer resetter( - new SceneGraph::BakerResetter(const_cast(&propertyOwner), - const_cast*>(&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 index 0000000..9c042b1 --- /dev/null +++ b/dali/internal/update/manager/resetter-container.h @@ -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 ResetterContainer +{ +public: + // std::list offers fast delete and fast iteration. + using ContainerType = std::list; + 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 diff --git a/dali/internal/update/manager/update-manager.cpp b/dali/internal/update/manager/update-manager.cpp index 72304ef..184573b 100644 --- a/dali/internal/update/manager/update-manager.cpp +++ b/dali/internal/update/manager/update-manager.cpp @@ -33,6 +33,7 @@ #include #include #include +#include #include #include #include @@ -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 taskList; ///< Scene graph render task list @@ -278,13 +279,14 @@ struct UpdateManager::Impl OwnerContainer customObjects; ///< A container of owned objects (with custom properties) - OwnerContainer propertyResetters; ///< A container of property resetters - OwnerContainer nodeResetters; ///< A container of node resetters - OwnerContainer animations; ///< A container of owned animations - PropertyNotificationContainer propertyNotifications; ///< A container of owner property notifications. - OwnerKeyContainer renderers; ///< A container of owned renderers - OwnerContainer textureSets; ///< A container of owned texture sets - OwnerContainer shaders; ///< A container of owned shaders + ResetterContainer propertyResetters; ///< A container of property resetters + ResetterContainer nodeResetters; ///< A container of node resetters + + OwnerContainer animations; ///< A container of owned animations + PropertyNotificationContainer propertyNotifications; ///< A container of owner property notifications. + OwnerKeyContainer renderers; ///< A container of owned renderers + OwnerContainer textureSets; ///< A container of owned texture sets + OwnerContainer shaders; ///< A container of owned shaders DiscardQueue> nodeDiscardQueue; ///< Nodes are added here when disconnected from the scene-graph. DiscardQueue> shaderDiscardQueue; @@ -348,7 +350,8 @@ void UpdateManager::InstallRoot(OwnerPointer& 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 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 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) { // 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(); }); } } } -- 2.7.4