diff --git a/src/broadcom/vulkan/v3dv_image.c b/src/broadcom/vulkan/v3dv_image.c index 8e9227d4f96..5474d375744 100644 --- a/src/broadcom/vulkan/v3dv_image.c +++ b/src/broadcom/vulkan/v3dv_image.c @@ -70,6 +70,27 @@ v3d_get_ub_pad(uint32_t cpp, uint32_t height) return 0; } +/** + * Computes the dimension with required padding for mip levels. + * + * This padding is required for width and height dimensions when the mip + * level is greater than 1, and for the depth dimension when the mip level + * is greater than 0. This function expects to be passed a mip level >= 1. + * + * Note: Hardware documentation seems to suggest that the third argument + * should be the utile dimensions, but through testing it was found that + * the block dimension should be used instead. + */ +static uint32_t +v3d_get_dimension_mpad(uint32_t dimension, uint32_t level, uint32_t block_dimension) +{ + assert(level >= 1); + uint32_t pot_dim = u_minify(dimension, 1); + pot_dim = util_next_power_of_two(DIV_ROUND_UP(pot_dim, block_dimension)); + uint32_t padded_dim = block_dimension * pot_dim; + return u_minify(padded_dim, level - 1); +} + static void v3d_setup_plane_slices(struct v3dv_image *image, uint8_t plane, uint32_t plane_offset) @@ -82,15 +103,6 @@ v3d_setup_plane_slices(struct v3dv_image *image, uint8_t plane, uint32_t height = image->planes[plane].height; uint32_t depth = image->vk.extent.depth; - /* Note that power-of-two padding is based on level 1. These are not - * equivalent to just util_next_power_of_two(dimension), because at a - * level 0 dimension of 9, the level 1 power-of-two padded value is 4, - * not 8. - */ - uint32_t pot_width = 2 * util_next_power_of_two(u_minify(width, 1)); - uint32_t pot_height = 2 * util_next_power_of_two(u_minify(height, 1)); - uint32_t pot_depth = 2 * util_next_power_of_two(u_minify(depth, 1)); - uint32_t utile_w = v3d_utile_width(image->planes[plane].cpp); uint32_t utile_h = v3d_utile_height(image->planes[plane].cpp); uint32_t uif_block_w = utile_w * 2; @@ -99,6 +111,21 @@ v3d_setup_plane_slices(struct v3dv_image *image, uint8_t plane, uint32_t block_width = vk_format_get_blockwidth(image->vk.format); uint32_t block_height = vk_format_get_blockheight(image->vk.format); + /* Note that power-of-two padding is based on level 1. These are not + * equivalent to just util_next_power_of_two(dimension), because at a + * level 0 dimension of 9, the level 1 power-of-two padded value is 4, + * not 8. Additionally the pot padding is based on the block size. + */ + uint32_t pot_width = 2 * v3d_get_dimension_mpad(width, + 1, + block_width); + uint32_t pot_height = 2 * v3d_get_dimension_mpad(height, + 1, + block_height); + uint32_t pot_depth = 2 * v3d_get_dimension_mpad(depth, + 1, + 1); + assert(image->vk.samples == VK_SAMPLE_COUNT_1_BIT || image->vk.samples == VK_SAMPLE_COUNT_4_BIT); bool msaa = image->vk.samples != VK_SAMPLE_COUNT_1_BIT; @@ -138,16 +165,6 @@ v3d_setup_plane_slices(struct v3dv_image *image, uint8_t plane, level_width = DIV_ROUND_UP(level_width, block_width); level_height = DIV_ROUND_UP(level_height, block_height); - /* Converting to the block size may have made it so the level_width - * and level height are no longer a POT for mip levels > 1, therefore - * if this is a mip level greater than 1 we set level_width and - * level_height to the next power of two - */ - if (i > 1) { - level_width = util_next_power_of_two(level_width); - level_height = util_next_power_of_two(level_height); - } - if (!image->tiled) { slice->tiling = V3D_TILING_RASTER; if (image->vk.image_type == VK_IMAGE_TYPE_1D)