#include "glsl_symbol_table.h"
#include "program.h"
#include "util/string_to_uint_map.h"
+#include "ir_variable_refcount.h"
/**
* \file link_uniforms.cpp
unsigned shader_shadow_samplers;
};
+static bool
+variable_is_referenced(ir_variable_refcount_visitor &v, ir_variable *var)
+{
+ ir_variable_refcount_entry *const entry = v.get_variable_entry(var);
+
+ return entry->referenced_count > 0;
+
+}
+
/**
* Walks the IR and update the references to uniform blocks in the
* ir_variables to point at linked shader's list (previously, they
* 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_variable_refcount_visitor v;
+
+ v.run(shader->ir);
+
foreach_in_list(ir_instruction, node, shader->ir) {
ir_variable *const var = node->as_variable();
assert(var->data.mode == ir_var_uniform ||
var->data.mode == ir_var_shader_storage);
+ 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;
+
if (var->is_interface_instance()) {
+ if (variable_is_referenced(v, var)) {
+ /* 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) {
+ blks[i]->stageref |= 1U << stage;
+ }
+ }
+ }
+
var->data.location = 0;
continue;
}
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++) {
if (found) {
var->data.location = j;
+
+ if (variable_is_referenced(v, var))
+ blks[i]->stageref |= 1U << stage;
+
break;
}
}
memset(sh->SamplerUnits, 0, sizeof(sh->SamplerUnits));
memset(sh->ImageUnits, 0, sizeof(sh->ImageUnits));
- link_update_uniform_buffer_variables(sh);
+ link_update_uniform_buffer_variables(sh, i);
/* Reset various per-shader target counts.
*/