diff --git a/Development.md b/Development.md index ec2a847..b9bdadf 100644 --- a/Development.md +++ b/Development.md @@ -12,13 +12,14 @@ npm run check # typecheck + lint + format:check + tests, the gate CI runs # code is lost (tail's is reported), so a red run reads as green npm run build # writes dist/ and regenerates index.html ./build.sh # the same under `set -o pipefail`, for callers that pipe the output -node tools/seed-e2e.mjs && node tools/e2e.mjs # 727 editor checks, screenshots in /tmp/gm-e2e-*.png +node tools/seed-e2e.mjs && node tools/e2e.mjs # 728 editor checks, screenshots in /tmp/gm-e2e-*.png GM_STEPS=20 node tools/e2e.mjs # or 1-12, or 6,20 — a subset while working on one step ./e2e.sh start [GM_STEPS] # the same run detached, see below ./e2e.sh status # live progress, or the last run's result node tools/seed-jumprun.mjs && node tools/smoke-jumprun.mjs # 24 checks: the example game, played end to end node tools/seed-tetris.mjs && node tools/smoke-tetris.mjs # 19 checks: the Tetris example, played end to end node tools/seed-actor.mjs && node tools/smoke-actor.mjs # 21 checks: the walk demo (the seed uploads its own sheet) +node tools/seed-e2e.mjs && node tools/perf-shaders.mjs # what a shader costs per sprite; a measuring tool, not a check ``` **A run needs a working GPU.** An idle editor page keeps rendering a picture that never changes, and @@ -62,7 +63,7 @@ to touch it. The e2e run is a list of steps in `tools/e2e/` (hierarchy, inspector, play, assets, drawing, graph, parenting, colliders, containers, text/enabled, menus, textures, frames, overflow, aspect, container tab, run-in-editor, pause, nested behaviors, key repeat, list tab, struct variable, -variable nodes, property nodes, animations, state machines, console) that build on each other's +variable nodes, property nodes, animations, state machines, console, shaders) that build on each other's scene state and share the CDP driver in `tools/lib/harness.mjs` — `press`, `undo`, `play`, `object(id)`, `world()`, `mutate(js)` and friends, so a check reads like the interaction it exercises. @@ -150,4 +151,4 @@ widths to find click points. The **render device is not in this repo** — `/dev and a 1 GB `/dev/shm` come from `container.options` in the runner's own `config.yaml`, which applies to every job on that runner. Without them chromium falls back to llvmpipe, which gets WebGL 1.0 only. Measured in the job container: `ANGLE (Intel, Vulkan 1.3.230, HD Graphics 630)`, -WebGL 2.0, and the same 727 checks as here. +WebGL 2.0, and the same 728 checks as here. diff --git a/Shaders.md b/Shaders.md index 4631da9..8b2ede3 100644 --- a/Shaders.md +++ b/Shaders.md @@ -83,7 +83,19 @@ deviations while their shader is not worn. ## What it costs, and where it stops A shader is a Pixi filter: the sprite is rendered into an intermediate texture and drawn back with -the fragment, one pass per sprite wearing one. Fine for dozens, not for thousands. The pass runs at +the fragment, one pass per sprite wearing one. Measured with `tools/perf-shaders.mjs` on an Intel +HD 630 (the GPU CI uses as well), sprites of 48x48 inside a 640x360 camera, neutral values, three +runs agreeing to within 1 fps: + +| shaded sprites | 25 | 50 | 100 | 200 | 400 | 800 | +| --- | --- | --- | --- | --- | --- | --- | +| frames per second | 58 | 56 | 54 | 48 | 34 | 20 | + +The very same scene without shaders holds 60 fps at every one of those counts, 800 included, so the +whole drop is the passes: about 20 microseconds each up to 200 sprites, 40 at 800. Sprite size +hardly matters — four times the area (96x96) measures the same, so what costs is the pass, not the +pixels in it. A few dozen shaded sprites are free in practice; a few hundred cost half the frame +rate. The pass runs at screen resolution, so pixel art stays sharp: measured in play at a fractional camera scale (1.43 screen pixels per world unit), a *Nearest* texture keeps its hard border pixel for pixel with a neutral shader on, and brightness 0.5 darkens every one of those pixels — the pass runs there, and