aboutsummaryrefslogtreecommitdiff
path: root/mesalib/src/glsl
diff options
context:
space:
mode:
Diffstat (limited to 'mesalib/src/glsl')
-rw-r--r--mesalib/src/glsl/ast.h49
-rw-r--r--mesalib/src/glsl/ast_to_hir.cpp135
-rw-r--r--mesalib/src/glsl/ast_type.cpp39
-rw-r--r--mesalib/src/glsl/builtin_compiler/Makefile.am13
-rw-r--r--mesalib/src/glsl/glsl_lexer.ll3
-rw-r--r--mesalib/src/glsl/glsl_parser.yy247
-rw-r--r--mesalib/src/glsl/ir.h15
-rw-r--r--mesalib/src/glsl/ir_clone.cpp2
-rw-r--r--mesalib/src/glsl/ir_optimization.h2
-rw-r--r--mesalib/src/glsl/link_uniform_initializers.cpp75
-rw-r--r--mesalib/src/glsl/linker.cpp21
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