summaryrefslogtreecommitdiffstats
path: root/src/glsl/linker.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/glsl/linker.cpp')
-rw-r--r--src/glsl/linker.cpp72
1 files changed, 62 insertions, 10 deletions
diff --git a/src/glsl/linker.cpp b/src/glsl/linker.cpp
index 616ec780071..e62fe6d7e9f 100644
--- a/src/glsl/linker.cpp
+++ b/src/glsl/linker.cpp
@@ -360,8 +360,12 @@ cross_validate_globals(struct gl_shader_program *prog,
&& (var->type->fields.array == existing->type->fields.array)
&& ((var->type->length == 0)
|| (existing->type->length == 0))) {
- if (existing->type->length == 0)
+ if (existing->type->length == 0) {
existing->type = var->type;
+ existing->max_array_access =
+ MAX2(existing->max_array_access,
+ var->max_array_access);
+ }
} else {
linker_error_printf(prog, "%s `%s' declared as type "
"`%s' and type `%s'\n",
@@ -411,8 +415,15 @@ cross_validate_globals(struct gl_shader_program *prog,
existing->constant_value =
var->constant_value->clone(talloc_parent(existing), NULL);
}
+
+ if (existing->invariant != var->invariant) {
+ linker_error_printf(prog, "declarations for %s `%s' have "
+ "mismatching invariant qualifiers\n",
+ mode_string(var), var->name);
+ return false;
+ }
} else
- variables.add_variable(var->name, var);
+ variables.add_variable(var);
}
}
@@ -454,7 +465,7 @@ cross_validate_outputs_to_inputs(struct gl_shader_program *prog,
if ((var == NULL) || (var->mode != ir_var_out))
continue;
- parameters.add_variable(var->name, var);
+ parameters.add_variable(var);
}
@@ -546,9 +557,9 @@ populate_symbol_table(gl_shader *sh)
ir_function *func;
if ((func = inst->as_function()) != NULL) {
- sh->symbols->add_function(func->name, func);
+ sh->symbols->add_function(func);
} else if ((var = inst->as_variable()) != NULL) {
- sh->symbols->add_variable(var->name, var);
+ sh->symbols->add_variable(var);
}
}
}
@@ -605,7 +616,7 @@ remap_variables(ir_instruction *inst, struct gl_shader *target,
else {
ir_variable *copy = ir->var->clone(this->target, NULL);
- this->symbols->add_variable(copy->name, copy);
+ this->symbols->add_variable(copy);
this->instructions->push_head(copy);
ir->var = copy;
}
@@ -726,7 +737,8 @@ get_main_function_signature(gl_shader *sh)
* shader is returned.
*/
static struct gl_shader *
-link_intrastage_shaders(struct gl_context *ctx,
+link_intrastage_shaders(void *mem_ctx,
+ struct gl_context *ctx,
struct gl_shader_program *prog,
struct gl_shader **shader_list,
unsigned num_shaders)
@@ -802,7 +814,7 @@ link_intrastage_shaders(struct gl_context *ctx,
gl_shader *linked = ctx->Driver.NewShader(NULL, 0, main->Type);
linked->ir = new(linked) exec_list;
- clone_ir_list(linked, linked->ir, main->ir);
+ clone_ir_list(mem_ctx, linked->ir, main->ir);
populate_symbol_table(linked);
@@ -855,6 +867,32 @@ link_intrastage_shaders(struct gl_context *ctx,
free(linking_shaders);
+ /* Make a pass over all global variables to ensure that arrays with
+ * unspecified sizes have a size specified. The size is inferred from the
+ * max_array_access field.
+ */
+ if (linked != NULL) {
+ foreach_list(node, linked->ir) {
+ ir_variable *const var = ((ir_instruction *) node)->as_variable();
+
+ if (var == NULL)
+ continue;
+
+ if ((var->mode != ir_var_auto) && (var->mode != ir_var_temporary))
+ continue;
+
+ if (!var->type->is_array() || (var->type->length != 0))
+ continue;
+
+ const glsl_type *type =
+ glsl_type::get_array_instance(var->type->fields.array,
+ var->max_array_access);
+
+ assert(type != NULL);
+ var->type = type;
+ }
+ }
+
return linked;
}
@@ -1407,6 +1445,8 @@ assign_varying_locations(struct gl_shader_program *prog,
void
link_shaders(struct gl_context *ctx, struct gl_shader_program *prog)
{
+ void *mem_ctx = talloc_init("temporary linker context");
+
prog->LinkStatus = false;
prog->Validated = false;
prog->_Used = false;
@@ -1475,7 +1515,8 @@ link_shaders(struct gl_context *ctx, struct gl_shader_program *prog)
*/
if (num_vert_shaders > 0) {
gl_shader *const sh =
- link_intrastage_shaders(ctx, prog, vert_shader_list, num_vert_shaders);
+ link_intrastage_shaders(mem_ctx, ctx, prog, vert_shader_list,
+ num_vert_shaders);
if (sh == NULL)
goto done;
@@ -1489,7 +1530,8 @@ link_shaders(struct gl_context *ctx, struct gl_shader_program *prog)
if (num_frag_shaders > 0) {
gl_shader *const sh =
- link_intrastage_shaders(ctx, prog, frag_shader_list, num_frag_shaders);
+ link_intrastage_shaders(mem_ctx, ctx, prog, frag_shader_list,
+ num_frag_shaders);
if (sh == NULL)
goto done;
@@ -1598,4 +1640,14 @@ link_shaders(struct gl_context *ctx, struct gl_shader_program *prog)
done:
free(vert_shader_list);
+
+ for (unsigned i = 0; i < MESA_SHADER_TYPES; i++) {
+ if (prog->_LinkedShaders[i] == NULL)
+ continue;
+
+ /* Retain any live IR, but trash the rest. */
+ reparent_ir(prog->_LinkedShaders[i]->ir, prog->_LinkedShaders[i]->ir);
+ }
+
+ talloc_free(mem_ctx);
}