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.
This commit is contained in:
ayo committed 2026-09-29 20:36:10 -04:00
1 parent f310d52b69
commit 4334a0c3c4
42 files changed
+3068 -529

No files matched your search

+7 -1
View File
@@ -9,6 +9,9 @@ LLVM_DIS="${LLVM_DIS:-$ROCM_ROOT/lib/llvm/bin/llvm-dis}"
LLVM_AS="${LLVM_AS:-$ROCM_ROOT/lib/llvm/bin/llvm-as}"
OCML="${OCML:-$ROCM_ROOT/amdgcn/bitcode/ocml.bc}"
WORK_ROOT="${D4R_ZLUDA_PTX_HELPER_WORK:-${TMPDIR:-/tmp}/d4r-zluda-ptx-helpers}"
# D4R_ZLUDA_HELPER_FLAGS: extra compiler flags, e.g. -DD4R_WMMA12_SHIM for the gfx12-layout test build (never
# ship it: its gfx12 helpers use gfx11 WMMAs)
read -r -a EXTRA_FLAGS <<< "${D4R_ZLUDA_HELPER_FLAGS:-}"
if [[ -z "$ZLUDA_SOURCE_ROOT" || ! -f "$ZLUDA_SOURCE_ROOT/ptx/lib/zluda_ptx_impl.cpp" ]]; then
printf 'Set ZLUDA_SOURCE_ROOT to a ZLUDA source checkout\n' >&2
@@ -27,7 +30,7 @@ PTX_LIB="$ZLUDA_SOURCE_ROOT/ptx/lib"
COMMON_FLAGS=(-DHIP_ENABLE_WARP_SYNC_BUILTINS -std=c++20 -Xclang -fdenormal-fp-math=dynamic
-Wall -Wextra -Wsign-compare -Wconversion -x hip "$SOURCE" -nogpulib -O3
-mno-wavefrontsize64 --offload-device-only --offload-arch=gfx1030 -emit-llvm -c
-Xclang -mlink-bitcode-file -Xclang "$OCML")
-Xclang -mlink-bitcode-file -Xclang "$OCML" "${EXTRA_FLAGS[@]}")
build_one() {
local suffix="$1"
@@ -55,3 +58,6 @@ build_one() {
build_one ""
build_one "_constrained" -ffp-model=strict -ffp-exception-behavior=ignore
# wave64 helpers (D4R_ZLUDA_WAVE64: two CUDA warps per wave; see d4r_warp_base in zluda_ptx_impl.cpp)
build_one "_w64" -mwavefrontsize64 -DD4R_WAVE64
build_one "_constrained_w64" -ffp-model=strict -ffp-exception-behavior=ignore -mwavefrontsize64 -DD4R_WAVE64
+3
View File
@@ -129,6 +129,9 @@ def main(argv):
value = flag("Kernels", key)
if value is not None:
env[var] = "1" if value else "0"
# RDNA4's native FP8 WMMA (on unless set off; ZLUDA and the bridge ignore it on other GPUs)
value = flag("Kernels", "NativeFp8")
env["D4R_ZLUDA_WMMA_FP8_NATIVE"] = "0" if value is False else "1"
value = get("Kernels", "ImplicitMaxBlock")
if value:
env["D4R_ZLUDA_IMPLICIT_MAX_BLOCK"] = value
+2 -2
View File
@@ -22,8 +22,8 @@ export D4R_ZLUDA_LIBCUDA="$D4R_ZLUDA_DIR/libcuda.so"
# most 256-thread blocks, as CUDA itself allows 255 registers for them; the
# default 1024 bound caps gfx11 waves at 96 VGPRs and makes them spill.
export D4R_ZLUDA_IMPLICIT_MAX_BLOCK="${D4R_ZLUDA_IMPLICIT_MAX_BLOCK:-256}"
# f16 tensor-core MMAs (DLSS's convolutions) run on gfx11 WMMA instead of a
# dot-product fallback (patches/zluda/0003); 0 selects the fallback.
# f16 tensor-core MMAs (DLSS's convolutions) run on gfx11/gfx12 WMMA instead of a
# dot-product fallback (patches/zluda/0003 and 0007); 0 selects the fallback.
export D4R_ZLUDA_WMMA="${D4R_ZLUDA_WMMA:-1}"
# DLSS frames in flight. The presented upscaled image is this many game frames
# old at most: 3 = highest frame rate (Townfall ~86 fps, age 2-3), 2 = age 2
+33 -11
View File
@@ -13,7 +13,8 @@
# D4R_ROCM_DIR ROCm with clang, for the kernels default /opt/rocm
# D4R_ROCM_RUNTIME ROCm runtime bundled as d4r/rocm (scripts/fetch_rocm_runtime.sh)
# default ~/.cache/d4r-rocm-runtime
# D4R_GPU_ARCHS GPU targets to build kernels for default gfx1101
# D4R_GPU_ARCHS GPU targets to build kernels for default gfx1100 gfx1101 gfx1102 gfx1103 gfx1200 gfx1201
# (RDNA4 targets also get a <target>-fp8 folder: the kernels for d4r.ini NativeFp8 = on)
# D4R_OPTISCALER_LICENSE OptiScaler's LICENSE (GPL-3.0) text; default: the system's SPDX copy
# D4R_VKD3D_SRC vkd3d-proton source checkout, for its license files default ~/.cache/d4r-vkd3d-proton
# D4R_ZLUDA_SRC ZLUDA source checkout, for its license files default: D4R_ZLUDA_DIR's ../d4r-zluda-upstream
@@ -21,7 +22,9 @@
# The zip also contains NVIDIA's files and the texture kernels built from NVIDIA's PTX; redistributing
# those is up to whoever publishes it (they are not covered by d4r's license):
# D4R_BUNDLE_DLSS nvngx_dlss.dll to include D4R_BUNDLE_NGX _nvngx.dll to include
# D4R_BUNDLE_TEX directory with the texture-kernel code objects (kernels/build.sh tex), for gfx1101
# D4R_BUNDLE_TEX directory with texture-kernel code objects (kernels/build.sh tex), one subdirectory
# per target folder (gfx1101, gfx1201, gfx1201-fp8, ...), or a flat gfx1101 directory for
# older builds
# D4R_BUNDLE_NVIDIA=0 leaves them out (d4r-VERSION-nonvidia.zip; users then add the two DLLs themselves).
set -euo pipefail
@@ -37,7 +40,7 @@ ZLUDA="${D4R_ZLUDA_DIR:-$HOME/.cache/d4r-zluda-current}"
VKD3D="${D4R_VKD3D_DIR:-$HOME/.cache/d4r-vkd3d-d4r}"
ROCM="${D4R_ROCM_DIR:-/opt/rocm}"
ROCM_RUNTIME="${D4R_ROCM_RUNTIME:-$HOME/.cache/d4r-rocm-runtime}"
ARCHS="${D4R_GPU_ARCHS:-gfx1101}"
ARCHS="${D4R_GPU_ARCHS:-gfx1100 gfx1101 gfx1102 gfx1103 gfx1200 gfx1201}"
: "${D4R_OPTISCALER:?set D4R_OPTISCALER to the OptiScaler release archive or folder}"
: "${D4R_DLSS_DLLS:?set D4R_DLSS_DLLS to the nvngx_dlss.dll files the kernel manifest accepts}"
for f in "$ZLUDA/libnvcuda.so" "$VKD3D/d3d12.dll" "$VKD3D/d3d12core.dll" "$ROCM_RUNTIME/lib/libamdhip64.so.7"; do
@@ -108,16 +111,35 @@ else
printf 'Put NVIDIA'"'"'s NGX runtime, _nvngx.dll, in this folder (see D4R_README.txt).\r\n' > "$STAGE/d4r/ngx/README.txt"
fi
IFS=: read -r -a DLLS <<< "$D4R_DLSS_DLLS"
# one folder per target; RDNA4 targets also get <target>-fp8 (native FP8 WMMA, d4r.ini NativeFp8), which the
# bridge serves instead when that setting is on
folders=()
for arch in $ARCHS; do
D4R_ROCM_DIR="$ROCM" D4R_GPU_ARCH="$arch" "$ROOT/kernels/build.sh" k "$STAGE/d4r/kernels/$arch" >/dev/null
D4R_ROCM_DIR="$ROCM" D4R_GPU_ARCH="$arch" "$ROOT/kernels/build.sh" m "$STAGE/d4r/kernels/$arch" >/dev/null
rm -f "$STAGE/d4r/kernels/$arch"/*.resolution.txt # empty LTO notes from clang's -save-temps
if [[ "$VARIANT" == full && "$arch" == gfx1101 ]]; then
for f in "$D4R_BUNDLE_TEX"/*.hsaco; do # texture kernels only; the layers above are built from source
[[ -e "$STAGE/d4r/kernels/$arch/$(basename "$f")" ]] || cp "$f" "$STAGE/d4r/kernels/$arch/"
done
folders+=("$arch")
[[ "$arch" == gfx12* ]] && folders+=("$arch-fp8")
done
for folder in "${folders[@]}"; do
arch="${folder%-fp8}"
fp8=0
[[ "$folder" == *-fp8 ]] && fp8=1
D4R_ROCM_DIR="$ROCM" D4R_GPU_ARCH="$arch" D4R_NATIVE_FP8="$fp8" "$ROOT/kernels/build.sh" k "$STAGE/d4r/kernels/$folder" >/dev/null
D4R_ROCM_DIR="$ROCM" D4R_GPU_ARCH="$arch" D4R_NATIVE_FP8="$fp8" "$ROOT/kernels/build.sh" m "$STAGE/d4r/kernels/$folder" >/dev/null
rm -f "$STAGE/d4r/kernels/$folder"/*.resolution.txt # empty LTO notes from clang's -save-temps
if [[ "$VARIANT" == full ]]; then
tex_dir=""
if [[ -d "$D4R_BUNDLE_TEX/$folder" ]]; then
tex_dir="$D4R_BUNDLE_TEX/$folder"
elif [[ "$folder" == gfx1101 ]]; then
tex_dir="$D4R_BUNDLE_TEX" # older, flat gfx1101 texture-kernel builds
fi
if [[ -n "$tex_dir" ]]; then
for f in "$tex_dir"/*.hsaco; do # texture kernels only; the layers above are built from source
[[ -f "$f" ]] || continue
[[ -e "$STAGE/d4r/kernels/$folder/$(basename "$f")" ]] || cp "$f" "$STAGE/d4r/kernels/$folder/"
done
fi
fi
python3 "$ROOT/kernels/tools/kernel_manifest.py" "$STAGE/d4r/kernels/$arch" "${DLLS[@]}"
python3 "$ROOT/kernels/tools/kernel_manifest.py" "$STAGE/d4r/kernels/$folder" "${DLLS[@]}"
done
# licenses and sources