Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 45 additions & 0 deletions dm/games/01001F5010DFA000/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# Pokémon Legends: Arceus (`01001F5010DFA000`)

Update 1.1.1 (`v262144`) over the base game, SDK 11.4.0. Game Freak's engine between Pokémon Sword's ([0100ABF008968000](../0100ABF008968000/README.md)) and the Trinity engine of Pokémon Scarlet and Legends: Z-A, on NVN, with Havok physics, Wwise sound and Pia / NPLN networking. Modules `main`, `subsdk0` (the movie module, which the profile does not load: `main` takes nothing from it the host does not supply), `subsdk1` (GLSLC) and `sdk`; the `sdk` build (`b39add63…`) is Kirby and the Forgotten Land's ([01004D300C5AE000](../01004D300C5AE000/README.md)). Started from the provisional profile the NSP script wrote from its survey (`dm/games/profile_guess.py`). Plays on the Mac at 30 fps, as on the Switch, from the first boot to free movement on the Obsidian Fieldlands beach (a short check, below). An unsigned IPA is built (4.2 GB); iOS is untested.

## What it needs

| Setting | Where | Why |
|---|---|---|
| 5 GB block: `mem_reserve 0x140000000`, `mem_alias 0x118000000` (4.38 GB), `sys_resource 0x1000000` | [`game.tsv`](game.tsv) | the NPDM declares 16 MB of system resource (virtual address memory); `nninitStartup` sets a 0.02 GB heap and initializes malloc's StandardAllocator over 32 GB of address space (`main+0x2779d8c`), which the host gives 4.06 GB ([StandardAllocators over 12 to 62 GB of address space](../../../docs/reference/memory.md#standardallocators-over-12-to-62-gb-of-address-space)) |
| Node area cut and 32 MB alignment of large regions | `dm/tools/sdk_patches.py`, `sdk` build `b39add63…` (Kirby's) | without the alignment the 4.06 GB region goes to the next 1 GB boundary past the node area and does not fit ([1 GB alignment of regions of 1 GB and more](../../../docs/reference/memory.md#1-gb-alignment-of-regions-of-1-gb-and-more)) |
| `dual_want.tsv` | profile | two post-effect pixel shaders are blended with their output 1 as the second source ([A written secondary blend source](../../../docs/reference/rendering.md#a-written-secondary-blend-source-nvn-dual-source-blending)) |
| `depth_mode zero` | `game.tsv` | the game sets the near=0 depth mode, so the pipeline bases made before it runs take the `main0_z` vertex entries |
| `pad_layout full` | `game.tsv` | the 3D gamepad layout: the camera is on the right stick |

No `patches.py`, and no host code keyed to this game.

## Bring-up

- **Resolved: a `Break` in `nninitStartup`** (`Break#1 reason=0` at `sdk+0x39fb54`, from `StandardAllocator::Initialize` at `sdk+0x2f98e4` ← `main+0x2779d8c`). The host's cap lowered the allocator's 32 GB to 4.06 GB, but this `sdk` build aligns a region of 1 GB or more to 1 GB, so the region would have started at alias +1 GB and ended past the 4.38 GB alias region. The SDK-wide node-area patch matched this build (implementation 3), the alignment patch had no implementation for SDK 11.4: its placement helper (`sdk+0x34e1d8`) is the SDK 12.3.9 one with 8 more bytes. It is now the alignment patch's second implementation, and both cuts are registered for this build: a build a profile was brought up on takes only registered cuts, so with this profile in `dm/games` the SDK-wide rules no longer reached it (the `Break` came back once). The region lands at alias +0.06 GB.
- **Resolved: an abort on Metal's compiler queue** a few seconds into the language screen (`[AGX] Failed assertion "error == MTLCompilerErrorNoError"` in `findOrCreateComputeFastClearPipeline`, `MTLCompilerService` crash reports in `AGCLLVMStatelessFragmentObject::buildBlendFactor`), with or without the pipeline prebuild. The pipeline was `ha_post_effects.bnsh` variation 4 (`f4f36a03b0c6691d`): an RGBA16Float target blended with destination factor `SRC1_ALPHA`, the shader writing outputs 0 and 1. A temporary log of each blended attachment in `pso_desc` named it as the last pipeline before the abort. `DM_NVN_DUAL_WANT` then listed a second one, `ff45da02e225f961`, in the first minute.
- `[RED] no render target could get an MTLTexture` once at boot ([Passes with no render target](../../../docs/reference/rendering.md#passes-with-no-render-target)); no other red line on the route below.
- The NSP script's rewrite step was reused after the alignment rule was added: it keyed only the patch files that name one of the modules' builds ([The packing script in detail](../../../docs/development.md#the-packing-script-in-detail)).

## Performance and memory

- On the Mac (M6): 30 fps as on the Switch (`power` lines: 30.0 fps, CPU 0.64 W, about 20% of a core), with long frames of 100–260 ms where new pipelines are first built (that run's archive was made for the near=−w depth mode, before `depth_mode zero`; the Mac build from this profile makes the near=0 bases, not measured on the route since). Resident memory 2.7 GB and 1.46 GB of Metal allocations on the beach after 7.5 minutes.

## Files and shaders

- RomFS 6.0 GB, 19,101 files: effects (`bin/effect`, 2.5 GB), 678 GFPAK archives under `bin/archive` (1.6 GB, every entry Oodle Kraken: [Oodle entries of GFPAK archives](../../../docs/reference/shaders.md#oodle-entries-of-gfpak-archives)), Wwise banks (`bin/sound/NX64/wwise/bank/Default.pck` is the `romfs_marker`), message tables, compiled scripts (`bin/haxe`, `.blua`), and Trinity-style model files (`.trmdl`, `.trmsh`, `.trmtr`). The game probes `arc/data.trpfd` and `arc/data.trfmd` (Trinity's pack index), which it does not ship.
- Shaders: 12,851, by where each first appears: 11,352 in the effects' particle files (`.ptcl`), 1,386 in the loose BNSH files of `system_resource/gfx2/shader` (materials, terrain, water, grass, lighting, shadows, post effects), 73 in the GFPAKs, 40 in `main`. 6,156 pixel shaders, 5,474 of them write exactly colours 0 and 1.

## Mac routes

- The work folder's `run/boot.sh <log> [secs] VAR=value…` runs `build/plahost` (a renamed copy of the host) on the NSP script's build, RomFS image and shader libraries; `run/ctl.sh` and `run/step.sh <shot> [wait] <presses…>` are Sword's (presses through `DM_CTL`, screenshots of the next frame). Run headless.
- From a fresh save (`DM_KBD=<name>` answers the name): A at the language screen (about 70 s after start with the archive opening and the first shaders), A presses through Arceus's questions and the name, the fall through the rift, waking on the beach, Professor Laventon and the three Pokémon, then the player walks (`LUp`, `LRight`).
- The route checked on the Mac: language, name, the opening, the beach with Laventon, Cyndaquil, Rowlet and Oshawott, and a walk through the grass toward the first marker. The game had not saved yet, so there is no reference save.

## Found on this game

General changes first needed here; each applies to every game:

- **The node area and 32 MB region alignment cuts of `sdk` `b39add63…`, and the SDK 11.4.0 implementation of the SDK-wide alignment patch** (`sdk_patches.py` `CUTS`, `MATCH_CUTS`): [1 GB alignment of regions of 1 GB and more](../../../docs/reference/memory.md#1-gb-alignment-of-regions-of-1-gb-and-more).
- **Dual-source blending for NVN shaders** (`dmsh_build.py` `fs_dual`, `main0_d`, the profile's `dual_want.tsv`, `DM_NVN_DUAL_WANT`; `pso_desc` `pso_reads_src1`): [A written secondary blend source (NVN dual-source blending)](../../../docs/reference/rendering.md#a-written-secondary-blend-source-nvn-dual-source-blending).
- **The NSP script's rewrite key always covers `sdk_patches.py`** (`patch_files`): [The packing script in detail](../../../docs/development.md#the-packing-script-in-detail).
1 change: 1 addition & 0 deletions dm/games/01001F5010DFA000/bf_want.tsv
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# generated
3 changes: 3 additions & 0 deletions dm/games/01001F5010DFA000/dual_want.tsv
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Pixel shaders a pipeline blends with their output 1 as the second source (dual-source blending): dmsh_build.py gives each a dual-source entry point (fs_dual). Rows: shader key, noted by the host with DM_NVN_DUAL_WANT
f4f36a03b0c6691d
ff45da02e225f961
43 changes: 43 additions & 0 deletions dm/games/01001F5010DFA000/game.tsv
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# Game profile of Pokémon Legends: Arceus (Switch, base game v0 + update 1.1.1 = v262144). Plays on the Mac
# Format: see dm/games/README.md
# Game Freak's engine between Sword's and Scarlet's Trinity, on SDK 11.4.0, NVN, Havok, Wwise, Pia / NPLN networking. The sdk build is Kirby and the Forgotten Land's; subsdk0 is the
# movie module, subsdk1 GLSLC. Started from the provisional profile scripts/build_ipa_from_nsp.py wrote from its survey (dm/games/profile_guess.py)

# ---- Identity ----
title_id 01001F5010DFA000
program_id 01001F5010DFA000

# ---- App ----
name Pokémon Legends: Arceus
ipa PokMonLegendsArceus.ipa
app_category public.app-category.games
# the camera is on the right stick
pad_layout full
# the game sets the near=0 depth mode (nvnDeviceSetDepthMode): the pipeline bases made before it runs take the main0_z vertex entries
depth_mode zero

# ---- Versions ----
build v262144 1.1.1 main=aee8f150dda1b5a838806e1a5ea6827a subsdk1=4dd097b435891c5e0e15a65dbe47124f sdk=b39add63421be525d352e576dab438d3
package v262144
shader_versions v262144

# ---- Files ----
# not loaded, main takes nothing from them the host does not supply: subsdk0 (NintendoSDK_movie)
modules main subsdk1 sdk
romfs_marker bin/sound/NX64/wwise/bank/Default.pck
zip_store .bfotf:.bnk:.gfpak:.pck:.ptcl:.metallib

# ---- Memory ----
# The NPDM declares 16 MB of system resource (virtual address memory); nninitStartup sets a 0.02 GB heap and initializes malloc's StandardAllocator over 32 GB of address space, which the
# host gives what the alias region has room for (4.06 GB). The SDK-wide node area and 32 MB region alignment patches (dm/tools/sdk_patches.py) let it fit after the 62 MB node area
mem_reserve 0x140000000
mem_alias 0x118000000
mem_stack 0x10000000
app_pool 0xCD500000
sys_resource 0x1000000

# ---- Shader split ----
# 12,851 shaders, by where each first appears: 11,352 in the effects' particle files (bin/effect/**/*.ptcl), 1,386 in the loose BNSH files (system_resource/gfx2/shader, the scene's
# materials, terrain, water, lighting, shadows and post effects), 73 in the 678 GFPAK archives under bin/archive (Oodle Kraken entries, decoded with the game's own OodleLZ_Decompress), 40 in main
shader_groups /bin/=bin /system_resource/=systemresource
shader_note Pokémon Legends: Arceus shaders
2 changes: 2 additions & 0 deletions dm/games/01001F5010DFA000/pso_manifest.tsv
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# Prewarm seed list (shipped in the app, next to shader_map.tsv). Rows: S<TAB>shader key<TAB>stage / R<TAB>render pipeline key (pso_skey hex) / C<TAB>compute shader key.
# Empty: not recorded yet (DM_PSO_MANIFEST=off DM_PSO_RECORD on the Mac); every item is built on demand or comes from the pipeline archive
84 changes: 84 additions & 0 deletions dm/games/01001F5010DFA000/shader_facts.tsv
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
# Answer table for translation queries (generated by dm/gfx/tools/shader_split.py, do not edit): key <TAB> fact JSON. No PC shader pairing supplied: only the thread group / shared memory of compute shaders (taken from the control section); other queries get the translator defaults
09307e9026b585a8 {"local":[32,1,1],"shared":0}
1078439be5e1b2b4 {"local":[32,1,1],"shared":0}
12bab6b1426b603b {"local":[32,1,1],"shared":0}
131de2433706fd2a {"local":[32,1,1],"shared":0}
14aaeadce8aa8e25 {"local":[32,1,1],"shared":0}
2409713b3322c847 {"local":[32,1,1],"shared":0}
26a43222b841665d {"local":[32,1,1],"shared":0}
282f2ca93e60d130 {"local":[32,1,1],"shared":0}
2866e16ce6a257dd {"local":[32,1,1],"shared":0}
2a5332e110735f02 {"local":[32,1,1],"shared":0}
2cf639b2a0e61f35 {"local":[32,1,1],"shared":0}
3442d4c62b35dee6 {"local":[32,1,1],"shared":0}
35b955da0a226cfc {"local":[32,1,1],"shared":0}
3754740a116af7e1 {"local":[32,1,1],"shared":0}
37aa21b799d67355 {"local":[32,1,1],"shared":0}
3c64724dfa805791 {"local":[32,1,1],"shared":0}
3e59d4d6f21f0e79 {"local":[32,1,1],"shared":0}
4016c50396be8385 {"local":[32,1,1],"shared":0}
44a0e7cc3a8113f6 {"local":[32,1,1],"shared":0}
46226f4ec8403620 {"local":[32,1,1],"shared":0}
46af8847fac0596c {"local":[32,1,1],"shared":0}
4a4285dc59c23746 {"local":[32,1,1],"shared":0}
4e498cd1416931fe {"local":[32,1,1],"shared":0}
5451dbd4af4f280a {"local":[32,1,1],"shared":0}
54c05056798aa8c4 {"local":[32,1,1],"shared":0}
54da3ba8b5c07a38 {"local":[32,1,1],"shared":0}
556477d01fc5e603 {"local":[32,1,1],"shared":0}
56cd80f64fd2d808 {"local":[32,1,1],"shared":0}
5ecba9b0a3056f74 {"local":[32,1,1],"shared":0}
60bf84dc440f06b5 {"local":[32,1,1],"shared":0}
68863cbc9c834d00 {"local":[32,1,1],"shared":0}
6ac77e528cad2f37 {"local":[32,1,1],"shared":0}
6d3e95191210707b {"local":[32,1,1],"shared":0}
6ea25cb2708f530b {"local":[32,1,1],"shared":0}
73f0de929f13f3a5 {"local":[32,1,1],"shared":0}
7c8ba985bf8b3f0f {"local":[32,1,1],"shared":0}
7cded32e92aa2fc5 {"local":[32,1,1],"shared":0}
7cfacf26faaed010 {"local":[32,1,1],"shared":0}
84579ed02449ce30 {"local":[32,1,1],"shared":0}
865485f2ccaf5dd3 {"local":[32,1,1],"shared":384}
865e186f5674dea3 {"local":[32,1,1],"shared":0}
86a8cbac809a7d33 {"local":[32,1,1],"shared":0}
8924384dffd01c17 {"local":[32,1,1],"shared":0}
8a3566abd5d00b20 {"local":[32,1,1],"shared":0}
8b066c0b6fa99bf2 {"local":[32,1,1],"shared":0}
8c725690cf830ce3 {"local":[32,1,1],"shared":0}
8dae3e7660ae3dae {"local":[32,1,1],"shared":0}
90a15a9d22ecd079 {"local":[32,1,1],"shared":0}
961a7bffe6dcba59 {"local":[32,1,1],"shared":0}
9dcb2095f055f0e7 {"local":[32,1,1],"shared":0}
9fa32cec7fddb366 {"local":[32,1,1],"shared":0}
a68e6a974479f7dd {"local":[32,1,1],"shared":0}
a73ba50e9dfa882b {"local":[32,1,1],"shared":0}
a7e6a319a451c30d {"local":[32,1,1],"shared":0}
a85d8c1bb0511f3c {"local":[32,1,1],"shared":0}
ab0268c7bcd728f7 {"local":[32,1,1],"shared":0}
ab413f4fee23abb7 {"local":[32,1,1],"shared":0}
ab725e3de5bd78d8 {"local":[32,1,1],"shared":0}
aec04d77e787f930 {"local":[32,1,1],"shared":0}
aec8a4dc811486ba {"local":[32,1,1],"shared":0}
afed6c147b743dce {"local":[32,1,1],"shared":0}
b093f3a319da22c6 {"local":[32,1,1],"shared":0}
b099fd2e35399bf5 {"local":[32,1,1],"shared":0}
b0ebd263bf124e0f {"local":[32,1,1],"shared":0}
b92a82c6351094b3 {"local":[32,1,1],"shared":0}
b9b0ccece033e553 {"local":[32,1,1],"shared":0}
bc6e3004cd3db956 {"local":[32,1,1],"shared":0}
bdf8ee78963f362a {"local":[32,1,1],"shared":0}
c2c7b6ae160a7dff {"local":[32,1,1],"shared":0}
c7fec03125b874b8 {"local":[32,1,1],"shared":0}
cbe8e0072590574d {"local":[32,1,1],"shared":0}
ccf7beb8cbb3cc75 {"local":[32,1,1],"shared":0}
ce4b552afd3821df {"local":[32,1,1],"shared":0}
d1037bb59d32d9ba {"local":[32,1,1],"shared":0}
d5b676f6dcb6b210 {"local":[32,1,1],"shared":0}
da3cf6d03ffbfa89 {"local":[32,1,1],"shared":0}
ddf81434e9021464 {"local":[32,1,1],"shared":0}
e670d459dff35f66 {"local":[32,1,1],"shared":896}
ea61bfeeede9346f {"local":[32,1,1],"shared":0}
ecaf01db76605550 {"local":[32,1,1],"shared":0}
f10ff49dbc6ba8e3 {"local":[32,1,1],"shared":0}
f5a43c0f1add26d4 {"local":[32,1,1],"shared":0}
f712a1290c83bad6 {"local":[32,1,1],"shared":0}
Loading
Loading