feat(render3d): Vulkan in a macOS window through MoltenVK; window built-ins take a slice's elements; the NEAR_FADE SPIR-V

- a CAMetalLayer on the view (cocoa.ll win_metal_layer), VK_EXT_metal_surface, QuartzCore linked
  with Vk.*; the drawable measured after the layer sets the backing scale
- vk_mac.ll opens MoltenVK directly after any loader: a bundle ships only libMoltenVK.dylib
- a covered window is not presented to (win_visible); one frame in flight on macOS
  (R3D_VK_INFLIGHT), with images, buffers and descriptor pools held until it is done
- win_held / win_mouse / win_pad / win_touch / win_text / win_present pass slice elements (arg_buf):
  every windowed program died on its first input poll
- variants.list and SPIR-V for the three NEAR_FADE foliage programs

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Orkun ÇAKILKAYA 2026-09-27 00:52:45 +03:00
parent 9862ec82e3
commit 38d4ea72b1
25 changed files with 627 additions and 164 deletions

View file

@ -0,0 +1,4 @@
bump: patch
type: fix
**The foliage's near-fade programs have SPIR-V.** The three `NEAR_FADE` variants were missing
from `variants.list`, so on Vulkan the trees' and cards' programs failed to build.

View file

@ -0,0 +1,10 @@
bump: minor
type: feature
**render3d's Vulkan renderer runs in a macOS window, through MoltenVK.** `R3D_GFX=vk` (or
`gpu_request("vulkan")`) now presents to a `CAMetalLayer` on the window (`VK_EXT_metal_surface`,
the runtime's `win_metal_layer()`), where it used to fall back to OpenGL. The loader also opens
MoltenVK on its own - `Contents/Frameworks/libMoltenVK.dylib` in a bundle, beside the executable,
or `$VULKAN_SDK/lib` - so a game needs no Vulkan SDK to ship it. A covered window is not drawn to
(its layer would hold every frame for a second), and on macOS one frame stays in flight so the CPU
runs the next tick while the GPU draws. OpenGL stays the default: on an M4 Pro the Vulkan frame is
still about a third slower, most of it in the alpha-tested foliage.

View file

@ -0,0 +1,7 @@
bump: patch
type: fix
**A windowed program's input no longer stops it on the first frame.** Since slices carry their
length, the window's built-ins (`win_held`, `win_mouse`, `win_pad`, `win_touch`, `win_text`,
`win_present`) were handed the slice's header instead of its elements, so the platform wrote the
mouse position over the length and the next read failed its bounds check. They take the elements,
as an `extern` call already did.