Fix scissor clipping
[platform/core/uifw/dali-core.git] / dali / internal / render / common / render-algorithms.cpp
index faa4b4e..664eb6b 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -23,7 +23,8 @@
 #include <dali/internal/render/common/render-list.h>
 #include <dali/internal/render/common/render-instruction.h>
 #include <dali/internal/render/gl-resources/context.h>
-#include <dali/internal/render/renderers/scene-graph-renderer.h>
+#include <dali/internal/render/renderers/render-renderer.h>
+#include <dali/internal/update/nodes/scene-graph-layer.h>
 
 using Dali::Internal::SceneGraph::RenderItem;
 using Dali::Internal::SceneGraph::RenderList;
@@ -39,197 +40,438 @@ namespace Internal
 namespace Render
 {
 
+namespace
+{
+
+// Table for fast look-up of Dali::DepthFunction enum to a GL depth function.
+// Note: These MUST be in the same order as Dali::DepthFunction enum.
+const int DaliDepthToGLDepthTable[]  = { GL_NEVER, GL_ALWAYS, GL_LESS, GL_GREATER, GL_EQUAL, GL_NOTEQUAL, GL_LEQUAL, GL_GEQUAL };
+
+// Table for fast look-up of Dali::StencilFunction enum to a GL stencil function.
+// Note: These MUST be in the same order as Dali::StencilFunction enum.
+const int DaliStencilFunctionToGL[]  = { GL_NEVER, GL_LESS, GL_EQUAL, GL_LEQUAL, GL_GREATER, GL_NOTEQUAL, GL_GEQUAL, GL_ALWAYS };
+
+// Table for fast look-up of Dali::StencilOperation enum to a GL stencil operation.
+// Note: These MUST be in the same order as Dali::StencilOperation enum.
+const int DaliStencilOperationToGL[] = { GL_ZERO, GL_KEEP, GL_REPLACE, GL_INCR, GL_DECR, GL_INVERT, GL_INCR_WRAP, GL_DECR_WRAP };
+
 /**
- * Sets up the scissor test if required.
- * @param[in] renderList The render list from which to get the clipping flag
- * @param[in] context The context
+ * @brief Find the intersection of two AABB rectangles.
+ * This is a logical AND operation. IE. The intersection is the area overlapped by both rectangles.
+ * @param[in]     aabbA                  Rectangle A
+ * @param[in]     aabbB                  Rectangle B
+ * @return                               The intersection of rectangle A & B (result is a rectangle)
  */
-inline void SetScissorTest( const RenderList& renderList, Context& context )
+inline ClippingBox IntersectAABB( const ClippingBox& aabbA, const ClippingBox& aabbB )
 {
-  // Scissor testing
-  if( renderList.IsClipping() )
-  {
-    context.SetScissorTest( true );
+  ClippingBox intersectionBox;
 
-    const Dali::ClippingBox& clip = renderList.GetClippingBox();
-    context.Scissor(clip.x, clip.y, clip.width, clip.height);
-  }
-  else
-  {
-    context.SetScissorTest( false );
-  }
+  // First calculate the largest starting positions in X and Y.
+  intersectionBox.x = std::max( aabbA.x, aabbB.x );
+  intersectionBox.y = std::max( aabbA.y, aabbB.y );
+
+  // Now calculate the smallest ending positions, and take the largest starting
+  // positions from the result, to get the width and height respectively.
+  // If the two boxes do not intersect at all, then we need a 0 width and height clipping area.
+  // We use max here to clamp both width and height to >= 0 for this use-case.
+  intersectionBox.width =  std::max( std::min( aabbA.x + aabbA.width,  aabbB.x + aabbB.width  ) - intersectionBox.x, 0 );
+  intersectionBox.height = std::max( std::min( aabbA.y + aabbA.height, aabbB.y + aabbB.height ) - intersectionBox.y, 0 );
+
+  return intersectionBox;
 }
 
 /**
- * Sets the render flags for depth testing and stencil buffer
- *
- * @param[in] renderList The render list from which to get the render flags
- * @param[in] context The context
+ * @brief Set up the stencil and color buffer for automatic clipping (StencilMode::AUTO).
+ * @param[in]     item                     The current RenderItem about to be rendered
+ * @param[in]     context                  The context
+ * @param[in/out] lastClippingDepth        The stencil depth of the last renderer drawn.
+ * @param[in/out] lastClippingId           The clipping ID of the last renderer drawn.
  */
-inline void SetRenderFlags( const RenderList& renderList, Context& context )
+inline void SetupStencilClipping( const RenderItem& item, Context& context, uint32_t& lastClippingDepth, uint32_t& lastClippingId )
 {
-  const unsigned int renderFlags = renderList.GetFlags();
+  const Dali::Internal::SceneGraph::Node* node = item.mNode;
+  const uint32_t clippingId = node->GetClippingId();
+  // If there is no clipping Id, then either we haven't reached a clipping Node yet, or there aren't any.
+  // Either way we can skip clipping setup for this renderer.
+  if( clippingId == 0u )
+  {
+    // Exit immediately if there are no clipping actions to perform (EG. we have not yet hit a clipping node).
+    context.EnableStencilBuffer( false );
+    return;
+  }
 
-  bool enableDepthBuffer = ( ( renderFlags & RenderList::DEPTH_BUFFER_ENABLED ) != 0u );
+  context.EnableStencilBuffer( true );
 
-  GLbitfield clearMask   = ( renderFlags & RenderList::DEPTH_CLEAR ) ? GL_DEPTH_BUFFER_BIT : 0u;
+  const uint32_t clippingDepth = node->GetClippingDepth();
 
-  context.EnableDepthBuffer( enableDepthBuffer );
+  // 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;
 
-  // Stencil enabled, writing, and clearing...
-  const bool enableStencilBuffer( renderFlags & RenderList::STENCIL_BUFFER_ENABLED );
-  const bool enableStencilWrite( renderFlags & RenderList::STENCIL_WRITE );
+  // 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.
+      context.StencilMask( 0xff );
+      context.Clear( GL_STENCIL_BUFFER_BIT, Context::CHECK_CACHED_VALUES );
+    }
+    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;
+
+      context.StencilMask( stencilClearMask );
+      context.Clear( GL_STENCIL_BUFFER_BIT, Context::CHECK_CACHED_VALUES );
+    }
 
-  context.EnableStencilBuffer( enableStencilBuffer );
+    // 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;
+
+    context.StencilFunc( GL_EQUAL, currentDepthMask, testMask ); // Test against existing stencil bit-planes. All must match up to (but not including) this depth.
+    context.StencilMask( currentDepthMask );                     // Write to the new stencil bit-plane (the other previous bit-planes are also written to).
+    context.StencilOp( GL_KEEP, GL_REPLACE, GL_REPLACE );
+  }
+  else
+  {
+    // 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 );
+  }
+}
 
