Skip to content

Anti-alias rounded primitives and adopt Per-Monitor V2 DPI on Windows#81

Merged
ctate merged 9 commits into
mainfrom
fix/windows-rounded-aa-dpi
Jul 10, 2026
Merged

Anti-alias rounded primitives and adopt Per-Monitor V2 DPI on Windows#81
ctate merged 9 commits into
mainfrom
fix/windows-rounded-aa-dpi

Conversation

@ctate

@ctate ctate commented Jul 9, 2026

Copy link
Copy Markdown
Collaborator

Fixes the Windows report of aliasing around round elements (buttons) in default native dev apps. Two defects compounded:

Rounded-primitive anti-aliasing (engine, all software-raster hosts)

Rounded-rect fills and strokes tested pixel centers with a binary in/out check, so curved edges stair-stepped — most visible on Windows and Linux, whose hosts present the software raster directly. They now blend fractional edge coverage derived from the signed corner distance:

  • Coverage ramps only inside corner squares with radius > 0; straight edges and radius-0 rects keep the binary test and stay bit-identical
  • Squared-distance short-circuits keep the cost to the ~1px boundary band; bench-render --check passes all budgets
  • The macOS GPU path already anti-aliases via its path rasterizer, so this improves cross-engine consistency; parity pixel signatures re-pinned from test output (chart goldens reviewed in both themes)

Per-Monitor V2 DPI on Windows

Apps were DPI-unaware: on >100% display scaling Windows virtualized DPI to 96 and bitmap-stretched the window, blurring everything and amplifying the aliasing. Now:

  • The embedded app manifest declares PerMonitorV2 DPI awareness
  • The Win32 host creates windows at physical size for the monitor's scale (800×600 points opens 1000×750 at 125%), frames child views/webviews in physical pixels, reports logical size + real scale, and handles WM_DPICHANGED by adopting the suggested rect and re-rasterizing surfaces at the new density

Verification

  • Full test suite, validate, and all seven smokes green; render budgets pass
  • Before/after pixel inspection on real Windows 11: DPI context probe flips UNAWARE → PER_MONITOR (PMv2), window geometry identical at 100% (no regression), button corners go from a hard 255→23 step to a proper coverage ramp
  • macOS 1x captures show the same staircase→ramp on curved edges with straight edges unchanged

@vercel

vercel Bot commented Jul 9, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
native-sdk Ready Ready Preview, Comment Jul 10, 2026 2:18am

- Rounded-rect fills and strokes render through one continuous signed-distance coverage field, so curved edges ramp smoothly with no silhouette drift; a supersampled ground-truth test pins shape fidelity and radius-0 rects stay bit-identical
- Hairline borders snap to whole device pixel columns at emit time and geometry snapping is on by default in the house and Geist packs, keeping 1px borders crisp while arcs stay smooth; pure-SDF geometry remains available by disabling pixel_snap.geometry
- Windows apps declare Per-Monitor V2 DPI awareness in the embedded manifest and the Win32 host sizes windows, child views, and surfaces in physical pixels with WM_DPICHANGED re-rasterization, so canvases render at device scale instead of being bitmap-stretched
- gpu-dashboard and gpu-components pin their reference-surface signatures inside the example suites, which only test-examples-native runs; the geometry-snap default changed those pixels
…s with surface scale

- WM_DPICHANGED now re-applies explicit child webview frames rooted at the message window, matching the native-view pass
- effectiveTokens stamps pixel_snap.scale onto a copy of static tokens and scale changes rebuild static-token apps, so hairline snapping stays on the device grid across monitor density changes
- The catalog laid out under default tokens (geometry snapping off) and rendered under pack tokens (snapping on), so the ceil rule for label-exact widths no-oped and per-edge frame rounding elided the third theme tab
- Layout builders now take the token set, the live app lays out with its surface tokens, and a regression test asserts the theme strip never elides under snapping in either pack
- Within the existing snap-eligibility window, fractional hairline widths now floor to the lighter device-pixel count instead of rounding, so a 1px border at 1.5x covers one crisp device column instead of two
- Sub-half-pixel strokes still never snap and 1x, 1.25x, and 2x rendering is pinned byte-identical by the updated tests
ctate added 2 commits July 9, 2026 19:05
- handleResize adopts the event's scale factor before rebuilding, so a DPI-only monitor move re-stamps tokens and re-emits even when the logical size is unchanged
- Window slots own a per-window pixel_snap_scale stamped into their token emission, so secondary windows on different-density monitors snap on their own device grid
- Native child view origins accumulate logical x/y through the parent chain and every physical edge rounds exactly once, so nested controls no longer drift a pixel at fractional scales and abutting frames share pixel columns
- The app manifest declares an ordered DPI awareness chain (PerMonitorV2, PerMonitor, legacy dpiAware) so pre-1607 systems degrade gracefully instead of losing awareness entirely
- hiddenOuterSizeForContent rounds scaled content extents through a shared helper instead of truncating, so hidden-titlebar windows and min-size floors match the requested logical size at fractional scales
- check-framework-sync now explains that the package mirror is generated and points at copy-framework.js instead of implying the mirror should be committed
- dpiForWindow now mirrors the manifest's awareness chain: GetDpiForWindow, then GetDpiForMonitor via shcore, then the system DPI, so pre-1607 systems that the manifest makes DPI-aware no longer render tiny 1x content
- gpuSurfaceScale delegates to the shared helper and the build pin asserts the chain alongside the manifest elements
@ctate ctate merged commit 512298b into main Jul 10, 2026
21 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant