Claude: Optimize SVG path rasterization (~10% faster)#586
Open
treeform wants to merge 1 commit into
Open
Conversation
- computeCoverage: gather subsample hits in one pass over entries (each entry loaded once instead of once per subsample line) - Accumulate coverage as int16 deltas and convert with a single prefix-sum pass (NEON accelerated) instead of adding sample coverage to every covered pixel per subsample - Track covered regions per scanline so blending and clearing only touch real coverage instead of the full path width - Store 1/m in PartitionEntry, replacing divides with multiplies - Reuse thread-local scratch buffers across fillShapes calls and inside partitionSegments, removing per-path allocations - Clip partition entries with the precomputed slope instead of generic segment-line intersection - Hoist blender lookup out of the trapezoid loop and inline blendNormal for the common blend mode Ghostscript Tiger render: 6.89 -> 6.16 ms min (same machine, interleaved runs), test_svg/test_paths/test_images_draw/test_paints/ test_contexts/test_fonts all pass with unchanged diff scores. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Speeds up the
tests/bench_svg.nimGhostscript Tiger render from 6.89 ms to 6.16 ms min (~10.5%, measured with interleaved A/B runs against a master-built binary on an M-series Mac,-d:danger).All changes are in
src/pixie/paths.nimand keep output effectively identical — everytest_svg/test_pathsxray diff score matches master to 4 decimal places (remaining differences come from replacing divides with multiplies by the reciprocal, well below the masters' own tolerance).Changes
int16delta buffer. One prefix-sum pass per scanline (NEON-vectorized on arm64) converts deltas to the exact same coverage bytes. Long interior spans go from 5 passes over every pixel to O(1) writes + 1 pass.computeCoveragepreviously rescanned all active entries once per subsample line (5x). Entries are now loaded once, their fields kept in registers, and hits bucketed per subsample line — same hit order, bit-identical sort/walk behavior. On the tiger this cuts 467k entry visits per render to 93k.zeroMemof the coverage buffer is gone (deltas are provably re-zeroed by the prefix pass).PartitionEntrystores1/m, turning the per-hit divide insolveX/hit gathering into a multiply.intersects().fillShapesandpartitionSegmentsreuse grow-only thread-local buffers (coverages, deltas, hits, buckets, partitions + entries, segments), removing a few thousand allocations per tiger render. Partitions gained anumEntriescount so entry storage can be reused without reallocating.blender()proc-pointer lookup is hoisted out of the trapezoid pair loop andblendNormalis called directly for the common NormalBlend case in the edge-coverage loops.Testing
test_svg,test_paths,test_images_draw,test_paints,test_contexts,test_fontsall pass; xray scores unchanged vs master.🤖 Generated with Claude Code