From 9b11552810a6839f3fd3da5f0ae94289174d006e Mon Sep 17 00:00:00 2001 From: Nanley Chery Date: Mon, 3 Nov 2025 13:18:07 -0500 Subject: [PATCH 1/3] intel/isl: Support MSAA in subimage range helper Prevents failures in the next commit with many multisampling tests, including piglit's: arb_framebuffer_srgb-blit renderbuffer linear_to_srgb upsample disabled clear -auto -fbo and dEQP's: dEQP-VK.pipeline.monolithic.multisample_with_fragment_shading_rate.std_sample_locations.draw.depth.samples_8.separate_renderpass_clear_image_same_pattern_secondary_cmd_buf_general_layout Fixes: 64ca8a3272e ("isl: Add a helper for calculating subimage memory ranges") Reviewed-by: Lionel Landwerlin --- src/intel/isl/isl.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/intel/isl/isl.c b/src/intel/isl/isl.c index 5986497b0f6..209d107243d 100644 --- a/src/intel/isl/isl.c +++ b/src/intel/isl/isl.c @@ -4724,7 +4724,17 @@ isl_surf_get_image_range_B_tile(const struct isl_surf *surf, /* We only consider one Z or array slice */ const uint32_t end_z_offset_el = start_z_offset_el; - const uint32_t end_array_slice = start_array_slice; + uint32_t end_array_slice = start_array_slice; + + /* Find the last sample */ + struct isl_tile_info tile_info; + isl_surf_get_tile_info(surf, &tile_info); + if (surf->msaa_layout == ISL_MSAA_LAYOUT_ARRAY) { + if (tile_info.logical_extent_el.a > 1) + end_array_slice += surf->samples - 1; + else + end_y_offset_el += (surf->samples - 1) * surf->array_pitch_el_rows; + } UNUSED uint32_t x_offset_el, y_offset_el, z_offset_el, array_slice; isl_tiling_get_intratile_offset_el(surf->tiling, surf->dim, @@ -4757,9 +4767,6 @@ isl_surf_get_image_range_B_tile(const struct isl_surf *surf, &z_offset_el, &array_slice); - struct isl_tile_info tile_info; - isl_surf_get_tile_info(surf, &tile_info); - /* We want the range we return to be exclusive but the tile containing the * last pixel (what we just calculated) is inclusive. Add one and round up * to the tile size. From 5e64f6795987f74a6be807f75ad6857d0b3274e4 Mon Sep 17 00:00:00 2001 From: Nanley Chery Date: Mon, 3 Nov 2025 08:05:33 -0500 Subject: [PATCH 2/3] intel/isl: Split surface size calculations in two The next patch will make use of image size functions that only operate on fully created images. pick Reviewed-by: Lionel Landwerlin --- src/intel/isl/isl.c | 121 ++++++++++++++++++++++++-------------------- 1 file changed, 65 insertions(+), 56 deletions(-) diff --git a/src/intel/isl/isl.c b/src/intel/isl/isl.c index 209d107243d..cb10eca8d12 100644 --- a/src/intel/isl/isl.c +++ b/src/intel/isl/isl.c @@ -3161,13 +3161,13 @@ isl_calc_row_pitch(const struct isl_device *dev, } static bool -isl_calc_size(const struct isl_device *dev, - const struct isl_surf_init_info *info, - const struct isl_tile_info *tile_info, - const struct isl_extent4d *phys_total_el, - uint32_t array_pitch_el_rows, - uint32_t row_pitch_B, - uint64_t *out_size_B) +isl_calc_initial_size(const struct isl_device *dev, + const struct isl_surf_init_info *info, + const struct isl_tile_info *tile_info, + const struct isl_extent4d *phys_total_el, + uint32_t array_pitch_el_rows, + uint32_t row_pitch_B, + uint64_t *out_size_B) { uint64_t size_B; if (tile_info->tiling == ISL_TILING_LINEAR) { @@ -3205,50 +3205,6 @@ isl_calc_size(const struct isl_device *dev, size_B = (uint64_t) total_h_tl * tile_info->phys_extent_B.height * row_pitch_B; - - /* Bspec 57340 (r59562): - * - * When allocating memory, MCS buffer size is extended by 4KB over - * its original calculated size. First 4KB page of the MCS is - * reserved for internal HW usage. - * - * Allocate an extra 4KB page reserved for hardware at the beginning of - * MCS buffer on Xe2. The start address of MCS is the head of the 4KB - * page. Any manipulation on the content of MCS should start after 4KB - * from the start address. - */ - if (dev->info->ver >= 20 && info->usage & ISL_SURF_USAGE_MCS_BIT) - size_B += 4096; - } - - /* If for some reason we can't support the appropriate tiling format and - * end up falling to linear or some other format, make sure the image size - * and alignment are aligned to the expected block size so we can at least - * do opaque binds. - */ - if (info->usage & ISL_SURF_USAGE_SPARSE_BIT) - size_B = isl_align(size_B, 64 * 1024); - - /* Pre-gfx9: from the Broadwell PRM Vol 5, Surface Layout: - * "In addition to restrictions on maximum height, width, and depth, - * surfaces are also restricted to a maximum size in bytes. This - * maximum is 2 GB for all products and all surface types." - * - * gfx9-10: from the Skylake PRM Vol 5, Maximum Surface Size in Bytes: - * "In addition to restrictions on maximum height, width, and depth, - * surfaces are also restricted to a maximum size of 2^38 bytes. - * All pixels within the surface must be contained within 2^38 bytes - * of the base address." - * - * gfx11+ platforms raised this limit to 2^44 bytes. - */ - uint64_t max_surface_B = 1ull << (ISL_GFX_VER(dev) >= 11 ? 44 : - ISL_GFX_VER(dev) >= 9 ? 38 : 31); - if (size_B > max_surface_B) { - return notify_failure( - info, - "calculated size (%"PRIu64"B) exceeds platform limit of %"PRIu64"B", - size_B, max_surface_B); } *out_size_B = size_B; @@ -3371,6 +3327,58 @@ isl_calc_base_alignment(const struct isl_device *dev, return base_alignment_B; } +static bool +isl_calc_final_size(const struct isl_device *dev, + const struct isl_surf_init_info *restrict info, + struct isl_surf *surf) +{ + /* If for some reason we can't support the appropriate tiling format and + * end up falling to linear or some other format, make sure the image size + * and alignment are aligned to the expected block size so we can at least + * do opaque binds. + */ + if (surf->usage & ISL_SURF_USAGE_SPARSE_BIT) + surf->size_B = isl_align(surf->size_B, 64 * 1024); + + /* Bspec 57340 (r59562): + * + * When allocating memory, MCS buffer size is extended by 4KB over + * its original calculated size. First 4KB page of the MCS is + * reserved for internal HW usage. + * + * Allocate an extra 4KB page reserved for hardware at the beginning of + * MCS buffer on Xe2. The start address of MCS is the head of the 4KB + * page. Any manipulation on the content of MCS should start after 4KB + * from the start address. + */ + if (dev->info->ver >= 20 && surf->usage & ISL_SURF_USAGE_MCS_BIT) + surf->size_B += 4096; + + /* Pre-gfx9: from the Broadwell PRM Vol 5, Surface Layout: + * "In addition to restrictions on maximum height, width, and depth, + * surfaces are also restricted to a maximum size in bytes. This + * maximum is 2 GB for all products and all surface types." + * + * gfx9-10: from the Skylake PRM Vol 5, Maximum Surface Size in Bytes: + * "In addition to restrictions on maximum height, width, and depth, + * surfaces are also restricted to a maximum size of 2^38 bytes. + * All pixels within the surface must be contained within 2^38 bytes + * of the base address." + * + * gfx11+ platforms raised this limit to 2^44 bytes. + */ + uint64_t max_surface_B = 1ull << (ISL_GFX_VER(dev) >= 11 ? 44 : + ISL_GFX_VER(dev) >= 9 ? 38 : 31); + if (surf->size_B > max_surface_B) { + return notify_failure( + info, + "calculated size (%"PRIu64"B) exceeds platform limit of %"PRIu64"B", + surf->size_B, max_surface_B); + } + + return true; +} + static bool isl_surf_init_s_with_tiling(const struct isl_device *dev, struct isl_surf *surf, @@ -3433,9 +3441,10 @@ isl_surf_init_s_with_tiling(const struct isl_device *dev, &phys_total_el, &row_pitch_B)) return false; - uint64_t size_B; - if (!isl_calc_size(dev, info, &tile_info, &phys_total_el, - array_pitch_el_rows, row_pitch_B, &size_B)) + uint64_t initial_size_B; + if (!isl_calc_initial_size(dev, info, &tile_info, &phys_total_el, + array_pitch_el_rows, row_pitch_B, + &initial_size_B)) return false; const uint32_t base_alignment_B = @@ -3455,7 +3464,7 @@ isl_surf_init_s_with_tiling(const struct isl_device *dev, .logical_level0_px = logical_level0_px, .phys_level0_sa = phys_level0_sa, - .size_B = size_B, + .size_B = initial_size_B, .alignment_B = base_alignment_B, .row_pitch_B = row_pitch_B, .array_pitch_el_rows = array_pitch_el_rows, @@ -3465,7 +3474,7 @@ isl_surf_init_s_with_tiling(const struct isl_device *dev, .usage = info->usage, }; - return true; + return isl_calc_final_size(dev, info, surf); } bool From d111ddf7041dc789aad4628ed8b3da8ef39dc38b Mon Sep 17 00:00:00 2001 From: Nanley Chery Date: Mon, 3 Nov 2025 08:05:33 -0500 Subject: [PATCH 3/3] intel/isl: Omit unused space when sizing mipmaps Some mipmapped surfaces contain unused space in the bottom right side of the mipmap. Omit as many unused tiles from that area as possible when computing the size of the surface. When running our Final Fantasy 14 dx11 trace on DG2, this saves 2MB on a 256x256x32 (3D) B8G8R8A8_UNORM image with 9 mip levels. Note that in addition to reducing memory usage, this change has a side effect of affecting tiling decisions. For example, when running the Total War Warhammer 3 trace on ICL, INTEL_DEBUG=isl emits the following information for a 4K x 4K, 3-level, R8G8B8A8_UNORM mipmap: * Omitted 64 4KB page(s) of padding. [...] tiling_flags=+Y0 * Omitted 64 4KB page(s) of padding. [...] tiling_flags=+icl-Yf * Omitted 256 4KB page(s) of padding. [...] tiling_flags=+icl-Ys * Saved 192 4KB page(s). [...] tiling_flags=+icl-Ys This demonstrates the two impacts: 1) ISL created three surfaces, and ultimately chose the Ys-tiled one due to the removal of padding resulting in a smaller image size. Without the removal, the Ys surface would have been the same size as the Y0 surface. With the removal, it is 768KB smaller. 2) The surface returned by ISL is 1MB smaller as a result of removing of the padding. Reviewed-by: Lionel Landwerlin --- src/intel/isl/isl.c | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/src/intel/isl/isl.c b/src/intel/isl/isl.c index cb10eca8d12..003dfc098f2 100644 --- a/src/intel/isl/isl.c +++ b/src/intel/isl/isl.c @@ -3332,6 +3332,38 @@ isl_calc_final_size(const struct isl_device *dev, const struct isl_surf_init_info *restrict info, struct isl_surf *surf) { + /* Remove extra padding if the row-pitch is flexible. A fixed row pitch + * could indicate that an image is being redescribed or imported/exported. + */ + if (info->row_pitch_B == 0) { + uint64_t end_tile_B_max = 0; + for (int lod = 0; lod < surf->levels; lod++) { + uint64_t start_tile_B, end_tile_B; + if (surf->dim == ISL_SURF_DIM_3D) { + int last_z = u_minify(surf->logical_level0_px.d, lod) - 1; + isl_surf_get_image_range_B_tile(surf, lod, 0, last_z, + &start_tile_B, &end_tile_B); + } else { + int last_layer = surf->logical_level0_px.a - 1; + isl_surf_get_image_range_B_tile(surf, lod, last_layer, 0, + &start_tile_B, &end_tile_B); + } + + end_tile_B_max = MAX2(end_tile_B_max, end_tile_B); + + /* There's no padding if this LOD has a pixel in the last tile. */ + if (end_tile_B_max == surf->size_B) + break; + } + + uint64_t padding_B = surf->size_B - end_tile_B_max; + if (padding_B > 0) { + print_info(info, "Omitted %ld 4KB page(s) of padding.", + padding_B / 4096); + surf->size_B = end_tile_B_max; + } + } + /* If for some reason we can't support the appropriate tiling format and * end up falling to linear or some other format, make sure the image size * and alignment are aligned to the expected block size so we can at least