From f23d54cfaaf79c2fab12593fea5982f918c948b2 Mon Sep 17 00:00:00 2001 From: Roland Scheidegger Date: Thu, 13 Apr 2023 20:06:36 +0200 Subject: [PATCH] llvmpipe: fix some corner cases with line rendering Some comparisons were wrong depending on swapped endpoints and the bottom_edge_rule (if the endpoint was exactly touching pixel center), hence the code assuming a line endpoint which should be drawn according to diamond exit rules would already be drawn (so not adjusting the endpoint) when in reality it was not, in which case the line would end up one pixel too short. Note that this is still not fully correct - the logic as such should be correct now, however these comparisons can give wrong results due to float math vs. fixed point planes (an endpoint very close to a pixel center might be exactly at pixel center in fixed point), but this should do for now. (Also, the logic is still completely wrong for state trackers not using half_pixel_center setting, but this is only really a concern for dx9 state tracker.) Reviewed-by: Brian Paul Part-of: --- src/gallium/drivers/llvmpipe/lp_setup_line.c | 47 +++++++++++++++++--- 1 file changed, 40 insertions(+), 7 deletions(-) diff --git a/src/gallium/drivers/llvmpipe/lp_setup_line.c b/src/gallium/drivers/llvmpipe/lp_setup_line.c index 2710f94a88a..371d899d755 100644 --- a/src/gallium/drivers/llvmpipe/lp_setup_line.c +++ b/src/gallium/drivers/llvmpipe/lp_setup_line.c @@ -409,8 +409,8 @@ try_setup_line(struct lp_setup_context *setup, } /* Are we already drawing start/end? */ - bool will_draw_start = sign(-x1diff) != sign(dx); - bool will_draw_end = (sign(x2diff) == sign(-dx)) || x2diff==0; + bool will_draw_start; + bool will_draw_end; /* interpolate using the preferred wide-lines formula */ info.dx *= 1.0f + dydx * dydx; @@ -421,23 +421,31 @@ try_setup_line(struct lp_setup_context *setup, const float (*temp)[4] = v1; v1 = v2; v2 = temp; - dx = -dx; + /* Otherwise shift planes appropriately */ + /* left edge */ + will_draw_start = x1diff <= 0.f; if (will_draw_start != draw_start) { x_offset_end = -x1diff - 0.5f; y_offset_end = x_offset_end * dydx; } + /* right edge */ + will_draw_end = x2diff > 0.f; if (will_draw_end != draw_end) { x_offset = -x2diff - 0.5f; y_offset = x_offset * dydx; } } else { /* Otherwise shift planes appropriately */ + /* right edge */ + will_draw_start = x1diff > 0.f; if (will_draw_start != draw_start) { x_offset = -x1diff + 0.5f; y_offset = x_offset * dydx; } + /* left edge */ + will_draw_end = x2diff <= 0.f; if (will_draw_end != draw_end) { x_offset_end = -x2diff + 0.5f; y_offset_end = x_offset_end * dydx; @@ -493,9 +501,15 @@ try_setup_line(struct lp_setup_context *setup, draw_end = (xintersect < 1.0f && xintersect >= 0.0f); } - /* Are we already drawing start/end? */ - bool will_draw_start = sign(y1diff) == sign(dy); - bool will_draw_end = (sign(-y2diff) == sign(dy)) || y2diff==0; + /* + * Are we already drawing start/end? + * FIXME: this needs to be done with fixed point arithmetic (otherwise + * the comparisons against zero are not mirroring what actually happens + * when rasterizing using the plane equations). + */ + + bool will_draw_start; + bool will_draw_end; /* interpolate using the preferred wide-lines formula */ info.dx = 0.0f; @@ -506,23 +520,42 @@ try_setup_line(struct lp_setup_context *setup, const float (*temp)[4] = v1; v1 = v2; v2 = temp; - dy = -dy; + + if (setup->bottom_edge_rule) { + will_draw_start = y1diff >= 0.f; + will_draw_end = y2diff < 0.f; + } else { + will_draw_start = y1diff > 0.f; + will_draw_end = y2diff <= 0.f; + } /* Otherwise shift planes appropriately */ + /* bottom edge */ if (will_draw_start != draw_start) { y_offset_end = -y1diff + 0.5f; x_offset_end = y_offset_end * dxdy; } + /* top edge */ if (will_draw_end != draw_end) { y_offset = -y2diff + 0.5f; x_offset = y_offset * dxdy; } } else { + if (setup->bottom_edge_rule) { + will_draw_start = y1diff < 0.f; + will_draw_end = y2diff >= 0.f; + } else { + will_draw_start = y1diff <= 0.f; + will_draw_end = y2diff > 0.f; + } + /* Otherwise shift planes appropriately */ + /* top edge */ if (will_draw_start != draw_start) { y_offset = -y1diff - 0.5f; x_offset = y_offset * dxdy; } + /* bottom edge */ if (will_draw_end != draw_end) { y_offset_end = -y2diff - 0.5f; x_offset_end = y_offset_end * dxdy;