X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fcompiler%2Fglsl%2Flink_varyings.cpp;h=e1a29b03549ee741b333b2bb1007796dcc2630db;hb=16b480547ffaa5bcc8fdac184349b13ce8f019f5;hp=b4a4fb348dca3b121e1f8c716f785dd2d67fd022;hpb=4fb4fd0b6b1fe8387dc4c9154359f890d379e9cd;p=mesa.git diff --git a/src/compiler/glsl/link_varyings.cpp b/src/compiler/glsl/link_varyings.cpp index b4a4fb348dc..e1a29b03549 100644 --- a/src/compiler/glsl/link_varyings.cpp +++ b/src/compiler/glsl/link_varyings.cpp @@ -36,7 +36,7 @@ #include "linker.h" #include "link_varyings.h" #include "main/macros.h" -#include "program/hash_table.h" +#include "util/hash_table.h" #include "program.h" @@ -107,7 +107,7 @@ create_xfb_varying_names(void *mem_ctx, const glsl_type *t, char **name, } 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) { @@ -118,7 +118,7 @@ process_xfb_layout_qualifiers(void *mem_ctx, const gl_shader *sh, * 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; } } @@ -182,6 +182,25 @@ process_xfb_layout_qualifiers(void *mem_ctx, const gl_shader *sh, 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. @@ -226,15 +245,19 @@ cross_validate_types_and_qualifiers(struct gl_shader_program *prog, * 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; + } } } @@ -248,7 +271,7 @@ cross_validate_types_and_qualifiers(struct gl_shader_program *prog, * 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, " @@ -285,7 +308,25 @@ cross_validate_types_and_qualifiers(struct gl_shader_program *prog, 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", @@ -307,7 +348,7 @@ cross_validate_types_and_qualifiers(struct gl_shader_program *prog, * */ 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, " @@ -347,7 +388,8 @@ cross_validate_front_and_back_color(struct gl_shader_program *prog, */ 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] = @@ -358,7 +400,7 @@ cross_validate_outputs_to_inputs(struct gl_shader_program *prog, 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 @@ -374,19 +416,20 @@ cross_validate_outputs_to_inputs(struct gl_shader_program *prog, 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 " @@ -401,7 +444,7 @@ cross_validate_outputs_to_inputs(struct gl_shader_program *prog, 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. " @@ -412,13 +455,14 @@ cross_validate_outputs_to_inputs(struct gl_shader_program *prog, } 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++; @@ -442,7 +486,7 @@ cross_validate_outputs_to_inputs(struct gl_shader_program *prog, 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) { @@ -531,7 +575,7 @@ cross_validate_outputs_to_inputs(struct gl_shader_program *prog, */ 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) @@ -540,7 +584,7 @@ remove_unused_shader_inputs_and_outputs(bool 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 @@ -549,6 +593,11 @@ remove_unused_shader_inputs_and_outputs(bool is_separate_shader_object, */ 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; } } @@ -683,7 +732,7 @@ tfeedback_decl::assign_location(struct gl_context *ctx, + 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 */ @@ -804,15 +853,20 @@ tfeedback_decl::store(struct gl_context *ctx, struct gl_shader_program *prog, 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 { @@ -820,41 +874,43 @@ tfeedback_decl::store(struct gl_context *ctx, struct gl_shader_program *prog, } 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.", @@ -895,10 +951,11 @@ tfeedback_decl::store(struct gl_context *ctx, struct gl_shader_program *prog, 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++; @@ -929,8 +986,11 @@ tfeedback_decl::find_candidate(gl_shader_program *prog, 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: @@ -942,6 +1002,7 @@ tfeedback_decl::find_candidate(gl_shader_program *prog, linker_error(prog, "Transform feedback varying %s undeclared.", this->orig_name); } + return this->matched_candidate; } @@ -1002,7 +1063,8 @@ cmp_xfb_offset(const void * x_generic, const void * y_generic) /** * 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. @@ -1020,11 +1082,9 @@ store_tfeedback_info(struct gl_context *ctx, struct gl_shader_program *prog, 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 @@ -1034,9 +1094,8 @@ store_tfeedback_info(struct gl_context *ctx, struct gl_shader_program *prog, 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; @@ -1045,9 +1104,8 @@ store_tfeedback_info(struct gl_context *ctx, struct gl_shader_program *prog, 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; @@ -1056,7 +1114,8 @@ store_tfeedback_info(struct gl_context *ctx, struct gl_shader_program *prog, 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; @@ -1078,7 +1137,7 @@ store_tfeedback_info(struct gl_context *ctx, struct gl_shader_program *prog, 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; } } @@ -1093,24 +1152,31 @@ store_tfeedback_info(struct gl_context *ctx, struct gl_shader_program *prog, } 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) { @@ -1121,16 +1187,16 @@ store_tfeedback_info(struct gl_context *ctx, struct gl_shader_program *prog, 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; } @@ -1149,7 +1215,8 @@ public: ~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: @@ -1278,8 +1345,8 @@ varying_matches::~varying_matches() /** - * 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, @@ -1331,8 +1398,9 @@ varying_matches::record(ir_variable *producer_var, ir_variable *consumer_var) (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 @@ -1347,13 +1415,13 @@ varying_matches::record(ir_variable *producer_var, ir_variable *consumer_var) 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; } } @@ -1364,10 +1432,26 @@ varying_matches::record(ir_variable *producer_var, ir_variable *consumer_var) 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 @@ -1397,8 +1481,8 @@ varying_matches::record(ir_variable *producer_var, ir_variable *consumer_var) */ 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 @@ -1462,14 +1546,16 @@ varying_matches::assign_locations(struct gl_shader_program *prog, 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 @@ -1477,29 +1563,21 @@ varying_matches::assign_locations(struct gl_shader_program *prog, * 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 " @@ -1507,9 +1585,15 @@ varying_matches::assign_locations(struct gl_shader_program *prog, 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; @@ -1571,7 +1655,8 @@ varying_matches::compute_packing_class(const ir_variable *var) 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; } @@ -1701,20 +1786,22 @@ public: 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(); } @@ -1757,7 +1844,7 @@ populate_consumer_input_sets(void *mem_ctx, exec_list *ir, 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()); @@ -1785,11 +1872,12 @@ populate_consumer_input_sets(void *mem_ctx, exec_list *ir, 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); } } } @@ -1817,12 +1905,11 @@ get_matching_input(void *mem_ctx, 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) @@ -1898,8 +1985,9 @@ canonicalize_shader_io(exec_list *ir, enum ir_variable_mode io_mode) * 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 */ @@ -1958,9 +2046,11 @@ bool 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. @@ -1979,51 +2069,32 @@ assign_varying_locations(struct gl_context *ctx, 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, }; @@ -2063,8 +2134,7 @@ assign_varying_locations(struct gl_context *ctx, 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 */ @@ -2082,7 +2152,7 @@ assign_varying_locations(struct gl_context *ctx, 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. * @@ -2090,7 +2160,7 @@ assign_varying_locations(struct gl_context *ctx, * 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); } @@ -2112,14 +2182,16 @@ assign_varying_locations(struct gl_context *ctx, 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; @@ -2128,9 +2200,7 @@ assign_varying_locations(struct gl_context *ctx, = 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; } @@ -2140,12 +2210,9 @@ assign_varying_locations(struct gl_context *ctx, } } - 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) { @@ -2153,16 +2220,11 @@ assign_varying_locations(struct gl_context *ctx, 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) { @@ -2170,7 +2232,7 @@ assign_varying_locations(struct gl_context *ctx, 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 @@ -2210,13 +2272,13 @@ assign_varying_locations(struct gl_context *ctx, } 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); } @@ -2227,14 +2289,16 @@ assign_varying_locations(struct gl_context *ctx, 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); @@ -2269,14 +2333,16 @@ check_against_output_limit(struct gl_context *ctx, 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);