fix(vk): give programs that read storage buffer lengths descriptor sets on MoltenVK #644

Closed
mooki wants to merge 2 commits from mooki/Longshot:mac/mvk-sizes into main
Member

Type: fix · Risk: low · Tested on: macOS 26.7.1, Apple M4 Max (MoltenVK 1.4.2), game-free at this head · Needs: Windows, Linux

Why

On a Mac, MoltenVK leaves a pushed storage buffer's length at 0, whatever the buffer's size: it writes the sizes a shader
reads for OpArrayLength only for a descriptor set bound with vkCmdBindDescriptorSets, never for a pushed one. The
renderer's shaders find which storage buffer holds a game address by those lengths, so in a pushed program no buffer ever
matched. The program still ran, but wrongly and silently: its writes and atomics to game memory were dropped, the atomics
returned 0, and reads the page table does not serve read 0. This PR gives every program whose shader reads a storage
buffer's length an ordinary descriptor set on MoltenVK, where the lengths are exact. Other drivers are unchanged. It is
part of the macOS port and stacks on #643. See #420.

How to reproduce

Seen on: macOS 26.7.1, Apple M4 Max, MoltenVK 1.4.2, arm64 and x86_64 under Rosetta: the NullRangeProbe GPU check,
revision 02 (reports/2026-11-14-null-range-probe.md; main does not build on macOS yet)
Settings and switches: defaults
Steps: in the game nothing is reported: the wrong results are silent. Game-free: in #643's tree (this PR's base), copy
in this PR's tests/test_set_for_lengths.py, tests/set_for_lengths_ir.cpp and tests/test_vendor_fixes.py, and run
python -I -B tests/test_set_for_lengths.py --cxx clang++ --spirv-headers <SPIRV-Headers/include> --headers <Vulkan-Headers/include> --jobs 1. On the GPU: the probe's pushed and set arms.
Expected: a program that reads a storage buffer's length gets a set on MoltenVK; the probe's pushed lengths equal the
ranges bound.
Actual: the probe read 0 for every pushed storage buffer's OpArrayLength, in every shape (single views, aliased
views, LS's 88-byte push-constant range, a module from LS's own emitter), on both CPU routes; ordinary sets read the exact
lengths. The test pushes 17 of 138 layouts that need a set (push, expected set).

What changed

On MoltenVK a program whose SPIR-V reads a storage buffer's length (OpArrayLength) in any stage is no longer pushed: it
gets an ordinary set, as #643's storage buffer tables do. Each stage's SPIR-V is scanned once for that instruction where the
program cache already handles it, and a compute program read from the cache without its code is decided by its global
memory use until the code is read. A switch forces it either way, and the log says whether it is on and, at close, how many
programs it moved. The SPIR-V, the translator's stamp and the program cache's format are unchanged.

  • vk: gpu/vk/vk_vendor.h: a new fix, VendorFixes::set_for_lengths, on by default when driver_id == VK_DRIVER_ID_MOLTENVK, forced by RX_VK_SET_FOR_LENGTHS.
  • vk: gpu/vk/spirv_lengths.h (new, no Vulkan, like fallback_size_policy.h): spirv_lengths::array_length(words, count) walks a module once: 1 when it has an OpArrayLength, 0 when not, 1 for words that do not walk as a module.
  • vk: Stage::array_length in gpu/vk/vk_shader.h (-1 until the stage's SPIR-V is seen; not written to the cache file),
    noted in gpu/vk/vk_progcache.cpp at the three places the stage's phis are: program_cache_save (every translated
    program, before it is published), a whole record's read, and complete_from (a light compute program's code read later).
  • vk: layout_pushes(p, bindings, total) in gpu/vk/vk_draw.cpp: with the fix on, a program with array_length > 0 in any
    stage, or < 0 (not read yet) in a stage that uses global memory, gets a set; two counters keep the moves, and
    draw_layouts_report() logs them once at close (mkwvk_close_asked in gpu/vk/vk_main.cpp, after the program census).
    Outside segmented variants, which the cache never keeps, the back end reads a length only in its global memory search, so
    the not-read-yet rule is a superset.
  • vk: the vk: vendor fixes line in create_device gains programs reading storage buffer lengths in descriptor sets, not pushed %d.
  • docs: the RX_VK_SET_FOR_LENGTHS row in docs/development.md; gpu/vk/VULKAN.md's Descriptors bullet names both
    MoltenVK exceptions.
  • tests: tests/test_set_for_lengths.py and tests/set_for_lengths_ir.cpp (new) build six real modules through the
    back end (CollectShaderInfoPass, EmitSPIRV: compute and vertex global memory with a storage buffer, 18
    OpArrayLength each; global memory with nothing to search; direct storage in compute, vertex and fragment stages, none),
    recount each module's OpArrayLength in Python, and compile vk_draw.cpp from kPushSize to the end of
    ensure_layout with their descriptors and notes: 138 layouts on MoltenVK and ten other drivers, the switch unset, 0
    and 1, stages not read yet, and the bindings the same pushed or not. They also check the scan on words that are not a
    module and the counts kept for the close line. tests/test_vendor_fixes.py covers the new fix on 17 devices and checks
    that both layout fixes stay out of translator_stamp() and make_profile(), that layout_pushes reads the notes, and
    that the log line, the close and the three notes are there. tests/test_set_for_tables.py's stub stage gets
    array_length = 0; the program cache fixtures (tests/program_cache_one_variant_test.cpp,
    tests/program_cache_cleanup_test.cpp) include spirv_lengths.h, as they compile vk_progcache.cpp's functions.

Measurements

Verdict: passes: the new test fails on #643's head (17 of 138 layouts pushed where a set is needed, and no scan) and
passes at this head, two interleaved runs each. In the game (history, an integration build) the close line counted 2,023
programs moved.

Baseline: #643 @ 77a91fc9, this PR's base in the stack. Main lacks #643's layout_pushes, which this PR extends, so main
against this PR would measure #643 too.

