Repository navigation
Conversation
…ternated with the DM_AB phases (diagnostic, off by default) DM_NVN_SHADER_ALT=<dir> gives a shader key with <key>.metallib in <dir> a variant: a shader object of its own, loaded with the game's reflection, its side libraries (_bx, _bf, _bp, _bv) from <dir>. prog_get returns the program's twin with the variants in the phases DM_NVN_SHADER_ALT_AB (default on; ab, ab:<k>/<n>) selects, so a draw uses one variant for all its state. Pipelines are other pso_key entries (the key holds the shader objects) and other archive entries (lib_name: alt/<file>). A variant whose side libraries are not the game's set, or whose entry points or argument buffer differ, is refused with a red line; the key stays the game's. Combined programs (bind_stages) take the game's shaders, never a twin's. Layer entry points get no variant. t_shader_alt: the twin in the switch's phases only, made once, its own pipeline key and archive name; no variant, side-library mismatch and entry-point mismatch keep the game's. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…rm lists or the user's record pso_skey names shaders by key, so a pipeline recorded from a variant would replay as the game's own. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… vertex inputs), which shader_load requires; stop when they do not load instead of dereferencing nil Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ce variants of it, on a full-screen draw rebuilt from a pass dump and its uniform dumps (time, output against the first library, Apple's compiler statistics); the scene format and its use are in its README, and development.md's GPU measurement section points to it and to DM_NVN_SHADER_ALT Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…signment, not memcpy, so it holds its own references: the copy left the twin's strong slots unretained, and replacing one then released the game's shader once too often (a program freed later would over-release its shaders). t_shader_alt checks the shared shader's retain count with the twin and after it. The ignored __unsafe_unretained on the program getters' return types is gone (clang's -Wignored-qualifiers), and a mixed && / || has its parentheses Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…pool around its use ends, since the program getters' results are autoreleased Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…l's and a mesh stage's function; distinct pipelines) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…tion, and crun's multiset compare On top of the PR's fsbench (which carried the work up to compare samplers and declared texture types), three-way merged from the fsbench series (base 619dddd4, head 04187b8a): - variants mark1 (the pool read mark once a SIMD group when every active lane reads the same ID) and guard (seedds#2254's loop guard) - scene: float textures get finite values below 1; the light-cluster grid filled as {count, list offset} pairs; a missing uniform block falls back to the same slot of another draw - mstats: a mesh pipeline's statistics; every statistics dictionary with its key path (print_stages; FSBENCH_STATSKEYS=1 prints the top-level keys) - a compute mode: cscene builds a dispatch's scene from a pass dump (uniform blocks from DM_NVN_CBDUMP, storage buffers by size, the dispatch's groups and the reflection's threadgroup size); cstats gives a kernel's statistics, threadgroup memory and threads; crun times a dispatch of each library against a null kernel and compares every written resource with the first library's from the same seeded inputs - stats, run, mstats and cstats make functions with newFunctionWithName:constantValues: (none set): cut libraries declare function constants (dm_border_off) and Metal refuses a plain function from them - crun also compares each written resource as a multiset of its 32-bit words (sorted, merge walk): Ocarina of Time's foliage kernels 510c344f and e855420a differ from copies of themselves in 8-17 words, as many by value as in place (racing writes or atomic accumulation), so a variant is judged against the first library's own difference with itself - README: the new commands and the two notes Checked: fsbench.py compiles, fsbench.m passes clang -fsyntax-only; the series' tools ran in OoT's measurements (cut7 stats of 06750e79 / 2a712d1a / d729234e, the cbdev crun timings, crunself3b's multiset counts, chainBstats2's mstats) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…zed locals in translated MSL (open; zero-initialization proposed) Ocarina of Time's full build (chain ecd9cb97f72c) logs 1,907 "variable '_N' is used uninitialized whenever 'if' condition is false" warnings, all of one shape: a switch on a small index structured with goto flags reads one flag's value after the join where only one path set it. In SPIR-V that is a phi with an OpUndef incoming (defined); SPIRV-Cross writes it as a local without an initializer, which MSL (C++) leaves undefined to read, and clang lowers the short-circuit to a branch on it. SPIRV-Cross --force-zero-initialized-variables in dmsh_build.py's spirv-cross arguments removed the warnings on the two measured shaders (d731a682, 58f47abf: 2 -> 0, same line count, both compile). Docs only: the chain change, its regress run and an fsbench exactness check are not done. Symptom index regenerated; OoT's note links the entry. test_docs passes Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… (open; not a chain rule) A compute kernel that rereads many constant-buffer words hits Apple's 256 uniform registers: the compiler merges reads of `constant` memory and keeps the words in uniform registers, and the overflow spills (Ocarina of Time's foliage kernel cee08c63: 292 words read 973 times, 219 live merged, 1,168 bytes of spill). Reading those slots as `const device` removed the spill (0.32 -> 0.04 ms a dispatch, bit-exact) but costs below the limit (5-18 % slower at 219 uniform registers), and in game it gave about 0.14 ms of compute; a general rule would need a calibrated static count of merged words. Symptom index regenerated; OoT's note links the entry. test_docs passes Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…, mstats) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Contributor
Author
|
Four commits added (24b9391):
Checked: t_shader_alt 22/22, t_pso_archive, t_nvn 298/298, test_docs, and the fsbench tool builds (M2 Air, macOS 27.0). |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What and why
Two diagnostic tools for measuring what a translation choice costs in one hot pixel shader, offline and then in game. Both are off by default; nothing changes for a player.
DM_NVN_SHADER_ALT=<dir>(host,nvn_mtl.m):<key>_b.metallibis in that folder draws with that library instead of the game's. The library is a variant built the waydmsh_build.pybuilds the game's, with the same side libraries.prog_alt), so its pipelines and archive entries are separate:pso_keyholds the shader objects, andlib_nametags the libraryalt/<file>. Variant pipelines are never written to the prewarm lists or the user's record._bx,_bf,_bp,_bv), entry points or argument-buffer layout differ from the game's is refused with one[RED]line, and the key keeps the game's library.DM_NVN_SHADER_ALT_AB=abwithDM_AB=<frames>draws the variants only in the odd phases, so one run compares them with the game's library in the neighbouring phases. The[ab]line of each phase is read as for any otherDM_ABswitch.prog_getisprog_alt(prog_get_base(cp)), andprog_altreturns its argument after adispatch_oncecheck.fsbench (
dm/gfx/tools/fsbench/, a tool only):DM_NVN_PASSDUMP_ALLpass dump andDM_NVN_CBDUMPuniform dumps.nobs), no NaN scrub of coordinates, read-only storage buffers throughconstant, the pool read mark off, and others.The method these tools were made for, used on Ocarina of Time (0400486024DEC000, v131072):
DM_NVN_HILITEstills.DM_NVN_GPUPROFjoined withDM_NVN_PASSDUMP.DM_NVN_SHADER_ALTandDM_AB.The first result, on a MacBook Air M2 (16 GB):
The coverage and ranking scripts used for steps 1 and 2 are not in this PR: they are tied to one game's scripted route and saves.
Checked
make -C dm/gfx/tests GAME=0400486024DEC000 check_t_shader_alt: the variant is drawn in its phases only; the twin is made once; archive tags; the pipeline key differs; nothing is recorded for the prewarm; a missing side library, a missing entry point, or no variant leaves the game's library.python3 -m unittest dm/tools/tests/test_docs.py: OK.dm/tools/env_switches.py --checkreports only what it reports on main: 4 removed switches still quoted, DM_NVN_VCONV_KEEP without a row.fsbench.py toolbuilds the binary on main, andfsbench.py compilecompiles a fixture. The same source ranfsbench runandstatson five of Ocarina of Time's shaders (below).[RED]line from the switch.target=is Metal's numbering, so a 2D array was read as a cube, and compare samplers had no compare function.mainwas compiled and tested, not played.scripts/regress.py check --games. Both switches are off by default, and with them unset the only change on the draw path is theprog_altcheck, which returns at once. Not checked on an iPhone (it is a Mac diagnostic, but nothing in it is Mac-only).Docs
docs/env_switches.tsv: rows forDM_NVN_SHADER_ALTandDM_NVN_SHADER_ALT_AB.docs/development.md, GPU measurement: a paragraph on the in-run A/B of one shader, with a link to fsbench.dm/gfx/tools/fsbench/README.md: commands, inputs, the scene format, and how to read the numbers.🤖 Generated with Claude Code