Skip to content

Cut WebGPU first-flush compile time and scratch memory - #421

Merged
JimBobSquarePants merged 3 commits into
mainfrom
js/webgpu-first-flush
Sep 15, 2026
Merged

JimBobSquarePants merged 3 commits into
mainfrom
js/webgpu-first-flush

Conversation

@JimBobSquarePants

@JimBobSquarePants JimBobSquarePants commented Sep 15, 2026

Copy link
Copy Markdown
Member

Prerequisites

  • I have written a descriptive pull-request title
  • I have verified that there are no overlapping pull-requests open
  • I have verified that I am following matches the existing coding patterns and practice as demonstrated in the repository. These follow strict Stylecop rules 👮.
  • I have provided test coverage for my change (where applicable)

Description

Cuts the WebGPU first-flush time and the scratch memory the staged pipeline reserves. Measured on the DrawingBackendBenchmark sample, WebGPU, 100k lines, preview 1576x1075, AMD Radeon 8060S.

before after
first run of the sample 2716 to 3540 ms 360 to 380 ms with the driver shader cache warm, about 1150 ms on a machine's first launch
fine shader compile, cold 1670 to 1850 ms 1130 to 1160 ms
fine shader compile, warm never cached 340 to 360 ms
scheduling shaders about 1 s, one by one, inside the first flush about 0.5 s, in parallel, at app start
scratch reserved 1.83 GB 1.12 GB
PTCL words the GPU writes 95.0 M 64.6 M
runs 2 and 3 of a cold process, before JIT tiering 58 to 90 ms 75 to 80 ms
steady state 20 to 40 ms 20 to 40 ms

Compile

  • The scheduling pipelines compile when the device is probed, on all cores, instead of one by one inside the first flush.
  • The fine pipeline compiles once, for the target's own format, starting when the target is created. The fixed list of four format variants is gone.
  • compose_source evaluates the blend overlap once per call instead of inside five switch cases. Same operands per mode, bit-identical output. The shader now fits the driver's shader cache.
  • The fine shader composes each paint command at one site after the command switch instead of inside every paint case. This cuts the cold compile from 1.8 s to 1.1 s.

Memory

  • Stroke scratch is seeded from the outline geometry (offset edges, caps, joins) instead of the bounding-box diagonal. Crossings reserved for 11.5 M used: 24.6 M before, 13.65 M after.
  • CMD_FILL goes from 9 words to 6, CMD_SOLID from 5 to 2, CMD_COLOR from 4 to 3. The interest rectangle and the colour are referenced by offset into the info and scene streams.
  • The PTCL seed is a per-draw bound: one fill command plus that draw's paint command per tile crossing.

Verification

  • No new tests. The existing 404 WebGPU tests, which include the blend-mode, gradient, clip, and 100k-line goldens, pass on net10.0 and net11.0.
  • No overflow, no retry, no chunking on the 100k scene; the GPU allocator counters were read back to confirm.

compose_source evaluates the blend overlap once per call instead of inside
five switch cases. The fine pipeline compiles in 0.5 s instead of 1.7 s with
identical arithmetic per mode.

The scheduling pipelines compile in parallel when the device is probed. The
fine pipeline compiles once per target format, started when the target is
created, instead of four fixed variants started at the first render.

Stroke scratch estimates are bounded from the outline geometry (offset edges,
caps, joins) instead of the bounding-box diagonal. The PTCL seed is a
per-crossing bound plus one chunk per target tile.
CMD_FILL and CMD_SOLID reference their raster interest rectangle by its
info-stream offset instead of copying four words into every tile. CMD_COLOR
references the packed colour in the scene stream and the draw flags in the
info stream. Fill goes from 9 words to 6, solid from 5 to 2, colour from 4
to 3. The PTCL seed bound drops from 14 to 11 words per crossing.

The fine shader stores each paint command's per-pixel colour and coverage
and composes them at one site after the command switch. One compose site
keeps the blend-mode switch from being inlined into every paint case, which
cuts the cold fine compile from 1.8 s to 1.1 s.
The encoder accumulates a PTCL word bound per draw: one CMD_FILL (6 words)
plus the paint command coarse writes for that draw tag, times the draw's
tile-crossing bound. The bound flows through partitions, checkpoints,
ranges, and the scene, and replaces the fixed 11 words per crossing in the
scratch seed. A solid-colour scene now seeds 9 words per crossing.
@codecov

codecov Bot commented Sep 15, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 95.47739% with 9 lines in your changes missing coverage. Please review.
✅ Project coverage is 79%. Comparing base (d1daf50) to head (620eae3).

Files with missing lines Patch % Lines
...c/ImageSharp.Drawing.WebGPU/WebGPUSceneDispatch.cs 93% 3 Missing and 2 partials ⚠️
...rc/ImageSharp.Drawing.WebGPU/WebGPUSceneEncoder.cs 97% 1 Missing and 2 partials ⚠️
src/ImageSharp.Drawing.WebGPU/WebGPURuntime.cs 66% 0 Missing and 1 partial ⚠️
Additional details and impacted files
@@          Coverage Diff           @@
##            main    #421    +/-   ##
======================================
  Coverage     79%     79%            
======================================
  Files        232     232            
  Lines      27392   27516   +124     
  Branches    3119    3128     +9     
======================================
+ Hits       21814   21934   +120     
- Misses      4540    4542     +2     
- Partials    1038    1040     +2     
Flag Coverage Δ
unittests 79% <95%> (+<1%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@JimBobSquarePants JimBobSquarePants added this to the v4.0.0 milestone Sep 15, 2026
@JimBobSquarePants
JimBobSquarePants merged commit 768086f into main Sep 15, 2026
12 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant