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
+30
-16
@@ -1,6 +1,6 @@
|
||||
#pragma once
|
||||
#include "diagnostic.h"
|
||||
#include "gpu_target.h"
|
||||
#include "gpu_selection.h"
|
||||
#include <hip/hip_runtime_api.h>
|
||||
#include <cstdlib>
|
||||
#include <string>
|
||||
@@ -43,14 +43,16 @@ struct HipApi {
|
||||
if (verbose || result != hipSuccess) std::printf("HIP %s -> %d (%s)\n", call, static_cast<int>(result), hipGetErrorName(result));
|
||||
if (result != hipSuccess) throw std::runtime_error(std::string(call) + ": " + hipGetErrorString(result));
|
||||
}
|
||||
// The package's backend sets D4R_GPU_ARCH to the GPU type of the game's adapter before it loads this DLL, so one
|
||||
// build serves every supported type (a compile-time-only target locked RDNA3 / gfx1201 cards out: "No selected
|
||||
// gfx1200 device"). Unknown or missing values fall back to the build's own target.
|
||||
// The architecture this process runs for: D4R_GPU_ARCH when it names a supported target, otherwise the build's
|
||||
// own D4R_TARGET_ARCH. The loader and the shim publish the adapter's real architecture there before the
|
||||
// NVAPI/NGX components start (publish_selected_gpu in gpu_environment.h), so every component agrees. A value that
|
||||
// is set but unsupported is reported and ignored; select_architecture still refuses any device that is not of
|
||||
// the architecture in use.
|
||||
static const char* target_arch() {
|
||||
static const std::string arch = [] {
|
||||
const char* e = std::getenv("D4R_GPU_ARCH");
|
||||
const std::string v = e ? gpu_architecture(e) : std::string(); // "gfx1101:xnack-" -> "gfx1101"
|
||||
return supported_gpu_target(v) ? v : std::string(D4R_TARGET_ARCH);
|
||||
const auto resolved = resolve_target_arch(std::getenv("D4R_GPU_ARCH"), D4R_TARGET_ARCH);
|
||||
if (!resolved.warning.empty()) std::fprintf(stderr, "d4r: %s\n", resolved.warning.c_str());
|
||||
return resolved.architecture;
|
||||
}();
|
||||
return arch.c_str();
|
||||
}
|
||||
@@ -59,6 +61,14 @@ struct HipApi {
|
||||
const char* e = std::getenv("D4R_HIP_DEVICE");
|
||||
return e && *e ? std::atoi(e) : -1;
|
||||
}
|
||||
// The adapter the loader or shim selected (D4R_GPU_LUID), for components that start before any D3D12 device is
|
||||
// at hand. Absent means "any device of the target architecture"; a malformed value is an error, never ignored.
|
||||
static bool configured_luid(AdapterLuid& luid) {
|
||||
const char* text = std::getenv("D4R_GPU_LUID");
|
||||
if (!text || !*text) return false;
|
||||
if (!parse_luid(text, luid)) throw std::runtime_error(std::string("D4R_GPU_LUID='") + text + "' is not HHHHHHHH:LLLLLLLL");
|
||||
return true;
|
||||
}
|
||||
int select_architecture(int requested, hipDeviceProp_t& selected, const void* required_luid = nullptr,
|
||||
bool allow_no_match = false) const {
|
||||
// Architecture spoofing invalidates a gfx12 correctness test.
|
||||
@@ -71,24 +81,28 @@ struct HipApi {
|
||||
std::printf("HIP runtime=%d driver_api=%d headers=%d.%d.%d sizeof(properties)=%zu\n",
|
||||
version, driver, HIP_VERSION_MAJOR, HIP_VERSION_MINOR, HIP_VERSION_PATCH, sizeof(hipDeviceProp_t));
|
||||
check(hipGetDeviceCount(&count), "hipGetDeviceCount");
|
||||
int found = -1;
|
||||
std::vector<GpuCandidate> devices;
|
||||
requested = requested_device(requested);
|
||||
AdapterLuid wanted{};
|
||||
const AdapterLuid* luid = nullptr;
|
||||
if (required_luid) { std::memcpy(wanted.data(), required_luid, wanted.size()); luid = &wanted; }
|
||||
else if (configured_luid(wanted)) luid = &wanted;
|
||||
std::vector<hipDeviceProp_t> properties;
|
||||
for (int i = 0; i < count; ++i) {
|
||||
hipDeviceProp_t props{};
|
||||
check(hipGetDeviceProperties(&props, i), "hipGetDevicePropertiesR0600");
|
||||
std::printf("GPU ordinal=%d name=%s gcnArchName=%s wave=%d vram=%zu pci=%04x:%02x:%02x\n",
|
||||
i, props.name, props.gcnArchName, props.warpSize, props.totalGlobalMem,
|
||||
props.pciDomainID, props.pciBusID, props.pciDeviceID);
|
||||
const std::string arch = props.gcnArchName;
|
||||
if (gpu_architecture(arch) == target_arch() && (requested < 0 || requested == i) && found < 0 &&
|
||||
(!required_luid || std::memcmp(props.luid, required_luid, sizeof(props.luid)) == 0)) {
|
||||
found = i;
|
||||
selected = props;
|
||||
}
|
||||
GpuCandidate candidate{props.name, gpu_architecture(props.gcnArchName), {}};
|
||||
std::memcpy(candidate.luid.data(), props.luid, candidate.luid.size());
|
||||
devices.push_back(candidate);
|
||||
properties.push_back(props);
|
||||
}
|
||||
const int found = find_gpu_device(devices, target_arch(), requested, luid);
|
||||
if (found < 0 && allow_no_match) return -1; // Capability enumeration can include Intel/WARP adapters.
|
||||
if (found < 0) throw std::runtime_error(std::string("No selected ") + target_arch() +
|
||||
" device for this adapter; use the package matching the actual HIP architecture (see GPU log)");
|
||||
if (found < 0) throw std::runtime_error(no_device_message(devices, target_arch(), luid));
|
||||
selected = properties[found];
|
||||
require_gpu_target(selected.gcnArchName, target_arch());
|
||||
check(hipSetDevice(found), "hipSetDevice");
|
||||
std::printf("SELECTED HIP ordinal=%d architecture=%s validation=%s\n", found, target_arch(),
|
||||
|
||||
Reference in new issue
Block a user