#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#ifndef _MSC_VER
+#include <strings.h>
+#endif
#include <assert.h>
#include "ast.h"
#include "glsl_types.h"
#include "main/context.h"
+#ifdef _MSC_VER
+#pragma warning( disable : 4065 ) // switch statement contains 'default' but no 'case' labels
+#endif
+
#undef yyerror
static void yyerror(YYLTYPE *loc, _mesa_glsl_parse_state *st, const char *msg)
%union {
int n;
float real;
+ double dreal;
const char *identifier;
struct ast_type_qualifier type_qualifier;
ast_case_statement *case_statement;
ast_case_statement_list *case_statement_list;
ast_interface_block *interface_block;
-
+ ast_subroutine_list *subroutine_list;
struct {
ast_node *cond;
ast_expression *rest;
} selection_rest_statement;
}
-%token ATTRIBUTE CONST_TOK BOOL_TOK FLOAT_TOK INT_TOK UINT_TOK
-%token BREAK CONTINUE DO ELSE FOR IF DISCARD RETURN SWITCH CASE DEFAULT
-%token BVEC2 BVEC3 BVEC4 IVEC2 IVEC3 IVEC4 UVEC2 UVEC3 UVEC4 VEC2 VEC3 VEC4
-%token CENTROID IN_TOK OUT_TOK INOUT_TOK UNIFORM VARYING
+%token ATTRIBUTE CONST_TOK BOOL_TOK FLOAT_TOK INT_TOK UINT_TOK DOUBLE_TOK
+%token BREAK BUFFER CONTINUE DO ELSE FOR IF DISCARD RETURN SWITCH CASE DEFAULT
+%token BVEC2 BVEC3 BVEC4 IVEC2 IVEC3 IVEC4 UVEC2 UVEC3 UVEC4 VEC2 VEC3 VEC4 DVEC2 DVEC3 DVEC4
+%token CENTROID IN_TOK OUT_TOK INOUT_TOK UNIFORM VARYING SAMPLE
%token NOPERSPECTIVE FLAT SMOOTH
%token MAT2X2 MAT2X3 MAT2X4
%token MAT3X2 MAT3X3 MAT3X4
%token MAT4X2 MAT4X3 MAT4X4
+%token DMAT2X2 DMAT2X3 DMAT2X4
+%token DMAT3X2 DMAT3X3 DMAT3X4
+%token DMAT4X2 DMAT4X3 DMAT4X4
%token SAMPLER1D SAMPLER2D SAMPLER3D SAMPLERCUBE SAMPLER1DSHADOW SAMPLER2DSHADOW
%token SAMPLERCUBESHADOW SAMPLER1DARRAY SAMPLER2DARRAY SAMPLER1DARRAYSHADOW
%token SAMPLER2DARRAYSHADOW SAMPLERCUBEARRAY SAMPLERCUBEARRAYSHADOW
%type <identifier> any_identifier
%type <interface_block> instance_name_opt
%token <real> FLOATCONSTANT
+%token <dreal> DOUBLECONSTANT
%token <n> INTCONSTANT UINTCONSTANT BOOLCONSTANT
%token <identifier> FIELD_SELECTION
%token LEFT_OP RIGHT_OP
%token AND_OP OR_OP XOR_OP MUL_ASSIGN DIV_ASSIGN ADD_ASSIGN
%token MOD_ASSIGN LEFT_ASSIGN RIGHT_ASSIGN AND_ASSIGN XOR_ASSIGN OR_ASSIGN
%token SUB_ASSIGN
-%token INVARIANT
+%token INVARIANT PRECISE
%token LOWP MEDIUMP HIGHP SUPERP PRECISION
%token VERSION_TOK EXTENSION LINE COLON EOL INTERFACE OUTPUT
%token PRAGMA_OPTIMIZE_ON PRAGMA_OPTIMIZE_OFF
%token PRAGMA_INVARIANT_ALL
%token LAYOUT_TOK
-
+%token DOT_TOK
/* Reserved words that are not actually used in the grammar.
*/
%token ASM CLASS UNION ENUM TYPEDEF TEMPLATE THIS PACKED_TOK GOTO
%token INLINE_TOK NOINLINE PUBLIC_TOK STATIC EXTERN EXTERNAL
-%token LONG_TOK SHORT_TOK DOUBLE_TOK HALF FIXED_TOK UNSIGNED INPUT_TOK OUPTUT
-%token HVEC2 HVEC3 HVEC4 DVEC2 DVEC3 DVEC4 FVEC2 FVEC3 FVEC4
+%token LONG_TOK SHORT_TOK HALF FIXED_TOK UNSIGNED INPUT_TOK
+%token HVEC2 HVEC3 HVEC4 FVEC2 FVEC3 FVEC4
%token SAMPLER3DRECT
%token SIZEOF CAST NAMESPACE USING
-%token RESOURCE PATCH SAMPLE
+%token RESOURCE PATCH
%token SUBROUTINE
%token ERROR_TOK
%type <type_qualifier> layout_qualifier
%type <type_qualifier> layout_qualifier_id_list layout_qualifier_id
%type <type_qualifier> interface_block_layout_qualifier
+%type <type_qualifier> memory_qualifier
+%type <type_qualifier> subroutine_qualifier
+%type <subroutine_list> subroutine_type_list
%type <type_qualifier> interface_qualifier
%type <type_specifier> type_specifier
%type <type_specifier> type_specifier_nonarray
%type <expression> function_call_generic
%type <expression> function_call_or_method
%type <expression> function_call
-%type <expression> method_call_generic
-%type <expression> method_call_header_with_parameters
-%type <expression> method_call_header_no_parameters
-%type <expression> method_call_header
%type <n> assignment_operator
%type <n> unary_operator
%type <expression> function_identifier
| PRAGMA_OPTIMIZE_OFF EOL
| PRAGMA_INVARIANT_ALL EOL
{
- if (!state->is_version(120, 100)) {
+ /* Pragma invariant(all) cannot be used in a fragment shader.
+ *
+ * Page 27 of the GLSL 1.20 spec, Page 53 of the GLSL ES 3.00 spec:
+ *
+ * "It is an error to use this pragma in a fragment shader."
+ */
+ if (state->is_version(120, 300) &&
+ state->stage == MESA_SHADER_FRAGMENT) {
+ _mesa_glsl_error(& @1, state,
+ "pragma `invariant(all)' cannot be used "
+ "in a fragment shader.");
+ } else if (!state->is_version(120, 100)) {
_mesa_glsl_warning(& @1, state,
"pragma `invariant(all)' not supported in %s "
"(GLSL ES 1.00 or GLSL 1.20 required)",
if ($2 != NULL)
state->translation_unit.push_tail(& $2->link);
}
+ | external_declaration_list extension_statement {
+ if (!state->allow_extension_directive_midshader) {
+ _mesa_glsl_error(& @2, state,
+ "#extension directive is not allowed "
+ "in the middle of a shader");
+ YYERROR;
+ }
+ }
;
variable_identifier:
$$->set_location(@1);
$$->primary_expression.float_constant = $1;
}
+ | DOUBLECONSTANT
+ {
+ void *ctx = state;
+ $$ = new(ctx) ast_expression(ast_double_constant, NULL, NULL, NULL);
+ $$->set_location(@1);
+ $$->primary_expression.double_constant = $1;
+ }
| BOOLCONSTANT
{
void *ctx = state;
{
$$ = $1;
}
- | postfix_expression '.' any_identifier
+ | postfix_expression DOT_TOK FIELD_SELECTION
{
void *ctx = state;
$$ = new(ctx) ast_expression(ast_field_selection, $1, NULL, NULL);
function_call_or_method:
function_call_generic
- | postfix_expression '.' method_call_generic
- {
- void *ctx = state;
- $$ = new(ctx) ast_expression(ast_field_selection, $1, $3, NULL);
- $$->set_location_range(@1, @3);
- }
;
function_call_generic:
$$ = new(ctx) ast_function_expression($1);
$$->set_location(@1);
}
- | variable_identifier
+ | postfix_expression
{
void *ctx = state;
- ast_expression *callee = new(ctx) ast_expression($1);
- callee->set_location(@1);
- $$ = new(ctx) ast_function_expression(callee);
- $$->set_location(@1);
- }
- | FIELD_SELECTION
- {
- void *ctx = state;
- ast_expression *callee = new(ctx) ast_expression($1);
- callee->set_location(@1);
- $$ = new(ctx) ast_function_expression(callee);
+ $$ = new(ctx) ast_function_expression($1);
$$->set_location(@1);
}
;
-method_call_generic:
- method_call_header_with_parameters ')'
- | method_call_header_no_parameters ')'
- ;
-
-method_call_header_no_parameters:
- method_call_header VOID_TOK
- | method_call_header
- ;
-
-method_call_header_with_parameters:
- method_call_header assignment_expression
- {
- $$ = $1;
- $$->set_location(@1);
- $$->expressions.push_tail(& $2->link);
- }
- | method_call_header_with_parameters ',' assignment_expression
- {
- $$ = $1;
- $$->set_location(@1);
- $$->expressions.push_tail(& $3->link);
- }
- ;
-
// Grammar Note: Constructors look like methods, but lexical
// analysis recognized most of them as keywords. They are now
// recognized through "type_specifier".
-method_call_header:
- variable_identifier '('
- {
- void *ctx = state;
- ast_expression *callee = new(ctx) ast_expression($1);
- callee->set_location(@1);
- $$ = new(ctx) ast_function_expression(callee);
- $$->set_location(@1);
- }
- ;
// Grammar Note: No traditional style type casts.
unary_expression:
$$->return_type = $1;
$$->identifier = $2;
- state->symbols->add_function(new(state) ir_function($2));
+ if ($1->qualifier.flags.q.subroutine) {
+ /* add type for IDENTIFIER search */
+ state->symbols->add_type($2, glsl_type::get_subroutine_instance($2));
+ } else
+ state->symbols->add_function(new(state) ir_function($2));
state->symbols->push_scope();
}
;
$$ = $2;
$$.flags.q.constant = 1;
}
+ | PRECISE parameter_qualifier
+ {
+ if ($2.flags.q.precise)
+ _mesa_glsl_error(&@1, state, "duplicate precise qualifier");
+
+ $$ = $2;
+ $$.flags.q.precise = 1;
+ }
| parameter_direction_qualifier parameter_qualifier
{
if (($1.flags.q.in || $1.flags.q.out) && ($2.flags.q.in || $2.flags.q.out))
_mesa_glsl_error(&@1, state, "duplicate in/out/inout qualifier");
- if (!state->ARB_shading_language_420pack_enable && $2.flags.q.constant)
- _mesa_glsl_error(&@1, state, "const must be specified before "
- "in/out/inout");
+ if (!state->has_420pack() && $2.flags.q.constant)
+ _mesa_glsl_error(&@1, state, "in/out/inout must come after const "
+ "or precise");
$$ = $1;
$$.merge_qualifier(&@1, state, $2);
if ($2.precision != ast_precision_none)
_mesa_glsl_error(&@1, state, "duplicate precision qualifier");
- if (!state->ARB_shading_language_420pack_enable && $2.flags.i != 0)
+ if (!state->has_420pack() && $2.flags.i != 0)
_mesa_glsl_error(&@1, state, "precision qualifiers must come last");
$$ = $2;
$$.precision = $1;
}
+ | memory_qualifier parameter_qualifier
+ {
+ $$ = $1;
+ $$.merge_qualifier(&@1, state, $2);
+ }
parameter_direction_qualifier:
IN_TOK
$$->set_location_range(@1, @2);
$$->declarations.push_tail(&decl->link);
}
- | INVARIANT variable_identifier // Vertex only.
+ | INVARIANT variable_identifier
{
void *ctx = state;
ast_declaration *decl = new(ctx) ast_declaration($2, NULL, NULL);
$$->declarations.push_tail(&decl->link);
}
+ | PRECISE variable_identifier
+ {
+ void *ctx = state;
+ ast_declaration *decl = new(ctx) ast_declaration($2, NULL, NULL);
+ decl->set_location(@2);
+
+ $$ = new(ctx) ast_declarator_list(NULL);
+ $$->set_location_range(@1, @2);
+ $$->precise = true;
+
+ $$->declarations.push_tail(&decl->link);
+ }
;
fully_specified_type:
/* Layout qualifiers for AMD/ARB_conservative_depth. */
if (!$$.flags.i &&
(state->AMD_conservative_depth_enable ||
- state->ARB_conservative_depth_enable)) {
+ state->ARB_conservative_depth_enable ||
+ state->is_version(420, 0))) {
if (match_layout_qualifier($1, "depth_any", state) == 0) {
$$.flags.q.depth_any = 1;
} else if (match_layout_qualifier($1, "depth_greater", state) == 0) {
{ "triangles_adjacency", GL_TRIANGLES_ADJACENCY },
{ "triangle_strip", GL_TRIANGLE_STRIP },
};
- for (unsigned i = 0; i < Elements(map); i++) {
+ for (unsigned i = 0; i < ARRAY_SIZE(map); i++) {
if (match_layout_qualifier($1, map[i].s, state) == 0) {
$$.flags.q.prim_type = 1;
$$.prim_type = map[i].e;
{ "r8_snorm", GL_R8_SNORM, GLSL_TYPE_FLOAT }
};
- for (unsigned i = 0; i < Elements(map); i++) {
+ for (unsigned i = 0; i < ARRAY_SIZE(map); i++) {
if (match_layout_qualifier($1, map[i].name, state) == 0) {
$$.flags.q.explicit_image_format = 1;
$$.image_format = map[i].format;
if (!$$.flags.i &&
match_layout_qualifier($1, "early_fragment_tests", state) == 0) {
+ /* From section 4.4.1.3 of the GLSL 4.50 specification
+ * (Fragment Shader Inputs):
+ *
+ * "Fragment shaders also allow the following layout
+ * qualifier on in only (not with variable declarations)
+ * layout-qualifier-id
+ * early_fragment_tests
+ * [...]"
+ */
+ if (state->stage != MESA_SHADER_FRAGMENT) {
+ _mesa_glsl_error(& @1, state,
+ "early_fragment_tests layout qualifier only "
+ "valid in fragment shaders");
+ }
+
$$.flags.q.early_fragment_tests = 1;
}
}
+ /* Layout qualifiers for tessellation evaluation shaders. */
+ if (!$$.flags.i) {
+ struct {
+ const char *s;
+ GLenum e;
+ } map[] = {
+ /* triangles already parsed by gs-specific code */
+ { "quads", GL_QUADS },
+ { "isolines", GL_ISOLINES },
+ };
+ for (unsigned i = 0; i < ARRAY_SIZE(map); i++) {
+ if (match_layout_qualifier($1, map[i].s, state) == 0) {
+ $$.flags.q.prim_type = 1;
+ $$.prim_type = map[i].e;
+ break;
+ }
+ }
+
+ if ($$.flags.i &&
+ !state->ARB_tessellation_shader_enable &&
+ !state->is_version(400, 0)) {
+ _mesa_glsl_error(& @1, state,
+ "primitive mode qualifier `%s' requires "
+ "GLSL 4.00 or ARB_tessellation_shader", $1);
+ }
+ }
+ if (!$$.flags.i) {
+ struct {
+ const char *s;
+ GLenum e;
+ } map[] = {
+ { "equal_spacing", GL_EQUAL },
+ { "fractional_odd_spacing", GL_FRACTIONAL_ODD },
+ { "fractional_even_spacing", GL_FRACTIONAL_EVEN },
+ };
+ for (unsigned i = 0; i < ARRAY_SIZE(map); i++) {
+ if (match_layout_qualifier($1, map[i].s, state) == 0) {
+ $$.flags.q.vertex_spacing = 1;
+ $$.vertex_spacing = map[i].e;
+ break;
+ }
+ }
+
+ if ($$.flags.i &&
+ !state->ARB_tessellation_shader_enable &&
+ !state->is_version(400, 0)) {
+ _mesa_glsl_error(& @1, state,
+ "vertex spacing qualifier `%s' requires "
+ "GLSL 4.00 or ARB_tessellation_shader", $1);
+ }
+ }
+ if (!$$.flags.i) {
+ if (match_layout_qualifier($1, "cw", state) == 0) {
+ $$.flags.q.ordering = 1;
+ $$.ordering = GL_CW;
+ } else if (match_layout_qualifier($1, "ccw", state) == 0) {
+ $$.flags.q.ordering = 1;
+ $$.ordering = GL_CCW;
+ }
+
+ if ($$.flags.i &&
+ !state->ARB_tessellation_shader_enable &&
+ !state->is_version(400, 0)) {
+ _mesa_glsl_error(& @1, state,
+ "ordering qualifier `%s' requires "
+ "GLSL 4.00 or ARB_tessellation_shader", $1);
+ }
+ }
+ if (!$$.flags.i) {
+ if (match_layout_qualifier($1, "point_mode", state) == 0) {
+ $$.flags.q.point_mode = 1;
+ $$.point_mode = true;
+ }
+
+ if ($$.flags.i &&
+ !state->ARB_tessellation_shader_enable &&
+ !state->is_version(400, 0)) {
+ _mesa_glsl_error(& @1, state,
+ "qualifier `point_mode' requires "
+ "GLSL 4.00 or ARB_tessellation_shader");
+ }
+ }
+
if (!$$.flags.i) {
_mesa_glsl_error(& @1, state, "unrecognized layout identifier "
"`%s'", $1);
}
}
- if ((state->ARB_shading_language_420pack_enable ||
- state->ARB_shader_atomic_counters_enable) &&
- match_layout_qualifier("binding", $1, state) == 0) {
+ if (match_layout_qualifier("binding", $1, state) == 0) {
$$.flags.q.explicit_binding = 1;
$$.binding = $3;
}
- if (state->ARB_shader_atomic_counters_enable &&
+ if (match_layout_qualifier("set", $1, state) == 0) {
+ $$.flags.q.vk_set = 1;
+ $$.set = $3;
+ }
+
+ if (state->has_atomic_counters() &&
match_layout_qualifier("offset", $1, state) == 0) {
$$.flags.q.explicit_offset = 1;
$$.offset = $3;
}
}
+ if (state->stage == MESA_SHADER_GEOMETRY) {
+ if (match_layout_qualifier("stream", $1, state) == 0 &&
+ state->check_explicit_attrib_stream_allowed(& @3)) {
+ $$.flags.q.stream = 1;
+
+ if ($3 < 0) {
+ _mesa_glsl_error(& @3, state,
+ "invalid stream %d specified", $3);
+ YYERROR;
+ } else {
+ $$.flags.q.explicit_stream = 1;
+ $$.stream = $3;
+ }
+ }
+ }
+
static const char * const local_size_qualifiers[3] = {
"local_size_x",
"local_size_y",
}
}
+ /* Layout qualifiers for tessellation control shaders. */
+ if (match_layout_qualifier("vertices", $1, state) == 0) {
+ $$.flags.q.vertices = 1;
+
+ if ($3 <= 0) {
+ _mesa_glsl_error(& @3, state,
+ "invalid vertices (%d) specified", $3);
+ YYERROR;
+ } else if ($3 > (int)state->Const.MaxPatchVertices) {
+ _mesa_glsl_error(& @3, state,
+ "vertices (%d) exceeds "
+ "GL_MAX_PATCH_VERTICES", $3);
+ YYERROR;
+ } else {
+ $$.vertices = $3;
+ if (!state->ARB_tessellation_shader_enable &&
+ !state->is_version(400, 0)) {
+ _mesa_glsl_error(& @1, state,
+ "vertices qualifier requires GLSL 4.00 or "
+ "ARB_tessellation_shader");
+ }
+ }
+ }
+
/* If the identifier didn't match any known layout identifiers,
* emit an error.
*/
}
;
+subroutine_qualifier:
+ SUBROUTINE
+ {
+ memset(& $$, 0, sizeof($$));
+ $$.flags.q.subroutine = 1;
+ }
+ | SUBROUTINE '(' subroutine_type_list ')'
+ {
+ memset(& $$, 0, sizeof($$));
+ $$.flags.q.subroutine_def = 1;
+ $$.subroutine_list = $3;
+ }
+ ;
+
+subroutine_type_list:
+ any_identifier
+ {
+ void *ctx = state;
+ ast_declaration *decl = new(ctx) ast_declaration($1, NULL, NULL);
+ decl->set_location(@1);
+
+ $$ = new(ctx) ast_subroutine_list();
+ $$->declarations.push_tail(&decl->link);
+ }
+ | subroutine_type_list ',' any_identifier
+ {
+ void *ctx = state;
+ ast_declaration *decl = new(ctx) ast_declaration($3, NULL, NULL);
+ decl->set_location(@3);
+
+ $$ = $1;
+ $$->declarations.push_tail(&decl->link);
+ }
+ ;
+
interpolation_qualifier:
SMOOTH
{
memset(& $$, 0, sizeof($$));
$$.flags.q.invariant = 1;
}
+ | PRECISE
+ {
+ memset(& $$, 0, sizeof($$));
+ $$.flags.q.precise = 1;
+ }
| auxiliary_storage_qualifier
| storage_qualifier
| interpolation_qualifier
| layout_qualifier
+ | memory_qualifier
+ | subroutine_qualifier
| precision_qualifier
{
memset(&$$, 0, sizeof($$));
* Each qualifier's rule ensures that the accumulated qualifiers on the right
* side don't contain any that must appear on the left hand side.
* For example, when processing a storage qualifier, we check that there are
- * no auxiliary, interpolation, layout, or invariant qualifiers to the right.
+ * no auxiliary, interpolation, layout, invariant, or precise qualifiers to the right.
*/
+ | PRECISE type_qualifier
+ {
+ if ($2.flags.q.precise)
+ _mesa_glsl_error(&@1, state, "duplicate \"precise\" qualifier");
+
+ $$ = $2;
+ $$.flags.q.precise = 1;
+ }
| INVARIANT type_qualifier
{
if ($2.flags.q.invariant)
_mesa_glsl_error(&@1, state, "duplicate \"invariant\" qualifier");
- if ($2.has_layout()) {
+ if (!state->has_420pack() && $2.flags.q.precise)
_mesa_glsl_error(&@1, state,
- "\"invariant\" cannot be used with layout(...)");
- }
+ "\"invariant\" must come after \"precise\"");
$$ = $2;
$$.flags.q.invariant = 1;
+
+ /* GLSL ES 3.00 spec, section 4.6.1 "The Invariant Qualifier":
+ *
+ * "Only variables output from a shader can be candidates for invariance.
+ * This includes user-defined output variables and the built-in output
+ * variables. As only outputs can be declared as invariant, an invariant
+ * output from one shader stage will still match an input of a subsequent
+ * stage without the input being declared as invariant."
+ */
+ if (state->es_shader && state->language_version >= 300 && $$.flags.q.in)
+ _mesa_glsl_error(&@1, state, "invariant qualifiers cannot be used with shader inputs");
}
| interpolation_qualifier type_qualifier
{
if ($2.has_interpolation())
_mesa_glsl_error(&@1, state, "duplicate interpolation qualifier");
- if ($2.has_layout()) {
- _mesa_glsl_error(&@1, state, "interpolation qualifiers cannot be used "
- "with layout(...)");
- }
-
- if (!state->ARB_shading_language_420pack_enable && $2.flags.q.invariant) {
+ if (!state->has_420pack() &&
+ ($2.flags.q.precise || $2.flags.q.invariant)) {
_mesa_glsl_error(&@1, state, "interpolation qualifiers must come "
- "after \"invariant\"");
+ "after \"precise\" or \"invariant\"");
}
$$ = $1;
}
| layout_qualifier type_qualifier
{
- /* The GLSL 1.50 grammar indicates that a layout(...) declaration can be
- * used standalone or immediately before a storage qualifier. It cannot
- * be used with interpolation qualifiers or invariant. There does not
- * appear to be any text indicating that it must come before the storage
- * qualifier, but always seems to in examples.
+ /* In the absence of ARB_shading_language_420pack, layout qualifiers may
+ * appear no later than auxiliary storage qualifiers. There is no
+ * particularly clear spec language mandating this, but in all examples
+ * the layout qualifier precedes the storage qualifier.
+ *
+ * We allow combinations of layout with interpolation, invariant or
+ * precise qualifiers since these are useful in ARB_separate_shader_objects.
+ * There is no clear spec guidance on this either.
*/
- if (!state->ARB_shading_language_420pack_enable && $2.has_layout())
+ if (!state->has_420pack() && $2.has_layout())
_mesa_glsl_error(&@1, state, "duplicate layout(...) qualifiers");
- if ($2.flags.q.invariant)
- _mesa_glsl_error(&@1, state, "layout(...) cannot be used with "
- "the \"invariant\" qualifier");
-
- if ($2.has_interpolation()) {
- _mesa_glsl_error(&@1, state, "layout(...) cannot be used with "
- "interpolation qualifiers");
- }
-
+ $$ = $1;
+ $$.merge_qualifier(&@1, state, $2);
+ }
+ | subroutine_qualifier type_qualifier
+ {
$$ = $1;
$$.merge_qualifier(&@1, state, $2);
}
"duplicate auxiliary storage qualifier (centroid or sample)");
}
- if (!state->ARB_shading_language_420pack_enable &&
- ($2.flags.q.invariant || $2.has_interpolation() || $2.has_layout())) {
+ if (!state->has_420pack() &&
+ ($2.flags.q.precise || $2.flags.q.invariant ||
+ $2.has_interpolation() || $2.has_layout())) {
_mesa_glsl_error(&@1, state, "auxiliary storage qualifiers must come "
"just before storage qualifiers");
}
if ($2.has_storage())
_mesa_glsl_error(&@1, state, "duplicate storage qualifier");
- if (!state->ARB_shading_language_420pack_enable &&
- ($2.flags.q.invariant || $2.has_interpolation() || $2.has_layout() ||
- $2.has_auxiliary_storage())) {
+ if (!state->has_420pack() &&
+ ($2.flags.q.precise || $2.flags.q.invariant || $2.has_interpolation() ||
+ $2.has_layout() || $2.has_auxiliary_storage())) {
_mesa_glsl_error(&@1, state, "storage qualifiers must come after "
- "invariant, interpolation, layout and auxiliary "
+ "precise, invariant, interpolation, layout and auxiliary "
"storage qualifiers");
}
if ($2.precision != ast_precision_none)
_mesa_glsl_error(&@1, state, "duplicate precision qualifier");
- if (!state->ARB_shading_language_420pack_enable && $2.flags.i != 0)
+ if (!state->has_420pack() && $2.flags.i != 0)
_mesa_glsl_error(&@1, state, "precision qualifiers must come last");
$$ = $2;
$$.precision = $1;
}
+ | memory_qualifier type_qualifier
+ {
+ $$ = $1;
+ $$.merge_qualifier(&@1, state, $2);
+ }
;
auxiliary_storage_qualifier:
memset(& $$, 0, sizeof($$));
$$.flags.q.sample = 1;
}
- /* TODO: "patch" also goes here someday. */
+ | PATCH
+ {
+ memset(& $$, 0, sizeof($$));
+ $$.flags.q.patch = 1;
+ }
storage_qualifier:
CONST_TOK
{
memset(& $$, 0, sizeof($$));
$$.flags.q.out = 1;
+
+ if (state->stage == MESA_SHADER_GEOMETRY &&
+ state->has_explicit_attrib_stream()) {
+ /* Section 4.3.8.2 (Output Layout Qualifiers) of the GLSL 4.00
+ * spec says:
+ *
+ * "If the block or variable is declared with the stream
+ * identifier, it is associated with the specified stream;
+ * otherwise, it is associated with the current default stream."
+ */
+ $$.flags.q.stream = 1;
+ $$.flags.q.explicit_stream = 0;
+ $$.stream = state->out_qualifier->stream;
+ }
}
| UNIFORM
{
memset(& $$, 0, sizeof($$));
$$.flags.q.uniform = 1;
}
- | COHERENT
+ | BUFFER
+ {
+ memset(& $$, 0, sizeof($$));
+ $$.flags.q.buffer = 1;
+ }
+ ;
+
+memory_qualifier:
+ COHERENT
{
memset(& $$, 0, sizeof($$));
$$.flags.q.coherent = 1;
basic_type_specifier_nonarray:
VOID_TOK { $$ = "void"; }
| FLOAT_TOK { $$ = "float"; }
+ | DOUBLE_TOK { $$ = "double"; }
| INT_TOK { $$ = "int"; }
| UINT_TOK { $$ = "uint"; }
| BOOL_TOK { $$ = "bool"; }
| UVEC2 { $$ = "uvec2"; }
| UVEC3 { $$ = "uvec3"; }
| UVEC4 { $$ = "uvec4"; }
+ | DVEC2 { $$ = "dvec2"; }
+ | DVEC3 { $$ = "dvec3"; }
+ | DVEC4 { $$ = "dvec4"; }
| MAT2X2 { $$ = "mat2"; }
| MAT2X3 { $$ = "mat2x3"; }
| MAT2X4 { $$ = "mat2x4"; }
| MAT4X2 { $$ = "mat4x2"; }
| MAT4X3 { $$ = "mat4x3"; }
| MAT4X4 { $$ = "mat4"; }
+ | DMAT2X2 { $$ = "dmat2"; }
+ | DMAT2X3 { $$ = "dmat2x3"; }
+ | DMAT2X4 { $$ = "dmat2x4"; }
+ | DMAT3X2 { $$ = "dmat3x2"; }
+ | DMAT3X3 { $$ = "dmat3"; }
+ | DMAT3X4 { $$ = "dmat3x4"; }
+ | DMAT4X2 { $$ = "dmat4x2"; }
+ | DMAT4X3 { $$ = "dmat4x3"; }
+ | DMAT4X4 { $$ = "dmat4"; }
| SAMPLER1D { $$ = "sampler1D"; }
| SAMPLER2D { $$ = "sampler2D"; }
| SAMPLER2DRECT { $$ = "sampler2DRect"; }
;
/*
- * siwtch_statement grammar is based on the syntax described in the body
+ * switch_statement grammar is based on the syntax described in the body
* of the GLSL spec, not in it's appendix!!!
*/
switch_statement:
if (!block->layout.merge_qualifier(& @1, state, $1)) {
YYERROR;
}
+
+ foreach_list_typed (ast_declarator_list, member, link, &block->declarations) {
+ ast_type_qualifier& qualifier = member->type->qualifier;
+ if (qualifier.flags.q.stream && qualifier.stream != block->layout.stream) {
+ _mesa_glsl_error(& @1, state,
+ "stream layout qualifier on "
+ "interface block member does not match "
+ "the interface block (%d vs %d)",
+ qualifier.stream, block->layout.stream);
+ YYERROR;
+ }
+ }
$$ = block;
}
;
block->block_name = $2;
block->declarations.push_degenerate_list_at_head(& $4->link);
- if ($1.flags.q.uniform) {
+ if ($1.flags.q.buffer) {
+ if (!state->has_shader_storage_buffer_objects()) {
+ _mesa_glsl_error(& @1, state,
+ "#version 430 / GL_ARB_shader_storage_buffer_object "
+ "required for defining shader storage blocks");
+ } else if (state->ARB_shader_storage_buffer_object_warn) {
+ _mesa_glsl_warning(& @1, state,
+ "#version 430 / GL_ARB_shader_storage_buffer_object "
+ "required for defining shader storage blocks");
+ }
+ } else if ($1.flags.q.uniform) {
if (!state->has_uniform_buffer_objects()) {
_mesa_glsl_error(& @1, state,
"#version 140 / GL_ARB_uniform_buffer_object "
uint64_t 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.
+ /* Get a bitmask containing only the in/out/uniform/buffer
+ * 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.buffer = true;
temp_type_qualifier.flags.q.in = true;
temp_type_qualifier.flags.q.out = true;
interface_type_mask = temp_type_qualifier.flags.i;
block->layout.flags.i |= block_interface_qualifier;
+ if (state->stage == MESA_SHADER_GEOMETRY &&
+ state->has_explicit_attrib_stream()) {
+ /* Assign global layout's stream value. */
+ block->layout.flags.q.stream = 1;
+ block->layout.flags.q.explicit_stream = 0;
+ block->layout.stream = state->out_qualifier->stream;
+ }
+
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) {
"interface block member does not match "
"the interface block");
}
+
+ /* From GLSL ES 3.0, chapter 4.3.7 "Interface Blocks":
+ *
+ * "GLSL ES 3.0 does not support interface blocks for shader inputs or
+ * outputs."
+ *
+ * And from GLSL ES 3.0, chapter 4.6.1 "The invariant qualifier":.
+ *
+ * "Only variables output from a shader can be candidates for
+ * invariance."
+ *
+ * From GLSL 4.40 and GLSL 1.50, section "Interface Blocks":
+ *
+ * "If optional qualifiers are used, they can include interpolation
+ * qualifiers, auxiliary storage qualifiers, and storage qualifiers
+ * and they must declare an input, output, or uniform member
+ * consistent with the interface qualifier of the block"
+ */
+ if (qualifier.flags.q.invariant)
+ _mesa_glsl_error(&@1, state,
+ "invariant qualifiers cannot be used "
+ "with interface blocks members");
}
$$ = block;
memset(& $$, 0, sizeof($$));
$$.flags.q.uniform = 1;
}
+ | BUFFER
+ {
+ memset(& $$, 0, sizeof($$));
+ $$.flags.q.buffer = 1;
+ }
;
instance_name_opt:
| layout_qualifier OUT_TOK ';'
{
- if (state->stage != MESA_SHADER_GEOMETRY) {
- _mesa_glsl_error(& @1, state,
- "out layout qualifiers only valid in "
- "geometry shaders");
- } else {
+ $$ = NULL;
+ if (state->stage == MESA_SHADER_GEOMETRY) {
if ($1.flags.q.prim_type) {
/* Make sure this is a valid output primitive type. */
switch ($1.prim_type) {
}
if (!state->out_qualifier->merge_qualifier(& @1, state, $1))
YYERROR;
+
+ /* Allow future assigments of global out's stream id value */
+ state->out_qualifier->flags.q.explicit_stream = 0;
+ } else if (state->stage == MESA_SHADER_TESS_CTRL) {
+ if (!state->out_qualifier->merge_out_qualifier(& @1, state, $1, $$))
+ YYERROR;
+ } else {
+ _mesa_glsl_error(& @1, state,
+ "out layout qualifiers only valid in "
+ "tessellation control or geometry shaders");
}
- $$ = NULL;
}