X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fglsl%2Flinker.cpp;h=3d1b8a2f70368e07dd10399630875f5401dfe5b9;hb=42fd9c2ebb8a9eecf69d6a7a2bc0d778f49285de;hp=c5c8c9cdd6382fc2b5d1eb6a2110d5353dd5b362;hpb=bfd7c9ac228c7ed8aec04c3b3aa33f40ee00b035;p=mesa.git diff --git a/src/glsl/linker.cpp b/src/glsl/linker.cpp index c5c8c9cdd63..3d1b8a2f703 100644 --- a/src/glsl/linker.cpp +++ b/src/glsl/linker.cpp @@ -68,10 +68,6 @@ #include #include -extern "C" { -#include -} - #include "main/core.h" #include "glsl_symbol_table.h" #include "ir.h" @@ -80,6 +76,10 @@ extern "C" { #include "linker.h" #include "ir_optimization.h" +extern "C" { +#include "main/shaderobj.h" +} + /** * Visitor that determines whether or not a variable is ever written. */ @@ -172,9 +172,9 @@ linker_error_printf(gl_shader_program *prog, const char *fmt, ...) { va_list ap; - prog->InfoLog = talloc_strdup_append(prog->InfoLog, "error: "); + ralloc_strcat(&prog->InfoLog, "error: "); va_start(ap, fmt); - prog->InfoLog = talloc_vasprintf_append(prog->InfoLog, fmt, ap); + ralloc_vasprintf_append(&prog->InfoLog, fmt, ap); va_end(ap); } @@ -191,7 +191,7 @@ invalidate_variable_locations(gl_shader *sh, enum ir_variable_mode mode, /* Only assign locations for generic attributes / varyings / etc. */ - if (var->location >= generic_base) + if ((var->location >= generic_base) && !var->explicit_location) var->location = -1; } } @@ -321,6 +321,9 @@ cross_validate_globals(struct gl_shader_program *prog, */ glsl_symbol_table variables; for (unsigned i = 0; i < num_shaders; i++) { + if (shader_list[i] == NULL) + continue; + foreach_list(node, shader_list[i]->ir) { ir_variable *const var = ((ir_instruction *) node)->as_variable(); @@ -343,14 +346,68 @@ cross_validate_globals(struct gl_shader_program *prog, ir_variable *const existing = variables.get_variable(var->name); if (existing != NULL) { if (var->type != existing->type) { - linker_error_printf(prog, "%s `%s' declared as type " - "`%s' and type `%s'\n", - mode_string(var), - var->name, var->type->name, - existing->type->name); - return false; + /* Consider the types to be "the same" if both types are arrays + * of the same type and one of the arrays is implicitly sized. + * In addition, set the type of the linked variable to the + * explicitly sized array. + */ + if (var->type->is_array() + && existing->type->is_array() + && (var->type->fields.array == existing->type->fields.array) + && ((var->type->length == 0) + || (existing->type->length == 0))) { + if (var->type->length != 0) { + existing->type = var->type; + } + } else { + linker_error_printf(prog, "%s `%s' declared as type " + "`%s' and type `%s'\n", + mode_string(var), + var->name, var->type->name, + existing->type->name); + return false; + } } + if (var->explicit_location) { + if (existing->explicit_location + && (var->location != existing->location)) { + linker_error_printf(prog, "explicit locations for %s " + "`%s' have differing values\n", + mode_string(var), var->name); + return false; + } + + existing->location = var->location; + existing->explicit_location = true; + } + + /* Validate layout qualifiers for gl_FragDepth. + * + * From the AMD_conservative_depth spec: + * "If gl_FragDepth is redeclared in any fragment shader in + * a program, it must be redeclared in all fragment shaders in that + * program that have static assignments to gl_FragDepth. All + * redeclarations of gl_FragDepth in all fragment shaders in + * a single program must have the same set of qualifiers." + */ + if (strcmp(var->name, "gl_FragDepth") == 0) { + bool layout_declared = var->depth_layout != ir_depth_layout_none; + bool layout_differs = var->depth_layout != existing->depth_layout; + if (layout_declared && layout_differs) { + linker_error_printf(prog, + "All redeclarations of gl_FragDepth in all fragment shaders " + "in a single program must have the same set of qualifiers."); + } + if (var->used && layout_differs) { + linker_error_printf(prog, + "If gl_FragDepth is redeclared with a layout qualifier in" + "any fragment shader, it must be redeclared with the same" + "layout qualifier in all fragment shaders that have" + "assignments to gl_FragDepth"); + } + } + /* FINISHME: Handle non-constant initializers. */ if (var->constant_value != NULL) { @@ -375,10 +432,23 @@ cross_validate_globals(struct gl_shader_program *prog, * FINISHME: will fail. */ existing->constant_value = - var->constant_value->clone(talloc_parent(existing), NULL); + var->constant_value->clone(ralloc_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; } + if (existing->centroid != var->centroid) { + linker_error_printf(prog, "declarations for %s `%s' have " + "mismatching centroid qualifiers\n", + mode_string(var), var->name); + return false; + } } else - variables.add_variable(var->name, var); + variables.add_variable(var); } } @@ -393,7 +463,7 @@ bool cross_validate_uniforms(struct gl_shader_program *prog) { return cross_validate_globals(prog, prog->_LinkedShaders, - prog->_NumLinkedShaders, true); + MESA_SHADER_TYPES, true); } @@ -420,7 +490,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); } @@ -442,14 +512,35 @@ cross_validate_outputs_to_inputs(struct gl_shader_program *prog, /* Check that the types match between stages. */ if (input->type != output->type) { - linker_error_printf(prog, - "%s shader output `%s' delcared as " - "type `%s', but %s shader input declared " - "as type `%s'\n", - producer_stage, output->name, - output->type->name, - consumer_stage, input->type->name); - return false; + /* There is a bit of a special case for gl_TexCoord. This + * built-in is unsized by default. Appliations that variable + * access it must redeclare it with a size. There is some + * language in the GLSL spec that implies the fragment shader + * and vertex shader do not have to agree on this size. Other + * driver behave this way, and one or two applications seem to + * rely on it. + * + * Neither declaration needs to be modified here because the array + * sizes are fixed later when update_array_sizes is called. + * + * From page 48 (page 54 of the PDF) of the GLSL 1.10 spec: + * + * "Unlike user-defined varying variables, the built-in + * varying variables don't have a strict one-to-one + * correspondence between the vertex language and the + * fragment language." + */ + if (!output->type->is_array() + || (strncmp("gl_", output->name, 3) != 0)) { + linker_error_printf(prog, + "%s shader output `%s' declared as " + "type `%s', but %s shader input declared " + "as type `%s'\n", + producer_stage, output->name, + output->type->name, + consumer_stage, input->type->name); + return false; + } } /* Check that all of the qualifiers match between stages. @@ -512,9 +603,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); } } } @@ -571,7 +662,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; } @@ -692,7 +783,8 @@ get_main_function_signature(gl_shader *sh) * shader is returned. */ static struct gl_shader * -link_intrastage_shaders(GLcontext *ctx, +link_intrastage_shaders(void *mem_ctx, + struct gl_context *ctx, struct gl_shader_program *prog, struct gl_shader **shader_list, unsigned num_shaders) @@ -726,14 +818,14 @@ link_intrastage_shaders(GLcontext *ctx, ir_function_signature *sig = (ir_function_signature *) iter.get(); - if (!sig->is_defined || sig->is_built_in) + if (!sig->is_defined || sig->is_builtin) continue; ir_function_signature *other_sig = other->exact_matching_signature(& sig->parameters); if ((other_sig != NULL) && other_sig->is_defined - && !other_sig->is_built_in) { + && !other_sig->is_builtin) { linker_error_printf(prog, "function `%s' is multiply defined", f->name); @@ -766,9 +858,9 @@ link_intrastage_shaders(GLcontext *ctx, return NULL; } - gl_shader *const linked = ctx->Driver.NewShader(NULL, 0, main->Type); + 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); @@ -813,10 +905,39 @@ link_intrastage_shaders(GLcontext *ctx, assert(idx == num_linking_shaders); - link_function_calls(prog, linked, linking_shaders, num_linking_shaders); + if (!link_function_calls(prog, linked, linking_shaders, + num_linking_shaders)) { + ctx->Driver.DeleteShader(ctx, linked); + linked = NULL; + } free(linking_shaders); + /* Make a pass over all variable declarations to ensure that arrays with + * unspecified sizes have a size specified. The size is inferred from the + * max_array_access field. + */ + if (linked != NULL) { + class array_sizing_visitor : public ir_hierarchical_visitor { + public: + virtual ir_visitor_status visit(ir_variable *var) + { + if (var->type->is_array() && (var->type->length == 0)) { + const glsl_type *type = + glsl_type::get_array_instance(var->type->fields.array, + var->max_array_access); + + assert(type != NULL); + var->type = type; + } + + return visit_continue; + } + } v; + + v.run(linked->ir); + } + return linked; } @@ -843,18 +964,26 @@ struct uniform_node { */ static void -update_uniform_array_sizes(struct gl_shader_program *prog) +update_array_sizes(struct gl_shader_program *prog) { - for (unsigned i = 0; i < prog->_NumLinkedShaders; i++) { + for (unsigned i = 0; i < MESA_SHADER_TYPES; i++) { + if (prog->_LinkedShaders[i] == NULL) + continue; + foreach_list(node, prog->_LinkedShaders[i]->ir) { ir_variable *const var = ((ir_instruction *) node)->as_variable(); - if ((var == NULL) || (var->mode != ir_var_uniform) || + if ((var == NULL) || (var->mode != ir_var_uniform && + var->mode != ir_var_in && + var->mode != ir_var_out) || !var->type->is_array()) continue; unsigned int size = var->max_array_access; - for (unsigned j = 0; j < prog->_NumLinkedShaders; j++) { + for (unsigned j = 0; j < MESA_SHADER_TYPES; j++) { + if (prog->_LinkedShaders[j] == NULL) + continue; + foreach_list(node2, prog->_LinkedShaders[j]->ir) { ir_variable *other_var = ((ir_instruction *) node2)->as_variable(); if (!other_var) @@ -866,6 +995,7 @@ update_uniform_array_sizes(struct gl_shader_program *prog) } } } + if (size + 1 != var->type->fields.array->length) { var->type = glsl_type::get_array_instance(var->type->fields.array, size + 1); @@ -877,6 +1007,84 @@ update_uniform_array_sizes(struct gl_shader_program *prog) } } +static void +add_uniform(void *mem_ctx, exec_list *uniforms, struct hash_table *ht, + const char *name, const glsl_type *type, GLenum shader_type, + unsigned *next_shader_pos, unsigned *total_uniforms) +{ + if (type->is_record()) { + for (unsigned int i = 0; i < type->length; i++) { + const glsl_type *field_type = type->fields.structure[i].type; + char *field_name = ralloc_asprintf(mem_ctx, "%s.%s", name, + type->fields.structure[i].name); + + add_uniform(mem_ctx, uniforms, ht, field_name, field_type, + shader_type, next_shader_pos, total_uniforms); + } + } else { + uniform_node *n = (uniform_node *) hash_table_find(ht, name); + unsigned int vec4_slots; + const glsl_type *array_elem_type = NULL; + + if (type->is_array()) { + array_elem_type = type->fields.array; + /* Array of structures. */ + if (array_elem_type->is_record()) { + for (unsigned int i = 0; i < type->length; i++) { + char *elem_name = ralloc_asprintf(mem_ctx, "%s[%d]", name, i); + add_uniform(mem_ctx, uniforms, ht, elem_name, array_elem_type, + shader_type, next_shader_pos, total_uniforms); + } + return; + } + } + + /* Fix the storage size of samplers at 1 vec4 each. Be sure to pad out + * vectors to vec4 slots. + */ + if (type->is_array()) { + if (array_elem_type->is_sampler()) + vec4_slots = type->length; + else + vec4_slots = type->length * array_elem_type->matrix_columns; + } else if (type->is_sampler()) { + vec4_slots = 1; + } else { + vec4_slots = type->matrix_columns; + } + + if (n == NULL) { + n = (uniform_node *) calloc(1, sizeof(struct uniform_node)); + n->u = (gl_uniform *) calloc(1, sizeof(struct gl_uniform)); + n->slots = vec4_slots; + + n->u->Name = strdup(name); + n->u->Type = type; + n->u->VertPos = -1; + n->u->FragPos = -1; + n->u->GeomPos = -1; + (*total_uniforms)++; + + hash_table_insert(ht, n, name); + uniforms->push_tail(& n->link); + } + + switch (shader_type) { + case GL_VERTEX_SHADER: + n->u->VertPos = *next_shader_pos; + break; + case GL_FRAGMENT_SHADER: + n->u->FragPos = *next_shader_pos; + break; + case GL_GEOMETRY_SHADER: + n->u->GeomPos = *next_shader_pos; + break; + } + + (*next_shader_pos) += vec4_slots; + } +} + void assign_uniform_locations(struct gl_shader_program *prog) { @@ -885,10 +1093,12 @@ assign_uniform_locations(struct gl_shader_program *prog) unsigned total_uniforms = 0; hash_table *ht = hash_table_ctor(32, hash_table_string_hash, hash_table_string_compare); + void *mem_ctx = ralloc_context(NULL); - update_uniform_array_sizes(prog); + for (unsigned i = 0; i < MESA_SHADER_TYPES; i++) { + if (prog->_LinkedShaders[i] == NULL) + continue; - for (unsigned i = 0; i < prog->_NumLinkedShaders; i++) { unsigned next_position = 0; foreach_list(node, prog->_LinkedShaders[i]->ir) { @@ -897,54 +1107,23 @@ assign_uniform_locations(struct gl_shader_program *prog) if ((var == NULL) || (var->mode != ir_var_uniform)) continue; - const unsigned vec4_slots = (var->component_slots() + 3) / 4; - if (vec4_slots == 0) { - /* If we've got a sampler or an aggregate of them, the size can - * end up zero. Don't allocate any space. + if (strncmp(var->name, "gl_", 3) == 0) { + /* At the moment, we don't allocate uniform locations for + * builtin uniforms. It's permitted by spec, and we'll + * likely switch to doing that at some point, but not yet. */ continue; } - uniform_node *n = (uniform_node *) hash_table_find(ht, var->name); - if (n == NULL) { - n = (uniform_node *) calloc(1, sizeof(struct uniform_node)); - n->u = (gl_uniform *) calloc(vec4_slots, sizeof(struct gl_uniform)); - n->slots = vec4_slots; - - n->u[0].Name = strdup(var->name); - for (unsigned j = 1; j < vec4_slots; j++) - n->u[j].Name = strdup(var->name); - - hash_table_insert(ht, n, n->u[0].Name); - uniforms.push_tail(& n->link); - total_uniforms += vec4_slots; - } - - if (var->constant_value != NULL) - for (unsigned j = 0; j < vec4_slots; j++) - n->u[j].Initialized = true; - var->location = next_position; - - for (unsigned j = 0; j < vec4_slots; j++) { - switch (prog->_LinkedShaders[i]->Type) { - case GL_VERTEX_SHADER: - n->u[j].VertPos = next_position; - break; - case GL_FRAGMENT_SHADER: - n->u[j].FragPos = next_position; - break; - case GL_GEOMETRY_SHADER: - /* FINISHME: Support geometry shaders. */ - assert(prog->_LinkedShaders[i]->Type != GL_GEOMETRY_SHADER); - break; - } - - next_position++; - } + add_uniform(mem_ctx, &uniforms, ht, var->name, var->type, + prog->_LinkedShaders[i]->Type, + &next_position, &total_uniforms); } } + ralloc_free(mem_ctx); + gl_uniform_list *ul = (gl_uniform_list *) calloc(1, sizeof(gl_uniform_list)); @@ -960,8 +1139,8 @@ assign_uniform_locations(struct gl_shader_program *prog) next = (uniform_node *) node->link.next; node->link.remove(); - memcpy(&ul->Uniforms[idx], node->u, sizeof(gl_uniform) * node->slots); - idx += node->slots; + memcpy(&ul->Uniforms[idx], node->u, sizeof(gl_uniform)); + idx++; free(node->u); free(node); @@ -1123,6 +1302,24 @@ assign_attribute_locations(gl_shader_program *prog, unsigned max_attribute_index if ((var == NULL) || (var->mode != ir_var_in)) continue; + if (var->explicit_location) { + const unsigned slots = count_attribute_slots(var->type); + const unsigned use_mask = (1 << slots) - 1; + const int attr = var->location - VERT_ATTRIB_GENERIC0; + + if ((var->location >= (int)(max_attribute_index + VERT_ATTRIB_GENERIC0)) + || (var->location < 0)) { + linker_error_printf(prog, + "invalid explicit location %d specified for " + "`%s'\n", + (var->location < 0) ? var->location : attr, + var->name); + return false; + } else if (var->location >= VERT_ATTRIB_GENERIC0) { + used_locations |= (use_mask << attr); + } + } + /* The location was explicitly assigned, nothing to do here. */ if (var->location != -1) @@ -1176,19 +1373,20 @@ assign_attribute_locations(gl_shader_program *prog, unsigned max_attribute_index /** - * Demote shader outputs that are not read to being just plain global variables + * Demote shader inputs and outputs that are not used in other stages */ void -demote_unread_shader_outputs(gl_shader *sh) +demote_shader_inputs_and_outputs(gl_shader *sh, enum ir_variable_mode mode) { foreach_list(node, sh->ir) { ir_variable *const var = ((ir_instruction *) node)->as_variable(); - if ((var == NULL) || (var->mode != ir_var_out)) + if ((var == NULL) || (var->mode != int(mode))) continue; - /* An 'out' variable is only really a shader output if its value is read - * by the following stage. + /* A shader 'in' or 'out' variable is only really an input or output if + * its value is used by other shader stages. This will cause the variable + * to have a location assigned. */ if (var->location == -1) { var->mode = ir_var_auto; @@ -1234,18 +1432,25 @@ assign_varying_locations(struct gl_shader_program *prog, assert(input_var->location == -1); - /* FINISHME: Location assignment will need some changes when arrays, - * FINISHME: matrices, and structures are allowed as shader inputs / - * FINISHME: outputs. - */ output_var->location = output_index; input_var->location = input_index; - output_index++; - input_index++; - } + /* FINISHME: Support for "varying" records in GLSL 1.50. */ + assert(!output_var->type->is_record()); + + if (output_var->type->is_array()) { + const unsigned slots = output_var->type->length + * output_var->type->fields.array->matrix_columns; - demote_unread_shader_outputs(producer); + output_index += slots; + input_index += slots; + } else { + const unsigned slots = output_var->type->matrix_columns; + + output_index += slots; + input_index += slots; + } + } foreach_list(node, consumer->ir) { ir_variable *const var = ((ir_instruction *) node)->as_variable(); @@ -1283,16 +1488,18 @@ assign_varying_locations(struct gl_shader_program *prog, void -link_shaders(GLcontext *ctx, struct gl_shader_program *prog) +link_shaders(struct gl_context *ctx, struct gl_shader_program *prog) { + void *mem_ctx = ralloc_context(NULL); // temporary linker context + prog->LinkStatus = false; prog->Validated = false; prog->_Used = false; if (prog->InfoLog != NULL) - talloc_free(prog->InfoLog); + ralloc_free(prog->InfoLog); - prog->InfoLog = talloc_strdup(NULL, ""); + prog->InfoLog = ralloc_strdup(NULL, ""); /* Separate the shaders into groups based on their type. */ @@ -1331,9 +1538,10 @@ link_shaders(GLcontext *ctx, struct gl_shader_program *prog) * match shading language versions. With GLSL 1.30 and later, the versions * of all shaders must match. */ - assert(min_version >= 110); + assert(min_version >= 100); assert(max_version <= 130); - if ((max_version >= 130) && (min_version != max_version)) { + if ((max_version >= 130 || min_version == 100) + && min_version != max_version) { linker_error_printf(prog, "all shaders must use same shading " "language version\n"); goto done; @@ -1341,39 +1549,43 @@ link_shaders(GLcontext *ctx, struct gl_shader_program *prog) prog->Version = max_version; - for (unsigned int i = 0; i < prog->_NumLinkedShaders; i++) { - ctx->Driver.DeleteShader(ctx, prog->_LinkedShaders[i]); + for (unsigned int i = 0; i < MESA_SHADER_TYPES; i++) { + if (prog->_LinkedShaders[i] != NULL) + ctx->Driver.DeleteShader(ctx, prog->_LinkedShaders[i]); + + prog->_LinkedShaders[i] = NULL; } /* Link all shaders for a particular stage and validate the result. */ - prog->_NumLinkedShaders = 0; 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; if (!validate_vertex_shader_executable(prog, sh)) - goto done; + goto done; - prog->_LinkedShaders[prog->_NumLinkedShaders] = sh; - prog->_NumLinkedShaders++; + _mesa_reference_shader(ctx, &prog->_LinkedShaders[MESA_SHADER_VERTEX], + sh); } 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; if (!validate_fragment_shader_executable(prog, sh)) - goto done; + goto done; - prog->_LinkedShaders[prog->_NumLinkedShaders] = sh; - prog->_NumLinkedShaders++; + _mesa_reference_shader(ctx, &prog->_LinkedShaders[MESA_SHADER_FRAGMENT], + sh); } /* Here begins the inter-stage linking phase. Some initial validation is @@ -1381,14 +1593,26 @@ link_shaders(GLcontext *ctx, struct gl_shader_program *prog) * varyings. */ if (cross_validate_uniforms(prog)) { + unsigned prev; + + for (prev = 0; prev < MESA_SHADER_TYPES; prev++) { + if (prog->_LinkedShaders[prev] != NULL) + break; + } + /* Validate the inputs of each stage with the output of the preceeding * stage. */ - for (unsigned i = 1; i < prog->_NumLinkedShaders; i++) { + for (unsigned i = prev + 1; i < MESA_SHADER_TYPES; i++) { + if (prog->_LinkedShaders[i] == NULL) + continue; + if (!cross_validate_outputs_to_inputs(prog, - prog->_LinkedShaders[i - 1], + prog->_LinkedShaders[prev], prog->_LinkedShaders[i])) goto done; + + prev = i; } prog->LinkStatus = true; @@ -1398,33 +1622,77 @@ link_shaders(GLcontext *ctx, struct gl_shader_program *prog) * uniforms, and varyings. Later optimization could possibly make * some of that unused. */ - for (unsigned i = 0; i < prog->_NumLinkedShaders; i++) { - while (do_common_optimization(prog->_LinkedShaders[i]->ir, true)) + for (unsigned i = 0; i < MESA_SHADER_TYPES; i++) { + if (prog->_LinkedShaders[i] == NULL) + continue; + + while (do_common_optimization(prog->_LinkedShaders[i]->ir, true, 32)) ; } + update_array_sizes(prog); + assign_uniform_locations(prog); - if (prog->_LinkedShaders[0]->Type == GL_VERTEX_SHADER) { + if (prog->_LinkedShaders[MESA_SHADER_VERTEX] != NULL) { /* FINISHME: The value of the max_attribute_index parameter is * FINISHME: implementation dependent based on the value of * FINISHME: GL_MAX_VERTEX_ATTRIBS. GL_MAX_VERTEX_ATTRIBS must be * FINISHME: at least 16, so hardcode 16 for now. */ - if (!assign_attribute_locations(prog, 16)) + if (!assign_attribute_locations(prog, 16)) { + prog->LinkStatus = false; goto done; + } + } - if (prog->_NumLinkedShaders == 1) - demote_unread_shader_outputs(prog->_LinkedShaders[0]); + unsigned prev; + for (prev = 0; prev < MESA_SHADER_TYPES; prev++) { + if (prog->_LinkedShaders[prev] != NULL) + break; } - for (unsigned i = 1; i < prog->_NumLinkedShaders; i++) + for (unsigned i = prev + 1; i < MESA_SHADER_TYPES; i++) { + if (prog->_LinkedShaders[i] == NULL) + continue; + assign_varying_locations(prog, - prog->_LinkedShaders[i - 1], + prog->_LinkedShaders[prev], prog->_LinkedShaders[i]); + prev = i; + } + + if (prog->_LinkedShaders[MESA_SHADER_VERTEX] != NULL) { + demote_shader_inputs_and_outputs(prog->_LinkedShaders[MESA_SHADER_VERTEX], + ir_var_out); + } + + if (prog->_LinkedShaders[MESA_SHADER_GEOMETRY] != NULL) { + gl_shader *const sh = prog->_LinkedShaders[MESA_SHADER_GEOMETRY]; + + demote_shader_inputs_and_outputs(sh, ir_var_in); + demote_shader_inputs_and_outputs(sh, ir_var_inout); + demote_shader_inputs_and_outputs(sh, ir_var_out); + } + + if (prog->_LinkedShaders[MESA_SHADER_FRAGMENT] != NULL) { + gl_shader *const sh = prog->_LinkedShaders[MESA_SHADER_FRAGMENT]; + + demote_shader_inputs_and_outputs(sh, ir_var_in); + } /* FINISHME: Assign fragment shader output locations. */ 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); + } + + ralloc_free(mem_ctx); }