<div dir="ltr"><div class="gmail_extra"><div class="gmail_quote">On Tue, Oct 10, 2017 at 3:14 PM, Kenneth Graunke <span dir="ltr"><<a href="mailto:kenneth@whitecape.org" target="_blank">kenneth@whitecape.org</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">From: Topi Pohjolainen <<a href="mailto:topi.pohjolainen@intel.com">topi.pohjolainen@intel.com</a>><br>
<br>
v2:<br>
   - Fix return value (s/MESA_FORMAT_NONE/false/) (Anuj)<br>
   - Move _mesa_tex_format_from_format_<wbr>and_type() just<br>
     in the end avoiding additional if-block (Anuj)<br>
   - Explain better the array alignment restriction (Anuj)<br>
   - Do not bail out in case of gl_pixelstore_attrib::<wbr>ImageHeight,<br>
     it is handled by _mesa_image_offset() automatically (Ken).<br>
   - Support 1D_ARRAY by flipping depth, width and y, z (Ken).<br>
<br>
v3:<br>
   - Contrary to v2, do not try to handle<br>
     gl_pixelstore_attrib::<wbr>ImageHeight. Currently there are no<br>
     tests in piglit or cts for it. One could possibly copy or<br>
     modify tests/texturing/texsubimage.c. There, however, seems<br>
     to be number of corner cases to consider. Moreover, current<br>
     meta path applies the packing height for both source and<br>
     targets when determining the offset. This would probably<br>
     require re-visiting also.<br>
<br>
v4: Rebased on top of merged drm-bacon<br>
<br>
v5 (Jason Ekstrand):<br>
   - Move to brw_blorp.c<br>
   - Significant refactoring<br>
   - Fixed 1-D array textures<br>
   - Simplified handling of PBOs vs. CPU data.<br>
   - Handle gl_pixelstore_attrib::<wbr>ImageHeight.  It turns out there are<br>
     piglit tests that cover this. The original version was failing them<br>
     because of an error in the way it handled 1-D array textures.<br>
   - Add support for texture download<br>
<br>
v6 (Ken): Rebase fixes:<br>
   - Use intel_miptree_check_level_<wbr>layer instead of deleted fields<br>
   - Update for mesa_format_supports_render[] rename.<br>
   - Pass 'false' (read-only) to intel_bufferobj_buffer<br></blockquote><div><br></div><div>Why pass false instead of !read_only?<br></div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<br>
Cc: Topi Pohjolainen <<a href="mailto:topi.pohjolainen@intel.com">topi.pohjolainen@intel.com</a>><br>
Cc: Kenneth Graunke <<a href="mailto:kenneth@whitecape.org">kenneth@whitecape.org</a>><br>
Signed-off-by: Jason Ekstrand <<a href="mailto:jason@jlekstrand.net">jason@jlekstrand.net</a>><br>
---<br>
 src/mesa/drivers/dri/i965/brw_<wbr>blorp.c | 331 ++++++++++++++++++++++++++++++<wbr>++++<br>
 src/mesa/drivers/dri/i965/brw_<wbr>blorp.h |  20 ++<br>
 2 files changed, 351 insertions(+)<br>
<br>
diff --git a/src/mesa/drivers/dri/i965/<wbr>brw_blorp.c b/src/mesa/drivers/dri/i965/<wbr>brw_blorp.c<br>
index 835dbd2af36..5f3e437be3c 100644<br>
--- a/src/mesa/drivers/dri/i965/<wbr>brw_blorp.c<br>
+++ b/src/mesa/drivers/dri/i965/<wbr>brw_blorp.c<br>
@@ -24,7 +24,10 @@<br>
 #include "main/context.h"<br>
 #include "main/teximage.h"<br>
 #include "main/blend.h"<br>
+#include "main/bufferobj.h"<br>
+#include "main/enums.h"<br>
 #include "main/fbobject.h"<br>
+#include "main/image.h"<br>
 #include "main/renderbuffer.h"<br>
 #include "main/glformats.h"<br>
<br>
@@ -33,6 +36,7 @@<br>
 #include "brw_defines.h"<br>
 #include "brw_meta_util.h"<br>
 #include "brw_state.h"<br>
+#include "intel_buffer_objects.h"<br>
 #include "intel_fbo.h"<br>
 #include "common/gen_debug.h"<br>
<br>
@@ -754,6 +758,333 @@ brw_blorp_framebuffer(struct brw_context *brw,<br>
    return mask;<br>
 }<br>
