summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/compiler/glsl/linker.cpp72
1 files changed, 62 insertions, 10 deletions
diff --git a/src/compiler/glsl/linker.cpp b/src/compiler/glsl/linker.cpp
index 81a683e9423..5c0e4b67ff2 100644
--- a/src/compiler/glsl/linker.cpp
+++ b/src/compiler/glsl/linker.cpp
@@ -2606,7 +2606,12 @@ assign_attribute_or_color_locations(gl_shader_program *prog,
} to_assign[32];
assert(max_index <= 32);
+ /* Temporary array for the set of attributes that have locations assigned.
+ */
+ ir_variable *assigned[16];
+
unsigned num_attr = 0;
+ unsigned assigned_attr = 0;
foreach_in_list(ir_instruction, node, sh->ir) {
ir_variable *const var = node->as_variable();
@@ -2768,18 +2773,62 @@ assign_attribute_or_color_locations(gl_shader_program *prog,
* attribute overlaps any previously allocated bits.
*/
if ((~(use_mask << attr) & used_locations) != used_locations) {
- if (target_index == MESA_SHADER_FRAGMENT ||
- (prog->IsES && prog->Version >= 300)) {
- linker_error(prog,
- "overlapping location is assigned "
- "to %s `%s' %d %d %d\n", string,
- var->name, used_locations, use_mask, attr);
+ if (target_index == MESA_SHADER_FRAGMENT && !prog->IsES) {
+ /* From section 4.4.2 (Output Layout Qualifiers) of the GLSL
+ * 4.40 spec:
+ *
+ * "Additionally, for fragment shader outputs, if two
+ * variables are placed within the same location, they
+ * must have the same underlying type (floating-point or
+ * integer). No component aliasing of output variables or
+ * members is allowed.
+ */
+ for (unsigned i = 0; i < assigned_attr; i++) {
+ unsigned assigned_slots =
+ assigned[i]->type->count_attribute_slots(false);
+ unsigned assig_attr =
+ assigned[i]->data.location - generic_base;
+ unsigned assigned_use_mask = (1 << assigned_slots) - 1;
+
+ if ((assigned_use_mask << assig_attr) &
+ (use_mask << attr)) {
+
+ const glsl_type *assigned_type =
+ assigned[i]->type->without_array();
+ const glsl_type *type = var->type->without_array();
+ if (assigned_type->base_type != type->base_type) {
+ linker_error(prog, "types do not match for aliased"
+ " %ss %s and %s\n", string,
+ assigned[i]->name, var->name);
+ return false;
+ }
+
+ unsigned assigned_component_mask =
+ ((1 << assigned_type->vector_elements) - 1) <<
+ assigned[i]->data.location_frac;
+ unsigned component_mask =
+ ((1 << type->vector_elements) - 1) <<
+ var->data.location_frac;
+ if (assigned_component_mask & component_mask) {
+ linker_error(prog, "overlapping component is "
+ "assigned to %ss %s and %s "
+ "(component=%d)\n",
+ string, assigned[i]->name, var->name,
+ var->data.location_frac);
+ return false;
+ }
+ }
+ }
+ } else if (target_index == MESA_SHADER_FRAGMENT ||
+ (prog->IsES && prog->Version >= 300)) {
+ linker_error(prog, "overlapping location is assigned "
+ "to %s `%s' %d %d %d\n", string, var->name,
+ used_locations, use_mask, attr);
return false;
} else {
- linker_warning(prog,
- "overlapping location is assigned "
- "to %s `%s' %d %d %d\n", string,
- var->name, used_locations, use_mask, attr);
+ linker_warning(prog, "overlapping location is assigned "
+ "to %s `%s' %d %d %d\n", string, var->name,
+ used_locations, use_mask, attr);
}
}
@@ -2809,6 +2858,9 @@ assign_attribute_or_color_locations(gl_shader_program *prog,
double_storage_locations |= (use_mask << attr);
}
+ assigned[assigned_attr] = var;
+ assigned_attr++;
+
continue;
}