[Mesa-dev] [PATCH 2/3] draw/clip: don't emit so many empty triangles

Roland Scheidegger sroland at vmware.com
Thu Sep 19 17:17:45 PDT 2013


Am 19.09.2013 20:43, schrieb Zack Rusin:
> Compress empty triangles (don't emit more than one in a row) and
> never emit empty triangles if we already generated a triangle
> covering a non-null area. We can't skip all null-triangles
> because c_primitives expects ones that were generated from vertices
> exactly at the clipping-plane, to be emitted.
> 
> Signed-off-by: Zack Rusin <zackr at vmware.com>
> ---
>  src/gallium/auxiliary/draw/draw_pipe_clip.c | 39 +++++++++++++++++++++++++++++
>  1 file changed, 39 insertions(+)
> 
> diff --git a/src/gallium/auxiliary/draw/draw_pipe_clip.c b/src/gallium/auxiliary/draw/draw_pipe_clip.c
> index 0f90bfd..2d6df81 100644
> --- a/src/gallium/auxiliary/draw/draw_pipe_clip.c
> +++ b/src/gallium/auxiliary/draw/draw_pipe_clip.c
> @@ -209,6 +209,29 @@ static void interp( const struct clip_stage *clip,
>     }
>  }
>  
> +/**
> + * Checks whether the specifed triangle is empty and if it is returns
specified

> + * true, otherwise returns false.
> + * Triangle is considered null/empty if it's area is qual to zero.
equal



> + */
> +static INLINE boolean
> +is_tri_null(struct draw_context *draw, const struct prim_header *header)
> +{
> +   const unsigned pos_attr = draw_current_shader_position_output(draw);
> +   float x1 = header->v[1]->data[pos_attr][0] - header->v[0]->data[pos_attr][0];
> +   float y1 = header->v[1]->data[pos_attr][1] - header->v[0]->data[pos_attr][1];
> +   float z1 = header->v[1]->data[pos_attr][2] - header->v[0]->data[pos_attr][2];
> +
> +   float x2 = header->v[2]->data[pos_attr][0] - header->v[0]->data[pos_attr][0];
> +   float y2 = header->v[2]->data[pos_attr][1] - header->v[0]->data[pos_attr][1];
> +   float z2 = header->v[2]->data[pos_attr][2] - header->v[0]->data[pos_attr][2];
> +
> +   float vx = y1 * z2 - z1 * y2;
> +   float vy = x1 * z2 - z1 * x2;
> +   float vz = x1 * y2 - y1 * x2;
> +
> +   return (vx*vx  + vy*vy + vz*vz) == 0.f;
> +}

Hmm I think the usual calculation for area would be:

   dx01 = x[0] - x[1];
   dy01 = y[0] - y[1];

   dx20 = x[2] - x[0];
   dy20 = y[2] - y[0];

   area = dx01 * dy20 - dx20 * dy01;

Do you really need to factor in z for figuring out if the area is null
here? In other words I'm wondering if the ordinary face culling stage
wouldn't just do the job if enabled (as even without face culling it
will calculate this area and toss out the prim in case it's zero).
I guess though the problem is that cull stage is _after_ clip.


>  
>  /**
>   * Emit a post-clip polygon to the next pipeline stage.  The polygon
> @@ -223,6 +246,8 @@ static void emit_poly( struct draw_stage *stage,
>     struct prim_header header;
>     unsigned i;
>     ushort edge_first, edge_middle, edge_last;
> +   boolean last_tri_was_null = FALSE;
> +   boolean tri_was_not_null = FALSE;
>  
>     if (stage->draw->rasterizer->flatshade_first) {
>        edge_first  = DRAW_PIPE_EDGE_FLAG_0;
> @@ -244,6 +269,7 @@ static void emit_poly( struct draw_stage *stage,
>     header.pad = 0;
>  
>     for (i = 2; i < n; i++, header.flags = edge_middle) {
> +      boolean tri_null;
>        /* order the triangle verts to respect the provoking vertex mode */
>        if (stage->draw->rasterizer->flatshade_first) {
>           header.v[0] = inlist[0];  /* the provoking vertex */
> @@ -256,6 +282,19 @@ static void emit_poly( struct draw_stage *stage,
>           header.v[2] = inlist[0];  /* the provoking vertex */
>        }
>  
> +      tri_null = is_tri_null(stage->draw, &header);
> +      /* If we generated a triangle with an area, aka. non-null triangle, 
> +       * or if the previous triangle was also null then skip all subsequent
> +       * null triangles */
> +      if ((tri_was_not_null && tri_null) || (last_tri_was_null && tri_null)) {
> +         last_tri_was_null = tri_null;
> +         continue;
> +      }
> +      last_tri_was_null = tri_null;
> +      if (!tri_null) {
> +         tri_was_not_null = TRUE;
> +      }
> +
>        if (!edgeflags[i-1]) {
>           header.flags &= ~edge_middle;
>        }
> 

I can't help but thinking we're doing something slightly wrong in the
draw pipeline. There's _no way_ real hw has to bend over backwards that
much to figure out something like that, and hence we shouldn't have to
neither. Unfortunately I can't see HOW it should work really (clipping
is friggin black magic, took even intel like 3 chipsets (not just
revisions) to iron out the clipping bugs after all too...
So I guess whatever works is ok.

Roland


More information about the mesa-dev mailing list