Mesa (master): pan/mdg: implement shader image instructions

GitLab Mirror gitlab-mirror at kemper.freedesktop.org
Wed Jan 27 12:52:33 UTC 2021


Module: Mesa
Branch: master
Commit: 8edccb7e8dd0dfc2e8b69ff158976eed0e90848f
URL:    http://cgit.freedesktop.org/mesa/mesa/commit/?id=8edccb7e8dd0dfc2e8b69ff158976eed0e90848f

Author: Italo Nicola <italonicola at collabora.com>
Date:   Fri Dec 11 23:35:21 2020 +0000

pan/mdg: implement shader image instructions

Implements load store opreations as midgard_op_ld_image_* and
midgard_op_st_image_*.

Implements midgard_op_lea_tex, which takes an image coordinate and
returns it's memory address.

Image atomics are implemented as a combination of midgard_op_lea_tex and
the usual midgard atomic opcodes.

Currently we don't support multisampled shader images.

Signed-off-by: Italo Nicola <italonicola at collabora.com>
Reviewed-by: Boris Brezillon <boris.brezillon at collabora.com>
Reviewed-by: Alyssa Rosenzweig <alyssa.rosenzweig at collabora.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/8066>

---

 src/panfrost/midgard/midgard.h         |   3 +
 src/panfrost/midgard/midgard_compile.c | 157 ++++++++++++++++++++++++++++++---
 src/panfrost/midgard/midgard_ops.c     |   1 +
 3 files changed, 149 insertions(+), 12 deletions(-)

