[Mesa-dev] [PATCH 68/70] i965: Add a userptr path for glReadPixels

Chris Wilson chris at chris-wilson.co.uk
Fri Aug 7 13:14:12 PDT 2015


While it is preferrable to use a fast manual detiling method for LLC
(does not require synchronisation with a busy GPU and for accessing main
memory both the CPU and GPU have the same bandwidth), if we don't have
such a path then using the GPU to perform the blit is far preferable to
a coherent mmapping.

Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>
---
 src/mesa/drivers/dri/i965/intel_pixel_read.c | 117 +++++++++++++++++++++++++++
 1 file changed, 117 insertions(+)

diff --git a/src/mesa/drivers/dri/i965/intel_pixel_read.c b/src/mesa/drivers/dri/i965/intel_pixel_read.c
index 5765027..16a04fb 100644
--- a/src/mesa/drivers/dri/i965/intel_pixel_read.c
+++ b/src/mesa/drivers/dri/i965/intel_pixel_read.c
@@ -196,6 +196,118 @@ intel_readpixels_tiled_memcpy(struct gl_context * ctx,
    );
 }
 
+static bool
+intel_readpixels_userptr(struct gl_context * ctx,
+                         GLint x, GLint y,
+                         GLsizei width, GLsizei height,
+                         GLenum format, GLenum type,
+                         GLvoid * pixels,
+                         const struct gl_pixelstore_attrib *pack)
+{
+   struct brw_context *brw = brw_context(ctx);
+
+   if (_mesa_is_bufferobj(pack->BufferObj))
+      return false;
+
+   struct gl_renderbuffer *rb = NULL;
+   switch (format) {
+   case GL_STENCIL_INDEX:
+      if (0) /* Stencils are W-tiled which is not supported by the blitter */
+         rb = ctx->ReadBuffer->Attachment[BUFFER_STENCIL].Renderbuffer;
+      break;
+   case GL_DEPTH_COMPONENT:
+      rb = ctx->ReadBuffer->Attachment[BUFFER_DEPTH].Renderbuffer;
+      break;
+   case GL_DEPTH_STENCIL_EXT:
+      break;
+   default:
+      /* all other formats should be color formats */
+      rb = ctx->ReadBuffer->_ColorReadBuffer;
+      break;
+   }
+   if (rb == NULL)
+      return false;
+
+   if (pack->SwapBytes || pack->LsbFirst) {
+      DBG("%s: bad packing params\n", __func__);
+      return false;
+   }
+
+   if (_mesa_readpixels_needs_slow_path(ctx, format, type, GL_TRUE)) {
+      DBG("%s: non-trivial conversion required\n", __func__);
+      return false;
+   }
+
+   struct intel_renderbuffer *irb = intel_renderbuffer(rb);
+   struct intel_mipmap_tree *src = irb->mt;
+   if (format == GL_STENCIL_INDEX && src->stencil_mt)
+      src = src->stencil_mt;
+
+   if (!_mesa_format_matches_format_and_type(src->format, format, type, 0)) {
+      mesa_format src_format = src->format;
+      mesa_format dst_format = _mesa_format_from_format_and_type(format, type);
+      if (_mesa_format_is_mesa_array_format(dst_format))
+         dst_format = _mesa_format_from_array_format(dst_format);
+
+      /* We can safely discard sRGB for the ReadPixels interface */
+      src_format = _mesa_get_srgb_format_linear(src_format);
+      dst_format = _mesa_get_srgb_format_linear(dst_format);
+
+      if (!intel_miptree_blit_compatible_formats(src_format, dst_format)) {
+         DBG("%s: incompatible formats for blit (src=%s, dst=%s)\n",
+             __func__,
+             _mesa_get_format_name(src_format),
+             _mesa_get_format_name(dst_format));
+         return false;
+      }
+   }
+
+   bool dst_flip = false;
+   int dst_stride = _mesa_image_row_stride(pack, width, format, type);
+   int size = dst_stride * height;
+
+   if (pack->Invert) {
+      dst_stride = -dst_stride;
+      dst_flip = true;
+   }
+
+   int dst_offset = (GLintptr)pixels & 4095;
+   dst_offset += _mesa_image_offset(2, pack, width, height,
+                                    format, type, 0, 0, 0);
+   size += dst_offset;
+   size = ALIGN(size, 4096);
+
+   brw_bo *dst_buffer =
+      brw_bo_create_userptr(&brw->batch, "readpixels",
+                            (void *)((GLintptr)pixels & ~4095),
+                            size, 0);
+   if (dst_buffer == NULL)
+      return false;
+
+   bool ok = false;
+   struct intel_mipmap_tree *dst =
+      intel_miptree_create_for_bo(brw,
+                                  dst_buffer,
+                                  src->format,
+                                  dst_offset,
+                                  width, height, 1,
+                                  dst_stride,
+                                  0);
+   if (dst)
+      ok = intel_miptree_blit(brw,
+                              src, irb->mt_level, irb->mt_layer,
+                              x, y, false,
+                              dst, 0, 0,
+                              0, 0, dst_flip,
+                              width, height, GL_COPY);
+   intel_miptree_release(&dst);
+
+   brw_bo_map(dst_buffer, MAP_WRITE, PERF_DEBUG(brw, "ReadPixels"));
+   brw_bo_put(dst_buffer);
+
+   return ok;
+}
+
 void
 intelReadPixels(struct gl_context * ctx,
                 GLint x, GLint y, GLsizei width, GLsizei height,
@@ -244,6 +356,11 @@ intelReadPixels(struct gl_context * ctx,
    if(ok)
       return;
 
+   ok = intel_readpixels_userptr(ctx, x, y, width, height,
+                                 format, type, pixels, pack);
+   if(ok)
+      return;
+
    /* glReadPixels() wont dirty the front buffer, so reset the dirty
     * flag after calling intel_prepare_render(). */
    dirty = brw->front_buffer_dirty;
-- 
2.5.0



More information about the mesa-dev mailing list