Ejemplo n.º 1
0
void
brw_emit_depthbuffer(struct brw_context *brw)
{
   struct gl_context *ctx = &brw->ctx;
   struct gl_framebuffer *fb = ctx->DrawBuffer;
   /* _NEW_BUFFERS */
   struct intel_renderbuffer *depth_irb = intel_get_renderbuffer(fb, BUFFER_DEPTH);
   struct intel_renderbuffer *stencil_irb = intel_get_renderbuffer(fb, BUFFER_STENCIL);
   struct intel_mipmap_tree *depth_mt = brw->depthstencil.depth_mt;
   struct intel_mipmap_tree *stencil_mt = brw->depthstencil.stencil_mt;
   uint32_t tile_x = brw->depthstencil.tile_x;
   uint32_t tile_y = brw->depthstencil.tile_y;
   bool hiz = depth_irb && intel_renderbuffer_has_hiz(depth_irb);
   bool separate_stencil = false;
   uint32_t depth_surface_type = BRW_SURFACE_NULL;
   uint32_t depthbuffer_format = BRW_DEPTHFORMAT_D32_FLOAT;
   uint32_t depth_offset = 0;
   uint32_t width = 1, height = 1;

   if (stencil_mt) {
      separate_stencil = stencil_mt->format == MESA_FORMAT_S_UINT8;

      /* Gen7 supports only separate stencil */
      assert(separate_stencil || brw->gen < 7);
   }

   /* If there's a packed depth/stencil bound to stencil only, we need to
    * emit the packed depth/stencil buffer packet.
    */
   if (!depth_irb && stencil_irb && !separate_stencil) {
      depth_irb = stencil_irb;
      depth_mt = stencil_mt;
   }

   if (depth_irb && depth_mt) {
      /* When 3DSTATE_DEPTH_BUFFER.Separate_Stencil_Enable is set, then
       * 3DSTATE_DEPTH_BUFFER.Surface_Format is not permitted to be a packed
       * depthstencil format.
       *
       * Gens prior to 7 require that HiZ_Enable and Separate_Stencil_Enable be
       * set to the same value. Gens after 7 implicitly always set
       * Separate_Stencil_Enable; software cannot disable it.
       */
      if ((brw->gen < 7 && hiz) || brw->gen >= 7) {
         assert(!_mesa_is_format_packed_depth_stencil(depth_mt->format));
      }

      /* Prior to Gen7, if using separate stencil, hiz must be enabled. */
      assert(brw->gen >= 7 || !separate_stencil || hiz);

      assert(brw->gen < 6 || depth_mt->region->tiling == I915_TILING_Y);
      assert(!hiz || depth_mt->region->tiling == I915_TILING_Y);

      depthbuffer_format = brw_depthbuffer_format(brw);
      depth_surface_type = BRW_SURFACE_2D;
      depth_offset = brw->depthstencil.depth_offset;
      width = depth_irb->Base.Base.Width;
      height = depth_irb->Base.Base.Height;
   } else if (separate_stencil) {
      /*
       * There exists a separate stencil buffer but no depth buffer.
       *
       * The stencil buffer inherits most of its fields from
       * 3DSTATE_DEPTH_BUFFER: namely the tile walk, surface type, width, and
       * height.
       *
       * The tiled bit must be set. From the Sandybridge PRM, Volume 2, Part 1,
       * Section 7.5.5.1.1 3DSTATE_DEPTH_BUFFER, Bit 1.27 Tiled Surface:
       *     [DevGT+]: This field must be set to TRUE.
       */
      assert(brw->has_separate_stencil);

      depth_surface_type = BRW_SURFACE_2D;
      width = stencil_irb->Base.Base.Width;
      height = stencil_irb->Base.Base.Height;
   }

   brw->vtbl.emit_depth_stencil_hiz(brw, depth_mt, depth_offset,
                                    depthbuffer_format, depth_surface_type,
                                    stencil_mt, hiz, separate_stencil,
                                    width, height, tile_x, tile_y);
}
Ejemplo n.º 2
0
void
brw_workaround_depthstencil_alignment(struct brw_context *brw,
                                      GLbitfield clear_mask)
{
   struct gl_context *ctx = &brw->ctx;
   struct gl_framebuffer *fb = ctx->DrawBuffer;
   bool rebase_depth = false;
   bool rebase_stencil = false;
   struct intel_renderbuffer *depth_irb = intel_get_renderbuffer(fb, BUFFER_DEPTH);
   struct intel_renderbuffer *stencil_irb = intel_get_renderbuffer(fb, BUFFER_STENCIL);
   struct intel_mipmap_tree *depth_mt = NULL;
   struct intel_mipmap_tree *stencil_mt = get_stencil_miptree(stencil_irb);
   uint32_t tile_x = 0, tile_y = 0, stencil_tile_x = 0, stencil_tile_y = 0;
   uint32_t stencil_draw_x = 0, stencil_draw_y = 0;
   bool invalidate_depth = clear_mask & BUFFER_BIT_DEPTH;
   bool invalidate_stencil = clear_mask & BUFFER_BIT_STENCIL;

   if (depth_irb)
      depth_mt = depth_irb->mt;

   /* Initialize brw->depthstencil to 'nop' workaround state.
    */
   brw->depthstencil.tile_x = 0;
   brw->depthstencil.tile_y = 0;
   brw->depthstencil.depth_offset = 0;
   brw->depthstencil.stencil_offset = 0;
   brw->depthstencil.hiz_offset = 0;
   brw->depthstencil.depth_mt = NULL;
   brw->depthstencil.stencil_mt = NULL;
   if (depth_irb)
      brw->depthstencil.depth_mt = depth_mt;
   if (stencil_irb)
      brw->depthstencil.stencil_mt = get_stencil_miptree(stencil_irb);

   /* Gen7+ doesn't require the workarounds, since we always program the
    * surface state at the start of the whole surface.
    */
   if (brw->gen >= 7)
      return;

   /* Check if depth buffer is in depth/stencil format.  If so, then it's only
    * safe to invalidate it if we're also clearing stencil, and both depth_irb
    * and stencil_irb point to the same miptree.
    *
    * Note: it's not sufficient to check for the case where
    * _mesa_get_format_base_format(depth_mt->format) == GL_DEPTH_STENCIL,
    * because this fails to catch depth/stencil buffers on hardware that uses
    * separate stencil.  To catch that case, we check whether
    * depth_mt->stencil_mt is non-NULL.
    */
   if (depth_irb && invalidate_depth &&
       (_mesa_get_format_base_format(depth_mt->format) == GL_DEPTH_STENCIL ||
        depth_mt->stencil_mt)) {
      invalidate_depth = invalidate_stencil && depth_irb && stencil_irb
         && depth_irb->mt == stencil_irb->mt;
   }

   uint32_t tile_mask_x, tile_mask_y;
   brw_get_depthstencil_tile_masks(depth_mt,
                                   depth_mt ? depth_irb->mt_level : 0,
                                   depth_mt ? depth_irb->mt_layer : 0,
                                   stencil_mt,
                                   &tile_mask_x, &tile_mask_y);

   if (depth_irb) {
      tile_x = depth_irb->draw_x & tile_mask_x;
      tile_y = depth_irb->draw_y & tile_mask_y;

      /* According to the Sandy Bridge PRM, volume 2 part 1, pp326-327
       * (3DSTATE_DEPTH_BUFFER dw5), in the documentation for "Depth
       * Coordinate Offset X/Y":
       *
       *   "The 3 LSBs of both offsets must be zero to ensure correct
       *   alignment"
       */
      if (tile_x & 7 || tile_y & 7)
         rebase_depth = true;

      /* We didn't even have intra-tile offsets before g45. */
      if (!brw->has_surface_tile_offset) {
         if (tile_x || tile_y)
            rebase_depth = true;
      }

      if (rebase_depth) {
         perf_debug("HW workaround: blitting depth level %d to a temporary "
                    "to fix alignment (depth tile offset %d,%d)\n",
                    depth_irb->mt_level, tile_x, tile_y);
         intel_renderbuffer_move_to_temp(brw, depth_irb, invalidate_depth);
         /* In the case of stencil_irb being the same packed depth/stencil
          * texture but not the same rb, make it point at our rebased mt, too.
          */
         if (stencil_irb &&
             stencil_irb != depth_irb &&
             stencil_irb->mt == depth_mt) {
            intel_miptree_reference(&stencil_irb->mt, depth_irb->mt);
            intel_renderbuffer_set_draw_offset(stencil_irb);
         }

         stencil_mt = get_stencil_miptree(stencil_irb);

         tile_x = depth_irb->draw_x & tile_mask_x;
         tile_y = depth_irb->draw_y & tile_mask_y;
      }

      if (stencil_irb) {
         stencil_mt = get_stencil_miptree(stencil_irb);
         intel_miptree_get_image_offset(stencil_mt,
                                        stencil_irb->mt_level,
                                        stencil_irb->mt_layer,
                                        &stencil_draw_x, &stencil_draw_y);
         int stencil_tile_x = stencil_draw_x & tile_mask_x;
         int stencil_tile_y = stencil_draw_y & tile_mask_y;

         /* If stencil doesn't match depth, then we'll need to rebase stencil
          * as well.  (if we hadn't decided to rebase stencil before, the
          * post-stencil depth test will also rebase depth to try to match it
          * up).
          */
         if (tile_x != stencil_tile_x ||
             tile_y != stencil_tile_y) {
            rebase_stencil = true;
         }
      }
   }

   /* If we have (just) stencil, check it for ignored low bits as well */
   if (stencil_irb) {
      intel_miptree_get_image_offset(stencil_mt,
                                     stencil_irb->mt_level,
                                     stencil_irb->mt_layer,
                                     &stencil_draw_x, &stencil_draw_y);
      stencil_tile_x = stencil_draw_x & tile_mask_x;
      stencil_tile_y = stencil_draw_y & tile_mask_y;

      if (stencil_tile_x & 7 || stencil_tile_y & 7)
         rebase_stencil = true;

      if (!brw->has_surface_tile_offset) {
         if (stencil_tile_x || stencil_tile_y)
            rebase_stencil = true;
      }
   }

   if (rebase_stencil) {
      perf_debug("HW workaround: blitting stencil level %d to a temporary "
                 "to fix alignment (stencil tile offset %d,%d)\n",
                 stencil_irb->mt_level, stencil_tile_x, stencil_tile_y);

      intel_renderbuffer_move_to_temp(brw, stencil_irb, invalidate_stencil);
      stencil_mt = get_stencil_miptree(stencil_irb);

      intel_miptree_get_image_offset(stencil_mt,
                                     stencil_irb->mt_level,
                                     stencil_irb->mt_layer,
                                     &stencil_draw_x, &stencil_draw_y);
      stencil_tile_x = stencil_draw_x & tile_mask_x;
      stencil_tile_y = stencil_draw_y & tile_mask_y;

      if (depth_irb && depth_irb->mt == stencil_irb->mt) {
         intel_miptree_reference(&depth_irb->mt, stencil_irb->mt);
         intel_renderbuffer_set_draw_offset(depth_irb);
      } else if (depth_irb && !rebase_depth) {
         if (tile_x != stencil_tile_x ||
             tile_y != stencil_tile_y) {
            perf_debug("HW workaround: blitting depth level %d to a temporary "
                       "to match stencil level %d alignment (depth tile offset "
                       "%d,%d, stencil offset %d,%d)\n",
                       depth_irb->mt_level,
                       stencil_irb->mt_level,
                       tile_x, tile_y,
                       stencil_tile_x, stencil_tile_y);

            intel_renderbuffer_move_to_temp(brw, depth_irb, invalidate_depth);

            tile_x = depth_irb->draw_x & tile_mask_x;
            tile_y = depth_irb->draw_y & tile_mask_y;

            if (stencil_irb && stencil_irb->mt == depth_mt) {
               intel_miptree_reference(&stencil_irb->mt, depth_irb->mt);
               intel_renderbuffer_set_draw_offset(stencil_irb);
            }

            WARN_ONCE(stencil_tile_x != tile_x ||
                      stencil_tile_y != tile_y,
                      "Rebased stencil tile offset (%d,%d) doesn't match depth "
                      "tile offset (%d,%d).\n",
                      stencil_tile_x, stencil_tile_y,
                      tile_x, tile_y);
         }
      }
   }

   if (!depth_irb) {
      tile_x = stencil_tile_x;
      tile_y = stencil_tile_y;
   }

   /* While we just tried to get everything aligned, we may have failed to do
    * so in the case of rendering to array or 3D textures, where nonzero faces
    * will still have an offset post-rebase.  At least give an informative
    * warning.
    */
   WARN_ONCE((tile_x & 7) || (tile_y & 7),
             "Depth/stencil buffer needs alignment to 8-pixel boundaries.\n"
             "Truncating offset, bad rendering may occur.\n");
   tile_x &= ~7;
   tile_y &= ~7;

   /* Now, after rebasing, save off the new dephtstencil state so the hardware
    * packets can just dereference that without re-calculating tile offsets.
    */
   brw->depthstencil.tile_x = tile_x;
   brw->depthstencil.tile_y = tile_y;
   if (depth_irb) {
      depth_mt = depth_irb->mt;
      brw->depthstencil.depth_mt = depth_mt;
      brw->depthstencil.depth_offset =
         intel_region_get_aligned_offset(depth_mt->region,
                                         depth_irb->draw_x & ~tile_mask_x,
                                         depth_irb->draw_y & ~tile_mask_y,
                                         false);
      if (intel_renderbuffer_has_hiz(depth_irb)) {
         brw->depthstencil.hiz_offset =
            intel_region_get_aligned_offset(depth_mt->region,
                                            depth_irb->draw_x & ~tile_mask_x,
                                            (depth_irb->draw_y & ~tile_mask_y) /
                                            2,
                                            false);
      }
   }
   if (stencil_irb) {
      stencil_mt = get_stencil_miptree(stencil_irb);

      brw->depthstencil.stencil_mt = stencil_mt;
      if (stencil_mt->format == MESA_FORMAT_S_UINT8) {
         /* Note: we can't compute the stencil offset using
          * intel_region_get_aligned_offset(), because stencil_region claims
          * that the region is untiled even though it's W tiled.
          */
         brw->depthstencil.stencil_offset =
            (stencil_draw_y & ~tile_mask_y) * stencil_mt->region->pitch +
            (stencil_draw_x & ~tile_mask_x) * 64;
      }
   }
}
Ejemplo n.º 3
0
/**
 * Implements fast depth clears on gen6+.
 *
 * Fast clears basically work by setting a flag in each of the subspans
 * represented in the HiZ buffer that says "When you need the depth values for
 * this subspan, it's the hardware's current clear value."  Then later rendering
 * can just use the static clear value instead of referencing memory.
 *
 * The tricky part of the implementation is that you have to have the clear
 * value that was used on the depth buffer in place for all further rendering,
 * at least until a resolve to the real depth buffer happens.
 */
