Merge "Fast bounding-box clipping feature" into devel/master
[platform/core/uifw/dali-core.git] / dali / internal / render / common / render-item.cpp
1 /*
2  * Copyright (c) 2017 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/memory-pool-object-allocator.h>
23 #include <dali/internal/render/renderers/render-renderer.h>
24 #include <dali/internal/common/math.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 }
31 namespace Dali
32 {
33
34 namespace Internal
35 {
36
37 namespace SceneGraph
38 {
39
40 RenderItem* RenderItem::New()
41 {
42   return new ( gRenderItemPool.AllocateRaw() ) RenderItem();
43 }
44
45 RenderItem::RenderItem()
46 : mModelMatrix( false ),
47   mModelViewMatrix( false ),
48   mSize(),
49   mRenderer( NULL ),
50   mNode( NULL ),
51   mDepthIndex( 0 ),
52   mIsOpaque( true )
53 {
54 }
55
56 RenderItem::~RenderItem()
57 {
58 }
59
60
61 ClippingBox RenderItem::CalculateViewportSpaceAABB( const int viewportWidth, const int viewportHeight ) const
62 {
63   // Calculate extent vector of the AABB:
64   const float halfActorX = mSize.x * 0.5f;
65   const float halfActorY = mSize.y * 0.5f;
66
67   // To transform the actor bounds to screen-space, We do a fast, 2D version of a matrix multiply optimized for 2D quads.
68   // This reduces float multiplications from 64 (16 * 4) to 12 (4 * 3).
69   // We create an array of 4 corners and directly initialize the first 3 with the matrix multiplication result of the respective corner.
70   // This causes the construction of the vector arrays contents in-place for optimization.
71   // We place the coords into the array in clockwise order, so we know opposite corners are always i + 2 from corner i.
72   // We skip the 4th corner here as we can calculate that from the other 3, bypassing matrix multiplication.
73   // Note: The below transform methods use a fast (2D) matrix multiply (only 4 multiplications are done).
74   Vector2 corners[4]{ Transform2D( mModelViewMatrix, -halfActorX, -halfActorY ),
75                       Transform2D( mModelViewMatrix,  halfActorX, -halfActorY ),
76                       Transform2D( mModelViewMatrix,  halfActorX,  halfActorY ) };
77
78   // 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).
79   corners[3] = Vector2( corners[0] + ( corners[2] - corners[1] ) );
80
81   // Calculate the AABB:
82   // We use knowledge that opposite corners will be the max/min of each other. Doing this reduces the normal 12 branching comparisons to 3.
83   // The standard equivalent min/max code of the below would be:
84   //       Vector2 AABBmax( std::max( corners[0].x, std::max( corners[1].x, std::max( corners[3].x, corners[2].x ) ) ),
85   //                        std::max( corners[0].y, std::max( corners[1].y, std::max( corners[3].y, corners[2].y ) ) ) );
86   //       Vector2 AABBmin( std::min( corners[0].x, std::min( corners[1].x, std::min( corners[3].x, corners[2].x ) ) ),
87   //                        std::min( corners[0].y, std::min( corners[1].y, std::min( corners[3].y, corners[2].y ) ) ) );
88   unsigned int smallestX = 0u;
89   // Loop 3 times to find the index of the smallest X value.
90   // Note: We deliberately do NOT unroll the code here as this hampers the compilers output.
91   for( unsigned int i = 1u; i < 4u; ++i )
92   {
93     if( corners[i].x < corners[smallestX].x )
94     {
95       smallestX = i;
96     }
97   }
98
99   // As we are dealing with a rectangle, we can assume opposite corners are the largest.
100   // So without doing min/max branching, we can fetch the min/max values of all the remaining X/Y coords from this one index.
101   Vector4 aabb( corners[smallestX].x, corners[( smallestX + 3u ) % 4].y, corners[( smallestX + 2u ) % 4].x, corners[( smallestX + 1u ) % 4].y );
102
103   // Convert maximums to extents.
104   aabb.z -= aabb.x;
105   aabb.w -= aabb.y;
106
107   // Return the AABB in screen-space pixels (x, y, width, height).
108   // Note: This is a algebraic simplification of: ( viewport.x - aabb.width ) / 2 - ( ( aabb.width / 2 ) + aabb.x ) per axis.
109   return ClippingBox( ( viewportWidth / 2 ) - aabb.z - aabb.x, ( viewportHeight / 2 ) - aabb.w - aabb.y, aabb.z, aabb.w );
110 }
111
112 void RenderItem::operator delete( void* ptr )
113 {
114   gRenderItemPool.Free( static_cast<RenderItem*>( ptr ) );
115 }
116
117
118 } // namespace SceneGraph
119
120 } // namespace Internal
121
122 } // namespace Dali