[Mesa-dev] [PATCH 69/70] i965: Add a userptr path for GetImage

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


Similar to glReadPixels, using the GPU to blit back into the client's
buffer is preferrable to using a coherent mmaping (but not manual
detiling for several reasons).

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

diff --git a/src/mesa/drivers/dri/i965/intel_tex_image.c b/src/mesa/drivers/dri/i965/intel_tex_image.c
index d0a4555..2589d77 100644
--- a/src/mesa/drivers/dri/i965/intel_tex_image.c
+++ b/src/mesa/drivers/dri/i965/intel_tex_image.c
@@ -6,6 +6,7 @@
 #include "main/bufferobj.h"
 #include "main/context.h"
 #include "main/formats.h"
+#include "main/glformats.h"
 #include "main/image.h"
 #include "main/pbo.h"
 #include "main/renderbuffer.h"
@@ -460,6 +461,124 @@ intel_gettexsubimage_tiled_memcpy(struct gl_context *ctx,
    );
 }
 
+static bool
+intel_gettexsubimage_userptr(struct gl_context *ctx,
+                             struct gl_texture_image *texImage,
+                             GLint x, GLint y, GLint z,
+                             GLsizei width, GLsizei height, GLsizei depth,
+                             GLenum format, GLenum type,
+                             GLvoid * pixels,
+                             const struct gl_pixelstore_attrib *pack)
+{
+   struct brw_context *brw = brw_context(ctx);
+   struct intel_texture_image *image = intel_texture_image(texImage);
+
+   if (_mesa_is_bufferobj(ctx->Pack.BufferObj))
+      return false;
+
+   if (ctx->_ImageTransferState)
+      return false;
+
+   if (pack->SwapBytes || pack->LsbFirst) {
+      DBG("%s: bad packing params\n", __func__);
+      return false;
+   }
+
+   /* Don't allow conversion between formats as the internal storage of the
+    * image (image->mt->format) may itself not match the original and
+    * allow false transforms.
+    */
+   if (texImage->_BaseFormat != format)
+      return false;
+
+   struct intel_mipmap_tree *src = image->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_get_format_base_format(dst_format) != texImage->_BaseFormat)
+         return false;
+
+      if (_mesa_format_is_mesa_array_format(dst_format))
+         dst_format = _mesa_format_from_array_format(dst_format);
+
+      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: bad format for blit\n", __func__);
+         return false;
+      }
+   }
+
+   int src_level = texImage->Level + texImage->TexObject->MinLevel;
+   int src_slice = texImage->Face + texImage->TexObject->MinLayer;
+
+   bool dst_flip = false;
+   int dst_stride = _mesa_image_row_stride(pack, width, format, type);
+   int image_height = pack->ImageHeight == 0 ? height : pack->ImageHeight;
+   int full_height = image_height * (depth - 1) + height;
+   int size = dst_stride * full_height;
+
+   if (pack->Invert) {
+      dst_stride = -dst_stride;
+      dst_flip = true;
+   }
+
+   int dst_offset = (GLintptr)pixels & 4095;
+   dst_offset += _mesa_image_offset(3, pack, width, height,
+                                    format, type, 0, 0, 0);
+   size += dst_offset;
+   size = ALIGN(size, 4096);
+
+   if (texImage->TexObject->Target == GL_TEXTURE_1D_ARRAY) {
+      assert(depth == 1);
+      assert(z == 0);
+      depth = height;
+      height = 1;
+      image_height = 1;
+      z = y;
+      y = 0;
+   }
+
+   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, depth,
+                                  dst_stride,
+                                  0);
+   if (dst) {
+      do {
+         ok = intel_miptree_blit(brw,
+                                 src, src_level, src_slice + z,
+                                 x, y, false,
+                                 dst, 0, 0,
+                                 0, z * image_height, dst_flip,
+                                 width, height, GL_COPY);
+         z++;
+      } while (--depth && ok);
+   }
+   intel_miptree_release(&dst);
+
+   brw_bo_map(dst_buffer, MAP_WRITE, PERF_DEBUG(brw, "ReadPixels"));
+   brw_bo_put(dst_buffer);
+
+   return ok;
+}
+
 static void
 intel_get_tex_sub_image(struct gl_context *ctx,
                         GLint xoffset, GLint yoffset, GLint zoffset,
@@ -496,6 +615,16 @@ intel_get_tex_sub_image(struct gl_context *ctx,
    if(ok)
       return;
 
+   ok = intel_gettexsubimage_userptr(ctx, texImage,
+                                     0, 0, 0,
+                                     texImage->Width,
+                                     texImage->Height,
+                                     texImage->Depth,
+                                     format, type, pixels, &ctx->Pack);
+
+   if(ok)
+      return;
+
    _mesa_meta_GetTexSubImage(ctx, xoffset, yoffset, zoffset,
                              width, height, depth,
                              format, type, pixels, texImage);
-- 
2.5.0



More information about the mesa-dev mailing list