#include "linker.h"
#include "link_varyings.h"
#include "main/macros.h"
-#include "program/hash_table.h"
+#include "util/hash_table.h"
#include "program.h"
}
bool
-process_xfb_layout_qualifiers(void *mem_ctx, const gl_shader *sh,
+process_xfb_layout_qualifiers(void *mem_ctx, const gl_linked_shader *sh,
unsigned *num_tfeedback_decls,
char ***varying_names)
{
* xfb_stride to interface block members so this will catch that case also.
*/
for (unsigned j = 0; j < MAX_FEEDBACK_BUFFERS; j++) {
- if (sh->TransformFeedback.BufferStride[j]) {
+ if (sh->info.TransformFeedback.BufferStride[j]) {
has_xfb_qualifiers = true;
}
}
return has_xfb_qualifiers;
}
+static bool
+anonymous_struct_type_matches(const glsl_type *output_type,
+ const glsl_type *to_match)
+{
+ while (output_type->is_array() && to_match->is_array()) {
+ /* if the lengths at each level don't match fail. */
+ if (output_type->length != to_match->length)
+ return false;
+ output_type = output_type->fields.array;
+ to_match = to_match->fields.array;
+ }
+
+ if (output_type->is_array() || to_match->is_array())
+ return false;
+ return output_type->is_anonymous() &&
+ to_match->is_anonymous() &&
+ to_match->record_compare(output_type);
+}
+
/**
* Validate the types and qualifiers of an output from one stage against the
* matching input to another stage.
* fragment language."
*/
if (!output->type->is_array() || !is_gl_identifier(output->name)) {
- linker_error(prog,
- "%s shader output `%s' declared as type `%s', "
- "but %s shader input declared as type `%s'\n",
- _mesa_shader_stage_to_string(producer_stage),
- output->name,
- output->type->name,
- _mesa_shader_stage_to_string(consumer_stage),
- input->type->name);
- return;
+ bool anon_matches = anonymous_struct_type_matches(output->type, type_to_match);
+
+ if (!anon_matches) {
+ linker_error(prog,
+ "%s shader output `%s' declared as type `%s', "
+ "but %s shader input declared as type `%s'\n",
+ _mesa_shader_stage_to_string(producer_stage),
+ output->name,
+ output->type->name,
+ _mesa_shader_stage_to_string(consumer_stage),
+ input->type->name);
+ return;
+ }
}
}
* OpenGLES 3.0 drivers, so we relax the checking in all cases.
*/
if (false /* always skip the centroid check */ &&
- prog->Version < (prog->IsES ? 310 : 430) &&
+ prog->data->Version < (prog->IsES ? 310 : 430) &&
input->data.centroid != output->data.centroid) {
linker_error(prog,
"%s shader output `%s' %s centroid qualifier, "
return;
}
- if (!prog->IsES && input->data.invariant != output->data.invariant) {
+ /* The GLSL 4.30 and GLSL ES 3.00 specifications say:
+ *
+ * "As only outputs need be declared with invariant, an output from
+ * one shader stage will still match an input of a subsequent stage
+ * without the input being declared as invariant."
+ *
+ * while GLSL 4.20 says:
+ *
+ * "For variables leaving one shader and coming into another shader,
+ * the invariant keyword has to be used in both shaders, or a link
+ * error will result."
+ *
+ * and GLSL ES 1.00 section 4.6.4 "Invariance and Linking" says:
+ *
+ * "The invariance of varyings that are declared in both the vertex
+ * and fragment shaders must match."
+ */
+ if (input->data.invariant != output->data.invariant &&
+ prog->data->Version < (prog->IsES ? 300 : 430)) {
linker_error(prog,
"%s shader output `%s' %s invariant qualifier, "
"but %s shader input %s invariant qualifier\n",
*
*/
if (input->data.interpolation != output->data.interpolation &&
- prog->Version < 440) {
+ prog->data->Version < 440) {
linker_error(prog,
"%s shader output `%s' specifies %s "
"interpolation qualifier, "
*/
void
cross_validate_outputs_to_inputs(struct gl_shader_program *prog,
- gl_shader *producer, gl_shader *consumer)
+ gl_linked_shader *producer,
+ gl_linked_shader *consumer)
{
glsl_symbol_table parameters;
ir_variable *explicit_locations[MAX_VARYINGS_INCL_PATCH][4] =
foreach_in_list(ir_instruction, node, producer->ir) {
ir_variable *const var = node->as_variable();
- if ((var == NULL) || (var->data.mode != ir_var_shader_out))
+ if (var == NULL || var->data.mode != ir_var_shader_out)
continue;
if (!var->data.explicit_location
unsigned slot_limit = idx + num_elements;
unsigned last_comp;
- if (var->type->without_array()->is_record()) {
+ if (type->without_array()->is_record()) {
/* The component qualifier can't be used on structs so just treat
* all component slots as used.
*/
last_comp = 4;
} else {
- unsigned dmul = var->type->is_double() ? 2 : 1;
+ unsigned dmul = type->without_array()->is_64bit() ? 2 : 1;
last_comp = var->data.location_frac +
- var->type->without_array()->vector_elements * dmul;
+ type->without_array()->vector_elements * dmul;
}
while (idx < slot_limit) {
- for (unsigned i = var->data.location_frac; i < last_comp; i++) {
+ unsigned i = var->data.location_frac;
+ while (i < last_comp) {
if (explicit_locations[idx][i] != NULL) {
linker_error(prog,
"%s shader has multiple outputs explicitly "
for (unsigned j = 0; j < 4; j++) {
if (explicit_locations[idx][j] &&
(explicit_locations[idx][j]->type->without_array()
- ->base_type != var->type->without_array()->base_type)) {
+ ->base_type != type->without_array()->base_type)) {
linker_error(prog,
"Varyings sharing the same location must "
"have the same underlying numerical type. "
}
explicit_locations[idx][i] = var;
+ i++;
/* 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 == 3 && last_comp > 4) {
+ if (i == 4 && last_comp > 4) {
last_comp = last_comp - 4;
/* Bump location index and reset the component index */
idx++;
foreach_in_list(ir_instruction, node, consumer->ir) {
ir_variable *const input = node->as_variable();
- if ((input == NULL) || (input->data.mode != ir_var_shader_in))
+ if (input == NULL || input->data.mode != ir_var_shader_in)
continue;
if (strcmp(input->name, "gl_Color") == 0 && input->data.used) {
*/
void
remove_unused_shader_inputs_and_outputs(bool is_separate_shader_object,
- gl_shader *sh,
+ gl_linked_shader *sh,
enum ir_variable_mode mode)
{
if (is_separate_shader_object)
foreach_in_list(ir_instruction, node, sh->ir) {
ir_variable *const var = node->as_variable();
- if ((var == NULL) || (var->data.mode != int(mode)))
+ if (var == NULL || var->data.mode != int(mode))
continue;
/* A shader 'in' or 'out' variable is only really an input or output if
*/
if (var->data.is_unmatched_generic_inout && !var->data.is_xfb_only) {
assert(var->data.mode != ir_var_temporary);
+
+ /* Assign zeros to demoted inputs to allow more optimizations. */
+ if (var->data.mode == ir_var_shader_in && !var->constant_value)
+ var->constant_value = ir_constant::zero(var, var->type);
+
var->data.mode = ir_var_auto;
}
}
+ this->matched_candidate->toplevel_var->data.location_frac
+ this->matched_candidate->offset;
const unsigned dmul =
- this->matched_candidate->type->without_array()->is_double() ? 2 : 1;
+ this->matched_candidate->type->without_array()->is_64bit() ? 2 : 1;
if (this->matched_candidate->type->is_array()) {
/* Array variable */
const unsigned max_outputs, bool *explicit_stride,
bool has_xfb_qualifiers) const
{
- assert(!this->next_buffer_separator);
-
+ unsigned xfb_offset = 0;
+ unsigned size = this->size;
/* Handle gl_SkipComponents. */
if (this->skip_components) {
info->Buffers[buffer].Stride += this->skip_components;
- return true;
+ size = this->skip_components;
+ goto store_varying;
+ }
+
+ if (this->next_buffer_separator) {
+ size = 0;
+ goto store_varying;
}
- unsigned xfb_offset = 0;
if (has_xfb_qualifiers) {
xfb_offset = this->offset / 4;
} else {
}
info->Varyings[info->NumVarying].Offset = xfb_offset * 4;
- unsigned location = this->location;
- unsigned location_frac = this->location_frac;
- unsigned num_components = this->num_components();
- while (num_components > 0) {
- unsigned output_size = MIN2(num_components, 4 - location_frac);
- assert((info->NumOutputs == 0 && max_outputs == 0) ||
- info->NumOutputs < max_outputs);
+ {
+ unsigned location = this->location;
+ unsigned location_frac = this->location_frac;
+ unsigned num_components = this->num_components();
+ while (num_components > 0) {
+ unsigned output_size = MIN2(num_components, 4 - location_frac);
+ assert((info->NumOutputs == 0 && max_outputs == 0) ||
+ info->NumOutputs < max_outputs);
+
+ /* From the ARB_enhanced_layouts spec:
+ *
+ * "If such a block member or variable is not written during a shader
+ * invocation, the buffer contents at the assigned offset will be
+ * undefined. Even if there are no static writes to a variable or
+ * member that is assigned a transform feedback offset, the space is
+ * still allocated in the buffer and still affects the stride."
+ */
+ if (this->is_varying_written()) {
+ info->Outputs[info->NumOutputs].ComponentOffset = location_frac;
+ info->Outputs[info->NumOutputs].OutputRegister = location;
+ info->Outputs[info->NumOutputs].NumComponents = output_size;
+ info->Outputs[info->NumOutputs].StreamId = stream_id;
+ info->Outputs[info->NumOutputs].OutputBuffer = buffer;
+ info->Outputs[info->NumOutputs].DstOffset = xfb_offset;
+ ++info->NumOutputs;
+ }
+ info->Buffers[buffer].Stream = this->stream_id;
+ xfb_offset += output_size;
- /* From the ARB_enhanced_layouts spec:
- *
- * "If such a block member or variable is not written during a shader
- * invocation, the buffer contents at the assigned offset will be
- * undefined. Even if there are no static writes to a variable or
- * member that is assigned a transform feedback offset, the space is
- * still allocated in the buffer and still affects the stride."
- */
- if (this->is_varying_written()) {
- info->Outputs[info->NumOutputs].ComponentOffset = location_frac;
- info->Outputs[info->NumOutputs].OutputRegister = location;
- info->Outputs[info->NumOutputs].NumComponents = output_size;
- info->Outputs[info->NumOutputs].StreamId = stream_id;
- info->Outputs[info->NumOutputs].OutputBuffer = buffer;
- info->Outputs[info->NumOutputs].DstOffset = xfb_offset;
- ++info->NumOutputs;
+ num_components -= output_size;
+ location++;
+ location_frac = 0;
}
- info->Buffers[buffer].Stream = this->stream_id;
- xfb_offset += output_size;
-
- num_components -= output_size;
- location++;
- location_frac = 0;
}
if (explicit_stride && explicit_stride[buffer]) {
- if (this->is_double() && info->Buffers[buffer].Stride % 2) {
+ if (this->is_64bit() && info->Buffers[buffer].Stride % 2) {
linker_error(prog, "invalid qualifier xfb_stride=%d must be a "
"multiple of 8 as its applied to a type that is or "
"contains a double.",
return false;
}
+ store_varying:
info->Varyings[info->NumVarying].Name = ralloc_strdup(prog,
this->orig_name);
info->Varyings[info->NumVarying].Type = this->type;
- info->Varyings[info->NumVarying].Size = this->size;
+ info->Varyings[info->NumVarying].Size = size;
info->Varyings[info->NumVarying].BufferIndex = buffer_index;
info->NumVarying++;
info->Buffers[buffer].NumVaryings++;
name = "gl_TessLevelInnerMESA";
break;
}
- this->matched_candidate = (const tfeedback_candidate *)
- hash_table_find(tfeedback_candidates, name);
+ hash_entry *entry = _mesa_hash_table_search(tfeedback_candidates, name);
+
+ this->matched_candidate = entry ?
+ (const tfeedback_candidate *) entry->data : NULL;
+
if (!this->matched_candidate) {
/* From GL_EXT_transform_feedback:
* A program will fail to link if:
linker_error(prog, "Transform feedback varying %s undeclared.",
this->orig_name);
}
+
return this->matched_candidate;
}
/**
* Store transform feedback location assignments into
- * prog->LinkedTransformFeedback based on the data stored in tfeedback_decls.
+ * prog->sh.LinkedTransformFeedback based on the data stored in
+ * tfeedback_decls.
*
* If an error occurs, the error is reported through linker_error() and false
* is returned.
bool separate_attribs_mode =
prog->TransformFeedback.BufferMode == GL_SEPARATE_ATTRIBS;
- ralloc_free(prog->LinkedTransformFeedback.Varyings);
- ralloc_free(prog->LinkedTransformFeedback.Outputs);
-
- memset(&prog->LinkedTransformFeedback, 0,
- sizeof(prog->LinkedTransformFeedback));
+ struct gl_program *xfb_prog = prog->xfb_program;
+ xfb_prog->sh.LinkedTransformFeedback =
+ rzalloc(xfb_prog, struct gl_transform_feedback_info);
/* The xfb_offset qualifier does not have to be used in increasing order
* however some drivers expect to receive the list of transform feedback
qsort(tfeedback_decls, num_tfeedback_decls, sizeof(*tfeedback_decls),
cmp_xfb_offset);
- prog->LinkedTransformFeedback.Varyings =
- rzalloc_array(prog,
- struct gl_transform_feedback_varying_info,
+ xfb_prog->sh.LinkedTransformFeedback->Varyings =
+ rzalloc_array(xfb_prog, struct gl_transform_feedback_varying_info,
num_tfeedback_decls);
unsigned num_outputs = 0;
num_outputs += tfeedback_decls[i].get_num_outputs();
}
- prog->LinkedTransformFeedback.Outputs =
- rzalloc_array(prog,
- struct gl_transform_feedback_output,
+ xfb_prog->sh.LinkedTransformFeedback->Outputs =
+ rzalloc_array(xfb_prog, struct gl_transform_feedback_output,
num_outputs);
unsigned num_buffers = 0;
if (!has_xfb_qualifiers && separate_attribs_mode) {
/* GL_SEPARATE_ATTRIBS */
for (unsigned i = 0; i < num_tfeedback_decls; ++i) {
- if (!tfeedback_decls[i].store(ctx, prog, &prog->LinkedTransformFeedback,
+ if (!tfeedback_decls[i].store(ctx, prog,
+ xfb_prog->sh.LinkedTransformFeedback,
num_buffers, num_buffers, num_outputs,
NULL, has_xfb_qualifiers))
return false;
if (prog->TransformFeedback.BufferStride[j]) {
buffers |= 1 << j;
explicit_stride[j] = true;
- prog->LinkedTransformFeedback.Buffers[j].Stride =
+ xfb_prog->sh.LinkedTransformFeedback->Buffers[j].Stride =
prog->TransformFeedback.BufferStride[j] / 4;
}
}
}
if (tfeedback_decls[i].is_next_buffer_separator()) {
+ if (!tfeedback_decls[i].store(ctx, prog,
+ xfb_prog->sh.LinkedTransformFeedback,
+ buffer, num_buffers, num_outputs,
+ explicit_stride, has_xfb_qualifiers))
+ return false;
num_buffers++;
buffer_stream_id = -1;
continue;
- } else if (buffer_stream_id == -1) {
- /* First varying writing to this buffer: remember its stream */
- buffer_stream_id = (int) tfeedback_decls[i].get_stream_id();
- } else if (buffer_stream_id !=
- (int) tfeedback_decls[i].get_stream_id()) {
- /* Varying writes to the same buffer from a different stream */
- linker_error(prog,
- "Transform feedback can't capture varyings belonging "
- "to different vertex streams in a single buffer. "
- "Varying %s writes to buffer from stream %u, other "
- "varyings in the same buffer write from stream %u.",
- tfeedback_decls[i].name(),
- tfeedback_decls[i].get_stream_id(),
- buffer_stream_id);
- return false;
+ } else 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();
+ } else if (buffer_stream_id !=
+ (int) tfeedback_decls[i].get_stream_id()) {
+ /* Varying writes to the same buffer from a different stream */
+ linker_error(prog,
+ "Transform feedback can't capture varyings belonging "
+ "to different vertex streams in a single buffer. "
+ "Varying %s writes to buffer from stream %u, other "
+ "varyings in the same buffer write from stream %u.",
+ tfeedback_decls[i].name(),
+ tfeedback_decls[i].get_stream_id(),
+ buffer_stream_id);
+ return false;
+ }
}
if (has_xfb_qualifiers) {
buffers |= 1 << buffer;
if (!tfeedback_decls[i].store(ctx, prog,
- &prog->LinkedTransformFeedback,
+ xfb_prog->sh.LinkedTransformFeedback,
buffer, num_buffers, num_outputs,
explicit_stride, has_xfb_qualifiers))
return false;
}
}
- assert(prog->LinkedTransformFeedback.NumOutputs == num_outputs);
+ assert(xfb_prog->sh.LinkedTransformFeedback->NumOutputs == num_outputs);
- prog->LinkedTransformFeedback.ActiveBuffers = buffers;
+ xfb_prog->sh.LinkedTransformFeedback->ActiveBuffers = buffers;
return true;
}
~varying_matches();
void record(ir_variable *producer_var, ir_variable *consumer_var);
unsigned assign_locations(struct gl_shader_program *prog,
- uint64_t reserved_slots, bool separate_shader);
+ uint8_t *components,
+ uint64_t reserved_slots);
void store_locations() const;
private:
/**
- * Packing is always safe on individual arrays, structure and matices. It is
- * also safe if the varying is only used for transform feedback.
+ * Packing is always safe on individual arrays, structures, and matrices. It
+ * is also safe if the varying is only used for transform feedback.
*/
bool
varying_matches::is_varying_packing_safe(const glsl_type *type,
(producer_var->type->contains_integer() ||
producer_var->type->contains_double());
- if (needs_flat_qualifier ||
- (consumer_stage != -1 && consumer_stage != MESA_SHADER_FRAGMENT)) {
+ if (!disable_varying_packing &&
+ (needs_flat_qualifier ||
+ (consumer_stage != -1 && consumer_stage != MESA_SHADER_FRAGMENT))) {
/* Since this varying is not being consumed by the fragment shader, its
* interpolation type varying cannot possibly affect rendering.
* Also, this variable is non-flat and is (or contains) an integer
if (producer_var) {
producer_var->data.centroid = false;
producer_var->data.sample = false;
- producer_var->data.interpolation = INTERP_QUALIFIER_FLAT;
+ producer_var->data.interpolation = INTERP_MODE_FLAT;
}
if (consumer_var) {
consumer_var->data.centroid = false;
consumer_var->data.sample = false;
- consumer_var->data.interpolation = INTERP_QUALIFIER_FLAT;
+ consumer_var->data.interpolation = INTERP_MODE_FLAT;
}
}
sizeof(*this->matches) * this->matches_capacity);
}
- const ir_variable *const var = (producer_var != NULL)
- ? producer_var : consumer_var;
- const gl_shader_stage stage = (producer_var != NULL)
- ? producer_stage : consumer_stage;
+ /* We must use the consumer to compute the packing class because in GL4.4+
+ * there is no guarantee interpolation qualifiers will match across stages.
+ *
+ * From Section 4.5 (Interpolation Qualifiers) of the GLSL 4.30 spec:
+ *
+ * "The type and presence of interpolation qualifiers of variables with
+ * the same name declared in all linked shaders for the same cross-stage
+ * interface must match, otherwise the link command will fail.
+ *
+ * When comparing an output from one stage to an input of a subsequent
+ * stage, the input and output don't match if their interpolation
+ * qualifiers (or lack thereof) are not the same."
+ *
+ * This text was also in at least revison 7 of the 4.40 spec but is no
+ * longer in revision 9 and not in the 4.50 spec.
+ */
+ const ir_variable *const var = (consumer_var != NULL)
+ ? consumer_var : producer_var;
+ const gl_shader_stage stage = (consumer_var != NULL)
+ ? consumer_stage : producer_stage;
const glsl_type *type = get_varying_type(var, stage);
this->matches[this->num_matches].packing_class
*/
unsigned
varying_matches::assign_locations(struct gl_shader_program *prog,
- uint64_t reserved_slots,
- bool separate_shader)
+ uint8_t *components,
+ uint64_t reserved_slots)
{
/* If packing has been disabled then we cannot safely sort the varyings by
* class as it may mean we are using a version of OpenGL where
previous_var_xfb_only = var->data.is_xfb_only;
- unsigned num_elements = type->count_attribute_slots(is_vertex_input);
- unsigned slot_end;
- if (this->disable_varying_packing &&
- !is_varying_packing_safe(type, var))
- slot_end = 4;
- else
- slot_end = type->without_array()->vector_elements;
- slot_end += *location - 1;
+ /* The number of components taken up by this variable. For vertex shader
+ * inputs, we use the number of slots * 4, as they have different
+ * counting rules.
+ */
+ unsigned num_components = is_vertex_input ?
+ type->count_attribute_slots(is_vertex_input) * 4 :
+ this->matches[i].num_components;
+
+ /* The last slot for this variable, inclusive. */
+ unsigned slot_end = *location + num_components - 1;
/* FIXME: We could be smarter in the below code and loop back over
* trying to fill any locations that we skipped because we couldn't pack
* hit the linking error if we run out of room and suggest they use
* explicit locations.
*/
- for (unsigned j = 0; j < num_elements; j++) {
- while ((slot_end < MAX_VARYING * 4u) &&
- ((reserved_slots & (UINT64_C(1) << *location / 4u) ||
- (reserved_slots & (UINT64_C(1) << slot_end / 4u))))) {
+ while (slot_end < MAX_VARYING * 4u) {
+ const unsigned slots = (slot_end / 4u) - (*location / 4u) + 1;
+ 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;
-
- /* reset the counter and try again */
- j = 0;
+ slot_end = *location + num_components - 1;
+ continue;
}
- /* Increase the slot to make sure there is enough room for next
- * array element.
- */
- if (this->disable_varying_packing &&
- !is_varying_packing_safe(type, var))
- slot_end += 4;
- else
- slot_end += type->without_array()->vector_elements;
+ break;
}
- if (!var->data.patch && *location >= MAX_VARYING * 4u) {
+ if (!var->data.patch && slot_end >= MAX_VARYING * 4u) {
linker_error(prog, "insufficient contiguous locations available for "
"%s it is possible an array or struct could not be "
"packed between varyings with explicit locations. Try "
var->name);
}
+ if (slot_end < MAX_VARYINGS_INCL_PATCH * 4u) {
+ for (unsigned j = *location / 4u; j < slot_end / 4u; j++)
+ components[j] = 4;
+ components[slot_end / 4u] = (slot_end & 3) + 1;
+ }
+
this->matches[i].generic_location = *location;
- *location += this->matches[i].num_components;
+ *location = slot_end + 1;
}
return (generic_location + 3) / 4;
unsigned packing_class = var->data.centroid | (var->data.sample << 1) |
(var->data.patch << 2);
packing_class *= 4;
- packing_class += var->data.interpolation;
+ packing_class += var->is_interpolation_flat()
+ ? unsigned(INTERP_MODE_FLAT) : var->data.interpolation;
return packing_class;
}
private:
virtual void visit_field(const glsl_type *type, const char *name,
- bool row_major)
+ bool /* row_major */,
+ const glsl_type * /* record_type */,
+ const enum glsl_interface_packing,
+ bool /* last_field */)
{
assert(!type->without_array()->is_record());
assert(!type->without_array()->is_interface());
- (void) row_major;
-
tfeedback_candidate *candidate
= rzalloc(this->mem_ctx, tfeedback_candidate);
candidate->toplevel_var = this->toplevel_var;
candidate->type = type;
candidate->offset = this->varying_floats;
- hash_table_insert(this->tfeedback_candidates, candidate,
- ralloc_strdup(this->mem_ctx, name));
+ _mesa_hash_table_insert(this->tfeedback_candidates,
+ ralloc_strdup(this->mem_ctx, name),
+ candidate);
this->varying_floats += type->component_slots();
}
foreach_in_list(ir_instruction, node, ir) {
ir_variable *const input_var = node->as_variable();
- if ((input_var != NULL) && (input_var->data.mode == ir_var_shader_in)) {
+ if (input_var != NULL && input_var->data.mode == ir_var_shader_in) {
/* All interface blocks should have been lowered by this point */
assert(!input_var->type->is_interface());
ralloc_asprintf(mem_ctx, "%s.%s",
input_var->get_interface_type()->without_array()->name,
input_var->name);
- hash_table_insert(consumer_interface_inputs, input_var,
- iface_field_name);
+ _mesa_hash_table_insert(consumer_interface_inputs,
+ iface_field_name, input_var);
} else {
- hash_table_insert(consumer_inputs, input_var,
- ralloc_strdup(mem_ctx, input_var->name));
+ _mesa_hash_table_insert(consumer_inputs,
+ ralloc_strdup(mem_ctx, input_var->name),
+ input_var);
}
}
}
ralloc_asprintf(mem_ctx, "%s.%s",
output_var->get_interface_type()->without_array()->name,
output_var->name);
- input_var =
- (ir_variable *) hash_table_find(consumer_interface_inputs,
- iface_field_name);
+ hash_entry *entry = _mesa_hash_table_search(consumer_interface_inputs, iface_field_name);
+ input_var = entry ? (ir_variable *) entry->data : NULL;
} else {
- input_var =
- (ir_variable *) hash_table_find(consumer_inputs, output_var->name);
+ hash_entry *entry = _mesa_hash_table_search(consumer_inputs, output_var->name);
+ input_var = entry ? (ir_variable *) entry->data : NULL;
}
return (input_var == NULL || input_var->data.mode != ir_var_shader_in)
* 64 bit map. Per-vertex and per-patch both have separate location domains
* with a max of MAX_VARYING.
*/
-static uint64_t
-reserved_varying_slot(struct gl_shader *stage, ir_variable_mode io_mode)
+uint64_t
+reserved_varying_slot(struct gl_linked_shader *stage,
+ ir_variable_mode io_mode)
{
assert(io_mode == ir_var_shader_in || io_mode == ir_var_shader_out);
/* Avoid an overflow of the returned value */
assign_varying_locations(struct gl_context *ctx,
void *mem_ctx,
struct gl_shader_program *prog,
- gl_shader *producer, gl_shader *consumer,
+ gl_linked_shader *producer,
+ gl_linked_shader *consumer,
unsigned num_tfeedback_decls,
- tfeedback_decl *tfeedback_decls)
+ tfeedback_decl *tfeedback_decls,
+ const uint64_t reserved_slots)
{
/* Tessellation shaders treat inputs and outputs as shared memory and can
* access inputs and outputs of other invocations.
bool xfb_enabled =
ctx->Extensions.EXT_transform_feedback && !unpackable_tess;
- /* Disable varying packing for GL 4.4+ as there is no guarantee
- * that interpolation qualifiers will match between shaders in these
- * versions. We also disable packing on outerward facing interfaces for
- * SSO because in ES we need to retain the unpacked varying information
- * for draw time validation. For desktop GL we could allow packing for
- * versions < 4.4 but its just safer not to do packing.
+ /* Disable packing on outward facing interfaces for SSO because in ES we
+ * need to retain the unpacked varying information for draw time
+ * validation.
*
* Packing is still enabled on individual arrays, structs, and matrices as
* these are required by the transform feedback code and it is still safe
* to do so. We also enable packing when a varying is only used for
* transform feedback and its not a SSO.
- *
- * Varying packing currently only packs together varyings with matching
- * interpolation qualifiers as the backends assume all packed components
- * are to be processed in the same way. Therefore we cannot do packing in
- * these versions of GL without the risk of mismatching interfaces.
- *
- * From Section 4.5 (Interpolation Qualifiers) of the GLSL 4.30 spec:
- *
- * "The type and presence of interpolation qualifiers of variables with
- * the same name declared in all linked shaders for the same cross-stage
- * interface must match, otherwise the link command will fail.
- *
- * When comparing an output from one stage to an input of a subsequent
- * stage, the input and output don't match if their interpolation
- * qualifiers (or lack thereof) are not the same."
- *
- * This text was also in at least revison 7 of the 4.40 spec but is no
- * longer in revision 9 and not in the 4.50 spec.
*/
bool disable_varying_packing =
ctx->Const.DisableVaryingPacking || unpackable_tess;
- if ((ctx->API == API_OPENGL_CORE && ctx->Version >= 44) ||
- (prog->SeparateShader && (producer == NULL || consumer == NULL)))
+ if (prog->SeparateShader && (producer == NULL || consumer == NULL))
disable_varying_packing = true;
varying_matches matches(disable_varying_packing, xfb_enabled,
producer ? producer->Stage : (gl_shader_stage)-1,
consumer ? consumer->Stage : (gl_shader_stage)-1);
- hash_table *tfeedback_candidates
- = hash_table_ctor(0, hash_table_string_hash, hash_table_string_compare);
- hash_table *consumer_inputs
- = hash_table_ctor(0, hash_table_string_hash, hash_table_string_compare);
- hash_table *consumer_interface_inputs
- = hash_table_ctor(0, hash_table_string_hash, hash_table_string_compare);
+ hash_table *tfeedback_candidates =
+ _mesa_hash_table_create(NULL, _mesa_key_hash_string,
+ _mesa_key_string_equal);
+ hash_table *consumer_inputs =
+ _mesa_hash_table_create(NULL, _mesa_key_hash_string,
+ _mesa_key_string_equal);
+ hash_table *consumer_interface_inputs =
+ _mesa_hash_table_create(NULL, _mesa_key_hash_string,
+ _mesa_key_string_equal);
ir_variable *consumer_inputs_with_locations[VARYING_SLOT_TESS_MAX] = {
NULL,
};
foreach_in_list(ir_instruction, node, producer->ir) {
ir_variable *const output_var = node->as_variable();
- if ((output_var == NULL) ||
- (output_var->data.mode != ir_var_shader_out))
+ if (output_var == NULL || output_var->data.mode != ir_var_shader_out)
continue;
/* Only geometry shaders can use non-zero streams */
consumer_interface_inputs,
consumer_inputs_with_locations);
- /* If a matching input variable was found, add this ouptut (and the
+ /* If a matching input variable was found, add this output (and the
* input) to the set. If this is a separable program and there is no
* consumer stage, add the output.
*
* within a patch and can be used as shared memory.
*/
if (input_var || (prog->SeparateShader && consumer == NULL) ||
- producer->Type == GL_TESS_CONTROL_SHADER) {
+ producer->Stage == MESA_SHADER_TESS_CTRL) {
matches.record(output_var, input_var);
}
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))
+ if (input_var == NULL || input_var->data.mode != ir_var_shader_in)
continue;
matches.record(NULL, input_var);
}
}
+ _mesa_hash_table_destroy(consumer_inputs, NULL);
+ _mesa_hash_table_destroy(consumer_interface_inputs, NULL);
+
for (unsigned i = 0; i < num_tfeedback_decls; ++i) {
if (!tfeedback_decls[i].is_varying())
continue;
= tfeedback_decls[i].find_candidate(prog, tfeedback_candidates);
if (matched_candidate == NULL) {
- hash_table_dtor(tfeedback_candidates);
- hash_table_dtor(consumer_inputs);
- hash_table_dtor(consumer_interface_inputs);
+ _mesa_hash_table_destroy(tfeedback_candidates, NULL);
return false;
}
}
}
- const uint64_t reserved_slots =
- reserved_varying_slot(producer, ir_var_shader_out) |
- reserved_varying_slot(consumer, ir_var_shader_in);
-
- const unsigned slots_used = matches.assign_locations(prog, reserved_slots,
- prog->SeparateShader);
+ uint8_t components[MAX_VARYINGS_INCL_PATCH] = {0};
+ const unsigned slots_used = matches.assign_locations(
+ prog, components, reserved_slots);
matches.store_locations();
for (unsigned i = 0; i < num_tfeedback_decls; ++i) {
continue;
if (!tfeedback_decls[i].assign_location(ctx, prog)) {
- hash_table_dtor(tfeedback_candidates);
- hash_table_dtor(consumer_inputs);
- hash_table_dtor(consumer_interface_inputs);
+ _mesa_hash_table_destroy(tfeedback_candidates, NULL);
return false;
}
}
-
- hash_table_dtor(tfeedback_candidates);
- hash_table_dtor(consumer_inputs);
- hash_table_dtor(consumer_interface_inputs);
+ _mesa_hash_table_destroy(tfeedback_candidates, NULL);
if (consumer && producer) {
foreach_in_list(ir_instruction, node, consumer->ir) {
if (var && var->data.mode == ir_var_shader_in &&
var->data.is_unmatched_generic_inout) {
- if (!prog->IsES && prog->Version <= 120) {
+ if (!prog->IsES && prog->data->Version <= 120) {
/* On page 25 (page 31 of the PDF) of the GLSL 1.20 spec:
*
* Only those varying variables used (i.e. read) in
}
if (producer) {
- lower_packed_varyings(mem_ctx, slots_used, ir_var_shader_out,
+ lower_packed_varyings(mem_ctx, slots_used, components, ir_var_shader_out,
0, producer, disable_varying_packing,
xfb_enabled);
}
if (consumer) {
- lower_packed_varyings(mem_ctx, slots_used, ir_var_shader_in,
+ lower_packed_varyings(mem_ctx, slots_used, components, ir_var_shader_in,
consumer_vertices, consumer,
disable_varying_packing, xfb_enabled);
}
bool
check_against_output_limit(struct gl_context *ctx,
struct gl_shader_program *prog,
- gl_shader *producer)
+ gl_linked_shader *producer,
+ unsigned num_explicit_locations)
{
- unsigned output_vectors = 0;
+ unsigned output_vectors = num_explicit_locations;
foreach_in_list(ir_instruction, node, producer->ir) {
ir_variable *const var = node->as_variable();
- if (var && var->data.mode == ir_var_shader_out &&
+ if (var && !var->data.explicit_location &&
+ var->data.mode == ir_var_shader_out &&
var_counts_against_varying_limit(producer->Stage, var)) {
/* outputs for fragment shader can't be doubles */
output_vectors += var->type->count_attribute_slots(false);
bool
check_against_input_limit(struct gl_context *ctx,
struct gl_shader_program *prog,
- gl_shader *consumer)
+ gl_linked_shader *consumer,
+ unsigned num_explicit_locations)
{
- unsigned input_vectors = 0;
+ unsigned input_vectors = num_explicit_locations;
foreach_in_list(ir_instruction, node, consumer->ir) {
ir_variable *const var = node->as_variable();
- if (var && var->data.mode == ir_var_shader_in &&
+ if (var && !var->data.explicit_location &&
+ var->data.mode == ir_var_shader_in &&
var_counts_against_varying_limit(consumer->Stage, var)) {
/* vertex inputs aren't varying counted */
input_vectors += var->type->count_attribute_slots(false);