mirror of
https://github.com/italicsjenga/vello.git
synced 2025-01-10 20:51:29 +11:00
path_coarse.comp: fix intersection inconsistencies, take 2
The previous attempt to fix inconsistent intersections because of floating
point inaccuracy[0] missed two cases.
The first case is that for top intersections with the very first row would fail
the test
tag == PathSeg_FillCubic && y > y0 && xbackdrop < bbox.z
In particular, y is not larger than y0 when y0 has been clipped to 0.
Fix that by re-introducing the min(p0.y, p1.y) < tile_y0 check that does work
and is just as consistent. Add similar check, min(p0.x, p1.x) < tile_x0, for
deciding when to clip the segment to the left edge (but keep consistent xray check
for deciding left edge *intersections*).
The second case is that the tracking left intersections in the [xray, next_xray]
range of tiles may fail when next_xray is forced to last_xray, the final xray value.
Fix that case by computing next_xray explicitly, before looping over the
x tiles. The code is now much simpler.
Finally, ensure that xx0 and xx1 doesn't overflow the allocated number of tiles
by clamping them *after* setting them. Adjust xx0 to include xray, just as xx1
is adjusted; I haven't seen corruption without it, but it's not obvious xx0
always includes xray.
While here, replace a "+=" on a guaranteed zero value to just "=".
Updates #23
[0] 29cfb8b63e
Signed-off-by: Elias Naur <mail@eliasnaur.com>
This commit is contained in:
parent
14e922e17e
commit
a2a2d12c5d
|
@ -198,21 +198,31 @@ void main() {
|
||||||
last_xray = tmp;
|
last_xray = tmp;
|
||||||
}
|
}
|
||||||
for (int y = y0; y < y1; y++) {
|
for (int y = y0; y < y1; y++) {
|
||||||
|
float tile_y0 = float(y * TILE_HEIGHT_PX);
|
||||||
int xbackdrop = max(xray + 1, bbox.x);
|
int xbackdrop = max(xray + 1, bbox.x);
|
||||||
if (tag == PathSeg_FillCubic && y > y0 && xbackdrop < bbox.z) {
|
if (tag == PathSeg_FillCubic && min(p0.y, p1.y) < tile_y0 && xbackdrop < bbox.z) {
|
||||||
int backdrop = p1.y < p0.y ? 1 : -1;
|
int backdrop = p1.y < p0.y ? 1 : -1;
|
||||||
TileRef tile_ref = Tile_index(path.tiles, uint(base + xbackdrop));
|
TileRef tile_ref = Tile_index(path.tiles, uint(base + xbackdrop));
|
||||||
uint tile_el = tile_ref.offset >> 2;
|
uint tile_el = tile_ref.offset >> 2;
|
||||||
atomicAdd(tile[tile_el + 1], backdrop);
|
atomicAdd(tile[tile_el + 1], backdrop);
|
||||||
}
|
}
|
||||||
|
|
||||||
int xx0 = clamp(int(floor(xc - c)), x0, x1);
|
// next_xray is the xray for the next scanline; the line segment intersects
|
||||||
int xx1 = clamp(int(ceil(xc + c)), x0, x1);
|
// all tiles between xray and next_xray.
|
||||||
xx1 = max(xx1, xray + 1);
|
int next_xray = last_xray;
|
||||||
|
if (y < y1 - 1) {
|
||||||
|
float tile_y1 = float((y + 1) * TILE_HEIGHT_PX);
|
||||||
|
float x_edge = mix(p0.x, p1.x, (tile_y1 - p0.y) / dy);
|
||||||
|
next_xray = int(floor(x_edge*SX));
|
||||||
|
}
|
||||||
|
|
||||||
|
int min_xray = min(xray, next_xray);
|
||||||
|
int max_xray = max(xray, next_xray);
|
||||||
|
int xx0 = min(int(floor(xc - c)), min_xray);
|
||||||
|
int xx1 = max(int(ceil(xc + c)), max_xray + 1);
|
||||||
|
xx0 = clamp(xx0, x0, x1);
|
||||||
|
xx1 = clamp(xx1, x0, x1);
|
||||||
|
|
||||||
// next_xray is the xray for the next scanline; it is derived
|
|
||||||
// by left edge intersections computed below.
|
|
||||||
int next_xray = xray;
|
|
||||||
for (int x = xx0; x < xx1; x++) {
|
for (int x = xx0; x < xx1; x++) {
|
||||||
float tile_x0 = float(x * TILE_WIDTH_PX);
|
float tile_x0 = float(x * TILE_WIDTH_PX);
|
||||||
TileRef tile_ref = Tile_index(path.tiles, uint(base + x));
|
TileRef tile_ref = Tile_index(path.tiles, uint(base + x));
|
||||||
|
@ -222,10 +232,8 @@ void main() {
|
||||||
tile_seg.vector = p1 - p0;
|
tile_seg.vector = p1 - p0;
|
||||||
float y_edge = 0.0;
|
float y_edge = 0.0;
|
||||||
if (tag == PathSeg_FillCubic) {
|
if (tag == PathSeg_FillCubic) {
|
||||||
float tile_y0 = float(y * TILE_HEIGHT_PX);
|
|
||||||
y_edge = mix(p0.y, p1.y, (tile_x0 - p0.x) / dx);
|
y_edge = mix(p0.y, p1.y, (tile_x0 - p0.x) / dx);
|
||||||
if (min(p0.x, p1.x) < tile_x0 && y_edge >= tile_y0 && y_edge < tile_y0 + TILE_HEIGHT_PX) {
|
if (min(p0.x, p1.x) < tile_x0) {
|
||||||
// Left edge intersection.
|
|
||||||
vec2 p = vec2(tile_x0, y_edge);
|
vec2 p = vec2(tile_x0, y_edge);
|
||||||
if (p0.x > p1.x) {
|
if (p0.x > p1.x) {
|
||||||
tile_seg.vector = p - p0;
|
tile_seg.vector = p - p0;
|
||||||
|
@ -236,22 +244,11 @@ void main() {
|
||||||
// kernel4 uses sign(vector.x) for the sign of the intersection backdrop.
|
// kernel4 uses sign(vector.x) for the sign of the intersection backdrop.
|
||||||
// Nudge zeroes towards the intended sign.
|
// Nudge zeroes towards the intended sign.
|
||||||
if (tile_seg.vector.x == 0) {
|
if (tile_seg.vector.x == 0) {
|
||||||
tile_seg.vector.x += sign(p1.x - p0.x)*1e-9;
|
tile_seg.vector.x = sign(p1.x - p0.x)*1e-9;
|
||||||
}
|
|
||||||
// Move next_xray consistently with previous intersections.
|
|
||||||
if (x > next_xray && next_xray >= xray) {
|
|
||||||
next_xray = x;
|
|
||||||
} else if (x <= next_xray && next_xray <= xray) {
|
|
||||||
next_xray = x - 1;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Force last xray on the last scanline for consistency with later
|
if (x <= min_xray || max_xray < x) {
|
||||||
// line segments.
|
// Reject inconsistent intersections.
|
||||||
if (y == y1 - 1) {
|
|
||||||
next_xray = last_xray;
|
|
||||||
}
|
|
||||||
// Drop inconsistent intersections.
|
|
||||||
if (x <= min(xray, next_xray) || max(xray, next_xray) < x) {
|
|
||||||
y_edge = 1e9;
|
y_edge = 1e9;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Binary file not shown.
Loading…
Reference in a new issue