From ba87e6e7b9422ca7aff53ab2a11778e030f395a2 Mon Sep 17 00:00:00 2001 From: doodlum <15017472+doodlum@users.noreply.github.com> Date: Thu, 30 Apr 2026 00:16:24 +0100 Subject: [PATCH 1/5] chore: shader compile settings for development --- src/Menu/AdvancedSettingsRenderer.cpp | 33 +++++++++++++++++++++++++++ src/State.cpp | 3 +++ src/State.h | 14 ++++++++++++ src/Utils/D3D.cpp | 9 ++++++++ 4 files changed, 59 insertions(+) diff --git a/src/Menu/AdvancedSettingsRenderer.cpp b/src/Menu/AdvancedSettingsRenderer.cpp index 85310a0ec4..db9282c1a5 100644 --- a/src/Menu/AdvancedSettingsRenderer.cpp +++ b/src/Menu/AdvancedSettingsRenderer.cpp @@ -659,6 +659,39 @@ void AdvancedSettingsRenderer::RenderDeveloperSection() ImGui::Text("Enable detailed frame annotations for debugging render passes and draw calls."); } + // Half-precision (partial precision) shader compile flag + if (ImGui::Checkbox("Half Precision (Partial Precision)", &globals::state->enablePartialPrecision)) { + // Force a recompile so the flag actually takes effect on subsequent shader builds. + globals::shaderCache->Clear(); + } + if (auto _tt = Util::HoverTooltipWrapper()) { + ImGui::Text( + "Adds D3DCOMPILE_PARTIAL_PRECISION to the shader compiler flags.\n" + "Lets fxc downgrade unmarked float ops to FP16 where it can prove safety, " + "on top of the existing min16float type hints.\n" + "On FP16-capable GPUs (Pascal+ / GCN+ / Skylake+) this can halve register " + "pressure and double ALU throughput, but it can also introduce minor visual " + "differences in shaders that haven't been audited for precision sensitivity.\n" + "Toggling this clears the shader cache and triggers a full recompile."); + } + + // Avoid flow control compiler flag (transient — not saved to config because the + // right setting depends on the current scene, not the user). + if (ImGui::Checkbox("Avoid Flow Control", &globals::state->enableAvoidFlowControl)) { + // Force a recompile so the flag actually takes effect on subsequent shader builds. + globals::shaderCache->Clear(); + } + if (auto _tt = Util::HoverTooltipWrapper()) { + ImGui::Text( + "Adds D3DCOMPILE_AVOID_FLOW_CONTROL to the shader compiler flags.\n" + "Forces fxc to flatten branches into predicated ops rather than emitting " + "dynamic flow control. Often a win for short branch bodies and uniformly-" + "taken branches; usually a loss for long divergent branches that vanilla " + "flow control would skip entirely.\n" + "Resets every launch. Toggling this clears the shader cache and triggers a " + "full recompile."); + } + ImGui::Spacing(); ImGui::Separator(); ImGui::Spacing(); diff --git a/src/State.cpp b/src/State.cpp index c0ba1574f4..c555406358 100644 --- a/src/State.cpp +++ b/src/State.cpp @@ -437,6 +437,7 @@ void State::SaveToJson(nlohmann::json& settings) advanced["Background Compiler Threads"] = shaderCache->backgroundCompilationThreadCount; advanced["Use FileWatcher"] = shaderCache->UseFileWatcher(); advanced["Frame Annotations"] = frameAnnotations; + advanced["Partial Precision"] = enablePartialPrecision; settings["Advanced"] = advanced; json general; @@ -511,6 +512,8 @@ void State::LoadFromJson(nlohmann::json& settings) shaderCache->SetFileWatcher(advanced["Use FileWatcher"]); if (advanced.contains("Frame Annotations") && advanced["Frame Annotations"].is_boolean()) frameAnnotations = advanced["Frame Annotations"]; + if (advanced.contains("Partial Precision") && advanced["Partial Precision"].is_boolean()) + enablePartialPrecision = advanced["Partial Precision"]; } if (settings.contains("General") && settings["General"].is_object()) { diff --git a/src/State.h b/src/State.h index f7877166d5..d11ddaa60a 100644 --- a/src/State.h +++ b/src/State.h @@ -141,6 +141,20 @@ class State bool frameAnnotations = false; + // Pass D3DCOMPILE_PARTIAL_PRECISION to fxc. With explicit min16float types this is + // mostly belt-and-braces in SM5, but it lets the compiler downgrade unmarked float + // ops to FP16 where it can prove safety. On by default; toggle off when reversing + // shaders or chasing a precision bug. + bool enablePartialPrecision = true; + + // Pass D3DCOMPILE_AVOID_FLOW_CONTROL to fxc. Forces the compiler to flatten branches + // into predicated ops instead of using dynamic flow control. Can win on uniform-branch + // or short-body branches; can lose on long divergent branches that vanilla flow + // control would skip. Transient (session-only); not saved to config because the + // right setting depends on the current scene/work, not the user. + bool enableAvoidFlowControl = false; + + uint lastVertexDescriptor = 0; uint lastPixelDescriptor = 0; uint modifiedVertexDescriptor = 0; diff --git a/src/Utils/D3D.cpp b/src/Utils/D3D.cpp index 042d2718b4..7e3f649ff9 100644 --- a/src/Utils/D3D.cpp +++ b/src/Utils/D3D.cpp @@ -193,6 +193,15 @@ namespace Util // Compiler setup uint32_t flags = !globals::state->IsDeveloperMode() ? (D3DCOMPILE_ENABLE_STRICTNESS | D3DCOMPILE_OPTIMIZATION_LEVEL3) : D3DCOMPILE_DEBUG; + if (globals::state->enablePartialPrecision) + flags |= D3DCOMPILE_PARTIAL_PRECISION; + if (globals::state->enableAvoidFlowControl) + flags |= D3DCOMPILE_AVOID_FLOW_CONTROL; + // Disk cache on = user is running shipped, known-good shaders — skip the fxc + // validation pass to trim compile time. Disk cache off = dev workflow, keep + // validation so malformed source produces a clean error instead of UB. + if (globals::shaderCache->IsDiskCache()) + flags |= D3DCOMPILE_SKIP_VALIDATION; ID3DBlob* shaderBlob; ID3DBlob* shaderErrors; From 18a2f8ddf678e50b05164aa908b4395457bfa50b Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 29 Apr 2026 23:17:22 +0000 Subject: [PATCH 2/5] =?UTF-8?q?style:=20=F0=9F=8E=A8=20apply=20pre-commit.?= =?UTF-8?q?ci=20formatting?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Automated formatting by clang-format, prettier, and other hooks. See https://pre-commit.ci for details. --- src/State.h | 1 - 1 file changed, 1 deletion(-) diff --git a/src/State.h b/src/State.h index d11ddaa60a..36949d1b68 100644 --- a/src/State.h +++ b/src/State.h @@ -154,7 +154,6 @@ class State // right setting depends on the current scene/work, not the user. bool enableAvoidFlowControl = false; - uint lastVertexDescriptor = 0; uint lastPixelDescriptor = 0; uint modifiedVertexDescriptor = 0; From 0bcc6c40d65cf0d451ec663562a357ee52f49bec Mon Sep 17 00:00:00 2001 From: doodlum <15017472+doodlum@users.noreply.github.com> Date: Thu, 30 Apr 2026 00:20:18 +0100 Subject: [PATCH 3/5] chore: disable half precision by default Changed enablePartialPrecision from true to false. --- src/State.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/State.h b/src/State.h index 36949d1b68..02ff2a6f7d 100644 --- a/src/State.h +++ b/src/State.h @@ -145,7 +145,7 @@ class State // mostly belt-and-braces in SM5, but it lets the compiler downgrade unmarked float // ops to FP16 where it can prove safety. On by default; toggle off when reversing // shaders or chasing a precision bug. - bool enablePartialPrecision = true; + bool enablePartialPrecision = false; // Pass D3DCOMPILE_AVOID_FLOW_CONTROL to fxc. Forces the compiler to flatten branches // into predicated ops instead of using dynamic flow control. Can win on uniform-branch From 066829fdb871427bbc664e45aabb38172d504323 Mon Sep 17 00:00:00 2001 From: doodlum <15017472+doodlum@users.noreply.github.com> Date: Thu, 30 Apr 2026 00:50:15 +0100 Subject: [PATCH 4/5] fix: fix compilation --- src/Utils/D3D.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Utils/D3D.cpp b/src/Utils/D3D.cpp index 7e3f649ff9..ecd02e2df9 100644 --- a/src/Utils/D3D.cpp +++ b/src/Utils/D3D.cpp @@ -1,6 +1,7 @@ #include "D3D.h" #include "Features/TerrainBlending.h" +#include "ShaderCache.h" #include "State.h" #include "Utils/Format.h" #include From 4719701d09d42fd64d0058bdbafac6a57fc26347 Mon Sep 17 00:00:00 2001 From: Alan Tse Date: Wed, 29 Apr 2026 18:42:46 -0700 Subject: [PATCH 5/5] fix: make compile-flag toggles thread-safe Compilation runs on a worker pool while the toggles are written from the UI thread; convert enablePartialPrecision and enableAvoidFlowControl to std::atomic_bool so the cross-thread access is well-defined. Co-Authored-By: Claude Opus 4.7 --- src/Menu/AdvancedSettingsRenderer.cpp | 8 ++++++-- src/State.cpp | 4 ++-- src/State.h | 7 +++++-- src/Utils/D3D.cpp | 4 ++-- 4 files changed, 15 insertions(+), 8 deletions(-) diff --git a/src/Menu/AdvancedSettingsRenderer.cpp b/src/Menu/AdvancedSettingsRenderer.cpp index db9282c1a5..03695094c5 100644 --- a/src/Menu/AdvancedSettingsRenderer.cpp +++ b/src/Menu/AdvancedSettingsRenderer.cpp @@ -660,7 +660,9 @@ void AdvancedSettingsRenderer::RenderDeveloperSection() } // Half-precision (partial precision) shader compile flag - if (ImGui::Checkbox("Half Precision (Partial Precision)", &globals::state->enablePartialPrecision)) { + bool partialPrecision = globals::state->enablePartialPrecision.load(std::memory_order_relaxed); + if (ImGui::Checkbox("Half Precision (Partial Precision)", &partialPrecision)) { + globals::state->enablePartialPrecision.store(partialPrecision, std::memory_order_relaxed); // Force a recompile so the flag actually takes effect on subsequent shader builds. globals::shaderCache->Clear(); } @@ -677,7 +679,9 @@ void AdvancedSettingsRenderer::RenderDeveloperSection() // Avoid flow control compiler flag (transient — not saved to config because the // right setting depends on the current scene, not the user). - if (ImGui::Checkbox("Avoid Flow Control", &globals::state->enableAvoidFlowControl)) { + bool avoidFlowControl = globals::state->enableAvoidFlowControl.load(std::memory_order_relaxed); + if (ImGui::Checkbox("Avoid Flow Control", &avoidFlowControl)) { + globals::state->enableAvoidFlowControl.store(avoidFlowControl, std::memory_order_relaxed); // Force a recompile so the flag actually takes effect on subsequent shader builds. globals::shaderCache->Clear(); } diff --git a/src/State.cpp b/src/State.cpp index c555406358..91c3e93256 100644 --- a/src/State.cpp +++ b/src/State.cpp @@ -437,7 +437,7 @@ void State::SaveToJson(nlohmann::json& settings) advanced["Background Compiler Threads"] = shaderCache->backgroundCompilationThreadCount; advanced["Use FileWatcher"] = shaderCache->UseFileWatcher(); advanced["Frame Annotations"] = frameAnnotations; - advanced["Partial Precision"] = enablePartialPrecision; + advanced["Partial Precision"] = enablePartialPrecision.load(std::memory_order_relaxed); settings["Advanced"] = advanced; json general; @@ -513,7 +513,7 @@ void State::LoadFromJson(nlohmann::json& settings) if (advanced.contains("Frame Annotations") && advanced["Frame Annotations"].is_boolean()) frameAnnotations = advanced["Frame Annotations"]; if (advanced.contains("Partial Precision") && advanced["Partial Precision"].is_boolean()) - enablePartialPrecision = advanced["Partial Precision"]; + enablePartialPrecision.store(advanced["Partial Precision"].get(), std::memory_order_relaxed); } if (settings.contains("General") && settings["General"].is_object()) { diff --git a/src/State.h b/src/State.h index 02ff2a6f7d..16018dda7f 100644 --- a/src/State.h +++ b/src/State.h @@ -5,6 +5,7 @@ #include #include +#include #include #include @@ -145,14 +146,16 @@ class State // mostly belt-and-braces in SM5, but it lets the compiler downgrade unmarked float // ops to FP16 where it can prove safety. On by default; toggle off when reversing // shaders or chasing a precision bug. - bool enablePartialPrecision = false; + // Atomic: written from the UI thread, read from compilation pool workers. + std::atomic_bool enablePartialPrecision{ false }; // Pass D3DCOMPILE_AVOID_FLOW_CONTROL to fxc. Forces the compiler to flatten branches // into predicated ops instead of using dynamic flow control. Can win on uniform-branch // or short-body branches; can lose on long divergent branches that vanilla flow // control would skip. Transient (session-only); not saved to config because the // right setting depends on the current scene/work, not the user. - bool enableAvoidFlowControl = false; + // Atomic: written from the UI thread, read from compilation pool workers. + std::atomic_bool enableAvoidFlowControl{ false }; uint lastVertexDescriptor = 0; uint lastPixelDescriptor = 0; diff --git a/src/Utils/D3D.cpp b/src/Utils/D3D.cpp index ecd02e2df9..202e78467e 100644 --- a/src/Utils/D3D.cpp +++ b/src/Utils/D3D.cpp @@ -194,9 +194,9 @@ namespace Util // Compiler setup uint32_t flags = !globals::state->IsDeveloperMode() ? (D3DCOMPILE_ENABLE_STRICTNESS | D3DCOMPILE_OPTIMIZATION_LEVEL3) : D3DCOMPILE_DEBUG; - if (globals::state->enablePartialPrecision) + if (globals::state->enablePartialPrecision.load(std::memory_order_relaxed)) flags |= D3DCOMPILE_PARTIAL_PRECISION; - if (globals::state->enableAvoidFlowControl) + if (globals::state->enableAvoidFlowControl.load(std::memory_order_relaxed)) flags |= D3DCOMPILE_AVOID_FLOW_CONTROL; // Disk cache on = user is running shipped, known-good shaders — skip the fxc // validation pass to trim compile time. Disk cache off = dev workflow, keep