[Mesa-dev] [PATCH 3/4] nir: Allow outputs reads and add the relevant intrinsics.

Jason Ekstrand jason at jlekstrand.net
Thu Nov 12 17:15:38 PST 2015


On Tue, Nov 10, 2015 at 1:21 AM, Kenneth Graunke <kenneth at whitecape.org> wrote:
> Normally, we rely on nir_lower_outputs_to_temporaries to create shadow
> variables for outputs, buffering the results and writing them all out
> at the end of the program.  However, this is infeasible for tessellation
> control shader outputs.
>
> Tessellation control shaders can generate multiple output vertices, and
> write per-vertex outputs.  These are arrays indexed by the vertex
> number; each thread only writes one element, but can read any other
> element - including those being concurrently written by other threads.
> The barrier() intrinsic synchronizes between threads.
>
> Even if we tried to shadow every output element (which is of dubious
> value), we'd have to read updated values in at barrier() time, which
> means we need to allow output reads.
>
> Most stages should continue using nir_lower_outputs_to_temporaries(),
> but in theory drivers could choose not to if they really wanted.
>
> Signed-off-by: Kenneth Graunke <kenneth at whitecape.org>
> ---
>  src/glsl/nir/nir_intrinsics.h |  2 ++
>  src/glsl/nir/nir_lower_io.c   | 28 ++++++++++++++++++++--------
>  src/glsl/nir/nir_print.c      |  2 ++
>  src/glsl/nir/nir_validate.c   |  1 -
>  4 files changed, 24 insertions(+), 9 deletions(-)
>
> diff --git a/src/glsl/nir/nir_intrinsics.h b/src/glsl/nir/nir_intrinsics.h
> index 26ac7ce..b8d7d6c 100644
> --- a/src/glsl/nir/nir_intrinsics.h
> +++ b/src/glsl/nir/nir_intrinsics.h
> @@ -255,6 +255,8 @@ LOAD(ubo, 1, 1, NIR_INTRINSIC_CAN_ELIMINATE | NIR_INTRINSIC_CAN_REORDER)
>  LOAD(input, 0, 1, NIR_INTRINSIC_CAN_ELIMINATE | NIR_INTRINSIC_CAN_REORDER)
>  LOAD(per_vertex_input, 1, 1, NIR_INTRINSIC_CAN_ELIMINATE | NIR_INTRINSIC_CAN_REORDER)
>  LOAD(ssbo, 1, 1, NIR_INTRINSIC_CAN_ELIMINATE)
> +LOAD(output, 0, 1, NIR_INTRINSIC_CAN_ELIMINATE)
> +LOAD(per_vertex_output, 1, 1, NIR_INTRINSIC_CAN_ELIMINATE)
>
>  /*
>   * Stores work the same way as loads, except now the first register input is
> diff --git a/src/glsl/nir/nir_lower_io.c b/src/glsl/nir/nir_lower_io.c
> index e460160..e81524c 100644
> --- a/src/glsl/nir/nir_lower_io.c
> +++ b/src/glsl/nir/nir_lower_io.c
> @@ -158,6 +158,15 @@ load_op(struct lower_io_state *state,
>                               nir_intrinsic_load_input;
>        }
>        break;
> +   case nir_var_shader_out:
> +      if (per_vertex) {
> +         op = has_indirect ? nir_intrinsic_load_per_vertex_output_indirect :
> +                             nir_intrinsic_load_per_vertex_output;
> +      } else {
> +         op = has_indirect ? nir_intrinsic_load_output_indirect :
> +                             nir_intrinsic_load_output;
> +      }
> +      break;
>     case nir_var_uniform:
>        op = has_indirect ? nir_intrinsic_load_uniform_indirect :
>                            nir_intrinsic_load_uniform;
> @@ -188,14 +197,18 @@ nir_lower_io_block(nir_block *block, void *void_state)
>        if (state->mode != -1 && state->mode != mode)
>           continue;
>
> +      if (mode != nir_var_shader_in &&
> +          mode != nir_var_shader_out &&
> +          mode != nir_var_uniform)
> +         continue;
> +
>        switch (intrin->intrinsic) {
>        case nir_intrinsic_load_var: {
> -         if (mode != nir_var_shader_in && mode != nir_var_uniform)
> -            continue;
> -
> -         bool per_vertex = stage_uses_per_vertex_inputs(state) &&
> -                           mode == nir_var_shader_in &&
> -                           !intrin->variables[0]->var->data.patch;
> +         bool per_vertex = !intrin->variables[0]->var->data.patch &&
> +                           ((mode == nir_var_shader_in &&
> +                             stage_uses_per_vertex_inputs(state)) ||
> +                            (mode == nir_var_shader_out &&
> +                             stage_uses_per_vertex_outputs(state)));

With my suggested functions, this would reduce to
is_per_vertex_input() || is_per_vertex_output()

>
>           nir_ssa_def *indirect;
>           nir_ssa_def *vertex_index;
> @@ -239,8 +252,7 @@ nir_lower_io_block(nir_block *block, void *void_state)
>        }
>
>        case nir_intrinsic_store_var: {
> -         if (intrin->variables[0]->var->data.mode != nir_var_shader_out)
> -            continue;
> +         assert(mode == nir_var_shader_out);
>
>           nir_ssa_def *indirect;
>           nir_ssa_def *vertex_index;
> diff --git a/src/glsl/nir/nir_print.c b/src/glsl/nir/nir_print.c
> index 23fcafe..f7f5fdf 100644
> --- a/src/glsl/nir/nir_print.c
> +++ b/src/glsl/nir/nir_print.c
> @@ -448,6 +448,8 @@ print_intrinsic_instr(nir_intrinsic_instr *instr, print_state *state)
>     case nir_intrinsic_load_per_vertex_input_indirect:
>        var_list = &state->shader->inputs;
>        break;
> +   case nir_intrinsic_load_output:
> +   case nir_intrinsic_load_output_indirect:
>     case nir_intrinsic_store_output:
>     case nir_intrinsic_store_output_indirect:
>     case nir_intrinsic_store_per_vertex_output:
> diff --git a/src/glsl/nir/nir_validate.c b/src/glsl/nir/nir_validate.c
> index a42e830..841bace 100644
> --- a/src/glsl/nir/nir_validate.c
> +++ b/src/glsl/nir/nir_validate.c
> @@ -422,7 +422,6 @@ validate_intrinsic_instr(nir_intrinsic_instr *instr, validate_state *state)
>        assert(instr->variables[0]->var->data.mode != nir_var_shader_in &&
>               instr->variables[0]->var->data.mode != nir_var_uniform &&
>               instr->variables[0]->var->data.mode != nir_var_shader_storage);
> -      assert(instr->variables[1]->var->data.mode != nir_var_shader_out);
>        break;
>     default:
>        break;
> --
> 2.6.2
>
> _______________________________________________
> mesa-dev mailing list
> mesa-dev at lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/mesa-dev


More information about the mesa-dev mailing list