[Mesa-dev] [PATCH 16/22] i965: Add a userptr path for glReadPixels

Chris Wilson chris at chris-wilson.co.uk
Sat Aug 5 09:40:08 UTC 2017


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/Makefile.sources   |   1 +
 src/mesa/drivers/dri/i965/intel_pixel.h      |   7 +
 src/mesa/drivers/dri/i965/intel_pixel_pbo.c  | 252 +++++++++++++++++++++++++++
 src/mesa/drivers/dri/i965/intel_pixel_read.c |  38 ++--
 4 files changed, 280 insertions(+), 18 deletions(-)
 create mode 100644 src/mesa/drivers/dri/i965/intel_pixel_pbo.c

diff --git a/src/mesa/drivers/dri/i965/Makefile.sources b/src/mesa/drivers/dri/i965/Makefile.sources
index 425c883de8..a5550876cd 100644
--- a/src/mesa/drivers/dri/i965/Makefile.sources
+++ b/src/mesa/drivers/dri/i965/Makefile.sources
@@ -101,6 +101,7 @@ i965_FILES = \
 	intel_pixel_draw.c \
 	intel_pixel.h \
 	intel_pixel_read.c \
+	intel_pixel_pbo.c \
 	intel_screen.c \
 	intel_screen.h \
 	intel_state.c \
diff --git a/src/mesa/drivers/dri/i965/intel_pixel.h b/src/mesa/drivers/dri/i965/intel_pixel.h
index f5b931f5c1..c3d90d3297 100644
--- a/src/mesa/drivers/dri/i965/intel_pixel.h
+++ b/src/mesa/drivers/dri/i965/intel_pixel.h
@@ -58,4 +58,11 @@ void intelBitmap(struct gl_context * ctx,
 		 const struct gl_pixelstore_attrib *unpack,
 		 const GLubyte * pixels);
 
+bool intel_readpixels_pbo(struct gl_context * ctx,
+                          GLint x, GLint y,
+                          GLsizei width, GLsizei height,
+                          GLenum format, GLenum type,
+                          const struct gl_pixelstore_attrib *pack,
+                          GLvoid *pixels);
+
 #endif
