From 079563c4ce8a23cc6c1aa5fc53223c1910cdde92 Mon Sep 17 00:00:00 2001 From: FakeMichau <49685661+FakeMichau@users.noreply.github.com> Date: Wed, 25 Feb 2026 23:41:54 +0100 Subject: [PATCH] Increase compatibility of FSR 4 model preset selection --- OptiScaler/dllmain.cpp | 2 +- OptiScaler/fsr4/FSR4ModelSelection.cpp | 106 +++++++++++++++++-------- OptiScaler/fsr4/FSR4ModelSelection.h | 14 +++- OptiScaler/fsr4/FSR4Upgrade.cpp | 31 ++++---- OptiScaler/hooks/LibraryLoad_Hooks.cpp | 2 +- OptiScaler/proxies/FfxApi_Proxy.h | 2 +- 6 files changed, 105 insertions(+), 52 deletions(-) diff --git a/OptiScaler/dllmain.cpp b/OptiScaler/dllmain.cpp index ec7bca28..af3ce085 100644 --- a/OptiScaler/dllmain.cpp +++ b/OptiScaler/dllmain.cpp @@ -972,7 +972,7 @@ static void CheckWorkingMode() if (ffxDx12SRModule != nullptr) { LOG_DEBUG("amd_fidelityfx_upscaler_dx12.dll already in memory"); - FSR4ModelSelection::Hook(ffxDx12SRModule, true); + FSR4ModelSelection::Hook(ffxDx12SRModule, FSR4Source::SDK); FfxApiProxy::InitFfxDx12_SR(ffxDx12SRModule); } diff --git a/OptiScaler/fsr4/FSR4ModelSelection.cpp b/OptiScaler/fsr4/FSR4ModelSelection.cpp index 0dac554e..0c0996cc 100644 --- a/OptiScaler/fsr4/FSR4ModelSelection.cpp +++ b/OptiScaler/fsr4/FSR4ModelSelection.cpp @@ -4,7 +4,8 @@ #include PFN_getModelBlob FSR4ModelSelection::o_getModelBlob = nullptr; -PFN_createModel FSR4ModelSelection::o_createModel = nullptr; +PFN_createModel FSR4ModelSelection::o_createModelSDK = nullptr; +PFN_createModel FSR4ModelSelection::o_createModelDriver = nullptr; uint32_t getCorrectedPreset(uint32_t preset) { @@ -43,26 +44,36 @@ uint64_t FSR4ModelSelection::hkgetModelBlob(uint32_t preset, uint64_t unknown, u return result; } -uint64_t FSR4ModelSelection::hkcreateModel(void* context, uint32_t preset) +uint64_t FSR4ModelSelection::hkcreateModelSDK(void* context, uint32_t preset) { LOG_FUNC(); preset = getCorrectedPreset(preset); - auto result = o_createModel(context, preset); + auto result = o_createModelSDK(context, preset); return result; } -void FSR4ModelSelection::Hook(HMODULE module, bool unhookOld) +uint64_t FSR4ModelSelection::hkcreateModelDriver(void* context, uint32_t preset) +{ + LOG_FUNC(); + + preset = getCorrectedPreset(preset); + + auto result = o_createModelDriver(context, preset); + + return result; +} + +void FSR4ModelSelection::Hook(HMODULE module, FSR4Source source) { if (module == nullptr) return; - if (unhookOld && (o_getModelBlob || o_createModel)) + if (o_getModelBlob) { - LOG_DEBUG("Unhooking old model selection hooks, o_getModelBlob: {:X}, o_createModel: {:X}", - (uintptr_t) o_getModelBlob, (uintptr_t) o_createModel); + LOG_DEBUG("Unhooking old model selection hooks"); DetourTransactionBegin(); DetourUpdateThread(GetCurrentThread()); @@ -70,18 +81,24 @@ void FSR4ModelSelection::Hook(HMODULE module, bool unhookOld) if (o_getModelBlob != nullptr) DetourDetach(&(PVOID&) o_getModelBlob, hkgetModelBlob); - if (o_createModel != nullptr) - DetourDetach(&(PVOID&) o_createModel, hkcreateModel); + if (o_createModelSDK && source == FSR4Source::SDK) + DetourDetach(&(PVOID&) o_createModelSDK, hkcreateModelSDK); + else if (o_createModelDriver && source == FSR4Source::DriverDll) + DetourDetach(&(PVOID&) o_createModelDriver, hkcreateModelDriver); if (DetourTransactionCommit() == 0) { LOG_DEBUG("Unhooked old model selection hooks"); o_getModelBlob = nullptr; - o_createModel = nullptr; + + if (source == FSR4Source::SDK) + o_createModelSDK = nullptr; + else if (source == FSR4Source::DriverDll) + o_createModelDriver = nullptr; } } - if (o_getModelBlob == nullptr && o_createModel == nullptr) + if (o_getModelBlob == nullptr) { const char* pattern = "83 F9 05 0F 87"; o_getModelBlob = (PFN_getModelBlob) scanner::GetAddress(module, pattern); @@ -97,30 +114,57 @@ void FSR4ModelSelection::Hook(HMODULE module, bool unhookOld) DetourTransactionCommit(); } - else + } + + const char* pattern403 = + "48 89 5C 24 ? 55 56 57 41 54 41 55 41 56 41 57 48 8D AC 24 ? ? ? ? B8 ? ? ? ? E8 ? ? ? ? 48 2B E0 0F 29 B4 24 " + "? ? ? ? 0F 29 BC 24 ? ? ? ? 48 8B 05 ? ? ? ? 48 33 C4 48 89 85 ? ? ? ? 44 8B F2"; + + if (!o_createModelSDK && source == FSR4Source::SDK) + { + // From amd_fidelityfx_upscaler_dx12 4.0.3.604 + + o_createModelSDK = (PFN_createModel) scanner::GetAddress(module, pattern403); + + LOG_DEBUG("Hooking model selection, o_createModelSDK: {:X}", (uintptr_t) o_createModelSDK); + + if (o_createModelSDK) { - // From amd_fidelityfx_upscaler_dx12 4.0.3.604 - const char* pattern = - "48 89 5C 24 ? 55 56 57 41 54 41 55 41 56 41 57 48 8D AC 24 ? ? ? ? B8 ? ? ? ? E8 ? ? ? ? 48 2B E0 0F " - "29 B4 24 ? ? ? ? 0F 29 BC 24 ? ? ? ? 48 8B 05 ? ? ? ? 48 33 C4 48 89 85 ? ? ? ? 44 8B F2"; - o_createModel = (PFN_createModel) scanner::GetAddress(module, pattern); + DetourTransactionBegin(); + DetourUpdateThread(GetCurrentThread()); - if (o_createModel) - { - LOG_DEBUG("Hooking model selection, o_createModel: {:X}", (uintptr_t) o_createModel); + DetourAttach(&(PVOID&) o_createModelSDK, hkcreateModelSDK); - DetourTransactionBegin(); - DetourUpdateThread(GetCurrentThread()); - - DetourAttach(&(PVOID&) o_createModel, hkcreateModel); - - DetourTransactionCommit(); - } - else - { - LOG_ERROR("Couldn't hook model selection"); - } + DetourTransactionCommit(); } + else + LOG_ERROR("Couldn't hook model selection"); + } + else if (!o_createModelDriver && source == FSR4Source::DriverDll) + { + o_createModelDriver = (PFN_createModel) scanner::GetAddress(module, pattern403); + + if (!o_createModelDriver) + { + // From amdxcffx64 2.1.0.968 + const char* pattern = "48 8B C4 48 89 58 ? 55 56 57 41 54 41 55 41 56 41 57 48 8D A8 ? ? ? ? 48 81 EC ? ? " + "? ? 0F 29 70 ? 0F 29 78 ? 48 8B 05"; + o_createModelDriver = (PFN_createModel) scanner::GetAddress(module, pattern); + } + + if (o_createModelDriver) + { + LOG_DEBUG("Hooking model selection, o_createModelDriver: {:X}", (uintptr_t) o_createModelDriver); + + DetourTransactionBegin(); + DetourUpdateThread(GetCurrentThread()); + + DetourAttach(&(PVOID&) o_createModelDriver, hkcreateModelDriver); + + DetourTransactionCommit(); + } + else + LOG_ERROR("Couldn't hook model selection"); } else { diff --git a/OptiScaler/fsr4/FSR4ModelSelection.h b/OptiScaler/fsr4/FSR4ModelSelection.h index 9ef0fff4..9cf10ead 100644 --- a/OptiScaler/fsr4/FSR4ModelSelection.h +++ b/OptiScaler/fsr4/FSR4ModelSelection.h @@ -5,13 +5,21 @@ typedef uint64_t (*PFN_getModelBlob)(uint32_t preset, uint64_t unknown, uint64_t* source, uint64_t* size); typedef uint64_t (*PFN_createModel)(void* context, uint32_t preset); +enum class FSR4Source +{ + SDK, + DriverDll, +}; + class FSR4ModelSelection { static uint64_t hkgetModelBlob(uint32_t preset, uint64_t unknown, uint64_t* source, uint64_t* size); static PFN_getModelBlob o_getModelBlob; - static uint64_t hkcreateModel(void* context, uint32_t preset); - static PFN_createModel o_createModel; + static uint64_t hkcreateModelSDK(void* context, uint32_t preset); + static uint64_t hkcreateModelDriver(void* context, uint32_t preset); + static PFN_createModel o_createModelSDK; + static PFN_createModel o_createModelDriver; public: - static void Hook(HMODULE module, bool unhookOld = true); + static void Hook(HMODULE module, FSR4Source source); }; diff --git a/OptiScaler/fsr4/FSR4Upgrade.cpp b/OptiScaler/fsr4/FSR4Upgrade.cpp index d606158a..d2bd0f95 100644 --- a/OptiScaler/fsr4/FSR4Upgrade.cpp +++ b/OptiScaler/fsr4/FSR4Upgrade.cpp @@ -28,7 +28,7 @@ #undef FFX_API_CONFIGURE_FG_SWAPCHAIN_KEY_FRAMEPACINGTUNING static HMODULE moduleAmdxc64 = nullptr; -static HMODULE fsr4Module = nullptr; +static HMODULE moduleAmdxcffx64 = nullptr; static AmdExtD3DDevice8* amdExtD3DDevice8 = nullptr; static AmdExtD3DShaderIntrinsics* amdExtD3DShaderIntrinsics = nullptr; @@ -233,21 +233,21 @@ struct AmdExtFfxApi : public IAmdExtFfxApi if (o_UpdateFfxApiProvider == nullptr) { - fsr4Module = NtdllProxy::LoadLibraryExW_Ldr(L"amdxcffx64.dll", NULL, 0); + moduleAmdxcffx64 = NtdllProxy::LoadLibraryExW_Ldr(L"amdxcffx64.dll", NULL, 0); - if (fsr4Module == nullptr) + if (moduleAmdxcffx64 == nullptr) { auto storePath = GetDriverStore(); for (size_t i = 0; i < storePath.size(); i++) { - if (fsr4Module == nullptr) + if (moduleAmdxcffx64 == nullptr) { auto dllPath = storePath[i] / L"amdxcffx64.dll"; LOG_DEBUG("Trying to load: {}", wstring_to_string(dllPath.c_str())); - fsr4Module = NtdllProxy::LoadLibraryExW_Ldr(dllPath.c_str(), NULL, 0); + moduleAmdxcffx64 = NtdllProxy::LoadLibraryExW_Ldr(dllPath.c_str(), NULL, 0); - if (fsr4Module != nullptr) + if (moduleAmdxcffx64 != nullptr) { LOG_INFO(L"amdxcffx64 loaded from {}", dllPath.wstring()); break; @@ -260,7 +260,7 @@ struct AmdExtFfxApi : public IAmdExtFfxApi LOG_INFO("amdxcffx64 loaded from game folder"); } - if (fsr4Module == nullptr) + if (moduleAmdxcffx64 == nullptr) { LOG_ERROR("Failed to load amdxcffx64.dll"); return E_NOINTERFACE; @@ -269,15 +269,16 @@ struct AmdExtFfxApi : public IAmdExtFfxApi auto sdk2upscalingModule = KernelBaseProxy::GetModuleHandleA_()("amd_fidelityfx_upscaler_dx12.dll"); constexpr bool unhookOld = false; - if (sdk2upscalingModule != nullptr) - FSR4ModelSelection::Hook(sdk2upscalingModule, unhookOld); - else - FSR4ModelSelection::Hook(fsr4Module, unhookOld); + if (sdk2upscalingModule) + FSR4ModelSelection::Hook(sdk2upscalingModule, FSR4Source::SDK); + + if (moduleAmdxcffx64) + FSR4ModelSelection::Hook(moduleAmdxcffx64, FSR4Source::DriverDll); o_UpdateFfxApiProvider = - (PFN_UpdateFfxApiProvider) KernelBaseProxy::GetProcAddress_()(fsr4Module, "UpdateFfxApiProvider"); - o_UpdateFfxApiProviderEx = - (PFN_UpdateFfxApiProviderEx) KernelBaseProxy::GetProcAddress_()(fsr4Module, "UpdateFfxApiProviderEx"); + (PFN_UpdateFfxApiProvider) KernelBaseProxy::GetProcAddress_()(moduleAmdxcffx64, "UpdateFfxApiProvider"); + o_UpdateFfxApiProviderEx = (PFN_UpdateFfxApiProviderEx) KernelBaseProxy::GetProcAddress_()( + moduleAmdxcffx64, "UpdateFfxApiProviderEx"); if (o_UpdateFfxApiProvider == nullptr) { @@ -491,7 +492,7 @@ void InitFSR4Update() } } -HMODULE GetFSR4Module() { return fsr4Module; } +HMODULE GetFSR4Module() { return moduleAmdxcffx64; } HRESULT STDMETHODCALLTYPE hkAmdExtD3DCreateInterface(IUnknown* pOuter, REFIID riid, void** ppvObject) { diff --git a/OptiScaler/hooks/LibraryLoad_Hooks.cpp b/OptiScaler/hooks/LibraryLoad_Hooks.cpp index 19363e9a..8ee543cd 100644 --- a/OptiScaler/hooks/LibraryLoad_Hooks.cpp +++ b/OptiScaler/hooks/LibraryLoad_Hooks.cpp @@ -455,7 +455,7 @@ HMODULE LibraryLoadHooks::LoadLibraryCheckW(std::wstring libName, LPCWSTR lpLibF { auto module = NtdllProxy::LoadLibraryExW_Ldr(libName.c_str(), NULL, 0); - FSR4ModelSelection::Hook(module, true); + FSR4ModelSelection::Hook(module, FSR4Source::SDK); if (module != nullptr) FfxApiProxy::InitFfxDx12_SR(module); diff --git a/OptiScaler/proxies/FfxApi_Proxy.h b/OptiScaler/proxies/FfxApi_Proxy.h index 4daa8f54..ce54fe86 100644 --- a/OptiScaler/proxies/FfxApi_Proxy.h +++ b/OptiScaler/proxies/FfxApi_Proxy.h @@ -321,7 +321,7 @@ class FfxApiProxy if (upscaling_dx12.dll != nullptr) { LOG_INFO("{} loaded from exe folder", wstring_to_string(dllNames[i])); - FSR4ModelSelection::Hook(upscaling_dx12.dll); + FSR4ModelSelection::Hook(upscaling_dx12.dll, FSR4Source::SDK); break; } }