[Mesa-dev] [PATCH v2] i965/fs: Don't use the pixel interpolater for centroid interpolation

Neil Roberts neil at linux.intel.com
Thu Jul 9 06:31:59 PDT 2015


For centroid interpolation we can just directly use the values set up
in the shader payload instead of querying the pixel interpolator. To
do this we need to modify brw_compute_barycentric_interp_modes to
detect when interpolateAtCentroid is called.

v2: Rebase on top of changes to set the pulls bary bit on SKL
---

As an aside, I was deliberating over whether to call the function
set_up_blah instead of setup_blah because I think the former is more
correct. The rest of Mesa seems to use setup so maybe it's more
important to be consistent than correct.

 src/mesa/drivers/dri/i965/brw_fs_nir.cpp | 52 +++++++++++++++++++-----------
 src/mesa/drivers/dri/i965/brw_wm.c       | 55 ++++++++++++++++++++++++++++++++
 2 files changed, 88 insertions(+), 19 deletions(-)

diff --git a/src/mesa/drivers/dri/i965/brw_fs_nir.cpp b/src/mesa/drivers/dri/i965/brw_fs_nir.cpp
index 5d1ea21..fd7f1b8 100644
--- a/src/mesa/drivers/dri/i965/brw_fs_nir.cpp
+++ b/src/mesa/drivers/dri/i965/brw_fs_nir.cpp
@@ -1238,6 +1238,25 @@ fs_visitor::emit_percomp(const fs_builder &bld, const fs_inst &inst,
    }
 }
 
+/* For most messages, we need one reg of ignored data; the hardware requires
+ * mlen==1 even when there is no payload. in the per-slot offset case, we'll
+ * replace this with the proper source data.
+ */
+static void
+setup_pixel_interpolater_instruction(fs_visitor *v,
+                                     nir_intrinsic_instr *instr,
+                                     fs_inst *inst,
+                                     int mlen = 1)
+{
+      inst->mlen = mlen;
+      inst->regs_written = 2 * v->dispatch_width / 8;
+      inst->pi_noperspective = instr->variables[0]->var->data.interpolation ==
+                               INTERP_QUALIFIER_NOPERSPECTIVE;
+
+      assert(v->stage == MESA_SHADER_FRAGMENT);
+      ((struct brw_wm_prog_data *) v->prog_data)->pulls_bary = true;
+}
+
 void
 fs_visitor::nir_emit_intrinsic(const fs_builder &bld, nir_intrinsic_instr *instr)
 {
@@ -1482,25 +1501,23 @@ fs_visitor::nir_emit_intrinsic(const fs_builder &bld, nir_intrinsic_instr *instr
    case nir_intrinsic_interp_var_at_centroid:
    case nir_intrinsic_interp_var_at_sample:
    case nir_intrinsic_interp_var_at_offset: {
-      assert(stage == MESA_SHADER_FRAGMENT);
-
-      ((struct brw_wm_prog_data *) prog_data)->pulls_bary = true;
-
       fs_reg dst_xy = bld.vgrf(BRW_REGISTER_TYPE_F, 2);
 
-      /* For most messages, we need one reg of ignored data; the hardware
-       * requires mlen==1 even when there is no payload. in the per-slot
-       * offset case, we'll replace this with the proper source data.
-       */
       fs_reg src = vgrf(glsl_type::float_type);
-      int mlen = 1;     /* one reg unless overriden */
       fs_inst *inst;
 
       switch (instr->intrinsic) {
-      case nir_intrinsic_interp_var_at_centroid:
-         inst = bld.emit(FS_OPCODE_INTERPOLATE_AT_CENTROID,
-                         dst_xy, src, fs_reg(0u));
+      case nir_intrinsic_interp_var_at_centroid: {
+         enum brw_wm_barycentric_interp_mode interp_mode;
+         if (instr->variables[0]->var->data.interpolation ==
+             INTERP_QUALIFIER_NOPERSPECTIVE)
+            interp_mode = BRW_WM_NONPERSPECTIVE_CENTROID_BARYCENTRIC;
+         else
+            interp_mode = BRW_WM_PERSPECTIVE_CENTROID_BARYCENTRIC;
+         uint8_t reg = payload.barycentric_coord_reg[interp_mode];
+         dst_xy = fs_reg(brw_vec16_grf(reg, 0));
          break;
+      }
 
       case nir_intrinsic_interp_var_at_sample: {
          /* XXX: We should probably handle non-constant sample id's */
@@ -1509,6 +1526,7 @@ fs_visitor::nir_emit_intrinsic(const fs_builder &bld, nir_intrinsic_instr *instr
          unsigned msg_data = const_sample ? const_sample->i[0] << 4 : 0;
          inst = bld.emit(FS_OPCODE_INTERPOLATE_AT_SAMPLE, dst_xy, src,
                          fs_reg(msg_data));
+         setup_pixel_interpolater_instruction(this, instr, inst);
          break;
       }
 
@@ -1521,6 +1539,7 @@ fs_visitor::nir_emit_intrinsic(const fs_builder &bld, nir_intrinsic_instr *instr
 
             inst = bld.emit(FS_OPCODE_INTERPOLATE_AT_SHARED_OFFSET, dst_xy, src,
                             fs_reg(off_x | (off_y << 4)));
+            setup_pixel_interpolater_instruction(this, instr, inst);
          } else {
             src = vgrf(glsl_type::ivec2_type);
             fs_reg offset_src = retype(get_nir_src(instr->src[0]),
@@ -1550,9 +1569,10 @@ fs_visitor::nir_emit_intrinsic(const fs_builder &bld, nir_intrinsic_instr *instr
                            bld.SEL(offset(src, bld, i), itemp, fs_reg(7)));
             }
 
-            mlen = 2 * dispatch_width / 8;
             inst = bld.emit(FS_OPCODE_INTERPOLATE_AT_PER_SLOT_OFFSET, dst_xy, src,
                             fs_reg(0u));
+            setup_pixel_interpolater_instruction(this, instr, inst,
+                                                 2 * dispatch_width / 8);
          }
          break;
       }
@@ -1561,12 +1581,6 @@ fs_visitor::nir_emit_intrinsic(const fs_builder &bld, nir_intrinsic_instr *instr
          unreachable("Invalid intrinsic");
       }
 
-      inst->mlen = mlen;
-      /* 2 floats per slot returned */
-      inst->regs_written = 2 * dispatch_width / 8;
-      inst->pi_noperspective = instr->variables[0]->var->data.interpolation ==
-                               INTERP_QUALIFIER_NOPERSPECTIVE;
-
       for (unsigned j = 0; j < instr->num_components; j++) {
          fs_reg src = interp_reg(instr->variables[0]->var->data.location, j);
          src.type = dest.type;
diff --git a/src/mesa/drivers/dri/i965/brw_wm.c b/src/mesa/drivers/dri/i965/brw_wm.c
index 592a729..f7fe1e0 100644
--- a/src/mesa/drivers/dri/i965/brw_wm.c
+++ b/src/mesa/drivers/dri/i965/brw_wm.c
@@ -40,9 +40,62 @@
 #include "program/prog_parameter.h"
 #include "program/program.h"
 #include "intel_mipmap_tree.h"
+#include "brw_nir.h"
 
 #include "util/ralloc.h"
 
+static bool
+compute_modes_in_block(nir_block *block,
+                       void *state)
+{
+   unsigned *interp_modes = state;
+   nir_intrinsic_instr *intrin;
+   enum brw_wm_barycentric_interp_mode interp_mode;
+
+   nir_foreach_instr(block, instr) {
+      if (instr->type != nir_instr_type_intrinsic)
+         continue;
+
+      intrin = nir_instr_as_intrinsic(instr);
+
+      if (intrin->intrinsic != nir_intrinsic_interp_var_at_centroid)
+         continue;
+
+      if (intrin->variables[0]->var->data.interpolation ==
+          INTERP_QUALIFIER_NOPERSPECTIVE)
+         interp_mode = BRW_WM_NONPERSPECTIVE_CENTROID_BARYCENTRIC;
+      else
+         interp_mode = BRW_WM_PERSPECTIVE_CENTROID_BARYCENTRIC;
+
+      *interp_modes |= 1 << interp_mode;
+   }
+
+   return true;
+}
+
+/**
+ * Looks for calls to interpolateAtCentroid within the program and returns a
+ * mask of the additional interpolation modes that they require.
+ */
+static unsigned
+compute_interpolate_at_centroid_modes(const struct gl_fragment_program *fprog)
+{
+   unsigned interp_modes = 0;
+   struct nir_shader *shader = fprog->Base.nir;
+
+   if (shader == NULL)
+      return 0;
+
+   nir_foreach_overload(shader, overload) {
+      if (overload->impl == NULL)
+         continue;
+
+      nir_foreach_block(overload->impl, compute_modes_in_block, &interp_modes);
+   }
+
+   return interp_modes;
+}
+
 /**
  * Return a bitfield where bit n is set if barycentric interpolation mode n
  * (see enum brw_wm_barycentric_interp_mode) is needed by the fragment shader.
@@ -114,6 +167,8 @@ brw_compute_barycentric_interp_modes(struct brw_context *brw,
       }
    }
 
+   barycentric_interp_modes |= compute_interpolate_at_centroid_modes(fprog);
+
    return barycentric_interp_modes;
 }
 
-- 
1.9.3



More information about the mesa-dev mailing list