From f406206fee342fec844350efdf40b8da71e9795e Mon Sep 17 00:00:00 2001 From: Faith Ekstrand Date: Thu, 7 Mar 2024 14:35:57 -0600 Subject: [PATCH] nil: Rework tiling calculations Instead of calling choose_tiling once per LOD, we now call it once at the top and then simply clamp at every LOD like the hardware does. This means all heuristic decisions get made up-front and the mip level walk simply emulates the hardware. Part-of: --- src/nouveau/nil/nil_image.c | 70 ++++++++++++++++++++++++++----------- src/nouveau/nil/nil_image.h | 1 + 2 files changed, 50 insertions(+), 21 deletions(-) diff --git a/src/nouveau/nil/nil_image.c b/src/nouveau/nil/nil_image.c index d296a7e767f..ebc6b2081e0 100644 --- a/src/nouveau/nil/nil_image.c +++ b/src/nouveau/nil/nil_image.c @@ -205,6 +205,31 @@ nil_tiling_extent_B(struct nil_tiling tiling) } } +/** Clamps the tiling to less than 2x the gven extent in each dimension + * + * This operation is done by the hardware at each LOD. + */ +static struct nil_tiling +nil_tiling_clamp(struct nil_tiling tiling, struct nil_extent4d extent_B) +{ + if (!tiling.is_tiled) + return tiling; + + const struct nil_extent4d extent_GOB = + nil_extent4d_B_to_GOB(extent_B, tiling.gob_height_8); + + tiling.y_log2 = MIN2(tiling.y_log2, util_logbase2_ceil(extent_GOB.h)); + tiling.z_log2 = MIN2(tiling.z_log2, util_logbase2_ceil(extent_GOB.d)); + + return tiling; +} + +static bool +nil_tiling_eq(struct nil_tiling a, struct nil_tiling b) +{ + return memcmp(&a, &b, sizeof(b)) == 0; +} + enum nil_sample_layout nil_choose_sample_layout(uint32_t samples) { @@ -220,7 +245,9 @@ nil_choose_sample_layout(uint32_t samples) } static struct nil_tiling -choose_tiling(struct nil_extent4d extent_B, +choose_tiling(struct nil_extent4d extent_px, + enum pipe_format format, + enum nil_sample_layout sample_layout, enum nil_image_usage_flags usage) { if (usage & NIL_IMAGE_USAGE_LINEAR_BIT) @@ -229,21 +256,17 @@ choose_tiling(struct nil_extent4d extent_B, struct nil_tiling tiling = { .is_tiled = true, .gob_height_8 = true, + .y_log2 = 5, + .z_log2 = 5, }; - const struct nil_extent4d extent_GOB = - nil_extent4d_B_to_GOB(extent_B, tiling.gob_height_8); - - const uint32_t height_log2 = util_logbase2_ceil(extent_GOB.height); - const uint32_t depth_log2 = util_logbase2_ceil(extent_GOB.depth); - - tiling.y_log2 = MIN2(height_log2, 5); - tiling.z_log2 = MIN2(depth_log2, 5); - if (usage & NIL_IMAGE_USAGE_2D_VIEW_BIT) tiling.z_log2 = 0; - return tiling; + const struct nil_extent4d extent_B = + nil_extent4d_px_to_B(extent_px, format, sample_layout); + + return nil_tiling_clamp(tiling, extent_B); } uint32_t @@ -490,22 +513,26 @@ nil_image_init(struct nv_device_info *dev, break; } + const enum nil_sample_layout sample_layout = + nil_choose_sample_layout(info->samples); + const struct nil_tiling tiling = + choose_tiling(info->extent_px, info->format, sample_layout, info->usage); + *image = (struct nil_image) { .dim = info->dim, .format = info->format, .extent_px = info->extent_px, - .sample_layout = nil_choose_sample_layout(info->samples), + .sample_layout = sample_layout, .num_levels = info->levels, }; uint64_t layer_size_B = 0; for (uint32_t l = 0; l < info->levels; l++) { struct nil_extent4d lvl_ext_B = image_level_extent_B(image, l); + if (tiling.is_tiled) { + struct nil_tiling lvl_tiling = nil_tiling_clamp(tiling, lvl_ext_B); + assert(l > 0 || nil_tiling_eq(tiling, lvl_tiling)); - /* Tiling is chosen per-level with LOD0 acting as a maximum */ - struct nil_tiling lvl_tiling = choose_tiling(lvl_ext_B, info->usage); - - if (lvl_tiling.is_tiled) { /* Align the size to tiles */ struct nil_extent4d lvl_tiling_ext_B = nil_tiling_extent_B(lvl_tiling); lvl_ext_B = nil_extent4d_align(lvl_ext_B, lvl_tiling_ext_B); @@ -525,7 +552,7 @@ nil_image_init(struct nv_device_info *dev, image->levels[l] = (struct nil_image_level) { .offset_B = layer_size_B, - .tiling = lvl_tiling, + .tiling = tiling, /* Row stride needs to be aligned to 128B for render to work */ .row_stride_B = align(lvl_ext_B.width, 128), }; @@ -533,13 +560,14 @@ nil_image_init(struct nv_device_info *dev, layer_size_B += nil_image_level_size_B(image, l); } - /* Align the image and array stride to a single level0 tile */ - image->align_B = nil_tiling_size_B(image->levels[0].tiling); + const uint32_t lvl0_tiling_size_B = + nil_tiling_size_B(image->levels[0].tiling); - /* I have no idea why but hardware seems to align layer strides */ - image->array_stride_B = (uint32_t)align64(layer_size_B, image->align_B); + /* The array stride has to be aligned to the size of a level 0 tile */ + image->array_stride_B = align(layer_size_B, lvl0_tiling_size_B); image->size_B = (uint64_t)image->array_stride_B * image->extent_px.a; + image->align_B = lvl0_tiling_size_B; if (image->levels[0].tiling.is_tiled) { image->tile_mode = (uint16_t)image->levels[0].tiling.y_log2 << 4 | diff --git a/src/nouveau/nil/nil_image.h b/src/nouveau/nil/nil_image.h index 431f549f4ac..ff627497225 100644 --- a/src/nouveau/nil/nil_image.h +++ b/src/nouveau/nil/nil_image.h @@ -109,6 +109,7 @@ struct nil_tiling { uint8_t y_log2:3; /**< log2 of the Y tile dimension in GOBs */ uint8_t z_log2:3; /**< log2 of the Z tile dimension in GOBs */ }; +static_assert(sizeof(struct nil_tiling) == 1, "This struct has no holes"); struct nil_image_init_info { enum nil_image_dim dim;