diff options
Diffstat (limited to 'mesalib/src/glsl')
-rw-r--r-- | mesalib/src/glsl/Makefile.sources | 1 | ||||
-rw-r--r--[-rwxr-xr-x] | mesalib/src/glsl/ast.h | 15 | ||||
-rw-r--r-- | mesalib/src/glsl/ast_to_hir.cpp | 63 | ||||
-rw-r--r-- | mesalib/src/glsl/ast_type.cpp | 13 | ||||
-rw-r--r-- | mesalib/src/glsl/builtin_functions.cpp | 3 | ||||
-rw-r--r-- | mesalib/src/glsl/glsl_lexer.ll | 2 | ||||
-rw-r--r-- | mesalib/src/glsl/glsl_parser.yy | 13 | ||||
-rw-r--r--[-rwxr-xr-x] | mesalib/src/glsl/glsl_parser_extras.h | 3 | ||||
-rw-r--r-- | mesalib/src/glsl/link_atomics.cpp | 277 | ||||
-rw-r--r-- | mesalib/src/glsl/linker.cpp | 21 | ||||
-rw-r--r-- | mesalib/src/glsl/linker.h | 8 | ||||
-rw-r--r--[-rwxr-xr-x] | mesalib/src/glsl/list.h | 0 |
12 files changed, 411 insertions, 8 deletions
diff --git a/mesalib/src/glsl/Makefile.sources b/mesalib/src/glsl/Makefile.sources index 2aabc0585..744b0adcf 100644 --- a/mesalib/src/glsl/Makefile.sources +++ b/mesalib/src/glsl/Makefile.sources @@ -47,6 +47,7 @@ LIBGLSL_FILES = \ $(GLSL_SRCDIR)/ir_validate.cpp \ $(GLSL_SRCDIR)/ir_variable_refcount.cpp \ $(GLSL_SRCDIR)/linker.cpp \ + $(GLSL_SRCDIR)/link_atomics.cpp \ $(GLSL_SRCDIR)/link_functions.cpp \ $(GLSL_SRCDIR)/link_interface_blocks.cpp \ $(GLSL_SRCDIR)/link_uniforms.cpp \ diff --git a/mesalib/src/glsl/ast.h b/mesalib/src/glsl/ast.h index 2307a7878..9c43920a4 100755..100644 --- a/mesalib/src/glsl/ast.h +++ b/mesalib/src/glsl/ast.h @@ -389,6 +389,12 @@ struct ast_type_qualifier { */ unsigned explicit_binding:1; + /** + * Flag set if GL_ARB_shader_atomic counter "offset" layout + * qualifier is used. + */ + unsigned explicit_offset:1; + /** \name Layout qualifiers for GL_AMD_conservative_depth */ /** \{ */ unsigned depth_any:1; @@ -452,6 +458,15 @@ struct ast_type_qualifier { int binding; /** + * Offset specified via GL_ARB_shader_atomic_counter's "offset" + * keyword. + * + * \note + * This field is only valid if \c explicit_offset is set. + */ + int offset; + + /** * Return true if and only if an interpolation qualifier is present. */ bool has_interpolation() const; diff --git a/mesalib/src/glsl/ast_to_hir.cpp b/mesalib/src/glsl/ast_to_hir.cpp index f75e68ce1..76b256c73 100644 --- a/mesalib/src/glsl/ast_to_hir.cpp +++ b/mesalib/src/glsl/ast_to_hir.cpp @@ -1997,10 +1997,20 @@ validate_binding_qualifier(struct _mesa_glsl_parse_state *state, return false; } + } else if (var->type->contains_atomic()) { + assert(ctx->Const.MaxAtomicBufferBindings <= MAX_COMBINED_ATOMIC_BUFFERS); + if (unsigned(qual->binding) >= ctx->Const.MaxAtomicBufferBindings) { + _mesa_glsl_error(loc, state, "layout(binding = %d) exceeds the " + " maximum number of atomic counter buffer bindings" + "(%d)", qual->binding, + ctx->Const.MaxAtomicBufferBindings); + + return false; + } } else { _mesa_glsl_error(loc, state, "the \"binding\" qualifier only applies to uniform " - "blocks, samplers, or arrays of samplers"); + "blocks, samplers, atomic counters, or arrays thereof"); return false; } @@ -2300,6 +2310,29 @@ apply_type_qualifier_to_variable(const struct ast_type_qualifier *qual, var->binding = qual->binding; } + if (var->type->contains_atomic()) { + if (var->mode == ir_var_uniform) { + if (var->explicit_binding) { + unsigned *offset = &state->atomic_counter_offsets[var->binding]; + + if (*offset % ATOMIC_COUNTER_SIZE) + _mesa_glsl_error(loc, state, + "misaligned atomic counter offset"); + + var->atomic.offset = *offset; + *offset += var->type->atomic_size(); + + } else { + _mesa_glsl_error(loc, state, + "atomic counters require explicit binding point"); + } + } else if (var->mode != ir_var_function_in) { + _mesa_glsl_error(loc, state, "atomic counters may only be declared as " + "function parameters or uniform-qualified " + "global variables"); + } + } + /* Does the declaration use the deprecated 'attribute' or 'varying' * keywords? */ @@ -2835,6 +2868,18 @@ ast_declarator_list::hir(exec_list *instructions, (void) this->type->specifier->hir(instructions, state); decl_type = this->type->glsl_type(& type_name, state); + + /* An offset-qualified atomic counter declaration sets the default + * offset for the next declaration within the same atomic counter + * buffer. + */ + if (decl_type && decl_type->contains_atomic()) { + if (type->qualifier.flags.q.explicit_binding && + type->qualifier.flags.q.explicit_offset) + state->atomic_counter_offsets[type->qualifier.binding] = + type->qualifier.offset; + } + if (this->declarations.is_empty()) { /* If there is no structure involved in the program text, there are two * possible scenarios: @@ -2864,6 +2909,11 @@ ast_declarator_list::hir(exec_list *instructions, _mesa_glsl_error(&loc, state, "invalid type `%s' in empty declaration", type_name); + } else if (decl_type->base_type == GLSL_TYPE_ATOMIC_UINT) { + /* Empty atomic counter declarations are allowed and useful + * to set the default offset qualifier. + */ + return NULL; } else if (this->type->qualifier.precision != ast_precision_none) { if (this->type->specifier->structure != NULL) { _mesa_glsl_error(&loc, state, @@ -4565,6 +4615,17 @@ ast_process_structure_or_interface_block(exec_list *instructions, "uniform in non-default uniform block contains sampler"); } + if (field_type->contains_atomic()) { + /* FINISHME: Add a spec quotation here once updated spec + * FINISHME: language is available. See Khronos bug #10903 + * FINISHME: on whether atomic counters are allowed in + * FINISHME: structures. + */ + YYLTYPE loc = decl_list->get_location(); + _mesa_glsl_error(&loc, state, "atomic counter in structure or " + "uniform block"); + } + const struct ast_type_qualifier *const qual = & decl_list->type->qualifier; if (qual->flags.q.std140 || diff --git a/mesalib/src/glsl/ast_type.cpp b/mesalib/src/glsl/ast_type.cpp index 8aabd95f9..2b088bf8b 100644 --- a/mesalib/src/glsl/ast_type.cpp +++ b/mesalib/src/glsl/ast_type.cpp @@ -72,7 +72,8 @@ ast_type_qualifier::has_layout() const || this->flags.q.packed || this->flags.q.explicit_location || this->flags.q.explicit_index - || this->flags.q.explicit_binding; + || this->flags.q.explicit_binding + || this->flags.q.explicit_offset; } bool @@ -121,13 +122,18 @@ ast_type_qualifier::merge_qualifier(YYLTYPE *loc, ubo_layout_mask.flags.q.packed = 1; ubo_layout_mask.flags.q.shared = 1; + ast_type_qualifier ubo_binding_mask; + ubo_binding_mask.flags.q.explicit_binding = 1; + ubo_binding_mask.flags.q.explicit_offset = 1; + /* Uniform block layout qualifiers get to overwrite each * other (rightmost having priority), while all other * qualifiers currently don't allow duplicates. */ if ((this->flags.i & q.flags.i & ~(ubo_mat_mask.flags.i | - ubo_layout_mask.flags.i)) != 0) { + ubo_layout_mask.flags.i | + ubo_binding_mask.flags.i)) != 0) { _mesa_glsl_error(loc, state, "duplicate layout qualifiers used"); return false; @@ -168,6 +174,9 @@ ast_type_qualifier::merge_qualifier(YYLTYPE *loc, if (q.flags.q.explicit_binding) this->binding = q.binding; + if (q.flags.q.explicit_offset) + this->offset = q.offset; + if (q.precision != ast_precision_none) this->precision = q.precision; diff --git a/mesalib/src/glsl/builtin_functions.cpp b/mesalib/src/glsl/builtin_functions.cpp index 3fa0cb5ad..8cb75e5ad 100644 --- a/mesalib/src/glsl/builtin_functions.cpp +++ b/mesalib/src/glsl/builtin_functions.cpp @@ -293,7 +293,8 @@ static bool fs_oes_derivatives(const _mesa_glsl_parse_state *state) { return state->target == fragment_shader && - (!state->es_shader || state->OES_standard_derivatives_enable); + (state->is_version(110, 300) || + state->OES_standard_derivatives_enable); } static bool diff --git a/mesalib/src/glsl/glsl_lexer.ll b/mesalib/src/glsl/glsl_lexer.ll index e24df8096..822d70d6b 100644 --- a/mesalib/src/glsl/glsl_lexer.ll +++ b/mesalib/src/glsl/glsl_lexer.ll @@ -337,6 +337,7 @@ samplerExternalOES { return IDENTIFIER; } +atomic_uint KEYWORD_WITH_ALT(420, 300, 420, 0, yyextra->ARB_shader_atomic_counters_enable, ATOMIC_UINT); struct return STRUCT; void return VOID_TOK; @@ -518,7 +519,6 @@ restrict KEYWORD(0, 300, 0, 0, RESTRICT); readonly KEYWORD(0, 300, 0, 0, READONLY); writeonly KEYWORD(0, 300, 0, 0, WRITEONLY); resource KEYWORD(0, 300, 0, 0, RESOURCE); -atomic_uint KEYWORD(0, 300, 0, 0, ATOMIC_UINT); patch KEYWORD(0, 300, 0, 0, PATCH); sample KEYWORD(0, 300, 0, 0, SAMPLE); subroutine KEYWORD(0, 300, 0, 0, SUBROUTINE); diff --git a/mesalib/src/glsl/glsl_parser.yy b/mesalib/src/glsl/glsl_parser.yy index 14420f8a3..ada3690f6 100644 --- a/mesalib/src/glsl/glsl_parser.yy +++ b/mesalib/src/glsl/glsl_parser.yy @@ -144,6 +144,7 @@ static bool match_layout_qualifier(const char *s1, const char *s2, %token SAMPLER2DMS ISAMPLER2DMS USAMPLER2DMS %token SAMPLER2DMSARRAY ISAMPLER2DMSARRAY USAMPLER2DMSARRAY %token SAMPLEREXTERNALOES +%token ATOMIC_UINT %token STRUCT VOID_TOK WHILE %token <identifier> IDENTIFIER TYPE_IDENTIFIER NEW_IDENTIFIER %type <identifier> any_identifier @@ -173,7 +174,7 @@ static bool match_layout_qualifier(const char *s1, const char *s2, %token HVEC2 HVEC3 HVEC4 DVEC2 DVEC3 DVEC4 FVEC2 FVEC3 FVEC4 %token SAMPLER3DRECT %token SIZEOF CAST NAMESPACE USING -%token COHERENT RESTRICT READONLY WRITEONLY RESOURCE ATOMIC_UINT PATCH SAMPLE +%token COHERENT RESTRICT READONLY WRITEONLY RESOURCE PATCH SAMPLE %token SUBROUTINE %token ERROR_TOK @@ -1324,12 +1325,19 @@ layout_qualifier_id: } } - if (state->ARB_shading_language_420pack_enable && + if ((state->ARB_shading_language_420pack_enable || + state->ARB_shader_atomic_counters_enable) && match_layout_qualifier("binding", $1, state) == 0) { $$.flags.q.explicit_binding = 1; $$.binding = $3; } + if (state->ARB_shader_atomic_counters_enable && + match_layout_qualifier("offset", $1, state) == 0) { + $$.flags.q.explicit_offset = 1; + $$.offset = $3; + } + if (match_layout_qualifier("max_vertices", $1, state) == 0) { $$.flags.q.max_vertices = 1; @@ -1703,6 +1711,7 @@ basic_type_specifier_nonarray: | SAMPLER2DMSARRAY { $$ = "sampler2DMSArray"; } | ISAMPLER2DMSARRAY { $$ = "isampler2DMSArray"; } | USAMPLER2DMSARRAY { $$ = "usampler2DMSArray"; } + | ATOMIC_UINT { $$ = "atomic_uint"; } ; precision_qualifier: diff --git a/mesalib/src/glsl/glsl_parser_extras.h b/mesalib/src/glsl/glsl_parser_extras.h index a30653eab..cb998d80e 100755..100644 --- a/mesalib/src/glsl/glsl_parser_extras.h +++ b/mesalib/src/glsl/glsl_parser_extras.h @@ -377,6 +377,9 @@ struct _mesa_glsl_parse_state { * Unused for other shader types. */ unsigned gs_input_size; + + /** Atomic counter offsets by binding */ + unsigned atomic_counter_offsets[MAX_COMBINED_ATOMIC_BUFFERS]; }; # define YYLLOC_DEFAULT(Current, Rhs, N) \ diff --git a/mesalib/src/glsl/link_atomics.cpp b/mesalib/src/glsl/link_atomics.cpp new file mode 100644 index 000000000..2466bbd79 --- /dev/null +++ b/mesalib/src/glsl/link_atomics.cpp @@ -0,0 +1,277 @@ +/* + * Copyright © 2013 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include "ir.h" +#include "ir_uniform.h" +#include "linker.h" +#include "program/hash_table.h" +#include "main/macros.h" + +namespace { + /* + * Atomic counter as seen by the program. + */ + struct active_atomic_counter { + unsigned id; + ir_variable *var; + }; + + /* + * Atomic counter buffer referenced by the program. There is a one + * to one correspondence between these and the objects that can be + * queried using glGetActiveAtomicCounterBufferiv(). + */ + struct active_atomic_buffer { + active_atomic_buffer() + : counters(0), num_counters(0), stage_references(), size(0) + {} + + ~active_atomic_buffer() + { + free(counters); + } + + void push_back(unsigned id, ir_variable *var) + { + counters = (active_atomic_counter *) + realloc(counters, sizeof(active_atomic_counter) * (num_counters + 1)); + + counters[num_counters].id = id; + counters[num_counters].var = var; + num_counters++; + } + + active_atomic_counter *counters; + unsigned num_counters; + unsigned stage_references[MESA_SHADER_TYPES]; + unsigned size; + }; + + int + cmp_actives(const void *a, const void *b) + { + const active_atomic_counter *const first = (active_atomic_counter *) a; + const active_atomic_counter *const second = (active_atomic_counter *) b; + + return int(first->var->atomic.offset) - int(second->var->atomic.offset); + } + + bool + check_atomic_counters_overlap(const ir_variable *x, const ir_variable *y) + { + return ((x->atomic.offset >= y->atomic.offset && + x->atomic.offset < y->atomic.offset + y->type->atomic_size()) || + (y->atomic.offset >= x->atomic.offset && + y->atomic.offset < x->atomic.offset + x->type->atomic_size())); + } + + active_atomic_buffer * + find_active_atomic_counters(struct gl_context *ctx, + struct gl_shader_program *prog, + unsigned *num_buffers) + { + active_atomic_buffer *const buffers = + new active_atomic_buffer[ctx->Const.MaxAtomicBufferBindings]; + + *num_buffers = 0; + + for (unsigned i = 0; i < MESA_SHADER_TYPES; ++i) { + struct gl_shader *sh = prog->_LinkedShaders[i]; + if (sh == NULL) + continue; + + foreach_list(node, sh->ir) { + ir_variable *var = ((ir_instruction *)node)->as_variable(); + + if (var && var->type->contains_atomic()) { + unsigned id; + bool found = prog->UniformHash->get(id, var->name); + assert(found); + active_atomic_buffer *buf = &buffers[var->binding]; + + /* If this is the first time the buffer is used, increment + * the counter of buffers used. + */ + if (buf->size == 0) + (*num_buffers)++; + + buf->push_back(id, var); + + buf->stage_references[i]++; + buf->size = MAX2(buf->size, var->atomic.offset + + var->type->atomic_size()); + } + } + } + + for (unsigned i = 0; i < ctx->Const.MaxAtomicBufferBindings; i++) { + if (buffers[i].size == 0) + continue; + + qsort(buffers[i].counters, buffers[i].num_counters, + sizeof(active_atomic_counter), + cmp_actives); + + for (unsigned j = 1; j < buffers[i].num_counters; j++) { + /* If an overlapping counter found, it must be a reference to the + * same counter from a different shader stage. + */ + if (check_atomic_counters_overlap(buffers[i].counters[j-1].var, + buffers[i].counters[j].var) + && strcmp(buffers[i].counters[j-1].var->name, + buffers[i].counters[j].var->name) != 0) { + linker_error(prog, "Atomic counter %s declared at offset %d " + "which is already in use.", + buffers[i].counters[j].var->name, + buffers[i].counters[j].var->atomic.offset); + } + } + } + return buffers; + } +} + +void +link_assign_atomic_counter_resources(struct gl_context *ctx, + struct gl_shader_program *prog) +{ + unsigned num_buffers; + active_atomic_buffer *abs = + find_active_atomic_counters(ctx, prog, &num_buffers); + + prog->AtomicBuffers = rzalloc_array(prog, gl_active_atomic_buffer, + num_buffers); + prog->NumAtomicBuffers = num_buffers; + + unsigned i = 0; + for (unsigned binding = 0; + binding < ctx->Const.MaxAtomicBufferBindings; + binding++) { + + /* If the binding was not used, skip. + */ + if (abs[binding].size == 0) + continue; + + active_atomic_buffer &ab = abs[binding]; + gl_active_atomic_buffer &mab = prog->AtomicBuffers[i]; + + /* Assign buffer-specific fields. */ + mab.Binding = binding; + mab.MinimumSize = ab.size; + mab.Uniforms = rzalloc_array(prog->AtomicBuffers, GLuint, + ab.num_counters); + mab.NumUniforms = ab.num_counters; + + /* Assign counter-specific fields. */ + for (unsigned j = 0; j < ab.num_counters; j++) { + ir_variable *const var = ab.counters[j].var; + const unsigned id = ab.counters[j].id; + gl_uniform_storage *const storage = &prog->UniformStorage[id]; + + mab.Uniforms[j] = id; + var->atomic.buffer_index = i; + storage->atomic_buffer_index = i; + storage->offset = var->atomic.offset; + storage->array_stride = (var->type->is_array() ? + var->type->element_type()->atomic_size() : 0); + } + + /* Assign stage-specific fields. */ + for (unsigned j = 0; j < MESA_SHADER_TYPES; ++j) + mab.StageReferences[j] = + (ab.stage_references[j] ? GL_TRUE : GL_FALSE); + + i++; + } + + delete [] abs; + assert(i == num_buffers); +} + +void +link_check_atomic_counter_resources(struct gl_context *ctx, + struct gl_shader_program *prog) +{ + STATIC_ASSERT(MESA_SHADER_TYPES == 3); + static const char *shader_names[MESA_SHADER_TYPES] = { + "vertex", "geometry", "fragment" + }; + const unsigned max_atomic_counters[MESA_SHADER_TYPES] = { + ctx->Const.VertexProgram.MaxAtomicCounters, + ctx->Const.GeometryProgram.MaxAtomicCounters, + ctx->Const.FragmentProgram.MaxAtomicCounters + }; + const unsigned max_atomic_buffers[MESA_SHADER_TYPES] = { + ctx->Const.VertexProgram.MaxAtomicBuffers, + ctx->Const.GeometryProgram.MaxAtomicBuffers, + ctx->Const.FragmentProgram.MaxAtomicBuffers + }; + unsigned num_buffers; + active_atomic_buffer *const abs = + find_active_atomic_counters(ctx, prog, &num_buffers); + unsigned atomic_counters[MESA_SHADER_TYPES] = {}; + unsigned atomic_buffers[MESA_SHADER_TYPES] = {}; + unsigned total_atomic_counters = 0; + unsigned total_atomic_buffers = 0; + + /* Sum the required resources. Note that this counts buffers and + * counters referenced by several shader stages multiple times + * against the combined limit -- That's the behavior the spec + * requires. + */ + for (unsigned i = 0; i < ctx->Const.MaxAtomicBufferBindings; i++) { + if (abs[i].size == 0) + continue; + + for (unsigned j = 0; j < MESA_SHADER_TYPES; ++j) { + const unsigned n = abs[i].stage_references[j]; + + if (n) { + atomic_counters[j] += n; + total_atomic_counters += n; + atomic_buffers[j]++; + total_atomic_buffers++; + } + } + } + + /* Check that they are within the supported limits. */ + for (unsigned i = 0; i < MESA_SHADER_TYPES; i++) { + if (atomic_counters[i] > max_atomic_counters[i]) + linker_error(prog, "Too many %s shader atomic counters", + shader_names[i]); + + if (atomic_buffers[i] > max_atomic_buffers[i]) + linker_error(prog, "Too many %s shader atomic counter buffers", + shader_names[i]); + } + + if (total_atomic_counters > ctx->Const.MaxCombinedAtomicCounters) + linker_error(prog, "Too many combined atomic counters"); + + if (total_atomic_buffers > ctx->Const.MaxCombinedAtomicBuffers) + linker_error(prog, "Too many combined atomic buffers"); + + delete [] abs; +} diff --git a/mesalib/src/glsl/linker.cpp b/mesalib/src/glsl/linker.cpp index 49bb142a8..1d53b6599 100644 --- a/mesalib/src/glsl/linker.cpp +++ b/mesalib/src/glsl/linker.cpp @@ -651,6 +651,14 @@ cross_validate_globals(struct gl_shader_program *prog, existing->explicit_binding = true; } + if (var->type->contains_atomic() && + var->atomic.offset != existing->atomic.offset) { + linker_error(prog, "offset specifications for %s " + "`%s' have differing values\n", + mode_string(var), var->name); + return; + } + /* Validate layout qualifiers for gl_FragDepth. * * From the AMD/ARB_conservative_depth specs: @@ -1485,8 +1493,12 @@ update_array_sizes(struct gl_shader_program *prog) /* GL_ARB_uniform_buffer_object says that std140 uniforms * will not be eliminated. Since we always do std140, just * don't resize arrays in UBOs. + * + * Atomic counters are supposed to get deterministic + * locations assigned based on the declaration ordering and + * sizes, array compaction would mess that up. */ - if (var->is_in_uniform_block()) + if (var->is_in_uniform_block() || var->type->contains_atomic()) continue; unsigned int size = var->max_array_access; @@ -1991,6 +2003,10 @@ link_shaders(struct gl_context *ctx, struct gl_shader_program *prog) prog->UniformBlockStageIndex[i] = NULL; } + ralloc_free(prog->AtomicBuffers); + prog->AtomicBuffers = NULL; + prog->NumAtomicBuffers = 0; + /* Separate the shaders into groups based on their type. */ struct gl_shader **vert_shader_list; @@ -2342,9 +2358,12 @@ link_shaders(struct gl_context *ctx, struct gl_shader_program *prog) update_array_sizes(prog); link_assign_uniform_locations(prog); + link_assign_atomic_counter_resources(ctx, prog); store_fragdepth_layout(prog); check_resources(ctx, prog); + link_check_atomic_counter_resources(ctx, prog); + if (!prog->LinkStatus) goto done; diff --git a/mesalib/src/glsl/linker.h b/mesalib/src/glsl/linker.h index 887cd33d1..7b1f6f9c5 100644 --- a/mesalib/src/glsl/linker.h +++ b/mesalib/src/glsl/linker.h @@ -69,6 +69,14 @@ validate_interstage_interface_blocks(struct gl_shader_program *prog, const gl_shader *producer, const gl_shader *consumer); +extern void +link_assign_atomic_counter_resources(struct gl_context *ctx, + struct gl_shader_program *prog); + +extern void +link_check_atomic_counter_resources(struct gl_context *ctx, + struct gl_shader_program *prog); + /** * Class for processing all of the leaf fields of a variable that corresponds * to a program resource. diff --git a/mesalib/src/glsl/list.h b/mesalib/src/glsl/list.h index 2934539fe..2934539fe 100755..100644 --- a/mesalib/src/glsl/list.h +++ b/mesalib/src/glsl/list.h |