diff options
Diffstat (limited to 'mesalib/src/glsl')
-rw-r--r-- | mesalib/src/glsl/ast.h | 49 | ||||
-rw-r--r-- | mesalib/src/glsl/ast_to_hir.cpp | 135 | ||||
-rw-r--r-- | mesalib/src/glsl/ast_type.cpp | 39 | ||||
-rw-r--r-- | mesalib/src/glsl/builtin_compiler/Makefile.am | 13 | ||||
-rw-r--r-- | mesalib/src/glsl/glsl_lexer.ll | 3 | ||||
-rw-r--r-- | mesalib/src/glsl/glsl_parser.yy | 247 | ||||
-rw-r--r-- | mesalib/src/glsl/ir.h | 15 | ||||
-rw-r--r-- | mesalib/src/glsl/ir_clone.cpp | 2 | ||||
-rw-r--r-- | mesalib/src/glsl/ir_optimization.h | 2 | ||||
-rw-r--r-- | mesalib/src/glsl/link_uniform_initializers.cpp | 75 | ||||
-rw-r--r-- | mesalib/src/glsl/linker.cpp | 21 |
11 files changed, 475 insertions, 126 deletions
diff --git a/mesalib/src/glsl/ast.h b/mesalib/src/glsl/ast.h index ff603b352..5f2d5b1e4 100644 --- a/mesalib/src/glsl/ast.h +++ b/mesalib/src/glsl/ast.h @@ -417,6 +417,12 @@ struct ast_type_qualifier { */ unsigned explicit_index:1; + /** + * Flag set if GL_ARB_shading_language_420pack "binding" layout + * qualifier is used. + */ + unsigned explicit_binding:1; + /** \name Layout qualifiers for GL_AMD_conservative_depth */ /** \{ */ unsigned depth_any:1; @@ -441,6 +447,9 @@ struct ast_type_qualifier { unsigned i; } flags; + /** Precision of the type (highp/medium/lowp). */ + unsigned precision:2; + /** * Location specified via GL_ARB_explicit_attrib_location layout * @@ -457,11 +466,34 @@ struct ast_type_qualifier { int index; /** + * Binding specified via GL_ARB_shading_language_420pack's "binding" keyword. + * + * \note + * This field is only valid if \c explicit_binding is set. + */ + int binding; + + /** * Return true if and only if an interpolation qualifier is present. */ bool has_interpolation() const; /** + * Return whether a layout qualifier is present. + */ + bool has_layout() const; + + /** + * Return whether a storage qualifier is present. + */ + bool has_storage() const; + + /** + * Return whether an auxiliary storage qualifier is present. + */ + bool has_auxiliary_storage() const; + + /** * \brief Return string representation of interpolation qualifier. * * If an interpolation qualifier is present, then return that qualifier's @@ -522,8 +554,8 @@ public: ast_type_specifier(const ast_type_specifier *that, bool is_array, ast_expression *array_size) : ast_node(), type_name(that->type_name), structure(that->structure), - is_array(is_array), array_size(array_size), precision(that->precision), - is_precision_statement(that->is_precision_statement) + is_array(is_array), array_size(array_size), + default_precision(that->default_precision) { /* empty */ } @@ -531,8 +563,8 @@ public: /** Construct a type specifier from a type name */ ast_type_specifier(const char *name) : type_name(name), structure(NULL), - is_array(false), array_size(NULL), precision(ast_precision_none), - is_precision_statement(false) + is_array(false), array_size(NULL), + default_precision(ast_precision_none) { /* empty */ } @@ -540,8 +572,8 @@ public: /** Construct a type specifier from a structure definition */ ast_type_specifier(ast_struct_specifier *s) : type_name(s->name), structure(s), - is_array(false), array_size(NULL), precision(ast_precision_none), - is_precision_statement(false) + is_array(false), array_size(NULL), + default_precision(ast_precision_none) { /* empty */ } @@ -560,9 +592,8 @@ public: bool is_array; ast_expression *array_size; - unsigned precision:2; - - bool is_precision_statement; + /** For precision statements, this is the given precision; otherwise none. */ + unsigned default_precision:2; }; diff --git a/mesalib/src/glsl/ast_to_hir.cpp b/mesalib/src/glsl/ast_to_hir.cpp index 28ccf7288..bfd5fda8f 100644 --- a/mesalib/src/glsl/ast_to_hir.cpp +++ b/mesalib/src/glsl/ast_to_hir.cpp @@ -1850,6 +1850,84 @@ validate_matrix_layout_for_type(struct _mesa_glsl_parse_state *state, } } +static bool +validate_binding_qualifier(struct _mesa_glsl_parse_state *state, + YYLTYPE *loc, + ir_variable *var, + const ast_type_qualifier *qual) +{ + if (var->mode != ir_var_uniform) { + _mesa_glsl_error(loc, state, + "the \"binding\" qualifier only applies to uniforms.\n"); + return false; + } + + if (qual->binding < 0) { + _mesa_glsl_error(loc, state, "binding values must be >= 0.\n"); + return false; + } + + const struct gl_context *const ctx = state->ctx; + unsigned elements = var->type->is_array() ? var->type->length : 1; + unsigned max_index = qual->binding + elements - 1; + + if (var->type->is_interface()) { + /* UBOs. From page 60 of the GLSL 4.20 specification: + * "If the binding point for any uniform block instance is less than zero, + * or greater than or equal to the implementation-dependent maximum + * number of uniform buffer bindings, a compilation error will occur. + * When the binding identifier is used with a uniform block instanced as + * an array of size N, all elements of the array from binding through + * binding + N – 1 must be within this range." + * + * The implementation-dependent maximum is GL_MAX_UNIFORM_BUFFER_BINDINGS. + */ + if (max_index >= ctx->Const.MaxUniformBufferBindings) { + _mesa_glsl_error(loc, state, "layout(binding = %d) for %d UBOs exceeds " + "the maximum number of UBO binding points (%d).\n", + qual->binding, elements, + ctx->Const.MaxUniformBufferBindings); + return false; + } + } else if (var->type->is_sampler() || + (var->type->is_array() && var->type->fields.array->is_sampler())) { + /* Samplers. From page 63 of the GLSL 4.20 specification: + * "If the binding is less than zero, or greater than or equal to the + * implementation-dependent maximum supported number of units, a + * compilation error will occur. When the binding identifier is used + * with an array of size N, all elements of the array from binding + * through binding + N - 1 must be within this range." + */ + unsigned limit; + switch (state->target) { + case vertex_shader: + limit = ctx->Const.VertexProgram.MaxTextureImageUnits; + break; + case geometry_shader: + limit = ctx->Const.GeometryProgram.MaxTextureImageUnits; + break; + case fragment_shader: + limit = ctx->Const.FragmentProgram.MaxTextureImageUnits; + break; + } + + if (max_index >= limit) { + _mesa_glsl_error(loc, state, "layout(binding = %d) for %d samplers " + "exceeds the maximum number of texture image units " + "(%d).\n", qual->binding, elements, limit); + + return false; + } + } else { + _mesa_glsl_error(loc, state, + "the \"binding\" qualifier only applies to uniform " + "blocks, samplers, or arrays of samplers.\n"); + return false; + } + + return true; +} + static void apply_type_qualifier_to_variable(const struct ast_type_qualifier *qual, ir_variable *var, @@ -2080,11 +2158,11 @@ apply_type_qualifier_to_variable(const struct ast_type_qualifier *qual, "explicit index requires explicit location\n"); } - /* Does the declaration use the 'layout' keyword? - */ - const bool uses_layout = qual->flags.q.pixel_center_integer - || qual->flags.q.origin_upper_left - || qual->flags.q.explicit_location; /* no need for index since it relies on location */ + if (qual->flags.q.explicit_binding && + validate_binding_qualifier(state, loc, var, qual)) { + var->explicit_binding = true; + var->binding = qual->binding; + } /* Does the declaration use the deprecated 'attribute' or 'varying' * keywords? @@ -2115,7 +2193,7 @@ apply_type_qualifier_to_variable(const struct ast_type_qualifier *qual, const bool relaxed_layout_qualifier_checking = state->ARB_fragment_coord_conventions_enable; - if (uses_layout && uses_deprecated_qualifier) { + if (qual->has_layout() && uses_deprecated_qualifier) { if (relaxed_layout_qualifier_checking) { _mesa_glsl_warning(loc, state, "`layout' qualifier may not be used with " @@ -2544,6 +2622,12 @@ ast_declarator_list::hir(exec_list *instructions, type_name); } } + + if (this->type->qualifier.precision != ast_precision_none && + this->type->specifier->structure != NULL) { + _mesa_glsl_error(&loc, state, "Precision qualifiers can't be applied " + "to structures.\n"); + } } foreach_list_typed (ast_declaration, decl, link, &this->declarations) { @@ -2846,7 +2930,7 @@ ast_declarator_list::hir(exec_list *instructions, /* Precision qualifiers exists only in GLSL versions 1.00 and >= 1.30. */ - if (this->type->specifier->precision != ast_precision_none) { + if (this->type->qualifier.precision != ast_precision_none) { state->check_precision_qualifiers_allowed(&loc); } @@ -2864,9 +2948,10 @@ ast_declarator_list::hir(exec_list *instructions, * From page 87 of the GLSL ES spec: * "RESOLUTION: Allow sampler types to take a precision qualifier." */ - if (this->type->specifier->precision != ast_precision_none + if (this->type->qualifier.precision != ast_precision_none && !var->type->is_float() && !var->type->is_integer() + && !var->type->is_record() && !(var->type->is_sampler() && state->es_shader) && !(var->type->is_array() && (var->type->fields.array->is_float() @@ -3958,22 +4043,11 @@ ir_rvalue * ast_type_specifier::hir(exec_list *instructions, struct _mesa_glsl_parse_state *state) { - if (!this->is_precision_statement && this->structure == NULL) + if (this->default_precision == ast_precision_none && this->structure == NULL) return NULL; YYLTYPE loc = this->get_location(); - if (this->precision != ast_precision_none - && !state->check_precision_qualifiers_allowed(&loc)) { - return NULL; - } - if (this->precision != ast_precision_none - && this->structure != NULL) { - _mesa_glsl_error(&loc, state, - "precision qualifiers do not apply to structures"); - return NULL; - } - /* If this is a precision statement, check that the type to which it is * applied is either float or int. * @@ -3984,10 +4058,16 @@ ast_type_specifier::hir(exec_list *instructions, * field can be either int or float [...]. Any other types or * qualifiers will result in an error. */ - if (this->is_precision_statement) { - assert(this->precision != ast_precision_none); - assert(this->structure == NULL); /* The check for structures was - * performed above. */ + if (this->default_precision != ast_precision_none) { + if (!state->check_precision_qualifiers_allowed(&loc)) + return NULL; + + if (this->structure != NULL) { + _mesa_glsl_error(&loc, state, + "precision qualifiers do not apply to structures"); + return NULL; + } + if (this->is_array) { _mesa_glsl_error(&loc, state, "default precision statements do not apply to " @@ -4307,6 +4387,13 @@ ast_interface_block::hir(exec_list *instructions, var_mode); var->interface_type = block_type; + /* Propagate the "binding" keyword into this UBO's fields; + * the UBO declaration itself doesn't get an ir_variable unless it + * has an instance name. This is ugly. + */ + var->explicit_binding = this->layout.flags.q.explicit_binding; + var->binding = this->layout.binding; + state->symbols->add_variable(var); instructions->push_tail(var); } diff --git a/mesalib/src/glsl/ast_type.cpp b/mesalib/src/glsl/ast_type.cpp index be84550da..275b2a1d0 100644 --- a/mesalib/src/glsl/ast_type.cpp +++ b/mesalib/src/glsl/ast_type.cpp @@ -56,6 +56,42 @@ bool ast_type_qualifier::has_interpolation() const || this->flags.q.noperspective; } +bool +ast_type_qualifier::has_layout() const +{ + return this->flags.q.origin_upper_left + || this->flags.q.pixel_center_integer + || this->flags.q.depth_any + || this->flags.q.depth_greater + || this->flags.q.depth_less + || this->flags.q.depth_unchanged + || this->flags.q.std140 + || this->flags.q.shared + || this->flags.q.column_major + || this->flags.q.row_major + || this->flags.q.packed + || this->flags.q.explicit_location + || this->flags.q.explicit_index + || this->flags.q.explicit_binding; +} + +bool +ast_type_qualifier::has_storage() const +{ + return this->flags.q.constant + || this->flags.q.attribute + || this->flags.q.varying + || this->flags.q.in + || this->flags.q.out + || this->flags.q.uniform; +} + +bool +ast_type_qualifier::has_auxiliary_storage() const +{ + return this->flags.q.centroid; +} + const char* ast_type_qualifier::interpolation_string() const { @@ -110,6 +146,9 @@ ast_type_qualifier::merge_qualifier(YYLTYPE *loc, if (q.flags.q.explicit_index) this->index = q.index; + if (q.flags.q.explicit_binding) + this->binding = q.binding; + return true; } diff --git a/mesalib/src/glsl/builtin_compiler/Makefile.am b/mesalib/src/glsl/builtin_compiler/Makefile.am index 823d546e1..5f1a995c3 100644 --- a/mesalib/src/glsl/builtin_compiler/Makefile.am +++ b/mesalib/src/glsl/builtin_compiler/Makefile.am @@ -65,6 +65,8 @@ AM_CXXFLAGS = $(AM_CFLAGS) include ../Makefile.sources noinst_PROGRAMS = builtin_compiler + +if !CROSS_COMPILING noinst_LTLIBRARIES = libglslcore.la libglcpp.la libglcpp_la_SOURCES = \ @@ -74,6 +76,7 @@ libglcpp_la_SOURCES = \ libglslcore_la_SOURCES = \ $(BUILTIN_COMPILER_GENERATED_CXX_FILES) \ $(LIBGLSL_FILES) +endif builtin_compiler_SOURCES = \ $(top_srcdir)/src/mesa/main/hash_table.c \ @@ -82,4 +85,14 @@ builtin_compiler_SOURCES = \ $(top_srcdir)/src/mesa/program/symbol_table.c \ $(BUILTIN_COMPILER_CXX_FILES) \ $(GLSL_COMPILER_CXX_FILES) + +if CROSS_COMPILING +builtin_compiler_SOURCES += \ + $(LIBGLCPP_GENERATED_FILES) \ + $(LIBGLCPP_FILES) \ + $(BUILTIN_COMPILER_GENERATED_CXX_FILES) \ + $(LIBGLSL_FILES) +builtin_compiler_CPPFLAGS = $(AM_CPPFLAGS) +else builtin_compiler_LDADD = libglslcore.la libglcpp.la +endif diff --git a/mesalib/src/glsl/glsl_lexer.ll b/mesalib/src/glsl/glsl_lexer.ll index e66ce7bee..dbc8154e4 100644 --- a/mesalib/src/glsl/glsl_lexer.ll +++ b/mesalib/src/glsl/glsl_lexer.ll @@ -366,7 +366,8 @@ layout { || yyextra->ARB_conservative_depth_enable || yyextra->ARB_explicit_attrib_location_enable || yyextra->ARB_uniform_buffer_object_enable - || yyextra->ARB_fragment_coord_conventions_enable) { + || yyextra->ARB_fragment_coord_conventions_enable + || yyextra->ARB_shading_language_420pack_enable) { return LAYOUT_TOK; } else { yylval->identifier = strdup(yytext); diff --git a/mesalib/src/glsl/glsl_parser.yy b/mesalib/src/glsl/glsl_parser.yy index b8f3df90e..cbd94b41f 100644 --- a/mesalib/src/glsl/glsl_parser.yy +++ b/mesalib/src/glsl/glsl_parser.yy @@ -162,6 +162,7 @@ static void yyerror(YYLTYPE *loc, _mesa_glsl_parse_state *st, const char *msg) %type <node> simple_statement %type <n> precision_qualifier %type <type_qualifier> type_qualifier +%type <type_qualifier> auxiliary_storage_qualifier %type <type_qualifier> storage_qualifier %type <type_qualifier> interpolation_qualifier %type <type_qualifier> layout_qualifier @@ -169,7 +170,6 @@ static void yyerror(YYLTYPE *loc, _mesa_glsl_parse_state *st, const char *msg) %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 <identifier> basic_type_specifier_nonarray %type <fully_specified_type> fully_specified_type @@ -180,7 +180,7 @@ static void yyerror(YYLTYPE *loc, _mesa_glsl_parse_state *st, const char *msg) %type <parameter_declarator> parameter_declarator %type <parameter_declarator> parameter_declaration %type <type_qualifier> parameter_qualifier -%type <type_qualifier> parameter_type_qualifier +%type <type_qualifier> parameter_direction_qualifier %type <type_specifier> parameter_type_specifier %type <function_definition> function_definition %type <compound_statement> compound_statement_no_new_scope @@ -790,10 +790,9 @@ declaration: { $$ = $1; } - | PRECISION precision_qualifier type_specifier_no_prec ';' + | PRECISION precision_qualifier type_specifier ';' { - $3->precision = $2; - $3->is_precision_statement = true; + $3->default_precision = $2; $$ = $3; } | interface_block @@ -864,29 +863,11 @@ parameter_declarator: ; parameter_declaration: - parameter_type_qualifier parameter_qualifier parameter_declarator - { - $1.flags.i |= $2.flags.i; - - $$ = $3; - $$->type->qualifier = $1; - } - | parameter_qualifier parameter_declarator + parameter_qualifier parameter_declarator { $$ = $2; $$->type->qualifier = $1; } - | parameter_type_qualifier parameter_qualifier parameter_type_specifier - { - void *ctx = state; - $1.flags.i |= $2.flags.i; - - $$ = new(ctx) ast_parameter_declarator(); - $$->set_location(yylloc); - $$->type = new(ctx) ast_fully_specified_type(); - $$->type->qualifier = $1; - $$->type->specifier = $3; - } | parameter_qualifier parameter_type_specifier { void *ctx = state; @@ -903,7 +884,40 @@ parameter_qualifier: { memset(& $$, 0, sizeof($$)); } - | IN_TOK + | CONST_TOK parameter_qualifier + { + if ($2.flags.q.constant) + _mesa_glsl_error(&@1, state, "duplicate const qualifier.\n"); + + $$ = $2; + $$.flags.q.constant = 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\n"); + + if (!state->ARB_shading_language_420pack_enable && $2.flags.q.constant) + _mesa_glsl_error(&@1, state, "const must be specified before " + "in/out/inout.\n"); + + $$ = $1; + $$.merge_qualifier(&@1, state, $2); + } + | precision_qualifier parameter_qualifier + { + if ($2.precision != ast_precision_none) + _mesa_glsl_error(&@1, state, "Duplicate precision qualifier.\n"); + + if (!state->ARB_shading_language_420pack_enable && $2.flags.i != 0) + _mesa_glsl_error(&@1, state, "Precision qualifiers must come last.\n"); + + $$ = $2; + $$.precision = $1; + } + +parameter_direction_qualifier: + IN_TOK { memset(& $$, 0, sizeof($$)); $$.flags.q.in = 1; @@ -1240,6 +1254,12 @@ layout_qualifier_id: } } + if (state->ARB_shading_language_420pack_enable && + strcmp("binding", $1) == 0) { + $$.flags.q.explicit_binding = 1; + $$.binding = $3; + } + /* If the identifier didn't match any known layout identifiers, * emit an error. */ @@ -1305,45 +1325,154 @@ interpolation_qualifier: } ; -parameter_type_qualifier: - CONST_TOK +type_qualifier: + /* Single qualifiers */ + INVARIANT { memset(& $$, 0, sizeof($$)); - $$.flags.q.constant = 1; + $$.flags.q.invariant = 1; } - ; - -type_qualifier: - storage_qualifier + | auxiliary_storage_qualifier + | storage_qualifier + | interpolation_qualifier | layout_qualifier - | layout_qualifier storage_qualifier + | precision_qualifier + { + memset(&$$, 0, sizeof($$)); + $$.precision = $1; + } + + /* Multiple qualifiers: + * In GLSL 4.20, these can be specified in any order. In earlier versions, + * they appear in this order (see GLSL 1.50 section 4.7 & comments below): + * + * invariant interpolation auxiliary storage precision ...or... + * layout storage precision + * + * 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. + */ + | INVARIANT type_qualifier + { + if ($2.flags.q.invariant) + _mesa_glsl_error(&@1, state, "Duplicate \"invariant\" qualifier.\n"); + + if ($2.has_layout()) { + _mesa_glsl_error(&@1, state, + "\"invariant\" cannot be used with layout(...).\n"); + } + + $$ = $2; + $$.flags.q.invariant = 1; + } + | interpolation_qualifier type_qualifier + { + /* Section 4.3 of the GLSL 1.40 specification states: + * "...qualified with one of these interpolation qualifiers" + * + * GLSL 1.30 claims to allow "one or more", but insists that: + * "These interpolation qualifiers may only precede the qualifiers in, + * centroid in, out, or centroid out in a declaration." + * + * ...which means that e.g. smooth can't precede smooth, so there can be + * only one after all, and the 1.40 text is a clarification, not a change. + */ + if ($2.has_interpolation()) + _mesa_glsl_error(&@1, state, "Duplicate interpolation qualifier.\n"); + + if ($2.has_layout()) { + _mesa_glsl_error(&@1, state, "Interpolation qualifiers cannot be used " + "with layout(...).\n"); + } + + if (!state->ARB_shading_language_420pack_enable && $2.flags.q.invariant) { + _mesa_glsl_error(&@1, state, "Interpolation qualifiers must come " + "after \"invariant\".\n"); + } + + $$ = $1; + $$.merge_qualifier(&@1, state, $2); + } + | 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. + */ + if (!state->ARB_shading_language_420pack_enable && $2.has_layout()) + _mesa_glsl_error(&@1, state, "Duplicate layout(...) qualifiers.\n"); + + if ($2.flags.q.invariant) + _mesa_glsl_error(&@1, state, "layout(...) cannot be used with " + "the \"invariant\" qualifier\n"); + + if ($2.has_interpolation()) { + _mesa_glsl_error(&@1, state, "layout(...) cannot be used with " + "interpolation qualifiers.\n"); + } + $$ = $1; - $$.flags.i |= $2.flags.i; + $$.merge_qualifier(&@1, state, $2); } - | interpolation_qualifier - | interpolation_qualifier storage_qualifier + | auxiliary_storage_qualifier type_qualifier { + if ($2.has_auxiliary_storage()) { + _mesa_glsl_error(&@1, state, + "Duplicate auxiliary storage qualifier (centroid).\n"); + } + + if (!state->ARB_shading_language_420pack_enable && + ($2.flags.q.invariant || $2.has_interpolation() || $2.has_layout())) { + _mesa_glsl_error(&@1, state, "Auxiliary storage qualifiers must come " + "just before storage qualifiers.\n"); + } $$ = $1; $$.flags.i |= $2.flags.i; } - | INVARIANT storage_qualifier + | storage_qualifier type_qualifier { - $$ = $2; - $$.flags.q.invariant = 1; + /* Section 4.3 of the GLSL 1.20 specification states: + * "Variable declarations may have a storage qualifier specified..." + * 1.30 clarifies this to "may have one storage qualifier". + */ + if ($2.has_storage()) + _mesa_glsl_error(&@1, state, "Duplicate storage qualifier.\n"); + + if (!state->ARB_shading_language_420pack_enable && + ($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 " + "storage qualifiers.\n"); + } + + $$ = $1; + $$.merge_qualifier(&@1, state, $2); } - | INVARIANT interpolation_qualifier storage_qualifier + | precision_qualifier type_qualifier { + if ($2.precision != ast_precision_none) + _mesa_glsl_error(&@1, state, "Duplicate precision qualifier.\n"); + + if (!state->ARB_shading_language_420pack_enable && $2.flags.i != 0) + _mesa_glsl_error(&@1, state, "Precision qualifiers must come last.\n"); + $$ = $2; - $$.flags.i |= $3.flags.i; - $$.flags.q.invariant = 1; + $$.precision = $1; } - | INVARIANT + ; + +auxiliary_storage_qualifier: + CENTROID { memset(& $$, 0, sizeof($$)); - $$.flags.q.invariant = 1; + $$.flags.q.centroid = 1; } - ; + /* TODO: "sample" and "patch" also go here someday. */ storage_qualifier: CONST_TOK @@ -1361,12 +1490,6 @@ storage_qualifier: memset(& $$, 0, sizeof($$)); $$.flags.q.varying = 1; } - | CENTROID VARYING - { - memset(& $$, 0, sizeof($$)); - $$.flags.q.centroid = 1; - $$.flags.q.varying = 1; - } | IN_TOK { memset(& $$, 0, sizeof($$)); @@ -1377,16 +1500,6 @@ storage_qualifier: memset(& $$, 0, sizeof($$)); $$.flags.q.out = 1; } - | CENTROID IN_TOK - { - memset(& $$, 0, sizeof($$)); - $$.flags.q.centroid = 1; $$.flags.q.in = 1; - } - | CENTROID OUT_TOK - { - memset(& $$, 0, sizeof($$)); - $$.flags.q.centroid = 1; $$.flags.q.out = 1; - } | UNIFORM { memset(& $$, 0, sizeof($$)); @@ -1395,18 +1508,6 @@ storage_qualifier: ; type_specifier: - type_specifier_no_prec - { - $$ = $1; - } - | precision_qualifier type_specifier_no_prec - { - $$ = $2; - $$->precision = $1; - } - ; - -type_specifier_no_prec: type_specifier_nonarray | type_specifier_nonarray '[' ']' { diff --git a/mesalib/src/glsl/ir.h b/mesalib/src/glsl/ir.h index 1f0dc0906..7ac291cf4 100644 --- a/mesalib/src/glsl/ir.h +++ b/mesalib/src/glsl/ir.h @@ -471,6 +471,14 @@ public: unsigned explicit_index:1; /** + * Was an initial binding explicitly set in the shader? + * + * If so, constant_value contains an integer ir_constant representing the + * initial binding point. + */ + unsigned explicit_binding:1; + + /** * Does this variable have an initializer? * * This is used by the linker to cross-validiate initializers of global @@ -528,6 +536,13 @@ public: int index; /** + * Initial binding point for a sampler or UBO. + * + * For array types, this represents the binding point for the first element. + */ + int binding; + + /** * Built-in state that backs this uniform * * Once set at variable creation, \c state_slots must remain invariant. diff --git a/mesalib/src/glsl/ir_clone.cpp b/mesalib/src/glsl/ir_clone.cpp index 5b42935f8..9d4178de8 100644 --- a/mesalib/src/glsl/ir_clone.cpp +++ b/mesalib/src/glsl/ir_clone.cpp @@ -50,11 +50,13 @@ ir_variable::clone(void *mem_ctx, struct hash_table *ht) const var->interpolation = this->interpolation; var->location = this->location; var->index = this->index; + var->binding = this->binding; var->warn_extension = this->warn_extension; var->origin_upper_left = this->origin_upper_left; var->pixel_center_integer = this->pixel_center_integer; var->explicit_location = this->explicit_location; var->explicit_index = this->explicit_index; + var->explicit_binding = this->explicit_binding; var->has_initializer = this->has_initializer; var->depth_layout = this->depth_layout; diff --git a/mesalib/src/glsl/ir_optimization.h b/mesalib/src/glsl/ir_optimization.h index fad6f1bfe..2c1479ff4 100644 --- a/mesalib/src/glsl/ir_optimization.h +++ b/mesalib/src/glsl/ir_optimization.h @@ -61,7 +61,7 @@ enum lower_packing_builtins_op { LOWER_UNPACK_SNORM_4x8 = 0x0200, LOWER_PACK_UNORM_4x8 = 0x0400, - LOWER_UNPACK_UNORM_4x8 = 0x0800, + LOWER_UNPACK_UNORM_4x8 = 0x0800 }; bool do_common_optimization(exec_list *ir, bool linked, diff --git a/mesalib/src/glsl/link_uniform_initializers.cpp b/mesalib/src/glsl/link_uniform_initializers.cpp index 54d9bf1f5..3f6671047 100644 --- a/mesalib/src/glsl/link_uniform_initializers.cpp +++ b/mesalib/src/glsl/link_uniform_initializers.cpp @@ -82,6 +82,56 @@ copy_constant_to_storage(union gl_constant_value *storage, } void +set_uniform_binding(void *mem_ctx, gl_shader_program *prog, + const char *name, const glsl_type *type, int binding) +{ + struct gl_uniform_storage *const storage = + get_storage(prog->UniformStorage, prog->NumUserUniformStorage, name); + + if (storage == NULL) { + assert(storage != NULL); + return; + } + + if (storage->type->is_sampler()) { + unsigned elements = MAX2(storage->array_elements, 1); + + /* From section 4.4.4 of the GLSL 4.20 specification: + * "If the binding identifier is used with an array, the first element + * of the array takes the specified unit and each subsequent element + * takes the next consecutive unit." + */ + for (unsigned int i = 0; i < elements; i++) { + storage->storage[i].i = binding + i; + } + + for (int sh = 0; sh < MESA_SHADER_TYPES; sh++) { + gl_shader *shader = prog->_LinkedShaders[sh]; + + if (shader && storage->sampler[sh].active) { + for (unsigned i = 0; i < elements; i++) { + unsigned index = storage->sampler[sh].index + i; + + shader->SamplerUnits[index] = storage->storage[i].i; + } + } + } + } else if (storage->block_index != -1) { + /* This is a field of a UBO. val is the binding index. */ + for (int i = 0; i < MESA_SHADER_TYPES; i++) { + int stage_index = prog->UniformBlockStageIndex[i][storage->block_index]; + + if (stage_index != -1) { + struct gl_shader *sh = prog->_LinkedShaders[i]; + sh->UniformBlocks[stage_index].Binding = binding; + } + } + } + + storage->initialized = true; +} + +void set_uniform_initializer(void *mem_ctx, gl_shader_program *prog, const char *name, const glsl_type *type, ir_constant *val) @@ -136,20 +186,6 @@ set_uniform_initializer(void *mem_ctx, gl_shader_program *prog, idx += elements; } - - if (base_type == GLSL_TYPE_SAMPLER) { - for (int sh = 0; sh < MESA_SHADER_TYPES; sh++) { - gl_shader *shader = prog->_LinkedShaders[sh]; - - if (shader && storage->sampler[sh].active) { - for (unsigned i = 0; i < storage->array_elements; i++) { - unsigned index = storage->sampler[sh].index + i; - - shader->SamplerUnits[index] = storage->storage[i].i; - } - } - } - } } else { copy_constant_to_storage(storage->storage, val, @@ -187,14 +223,19 @@ link_set_uniform_initializers(struct gl_shader_program *prog) foreach_list(node, shader->ir) { ir_variable *const var = ((ir_instruction *) node)->as_variable(); - if (!var || var->mode != ir_var_uniform || !var->constant_value) + if (!var || var->mode != ir_var_uniform) continue; if (!mem_ctx) mem_ctx = ralloc_context(NULL); - linker::set_uniform_initializer(mem_ctx, prog, var->name, - var->type, var->constant_value); + if (var->explicit_binding) { + linker::set_uniform_binding(mem_ctx, prog, var->name, + var->type, var->binding); + } else if (var->constant_value) { + linker::set_uniform_initializer(mem_ctx, prog, var->name, + var->type, var->constant_value); + } } } diff --git a/mesalib/src/glsl/linker.cpp b/mesalib/src/glsl/linker.cpp index ba97ade25..ac010cfbb 100644 --- a/mesalib/src/glsl/linker.cpp +++ b/mesalib/src/glsl/linker.cpp @@ -541,6 +541,25 @@ cross_validate_globals(struct gl_shader_program *prog, existing->explicit_location = true; } + /* From the GLSL 4.20 specification: + * "A link error will result if two compilation units in a program + * specify different integer-constant bindings for the same + * opaque-uniform name. However, it is not an error to specify a + * binding on some but not all declarations for the same name" + */ + if (var->explicit_binding) { + if (existing->explicit_binding && + var->binding != existing->binding) { + linker_error(prog, "explicit bindings for %s " + "`%s' have differing values\n", + mode_string(var), var->name); + return false; + } + + existing->binding = var->binding; + existing->explicit_binding = true; + } + /* Validate layout qualifiers for gl_FragDepth. * * From the AMD/ARB_conservative_depth specs: @@ -1147,7 +1166,7 @@ update_array_sizes(struct gl_shader_program *prog) } } - if (size + 1 != var->type->fields.array->length) { + if (size + 1 != var->type->length) { /* If this is a built-in uniform (i.e., it's backed by some * fixed-function state), adjust the number of state slots to * match the new array size. The number of slots per array entry |