#include "linker.h"
#include "ir_uniform.h"
#include "glsl_symbol_table.h"
-#include "program/hash_table.h"
#include "program.h"
+#include "util/string_to_uint_map.h"
/**
* \file link_uniforms.cpp
}
void
-program_resource_visitor::visit_field(const glsl_struct_field *field)
+program_resource_visitor::visit_field(const glsl_struct_field *)
{
- (void) field;
- /* empty */
}
void
private:
virtual void visit_field(const glsl_type *type, const char *name,
- bool row_major)
+ bool /* row_major */)
{
assert(!type->without_array()->is_record());
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
* 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.
this->record_array_count = record_array_count;
}
- virtual void visit_field(const glsl_type *type, const char *name,
- bool row_major)
+ virtual void visit_field(const glsl_type *, const char *,
+ 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) {
+ bool row_major,
+ const enum glsl_interface_packing packing)
+ {
assert(type->is_record());
if (this->buffer_block_index == -1)
return;
}
virtual void leave_record(const glsl_type *type, const char *,
- bool row_major, const enum glsl_interface_packing packing) {
+ bool row_major,
+ const enum glsl_interface_packing packing)
+ {
assert(type->is_record());
if (this->buffer_block_index == -1)
return;
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 ||
break;
}
}
+
if (found)
break;
}
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,
+ unsigned num_explicit_uniform_locs)
{
- 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 empty_locs =
+ prog->NumUniformRemapTable - num_explicit_uniform_locs;
/* 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->NumUniformStorage; i++) {
+ if (prog->UniformStorage[i].type->is_subroutine() ||
+ prog->UniformStorage[i].is_shader_storage)
continue;
- if (uniforms[i].remap_location != UNMAPPED_UNIFORM_LOC) {
+ if (prog->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->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->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->UniformStorage[i];
}
}
}
/* Reserve locations for rest of the uniforms. */
- for (unsigned i = 0; i < num_uniforms; i++) {
+ for (unsigned i = 0; i < prog->NumUniformStorage; i++) {
- if (uniforms[i].type->is_subroutine() ||
- uniforms[i].is_shader_storage)
+ if (prog->UniformStorage[i].type->is_subroutine() ||
+ prog->UniformStorage[i].is_shader_storage)
continue;
/* Built-in uniforms should not get any location. */
- if (uniforms[i].builtin)
+ if (prog->UniformStorage[i].builtin)
continue;
/* Explicit ones have been set already. */
- if (uniforms[i].remap_location != UNMAPPED_UNIFORM_LOC)
+ if (prog->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->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 = find_empty_block(prog, &prog->UniformStorage[i]);
/* Add new entries to the total amount of entries. */
total_entries += entries;
/* 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->UniformStorage[i];
/* set the base location in remap table for the uniform */
- uniforms[i].remap_location = chosen_location;
+ prog->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->NumUniformStorage; i++) {
+ if (!prog->UniformStorage[i].type->is_subroutine())
continue;
- if (uniforms[i].remap_location == UNMAPPED_UNIFORM_LOC)
+ if (prog->UniformStorage[i].remap_location == UNMAPPED_UNIFORM_LOC)
continue;
for (unsigned j = 0; j < MESA_SHADER_STAGES; j++) {
if (!sh)
continue;
- if (!uniforms[i].opaque[j].active)
+ if (!prog->UniformStorage[i].opaque[j].active)
continue;
/* How many new entries for this uniform? */
- const unsigned entries = MAX2(1, uniforms[i].array_elements);
+ const unsigned entries =
+ MAX2(1, prog->UniformStorage[i].array_elements);
/* 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;
+ unsigned element_loc = prog->UniformStorage[i].remap_location + k;
assert(sh->SubroutineUniformRemapTable[element_loc] ==
INACTIVE_UNIFORM_EXPLICIT_LOCATION);
- sh->SubroutineUniformRemapTable[element_loc] = &uniforms[i];
+ sh->SubroutineUniformRemapTable[element_loc] =
+ &prog->UniformStorage[i];
}
}
}
/* reserve subroutine locations */
- for (unsigned i = 0; i < num_uniforms; i++) {
+ for (unsigned i = 0; i < prog->NumUniformStorage; i++) {
- if (!uniforms[i].type->is_subroutine())
+ if (!prog->UniformStorage[i].type->is_subroutine())
continue;
- const unsigned entries = MAX2(1, uniforms[i].array_elements);
+ const unsigned entries = MAX2(1, prog->UniformStorage[i].array_elements);
- if (uniforms[i].remap_location != UNMAPPED_UNIFORM_LOC)
+ if (prog->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)
+ if (!prog->UniformStorage[i].opaque[j].active)
continue;
sh->SubroutineUniformRemapTable =
gl_uniform_storage *,
sh->NumSubroutineUniformRemapTable + entries);
- for (unsigned k = 0; k < entries; k++)
- sh->SubroutineUniformRemapTable[sh->NumSubroutineUniformRemapTable + k] = &uniforms[i];
- uniforms[i].remap_location = sh->NumSubroutineUniformRemapTable;
+ for (unsigned k = 0; k < entries; k++) {
+ sh->SubroutineUniformRemapTable[sh->NumSubroutineUniformRemapTable + k] =
+ &prog->UniformStorage[i];
+ }
+ prog->UniformStorage[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,
+ unsigned num_explicit_uniform_locs)
+{
+ /* On the outside chance that there were no uniforms, bail out.
+ */
+ if (prog->NumUniformStorage == 0)
+ return;
+
+ unsigned int boolean_true = ctx->Const.UniformBooleanTrue;
+
+ prog->UniformStorage = rzalloc_array(prog, struct gl_uniform_storage,
+ prog->NumUniformStorage);
+ union gl_constant_value *data = rzalloc_array(prog->UniformStorage,
+ 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,
+ prog->UniformStorage, data);
+
+ 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));
+ }
#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->NumUniformStorage; i++) {
+ assert(prog->UniformStorage[i].storage != NULL ||
+ prog->UniformStorage[i].builtin ||
+ prog->UniformStorage[i].is_shader_storage ||
+ prog->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, num_explicit_uniform_locs);
link_set_uniform_initializers(prog, boolean_true);
+}
+
+void
+link_assign_uniform_locations(struct gl_shader_program *prog,
+ struct gl_context *ctx,
+ unsigned int num_explicit_uniform_locs)
+{
+ 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;
+ }
+ }
+
+ prog->NumUniformStorage = uniform_size.num_active_uniforms;
+ prog->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,
+ num_explicit_uniform_locs);
}