Let we keep whole nodes cache by id.
And let we make scene graph traveler use this system instead of traveling.
Previously, if we want to check whether given node is under root node,
we should search whole childrens (travel up-to-down).
Instead, let we travel down-to-up, s.t. will spend much less time than before.
And also, let we make a way to user don't use root actor for frame callback.
It is not a neccessary if we ask to node to mUpdateManger.
Change-Id: Ied34d176a05c87687cbfe0530612d53606c7e7a4
Signed-off-by: Eunki, Hong <eunkiki.hong@samsung.com>
/*
- * Copyright (c) 2023 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2024 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.
DALI_TEST_EQUALS(frameCallback.mSyncPoints.back(), syncPoint2, TEST_LOCATION);
END_TEST;
}
+
+int UtcDaliFrameCallbackWithoutRootActor(void)
+{
+ // Test to ensure that we should call methods on actors even if have been removed on the stage
+ // If we add frame callback with empty handle.
+
+ TestApplication application;
+ Stage stage = Stage::GetCurrent();
+
+ Actor actor = Actor::New();
+ stage.Add(actor);
+
+ FrameCallbackActorIdCheck frameCallback(actor.GetProperty<int>(Actor::Property::ID));
+ DevelStage::AddFrameCallback(stage, frameCallback, Actor());
+
+ application.SendNotification();
+ application.Render();
+
+ // All methods should return successfully.
+
+ DALI_TEST_EQUALS(frameCallback.mCalled, true, TEST_LOCATION);
+ DALI_TEST_EQUALS(frameCallback.mGetSizeCallSuccess, true, TEST_LOCATION);
+ DALI_TEST_EQUALS(frameCallback.mGetPositionCallSuccess, true, TEST_LOCATION);
+ DALI_TEST_EQUALS(frameCallback.mGetColorCallSuccess, true, TEST_LOCATION);
+ DALI_TEST_EQUALS(frameCallback.mGetScaleCallSuccess, true, TEST_LOCATION);
+ DALI_TEST_EQUALS(frameCallback.mGetPositionAndSizeCallSuccess, true, TEST_LOCATION);
+ DALI_TEST_EQUALS(frameCallback.mGetWorldPositionScaleAndSizeCallSuccess, true, TEST_LOCATION);
+ DALI_TEST_EQUALS(frameCallback.mSetSizeCallSuccess, true, TEST_LOCATION);
+ DALI_TEST_EQUALS(frameCallback.mSetPositionCallSuccess, true, TEST_LOCATION);
+ DALI_TEST_EQUALS(frameCallback.mSetColorCallSuccess, true, TEST_LOCATION);
+ DALI_TEST_EQUALS(frameCallback.mSetScaleCallSuccess, true, TEST_LOCATION);
+ DALI_TEST_EQUALS(frameCallback.mBakeSizeCallSuccess, true, TEST_LOCATION);
+ DALI_TEST_EQUALS(frameCallback.mBakePositionCallSuccess, true, TEST_LOCATION);
+ DALI_TEST_EQUALS(frameCallback.mBakeColorCallSuccess, true, TEST_LOCATION);
+ DALI_TEST_EQUALS(frameCallback.mBakeScaleCallSuccess, true, TEST_LOCATION);
+ DALI_TEST_EQUALS(frameCallback.mGetOrientationCallSuccess, true, TEST_LOCATION);
+ DALI_TEST_EQUALS(frameCallback.mSetOrientationCallSuccess, true, TEST_LOCATION);
+ DALI_TEST_EQUALS(frameCallback.mBakeOrientationCallSuccess, true, TEST_LOCATION);
+ DALI_TEST_EQUALS(frameCallback.mGetWorldTransformCallSuccess, true, TEST_LOCATION);
+
+ frameCallback.Reset();
+
+ // Remove the actor from stage, the methods should return successfully.
+
+ stage.Remove(actor);
+
+ application.SendNotification();
+ application.Render();
+
+ DALI_TEST_EQUALS(frameCallback.mCalled, true, TEST_LOCATION);
+ DALI_TEST_EQUALS(frameCallback.mGetSizeCallSuccess, true, TEST_LOCATION);
+ DALI_TEST_EQUALS(frameCallback.mGetPositionCallSuccess, true, TEST_LOCATION);
+ DALI_TEST_EQUALS(frameCallback.mGetColorCallSuccess, true, TEST_LOCATION);
+ DALI_TEST_EQUALS(frameCallback.mGetScaleCallSuccess, true, TEST_LOCATION);
+ DALI_TEST_EQUALS(frameCallback.mGetPositionAndSizeCallSuccess, true, TEST_LOCATION);
+ DALI_TEST_EQUALS(frameCallback.mGetWorldPositionScaleAndSizeCallSuccess, true, TEST_LOCATION);
+ DALI_TEST_EQUALS(frameCallback.mSetSizeCallSuccess, true, TEST_LOCATION);
+ DALI_TEST_EQUALS(frameCallback.mSetPositionCallSuccess, true, TEST_LOCATION);
+ DALI_TEST_EQUALS(frameCallback.mSetColorCallSuccess, true, TEST_LOCATION);
+ DALI_TEST_EQUALS(frameCallback.mSetScaleCallSuccess, true, TEST_LOCATION);
+ DALI_TEST_EQUALS(frameCallback.mBakeSizeCallSuccess, true, TEST_LOCATION);
+ DALI_TEST_EQUALS(frameCallback.mBakePositionCallSuccess, true, TEST_LOCATION);
+ DALI_TEST_EQUALS(frameCallback.mBakeColorCallSuccess, true, TEST_LOCATION);
+ DALI_TEST_EQUALS(frameCallback.mBakeScaleCallSuccess, true, TEST_LOCATION);
+ DALI_TEST_EQUALS(frameCallback.mGetOrientationCallSuccess, true, TEST_LOCATION);
+ DALI_TEST_EQUALS(frameCallback.mSetOrientationCallSuccess, true, TEST_LOCATION);
+ DALI_TEST_EQUALS(frameCallback.mBakeOrientationCallSuccess, true, TEST_LOCATION);
+ DALI_TEST_EQUALS(frameCallback.mGetWorldTransformCallSuccess, true, TEST_LOCATION);
+
+ // Remove callback. frameCallback should not be called.
+
+ frameCallback.Reset();
+ DevelStage::RemoveFrameCallback(stage, frameCallback);
+
+ application.SendNotification();
+ application.Render();
+
+ DALI_TEST_EQUALS(frameCallback.mCalled, false, TEST_LOCATION);
+ DALI_TEST_EQUALS(frameCallback.mGetSizeCallSuccess, false, TEST_LOCATION);
+ DALI_TEST_EQUALS(frameCallback.mGetPositionCallSuccess, false, TEST_LOCATION);
+ DALI_TEST_EQUALS(frameCallback.mGetColorCallSuccess, false, TEST_LOCATION);
+ DALI_TEST_EQUALS(frameCallback.mGetScaleCallSuccess, false, TEST_LOCATION);
+ DALI_TEST_EQUALS(frameCallback.mGetPositionAndSizeCallSuccess, false, TEST_LOCATION);
+ DALI_TEST_EQUALS(frameCallback.mGetWorldPositionScaleAndSizeCallSuccess, false, TEST_LOCATION);
+ DALI_TEST_EQUALS(frameCallback.mSetSizeCallSuccess, false, TEST_LOCATION);
+ DALI_TEST_EQUALS(frameCallback.mSetPositionCallSuccess, false, TEST_LOCATION);
+ DALI_TEST_EQUALS(frameCallback.mSetColorCallSuccess, false, TEST_LOCATION);
+ DALI_TEST_EQUALS(frameCallback.mSetScaleCallSuccess, false, TEST_LOCATION);
+ DALI_TEST_EQUALS(frameCallback.mBakeSizeCallSuccess, false, TEST_LOCATION);
+ DALI_TEST_EQUALS(frameCallback.mBakePositionCallSuccess, false, TEST_LOCATION);
+ DALI_TEST_EQUALS(frameCallback.mBakeColorCallSuccess, false, TEST_LOCATION);
+ DALI_TEST_EQUALS(frameCallback.mBakeScaleCallSuccess, false, TEST_LOCATION);
+ DALI_TEST_EQUALS(frameCallback.mGetOrientationCallSuccess, false, TEST_LOCATION);
+ DALI_TEST_EQUALS(frameCallback.mSetOrientationCallSuccess, false, TEST_LOCATION);
+ DALI_TEST_EQUALS(frameCallback.mBakeOrientationCallSuccess, false, TEST_LOCATION);
+ DALI_TEST_EQUALS(frameCallback.mGetWorldTransformCallSuccess, false, TEST_LOCATION);
+
+ frameCallback.Reset();
+
+ // Re-add the actor back to the stage, but frameCallback should not be emitted because we remove it.
+
+ stage.Add(actor);
+
+ application.SendNotification();
+ application.Render();
+
+ DALI_TEST_EQUALS(frameCallback.mCalled, false, TEST_LOCATION);
+ DALI_TEST_EQUALS(frameCallback.mGetSizeCallSuccess, false, TEST_LOCATION);
+ DALI_TEST_EQUALS(frameCallback.mGetPositionCallSuccess, false, TEST_LOCATION);
+ DALI_TEST_EQUALS(frameCallback.mGetColorCallSuccess, false, TEST_LOCATION);
+ DALI_TEST_EQUALS(frameCallback.mGetScaleCallSuccess, false, TEST_LOCATION);
+ DALI_TEST_EQUALS(frameCallback.mGetPositionAndSizeCallSuccess, false, TEST_LOCATION);
+ DALI_TEST_EQUALS(frameCallback.mGetWorldPositionScaleAndSizeCallSuccess, false, TEST_LOCATION);
+ DALI_TEST_EQUALS(frameCallback.mSetSizeCallSuccess, false, TEST_LOCATION);
+ DALI_TEST_EQUALS(frameCallback.mSetPositionCallSuccess, false, TEST_LOCATION);
+ DALI_TEST_EQUALS(frameCallback.mSetColorCallSuccess, false, TEST_LOCATION);
+ DALI_TEST_EQUALS(frameCallback.mSetScaleCallSuccess, false, TEST_LOCATION);
+ DALI_TEST_EQUALS(frameCallback.mBakeSizeCallSuccess, false, TEST_LOCATION);
+ DALI_TEST_EQUALS(frameCallback.mBakePositionCallSuccess, false, TEST_LOCATION);
+ DALI_TEST_EQUALS(frameCallback.mBakeColorCallSuccess, false, TEST_LOCATION);
+ DALI_TEST_EQUALS(frameCallback.mBakeScaleCallSuccess, false, TEST_LOCATION);
+ DALI_TEST_EQUALS(frameCallback.mGetOrientationCallSuccess, false, TEST_LOCATION);
+ DALI_TEST_EQUALS(frameCallback.mSetOrientationCallSuccess, false, TEST_LOCATION);
+ DALI_TEST_EQUALS(frameCallback.mBakeOrientationCallSuccess, false, TEST_LOCATION);
+ DALI_TEST_EQUALS(frameCallback.mGetWorldTransformCallSuccess, false, TEST_LOCATION);
+
+ END_TEST;
+}
\ No newline at end of file
/*
- * Copyright (c) 2023 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2024 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.
void AddFrameCallback(Dali::Stage stage, FrameCallbackInterface& frameCallback, Actor rootActor)
{
- GetImplementation(stage).AddFrameCallback(frameCallback, GetImplementation(rootActor));
+ if(rootActor)
+ {
+ GetImplementation(stage).AddFrameCallback(frameCallback, GetImplementation(rootActor));
+ }
+ else
+ {
+ GetImplementation(stage).AddGlobalFrameCallback(frameCallback);
+ }
}
void RemoveFrameCallback(Dali::Stage stage, FrameCallbackInterface& frameCallback)
#define DALI_STAGE_DEVEL_H
/*
- * Copyright (c) 2023 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2024 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.
*
* @param[in] stage The stage to set the FrameCallbackInterface implementation on
* @param[in] frameCallback An implementation of the FrameCallbackInterface
- * @param[in] rootActor The root-actor in the scene that the callback applies to
+ * @param[in] rootActor The root-actor in the scene that the callback applies to. Or empty handle if we don't care whether the node is scene on or not.
*
* @note The frameCallback cannot be added more than once. This will assert if that is attempted.
* @note Only the rootActor and it's children will be parsed by the UpdateProxy.
- * @note If the rootActor is destroyed, then the callback is automatically removed
+ * @note If the rootActor is destroyed, then the callback is automatically removed.
+ * @note If the rootActor is empty handle, given frameCallback will not be removed automatically.
* @see FrameCallbackInterface
*/
DALI_CORE_API void AddFrameCallback(Dali::Stage stage, FrameCallbackInterface& frameCallback, Actor rootActor);
/*
- * Copyright (c) 2023 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2024 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.
AddFrameCallbackMessage(mUpdateManager, transferOwnership, rootActor.GetNode());
}
+void Stage::AddGlobalFrameCallback(FrameCallbackInterface& frameCallback)
+{
+ DALI_ASSERT_ALWAYS((!FrameCallbackInterface::Impl::Get(frameCallback).IsConnectedToSceneGraph()) && "FrameCallbackInterface implementation already added");
+
+ // Create scene-graph object and transfer to UpdateManager
+ OwnerPointer<SceneGraph::FrameCallback> transferOwnership(SceneGraph::FrameCallback::New(frameCallback));
+ AddGlobalFrameCallbackMessage(mUpdateManager, transferOwnership);
+}
+
void Stage::RemoveFrameCallback(FrameCallbackInterface& frameCallback)
{
FrameCallbackInterface::Impl::Get(frameCallback).Invalidate();
#define DALI_INTERNAL_STAGE_H
/*
- * Copyright (c) 2023 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2024 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.
void AddFrameCallback(FrameCallbackInterface& frameCallback, Actor& rootActor);
/**
+ * @copydoc Dali::DevelStage::AddFrameCallback()
+ */
+ void AddGlobalFrameCallback(FrameCallbackInterface& frameCallback);
+
+ /**
* @copydoc Dali::DevelStage::RemoveFrameCallback()
*/
void RemoveFrameCallback(FrameCallbackInterface& frameCallback);
${internal_src_dir}/update/gestures/scene-graph-pan-gesture.cpp
${internal_src_dir}/update/queue/update-message-queue.cpp
${internal_src_dir}/update/manager/frame-callback-processor.cpp
+ ${internal_src_dir}/update/manager/global-scene-graph-traveler.cpp
${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
/*
- * Copyright (c) 2023 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2024 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.
#include <dali/devel-api/update/update-proxy.h>
#include <dali/integration-api/debug.h>
#include <dali/integration-api/trace.h>
+#include <dali/internal/update/manager/global-scene-graph-traveler.h>
+#include <dali/internal/update/manager/scene-graph-traveler.h>
namespace
{
: mFrameCallbacks(),
mUpdateManager(updateManager),
mTransformManager(transformManager),
- mTravelerMap{},
+ mRootNodeTravelerMap{},
mNodeHierarchyChanged(true)
{
}
void FrameCallbackProcessor::AddFrameCallback(OwnerPointer<FrameCallback>& frameCallback, const Node* rootNode)
{
- Node& node = const_cast<Node&>(*rootNode); // Was sent as const from event thread, we need to be able to use non-const version here.
+ // We allow to input root node as nullptr.
+ // In this case, let we use global scene graph traveler, instead of node traveler
+ if(rootNode)
+ {
+ Node& node = const_cast<Node&>(*rootNode); // Was sent as const from event thread, we need to be able to use non-const version here.
- SceneGraphTravelerPtr traveler = GetSceneGraphTraveler(&node);
+ auto traveler = GetSceneGraphTraveler(&node);
- frameCallback->ConnectToSceneGraph(mUpdateManager, mTransformManager, node, traveler);
+ frameCallback->ConnectToSceneGraph(mUpdateManager, mTransformManager, node, traveler);
+ }
+ else
+ {
+ if(!mGlobalTraveler)
+ {
+ mGlobalTraveler = new GlobalSceneGraphTraveler(mUpdateManager);
+ }
+ frameCallback->ConnectToSceneGraph(mUpdateManager, mTransformManager, mGlobalTraveler);
+ }
mFrameCallbacks.emplace_back(frameCallback);
}
{
bool keepRendering = false;
- if(mNodeHierarchyChanged)
+ if(mNodeHierarchyChanged && !mRootNodeTravelerMap.empty())
{
DALI_LOG_DEBUG_INFO("Node hierarchy changed. Update traveler map\n");
// Clear node traveler
- for(auto iter = mTravelerMap.begin(); iter != mTravelerMap.end();)
+ for(auto iter = mRootNodeTravelerMap.begin(); iter != mRootNodeTravelerMap.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);
+ iter = mRootNodeTravelerMap.erase(iter);
}
else
{
SceneGraphTravelerPtr FrameCallbackProcessor::GetSceneGraphTraveler(Node* rootNode)
{
- auto iter = mTravelerMap.find(rootNode);
+ auto iter = mRootNodeTravelerMap.find(rootNode);
- if(iter != mTravelerMap.end())
+ if(iter != mRootNodeTravelerMap.end())
{
// Check wheter traveler is invalidated or not
if(!iter->second->IsInvalidated())
}
else
{
- mTravelerMap.erase(iter);
+ mRootNodeTravelerMap.erase(iter);
}
}
// Create new traveler and keep it.
- return (mTravelerMap.insert({rootNode, new SceneGraphTraveler(*rootNode)})).first->second;
+ return (mRootNodeTravelerMap.insert({rootNode, new SceneGraphTraveler(mUpdateManager, *rootNode)})).first->second;
}
} // namespace SceneGraph
#define DALI_INTERNAL_SCENE_GRAPH_FRAME_CALLBACK_PROCESSOR_H
/*
- * Copyright (c) 2023 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2024 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.
/**
* Adds an implementation of the FrameCallbackInterface.
* @param[in] frameCallback An OwnerPointer to the SceneGraph FrameCallback object
- * @param[in] rootNode A pointer to the root node to apply the FrameCallback to
+ * @param[in] rootNode A pointer to the root node to apply the FrameCallback to. Or nullptr if given frame callback use globally.
*/
void AddFrameCallback(OwnerPointer<FrameCallback>& frameCallback, const Node* rootNode);
TransformManager& mTransformManager;
using TravelerContainer = std::unordered_map<const Node*, SceneGraphTravelerPtr>;
- TravelerContainer mTravelerMap;
+ TravelerContainer mRootNodeTravelerMap;
+
+ SceneGraphTravelerInterfacePtr mGlobalTraveler;
bool mNodeHierarchyChanged; ///< Set to true if the node hierarchy changes
};
--- /dev/null
+/*
+ * Copyright (c) 2024 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/global-scene-graph-traveler.h>
+
+// INTERNAL INCLUDES
+#include <dali/internal/update/manager/update-manager.h>
+#include <dali/internal/update/nodes/node.h>
+
+namespace Dali
+{
+namespace Internal
+{
+GlobalSceneGraphTraveler::GlobalSceneGraphTraveler(SceneGraph::UpdateManager& updateManager)
+: SceneGraphTravelerInterface(updateManager)
+{
+}
+
+SceneGraph::Node* GlobalSceneGraphTraveler::FindNode(uint32_t id)
+{
+ return mUpdateManager.GetNodePointerById(id);
+}
+
+} // namespace Internal
+
+} // namespace Dali
--- /dev/null
+#ifndef DALI_INTERNAL_GLOBAL_SCENE_GRAPH_TRAVELER_H
+#define DALI_INTERNAL_GLOBAL_SCENE_GRAPH_TRAVELER_H
+
+/*
+ * Copyright (c) 2024 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.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include <dali/internal/update/manager/scene-graph-traveler-interface.h>
+
+namespace Dali
+{
+namespace Internal
+{
+class GlobalSceneGraphTraveler;
+using GlobalSceneGraphTravelerPtr = IntrusivePtr<GlobalSceneGraphTraveler>;
+/**
+ * @brief Helper class to travel global scene graph.
+ */
+class GlobalSceneGraphTraveler : public SceneGraphTravelerInterface
+{
+public:
+ /**
+ * @brief Construct
+ * @param[in] updateManager The update manager.
+ */
+ GlobalSceneGraphTraveler(SceneGraph::UpdateManager& updateManager);
+
+ /**
+ * @brief Destructor
+ */
+ ~GlobalSceneGraphTraveler() override
+ {
+ }
+
+public: // From SceneGraphTravelerInterface
+ /**
+ * @copydoc Dali::Internal::SceneGraphTravelerInterface::FindNode()
+ */
+ SceneGraph::Node* FindNode(uint32_t id) override;
+};
+
+} // namespace Internal
+
+} // namespace Dali
+
+#endif // DALI_INTERNAL_UPDATE_PROXY_SCENE_GRAPH_TRAVELER_H
/*
- * Copyright (c) 2023 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2024 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.
{
if(mUpdateProxy)
{
- mUpdateProxy->GetRootNode().RemoveObserver(*this);
+ if(mRootNode)
+ {
+ mRootNode->RemoveObserver(*this);
+ }
mUpdateProxy->AddNodeResetters();
}
Invalidate();
}
-void FrameCallback::ConnectToSceneGraph(UpdateManager& updateManager, TransformManager& transformManager, Node& rootNode, SceneGraphTravelerPtr traveler)
+void FrameCallback::ConnectToSceneGraph(UpdateManager& updateManager, TransformManager& transformManager, Node& rootNode, SceneGraphTravelerInterfacePtr traveler)
{
- mUpdateProxy = std::unique_ptr<UpdateProxy>(new UpdateProxy(updateManager, transformManager, rootNode, traveler));
+ mRootNode = &rootNode;
rootNode.AddObserver(*this);
+
+ ConnectToSceneGraph(updateManager, transformManager, traveler);
+}
+
+void FrameCallback::ConnectToSceneGraph(UpdateManager& updateManager, TransformManager& transformManager, SceneGraphTravelerInterfacePtr traveler)
+{
+ mUpdateProxy = std::unique_ptr<UpdateProxy>(new UpdateProxy(updateManager, transformManager, traveler));
}
FrameCallback::RequestFlags FrameCallback::Update(BufferIndex bufferIndex, float elapsedSeconds, bool nodeHierarchyChanged)
void FrameCallback::PropertyOwnerDestroyed(PropertyOwner& owner)
{
mUpdateProxy.reset(); // Root node is being destroyed so no point keeping the update-proxy either
+ mRootNode = nullptr;
Invalidate();
}
#define DALI_INTERNAL_SCENE_GRAPH_FRAME_CALLBACK_H
/*
- * Copyright (c) 2023 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2024 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.
#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/scene-graph-traveler-interface.h>
#include <dali/internal/update/manager/update-proxy-impl.h>
#include <dali/public-api/common/list-wrapper.h>
* @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, SceneGraphTravelerPtr traveler);
+ void ConnectToSceneGraph(UpdateManager& updateManager, TransformManager& transformManager, Node& rootNode, SceneGraphTravelerInterfacePtr traveler);
+
+ /**
+ * Called from the update-thread when connecting to the scene-graph.
+ * @param[in] updateManager The Update Manager
+ * @param[in] transformManager The Transform Manager
+ * @param[in] traveler The cache of traversal
+ */
+ void ConnectToSceneGraph(UpdateManager& updateManager, TransformManager& transformManager, SceneGraphTravelerInterfacePtr traveler);
// Movable but not copyable
private:
Mutex mMutex;
std::unique_ptr<UpdateProxy> mUpdateProxy{nullptr}; ///< A unique pointer to the implementation of the UpdateProxy.
+ Node* mRootNode{nullptr}; ///< Connected root node for given FrameCallback. It could be nullptr if it is global callback.
FrameCallbackInterface* mFrameCallbackInterface;
std::list<Dali::UpdateProxy::NotifySyncPoint> mSyncPoints;
bool mValid{true}; ///< Set to false when Invalidate() is called.
--- /dev/null
+#ifndef DALI_INTERNAL_SCENE_GRAPH_TRAVELER_INTERFACE_H
+#define DALI_INTERNAL_SCENE_GRAPH_TRAVELER_INTERFACE_H
+
+/*
+ * Copyright (c) 2024 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.
+ *
+ */
+
+// 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;
+class UpdateManager;
+} // namespace SceneGraph
+
+class SceneGraphTravelerInterface;
+using SceneGraphTravelerInterfacePtr = IntrusivePtr<SceneGraphTravelerInterface>;
+
+/**
+ * @brief Interface of helper class to travel scene graph.
+ */
+class SceneGraphTravelerInterface : public Dali::RefObject
+{
+public:
+ /**
+ * @brief Construct
+ * @param[in] updateManager The update manager.
+ */
+ SceneGraphTravelerInterface(SceneGraph::UpdateManager& updateManager)
+ : mUpdateManager(updateManager)
+ {
+ }
+
+ /**
+ * @brief Destructor
+ */
+ virtual ~SceneGraphTravelerInterface() = default;
+
+public:
+ /**
+ * @brief Get SceneGraph::Node pointer from node id.
+ * The way of find & choose mechanism is depend on inherited class.
+ *
+ * @param[in] id The id of node what we want to find.
+ * @return Node pointer, or nullptr if we fail to find it.
+ */
+ virtual SceneGraph::Node* FindNode(uint32_t id) = 0;
+
+protected:
+ SceneGraph::UpdateManager& mUpdateManager;
+};
+
+} // namespace Internal
+
+} // namespace Dali
+
+#endif // DALI_INTERNAL_UPDATE_PROXY_SCENE_GRAPH_TRAVELER_H
/*
- * Copyright (c) 2023 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2024 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.
#include <dali/internal/update/manager/scene-graph-traveler.h>
// INTERNAL INCLUDES
+#include <dali/internal/update/manager/update-manager.h>
#include <dali/internal/update/nodes/node.h>
namespace Dali
{
namespace Internal
{
-SceneGraphTraveler::SceneGraphTraveler(SceneGraph::Node& rootNode)
-: mRootNode(rootNode),
- mNodeStack{},
+SceneGraphTraveler::SceneGraphTraveler(SceneGraph::UpdateManager& updateManager, SceneGraph::Node& rootNode)
+: SceneGraphTravelerInterface(updateManager),
+ mRootNode(rootNode),
mInvalidated{false}
{
mRootNode.AddObserver(*this);
{
SceneGraph::Node* node = nullptr;
- // Find node in cached map
- auto iter = mTravledNodeMap.find(id);
- if(iter != mTravledNodeMap.end())
- {
- node = iter->second;
- }
- else
+ if(!mInvalidated)
{
- while(!FullSearched())
+ // Find node in cached map
+ auto iter = mTravledNodeMap.find(id);
+ if(iter != mTravledNodeMap.end())
+ {
+ node = iter->second;
+ }
+ else
{
- SceneGraph::Node& currentNode = GetCurrentNode();
- IterateNextNode();
+ SceneGraph::Node* currentNode = mUpdateManager.GetNodePointerById(id);
+
+ bool isNodeUnderRootNode = false;
+
+ std::vector<std::pair<uint32_t, SceneGraph::Node*>> nodeStack;
- // Cache traveled node and id pair.
- mTravledNodeMap.insert({currentNode.mId, ¤tNode});
+ SceneGraph::Node* iterateNode = currentNode;
- if(currentNode.mId == id)
+ while(iterateNode)
{
- node = ¤tNode;
- break;
+ uint32_t iterateNodeId = iterateNode->GetId();
+
+ auto iter = mTravledNodeMap.find(iterateNodeId);
+ if(iter != mTravledNodeMap.end())
+ {
+ // iter->second could be nullptr if it was failed item before.
+ if(iter->second != nullptr)
+ {
+ isNodeUnderRootNode = true;
+ }
+ break;
+ }
+ nodeStack.push_back({iterateNodeId, iterateNode});
+
+ // Go to parent.
+ iterateNode = iterateNode->GetParent();
+ }
+
+ // Store current found result.
+ for(auto&& idPair : nodeStack)
+ {
+ mTravledNodeMap.insert({idPair.first, isNodeUnderRootNode ? idPair.second : nullptr});
+ }
+
+ if(isNodeUnderRootNode)
+ {
+ node = currentNode;
}
}
}
{
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;
- }
+ mTravledNodeMap.insert({mRootNode.GetId(), &mRootNode});
}
}
#define DALI_INTERNAL_SCENE_GRAPH_TRAVELER_H
/*
- * Copyright (c) 2023 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2024 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.
#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>
+#include <dali/internal/update/manager/scene-graph-traveler-interface.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.
+ * @brief Helper class to travel scene graph under root node.
*/
-class SceneGraphTraveler : public Dali::RefObject, public SceneGraph::PropertyOwner::Observer
+class SceneGraphTraveler : public SceneGraphTravelerInterface, public SceneGraph::PropertyOwner::Observer
{
public:
- SceneGraphTraveler(SceneGraph::Node& rootNode);
+ /**
+ * @brief Construct
+ * @param[in] updateManager The update manager.
+ * @param[in] rootNode The root node of this traveler. The traveler will find only under this rootNode.
+ */
+ SceneGraphTraveler(SceneGraph::UpdateManager& updateManager, SceneGraph::Node& rootNode);
- ~SceneGraphTraveler();
+ /**
+ * @brief Destructor
+ */
+ ~SceneGraphTraveler() override;
public:
+ /**
+ * @brief Call this method if hierarchy was changed under root node.
+ */
void NodeHierarchyChanged()
{
Clear();
}
+ /**
+ * @brief Whether root node is invalidated or not.
+ *
+ * @return True if root node is invalidated.
+ */
bool IsInvalidated() const
{
return mInvalidated;
}
- SceneGraph::Node* FindNode(uint32_t id);
-
-private:
- // From SceneGraph::PropertyOwner::Observer
+public: // From SceneGraphTravelerInterface
+ /**
+ * @copydoc Dali::Internal::SceneGraphTravelerInterface::FindNode()
+ */
+ SceneGraph::Node* FindNode(uint32_t id) override;
+private: // From SceneGraph::PropertyOwner::Observer
/**
* @copydoc SceneGraph::PropertyOwner::Observer::PropertyOwnerConnected()
*/
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.
+ SceneGraph::Node& mRootNode;
std::unordered_map<uint32_t, SceneGraph::Node*> mTravledNodeMap; ///< Used to store cached pointers to already searched for Nodes.
+ ///< If node is not under root node, it will store nullptr.
- bool mInvalidated : 1; ///< Troe if root node was destroyed.
+ bool mInvalidated : 1; ///< True if root node was destroyed.
};
} // namespace Internal
/*
- * Copyright (c) 2023 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2024 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.
(*iter)->OnDestroy();
Node::Delete(*iter);
}
+ nodeIdMap.clear();
for(auto&& scene : scenes)
{
Vector<Node*> nodes; ///< A container of all instantiated nodes
+ std::unordered_map<uint32_t, Node*> nodeIdMap; ///< A container of nodes map by id.
+
Vector<Camera*> cameras; ///< A container of cameras. Note : these cameras are owned by Impl::nodes.
OwnerContainer<PropertyOwner*> customObjects; ///< A container of owned objects (with custom properties)
rootLayer->AddInitializeResetter(*this);
+ // Do not allow to insert duplicated nodes.
+ // It could be happened if node id is overflowed.
+ DALI_ASSERT_ALWAYS(mImpl->nodeIdMap.insert({rootLayer->GetId(), rootLayer}).second);
+
mImpl->scenes.emplace_back(new Impl::SceneInfo(rootLayer));
}
}
}
+ mImpl->nodeIdMap.erase(layer->GetId());
+
mImpl->nodeDiscardQueue.Add(mSceneGraphBuffers.GetUpdateBufferIndex(), layer);
// Notify the layer about impending destruction
AddCamera(static_cast<Camera*>(rawNode));
}
+ // Do not allow to insert duplicated nodes.
+ // It could be happened if node id is overflowed.
+ DALI_ASSERT_ALWAYS(mImpl->nodeIdMap.insert({rawNode->GetId(), rawNode}).second);
+
mImpl->nodes.PushBack(rawNode);
+
rawNode->CreateTransform(&mImpl->transformManager);
}
RemoveCamera(static_cast<Camera*>(node));
}
+ mImpl->nodeIdMap.erase(node->GetId());
+
mImpl->nodeDiscardQueue.Add(mSceneGraphBuffers.GetUpdateBufferIndex(), node);
// Notify the Node about impending destruction
mImpl->renderingRequired = true;
}
+Node* UpdateManager::GetNodePointerById(uint32_t nodeId) const
+{
+ Node* foundNodePointer = nullptr;
+ auto iter = mImpl->nodeIdMap.find(nodeId);
+ if(iter != mImpl->nodeIdMap.end())
+ {
+ foundNodePointer = iter->second;
+ }
+ return foundNodePointer;
+}
+
void UpdateManager::SetLayerDepths(const SortedLayerPointers& layers, const Layer* rootLayer)
{
for(auto&& scene : mImpl->scenes)
#define DALI_INTERNAL_SCENE_GRAPH_UPDATE_MANAGER_H
/*
- * Copyright (c) 2023 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2024 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.
void RequestRendering();
/**
+ * @brief Get the active Node pointer by node id.
+ *
+ * @param[in] nodeId The id of node what we want to get.
+ * @return The pointer of node, or nullptr if given node id is not exist, or discarded.
+ */
+ Node* GetNodePointerById(uint32_t nodeId) const;
+
+ /**
* Sets the depths of all layers.
* @param layers The layers in depth order.
* @param[in] rootLayer The root layer of the sorted layers.
new(slot) LocalType(&manager, &UpdateManager::AddFrameCallback, frameCallback, &rootNode);
}
+inline void AddGlobalFrameCallbackMessage(UpdateManager& manager, OwnerPointer<FrameCallback>& frameCallback)
+{
+ using LocalType = MessageValue2<UpdateManager, OwnerPointer<FrameCallback>, const Node*>;
+
+ // Reserve some memory inside the message queue
+ uint32_t* slot = manager.ReserveMessageSlot(sizeof(LocalType));
+
+ // Construct message in the message queue memory; note that delete should not be called on the return value
+ new(slot) LocalType(&manager, &UpdateManager::AddFrameCallback, frameCallback, nullptr);
+}
+
inline void RemoveFrameCallbackMessage(UpdateManager& manager, FrameCallbackInterface& frameCallback)
{
using LocalType = MessageValue1<UpdateManager, FrameCallbackInterface*>;
/*
- * Copyright (c) 2023 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2024 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.
#include <dali/internal/update/manager/update-proxy-impl.h>
// INTERNAL INCLUDES
+#include <dali/internal/update/manager/update-manager.h>
#include <dali/internal/update/manager/update-proxy-property-modifier.h>
namespace Dali
{
namespace Internal
{
-UpdateProxy::UpdateProxy(SceneGraph::UpdateManager& updateManager, SceneGraph::TransformManager& transformManager, SceneGraph::Node& rootNode, SceneGraphTravelerPtr traveler)
+UpdateProxy::UpdateProxy(SceneGraph::UpdateManager& updateManager, SceneGraph::TransformManager& transformManager, SceneGraphTravelerInterfacePtr traveler)
: mLastCachedIdNodePair({0u, nullptr}),
mDirtyNodes(),
mCurrentBufferIndex(0u),
mUpdateManager(updateManager),
mTransformManager(transformManager),
- mRootNode(rootNode),
mSceneGraphTraveler(traveler),
mPropertyModifier(nullptr)
{
#define DALI_INTERNAL_UPDATE_PROXY_IMPL_H
/*
- * Copyright (c) 2023 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2024 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.
#include <dali/public-api/math/matrix.h>
#include <dali/public-api/math/vector3.h>
-#include <dali/internal/update/manager/scene-graph-traveler.h>
+#include <dali/internal/update/manager/scene-graph-traveler-interface.h>
namespace Dali
{
* @brief Constructor.
* @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
+ * @param[in] traveler The cache of traversal.
*/
- UpdateProxy(SceneGraph::UpdateManager& updateManager, SceneGraph::TransformManager& transformManager, SceneGraph::Node& rootNode, SceneGraphTravelerPtr traveler);
+ UpdateProxy(SceneGraph::UpdateManager& updateManager, SceneGraph::TransformManager& transformManager, SceneGraphTravelerInterfacePtr traveler);
/**
* @brief Destructor.
bool BakeColor(uint32_t id, const Vector4& color);
/**
- * @brief Retrieves the root-node used by this class
- * @return The root node used by this class.
- */
- SceneGraph::Node& GetRootNode() const
- {
- return mRootNode;
- }
-
- /**
* @brief Sets the buffer index to use when processing the next callback.
* @param[in] bufferIndex The current buffer index
*/
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.
+ SceneGraphTravelerInterfacePtr mSceneGraphTraveler; ///< The cache system when we travel scene graph. (Not owned)
std::list<Dali::UpdateProxy::NotifySyncPoint> mSyncPoints;