i965/Gen6: Work around GPU hangs due to misaligned depth coordinate offsets.
authorPaul Berry <stereotype441@gmail.com>
Thu, 26 Apr 2012 13:35:56 +0000 (06:35 -0700)
committerPaul Berry <stereotype441@gmail.com>
Mon, 7 May 2012 17:50:04 +0000 (10:50 -0700)
In i965 Gen6, Mesa has for a long time used the "depth coordinate
offset X/Y" settings (in 3DSTATE_DEPTH_BUFFER) to cause the GPU to
render to miplevels other than 0.  Unfortunately, this doesn't work,
because these offsets must be aligned to multiples of 8, and miplevels
in the depth buffer are only guaranteed to be aligned to multiples of
4.  When the offsets aren't aligned to a multiple of 8, the GPU
sometimes hangs.

As a temporary measure, to avoid GPU hangs, this patch smashes the 3
LSB's of "depth coordinate offset X/Y" to 0.  This results in
incorrect rendering to mipmapped depth textures, but that seems like a
reasonable stopgap while we figure out a better solution.

(Note that we have only ever observed this GPU hang on Gen6 when HiZ
is enabled, so another possible stopgap would be to disable HiZ).

Avoids GPU hangs in piglit test "depthstencil-render-miplevels" at
texture sizes that are not powers of 2.

Reviewed-by: Chad Verace <chad.versace@linux.intel.com>
src/mesa/drivers/dri/i965/brw_misc_state.c
src/mesa/drivers/dri/i965/gen6_hiz.c

index 7a0f5a31ac079fe3721c46809ff711bd0f79c84c..0c0389f8bdf44184bc76bcf02cdc99e42593292f 100644 (file)
@@ -398,6 +398,24 @@ static void emit_depthbuffer(struct brw_context *brw)
       tile_x = draw_x & tile_mask_x;
       tile_y = 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"
+       *
+       * We have no guarantee that tile_x and tile_y are correctly aligned,
+       * since they are determined by the mipmap layout, which is only aligned
+       * to multiples of 4.
+       *
+       * So, to avoid hanging the GPU, just smash the low order 3 bits of
+       * tile_x and tile_y to 0.  This is a temporary workaround until we come
+       * up with a better solution.
+       */
+      tile_x &= ~7;
+      tile_y &= ~7;
+
       BEGIN_BATCH(len);
       OUT_BATCH(_3DSTATE_DEPTH_BUFFER << 16 | (len - 2));
       OUT_BATCH((BRW_DEPTHFORMAT_D32_FLOAT << 18) |
@@ -436,6 +454,24 @@ static void emit_depthbuffer(struct brw_context *brw)
       tile_x = draw_x & tile_mask_x;
       tile_y = 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"
+       *
+       * We have no guarantee that tile_x and tile_y are correctly aligned,
+       * since they are determined by the mipmap layout, which is only aligned
+       * to multiples of 4.
+       *
+       * So, to avoid hanging the GPU, just smash the low order 3 bits of
+       * tile_x and tile_y to 0.  This is a temporary workaround until we come
+       * up with a better solution.
+       */
+      tile_x &= ~7;
+      tile_y &= ~7;
+
       offset = intel_region_get_aligned_offset(region,
                                                draw_x & ~tile_mask_x,
                                                draw_y & ~tile_mask_y);
index d9b547c39645b98bc0a3e308c0a06ac6d709d8c4..67d6bdb7ea94f4276a5fca0613bbeaa0e5fdba5d 100644 (file)
@@ -487,6 +487,24 @@ gen6_hiz_exec(struct intel_context *intel,
                                                         draw_x & ~tile_mask_x,
                                                         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"
+       *
+       * We have no guarantee that tile_x and tile_y are correctly aligned,
+       * since they are determined by the mipmap layout, which is only aligned
+       * to multiples of 4.
+       *
+       * So, to avoid hanging the GPU, just smash the low order 3 bits of
+       * tile_x and tile_y to 0.  This is a temporary workaround until we come
+       * up with a better solution.
+       */
+      tile_x &= ~7;
+      tile_y &= ~7;
+
       uint32_t format;
       switch (mt->format) {
       case MESA_FORMAT_Z16:       format = BRW_DEPTHFORMAT_D16_UNORM; break;