[Mesa-dev,17/37] i965/gen6/gs: Implement geometry shaders for outputs other than points.

Submitted by Iago Toral Quiroga on Aug. 14, 2014, 11:11 a.m.

Details

Message ID 1408014729-12708-18-git-send-email-itoral@igalia.com
State Accepted
Headers show

Not browsing as part of any series.

Commit Message

Iago Toral Quiroga Aug. 14, 2014, 11:11 a.m.
---
 src/mesa/drivers/dri/i965/gen6_gs_visitor.cpp | 72 ++++++++++++++++++++++++---
 src/mesa/drivers/dri/i965/gen6_gs_visitor.h   |  2 +
 2 files changed, 67 insertions(+), 7 deletions(-)

Patch hide | download patch | download mbox

diff --git a/src/mesa/drivers/dri/i965/gen6_gs_visitor.cpp b/src/mesa/drivers/dri/i965/gen6_gs_visitor.cpp
index b78c55e..5123bd7 100644
--- a/src/mesa/drivers/dri/i965/gen6_gs_visitor.cpp
+++ b/src/mesa/drivers/dri/i965/gen6_gs_visitor.cpp
@@ -79,6 +79,21 @@  gen6_gs_visitor::emit_prolog()
     * and URB_WRITE messages.
     */
    this->temp = src_reg(this, glsl_type::uint_type);
+
+   /* This will be used to know when we are processing the first vertex of
+    * a primitive. We will set this to URB_WRITE_PRIM_START only when we know
+    * that we are processing the first vertex in the primitive and to zero
+    * otherwise. This way we can use its value directly in the URB write
+    * headers.
+    */
+   this->first_vertex = src_reg(this, glsl_type::uint_type);
+   emit(MOV(dst_reg(this->first_vertex), URB_WRITE_PRIM_START));
+
+   /* The FF_SYNC message requires to know the number of primitives generated,
+    * so keep a counter for this.
+    */
+   this->prim_count = src_reg(this, glsl_type::uint_type);
+   emit(MOV(dst_reg(this->prim_count), 0u));
 }
 
 void
@@ -109,18 +124,26 @@  gen6_gs_visitor::visit(ir_emit_vertex *)
                   this->vertex_output_offset, 1u));
       }
 
-      /* Now buffer flags for this vertex (we only support point output
-       * for now).
-       */
+      /* Now buffer flags for this vertex */
       dst_reg dst(this->vertex_output);
       dst.reladdr = ralloc(mem_ctx, src_reg);
       memcpy(dst.reladdr, &this->vertex_output_offset, sizeof(src_reg));
-      /* If we are outputting points, then every vertex has PrimStart and
-       * PrimEnd set.
-       */
       if (c->gp->program.OutputType == GL_POINTS) {
+         /* If we are outputting points, then every vertex has PrimStart and
+          * PrimEnd set.
+          */
          emit(MOV(dst, (_3DPRIM_POINTLIST << URB_WRITE_PRIM_TYPE_SHIFT) |
                   URB_WRITE_PRIM_START | URB_WRITE_PRIM_END));
+         emit(ADD(dst_reg(this->prim_count), this->prim_count, 1u));
+      } else {
+         /* Otherwise, we can only set the PrimStart flag, which we have stored
+          * in the first_vertex register. We will have to wait until we execute
+          * EndPrimitive() or we end the thread to set the PrimEnd flag on a
+          * vertex.
+          */
+         emit(OR(dst, this->first_vertex,
+                 (c->prog_data.output_topology << URB_WRITE_PRIM_TYPE_SHIFT)));
+         emit(MOV(dst_reg(this->first_vertex), 0u));
       }
       emit(ADD(dst_reg(this->vertex_output_offset),
                this->vertex_output_offset, 1u));
@@ -140,6 +163,41 @@  gen6_gs_visitor::visit(ir_end_primitive *)
     */
    if (c->gp->program.OutputType == GL_POINTS)
       return;
