change tile segment representation to (origin, vector)

Eliminates the precision loss of the subtraction in the sign(end.x - start.x)
expression in kernel4. That's important for the next change that avoids
inconsistent line intersections in path_coarse.

Updates #23

Signed-off-by: Elias Naur <mail@eliasnaur.com>
This commit is contained in:
Elias Naur 2020-12-01 18:06:09 +01:00
parent 2068171f96
commit 19f4d9fa95
6 changed files with 21 additions and 19 deletions

View file

@ -13,8 +13,8 @@ piet_gpu! {
} }
// Segments within a tile are represented as a linked list. // Segments within a tile are represented as a linked list.
struct TileSeg { struct TileSeg {
start: [f32; 2], origin: [f32; 2],
end: [f32; 2], vector: [f32; 2],
y_edge: f32, y_edge: f32,
next: Ref<TileSeg>, next: Ref<TileSeg>,
} }

View file

@ -65,8 +65,8 @@ float[CHUNK] computeArea(vec2 xy, int backdrop, uint tile_ref) {
TileSeg seg = TileSeg_read(tile_seg_ref); TileSeg seg = TileSeg_read(tile_seg_ref);
for (uint k = 0; k < CHUNK; k++) { for (uint k = 0; k < CHUNK; k++) {
vec2 my_xy = vec2(xy.x, xy.y + float(k * CHUNK_DY)); vec2 my_xy = vec2(xy.x, xy.y + float(k * CHUNK_DY));
vec2 start = seg.start - my_xy; vec2 start = seg.origin - my_xy;
vec2 end = seg.end - my_xy; vec2 end = start + seg.vector;
vec2 window = clamp(vec2(start.y, end.y), 0.0, 1.0); vec2 window = clamp(vec2(start.y, end.y), 0.0, 1.0);
if (window.x != window.y) { if (window.x != window.y) {
vec2 t = (window - start.y) / (end.y - start.y); vec2 t = (window - start.y) / (end.y - start.y);
@ -79,7 +79,7 @@ float[CHUNK] computeArea(vec2 xy, int backdrop, uint tile_ref) {
float a = (b + 0.5 * (d * d - c * c) - xmin) / (xmax - xmin); float a = (b + 0.5 * (d * d - c * c) - xmin) / (xmax - xmin);
area[k] += a * (window.x - window.y); area[k] += a * (window.x - window.y);
} }
area[k] += sign(end.x - start.x) * clamp(my_xy.y - seg.y_edge + 1.0, 0.0, 1.0); area[k] += sign(seg.vector.x) * clamp(my_xy.y - seg.y_edge + 1.0, 0.0, 1.0);
} }
tile_seg_ref = seg.next; tile_seg_ref = seg.next;
} while (tile_seg_ref.offset != 0); } while (tile_seg_ref.offset != 0);
@ -131,9 +131,9 @@ void main() {
TileSegRef tile_seg_ref = TileSegRef(stroke.tile_ref); TileSegRef tile_seg_ref = TileSegRef(stroke.tile_ref);
do { do {
TileSeg seg = TileSeg_read(tile_seg_ref); TileSeg seg = TileSeg_read(tile_seg_ref);
vec2 line_vec = seg.end - seg.start; vec2 line_vec = seg.vector;
for (uint k = 0; k < CHUNK; k++) { for (uint k = 0; k < CHUNK; k++) {
vec2 dpos = xy + vec2(0.5, 0.5) - seg.start; vec2 dpos = xy + vec2(0.5, 0.5) - seg.origin;
dpos.y += float(k * CHUNK_DY); dpos.y += float(k * CHUNK_DY);
float t = clamp(dot(line_vec, dpos) / dot(line_vec, line_vec), 0.0, 1.0); float t = clamp(dot(line_vec, dpos) / dot(line_vec, line_vec), 0.0, 1.0);
df[k] = min(df[k], length(line_vec * t - dpos)); df[k] = min(df[k], length(line_vec * t - dpos));

Binary file not shown.

View file

@ -205,16 +205,18 @@ void main() {
TileRef tile_ref = Tile_index(path.tiles, uint(base + x)); TileRef tile_ref = Tile_index(path.tiles, uint(base + x));
uint tile_el = tile_ref.offset >> 2; uint tile_el = tile_ref.offset >> 2;
uint old = atomicExchange(tile[tile_el], tile_offset); uint old = atomicExchange(tile[tile_el], tile_offset);
tile_seg.start = p0; tile_seg.origin = p0;
tile_seg.end = p1; tile_seg.vector = p1 - p0;
float y_edge = 0.0; float y_edge = 0.0;
if (tag == PathSeg_FillCubic) { if (tag == PathSeg_FillCubic) {
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 && y_edge >= tile_y0 && y_edge < tile_y0 + TILE_HEIGHT_PX) {
vec2 p = vec2(tile_x0, y_edge);
if (p0.x > p1.x) { if (p0.x > p1.x) {
tile_seg.end = vec2(tile_x0, y_edge); tile_seg.vector = p - p0;
} else { } else {
tile_seg.start = vec2(tile_x0, y_edge); tile_seg.origin = p;
tile_seg.vector = p1 - p;
} }
} else { } else {
y_edge = 1e9; y_edge = 1e9;

Binary file not shown.

View file

@ -35,8 +35,8 @@ TileRef Tile_index(TileRef ref, uint index) {
} }
struct TileSeg { struct TileSeg {
vec2 start; vec2 origin;
vec2 end; vec2 vector;
float y_edge; float y_edge;
TileSegRef next; TileSegRef next;
}; };
@ -90,8 +90,8 @@ TileSeg TileSeg_read(TileSegRef ref) {
uint raw4 = tile[ix + 4]; uint raw4 = tile[ix + 4];
uint raw5 = tile[ix + 5]; uint raw5 = tile[ix + 5];
TileSeg s; TileSeg s;
s.start = vec2(uintBitsToFloat(raw0), uintBitsToFloat(raw1)); s.origin = vec2(uintBitsToFloat(raw0), uintBitsToFloat(raw1));
s.end = vec2(uintBitsToFloat(raw2), uintBitsToFloat(raw3)); s.vector = vec2(uintBitsToFloat(raw2), uintBitsToFloat(raw3));
s.y_edge = uintBitsToFloat(raw4); s.y_edge = uintBitsToFloat(raw4);
s.next = TileSegRef(raw5); s.next = TileSegRef(raw5);
return s; return s;
@ -99,10 +99,10 @@ TileSeg TileSeg_read(TileSegRef ref) {
void TileSeg_write(TileSegRef ref, TileSeg s) { void TileSeg_write(TileSegRef ref, TileSeg s) {
uint ix = ref.offset >> 2; uint ix = ref.offset >> 2;
tile[ix + 0] = floatBitsToUint(s.start.x); tile[ix + 0] = floatBitsToUint(s.origin.x);
tile[ix + 1] = floatBitsToUint(s.start.y); tile[ix + 1] = floatBitsToUint(s.origin.y);
tile[ix + 2] = floatBitsToUint(s.end.x); tile[ix + 2] = floatBitsToUint(s.vector.x);
tile[ix + 3] = floatBitsToUint(s.end.y); tile[ix + 3] = floatBitsToUint(s.vector.y);
tile[ix + 4] = floatBitsToUint(s.y_edge); tile[ix + 4] = floatBitsToUint(s.y_edge);
tile[ix + 5] = s.next.offset; tile[ix + 5] = s.next.offset;
} }