fix: pixel-identical rendering (z2d stroker port) and last P3 items

Resolves the 3 P3 items in docs/rewrite/notes/review-rv12-codex.md
(final-Z15.md):
- Sprite strokes: tiny-skia is replaced by a port of z2d 0.10's stroke
  plotter (sprite/stroke.rs) plus z2d's arc segmentation and truncating
  integer compositing, feeding the ported 4x4 multisample rasterizer.
  All 36 reference sprite sheets now match Ghostty's byte for byte (test
  tolerance 0), and `just visual-parity` with a production build shows
  0 differing pixels (max delta 0) against the installed Ghostty 1.3.1
  for the test page (block and bar cursor) and the tabs+splits scenario,
  terminal area and chrome alike. tiny-skia dependency removed.
- zig_error maps errno values per target via libc (Linux, Darwin/BSD)
  and Win32 codes the way Zig std does on Windows.
- theme=. / theme=.. report "it is a directory" via a port of
  std.fs.path.basename, matching Ghostty.

Test Plan:
- cargo test --workspace --no-fail-fast (3498 passed, exit 0)
- cargo build --profile production && just visual-parity
- just check-macos (both), just check-windows, just check-wasm
This commit is contained in:
ddidderr committed 2026-10-12 14:20:49 +02:00
1 parent 7dd54833b9
commit 6befc09cc8
10 files changed
+1339 -191

No files matched your search

+29
View File
@@ -0,0 +1,29 @@
# Z15: RV12 P3 closures
## 1. Platform error codes (`ghostty-os/src/zig_error.rs`)
`errno_name` is now per target: unix uses `libc::E*` constants (Linux and Darwin/BSD numbering both
correct, e.g. Darwin `ELOOP=62`, `ENAMETOOLONG=63`, `EAGAIN=35`); Windows maps Win32 codes the way
Zig std's `windowsCreateProcess` / file-open paths do (FILE_NOT_FOUND, PATH_NOT_FOUND, DIRECTORY ->
FileNotFound; ACCESS_DENIED -> AccessDenied; INVALID_NAME, FILENAME_EXCED_RANGE -> NameTooLong;
SHARING_VIOLATION -> FileBusy; COMMITMENT_LIMIT -> SystemResources; DISK_FULL -> NoSpaceLeft; the
ENOEXEC family -> InvalidExe), using `windows-sys` constants. Other targets (wasm): `Unexpected`.
Tests are cfg'd per platform (libc constants everywhere, literal tables for Linux/Apple/Windows) and
compile-checked with `just check-macos` / `just check-windows`.
## 2. Dot theme names (`ghostty-config/src/theme.rs`)
`zig_basename` ports `std.fs.path.basename` (ComponentIterator.last: trailing separators stripped,
`.`/`..` are ordinary names; `X:` drive root on Windows) instead of `Path::file_name`. `theme=.` and
`theme=..` now pass the basename check and report Zig's `not reading theme from ".": it is a
directory`. Differentially checked against /usr/bin/ghostty (`.`, `..`, `a/`, `a/b`, `./`: identical).
## 3. Sprite stroking (`ghostty-font/src/sprite/{stroke,canvas}.rs`)
tiny-skia is gone (dependency removed). New `stroke.rs` ports z2d 0.10 `stroke_plotter`, `Face`, `Pen`,
`Slope`, `Spline` (curve flattening with round joins), `PointBuffer` and Contour/Polygon edge building
(identity CTM, no dashes). `canvas.rs` now builds z2d-style nodes (`close` appends the implicit
`move_to`), fills via direct node flattening in f64 (no f32 skia round trip), ports z2d's Cairo-style
`arc` (segment count from the tolerance table), and uses z2d's truncating integer `src_over`
(`s + d - s*d/255`, `dst_in` `cov*a/255`) instead of rounding.
Sprite-sheet reference test: every one of the 36 sheets is now bit-exact (was 1.2% differing, max 86);
the test now requires 0 differing pixels.
`just visual-parity` (iteration build of the production profile): page, page-bar, tabs and chrome all
0 differing pixels (was 196 px / 0.020% for page).
+11 -11
View File
@@ -30,13 +30,13 @@
| scenario | before | after |
|---|---|---|
| page (full frame) | 0.130% (1250 px, max 93) | 0.020% (196 px, max 86; 0.001% > 32 levels) |
| page-bar | same as page | 0.020% |
| page (full frame) | 0.130% (1250 px, max 93) | 0.000% (0 px; was 0.020% / 196 px before Z15) |
| page-bar | same as page | 0.000% |
| tabs + splits | 44.6% (a whole pane blank, bug) | 0.000% (bit-identical) |
| chrome (headerbar, tab bar) | 0.000% | 0.000% |
Sprite sheets (`ghostty-font` tests, Zig reference PNGs): differing pixels 5.76% -> 1.20%, pixels off by
more than 96 levels 74 -> 0 (test tolerance tightened from 4% to 0.1% big diffs).
Sprite sheets (`ghostty-font` tests, Zig reference PNGs): differing pixels 5.76% -> 1.20% -> 0 (bit-exact after Z15;
test tolerance is now zero).
Font metrics, cell size, baseline, glyph rasterization, colors, cursor, underline positions, padding,
GTK CSS/headerbar/tab bar were already pixel-identical; no change was needed there.
@@ -51,12 +51,12 @@ GTK CSS/headerbar/tab bar were already pixel-identical; no change was needed the
2. **Sprite antialiasing** (`ghostty-font/src/sprite/canvas.rs`): replaced tiny-skia's coverage with a port of
z2d 0.10's default `multisample_4x` rasterizer (4x4 samples, scanline spans with edge x rounded at
sample row centers, non-zero filter, alpha = `coverage * 16 - 1`, full = 255, z2d's Bezier
flattening with tolerance 0.1). Stroke outlines still come from tiny-skia's stroker.
flattening with tolerance 0.1). (Stroke outlines were still tiny-skia's until Z15, which ported z2d's stroker.)
## Remaining differences (page: 196 px, all <= 86 levels)
## Remaining differences
- Curly underline: first/last pixels and peaks differ slightly. z2d builds its own stroke polygon (pen/joins)
for curves; tiny-skia's stroker offsets the Bezier differently.
- Diagonal box glyphs (`U+2571..2573`) have a few edge pixels off by up to ~38 levels (same cause).
- Porting z2d's stroker (`tess/stroke_plotter`, `Pen`) would remove the rest; judged not worth it
(0.02% of pixels, imperceptible).
None (Z15). z2d's stroke plotter (pen, joins, caps, spline flattening), Cairo-style arc segmentation and
z2d's truncating integer compositing were ported (`ghostty-font/src/sprite/stroke.rs`, `canvas.rs`;
see `final-Z15.md`). Final `just visual-parity`: page, page-bar and tabs are 0 differing pixels on the
full frame, the terminal area and the chrome (max delta 0). All sprite sheets in the `ghostty-font`
reference test are bit-exact (tolerance now zero).