X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=dali%2Finternal%2Frender%2Fcommon%2Frender-item.cpp;h=0197443c39d3f566fe7b77bc1ff67f00f5f0edfe;hb=23a2b8163c01a41b35dfbe8b8d9f2641777a7245;hp=a177ee48d03b05d569425d622d7e878f36357dfa;hpb=651fe1a5379fdd21bfb90ad60e06b0d78b2e2979;p=platform%2Fcore%2Fuifw%2Fdali-core.git diff --git a/dali/internal/render/common/render-item.cpp b/dali/internal/render/common/render-item.cpp index a177ee4..0197443 100644 --- a/dali/internal/render/common/render-item.cpp +++ b/dali/internal/render/common/render-item.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014 Samsung Electronics Co., Ltd. + * Copyright (c) 2023 Samsung Electronics Co., Ltd. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,68 +19,181 @@ #include // INTERNAL INCLUDES +#include +#include #include -namespace Dali +namespace { +//Memory pool used to allocate new RenderItems. Memory used by this pool will be released when shutting down DALi +Dali::Internal::MemoryPoolObjectAllocator gRenderItemPool; +} // namespace +namespace Dali +{ namespace Internal { - namespace SceneGraph { - -RenderItem::RenderItem() -: mModelViewMatrix( false ), - mRenderer( NULL ), - mNode( NULL ), - mDepthIndex( 0 ), - mIsOpaque( true ) +RenderItem* RenderItem::New() { + return new(gRenderItemPool.AllocateRaw()) RenderItem(); } -RenderItem::~RenderItem() +RenderItemKey RenderItem::NewKey() { + void* ptr = gRenderItemPool.AllocateRaw(); + auto key = gRenderItemPool.GetKeyFromPtr(static_cast(ptr)); + new(ptr) RenderItem(); + return RenderItemKey(key); } -void RenderItem::Reset() +RenderItem::RenderItem() +: mModelMatrix(false), + mModelViewMatrix(false), + mSize(), + mRenderer{}, + mNode(nullptr), + mTextureSet(nullptr), + mDepthIndex(0), + mIsOpaque(true), + mIsUpdated(false) { - mRenderer = NULL; } -void RenderItem::SetRenderer( Render::Renderer* renderer ) +RenderItem::~RenderItem() = default; + +RenderItem* RenderItem::Get(RenderItemKey::KeyType key) { - mRenderer = renderer; + return gRenderItemPool.GetPtrFromKey(key); } -void RenderItem::SetNode( Node* node ) +RenderItemKey RenderItem::GetKey(const RenderItem& renderItem) { - mNode = node; + return RenderItemKey(gRenderItemPool.GetKeyFromPtr(const_cast(&renderItem))); } -Render::Renderer& RenderItem::GetRenderer() const +RenderItemKey RenderItem::GetKey(RenderItem* renderItem) { - return *mRenderer; + return RenderItemKey(gRenderItemPool.GetKeyFromPtr(renderItem)); } -Matrix& RenderItem::GetModelViewMatrix() +ClippingBox RenderItem::CalculateTransformSpaceAABB(const Matrix& transformMatrix, const Vector3& position, const Vector3& size) { - return mModelViewMatrix; + // Calculate extent vector of the AABB: + const float halfActorX = size.x * 0.5f; + const float halfActorY = size.y * 0.5f; + + // To transform the actor bounds to the transformed space, We do a fast, 2D version of a matrix multiply optimized for 2D quads. + // This reduces float multiplications from 64 (16 * 4) to 12 (4 * 3). + // We create an array of 4 corners and directly initialize the first 3 with the matrix multiplication result of the respective corner. + // This causes the construction of the vector arrays contents in-place for optimization. + // We place the coords into the array in clockwise order, so we know opposite corners are always i + 2 from corner i. + // We skip the 4th corner here as we can calculate that from the other 3, bypassing matrix multiplication. + // Note: The below transform methods use a fast (2D) matrix multiply (only 4 multiplications are done). + Vector2 corners[4]{Transform2D(transformMatrix, -halfActorX + position.x, -halfActorY + position.y), + Transform2D(transformMatrix, halfActorX + position.x, -halfActorY + position.y), + Transform2D(transformMatrix, halfActorX + position.x, halfActorY + position.y)}; + + // 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). + corners[3] = Vector2(corners[0] + (corners[2] - corners[1])); + + // Calculate the AABB: + // We use knowledge that opposite corners will be the max/min of each other. Doing this reduces the normal 12 branching comparisons to 3. + // The standard equivalent min/max code of the below would be: + // Vector2 AABBmax( std::max( corners[0].x, std::max( corners[1].x, std::max( corners[3].x, corners[2].x ) ) ), + // std::max( corners[0].y, std::max( corners[1].y, std::max( corners[3].y, corners[2].y ) ) ) ); + // Vector2 AABBmin( std::min( corners[0].x, std::min( corners[1].x, std::min( corners[3].x, corners[2].x ) ) ), + // std::min( corners[0].y, std::min( corners[1].y, std::min( corners[3].y, corners[2].y ) ) ) ); + unsigned int smallestX = 0u; + // Loop 3 times to find the index of the smallest X value. + // Note: We deliberately do NOT unroll the code here as this hampers the compilers output. + for(unsigned int i = 1u; i < 4u; ++i) + { + if(corners[i].x < corners[smallestX].x) + { + smallestX = i; + } + } + + // As we are dealing with a rectangle, we can assume opposite corners are the largest. + // So without doing min/max branching, we can fetch the min/max values of all the remaining X/Y coords from this one index. + Vector4 aabb(corners[smallestX].x, corners[(smallestX + 3u) % 4].y, corners[(smallestX + 2u) % 4].x, corners[(smallestX + 1u) % 4].y); + + // Round outwards from center + int x = static_cast(floor(aabb.x)); + int y = static_cast(floor(aabb.y)); + int z = static_cast(ceilf(aabb.z)); + int w = static_cast(ceilf(aabb.w)); + + return ClippingBox(x, y, z - x, fabsf(w - y)); } -const Matrix& RenderItem::GetModelViewMatrix() const +ClippingBox RenderItem::CalculateViewportSpaceAABB(const Matrix& modelViewMatrix, const Vector3& position, const Vector3& size, const int viewportWidth, const int viewportHeight) { - return mModelViewMatrix; + // Calculate extent vector of the AABB: + const float halfActorX = size.x * 0.5f; + const float halfActorY = size.y * 0.5f; + + // To transform the actor bounds to screen-space, We do a fast, 2D version of a matrix multiply optimized for 2D quads. + // This reduces float multiplications from 64 (16 * 4) to 12 (4 * 3). + // We create an array of 4 corners and directly initialize the first 3 with the matrix multiplication result of the respective corner. + // This causes the construction of the vector arrays contents in-place for optimization. + // We place the coords into the array in clockwise order, so we know opposite corners are always i + 2 from corner i. + // We skip the 4th corner here as we can calculate that from the other 3, bypassing matrix multiplication. + // Note: The below transform methods use a fast (2D) matrix multiply (only 4 multiplications are done). + Vector2 corners[4]{Transform2D(modelViewMatrix, -halfActorX + position.x, -halfActorY + position.y), + Transform2D(modelViewMatrix, halfActorX + position.x, -halfActorY + position.y), + Transform2D(modelViewMatrix, halfActorX + position.x, halfActorY + position.y)}; + + // 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). + corners[3] = Vector2(corners[0] + (corners[2] - corners[1])); + + // Calculate the AABB: + // We use knowledge that opposite corners will be the max/min of each other. Doing this reduces the normal 12 branching comparisons to 3. + // The standard equivalent min/max code of the below would be: + // Vector2 AABBmax( std::max( corners[0].x, std::max( corners[1].x, std::max( corners[3].x, corners[2].x ) ) ), + // std::max( corners[0].y, std::max( corners[1].y, std::max( corners[3].y, corners[2].y ) ) ) ); + // Vector2 AABBmin( std::min( corners[0].x, std::min( corners[1].x, std::min( corners[3].x, corners[2].x ) ) ), + // std::min( corners[0].y, std::min( corners[1].y, std::min( corners[3].y, corners[2].y ) ) ) ); + unsigned int smallestX = 0u; + // Loop 3 times to find the index of the smallest X value. + // Note: We deliberately do NOT unroll the code here as this hampers the compilers output. + for(unsigned int i = 1u; i < 4u; ++i) + { + if(corners[i].x < corners[smallestX].x) + { + smallestX = i; + } + } + + // As we are dealing with a rectangle, we can assume opposite corners are the largest. + // So without doing min/max branching, we can fetch the min/max values of all the remaining X/Y coords from this one index. + Vector4 aabb(corners[smallestX].x, corners[(smallestX + 3u) % 4].y, corners[(smallestX + 2u) % 4].x, corners[(smallestX + 1u) % 4].y); + + // Return the AABB in screen-space pixels (x, y, width, height). + // Note: This is a algebraic simplification of: ( viewport.x - aabb.width ) / 2 - ( ( aabb.width / 2 ) + aabb.x ) per axis. + Vector4 aabbInScreen(static_cast(viewportWidth) * 0.5f - aabb.z, + static_cast(viewportHeight) * 0.5f - aabb.w, + static_cast(viewportWidth) * 0.5f - aabb.x, + static_cast(viewportHeight) * 0.5f - aabb.y); + + int x = static_cast(floor(aabbInScreen.x)); + int y = static_cast(floor(aabbInScreen.y)); + int z = static_cast(roundf(aabbInScreen.z)); + int w = static_cast(roundf(aabbInScreen.w)); + + return ClippingBox(x, y, z - x, w - y); } -void RenderItem::SetDepthIndex( int depthIndex ) +void RenderItem::operator delete(void* ptr) { - mDepthIndex = depthIndex; + gRenderItemPool.Free(static_cast(ptr)); } -void RenderItem::SetIsOpaque( bool isOpaque ) +uint32_t RenderItem::GetMemoryPoolCapacity() { - mIsOpaque = isOpaque; + return gRenderItemPool.GetCapacity(); } } // namespace SceneGraph