+inline void RenderAlgorithms::SetupScissorClipping(
+ const RenderItem& item,
+ Graphics::CommandBuffer& commandBuffer,
+ const RenderInstruction& instruction,
+ int orientation)
+{
+ // Get the number of child scissors in the stack (do not include layer or root box).
+ size_t childStackDepth = mScissorStack.size() - 1u;
+ const uint32_t scissorDepth = item.mNode->GetScissorDepth();
+ const bool clippingNode = item.mNode->GetClippingMode() == Dali::ClippingMode::CLIP_TO_BOUNDING_BOX;
+ bool traversedUpTree = false;
+
+ // If we are using scissor clipping and we are at the same depth (or less), we need to undo previous clips.
+ // We do this by traversing up the scissor clip stack and then apply the appropriate clip for the current render item.
+ // To know this, we use clippingDepth. This value is set on *every* node, but only increased as clipping nodes are hit depth-wise.
+ // So we know if we are at depth 4 and the stackDepth is 5, that we have gone up.
+ // If the depth is the same then we are effectively part of a different sub-tree from the parent, we must also remove the current clip.
+ // Note: Stack depth must always be at least 1, as we will have the layer or stage size as the root value.
+ if((childStackDepth > 0u) && (scissorDepth < childStackDepth))
+ {
+ while(scissorDepth < childStackDepth)
+ {
+ mScissorStack.pop_back();
+ --childStackDepth;
+ }
+
+ // 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(RenderItem::CalculateViewportSpaceAABB(item.mModelViewMatrix, Vector3::ZERO, item.mSize, 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.empty()) || mHasLayerScissor;
+
+ // Enable the scissor test based on the above calculation
+ if(scissorEnabled)
+ {
+ commandBuffer.SetScissorTestEnable(scissorEnabled);
+ }
+
+ // If scissor is enabled, we use the calculated screen-space coordinates (now in the stack).
+ if(scissorEnabled)
+ {
+ ClippingBox useScissorBox(mScissorStack.back());
+
+ if(instruction.mFrameBuffer && instruction.GetCamera()->IsYAxisInverted())
+ {
+ useScissorBox.y = (instruction.mFrameBuffer->GetHeight() - useScissorBox.height) - useScissorBox.y;
+ }
+
+ Graphics::Viewport graphicsViewport = ViewportFromClippingBox(Uint16Pair{0, 0}, mViewportRectangle, 0);
+ commandBuffer.SetScissor(Rect2DFromClippingBox(useScissorBox, orientation, graphicsViewport));
+ }
+ }
+ else
+ {
+ // If there is render callback on the Renderer we need to calculate the scissor box and provide it to the
+ // callback so it may be clipped
+ if(item.mRenderer->GetRenderCallback())
+ {
+ // store clipping box inside the render callback input structure
+ auto& input = item.mRenderer->GetRenderCallbackInput();
+ input.clippingBox = ClippingBox(RenderItem::CalculateViewportSpaceAABB(item.mModelViewMatrix, Vector3::ZERO, item.mSize, mViewportRectangle.width, mViewportRectangle.height));
+ }
+ }
+}
+
+inline void RenderAlgorithms::SetupClipping(const RenderItem& item,
+ Graphics::CommandBuffer& commandBuffer,
+ bool& usedStencilBuffer,
+ uint32_t& lastClippingDepth,
+ uint32_t& lastClippingId,
+ Integration::StencilBufferAvailable stencilBufferAvailable,
+ const RenderInstruction& instruction,
+ int orientation)