Add live FSR2 motion/jitter tuning controls and HUD readout

This commit is contained in:
Kelsi 2026-03-08 20:56:22 -07:00
parent 38c55e4f37
commit 2e71c768db
5 changed files with 65 additions and 6 deletions

View file

@ -274,6 +274,10 @@ public:
float getFSRSharpness() const { return fsr_.sharpness; }
void setFSR2Enabled(bool enabled);
bool isFSR2Enabled() const { return fsr2_.enabled; }
void setFSR2DebugTuning(float jitterSign, float motionVecScaleX, float motionVecScaleY);
float getFSR2JitterSign() const { return fsr2_.jitterSign; }
float getFSR2MotionVecScaleX() const { return fsr2_.motionVecScaleX; }
float getFSR2MotionVecScaleY() const { return fsr2_.motionVecScaleY; }
#if WOWEE_HAS_AMD_FSR2
bool isAmdFsr2SdkAvailable() const { return true; }
#else
@ -425,6 +429,9 @@ private:
uint32_t frameIndex = 0;
bool needsHistoryReset = true;
bool useAmdBackend = false;
float jitterSign = -1.0f;
float motionVecScaleX = 1.0f;
float motionVecScaleY = 1.0f;
#if WOWEE_HAS_AMD_FSR2
FfxFsr2Context amdContext{};
FfxFsr2Interface amdInterface{};

View file

@ -120,6 +120,9 @@ private:
int pendingUpscalingMode = 0; // 0=Off, 1=FSR1, 2=FSR2
int pendingFSRQuality = 0; // 0=UltraQuality, 1=Quality, 2=Balanced, 3=Performance
float pendingFSRSharpness = 0.5f;
float pendingFSR2JitterSign = -1.0f;
float pendingFSR2MotionVecScaleX = 1.0f;
float pendingFSR2MotionVecScaleY = 1.0f;
bool fsrSettingsApplied_ = false;
// UI element transparency (0.0 = fully transparent, 1.0 = fully opaque)

View file

@ -200,6 +200,13 @@ void PerformanceHUD::render(const Renderer* renderer, const Camera* camera) {
ImGui::Text(" %ux%u -> %ux%u (%.0f%%)", iw, ih, ext.width, ext.height, sf * 100.0f);
}
}
if (renderer->isFSR2Enabled()) {
ImGui::TextColored(ImVec4(0.4f, 0.9f, 1.0f, 1.0f), "FSR 2.2: ON");
ImGui::Text(" JitterSign=%.2f MVScale=(%.2f, %.2f)",
renderer->getFSR2JitterSign(),
renderer->getFSR2MotionVecScaleX(),
renderer->getFSR2MotionVecScaleY());
}
ImGui::Spacing();
}

View file

