intel: Fix intel_map_renderbuffer() for depthstencil buffers with separate stencil
authorChad Versace <chad.versace@linux.intel.com>
Mon, 14 Nov 2011 01:36:30 +0000 (17:36 -0800)
committerChad Versace <chad.versace@linux.intel.com>
Tue, 15 Nov 2011 14:42:09 +0000 (06:42 -0800)
For a depthstencil buffer with separate stencil,
intel_renderbuffer::region is null. (The regions are kept in hidden depth
and stencil buffers). Since the region is null, intel_map_renderbuffer()
assumed there was no data and returned a null map pointer, which in turn
was dereferenced (!) by MapRenderbuffer's caller.

This patch fixes intel_map_renderbuffer() to map the hidden depth buffer
through the GTT and return that as the mapped pointer. Also, the stencil
bits are scattered and gathered when needed.

Fixes the following Piglit tests on gen7:
    fbo/fbo-readpixels-depth-formats
    hiz/hiz-depth-read-fbo-d24s8
    hiz/hiz-stencil-read-fbo-d24s8
    EXT_packed_depth_stencil/fbo-clear-formats
    EXT_packed_depth_stencil/fbo-depth-GL_DEPTH24_STENCIL8-blit
    EXT_packed_depth_stencil/fbo-depth-GL_DEPTH24_STENCIL8-drawpixels
    EXT_packed_depth_stencil/fbo-depth-GL_DEPTH24_STENCIL8-readpixels
    EXT_packed_depth_stencil/fbo-depthstencil-GL_DEPTH24_STENCIL8-readpixels-24_8
    EXT_packed_depth_stencil/fbo-depthstencil-GL_DEPTH24_STENCIL8-readpixels-FLOAT-and-USHORT
    EXT_packed_depth_stencil/fbo-stencil-GL_DEPTH24_STENCIL8-readpixels

Reviewed-by: Eric Anholt <eric@anholt.net>
Signed-off-by: Chad Versace <chad.versace@linux.intel.com>
src/mesa/drivers/dri/intel/intel_fbo.c

index 2a78edfb6be42141724f2eac3252937c48b4b776..dbd5163b5f1b6b1e2359abbd6672812483b42e5a 100644 (file)
@@ -293,6 +293,91 @@ intel_map_renderbuffer_s8(struct gl_context *ctx,
        x, y, w, h, *out_map, *out_stride);
 }
 
+/**
+ * \brief Map a depthstencil buffer with separate stencil.
+ *
+ * A depthstencil renderbuffer, if using separate stencil, consists of a depth
+ * renderbuffer and a hidden stencil renderbuffer.  This function maps the
+ * depth buffer, whose format is MESA_FORMAT_X8_Z24, through the GTT and
+ * returns that as the mapped pointer. The caller need not be aware of the
+ * hidden stencil buffer and may safely assume that the mapped pointer points
+ * to a MESA_FORMAT_S8_Z24 buffer
+ *
+ * The consistency between the depth buffer's S8 bits and the hidden stencil
+ * buffer is managed within intel_map_renderbuffer() and
+ * intel_unmap_renderbuffer() by scattering or gathering the stencil bits
+ * according to the map mode.
+ *
+ * \see intel_map_renderbuffer()
+ * \see intel_unmap_renderbuffer_separate_s8z24()
+ */
+static void
+intel_map_renderbuffer_separate_s8z24(struct gl_context *ctx,
+                                     struct gl_renderbuffer *rb,
+                                     GLuint x, GLuint y, GLuint w, GLuint h,
+                                     GLbitfield mode,
+                                     GLubyte **out_map,
+                                     GLint *out_stride)
+{
+   struct intel_context *intel = intel_context(ctx);
+   struct intel_renderbuffer *irb = intel_renderbuffer(rb);
+
+   GLbitfield adjusted_mode;
+
+   uint8_t *s8z24_map;
+   int32_t s8z24_stride;
+
+   assert(rb->Name != 0);
+   assert(rb->Format == MESA_FORMAT_S8_Z24);
+   assert(irb->wrapped_depth != NULL);
+   assert(irb->wrapped_stencil != NULL);
+
+   irb->map_mode = mode;
+   irb->map_x = x;
+   irb->map_y = y;
+   irb->map_w = w;
+   irb->map_h = h;
+
+   if (mode & GL_MAP_READ_BIT) {
+      /* Since the caller may read the stencil bits, we must copy the stencil
+       * buffer's contents into the depth buffer. This necessitates that the
+       * depth buffer be mapped in write mode.
+       */
+      adjusted_mode = mode | GL_MAP_WRITE_BIT;
+   } else {
+      adjusted_mode = mode;
+   }
+
+   intel_map_renderbuffer_gtt(ctx, irb->wrapped_depth,
+                              x, y, w, h, adjusted_mode,
+                              &s8z24_map, &s8z24_stride);
+
+   if (mode & GL_MAP_READ_BIT) {
+      struct intel_renderbuffer *s8_irb;
+      uint8_t *s8_map;
+
+      s8_irb = intel_renderbuffer(irb->wrapped_stencil);
+      s8_map = intel_region_map(intel, s8_irb->region, GL_MAP_READ_BIT);
+
+      for (uint32_t pix_y = 0; pix_y < h; ++pix_y) {
+        for (uint32_t pix_x = 0; pix_x < w; ++pix_x) {
+           ptrdiff_t s8_offset = intel_offset_S8(s8_irb->region->pitch,
+                                                 x + pix_x,
+                                                 y + pix_y);
+           ptrdiff_t s8z24_offset = pix_y * s8z24_stride
+                                  + pix_x * 4
+                                  + 3;
+           s8z24_map[s8z24_offset] = s8_map[s8_offset];
+        }
+      }
+
+      intel_region_unmap(intel, s8_irb->region);
+   }
+
+   *out_map = s8z24_map;
+   *out_stride = s8z24_stride;
+}
+
 /**
  * \see dd_function_table::MapRenderbuffer
  */
