[Mesa-dev] [PATCH 3/4] nir/lower_tex_proj: add support to clamp texture coords
Rob Clark
robdclark at gmail.com
Wed Sep 16 11:07:15 PDT 2015
From: Rob Clark <robclark at freedesktop.org>
Some hardware needs to clamp texture coordinates to [0.0, 1.0] in the
shader to emulate GL_CLAMP. This is added to lower_tex_proj since, in
the case of projected coords, the clamping needs to happen *after*
projection.
Signed-off-by: Rob Clark <robclark at freedesktop.org>
---
src/glsl/nir/nir.h | 4 +-
src/glsl/nir/nir_lower_tex_projector.c | 98 ++++++++++++++++++++++++++++++++--
src/mesa/drivers/dri/i965/brw_nir.c | 2 +-
3 files changed, 99 insertions(+), 5 deletions(-)
diff --git a/src/glsl/nir/nir.h b/src/glsl/nir/nir.h
index 9d47001..fba28f2 100644
--- a/src/glsl/nir/nir.h
+++ b/src/glsl/nir/nir.h
@@ -1830,7 +1830,9 @@ void nir_lower_samplers(nir_shader *shader,
const struct gl_shader_program *shader_program);
void nir_lower_system_values(nir_shader *shader);
-void nir_lower_tex_projector(nir_shader *shader, unsigned lower_txp);
+void nir_lower_tex_projector(nir_shader *shader, unsigned lower_txp,
+ unsigned saturate_s, unsigned saturate_t,
+ unsigned saturate_r);
void nir_lower_idiv(nir_shader *shader);
void nir_lower_clip_vs(nir_shader *shader, unsigned ucp_enables);
diff --git a/src/glsl/nir/nir_lower_tex_projector.c b/src/glsl/nir/nir_lower_tex_projector.c
index ce20956..1a72fd0 100644
--- a/src/glsl/nir/nir_lower_tex_projector.c
+++ b/src/glsl/nir/nir_lower_tex_projector.c
@@ -33,6 +33,9 @@
typedef struct {
nir_builder b;
unsigned lower_txp;
+ unsigned saturate_s;
+ unsigned saturate_t;
+ unsigned saturate_r;
} lower_tex_state;
static void
@@ -111,6 +114,62 @@ project_src(nir_builder *b, nir_tex_instr *tex)
tex->num_srcs--;
}
+static void
+saturate_src(nir_builder *b, nir_tex_instr *tex, unsigned sat_mask)
+{
+ b->cursor = nir_before_instr(&tex->instr);
+
+ /* Walk through the sources saturating the requested arguments. */
+ for (unsigned i = 0; i < tex->num_srcs; i++) {
+ switch (tex->src[i].src_type) {
+ case nir_tex_src_coord:
+ break;
+ default:
+ continue;
+ }
+ nir_ssa_def *src =
+ nir_ssa_for_src(b, tex->src[i].src, tex->coord_components);
+
+ /* split src into components: */
+ nir_ssa_def *comp[4];
+
+ for (unsigned j = 0; j < tex->coord_components; j++)
+ comp[j] = nir_channel(b, src, j);
+
+ /* clamp requested components, array index does not get clamped: */
+ unsigned ncomp = tex->coord_components;
+ if (tex->is_array)
+ ncomp--;
+
+ for (unsigned j = 0; j < ncomp; j++)
+ if ((1 << j) & sat_mask)
+ comp[j] = nir_fsat(b, comp[j]);
+
+ /* and move the result back into a single vecN: */
+ switch (tex->coord_components) {
+ case 4:
+ src = nir_vec4(b, comp[0], comp[1], comp[2], comp[3]);
+ break;
+ case 3:
+ src = nir_vec3(b, comp[0], comp[1], comp[2]);
+ break;
+ case 2:
+ src = nir_vec2(b, comp[0], comp[1]);
+ break;
+ case 1:
+ src = comp[0];
+ break;
+ default:
+ unreachable("bad texture coord count");
+ break;
+ }
+
+ nir_instr_rewrite_src(&tex->instr,
+ &tex->src[i].src,
+ nir_src_for_ssa(src));
+ }
+}
+
static bool
nir_lower_tex_projector_block(nir_block *block, void *void_state)
{
@@ -123,10 +182,24 @@ nir_lower_tex_projector_block(nir_block *block, void *void_state)
nir_tex_instr *tex = nir_instr_as_tex(instr);
bool lower_txp = !!(state->lower_txp & (1 << tex->sampler_dim));
-
- if (lower_txp)
+ /* mask of src coords to saturate (clamp): */
+ unsigned sat_mask = 0;
+
+ if ((1 << tex->sampler_index) & state->saturate_r)
+ sat_mask |= (1 << 2); /* .z */
+ if ((1 << tex->sampler_index) & state->saturate_t)
+ sat_mask |= (1 << 1); /* .y */
+ if ((1 << tex->sampler_index) & state->saturate_s)
+ sat_mask |= (1 << 0); /* .x */
+
+ /* If we are clamping any coords, we must lower projector first
+ * as clamping happens *after* projection:
+ */
+ if (lower_txp || sat_mask)
project_src(b, tex);
+ if (sat_mask)
+ saturate_src(b, tex, sat_mask);
}
return true;
@@ -147,12 +220,31 @@ nir_lower_tex_projector_impl(nir_function_impl *impl, lower_tex_state *state)
* lower_txp:
* bitmask of (1 << GLSL_SAMPLER_DIM_x) to control for which
* sampler types a texture projector is lowered.
+ *
+ * saturate_s/t/r:
+ * To emulate certain texture wrap modes, this can be used
+ * to saturate the specified tex coord to [0.0, 1.0]. The
+ * bits are according to sampler #, ie. if, for example:
+ *
+ * (conf->saturate_s & (1 << n))
+ *
+ * is true, then the s coord for sampler n is saturated.
+ *
+ * Note that clamping must happen *after* projector lowering
+ * so any projected texture sample instruction with a clamped
+ * coordinate gets automatically lowered, regardless of the
+ * 'lower_txp' setting.
*/
void
-nir_lower_tex_projector(nir_shader *shader, unsigned lower_txp)
+nir_lower_tex_projector(nir_shader *shader, unsigned lower_txp,
+ unsigned saturate_s, unsigned saturate_t,
+ unsigned saturate_r)
{
lower_tex_state state;
state.lower_txp = lower_txp;
+ state.saturate_s = saturate_s;
+ state.saturate_t = saturate_t;
+ state.saturate_r = saturate_r;
nir_foreach_overload(shader, overload) {
if (overload->impl)
nir_lower_tex_projector_impl(overload->impl, &state);
diff --git a/src/mesa/drivers/dri/i965/brw_nir.c b/src/mesa/drivers/dri/i965/brw_nir.c
index 2a924bb..31b24d6 100644
--- a/src/mesa/drivers/dri/i965/brw_nir.c
+++ b/src/mesa/drivers/dri/i965/brw_nir.c
@@ -96,7 +96,7 @@ brw_create_nir(struct brw_context *brw,
nir_lower_global_vars_to_local(nir);
nir_validate_shader(nir);
- nir_lower_tex_projector(nir, ~0);
+ nir_lower_tex_projector(nir, ~0, 0, 0, 0);
nir_validate_shader(nir);
nir_normalize_cubemap_coords(nir);
--
2.4.3
More information about the mesa-dev
mailing list