panfrost: add support for image2DMSArray on bifrost

On bifrost we only can use 3 coordinates for images, but
image2DMSArray needs 4 (x, y, sample#, and array index).
We work around this by making the image nr_samples times
higher than the original image, using the Y coordinate to
address the sample plane. This limits the maximum image
height (to 4K pixels instead of 64K pixels in the 16 sample
case) but at least allows us to use the images.

Reviewed-by: Boris Brezillon <boris.brezillon@collabora.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/30521>
This commit is contained in:
Eric R. Smith 2024-08-23 07:19:34 -03:00 committed by Marge Bot
parent 3173b2c9b7
commit 9e04c0a818
2 changed files with 67 additions and 26 deletions

View file

@ -1850,29 +1850,34 @@ emit_image_bufs(struct panfrost_batch *batch, enum pipe_shader_type shader,
pan_pack(bufs + (i * 2) + 1, ATTRIBUTE_BUFFER_CONTINUATION_3D, cfg) {
unsigned level = image->u.tex.level;
unsigned r_dim;
unsigned samples = rsrc->image.layout.nr_samples;
if (is_3d) {
r_dim = u_minify(rsrc->base.depth0, level);
} else if (is_msaa) {
r_dim = u_minify(image->resource->nr_samples, level);
} else {
r_dim = image->u.tex.last_layer - image->u.tex.first_layer + 1;
}
cfg.s_dimension = u_minify(rsrc->base.width0, level);
cfg.t_dimension = u_minify(rsrc->base.height0, level);
cfg.r_dimension = r_dim;
cfg.r_dimension = is_3d ? u_minify(rsrc->image.layout.depth, level)
: (image->u.tex.last_layer - image->u.tex.first_layer + 1);
cfg.row_stride = rsrc->image.layout.slices[level].row_stride;
if (is_msaa) {
unsigned samples = rsrc->base.nr_samples;
cfg.slice_stride =
panfrost_get_layer_stride(&rsrc->image.layout, level) / samples;
} else if (rsrc->base.target != PIPE_TEXTURE_2D) {
if (cfg.r_dimension > 1) {
cfg.slice_stride =
panfrost_get_layer_stride(&rsrc->image.layout, level);
}
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 =
panfrost_get_layer_stride(&rsrc->image.layout, level) / 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;
}
}
}
}
}

View file

@ -32,12 +32,16 @@ static bool
nir_lower_image_ms(nir_builder *b, nir_intrinsic_instr *intr,
UNUSED void *data)
{
bool img_deref = false;
switch (intr->intrinsic) {
case nir_intrinsic_image_load:
case nir_intrinsic_image_deref_load:
case nir_intrinsic_image_store:
case nir_intrinsic_image_deref_store:
img_deref = true;
break;
case nir_intrinsic_image_texel_address:
case nir_intrinsic_image_load:
case nir_intrinsic_image_store:
break;
default:
return false;
@ -49,17 +53,49 @@ nir_lower_image_ms(nir_builder *b, nir_intrinsic_instr *intr,
b->cursor = nir_before_instr(&intr->instr);
nir_def *coord = intr->src[1].ssa;
nir_def *index = intr->src[2].ssa;
nir_def *sample = nir_channel(b, intr->src[2].ssa, 0);
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);
/* 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);
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
*/
nir_src_rewrite(&intr->src[1],
nir_vector_insert_imm(b, coord,
nir_channel(b, index, 0),
2) );
nir_intrinsic_set_image_dim(intr, GLSL_SAMPLER_DIM_3D);
nir_intrinsic_set_image_array(intr, false);
return true;
}