nir: Add nir_load_interpolated_input lowering code.
authorKenneth Graunke <kenneth@whitecape.org>
Tue, 12 Jul 2016 08:46:53 +0000 (01:46 -0700)
committerKenneth Graunke <kenneth@whitecape.org>
Wed, 20 Jul 2016 18:01:00 +0000 (11:01 -0700)
Now nir_lower_io can optionally produce load_interpolated_input
and load_barycentric_* intrinsics for fragment shader inputs.

flat inputs continue using regular load_input.

v2: Use a nir_shader_compiler_options flag rather than ad-hoc boolean
    passing (in response to review feedback from Chris Forbes).

Signed-off-by: Kenneth Graunke <kenneth@whitecape.org>
Reviewed-by: Chris Forbes <chrisforbes@google.com>
Reviewed-by: Jason Ekstrand <jason@jlekstrand.net>
src/compiler/nir/nir.h
src/compiler/nir/nir_lower_io.c

index ac119981ec9922f305a997b0cc0a4f22213d94fd..2873c1529aaba0bbf637e7c7d951ff8870e5375c 100644 (file)
@@ -1699,6 +1699,14 @@ typedef struct nir_shader_compiler_options {
    bool vertex_id_zero_based;
 
    bool lower_cs_local_index_from_id;
+
+   /**
+    * Should nir_lower_io() create load_interpolated_input intrinsics?
+    *
+    * If not, it generates regular load_input intrinsics and interpolation
+    * information must be inferred from the list of input nir_variables.
+    */
+   bool use_interpolated_input_intrinsics;
 } nir_shader_compiler_options;
 
 typedef struct nir_shader_info {
index 9c1096179b165093789873dcfc58b78827a96735..4d191feb53ed6f3246918e07eb513e0aed416d2f 100644 (file)
@@ -171,14 +171,34 @@ static nir_intrinsic_instr *
 lower_load(nir_intrinsic_instr *intrin, struct lower_io_state *state,
            nir_ssa_def *vertex_index, nir_ssa_def *offset)
 {
+   const nir_shader *nir = state->builder.shader;
    nir_variable *var = intrin->variables[0]->var;
    nir_variable_mode mode = var->data.mode;
+   nir_ssa_def *barycentric = NULL;
 
    nir_intrinsic_op op;
    switch (mode) {
    case nir_var_shader_in:
-      op = vertex_index ? nir_intrinsic_load_per_vertex_input :
-                          nir_intrinsic_load_input;
+      if (nir->stage == MESA_SHADER_FRAGMENT &&
+          nir->options->use_interpolated_input_intrinsics &&
+          var->data.interpolation != INTERP_MODE_FLAT) {
+         assert(vertex_index == NULL);
+
+         nir_intrinsic_op bary_op;
+         if (var->data.sample)
+            bary_op = nir_intrinsic_load_barycentric_sample;
+         else if (var->data.centroid)
+            bary_op = nir_intrinsic_load_barycentric_centroid;
+         else
+            bary_op = nir_intrinsic_load_barycentric_pixel;
+
+         barycentric = nir_load_barycentric(&state->builder, bary_op,
+                                            var->data.interpolation);
+         op = nir_intrinsic_load_interpolated_input;
+      } else {
+         op = vertex_index ? nir_intrinsic_load_per_vertex_input :
+                             nir_intrinsic_load_input;
+      }
       break;
    case nir_var_shader_out:
       op = vertex_index ? nir_intrinsic_load_per_vertex_output :
@@ -204,10 +224,15 @@ lower_load(nir_intrinsic_instr *intrin, struct lower_io_state *state,
    if (load->intrinsic == nir_intrinsic_load_uniform)
       nir_intrinsic_set_range(load, state->type_size(var->type));
 
-   if (vertex_index)
+   if (vertex_index) {
       load->src[0] = nir_src_for_ssa(vertex_index);
-
-   load->src[vertex_index ? 1 : 0] = nir_src_for_ssa(offset);
+      load->src[1] = nir_src_for_ssa(offset);
+   } else if (barycentric) {
+      load->src[0] = nir_src_for_ssa(barycentric);
+      load->src[1] = nir_src_for_ssa(offset);
+   } else {
+      load->src[0] = nir_src_for_ssa(offset);
+   }
 
    return load;
 }
@@ -287,11 +312,60 @@ lower_atomic(nir_intrinsic_instr *intrin, struct lower_io_state *state,
    return atomic;
 }
 
+static nir_intrinsic_instr *
+lower_interpolate_at(nir_intrinsic_instr *intrin, struct lower_io_state *state,
+                     nir_ssa_def *offset)
+{
+   nir_variable *var = intrin->variables[0]->var;
+
+   assert(var->data.mode == nir_var_shader_in);
+
+   nir_intrinsic_op bary_op;
+   switch (intrin->intrinsic) {
+   case nir_intrinsic_interp_var_at_centroid:
+      bary_op = nir_intrinsic_load_barycentric_centroid;
+      break;
+   case nir_intrinsic_interp_var_at_sample:
+      bary_op = nir_intrinsic_load_barycentric_at_sample;
+      break;
+   case nir_intrinsic_interp_var_at_offset:
+      bary_op = nir_intrinsic_load_barycentric_at_offset;
+      break;
+   default:
+      unreachable("Bogus interpolateAt() intrinsic.");
+   }
+
+   nir_intrinsic_instr *bary_setup =
+      nir_intrinsic_instr_create(state->mem_ctx, bary_op);
+
+   nir_ssa_dest_init(&bary_setup->instr, &bary_setup->dest, 2, 32, NULL);
+   nir_intrinsic_set_interp_mode(bary_setup, var->data.interpolation);
+
+   if (intrin->intrinsic != nir_intrinsic_interp_var_at_centroid)
+      nir_src_copy(&bary_setup->src[0], &intrin->src[0], bary_setup);
+
+   nir_builder_instr_insert(&state->builder, &bary_setup->instr);
+
+   nir_intrinsic_instr *load =
+      nir_intrinsic_instr_create(state->mem_ctx,
+                                 nir_intrinsic_load_interpolated_input);
+   load->num_components = intrin->num_components;
+
+   nir_intrinsic_set_base(load, var->data.driver_location);
+   nir_intrinsic_set_component(load, var->data.location_frac);
+
+   load->src[0] = nir_src_for_ssa(&bary_setup->dest.ssa);
+   load->src[1] = nir_src_for_ssa(offset);
+
+   return load;
+}
+
 static bool
 nir_lower_io_block(nir_block *block,
                    struct lower_io_state *state)
 {
    nir_builder *b = &state->builder;
+   const nir_shader_compiler_options *options = b->shader->options;
 
    nir_foreach_instr_safe(instr, block) {
       if (instr->type != nir_instr_type_intrinsic)
@@ -314,6 +388,12 @@ nir_lower_io_block(nir_block *block,
       case nir_intrinsic_var_atomic_comp_swap:
          /* We can lower the io for this nir instrinsic */
          break;
+      case nir_intrinsic_interp_var_at_centroid:
+      case nir_intrinsic_interp_var_at_sample:
+      case nir_intrinsic_interp_var_at_offset:
+         /* We can optionally lower these to load_interpolated_input */
+         if (options->use_interpolated_input_intrinsics)
+            break;
       default:
          /* We can't lower the io for this nir instrinsic, so skip it */
          continue;
@@ -368,6 +448,13 @@ nir_lower_io_block(nir_block *block,
          replacement = lower_atomic(intrin, state, offset);
          break;
 
+      case nir_intrinsic_interp_var_at_centroid:
+      case nir_intrinsic_interp_var_at_sample:
+      case nir_intrinsic_interp_var_at_offset:
+         assert(vertex_index == NULL);
+         replacement = lower_interpolate_at(intrin, state, offset);
+         break;
+
       default:
          continue;
       }