Homebrew  Updated

FPSLocker - set custom FPS target in retail games

An overlay that with SaltyNX 1.2.0+ allows to set custom refresh rate in both handheld and docked mode + FPS in Nintendo Switch retail games.

Disclaimer: Tool is utilizing detection of graphics API to manipulate FPS. It supports special patches that are helping with going above 30 FPS in games using proprietary FPS locks.

You can see here how it works (I was utilizing Witcher 3 dynamic resolution config mod to make anything above 30 FPS available):


More in README (I recommend to read it + also SaltyNX readme if you don't know how it works)
Repo: https://github.com/masagrator/FPSLocker
Releases: https://github.com/masagrator/FPSLocker/releases
Patches: https://github.com/masagrator/FPSLocker-Warehouse
 
Last edited by masagrator,
Hello. I've just downloaded last version of saltyNX 1.5.4 and I saw this interesting quote regarding the new features:

Add to toolbox.json version of sysmodule so Sysmodules 1.4.0+ overlay can show properly sysmodule's version.

I was wondering where can I find the sysmodules 1.4.0 overlay, since I am unable to locate it here:

https://github.com/zdm65477730/ovl-sysmodules

Maybe this version of sysmodules overlay will be released at a later date?

Thanks a lot for your help.
 
FPSLocker 3.2.0/SaltyNX 1.6.2
FPSLocker 3.2.0 was released.

All changes since 3.0.2:
  • Multiple fixes in FPSLocker config to patch conversion related to assembly instructions (no config was affected by it as of 17.10.2025, but this was hindering slightly process of writing them)
    • LDRB and LDRH now don't return error when instruction has provided fixed offset
    • TBZ and TBNZ now support goto labels
    • All conditonal branches are now supported
  • Fix config to patch conversion in scenario where MASTER_WRITE's asm_a64 type included BL instruction with direct offset (this fixes an issue with config for Kirby's Dream Buffet)
  • Fix Halt unfocused game state not being saved in certain situations.
  • Now if game has no config available on sdcard, in Advanced settings below provided TID and BID you will see also game versions:
    • Developer game version | Internal game version's major value / Raw internal game version
  • When using the Check/Download config file, information will be sent to my own tracker. This will provide a clearer view of what people would like to be available in the Warehouse. No personal data or hardware data is sent.
    • To avoid introducing a visibly worse experience when using the Check/Download config file, I set the connection to terminate if it takes longer than 1 second.
  • Added compatibility for Atmosphere 1.10.0+
  • When using Check/Download config file and when config file was not found, but it was confirmed that game is listed in Warehouse with different version, now newest listed update is printed.
  • Games list titles now load faster by 35% on average on FW 19.0.0+
    • Found a different way to retrieve titles which is faster than original function. Added PR to libnx so other people can use it.
  • If you are using old enough SaltyNX for BID to show only zeroes, Check/Download config file will instantly time out.
  • Updated Chinese Simplified translation. Thanks to @naicfeng
  • Add an alternative source "Gitee" for downloading FPSLocker configs that is not blocked by China and other countries that block Github/are blocked by Github. I used it as first source because it's universally available, though it may be a bit slower to use for people located further from China.
    • Big thanks to sskyNS for hosting automated clone repository on Gitee (because it requires Chinese phone number to create repository).
    • So first is checked Gitee, if config was not found it checks readme on gitee. If game or its version was not found in readme on Gitee, it moves to github to check for config and if not found, it checks readme on Github.
  • Now you can exit Advanced settings even in the middle of Check/Download config file connection, session will be terminated before going back to main menu.
  • When config file is not found in Warehouse, percentage indicator will show up when downloading README.

