<div dir="ltr">I applied a fix locally for the problem Olv pointed out and tested the patches.<div><br></div><div>Running into a problem with the linker code when a geometry shader has location layout qualifiers for both inputs and outputs.<br>
<br>It
falls into the assign_varying_locations() scenario that has a producer
but no consumer, which prevents the input locations from being
processed. This leads to backend instructions like these, which have
negative attribute registers:<br>
<span style="font-family:'courier new',monospace"><br></span><span style="font-family:'courier new',monospace"> 3: mov vgrf11.0.xyz:F, attr-1.59.xyzx:F<br> 4: mov vgrf12.0.xyz:F, attr-1.118.xyzx:F<br>
</span><br>Those trigger the following debug assert when a negative register indexes the attribute_map:<br><br><font face="courier new, monospace"> int grf = attribute_map[inst->src[i].reg + inst->src[i].reg_offset];<br>
<br> /* All attributes used in the shader need to have been assigned a<br> * hardware register by the caller<br> */<br> assert(grf != 0);</font><br><br>Does assign_varying_locations() need to be updated to handle when a single shader is both a consumer and producer? Or maybe call it twice on the same separate shader, once as producer, once as consumer?</div>
<div>
<br>The below patch to an existing piglit test demonstrates the
assert, although it doesn't render to verify the locations get
matched up correctly. Adding a geometry shader to rendezvous_by_location.c is a better long term test, unless it is already tested somewhere I haven't found.</div><div><br></div><div>Thanks,</div><div><br></div><div>
-C<br>
<br><div><font face="courier new, monospace">diff --git a/tests/spec/arb_separate_shader_objects/GetProgramPipelineiv.c b/tests/spec/arb_separate_shader_objects/GetProgramPipelineiv.c</font></div><div><font face="courier new, monospace">index d95d7b8..93e3fd9 100644</font></div>
<div><font face="courier new, monospace">--- a/tests/spec/arb_separate_shader_objects/GetProgramPipelineiv.c</font></div><div><font face="courier new, monospace">+++ b/tests/spec/arb_separate_shader_objects/GetProgramPipelineiv.c</font></div>
<div><font face="courier new, monospace">@@ -145,9 +145,12 @@ piglit_init(int argc, char **argv)</font></div><div><font face="courier new, monospace"> "\n"</font></div><div><font face="courier new, monospace"> "layout(triangles) in;\n"</font></div>
<div><font face="courier new, monospace"> "layout(triangle_strip, max_vertices = 3) out;\n"</font></div><div><font face="courier new, monospace">+ "layout(location = 0) in vec4 foo[3];\n"</font></div>
<div><font face="courier new, monospace">+ "layout(location = 0) out vec4 bar[3];\n"</font></div><div><font face="courier new, monospace"> "void main() {\n"</font></div><div>
<font face="courier new, monospace"> " for(int i = 0; i < gl_in.length(); i++) {\n"</font></div><div><font face="courier new, monospace">- " gl_Position = gl_in[i].gl_Position;\n"</font></div>
<div><font face="courier new, monospace">+ " gl_Position = gl_in[i].gl_Position + foo[1];\n"</font></div><div><font face="courier new, monospace">+ " bar[2] = foo[2];\n"</font></div>
<div><font face="courier new, monospace"> " EmitVertex();\n"</font></div><div><font face="courier new, monospace"> " }\n"</font></div><div><font face="courier new, monospace"> " EndPrimitive();\n"</font></div>
</div><div><br></div></div><div class="gmail_extra"><br><br><div class="gmail_quote">On Fri, Mar 28, 2014 at 12:36 AM, Chia-I Wu <span dir="ltr"><<a href="mailto:olvaffe@gmail.com" target="_blank">olvaffe@gmail.com</a>></span> wrote:<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div class="HOEnZb"><div class="h5">On Fri, Mar 28, 2014 at 5:40 AM, Ian Romanick <<a href="mailto:idr@freedesktop.org">idr@freedesktop.org</a>> wrote:<br>
> From: Ian Romanick <<a href="mailto:ian.d.romanick@intel.com">ian.d.romanick@intel.com</a>><br>
><br>
> This will be used for GL_ARB_separate_shader_objects. That extension<br>
> not only allows separable shaders to rendezvous by location, but it also<br>
> allows traditionally linked shaders to rendezvous by location. The spec<br>
> says:<br>
><br>
> 36. How does the behavior of input/output interface matching differ<br>
> between separable programs and non-separable programs?<br>
><br>
> RESOLVED: The rules for matching individual variables or block<br>
> members between stages are identical for separable and<br>
> non-separable programs, with one exception -- matching variables<br>
> of different type with the same location, as discussed in issue<br>
> 34, applies only to separable programs.<br>
><br>
> However, the ability to enforce matching requirements differs<br>
> between program types. In non-separable programs, both sides of<br>
> an interface are contained in the same linked program. In this<br>
> case, if the linker detects a mismatch, it will generate a link<br>
> error.<br>
><br>
> Signed-off-by: Ian Romanick <<a href="mailto:ian.d.romanick@intel.com">ian.d.romanick@intel.com</a>><br>
> ---<br>
> src/glsl/link_varyings.cpp | 73 +++++++++++++++++++++++++++++++++++-----<br>
> src/glsl/tests/varyings_test.cpp | 35 ++++++++++++-------<br>
> 2 files changed, 88 insertions(+), 20 deletions(-)<br>
><br>
> diff --git a/src/glsl/link_varyings.cpp b/src/glsl/link_varyings.cpp<br>
> index 3d9516c..3f80dbd 100644<br>
> --- a/src/glsl/link_varyings.cpp<br>
> +++ b/src/glsl/link_varyings.cpp<br>
> @@ -172,6 +172,7 @@ cross_validate_outputs_to_inputs(struct gl_shader_program *prog,<br>
> gl_shader *producer, gl_shader *consumer)<br>
> {<br>
> glsl_symbol_table parameters;<br>
> + ir_variable *explicit_locations[MAX_VARYING] = { NULL, };<br>
><br>
> /* Find all shader outputs in the "producer" stage.<br>
> */<br>
> @@ -181,7 +182,26 @@ cross_validate_outputs_to_inputs(struct gl_shader_program *prog,<br>
> if ((var == NULL) || (var->data.mode != ir_var_shader_out))<br>
> continue;<br>
><br>
> - parameters.add_variable(var);<br>
> + if (!var->data.explicit_location<br>
> + || var->data.location < VARYING_SLOT_VAR0)<br>
> + parameters.add_variable(var);<br>
> + else {<br>
> + /* User-defined varyings with explicit locations are handled<br>
> + * differently because they do not need to have matching names.<br>
> + */<br>
> + const unsigned idx = var->data.location - VARYING_SLOT_VAR0;<br>
> +<br>
> + if (explicit_locations[idx] != NULL) {<br>
> + linker_error(prog,<br>
> + "%s shader has multiple outputs explicitly "<br>
> + "assigned to location %d\n",<br>
> + _mesa_shader_stage_to_string(producer->Stage),<br>
> + idx);<br>
> + return;<br>
> + }<br>
> +<br>
> + explicit_locations[idx] = var;<br>
> + }<br>
> }<br>
><br>
><br>
> @@ -220,7 +240,27 @@ cross_validate_outputs_to_inputs(struct gl_shader_program *prog,<br>
> front_color, back_color,<br>
> consumer->Stage, producer->Stage);<br>
> } else {<br>
> - ir_variable *const output = parameters.get_variable(input->name);<br>
> + /* The rules for connecting inputs and outputs change in the presence<br>
> + * of explicit locations. In this case, we no longer care about the<br>
> + * names of the variables. Instead, we care only about the<br>
> + * explicitly assigned location.<br>
> + */<br>
> + ir_variable *output = NULL;<br>
> + if (input->data.explicit_location<br>
> + && input->data.location >= VARYING_SLOT_VAR0) {<br>
> + output = explicit_locations[input->data.location - VARYING_SLOT_VAR0];<br>
> +<br>
> + if (output == NULL) {<br>
> + linker_error(prog,<br>
> + "%s shader input `%s' with explicit location "<br>
> + "has no matching output\n",<br>
> + _mesa_shader_stage_to_string(consumer->Stage),<br>
> + input->name);<br>
> + }<br>
> + } else {<br>
> + output = parameters.get_variable(input->name);<br>
> + }<br>
> +<br>
> if (output != NULL) {<br>
> cross_validate_types_and_qualifiers(prog, input, output,<br>
> consumer->Stage, producer->Stage);<br>
> @@ -1052,8 +1092,13 @@ namespace linker {<br>
> bool<br>
> populate_consumer_input_sets(void *mem_ctx, exec_list *ir,<br>
> hash_table *consumer_inputs,<br>
> - hash_table *consumer_interface_inputs)<br>
> + hash_table *consumer_interface_inputs,<br>
> + ir_variable *consumer_inputs_with_locations[MAX_VARYING])<br>
> {<br>
> + memset(consumer_inputs_with_locations,<br>
> + 0,<br>
> + sizeof(consumer_inputs_with_locations[0]) * MAX_VARYING);<br>
> +<br>
> foreach_list(node, ir) {<br>
> ir_variable *const input_var = ((ir_instruction *) node)->as_variable();<br>
><br>
> @@ -1061,7 +1106,13 @@ populate_consumer_input_sets(void *mem_ctx, exec_list *ir,<br>
> if (input_var->type->is_interface())<br>
> return false;<br>
><br>
> - if (input_var->get_interface_type() != NULL) {<br>
> + if (input_var->data.user_location != -1) {<br>
> + /* FINISHME: If the input is an interface, array, or structure, it<br>
> + * FINISHME: will use multiple slots.<br>
> + */<br>
> + consumer_inputs_with_locations[input_var->data.user_location] =<br>
> + input_var;<br>
> + } else if (input_var->get_interface_type() != NULL) {<br>
> char *const iface_field_name =<br>
> ralloc_asprintf(mem_ctx, "%s.%s",<br>
> input_var->get_interface_type()->name,<br>
> @@ -1088,11 +1139,14 @@ ir_variable *<br>
> get_matching_input(void *mem_ctx,<br>
> const ir_variable *output_var,<br>
> hash_table *consumer_inputs,<br>
> - hash_table *consumer_interface_inputs)<br>
> + hash_table *consumer_interface_inputs,<br>
> + ir_variable *consumer_inputs_with_locations[MAX_VARYING])<br>
> {<br>
> ir_variable *input_var;<br>
><br>
> - if (output_var->get_interface_type() != NULL) {<br>
> + if (output_var->data.user_location != -1) {<br>
> + input_var = consumer_inputs_with_locations[output_var->data.user_location];<br>
> + } else if (output_var->get_interface_type() != NULL) {<br>
> char *const iface_field_name =<br>
> ralloc_asprintf(mem_ctx, "%s.%s",<br>
> output_var->get_interface_type()->name,<br>
> @@ -1213,6 +1267,7 @@ assign_varying_locations(struct gl_context *ctx,<br>
> = hash_table_ctor(0, hash_table_string_hash, hash_table_string_compare);<br>
> hash_table *consumer_interface_inputs<br>
> = hash_table_ctor(0, hash_table_string_hash, hash_table_string_compare);<br>
> + ir_variable *consumer_inputs_with_locations[MAX_VARYING];<br>
><br>
> /* Operate in a total of four passes.<br>
> *<br>
> @@ -1239,7 +1294,8 @@ assign_varying_locations(struct gl_context *ctx,<br>
> && !linker::populate_consumer_input_sets(mem_ctx,<br>
> consumer->ir,<br>
> consumer_inputs,<br>
> - consumer_interface_inputs)) {<br>
> + consumer_interface_inputs,<br>
> + consumer_inputs_with_locations)) {<br>
> assert(!"populate_consumer_input_sets failed");<br>
> hash_table_dtor(tfeedback_candidates);<br>
> hash_table_dtor(consumer_inputs);<br>
> @@ -1261,7 +1317,8 @@ assign_varying_locations(struct gl_context *ctx,<br>
><br>
> ir_variable *const input_var =<br>
> linker::get_matching_input(mem_ctx, output_var, consumer_inputs,<br>
> - consumer_interface_inputs);<br>
> + consumer_interface_inputs,<br>
> + consumer_inputs_with_locations);<br>
</div></div>consumer_inputs_with_locations is uninitialized when there is no<br>
consumer. get_matching_input would return garbage when output_var has<br>
a user location.<br>
<br>
Something I ran into when testing the patches out.<br>
<div class="HOEnZb"><div class="h5"><br>
><br>
> /* If a matching input variable was found, add this ouptut (and the<br>
> * input) to the set. If this is a separable program and there is no<br>
> diff --git a/src/glsl/tests/varyings_test.cpp b/src/glsl/tests/varyings_test.cpp<br>
> index 1749112..8a188a7 100644<br>
> --- a/src/glsl/tests/varyings_test.cpp<br>
> +++ b/src/glsl/tests/varyings_test.cpp<br>
> @@ -38,13 +38,15 @@ namespace linker {<br>
> bool<br>
> populate_consumer_input_sets(void *mem_ctx, exec_list *ir,<br>
> hash_table *consumer_inputs,<br>
> - hash_table *consumer_interface_inputs);<br>
> + hash_table *consumer_interface_inputs,<br>
> + ir_variable *consumer_inputs_with_locations[MAX_VARYING]);<br>
><br>
> ir_variable *<br>
> get_matching_input(void *mem_ctx,<br>
> const ir_variable *output_var,<br>
> hash_table *consumer_inputs,<br>
> - hash_table *consumer_interface_inputs);<br>
> + hash_table *consumer_interface_inputs,<br>
> + ir_variable *consumer_inputs_with_locations[MAX_VARYING]);<br>
> }<br>
><br>
> class link_varyings : public ::testing::Test {<br>
> @@ -68,6 +70,7 @@ public:<br>
> hash_table *consumer_interface_inputs;<br>
><br>
> const glsl_type *simple_interface;<br>
> + ir_variable *junk[MAX_VARYING];<br>
> };<br>
><br>
> link_varyings::link_varyings()<br>
> @@ -164,7 +167,8 @@ TEST_F(link_varyings, single_simple_input)<br>
> ASSERT_TRUE(linker::populate_consumer_input_sets(mem_ctx,<br>
> &ir,<br>
> consumer_inputs,<br>
> - consumer_interface_inputs));<br>
> + consumer_interface_inputs,<br>
> + junk));<br>
><br>
> EXPECT_EQ((void *) v, hash_table_find(consumer_inputs, "a"));<br>
> EXPECT_EQ(1u, num_elements(consumer_inputs));<br>
> @@ -190,7 +194,8 @@ TEST_F(link_varyings, gl_ClipDistance)<br>
> ASSERT_TRUE(linker::populate_consumer_input_sets(mem_ctx,<br>
> &ir,<br>
> consumer_inputs,<br>
> - consumer_interface_inputs));<br>
> + consumer_interface_inputs,<br>
> + junk));<br>
><br>
> EXPECT_EQ((void *) clipdistance,<br>
> hash_table_find(consumer_inputs, "gl_ClipDistance"));<br>
> @@ -212,8 +217,8 @@ TEST_F(link_varyings, single_interface_input)<br>
> ASSERT_TRUE(linker::populate_consumer_input_sets(mem_ctx,<br>
> &ir,<br>
> consumer_inputs,<br>
> - consumer_interface_inputs));<br>
> -<br>
> + consumer_interface_inputs,<br>
> + junk));<br>
> char *const full_name = interface_field_name(simple_interface);<br>
><br>
> EXPECT_EQ((void *) v, hash_table_find(consumer_interface_inputs, full_name));<br>
> @@ -243,7 +248,8 @@ TEST_F(link_varyings, one_interface_and_one_simple_input)<br>
> ASSERT_TRUE(linker::populate_consumer_input_sets(mem_ctx,<br>
> &ir,<br>
> consumer_inputs,<br>
> - consumer_interface_inputs));<br>
> + consumer_interface_inputs,<br>
> + junk));<br>
><br>
> char *const iface_field_name = interface_field_name(simple_interface);<br>
><br>
> @@ -269,7 +275,8 @@ TEST_F(link_varyings, invalid_interface_input)<br>
> EXPECT_FALSE(linker::populate_consumer_input_sets(mem_ctx,<br>
> &ir,<br>
> consumer_inputs,<br>
> - consumer_interface_inputs));<br>
> + consumer_interface_inputs,<br>
> + junk));<br>
> }<br>
><br>
> TEST_F(link_varyings, interface_field_doesnt_match_noninterface)<br>
> @@ -288,7 +295,8 @@ TEST_F(link_varyings, interface_field_doesnt_match_noninterface)<br>
> ASSERT_TRUE(linker::populate_consumer_input_sets(mem_ctx,<br>
> &ir,<br>
> consumer_inputs,<br>
> - consumer_interface_inputs));<br>
> + consumer_interface_inputs,<br>
> + junk));<br>
><br>
> /* Create an output variable, "v", that is part of an interface block named<br>
> * "a". They should not match.<br>
> @@ -304,7 +312,8 @@ TEST_F(link_varyings, interface_field_doesnt_match_noninterface)<br>
> linker::get_matching_input(mem_ctx,<br>
> out_v,<br>
> consumer_inputs,<br>
> - consumer_interface_inputs);<br>
> + consumer_interface_inputs,<br>
> + junk);<br>
><br>
> EXPECT_EQ(NULL, match);<br>
> }<br>
> @@ -328,7 +337,8 @@ TEST_F(link_varyings, interface_field_doesnt_match_noninterface_vice_versa)<br>
> ASSERT_TRUE(linker::populate_consumer_input_sets(mem_ctx,<br>
> &ir,<br>
> consumer_inputs,<br>
> - consumer_interface_inputs));<br>
> + consumer_interface_inputs,<br>
> + junk));<br>
><br>
> /* Create an output variable "a.v". They should not match.<br>
> */<br>
> @@ -341,7 +351,8 @@ TEST_F(link_varyings, interface_field_doesnt_match_noninterface_vice_versa)<br>
> linker::get_matching_input(mem_ctx,<br>
> out_v,<br>
> consumer_inputs,<br>
> - consumer_interface_inputs);<br>
> + consumer_interface_inputs,<br>
> + junk);<br>
><br>
> EXPECT_EQ(NULL, match);<br>
> }<br>
> --<br>
> 1.8.1.4<br>
><br>
> _______________________________________________<br>
> mesa-dev mailing list<br>
> <a href="mailto:mesa-dev@lists.freedesktop.org">mesa-dev@lists.freedesktop.org</a><br>
> <a href="http://lists.freedesktop.org/mailman/listinfo/mesa-dev" target="_blank">http://lists.freedesktop.org/mailman/listinfo/mesa-dev</a><br>
<br>
<br>
<br>
</div></div><span class="HOEnZb"><font color="#888888">--<br>
olv@LunarG.com<br>
</font></span><div class="HOEnZb"><div class="h5">_______________________________________________<br>
mesa-dev mailing list<br>
<a href="mailto:mesa-dev@lists.freedesktop.org">mesa-dev@lists.freedesktop.org</a><br>
<a href="http://lists.freedesktop.org/mailman/listinfo/mesa-dev" target="_blank">http://lists.freedesktop.org/mailman/listinfo/mesa-dev</a><br>
</div></div></blockquote></div><br><br clear="all"><div><br></div>-- <br><div dir="ltr"><div><font color="#999999"><font face="trebuchet ms, sans-serif"> Cody Northrop<br> Graphics Software Engineer<br> LunarG, Inc.- 3D Driver Innovations</font><font face="trebuchet ms, sans-serif" style="font-size:small"><br>
Email: <a href="mailto:cody@lunarg.com" target="_blank">cody@lunarg.com</a><br> Website: <a href="http://www.lunarg.com/" target="_blank">http://www.lunarg.com</a></font></font></div></div>
</div>