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@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(). Reviewed-by: Ian Romanick <ian.d.romanick@intel.com> Reviewed-by: Kenneth Graunke <kenneth@whitecape.org>tags/mesa-10.1-devel
@@ -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 |
@@ -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) |
@@ -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) |
@@ -254,6 +254,7 @@ _mesa_glsl_lex(YYSTYPE *val, YYLTYPE *loc, _mesa_glsl_parse_state *state) | |||
%type <node> for_init_statement | |||
%type <for_rest_statement> for_rest_statement | |||
%type <n> integer_constant | |||
%type <node> 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; | |||
} |
@@ -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(); | |||
} | |||
/** |
@@ -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 | |||
* |