diff --git a/src/panfrost/midgard/midgard.h b/src/panfrost/midgard/midgard.h
index 2eb50d76e21..955c172cbc9 100644
--- a/src/panfrost/midgard/midgard.h
+++ b/src/panfrost/midgard/midgard.h
@@ -418,6 +418,9 @@ typedef enum {
         /* Likewise packs from fp32 */
         midgard_op_pack_colour_32 = 0x0A,
 
+        /* Converts image/tex coordinates into mem address */
+        midgard_op_lea_tex = 0x0D,
+
         /* Unclear why this is on the L/S unit, but moves fp32 cube map
          * coordinates in r27 to its cube map texture coordinate destination
          * (e.g r29). */
diff --git a/src/panfrost/midgard/midgard_compile.c b/src/panfrost/midgard/midgard_compile.c
index bb1f4147bcf..dc6ab9aaf6c 100644
--- a/src/panfrost/midgard/midgard_compile.c
+++ b/src/panfrost/midgard/midgard_compile.c
@@ -143,6 +143,36 @@ M_LOAD(ld_color_buffer_as_fp32, nir_type_float32);
 M_STORE(st_vary_32, nir_type_uint32);
 M_LOAD(ld_cubemap_coords, nir_type_uint32);
 M_LOAD(ld_compute_id, nir_type_uint32);
+M_LOAD(ld_image_32f, nir_type_float32);
+M_LOAD(ld_image_16f, nir_type_float16);
+M_LOAD(ld_image_32u, nir_type_uint32);
+M_LOAD(ld_image_32i, nir_type_int32);
+M_STORE(st_image_32f, nir_type_float32);
+M_STORE(st_image_16f, nir_type_float16);
+M_STORE(st_image_32u, nir_type_uint32);
+M_STORE(st_image_32i, nir_type_int32);
+M_LOAD(lea_tex, nir_type_uint64);
+
+#define M_IMAGE(op) \
+static midgard_instruction \
+op ## _image(nir_alu_type type, unsigned val, unsigned address) \
+{ \
+        switch (type) { \
+        case nir_type_float32: \
+                 return m_ ## op ## _image_32f(val, address); \
+        case nir_type_float16: \
+                 return m_ ## op ## _image_16f(val, address); \
+        case nir_type_uint32: \
+                 return m_ ## op ## _image_32u(val, address); \
+        case nir_type_int32: \
+                 return m_ ## op ## _image_32i(val, address); \
+        default: \
+                 unreachable("Invalid image type"); \
+        } \
+}
+
+M_IMAGE(ld);
+M_IMAGE(st);
 
 static midgard_instruction
 v_branch(bool conditional, bool invert)
@@ -446,13 +476,20 @@ nir_is_non_scalar_swizzle(nir_alu_src *src, unsigned nr_components)
 
 #define ATOMIC_CASE_IMPL(ctx, instr, nir, op, is_shared) \
         case nir_intrinsic_##nir: \
-                emit_atomic(ctx, instr, is_shared, midgard_op_##op); \
+                emit_atomic(ctx, instr, is_shared, midgard_op_##op, ~0); \
                 break;
 
 #define ATOMIC_CASE(ctx, instr, nir, op) \
         ATOMIC_CASE_IMPL(ctx, instr, shared_atomic_##nir, atomic_##op, true); \
         ATOMIC_CASE_IMPL(ctx, instr, global_atomic_##nir, atomic_##op, false);
 
+#define IMAGE_ATOMIC_CASE(ctx, instr, nir, op) \
+        case nir_intrinsic_image_atomic_##nir: { \
+                midgard_instruction ins = emit_image_op(ctx, instr, true); \
+                emit_atomic(ctx, instr, false, midgard_op_atomic_##op, ins.dest); \
+                break; \
+        }
+
 #define ALU_CASE(nir, _op) \
 	case nir_op_##nir: \
 		op = midgard_alu_op_##_op; \
@@ -1160,21 +1197,27 @@ emit_global(
 }
 
 /* If is_shared is off, the only other possible value are globals, since
- * SSBO's are being lowered to globals through a NIR pass. */
+ * SSBO's are being lowered to globals through a NIR pass.
+ * `image_direct_address` should be ~0 when instr is not an image_atomic
+ * and the destination register of a lea_tex op when it is an image_atomic. */
 static void
 emit_atomic(
         compiler_context *ctx,
         nir_intrinsic_instr *instr,
         bool is_shared,
-        midgard_load_store_op op)
+        midgard_load_store_op op,
+        unsigned image_direct_address)
 {
-        unsigned bitsize = nir_src_bit_size(instr->src[1]);
         nir_alu_type type =
                 (op == midgard_op_atomic_imin || op == midgard_op_atomic_imax) ?
                 nir_type_int : nir_type_uint;
 
+        bool is_image = image_direct_address != ~0;
+
         unsigned dest = nir_dest_index(&instr->dest);
-        unsigned val = nir_src_index(ctx, &instr->src[1]);
+        unsigned val_src = is_image ? 3 : 1;
+        unsigned val = nir_src_index(ctx, &instr->src[val_src]);
+        unsigned bitsize = nir_src_bit_size(instr->src[val_src]);
         emit_explicit_constant(ctx, val, val);
 
         midgard_instruction ins = {
@@ -1188,14 +1231,15 @@ emit_atomic(
 
         nir_src *src_offset = nir_get_io_offset_src(instr);
 
-        /* cmpxchg takes an extra value in arg_2, so we don't use it for the offset */
         if (op == midgard_op_atomic_cmpxchg) {
-                unsigned addr = nir_src_index(ctx, src_offset);
+                for(unsigned i = 0; i < 2; ++i)
+                        ins.swizzle[1][i] = i;
 
-                ins.src[1] = addr;
-                ins.src_types[1] = nir_type_uint | nir_src_bit_size(*src_offset);
+                ins.src[1] = is_image ? image_direct_address : nir_src_index(ctx, src_offset);
+                ins.src_types[1] = nir_type_uint64;
 
-                unsigned xchg_val = nir_src_index(ctx, &instr->src[2]);
+                unsigned xchg_val_src = is_image ? 4 : 2;
+                unsigned xchg_val = nir_src_index(ctx, &instr->src[xchg_val_src]);
                 emit_explicit_constant(ctx, xchg_val, xchg_val);
 
                 ins.src[2] = val;
@@ -1204,9 +1248,16 @@ emit_atomic(
 
                 if (is_shared)
                         ins.load_store.arg_1 |= 0x6E;
-        } else {
+        } else if (is_image) {
+                for(unsigned i = 0; i < 2; ++i)
+                        ins.swizzle[2][i] = i;
+
+                ins.src[2] = image_direct_address;
+                ins.src_types[2] = nir_type_uint64;
+
+                ins.load_store.arg_1 |= 0x7E;
+        } else
                 mir_set_offset(ctx, &ins, src_offset, is_shared ? LDST_SHARED : LDST_GLOBAL);
-        }
 
         mir_set_intr_mask(&instr->instr, &ins, true);
 
@@ -1276,6 +1327,72 @@ emit_varying_read(
         emit_mir_instruction(ctx, ins);
 }
 
+
+/* If `is_atomic` is true, we emit a `lea_tex` since midgard doesn't not have special
+ * image_atomic opcodes. The caller can then use that address to emit a normal atomic opcode. */
+static midgard_instruction
+emit_image_op(compiler_context *ctx, nir_intrinsic_instr *instr, bool is_atomic)
+{
+        enum glsl_sampler_dim dim = nir_intrinsic_image_dim(instr);
+        unsigned nr_attr = ctx->stage == MESA_SHADER_VERTEX ?
+                util_bitcount64(ctx->nir->info.inputs_read) : 0;
+        unsigned nr_dim = glsl_get_sampler_dim_coordinate_components(dim);
+        bool is_array = nir_intrinsic_image_array(instr);
+        bool is_store = instr->intrinsic == nir_intrinsic_image_store;
+
+        /* TODO: MSAA */
+        assert(dim != GLSL_SAMPLER_DIM_MS && "MSAA'd images not supported");
+
+        unsigned coord_reg = nir_src_index(ctx, &instr->src[1]);
+        emit_explicit_constant(ctx, coord_reg, coord_reg);
+
+        nir_src *index = &instr->src[0];
+        bool is_direct = nir_src_is_const(*index);
+
+        /* For image opcodes, address is used as an index into the attribute descriptor */
+        unsigned address = nr_attr;
+        if (is_direct)
+                address += nir_src_as_uint(*index);
+
+        midgard_instruction ins;
+        if (is_store) { /* emit st_image_* */
+                unsigned val = nir_src_index(ctx, &instr->src[3]);
+                emit_explicit_constant(ctx, val, val);
+
+                nir_alu_type type = nir_intrinsic_src_type(instr);
+                ins = st_image(type, val, address);
+                nir_alu_type base_type = nir_alu_type_get_base_type(type);
+                ins.src_types[0] = base_type | nir_src_bit_size(instr->src[3]);
+        } else if (is_atomic) { /* emit lea_tex */
+                unsigned dest = make_compiler_temp_reg(ctx);
+                ins = m_lea_tex(dest, address);
+                ins.mask = mask_of(2); /* 64-bit memory address */
+        } else { /* emit ld_image_* */
+                nir_alu_type type = nir_intrinsic_dest_type(instr);
+                ins = ld_image(type, nir_dest_index(&instr->dest), address);
+                ins.mask = mask_of(nir_intrinsic_dest_components(instr));
+                ins.dest_type = type;
+        }
+
+        /* Coord reg */
+        ins.src[1] = coord_reg;
+        ins.src_types[1] = nir_type_uint16;
+        if (nr_dim == 3 || is_array) {
+                ins.load_store.arg_1 |= 0x20;
+        }
+
+        /* Image index reg */
+        if (!is_direct) {
+                ins.src[2] = nir_src_index(ctx, index);
+                ins.src_types[2] = nir_type_uint32;
+        } else
+                ins.load_store.arg_2 = 0x1E;
+
+        emit_mir_instruction(ctx, ins);
+
+        return ins;
+}
+
 static void
 emit_attr_read(
         compiler_context *ctx,
@@ -1524,6 +1641,11 @@ emit_intrinsic(compiler_context *ctx, nir_intrinsic_instr *instr)
                 break;
         }
 
+        case nir_intrinsic_image_load:
+        case nir_intrinsic_image_store:
+                emit_image_op(ctx, instr, false);
+                break;
+
         case nir_intrinsic_load_uniform:
         case nir_intrinsic_load_ubo:
         case nir_intrinsic_load_global:
@@ -1883,6 +2005,17 @@ emit_intrinsic(compiler_context *ctx, nir_intrinsic_instr *instr)
         ATOMIC_CASE(ctx, instr, umin, umin);
         ATOMIC_CASE(ctx, instr, xor, xor);
 
+        IMAGE_ATOMIC_CASE(ctx, instr, add, add);
+        IMAGE_ATOMIC_CASE(ctx, instr, and, and);
+        IMAGE_ATOMIC_CASE(ctx, instr, comp_swap, cmpxchg);
+        IMAGE_ATOMIC_CASE(ctx, instr, exchange, xchg);
+        IMAGE_ATOMIC_CASE(ctx, instr, imax, imax);
+        IMAGE_ATOMIC_CASE(ctx, instr, imin, imin);
+        IMAGE_ATOMIC_CASE(ctx, instr, or, or);
+        IMAGE_ATOMIC_CASE(ctx, instr, umax, umax);
+        IMAGE_ATOMIC_CASE(ctx, instr, umin, umin);
+        IMAGE_ATOMIC_CASE(ctx, instr, xor, xor);
+
         default:
                 fprintf(stderr, "Unhandled intrinsic %s\n", nir_intrinsic_infos[instr->intrinsic].name);
                 assert(0);
diff --git a/src/panfrost/midgard/midgard_ops.c b/src/panfrost/midgard/midgard_ops.c
index dd753ff8cef..34f49bec001 100644
--- a/src/panfrost/midgard/midgard_ops.c
+++ b/src/panfrost/midgard/midgard_ops.c
@@ -184,6 +184,7 @@ struct mir_ldst_op_props load_store_opcode_props[256] = {
         [midgard_op_unpack_colour] = {"unpack_colour", M32},
         [midgard_op_pack_colour] = {"pack_colour", M32},
         [midgard_op_pack_colour_32] = {"pack_colour_32", M32},
+        [midgard_op_lea_tex] = {"lea_tex", M32},
         [midgard_op_ld_cubemap_coords] = {"ld_cubemap_coords", M32},
         [midgard_op_ld_compute_id] = {"ld_compute_id", M32},
         [midgard_op_ldst_perspective_division_z] = {"ldst_perspective_division_z", M32},



More information about the mesa-commit mailing list