[Mesa-dev] [PATCH 4/6] i965: Add blorp-based texture upload path

Pohjolainen, Topi topi.pohjolainen at gmail.com
Wed Oct 11 16:30:27 UTC 2017


On Tue, Oct 10, 2017 at 03:14:17PM -0700, Kenneth Graunke wrote:
> From: Topi Pohjolainen <topi.pohjolainen at intel.com>

I really don't qualify as an author anymore, you two have done a lot more work
here since the slim early version of mine.

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


More information about the mesa-dev mailing list