R-15a — retained GPU buffers for v2 terrain (perf Lever 1, look-independent)
Part of the "hex diorama" program. Integration branch: render-r12-terragen-preview — branch
off it, and PR back into it with --base render-r12-terragen-preview EXPLICITLY (gh defaults
to main; see GOTCHAS.md, this exact rake was stepped on in PR #435).
Lane: render (v2/crates/render/** ONLY; standalone workspace, OUT of CI).
Why
macroquad's draw_mesh re-copies vertices and rewrites indices CPU->GPU EVERY frame (see the
comment in main.rs around the drawcall-capacity setup). At 512x512 that is ~3.5M verts/frame
re-streamed (R-13 BENCH: cpu_ms 9.56 avg / 13.43 p95 at dim=512). R-14's look pack (AO, chamfer
bevel) will roughly double vertex count — the copy cost is the wall the program hits at 60fps.
Retained buffers upload each chunk ONCE and draw per frame.
Scope
Port the PATTERN (not the code) from v1 crates/animata/src/render/gpu.rs (retained immutable
miniquad buffers, one draw call per visible chunk, own GLSL + MVP uniform + Pipeline with depth
test + backface culling) into the v2 render terrain path:
- New module
v2/crates/render/src/gpu_terrain.rs: build-once upload of each chunk's mesh
(positions, normals baked into vertex color shading as today, colors) into immutable miniquad
buffers; per-frame: frustum-cull chunks (existing AABBs), bind pipeline, set MVP from the
existing IsoCam, draw visible chunks.
- Runtime toggle
--retained (default OFF for now; flipping the default is R-15 proper, after
R-14 lands on top). Interactive key toggle optional.
- Both hex and cube mesh kinds must work (they share chunk struct).
- The egui/macroquad UI overlay and creature rendering keep using the macroquad path — only
terrain chunks move to retained buffers. Verify draw-order/depth interop (v1 does exactly this
mix; its gpu.rs comments document the pitfalls — depth Comparison::Less, clockwise cull).
Acceptance
- Screenshot PARITY:
--screenshot at --cam iso-default and iso-zoom-close, dim=512 seed=1,
retained OFF vs ON — pixel-identical or diff-explained in the PR (this is the guard against
silent depth/cull/format drift; R-13 makes it free). Attach both pairs.
- BENCH lines (dim=64 and dim=512, both modes) in the PR body: expect cpu_ms to DROP
substantially with --retained; wall_ms stays vsync-locked (documented macOS Metal behavior).
- No regression in interactive controls; 'T' hex/cube toggle works in retained mode.
cd v2/crates/render && bash ../../../scripts/compile-check.sh PASS (quoted) + clippy clean.
- Code-critic self-review, verdict block posted as PR comment, before ready-for-review.
Process
Branch r15a-retained-buffers off origin/render-r12-terragen-preview (fetch first — R-13 just
merged into it). PR with EXPLICIT --base. App launches via background execution (GOTCHAS).
VERIFY every screenshot by opening it with the Read tool before claiming anything about it —
a black/empty PNG is not evidence (precedent: R-13 F-B5).
Final report: STATUS line contract; status.md last.
R-15a — retained GPU buffers for v2 terrain (perf Lever 1, look-independent)
Part of the "hex diorama" program. Integration branch:
render-r12-terragen-preview— branchoff it, and PR back into it with
--base render-r12-terragen-previewEXPLICITLY (gh defaultsto main; see GOTCHAS.md, this exact rake was stepped on in PR #435).
Lane: render (
v2/crates/render/**ONLY; standalone workspace, OUT of CI).Why
macroquad's
draw_meshre-copies vertices and rewrites indices CPU->GPU EVERY frame (see thecomment in main.rs around the drawcall-capacity setup). At 512x512 that is ~3.5M verts/frame
re-streamed (R-13 BENCH: cpu_ms 9.56 avg / 13.43 p95 at dim=512). R-14's look pack (AO, chamfer
bevel) will roughly double vertex count — the copy cost is the wall the program hits at 60fps.
Retained buffers upload each chunk ONCE and draw per frame.
Scope
Port the PATTERN (not the code) from v1
crates/animata/src/render/gpu.rs(retained immutableminiquad buffers, one draw call per visible chunk, own GLSL + MVP uniform + Pipeline with depth
test + backface culling) into the v2 render terrain path:
v2/crates/render/src/gpu_terrain.rs: build-once upload of each chunk's mesh(positions, normals baked into vertex color shading as today, colors) into immutable miniquad
buffers; per-frame: frustum-cull chunks (existing AABBs), bind pipeline, set MVP from the
existing IsoCam, draw visible chunks.
--retained(default OFF for now; flipping the default is R-15 proper, afterR-14 lands on top). Interactive key toggle optional.
terrain chunks move to retained buffers. Verify draw-order/depth interop (v1 does exactly this
mix; its gpu.rs comments document the pitfalls — depth Comparison::Less, clockwise cull).
Acceptance
--screenshotat--cam iso-defaultandiso-zoom-close, dim=512 seed=1,retained OFF vs ON — pixel-identical or diff-explained in the PR (this is the guard against
silent depth/cull/format drift; R-13 makes it free). Attach both pairs.
substantially with --retained; wall_ms stays vsync-locked (documented macOS Metal behavior).
cd v2/crates/render && bash ../../../scripts/compile-check.shPASS (quoted) + clippy clean.Process
Branch
r15a-retained-buffersofforigin/render-r12-terragen-preview(fetch first — R-13 justmerged into it). PR with EXPLICIT --base. App launches via background execution (GOTCHAS).
VERIFY every screenshot by opening it with the Read tool before claiming anything about it —
a black/empty PNG is not evidence (precedent: R-13 F-B5).
Final report: STATUS line contract; status.md last.