diff --git a/src/intel/isl/isl.c b/src/intel/isl/isl.c index 5986497b0f6..003dfc098f2 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,90 @@ 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) +{ + /* 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 + * 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 +3473,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 +3496,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 +3506,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 @@ -4724,7 +4765,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 +4808,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.