From: Iago Toral Quiroga Date: Mon, 16 Oct 2017 10:43:52 +0000 (+0200) Subject: glsl/linker: produce error when invalid explicit locations are used X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=2d87caa279ea319fa89572fb8595a46c05a615c4;p=mesa.git glsl/linker: produce error when invalid explicit locations are used We only need to add a check to validate output locations here. For inputs with invalid locations we will fail to link when we can't find a matching output in the same (invalid) location. v2: compute location slots properly depending on shader stage and variable type / direction Fixes: KHR-GL45.enhanced_layouts.varying_location_limit Reviewed-by: Nicolai Hähnle --- diff --git a/src/compiler/glsl/link_varyings.cpp b/src/compiler/glsl/link_varyings.cpp index 29842ecacda..69c92bf53b0 100644 --- a/src/compiler/glsl/link_varyings.cpp +++ b/src/compiler/glsl/link_varyings.cpp @@ -377,11 +377,38 @@ cross_validate_front_and_back_color(struct gl_shader_program *prog, consumer_stage, producer_stage); } +static unsigned +compute_variable_location_slot(ir_variable *var, gl_shader_stage stage) +{ + unsigned location_start = VARYING_SLOT_VAR0; + + switch (stage) { + case MESA_SHADER_VERTEX: + if (var->data.mode == ir_var_shader_in) + location_start = VERT_ATTRIB_GENERIC0; + break; + case MESA_SHADER_TESS_CTRL: + case MESA_SHADER_TESS_EVAL: + if (var->data.patch) + location_start = VARYING_SLOT_PATCH0; + break; + case MESA_SHADER_FRAGMENT: + if (var->data.mode == ir_var_shader_out) + location_start = FRAG_RESULT_DATA0; + break; + default: + break; + } + + return var->data.location - location_start; +} + /** * Validate that outputs from one stage match inputs of another */ void -cross_validate_outputs_to_inputs(struct gl_shader_program *prog, +cross_validate_outputs_to_inputs(struct gl_context *ctx, + struct gl_shader_program *prog, gl_linked_shader *producer, gl_linked_shader *consumer) { @@ -406,10 +433,19 @@ cross_validate_outputs_to_inputs(struct gl_shader_program *prog, */ const glsl_type *type = get_varying_type(var, producer->Stage); unsigned num_elements = type->count_attribute_slots(false); - unsigned idx = var->data.location - VARYING_SLOT_VAR0; + unsigned idx = compute_variable_location_slot(var, producer->Stage); unsigned slot_limit = idx + num_elements; unsigned last_comp; + unsigned slot_max = + ctx->Const.Program[producer->Stage].MaxOutputComponents / 4; + if (slot_limit > slot_max) { + linker_error(prog, + "Invalid location %u in %s shader\n", + idx, _mesa_shader_stage_to_string(producer->Stage)); + return; + } + if (type->without_array()->is_record()) { /* The component qualifier can't be used on structs so just treat * all component slots as used. @@ -515,7 +551,8 @@ cross_validate_outputs_to_inputs(struct gl_shader_program *prog, const glsl_type *type = get_varying_type(input, consumer->Stage); unsigned num_elements = type->count_attribute_slots(false); - unsigned idx = input->data.location - VARYING_SLOT_VAR0; + unsigned idx = + compute_variable_location_slot(input, consumer->Stage); unsigned slot_limit = idx + num_elements; while (idx < slot_limit) { diff --git a/src/compiler/glsl/link_varyings.h b/src/compiler/glsl/link_varyings.h index 4e1f6d2e42a..081b04ea38f 100644 --- a/src/compiler/glsl/link_varyings.h +++ b/src/compiler/glsl/link_varyings.h @@ -300,7 +300,8 @@ link_varyings(struct gl_shader_program *prog, unsigned first, unsigned last, struct gl_context *ctx, void *mem_ctx); void -cross_validate_outputs_to_inputs(struct gl_shader_program *prog, +cross_validate_outputs_to_inputs(struct gl_context *ctx, + struct gl_shader_program *prog, gl_linked_shader *producer, gl_linked_shader *consumer); diff --git a/src/compiler/glsl/linker.cpp b/src/compiler/glsl/linker.cpp index 03eb05bf637..37983096784 100644 --- a/src/compiler/glsl/linker.cpp +++ b/src/compiler/glsl/linker.cpp @@ -4929,7 +4929,7 @@ link_shaders(struct gl_context *ctx, struct gl_shader_program *prog) if (!prog->data->LinkStatus) goto done; - cross_validate_outputs_to_inputs(prog, + cross_validate_outputs_to_inputs(ctx, prog, prog->_LinkedShaders[prev], prog->_LinkedShaders[i]); if (!prog->data->LinkStatus)