[Mesa-dev] [PATCH 28/34] glsl: Parse the GLSL 1.50 GS layout qualifiers.
Paul Berry
stereotype441 at gmail.com
Sun Jul 28 23:03:54 PDT 2013
From: Eric Anholt <eric at anholt.net>
Limited semantic checking (compatibility between declarations, checking
that they're in the right shader target, etc.) is done.
v2: Remove stray debug printfs.
v3 (Paul Berry <stereotype441 at gmail.com>): Process input layout
qualifiers at ast_to_hir time rather than at parse time, since certain
error conditions depend on the relative ordering between input layout
qualifiers, declarations, and calls to .length().
---
src/glsl/ast.h | 34 ++++++++++++++++++
src/glsl/ast_to_hir.cpp | 27 +++++++++++++++
src/glsl/ast_type.cpp | 19 +++++++++++
src/glsl/glsl_parser.yy | 76 ++++++++++++++++++++++++++++++++++++++++-
src/glsl/glsl_parser_extras.cpp | 4 +++
src/glsl/glsl_parser_extras.h | 18 ++++++++++
6 files changed, 177 insertions(+), 1 deletion(-)
diff --git a/src/glsl/ast.h b/src/glsl/ast.h
index d98f1a3..3ef9913 100644
--- a/src/glsl/ast.h
+++ b/src/glsl/ast.h
@@ -435,6 +435,12 @@ struct ast_type_qualifier {
unsigned column_major:1;
unsigned row_major:1;
/** \} */
+
+ /** \name Layout qualifiers for GLSL 1.50 geometry shaders */
+ /** \{ */
+ unsigned prim_type:1;
+ unsigned max_vertices:1;
+ /** \} */
}
/** \brief Set of flags, accessed by name. */
q;
@@ -461,6 +467,12 @@ struct ast_type_qualifier {
*/
int index;
+ /** Maximum output vertices in GLSL 1.50 geometry shaders. */
+ int max_vertices;
+
+ /** Input or output primitive type in GLSL 1.50 geometry shaders */
+ GLenum prim_type;
+
/**
* Binding specified via GL_ARB_shading_language_420pack's "binding" keyword.
*
@@ -931,6 +943,28 @@ public:
*/
ast_expression *array_size;
};
+
+
+/**
+ * AST node representing a declaration of the input layout for geometry
+ * shaders.
+ */
+class ast_gs_input_layout : public ast_node
+{
+public:
+ ast_gs_input_layout(const struct YYLTYPE &locp, GLenum prim_type)
+ : prim_type(prim_type)
+ {
+ set_location(locp);
+ }
+
+ virtual ir_rvalue *hir(exec_list *instructions,
+ struct _mesa_glsl_parse_state *state);
+
+private:
+ const GLenum prim_type;
+};
+
/*@}*/
extern void
diff --git a/src/glsl/ast_to_hir.cpp b/src/glsl/ast_to_hir.cpp
index 3cfa1a4..3a013c5 100644
--- a/src/glsl/ast_to_hir.cpp
+++ b/src/glsl/ast_to_hir.cpp
@@ -72,6 +72,8 @@ _mesa_ast_to_hir(exec_list *instructions, struct _mesa_glsl_parse_state *state)
state->toplevel_ir = instructions;
+ state->gs_input_prim_type_specified = false;
+
/* Section 4.2 of the GLSL 1.20 specification states:
* "The built-in functions are scoped in a scope outside the global scope
* users declare global variables in. That is, a shader's global scope,
@@ -4438,6 +4440,31 @@ ast_interface_block::hir(exec_list *instructions,
return NULL;
}
+
+ir_rvalue *
+ast_gs_input_layout::hir(exec_list *instructions,
+ struct _mesa_glsl_parse_state *state)
+{
+ YYLTYPE loc = this->get_location();
+
+ /* If any geometry input layout declaration preceded this one, make sure it
+ * was consistent with this one.
+ */
+ if (state->gs_input_prim_type_specified &&
+ state->gs_input_prim_type != this->prim_type) {
+ _mesa_glsl_error(&loc, state,
+ "geometry shader input layout does not match"
+ " previous declaration");
+ return NULL;
+ }
+
+ state->gs_input_prim_type_specified = true;
+ state->gs_input_prim_type = this->prim_type;
+
+ return NULL;
+}
+
+
static void
detect_conflicting_assignments(struct _mesa_glsl_parse_state *state,
exec_list *instructions)
diff --git a/src/glsl/ast_type.cpp b/src/glsl/ast_type.cpp
index 38c3f8e..ce6b6a7 100644
--- a/src/glsl/ast_type.cpp
+++ b/src/glsl/ast_type.cpp
@@ -133,6 +133,25 @@ ast_type_qualifier::merge_qualifier(YYLTYPE *loc,
return false;
}
+ if (q.flags.q.prim_type) {
+ if (this->flags.q.prim_type && this->prim_type != q.prim_type) {
+ _mesa_glsl_error(loc, state,
+ "conflicting primitive type qualifiers used");
+ return false;
+ }
+ this->prim_type = q.prim_type;
+ }
+
+ if (q.flags.q.max_vertices) {
+ if (this->flags.q.max_vertices && this->max_vertices != q.max_vertices) {
+ _mesa_glsl_error(loc, state,
+ "geometry shader set conflicting max_vertices "
+ "(%d and %d)", this->max_vertices, q.max_vertices);
+ return false;
+ }
+ this->max_vertices = q.max_vertices;
+ }
+
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 bf31236..6f39d07 100644
--- a/src/glsl/glsl_parser.yy
+++ b/src/glsl/glsl_parser.yy
@@ -250,6 +250,7 @@ static void yyerror(YYLTYPE *loc, _mesa_glsl_parse_state *st, const char *msg)
%type <node> for_init_statement
%type <for_rest_statement> for_rest_statement
%type <n> integer_constant
+%type <node> layout_defaults
%right THEN ELSE
%%
@@ -1218,6 +1219,34 @@ layout_qualifier_id:
}
}
+ /* Layout qualifiers for GLSL 1.50 geometry shaders. */
+ if (!$$.flags.i) {
+ struct {
+ const char *s;
+ GLenum e;
+ } map[] = {
+ { "points", GL_POINTS },
+ { "lines", GL_LINES },
+ { "lines_adjacency", GL_LINES_ADJACENCY },
+ { "line_strip", GL_LINE_STRIP },
+ { "triangles", GL_TRIANGLES },
+ { "triangles_adjacency", GL_TRIANGLES_ADJACENCY },
+ { "triangle_strip", GL_TRIANGLE_STRIP },
+ };
+ for (unsigned i = 0; i < Elements(map); i++) {
+ if (strcmp($1, map[i].s) == 0) {
+ $$.flags.q.prim_type = 1;
+ $$.prim_type = map[i].e;
+ break;
+ }
+ }
+
+ if ($$.flags.i && !state->is_version(150, 0)) {
+ _mesa_glsl_error(& @1, state, "#version 150 layout "
+ "qualifier `%s' used", $1);
+ }
+ }
+
if (!$$.flags.i) {
_mesa_glsl_error(& @1, state, "unrecognized layout identifier "
"`%s'", $1);
@@ -1260,6 +1289,23 @@ layout_qualifier_id:
$$.binding = $3;
}
+ if (strcmp("max_vertices", $1) == 0) {
+ $$.flags.q.max_vertices = 1;
+
+ if ($3 < 0) {
+ _mesa_glsl_error(& @3, state,
+ "invalid max_vertices %d specified", $3);
+ YYERROR;
+ } else {
+ $$.max_vertices = $3;
+ if (!state->is_version(150, 0)) {
+ _mesa_glsl_error(& @3, state,
+ "#version 150 max_vertices qualifier "
+ "specified", $3);
+ }
+ }
+ }
+
/* If the identifier didn't match any known layout identifiers,
* emit an error.
*/
@@ -2042,7 +2088,7 @@ external_declaration:
function_definition { $$ = $1; }
| declaration { $$ = $1; }
| pragma_statement { $$ = NULL; }
- | layout_defaults { $$ = NULL; }
+ | layout_defaults { $$ = $1; }
;
function_definition:
@@ -2259,4 +2305,32 @@ layout_defaults:
if (!state->default_uniform_qualifier->merge_qualifier(& @1, state, $1)) {
YYERROR;
}
+ $$ = NULL;
+ }
+
+ | layout_qualifier IN_TOK ';'
+ {
+ void *ctx = state;
+ if (state->target != geometry_shader) {
+ _mesa_glsl_error(& @1, state,
+ "input layout qualifiers only valid in "
+ "geometry shaders");
+ } else if (!$1.flags.q.prim_type) {
+ _mesa_glsl_error(& @1, state,
+ "input layout qualifiers must specify a primitive"
+ " type");
+ }
+ $$ = new(ctx) ast_gs_input_layout(@1, $1.prim_type);
+ }
+
+ | layout_qualifier OUT_TOK ';'
+ {
+ if (state->target != geometry_shader) {
+ _mesa_glsl_error(& @1, state,
+ "out layout qualifiers only valid in "
+ "geometry shaders");
+ } else if (!state->out_qualifier->merge_qualifier(& @1, state, $1)) {
+ YYERROR;
+ }
+ $$ = NULL;
}
diff --git a/src/glsl/glsl_parser_extras.cpp b/src/glsl/glsl_parser_extras.cpp
index 9881bcb..6b8fb45 100644
--- a/src/glsl/glsl_parser_extras.cpp
+++ b/src/glsl/glsl_parser_extras.cpp
@@ -158,6 +158,10 @@ _mesa_glsl_parse_state::_mesa_glsl_parse_state(struct gl_context *_ctx,
this->default_uniform_qualifier = new(this) ast_type_qualifier();
this->default_uniform_qualifier->flags.q.shared = 1;
this->default_uniform_qualifier->flags.q.column_major = 1;
+
+ this->gs_input_prim_type_specified = false;
+ this->gs_input_prim_type = GL_POINTS;
+ this->out_qualifier = new(this) ast_type_qualifier();
}
/**
diff --git a/src/glsl/glsl_parser_extras.h b/src/glsl/glsl_parser_extras.h
index 7f478df..fe662e8 100644
--- a/src/glsl/glsl_parser_extras.h
+++ b/src/glsl/glsl_parser_extras.h
@@ -166,6 +166,24 @@ struct _mesa_glsl_parse_state {
struct ast_type_qualifier *default_uniform_qualifier;
/**
+ * True if a geometry shader input primitive type was specified using a
+ * layout directive.
+ *
+ * Note: this value is computed at ast_to_hir time rather than at parse
+ * time.
+ */
+ bool gs_input_prim_type_specified;
+
+ /**
+ * If gs_input_prim_type_specified is true, the primitive type that was
+ * specified. Otherwise ignored.
+ */
+ GLenum gs_input_prim_type;
+
+ /** Output layout qualifiers from GLSL 1.50. (geometry shader controls)*/
+ struct ast_type_qualifier *out_qualifier;
+
+ /**
* Printable list of GLSL versions supported by the current context
*
* \note
--
1.8.3.4
More information about the mesa-dev
mailing list