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 <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>
This commit is contained in:
@@ -435,6 +435,12 @@ struct ast_type_qualifier {
|
|||||||
unsigned column_major:1;
|
unsigned column_major:1;
|
||||||
unsigned row_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. */
|
/** \brief Set of flags, accessed by name. */
|
||||||
q;
|
q;
|
||||||
@@ -461,6 +467,12 @@ struct ast_type_qualifier {
|
|||||||
*/
|
*/
|
||||||
int index;
|
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.
|
* Binding specified via GL_ARB_shading_language_420pack's "binding" keyword.
|
||||||
*
|
*
|
||||||
@@ -931,6 +943,28 @@ public:
|
|||||||
*/
|
*/
|
||||||
ast_expression *array_size;
|
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
|
extern void
|
||||||
|
@@ -72,6 +72,8 @@ _mesa_ast_to_hir(exec_list *instructions, struct _mesa_glsl_parse_state *state)
|
|||||||
|
|
||||||
state->toplevel_ir = instructions;
|
state->toplevel_ir = instructions;
|
||||||
|
|
||||||
|
state->gs_input_prim_type_specified = false;
|
||||||
|
|
||||||
/* Section 4.2 of the GLSL 1.20 specification states:
|
/* Section 4.2 of the GLSL 1.20 specification states:
|
||||||
* "The built-in functions are scoped in a scope outside the global scope
|
* "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,
|
* 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;
|
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
|
static void
|
||||||
detect_conflicting_assignments(struct _mesa_glsl_parse_state *state,
|
detect_conflicting_assignments(struct _mesa_glsl_parse_state *state,
|
||||||
exec_list *instructions)
|
exec_list *instructions)
|
||||||
|
@@ -133,6 +133,25 @@ ast_type_qualifier::merge_qualifier(YYLTYPE *loc,
|
|||||||
return false;
|
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)
|
if ((q.flags.i & ubo_mat_mask.flags.i) != 0)
|
||||||
this->flags.i &= ~ubo_mat_mask.flags.i;
|
this->flags.i &= ~ubo_mat_mask.flags.i;
|
||||||
if ((q.flags.i & ubo_layout_mask.flags.i) != 0)
|
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 <node> for_init_statement
|
||||||
%type <for_rest_statement> for_rest_statement
|
%type <for_rest_statement> for_rest_statement
|
||||||
%type <n> integer_constant
|
%type <n> integer_constant
|
||||||
|
%type <node> layout_defaults
|
||||||
|
|
||||||
%right THEN ELSE
|
%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) {
|
if (!$$.flags.i) {
|
||||||
_mesa_glsl_error(& @1, state, "unrecognized layout identifier "
|
_mesa_glsl_error(& @1, state, "unrecognized layout identifier "
|
||||||
"`%s'", $1);
|
"`%s'", $1);
|
||||||
@@ -1264,6 +1293,23 @@ layout_qualifier_id:
|
|||||||
$$.binding = $3;
|
$$.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,
|
/* If the identifier didn't match any known layout identifiers,
|
||||||
* emit an error.
|
* emit an error.
|
||||||
*/
|
*/
|
||||||
@@ -2046,7 +2092,7 @@ external_declaration:
|
|||||||
function_definition { $$ = $1; }
|
function_definition { $$ = $1; }
|
||||||
| declaration { $$ = $1; }
|
| declaration { $$ = $1; }
|
||||||
| pragma_statement { $$ = NULL; }
|
| pragma_statement { $$ = NULL; }
|
||||||
| layout_defaults { $$ = NULL; }
|
| layout_defaults { $$ = $1; }
|
||||||
;
|
;
|
||||||
|
|
||||||
function_definition:
|
function_definition:
|
||||||
@@ -2263,4 +2309,32 @@ layout_defaults:
|
|||||||
if (!state->default_uniform_qualifier->merge_qualifier(& @1, state, $1)) {
|
if (!state->default_uniform_qualifier->merge_qualifier(& @1, state, $1)) {
|
||||||
YYERROR;
|
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 = new(this) ast_type_qualifier();
|
||||||
this->default_uniform_qualifier->flags.q.shared = 1;
|
this->default_uniform_qualifier->flags.q.shared = 1;
|
||||||
this->default_uniform_qualifier->flags.q.column_major = 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;
|
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
|
* Printable list of GLSL versions supported by the current context
|
||||||
*
|
*
|
||||||
|
Reference in New Issue
Block a user