[Mesa-dev] [PATCH 11/18] glsl: Add support for EmitStreamVertex() and EndStreamPrimitive().
Iago Toral Quiroga
itoral at igalia.com
Wed Jun 11 00:49:34 PDT 2014
---
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
More information about the mesa-dev
mailing list