static bool
brw_fast_clear_depth(struct gl_context *ctx)
{
   struct brw_context *brw = brw_context(ctx);
   struct gl_framebuffer *fb = ctx->DrawBuffer;
   struct intel_renderbuffer *depth_irb =
      intel_get_renderbuffer(fb, BUFFER_DEPTH);
   struct intel_mipmap_tree *mt = depth_irb->mt;
   struct gl_renderbuffer_attachment *depth_att = &fb->Attachment[BUFFER_DEPTH];

   if (brw->gen < 6)
      return false;

   if (!intel_renderbuffer_has_hiz(depth_irb))
      return false;

   /* We only handle full buffer clears -- otherwise you'd have to track whether
    * a previous clear had happened at a different clear value and resolve it
    * first.
    */
   if ((ctx->Scissor.EnableFlags & 1) && !noop_scissor(ctx, fb)) {
      perf_debug("Failed to fast clear %dx%d depth because of scissors.  "
                 "Possible 5%% performance win if avoided.\n",
                 mt->logical_width0, mt->logical_height0);
      return false;
   }

   uint32_t depth_clear_value;
   switch (mt->format) {
   case MESA_FORMAT_Z32_FLOAT_S8X24_UINT:
   case MESA_FORMAT_Z24_UNORM_S8_UINT:
      /* From the Sandy Bridge PRM, volume 2 part 1, page 314:
       *
       *     "[DevSNB+]: Several cases exist where Depth Buffer Clear cannot be
       *      enabled (the legacy method of clearing must be performed):
       *
       *      - If the depth buffer format is D32_FLOAT_S8X24_UINT or
       *        D24_UNORM_S8_UINT.
       */
      return false;

   case MESA_FORMAT_Z_FLOAT32:
      depth_clear_value = float_as_int(ctx->Depth.Clear);
      break;

   case MESA_FORMAT_Z_UNORM16:
      /* From the Sandy Bridge PRM, volume 2 part 1, page 314:
       *
       *     "[DevSNB+]: Several cases exist where Depth Buffer Clear cannot be
       *      enabled (the legacy method of clearing must be performed):
       *
       *      - DevSNB{W/A}]: When depth buffer format is D16_UNORM and the
       *        width of the map (LOD0) is not multiple of 16, fast clear
       *        optimization must be disabled.
       */
      if (brw->gen == 6 &&
          (minify(mt->physical_width0,
                  depth_irb->mt_level - mt->first_level) % 16) != 0)
	 return false;
      /* FALLTHROUGH */

   default:
      if (brw->gen >= 8)
         depth_clear_value = float_as_int(ctx->Depth.Clear);
      else
         depth_clear_value = fb->_DepthMax * ctx->Depth.Clear;
      break;
   }

   /* If we're clearing to a new clear value, then we need to resolve any clear
    * flags out of the HiZ buffer into the real depth buffer.
    */
   if (mt->depth_clear_value != depth_clear_value) {
      intel_miptree_all_slices_resolve_depth(brw, mt);
      mt->depth_clear_value = depth_clear_value;
   }

   /* From the Sandy Bridge PRM, volume 2 part 1, page 313:
    *
    *     "If other rendering operations have preceded this clear, a
    *      PIPE_CONTROL with write cache flush enabled and Z-inhibit disabled
    *      must be issued before the rectangle primitive used for the depth
    *      buffer clear operation.
    */
   brw_emit_mi_flush(brw);

   if (fb->MaxNumLayers > 0) {
      for (unsigned layer = 0; layer < depth_irb->layer_count; layer++) {
         intel_hiz_exec(brw, mt, depth_irb->mt_level,
                        depth_irb->mt_layer + layer,
                        GEN6_HIZ_OP_DEPTH_CLEAR);
      }
   } else {
      intel_hiz_exec(brw, mt, depth_irb->mt_level, depth_irb->mt_layer,
                     GEN6_HIZ_OP_DEPTH_CLEAR);
   }

   if (brw->gen == 6) {
      /* From the Sandy Bridge PRM, volume 2 part 1, page 314:
       *
       *     "DevSNB, DevSNB-B{W/A}]: Depth buffer clear pass must be followed
       *      by a PIPE_CONTROL command with DEPTH_STALL bit set and Then
       *      followed by Depth FLUSH'
      */
      brw_emit_mi_flush(brw);
   }

   /* Now, the HiZ buffer contains data that needs to be resolved to the depth
    * buffer.
    */
   intel_renderbuffer_att_set_needs_depth_resolve(depth_att);

   return true;
}
Ejemplo n.º 4
0
/**
 * Do additional "completeness" testing of a framebuffer object.
 */
