FINAL FANTASY RESONANCE plays on the Mac at 60 fps: profile 0100606026F12000 (update 1.0.1, SDK 20.5.17)
- Engine: Unreal Engine 5.6.1 (Square Enix, the desktop renderer), the newest Unreal so far; everything in one IoStore container beside one pak; the sdk and subsdk0 builds are STEINS;GATE RE:BOOT's - Rewriter, for every module: code before the first unwind entry is one function (each site there was a function of one instruction, so a byte jump table at main+0x219234 went unseen), and a function longer than 256 KB is analysed in pieces cut after a ret / br / b that no conditional branch or b within 64 KB crosses, with far branches and jump table targets checked against windows and retry blocks afterwards (this main's 82 MB without unwind entries took 100 GB of memory as one function; now 2.7 GB resident). Checked: DRAGON QUEST VII Reimagined's main byte-identical to its rewrite by the previous patch_nso.py; FINAL FANTASY RESONANCE's, Octopath Traveler 0's and DRAGON QUEST XI S's byte-identical between two different cut placements; only DQ VII's main among the 120 modules of 33 games on hand has other sites before its first unwind entry (none in a window or jump table) - Shaders: no archive in the pak; the two libraries are IoStore shader library chunks whose tables and shader groups are Oodle-compressed, read through the game's own Oodle in the Mac host's tool mode with no boot (uepak.py Toc / io_archive / OodleHost; library names from CityHash64 of the manifest's archive names) and written as decoded version 2 archives; the NSP script uses them for any game with IoStore shader libraries. The pak's single-block files store block size 0 (Pak.entry). 73,496 unique shaders; 11 do not build (3 geometry, 8 compute with 3D image atomics), none met so far. 2,077 particle vertex shaders pick their texture slot at run time (tex_dyn_slots); CopyStencilToLightingChannelsPS writes integers to an R8Uint target (shader_facts_manual.tsv; without it the sprites were dark silhouettes) - Host, for every game: a shader with run-time texture handles in a game without tex_dyn_slots freed its reflection twice and aborted the host (nvn_mtl.m); oe::MuteRecording / UnmuteRecording (no-ops) - Memory: the FMallocBinned3 constructor call is cut and the host's allocator runs Unreal's heap (hle_uemalloc.c layout UE5_6: UE 5.5+ FMalloc has 32 slots, with MallocZeroed and two more TLS cache calls); the SDK's node area is cut to 62 MB. The engine's own page allocator only grows its use of the engine region (2.03 GB of address space over seven minutes, about 1 GB mapped), and a 2 GB region aborted in the first battle, so the region is 4064 MB in Engage's 5 GB block (this sdk build aligns regions to 2 MB, no alignment cut needed) - Frame rate: 60 fps (30 on the Switch): the host writes rhi.SyncInterval 1 (hle_fpslock.c rows for this build; profile fps_target 60); the game steps by real time (DM_NVN_REGLUM traces at 30 and 60 fps match from the load through a walk) - Mac: first-boot settings, the title, a new game, the opening cutscene, the first field and its autosave, Continue, and the first two battles at 59.7 fps, 2.3-2.6 GB resident, flat over seven minutes, no red line apart from a few texture type mismatches at one moment of the new game's load in some runs. Docs: docs/agents 01, 03, 04 and development.md
This commit is contained in:
1 parent
0b3c7b1200
commit
2000f9274a
23 files changed
+159450
-18
No files matched your search
@@ -0,0 +1 @@
|
||||
# generated
|
||||
|
@@ -0,0 +1,26 @@
|
||||
# chain b-650bb0cacdba 2026-10-23T06:37:35+08:00
|
||||
114ba379d35f98ac
|
||||
12041d2a0d717938
|
||||
18ccc110f0abf48e
|
||||
1c69a5865b200713
|
||||
1d0e296df7df9d2e
|
||||
1e31184b70862647
|
||||
327581a0d46e0817
|
||||
45cae1f83852724f
|
||||
61308412eb911f79
|
||||
83210ea2c1575566
|
||||
853b5fb1bbaebd54
|
||||
88ba8b2a90149c97
|
||||
894f7cbca8f53c2b
|
||||
922273c0c61517ce
|
||||
9390e020cb6333e4
|
||||
9907e4343ceb38cc
|
||||
b28cebe353a212a8
|
||||
b9907381cf1fbff5
|
||||
ce7c8c914188744f
|
||||
cf75f8c9fb510b28
|
||||
ef9ee1bbe3495128
|
||||
f3a188919ebbd946
|
||||
f4db3f54ae52c90a
|
||||
f741f3837e362c3e
|
||||
fc0dc911a2850953
|
||||
|
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,2 @@
|
||||
// Generated file (dm/gfx/tools/dmsh_chain.py --header, game 0100606026F12000): the B shader library translation chain version this source tree expects (default options); the host loads only <library dir>/b-<V>/
|
||||
#define DMSH_CHAIN "650bb0cacdba"
|
||||
@@ -0,0 +1,65 @@
|
||||
# FINAL FANTASY RESONANCE: Square Enix, Unreal Engine 5.6.1 (SDK MW+EpicGames+UnrealEngine-5_6_1 in main; the desktop renderer, SF_GLSL_SWITCH shaders), SDK 20.5.17, NVN, CRIWARE sound;
|
||||
# update 1.0.1 (v65536). Everything is in one IoStore container beside one pak; the shader libraries are IoStore chunks (uepak.py).
|
||||
# Started from the NSP script's provisional profile (dm/games/profile_guess.py) and brought up on the Mac (docs/agents)
|
||||
# Format: see dm/games/README.md
|
||||
|
||||
# ---- Identity ----
|
||||
title_id 0100606026F12000
|
||||
program_id 0100606026F12000
|
||||
|
||||
# ---- App ----
|
||||
# Game name: only a label for profile listings and the Mac window title; the iOS app name is the game name in the base NSP, and the bundle ID comes from the base game title ID (build_ipa.sh / NSP script)
|
||||
name FINAL FANTASY RESONANCE
|
||||
ipa FinalFantasyResonance.ipa
|
||||
app_category public.app-category.games
|
||||
|
||||
# ---- Versions ----
|
||||
build v65536 1.0.1 main=84e182f72ee1da4f477804bd05b54c15 subsdk0=ab62fe8edd07a6a293f885d54359e559 sdk=0023a1b06130cd795f7bc4613772af0a
|
||||
package v65536
|
||||
shader_versions v65536
|
||||
|
||||
# ---- Files ----
|
||||
# load order as on Horizon: main, subsdk*, sdk (subsdk0 = NintendoSDK_movie, which main imports from; the sdk is STEINS;GATE RE:BOOT's build)
|
||||
modules main subsdk0 sdk
|
||||
romfs_marker FFRS/Content/Paks/FFRS-Switch.ucas
|
||||
zip_store .pak:.ttf:.txt:.ucas:.utoc:.metallib
|
||||
|
||||
# ---- Graphics ----
|
||||
# 60 fps (30 on the Switch): the engine's Switch device profile sets rhi.syncinterval=2 (BaseSwitchDeviceProfiles.ini), so the game asks for present interval 2, and the game sets no t.MaxFPS.
|
||||
# The host writes rhi.SyncInterval 1 into its console variable (hle_fpslock.c), whenever the game sets it back (at level loads), so the game asks for present interval 1 itself. Unreal steps
|
||||
# the game by the time that really passed: DM_NVN_REGLUM traces of the same keys from the same save at 30 and 60 fps (59.8 fps, frame time p99 18 ms on the Mac) match from the load
|
||||
# through a 3 s walk (thumbnail difference ≤ 0.006). DM_FPS_TARGET=30 (Documents/env.txt on the iPhone) keeps the game's 30 and saves power
|
||||
fps_target 60
|
||||
|
||||
# ---- Memory ----
|
||||
# Unreal Engine 5.6.1: nninitStartup (main+0x13370) reserves one 62 GB region for the engine (-SwitchVirtualAddressSpaceSize= in MB up to 4095, game_args below), and its FMallocBinned3
|
||||
# (38 GB of address space) is constructed in place in the bss; the constructor call is cut and the host runs Unreal's heap on a malloc zone (patch_nso.py, hle_uemalloc.c layout UE5_6),
|
||||
# and the SDK's node area is cut to 62 MB. The engine hands the region out with a page allocator of its own (main+0x13ef0): a bump pointer, and freed blocks kept in free lists by size
|
||||
# class, so its address use only grows, and past the region's end OnOutOfMemory (main+0x13c74) aborts. Probed at main+0x13fcc from the save in the first field, through the first battle:
|
||||
# a 1 GB block at boot (a static constructor), the high-water mark at +1.50 GB 15 s in, +1.77 GB at 56 s, +2.02 GB at 166 s; a 2 GB region (DRAGON QUEST VII Reimagined's) aborted in that
|
||||
# battle. This SDK build aligns regions of 2 MB and more to 2 MB only (VammManager::AllocateAddressRegion, sdk+0x145e00), so the region starts right after the node area: a 4064 MB region
|
||||
# in Engage's 5 GB block (256 MB in front + 4.375 GB alias region + 256 MB stack region + 128 MB heap region), as DRAGON QUEST XI S's. On the Mac in the field and the first battle:
|
||||
# about 1 GB of the alias region mapped, an Unreal heap of 1 GB, 2.2-2.4 GB resident and 1.2-1.5 GB of Metal allocations
|
||||
game_args -SwitchVirtualAddressSpaceSize=4064
|
||||
mem_reserve 0x140000000
|
||||
mem_alias 0x118000000
|
||||
mem_stack 0x10000000
|
||||
app_pool 0xCD500000
|
||||
# the NPDM declares 20 MB of system resource
|
||||
sys_resource 0x1400000
|
||||
|
||||
# ---- Input ----
|
||||
# A 3D field whose camera the right stick tilts and turns: the 3D pad layout. It plays docked (1920x1080)
|
||||
pad_layout full
|
||||
|
||||
# ---- NVN ----
|
||||
# 2,077 vertex shaders (Unreal's particle vertex factories) pick one of several c2 table slots at run time: texture table words 0x168-0x1c0 and sampler table words 0x568-0x590, and no other
|
||||
# word of c2. The translator cannot trace them to one slot: slot indices in c2, the bound slots in its arrays (without the key the first one aborted the host in a double free, now fixed)
|
||||
tex_dyn_slots on
|
||||
|
||||
# ---- Shader split ----
|
||||
# The two shader libraries of the IoStore container FFRS-Switch.utoc / .ucas (no shader code archive in the pak): the engine's global shaders and the game's material shaders. Their tables and
|
||||
# shader groups are Oodle-compressed, which the game's own decoder undoes in the Mac host's tool mode (uepak.py Toc / io_archive / OodleHost, no boot). Unreal combines vertex and pixel
|
||||
# shaders per draw from its pipeline state, so every vertex shader is made to link with any pixel shader (shader_split.py separable_pairs)
|
||||
shader_groups ShaderArchive-Global-=global ShaderArchive-=game
|
||||
shader_note FINAL FANTASY RESONANCE shaders
|
||||
|
@@ -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.
|
||||
# Provisional profile: empty until recorded on the Mac (DM_PSO_MANIFEST=off DM_PSO_RECORD).
|
||||
|
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,6 @@
|
||||
# Hand-written translation facts, merged over the generated rows of shader_facts.tsv by dm/gfx/tools/shader_split.py: key <TAB> facts JSON (same format)
|
||||
# Unreal's GLSL_SWITCH shaders carry no fragment output types, so the translator declares every output float; Metal refuses a pipeline whose float output meets an integer attachment
|
||||
# (the host's red line then prints the row to add here).
|
||||
# c254eaa40e0c4f1e (ShaderArchive-Global-SF_GLSL_SWITCH-SP_GLSL_SWITCH shader 1627, pixel: DownsampleDepthPixelShader.usf CopyStencilToLightingChannelsPS): writes the stencil's lighting
|
||||
# channel bits to an R8Uint target (seen in the first scene after the opening cutscene)
|
||||
c254eaa40e0c4f1e {"fout":{"0":"uint"}}
|
||||
|
Can't render this file because it contains an unexpected character in line 6 and column 19.
|
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,2 @@
|
||||
# kind: evidence control-section key conflict rulings: empty
|
||||
dm_ctl_sha16 chosen_pc class candidates records
|
||||
|
File diff suppressed because it is too large.
Load diff
Reference in new issue
Block a user