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

Topi Pohjolainen topi.pohjolainen at gmail.com
Mon Feb 27 19:02:22 UTC 2017


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.

CC: Kenneth Graunke <kenneth at whitecape.org>
CC: Anuj Phogat <anuj.phogat at gmail.com>
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 | 191 +++++++++++++++++++++++++
 2 files changed, 199 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 a2db953..91e49bc 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,9 +35,11 @@
 #include "main/enums.h"
 #include "drivers/common/meta.h"
 
+#include "brw_blorp.h"
 #include "brw_context.h"
 #include "intel_batchbuffer.h"
 #include "intel_fbo.h"
+#include "intel_buffer_objects.h"
 #include "intel_tex.h"
 #include "intel_mipmap_tree.h"
 #include "intel_blit.h"
@@ -44,6 +47,194 @@
 
 #define FILE_DEBUG_FLAG DEBUG_TEXTURE
 
+static drm_intel_bo *
+intel_texsubimage_get_src_as_bo(struct brw_context *brw, unsigned dims,
+                                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)
+{
+   if (brw->ctx._ImageTransferState)
+      return MESA_FORMAT_NONE;
+
+   if (packing->ImageHeight) {
+      perf_debug("intel_texsubimage: ImageHeight is not supported\n");
+      return MESA_FORMAT_NONE;
+   }
+
+   if (packing->SwapBytes || packing->LsbFirst || packing->Invert) {
+      perf_debug("intel_texsubimage: unsupported gl_pixelstore_attrib\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;
+   }
+
+   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 _mesa_tex_format_from_format_and_type(&brw->ctx, format, type);
+}
+
+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 false;
+
+   drm_intel_bo * const src_bo = is_src_bo ?
+      intel_buffer_object(packing->BufferObj)->buffer :
+      intel_texsubimage_get_src_as_bo(brw, dims, w, h, d, format, type,
+                                      pixels, packing);
+   if (src_bo == NULL)
+      return false;
+
+   const uint32_t offset = is_src_bo ?
+      intel_texsubimage_get_src_offset(dims, w, h, format, type, pixels,
+                                       packing) : 0;
+
+   /* Now that source is offset to correct starting point, adjust the
+    * given dimensions to treat 1D arrays as 2D.
+    */
+   if (tex_image->TexObject->Target == GL_TEXTURE_1D_ARRAY) {
+      assert(d == 1);
+      assert(z == 0);
+      d = h;
+      h = 1;
+      z = y;
+      y = 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);
+
+   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 < d; ++i) {
+      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.9.3



More information about the mesa-dev mailing list