if (var->data.from_named_ifc_block) {
type = var->get_interface_type();
+
/* Find the member type before it was altered by lowering */
+ const glsl_type *type_wa = type->without_array();
member_type =
- type->fields.structure[type->field_index(var->name)].type;
- name = ralloc_strdup(NULL, type->without_array()->name);
+ type_wa->fields.structure[type_wa->field_index(var->name)].type;
+ name = ralloc_strdup(NULL, type_wa->name);
} else {
type = var->type;
member_type = NULL;
* matching input to another stage.
*/
static void
-cross_validate_types_and_qualifiers(struct gl_shader_program *prog,
+cross_validate_types_and_qualifiers(struct gl_context *ctx,
+ struct gl_shader_program *prog,
const ir_variable *input,
const ir_variable *output,
gl_shader_stage consumer_stage,
}
if (input_interpolation != output_interpolation &&
prog->data->Version < 440) {
- linker_error(prog,
- "%s shader output `%s' specifies %s "
- "interpolation qualifier, "
- "but %s shader input specifies %s "
- "interpolation qualifier\n",
- _mesa_shader_stage_to_string(producer_stage),
- output->name,
- interpolation_string(output->data.interpolation),
- _mesa_shader_stage_to_string(consumer_stage),
- interpolation_string(input->data.interpolation));
- return;
+ if (!ctx->Const.AllowGLSLCrossStageInterpolationMismatch) {
+ linker_error(prog,
+ "%s shader output `%s' specifies %s "
+ "interpolation qualifier, "
+ "but %s shader input specifies %s "
+ "interpolation qualifier\n",
+ _mesa_shader_stage_to_string(producer_stage),
+ output->name,
+ interpolation_string(output->data.interpolation),
+ _mesa_shader_stage_to_string(consumer_stage),
+ interpolation_string(input->data.interpolation));
+ return;
+ } else {
+ linker_warning(prog,
+ "%s shader output `%s' specifies %s "
+ "interpolation qualifier, "
+ "but %s shader input specifies %s "
+ "interpolation qualifier\n",
+ _mesa_shader_stage_to_string(producer_stage),
+ output->name,
+ interpolation_string(output->data.interpolation),
+ _mesa_shader_stage_to_string(consumer_stage),
+ interpolation_string(input->data.interpolation));
+ }
}
}
* Validate front and back color outputs against single color input
*/
static void
-cross_validate_front_and_back_color(struct gl_shader_program *prog,
+cross_validate_front_and_back_color(struct gl_context *ctx,
+ struct gl_shader_program *prog,
const ir_variable *input,
const ir_variable *front_color,
const ir_variable *back_color,
gl_shader_stage producer_stage)
{
if (front_color != NULL && front_color->data.assigned)
- cross_validate_types_and_qualifiers(prog, input, front_color,
+ cross_validate_types_and_qualifiers(ctx, prog, input, front_color,
consumer_stage, producer_stage);
if (back_color != NULL && back_color->data.assigned)
- cross_validate_types_and_qualifiers(prog, input, back_color,
+ cross_validate_types_and_qualifiers(ctx, prog, input, back_color,
consumer_stage, producer_stage);
}
struct explicit_location_info {
ir_variable *var;
- unsigned base_type;
+ unsigned numerical_type;
unsigned interpolation;
bool centroid;
bool sample;
bool patch;
};
+static inline unsigned
+get_numerical_type(const glsl_type *type)
+{
+ /* From the OpenGL 4.6 spec, section 4.4.1 Input Layout Qualifiers, Page 68,
+ * (Location aliasing):
+ *
+ * "Further, when location aliasing, the aliases sharing the location
+ * must have the same underlying numerical type (floating-point or
+ * integer)
+ */
+ if (type->is_float() || type->is_double())
+ return GLSL_TYPE_FLOAT;
+ return GLSL_TYPE_INT;
+}
+
static bool
check_location_aliasing(struct explicit_location_info explicit_locations[][4],
ir_variable *var,
}
while (location < location_limit) {
- unsigned i = component;
-
- /* If there are other outputs assigned to the same location
- * they must have the same interpolation
- */
unsigned comp = 0;
while (comp < 4) {
- /* Skip the components used by this output, we only care about
- * other outputs in the same location
- */
- if (comp == i) {
- comp = last_comp;
- continue;
- }
-
struct explicit_location_info *info =
&explicit_locations[location][comp];
if (info->var) {
- if (info->interpolation != interpolation) {
+ /* Component aliasing is not alloed */
+ if (comp >= component && comp < last_comp) {
linker_error(prog,
- "%s shader has multiple outputs at explicit "
- "location %u with different interpolation "
- "settings\n",
- _mesa_shader_stage_to_string(stage), location);
+ "%s shader has multiple outputs explicitly "
+ "assigned to location %d and component %d\n",
+ _mesa_shader_stage_to_string(stage),
+ location, comp);
return false;
- }
-
- if (info->centroid != centroid ||
- info->sample != sample ||
- info->patch != patch) {
- linker_error(prog,
- "%s shader has multiple outputs at explicit "
- "location %u with different aux storage\n",
- _mesa_shader_stage_to_string(stage), location);
- return false;
- }
- }
-
- comp++;
- }
+ } else {
+ /* For all other used components we need to have matching
+ * types, interpolation and auxiliary storage
+ */
+ if (info->numerical_type !=
+ get_numerical_type(type->without_array())) {
+ linker_error(prog,
+ "Varyings sharing the same location must "
+ "have the same underlying numerical type. "
+ "Location %u component %u\n",
+ location, comp);
+ return false;
+ }
- /* Component aliasing is not allowed */
- while (i < last_comp) {
- if (explicit_locations[location][i].var != NULL) {
- linker_error(prog,
- "%s shader has multiple outputs explicitly "
- "assigned to location %d and component %d\n",
- _mesa_shader_stage_to_string(stage),
- location, component);
- return false;
- }
+ if (info->interpolation != interpolation) {
+ linker_error(prog,
+ "%s shader has multiple outputs at explicit "
+ "location %u with different interpolation "
+ "settings\n",
+ _mesa_shader_stage_to_string(stage), location);
+ return false;
+ }
- /* Make sure all component at this location have the same type.
- */
- for (unsigned j = 0; j < 4; j++) {
- if (explicit_locations[location][j].var &&
- explicit_locations[location][j].base_type !=
- type->without_array()->base_type) {
- linker_error(prog,
- "Varyings sharing the same location must "
- "have the same underlying numerical type. "
- "Location %u component %u\n", location, component);
- return false;
+ if (info->centroid != centroid ||
+ info->sample != sample ||
+ info->patch != patch) {
+ linker_error(prog,
+ "%s shader has multiple outputs at explicit "
+ "location %u with different aux storage\n",
+ _mesa_shader_stage_to_string(stage), location);
+ return false;
+ }
}
+ } else if (comp >= component && comp < last_comp) {
+ info->var = var;
+ info->numerical_type = get_numerical_type(type->without_array());
+ info->interpolation = interpolation;
+ info->centroid = centroid;
+ info->sample = sample;
+ info->patch = patch;
}
- explicit_locations[location][i].var = var;
- explicit_locations[location][i].base_type =
- type->without_array()->base_type;
- explicit_locations[location][i].interpolation = interpolation;
- explicit_locations[location][i].centroid = centroid;
- explicit_locations[location][i].sample = sample;
- explicit_locations[location][i].patch = patch;
- i++;
+ comp++;
/* We need to do some special handling for doubles as dvec3 and
* dvec4 consume two consecutive locations. We don't need to
* worry about components beginning at anything other than 0 as
* the spec does not allow this for dvec3 and dvec4.
*/
- if (i == 4 && last_comp > 4) {
+ if (comp == 4 && last_comp > 4) {
last_comp = last_comp - 4;
/* Bump location index and reset the component index */
location++;
- i = 0;
+ comp = 0;
+ component = 0;
}
}
return false;
}
- if (type->without_array()->is_interface()) {
- for (unsigned i = 0; i < type->without_array()->length; i++) {
- glsl_struct_field *field = &type->fields.structure[i];
+ const glsl_type *type_without_array = type->without_array();
+ if (type_without_array->is_interface()) {
+ for (unsigned i = 0; i < type_without_array->length; i++) {
+ glsl_struct_field *field = &type_without_array->fields.structure[i];
unsigned field_location = field->location -
(field->patch ? VARYING_SLOT_PATCH0 : VARYING_SLOT_VAR0);
if (!check_location_aliasing(explicit_locations, var,
const ir_variable *const back_color =
parameters.get_variable("gl_BackColor");
- cross_validate_front_and_back_color(prog, input,
+ cross_validate_front_and_back_color(ctx, prog, input,
front_color, back_color,
consumer->Stage, producer->Stage);
} else if (strcmp(input->name, "gl_SecondaryColor") == 0 && input->data.used) {
const ir_variable *const back_color =
parameters.get_variable("gl_BackSecondaryColor");
- cross_validate_front_and_back_color(prog, input,
+ cross_validate_front_and_back_color(ctx, prog, input,
front_color, back_color,
consumer->Stage, producer->Stage);
} else {
*/
if (!(input->get_interface_type() &&
output->get_interface_type()))
- cross_validate_types_and_qualifiers(prog, input, output,
+ cross_validate_types_and_qualifiers(ctx, prog, input, output,
consumer->Stage,
producer->Stage);
} else {
* feedback of arrays would be useless otherwise.
*/
for (unsigned j = 0; j < i; ++j) {
- if (!decls[j].is_varying())
- continue;
-
- if (tfeedback_decl::is_same(decls[i], decls[j])) {
- linker_error(prog, "Transform feedback varying %s specified "
- "more than once.", varying_names[i]);
- return false;
+ if (decls[j].is_varying()) {
+ if (tfeedback_decl::is_same(decls[i], decls[j])) {
+ linker_error(prog, "Transform feedback varying %s specified "
+ "more than once.", varying_names[i]);
+ return false;
+ }
}
}
}
* however some drivers expect to receive the list of transform feedback
* declarations in order so sort it now for convenience.
*/
- if (has_xfb_qualifiers)
+ if (has_xfb_qualifiers) {
qsort(tfeedback_decls, num_tfeedback_decls, sizeof(*tfeedback_decls),
cmp_xfb_offset);
+ }
xfb_prog->sh.LinkedTransformFeedback->Varyings =
rzalloc_array(xfb_prog, struct gl_transform_feedback_varying_info,
if (has_xfb_qualifiers) {
for (unsigned j = 0; j < MAX_FEEDBACK_BUFFERS; j++) {
if (prog->TransformFeedback.BufferStride[j]) {
- buffers |= 1 << j;
explicit_stride[j] = true;
xfb_prog->sh.LinkedTransformFeedback->Buffers[j].Stride =
prog->TransformFeedback.BufferStride[j] / 4;
num_buffers++;
buffer_stream_id = -1;
continue;
- } else if (tfeedback_decls[i].is_varying()) {
+ }
+
+ if (has_xfb_qualifiers) {
+ buffer = tfeedback_decls[i].get_buffer();
+ } else {
+ buffer = num_buffers;
+ }
+
+ if (tfeedback_decls[i].is_varying()) {
if (buffer_stream_id == -1) {
/* First varying writing to this buffer: remember its stream */
buffer_stream_id = (int) tfeedback_decls[i].get_stream_id();
+
+ /* Only mark a buffer as active when there is a varying
+ * attached to it. This behaviour is based on a revised version
+ * of section 13.2.2 of the GL 4.6 spec.
+ */
+ buffers |= 1 << buffer;
} else if (buffer_stream_id !=
(int) tfeedback_decls[i].get_stream_id()) {
/* Varying writes to the same buffer from a different stream */
}
}
- if (has_xfb_qualifiers) {
- buffer = tfeedback_decls[i].get_buffer();
- } else {
- buffer = num_buffers;
- }
- buffers |= 1 << buffer;
-
if (!tfeedback_decls[i].store(ctx, prog,
xfb_prog->sh.LinkedTransformFeedback,
buffer, num_buffers, num_outputs,
~varying_matches();
void record(ir_variable *producer_var, ir_variable *consumer_var);
unsigned assign_locations(struct gl_shader_program *prog,
- uint8_t *components,
+ uint8_t components[],
uint64_t reserved_slots);
void store_locations() const;
private:
bool is_varying_packing_safe(const glsl_type *type,
- const ir_variable *var);
+ const ir_variable *var) const;
/**
* If true, this driver disables varying packing, so all varyings need to
*/
bool
varying_matches::is_varying_packing_safe(const glsl_type *type,
- const ir_variable *var)
+ const ir_variable *var) const
{
if (consumer_stage == MESA_SHADER_TESS_EVAL ||
consumer_stage == MESA_SHADER_TESS_CTRL ||
/**
* Choose locations for all of the variable matches that were previously
* passed to varying_matches::record().
+ * \param components returns array[slot] of number of components used
+ * per slot (1, 2, 3 or 4)
+ * \param reserved_slots bitmask indicating which varying slots are already
+ * allocated
+ * \return number of slots (4-element vectors) allocated
*/
unsigned
varying_matches::assign_locations(struct gl_shader_program *prog,
- uint8_t *components,
+ uint8_t components[],
uint64_t reserved_slots)
{
/* If packing has been disabled then we cannot safely sort the varyings by
unsigned generic_location = 0;
unsigned generic_patch_location = MAX_VARYING*4;
bool previous_var_xfb_only = false;
+ unsigned previous_packing_class = ~0u;
+
+ /* For tranform feedback separate mode, we know the number of attributes
+ * is <= the number of buffers. So packing isn't critical. In fact,
+ * packing vec3 attributes can cause trouble because splitting a vec3
+ * effectively creates an additional transform feedback output. The
+ * extra TFB output may exceed device driver limits.
+ */
+ const bool dont_pack_vec3 =
+ (prog->TransformFeedback.BufferMode == GL_SEPARATE_ATTRIBS &&
+ prog->TransformFeedback.NumVarying > 0);
for (unsigned i = 0; i < this->num_matches; i++) {
unsigned *location = &generic_location;
-
const ir_variable *var;
const glsl_type *type;
bool is_vertex_input = false;
+
if (matches[i].consumer_var) {
var = matches[i].consumer_var;
type = get_varying_type(var, consumer_stage);
if (var->data.must_be_shader_input ||
(this->disable_varying_packing &&
!(previous_var_xfb_only && var->data.is_xfb_only)) ||
- (i > 0 && this->matches[i - 1].packing_class
- != this->matches[i].packing_class )) {
+ (previous_packing_class != this->matches[i].packing_class) ||
+ (this->matches[i].packing_order == PACKING_ORDER_VEC3 &&
+ dont_pack_vec3)) {
*location = ALIGN(*location, 4);
}
previous_var_xfb_only = var->data.is_xfb_only;
+ previous_packing_class = this->matches[i].packing_class;
/* The number of components taken up by this variable. For vertex shader
* inputs, we use the number of slots * 4, as they have different
const uint64_t slot_mask = ((1ull << slots) - 1) << (*location / 4u);
assert(slots > 0);
- if (reserved_slots & slot_mask) {
- *location = ALIGN(*location + 1, 4);
- slot_end = *location + num_components - 1;
- continue;
+
+ if ((reserved_slots & slot_mask) == 0) {
+ break;
}
- break;
+ *location = ALIGN(*location + 1, 4);
+ slot_end = *location + num_components - 1;
}
if (!var->data.patch && slot_end >= MAX_VARYING * 4u) {
*
* Therefore, the packing class depends only on the interpolation type.
*/
- unsigned packing_class = var->data.centroid | (var->data.sample << 1) |
- (var->data.patch << 2) |
- (var->data.must_be_shader_input << 3);
- packing_class *= 8;
- packing_class += var->is_interpolation_flat()
+ const unsigned interp = var->is_interpolation_flat()
? unsigned(INTERP_MODE_FLAT) : var->data.interpolation;
+
+ assert(interp < (1 << 3));
+
+ const unsigned packing_class = (interp << 0) |
+ (var->data.centroid << 3) |
+ (var->data.sample << 4) |
+ (var->data.patch << 5) |
+ (var->data.must_be_shader_input << 6);
+
return packing_class;
}
const match *x = (const match *) x_generic;
if (x->producer_var != NULL && x->producer_var->data.is_xfb_only)
- return match_comparator(x_generic, y_generic);
+ return match_comparator(x_generic, y_generic);
/* FIXME: When the comparator returns 0 it means the elements being
* compared are equivalent. However the qsort documentation says:
*/
foreach_in_list(ir_instruction, node, consumer->ir) {
ir_variable *const input_var = node->as_variable();
-
- if (input_var == NULL || input_var->data.mode != ir_var_shader_in)
- continue;
-
- matches.record(NULL, input_var);
+ if (input_var && input_var->data.mode == ir_var_shader_in) {
+ matches.record(NULL, input_var);
+ }
}
}
matches.store_locations();
for (unsigned i = 0; i < num_tfeedback_decls; ++i) {
- if (!tfeedback_decls[i].is_varying())
- continue;
-
- if (!tfeedback_decls[i].assign_location(ctx, prog)) {
- _mesa_hash_table_destroy(tfeedback_candidates, NULL);
- return false;
+ if (tfeedback_decls[i].is_varying()) {
+ if (!tfeedback_decls[i].assign_location(ctx, prog)) {
+ _mesa_hash_table_destroy(tfeedback_candidates, NULL);
+ return false;
+ }
}
}
_mesa_hash_table_destroy(tfeedback_candidates, NULL);