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 <nicolai.haehnle@amd.com>
This commit is contained in:
@@ -377,11 +377,38 @@ cross_validate_front_and_back_color(struct gl_shader_program *prog,
|
|||||||
consumer_stage, producer_stage);
|
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
|
* Validate that outputs from one stage match inputs of another
|
||||||
*/
|
*/
|
||||||
void
|
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 *producer,
|
||||||
gl_linked_shader *consumer)
|
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);
|
const glsl_type *type = get_varying_type(var, producer->Stage);
|
||||||
unsigned num_elements = type->count_attribute_slots(false);
|
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 slot_limit = idx + num_elements;
|
||||||
unsigned last_comp;
|
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()) {
|
if (type->without_array()->is_record()) {
|
||||||
/* The component qualifier can't be used on structs so just treat
|
/* The component qualifier can't be used on structs so just treat
|
||||||
* all component slots as used.
|
* 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);
|
const glsl_type *type = get_varying_type(input, consumer->Stage);
|
||||||
unsigned num_elements = type->count_attribute_slots(false);
|
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;
|
unsigned slot_limit = idx + num_elements;
|
||||||
|
|
||||||
while (idx < slot_limit) {
|
while (idx < slot_limit) {
|
||||||
|
@@ -300,7 +300,8 @@ link_varyings(struct gl_shader_program *prog, unsigned first, unsigned last,
|
|||||||
struct gl_context *ctx, void *mem_ctx);
|
struct gl_context *ctx, void *mem_ctx);
|
||||||
|
|
||||||
void
|
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 *producer,
|
||||||
gl_linked_shader *consumer);
|
gl_linked_shader *consumer);
|
||||||
|
|
||||||
|
@@ -4929,7 +4929,7 @@ link_shaders(struct gl_context *ctx, struct gl_shader_program *prog)
|
|||||||
if (!prog->data->LinkStatus)
|
if (!prog->data->LinkStatus)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
cross_validate_outputs_to_inputs(prog,
|
cross_validate_outputs_to_inputs(ctx, prog,
|
||||||
prog->_LinkedShaders[prev],
|
prog->_LinkedShaders[prev],
|
||||||
prog->_LinkedShaders[i]);
|
prog->_LinkedShaders[i]);
|
||||||
if (!prog->data->LinkStatus)
|
if (!prog->data->LinkStatus)
|
||||||
|
Reference in New Issue
Block a user