+
+   /* Otheriwse we know that the last vertex we have processed was the last
+    * vertex in the primitive and we need to set its PrimEnd flag, so do this
+    * unless we haven't emitted that vertex at all.
+    *
+    * Notice that we have already incremented vertex_count when we processed
+    * the last emit_vertex, so we need to take that into account in the
+    * comparison below (hence the num_output_vertices + 1 in the comparison
+    * below).
+    */
+   unsigned num_output_vertices = c->gp->program.VerticesOut;
+   emit(CMP(dst_null_d(), this->vertex_count, src_reg(num_output_vertices + 1),
+            BRW_CONDITIONAL_L));
+   emit(IF(BRW_PREDICATE_NORMAL));
+   {
+      /* vertex_output_offset is already pointing at the first entry of the
+       * next vertex. So subtract 1 to modify the flags for the previous
+       * vertex.
+       */
+      src_reg offset(this, glsl_type::uint_type);
+      emit(ADD(dst_reg(offset), this->vertex_output_offset, brw_imm_d(-1)));
+
+      src_reg dst(this->vertex_output);
+      dst.reladdr = ralloc(mem_ctx, src_reg);
+      memcpy(dst.reladdr, &offset, sizeof(src_reg));
+
+      emit(OR(dst_reg(dst), dst, URB_WRITE_PRIM_END));
+      emit(ADD(dst_reg(this->prim_count), this->prim_count, 1u));
+
+      /* Set the first vertex flag to indicate that the next vertex will start
+       * a primitive.
+       */
+      emit(MOV(dst_reg(this->first_vertex), URB_WRITE_PRIM_START));
+   }
+   emit(BRW_OPCODE_ENDIF);
 }
 
 void
@@ -234,7 +292,7 @@  gen6_gs_visitor::emit_thread_end()
    /* Issue the FF_SYNC message and obtain the initial VUE handle. */
    this->current_annotation = "gen6 thread end: ff_sync";
    emit(GS_OPCODE_FF_SYNC,
-        dst_reg(MRF, base_mrf), this->temp, this->vertex_count);
+        dst_reg(MRF, base_mrf), this->temp, this->prim_count);
 
    /* Loop over all buffered vertices and emit URB write messages */
    this->current_annotation = "gen6 thread end: urb writes init";
diff --git a/src/mesa/drivers/dri/i965/gen6_gs_visitor.h b/src/mesa/drivers/dri/i965/gen6_gs_visitor.h
index 6dd3a19..68fe88d 100644
--- a/src/mesa/drivers/dri/i965/gen6_gs_visitor.h
+++ b/src/mesa/drivers/dri/i965/gen6_gs_visitor.h
@@ -58,6 +58,8 @@  private:
    src_reg vertex_output;
    src_reg vertex_output_offset;
    src_reg temp;
+   src_reg first_vertex;
+   src_reg prim_count;
 };
 
 } /* namespace brw */

Comments

