+ // We traversed up the tree, we need to apply a new scissor rectangle (unless we are at the root).
+ traversedUpTree = true;
+ }
+ if( clippingNode && childStackDepth > 0u && childStackDepth == scissorDepth ) // case of sibling clip area
+ {
+ mScissorStack.pop_back();
+ --childStackDepth;
+ }
+
+ // If we are on a clipping node, or we have traveled up the tree and gone back past a clipping node, may need to apply a new scissor clip.
+ if( clippingNode || traversedUpTree )
+ {
+ // First, check if we are a clipping node.
+ if( clippingNode )
+ {
+ // This is a clipping node. We generate the AABB for this node and intersect it with the previous intersection further up the tree.
+
+ // Get the AABB bounding box for the current render item.
+ const ClippingBox scissorBox( item.CalculateViewportSpaceAABB( mViewportRectangle.width, mViewportRectangle.height ) );
+
+ // Get the AABB for the parent item that we must intersect with.
+ const ClippingBox& parentBox( mScissorStack.back() );
+
+ // We must reduce the clipping area based on the parents area to allow nested clips. This is a set intersection function.
+ // We add the new scissor box to the stack so we can return to it if needed.
+ mScissorStack.emplace_back( IntersectAABB( parentBox, scissorBox ) );
+ }
+
+ // The scissor test is enabled if we have any children on the stack, OR, if there are none but it is a user specified layer scissor box.
+ // IE. It is not enabled if we are at the top of the stack and the layer does not have a specified clipping box.
+ const bool scissorEnabled = ( mScissorStack.size() > 0u ) || mHasLayerScissor;
+
+ // Enable the scissor test based on the above calculation
+ context.SetScissorTest( scissorEnabled );
+
+ // If scissor is enabled, we use the calculated screen-space coordinates (now in the stack).
+ if( scissorEnabled )
+ {
+ ClippingBox useScissorBox( mScissorStack.back() );
+ GLint x = useScissorBox.x;
+ GLint y = useScissorBox.y;
+ if( orientation == 90 )
+ {
+ x = mViewportRectangle.height - (useScissorBox.y + useScissorBox.height);
+ y = useScissorBox.x;
+ context.Scissor( x, y, useScissorBox.height, useScissorBox.width );
+ }
+ else if( orientation == 180 )
+ {
+ x = mViewportRectangle.width - (useScissorBox.x + useScissorBox.width);
+ y = mViewportRectangle.height - (useScissorBox.y + useScissorBox.height);
+ context.Scissor( x, y, useScissorBox.width, useScissorBox.height );
+ }
+ else if( orientation == 270 )
+ {
+ x = useScissorBox.y;
+ y = mViewportRectangle.width - (useScissorBox.x + useScissorBox.width);
+ context.Scissor( x, y, useScissorBox.height, useScissorBox.width );
+ }
+ else
+ {
+ context.Scissor( x, y, useScissorBox.width, useScissorBox.height );
+ }
+ }
+ }
+}
+
+inline void RenderAlgorithms::SetupClipping( const RenderItem& item,
+ Context& context,
+ bool& usedStencilBuffer,
+ uint32_t& lastClippingDepth,
+ uint32_t& lastClippingId,
+ Integration::StencilBufferAvailable stencilBufferAvailable,
+ int orientation )
+{
+ RenderMode::Type renderMode = RenderMode::AUTO;
+ const Renderer *renderer = item.mRenderer;
+ if( renderer )
+ {
+ renderMode = renderer->GetRenderMode();
+ }
+
+ // Setup the stencil using either the automatic clipping feature, or, the manual per-renderer stencil API.
+ // Note: This switch is in order of most likely value first.
+ switch( renderMode )
+ {
+ case RenderMode::AUTO:
+ {
+ // Turn the color buffer on as we always want to render this renderer, regardless of clipping hierarchy.
+ context.ColorMask( true );
+
+ // The automatic clipping feature will manage the scissor and stencil functions, only if stencil buffer is available for the latter.
+ // As both scissor and stencil clips can be nested, we may be simultaneously traversing up the scissor tree, requiring a scissor to be un-done. Whilst simultaneously adding a new stencil clip.
+ // We process both based on our current and old clipping depths for each mode.
+ // Both methods with return rapidly if there is nothing to be done for that type of clipping.
+ SetupScissorClipping( item, context, orientation );
+
+ if( stencilBufferAvailable == Integration::StencilBufferAvailable::TRUE )
+ {
+ SetupStencilClipping( item, context, lastClippingDepth, lastClippingId );
+ }
+ break;
+ }
+
+ case RenderMode::NONE:
+ case RenderMode::COLOR:
+ {
+ // No clipping is performed for these modes.
+ // Note: We do not turn off scissor clipping as it may be used for the whole layer.
+ // The stencil buffer will not be used at all, but we only need to disable it if it's available.
+ if( stencilBufferAvailable == Integration::StencilBufferAvailable::TRUE )
+ {
+ context.EnableStencilBuffer( false );
+ }
+
+ // Setup the color buffer based on the RenderMode.
+ context.ColorMask( renderMode == RenderMode::COLOR );
+ break;
+ }
+
+ case RenderMode::STENCIL:
+ case RenderMode::COLOR_STENCIL:
+ {
+ if( stencilBufferAvailable == Integration::StencilBufferAvailable::TRUE )
+ {
+ // We are using the low-level Renderer Stencil API.
+ // The stencil buffer must be enabled for every renderer with stencil mode on, as renderers in between can disable it.
+ // Note: As the command state is cached, it is only sent when needed.
+ context.EnableStencilBuffer( true );
+
+ // Setup the color buffer based on the RenderMode.
+ context.ColorMask( renderMode == RenderMode::COLOR_STENCIL );
+
+ // If this is the first use of the stencil buffer within this RenderList, clear it (this avoids unnecessary clears).
+ if( !usedStencilBuffer )
+ {
+ context.Clear( GL_STENCIL_BUFFER_BIT, Context::CHECK_CACHED_VALUES );
+ usedStencilBuffer = true;
+ }
+
+ // Setup the stencil buffer based on the renderers properties.
+ context.StencilFunc( DaliStencilFunctionToGL[ renderer->GetStencilFunction() ],
+ renderer->GetStencilFunctionReference(),
+ renderer->GetStencilFunctionMask() );
+ context.StencilOp( DaliStencilOperationToGL[ renderer->GetStencilOperationOnFail() ],
+ DaliStencilOperationToGL[ renderer->GetStencilOperationOnZFail() ],
+ DaliStencilOperationToGL[ renderer->GetStencilOperationOnZPass() ] );
+ context.StencilMask( renderer->GetStencilMask() );
+ }
+ break;
+ }
+ }
+}
+
+inline void RenderAlgorithms::ProcessRenderList( const RenderList& renderList,
+ Context& context,
+ BufferIndex bufferIndex,
+ const Matrix& viewMatrix,
+ const Matrix& projectionMatrix,
+ Integration::DepthBufferAvailable depthBufferAvailable,
+ Integration::StencilBufferAvailable stencilBufferAvailable,
+ Vector<GLuint>& boundTextures,
+ int orientation )
+{
+ DALI_PRINT_RENDER_LIST( renderList );