Keep node by id + Make SceneGraphTraveler don't travel anymore
[platform/core/uifw/dali-core.git] / dali / internal / update / manager / frame-callback-processor.cpp
1 /*
2  * Copyright (c) 2024 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  */
17
18 // CLASS HEADER
19 #include <dali/internal/update/manager/frame-callback-processor.h>
20
21 // EXTERNAL INCLUDES
22 #include <algorithm>
23
24 // INTERNAL INCLUDES
25 #include <dali/devel-api/update/frame-callback-interface.h>
26 #include <dali/devel-api/update/update-proxy.h>
27 #include <dali/integration-api/debug.h>
28 #include <dali/integration-api/trace.h>
29 #include <dali/internal/update/manager/global-scene-graph-traveler.h>
30 #include <dali/internal/update/manager/scene-graph-traveler.h>
31
32 namespace
33 {
34 DALI_INIT_TRACE_FILTER(gTraceFilter, DALI_TRACE_PERFORMANCE_MARKER, false);
35 } // namespace
36
37 namespace Dali
38 {
39 namespace Internal
40 {
41 namespace SceneGraph
42 {
43 FrameCallbackProcessor::FrameCallbackProcessor(UpdateManager& updateManager, TransformManager& transformManager)
44 : mFrameCallbacks(),
45   mUpdateManager(updateManager),
46   mTransformManager(transformManager),
47   mRootNodeTravelerMap{},
48   mNodeHierarchyChanged(true)
49 {
50 }
51
52 FrameCallbackProcessor::~FrameCallbackProcessor() = default;
53
54 void FrameCallbackProcessor::AddFrameCallback(OwnerPointer<FrameCallback>& frameCallback, const Node* rootNode)
55 {
56   // We allow to input root node as nullptr.
57   // In this case, let we use global scene graph traveler, instead of node traveler
58   if(rootNode)
59   {
60     Node& node = const_cast<Node&>(*rootNode); // Was sent as const from event thread, we need to be able to use non-const version here.
61
62     auto traveler = GetSceneGraphTraveler(&node);
63
64     frameCallback->ConnectToSceneGraph(mUpdateManager, mTransformManager, node, traveler);
65   }
66   else
67   {
68     if(!mGlobalTraveler)
69     {
70       mGlobalTraveler = new GlobalSceneGraphTraveler(mUpdateManager);
71     }
72     frameCallback->ConnectToSceneGraph(mUpdateManager, mTransformManager, mGlobalTraveler);
73   }
74
75   mFrameCallbacks.emplace_back(frameCallback);
76 }
77
78 void FrameCallbackProcessor::RemoveFrameCallback(FrameCallbackInterface* frameCallback)
79 {
80   // Find and remove all frame-callbacks that use the given frame-callback-interface
81   auto iter = std::remove(mFrameCallbacks.begin(), mFrameCallbacks.end(), frameCallback);
82   mFrameCallbacks.erase(iter, mFrameCallbacks.end());
83 }
84
85 void FrameCallbackProcessor::NotifyFrameCallback(FrameCallbackInterface* frameCallback, Dali::UpdateProxy::NotifySyncPoint syncPoint)
86 {
87   // Ensure that frame callback is still valid before sending notification
88   auto iter = std::find(mFrameCallbacks.begin(), mFrameCallbacks.end(), frameCallback);
89   if(iter != mFrameCallbacks.end())
90   {
91     (*iter)->Notify(syncPoint);
92   }
93 }
94
95 bool FrameCallbackProcessor::Update(BufferIndex bufferIndex, float elapsedSeconds)
96 {
97   bool keepRendering = false;
98
99   if(mNodeHierarchyChanged && !mRootNodeTravelerMap.empty())
100   {
101     DALI_LOG_DEBUG_INFO("Node hierarchy changed. Update traveler map\n");
102     // Clear node traveler
103     for(auto iter = mRootNodeTravelerMap.begin(); iter != mRootNodeTravelerMap.end();)
104     {
105       // We don't need to erase invalidated traveler always. Just erase now.
106       // Note : ReferenceCount == 1 mean, no frame callbacks use this traveler now. We can erase it.
107       if(iter->second->IsInvalidated() || iter->second->ReferenceCount() == 1u)
108       {
109         iter = mRootNodeTravelerMap.erase(iter);
110       }
111       else
112       {
113         if(iter->first->IsDescendentHierarchyChanged())
114         {
115           iter->second->NodeHierarchyChanged();
116         }
117         ++iter;
118       }
119     }
120   }
121
122   if(!mFrameCallbacks.empty())
123   {
124     DALI_TRACE_BEGIN_WITH_MESSAGE_GENERATOR(gTraceFilter, "DALI_FRAME_CALLBACK_UPDATE", [&](std::ostringstream& oss) {
125       oss << "[" << mFrameCallbacks.size() << "]";
126     });
127
128     // If any of the FrameCallback::Update calls returns false, then they are no longer required & can be removed.
129     auto iter = std::remove_if(
130       mFrameCallbacks.begin(), mFrameCallbacks.end(), [&](OwnerPointer<FrameCallback>& frameCallback) {
131         FrameCallback::RequestFlags requests = frameCallback->Update(bufferIndex, elapsedSeconds, mNodeHierarchyChanged);
132         keepRendering |= (requests & FrameCallback::KEEP_RENDERING);
133         return (requests & FrameCallback::CONTINUE_CALLING) == 0;
134       });
135     mFrameCallbacks.erase(iter, mFrameCallbacks.end());
136
137     DALI_TRACE_END_WITH_MESSAGE_GENERATOR(gTraceFilter, "DALI_FRAME_CALLBACK_UPDATE", [&](std::ostringstream& oss) {
138       oss << "[" << mFrameCallbacks.size() << "]";
139     });
140   }
141
142   mNodeHierarchyChanged = false;
143
144   return keepRendering;
145 }
146
147 SceneGraphTravelerPtr FrameCallbackProcessor::GetSceneGraphTraveler(Node* rootNode)
148 {
149   auto iter = mRootNodeTravelerMap.find(rootNode);
150
151   if(iter != mRootNodeTravelerMap.end())
152   {
153     // Check wheter traveler is invalidated or not
154     if(!iter->second->IsInvalidated())
155     {
156       return iter->second;
157     }
158     else
159     {
160       mRootNodeTravelerMap.erase(iter);
161     }
162   }
163
164   // Create new traveler and keep it.
165   return (mRootNodeTravelerMap.insert({rootNode, new SceneGraphTraveler(mUpdateManager, *rootNode)})).first->second;
166 }
167
168 } // namespace SceneGraph
169
170 } // namespace Internal
171
172 } // namespace Dali