@ -4323,13 +4323,11 @@ void Renderer::dispatchAmdFsr2() {
L"FSR2_Output", FFX_RESOURCE_STATE_UNORDERED_ACCESS);
// Camera jitter is stored as NDC projection offsets; convert to render-pixel offsets.
// AMD jitter convention is opposite our projection offset sign in Vulkan space.
const float jitterSign = static_cast<float>(envIntOrDefault("WOWEE_FSR2_JITTER_SIGN", -1));
glm::vec2 jitterNdc = camera->getJitter();
desc.jitterOffset.x = jitterSign * jitterNdc.x * 0.5f * static_cast<float>(fsr2_.internalWidth);
desc.jitterOffset.y = jitterSign * jitterNdc.y * 0.5f * static_cast<float>(fsr2_.internalHeight);
desc.motionVectorScale.x = static_cast<float>(fsr2_.internalWidth);
desc.motionVectorScale.y = static_cast<float>(fsr2_.internalHeight);
desc.jitterOffset.x = fsr2_.jitterSign * jitterNdc.x * 0.5f * static_cast<float>(fsr2_.internalWidth);
desc.jitterOffset.y = fsr2_.jitterSign * jitterNdc.y * 0.5f * static_cast<float>(fsr2_.internalHeight);
desc.motionVectorScale.x = static_cast<float>(fsr2_.internalWidth) * fsr2_.motionVecScaleX;
desc.motionVectorScale.y = static_cast<float>(fsr2_.internalHeight) * fsr2_.motionVecScaleY;
desc.renderSize.width = fsr2_.internalWidth;
desc.renderSize.height = fsr2_.internalHeight;
desc.enableSharpening = false; // Keep existing RCAS post pass.
@ -4415,6 +4413,12 @@ void Renderer::setFSR2Enabled(bool enabled) {
}
}
void Renderer::setFSR2DebugTuning(float jitterSign, float motionVecScaleX, float motionVecScaleY) {
fsr2_.jitterSign = glm::clamp(jitterSign, -2.0f, 2.0f);
fsr2_.motionVecScaleX = glm::clamp(motionVecScaleX, -2.0f, 2.0f);
fsr2_.motionVecScaleY = glm::clamp(motionVecScaleY, -2.0f, 2.0f);
}
// ========================= End FSR 2.2 =========================
void Renderer::renderWorld(game::World* world, game::GameHandler* gameHandler) {

View file

@ -324,6 +324,7 @@ void GameScreen::render(game::GameHandler& gameHandler) {
static const float fsrScales[] = { 0.77f, 0.67f, 0.59f, 0.50f };
renderer->setFSRQuality(fsrScales[pendingFSRQuality]);
renderer->setFSRSharpness(pendingFSRSharpness);
renderer->setFSR2DebugTuning(pendingFSR2JitterSign, pendingFSR2MotionVecScaleX, pendingFSR2MotionVecScaleY);
// Safety fallback: persisted FSR2 can still hang on some systems during startup.
// Require explicit opt-in for startup FSR2; otherwise fall back to FSR1.
const bool allowStartupFsr2 = (std::getenv("WOWEE_ALLOW_STARTUP_FSR2") != nullptr);
@ -6345,6 +6346,37 @@ void GameScreen::renderSettingsWindow() {
if (renderer) renderer->setFSRSharpness(pendingFSRSharpness);
saveSettings();
}
if (fsrMode == 2) {
ImGui::SeparatorText("FSR2 Tuning");
if (ImGui::SliderFloat("Jitter Sign", &pendingFSR2JitterSign, -2.0f, 2.0f, "%.2f")) {
if (renderer) {
renderer->setFSR2DebugTuning(
pendingFSR2JitterSign,
pendingFSR2MotionVecScaleX,
pendingFSR2MotionVecScaleY);
}
saveSettings();
}
if (ImGui::SliderFloat("MV Scale X", &pendingFSR2MotionVecScaleX, -2.0f, 2.0f, "%.2f")) {
if (renderer) {
renderer->setFSR2DebugTuning(
pendingFSR2JitterSign,
pendingFSR2MotionVecScaleX,
pendingFSR2MotionVecScaleY);
}
saveSettings();
}
if (ImGui::SliderFloat("MV Scale Y", &pendingFSR2MotionVecScaleY, -2.0f, 2.0f, "%.2f")) {
if (renderer) {
renderer->setFSR2DebugTuning(
pendingFSR2JitterSign,
pendingFSR2MotionVecScaleX,
pendingFSR2MotionVecScaleY);
}
saveSettings();
}
ImGui::TextDisabled("Tip: default is jitter=-1, mv=(1,1).");
}
}
}
if (ImGui::SliderInt("Ground Clutter Density", &pendingGroundClutterDensity, 0, 150, "%d%%")) {
@ -7465,6 +7497,9 @@ void GameScreen::saveSettings() {
out << "fsr=" << (pendingFSR ? 1 : 0) << "\n";
out << "fsr_quality=" << pendingFSRQuality << "\n";
out << "fsr_sharpness=" << pendingFSRSharpness << "\n";
out << "fsr2_jitter_sign=" << pendingFSR2JitterSign << "\n";
out << "fsr2_mv_scale_x=" << pendingFSR2MotionVecScaleX << "\n";
out << "fsr2_mv_scale_y=" << pendingFSR2MotionVecScaleY << "\n";
// Controls
out << "mouse_sensitivity=" << pendingMouseSensitivity << "\n";
@ -7561,6 +7596,9 @@ void GameScreen::loadSettings() {
}
else if (key == "fsr_quality") pendingFSRQuality = std::clamp(std::stoi(val), 0, 3);
else if (key == "fsr_sharpness") pendingFSRSharpness = std::clamp(std::stof(val), 0.0f, 2.0f);
else if (key == "fsr2_jitter_sign") pendingFSR2JitterSign = std::clamp(std::stof(val), -2.0f, 2.0f);
else if (key == "fsr2_mv_scale_x") pendingFSR2MotionVecScaleX = std::clamp(std::stof(val), -2.0f, 2.0f);
else if (key == "fsr2_mv_scale_y") pendingFSR2MotionVecScaleY = std::clamp(std::stof(val), -2.0f, 2.0f);
// Controls
else if (key == "mouse_sensitivity") pendingMouseSensitivity = std::clamp(std::stof(val), 0.05f, 1.0f);
else if (key == "invert_mouse") pendingInvertMouse = (std::stoi(val) != 0);