[Mesa-dev] [PATCH 3/4] i965: Attempt to blit for larger textures

Ben Widawsky benjamin.widawsky at intel.com
Tue Jan 13 23:37:49 PST 2015


The blit engine is limited to 32Kx32K transfer. In cases where we have to fall
back to the blitter, and when trying to blit a slice of a 2d texture array, or
face of a cube map, we don't need to transfer the entire texture.

I doubt this patch will get exercised at this point since we'll always allocate
a linear BO for huge buffers. The next patch changes that.

v2: Fix NDEBUG warning

Signed-off-by: Ben Widawsky <ben at bwidawsk.net>
---
 src/mesa/drivers/dri/i965/intel_blit.c | 107 ++++++++++++++++++++++++++++++++-
 1 file changed, 105 insertions(+), 2 deletions(-)

diff --git a/src/mesa/drivers/dri/i965/intel_blit.c b/src/mesa/drivers/dri/i965/intel_blit.c
index 9500bd7..a56e394 100644
--- a/src/mesa/drivers/dri/i965/intel_blit.c
+++ b/src/mesa/drivers/dri/i965/intel_blit.c
@@ -130,6 +130,104 @@ set_blitter_tiling(struct brw_context *brw,
       ADVANCE_BATCH();                                                  \
    } while (0)
 
+
+/* Returns the height of the tiling format. This would be measured in scanlines
+ * (of pitch bytes) */
+static int
+tile_height(uint32_t tiling)
+{
+   const long PAGE_SIZE = sysconf(_SC_PAGE_SIZE);
+   switch (tiling) {
+   case I915_TILING_X:
+      return PAGE_SIZE / 512;
+   case I915_TILING_Y:
+      return PAGE_SIZE / 128;
+   case I915_TILING_NONE:
+   default:
+      unreachable("Helper function is only used for tiled surfaces\n");
+   }
+}
+
+/* This function returns the offset to be used by the blit operation. It may
+ * modify the y if the texture would otherwise fail to be able to perform a
+ * blit. The x offset will not need to change based on the computations made by
+ * this function.
+ *
+ * By the time we get to this function, the miptree creation code should have
+ * already determined it's possible to blit the texture, so there should never
+ * be a case where this function fails.
+ */
+static GLuint
+intel_miptree_get_adjusted_y_offset(struct intel_mipmap_tree *mt, int slice,
+                                    uint32_t *y)
+{
+   GLuint offset = mt->offset;
+
+   /* Convert an input number of rows: y into 2 values: an offset (page aligned
+    * in byte units), and the remaining rows of y. The resulting 2 values will
+    * be used as parameters for a blit operation [using the HW blit engine].
+    * They will therefore conform to whatever restrictions are needed.
+    *
+    * XXX: This code assumes that LOD0 is always guaranteed to be properly
+    * aligned for the blit operation. The round down only mutates y if the LOD
+    * being adjusted isn't tile aligned. In other words, if input y is pointing
+    * to LOD0 of a slice, the adjusted y should always be 0. Similarly if input
+    * y is pointing to another LOD, and the offset happens to be tile aligned, y
+    * will again be 0.
+    *
+    * The following diagram shows how the blit parameters are modified. In the
+    * example, is is trying to blit with LOD1 from slice[x] as a surface, and
+    * LOD1 is not properly tile aligned.  "TA" means tile aligned. The rectangle
+    * is the BO that contains the mipmaps. There may be an offset from the start
+    * of the BO to the first slice.
+    *
+    *                   INPUT                               OUTPUT
+    *   0    +---------------------------+
+    *        |                           |        +---------------------------+
+    * offset |  slice[0]...slice[x-2]    | offset |  +----------+             |
+    *        |                           |        |  |  lod0    | slice[x]    |
+    *   TA   |  +----------+             |        |  |          |             |
+    *        |  |  lod0    | slice[x-1]  |        |  +----------+             |
+    *        |  |          |             |  y---> |  +---+ +-+                |
+    *        |  +----------+             |        |  |   | +-+                |
+    *        |  +---+ +-+                |        |  +---+ *                  |
+    *        |  |   | +-+                |        |                           |
+    *        |  +---+ *                  |        |  slice[x+1]...            |
+    *        |                           |        +---------------------------+
+    *        |  // qpitch padding        |
+    *        |                           |
+    *   TA   |  +----------+             |
+    *        |  |  lod0    | slice[x]    |
+    *        |  |          |             |
+    *        |  +----------+             |
+    *  y---> |  +---+ +-+                |
+    *        |  |   | +-+                |
+    *        |  +---+ *                  |
+    *        |                           |
+    *        |  slice[x+1]...            |
+    *        +---------------------------+
+    */
+   if (slice > 0 && *y >= 32768) {
+      const long PAGE_MASK = sysconf(_SC_PAGE_SIZE) - 1;
+      (void) PAGE_MASK;
+
+      /* Since we need to output a page aligned offset, the original offset must
+       * also be page aligned. For tiled buffers, it always should be. */
+      assert((offset & PAGE_MASK) == 0);
+
+      /* Adjust the y value to pick the nearest tile aligned mipmap row */
+      unsigned tile_aligned_row = ROUND_DOWN_TO(*y, tile_height(mt->tiling));
+      *y -= tile_aligned_row;
+
+      /* Convert tiled aligned row to a byte offset for use by the blitter */
+      tile_aligned_row *= mt->pitch;
+      assert((tile_aligned_row & PAGE_MASK) == 0);
+      offset += tile_aligned_row;
+   }
+
+   return offset;
+}
+
 /**
  * Implements a rectangular block transfer (blit) of pixels between two
  * miptrees.
@@ -236,6 +334,11 @@ intel_miptree_blit(struct brw_context *brw,
    dst_x += dst_image_x;
    dst_y += dst_image_y;
 
+   GLuint src_offset = intel_miptree_get_adjusted_y_offset(src_mt, src_slice,
+                                                           &src_y);
+   GLuint dst_offset = intel_miptree_get_adjusted_y_offset(dst_mt, dst_slice,
+                                                           &dst_y);
+
    /* The blitter interprets the 16-bit destination x/y as a signed 16-bit
     * value. The values we're working with are unsigned, so make sure we don't
     * overflow.
@@ -249,10 +352,10 @@ intel_miptree_blit(struct brw_context *brw,
    if (!intelEmitCopyBlit(brw,
                           src_mt->cpp,
                           src_pitch,
-                          src_mt->bo, src_mt->offset,
+                          src_mt->bo, src_offset,
                           src_mt->tiling,
                           dst_mt->pitch,
-                          dst_mt->bo, dst_mt->offset,
+                          dst_mt->bo, dst_offset,
                           dst_mt->tiling,
                           src_x, src_y,
                           dst_x, dst_y,
-- 
2.2.1



More information about the mesa-dev mailing list