Skip to content

Build CGPaths during parallel projection, not on every draw call - #43

Merged
nighthawk merged 1 commit into
mainfrom
perf/prebuilt-cgpaths
Sep 22, 2026
Merged

nighthawk merged 1 commit into
mainfrom
perf/prebuilt-cgpaths

Conversation

@nighthawk

@nighthawk nighthawk commented Sep 20, 2026 •

Copy link
Copy Markdown
Member

Summary

GeoMapView used to rebuild CGMutablePath from raw Point arrays on every setNeedsDisplay even for redraws that don't touch the geometry (e.g., mapBackground/mapOutline toggles, re-render on tile arrival, invalidation on drag). Now the path-building loop runs once alongside the projection math on the background task, and draw(_:) is context.addPath(path).

Also folds the polygon-interior "clip out holes" step into an even-odd fill on a compound path, which has the same visual result but no CGContext clip state that could leak into the next polygon.

Test plan

  • swift test — 53 tests pass.
  • Cassini smoke test on macOS: drag the reference-lat/lon sliders while a heavy scene is up (Danseiji IV, all continents). Should feel smoother mid-drag now that each debounced re-render skips path reconstruction.
  • Cassini smoke test: flip mapBackground / mapOutline / light-dark. These invalidate the view without changing projected content — Time Profiler should show CGMutablePath.addLine gone from draw(_:) samples.

The two GeoMapView subclasses (AppKit + UIKit) used to reconstruct
`CGMutablePath` from raw `Point` arrays on every `setNeedsDisplay`,
including trivial redraws — `mapBackground` toggles, tile arrivals
triggering a re-render, drag-frame invalidations, mapOutline flips.
The path-building loop is now done once inside a new
`projectInParallelCG` alongside the projection math, producing
pre-built `CGPath` objects stored in CG-specific projected types
(`CGProjectedLine`, `CGProjectedPolygon`, `CGProjectedContent`).

The `draw([CGProjectedContent])` path then just calls
`context.addPath(path)` — no allocation, no per-vertex iteration per
frame.

Polygon interior holes switch from a `CGContext` clip-state approach
to even-odd fill on a compound path, which also fixes a latent
clip-leak when polygons with interiors were followed by polygons
without.

Parallel projection chunk size is 5 (vs. the original 25 in
`projectInParallel`) so finer-grained work distributes more evenly
across cores.

`projectInParallel` / `draw([ProjectedContent])` stay untouched for
SVG output.

Ported from claude/investigate-map-performance-rb4u7 (commit 5c59a00)
onto today's layout — handles the tiledBaseMap case added since, and
the UIKit CTM counter-flip for raster underlays.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@nighthawk
nighthawk force-pushed the perf/prebuilt-cgpaths branch from df79f57 to cdcb05d Compare September 20, 2026 22:34
@nighthawk nighthawk added the under-the-hood Code refactoring and other under-the-hood tweaks label Sep 22, 2026
@nighthawk nighthawk self-assigned this Sep 22, 2026
@nighthawk
nighthawk merged commit 21187a5 into main Sep 22, 2026
8 checks passed
@nighthawk
nighthawk deleted the perf/prebuilt-cgpaths branch September 22, 2026 01:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

under-the-hood Code refactoring and other under-the-hood tweaks

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant