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
_______________________________________________
mesa-dev mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/mesa-dev