[Mesa-dev] [PATCH 6/9] i965: Add support for tex upload using gpu

Pohjolainen, Topi topi.pohjolainen at gmail.com
Mon Jan 2 08:45:06 UTC 2017


On Thu, Dec 29, 2016 at 11:55:37AM -0800, Anuj Phogat wrote:
> On Tue, Dec 20, 2016 at 6:45 AM, Topi Pohjolainen
> <topi.pohjolainen at gmail.com> wrote:
> > Signed-off-by: Topi Pohjolainen <topi.pohjolainen at intel.com>
> > ---
> >  src/mesa/drivers/dri/i965/intel_tex.h          |   8 +
> >  src/mesa/drivers/dri/i965/intel_tex_subimage.c | 194 +++++++++++++++++++++++++
> >  2 files changed, 202 insertions(+)
> >
> > diff --git a/src/mesa/drivers/dri/i965/intel_tex.h b/src/mesa/drivers/dri/i965/intel_tex.h
> > index 376f075..c7d0937 100644
> > --- a/src/mesa/drivers/dri/i965/intel_tex.h
> > +++ b/src/mesa/drivers/dri/i965/intel_tex.h
> > @@ -65,6 +65,14 @@ intel_texsubimage_tiled_memcpy(struct gl_context *ctx,
> >                                 bool for_glTexImage);
> >
> >  bool
> > +intel_texsubimage_gpu_copy(struct brw_context *brw, GLuint dims,
> > +                           struct gl_texture_image *tex_image,
> > +                           unsigned x, unsigned y, unsigned z,
> > +                           unsigned w, unsigned h, unsigned d,
> > +                           GLenum format, GLenum type, const void *pixels,
> > +                           const struct gl_pixelstore_attrib *packing);
> > +
> > +bool
> >  intel_gettexsubimage_tiled_memcpy(struct gl_context *ctx,
> >                                    struct gl_texture_image *texImage,
> >                                    GLint xoffset, GLint yofset,
> > diff --git a/src/mesa/drivers/dri/i965/intel_tex_subimage.c b/src/mesa/drivers/dri/i965/intel_tex_subimage.c
> > index b7e52bc..f999a93 100644
> > --- a/src/mesa/drivers/dri/i965/intel_tex_subimage.c
> > +++ b/src/mesa/drivers/dri/i965/intel_tex_subimage.c
> > @@ -24,6 +24,7 @@
> >   */
> >
> >  #include "main/bufferobj.h"
> > +#include "main/glformats.h"
> >  #include "main/image.h"
> >  #include "main/macros.h"
> >  #include "main/mtypes.h"
> > @@ -34,8 +35,10 @@
> >  #include "main/enums.h"
> >  #include "drivers/common/meta.h"
> >
> > +#include "brw_blorp.h"
> >  #include "brw_context.h"
> >  #include "intel_batchbuffer.h"
> > +#include "intel_buffer_objects.h"
> >  #include "intel_tex.h"
> >  #include "intel_mipmap_tree.h"
> >  #include "intel_blit.h"
> > @@ -43,6 +46,197 @@
> >
> >  #define FILE_DEBUG_FLAG DEBUG_TEXTURE
> >
> > +static drm_intel_bo *
> > +intel_texsubimage_get_src_as_bo(struct brw_context *brw, unsigned dims,
> > +                                struct gl_texture_image *tex_image,
> > +                                unsigned w, unsigned h, unsigned d,
> > +                                GLenum format, GLenum type, const void *pixels,
> > +                                const struct gl_pixelstore_attrib *packing)
> > +{
> > +   /* Account for SKIP_PIXELS, SKIP_ROWS, ALIGNMENT, and SKIP_IMAGES */
> > +   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 size = last_pixel - first_pixel;
> > +
> > +   drm_intel_bo * const bo =
> > +      drm_intel_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 false;
> > +   }
> > +
> > +   if (drm_intel_bo_subdata(bo, 0, size, pixels + first_pixel)) {
> > +      perf_debug("intel_texsubimage: temp bo upload failed\n");
> > +      drm_intel_bo_unreference(bo);
> > +      return NULL;
> > +   }
> > +
> > +   return bo;
> > +}
> > +
> > +static uint32_t
> > +intel_texsubimage_get_src_offset(unsigned dims, unsigned w, unsigned h,
> > +                                 GLenum format, GLenum type,
> > +                                 const void *pixels,
> > +                                 const struct gl_pixelstore_attrib *packing)
> > +{
> > +   /* Account for SKIP_PIXELS, SKIP_ROWS, ALIGNMENT, and SKIP_IMAGES */
> > +   const uint32_t first_pixel = _mesa_image_offset(dims, packing, w, h,
> > +                                                   format, type, 0, 0, 0);
> > +
> > +   /* In case of buffer object source 'pixels' represents offset in bytes. */
> > +   return first_pixel + (intptr_t)pixels;
> > +}
> > +
> > +/* Consider all the restrictions and determine the format of the source. */
> > +static mesa_format
> > +intel_texsubimage_check_upload(struct brw_context *brw,
> > +                               const struct gl_texture_image *tex_image,
> > +                               unsigned h, GLenum format, GLenum type,
> > +                               const struct gl_pixelstore_attrib *packing)
> > +{
> > +   /* TODO: Add support for buffer object upload 1D alignment or perhaps use
> > +    * flat 2D source.
> > +    */
> > +   if (tex_image->TexObject->Target == GL_TEXTURE_1D_ARRAY) {
> > +      perf_debug("intel_texsubimage: 1D_ARRAY not supported\n");
> > +      return MESA_FORMAT_NONE;
> > +   }
> > +
> > +   if (brw->ctx._ImageTransferState)
> > +      return MESA_FORMAT_NONE;
> > +
> > +   if (packing->SwapBytes || packing->LsbFirst || packing->Invert) {
> > +      perf_debug("intel_texsubimage: unsupported gl_pixelstore_attrib\n");
> > +      return MESA_FORMAT_NONE;
> > +   }
> > +
> > +   /* TODO: This can be easily supported as blit manually offsets miptree
> > +    *       for each slice.
> > +    */
> > +   if (packing->ImageHeight != 0) {
> > +      perf_debug("intel_texsubimage: _attrib::ImageHeight not supported\n");
> > +      return MESA_FORMAT_NONE;
> > +   }
> > +
> > +   if (packing->RowLength != 0) {
> > +      perf_debug("intel_texsubimage: _attrib::RowLength not supported\n");
> > +      return MESA_FORMAT_NONE;
> > +   }
> > +
> > +   if (format != GL_RED &&
> > +       format != GL_RG &&
> > +       format != GL_RGB &&
> > +       format != GL_RGBA &&
> > +       format != GL_ALPHA) {
> > +      perf_debug("intel_texsubimage: %s not supported",
> > +                 _mesa_enum_to_string(format));
> > +      return MESA_FORMAT_NONE;
> > +   }
> > +
> > +   const mesa_format src_mesa_format =
> > +      _mesa_tex_format_from_format_and_type(&brw->ctx, format, type);
> > +   if (src_mesa_format == MESA_FORMAT_NONE)
> > +      return MESA_FORMAT_NONE;
> Above if check is not required if you move the src_mesa_format
> computation after the below if block.

That makes it simpler, will do.

> > +
> > +   if (!brw->format_supported_as_render_target[tex_image->TexFormat]) {
> > +      perf_debug("intel_texsubimage: can't use %s as render target\n",
> > +                 _mesa_get_format_name(tex_image->TexFormat));
> > +      return MESA_FORMAT_NONE;
> > +   }
> > +
> > +   return src_mesa_format;
> > +}
> > +
> > +bool
> > +intel_texsubimage_gpu_copy(struct brw_context *brw, GLuint dims,
> > +                           struct gl_texture_image *tex_image,
> > +                           unsigned x, unsigned y, unsigned z,
> > +                           unsigned w, unsigned h, unsigned d,
> > +                           GLenum format, GLenum type, const void *pixels,
> > +                           const struct gl_pixelstore_attrib *packing)
> > +{
> > +   const bool is_src_bo = _mesa_is_bufferobj(packing->BufferObj);
> > +   struct intel_texture_image *intel_image = intel_texture_image(tex_image);
> > +
> > +   /* Make sure there is something to upload. */
> > +   if (pixels == NULL && !is_src_bo)
> > +      return false;
> > +
> > +   const mesa_format src_mesa_format = intel_texsubimage_check_upload(
> > +      brw, tex_image, h, format, type, packing);
> > +   if (src_mesa_format == MESA_FORMAT_NONE)
> > +      return MESA_FORMAT_NONE;
> return false ?

Oops, good catch!

> > +
> > +   const uint32_t offset = is_src_bo ?
> > +      intel_texsubimage_get_src_offset(dims, w, h, format, type, pixels,
> > +                                       packing) : 0;
> > +   const uint32_t stride = _mesa_image_row_stride(packing, w, format, type);
> > +   const unsigned level = tex_image->Level + tex_image->TexObject->MinLevel;
> > +   const unsigned start_layer =
> > +      tex_image->TexObject->MinLayer + tex_image->Face + z;
> > +
> > +   assert(level <= intel_image->mt->last_level);
> > +   assert(start_layer + d <= intel_image->mt->level[level].depth);
> > +
> > +   drm_intel_bo * const src_bo = is_src_bo ?
> > +      intel_buffer_object(packing->BufferObj)->buffer :
> > +      intel_texsubimage_get_src_as_bo(brw, dims, tex_image, w, h, d,
> > +                                      format, type, pixels, packing);
> > +   if (src_bo == NULL)
> > +      return false;
> > +
> > +   bool result = false;
> > +
> > +   /* Blit slice-by-slice creating a single-slice miptree for each layer. This
> > +    * way the alignment in the source buffer object does not need to meet the
> > +    * hw requirements.
> > +    */
> Can you explain this hw alignment requirement? This is for my understanding.

Good question. Even for linear (non-tiled) buffers I noticed by experimenting
that hardware wants to have individual slices of arrayed textures vertically
aligned by 4. However, for single slice the starting address doesn't need to
be aligned, and therefore offsetting to individual slices manually works.

> 
> > +   for (unsigned i = 0; i < d; ++i) {
> > +      /* Wrap the source buffer object with a miptree. */
> > +      struct intel_mipmap_tree *src_mt = intel_miptree_create_for_bo(
> > +                                            brw, src_bo, src_mesa_format,
> > +                                            offset + i * h * stride,
> > +                                            w, h, 1, 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 == intel_image->mt->format) {
> > +         brw_blorp_copy_miptrees(brw, src_mt, 0, 0,
> > +                                 intel_image->mt, level, start_layer + i,
> > +                                 0, 0, x, y, w, h);
> > +      } else {
> > +         brw_blorp_blit_miptrees(brw, src_mt, 0, 0,
> > +                                 src_mesa_format, SWIZZLE_XYZW,
> > +                                 intel_image->mt, level, start_layer + i,
> > +                                 intel_image->mt->format,
> > +                                 0, 0, w, h,
> > +                                 x, y, x + w, y + h,
> > +                                 GL_NEAREST, false, false, false, false);
> > +      }
> > +
> > +      intel_miptree_release(&src_mt);
> > +   }
> > +
> > +   result = true;
> > +
> > +err:
> > +   if (!is_src_bo)
> > +      drm_intel_bo_unreference(src_bo);
> > +
> > +   return result;
> > +}
> > +
> >  /**
> >   * \brief A fast path for glTexImage and glTexSubImage.
> >   *
> > --
> > 2.5.5
> >
> > _______________________________________________
> > 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