Slice Tilt: from 40 seconds of shader compile to 6
· 2 min read · webgpu, three.js, performance, game-dev, batchedmesh
How long Slice Tilt takes to become playable is, on a first visit, almost all shader compilation. This is what was slow and what changed.
Measure with a cold cache #
The driver keeps what it compiled, so the second visit of anything is 30 to 150 times faster than the first. A measurement taken on a machine that has run the page before measures nothing a new player will see. The probe gives every shader a constant that is new in each page load, so the driver cannot answer from its cache.
What was slow (about 40 s) #
- Frames ran before the pre-compile did.
compileAsync(scene)was called without a camera: it threw, a.catchhid the error, and nothing was compiled ahead. 563 pipelines were made on the render path, one at a time. - One shader per
InstancedMesh. three keys instanced meshes on the object's uuid, so 186 instanced meshes with one material were 186 builds and 2.5 MB of WGSL. - The ball's reflection probe draws the slice into a cube, another render context, so 85 more pipelines on the first frames.
compileAsyncitself compiles one at a time and yields a lot.
What changed #
- The canvas does not draw until a custom pre-compile resolves. All pipelines are in flight at once, 16 at a time, including objects out of the frustum, and errors are not swallowed.
- The probe's cube pass is part of the pre-compile.
- About 140 InstancedMeshes became one
BatchedMeshper kit and two for the dressing.
Results (cold, M2 Max) #
| before | after | |
|---|---|---|
| ready | 35-39 s | 5-7 s |
| CPU x4, a phone's main thread | 43 s | 12 s |
| shader modules | 602 | 210 |
| pipelines on the render path | 563 | 26 |
A trap worth knowing #
NodeMaterial reads instanceColor while it builds, and three's cache key does not include it. An InstancedMesh that gets its colors later, in the first frame, keeps the shader built without them and draws white, with no warning. Create colors where the mesh is made.
The same family of work on another game is in the Threejs-Punk startup post. The project is on its project page.
Related projects
- Slice Tilt — Free pinball on a four-slice pizza