Am 17.12.2015 um 20:22 schrieb Matt Turner: > On Thu, Dec 17, 2015 at 11:19 AM, Roland Scheidegger <srol...@vmware.com> > wrote: >> Am 17.12.2015 um 19:13 schrieb Brian Paul: >>> On 12/17/2015 09:58 AM, srol...@vmware.com wrote: >>>> From: Roland Scheidegger <srol...@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 <bri...@vmware.com> >>> >> >> If we set the clip mask bit when there's a NaN, this simply ensures >> we're entering the clip stage (and the clip stage will also actually >> perform clipping against the affected clip plane). >> We won't actually cull such a tri directly, but the math in the clip >> stage should ensure it will eventually be discarded. Because >> getclipdist() then should return a NaN too, which will cause the code to >> immediately return without emitting the tri (or any already generated >> tri due to clipping with other planes) immediately. As far as I can see, >> this logic should work reliably (the nans cannot disappear even if we >> performed some math on them due to clipping with other planes). >> There's more bugs in the clip stage but I don't quite understand it. >> Though I spotted some issue which could be problematic, there's some >> DIFFERENT_SIGNS logic (which is also used to avoid division by zero) >> which doesn't look bullet-proof. This is defined as: >> DIFFERENT_SIGNS(x, y) ((x) * (y) <= 0.0F && (x) - (y) != 0.0F) >> But for sufficiently small x and y (in the order of 2^-63) this will be >> true even if both x and y have the same sign (as the product would be >> zero). But there's probably more to it which causes it to generate bogus >> tris in the end... > > I changed the implementation of DIFFERENT_SIGNS in src/mesa/main/macros.h to > be > > return signbit(x) != signbit(y); > > a while ago. Perhaps you could just pull that into draw_pipe_clip.c? >
I'm not sure it's a good fit as it sounds like we really need the result to be false for negative zero / positive zero comparison. The existing code does that too (which is the x-y != 0 part). (Rather interestingly, the old definition in macros.h would actually have returned different values for this depending on USE_IEEE or not...) That said, the only user of the macro is in tnl/t_vb_cliptmp.h so I guess it actually would want a different definition than it now is too (the code is pretty much the same there as the one in draw) though I don't think this code there generaly handles "crazy" clip conditions right in any case. And I'd have to pull that macro into util code. Roland _______________________________________________ mesa-dev mailing list mesa-dev@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/mesa-dev