diff options
Diffstat (limited to 'src/glsl/linker.cpp')
-rw-r--r-- | src/glsl/linker.cpp | 72 |
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); } |