[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