On 23 December 2011 13:02, Kenneth Graunke <span dir="ltr">&lt;<a href="mailto:kenneth@whitecape.org">kenneth@whitecape.org</a>&gt;</span> wrote:<br><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<div class="im">On 12/23/2011 09:37 AM, Paul Berry wrote:<br>
&gt; When rendering triangle strips, vertices come down the pipeline in the<br>
&gt; order specified, even though this causes alternate triangles to have<br>
&gt; reversed winding order.  For example, if the vertices are ABCDE, then<br>
&gt; the GS is invoked on triangles ABC, BCD, and CDE, even though this<br>
&gt; means that triangle BCD is in the reverse of the normal winding order.<br>
&gt; The hardware automatically flags the triangles with reversed winding<br>
&gt; order as _3DPRIM_TRISTRIP_REVERSE, so that face culling and two-sided<br>
&gt; coloring can be adjusted to account for the reversed order.<br>
&gt;<br>
&gt; In order to ensure that winding order is correct when streaming<br>
&gt; vertices out to a transform feedback buffer, we need to alter the<br>
&gt; ordering of BCD to BDC when the first provoking vertex convention is<br>
&gt; in use, and to CBD when the last provoking vertex convention is in<br>
&gt; use.<br>
&gt;<br>
&gt; To do this, we precompute an array of indices indicating where each<br>
&gt; vertex will be placed in the transform feedback buffer; normally this<br>
&gt; is SVBI[0] + (0, 1, 2), indicating that vertex order should be<br>
&gt; preserved.  When the primitive type is _3DPRIM_TRISTRIP_REVERSE, we<br>
&gt; change this order to either SVBI[0] + (0, 2, 1) or SVBI[0] + (1, 0,<br>
&gt; 2), depending on the provoking vertex convention.<br>
&gt;<br>
&gt; Fixes piglit tests &quot;EXT_transform_feedback/tessellation<br>
&gt; triangle_strip&quot; on Gen6.<br>
<br>
</div>It&#39;s really too bad we can&#39;t use the 3DSTATE_GS &quot;Reorder Enable&quot; bit.<br>
It&#39;s supposed to take care of this, but it looks like it only does PV<br>
first mode on Sandybridge.  Turning it on makes triangle_strip wireframe<br>
fail, and nothing else pass.<br></blockquote><div><br>Yeah, I concur.  That bit is *so* close to what we need, but not quite close enough.<br> </div><blockquote class="gmail_quote" style="margin:0pt 0pt 0pt 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">

<br>
I had a bit of trouble following this patch, but it looks okay to me.<br></blockquote><div><br>Ok.  I won&#39;t push it until this evening, so let me know if you can think of a way to improve the readability (I&#39;m at a loss for how to improve it).<br>
 </div><blockquote class="gmail_quote" style="margin:0pt 0pt 0pt 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
