summaryrefslogtreecommitdiffstats
path: root/src/mesa
diff options
context:
space:
mode:
authorIan Romanick <[email protected]>2016-06-10 08:01:30 -0700
committerIan Romanick <[email protected]>2016-07-05 16:58:27 -0700
commit73a6a4ce4975016d4f86d644b31d30bb6d3a38f8 (patch)
treead84147dd64793e33a425efa5f9b8417b40be56d /src/mesa
parent32651c67d14b9aa408eaae9c9a36bc04c399ee39 (diff)
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 <[email protected]> Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=96358 Reviewed-by: Kenneth Graunke <[email protected]> Cc: "12.0" <[email protected]> Cc: Gregory Hainaut <[email protected]> Cc: Ilia Mirkin <[email protected]>
Diffstat (limited to 'src/mesa')
-rw-r--r--src/mesa/main/shader_query.cpp98
1 files changed, 90 insertions, 8 deletions
diff --git a/src/mesa/main/shader_query.cpp b/src/mesa/main/shader_query.cpp
index a2a93b16d4e..0eae39a3557 100644
--- a/src/mesa/main/shader_query.cpp
+++ b/src/mesa/main/shader_query.cpp
@@ -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,25 +1582,53 @@ 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->outermost_struct_type != consumer_var->outermost_struct_type) {
+ if (producer_var->precision != consumer_var->precision) {
valid = false;
goto out;
}
- if (producer_var->interface_type != consumer_var->interface_type) {
+ if (producer_var->outermost_struct_type != consumer_var->outermost_struct_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;