(Switch 2) Compatibility Mode

From Nintendo Switch Brew
Revision as of 08:58, 6 June 2025 by Ootulp (talk | contribs) (Created page with "When a Switch 1 game is running on the Switch 2, it is loaded together with 3 new modules: * nnCompatTrampoline * nnCompatThin * nnCompat These binaries are compiled with PAC enabled. = Hooking = Backwards-compatibility is achieved by (ab)using dynamic linking to selectively hook API functions. Three compatibility libraries are mapped into the game process. They provide symbols which override the original sdk co...")
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigation Jump to search

When a Switch 1 game is running on the Switch 2, it is loaded together with 3 new modules:

These binaries are compiled with PAC enabled.


Hooking

Backwards-compatibility is achieved by (ab)using dynamic linking to selectively hook API functions. Three compatibility libraries are mapped into the game process. They provide symbols which override the original sdk codebin implementation, wherein a translation layer for Switch 2 is provided.

Most of these end up doing small tweaks to the parameters, and then calling into the original function implementation.

Switch 2 is mostly backwards-compatible, so most sdk codebin symbols remain unchanged and execute their original code. The overrides are mostly related to Graphics (i.e. translating to the new GPU), but there are also plenty other function overrides to deal with various system differences.

Below is a breakdown what some of the hooks and what their purpose is.

CompatibilityParameter

The system puts an additional information block in the ProgramArgument parameter for the LaunchParameter for the process. This block contains certain extra information and overrides, which allows customization of the compatibility hooks depending on the game.

To retrieve this pointer, nnCompatThin intercepts the nnosInitialize function and retrieves it from there. Normally, a game doesn't use the ProgramParameter so it doesn't care this parameter was passed.


nnCompatTrampoline

nnCompatThin

Hooked Symbol Difference
nnosInitialize Captures the ProgramArgument parameter where the #CompatibilityParameter is stored.
nn::os::CreateThread No change.
nn::os::SetThreadCoreMask No change.
nn::os::GetThreadAvailableCoreMask Returns actual core mask masked with 0x7, effectively pretending that there are only 3 CPU cores available.
nn::audio::GetAudioInName If the primary audio in name is "XUac", it returns the secondary device name instead. Presumably, the "XUac" device has been removed in Switch 2.
nn::audio::GetReleasedWaveBuffer Now returns NULL under certain circumstances.

nnCompat

Hooked Symbol Difference
nn::os::GetSystemTickFrequency Returns 31250000 instead of 19200000.
nn::os::ConvertToTick Uses conversion ratio 31250000 instead of 19200000.