Also SaltyNX changes since 1.5.3 to 1.6.2:
  • Add support for reading resolutions from nvnCommandBufferSetScissor and nvnCommandBufferSetScissors, resolutions are pushed as Viewport. Any resolution passed to Scissor(s) is ignored that was the same as last resolution pushed via nvnCommandBufferSetViewport and nvnCommandBufferSetViewports. This fixes an issue with reading resolution in games on Pokemon Engine which are using Scissors for dynamic resolution.
  • Core32 now is using hard float ABI, making it faster and smaller.
  • Fixed a bug in 64-bit Core with FPSLocker patches that were using negative offsets in addresses (fixes an issue with WARRIORS OROCHI 4 / 無双OROCHI3 patches).
  • Change method of forcing game into pause (FPSLocker's Halt unfocused game), now Core only manages how game should handle focus state, leaving to kernel maintaining game in pause state which should have better compatibility than previous method
  • Change method for retrieving focus of Application
    • It doesn't change anything in Core so perfect compatibility is maintained
    • Now CPU usage doesn't spike drastically while some games are running, causing sysmodule to be randomly unresponsive - if user decides to enable 60 HZ in HOME Menu in FPSLocker
  • Added compatibility for Atmosphere 1.10.0+
  • Streamlined compiling Core and Bootstrap so 32-bit and 64-bit share now the same source code with few ifdefs
  • Fix an issue with some games not reporting file read speed (f.e. Saints Row The Third)
    • Replaced a function pointer for reading file that is used when GlobalFileDataCache is enabled.
  • Add support for reading resolutions from Vulkan's Scissor functions (Similar to nvn, reported as Viewport)
    • It fixes an issue with some games not reporting resolutions, f.e. Blades of Time
 
3.3.0
Released FPSLocker 3.3.0

Changes since 3.2.1:
  • Fix an issue with game specific "Delete settings" option not deleting settings for different programs than main one (limited to first 16 IDs).
  • Fix 0x207 error showing up for some people
    • It was a combination of using nx-ovlloader in 4MB mode and overlay using too big socket buffers which I increased recently when debugging some other errors, which resulted in socket buffers taking 4x more space.
  • Fixed an issue where running game with different program than main one resulted in no game version showing up in Advanced Settings
  • Add Traditional Chinese language
  • Fixed numerous issues that occured when using sys-dock sysmodule
  • Fixed an issue with emoji indicator next to HBR mode that was not properly aligned in different languages than English
  • Changed emoji behavior next to HBR mode so ❌ occurs only for HBR mode with 2 DP lanes, in case of 4 DP lanes or HBR2 it will show ✅.
  • Updated internal titleid base.
For Switch OLED users that want to play in docked mode at high refresh rates and can't get past 75 Hz: new sysmodule has been released to fix your issues - it's called sys-dock. This can fix your issues. Read README properly!

Also SaltyNX changes since 1.7.0 to 1.7.4:
  • Reduced sysmodule RAM usage from 752 kB to 432 kB without removing any functionality (this is like the hard limit without doing some optimization shenanigans or reducing functionality, ram usage is now completely independent from Core's size)
  • Reduce Cores sizes by 20%
  • Fix elf plugins support broken in 1.7.0 release
    • This also fixed issues with loading elf plugins to all retail games that were added as exceptions, so now those games are fully compatible with SaltyNX instead of partially compatible:
      • Alien: Isolation
      • Company of Heroes Collection
      • EA SPORTS FC 24
      • GRID: Autosport
      • Immortals Fenyx Rising
      • Luigi's Mansion 3
      • Mario Strikers: Battle League
      • Olympic Games Tokyo 2020 – The Official Video Game
      • Plants vs. Zombies: Battle for Neighborville
      • Stubbs the Zombie in Rebel Without a Pulse
      • The Lara Croft Collection
  • Fixed an issue with Unreal Engine games not setting properly on boot Fake Docked mode saved with ReverseNX-RT
    • Issue comes from engine's strict order in processing notifications, OperationMode must be processed before PerformanceMode
  • Properly fix an issue with GetAllModuleInfo function introduced in 20.x SDK instead of using workaround (Thanks to @nvnprogram for solution). This function is mainly used by Unity 6 games.
    • Because of this change if you use any ELF Plugins, you may be forced to recompile it with libnx_min from this repository for it to work with 20.X.X SDKs and newer.
  • Expose dock DP lane count via IPC (necessary to introduce some changes in FPSLocker)
  • Don't block max refresh rate to 75 Hz in case of detecting HBR mode in 3rd party dock with active 4 DP lanes
 
Hello, is it possible to set custom refresh rate for homebrew also, i really like tsvitch and my in region is 25fps channels, so i have to manually set it to 50hz every time.

Also i noticed in my oled with original dock, if i change the refresh rate there is a bag, the switch send full rgb color with signal to tv or monitor to set limited, of course after that there is mismatch. Is that happens only with my oled unit? On 144hz and up it send full rgb with signal full so it is correct. Also if in hos settings i put limited it also correctly send signal to monitor to set limited on all refresh rates.
 
Last edited by AlexArt87,
Hi, does anyone here have experience doing 1080p 120hz with a V2 Switch and a 3rd party Newdery Switch Dock?. I have the newest version of fpslocker and sys-dock but no matter what flags I toggle and patch after a restart I can't get refresh rates over 60 fps to populate or the display overclock wizard. Only the underclock Wizard shows and myDP link rate only shows with HBR and a red X. Also I have a TCL QM7K 144hz tv. Thanks
 
FPSLocker 3.4.0 / SaltyNX 2.0.0 New
FPSLocker 3.4.0 got released, changes since 3.3.1:
  • Fix an issue with Change Refresh Rate not showing up when Docked Display Sync was off
  • Add support for new type of NACP introduced with The Legend of Zelda: Breath of The Wild 1.9.0, now title is showing up properly.
  • Titles for "Games list" are retrieved faster by 10-15% on 21.0.0+
If you ever had an issue with glitchy horizontal lines when using high refresh rate in docked mode at 1080p, new sys-dock release introduced "force_full_render_pass" patch which fixes the issue. Read README for link.

  • 22.0.0+ FW
    • 22.0.0 improved exeuction time of nsGetApplicationControlData() and its alternatives by 4x in comparison to 21.0.0 - as long as you use standard 0 or 1 flag (nsGetApplicationControlData() doesn't expose that flag and uses 0).
  • Match functionality of FPSLocker patches for 32-bit games to 64-bit games
    • Add new type to MASTER_WRITE: asm_a32
    • Add support for generating Aarch32 assembly instructions
    • Requires SaltyNX 2.0.0+
  • Updated internal titleid base.
SaltyNX got 2.0.0 release.

Changes since 1.7.5
Small performance optimizations:

  • Core:
    • 32-bit Core now has properly implemented support for generating Armv8-a 32-bit code instead of being forced to armv6k, thanks to that we can use less instructions to achieve the same thing
    • 32-bit Core now properly recognizes alignment of SharedMemory so compiler properly optimizes instructions accessing it instead of taking worst case approach
    • NX-FPS:
      • Remove most of repetetive code
      • Cache more frequently values returned by weakly linked function calls
      • Avoid using float divisions in functions that are called multiple times in one frame
  • Sysmodule:
    • Apply proper fix instead of workaround for SM
    • Fix an overflow in internal display pixel clock calculation which resulted in wrong reported refresh rate for overclocked displays (was not an issue in stock SaltyNX because overclocking internal displays is unsupported)
  • IPC redesign
    • completely remove old libnx code from sysmodule
      • main reason for using it was to retrieve sdmc handle that can still work after passing to Core, with how current libnx works it is not possible to do that
      • but this was causing rare issues with homebrew where FS would "forget" about process when trying to write to/read from sdcard, resulting in random process hanging. This happened only when multiple processes tried to do this at the same time. This change should technically fix the issue.
      • function for retrieving sdmc handle from sysmodule is now stubbed
    • Add new IPC functions that are just wrappers around libc I/O functions that are exposed by Core (so plugins shouldn't be affected by this change as long as they didn't try to retrieve sdmc handle manually - which was not officially supported)
    • Rewrite most of IPC functions so they work only when request comes from Application with injected Core
    • Logging was redesigned for those calls
    • Since now most of I/O heavy lifting was moved to sysmodule, Cores got smaller
  • Remove most of c++ unwinding and abort stuff to reduce sysmodule size
    • This way - after redesigning IPC - sysmodule RAM usage is bigger only by 12 kB
  • Reduce amount of FS sessions to 1 to fix an issue with session manager's session exhaustion
  • Move from custom libnx fork used in 64-bit Core to main one
    • This is the main reason why Core got slightly bigger
  • Change filenames for elf and log files starting with "saltysd" to start with "saltynx"
    • Improperly updating SaltySD folder will result in Cores not being injected into games
  • Add new members to NX-FPS struct - PerfCounters, from which for now only NVN performance counters are fully implemented
    • It doesn't break compatibility with tools using older struct definition
  • Fix internal display refresh rate calculations so it won't break at some custom values
  • Modify some IPC commands to guard against access from other processes than retail game (so only injected Core can access them)
  • Detach and remove some files from libnx32_min for faster compilation
  • Fix all GCC 16 warnings and errors, move from c++23 to c++26
  • Code design changes in NX-FPS module
  • Add support for REFRESH_RATE variable in FPSLocker patches
  • Properly enable access to NEON instructions in 32-bit parts of SaltyNX which allows better code optimizations
  • Optimize copying NVN performance counters in 64-bit Core to SharedMemory
  • Omitted "samplesPassed" performance counter is now properly copied to SharedMemory
  • Core source code changes
    • Decouple FPSLocker parser so now its code can be used in Warehouse workflow to test if patch is properly applied in virtual environment
    • IPC now has common parts moved to noninlined function which allows making whole IPC code smaller
  • Add support for Aarch32 code cave
    • Thanks to this now 64-bit and 32-bit have the same FPSLocker patches functionality
  • Update code to support 42-bit address space introduced with 23.0.0

Upcoming next feature is enabling triple buffer in double buffer games without dedicated patches. Currently tested only XCX, solution needs more testing to check which double buffer games will not like that we steal 26 MB from them. This will be opt-in since without playing whole game we won't know which one is truly safe from crash.

 
Last edited by masagrator,

Site & Scene News