[Mesa-dev] [PATCH v3 06/12] i965/fs: Get rid of load/store_foo_indirect

Jason Ekstrand jason at jlekstrand.net
Tue Dec 8 13:46:23 PST 2015


---
 src/mesa/drivers/dri/i965/brw_fs.h       |   2 +-
 src/mesa/drivers/dri/i965/brw_fs_nir.cpp | 106 ++++++++++++++-----------------
 src/mesa/drivers/dri/i965/brw_nir.c      |  45 ++++++++++---
 3 files changed, 84 insertions(+), 69 deletions(-)

diff --git a/src/mesa/drivers/dri/i965/brw_fs.h b/src/mesa/drivers/dri/i965/brw_fs.h
index bca4589..b55589f 100644
--- a/src/mesa/drivers/dri/i965/brw_fs.h
+++ b/src/mesa/drivers/dri/i965/brw_fs.h
@@ -278,7 +278,7 @@ public:
                        unsigned stream_id);
    void emit_gs_thread_end();
    void emit_gs_input_load(const fs_reg &dst, const nir_src &vertex_src,
-                           const fs_reg &indirect_offset, unsigned imm_offset,
+                           unsigned base_offset, const nir_src &offset_src,
                            unsigned num_components);
    void emit_cs_terminate();
    fs_reg *emit_cs_local_invocation_id_setup();