-  if( enableStencilBuffer )
+/**
+ * @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 )
   {
-    context.StencilFunc( (enableStencilWrite ? GL_ALWAYS : GL_EQUAL), 1, 0xFF );
-    context.StencilOp(GL_KEEP, GL_REPLACE, GL_REPLACE);
+    // The depth buffer must be enabled if either reading or writing.
+    context.EnableDepthBuffer( true );
 
-    clearMask |= (renderFlags & RenderList::STENCIL_CLEAR) ? GL_STENCIL_BUFFER_BIT : 0u;
-  }
+    // Set up the depth mask based on our depth write setting.
+    context.DepthMask( enableDepthWrite );
+
+    // Look-up the GL depth function from the Dali::DepthFunction enum, and set it.
+    context.DepthFunc( DaliDepthToGLDepthTable[ item.mRenderer->GetDepthFunction() ] );
 
-  // Write to stencil buffer or color buffer, but not both
-  context.StencilMask( enableStencilWrite ? 0xFF : 0x00 );
-  context.ColorMask( !enableStencilWrite );
+    // 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;
 
-  // Clear depth and/or stencil buffer.
-  if( clearMask )
+      // Note: The buffer will only be cleared if written to since a previous clear.
+      context.Clear( GL_DEPTH_BUFFER_BIT, Context::CHECK_CACHED_VALUES );
+    }
+  }
+  else
   {
-    // only clear if the depth and/or stencil buffer have been written to after a previous clear
-    context.Clear( clearMask, Context::CHECK_CACHED_VALUES );
+    // 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
+
 
 /**
- * Process a render-list.
- * @param[in] renderList The render-list to process.
- * @param[in] context The GL context.
- * @param[in] defaultShader The default shader to use.
- * @param[in] buffer The current render buffer index (previous update buffer)
- * @param[in] frameTime The elapsed time between the last two updates.
- * @param[in] viewMatrix The view matrix from the appropriate camera.
- * @param[in] projectionMatrix The projection matrix from the appropriate camera.
- * @param[in] cullMode True if the renderers should be subjected to clipspace culling
+ * @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 ProcessRenderList(
-  const RenderList& renderList,
-  Context& context,
-  SceneGraph::TextureCache& textureCache,
-  SceneGraph::Shader& defaultShader,
-  BufferIndex bufferIndex,
-  float frameTime,
-  const Matrix& viewMatrix,
-  const Matrix& projectionMatrix,
-  bool cullMode )
+inline void RenderAlgorithms::SetupScissorClipping( const RenderItem& item, Context& context )
 {
-  DALI_PRINT_RENDER_LIST( renderList );
+  // 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;
+    }
 
-  SetScissorTest( renderList, context );
-  SetRenderFlags( renderList, context );
+    // 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( renderList.HasColorRenderItems() )
+  // 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 )
   {
-    bool depthBufferEnabled = ( ( renderList.GetFlags() & RenderList::DEPTH_BUFFER_ENABLED ) != 0u );
-    size_t count = renderList.Count();
-    for ( size_t index = 0; index < count; ++index )
+    // First, check if we are a clipping node.
+    if( clippingNode )
     {
-      const RenderItem& item = renderList.GetItem( index );
-      DALI_PRINT_RENDER_ITEM( item );
+      // This is a clipping node. We generate the AABB for this node and intersect it with the previous intersection further up the tree.
 
-      //Enable depth writes if depth buffer is enabled and item is opaque
-      context.DepthMask( depthBufferEnabled && item.IsOpaque() );
+      // Get the AABB bounding box for the current render item.
+      const ClippingBox scissorBox( item.CalculateViewportSpaceAABB( mViewportRectangle.width, mViewportRectangle.height ) );
 
-      SceneGraph::Renderer* renderer = const_cast< SceneGraph::Renderer* >( item.GetRenderer() );
-      renderer->Render( context, textureCache, bufferIndex, defaultShader, item.GetModelViewMatrix(), viewMatrix, projectionMatrix, frameTime, cullMode );
+      // 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() );
+      context.Scissor( useScissorBox.x, useScissorBox.y, useScissorBox.width, useScissorBox.height );
     }
   }
-  else
+}
+
+inline void RenderAlgorithms::SetupClipping( const RenderItem& item,
+                                             Context& context,
+                                             bool& usedStencilBuffer,
+                                             uint32_t& lastClippingDepth,
+                                             uint32_t& lastClippingId,
+                                             Integration::StencilBufferAvailable stencilBufferAvailable )
+{
+  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 )
   {
-    size_t count = renderList.Count();
-    for ( size_t index = 0; index < count; ++index )
+    case RenderMode::AUTO:
     {
-      const RenderItem& item = renderList.GetItem( index );
-      DALI_PRINT_RENDER_ITEM( item );
+      // 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 );
 
-      SceneGraph::Renderer* renderer = const_cast< SceneGraph::Renderer* >( item.GetRenderer() );
-      renderer->Render( context, textureCache, bufferIndex, defaultShader, item.GetModelViewMatrix(), viewMatrix, projectionMatrix, frameTime, cullMode );
+      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;
+    }
   }
 }
 
-/**
- * Render items from the currentIndex until the depth index changes.
- * Leaves currentIndex pointing at the
- *
- * @param[in] renderList The render-list to process.
- * @param[in] context The GL context.
- * @param[in] defaultShader The default shader to use.
- * @param[in] buffer The current render buffer index (previous update buffer)
- * @param[in] frameTime The elapsed time between the last two updates.
- * @param[in] viewMatrix The view matrix from the appropriate camera.
- * @param[in] projectionMatrix The projection matrix from the appropriate camera.
- * @param[in] cullMode True if the renderers should be subjected to clipspace culling
- * @param[in] depthIndex The current depth index
- * @param[inout] currentIndex On entry, the index in the render list of the first item at the given depth index. On exit, the index of the first item at the next depth index.
- */
-inline void RenderItemsAtDepthIndex(
-  const RenderList&         renderList,
-  Context&                  context,
-  SceneGraph::TextureCache& textureCache,
-  SceneGraph::Shader&       defaultShader,
-  BufferIndex               bufferIndex,
-  float                     frameTime,
-  const Matrix&             viewMatrix,
-  const Matrix&             projectionMatrix,
-  bool                      cullMode,
-  int                       depthIndex,
-  size_t&                   currentIndex ) // Out parameter
+inline void RenderAlgorithms::ProcessRenderList( const RenderList& renderList,
+                                                 Context& context,
+                                                 BufferIndex bufferIndex,
+                                                 const Matrix& viewMatrix,
+                                                 const Matrix& projectionMatrix,
+                                                 Integration::DepthBufferAvailable depthBufferAvailable,
+                                                 Integration::StencilBufferAvailable stencilBufferAvailable )
 {
-  const size_t count = renderList.Count();
+  DALI_PRINT_RENDER_LIST( renderList );
 
-  // Don't initialise currentIndex. Ever.
-  for( ; currentIndex < count ; currentIndex++ )
+  // Note: The depth buffer is enabled or disabled on a per-renderer basis.
+  // Here we pre-calculate the value to use if these modes are set to AUTO.
+  const bool autoDepthTestMode(  ( depthBufferAvailable == Integration::DepthBufferAvailable::TRUE ) &&
+                                !( renderList.GetSourceLayer()->IsDepthTestDisabled() ) &&
+                                 renderList.HasColorRenderItems() );
+  const std::size_t count = renderList.Count();
+  uint32_t lastClippingDepth( 0u );
+  uint32_t lastClippingId( 0u );
+  bool usedStencilBuffer( false );
+  bool firstDepthBufferUse( true );
+  mViewportRectangle = context.GetViewport();
+  mHasLayerScissor = false;
+
+  // Setup Scissor testing (for both viewport and per-node scissor)
+  mScissorStack.clear();
+  if( renderList.IsClipping() )
   {
-    const RenderItem& renderItem = renderList.GetItem( currentIndex );
-    DALI_PRINT_RENDER_ITEM( renderItem );
+    context.SetScissorTest( true );
+    const ClippingBox& layerScissorBox = renderList.GetClippingBox();
+    context.Scissor( layerScissorBox.x, layerScissorBox.y, layerScissorBox.width, layerScissorBox.height );
+    mScissorStack.push_back( layerScissorBox );
+    mHasLayerScissor = true;
+  }
+  else
+  {
+    // We are not performing a layer clip. Add the viewport as the root scissor rectangle.
+    context.SetScissorTest( false );
+    mScissorStack.push_back( mViewportRectangle );
+  }
 
-    if( renderItem.GetDepthIndex() == depthIndex )
-    {
-      SceneGraph::Renderer* renderer = const_cast< SceneGraph::Renderer* >( renderItem.GetRenderer() );
-      const Matrix& modelViewMatrix = renderItem.GetModelViewMatrix();
-      renderer->Render( context, textureCache, bufferIndex, defaultShader, modelViewMatrix, viewMatrix, projectionMatrix, frameTime, cullMode );
+  // Loop through all RenderList in the RenderList, set up any prerequisites to render them, then perform the render.
+  for( size_t index( 0u ); index < count; ++index )
+  {
+    const RenderItem& item = renderList.GetItem( index );
+    DALI_PRINT_RENDER_ITEM( item );
 
-    }
-    else
+    // Set up clipping based on both the Renderer and Actor APIs.
+    // The Renderer API will be used if specified. If AUTO, the Actors automatic clipping feature will be used.
+    SetupClipping( item, context, usedStencilBuffer, lastClippingDepth, lastClippingId, stencilBufferAvailable );
+
+    if( DALI_LIKELY( item.mRenderer ) )
     {
-      break; // Stop iterating when we reach a new depth index
+      // Set up the depth buffer based on per-renderer flags if depth buffer is available
+      // If the per renderer flags are set to "ON" or "OFF", they will always override any Layer depth mode or
+      // draw-mode state, such as Overlays.
+      // If the flags are set to "AUTO", the behavior then depends on the type of renderer. Overlay Renderers will always
+      // disable depth testing and writing. Color Renderers will enable them if the Layer does.
+      if( depthBufferAvailable == Integration::DepthBufferAvailable::TRUE )
+      {
+        SetupDepthBuffer( item, context, autoDepthTestMode, firstDepthBufferUse );
+      }
+
+      // Render the item.
+      item.mRenderer->Render( context, bufferIndex, *item.mNode, item.mModelMatrix, item.mModelViewMatrix,
+                              viewMatrix, projectionMatrix, item.mSize, !item.mIsOpaque );
     }
   }
 }
 
