[Mesa-dev] [PATCH 3/4] i965: Attempt to blit for larger textures
Ben Widawsky
ben at bwidawsk.net
Thu Feb 5 18:49:07 PST 2015
On Wed, Jan 14, 2015 at 10:42:01AM -0800, Jason Ekstrand wrote:
> On Tue, Jan 13, 2015 at 11:37 PM, Ben Widawsky <benjamin.widawsky at intel.com>
> wrote:
>
> > 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) {
> >
>
> Why are we going through all these hoops to avoid the adjustment? Does
> setting an offset cost us something we want to avoid? Also, I think the
> check above needs to check y2 not y1 because y2 is larger and will actually
> be the determining factor on whether or not we can blit.
> --Jason
>
I don't understand your y2 vs. y1 comment, can you elaborate a bit?
You're right that the check can go. Personally, I liked the clarity for the
common case, it's just offset, whereas when you remove the if it's like - where
did all this adjustment come from. Not sure how strongly you feel about it, I'm
willing to change it if you do feel strongly.
>
> > + 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 at lists.freedesktop.org
> > http://lists.freedesktop.org/mailman/listinfo/mesa-dev
> >
--
Ben Widawsky, Intel Open Source Technology Center
More information about the mesa-dev
mailing list