On Thu, Aug 14, 2014 at 4:11 AM, Iago Toral Quiroga <itoral@igalia.com> wrote:
> ---
>  src/mesa/drivers/dri/i965/gen6_gs_visitor.cpp | 72 ++++++++++++++++++++++++---
>  src/mesa/drivers/dri/i965/gen6_gs_visitor.h   |  2 +
>  2 files changed, 67 insertions(+), 7 deletions(-)
>
> diff --git a/src/mesa/drivers/dri/i965/gen6_gs_visitor.cpp b/src/mesa/drivers/dri/i965/gen6_gs_visitor.cpp
> index b78c55e..5123bd7 100644
> --- a/src/mesa/drivers/dri/i965/gen6_gs_visitor.cpp
> +++ b/src/mesa/drivers/dri/i965/gen6_gs_visitor.cpp
> @@ -79,6 +79,21 @@ gen6_gs_visitor::emit_prolog()
>      * and URB_WRITE messages.
>      */
>     this->temp = src_reg(this, glsl_type::uint_type);
> +
> +   /* This will be used to know when we are processing the first vertex of
> +    * a primitive. We will set this to URB_WRITE_PRIM_START only when we know
> +    * that we are processing the first vertex in the primitive and to zero
> +    * otherwise. This way we can use its value directly in the URB write
> +    * headers.
> +    */
> +   this->first_vertex = src_reg(this, glsl_type::uint_type);
> +   emit(MOV(dst_reg(this->first_vertex), URB_WRITE_PRIM_START));
> +
> +   /* The FF_SYNC message requires to know the number of primitives generated,
> +    * so keep a counter for this.
> +    */
> +   this->prim_count = src_reg(this, glsl_type::uint_type);
> +   emit(MOV(dst_reg(this->prim_count), 0u));
>  }
>
>  void
> @@ -109,18 +124,26 @@ gen6_gs_visitor::visit(ir_emit_vertex *)
>                    this->vertex_output_offset, 1u));
>        }
>
> -      /* Now buffer flags for this vertex (we only support point output
> -       * for now).
> -       */
> +      /* Now buffer flags for this vertex */
>        dst_reg dst(this->vertex_output);
>        dst.reladdr = ralloc(mem_ctx, src_reg);
>        memcpy(dst.reladdr, &this->vertex_output_offset, sizeof(src_reg));
> -      /* If we are outputting points, then every vertex has PrimStart and
> -       * PrimEnd set.
> -       */
>        if (c->gp->program.OutputType == GL_POINTS) {
> +         /* If we are outputting points, then every vertex has PrimStart and
> +          * PrimEnd set.
> +          */
>           emit(MOV(dst, (_3DPRIM_POINTLIST << URB_WRITE_PRIM_TYPE_SHIFT) |
>                    URB_WRITE_PRIM_START | URB_WRITE_PRIM_END));
> +         emit(ADD(dst_reg(this->prim_count), this->prim_count, 1u));
> +      } else {
> +         /* Otherwise, we can only set the PrimStart flag, which we have stored
> +          * in the first_vertex register. We will have to wait until we execute
> +          * EndPrimitive() or we end the thread to set the PrimEnd flag on a
> +          * vertex.
> +          */
> +         emit(OR(dst, this->first_vertex,
> +                 (c->prog_data.output_topology << URB_WRITE_PRIM_TYPE_SHIFT)));
> +         emit(MOV(dst_reg(this->first_vertex), 0u));
>        }
>        emit(ADD(dst_reg(this->vertex_output_offset),
>                 this->vertex_output_offset, 1u));
> @@ -140,6 +163,41 @@ gen6_gs_visitor::visit(ir_end_primitive *)
>      */
>     if (c->gp->program.OutputType == GL_POINTS)
>        return;
> +
> +   /* Otheriwse we know that the last vertex we have processed was the last

Typo.

16 & 17
Reviewed-by: Jordan Justen <jordan.l.justen@intel.com>

> +    * vertex in the primitive and we need to set its PrimEnd flag, so do this
> +    * unless we haven't emitted that vertex at all.
> +    *
> +    * Notice that we have already incremented vertex_count when we processed
> +    * the last emit_vertex, so we need to take that into account in the
> +    * comparison below (hence the num_output_vertices + 1 in the comparison
> +    * below).
> +    */
> +   unsigned num_output_vertices = c->gp->program.VerticesOut;
> +   emit(CMP(dst_null_d(), this->vertex_count, src_reg(num_output_vertices + 1),
> +            BRW_CONDITIONAL_L));
> +   emit(IF(BRW_PREDICATE_NORMAL));
> +   {
> +      /* vertex_output_offset is already pointing at the first entry of the
> +       * next vertex. So subtract 1 to modify the flags for the previous
> +       * vertex.
> +       */
> +      src_reg offset(this, glsl_type::uint_type);
> +      emit(ADD(dst_reg(offset), this->vertex_output_offset, brw_imm_d(-1)));
> +
> +      src_reg dst(this->vertex_output);
> +      dst.reladdr = ralloc(mem_ctx, src_reg);
> +      memcpy(dst.reladdr, &offset, sizeof(src_reg));
> +
> +      emit(OR(dst_reg(dst), dst, URB_WRITE_PRIM_END));
> +      emit(ADD(dst_reg(this->prim_count), this->prim_count, 1u));
> +
> +      /* Set the first vertex flag to indicate that the next vertex will start
> +       * a primitive.
> +       */
> +      emit(MOV(dst_reg(this->first_vertex), URB_WRITE_PRIM_START));
> +   }
> +   emit(BRW_OPCODE_ENDIF);
>  }
>
>  void
> @@ -234,7 +292,7 @@ gen6_gs_visitor::emit_thread_end()
>     /* Issue the FF_SYNC message and obtain the initial VUE handle. */
>     this->current_annotation = "gen6 thread end: ff_sync";
>     emit(GS_OPCODE_FF_SYNC,
> -        dst_reg(MRF, base_mrf), this->temp, this->vertex_count);
> +        dst_reg(MRF, base_mrf), this->temp, this->prim_count);
>
>     /* Loop over all buffered vertices and emit URB write messages */
>     this->current_annotation = "gen6 thread end: urb writes init";
> diff --git a/src/mesa/drivers/dri/i965/gen6_gs_visitor.h b/src/mesa/drivers/dri/i965/gen6_gs_visitor.h
> index 6dd3a19..68fe88d 100644
> --- a/src/mesa/drivers/dri/i965/gen6_gs_visitor.h
> +++ b/src/mesa/drivers/dri/i965/gen6_gs_visitor.h
> @@ -58,6 +58,8 @@ private:
>     src_reg vertex_output;
>     src_reg vertex_output_offset;
>     src_reg temp;
> +   src_reg first_vertex;
> +   src_reg prim_count;
>  };
>
>  } /* namespace brw */
> --
> 1.9.1
>
> _______________________________________________
> mesa-dev mailing list
> mesa-dev@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/mesa-dev