2 * Copyright (c) 2023 Samsung Electronics Co., Ltd.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
19 #include <dali/internal/render/common/render-item.h>
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>
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>& GetRenderItemPool()
31 static Dali::Internal::MemoryPoolObjectAllocator<Dali::Internal::SceneGraph::RenderItem> gRenderItemPool;
32 return gRenderItemPool;
42 RenderItem* RenderItem::New()
44 return new(GetRenderItemPool().AllocateRaw()) RenderItem();
47 RenderItemKey RenderItem::NewKey()
49 void* ptr = GetRenderItemPool().AllocateRaw();
50 auto key = GetRenderItemPool().GetKeyFromPtr(static_cast<RenderItem*>(ptr));
51 new(ptr) RenderItem();
52 return RenderItemKey(key);
55 RenderItem::RenderItem()
56 : mModelMatrix(false),
57 mModelViewMatrix(false),
68 RenderItem::~RenderItem() = default;
70 RenderItem* RenderItem::Get(RenderItemKey::KeyType key)
72 return GetRenderItemPool().GetPtrFromKey(key);
75 RenderItemKey RenderItem::GetKey(const RenderItem& renderItem)
77 return RenderItemKey(GetRenderItemPool().GetKeyFromPtr(const_cast<RenderItem*>(&renderItem)));
80 RenderItemKey RenderItem::GetKey(RenderItem* renderItem)
82 return RenderItemKey(GetRenderItemPool().GetKeyFromPtr(renderItem));
85 ClippingBox RenderItem::CalculateTransformSpaceAABB(const Matrix& transformMatrix, const Vector3& position, const Vector3& size)
87 // Calculate extent vector of the AABB:
88 const float halfActorX = size.x * 0.5f;
89 const float halfActorY = size.y * 0.5f;
91 // To transform the actor bounds to the transformed space, We do a fast, 2D version of a matrix multiply optimized for 2D quads.
92 // This reduces float multiplications from 64 (16 * 4) to 12 (4 * 3).
93 // We create an array of 4 corners and directly initialize the first 3 with the matrix multiplication result of the respective corner.
94 // This causes the construction of the vector arrays contents in-place for optimization.
95 // We place the coords into the array in clockwise order, so we know opposite corners are always i + 2 from corner i.
96 // We skip the 4th corner here as we can calculate that from the other 3, bypassing matrix multiplication.
97 // Note: The below transform methods use a fast (2D) matrix multiply (only 4 multiplications are done).
98 Vector2 corners[4]{Transform2D(transformMatrix, -halfActorX + position.x, -halfActorY + position.y),
99 Transform2D(transformMatrix, halfActorX + position.x, -halfActorY + position.y),
100 Transform2D(transformMatrix, halfActorX + position.x, halfActorY + position.y)};
102 // 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).
103 corners[3] = Vector2(corners[0] + (corners[2] - corners[1]));
105 // Calculate the AABB:
106 // We use knowledge that opposite corners will be the max/min of each other. Doing this reduces the normal 12 branching comparisons to 3.
107 // The standard equivalent min/max code of the below would be:
108 // Vector2 AABBmax( std::max( corners[0].x, std::max( corners[1].x, std::max( corners[3].x, corners[2].x ) ) ),
109 // std::max( corners[0].y, std::max( corners[1].y, std::max( corners[3].y, corners[2].y ) ) ) );
110 // Vector2 AABBmin( std::min( corners[0].x, std::min( corners[1].x, std::min( corners[3].x, corners[2].x ) ) ),
111 // std::min( corners[0].y, std::min( corners[1].y, std::min( corners[3].y, corners[2].y ) ) ) );
112 unsigned int smallestX = 0u;
113 // Loop 3 times to find the index of the smallest X value.
114 // Note: We deliberately do NOT unroll the code here as this hampers the compilers output.
115 for(unsigned int i = 1u; i < 4u; ++i)
117 if(corners[i].x < corners[smallestX].x)
123 // As we are dealing with a rectangle, we can assume opposite corners are the largest.
124 // So without doing min/max branching, we can fetch the min/max values of all the remaining X/Y coords from this one index.
125 Vector4 aabb(corners[smallestX].x, corners[(smallestX + 3u) % 4].y, corners[(smallestX + 2u) % 4].x, corners[(smallestX + 1u) % 4].y);
127 // Round outwards from center
128 int x = static_cast<int>(floor(aabb.x));
129 int y = static_cast<int>(floor(aabb.y));
130 int z = static_cast<int>(ceilf(aabb.z));
131 int w = static_cast<int>(ceilf(aabb.w));
133 return ClippingBox(x, y, z - x, fabsf(w - y));
136 ClippingBox RenderItem::CalculateViewportSpaceAABB(const Matrix& modelViewMatrix, const Vector3& position, const Vector3& size, const int viewportWidth, const int viewportHeight)
138 // Calculate extent vector of the AABB:
139 const float halfActorX = size.x * 0.5f;
140 const float halfActorY = size.y * 0.5f;
142 // To transform the actor bounds to screen-space, We do a fast, 2D version of a matrix multiply optimized for 2D quads.
143 // This reduces float multiplications from 64 (16 * 4) to 12 (4 * 3).
144 // We create an array of 4 corners and directly initialize the first 3 with the matrix multiplication result of the respective corner.
145 // This causes the construction of the vector arrays contents in-place for optimization.
146 // We place the coords into the array in clockwise order, so we know opposite corners are always i + 2 from corner i.
147 // We skip the 4th corner here as we can calculate that from the other 3, bypassing matrix multiplication.
148 // Note: The below transform methods use a fast (2D) matrix multiply (only 4 multiplications are done).
149 Vector2 corners[4]{Transform2D(modelViewMatrix, -halfActorX + position.x, -halfActorY + position.y),
150 Transform2D(modelViewMatrix, halfActorX + position.x, -halfActorY + position.y),
151 Transform2D(modelViewMatrix, halfActorX + position.x, halfActorY + position.y)};
153 // 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).
154 corners[3] = Vector2(corners[0] + (corners[2] - corners[1]));
156 // Calculate the AABB:
157 // We use knowledge that opposite corners will be the max/min of each other. Doing this reduces the normal 12 branching comparisons to 3.
158 // The standard equivalent min/max code of the below would be:
159 // Vector2 AABBmax( std::max( corners[0].x, std::max( corners[1].x, std::max( corners[3].x, corners[2].x ) ) ),
160 // std::max( corners[0].y, std::max( corners[1].y, std::max( corners[3].y, corners[2].y ) ) ) );
161 // Vector2 AABBmin( std::min( corners[0].x, std::min( corners[1].x, std::min( corners[3].x, corners[2].x ) ) ),
162 // std::min( corners[0].y, std::min( corners[1].y, std::min( corners[3].y, corners[2].y ) ) ) );
163 unsigned int smallestX = 0u;
164 // Loop 3 times to find the index of the smallest X value.
165 // Note: We deliberately do NOT unroll the code here as this hampers the compilers output.
166 for(unsigned int i = 1u; i < 4u; ++i)
168 if(corners[i].x < corners[smallestX].x)
174 // As we are dealing with a rectangle, we can assume opposite corners are the largest.
175 // So without doing min/max branching, we can fetch the min/max values of all the remaining X/Y coords from this one index.
176 Vector4 aabb(corners[smallestX].x, corners[(smallestX + 3u) % 4].y, corners[(smallestX + 2u) % 4].x, corners[(smallestX + 1u) % 4].y);
178 // Return the AABB in screen-space pixels (x, y, width, height).
179 // Note: This is a algebraic simplification of: ( viewport.x - aabb.width ) / 2 - ( ( aabb.width / 2 ) + aabb.x ) per axis.
180 Vector4 aabbInScreen(static_cast<float>(viewportWidth) * 0.5f - aabb.z,
181 static_cast<float>(viewportHeight) * 0.5f - aabb.w,
182 static_cast<float>(viewportWidth) * 0.5f - aabb.x,
183 static_cast<float>(viewportHeight) * 0.5f - aabb.y);
185 int x = static_cast<int>(floor(aabbInScreen.x));
186 int y = static_cast<int>(floor(aabbInScreen.y));
187 int z = static_cast<int>(roundf(aabbInScreen.z));
188 int w = static_cast<int>(roundf(aabbInScreen.w));
190 return ClippingBox(x, y, z - x, w - y);
193 void RenderItem::operator delete(void* ptr)
195 GetRenderItemPool().Free(static_cast<RenderItem*>(ptr));
198 uint32_t RenderItem::GetMemoryPoolCapacity()
200 return GetRenderItemPool().GetCapacity();
203 } // namespace SceneGraph
205 } // namespace Internal