Merge "Make sure that global variables are initialized lazily." into devel/master
[platform/core/uifw/dali-core.git] / dali / internal / update / nodes / node.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/nodes/node.h>
20
21 // INTERNAL INCLUDES
22 #include <dali/internal/common/internal-constants.h>
23 #include <dali/internal/common/memory-pool-object-allocator.h>
24 #include <dali/internal/update/common/discard-queue.h>
25 #include <dali/public-api/common/constants.h>
26 #include <dali/public-api/common/dali-common.h>
27
28 namespace
29 {
30 // Memory pool used to allocate new nodes. Memory used by this pool will be released when process dies
31 //  or DALI library is unloaded
32 Dali::Internal::MemoryPoolObjectAllocator<Dali::Internal::SceneGraph::Node>& GetNodeMemoryPool()
33 {
34   static Dali::Internal::MemoryPoolObjectAllocator<Dali::Internal::SceneGraph::Node> gNodeMemoryPool;
35   return gNodeMemoryPool;
36 }
37 #ifdef DEBUG_ENABLED
38 // keep track of nodes alive, to ensure we have 0 when the process exits or DALi library is unloaded
39 int32_t gNodeCount = 0;
40
41 // Called when the process is about to exit, Node count should be zero at this point.
42 void __attribute__((destructor)) ShutDown(void)
43 {
44   DALI_ASSERT_DEBUG((gNodeCount == 0) && "Node memory leak");
45 }
46 #endif
47 } // Unnamed namespace
48
49 namespace Dali
50 {
51 namespace Internal
52 {
53 namespace SceneGraph
54 {
55 const ColorMode Node::DEFAULT_COLOR_MODE(USE_OWN_MULTIPLY_PARENT_ALPHA);
56
57 uint32_t Node::mNodeCounter = 0; ///< A counter to provide unique node ids, up-to 4 billion
58
59 Node* Node::New()
60 {
61   return new(GetNodeMemoryPool().AllocateRawThreadSafe()) Node;
62 }
63
64 void Node::Delete(Node* node)
65 {
66   // check we have a node not a derived node
67   if(!node->mIsLayer && !node->mIsCamera)
68   {
69     // Manually call the destructor
70     node->~Node();
71
72     // Mark the memory it used as free in the memory pool
73     GetNodeMemoryPool().FreeThreadSafe(node);
74   }
75   else
76   {
77     // not in the pool, just delete it.
78     delete node;
79   }
80 }
81
82 Node::Node()
83 : mOrientation(),                                                               // Initialized to identity by default
84   mWorldPosition(TRANSFORM_PROPERTY_WORLD_POSITION, Vector3(0.0f, 0.0f, 0.0f)), // Zero initialized by default
85   mWorldScale(TRANSFORM_PROPERTY_WORLD_SCALE, Vector3(1.0f, 1.0f, 1.0f)),
86   mWorldOrientation(), // Initialized to identity by default
87   mWorldMatrix(),
88   mVisible(true),
89   mCulled(false),
90   mColor(Color::WHITE),
91   mWorldColor(Color::WHITE),
92   mUpdateAreaHint(Vector4::ZERO),
93   mClippingSortModifier(0u),
94   mId(++mNodeCounter),
95   mParent(nullptr),
96   mExclusiveRenderTask(nullptr),
97   mChildren(),
98   mClippingDepth(0u),
99   mScissorDepth(0u),
100   mDepthIndex(0u),
101   mDirtyFlags(NodePropertyFlags::ALL),
102   mDrawMode(DrawMode::NORMAL),
103   mColorMode(DEFAULT_COLOR_MODE),
104   mClippingMode(ClippingMode::DISABLED),
105   mIsRoot(false),
106   mIsLayer(false),
107   mIsCamera(false),
108   mPositionUsesAnchorPoint(true),
109   mTransparent(false),
110   mUpdateAreaChanged(false)
111 {
112 #ifdef DEBUG_ENABLED
113   gNodeCount++;
114 #endif
115 }
116
117 Node::~Node()
118 {
119   if(mTransformManagerData.Id() != INVALID_TRANSFORM_ID)
120   {
121     mTransformManagerData.Manager()->RemoveTransform(mTransformManagerData.Id());
122   }
123
124 #ifdef DEBUG_ENABLED
125   gNodeCount--;
126 #endif
127 }
128
129 void Node::OnDestroy()
130 {
131   // Animators, Constraints etc. should be disconnected from the child's properties.
132   PropertyOwner::Destroy();
133 }
134
135 uint32_t Node::GetId() const
136 {
137   return mId;
138 }
139
140 void Node::CreateTransform(SceneGraph::TransformManager* transformManager)
141 {
142   // Create a new transform
143   mTransformManagerData.mManager = transformManager;
144   TransformId createdTransformId = transformManager->CreateTransform();
145
146   // Set whether the position should use the anchor point
147   transformManager->SetPositionUsesAnchorPoint(createdTransformId, mPositionUsesAnchorPoint);
148
149   // Set TransformId after initialize done.
150   mTransformManagerData.mId = createdTransformId;
151 }
152
153 void Node::SetRoot(bool isRoot)
154 {
155   DALI_ASSERT_DEBUG(!isRoot || mParent == NULL); // Root nodes cannot have a parent
156
157   mIsRoot = isRoot;
158 }
159
160 bool Node::IsAnimationPossible() const
161 {
162   return mIsConnectedToSceneGraph;
163 }
164
165 void Node::ConnectChild(Node* childNode)
166 {
167   DALI_ASSERT_ALWAYS(this != childNode);
168   DALI_ASSERT_ALWAYS(IsRoot() || nullptr != mParent);                            // Parent should be connected first
169   DALI_ASSERT_ALWAYS(!childNode->IsRoot() && nullptr == childNode->GetParent()); // Child should be disconnected
170
171   childNode->SetParent(*this);
172
173   // Everything should be reinherited when reconnected to scene-graph
174   childNode->SetAllDirtyFlags();
175
176   // Add the node to the end of the child list.
177   mChildren.PushBack(childNode);
178
179   // Inform property observers of new connection
180   childNode->ConnectToSceneGraph();
181 }
182
183 void Node::DisconnectChild(BufferIndex updateBufferIndex, Node& childNode)
184 {
185   DALI_ASSERT_ALWAYS(this != &childNode);
186   DALI_ASSERT_ALWAYS(childNode.GetParent() == this);
187
188   // Find the childNode and remove it
189   Node* found(nullptr);
190
191   const NodeIter endIter = mChildren.End();
192   for(NodeIter iter = mChildren.Begin(); iter != endIter; ++iter)
193   {
194     Node* current = *iter;
195     if(current == &childNode)
196     {
197       found = current;
198       mChildren.Erase(iter); // order matters here
199       break;                 // iter is no longer valid
200     }
201   }
202   DALI_ASSERT_ALWAYS(nullptr != found);
203
204   found->RecursiveDisconnectFromSceneGraph(updateBufferIndex);
205 }
206
207 void Node::AddRenderer(const RendererKey& renderer)
208 {
209   // If it is the first renderer added, make sure the world transform will be calculated
210   // in the next update as world transform is not computed if node has no renderers.
211   if(mRenderers.Empty())
212   {
213     mDirtyFlags |= NodePropertyFlags::TRANSFORM;
214   }
215   else
216   {
217     // Check that it has not been already added.
218     for(auto&& existingRenderer : mRenderers)
219     {
220       if(existingRenderer == renderer)
221       {
222         // Renderer is already in the list.
223         return;
224       }
225     }
226   }
227
228   SetUpdated(true);
229
230   mRenderers.PushBack(renderer);
231 }
232
233 void Node::RemoveRenderer(const RendererKey& renderer)
234 {
235   RendererContainer::SizeType rendererCount(mRenderers.Size());
236   for(RendererContainer::SizeType i = 0; i < rendererCount; ++i)
237   {
238     if(mRenderers[i] == renderer)
239     {
240       SetUpdated(true);
241       mRenderers.Erase(mRenderers.Begin() + i);
242       return;
243     }
244   }
245 }
246
247 NodePropertyFlags Node::GetDirtyFlags() const
248 {
249   // get initial dirty flags, they are reset ResetDefaultProperties, but setters may have made the node dirty already
250   NodePropertyFlags flags = mDirtyFlags;
251
252   // Check whether the visible property has changed
253   if(!mVisible.IsClean())
254   {
255     flags |= NodePropertyFlags::VISIBLE;
256   }
257
258   // Check whether the color property has changed
259   if(!mColor.IsClean())
260   {
261     flags |= NodePropertyFlags::COLOR;
262   }
263
264   return flags;
265 }
266
267 NodePropertyFlags Node::GetInheritedDirtyFlags(NodePropertyFlags parentFlags) const
268 {
269   // Size is not inherited. VisibleFlag is inherited
270   static const NodePropertyFlags InheritedDirtyFlags = NodePropertyFlags::TRANSFORM | NodePropertyFlags::VISIBLE | NodePropertyFlags::COLOR;
271   using UnderlyingType                               = typename std::underlying_type<NodePropertyFlags>::type;
272
273   return static_cast<NodePropertyFlags>(static_cast<UnderlyingType>(mDirtyFlags) |
274                                         (static_cast<UnderlyingType>(parentFlags) & static_cast<UnderlyingType>(InheritedDirtyFlags)));
275 }
276
277 void Node::ResetDirtyFlags(BufferIndex updateBufferIndex)
278 {
279   mDirtyFlags = NodePropertyFlags::NOTHING;
280
281   mUpdateAreaChanged = false;
282 }
283
284 void Node::UpdateUniformHash(BufferIndex bufferIndex)
285 {
286   uint64_t hash = 0xc70f6907UL;
287   for(uint32_t i = 0u, count = mUniformMaps.Count(); i < count; ++i)
288   {
289     hash = mUniformMaps[i].propertyPtr->Hash(bufferIndex, hash);
290   }
291   if(mUniformsHash != hash)
292   {
293     mUniformsHash = hash;
294     SetUpdated(true);
295   }
296 }
297
298 void Node::SetParent(Node& parentNode)
299 {
300   DALI_ASSERT_ALWAYS(this != &parentNode);
301   DALI_ASSERT_ALWAYS(!mIsRoot);
302   DALI_ASSERT_ALWAYS(mParent == nullptr);
303
304   mParent = &parentNode;
305
306   if(mTransformManagerData.Id() != INVALID_TRANSFORM_ID)
307   {
308     mTransformManagerData.Manager()->SetParent(mTransformManagerData.Id(), parentNode.GetTransformId());
309   }
310 }
311
312 void Node::RecursiveDisconnectFromSceneGraph(BufferIndex updateBufferIndex)
313 {
314   DALI_ASSERT_ALWAYS(!mIsRoot);
315   DALI_ASSERT_ALWAYS(mParent != nullptr);
316
317   const NodeIter endIter = mChildren.End();
318   for(NodeIter iter = mChildren.Begin(); iter != endIter; ++iter)
319   {
320     (*iter)->RecursiveDisconnectFromSceneGraph(updateBufferIndex);
321   }
322
323   // Animators, Constraints etc. should be disconnected from the child's properties.
324   PropertyOwner::DisconnectFromSceneGraph(updateBufferIndex);
325
326   // Remove back-pointer to parent
327   mParent = nullptr;
328
329   // Remove all child pointers
330   mChildren.Clear();
331
332   if(mTransformManagerData.Id() != INVALID_TRANSFORM_ID)
333   {
334     mTransformManagerData.Manager()->SetParent(mTransformManagerData.Id(), INVALID_TRANSFORM_ID);
335   }
336 }
337
338 uint32_t Node::GetMemoryPoolCapacity()
339 {
340   return GetNodeMemoryPool().GetCapacity();
341 }
342
343 } // namespace SceneGraph
344
345 } // namespace Internal
346
347 } // namespace Dali