<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>