feat: add d4r inference engines and Windows parity tooling
Add native K/M/RR inference engines, HIP kernels, replay and validation harnesses, and Windows DLSS setup and runtime support. Include GPU profiling tools, build and packaging scripts, platform integration patches, and implementation documentation.
This commit is contained in:
1 parent
25493b3198
commit
7c5d3c9157
430 files changed
+76191
No files matched your search
@@ -0,0 +1,98 @@
|
||||
# Architecture
|
||||
|
||||
d4r keeps NVIDIA's DLSS library unmodified and gives it what it expects: an NGX D3D12 entry point in the game process, a CUDA driver underneath, and CUDA kernels that run. Everything between those points is translation.
|
||||
|
||||
## Components
|
||||
|
||||
| Piece | Where | Role |
|
||||
|---|---|---|
|
||||
| OptiScaler (in GE-Proton) | external | Hooks the game's upscaler call and forwards DLSS requests to an NGX DLL (`NvngxPath`) |
|
||||
| NGX shim `d4r_nvngx.dll` | `tools/d4r_nvngx_shim.cpp` | Implements the NGX D3D12 API. Moves inputs and output between the game's D3D12 resources and CUDA, and drives the official NGX core through its CUDA API |
|
||||
| NGX core + `nvngx_dlss.dll` | NVIDIA, supplied by you | The real DLSS: parameter handling, network selection, the CUDA kernels |
|
||||
| CUDA bridge `nvcuda.dll` | `tools/wine_nvcuda_bridge.c` | A Wine builtin whose Windows exports forward to ZLUDA's Linux `libcuda.so`, plus d4r helpers (Vulkan memory import, asynchronous 2D copies, GPU-side waits, output redirect, linear textures) |
|
||||
| ZLUDA | `patches/zluda` | CUDA driver API on HIP; compiles NVIDIA's PTX to AMDGPU code; serves native kernels in place of PTX kernels |
|
||||
| Native kernels | `kernels/` | RDNA3 implementations of the DLSS network layers and parts of texture kernels |
|
||||
| vkd3d-proton patch | `patches/vkd3d-proton` | Splits a D3D12 command list around DLSS and retains external resources through command allocator completion |
|
||||
| NVAPI identity | `tools/d4r_nvapi_identity.c` | Reports an Ada (sm_89) GPU so NGX selects the network weights matching the PTX ZLUDA compiles |
|
||||
|
||||
## One frame
|
||||
|
||||
With VRAM interop and split frames (the defaults when the patched vkd3d-proton is present):
|
||||
|
||||
1. **The game records DLSS.** Its `EvaluateFeature` call reaches the shim with the game's command list. Into that list the shim records:
|
||||
- Vulkan commands (vkd3d-proton interop) that copy colour, depth, motion vectors and optional exposure into buffers exported to HIP. Linear R11G11B10, RGB10A2, and RGBA8/BGRA8 colour inputs are blitted to RGBA16F; multichannel float exposure is blitted to R32F using its first component when the device supports the conversion.
|
||||
- A frame marker.
|
||||
- A split. vkd3d-proton submits everything the game records after the DLSS call separately, gated on a timeline semaphore reaching this frame's number.
|
||||
- At the start of that second part, a copy of the DLSS result into the game's output texture. Linear R11G11B10, RGB10A2, and RGBA8/BGRA8 outputs are converted from RGBA16F on the GPU. sRGB formats continue through host staging to preserve their existing byte interpretation.
|
||||
2. **The CUDA worker queues DLSS.** The prep thread checks the GPU-written input marker with short CPU sleeps. It drops recorded-but-unsubmitted frames when they time out or their feature retires, before any DLSS work is queued. The CUDA worker then queues:
|
||||
- the input copies into CUDA arrays, or none when NGX samples the buffers in place (`LinearInputs`);
|
||||
- NGX's evaluation (NGX's own CPU synchronisations are elided with `ElideNgxSync`);
|
||||
- the result, written straight into the output buffer by the native output kernel (`DirectOutput`, preset K) or copied there.
|
||||
3. **Release.** When the GPU finishes, the worker signals the timeline semaphore and the rest of the game's frame runs, now with this frame's result.
|
||||
|
||||
The watchdog reports delayed output but never signals an unfinished producer as ready. Retiring features remain registered until their CPU/CUDA jobs drain. The lifetime-aware vkd3d extension retains their staging buffers, imported buffers, conversion images and split semaphore through command-allocator reset or destruction after GPU completion. Discarded recordings are covered too; cleanup no longer relies on a 50 ms delay.
|
||||
|
||||
The shim requires the matching lifetime-aware d3d12.dll and d3d12core.dll, even for host staging. It rejects older runtimes rather than recording references whose lifetime it cannot protect. FrameAge > 0 shows the newest finished result; without VRAM interop, inputs and output are staged through host memory.
|
||||
|
||||
## Why each piece exists
|
||||
|
||||
- **CUDA NGX instead of D3D12 NGX.** NVIDIA's D3D12 path needs NVIDIA's driver. The CUDA path only needs a CUDA driver API, which ZLUDA provides.
|
||||
- **The Ada identity.** NGX picks network weights by GPU architecture. The weights have to match the PTX that ZLUDA compiles, which is sm_89 for DLSS 310.
|
||||
- **Native kernels.** Translating NVIDIA's warp-level matrix code is slow (register pressure, lane shuffles, per-instruction mode switches). Earlier translated K layers also produced non-finite outputs that the final kernel masked. Native layers avoid that path; the compiler now preserves FP16 denormal requirements too, which fixes the translated failure in recorded captures. Numerical and image-quality parity with RTX hardware remains unverified.
|
||||
- **Sleeping readiness checks.** Waiting for input submission before queueing DLSS avoids an uncancellable GPU wait. Explicit output event queries with short sleeps avoid HIP event/context waits that can consume a CPU core. Submillisecond waits use NtDelayExecution because MinGW std::sleep_for can truncate them to zero. Linear inputs and direct output remain available.
|
||||
|
||||
## Configuration
|
||||
|
||||
`config/d4r.ini.default` documents every setting. `scripts/d4r_config.py` turns the file into environment variables for `scripts/run_game_d4r_optiscaler_proton.sh`, and an environment variable that is already set wins. The most useful switches:
|
||||
|
||||
| d4r.ini | Environment | Effect |
|
||||
|---|---|---|
|
||||
| `[DLSS] Model` | `D4R_DLSS_PRESET` | DLSS network: `E` (CNN), `K` (DLSS 4), `M` (DLSS 4.5) |
|
||||
| `[Latency] FrameAge` | `D4R_SHIM_SPLIT_FRAME`, `D4R_SHIM_MAX_IN_FLIGHT` | 0 = same-frame results; higher values pipeline frames |
|
||||
| `[Kernels] NativeKernels` | `D4R_ZLUDA_NATIVE_DIR` | native kernel directory (`fast` / `exact` / `off`) |
|
||||
| `[Kernels] PreferAccuracy` | `D4R_PREFER_ACCURACY` | default off; accuracy variants for every native family and conservative translation/synchronization settings |
|
||||
| `[Interop] VramInterop` | `D4R_SHIM_VRAM_INTEROP` | keep inputs and output in VRAM |
|
||||
| `[Interop] LinearInputs` | `D4R_SHIM_LINEAR_INPUTS` | NGX samples the input buffers in place |
|
||||
| `[Interop] DirectOutput` | `D4R_SHIM_OUTPUT_DIRECT` | the output kernel writes the game-side buffer directly (preset K) |
|
||||
| `[Interop] ElideNgxSync` | `D4R_ELIDE_NGX_SYNC` | skip NGX's internal CPU waits |
|
||||
| `[Paths] JitCacheDir` | `XDG_CACHE_HOME` | where ZLUDA caches compiled kernels |
|
||||
|
||||
## Portable installs (the release zip)
|
||||
|
||||
The release zip (`scripts/package_release.sh`) is unpacked into the folder that holds a game's main `.exe`, like an OptiScaler release. Nothing in the Proton prefix or the system is changed.
|
||||
|
||||
| File | Role |
|
||||
|---|---|
|
||||
| `dxgi.dll`, `OptiScaler.ini` | OptiScaler 0.9.4. Its INI sets DLSS as the DX12 upscaler and `OptiDllPath=d4r`, so OptiScaler loads the shim as `d4r\nvngx.dll`. |
|
||||
| `d3d12.dll`, `d3d12core.dll` | the d4r-patched vkd3d-proton. Proton loads DLLs from the game folder before `system32`. |
|
||||
| `d4r\nvngx.dll`, `d4r\nvcuda.dll` | the shim and the CUDA bridge |
|
||||
| `d4r\zluda\libcuda.so` | ZLUDA |
|
||||
| `d4r\kernels\<gfx target>\` | native kernels and their manifest `d4r-kernels.txt` |
|
||||
| `d4r\d4r.ini` | this game's settings |
|
||||
| `d4r\nvngx_dlss.dll`, `d4r\ngx\_nvngx.dll` | NVIDIA's files (the packager's `D4R_BUNDLE_NVIDIA=0` leaves them for the user to add) |
|
||||
|
||||
**Settings.** When an `d4r.ini` sits next to the shim, the shim turns it into the same environment variables the developer launcher sets, with the release's defaults. A variable that is already set, for example in the launch options, wins. Settings for the Linux side (ZLUDA's and the bridge's) are handed to the bridge through `d4rSetEnv` right after it is loaded, before its first CUDA call.
|
||||
|
||||
**Loading ROCm.** Steam runs GE-Proton 11 inside its container runtime (SteamLinuxRuntime_4), whose library search path has no ROCm. The bridge therefore:
|
||||
- loads HIP, HSA and comgr by path, from `RocmDir` (default: the release's bundled `d4r/rocm`, else `/opt/rocm`);
|
||||
- looks up any dependency they lack in the host's library directories, which the container mounts under `/run/host`;
|
||||
- sets `XDG_CACHE_HOME` only while ZLUDA initialises, so ZLUDA's kernel cache goes to `~/.cache/d4r` without affecting the rest of the game.
|
||||
|
||||
**Native kernel checks.** For each kernel, `d4r-kernels.txt` lists the hash of the DLSS PTX module it was written for. ZLUDA is pointed at a per-process directory, and the bridge adds a kernel to it only when NGX loads a module with a matching hash. A DLSS version whose kernel changed therefore gets ZLUDA's compile of that kernel: slower, but correct. The bridge picks the `gfx` folder from the GPU's KFD topology entry. `DirectOutput` takes effect only while the bridge reports that NGX uses a native `hiluma_engine_output_*` kernel. That kernel is one of the texture kernels built from NVIDIA's PTX, and it is worth about 3 fps for DLSS 4 at Quality.
|
||||
|
||||
**NGX identity and watermark.** A game that initialises NGX with a project ID (Unreal's DLSS plugin does) is passed to the NGX core's `NVSDK_NGX_CUDA_Init_ProjectID` with that ID. In this setup the DLSS library still stamps "DLSS SDK - DO NOT DISTRIBUTE" over its output. The shim sets the SDK's `Disable.Watermark` evaluation parameter unless `[DLSS] ShowWatermark = true` (`D4R_SHIM_WATERMARK=1`).
|
||||
|
||||
**NVAPI.** The launch option `PROTON_FORCE_NVAPI=1` makes Proton enable dxvk-nvapi on the AMD driver and set `WINE_HIDE_AMD_GPU`, so Windows sees an NVIDIA PCI ID. OptiScaler's NVIDIA check accepts that, so the NVAPI identity bridge is only needed by the developer launcher. `DXVK_NVAPI_GPU_ARCH=AD100` is still required, because NGX picks its weights by GPU architecture.
|
||||
|
||||
## Logs
|
||||
|
||||
The launcher writes each run's logs to `~/.cache/d4r-dlss-captures/game-<exe>-<time>/`. `d4r_nvngx.log` holds the shim's log. With `[Debug] Profile = true` it also records one `D4R_PROFILE` line per frame, with the stage timings.
|
||||
|
||||
Output completion uses event queries with 200 us NtDelayExecution sleeps by default. `D4R_SHIM_BLOCKING_SYNC = 0`
|
||||
under `[Env]` restores context synchronization for an A/B check. The profile records
|
||||
`output_sync_wall`, `output_sync_cpu`, and `output_sync_method=event_query_sleep` for the new path.
|
||||
An unavailable or failed event falls back to context synchronization. The old `GpuWait` setting
|
||||
is no longer used: input readiness is checked on the CPU before CUDA work is queued.
|
||||
|
||||
The `d2h` field on this path includes the output synchronization wait, even when direct output
|
||||
skips the array-to-buffer copy.
|
||||
@@ -0,0 +1,148 @@
|
||||
# Building d4r
|
||||
|
||||
These steps produce the pieces the launcher needs: a patched ZLUDA, a patched vkd3d-proton, the NGX shim and CUDA bridge, a staged runtime directory with your NVIDIA files, and the native kernels. The versions below are the ones that were tested; others may need changes.
|
||||
|
||||
| Component | Tested version |
|
||||
|---|---|
|
||||
| ZLUDA | `ee2f25a` (upstream), plus `patches/zluda/0002` through `0007` in order |
|
||||
| vkd3d-proton | `3dfc6f07` (the base GE-Proton11-3 ships), plus `patches/vkd3d-proton/0001` and `0002` |
|
||||
| ROCm | 7.2 (HIP runtime, clang, device libraries) |
|
||||
| Proton | GE-Proton11-3 (with its OptiScaler integration) |
|
||||
| DLSS | `nvngx_dlss.dll` 310.7.0 |
|
||||
|
||||
## 1. ZLUDA
|
||||
|
||||
```sh
|
||||
git clone https://github.com/vosen/ZLUDA zluda && cd zluda
|
||||
git checkout ee2f25a
|
||||
git submodule update --init --recursive
|
||||
git lfs pull
|
||||
for p in 0002 0003 0004 0005 0006 0007; do git apply /path/to/d4r/patches/zluda/$p-*.patch; done
|
||||
# rebuild the device helpers the patches changed (ptx/lib/zluda_ptx_impl*.bc)
|
||||
ZLUDA_SOURCE_ROOT=$PWD ROCM_ROOT=/opt/rocm /path/to/d4r/scripts/build_zluda_ptx_helpers.sh
|
||||
LIBRARY_PATH=/opt/rocm/lib cargo build --release -p zluda
|
||||
LIBRARY_PATH=/opt/rocm/lib cargo build --release -p ptx --example d4r_emit
|
||||
mkdir -p ~/.cache/d4r-zluda-current
|
||||
cp target/release/libnvcuda.so ~/.cache/d4r-zluda-current/
|
||||
ln -sf libnvcuda.so ~/.cache/d4r-zluda-current/libcuda.so
|
||||
```
|
||||
|
||||
Build the release ZLUDA library on a system or in a container with GLIBC 2.41 or older. A binary
|
||||
linked on a newer system can require newer GLIBC symbols even when the ZLUDA source does not need new
|
||||
GLIBC features. Before packaging, check it with
|
||||
`scripts/check_glibc_compat.sh 2.41 /path/to/libnvcuda.so`. The release packager runs the same
|
||||
check on ZLUDA, the Wine CUDA bridge, and every bundled ROCm library. Test the rebuilt library
|
||||
with the D3D12 harness and in a game before publishing a release.
|
||||
|
||||
The launcher looks for ZLUDA in `D4R_ZLUDA_DIR` (default `~/.cache/d4r-zluda-current`, or `ZludaDir` in d4r.ini).
|
||||
|
||||
What the patches add:
|
||||
|
||||
- **0002**: the CUDA driver API surface NGX and DLSS use (arrays, textures, surfaces, 1010102 formats, launch parameter buffers), the PTX features DLSS kernels need, and module dumps for debugging (`D4R_ZLUDA_DUMP_DIR`).
|
||||
- **0003**: an implicit 256-thread launch bound for kernels without PTX bounds (removes massive register spilling, `D4R_ZLUDA_IMPLICIT_MAX_BLOCK`) and f16 tensor-core MMA on RDNA3 WMMA (`D4R_ZLUDA_WMMA`).
|
||||
- **0004**: the native kernel override hook (`D4R_ZLUDA_NATIVE_DIR`, see [native-kernels.md](native-kernels.md)), FP8 MMA on WMMA (`D4R_ZLUDA_WMMA_FP8`), optional elision of per-instruction denormal mode switches (`D4R_ZLUDA_IGNORE_DENORMAL`), inlined image helpers, and linking extra bitcode into a PTX module (`D4R_ZLUDA_EXTRA_BC`, used by the texture-kernel build).
|
||||
- **0005**: a null texture object (CUDA handle 0) reads as zeros, as on NVIDIA GPUs, instead of faulting the GPU. DLSS samples absent optional inputs that way in some configurations (low-resolution motion vectors without HDR, as in Ghost of Tsushima).
|
||||
- **0006**: `m16n8k8` f16 MMAs (DLSS 3 CNN, presets E/F) on RDNA3 WMMA like the k16 ones (`D4R_ZLUDA_WMMA_K8=0` disables it); weight-image slots for native prep kernels (`d4r_prep_key_at`, `d4r_prep_key_slots`); and wave64 compilation for offline texture-kernel builds (`D4R_ZLUDA_WAVE64=1`, with wave64 builds of the helper bitcode). `scripts/build_zluda_ptx_helpers.sh` now writes the `_w64` helper variants too.
|
||||
- **0007**: gfx12 WMMA layout lowering, optional native e4m3 FP8 WMMA (`D4R_ZLUDA_WMMA_FP8_NATIVE=1`), and an architecture argument for `d4r_emit`. `D4R_ZLUDA_WMMA_LAYOUT=12` on gfx11 is a validation shim, not a release setting.
|
||||
|
||||
When linking on a system with ROCm libraries outside the default search path, include their library directory in `LIBRARY_PATH`. The build also needs the appropriate ROCm link libraries. `CARGO_BUILD_JOBS=8` caps parallel Rust compilation if memory is limited.
|
||||
|
||||
## 2. vkd3d-proton
|
||||
|
||||
```sh
|
||||
scripts/build_vkd3d_proton_d4r.sh ~/.cache/d4r-vkd3d-d4r
|
||||
```
|
||||
|
||||
The patch lets the shim split the game's command list at the DLSS call, so the rest of the frame waits (at queue level) for DLSS instead of showing the previous frame's result. Point `D4R_VKD3D_DIR` (or `VkD3DDir` in d4r.ini) at the output. Without it the shim falls back to showing a one-frame-old result.
|
||||
|
||||
## 3. Shim, bridge and NVAPI identity
|
||||
|
||||
```sh
|
||||
scripts/build_d4r_nvngx_shim.sh # build/d4r_nvngx.dll (needs x86_64-w64-mingw32-g++ and clang-cl)
|
||||
scripts/build_wine_nvcuda_bridge.sh # build/wine-nvcuda/ (needs winegcc and winebuild)
|
||||
```
|
||||
|
||||
The launcher builds the small NVAPI identity bridge (`scripts/build_d4r_nvapi_identity.sh`) itself.
|
||||
|
||||
## 4. Runtime directory
|
||||
|
||||
```sh
|
||||
scripts/install_d4r_runtime.sh /path/to/_nvngx.dll /path/to/nvngx_dlss.dll
|
||||
```
|
||||
|
||||
This stages the shim, the bridge, the NGX core and the DLSS feature library in `D4R_RUNTIME_DIR` (default `~/.local/share/d4r-dlss`, or `RuntimeDir` in d4r.ini). The NVIDIA files come from your own sources, for example an NVIDIA driver package (NGX core) and a game or the DLSS SDK (feature library).
|
||||
|
||||
## 5. Native kernels
|
||||
|
||||
```sh
|
||||
D4R_ROCM_DIR=/opt/rocm \
|
||||
D4R_DLSS_DLL=/path/to/nvngx_dlss.dll \
|
||||
D4R_ZLUDA_EMIT=/path/to/zluda/target/release/examples/d4r_emit \
|
||||
kernels/build.sh all kernels/out/native
|
||||
```
|
||||
|
||||
`kernels/out/native` then holds one code object per replaced DLSS kernel; set `NativeKernelDirFast` in d4r.ini (or `D4R_ZLUDA_NATIVE_DIR`) to it. `kernels/build.sh k` or `m` builds only the network layers and needs neither the DLL nor ZLUDA. `kernels/build.sh l` builds L's shared network layers and unfolded texture variants; it needs the DLL and emitter. The texture kernels (`tex`, including L) extract PTX from your DLL into `kernels/extracted/` and compile it offline for `D4R_GPU_ARCH` through `D4R_ZLUDA_EMIT`; that directory and the build output are git-ignored and must not be redistributed. On gfx12, build a second variant with `D4R_NATIVE_FP8=1` and place it in an `<arch>-fp8` folder.
|
||||
|
||||
To add the accuracy option to a developer set, repeat the build with `D4R_PREFER_ACCURACY=1` and output `kernels/out/native/accuracy` (multi-target builds: `kernels/accuracy/<arch>` and `<arch>-fp8`). Use a separate empty directory; successfully built accuracy sets receive `d4r-accuracy.txt`. Enable `[Kernels] PreferAccuracy = true` and restart. The option defaults to false and never substitutes the fast set when accuracy binaries are absent.
|
||||
|
||||
## 6. Configure and play
|
||||
|
||||
The first launch copies `config/d4r.ini.default` to `~/.config/d4r/d4r.ini`. Set the `[Launch]` paths (Proton, the game's compatdata prefix and the game executable), the `[Paths]` above, and the model in `[DLSS]`, then run:
|
||||
|
||||
```sh
|
||||
scripts/d4r_play.sh
|
||||
```
|
||||
|
||||
In the game, pick DLSS as the upscaler (OptiScaler intercepts it). Every setting in the file can also be given as an environment variable, which takes precedence; `D4R_NO_CONFIG=1` ignores the file.
|
||||
|
||||
## 7. Package a release
|
||||
|
||||
```sh
|
||||
scripts/fetch_rocm_runtime.sh # -> ~/.cache/d4r-rocm-runtime (AMD's ROCm 7.2.4 runtime, checksummed)
|
||||
D4R_OPTISCALER=/path/to/OptiScaler_0.9.4.7z \
|
||||
D4R_DLSS_DLLS=/path/to/310.7/nvngx_dlss.dll:/path/to/310.9/nvngx_dlss.dll \
|
||||
D4R_BUNDLE_DLSS=/path/to/nvngx_dlss.dll D4R_BUNDLE_NGX=/path/to/_nvngx.dll D4R_BUNDLE_TEX=kernels/out/native \
|
||||
D4R_ZLUDA_DIR=~/.cache/d4r-zluda-current D4R_VKD3D_DIR=~/.cache/d4r-vkd3d-d4r D4R_ROCM_DIR=/opt/rocm \
|
||||
D4R_ZLUDA_EMIT=/path/to/zluda/target/release/examples/d4r_emit \
|
||||
scripts/package_release.sh # -> dist/d4r-<version>.zip
|
||||
```
|
||||
|
||||
The script:
|
||||
- builds the shim, the bridge and both fast and accuracy network-layer kernels for gfx1100–gfx1103 and gfx1200–gfx1201 by default (`D4R_GPU_ARCHS` can select fewer targets); each gfx12 target also gets an `<arch>-fp8` variant;
|
||||
- writes the kernel manifest from the DLLs you list (it records hashes of their PTX, nothing else);
|
||||
- stages OptiScaler as `dxgi.dll` with the settings in `packaging/optiscaler.settings`;
|
||||
- adds NVIDIA's two DLLs and any supplied texture kernels (built from NVIDIA's PTX by `kernels/build.sh tex`); builds accuracy texture sets with `D4R_ZLUDA_EMIT` unless marked prebuilt sets are supplied in `D4R_BUNDLE_TEX/accuracy/<target>`;
|
||||
- zips the result together with the ZLUDA and vkd3d-proton builds, the ROCm runtime (as `d4r/rocm`), `packaging/d4r.ini`, the licenses and the patches.
|
||||
|
||||
The NVIDIA files are not covered by d4r's license; redistributing them is up to whoever publishes the zip. `D4R_BUNDLE_NVIDIA=0` builds `d4r-<version>-nonvidia.zip` without them and without the texture kernels. [architecture.md](architecture.md#portable-installs-the-release-zip) describes how the installed files work together.
|
||||
|
||||
### GLIBC 2.41 release builds
|
||||
|
||||
Build the pinned environment with:
|
||||
|
||||
```sh
|
||||
docker build -f packaging/build/Dockerfile.glibc241 -t d4r-build:glibc241 packaging/build
|
||||
```
|
||||
|
||||
Inside that image, `scripts/build_release_glibc241.sh` rebuilds the GPU device helpers, ZLUDA and its LLVM, `d4r_emit`, the NGX shim, Wine CUDA bridge, patched vkd3d-proton, and performance/accuracy texture sets for every release target. Packaging then builds both network sets, checks all bundled Linux libraries against 2.41, and records the toolchain in `d4r/source/BUILD_INFO.txt`.
|
||||
|
||||
Mount the repository at `/work`, ROCm's compiler/headers/device libraries at `/opt/rocm`, and an official Rust toolchain (1.98.0 used for 0.1.3) at `/opt/rust`, with `/opt/rust/bin` on `PATH`. Keep toolchain and third-party runtime inputs read-only. Supply the normal package inputs listed above and these build settings:
|
||||
|
||||
| Variable | Input |
|
||||
|---|---|
|
||||
| `D4R_RELEASE_BUILD_ROOT` | writable directory under `/work/build/` |
|
||||
| `D4R_ZLUDA_SRC` | isolated checkout inside that directory, with both pinned LLVM and HiGHS submodules, the real OCKL LFS payload, and patches `0002`–`0007` applied |
|
||||
| `D4R_VKD3D_SRC` | isolated vkd3d-proton checkout inside that directory, with its submodules and patches `0001` and `0002` applied |
|
||||
| `CARGO_HOME` | writable build-local Cargo cache; prefetch the locked dependencies for an offline build |
|
||||
| `D4R_ROCM_DIR` | `/opt/rocm` |
|
||||
| `D4R_ROCM_LINK_STUBS` | optional directory for additional ROCm link libraries |
|
||||
|
||||
Run `bash scripts/build_release_glibc241.sh` inside the container. The script checks that the build system actually reports `glibc 2.41`, rejects external source-cache checkouts, builds with the locked Cargo dependencies offline, and runs the configuration tests before packaging. The ZIP and checksum go in `$D4R_RELEASE_BUILD_ROOT/dist/`; logs and `toolchain.txt` remain in the build directory. AMD's bundled ROCm runtime, OptiScaler and NVIDIA's libraries remain supplied binaries; the Linux ABI check covers the bundled ROCm libraries too.
|
||||
|
||||
`D4R_BUNDLE_TEX` accepts the older flat directory for gfx1101, or a directory with per-target subdirectories (`gfx1100/`–`gfx1103/`, `gfx1200/`, `gfx1201/`, plus `gfx1200-fp8/` and `gfx1201-fp8/`). Build each texture set with `D4R_GPU_ARCH` and `D4R_ZLUDA_EMIT`; the `-fp8` sets also need `D4R_NATIVE_FP8=1`. `d4r_emit` targets those GPUs offline. Missing texture kernels fall back to ZLUDA on that target; the network-layer kernels are still included. Only the RX 7700 XT has been tested on real hardware.
|
||||
|
||||
## Checks
|
||||
|
||||
- `scripts/check_environment.sh` lists the tools, GPU and Proton builds it finds.
|
||||
- The D3D12 harness (`scripts/run_d3d12_dlss_harness_proton.sh`) drives DLSS outside a game.
|
||||
- Native kernels have their own validation path; see [native-kernels.md](native-kernels.md).
|
||||
@@ -0,0 +1,136 @@
|
||||
# Native kernels
|
||||
|
||||
The native kernels are RDNA3 (gfx11) and RDNA4 (gfx12) code objects that ZLUDA runs in place of specific DLSS kernels. Each one has the same name, launch shape and parameter block as the PTX kernel it replaces, and reads the same buffers, including the network weights inside NVIDIA's DLL. No weights or NVIDIA code are stored here.
|
||||
|
||||
## The override hook (patches/zluda/0004)
|
||||
|
||||
With `D4R_ZLUDA_NATIVE_DIR=DIR`, whenever NGX loads a PTX module and asks for kernel `NAME`, ZLUDA looks for `DIR/NAME.hsaco` and uses its kernel `NAME` instead. The code object can export:
|
||||
|
||||
| Symbol | Meaning |
|
||||
|---|---|
|
||||
| `NAME_prep` kernel | launched first on the same stream, with the same parameters (typically re-lays out weights) |
|
||||
| `u32 d4r_prep_blocks` | grid size of the prep kernel (128 threads per block) |
|
||||
| `u32 d4r_prep_key_offset` | byte offset of a u64 in the parameter block; the prep is skipped while that value (the weights pointer) repeats (0 = no key) |
|
||||
| `u32 d4r_prep_key_at` | the same as offset + 1, so a key at offset 0 can be named (M's layers keep their weights pointer there) |
|
||||
| `u32 d4r_prep_key_slots` | N > 0: the kernel keeps one prepared image per key for up to N keys, so the prep runs once per weight set (the six enc3 tube blocks); keys beyond N share an overflow image and are prepared on every launch |
|
||||
| `u32 d4r_block_z` | replaces the launch's block z dimension (more waves per window) |
|
||||
| `u32 d4r_grid_x` | replaces the grid (persistent kernels) |
|
||||
|
||||
Kernels without a file in `DIR` are compiled from PTX as usual, so a partial set works.
|
||||
|
||||
**Release directories.** A directory that holds `d4r-kernels.txt` (or `<gfx target>/d4r-kernels.txt`) is checked before use:
|
||||
- `kernels/tools/kernel_manifest.py DIR nvngx_dlss.dll...` writes the manifest. For each `NAME.hsaco` it records the FNV-1a 64 hash of the PTX module that defines `.entry NAME`, taken from each DLL given.
|
||||
- The CUDA bridge serves a kernel only after NGX has loaded a module with one of the listed hashes.
|
||||
- It picks the KFD GPU with the most SIMDs, then selects that GPU's target folder. `D4R_GPU_ARCH` overrides the choice. On gfx12, `D4R_ZLUDA_WMMA_FP8_NATIVE=1` selects the `<arch>-fp8` folder.
|
||||
|
||||
The release is built this way, with hashes from DLSS 310.7.0 and 310.9.1. The PTX of every replaced kernel is identical in those two versions.
|
||||
|
||||
## Families
|
||||
|
||||
**DLSS 4, preset K (`kernels/k`, `dltss_pwin_*`).**
|
||||
- **Network:** a Swin-style U-Net of eleven layers over 8×8 token windows. There are encoders enc0–enc4 with 2×2 patch merging, a bottleneck dec5, and decoders dec4–dec0 with patch expansion and skip inputs. The window attention is either learned (query × key plus a bias table) or position-only (a fixed table times the values).
|
||||
- **Templates:**
|
||||
- `pwin_layer.h`: four waves per window, each owning a 16-token tile.
|
||||
- `pwin_pos.h`: position-only layers with two token tiles per wave, which halves weight traffic.
|
||||
- `pwin_wide.h`: the deep layers, which have only 6–77 windows per frame. It uses 4·NG waves per window, split by token tile and channel group, so the GPU stays busy.
|
||||
- **Weights:** prep kernels expand the weights into WMMA operand images once.
|
||||
|
||||
**DLSS 4.5, presets L/M (`kernels/m`, `rrlite_*`).**
|
||||
- **Network:** the Swin blocks of DLSS 4.5, whose weights are FP8. Their prep kernels expand the weights to f16 WMMA operands, once per weight set.
|
||||
- **Template:** `swin_block.h` covers encoders, the tube-shaped enc3 and decoders.
|
||||
- **Output encoding:** the FP8 output is encoded two values at a time with packed 16-bit operations (`enc8x2`, exhaustively equal to the scalar encoder), and the 2×2 patch merge reads the rounded f16 values the codes decode to, from a row layout without LDS bank conflicts, instead of decoding the bytes again in every wave.
|
||||
- **Weight loads:** enc1 forms each weight tile's address in scalar registers (`SWIN_SCALAR_BLOAD`); the 8-wave layers are faster without it.
|
||||
|
||||
**Preset L texture variants.** L uses unfolded `rrlite_enc0_4x4_*`, `rrlite_dec0_4x4`, and `rrlite_post_3_*` kernels. The L build keeps their full neural arithmetic and replaces surface stores with the existing native format-conversion functions. M's folded enc0 tail and dec0 head cannot be used for these variants. All four input flag combinations and all eight post variants are built, along with the shared downsample kernels. `all` and `tex` include these variants; `l` builds the shared Swin layers plus only the L texture set. L remains experimental; these replacements do not establish RTX parity or game performance.
|
||||
|
||||
**Motion mitigation.** `[Kernels] NativeSwinEncoders = false` (`D4R_NATIVE_SWIN_ENCODERS=0`) bypasses only `rrlite_enc1_4x4` and `rrlite_enc2_4x4` in the native manifest. L/M then use the original translated PTX for those encoders, retaining native tube, decoder and texture kernels. Keep `PreferAccuracy = true` for the tested conservative path. It reduced the extra building-edge trails in a 64-frame moving Townfall capture at 853×480 → 2560×1440 on gfx1101; it does not recover detail absent from the low-resolution input or establish RTX parity. The default remains `true` for speed. Flat developer sets without manifests fall back entirely when this switch is off; add a manifest to keep selective acceleration.
|
||||
|
||||
Initial validation: a gfx1101 fast L build completed two Ultra Performance harness frames (192×108 → 576×324, DLSS 310.7). Its finite, nonzero RGBA16F output matched the original translated L texture kernels byte for byte with the same native Swin layers. A gfx1201 FP8 accuracy L set compiled successfully; RDNA4 hardware and 4K game output have not been tested. Full packaging rebuilds missing L variants when given an older texture bundle.
|
||||
|
||||
## RDNA4
|
||||
|
||||
`kernels/common/wmma_layout.h` selects the WMMA operand and accumulator layout. gfx12 uses eight f16 values per lane in each K half; the accumulator rows are `i + 8·half`. The gfx11 path retains its original layout. `D4R_WMMA_LAYOUT=12` on gfx11 is a test shim: it exercises gfx12 indexing but executes gfx11 WMMA, so its replay output can be compared byte for byte with the existing gfx11 build.
|
||||
|
||||
The gfx12 M variant can use native e4m3 FP8 WMMA with `D4R_NATIVE_FP8=1`. Its activations are requantized to e4m3 at operand load, and its prepared weights remain bytes. The matching ZLUDA and texture-tail variant uses `D4R_ZLUDA_WMMA_FP8_NATIVE=1` / `D4R_TEX_FP8=1`; the release bridge chooses the `-fp8` kernel folder. `NativeFp8` in d4r.ini controls that choice and defaults to on. The f16 widening path remains available.
|
||||
|
||||
The gfx11 refactor and gfx12-layout shim matched the recorded gfx11 replays and 88-frame K/M harness images byte for byte on the RX 7700 XT. rocjitsu gfx1201 replay comparisons put the native K layers within 96–109 dB PSNR of gfx11, and M differed in 0.001–0.3% of e4m3 bytes. These are emulator results, not RDNA4 hardware results. rocjitsu's FP8 arithmetic is not hardware-checked; bit-exactness, speed and driver stability on an RDNA4 GPU remain unverified.
|
||||
|
||||
For ZLUDA-compiled code, compare rocjitsu runs with other rocjitsu runs: the emulator does not reproduce the denormal-flush mode of those code objects, so a GPU byte comparison is not a valid arithmetic check. Captures with texture or surface objects must not be sent to the replay tools; the standalone `tail_check.hip` and the full D3D12 harness cover those tails.
|
||||
|
||||
**Texture kernels (`kernels/tex`).**
|
||||
- **The problem:** some DLSS kernels are mostly texture sampling and scalar maths that ZLUDA already compiles well, apart from a few slow parts.
|
||||
- **The approach:** for those, `make_ptx.py` edits NVIDIA's PTX (extracted from your DLL at build time):
|
||||
- surface stores become calls into `tex_common.h`;
|
||||
- the `roundf` idiom that forces ZLUDA into strict-FP mode is rewritten exactly;
|
||||
- for M's enc0 and dec0, a range of the kernel is replaced by a native tail or head.
|
||||
- **Build:** ZLUDA's `d4r_emit` compiles the edited PTX for `D4R_GPU_ARCH` with the HIP bitcode linked in (`D4R_ZLUDA_EXTRA_BC`), and the resulting code object is saved. This is an offline per-target build.
|
||||
- **Every flag combination:** DLSS picks kernel variants by the game's settings (motion vectors at render or display resolution, HDR or LDR input, inverted or regular depth, ...). `kernels/build.sh` builds all of them: 24 K output kernels, 8 M post, 4 M downsample and 4 M enc0 kernels. enc0's native tail is spliced into each variant at its own line, with the registers read off the variant's PTX (`make_ptx.py` checks that the code after the cut matches the reference variant line for line).
|
||||
- **Wave64:** kernels without MMAs can be compiled as wave64 (`D4R_ZLUDA_WAVE64=1`, ZLUDA patch 0006): each wave runs two CUDA warps, and RDNA3 issues FP32 work for all 64 lanes at once. The post and K output kernels are built this way (post 0.89 → 0.77 ms), with bit-identical results.
|
||||
- **Output redirect:** the kernel that writes a preset's result can write it straight into the shim's output buffer instead of a CUDA array: `hiluma_engine_output_*` for K, `rrlite_downsample_kernel_*` for M (M's post kernel works at 3840×2160; the downsample produces the output). See `D4R_SHIM_OUTPUT_DIRECT` in [architecture.md](architecture.md).
|
||||
|
||||
## Numerics
|
||||
|
||||
The conservative kernels round their f16 accumulator after each MMA step (k16 for K, k32 for M). The fast kernels keep f32 accumulators through a chain (`PWIN_F32ACC`, `SWIN_F32ACC`); RDNA3 M also skips intermediate FP8 re-quantization (`SWIN_NO_Q8`). Wider arithmetic changes the network's intermediate values; it does not establish better image quality. Recorded fast-versus-conservative replays were close (about 66 dB PSNR), but that is not an RTX reference comparison or a guarantee for all scenes.
|
||||
|
||||
The installed K set uses f32 accumulation for enc0–enc2 and dec0–dec2 and exact rounding for the deep layers. The M set uses the fast numerics throughout.
|
||||
|
||||
**`[Kernels] PreferAccuracy = true`** (default `false`, environment `D4R_PREFER_ACCURACY=1`) selects a separate accuracy set for all K/M network layers and all texture/output variants, on every supported target, including gfx12 FP8. K disables `PWIN_F32ACC`; M restores FP8 quantization and rounds each k32 accumulator to f16. Texture builds use wave32 and retain the original denormal requirements; the existing exact round-half-away rewrite is retained. Native texture heads/tails already round their accumulators per k32 step. The bridge also disables `IgnoreDenormals`, translated f32 accumulator shadows, wave64 translation and NGX synchronization elision before ZLUDA loads, including when native kernels are off or fail their PTX hash check. Other interop and latency settings remain independent.
|
||||
|
||||
The bridge selects `kernels/accuracy/<target>` (or `<target>-fp8`). Accuracy directories carry a `d4r-accuracy.txt` marker written only after a successful build. A marked flat developer directory also works. Missing accuracy variants fall back to translated PTX and are logged; the bridge never substitutes fast native binaries. Restart the game when changing the setting. The mode uses a separate `d4r-accuracy` JIT cache under the configured cache directory so older runtimes cannot reuse experimental fast-math results. The first accuracy run may compile new kernels.
|
||||
|
||||
This mode aims to preserve NVIDIA's arithmetic, not to promise bit-identical RTX output: matrix accumulation order differs across hardware, and the shim still canonicalizes input formats and does not forward the optional transparency/current-color-bias masks. RTX parity requires identical captured inputs, library version, preset and temporal sequence on NVIDIA hardware.
|
||||
|
||||
## Building
|
||||
|
||||
```sh
|
||||
kernels/build.sh k # DLSS 4 layers (ROCm clang only)
|
||||
kernels/build.sh m # DLSS 4.5 layers
|
||||
kernels/build.sh l # L shared layers + unfolded textures (needs DLL and D4R_ZLUDA_EMIT)
|
||||
kernels/build.sh tex # texture kernels (needs D4R_DLSS_DLL and D4R_ZLUDA_BUILD)
|
||||
kernels/build.sh all DIR # everything into DIR (default kernels/out/native)
|
||||
D4R_PREFER_ACCURACY=1 kernels/build.sh all DIR/accuracy # conservative versions of every family
|
||||
```
|
||||
|
||||
`D4R_GPU_ARCH` selects one target for this standalone build (default gfx1101). The release script builds the network layers for gfx1100–gfx1103 and gfx1200–gfx1201 by default and puts each set in its own directory. The network kernels need gfx11 or gfx12 WMMA. Texture-kernel builds use `D4R_ZLUDA_EMIT` to generate code objects for the selected target without that GPU. Set `D4R_NATIVE_FP8=1` on gfx12 for the matching FP8 M and texture variants.
|
||||
|
||||
The release includes both fast and accuracy network sets. Full releases also include accuracy texture sets: supply them in `D4R_BUNDLE_TEX/accuracy/<target>` or set `D4R_ZLUDA_EMIT` so packaging builds them. Build accuracy sets into a separate directory; the builder refuses to mark a directory containing unmarked older binaries as accurate.
|
||||
|
||||
## Validating a kernel
|
||||
|
||||
1. **Capture launches.** Set `D4R_CUDA_REPLAY_DUMP_DIR` (with `D4R_CUDA_REPLAY_DUMP_FILTER=<kernel name>`) while running the D3D12 harness or a game. The bridge then writes each matching launch as `manifest.txt`, `args.bin` and one `alloc-N.bin` per buffer.
|
||||
2. **Run the native kernel on a capture.** Build `kernels/tools/dump_runner.cpp` with hipcc. Then run:
|
||||
|
||||
```sh
|
||||
PREP_GRID=<d4r_prep_blocks> dump_runner NAME.hsaco NAME <capture> <out> 30
|
||||
```
|
||||
|
||||
It runs the prep and main kernels, saves every buffer after the first launch, and times 30 launches. The replay tool refuses captures with texture or surface objects; use the full harness for those kernels.
|
||||
3. **Compare against a reference.** `kernels/tools/pwin_model.py` (K) and `swin_model.py` (M) are numpy models of the layers, written stage by stage against `ptxsim.py`, a small vectorised PTX interpreter that runs NVIDIA's kernels on the CPU. A bit-exact variant should match the model within f16 rounding; after any change, compare the new build's buffers with the previous build's.
|
||||
4. **Check the whole pipeline.** Replay captured frames through the harness with both kernel sets and compare the outputs with `kernels/tools/psnr.py`. `D4R_CUDA_KERNEL_PROFILE=1` makes the bridge time every kernel; `kernels/tools/kprof.py` summarises the log per frame.
|
||||
|
||||
## Per-kernel cost
|
||||
|
||||
Median GPU time per frame at Quality (1706×960 → 2560×1440, RX 7700 XT), from `D4R_CUDA_KERNEL_PROFILE` in the D3D12 harness (flags as in Townfall; frames 21–40). The profiler's per-launch events add a little to every kernel, so totals are slightly above the in-game cost. "Before" is release 0.1.1.
|
||||
|
||||
| DLSS 4 (K) | before | now | DLSS 4.5 (M) | before | now |
|
||||
|---|---|---|---|---|---|
|
||||
| hiluma output (texture kernel) | 0.92 | 0.89 | enc3 tube (6 launches) | 1.62 | 1.57 |
|
||||
| dec0 | 0.33 | 0.32 | enc1 | 1.41 | 1.27 |
|
||||
| enc0 | 0.31 | 0.31 | dec1 | 1.44 | 1.43 |
|
||||
| dec1 | 0.26 | 0.26 | enc2 | 0.87 | 0.77 |
|
||||
| hiluma input (ZLUDA) | 0.25 | 0.24 | post (texture kernel) | 0.88 | 0.77 |
|
||||
| enc1 | 0.23 | 0.22 | dec2 | 0.84 | 0.82 |
|
||||
| enc2, dec2 | 0.12, 0.10 | 0.12, 0.10 | enc0 (texture kernel) | 0.64 | 0.63 |
|
||||
| enc3, dec3, enc4, dec4, dec5 | 0.07–0.09 each | 0.07–0.09 each | dec0 (texture kernel) | 0.64 | 0.63 |
|
||||
| NGX exposure and misc | 0.1 | 0.1 | downsample, NGX misc | 0.32 | 0.33 |
|
||||
| **total** | **3.10** | **2.97** | **total** | **9.04** | **8.23** |
|
||||
|
||||
Runs of the same build vary by about ±3% per kernel. M additionally skips its output copy now (direct output through the downsample kernel), which is not a kernel and not in the table. Games whose flags differ from Townfall's (motion vectors at render resolution, LDR input, regular depth) gain more: those kernel variants used to run as plain ZLUDA compiles (K 3.6–4.6 ms → 2.8–3.0 ms, M −0.5 to −0.7 ms per frame).
|
||||
|
||||
## Experimental thin-feature motion coverage
|
||||
|
||||
`[Interop] MotionVectorDilation = 1` or `2` (`D4R_MOTION_DILATION`) extends nearby foreground motion into pixels whose depth otherwise belongs to the background. The value selects the opaque-surface radius in render pixels. Both enabled values also fill sky gaps using the nearest foreground pixel within an eight-render-pixel circle (far depth 0 for reversed Z, 1 for normal Z). This is the wider sky fill from the comparison; it can strengthen trails in some frames and remains opt-in through `MotionVectorDilation`. This is a depth-guided approximation to better thin-feature motion coverage, not engine-side conservative rasterization. It improved the captured Townfall rooftop where the earlier native-encoder fallback did not resolve the artifact.
|
||||
|
||||
The d4r-owned GPU kernel preserves the original depth/motion buffers and writes a separate RG16F velocity texture. The worker waits for its completion before NGX evaluates. No per-frame CPU readback is needed. It requires same-frame linear VRAM inputs, full-resolution unjittered motion vectors and zero subrect bases. Unsupported features or unavailable kernels keep the original vectors. The default is `0` (off); larger radii can affect disocclusion and unrelated foreground edges. The method does not recreate geometry missing from every input frame or establish RTX parity.
|
||||
|
||||
`scripts/build_wine_nvcuda_bridge.sh` embeds the support kernels when `D4R_ROCM_DIR` points to ROCm clang. All six gfx110x/gfx120x targets compile; physical validation is currently gfx1101 only. A bridge built without the support kernels reports the feature unavailable rather than changing inputs. Optional GPU regressions cover forward/reversed depth, two radii, jitter, padded rows and preservation of input buffers; see `tests/test_motion_kernel_gpu.py`.
|
||||
@@ -0,0 +1,63 @@
|
||||
# Performance
|
||||
|
||||
All frame rates and kernel timings on this page were measured on an RX 7700 XT (gfx1101). RDNA4 (gfx1200/gfx1201) has compile and emulator validation only; no RDNA4 frame rate, latency, or kernel timing has been measured. Native FP8 may change both arithmetic and cost, so the gfx11 results cannot be projected to it.
|
||||
|
||||
## Method
|
||||
|
||||
- **Hardware and settings:** Radeon RX 7700 XT (RDNA3, 54 CUs), Ryzen 9 5900XT, Linux 6.18. SILENT HILL Townfall at 2560×1440 output.
|
||||
- **Route:** every run plays the same scripted 62-second walk through a street, with fog, wires, fences and signage.
|
||||
- **Frame rate:** from MangoHud's per-frame log over the walk, as frames divided by the sum of frame times.
|
||||
- **Pairing:** runs are compared back-to-back in one session, because repeated runs of an identical setup vary by about 1%.
|
||||
- **Screen recording:** it costs a few fps, so recorded videos show slightly lower numbers than the table.
|
||||
- **Latency:** all DLSS numbers are same-frame (frame age 0). Every frame shows its own DLSS result, as with a native upscaler.
|
||||
- **Upscaler modes:** every mode uses OptiScaler's render-ratio override (1.5, 1.72, 2.0, 3.0), so the result does not depend on the DLSS mode chosen in the game.
|
||||
|
||||
## Results
|
||||
|
||||
| Mode (render resolution) | DLSS 3 CNN (E) | DLSS 4 (K) | DLSS 4.5 (M) | FSR 4\* |
|
||||
|---|---|---|---|---|
|
||||
| Quality (1705×960) | **71.7** | 67.9 | 49.3 | 76.0 |
|
||||
| Balanced (1488×837) | **80.8** | 75.9 | 58.0 | 84.5 |
|
||||
| Performance (1280×720) | **89.7** | 84.1 | 69.0 | 94.0 |
|
||||
| Ultra Performance (853×480) | 89.1 | **95.5** | 92.2 | 107.3 |
|
||||
| Native 2560×1440, no upscaling (TSR at 100%) | | 49.1 | | |
|
||||
|
||||
\* FSR 4 and the native row are from 2026-09-27; the DLSS columns from 2026-09-29, when the machine ran about 2–4% slower overall (release 0.1.1 at Quality that day: E 71.2, K 67.9, M 48.4 fps, against 72.4, 69.4 and 51.5 two days earlier). The render resolution of every mode is set with OptiScaler's ratio override for whichever DLSS mode the game is set to (ratios 1.5, 1.72, 2.0 and 3.0).
|
||||
|
||||
DLSS 4's cost is almost constant across modes (about 2.8 ms of GPU time per frame). Its network runs on a grid set by the output resolution, not the render resolution, so the gap to FSR 4 widens as the render resolution drops. The CNN gets more expensive at the 3× ratio, so K is the better choice at Ultra Performance.
|
||||
|
||||
## What each step contributed
|
||||
|
||||
DLSS 4 (K) at Quality, frames per second on the walk:
|
||||
|
||||
| Step | fps |
|
||||
|---|---|
|
||||
| ZLUDA only: the transformer's outputs were non-finite, so the network had no effect | 58.5\* |
|
||||
| All eleven K layers native | 65.0\* |
|
||||
| Wide deep layers, f32 accumulation, cheaper operand transposes | 66.0 |
|
||||
| NGX's CPU syncs removed, faster marker polling, no sync before the output copy | 66.7 |
|
||||
| DLSS queued behind a GPU-side wait for the inputs (GPU busy 95% → 99%) | 68.0 |
|
||||
| Native output kernel writes the game-side buffer directly | 68.4 |
|
||||
| NGX samples the input buffers in place (no array copies) | 69.4 |
|
||||
|
||||
\* Measured from the shim's frame log on a similar stretch, before the MangoHud method was in use.
|
||||
|
||||
DLSS 4.5 (M) at Quality went from 28 fps (ZLUDA only) to 42 with the first native Swin layers, 46 with more waves per window, 50 with fast numerics and the texture-kernel tails, and 51.5 with the hand-off changes.
|
||||
|
||||
## What did not help
|
||||
|
||||
- **Accumulating in f16 on the WMMA units.** The error grows about 20× and the image degrades.
|
||||
- **Occupancy tweaks** (VGPR caps, waves-per-EU hints) and **persistent work-groups.**
|
||||
- **Non-temporal hints** for activation traffic.
|
||||
- **Splitting the position-only layers by channel** instead of by token. It halves weight traffic but serialises the compute.
|
||||
- **Mapping the Vulkan buffers directly as HIP arrays.** ROCm 7.2 does not export `hipExternalMemoryGetMappedMipmappedArray`.
|
||||
- **Signalling the game's Vulkan timeline semaphore from HIP.** HIP does not import timeline semaphores, so the end of DLSS is still signalled from the CPU.
|
||||
|
||||
## Where the time goes now
|
||||
|
||||
For DLSS 4 at Quality the GPU spends about 2.8 ms per frame in DLSS kernels:
|
||||
- NVIDIA's output kernel: 0.82 ms. It is ALU-bound at close to the GPU's instruction rate.
|
||||
- The eleven network layers: 1.6 ms.
|
||||
- The input kernel, exposure and miscellaneous kernels: about 0.35 ms.
|
||||
|
||||
The game-side input and output copies add about 0.3 ms. [native-kernels.md](native-kernels.md) lists every kernel.
|
||||
@@ -0,0 +1,189 @@
|
||||
# Experimental Windows RDNA3 / RDNA4 coverage
|
||||
|
||||
The shim, diagnostics, native K/M kernels and game installer accept the
|
||||
targets below, with one package per actual ISA. **Only RX 9070 XT has physical
|
||||
validation here.** Community RX 9060 XT / gfx1200 logs now show K/M backend
|
||||
execution in Cyberpunk and Dawnwalker with all required native layers and
|
||||
finite output. Visual issues remain reported and are not resolved by those
|
||||
checks. All other targets are experimental and compile-tested; their DLSS,
|
||||
interop and performance remain unverified.
|
||||
|
||||
| Family | Target | Examples / scope |
|
||||
| --- | --- | --- |
|
||||
| RDNA3 | gfx1100 | RX 7900 family; same-target workstation GPUs |
|
||||
| RDNA3 | gfx1101 | RX 7700 / 7700 XT / 7800 XT; same-target mobile/workstation GPUs |
|
||||
| RDNA3 | gfx1102 | RX 7600 / 7600 XT; same-target mobile/workstation GPUs |
|
||||
| RDNA3 | gfx1103 | RDNA3 integrated graphics |
|
||||
| RDNA3.5 | gfx1150, gfx1151, gfx1152, gfx1153, gfx1154 | Corresponding integrated graphics targets |
|
||||
| RDNA4 | gfx1200 | RX 9060 / 9060 XT; same-target GPUs |
|
||||
| RDNA4 | gfx1201 | RX 9070 / 9070 XT / 9070 GRE; same-target GPUs |
|
||||
|
||||
Names and IDs follow [LLVM processors](https://llvm.org/docs/AMDGPUUsage.html#processors)
|
||||
and [ELF ABI](https://llvm.org/docs/AMDGPUUsage.html#amdgpu-elf-header-e-flags).
|
||||
`tools/windows/gpu-targets.json` supplies CMake-generated C++, PowerShell and
|
||||
the private texture builder. Selection uses HIP's real `gcnArchName` and the
|
||||
D3D12 adapter LUID, including systems with several GPUs sharing a target.
|
||||
Marketing names do not control eligibility.
|
||||
|
||||
All listed RDNA3/RDNA3.5/RDNA4 targets with existing gfx11/gfx12 WMMA contracts
|
||||
are included. TBD RDNA4m gfx1170..gfx1172 and gfx12.5 gfx1250/gfx1251 are
|
||||
different ISA groups and excluded. Unknown future targets need explicit review.
|
||||
Check [AMD's Windows matrix](https://rocm.docs.amd.com/projects/radeon-ryzen/en/latest/docs/compatibility/compatibilityrad/windows/windows_compatibility.html)
|
||||
for driver/runtime eligibility. Compiler support cannot supply missing Windows
|
||||
driver support or external-memory APIs, especially on APUs.
|
||||
|
||||
## Installation and diagnostics
|
||||
|
||||
Use the actual target's archive: **gfx1200 for RX 9060 XT**, for example.
|
||||
Metadata, host target and every ELF target must agree. Runtime/scripts reject
|
||||
mixed targets and never rename targets, rewrite ELF IDs or set
|
||||
`HSA_OVERRIDE_GFX_VERSION`. Legacy metadata-free packages remain gfx1201 only.
|
||||
|
||||
Before changing game files, `windows-game.ps1` now runs a read-only HIP
|
||||
inventory and checks the target and wave32. Inventory allocates no GPU buffers
|
||||
and runs no kernels; success is discovery, not validation. Failure prints one
|
||||
ZIP containing stdout/stderr, exit code, runtime/DLL and driver details. A local
|
||||
`d3d12.dll` identifying itself as vkd3d/Wine is rejected before install. Restore
|
||||
the game's native D3D12 installation; the script never loads or removes that
|
||||
proxy itself. Begin synchronously on an untested GPU:
|
||||
|
||||
```powershell
|
||||
.\windows-game.ps1 -GameExe "D:\Games\Example\Game.exe" -NgxCore "C:\LocalDLLs\_nvngx.dll" -DlssDll "C:\LocalDLLs\nvngx_dlss.dll" -Preset 11 -ValidateOutput -CaptureExceptions
|
||||
```
|
||||
|
||||
The local DLLs must match the documented NGX version and DLSS 310.9.1 SHA256
|
||||
in `package.json`. NVIDIA DLLs are never distributed. Retain the printed ZIP
|
||||
on failure. Async K and performance are subsequent gates; gfx1201-specific
|
||||
FP8, arithmetic and tuning experiments remain separate.
|
||||
|
||||
## Issue #10 review, 2026-10-02
|
||||
|
||||
Reviewed [comment 5952822115](https://github.com/countervolts/d4r/issues/10#issuecomment-5952822115),
|
||||
including all 32 attached text logs from eight attempts. HIP discovers
|
||||
**RX 9060 XT / gfx1200** successfully. Every attempt fails with the old shim's
|
||||
**"No selected gfx1201 device"** rejection; OptiScaler reports `support=false`
|
||||
/ `BAD00002`. None reaches `D4R_RUNTIME` initialization or native transformer
|
||||
execution. These logs do not demonstrate a K/M kernel crash. Use the gfx1200
|
||||
package instead of overriding architecture. Three attempts also load
|
||||
vkd3d-proton 3.1.0 from a local D3D12 proxy, outside this Windows backend.
|
||||
|
||||
The new packages/preflight address the identified failures. They do not prove
|
||||
those games work on RX 9060 XT; a new native-D3D12 run on that GPU is required.
|
||||
Raw community logs and personal directory paths stay local.
|
||||
|
||||
## Community retest, 2026-10-03
|
||||
|
||||
[Comment 5962444244](https://github.com/countervolts/d4r/issues/10#issuecomment-5962444244)
|
||||
uses the corrected `52d9872` package / `3d62b98` binaries on RX 9060 XT
|
||||
(`gfx1200`, 16 GB). Cyberpunk K/M complete 4,365 / 1,751 session frames;
|
||||
Dawnwalker K/M complete 6,713 / 1,690. Every frame has a finite-output GPU
|
||||
check, all required native layers execute and all four sessions exit normally.
|
||||
The logs record zero backend failures, previous-frame outputs and CPU image
|
||||
copies. This is community backend coverage, not a reference-image comparison:
|
||||
the tester reports texture/LOD and motion-related artifacts. All four runs use
|
||||
the HDR network input/output path, unlike the local Cyberpunk LDR validation.
|
||||
|
||||
Spider-Man 2 crashes with `0xc0000005` before any completed DLSS frame;
|
||||
its nonstandard launch is not evidence of a transformer kernel failure.
|
||||
Assassin's Creed exits with zero frames and Streamline logs repeated internal
|
||||
minidumps; its clean process exit is still inconclusive. Their causes remain
|
||||
open without a stack trace. The Witcher 3 log in
|
||||
[comment 5962808629](https://github.com/countervolts/d4r/issues/10#issuecomment-5962808629)
|
||||
selects the gfx1200 d4r shim instead of the original NGX core (its SHA256
|
||||
matches the shipped shim exactly), and the installer correctly refuses
|
||||
before modifying the game. It does not establish a Witcher runtime failure.
|
||||
|
||||
## Build
|
||||
|
||||
Prepare dependencies following `windows-rdna4-port.md`. Default: gfx1201.
|
||||
Select another target explicitly and keep separate directories:
|
||||
|
||||
```powershell
|
||||
$arch = 'gfx1101' # for example RX 7800 XT
|
||||
$diag = "$PWD\dist\windows-$arch-diagnostics"
|
||||
.\scripts\windows\build-windows-rdna4.ps1 -RuntimeProfile therock -GpuArch $arch -ZludaRoot "$PWD\dist\zluda-windows-final" -BuildDirectory "$PWD\build\windows-$arch" -InstallDirectory $diag
|
||||
.\scripts\windows\stage-native-k.ps1 -DlssDll "$PWD\nvngx_dlss.dll" -PackageRoot $diag
|
||||
.\scripts\windows\stage-native-m.ps1 -DlssDll "$PWD\nvngx_dlss.dll" -PackageRoot $diag
|
||||
.\scripts\windows\package-windows-game.ps1 -DiagnosticRoot $diag -GpuArch $arch -PackageRoot "$PWD\dist\windows-$arch-game" -ArchivePath "$PWD\dist\windows-$arch-game.zip"
|
||||
```
|
||||
|
||||
Rebuild diagnostics for the new inventory executable. The package keeps strict
|
||||
K FP16 and M FP16-equivalent baselines; native M FP8 remains disabled. CMake:
|
||||
`-DD4R_GPU_ARCH=gfx1101`. Some source/executable names retain gfx1201/gfx12 for
|
||||
compatibility; actual targets follow the selected architecture.
|
||||
|
||||
One command compiles all eleven targets without GPU workloads:
|
||||
|
||||
```powershell
|
||||
.\scripts\windows\build-windows-gpu-matrix.ps1 -ZludaRoot "$PWD\dist\zluda-windows-final"
|
||||
```
|
||||
|
||||
Add `-PackageGames -DlssDll "$PWD\nvngx_dlss.dll" -ArchiveDirectory "$PWD\dist\windows-gpu-archives"`
|
||||
to stage/archive all packages after committing source and preparing OptiScaler.
|
||||
Use `-GpuArchitectures gfx1100,gfx1101,gfx1102,gfx1200,gfx1201` for a subset.
|
||||
Per-target logs and `matrix-build.json` distinguish compilation from execution.
|
||||
The supplied DLL generates manifests locally and is never copied into archives.
|
||||
|
||||
Rebuild LLVM/ZLUDA when updating from an older package: the old LLVM 22 backend
|
||||
does not recognize gfx1154 even though Clang 24 compiles native objects for it.
|
||||
`build-zluda-llvm.ps1` now applies the source backport in `patches/zluda-llvm`
|
||||
automatically; relink with `build-zluda-windows.ps1` afterward. Compiler base
|
||||
and patch hashes are recorded in the ZLUDA build metadata and included in game
|
||||
packages. The expected patched LLVM submodule appears modified in its parent
|
||||
checkout; its complete source delta is exported, not a binary target override.
|
||||
|
||||
For a compilation gate requiring neither a GPU nor NVIDIA DLLs, run:
|
||||
|
||||
```powershell
|
||||
.\scripts\windows\test-zluda-target-compilation.ps1 -ZludaRoot "$PWD\dist\zluda-windows-final"
|
||||
```
|
||||
|
||||
All 33 public PTX compilations pass for the eleven targets: Driver API pattern,
|
||||
FP16 MMA strict reference and explicit WMMA modes, with correct ELF targets
|
||||
and wave32. The gfx12 strict F16 reference intentionally retains its existing
|
||||
double-precision helper; the separate WMMA mode checks code generation only.
|
||||
It does not enable relaxed arithmetic in game packages or validate numerical
|
||||
results on other GPUs. The original gfx1154 compiler abort is preserved locally
|
||||
in `build/llvm-gfx1154/before.log`; the regression results are in
|
||||
`test-results/windows-gpu-coverage/zluda-offline`.
|
||||
|
||||
## Fork adaptation
|
||||
|
||||
Reviewed [realdody's branch](https://github.com/realdody/d4r/tree/windows-rdna3)
|
||||
at `ae530b0f53ed5c0bb87558dd7c20f619e014e4fd` and the newer
|
||||
[`1897b4a` correction](https://github.com/realdody/d4r/commit/1897b4afa79832bd879234cfb37e7c1468db5cde).
|
||||
Earlier MSVC binary16 and generated `BOOL` fixes remain. The earlier forced
|
||||
gfx12 fragment layout is not used.
|
||||
|
||||
The newer fork reports Windows gfx1101 `permlanex16` returning its own lane,
|
||||
duplicating even K values into odd slots. This port adapts that finding into
|
||||
`kernels/common/wave32_exchange.h`: a Windows/gfx11-only per-wave LDS exchange,
|
||||
with native gfx11 layout, generic x/y/z indexing, 2 KiB scratch (512 threads
|
||||
maximum), volatile accesses and wave fences/barriers protecting scratch reuse.
|
||||
It covers K/M fragment conversions and other K half-wave exchanges. gfx12 and
|
||||
Linux keep the original instruction path. The raw gfx11 probe uses its actual
|
||||
intrinsic/layout, without a forced gfx12 shim.
|
||||
|
||||
The fork reports RX 7800 XT enc1/enc2 identity/nonzero/reference checks. Those
|
||||
are **the author's results**, not validation of this adaptation or full K/M
|
||||
here. LDS exchange, full network, translated CUDA, accuracy, interop and speed
|
||||
still need physical gfx11 testing. Credit: realdody <dodobozicek@gmail.com>.
|
||||
|
||||
## Results and next hardware gate
|
||||
|
||||
All eleven targets compile the complete MinGW host build and 19 device objects
|
||||
with TheRock `10.2.0a20260929`, HIP `7.17.26386`, Clang 24. Software target
|
||||
contracts inspect actual ELF objects without other-target GPU launches.
|
||||
RX 9070 XT passes all 20 CTest gates after these changes. K/M full-frame and
|
||||
package checks are recorded in `windows-rdna4-port.md`. Local logs are in
|
||||
`build/windows-gpu-coverage` and `test-results/windows-gpu-coverage`.
|
||||
|
||||
The first hardware gate on another GPU needs no NVIDIA DLL:
|
||||
|
||||
```powershell
|
||||
.\scripts\windows\test-windows-rdna4.ps1 -RuntimeProfile therock -PackageRoot "$PWD\dist\windows-gfx1101-diagnostics" -ZludaRoot "$PWD\dist\zluda-windows-final"
|
||||
```
|
||||
|
||||
Success requires exit 0, correct actual target, exact HIP/PTX/WMMA/pixel checks
|
||||
and stable interop lifetime. Failure prints one ZIP. Full K/M reference,
|
||||
temporal, DLSS and game validation remain subsequent gates.
|
||||
@@ -0,0 +1,65 @@
|
||||
# Native Windows inference engine
|
||||
|
||||
Windows builds use the Linux branch's standalone Vulkan runtime. It loads Vulkan through pinned Volk, not through the
|
||||
D3D12 NGX shim. This keeps game integration separate while the inference and frame path is validated.
|
||||
|
||||
## Setup and build
|
||||
|
||||
Run `scripts/windows/setup-windows-tools.ps1 -RuntimeProfile therock`, then build the standalone runners:
|
||||
|
||||
```powershell
|
||||
pwsh -NoProfile -File scripts/windows/build-native-engine.ps1 `
|
||||
-HipRoot .tools/therock-10.2.0a20260929/_rocm_sdk_core -GpuArch gfx1101
|
||||
```
|
||||
|
||||
The script verifies pinned Vulkan-Headers and Volk revisions. It downloads Khronos glslang 16.6.0 from its official
|
||||
release and checks its SHA256 before extraction. Tools remain under ignored `.tools/`; runners remain under ignored
|
||||
`build/`. Rebuild a different architecture with its exact `gfx11*` or `gfx12*` target. The runner checks its required
|
||||
Vulkan features at startup and reports missing extensions or matrix types.
|
||||
|
||||
## Models and local frames
|
||||
|
||||
K, M and L model weights are local, derived from the user's own DLSS DLL or capture. Never copy them into source control
|
||||
or packages. Linux-compatible preparation tools are in `engine/`; K uses `extract_k.py`, `prepare_k.py` and
|
||||
`compile_k.py`. M and L use `compile_m.py`. A complete model needs a real captured NGX upload. The current native
|
||||
Windows runner does not provide a model-capture front end or D3D12 game adapter.
|
||||
|
||||
Prepare a frame case from tightly packed linear HDR color, motion, and inverse-depth images, then run K:
|
||||
|
||||
```powershell
|
||||
python engine/prepare_frames.py frames.json build/case.txt
|
||||
build/native-engine-windows-gfx1101/d4r-k.exe build/engine/k build/case.txt build/results 1
|
||||
```
|
||||
|
||||
To compile a local capture into K model files, expose the provisioned NumPy and shader compiler:
|
||||
|
||||
```powershell
|
||||
$env:PYTHONPATH = "$PWD/.tools/python/vendor"
|
||||
$env:PATH = "$PWD/.tools/glslang-16.6.0/bin;$env:PATH"
|
||||
python engine/extract_k.py CAPTURE/replay build/model-k/model
|
||||
python engine/prepare_k.py CAPTURE build/model-k/case --lut-only
|
||||
python engine/compile_k.py build/model-k/model build/model-k/case/lut.bin build/engine/k
|
||||
```
|
||||
|
||||
The runner writes full-resolution output and intermediate history files. Set `D4R_ENGINE_PROFILE=1` to report per-stage
|
||||
GPU timings. Timings are Vulkan replay measurements; they do not prove game-queue latency or DLSS numerical parity.
|
||||
|
||||
M uses `d4r-m.exe MODEL_DIR RENDER_W RENDER_H OUT_W OUT_H OUTPUT_PREFIX [REPEATS] -- COLOR MOTION DEPTH JITTER_X JITTER_Y ...`.
|
||||
L uses the same runner and a preset-L model produced from an L capture. `d4r-rr.exe` uses the Linux RR model/input
|
||||
formats documented in `engine/README.md`; it is not connected to Ghost of Tsushima.
|
||||
|
||||
## Current Windows evidence
|
||||
|
||||
K, M and RR runners compile as native Windows x64 executables. RX 7700 XT Vulkan feature checks pass for the K f16
|
||||
engine. A seeded finite synthetic K model completed a 256x256 full-frame dispatch and readback on that GPU in about
|
||||
4.14 ms. It has synthetic weights and is not evidence of DLSS model quality. NVIDIA NGX model extraction, game
|
||||
integration, presets M/L runtime feature support, and preset timings remain unverified.
|
||||
|
||||
## NVIDIA runtime files
|
||||
|
||||
The release includes `install.bat` plus `install-dlss.ps1`. It downloads SR and RR 310.9.1 from the pinned official
|
||||
NVIDIA/DLSS source, and the NGX core from NVIDIA driver 617.14. It verifies archive and DLL SHA256 values before
|
||||
changing the local d4r folder. The 991 MiB driver archive is extracted with pinned 7-Zip `7zr`; the driver installer
|
||||
never runs. Existing target DLLs are copied to `%LOCALAPPDATA%\d4r\backups` with a manifest of original paths and
|
||||
hashes. Verified files are cached under `%LOCALAPPDATA%\d4r\cache\nvidia`. The RR DLL is preparatory; RR inference is
|
||||
not connected to the Windows game shim.
|
||||
@@ -0,0 +1,27 @@
|
||||
d4r Windows quick test
|
||||
======================
|
||||
|
||||
This private test package supports native Windows D3D12 on the GPU target in
|
||||
its manifest. It needs the matching original NVIDIA _nvngx.dll and
|
||||
nvngx_dlss.dll supplied by the tester. Those DLLs are not in d4r source or
|
||||
public packages.
|
||||
|
||||
Run START-K.cmd, START-M.cmd, START-E.cmd, or START-L.cmd. The launcher checks
|
||||
the package hashes, detects the real HIP target, and rejects a package/GPU
|
||||
mismatch before changing the game folder. It backs up only files it replaces
|
||||
in .d4r-backup. The run lasts up to 180 seconds by default; use the PowerShell
|
||||
launcher with -RunSeconds to choose another bounded run.
|
||||
|
||||
Preset E uses NGX preset 5 and has no native Windows CNN kernels. K uses preset
|
||||
11 and the native K transformer. L uses preset 12 and currently relies on the
|
||||
M-family Swin layers plus translated texture kernels. M uses preset 13. E and L
|
||||
are experimental Windows paths; a selected hint or successful DLL load is not
|
||||
frame proof. Reports must show completed DLSS frames and output checks.
|
||||
|
||||
After the game exits, run RESTORE-GAME.cmd before using the game normally. The
|
||||
restore checks installed-file hashes and restores only the entries recorded in
|
||||
.d4r-backup. It preserves unrelated mods, shared loaders, game files and saves.
|
||||
Keep the printed diagnostic ZIP for any failed or inconclusive run.
|
||||
|
||||
Do not enable async interop for first tests. Do not change drivers, TDR values,
|
||||
Windows security policy or GPU tuning as part of this test.
|
||||
File diff suppressed because it is too large.
Load diff
Reference in new issue
Block a user