diff --git a/dm/games/0100A00019DE0000/bf_want.tsv b/dm/games/0100A00019DE0000/bf_want.tsv new file mode 100644 index 0000000..54caeb8 --- /dev/null +++ b/dm/games/0100A00019DE0000/bf_want.tsv @@ -0,0 +1 @@ +# generated diff --git a/dm/games/0100A00019DE0000/c1_full.tsv b/dm/games/0100A00019DE0000/c1_full.tsv new file mode 100644 index 0000000..a726d7b --- /dev/null +++ b/dm/games/0100A00019DE0000/c1_full.tsv @@ -0,0 +1 @@ +# chain b-3f6065a844fa 2026-10-20T19:40:15+08:00 diff --git a/dm/games/0100A00019DE0000/dmsh_chain.h b/dm/games/0100A00019DE0000/dmsh_chain.h new file mode 100644 index 0000000..7451c28 --- /dev/null +++ b/dm/games/0100A00019DE0000/dmsh_chain.h @@ -0,0 +1,2 @@ +// Generated file (dm/gfx/tools/dmsh_chain.py --header, game 0100A00019DE0000): the B shader library translation chain version this source tree expects (default options); the host loads only /b-/ +#define DMSH_CHAIN "3f6065a844fa" diff --git a/dm/games/0100A00019DE0000/game.tsv b/dm/games/0100A00019DE0000/game.tsv new file mode 100644 index 0000000..8ca65bc --- /dev/null +++ b/dm/games/0100A00019DE0000/game.tsv @@ -0,0 +1,52 @@ +# Hades II (Supergiant Games' engine on NVN, SDK 19.3.9), base game v0 (the NACP's display version 0.0.126424). +# Started from the NSP script's provisional profile; values marked "Mario's" are not measured for this game yet. +# Unlike Hades (Vulkan), the Switch version renders with NVN: its 88 shaders are BNSH files in Shaders/NVN/bin (.vert / .frag; the .shader files list each program's pair). +# The ExeFS has only main and sdk. main's EOS_* imports (Epic Online Services, from nro/EOSSDK-Switch-Shipping.nro, loaded through nn::ro) stay offline: the host +# registers no NRR, so the game never loads the NRO. + +# ---- Identity ---- +title_id 0100A00019DE0000 +program_id 0100A00019DE0000 + +# ---- App ---- +name Hades II +ipa HadesII.ipa +app_category public.app-category.action-games +# the right stick aims (the weapons with ManualAiming in Game/Weapons/PlayerWeapons.sjson) +pad_layout full + +# ---- Versions ---- +build v0 0.0.126424 main=5219053e5eb156be80fbb2f303779531 sdk=d83a56a5558798414c78ec722867a7da +package v0 +shader_versions v0 + +# ---- Files ---- +modules main sdk +romfs_marker Audio/Switch/Music.bank +zip_store .bank:.bik:.fsb:.gpk:.nro:.pkg:.xnb:.metallib + +# ---- Graphics ---- +graphics nvn + +# ---- Memory ---- +# The NPDM declares no system resource (META +0x14 = 0): the game uses SetHeapSize. It asks for 3.10 GB (pool − used memory), which the 3.25 GB heap region of +# the 4 GB layout holds. main carries an 82 MB bss: the rewritten modules take more than the default 64 MB of used memory, so SetHeapSize(pool − 64 MB) would not fit +mem_reserve 0x100000000 +mem_alias 0x10000000 +mem_stack 0x10000000 +app_pool 0xCD500000 +mem_used 0x6c00000 + +# ---- NVN driver constant segments (Mario's values, the translator's built-in layout, except the texture slot count) ---- +# The game's shaders bind textures at fixed, sparse slots: c2 handles at 0x20 + 8 r for r = 0, 1, 3, 6, 8, 11, 15, 21, 25, 26, 30, 31 and 34 over all 88 shaders. +# Slot 34 (SceneFade.frag, 0x130) lies past Mario's 32 slots, where his image table starts; this game has no image bindings and no shader reads c2 at run time +nvn_tex_base 0x20 +nvn_tex_slots 35 +nvn_samp_base 0x568 +nvn_img_base 0x120 +nvn_img_slots 8 +nvn_ssbo_bases vs=0x110 ps=0x510 cs=0x310 + +# ---- Shader split ---- +shader_groups /Shaders/=shaders +shader_note Hades II shaders (Shaders/NVN/bin) diff --git a/dm/games/0100A00019DE0000/pso_manifest.tsv b/dm/games/0100A00019DE0000/pso_manifest.tsv new file mode 100644 index 0000000..4620515 --- /dev/null +++ b/dm/games/0100A00019DE0000/pso_manifest.tsv @@ -0,0 +1,2 @@ +# Prewarm seed list (shipped in the app, next to shader_map.tsv). Rows: Sshader keystage / Rrender pipeline key (pso_skey hex) / Ccompute shader key. +# Provisional profile: empty until recorded on the Mac (DM_PSO_MANIFEST=off DM_PSO_RECORD). diff --git a/dm/games/0100A00019DE0000/shader_facts.tsv b/dm/games/0100A00019DE0000/shader_facts.tsv new file mode 100644 index 0000000..e665d36 --- /dev/null +++ b/dm/games/0100A00019DE0000/shader_facts.tsv @@ -0,0 +1 @@ +# Answer table for translation queries (generated by dm/gfx/tools/shader_split.py, do not edit): key fact JSON. This game has no PC version to pair with: only the thread group / shared memory of compute shaders (taken from the control section); other queries get the translator defaults diff --git a/dm/games/0100A00019DE0000/shader_map.tsv b/dm/games/0100A00019DE0000/shader_map.tsv new file mode 100644 index 0000000..bd85203 --- /dev/null +++ b/dm/games/0100A00019DE0000/shader_map.tsv @@ -0,0 +1,91 @@ +# kind: evidence Hades II shaders (Shaders/NVN/bin) (BNSH / BAHS in RomFS + main) → control section + code area keys (dm/gfx/tools/shader_split.py) +# column 5 records where each key first appears; this game has no PC version to pair with +package index stage dm_ctl_sha16 source +ps_shaders.bin 0 pixel a4f27b9d4a0e89ad /Shaders/NVN/bin/AA3D.frag#BNSH@0x0#var0 +ps_shaders.bin 1 pixel 5058f3a2f05e0bf6 /Shaders/NVN/bin/AddColor.frag#BNSH@0x0#var0 +ps_shaders.bin 2 pixel 7be530b1cc195b2c /Shaders/NVN/bin/AddColorMultiplyAndLerp.frag#BNSH@0x0#var0 +ps_shaders.bin 3 pixel e71decce4706f348 /Shaders/NVN/bin/AddColorMultiplyAndLerpYRB.frag#BNSH@0x0#var0 +ps_shaders.bin 4 pixel 54dc14fa6a0d0b3d /Shaders/NVN/bin/AlphaMask.frag#BNSH@0x0#var0 +vs_shaders.bin 0 vertex f54b3ecef6f96a60 /Shaders/NVN/bin/AlphaMask.vert#BNSH@0x0#var0 +ps_shaders.bin 5 pixel bb19c0f76de8957e /Shaders/NVN/bin/Blit2D.frag#BNSH@0x0#var0 +ps_shaders.bin 6 pixel 3714c16053835476 /Shaders/NVN/bin/Blit2DDepth.frag#BNSH@0x0#var0 +ps_shaders.bin 7 pixel 8bd6710d108c88b6 /Shaders/NVN/bin/BloomCombine.frag#BNSH@0x0#var0 +ps_shaders.bin 8 pixel 92eb59ba5ba4c1ed /Shaders/NVN/bin/BloomExtract.frag#BNSH@0x0#var0 +ps_shaders.bin 9 pixel b9f419cc1a7726fa /Shaders/NVN/bin/ColorBurn2D.frag#BNSH@0x0#var0 +ps_shaders.bin 10 pixel 40d2414e7d69711b /Shaders/NVN/bin/ColorGrading.frag#BNSH@0x0#var0 +ps_shaders.bin 11 pixel 05d651ee6dc20ccc /Shaders/NVN/bin/ColorGradingLerp.frag#BNSH@0x0#var0 +ps_shaders.bin 12 pixel 96366296584d4749 /Shaders/NVN/bin/DarkerColor2D.frag#BNSH@0x0#var0 +ps_shaders.bin 13 pixel 4570a40f26776c99 /Shaders/NVN/bin/DebugZ.frag#BNSH@0x0#var0 +ps_shaders.bin 14 pixel 7cf1b7d9a4ac312a /Shaders/NVN/bin/Default.frag#BNSH@0x0#var0 +vs_shaders.bin 1 vertex a57dea937fd309a7 /Shaders/NVN/bin/Default.vert#BNSH@0x0#var0 +vs_shaders.bin 2 vertex 585b24f3628d42ed /Shaders/NVN/bin/Default2D.vert#BNSH@0x0#var0 +vs_shaders.bin 3 vertex 602da5e84c9b9fd7 /Shaders/NVN/bin/Default2DInv.vert#BNSH@0x0#var0 +ps_shaders.bin 15 pixel f72073702fa4546e /Shaders/NVN/bin/Default3D.frag#BNSH@0x0#var0 +vs_shaders.bin 4 vertex 1e59b871d956e5a3 /Shaders/NVN/bin/Default3D.vert#BNSH@0x0#var0 +ps_shaders.bin 16 pixel b114e406f89e38a7 /Shaders/NVN/bin/Default3DSprite.frag#BNSH@0x0#var0 +ps_shaders.bin 17 pixel 0a3ff709aeb4d752 /Shaders/NVN/bin/DefaultBlank.frag#BNSH@0x0#var0 +vs_shaders.bin 5 vertex b9ede1459ecf43bd /Shaders/NVN/bin/DefaultInv.vert#BNSH@0x0#var0 +ps_shaders.bin 18 pixel 155ec62dcd886da9 /Shaders/NVN/bin/Desaturate.frag#BNSH@0x0#var0 +ps_shaders.bin 19 pixel fa02a9cef59b0e6e /Shaders/NVN/bin/Disappear.frag#BNSH@0x0#var0 +vs_shaders.bin 6 vertex 55893025726667d3 /Shaders/NVN/bin/Disappear.vert#BNSH@0x0#var0 +ps_shaders.bin 20 pixel 0120d1bc0a433822 /Shaders/NVN/bin/Displacement2D.frag#BNSH@0x0#var0 +ps_shaders.bin 21 pixel b1665fd487e31e55 /Shaders/NVN/bin/DistanceFieldFancy.frag#BNSH@0x0#var0 +vs_shaders.bin 7 vertex 42f68f016c9381f2 /Shaders/NVN/bin/DistanceFieldFancy.vert#BNSH@0x0#var0 +ps_shaders.bin 22 pixel ae6e4a655d11e89f /Shaders/NVN/bin/DistanceFieldText.frag#BNSH@0x0#var0 +vs_shaders.bin 8 vertex 5e1e03b1fe18ad72 /Shaders/NVN/bin/DistanceFieldText.vert#BNSH@0x0#var0 +ps_shaders.bin 23 pixel 3db1c491ba7b6ff2 /Shaders/NVN/bin/Distortion.frag#BNSH@0x0#var0 +ps_shaders.bin 24 pixel 6ed9cff7efcde280 /Shaders/NVN/bin/EditorOutline.frag#BNSH@0x0#var0 +ps_shaders.bin 25 pixel 89a736b2558bdfcb /Shaders/NVN/bin/Fade.frag#BNSH@0x0#var0 +ps_shaders.bin 26 pixel df85791082d97fa3 /Shaders/NVN/bin/FancyText.frag#BNSH@0x0#var0 +vs_shaders.bin 9 vertex 60bbb69a4b411dcd /Shaders/NVN/bin/FancyText.vert#BNSH@0x0#var0 +ps_shaders.bin 27 pixel 0851573221ea6cfa /Shaders/NVN/bin/GaussianBlur.frag#BNSH@0x0#var0 +vs_shaders.bin 10 vertex 102a3746727e5029 /Shaders/NVN/bin/GaussianBlur.vert#BNSH@0x0#var0 +ps_shaders.bin 28 pixel 9a912e9da383d799 /Shaders/NVN/bin/GaussianBlurWithBloomExtract.frag#BNSH@0x0#var0 +ps_shaders.bin 29 pixel c6debcbcf671c47d /Shaders/NVN/bin/Light.frag#BNSH@0x0#var0 +vs_shaders.bin 11 vertex 4f441f9187d9c1b3 /Shaders/NVN/bin/Light.vert#BNSH@0x0#var0 +ps_shaders.bin 30 pixel b6ebda3fafc3a313 /Shaders/NVN/bin/LightAndShadow.frag#BNSH@0x0#var0 +ps_shaders.bin 31 pixel e7eddff0dee36147 /Shaders/NVN/bin/LighterColor2D.frag#BNSH@0x0#var0 +ps_shaders.bin 32 pixel 84123d26a641bbcb /Shaders/NVN/bin/Lighting3D.frag#BNSH@0x0#var0 +vs_shaders.bin 12 vertex df9564a0b9ea7175 /Shaders/NVN/bin/Lighting3D.vert#BNSH@0x0#var0 +ps_shaders.bin 33 pixel a8222dc4e0854c29 /Shaders/NVN/bin/Lighting3DFast.frag#BNSH@0x0#var0 +vs_shaders.bin 13 vertex febf2d05477f2d3d /Shaders/NVN/bin/Lighting3DFast.vert#BNSH@0x0#var0 +ps_shaders.bin 34 pixel 353bf2ea5a0323c4 /Shaders/NVN/bin/Lighting3DFastAlpha.frag#BNSH@0x0#var0 +ps_shaders.bin 35 pixel b246044c1f067ed8 /Shaders/NVN/bin/Lit.frag#BNSH@0x0#var0 +ps_shaders.bin 36 pixel 2234ecf1a206c06d /Shaders/NVN/bin/MaskedColorChangeLit.frag#BNSH@0x0#var0 +vs_shaders.bin 14 vertex 254a73f8b7214283 /Shaders/NVN/bin/MaskedColorChangeLit.vert#BNSH@0x0#var0 +ps_shaders.bin 37 pixel 5f93206484de3596 /Shaders/NVN/bin/Multiplicative.frag#BNSH@0x0#var0 +ps_shaders.bin 38 pixel 9168db30caac6253 /Shaders/NVN/bin/MultiplyAndLerp.frag#BNSH@0x0#var0 +ps_shaders.bin 39 pixel 21425f3e93b44a5e /Shaders/NVN/bin/MultiplyAndLerpYRB.frag#BNSH@0x0#var0 +ps_shaders.bin 40 pixel 99da01a4a43956e1 /Shaders/NVN/bin/NonPremul.frag#BNSH@0x0#var0 +ps_shaders.bin 41 pixel 0d60254e46a57b8c /Shaders/NVN/bin/Outline.frag#BNSH@0x0#var0 +vs_shaders.bin 15 vertex 175952012bc68784 /Shaders/NVN/bin/Outline.vert#BNSH@0x0#var0 +ps_shaders.bin 42 pixel c73a9fd48874c720 /Shaders/NVN/bin/OutlineBink.frag#BNSH@0x0#var0 +ps_shaders.bin 43 pixel 42dbcb02a47502c4 /Shaders/NVN/bin/Overlay2D.frag#BNSH@0x0#var0 +ps_shaders.bin 44 pixel 3e10eeba7823b4dd /Shaders/NVN/bin/Overlay2DHardwareAdd.frag#BNSH@0x0#var0 +ps_shaders.bin 45 pixel 85a3da799d686971 /Shaders/NVN/bin/Overlay2DHardwareSub.frag#BNSH@0x0#var0 +ps_shaders.bin 46 pixel 00b66ee69b7fde95 /Shaders/NVN/bin/Phantom.frag#BNSH@0x0#var0 +vs_shaders.bin 16 vertex 02d134235f7f498b /Shaders/NVN/bin/Phantom.vert#BNSH@0x0#var0 +ps_shaders.bin 47 pixel 800fef7e9a51f10c /Shaders/NVN/bin/RadialBlur.frag#BNSH@0x0#var0 +ps_shaders.bin 48 pixel 5715938e6de314fb /Shaders/NVN/bin/SceneFade.frag#BNSH@0x0#var0 +ps_shaders.bin 49 pixel e101922d4aaca005 /Shaders/NVN/bin/Shadow3D.frag#BNSH@0x0#var0 +vs_shaders.bin 17 vertex 38ca300e679ffba7 /Shaders/NVN/bin/Shadow3D.vert#BNSH@0x0#var0 +ps_shaders.bin 50 pixel 2de1efb8564f02fa /Shaders/NVN/bin/ShadowCast3D.frag#BNSH@0x0#var0 +vs_shaders.bin 18 vertex f203b77d1681cc81 /Shaders/NVN/bin/ShadowCast3D.vert#BNSH@0x0#var0 +ps_shaders.bin 51 pixel 8932b3ec6cb47a5b /Shaders/NVN/bin/ShadowMap.frag#BNSH@0x0#var0 +ps_shaders.bin 52 pixel a83ce5b2fde6caf2 /Shaders/NVN/bin/Shroud.frag#BNSH@0x0#var0 +vs_shaders.bin 19 vertex 5d0736e9a1558078 /Shaders/NVN/bin/Shroud.vert#BNSH@0x0#var0 +ps_shaders.bin 53 pixel 410736215a5ed337 /Shaders/NVN/bin/Shroud2.frag#BNSH@0x0#var0 +ps_shaders.bin 54 pixel ffafb5cc385086ed /Shaders/NVN/bin/String.frag#BNSH@0x0#var0 +ps_shaders.bin 55 pixel d7fdb4fffa53e834 /Shaders/NVN/bin/Supersample3D.frag#BNSH@0x0#var0 +ps_shaders.bin 56 pixel 381e044cfb112a83 /Shaders/NVN/bin/Text.frag#BNSH@0x0#var0 +vs_shaders.bin 20 vertex ea0e7dc8fcdded78 /Shaders/NVN/bin/Text.vert#BNSH@0x0#var0 +ps_shaders.bin 57 pixel 74e562222e357a4d /Shaders/NVN/bin/Thumbnail3D.frag#BNSH@0x0#var0 +vs_shaders.bin 21 vertex 4c41035860215e19 /Shaders/NVN/bin/Thumbnail3D.vert#BNSH@0x0#var0 +ps_shaders.bin 58 pixel 778b5e906ce31e0f /Shaders/NVN/bin/Unlit.frag#BNSH@0x0#var0 +ps_shaders.bin 59 pixel 0a1b52a157395600 /Shaders/NVN/bin/YUVA.frag#BNSH@0x0#var0 +ps_shaders.bin 60 pixel 0b9563a5c525a4f7 /Shaders/NVN/bin/YUVAAddColor.frag#BNSH@0x0#var0 +ps_shaders.bin 61 pixel 67c6c57ab2a55a0a /Shaders/NVN/bin/YUVAMask.frag#BNSH@0x0#var0 +vs_shaders.bin 22 vertex 3cfbb93f88ce24fc /Shaders/NVN/bin/YUVAMask.vert#BNSH@0x0#var0 +ps_shaders.bin 62 pixel 15bde041d415b8cb /Shaders/NVN/bin/YUVAMaskDebug.frag#BNSH@0x0#var0 +ps_shaders.bin 63 pixel b9c900eb1e0113fe /Shaders/NVN/bin/ZOnly.frag#BNSH@0x0#var0 +vs_shaders.bin 23 vertex 8eb964efef64d58e /Shaders/NVN/bin/ZOnly.vert#BNSH@0x0#var0 diff --git a/dm/games/0100A00019DE0000/shader_map.tsv.conflicts.tsv b/dm/games/0100A00019DE0000/shader_map.tsv.conflicts.tsv new file mode 100644 index 0000000..35c1b4d --- /dev/null +++ b/dm/games/0100A00019DE0000/shader_map.tsv.conflicts.tsv @@ -0,0 +1,2 @@ +# kind: evidence control-section key conflict rulings: empty +dm_ctl_sha16 chosen_pc class candidates records diff --git a/dm/games/0100A00019DE0000/shader_pairs.tsv b/dm/games/0100A00019DE0000/shader_pairs.tsv new file mode 100644 index 0000000..ac32dd3 --- /dev/null +++ b/dm/games/0100A00019DE0000/shader_pairs.tsv @@ -0,0 +1 @@ +# kind: evidence vertex / pixel shader pairs within BNSH variations (generated by dm/gfx/tools/shader_split.py, do not edit): vertex key pixel key diff --git a/dm/gfx/nvn/nvn_mtl.m b/dm/gfx/nvn/nvn_mtl.m index a40823c..bcf2087 100644 --- a/dm/gfx/nvn/nvn_mtl.m +++ b/dm/gfx/nvn/nvn_mtl.m @@ -3271,15 +3271,17 @@ static MTLRenderPipelineDescriptor *pso_desc(const pso_key *k, NvShader *vs, NvS MTLRenderPipelineDescriptor *d = [MTLRenderPipelineDescriptor new]; d.vertexFunction = vs->fn; d.fragmentFunction = fsfn ? fsfn : fs ? fs->fn : nil; // Diagnostic DM_NVN_HILITE=fragment shader key,...: these draws use a solid-color fragment instead (keys 1–6 in order magenta / green / cyan / yellow / blue / white), to see where the geometry lands - if (fs) { static char keys[6][24]; static int nk = -1; static id hl; - if (nk < 0) { nk = 0; const char *e = getenv("DM_NVN_HILITE"); - for (const char *q = e; q && *q && nk < 6; q = strchr(q, ',') ? strchr(q, ',') + 1 : q + strlen(q)) { size_t n = strcspn(q, ","); if (n > 23) n = 23; memcpy(keys[nk], q, n); keys[nk++][n] = 0; } } - for (int i = 0; i < nk; i++) if (!strncmp(fs->key, keys[i], strlen(keys[i]))) { - if (!hl) { NSError *e = nil; hl = [g_dev newLibraryWithSource:@"#include \nusing namespace metal;\nstruct O { float4 c0 [[color(0)]]; float4 c1 [[color(1)]]; float4 c2 [[color(2)]]; };\n" + // Pipelines are built on several threads at once: the keys and the library are set up once (a lazy setup raced, and a thread used a library another had just replaced: Hades II, 6 keys) + if (fs) { static char keys[6][24]; static int nk; static id hl; static dispatch_once_t once; + dispatch_once(&once, ^{ const char *e = getenv("DM_NVN_HILITE"); + for (const char *q = e; q && *q && nk < 6; q = strchr(q, ',') ? strchr(q, ',') + 1 : q + strlen(q)) { size_t n = strcspn(q, ","); if (n > 23) n = 23; memcpy(keys[nk], q, n); keys[nk++][n] = 0; } + if (!nk) return; + NSError *err = nil; hl = [g_dev newLibraryWithSource:@"#include \nusing namespace metal;\nstruct O { float4 c0 [[color(0)]]; float4 c1 [[color(1)]]; float4 c2 [[color(2)]]; };\n" "fragment O hl0() { return {float4(1,0,1,1),float4(1,0,1,1),float4(1,0,1,1)}; } fragment O hl1() { return {float4(0,1,0,1),float4(0,1,0,1),float4(0,1,0,1)}; }\n" "fragment O hl2() { return {float4(0,1,1,1),float4(0,1,1,1),float4(0,1,1,1)}; } fragment O hl3() { return {float4(1,1,0,1),float4(1,1,0,1),float4(1,1,0,1)}; }\n" - "fragment O hl4() { return {float4(0,0,1,1),float4(0,0,1,1),float4(0,0,1,1)}; } fragment O hl5() { return {float4(1,1,1,1),float4(1,1,1,1),float4(1,1,1,1)}; }\n" options:nil error:&e]; - if (!hl) MLOG("[RED] HILITE shader compile failed %s", e.localizedDescription.UTF8String); } + "fragment O hl4() { return {float4(0,0,1,1),float4(0,0,1,1),float4(0,0,1,1)}; } fragment O hl5() { return {float4(1,1,1,1),float4(1,1,1,1),float4(1,1,1,1)}; }\n" options:nil error:&err]; + if (!hl) MLOG("[RED] HILITE shader compile failed %s", err.localizedDescription.UTF8String); }); + for (int i = 0; i < nk; i++) if (!strncmp(fs->key, keys[i], strlen(keys[i]))) { if (hl) d.fragmentFunction = [hl newFunctionWithName:[NSString stringWithFormat:@"hl%d", i]]; break; } } d.rasterSampleCount = k->samples ? k->samples : 1; diff --git a/dm/host/hle_ro.c b/dm/host/hle_ro.c index 46b7933..5e6ee64 100644 --- a/dm/host/hle_ro.c +++ b/dm/host/hle_ro.c @@ -28,6 +28,13 @@ HLE_FORCE("_ZN2nn2ro10LoadModuleEPNS0_6ModuleEPKvPvmi", "NROs are not loaded", R (void)m; (void)image; (void)buf; (void)flag; static int red; if (!red++) LOG("[RED] ro::LoadModule: the host does not load NROs (buffer %#zx)", size); return RO_FAIL; } +// SDK 19 adds a bool after the bind flag (Hades II imports only this form, for its Epic Online Services NRO) +HLE_FORCE("_ZN2nn2ro10LoadModuleEPNS0_6ModuleEPKvPvmib", "NROs are not loaded", Result, h_ro_LoadModule2, void *m, const void *image, void *buf, size_t size, int flag, int b) { + (void)b; return h_ro_LoadModule(m, image, buf, size, flag); +} + +HLE_FORCE("_ZN2nn2ro8FinalizeEv", "Initialize opened no ldr:ro session", void, h_ro_Finalize, void) { } + HLE_FORCE("_ZN2nn2ro12UnloadModuleEPNS0_6ModuleE", "NROs are not loaded", void, h_ro_UnloadModule, void *m) { (void)m; } HLE_FORCE("_ZN2nn2ro18RegisterModuleInfoEPNS0_16RegistrationInfoEPKv", "NRRs are not registered", Result, h_ro_RegisterModuleInfo, void *info, const void *nrr) { diff --git a/docs/agents/03-bringup.md b/docs/agents/03-bringup.md index 6dafb29..8dc04c7 100644 --- a/docs/agents/03-bringup.md +++ b/docs/agents/03-bringup.md @@ -85,7 +85,7 @@ Each entry: symptom → root cause → fix (where the fix lives). Check these fi - **A library's `free` rejects a pointer (`CentralHeap::Free` → `NotNMallocPtrError`)** → the game's `main` defines its own `operator new` / `delete` (Unity's memory manager) and `sdk` has a copy forwarding to `malloc` / `free`. Symbols are resolved globally in load order (the first module's definition wins, also for a module's references to its own exports); only local / non-default-visibility symbols bind to the module itself (`loader.c`). The loader logs how many references bind to an earlier module. - **IL2CPP "Could not open …/global-metadata.dat" (then a crash in its logger)** → IL2CPP checks `nn::fs::IsMounted("rom")` before opening; the SDK's own `IsMounted` reads a mount table the host never fills → answer from the host's mount table (`hle_fs.c`). -- **Crash in `nn::ro::InitializeWithPortName`** → `nn::ro` connects to `ldr:ro`; take over `Initialize` and answer `LookupSymbol` from the loaded modules (`hle_ro.c`). +- **Crash in `nn::ro::InitializeWithPortName`** → `nn::ro` connects to `ldr:ro`; take over `Initialize` and answer `LookupSymbol` from the loaded modules (`hle_ro.c`). Check the mangled names against the new title's imports: SDK 19's `LoadModule` takes one more bool (`_ZN2nn2ro10LoadModuleEPNS0_6ModuleEPKvPvmib`, Hades II), so the hook for the older form did not catch it and the SDK's own code would have run. - **SDK 12 names** → older SDKs export other names for the same calls (`ListAudioDeviceName` / `GetActiveAudioDeviceName`, singular `hid::GetNpadState`, `OpenDefaultAudioOut`); hook both generations. - **SDK 11 names** (Metroid Dread) → `fs::CommitSaveData(mount)` is the older name of `fs::Commit`; `fs::DeleteDirectory` (an empty directory) was missing too. - **More SDK 11 calls that reach a service** (13 Sentinels) → `hid::GetMouseState` (the first boot aborted in it: the SDK's mouse resource was never initialized), `fs::CleanDirectoryRecursively`, `fs::EnableGlobalFileDataCache`, `oe::SetUserInactivityDetectionTimeExtendedUnsafe`, `time::ToPosixTime` (host `mktime`) and `audio::GetAudioOutName`. Finding them before the first boot: list `main`'s `nn::` imports that no host hook names (the survey's import table, filtered against `HLE_FORCE` names); most `nn::os` / `nn::mem` imports run natively in `sdk` and need nothing. diff --git a/docs/agents/04-graphics.md b/docs/agents/04-graphics.md index a2cb671..da3408c 100644 --- a/docs/agents/04-graphics.md +++ b/docs/agents/04-graphics.md @@ -45,6 +45,8 @@ Ace Attorney Investigations Collection (Unity 2022.3, SDK 17.5.3) uses Engage's Metroid Dread (SDK 11.4.3) uses Mario's texture handle layout, `0x20 + 8 × slot`: the `TEX` / `TEXS` handle immediates in its shader files' own SASS text are words 0x8–0x22 in steps of 2. Its full build leaves no unresolved bindings and no unfillable driver-bank reads; the other rows are not measured separately. +Hades II (SDK 19.3.9) has Mario's layout too, but its 88 shaders bind textures at fixed, sparse slots up to 34 (`fp_t_tcb_4C`: c2 word 0x4C = 0x20 + 8 × 34, in `SceneFade.frag`). With the profile's 32 slots, `dmsh_build.py` reported that binding as not decoded ("shaders with a binding whose slot was not decoded 1", which prints a red line when the shader loads). Its `nvn_tex_slots` is 35. The census of `fp_t_*` names in the translated libraries gives the slots in use; the host's tables hold up to 128. + Monster Hunter Rise (RE Engine, SDK 11.4.3) uses both tables at once: combined handles from `nvnCommandBufferBindTexture` at `0x20 + 8 × slot` and separate textures from `BindSeparateTexture(s)` at `0x168 + 8 × slot`, with separate samplers at 0x568, and binds slot 0 of both in the same frames. A census of 23,478 translated shaders' texture names: 33,813 combined (`fp_t_tcb_1E`), 29,342 separate textures with a constant sampler ID (handle type 3, `fp_t_cb65538_3041005C`: texture at c2 word 0x5C, sampler 0x104 ORed in), 8,265 separate texture + separate sampler (type 1, `fp_t_cb196610_1017815A`), 5,227 separate textures whose own handle carries the sampler (`fp_t_tcb_5A`), about 1,500 uniform-buffer handles with a constant sampler (`fp_t_cb65541_30410028`), and 121 fully dynamic handles (type 4, `fp_t2d_cb0_40000000`, not supported). The profile keys `nvn_septex_base` / `nvn_septex_slots` give the separate table: separate binds go to slots 128 + n of the replay's table and their handles decode to 128 + n; a constant sampler is the binding kind `samp_id` (`NVN_RB_SAMPI`, reg = the sampler ID). The profile's `nvn_*` keys hold these constants; `dmsh_build.py` decodes the bindings from them (`decode_tex`). `Program.cs` still has Mario's `TexBase` built in, but uses it only to look up per-slot texture / image types in the facts table, so a profile with other bases builds as long as its facts table has no such entries (Engage's has none; `dmsh_build.py` stops otherwise); the replay layer fills driver banks with the same layout: the texture, image and separate-sampler tables of `c2` (`NVN_RB_DRV2` in `encode_args`). Some shaders read `c2` rows as data at run time (Engage: 243, the texture and sampler handles of slots 0–11); the build lists reads outside those tables as `cannot fill`. After a full build, the summary must say `shaders with a binding whose slot was not decoded 0`. diff --git a/docs/development.md b/docs/development.md index a8986e6..63034ce 100644 --- a/docs/development.md +++ b/docs/development.md @@ -204,6 +204,14 @@ The game's own work and its frame rate stay as they are; the host avoids work of - **Mac input:** `DM_KEYS="f800:A,f1000:A,f1200:A,f1500:A,f1900:A"` goes through the title and the intro into Tartarus. - **Packing:** for a `graphics vulkan` profile the NSP script runs `vk_shaders.py` (Mac and iOS libraries in `_build/shader/vk` and `shader/ios/vk`) in place of the NVN shader split and chain build. +**Hades II (`0100A00019DE0000`)** +- **Engine:** Supergiant Games' engine, SDK 19.3.9, base game v0 (the NACP's display version is 0.0.126424). Unlike Hades it renders with **NVN**, and its ExeFS holds only main and sdk. The NSP script's provisional profile booted it on the Mac with no host change: title, a new save, the opening and Erebus at 60 fps. Not tested on an iPhone yet. +- **Shaders:** 88 BNSH files in `Shaders/NVN/bin` (`.vert` / `.frag`; the `.shader` files list each program's pair). They bind textures at fixed, sparse slots: 0, 1, 3, 6, 8, 11, 15, 21, 25, 26, 30, 31 and 34. Slot 34 (`SceneFade.frag`, c2 0x130) lies past the 32 slots of Mario's layout, so its binding was not decoded until the profile's `nvn_tex_slots` became 35. The game has no image bindings, so the overlap with the image table at 0x120 does not matter. +- **Online:** its `EOS_*` imports (Epic Online Services, `nro/EOSSDK-Switch-Shipping.nro`) stay offline, as in Hades: `ro::RegisterModuleInfo` fails (red line), so the game never loads the NRO. SDK 19's `nn::ro::LoadModule` takes one more bool (`…mib`); the host hooks that form and `ro::Finalize` too, so neither reaches the SDK's `ldr:ro` client. +- **Memory:** no system resource; the game asks for a 3.10 GB heap, which the 4 GB layout's heap region holds. main has an 82 MB bss, so the profile's `mem_used` is 108 MB. Resident memory levels off at about 3.4 GB in Erebus on the Mac. +- **Not a bug: two long lines through Melinoë.** While the staff's Omega attack charges, two thin white lines run from her to the screen edges, one forward and one back. They are that weapon's aim lines (`WeaponStaffSwing5`: `AimLineCountOverride = 2`, `AimLineAngleOffsetOverride = 180`, animation `AuraAimLineNoMovementStaff`). The sprite is a long arrow with white edges, a dark fill drawn emissive and its tip off-screen, and the game hides it while she moves. Traced with `DM_NVN_CBDUMP` vertex dumps and `DM_PROBE` on the aim-line update (`main+0x39ade0`); a scripted run that taps Y shows them often. +- **Mac input:** `DM_KEYS="f700:A,f900:A,f1100:A,f1300:A,f1500:A,f1800:A,f2100:A,f2400:A,f2700:A"` goes through Play, the first save slot and the opening into Erebus (control around frame 3000). + **Hyrule Warriors: Age of Calamity (`01002B00111A2000`)** - **Engine:** Koei Tecmo's KTGL on NVN, SDK 9.6.0, update 1.3.0 (v327680), four DLC packages (one is only a licence). Modules main + subsdk0 (movie) + sdk. - **Files:** everything sits in RDB archives (`asset/*.rdb` index; `asset/*.rdb.bin*` and `asset/data/*.file` hold `IDRK` entries, zlib in 16 KB chunks) ([01](agents/01-extract.md)).