The capture harness uses the graphics card that was there all along
`launch()` asks for `--use-angle=vulkan` and gets the Radeon RX 6700 XT. On the real film loop at 1440x900 that is 7.56 s a frame to 0.47, and about twelve cores pegged down to less than one. A 180-frame film goes from twenty-two minutes to ninety seconds; the three shipped reels go from over an hour to four minutes. The SwiftShader flag was inherited from the share-card script and its comment said "a box with no display and no GPU". Half of that was never true. The card has been in this machine the whole time, with the amdgpu driver and a working RADV ICD, and Chrome reaches it with **no display server at all** — no DISPLAY, no XDG_RUNTIME_DIR, nothing but read access to /dev/dri/renderD128, which group `render` already grants. So the portability the flag was protecting is intact: this still runs over ssh and under cron. Naming the backend is the whole trick, and most of the plausible spellings are traps. `--use-angle=gl`, `--use-gl=egl`, `--use-gl=desktop`, `--enable-features=Vulkan` and passing no GL flags at all were each measured on this box, and all five land on SwiftShader while reporting success. Only `--use-angle=vulkan` and `--use-angle=gl-egl` reach the card. So `launch()` verifies instead of assuming. `--use-angle=vulkan` is a demand, not a preference: with the driver hidden it yields no WebGL context at all rather than falling back, the boot curtain never lifts, and the caller sits in `waitForFunction` until a three-minute timeout before failing with something that looks nothing like "there is no GPU here". Reading `UNMASKED_RENDERER_WEBGL` once per run costs about half a second and turns that into a printed line and a slow, correct render. Both branches are tested; the sabotaged one was verified with `VK_LOADER_DRIVERS_DISABLE`. The pictures are the same pictures: mean absolute difference of half a level out of 255, confined to MSAA edges and to cloud shadow that already drifts between any two runs of the same renderer. Also corrects every comment across the four scripts that asserted three frames a second or twenty-two minutes a reel. Those were true when written and are not now, and the `reducedMotion` rationale in two of them was resting on the number: the real reason a chapter flight cannot be waited out is that it is ~40 frames however fast they are drawn, which was twenty seconds under software GL and is a shorter race on the GPU — still a race. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -53,12 +53,13 @@ async function shootApp(browser, url, file, { key = null, settle = 20000 } = {})
|
||||
* since the day it was written.
|
||||
*
|
||||
* `scenekit.ts` eases a chapter change over about two seconds of scene
|
||||
* time, `stage.ts` clamps `dt` to 50 ms a frame, and SwiftShader on this
|
||||
* box draws about three frames a second — so the flight below takes some
|
||||
* twenty seconds of wall clock, and the four this waited caught the camera
|
||||
* partway across the bay at a different point each time. Two consecutive
|
||||
* captures of an unchanged repo produced two different cards, neither of
|
||||
* them the chapter the key press had asked for.
|
||||
* time and `stage.ts` clamps `dt` to 50 ms a frame — so a flight is about
|
||||
* forty frames however fast they are drawn, and the four seconds this
|
||||
* waited caught the camera partway across the bay at a different point
|
||||
* each time. Two consecutive captures of an unchanged repo produced two
|
||||
* different cards, neither of them the chapter the key press had asked
|
||||
* for. It was worst under software GL, where forty frames took twenty
|
||||
* seconds; on the GPU it is a shorter race and still a race.
|
||||
*
|
||||
* Reduced motion is the app's own answer for "somebody clicked a name in a
|
||||
* list": `flyTo` sets the pose outright, so the shutter opens on the pose
|
||||
@@ -102,10 +103,10 @@ async function renderCard(browser, which, out) {
|
||||
/**
|
||||
* `--cards-only` re-renders the two PNGs from art already on disk.
|
||||
*
|
||||
* The app pass is a minute of software rasterisation and the card pass is two
|
||||
* seconds, and every iteration on a headline needs only the second. Without the
|
||||
* flag, tuning a line of copy costs a minute each time, which is how a card ends
|
||||
* up shipped with the first wording anybody tried.
|
||||
* The app pass shoots the running city and the card pass is two seconds, and
|
||||
* every iteration on a headline needs only the second. Without the flag, tuning
|
||||
* a line of copy costs a whole app pass each time, which is how a card ends up
|
||||
* shipped with the first wording anybody tried.
|
||||
*/
|
||||
const cardsOnly = process.argv.includes("--cards-only");
|
||||
|
||||
|
||||
Reference in New Issue
Block a user