+ // We are reading from the stencil buffer. Set up the stencil accordingly
+ // This calculation sets all the bits up to the current depth bit.
+ // This has the effect of testing that the pixel being written to exists in every bit-plane up to the current depth.
+ context.StencilFunc( GL_EQUAL, currentDepthMask, 0xff );
+ context.StencilOp( GL_KEEP, GL_KEEP, GL_KEEP );
+ }
+}
+
+/**
+ * @brief Sets up the depth buffer for reading and writing based on the current render item.
+ * The items read and write mode are used if specified.
+ * - If AUTO is selected for reading, the decision will be based on the Layer Behavior.
+ * - If AUTO is selected for writing, the decision will be based on the items opacity.
+ * @param[in] item The RenderItem to set up the depth buffer for.
+ * @param[in] context The context used to execute GL commands.
+ * @param[in] depthTestEnabled True if depth testing has been enabled.
+ * @param[in/out] firstDepthBufferUse Initialize to true on the first call, this method will set it to false afterwards.
+ */
+inline void SetupDepthBuffer( const RenderItem& item, Context& context, bool depthTestEnabled, bool& firstDepthBufferUse )
+{
+ // Set up whether or not to write to the depth buffer.
+ const DepthWriteMode::Type depthWriteMode = item.mRenderer->GetDepthWriteMode();
+ // Most common mode (AUTO) is tested first.
+ const bool enableDepthWrite = ( ( depthWriteMode == DepthWriteMode::AUTO ) && depthTestEnabled && item.mIsOpaque ) ||
+ ( depthWriteMode == DepthWriteMode::ON );
+
+ // Set up whether or not to read from (test) the depth buffer.
+ const DepthTestMode::Type depthTestMode = item.mRenderer->GetDepthTestMode();
+ // Most common mode (AUTO) is tested first.
+ const bool enableDepthTest = ( ( depthTestMode == DepthTestMode::AUTO ) && depthTestEnabled ) ||
+ ( depthTestMode == DepthTestMode::ON );
+
+ // Is the depth buffer in use?
+ if( enableDepthWrite || enableDepthTest )
+ {
+ // The depth buffer must be enabled if either reading or writing.
+ context.EnableDepthBuffer( true );
+
+ // Look-up the GL depth function from the Dali::DepthFunction enum, and set it.
+ context.DepthFunc( DaliDepthToGLDepthTable[ item.mRenderer->GetDepthFunction() ] );
+
+ // If this is the first use of the depth buffer this RenderTask, perform a clear.
+ // Note: We could do this at the beginning of the RenderTask and rely on the
+ // context cache to ignore the clear if not required, but, we would have to enable
+ // the depth buffer to do so, which could be a redundant enable.
+ if( DALI_UNLIKELY( firstDepthBufferUse ) )
+ {
+ // This is the first time the depth buffer is being written to or read.
+ firstDepthBufferUse = false;
+
+ // Note: The buffer will only be cleared if written to since a previous clear.
+ context.DepthMask( true );
+ context.Clear( GL_DEPTH_BUFFER_BIT, Context::CHECK_CACHED_VALUES );
+ }
+
+ // Set up the depth mask based on our depth write setting.
+ context.DepthMask( enableDepthWrite );
+ }
+ else
+ {
+ // The depth buffer is not being used by this renderer, so we must disable it to stop it being tested.
+ context.EnableDepthBuffer( false );
+ }
+}
+
+} // Unnamed namespace
+
+
+/**
+ * @brief This method is responsible for making decisions on when to apply and unapply scissor clipping, and what rectangular dimensions should be used.
+ * A stack of scissor clips at each depth of clipping is maintained, so it can be applied and unapplied.
+ * As the clips are hierarchical, this RenderItems AABB is clipped against the current "active" scissor bounds via an intersection operation.
+ * @param[in] item The current RenderItem about to be rendered
+ * @param[in] context The context
+ */
+inline void RenderAlgorithms::SetupScissorClipping( const RenderItem& item, Context& context )
+{
+ // 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;