e6d2617530c837a6a71c53772b72b438f0066467
[platform/core/uifw/dali-core.git] / dali / internal / update / manager / frame-callback-processor.cpp
1 /*
2  * Copyright (c) 2023 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
30 namespace
31 {
32 DALI_INIT_TRACE_FILTER(gTraceFilter, DALI_TRACE_PERFORMANCE_MARKER, false);
33 } // namespace
34
35 namespace Dali
36 {
37 namespace Internal
38 {
39 namespace SceneGraph
40 {
41 FrameCallbackProcessor::FrameCallbackProcessor(UpdateManager& updateManager, TransformManager& transformManager)
42 : mFrameCallbacks(),
43   mUpdateManager(updateManager),
44   mTransformManager(transformManager),
45   mTravelerMap{},
46   mNodeHierarchyChanged(true)
47 {
48 }
49
50 FrameCallbackProcessor::~FrameCallbackProcessor() = default;
51
52 void FrameCallbackProcessor::AddFrameCallback(OwnerPointer<FrameCallback>& frameCallback, const Node* rootNode)
53 {
54   Node& node = const_cast<Node&>(*rootNode); // Was sent as const from event thread, we need to be able to use non-const version here.
55
56   SceneGraphTravelerPtr traveler = GetSceneGraphTraveler(&node);
57
58   frameCallback->ConnectToSceneGraph(mUpdateManager, mTransformManager, node, traveler);
59
60   mFrameCallbacks.emplace_back(frameCallback);
61 }
62
63 void FrameCallbackProcessor::RemoveFrameCallback(FrameCallbackInterface* frameCallback)
64 {
65   // Find and remove all frame-callbacks that use the given frame-callback-interface
66   auto iter = std::remove(mFrameCallbacks.begin(), mFrameCallbacks.end(), frameCallback);
67   mFrameCallbacks.erase(iter, mFrameCallbacks.end());
68 }
69
70 void FrameCallbackProcessor::NotifyFrameCallback(FrameCallbackInterface* frameCallback, Dali::UpdateProxy::NotifySyncPoint syncPoint)
71 {
72   // Ensure that frame callback is still valid before sending notification
73   auto iter = std::find(mFrameCallbacks.begin(), mFrameCallbacks.end(), frameCallback);
74   if(iter != mFrameCallbacks.end())
75   {
76     (*iter)->Notify(syncPoint);
77   }
78 }
79
80 bool FrameCallbackProcessor::Update(BufferIndex bufferIndex, float elapsedSeconds)
81 {
82   bool keepRendering = false;
83
84   if(mNodeHierarchyChanged)
85   {
86     DALI_LOG_DEBUG_INFO("Node hierarchy changed. Update traveler map\n");
87     // Clear node traveler
88     for(auto iter = mTravelerMap.begin(); iter != mTravelerMap.end();)
89     {
90       // We don't need to erase invalidated traveler always. Just erase now.
91       // Note : ReferenceCount == 1 mean, no frame callbacks use this traveler now. We can erase it.
92       if(iter->second->IsInvalidated() || iter->second->ReferenceCount() == 1u)
93       {
94         iter = mTravelerMap.erase(iter);
95       }
96       else
97       {
98         if(iter->first->IsDescendentHierarchyChanged())
99         {
100           iter->second->NodeHierarchyChanged();
101         }
102         ++iter;
103       }
104     }
105   }
106
107   if(!mFrameCallbacks.empty())
108   {
109     DALI_TRACE_BEGIN_WITH_MESSAGE_GENERATOR(gTraceFilter, "DALI_FRAME_CALLBACK_UPDATE", [&](std::ostringstream& oss) {
110       oss << "[" << mFrameCallbacks.size() << "]";
111     });
112
113     // If any of the FrameCallback::Update calls returns false, then they are no longer required & can be removed.
114     auto iter = std::remove_if(
115       mFrameCallbacks.begin(), mFrameCallbacks.end(), [&](OwnerPointer<FrameCallback>& frameCallback) {
116         FrameCallback::RequestFlags requests = frameCallback->Update(bufferIndex, elapsedSeconds, mNodeHierarchyChanged);
117         keepRendering |= (requests & FrameCallback::KEEP_RENDERING);
118         return (requests & FrameCallback::CONTINUE_CALLING) == 0;
119       });
120     mFrameCallbacks.erase(iter, mFrameCallbacks.end());
121
122     DALI_TRACE_END_WITH_MESSAGE_GENERATOR(gTraceFilter, "DALI_FRAME_CALLBACK_UPDATE", [&](std::ostringstream& oss) {
123       oss << "[" << mFrameCallbacks.size() << "]";
124     });
125   }
126
127   mNodeHierarchyChanged = false;
128
129   return keepRendering;
130 }
131
132 SceneGraphTravelerPtr FrameCallbackProcessor::GetSceneGraphTraveler(Node* rootNode)
133 {
134   auto iter = mTravelerMap.find(rootNode);
135
136   if(iter != mTravelerMap.end())
137   {
138     // Check wheter traveler is invalidated or not
139     if(!iter->second->IsInvalidated())
140     {
141       return iter->second;
142     }
143     else
144     {
145       mTravelerMap.erase(iter);
146     }
147   }
148
149   // Create new traveler and keep it.
150   return (mTravelerMap.insert({rootNode, new SceneGraphTraveler(*rootNode)})).first->second;
151 }
152
153 } // namespace SceneGraph
154
155 } // namespace Internal
156
157 } // namespace Dali