Hardware: macOS 26.7.1, Apple M4 Max, 16-core CPU, 64 GB, Apple clang 21.0.0 (game-free: no GPU, no game)
Scene: none for the tests (a layout fix: its proof is the test). The game row below is history: start 12's precompile,
windowless, defaults
Method: tests/test_set_for_lengths.py (--jobs 1) and tests/test_vendor_fixes.py run as this head, base, this head,
base (arm64, fresh HOME and TMPDIR, tools/slot.py), the base tree with this PR's test files copied in (SHA-256 equal)
How to reproduce: python -I -B tests/test_set_for_lengths.py --cxx clang++ --spirv-headers <SPIRV-Headers/include> --headers <Vulkan-Headers/include> --jobs 1 and python -I -B tests/test_vendor_fixes.py --cxx clang++ --headers <Vulkan-Headers/include>, in this PR's tree and in #643's with the test files copied in

Before: #643 @ 77a91fc9 After: this PR @ e90ba9a6
tests/test_set_for_lengths.py, arm64, 2 runs each fails both runs: 17 of 138 layouts push, expected set; no count kept; no spirv_lengths.h passes both runs: 6 real modules, 138 layouts, 0 not as expected
tests/test_vendor_fixes.py, arm64, 2 runs each fails both runs: layout_pushes does not read dev.fixes.set_for_lengths passes both runs: 17 devices
#643 @ 77a91fc9 (this PR's test):
layouts: 138 cases, 17 not as expected
FAIL:
  vk_draw.cpp: ensure_layout's code keeps no count of the programs set_for_lengths gives a set
  moltenvk.compute_global: push, expected set
  moltenvk.compute_global.unread: push, expected set
  moltenvk.compute_global_bare.unread: push, expected set
  moltenvk.graphics_global: push, expected set
  (… the same four with the switch at 1 on MoltenVK, NVIDIA and RADV, and bindings.moltenvk)
  gpu/vk/spirv_lengths.h: no array_length, the scan each stage's note is made with
this PR @ e90ba9a6:
layouts: 138 cases, 0 not as expected
ok: 6 real modules; 138 layouts: on MoltenVK a program whose SPIR-V reads a storage buffer's length in any stage gets a set (and one not read yet by its global memory use), every other program and every other driver pushes as before, RX_VK_SET_FOR_LENGTHS forces it both ways, the bindings are the same pushed or not

History, not this head: start 12 (reports/2026-11-14-mac-startup-12.md, arm64, integration build a7711f3c, which
carries this commit as bf5ca961), the first start whose precompile laid out real pipelines: the close line counted
2,023 programs given a set for their storage buffer lengths. The cause was measured by the NullRangeProbe GPU check,
revision 02, on both CPU routes (reports/2026-11-14-null-range-probe.md): with a push layout every OpArrayLength read 0
and the guarded loads were skipped; with an ordinary set every length was exact. Whether the game draws differently with
this change on was not compared.

Flags and settings

