ast_case_label_list *case_label_list;
ast_case_statement *case_statement;
ast_case_statement_list *case_statement_list;
- ast_uniform_block *uniform_block;
+ ast_interface_block *interface_block;
struct {
ast_node *cond;
%token STRUCT VOID_TOK WHILE
%token <identifier> IDENTIFIER TYPE_IDENTIFIER NEW_IDENTIFIER
%type <identifier> any_identifier
-%type <uniform_block> instance_name_opt
+%type <interface_block> instance_name_opt
%token <real> FLOATCONSTANT
%token <n> INTCONSTANT UINTCONSTANT BOOLCONSTANT
%token <identifier> FIELD_SELECTION
%type <type_qualifier> interpolation_qualifier
%type <type_qualifier> layout_qualifier
%type <type_qualifier> layout_qualifier_id_list layout_qualifier_id
-%type <type_qualifier> uniform_block_layout_qualifier
+%type <type_qualifier> interface_block_layout_qualifier
+%type <type_qualifier> interface_qualifier
%type <type_specifier> type_specifier
%type <type_specifier> type_specifier_no_prec
%type <type_specifier> type_specifier_nonarray
%type <declarator_list> init_declarator_list
%type <declarator_list> single_declaration
%type <expression> initializer
+%type <expression> initializer_list
%type <node> declaration
%type <node> declaration_statement
%type <node> jump_statement
-%type <node> uniform_block
-%type <uniform_block> basic_uniform_block
+%type <node> interface_block
+%type <interface_block> basic_interface_block
%type <struct_specifier> struct_specifier
%type <declarator_list> struct_declaration_list
%type <declarator_list> struct_declaration
| VERSION_TOK INTCONSTANT EOL
{
state->process_version_directive(&@2, $2, NULL);
+ if (state->error) {
+ YYERROR;
+ }
}
| VERSION_TOK INTCONSTANT any_identifier EOL
{
state->process_version_directive(&@2, $2, $3);
+ if (state->error) {
+ YYERROR;
+ }
}
;
$3->is_precision_statement = true;
$$ = $3;
}
- | uniform_block
+ | interface_block
{
$$ = $1;
}
$$ = $1;
$$->declarations.push_tail(&decl->link);
state->symbols->add_variable(new(state) ir_variable(NULL, $3, ir_var_auto));
+ if ($7->oper == ast_aggregate) {
+ ast_aggregate_initializer *ai = (ast_aggregate_initializer *)$7;
+ ast_type_specifier *type = new(ctx) ast_type_specifier($1->type->specifier, true, NULL);
+ _mesa_ast_set_aggregate_type(type, ai, state);
+ }
}
| init_declarator_list ',' any_identifier '[' constant_expression ']' '=' initializer
{
$$ = $1;
$$->declarations.push_tail(&decl->link);
state->symbols->add_variable(new(state) ir_variable(NULL, $3, ir_var_auto));
+ if ($8->oper == ast_aggregate) {
+ ast_aggregate_initializer *ai = (ast_aggregate_initializer *)$8;
+ ast_type_specifier *type = new(ctx) ast_type_specifier($1->type->specifier, true, $5);
+ _mesa_ast_set_aggregate_type(type, ai, state);
+ }
}
| init_declarator_list ',' any_identifier '=' initializer
{
$$ = $1;
$$->declarations.push_tail(&decl->link);
state->symbols->add_variable(new(state) ir_variable(NULL, $3, ir_var_auto));
+ if ($5->oper == ast_aggregate) {
+ ast_aggregate_initializer *ai = (ast_aggregate_initializer *)$5;
+ _mesa_ast_set_aggregate_type($1->type->specifier, ai, state);
+ }
}
;
$$ = new(ctx) ast_declarator_list($1);
$$->set_location(yylloc);
$$->declarations.push_tail(&decl->link);
+ if ($6->oper == ast_aggregate) {
+ ast_aggregate_initializer *ai = (ast_aggregate_initializer *)$6;
+ ast_type_specifier *type = new(ctx) ast_type_specifier($1->specifier, true, NULL);
+ _mesa_ast_set_aggregate_type(type, ai, state);
+ }
}
| fully_specified_type any_identifier '[' constant_expression ']' '=' initializer
{
$$ = new(ctx) ast_declarator_list($1);
$$->set_location(yylloc);
$$->declarations.push_tail(&decl->link);
+ if ($7->oper == ast_aggregate) {
+ ast_aggregate_initializer *ai = (ast_aggregate_initializer *)$7;
+ ast_type_specifier *type = new(ctx) ast_type_specifier($1->specifier, true, $4);
+ _mesa_ast_set_aggregate_type(type, ai, state);
+ }
}
| fully_specified_type any_identifier '=' initializer
{
$$ = new(ctx) ast_declarator_list($1);
$$->set_location(yylloc);
$$->declarations.push_tail(&decl->link);
+ if ($4->oper == ast_aggregate) {
+ _mesa_ast_set_aggregate_type($1->specifier, $4, state);
+ }
}
| INVARIANT variable_identifier // Vertex only.
{
}
}
- /* See also uniform_block_layout_qualifier. */
+ /* See also interface_block_layout_qualifier. */
if (!$$.flags.i && state->ARB_uniform_buffer_object_enable) {
if (strcmp($1, "std140") == 0) {
$$.flags.q.std140 = 1;
$$.flags.q.shared = 1;
} else if (strcmp($1, "column_major") == 0) {
$$.flags.q.column_major = 1;
+ /* "row_major" is a reserved word in GLSL 1.30+. Its token is parsed
+ * below in the interface_block_layout_qualifier rule.
+ *
+ * It is not a reserved word in GLSL ES 3.00, so it's handled here as
+ * an identifier.
+ */
} else if (strcmp($1, "row_major") == 0) {
$$.flags.q.row_major = 1;
}
memset(& $$, 0, sizeof($$));
if (state->ARB_explicit_attrib_location_enable) {
- /* FINISHME: Handle 'index' once GL_ARB_blend_func_exteneded and
- * FINISHME: GLSL 1.30 (or later) are supported.
- */
if (strcmp("location", $1) == 0) {
$$.flags.q.explicit_location = 1;
"identifier `%s' used\n", $1);
}
}
- | uniform_block_layout_qualifier
+ | interface_block_layout_qualifier
{
$$ = $1;
/* Layout qualifiers for ARB_uniform_buffer_object. */
- if (!state->ARB_uniform_buffer_object_enable) {
+ if ($$.flags.q.uniform && !state->ARB_uniform_buffer_object_enable) {
_mesa_glsl_error(& @1, state,
"#version 140 / GL_ARB_uniform_buffer_object "
"layout qualifier `%s' is used\n", $1);
- } else if (state->ARB_uniform_buffer_object_warn) {
+ } else if ($$.flags.q.uniform && state->ARB_uniform_buffer_object_warn) {
_mesa_glsl_warning(& @1, state,
"#version 140 / GL_ARB_uniform_buffer_object "
"layout qualifier `%s' is used\n", $1);
* most qualifiers. See the any_identifier path of
* layout_qualifier_id for the others.
*/
-uniform_block_layout_qualifier:
+interface_block_layout_qualifier:
ROW_MAJOR
{
memset(& $$, 0, sizeof($$));
$$ = new(ctx) ast_struct_specifier($2, $4);
$$->set_location(yylloc);
state->symbols->add_type($2, glsl_type::void_type);
+ state->symbols->add_type_ast($2, new(ctx) ast_type_specifier($$));
}
| STRUCT '{' struct_declaration_list '}'
{
initializer:
assignment_expression
+ | '{' initializer_list '}'
+ {
+ $$ = $2;
+ }
+ | '{' initializer_list ',' '}'
+ {
+ $$ = $2;
+ }
+ ;
+
+initializer_list:
+ initializer
+ {
+ void *ctx = state;
+ $$ = new(ctx) ast_aggregate_initializer();
+ $$->set_location(yylloc);
+ $$->expressions.push_tail(& $1->link);
+ }
+ | initializer_list ',' initializer
+ {
+ $1->expressions.push_tail(& $3->link);
+ }
;
declaration_statement:
;
/* layout_qualifieropt is packed into this rule */
-uniform_block:
- basic_uniform_block
+interface_block:
+ basic_interface_block
{
$$ = $1;
}
- | layout_qualifier basic_uniform_block
+ | layout_qualifier basic_interface_block
{
- ast_uniform_block *block = $2;
+ ast_interface_block *block = $2;
if (!block->layout.merge_qualifier(& @1, state, $1)) {
YYERROR;
}
}
;
-basic_uniform_block:
- UNIFORM NEW_IDENTIFIER '{' member_list '}' instance_name_opt ';'
+basic_interface_block:
+ interface_qualifier NEW_IDENTIFIER '{' member_list '}' instance_name_opt ';'
{
- ast_uniform_block *const block = $6;
+ ast_interface_block *const block = $6;
block->block_name = $2;
block->declarations.push_degenerate_list_at_head(& $4->link);
- if (!state->ARB_uniform_buffer_object_enable) {
+ if ($1.flags.q.uniform) {
+ if (!state->ARB_uniform_buffer_object_enable) {
+ _mesa_glsl_error(& @1, state,
+ "#version 140 / GL_ARB_uniform_buffer_object "
+ "required for defining uniform blocks\n");
+ } else if (state->ARB_uniform_buffer_object_warn) {
+ _mesa_glsl_warning(& @1, state,
+ "#version 140 / GL_ARB_uniform_buffer_object "
+ "required for defining uniform blocks\n");
+ }
+ } else {
+ if (state->es_shader || state->language_version < 150) {
+ _mesa_glsl_error(& @1, state,
+ "#version 150 required for using "
+ "interface blocks.\n");
+ }
+ }
+
+ /* From the GLSL 1.50.11 spec, section 4.3.7 ("Interface Blocks"):
+ * "It is illegal to have an input block in a vertex shader
+ * or an output block in a fragment shader"
+ */
+ if ((state->target == vertex_shader) && $1.flags.q.in) {
_mesa_glsl_error(& @1, state,
- "#version 140 / GL_ARB_uniform_buffer_object "
- "required for defining uniform blocks\n");
- } else if (state->ARB_uniform_buffer_object_warn) {
- _mesa_glsl_warning(& @1, state,
- "#version 140 / GL_ARB_uniform_buffer_object "
- "required for defining uniform blocks\n");
+ "`in' interface block is not allowed for "
+ "a vertex shader\n");
+ } else if ((state->target == fragment_shader) && $1.flags.q.out) {
+ _mesa_glsl_error(& @1, state,
+ "`out' interface block is not allowed for "
+ "a fragment shader\n");
}
/* Since block arrays require names, and both features are added in
* the same language versions, we don't have to explicitly
* version-check both things.
*/
- if (block->instance_name != NULL
- && !(state->language_version == 300 && state->es_shader)) {
- _mesa_glsl_error(& @1, state,
- "#version 300 es required for using uniform "
- "blocks with an instance name\n");
+ if (block->instance_name != NULL) {
+ state->check_version(150, 300, & @1, "interface blocks with "
+ "an instance name are not allowed");
+ }
+
+ unsigned interface_type_mask;
+ struct ast_type_qualifier temp_type_qualifier;
+
+ /* Get a bitmask containing only the in/out/uniform flags, allowing us
+ * to ignore other irrelevant flags like interpolation qualifiers.
+ */
+ temp_type_qualifier.flags.i = 0;
+ temp_type_qualifier.flags.q.uniform = true;
+ temp_type_qualifier.flags.q.in = true;
+ temp_type_qualifier.flags.q.out = true;
+ interface_type_mask = temp_type_qualifier.flags.i;
+
+ /* Get the block's interface qualifier. The interface_qualifier
+ * production rule guarantees that only one bit will be set (and
+ * it will be in/out/uniform).
+ */
+ unsigned block_interface_qualifier = $1.flags.i;
+
+ block->layout.flags.i |= block_interface_qualifier;
+
+ 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) {
+ /* GLSLangSpec.1.50.11, 4.3.7 (Interface Blocks):
+ * "If no optional qualifier is used in a member declaration, the
+ * qualifier of the variable is just in, out, or uniform as declared
+ * by interface-qualifier."
+ */
+ qualifier.flags.i |= block_interface_qualifier;
+ } else if ((qualifier.flags.i & interface_type_mask) !=
+ block_interface_qualifier) {
+ /* GLSLangSpec.1.50.11, 4.3.7 (Interface Blocks):
+ * "If optional qualifiers are used, they can include interpolation
+ * and storage qualifiers and they must declare an input, output,
+ * or uniform variable consistent with the interface qualifier of
+ * the block."
+ */
+ _mesa_glsl_error(& @1, state,
+ "uniform/in/out qualifier on "
+ "interface block member does not match "
+ "the interface block\n");
+ }
}
$$ = block;
}
;
+interface_qualifier:
+ IN_TOK
+ {
+ memset(& $$, 0, sizeof($$));
+ $$.flags.q.in = 1;
+ }
+ | OUT_TOK
+ {
+ memset(& $$, 0, sizeof($$));
+ $$.flags.q.out = 1;
+ }
+ | UNIFORM
+ {
+ memset(& $$, 0, sizeof($$));
+ $$.flags.q.uniform = 1;
+ }
+ ;
+
instance_name_opt:
/* empty */
{
- $$ = new(state) ast_uniform_block(*state->default_uniform_qualifier,
+ $$ = new(state) ast_interface_block(*state->default_uniform_qualifier,
NULL,
NULL);
}
| NEW_IDENTIFIER
{
- $$ = new(state) ast_uniform_block(*state->default_uniform_qualifier,
+ $$ = new(state) ast_interface_block(*state->default_uniform_qualifier,
$1,
NULL);
}
| NEW_IDENTIFIER '[' constant_expression ']'
{
- $$ = new(state) ast_uniform_block(*state->default_uniform_qualifier,
+ $$ = new(state) ast_interface_block(*state->default_uniform_qualifier,
$1,
$3);
}
_mesa_glsl_error(& @1, state,
"instance block arrays must be explicitly sized\n");
- $$ = new(state) ast_uniform_block(*state->default_uniform_qualifier,
+ $$ = new(state) ast_interface_block(*state->default_uniform_qualifier,
$1,
NULL);
}
}
;
-/* Specifying "uniform" inside of a uniform block is redundant. */
-uniformopt:
- /* nothing */
- | UNIFORM
- ;
-
member_declaration:
- layout_qualifier uniformopt type_specifier struct_declarator_list ';'
+ fully_specified_type struct_declarator_list ';'
{
void *ctx = state;
- ast_fully_specified_type *type = new(ctx) ast_fully_specified_type();
+ ast_fully_specified_type *type = $1;
type->set_location(yylloc);
- type->qualifier = $1;
- type->qualifier.flags.q.uniform = true;
- type->specifier = $3;
- $$ = new(ctx) ast_declarator_list(type);
- $$->set_location(yylloc);
- $$->ubo_qualifiers_valid = true;
-
- $$->declarations.push_degenerate_list_at_head(& $4->link);
- }
- | uniformopt type_specifier struct_declarator_list ';'
- {
- void *ctx = state;
- ast_fully_specified_type *type = new(ctx) ast_fully_specified_type();
- type->set_location(yylloc);
+ if (type->qualifier.flags.q.attribute) {
+ _mesa_glsl_error(& @1, state,
+ "keyword 'attribute' cannot be used with "
+ "interface block member\n");
+ } else if (type->qualifier.flags.q.varying) {
+ _mesa_glsl_error(& @1, state,
+ "keyword 'varying' cannot be used with "
+ "interface block member\n");
+ }
- type->qualifier.flags.q.uniform = true;
- type->specifier = $2;
$$ = new(ctx) ast_declarator_list(type);
$$->set_location(yylloc);
$$->ubo_qualifiers_valid = true;
- $$->declarations.push_degenerate_list_at_head(& $3->link);
+ $$->declarations.push_degenerate_list_at_head(& $2->link);
}
;