static void
intel_validate_framebuffer(struct gl_context *ctx, struct gl_framebuffer *fb)
{
   struct brw_context *brw = brw_context(ctx);
   struct intel_renderbuffer *depthRb =
      intel_get_renderbuffer(fb, BUFFER_DEPTH);
   struct intel_renderbuffer *stencilRb =
      intel_get_renderbuffer(fb, BUFFER_STENCIL);
   struct intel_mipmap_tree *depth_mt = NULL, *stencil_mt = NULL;
   int i;

   DBG("%s() on fb %p (%s)\n", __FUNCTION__,
       fb, (fb == ctx->DrawBuffer ? "drawbuffer" :
	    (fb == ctx->ReadBuffer ? "readbuffer" : "other buffer")));

   if (depthRb)
      depth_mt = depthRb->mt;
   if (stencilRb) {
      stencil_mt = stencilRb->mt;
      if (stencil_mt->stencil_mt)
	 stencil_mt = stencil_mt->stencil_mt;
   }

   if (depth_mt && stencil_mt) {
      if (depth_mt == stencil_mt) {
	 /* For true packed depth/stencil (not faked on prefers-separate-stencil
	  * hardware) we need to be sure they're the same level/layer, since
	  * we'll be emitting a single packet describing the packed setup.
	  */
	 if (depthRb->mt_level != stencilRb->mt_level ||
	     depthRb->mt_layer != stencilRb->mt_layer) {
	    fbo_incomplete(fb,
                           "FBO incomplete: depth image level/layer %d/%d != "
                           "stencil image %d/%d\n",
                           depthRb->mt_level,
                           depthRb->mt_layer,
                           stencilRb->mt_level,
                           stencilRb->mt_layer);
	 }
      } else {
	 if (!brw->has_separate_stencil) {
	    fbo_incomplete(fb, "FBO incomplete: separate stencil "
                           "unsupported\n");
	 }
	 if (stencil_mt->format != MESA_FORMAT_S8) {
	    fbo_incomplete(fb, "FBO incomplete: separate stencil is %s "
                           "instead of S8\n",
                           _mesa_get_format_name(stencil_mt->format));
	 }
	 if (brw->gen < 7 && !intel_renderbuffer_has_hiz(depthRb)) {
	    /* Before Gen7, separate depth and stencil buffers can be used
	     * only if HiZ is enabled. From the Sandybridge PRM, Volume 2,
	     * Part 1, Bit 3DSTATE_DEPTH_BUFFER.SeparateStencilBufferEnable:
	     *     [DevSNB]: This field must be set to the same value (enabled
	     *     or disabled) as Hierarchical Depth Buffer Enable.
	     */
	    fbo_incomplete(fb, "FBO incomplete: separate stencil "
                           "without HiZ\n");
	 }
      }
   }

   for (i = 0; i < Elements(fb->Attachment); i++) {
      struct gl_renderbuffer *rb;
      struct intel_renderbuffer *irb;

      if (fb->Attachment[i].Type == GL_NONE)
	 continue;

      /* A supported attachment will have a Renderbuffer set either
       * from being a Renderbuffer or being a texture that got the
       * intel_wrap_texture() treatment.
       */
      rb = fb->Attachment[i].Renderbuffer;
      if (rb == NULL) {
	 fbo_incomplete(fb, "FBO incomplete: attachment without "
                        "renderbuffer\n");
	 continue;
      }

      if (fb->Attachment[i].Type == GL_TEXTURE) {
	 if (rb->TexImage->Border) {
	    fbo_incomplete(fb, "FBO incomplete: texture with border\n");
	    continue;
	 }
      }

      irb = intel_renderbuffer(rb);
      if (irb == NULL) {
	 fbo_incomplete(fb, "FBO incomplete: software rendering "
                        "renderbuffer\n");
	 continue;
      }

      if (!brw_render_target_supported(brw, rb)) {
	 fbo_incomplete(fb, "FBO incomplete: Unsupported HW "
                        "texture/renderbuffer format attached: %s\n",
                        _mesa_get_format_name(intel_rb_format(irb)));
      }
   }
}
Ejemplo n.º 5
0
/**
 * Implements fast depth clears on gen6+.
 *
 * Fast clears basically work by setting a flag in each of the subspans
 * represented in the HiZ buffer that says "When you need the depth values for
 * this subspan, it's the hardware's current clear value."  Then later rendering
 * can just use the static clear value instead of referencing memory.
 *
 * The tricky part of the implementation is that you have to have the clear
 * value that was used on the depth buffer in place for all further rendering,
 * at least until a resolve to the real depth buffer happens.
 */
