d4r: official NVIDIA DLSS on AMD GPUs under Linux and Proton

This commit is contained in:
ayo committed 2026-09-27 15:26:56 -04:00
commit 118173ecd7
128 files changed
+31333

No files matched your search

+194
View File
@@ -0,0 +1,194 @@
// Replays one captured DLSS kernel launch outside Wine with buffer-only
// arguments, using resource dumps from the Wine bridge's
// D4R_CUDA_LAUNCH_DUMP_DIR instrumentation.
//
// usage: replay_dlss_layer MODULE KERNEL GX,GY,GZ BX,BY,BZ SHARED OUTDIR WORD...
// MODULE PTX text or CUDA fatbin
// WORD one 8-byte packed-argument word: either a hex literal (0x...) or
// @FILE#0xOFFSET, which uploads FILE into a fresh device buffer (once
// per distinct FILE) and passes that buffer's address plus OFFSET.
// After the launch every uploaded buffer is written to OUTDIR/<basename>.out.
#include <dlfcn.h>
#include <cstdint>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <fstream>
#include <iterator>
#include <string>
#include <vector>
using CUresult = int;
using CUdevice = int;
using CUcontext = void*;
using CUmodule = void*;
using CUfunction = void*;
using CUstream = void*;
using CUdeviceptr = uint64_t;
template <typename Function> static Function load_function(void* library, const char* name)
{
void* raw = dlsym(library, name);
Function function{};
static_assert(sizeof(function) == sizeof(raw));
std::memcpy(&function, &raw, sizeof(function));
return function;
}
static bool read_file(const std::string& path, std::vector<char>& data)
{
std::ifstream input(path, std::ios::binary);
if (!input)
return false;
data.assign(std::istreambuf_iterator<char>(input), std::istreambuf_iterator<char>());
return true;
}
static bool parse_triple(const char* text, unsigned int values[3])
{
return std::sscanf(text, "%u,%u,%u", &values[0], &values[1], &values[2]) == 3;
}
struct Buffer
{
std::string path;
CUdeviceptr device = 0;
size_t bytes = 0;
};
int main(int argc, char** argv)
{
if (argc < 8)
{
std::fprintf(stderr, "usage: %s MODULE KERNEL GX,GY,GZ BX,BY,BZ SHARED OUTDIR WORD...\n", argv[0]);
return 2;
}
unsigned int grid[3], block[3];
if (!parse_triple(argv[3], grid) || !parse_triple(argv[4], block))
{
std::fprintf(stderr, "grid and block must be X,Y,Z\n");
return 2;
}
const unsigned int shared = static_cast<unsigned int>(std::strtoul(argv[5], nullptr, 0));
const std::string outputDirectory = argv[6];
std::vector<char> module;
if (!read_file(argv[1], module))
{
std::fprintf(stderr, "cannot read %s\n", argv[1]);
return 1;
}
module.push_back('\0'); // PTX text must be NUL terminated; harmless for fatbins
void* library = dlopen("libcuda.so", RTLD_NOW | RTLD_LOCAL);
if (library == nullptr)
{
std::fprintf(stderr, "dlopen(libcuda.so) failed: %s\n", dlerror());
return 1;
}
const auto init = load_function<CUresult (*)(unsigned int)>(library, "cuInit");
const auto deviceGet = load_function<CUresult (*)(CUdevice*, int)>(library, "cuDeviceGet");
const auto contextCreate = load_function<CUresult (*)(CUcontext*, unsigned int, CUdevice)>(library, "cuCtxCreate_v2");
const auto moduleLoad = load_function<CUresult (*)(CUmodule*, const void*)>(library, "cuModuleLoadData");
const auto moduleGetFunction = load_function<CUresult (*)(CUfunction*, CUmodule, const char*)>(library, "cuModuleGetFunction");
const auto alloc = load_function<CUresult (*)(CUdeviceptr*, size_t)>(library, "cuMemAlloc_v2");
const auto copyHtoD = load_function<CUresult (*)(CUdeviceptr, const void*, size_t)>(library, "cuMemcpyHtoD_v2");
const auto copyDtoH = load_function<CUresult (*)(void*, CUdeviceptr, size_t)>(library, "cuMemcpyDtoH_v2");
const auto launch = load_function<CUresult (*)(CUfunction, unsigned int, unsigned int, unsigned int, unsigned int,
unsigned int, unsigned int, unsigned int, CUstream, void**, void**)>(
library, "cuLaunchKernel");
const auto synchronize = load_function<CUresult (*)(void)>(library, "cuCtxSynchronize");
if (!init || !deviceGet || !contextCreate || !moduleLoad || !moduleGetFunction || !alloc ||
!copyHtoD || !copyDtoH || !launch || !synchronize)
{
std::fprintf(stderr, "ZLUDA libcuda.so is missing a required export\n");
return 1;
}
CUdevice device = 0;
CUcontext context = nullptr;
CUmodule loaded = nullptr;
CUfunction function = nullptr;
CUresult result = init(0);
if (result == 0)
result = deviceGet(&device, 0);
if (result == 0)
result = contextCreate(&context, 0, device);
if (result == 0)
result = moduleLoad(&loaded, module.data());
if (result == 0)
result = moduleGetFunction(&function, loaded, argv[2]);
if (result != 0)
{
std::fprintf(stderr, "module setup for %s failed: CUDA result=%d\n", argv[2], result);
return 1;
}
std::vector<Buffer> buffers;
std::vector<uint64_t> words;
for (int index = 7; index < argc; ++index)
{
const std::string word = argv[index];
if (word.empty() || word[0] != '@')
{
words.push_back(std::strtoull(word.c_str(), nullptr, 0));
continue;
}
const size_t plus = word.rfind('#');
const std::string path = word.substr(1, plus == std::string::npos ? std::string::npos : plus - 1);
const uint64_t offset = plus == std::string::npos ? 0 : std::strtoull(word.c_str() + plus + 1, nullptr, 0);
Buffer* buffer = nullptr;
for (Buffer& existing : buffers)
if (existing.path == path)
buffer = &existing;
if (buffer == nullptr)
{
std::vector<char> contents;
if (!read_file(path, contents))
{
std::fprintf(stderr, "cannot read %s\n", path.c_str());
return 1;
}
Buffer created;
created.path = path;
created.bytes = contents.size();
result = alloc(&created.device, created.bytes);
if (result == 0)
result = copyHtoD(created.device, contents.data(), created.bytes);
if (result != 0)
{
std::fprintf(stderr, "upload of %s failed: CUDA result=%d\n", path.c_str(), result);
return 1;
}
buffers.push_back(created);
buffer = &buffers.back();
}
words.push_back(buffer->device + offset);
}
size_t argumentBytes = words.size() * sizeof(uint64_t);
void* extra[] = {reinterpret_cast<void*>(1), words.data(), reinterpret_cast<void*>(2), &argumentBytes,
nullptr};
result = launch(function, grid[0], grid[1], grid[2], block[0], block[1], block[2], shared, nullptr,
nullptr, extra);
if (result == 0)
result = synchronize();
std::printf("%s grid=%u,%u,%u block=%u,%u,%u: CUDA result=%d\n", argv[2], grid[0], grid[1], grid[2],
block[0], block[1], block[2], result);
if (result != 0)
return 1;
for (const Buffer& buffer : buffers)
{
std::vector<char> contents(buffer.bytes);
result = copyDtoH(contents.data(), buffer.device, buffer.bytes);
const size_t slash = buffer.path.rfind('/');
const std::string name = outputDirectory + "/" +
(slash == std::string::npos ? buffer.path : buffer.path.substr(slash + 1)) + ".out";
std::ofstream output(name, std::ios::binary);
output.write(contents.data(), static_cast<std::streamsize>(contents.size()));
std::printf("wrote %s (%zu bytes, CUDA result=%d)\n", name.c_str(), buffer.bytes, result);
}
return 0;
}