- profile 01007BB017812000 (1.0.3, SDK 13.3.0): plays on the Mac at 60 fps - provisional profiles add the subsdks the NROs import (profile_guess nro_modules) - an NRO importing nvnBootstrapLoader makes an NVN game; NROs calling glslcCompile get the run-time GLSLC capture - shader_split reads zip archive members (Portal's nxcontent/nvsb GLSLC outputs) - ro::LookupModuleSymbol for a name a loaded module lacks is not red (Horizon fails it too) - AGENTS.md: a Mac gameplay test is enough to count a game as playable (65)
Portal (01007BB017812000)
Update 1.0.3 (v196608) over the base game, SDK 13.3.0. Valve's Source engine as NVIDIA Lightspeed Studios ported it to the Switch: main is a 0.5 MB launcher with SDL, and the engine is 28 NRO modules (nro/*.nro in the RomFS, registered by .nrr/launcher_main.nrr) loaded with nn::ro. It renders with NVN, its D3D9 layer linked into materialsystem.nro. Modules main, subsdk0 (GLSLC), subsdk2 (NintendoSDK_movie) and sdk; subsdk1 is NVIDIA's OpenGL driver and is never loaded.
Current: plays on the Mac at 60 fps: the opening movie, the title menu (its 3D background map), New Game, test chamber 00 with its portals (the view through them included), the pause menu and a saved game, with sound; no red line. About 1.5 GB footprint in the chamber. The unsigned IPA is built (2,823,721,518 bytes, about 2.6 GB); not yet tested on an iPhone.
What it needs
| Setting | Where | Why |
|---|---|---|
modules main subsdk0 subsdk2 sdk |
game.tsv |
main imports from no subsdk; the NROs do: video_nx.nro plays the movies through the movie module and both it and materialsystem.nro call GLSLC (Modules only the NROs import from) |
4 GB layout: mem_reserve 0x100000000, mem_alias 0x10000000, mem_stack 0x10000000, app_pool 0xCD500000, sys_resource 0x0 |
game.tsv |
no system resource, so no virtual address memory; the game sets a heap in the 4 GB layout. The rewritten modules fit the default 64 MB of used memory |
pad_layout full |
game.tsv |
first-person: move with the left stick, look with the right |
shader_groups /game.zip/=game |
game.tsv |
the shipped programs come from game.zip; the run-time captures go to other |
Rendering
- Resolved: the NSP script took it for an OpenGL game.
mainimports 20 EGL functions and namesglShaderSource(SDL's EGL backend and GL renderer), but draws nothing;materialsystem.nroandvideo_nx.nroimportnvnBootstrapLoader. The first capture boot stopped with[nvn-mtl] FATAL cannot read the shader mapfrom an NVN submit innro8(NVN in NROs under an SDL main that names GL). - About 140 draws a frame at the title and in chamber 00; GPU p50 about 6 ms on an M4 Pro, NVN submit and present under 3 ms.
Shaders
- The D3D9 layer links each Source shader combination (
hl2/shaders/fxc/*.vcs, D3D9 bytecode) into one program and keeps the GLSLC output of every program in the game's precache list (portal/glbaseshaders.cfg, 219 entries) innxcontent/nvsb/<hash>.nvsb: a 0x60-byteNVSBheader (version 0x65, the file's length at +8), then one GLSLC output holding a vertex and a pixel shader. The game compiles the rest withglslcCompile: within 30 s of boot, 10 outputs (the movie's and the engine's own). - Resolved: the split found none of the 219: they are deflated members of
game.zip(GLSLC outputs in a zip archive, and those NROs compile at run time). The map has 255 keys, 165 pixel and 90 vertex, 242 from the.nvsbfiles and 13 from the capture, with 229 vertex and pixel pairs. - The game writes the programs it has linked to its save,
portal/glshaders/glshaders.cfg(-glshadersSaveFSin its boot parameters): 219 entries after chamber 00, the precache list. More entries there mean programs compiled at run time on that route, which a fresh capture boot does not reach; on the iPhone each would give[RED] shader … is not in the shader map.
Files
- The whole game is
game.zip(2.7 GB, 41,416 members, Deflate or stored) beside the NROs; the Source file system reads it itself. The profile'sromfs_markerisgame.zip. - The boot parameters are
nxcontent/rom_boot_params.txtin the zip (-game portal -glshadersSaveFS -nodev -nosteam +mat_queue_mode 2 +mat_picmip 0); host arguments after--(a+mapamong them) change nothing. - Only the merged update is registered. The base game's build has no profile row.
Movies
- The opening movie (1280x720 H.264 with AAC) plays through the host's movie decoder from
video_nx.nro, which shows the frames with NVN and plays the sound through its ownAudioOut.
Mac routes
- Run the command the NSP script prints for
--platform mac(DM_NVN_SHMAPnames this profile'sshader_map.tsv), withDM_CTL=<file>to drive it (05-debugging.md). - From a fresh save: the title menu at about 25 s;
A(New Game),A(Chapter 1) loads test chamber 00 in about 15 s. The portal opens in the vault after GLaDOS's first lines (about 30 s); the right stick turns, the left stick walks through it.Plusopens the pause menu;Down,A,Asaves (portal/save/*.savin the save).
Found on this game
- Modules only the NROs import from: the provisional profile adds the subsdks the NROs need.
- NVN in NROs under an SDL main that names GL: the graphics API follows the NROs' imports.
- GLSLC outputs in a zip archive, and those NROs compile at run time: the split reads zip members; the run-time capture also runs for NROs that call
glslcCompile. ro::LookupModuleSymbolfor a name the module does not define: the engine'sBuiltDebugprobe is answered as on Horizon, without a red line.
Open
- iPhone test of the IPA.
- Later chambers (energy balls, turrets, water, the escape) are untested; watch
glshaders.cfgand the log for programs outside the shipped 219.