[Mesa-dev] [PATCH] draw: fix infinite loop in line stippling

Jose Fonseca jfonseca at vmware.com
Fri Nov 23 15:00:16 UTC 2018


On 23/11/2018 01:34, sroland at vmware.com wrote:
> From: Roland Scheidegger <sroland at vmware.com>
> 
> The calculated length of a line may be infinite, if the coords we
> get are bogus. This leads to an infinite loop in line stippling.
> To prevent this test for this explicitly (although technically
> on at least x86 sse it would actually work without the explicit
> test, as long as we use the int-converted length value).
> While here also get rid of some always-true condition.
> 
> Note this does not actually solve the root cause, which is that
> the coords we receive are bogus after clipping. This seems a difficult
> problem to solve. One issue is that due to float arithmetic, clip w
> may become 0 after clipping if the incoming geometry is
> "sufficiently degenerate", hence x/y/z ndc (and window) coords will
> be all inf (or nan). Even with w not quite 0, I believe it's possible
> we produce values which are actually outside the view volume.
> (Also, x=y=z=w=0 coords in clipspace would be not considered subject
> to clipping, and similarly result in all NaN coords.) We just hope for
> now other draw stages (and rasterizers) can handle those relatively
> safely (llvmpipe itself should be sort of robust against this, certainly
> converstion to fixed point will produce garbage, it might fail a couple
> assertions but should neither hang nor crash otherwise).
> ---
>   .../auxiliary/draw/draw_pipe_stipple.c        | 26 +++++++++++--------
>   1 file changed, 15 insertions(+), 11 deletions(-)
> 
> diff --git a/src/gallium/auxiliary/draw/draw_pipe_stipple.c b/src/gallium/auxiliary/draw/draw_pipe_stipple.c
> index d30572cc61..386b7649e4 100644
> --- a/src/gallium/auxiliary/draw/draw_pipe_stipple.c
> +++ b/src/gallium/auxiliary/draw/draw_pipe_stipple.c
> @@ -48,8 +48,8 @@
>   struct stipple_stage {
>      struct draw_stage stage;
>      float counter;
> -   uint pattern;
> -   uint factor;
> +   ushort pattern;
> +   ushort factor;
>      bool smooth;
>   };
>   
> @@ -110,7 +110,7 @@ emit_segment(struct draw_stage *stage, struct prim_header *header,
>   
>   
>   static inline bool
> -stipple_test(int counter, ushort pattern, int factor)
> +stipple_test(int counter, ushort pattern, ushort factor)
>   {
>      int b = (counter / factor) & 0xf;
>      return !!((1 << b) & pattern);
> @@ -136,6 +136,10 @@ stipple_line(struct draw_stage *stage, struct prim_header *header)
>   
>      float length;
>      int i;
> +   int intlength;
> +
> +   if (header->flags & DRAW_PIPE_RESET_STIPPLE)
> +      stipple->counter = 0;
>   
>      if (stipple->smooth) {
>         float dx = x1 - x0;
> @@ -147,21 +151,21 @@ stipple_line(struct draw_stage *stage, struct prim_header *header)
>         length = MAX2(dx, dy);
>      }
>   
> -   if (header->flags & DRAW_PIPE_RESET_STIPPLE)
> -      stipple->counter = 0;
> +   if (util_is_inf_or_nan(length))
> +      intlength = 0;
> +   else
> +      intlength = ceilf(length);
>   
>      /* XXX ToDo: instead of iterating pixel-by-pixel, use a look-up table.
>       */
> -   for (i = 0; i < length; i++) {
> +   for (i = 0; i < intlength; i++) {
>         bool result = stipple_test((int)stipple->counter + i,
> -                                 (ushort)stipple->pattern, stipple->factor);
> +                                 stipple->pattern, stipple->factor);
>         if (result != state) {
>            /* changing from "off" to "on" or vice versa */
>            if (state) {
> -            if (start != i) {
> -               /* finishing an "on" segment */
> -               emit_segment(stage, header, start / length, i / length);
> -            }
> +            /* finishing an "on" segment */
> +            emit_segment(stage, header, start / length, i / length);
>            }
>            else {
>               /* starting an "on" segment */
> 

Reviewed-by: Jose Fonseca <jfonseca at vmware.com>


More information about the mesa-dev mailing list