From 5385624c6d00d911fd43f8246515c0f10ea98598 Mon Sep 17 00:00:00 2001 From: Roland Scheidegger Date: Tue, 22 Jul 2025 18:01:56 +0200 Subject: [PATCH] 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 Reviewed-by: Brian Paul Part-of: --- .../drivers/llvmpipe/lp_texture_handle.c | 15 +++++++++++++- src/gallium/frontends/lavapipe/lvp_image.c | 20 +++++++++++++++++++ 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/src/gallium/drivers/llvmpipe/lp_texture_handle.c b/src/gallium/drivers/llvmpipe/lp_texture_handle.c index 4e18d17447b..542a3e8703d 100644 --- a/src/gallium/drivers/llvmpipe/lp_texture_handle.c +++ b/src/gallium/drivers/llvmpipe/lp_texture_handle.c @@ -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 || diff --git a/src/gallium/frontends/lavapipe/lvp_image.c b/src/gallium/frontends/lavapipe/lvp_image.c index 5cf6aff111f..5935bb5c860 100644 --- a/src/gallium/frontends/lavapipe/lvp_image.c +++ b/src/gallium/frontends/lavapipe/lvp_image.c @@ -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; }