+ // Exit immediately if there are no clipping actions to perform (EG. we have not yet hit a clipping node).
+ commandBuffer.SetStencilTestEnable(false);
+ return;
+ }
+ commandBuffer.SetStencilTestEnable(true);
+
+ const uint32_t clippingDepth = node->GetClippingDepth();
+
+ // Pre-calculate a mask which has all bits set up to and including the current clipping depth.
+ // EG. If depth is 3, the mask would be "111" in binary.
+ const uint32_t currentDepthMask = (1u << clippingDepth) - 1u;
+
+ // Are we are writing to the stencil buffer?
+ if(item.mNode->GetClippingMode() == Dali::ClippingMode::CLIP_CHILDREN)
+ {
+ // We are writing to the stencil buffer.
+ // If clipping Id is 1, this is the first clipping renderer within this render-list.
+ if(clippingId == 1u)
+ {
+ // We are enabling the stencil-buffer for the first time within this render list.
+ // Clear the buffer at this point.
+
+ commandBuffer.SetStencilWriteMask(0xFF);
+ commandBuffer.ClearStencilBuffer();
+ }
+ else if((clippingDepth < lastClippingDepth) ||
+ ((clippingDepth == lastClippingDepth) && (clippingId > lastClippingId)))
+ {
+ // The above if() statement tests if we need to clear some (not all) stencil bit-planes.
+ // We need to do this if either of the following are true:
+ // 1) We traverse up the scene-graph to a previous stencil depth
+ // 2) We are at the same stencil depth but the clipping Id has increased.
+ //
+ // This calculation takes the new depth to move to, and creates an inverse-mask of that number of consecutive bits.
+ // This has the effect of clearing everything except the bit-planes up to (and including) our current depth.
+ const uint32_t stencilClearMask = (currentDepthMask >> 1u) ^ 0xff;
+
+ commandBuffer.SetStencilWriteMask(stencilClearMask);
+ commandBuffer.ClearStencilBuffer();
+ }
+
+ // We keep track of the last clipping Id and depth so we can determine when we are
+ // moving back up the scene graph and require some of the stencil bit-planes to be deleted.
+ lastClippingDepth = clippingDepth;
+ lastClippingId = clippingId;
+
+ // We only ever write to bit-planes up to the current depth as we may need
+ // to erase individual bit-planes and revert to a previous clipping area.
+ // Our reference value for testing (in StencilFunc) is written to to the buffer, but we actually
+ // want to test a different value. IE. All the bit-planes up to but not including the current depth.
+ // So we use the Mask parameter of StencilFunc to mask off the top bit-plane when testing.
+ // Here we create our test mask to innore the top bit of the reference test value.
+ // As the mask is made up of contiguous "1" values, we can do this quickly with a bit-shift.
+ const uint32_t testMask = currentDepthMask >> 1u;
+
+ // Test against existing stencil bit-planes. All must match up to (but not including) this depth.
+ commandBuffer.SetStencilFunc(Graphics::CompareOp::EQUAL, currentDepthMask, testMask);
+ // Write to the new stencil bit-plane (the other previous bit-planes are also written to).
+ commandBuffer.SetStencilWriteMask(currentDepthMask);
+ commandBuffer.SetStencilOp(Graphics::StencilOp::KEEP, Graphics::StencilOp::REPLACE, Graphics::StencilOp::REPLACE);