Files
d4r/docs/building.md
T
ayo 4334a0c3c4 Add RDNA4 (gfx12) support and a 0.1.2 optimization round
RDNA4 (experimental; untested on RDNA4 hardware)
- kernels/common/wmma_layout.h picks the WMMA operand/accumulator layout
  per target; K (pwin_*) and M (swin_*) index through it, so the same
  sources build for gfx11 and gfx12. D4R_WMMA_LAYOUT=12 on gfx11 is a test
  shim that runs the gfx12 indexing on gfx11 WMMA.

- M can use native e4m3 FP8 WMMA on gfx12 (D4R_NATIVE_FP8=1). Texture
  tails (enc0_tail, dec0_head) get gfx12 f16 and FP8 paths that match
  ZLUDA's gfx12 lowering.

- ZLUDA patch 0007: gfx12 WMMA helpers, optional native FP8 MMA
  (D4R_ZLUDA_WMMA_FP8_NATIVE), a layout override for testing, and an
  architecture argument for d4r_emit. Texture kernels are now compiled
  offline per target through d4r_emit (D4R_ZLUDA_EMIT) instead of on the
  local GPU.

- New d4r.ini option [Kernels] NativeFp8 (default on), wired through the
  shim and d4r_config.py. On gfx12 the bridge serves kernels/<arch>-fp8
  when it is on.

- The bridge picks the KFD GPU with the most SIMDs (so an iGPU is not
  chosen over a discrete GPU); D4R_GPU_ARCH overrides it.

- kernels/build.sh and package_release.sh build gfx1100-gfx1103 and
  gfx1200/gfx1201 (plus -fp8 variants), and D4R_BUNDLE_TEX takes
  per-target folders.

Performance (RDNA3; harness byte-identical unless noted)
- ZLUDA patch 0006: m16n8k8 f16 MMAs on WMMA (E; not bit-exact, 52-55 dB
  per layer, D4R_ZLUDA_WMMA_K8=0 disables it), per-key weight-image slots
  for native prep kernels (d4r_prep_key_at, d4r_prep_key_slots), and
  wave64 builds of MMA-free kernels (D4R_ZLUDA_WAVE64).

- M: packed FP8 encoding, conflict-free patch-merge reads, scalar weight
  loads in enc1, and weight prep once per weight set for the six enc3
  tube blocks.

- K: CU mode for the six non-wide pwin layers.

- Texture kernels: every DLSS flag variant is built natively (24 K output,
  8 M post, 4 M downsample, 4 M enc0), not only Townfall's; post and K
  output run as wave64.

- M direct output: rrlite_downsample_kernel writes the shim's output
  buffer; the shim's default direct-output presets are now 11,13.

Tools
- dump_runner takes the prep grid from d4r_prep_blocks and refuses
  texture/surface dumps.

- New pwin_check.py, swin_check.py, model_enc3.py and tail_check.hip.

Docs: README GPU table and RDNA4 notes, building (patches 0002-0007,
d4r_emit), native-kernels (RDNA4 section), performance (new numbers),
packaging README. Version 0.1.2.
2026-09-29 20:36:10 -04:00

8.0 KiB
Raw Blame History

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
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

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

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), 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

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

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

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

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. The texture kernels (tex) 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.

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:

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

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 \
scripts/package_release.sh            # -> dist/d4r-<version>.zip

The script:

  • builds the shim, the bridge and the 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);
  • 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 describes how the installed files work together.

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.