WIP: feat(vk): the SPIR-V back end on MoltenVK and guest spans past one device allocation #848

Draft
mooki wants to merge 49 commits from mooki/Longshot:mac/topic-shader-backend into main
Member

Type: feat · Risk: medium · Tested on: macOS 26.7.1, Apple M4 Max (arm64; x86_64 under Rosetta) · Needs: Windows and Linux, any GPU

Why

On a Mac the game's shaders go from LS's SPIR-V back end through MoltenVK (SPIRV-Cross) to Metal, and many of them came out
wrong or not at all: texel formats MoltenVK cannot view read zeros; an empty descriptor slot is not empty (MoltenVK has no
nullDescriptor); a storage image read could return the value of a later write; Metal refused programs nesting more than 256
brackets or braces; vertex stages could not use the guest's warp operations; and a few giant programs took Metal minutes to
compile. Under them, one MoltenVK device allocation holds at most about 41.7 GB while the game's memory window is larger, so
a guest span past one allocation could not be bound at all; and under Rosetta host imports failed on split pages and were
asked again every frame, leaving about 1,640 draws a frame out. This PR is the shader and binding layer of the macOS port that
fixes those. See #420.

What changed

The back end can bind a descriptor as an array of pieces and read texel formats through integer carrier codecs; the renderer
admits guest buffers per operation, imports a span past one allocation as segments and binds what straddles a cut as
pieces; on MoltenVK the back end emulates null descriptors, keeps image reads in program order, bounds SPIRV-Cross's
expression and control-flow nesting, runs vertex stages' warp operations as one-lane warps, and searches storage buffer
tables and zeroes local memory in loops. Each is chosen by a Profile flag that make_profile sets on Apple (MoltenVK, some
also KosmicKrisp) or by alias_isolation (macOS); with them off every module, layout, push range and command is what it was.
The PR sits on topic 2 (vulkan-on-metal) and topic 3 (mvk-descriptor-limits), and merges #431 (fix(vk): scan the import table as far back as its largest live import, an every-platform fix with its own pull request, which #658 builds on: review it
there). The eighteen original pull requests, in commit order, one port and one merged-together fix:

  • segment planner (a0afe121; Was: #647): gpu/vk/span_segments.h
    (new, header only, no Vulkan): where to cut a guest span into segments. Test: tests/test_span_segments.py.
  • piece arrays in the back end (ad8133a3; Was: #648):
    RuntimeInfo::segmented; a listed descriptor becomes an array of pieces, each access through a helper walking the pieces by
    their lengths with constant indices (spirv_emit_context.cpp, emit_spirv_*.cpp, vk_shader.cpp). Test:
    tests/test_seg_shader.py.
  • texel carrier codecs (ff007b3d; Was: #649): a texel buffer's
    codec is part of the variant; the back end decodes and encodes ten formats MoltenVK cannot view through R8/R16/R32 UINT views
    with integer operations only (texel_codec.h, new, both levels); RX_VK_TEXEL_CODECS; kProgramCacheFormat 1 to 2;
    nx2/bake_ds/bake_ds.cpp stamps the switch.
  • per-operation admission and segments (cfb67020; Was: #658):
    on macOS (alias_isolation) each operation's guest buffers are admitted before it binds them, so two imports of the same
    bytes are never live in one submission, and an over-cap span is imported as segments (vk_memory.cpp, vk_draw.cpp,
    vk_replay.cpp, vk_xfer.cpp, vk_temporal.cpp, vk_texture.cpp). Tests: test_alias_admission.py,
    test_admission_handoff.py, test_segmented_domains.py and others (new).
  • the segmented consumers' contract (39a916d6; Was: #662):
    inert interfaces with their contracts (presence words, piece plans), and two fixes to gpu_span_bind's segmented path.
  • segmented consumers (7eb53a2d; Was: #663): storage and texel
    buffers, vertices, indices, indirect records, uniform buffers, copies, fills and inline writes that straddle a cut are bound
    as piece arrays or split at it (span_xfer.h, new); every empty slot gets a stand-in on Apple without nullDescriptor
    (null_dummies.h, new; null_dummies_make).
  • null descriptors in the back end (3ccdc8af; Was: #674): with
    Profile::emulate_null_descriptors a stand-in slot reads zero, drops writes and atomics and reports size 0, by a pushed
    presence word; kProgramCacheFormat 2 to 3 (the record head gains presence_words).
  • image reads in program order (2843f77e; Was: #675):
    Profile::materialize_image_reads stores each storage image read at the read and puts an image barrier before each write and
    atomic (MoltenVK).
  • expression nesting (85b977e3; Was: #676):
    Profile::bound_forwarded_depth, a pass that keeps SPIRV-Cross from nesting an expression past 32 instructions
    (msl_depth.cpp, new).
  • Rosetta host imports (48af6a54; Was: #686): frees and imports
    at whole 16 KiB hardware pages under Rosetta, and a refused import asked again only when its backing changes
    (darwin_mem.c, import_hold.h, darwin_import.h); Apple host ABI 26 (size 408).
  • the nesting model's reads (6ada3608; Was: #692): a value is a
    temporary only where SPIRV-Cross certainly reads it twice.
  • control-flow nesting (4c8dcc77; Was: #693):
    Profile::bound_scope_nesting moves the outermost deep construct into its own function until a function nests at most 128
    levels (msl_scope.cpp, new).
  • one-lane warps in vertex stages (1e976d5f; Was: #694): on
    MoltenVK the vertex-side stages the device does not list in subgroupSupportedStages run the guest's warp operations as
    lane 0 of a 32-lane warp.
  • RX_VK_SPV_PROFILE (d87bcd25; Was: #695): a log line per big
    module saying what its words are made of (spirv_profile.h, new); off by default.
  • storage buffer tables searched in loops (d58c00e2; Was: #696):
    Profile::search_tables_in_loops on MoltenVK and KosmicKrisp in every global memory fallback (RX_VK_GM_LOOP).
  • local memory zeroed by a loop (51da27ed; Was: #697):
    Profile::zero_local_memory_by_loop on MoltenVK (RX_VK_LOCAL_ZERO_LOOP=0 turns it off).
  • KosmicKrisp's image reads (234bb376; Was: #698):
    materialize_image_reads for KosmicKrisp's driver id too.
  • giant mesh fallbacks' shape (1bf322f4; Was: #787): a
    test-only generator of programs in that shape through the real back end (tests/giant_shape_ir.cpp,
    tests/test_giant_shape.py).
  • port, the stand-ins' clear (55cfa887): the Mac-only part of fix/async-safe-frees-i40 (c151fcea, MvkAsyncFix's F5c,
    reports/2026-11-15-mvk-async-fixes.md), which the every-platform #788 does not carry because null_dummies_make exists only
    on this stack: a stand-in clear not done in 5 s is waited for without a limit before its fence and command pool are destroyed
    (vk_texture.cpp); tests/test_null_dummies.py's make-slow-clear case.
  • merged-together fix, the profile fixtures (70cc5ba1, tests only): where #698's Apple-drivers fixture in
    tests/test_vendor_fixes.py meets #694's dev.subgroup_stages and Shader::Stage and #696's and #697's switches, and
    tests/test_subgroup_vertex.py's stub meets KosmicKrisp's driver id in make_profile, the fixtures did not build at the
    members' merge; each passes at its own pull request's head. The fixtures get stage.h, subgroup_stages, the
    table_loops_on and local_zero_loop_on stubs and the KosmicKrisp constant (28), as the integration build I41 has them
    (02b10861 and one line of 56092389).

Measurements

Verdict: works game-free on both Mac routes and, where the members probed the GPU (history), on MoltenVK: with its flag
off every member's modules, layouts and commands are its base's byte for byte; with it on, each member's fixture passes and
fails on its base. On the GPU the probes' failing shapes were refused or wrong before and made and exact after, and two members
cut Metal's pipeline creation (15.36 s to 1.45 s; 7,518 ms to 15-16 ms). The full suite at this head: 603 passed, 15 failed,
17 skipped against main's 543/33/17 on this Mac (topic 2's 576/15/17), with no check failing that passes on main.

Baseline: each member compared with its own base in the stack (as its description says), because each extends the back end and
the renderer of the members before it, which main has none of; the GPU rows are those members' probes (history), on modules
this stack's tests reproduce byte for byte; the port's row compares the port 55cfa887 with its parent 1bf322f4.

Hardware: macOS 26.7.1, Apple M4 Max (40-core GPU), MoltenVK 1.4.2, KosmicKrisp (SDK 1.4.363.1) for #698, 16-core CPU, 64 GB
Scene: none for the tests (game-free fixtures); the GPU probes are standalone programs, no game scene
Method: each member's fixture before and after (two interleaved runs in the members' own runs); at this head each once per
architecture; the probes once per CPU route; the suite once through tools/ls-suite.py
How to reproduce: the commands under Testing (tests/test_seg_shader.py, test_null_descriptors.py, test_msl_depth.py,
test_msl_scope.py, test_subgroup_vertex.py, test_gm_loop.py, test_local_zero.py, test_null_dummies.py ...)

Before: main @ aa95d35f After: this PR @ 70cc5ba1
#648, #649: plain SPIR-V main's byte for byte main's (16 of 16 plain modules), both arches
#648: segmented modules passing a pointer into a buffer array 3 modules, 54 calls (its first commit) 0
#663, #674: fixtures off macOS or with the flag off (the base's) byte for byte the base's
#675: storage image read before an atomic (GPU, TO-03) the later value 44 of 44 predictions, both CPU routes
#676, #692: deep expression chains (levels) 579, 579, 603, 303; 906, 603 32 each; MD-01 8 of 8 and MD-02 4 of 4 on the GPU
#693: control-flow nesting past 256 (levels; GPU, CG-01) refused at the 257th brace 108, 93, 108; made, exact words
#694: vertex pipelines with lane ids (GPU, SG-01) 14 refused 19 of 19 made, words equal to the CPU's
#686: imports of split 16 KiB pages under Rosetta (GPU, RI-01) refused, and asked again unchanged whole-page discard imported
#696: big program's pipeline creation (GPU, GL-01) 15.36 s; 2.97 s 1.45 s; 0.37 s
#697: pipeline creation with 4/16/64 KiB local memory (GPU, LM-01/02) 493 / 1,869 / 7,518 ms 15-16 ms at every size
#698: KosmicKrisp storage image read before an atomic (GPU, kk02) post-atomic in 128 of 128 lanes 44 of 44 with the flag
port: test_null_dummies.py make-slow-clear FAIL at 1bf322f4: one wait, none unbounded PASS, arm64 and x86_64
full game-free suite on this Mac 543 passed, 33 failed, 17 skipped 603 passed, 15 failed, 17 skipped
c4-seg-aa95-arm64: base tree (-DSEG_SHADER_BASE=1): 16 of 16 modules byte-identical (16 plain)
c4-nulldummies-arm64: make-slow-clear: waited for without a limit after its 5 s wait, before its fence and pool were destroyed
c4-nulldummies-parent-arm64: FAIL: make-slow-clear: the clear not done in 5 s is not waited for, without a limit, before its fence and pool are destroyed

Flags and settings

Three new switches (one changes a default on Apple), and one existing switch's default changes on Apple; none changes
anything on Windows or Linux by default.

Flag What it is Before this PR After this PR Effect Helps / doesn't help / untested Recommendation
RX_VK_TEXEL_CODECS 0 or 1: texel buffers of a format the GPU cannot view read and written through an R8/R16/R32 UINT view with the codec in the shader (no switch: native views, float reads) unset: on on macOS when the format query lacks one of the ten formats (MoltenVK 1.4.2), off elsewhere those programs are translated with codecs (the stamp gains "txcd") helps: macOS (once #663 binds the views); untested: =1 on Windows or Linux leave unset
RX_VK_SPV_PROFILE =1: one vk: spv profile line per big module translated (at most 200 a run) (no switch) unset: nothing log lines only; a profiled run translates slower helps: naming what makes Metal's slow compiles big; untested on the game off; for diagnosis, apart from timing runs
RX_VK_SPV_PROFILE_MIN=<words> the SPIR-V words a module must exceed for its line (no switch) 100000 which modules get a line as above 100000
RX_VK_GM_LOOP (existing) 0 or 1: storage buffer tables searched in a loop or written out loops on Intel's Mesa driver only also on MoltenVK and KosmicKrisp (macOS, with dynamic indexing), in every fallback Metal source size and compile time; more instructions run where a search runs helps: compile time (GL-01: 8-10x faster pipeline creation); untested: the game's own programs unset
RX_VK_LOCAL_ZERO_LOOP =0: local memory at computed offsets zeroed by its null initializer again (no switch: the initializer everywhere) unset: the loop on MoltenVK Metal source size and compile time helps: compile time (LM-02); other drivers: no effect unset

Existing switches #658 reads at one more place, unchanged: RX_VK_DLSS_ACTORS, RX_VK_GPU_DUMP, RX_VK_MESH_IND_COUNT_WORD,
RX_VK_NO_UPSCALE_STUB.

Testing

Tested: on macOS 26.7.1, Apple M4 Max, at this head 70cc5ba1 (a clean worktree), or at 55cfa887 for the runs before the
fix commit, which changes only tests/test_vendor_fixes.py and tests/test_subgroup_vertex.py:

  • The eighteen member pull requests' own tests, deduplicated, on arm64 and on x86_64 under Rosetta (each test's --arch x86_64
    or its fixture built with -arch x86_64): test_seg_shader against each member's own base tree (git archives of the 11
    bases the members used: 16 of 16, 32 of 32, 57 of 57, 125 of 139 (#675's 14 new modules) and 139 of 139 modules
    byte-identical, as each member had them), test_span_segments, test_null_descriptors, test_null_layout_push,
    test_native_float_atomic_add, test_program_record_head, test_amd_subgroup_profiles, test_msl_depth, test_msl_scope,
    test_subgroup_vertex (three bases), test_spv_profile, test_gm_loop, test_local_zero, test_vendor_fixes,
    test_split_ub_flush, test_import_buffer_binding, test_rosetta_import_geometry, test_import_hold,
    nx2/test_import_windows, test_vk_darwin_admission, test_darwin_renderer, test_darwin_guest_memory,
    test_macos_build_flags, test_giant_shape, the pure-Python test_bake_ds, test_program_cache_format and
    test_program_stamp_knobs, #658's 14 renderer checks (all exit 0, test_mirror_trim among them now) and its 20 fixture
    cases, two of them controls, on both arches (40 runs, all exit 0), and #663's 60 consumer checks (positive and negative,
    both arches): 102 logged jobs (the 14 checks, the 40 cases and the 60 consumer checks one job each). Every one passes
    but these, each explained: test_vendor_fixes and test_subgroup_vertex did not build their fixtures at 55cfa887 (the
    members' meeting the fix commit repairs) and pass at 70cc5ba1 on both arches (8 runs); test_seg_shader against #662's
    base 5d169c3b does not build its fixture at this head, as at #674's head (#674's test reads a base with codecs as #663's
    generation), and passes at #662's head; the three Rosetta consumer positives the system killed (exit -9, no crash report)
    passed on their one rerun, as in #663's own runs; seg-bind's two positives differ from #663's base 918e6214 only by
    #646's update-after-bind layout flag (the fixture's device is MoltenVK) and pass against that base with #646 merged in;
    nx2/bake_ds/bake_ds.cpp does not compile on macOS (environ undeclared: the Linux offline tool, as at #648's and #649's
    heads) and compiles on both arches with a one-line extern char **environ; prelude.
  • The port: tests/test_null_dummies.py --cxx clang++ --headers <Vulkan-Headers> at 55cfa887: pass on arm64 and with
    --arch x86_64 under Rosetta (make-slow-clear: waited for without a limit after its 5 s wait); at its parent 1bf322f4
    with the port's two test files (a scratch worktree): FAIL at make-slow-clear on both (one wait, none unbounded).
    gpu/vk/vk_texture.cpp compiled whole at 55cfa887 with the tree's own nx2/build.py macOS commands, arm64 and x86_64:
    exit 0.
  • python -I -B tests/run_all.py through tools/ls-suite.py at this head 70cc5ba1: 603 passed, 15 failed, 17 skipped,
    against main aa95d35f's 543/33/17 on this Mac, compared by test name: no check that passes on main fails here. Against
    topic 2's head (576/15/17) the only differences are 27 new tests, all passing: this PR's 24, topic 3's test_set_for_tables
    and test_set_for_lengths, and #431's test_import_reach; against main also topic 1's differences as its description lists
    them. The 15 failures fail on main too, on this Mac: test_readback_late, test_appimage_player_build,
    test_options_budget_once, test_vk_pgo, test_crash_dialog, test_walk_key, test_lift_cleanup_error,
    test_game_layout, test_options_path, test_make_game_cache, test_cpm_discovery, test_pipeline_tour,
    test_linux_preflight, test_env_on, test_split_giants.
  • The renderer's link check at 55cfa887 (the fix commit changes tests only; every mkwvk:: name one file declares and
    another defines; each defining .cpp
    compiled with the tree's own renderer_flags(), arm64 and x86_64): 0 of 629 declared names lack a definition, 66 of 66
    objects compiled, 573 cross-file symbols per architecture all defined.
  • Off Apple (unifdef -U__APPLE__ of every changed non-test C/C++ file against this PR's base c1229ac2, compared as tokens):
    7 files are the base's text; 30 differ and 10 new files have code off Apple. These are by design: the back end's new paths
    are chosen at run time by Profile flags and the renderer's by alias_isolation, gpu_span_any() and null_dummies_on(),
    all off on Windows and Linux, so the code is compiled there and not reached: emit_spirv*.cpp, spirv_emit_context.*,
    profile.h, runtime_info.h, bindings.h, emit_spirv.h, emit_spirv_instructions.h (#648, #649, #662, #674-#676,
    #693, #694, #696, #697), the new msl_depth.*, msl_scope.*, texel_codec.h (both), span_segments.h, span_xfer.h,
    null_dummies.h, spirv_profile.h; vk_shader.cpp/.h and vk_progcache.cpp (the variant keys, stamp words and
    kProgramCacheFormat 3, every platform); vk_draw.cpp, vk_memory.cpp, vk_replay.cpp, vk_xfer.cpp, vk_temporal.cpp,
    vk_texture.cpp/.h, vk_internal.h (#658, #662, #663: each path starts with a test that is false off macOS; the port's
    two lines are in null_dummies_make, which returns at once off Apple); vk_main.cpp (#694 reads subgroupSupportedStages);
    #686's darwin_import.h, import_hold.h, host/posix/darwin_mem.h and its vk_memory.cpp/vk_replay.cpp lines (comments,
    an unused type, an empty report function); nx2/bake_ds/bake_ds.cpp (#649: one more switch name in its stamp's list).
  • macOS game runs with these commits in the stack (integration builds carrying this topic's members): arm64, windowless: run
    E9a on I41 78ec1c47: a 1,197 s hold in play, 12 of 12 must-shows, 0 skipped draws, a clean end
    (reports/2026-11-15-mac-perf-E9.md); x86_64 under Rosetta: run #34 on I38 3f872b0c: 16 m 52 s of play, every draw
    drawn, 19 of 19 checks, a clean exit (reports/2026-11-14-mac-startup-34-x86_64.md).

Not tested: Windows and Linux: nothing was built or run there (the test request below). No GPU run at this head (the probes
are history, on modules the tests reproduce byte for byte); no game run has reached a segmented domain yet; the cost of the
null-descriptor guards, the stored image reads and the one-lane warps in a real frame; RX_VK_TEXEL_CODECS=1 off macOS;
KosmicKrisp in a game.

Must be tested:

  • Windows and Linux, any GPU: build this PR and main aa95d35f the same way, run python -I -B tests/run_all.py on each and
    start each to the title, expecting the new tests to pass or skip with their macOS reason, no other check to change status,
    and the vk: lines to match main's (the shaders and the program cache are prepared again once) (Test Farm: @Beanstalk
    windows linux, build, run_all and start to the title)

Risks

What could break: every platform: the back end's emit paths and the renderer's binding paths changed under flags that are
off there; a mistake in a flag's gate would change modules or commands off macOS (the fixtures check them byte for byte
against the bases). On macOS: the null-descriptor guards, stored image reads and barriers, one-lane warps and nesting bounds
cost instructions (not measured in a frame); segmented binding has not run in a game.

Turning it off: RX_VK_TEXEL_CODECS=0, RX_VK_GM_LOOP=0, RX_VK_LOCAL_ZERO_LOOP=0; the other fixes follow the driver
with no switch: revert the PR.

Compatibility: every platform prepares its shaders again once (the translator's stamp goes from 6241b7736c8060e3 to
ba2e3585119b57a6) and rebuilds its program cache once (kProgramCacheFormat 1 to 3). The vk ABI: MKWVK_API_VERSION is 26
on macOS only (size 408; the macOS executable and renderer are built together); Windows and Linux keep main's 23. Saves and
longshot_options.ini are unchanged.

Issues

See #420. The macOS topic PRs, merged in this order; "topic N" in each description means these: 1 #845 (macos-host), 2 #846 (vulkan-on-metal, on 1), 3 #847 (mvk-descriptor-limits), 4 #848 (shader-backend, on 2, 3 and #431), 5 #849 (precompile-metal, on 4), 6 #850 (draw-path, on 4), 7 #851 (draw-path-quads-mesh, on 6, #705 and #707), 8 #852 (mac-perf, on 7).

Checklist

Everyone

  • One topic.
  • The title is a Conventional Commit (type(scope): description) of the status line's type.
  • Why gives the reason plainly and links the issues that fit (the tracker searched).
  • Measurements has a verdict, or one line saying why there is nothing to measure.
  • Testing names what was tested, what wasn't, and what must still be tested, where and how.
  • Rebased on current main: on aa95d35f (through topics 2 and 3 and #431).
  • python -I -B tests/run_all.py passes (any failure that also fails on main is named). (macOS: 603/15/17, the 15 failures also fail on main, named under Testing; Windows and Linux: the test request.)
  • No game files, dumps, build output or generated files.
  • third_party/ untouched (a new folder with a PROVENANCE.md instead).
  • The license is OK: GPL-3.0-or-later, nothing incompatible and nothing decompiled.

When it applies

  • AI assistance recorded with Assisted-by: / Co-Authored-By: trailers.
  • Switches documented (docs/development.md; the README for a menu row) and shipped at their recommended value.
  • MKWVK_API_VERSION bumped (gpu/vk/vk_api.h's MkwVkHost or MkwVkRenderer changed).
  • A game-free test added for the fix, failing on main and passing here.
  • A check under tests/ that reads changed source updated in this PR, not weakened.
  • Host code builds on both Windows (llvm-mingw) and Linux, with UTF-8 paths. (Not built there yet: the test request.)
  • Docs updated.
**Type:** feat · **Risk:** medium · **Tested on:** macOS 26.7.1, Apple M4 Max (arm64; x86_64 under Rosetta) · **Needs:** Windows and Linux, any GPU ## Why On a Mac the game's shaders go from LS's SPIR-V back end through MoltenVK (SPIRV-Cross) to Metal, and many of them came out wrong or not at all: texel formats MoltenVK cannot view read zeros; an empty descriptor slot is not empty (MoltenVK has no `nullDescriptor`); a storage image read could return the value of a later write; Metal refused programs nesting more than 256 brackets or braces; vertex stages could not use the guest's warp operations; and a few giant programs took Metal minutes to compile. Under them, one MoltenVK device allocation holds at most about 41.7 GB while the game's memory window is larger, so a guest span past one allocation could not be bound at all; and under Rosetta host imports failed on split pages and were asked again every frame, leaving about 1,640 draws a frame out. This PR is the shader and binding layer of the macOS port that fixes those. See #420. ## What changed The back end can bind a descriptor as an array of pieces and read texel formats through integer carrier codecs; the renderer admits guest buffers per operation, imports a span past one allocation as segments and binds what straddles a cut as pieces; on MoltenVK the back end emulates null descriptors, keeps image reads in program order, bounds SPIRV-Cross's expression and control-flow nesting, runs vertex stages' warp operations as one-lane warps, and searches storage buffer tables and zeroes local memory in loops. Each is chosen by a `Profile` flag that `make_profile` sets on Apple (MoltenVK, some also KosmicKrisp) or by `alias_isolation` (macOS); with them off every module, layout, push range and command is what it was. The PR sits on topic 2 (`vulkan-on-metal`) and topic 3 (`mvk-descriptor-limits`), and merges #431 (`fix(vk): scan the import table as far back as its largest live import`, an every-platform fix with its own pull request, which #658 builds on: review it there). The eighteen original pull requests, in commit order, one port and one merged-together fix: - segment planner (`a0afe121`; Was: [#647](https://git.magicbean.dev/MagicBeanDev/Longshot/pulls/647)): `gpu/vk/span_segments.h` (new, header only, no Vulkan): where to cut a guest span into segments. Test: `tests/test_span_segments.py`. - piece arrays in the back end (`ad8133a3`; Was: [#648](https://git.magicbean.dev/MagicBeanDev/Longshot/pulls/648)): `RuntimeInfo::segmented`; a listed descriptor becomes an array of pieces, each access through a helper walking the pieces by their lengths with constant indices (`spirv_emit_context.cpp`, `emit_spirv_*.cpp`, `vk_shader.cpp`). Test: `tests/test_seg_shader.py`. - texel carrier codecs (`ff007b3d`; Was: [#649](https://git.magicbean.dev/MagicBeanDev/Longshot/pulls/649)): a texel buffer's codec is part of the variant; the back end decodes and encodes ten formats MoltenVK cannot view through R8/R16/R32 UINT views with integer operations only (`texel_codec.h`, new, both levels); `RX_VK_TEXEL_CODECS`; `kProgramCacheFormat` 1 to 2; `nx2/bake_ds/bake_ds.cpp` stamps the switch. - per-operation admission and segments (`cfb67020`; Was: [#658](https://git.magicbean.dev/MagicBeanDev/Longshot/pulls/658)): on macOS (`alias_isolation`) each operation's guest buffers are admitted before it binds them, so two imports of the same bytes are never live in one submission, and an over-cap span is imported as segments (`vk_memory.cpp`, `vk_draw.cpp`, `vk_replay.cpp`, `vk_xfer.cpp`, `vk_temporal.cpp`, `vk_texture.cpp`). Tests: `test_alias_admission.py`, `test_admission_handoff.py`, `test_segmented_domains.py` and others (new). - the segmented consumers' contract (`39a916d6`; Was: [#662](https://git.magicbean.dev/MagicBeanDev/Longshot/pulls/662)): inert interfaces with their contracts (presence words, piece plans), and two fixes to `gpu_span_bind`'s segmented path. - segmented consumers (`7eb53a2d`; Was: [#663](https://git.magicbean.dev/MagicBeanDev/Longshot/pulls/663)): storage and texel buffers, vertices, indices, indirect records, uniform buffers, copies, fills and inline writes that straddle a cut are bound as piece arrays or split at it (`span_xfer.h`, new); every empty slot gets a stand-in on Apple without `nullDescriptor` (`null_dummies.h`, new; `null_dummies_make`). - null descriptors in the back end (`3ccdc8af`; Was: [#674](https://git.magicbean.dev/MagicBeanDev/Longshot/pulls/674)): with `Profile::emulate_null_descriptors` a stand-in slot reads zero, drops writes and atomics and reports size 0, by a pushed presence word; `kProgramCacheFormat` 2 to 3 (the record head gains `presence_words`). - image reads in program order (`2843f77e`; Was: [#675](https://git.magicbean.dev/MagicBeanDev/Longshot/pulls/675)): `Profile::materialize_image_reads` stores each storage image read at the read and puts an image barrier before each write and atomic (MoltenVK). - expression nesting (`85b977e3`; Was: [#676](https://git.magicbean.dev/MagicBeanDev/Longshot/pulls/676)): `Profile::bound_forwarded_depth`, a pass that keeps SPIRV-Cross from nesting an expression past 32 instructions (`msl_depth.cpp`, new). - Rosetta host imports (`48af6a54`; Was: [#686](https://git.magicbean.dev/MagicBeanDev/Longshot/pulls/686)): frees and imports at whole 16 KiB hardware pages under Rosetta, and a refused import asked again only when its backing changes (`darwin_mem.c`, `import_hold.h`, `darwin_import.h`); Apple host ABI 26 (size 408). - the nesting model's reads (`6ada3608`; Was: [#692](https://git.magicbean.dev/MagicBeanDev/Longshot/pulls/692)): a value is a temporary only where SPIRV-Cross certainly reads it twice. - control-flow nesting (`4c8dcc77`; Was: [#693](https://git.magicbean.dev/MagicBeanDev/Longshot/pulls/693)): `Profile::bound_scope_nesting` moves the outermost deep construct into its own function until a function nests at most 128 levels (`msl_scope.cpp`, new). - one-lane warps in vertex stages (`1e976d5f`; Was: [#694](https://git.magicbean.dev/MagicBeanDev/Longshot/pulls/694)): on MoltenVK the vertex-side stages the device does not list in `subgroupSupportedStages` run the guest's warp operations as lane 0 of a 32-lane warp. - `RX_VK_SPV_PROFILE` (`d87bcd25`; Was: [#695](https://git.magicbean.dev/MagicBeanDev/Longshot/pulls/695)): a log line per big module saying what its words are made of (`spirv_profile.h`, new); off by default. - storage buffer tables searched in loops (`d58c00e2`; Was: [#696](https://git.magicbean.dev/MagicBeanDev/Longshot/pulls/696)): `Profile::search_tables_in_loops` on MoltenVK and KosmicKrisp in every global memory fallback (`RX_VK_GM_LOOP`). - local memory zeroed by a loop (`51da27ed`; Was: [#697](https://git.magicbean.dev/MagicBeanDev/Longshot/pulls/697)): `Profile::zero_local_memory_by_loop` on MoltenVK (`RX_VK_LOCAL_ZERO_LOOP=0` turns it off). - KosmicKrisp's image reads (`234bb376`; Was: [#698](https://git.magicbean.dev/MagicBeanDev/Longshot/pulls/698)): `materialize_image_reads` for KosmicKrisp's driver id too. - giant mesh fallbacks' shape (`1bf322f4`; Was: [#787](https://git.magicbean.dev/MagicBeanDev/Longshot/pulls/787)): a test-only generator of programs in that shape through the real back end (`tests/giant_shape_ir.cpp`, `tests/test_giant_shape.py`). - port, the stand-ins' clear (`55cfa887`): the Mac-only part of `fix/async-safe-frees-i40` (`c151fcea`, MvkAsyncFix's F5c, `reports/2026-11-15-mvk-async-fixes.md`), which the every-platform #788 does not carry because `null_dummies_make` exists only on this stack: a stand-in clear not done in 5 s is waited for without a limit before its fence and command pool are destroyed (`vk_texture.cpp`); `tests/test_null_dummies.py`'s `make-slow-clear` case. - merged-together fix, the profile fixtures (`70cc5ba1`, tests only): where #698's Apple-drivers fixture in `tests/test_vendor_fixes.py` meets #694's `dev.subgroup_stages` and `Shader::Stage` and #696's and #697's switches, and `tests/test_subgroup_vertex.py`'s stub meets KosmicKrisp's driver id in `make_profile`, the fixtures did not build at the members' merge; each passes at its own pull request's head. The fixtures get `stage.h`, `subgroup_stages`, the `table_loops_on` and `local_zero_loop_on` stubs and the KosmicKrisp constant (28), as the integration build I41 has them (`02b10861` and one line of `56092389`). ## Measurements **Verdict:** works game-free on both Mac routes and, where the members probed the GPU (history), on MoltenVK: with its flag off every member's modules, layouts and commands are its base's byte for byte; with it on, each member's fixture passes and fails on its base. On the GPU the probes' failing shapes were refused or wrong before and made and exact after, and two members cut Metal's pipeline creation (15.36 s to 1.45 s; 7,518 ms to 15-16 ms). The full suite at this head: 603 passed, 15 failed, 17 skipped against main's 543/33/17 on this Mac (topic 2's 576/15/17), with no check failing that passes on main. Baseline: each member compared with its own base in the stack (as its description says), because each extends the back end and the renderer of the members before it, which main has none of; the GPU rows are those members' probes (history), on modules this stack's tests reproduce byte for byte; the port's row compares the port `55cfa887` with its parent `1bf322f4`. Hardware: macOS 26.7.1, Apple M4 Max (40-core GPU), MoltenVK 1.4.2, KosmicKrisp (SDK 1.4.363.1) for #698, 16-core CPU, 64 GB Scene: none for the tests (game-free fixtures); the GPU probes are standalone programs, no game scene Method: each member's fixture before and after (two interleaved runs in the members' own runs); at this head each once per architecture; the probes once per CPU route; the suite once through `tools/ls-suite.py` How to reproduce: the commands under Testing (`tests/test_seg_shader.py`, `test_null_descriptors.py`, `test_msl_depth.py`, `test_msl_scope.py`, `test_subgroup_vertex.py`, `test_gm_loop.py`, `test_local_zero.py`, `test_null_dummies.py` ...) | | Before: main @ aa95d35f | After: this PR @ 70cc5ba1 | |---|---|---| | #648, #649: plain SPIR-V | main's | byte for byte main's (16 of 16 plain modules), both arches | | #648: segmented modules passing a pointer into a buffer array | 3 modules, 54 calls (its first commit) | 0 | | #663, #674: fixtures off macOS or with the flag off | (the base's) | byte for byte the base's | | #675: storage image read before an atomic (GPU, TO-03) | the later value | 44 of 44 predictions, both CPU routes | | #676, #692: deep expression chains (levels) | 579, 579, 603, 303; 906, 603 | 32 each; MD-01 8 of 8 and MD-02 4 of 4 on the GPU | | #693: control-flow nesting past 256 (levels; GPU, CG-01) | refused at the 257th brace | 108, 93, 108; made, exact words | | #694: vertex pipelines with lane ids (GPU, SG-01) | 14 refused | 19 of 19 made, words equal to the CPU's | | #686: imports of split 16 KiB pages under Rosetta (GPU, RI-01) | refused, and asked again unchanged | whole-page discard imported | | #696: big program's pipeline creation (GPU, GL-01) | 15.36 s; 2.97 s | 1.45 s; 0.37 s | | #697: pipeline creation with 4/16/64 KiB local memory (GPU, LM-01/02) | 493 / 1,869 / 7,518 ms | 15-16 ms at every size | | #698: KosmicKrisp storage image read before an atomic (GPU, kk02) | post-atomic in 128 of 128 lanes | 44 of 44 with the flag | | port: `test_null_dummies.py` `make-slow-clear` | FAIL at `1bf322f4`: one wait, none unbounded | PASS, arm64 and x86_64 | | full game-free suite on this Mac | 543 passed, 33 failed, 17 skipped | 603 passed, 15 failed, 17 skipped | ``` c4-seg-aa95-arm64: base tree (-DSEG_SHADER_BASE=1): 16 of 16 modules byte-identical (16 plain) c4-nulldummies-arm64: make-slow-clear: waited for without a limit after its 5 s wait, before its fence and pool were destroyed c4-nulldummies-parent-arm64: FAIL: make-slow-clear: the clear not done in 5 s is not waited for, without a limit, before its fence and pool are destroyed ``` ### Flags and settings Three new switches (one changes a default on Apple), and one existing switch's default changes on Apple; none changes anything on Windows or Linux by default. | Flag | What it is | Before this PR | After this PR | Effect | Helps / doesn't help / untested | Recommendation | |---|---|---|---|---|---|---| | `RX_VK_TEXEL_CODECS` | `0` or `1`: texel buffers of a format the GPU cannot view read and written through an R8/R16/R32 UINT view with the codec in the shader | (no switch: native views, float reads) | unset: on on macOS when the format query lacks one of the ten formats (MoltenVK 1.4.2), off elsewhere | those programs are translated with codecs (the stamp gains "txcd") | helps: macOS (once #663 binds the views); untested: `=1` on Windows or Linux | leave unset | | `RX_VK_SPV_PROFILE` | `=1`: one `vk: spv profile` line per big module translated (at most 200 a run) | (no switch) | unset: nothing | log lines only; a profiled run translates slower | helps: naming what makes Metal's slow compiles big; untested on the game | off; for diagnosis, apart from timing runs | | `RX_VK_SPV_PROFILE_MIN=<words>` | the SPIR-V words a module must exceed for its line | (no switch) | 100000 | which modules get a line | as above | 100000 | | `RX_VK_GM_LOOP` (existing) | `0` or `1`: storage buffer tables searched in a loop or written out | loops on Intel's Mesa driver only | also on MoltenVK and KosmicKrisp (macOS, with dynamic indexing), in every fallback | Metal source size and compile time; more instructions run where a search runs | helps: compile time (GL-01: 8-10x faster pipeline creation); untested: the game's own programs | unset | | `RX_VK_LOCAL_ZERO_LOOP` | `=0`: local memory at computed offsets zeroed by its null initializer again | (no switch: the initializer everywhere) | unset: the loop on MoltenVK | Metal source size and compile time | helps: compile time (LM-02); other drivers: no effect | unset | Existing switches #658 reads at one more place, unchanged: `RX_VK_DLSS_ACTORS`, `RX_VK_GPU_DUMP`, `RX_VK_MESH_IND_COUNT_WORD`, `RX_VK_NO_UPSCALE_STUB`. ## Testing **Tested:** on macOS 26.7.1, Apple M4 Max, at this head `70cc5ba1` (a clean worktree), or at `55cfa887` for the runs before the fix commit, which changes only `tests/test_vendor_fixes.py` and `tests/test_subgroup_vertex.py`: - The eighteen member pull requests' own tests, deduplicated, on arm64 and on x86_64 under Rosetta (each test's `--arch x86_64` or its fixture built with `-arch x86_64`): `test_seg_shader` against each member's own base tree (git archives of the 11 bases the members used: 16 of 16, 32 of 32, 57 of 57, 125 of 139 (#675's 14 new modules) and 139 of 139 modules byte-identical, as each member had them), `test_span_segments`, `test_null_descriptors`, `test_null_layout_push`, `test_native_float_atomic_add`, `test_program_record_head`, `test_amd_subgroup_profiles`, `test_msl_depth`, `test_msl_scope`, `test_subgroup_vertex` (three bases), `test_spv_profile`, `test_gm_loop`, `test_local_zero`, `test_vendor_fixes`, `test_split_ub_flush`, `test_import_buffer_binding`, `test_rosetta_import_geometry`, `test_import_hold`, `nx2/test_import_windows`, `test_vk_darwin_admission`, `test_darwin_renderer`, `test_darwin_guest_memory`, `test_macos_build_flags`, `test_giant_shape`, the pure-Python `test_bake_ds`, `test_program_cache_format` and `test_program_stamp_knobs`, #658's 14 renderer checks (all exit 0, `test_mirror_trim` among them now) and its 20 fixture cases, two of them controls, on both arches (40 runs, all exit 0), and #663's 60 consumer checks (positive and negative, both arches): 102 logged jobs (the 14 checks, the 40 cases and the 60 consumer checks one job each). Every one passes but these, each explained: `test_vendor_fixes` and `test_subgroup_vertex` did not build their fixtures at `55cfa887` (the members' meeting the fix commit repairs) and pass at `70cc5ba1` on both arches (8 runs); `test_seg_shader` against #662's base `5d169c3b` does not build its fixture at this head, as at #674's head (#674's test reads a base with codecs as #663's generation), and passes at #662's head; the three Rosetta consumer positives the system killed (exit -9, no crash report) passed on their one rerun, as in #663's own runs; `seg-bind`'s two positives differ from #663's base `918e6214` only by #646's update-after-bind layout flag (the fixture's device is MoltenVK) and pass against that base with #646 merged in; `nx2/bake_ds/bake_ds.cpp` does not compile on macOS (`environ` undeclared: the Linux offline tool, as at #648's and #649's heads) and compiles on both arches with a one-line `extern char **environ;` prelude. - The port: `tests/test_null_dummies.py --cxx clang++ --headers <Vulkan-Headers>` at `55cfa887`: pass on arm64 and with `--arch x86_64` under Rosetta (`make-slow-clear: waited for without a limit after its 5 s wait`); at its parent `1bf322f4` with the port's two test files (a scratch worktree): FAIL at `make-slow-clear` on both (one wait, none unbounded). `gpu/vk/vk_texture.cpp` compiled whole at `55cfa887` with the tree's own `nx2/build.py` macOS commands, arm64 and x86_64: exit 0. - `python -I -B tests/run_all.py` through `tools/ls-suite.py` at this head `70cc5ba1`: 603 passed, 15 failed, 17 skipped, against main `aa95d35f`'s 543/33/17 on this Mac, compared by test name: no check that passes on main fails here. Against topic 2's head (576/15/17) the only differences are 27 new tests, all passing: this PR's 24, topic 3's `test_set_for_tables` and `test_set_for_lengths`, and #431's `test_import_reach`; against main also topic 1's differences as its description lists them. The 15 failures fail on main too, on this Mac: `test_readback_late`, `test_appimage_player_build`, `test_options_budget_once`, `test_vk_pgo`, `test_crash_dialog`, `test_walk_key`, `test_lift_cleanup_error`, `test_game_layout`, `test_options_path`, `test_make_game_cache`, `test_cpm_discovery`, `test_pipeline_tour`, `test_linux_preflight`, `test_env_on`, `test_split_giants`. - The renderer's link check at `55cfa887` (the fix commit changes tests only; every `mkwvk::` name one file declares and another defines; each defining `.cpp` compiled with the tree's own `renderer_flags()`, arm64 and x86_64): 0 of 629 declared names lack a definition, 66 of 66 objects compiled, 573 cross-file symbols per architecture all defined. - Off Apple (`unifdef -U__APPLE__` of every changed non-test C/C++ file against this PR's base `c1229ac2`, compared as tokens): 7 files are the base's text; 30 differ and 10 new files have code off Apple. These are by design: the back end's new paths are chosen at run time by `Profile` flags and the renderer's by `alias_isolation`, `gpu_span_any()` and `null_dummies_on()`, all off on Windows and Linux, so the code is compiled there and not reached: `emit_spirv*.cpp`, `spirv_emit_context.*`, `profile.h`, `runtime_info.h`, `bindings.h`, `emit_spirv.h`, `emit_spirv_instructions.h` (#648, #649, #662, #674-#676, #693, #694, #696, #697), the new `msl_depth.*`, `msl_scope.*`, `texel_codec.h` (both), `span_segments.h`, `span_xfer.h`, `null_dummies.h`, `spirv_profile.h`; `vk_shader.cpp`/`.h` and `vk_progcache.cpp` (the variant keys, stamp words and `kProgramCacheFormat` 3, every platform); `vk_draw.cpp`, `vk_memory.cpp`, `vk_replay.cpp`, `vk_xfer.cpp`, `vk_temporal.cpp`, `vk_texture.cpp`/`.h`, `vk_internal.h` (#658, #662, #663: each path starts with a test that is false off macOS; the port's two lines are in `null_dummies_make`, which returns at once off Apple); `vk_main.cpp` (#694 reads `subgroupSupportedStages`); #686's `darwin_import.h`, `import_hold.h`, `host/posix/darwin_mem.h` and its `vk_memory.cpp`/`vk_replay.cpp` lines (comments, an unused type, an empty report function); `nx2/bake_ds/bake_ds.cpp` (#649: one more switch name in its stamp's list). - macOS game runs with these commits in the stack (integration builds carrying this topic's members): arm64, windowless: run E9a on I41 `78ec1c47`: a 1,197 s hold in play, 12 of 12 must-shows, 0 skipped draws, a clean end (`reports/2026-11-15-mac-perf-E9.md`); x86_64 under Rosetta: run #34 on I38 `3f872b0c`: 16 m 52 s of play, every draw drawn, 19 of 19 checks, a clean exit (`reports/2026-11-14-mac-startup-34-x86_64.md`). **Not tested:** Windows and Linux: nothing was built or run there (the test request below). No GPU run at this head (the probes are history, on modules the tests reproduce byte for byte); no game run has reached a segmented domain yet; the cost of the null-descriptor guards, the stored image reads and the one-lane warps in a real frame; `RX_VK_TEXEL_CODECS=1` off macOS; KosmicKrisp in a game. **Must be tested:** - Windows and Linux, any GPU: build this PR and main `aa95d35f` the same way, run `python -I -B tests/run_all.py` on each and start each to the title, expecting the new tests to pass or skip with their macOS reason, no other check to change status, and the `vk:` lines to match main's (the shaders and the program cache are prepared again once) (Test Farm: @Beanstalk windows linux, build, run_all and start to the title) ## Risks **What could break:** every platform: the back end's emit paths and the renderer's binding paths changed under flags that are off there; a mistake in a flag's gate would change modules or commands off macOS (the fixtures check them byte for byte against the bases). On macOS: the null-descriptor guards, stored image reads and barriers, one-lane warps and nesting bounds cost instructions (not measured in a frame); segmented binding has not run in a game. **Turning it off:** `RX_VK_TEXEL_CODECS=0`, `RX_VK_GM_LOOP=0`, `RX_VK_LOCAL_ZERO_LOOP=0`; the other fixes follow the driver with no switch: revert the PR. **Compatibility:** every platform prepares its shaders again once (the translator's stamp goes from `6241b7736c8060e3` to `ba2e3585119b57a6`) and rebuilds its program cache once (`kProgramCacheFormat` 1 to 3). The vk ABI: `MKWVK_API_VERSION` is 26 on macOS only (size 408; the macOS executable and renderer are built together); Windows and Linux keep main's 23. Saves and `longshot_options.ini` are unchanged. ## Issues See #420. The macOS topic PRs, merged in this order; "topic N" in each description means these: 1 #845 (macos-host), 2 #846 (vulkan-on-metal, on 1), 3 #847 (mvk-descriptor-limits), 4 #848 (shader-backend, on 2, 3 and #431), 5 #849 (precompile-metal, on 4), 6 #850 (draw-path, on 4), 7 #851 (draw-path-quads-mesh, on 6, #705 and #707), 8 #852 (mac-perf, on 7). ## Checklist ### Everyone - [x] One topic. - [x] The title is a Conventional Commit (`type(scope): description`) of the status line's type. - [x] Why gives the reason plainly and links the issues that fit (the tracker searched). - [x] Measurements has a verdict, or one line saying why there is nothing to measure. - [x] Testing names what was tested, what wasn't, and what must still be tested, where and how. - [x] Rebased on current `main`: on `aa95d35f` (through topics 2 and 3 and #431). - [ ] `python -I -B tests/run_all.py` passes (any failure that also fails on `main` is named). (macOS: 603/15/17, the 15 failures also fail on main, named under Testing; Windows and Linux: the test request.) - [x] No game files, dumps, build output or generated files. - [x] `third_party/` untouched (a new folder with a `PROVENANCE.md` instead). - [x] The license is OK: GPL-3.0-or-later, nothing incompatible and nothing decompiled. ### When it applies - [x] AI assistance recorded with `Assisted-by:` / `Co-Authored-By:` trailers. - [x] Switches documented (docs/development.md; the README for a menu row) and shipped at their recommended value. - [x] `MKWVK_API_VERSION` bumped (`gpu/vk/vk_api.h`'s `MkwVkHost` or `MkwVkRenderer` changed). - [x] A game-free test added for the fix, failing on `main` and passing here. - [x] A check under `tests/` that reads changed source updated in this PR, not weakened. - [ ] Host code builds on both Windows (llvm-mingw) and Linux, with UTF-8 paths. (Not built there yet: the test request.) - [x] Docs updated.
Every scan down vk_memory.cpp's import table by start (pool_lookup's
covering import and merge plan, bg_drain, prefetch_chunks,
import_in_background, memory_note_gpu_write and memory_guest_imported)
stopped once an import ended more than 1 GiB below its address, on the
belief that no import is larger than that. pool_lookup's own merge escape
leaves an import above 1 GiB over the smaller ones inside it ("left
overlapping"), and the device allows imports up to max_import_size: a scan
stopped at a small import inside a large one, missed the large one, and
the same bytes were imported again, two memories over the same bytes.

import_reach.h counts the live imports by span class; its bound is above
every live span, within twice the largest. imported_add and imported_take,
now the table's only ways in and out, keep the count. A scan stops only
where no import further down can reach its address, so it also stops
sooner than before when the imports are small. The covering-import checks
in pool_lookup and import_in_background look past the last import at or
below the range for the same reason.

Tests: test_import_reach.py runs the actual scans with a 4 GiB import over
a 16 MiB chunk, left by the merge escape (imports are recorded ranges: no
payload, no Vulkan, no game). Its lookup, query, note, drain, background
and prefetch cases fail on main 5e072fc8 and pass here, and a source check
keeps every change to the table in the two helpers. test_import_windows
runs pool_lookup with the helpers; test_mirror_gpu_only names the new
publication point.

Assisted-by: Claude Opus 5.5
Co-Authored-By: Claude Opus 5.5 <[email protected]>
test(vk): the readback refresh fixture runs memory_note_gpu_write with the import table's helpers
Some checks failed
CI / Python source checks (ubuntu-24.04, part 1/2) (pull_request) Has been skipped
CI / Python source checks (ubuntu-24.04, part 2/2) (pull_request) Has been skipped
CI / SPIR-V fixtures (global narrow load/store, direct surface atomics, F2I immediate) (pull_request) Has been skipped
Third-party parts / The same as upstream (pull_request) Has been skipped
Website / Website on Cloudflare (pull_request) Has been skipped
CI / Conventional Commit title (pull_request) Successful in 4s
CI / Workflow lint (actionlint) (pull_request) Successful in 7s
Guide screenshots / Guide images and local UI source review (pull_request) Failing after 6s
Third-party parts / As their notes say (pull_request) Successful in 10s
PR description / Description follows the template (pull_request_target) Successful in 5s
497be2d480
test_parallel_rb_refresh cuts memory_note_gpu_write out of vk_memory.cpp,
whose scan now stops at the live imports' reach: the fixture includes
import_reach.h, cuts live_reach, imported_add and imported_take beside it,
and puts its pool in the table through imported_add. It failed to build
at 11e9ee44 ("use of undeclared identifier 'import_reach'").

Assisted-by: Claude Opus 5.5
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Was: #454 (#454), branch mac/run-all at 264f826a7c (Sweep3, on main aa95d35f).

Its own commits, squashed:
- test: teach the game-free runner about macOS (45c54bc6f)
- test: skip main's new Windows-only guard check on macOS, and undo the SDK's vsnprintf macro in a fixture (264f826a7)

Assisted-by: Claude Opus 5.5
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Was: #477 (#477), branch mac/arm64-host at 0f021f29c1 (Sweep3, on main aa95d35f).

Its own commits, squashed:
- fix(runtime): compile host jumps and pause hints on macOS arm64 (0f021f29c)

Assisted-by: Claude Opus 5.5
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Was: #478 (#478), branch mac/guest-memory at dfb71ec850 (Sweep3, on main aa95d35f).

Its own commits, squashed:
- fix(runtime): preserve guest pages when discarding on macOS (b668404c8)
- fix(runtime): retain guest-page rounding in Darwin memory wrappers (e9c77d9f3)
- test(runtime): cut main's int hos_commit in the Darwin guest-memory test (7e737ce0f)
- test(runtime): follow main's HLE call counts in the Darwin guest-memory fixture (dfb71ec85)

Assisted-by: Claude Opus 5.5
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Was: #436 (#436), branch mac/fault-contexts at bccfd1c2e9 (Sweep3, on main aa95d35f).

Its own commits, squashed:
- fix(runtime): translate macOS fault contexts on both CPU routes (08940fb3d)
- test(runtime): keep Darwin fault checks native by default (7d7f99dcb)
- test(runtime): classify the fault bridge's fatal _exit in main's exit inventory (bccfd1c2e)

Assisted-by: Claude Opus 5.5
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Was: #437 (#437), branch mac/waits at beb8a2881a (Sweep3, on main aa95d35f).

Its own commits, squashed:
- fix(runtime): port Win32 waits and deadlines to macOS (2f05d007f)
- test(runtime): link Darwin waits into the pointer fixture (ef081688d)
- fix(macos): share address wait state through the executable (186a461c5)
- docs(runtime): describe the executable-owned macOS address-wait state (beb8a2881)

Assisted-by: Claude Opus 5.5
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Was: #438 (#438), branch mac/vk-admission at 681e37081d (Sweep3, on main aa95d35f).

Its own commits, squashed:
- feat(vk): add macOS Vulkan loader and device admission (6f34d00bc)
- test(vk): use semantic admission contracts (fdd161190)
- test(vk): follow main's LoadLibraryA and float-add choice in the admission fixture (3e088644f)
- test(vk): pin the admission ABI at main's version 23 and macOS 24 (4f4ca3c73)
- fix(macos): a window without Vulkan extensions ends as a clean exit, as main's exit inventory asks (681e37081)

Assisted-by: Claude Opus 5.5
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Was: #490 (#490), branch mac/darwin-host at 162a39dcd3 (Sweep3, on main aa95d35f).

It was stacked on #436, #437, #438, #454, #477, #478; their changes are the earlier commits here.

Its own commits, squashed:
- feat(macos): complete Darwin host lifecycle and diagnostics (71a9ed0bb)
- fix(macos): integrate profile consumers and joined-thread shutdown (f420761ab)
- docs(macos): describe Darwin profile symbol loading (04e40191a)
- test(macos): integration fix: cut the tagged HThread in the waits fixture (9c18e64c4)
- test(macos): integration fix: stub the kept startup in the display fixture (5f8d511e6)
- test(macos): integration fix: prof symbols run on macOS, not a skip (a1e73d31e)
- test(macos): the memory-notice fixture runs the Darwin query (f4d7aaf76)
- fix(macos): a failed swap query still shows the low-RAM notice (28ed288a2)
- test(macos): the Darwin LoadLibraryA keeps dlerror()'s text for hos_load_error (52faf1d3d)
- fix(macos): integration fix: main's process affinity for new threads is Linux-only (61ec2411b)
- fix(macos): the POSIX main's end after the game's thread marks the clean end, as main's exit inventory asks (162a39dcd)

Assisted-by: Claude Opus 5.5
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Was: #453 (#453), branch mac/build-flags at 8ca4bff7a4 (Sweep3, on main aa95d35f).

Its own commits, squashed:
- build(macos): discover dual-architecture toolchains and form Mach-O commands (499e3853a)
- test(macos): default real link fixtures to the process architecture (f6f6f042c)
- test(macos): isolate synthetic command paths from the test host (7c846ae91)
- build(macos): keep third_party/a64-kit as it is; nx2/darwin_toolchain.py makes its commands Mach-O (88054c966)
- build(macos): follow main's one-way renderer build and CPU target in the moved build code (a5b02633d)
- test(macos): the frozen Windows/Linux build arrays are main e090cc48's (c3009e01c)
- test: main's third-party objects test reads build.py with this PR's macOS names (8ca4bff7a)

Assisted-by: Claude Opus 5.5
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Was: #479 (#479), branch mac/build-complete at 1bd269c7e2 (Sweep3, on main aa95d35f).

It was stacked on #437, #453; their changes are the earlier commits here.

Its own commits, squashed:
- build(macos): complete strict standalone dependency packaging (9424b4886)
- fix(macos): bind SDL3, imports and archive members to their real formats (8ad0e3265)
- fix(macos): keep the lazy-bind library ordinal across DONE (48f6ec02b)
- build(macos): take the architecture and SDK from darwin_toolchain when packaging (5ce85548c)
- build(macos): no prebuilt renderer on macOS either, as main has none (1bd269c7e)

Assisted-by: Claude Opus 5.5
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Was: #455 (#455), branch mac/mem-gate at 82c2e10341 (Sweep3, on main aa95d35f).

Its own commits, squashed:
- fix(builder): account for available memory and compiler children on macOS (8f8e03b7f)
- fix(builder): avoid stale Darwin available-memory snapshots (5240e431a)
- fix(builder): keep Darwin RSS behind the shared tree backend (82c2e1034)

Assisted-by: Claude Opus 5.5
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Was: #456 (#456), branch mac/control-sockets at fc2f104050 (Sweep3, on main aa95d35f).

Its own commits, squashed:
- fix(runtime): support control bridge Unix sockets on macOS (5fc3fe390)
- test(control): link the bridge's macOS socket helpers into test_oot_state_tap's fixture (fc2f10405)

Assisted-by: Claude Opus 5.5
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Was: #457 (#457), branch mac/control-quit at fe3e8c9178 (Sweep3, on main aa95d35f).

It was stacked on #456; their changes are the earlier commits here.

Its own commits, squashed:
- test(control): quit's parent waits for its bridge to listen, and a failed check ends the bridge it forked (fe3e8c917)

Assisted-by: Claude Opus 5.5
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Was: #476 (#476), branch mac/cache-files at 7e561fbb53 (Sweep3, on main aa95d35f).

Its own commits, squashed:
- fix(vk): preserve cache file reservations on macOS (7e561fbb5)

Assisted-by: Claude Opus 5.5
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Was: #480 (#480), branch mac/guest-16k at 657b780359 (Sweep3, on main aa95d35f).

It was stacked on #436, #478; their changes are the earlier commits here.

Merged with the topic's earlier commits by hand where they met (Consolidate-files/hand-resolutions.md).

Its own commits, squashed:
- fix(macos): serialize guest backing and native-page watch lifetimes (d7d999b92)
- fix(macos): retain pending watch faults across protection changes (a6a3e9e98)
- fix(macos): make the guest-memory changes Apple-only; Windows and Linux keep main's code (126d7bd67)
- docs(macos): describe the guest window's one owner, import pins and native-page watches (657b78035)

Assisted-by: Claude Opus 5.5
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Was: #492 (#492), branch mac/renderer-compile at 59f750aa38 (Sweep3, on main aa95d35f).

Its own commits, squashed:
- fix(macos): the renderer's last two files compile on Darwin (7ee5fd584)
- fix(macos): the debug tools are compiled on Darwin too (82b2d6606)
- test(macos): the debug tools check reads hos_oot_player_seen's body too (59f750aa3)

Assisted-by: Claude Opus 5.5
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Was: #511 (#511), branch mac/crash-records at c4d95017aa (Sweep3, on main aa95d35f).

It was stacked on #436; their changes are the earlier commits here.

Its own commits, squashed:
- fix(runtime): take the macOS report run id from getentropy (d3e86ddd7)
- fix(runtime): read crash-record memory and modules without /proc on macOS (aa039e142)
- test(runtime): build the crash-record fixture on macOS (adebf9dbb)
- test(runtime): link the macOS fault bridge into the crash-record fixture (c4d95017a)

Assisted-by: Claude Opus 5.5
Co-Authored-By: Claude Opus 5.5 <[email protected]>
fix(control): keep command-line sessions alive on macOS
Some checks failed
CI / Python source checks (ubuntu-24.04, part 1/2) (pull_request) Has been skipped
CI / Python source checks (ubuntu-24.04, part 2/2) (pull_request) Has been skipped
CI / SPIR-V fixtures (global narrow load/store, direct surface atomics, F2I immediate) (pull_request) Has been skipped
Third-party parts / The same as upstream (pull_request) Has been skipped
Website / Website on Cloudflare (pull_request_target) Has been skipped
CI / Conventional Commit title (pull_request) Successful in 14s
CI / Workflow lint (actionlint) (pull_request) Successful in 19s
Guide screenshots / Guide images and local UI source review (pull_request) Failing after 19s
Third-party parts / As their notes say (pull_request) Successful in 30s
PR description / Description follows the template (pull_request_target) Successful in 19s
40c1c5f5f8
Was: #516 (#516), branch mac/longshot-ctl-darwin at 3b9d3cfa2a (Sweep3, on main aa95d35f).

Its own commits, squashed:
- fix(control): tell macOS processes apart by their sysctl start time (56f4ca876)
- test(control): compare launch's data folder with the resolved run folder (3b9d3cfa2)

Assisted-by: Claude Opus 5.5
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Was: #491 (#491), branch mac/renderer-correctness at 695f6859dc (Sweep3, on main aa95d35f).

It was stacked on #438, #480; their changes are the earlier commits here.

Its own commits, squashed:
- fix(macos): pin renderer imports through final resource ownership (db82a0f23)
- test(macos): cut the non-Apple Pool and import route in three more fixtures (6cee76eb1)
- fix(vk): drain the recorder before startup rollback destroys the allocator (18c05be52)
- test(macos): follow main's #324 and #250 in the Darwin renderer fixture (c099f5da6)
- test(vk): follow the moved Pool in test_mirror_gpu_only's cut (165bf7e61)
- fix(macos): the import pin callbacks are macOS host API version 25 (fa691b55b)
- fix(macos): vk_memory.cpp compiles on macOS: #324's evicted_pools declaration is not Apple's (695f6859d)

Assisted-by: Claude Opus 5.5
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Was: #642 (#642), branch mac/gpu-budget at 09978824a0 (Sweep3, on main aa95d35f).

Its own commits, squashed:
- feat(vk): read the Mac's system memory for the renderer (gpu/vk/system_memory.h) (ba1952096)
- fix(macos): on unified memory the GPU's allowance is what the Mac's RAM leaves, not Metal's working set (632636ee0)
- fix(macos): vk_work.h stays vk_vma.cpp's last include (0e63a1dc1)
- fix(macos): the unified budget reads the system's memory at its first ask (5240eade7)
- docs(macos): RX_VK_UNIFIED_BUDGET in the switch table (09978824a)

Assisted-by: Claude Opus 5.5
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Was: #653 (#653), branch mac/metal-cache at db50cf3d26 (Sweep3, on main aa95d35f).

It was stacked on #438; their changes are the earlier commits here.

Its own commits, squashed:
- feat(macos): Metal's shader cache in a folder the caller names (db50cf3d2)

Assisted-by: Claude Opus 5.5
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Was: #643 (#643), branch mac/mvk-push at ca17df3be6 (Sweep3, on main aa95d35f).

Its own commits, squashed:
- fix(macos): storage buffer tables get descriptor sets on MoltenVK (ca17df3be)

Assisted-by: Claude Opus 5.5
Co-Authored-By: Claude Opus 5.5 <[email protected]>
feat(macos): ship the Vulkan loader with KosmicKrisp and MoltenVK, MoltenVK the default
Some checks failed
CI / Python source checks (ubuntu-24.04, part 1/2) (pull_request) Has been skipped
CI / Python source checks (ubuntu-24.04, part 2/2) (pull_request) Has been skipped
CI / SPIR-V fixtures (global narrow load/store, direct surface atomics, F2I immediate) (pull_request) Has been skipped
Third-party parts / The same as upstream (pull_request) Has been skipped
Website / Website on Cloudflare (pull_request_target) Has been skipped
CI / Conventional Commit title (pull_request) Successful in 14s
CI / Workflow lint (actionlint) (pull_request) Successful in 19s
Guide screenshots / Guide images and local UI source review (pull_request) Failing after 17s
Third-party parts / As their notes say (pull_request) Successful in 31s
PR description / Description follows the template (pull_request_target) Successful in 22s
7df74b124d
Was: #654 (#654), branch mac/kosmickrisp at 9d34f9a1c8 (Sweep3, on main aa95d35f).

It was stacked on #438, #479; their changes are the earlier commits here.

Merged with the topic's earlier commits by hand where they met (Consolidate-files/hand-resolutions.md).

Its own commits, squashed:
- feat(macos): ship the Vulkan loader with KosmicKrisp and MoltenVK, chosen at startup (fbd562421)
- test(macos): the driver package fixture takes the architecture and SDK from darwin_toolchain (3472d670c)
- fix(macos): type the driver manifest's ICD record for Pyright (296b5347b)
- fix(macos): MoltenVK is the default Vulkan driver on every macOS (86c017e42)
- test(macos): the display fixture counts longshot_env.txt's loads on Apple only (9d34f9a1c)

Assisted-by: Claude Opus 5.5
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Was: #644 (#644), branch mac/mvk-sizes at f08eb70206 (Sweep3, on main aa95d35f).

It was stacked on #643; their changes are the earlier commits here.

Its own commits, squashed:
- fix(macos): programs reading storage buffer lengths get descriptor sets on MoltenVK (f08eb7020)

Assisted-by: Claude Opus 5.5
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Was: #645 (#645), branch mac/mvk-rwtex at b8b1ba998a (Sweep3, on main aa95d35f).

It was stacked on #644; their changes are the earlier commits here.

Its own commits, squashed:
- fix(macos): stages with more than 8 read_write textures get descriptor sets on MoltenVK (b8b1ba998)

Assisted-by: Claude Opus 5.5
Co-Authored-By: Claude Opus 5.5 <[email protected]>
fix(vk): use update-after-bind sets past Metal's per-stage limits on MoltenVK
Some checks failed
CI / Python source checks (ubuntu-24.04, part 1/2) (pull_request) Has been skipped
CI / Python source checks (ubuntu-24.04, part 2/2) (pull_request) Has been skipped
CI / SPIR-V fixtures (global narrow load/store, direct surface atomics, F2I immediate) (pull_request) Has been skipped
Third-party parts / The same as upstream (pull_request) Has been skipped
Website / Website on Cloudflare (pull_request_target) Has been skipped
CI / Conventional Commit title (pull_request) Successful in 15s
CI / Workflow lint (actionlint) (pull_request) Successful in 16s
Guide screenshots / Guide images and local UI source review (pull_request) Failing after 12s
Third-party parts / As their notes say (pull_request) Successful in 14s
PR description / Description follows the template (pull_request_target) Successful in 16s
792a7d8a32
Was: #646 (#646), branch mac/mvk-pushlimits at 374c55a031 (Sweep3, on main aa95d35f).

It was stacked on #645; their changes are the earlier commits here.

Its own commits, squashed:
- fix(macos): stages past a Metal function's buffer, texture or sampler table get descriptor sets on MoltenVK (6c9e3c9fa)
- fix(macos): MoltenVK's descriptor sets are update-after-bind layouts, within Vulkan's limits for them (3e7d8d3d3)
- test(vk): recording_admission's device stub has the fixes make_pool now reads (374c55a03)

Assisted-by: Claude Opus 5.5
Co-Authored-By: Claude Opus 5.5 <[email protected]>
The topic needs it (as the stacks merged it before).
The topic needs it (as the stacks merged it before).
Was: #647 (#647), branch mac/seg-plan at 52def6832c (Sweep3, on main aa95d35f).

Its own commits, squashed:
- feat(vk): plan where an oversize guest span is cut into import segments (601c00ccd)
- feat(vk): let the segment planner add segments that pay for themselves (52def6832)

Assisted-by: Claude Opus 5.5
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Was: #648 (#648), branch mac/seg-shader at 9b73e82942 (Sweep3, on main aa95d35f).

Its own commits, squashed:
- feat(vk): descriptors bound as pieces in the SPIR-V back end and program variants (1f9183c2a)
- fix(vk): MslArrayPtr: no pointer into a storage buffer array is passed to a function (9b73e8294)

Assisted-by: Claude Opus 5.5
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Was: #649 (#649), branch mac/texel-codec at c5cbd39d26 (Sweep3, on main aa95d35f).

It was stacked on #648; their changes are the earlier commits here.

Its own commits, squashed:
- feat(vk): texel codecs in the SPIR-V back end and program variants (c5cbd39d2)

Assisted-by: Claude Opus 5.5
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Was: #658 (#658), branch mac/renderer-core at f8d4e51ad5 (Sweep3, on main aa95d35f).

It was stacked on #431, #491, #647; their changes are the earlier commits here.

Merged with the topic's earlier commits by hand where they met (Consolidate-files/hand-resolutions.md).

Its own commits, squashed:
- fix(vk): join #431's import table helpers with #491's macOS Pool (a1d08d92a)
- fix(macos): import NOACCESS guest pages and name a missing audio service (e6e92a90d)
- feat(vk): admit an operation's guest buffers before it binds them (alias isolation, macOS) (a27bee681)
- feat(vk): import a span past one device allocation as segments (SegMem, alias isolation) (dd4f13047)
- test(vk): follow the renderer-core merge's moved code in three extractions (6e77a383f)
- fix(vk, macos): admit a parallel batch's uniform updates in order, and keep its own updates out of its handoff (3fbfca08d)
- fix(vk, macos): keep every byte the page table reached mapped when an admission retires imports (616eacb83)
- fix(vk, macos): one view per byte of an Apple spare backing, and no endless retry of a failed view (04e00832b)
- fix(vk, macos): bg_drain publishes no background import over this epoch's retired memory or across a domain (a3913a646)
- fix(vk, macos): admission merges no import past 1 GiB again, so mirror_make can still mirror it (b8d16a20b)
- fix(vk, macos): a segment keeps a crossing import's bytes as leftovers clipped at the cuts, not as whole segments (aab3fd8a6)
- fix(vk, macos): each new import over a retired import's bytes inherits its share of that import's VRAM mirror (73bbb89ad)
- test(vk): the admission fixtures follow main's #250 sparse mirrors (6fa302cce)
- fix(vk, macos): the actor motion's resolver follows #59: a pose read at its draw is not copied (e0941ccc0)
- test(vk): test_split_ub_flush follows flush_ub_updates' end parameter (f8d4e51ad)

Assisted-by: Claude Opus 5.5
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Was: #662 (#662), branch mac/seg-contract at 0401eeb237 (Sweep3, on main aa95d35f).

It was stacked on #649, #658; their changes are the earlier commits here.

Its own commits, squashed:
- feat(vk): the segmented consumers' frozen contract (C0) (0401eeb23)

Assisted-by: Claude Opus 5.5
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Was: #663 (#663), branch mac/seg-consumers at 5400f1a0b6 (Sweep3, on main aa95d35f).

It was stacked on #645, #662; their changes are the earlier commits here.

Its own commits, squashed:
- feat(vk): texel codecs' views, texel piece views, null-descriptor stand-ins and presence words (TexelDesc, L3) (da741bdb2)
- test(vk): the texel ownership fixture names the case that failed (39d6490dd)
- feat(vk): SegBind's descriptor core, gathers and arena (L1) (7d5d51276)
- fix(vk): a draw reusing its descriptors drops an earlier build's refusal (SegBind) (7104d8324)
- test(vk): SegBind's gathers and notes fixtures, its parts of three checks, and its docs section (31d52778f)
- test(vk): test_set_for_tables reads its cut from --source (4462202ff)
- test(vk): test_mesh_fallback's topology anchor follows draw()'s `plain` (0f743f0b9)
- test(vk): test_set_for_lengths' layout fixture takes SegBind's seg_layout_count and presence_words (3b5f3b477)
- feat(vk): SegXfer, the transfer consumers of a range across a segment's cut (L2) (3200ff464)
- fix(vk): dispatch()'s compute-variant path (#252) names SegBind's pre-seam `plain` (c13540fc5)
- test(vk): the seg_gathers fixture stubs #162's rec::OwnSlot (8089dc409)
- test(vk): SegXfer's fixture and resolver sites follow #59's actor motion (1ab6beb2b)
- test(vk): SegXfer's gpu_write checks follow #329's ordered inline writes (5400f1a0b)

Assisted-by: Claude Opus 5.5
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Was: #674 (#674), branch mac/null-shader at b7683077e6 (Sweep3, on main aa95d35f).

It was stacked on #663; their changes are the earlier commits here.

Its own commits, squashed:
- feat(vk): null-descriptor emulation in the SPIR-V back end (NullShader, L4) (71003696f)
- docs(vk): NullShader: image and image buffer arrays share a known gap (17667bea3)
- fix(vk): NullShader: two source-cutting checks the wip commit broke (f53eda6cd)
- fix(vk): MslArrayPtr's NullShader half: a descriptor bound whole calls its loop function, and the loops' CPU runs (b7683077e)

Assisted-by: Claude Opus 5.5
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Was: #675 (#675), branch mac/tex-read-order at c5c6a853a8 (Sweep3, on main aa95d35f).

It was stacked on #674; their changes are the earlier commits here.

Its own commits, squashed:
- fix(vk): TexOrder: store each image read in place on MoltenVK (fb51f7807)
- test: test_amd_subgroup_profiles: the MoltenVK driver id in make_profile's stand-in (8d5fc5373)
- fix(vk): TexOrder: an image memory barrier before each image write and atomic on MoltenVK (c5c6a853a)

Assisted-by: Claude Opus 5.5
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Was: #676 (#676), branch mac/msl-depth at f8e18c953b (Sweep3, on main aa95d35f).

It was stacked on #675; their changes are the earlier commits here.

Its own commits, squashed:
- fix(macos): MoltenVK's Metal source nests no deeper than 32 forwarded instructions (71d2498c4)
- test(vk): the subgroup profile fixture knows MoltenVK's driver id (f8e18c953)

Assisted-by: Claude Opus 5.5
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Was: #686 (#686), branch mac/rosetta-import at 6ec9629e59 (Sweep3, on main aa95d35f).

It was stacked on #658; their changes are the earlier commits here.

Its own commits, squashed:
- fix(macos): Rosetta host imports: whole hardware pages, refused imports asked again only when their backing changes (ae91338ae)
- fix(macos): the backing generation is Apple host API version 26, after #491's import pins at 25 (6ec9629e5)

Assisted-by: Claude Opus 5.5
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Was: #692 (#692), branch mac/msl-depth2 at a67e1934ec (Sweep3, on main aa95d35f).

It was stacked on #676; their changes are the earlier commits here.

Its own commits, squashed:
- fix(macos): the nesting bound counts only the reads SPIRV-Cross certainly makes (a67e1934e)

Assisted-by: Claude Opus 5.5
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Was: #693 (#693), branch mac/compile-gaps at 5ceed495b2 (Sweep3, on main aa95d35f).

It was stacked on #692; their changes are the earlier commits here.

Its own commits, squashed:
- fix(vk): bound the control-flow nesting of SPIRV-Cross's Metal source on MoltenVK (46b5810a9)
- perf(vk): parse the module in place when the scope bound has nothing to move (5ceed495b)

Assisted-by: Claude Opus 5.5
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Was: #694 (#694), branch mac/subgroup-vertex at a3e8a51faf (Sweep3, on main aa95d35f).

It was stacked on #676; their changes are the earlier commits here.

Merged with the topic's earlier commits by hand where they met (Consolidate-files/hand-resolutions.md).

Its own commits, squashed:
- fix(vk): MoltenVK's vertex stages run the guest's warp operations as one-lane warps (a2b3b0578)
- test(vk): test_subgroup_vertex: the base tree's own checks unprinted, and one failure message per cause (e20482fa9)
- test(vk): test_subgroup_vertex: SPIRV-Cross drops a subgroup barrier in a vertex function (a3e8a51fa)

Assisted-by: Claude Opus 5.5
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Was: #695 (#695), branch mac/spv-size at 43d1a23420 (Sweep3, on main aa95d35f).

It was stacked on #676; their changes are the earlier commits here.

Its own commits, squashed:
- feat(vk): RX_VK_SPV_PROFILE, what the big SPIR-V modules are made of (3d7b1f5f6)
- docs(vk): spirv_profile.h's store names where the line is printed (ebf1854b4)
- docs(vk): RX_VK_SPV_PROFILE's text names the slow compile line as the precompile hand-off's (43d1a2342)

Assisted-by: Claude Opus 5.5
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Was: #696 (#696), branch mac/gm-loop at 231115f14c (Sweep3, on main aa95d35f).

It was stacked on #694, #695; their changes are the earlier commits here.

Merged with the topic's earlier commits by hand where they met (Consolidate-files/hand-resolutions.md).

Its own commits, squashed:
- feat(vk): MoltenVK and KosmicKrisp search storage buffer tables in loops in every global memory fallback (39a40fed6)
- test(vk): gm_loop_ir --gpu: the loop forms first, then the written-out ones, smaller first (99616b7ab)
- test(vk): stub table_loops_on where make_profile is compiled cut out (231115f14)

Assisted-by: Claude Opus 5.5
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Was: #697 (#697), branch mac/local-mem-buffer at a526c34c9f (Sweep3, on main aa95d35f).

It was stacked on #696; their changes are the earlier commits here.

Its own commits, squashed:
- feat(vk): MoltenVK zeroes local memory at computed offsets by a loop, not a written-out initializer (a526c34c9)

Assisted-by: Claude Opus 5.5
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Was: #698 (#698), branch mac/kk-tex-order at 8a3d7db0ce (Sweep3, on main aa95d35f).

It was stacked on #654, #675; their changes are the earlier commits here.

Its own commits, squashed:
- fix(macos): TexOrder's stored image reads on KosmicKrisp too (27d566b45)
- test(macos): the Apple drivers' check names the fixes this tree makes (8a3d7db0c)

Assisted-by: Claude Opus 5.5
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Was: #787 (#787), branch mac/giant-shape at 96b51b55b5 (Sweep3, on main aa95d35f).

It was stacked on #697; their changes are the earlier commits here.

Its own commits, squashed:
- test: giant mesh fallbacks' shape through the real SPIR-V back end (tests/giant_shape_ir.cpp) (96b51b55b)

Assisted-by: Claude Opus 5.5
Co-Authored-By: Claude Opus 5.5 <[email protected]>
The Mac-only part of fix/async-safe-frees-i40 (c151fcea, MvkAsyncFix's F5) that #788 does not carry, because
null_dummies_make (#663, macOS: MoltenVK has no nullDescriptor) exists only on the macOS stack. The stand-in images' clear
waits 5 s for its fence; when that wait ran out, the fence and the command pool were destroyed while the GPU might still be
clearing (a destroyed pool under a pending command buffer). Now a clear submitted and not seen done in 5 s is waited for
without a limit first, as #788 does for the read-back. The clear is still reported as not done in time (the "may read
garbage" line), as before.

tests/test_null_dummies.py: case make-slow-clear (the fixture's fence wait runs out once): one unbounded wait after the 5 s
one, before the fence and the pool are destroyed. Fails before this commit (one wait, none unbounded), passes after, on arm64
and x86_64 under Rosetta.

Assisted-by: Claude Opus 5.5
Co-Authored-By: Claude Opus 5.5 <[email protected]>
test: make_profile's cut-out fixtures know KosmicKrisp, SubgroupVertex, GmLoop and LocalMemBuffer
Some checks failed
CI / Python source checks (ubuntu-24.04, part 1/2) (pull_request) Has been skipped
CI / Python source checks (ubuntu-24.04, part 2/2) (pull_request) Has been skipped
CI / SPIR-V fixtures (global narrow load/store, direct surface atomics, F2I immediate) (pull_request) Has been skipped
Third-party parts / The same as upstream (pull_request) Has been skipped
Website / Website on Cloudflare (pull_request_target) Has been skipped
CI / Conventional Commit title (pull_request) Successful in 7s
CI / Workflow lint (actionlint) (pull_request) Successful in 11s
Guide screenshots / Guide images and local UI source review (pull_request) Failing after 9s
Third-party parts / As their notes say (pull_request) Successful in 11s
PR description / Description follows the template (pull_request_target) Successful in 16s
70cc5ba1cb
In this topic #698 (KosmicKrisp's TexOrder, its Apple drivers' fixture in test_vendor_fixes) meets #694/#696
(SubgroupVertex: make_profile reads dev.subgroup_stages and Shader::Stage) and #697's two switches (GmLoop's
table_loops_on, LocalMemBuffer's local_zero_loop_on), and test_subgroup_vertex's stub meets KosmicKrisp's
VK_DRIVER_ID_MESA_KOSMICKRISP in make_profile. Each member passes at its own Sweep3 head; at the topic's tip the
fixtures did not build. This takes I41's fixes 02b10861 and 560923891's stub line:
- test_subgroup_vertex: the KosmicKrisp driver constant (28, the Vulkan headers' value);
- test_vendor_fixes' Apple drivers' fixture: subgroup_stages (all stages), stage.h, and table_loops_on and
  local_zero_loop_on stubs; its columns are unchanged.

Assisted-by: Claude Opus 5.5
Co-Authored-By: Claude Opus 5.5 <[email protected]>
(cherry picked from commit 02b108611 and the local_zero_loop_on line of 560923891)
Owner

This conflicts with main and is built on top of the macOS series (it carries the commits of #845 and others below it). nx2/build.py, nx2/make_game.py and docs/development.md conflict with #577 (the WebGPU renderer removed from the Windows build). Please rebase onto current main once its base PR #845 lands or is rebased; I didn't touch it because a rebase here would have to be redone after that.

This conflicts with `main` and is built on top of the macOS series (it carries the commits of https://git.magicbean.dev/MagicBeanDev/Longshot/pulls/845 and others below it). `nx2/build.py`, `nx2/make_game.py` and `docs/development.md` conflict with https://git.magicbean.dev/MagicBeanDev/Longshot/pulls/577 (the WebGPU renderer removed from the Windows build). Please rebase onto current `main` once its base PR https://git.magicbean.dev/MagicBeanDev/Longshot/pulls/845 lands or is rebased; I didn't touch it because a rebase here would have to be redone after that.
Some checks failed
CI / Python source checks (ubuntu-24.04, part 1/2) (pull_request) Has been skipped
CI / Python source checks (ubuntu-24.04, part 2/2) (pull_request) Has been skipped
CI / SPIR-V fixtures (global narrow load/store, direct surface atomics, F2I immediate) (pull_request) Has been skipped
Third-party parts / The same as upstream (pull_request) Has been skipped
Website / Website on Cloudflare (pull_request_target) Has been skipped
CI / Conventional Commit title (pull_request) Successful in 7s
CI / Workflow lint (actionlint) (pull_request) Successful in 11s
Guide screenshots / Guide images and local UI source review (pull_request) Failing after 9s
Third-party parts / As their notes say (pull_request) Successful in 11s
PR description / Description follows the template (pull_request_target) Successful in 16s
This pull request has changes conflicting with the target branch.
  • docs/development.md
  • gpu/vk/vk_draw.cpp
  • gpu/vk/vk_memory.cpp
  • gpu/vk/vk_shader.h
  • gpu/vk/vk_texture.cpp
  • nx2/build.py
  • nx2/make_game.py
View command line instructions

Manual merge helper

Use this merge commit message when completing the merge manually.

Checkout

From your project repository, check out a new branch and test the changes.
git fetch -u 'mac/topic-shader-backend:mooki-mac/topic-shader-backend'
git switch 'mooki-mac/topic-shader-backend'
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
MagicBeanDev/Longshot!848
No description provided.