diff options
-rw-r--r-- | src/glsl/link_varyings.cpp | 88 | ||||
-rw-r--r-- | src/glsl/tests/varyings_test.cpp | 35 |
2 files changed, 103 insertions, 20 deletions
diff --git a/src/glsl/link_varyings.cpp b/src/glsl/link_varyings.cpp index e5c27516f56..45f1b10f0a4 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); @@ -1051,8 +1091,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(); @@ -1060,7 +1105,26 @@ 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.explicit_location) { + /* assign_varying_locations only cares about finding the + * ir_variable at the start of a contiguous location block. + * + * - For !producer, consumer_inputs_with_locations isn't used. + * + * - For !consumer, consumer_inputs_with_locations is empty. + * + * For consumer && producer, if you were trying to set some + * ir_variable to the middle of a location block on the other side + * of producer/consumer, cross_validate_outputs_to_inputs() should + * be link-erroring due to either type mismatch or location + * overlaps. If the variables do match up, then they've got a + * matching data.location and you only looked at + * consumer_inputs_with_locations[var->data.location], not any + * following entries for the array/structure. + */ + consumer_inputs_with_locations[input_var->data.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, @@ -1087,11 +1151,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.explicit_location) { + input_var = consumer_inputs_with_locations[output_var->data.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, @@ -1210,6 +1277,9 @@ 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] = { + NULL, + }; /* Operate in a total of four passes. * @@ -1236,7 +1306,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); @@ -1258,7 +1329,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); /* 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 174911245f7..8a188a7b6a8 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); } |