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 <boris.brezillon@collabora.com>
Tested-by: Heiko Stuebner <heiko@sntech.de>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/34839>
This commit is contained in:
Lars-Ivar Hesselberg Simonsen 2025-05-06 14:22:54 +02:00 committed by Marge Bot
parent e2aa0b7566
commit 7451bc3bef
5 changed files with 162 additions and 43 deletions

View file

@ -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)

View file

@ -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,

View file

@ -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;

View file

@ -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
}
}

View file

@ -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)