<br>
+static struct brw_bo *<br>
+blorp_get_client_bo(struct brw_context *brw,<br>
+                    unsigned w, unsigned h, unsigned d,<br>
+                    GLenum target, GLenum format, GLenum type,<br>
+                    const void *pixels,<br>
+                    const struct gl_pixelstore_attrib *packing,<br>
+                    uint32_t *offset_out, uint32_t *row_stride_out,<br>
+                    uint32_t *image_stride_out, bool read_only)<br>
+{<br>
+   /* Account for SKIP_PIXELS, SKIP_ROWS, ALIGNMENT, and SKIP_IMAGES */<br>
+   const GLuint dims = _mesa_get_texture_dimensions(<wbr>target);<br>
+   const uint32_t first_pixel = _mesa_image_offset(dims, packing, w, h,<br>
+                                                   format, type, 0, 0, 0);<br>
+   const uint32_t last_pixel =  _mesa_image_offset(dims, packing, w, h,<br>
+                                                   format, type,<br>
+                                                   d - 1, h - 1, w);<br>
+   const uint32_t stride = _mesa_image_row_stride(<wbr>packing, w, format, type);<br>
+   const uint32_t cpp = _mesa_bytes_per_pixel(format, type);<br>
+   const uint32_t size = last_pixel - first_pixel;<br>
+<br>
+   *row_stride_out = stride;<br>
+   *image_stride_out = _mesa_image_image_stride(<wbr>packing, w, h, format, type);<br>
+<br>
+   if (_mesa_is_bufferobj(packing-><wbr>BufferObj)) {<br>
+      const uint32_t offset = first_pixel + (intptr_t)pixels;<br>
+      if (!read_only && ((offset % cpp) || (stride % cpp))) {<br>
+         perf_debug("Bad PBO alignment; fallback to CPU mapping\n");<br>
+         return false;<br>
+      }<br>
+<br>
+      /* This is a user-provided PBO. We just need to get the BO out */<br>
+      struct intel_buffer_object *intel_pbo =<br>
+         intel_buffer_object(packing-><wbr>BufferObj);<br>
+      struct brw_bo *bo =<br>
+         intel_bufferobj_buffer(brw, intel_pbo, offset, size, false);<br>
+<br>
+      /* We take a reference to the BO so that the caller can just always<br>
+       * unref without having to worry about whether it's a user PBO or one<br>
+       * we created.<br>
+       */<br>
+      brw_bo_reference(bo);<br>
+<br>
+      *offset_out = offset;<br>
+      return bo;<br>
+   } else {<br>
+      /* Someone should have already checked that there is data to upload. */<br>
+      assert(pixels);<br>
+<br>
+      /* Creating a temp buffer currently only works for upload */<br>
+      assert(read_only);<br>
+<br>
+      /* This is not a user-provided PBO.  Instead, pixels is a pointer to CPU<br>
+       * data which we need to copy into a BO.<br>
+       */<br>
+      struct brw_bo *bo =<br>
+         brw_bo_alloc(brw->bufmgr, "tmp_tex_subimage_src", size, 64);<br>
+      if (bo == NULL) {<br>
+         perf_debug("intel_texsubimage: temp bo creation failed: size = %u\n",<br>
+                    size);<br>
+         return NULL;<br>
+      }<br>
+<br>
+      if (brw_bo_subdata(bo, 0, size, pixels + first_pixel)) {<br>
+         perf_debug("intel_texsubimage: temp bo upload failed\n");<br>
+         brw_bo_unreference(bo);<br>
+         return NULL;<br>
+      }<br>
+<br>
+      *offset_out = 0;<br>
+      return bo;<br>
+   }<br>
+}<br>
+<br>
+/* Consider all the restrictions and determine the format of the source. */<br>
+static mesa_format<br>
+blorp_get_client_format(<wbr>struct brw_context *brw,<br>
+                        GLenum format, GLenum type,<br>
+                        const struct gl_pixelstore_attrib *packing)<br>
+{<br>
+   if (brw->ctx._ImageTransferState)<br>
+      return MESA_FORMAT_NONE;<br>
+<br>
+   if (packing->SwapBytes || packing->LsbFirst || packing->Invert) {<br>
+      perf_debug("intel_texsubimage_<wbr>blorp: unsupported gl_pixelstore_attrib\n");<br>
+      return MESA_FORMAT_NONE;<br>
+   }<br>
+<br>
+   if (format != GL_RED &&<br>
+       format != GL_RG &&<br>
+       format != GL_RGB &&<br>
+       format != GL_RGBA &&<br>
+       format != GL_ALPHA &&<br>
+       format != GL_RED_INTEGER &&<br>
+       format != GL_RG_INTEGER &&<br>
+       format != GL_RGB_INTEGER &&<br>
+       format != GL_RGBA_INTEGER) {<br>
+      perf_debug("intel_texsubimage_<wbr>blorp: %s not supported",<br>
+                 _mesa_enum_to_string(format));<br>
+      return MESA_FORMAT_NONE;<br>
+   }<br>
+<br>
+   return _mesa_tex_format_from_format_<wbr>and_type(&brw->ctx, format, type);<br>
+}<br>
+<br>
+static bool<br>
+need_signed_unsigned_int_<wbr>conversion(mesa_format src_format,<br>
+                                    mesa_format dst_format)<br>
+{<br>
+   const GLenum src_type = _mesa_get_format_datatype(src_<wbr>format);<br>
+   const GLenum dst_type = _mesa_get_format_datatype(dst_<wbr>format);<br>
+   return (src_type == GL_INT && dst_type == GL_UNSIGNED_INT) ||<br>
+          (src_type == GL_UNSIGNED_INT && dst_type == GL_INT);<br>
+}<br>
+<br>
+bool<br>
+brw_blorp_upload_miptree(<wbr>struct brw_context *brw,<br>
+                         struct intel_mipmap_tree *dst_mt,<br>
+                         mesa_format dst_format,<br>
+                         uint32_t level, uint32_t x, uint32_t y, uint32_t z,<br>
+                         uint32_t width, uint32_t height, uint32_t depth,<br>
+                         GLenum target, GLenum format, GLenum type,<br>
+                         const void *pixels,<br>
+                         const struct gl_pixelstore_attrib *packing)<br>
+{<br>
+   const mesa_format src_format =<br>
+      blorp_get_client_format(brw, format, type, packing);<br>
+   if (src_format == MESA_FORMAT_NONE)<br>
+      return false;<br>
+<br>
+   if (!brw->mesa_format_supports_<wbr>render[dst_format]) {<br>
+      perf_debug("intel_texsubimage: can't use %s as render target\n",<br>
+                 _mesa_get_format_name(dst_<wbr>format));<br>
+      return false;<br>
+   }<br>
+<br>
+   /* This function relies on blorp_blit to upload the pixel data to the<br>
+    * miptree.  But, blorp_blit doesn't support signed to unsigned or<br>
+    * unsigned to signed integer conversions.<br>
+    */<br>
+   if (need_signed_unsigned_int_<wbr>conversion(src_format, dst_format))<br>
+      return false;<br>
+<br>
+   uint32_t src_offset, src_row_stride, src_image_stride;<br>
+   struct brw_bo *src_bo =<br>
+      blorp_get_client_bo(brw, width, height, depth,<br>
+                          target, format, type, pixels, packing,<br>
+                          &src_offset, &src_row_stride,<br>
+                          &src_image_stride, true);<br>
+   if (src_bo == NULL)<br>
+      return false;<br>
+<br>
+   /* Now that source is offset to correct starting point, adjust the<br>
+    * given dimensions to treat 1D arrays as 2D.<br>
+    */<br>
+   if (target == GL_TEXTURE_1D_ARRAY) {<br>
+      assert(depth == 1);<br>
+      assert(z == 0);<br>
+      depth = height;<br>
+      height = 1;<br>
+      z = y;<br>
+      y = 0;<br>
+      src_image_stride = src_row_stride;<br>
+   }<br>
+<br>
+   intel_miptree_check_level_<wbr>layer(dst_mt, level, z + depth - 1);<br>
+<br>
+   bool result = false;<br>
+<br>
+   /* Blit slice-by-slice creating a single-slice miptree for each layer. Even<br>
+    * in case of linear buffers hardware wants image arrays to be aligned by<br>
+    * four rows. This way hardware only gets one image at a time and any<br>
+    * source alignment will do.<br>
+    */<br>
+   for (unsigned i = 0; i < depth; ++i) {<br>
+      struct intel_mipmap_tree *src_mt = intel_miptree_create_for_bo(<br>
+                                            brw, src_bo, src_format,<br>
+                                            src_offset + i * src_image_stride,<br>
+                                            width, height, 1,<br>
+                                            src_row_stride, 0);<br>
+<br>
+      if (!src_mt) {<br>
+         perf_debug("intel_texsubimage: miptree creation for src failed\n");<br>
+         goto err;<br>
+      }<br>
+<br>
+      /* In case exact match is needed, copy using equivalent UINT formats<br>
+       * preventing hardware from changing presentation for SNORM -1.<br>
+       */<br>
+      if (src_mt->format == dst_format) {<br>
+         brw_blorp_copy_miptrees(brw, src_mt, 0, 0,<br>
+                                 dst_mt, level, z + i,<br>
+                                 0, 0, x, y, width, height);<br>
+      } else {<br>
+         brw_blorp_blit_miptrees(brw, src_mt, 0, 0,<br>
+                                 src_format, SWIZZLE_XYZW,<br>
+                                 dst_mt, level, z + i,<br>
+                                 dst_format,<br>
+                                 0, 0, width, height,<br>
+                                 x, y, x + width, y + height,<br>
+                                 GL_NEAREST, false, false, false, false);<br>
+      }<br>
+<br>
+      intel_miptree_release(&src_mt)<wbr>;<br>
+   }<br>
+<br>
+   result = true;<br>
+<br>
+err:<br>
+   brw_bo_unreference(src_bo);<br>
+<br>
+   return result;<br>
+}<br>
+<br>
+bool<br>
+brw_blorp_download_miptree(<wbr>struct brw_context *brw,<br>
+                           struct intel_mipmap_tree *src_mt,<br>
+                           mesa_format src_format, uint32_t src_swizzle,<br>
+                           uint32_t level, uint32_t x, uint32_t y, uint32_t z,<br>
+                           uint32_t width, uint32_t height, uint32_t depth,<br>
+                           GLenum target, GLenum format, GLenum type,<br>
+                           bool y_flip, const void *pixels,<br>
+                           const struct gl_pixelstore_attrib *packing)<br>
+{<br>
+   const mesa_format dst_format =<br>
+      blorp_get_client_format(brw, format, type, packing);<br>
+   if (dst_format == MESA_FORMAT_NONE)<br>
+      return false;<br>
+<br>
+   if (!brw->mesa_format_supports_<wbr>render[dst_format]) {<br>
+      perf_debug("intel_texsubimage: can't use %s as render target\n",<br>
+                 _mesa_get_format_name(dst_<wbr>format));<br>
+      return false;<br>
+   }<br>
+<br>
+   /* This function relies on blorp_blit to download the pixel data from the<br>
+    * miptree. But, blorp_blit doesn't support signed to unsigned or unsigned<br>
+    * to signed integer conversions.<br>
+    */<br>
+   if (need_signed_unsigned_int_<wbr>conversion(src_format, dst_format))<br>
+      return false;<br>
+<br>
+   /* We can't fetch from LUMINANCE or intensity as that would require a<br>
+    * non-trivial swizzle.<br>
+    */<br>
+   switch (_mesa_get_format_base_format(<wbr>src_format)) {<br>
+   case GL_LUMINANCE:<br>
+   case GL_LUMINANCE_ALPHA:<br>
+   case GL_INTENSITY:<br>
+      return false;<br>
+   default:<br>
+      break;<br>
+   }<br>
+<br>
+   /* This pass only works for PBOs */<br>
+   assert(_mesa_is_bufferobj(<wbr>packing->BufferObj));<br>
+<br>
+   uint32_t dst_offset, dst_row_stride, dst_image_stride;<br>
+   struct brw_bo *dst_bo =<br>
+      blorp_get_client_bo(brw, width, height, depth,<br>
+                          target, format, type, pixels, packing,<br>
+                          &dst_offset, &dst_row_stride,<br>
+                          &dst_image_stride, true);<br>
+   if (dst_bo == NULL)<br>
+      return false;<br>
+<br>
+   /* Now that source is offset to correct starting point, adjust the<br>
+    * given dimensions to treat 1D arrays as 2D.<br>
+    */<br>
+   if (target == GL_TEXTURE_1D_ARRAY) {<br>
+      assert(depth == 1);<br>
+      assert(z == 0);<br>
+      depth = height;<br>
+      height = 1;<br>
+      z = y;<br>
+      y = 0;<br>
+      dst_image_stride = dst_row_stride;<br>
+   }<br>
+<br>
+   intel_miptree_check_level_<wbr>layer(src_mt, level, z + depth - 1);<br>
+<br>
+   bool result = false;<br>
+<br>
+   /* Blit slice-by-slice creating a single-slice miptree for each layer. Even<br>
+    * in case of linear buffers hardware wants image arrays to be aligned by<br>
+    * four rows. This way hardware only gets one image at a time and any<br>
+    * source alignment will do.<br>
+    */<br>
+   for (unsigned i = 0; i < depth; ++i) {<br>
+      struct intel_mipmap_tree *dst_mt = intel_miptree_create_for_bo(<br>
+                                            brw, dst_bo, dst_format,<br>
+                                            dst_offset + i * dst_image_stride,<br>
+                                            width, height, 1,<br>
+                                            dst_row_stride, 0);<br>
+<br>
+      if (!dst_mt) {<br>
+         perf_debug("intel_texsubimage: miptree creation for src failed\n");<br>
+         goto err;<br>
+      }<br>
+<br>
+      /* In case exact match is needed, copy using equivalent UINT formats<br>
+       * preventing hardware from changing presentation for SNORM -1.<br>
+       */<br>
+      if (dst_mt->format == src_format && !y_flip &&<br>
+          src_swizzle == SWIZZLE_XYZW) {<br>
+         brw_blorp_copy_miptrees(brw, src_mt, level, z + i,<br>
+                                 dst_mt, 0, 0,<br>
+                                 x, y, 0, 0, width, height);<br>
+      } else {<br>
+         brw_blorp_blit_miptrees(brw, src_mt, level, z + i,<br>
+                                 src_format, src_swizzle,<br>
+                                 dst_mt, 0, 0, dst_format,<br>
+                                 x, y, x + width, y + height,<br>
+                                 0, 0, width, height,<br>
+                                 GL_NEAREST, false, y_flip, false, false);<br>
+      }<br>
+<br>
+      intel_miptree_release(&dst_mt)<wbr>;<br>
+   }<br>
+<br>
+   result = true;<br>
+<br>
+err:<br>
+   brw_bo_unreference(dst_bo);<br>
+<br>
+   return result;<br>
+}<br>
+<br>
 static bool<br>
 set_write_disables(const struct intel_renderbuffer *irb,<br>
                    const GLubyte *color_mask, bool *color_write_disable)<br>
