pan: change image2DMSArray lowering to use Z instead of Y

We used to lower multisampled arrays to 3D images by adjusting the
height and the Y coordinate so that addressing samples became
addressing into the new base image. This worked for gallium, but
was never implemented for vulkan, and also had the disadvantages
that (a) we handled arrays and non-arrays differently, and
(b) the image height was restricted to 4096.

Change this so that we lower samples into the Z coordinate instead,
adding new layers for each sample. This requires that we know the
number of samples (so we have to save a sysval for this in gallium)
but means that we handle arrays and non-arrays the same. More
importantly, we can fit 3 bits to indicate the number of samples
into the attribute descriptor in Vulkan, so this scheme works
there as well as in OpenGL.

Reviewed-by: Lars-Ivar Hesselberg Simonsen <lars-ivar.simonsen@arm.com>
Reviewed-by: Erik Faye-Lund <erik.faye-lund@collabora.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/40460>
This commit is contained in:
Eric R. Smith 2026-03-24 09:53:08 -03:00 committed by Marge Bot
parent 968b6896d5
commit a2e61ee1b9
5 changed files with 56 additions and 65 deletions

View file

@ -2187,18 +2187,9 @@ emit_image_bufs(struct panfrost_batch *batch, mesa_shader_stage shader,
cfg.slice_stride = slice_stride;
if (is_msaa) {
if (cfg.r_dimension == 1) {
/* regular multisampled images get the sample index in
the R dimension */
cfg.r_dimension = samples;
cfg.slice_stride = slice_stride / samples;
} else {
/* multisampled image arrays are emulated by making the
image "samples" times higher than the original image,
and fixing up the T coordinate by the sample number
to address the correct sample (on bifrost) */
cfg.t_dimension *= samples;
}
/* scale up the R dimension by the number of samples */
cfg.r_dimension *= samples;
cfg.slice_stride = slice_stride / samples;
}
}
}

View file

@ -307,16 +307,6 @@ dEQP-VK.api.device_init.create_device_global_priority_khr.basic,Fail
dEQP-VK.api.device_init.create_device_global_priority_query.basic,Fail
dEQP-VK.api.device_init.create_device_global_priority_query_khr.basic,Fail
# New with vk_clear
dEQP-VK.api.copy_and_blit.dedicated_allocation.resolve_image.whole_copy_before_resolving_no_cab.4_bit,Fail
dEQP-VK.api.copy_and_blit.dedicated_allocation.resolve_image.copy_with_regions_before_resolving.4_bit,Fail
dEQP-VK.api.copy_and_blit.core.resolve_image.whole_copy_before_resolving_no_cab.4_bit,Fail
dEQP-VK.api.copy_and_blit.core.resolve_image.whole_copy_before_resolving_no_cab.4_bit_bind_offset,Fail
dEQP-VK.api.copy_and_blit.core.resolve_image.copy_with_regions_before_resolving.4_bit,Fail
dEQP-VK.api.copy_and_blit.core.resolve_image.copy_with_regions_before_resolving.4_bit_bind_offset,Fail
dEQP-VK.api.copy_and_blit.copy_commands2.resolve_image.whole_copy_before_resolving_no_cab.4_bit,Fail
dEQP-VK.api.copy_and_blit.copy_commands2.resolve_image.copy_with_regions_before_resolving.4_bit,Fail
# New failures with VKCTS 1.4.4.0
dEQP-VK.binding_model.unused_invalid_descriptor.write.invalid.combined_image_sampler,Crash
dEQP-VK.binding_model.unused_invalid_descriptor.write.invalid.sampled_image,Crash

View file

