Build patched Windows ZLUDA and execute native NGX DLSS diagnostics

This commit is contained in:
Codex committed 2026-09-30 16:35:30 +03:00
1 parent 64472e5a61
commit 3c28a82e34
17 files changed
+1114 -13

No files matched your search

+4 -1
View File
@@ -7,6 +7,7 @@ using CUcontext = void*;
using CUmodule = void*;
using CUfunction = void*;
struct CudaApi {
d4r::diag::SearchDirectory search;
d4r::diag::Library library;
#define D4R_CU(name, ret, ...) using name##_fn = ret(WINAPI*)(__VA_ARGS__); name##_fn name = library.symbol<name##_fn>(#name)
D4R_CU(cuInit, int, unsigned);
@@ -33,7 +34,9 @@ struct CudaApi {
D4R_CU(cuGetErrorName, int, int, const char**);
D4R_CU(cuGetErrorString, int, int, const char**);
#undef D4R_CU
explicit CudaApi(const std::string& path) : library(d4r::diag::wide(path)) {}
explicit CudaApi(const std::string& path) :
search(std::filesystem::path(d4r::diag::wide(path)).parent_path()),
library(d4r::diag::wide(path)) {}
void check(int result, const char* call) {
const char* name = "unknown", *message = "unknown";
if (result) { cuGetErrorName(result, &name); cuGetErrorString(result, &message); }
+135
View File
@@ -0,0 +1,135 @@
#pragma once
#include "cuda_api.h"
namespace d4r::cuda {
// Public CUDA Driver API layouts, kept independent of NVIDIA SDK headers.
using Array = void*;
using Texture = uint64_t;
struct ArrayDescriptor { size_t width, height; uint32_t format, channels; };
struct Array3DDescriptor {
size_t width, height, depth;
uint32_t format, channels, flags;
};
struct Copy2D {
size_t srcX, srcY;
uint32_t srcType, srcAlignment;
const void* srcHost;
CUdeviceptr srcDevice;
Array srcArray;
size_t srcPitch, dstX, dstY;
uint32_t dstType, dstAlignment;
void* dstHost;
CUdeviceptr dstDevice;
Array dstArray;
size_t dstPitch, widthBytes, height;
};
struct ResourceDescriptor {
uint32_t type, alignment;
union { Array array; int reserved[32]; } resource;
uint32_t flags, reserved;
};
struct TextureDescriptor {
uint32_t addressMode[3], filterMode, flags, maxAnisotropy, mipmapFilterMode;
float mipmapBias, minMipmapClamp, maxMipmapClamp, borderColor[4];
int reserved[12];
};
static_assert(sizeof(Array3DDescriptor) == 40);
static_assert(sizeof(ArrayDescriptor) == 24);
static_assert(sizeof(Copy2D) == 128);
static_assert(sizeof(ResourceDescriptor) == 144);
static_assert(sizeof(TextureDescriptor) == 104);
struct ImageApi {
CudaApi& cuda;
#define D4R_IMAGE(name, ...) using name##_fn = int(WINAPI*)(__VA_ARGS__); name##_fn name = cuda.library.symbol<name##_fn>(#name)
D4R_IMAGE(cuArray3DCreate_v2, Array*, const Array3DDescriptor*);
D4R_IMAGE(cuArrayGetDescriptor_v2, ArrayDescriptor*, Array);
D4R_IMAGE(cuArray3DGetDescriptor_v2, Array3DDescriptor*, Array);
D4R_IMAGE(cuArrayDestroy, Array);
D4R_IMAGE(cuMemcpy2D_v2, const Copy2D*);
D4R_IMAGE(cuTexObjectCreate, Texture*, const ResourceDescriptor*, const TextureDescriptor*, const void*);
D4R_IMAGE(cuTexObjectDestroy, Texture);
D4R_IMAGE(cuTexObjectGetResourceDesc, ResourceDescriptor*, Texture);
D4R_IMAGE(cuSurfObjectCreate, Texture*, const ResourceDescriptor*);
D4R_IMAGE(cuSurfObjectDestroy, Texture);
D4R_IMAGE(cuSurfObjectGetResourceDesc, ResourceDescriptor*, Texture);
#undef D4R_IMAGE
explicit ImageApi(CudaApi& api) : cuda(api) {}
};
class Image {
ImageApi& api_;
void release() noexcept {
if (object) {
const int result = surface_ ? api_.cuSurfObjectDestroy(object) : api_.cuTexObjectDestroy(object);
if (result) std::fprintf(stderr, "IMAGE_DESTROY object result=%d\n", result);
object = 0;
}
if (array_) {
const int result = api_.cuArrayDestroy(array_);
if (result) std::fprintf(stderr, "IMAGE_DESTROY array result=%d\n", result);
array_ = nullptr;
}
}
Array array_ = nullptr;
bool surface_;
size_t rowBytes_, height_;
public:
Texture object = 0;
Image(ImageApi& api, unsigned width, unsigned height, uint32_t format,
unsigned channels, bool surface, unsigned filter = 0)
: api_(api), surface_(surface), rowBytes_(size_t(width) * channels * (format == 16 ? 2 : 4)), height_(height) {
try {
const Array3DDescriptor descriptor{width, height, 0, format, channels, surface ? 2u : 0u};
api_.cuda.check(api_.cuArray3DCreate_v2(&array_, &descriptor), "cuArray3DCreate_v2");
ResourceDescriptor resource{};
resource.resource.array = array_;
if (surface) api_.cuda.check(api_.cuSurfObjectCreate(&object, &resource), "cuSurfObjectCreate");
else {
TextureDescriptor texture{};
texture.addressMode[0] = texture.addressMode[1] = 1; // clamp
texture.filterMode = filter;
texture.flags = 2; // normalized coordinates
api_.cuda.check(api_.cuTexObjectCreate(&object, &resource, &texture, nullptr), "cuTexObjectCreate");
}
ResourceDescriptor roundtrip{};
api_.cuda.check(surface ? api_.cuSurfObjectGetResourceDesc(&roundtrip, object) :
api_.cuTexObjectGetResourceDesc(&roundtrip, object), "CUDA object resource descriptor roundtrip");
if (roundtrip.type != 0 || roundtrip.resource.array != array_ || roundtrip.flags != 0)
throw std::runtime_error("CUDA object descriptor does not match its array");
ArrayDescriptor twoD{};
Array3DDescriptor threeD{};
api_.cuda.check(api_.cuArrayGetDescriptor_v2(&twoD, array_), "cuArrayGetDescriptor_v2");
api_.cuda.check(api_.cuArray3DGetDescriptor_v2(&threeD, array_), "cuArray3DGetDescriptor_v2");
if (twoD.width != width || twoD.height != height || twoD.format != format || twoD.channels != channels ||
threeD.width != width || threeD.height != height || threeD.depth != 0 || threeD.format != format ||
threeD.channels != channels || threeD.flags != descriptor.flags)
throw std::runtime_error("CUDA array descriptor geometry or format mismatch");
} catch (...) { release(); throw; }
}
Image(const Image&) = delete;
Image& operator=(const Image&) = delete;
~Image() { release(); }
void verify_wrong_object_kind() {
ResourceDescriptor wrong{};
const int result = surface_ ? api_.cuTexObjectGetResourceDesc(&wrong, object) :
api_.cuSurfObjectGetResourceDesc(&wrong, object);
if (!result) throw std::runtime_error("Wrong CUDA object kind was accepted as a valid resource");
std::printf("CUDA wrong-kind descriptor safely rejected result=%d\n", result);
}
void upload(const void* source) {
Copy2D copy{};
copy.srcType = 1; copy.srcHost = source; copy.srcPitch = rowBytes_;
copy.dstType = 3; copy.dstArray = array_;
copy.widthBytes = rowBytes_; copy.height = height_;
api_.cuda.check(api_.cuMemcpy2D_v2(&copy), "cuMemcpy2D_v2(host to diagnostic array)");
}
void download(void* destination) {
Copy2D copy{};
copy.srcType = 3; copy.srcArray = array_;
copy.dstType = 1; copy.dstHost = destination; copy.dstPitch = rowBytes_;
copy.widthBytes = rowBytes_; copy.height = height_;
api_.cuda.check(api_.cuMemcpy2D_v2(&copy), "cuMemcpy2D_v2(diagnostic array to host)");
}
};
}
+51
View File
@@ -0,0 +1,51 @@
#include "hip_api.h"
#include "cuda_image_api.h"
int main(int argc, char** argv) {
using namespace d4r::diag;
start();
try {
Args args(argc, argv);
HipApi hip(args.hip_root);
hipDeviceProp_t props{};
hip.select_gfx1201(args.device, props);
SearchDirectory search(std::filesystem::path(wide(args.cuda_dll)).parent_path());
CudaApi cuda(args.cuda_dll);
cuda.check(cuda.cuInit(0), "cuInit");
CUdevice device = -1;
int count = 0;
cuda.check(cuda.cuDeviceGetCount(&count), "cuDeviceGetCount");
for (int ordinal = 0; ordinal < count; ++ordinal) {
CUdevice candidate = -1;
int bus = -1, pciDevice = -1, domain = -1;
cuda.check(cuda.cuDeviceGet(&candidate, ordinal), "cuDeviceGet");
cuda.check(cuda.cuDeviceGetAttribute(&bus, 33, candidate), "cuDeviceGetAttribute(PCI_BUS_ID)");
cuda.check(cuda.cuDeviceGetAttribute(&pciDevice, 34, candidate), "cuDeviceGetAttribute(PCI_DEVICE_ID)");
cuda.check(cuda.cuDeviceGetAttribute(&domain, 50, candidate), "cuDeviceGetAttribute(PCI_DOMAIN_ID)");
if (bus == props.pciBusID && pciDevice == props.pciDeviceID && domain == props.pciDomainID) device = candidate;
}
if (device < 0) throw std::runtime_error("CUDA image probe HIP/CUDA PCI identity mismatch");
CUcontext context = nullptr;
cuda.check(cuda.cuCtxCreate_v2(&context, 0, device), "cuCtxCreate_v2");
struct Cleanup { CudaApi& api; CUcontext context; ~Cleanup() { (void)api.cuCtxDestroy_v2(context); } } cleanup{cuda, context};
d4r::cuda::ImageApi images(cuda);
for (unsigned iteration = 0; iteration < args.iterations; ++iteration) {
for (unsigned channels : {1u, 2u, 4u}) for (bool surface : {false, true}) {
d4r::cuda::Image image(images, 17, 9, 16, channels, surface);
image.verify_wrong_object_kind();
std::vector<uint16_t> input(17 * 9 * channels), output(input.size());
for (size_t i = 0; i < input.size(); ++i) input[i] = uint16_t((i + iteration) % 8 * 0x100);
image.upload(input.data());
image.download(output.data());
if (input != output) throw std::runtime_error("CUDA array storage roundtrip mismatch");
}
}
cuda.check(cuda.cuCtxSynchronize(), "cuCtxSynchronize");
std::printf("PASS CUDA_IMAGES architecture=gfx1201 iterations=%u descriptor_and_storage=1\n", args.iterations);
return 0;
} catch (const std::exception& e) {
std::fprintf(stderr, "FAIL CUDA_IMAGES %s\n", e.what());
loaded_modules();
return 4;
}
}
+33
View File
@@ -57,6 +57,18 @@ inline LONG WINAPI unhandled(EXCEPTION_POINTERS* info)
{
std::fprintf(stderr, "EXCEPTION code=0x%08lx address=%p\n",
info->ExceptionRecord->ExceptionCode, info->ExceptionRecord->ExceptionAddress);
if (info->ExceptionRecord->ExceptionCode == EXCEPTION_ACCESS_VIOLATION &&
info->ExceptionRecord->NumberParameters >= 2)
std::fprintf(stderr, "EXCEPTION_ACCESS operation=%llu target=0x%llx\n",
static_cast<unsigned long long>(info->ExceptionRecord->ExceptionInformation[0]),
static_cast<unsigned long long>(info->ExceptionRecord->ExceptionInformation[1]));
std::fprintf(stderr, "CONTEXT rip=0x%llx rsp=0x%llx rcx=0x%llx rdx=0x%llx r8=0x%llx r9=0x%llx\n",
static_cast<unsigned long long>(info->ContextRecord->Rip),
static_cast<unsigned long long>(info->ContextRecord->Rsp),
static_cast<unsigned long long>(info->ContextRecord->Rcx),
static_cast<unsigned long long>(info->ContextRecord->Rdx),
static_cast<unsigned long long>(info->ContextRecord->R8),
static_cast<unsigned long long>(info->ContextRecord->R9));
loaded_modules();
wchar_t directory[32768]{};
const DWORD n = GetEnvironmentVariableW(L"D4R_DIAG_DIR", directory, 32768);
@@ -74,12 +86,24 @@ inline LONG WINAPI unhandled(EXCEPTION_POINTERS* info)
}
return EXCEPTION_EXECUTE_HANDLER;
}
inline LONG WINAPI first_chance(EXCEPTION_POINTERS* info)
{
// NGX installs its own final exception filter. Capture a diagnostic dump
// before that filter can replace ours; do not swallow or retry the fault.
const auto code = info->ExceptionRecord->ExceptionCode;
if (code == EXCEPTION_ACCESS_VIOLATION || code == EXCEPTION_ILLEGAL_INSTRUCTION) {
static LONG captured = 0;
if (InterlockedCompareExchange(&captured, 1, 0) == 0) (void)unhandled(info);
}
return EXCEPTION_CONTINUE_SEARCH;
}
inline void start()
{
std::setvbuf(stdout, nullptr, _IONBF, 0);
std::setvbuf(stderr, nullptr, _IONBF, 0);
SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX);
SetUnhandledExceptionFilter(unhandled);
AddVectoredExceptionHandler(1, first_chance);
std::printf("d4r native Windows diagnostic x64 pid=%lu\n", GetCurrentProcessId());
}
struct Args {
@@ -89,6 +113,8 @@ struct Args {
std::string ngx_core, dlss_dll;
std::string nvapi_dll;
std::string ngx_abi = "driver";
std::string ngx_mode = "init";
unsigned preset = 11;
std::string fixture_dir;
std::string kernel_name = "enc1";
unsigned iterations = 32;
@@ -108,6 +134,13 @@ struct Args {
else if (key == "--dlss-dll") dlss_dll = value;
else if (key == "--nvapi-dll") nvapi_dll = value;
else if (key == "--ngx-abi") ngx_abi = value;
else if (key == "--ngx-mode") ngx_mode = value;
else if (key == "--preset") {
size_t end = 0;
preset = static_cast<unsigned>(std::stoul(value, &end));
if (end != value.size() || (preset != 5 && preset != 11 && preset != 13))
throw std::runtime_error("preset must be 5 (E), 11 (K) or 13 (M)");
}
else if (key == "--fixture-dir") fixture_dir = value;
else if (key == "--kernel-name") kernel_name = value;
else if (key == "--iterations") {
+147
View File
@@ -0,0 +1,147 @@
#pragma once
#include "cuda_image_api.h"
#include <cmath>
#include <chrono>
#include <fstream>
extern "C" void d4r_ngx_set_uint(void*, const char*, unsigned);
extern "C" void d4r_ngx_set_int(void*, const char*, int);
extern "C" void d4r_ngx_set_float(void*, const char*, float);
extern "C" void d4r_ngx_set_ull(void*, const char*, unsigned long long);
extern "C" void d4r_ngx_set_void(void*, const char*, void*);
namespace d4r::diag {
inline float half_value(uint16_t bits) {
const unsigned exponent = (bits >> 10) & 31, mantissa = bits & 1023;
const float sign = bits & 0x8000 ? -1.0f : 1.0f;
if (exponent == 31) return mantissa ? NAN : sign * INFINITY;
if (!exponent) return sign * std::ldexp(float(mantissa), -24);
return sign * std::ldexp(float(1024 + mantissa), int(exponent) - 25);
}
inline void save_output(const std::filesystem::path& directory, const std::vector<uint16_t>& output,
unsigned width, unsigned height, unsigned frame) {
const auto stem = "output-" + std::to_string(frame);
std::ofstream raw(directory / (stem + ".rgba16f"), std::ios::binary);
raw.write(reinterpret_cast<const char*>(output.data()), std::streamsize(output.size() * 2));
// BMP is only a diagnostic preview; the raw file preserves unmodified HDR values.
const unsigned stride = (width * 3 + 3) & ~3u;
std::vector<unsigned char> bytes(54 + size_t(stride) * height, 0);
auto u32 = [&](size_t offset, uint32_t value) {
for (int j = 0; j < 4; ++j) bytes[offset + j] = static_cast<unsigned char>(value >> (8 * j));
};
bytes[0] = 'B'; bytes[1] = 'M'; u32(2, static_cast<uint32_t>(bytes.size())); u32(10, 54);
u32(14, 40); u32(18, width); u32(22, height); bytes[26] = 1; bytes[28] = 24;
for (unsigned y = 0; y < height; ++y) for (unsigned x = 0; x < width; ++x)
for (unsigned c = 0; c < 3; ++c) {
const float value = half_value(output[(size_t(y) * width + x) * 4 + c]);
bytes[54 + size_t(height - y - 1) * stride + x * 3 + (2 - c)] =
static_cast<unsigned char>(std::clamp(value, 0.0f, 1.0f) * 255.0f + 0.5f);
}
std::ofstream bmp(directory / (stem + ".bmp"), std::ios::binary);
bmp.write(reinterpret_cast<const char*>(bytes.data()), std::streamsize(bytes.size()));
if (!raw || !bmp) throw std::runtime_error("Saving DLSS output failed");
}
inline void run_synthetic_dlss(CudaApi& cuda, Library& core, void* parameters,
unsigned preset, unsigned frames, const std::filesystem::path& directory) {
// CPU upload/readback is confined to this synthetic diagnostic. The game
// backend uses external D3D12 memory and GPU copies instead.
constexpr unsigned width = 256, height = 144, outWidth = 512, outHeight = 288;
using Create = unsigned(*)(unsigned, void*, void**);
using Evaluate = unsigned(*)(void*, void*, void*);
using Release = unsigned(*)(void*);
const auto create = core.symbol<Create>("NVSDK_NGX_CUDA_CreateFeature");
const auto evaluate = core.symbol<Evaluate>("NVSDK_NGX_CUDA_EvaluateFeature");
const auto release = core.symbol<Release>("NVSDK_NGX_CUDA_ReleaseFeature");
auto ngx_check = [](unsigned result, const char* operation) {
std::printf("NGX %s -> 0x%08x\n", operation, result);
if (result != 1) throw std::runtime_error(std::string(operation) + " result=" + std::to_string(result));
};
d4r_ngx_set_uint(parameters, "Width", width);
d4r_ngx_set_uint(parameters, "Height", height);
d4r_ngx_set_uint(parameters, "OutWidth", outWidth);
d4r_ngx_set_uint(parameters, "OutHeight", outHeight);
d4r_ngx_set_int(parameters, "PerfQualityValue", 2);
d4r_ngx_set_int(parameters, "DLSS.Feature.Create.Flags", 0);
d4r_ngx_set_int(parameters, "DLSS.Enable.Output.Subrects", 0);
d4r_ngx_set_uint(parameters, "CreationNodeMask", 1);
d4r_ngx_set_uint(parameters, "VisibilityNodeMask", 1);
for (const char* name : {"DLSS.Hint.Render.Preset.DLAA", "DLSS.Hint.Render.Preset.Quality",
"DLSS.Hint.Render.Preset.Balanced", "DLSS.Hint.Render.Preset.Performance",
"DLSS.Hint.Render.Preset.UltraPerformance", "DLSS.Hint.Render.Preset.UltraQuality"})
d4r_ngx_set_uint(parameters, name, preset);
CUdeviceptr scratch = 0;
cuda.check(cuda.cuMemAlloc_v2(&scratch, 64ull * 1024 * 1024), "cuMemAlloc_v2(NGX scratch)");
struct ScratchCleanup { CudaApi& api; CUdeviceptr pointer; ~ScratchCleanup() { (void)api.cuMemFree_v2(pointer); } } sc{cuda, scratch};
d4r_ngx_set_void(parameters, "Scratch", reinterpret_cast<void*>(uintptr_t(scratch)));
d4r_ngx_set_ull(parameters, "Scratch.SizeInBytes", 64ull * 1024 * 1024);
void* handle = nullptr;
std::printf("STAGE NGX_CREATE preset=%u dimensions=%ux%u->%ux%u\n", preset, width, height, outWidth, outHeight);
ngx_check(create(1, parameters, &handle), "NVSDK_NGX_CUDA_CreateFeature");
if (!handle) throw std::runtime_error("NGX CreateFeature returned a null handle");
struct FeatureCleanup { Release release; void*& handle; ~FeatureCleanup() { if (handle) (void)release(handle); } } fc{release, handle};
cuda::ImageApi images(cuda);
cuda::Image color(images, width, height, 16, 4, false, 1);
cuda::Image depth(images, width, height, 32, 1, false);
cuda::Image motion(images, width, height, 16, 2, false);
cuda::Image exposure(images, 1, 1, 32, 1, false);
cuda::Image output(images, outWidth, outHeight, 16, 4, true);
std::vector<uint16_t> input(size_t(width) * height * 4), zeroMotion(size_t(width) * height * 2, 0);
std::vector<float> inputDepth(size_t(width) * height, 0.5f);
for (unsigned y = 0; y < height; ++y) for (unsigned x = 0; x < width; ++x) {
const size_t index = (size_t(y) * width + x) * 4;
input[index] = ((x / 16 + y / 16) & 1) ? 0x3a00 : 0x3400; // .75 / .25
input[index + 1] = (x & 32) ? 0x3800 : 0x3400;
input[index + 2] = (y & 32) ? 0x3a00 : 0x3800;
input[index + 3] = 0x3c00;
}
const float one = 1.0f;
color.upload(input.data()); depth.upload(inputDepth.data()); motion.upload(zeroMotion.data()); exposure.upload(&one);
d4r_ngx_set_void(parameters, "Color", &color.object);
d4r_ngx_set_void(parameters, "Depth", &depth.object);
d4r_ngx_set_void(parameters, "MotionVectors", &motion.object);
d4r_ngx_set_void(parameters, "ExposureTexture", &exposure.object);
d4r_ngx_set_void(parameters, "Output", &output.object);
for (const char* name : {"TransparencyMask", "DLSS.Input.Bias.Current.Color.Mask"})
d4r_ngx_set_void(parameters, name, nullptr);
for (const char* name : {"Jitter.Offset.X", "Jitter.Offset.Y", "Sharpness"})
d4r_ngx_set_float(parameters, name, 0.0f);
for (const char* name : {"MV.Scale.X", "MV.Scale.Y", "DLSS.Pre.Exposure", "DLSS.Exposure.Scale"})
d4r_ngx_set_float(parameters, name, 1.0f);
d4r_ngx_set_float(parameters, "FrameTimeDeltaInMsec", 16.666667f);
d4r_ngx_set_int(parameters, "Disable.Watermark", 1);
d4r_ngx_set_uint(parameters, "DLSS.Render.Subrect.Dimensions.Width", width);
d4r_ngx_set_uint(parameters, "DLSS.Render.Subrect.Dimensions.Height", height);
for (const char* name : {"DLSS.Input.Color.Subrect.Base.X", "DLSS.Input.Color.Subrect.Base.Y",
"DLSS.Input.Depth.Subrect.Base.X", "DLSS.Input.Depth.Subrect.Base.Y", "DLSS.Input.MV.Subrect.Base.X",
"DLSS.Input.MV.Subrect.Base.Y", "DLSS.Output.Subrect.Base.X", "DLSS.Output.Subrect.Base.Y"})
d4r_ngx_set_uint(parameters, name, 0);
std::vector<uint16_t> pixels(size_t(outWidth) * outHeight * 4, 0x7e00);
for (unsigned frame = 0; frame < frames; ++frame) {
std::fill(pixels.begin(), pixels.end(), 0x7e00); // unwritten output is an explicit failure
output.upload(pixels.data());
d4r_ngx_set_int(parameters, "Reset", frame == 0 ? 1 : 0);
std::printf("STAGE NGX_EVALUATE preset=%u frame=%u\n", preset, frame);
const auto begin = std::chrono::steady_clock::now();
ngx_check(evaluate(handle, parameters, nullptr), "NVSDK_NGX_CUDA_EvaluateFeature");
cuda.check(cuda.cuCtxSynchronize(), "cuCtxSynchronize(NGX Evaluate)");
const double milliseconds = std::chrono::duration<double, std::milli>(std::chrono::steady_clock::now() - begin).count();
output.download(pixels.data());
size_t nonfinite = 0; double sum = 0, square = 0;
for (size_t i = 0; i < pixels.size(); ++i) {
const float value = half_value(pixels[i]);
if (!std::isfinite(value)) ++nonfinite;
if ((i & 3) < 3) { sum += value; square += double(value) * value; }
}
const double count = outWidth * outHeight * 3;
const double variance = square / count - (sum / count) * (sum / count);
std::printf("NGX_OUTPUT preset=%u frame=%u nonfinite=%zu mean=%.9g variance=%.9g evaluate_ms=%.3f\n",
preset, frame, nonfinite, sum / count, variance, milliseconds);
if (nonfinite || !std::isfinite(variance) || variance < 1e-6)
throw std::runtime_error("DLSS output has NaN/Inf, unwritten pixels or no synthetic pattern");
save_output(directory, pixels, outWidth, outHeight, frame);
}
ngx_check(release(handle), "NVSDK_NGX_CUDA_ReleaseFeature"); handle = nullptr;
std::printf("PASS NGX_EVALUATE preset=%u frames=%u finite=1 network_validation=pending\n", preset, frames);
}
}
+4
View File
@@ -1,5 +1,6 @@
#include "hip_api.h"
#include "cuda_api.h"
#include "ngx_cuda_evaluate.h"
// Same NGX C ABI and freestanding MSVC parameter accessors as the upstream shim.
// NVIDIA SDK headers and proprietary binaries are not build dependencies.
@@ -110,6 +111,9 @@ int main(int argc, char** argv)
unsigned roundtrip = 0;
check(d4r_ngx_get_uint(parameters, "Width", &roundtrip), "MSVC parameter ABI roundtrip");
if (roundtrip != 640) throw std::runtime_error("NGX parameter ABI mismatch");
if (args.ngx_mode == "evaluate")
run_synthetic_dlss(cuda, core, parameters, args.preset, args.iterations, data_path);
else if (args.ngx_mode != "init") throw std::runtime_error("--ngx-mode must be init or evaluate");
check(destroy(parameters), "DestroyParameters(allocated)"); parameters = nullptr;
check(destroy(caps), "DestroyParameters(capabilities)"); caps = nullptr;
loaded_modules();