diff --git a/src/mesa/drivers/dri/i965/brw_fs_nir.cpp b/src/mesa/drivers/dri/i965/brw_fs_nir.cpp
index 3754622..18c9d65 100644
--- a/src/mesa/drivers/dri/i965/brw_fs_nir.cpp
+++ b/src/mesa/drivers/dri/i965/brw_fs_nir.cpp
@@ -1603,29 +1603,31 @@ fs_visitor::emit_gs_vertex(const nir_src &vertex_count_nir_src,
 void
 fs_visitor::emit_gs_input_load(const fs_reg &dst,
                                const nir_src &vertex_src,
-                               const fs_reg &indirect_offset,
-                               unsigned imm_offset,
+                               unsigned base_offset,
+                               const nir_src &offset_src,
                                unsigned num_components)
 {
    struct brw_gs_prog_data *gs_prog_data = (struct brw_gs_prog_data *) prog_data;
 
+   nir_const_value *vertex_const = nir_src_as_const_value(vertex_src);
+   nir_const_value *offset_const = nir_src_as_const_value(offset_src);
+   const unsigned push_reg_count = gs_prog_data->base.urb_read_length * 8;
+
    /* Offset 0 is the VUE header, which contains VARYING_SLOT_LAYER [.y],
     * VARYING_SLOT_VIEWPORT [.z], and VARYING_SLOT_PSIZ [.w].  Only
     * gl_PointSize is available as a GS input, however, so it must be that.
     */
-   const bool is_point_size =
-      indirect_offset.file == BAD_FILE && imm_offset == 0;
-
-   nir_const_value *vertex_const = nir_src_as_const_value(vertex_src);
-   const unsigned push_reg_count = gs_prog_data->base.urb_read_length * 8;
+   const bool is_point_size = (base_offset == 0);
 
-   if (indirect_offset.file == BAD_FILE && vertex_const != NULL &&
-       4 * imm_offset < push_reg_count) {
-      imm_offset = 4 * imm_offset + vertex_const->u[0] * push_reg_count;
+   if (offset_const != NULL && vertex_const != NULL &&
+       4 * offset_const->u[0] < push_reg_count) {
+      int imm_offset = (base_offset + offset_const->u[0]) * 4 +
+                       vertex_const->u[0] * push_reg_count;
       /* This input was pushed into registers. */
       if (is_point_size) {
          /* gl_PointSize comes in .w */
-         bld.MOV(dst, fs_reg(ATTR, imm_offset + 3, dst.type));
+         assert(imm_offset == 0);
+         bld.MOV(dst, fs_reg(ATTR, 3, dst.type));
       } else {
          for (unsigned i = 0; i < num_components; i++) {
             bld.MOV(offset(dst, bld, i),
@@ -1683,21 +1685,21 @@ fs_visitor::emit_gs_input_load(const fs_reg &dst,
       }
 
       fs_inst *inst;
-      if (indirect_offset.file == BAD_FILE) {
+      if (offset_const) {
          /* Constant indexing - use global offset. */
          inst = bld.emit(SHADER_OPCODE_URB_READ_SIMD8, dst, icp_handle);
-         inst->offset = imm_offset;
+         inst->offset = base_offset + offset_const->u[0];
          inst->base_mrf = -1;
          inst->mlen = 1;
          inst->regs_written = num_components;
       } else {
          /* Indirect indexing - use per-slot offsets as well. */
-         const fs_reg srcs[] = { icp_handle, indirect_offset };
+         const fs_reg srcs[] = { icp_handle, get_nir_src(offset_src) };
          fs_reg payload = bld.vgrf(BRW_REGISTER_TYPE_UD, 2);
          bld.LOAD_PAYLOAD(payload, srcs, ARRAY_SIZE(srcs), 0);
 
          inst = bld.emit(SHADER_OPCODE_URB_READ_SIMD8_PER_SLOT, dst, payload);
-         inst->offset = imm_offset;
+         inst->offset = base_offset;
          inst->base_mrf = -1;
          inst->mlen = 2;
          inst->regs_written = num_components;
@@ -1763,17 +1765,12 @@ fs_visitor::nir_emit_gs_intrinsic(const fs_builder &bld,
               retype(fs_reg(brw_vec8_grf(2, 0)), BRW_REGISTER_TYPE_UD));
       break;
 
-   case nir_intrinsic_load_input_indirect:
    case nir_intrinsic_load_input:
       unreachable("load_input intrinsics are invalid for the GS stage");
 
-   case nir_intrinsic_load_per_vertex_input_indirect:
-      indirect_offset = retype(get_nir_src(instr->src[1]), BRW_REGISTER_TYPE_D);
-      /* fallthrough */
    case nir_intrinsic_load_per_vertex_input:
-      emit_gs_input_load(dest, instr->src[0],
-                         indirect_offset, instr->const_index[0],
-                         instr->num_components);
+      emit_gs_input_load(dest, instr->src[0], instr->const_index[0],
+                         instr->src[1], instr->num_components);
       break;
 
    case nir_intrinsic_emit_vertex_with_counter:
@@ -2106,8 +2103,6 @@ fs_visitor::nir_emit_intrinsic(const fs_builder &bld, nir_intrinsic_instr *instr
    if (nir_intrinsic_infos[instr->intrinsic].has_dest)
       dest = get_nir_dest(instr->dest);
 
-   bool has_indirect = false;
-
    switch (instr->intrinsic) {
    case nir_intrinsic_atomic_counter_inc:
    case nir_intrinsic_atomic_counter_dec:
@@ -2296,19 +2291,20 @@ fs_visitor::nir_emit_intrinsic(const fs_builder &bld, nir_intrinsic_instr *instr
       bld.MOV(retype(dest, BRW_REGISTER_TYPE_D), brw_imm_d(1));
       break;
 
-   case nir_intrinsic_load_uniform_indirect:
-      has_indirect = true;
-      /* fallthrough */
    case nir_intrinsic_load_uniform: {
       /* Offsets are in bytes but they should always be multiples of 4 */
       assert(instr->const_index[0] % 4 == 0);
-      assert(instr->const_index[1] % 4 == 0);
 
       fs_reg src(UNIFORM, instr->const_index[0] / 4, dest.type);
-      src.reg_offset = instr->const_index[1] / 4;
 
-      if (has_indirect)
+      nir_const_value *const_offset = nir_src_as_const_value(instr->src[0]);
+      if (const_offset) {
+         /* Offsets are in bytes but they should always be multiples of 4 */
+         assert(const_offset->u[0] % 4 == 0);
+         src.reg_offset = const_offset->u[0] / 4;
+      } else {
          src.reladdr = new(mem_ctx) fs_reg(get_nir_src(instr->src[0]));
+      }
 
       for (unsigned j = 0; j < instr->num_components; j++) {
          bld.MOV(offset(dest, bld, j), offset(src, bld, j));
@@ -2316,9 +2312,6 @@ fs_visitor::nir_emit_intrinsic(const fs_builder &bld, nir_intrinsic_instr *instr
       break;
    }
 
-   case nir_intrinsic_load_ubo_indirect:
-      has_indirect = true;
-      /* fallthrough */
    case nir_intrinsic_load_ubo: {
       nir_const_value *const_index = nir_src_as_const_value(instr->src[0]);
       fs_reg surf_index;
@@ -2346,24 +2339,24 @@ fs_visitor::nir_emit_intrinsic(const fs_builder &bld, nir_intrinsic_instr *instr
                                nir->info.num_ubos - 1);
       }
 
-      if (has_indirect) {
+      nir_const_value *const_offset = nir_src_as_const_value(instr->src[1]);
+      if (const_offset == NULL) {
          fs_reg base_offset = retype(get_nir_src(instr->src[1]),
                                      BRW_REGISTER_TYPE_D);
 
-         unsigned vec4_offset = instr->const_index[0];
          for (int i = 0; i < instr->num_components; i++)
             VARYING_PULL_CONSTANT_LOAD(bld, offset(dest, bld, i), surf_index,
-                                       base_offset, vec4_offset + i * 4);
+                                       base_offset, i * 4);
       } else {
          fs_reg packed_consts = vgrf(glsl_type::float_type);
          packed_consts.type = dest.type;
 
-         struct brw_reg const_offset_reg = brw_imm_ud(instr->const_index[0] & ~15);
+         struct brw_reg const_offset_reg = brw_imm_ud(const_offset->u[0] & ~15);
          bld.emit(FS_OPCODE_UNIFORM_PULL_CONSTANT_LOAD, packed_consts,
                   surf_index, const_offset_reg);
 
          for (unsigned i = 0; i < instr->num_components; i++) {
-            packed_consts.set_smear(instr->const_index[0] % 16 / 4 + i);
+            packed_consts.set_smear(const_offset->u[0] % 16 / 4 + i);
 
             /* The std140 packing rules don't allow vectors to cross 16-byte
              * boundaries, and a reg is 32 bytes.
@@ -2377,9 +2370,6 @@ fs_visitor::nir_emit_intrinsic(const fs_builder &bld, nir_intrinsic_instr *instr
       break;
    }
 
-   case nir_intrinsic_load_ssbo_indirect:
-      has_indirect = true;
-      /* fallthrough */
    case nir_intrinsic_load_ssbo: {
       assert(devinfo->gen >= 7);
 
@@ -2405,12 +2395,12 @@ fs_visitor::nir_emit_intrinsic(const fs_builder &bld, nir_intrinsic_instr *instr
                                nir->info.num_ssbos - 1);
       }
 
-      /* Get the offset to read from */
       fs_reg offset_reg;
-      if (has_indirect) {
-         offset_reg = get_nir_src(instr->src[1]);
+      nir_const_value *const_offset = nir_src_as_const_value(instr->src[1]);
+      if (const_offset) {
+         offset_reg = brw_imm_ud(const_offset->u[0]);
       } else {
-         offset_reg = brw_imm_ud(instr->const_index[0]);
+         offset_reg = get_nir_src(instr->src[1]);
       }
 
       /* Read the vector */
@@ -2425,9 +2415,6 @@ fs_visitor::nir_emit_intrinsic(const fs_builder &bld, nir_intrinsic_instr *instr
       break;
    }
 
-   case nir_intrinsic_load_input_indirect:
-      unreachable("Not allowed");
-      /* fallthrough */
    case nir_intrinsic_load_input: {
       fs_reg src;
       if (stage == MESA_SHADER_VERTEX) {
@@ -2437,15 +2424,16 @@ fs_visitor::nir_emit_intrinsic(const fs_builder &bld, nir_intrinsic_instr *instr
                       instr->const_index[0]);
       }
 
+      nir_const_value *const_offset = nir_src_as_const_value(instr->src[0]);
+      assert(const_offset && "Indirect input loads not allowed");
+      src = offset(src, bld, const_offset->u[0]);
+
       for (unsigned j = 0; j < instr->num_components; j++) {
          bld.MOV(offset(dest, bld, j), offset(src, bld, j));
       }
       break;
    }
 
-   case nir_intrinsic_store_ssbo_indirect:
-      has_indirect = true;
-      /* fallthrough */
    case nir_intrinsic_store_ssbo: {
       assert(devinfo->gen >= 7);
 
@@ -2472,7 +2460,7 @@ fs_visitor::nir_emit_intrinsic(const fs_builder &bld, nir_intrinsic_instr *instr
       fs_reg val_reg = get_nir_src(instr->src[0]);
 
       /* Writemask */
-      unsigned writemask = instr->const_index[1];
+      unsigned writemask = instr->const_index[0];
 
       /* Combine groups of consecutive enabled channels in one write
        * message. We use ffs to find the first enabled channel and then ffs on
@@ -2482,10 +2470,11 @@ fs_visitor::nir_emit_intrinsic(const fs_builder &bld, nir_intrinsic_instr *instr
       while (writemask) {
          unsigned first_component = ffs(writemask) - 1;
          unsigned length = ffs(~(writemask >> first_component)) - 1;
-         fs_reg offset_reg;
 
-         if (!has_indirect) {
-            offset_reg = brw_imm_ud(instr->const_index[0] + 4 * first_component);
+         fs_reg offset_reg;
+         nir_const_value *const_offset = nir_src_as_const_value(instr->src[2]);
+         if (const_offset) {
+            offset_reg = brw_imm_ud(const_offset->u[0] + 4 * first_component);
          } else {
             offset_reg = vgrf(glsl_type::uint_type);
             bld.ADD(offset_reg,
@@ -2506,14 +2495,15 @@ fs_visitor::nir_emit_intrinsic(const fs_builder &bld, nir_intrinsic_instr *instr
       break;
    }
 
-   case nir_intrinsic_store_output_indirect:
-      unreachable("Not allowed");
-      /* fallthrough */
    case nir_intrinsic_store_output: {
       fs_reg src = get_nir_src(instr->src[0]);
       fs_reg new_dest = offset(retype(nir_outputs, src.type), bld,
                                instr->const_index[0]);
 
+      nir_const_value *const_offset = nir_src_as_const_value(instr->src[1]);
+      assert(const_offset && "Indirect output stores not allowed");
+      new_dest = offset(new_dest, bld, const_offset->u[0]);
+
       for (unsigned j = 0; j < instr->num_components; j++) {
          bld.MOV(offset(new_dest, bld, j), offset(src, bld, j));
       }
diff --git a/src/mesa/drivers/dri/i965/brw_nir.c b/src/mesa/drivers/dri/i965/brw_nir.c
index d624703..14ad172 100644
--- a/src/mesa/drivers/dri/i965/brw_nir.c
+++ b/src/mesa/drivers/dri/i965/brw_nir.c
@@ -24,31 +24,49 @@
 #include "brw_nir.h"
 #include "brw_shader.h"
 #include "glsl/nir/glsl_to_nir.h"
+#include "glsl/nir/nir_builder.h"
 #include "program/prog_to_nir.h"
 
+struct remap_vs_attrs_state {
+   nir_builder b;
+   uint64_t inputs_read;
+};
+
 static bool
-remap_vs_attrs(nir_block *block, void *closure)
+remap_vs_attrs(nir_block *block, void *void_state)
 {
-   GLbitfield64 inputs_read = *((GLbitfield64 *) closure);
+   struct remap_vs_attrs_state *state = void_state;
 
-   nir_foreach_instr(block, instr) {
+   nir_foreach_instr_safe(block, instr) {
       if (instr->type != nir_instr_type_intrinsic)
          continue;
 
       nir_intrinsic_instr *intrin = nir_instr_as_intrinsic(instr);
 
-      /* We set EmitNoIndirect for VS inputs, so there are no indirects. */
-      assert(intrin->intrinsic != nir_intrinsic_load_input_indirect);
-
       if (intrin->intrinsic == nir_intrinsic_load_input) {
          /* Attributes come in a contiguous block, ordered by their
           * gl_vert_attrib value.  That means we can compute the slot
           * number for an attribute by masking out the enabled attributes
           * before it and counting the bits.
           */
-         int attr = intrin->const_index[0];
-         int slot = _mesa_bitcount_64(inputs_read & BITFIELD64_MASK(attr));
+         nir_const_value *const_offset = nir_src_as_const_value(intrin->src[0]);
+
+         /* We set EmitNoIndirect for VS inputs, so there are no indirects. */
+         assert(const_offset);
+
+         int attr = intrin->const_index[0] + const_offset->u[0];
+         int slot = _mesa_bitcount_64(state->inputs_read &
+                                      BITFIELD64_MASK(attr));
+
+         /* The NIR -> FS pass will just add the base and offset together, so
+          * there's no reason to keep them separate.  Just put it all in
+          * const_index[0] and set the offset src[0] to load_const(0).
+          */
          intrin->const_index[0] = 4 * slot;
+
+         state->b.cursor = nir_before_instr(&intrin->instr);
+         nir_instr_rewrite_src(&intrin->instr, &intrin->src[0],
+                               nir_src_for_ssa(nir_imm_int(&state->b, 0)));
       }
    }
    return true;
@@ -79,10 +97,17 @@ brw_nir_lower_inputs(nir_shader *nir,
           * key->inputs_read since the two are identical aside from Gen4-5
           * edge flag differences.
           */
-         GLbitfield64 inputs_read = nir->info.inputs_read;
+         struct remap_vs_attrs_state remap_state = {
+            .inputs_read = nir->info.inputs_read,
+         };
+
+         /* This pass needs actual constants */
+         nir_opt_constant_folding(nir);
+
          nir_foreach_overload(nir, overload) {
             if (overload->impl) {
-               nir_foreach_block(overload->impl, remap_vs_attrs, &inputs_read);
+               nir_builder_init(&remap_state.b, overload->impl);
+               nir_foreach_block(overload->impl, remap_vs_attrs, &remap_state);
             }
          }
       }
-- 
2.5.0.400.gff86faf



More information about the mesa-dev mailing list