[Freedreno] [PATCH] ir3_compiler/nir: fix imageSize() for buffer-backed images

Eduardo Lima Mitev elima at igalia.com
Tue Oct 23 10:11:28 UTC 2018


GL_EXT_texture_buffer introduced texture buffers, which can be used
in shaders through a new type imageBuffer.

Because how image access is implemented in freedreno, calling
imageSize on an imageBuffer returns the size in bytes instead of texels,
which is incorrect.

This patch adds a division of imageSize result by the bytes-per-pixel
of the image format, when image is buffer-backed.

Fixes all tests under
dEQP-GLES31.functional.image_load_store.buffer.image_size.*
---
 .../drivers/freedreno/ir3/ir3_compiler_nir.c  | 34 +++++++++++++++++++
 1 file changed, 34 insertions(+)

diff --git a/src/gallium/drivers/freedreno/ir3/ir3_compiler_nir.c b/src/gallium/drivers/freedreno/ir3/ir3_compiler_nir.c
index 197196383b0..80ca2aa0161 100644
--- a/src/gallium/drivers/freedreno/ir3/ir3_compiler_nir.c
+++ b/src/gallium/drivers/freedreno/ir3/ir3_compiler_nir.c
@@ -2035,6 +2035,40 @@ emit_intrinsic_image_size(struct ir3_context *ctx, nir_intrinsic_instr *intr,
 
 	split_dest(b, tmp, sam, 0, 4);
 
+	/* get_size instruction returns size in bytes instead of texels
+	 * for imageBuffer, so we need to divide it by the pixel size
+	 * of the image format.
+	 *
+	 * TODO: This is at least true on a5xx. Check other gens.
+	 */
+	enum glsl_sampler_dim dim =
+		glsl_get_sampler_dim(glsl_without_array(var->type));
+	if (dim == GLSL_SAMPLER_DIM_BUF) {
+		/* The image format's bytes-per-pixel should have been
+		 * emitted as part of shader constants. It is
+		 * the constant at offset 0 of image_dims. See
+		 * ir3_shader::emit_image_dims().
+		 */
+		unsigned cb = regid(ctx->so->constbase.image_dims, 0) +
+			ctx->so->const_layout.image_dims.off[var->data.driver_location];
+		struct ir3_instruction *aux = create_uniform(ctx, cb + 0);
+
+		/* Since all the possible values the divisor can take are [4, 8, 16],
+		 * all power-of-two, we implement the division as a shift-right
+		 * instruction. We just need the log2 of the divisor first.
+		 *
+		 * However, log2 instruction seems to operate only on a float
+		 * type reg, so we need to convert the reg to float,
+		 * perform the log2, and then convert the result back again
+		 * to integer for shift-right.
+		 */
+		aux = ir3_COV(b, aux, TYPE_S32, TYPE_F32);
+		aux = ir3_LOG2(b, aux, 0);
+		aux = ir3_COV(b, aux, TYPE_F32, TYPE_S32);
+
+		tmp[0] = ir3_SHR_B(b, tmp[0], 0, aux, 0);
+	}
+
 	for (unsigned i = 0; i < ncoords; i++)
 		dst[i] = tmp[i];
 
-- 
2.19.1



More information about the Freedreno mailing list