diff --git a/src/mesa/drivers/dri/i965/<wbr>brw_blorp.h b/src/mesa/drivers/dri/i965/<wbr>brw_blorp.h<br>
index cf781ec53cb..c5ded891bbf 100644<br>
--- a/src/mesa/drivers/dri/i965/<wbr>brw_blorp.h<br>
+++ b/src/mesa/drivers/dri/i965/<wbr>brw_blorp.h<br>
@@ -67,6 +67,26 @@ brw_blorp_copy_buffers(struct brw_context *brw,<br>
                        unsigned dst_offset,<br>
                        unsigned size);<br>
<br>
+bool<br>
+brw_blorp_upload_miptree(<wbr>struct brw_context *brw,<br>
+                         struct intel_mipmap_tree *dst_mt,<br>
+                         mesa_format dst_format,<br>
+                         uint32_t level, uint32_t x, uint32_t y, uint32_t z,<br>
+                         uint32_t width, uint32_t height, uint32_t depth,<br>
+                         GLenum target, GLenum format, GLenum type,<br>
+                         const void *pixels,<br>
+                         const struct gl_pixelstore_attrib *packing);<br>
+<br>
+bool<br>
+brw_blorp_download_miptree(<wbr>struct brw_context *brw,<br>
+                           struct intel_mipmap_tree *src_mt,<br>
+                           mesa_format src_format, uint32_t src_swizzle,<br>
+                           uint32_t level, uint32_t x, uint32_t y, uint32_t z,<br>
+                           uint32_t width, uint32_t height, uint32_t depth,<br>
+                           GLenum target, GLenum format, GLenum type,<br>
+                           bool y_flip, const void *pixels,<br>
+                           const struct gl_pixelstore_attrib *packing);<br>
+<br>
 void<br>
 brw_blorp_clear_color(struct brw_context *brw, struct gl_framebuffer *fb,<br>
                       GLbitfield mask, bool partial_clear, bool encode_srgb);<br>
<span class="HOEnZb"><font color="#888888">--<br>
2.14.2<br>
<br>
</font></span></blockquote></div><br></div></div>