@ -33,45 +33,27 @@ nir_lower_image_ms(nir_builder *b, nir_intrinsic_instr *intr,
nir_def *coord = intr->src[1].ssa;
nir_def *sample = nir_channel(b, intr->src[2].ssa, 0);
bool is_array = nir_intrinsic_image_array(intr);
if (nir_intrinsic_image_array(intr)) {
/* Unlike textures, images only embed a single LOD, hence the zero. */
nir_def *lod = nir_imm_int(b, 0);
nir_def *img_size =
img_deref ? nir_image_deref_size(b, 3, 32, intr->src[0].ssa, lod) :
nir_image_size(b, 3, 32, intr->src[0].ssa, lod,
.image_array = true, .image_dim = GLSL_SAMPLER_DIM_MS);
nir_def *img_height = nir_channel(b, img_size, 1);
nir_def *y_coord = nir_channel(b, coord, 1);
nir_def *z_coord = nir_channel(b, coord, 2);
nir_def *img_samples =
img_deref ?
nir_image_deref_samples(b, 32, intr->src[0].ssa, .image_array = is_array,
.image_dim = GLSL_SAMPLER_DIM_MS) :
nir_image_samples(b, 32, intr->src[0].ssa, .image_array = is_array,
.image_dim = GLSL_SAMPLER_DIM_MS);
/* With image2DMSArray, the Z coord is already used to index the array. We
* assume sample planes are adjacent and patch the Y coordinate to address
* the right sample plane. This means our image height is effectively
* limited to 4k though.
*
* Note that we don't trust image intrinsic is_array information because
* arrays of size one are allowed, and we only get to know the actual
* image size at bind time.
*/
nir_def *is_array = nir_ugt_imm(b, nir_channel(b, img_size, 2), 1);
nir_def *z_coord = nir_channel(b, coord, 2);
y_coord = nir_bcsel(
b, is_array,
nir_iadd(b, nir_imul(b, img_height, sample), y_coord), y_coord);
z_coord = nir_bcsel(b, is_array, z_coord, sample);
coord = nir_vec4(b, nir_channel(b, coord, 0), y_coord, z_coord,
nir_channel(b, coord, 3));
nir_src_rewrite(&intr->src[1], coord);
} else {
/* image2DMS is treated by panfrost as if it were a 3D image, so
* the sample index is in src[2]. We need to put this into the coordinates
* in the Z component.
*/
nir_src_rewrite(&intr->src[1],
nir_vector_insert_imm(b, coord, sample, 2));
}
/* image2DMS is treated by panfrost as if it were a 3D image, so
* the sample index is in src[2]. We need to put this into the coordinates
* in the Z component. If there already was a Z component (i.e. an
* array index) then scale that by the number of samples and add it to
* the sample number. We've lowered image2DMSArray images to be 3D images
* with a larger Z.
*/
z_coord = nir_iadd(b, sample, nir_imul(b, z_coord, img_samples));
nir_src_rewrite(&intr->src[1],
nir_vector_insert_imm(b, coord, z_coord, 2));
nir_intrinsic_set_image_dim(intr, GLSL_SAMPLER_DIM_3D);
nir_intrinsic_set_image_array(intr, false);

View file

@ -261,11 +261,15 @@ prepare_attr_buf_descs(struct panvk_image_view *view)
? extent.depth
: (view->pview.last_layer - view->pview.first_layer + 1);
cfg.row_stride = slayout->tiled_or_linear.row_stride_B;
if (cfg.r_dimension > 1) {
if (cfg.r_dimension > 1 || nr_samples > 1) {
cfg.slice_stride = view->pview.dim == MALI_TEXTURE_DIMENSION_3D
? slayout->tiled_or_linear.surface_stride_B
: plane_layout->array_stride_B;
}
if (nr_samples > 1) {
cfg.r_dimension *= nr_samples;
cfg.slice_stride /= nr_samples;
}
}
}
#endif

View file

@ -651,7 +651,26 @@ load_img_size(nir_builder *b, nir_deref_instr *deref, enum glsl_sampler_dim dim,
/* The sizes are provided as 16-bit values with 1 subtracted so
* convert to 32-bit and add 1.
*/
return nir_iadd_imm(b, nir_u2u32(b, tex_sz), 1);
tex_sz = nir_iadd_imm(b, nir_u2u32(b, tex_sz), 1);
if (is_array && dim == GLSL_SAMPLER_DIM_MS) {
/* log2(sample_count) is placed into bits 7..9 of the pixel
* stride (see prepare_attr_buf_descs) which is stored at
* offset 8 in the attribute descriptor buffer
*/
nir_def *sample_count = load_resource_deref_desc(
b, deref, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, 8, 1, 32, ctx);
sample_count = nir_iand_imm(b, nir_ushr_imm(b, sample_count, 7),
BITFIELD_MASK(3));
/* the Z value was lowered by the number of samples so that
* we could make the multisampled array look like a 3D texture
* Undo that here so we get the correct size
*/
nir_def *z_val = nir_channel(b, tex_sz, 2);
z_val = nir_ushr(b, z_val, sample_count);
tex_sz = nir_vector_insert_imm(b, tex_sz, z_val, 2);
}
return tex_sz;
}
}
@ -706,12 +725,17 @@ load_img_samples(nir_builder *b, nir_deref_instr *deref,
assert(dim != GLSL_SAMPLER_DIM_BUF);
/* Sample count is stored in the image depth field.
* FIXME: This won't work for 2DMSArray images, but those are already
* broken. */
/* log2(sample_count) is placed into bits 7..9 of the pixel
* stride (see prepare_attr_buf_descs) which is stored at
* offset 8 in the attribute descriptor buffer
*/
nir_def *one = nir_imm_int(b, 1);
nir_def *sample_count = load_resource_deref_desc(
b, deref, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, 22, 1, 16, ctx);
return nir_iadd_imm(b, nir_u2u32(b, sample_count), 1);
b, deref, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, 8, 1, 32, ctx);
sample_count = nir_iand_imm(b, nir_ushr_imm(b, sample_count, 7),
BITFIELD_MASK(3));
return nir_ishl(b, one, sample_count);
}
static uint32_t