mesa: Strip arrayness from interface block names in some IO validation

Outputs from the vertex shader need to be able to match
per-vertex-arrayed inputs of later stages.  Acomplish this by stripping
one level of arrayness from the names and types of outputs going to a
per-vertex-arrayed stage.

v2: Add missing checks for TESS_EVAL->GEOMETRY.  Noticed by Timothy
Arceri.

v3: Use a slightly simpler stage check suggested by Ilia.

Signed-off-by: Ian Romanick <ian.d.romanick@intel.com>
Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=96358
Reviewed-by: Kenneth Graunke <kenneth@whitecape.org>
Cc: "12.0" <mesa-stable@lists.freedesktop.org>
Cc: Gregory Hainaut <gregory.hainaut@gmail.com>
Cc: Ilia Mirkin <imirkin@alum.mit.edu>
This commit is contained in:
Ian Romanick 2016-06-10 08:01:30 -07:00
parent 32651c67d1
commit 73a6a4ce49
1 changed files with 93 additions and 11 deletions

View File

@ -1386,13 +1386,24 @@ _mesa_get_program_resourceiv(struct gl_shader_program *shProg,
static bool
validate_io(struct gl_shader_program *producer,
struct gl_shader_program *consumer)
struct gl_shader_program *consumer,
gl_shader_stage producer_stage,
gl_shader_stage consumer_stage)
{
if (producer == consumer)
return true;
const bool nonarray_stage_to_array_stage =
producer_stage != MESA_SHADER_TESS_CTRL &&
(consumer_stage == MESA_SHADER_GEOMETRY ||
consumer_stage == MESA_SHADER_TESS_CTRL ||
consumer_stage == MESA_SHADER_TESS_EVAL);
bool valid = true;
void *name_buffer = NULL;
size_t name_buffer_size = 0;
gl_shader_variable const **outputs =
(gl_shader_variable const **) calloc(producer->NumProgramResourceList,
sizeof(gl_shader_variable *));
@ -1464,11 +1475,52 @@ validate_io(struct gl_shader_program *producer,
}
}
} else {
char *consumer_name = consumer_var->name;
if (nonarray_stage_to_array_stage &&
consumer_var->interface_type != NULL &&
consumer_var->interface_type->is_array() &&
!is_gl_identifier(consumer_var->name)) {
const size_t name_len = strlen(consumer_var->name);
if (name_len >= name_buffer_size) {
free(name_buffer);
name_buffer_size = name_len + 1;
name_buffer = malloc(name_buffer_size);
if (name_buffer == NULL) {
valid = false;
goto out;
}
}
consumer_name = (char *) name_buffer;
char *s = strchr(consumer_var->name, '[');
if (s == NULL) {
valid = false;
goto out;
}
char *t = strchr(s, ']');
if (t == NULL) {
valid = false;
goto out;
}
assert(t[1] == '.' || t[1] == '[');
const ptrdiff_t base_name_len = s - consumer_var->name;
memcpy(consumer_name, consumer_var->name, base_name_len);
strcpy(consumer_name + base_name_len, t + 1);
}
for (unsigned j = 0; j < num_outputs; j++) {
const gl_shader_variable *const var = outputs[j];
if (!var->explicit_location &&
strcmp(consumer_var->name, var->name) == 0) {
strcmp(consumer_name, var->name) == 0) {
producer_var = var;
match_index = j;
break;
@ -1530,9 +1582,41 @@ validate_io(struct gl_shader_program *producer,
* Note that location mismatches are detected by the loops above that
* find the producer variable that goes with the consumer variable.
*/
if (producer_var->type != consumer_var->type ||
producer_var->interpolation != consumer_var->interpolation ||
producer_var->precision != consumer_var->precision) {
if (nonarray_stage_to_array_stage) {
if (!consumer_var->type->is_array() ||
consumer_var->type->fields.array != producer_var->type) {
valid = false;
goto out;
}
if (consumer_var->interface_type != NULL) {
if (!consumer_var->interface_type->is_array() ||
consumer_var->interface_type->fields.array != producer_var->interface_type) {
valid = false;
goto out;
}
} else if (producer_var->interface_type != NULL) {
valid = false;
goto out;
}
} else {
if (producer_var->type != consumer_var->type) {
valid = false;
goto out;
}
if (producer_var->interface_type != consumer_var->interface_type) {
valid = false;
goto out;
}
}
if (producer_var->interpolation != consumer_var->interpolation) {
valid = false;
goto out;
}
if (producer_var->precision != consumer_var->precision) {
valid = false;
goto out;
}
@ -1541,14 +1625,10 @@ validate_io(struct gl_shader_program *producer,
valid = false;
goto out;
}
if (producer_var->interface_type != consumer_var->interface_type) {
valid = false;
goto out;
}
}
out:
free(name_buffer);
free(outputs);
return valid && num_outputs == 0;
}
@ -1580,7 +1660,9 @@ _mesa_validate_pipeline_io(struct gl_pipeline_object *pipeline)
if (shProg[idx]->_LinkedShaders[idx]->Stage == MESA_SHADER_COMPUTE)
break;
if (!validate_io(shProg[prev], shProg[idx]))
if (!validate_io(shProg[prev], shProg[idx],
shProg[prev]->_LinkedShaders[prev]->Stage,
shProg[idx]->_LinkedShaders[idx]->Stage))
return false;
prev = idx;