One new switch, RX_VK_SET_FOR_LENGTHS; its default is on with MoltenVK only. (RX_VK_SET_FOR_TABLES, in this PR's diff
until #643 merges, is #643's and unchanged here.)

Flag What it is Before this PR After this PR Effect Helps / doesn't help / untested Recommendation
RX_VK_SET_FOR_LENGTHS 0 or 1: a program whose SPIR-V reads a storage buffer's length in any stage gets an ordinary descriptor set instead of a pushed one (no switch: pushed wherever the set fits the push limit) unset: on with MoltenVK, off with every other driver; 0 off, 1 on, whatever the driver on: these programs' sets are allocated and bound per draw or dispatch, and their lengths are exact on MoltenVK; a line at close counts them helps: MoltenVK (global memory stores, atomics and loads by storage buffer reach their buffers); doesn't help: other drivers, whose pushed lengths are right; untested: the game with it off against on, and =1 on another driver leave unset; =0 only to compare on a Mac, =1 only to try the set path on another GPU

Testing

Tested: on macOS 26.7.1, Apple M4 Max, at e90ba9a6, this PR's head before the rebases onto e090cc48 and aa95d35f
(main 6c9edffe plus #643 and this PR), game-free:

  • tests/test_set_for_lengths.py and tests/test_vendor_fixes.py, arm64: pass at this head (2 runs each); fail on #643's
    head with this PR's test files (2 runs each), as in Measurements. The failing side ran on arm64 only (the owner's rule for
    these fixtures' negatives, after the employer's endpoint agent killed an x86_64 negative in an earlier lane).
  • At this head with the fixtures compiled for x86_64 (clang++ -arch x86_64, run under Rosetta): test_set_for_lengths
    (6 real modules, 138 layouts) and test_vendor_fixes (17 devices) pass. test_set_for_tables' x86_64 fixture was
    killed (SIGKILL, exit -9, no crash report: the endpoint agent [inference]); by policy it was not retried. It passes here
    on arm64 (79 layouts) and, as #646's superset, on x86_64 at the top of the stack.
  • tests/test_program_cache_one_variant.py and tests/test_program_cache_cleanup.py (the fixtures this PR touches) fail
    at this head and on main 6c9edffe alike, on arm64 and x86_64: they compile main's posix_fadvise read-ahead hint, which
    macOS lacks (#476 gives it a Darwin path). With a test-only prelude declaring the hint as a no-op (given through the
    compiler wrapper, the same on both sides) both pass at this head on arm64 and x86_64, and on main on arm64 (one variant:
    11 modules whole, 1 light, the same variant for 9 picks; cleanup: 9 tests OK).
  • The 133 tests that read the files this stack changes (tests naming a changed file, or cutting ensure_layout,
    make_pool, layout_pushes and their neighbours), through tools/ls-suite.py at this head and on main 6c9edffe: here
    123 passed and 10 failed, main 121 passed and 10 failed. The same 10 fail on both (test_appimage_player_build,
    test_crash_dialog, test_pcache_header_read, test_pipeline_cache_save, test_pipeline_play_cache,
    test_pipeline_tour, test_precompile_compute_guard, test_program_cache_cleanup, test_program_cache_one_variant,
    test_shader_module_guard: macOS gaps on main, the last two Windows-only checks); the only status changes are this
    stack's two new tests passing (related-P26-e90ba9a6/compare-main-names-summary.txt).
  • vk_draw.cpp, vk_main.cpp and vk_progcache.cpp compiled for arm64 and x86_64 at this head with main's renderer flags
    (nx2/build.py's vflags plus -arch) and a compile-only prelude declaring posix_fallocate and posix_fadvise,
    which main's renderer calls and macOS lacks (#476 gives them Darwin paths): exit 0 for all six.
  • The translator's stamp (nx2/translator_files.py stamp()) is ebbf160ce9626041 on main and at this head.
  • git merge-tree of this head with each open macOS PR's head (#431, #437, #438, #479, #480, #490, #491, #492): no
    conflict.
  • Logs: reports/PubWave-files/PubMvk/proof/P26-*.log, related-P26-*, objects2-P26-*, merge-tree.txt.
  • After the rebase onto main aa95d35f, at f08eb702 (e90ba9a6 before the rebases onto e090cc48 and aa95d35f):
    Sweep3's checks of this head (the C/C++ it changes compiled, and its own tests run, on arm64 and x86_64 where they
    apply) gave the same results as before; python -I -B tests/run_all.py on wave B's merge db0e2e16, which carries
    this head: 569/32/18 (passed/failed/skipped) against main aa95d35f's 543/33/17 on this Mac, no new failure
    (reports/2026-11-15-rebase-sweep-3.md).
  • macOS game runs with this PR in the stack: arm64, windowless: run E9a on I41 78ec1c47, which carries every Mac
    PR through #708 and the I41 fixes: a start from the field-dawn save to a 1,197 s hold in play, the runner's 12 of 12
    checks passed, 0 skipped draws in the hold, 0 XPC errors, a clean exit (reports/2026-11-15-mac-perf-E9.md); x86_64
    under Rosetta 2: run #34 on I38 3f872b0c: 16 m 52 s of play, 19 of 19 checks, 0 skipped draws, 1,906 draws a frame,
    no device loss, a clean exit (reports/2026-11-14-mac-startup-34-x86_64.md).
  • E9a's log (line 200): … programs reading storage buffer lengths in descriptor sets, not pushed 1 …; at close
    (line 65749): vk: storage buffer lengths (RX_VK_SET_FOR_LENGTHS): 11472 programs given a descriptor set, not pushed, because a stage reads a storage buffer's length, which MoltenVK leaves 0 in a pushed set (0 of them laid out before their code was read, by their global memory use). Under Rosetta, #34's 19 of 19 checks stand for it; that log's lines
    for this PR are not quoted here.

Not tested: not built on Windows or Linux; its test request covers it. The game at this head (per-PR game runs are
not planned; the stack's runs with it, E9a on arm64 and #34 under Rosetta, are under Tested); the game with
RX_VK_SET_FOR_LENGTHS=0 against unset, to see what the dropped writes did on screen; the cost of the extra sets
(RX_VK_PROF_FINE=1 counts them); KosmicKrisp. The audit's other open items are outside this PR: an empty size buffer
picking up stale bytes, a pushed texel size query, and the prebuilt FSR 3 frame interpolation SPIR-V (back-end pipelines
with layouts of their own, which never pass layout_pushes). Windows and Linux: nothing was built or run there; their
layouts do not change (the test's ten other drivers).

Must be tested:

  • Windows and Linux, any GPU: build this PR (head f08eb702, it carries #643) and main aa95d35f the same way, start each to
    the title and quit, expecting the build to succeed, the vk: vendor fixes line to end programs reading storage buffer lengths in descriptor sets, not pushed 0, no vk: storage buffer lengths line at close, and every other line to match
    main's (by hand: test request T-HG4R)

Risks

What could break: on MoltenVK these programs (2,023 in start 12) now allocate, write and bind a set per draw or
dispatch instead of a push, and leave Metal's 31 discrete buffer slots; that cost is unmeasured. A light compute program
with global memory but no length gets a set it does not need until its code is read (counted apart at close). On every
platform each stage's SPIR-V gets one more walk over its words where the program cache already walks them for phis; on
other drivers nothing else changes.

Turning it off: RX_VK_SET_FOR_LENGTHS=0 (MoltenVK's pushed lengths then read 0 again), or revert the commit.

Compatibility: Nothing changes in saves, longshot_options.ini or the vk ABI (MKWVK_API_VERSION). The shader caches
are kept: none of the changed files is in the translator's stamp (ebbf160ce9626041 before and after), and the note is
not written to the program cache, whose format is unchanged. On Windows and Linux the vk: vendor fixes line has one more
field (0). On macOS the moved programs' pipelines change layout, so Metal compiles them once.

Reviewer notes

  • Review e90ba9a6 (this PR's one commit, cherry-picked with -x from macos/mvk-sizes bf5ca961): layout_pushes
    and draw_layouts_report in vk_draw.cpp, then the three notes in vk_progcache.cpp, spirv_lengths.h and the stage
    field.
  • Depends on #643: this branch is stacked on its head, 77a91fc9, and shows its commit too until #643 merges. #645 and #646
    stack on this one.
  • Conflicts with main: none for this commit. Main's #252 (57f4eaec) gave complete_from its busy path and #321
    (76699aad) moved the cache file: the notes follow make_module as before, and a busy return reaches the note when the
    code is read again. The three places a stage's SPIR-V is noted are still every place the program cache reads or saves it.
  • Conflict resolved in the cherry-pick, from the stack: gpu/vk/vk_main.cpp's vk: vendor fixes logf (the topic's base
    also had #650's two fields there): one logf with #643's field and this PR's, without #650's. And docs/development.md:
    this PR's RX_VK_SET_FOR_LENGTHS row after #643's row and before main's RX_VK_NATIVE_FADD row (#191 7ec25fd1
    rewrote that row; the topic's side also carried #649's RX_VK_TEXEL_CODECS row, left to #649).
  • With the PRs of this wave: #650 (prep-fast) changes the same logf (a conflict in git merge-tree against its branch tip
    f5905178): whichever lands second keeps one logf holding every field, in order (set_for_tables, set_for_lengths, worker_caches, pcache_no_load, as the integration did). The plan has this PR rebase after #648 and #650.
  • tests/test_program_cache_cleanup.py and tests/test_program_cache_one_variant.py fail on macOS on main 6c9edffe and
    here alike: their fixtures compile main's posix_fadvise call, which macOS lacks (#476 fixes that). With the hint
    declared as a no-op both pass here (arm64, x86_64) and on main (proof/P26-program_cache_*-fadvise-*.log).
  • #663 (seg-bind, a later wave) adds stubs to tests/test_set_for_lengths.py's fixture (presence_words,
    seg_layout_count) when it lands, as the integration's 071c628f did.

Issues

See #420

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. (Test request T-HG4R.)
  • Rebased on current main: on aa95d35f (#761, 2026-11-15), head f08eb702, on #643 ca17df3b, without a
    conflict; this PR's own commits, old → new: e90ba9a6 → f08eb702; the commit names elsewhere in this description
    are from before the rebase.
  • python -I -B tests/run_all.py passes (any failure that also fails on main is named). (On the wave's merge of every macOS PR built with this one, 453eb678: 553 passed, 32 failed, 18 skipped against main 6c9edffe's 531/32/17 on this Mac; the failures are main's own except test_split_ub_flush, which #658's tree at the time broke and its head fixes; test_collect_wide now passes; the new tests pass and test_darwin_audio_service, Darwin-only, is skipped by the runner; reports/PubWave-files/waveA/. After the rebase onto main aa95d35f (head f08eb702): wave B's merge db0e2e16, 569/32/18 against main aa95d35f's 543/33/17, no new failure.)
  • 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.
  • Switches documented (docs/development.md; the README for a menu row) and shipped at their recommended value.
  • A game-free test added for the fix, failing on main and passing here. (Failing on #643's head, this PR's base.)
  • A check under tests/ that reads changed source updated in this PR, not weakened.
  • Docs updated.
**Type:** fix · **Risk:** low · **Tested on:** macOS 26.7.1, Apple M4 Max (MoltenVK 1.4.2), game-free at this head · **Needs:** Windows, Linux ## Why On a Mac, MoltenVK leaves a pushed storage buffer's length at 0, whatever the buffer's size: it writes the sizes a shader reads for `OpArrayLength` only for a descriptor set bound with `vkCmdBindDescriptorSets`, never for a pushed one. The renderer's shaders find which storage buffer holds a game address by those lengths, so in a pushed program no buffer ever matched. The program still ran, but wrongly and silently: its writes and atomics to game memory were dropped, the atomics returned 0, and reads the page table does not serve read 0. This PR gives every program whose shader reads a storage buffer's length an ordinary descriptor set on MoltenVK, where the lengths are exact. Other drivers are unchanged. It is part of the macOS port and stacks on #643. See #420. ## How to reproduce **Seen on:** macOS 26.7.1, Apple M4 Max, MoltenVK 1.4.2, arm64 and x86_64 under Rosetta: the NullRangeProbe GPU check, revision 02 (`reports/2026-11-14-null-range-probe.md`; main does not build on macOS yet) **Settings and switches:** defaults **Steps:** in the game nothing is reported: the wrong results are silent. Game-free: in #643's tree (this PR's base), copy in this PR's `tests/test_set_for_lengths.py`, `tests/set_for_lengths_ir.cpp` and `tests/test_vendor_fixes.py`, and run `python -I -B tests/test_set_for_lengths.py --cxx clang++ --spirv-headers <SPIRV-Headers/include> --headers <Vulkan-Headers/include> --jobs 1`. On the GPU: the probe's pushed and set arms. **Expected:** a program that reads a storage buffer's length gets a set on MoltenVK; the probe's pushed lengths equal the ranges bound. **Actual:** the probe read 0 for every pushed storage buffer's `OpArrayLength`, in every shape (single views, aliased views, LS's 88-byte push-constant range, a module from LS's own emitter), on both CPU routes; ordinary sets read the exact lengths. The test pushes 17 of 138 layouts that need a set (`push, expected set`). ## What changed On MoltenVK a program whose SPIR-V reads a storage buffer's length (`OpArrayLength`) in any stage is no longer pushed: it gets an ordinary set, as #643's storage buffer tables do. Each stage's SPIR-V is scanned once for that instruction where the program cache already handles it, and a compute program read from the cache without its code is decided by its global memory use until the code is read. A switch forces it either way, and the log says whether it is on and, at close, how many programs it moved. The SPIR-V, the translator's stamp and the program cache's format are unchanged. - vk: `gpu/vk/vk_vendor.h`: a new fix, `VendorFixes::set_for_lengths`, on by default when `driver_id == VK_DRIVER_ID_MOLTENVK`, forced by `RX_VK_SET_FOR_LENGTHS`. - vk: `gpu/vk/spirv_lengths.h` (new, no Vulkan, like `fallback_size_policy.h`): `spirv_lengths::array_length(words, count)` walks a module once: 1 when it has an `OpArrayLength`, 0 when not, 1 for words that do not walk as a module. - vk: `Stage::array_length` in `gpu/vk/vk_shader.h` (`-1` until the stage's SPIR-V is seen; not written to the cache file), noted in `gpu/vk/vk_progcache.cpp` at the three places the stage's phis are: `program_cache_save` (every translated program, before it is published), a whole record's read, and `complete_from` (a light compute program's code read later). - vk: `layout_pushes(p, bindings, total)` in `gpu/vk/vk_draw.cpp`: with the fix on, a program with `array_length > 0` in any stage, or `< 0` (not read yet) in a stage that uses global memory, gets a set; two counters keep the moves, and `draw_layouts_report()` logs them once at close (`mkwvk_close_asked` in `gpu/vk/vk_main.cpp`, after the program census). Outside segmented variants, which the cache never keeps, the back end reads a length only in its global memory search, so the not-read-yet rule is a superset. - vk: the `vk: vendor fixes` line in `create_device` gains `programs reading storage buffer lengths in descriptor sets, not pushed %d`. - docs: the `RX_VK_SET_FOR_LENGTHS` row in `docs/development.md`; `gpu/vk/VULKAN.md`'s Descriptors bullet names both MoltenVK exceptions. - tests: `tests/test_set_for_lengths.py` and `tests/set_for_lengths_ir.cpp` (new) build six real modules through the back end (`CollectShaderInfoPass`, `EmitSPIRV`: compute and vertex global memory with a storage buffer, 18 `OpArrayLength` each; global memory with nothing to search; direct storage in compute, vertex and fragment stages, none), recount each module's `OpArrayLength` in Python, and compile `vk_draw.cpp` from `kPushSize` to the end of `ensure_layout` with their descriptors and notes: 138 layouts on MoltenVK and ten other drivers, the switch unset, `0` and `1`, stages not read yet, and the bindings the same pushed or not. They also check the scan on words that are not a module and the counts kept for the close line. `tests/test_vendor_fixes.py` covers the new fix on 17 devices and checks that both layout fixes stay out of `translator_stamp()` and `make_profile()`, that `layout_pushes` reads the notes, and that the log line, the close and the three notes are there. `tests/test_set_for_tables.py`'s stub stage gets `array_length = 0`; the program cache fixtures (`tests/program_cache_one_variant_test.cpp`, `tests/program_cache_cleanup_test.cpp`) include `spirv_lengths.h`, as they compile `vk_progcache.cpp`'s functions. ## Measurements **Verdict:** passes: the new test fails on #643's head (17 of 138 layouts pushed where a set is needed, and no scan) and passes at this head, two interleaved runs each. In the game (history, an integration build) the close line counted 2,023 programs moved. Baseline: #643 @ 77a91fc9, this PR's base in the stack. Main lacks #643's `layout_pushes`, which this PR extends, so main against this PR would measure #643 too. Hardware: macOS 26.7.1, Apple M4 Max, 16-core CPU, 64 GB, Apple clang 21.0.0 (game-free: no GPU, no game) Scene: none for the tests (a layout fix: its proof is the test). The game row below is history: start 12's precompile, windowless, defaults Method: `tests/test_set_for_lengths.py` (`--jobs 1`) and `tests/test_vendor_fixes.py` run as this head, base, this head, base (arm64, fresh HOME and TMPDIR, `tools/slot.py`), the base tree with this PR's test files copied in (SHA-256 equal) How to reproduce: `python -I -B tests/test_set_for_lengths.py --cxx clang++ --spirv-headers <SPIRV-Headers/include> --headers <Vulkan-Headers/include> --jobs 1` and `python -I -B tests/test_vendor_fixes.py --cxx clang++ --headers <Vulkan-Headers/include>`, in this PR's tree and in #643's with the test files copied in | | Before: #643 @ 77a91fc9 | After: this PR @ e90ba9a6 | |---|---|---| | `tests/test_set_for_lengths.py`, arm64, 2 runs each | fails both runs: 17 of 138 layouts `push, expected set`; no count kept; no `spirv_lengths.h` | passes both runs: 6 real modules, 138 layouts, 0 not as expected | | `tests/test_vendor_fixes.py`, arm64, 2 runs each | fails both runs: `layout_pushes does not read dev.fixes.set_for_lengths` | passes both runs: 17 devices | ``` #643 @ 77a91fc9 (this PR's test): layouts: 138 cases, 17 not as expected FAIL: vk_draw.cpp: ensure_layout's code keeps no count of the programs set_for_lengths gives a set moltenvk.compute_global: push, expected set moltenvk.compute_global.unread: push, expected set moltenvk.compute_global_bare.unread: push, expected set moltenvk.graphics_global: push, expected set (… the same four with the switch at 1 on MoltenVK, NVIDIA and RADV, and bindings.moltenvk) gpu/vk/spirv_lengths.h: no array_length, the scan each stage's note is made with this PR @ e90ba9a6: layouts: 138 cases, 0 not as expected ok: 6 real modules; 138 layouts: on MoltenVK a program whose SPIR-V reads a storage buffer's length in any stage gets a set (and one not read yet by its global memory use), every other program and every other driver pushes as before, RX_VK_SET_FOR_LENGTHS forces it both ways, the bindings are the same pushed or not ``` History, not this head: start 12 (`reports/2026-11-14-mac-startup-12.md`, arm64, integration build a7711f3c, which carries this commit as `bf5ca961`), the first start whose precompile laid out real pipelines: the close line counted **2,023** programs given a set for their storage buffer lengths. The cause was measured by the NullRangeProbe GPU check, revision 02, on both CPU routes (`reports/2026-11-14-null-range-probe.md`): with a push layout every `OpArrayLength` read 0 and the guarded loads were skipped; with an ordinary set every length was exact. Whether the game draws differently with this change on was not compared. ### Flags and settings One new switch, `RX_VK_SET_FOR_LENGTHS`; its default is on with MoltenVK only. (`RX_VK_SET_FOR_TABLES`, in this PR's diff until #643 merges, is #643's and unchanged here.) | Flag | What it is | Before this PR | After this PR | Effect | Helps / doesn't help / untested | Recommendation | |---|---|---|---|---|---|---| | `RX_VK_SET_FOR_LENGTHS` | `0` or `1`: a program whose SPIR-V reads a storage buffer's length in any stage gets an ordinary descriptor set instead of a pushed one | (no switch: pushed wherever the set fits the push limit) | unset: on with MoltenVK, off with every other driver; `0` off, `1` on, whatever the driver | on: these programs' sets are allocated and bound per draw or dispatch, and their lengths are exact on MoltenVK; a line at close counts them | helps: MoltenVK (global memory stores, atomics and loads by storage buffer reach their buffers); doesn't help: other drivers, whose pushed lengths are right; untested: the game with it off against on, and `=1` on another driver | leave unset; `=0` only to compare on a Mac, `=1` only to try the set path on another GPU | ## Testing **Tested:** on macOS 26.7.1, Apple M4 Max, at `e90ba9a6`, this PR's head before the rebases onto e090cc48 and aa95d35f (main 6c9edffe plus #643 and this PR), game-free: - `tests/test_set_for_lengths.py` and `tests/test_vendor_fixes.py`, arm64: pass at this head (2 runs each); fail on #643's head with this PR's test files (2 runs each), as in Measurements. The failing side ran on arm64 only (the owner's rule for these fixtures' negatives, after the employer's endpoint agent killed an x86_64 negative in an earlier lane). - At this head with the fixtures compiled for x86_64 (`clang++ -arch x86_64`, run under Rosetta): `test_set_for_lengths` (6 real modules, 138 layouts) and `test_vendor_fixes` (17 devices) pass. `test_set_for_tables`' x86_64 fixture was killed (SIGKILL, exit -9, no crash report: the endpoint agent [inference]); by policy it was not retried. It passes here on arm64 (79 layouts) and, as #646's superset, on x86_64 at the top of the stack. - `tests/test_program_cache_one_variant.py` and `tests/test_program_cache_cleanup.py` (the fixtures this PR touches) fail at this head and on main 6c9edffe alike, on arm64 and x86_64: they compile main's `posix_fadvise` read-ahead hint, which macOS lacks (#476 gives it a Darwin path). With a test-only prelude declaring the hint as a no-op (given through the compiler wrapper, the same on both sides) both pass at this head on arm64 and x86_64, and on main on arm64 (one variant: 11 modules whole, 1 light, the same variant for 9 picks; cleanup: 9 tests OK). - The 133 tests that read the files this stack changes (tests naming a changed file, or cutting `ensure_layout`, `make_pool`, `layout_pushes` and their neighbours), through `tools/ls-suite.py` at this head and on main 6c9edffe: here 123 passed and 10 failed, main 121 passed and 10 failed. The same 10 fail on both (`test_appimage_player_build`, `test_crash_dialog`, `test_pcache_header_read`, `test_pipeline_cache_save`, `test_pipeline_play_cache`, `test_pipeline_tour`, `test_precompile_compute_guard`, `test_program_cache_cleanup`, `test_program_cache_one_variant`, `test_shader_module_guard`: macOS gaps on main, the last two Windows-only checks); the only status changes are this stack's two new tests passing (`related-P26-e90ba9a6/compare-main-names-summary.txt`). - `vk_draw.cpp`, `vk_main.cpp` and `vk_progcache.cpp` compiled for arm64 and x86_64 at this head with main's renderer flags (`nx2/build.py`'s `vflags` plus `-arch`) and a compile-only prelude declaring `posix_fallocate` and `posix_fadvise`, which main's renderer calls and macOS lacks (#476 gives them Darwin paths): exit 0 for all six. - The translator's stamp (`nx2/translator_files.py` `stamp()`) is `ebbf160ce9626041` on main and at this head. - `git merge-tree` of this head with each open macOS PR's head (#431, #437, #438, #479, #480, #490, #491, #492): no conflict. - Logs: `reports/PubWave-files/PubMvk/proof/P26-*.log`, `related-P26-*`, `objects2-P26-*`, `merge-tree.txt`. - **After the rebase onto main aa95d35f**, at `f08eb702` (`e90ba9a6` before the rebases onto e090cc48 and aa95d35f): Sweep3's checks of this head (the C/C++ it changes compiled, and its own tests run, on arm64 and x86_64 where they apply) gave the same results as before; `python -I -B tests/run_all.py` on wave B's merge `db0e2e16`, which carries this head: 569/32/18 (passed/failed/skipped) against main aa95d35f's 543/33/17 on this Mac, no new failure (`reports/2026-11-15-rebase-sweep-3.md`). - **macOS game runs with this PR in the stack:** arm64, windowless: run E9a on I41 `78ec1c47`, which carries every Mac PR through #708 and the I41 fixes: a start from the field-dawn save to a 1,197 s hold in play, the runner's 12 of 12 checks passed, 0 skipped draws in the hold, 0 XPC errors, a clean exit (`reports/2026-11-15-mac-perf-E9.md`); x86_64 under Rosetta 2: run #34 on I38 `3f872b0c`: 16 m 52 s of play, 19 of 19 checks, 0 skipped draws, 1,906 draws a frame, no device loss, a clean exit (`reports/2026-11-14-mac-startup-34-x86_64.md`). - **E9a's log** (line 200): `… programs reading storage buffer lengths in descriptor sets, not pushed 1 …`; at close (line 65749): `vk: storage buffer lengths (RX_VK_SET_FOR_LENGTHS): 11472 programs given a descriptor set, not pushed, because a stage reads a storage buffer's length, which MoltenVK leaves 0 in a pushed set (0 of them laid out before their code was read, by their global memory use)`. Under Rosetta, #34's 19 of 19 checks stand for it; that log's lines for this PR are not quoted here. **Not tested:** not built on Windows or Linux; its test request covers it. The game at this head (per-PR game runs are not planned; the stack's runs with it, E9a on arm64 and #34 under Rosetta, are under Tested); the game with `RX_VK_SET_FOR_LENGTHS=0` against unset, to see what the dropped writes did on screen; the cost of the extra sets (`RX_VK_PROF_FINE=1` counts them); KosmicKrisp. The audit's other open items are outside this PR: an empty size buffer picking up stale bytes, a pushed texel size query, and the prebuilt FSR 3 frame interpolation SPIR-V (back-end pipelines with layouts of their own, which never pass `layout_pushes`). Windows and Linux: nothing was built or run there; their layouts do not change (the test's ten other drivers). **Must be tested:** - Windows and Linux, any GPU: build this PR (head f08eb702, it carries #643) and main aa95d35f the same way, start each to the title and quit, expecting the build to succeed, the `vk: vendor fixes` line to end `programs reading storage buffer lengths in descriptor sets, not pushed 0`, no `vk: storage buffer lengths` line at close, and every other line to match main's (by hand: test request T-HG4R) ## Risks **What could break:** on MoltenVK these programs (2,023 in start 12) now allocate, write and bind a set per draw or dispatch instead of a push, and leave Metal's 31 discrete buffer slots; that cost is unmeasured. A light compute program with global memory but no length gets a set it does not need until its code is read (counted apart at close). On every platform each stage's SPIR-V gets one more walk over its words where the program cache already walks them for phis; on other drivers nothing else changes. **Turning it off:** `RX_VK_SET_FOR_LENGTHS=0` (MoltenVK's pushed lengths then read 0 again), or revert the commit. **Compatibility:** Nothing changes in saves, `longshot_options.ini` or the vk ABI (`MKWVK_API_VERSION`). The shader caches are kept: none of the changed files is in the translator's stamp (`ebbf160ce9626041` before and after), and the note is not written to the program cache, whose format is unchanged. On Windows and Linux the `vk: vendor fixes` line has one more field (`0`). On macOS the moved programs' pipelines change layout, so Metal compiles them once. ## Reviewer notes - Review `e90ba9a6` (this PR's one commit, cherry-picked with `-x` from `macos/mvk-sizes` `bf5ca961`): `layout_pushes` and `draw_layouts_report` in `vk_draw.cpp`, then the three notes in `vk_progcache.cpp`, `spirv_lengths.h` and the stage field. - Depends on #643: this branch is stacked on its head, 77a91fc9, and shows its commit too until #643 merges. #645 and #646 stack on this one. - Conflicts with main: none for this commit. Main's #252 (`57f4eaec`) gave `complete_from` its `busy` path and #321 (`76699aad`) moved the cache file: the notes follow `make_module` as before, and a busy return reaches the note when the code is read again. The three places a stage's SPIR-V is noted are still every place the program cache reads or saves it. - Conflict resolved in the cherry-pick, from the stack: `gpu/vk/vk_main.cpp`'s `vk: vendor fixes` `logf` (the topic's base also had #650's two fields there): one `logf` with #643's field and this PR's, without #650's. And `docs/development.md`: this PR's `RX_VK_SET_FOR_LENGTHS` row after #643's row and before main's `RX_VK_NATIVE_FADD` row (#191 `7ec25fd1` rewrote that row; the topic's side also carried #649's `RX_VK_TEXEL_CODECS` row, left to #649). - With the PRs of this wave: #650 (prep-fast) changes the same `logf` (a conflict in `git merge-tree` against its branch tip `f5905178`): whichever lands second keeps one `logf` holding every field, in order (`set_for_tables, set_for_lengths, worker_caches, pcache_no_load`, as the integration did). The plan has this PR rebase after #648 and #650. - `tests/test_program_cache_cleanup.py` and `tests/test_program_cache_one_variant.py` fail on macOS on main 6c9edffe and here alike: their fixtures compile main's `posix_fadvise` call, which macOS lacks (#476 fixes that). With the hint declared as a no-op both pass here (arm64, x86_64) and on main (`proof/P26-program_cache_*-fadvise-*.log`). - #663 (seg-bind, a later wave) adds stubs to `tests/test_set_for_lengths.py`'s fixture (`presence_words`, `seg_layout_count`) when it lands, as the integration's `071c628f` did. ## Issues See #420 ## Checklist ### Everyone - [x] One topic. - [x] The title is a Conventional Commit (`type(scope): description`) of the status line's type. - [x] Why gives the reason plainly and links the issues that fit (the tracker searched). - [x] Measurements has a verdict, or one line saying why there is nothing to measure. - [x] Testing names what was tested, what wasn't, and what must still be tested, where and how. (Test request T-HG4R.) - [x] Rebased on current `main`: on aa95d35f (#761, 2026-11-15), head `f08eb702`, on #643 `ca17df3b`, without a conflict; this PR's own commits, old → new: `e90ba9a6` → `f08eb702`; the commit names elsewhere in this description are from before the rebase. - [x] `python -I -B tests/run_all.py` passes (any failure that also fails on `main` is named). (On the wave's merge of every macOS PR built with this one, `453eb678`: 553 passed, 32 failed, 18 skipped against main 6c9edffe's 531/32/17 on this Mac; the failures are main's own except `test_split_ub_flush`, which #658's tree at the time broke and its head fixes; `test_collect_wide` now passes; the new tests pass and `test_darwin_audio_service`, Darwin-only, is skipped by the runner; `reports/PubWave-files/waveA/`. After the rebase onto main aa95d35f (head `f08eb702`): wave B's merge `db0e2e16`, 569/32/18 against main aa95d35f's 543/33/17, no new failure.) - [x] No game files, dumps, build output or generated files. - [x] `third_party/` untouched (a new folder with a `PROVENANCE.md` instead). - [x] The license is OK: GPL-3.0-or-later, nothing incompatible and nothing decompiled. ### When it applies - [x] AI assistance recorded with `Assisted-by:` / `Co-Authored-By:` trailers. - [x] Numbers from the same PC, scene and settings, at least 2 interleaved runs each, the median reported. - [x] Switches documented (docs/development.md; the README for a menu row) and shipped at their recommended value. - [x] A game-free test added for the fix, failing on `main` and passing here. (Failing on #643's head, this PR's base.) - [x] A check under `tests/` that reads changed source updated in this PR, not weakened. - [x] Docs updated.
fix(macos): storage buffer tables get descriptor sets on MoltenVK
All checks were successful
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
CI / Conventional Commit title (pull_request) Successful in 3s
CI / Workflow lint (actionlint) (pull_request) Successful in 6s
Third-party parts / As their notes say (pull_request) Successful in 9s
PR description / Description follows the template (pull_request_target) Successful in 4s
77a91fc936
MoltenVK 1.4.2 binds a push descriptor set's resources one by one, never
through a Metal argument buffer (MVKDescriptorSet.mm pickArgumentBufferMode
returns Off for every push layout, and the pipeline names that set to
SPIRV-Cross as discrete). The SPIR-V back end declares a storage buffer
table (count > 1: Info::global_tables, the task and mesh programs'
c0+0x880 table) as one fixed-size array per typed view, all at one binding
(DefineSsbos; any global memory access uses the U32, U32x2 and U32x4
views), and SPIRV-Cross 6c09849f aliases such arrays only inside an
argument buffer. So every pushed program with a table failed: 256
"Attempting to alias same binding with a descriptor array which is not
implemented through argument buffers" errors and as many failed compute
pipelines in the first Mac start (mac-arm64-a5f2d6f9-01).

vk_vendor.h gets a fix, set_for_tables, on by default only for
VK_DRIVER_ID_MOLTENVK, with RX_VK_SET_FOR_TABLES to force it either way.
ensure_layout's push decision moves into layout_pushes(): with the fix on,
a set that has an array of storage buffers is not pushed but allocated
from the recording's pool, the path programs over the push limit already
take, where MoltenVK's sets are Metal 3 argument buffers. Every other set
is still pushed, the bindings are the same either way, and the SPIR-V,
the translator stamp and the program cache are unchanged. The vendor
fixes' log line at device creation says whether it is on, and a MoltenVK
run with MVK_CONFIG_USE_METAL_ARGUMENT_BUFFERS=0 is warned that these
programs cannot translate.

tests/test_set_for_tables.py compiles vk_draw.cpp's layout code (kPushSize
to the end of ensure_layout) on made-up programs and devices: on MoltenVK
a set with a table (compute, task, fragment) is a set, a set without one
(texture arrays and a constant buffer of count 2 included) is pushed;
ten other drivers push as before; the switch works both ways. It fails
on the base with 7 of 79 cases. tests/test_vendor_fixes.py adds a MoltenVK
device and the switch, and checks that the fix stays out of the
translation's profile and stamp. Windows and Linux: same layouts as
before; the log line gains one field.

Assisted-by: Claude Opus 5.5
Co-Authored-By: Claude Opus 5.5 <[email protected]>
(cherry picked from commit 0c2fea2a303a5158d12ebc87bcd28467486486ef)
fix(macos): programs reading storage buffer lengths get descriptor sets on MoltenVK
All checks were successful
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
CI / Conventional Commit title (pull_request) Successful in 3s
CI / Workflow lint (actionlint) (pull_request) Successful in 5s
Third-party parts / As their notes say (pull_request) Successful in 9s
PR description / Description follows the template (pull_request_target) Successful in 4s
e90ba9a66c
MoltenVK 1.4.2 writes the buffer sizes SPIRV-Cross reads for OpArrayLength
in a discretely bound set only in bindDescriptorSets
(MVKCommandEncoderState.mm), never in pushDescriptorSet, and it binds every
push set discretely. So every pushed storage buffer's length read 0
whatever its range, while an ordinary set's (a Metal 3 argument buffer
with its own sizes) was exact (GPU probe,
reports/2026-11-14-null-range-probe.md). The back end measures storage
buffers in its global memory search (DefineGlobalMemoryFunctions:
native_global_bounds' candidates and every single storage buffer), so in a
pushed program no buffer ever held a global address: global stores and
atomics were dropped, the atomics returned 0, and loads the page table
does not serve read 0.

vk_vendor.h gets set_for_lengths, on by default only for
VK_DRIVER_ID_MOLTENVK, with RX_VK_SET_FOR_LENGTHS to force it either way.
The new gpu/vk/spirv_lengths.h (no Vulkan, as fallback_size_policy.h)
walks a module's words for OpArrayLength.
Each Stage gets array_length, noted beside its phis wherever the program
cache handles its SPIR-V: program_cache_save after translation (before the
program is published), a whole record read, and complete_from for a
compute program read without its code. The words are not kept anywhere a
layout could scan them later, and a light compute program's layout is made
before its code is read, so until then (array_length -1) a stage counts as
reading a length where it uses global memory: outside segmented variants,
which the cache never keeps, that is the only place the back end measures
a storage buffer. layout_pushes(p, bindings, total) then refuses a push
for any program with a length in any stage. Every other program, every
other driver, the SPIR-V, the translator stamp and the program cache are
unchanged.

The vendor fixes' log line says whether it is on, and at close one line
says how many programs it gave a set (and how many of those were decided
before their code was read).

tests/test_set_for_lengths.py builds real back end modules
(tests/set_for_lengths_ir.cpp: compute and vertex global memory with a
single storage buffer, 18 OpArrayLength each; global memory with nothing to
search; direct storage in compute, vertex and fragment stages, none), then
compiles vk_draw.cpp's layout code with their descriptors and notes:
138 layouts on MoltenVK and ten other drivers, with the switch unset, 0
and 1, stages not read yet, and the bindings equal pushed or not; plus the
renderer's scan on the same modules and on words that are not a module,
and the count kept for the log. test_vendor_fixes.py covers the new fix
on 17 devices, both ways of the switch, and its absence from the
translation's profile and stamp. The program cache fixtures
(program_cache_one_variant_test.cpp, program_cache_cleanup_test.cpp), which
compile vk_progcache.cpp's functions, include spirv_lengths.h beside
fallback_size_policy.h.

Assisted-by: Claude Opus 5.5
Co-Authored-By: Claude Opus 5.5 <[email protected]>
(cherry picked from commit bf5ca961c91479da13e8923387012ef6dc7fb2c7)
mooki force-pushed mac/mvk-sizes from e90ba9a66c
All checks were successful
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
CI / Conventional Commit title (pull_request) Successful in 3s
CI / Workflow lint (actionlint) (pull_request) Successful in 5s
Third-party parts / As their notes say (pull_request) Successful in 9s
PR description / Description follows the template (pull_request_target) Successful in 4s
to ef43dffcc8
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
PR description / Description follows the template (pull_request_target) Successful in 16s
CI / Conventional Commit title (pull_request) Successful in 15s
CI / Workflow lint (actionlint) (pull_request) Successful in 22s
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 31s
2026-11-15 07:16:21 +00:00
Compare
mooki force-pushed mac/mvk-sizes from ef43dffcc8
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
PR description / Description follows the template (pull_request_target) Successful in 16s
CI / Conventional Commit title (pull_request) Successful in 15s
CI / Workflow lint (actionlint) (pull_request) Successful in 22s
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 31s
to f08eb70206
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 5s
CI / Workflow lint (actionlint) (pull_request) Successful in 7s
Guide screenshots / Guide images and local UI source review (pull_request) Failing after 7s
Third-party parts / As their notes say (pull_request) Successful in 10s
Website / Website on Cloudflare (pull_request_target) Has been skipped
PR description / Description follows the template (pull_request_target) Successful in 4s
2026-11-15 13:09:50 +00:00
Compare
mooki changed title from WIP: fix(vk): give programs that read storage buffer lengths descriptor sets on MoltenVK to fix(vk): give programs that read storage buffer lengths descriptor sets on MoltenVK 2026-11-15 14:18:01 +00:00
Author
Member

Folded into #847 (fix(vk): MoltenVK's descriptor limits in descriptor sets)

Folded into #847 (fix(vk): MoltenVK's descriptor limits in descriptor sets)
mooki closed this pull request 2026-11-15 18:07:47 +00:00
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 5s
CI / Workflow lint (actionlint) (pull_request) Successful in 7s
Guide screenshots / Guide images and local UI source review (pull_request) Failing after 7s
Third-party parts / As their notes say (pull_request) Successful in 10s
Website / Website on Cloudflare (pull_request_target) Has been skipped
PR description / Description follows the template (pull_request_target) Successful in 4s

Pull request closed

Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
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!644
No description provided.