|| (type->is_array() && type->fields.array->is_interface()));
char *name_copy = ralloc_strdup(NULL, name);
- recursion(type, &name_copy, strlen(name), false);
+ recursion(type, &name_copy, strlen(name), false, NULL);
ralloc_free(name_copy);
}
*/
/* Only strdup the name if we actually will need to modify it. */
- if (t->is_record() || (t->is_array() && t->fields.array->is_record())) {
+ if (var->from_named_ifc_block_array) {
+ /* lower_named_interface_blocks created this variable by lowering an
+ * interface block array to an array variable. For example if the
+ * original source code was:
+ *
+ * out Blk { vec4 bar } foo[3];
+ *
+ * Then the variable is now:
+ *
+ * out vec4 bar[3];
+ *
+ * We need to visit each array element using the names constructed like
+ * so:
+ *
+ * Blk[0].bar
+ * Blk[1].bar
+ * Blk[2].bar
+ */
+ assert(t->is_array());
+ const glsl_type *ifc_type = var->get_interface_type();
+ char *name = ralloc_strdup(NULL, ifc_type->name);
+ size_t name_length = strlen(name);
+ for (unsigned i = 0; i < t->length; i++) {
+ size_t new_length = name_length;
+ ralloc_asprintf_rewrite_tail(&name, &new_length, "[%u].%s", i,
+ var->name);
+ /* Note: row_major is only meaningful for uniform blocks, and
+ * lowering is only applied to non-uniform interface blocks, so we
+ * can safely pass false for row_major.
+ */
+ recursion(var->type, &name, new_length, false, NULL);
+ }
+ ralloc_free(name);
+ } else if (var->from_named_ifc_block_nonarray) {
+ /* lower_named_interface_blocks created this variable by lowering a
+ * named interface block (non-array) to an ordinary variable. For
+ * example if the original source code was:
+ *
+ * out Blk { vec4 bar } foo;
+ *
+ * Then the variable is now:
+ *
+ * out vec4 bar;
+ *
+ * We need to visit this variable using the name:
+ *
+ * Blk.bar
+ */
+ const glsl_type *ifc_type = var->get_interface_type();
+ char *name = ralloc_asprintf(NULL, "%s.%s", ifc_type->name, var->name);
+ /* Note: row_major is only meaningful for uniform blocks, and lowering
+ * is only applied to non-uniform interface blocks, so we can safely
+ * pass false for row_major.
+ */
+ recursion(var->type, &name, strlen(name), false, NULL);
+ ralloc_free(name);
+ } else if (t->is_record() || (t->is_array() && t->fields.array->is_record())) {
char *name = ralloc_strdup(NULL, var->name);
- recursion(var->type, &name, strlen(name), false);
+ recursion(var->type, &name, strlen(name), false, NULL);
ralloc_free(name);
} else if (t->is_interface()) {
char *name = ralloc_strdup(NULL, var->type->name);
- recursion(var->type, &name, strlen(name), false);
+ recursion(var->type, &name, strlen(name), false, NULL);
ralloc_free(name);
} else if (t->is_array() && t->fields.array->is_interface()) {
char *name = ralloc_strdup(NULL, var->type->fields.array->name);
- recursion(var->type, &name, strlen(name), false);
+ recursion(var->type, &name, strlen(name), false, NULL);
ralloc_free(name);
} else {
- this->visit_field(t, var->name, false);
+ this->visit_field(t, var->name, false, NULL);
}
}
void
program_resource_visitor::recursion(const glsl_type *t, char **name,
- size_t name_length, bool row_major)
+ size_t name_length, bool row_major,
+ const glsl_type *record_type)
{
/* Records need to have each field processed individually.
*
* individually.
*/
if (t->is_record() || t->is_interface()) {
+ if (record_type == NULL && t->is_record())
+ record_type = t;
+
for (unsigned i = 0; i < t->length; i++) {
const char *field = t->fields.structure[i].name;
size_t new_length = name_length;
}
recursion(t->fields.structure[i].type, name, new_length,
- t->fields.structure[i].row_major);
+ t->fields.structure[i].row_major, record_type);
+
+ /* Only the first leaf-field of the record gets called with the
+ * record type pointer.
+ */
+ record_type = NULL;
}
} else if (t->is_array() && (t->fields.array->is_record()
|| t->fields.array->is_interface())) {
+ if (record_type == NULL && t->fields.array->is_record())
+ record_type = t->fields.array;
+
for (unsigned i = 0; i < t->length; i++) {
size_t new_length = name_length;
/* Append the subscript to the current variable name */
ralloc_asprintf_rewrite_tail(name, &new_length, "[%u]", i);
- recursion(t->fields.array, name, new_length,
- t->fields.structure[i].row_major);
+ recursion(t->fields.array, name, new_length, row_major,
+ record_type);
+
+ /* Only the first leaf-field of the record gets called with the
+ * record type pointer.
+ */
+ record_type = NULL;
}
} else {
- this->visit_field(t, *name, row_major);
+ this->visit_field(t, *name, row_major, record_type);
}
}
+void
+program_resource_visitor::visit_field(const glsl_type *type, const char *name,
+ bool row_major,
+ const glsl_type *record_type)
+{
+ visit_field(type, name, row_major);
+}
+
void
program_resource_visitor::visit_field(const glsl_struct_field *field)
{
/* empty */
}
+namespace {
+
/**
* Class to help calculate the storage requirements for a set of uniforms
*
public:
count_uniform_size(struct string_to_uint_map *map)
: num_active_uniforms(0), num_values(0), num_shader_samplers(0),
- num_shader_uniform_components(0), map(map)
+ num_shader_uniform_components(0), is_ubo_var(false), map(map)
{
/* empty */
}
void process(ir_variable *var)
{
+ this->is_ubo_var = var->is_in_uniform_block();
if (var->is_interface_instance())
- program_resource_visitor::process(var->interface_type,
- var->interface_type->name);
+ program_resource_visitor::process(var->get_interface_type(),
+ var->get_interface_type()->name);
else
program_resource_visitor::process(var);
}
*/
unsigned num_shader_uniform_components;
+ bool is_ubo_var;
+
private:
virtual void visit_field(const glsl_type *type, const char *name,
bool row_major)
* Note that samplers do not count against this limit because they
* don't use any storage on current hardware.
*/
- this->num_shader_uniform_components += values;
+ if (!is_ubo_var)
+ this->num_shader_uniform_components += values;
}
/* If the uniform is already in the map, there's nothing more to do.
struct string_to_uint_map *map;
};
+} /* anonymous namespace */
+
/**
* Class to help parcel out pieces of backing storage to uniforms
*
ubo_block_index = -1;
if (var->is_in_uniform_block()) {
if (var->is_interface_instance() && var->type->is_array()) {
- unsigned l = strlen(var->interface_type->name);
+ unsigned l = strlen(var->get_interface_type()->name);
for (unsigned i = 0; i < prog->NumUniformBlocks; i++) {
- if (strncmp(var->interface_type->name,
+ if (strncmp(var->get_interface_type()->name,
prog->UniformBlocks[i].Name,
l) == 0
&& prog->UniformBlocks[i].Name[l] == '[') {
}
} else {
for (unsigned i = 0; i < prog->NumUniformBlocks; i++) {
- if (strcmp(var->interface_type->name,
+ if (strcmp(var->get_interface_type()->name,
prog->UniformBlocks[i].Name) == 0) {
ubo_block_index = i;
break;
}
if (var->is_interface_instance())
- process(var->interface_type, var->interface_type->name);
+ process(var->get_interface_type(),
+ var->get_interface_type()->name);
else
process(var);
} else
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 visit_field(const glsl_type *type, const char *name,
+ bool row_major, const glsl_type *record_type)
{
assert(!type->is_record());
assert(!(type->is_array() && type->fields.array->is_record()));
this->uniforms[id].num_driver_storage = 0;
this->uniforms[id].driver_storage = NULL;
this->uniforms[id].storage = this->values;
+ this->uniforms[id].atomic_buffer_index = -1;
if (this->ubo_block_index != -1) {
this->uniforms[id].block_index = this->ubo_block_index;
- unsigned alignment = type->std140_base_alignment(ubo_row_major);
+ const unsigned alignment = record_type
+ ? record_type->std140_base_alignment(ubo_row_major)
+ : type->std140_base_alignment(ubo_row_major);
this->ubo_byte_offset = glsl_align(this->ubo_byte_offset, alignment);
this->uniforms[id].offset = this->ubo_byte_offset;
this->ubo_byte_offset += type->std140_size(ubo_row_major);
*/
count_uniform_size uniform_size(prog->UniformHash);
for (unsigned i = 0; i < MESA_SHADER_TYPES; i++) {
- if (prog->_LinkedShaders[i] == NULL)
+ struct gl_shader *sh = prog->_LinkedShaders[i];
+
+ if (sh == NULL)
continue;
/* Uniforms that lack an initializer in the shader code have an initial
* initializer, if present, or 0 if no initializer is present. Sampler
* types cannot have initializers."
*/
- memset(prog->_LinkedShaders[i]->SamplerUnits, 0,
- sizeof(gl_shader::SamplerUnits));
+ memset(sh->SamplerUnits, 0, sizeof(sh->SamplerUnits));
- link_update_uniform_buffer_variables(prog->_LinkedShaders[i]);
+ link_update_uniform_buffer_variables(sh);
/* Reset various per-shader target counts.
*/
uniform_size.start_shader();
- foreach_list(node, prog->_LinkedShaders[i]->ir) {
+ foreach_list(node, sh->ir) {
ir_variable *const var = ((ir_instruction *) node)->as_variable();
if ((var == NULL) || (var->mode != ir_var_uniform))
uniform_size.process(var);
}
- prog->_LinkedShaders[i]->num_samplers = uniform_size.num_shader_samplers;
- prog->_LinkedShaders[i]->num_uniform_components =
- uniform_size.num_shader_uniform_components;
+ sh->num_samplers = uniform_size.num_shader_samplers;
+ 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_user_uniforms = uniform_size.num_active_uniforms;
prog->_LinkedShaders[i]->active_samplers = parcel.shader_samplers_used;
prog->_LinkedShaders[i]->shadow_samplers = parcel.shader_shadow_samplers;
- assert(sizeof(gl_shader::SamplerTargets) == sizeof(parcel.targets));
+ STATIC_ASSERT(sizeof(prog->_LinkedShaders[i]->SamplerTargets) == sizeof(parcel.targets));
memcpy(prog->_LinkedShaders[i]->SamplerTargets, parcel.targets,
- sizeof(gl_shader::SamplerTargets));
+ sizeof(prog->_LinkedShaders[i]->SamplerTargets));
}
+ /* Determine the size of the largest uniform array queryable via
+ * glGetUniformLocation. Using this as the location scale guarantees that
+ * there is enough "room" for the array index to be stored in the low order
+ * part of the uniform location. It also makes the locations be more
+ * tightly packed.
+ */
+ unsigned max_array_size = 1;
+ for (unsigned i = 0; i < num_user_uniforms; i++) {
+ if (uniforms[i].array_elements > max_array_size)
+ max_array_size = uniforms[i].array_elements;
+ }
+
+ prog->UniformLocationBaseScale = max_array_size;
+
#ifndef NDEBUG
for (unsigned i = 0; i < num_user_uniforms; i++) {
assert(uniforms[i].storage != NULL);