Skip to content

Stealing 1613 shaders from the WebGPU CTS with a fake GPU

The best corpus of real-world WGSL is locked inside a test framework that refuses to hand it over. So I gave the framework a GPU that does not exist and wrote…

23 August 2026

techwebgpuzig

A wireframe GPU stub catching streams of WGSL shader cards in neon mint green

If you are testing a WGSL backend, you need WGSL. Not ten shaders you wrote yourself; you need the strange ones, the ones written by people with different assumptions than you, exercising corners of the spec you did not know were corners. In the WebGPU world the obvious corpus exists: the WebGPU CTS, the conformance test suite, thousands of cases of shader code written by spec authors to poke at exactly the edges a compiler needs to survive.

There is one problem. The CTS is not a folder of shaders. It is a test framework: TypeScript, data tables, parameterized cases, plan files. The WGSL you want is buried inside per-case setup routines that only run when a real GPU is attached. There is no export button. The answer to "can I get the shaders" is, structurally, no.

So I built a GPU that does not exist.

The fake device

The harness runs the CTS's own code. It loads the real suite, transpiles it, and starts executing actual cases. Before a case runs, the framework asks the browser for a GPU: adapter, device, queues. My harness answers those requests with a stub. A fake adapter that always says yes. A fake device whose methods accept whatever they are handed and remember it. Then the case's setup runs, the framework composes the shader source it intends to submit, hands it to what it believes is a GPU, and my stub writes down every WGSL string that touches its palm.

No rendering. No GPU. No browser. The CTS never notices, because from its point of view it is talking to a perfectly agreeable, perfectly inert device.

Out the other end comes what nobody was meant to have: 1613 real, CTS-authored WGSL shaders, extracted deterministically, byte-reproducible from a pinned revision of the suite. Two runs, two identical corpora. That matters because a corpus you cannot reproduce is a benchmark you cannot defend.

Then the actual test

Each harvested shader takes the trip a real shader never takes backwards: WGSL to SPIR-V (naga does the converting; a tint fallback catches dialects naga cannot parse, like subgroups), SPIR-V through zioshade's WGSL backend, and the result into naga and tint for validation. Round-trip or bust. It is a brutal shape for a cross-compiler: you are not translating someone else's SPIR-V, you are regenerating WGSL from WGSL-derived IR and it has to still be WGSL.

The first run was ugly, and that was the point. 43 invalid cases across 11 distinct bug classes: null-constant folding that emitted the wrong literal, depth-texture forms, image-query signedness, depth-only fragments that returned a hardcoded 0.0, multiple-render-target type mismatches, functions that were reachable but never emitted, once-stored privates, phi-scope identifier collisions. Every one of those was a shader that would have compiled and computed the wrong thing. All fixed, each with a minimized regression test.

The scoreboard now: 1597 of 1613 round-trip valid, zero invalid, zero crashes. Two cases even the upstream converters cannot digest, and 14 refusals that are deliberate and named: the cross-function subgroup shapes no faithful WGSL spelling can express, integer-64, binding collisions, and point-size builtins. A refusal with a reason is a bug report you filed against the spec, not a failure.

The general trick

Strip the specifics and this is a reusable move: when the artifact you need is imprisoned in a framework, do not parse the framework, run it. Implement the smallest interface the framework demands, become the environment it trusts, and record what it hands you. It is the same move I described when I shipped stunt: a stunt double takes the hits so the star does not have to. Here the star is a real GPU and the double is a stub just agreeable enough to get the CTS to show its hand.

The prerequisite is licenses and honesty: the CTS is BSD-3-Clause, the vendored corpus carries its notice, and the pinned revision is in the manifest, so anyone can check that what I claim as a corpus is what the suite actually contains. A corpus you stole is only useful if you can prove where it came from.

Get new posts by email

No spam. Confirm once, unsubscribe anytime.

Share𝕏LinkedInRedditWhatsApp