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;
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>
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>
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>
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>
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>
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
--- /dev/null
+#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
#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>
{
}
- ~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
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;
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);
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)
{
// 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(); });
}
}
}