[Mesa-dev] [PATCH 1/7] nir: Add new intrinsics for fragment shader input interpolation.
Kenneth Graunke
kenneth at whitecape.org
Mon Jul 18 20:26:31 UTC 2016
Backends can normally handle shader inputs solely by looking at
load_input intrinsics, and ignore the nir_variables in nir->inputs.
One exception is fragment shader inputs. load_input doesn't capture
the necessary interpolation information - flat, smooth, noperspective
mode, and centroid, sample, or pixel for the location. This means
that backends have to interpolate based on the nir_variables, then
associate those with the load_input intrinsics (say, by storing a
map of which variables are at which locations).
With GL_ARB_enhanced_layouts, we're going to have multiple varyings
packed into a single vec4 location. The intrinsics make this easy:
simply load N components from location <loc, component>. However,
working with variables and correlating the two is very awkward; we'd
much rather have intrinsics capture all the necessary information.
Fragment shader input interpolation typically works by producing a
set of barycentric coordinates, then using those to do a linear
interpolation between the values at the triangle's corners.
We represent this by introducing five new load_barycentric_* intrinsics:
- load_barycentric_pixel (ordinary variable)
- load_barycentric_centroid (centroid qualified variable)
- load_barycentric_sample (sample qualified variable)
- load_barycentric_at_sample (ARB_gpu_shader5's interpolateAtSample())
- load_barycentric_at_offset (ARB_gpu_shader5's interpolateAtOffset())
Each of these take the interpolation mode (smooth or noperspective only)
as a const_index, and produce a vec2. The last two also take a sample
or offset source.
We then introduce a new load_interpolated_input intrinsic, which
is like a normal load_input intrinsic, but with an additional
barycentric coordinate source.
The intention is that flat inputs will still use regular load_input
intrinsics. This makes them distinguishable from normal inputs that
need fancy interpolation, while also providing all the necessary data.
This nicely unifies regular inputs and interpolateAt functions.
Qualifiers and variables become irrelevant; there are just
load_barycentric intrinsics that determine the interpolation.
Signed-off-by: Kenneth Graunke <kenneth at whitecape.org>
---
src/compiler/nir/nir.h | 6 ++++++
src/compiler/nir/nir_builder.h | 11 +++++++++++
src/compiler/nir/nir_intrinsics.h | 24 ++++++++++++++++++++++++
src/compiler/nir/nir_lower_io.c | 1 +
src/compiler/nir/nir_print.c | 1 +
5 files changed, 43 insertions(+)
diff --git a/src/compiler/nir/nir.h b/src/compiler/nir/nir.h
index c5d3b6b..ac11998 100644
--- a/src/compiler/nir/nir.h
+++ b/src/compiler/nir/nir.h
@@ -992,6 +992,11 @@ typedef enum {
*/
NIR_INTRINSIC_COMPONENT = 8,
+ /**
+ * Interpolation mode (only meaningful for FS inputs).
+ */
+ NIR_INTRINSIC_INTERP_MODE = 9,
+
NIR_INTRINSIC_NUM_INDEX_FLAGS,
} nir_intrinsic_index_flag;
@@ -1059,6 +1064,7 @@ INTRINSIC_IDX_ACCESSORS(range, RANGE, unsigned)
INTRINSIC_IDX_ACCESSORS(desc_set, DESC_SET, unsigned)
INTRINSIC_IDX_ACCESSORS(binding, BINDING, unsigned)
INTRINSIC_IDX_ACCESSORS(component, COMPONENT, unsigned)
+INTRINSIC_IDX_ACCESSORS(interp_mode, INTERP_MODE, unsigned)
/**
* \group texture information
diff --git a/src/compiler/nir/nir_builder.h b/src/compiler/nir/nir_builder.h
index 09cdf72..435582a 100644
--- a/src/compiler/nir/nir_builder.h
+++ b/src/compiler/nir/nir_builder.h
@@ -458,6 +458,17 @@ nir_load_system_value(nir_builder *build, nir_intrinsic_op op, int index)
return &load->dest.ssa;
}
+static inline nir_ssa_def *
+nir_load_barycentric(nir_builder *build, nir_intrinsic_op op,
+ unsigned interp_mode)
+{
+ nir_intrinsic_instr *bary = nir_intrinsic_instr_create(build->shader, op);
+ nir_ssa_dest_init(&bary->instr, &bary->dest, 2, 32, NULL);
+ nir_intrinsic_set_interp_mode(bary, interp_mode);
+ nir_builder_instr_insert(build, &bary->instr);
+ return &bary->dest.ssa;
+}
+
static inline void
nir_jump(nir_builder *build, nir_jump_type jump_type)
{
diff --git a/src/compiler/nir/nir_intrinsics.h b/src/compiler/nir/nir_intrinsics.h
index 2f74555..29917e3 100644
--- a/src/compiler/nir/nir_intrinsics.h
+++ b/src/compiler/nir/nir_intrinsics.h
@@ -306,6 +306,27 @@ SYSTEM_VALUE(num_work_groups, 3, 0, xx, xx, xx)
SYSTEM_VALUE(helper_invocation, 1, 0, xx, xx, xx)
SYSTEM_VALUE(channel_num, 1, 0, xx, xx, xx)
+/**
+ * Barycentric coordinate intrinsics.
+ *
+ * These set up the barycentric coordinates for a particular interpolation.
+ * The first three are for the simple cases: pixel, centroid, or per-sample
+ * (at gl_SampleID). The next two handle interpolating at a specified
+ * sample location, or interpolating with a vec2 offset,
+ *
+ * The vec2 value produced by these intrinsics is intended for use as the
+ * barycoord source of a load_interpolated_input intrinsic.
+ */
+SYSTEM_VALUE(barycentric_pixel, 2, 1, INTERP_MODE, xx, xx)
+SYSTEM_VALUE(barycentric_centroid, 2, 1, INTERP_MODE, xx, xx)
+SYSTEM_VALUE(barycentric_sample, 2, 1, INTERP_MODE, xx, xx)
+/* src[] = { sample_id }. const_index[] = { interp_mode } */
+INTRINSIC(load_barycentric_at_sample, 1, ARR(1), true, 2, 0, 1, INTERP_MODE,
+ xx, xx, NIR_INTRINSIC_CAN_ELIMINATE | NIR_INTRINSIC_CAN_REORDER)
+/* src[] = { offset.xy }. const_index[] = { interp_mode } */
+INTRINSIC(load_barycentric_at_offset, 1, ARR(2), true, 2, 0, 1, INTERP_MODE,
+ xx, xx, NIR_INTRINSIC_CAN_ELIMINATE | NIR_INTRINSIC_CAN_REORDER)
+
/*
* Load operations pull data from some piece of GPU memory. All load
* operations operate in terms of offsets into some piece of theoretical
@@ -339,6 +360,9 @@ LOAD(ubo, 2, 0, xx, xx, xx, NIR_INTRINSIC_CAN_ELIMINATE | NIR_INTRINSIC_CAN_REOR
LOAD(input, 1, 2, BASE, COMPONENT, xx, NIR_INTRINSIC_CAN_ELIMINATE | NIR_INTRINSIC_CAN_REORDER)
/* src[] = { vertex, offset }. const_index[] = { base, component } */
LOAD(per_vertex_input, 2, 2, BASE, COMPONENT, xx, NIR_INTRINSIC_CAN_ELIMINATE | NIR_INTRINSIC_CAN_REORDER)
+/* src[] = { barycoord, offset }. const_index[] = { base, component } */
+LOAD(interpolated_input, 2, 2, BASE, COMPONENT, xx, NIR_INTRINSIC_CAN_ELIMINATE | NIR_INTRINSIC_CAN_REORDER)
+
/* src[] = { buffer_index, offset }. No const_index */
LOAD(ssbo, 2, 0, xx, xx, xx, NIR_INTRINSIC_CAN_ELIMINATE)
/* src[] = { offset }. const_index[] = { base, component } */
diff --git a/src/compiler/nir/nir_lower_io.c b/src/compiler/nir/nir_lower_io.c
index 71d2432..b05a73f 100644
--- a/src/compiler/nir/nir_lower_io.c
+++ b/src/compiler/nir/nir_lower_io.c
@@ -436,6 +436,7 @@ nir_get_io_offset_src(nir_intrinsic_instr *instr)
case nir_intrinsic_load_ssbo:
case nir_intrinsic_load_per_vertex_input:
case nir_intrinsic_load_per_vertex_output:
+ case nir_intrinsic_load_interpolated_input:
case nir_intrinsic_store_output:
return &instr->src[1];
case nir_intrinsic_store_ssbo:
diff --git a/src/compiler/nir/nir_print.c b/src/compiler/nir/nir_print.c
index a3380e6..3beb70a 100644
--- a/src/compiler/nir/nir_print.c
+++ b/src/compiler/nir/nir_print.c
@@ -571,6 +571,7 @@ print_intrinsic_instr(nir_intrinsic_instr *instr, print_state *state)
[NIR_INTRINSIC_DESC_SET] = "desc-set",
[NIR_INTRINSIC_BINDING] = "binding",
[NIR_INTRINSIC_COMPONENT] = "component",
+ [NIR_INTRINSIC_INTERP_MODE] = "interp_mode",
};
for (unsigned idx = 1; idx < NIR_INTRINSIC_NUM_INDEX_FLAGS; idx++) {
if (!info->index_map[idx])
--
2.9.0
More information about the mesa-dev
mailing list