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 <b...@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 _______________________________________________ mesa-dev mailing list mesa-dev@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/mesa-dev