From 911832e9cfac39a1bb160853c6302fd4adaceee0 Mon Sep 17 00:00:00 2001 From: Jason Ekstrand Date: Wed, 21 Feb 2018 16:04:32 -0800 Subject: [PATCH] intel/isl: Implement correct tile size calculations for Ys/Yf The tile size calculations use a clever bit of math to make them short and simple. We add unit tests to assert that they identically match the tables in the PRM. Reviewed-by: Topi Pohjolainen Reviewed-by: Lionel Landwerlin Reviewed-by: Nanley Chery Part-of: --- src/intel/isl/isl.c | 64 ++++++++++- src/intel/isl/isl_gfx12.c | 24 ++++- src/intel/isl/isl_gfx9.c | 86 ++------------- src/intel/isl/meson.build | 12 +++ src/intel/isl/tests/isl_tile_std_y_test.c | 170 ++++++++++++++++++++++++++++++ 5 files changed, 273 insertions(+), 83 deletions(-) create mode 100644 src/intel/isl/tests/isl_tile_std_y_test.c diff --git a/src/intel/isl/isl.c b/src/intel/isl/isl.c index 3055857..3857d39 100644 --- a/src/intel/isl/isl.c +++ b/src/intel/isl/isl.c @@ -507,13 +507,67 @@ isl_tiling_get_info(enum isl_tiling tiling, case ISL_TILING_ICL_Ys: { bool is_Ys = tiling == ISL_TILING_SKL_Ys || tiling == ISL_TILING_ICL_Ys; + assert(format_bpb >= 8); - assert(bs > 0); - unsigned width = 1 << (6 + (ffs(bs) / 2) + (2 * is_Ys)); - unsigned height = 1 << (6 - (ffs(bs) / 2) + (2 * is_Ys)); + switch (dim) { + case ISL_SURF_DIM_2D: + /* See the BSpec Memory Data Formats » Common Surface Formats » + * Surface Layout and Tiling [SKL+] » 2D Surfaces SKL+ » 2D/CUBE + * Alignment Requirement [SKL+] + * + * Or, look in the SKL PRM under Memory Views > Common Surface + * Formats > Surface Layout and Tiling > 2D Surfaces > 2D/CUBE + * Alignment Requirements. + */ + logical_el = (struct isl_extent4d) { + .w = 1 << (6 - ((ffs(format_bpb) - 4) / 2) + (2 * is_Ys)), + .h = 1 << (6 - ((ffs(format_bpb) - 3) / 2) + (2 * is_Ys)), + .d = 1, + .a = 1, + }; + + if (samples > 1 && tiling != ISL_TILING_SKL_Yf) { + /* SKL PRMs, Volume 5: Memory Views, 2D/CUBE Alignment + * Requirement: + * + * "For MSFMT_MSS type multi-sampled TileYS surfaces, the + * alignments given above must be divided by the appropriate + * value from the table below." + * + * The formulas below reproduce those values. + */ + if (msaa_layout == ISL_MSAA_LAYOUT_ARRAY) { + logical_el.w >>= (ffs(samples) - 0) / 2; + logical_el.h >>= (ffs(samples) - 1) / 2; + logical_el.a = samples; + } + } + break; + + case ISL_SURF_DIM_3D: + /* See the BSpec Memory Data Formats » Common Surface Formats » + * Surface Layout and Tiling [SKL+] » 3D Surfaces SKL+ » 3D Alignment + * Requirements [SKL+] + * + * Or, look in the SKL PRM under Memory Views > Common Surface + * Formats > Surface Layout and Tiling > 3D Surfaces > 3D Alignment + * Requirements. + */ + logical_el = (struct isl_extent4d) { + .w = 1 << (4 - ((ffs(format_bpb) - 2) / 3) + (2 * is_Ys)), + .h = 1 << (4 - ((ffs(format_bpb) - 4) / 3) + (1 * is_Ys)), + .d = 1 << (4 - ((ffs(format_bpb) - 3) / 3) + (1 * is_Ys)), + .a = 1, + }; + break; + default: + unreachable("Invalid dimension"); + } + + uint32_t tile_size_B = is_Ys ? (1 << 16) : (1 << 12); - logical_el = isl_extent4d(width / bs, height, 1, 1); - phys_B = isl_extent2d(width, height); + phys_B.w = logical_el.width * bs; + phys_B.h = tile_size_B / phys_B.w; break; } case ISL_TILING_64: diff --git a/src/intel/isl/isl_gfx12.c b/src/intel/isl/isl_gfx12.c index 215e901..ec4325d 100644 --- a/src/intel/isl/isl_gfx12.c +++ b/src/intel/isl/isl_gfx12.c @@ -220,7 +220,29 @@ isl_gfx12_choose_image_alignment_el(const struct isl_device *dev, return; } - if (isl_surf_usage_is_depth(info->usage)) { + if (isl_tiling_is_std_y(tiling)) { + /* From RENDER_SURFACE_STATE::SurfaceHorizontalAlignment, + * + * This field is ignored for Tile64 surface formats because horizontal + * alignment is always to the start of the next tile in that case. + * + * From RENDER_SURFACE_STATE::SurfaceQPitch, + * + * Because MSAA is only supported for Tile64, QPitch must also be + * programmed to an aligned tile boundary for MSAA surfaces. + * + * Images in this surface must be tile-aligned. The table on the Bspec + * page, "2D/CUBE Alignment Requirement", shows that the vertical + * alignment is also a tile height for non-MSAA as well. + */ + struct isl_tile_info tile_info; + isl_tiling_get_info(tiling, info->dim, msaa_layout, fmtl->bpb, + info->samples, &tile_info); + + *image_align_el = isl_extent3d(tile_info.logical_extent_el.w, + tile_info.logical_extent_el.h, + 1); + } else if (isl_surf_usage_is_depth(info->usage)) { /* The alignment parameters for depth buffers are summarized in the * following table: * diff --git a/src/intel/isl/isl_gfx9.c b/src/intel/isl/isl_gfx9.c index 4c22f60..75db0fd 100644 --- a/src/intel/isl/isl_gfx9.c +++ b/src/intel/isl/isl_gfx9.c @@ -25,78 +25,6 @@ #include "isl_gfx9.h" #include "isl_priv.h" -/** - * Calculate the surface's subimage alignment, in units of surface samples, - * for the standard tiling formats Yf and Ys. - */ -static void -gfx9_calc_std_image_alignment_sa(const struct isl_device *dev, - const struct isl_surf_init_info *restrict info, - enum isl_tiling tiling, - enum isl_msaa_layout msaa_layout, - struct isl_extent3d *align_sa) -{ - const struct isl_format_layout *fmtl = isl_format_get_layout(info->format); - - assert(isl_tiling_is_std_y(tiling)); - - const uint32_t bpb = fmtl->bpb; - const uint32_t is_Ys = tiling == ISL_TILING_SKL_Ys || - tiling == ISL_TILING_ICL_Ys; - - switch (info->dim) { - case ISL_SURF_DIM_1D: - /* See the Skylake BSpec > Memory Views > Common Surface Formats > Surface - * Layout and Tiling > 1D Surfaces > 1D Alignment Requirements. - */ - *align_sa = (struct isl_extent3d) { - .w = 1 << (12 - (ffs(bpb) - 4) + (4 * is_Ys)), - .h = 1, - .d = 1, - }; - return; - case ISL_SURF_DIM_2D: - /* See the Skylake BSpec > Memory Views > Common Surface Formats > - * Surface Layout and Tiling > 2D Surfaces > 2D/CUBE Alignment - * Requirements. - */ - *align_sa = (struct isl_extent3d) { - .w = 1 << (6 - ((ffs(bpb) - 4) / 2) + (4 * is_Ys)), - .h = 1 << (6 - ((ffs(bpb) - 3) / 2) + (4 * is_Ys)), - .d = 1, - }; - - if (is_Ys) { - /* FINISHME(chadv): I don't trust this code. Untested. */ - isl_finishme("%s:%s: [SKL+] multisample TileYs", __FILE__, __func__); - - switch (msaa_layout) { - case ISL_MSAA_LAYOUT_NONE: - case ISL_MSAA_LAYOUT_INTERLEAVED: - break; - case ISL_MSAA_LAYOUT_ARRAY: - align_sa->w >>= (ffs(info->samples) - 0) / 2; - align_sa->h >>= (ffs(info->samples) - 1) / 2; - break; - } - } - return; - - case ISL_SURF_DIM_3D: - /* See the Skylake BSpec > Memory Views > Common Surface Formats > Surface - * Layout and Tiling > 1D Surfaces > 1D Alignment Requirements. - */ - *align_sa = (struct isl_extent3d) { - .w = 1 << (4 - ((ffs(bpb) - 2) / 3) + (4 * is_Ys)), - .h = 1 << (4 - ((ffs(bpb) - 4) / 3) + (2 * is_Ys)), - .d = 1 << (4 - ((ffs(bpb) - 3) / 3) + (2 * is_Ys)), - }; - return; - } - - unreachable("bad isl_surface_type"); -} - void isl_gfx9_choose_image_alignment_el(const struct isl_device *dev, const struct isl_surf_init_info *restrict info, @@ -167,11 +95,15 @@ isl_gfx9_choose_image_alignment_el(const struct isl_device *dev, */ if (isl_tiling_is_std_y(tiling)) { - struct isl_extent3d image_align_sa; - gfx9_calc_std_image_alignment_sa(dev, info, tiling, msaa_layout, - &image_align_sa); - - *image_align_el = isl_extent3d_sa_to_el(info->format, image_align_sa); + /* Ys and Yf tiled images are aligned to the tile size */ + struct isl_tile_info tile_info; + isl_tiling_get_info(tiling, info->dim, msaa_layout, + fmtl->bpb, info->samples, &tile_info); + *image_align_el = (struct isl_extent3d) { + .w = tile_info.logical_extent_el.w, + .h = tile_info.logical_extent_el.h, + .d = tile_info.logical_extent_el.d, + }; return; } diff --git a/src/intel/isl/meson.build b/src/intel/isl/meson.build index c3816bd..682392b 100644 --- a/src/intel/isl/meson.build +++ b/src/intel/isl/meson.build @@ -186,4 +186,16 @@ if with_tests suite : ['intel'], protocol : 'gtest', ) + + test( + 'isl_tile_std_y', + executable( + 'isl_tile_std_y_test', + 'tests/isl_tile_std_y_test.c', + dependencies : dep_m, + include_directories : [inc_include, inc_src, inc_gallium, inc_intel], + link_with : [libisl, libintel_dev], + ), + suite : ['intel'], + ) endif diff --git a/src/intel/isl/tests/isl_tile_std_y_test.c b/src/intel/isl/tests/isl_tile_std_y_test.c new file mode 100644 index 0000000..83bd647 --- /dev/null +++ b/src/intel/isl/tests/isl_tile_std_y_test.c @@ -0,0 +1,170 @@ +/* + * Copyright 2018 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include +#include +#include +#include + +#include "isl/isl.h" + +// An asssert that works regardless of NDEBUG. +#define t_assert(cond) \ + do { \ + if (!(cond)) { \ + fprintf(stderr, "%s:%d: assertion failed\n", __FILE__, __LINE__); \ + abort(); \ + } \ + } while (0) + +static void +assert_tile_size(enum isl_tiling tiling, enum isl_surf_dim dim, + enum isl_msaa_layout msaa_layout, + uint32_t bpb, uint32_t samples, + uint32_t w, uint32_t h, uint32_t d, uint32_t a) +{ + struct isl_tile_info tile_info; + isl_tiling_get_info(tiling, dim, msaa_layout, bpb, samples, &tile_info); + + /* Sanity */ + t_assert(tile_info.tiling == tiling); + t_assert(tile_info.format_bpb == bpb); + + t_assert(tile_info.logical_extent_el.w == w); + t_assert(tile_info.logical_extent_el.h == h); + t_assert(tile_info.logical_extent_el.d == d); + t_assert(tile_info.logical_extent_el.a == a); + + bool is_Ys = tiling == ISL_TILING_SKL_Ys || + tiling == ISL_TILING_ICL_Ys; + uint32_t tile_size = is_Ys ? 64 * 1024 : 4 * 1024; + + assert(tile_size == tile_info.phys_extent_B.w * + tile_info.phys_extent_B.h); + + assert(tile_size == tile_info.logical_extent_el.w * + tile_info.logical_extent_el.h * + tile_info.logical_extent_el.d * + tile_info.logical_extent_el.a * + bpb / 8); +} + +static void +assert_2d_tile_size(enum isl_tiling tiling, uint32_t bpb, + uint32_t halign, uint32_t valign) +{ +#define ASSERT_2D(tiling, bpb, samples, w, h, a) \ + assert_tile_size(tiling, ISL_SURF_DIM_2D, ISL_MSAA_LAYOUT_ARRAY, \ + bpb, samples, w, h, 1, a) + + /* Single sampled */ + ASSERT_2D(tiling, bpb, 1, halign, valign, 1); + + /* Multisampled */ + if (tiling == ISL_TILING_SKL_Yf) { + ASSERT_2D(tiling, bpb, 2, halign, valign, 1); + ASSERT_2D(tiling, bpb, 4, halign, valign, 1); + ASSERT_2D(tiling, bpb, 8, halign, valign, 1); + ASSERT_2D(tiling, bpb, 16, halign, valign, 1); + } else { + /* For gfx9 Ys and for both Yf and Ys on gfx11, we have to divide the + * size by the number of samples. + */ + ASSERT_2D(tiling, bpb, 2, halign / 2, valign / 1, 2); + ASSERT_2D(tiling, bpb, 4, halign / 2, valign / 2, 4); + ASSERT_2D(tiling, bpb, 8, halign / 4, valign / 2, 8); + ASSERT_2D(tiling, bpb, 16, halign / 4, valign / 4, 16); + } + +#undef ASSERT_2D +} + +static void +test_2d_tile_dimensions() +{ + assert_2d_tile_size(ISL_TILING_SKL_Ys, 128, 64, 64); + assert_2d_tile_size(ISL_TILING_SKL_Ys, 64, 128, 64); + assert_2d_tile_size(ISL_TILING_SKL_Ys, 32, 128, 128); + assert_2d_tile_size(ISL_TILING_SKL_Ys, 16, 256, 128); + assert_2d_tile_size(ISL_TILING_SKL_Ys, 8, 256, 256); + + assert_2d_tile_size(ISL_TILING_SKL_Yf, 128, 16, 16); + assert_2d_tile_size(ISL_TILING_SKL_Yf, 64, 32, 16); + assert_2d_tile_size(ISL_TILING_SKL_Yf, 32, 32, 32); + assert_2d_tile_size(ISL_TILING_SKL_Yf, 16, 64, 32); + assert_2d_tile_size(ISL_TILING_SKL_Yf, 8, 64, 64); + + assert_2d_tile_size(ISL_TILING_ICL_Ys, 128, 64, 64); + assert_2d_tile_size(ISL_TILING_ICL_Ys, 64, 128, 64); + assert_2d_tile_size(ISL_TILING_ICL_Ys, 32, 128, 128); + assert_2d_tile_size(ISL_TILING_ICL_Ys, 16, 256, 128); + assert_2d_tile_size(ISL_TILING_ICL_Ys, 8, 256, 256); + + assert_2d_tile_size(ISL_TILING_ICL_Yf, 128, 16, 16); + assert_2d_tile_size(ISL_TILING_ICL_Yf, 64, 32, 16); + assert_2d_tile_size(ISL_TILING_ICL_Yf, 32, 32, 32); + assert_2d_tile_size(ISL_TILING_ICL_Yf, 16, 64, 32); + assert_2d_tile_size(ISL_TILING_ICL_Yf, 8, 64, 64); +} + +static void +test_3d_tile_dimensions() +{ +#define ASSERT_3D(tiling, bpb, halign, valign, dalign) \ + assert_tile_size(tiling, ISL_SURF_DIM_3D, ISL_MSAA_LAYOUT_ARRAY, \ + bpb, 1, halign, valign, dalign, 1) + + ASSERT_3D(ISL_TILING_SKL_Ys, 128, 16, 16, 16); + ASSERT_3D(ISL_TILING_SKL_Ys, 64, 32, 16, 16); + ASSERT_3D(ISL_TILING_SKL_Ys, 32, 32, 32, 16); + ASSERT_3D(ISL_TILING_SKL_Ys, 16, 32, 32, 32); + ASSERT_3D(ISL_TILING_SKL_Ys, 8, 64, 32, 32); + + ASSERT_3D(ISL_TILING_SKL_Yf, 128, 4, 8, 8); + ASSERT_3D(ISL_TILING_SKL_Yf, 64, 8, 8, 8); + ASSERT_3D(ISL_TILING_SKL_Yf, 32, 8, 16, 8); + ASSERT_3D(ISL_TILING_SKL_Yf, 16, 8, 16, 16); + ASSERT_3D(ISL_TILING_SKL_Yf, 8, 16, 16, 16); + + ASSERT_3D(ISL_TILING_ICL_Ys, 128, 16, 16, 16); + ASSERT_3D(ISL_TILING_ICL_Ys, 64, 32, 16, 16); + ASSERT_3D(ISL_TILING_ICL_Ys, 32, 32, 32, 16); + ASSERT_3D(ISL_TILING_ICL_Ys, 16, 32, 32, 32); + ASSERT_3D(ISL_TILING_ICL_Ys, 8, 64, 32, 32); + + ASSERT_3D(ISL_TILING_ICL_Yf, 128, 4, 8, 8); + ASSERT_3D(ISL_TILING_ICL_Yf, 64, 8, 8, 8); + ASSERT_3D(ISL_TILING_ICL_Yf, 32, 8, 16, 8); + ASSERT_3D(ISL_TILING_ICL_Yf, 16, 8, 16, 16); + ASSERT_3D(ISL_TILING_ICL_Yf, 8, 16, 16, 16); + +#undef ASSERT_3D +} + +int main(void) +{ + test_2d_tile_dimensions(); + test_3d_tile_dimensions(); + + return 0; +} -- 2.7.4