static bool
brw_fast_clear_depth(struct gl_context *ctx)
{
   struct brw_context *brw = brw_context(ctx);
   struct gl_framebuffer *fb = ctx->DrawBuffer;
   struct intel_renderbuffer *depth_irb =
      intel_get_renderbuffer(fb, BUFFER_DEPTH);
   struct intel_mipmap_tree *mt = depth_irb->mt;
   struct gl_renderbuffer_attachment *depth_att = &fb->Attachment[BUFFER_DEPTH];
   const struct gen_device_info *devinfo = &brw->screen->devinfo;

   if (devinfo->gen < 6)
      return false;

   if (!intel_renderbuffer_has_hiz(depth_irb))
      return false;

   /* We only handle full buffer clears -- otherwise you'd have to track whether
    * a previous clear had happened at a different clear value and resolve it
    * first.
    */
   if ((ctx->Scissor.EnableFlags & 1) && !noop_scissor(fb)) {
      perf_debug("Failed to fast clear %dx%d depth because of scissors.  "
                 "Possible 5%% performance win if avoided.\n",
                 mt->surf.logical_level0_px.width,
                 mt->surf.logical_level0_px.height);
      return false;
   }

   switch (mt->format) {
   case MESA_FORMAT_Z32_FLOAT_S8X24_UINT:
   case MESA_FORMAT_Z24_UNORM_S8_UINT:
      /* From the Sandy Bridge PRM, volume 2 part 1, page 314:
       *
       *     "[DevSNB+]: Several cases exist where Depth Buffer Clear cannot be
       *      enabled (the legacy method of clearing must be performed):
       *
       *      - If the depth buffer format is D32_FLOAT_S8X24_UINT or
       *        D24_UNORM_S8_UINT.
       */
      return false;

   case MESA_FORMAT_Z_UNORM16:
      /* From the Sandy Bridge PRM, volume 2 part 1, page 314:
       *
       *     "[DevSNB+]: Several cases exist where Depth Buffer Clear cannot be
       *      enabled (the legacy method of clearing must be performed):
       *
       *      - DevSNB{W/A}]: When depth buffer format is D16_UNORM and the
       *        width of the map (LOD0) is not multiple of 16, fast clear
       *        optimization must be disabled.
       */
      if (devinfo->gen == 6 &&
          (minify(mt->surf.phys_level0_sa.width,
                  depth_irb->mt_level - mt->first_level) % 16) != 0)
	 return false;
      break;

   default:
      break;
   }

   /* Quantize the clear value to what can be stored in the actual depth
    * buffer.  This makes the following check more accurate because it now
    * checks if the actual depth bits will match.  It also prevents us from
    * getting a too-accurate depth value during depth testing or when sampling
    * with HiZ enabled.
    */
   float clear_value =
      mt->format == MESA_FORMAT_Z_FLOAT32 ? ctx->Depth.Clear :
      (unsigned)(ctx->Depth.Clear * fb->_DepthMax) / (float)fb->_DepthMax;

   const uint32_t num_layers = depth_att->Layered ? depth_irb->layer_count : 1;

   /* If we're clearing to a new clear value, then we need to resolve any clear
    * flags out of the HiZ buffer into the real depth buffer.
    */
   if (mt->fast_clear_color.f32[0] != clear_value) {
      for (uint32_t level = mt->first_level; level <= mt->last_level; level++) {
         if (!intel_miptree_level_has_hiz(mt, level))
            continue;

         const unsigned level_layers = brw_get_num_logical_layers(mt, level);

         for (uint32_t layer = 0; layer < level_layers; layer++) {
            if (level == depth_irb->mt_level &&
                layer >= depth_irb->mt_layer &&
                layer < depth_irb->mt_layer + num_layers) {
               /* We're going to clear this layer anyway.  Leave it alone. */
               continue;
            }

            enum isl_aux_state aux_state =
               intel_miptree_get_aux_state(mt, level, layer);

            if (aux_state != ISL_AUX_STATE_CLEAR &&
                aux_state != ISL_AUX_STATE_COMPRESSED_CLEAR) {
               /* This slice doesn't have any fast-cleared bits. */
               continue;
            }

            /* If we got here, then the level may have fast-clear bits that
             * use the old clear value.  We need to do a depth resolve to get
             * rid of their use of the clear value before we can change it.
             * Fortunately, few applications ever change their depth clear
             * value so this shouldn't happen often.
             */
            intel_hiz_exec(brw, mt, level, layer, 1,
                           ISL_AUX_OP_FULL_RESOLVE);
            intel_miptree_set_aux_state(brw, mt, level, layer, 1,
                                        ISL_AUX_STATE_RESOLVED);
         }
      }

      intel_miptree_set_depth_clear_value(ctx, mt, clear_value);
   }

   bool need_clear = false;
   for (unsigned a = 0; a < num_layers; a++) {
      enum isl_aux_state aux_state =
         intel_miptree_get_aux_state(mt, depth_irb->mt_level,
                                     depth_irb->mt_layer + a);

      if (aux_state != ISL_AUX_STATE_CLEAR) {
         need_clear = true;
         break;
      }
   }

   if (!need_clear) {
      /* If all of the layers we intend to clear are already in the clear
       * state then simply updating the miptree fast clear value is sufficient
       * to change their clear value.
       */
      return true;
   }

   for (unsigned a = 0; a < num_layers; a++) {
      enum isl_aux_state aux_state =
         intel_miptree_get_aux_state(mt, depth_irb->mt_level,
                                     depth_irb->mt_layer + a);

      if (aux_state != ISL_AUX_STATE_CLEAR) {
         intel_hiz_exec(brw, mt, depth_irb->mt_level,
                        depth_irb->mt_layer + a, 1,
                        ISL_AUX_OP_FAST_CLEAR);
      }
   }

   /* Now, the HiZ buffer contains data that needs to be resolved to the depth
    * buffer.
    */
   intel_miptree_set_aux_state(brw, mt, depth_irb->mt_level,
                               depth_irb->mt_layer, num_layers,
                               ISL_AUX_STATE_CLEAR);

   return true;
}