[Mesa-dev] [PATCH 11/18] glsl: Add support for EmitStreamVertex() and EndStreamPrimitive().

Chris Forbes chrisf at ijw.co.nz
Wed Jun 11 02:25:48 PDT 2014


This is pretty weird.

We should be able to generate a normal builtin function body here
which consists of just the ir_emit_vertex, passing the stream
parameter to it. This would then get inlined like any other function
leaving a bare ir_emit_vertex / ir_end_primitive with a constant
operand. If one of the optimization passes eats that, then it's
broken.


On Wed, Jun 11, 2014 at 7:49 PM, Iago Toral Quiroga <itoral at igalia.com> wrote:
> ---
>  src/glsl/ast_function.cpp      | 37 +++++++++++++++++++++-----
>  src/glsl/builtin_functions.cpp | 60 ++++++++++++++++++++++++++++++++++++++++++
>  src/glsl/ir.h                  | 18 ++++++++-----
>  3 files changed, 103 insertions(+), 12 deletions(-)
>
> diff --git a/src/glsl/ast_function.cpp b/src/glsl/ast_function.cpp
> index 8e91a1e..1c4d7e7 100644
> --- a/src/glsl/ast_function.cpp
> +++ b/src/glsl/ast_function.cpp
> @@ -1722,15 +1722,40 @@ ast_function_expression::hir(exec_list *instructions,
>        ir_function_signature *sig =
>          match_function_by_name(func_name, &actual_parameters, state);
>
> +      bool is_emit_stream_vertex = !strcmp(func_name, "EmitStreamVertex");
> +      bool is_end_stream_primitive = !strcmp(func_name, "EndStreamPrimitive");
> +
>        ir_rvalue *value = NULL;
>        if (sig == NULL) {
> -        no_matching_function_error(func_name, &loc, &actual_parameters, state);
> -        value = ir_rvalue::error_value(ctx);
> +         no_matching_function_error(func_name, &loc, &actual_parameters, state);
> +         value = ir_rvalue::error_value(ctx);
>        } else if (!verify_parameter_modes(state, sig, actual_parameters, this->expressions)) {
> -        /* an error has already been emitted */
> -        value = ir_rvalue::error_value(ctx);
> -      } else {
> -        value = generate_call(instructions, sig, &actual_parameters, state);
> +         /* an error has already been emitted */
> +         value = ir_rvalue::error_value(ctx);
> +      } else if (is_emit_stream_vertex || is_end_stream_primitive) {
> +         /* See builtin_builder::_EmitStreamVertex() to undertand why we need
> +          * to handle these as a special case.
> +          */
> +         ir_rvalue *stream_param = (ir_rvalue *) actual_parameters.head;
> +         ir_constant *stream_const = stream_param->as_constant();
> +         /* stream_const should not be NULL if we got here */
> +         assert(stream_const);
> +         int stream_id = stream_const->value.i[0];
> +         if (stream_id < 0 || stream_id >= MAX_VERTEX_STREAMS) {
> +            _mesa_glsl_error(&loc, state,
> +                             "Invalid call %s(%d). Accepted "
> +                             "values for the stream parameter are in the "
> +                             "range [0, %d].",
> +                             func_name, stream_id, MAX_VERTEX_STREAMS - 1);
> +         }
> +         /* Only enable multi-stream if we emit vertices to non-zero streams */
> +         state->gs_uses_streams = state->gs_uses_streams || stream_id > 0;
> +         if (is_emit_stream_vertex)
> +            instructions->push_tail(new(ctx) ir_emit_vertex(stream_id));
> +         else
> +            instructions->push_tail(new(ctx) ir_end_primitive(stream_id));
> +       } else {
> +         value = generate_call(instructions, sig, &actual_parameters, state);
>        }
>
>        return value;
> diff --git a/src/glsl/builtin_functions.cpp b/src/glsl/builtin_functions.cpp
> index f9f0686..412e8f3 100644
> --- a/src/glsl/builtin_functions.cpp
> +++ b/src/glsl/builtin_functions.cpp
> @@ -359,6 +359,12 @@ shader_image_load_store(const _mesa_glsl_parse_state *state)
>             state->ARB_shader_image_load_store_enable);
>  }
>
> +static bool
> +gs_streams(const _mesa_glsl_parse_state *state)
> +{
> +   return gpu_shader5(state) && gs_only(state);
> +}
> +
>  /** @} */
>
>  /******************************************************************************/
> @@ -594,6 +600,10 @@ private:
>
>     B0(EmitVertex)
>     B0(EndPrimitive)
> +   ir_function_signature *_EmitStreamVertex(builtin_available_predicate avail,
> +                                            const glsl_type *stream_type);
> +   ir_function_signature *_EndStreamPrimitive(builtin_available_predicate avail,
> +                                              const glsl_type *stream_type);
>
>     B2(textureQueryLod);
>     B1(textureQueryLevels);
> @@ -1708,6 +1718,14 @@ builtin_builder::create_builtins()
>
>     add_function("EmitVertex",   _EmitVertex(),   NULL);
>     add_function("EndPrimitive", _EndPrimitive(), NULL);
> +   add_function("EmitStreamVertex",
> +                _EmitStreamVertex(gs_streams, glsl_type::uint_type),
> +                _EmitStreamVertex(gs_streams, glsl_type::int_type),
> +                NULL);
> +   add_function("EndStreamPrimitive",
> +                _EndStreamPrimitive(gs_streams, glsl_type::uint_type),
> +                _EndStreamPrimitive(gs_streams, glsl_type::int_type),
> +                NULL);
>
>     add_function("textureQueryLOD",
>                  _textureQueryLod(glsl_type::sampler1D_type,  glsl_type::float_type),
> @@ -3878,6 +3896,35 @@ builtin_builder::_EmitVertex()
>  }
>
>  ir_function_signature *
> +builtin_builder::_EmitStreamVertex(builtin_available_predicate avail,
> +                                   const glsl_type *stream_type)
> +{
> +   ir_variable *stream =
> +      new(mem_ctx) ir_variable(stream_type, "stream", ir_var_const_in);
> +
> +   /* EmitStreamVertex is a special kind of built-in function. It does
> +    * not really generate any IR when processed, instead, it only adds a
> +    * marker in the IR to know when we need to generate code for vertex
> +    * emission, just like EmitVertex(). However, in this case we have
> +    * an input parameter that we need to preserve and that the dead code
> +    * optimization passes will kill because it is apparently unused.
> +    * We will actually use it, but not until code generation time, after
> +    * the dead code elimination passes have run and kill the input variable.
> +    *
> +    * To deal with this situation, since the input parameter for
> +    * EmitStreamVertex() must be a constant expression, we don't generate a
> +    * function body here. Then, when we detect EmitVertexStream() calls the
> +    * AST, instead of producing an ir_call, we get the constant value of
> +    * the input parameter in that moment and produce a ir_emit_vertex directly.
> +    * See ast_function_expression::hir().
> +    */
> +
> +   MAKE_INTRINSIC(glsl_type::void_type, avail, 1, stream);
> +
> +   return sig;
> +}
> +
> +ir_function_signature *
>  builtin_builder::_EndPrimitive()
>  {
>     MAKE_SIG(glsl_type::void_type, gs_only, 0);
> @@ -3888,6 +3935,19 @@ builtin_builder::_EndPrimitive()
>  }
>
>  ir_function_signature *
> +builtin_builder::_EndStreamPrimitive(builtin_available_predicate avail,
> +                                     const glsl_type *stream_type)
> +{
> +   ir_variable *stream =
> +      new(mem_ctx) ir_variable(stream_type, "stream", ir_var_const_in);
> +
> +   /* See comment in builtin_builder::_EmitStreamVertex, same applies here */
> +   MAKE_INTRINSIC(glsl_type::void_type, avail, 1, stream);
> +
> +   return sig;
> +}
> +
> +ir_function_signature *
>  builtin_builder::_textureQueryLod(const glsl_type *sampler_type,
>                                    const glsl_type *coord_type)
>  {
> diff --git a/src/glsl/ir.h b/src/glsl/ir.h
> index 8cc58af..7ae91ab 100644
> --- a/src/glsl/ir.h
> +++ b/src/glsl/ir.h
> @@ -2159,8 +2159,9 @@ private:
>   */
>  class ir_emit_vertex : public ir_instruction {
>  public:
> -   ir_emit_vertex()
> -      : ir_instruction(ir_type_emit_vertex)
> +   ir_emit_vertex(unsigned stream = 0)
> +      : ir_instruction(ir_type_emit_vertex),
> +        stream(stream)
>     {
>     }
>
> @@ -2171,10 +2172,12 @@ public:
>
>     virtual ir_emit_vertex *clone(void *mem_ctx, struct hash_table *) const
>     {
> -      return new(mem_ctx) ir_emit_vertex();
> +      return new(mem_ctx) ir_emit_vertex(stream);
>     }
>
>     virtual ir_visitor_status accept(ir_hierarchical_visitor *);
> +
> +   unsigned stream;
>  };
>
>  /**
> @@ -2183,8 +2186,9 @@ public:
>   */
>  class ir_end_primitive : public ir_instruction {
>  public:
> -   ir_end_primitive()
> -      : ir_instruction(ir_type_end_primitive)
> +   ir_end_primitive(unsigned stream = 0)
> +      : ir_instruction(ir_type_end_primitive),
> +        stream(stream)
>     {
>     }
>
> @@ -2195,10 +2199,12 @@ public:
>
>     virtual ir_end_primitive *clone(void *mem_ctx, struct hash_table *) const
>     {
> -      return new(mem_ctx) ir_end_primitive();
> +      return new(mem_ctx) ir_end_primitive(stream);
>     }
>
>     virtual ir_visitor_status accept(ir_hierarchical_visitor *);
> +
> +   unsigned stream;
>  };
>
>  /*@}*/
> --
> 1.9.1
>
> _______________________________________________
> 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