From 7451bc3bef0b983063cb996a25a06312a751ac9b Mon Sep 17 00:00:00 2001 From: Lars-Ivar Hesselberg Simonsen Date: Tue, 6 May 2025 14:22:54 +0200 Subject: [PATCH] panvk/v9+: Set up limited texture descs for storage use Storage access to images using LEA_TEX[_IMM] has limitations on some fields in the texture descriptors, making them incompatible with the descriptors required for texture access, specifically in the case non-zero levels. This change sets up two sets of texture descriptors for image views of storage images, then picks the correct one when writing the image view descriptors. Backport-to: 25.0 Backport-to: 25.1 Reviewed-by: Boris Brezillon Tested-by: Heiko Stuebner Part-of: --- src/panfrost/lib/pan_texture.c | 151 +++++++++++++----- src/panfrost/lib/pan_texture.h | 6 + src/panfrost/vulkan/panvk_image_view.h | 7 +- src/panfrost/vulkan/panvk_vX_descriptor_set.c | 10 +- src/panfrost/vulkan/panvk_vX_image_view.c | 31 ++++ 5 files changed, 162 insertions(+), 43 deletions(-) diff --git a/src/panfrost/lib/pan_texture.c b/src/panfrost/lib/pan_texture.c index 4abc42973ff..b80c11bcab3 100644 --- a/src/panfrost/lib/pan_texture.c +++ b/src/panfrost/lib/pan_texture.c @@ -733,6 +733,55 @@ GENX(panfrost_texture_afbc_reswizzle)(struct pan_image_view *iview) } #endif +static unsigned +panfrost_texture_get_array_size(const struct pan_image_view *iview) +{ + unsigned array_size = iview->last_layer - iview->first_layer + 1; + + /* If this is a cubemap, we expect the number of layers to be a multiple + * of 6. + */ + if (iview->dim == MALI_TEXTURE_DIMENSION_CUBE) { + assert(array_size % 6 == 0); + array_size /= 6; + } + + /* Multiplanar YUV textures require 2 surface descriptors. */ + if (panfrost_format_is_yuv(iview->format) && PAN_ARCH >= 9 && + pan_image_view_get_plane(iview, 1) != NULL) + array_size *= 2; + + return array_size; +} + +static struct panfrost_tex_extent +panfrost_texture_get_extent(const struct pan_image_view *iview, + const struct pan_image_layout *layout) +{ + if (iview->buf.size) + return panfrost_texture_buf_get_extent(iview, layout); + + struct panfrost_tex_extent extent; + extent.width = u_minify(layout->width, iview->first_level); + extent.height = u_minify(layout->height, iview->first_level); + extent.depth = u_minify(layout->depth, iview->first_level); + if (util_format_is_compressed(layout->format) && + !util_format_is_compressed(iview->format)) { + extent.width = + DIV_ROUND_UP(extent.width, util_format_get_blockwidth(layout->format)); + extent.height = DIV_ROUND_UP(extent.height, + util_format_get_blockheight(layout->format)); + extent.depth = + DIV_ROUND_UP(extent.depth, util_format_get_blockdepth(layout->format)); + assert(util_format_get_blockwidth(iview->format) == 1); + assert(util_format_get_blockheight(iview->format) == 1); + assert(util_format_get_blockheight(iview->format) == 1); + assert(iview->last_level == iview->first_level); + } + + return extent; +} + /* * Generates a texture descriptor. Ideally, descriptors are immutable after the * texture is created, so we can keep these hanging around in GPU memory in a @@ -751,9 +800,9 @@ GENX(panfrost_new_texture)(const struct pan_image_view *iview, util_format_description(iview->format); const struct pan_image *first_plane = pan_image_view_get_first_plane(iview); const struct pan_image_layout *layout = &first_plane->layout; + uint32_t mali_format = GENX(panfrost_format_from_pipe_format)(iview->format)->hw; - if (desc->layout == UTIL_FORMAT_LAYOUT_ASTC && iview->astc.narrow && desc->colorspace != UTIL_FORMAT_COLORSPACE_SRGB) { mali_format = MALI_PACK_FMT(RGBA8_UNORM, RGBA, L); @@ -761,43 +810,10 @@ GENX(panfrost_new_texture)(const struct pan_image_view *iview, panfrost_emit_texture_payload(iview, payload->cpu); - unsigned array_size = iview->last_layer - iview->first_layer + 1; + unsigned array_size = panfrost_texture_get_array_size(iview); - /* If this is a cubemap, we expect the number of layers to be a multiple - * of 6. - */ - if (iview->dim == MALI_TEXTURE_DIMENSION_CUBE) { - assert(array_size % 6 == 0); - array_size /= 6; - } - - /* Multiplanar YUV textures require 2 surface descriptors. */ - if (panfrost_format_is_yuv(iview->format) && PAN_ARCH >= 9 && - pan_image_view_get_plane(iview, 1) != NULL) - array_size *= 2; - - struct panfrost_tex_extent extent; - - if (iview->buf.size) { - extent = panfrost_texture_buf_get_extent(iview, layout); - } else { - extent.width = u_minify(layout->width, iview->first_level); - extent.height = u_minify(layout->height, iview->first_level); - extent.depth = u_minify(layout->depth, iview->first_level); - if (util_format_is_compressed(layout->format) && - !util_format_is_compressed(iview->format)) { - extent.width = DIV_ROUND_UP( - extent.width, util_format_get_blockwidth(layout->format)); - extent.height = DIV_ROUND_UP( - extent.height, util_format_get_blockheight(layout->format)); - extent.depth = DIV_ROUND_UP( - extent.depth, util_format_get_blockdepth(layout->format)); - assert(util_format_get_blockwidth(iview->format) == 1); - assert(util_format_get_blockheight(iview->format) == 1); - assert(util_format_get_blockheight(iview->format) == 1); - assert(iview->last_level == iview->first_level); - } - } + struct panfrost_tex_extent extent = + panfrost_texture_get_extent(iview, layout); pan_pack(out, TEXTURE, cfg) { cfg.dimension = iview->dim; @@ -830,6 +846,67 @@ GENX(panfrost_new_texture)(const struct pan_image_view *iview, } } +#if PAN_ARCH >= 9 +void +GENX(panfrost_new_storage_texture)(const struct pan_image_view *iview, + struct mali_texture_packed *out, + const struct panfrost_ptr *payload) +{ + const struct util_format_description *desc = + util_format_description(iview->format); + const struct pan_image *first_plane = pan_image_view_get_first_plane(iview); + const struct pan_image_layout *layout = &first_plane->layout; + + /* AFBC and AFRC cannot be used in storage operations. */ + assert(!drm_is_afbc(layout->modifier)); + assert(!drm_is_afrc(layout->modifier)); + + uint32_t mali_format = + GENX(panfrost_format_from_pipe_format)(iview->format)->hw; + if (desc->layout == UTIL_FORMAT_LAYOUT_ASTC && iview->astc.narrow && + desc->colorspace != UTIL_FORMAT_COLORSPACE_SRGB) { + mali_format = MALI_PACK_FMT(RGBA8_UNORM, RGBA, L); + } + + panfrost_emit_texture_payload(iview, payload->cpu); + + unsigned array_size = panfrost_texture_get_array_size(iview); + + struct panfrost_tex_extent extent = + panfrost_texture_get_extent(iview, layout); + + static const unsigned char rgba_swizzle[4] = { + PIPE_SWIZZLE_X, + PIPE_SWIZZLE_Y, + PIPE_SWIZZLE_Z, + PIPE_SWIZZLE_W, + }; + + pan_pack(out, TEXTURE, cfg) { + cfg.dimension = iview->dim; + cfg.format = mali_format; + cfg.width = extent.width; + cfg.height = extent.height; + if (iview->dim == MALI_TEXTURE_DIMENSION_3D) + cfg.depth = extent.depth; + else + cfg.sample_count = layout->nr_samples; + cfg.texel_interleave = (layout->modifier != DRM_FORMAT_MOD_LINEAR) || + util_format_is_compressed(iview->format); + cfg.levels = iview->last_level - iview->first_level + 1; + cfg.array_size = array_size; + + cfg.surfaces = payload->gpu; + + /* Requirements for storage image use. */ + cfg.minimum_lod = 0; + cfg.maximum_lod = 0; + cfg.minimum_level = 0; + cfg.swizzle = panfrost_translate_swizzle_4(rgba_swizzle); + } +} +#endif + #if PAN_ARCH >= 9 enum mali_afbc_compression_mode GENX(pan_afbc_compression_mode)(enum pipe_format format) diff --git a/src/panfrost/lib/pan_texture.h b/src/panfrost/lib/pan_texture.h index b57b4bd1bc8..11e3018d031 100644 --- a/src/panfrost/lib/pan_texture.h +++ b/src/panfrost/lib/pan_texture.h @@ -419,6 +419,12 @@ void GENX(panfrost_texture_afbc_reswizzle)(struct pan_image_view *iview); void GENX(panfrost_new_texture)(const struct pan_image_view *iview, struct mali_texture_packed *out, const struct panfrost_ptr *payload); + +#if PAN_ARCH >= 9 +void GENX(panfrost_new_storage_texture)(const struct pan_image_view *iview, + struct mali_texture_packed *out, + const struct panfrost_ptr *payload); +#endif #endif unsigned panfrost_get_layer_stride(const struct pan_image_layout *layout, diff --git a/src/panfrost/vulkan/panvk_image_view.h b/src/panfrost/vulkan/panvk_image_view.h index 07e22b86d9c..fb85e12a2aa 100644 --- a/src/panfrost/vulkan/panvk_image_view.h +++ b/src/panfrost/vulkan/panvk_image_view.h @@ -36,9 +36,10 @@ struct panvk_image_view { struct mali_texture_packed other_aspect_tex; } zs; }; - -#if PAN_ARCH <= 7 - /* Valhall passes a texture descriptor to the LEA_TEX instruction. */ +#if PAN_ARCH >= 9 + /* Valhall passes a limited texture descriptor to the LEA_TEX instruction */ + struct mali_texture_packed storage_tex[PANVK_MAX_PLANES]; +#else struct mali_attribute_buffer_packed img_attrib_buf[2]; #endif } descs; diff --git a/src/panfrost/vulkan/panvk_vX_descriptor_set.c b/src/panfrost/vulkan/panvk_vX_descriptor_set.c index 92232548e90..932839e0102 100644 --- a/src/panfrost/vulkan/panvk_vX_descriptor_set.c +++ b/src/panfrost/vulkan/panvk_vX_descriptor_set.c @@ -95,14 +95,18 @@ write_image_view_desc(struct panvk_descriptor_set *set, uint8_t plane_count = vk_format_get_plane_count(view->vk.format); for (uint8_t plane = 0; plane < plane_count; plane++) { struct panvk_subdesc_info subdesc = get_tex_subdesc_info(type, plane); -#if PAN_ARCH <= 7 +#if PAN_ARCH >= 9 + if (type == VK_DESCRIPTOR_TYPE_STORAGE_IMAGE) + write_desc(set, binding, elem, &view->descs.storage_tex[plane], + subdesc); + else + write_desc(set, binding, elem, &view->descs.tex[plane], subdesc); +#else if (type == VK_DESCRIPTOR_TYPE_STORAGE_IMAGE) write_desc(set, binding, elem, &view->descs.img_attrib_buf, NO_SUBDESC); else write_desc(set, binding, elem, &view->descs.tex[plane], subdesc); -#else - write_desc(set, binding, elem, &view->descs.tex[plane], subdesc); #endif } } diff --git a/src/panfrost/vulkan/panvk_vX_image_view.c b/src/panfrost/vulkan/panvk_vX_image_view.c index 2cb72a1f66c..177b3f95cbf 100644 --- a/src/panfrost/vulkan/panvk_vX_image_view.c +++ b/src/panfrost/vulkan/panvk_vX_image_view.c @@ -131,6 +131,15 @@ prepare_tex_descs(struct panvk_image_view *view) .size = tex_payload_size * (can_preload_other_aspect ? 2 : plane_count), }; +#if PAN_ARCH >= 9 + uint32_t storage_payload_size = 0; + if (view->vk.usage & VK_IMAGE_USAGE_STORAGE_BIT) { + /* We'll need a second set of Texture Descriptors for storage use. */ + storage_payload_size = tex_payload_size * plane_count; + alloc_info.size += storage_payload_size; + } +#endif + view->mem = panvk_pool_alloc_mem(&dev->mempools.rw, alloc_info); if (!panvk_priv_mem_host_addr(view->mem)) return panvk_error(dev, VK_ERROR_OUT_OF_DEVICE_MEMORY); @@ -140,6 +149,15 @@ prepare_tex_descs(struct panvk_image_view *view) .cpu = panvk_priv_mem_host_addr(view->mem), }; +#if PAN_ARCH >= 9 + struct panfrost_ptr storage_ptr = ptr; + if (view->vk.usage & VK_IMAGE_USAGE_STORAGE_BIT) { + uint32_t storage_payload_offset = alloc_info.size - storage_payload_size; + storage_ptr.gpu += storage_payload_offset; + storage_ptr.cpu += storage_payload_offset; + } +#endif + if (plane_count > 1) { memset(pview.planes, 0, sizeof(pview.planes)); @@ -152,12 +170,25 @@ prepare_tex_descs(struct panvk_image_view *view) pview.format = vk_format_to_pipe_format(plane_format); GENX(panfrost_new_texture)(&pview, &view->descs.tex[plane], &ptr); +#if PAN_ARCH >= 9 + if (view->vk.usage & VK_IMAGE_USAGE_STORAGE_BIT) { + GENX(panfrost_new_storage_texture)( + &pview, &view->descs.storage_tex[plane], &storage_ptr); + storage_ptr.cpu += tex_payload_size; + storage_ptr.gpu += tex_payload_size; + } +#endif ptr.cpu += tex_payload_size; ptr.gpu += tex_payload_size; } } else { GENX(panfrost_new_texture)(&pview, &view->descs.tex[0], &ptr); +#if PAN_ARCH >= 9 + if (view->vk.usage & VK_IMAGE_USAGE_STORAGE_BIT) + GENX(panfrost_new_storage_texture)(&pview, &view->descs.storage_tex[0], + &storage_ptr); +#endif } if (!can_preload_other_aspect)