summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSamuel Iglesias Gonsalvez <[email protected]>2014-06-10 08:45:43 +0200
committerIago Toral Quiroga <[email protected]>2014-06-30 08:08:49 +0200
commita7e6ec68985dda9ca70c3eeb4fa9d807b67f7c99 (patch)
tree90940ad0089512c39e6c96ded1f9250ad213e1cd
parent15b5e663b050505683b7b4c9c489e46863b8441d (diff)
glsl: Add parsing support for multi-stream output in geometry shaders.
This implements parsing requirements for multi-stream support in geometry shaders as defined in ARB_gpu_shader5. Signed-off-by: Samuel Iglesias Gonsalvez <[email protected]> Reviewed-by: Ian Romanick <[email protected]>
-rw-r--r--src/glsl/ast.h5
-rw-r--r--src/glsl/ast_to_hir.cpp19
-rw-r--r--src/glsl/ast_type.cpp39
-rw-r--r--src/glsl/glsl_parser.yy53
-rw-r--r--src/glsl/glsl_parser_extras.h18
-rw-r--r--src/glsl/glsl_types.h6
-rw-r--r--src/glsl/ir.h5
7 files changed, 144 insertions, 1 deletions
diff --git a/src/glsl/ast.h b/src/glsl/ast.h
index 56e7bd86f91..15bf086a18e 100644
--- a/src/glsl/ast.h
+++ b/src/glsl/ast.h
@@ -509,6 +509,8 @@ struct ast_type_qualifier {
/** \name Layout qualifiers for GL_ARB_gpu_shader5 */
/** \{ */
unsigned invocations:1;
+ unsigned stream:1; /**< Has stream value assigned */
+ unsigned explicit_stream:1; /**< stream value assigned explicitly by shader code */
/** \} */
}
/** \brief Set of flags, accessed by name. */
@@ -542,6 +544,9 @@ struct ast_type_qualifier {
/** Maximum output vertices in GLSL 1.50 geometry shaders. */
int max_vertices;
+ /** Stream in GLSL 1.50 geometry shaders. */
+ unsigned stream;
+
/** Input or output primitive type in GLSL 1.50 geometry shaders */
GLenum prim_type;
diff --git a/src/glsl/ast_to_hir.cpp b/src/glsl/ast_to_hir.cpp
index 7ba04a808c2..042ef243b64 100644
--- a/src/glsl/ast_to_hir.cpp
+++ b/src/glsl/ast_to_hir.cpp
@@ -2461,6 +2461,11 @@ apply_type_qualifier_to_variable(const struct ast_type_qualifier *qual,
if (qual->flags.q.sample)
var->data.sample = 1;
+ if (state->stage == MESA_SHADER_GEOMETRY &&
+ qual->flags.q.out && qual->flags.q.stream) {
+ var->data.stream = qual->stream;
+ }
+
if (qual->flags.q.attribute && state->stage != MESA_SHADER_VERTEX) {
var->type = glsl_type::error_type;
_mesa_glsl_error(loc, state,
@@ -5100,6 +5105,9 @@ ast_process_structure_or_interface_block(exec_list *instructions,
fields[i].centroid = qual->flags.q.centroid ? 1 : 0;
fields[i].sample = qual->flags.q.sample ? 1 : 0;
+ /* Only save explicitly defined streams in block's field */
+ fields[i].stream = qual->flags.q.explicit_stream ? qual->stream : -1;
+
if (qual->flags.q.row_major || qual->flags.q.column_major) {
if (!qual->flags.q.uniform) {
_mesa_glsl_error(&loc, state,
@@ -5548,6 +5556,17 @@ ast_interface_block::hir(exec_list *instructions,
var->data.sample = fields[i].sample;
var->init_interface_type(block_type);
+ if (fields[i].stream != -1 &&
+ ((unsigned)fields[i].stream) != this->layout.stream) {
+ _mesa_glsl_error(&loc, state,
+ "stream layout qualifier on "
+ "interface block member `%s' does not match "
+ "the interface block (%d vs %d)",
+ var->name, fields[i].stream, this->layout.stream);
+ }
+
+ var->data.stream = this->layout.stream;
+
if (redeclaring_per_vertex) {
ir_variable *earlier =
get_variable_being_redeclared(var, loc, state,
diff --git a/src/glsl/ast_type.cpp b/src/glsl/ast_type.cpp
index 77053d5b12e..017f23d0e38 100644
--- a/src/glsl/ast_type.cpp
+++ b/src/glsl/ast_type.cpp
@@ -125,9 +125,13 @@ ast_type_qualifier::merge_qualifier(YYLTYPE *loc,
/* Uniform block layout qualifiers get to overwrite each
* other (rightmost having priority), while all other
* qualifiers currently don't allow duplicates.
+ *
+ * Geometry shaders can have several layout qualifiers
+ * assigning different stream values.
*/
- if ((this->flags.i & q.flags.i & ~(ubo_mat_mask.flags.i |
+ if ((state->stage != MESA_SHADER_GEOMETRY) &&
+ (this->flags.i & q.flags.i & ~(ubo_mat_mask.flags.i |
ubo_layout_mask.flags.i |
ubo_binding_mask.flags.i)) != 0) {
_mesa_glsl_error(loc, state,
@@ -154,6 +158,39 @@ ast_type_qualifier::merge_qualifier(YYLTYPE *loc,
this->max_vertices = q.max_vertices;
}
+ if (state->stage == MESA_SHADER_GEOMETRY &&
+ state->has_explicit_attrib_stream()) {
+ if (q.flags.q.stream && q.stream >= state->ctx->Const.MaxVertexStreams) {
+ _mesa_glsl_error(loc, state,
+ "`stream' value is larger than MAX_VERTEX_STREAMS - 1 "
+ "(%d > %d)",
+ q.stream, state->ctx->Const.MaxVertexStreams - 1);
+ }
+ if (this->flags.q.explicit_stream &&
+ this->stream >= state->ctx->Const.MaxVertexStreams) {
+ _mesa_glsl_error(loc, state,
+ "`stream' value is larger than MAX_VERTEX_STREAMS - 1 "
+ "(%d > %d)",
+ this->stream, state->ctx->Const.MaxVertexStreams - 1);
+ }
+
+ if (!this->flags.q.explicit_stream) {
+ if (q.flags.q.stream) {
+ this->flags.q.stream = 1;
+ this->stream = q.stream;
+ } else if (!this->flags.q.stream && this->flags.q.out) {
+ /* Assign default global stream value */
+ this->flags.q.stream = 1;
+ this->stream = state->out_qualifier->stream;
+ }
+ } else {
+ if (q.flags.q.explicit_stream) {
+ _mesa_glsl_error(loc, state,
+ "duplicate layout `stream' qualifier");
+ }
+ }
+ }
+
if ((q.flags.i & ubo_mat_mask.flags.i) != 0)
this->flags.i &= ~ubo_mat_mask.flags.i;
if ((q.flags.i & ubo_layout_mask.flags.i) != 0)
diff --git a/src/glsl/glsl_parser.yy b/src/glsl/glsl_parser.yy
index 2409959015d..b9897498ff7 100644
--- a/src/glsl/glsl_parser.yy
+++ b/src/glsl/glsl_parser.yy
@@ -1395,6 +1395,22 @@ layout_qualifier_id:
}
}
+ if (state->stage == MESA_SHADER_GEOMETRY) {
+ if (match_layout_qualifier("stream", $1, state) == 0 &&
+ state->check_explicit_attrib_stream_allowed(& @3)) {
+ $$.flags.q.stream = 1;
+
+ if ($3 < 0) {
+ _mesa_glsl_error(& @3, state,
+ "invalid stream %d specified", $3);
+ YYERROR;
+ } else {
+ $$.flags.q.explicit_stream = 1;
+ $$.stream = $3;
+ }
+ }
+ }
+
static const char * const local_size_qualifiers[3] = {
"local_size_x",
"local_size_y",
@@ -1693,6 +1709,20 @@ storage_qualifier:
{
memset(& $$, 0, sizeof($$));
$$.flags.q.out = 1;
+
+ if (state->stage == MESA_SHADER_GEOMETRY &&
+ state->has_explicit_attrib_stream()) {
+ /* Section 4.3.8.2 (Output Layout Qualifiers) of the GLSL 4.00
+ * spec says:
+ *
+ * "If the block or variable is declared with the stream
+ * identifier, it is associated with the specified stream;
+ * otherwise, it is associated with the current default stream."
+ */
+ $$.flags.q.stream = 1;
+ $$.flags.q.explicit_stream = 0;
+ $$.stream = state->out_qualifier->stream;
+ }
}
| UNIFORM
{
@@ -2361,6 +2391,18 @@ interface_block:
if (!block->layout.merge_qualifier(& @1, state, $1)) {
YYERROR;
}
+
+ foreach_list_typed (ast_declarator_list, member, link, &block->declarations) {
+ ast_type_qualifier& qualifier = member->type->qualifier;
+ if (qualifier.flags.q.stream && qualifier.stream != block->layout.stream) {
+ _mesa_glsl_error(& @1, state,
+ "stream layout qualifier on "
+ "interface block member does not match "
+ "the interface block (%d vs %d)",
+ qualifier.stream, block->layout.stream);
+ YYERROR;
+ }
+ }
$$ = block;
}
;
@@ -2434,6 +2476,14 @@ basic_interface_block:
block->layout.flags.i |= block_interface_qualifier;
+ if (state->stage == MESA_SHADER_GEOMETRY &&
+ state->has_explicit_attrib_stream()) {
+ /* Assign global layout's stream value. */
+ block->layout.flags.q.stream = 1;
+ block->layout.flags.q.explicit_stream = 0;
+ block->layout.stream = state->out_qualifier->stream;
+ }
+
foreach_list_typed (ast_declarator_list, member, link, &block->declarations) {
ast_type_qualifier& qualifier = member->type->qualifier;
if ((qualifier.flags.i & interface_type_mask) == 0) {
@@ -2576,6 +2626,9 @@ layout_defaults:
}
if (!state->out_qualifier->merge_qualifier(& @1, state, $1))
YYERROR;
+
+ /* Allow future assigments of global out's stream id value */
+ state->out_qualifier->flags.q.explicit_stream = 0;
}
$$ = NULL;
}
diff --git a/src/glsl/glsl_parser_extras.h b/src/glsl/glsl_parser_extras.h
index aa4a114e414..a0af965fd23 100644
--- a/src/glsl/glsl_parser_extras.h
+++ b/src/glsl/glsl_parser_extras.h
@@ -119,6 +119,19 @@ struct _mesa_glsl_parse_state {
return check_version(130, 300, locp, "bit-wise operations are forbidden");
}
+ bool check_explicit_attrib_stream_allowed(YYLTYPE *locp)
+ {
+ if (!this->has_explicit_attrib_stream()) {
+ const char *const requirement = "GL_ARB_gpu_shader5 extension or GLSL 400";
+
+ _mesa_glsl_error(locp, this, "explicit stream requires %s",
+ requirement);
+ return false;
+ }
+
+ return true;
+ }
+
bool check_explicit_attrib_location_allowed(YYLTYPE *locp,
const ir_variable *var)
{
@@ -166,6 +179,11 @@ struct _mesa_glsl_parse_state {
return true;
}
+ bool has_explicit_attrib_stream() const
+ {
+ return ARB_gpu_shader5_enable || is_version(400, 0);
+ }
+
bool has_explicit_attrib_location() const
{
return ARB_explicit_attrib_location_enable || is_version(330, 300);
diff --git a/src/glsl/glsl_types.h b/src/glsl/glsl_types.h
index f6d4a02ab68..0b63d4850e1 100644
--- a/src/glsl/glsl_types.h
+++ b/src/glsl/glsl_types.h
@@ -671,6 +671,12 @@ struct glsl_struct_field {
* in ir_variable::sample). 0 otherwise.
*/
unsigned sample:1;
+
+ /**
+ * For interface blocks, it has a value if this variable uses multiple vertex
+ * streams (as in ir_variable::stream). -1 otherwise.
+ */
+ int stream;
};
static inline unsigned int
diff --git a/src/glsl/ir.h b/src/glsl/ir.h
index b4e52d3d0a5..2e422ddac4a 100644
--- a/src/glsl/ir.h
+++ b/src/glsl/ir.h
@@ -706,6 +706,11 @@ public:
int location;
/**
+ * Vertex stream output identifier.
+ */
+ unsigned stream;
+
+ /**
* output index for dual source blending.
*/
int index;