draw: handle nan clipdistance
authorZack Rusin <zackr@vmware.com>
Thu, 15 Aug 2013 17:10:22 +0000 (13:10 -0400)
committerZack Rusin <zackr@vmware.com>
Thu, 15 Aug 2013 20:26:32 +0000 (16:26 -0400)
If clipdistance for one of the vertices is nan (or inf) then the
entire primitive should be discarded.

Signed-off-by: Zack Rusin <zackr@vmware.com>
Reviewed-by: Roland Scheidegger <sroland@vmware.com>
src/gallium/auxiliary/draw/draw_cliptest_tmp.h
src/gallium/auxiliary/draw/draw_llvm.c
src/gallium/auxiliary/draw/draw_pipe_clip.c
src/gallium/auxiliary/gallivm/lp_bld_arit.c
src/gallium/auxiliary/gallivm/lp_bld_arit.h

index e4500dbd971d7137692e1b6ebd0d9262899a0de4..fc548102f2b894628715b4daf315f894cc3ef828 100644 (file)
@@ -140,7 +140,7 @@ static boolean TAG(do_cliptest)( struct pt_post_vs *pvs,
                      clipdist = out->data[cd[0]][i];
                   else
                      clipdist = out->data[cd[1]][i-4];
-                  if (clipdist < 0)
+                  if (clipdist < 0 || util_is_inf_or_nan(clipdist))
                      mask |= 1 << plane_idx;
                } else {
                   if (dot4(clipvertex, plane[plane_idx]) < 0)
index 84e33926a2bcb408950f3a469c37e44f065c9f6d..820d6b0013e1c7f170c0b09876cccdd935d3189d 100644 (file)
@@ -1261,6 +1261,7 @@ generate_clipmask(struct draw_llvm *llvm,
    if (clip_user) {
       LLVMValueRef planes_ptr = draw_jit_context_planes(gallivm, context_ptr);
       LLVMValueRef indices[3];
+      LLVMValueRef is_nan_or_inf;
 
       /* userclip planes */
       while (ucp_enable) {
@@ -1280,6 +1281,8 @@ generate_clipmask(struct draw_llvm *llvm,
                clipdist = LLVMBuildLoad(builder, outputs[cd[1]][i-4], "");
             }
             test = lp_build_compare(gallivm, f32_type, PIPE_FUNC_GREATER, zero, clipdist);
+            is_nan_or_inf = lp_build_is_inf_or_nan(gallivm, vs_type, clipdist);
+            test = LLVMBuildOr(builder, test, is_nan_or_inf, "");
             temp = lp_build_const_int_vec(gallivm, i32_type, 1 << plane_idx);
             test = LLVMBuildAnd(builder, test, temp, "");
             mask = LLVMBuildOr(builder, mask, test, "");
index b76e9a501ac879335254ac22d570141207c67a01..0f90bfdff088cb4051944011ad20b357f71a75dd 100644 (file)
@@ -104,7 +104,7 @@ static void interp_attr( float dst[4],
                         float t,
                         const float in[4],
                         const float out[4] )
-{  
+{
    dst[0] = LINTERP( t, out[0], in[0] );
    dst[1] = LINTERP( t, out[1], in[1] );
    dst[2] = LINTERP( t, out[2], in[2] );
@@ -380,6 +380,9 @@ do_clip_tri( struct draw_stage *stage,
       dp_prev = getclipdist(clipper, vert_prev, plane_idx);
       clipmask &= ~(1<<plane_idx);
 
+      if (util_is_inf_or_nan(dp_prev))
+         return; //discard nan
+
       assert(n < MAX_CLIPPED_VERTICES);
       if (n >= MAX_CLIPPED_VERTICES)
          return;
@@ -392,6 +395,9 @@ do_clip_tri( struct draw_stage *stage,
 
          float dp = getclipdist(clipper, vert, plane_idx);
 
+         if (util_is_inf_or_nan(dp))
+            return; //discard nan
+
         if (!IS_NEGATIVE(dp_prev)) {
             assert(outcount < MAX_CLIPPED_VERTICES);
             if (outcount >= MAX_CLIPPED_VERTICES)
@@ -522,6 +528,9 @@ do_clip_line( struct draw_stage *stage,
       const float dp0 = getclipdist(clipper, v0, plane_idx);
       const float dp1 = getclipdist(clipper, v1, plane_idx);
 
+      if (util_is_inf_or_nan(dp0) || util_is_inf_or_nan(dp1))
+         return; //discard nan
+
       if (dp1 < 0.0F) {
         float t = dp1 / (dp1 - dp0);
          t1 = MAX2(t1, t);
@@ -574,7 +583,7 @@ clip_line( struct draw_stage *stage,
 {
    unsigned clipmask = (header->v[0]->clipmask | 
                         header->v[1]->clipmask);
-   
+
    if (clipmask == 0) {
       /* no clipping needed */
       stage->next->line( stage->next, header );
@@ -594,7 +603,7 @@ clip_tri( struct draw_stage *stage,
    unsigned clipmask = (header->v[0]->clipmask | 
                         header->v[1]->clipmask | 
                         header->v[2]->clipmask);
-   
+
    if (clipmask == 0) {
       /* no clipping needed */
       stage->next->tri( stage->next, header );
index 98409c3be8620371d903e279792f5567d9ba0b5f..f7daabc639e3991ab8bcb00bd795c900c90d312c 100644 (file)
@@ -3671,3 +3671,29 @@ lp_build_isfinite(struct lp_build_context *bld,
    return lp_build_compare(bld->gallivm, int_type, PIPE_FUNC_NOTEQUAL,
                            intx, infornan32);
 }
+
+/*
+ * Returns true if the number is nan or inf and false otherwise.
+ * The input has to be a floating point vector.
+ */
+LLVMValueRef
+lp_build_is_inf_or_nan(struct gallivm_state *gallivm,
+                       const struct lp_type type,
+                       LLVMValueRef x)
+{
+   LLVMBuilderRef builder = gallivm->builder;
+   struct lp_type int_type = lp_int_type(type);
+   LLVMValueRef const0 = lp_build_const_int_vec(gallivm, int_type,
+                                                0x7f800000);
+   LLVMValueRef ret;
+
+   assert(type.floating);
+
+   ret = LLVMBuildBitCast(builder, x, lp_build_vec_type(gallivm, int_type), "");
+   ret = LLVMBuildAnd(builder, ret, const0, "");
+   ret = lp_build_compare(gallivm, int_type, PIPE_FUNC_EQUAL,
+                          ret, const0);
+
+   return ret;
+}
+
index 35119d18f7b05219e0903d697a0a76846aa3bdd5..d98025e42e3a89322d9b4ab66a1bf4e102cd9ac8 100644 (file)
@@ -42,6 +42,7 @@
 
 struct lp_type;
 struct lp_build_context;
+struct gallivm_state;
 
 
 /**
@@ -353,4 +354,9 @@ lp_build_isfinite(struct lp_build_context *bld,
                   LLVMValueRef x);
 
 
+LLVMValueRef
+lp_build_is_inf_or_nan(struct gallivm_state *gallivm,
+                       const struct lp_type type,
+                       LLVMValueRef x);
+
 #endif /* !LP_BLD_ARIT_H */