diff --git a/src/gallium/drivers/panfrost/pan_cmdstream.c b/src/gallium/drivers/panfrost/pan_cmdstream.c index e650b39dc2b..8047f26e3b2 100644 --- a/src/gallium/drivers/panfrost/pan_cmdstream.c +++ b/src/gallium/drivers/panfrost/pan_cmdstream.c @@ -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; + } + } } } } diff --git a/src/panfrost/util/pan_lower_image_ms.c b/src/panfrost/util/pan_lower_image_ms.c index e1ad3d593cd..c1585f1ecad 100644 --- a/src/panfrost/util/pan_lower_image_ms.c +++ b/src/panfrost/util/pan_lower_image_ms.c @@ -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; }