WIP: perf(macos): Mac performance on MoltenVK #852

Draft
mooki wants to merge 96 commits from mooki/Longshot:mac/topic-mac-perf into main
Member

Type: perf · 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 ran at about 30 fps in the first field, and a run could not say why: no reason for each render pass end, no
attachment traffic, no GPU timeline. With those lines (#704) the frame turned out to be held by passes broken for every mesh draw
(the Mac has no mesh shaders, so each draw's compute stages end the pass, and on Apple's tile GPUs every break stores and loads
every attachment), by MoltenVK's own widening of 8-bit indices (which loses restart-off primitives at vertex 255 and splits the
Metal pass) and by the presenting thread's walk over the write marks, 0.31 ns a mark on the Mac. Batching the mesh draws dropped
provoking-vertex draws in batched passes, 0.6-0.9 a frame (run #36). This PR folds the macOS port's performance PRs and two
lanes' follow-ups into one: what measured faster is on by default on the Mac, what did not is off, and the measuring lines are
off by default everywhere. It is part of the macOS port. See #420.

What changed

On MoltenVK a run of mesh fallback draws on the same targets is drawn in one pass, their dispatches first; restart-off 8-bit
draws are widened by LS so they fetch vertex 255 as NVN does; and provoking-vertex draws in a batched pass take their list's room
after the admission instead of being left out. On macOS the write marks' walk reads 64 marks a test in 16-byte vector loads. Two
switches stay opt-in (a pass's leading clears as load ops; LS's widening ahead of a pass), and three log-only switches (frame cost
lines, a GPU timeline, the bench's A/B arm) are off by default on every platform. One commit per original PR, in order, then the
ports and the merge fixes:

  • feat(vk): log-only frame cost lines, a GPU timeline and the bench's A/B exactness arm, all off by default, every platform
    (gpu/vk/vk_perf.cpp, gpu/vk/perf_lines.h, hooks in vk_draw.cpp, vk_replay.cpp, vk_texture.cpp; NVN's discards counted
    in host/nvn_native.c, the poll's sleeps in host/hos_thread.c; RX_VK_PERF_LINES, RX_VK_GPU_TIMELINE, RX_VK_BENCH_AB).
    Was: #704
  • perf(macos): a pass's leading whole clears as its attachments' LOAD_OP_CLEAR, off by default (gpu/vk/load_clear.h,
    begin_pass in vk_draw.cpp; RX_VK_LOAD_CLEAR=1). Was: #780
  • fix(macos): restart-off 8-bit indices drawn as NVN does on MoltenVK; LS's widening ahead of a pass opt-in (gpu/vk/widen8.h,
    widen8_scan.h, the shader widen8.comp, vk_vendor.h index8_raw/widen8; RX_VK_INDEX8_RAW, RX_VK_WIDEN8=1). Was:
    #782
  • perf(macos): batch the mesh fallback's draws of a pass on MoltenVK (gpu/vk/mesh_batch.h, secondary command buffers in
    vk_draw.cpp and vk_recorder.h; RX_VK_MESH_BATCH). Was: #783
  • Port, fix(vk): no provoking-vertex draw left out in a mesh batch's segment; its list's room taken after the admission
    (provoking_room, records_into_recording in vk_draw.cpp; tests/test_stream_room.py), and test_pipeline_share's count of
    draw()'s third pipeline lookup. From macos/stream-room ae7daf5f and d987ab79 (reports/2026-11-15-stream-room.md); its
    every-platform middle commit bbfb465f (a direct quad draw's triangles grow the stream under RX_VK_STREAM_GROW_OFF) is a PR of
    its own, fix/quad-stream-grow.
  • Port, perf(macos): the write marks' walk 64 marks a test in 16-byte vector loads (collect_in in host/rx_backend.c, macOS
    only; HOS_COLLECT_VECTOR=0 the byte walk). From macos/page-scan 74619b9b (reports/2026-11-15-page-scan.md), placed in
    macOS's branch of the walk (Windows and Linux keep main's word loads).
  • Merge fixes (tests the members each passed alone, failing where two met here; each follows I41's fix for the same pair): the
    indirect quads' draw hooked by PerfInstr, test_perf_lines' six sites (#704 x #705, I41 74da414a); test_stream_room cuts
    provoking_first (the port x #703); test_darwin_guest_memory takes the walk's pieces apart (the port x #480); fan_indirect's
    fixture knows Widen8's bind (#702 x #782, I41 47f4695b); and the merge of topic 7's fixes.

Measurements

Verdict: helps: MeshBatch is worth 1.0 ms of frame and 1.1 ms of GPU a frame (+1.1 fps) and the vector walk 3.0 ms of the
presenting thread's replay and 3.2 ms of frame − GPU, each against a run-to-run noise of 0.17 ms of frame (E7); LoadClear and
Widen8's look ahead each measured under the noise on an M4 Max, so both ship off. The provoking-vertex draws left out in batched
passes went from 0.6-0.9 a frame (run #36: 11,756) to 0 (E9a). The fixes are exact on the GPU where probed: W8-01 r2 (14 of 14
scenes as NVN's reference), LC-01 (327 folds), MB-01 (8 of 8 batched as unbatched).

Hardware: macOS 26.7.1 (25G241), Apple M4 Max, 64 GB; MoltenVK main 5189f8de with the argbuf-slots patch (c170a745)
Scene: the field-dawn save's first area (slot 00, #24's inputs), windowed 1280x720, LS's defaults, frame cap 60 (E7: 240)
Method: one start each with the lanes paused, a 600 s hold (E9a 1,197 s); the medians over the hold's 120-present periods from +20 s of the FPS counter's Dev level and RX_VK_PERF_LINES' L1-L6 and the replay lines
How to reproduce: the macOS runner (tools/ls-run.py, Rev13/Rev14) on the named build, quiet-required, field-dawn slot 00, the switches as in the column

Baseline: main does not start on a Mac, so each pair is one integration build with the change's switch off and on: I39 7a7726fe for the three PRs' topics (E3 all off, E4 MeshBatch off, E2 all on), I41 78ec1c47 for the walk (E9b HOS_COLLECT_VECTOR=0, E9c the vector walk). I41 carries every member here and both ports as they were before Sweep3's rebase; Widen8's look ahead and LoadClear are off by default there, as here.

field-dawn hold Before, the three off: integration @ 7a7726fe (E3) Before, MeshBatch off: integration @ 7a7726fe (E4) After, all on: integration @ 7a7726fe (E2)
fps 32.3 32.6 33.7
frame ms 30.96 30.67 29.67
GPU ms a frame 20.5 20.2 19.1
L1 pass ends a frame 206.2 188.0 133.9
L2 MB loaded and stored a frame 660 649 378
field-dawn hold, the walk Before, HOS_COLLECT_VECTOR=0: integration @ 78ec1c47 (E9b) After: integration @ 78ec1c47 (E9c)
the replay's memory sync, ms a frame 3.25 0.25
frame − GPU, ms 10.74 7.58
a capture's scan, ms a submit (~1,760 MB) 0.190 0.020
frame ms (fps) 33.56 (29.8) 27.10 (36.9)
E3 (7a7726fe, all three off): 32.3 fps, 30.96 ms, GPU 20.5; E4 (MeshBatch off) 32.6, 30.67, 20.2; E2 (all on) 33.7, 29.67, 19.1
E7 (all on, cap 240): 33.9 fps, 29.50 ms, GPU 19.1 (noise against E2: 0.17 ms of frame, 0.0 ms of GPU, 0.2 fps)
E9b (78ec1c47, byte walk): memory sync 3.25 ms, frame - GPU 10.74, 29.8 fps; E9c (vector walk): 0.25, 7.58, 36.9 fps
E9a (78ec1c47): 12/12 must-shows; provoking-vertex draws left out 0; drawn as lists 262.3 a frame, drawn as they were 0

About half of E9b against E9c's 6.46 ms of frame is GPU time (22.8 against 19.5 ms) the walk cannot be credited with; at equal
GPU time the walk's whole-frame saving is about 3.1 ms (reports/2026-11-15-mac-perf-E9.md).

Flags and settings

Eight new switches: MeshBatch and RX_VK_INDEX8_RAW on by default on MoltenVK only, the vector walk on by default on macOS only;
LoadClear and Widen8's look ahead off; the three measuring switches off on every platform. RX_VK_BENCH, RX_VK_CHUNK,
RX_VK_DRAW_STATS, RX_VK_PASS_BARRIER, RX_VK_PASS_TIMING, RX_VK_BARRIER_DEDUPE_OFF, RX_VK_BARRIER_EVERY_DRAW,
RX_VK_PUSH_STATE_OLD and HOS_COLLECT_WIDE appear in the diff as main's switches, read as before.

Flag What it is Before this PR After this PR Effect Helps / doesn't help / untested Recommendation
RX_VK_PERF_LINES=1 the L1-L6 frame cost lines no switch off log lines; relaxed counters per op and draw helps: the E-series' numbers off; for diagnosis
RX_VK_GPU_TIMELINE=1 or 2 the frames' GPU timeline on the CPU's clock (2: the top spans) no switch off T1 lines every 120 presents; asks for calibrated timestamps helps: E1 off; for diagnosis
RX_VK_BENCH_AB=<arm> the bench's B arm (pass_barrier, dedupe_off, chunk:<n>, load_clear, widen8, mesh_batch), with RX_VK_BENCH no switch unset: the bench as before A, B, A blocks and a verdict no verdict on the field frame (it never repeats) off; for measuring a change
RX_VK_LOAD_CLEAR=0 or 1 a pass's leading whole clears as its attachments' load ops no switch off on every driver the same pixels with fewer loads doesn't help on an M4 Max (E4c, under the noise); exact in LC-01 off; try on a Mac with less bandwidth
RX_VK_INDEX8_RAW=0 or 1 restart-off 8-bit draws fetch 0xFF as vertex 255 (NVN's) MoltenVK's 0xFFFF: those primitives lost on on MoltenVK only NVN's primitives helps: W8-01 r2 (14/14) on, as it ships
RX_VK_WIDEN8=0 or 1 LS widens a pass's 8-bit indices before the pass (the look ahead) no switch off one widening a pass instead of one a draw doesn't help on an M4 Max (E4b, under the noise) off
RX_VK_MESH_BATCH=0 or <n> the mesh fallback's draws of a pass batched in that pass (<n> members, 2-64) no switch: each fallback draw breaks its pass on on MoltenVK only, 8 members 54 fewer pass ends a frame helps: −1.0 ms frame, −1.1 ms GPU (E4 → E2) on, as it ships
HOS_COLLECT_VECTOR=0 macOS: the write marks' walk a byte load each, as before no switch the vector walk (64 marks a test) the same pages, order and marks helps: −3.0 ms memory sync (E9b → E9c) on, as it ships; =0 for A/B

Testing

Tested: on macOS 26.7.1, Apple M4 Max, at 1b7c7656 on topic 7, whose tree this PR's head bc0c7799 keeps (its last commit,
a merge of topic 7's last fix, changes no file here):

  • The members' own checks (their Sweep3 commands, 82, deduplicated) at the head, on arm64 and on x86_64 under Rosetta where the
    member ran it (36 of them x86_64 or both): 82 of 82 pass. Logs: reports/Consolidate-files/proof/c8z-m-*.
  • The ports' own checks at the head, both arches: test_stream_room (all six cases; on the pre-port tip b83bc3d0, --source,
    five fail, as they should), the tests it touches or cuts (test_provoking_first, test_drawid_direct, test_widen8,
    test_seg_gathers, test_draw_side_effects, test_draw_stream_visibility, test_recording_admission, test_fsr_uniform_ownership,
    test_mesh_batch, test_mesh_provoking, test_quad_draws, test_load_clear, test_pipeline_share), test_collect_wide (both walks;
    with the pre-port rx_backend.c it fails: no vector walk built), test_darwin_guest_memory, and the merge fixes' tests
    (test_perf_lines, test_fan_indirect, test_fan_key, test_index8_bind, test_vendor_fixes, test_subgroup_vertex): 46 of 46
    pass, the 3 runs on the pre-port tree fail. Logs: proof/c8z-*.
  • The ports' whole files and the merge fixes': vk_draw.cpp, vk_replay.cpp and host/rx_backend.c compiled whole on arm64
    and x86_64 with nx2/build.py's own macOS commands at the head: 6 of 6 exit 0; against topic 8's pre-port tip b83bc3d0, no
    undefined symbol added in vk_draw.cpp or rx_backend.c.
  • python -I -B tests/run_all.py at the head against main aa95d35f's 543/33/17 on this Mac: 622 passed, 15 failed, 17
    skipped; by name nothing fails here that passes on main; 17 of main's failures pass (the macOS host's and caches' fixes from
    topics 1-4), 61 new checks pass, test_appimage_package_retry is skipped on macOS (#454) and test_dav1d_av1 runs (#454);
    the 15 failures fail on main too: test_appimage_player_build, test_cpm_discovery, test_crash_dialog, test_env_on,
    test_game_layout, test_lift_cleanup_error, test_linux_preflight, test_make_game_cache, test_options_budget_once,
    test_options_path, test_pipeline_tour, test_readback_late, test_split_giants, test_vk_pgo, test_walk_key
    (reports/Consolidate-files/checks/compare-mac-perf.txt).
  • The renderer's cross-file link check at the head (every mkwvk:: name declared in one gpu/vk file and defined in another,
    each defining file compiled on both arches): 0 not exported, 0 undefined across the 34 objects of each arch.
  • Off Apple (unifdef -U__APPLE__ of every changed non-test C/C++ file, against topic 7): 16 files differ and 9 are new, all
    of them #704's every-platform measuring lines (log-only, off by default: vk_perf.cpp, perf_lines.h, perf_op.h,
    vk_perf.h, their hooks and includes, NVN's discards counted in host/nvn_native.c and gpu/render/rx_nvn.h, the poll's
    sleeps in host/hos_thread.c and host/rx_backend.c) or the MoltenVK paths compiled everywhere and gated at run time on the
    MoltenVK driver (load_clear.h, mesh_batch.h, widen8*.h, the vendor flags in vk_vendor.h and vk_internal.h,
    vkCmdExecuteCommands in vk_loader.h, vk_recorder.h and vk_work.h, gpu_buffer_bind_imported in vk_memory.cpp, the
    stream-room port's provoking_room, behind provoking_first(), false off macOS). The page scan's walk is the same off Apple,
    token for token.
  • In the game: E9a on I41 78ec1c47 (arm64, 1,197 s hold, 12/12 must-shows, clean end, 0 skipped draws), an integration build
    that carries every member here and both ports; run #34 on I38 (x86_64 under Rosetta, 16 m 52 s, every draw drawn, 19/19,
    clean exit), which carried #704 and earlier versions of #780, #782 and #783 (not the ports).

Not tested: Windows and Linux (no such machine here): the measuring lines are every platform's, off by default, and the
MoltenVK paths compile there gated off. A Mac with less memory bandwidth than an M4 Max with LoadClear or the look ahead on.
Rosetta in a game run with these members as they are now.

Must be tested:

  • Windows and Linux, any GPU: build this PR (head bc0c7799) and main aa95d35f the same way, run python -I -B tests/run_all.py on each and start each to the title, then once more with RX_VK_PERF_LINES=1 RX_VK_GPU_TIMELINE=1, expecting the build to succeed, the new tests to pass with no other check changing status, the vk lines to match main's with the switches off, and the vk: L1-L6 and T1 lines with them on (Test Farm: @Beanstalk windows linux, build, run_all and start unchanged, then with the perf lines on)

Risks

What could break: on MoltenVK, a batched pass drawing something other than the unbatched replay (MB-01 found none), and
restart-off 8-bit draws widened by LS (W8-01 r2 found none). On macOS, the walk missing a write mark (test_collect_wide compares
it with the byte walk on random and dense marks; the pages, order and marks cleared are the byte walk's). Elsewhere, the measuring
hooks cost one flag load each with their switches off (about 1 ns a call; 7.6 µs a frame of run #25's shape).

Turning it off: RX_VK_MESH_BATCH=0, RX_VK_INDEX8_RAW=0, HOS_COLLECT_VECTOR=0; or revert the commits.

Compatibility: Nothing changes for a player's saves, longshot_options.ini, the shader and pipeline caches (Widen8's compute
shader is a new pipeline, built at the first use) or MKWVK_API_VERSION. Windows and Linux players see no change with the
switches unset.

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. (Windows and Linux untested; the test request is not open yet.)
  • Rebased on current main: on aa95d35f, through topic 7 (draw-path-quads-mesh).
  • python -I -B tests/run_all.py passes (any failure that also fails on main is named). (On this Mac at 1b7c7656, this head's tree: 622/15/17 against main aa95d35f's 543/33/17; the 15 failures, named under Testing, fail on main too; no check fails here that passes on main.)
  • 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.
  • Numbers from the same PC, scene and settings, at least 2 interleaved runs each, the median reported. (Same PC, scene and settings and the hold's median, but one start each: E7 against E2 measured the run-to-run noise.)
  • Switches documented (docs/development.md; the README for a menu row) and shipped at their recommended value.
  • The SPIR-V headers regenerated with glslang (a shader changed).
  • Host code builds on both Windows (llvm-mingw) and Linux, with UTF-8 paths. (Not built here: the Windows/Linux test request asks for it.)
  • 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.
  • Docs updated.
**Type:** perf · **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 ran at about 30 fps in the first field, and a run could not say why: no reason for each render pass end, no attachment traffic, no GPU timeline. With those lines (#704) the frame turned out to be held by passes broken for every mesh draw (the Mac has no mesh shaders, so each draw's compute stages end the pass, and on Apple's tile GPUs every break stores and loads every attachment), by MoltenVK's own widening of 8-bit indices (which loses restart-off primitives at vertex 255 and splits the Metal pass) and by the presenting thread's walk over the write marks, 0.31 ns a mark on the Mac. Batching the mesh draws dropped provoking-vertex draws in batched passes, 0.6-0.9 a frame (run #36). This PR folds the macOS port's performance PRs and two lanes' follow-ups into one: what measured faster is on by default on the Mac, what did not is off, and the measuring lines are off by default everywhere. It is part of the macOS port. See #420. ## What changed On MoltenVK a run of mesh fallback draws on the same targets is drawn in one pass, their dispatches first; restart-off 8-bit draws are widened by LS so they fetch vertex 255 as NVN does; and provoking-vertex draws in a batched pass take their list's room after the admission instead of being left out. On macOS the write marks' walk reads 64 marks a test in 16-byte vector loads. Two switches stay opt-in (a pass's leading clears as load ops; LS's widening ahead of a pass), and three log-only switches (frame cost lines, a GPU timeline, the bench's A/B arm) are off by default on every platform. One commit per original PR, in order, then the ports and the merge fixes: - `feat(vk)`: log-only frame cost lines, a GPU timeline and the bench's A/B exactness arm, all off by default, every platform (`gpu/vk/vk_perf.cpp`, `gpu/vk/perf_lines.h`, hooks in `vk_draw.cpp`, `vk_replay.cpp`, `vk_texture.cpp`; NVN's discards counted in `host/nvn_native.c`, the poll's sleeps in `host/hos_thread.c`; `RX_VK_PERF_LINES`, `RX_VK_GPU_TIMELINE`, `RX_VK_BENCH_AB`). Was: [#704](https://git.magicbean.dev/MagicBeanDev/Longshot/pulls/704) - `perf(macos)`: a pass's leading whole clears as its attachments' `LOAD_OP_CLEAR`, off by default (`gpu/vk/load_clear.h`, `begin_pass` in `vk_draw.cpp`; `RX_VK_LOAD_CLEAR=1`). Was: [#780](https://git.magicbean.dev/MagicBeanDev/Longshot/pulls/780) - `fix(macos)`: restart-off 8-bit indices drawn as NVN does on MoltenVK; LS's widening ahead of a pass opt-in (`gpu/vk/widen8.h`, `widen8_scan.h`, the shader `widen8.comp`, `vk_vendor.h` `index8_raw`/`widen8`; `RX_VK_INDEX8_RAW`, `RX_VK_WIDEN8=1`). Was: [#782](https://git.magicbean.dev/MagicBeanDev/Longshot/pulls/782) - `perf(macos)`: batch the mesh fallback's draws of a pass on MoltenVK (`gpu/vk/mesh_batch.h`, secondary command buffers in `vk_draw.cpp` and `vk_recorder.h`; `RX_VK_MESH_BATCH`). Was: [#783](https://git.magicbean.dev/MagicBeanDev/Longshot/pulls/783) - Port, `fix(vk)`: no provoking-vertex draw left out in a mesh batch's segment; its list's room taken after the admission (`provoking_room`, `records_into_recording` in `vk_draw.cpp`; tests/test_stream_room.py), and test_pipeline_share's count of draw()'s third pipeline lookup. From `macos/stream-room` ae7daf5f and d987ab79 (reports/2026-11-15-stream-room.md); its every-platform middle commit bbfb465f (a direct quad draw's triangles grow the stream under `RX_VK_STREAM_GROW_OFF`) is a PR of its own, `fix/quad-stream-grow`. - Port, `perf(macos)`: the write marks' walk 64 marks a test in 16-byte vector loads (`collect_in` in `host/rx_backend.c`, macOS only; `HOS_COLLECT_VECTOR=0` the byte walk). From `macos/page-scan` 74619b9b (reports/2026-11-15-page-scan.md), placed in macOS's branch of the walk (Windows and Linux keep main's word loads). - Merge fixes (tests the members each passed alone, failing where two met here; each follows I41's fix for the same pair): the indirect quads' draw hooked by PerfInstr, test_perf_lines' six sites (#704 x #705, I41 74da414a); test_stream_room cuts `provoking_first` (the port x #703); test_darwin_guest_memory takes the walk's pieces apart (the port x #480); fan_indirect's fixture knows Widen8's bind (#702 x #782, I41 47f4695b); and the merge of topic 7's fixes. ## Measurements **Verdict:** helps: MeshBatch is worth 1.0 ms of frame and 1.1 ms of GPU a frame (+1.1 fps) and the vector walk 3.0 ms of the presenting thread's replay and 3.2 ms of frame − GPU, each against a run-to-run noise of 0.17 ms of frame (E7); LoadClear and Widen8's look ahead each measured under the noise on an M4 Max, so both ship off. The provoking-vertex draws left out in batched passes went from 0.6-0.9 a frame (run #36: 11,756) to 0 (E9a). The fixes are exact on the GPU where probed: W8-01 r2 (14 of 14 scenes as NVN's reference), LC-01 (327 folds), MB-01 (8 of 8 batched as unbatched). Hardware: macOS 26.7.1 (25G241), Apple M4 Max, 64 GB; MoltenVK main 5189f8de with the argbuf-slots patch (`c170a745`) Scene: the field-dawn save's first area (slot 00, #24's inputs), windowed 1280x720, LS's defaults, frame cap 60 (E7: 240) Method: one start each with the lanes paused, a 600 s hold (E9a 1,197 s); the medians over the hold's 120-present periods from +20 s of the FPS counter's Dev level and `RX_VK_PERF_LINES`' L1-L6 and the replay lines How to reproduce: the macOS runner (`tools/ls-run.py`, Rev13/Rev14) on the named build, quiet-required, field-dawn slot 00, the switches as in the column Baseline: main does not start on a Mac, so each pair is one integration build with the change's switch off and on: I39 `7a7726fe` for the three PRs' topics (E3 all off, E4 MeshBatch off, E2 all on), I41 `78ec1c47` for the walk (E9b `HOS_COLLECT_VECTOR=0`, E9c the vector walk). I41 carries every member here and both ports as they were before Sweep3's rebase; Widen8's look ahead and LoadClear are off by default there, as here. | field-dawn hold | Before, the three off: integration @ 7a7726fe (E3) | Before, MeshBatch off: integration @ 7a7726fe (E4) | After, all on: integration @ 7a7726fe (E2) | |---|---|---|---| | fps | 32.3 | 32.6 | 33.7 | | frame ms | 30.96 | 30.67 | 29.67 | | GPU ms a frame | 20.5 | 20.2 | 19.1 | | L1 pass ends a frame | 206.2 | 188.0 | 133.9 | | L2 MB loaded and stored a frame | 660 | 649 | 378 | | field-dawn hold, the walk | Before, HOS_COLLECT_VECTOR=0: integration @ 78ec1c47 (E9b) | After: integration @ 78ec1c47 (E9c) | |---|---|---| | the replay's memory sync, ms a frame | 3.25 | 0.25 | | frame − GPU, ms | 10.74 | 7.58 | | a capture's scan, ms a submit (~1,760 MB) | 0.190 | 0.020 | | frame ms (fps) | 33.56 (29.8) | 27.10 (36.9) | ``` E3 (7a7726fe, all three off): 32.3 fps, 30.96 ms, GPU 20.5; E4 (MeshBatch off) 32.6, 30.67, 20.2; E2 (all on) 33.7, 29.67, 19.1 E7 (all on, cap 240): 33.9 fps, 29.50 ms, GPU 19.1 (noise against E2: 0.17 ms of frame, 0.0 ms of GPU, 0.2 fps) E9b (78ec1c47, byte walk): memory sync 3.25 ms, frame - GPU 10.74, 29.8 fps; E9c (vector walk): 0.25, 7.58, 36.9 fps E9a (78ec1c47): 12/12 must-shows; provoking-vertex draws left out 0; drawn as lists 262.3 a frame, drawn as they were 0 ``` About half of E9b against E9c's 6.46 ms of frame is GPU time (22.8 against 19.5 ms) the walk cannot be credited with; at equal GPU time the walk's whole-frame saving is about 3.1 ms (reports/2026-11-15-mac-perf-E9.md). ### Flags and settings Eight new switches: MeshBatch and `RX_VK_INDEX8_RAW` on by default on MoltenVK only, the vector walk on by default on macOS only; LoadClear and Widen8's look ahead off; the three measuring switches off on every platform. `RX_VK_BENCH`, `RX_VK_CHUNK`, `RX_VK_DRAW_STATS`, `RX_VK_PASS_BARRIER`, `RX_VK_PASS_TIMING`, `RX_VK_BARRIER_DEDUPE_OFF`, `RX_VK_BARRIER_EVERY_DRAW`, `RX_VK_PUSH_STATE_OLD` and `HOS_COLLECT_WIDE` appear in the diff as main's switches, read as before. | Flag | What it is | Before this PR | After this PR | Effect | Helps / doesn't help / untested | Recommendation | |---|---|---|---|---|---|---| | `RX_VK_PERF_LINES=1` | the L1-L6 frame cost lines | no switch | off | log lines; relaxed counters per op and draw | helps: the E-series' numbers | off; for diagnosis | | `RX_VK_GPU_TIMELINE=1` or `2` | the frames' GPU timeline on the CPU's clock (2: the top spans) | no switch | off | T1 lines every 120 presents; asks for calibrated timestamps | helps: E1 | off; for diagnosis | | `RX_VK_BENCH_AB=<arm>` | the bench's B arm (`pass_barrier`, `dedupe_off`, `chunk:<n>`, `load_clear`, `widen8`, `mesh_batch`), with `RX_VK_BENCH` | no switch | unset: the bench as before | A, B, A blocks and a verdict | no verdict on the field frame (it never repeats) | off; for measuring a change | | `RX_VK_LOAD_CLEAR=0` or `1` | a pass's leading whole clears as its attachments' load ops | no switch | off on every driver | the same pixels with fewer loads | doesn't help on an M4 Max (E4c, under the noise); exact in LC-01 | off; try on a Mac with less bandwidth | | `RX_VK_INDEX8_RAW=0` or `1` | restart-off 8-bit draws fetch 0xFF as vertex 255 (NVN's) | MoltenVK's 0xFFFF: those primitives lost | on on MoltenVK only | NVN's primitives | helps: W8-01 r2 (14/14) | on, as it ships | | `RX_VK_WIDEN8=0` or `1` | LS widens a pass's 8-bit indices before the pass (the look ahead) | no switch | off | one widening a pass instead of one a draw | doesn't help on an M4 Max (E4b, under the noise) | off | | `RX_VK_MESH_BATCH=0` or `<n>` | the mesh fallback's draws of a pass batched in that pass (`<n>` members, 2-64) | no switch: each fallback draw breaks its pass | on on MoltenVK only, 8 members | 54 fewer pass ends a frame | helps: −1.0 ms frame, −1.1 ms GPU (E4 → E2) | on, as it ships | | `HOS_COLLECT_VECTOR=0` | macOS: the write marks' walk a byte load each, as before | no switch | the vector walk (64 marks a test) | the same pages, order and marks | helps: −3.0 ms memory sync (E9b → E9c) | on, as it ships; `=0` for A/B | ## Testing **Tested:** on macOS 26.7.1, Apple M4 Max, at `1b7c7656` on topic 7, whose tree this PR's head `bc0c7799` keeps (its last commit, a merge of topic 7's last fix, changes no file here): - The members' own checks (their Sweep3 commands, 82, deduplicated) at the head, on arm64 and on x86_64 under Rosetta where the member ran it (36 of them x86_64 or both): 82 of 82 pass. Logs: `reports/Consolidate-files/proof/c8z-m-*`. - The ports' own checks at the head, both arches: test_stream_room (all six cases; on the pre-port tip `b83bc3d0`, `--source`, five fail, as they should), the tests it touches or cuts (test_provoking_first, test_drawid_direct, test_widen8, test_seg_gathers, test_draw_side_effects, test_draw_stream_visibility, test_recording_admission, test_fsr_uniform_ownership, test_mesh_batch, test_mesh_provoking, test_quad_draws, test_load_clear, test_pipeline_share), test_collect_wide (both walks; with the pre-port `rx_backend.c` it fails: no vector walk built), test_darwin_guest_memory, and the merge fixes' tests (test_perf_lines, test_fan_indirect, test_fan_key, test_index8_bind, test_vendor_fixes, test_subgroup_vertex): 46 of 46 pass, the 3 runs on the pre-port tree fail. Logs: `proof/c8z-*`. - The ports' whole files and the merge fixes': `vk_draw.cpp`, `vk_replay.cpp` and `host/rx_backend.c` compiled whole on arm64 and x86_64 with nx2/build.py's own macOS commands at the head: 6 of 6 exit 0; against topic 8's pre-port tip `b83bc3d0`, no undefined symbol added in `vk_draw.cpp` or `rx_backend.c`. - `python -I -B tests/run_all.py` at the head against main aa95d35f's 543/33/17 on this Mac: 622 passed, 15 failed, 17 skipped; by name nothing fails here that passes on main; 17 of main's failures pass (the macOS host's and caches' fixes from topics 1-4), 61 new checks pass, `test_appimage_package_retry` is skipped on macOS (#454) and `test_dav1d_av1` runs (#454); the 15 failures fail on main too: test_appimage_player_build, test_cpm_discovery, test_crash_dialog, test_env_on, test_game_layout, test_lift_cleanup_error, test_linux_preflight, test_make_game_cache, test_options_budget_once, test_options_path, test_pipeline_tour, test_readback_late, test_split_giants, test_vk_pgo, test_walk_key (`reports/Consolidate-files/checks/compare-mac-perf.txt`). - The renderer's cross-file link check at the head (every `mkwvk::` name declared in one gpu/vk file and defined in another, each defining file compiled on both arches): 0 not exported, 0 undefined across the 34 objects of each arch. - Off Apple (`unifdef -U__APPLE__` of every changed non-test C/C++ file, against topic 7): 16 files differ and 9 are new, all of them #704's every-platform measuring lines (log-only, off by default: `vk_perf.cpp`, `perf_lines.h`, `perf_op.h`, `vk_perf.h`, their hooks and includes, NVN's discards counted in `host/nvn_native.c` and `gpu/render/rx_nvn.h`, the poll's sleeps in `host/hos_thread.c` and `host/rx_backend.c`) or the MoltenVK paths compiled everywhere and gated at run time on the MoltenVK driver (`load_clear.h`, `mesh_batch.h`, `widen8*.h`, the vendor flags in `vk_vendor.h` and `vk_internal.h`, `vkCmdExecuteCommands` in `vk_loader.h`, `vk_recorder.h` and `vk_work.h`, `gpu_buffer_bind_imported` in `vk_memory.cpp`, the stream-room port's `provoking_room`, behind `provoking_first()`, false off macOS). The page scan's walk is the same off Apple, token for token. - In the game: E9a on I41 `78ec1c47` (arm64, 1,197 s hold, 12/12 must-shows, clean end, 0 skipped draws), an integration build that carries every member here and both ports; run #34 on I38 (x86_64 under Rosetta, 16 m 52 s, every draw drawn, 19/19, clean exit), which carried #704 and earlier versions of #780, #782 and #783 (not the ports). **Not tested:** Windows and Linux (no such machine here): the measuring lines are every platform's, off by default, and the MoltenVK paths compile there gated off. A Mac with less memory bandwidth than an M4 Max with LoadClear or the look ahead on. Rosetta in a game run with these members as they are now. **Must be tested:** - Windows and Linux, any GPU: build this PR (head `bc0c7799`) and main aa95d35f the same way, run `python -I -B tests/run_all.py` on each and start each to the title, then once more with `RX_VK_PERF_LINES=1 RX_VK_GPU_TIMELINE=1`, expecting the build to succeed, the new tests to pass with no other check changing status, the vk lines to match main's with the switches off, and the `vk: L1`-`L6` and T1 lines with them on (Test Farm: @Beanstalk windows linux, build, run_all and start unchanged, then with the perf lines on) ## Risks **What could break:** on MoltenVK, a batched pass drawing something other than the unbatched replay (MB-01 found none), and restart-off 8-bit draws widened by LS (W8-01 r2 found none). On macOS, the walk missing a write mark (test_collect_wide compares it with the byte walk on random and dense marks; the pages, order and marks cleared are the byte walk's). Elsewhere, the measuring hooks cost one flag load each with their switches off (about 1 ns a call; 7.6 µs a frame of run #25's shape). **Turning it off:** `RX_VK_MESH_BATCH=0`, `RX_VK_INDEX8_RAW=0`, `HOS_COLLECT_VECTOR=0`; or revert the commits. **Compatibility:** Nothing changes for a player's saves, `longshot_options.ini`, the shader and pipeline caches (Widen8's compute shader is a new pipeline, built at the first use) or `MKWVK_API_VERSION`. Windows and Linux players see no change with the switches unset. ## 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. - [ ] Testing names what was tested, what wasn't, and what must still be tested, where and how. (Windows and Linux untested; the test request is not open yet.) - [x] Rebased on current `main`: on aa95d35f, through topic 7 (`draw-path-quads-mesh`). - [x] `python -I -B tests/run_all.py` passes (any failure that also fails on `main` is named). (On this Mac at `1b7c7656`, this head's tree: 622/15/17 against main aa95d35f's 543/33/17; the 15 failures, named under Testing, fail on main too; no check fails here that passes on main.) - [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. - [ ] Numbers from the same PC, scene and settings, at least 2 interleaved runs each, the median reported. (Same PC, scene and settings and the hold's median, but one start each: E7 against E2 measured the run-to-run noise.) - [x] Switches documented (docs/development.md; the README for a menu row) and shipped at their recommended value. - [x] The SPIR-V headers regenerated with glslang (a shader changed). - [ ] Host code builds on both Windows (llvm-mingw) and Linux, with UTF-8 paths. (Not built here: the Windows/Linux test request asks for it.) - [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. - [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]>
Was: #677 (#677), branch mac/mode-census at d2fd7a90ff (Sweep3, on main aa95d35f).

It was stacked on #663; 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): count polygon modes and restart-off strip draws on Apple, log-only (d2fd7a90f)

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

It was stacked on #677; 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): bind a direct draw's 8-bit indices with their size on MoltenVK (ca6b27fdd)
- docs(macos): RX_VK_INDEX8_SIZE in the switch table (989a6423d)

Assisted-by: Claude Opus 5.5
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Was: #679 (#679), branch mac/count-draws at 2028d598e6 (Sweep3, on main aa95d35f).

It was stacked on #677; 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): draw count draws through a record rewrite where the device has no drawIndirectCount (4d9de1004)
- fix(macos): the count draw report in its own block; SegBind's fixture cuts the rewrite (ce7388bf0)
- fix(macos): buffer updates copied from the recording's stream on MoltenVK (574597e08)
- fix(macos): the count-draw rewrite on macOS only; Windows and Linux give count draws to the driver as before (791fe3a75)
- docs(macos): RX_VK_COUNT_REWRITE in the switch table (e4a7ab285)
- test(vk): test_inline_write_order (main's, #329) has gpu_write's cmd_update_buffer (2028d598e)

Assisted-by: Claude Opus 5.5
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Was: #680 (#680), branch mac/drawid-direct at 6c0204eb98 (Sweep3, on main aa95d35f).

It was stacked on #679; 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): direct draws that read the draw index drawn as one indirect record on MoltenVK (4876f2615)
- fix(macos): tessellated direct draws reading the draw index counted, not logged as errors (32a83be13)
- test(macos): the three recording fixtures stand in stream_usage (6c0204eb9)

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

It was stacked on #654, #679; 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:
- docs(macos): a MoltenVK built from main as the MoltenVK input (546102abe)
- docs(macos): MoltenVK main 5189f8de with the argbuf-slots patch as the recommended MoltenVK input, and how to build it (ebd6b127e)

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

It was stacked on #680; 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): count fans against their pipelines' static topology on MoltenVK, log-only (773588160)
- fix(macos): fans keyed apart from the other triangle topologies on MoltenVK (cd1ce0b21)

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

It was stacked on #701; 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): count indirect fans and their records on MoltenVK, log-only (927ed3de1)
- fix(macos): an indirect fan of more than one record drawn a call a record on MoltenVK (3a743b80f)
- test(macos): the indirect fans' census checked right after FanKey's, not as draw()'s last statement (62a089ad7)
- test(macos): the segment gathers' fixture stands in FanIndirect's way and split (d7878c9d1)

Assisted-by: Claude Opus 5.5
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Was: #703 (#703), branch mac/provoking-first at 73d4bc9bd4 (Sweep3, on main aa95d35f).

It was stacked on #701; 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): count the draws that depend on the provoking vertex where the device has no provokingVertexLast (8276aa94d)
- fix(macos): direct draws that depend on the provoking vertex drawn with each primitive's last vertex first, without provokingVertexLast (ac8416c59)
- fix(macos): adjacency draws that depend on the provoking vertex drawn as plain lists with each primitive's last vertex first (1977f19f5)
- fix(macos): the mesh fallback's draws that depend on the provoking vertex drawn with each primitive's last corner first (6493717b6)
- fix(macos): lines that depend on the provoking vertex counted only, not reversed (e702fd96e)
- fix(macos): a converted draw's list written into the stream of the recording it is drawn in (4f9891106)
- test(macos): draw()'s fixtures stand in ProvokingFirst's list and count its index binds (e42bf6e87)
- test(macos): test_fan_key reads draw()'s count lines with ProvokingFirst's count on them (531fd13ec)
- test(macos): a converted fan is drawn with a pipeline built as a list under FanKey's key (523d0696e)
- fix(macos): the provoking-vertex count and lists on macOS only; Windows and Linux record as before (73d4bc9bd)

Assisted-by: Claude Opus 5.5
Co-Authored-By: Claude Opus 5.5 <[email protected]>
#705 restacked on topic/draw-path (the topic that carries #679, which it was stacked on): its commits at 5fa122654c (Sweep3, on main aa95d35f), squashed into one because the topic's later commits meet them. Every platform. Its own commits:
- feat(vk): count quad draws, and the indirect ones left out (log-only) (08878e8c7)
- fix(vk): draw indirect quad draws, with and without a count, on every driver (30c4461d3)
- fix(vk): an indexed quad expansion's workgroup bound saturates (5fa122654)

Assisted-by: Claude Opus 5.5
Co-Authored-By: Claude Opus 5.5 <[email protected]>
#707 restacked on topic/draw-path (the topic that carries #679, which it was stacked on): its commits at b41a03a9ac (Sweep3, on main aa95d35f), squashed into one because the topic's later commits meet them. Every platform. Its own commits:
- feat(vk): count mesh draws by kind and what the mesh fallback cuts (log-only) (435c47d47)
- feat(vk): draw mesh count draws on the compute fallback (092afd495)
- fix(vk): the mesh fallback's records area grows on demand (17cace138)
- test(vk): six fixtures follow the mesh counters, count draws and growing area (02db49808)
- fix(vk): the mesh count draws bind their stages without RX_VK_LMEM_LOG's hook, which this base lacks (b41a03a9a)

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: #706 (#706), branch mac/indirect-quads at 6e6bc8d921 (Sweep3, on main aa95d35f).

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

Its own commits, squashed:
- fix(macos): quads provoke the same corners where the first vertex provokes (6e6bc8d92)

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

It was stacked on #703, #707; 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): the mesh fallback's rotation kept to what its list covers; the indirect quads counted for the provoking vertex; five checks follow (3a7b258ec)
- test: test_seg_xfer's fixture stands in fallback_draw_area (87f575c40)
- fix(macos): the mesh fallback's rotation follows the count draws and the growing records area (70686bc10)
- fix(macos): the mesh fallback's rotation decided and counted on macOS only, as ProvokingFirst's other gates (4800449a5)
- fix(macos): a rotated mesh fallback draw's area is cut only when its rotation list covers fewer corners than it holds (d24ecc70e)

Assisted-by: Claude Opus 5.5
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Was: #704 (#704), branch mac/perf-instr at 040b840d97 (Sweep3, on main aa95d35f).

It was stacked on #679; 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): log-only frame cost lines, a GPU timeline and the bench's A/B exactness arm, all off by default (43d7e8e89)
- test(vk): test_inline_write_order (main's, #329) includes perf_lines.h for full_barrier's bench arm (040b840d9)

Assisted-by: Claude Opus 5.5
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Was: #780 (#780), branch mac/load-clear at 12fe15f62d (Sweep3, on main aa95d35f).

It was stacked on #704; 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:
- perf(macos): a pass's leading whole clears as its attachments' LOAD_OP_CLEAR on MoltenVK (MacPerf #7) (66b6b0234)
- fix(macos): load_clear's kept operations as a set of bits, its device line from the vendor fixes (1b86d46b2)
- fix(vk): LoadClear off by default (mirrors macos/integrated 2b4b7b8e, I40) (12fe15f62)

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

It was stacked on #678, #703, #780; 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:
- test: test_perf_lines reads draw()'s counted draws with ProvokingFirst's count line and FanKey's census (610309546)
- perf(macos): LS widens a pass's 8-bit indices itself on MoltenVK (8115c3272)
- fix(macos): restart-off 8-bit draws fetch 0xFF as vertex 255 on MoltenVK, as NVN does (84cd6d0c3)
- test: test_resolver_coverage lists widen8_before_draw's index binding (bf07ead64)
- fix(vk): one pass_keeps for LoadClear and Widen8; the widening checked right before a held begin (fe92e5378)
- fix(vk): Widen8's look ahead off by default; INDEX8_RAW stays on (mirrors macos/integrated 2b4b7b8e, I40) (8b3eb471f)

Assisted-by: Claude Opus 5.5
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Was: #783 (#783), branch mac/mesh-batch at 7a196c0a99 (Sweep3, on main aa95d35f).

It was stacked on #708, #782; 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): mesh count draws' pass end said MeshFallback; two checks follow mesh-count's moves (3d33cd202)
- vk: batch the mesh fallback's draws of a pass on MoltenVK (MeshBatch) (e5450f384)
- vk: MeshBatch's per-thread batch as a TLS_OBJECT (210a1f9fb)
- test: LoadClear, Widen8 and MeshBatch checked together at a pass's begin and end (7a196c0a9)

Assisted-by: Claude Opus 5.5
Co-Authored-By: Claude Opus 5.5 <[email protected]>
StreamRoom (reports/2026-11-15-stream-room.md). Run #36 (I40) left out 11,756 direct draws that depend on the provoking vertex
("no room for its list in the stream of the recording it was drawn in", count 4, not indexed; vk_draw.cpp:11764), I39's
MeshBatch-on runs 122-174 each (:11747, the same line). The stream was never short: the most a recording held was 292 KB of
2 MB and none grew. ProvokingFirst decides the list with the recording's command buffer, then draw() redirects the open mesh
batch's draws into its segment (mesh_batch_cmd), and provoking_write asked for cmd == rec_cmd: every list draw recorded in a
batch's pass was left out, its pipeline already the list's. How many depends on the frame's order of draws (#36: one more
batched pass a frame than I39's runs, holding such a draw).

- records_into_recording: the recording's command buffer, or the open batch's segment while its primary is that command
  buffer (executed there, in the same submission, after the stream is flushed). provoking_list and drawid_indirect ask it;
  a DrawIdDirect record of a draw in a segment is now taken from the stream too, as in the primary, instead of drawn direct
  with MoltenVK's stale draw index.
- provoking_room: the list's room is taken right after the draw's admission (the last place its recording can change, a
  handoff giving a new stream) and before the descriptors' uploads, so provoking_write only writes into it and cannot fail.
  No room there (RX_VK_STREAM_GROW_OFF, or no buffer made): the draw is drawn as it was with its own topology's pipeline
  (waited for, as a segmented variant is), logged and counted as "drawn as they were"; never left out. The tally's lost
  counter and the report's "left out, no room ..." clause go: nothing can count there now.
- Cost: none on the fast path. The list's stream_alloc moved from the draw to after the admission (the same bytes; a draw
  skipped between the two leaves its list's room unused until the recording ends); records_into_recording is cmd == rec_cmd
  first, the batch's state read only for another command buffer.

MoltenVK only (devices without provokingVertexLast; DrawIdDirect on MoltenVK; MeshBatch on MoltenVK). Tests:
tests/test_stream_room.py (new: run #36's frame under 32 switch sets, a stream filled between decision and draw, a handoff
into a stream that cannot hold the list, no memory there, a draw-index draw in a segment; every case fails on 2b4b7b8e),
test_provoking_first, test_drawid_direct (a segments case), test_widen8, test_seg_gathers, test_draw_side_effects updated.

Ported onto topic/mac-perf (StreamRoom's macos/stream-room, I40 2b4b7b8e; its every-platform second commit bbfb465f, the
direct quad draw's needed room, is a PR of its own): tests/seg_gathers_test.cpp's ProvokingFirst stand-ins replaced in
place, before FanIndirect's as the topic has them; test_provoking_first.py's docstring keeps the topic's gate (every device
off macOS counts nothing) with this commit's words; everything else line for line as on 2b4b7b8e.

Assisted-by: Claude Opus 5.5
Co-Authored-By: Claude Opus 5.5 <[email protected]>
(cherry picked from commit ae7daf5fb708e4185a5d316edee1cd25e73515d9)
StreamRoom (reports/2026-11-15-stream-room.md). ae7daf5f's fallback, a ProvokingFirst draw whose list found no room after the
admission drawn as it was, asks graphics_pipeline() again for the plain variant with the game's topology, inside draw(). The
check that graphics_pipeline() is reached from draw() alone counted two calls; it now counts the three, two of them the plain
variant's. MoltenVK paths only (the fallback runs on devices without provokingVertexLast).

Ported onto topic/mac-perf after ae7daf5f's port (dd801607); line for line as on bbfb465f.

Assisted-by: Claude Opus 5.5
Co-Authored-By: Claude Opus 5.5 <[email protected]>
(cherry picked from commit d987ab79a8a196ebf0712101c9da19d4886b2418)
On macOS (arm64, and x86_64 under Rosetta) collect_in reads the write marks
64 to a test with inline-asm 16-byte loads (ld1 .16b, movdqu) from any page,
then takes each mark read set in turn with the same relaxed load and acquire
exchange as before. Since the byte loads (a3f3001d8) the walk cost 0.31 ns a
mark there, 4-6 times Linux's word walk: about 0.7 ms of each submit on the
presenting thread (ReplayCPU #2).

The loads are the asm's own, not C accesses, so they race nothing in the C
memory model, and each byte they read is single-copy atomic: the writers'
granule and the byte loads'. Like those relaxed loads they order nothing and
only choose pages: the pages found, their order, the marks cleared and what a
found page's exchange makes visible are the byte walk's. Other systems keep
their walk unchanged (the vector walk is compiled out there).

HOS_COLLECT_VECTOR=0 (read once, logged) is the byte walk on the same build.
test_collect_wide compiles both walks and requires the same pages, order and
marks left on random marks and ranges (near page 0, at the array's end,
overlapping, dense), per arch; test_darwin_guest_memory takes the new code.

Ported onto topic/mac-perf (page-scan 74619b9b was on I40 7092f286, where every
system read the marks with the byte loads). Here the byte loads are macOS's only
(#480: elsewhere main's word loads, marks_clear_256), so:
- host/rx_backend.c: the vector walk goes in macOS's branch of collect_in, the
  byte walk its HOS_COLLECT_VECTOR=0 fallback; its code and its switch's reading
  sit under "defined(__APPLE__) && HOS_MARKS_VECTOR", so Windows and Linux compile
  exactly the walk they did (unifdef -U__APPLE__: the file's tokens unchanged);
- tests/test_collect_wide.py: on macOS the commit's fixture, both walks (the vector
  walk's text cut from its comment to collect_in); elsewhere the topic's fixture as
  it was (one walk against the plain one, the wide step counted through its memcpy);
- docs/development.md: HOS_COLLECT_WIDE's row says macOS's byte walk takes it with
  HOS_COLLECT_VECTOR=0; HOS_COLLECT_VECTOR's row as the commit's, without "as on the
  other systems".

Assisted-by: Claude Opus 5.5
Co-Authored-By: Claude Opus 5.5 <[email protected]>
(cherry picked from commit 74619b9b3f5553aa7d1ad8bc6384c42e2584a9b7)
Hand resolution on topic/draw-path, where #702 (FanIndirect) met #703 (ProvokingFirst), siblings on #701 that only this topic
combines. test_fan_indirect (#702) cuts draw()'s indirect block up to "} else if (d.indexed) {"; #703 puts its own branch,
"} else if (pv.made) {" (the list written into the stream and drawn as an indexed draw), between the two, so the cut took it in and
the fixture no longer built (pv, ProvokingWrite, game_topo, drawid_direct undeclared). The cut now ends at draw()'s next branch,
whichever it is, as Integration 37's eb4d02046 has it (its tests/test_fan_indirect.py line only). The check keeps what it requires;
no source changes.

test_fan_indirect: failing at 5efbe9d8 on arm64 and x86_64, passing with this commit; passing at #702's Sweep3 head d7878c9d.

Assisted-by: Claude Opus 5.5
Co-Authored-By: Claude Opus 5.5 <[email protected]>
The base's hand resolution c2cfee0f (test_fan_indirect's cut, #702 with #703).

Assisted-by: Claude Opus 5.5
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Hand resolution on restack/fix/indirect-quads, where #705 (IndirectQuads) meets topic/draw-path (#678, #680, #701, #703), as
Integration 36's 74da414a and Integration 37's eb4d02046 resolved it (only their hunks at this level: no PerfInstr hook, no mesh
fallback part).

- gpu/vk/vk_draw.cpp: #705's indirect quad draw is a sixth draw site in draw(). Its count gains ProvokingFirst's provoking_note
  (#703) and FanKey's census_fan_draw (#701), as the other sites and the direct quads' have them. Both return at once off Apple and
  off MoltenVK (provoking_first() is false off __APPLE__; census_fan_draw checks VK_DRIVER_ID_MOLTENVK): log-only counts, nothing
  recorded or drawn changes on any driver. Off Apple the two calls are the token change.
- tests/test_quad_draws.py (#705's): the direct quad draw as topic/draw-path has it, DrawIdDirect's record (rq) drawn from its
  words, then the count with provoking_note, then quad_drawn.
- tests/test_provoking_first.py (#703's): six census_draw sites, each with provoking_note (was five).
- tests/test_fan_key.py (#701's): three non-mesh sites of six counts (was two of five).
- tests/test_index8_bind.py (#678's): draw()'s indirect and direct branches found at a line's start (#705's rewrite gate holds a
  deeper "if (d.indirect) {" line first).
Each check keeps what it requires; none is dropped.

test_quad_draws, test_provoking_first and test_index8_bind failed at the merge before this commit; with it they pass, with
test_fan_key and test_fan_indirect, on arm64 and x86_64.

Assisted-by: Claude Opus 5.5
Co-Authored-By: Claude Opus 5.5 <[email protected]>
The base's hand resolution c2cfee0f (test_fan_indirect's cut, #702 with #703).

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)
The base's update: topic/draw-path's hand resolution c2cfee0f and #705's a27f8f47 (the indirect quads' count with provoking_note and FanKey's census; four checks).

Assisted-by: Claude Opus 5.5
Co-Authored-By: Claude Opus 5.5 <[email protected]>

# Conflicts:
#	tests/test_provoking_first.py
The base's update: topic/draw-path's hand resolution c2cfee0f (#707's restack takes it, nothing else).

Assisted-by: Claude Opus 5.5
Co-Authored-By: Claude Opus 5.5 <[email protected]>
The base's fixture fix 70cc5ba1 (test_vendor_fixes' Apple-drivers fixture and test_subgroup_vertex's stub, #698 with #694/#696/#697). Merged after c2cfee0f, which was in before the fix was named: the tree is the same in either order (the two touch different tests).

Assisted-by: Claude Opus 5.5
Co-Authored-By: Claude Opus 5.5 <[email protected]>
The base's fixture fix 70cc5ba1 (topic/shader-backend), by topic/draw-path.

Assisted-by: Claude Opus 5.5
Co-Authored-By: Claude Opus 5.5 <[email protected]>
The base's update: the fixture fix 70cc5ba1 (topic/shader-backend), by topic/draw-path.

Assisted-by: Claude Opus 5.5
Co-Authored-By: Claude Opus 5.5 <[email protected]>
The base's fixture fix 70cc5ba1 (topic/shader-backend), by topic/draw-path.

Assisted-by: Claude Opus 5.5
Co-Authored-By: Claude Opus 5.5 <[email protected]>
The base's update: the fixture fix 70cc5ba1 (topic/shader-backend), by topic/draw-path.

Assisted-by: Claude Opus 5.5
Co-Authored-By: Claude Opus 5.5 <[email protected]>
The base topic's resolution fixes (b8ba5986): topic 4's fixture fix 70cc5ba1, topic 6's c2cfee0f (test_fan_indirect's
cut, #702 x #703) and #705's restack fix a27f8f47 (the indirect quads' count carries provoking_note and FanKey's census,
#705 x #703/#701), so that this topic's own checks run on them.

Assisted-by: Claude Opus 5.5
Co-Authored-By: Claude Opus 5.5 <[email protected]>
In this topic #704's PerfInstr hook (perf_drawn after every counted draw) meets #705's IndirectQuads, whose one
vkCmdDrawIndexedIndirect is a sixth counted site in draw() (restacked, with provoking_note and FanKey's census,
a27f8f47): it gets the hook after the census, in the order the direct quads' site has them (count, census,
perf hook, quad_drawn), as I41's 74da414a. Log-only, off by default (RX_VK_PERF_LINES and the GPU timeline): what is
recorded and drawn does not change. test_perf_lines checks six sites (was five), with FanKey's census line at the
three non-mesh ones and FanIndirect's after it at the common end, exactly one place (I41's eb4d0204 form).

Assisted-by: Claude Opus 5.5
Co-Authored-By: Claude Opus 5.5 <[email protected]>
The stream-room port (dd801607) brought StreamRoom's fixture from I40, where provoking_list's gate is
"if (dev.provoking_vertex) return {};". In this topic #703 gates it with provoking_first() (a device without
provokingVertexLast, on macOS; every device off macOS asks NVN's last vertex of the device), defined outside the
lines the fixture cuts, so stream_room_test.cpp did not build. The fixture now cuts provoking_first too when the
tree has it (@PROVOKING_FIRST@); a tree without it (--source on I40) builds as before.

Assisted-by: Claude Opus 5.5
Co-Authored-By: Claude Opus 5.5 <[email protected]>
The page-scan port (cd7dd435) took host/rx_backend.c from marks_clear to host_collect in one piece, as on I40, where
every system read the marks with byte loads. In this topic main's word-load test (marks_clear_256) sits between, in
the #else of macOS's marks_clear (#480), so the piece began inside an #if and did not compile ("#else without #if").
The fixture now takes macOS's marks_clear, the vector walk (its comment to collect_in) and collect_in, each whole.

Assisted-by: Claude Opus 5.5
Co-Authored-By: Claude Opus 5.5 <[email protected]>
In this topic #702's test_fan_indirect (topic 6) cuts draw()'s indirect block, where #782 (Widen8) asks
widen8_range for a restart-off 8-bit draw's 16-bit bind with the pipeline's last_dyn.restart; its fixture had
neither, so it did not build at the topic's tip (it passes at #702's and #782's Sweep3 heads). It gets I41's stubs
(47f4695b): W8Bind and a widen8_range that widens nowhere, as on every driver but MoltenVK, and a last_dyn with
restart off. The fixture is now I41 78ec1c47's, byte for byte.

Assisted-by: Claude Opus 5.5
Co-Authored-By: Claude Opus 5.5 <[email protected]>
fix(macos): draw_index8_report's closing brace, lost where #701's fan census report met #678's 8-bit report (#678 with #701)
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 5s
CI / Workflow lint (actionlint) (pull_request) Successful in 9s
Guide screenshots / Guide images and local UI source review (pull_request) Failing after 8s
Third-party parts / As their notes say (pull_request) Successful in 17s
PR description / Description follows the template (pull_request_target) Successful in 24s
67fd90bc88
Hand resolution on topic/draw-path. #701's resolution (chain commit 21e6ec79) placed draw_fan_census_report after #678's
draw_index8_report and dropped the closing } of draw_index8_report, so gpu/vk/vk_draw.cpp stopped compiling from there ("function
definition is not allowed here" at draw_fan_census_report, then every later definition), on arm64 and x86_64, at every commit from
21e6ec79 to this one. The } goes back after the report's logf, as Integration 41 (78ec1c47, vk_draw.cpp 5087) has it, without
#782's widen8_report line (topic mac-perf). No other change.

Found by the whole-file compile of vk_draw.cpp at this topic's tip and at the topics on it.

Assisted-by: Claude Opus 5.5
Co-Authored-By: Claude Opus 5.5 <[email protected]>
The base's hand resolution 67fd90bc (draw_index8_report's closing brace, #678 with #701).

Assisted-by: Claude Opus 5.5
Co-Authored-By: Claude Opus 5.5 <[email protected]>
The base's hand resolution 67fd90bc (draw_index8_report's closing brace, #678 with #701).

Assisted-by: Claude Opus 5.5
Co-Authored-By: Claude Opus 5.5 <[email protected]>
The base's update: topic/draw-path's 67fd90bc (draw_index8_report's closing brace).

Assisted-by: Claude Opus 5.5
Co-Authored-By: Claude Opus 5.5 <[email protected]>
The base's update: topic/draw-path's 67fd90bc (draw_index8_report's closing brace).

Assisted-by: Claude Opus 5.5
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Hand resolution on topic/draw-path-quads-mesh. The base merge of #707 (3d3939ad) put #707's MeshCountDraws report block in
gpu/vk/vk_replay.cpp's log_frame_stats ({ char when[48]; snprintf(...); draw_mesh_report(when, 120.0); }) before #702's FanIndirect
block and dropped the block's closing }, so vk_replay.cpp stopped compiling from there ("function definition is not allowed here"
at status_tick, then every later definition), on arm64 and x86_64, at every commit of this topic from 3d3939ad on. restack/fix/
mesh-count (cb500844) and Integration 41 (78ec1c47, vk_replay.cpp 3962) have the }; it goes back. No other change.

Assisted-by: Claude Opus 5.5
Co-Authored-By: Claude Opus 5.5 <[email protected]>
The base topics' compile fixes (d99221c4): topic 6's 67fd90bc (draw_index8_report's closing } in vk_draw.cpp, which
the chain's #701 resolution had dropped) and topic 7's d99221c4 (log_frame_stats' MeshCountDraws block's closing } in
vk_replay.cpp, dropped at topic 7's merge of #707), with the restacks' merges of them. One conflict: draw_index8_report's
end, where this topic's #782 resolution already had the } after Widen8's widen8_report(when): kept as it is.

Assisted-by: Claude Opus 5.5
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Hand resolution on restack/fix/mesh-count, where #707 (MeshCountDraws) meets #680 (DrawIdDirect), a pair this restack first
combines. #707 declares BuiltIn DrawIndex for a stage loading DrawID except a mesh fallback's task or mesh stage (a GLCompute stage,
its draw index pushed); test_drawid_direct (#680's) pinned the old condition and failed ("spirv_emit_context.cpp declares
DrawIndex other than for a stage loading DrawID and the mesh-first task stage") at this restack and at topic draw-path-quads-mesh,
on arm64 and x86_64. It now pins the new one (DrawIdDirect's direct draws never come from those stages), and
program_reads_draw_index's comment says so: Integration 36's b4732392, its test_drawid_direct hunk and that comment only (its
perf_lines parts belong to topic mac-perf). No code change: the comment is the only vk_draw.cpp change.

test_drawid_direct: failing before this commit, passing with it, on arm64 and x86_64.

Assisted-by: Claude Opus 5.5
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Merge restack/fix/mesh-count into topic/draw-path-quads-mesh
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 6s
CI / Workflow lint (actionlint) (pull_request) Successful in 12s
Guide screenshots / Guide images and local UI source review (pull_request) Failing after 13s
Third-party parts / As their notes say (pull_request) Successful in 24s
PR description / Description follows the template (pull_request_target) Successful in 17s
90ab8ea110
The base's update: #707's 19d6d2d4 (test_drawid_direct pins MeshCountDraws' DrawIndex condition, #707 with #680).

Assisted-by: Claude Opus 5.5
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Merge topic/draw-path-quads-mesh into topic/mac-perf
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 9s
CI / Workflow lint (actionlint) (pull_request) Successful in 14s
Guide screenshots / Guide images and local UI source review (pull_request) Failing after 21s
Third-party parts / As their notes say (pull_request) Successful in 38s
PR description / Description follows the template (pull_request_target) Successful in 23s
bc0c77992e
The base topic's 90ab8ea1: #707's restack fix 19d6d2d4 (test_drawid_direct pins MeshCountDraws' DrawIndex condition,
I41 b4732392), merged into topic 7. This topic already had the same lines from #783 (its commit 3d33cd20 carries
b4732392), so the merge changes no file here: it keeps topic 7's tip in this topic's history.

Assisted-by: Claude Opus 5.5
Co-Authored-By: Claude Opus 5.5 <[email protected]>
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 9s
CI / Workflow lint (actionlint) (pull_request) Successful in 14s
Guide screenshots / Guide images and local UI source review (pull_request) Failing after 21s
Third-party parts / As their notes say (pull_request) Successful in 38s
PR description / Description follows the template (pull_request_target) Successful in 23s
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_replay.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-mac-perf:mooki-mac/topic-mac-perf'
git switch 'mooki-mac/topic-mac-perf'
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!852
No description provided.