Skip to content

Post Stack

apps/post_stack_demo proves the stacked N-effect post chain (engine ADR 0101): Graphics.addPostEffect called four times runs a chain — each effect’s output feeds the next, and the last writes the swapchain.

A colourful scene (three depth-layered colour blocks on a light background), then four post effects added in order:

  1. tint — a warm colour multiply (params p0.rgb).
  2. vignette — darkens toward the corners (p0.x strength).
  3. desaturate — mutes the colours (p0.x amount). This stage re-uses a ping-pong scratch target, so it also exercises the renderer’s write-after-read barrier.
  4. scanlines — CRT bands (p0.x intensity, p0.y line count) — the final stage, which writes the screen.

The screenshot shows all four composed: warm but muted colours, hard dark corners, and horizontal bands. Before the stack landed only the first effect ran and the rest were silently dropped — so the dark vignette corners (plus the muting and the scanlines) are the definitive proof that stages 2–4 executed.

// draw(): render the scene, then stack the effects in order
for (m in _meshes) Graphics.drawMesh(m)
Graphics.addPostEffect("shaders/tint", [1.25, 0.95, 0.72, 0.0]) // 1. warm tint
Graphics.addPostEffect("shaders/vignette", [1.0, 0.0, 0.0, 0.0]) // 2. vignette
Graphics.addPostEffect("shaders/desaturate", [0.45, 0.0, 0.0, 0.0]) // 3. desaturate (re-uses a scratch target)
Graphics.addPostEffect("shaders/scanlines", [0.35, 220.0, 0.0, 0.0]) // 4. scanlines (writes the screen)

The engine renders the scene to an offscreen colour+depth target, then runs the chain: the intermediate effects render into two ping-pong scratch targets (effect i samples the previous result, writes the other target), and the final effect draws into the swapchain. Each effect is an ordinary post shader — it just samples its input at plume3d_sceneColor(uv) and doesn’t need to know its position in the chain. A single effect (one addPostEffect) is the same direct-to-swapchain path as before. See the post-effect ABI.