Fix Windows NVAPI loading the gfx1101 build on every other AMD GPU
0.1.5 shipped one d4r/zluda/nvapi64.dll (the gfx1101 build) for all targets, and compat_nvapi_path() preferred it over d4r/nvapi/<arch>/. Nothing on Windows ever set D4R_GPU_ARCH, so on any other GPU NVAPI failed with "No selected gfx1101 device", NGX CUDA init failed, and DLSS stayed unavailable (black frames, no OptiScaler upscaler section). - Select the NVAPI per architecture; never fall back to a shared DLL in a multi-target folder, and report a missing build by name. - The loader and runtime publish D4R_GPU_ARCH and D4R_GPU_LUID for the game's adapter, so NVAPI picks the right device with several GPUs. - nvapi64.dll exports the target it was built for; the runtime refuses a mismatch, and the packager and d4r-check read the same marker. - Release packaging no longer ships d4r/zluda/nvapi64.dll and rejects NVAPI builds for the wrong target, without a marker, or missing. - Move target resolution, device matching and loader choice into gpu_selection.h; regression tests cover all 11 targets, bad or missing D4R_GPU_ARCH, mixed installs, multi-GPU and missing files. - d4r-check: accept the FSR keys in the shipped d4r.ini.
This commit is contained in:
1 parent
df9f2cd012
commit
7da2f9ac39
16 files changed
+530
-46
No files matched your search
@@ -1,5 +1,6 @@
|
||||
#pragma once
|
||||
#include "d3d12_external.h"
|
||||
#include "gpu_environment.h"
|
||||
#include "d3d12_boundary_timing.h"
|
||||
#include "pixel_conversion.h"
|
||||
#include "cuda_image_api.h"
|
||||
@@ -23,6 +24,19 @@ inline std::string env_path(const char* name) {
|
||||
if (!std::filesystem::path(diag::wide(value)).is_absolute()) throw std::runtime_error(std::string(name) + " must be absolute");
|
||||
return value;
|
||||
}
|
||||
// The NVAPI compatibility DLL names the GPU target it was built for. A file for another GPU (a mixed install, or
|
||||
// a shared copy from an older release) is refused here with the fix spelled out; older builds without the export
|
||||
// are accepted and still validate the device themselves.
|
||||
inline void require_nvapi_target(const diag::Library& nvapi, const std::string& path) {
|
||||
using Target = const char*(__cdecl*)();
|
||||
Target target = nullptr;
|
||||
try { target = nvapi.symbol<Target>("d4r_NvapiTargetArchitecture"); }
|
||||
catch (const std::exception&) { std::printf("D4R_NVAPI target=unknown (no d4r_NvapiTargetArchitecture export) path=%s\n", path.c_str()); return; }
|
||||
const std::string built = target ? target() : "";
|
||||
const std::string wanted = diag::HipApi::target_arch();
|
||||
std::printf("D4R_NVAPI target=%s wanted=%s path=%s\n", built.c_str(), wanted.c_str(), path.c_str());
|
||||
if (const auto error = diag::nvapi_target_error(built, wanted, path); !error.empty()) throw std::runtime_error(error);
|
||||
}
|
||||
inline void ngx_check(unsigned result, const char* operation) {
|
||||
if (result != 1 || !std::getenv("D4R_QUIET_API")) std::printf("D4R_NGX %s result=0x%08x\n", operation, result);
|
||||
if (result != 1) throw std::runtime_error(std::string(operation) + " NGX=" + std::to_string(result));
|
||||
@@ -105,6 +119,9 @@ struct Runtime {
|
||||
hip.select_architecture(-1, props, &luid);
|
||||
hip.verbose = cuda.verbose = !std::getenv("D4R_QUIET_API");
|
||||
if (std::memcmp(&luid, props.luid, sizeof(luid))) throw std::runtime_error("D3D12/HIP LUID mismatch");
|
||||
// NVAPI and the NGX core start from the environment: tell them which adapter and architecture this is.
|
||||
diag::AdapterLuid selectedLuid{}; std::memcpy(selectedLuid.data(), props.luid, selectedLuid.size());
|
||||
diag::publish_selected_gpu(diag::HipApi::target_arch(), &selectedLuid);
|
||||
cuda.check(cuda.cuInit(0), "cuInit(Windows runtime)");
|
||||
int count = 0; cuda.check(cuda.cuDeviceGetCount(&count), "cuDeviceGetCount");
|
||||
for (int i = 0; i < count; ++i) {
|
||||
@@ -124,6 +141,7 @@ struct Runtime {
|
||||
// NGX's loader can probe CUDA during DLL initialization: establish
|
||||
// the correct primary context before loading either NVIDIA DLL.
|
||||
nvapi = std::make_unique<diag::Library>(diag::wide(env_path("D4R_NVAPI_DLL")));
|
||||
require_nvapi_target(*nvapi, env_path("D4R_NVAPI_DLL"));
|
||||
dlss = std::make_unique<diag::Library>(diag::wide(env_path("D4R_DLSS_DLL")));
|
||||
core = std::make_unique<diag::Library>(diag::wide(env_path("D4R_NGX_CORE")));
|
||||
allocate = core->symbol<Allocate>("NVSDK_NGX_CUDA_AllocateParameters");
|
||||
|
||||
Reference in new issue
Block a user