[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:20:13 PDT 2015


On Wed, Sep 16, 2015 at 2:07 PM, Rob Clark <robdclark at gmail.com> wrote:
> 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)

btw, I'd mentioned to add a note.. but I wonder if it would be
appropriate to put these params in nir_shader_compiler_options?  That
seems a bit cleaner to me, in that they are things that need more than
a one line @param comment tag to describe, plus then in the driver I'd
just have one place to set params derived from shader key..

BR,
-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