From 624b7bac76c3f70a3a110d114a3c1c327d3dad5f Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Wed, 12 Jun 2013 14:03:49 -0700 Subject: [PATCH] glsl: Parse the GLSL 1.50 GS layout qualifiers. 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 ): 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(). Reviewed-by: Ian Romanick Reviewed-by: Kenneth Graunke --- 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 d98f1a39b47..3ef9913a78e 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 f3c49d2271d..d2170e5e566 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, @@ -4451,6 +4453,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 38c3f8eb02c..ce6b6a77145 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 fcc5620cd6d..2c339add62a 100644 --- a/src/glsl/glsl_parser.yy +++ b/src/glsl/glsl_parser.yy @@ -254,6 +254,7 @@ _mesa_glsl_lex(YYSTYPE *val, YYLTYPE *loc, _mesa_glsl_parse_state *state) %type for_init_statement %type for_rest_statement %type integer_constant +%type layout_defaults %right THEN ELSE %% @@ -1222,6 +1223,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); @@ -1264,6 +1293,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. */ @@ -2046,7 +2092,7 @@ external_declaration: function_definition { $$ = $1; } | declaration { $$ = $1; } | pragma_statement { $$ = NULL; } - | layout_defaults { $$ = NULL; } + | layout_defaults { $$ = $1; } ; function_definition: @@ -2263,4 +2309,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 a5bc20c2384..a962742e439 100644 --- a/src/glsl/glsl_parser_extras.cpp +++ b/src/glsl/glsl_parser_extras.cpp @@ -159,6 +159,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 1e386dd3132..7c563ea7f60 100644 --- a/src/glsl/glsl_parser_extras.h +++ b/src/glsl/glsl_parser_extras.h @@ -165,6 +165,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 * -- 2.30.2