<br>
Reviewed-by: Kenneth Graunke &lt;<a href="mailto:kenneth@whitecape.org">kenneth@whitecape.org</a>&gt;<br>
<div class="HOEnZb"><div class="h5"><br>
&gt; ---<br>
&gt;  src/mesa/drivers/dri/i965/brw_gs.h      |    6 ++<br>
&gt;  src/mesa/drivers/dri/i965/brw_gs_emit.c |   84 ++++++++++++++++++++++++-------<br>
&gt;  2 files changed, 72 insertions(+), 18 deletions(-)<br>
&gt;<br>
&gt; diff --git a/src/mesa/drivers/dri/i965/brw_gs.h b/src/mesa/drivers/dri/i965/brw_gs.h<br>
&gt; index 7bf2248..2ab8b72 100644<br>
&gt; --- a/src/mesa/drivers/dri/i965/brw_gs.h<br>
&gt; +++ b/src/mesa/drivers/dri/i965/brw_gs.h<br>
&gt; @@ -83,6 +83,12 @@ struct brw_gs_compile {<br>
&gt;        struct brw_reg vertex[MAX_GS_VERTS];<br>
&gt;        struct brw_reg header;<br>
&gt;        struct brw_reg temp;<br>
&gt; +<br>
&gt; +      /**<br>
&gt; +       * Register holding destination indices for streamed buffer writes.<br>
&gt; +       * Only used for SOL programs.<br>
&gt; +       */<br>
&gt; +      struct brw_reg destination_indices;<br>
&gt;     } reg;<br>
&gt;<br>
&gt;     /* Number of registers used to store vertex data */<br>
&gt; diff --git a/src/mesa/drivers/dri/i965/brw_gs_emit.c b/src/mesa/drivers/dri/i965/brw_gs_emit.c<br>
&gt; index 1f96a16..607ee75 100644<br>
&gt; --- a/src/mesa/drivers/dri/i965/brw_gs_emit.c<br>
&gt; +++ b/src/mesa/drivers/dri/i965/brw_gs_emit.c<br>
&gt; @@ -45,13 +45,16 @@<br>
&gt;  /**<br>
&gt;   * Allocate registers for GS.<br>
&gt;   *<br>
&gt; - * If svbi_payload_enable is true, then the thread will be spawned with the<br>
&gt; - * &quot;SVBI Payload Enable&quot; bit set, so GRF 1 needs to be set aside to hold the<br>
&gt; - * streamed vertex buffer indices.<br>
&gt; + * If sol_program is true, then:<br>
&gt; + *<br>
&gt; + * - The thread will be spawned with the &quot;SVBI Payload Enable&quot; bit set, so GRF<br>
&gt; + *   1 needs to be set aside to hold the streamed vertex buffer indices.<br>
&gt; + *<br>
&gt; + * - The thread will need to use the destination_indices register.<br>
&gt;   */<br>
&gt;  static void brw_gs_alloc_regs( struct brw_gs_compile *c,<br>
&gt;                              GLuint nr_verts,<br>
&gt; -                               bool svbi_payload_enable )<br>
&gt; +                               bool sol_program )<br>
&gt;  {<br>
&gt;     GLuint i = 0,j;<br>
&gt;<br>
&gt; @@ -60,7 +63,7 @@ static void brw_gs_alloc_regs( struct brw_gs_compile *c,<br>
&gt;     c-&gt;reg.R0 = retype(brw_vec8_grf(i, 0), BRW_REGISTER_TYPE_UD); i++;<br>
&gt;<br>
&gt;     /* Streamed vertex buffer indices */<br>
&gt; -   if (svbi_payload_enable)<br>
&gt; +   if (sol_program)<br>
&gt;        c-&gt;reg.SVBI = retype(brw_vec8_grf(i++, 0), BRW_REGISTER_TYPE_UD);<br>
&gt;<br>
&gt;     /* Payload vertices plus space for more generated vertices:<br>
&gt; @@ -73,6 +76,11 @@ static void brw_gs_alloc_regs( struct brw_gs_compile *c,<br>
&gt;     c-&gt;reg.header = retype(brw_vec8_grf(i++, 0), BRW_REGISTER_TYPE_UD);<br>
&gt;     c-&gt;reg.temp = retype(brw_vec8_grf(i++, 0), BRW_REGISTER_TYPE_UD);<br>
&gt;<br>
&gt; +   if (sol_program) {<br>
&gt; +      c-&gt;reg.destination_indices =<br>
&gt; +         retype(brw_vec4_grf(i++, 0), BRW_REGISTER_TYPE_UD);<br>
&gt; +   }<br>
&gt; +<br>
&gt;     c-&gt;prog_data.urb_read_length = c-&gt;nr_regs;<br>
&gt;     c-&gt;prog_data.total_grf = i;<br>
&gt;  }<br>
&gt; @@ -351,16 +359,17 @@ gen6_sol_program(struct brw_gs_compile *c, struct brw_gs_prog_key *key,<br>
&gt;<br>
&gt;     if (key-&gt;num_transform_feedback_bindings &gt; 0) {<br>
&gt;        unsigned vertex, binding;<br>
&gt; +      struct brw_reg destination_indices_uw =<br>
&gt; +         vec8(retype(c-&gt;reg.destination_indices, BRW_REGISTER_TYPE_UW));<br>
&gt; +<br>
&gt;        /* Note: since we use the binding table to keep track of buffer offsets<br>
&gt;         * and stride, the GS doesn&#39;t need to keep track of a separate pointer<br>
&gt;         * into each buffer; it uses a single pointer which increments by 1 for<br>
&gt;         * each vertex.  So we use SVBI0 for this pointer, regardless of whether<br>
&gt;         * transform feedback is in interleaved or separate attribs mode.<br>
&gt; +       *<br>
&gt; +       * Make sure that the buffers have enough room for all the vertices.<br>
&gt;         */<br>
&gt; -      brw_MOV(p, get_element_ud(c-&gt;reg.header, 5),<br>
&gt; -              get_element_ud(c-&gt;reg.SVBI, 0));<br>
&gt; -<br>
&gt; -      /* Make sure that the buffers have enough room for all the vertices. */<br>
&gt;        brw_ADD(p, get_element_ud(c-&gt;reg.temp, 0),<br>
&gt;                get_element_ud(c-&gt;reg.SVBI, 0), brw_imm_ud(num_verts));<br>
&gt;        brw_CMP(p, vec1(brw_null_reg()), BRW_CONDITIONAL_LE,<br>
&gt; @@ -368,10 +377,58 @@ gen6_sol_program(struct brw_gs_compile *c, struct brw_gs_prog_key *key,<br>
&gt;                get_element_ud(c-&gt;reg.SVBI, 4));<br>
&gt;        brw_IF(p, BRW_EXECUTE_1);<br>
&gt;<br>
&gt; +      /* Compute the destination indices to write to.  Usually we use SVBI[0]<br>
&gt; +       * + (0, 1, 2).  However, for odd-numbered triangles in tristrips, the<br>
&gt; +       * vertices come down the pipeline in reversed winding order, so we need<br>
&gt; +       * to flip the order when writing to the transform feedback buffer.  To<br>
&gt; +       * ensure that flatshading accuracy is preserved, we need to write them<br>
&gt; +       * in order SVBI[0] + (0, 2, 1) if we&#39;re using the first provoking<br>
&gt; +       * vertex convention, and in order SVBI[0] + (1, 0, 2) if we&#39;re using<br>
&gt; +       * the last provoking vertex convention.<br>
&gt; +       *<br>
&gt; +       * Note: since brw_imm_v can only be used in instructions in<br>
&gt; +       * packed-word execution mode, and SVBI is a double-word, we need to<br>
&gt; +       * first move the appropriate immediate constant ((0, 1, 2), (0, 2, 1),<br>
&gt; +       * or (1, 0, 2)) to the destination_indices register, and then add SVBI<br>
&gt; +       * using a separate instruction.  Also, since the immediate constant is<br>
&gt; +       * expressed as packed words, and we need to load double-words into<br>
&gt; +       * destination_indices, we need to intersperse zeros to fill the upper<br>
&gt; +       * halves of each double-word.<br>
&gt; +       */<br>
&gt; +      brw_MOV(p, destination_indices_uw,<br>
&gt; +              brw_imm_v(0x00020100)); /* (0, 1, 2) */<br>
&gt; +      if (num_verts == 3) {<br>
&gt; +         /* Get primitive type into temp register. */<br>
&gt; +         brw_AND(p, get_element_ud(c-&gt;reg.temp, 0),<br>
&gt; +                 get_element_ud(c-&gt;reg.R0, 2), brw_imm_ud(0x1f));<br>
&gt; +<br>
&gt; +         /* Test if primitive type is TRISTRIP_REVERSE.  We need to do this as<br>
&gt; +          * an 8-wide comparison so that the conditional MOV that follows<br>
&gt; +          * moves all 8 words correctly.<br>
&gt; +          */<br>
&gt; +         brw_CMP(p, vec8(brw_null_reg()), BRW_CONDITIONAL_EQ,<br>
&gt; +                 get_element_ud(c-&gt;reg.temp, 0),<br>
&gt; +                 brw_imm_ud(_3DPRIM_TRISTRIP_REVERSE));<br>
&gt; +<br>
&gt; +         /* If so, then overwrite destination_indices_uw with the appropriate<br>
&gt; +          * reordering.<br>
&gt; +          */<br>
&gt; +         brw_MOV(p, destination_indices_uw,<br>
&gt; +                 brw_imm_v(key-&gt;pv_first ? 0x00010200    /* (0, 2, 1) */<br>
&gt; +                                         : 0x00020001)); /* (1, 0, 2) */<br>
&gt; +         brw_set_predicate_control(p, BRW_PREDICATE_NONE);<br>
&gt; +      }<br>
&gt; +      brw_ADD(p, c-&gt;reg.destination_indices,<br>
&gt; +              c-&gt;reg.destination_indices, get_element_ud(c-&gt;reg.SVBI, 0));<br>
&gt; +<br>
&gt;        /* For each vertex, generate code to output each varying using the<br>
&gt;         * appropriate binding table entry.<br>
&gt;         */<br>
&gt;        for (vertex = 0; vertex &lt; num_verts; ++vertex) {<br>
&gt; +         /* Set up the correct destination index for this vertex */<br>
&gt; +         brw_MOV(p, get_element_ud(c-&gt;reg.header, 5),<br>
&gt; +                 get_element_ud(c-&gt;reg.destination_indices, vertex));<br>
&gt; +<br>
&gt;           for (binding = 0; binding &lt; key-&gt;num_transform_feedback_bindings;<br>
&gt;                ++binding) {<br>
&gt;              unsigned char vert_result =<br>
&gt; @@ -398,15 +455,6 @@ gen6_sol_program(struct brw_gs_compile *c, struct brw_gs_prog_key *key,<br>
&gt;                            SURF_INDEX_SOL_BINDING(binding), /* binding_table_index */<br>
&gt;                            final_write); /* send_commit_msg */<br>
&gt;           }<br>
&gt; -<br>
&gt; -         /* If there are more vertices to output, increment the pointer so<br>
&gt; -          * that we will start outputting to the next location in the<br>
&gt; -          * transform feedback buffers.<br>
&gt; -          */<br>
&gt; -         if (vertex != num_verts - 1) {<br>
&gt; -            brw_ADD(p, get_element_ud(c-&gt;reg.header, 5),<br>
&gt; -                    get_element_ud(c-&gt;reg.header, 5), brw_imm_ud(1));<br>
&gt; -         }<br>
&gt;        }<br>
&gt;        brw_ENDIF(p);<br>
&gt;<br>
<br>
</div></div></blockquote></div><br>