On Fri, Mar 28, 2014 at 5:40 AM, Ian Romanick <i...@freedesktop.org> wrote: > From: Ian Romanick <ian.d.roman...@intel.com> > > This will be used for GL_ARB_separate_shader_objects. That extension > not only allows separable shaders to rendezvous by location, but it also > allows traditionally linked shaders to rendezvous by location. The spec > says: > > 36. How does the behavior of input/output interface matching differ > between separable programs and non-separable programs? > > RESOLVED: The rules for matching individual variables or block > members between stages are identical for separable and > non-separable programs, with one exception -- matching variables > of different type with the same location, as discussed in issue > 34, applies only to separable programs. > > However, the ability to enforce matching requirements differs > between program types. In non-separable programs, both sides of > an interface are contained in the same linked program. In this > case, if the linker detects a mismatch, it will generate a link > error. > > Signed-off-by: Ian Romanick <ian.d.roman...@intel.com> > --- > src/glsl/link_varyings.cpp | 73 > +++++++++++++++++++++++++++++++++++----- > src/glsl/tests/varyings_test.cpp | 35 ++++++++++++------- > 2 files changed, 88 insertions(+), 20 deletions(-) > > diff --git a/src/glsl/link_varyings.cpp b/src/glsl/link_varyings.cpp > index 3d9516c..3f80dbd 100644 > --- a/src/glsl/link_varyings.cpp > +++ b/src/glsl/link_varyings.cpp > @@ -172,6 +172,7 @@ cross_validate_outputs_to_inputs(struct gl_shader_program > *prog, > gl_shader *producer, gl_shader *consumer) > { > glsl_symbol_table parameters; > + ir_variable *explicit_locations[MAX_VARYING] = { NULL, }; > > /* Find all shader outputs in the "producer" stage. > */ > @@ -181,7 +182,26 @@ cross_validate_outputs_to_inputs(struct > gl_shader_program *prog, > if ((var == NULL) || (var->data.mode != ir_var_shader_out)) > continue; > > - parameters.add_variable(var); > + if (!var->data.explicit_location > + || var->data.location < VARYING_SLOT_VAR0) > + parameters.add_variable(var); > + else { > + /* User-defined varyings with explicit locations are handled > + * differently because they do not need to have matching names. > + */ > + const unsigned idx = var->data.location - VARYING_SLOT_VAR0; > + > + if (explicit_locations[idx] != NULL) { > + linker_error(prog, > + "%s shader has multiple outputs explicitly " > + "assigned to location %d\n", > + _mesa_shader_stage_to_string(producer->Stage), > + idx); > + return; > + } > + > + explicit_locations[idx] = var; > + } > } > > > @@ -220,7 +240,27 @@ cross_validate_outputs_to_inputs(struct > gl_shader_program *prog, > front_color, back_color, > consumer->Stage, > producer->Stage); > } else { > - ir_variable *const output = parameters.get_variable(input->name); > + /* The rules for connecting inputs and outputs change in the > presence > + * of explicit locations. In this case, we no longer care about the > + * names of the variables. Instead, we care only about the > + * explicitly assigned location. > + */ > + ir_variable *output = NULL; > + if (input->data.explicit_location > + && input->data.location >= VARYING_SLOT_VAR0) { > + output = explicit_locations[input->data.location - > VARYING_SLOT_VAR0]; > + > + if (output == NULL) { > + linker_error(prog, > + "%s shader input `%s' with explicit location " > + "has no matching output\n", > + _mesa_shader_stage_to_string(consumer->Stage), > + input->name); > + } > + } else { > + output = parameters.get_variable(input->name); > + } > + > if (output != NULL) { > cross_validate_types_and_qualifiers(prog, input, output, > consumer->Stage, > producer->Stage); > @@ -1052,8 +1092,13 @@ namespace linker { > bool > populate_consumer_input_sets(void *mem_ctx, exec_list *ir, > hash_table *consumer_inputs, > - hash_table *consumer_interface_inputs) > + hash_table *consumer_interface_inputs, > + ir_variable > *consumer_inputs_with_locations[MAX_VARYING]) > { > + memset(consumer_inputs_with_locations, > + 0, > + sizeof(consumer_inputs_with_locations[0]) * MAX_VARYING); > + > foreach_list(node, ir) { > ir_variable *const input_var = ((ir_instruction *) > node)->as_variable(); > > @@ -1061,7 +1106,13 @@ populate_consumer_input_sets(void *mem_ctx, exec_list > *ir, > if (input_var->type->is_interface()) > return false; > > - if (input_var->get_interface_type() != NULL) { > + if (input_var->data.user_location != -1) { > + /* FINISHME: If the input is an interface, array, or structure, > it > + * FINISHME: will use multiple slots. > + */ > + consumer_inputs_with_locations[input_var->data.user_location] = > + input_var; > + } else if (input_var->get_interface_type() != NULL) { > char *const iface_field_name = > ralloc_asprintf(mem_ctx, "%s.%s", > input_var->get_interface_type()->name, > @@ -1088,11 +1139,14 @@ ir_variable * > get_matching_input(void *mem_ctx, > const ir_variable *output_var, > hash_table *consumer_inputs, > - hash_table *consumer_interface_inputs) > + hash_table *consumer_interface_inputs, > + ir_variable *consumer_inputs_with_locations[MAX_VARYING]) > { > ir_variable *input_var; > > - if (output_var->get_interface_type() != NULL) { > + if (output_var->data.user_location != -1) { > + input_var = > consumer_inputs_with_locations[output_var->data.user_location]; > + } else if (output_var->get_interface_type() != NULL) { > char *const iface_field_name = > ralloc_asprintf(mem_ctx, "%s.%s", > output_var->get_interface_type()->name, > @@ -1213,6 +1267,7 @@ assign_varying_locations(struct gl_context *ctx, > = 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); > + ir_variable *consumer_inputs_with_locations[MAX_VARYING]; > > /* Operate in a total of four passes. > * > @@ -1239,7 +1294,8 @@ assign_varying_locations(struct gl_context *ctx, > && !linker::populate_consumer_input_sets(mem_ctx, > consumer->ir, > consumer_inputs, > - consumer_interface_inputs)) { > + consumer_interface_inputs, > + > consumer_inputs_with_locations)) { > assert(!"populate_consumer_input_sets failed"); > hash_table_dtor(tfeedback_candidates); > hash_table_dtor(consumer_inputs); > @@ -1261,7 +1317,8 @@ assign_varying_locations(struct gl_context *ctx, > > ir_variable *const input_var = > linker::get_matching_input(mem_ctx, output_var, consumer_inputs, > - consumer_interface_inputs); > + consumer_interface_inputs, > + consumer_inputs_with_locations); consumer_inputs_with_locations is uninitialized when there is no consumer. get_matching_input would return garbage when output_var has a user location.
Something I ran into when testing the patches out. > > /* If a matching input variable was found, add this ouptut (and the > * input) to the set. If this is a separable program and there is > no > diff --git a/src/glsl/tests/varyings_test.cpp > b/src/glsl/tests/varyings_test.cpp > index 1749112..8a188a7 100644 > --- a/src/glsl/tests/varyings_test.cpp > +++ b/src/glsl/tests/varyings_test.cpp > @@ -38,13 +38,15 @@ namespace linker { > bool > populate_consumer_input_sets(void *mem_ctx, exec_list *ir, > hash_table *consumer_inputs, > - hash_table *consumer_interface_inputs); > + hash_table *consumer_interface_inputs, > + ir_variable > *consumer_inputs_with_locations[MAX_VARYING]); > > ir_variable * > get_matching_input(void *mem_ctx, > const ir_variable *output_var, > hash_table *consumer_inputs, > - hash_table *consumer_interface_inputs); > + hash_table *consumer_interface_inputs, > + ir_variable *consumer_inputs_with_locations[MAX_VARYING]); > } > > class link_varyings : public ::testing::Test { > @@ -68,6 +70,7 @@ public: > hash_table *consumer_interface_inputs; > > const glsl_type *simple_interface; > + ir_variable *junk[MAX_VARYING]; > }; > > link_varyings::link_varyings() > @@ -164,7 +167,8 @@ TEST_F(link_varyings, single_simple_input) > ASSERT_TRUE(linker::populate_consumer_input_sets(mem_ctx, > &ir, > consumer_inputs, > - > consumer_interface_inputs)); > + > consumer_interface_inputs, > + junk)); > > EXPECT_EQ((void *) v, hash_table_find(consumer_inputs, "a")); > EXPECT_EQ(1u, num_elements(consumer_inputs)); > @@ -190,7 +194,8 @@ TEST_F(link_varyings, gl_ClipDistance) > ASSERT_TRUE(linker::populate_consumer_input_sets(mem_ctx, > &ir, > consumer_inputs, > - > consumer_interface_inputs)); > + > consumer_interface_inputs, > + junk)); > > EXPECT_EQ((void *) clipdistance, > hash_table_find(consumer_inputs, "gl_ClipDistance")); > @@ -212,8 +217,8 @@ TEST_F(link_varyings, single_interface_input) > ASSERT_TRUE(linker::populate_consumer_input_sets(mem_ctx, > &ir, > consumer_inputs, > - > consumer_interface_inputs)); > - > + > consumer_interface_inputs, > + junk)); > char *const full_name = interface_field_name(simple_interface); > > EXPECT_EQ((void *) v, hash_table_find(consumer_interface_inputs, > full_name)); > @@ -243,7 +248,8 @@ TEST_F(link_varyings, one_interface_and_one_simple_input) > ASSERT_TRUE(linker::populate_consumer_input_sets(mem_ctx, > &ir, > consumer_inputs, > - > consumer_interface_inputs)); > + > consumer_interface_inputs, > + junk)); > > char *const iface_field_name = interface_field_name(simple_interface); > > @@ -269,7 +275,8 @@ TEST_F(link_varyings, invalid_interface_input) > EXPECT_FALSE(linker::populate_consumer_input_sets(mem_ctx, > &ir, > consumer_inputs, > - > consumer_interface_inputs)); > + > consumer_interface_inputs, > + junk)); > } > > TEST_F(link_varyings, interface_field_doesnt_match_noninterface) > @@ -288,7 +295,8 @@ TEST_F(link_varyings, > interface_field_doesnt_match_noninterface) > ASSERT_TRUE(linker::populate_consumer_input_sets(mem_ctx, > &ir, > consumer_inputs, > - > consumer_interface_inputs)); > + > consumer_interface_inputs, > + junk)); > > /* Create an output variable, "v", that is part of an interface block > named > * "a". They should not match. > @@ -304,7 +312,8 @@ TEST_F(link_varyings, > interface_field_doesnt_match_noninterface) > linker::get_matching_input(mem_ctx, > out_v, > consumer_inputs, > - consumer_interface_inputs); > + consumer_interface_inputs, > + junk); > > EXPECT_EQ(NULL, match); > } > @@ -328,7 +337,8 @@ TEST_F(link_varyings, > interface_field_doesnt_match_noninterface_vice_versa) > ASSERT_TRUE(linker::populate_consumer_input_sets(mem_ctx, > &ir, > consumer_inputs, > - > consumer_interface_inputs)); > + > consumer_interface_inputs, > + junk)); > > /* Create an output variable "a.v". They should not match. > */ > @@ -341,7 +351,8 @@ TEST_F(link_varyings, > interface_field_doesnt_match_noninterface_vice_versa) > linker::get_matching_input(mem_ctx, > out_v, > consumer_inputs, > - consumer_interface_inputs); > + consumer_interface_inputs, > + junk); > > EXPECT_EQ(NULL, match); > } > -- > 1.8.1.4 > > _______________________________________________ > mesa-dev mailing list > mesa-dev@lists.freedesktop.org > http://lists.freedesktop.org/mailman/listinfo/mesa-dev -- o...@lunarg.com _______________________________________________ mesa-dev mailing list mesa-dev@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/mesa-dev