1108 lines
55 KiB
C++
1108 lines
55 KiB
C++
#define WIN32_LEAN_AND_MEAN
|
|
#include <windows.h>
|
|
#include <dxgi1_4.h>
|
|
#include "nvsdk_ngx.h"
|
|
#include "ngx_param_abi_probe_shared.h"
|
|
|
|
#include <cstdio>
|
|
#include <cstdlib>
|
|
#include <cstring>
|
|
#include <algorithm>
|
|
#include <cmath>
|
|
#include <cstdint>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
extern "C" void d4r_ngx_parameter_set_ull(void*, const char*, unsigned long long);
|
|
extern "C" void d4r_ngx_parameter_set_float(void*, const char*, float);
|
|
extern "C" void d4r_ngx_parameter_set_double(void*, const char*, double);
|
|
extern "C" void d4r_ngx_parameter_set_uint(void*, const char*, unsigned int);
|
|
extern "C" void d4r_ngx_parameter_set_int(void*, const char*, int);
|
|
extern "C" void d4r_ngx_parameter_set_void(void*, const char*, void*);
|
|
extern "C" unsigned int d4r_ngx_parameter_get_ull(void*, const char*, unsigned long long*);
|
|
extern "C" unsigned int d4r_ngx_parameter_get_float(void*, const char*, float*);
|
|
extern "C" unsigned int d4r_ngx_parameter_get_double(void*, const char*, double*);
|
|
extern "C" unsigned int d4r_ngx_parameter_get_uint(void*, const char*, unsigned int*);
|
|
extern "C" unsigned int d4r_ngx_parameter_get_int(void*, const char*, int*);
|
|
extern "C" unsigned int d4r_ngx_parameter_get_void(void*, const char*, void**);
|
|
extern "C" unsigned int d4r_ngx_parameter_float_roundtrip(void*, const char*, float, float*);
|
|
extern "C" unsigned int d4r_ngx_parameter_uint_roundtrip(void*, const char*, unsigned int, unsigned int*);
|
|
extern "C" unsigned int d4r_ngx_parameter_proxy_size();
|
|
extern "C" void d4r_ngx_parameter_proxy_construct(void*, void*);
|
|
extern "C" unsigned int d4r_ngx_parameter_proxy_count(const void*);
|
|
extern "C" unsigned int d4r_ngx_parameter_proxy_dropped(const void*);
|
|
extern "C" int d4r_ngx_parameter_proxy_copy_record(
|
|
const void*, unsigned int, D4rNgxParamLogRecord*);
|
|
|
|
template <typename Target, typename Source> Target copy_function_pointer(Source source)
|
|
{
|
|
static_assert(sizeof(Target) == sizeof(Source), "function pointer sizes differ");
|
|
Target target{};
|
|
std::memcpy(&target, &source, sizeof(target));
|
|
return target;
|
|
}
|
|
|
|
template <typename Function> Function load_export(HMODULE module, const char* name)
|
|
{
|
|
FARPROC raw = GetProcAddress(module, name);
|
|
return raw ? copy_function_pointer<Function>(raw) : nullptr;
|
|
}
|
|
|
|
static std::wstring utf8_to_wide(const char* input)
|
|
{
|
|
const int required = MultiByteToWideChar(CP_UTF8, 0, input, -1, nullptr, 0);
|
|
if (required <= 1)
|
|
return {};
|
|
std::wstring output(static_cast<size_t>(required), L'\0');
|
|
MultiByteToWideChar(CP_UTF8, 0, input, -1, output.data(), required);
|
|
output.resize(static_cast<size_t>(required - 1));
|
|
return output;
|
|
}
|
|
|
|
static const char* ngx_result_name(NVSDK_NGX_Result result)
|
|
{
|
|
switch (result)
|
|
{
|
|
case NVSDK_NGX_Result_Success:
|
|
return "Success";
|
|
case NVSDK_NGX_Result_FAIL_FeatureNotSupported:
|
|
return "FeatureNotSupported";
|
|
case NVSDK_NGX_Result_FAIL_PlatformError:
|
|
return "PlatformError";
|
|
case NVSDK_NGX_Result_FAIL_InvalidParameter:
|
|
return "InvalidParameter";
|
|
case NVSDK_NGX_Result_FAIL_NotInitialized:
|
|
return "NotInitialized";
|
|
case NVSDK_NGX_Result_FAIL_UnableToInitializeFeature:
|
|
return "UnableToInitializeFeature";
|
|
case NVSDK_NGX_Result_FAIL_OutOfDate:
|
|
return "OutOfDate";
|
|
default:
|
|
return "Other";
|
|
}
|
|
}
|
|
|
|
static void print_ngx_result(const char* stage, NVSDK_NGX_Result result)
|
|
{
|
|
std::printf("%s: result=0x%08x (%s)\n", stage, static_cast<unsigned int>(result), ngx_result_name(result));
|
|
}
|
|
|
|
using D4rCudaDevicePtr = unsigned long long;
|
|
using D4rCudaArray = void*;
|
|
using D4rCudaTextureObject = unsigned long long;
|
|
using D4rCuMemAlloc = int(WINAPI*)(D4rCudaDevicePtr*, size_t);
|
|
using D4rCuMemFree = int(WINAPI*)(D4rCudaDevicePtr);
|
|
using D4rCuMemcpyHtoDAsync = int(WINAPI*)(D4rCudaDevicePtr, const void*, size_t, void*);
|
|
using D4rCuMemcpyDtoH = int(WINAPI*)(void*, D4rCudaDevicePtr, size_t);
|
|
using D4rCuCtxSynchronize = int(WINAPI*)();
|
|
|
|
struct D4rCudaArrayDescriptor
|
|
{
|
|
size_t Width;
|
|
size_t Height;
|
|
uint32_t Format;
|
|
uint32_t NumChannels;
|
|
};
|
|
static_assert(sizeof(D4rCudaArrayDescriptor) == 24);
|
|
|
|
struct D4rCudaArray3DDescriptor
|
|
{
|
|
size_t Width;
|
|
size_t Height;
|
|
size_t Depth;
|
|
uint32_t Format;
|
|
uint32_t NumChannels;
|
|
uint32_t Flags;
|
|
};
|
|
static_assert(sizeof(D4rCudaArray3DDescriptor) == 40);
|
|
|
|
struct D4rCudaMemcpy2D
|
|
{
|
|
size_t srcXInBytes;
|
|
size_t srcY;
|
|
uint32_t srcMemoryType;
|
|
uint32_t srcAlignment;
|
|
const void* srcHost;
|
|
D4rCudaDevicePtr srcDevice;
|
|
D4rCudaArray srcArray;
|
|
size_t srcPitch;
|
|
size_t dstXInBytes;
|
|
size_t dstY;
|
|
uint32_t dstMemoryType;
|
|
uint32_t dstAlignment;
|
|
void* dstHost;
|
|
D4rCudaDevicePtr dstDevice;
|
|
D4rCudaArray dstArray;
|
|
size_t dstPitch;
|
|
size_t WidthInBytes;
|
|
size_t Height;
|
|
};
|
|
static_assert(sizeof(D4rCudaMemcpy2D) == 128);
|
|
|
|
struct D4rCudaResourceDesc
|
|
{
|
|
uint32_t resType;
|
|
uint32_t alignment;
|
|
union
|
|
{
|
|
struct { D4rCudaArray hArray; } array;
|
|
int reserved[32];
|
|
} res;
|
|
uint32_t flags;
|
|
uint32_t reserved;
|
|
};
|
|
static_assert(sizeof(D4rCudaResourceDesc) == 144);
|
|
|
|
struct D4rCudaTextureDesc
|
|
{
|
|
uint32_t addressMode[3];
|
|
uint32_t filterMode;
|
|
uint32_t flags;
|
|
uint32_t maxAnisotropy;
|
|
uint32_t mipmapFilterMode;
|
|
float mipmapLevelBias;
|
|
float minMipmapLevelClamp;
|
|
float maxMipmapLevelClamp;
|
|
float borderColor[4];
|
|
int32_t reserved[12];
|
|
};
|
|
static_assert(sizeof(D4rCudaTextureDesc) == 104);
|
|
|
|
using D4rCuArrayCreate = int(WINAPI*)(D4rCudaArray*, const D4rCudaArrayDescriptor*);
|
|
using D4rCuArray3DCreate = int(WINAPI*)(D4rCudaArray*, const D4rCudaArray3DDescriptor*);
|
|
using D4rCuArrayDestroy = int(WINAPI*)(D4rCudaArray);
|
|
using D4rCuMemcpy2D = int(WINAPI*)(const D4rCudaMemcpy2D*);
|
|
using D4rCuTexObjectCreate = int(WINAPI*)(D4rCudaTextureObject*, const D4rCudaResourceDesc*,
|
|
const D4rCudaTextureDesc*, const void*);
|
|
using D4rCuTexObjectDestroy = int(WINAPI*)(D4rCudaTextureObject);
|
|
using D4rCuTexObjectGetResourceDesc = int(WINAPI*)(D4rCudaResourceDesc*, D4rCudaTextureObject);
|
|
using D4rCudaSurfaceObject = unsigned long long;
|
|
using D4rCuSurfObjectCreate = int(WINAPI*)(D4rCudaSurfaceObject*, const D4rCudaResourceDesc*);
|
|
using D4rCuSurfObjectDestroy = int(WINAPI*)(D4rCudaSurfaceObject);
|
|
using D4rCuSurfObjectGetResourceDesc = int(WINAPI*)(D4rCudaResourceDesc*, D4rCudaSurfaceObject);
|
|
using D4rNgxGetParameters = NVSDK_NGX_Result(NVSDK_CONV*)(NVSDK_NGX_Parameter**);
|
|
|
|
struct NgxParameterApi
|
|
{
|
|
PFN_NVSDK_NGX_Parameter_SetULL setULL = nullptr;
|
|
PFN_NVSDK_NGX_Parameter_SetF setF = nullptr;
|
|
PFN_NVSDK_NGX_Parameter_SetD setD = nullptr;
|
|
PFN_NVSDK_NGX_Parameter_SetUI setUI = nullptr;
|
|
PFN_NVSDK_NGX_Parameter_SetI setI = nullptr;
|
|
PFN_NVSDK_NGX_Parameter_SetVoidPointer setVoidPointer = nullptr;
|
|
PFN_NVSDK_NGX_Parameter_GetULL getULL = nullptr;
|
|
PFN_NVSDK_NGX_Parameter_GetF getF = nullptr;
|
|
PFN_NVSDK_NGX_Parameter_GetD getD = nullptr;
|
|
PFN_NVSDK_NGX_Parameter_GetUI getUI = nullptr;
|
|
PFN_NVSDK_NGX_Parameter_GetI getI = nullptr;
|
|
PFN_NVSDK_NGX_Parameter_GetVoidPointer getVoidPointer = nullptr;
|
|
};
|
|
|
|
static NgxParameterApi g_ngxParameterApi;
|
|
|
|
static void ngx_set(NVSDK_NGX_Parameter* parameters, const char* name, unsigned long long value)
|
|
{
|
|
if (g_ngxParameterApi.setULL != nullptr)
|
|
g_ngxParameterApi.setULL(parameters, name, value);
|
|
else
|
|
d4r_ngx_parameter_set_ull(parameters, name, value);
|
|
}
|
|
static void ngx_set(NVSDK_NGX_Parameter* parameters, const char* name, float value)
|
|
{
|
|
if (g_ngxParameterApi.setF != nullptr)
|
|
g_ngxParameterApi.setF(parameters, name, value);
|
|
else
|
|
d4r_ngx_parameter_set_float(parameters, name, value);
|
|
}
|
|
static void ngx_set(NVSDK_NGX_Parameter* parameters, const char* name, double value)
|
|
{
|
|
if (g_ngxParameterApi.setD != nullptr)
|
|
g_ngxParameterApi.setD(parameters, name, value);
|
|
else
|
|
d4r_ngx_parameter_set_double(parameters, name, value);
|
|
}
|
|
static void ngx_set(NVSDK_NGX_Parameter* parameters, const char* name, unsigned int value)
|
|
{
|
|
if (g_ngxParameterApi.setUI != nullptr)
|
|
g_ngxParameterApi.setUI(parameters, name, value);
|
|
else
|
|
d4r_ngx_parameter_set_uint(parameters, name, value);
|
|
}
|
|
static void ngx_set(NVSDK_NGX_Parameter* parameters, const char* name, int value)
|
|
{
|
|
if (g_ngxParameterApi.setI != nullptr)
|
|
g_ngxParameterApi.setI(parameters, name, value);
|
|
else
|
|
d4r_ngx_parameter_set_int(parameters, name, value);
|
|
}
|
|
static void ngx_set(NVSDK_NGX_Parameter* parameters, const char* name, void* value)
|
|
{
|
|
if (g_ngxParameterApi.setVoidPointer != nullptr)
|
|
g_ngxParameterApi.setVoidPointer(parameters, name, value);
|
|
else
|
|
d4r_ngx_parameter_set_void(parameters, name, value);
|
|
}
|
|
static NVSDK_NGX_Result ngx_get_ull(NVSDK_NGX_Parameter* parameters, const char* name,
|
|
unsigned long long* value)
|
|
{
|
|
if (g_ngxParameterApi.getULL != nullptr)
|
|
return g_ngxParameterApi.getULL(parameters, name, value);
|
|
return static_cast<NVSDK_NGX_Result>(d4r_ngx_parameter_get_ull(parameters, name, value));
|
|
}
|
|
static NVSDK_NGX_Result ngx_get_float(NVSDK_NGX_Parameter* parameters, const char* name, float* value)
|
|
{
|
|
if (g_ngxParameterApi.getF != nullptr)
|
|
return g_ngxParameterApi.getF(parameters, name, value);
|
|
return static_cast<NVSDK_NGX_Result>(d4r_ngx_parameter_get_float(parameters, name, value));
|
|
}
|
|
static NVSDK_NGX_Result ngx_get_double(NVSDK_NGX_Parameter* parameters, const char* name, double* value)
|
|
{
|
|
if (g_ngxParameterApi.getD != nullptr)
|
|
return g_ngxParameterApi.getD(parameters, name, value);
|
|
return static_cast<NVSDK_NGX_Result>(d4r_ngx_parameter_get_double(parameters, name, value));
|
|
}
|
|
static NVSDK_NGX_Result ngx_get_ui(NVSDK_NGX_Parameter* parameters, const char* name,
|
|
unsigned int* value)
|
|
{
|
|
if (g_ngxParameterApi.getUI != nullptr)
|
|
return g_ngxParameterApi.getUI(parameters, name, value);
|
|
return static_cast<NVSDK_NGX_Result>(d4r_ngx_parameter_get_uint(parameters, name, value));
|
|
}
|
|
static NVSDK_NGX_Result ngx_get_i(NVSDK_NGX_Parameter* parameters, const char* name, int* value)
|
|
{
|
|
if (g_ngxParameterApi.getI != nullptr)
|
|
return g_ngxParameterApi.getI(parameters, name, value);
|
|
return static_cast<NVSDK_NGX_Result>(d4r_ngx_parameter_get_int(parameters, name, value));
|
|
}
|
|
static NVSDK_NGX_Result ngx_get_void(NVSDK_NGX_Parameter* parameters, const char* name, void** value)
|
|
{
|
|
if (g_ngxParameterApi.getVoidPointer != nullptr)
|
|
return g_ngxParameterApi.getVoidPointer(parameters, name, value);
|
|
return static_cast<NVSDK_NGX_Result>(d4r_ngx_parameter_get_void(parameters, name, value));
|
|
}
|
|
static void* ngx_pointer_from_handle(uint64_t handle)
|
|
{
|
|
return reinterpret_cast<void*>(static_cast<uintptr_t>(handle));
|
|
}
|
|
|
|
static float half_to_float(uint16_t half)
|
|
{
|
|
const uint32_t sign = static_cast<uint32_t>(half & 0x8000u) << 16;
|
|
const uint32_t exponent = (half >> 10) & 0x1fu;
|
|
const uint32_t mantissa = half & 0x03ffu;
|
|
uint32_t bits = 0;
|
|
if (exponent == 0)
|
|
{
|
|
if (mantissa == 0)
|
|
bits = sign;
|
|
else
|
|
{
|
|
const float subnormal = std::ldexp(static_cast<float>(mantissa), -24);
|
|
return (sign != 0 ? -subnormal : subnormal);
|
|
}
|
|
}
|
|
else if (exponent == 0x1fu)
|
|
bits = sign | 0x7f800000u | (mantissa << 13);
|
|
else
|
|
bits = sign | ((exponent + 112u) << 23) | (mantissa << 13);
|
|
float value = 0.0f;
|
|
std::memcpy(&value, &bits, sizeof(value));
|
|
return value;
|
|
}
|
|
|
|
static bool write_file(const std::wstring& path, const void* data, size_t bytes)
|
|
{
|
|
HANDLE file = CreateFileW(path.c_str(), GENERIC_WRITE, 0, nullptr, CREATE_ALWAYS,
|
|
FILE_ATTRIBUTE_NORMAL, nullptr);
|
|
if (file == INVALID_HANDLE_VALUE)
|
|
return false;
|
|
const auto* source = static_cast<const unsigned char*>(data);
|
|
size_t offset = 0;
|
|
bool success = true;
|
|
while (offset < bytes)
|
|
{
|
|
const DWORD chunk = static_cast<DWORD>(std::min<size_t>(bytes - offset, 0x7fffffffu));
|
|
DWORD written = 0;
|
|
if (!WriteFile(file, source + offset, chunk, &written, nullptr) || written != chunk)
|
|
{
|
|
success = false;
|
|
break;
|
|
}
|
|
offset += written;
|
|
}
|
|
CloseHandle(file);
|
|
return success;
|
|
}
|
|
|
|
static void evaluate_synthetic_frame(NVSDK_NGX_Parameter* parameters,
|
|
const NVSDK_NGX_Handle* featureHandle,
|
|
decltype(&NVSDK_NGX_CUDA_EvaluateFeature) evaluateFeature,
|
|
decltype(&NVSDK_NGX_CUDA_EvaluateFeature_C) evaluateFeatureC,
|
|
bool useCEvaluate,
|
|
const std::wstring& appData,
|
|
D4rCudaDevicePtr scratchDevice,
|
|
size_t scratchBytes)
|
|
{
|
|
constexpr unsigned int inputWidth = 640;
|
|
constexpr unsigned int inputHeight = 360;
|
|
constexpr unsigned int outputWidth = 1280;
|
|
constexpr unsigned int outputHeight = 720;
|
|
const size_t inputPixels = static_cast<size_t>(inputWidth) * inputHeight;
|
|
const size_t outputPixels = static_cast<size_t>(outputWidth) * outputHeight;
|
|
const size_t colorBytes = inputPixels * 4 * sizeof(uint16_t);
|
|
const size_t depthBytes = inputPixels * sizeof(float);
|
|
const size_t motionBytes = inputPixels * 2 * sizeof(float);
|
|
const size_t outputBytes = outputPixels * 4 * sizeof(uint16_t);
|
|
|
|
HMODULE cuda = LoadLibraryA("nvcuda.dll");
|
|
if (cuda == nullptr)
|
|
{
|
|
std::printf("Synthetic DLSS evaluate: LoadLibraryA(nvcuda.dll) failed: %lu\n", GetLastError());
|
|
return;
|
|
}
|
|
const auto alloc = load_export<D4rCuMemAlloc>(cuda, "cuMemAlloc");
|
|
const auto free = load_export<D4rCuMemFree>(cuda, "cuMemFree");
|
|
const auto copyHtoD = load_export<D4rCuMemcpyHtoDAsync>(cuda, "cuMemcpyHtoDAsync");
|
|
const auto copyDtoH = load_export<D4rCuMemcpyDtoH>(cuda, "cuMemcpyDtoH");
|
|
const auto synchronize = load_export<D4rCuCtxSynchronize>(cuda, "cuCtxSynchronize");
|
|
const auto arrayCreate = load_export<D4rCuArrayCreate>(cuda, "cuArrayCreate");
|
|
const auto arrayDestroy = load_export<D4rCuArrayDestroy>(cuda, "cuArrayDestroy");
|
|
const auto copy2D = load_export<D4rCuMemcpy2D>(cuda, "cuMemcpy2D");
|
|
const auto textureCreate = load_export<D4rCuTexObjectCreate>(cuda, "cuTexObjectCreate");
|
|
const auto textureDestroy = load_export<D4rCuTexObjectDestroy>(cuda, "cuTexObjectDestroy");
|
|
const auto textureGetResourceDesc = load_export<D4rCuTexObjectGetResourceDesc>(
|
|
cuda, "cuTexObjectGetResourceDesc");
|
|
const auto array3DCreate = load_export<D4rCuArray3DCreate>(cuda, "cuArray3DCreate");
|
|
const auto surfaceCreate = load_export<D4rCuSurfObjectCreate>(cuda, "cuSurfObjectCreate");
|
|
const auto surfaceDestroy = load_export<D4rCuSurfObjectDestroy>(cuda, "cuSurfObjectDestroy");
|
|
const auto surfaceGetResourceDesc = load_export<D4rCuSurfObjectGetResourceDesc>(
|
|
cuda, "cuSurfObjectGetResourceDesc");
|
|
const char* resourceMode = std::getenv("D4R_NGX_RESOURCE_MODE");
|
|
const bool textureMode = resourceMode != nullptr &&
|
|
(std::strcmp(resourceMode, "texture") == 0 || std::strcmp(resourceMode, "surface") == 0);
|
|
const bool surfaceMode = resourceMode != nullptr && std::strcmp(resourceMode, "surface") == 0;
|
|
if (alloc == nullptr || free == nullptr || copyHtoD == nullptr || copyDtoH == nullptr || synchronize == nullptr)
|
|
{
|
|
std::printf("Synthetic DLSS evaluate: CUDA driver bridge is missing a required memory export\n");
|
|
FreeLibrary(cuda);
|
|
return;
|
|
}
|
|
if (textureMode && (arrayCreate == nullptr || arrayDestroy == nullptr || copy2D == nullptr ||
|
|
textureCreate == nullptr || textureDestroy == nullptr))
|
|
{
|
|
std::printf("Synthetic DLSS evaluate: CUDA array/texture bridge exports are missing\n");
|
|
FreeLibrary(cuda);
|
|
return;
|
|
}
|
|
if (surfaceMode && (array3DCreate == nullptr || surfaceCreate == nullptr || surfaceDestroy == nullptr))
|
|
{
|
|
std::printf("Synthetic DLSS evaluate: CUDA surface bridge exports are missing\n");
|
|
FreeLibrary(cuda);
|
|
return;
|
|
}
|
|
|
|
std::vector<uint16_t> color(inputPixels * 4);
|
|
std::vector<float> depth(inputPixels, 0.5f);
|
|
std::vector<float> motion(inputPixels * 2, 0.0f);
|
|
std::vector<uint16_t> output(outputPixels * 4, 0);
|
|
|
|
constexpr uint16_t dark = 0x2a66u; // half 0.05
|
|
constexpr uint16_t mid = 0x3400u; // half 0.25
|
|
constexpr uint16_t bright = 0x3a66u; // half 0.8
|
|
constexpr uint16_t white = 0x3c00u; // half 1.0
|
|
for (unsigned int y = 0; y < inputHeight; ++y)
|
|
{
|
|
for (unsigned int x = 0; x < inputWidth; ++x)
|
|
{
|
|
const size_t pixel = static_cast<size_t>(y) * inputWidth + x;
|
|
const bool fence = (x % 24u == 0u) || (y % 24u == 0u);
|
|
const bool checker = (((x / 4u) + (y / 4u)) & 1u) != 0;
|
|
color[pixel * 4 + 0] = fence ? white : (checker ? mid : dark);
|
|
color[pixel * 4 + 1] = ((x + y) % 32u < 2u) ? bright : (checker ? dark : mid);
|
|
color[pixel * 4 + 2] = (((x / 8u) ^ (y / 8u)) & 1u) ? bright : dark;
|
|
color[pixel * 4 + 3] = white;
|
|
}
|
|
}
|
|
|
|
D4rCudaArray colorArray = nullptr;
|
|
D4rCudaArray depthArray = nullptr;
|
|
D4rCudaArray motionArray = nullptr;
|
|
D4rCudaArray exposureArray = nullptr;
|
|
D4rCudaArray outputArray = nullptr;
|
|
D4rCudaTextureObject colorTexture = 0;
|
|
D4rCudaTextureObject depthTexture = 0;
|
|
D4rCudaTextureObject motionTexture = 0;
|
|
D4rCudaTextureObject exposureTexture = 0;
|
|
D4rCudaSurfaceObject outputSurface = 0;
|
|
int textureSetupResult = 0;
|
|
if (textureMode)
|
|
{
|
|
auto create_and_upload_array = [&](const char* label, size_t width, size_t height,
|
|
uint32_t format, uint32_t channels, const void* source,
|
|
size_t pitch, D4rCudaArray& array) {
|
|
const D4rCudaArrayDescriptor descriptor{width, height, format, channels};
|
|
int result = arrayCreate(&array, &descriptor);
|
|
std::printf("Synthetic DLSS eval cuArrayCreate(%s): result=%d array=%p\n", label, result, array);
|
|
if (result != 0)
|
|
return result;
|
|
D4rCudaMemcpy2D copy{};
|
|
copy.srcMemoryType = 1; // CUDA_MEMORYTYPE_HOST
|
|
copy.srcHost = source;
|
|
copy.srcPitch = pitch;
|
|
copy.dstMemoryType = 3; // CUDA_MEMORYTYPE_ARRAY
|
|
copy.dstArray = array;
|
|
copy.WidthInBytes = pitch;
|
|
copy.Height = height;
|
|
result = copy2D(©);
|
|
std::printf("Synthetic DLSS eval array upload(%s): result=%d bytesPerRow=%zu\n",
|
|
label, result, pitch);
|
|
return result;
|
|
};
|
|
auto create_texture = [&](const char* label, D4rCudaArray array, uint32_t filterMode,
|
|
D4rCudaTextureObject& texture) {
|
|
D4rCudaResourceDesc resource{};
|
|
resource.resType = 0; // CUDA_RESOURCE_TYPE_ARRAY
|
|
resource.res.array.hArray = array;
|
|
D4rCudaTextureDesc sampler{};
|
|
sampler.addressMode[0] = 1; // clamp
|
|
sampler.addressMode[1] = 1;
|
|
sampler.addressMode[2] = 0;
|
|
sampler.filterMode = filterMode;
|
|
sampler.flags = 2; // CU_TRSF_NORMALIZED_COORDINATES, matching NGX-created textures
|
|
sampler.maxAnisotropy = 0;
|
|
int result = textureCreate(&texture, &resource, &sampler, nullptr);
|
|
std::printf("Synthetic DLSS eval cuTexObjectCreate(%s): result=%d object=0x%llx\n",
|
|
label, result, texture);
|
|
return result;
|
|
};
|
|
|
|
const std::vector<uint16_t> motionHalf(inputPixels * 2, 0);
|
|
const float exposureValue = 1.0f;
|
|
textureSetupResult = create_and_upload_array(
|
|
"Color RGBA16F", inputWidth, inputHeight, 16, 4, color.data(),
|
|
inputWidth * 4 * sizeof(uint16_t), colorArray);
|
|
if (textureSetupResult == 0)
|
|
textureSetupResult = create_and_upload_array(
|
|
"Depth R32F", inputWidth, inputHeight, 32, 1, depth.data(),
|
|
inputWidth * sizeof(float), depthArray);
|
|
if (textureSetupResult == 0)
|
|
textureSetupResult = create_and_upload_array(
|
|
"Motion RG16F", inputWidth, inputHeight, 16, 2, motionHalf.data(),
|
|
inputWidth * 2 * sizeof(uint16_t), motionArray);
|
|
if (textureSetupResult == 0)
|
|
textureSetupResult = create_and_upload_array(
|
|
"Exposure R32F", 1, 1, 32, 1, &exposureValue,
|
|
sizeof(exposureValue), exposureArray);
|
|
if (textureSetupResult == 0)
|
|
textureSetupResult = create_texture("Color", colorArray, 1, colorTexture);
|
|
if (textureSetupResult == 0)
|
|
textureSetupResult = create_texture("Depth", depthArray, 0, depthTexture);
|
|
if (textureSetupResult == 0)
|
|
textureSetupResult = create_texture("MotionVectors", motionArray, 0, motionTexture);
|
|
if (textureSetupResult == 0)
|
|
textureSetupResult = create_texture("Exposure", exposureArray, 0, exposureTexture);
|
|
if (textureSetupResult == 0 && surfaceMode)
|
|
{
|
|
const D4rCudaArray3DDescriptor descriptor{
|
|
outputWidth, outputHeight, 0, 16, 4, 2u // RGBA16F with CUDA_ARRAY3D_SURFACE_LDST
|
|
};
|
|
textureSetupResult = array3DCreate(&outputArray, &descriptor);
|
|
std::printf("Synthetic DLSS eval cuArray3DCreate(Output RGBA16F): result=%d array=%p\n",
|
|
textureSetupResult, outputArray);
|
|
if (textureSetupResult == 0)
|
|
{
|
|
D4rCudaResourceDesc resource{};
|
|
resource.resType = 0; // CUDA_RESOURCE_TYPE_ARRAY
|
|
resource.res.array.hArray = outputArray;
|
|
textureSetupResult = surfaceCreate(&outputSurface, &resource);
|
|
std::printf("Synthetic DLSS eval cuSurfObjectCreate(Output): result=%d object=0x%llx\n",
|
|
textureSetupResult, outputSurface);
|
|
}
|
|
}
|
|
if (textureSetupResult == 0 && textureMode)
|
|
{
|
|
D4rCudaResourceDesc descriptor{};
|
|
const int descriptorResult = textureGetResourceDesc != nullptr
|
|
? textureGetResourceDesc(&descriptor, colorTexture) : 801;
|
|
std::printf("Synthetic DLSS cuTexObjectGetResourceDesc(Color): result=%d type=%u array=%p\n",
|
|
descriptorResult, descriptor.resType, descriptor.res.array.hArray);
|
|
}
|
|
if (textureSetupResult == 0 && surfaceMode)
|
|
{
|
|
D4rCudaResourceDesc descriptor{};
|
|
const int descriptorResult = surfaceGetResourceDesc != nullptr
|
|
? surfaceGetResourceDesc(&descriptor, outputSurface) : 801;
|
|
std::printf("Synthetic DLSS cuSurfObjectGetResourceDesc(Output): result=%d type=%u array=%p\n",
|
|
descriptorResult, descriptor.resType, descriptor.res.array.hArray);
|
|
}
|
|
std::printf("Synthetic DLSS texture resource setup: CUDA result=%d\n", textureSetupResult);
|
|
}
|
|
|
|
D4rCudaDevicePtr colorDevice = 0;
|
|
D4rCudaDevicePtr depthDevice = 0;
|
|
D4rCudaDevicePtr motionDevice = 0;
|
|
D4rCudaDevicePtr outputDevice = 0;
|
|
auto allocate_and_upload = [&](const char* label, D4rCudaDevicePtr& device,
|
|
const void* source, size_t bytes) {
|
|
int result = alloc(&device, bytes);
|
|
std::printf("Synthetic DLSS eval cuMemAlloc(%s): result=%d ptr=0x%llx bytes=%zu\n",
|
|
label, result, device, bytes);
|
|
if (result == 0)
|
|
result = copyHtoD(device, source, bytes, nullptr);
|
|
std::printf("Synthetic DLSS eval upload(%s): result=%d\n", label, result);
|
|
return result;
|
|
};
|
|
|
|
int cudaResult = textureMode ? textureSetupResult : 0;
|
|
if (cudaResult == 0 && !textureMode)
|
|
cudaResult = allocate_and_upload("Color", colorDevice, color.data(), colorBytes);
|
|
if (cudaResult == 0 && !textureMode)
|
|
cudaResult = allocate_and_upload("Depth", depthDevice, depth.data(), depthBytes);
|
|
if (cudaResult == 0 && !textureMode)
|
|
cudaResult = allocate_and_upload("MotionVectors", motionDevice, motion.data(), motionBytes);
|
|
if (cudaResult == 0 && !surfaceMode)
|
|
cudaResult = allocate_and_upload("Output", outputDevice, output.data(), outputBytes);
|
|
if (cudaResult == 0)
|
|
cudaResult = synchronize();
|
|
std::printf("Synthetic DLSS eval input upload/sync: CUDA result=%d\n", cudaResult);
|
|
|
|
if (cudaResult == 0)
|
|
{
|
|
if (scratchDevice != 0 && scratchBytes != 0)
|
|
{
|
|
ngx_set(parameters, NVSDK_NGX_Parameter_Scratch,
|
|
ngx_pointer_from_handle(scratchDevice));
|
|
ngx_set(parameters, NVSDK_NGX_Parameter_Scratch_SizeInBytes,
|
|
static_cast<unsigned long long>(scratchBytes));
|
|
}
|
|
ngx_set(parameters, NVSDK_NGX_EParameter_EvaluationNode, 0u);
|
|
ngx_set(parameters, NVSDK_NGX_Parameter_Width, inputWidth);
|
|
ngx_set(parameters, NVSDK_NGX_Parameter_Height, inputHeight);
|
|
ngx_set(parameters, NVSDK_NGX_Parameter_OutWidth, outputWidth);
|
|
ngx_set(parameters, NVSDK_NGX_Parameter_OutHeight, outputHeight);
|
|
ngx_set(parameters, NVSDK_NGX_Parameter_PerfQualityValue,
|
|
static_cast<int>(NVSDK_NGX_PerfQuality_Value_MaxQuality));
|
|
ngx_set(parameters, NVSDK_NGX_Parameter_DLSS_Feature_Create_Flags,
|
|
static_cast<int>(NVSDK_NGX_DLSS_Feature_Flags_None));
|
|
ngx_set(parameters, NVSDK_NGX_Parameter_DLSS_Enable_Output_Subrects, 0);
|
|
void* colorResource = textureMode
|
|
? static_cast<void*>(&colorTexture) : static_cast<void*>(&colorDevice);
|
|
void* depthResource = textureMode
|
|
? static_cast<void*>(&depthTexture) : static_cast<void*>(&depthDevice);
|
|
void* motionResource = textureMode
|
|
? static_cast<void*>(&motionTexture) : static_cast<void*>(&motionDevice);
|
|
void* exposureResource = textureMode
|
|
? static_cast<void*>(&exposureTexture) : static_cast<void*>(nullptr);
|
|
void* outputResource = surfaceMode
|
|
? static_cast<void*>(&outputSurface) : static_cast<void*>(&outputDevice);
|
|
ngx_set(parameters, NVSDK_NGX_Parameter_Color, colorResource);
|
|
ngx_set(parameters, NVSDK_NGX_Parameter_Color_Format, static_cast<int>(NVSDK_NGX_Buffer_Format_RGBA16F));
|
|
ngx_set(parameters, NVSDK_NGX_Parameter_Color_SizeInBytes, static_cast<unsigned long long>(colorBytes));
|
|
ngx_set(parameters, NVSDK_NGX_Parameter_Output, outputResource);
|
|
if (!surfaceMode)
|
|
{
|
|
ngx_set(parameters, NVSDK_NGX_Parameter_Output_Format,
|
|
static_cast<int>(NVSDK_NGX_Buffer_Format_RGBA16F));
|
|
ngx_set(parameters, NVSDK_NGX_Parameter_Output_SizeInBytes,
|
|
static_cast<unsigned long long>(outputBytes));
|
|
}
|
|
ngx_set(parameters, NVSDK_NGX_Parameter_Depth, depthResource);
|
|
ngx_set(parameters, NVSDK_NGX_Parameter_MotionVectors, motionResource);
|
|
ngx_set(parameters, NVSDK_NGX_Parameter_Sharpness, 0.0f);
|
|
ngx_set(parameters, NVSDK_NGX_Parameter_Jitter_Offset_X, 0.0f);
|
|
ngx_set(parameters, NVSDK_NGX_Parameter_Jitter_Offset_Y, 0.0f);
|
|
ngx_set(parameters, NVSDK_NGX_Parameter_MV_Scale_X, 1.0f);
|
|
ngx_set(parameters, NVSDK_NGX_Parameter_MV_Scale_Y, 1.0f);
|
|
ngx_set(parameters, NVSDK_NGX_Parameter_Reset, 1);
|
|
ngx_set(parameters, NVSDK_NGX_Parameter_TransparencyMask, static_cast<void*>(nullptr));
|
|
ngx_set(parameters, NVSDK_NGX_Parameter_ExposureTexture, exposureResource);
|
|
ngx_set(parameters, NVSDK_NGX_Parameter_DLSS_Input_Bias_Current_Color_Mask, static_cast<void*>(nullptr));
|
|
ngx_set(parameters, NVSDK_NGX_Parameter_GBuffer_Albedo, static_cast<void*>(nullptr));
|
|
ngx_set(parameters, NVSDK_NGX_Parameter_GBuffer_Roughness, static_cast<void*>(nullptr));
|
|
ngx_set(parameters, NVSDK_NGX_Parameter_GBuffer_Metallic, static_cast<void*>(nullptr));
|
|
ngx_set(parameters, NVSDK_NGX_Parameter_GBuffer_Specular, static_cast<void*>(nullptr));
|
|
ngx_set(parameters, NVSDK_NGX_Parameter_GBuffer_Subsurface, static_cast<void*>(nullptr));
|
|
ngx_set(parameters, NVSDK_NGX_Parameter_GBuffer_Normals, static_cast<void*>(nullptr));
|
|
ngx_set(parameters, NVSDK_NGX_Parameter_GBuffer_ShadingModelId, static_cast<void*>(nullptr));
|
|
ngx_set(parameters, NVSDK_NGX_Parameter_GBuffer_MaterialId, static_cast<void*>(nullptr));
|
|
ngx_set(parameters, NVSDK_NGX_Parameter_GBuffer_Atrrib_8, static_cast<void*>(nullptr));
|
|
ngx_set(parameters, NVSDK_NGX_Parameter_GBuffer_Atrrib_9, static_cast<void*>(nullptr));
|
|
ngx_set(parameters, NVSDK_NGX_Parameter_GBuffer_Atrrib_10, static_cast<void*>(nullptr));
|
|
ngx_set(parameters, NVSDK_NGX_Parameter_GBuffer_Atrrib_11, static_cast<void*>(nullptr));
|
|
ngx_set(parameters, NVSDK_NGX_Parameter_GBuffer_Atrrib_12, static_cast<void*>(nullptr));
|
|
ngx_set(parameters, NVSDK_NGX_Parameter_GBuffer_Atrrib_13, static_cast<void*>(nullptr));
|
|
ngx_set(parameters, NVSDK_NGX_Parameter_GBuffer_Atrrib_14, static_cast<void*>(nullptr));
|
|
ngx_set(parameters, NVSDK_NGX_Parameter_GBuffer_Atrrib_15, static_cast<void*>(nullptr));
|
|
ngx_set(parameters, NVSDK_NGX_Parameter_TonemapperType, 0u);
|
|
ngx_set(parameters, NVSDK_NGX_Parameter_MotionVectors3D, static_cast<void*>(nullptr));
|
|
ngx_set(parameters, NVSDK_NGX_Parameter_IsParticleMask, static_cast<void*>(nullptr));
|
|
ngx_set(parameters, NVSDK_NGX_Parameter_AnimatedTextureMask, static_cast<void*>(nullptr));
|
|
ngx_set(parameters, NVSDK_NGX_Parameter_DepthHighRes, static_cast<void*>(nullptr));
|
|
ngx_set(parameters, NVSDK_NGX_Parameter_Position_ViewSpace, static_cast<void*>(nullptr));
|
|
ngx_set(parameters, NVSDK_NGX_Parameter_FrameTimeDeltaInMsec, 16.666667f);
|
|
ngx_set(parameters, NVSDK_NGX_Parameter_RayTracingHitDistance, static_cast<void*>(nullptr));
|
|
ngx_set(parameters, NVSDK_NGX_Parameter_MotionVectorsReflection, static_cast<void*>(nullptr));
|
|
ngx_set(parameters, NVSDK_NGX_Parameter_DLSS_Input_Color_Subrect_Base_X, 0u);
|
|
ngx_set(parameters, NVSDK_NGX_Parameter_DLSS_Input_Color_Subrect_Base_Y, 0u);
|
|
ngx_set(parameters, NVSDK_NGX_Parameter_DLSS_Input_Depth_Subrect_Base_X, 0u);
|
|
ngx_set(parameters, NVSDK_NGX_Parameter_DLSS_Input_Depth_Subrect_Base_Y, 0u);
|
|
ngx_set(parameters, NVSDK_NGX_Parameter_DLSS_Input_MV_SubrectBase_X, 0u);
|
|
ngx_set(parameters, NVSDK_NGX_Parameter_DLSS_Input_MV_SubrectBase_Y, 0u);
|
|
ngx_set(parameters, NVSDK_NGX_Parameter_DLSS_Input_Translucency_SubrectBase_X, 0u);
|
|
ngx_set(parameters, NVSDK_NGX_Parameter_DLSS_Input_Translucency_SubrectBase_Y, 0u);
|
|
ngx_set(parameters, NVSDK_NGX_Parameter_DLSS_Input_Bias_Current_Color_SubrectBase_X, 0u);
|
|
ngx_set(parameters, NVSDK_NGX_Parameter_DLSS_Input_Bias_Current_Color_SubrectBase_Y, 0u);
|
|
ngx_set(parameters, NVSDK_NGX_Parameter_DLSS_Output_Subrect_Base_X, 0u);
|
|
ngx_set(parameters, NVSDK_NGX_Parameter_DLSS_Output_Subrect_Base_Y, 0u);
|
|
ngx_set(parameters, NVSDK_NGX_Parameter_DLSS_Render_Subrect_Dimensions_Width, inputWidth);
|
|
ngx_set(parameters, NVSDK_NGX_Parameter_DLSS_Render_Subrect_Dimensions_Height, inputHeight);
|
|
ngx_set(parameters, NVSDK_NGX_Parameter_DLSS_Pre_Exposure, 1.0f);
|
|
ngx_set(parameters, NVSDK_NGX_Parameter_DLSS_Exposure_Scale, 1.0f);
|
|
ngx_set(parameters, NVSDK_NGX_Parameter_DLSS_Indicator_Invert_X_Axis, 0);
|
|
ngx_set(parameters, NVSDK_NGX_Parameter_DLSS_Indicator_Invert_Y_Axis, 0);
|
|
|
|
const char* doubleFloatTest = std::getenv("D4R_NGX_DOUBLE_FLOAT_TEST");
|
|
if (doubleFloatTest != nullptr && std::strcmp(doubleFloatTest, "1") == 0)
|
|
ngx_set(parameters, NVSDK_NGX_Parameter_MV_Scale_X, static_cast<double>(1.0));
|
|
|
|
void* checkColor = nullptr;
|
|
unsigned long long checkColorAsUll = 0;
|
|
float checkMvScale = 0.0f;
|
|
double checkMvScaleDouble = 0.0;
|
|
const NVSDK_NGX_Result colorGet = ngx_get_void(
|
|
parameters, NVSDK_NGX_Parameter_Color, &checkColor);
|
|
const NVSDK_NGX_Result colorUllGet = ngx_get_ull(
|
|
parameters, NVSDK_NGX_Parameter_Color, &checkColorAsUll);
|
|
const NVSDK_NGX_Result mvScaleGet = ngx_get_float(
|
|
parameters, NVSDK_NGX_Parameter_MV_Scale_X, &checkMvScale);
|
|
const NVSDK_NGX_Result mvScaleDoubleGet = ngx_get_double(
|
|
parameters, NVSDK_NGX_Parameter_MV_Scale_X, &checkMvScaleDouble);
|
|
std::printf("Synthetic DLSS parameter round-trip: Color=%p result=0x%08x asULL=0x%llx result=0x%08x MV.Scale.X=%g result=0x%08x asDouble=%g result=0x%08x\n",
|
|
checkColor, static_cast<unsigned int>(colorGet), checkColorAsUll,
|
|
static_cast<unsigned int>(colorUllGet), checkMvScale,
|
|
static_cast<unsigned int>(mvScaleGet), checkMvScaleDouble,
|
|
static_cast<unsigned int>(mvScaleDoubleGet));
|
|
|
|
float msvcAbiMvScale = 0.0f;
|
|
unsigned int msvcAbiWidth = 0;
|
|
const unsigned int msvcAbiMvScaleResult = d4r_ngx_parameter_float_roundtrip(
|
|
parameters, NVSDK_NGX_Parameter_MV_Scale_X, 1.0f, &msvcAbiMvScale);
|
|
const unsigned int msvcAbiWidthResult = d4r_ngx_parameter_uint_roundtrip(
|
|
parameters, NVSDK_NGX_Parameter_Width, inputWidth, &msvcAbiWidth);
|
|
std::printf("MSVC ABI parameter round-trip: MV.Scale.X=%g result=0x%08x Width=%u result=0x%08x\n",
|
|
msvcAbiMvScale, msvcAbiMvScaleResult, msvcAbiWidth, msvcAbiWidthResult);
|
|
|
|
const char* proxyMode = std::getenv("D4R_NGX_PARAMETER_PROXY");
|
|
const bool useParameterProxy = proxyMode != nullptr && std::strcmp(proxyMode, "1") == 0;
|
|
NVSDK_NGX_Parameter* evalParameters = parameters;
|
|
std::vector<unsigned long long> proxyStorage;
|
|
if (useParameterProxy)
|
|
{
|
|
const size_t proxyBytes = d4r_ngx_parameter_proxy_size();
|
|
proxyStorage.resize((proxyBytes + sizeof(unsigned long long) - 1) /
|
|
sizeof(unsigned long long));
|
|
d4r_ngx_parameter_proxy_construct(proxyStorage.data(), parameters);
|
|
evalParameters = reinterpret_cast<NVSDK_NGX_Parameter*>(proxyStorage.data());
|
|
std::printf("Synthetic DLSS parameter proxy: %zu bytes\n", proxyBytes);
|
|
}
|
|
|
|
const NVSDK_NGX_Result evalResult = useCEvaluate
|
|
? evaluateFeatureC(featureHandle, evalParameters, nullptr)
|
|
: evaluateFeature(featureHandle, evalParameters, nullptr);
|
|
print_ngx_result(useCEvaluate
|
|
? "CUDA_EvaluateFeature_C(DLSS SR; synthetic RGBA16F test pattern)"
|
|
: "CUDA_EvaluateFeature(DLSS SR; synthetic RGBA16F test pattern)", evalResult);
|
|
if (useParameterProxy)
|
|
{
|
|
const unsigned int traceCount = d4r_ngx_parameter_proxy_count(proxyStorage.data());
|
|
const unsigned int droppedCount = d4r_ngx_parameter_proxy_dropped(proxyStorage.data());
|
|
std::printf("Synthetic DLSS parameter proxy trace: %u records, %u dropped\n",
|
|
traceCount, droppedCount);
|
|
for (unsigned int index = 0; index < traceCount && index < 128; ++index)
|
|
{
|
|
D4rNgxParamLogRecord record{};
|
|
if (d4r_ngx_parameter_proxy_copy_record(proxyStorage.data(), index, &record))
|
|
std::printf("NGX parameter trace[%u]: %c/%c %s result=0x%08x value=0x%llx\n",
|
|
index, record.operation, record.valueType, record.name,
|
|
record.result, record.value);
|
|
}
|
|
}
|
|
if (evalResult == NVSDK_NGX_Result_Success)
|
|
{
|
|
cudaResult = synchronize();
|
|
std::printf("Synthetic DLSS eval cuCtxSynchronize: CUDA result=%d\n", cudaResult);
|
|
if (cudaResult == 0 && surfaceMode)
|
|
{
|
|
D4rCudaMemcpy2D copyBack{};
|
|
copyBack.srcMemoryType = 3; // CUDA_MEMORYTYPE_ARRAY
|
|
copyBack.srcArray = outputArray;
|
|
copyBack.dstMemoryType = 1; // CUDA_MEMORYTYPE_HOST
|
|
copyBack.dstHost = output.data();
|
|
copyBack.dstPitch = outputWidth * 4 * sizeof(uint16_t);
|
|
copyBack.WidthInBytes = outputWidth * 4 * sizeof(uint16_t);
|
|
copyBack.Height = outputHeight;
|
|
cudaResult = copy2D(©Back);
|
|
}
|
|
else if (cudaResult == 0)
|
|
cudaResult = copyDtoH(output.data(), outputDevice, outputBytes);
|
|
std::printf("Synthetic DLSS eval output readback: CUDA result=%d bytes=%zu\n",
|
|
cudaResult, outputBytes);
|
|
if (cudaResult == 0)
|
|
{
|
|
const std::wstring rawPath = appData + L"\\dlss-synthetic-output.rgba16f";
|
|
const std::wstring ppmPath = appData + L"\\dlss-synthetic-output.ppm";
|
|
const bool rawWritten = write_file(rawPath, output.data(), outputBytes);
|
|
char ppmHeader[32]{};
|
|
const int headerLength = std::snprintf(ppmHeader, sizeof(ppmHeader),
|
|
"P6\n%u %u\n255\n", outputWidth, outputHeight);
|
|
std::vector<unsigned char> ppm(static_cast<size_t>(headerLength) + outputPixels * 3);
|
|
std::memcpy(ppm.data(), ppmHeader, static_cast<size_t>(headerLength));
|
|
size_t ppmOffset = static_cast<size_t>(headerLength);
|
|
size_t nonzero = 0;
|
|
double sum = 0.0;
|
|
for (size_t pixel = 0; pixel < outputPixels; ++pixel)
|
|
{
|
|
for (size_t channel = 0; channel < 3; ++channel)
|
|
{
|
|
float value = half_to_float(output[pixel * 4 + channel]);
|
|
if (!std::isfinite(value))
|
|
value = 0.0f;
|
|
if (value > 0.0f)
|
|
++nonzero;
|
|
sum += value;
|
|
value = std::clamp(value, 0.0f, 1.0f);
|
|
const float srgb = value <= 0.0031308f ? value * 12.92f
|
|
: 1.055f * std::pow(value, 1.0f / 2.4f) - 0.055f;
|
|
ppm[ppmOffset++] = static_cast<unsigned char>(std::lround(srgb * 255.0f));
|
|
}
|
|
}
|
|
const bool ppmWritten = write_file(ppmPath, ppm.data(), ppmOffset);
|
|
std::printf("Synthetic DLSS output: raw=%s preview=%s positiveRGB=%zu/%zu meanRGB=%f\n",
|
|
rawWritten ? "written" : "failed", ppmWritten ? "written" : "failed",
|
|
nonzero, outputPixels * 3, sum / static_cast<double>(outputPixels * 3));
|
|
}
|
|
}
|
|
}
|
|
|
|
if (textureMode)
|
|
{
|
|
if (outputSurface != 0) surfaceDestroy(outputSurface);
|
|
if (colorTexture != 0) textureDestroy(colorTexture);
|
|
if (depthTexture != 0) textureDestroy(depthTexture);
|
|
if (motionTexture != 0) textureDestroy(motionTexture);
|
|
if (exposureTexture != 0) textureDestroy(exposureTexture);
|
|
if (colorArray != nullptr) arrayDestroy(colorArray);
|
|
if (depthArray != nullptr) arrayDestroy(depthArray);
|
|
if (motionArray != nullptr) arrayDestroy(motionArray);
|
|
if (exposureArray != nullptr) arrayDestroy(exposureArray);
|
|
if (outputArray != nullptr) arrayDestroy(outputArray);
|
|
}
|
|
|
|
for (D4rCudaDevicePtr pointer : {outputDevice, motionDevice, depthDevice, colorDevice})
|
|
{
|
|
if (pointer != 0)
|
|
std::printf("Synthetic DLSS eval cuMemFree(0x%llx): result=%d\n", pointer, free(pointer));
|
|
}
|
|
FreeLibrary(cuda);
|
|
}
|
|
|
|
static void set_cuda_luid_from_amd_dxgi_adapter()
|
|
{
|
|
HMODULE dxgi = LoadLibraryA("dxgi.dll");
|
|
if (dxgi == nullptr)
|
|
{
|
|
std::printf("DXGI unavailable for CUDA LUID matching: GetLastError=%lu\n", GetLastError());
|
|
return;
|
|
}
|
|
using CreateFactoryFn = HRESULT(WINAPI*)(REFIID, void**);
|
|
auto createFactory = load_export<CreateFactoryFn>(dxgi, "CreateDXGIFactory1");
|
|
if (createFactory == nullptr)
|
|
{
|
|
std::printf("CreateDXGIFactory1 unavailable for CUDA LUID matching\n");
|
|
FreeLibrary(dxgi);
|
|
return;
|
|
}
|
|
|
|
constexpr GUID iidFactory1 = {0x770aae78, 0xf26f, 0x4dba, {0xa8, 0x29, 0x25, 0x3c, 0x83, 0xd1, 0xb3, 0x87}};
|
|
IDXGIFactory1* factory = nullptr;
|
|
HRESULT hr = createFactory(iidFactory1, reinterpret_cast<void**>(&factory));
|
|
if (FAILED(hr) || factory == nullptr)
|
|
{
|
|
std::printf("CreateDXGIFactory1 failed while matching CUDA LUID: HRESULT=0x%08lx\n",
|
|
static_cast<unsigned long>(hr));
|
|
FreeLibrary(dxgi);
|
|
return;
|
|
}
|
|
|
|
bool found = false;
|
|
IDXGIAdapter1* adapter = nullptr;
|
|
for (UINT index = 0; factory->EnumAdapters1(index, &adapter) != DXGI_ERROR_NOT_FOUND; ++index)
|
|
{
|
|
DXGI_ADAPTER_DESC1 description{};
|
|
if (SUCCEEDED(adapter->GetDesc1(&description)) && description.VendorId == 0x1002)
|
|
{
|
|
char low[24]{};
|
|
char high[24]{};
|
|
std::snprintf(low, sizeof(low), "0x%08lx", static_cast<unsigned long>(description.AdapterLuid.LowPart));
|
|
std::snprintf(high, sizeof(high), "0x%08lx", static_cast<unsigned long>(description.AdapterLuid.HighPart));
|
|
SetEnvironmentVariableA("D4R_CUDA_LUID_LOW", low);
|
|
SetEnvironmentVariableA("D4R_CUDA_LUID_HIGH", high);
|
|
SetEnvironmentVariableA("D4R_CUDA_NODE_MASK", "1");
|
|
std::printf("CUDA device LUID override from AMD DXGI adapter: %08lx:%08lx nodeMask=1\n",
|
|
static_cast<unsigned long>(description.AdapterLuid.HighPart),
|
|
static_cast<unsigned long>(description.AdapterLuid.LowPart));
|
|
found = true;
|
|
adapter->Release();
|
|
adapter = nullptr;
|
|
break;
|
|
}
|
|
adapter->Release();
|
|
adapter = nullptr;
|
|
}
|
|
if (!found)
|
|
std::printf("No AMD DXGI adapter found for CUDA LUID matching\n");
|
|
factory->Release();
|
|
FreeLibrary(dxgi);
|
|
}
|
|
|
|
int main(int argc, char** argv)
|
|
{
|
|
if (argc != 4)
|
|
{
|
|
std::fprintf(stderr,
|
|
"usage: ngx_cuda_probe.exe PATH_TO_NGX_CORE_DLL PATH_TO_NVNGX_DLSS_DLL WRITABLE_APPDATA_DIRECTORY\n");
|
|
return 2;
|
|
}
|
|
|
|
SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX);
|
|
set_cuda_luid_from_amd_dxgi_adapter();
|
|
const char* corePath = argv[1];
|
|
const char* featureDllPath = argv[2];
|
|
std::wstring appData = utf8_to_wide(argv[3]);
|
|
std::wstring featureDirectory = utf8_to_wide(featureDllPath);
|
|
if (appData.empty() || featureDirectory.empty())
|
|
{
|
|
std::fprintf(stderr, "Invalid UTF-8 feature-DLL path or appdata path argument\n");
|
|
return 2;
|
|
}
|
|
|
|
const size_t separator = featureDirectory.find_last_of(L"\\/");
|
|
if (separator == std::wstring::npos)
|
|
featureDirectory = L".";
|
|
else
|
|
featureDirectory.resize(separator);
|
|
|
|
const wchar_t* featurePaths[] = {featureDirectory.c_str()};
|
|
NVSDK_NGX_FeatureCommonInfo commonInfo{};
|
|
commonInfo.PathListInfo.Path = featurePaths;
|
|
commonInfo.PathListInfo.Length = 1;
|
|
|
|
HMODULE core = LoadLibraryA(corePath);
|
|
if (core == nullptr)
|
|
{
|
|
std::fprintf(stderr, "LoadLibraryA(%s) failed: GetLastError=%lu\n", corePath, GetLastError());
|
|
return 1;
|
|
}
|
|
std::printf("Loaded NGX core: %s\n", corePath);
|
|
std::printf("DLSS SR feature search directory: %ls\n", featureDirectory.c_str());
|
|
|
|
auto init = load_export<decltype(&NVSDK_NGX_CUDA_Init)>(core, "NVSDK_NGX_CUDA_Init");
|
|
auto shutdown = load_export<decltype(&NVSDK_NGX_CUDA_Shutdown)>(core, "NVSDK_NGX_CUDA_Shutdown");
|
|
auto getCapabilityParameters = load_export<decltype(&NVSDK_NGX_CUDA_GetCapabilityParameters)>(
|
|
core, "NVSDK_NGX_CUDA_GetCapabilityParameters");
|
|
const auto getLegacyParameters = load_export<D4rNgxGetParameters>(core, "NVSDK_NGX_CUDA_GetParameters");
|
|
auto destroyParameters = load_export<decltype(&NVSDK_NGX_CUDA_DestroyParameters)>(
|
|
core, "NVSDK_NGX_CUDA_DestroyParameters");
|
|
auto getScratchBufferSize = load_export<decltype(&NVSDK_NGX_CUDA_GetScratchBufferSize)>(
|
|
core, "NVSDK_NGX_CUDA_GetScratchBufferSize");
|
|
auto createFeature = load_export<decltype(&NVSDK_NGX_CUDA_CreateFeature)>(core, "NVSDK_NGX_CUDA_CreateFeature");
|
|
auto releaseFeature = load_export<decltype(&NVSDK_NGX_CUDA_ReleaseFeature)>(core, "NVSDK_NGX_CUDA_ReleaseFeature");
|
|
auto evaluateFeature = load_export<decltype(&NVSDK_NGX_CUDA_EvaluateFeature)>(core, "NVSDK_NGX_CUDA_EvaluateFeature");
|
|
auto evaluateFeatureC = load_export<decltype(&NVSDK_NGX_CUDA_EvaluateFeature_C)>(
|
|
core, "NVSDK_NGX_CUDA_EvaluateFeature_C");
|
|
const char* evaluateApiMode = std::getenv("D4R_NGX_USE_C_EVALUATE");
|
|
const bool useCEvaluate = evaluateApiMode != nullptr && std::strcmp(evaluateApiMode, "1") == 0;
|
|
g_ngxParameterApi.setULL = load_export<PFN_NVSDK_NGX_Parameter_SetULL>(core, "NVSDK_NGX_Parameter_SetULL");
|
|
g_ngxParameterApi.setF = load_export<PFN_NVSDK_NGX_Parameter_SetF>(core, "NVSDK_NGX_Parameter_SetF");
|
|
g_ngxParameterApi.setD = load_export<PFN_NVSDK_NGX_Parameter_SetD>(core, "NVSDK_NGX_Parameter_SetD");
|
|
g_ngxParameterApi.setUI = load_export<PFN_NVSDK_NGX_Parameter_SetUI>(core, "NVSDK_NGX_Parameter_SetUI");
|
|
g_ngxParameterApi.setI = load_export<PFN_NVSDK_NGX_Parameter_SetI>(core, "NVSDK_NGX_Parameter_SetI");
|
|
g_ngxParameterApi.setVoidPointer = load_export<PFN_NVSDK_NGX_Parameter_SetVoidPointer>(
|
|
core, "NVSDK_NGX_Parameter_SetVoidPointer");
|
|
g_ngxParameterApi.getULL = load_export<PFN_NVSDK_NGX_Parameter_GetULL>(core, "NVSDK_NGX_Parameter_GetULL");
|
|
g_ngxParameterApi.getF = load_export<PFN_NVSDK_NGX_Parameter_GetF>(core, "NVSDK_NGX_Parameter_GetF");
|
|
g_ngxParameterApi.getD = load_export<PFN_NVSDK_NGX_Parameter_GetD>(core, "NVSDK_NGX_Parameter_GetD");
|
|
g_ngxParameterApi.getUI = load_export<PFN_NVSDK_NGX_Parameter_GetUI>(core, "NVSDK_NGX_Parameter_GetUI");
|
|
g_ngxParameterApi.getI = load_export<PFN_NVSDK_NGX_Parameter_GetI>(core, "NVSDK_NGX_Parameter_GetI");
|
|
g_ngxParameterApi.getVoidPointer = load_export<PFN_NVSDK_NGX_Parameter_GetVoidPointer>(
|
|
core, "NVSDK_NGX_Parameter_GetVoidPointer");
|
|
std::printf("NGX parameter C wrappers: SetULL=%p SetF=%p SetUI=%p SetI=%p SetPtr=%p GetI=%p\n",
|
|
reinterpret_cast<void*>(g_ngxParameterApi.setULL),
|
|
reinterpret_cast<void*>(g_ngxParameterApi.setF),
|
|
reinterpret_cast<void*>(g_ngxParameterApi.setUI),
|
|
reinterpret_cast<void*>(g_ngxParameterApi.setI),
|
|
reinterpret_cast<void*>(g_ngxParameterApi.setVoidPointer),
|
|
reinterpret_cast<void*>(g_ngxParameterApi.getI));
|
|
std::printf("NGX CUDA EvaluateFeature C export: %p\n",
|
|
reinterpret_cast<void*>(evaluateFeatureC));
|
|
const char* parameterMode = std::getenv("D4R_NGX_USE_LEGACY_PARAMETERS");
|
|
const bool useLegacyParameters = parameterMode != nullptr && std::strcmp(parameterMode, "1") == 0;
|
|
if (init == nullptr || (!useLegacyParameters && getCapabilityParameters == nullptr) ||
|
|
(useLegacyParameters && getLegacyParameters == nullptr) || destroyParameters == nullptr ||
|
|
getScratchBufferSize == nullptr || createFeature == nullptr ||
|
|
releaseFeature == nullptr || evaluateFeature == nullptr ||
|
|
(useCEvaluate && evaluateFeatureC == nullptr))
|
|
{
|
|
std::fprintf(stderr, "The NGX core is missing one or more CUDA API exports\n");
|
|
FreeLibrary(core);
|
|
return 1;
|
|
}
|
|
|
|
NVSDK_NGX_FeatureDiscoveryInfo discovery{};
|
|
discovery.SDKVersion = static_cast<NVSDK_NGX_Version>(0x13);
|
|
if (const char* apiVersion = std::getenv("D4R_NGX_API_VERSION"))
|
|
discovery.SDKVersion = static_cast<NVSDK_NGX_Version>(std::strtoul(apiVersion, nullptr, 0));
|
|
discovery.FeatureID = NVSDK_NGX_Feature_SuperSampling;
|
|
discovery.Identifier.IdentifierType = NVSDK_NGX_Application_Identifier_Type_Application_Id;
|
|
discovery.Identifier.v.ApplicationId = 241534723ULL;
|
|
discovery.ApplicationDataPath = appData.c_str();
|
|
discovery.FeatureInfo = &commonInfo;
|
|
|
|
std::printf("NGX API version passed to core: 0x%08x\n", static_cast<unsigned int>(discovery.SDKVersion));
|
|
NVSDK_NGX_Result result = init(discovery.Identifier.v.ApplicationId, discovery.ApplicationDataPath,
|
|
&commonInfo, discovery.SDKVersion);
|
|
print_ngx_result("CUDA_Init(DLSS SR)", result);
|
|
|
|
if (result == NVSDK_NGX_Result_Success)
|
|
{
|
|
NVSDK_NGX_Parameter* parameters = nullptr;
|
|
NVSDK_NGX_Result paramsResult = useLegacyParameters
|
|
? getLegacyParameters(¶meters) : getCapabilityParameters(¶meters);
|
|
print_ngx_result(useLegacyParameters ? "CUDA_GetParameters(legacy)" : "CUDA_GetCapabilityParameters",
|
|
paramsResult);
|
|
if (paramsResult == NVSDK_NGX_Result_Success && parameters != nullptr)
|
|
{
|
|
int available = -1;
|
|
NVSDK_NGX_Result availabilityResult = ngx_get_i(parameters,
|
|
NVSDK_NGX_Parameter_SuperSampling_Available, &available);
|
|
print_ngx_result("Parameters.Get(SuperSampling.Available)", availabilityResult);
|
|
std::printf("DLSS SR availability value: %d\n", available);
|
|
|
|
int featureInitResult = -1;
|
|
NVSDK_NGX_Result initStateResult = ngx_get_i(parameters,
|
|
NVSDK_NGX_Parameter_SuperSampling_FeatureInitResult, &featureInitResult);
|
|
print_ngx_result("Parameters.Get(SuperSampling.FeatureInitResult)", initStateResult);
|
|
std::printf("DLSS SR recorded feature-init result: 0x%08x\n",
|
|
static_cast<unsigned int>(featureInitResult));
|
|
int needsUpdatedDriver = -1;
|
|
NVSDK_NGX_Result driverStateResult = ngx_get_i(parameters,
|
|
NVSDK_NGX_Parameter_SuperSampling_NeedsUpdatedDriver, &needsUpdatedDriver);
|
|
print_ngx_result("Parameters.Get(SuperSampling.NeedsUpdatedDriver)", driverStateResult);
|
|
std::printf("DLSS SR needs updated driver: %d\n", needsUpdatedDriver);
|
|
|
|
ngx_set(parameters, NVSDK_NGX_Parameter_Width, 640u);
|
|
ngx_set(parameters, NVSDK_NGX_Parameter_Height, 360u);
|
|
ngx_set(parameters, NVSDK_NGX_Parameter_OutWidth, 1280u);
|
|
ngx_set(parameters, NVSDK_NGX_Parameter_OutHeight, 720u);
|
|
ngx_set(parameters, NVSDK_NGX_Parameter_PerfQualityValue,
|
|
static_cast<int>(NVSDK_NGX_PerfQuality_Value_MaxQuality));
|
|
ngx_set(parameters, NVSDK_NGX_Parameter_DLSS_Feature_Create_Flags,
|
|
static_cast<int>(NVSDK_NGX_DLSS_Feature_Flags_None));
|
|
ngx_set(parameters, NVSDK_NGX_Parameter_DLSS_Enable_Output_Subrects, 0);
|
|
|
|
unsigned int widthCheck = 0;
|
|
unsigned int outWidthCheck = 0;
|
|
const NVSDK_NGX_Result widthCheckResult = ngx_get_ui(
|
|
parameters, NVSDK_NGX_Parameter_Width, &widthCheck);
|
|
const NVSDK_NGX_Result outWidthCheckResult = ngx_get_ui(
|
|
parameters, NVSDK_NGX_Parameter_OutWidth, &outWidthCheck);
|
|
std::printf("NGX create parameter round-trip: Width=%u result=0x%08x OutWidth=%u result=0x%08x\n",
|
|
widthCheck, static_cast<unsigned int>(widthCheckResult), outWidthCheck,
|
|
static_cast<unsigned int>(outWidthCheckResult));
|
|
|
|
size_t scratchSize = 0;
|
|
NVSDK_NGX_Result scratchResult = getScratchBufferSize(
|
|
NVSDK_NGX_Feature_SuperSampling, parameters, &scratchSize);
|
|
print_ngx_result("CUDA_GetScratchBufferSize(DLSS SR)", scratchResult);
|
|
std::printf("DLSS SR scratch size: %llu bytes\n", static_cast<unsigned long long>(scratchSize));
|
|
|
|
const char* evaluate = std::getenv("D4R_NGX_EVALUATE");
|
|
const bool evaluateRequested = evaluate != nullptr && std::strcmp(evaluate, "1") == 0;
|
|
HMODULE scratchCuda = nullptr;
|
|
D4rCudaDevicePtr scratchDevice = 0;
|
|
size_t scratchBytes = scratchSize;
|
|
D4rCuMemFree scratchFree = nullptr;
|
|
if (evaluateRequested)
|
|
{
|
|
if (scratchBytes == 0)
|
|
scratchBytes = 64u * 1024u * 1024u;
|
|
scratchCuda = LoadLibraryA("nvcuda.dll");
|
|
if (scratchCuda != nullptr)
|
|
{
|
|
const auto scratchAlloc = load_export<D4rCuMemAlloc>(scratchCuda, "cuMemAlloc");
|
|
scratchFree = load_export<D4rCuMemFree>(scratchCuda, "cuMemFree");
|
|
const int scratchAllocResult = scratchAlloc != nullptr
|
|
? scratchAlloc(&scratchDevice, scratchBytes) : 801;
|
|
std::printf("Synthetic DLSS scratch allocation before create: CUDA result=%d ptr=0x%llx bytes=%zu\n",
|
|
scratchAllocResult, scratchDevice, scratchBytes);
|
|
if (scratchAllocResult == 0)
|
|
{
|
|
ngx_set(parameters, NVSDK_NGX_Parameter_Scratch,
|
|
reinterpret_cast<void*>(static_cast<uintptr_t>(scratchDevice)));
|
|
ngx_set(parameters, NVSDK_NGX_Parameter_Scratch_SizeInBytes,
|
|
static_cast<unsigned long long>(scratchBytes));
|
|
}
|
|
else
|
|
{
|
|
scratchDevice = 0;
|
|
scratchBytes = 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
std::printf("Synthetic DLSS scratch allocation: LoadLibraryA(nvcuda.dll) failed: %lu\n",
|
|
GetLastError());
|
|
scratchBytes = 0;
|
|
}
|
|
}
|
|
|
|
NVSDK_NGX_Handle* featureHandle = nullptr;
|
|
NVSDK_NGX_Result createResult = createFeature(
|
|
NVSDK_NGX_Feature_SuperSampling, parameters, &featureHandle);
|
|
print_ngx_result("CUDA_CreateFeature(DLSS SR)", createResult);
|
|
std::printf("DLSS SR feature handle: %s\n", featureHandle != nullptr ? "created" : "null");
|
|
if (createResult == NVSDK_NGX_Result_Success && featureHandle != nullptr)
|
|
{
|
|
if (evaluateRequested)
|
|
evaluate_synthetic_frame(parameters, featureHandle, evaluateFeature,
|
|
evaluateFeatureC, useCEvaluate, appData,
|
|
scratchDevice, scratchBytes);
|
|
NVSDK_NGX_Result releaseResult = releaseFeature(featureHandle);
|
|
print_ngx_result("CUDA_ReleaseFeature", releaseResult);
|
|
}
|
|
|
|
if (scratchDevice != 0 && scratchFree != nullptr)
|
|
std::printf("Synthetic DLSS scratch free: CUDA result=%d\n", scratchFree(scratchDevice));
|
|
if (scratchCuda != nullptr)
|
|
FreeLibrary(scratchCuda);
|
|
|
|
if (useLegacyParameters)
|
|
std::printf("CUDA_GetParameters map lifetime is managed by NGX; skipping DestroyParameters\n");
|
|
else
|
|
{
|
|
NVSDK_NGX_Result destroyResult = destroyParameters(parameters);
|
|
print_ngx_result("CUDA_DestroyParameters", destroyResult);
|
|
}
|
|
}
|
|
|
|
if (shutdown != nullptr)
|
|
{
|
|
NVSDK_NGX_Result shutdownResult = shutdown();
|
|
print_ngx_result("CUDA_Shutdown1", shutdownResult);
|
|
}
|
|
}
|
|
|
|
FreeLibrary(core);
|
|
return 0;
|
|
}
|