llvmpipe: Fix array mismatch when accessing shader images

The compiled image function is derived from the image view, which is
supposed to match what is declared in the shader, however we did fixups
for array targets that only had one layer, since pipe_shader_image
actually doesn't have a target (derived from the resource instead).
But this is not correct at least for vulkan, since then the layer
coord is completely ignored, so we never got OOB behavior wrt the
layer coord.
Use single_layer_view field in pipe_shader_image to denote non-array
targets (the GL state tracker uses this in a similar way already,
although llvmpipe ignored it).

Reviewed-by: Konstantin Seurer <konstantin.seurer@gmail.com>
Reviewed-by: Brian Paul <brian.paul@broadcom.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/36304>
This commit is contained in:
Roland Scheidegger
2025-07-22 18:01:56 +02:00
committed by Marge Bot
parent 5291eb9cd2
commit 5385624c6d
2 changed files with 34 additions and 1 deletions
@@ -126,7 +126,20 @@ llvmpipe_create_image_handle(struct pipe_context *pctx, const struct pipe_image_
state.static_state.pot_height = false;
state.static_state.pot_depth = false;
if (view->u.tex.first_layer == view->u.tex.last_layer) {
/*
* Rely on single_layer_view to distinguish array and non-array targets,
* since there's no target field in pipe_image_view, and there can
* be mismatch between resource and view.
* We cannot unconditionally demote array to non-array targets if there's
* only one layer, since we'd then ignore the layer coord completely and
* OOB behavior would be wrong.
*
* XXX shouldn't we do this in lp_sampler_static_texture_state_image()
* in the first place (there's more callers)?
*/
if (view->resource && llvmpipe_resource_is_texture(view->resource) &&
view->u.tex.single_layer_view &&
view->u.tex.first_layer == view->u.tex.last_layer) {
if (state.static_state.target == PIPE_TEXTURE_1D_ARRAY)
state.static_state.target = PIPE_TEXTURE_1D;
else if (state.static_state.target == PIPE_TEXTURE_2D_ARRAY ||
@@ -337,6 +337,26 @@ lvp_create_imageview(const struct lvp_image_view *iv, VkFormat plane_format, uns
if (view.resource->target == PIPE_TEXTURE_3D)
view.u.tex.is_2d_view_of_3d = true;
}
if (iv->vk.view_type == VK_IMAGE_VIEW_TYPE_1D ||
iv->vk.view_type == VK_IMAGE_VIEW_TYPE_2D) {
/*
* There's no target field in pipe_image_view, but
* there's a single_layer_view which the mesa state tracker
* uses for a similar purpose, although not exactly the same,
* here we just use it to indicate the view is of a non-array
* type.
* Note that the layered-ness must match between shader dcl
* and view (but not between view and resource).
* We ignore VK_IMAGE_VIEW_TYPE_CUBE here, should be fine
* since there's no difference in accessing cube and cube arrays
* (as layer and face combine into one var), and for size queries
* we fix up targets separately (always using array types).
*/
assert(view.u.tex.first_layer == view.u.tex.last_layer);
view.u.tex.single_layer_view = 1;
}
view.u.tex.level = iv->vk.base_mip_level;
return view;
}