+RenderAlgorithms::RenderAlgorithms()
+  : mViewportRectangle(),
+    mHasLayerScissor( false )
+{
+}
 
-
-void ProcessRenderInstruction( const RenderInstruction& instruction,
-                               Context& context,
-                               SceneGraph::TextureCache& textureCache,
-                               SceneGraph::Shader& defaultShader,
-                               BufferIndex bufferIndex,
-                               float frameTime )
+void RenderAlgorithms::ProcessRenderInstruction( const RenderInstruction& instruction,
+                                                 Context& context,
+                                                 BufferIndex bufferIndex,
+                                                 Integration::DepthBufferAvailable depthBufferAvailable,
+                                                 Integration::StencilBufferAvailable stencilBufferAvailable )
 {
   DALI_PRINT_RENDER_INSTRUCTION( instruction, bufferIndex );
 
   const Matrix* viewMatrix       = instruction.GetViewMatrix( bufferIndex );
   const Matrix* projectionMatrix = instruction.GetProjectionMatrix( bufferIndex );
 
-  DALI_ASSERT_DEBUG( NULL != viewMatrix );
-  DALI_ASSERT_DEBUG( NULL != projectionMatrix );
+  DALI_ASSERT_DEBUG( viewMatrix );
+  DALI_ASSERT_DEBUG( projectionMatrix );
 
-  if( NULL != viewMatrix &&
-      NULL != projectionMatrix )
+  if( viewMatrix && projectionMatrix )
   {
     const RenderListContainer::SizeType count = instruction.RenderListCount();
 
@@ -239,15 +481,21 @@ void ProcessRenderInstruction( const RenderInstruction& instruction,
     {
       const RenderList* renderList = instruction.GetRenderList( index );
 
-      if(  renderList &&
-          !renderList->IsEmpty() )
+      if( renderList && !renderList->IsEmpty() )
       {
-          ProcessRenderList( *renderList, context, textureCache, defaultShader, bufferIndex, frameTime, *viewMatrix, *projectionMatrix, instruction.mCullMode );
+        ProcessRenderList( *renderList,
+                            context,
+                            bufferIndex,
+                           *viewMatrix,
+                           *projectionMatrix,
+                            depthBufferAvailable,
+                            stencilBufferAvailable );
       }
     }
   }
 }
 
+
 } // namespace Render
 
 } // namespace Internal