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