0197443c39d3f566fe7b77bc1ff67f00f5f0edfe
[platform/core/uifw/dali-core.git] / dali / internal / render / common / render-item.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/render/common/render-item.h>
20
21 // INTERNAL INCLUDES
22 #include <dali/internal/common/math.h>
23 #include <dali/internal/common/memory-pool-object-allocator.h>
24 #include <dali/internal/render/renderers/render-renderer.h>
25
26 namespace
27 {
28 //Memory pool used to allocate new RenderItems. Memory used by this pool will be released when shutting down DALi
29 Dali::Internal::MemoryPoolObjectAllocator<Dali::Internal::SceneGraph::RenderItem> gRenderItemPool;
30 } // namespace
31
32 namespace Dali
33 {
34 namespace Internal
35 {
36 namespace SceneGraph
37 {
38 RenderItem* RenderItem::New()
39 {
40   return new(gRenderItemPool.AllocateRaw()) RenderItem();
41 }
42
43 RenderItemKey RenderItem::NewKey()
44 {
45   void* ptr = gRenderItemPool.AllocateRaw();
46   auto  key = gRenderItemPool.GetKeyFromPtr(static_cast<RenderItem*>(ptr));
47   new(ptr) RenderItem();
48   return RenderItemKey(key);
49 }
50
51 RenderItem::RenderItem()
52 : mModelMatrix(false),
53   mModelViewMatrix(false),
54   mSize(),
55   mRenderer{},
56   mNode(nullptr),
57   mTextureSet(nullptr),
58   mDepthIndex(0),
59   mIsOpaque(true),
60   mIsUpdated(false)
61 {
62 }
63
64 RenderItem::~RenderItem() = default;
65
66 RenderItem* RenderItem::Get(RenderItemKey::KeyType key)
67 {
68   return gRenderItemPool.GetPtrFromKey(key);
69 }
70
71 RenderItemKey RenderItem::GetKey(const RenderItem& renderItem)
72 {
73   return RenderItemKey(gRenderItemPool.GetKeyFromPtr(const_cast<RenderItem*>(&renderItem)));
74 }
75
76 RenderItemKey RenderItem::GetKey(RenderItem* renderItem)
77 {
78   return RenderItemKey(gRenderItemPool.GetKeyFromPtr(renderItem));
79 }
80
81 ClippingBox RenderItem::CalculateTransformSpaceAABB(const Matrix& transformMatrix, const Vector3& position, const Vector3& size)
82 {
83   // Calculate extent vector of the AABB:
84   const float halfActorX = size.x * 0.5f;
85   const float halfActorY = size.y * 0.5f;
86
87   // To transform the actor bounds to the transformed space, We do a fast, 2D version of a matrix multiply optimized for 2D quads.
88   // This reduces float multiplications from 64 (16 * 4) to 12 (4 * 3).
89   // We create an array of 4 corners and directly initialize the first 3 with the matrix multiplication result of the respective corner.
90   // This causes the construction of the vector arrays contents in-place for optimization.
91   // We place the coords into the array in clockwise order, so we know opposite corners are always i + 2 from corner i.
92   // We skip the 4th corner here as we can calculate that from the other 3, bypassing matrix multiplication.
93   // Note: The below transform methods use a fast (2D) matrix multiply (only 4 multiplications are done).
94   Vector2 corners[4]{Transform2D(transformMatrix, -halfActorX + position.x, -halfActorY + position.y),
95                      Transform2D(transformMatrix, halfActorX + position.x, -halfActorY + position.y),
96                      Transform2D(transformMatrix, halfActorX + position.x, halfActorY + position.y)};
97
98   // As we are dealing with a rectangle, we can do a fast calculation to get the 4th corner from knowing the other 3 (even if rotated).
99   corners[3] = Vector2(corners[0] + (corners[2] - corners[1]));
100
101   // Calculate the AABB:
102   // We use knowledge that opposite corners will be the max/min of each other. Doing this reduces the normal 12 branching comparisons to 3.
103   // The standard equivalent min/max code of the below would be:
104   //       Vector2 AABBmax( std::max( corners[0].x, std::max( corners[1].x, std::max( corners[3].x, corners[2].x ) ) ),
105   //                        std::max( corners[0].y, std::max( corners[1].y, std::max( corners[3].y, corners[2].y ) ) ) );
106   //       Vector2 AABBmin( std::min( corners[0].x, std::min( corners[1].x, std::min( corners[3].x, corners[2].x ) ) ),
107   //                        std::min( corners[0].y, std::min( corners[1].y, std::min( corners[3].y, corners[2].y ) ) ) );
108   unsigned int smallestX = 0u;
109   // Loop 3 times to find the index of the smallest X value.
110   // Note: We deliberately do NOT unroll the code here as this hampers the compilers output.
111   for(unsigned int i = 1u; i < 4u; ++i)
112   {
113     if(corners[i].x < corners[smallestX].x)
114     {
115       smallestX = i;
116     }
117   }
118
119   // As we are dealing with a rectangle, we can assume opposite corners are the largest.
120   // So without doing min/max branching, we can fetch the min/max values of all the remaining X/Y coords from this one index.
121   Vector4 aabb(corners[smallestX].x, corners[(smallestX + 3u) % 4].y, corners[(smallestX + 2u) % 4].x, corners[(smallestX + 1u) % 4].y);
122
123   // Round outwards from center
124   int x = static_cast<int>(floor(aabb.x));
125   int y = static_cast<int>(floor(aabb.y));
126   int z = static_cast<int>(ceilf(aabb.z));
127   int w = static_cast<int>(ceilf(aabb.w));
128
129   return ClippingBox(x, y, z - x, fabsf(w - y));
130 }
131
132 ClippingBox RenderItem::CalculateViewportSpaceAABB(const Matrix& modelViewMatrix, const Vector3& position, const Vector3& size, const int viewportWidth, const int viewportHeight)
133 {
134   // Calculate extent vector of the AABB:
135   const float halfActorX = size.x * 0.5f;
136   const float halfActorY = size.y * 0.5f;
137
138   // To transform the actor bounds to screen-space, We do a fast, 2D version of a matrix multiply optimized for 2D quads.
139   // This reduces float multiplications from 64 (16 * 4) to 12 (4 * 3).
140   // We create an array of 4 corners and directly initialize the first 3 with the matrix multiplication result of the respective corner.
141   // This causes the construction of the vector arrays contents in-place for optimization.
142   // We place the coords into the array in clockwise order, so we know opposite corners are always i + 2 from corner i.
143   // We skip the 4th corner here as we can calculate that from the other 3, bypassing matrix multiplication.
144   // Note: The below transform methods use a fast (2D) matrix multiply (only 4 multiplications are done).
145   Vector2 corners[4]{Transform2D(modelViewMatrix, -halfActorX + position.x, -halfActorY + position.y),
146                      Transform2D(modelViewMatrix, halfActorX + position.x, -halfActorY + position.y),
147                      Transform2D(modelViewMatrix, halfActorX + position.x, halfActorY + position.y)};
148
149   // As we are dealing with a rectangle, we can do a fast calculation to get the 4th corner from knowing the other 3 (even if rotated).
150   corners[3] = Vector2(corners[0] + (corners[2] - corners[1]));
151
152   // Calculate the AABB:
153   // We use knowledge that opposite corners will be the max/min of each other. Doing this reduces the normal 12 branching comparisons to 3.
154   // The standard equivalent min/max code of the below would be:
155   //       Vector2 AABBmax( std::max( corners[0].x, std::max( corners[1].x, std::max( corners[3].x, corners[2].x ) ) ),
156   //                        std::max( corners[0].y, std::max( corners[1].y, std::max( corners[3].y, corners[2].y ) ) ) );
157   //       Vector2 AABBmin( std::min( corners[0].x, std::min( corners[1].x, std::min( corners[3].x, corners[2].x ) ) ),
158   //                        std::min( corners[0].y, std::min( corners[1].y, std::min( corners[3].y, corners[2].y ) ) ) );
159   unsigned int smallestX = 0u;
160   // Loop 3 times to find the index of the smallest X value.
161   // Note: We deliberately do NOT unroll the code here as this hampers the compilers output.
162   for(unsigned int i = 1u; i < 4u; ++i)
163   {
164     if(corners[i].x < corners[smallestX].x)
165     {
166       smallestX = i;
167     }
168   }
169
170   // As we are dealing with a rectangle, we can assume opposite corners are the largest.
171   // So without doing min/max branching, we can fetch the min/max values of all the remaining X/Y coords from this one index.
172   Vector4 aabb(corners[smallestX].x, corners[(smallestX + 3u) % 4].y, corners[(smallestX + 2u) % 4].x, corners[(smallestX + 1u) % 4].y);
173
174   // Return the AABB in screen-space pixels (x, y, width, height).
175   // Note: This is a algebraic simplification of: ( viewport.x - aabb.width ) / 2 - ( ( aabb.width / 2 ) + aabb.x ) per axis.
176   Vector4 aabbInScreen(static_cast<float>(viewportWidth) * 0.5f - aabb.z,
177                        static_cast<float>(viewportHeight) * 0.5f - aabb.w,
178                        static_cast<float>(viewportWidth) * 0.5f - aabb.x,
179                        static_cast<float>(viewportHeight) * 0.5f - aabb.y);
180
181   int x = static_cast<int>(floor(aabbInScreen.x));
182   int y = static_cast<int>(floor(aabbInScreen.y));
183   int z = static_cast<int>(roundf(aabbInScreen.z));
184   int w = static_cast<int>(roundf(aabbInScreen.w));
185
186   return ClippingBox(x, y, z - x, w - y);
187 }
188
189 void RenderItem::operator delete(void* ptr)
190 {
191   gRenderItemPool.Free(static_cast<RenderItem*>(ptr));
192 }
193
194 uint32_t RenderItem::GetMemoryPoolCapacity()
195 {
196   return gRenderItemPool.GetCapacity();
197 }
198
199 } // namespace SceneGraph
200
201 } // namespace Internal
202
203 } // namespace Dali