@@ -308,7 +393,7 @@ intel_map_renderbuffer(struct gl_context *ctx,
    struct intel_renderbuffer *irb = intel_renderbuffer(rb);
 
    /* We sometimes get called with this by our intel_span.c usage. */
-   if (!irb->region) {
+   if (!irb->region && !irb->wrapped_depth) {
       *out_map = NULL;
       *out_stride = 0;
       return;
@@ -317,6 +402,9 @@ intel_map_renderbuffer(struct gl_context *ctx,
    if (rb->Format == MESA_FORMAT_S8) {
       intel_map_renderbuffer_s8(ctx, rb, x, y, w, h, mode,
                                out_map, out_stride);
+   } else if (irb->wrapped_depth) {
+      intel_map_renderbuffer_separate_s8z24(ctx, rb, x, y, w, h, mode,
+                                           out_map, out_stride);
    } else if (intel->gen >= 6 &&
              !(mode & GL_MAP_WRITE_BIT) &&
              irb->region->tiling == I915_TILING_X) {
@@ -375,6 +463,64 @@ intel_unmap_renderbuffer_s8(struct gl_context *ctx,
    irb->map_buffer = NULL;
 }
 
+/**
+ * \brief Unmap a depthstencil renderbuffer with separate stencil.
+ *
+ * \see intel_map_renderbuffer_separate_s8z24()
+ * \see intel_unmap_renderbuffer()
+ */
+static void
+intel_unmap_renderbuffer_separate_s8z24(struct gl_context *ctx,
+                                       struct gl_renderbuffer *rb)
+{
+   struct intel_context *intel = intel_context(ctx);
+   struct intel_renderbuffer *irb = intel_renderbuffer(rb);
+   struct intel_renderbuffer *s8z24_irb;
+
+   assert(rb->Name != 0);
+   assert(rb->Format == MESA_FORMAT_S8_Z24);
+   assert(irb->wrapped_depth != NULL);
+   assert(irb->wrapped_stencil != NULL);
+
+   s8z24_irb = intel_renderbuffer(irb->wrapped_depth);
+
+   if (irb->map_mode & GL_MAP_WRITE_BIT) {
+      /* Copy the stencil bits from the depth buffer into the stencil buffer.
+       */
+      uint32_t map_x = irb->map_x;
+      uint32_t map_y = irb->map_y;
+      uint32_t map_w = irb->map_w;
+      uint32_t map_h = irb->map_h;
+
+      struct intel_renderbuffer *s8_irb;
+      uint8_t *s8_map;
+      
+      s8_irb = intel_renderbuffer(irb->wrapped_stencil);
+      s8_map = intel_region_map(intel, s8_irb->region, GL_MAP_WRITE_BIT);
+
+      int32_t s8z24_stride = 4 * s8z24_irb->region->pitch;
+      uint8_t *s8z24_map = s8z24_irb->region->bo->virtual
+                        + map_y * s8z24_stride
+                        + map_x * 4;
+
+      for (uint32_t pix_y = 0; pix_y < map_h; ++pix_y) {
+        for (uint32_t pix_x = 0; pix_x < map_w; ++pix_x) {
+           ptrdiff_t s8_offset = intel_offset_S8(s8_irb->region->pitch,
+                                                 map_x + pix_x,
+                                                 map_y + pix_y);
+           ptrdiff_t s8z24_offset = pix_y * s8z24_stride
+                                  + pix_x * 4
+                                  + 3;
+           s8_map[s8_offset] = s8z24_map[s8z24_offset];
+        }
+      }
+
+      intel_region_unmap(intel, s8_irb->region);
+   }
+
+   drm_intel_gem_bo_unmap_gtt(s8z24_irb->region->bo);
+}
+
 /**
  * \see dd_function_table::UnmapRenderbuffer
  */
@@ -389,6 +535,8 @@ intel_unmap_renderbuffer(struct gl_context *ctx,
 
    if (rb->Format == MESA_FORMAT_S8) {
       intel_unmap_renderbuffer_s8(ctx, rb);
+   } else if (irb->wrapped_depth) {
+      intel_unmap_renderbuffer_separate_s8z24(ctx, rb);
    } else if (irb->map_bo) {
       /* Paired with intel_map_renderbuffer_blit(). */
       drm_intel_bo_unmap(irb->map_bo);