Repository navigation
Description
This issue is fundamentally about how this project manages the deluge of changes that are landing in such a way so as fixes for one game don't break others. Please read the below @seedds! Cheers.
What happened
c3a0880 (from #178, "Guard Metal image atomics") was validated thoroughly on Pokémon Legends: Z-A: all 28,603 shaders, GPU probes and a 240 s run. Even so, it broke at least two games outside that set:
- SHIN MEGAMI TENSEI V (SHIN MEGAMI TENSEI V (010063B012DC6000, 1.0.0): game profile, version 8 Unreal paks, UE 4.23's FMalloc layout and engine region, 60 fps and an iOS Screen setting #173): the host aborts with
FATAL [RED] image atomics: unsupported or overflowing IMG extentat the first atomic on a buffer image. Image atomics on buffer images: declared as buffers, and an unbound one gets a buffer placeholder and an atomic scratch of its own (general, from SHIN MEGAMI TENSEI V) #263 fixes the reflection side. - Yoshi's Crafted World (Yoshi's Crafted World: profile, sparse texture layout, GPU copies into texture storage #218): the same abort about 6 s in, on compute shader
a94ca5c952ce0d72. In addition, the translator now rejects 3 of its shaders (572c1b843ca32afb,8dbd4ee9b3da30d4,f0b33a6b4f3cc64f) because they use the value an image atomic returns, and it changesa94ca5c952ce0d72to read 0. Builds made with shaders from before c3a0880 run fine.
Neither failure is a mistake in the testing of #178. The project has one shader chain (DMSH_CHAIN) for every game, so each translator or host change affects all of the roughly 70 profiles. But it can only be checked on the games its author owns, and no contributor owns them all. CI can't help either, since it can't hold game files or run Metal 4 (#112).
What the existing tests miss
dm/tools/tests/test_image_atomic_bounds.pyalready builds synthetic Maxwell shaders fromInstTable.csand runs them through the translator,spirv-valandspirv-cross, with no game inputs. In CI, though, the translator cases are skipped:DMSH_TEST_XLATEis unset, andspirv-crossandspirv-valaren't installed.- The same test asserts that an atomic whose result is used must be rejected (
require IGN with a discarded result). That is the pattern Yoshi uses, so the regression was locked in as intended behaviour. Nothing told the author that shipping games depend on it. - When shaders fail to translate,
dmsh_build.pyexits 0 and the NSP script packs the app anyway with "N of M shaders ready; K failed". The first sign is a crash at run time, often long after the change, once a rebuild picks up the new chain.
Proposal
Every item works for any contributor and in CI. None needs game files, keys, Metal or a particular contributor owning a particular game.
- Run the translator fixture tests in CI. Point
DMSH_TEST_XLATEat the committeddm/gfx/tools/dmsh_xlate_bin, and install the .NET runtime andspirv-cross/spirv-valintool-tests. The Metal compile step (DMSH_TEST_METAL) stays local. This is small: about 15 lines of workflow. - A synthetic fixture for each pattern a game turns up. When a game hits a translator gap, the fix comes with a hand-encoded shader reproducing the instruction pattern, as
test_image_atomic_bounds.pyalready does. For this case, that means a SUATOM/SURED with a used result, plus a buffer-image binding, replacing the assertion that requires rejection. - Report shader regressions against the contributor's own previous build.
dmsh_build.pycompares the new_b_build.jsonwith the previous one in the same build folder. It prints the shaders that used to translate and now fail, with reasons, and the NSP script stops unless told to continue. Nothing is committed: every contributor gets the check for the games they own. - A per-profile instruction census (for discussion).
shader_split.pyalready decodes every shader to make the profile's tables. It could also write per-shader counts of the instruction forms the translator treats specially (for example SUATOM with a used result, by clamp mode). Likeshader_facts.tsv, it would hold only hashes and counts, no game code. The translator would declare the forms it rejects, and a CI test would list every profile whose census contains one. A PR that rejects a form used by a shipping game would then name those games, even when its author doesn't own them. Profiles without a census report "unknown" rather than pass, so it can be filled in gradually by people who own each game.
Ruled out: golden MSL outputs and committed per-game translation baselines. Both need the game to verify, and golden MSL is code derived from the game.
A smaller question: should the image-atomic admission skip the one dispatch with a [RED] line instead of aborting the app? I understand the abort is deliberate, since an unchecked atomic must never reach a dummy buffer. Skipping writes nothing, so it keeps that guarantee while a game keeps running.
Offer
I'm happy to open PRs for items 1 to 3 now, as separate small PRs (2 together with the Yoshi translator fix). Item 4 changes what a profile holds, so I'd like your view first. Does the census sound acceptable, and would you prefer it in shader_facts.tsv or a separate table?
Activity
JMRBDev commentedon Oct 26, 2026
One more data point for the same cause, from Super Mario Bros. Wonder (010015100B514000, update v327680, chain 2647452f4522): 2 of 16,268 shaders are rejected at translation with
The other 16,266 build, the split finds them all, and the IPA packs (4.0 GB) — the game itself was not run yet, so what those two pipelines do at run time is unknown. It reads like the same semantic as Yoshi's three rejections (a shader that uses the value an image atomic returns), with a different message. The build log is at hand if the keys help.
JMRBDev commentedon Oct 26, 2026
Follow-up on the Wonder case I reported above: on current main (chain a3b77ce4602d) those two shaders compile — 16,268 of 16,268 — so whatever moved between 2647452f4522 and now (the translator binary included) covers that pattern. The rejection was real on 2647452f4522.
Check translation chain changes on games their author does not own (#272
v0lumehi commentedon Oct 26, 2026
Good point @jthrilly and I have the same observation. Some of my new features introduced side effects that I could not have tested thoroughly because testing all games requires a heavy amount of compute and storage.
I am trying to come up with a solution to this that doesn't break ToS of the well known Japanese company.
I think at this state the project deverses a proper release cycle and an agent harness to test against to find regressions and bugs.
Compute and storage are a cost factor also
I would also appreciate some way of communicating with each other to plan and design more
jthrilly commentedon Oct 26, 2026
Agree completely @v0lumehi - some sort of coordination is essential.
I do think that the ideas proposed here could work. If the four proposals in my PR were implemented, the regression I experienced couldn't have happened. Is the same true of your regressions? Or is something more needed?
@seedds - would really appreciate your thoughts!
v0lumehi commentedon Oct 26, 2026
Good question. Your four proposals would have caught c3a0880, and seedds has since landed 1 and 3 (and part of 2) in b117c91. Mine were a different kind, though, and none of the four would have caught them:
So I think something more is needed, and that's what #328 and #329 try to be, building on b117c91:
regress.py) adds a pair interface check (no GPU, finds pso_offline: metal-tt fails on ToTK's pso_pairs.tsv pairs whose pixel shader reads an output the vertex shader does not write #283's 11 pairs) and a boot smoke run with a watchdog on the games you own. The report holds only numbers and hashes, so you can paste it into a PR.regress.py usage/impact) is your item 4, generalised: each profile lists the NVN functions, services and shader features its game uses (names and counts only), so a PR can name the games it can reach, even ones its author doesn't own.I'd really value your eyes on both, especially #329, since the census was your idea. I'm tracking all of this in #313, which builds on this issue, so feel free to add or reorder things there.
scripts/regress.py: a regression harness over the local games (issue s…
regress.py counts newly failing shaders by shader_regressions.py's ru…
regress.py usage / impact: which games a change can reach (issue seed…
seedds commentedon Oct 28, 2026
The original safeguards are implemented: translator fixture tests in CI and shader-regression checks, native image atomics with synthetic coverage, the cross-game regression harness, and usage manifests / impact analysis. Closing this proposal as completed; continuing regression infrastructure work stays tracked in #313. Thanks for identifying the gap.
Check translation chain changes on games their author does not own (s…