[Mesa-dev] [PATCH 04/14] isl: Rework the way we define tile sizes.
Pohjolainen, Topi
topi.pohjolainen at intel.com
Mon Jul 11 15:28:32 UTC 2016
On Sat, Jul 09, 2016 at 12:17:21PM -0700, Jason Ekstrand wrote:
> This is based on a very long set of discussions between Chad and myself
> about how we should properly represent HiZ and CCS buffers. The end result
> of that discussion was that a tiling actually has two different sizes, a
> logical size in elements, and a physical size in bytes and rows. This
> commit reworks ISL's pitch and size calculations to work in terms of these
> two sizes.
> ---
> src/intel/isl/isl.c | 181 ++++++++++++++++++++++++++++++----------------------
> src/intel/isl/isl.h | 32 +++++++++-
> 2 files changed, 133 insertions(+), 80 deletions(-)
>
> diff --git a/src/intel/isl/isl.c b/src/intel/isl/isl.c
> index 6f57ac2..633bfdf 100644
> --- a/src/intel/isl/isl.c
> +++ b/src/intel/isl/isl.c
> @@ -111,30 +111,32 @@ isl_tiling_get_info(const struct isl_device *dev,
> struct isl_tile_info *tile_info)
> {
> const uint32_t bs = format_block_size;
> - uint32_t width, height;
> + struct isl_extent2d logical_el, phys_B;
>
> assert(bs > 0);
> + assert(tiling == ISL_TILING_LINEAR || isl_is_pow2(bs));
>
> switch (tiling) {
> case ISL_TILING_LINEAR:
> - width = 1;
> - height = 1;
> + logical_el = isl_extent2d(1, 1);
> + phys_B = isl_extent2d(bs, 1);
> break;
>
> case ISL_TILING_X:
> - width = 1 << 9;
> - height = 1 << 3;
Maybe:
assert(bs < 512);
> + logical_el = isl_extent2d(512 / bs, 8);
> + phys_B = isl_extent2d(512, 8);
> break;
>
> case ISL_TILING_Y0:
> - width = 1 << 7;
> - height = 1 << 5;
And:
assert(bs < 128);
> + logical_el = isl_extent2d(128 / bs, 32);
> + phys_B = isl_extent2d(128, 32);
> break;
>
> case ISL_TILING_W:
> /* XXX: Should W tile be same as Y? */
> - width = 1 << 6;
> - height = 1 << 6;
> + assert(bs == 1);
> + logical_el = isl_extent2d(64, 64);
> + phys_B = isl_extent2d(64, 64);
> break;
>
> case ISL_TILING_Yf:
> @@ -147,8 +149,11 @@ isl_tiling_get_info(const struct isl_device *dev,
>
> bool is_Ys = tiling == ISL_TILING_Ys;
>
> - width = 1 << (6 + (ffs(bs) / 2) + (2 * is_Ys));
> - height = 1 << (6 - (ffs(bs) / 2) + (2 * is_Ys));
> + unsigned width = 1 << (6 + (ffs(bs) / 2) + (2 * is_Ys));
> + unsigned height = 1 << (6 - (ffs(bs) / 2) + (2 * is_Ys));
These could be both 'const'.
> +
> + logical_el = isl_extent2d(width / bs, height);
> + phys_B = isl_extent2d(width, height);
> break;
> }
>
> @@ -158,9 +163,8 @@ isl_tiling_get_info(const struct isl_device *dev,
>
> *tile_info = (struct isl_tile_info) {
> .tiling = tiling,
> - .width = width,
> - .height = height,
> - .size = width * height,
> + .logical_extent_el = logical_el,
> + .phys_extent_B = phys_B,
> };
>
> return true;
> @@ -827,7 +831,7 @@ isl_calc_array_pitch_el_rows(const struct isl_device *dev,
> * Tile Mode != Linear: This field must be set to an integer multiple
> * of the tile height
> */
> - pitch_el_rows = isl_align(pitch_el_rows, tile_info->height);
> + pitch_el_rows = isl_align(pitch_el_rows, tile_info->logical_extent_el.height);
Looks like you are overflowing the line here.
> }
>
> return pitch_el_rows;
> @@ -837,11 +841,9 @@ isl_calc_array_pitch_el_rows(const struct isl_device *dev,
> * Calculate the pitch of each surface row, in bytes.
> */
> static uint32_t
> -isl_calc_row_pitch(const struct isl_device *dev,
> - const struct isl_surf_init_info *restrict info,
> - const struct isl_tile_info *tile_info,
> - const struct isl_extent3d *image_align_sa,
> - const struct isl_extent2d *phys_slice0_sa)
> +isl_calc_linear_row_pitch(const struct isl_device *dev,
> + const struct isl_surf_init_info *restrict info,
> + const struct isl_extent2d *phys_slice0_sa)
> {
> const struct isl_format_layout *fmtl = isl_format_get_layout(info->format);
>
> @@ -894,39 +896,26 @@ isl_calc_row_pitch(const struct isl_device *dev,
> assert(phys_slice0_sa->w % fmtl->bw == 0);
> row_pitch = MAX(row_pitch, fmtl->bs * (phys_slice0_sa->w / fmtl->bw));
>
> - switch (tile_info->tiling) {
> - case ISL_TILING_LINEAR:
> - /* From the Broadwel PRM >> Volume 2d: Command Reference: Structures >>
> - * RENDER_SURFACE_STATE Surface Pitch (p349):
> - *
> - * - For linear render target surfaces and surfaces accessed with the
> - * typed data port messages, the pitch must be a multiple of the
> - * element size for non-YUV surface formats. Pitch must be
> - * a multiple of 2 * element size for YUV surface formats.
> - *
> - * - [Requirements for SURFTYPE_BUFFER and SURFTYPE_STRBUF, which we
> - * ignore because isl doesn't do buffers.]
> - *
> - * - For other linear surfaces, the pitch can be any multiple of
> - * bytes.
> - */
> - if (info->usage & ISL_SURF_USAGE_RENDER_TARGET_BIT) {
> - if (isl_format_is_yuv(info->format)) {
> - row_pitch = isl_align_npot(row_pitch, 2 * fmtl->bs);
> - } else {
> - row_pitch = isl_align_npot(row_pitch, fmtl->bs);
> - }
> + /* From the Broadwel PRM >> Volume 2d: Command Reference: Structures >>
> + * RENDER_SURFACE_STATE Surface Pitch (p349):
> + *
> + * - For linear render target surfaces and surfaces accessed with the
> + * typed data port messages, the pitch must be a multiple of the
> + * element size for non-YUV surface formats. Pitch must be
> + * a multiple of 2 * element size for YUV surface formats.
> + *
> + * - [Requirements for SURFTYPE_BUFFER and SURFTYPE_STRBUF, which we
> + * ignore because isl doesn't do buffers.]
> + *
> + * - For other linear surfaces, the pitch can be any multiple of
> + * bytes.
> + */
> + if (info->usage & ISL_SURF_USAGE_RENDER_TARGET_BIT) {
> + if (isl_format_is_yuv(info->format)) {
> + row_pitch = isl_align_npot(row_pitch, 2 * fmtl->bs);
> + } else {
> + row_pitch = isl_align_npot(row_pitch, fmtl->bs);
> }
> - break;
> - default:
> - /* From the Broadwel PRM >> Volume 2d: Command Reference: Structures >>
> - * RENDER_SURFACE_STATE Surface Pitch (p349):
> - *
> - * - For tiled surfaces, the pitch must be a multiple of the tile
> - * width.
> - */
> - row_pitch = isl_align(row_pitch, tile_info->width);
> - break;
> }
>
> return row_pitch;
> @@ -1094,10 +1083,6 @@ isl_surf_init_s(const struct isl_device *dev,
> assert(phys_slice0_sa.w % fmtl->bw == 0);
> assert(phys_slice0_sa.h % fmtl->bh == 0);
>
> - const uint32_t row_pitch = isl_calc_row_pitch(dev, info, &tile_info,
> - &image_align_sa,
> - &phys_slice0_sa);
> -
> const uint32_t array_pitch_el_rows =
> isl_calc_array_pitch_el_rows(dev, info, &tile_info, dim_layout,
> array_pitch_span, &image_align_sa,
> @@ -1108,16 +1093,50 @@ isl_surf_init_s(const struct isl_device *dev,
> uint32_t pad_bytes;
> isl_apply_surface_padding(dev, info, &tile_info, &total_h_el, &pad_bytes);
>
> - /* Be sloppy. Align any leftover padding to a row boundary. */
> - total_h_el += isl_align_div_npot(pad_bytes, row_pitch);
> + uint32_t row_pitch, size, base_alignment;
> + if (tiling == ISL_TILING_LINEAR) {
> + row_pitch = isl_calc_linear_row_pitch(dev, info, &phys_slice0_sa);
> + size = row_pitch * total_h_el + pad_bytes;
>
> - const uint32_t size =
> - row_pitch * isl_align(total_h_el, tile_info.height);
> + /* From the Broadwell PRM Vol 2d, RENDER_SURFACE_STATE::SurfaceBaseAddress:
> + *
> + * "The Base Address for linear render target surfaces and surfaces
> + * accessed with the typed surface read/write data port messages must
> + * be element-size aligned, for non-YUV surface formats, or a
> + * multiple of 2 element-sizes for YUV surface formats. Other linear
> + * surfaces have no alignment requirements (byte alignment is
> + * sufficient.)"
> + */
> + base_alignment = MAX(1, info->min_alignment);
> + if (info->usage & ISL_SURF_USAGE_RENDER_TARGET_BIT) {
> + if (isl_format_is_yuv(info->format)) {
> + base_alignment = MAX(base_alignment, 2 * fmtl->bs);
> + } else {
> + base_alignment = MAX(base_alignment, fmtl->bs);
> + }
> + }
> + } else {
> + assert(phys_slice0_sa.w % fmtl->bw == 0);
> + const uint32_t total_w_el = phys_slice0_sa.width / fmtl->bw;
> + const uint32_t total_w_tl =
> + isl_align_div(total_w_el, tile_info.logical_extent_el.width);
> +
> + row_pitch = total_w_tl * tile_info.phys_extent_B.width;
> + if (row_pitch < info->min_pitch) {
> + row_pitch = isl_align(info->min_pitch, tile_info.phys_extent_B.width);
> + }
>
> - /* Alignment of surface base address, in bytes */
> - uint32_t base_alignment = MAX(1, info->min_alignment);
> - assert(isl_is_pow2(base_alignment) && isl_is_pow2(tile_info.size));
> - base_alignment = MAX(base_alignment, tile_info.size);
> + total_h_el += isl_align_div_npot(pad_bytes, row_pitch);
> + const uint32_t total_h_tl =
> + isl_align_div(total_h_el, tile_info.logical_extent_el.height);
> +
> + size = total_h_tl * tile_info.phys_extent_B.height * row_pitch;
> +
> + const uint32_t tile_size = tile_info.phys_extent_B.width *
> + tile_info.phys_extent_B.height;
> + assert(isl_is_pow2(info->min_alignment) && isl_is_pow2(tile_size));
> + base_alignment = MAX(info->min_alignment, tile_size);
> + }
>
> *surf = (struct isl_surf) {
> .dim = info->dim,
> @@ -1420,9 +1439,6 @@ isl_tiling_get_intratile_offset_el(const struct isl_device *dev,
> uint32_t *x_offset_el,
> uint32_t *y_offset_el)
> {
> - struct isl_tile_info tile_info;
> - isl_tiling_get_info(dev, tiling, bs, &tile_info);
> -
> /* This function only really works for power-of-two surfaces. In
> * theory, we could make it work for non-power-of-two surfaces by going
> * to the left until we find a block that is bs-aligned. The Vulkan
> @@ -1431,18 +1447,29 @@ isl_tiling_get_intratile_offset_el(const struct isl_device *dev,
> */
> assert(tiling == ISL_TILING_LINEAR || isl_is_pow2(bs));
>
> - uint32_t small_y_offset_el = total_y_offset_el % tile_info.height;
> - uint32_t big_y_offset_el = total_y_offset_el - small_y_offset_el;
> - uint32_t big_y_offset_B = big_y_offset_el * row_pitch;
> + if (tiling == ISL_TILING_LINEAR) {
> + *base_address_offset = total_y_offset_el * row_pitch +
> + total_x_offset_el * bs;
> + *x_offset_el = 0;
> + *y_offset_el = 0;
> + return;
> + }
> +
> + struct isl_tile_info tile_info;
> + isl_tiling_get_info(dev, tiling, bs, &tile_info);
> +
> + /* Compute the offset into the tile */
> + *x_offset_el = total_x_offset_el % tile_info.logical_extent_el.w;
> + *y_offset_el = total_y_offset_el % tile_info.logical_extent_el.h;
>
> - uint32_t total_x_offset_B = total_x_offset_el * bs;
> - uint32_t small_x_offset_B = total_x_offset_B % tile_info.width;
> - uint32_t small_x_offset_el = small_x_offset_B / bs;
> - uint32_t big_x_offset_B = (total_x_offset_B / tile_info.width) * tile_info.size;
> + /* Compute the offset of the tile in units of whole tiles */
> + uint32_t x_offset_tl = total_x_offset_el / tile_info.logical_extent_el.w;
> + uint32_t y_offset_tl = total_y_offset_el / tile_info.logical_extent_el.h;
>
> - *base_address_offset = big_y_offset_B + big_x_offset_B;
> - *x_offset_el = small_x_offset_el;
> - *y_offset_el = small_y_offset_el;
> + assert(row_pitch % tile_info.phys_extent_B.width == 0);
> + *base_address_offset =
> + y_offset_tl * tile_info.phys_extent_B.h * row_pitch +
> + x_offset_tl * tile_info.phys_extent_B.h * tile_info.phys_extent_B.w;
> }
>
> uint32_t
> diff --git a/src/intel/isl/isl.h b/src/intel/isl/isl.h
> index 985b605..6ec956b 100644
> --- a/src/intel/isl/isl.h
> +++ b/src/intel/isl/isl.h
> @@ -660,9 +660,28 @@ struct isl_format_layout {
>
> struct isl_tile_info {
> enum isl_tiling tiling;
> - uint32_t width; /**< in bytes */
> - uint32_t height; /**< in rows of memory */
> - uint32_t size; /**< in bytes */
> +
> + /** The logical size of the tile in units of surface elements
> + *
> + * This field determines how a given surface is cut up into tiles. It is
> + * used to compute the size of a surface in tiles and can be used to
> + * determine the location of the tile containing any given surface element.
> + * The exact value of this field depends heavily on the bits-per-block of
> + * the format being used.
> + */
> + struct isl_extent2d logical_extent_el;
> +
> + /** The physical size of the tile in bytes and rows of bytes
> + *
> + * This field determines how the tiles of a surface are physically layed
> + * out in memory. The logical and physical tile extent are frequently the
> + * same but this is not always the case. For instance, a W-tile (which is
> + * always used with ISL_FORMAT_R8) has a logical size of 64el x 64el but
> + * its physical size is 128B x 32rows, the same as a Y-tile.
> + *
> + * @see isl_surf::row_pitch
> + */
> + struct isl_extent2d phys_extent_B;
> };
>
> /**
> @@ -744,6 +763,13 @@ struct isl_surf {
>
> /**
> * Pitch between vertically adjacent surface elements, in bytes.
> + *
> + * For tiled surfaces, the interpretation of this value depends on the
> + * value of isl_tile_info::physical_extent_B. In particular, the distance
> + * in bytes between vertically adjacent tiles in the image is given by
> + * row_pitch * isl_tile_info::physical_extent_B.height.
> + *
> + * @see isl_tile_info::phys_extent_B;
> */
> uint32_t row_pitch;
>
> --
> 2.5.0.400.gff86faf
>
> _______________________________________________
> mesa-dev mailing list
> mesa-dev at lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/mesa-dev
More information about the mesa-dev
mailing list