diff --git a/src/mesa/drivers/dri/i965/intel_pixel_pbo.c b/src/mesa/drivers/dri/i965/intel_pixel_pbo.c
new file mode 100644
index 0000000000..4e212ee92f
--- /dev/null
+++ b/src/mesa/drivers/dri/i965/intel_pixel_pbo.c
@@ -0,0 +1,252 @@
+/*
+ * Copyright © 2012 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "main/enums.h"
+#include "main/mtypes.h"
+#include "main/macros.h"
+#include "main/fbobject.h"
+#include "main/image.h"
+#include "main/bufferobj.h"
+#include "main/readpix.h"
+#include "main/state.h"
+#include "main/glformats.h"
+
+#include "brw_blorp.h"
+#include "brw_context.h"
+#include "intel_screen.h"
+#include "intel_batchbuffer.h"
+#include "intel_blit.h"
+#include "intel_buffer_objects.h"
+#include "intel_buffers.h"
+#include "intel_fbo.h"
+#include "intel_mipmap_tree.h"
+#include "intel_pixel.h"
+#include "intel_buffer_objects.h"
+
+#define FILE_DEBUG_FLAG DEBUG_PIXEL
+
+
+static int
+get_texture_swizzle(const struct intel_renderbuffer *irb)
+{
+   if (irb->Base.Base._BaseFormat == GL_LUMINANCE ||
+       irb->Base.Base._BaseFormat == GL_INTENSITY)
+      return MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_ZERO, SWIZZLE_ZERO, SWIZZLE_ONE);
+
+   if (irb->Base.Base._BaseFormat == GL_LUMINANCE_ALPHA)
+      return MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_ZERO, SWIZZLE_ZERO, SWIZZLE_W);
+
+   if (irb->Base.Base._BaseFormat == GL_ALPHA)
+      return MAKE_SWIZZLE4(SWIZZLE_ZERO, SWIZZLE_ZERO, SWIZZLE_ZERO, SWIZZLE_W);
+
+   if (irb->Base.Base._BaseFormat == GL_RGB)
+      return MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_Y, SWIZZLE_Z, SWIZZLE_ONE);
+
+   return SWIZZLE_XYZW;
+}
+
+static bool
+need_signed_unsigned_int_conversion(mesa_format mesaFormat,
+                                    GLenum format, GLenum type)
+{
+   const GLenum mesaFormatType = _mesa_get_format_datatype(mesaFormat);
+   const bool is_format_integer = _mesa_is_enum_format_integer(format);
+   return (mesaFormatType == GL_INT &&
+           is_format_integer &&
+           (type == GL_UNSIGNED_INT ||
+            type == GL_UNSIGNED_SHORT ||
+            type == GL_UNSIGNED_BYTE)) ||
+          (mesaFormatType == GL_UNSIGNED_INT &&
+           is_format_integer &&
+           (type == GL_INT ||
+            type == GL_SHORT ||
+            type == GL_BYTE));
+}
+
+bool
+intel_readpixels_pbo(struct gl_context * ctx,
+                     GLint x, GLint y,
+                     GLsizei width, GLsizei height,
+                     GLenum format, GLenum type,
+                     const struct gl_pixelstore_attrib *pack,
+                     GLvoid *pixels)
+{
+   struct brw_context *brw = brw_context(ctx);
+   bool ok = false;
+
+   struct gl_renderbuffer *rb;
+   switch (format) {
+   case GL_STENCIL_INDEX:
+      rb = ctx->ReadBuffer->Attachment[BUFFER_STENCIL].Renderbuffer;
+      break;
+   case GL_DEPTH_COMPONENT:
+   case GL_DEPTH_STENCIL_EXT:
+      rb = ctx->ReadBuffer->Attachment[BUFFER_DEPTH].Renderbuffer;
+      break;
+   case GL_COLOR_INDEX:
+      rb = NULL;
+      break;
+   default:
+      /* all other formats should be color formats */
+      rb = ctx->ReadBuffer->_ColorReadBuffer;
+      break;
+   }
+   if (!rb)
+      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 (need_signed_unsigned_int_conversion(src->format, format, type))
+      return false;
+
+   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);
+   dst_format = _mesa_get_srgb_format_linear(dst_format);
+
+   if (!brw->mesa_format_supports_render[dst_format]) {
+      dst_format = _mesa_format_fallback_rgbx_to_rgba(dst_format);
+      if (!brw->mesa_format_supports_render[dst_format])
+         return false;
+   }
+
+   bool dst_flip = false;
+   int dst_stride = _mesa_image_row_stride(pack, width, format, type);
+   if (pack->Invert) {
+      dst_stride = -dst_stride;
+      dst_flip = true;
+   }
+
+   int bpp = _mesa_bytes_per_pixel(format, type);
+   pixels += pack->SkipRows * dst_stride + pack->SkipPixels * bpp;
+   int dst_size = dst_stride * (height - 1) + width * bpp;
+
+   struct brw_bo *dst_buffer;
+   int dst_offset;
+   if (_mesa_is_bufferobj(pack->BufferObj)) {
+      dst_offset = (GLintptr)pixels;
+      if ((dst_offset | dst_stride) % bpp)
+         return false;
+
+      dst_buffer = intel_bufferobj_buffer(brw,
+                                          intel_buffer_object(pack->BufferObj),
+                                          dst_offset,
+                                          dst_size,
+                                          false);
+   } else {
+      dst_offset = (GLintptr)pixels & 4095;
+      if ((dst_offset | dst_stride) % bpp)
+         return false;
+
+      dst_buffer = brw_bo_alloc_userptr(brw->bufmgr, "readpixels",
+                                        (void *)((GLintptr)pixels & -4096),
+                                        ALIGN(dst_size + dst_offset, 4096), 0);
+   }
+   if (!dst_buffer)
+      return false;
+
+   struct intel_mipmap_tree *dst =
+      intel_miptree_create_for_bo(brw,
+                                  dst_buffer,
+                                  dst_format,
+                                  dst_offset,
+                                  width, height, 1,
+                                  dst_stride,
+                                  MIPTREE_LAYOUT_TILING_NONE |
+                                  MIPTREE_LAYOUT_DISABLE_AUX);
+   if (!dst)
+      goto err_dst_buffer;
+
+   if (!rb->Name) {
+      dst_flip = !dst_flip;
+      y = rb->Height - y - height;
+   }
+
+   assert(dst->surf.tiling == ISL_TILING_LINEAR);
+   if (!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)) {
+      mesa_format src_format = irb->Base.Base.Format;
+
+      /* blorp restrictions; see try_blorp_blit() */
+      switch (format) {
+      case GL_STENCIL_INDEX:
+         if (src_format != dst_format)
+            goto err_dst_mt;
+
+         /* fallthrough */
+      case GL_DEPTH_COMPONENT:
+      case GL_DEPTH_STENCIL_EXT:
+         if ((src_format == MESA_FORMAT_Z24_UNORM_X8_UINT) !=
+             (dst_format == MESA_FORMAT_Z24_UNORM_X8_UINT))
+            goto err_dst_mt;
+
+         if (_mesa_get_format_base_format(src_format) == GL_DEPTH_STENCIL ||
+             _mesa_get_format_base_format(dst_format) == GL_DEPTH_STENCIL)
+            goto err_dst_mt;
+
+         src_format = MESA_FORMAT_NONE;
+         dst_format = MESA_FORMAT_NONE;
+         break;
+
+      default:
+         break;
+      }
+
+      brw_blorp_blit_miptrees(brw,
+                              src, irb->mt_level, irb->mt_layer,
+                              src_format, get_texture_swizzle(irb),
+                              dst, 0, 0, dst_format,
+                              x, y, x + width, y + height,
+                              0, 0, width, height,
+                              GL_NEAREST, false, dst_flip,
+                              false, false);
+   }
+
+   if (!_mesa_is_bufferobj(pack->BufferObj)) {
+      intel_batchbuffer_flush(brw);
+      brw_bo_wait_rendering(dst_buffer);
+   }
+
+   ok = true;
+err_dst_mt:
+   intel_miptree_release(&dst);
+err_dst_buffer:
+   if (!_mesa_is_bufferobj(pack->BufferObj))
+      brw_bo_unreference(dst_buffer);
+   return ok;
+}
diff --git a/src/mesa/drivers/dri/i965/intel_pixel_read.c b/src/mesa/drivers/dri/i965/intel_pixel_read.c
index 56ae678573..398a8b686d 100644
--- a/src/mesa/drivers/dri/i965/intel_pixel_read.c
+++ b/src/mesa/drivers/dri/i965/intel_pixel_read.c
@@ -34,10 +34,12 @@
 #include "main/glformats.h"
 #include "drivers/common/meta.h"
 
