Files
d4r/patches/optiscaler/0001-proton-external-dlss-fsr4-coexistence.patch
T
ayo cb08e1c313 Fix OptiScaler NGX routing and align marker polling defaults
- Explicitly route OptiScaler to d4r\nvngx.dll in release packages.

- Extract INI generation into a helper that preserves line endings
  and rejects missing or duplicate settings.

- Check NGX routing separately from file presence and return failure
  when the installation is incomplete or misconfigured.

- Add an optional OptiScaler patch for external DLSS backends while
  preserving AMD identity for FSR4, with matching launch guidance.

- Align portable and launcher marker polling defaults at 200 us.

- Log when d4r's model override replaces game or OptiScaler presets.

- Add configuration, package, routing and coexistence regression tests.

- Update installation documentation, add FSR/DLSS comparison videos
  and ignore local .tools artifacts.

Refs: #7, #14
2026-10-02 16:32:49 -04:00

206 lines
9.4 KiB
Diff

diff --git a/OptiScaler.ini b/OptiScaler.ini
index a9b7a88..adbb206 100644
--- a/OptiScaler.ini
+++ b/OptiScaler.ini
@@ -612,6 +612,11 @@ FsrAgilitySDKUpgrade=auto
; true or false - Default (auto) is true
Enabled=auto
+; Permit an explicitly configured external NGX shim on non-Nvidia hardware.
+; NvngxPath must name an existing DLL file; keep physical GPU identity for FSR4.
+; false by default; this does not make Nvidia's driver NGX core work on AMD.
+AllowExternalBackend=false
+
; Set this to true to enable custom render preset overrides
; true or false - Default (auto) is false
RenderPresetOverride=auto
diff --git a/OptiScaler/Config.cpp b/OptiScaler/Config.cpp
index d0265c4..5403430 100644
--- a/OptiScaler/Config.cpp
+++ b/OptiScaler/Config.cpp
@@ -263,6 +263,7 @@ bool Config::Reload(std::filesystem::path iniPath)
{
// Don't enable again if set false because of no nvngx found
DLSSEnabled.set_from_config(readBool("DLSS", "Enabled"));
+ DLSSAllowExternalBackend.set_from_config(readBool("DLSS", "AllowExternalBackend"));
UseGenericAppIdWithDlss.set_from_config(readBool("DLSS", "UseGenericAppIdWithDlss"));
RenderPresetOverride.set_from_config(readBool("DLSS", "RenderPresetOverride"));
@@ -998,6 +999,8 @@ bool Config::SaveIni()
// DLSS
{
ini.SetValue("DLSS", "Enabled", GetBoolValue(Instance()->DLSSEnabled.value_for_config()).c_str());
+ ini.SetValue("DLSS", "AllowExternalBackend",
+ GetBoolValue(Instance()->DLSSAllowExternalBackend.value_for_config()).c_str());
ini.SetValue("DLSS", "RenderPresetOverride",
GetBoolValue(Instance()->RenderPresetOverride.value_for_config()).c_str());
ini.SetValue("DLSS", "RenderPresetForAll",
diff --git a/OptiScaler/Config.h b/OptiScaler/Config.h
index d7909b7..0225c87 100644
--- a/OptiScaler/Config.h
+++ b/OptiScaler/Config.h
@@ -218,6 +218,7 @@ class Config
// DLSS
CustomOptional<bool> DLSSEnabled { true };
+ CustomOptional<bool> DLSSAllowExternalBackend { false };
CustomOptional<bool> RenderPresetOverride { false };
CustomOptional<uint32_t> RenderPresetForAll { 0 };
CustomOptional<uint32_t> RenderPresetDLAA { 0 };
diff --git a/OptiScaler/dllmain.cpp b/OptiScaler/dllmain.cpp
index 7580c65..e5f047c 100644
--- a/OptiScaler/dllmain.cpp
+++ b/OptiScaler/dllmain.cpp
@@ -1,4 +1,5 @@
#include "pch.h"
+#include "spoofing/BackendIdentity.h"
#include "dllmain.h"
#include "Util.h"
@@ -1977,9 +1978,29 @@ BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserv
spdlog::info("");
State::Instance().isRunningOnNvidia = isNvidia();
- if (State::Instance().isRunningOnNvidia)
+ // External NGX backends (e.g. d4r) do not require a physical Nvidia GPU.
+ // Keep isRunningOnNvidia truthful so FSR4 and other hardware checks remain valid.
+ bool externalBackendFile = false;
+ if (Config::Instance()->DLSSAllowExternalBackend.value_or_default() &&
+ Config::Instance()->NvngxPath.has_value())
+ {
+ auto backendPath = std::filesystem::path(Config::Instance()->NvngxPath.value());
+ if (backendPath.is_relative())
+ backendPath = Util::ExePath().parent_path() / backendPath;
+ std::error_code error;
+ externalBackendFile = std::filesystem::is_regular_file(backendPath, error);
+ if (externalBackendFile)
+ Config::Instance()->NvngxPath.set_volatile_value(backendPath.wstring());
+ else
+ spdlog::warn("External DLSS requires NvngxPath to name an existing shim DLL file");
+ }
+
+ if (BackendIdentity::AllowDlss(State::Instance().isRunningOnNvidia,
+ Config::Instance()->DLSSAllowExternalBackend.value_or_default(),
+ externalBackendFile))
{
- spdlog::info("Running on Nvidia");
+ spdlog::info(State::Instance().isRunningOnNvidia ? "Running on Nvidia" :
+ "External DLSS backend enabled; preserving physical GPU identity for FSR4");
if (!State::Instance().NVNGX_DLSS_Path.has_value() &&
Config::Instance()->NVNGX_DLSS_Library.has_value())
@@ -2020,7 +2041,7 @@ BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserv
Config::Instance()->DLSSEnabled.set_volatile_value(false);
}
- if (!Config::Instance()->DxgiSpoofing.has_value())
+ if (State::Instance().isRunningOnNvidia && !Config::Instance()->DxgiSpoofing.has_value())
{
spdlog::info("Disabling DxgiSpoofing");
Config::Instance()->DxgiSpoofing.set_volatile_value(false);
diff --git a/OptiScaler/spoofing/BackendIdentity.h b/OptiScaler/spoofing/BackendIdentity.h
new file mode 100644
index 0000000..c0e6a19
--- /dev/null
+++ b/OptiScaler/spoofing/BackendIdentity.h
@@ -0,0 +1,41 @@
+#pragma once
+
+#include <string_view>
+
+// Physical hardware identity is independent of external DLSS availability.
+namespace BackendIdentity
+{
+inline bool AllowDlss(bool isNvidia, bool allowExternalBackend, bool explicitBackendFile)
+{
+ return isNvidia || (allowExternalBackend && explicitBackendFile);
+}
+
+inline bool IsAmdFsrCaller(std::string_view caller)
+{
+ constexpr std::string_view modules[] = {
+ "amdxc64.dll", "amdxcffx64.dll", "amd_fidelityfx_dx12.dll",
+ "amd_fidelityfx_loader_dx12.dll", "amd_fidelityfx_upscaler_dx12.dll",
+ "amd_fidelityfx_framegeneration_dx12.dll", "amd_fidelityfx_denoiser_dx12.dll",
+ "amd_fidelityfx_radiancecache_dx12.dll"
+ };
+ for (auto module : modules)
+ {
+ if (caller.size() != module.size())
+ continue;
+ bool match = true;
+ for (size_t index = 0; index < caller.size(); ++index)
+ {
+ const char c = caller[index];
+ const char lower = c >= 'A' && c <= 'Z' ? c + ('a' - 'A') : c;
+ if (lower != module[index])
+ {
+ match = false;
+ break;
+ }
+ }
+ if (match)
+ return true;
+ }
+ return false;
+}
+}
diff --git a/OptiScaler/spoofing/Dxgi_Spoofing.cpp b/OptiScaler/spoofing/Dxgi_Spoofing.cpp
index 41b61b6..bd98862 100644
--- a/OptiScaler/spoofing/Dxgi_Spoofing.cpp
+++ b/OptiScaler/spoofing/Dxgi_Spoofing.cpp
@@ -1,5 +1,6 @@
#include "pch.h"
#include "Dxgi_Spoofing.h"
+#include "BackendIdentity.h"
#include <Config.h>
@@ -48,7 +49,7 @@ HRESULT DxgiSpoofing::hkGetDesc3(IDXGIAdapter4* This, DXGI_ADAPTER_DESC3* pDesc)
auto caller = Util::WhoIsTheCaller(_ReturnAddress());
- if (iequals(caller, "fakenvapi.dll") || iequals(caller, "vulkan-1.dll") || iequals(caller, "amdvlk64.dll") ||
+ if (BackendIdentity::IsAmdFsrCaller(caller) || iequals(caller, "fakenvapi.dll") || iequals(caller, "vulkan-1.dll") || iequals(caller, "amdvlk64.dll") ||
iequals(caller, "dxgi.dll") || iequals(caller, "d3d12.dll") || iequals(caller, "d3d12Core.dll"))
{
return result;
@@ -109,7 +110,7 @@ HRESULT DxgiSpoofing::hkGetDesc2(IDXGIAdapter2* This, DXGI_ADAPTER_DESC2* pDesc)
auto caller = Util::WhoIsTheCaller(_ReturnAddress());
- if (iequals(caller, "fakenvapi.dll") || iequals(caller, "vulkan-1.dll") || iequals(caller, "amdvlk64.dll") ||
+ if (BackendIdentity::IsAmdFsrCaller(caller) || iequals(caller, "fakenvapi.dll") || iequals(caller, "vulkan-1.dll") || iequals(caller, "amdvlk64.dll") ||
iequals(caller, "dxgi.dll") || iequals(caller, "d3d12.dll") || iequals(caller, "d3d12Core.dll"))
{
return result;
@@ -170,7 +171,7 @@ HRESULT DxgiSpoofing::hkGetDesc1(IDXGIAdapter1* This, DXGI_ADAPTER_DESC1* pDesc)
auto caller = Util::WhoIsTheCaller(_ReturnAddress());
- if (iequals(caller, "fakenvapi.dll") || iequals(caller, "vulkan-1.dll") || iequals(caller, "amdvlk64.dll") ||
+ if (BackendIdentity::IsAmdFsrCaller(caller) || iequals(caller, "fakenvapi.dll") || iequals(caller, "vulkan-1.dll") || iequals(caller, "amdvlk64.dll") ||
iequals(caller, "dxgi.dll") || iequals(caller, "d3d12.dll") || iequals(caller, "d3d12Core.dll"))
{
return result;
@@ -231,7 +232,7 @@ HRESULT DxgiSpoofing::hkGetDesc(IDXGIAdapter* This, DXGI_ADAPTER_DESC* pDesc)
auto caller = Util::WhoIsTheCaller(_ReturnAddress());
- if (iequals(caller, "fakenvapi.dll") || iequals(caller, "vulkan-1.dll") || iequals(caller, "amdvlk64.dll") ||
+ if (BackendIdentity::IsAmdFsrCaller(caller) || iequals(caller, "fakenvapi.dll") || iequals(caller, "vulkan-1.dll") || iequals(caller, "amdvlk64.dll") ||
iequals(caller, "dxgi.dll") || iequals(caller, "d3d12.dll") || iequals(caller, "d3d12Core.dll"))
{
return result;
diff --git a/OptiScaler/upscalers/fsr31/FSR31Feature_Dx12.cpp b/OptiScaler/upscalers/fsr31/FSR31Feature_Dx12.cpp
--- a/OptiScaler/upscalers/fsr31/FSR31Feature_Dx12.cpp
+++ b/OptiScaler/upscalers/fsr31/FSR31Feature_Dx12.cpp
@@ -848,6 +848,7 @@
State::Instance().ffxUpscalerVersionNames[Config::Instance()->FfxUpscalerIndex.value_or_default()];
_name = "FSR";
parse_version(version);
+ LOG_INFO("FSR context initialized: provider {}, versionId {:#x}", version, override.versionId);
}
SetInit(true);