TL;DR: Add an experimental FSR Ray Regeneration backend on Windows, run the K
network natively on HIP with Vulkan->HIP shared memory, extend K kernels to
gfx11 (RDNA3), and add dependency/packaging/test tooling around them.
Windows: FSR RR backend, native HIP K runner, gfx11 K kernels, tooling
FSR Ray Regeneration (experimental)
- Add fsr_rr_backend.{h,cpp}, fsr_rr_passes.h and the fsr_rr/ prepare and
compose compute shaders. They run AMD's FidelityFX denoiser
(amd_fidelityfx_denoiser_dx12.dll, SDK 2.3, not bundled) on a private
vkd3d-proton device.
- Add the amdxc64 shim (tools/windows/amdxc64_shim) and two vkd3d-proton
patches for libcxx includes. AMD's amdxc64.dll is never loaded.
- d4r_nvngx_windows: RrFeature now selects between the native DLSS RR
backend and the FSR backend (D4R_RR_BACKEND=fsr). After the denoiser it
runs an internal Super Sampling stage (feature 1) to upscale. If SR is
unavailable and output != render size, the frame fails; it is never
returned noisy.
- d4r.ini / player_config: new [RayReconstruction] FsrDenoiser,
FsrStabilityBias (auto or >= 0) and FsrDetail (0-1), with validation, and
matching D4R_FSR_* environment variables.
- Add the FSR RR fixture, output-check and ngx test scripts, and a shader
compile script.
Native HIP K runner (Windows)
- CMake: add d4r_engine_k_hip (d4r-k-hip) plus separate volk/engine copies,
because VK_USE_PLATFORM_WIN32_KHR changes volk's entry points.
- Share Vulkan memory with HIP via Win32 opaque handles on Windows
(VK_KHR_external_memory_win32) and via fds on Linux. Handle types are now
intptr_t, and the platform choice is in D4R_EXT_MEMORY_* macros.
- HipNetwork: add debugRepeatHashes and debugNodeMicros, exposed as
D4R_HIP_REPEAT_CHECK, D4R_HIP_REPEAT_ALL and D4R_HIP_NODE_PROFILE in
replay.cpp.
- replay.cpp: display-resolution-motion frames (FrameFlagDisplayMotion) no
longer require near2rnd == out2rnd. Both values must still be in (0, 1].
K kernels on gfx11
- Allow position-token and enc1 tiling on __GFX11__ as well as gfx12.
- Add an opt-in ds_bpermute cross-half exchange
(D4R_WINDOWS_GFX11_DS_EXCHANGE, enabled for K on Windows gfx11). M keeps
its LDS path.
- Fix a block-barrier race in the position layer. Without POS_VSHARE a fast
wave could overwrite its hb rows while a slower wave still read them for a
later head, giving rare wrong results on gfx1101 (enc0 outputs differing
between identical launches).
Packaging and install
- install.bat, d4r.ini, WINDOWS_README: FSR option, and
install_dependencies.py to install pinned NVIDIA dependencies with staged,
hash-verified replacement and rollback.
- Update the release package, local package refresh and test scripts.
- Add the InteropBatchInputCopies option (default false). Batching is faster
on some synthetic runs, but player temporal exactness is unresolved.
Tooling and tests
- K model: capture_k_weights, build_k_model, compare_k_outputs,
benchmark_k_hip, build_capture_runtime, test_k_model and the
zluda-k-output-capture patch. Captured weights and models are private
local assets and must not enter release archives.
- Synthetic probes: test_m_ngx, test_sr_dynamic,
prepare_rr_dynamic_fixture and the d3d12/rr_ngx probe updates.
- Add tests/windows/test_install_dependencies.py.
Docs
- Update the windows-fsr-rr, k-performance, local-package, rr-interop and
rr-model-cache docs. Add windows-parity-handoff.md and
windows-parity-continuation-prompt.md.
This commit is contained in:
1 parent
247fe1092d
commit
a617c818de
62 files changed
+5894
-89
No files matched your search
+49
-8
@@ -6,6 +6,14 @@
|
||||
#ifdef D4R_ENGINE_HIP
|
||||
#include "hip_net.h"
|
||||
#endif
|
||||
// Opaque memory handle shared with HIP: a file descriptor on Linux, a Win32 NT handle on Windows.
|
||||
#ifdef _WIN32
|
||||
#define D4R_EXT_MEMORY_EXTENSION "VK_KHR_external_memory_win32"
|
||||
#define D4R_EXT_MEMORY_HANDLE VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT
|
||||
#else
|
||||
#define D4R_EXT_MEMORY_EXTENSION VK_KHR_EXTERNAL_MEMORY_FD_EXTENSION_NAME
|
||||
#define D4R_EXT_MEMORY_HANDLE VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT
|
||||
#endif
|
||||
#include <algorithm>
|
||||
#include <chrono>
|
||||
#include <cstring>
|
||||
@@ -87,8 +95,8 @@ struct Context {
|
||||
throw std::runtime_error("VK_KHR_cooperative_matrix required");
|
||||
if (fp8 && std::none_of(extensions.begin(), extensions.end(), [](const auto& e) { return !std::strcmp(e.extensionName, VK_EXT_SHADER_FLOAT8_EXTENSION_NAME); }))
|
||||
throw std::runtime_error("VK_EXT_shader_float8 required for M");
|
||||
if (externalMemory && std::none_of(extensions.begin(), extensions.end(), [](const auto& e) { return !std::strcmp(e.extensionName, VK_KHR_EXTERNAL_MEMORY_FD_EXTENSION_NAME); }))
|
||||
throw std::runtime_error("VK_KHR_external_memory_fd required for the native HIP network");
|
||||
if (externalMemory && std::none_of(extensions.begin(), extensions.end(), [](const auto& e) { return !std::strcmp(e.extensionName, D4R_EXT_MEMORY_EXTENSION); }))
|
||||
throw std::runtime_error("external memory extension required for the native HIP network");
|
||||
VkPhysicalDeviceShaderFloat8FeaturesEXT float8{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_FLOAT8_FEATURES_EXT};
|
||||
VkPhysicalDeviceCooperativeMatrixFeaturesKHR matrix{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COOPERATIVE_MATRIX_FEATURES_KHR, fp8 ? &float8 : nullptr};
|
||||
VkPhysicalDeviceVulkan13Features f13{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_3_FEATURES, &matrix};
|
||||
@@ -137,7 +145,7 @@ struct Context {
|
||||
const char* enabled[3] = {VK_KHR_COOPERATIVE_MATRIX_EXTENSION_NAME};
|
||||
uint32_t enabledCount = 1;
|
||||
if (fp8) enabled[enabledCount++] = VK_EXT_SHADER_FLOAT8_EXTENSION_NAME;
|
||||
if (externalMemory) enabled[enabledCount++] = VK_KHR_EXTERNAL_MEMORY_FD_EXTENSION_NAME;
|
||||
if (externalMemory) enabled[enabledCount++] = D4R_EXT_MEMORY_EXTENSION;
|
||||
VkDeviceCreateInfo di{VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, &features};
|
||||
di.queueCreateInfoCount = 1; di.pQueueCreateInfos = &qi; di.enabledExtensionCount = enabledCount;
|
||||
di.ppEnabledExtensionNames = enabled;
|
||||
@@ -212,16 +220,16 @@ struct Buffer {
|
||||
};
|
||||
#ifdef D4R_ENGINE_HIP
|
||||
// A storage buffer whose memory another API (HIP) imports through a file descriptor, for the native network.
|
||||
struct Shared { VkBuffer buffer{}; VkDeviceMemory memory{}; VkDeviceSize allocation = 0; int fd = -1; };
|
||||
struct Shared { VkBuffer buffer{}; VkDeviceMemory memory{}; VkDeviceSize allocation = 0; intptr_t fd = -1; };
|
||||
static Shared shared(const Context& c, VkDeviceSize size) {
|
||||
Shared s;
|
||||
VkExternalMemoryBufferCreateInfo ei{VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_BUFFER_CREATE_INFO};
|
||||
ei.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT;
|
||||
ei.handleTypes = D4R_EXT_MEMORY_HANDLE;
|
||||
VkBufferCreateInfo bi{VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, &ei}; bi.size = size; bi.usage = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT;
|
||||
CK(vkCreateBuffer(c.device, &bi, nullptr, &s.buffer));
|
||||
VkMemoryRequirements r; vkGetBufferMemoryRequirements(c.device, s.buffer, &r);
|
||||
VkExportMemoryAllocateInfo xi{VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO};
|
||||
xi.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT;
|
||||
xi.handleTypes = D4R_EXT_MEMORY_HANDLE;
|
||||
VkMemoryAllocateInfo ai{VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, &xi}; ai.allocationSize = s.allocation = r.size;
|
||||
uint32_t index = c.memory.memoryTypeCount;
|
||||
for (uint32_t i = 0; i < c.memory.memoryTypeCount; ++i)
|
||||
@@ -229,11 +237,19 @@ static Shared shared(const Context& c, VkDeviceSize size) {
|
||||
if (index == c.memory.memoryTypeCount) throw std::runtime_error("no device-local memory type");
|
||||
ai.memoryTypeIndex = index;
|
||||
CK(vkAllocateMemory(c.device, &ai, nullptr, &s.memory)); CK(vkBindBufferMemory(c.device, s.buffer, s.memory, 0));
|
||||
#ifdef _WIN32
|
||||
VkMemoryGetWin32HandleInfoKHR gi{VK_STRUCTURE_TYPE_MEMORY_GET_WIN32_HANDLE_INFO_KHR};
|
||||
gi.memory = s.memory; gi.handleType = D4R_EXT_MEMORY_HANDLE;
|
||||
const auto getHandle = reinterpret_cast<PFN_vkGetMemoryWin32HandleKHR>(vkGetDeviceProcAddr(c.device, "vkGetMemoryWin32HandleKHR"));
|
||||
if (!getHandle) throw std::runtime_error("vkGetMemoryWin32HandleKHR is unavailable");
|
||||
HANDLE handle = nullptr; CK(getHandle(c.device, &gi, &handle)); s.fd = reinterpret_cast<intptr_t>(handle);
|
||||
#else
|
||||
VkMemoryGetFdInfoKHR gi{VK_STRUCTURE_TYPE_MEMORY_GET_FD_INFO_KHR};
|
||||
gi.memory = s.memory; gi.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT;
|
||||
gi.memory = s.memory; gi.handleType = D4R_EXT_MEMORY_HANDLE;
|
||||
const auto getFd = reinterpret_cast<PFN_vkGetMemoryFdKHR>(vkGetDeviceProcAddr(c.device, "vkGetMemoryFdKHR"));
|
||||
if (!getFd) throw std::runtime_error("vkGetMemoryFdKHR is unavailable");
|
||||
CK(getFd(c.device, &gi, &s.fd));
|
||||
int fd = -1; CK(getFd(c.device, &gi, &fd)); s.fd = fd;
|
||||
#endif
|
||||
return s;
|
||||
}
|
||||
#endif
|
||||
@@ -419,6 +435,31 @@ int run(const std::string& modelDir, const std::string& caseFile, const std::str
|
||||
context.submit();
|
||||
#ifdef D4R_ENGINE_HIP
|
||||
network->launch(); network->wait();
|
||||
static bool nodesProfiled = false;
|
||||
if (!nodesProfiled && std::getenv("D4R_HIP_NODE_PROFILE")) {
|
||||
nodesProfiled = true; float total = 0;
|
||||
auto micros = network->debugNodeMicros(0, 30);
|
||||
for (size_t k = 0; k < micros.size(); ++k) { std::cout << " node " << k << ": " << micros[k] << " us\n"; total += micros[k]; }
|
||||
std::cout << "hip node profile total (individually launched, phase 0): " << total << " us\n";
|
||||
}
|
||||
static bool repeatChecked = false;
|
||||
if (!repeatChecked && std::getenv("D4R_HIP_REPEAT_CHECK")) {
|
||||
repeatChecked = true;
|
||||
const uint32_t rounds = uint32_t(std::atoi(std::getenv("D4R_HIP_REPEAT_CHECK")));
|
||||
auto hashes = network->debugRepeatHashes(rounds); unsigned bad = 0;
|
||||
const size_t stride = hashes.size() / (size_t(rounds) * 8); // 1 unless D4R_HIP_REPEAT_ALL
|
||||
for (uint32_t phase = 0; phase < 8; ++phase)
|
||||
for (uint32_t r = 1; r < rounds; ++r) {
|
||||
bool any = false;
|
||||
for (size_t k = 0; k < stride; ++k)
|
||||
if (hashes[(size_t(r) * 8 + phase) * stride + k] != hashes[size_t(phase) * stride + k]) {
|
||||
any = true; std::cout << " mismatch round " << r << " phase " << phase << " slot " << k << " (0=output, 1+=owned alloc)\n";
|
||||
}
|
||||
if (any) ++bad;
|
||||
}
|
||||
std::cout << "hip repeat check: " << rounds << " rounds x 8 phases, mismatching launches vs round 0: " << bad << '\n';
|
||||
}
|
||||
if (profile) std::cout << " hip network GPU: " << network->lastMilliseconds() * 1000.0 << " us\n";
|
||||
#else
|
||||
throw std::runtime_error("this build has no HIP support");
|
||||
#endif
|
||||
|
||||
Reference in new issue
Block a user