L's unfolded enc0 and dec0 are still ZLUDA's compile of NVIDIA's PTX and cost
2.95 ms of the preset's 5.86 ms per frame (RX 9070 XT, 1280x720 -> 4K). The
embedding, the patch expand, the Swin block (32 channels, 2 heads, at pixel
resolution) and the patch merge are now native token-lane code; the texture
work around them stays ZLUDA's compile.
enc0l_tail.hip cuts in at the barrier after the feature staging and dec0l_block.hip
before the output code that reads the block's f16 result out of the last MMAs; make_ptx.py
splices either in when D4R_TEX_SRC names it and build.sh selects both for the gfx12
native-FP8 builds. swin_tex.h carries the indexing the two tails share; swin_tok.h gains
the pixel-order token layout (SWIN_TOK_NATURAL), ZLUDA's attention key order
(SWIN_PV_ZLUDA_ORDER) and swin_tok_core, which the encoded tests reuse. swin_common.h
takes the block weight layout (moved out of swin_block.h) and the exact and approximate
reciprocal / mix forms the tails need without the HIP headers (D4R_NO_HIP_RUNTIME).
The f32 sums stay in ZLUDA's order (K slots of the FP8 WMMAs, key order of the f16
attention product) and rsqrt/rcp use the hardware approximations ZLUDA lowers to, so the
harness's final frame is byte-identical to the translated kernels: all four enc0 flag
variants, 720p and 1080p render, 1440p and 4K output, static and moving scenes, 100
frames, and the accuracy set. With M's own sum order about one token in 20,000 differed.
M's layers compile to the same instructions and its frame is byte-identical.
enc0 1.69 -> 0.63 ms and dec0 1.26 -> 0.54 ms at 720p->4K, 2.73 -> 1.16 and 2.28 -> 1.01
at 1080p->4K; the preset 5.83 -> 4.06 and 8.63 -> 5.69 ms. -DD4R_SWIN_K32_MIX rounds the
f16 products earlier for 0.56 and 0.49 ms and is not byte-identical, so it is not built by
default. The repo's tests pass (36, 3 skipped).
Shim
- Adaptive output-event wait: sleep to ~120 us before the predicted
completion (smoothed per wait site), spin near it, back off when late.
D4R_SHIM_OUTPUT_POLL_US restores a fixed interval.
- Defer the input-marker wait into the worker thread with VRAM interop
(D4R_SHIM_DEFER_MARKER, default on), taking the host setup off the
critical path.
MicroCUDA
- Experimental ZLUDA-free backend in wine_nvcuda_bridge, plus
tools/microcuda and scripts/build_microcuda.sh. Serves accuracy, fast
and native kernels; unregistered modules fall back to the reference
path. Unclassified writes invalidate prepared weights.
M kernels
- SWIN_PREP_IDENTITY_AT: key weight prep by allocation identity
(MicroCUDA); enc3 tube uses it with 8 slots. ZLUDA ignores it.
- dec2 (gfx1101): SWIN_PACKED_RESIDUAL, byte-identical, ~1.6% faster.
- Opt-in gfx12 hardware fp8 conversion (SWIN_FP8_HWCVT), unverified
on hardware.
Native K translators
- ctile: handle variants that re-materialize the parameter base (mvlo).
- rewrite_output: check live-in registers, not just outputs.
- build.sh: native input covers all 8 flag variants, output the 4 HDR
"max" variants; depth-tile skip stays mvhi-only.
Tools
- dump_runner and bench_dlss_kernel harness additions.
swin_tok.h passes the weights as the first WMMA operand and the activations as the second, so each GEMM's encoded result is already the next one's operand and stays in registers (swin_block.h transposes every result through LDS). One wave owns one 4x4 window for the whole block: norms, attention and the MLP need no LDS and no barriers; only the patch expand and the patch merge go through an e4m3 image in LDS. Outputs are bit-identical to swin_block.h (swapped WMMA operand roles, verified on an RX 9070 XT and on recorded launches). mix2 rounds in place (accumulator is addend and destination, no copy per pair). -DSWIN_NO_TOKEN_LANES builds these layers from swin_block.h again; enc2 and dec2 are unchanged. RX 9070 XT accuracy set, 2560x1440 render: whole evaluation 8.56 -> 7.18 ms.
The FP8 Swin layers encode with a clamp to +-448 (NaN-propagating packed
minimum/maximum) followed by v_cvt_pk_fp8_f32, in both the fast and the
accuracy build: equal to half_to_e4m3 for every non-NaN input, NaN encodes
as 0xff. The accuracy build rounds each k32 step with v_fma_mix (K32_MIX).
On gfx12 the accuracy builds of M's post and downsample kernels are wave64
with denormal handling kept.
RX 9070 XT, 1280x720 -> 3840x2160, D3D12 harness: the accuracy set goes
from 3.54 ms to 3.05 ms per evaluation (3.01 -> 2.59 ms under load). Its
Swin layers still equal swin_model.py on sampled blocks and its image is
byte-identical to the previous accuracy set over 8 temporal frames.
On the gfx12 native-FP8 path the Swin layers kept GEMM activations as f16
in LDS and encoded them to e4m3 again at every operand load. They are now
encoded once where they are produced, with v_cvt_pk_fp8_f32, and stored as
bytes (SWIN_A8); the patch merge reads the stored output codes. The M
downsample kernels are built as wave64 on gfx12.
RX 9070 XT, 1280x720 -> 3840x2160, D3D12 harness, DLSS 310.7: whole
evaluation 5.9 ms -> 2.8 ms of GPU time with the GPU otherwise idle, 2.4 ms
at 80-98% GPU utilisation. Harness output is byte-identical to the previous
kernels; the accuracy build matches swin_model.py on sampled blocks.
Builds without D4R_FP8_WMMA (RDNA3, and RDNA4 with NativeFp8 off) compile to
the same instructions as before.
Preset K, byte-identical to the previous output in all captured buffers
and the harness image, measured on an RX 7700 XT:
- LDS row padding so WMMA operand loads hit distinct banks
- WGP mode for enc1/enc2/dec1/dec2, ds_bpermute half-wave exchange for
enc0/dec0/dec3, more waves per window in enc4/dec4/dec5
- cheaper operand plumbing in common/wmma_layout.h (packed f16
conversions, no dynamic vector indexing), raw buffer weight loads,
accumulator-init vectors prepared once
- enc1 as a single-buffer recompute layer, dec1 Q/K/V chains split
- dec5 as four dependent phase kernels
- Add default-off PreferAccuracy for all native kernel families,
including RDNA4 FP8 variants.
- Restore intermediate FP8 quantization, per-MMA FP16 rounding,
denormal handling and NGX synchronization in accuracy mode.
- Select separately marked accuracy kernels and use a separate JIT
cache; reject mixed sets and never silently substitute fast kernels.
- Add a pinned GLIBC 2.41 build environment for ZLUDA/LLVM, the DLLs
and both kernel sets, with ABI checks and toolchain provenance.
- Support parallel target builds and pre-extracted PTX; correct
ROCm header paths and Clang-CL input handling.
- Bump to 0.1.3 and update release notes, documentation and tests.
Validation: 11 tests passed; all 912 kernels built; E/K/M GPU harness
runs completed with accuracy off/on. Packaged libraries loaded under
GLIBC 2.41 and require no GLIBC version newer than 2.38.
RTX image-quality parity remains unverified.
Fixes#6
Refs #6
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.