Skip to content

An NDSR pack's record table is read one word at a time: a constant-data pair between two shaders' pairs hid every other shader of Ocarina of Time's agl_ndsr_vr.pck - #1388

Closed
Romen-Adama-Dev wants to merge 1 commit into
seedds:mainfrom
Romen-Adama-Dev:ndsr-record-walk

Conversation

@Romen-Adama-Dev

Copy link
Copy Markdown
Contributor

What and why

A small, general change to shader_split.py's ndsr_shaders, found while bringing up The Legend of Zelda: Ocarina of Time (Switch 2, 0400486024DEC000, update v131072, SDK 22.2.8) on a Mac. It is independent of #1299, which carries the game's profile; it does not touch the chain.

Symptom: the split read 21 of the 24 shaders of the game's agl_ndsr_vr.pck (in Lib/agl/agl_resource.Nin_Ounce_NVN2.release.sarc.zs), with no red line.

Cause: the pack's table is {offset, length << 4 | type} pairs: a shader's control pair, then its code pair. ndsr_shaders read them as 16-byte records from +0x10 or +0x14, which holds for Donkey Kong Bananza's and Splatoon Raiders' packs. This pack puts one constant-data pair (type 9) after each shader, so every other control pair started in the middle of a record and was skipped.

Change: the walk moves one 4-byte word at a time from +0x10. A word that points at an NVN2 control section and is followed by a control-typed length (type 0, 3 or 6, at least 0x48 bytes) starts a shader's two pairs; any other word is stepped over. A pack whose shaders' pairs start every record reads exactly as before, from either header size.

Reference entry: the existing The NDSR pack's record start says what changed and names the pack.

Checked

  • Tests: python3 -m unittest dm/tools/tests/test_split_ndsr_pairs.py (new: both pack shapes, the vertex / pixel pairing of the upscaler's graphics programs) and dm/tools/tests/test_docs.py pass.
  • Game files: on Ocarina of Time's RomFS the split goes from 42,321 to 42,324 shaders: agl_ndsr.pck gives the same 43 as before, agl_ndsr_vr.pck 24 instead of 21. Each new control section's +0x44 code length matches the code the record names.
  • Game run: not affected by this change at the title, the opening or the first area (the game does not dispatch the _vr pack there), so no picture or timing difference is claimed. Apple M3 Pro (18 GB), macOS 27.0.1, Xcode 27.2.
  • scripts/regress.py: not run (no other local game builds on this Mac). Donkey Kong Bananza (040074A01BF12000), Splatoon Raiders (0400380020056000) and Star Fox (0400E88025B1A000) read NDSR packs: their packs' records start every 16 bytes, so their tables should split to the same keys, but a check by their owners before merging would be welcome.
  • Not run: lint_python.py (no lint venv on this Mac).

Docs

  • The finding is in its docs/reference/shaders.md entry; python3 dm/tools/docs_symptoms.py was run (the symptom line is unchanged, so the index did not change)
  • No game files, keys or data extracted from a game in the change

@github-actions github-actions Bot added packing Building an IPA or a Mac app: the NSP script, extraction, the shader split, the packers tools Tools and scripts (dm/tools, scripts) docs Documentation labels Nov 5, 2026
@lunks

lunks commented Nov 5, 2026

Copy link
Copy Markdown
Contributor

Thanks for this. I compared it with #1353, which fixes the same walk by reading the table as single 8-byte entries. Read only, on Ocarina of Time v131072's agl resource archive, running each branch's ndsr_shaders on its three NDSR packs:

agl_ndsr_vr agl_ndsr agl_ndsr_vr_light total
main 865cc35 18 43 24 85
#1353 (5ec8a62) 20 43 26 89
this PR (9c6194ce) 20 43 26 89

The two sets are identical, shader by shader (same pack, offset, stage, code length, and a hash of the control section plus code), and neither drops a shader main has. Four entries are new: three distinct programs, one of them in both variable-ratio packs. Your description says 21 to 24 shaders in agl_ndsr_vr.pck; I get 18 to 20 there and 24 to 26 in agl_ndsr_vr_light.pck, so +4 in all, not +3.

So the two PRs do the same thing for this game, and one of them can close; either is fine with me. I did not run a game, and I did not run the other games' NDSR packs (Donkey Kong Bananza, Splatoon Raiders, Star Fox).

The entries of agl's NDSR packs are {offset, length << 4 | type} pairs, a shader's control pair followed by its code pair. ndsr_shaders read them as 16-byte records from +0x10 or +0x14, which holds for Donkey Kong Bananza's and Splatoon Raiders' packs. In The Legend of Zelda: Ocarina of Time (Switch 2, SDK 22.2.8) agl_ndsr_vr.pck puts one constant-data pair after each shader, so every other control pair started in the middle of a record and the walk read 21 of the pack's 24 shaders. The walk now moves one 4-byte word at a time: a word that points at an NVN2 control section and is followed by a control-typed length starts a shader's two pairs, any other word is stepped over. The aligned packs read the same as before (test_split_ndsr_pairs.py builds both shapes), and the reference entry on the pack's record start says what changed.
gnosticgeek pushed a commit to gnosticgeek/nxforge that referenced this pull request Nov 6, 2026
AnkMister added a commit to AnkMister/nxnative that referenced this pull request Nov 6, 2026
…ee NDSR keys and facts from the corrected split. The splitter algorithm remains behind DM
@seedds

seedds commented Nov 6, 2026

Copy link
Copy Markdown
Owner

Thank you for tracking this down. The NDSR pack's shaders are all read on main now, so I'm closing this. Final checks on the rebased tree (full shader build, walks, regression) are still running, so please report anything you see.

@seedds seedds closed this Nov 6, 2026
@Romen-Adama-Dev

Copy link
Copy Markdown
Contributor Author

Thanks for the comparison. Your per-pack counts are the right ones: my 21 → 24 came from the split's totals (42,321 → 42,324 keys, which dedupe the program shared by the two variable-ratio packs), not from one pack. #1353 came first and reads the same four entries, so this one can close in its favour. For whoever merges either: the lint-python failure here is main's own (the reportIndexIssue findings #1373 describes), not from these files.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

docs Documentation packing Building an IPA or a Mac app: the NSP script, extraction, the shader split, the packers tools Tools and scripts (dm/tools, scripts)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants