[Mesa-dev] [PATCH] draw: fix clip test with NaNs

Brian Paul brianp at vmware.com
Thu Dec 17 10:13:51 PST 2015


On 12/17/2015 09:58 AM, sroland at vmware.com wrote:
> From: Roland Scheidegger <sroland at vmware.com>
>
> NaNs mean it should be clipped, otherwise the NaNs might get passed to the
> next stages (if clipping didn't happen for another reason already), which
> might cause all kind of problems.
> The llvm path got this right already (possibly by luck), but this isn't used
> when there's a gs active.
> Found by code inspection, verified with some hacked piglit test and some more
> hacked debug output.
> (Note the clipper can still itself incorrectly generate NaN and INF position
> values in its output prims (at least after w divide / viewport transform) even
> if the inputs weren't NaNs, if the position data of the vertices is
> "sufficiently bad".)
> ---
>   src/gallium/auxiliary/draw/draw_cliptest_tmp.h | 28 +++++++++++++-------------
>   src/gallium/auxiliary/draw/draw_llvm.c         |  4 ++++
>   2 files changed, 18 insertions(+), 14 deletions(-)
>
> diff --git a/src/gallium/auxiliary/draw/draw_cliptest_tmp.h b/src/gallium/auxiliary/draw/draw_cliptest_tmp.h
> index 779b237..d8866cd 100644
> --- a/src/gallium/auxiliary/draw/draw_cliptest_tmp.h
> +++ b/src/gallium/auxiliary/draw/draw_cliptest_tmp.h
> @@ -95,30 +95,31 @@ static boolean TAG(do_cliptest)( struct pt_post_vs *pvs,
>               out->pre_clip_pos[i] = position[i];
>            }
>
> +         /* Be careful with NaNs. Comparisons must be true for them. */
>            /* Do the hardwired planes first:
>             */
>            if (flags & DO_CLIP_XY_GUARD_BAND) {
> -            if (-0.50 * position[0] + position[3] < 0) mask |= (1<<0);
> -            if ( 0.50 * position[0] + position[3] < 0) mask |= (1<<1);
> -            if (-0.50 * position[1] + position[3] < 0) mask |= (1<<2);
> -            if ( 0.50 * position[1] + position[3] < 0) mask |= (1<<3);
> +            if (!(-0.50 * position[0] + position[3] >= 0)) mask |= (1<<0);
> +            if (!( 0.50 * position[0] + position[3] >= 0)) mask |= (1<<1);
> +            if (!(-0.50 * position[1] + position[3] >= 0)) mask |= (1<<2);
> +            if (!( 0.50 * position[1] + position[3] >= 0)) mask |= (1<<3);
>            }
>            else if (flags & DO_CLIP_XY) {
> -            if (-position[0] + position[3] < 0) mask |= (1<<0);
> -            if ( position[0] + position[3] < 0) mask |= (1<<1);
> -            if (-position[1] + position[3] < 0) mask |= (1<<2);
> -            if ( position[1] + position[3] < 0) mask |= (1<<3);
> +            if (!(-position[0] + position[3] >= 0)) mask |= (1<<0);
> +            if (!( position[0] + position[3] >= 0)) mask |= (1<<1);
> +            if (!(-position[1] + position[3] >= 0)) mask |= (1<<2);
> +            if (!( position[1] + position[3] >= 0)) mask |= (1<<3);
>            }
>
>            /* Clip Z planes according to full cube, half cube or none.
>             */
>            if (flags & DO_CLIP_FULL_Z) {
> -            if ( position[2] + position[3] < 0) mask |= (1<<4);
> -            if (-position[2] + position[3] < 0) mask |= (1<<5);
> +            if (!( position[2] + position[3] >= 0)) mask |= (1<<4);
> +            if (!(-position[2] + position[3] >= 0)) mask |= (1<<5);
>            }
>            else if (flags & DO_CLIP_HALF_Z) {
> -            if ( position[2]               < 0) mask |= (1<<4);
> -            if (-position[2] + position[3] < 0) mask |= (1<<5);
> +            if (!( position[2]               >= 0)) mask |= (1<<4);
> +            if (!(-position[2] + position[3] >= 0)) mask |= (1<<5);
>            }
>
>            if (flags & DO_CLIP_USER) {
> @@ -146,7 +147,7 @@ static boolean TAG(do_cliptest)( struct pt_post_vs *pvs,
>                     if (clipdist < 0 || util_is_inf_or_nan(clipdist))
>                        mask |= 1 << plane_idx;
>                  } else {
> -                  if (dot4(clipvertex, plane[plane_idx]) < 0)
> +                  if (!(dot4(clipvertex, plane[plane_idx]) >= 0))
>                        mask |= 1 << plane_idx;
>                  }
>               }
> @@ -192,7 +193,6 @@ static boolean TAG(do_cliptest)( struct pt_post_vs *pvs,
>
>         out = (struct vertex_header *)( (char *)out + info->stride );
>      }
> -
>      return need_pipeline != 0;
>   }
>
> diff --git a/src/gallium/auxiliary/draw/draw_llvm.c b/src/gallium/auxiliary/draw/draw_llvm.c
> index 8435991..dad523a 100644
> --- a/src/gallium/auxiliary/draw/draw_llvm.c
> +++ b/src/gallium/auxiliary/draw/draw_llvm.c
> @@ -1200,6 +1200,10 @@ generate_clipmask(struct draw_llvm *llvm,
>         cv_w = pos_w;
>      }
>
> +   /*
> +    * Be careful with the comparisons and NaNs (using llvm's unordered
> +    * comparisons here).
> +    */
>      /* Cliptest, for hardwired planes */
>      if (clip_xy) {
>         /* plane 1 */
>

Looks OK to me, but I'm not sure I understand what'll happen when we 
find a vertex with a NaN coordinate.  Does the whole triangle get 
culled?  Otherwise, what would be the result of computing the 
intersection point on the clip plane?

Reviewed-by: Brian Paul <brianp at vmware.com>



More information about the mesa-dev mailing list