i965/gen6+: Adjust stencil buffer size after computing miptree layout.
authorPaul Berry <stereotype441@gmail.com>
Tue, 4 Sep 2012 14:57:37 +0000 (07:57 -0700)
committerPaul Berry <stereotype441@gmail.com>
Wed, 12 Sep 2012 21:44:12 +0000 (14:44 -0700)
Since Gen6+ stencil buffers use W-tiling (a tiling arrangement which
drm and the kernel are not aware of) we need to round up the width and
height of a stencil buffer to multiples of the W-tile size (64x64)
before allocating a stencil buffer.  Previously, we rounded up the
size of the base miplevel, and then computed the miptree layout based
on the rounded up size.  This was incorrect, because it meant that the
total size of the miptree would not be properly W-tile aligned, and
therefore we would not always allocate enough pages.

(Note: even though the GL API doesn't allow creation of mipmapped
stencil textures, it does allow mipmapping of a combined depth/stencil
texture, and on Gen6+, a combined depth/stencil texture is internally
implemented as a pair of separate depth and stencil buffers.)

For example, on Sandy Bridge, when allocating a mipmapped stencil
texture of size 128x128, we would first round up to the nearest
multiple of 64x64 (causing no change to the size), and then compute
the miptree layout (whose size worked out to 128x196).  Then we would
request an allocation of 128*196 bytes (6.125 pages), causing 7 pages
to be allocated to the texture.  However, the texture needs 8 pages,
since each W-tile occupies a page, and it takes 2 W-tiles to cover a
width of 128 and 4 W-tiles to cover a height of 196.

This patch changes the order of operations so that the miptree layout
is computed first and then the total size of the miptree is rounded up
to be W-tile aligned.

NOTE: This is a candidate for stable release branches.

Reviewed-by: Eric Anholt <eric@anholt.net>
src/mesa/drivers/dri/intel/intel_mipmap_tree.c

index 24cd9e9ad995d90d66b35f3d5dcec7c68bc33068..dbfddc8ffffbca7c7cb6c33a37ccf63c92f38aab 100644 (file)
@@ -200,6 +200,7 @@ intel_miptree_create(struct intel_context *intel,
    uint32_t tiling = I915_TILING_NONE;
    GLenum base_format;
    bool wraps_etc1 = false;
+   GLuint total_width, total_height;
 
    if (format == MESA_FORMAT_ETC1_RGB8) {
       format = MESA_FORMAT_RGBX8888_REV;
@@ -231,16 +232,6 @@ intel_miptree_create(struct intel_context *intel,
         tiling = I915_TILING_X;
    }
 
-   if (format == MESA_FORMAT_S8) {
-      /* The stencil buffer is W tiled. However, we request from the kernel a
-       * non-tiled buffer because the GTT is incapable of W fencing.  So round
-       * up the width and height to match the size of W tiles (64x64).
-       */
-      tiling = I915_TILING_NONE;
-      width0 = ALIGN(width0, 64);
-      height0 = ALIGN(height0, 64);
-   }
-
    mt = intel_miptree_create_internal(intel, target, format,
                                      first_level, last_level, width0,
                                      height0, depth0,
@@ -253,12 +244,25 @@ intel_miptree_create(struct intel_context *intel,
       return NULL;
    }
 
+   total_width = mt->total_width;
+   total_height = mt->total_height;
+
+   if (format == MESA_FORMAT_S8) {
+      /* The stencil buffer is W tiled. However, we request from the kernel a
+       * non-tiled buffer because the GTT is incapable of W fencing.  So round
+       * up the width and height to match the size of W tiles (64x64).
+       */
+      tiling = I915_TILING_NONE;
+      total_width = ALIGN(total_width, 64);
+      total_height = ALIGN(total_height, 64);
+   }
+
    mt->wraps_etc1 = wraps_etc1;
    mt->region = intel_region_alloc(intel->intelScreen,
                                   tiling,
                                   mt->cpp,
-                                  mt->total_width,
-                                  mt->total_height,
+                                  total_width,
+                                  total_height,
                                   expect_accelerated_upload);
    mt->offset = 0;