fix(shaders): varyings meet by name on Vulkan, so the meadow's flowers draw

OpenGL links a vertex output to a fragment input by name; SPIR-V links them by location, and
glslang's --auto-map-locations numbered each stage in its own declaration order. The foliage
prepass's depth.frag declares v_wpos then v_uv where model.vert writes v_wpos, v_nrm, v_uv, so
the prepass read a normal as its texture coordinate, its alpha test cut every flower head and
leaf, and the lit pass (depth EQUAL) drew nothing over them. `ludic-dev shaders` now gives both
stages explicit locations: the vertex stage's out order numbers them and the fragment stage looks
each in up by name. All 45 variants checked: every fragment input sits on its vertex output.

Also:
- A clear still waiting for its pass when the framebuffer changes now runs on that framebuffer,
  instead of becoming the load op of whichever pass began next.
- R3D_DUMP_ATLAS writes every impostor and card atlas a run bakes (build/atlas_<n>_*.ppm); the
  40 baked on Vulkan match OpenGL's.

The PC's Vulkan frame now shows the flowers as OpenGL does, validation-clean. ludic-dev test 140
passed; OpenGL frames byte-identical at the five viewpoints; 59 self-tests pass.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Orkun ÇAKILKAYA 2026-09-15 12:50:54 +03:00
parent a674c9b372
commit 66940f9c0a
8 changed files with 81 additions and 4 deletions

View file

@ -738,7 +738,7 @@ function gpu_debug_check(tag: string) -> void { if gpu_kind == GPU_VK { return }
function gpu_fb_new() -> int { if gpu_kind == GPU_VK { gvk_fb_counter += 1; return gvk_fb_counter }; return gl_framebuffer() }
function gpu_fb_bind(fb: int) -> void {
if gpu_kind == GPU_VK { if fb != gvk_fb_cur { gvk_pass_end() }; gvk_fb_cur = fb } else { gl_bind_framebuffer(GL_FRAMEBUFFER, fb) }
if gpu_kind == GPU_VK { gvk_rebind(fb) } else { gl_bind_framebuffer(GL_FRAMEBUFFER, fb) }
gpu_fb_cur = fb
gpu_glcheck_after("fb bind")
}