mirror of
https://github.com/mitch030504/Wiicompiled_VR_Frame.git
synced 2026-10-06 00:00:17 +02:00
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:
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>
|
||||
|
||||
@@ -63,6 +63,7 @@ struct RuntimeUserConfig {
|
||||
std::optional<std::string> vrMirrorView;
|
||||
std::optional<std::string> vrControllerMode;
|
||||
std::optional<uint32_t> vrFrameInterpolationFps;
|
||||
std::optional<uint32_t> vrRefreshRate;
|
||||
std::optional<bool> vrFirstPerson;
|
||||
std::optional<bool> vrFirstPersonToggleClick;
|
||||
std::optional<float> vrFirstPersonUnitsPerMeter;
|
||||
@@ -281,6 +282,25 @@ inline bool IsSupportedVrPerformanceLevel(std::string_view value) {
|
||||
return value == "default" || value == "power_savings" || value == "sustained_low" ||
|
||||
value == "sustained_high" || value == "boost";
|
||||
}
|
||||
// The display refresh rate asked of the OpenXR runtime (XR_FB_display_refresh_rate), in Hz, each
|
||||
// time the session starts and whenever the setting changes; 0 leaves the headset's own rate. 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 starts at 120; elsewhere the
|
||||
// headset's own setting stays in charge. A runtime without the extension, or one that declines the
|
||||
// rate, keeps its own.
|
||||
#if defined(MKW_HEADSET_STEAM_FRAME)
|
||||
inline constexpr uint32_t kVrRefreshRateDefault = 120;
|
||||
#define MKW_VR_REFRESH_RATE_DEFAULT_TEXT "120"
|
||||
#else
|
||||
inline constexpr uint32_t kVrRefreshRateDefault = 0;
|
||||
#define MKW_VR_REFRESH_RATE_DEFAULT_TEXT "0"
|
||||
#endif
|
||||
inline constexpr uint32_t kVrRefreshRateMin = 60;
|
||||
inline constexpr uint32_t kVrRefreshRateMax = 240;
|
||||
|
||||
inline bool IsSupportedVrRefreshRate(uint32_t value) {
|
||||
return value == 0 || (value >= kVrRefreshRateMin && value <= kVrRefreshRateMax);
|
||||
}
|
||||
// Fixed foveated rendering of the immersive eyes on the Quest, in the order of
|
||||
// aurora_set_stereo_foveation's levels: the periphery is shaded in 2x2, then
|
||||
// 4x4 pixel blocks, the higher the level the closer to the centre. Whether the
|
||||
@@ -545,6 +565,11 @@ inline void EnsureConfigFile() {
|
||||
"controller_mode = \"wii_remote\"\n"
|
||||
"# VR interpolation: 0 = Off, 1 = Auto, or 72/90/120 FPS. Live.\n"
|
||||
"frame_interpolation_fps = 0\n"
|
||||
"# Display refresh rate asked of the headset, in Hz (72, 90, 120,\n"
|
||||
"# 144, ...), or 0 to leave the headset's own setting. The game runs\n"
|
||||
"# at 60, so 120 shows every frame twice. Only runtimes that let apps\n"
|
||||
"# choose (XR_FB_display_refresh_rate) take it. Live.\n"
|
||||
"refresh_rate = " MKW_VR_REFRESH_RATE_DEFAULT_TEXT "\n"
|
||||
"render_scale = " MKW_VR_RENDER_SCALE_DEFAULT_TEXT "\n"
|
||||
"world_units_per_meter = 500.0\n"
|
||||
"hud_distance_meters = 2.0\n"
|
||||
@@ -872,6 +897,9 @@ inline RuntimeUserConfig ParseConfigDocument(const toml::value& document) {
|
||||
value && IsSupportedVrControllerMode(*value)) {
|
||||
config.vrControllerMode = *value;
|
||||
}
|
||||
if (auto value = FindConfigUint(document, "vr", "refresh_rate"); value && IsSupportedVrRefreshRate(*value)) {
|
||||
config.vrRefreshRate = *value;
|
||||
}
|
||||
config.vrFrameInterpolationFps = FindConfigValue<uint32_t>(document, "vr", "frame_interpolation_fps");
|
||||
if (!config.vrFrameInterpolationFps) {
|
||||
// Migrate the initial experimental checkbox to Auto.
|
||||
@@ -1241,6 +1269,14 @@ inline bool SetVrFrameInterpolationFps(uint32_t value) {
|
||||
return WriteSetting("vr", "frame_interpolation_fps", std::to_string(value));
|
||||
}
|
||||
|
||||
inline bool SetVrRefreshRate(uint32_t value) {
|
||||
if (!IsSupportedVrRefreshRate(value)) {
|
||||
return false;
|
||||
}
|
||||
Mutable().vrRefreshRate = value;
|
||||
return WriteSetting("vr", "refresh_rate", std::to_string(value));
|
||||
}
|
||||
|
||||
inline bool SetVrFirstPersonRotation(std::string value) {
|
||||
if (!IsSupportedVrFirstPersonRotation(value)) {
|
||||
return false;
|
||||
@@ -1743,6 +1779,11 @@ inline uint32_t VrFrameInterpolationFps() {
|
||||
return mkw::vr::NormalizeFrameInterpolationFps(Get().vrFrameInterpolationFps.value_or(0));
|
||||
}
|
||||
|
||||
inline uint32_t VrRefreshRate(uint32_t fallback = kVrRefreshRateDefault) {
|
||||
const uint32_t value = Get().vrRefreshRate.value_or(fallback);
|
||||
return IsSupportedVrRefreshRate(value) ? value : 0;
|
||||
}
|
||||
|
||||
inline bool DiagnosticsOpenXRLogging(bool fallback = false) {
|
||||
return Get().diagnosticsOpenXRLogging.value_or(fallback);
|
||||
}
|
||||
|
||||
@@ -9,6 +9,21 @@ inline uint32_t NormalizeFrameInterpolationFps(uint32_t value) noexcept {
|
||||
return value == 1 || value == 72 || value == 90 || value == 120 ? value : 0;
|
||||
}
|
||||
|
||||
// The display refresh rate to ask the runtime for ([vr] refresh_rate): the one it lists within half
|
||||
// a hertz of `requested` (runtimes report 119.9 or 120.00001 for 120), or 0 when none is close.
|
||||
inline float MatchDisplayRefreshRate(const float* rates, uint32_t count, float requested) noexcept {
|
||||
float best = 0.0f;
|
||||
float best_distance = 0.5f;
|
||||
for (uint32_t i = 0; i < count; ++i) {
|
||||
const float distance = rates[i] > requested ? rates[i] - requested : requested - rates[i];
|
||||
if (rates[i] > 0.0f && distance <= best_distance) {
|
||||
best = rates[i];
|
||||
best_distance = distance;
|
||||
}
|
||||
}
|
||||
return best;
|
||||
}
|
||||
|
||||
// A render-rate ceiling on the compositor's own display-time grid. Auto (1)
|
||||
// renders every tick. Fixed targets cannot increase the physical refresh rate.
|
||||
class FrameInterpolationPacing {
|
||||
|
||||
@@ -187,6 +187,9 @@ int g_vrFrameInterpolationMode = [] {
|
||||
return static_cast<int>(std::find(kVrInterpolationFps.begin(), kVrInterpolationFps.end(), value) -
|
||||
kVrInterpolationFps.begin());
|
||||
}();
|
||||
// [vr] refresh_rate choices; a value set in Config.toml outside them is shown as it is.
|
||||
constexpr std::array<uint32_t, 5> kVrRefreshRates{0, 72, 90, 120, 144};
|
||||
uint32_t g_vrRefreshRate = RuntimeConfigFile::VrRefreshRate();
|
||||
int g_vrFirstPersonHiddenModel = RuntimeConfigFile::VrFirstPersonHiddenModel();
|
||||
bool g_openxrDiagnosticsLogging = RuntimeConfigFile::DiagnosticsOpenXRLogging(false);
|
||||
bool g_firstPersonDiagnosticsLogging = RuntimeConfigFile::DiagnosticsFirstPersonLogging(false);
|
||||
@@ -1517,6 +1520,29 @@ void DrawVrSettings() {
|
||||
"off, or without a GPU that supports it: a new level applies after a restart.");
|
||||
}
|
||||
#endif
|
||||
{
|
||||
const auto rateLabel = [](uint32_t hz) {
|
||||
return hz == 0 ? std::string("Headset's own") : std::to_string(hz) + " Hz";
|
||||
};
|
||||
if (ImGui::BeginCombo("Headset refresh rate", rateLabel(g_vrRefreshRate).c_str())) {
|
||||
for (const uint32_t hz : kVrRefreshRates) {
|
||||
if (ImGui::Selectable(rateLabel(hz).c_str(), hz == g_vrRefreshRate) && hz != g_vrRefreshRate) {
|
||||
g_vrRefreshRate = hz;
|
||||
// The XR thread follows the setting and asks the runtime for it.
|
||||
RuntimeConfigFile::SetVrRefreshRate(hz);
|
||||
}
|
||||
}
|
||||
ImGui::EndCombo();
|
||||
}
|
||||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::SetTooltip(
|
||||
"Asks the headset for this display rate. 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. "
|
||||
"Only runtimes that let apps choose (XR_FB_display_refresh_rate: the Quest, the Steam "
|
||||
"Frame, Virtual Desktop) take it; the Headset line below shows the rate in use. Applies "
|
||||
"immediately.");
|
||||
}
|
||||
}
|
||||
if (ImGui::Combo("VR frame interpolation (experimental)", &g_vrFrameInterpolationMode,
|
||||
kVrInterpolationLabels.data(), static_cast<int>(kVrInterpolationLabels.size()))) {
|
||||
const auto target = kVrInterpolationFps[static_cast<size_t>(g_vrFrameInterpolationMode)];
|
||||
@@ -1526,7 +1552,7 @@ void DrawVrSettings() {
|
||||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::SetTooltip(
|
||||
"Auto matches the headset refresh rate. 72, 90 and 120 cap the scene rendering rate; "
|
||||
"set the headset's refresh rate in Virtual Desktop or your VR runtime. "
|
||||
"set the headset's refresh rate above, or in Virtual Desktop or your VR runtime. "
|
||||
"The game stays at 60 Hz. Adds one game frame of scene latency; head tracking stays current. "
|
||||
"Needs GPU headroom and may show interpolation artifacts. Applies immediately.");
|
||||
}
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
|
||||
#if defined(MKW_ENABLE_OPENXR)
|
||||
#include "vr/openxr_backend.h"
|
||||
@@ -446,6 +447,8 @@ public:
|
||||
#endif
|
||||
if (has_extension("XR_FB_display_refresh_rate")) {
|
||||
runtime_->LoadFunction("xrGetDisplayRefreshRateFB", &get_display_refresh_rate_);
|
||||
runtime_->LoadFunction("xrEnumerateDisplayRefreshRatesFB", &enumerate_refresh_rates_);
|
||||
runtime_->LoadFunction("xrRequestDisplayRefreshRateFB", &request_refresh_rate_);
|
||||
}
|
||||
if (has_extension("XR_EXT_performance_settings")) {
|
||||
runtime_->LoadFunction("xrPerfSettingsSetPerformanceLevelEXT", &set_performance_level_);
|
||||
@@ -576,6 +579,8 @@ public:
|
||||
prepared_ = false;
|
||||
convert_display_time_ = nullptr;
|
||||
get_display_refresh_rate_ = nullptr;
|
||||
enumerate_refresh_rates_ = nullptr;
|
||||
request_refresh_rate_ = nullptr;
|
||||
set_performance_level_ = nullptr;
|
||||
headset_hz_.store(0, std::memory_order_relaxed);
|
||||
rendered_fps_.store(0, std::memory_order_relaxed);
|
||||
@@ -590,6 +595,10 @@ public:
|
||||
ResetTrackingOrigin();
|
||||
applied_session_run_serial_ = 0;
|
||||
session_was_active_ = false;
|
||||
refresh_rate_session_serial_ = 0;
|
||||
requested_refresh_rate_ = 0;
|
||||
session_start_refresh_rate_ = 0.0f;
|
||||
refresh_rate_changed_ = false;
|
||||
}
|
||||
|
||||
bool IsRunning() const noexcept { return running_.load(std::memory_order_acquire); }
|
||||
@@ -797,6 +806,70 @@ private:
|
||||
<< (XR_SUCCEEDED(gpu) ? "set" : "refused") << " (" << gpu << ")" << std::endl;
|
||||
}
|
||||
|
||||
// [vr] refresh_rate (XR_FB_display_refresh_rate), asked of the runtime each time the session
|
||||
// starts running and whenever the setting changes. The game renders 60 frames a second, so a
|
||||
// display at 120 Hz shows each one for exactly two refreshes. 0 gives back the rate the session
|
||||
// started at, if this changed it. A rate the runtime does not list, or declines (SteamVR may),
|
||||
// is logged and the runtime keeps its own.
|
||||
void ApplyRefreshRate(uint32_t requested, bool session_started) {
|
||||
if (runtime_ == nullptr || !runtime_->HasSession()) {
|
||||
return;
|
||||
}
|
||||
if (session_started) {
|
||||
session_start_refresh_rate_ = 0.0f;
|
||||
refresh_rate_changed_ = false;
|
||||
if (get_display_refresh_rate_ != nullptr &&
|
||||
XR_FAILED(get_display_refresh_rate_(runtime_->Session(), &session_start_refresh_rate_))) {
|
||||
session_start_refresh_rate_ = 0.0f;
|
||||
}
|
||||
}
|
||||
float target = static_cast<float>(requested);
|
||||
if (requested == 0) {
|
||||
if (!refresh_rate_changed_ || !(session_start_refresh_rate_ > 0.0f)) {
|
||||
return;
|
||||
}
|
||||
target = session_start_refresh_rate_;
|
||||
}
|
||||
if (enumerate_refresh_rates_ == nullptr || request_refresh_rate_ == nullptr) {
|
||||
RT_LOG(RT_TAG_RUNTIME) << "OpenXR: display refresh rate " << target
|
||||
<< " Hz not requested: the runtime does not offer XR_FB_display_refresh_rate"
|
||||
<< std::endl;
|
||||
return;
|
||||
}
|
||||
uint32_t count = 0;
|
||||
XrResult result = enumerate_refresh_rates_(runtime_->Session(), 0, &count, nullptr);
|
||||
std::vector<float> rates;
|
||||
if (XR_SUCCEEDED(result) && count > 0) {
|
||||
rates.resize(count);
|
||||
result = enumerate_refresh_rates_(runtime_->Session(), count, &count, rates.data());
|
||||
rates.resize(XR_SUCCEEDED(result) ? std::min<size_t>(count, rates.size()) : 0);
|
||||
}
|
||||
if (XR_FAILED(result) || rates.empty()) {
|
||||
RT_LOG(RT_TAG_RUNTIME) << "OpenXR: display refresh rate " << target
|
||||
<< " Hz not requested: the runtime lists no rates (" << result << ")" << std::endl;
|
||||
return;
|
||||
}
|
||||
std::ostringstream available;
|
||||
for (size_t i = 0; i < rates.size(); ++i) {
|
||||
available << (i == 0 ? "" : "/") << rates[i];
|
||||
}
|
||||
const float rate = MatchDisplayRefreshRate(rates.data(), static_cast<uint32_t>(rates.size()), target);
|
||||
if (rate == 0.0f) {
|
||||
RT_LOG(RT_TAG_RUNTIME) << "OpenXR: display refresh rate " << target
|
||||
<< " Hz is not offered (available " << available.str()
|
||||
<< " Hz); keeping the runtime's" << std::endl;
|
||||
return;
|
||||
}
|
||||
const XrResult set = request_refresh_rate_(runtime_->Session(), rate);
|
||||
if (XR_SUCCEEDED(set)) {
|
||||
refresh_rate_changed_ = requested != 0;
|
||||
}
|
||||
RT_LOG(RT_TAG_RUNTIME) << "OpenXR: display refresh rate " << rate << " Hz "
|
||||
<< (XR_SUCCEEDED(set) ? "requested" : "refused") << " (" << set << "; available "
|
||||
<< available.str() << " Hz, session started at " << session_start_refresh_rate_
|
||||
<< " Hz)" << std::endl;
|
||||
}
|
||||
|
||||
static bool ProvideStereoFrame(uint32_t, AuroraStereoFrame* output, void* userdata) {
|
||||
auto* self = static_cast<OpenXRIntegration*>(userdata);
|
||||
if (self == nullptr || output == nullptr) {
|
||||
@@ -894,6 +967,14 @@ private:
|
||||
WaitForStopOrDelay(std::chrono::milliseconds(5));
|
||||
continue;
|
||||
}
|
||||
// The configured refresh rate, at each session start and whenever it changes.
|
||||
if (const uint32_t refresh_rate = RuntimeConfigFile::VrRefreshRate();
|
||||
session_run_serial != refresh_rate_session_serial_ || refresh_rate != requested_refresh_rate_) {
|
||||
const bool session_started = session_run_serial != refresh_rate_session_serial_;
|
||||
refresh_rate_session_serial_ = session_run_serial;
|
||||
requested_refresh_rate_ = refresh_rate;
|
||||
ApplyRefreshRate(refresh_rate, session_started);
|
||||
}
|
||||
|
||||
const MkwVRPolicySnapshot policy = MkwVRPolicyGetSnapshot();
|
||||
aurora_set_stereo_motion_logging(diagnostics::Enabled());
|
||||
@@ -1874,7 +1955,15 @@ private:
|
||||
std::chrono::steady_clock::time_point timing_start_ = std::chrono::steady_clock::now();
|
||||
uint32_t timing_submissions_ = 0;
|
||||
PFN_xrGetDisplayRefreshRateFB get_display_refresh_rate_ = nullptr;
|
||||
PFN_xrEnumerateDisplayRefreshRatesFB enumerate_refresh_rates_ = nullptr;
|
||||
PFN_xrRequestDisplayRefreshRateFB request_refresh_rate_ = nullptr;
|
||||
PFN_xrPerfSettingsSetPerformanceLevelEXT set_performance_level_ = nullptr;
|
||||
// [vr] refresh_rate as last applied, the session run it was applied in, and the rate that run
|
||||
// started at (pacing thread).
|
||||
uint64_t refresh_rate_session_serial_ = 0;
|
||||
uint32_t requested_refresh_rate_ = 0;
|
||||
float session_start_refresh_rate_ = 0.0f;
|
||||
bool refresh_rate_changed_ = false;
|
||||
#if defined(_WIN32)
|
||||
using ConvertDisplayTime = XrResult (XRAPI_PTR*)(XrInstance, XrTime, LARGE_INTEGER*);
|
||||
#else
|
||||
|
||||
@@ -12,6 +12,13 @@ static void Require(bool condition) {
|
||||
}
|
||||
|
||||
int main() {
|
||||
// [vr] refresh_rate picks the runtime's own value for the rate asked.
|
||||
const float frame_rates[] = {72.0f, 90.0f, 119.98f, 144.0f};
|
||||
Require(mkw::vr::MatchDisplayRefreshRate(frame_rates, 4, 120.0f) == 119.98f);
|
||||
Require(mkw::vr::MatchDisplayRefreshRate(frame_rates, 4, 90.0f) == 90.0f);
|
||||
Require(mkw::vr::MatchDisplayRefreshRate(frame_rates, 4, 60.0f) == 0.0f);
|
||||
Require(mkw::vr::MatchDisplayRefreshRate(frame_rates, 4, 100.0f) == 0.0f);
|
||||
Require(mkw::vr::MatchDisplayRefreshRate(frame_rates, 0, 120.0f) == 0.0f);
|
||||
for (uint32_t target : {0u, 1u, 72u, 90u, 120u}) {
|
||||
std::istringstream input("[vr]\nframe_interpolation_fps = " + std::to_string(target) + "\n");
|
||||
const auto config = RuntimeConfigFile::ParseConfig(input);
|
||||
|
||||
@@ -50,6 +50,24 @@ int main() {
|
||||
Require(RuntimeConfigFile::VrFoveationLevelIndex("high") == 3);
|
||||
Require(RuntimeConfigFile::VrFoveationLevelIndex("ultra") == 0);
|
||||
|
||||
// [vr] refresh_rate: Hz asked of the runtime, 0 leaving its own. The Steam Frame
|
||||
// starts at 120, twice the game's 60.
|
||||
Require(Parse("[vr]\nrefresh_rate = 120\n").vrRefreshRate == 120u);
|
||||
Require(Parse("[vr]\nrefresh_rate = 0\n").vrRefreshRate == 0u);
|
||||
Require(Parse("[vr]\nrefresh_rate = 144\n").vrRefreshRate == 144u);
|
||||
Require(!Parse("[vr]\nrefresh_rate = 30\n").vrRefreshRate.has_value());
|
||||
Require(!Parse("[vr]\nrefresh_rate = 500\n").vrRefreshRate.has_value());
|
||||
Require(!Parse("[vr]\nrefresh_rate = -1\n").vrRefreshRate.has_value());
|
||||
Require(!Parse("[vr]\nrefresh_rate = \"120\"\n").vrRefreshRate.has_value());
|
||||
Require(!Parse("[vr]\n").vrRefreshRate.has_value());
|
||||
#if defined(MKW_HEADSET_STEAM_FRAME)
|
||||
Require(RuntimeConfigFile::kVrRefreshRateDefault == 120u);
|
||||
Require(std::string_view(MKW_VR_REFRESH_RATE_DEFAULT_TEXT) == "120");
|
||||
#else
|
||||
Require(RuntimeConfigFile::kVrRefreshRateDefault == 0u);
|
||||
Require(std::string_view(MKW_VR_REFRESH_RATE_DEFAULT_TEXT) == "0");
|
||||
#endif
|
||||
|
||||
// [vr] hand_tracking: the cockpit hands follow the headset's hand tracking.
|
||||
Require(Parse("[vr]\nhand_tracking = true\n").vrHandTracking == true);
|
||||
Require(Parse("[vr]\nhand_tracking = false\n").vrHandTracking == false);
|
||||
|
||||
Reference in new issue
Block a user