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

Topi Pohjolainen topi.pohjolainen at gmail.com
Tue Jan 31 16:13:45 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).

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 | 186 +++++++++++++++++++++++++
 2 files changed, 194 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 57c4c38..43e816b 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_fbo.h"
 #include "intel_tex.h"
 #include "intel_mipmap_tree.h"
@@ -44,6 +47,189 @@
 
 #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->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.5.5



More information about the mesa-dev mailing list