From: Rob Clark <robcl...@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 <robcl...@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 _______________________________________________ mesa-dev mailing list mesa-dev@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/mesa-dev