${internal_src_dir}/update/manager/render-instruction-processor.cpp
${internal_src_dir}/update/manager/render-task-processor.cpp
${internal_src_dir}/update/manager/scene-graph-frame-callback.cpp
+ ${internal_src_dir}/update/manager/scene-graph-traveler.cpp
${internal_src_dir}/update/manager/transform-manager.cpp
${internal_src_dir}/update/manager/update-algorithms.cpp
${internal_src_dir}/update/manager/update-manager.cpp
// INTERNAL INCLUDES
#include <dali/devel-api/update/frame-callback-interface.h>
#include <dali/devel-api/update/update-proxy.h>
+#include <dali/integration-api/debug.h>
#include <dali/integration-api/trace.h>
namespace
: mFrameCallbacks(),
mUpdateManager(updateManager),
mTransformManager(transformManager),
+ mTravelerMap{},
mNodeHierarchyChanged(true)
{
}
{
Node& node = const_cast<Node&>(*rootNode); // Was sent as const from event thread, we need to be able to use non-const version here.
- frameCallback->ConnectToSceneGraph(mUpdateManager, mTransformManager, node);
+ SceneGraphTravelerPtr traveler = GetSceneGraphTraveler(&node);
+
+ frameCallback->ConnectToSceneGraph(mUpdateManager, mTransformManager, node, traveler);
mFrameCallbacks.emplace_back(frameCallback);
}
{
bool keepRendering = false;
+ if(mNodeHierarchyChanged)
+ {
+ DALI_LOG_DEBUG_INFO("Node hierarchy changed. Update traveler map\n");
+ // Clear node traveler
+ for(auto iter = mTravelerMap.begin(); iter != mTravelerMap.end();)
+ {
+ // We don't need to erase invalidated traveler always. Just erase now.
+ // Note : ReferenceCount == 1 mean, no frame callbacks use this traveler now. We can erase it.
+ if(iter->second->IsInvalidated() || iter->second->ReferenceCount() == 1u)
+ {
+ iter = mTravelerMap.erase(iter);
+ }
+ else
+ {
+ (iter++)->second->NodeHierarchyChanged();
+ }
+ }
+ }
+
if(!mFrameCallbacks.empty())
{
DALI_TRACE_SCOPE(gTraceFilter, "DALI_FRAME_CALLBACK_UPDATE");
return keepRendering;
}
+SceneGraphTravelerPtr FrameCallbackProcessor::GetSceneGraphTraveler(Node* rootNode)
+{
+ auto iter = mTravelerMap.find(rootNode);
+
+ if(iter != mTravelerMap.end())
+ {
+ // Check wheter traveler is invalidated or not
+ if(!iter->second->IsInvalidated())
+ {
+ return iter->second;
+ }
+ else
+ {
+ mTravelerMap.erase(iter);
+ }
+ }
+
+ // Create new traveler and keep it.
+ return (mTravelerMap.insert({rootNode, new SceneGraphTraveler(*rootNode)})).first->second;
+}
+
} // namespace SceneGraph
} // namespace Internal
// EXTERNAL INCLUDES
#include <memory>
+#include <unordered_map>
// INTERNAL INCLUDES
#include <dali/internal/common/buffer-index.h>
#include <dali/internal/common/owner-pointer.h>
#include <dali/internal/update/manager/scene-graph-frame-callback.h>
+#include <dali/internal/update/manager/scene-graph-traveler.h>
#include <dali/internal/update/manager/update-proxy-impl.h>
#include <dali/public-api/common/vector-wrapper.h>
}
private:
+ SceneGraphTravelerPtr GetSceneGraphTraveler(Node* rootNode);
+
+private:
std::vector<OwnerPointer<FrameCallback> > mFrameCallbacks; ///< A container of all the frame-callbacks & accompanying update-proxies.
UpdateManager& mUpdateManager;
TransformManager& mTransformManager;
+ using TravelerContainer = std::unordered_map<const Node*, SceneGraphTravelerPtr>;
+ TravelerContainer mTravelerMap;
+
bool mNodeHierarchyChanged; ///< Set to true if the node hierarchy changes
};
Invalidate();
}
-void FrameCallback::ConnectToSceneGraph(UpdateManager& updateManager, TransformManager& transformManager, Node& rootNode)
+void FrameCallback::ConnectToSceneGraph(UpdateManager& updateManager, TransformManager& transformManager, Node& rootNode, SceneGraphTravelerPtr traveler)
{
- mUpdateProxy = std::unique_ptr<UpdateProxy>(new UpdateProxy(updateManager, transformManager, rootNode));
+ mUpdateProxy = std::unique_ptr<UpdateProxy>(new UpdateProxy(updateManager, transformManager, rootNode, traveler));
rootNode.AddObserver(*this);
}
#include <dali/devel-api/update/frame-callback-interface.h>
#include <dali/internal/common/owner-pointer.h>
#include <dali/internal/update/common/property-owner.h>
+#include <dali/internal/update/manager/scene-graph-traveler.h>
#include <dali/internal/update/manager/update-proxy-impl.h>
#include <dali/public-api/common/list-wrapper.h>
* @param[in] updateManager The Update Manager
* @param[in] transformManager The Transform Manager
* @param[in] rootNode The rootNode of this frame-callback
+ * @param[in] traveler The cache of traversal for given rootNode
*/
- void ConnectToSceneGraph(UpdateManager& updateManager, TransformManager& transformManager, Node& rootNode);
+ void ConnectToSceneGraph(UpdateManager& updateManager, TransformManager& transformManager, Node& rootNode, SceneGraphTravelerPtr traveler);
// Movable but not copyable
--- /dev/null
+/*
+ * 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.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/internal/update/manager/scene-graph-traveler.h>
+
+// INTERNAL INCLUDES
+#include <dali/internal/update/nodes/node.h>
+
+namespace Dali
+{
+namespace Internal
+{
+SceneGraphTraveler::SceneGraphTraveler(SceneGraph::Node& rootNode)
+: mRootNode(rootNode),
+ mNodeStack{},
+ mInvalidated{false}
+{
+ mRootNode.AddObserver(*this);
+ Clear();
+}
+
+SceneGraphTraveler::~SceneGraphTraveler()
+{
+ if(!mInvalidated)
+ {
+ mRootNode.RemoveObserver(*this);
+ }
+}
+
+SceneGraph::Node* SceneGraphTraveler::FindNode(uint32_t id)
+{
+ SceneGraph::Node* node = nullptr;
+
+ // Find node in cached map
+ auto iter = mTravledNodeMap.find(id);
+ if(iter != mTravledNodeMap.end())
+ {
+ node = iter->second;
+ }
+ else
+ {
+ while(!FullSearched())
+ {
+ SceneGraph::Node& currentNode = GetCurrentNode();
+ IterateNextNode();
+
+ // Cache traveled node and id pair.
+ mTravledNodeMap.insert({currentNode.mId, ¤tNode});
+
+ if(currentNode.mId == id)
+ {
+ node = ¤tNode;
+ break;
+ }
+ }
+ }
+
+ return node;
+}
+
+void SceneGraphTraveler::Clear()
+{
+ mTravledNodeMap.clear();
+ mTravledNodeMap.rehash(0u); ///< Note : We have to reduce capacity of hash map. Without this line, clear() API will be slow downed.
+ mNodeStack.clear();
+ if(!mInvalidated)
+ {
+ mNodeStack.emplace_back(&mRootNode, 0u);
+ }
+}
+
+bool SceneGraphTraveler::FullSearched() const
+{
+ return mNodeStack.empty();
+}
+
+SceneGraph::Node& SceneGraphTraveler::GetCurrentNode()
+{
+ DALI_ASSERT_DEBUG(!FullSearched());
+
+ return *(mNodeStack.back().first);
+}
+
+void SceneGraphTraveler::IterateNextNode()
+{
+ while(!mNodeStack.empty())
+ {
+ auto& currentNode = *(mNodeStack.back().first);
+ uint32_t currentChildIndex = mNodeStack.back().second;
+
+ if(currentNode.GetChildren().Count() <= currentChildIndex)
+ {
+ mNodeStack.pop_back();
+ continue;
+ }
+ else
+ {
+ // Stack current child, and increase index
+ ++mNodeStack.back().second;
+ mNodeStack.emplace_back(currentNode.GetChildren()[currentChildIndex], 0u);
+ break;
+ }
+ }
+}
+
+} // namespace Internal
+
+} // namespace Dali
--- /dev/null
+#ifndef DALI_INTERNAL_SCENE_GRAPH_TRAVELER_H
+#define DALI_INTERNAL_SCENE_GRAPH_TRAVELER_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.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <unordered_map>
+
+// INTERNAL INCLUDES
+#include <dali/internal/update/common/property-owner.h>
+#include <dali/public-api/common/dali-common.h>
+#include <dali/public-api/common/intrusive-ptr.h>
+#include <dali/public-api/common/vector-wrapper.h>
+#include <dali/public-api/object/ref-object.h>
+
+namespace Dali
+{
+namespace Internal
+{
+namespace SceneGraph
+{
+class Node;
+} // namespace SceneGraph
+
+class SceneGraphTraveler;
+using SceneGraphTravelerPtr = IntrusivePtr<SceneGraphTraveler>;
+
+/**
+ * @brief Helper class to travel scene graph incrementally.
+ */
+class SceneGraphTraveler : public Dali::RefObject, public SceneGraph::PropertyOwner::Observer
+{
+public:
+ SceneGraphTraveler(SceneGraph::Node& rootNode);
+
+ ~SceneGraphTraveler();
+
+public:
+ void NodeHierarchyChanged()
+ {
+ Clear();
+ }
+
+ bool IsInvalidated() const
+ {
+ return mInvalidated;
+ }
+
+ SceneGraph::Node* FindNode(uint32_t id);
+
+private:
+ // From SceneGraph::PropertyOwner::Observer
+
+ /**
+ * @copydoc SceneGraph::PropertyOwner::Observer::PropertyOwnerConnected()
+ */
+ void PropertyOwnerConnected(SceneGraph::PropertyOwner& owner) override
+ { /* Nothing to do */
+ }
+
+ /**
+ * @copydoc SceneGraph::PropertyOwner::Observer::PropertyOwnerDisconnected()
+ */
+ void PropertyOwnerDisconnected(BufferIndex updateBufferIndex, SceneGraph::PropertyOwner& owner) override
+ { /* Nothing to do */
+ }
+
+ /**
+ * @copydoc SceneGraph::PropertyOwner::Observer::PropertyOwnerDisconnected()
+ */
+ void PropertyOwnerDestroyed(SceneGraph::PropertyOwner& owner) override
+ {
+ // Invalidate this traveler
+ mInvalidated = true;
+ Clear();
+ }
+
+private:
+ void Clear();
+
+ bool FullSearched() const;
+
+ SceneGraph::Node& GetCurrentNode();
+
+ void IterateNextNode();
+
+private:
+ SceneGraph::Node& mRootNode;
+ std::vector<std::pair<SceneGraph::Node*, uint32_t>> mNodeStack; ///< Depth first search stack. Pair of node, and it's index of children that we need to iterate next.
+
+ std::unordered_map<uint32_t, SceneGraph::Node*> mTravledNodeMap; ///< Used to store cached pointers to already searched for Nodes.
+
+ bool mInvalidated : 1; ///< Troe if root node was destroyed.
+};
+
+} // namespace Internal
+
+} // namespace Dali
+
+#endif // DALI_INTERNAL_UPDATE_PROXY_SCENE_GRAPH_TRAVELER_H
{
namespace Internal
{
-namespace
-{
-SceneGraph::Node* FindNodeInSceneGraph(uint32_t id, SceneGraph::Node& node)
-{
- SceneGraph::Node* matchingNode = nullptr;
-
- if(node.mId == id)
- {
- matchingNode = &node;
- }
- else
- {
- for(auto&& i : node.GetChildren())
- {
- matchingNode = FindNodeInSceneGraph(id, *i);
- if(matchingNode)
- {
- break;
- }
- }
- }
-
- return matchingNode;
-}
-
-} // unnamed namespace
-
-UpdateProxy::UpdateProxy(SceneGraph::UpdateManager& updateManager, SceneGraph::TransformManager& transformManager, SceneGraph::Node& rootNode)
-: mNodeContainer(),
- mLastCachedIdNodePair({0u, nullptr}),
+UpdateProxy::UpdateProxy(SceneGraph::UpdateManager& updateManager, SceneGraph::TransformManager& transformManager, SceneGraph::Node& rootNode, SceneGraphTravelerPtr traveler)
+: mLastCachedIdNodePair({0u, nullptr}),
mDirtyNodes(),
mCurrentBufferIndex(0u),
mUpdateManager(updateManager),
mTransformManager(transformManager),
mRootNode(rootNode),
+ mSceneGraphTraveler(traveler),
mPropertyModifier(nullptr)
{
}
void UpdateProxy::NodeHierarchyChanged()
{
mLastCachedIdNodePair = {0u, nullptr};
- mNodeContainer.clear();
mPropertyModifier.reset();
}
}
else
{
- // Find node in vector
- for(auto&& pair : mNodeContainer)
- {
- if(pair.id == id)
- {
- node = pair.node;
- mLastCachedIdNodePair = pair;
- break;
- }
- }
+ node = mSceneGraphTraveler->FindNode(id);
- if(!node)
+ if(node)
{
- // Node not in vector, find in scene-graph
- node = FindNodeInSceneGraph(id, mRootNode);
- if(node)
- {
- mNodeContainer.push_back({id, node});
- mLastCachedIdNodePair = *mNodeContainer.rbegin();
- }
+ mLastCachedIdNodePair = {id, node};
}
}
{
for(auto&& id : mDirtyNodes)
{
- SceneGraph::Node* node = FindNodeInSceneGraph(id, mRootNode);
+ SceneGraph::Node* node = GetNodeWithId(id);
if(node)
{
mUpdateManager.AddNodeResetter(*node);
#include <dali/public-api/math/matrix.h>
#include <dali/public-api/math/vector3.h>
+#include <dali/internal/update/manager/scene-graph-traveler.h>
+
namespace Dali
{
namespace Internal
* @param[in] updateManager Ref to the UpdateManager in order to add property resetters
* @param[in] transformManager Ref to the TransformManager in order to set/get transform properties of nodes
* @param[in] rootNode The root node for this proxy
+ * @param[in] traveler The cache of traversal for given rootNode
*/
- UpdateProxy(SceneGraph::UpdateManager& updateManager, SceneGraph::TransformManager& transformManager, SceneGraph::Node& rootNode);
+ UpdateProxy(SceneGraph::UpdateManager& updateManager, SceneGraph::TransformManager& transformManager, SceneGraph::Node& rootNode, SceneGraphTravelerPtr traveler);
/**
* @brief Destructor.
class PropertyModifier;
using PropertyModifierPtr = std::unique_ptr<PropertyModifier>;
- mutable std::vector<IdNodePair> mNodeContainer; ///< Used to store cached pointers to already searched for Nodes.
- mutable IdNodePair mLastCachedIdNodePair; ///< Used to cache the last retrieved id-node pair.
- mutable std::vector<uint32_t> mDirtyNodes; ///< Used to store the ID of the dirty nodes with non-transform property modifications.
- BufferIndex mCurrentBufferIndex;
+ mutable IdNodePair mLastCachedIdNodePair; ///< Used to cache the last retrieved id-node pair.
+ std::vector<uint32_t> mDirtyNodes; ///< Used to store the ID of the dirty nodes with non-transform property modifications.
+ BufferIndex mCurrentBufferIndex;
+
+ SceneGraph::UpdateManager& mUpdateManager; ///< Reference to the Update Manager.
+ SceneGraph::TransformManager& mTransformManager; ///< Reference to the Transform Manager.
+ SceneGraph::Node& mRootNode; ///< The root node of this update proxy.
+ SceneGraphTravelerPtr mSceneGraphTraveler; ///< The cache system when we travel scene graph. (Not owned)
- SceneGraph::UpdateManager& mUpdateManager; ///< Reference to the Update Manager.
- SceneGraph::TransformManager& mTransformManager; ///< Reference to the Transform Manager.
- SceneGraph::Node& mRootNode; ///< The root node of this update proxy.
std::list<Dali::UpdateProxy::NotifySyncPoint> mSyncPoints;
- PropertyModifierPtr mPropertyModifier; ///< To ensure non-transform property modifications reset to base values.
+
+ PropertyModifierPtr mPropertyModifier; ///< To ensure non-transform property modifications reset to base values.
};
} // namespace Internal