Skip to content

Instantly share code, notes, and snippets.

@MoreOrLessSoftware
Last active November 19, 2025 22:43
Show Gist options
  • Select an option

  • Save MoreOrLessSoftware/7ab6eb4881059070b23a68fc58ca9dc2 to your computer and use it in GitHub Desktop.

Select an option

Save MoreOrLessSoftware/7ab6eb4881059070b23a68fc58ca9dc2 to your computer and use it in GitHub Desktop.
PowerShell script for changing the FPS limit in a RivaTuner Statistics Server profile
param(
# One or more (separated by commas) RTSS profile names to modify (e.g. Global or MyApp.exe or Global,MyApp.exe)
[string[]]$profiles = ("Global"),
# The FPS limit to set (use 0 for no limit, "auto" for current primary display refresh rate)
$limit = "auto",
# Optional limit denominator if you want to set a fractional FPS limit (e.g. for 59.56, use limit = 5956 and limitDenominator = 100)
[int]$limitDenominator = 1,
# Delay before attempting to read the current display refresh rate
[int]$autoLimitDelaySeconds = 0
)
# RivaTunerStatisticsServer v7.3.7 or higher is required
#
# Example usage:
# Set the global FPS limit to the current primary display refresh rate:
# .\Set-RTSS-Profile-Limit.ps1
# Set the global FPS limit to 60 FPS:
# .\Set-RTSS-Profile-Limit.ps1 Global 60
# Disable the global FPS limit (reset it to 0):
# .\Set-RTSS-Profile-Limit.ps1 Global 0
# Set the FPS limit of the Dolphin emulator to 59.56 FPS
# .\Set-RTSS-Profile-Limit.ps1 Dolphin.exe 5956 100
# RTSS interop
if (-not ("RTSS" -as [type])) {
Add-Type -TypeDefinition @"
using System;
using System.Runtime.InteropServices;
public static class RTSS
{
[DllImport("RTSSHooks64.dll", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Ansi)]
public static extern bool SetProfileProperty(string name, IntPtr data, uint size);
[DllImport("RTSSHooks64.dll", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Ansi)]
public static extern bool GetProfileProperty(string name, IntPtr data, uint size);
[DllImport("RTSSHooks64.dll", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Ansi)]
public static extern void LoadProfile(string profile);
[DllImport("RTSSHooks64.dll", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Ansi)]
public static extern void SaveProfile(string profile);
[DllImport("RTSSHooks64.dll", CallingConvention = CallingConvention.StdCall)]
public static extern void UpdateProfiles();
}
"@
}
# Determine the current display refresh rate if "auto" mode
if ("auto" -eq $limit) {
if (-not (Get-Command Get-DisplayInfo -ErrorAction Ignore)) {
Write-Host "Required module DisplayConfig does not appear to be installed" -ForegroundColor Red
Write-Host "Installation command:"
Write-Host " Install-Module -Name DisplayConfig" -ForegroundColor DarkGray
Exit 1
}
if ($autoLimitDelaySeconds -gt 0) {
Write-Host "Waiting $autoLimitDelaySeconds seconds before getting current refresh rate..."
Start-Sleep -Seconds $autoLimitDelaySeconds
}
$displayInfo = Get-DisplayInfo | Where-Object { $_.Primary }
$limit = $displayInfo.Mode.RefreshRate
Write-Host "Detected primary display refresh rate: $limit"
}
# Limit must be an integer
try {
$limit = [decimal]$limit
if (($limit % 1) -ne 0) {
$limit = $limit * 100
$limitDenominator = 100
}
$limit = [int]$limit
}
catch {
Write-Host "Failed to convert limit to number: $($_.Exception.Message)" -ForegroundColor Red
Exit 1
}
try {
# IntPtr for dll calls
$ptr = [System.Runtime.InteropServices.Marshal]::AllocHGlobal(4)
# Loop through all the profiles
foreach ($profileName in $profiles) {
# Normalize the profile name
$profileName = $profileName -replace "(.exe)?(.cfg)?$", ""
$profileNameFriendly = $profileName
if ($profileName -eq "Global") {
$profileName = ""
}
# Load the RTSS profile
try {
[RTSS]::LoadProfile($profileName)
} catch {
Write-Host "Failed to load profile '$profileName': $($_.Exception.Message)" -ForegroundColor Red
continue
}
# Read the current limit
try {
$currentLimitRead = [RTSS]::GetProfileProperty("FramerateLimit", $ptr, 4)
if ($currentLimitRead) {
$currentLimit = [System.Runtime.InteropServices.Marshal]::ReadInt32($ptr)
}
} catch {
Write-Host "Failed to retrieve FramerateLimit on profile '$profileNameFriendly': $($_.Exception.Message)" -ForegroundColor Red
continue
}
# Update the framerate limit denominator
[System.Runtime.InteropServices.Marshal]::WriteInt32($ptr, $limitDenominator)
if (![RTSS]::SetProfileProperty("FramerateLimitDenominator", $ptr, 4)) {
Write-Host "Failed to set FramerateLimitDenominator property on profile '$profileNameFriendly'" -ForegroundColor Red
continue
}
# Update the framerate limit
[System.Runtime.InteropServices.Marshal]::WriteInt32($ptr, $limit)
if (![RTSS]::SetProfileProperty("FramerateLimit", $ptr, 4)) {
Write-Host "Failed to set FramerateLimit property on profile '$profileNameFriendly'" -ForegroundColor Red
continue
}
# Save the profile
try {
[RTSS]::SaveProfile($profileName)
Write-Output "[Profile: $profileNameFriendly] Updated FPS limit ($currentLimit >> $limit[/$limitDenominator])"
} catch {
Write-Host "Failed to save profile '$profileName': $($_.Exception.Message)" -ForegroundColor Red
}
}
} finally {
# Free pointer memory
[System.Runtime.InteropServices.Marshal]::FreeHGlobal($ptr)
}
# Ensure the profile changes take effect
try {
[RTSS]::UpdateProfiles()
Write-Host "✓ " -NoNewline -ForegroundColor Green
Write-Host "RTSS profiles updated"
} catch {
Write-Host "Failed to update RTSS profiles: $($_.Exception.Message)" -ForegroundColor Red
}
@Wordsmith9091
Copy link

Hi! this just proved super-helpful to me, setting RTSS to match refresh rates when streaming with Apollo (the Sunshine fork). It could also be done with RTSS-CLI, but in order to use fractional refresh rates, I needed to be able to set LimitDenominator as well, and I'm not sure if RTSS-CLI could handle that. This worked great!

I describe how I'm using it in a discussion thread for Apollo here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment