pan/lib: validate data_size_B in drivers

In order to be able to properly check for maxResourceSize on Vulkan, we
need to be able to report the size even for resources that overflow that
limit. Otherwise we end up failing to find a usable modifier rather than
properly report the problem to the application. This means we need to move
the check out of the mod-handler.

There's no need to validate the slice-stride. The reason is a little bit
complicated, but we have two possible cases:

1. V10 and before: the image-size and the slice-stride are both limited
   to UINT32_MAX. Since the image-size is always at least as large as the
   slice-stride, it's enough to check the image-stride.
2. V11 and later: 37 bits is large enough to store any valid
   slice-stride. The only way we could blow this one up, would be to
   pass out-of-range width or height, which is already either validated
   by higher-level logic (gallium) or UB (vulkan). This is important,
   because we don't have another mandate to reject large resources on
   Vulkan; we can only reject due to maxResourceSize, not an individual
   plane.

So let's move this out to the call-site. We don't need to do anything
for PanVK, becuase it already checks for maxResourceSize.

To keep the Gallium and Vulkan driver as similar as reasonably possible,
check against the whole resource even in Gallium, where we could have
gotten away with checking a plane at the time instead.

Reviewed-by: Boris Brezillon <boris.brezillon@collabora.com>
Reviewed-by: Lars-Ivar Hesselberg Simonsen <lars-ivar.simonsen@arm.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/40999>
This commit is contained in:
Erik Faye-Lund 2026-04-17 09:48:43 +02:00 committed by Marge Bot
parent 57a80ff78c
commit d76e4f6054
3 changed files with 46 additions and 39 deletions

View file

@ -85,6 +85,12 @@ panfrost_clear_render_target(struct pipe_context *pipe,
height);
}
static uint64_t
panfrost_max_res_size_b(unsigned arch)
{
return u_uintN_max(arch < 11 ? 32 : 48);
}
static bool
panfrost_resource_init_image(
struct pipe_screen *screen, struct panfrost_resource *rsc,
@ -111,22 +117,32 @@ panfrost_resource_init_image(
/* The rest of the resource planes will be initialized when we hit the first
* plane. */
if (plane_idx > 0 || format_plane_count == 1)
if (plane_idx > 0)
return true;
plane_idx = 1;
for (struct panfrost_resource *plane = pan_resource(rsc->base.next);
plane && plane_idx < ARRAY_SIZE(rsc->image.planes);
plane = pan_resource(plane->base.next))
rsc->image.planes[plane_idx++] = &plane->plane;
if (format_plane_count > 1) {
plane_idx = 1;
for (struct panfrost_resource *plane = pan_resource(rsc->base.next);
plane && plane_idx < ARRAY_SIZE(rsc->image.planes);
plane = pan_resource(plane->base.next))
rsc->image.planes[plane_idx++] = &plane->plane;
assert(plane_idx == util_format_get_num_planes(iprops->format));
assert(plane_idx == util_format_get_num_planes(iprops->format));
for (struct panfrost_resource *plane = pan_resource(rsc->base.next);
plane; plane = pan_resource(plane->base.next)) {
memcpy(plane->image.planes, rsc->image.planes, sizeof(plane->image.planes));
for (struct panfrost_resource *plane = pan_resource(rsc->base.next);
plane; plane = pan_resource(plane->base.next)) {
memcpy(plane->image.planes, rsc->image.planes, sizeof(plane->image.planes));
}
}
/* validate layout */
uint64_t res_size = 0;
for (uint32_t i = 0; i < util_format_get_num_planes(iprops->format); i++)
res_size += rsc->image.planes[i]->layout.data_size_B;
if (res_size > panfrost_max_res_size_b(dev->arch))
return false;
return true;
}

View file

@ -16,14 +16,6 @@
#include "util/format/u_format.h"
#if PAN_ARCH <= 10
#define MAX_SIZE_B u_uintN_max(32)
#define MAX_SLICE_STRIDE_B u_uintN_max(32)
#else
#define MAX_SIZE_B u_uintN_max(48)
#define MAX_SLICE_STRIDE_B u_uintN_max(37)
#endif
static bool
pan_mod_afbc_match(uint64_t mod)
{
@ -179,8 +171,7 @@ pan_mod_afbc_init_slice_layout(
slayout->afbc.surface_stride_B = surf_stride_B;
slayout->size_B = surf_stride_B * mip_extent_px.depth;
if (hdr_surf_size_B > UINT32_MAX || surf_stride_B > MAX_SLICE_STRIDE_B ||
slayout->size_B > MAX_SIZE_B)
if (hdr_surf_size_B > UINT32_MAX)
return false;
return true;
@ -427,11 +418,6 @@ pan_mod_afrc_init_slice_layout(
slayout->size_B =
surf_stride_B * aligned_extent_px.depth * props->nr_samples;
/* Make sure the stride/size fits in the descriptor fields. */
if (slayout->size_B > MAX_SIZE_B ||
slayout->tiled_or_linear.surface_stride_B > MAX_SLICE_STRIDE_B)
return false;
return true;
}
@ -571,11 +557,6 @@ pan_mod_u_tiled_init_slice_layout(
slayout->tiled_or_linear.surface_stride_B = surf_stride_B;
slayout->size_B = surf_stride_B * mip_extent_el.depth * props->nr_samples;
/* Make sure the stride/size fits in the descriptor fields. */
if (slayout->size_B > MAX_SIZE_B ||
slayout->tiled_or_linear.surface_stride_B > MAX_SLICE_STRIDE_B)
return false;
return true;
}
@ -620,10 +601,6 @@ pan_mod_interleaved_64k_init_slice_layout(
slayout->tiled_or_linear.row_stride_B = row_stride_B;
slayout->tiled_or_linear.surface_stride_B = surf_stride_B;
if (slayout->size_B > MAX_SIZE_B ||
slayout->tiled_or_linear.surface_stride_B > MAX_SLICE_STRIDE_B)
return false;
return true;
}
@ -802,11 +779,6 @@ pan_mod_linear_init_slice_layout(
(uint64_t)slayout->tiled_or_linear.row_stride_B * mip_extent_el.height;
surf_stride_B = ALIGN_POT(surf_stride_B, (uint64_t)align_mask + 1);
/* Surface stride is passed as a 32-bit unsigned integer to RT/ZS and texture
* descriptors, make sure it fits. */
if (surf_stride_B > MAX_SLICE_STRIDE_B)
return false;
slayout->tiled_or_linear.surface_stride_B = surf_stride_B;
slayout->size_B = surf_stride_B * mip_extent_el.depth * props->nr_samples;
return true;

View file

@ -249,6 +249,25 @@ layout_init(unsigned arch, const struct pan_image_props *props,
return true;
}
TEST(Layout, LargeImage)
{
struct pan_image_props p = {
.modifier = DRM_FORMAT_MOD_LINEAR,
.format = PIPE_FORMAT_R8G8B8A8_UNORM,
.extent_px = {
.width = 65536,
.height = 65536,
.depth = 1,
},
.nr_samples = 1,
.dim = MALI_TEXTURE_DIMENSION_2D,
.nr_slices = 1,
};
struct pan_image_layout l = {};
ASSERT_TRUE(layout_init(0, &p, 0, NULL, &l));
}
/* dEQP-GLES3.functional.texture.format.compressed.etc1_2d_pot */
TEST(Layout, ImplicitLayoutInterleavedETC2)
{