Ask the headset for a configured refresh rate, 120 Hz on the Steam Frame

[vr] refresh_rate (Hz, 0 = the headset's own) is requested through
XR_FB_display_refresh_rate each time the session starts running and
whenever the setting changes, matched against the runtime's own list
within half a hertz. Setting it back to 0 restores the rate the session
started at. A rate that is not offered, or one the runtime declines, is
logged and changes nothing.

The game renders 60 frames a second, so at 120 Hz every frame shows for
exactly two refreshes, where 72 or 90 Hz hold some frames longer than
others. The Steam Frame build defaults to 120; every other build keeps
the headset's own rate unless the player picks one.

The F10/headset panel and the Android launcher's Headset section offer
the choice; the interpolation tooltip points at it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019HBRGKTE1GnN2ah8gcZKr3
This commit is contained in:
Claude committed 2026-10-04 08:32:33 +00:00
1 parent 150062280d
commit 8b98330485
8 files changed
+215 -1

No files matched your search

@@ -243,6 +243,13 @@ class SettingsPage(
read = { stringIndex(it, "vr", "performance_level", PERFORMANCE_LEVELS) },
write = { c, index -> c.setString("vr", "performance_level", PERFORMANCE_LEVELS[index]) },
)
choice(
R.string.vr_refresh_rate, R.string.vr_refresh_rate_helper,
listOf(activity.getString(R.string.vr_refresh_rate_headset), "72 Hz", "90 Hz", "120 Hz", "144 Hz"),
read = { REFRESH_RATES.indexOf(vrRefreshRate(it)) },
write = { c, index -> c.setInteger("vr", "refresh_rate", REFRESH_RATES[index]) },
custom = { "${vrRefreshRate(it)} Hz" },
)
choice(
R.string.vr_foveation, R.string.vr_foveation_helper,
listOf(
@@ -784,6 +791,10 @@ class SettingsPage(
val FOVEATION_DEFAULT = FOVEATION_LEVELS.indexOf("medium")
val CONTROLLER_MODES = listOf("wii_remote", "gamepad", "none")
val INTERPOLATION_FPS = listOf(0L, 1L, 72L, 90L, 120L)
// [vr] refresh_rate choices, 0 being the headset's own rate.
val REFRESH_RATES = listOf(0L, 72L, 90L, 120L, 144L)
/** runtime_config.h's kVrRefreshRateDefault: 120 on the Steam Frame, the headset's own elsewhere. */
val REFRESH_RATE_DEFAULT = if (BuildConfig.STEAM_FRAME) 120L else 0L
val RESOLUTIONS = listOf(1.0, 1.5, 2.0, 3.0, 4.0)
val SUPPORTED_RESOLUTIONS = listOf(0.0, 1.0, 1.5, 2.0, 3.0, 4.0, 6.0, 8.0)
const val BLOOM_PATH = 0x10L
@@ -813,6 +824,10 @@ class SettingsPage(
config.integer("video", "disabled_post_processing_paths")
?.takeIf { it in 0L..UINT32_MAX && (it and BLOOM_PATH.inv()) == 0L } ?: BLOOM_PATH
/** vr.refresh_rate where IsSupportedVrRefreshRate accepts it, else the runtime's default. */
fun vrRefreshRate(config: TomlConfig): Long =
config.integer("vr", "refresh_rate")?.takeIf { it == 0L || it in 60L..240L } ?: REFRESH_RATE_DEFAULT
/** vr.frame_interpolation_fps, with the legacy frame_interpolation switch and NormalizeFrameInterpolationFps. */
fun vrInterpolationFps(config: TomlConfig): Long {
val value = config.integer("vr", "frame_interpolation_fps")?.takeIf { it in 0L..UINT32_MAX }
@@ -559,6 +559,9 @@
<string name="vr_performance_level_sustained_low">Sustained low</string>
<string name="vr_performance_level_power_savings">Power savings</string>
<string name="vr_performance_level_default">Headset default</string>
<string name="vr_refresh_rate">Headset refresh rate</string>
<string name="vr_refresh_rate_helper">The display rate asked of the headset. The game runs at 60 FPS, so 120 Hz shows every frame for exactly two refreshes, where 72 and 90 Hz hold some frames longer than others. A rate the headset does not offer leaves its own.</string>
<string name="vr_refresh_rate_headset">Headset\'s own</string>
<string name="vr_foveation">Foveated rendering</string>
<string name="vr_foveation_helper">Shades the edges of the race view in coarser blocks, where the lenses blur the picture anyway, to free GPU time for a higher render scale or a steadier frame rate. Higher levels start closer to the centre; High also coarsens the corners of the HUD. Menus are never foveated.</string>
<string name="vr_foveation_off">Off</string>