Files
d4r/tools/d4r_fsr4_identity.h
ayo 0e851b7f90 release: prepare 0.1.5 with RDNA2 kernels and in-game DLSS/FSR switching
- Add native preset K kernels for gfx1030–gfx1036 using software matrix
  products, with fast and accuracy builds and RDNA2 motion kernels.
- Follow OptiScaler's DLSS and RR preset overrides, sanitize unsupported
  values and select the preset matching the feature's quality mode.
- Enable FSR 4 under NVIDIA GPU spoofing by exposing real AMD PCI IDs
  to OptiScaler and FidelityFX modules; bundle AMD's loader and upscaler.
- Keep K on native kernels in engine auto mode unless HIP is selected,
  and fall back to CUDA for M/L when shader_float8 is unavailable.
- Add native-engine K GPU timings, preset recreation harness controls
  and regression coverage; fix the input-wait test's glibc name clash.
- Update configuration, installer guidance and release documentation,
  simplify the README and move gameplay videos to docs/videos.md.

RDNA2 kernels remain untested on RDNA2 hardware; software matrix
arithmetic was validated against WMMA on RDNA3.
2026-10-17 16:05:09 -04:00

174 lines
7.5 KiB
C++

// FSR 4 from OptiScaler's upscaler menu while the game sees an NVIDIA GPU.
//
// d4r's games run with WINE_HIDE_AMD_GPU (PROTON_FORCE_NVAPI), so every DXGI adapter reports vendor 0x10de. Three
// parties then refuse FSR 4 on the AMD GPU that runs it: OptiScaler's own GPU check (RDNA3/RDNA4 -> FSR 4 update,
// INT8 or FP8 model), AMD's amd_fidelityfx_upscaler_dx12.dll and the FSR 4 provider amdxcffx64.dll, each of which
// reads the adapter's vendor before using the driver extension (2026-10-17: with the identity hidden, FSR 4.1.1
// produced FSR 3.1's output byte for byte; amdxcffx64.dll never loaded unless Fsr4Update was forced, and then the
// upscaler still chose FSR 3.1).
//
// The adapter's GetDesc family is wrapped so that these callers alone - OptiScaler (found by its PE export name,
// whatever its loader file is called) and AMD's FidelityFX modules - read the GPU's real PCI vendor and device ids,
// from sysfs. The game, vkd3d-proton, NVIDIA's NGX libraries and everything else keep the NVIDIA identity, and only
// the adapter behind the game's D3D12 device is changed.
#pragma once
#include <windows.h>
#include <dxgi1_6.h>
#include <cstdint>
#include <cstring>
#include <string>
#include "d4r_fsr_rr_identity.h"
namespace d4r_fsr4_identity
{
inline D4rPciIdentity g_real;
inline LUID g_luid = {};
using GetDescFn = HRESULT(STDMETHODCALLTYPE*)(IDXGIAdapter*, DXGI_ADAPTER_DESC*);
using GetDesc1Fn = HRESULT(STDMETHODCALLTYPE*)(IDXGIAdapter1*, DXGI_ADAPTER_DESC1*);
using GetDesc2Fn = HRESULT(STDMETHODCALLTYPE*)(IDXGIAdapter2*, DXGI_ADAPTER_DESC2*);
using GetDesc3Fn = HRESULT(STDMETHODCALLTYPE*)(IDXGIAdapter4*, DXGI_ADAPTER_DESC3*);
inline GetDescFn g_getDesc = nullptr;
inline GetDesc1Fn g_getDesc1 = nullptr;
inline GetDesc2Fn g_getDesc2 = nullptr;
inline GetDesc3Fn g_getDesc3 = nullptr;
// The DLL name in a module's PE export directory ("OptiScaler.dll" for OptiScaler under any file name).
inline bool export_name_is(HMODULE module, const char* expected)
{
auto* base = reinterpret_cast<const unsigned char*>(module);
auto* dos = reinterpret_cast<const IMAGE_DOS_HEADER*>(base);
if (dos->e_magic != IMAGE_DOS_SIGNATURE)
return false;
auto* nt = reinterpret_cast<const IMAGE_NT_HEADERS*>(base + dos->e_lfanew);
if (nt->Signature != IMAGE_NT_SIGNATURE)
return false;
const IMAGE_DATA_DIRECTORY& directory = nt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT];
if (directory.VirtualAddress == 0 || directory.Size == 0)
return false;
auto* exports = reinterpret_cast<const IMAGE_EXPORT_DIRECTORY*>(base + directory.VirtualAddress);
return exports->Name != 0 && _stricmp(reinterpret_cast<const char*>(base + exports->Name), expected) == 0;
}
// Whether the code at `address` belongs to OptiScaler or to one of AMD's FidelityFX/FSR 4 modules.
inline bool caller_sees_real(void* address)
{
HMODULE module = nullptr;
if (!GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
static_cast<const char*>(address), &module) || module == nullptr)
return false;
char path[MAX_PATH] = {};
const DWORD length = GetModuleFileNameA(module, path, MAX_PATH);
if (length == 0 || length >= MAX_PATH)
return false;
const char* slash = std::strrchr(path, '\\');
const char* name = slash != nullptr ? slash + 1 : path;
if (_strnicmp(name, "amd_fidelityfx_", 15) == 0 || _stricmp(name, "amdxcffx64.dll") == 0 ||
_stricmp(name, "amdxc64.dll") == 0)
return true;
return export_name_is(module, "OptiScaler.dll");
}
template <typename Desc> inline void correct(void* caller, Desc* out)
{
if (out->AdapterLuid.LowPart == g_luid.LowPart && out->AdapterLuid.HighPart == g_luid.HighPart &&
caller_sees_real(caller))
{
out->VendorId = g_real.vendor;
out->DeviceId = g_real.device;
}
}
inline HRESULT STDMETHODCALLTYPE get_desc(IDXGIAdapter* self, DXGI_ADAPTER_DESC* desc)
{
const HRESULT result = g_getDesc(self, desc);
if (SUCCEEDED(result) && desc != nullptr)
correct(__builtin_return_address(0), desc);
return result;
}
inline HRESULT STDMETHODCALLTYPE get_desc1(IDXGIAdapter1* self, DXGI_ADAPTER_DESC1* desc)
{
const HRESULT result = g_getDesc1(self, desc);
if (SUCCEEDED(result) && desc != nullptr)
correct(__builtin_return_address(0), desc);
return result;
}
inline HRESULT STDMETHODCALLTYPE get_desc2(IDXGIAdapter2* self, DXGI_ADAPTER_DESC2* desc)
{
const HRESULT result = g_getDesc2(self, desc);
if (SUCCEEDED(result) && desc != nullptr)
correct(__builtin_return_address(0), desc);
return result;
}
inline HRESULT STDMETHODCALLTYPE get_desc3(IDXGIAdapter4* self, DXGI_ADAPTER_DESC3* desc)
{
const HRESULT result = g_getDesc3(self, desc);
if (SUCCEEDED(result) && desc != nullptr)
correct(__builtin_return_address(0), desc);
return result;
}
template <typename Fn> inline void patch_slot(void** vtable, int slot, Fn hook, Fn& original)
{
if (vtable[slot] == reinterpret_cast<void*>(hook))
return;
DWORD protect = 0;
if (!VirtualProtect(&vtable[slot], sizeof(void*), PAGE_READWRITE, &protect))
return;
original = reinterpret_cast<Fn>(vtable[slot]);
vtable[slot] = reinterpret_cast<void*>(hook);
VirtualProtect(&vtable[slot], sizeof(void*), protect, &protect);
}
// Installs the wrapper for the adapter of `device` when the GPU is really AMD's and DXGI reports someone else.
// Once per process; `detail` says what was found and done.
inline bool install(ID3D12Device* device, std::string& detail)
{
const D4rPciIdentity reported = d4r_dxgi_identity(device);
std::string pci;
const D4rPciIdentity real = d4r_true_identity(device, pci);
char text[640];
std::snprintf(text, sizeof(text), "DXGI reports %04x:%04x; %s", reported.vendor, reported.device,
real.known ? pci.c_str() : ("real PCI identity unknown (" + pci + ")").c_str());
detail = text;
if (!real.known || real.vendor != 0x1002)
{
detail += "; not an AMD GPU: nothing to do";
return false;
}
if (reported.known && reported.vendor == real.vendor)
{
detail += "; DXGI already reports the real vendor: nothing to do";
return false;
}
g_real = real;
device->GetAdapterLuid(&g_luid);
IDXGIFactory4* factory = nullptr;
if (FAILED(CreateDXGIFactory2(0, __uuidof(IDXGIFactory4), reinterpret_cast<void**>(&factory))))
{
detail += "; no DXGI factory";
return false;
}
IDXGIAdapter4* adapter = nullptr;
const HRESULT found = factory->EnumAdapterByLuid(g_luid, __uuidof(IDXGIAdapter4), reinterpret_cast<void**>(&adapter));
factory->Release();
if (FAILED(found) || adapter == nullptr)
{
detail += "; the device's adapter has no IDXGIAdapter4";
return false;
}
// IDXGIAdapter4's vtable: GetDesc 8, GetDesc1 10, GetDesc2 11, GetDesc3 18. All adapters of the
// implementation share it; the LUID check above keeps other adapters unchanged.
void** vtable = *reinterpret_cast<void***>(adapter);
patch_slot(vtable, 8, &get_desc, g_getDesc);
patch_slot(vtable, 10, &get_desc1, g_getDesc1);
patch_slot(vtable, 11, &get_desc2, g_getDesc2);
patch_slot(vtable, 18, &get_desc3, g_getDesc3);
adapter->Release();
detail += "; OptiScaler and AMD's FidelityFX modules read the real ids (FSR 4)";
return g_getDesc != nullptr && g_getDesc1 != nullptr && g_getDesc2 != nullptr && g_getDesc3 != nullptr;
}
} // namespace d4r_fsr4_identity