X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fcompiler%2Fglsl%2Flink_uniforms.cpp;h=d588f3fc190fe55e9dfea4356951843b89e9a2e4;hb=08dc541b662c39ebae80935d4845b2f40e92d028;hp=9f8adcc11544ba65b057f804f4f53fc17fb38d79;hpb=42ba435fd16c3372dbc47f6b52deb309a1873b25;p=mesa.git diff --git a/src/compiler/glsl/link_uniforms.cpp b/src/compiler/glsl/link_uniforms.cpp index 9f8adcc1154..d588f3fc190 100644 --- a/src/compiler/glsl/link_uniforms.cpp +++ b/src/compiler/glsl/link_uniforms.cpp @@ -21,13 +21,14 @@ * DEALINGS IN THE SOFTWARE. */ -#include "main/core.h" #include "ir.h" #include "linker.h" #include "ir_uniform.h" #include "glsl_symbol_table.h" -#include "program/hash_table.h" #include "program.h" +#include "string_to_uint_map.h" +#include "ir_array_refcount.h" +#include "main/mtypes.h" /** * \file link_uniforms.cpp @@ -41,30 +42,18 @@ */ #define UNMAPPED_UNIFORM_LOC ~0u -/** - * Count the backing storage requirements for a type - */ -static unsigned -values_for_type(const glsl_type *type) -{ - if (type->is_sampler()) { - return 1; - } else if (type->is_array() && type->fields.array->is_sampler()) { - return type->array_size(); - } else { - return type->component_slots(); - } -} - void -program_resource_visitor::process(const glsl_type *type, const char *name) +program_resource_visitor::process(const glsl_type *type, const char *name, + bool use_std430_as_default) { - assert(type->without_array()->is_record() + assert(type->without_array()->is_struct() || type->without_array()->is_interface()); unsigned record_array_count = 1; char *name_copy = ralloc_strdup(NULL, name); - enum glsl_interface_packing packing = type->get_interface_packing(); + + enum glsl_interface_packing packing = + type->get_internal_ifc_packing(use_std430_as_default); recursion(type, &name_copy, strlen(name), false, NULL, packing, false, record_array_count, NULL); @@ -72,25 +61,34 @@ program_resource_visitor::process(const glsl_type *type, const char *name) } void -program_resource_visitor::process(ir_variable *var) +program_resource_visitor::process(ir_variable *var, bool use_std430_as_default) +{ + const glsl_type *t = + var->data.from_named_ifc_block ? var->get_interface_type() : var->type; + process(var, t, use_std430_as_default); +} + +void +program_resource_visitor::process(ir_variable *var, const glsl_type *var_type, + bool use_std430_as_default) { unsigned record_array_count = 1; const bool row_major = var->data.matrix_layout == GLSL_MATRIX_LAYOUT_ROW_MAJOR; - const enum glsl_interface_packing packing = var->get_interface_type() ? - var->get_interface_type_packing() : - var->type->get_interface_packing(); + enum glsl_interface_packing packing = var->get_interface_type() ? + var->get_interface_type()-> + get_internal_ifc_packing(use_std430_as_default) : + var->type->get_internal_ifc_packing(use_std430_as_default); - const glsl_type *t = - var->data.from_named_ifc_block ? var->get_interface_type() : var->type; + const glsl_type *t = var_type; const glsl_type *t_without_array = t->without_array(); /* false is always passed for the row_major parameter to the other * processing functions because no information is available to do * otherwise. See the warning in linker.h. */ - if (t_without_array->is_record() || + if (t_without_array->is_struct() || (t->is_array() && t->fields.array->is_array())) { char *name = ralloc_strdup(NULL, var->name); recursion(var->type, &name, strlen(name), row_major, NULL, packing, @@ -131,20 +129,17 @@ program_resource_visitor::recursion(const glsl_type *t, char **name, named_ifc_member->name); recursion(named_ifc_member->type, name, name_length, row_major, NULL, packing, false, record_array_count, NULL); - } else if (t->is_record() || t->is_interface()) { - if (record_type == NULL && t->is_record()) + } else if (t->is_struct() || t->is_interface()) { + if (record_type == NULL && t->is_struct()) record_type = t; - if (t->is_record()) + if (t->is_struct()) this->enter_record(t, *name, row_major, packing); for (unsigned i = 0; i < t->length; i++) { const char *field = t->fields.structure[i].name; size_t new_length = name_length; - if (t->fields.structure[i].type->is_record()) - this->visit_field(&t->fields.structure[i]); - if (t->is_interface() && t->fields.structure[i].offset != -1) this->set_buffer_offset(t->fields.structure[i].offset); @@ -182,19 +177,21 @@ program_resource_visitor::recursion(const glsl_type *t, char **name, record_type = NULL; } - if (t->is_record()) { + if (t->is_struct()) { (*name)[name_length] = '\0'; this->leave_record(t, *name, row_major, packing); } - } else if (t->without_array()->is_record() || + } else if (t->without_array()->is_struct() || t->without_array()->is_interface() || (t->is_array() && t->fields.array->is_array())) { - if (record_type == NULL && t->fields.array->is_record()) + if (record_type == NULL && t->fields.array->is_struct()) record_type = t->fields.array; unsigned length = t->length; + /* Shader storage block unsized arrays: add subscript [0] to variable - * names */ + * names. + */ if (t->is_unsized_array()) length = 1; @@ -223,23 +220,6 @@ program_resource_visitor::recursion(const glsl_type *t, char **name, } } -void -program_resource_visitor::visit_field(const glsl_type *type, const char *name, - bool row_major, - const glsl_type *, - const enum glsl_interface_packing, - bool /* last_field */) -{ - visit_field(type, name, row_major); -} - -void -program_resource_visitor::visit_field(const glsl_struct_field *field) -{ - (void) field; - /* empty */ -} - void program_resource_visitor::enter_record(const glsl_type *, const char *, bool, const enum glsl_interface_packing) @@ -277,12 +257,14 @@ namespace { class count_uniform_size : public program_resource_visitor { public: count_uniform_size(struct string_to_uint_map *map, - struct string_to_uint_map *hidden_map) + struct string_to_uint_map *hidden_map, + bool use_std430_as_default) : num_active_uniforms(0), num_hidden_uniforms(0), num_values(0), num_shader_samplers(0), num_shader_images(0), num_shader_uniform_components(0), num_shader_subroutines(0), is_buffer_block(false), is_shader_storage(false), map(map), - hidden_map(hidden_map) + hidden_map(hidden_map), current_var(NULL), + use_std430_as_default(use_std430_as_default) { /* empty */ } @@ -302,9 +284,10 @@ public: this->is_shader_storage = var->is_in_shader_storage_block(); if (var->is_interface_instance()) program_resource_visitor::process(var->get_interface_type(), - var->get_interface_type()->name); + var->get_interface_type()->name, + use_std430_as_default); else - program_resource_visitor::process(var); + program_resource_visitor::process(var, use_std430_as_default); } /** @@ -346,33 +329,38 @@ public: private: virtual void visit_field(const glsl_type *type, const char *name, - bool row_major) + bool /* row_major */, + const glsl_type * /* record_type */, + const enum glsl_interface_packing, + bool /* last_field */) { - assert(!type->without_array()->is_record()); + assert(!type->without_array()->is_struct()); assert(!type->without_array()->is_interface()); assert(!(type->is_array() && type->fields.array->is_array())); - (void) row_major; - /* Count the number of samplers regardless of whether the uniform is * already in the hash table. The hash table prevents adding the same * uniform for multiple shader targets, but in this case we want to * count it for each shader target. */ - const unsigned values = values_for_type(type); + const unsigned values = type->component_slots(); if (type->contains_subroutine()) { this->num_shader_subroutines += values; - } else if (type->contains_sampler()) { - this->num_shader_samplers += values; - } else if (type->contains_image()) { - this->num_shader_images += values; + } else if (type->contains_sampler() && !current_var->data.bindless) { + /* Samplers (bound or bindless) are counted as two components as + * specified by ARB_bindless_texture. */ + this->num_shader_samplers += values / 2; + } else if (type->contains_image() && !current_var->data.bindless) { + /* Images (bound or bindless) are counted as two components as + * specified by ARB_bindless_texture. */ + this->num_shader_images += values / 2; /* As drivers are likely to represent image uniforms as * scalar indices, count them against the limit of uniform * components in the default block. The spec allows image * uniforms to use up no more than one scalar slot. */ - if(!is_shader_storage) + if (!is_shader_storage) this->num_shader_uniform_components += values; } else { /* Accumulate the total number of uniform slots used by this shader. @@ -412,10 +400,54 @@ private: * Current variable being processed. */ ir_variable *current_var; + + bool use_std430_as_default; }; } /* anonymous namespace */ +unsigned +link_calculate_matrix_stride(const glsl_type *matrix, bool row_major, + enum glsl_interface_packing packing) +{ + const unsigned N = matrix->is_double() ? 8 : 4; + const unsigned items = + row_major ? matrix->matrix_columns : matrix->vector_elements; + + assert(items <= 4); + + /* Matrix stride for std430 mat2xY matrices are not rounded up to + * vec4 size. + * + * Section 7.6.2.2 "Standard Uniform Block Layout" of the OpenGL 4.3 spec + * says: + * + * 2. If the member is a two- or four-component vector with components + * consuming N basic machine units, the base alignment is 2N or 4N, + * respectively. + * ... + * 4. If the member is an array of scalars or vectors, the base + * alignment and array stride are set to match the base alignment of + * a single array element, according to rules (1), (2), and (3), and + * rounded up to the base alignment of a vec4. + * ... + * 7. If the member is a row-major matrix with C columns and R rows, the + * matrix is stored identically to an array of R row vectors with C + * components each, according to rule (4). + * ... + * + * When using the std430 storage layout, shader storage blocks will be + * laid out in buffer storage identically to uniform and shader storage + * blocks using the std140 layout, except that the base alignment and + * stride of arrays of scalars and vectors in rule 4 and of structures + * in rule 9 are not rounded up a multiple of the base alignment of a + * vec4. + */ + return packing == GLSL_INTERFACE_PACKING_STD430 + ? (items < 3 ? items * N : glsl_align(items * N, 16)) + : glsl_align(items * N, 16); +} + /** * Class to help parcel out pieces of backing storage to uniforms * @@ -436,11 +468,21 @@ public: parcel_out_uniform_storage(struct gl_shader_program *prog, struct string_to_uint_map *map, struct gl_uniform_storage *uniforms, - union gl_constant_value *values) - : prog(prog), map(map), uniforms(uniforms), values(values) + union gl_constant_value *values, + bool use_std430_as_default) + : prog(prog), map(map), uniforms(uniforms), + use_std430_as_default(use_std430_as_default), values(values), + bindless_targets(NULL), bindless_access(NULL), + shader_storage_blocks_write_access(0) { } + virtual ~parcel_out_uniform_storage() + { + free(this->bindless_targets); + free(this->bindless_access); + } + void start_shader(gl_shader_stage shader_type) { assert(shader_type < MESA_SHADER_STAGES); @@ -453,6 +495,17 @@ public: this->next_subroutine = 0; this->record_array_count = 1; memset(this->targets, 0, sizeof(this->targets)); + + this->num_bindless_samplers = 0; + this->next_bindless_sampler = 0; + free(this->bindless_targets); + this->bindless_targets = NULL; + + this->num_bindless_images = 0; + this->next_bindless_image = 0; + free(this->bindless_access); + this->bindless_access = NULL; + this->shader_storage_blocks_write_access = 0; } void set_and_process(ir_variable *var) @@ -460,15 +513,20 @@ public: current_var = var; field_counter = 0; this->record_next_sampler = new string_to_uint_map; + this->record_next_bindless_sampler = new string_to_uint_map; + this->record_next_image = new string_to_uint_map; + this->record_next_bindless_image = new string_to_uint_map; buffer_block_index = -1; if (var->is_in_buffer_block()) { struct gl_uniform_block *blks = var->is_in_shader_storage_block() ? - prog->ShaderStorageBlocks : prog->UniformBlocks; + prog->data->ShaderStorageBlocks : prog->data->UniformBlocks; unsigned num_blks = var->is_in_shader_storage_block() ? - prog->NumShaderStorageBlocks : prog->NumUniformBlocks; + prog->data->NumShaderStorageBlocks : prog->data->NumUniformBlocks; + bool is_interface_array = + var->is_interface_instance() && var->type->is_array(); - if (var->is_interface_instance() && var->type->is_array()) { + if (is_interface_array) { unsigned l = strlen(var->get_interface_type()->name); for (unsigned i = 0; i < num_blks; i++) { @@ -480,8 +538,7 @@ public: } } else { for (unsigned i = 0; i < num_blks; i++) { - if (strcmp(var->get_interface_type()->name, blks[i].Name) == - 0) { + if (strcmp(var->get_interface_type()->name, blks[i].Name) == 0) { buffer_block_index = i; break; } @@ -489,6 +546,24 @@ public: } assert(buffer_block_index != -1); + if (var->is_in_shader_storage_block() && + !var->data.memory_read_only) { + unsigned array_size = is_interface_array ? + var->type->array_size() : 1; + + STATIC_ASSERT(MAX_SHADER_STORAGE_BUFFERS <= 32); + + /* Shaders that use too many SSBOs will fail to compile, which + * we don't care about. + * + * This is true for shaders that do not use too many SSBOs: + */ + if (buffer_block_index + array_size <= 32) { + shader_storage_blocks_write_access |= + u_bit_consecutive(buffer_block_index, array_size); + } + } + /* Uniform blocks that were specified with an instance name must be * handled a little bit differently. The name of the variable is the * name used to reference the uniform block instead of being the name @@ -498,7 +573,8 @@ public: if (var->is_interface_instance()) { ubo_byte_offset = 0; process(var->get_interface_type(), - var->get_interface_type()->name); + var->get_interface_type()->name, + use_std430_as_default); } else { const struct gl_uniform_block *const block = &blks[buffer_block_index]; @@ -509,7 +585,7 @@ public: &block->Uniforms[var->data.location]; ubo_byte_offset = ubo_var->Offset; - process(var); + process(var, use_std430_as_default); } } else { /* Store any explicit location and reset data location so we can @@ -518,9 +594,12 @@ public: this->explicit_location = current_var->data.location; current_var->data.location = -1; - process(var); + process(var, use_std430_as_default); } delete this->record_next_sampler; + delete this->record_next_bindless_sampler; + delete this->record_next_image; + delete this->record_next_bindless_image; } int buffer_block_index; @@ -528,101 +607,154 @@ public: gl_shader_stage shader_type; private: + bool set_opaque_indices(const glsl_type *base_type, + struct gl_uniform_storage *uniform, + const char *name, unsigned &next_index, + struct string_to_uint_map *record_next_index) + { + assert(base_type->is_sampler() || base_type->is_image()); + + if (this->record_array_count > 1) { + unsigned inner_array_size = MAX2(1, uniform->array_elements); + char *name_copy = ralloc_strdup(NULL, name); + + /* Remove all array subscripts from the sampler/image name */ + char *str_start; + const char *str_end; + while((str_start = strchr(name_copy, '[')) && + (str_end = strchr(name_copy, ']'))) { + memmove(str_start, str_end + 1, 1 + strlen(str_end + 1)); + } + + unsigned index = 0; + if (record_next_index->get(index, name_copy)) { + /* In this case, we've already seen this uniform so we just use the + * next sampler/image index recorded the last time we visited. + */ + uniform->opaque[shader_type].index = index; + index = inner_array_size + uniform->opaque[shader_type].index; + record_next_index->put(index, name_copy); + + ralloc_free(name_copy); + /* Return as everything else has already been initialised in a + * previous pass. + */ + return false; + } else { + /* We've never seen this uniform before so we need to allocate + * enough indices to store it. + * + * Nested struct arrays behave like arrays of arrays so we need to + * increase the index by the total number of elements of the + * sampler/image in case there is more than one sampler/image + * inside the structs. This allows the offset to be easily + * calculated for indirect indexing. + */ + uniform->opaque[shader_type].index = next_index; + next_index += inner_array_size * this->record_array_count; + + /* Store the next index for future passes over the struct array + */ + index = uniform->opaque[shader_type].index + inner_array_size; + record_next_index->put(index, name_copy); + ralloc_free(name_copy); + } + } else { + /* Increment the sampler/image by 1 for non-arrays and by the number + * of array elements for arrays. + */ + uniform->opaque[shader_type].index = next_index; + next_index += MAX2(1, uniform->array_elements); + } + return true; + } + void handle_samplers(const glsl_type *base_type, struct gl_uniform_storage *uniform, const char *name) { if (base_type->is_sampler()) { uniform->opaque[shader_type].active = true; - /* Handle multiple samplers inside struct arrays */ - if (this->record_array_count > 1) { - unsigned inner_array_size = MAX2(1, uniform->array_elements); - char *name_copy = ralloc_strdup(NULL, name); - - /* Remove all array subscripts from the sampler name */ - char *str_start; - const char *str_end; - while((str_start = strchr(name_copy, '[')) && - (str_end = strchr(name_copy, ']'))) { - memmove(str_start, str_end + 1, 1 + strlen(str_end)); - } - - unsigned index = 0; - if (this->record_next_sampler->get(index, name_copy)) { - /* In this case, we've already seen this uniform so we just use - * the next sampler index recorded the last time we visited. - */ - uniform->opaque[shader_type].index = index; - index = inner_array_size + uniform->opaque[shader_type].index; - this->record_next_sampler->put(index, name_copy); + const gl_texture_index target = base_type->sampler_index(); + const unsigned shadow = base_type->sampler_shadow; - ralloc_free(name_copy); - /* Return as everything else has already been initialised in a - * previous pass. - */ + if (current_var->data.bindless) { + if (!set_opaque_indices(base_type, uniform, name, + this->next_bindless_sampler, + this->record_next_bindless_sampler)) return; - } else { - /* We've never seen this uniform before so we need to allocate - * enough indices to store it. - * - * Nested struct arrays behave like arrays of arrays so we need - * to increase the index by the total number of elements of the - * sampler in case there is more than one sampler inside the - * structs. This allows the offset to be easily calculated for - * indirect indexing. - */ - uniform->opaque[shader_type].index = this->next_sampler; - this->next_sampler += - inner_array_size * this->record_array_count; - /* Store the next index for future passes over the struct array - */ - index = uniform->opaque[shader_type].index + inner_array_size; - this->record_next_sampler->put(index, name_copy); - ralloc_free(name_copy); + this->num_bindless_samplers = this->next_bindless_sampler; + + this->bindless_targets = (gl_texture_index *) + realloc(this->bindless_targets, + this->num_bindless_samplers * sizeof(gl_texture_index)); + + for (unsigned i = uniform->opaque[shader_type].index; + i < this->num_bindless_samplers; + i++) { + this->bindless_targets[i] = target; } } else { - /* Increment the sampler by 1 for non-arrays and by the number of - * array elements for arrays. - */ - uniform->opaque[shader_type].index = this->next_sampler; - this->next_sampler += MAX2(1, uniform->array_elements); - } + if (!set_opaque_indices(base_type, uniform, name, + this->next_sampler, + this->record_next_sampler)) + return; - const gl_texture_index target = base_type->sampler_index(); - const unsigned shadow = base_type->sampler_shadow; - for (unsigned i = uniform->opaque[shader_type].index; - i < MIN2(this->next_sampler, MAX_SAMPLERS); - i++) { - this->targets[i] = target; - this->shader_samplers_used |= 1U << i; - this->shader_shadow_samplers |= shadow << i; + for (unsigned i = uniform->opaque[shader_type].index; + i < MIN2(this->next_sampler, MAX_SAMPLERS); + i++) { + this->targets[i] = target; + this->shader_samplers_used |= 1U << i; + this->shader_shadow_samplers |= shadow << i; + } } } } void handle_images(const glsl_type *base_type, - struct gl_uniform_storage *uniform) + struct gl_uniform_storage *uniform, const char *name) { if (base_type->is_image()) { - uniform->opaque[shader_type].index = this->next_image; uniform->opaque[shader_type].active = true; /* Set image access qualifiers */ const GLenum access = - (current_var->data.image_read_only ? GL_READ_ONLY : - current_var->data.image_write_only ? GL_WRITE_ONLY : - GL_READ_WRITE); + current_var->data.memory_read_only ? + (current_var->data.memory_write_only ? GL_NONE : + GL_READ_ONLY) : + (current_var->data.memory_write_only ? GL_WRITE_ONLY : + GL_READ_WRITE); + + if (current_var->data.bindless) { + if (!set_opaque_indices(base_type, uniform, name, + this->next_bindless_image, + this->record_next_bindless_image)) + return; - const unsigned first = this->next_image; + this->num_bindless_images = this->next_bindless_image; - /* Increment the image index by 1 for non-arrays and by the - * number of array elements for arrays. - */ - this->next_image += MAX2(1, uniform->array_elements); + this->bindless_access = (GLenum *) + realloc(this->bindless_access, + this->num_bindless_images * sizeof(GLenum)); - for (unsigned i = first; i < MIN2(next_image, MAX_IMAGE_UNIFORMS); i++) - prog->_LinkedShaders[shader_type]->ImageAccess[i] = access; + for (unsigned i = uniform->opaque[shader_type].index; + i < this->num_bindless_images; + i++) { + this->bindless_access[i] = access; + } + } else { + if (!set_opaque_indices(base_type, uniform, name, + this->next_image, + this->record_next_image)) + return; + + for (unsigned i = uniform->opaque[shader_type].index; + i < MIN2(this->next_image, MAX_IMAGE_UNIFORMS); + i++) { + prog->_LinkedShaders[shader_type]->Program->sh.ImageAccess[i] = access; + } + } } } @@ -633,6 +765,8 @@ private: uniform->opaque[shader_type].index = this->next_subroutine; uniform->opaque[shader_type].active = true; + prog->_LinkedShaders[shader_type]->Program->sh.NumSubroutineUniforms++; + /* Increment the subroutine index by 1 for non-arrays and by the * number of array elements for arrays. */ @@ -651,18 +785,11 @@ private: this->record_array_count = record_array_count; } - virtual void visit_field(const glsl_type *type, const char *name, - bool row_major) - { - (void) type; - (void) name; - (void) row_major; - assert(!"Should not get here."); - } - virtual void enter_record(const glsl_type *type, const char *, - bool row_major, const enum glsl_interface_packing packing) { - assert(type->is_record()); + bool row_major, + const enum glsl_interface_packing packing) + { + assert(type->is_struct()); if (this->buffer_block_index == -1) return; if (packing == GLSL_INTERFACE_PACKING_STD430) @@ -674,8 +801,10 @@ private: } virtual void leave_record(const glsl_type *type, const char *, - bool row_major, const enum glsl_interface_packing packing) { - assert(type->is_record()); + bool row_major, + const enum glsl_interface_packing packing) + { + assert(type->is_struct()); if (this->buffer_block_index == -1) return; if (packing == GLSL_INTERFACE_PACKING_STD430) @@ -691,7 +820,7 @@ private: const enum glsl_interface_packing packing, bool /* last_field */) { - assert(!type->without_array()->is_record()); + assert(!type->without_array()->is_struct()); assert(!type->without_array()->is_interface()); assert(!(type->is_array() && type->fields.array->is_array())); @@ -715,9 +844,11 @@ private: this->uniforms[id].opaque[shader_type].index = ~0; this->uniforms[id].opaque[shader_type].active = false; + this->uniforms[id].active_shader_mask |= 1 << shader_type; + /* This assigns uniform indices to sampler and image uniforms. */ handle_samplers(base_type, &this->uniforms[id], name); - handle_images(base_type, &this->uniforms[id]); + handle_images(base_type, &this->uniforms[id], name); handle_subroutines(base_type, &this->uniforms[id]); /* For array of arrays or struct arrays the base location may have @@ -740,7 +871,7 @@ private: /* Assign explicit locations. */ if (current_var->data.explicit_location) { /* Set sequential locations for struct fields. */ - if (current_var->type->without_array()->is_record() || + if (current_var->type->without_array()->is_struct() || current_var->type->is_array_of_arrays()) { const unsigned entries = MAX2(1, this->uniforms[id].array_elements); this->uniforms[id].remap_location = @@ -765,6 +896,7 @@ private: this->uniforms[id].is_shader_storage = current_var->is_in_shader_storage_block(); + this->uniforms[id].is_bindless = current_var->data.bindless; /* Do not assign storage if the uniform is a builtin or buffer object */ if (!this->uniforms[id].builtin && @@ -798,17 +930,10 @@ private: } if (type->without_array()->is_matrix()) { - const glsl_type *matrix = type->without_array(); - const unsigned N = matrix->base_type == GLSL_TYPE_DOUBLE ? 8 : 4; - const unsigned items = - row_major ? matrix->matrix_columns : matrix->vector_elements; - - assert(items <= 4); - if (packing == GLSL_INTERFACE_PACKING_STD430) - this->uniforms[id].matrix_stride = items < 3 ? items * N : - glsl_align(items * N, 16); - else - this->uniforms[id].matrix_stride = glsl_align(items * N, 16); + this->uniforms[id].matrix_stride = + link_calculate_matrix_stride(type->without_array(), + row_major, + packing); this->uniforms[id].row_major = row_major; } else { this->uniforms[id].matrix_stride = 0; @@ -825,7 +950,7 @@ private: if (!this->uniforms[id].builtin && !this->uniforms[id].is_shader_storage && this->buffer_block_index == -1) - this->values += values_for_type(type); + this->values += type->component_slots(); } /** @@ -837,9 +962,13 @@ private: struct gl_uniform_storage *uniforms; unsigned next_sampler; + unsigned next_bindless_sampler; unsigned next_image; + unsigned next_bindless_image; unsigned next_subroutine; + bool use_std430_as_default; + /** * Field counter is used to take care that uniform structures * with explicit locations get sequential locations. @@ -864,6 +993,21 @@ private: */ struct string_to_uint_map *record_next_sampler; + /* Map for temporarily storing next imager index when handling images in + * struct arrays. + */ + struct string_to_uint_map *record_next_image; + + /* Map for temporarily storing next bindless sampler index when handling + * bindless samplers in struct arrays. + */ + struct string_to_uint_map *record_next_bindless_sampler; + + /* Map for temporarily storing next bindless image index when handling + * bindless images in struct arrays. + */ + struct string_to_uint_map *record_next_bindless_image; + public: union gl_constant_value *values; @@ -878,8 +1022,42 @@ public: * Mask of samplers used by the current shader stage for shadows. */ unsigned shader_shadow_samplers; + + /** + * Number of bindless samplers used by the current shader stage. + */ + unsigned num_bindless_samplers; + + /** + * Texture targets for bindless samplers used by the current stage. + */ + gl_texture_index *bindless_targets; + + /** + * Number of bindless images used by the current shader stage. + */ + unsigned num_bindless_images; + + /** + * Access types for bindless images used by the current stage. + */ + GLenum *bindless_access; + + /** + * Bitmask of shader storage blocks not declared as read-only. + */ + unsigned shader_storage_blocks_write_access; }; +static bool +variable_is_referenced(ir_array_refcount_visitor &v, ir_variable *var) +{ + ir_array_refcount_entry *const entry = v.get_variable_entry(var); + + return entry->is_referenced; + +} + /** * Walks the IR and update the references to uniform blocks in the * ir_variables to point at linked shader's list (previously, they @@ -887,18 +1065,65 @@ public: * shaders). */ static void -link_update_uniform_buffer_variables(struct gl_linked_shader *shader) +link_update_uniform_buffer_variables(struct gl_linked_shader *shader, + unsigned stage) { + ir_array_refcount_visitor v; + + v.run(shader->ir); + foreach_in_list(ir_instruction, node, shader->ir) { ir_variable *const var = node->as_variable(); - if ((var == NULL) || !var->is_in_buffer_block()) + if (var == NULL || !var->is_in_buffer_block()) continue; assert(var->data.mode == ir_var_uniform || var->data.mode == ir_var_shader_storage); + unsigned num_blocks = var->data.mode == ir_var_uniform ? + shader->Program->info.num_ubos : shader->Program->info.num_ssbos; + struct gl_uniform_block **blks = var->data.mode == ir_var_uniform ? + shader->Program->sh.UniformBlocks : + shader->Program->sh.ShaderStorageBlocks; + if (var->is_interface_instance()) { + const ir_array_refcount_entry *const entry = v.get_variable_entry(var); + + if (entry->is_referenced) { + /* Since this is an interface instance, the instance type will be + * same as the array-stripped variable type. If the variable type + * is an array, then the block names will be suffixed with [0] + * through [n-1]. Unlike for non-interface instances, there will + * not be structure types here, so the only name sentinel that we + * have to worry about is [. + */ + assert(var->type->without_array() == var->get_interface_type()); + const char sentinel = var->type->is_array() ? '[' : '\0'; + + const ptrdiff_t len = strlen(var->get_interface_type()->name); + for (unsigned i = 0; i < num_blocks; i++) { + const char *const begin = blks[i]->Name; + const char *const end = strchr(begin, sentinel); + + if (end == NULL) + continue; + + if (len != (end - begin)) + continue; + + /* Even when a match is found, do not "break" here. This could + * be an array of instances, and all elements of the array need + * to be marked as referenced. + */ + if (strncmp(begin, var->get_interface_type()->name, len) == 0 && + (!var->type->is_array() || + entry->is_linearized_index_referenced(blks[i]->linearized_array_index))) { + blks[i]->stageref |= 1U << stage; + } + } + } + var->data.location = 0; continue; } @@ -906,18 +1131,13 @@ link_update_uniform_buffer_variables(struct gl_linked_shader *shader) bool found = false; char sentinel = '\0'; - if (var->type->is_record()) { + if (var->type->is_struct()) { sentinel = '.'; } else if (var->type->is_array() && (var->type->fields.array->is_array() - || var->type->without_array()->is_record())) { + || var->type->without_array()->is_struct())) { sentinel = '['; } - unsigned num_blocks = var->data.mode == ir_var_uniform ? - shader->NumUniformBlocks : shader->NumShaderStorageBlocks; - struct gl_uniform_block **blks = var->data.mode == ir_var_uniform ? - shader->UniformBlocks : shader->ShaderStorageBlocks; - const unsigned l = strlen(var->name); for (unsigned i = 0; i < num_blocks; i++) { for (unsigned j = 0; j < blks[i]->NumUniforms; j++) { @@ -931,17 +1151,21 @@ link_update_uniform_buffer_variables(struct gl_linked_shader *shader) if ((ptrdiff_t) l != (end - begin)) continue; - if (strncmp(var->name, begin, l) == 0) { - found = true; - var->data.location = j; - break; - } - } else if (!strcmp(var->name, blks[i]->Uniforms[j].Name)) { - found = true; + found = strncmp(var->name, begin, l) == 0; + } else { + found = strcmp(var->name, blks[i]->Uniforms[j].Name) == 0; + } + + if (found) { var->data.location = j; + + if (variable_is_referenced(v, var)) + blks[i]->stageref |= 1U << stage; + break; } } + if (found) break; } @@ -965,205 +1189,68 @@ assign_hidden_uniform_slot_id(const char *name, unsigned hidden_id, uniform_size->map->put(hidden_uniform_start + hidden_id, name); } -/** - * Search through the list of empty blocks to find one that fits the current - * uniform. - */ -static int -find_empty_block(struct gl_shader_program *prog, - struct gl_uniform_storage *uniform) -{ - const unsigned entries = MAX2(1, uniform->array_elements); - - foreach_list_typed(struct empty_uniform_block, block, link, - &prog->EmptyUniformLocations) { - /* Found a block with enough slots to fit the uniform */ - if (block->slots == entries) { - unsigned start = block->start; - exec_node_remove(&block->link); - ralloc_free(block); - - return start; - /* Found a block with more slots than needed. It can still be used. */ - } else if (block->slots > entries) { - unsigned start = block->start; - block->start += entries; - block->slots -= entries; - - return start; - } - } - - return -1; -} - -void -link_assign_uniform_locations(struct gl_shader_program *prog, - unsigned int boolean_true, - unsigned int num_explicit_uniform_locs, - unsigned int max_uniform_locs) +static void +link_setup_uniform_remap_tables(struct gl_context *ctx, + struct gl_shader_program *prog) { - ralloc_free(prog->UniformStorage); - prog->UniformStorage = NULL; - prog->NumUniformStorage = 0; - - if (prog->UniformHash != NULL) { - prog->UniformHash->clear(); - } else { - prog->UniformHash = new string_to_uint_map; - } - - /* First pass: Count the uniform resources used by the user-defined - * uniforms. While this happens, each active uniform will have an index - * assigned to it. - * - * Note: this is *NOT* the index that is returned to the application by - * glGetUniformLocation. - */ - struct string_to_uint_map *hiddenUniforms = new string_to_uint_map; - count_uniform_size uniform_size(prog->UniformHash, hiddenUniforms); - for (unsigned i = 0; i < MESA_SHADER_STAGES; i++) { - struct gl_linked_shader *sh = prog->_LinkedShaders[i]; - - if (sh == NULL) - continue; - - /* Uniforms that lack an initializer in the shader code have an initial - * value of zero. This includes sampler uniforms. - * - * Page 24 (page 30 of the PDF) of the GLSL 1.20 spec says: - * - * "The link time initial value is either the value of the variable's - * initializer, if present, or 0 if no initializer is present. Sampler - * types cannot have initializers." - */ - memset(sh->SamplerUnits, 0, sizeof(sh->SamplerUnits)); - memset(sh->ImageUnits, 0, sizeof(sh->ImageUnits)); - - link_update_uniform_buffer_variables(sh); - - /* Reset various per-shader target counts. - */ - uniform_size.start_shader(); - - foreach_in_list(ir_instruction, node, sh->ir) { - ir_variable *const var = node->as_variable(); - - if ((var == NULL) || (var->data.mode != ir_var_uniform && - var->data.mode != ir_var_shader_storage)) - continue; - - uniform_size.process(var); - } - - sh->num_samplers = uniform_size.num_shader_samplers; - sh->NumImages = uniform_size.num_shader_images; - sh->num_uniform_components = uniform_size.num_shader_uniform_components; - sh->num_combined_uniform_components = sh->num_uniform_components; - - for (unsigned i = 0; i < sh->NumUniformBlocks; i++) { - sh->num_combined_uniform_components += - sh->UniformBlocks[i]->UniformBufferSize / 4; - } - } - - const unsigned num_uniforms = uniform_size.num_active_uniforms; - const unsigned num_data_slots = uniform_size.num_values; - const unsigned hidden_uniforms = uniform_size.num_hidden_uniforms; - - /* assign hidden uniforms a slot id */ - hiddenUniforms->iterate(assign_hidden_uniform_slot_id, &uniform_size); - delete hiddenUniforms; - - /* On the outside chance that there were no uniforms, bail out. - */ - if (num_uniforms == 0) - return; - - struct gl_uniform_storage *uniforms = - rzalloc_array(prog, struct gl_uniform_storage, num_uniforms); - union gl_constant_value *data = - rzalloc_array(uniforms, union gl_constant_value, num_data_slots); -#ifndef NDEBUG - union gl_constant_value *data_end = &data[num_data_slots]; -#endif - - parcel_out_uniform_storage parcel(prog, prog->UniformHash, uniforms, data); - - unsigned total_entries = num_explicit_uniform_locs; - unsigned empty_locs = prog->NumUniformRemapTable - num_explicit_uniform_locs; - - for (unsigned i = 0; i < MESA_SHADER_STAGES; i++) { - if (prog->_LinkedShaders[i] == NULL) - continue; - - parcel.start_shader((gl_shader_stage)i); - - foreach_in_list(ir_instruction, node, prog->_LinkedShaders[i]->ir) { - ir_variable *const var = node->as_variable(); - - if ((var == NULL) || (var->data.mode != ir_var_uniform && - var->data.mode != ir_var_shader_storage)) - continue; - - parcel.set_and_process(var); - } - - prog->_LinkedShaders[i]->active_samplers = parcel.shader_samplers_used; - prog->_LinkedShaders[i]->shadow_samplers = parcel.shader_shadow_samplers; - - STATIC_ASSERT(sizeof(prog->_LinkedShaders[i]->SamplerTargets) == - sizeof(parcel.targets)); - memcpy(prog->_LinkedShaders[i]->SamplerTargets, parcel.targets, - sizeof(prog->_LinkedShaders[i]->SamplerTargets)); - } + unsigned total_entries = prog->NumExplicitUniformLocations; + unsigned empty_locs = prog->NumUniformRemapTable - total_entries; /* Reserve all the explicit locations of the active uniforms. */ - for (unsigned i = 0; i < num_uniforms; i++) { - if (uniforms[i].type->is_subroutine() || - uniforms[i].is_shader_storage) + for (unsigned i = 0; i < prog->data->NumUniformStorage; i++) { + if (prog->data->UniformStorage[i].type->is_subroutine() || + prog->data->UniformStorage[i].is_shader_storage) continue; - if (uniforms[i].remap_location != UNMAPPED_UNIFORM_LOC) { + if (prog->data->UniformStorage[i].remap_location != + UNMAPPED_UNIFORM_LOC) { /* How many new entries for this uniform? */ - const unsigned entries = MAX2(1, uniforms[i].array_elements); + const unsigned entries = + MAX2(1, prog->data->UniformStorage[i].array_elements); /* Set remap table entries point to correct gl_uniform_storage. */ for (unsigned j = 0; j < entries; j++) { - unsigned element_loc = uniforms[i].remap_location + j; + unsigned element_loc = + prog->data->UniformStorage[i].remap_location + j; assert(prog->UniformRemapTable[element_loc] == INACTIVE_UNIFORM_EXPLICIT_LOCATION); - prog->UniformRemapTable[element_loc] = &uniforms[i]; + prog->UniformRemapTable[element_loc] = + &prog->data->UniformStorage[i]; } } } /* Reserve locations for rest of the uniforms. */ - for (unsigned i = 0; i < num_uniforms; i++) { + for (unsigned i = 0; i < prog->data->NumUniformStorage; i++) { - if (uniforms[i].type->is_subroutine() || - uniforms[i].is_shader_storage) + if (prog->data->UniformStorage[i].type->is_subroutine() || + prog->data->UniformStorage[i].is_shader_storage) continue; /* Built-in uniforms should not get any location. */ - if (uniforms[i].builtin) + if (prog->data->UniformStorage[i].builtin) continue; /* Explicit ones have been set already. */ - if (uniforms[i].remap_location != UNMAPPED_UNIFORM_LOC) + if (prog->data->UniformStorage[i].remap_location != UNMAPPED_UNIFORM_LOC) continue; /* how many new entries for this uniform? */ - const unsigned entries = MAX2(1, uniforms[i].array_elements); + const unsigned entries = + MAX2(1, prog->data->UniformStorage[i].array_elements); /* Find UniformRemapTable for empty blocks where we can fit this uniform. */ int chosen_location = -1; if (empty_locs) - chosen_location = find_empty_block(prog, &uniforms[i]); + chosen_location = link_util_find_empty_block(prog, &prog->data->UniformStorage[i]); - /* Add new entries to the total amount of entries. */ - total_entries += entries; + /* Add new entries to the total amount for checking against MAX_UNIFORM- + * _LOCATIONS. This only applies to the default uniform block (-1), + * because locations of uniform block entries are not assignable. + */ + if (prog->data->UniformStorage[i].block_index == -1) + total_entries += entries; if (chosen_location != -1) { empty_locs -= entries; @@ -1181,95 +1268,260 @@ link_assign_uniform_locations(struct gl_shader_program *prog, /* set pointers for this uniform */ for (unsigned j = 0; j < entries; j++) - prog->UniformRemapTable[chosen_location + j] = &uniforms[i]; + prog->UniformRemapTable[chosen_location + j] = + &prog->data->UniformStorage[i]; /* set the base location in remap table for the uniform */ - uniforms[i].remap_location = chosen_location; + prog->data->UniformStorage[i].remap_location = chosen_location; } /* Verify that total amount of entries for explicit and implicit locations * is less than MAX_UNIFORM_LOCATIONS. */ - if (total_entries > max_uniform_locs) { + if (total_entries > ctx->Const.MaxUserAssignableUniformLocations) { linker_error(prog, "count of uniform locations > MAX_UNIFORM_LOCATIONS" - "(%u > %u)", total_entries, max_uniform_locs); + "(%u > %u)", total_entries, + ctx->Const.MaxUserAssignableUniformLocations); } /* Reserve all the explicit locations of the active subroutine uniforms. */ - for (unsigned i = 0; i < num_uniforms; i++) { - if (!uniforms[i].type->is_subroutine()) + for (unsigned i = 0; i < prog->data->NumUniformStorage; i++) { + if (!prog->data->UniformStorage[i].type->is_subroutine()) continue; - if (uniforms[i].remap_location == UNMAPPED_UNIFORM_LOC) + if (prog->data->UniformStorage[i].remap_location == UNMAPPED_UNIFORM_LOC) continue; - for (unsigned j = 0; j < MESA_SHADER_STAGES; j++) { - struct gl_linked_shader *sh = prog->_LinkedShaders[j]; - if (!sh) - continue; + /* How many new entries for this uniform? */ + const unsigned entries = + MAX2(1, prog->data->UniformStorage[i].array_elements); - if (!uniforms[i].opaque[j].active) - continue; + unsigned mask = prog->data->linked_stages; + while (mask) { + const int j = u_bit_scan(&mask); + struct gl_program *p = prog->_LinkedShaders[j]->Program; - /* How many new entries for this uniform? */ - const unsigned entries = MAX2(1, uniforms[i].array_elements); + if (!prog->data->UniformStorage[i].opaque[j].active) + continue; /* Set remap table entries point to correct gl_uniform_storage. */ for (unsigned k = 0; k < entries; k++) { - unsigned element_loc = uniforms[i].remap_location + k; - assert(sh->SubroutineUniformRemapTable[element_loc] == + unsigned element_loc = + prog->data->UniformStorage[i].remap_location + k; + assert(p->sh.SubroutineUniformRemapTable[element_loc] == INACTIVE_UNIFORM_EXPLICIT_LOCATION); - sh->SubroutineUniformRemapTable[element_loc] = &uniforms[i]; + p->sh.SubroutineUniformRemapTable[element_loc] = + &prog->data->UniformStorage[i]; } } } /* reserve subroutine locations */ - for (unsigned i = 0; i < num_uniforms; i++) { - - if (!uniforms[i].type->is_subroutine()) + for (unsigned i = 0; i < prog->data->NumUniformStorage; i++) { + if (!prog->data->UniformStorage[i].type->is_subroutine()) continue; - const unsigned entries = MAX2(1, uniforms[i].array_elements); - if (uniforms[i].remap_location != UNMAPPED_UNIFORM_LOC) + if (prog->data->UniformStorage[i].remap_location != + UNMAPPED_UNIFORM_LOC) continue; - for (unsigned j = 0; j < MESA_SHADER_STAGES; j++) { - struct gl_linked_shader *sh = prog->_LinkedShaders[j]; - if (!sh) - continue; - if (!uniforms[i].opaque[j].active) + const unsigned entries = + MAX2(1, prog->data->UniformStorage[i].array_elements); + + unsigned mask = prog->data->linked_stages; + while (mask) { + const int j = u_bit_scan(&mask); + struct gl_program *p = prog->_LinkedShaders[j]->Program; + + if (!prog->data->UniformStorage[i].opaque[j].active) continue; - sh->SubroutineUniformRemapTable = - reralloc(sh, - sh->SubroutineUniformRemapTable, + p->sh.SubroutineUniformRemapTable = + reralloc(p, + p->sh.SubroutineUniformRemapTable, gl_uniform_storage *, - sh->NumSubroutineUniformRemapTable + entries); + p->sh.NumSubroutineUniformRemapTable + entries); + + for (unsigned k = 0; k < entries; k++) { + p->sh.SubroutineUniformRemapTable[p->sh.NumSubroutineUniformRemapTable + k] = + &prog->data->UniformStorage[i]; + } + prog->data->UniformStorage[i].remap_location = + p->sh.NumSubroutineUniformRemapTable; + p->sh.NumSubroutineUniformRemapTable += entries; + } + } +} - for (unsigned k = 0; k < entries; k++) - sh->SubroutineUniformRemapTable[sh->NumSubroutineUniformRemapTable + k] = &uniforms[i]; - uniforms[i].remap_location = sh->NumSubroutineUniformRemapTable; - sh->NumSubroutineUniformRemapTable += entries; +static void +link_assign_uniform_storage(struct gl_context *ctx, + struct gl_shader_program *prog, + const unsigned num_data_slots) +{ + /* On the outside chance that there were no uniforms, bail out. + */ + if (prog->data->NumUniformStorage == 0) + return; + + unsigned int boolean_true = ctx->Const.UniformBooleanTrue; + + union gl_constant_value *data; + if (prog->data->UniformStorage == NULL) { + prog->data->UniformStorage = rzalloc_array(prog->data, + struct gl_uniform_storage, + prog->data->NumUniformStorage); + data = rzalloc_array(prog->data->UniformStorage, + union gl_constant_value, num_data_slots); + prog->data->UniformDataDefaults = + rzalloc_array(prog->data->UniformStorage, + union gl_constant_value, num_data_slots); + } else { + data = prog->data->UniformDataSlots; + } + +#ifndef NDEBUG + union gl_constant_value *data_end = &data[num_data_slots]; +#endif + + parcel_out_uniform_storage parcel(prog, prog->UniformHash, + prog->data->UniformStorage, data, + ctx->Const.UseSTD430AsDefaultPacking); + + for (unsigned i = 0; i < MESA_SHADER_STAGES; i++) { + struct gl_linked_shader *shader = prog->_LinkedShaders[i]; + + if (!shader) + continue; + + parcel.start_shader((gl_shader_stage)i); + + foreach_in_list(ir_instruction, node, shader->ir) { + ir_variable *const var = node->as_variable(); + + if ((var == NULL) || (var->data.mode != ir_var_uniform && + var->data.mode != ir_var_shader_storage)) + continue; + + parcel.set_and_process(var); + } + + shader->Program->SamplersUsed = parcel.shader_samplers_used; + shader->shadow_samplers = parcel.shader_shadow_samplers; + shader->Program->sh.ShaderStorageBlocksWriteAccess = + parcel.shader_storage_blocks_write_access; + + if (parcel.num_bindless_samplers > 0) { + shader->Program->sh.NumBindlessSamplers = parcel.num_bindless_samplers; + shader->Program->sh.BindlessSamplers = + rzalloc_array(shader->Program, gl_bindless_sampler, + parcel.num_bindless_samplers); + for (unsigned j = 0; j < parcel.num_bindless_samplers; j++) { + shader->Program->sh.BindlessSamplers[j].target = + parcel.bindless_targets[j]; + } + } + + if (parcel.num_bindless_images > 0) { + shader->Program->sh.NumBindlessImages = parcel.num_bindless_images; + shader->Program->sh.BindlessImages = + rzalloc_array(shader->Program, gl_bindless_image, + parcel.num_bindless_images); + for (unsigned j = 0; j < parcel.num_bindless_images; j++) { + shader->Program->sh.BindlessImages[j].access = + parcel.bindless_access[j]; + } } + + STATIC_ASSERT(ARRAY_SIZE(shader->Program->sh.SamplerTargets) == + ARRAY_SIZE(parcel.targets)); + for (unsigned j = 0; j < ARRAY_SIZE(parcel.targets); j++) + shader->Program->sh.SamplerTargets[j] = parcel.targets[j]; } #ifndef NDEBUG - for (unsigned i = 0; i < num_uniforms; i++) { - assert(uniforms[i].storage != NULL || uniforms[i].builtin || - uniforms[i].is_shader_storage || - uniforms[i].block_index != -1); + for (unsigned i = 0; i < prog->data->NumUniformStorage; i++) { + assert(prog->data->UniformStorage[i].storage != NULL || + prog->data->UniformStorage[i].builtin || + prog->data->UniformStorage[i].is_shader_storage || + prog->data->UniformStorage[i].block_index != -1); } assert(parcel.values == data_end); #endif - prog->NumUniformStorage = num_uniforms; - prog->NumHiddenUniforms = hidden_uniforms; - prog->UniformStorage = uniforms; + link_setup_uniform_remap_tables(ctx, prog); + + /* Set shader cache fields */ + prog->data->NumUniformDataSlots = num_data_slots; + prog->data->UniformDataSlots = data; link_set_uniform_initializers(prog, boolean_true); +} + +void +link_assign_uniform_locations(struct gl_shader_program *prog, + struct gl_context *ctx) +{ + ralloc_free(prog->data->UniformStorage); + prog->data->UniformStorage = NULL; + prog->data->NumUniformStorage = 0; + + if (prog->UniformHash != NULL) { + prog->UniformHash->clear(); + } else { + prog->UniformHash = new string_to_uint_map; + } + + /* First pass: Count the uniform resources used by the user-defined + * uniforms. While this happens, each active uniform will have an index + * assigned to it. + * + * Note: this is *NOT* the index that is returned to the application by + * glGetUniformLocation. + */ + struct string_to_uint_map *hiddenUniforms = new string_to_uint_map; + count_uniform_size uniform_size(prog->UniformHash, hiddenUniforms, + ctx->Const.UseSTD430AsDefaultPacking); + for (unsigned i = 0; i < MESA_SHADER_STAGES; i++) { + struct gl_linked_shader *sh = prog->_LinkedShaders[i]; + + if (sh == NULL) + continue; + + link_update_uniform_buffer_variables(sh, i); + + /* Reset various per-shader target counts. + */ + uniform_size.start_shader(); + + foreach_in_list(ir_instruction, node, sh->ir) { + ir_variable *const var = node->as_variable(); + + if ((var == NULL) || (var->data.mode != ir_var_uniform && + var->data.mode != ir_var_shader_storage)) + continue; + + uniform_size.process(var); + } + + sh->Program->info.num_textures = uniform_size.num_shader_samplers; + sh->Program->info.num_images = uniform_size.num_shader_images; + sh->num_uniform_components = uniform_size.num_shader_uniform_components; + sh->num_combined_uniform_components = sh->num_uniform_components; + + for (unsigned i = 0; i < sh->Program->info.num_ubos; i++) { + sh->num_combined_uniform_components += + sh->Program->sh.UniformBlocks[i]->UniformBufferSize / 4; + } + } + + prog->data->NumUniformStorage = uniform_size.num_active_uniforms; + prog->data->NumHiddenUniforms = uniform_size.num_hidden_uniforms; + + /* assign hidden uniforms a slot id */ + hiddenUniforms->iterate(assign_hidden_uniform_slot_id, &uniform_size); + delete hiddenUniforms; - return; + link_assign_uniform_storage(ctx, prog, uniform_size.num_values); }