mirror of
https://github.com/mitch030504/Wiicompiled_VR_Frame.git
synced 2026-10-06 10:00:27 +02:00
Repeat the last frame on every refresh the game has no new frame for
SteamVR on the Steam Frame ran the game at half the 120 Hz display rate, since render-first pacing submits only when a game frame is sealed, and filled every other refresh itself even with Motion Smoothing off, which doubled the HUD and the menu screen while the head turned. With the new [vr] repeat_frames (default on for the Frame, off elsewhere, live), the pacing thread waits a millisecond for the eyes and otherwise spends the refresh on a keep-alive cycle that resubmits the retained layer with its rendered poses, paced by xrWaitFrame. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019HBRGKTE1GnN2ah8gcZKr3
This commit is contained in:
6 files changed
+77
-5
No files matched your search
@@ -157,6 +157,7 @@ constexpr std::array<const char*, 4> kVrFoveationLabels{"Off", "Low", "Medium",
|
||||
static_assert(kVrFoveationLabels.size() == RuntimeConfigFile::kVrFoveationLevels.size());
|
||||
int g_vrFoveation = static_cast<int>(RuntimeConfigFile::VrFoveationLevelIndex(RuntimeConfigFile::VrFoveation()));
|
||||
bool g_vrEyeTrackedFoveation = RuntimeConfigFile::VrEyeTrackedFoveation();
|
||||
bool g_vrRepeatFrames = RuntimeConfigFile::VrRepeatFrames();
|
||||
#endif
|
||||
bool g_vrFirstPerson = RuntimeConfigFile::VrFirstPerson(false);
|
||||
bool g_vrFirstPersonToggleClick = RuntimeConfigFile::VrFirstPersonToggleClick();
|
||||
@@ -1557,6 +1558,16 @@ void DrawVrSettings() {
|
||||
"immediately.");
|
||||
}
|
||||
}
|
||||
if (ImGui::Checkbox("Repeat frames at the headset's rate", &g_vrRepeatFrames)) {
|
||||
RuntimeConfigFile::SetVrRepeatFrames(g_vrRepeatFrames);
|
||||
}
|
||||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::SetTooltip(
|
||||
"Shows the last frame again, turned to where you now look, on each refresh the game has "
|
||||
"no new frame for. The headset's runtime then does not drop the game to half its rate and "
|
||||
"fill the gaps itself, which doubles the HUD and the menu screen as you turn your head "
|
||||
"(SteamVR on the Steam Frame). 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)];
|
||||
|
||||
@@ -710,6 +710,9 @@ private:
|
||||
// Skipped eye copies tolerated back to back before the session is given up: a few seconds
|
||||
// at the headset's refresh rate.
|
||||
static constexpr uint32_t kMaxConsecutiveSkips = 300;
|
||||
// With [vr] repeat_frames, how long render-first pacing waits for the eyes before it spends the
|
||||
// next display refresh on the retained layer. The repeat's xrWaitFrame does the actual pacing.
|
||||
static constexpr uint32_t kRepeatFramePollMs = 1;
|
||||
|
||||
static float ClampRenderScale(float scale) noexcept {
|
||||
return std::clamp(scale, RuntimeConfigFile::kVrRenderScaleMin, RuntimeConfigFile::kVrRenderScaleMax);
|
||||
@@ -1335,13 +1338,17 @@ private:
|
||||
aurora_notify_stereo_frame();
|
||||
|
||||
// Aurora renders the eyes at its next seal. Meanwhile the compositor keeps showing the
|
||||
// retained layer; a 50 ms stall repeats it explicitly and withdraws the packet.
|
||||
// retained layer; a 50 ms stall repeats it explicitly and withdraws the packet. With
|
||||
// [vr] repeat_frames the retained layer is also submitted for every display refresh the
|
||||
// eyes are not ready for, each cycle paced by xrWaitFrame, so the runtime sees the app at
|
||||
// the display's rate rather than the game's and never fills refreshes in itself.
|
||||
const uint32_t wait_ms = RuntimeConfigFile::VrRepeatFrames() ? kRepeatFramePollMs : 50;
|
||||
OpenXRSubmissionStatus submission = OpenXRSubmissionStatus::Timeout;
|
||||
bool canceled_before_encode = false;
|
||||
const auto cancel_after = std::chrono::steady_clock::now() + std::chrono::milliseconds(50);
|
||||
while (!stop_.load(std::memory_order_acquire) && submission == OpenXRSubmissionStatus::Timeout) {
|
||||
submission = diagnostics::Measure(diagnostics::Stage::SubmissionWait, [&] {
|
||||
return backend_->WaitForSubmission(packet, 50);
|
||||
return backend_->WaitForSubmission(packet, wait_ms);
|
||||
});
|
||||
if (submission == OpenXRSubmissionStatus::Timeout) {
|
||||
if (std::chrono::steady_clock::now() >= cancel_after) {
|
||||
|
||||
Reference in new issue
Block a user