+#include "brw_blorp.h"
 #include "brw_context.h"
 #include "intel_screen.h"
 #include "intel_batchbuffer.h"
 #include "intel_blit.h"
+#include "intel_buffer_objects.h"
 #include "intel_buffers.h"
 #include "intel_fbo.h"
 #include "intel_mipmap_tree.h"
@@ -205,16 +207,26 @@ intelReadPixels(struct gl_context * ctx,
                 GLenum format, GLenum type,
                 const struct gl_pixelstore_attrib *pack, GLvoid * pixels)
 {
-   bool ok;
-
    struct brw_context *brw = brw_context(ctx);
    bool dirty;
 
    DBG("%s\n", __func__);
 
-   if (_mesa_is_bufferobj(pack->BufferObj)) {
-      if (_mesa_meta_pbo_GetTexSubImage(ctx, 2, NULL, x, y, 0, width, height, 1,
-                                        format, type, pixels, pack)) {
+   /* Reading pixels wont dirty the front buffer, so reset the dirty
+    * flag after calling intel_prepare_render(). */
+   dirty = brw->front_buffer_dirty;
+   intel_prepare_render(brw);
+   brw->front_buffer_dirty = dirty;
+
+   if (!_mesa_is_bufferobj(pack->BufferObj)) {
+      if (intel_readpixels_tiled_memcpy(ctx, x, y, width, height,
+                                        format, type, pixels, pack))
+         return;
+   }
+
+   if (intel_readpixels_pbo(ctx, x, y, width, height,
+                            format, type, pack, pixels)) {
+      if (_mesa_is_bufferobj(pack->BufferObj)) {
          /* _mesa_meta_pbo_GetTexSubImage() implements PBO transfers by
           * binding the user-provided BO as a fake framebuffer and rendering
           * to it.  This breaks the invariant of the GL that nothing is able
@@ -236,22 +248,12 @@ intelReadPixels(struct gl_context * ctx,
           * flush here unconditionally.
           */
          brw_emit_mi_flush(brw);
-         return;
       }
-
-      perf_debug("%s: fallback to CPU mapping in PBO case\n", __func__);
+      return;
    }
 
-   /* Reading pixels wont dirty the front buffer, so reset the dirty
-    * flag after calling intel_prepare_render(). */
-   dirty = brw->front_buffer_dirty;
-   intel_prepare_render(brw);
-   brw->front_buffer_dirty = dirty;
-
-   ok = intel_readpixels_tiled_memcpy(ctx, x, y, width, height,
-                                      format, type, pixels, pack);
-   if(ok)
-      return;
+   perf_debug("%s: fallback to CPU mapping%s\n", __func__,
+              _mesa_is_bufferobj(pack->BufferObj) ? " for PBO" : "");
 
    /* Update Mesa state before calling _mesa_readpixels().
     * XXX this may not be needed since ReadPixels no longer uses the
-- 
2.13.3



More information about the mesa-dev mailing list