Files
d4r/docs/windows-rdna4-port.md
T

69 KiB
Raw Blame History

Windows / RDNA4 port

Branch: windows-rdna4. Target: Windows 11 x64, RX 9070 XT, gfx1201. Priority: correct K, correct M, native Windows, same-frame output, then speed. This is a work log for an implementation in progress. Standalone DLSS K/M works on the real Windows GPU, including the patched OptiScaler frontend. An actual game session remains unverified.

Milestone and gates

Current milestone: M1/M2/M4/M5 passed; native NGX Create/Evaluate on the simple requested E path passes with the user's DLLs. All 11 K layers now pass synthetic and real-weight NumPy/PTX replay checks; native K Evaluate produces four finite frames on Windows. M now passes all five synthetic and real-weight layers against NumPy and independent PTX, and four native CUDA frames. The standalone D3D12 harness now produces four K and four M frames using imported VRAM and shared fences, with bit-exact RGB agreement against the corresponding CUDA harnesses. Game integration remains in progress. The ordinary NGX D3D12 Evaluate API now records a boundary in an open command list; a native queue interception backend executes prefix, CUDA evaluation, then suffix in the same submitted frame. A full temporal M scan found rare attention P/V accumulation mismatches that the earlier twelve-block sampling missed. SWIN_EXACT_PV fixes the native baseline; ZLUDA patch 0013 adds the corresponding opt-in f16 reference accumulation. All spatial blocks in 40 actual native M launches now exactly match NumPy. Four complete native M RGB frames exactly match fully translated M with the corrected reference option. Do not integrate NGX until the integer PTX workload is stable on the real GPU.

Gate Status
M0: branch, audit, Windows build and diagnostics Initial implementation complete
M1: native HIP gfx1201 allocation, kernel, CPU verification PASS, 32 iterations + guard verification
M2: Windows ZLUDA integer PTX, primary and created contexts PASS, 32 iterations each + guard verification
M3: Windows NGX initialization and simple DLSS path Init, SR capabilities, Create/Evaluate PASS; E, K and M CUDA harnesses execute
M4: D3D12 / HIP external memory and fence round trip PASS with TheRock; stable 7.2 has mapped-view leak
M5: independently validated gfx12 WMMA backend PASS: raw + legacy adapter + upstream layout, max abs/relative error 0
M6: K layers, full transformer and image validation PASS: 11 real-weight layers, 44 native launches, four D3D12 frames bit-exact against native CUDA, 81.85–92.91 dB versus translated K
M7: M FP16-equivalent baseline and full transformer PASS: all blocks of 40 native launches exactly match NumPy; targeted independent PTX regression matches; four D3D12 frames bit-exact against corrected translated M
M8: standalone Windows D3D12 NGX harness PASS for ordinary recorded EvaluateFeature and explicit boundaries: K/M, four frames each, no shim CPU image copies; both bit-exact against explicit boundary baselines
M9: OptiScaler integration, profiling, installation Patched frontend K/M PASS; game, profiling and final package pending

Public NGX identity and OptiScaler gate (2026-10-01)

The Windows shim now implements D3D12 GetFeatureRequirements and forwards Init_ProjectID to CUDA Init_ProjectID with the caller's project/engine/version. The runtime owns the feature path strings and pointer list. The physical HIP gfx1201 architecture and full DXGI adapter LUID determine SR support; other features remain unsupported. Numeric driver initialization retains the tested three-argument CUDA Init ABI. -NgxAbi project selects the public project path in both CUDA and D3D12 probes. Capability parameter allocation is transactional.

ngx-project-api.zip passes direct CUDA project initialization. d3d12-k-project-api.zip and d3d12-m-project-api.zip pass four recorded enhanced-barrier packed-format frames with 44 K / 40 M native launches. All RGB values exactly match the independently quantised earlier baselines, max absolute/relative error 0. Full rebuild and CTest pass 16/16 gates (project-api-ctest.log).

The runner now accepts -OptiScalerDll <absolute-path>, creates a private OptiScaler.ini and captures the frontend log. Native-network hit validation is mandatory for the integration runs. The official 0.9.4 release silently chose FSR despite DLSS=enabled on AMD: optiscaler-m-first.zip is correctly FAIL with zero native launches. Current nightly 20261001 also gates DLSS on a System32 NVIDIA driver; preloading our NVAPI triggered access violation 0xc0000005 in its loader hooks (optiscaler-m-nightly-first.zip). This is not a DLSS success. The probe no longer preloads NVAPI before OptiScaler startup. Crash capture avoids module resource enumeration in the exception filter, guards reentrancy and records the minidump's module list instead.

A local OptiScaler source fork starts from 45a2001303ddff632e279f77aef85ceede5832cb. Its explicit [DLSS] AllowExternalBackend=true option requires an absolute NvngxPath with the d4r_WindowsBackendVersion ABI-1 marker; it does not spoof HIP architecture. The marker is GPU-free and safe during discovery. The patch lets the external backend load its own NVAPI provider through the original loader and preserves the exact locally supplied CUDA NGX core path from frontend redirection. Physical adapter capability is queried outside DLL startup instead of using NVIDIA architecture as a proxy. GetFeatureRequirements spoofing is bypassed. Explicit external DLSS selection returns errors instead of silently using FSR. Microsoft Build Tools 17.14 / MSVC 14.44.35207 and SDK 10.0.26100 were installed from the signature-verified official bootstrapper without restarting Windows. No game files have been modified.

The OptiScaler fork commit is 33bbac2 on windows-rdna4-d4r. Its reproducible source patch and build instructions are in patches/optiscaler. build-optiscaler-windows.ps1 produces a DLL, PDB, GPL license and dependency metadata from pinned source/submodules; it disables upstream's unrelated packaging post-build commands. The public D3D12 probe now supplies and submits a real open creation command list, as required by OptiScaler's API.

optiscaler-k-final.zip and optiscaler-m-final.zip pass four complete OptiScaler -> Windows d4r -> CUDA NGX -> ZLUDA/HIP evaluations on RX 9070 XT. They contain 44 K and 40 M native transformer launches, respectively. Every RGB value exactly matches the independently quantised direct-d4r baseline; max absolute/relative error is 0. No FSR evaluation, NaN/Inf, shim CPU image copy or previous-frame output is observed. The invalid-core regression intentionally passes the shim as the CUDA core: it fails with an explicit frontend refusing FSR fallback message and zero FSR evaluations, as required.

The loader crash was localized with a PDB to Util::IsSubpath calling filesystem::relative/weakly_canonical from LdrLoadDll interception. The patched check is lexical, case-insensitive and handles empty relative paths without filesystem I/O. The separate d4r_debug_launcher.exe, enabled by -CaptureExceptions, captures minidumps, first/second-chance exception codes, module load/unload addresses and raw stack slots outside the hooked process. It propagates the child's exit code and terminates its child on runner timeout via a process lifetime job. optiscaler-m-source-debug2.zip contains the successful dump capture and optiscaler-source-stack-symbols.log the source attribution. The ordinary in-process crash filter remains available too.

Initial PSO and enhanced texture layouts (2026-10-01)

The backend now captures the initial PSO supplied to public CreateCommandList, in addition to Reset and SetPipelineState. Its suffix can dispatch without rebinding that PSO. The public foundation probe's initial-pso mode passes 32 native RX 9070 XT iterations; the WARP diagnostic passes too. The runtime now installs 81 documented method hooks, including CreateCommandList.

Resource tracking distinguishes legacy states from enhanced texture layouts for mip/array/plane zero. Barriers on unrelated subresources do not overwrite that state. An unfinished split barrier on an NGX texture explicitly rejects Evaluate. The queued snapshot owns the layout/access metadata. Native interop uses CommandList7 texture barriers to enter COPY_SOURCE/COPY_DEST and restore the exact enhanced layout and access class; it does not reinterpret enhanced layouts as legacy states. Legacy texture copies also affect only subresource zero. Shared linear buffers continue to use their own legacy COMMON/copy states. This follows Microsoft's enhanced barrier interoperability rules.

d3d12_gpu_enhanced_formats independently tests all nineteen storage/plane cases with a D3D12 enhanced producer and consumer. Full build and CTest pass 16/16 gates (enhanced-final-ctest.log, fifteen hardware and one WARP). d3d12-m-enhanced-packed.zip and d3d12-k-enhanced-packed.zip each pass four recorded NGX frames with their complete native transformer. Enhanced snapshot logs report shader-resource layout 21 and unordered-access layout 20. All four RGB images in both runs exactly match their independently quantised FP16 baselines, max absolute/relative error 0. Frame age and shim CPU image copy counts remain zero. Add -BarrierMode enhanced to the packed-run command below to reproduce. The explicit harness can also supply layout metadata.

Tracking currently observes the evaluated list's barriers. A texture whose state was established only in a different list uses the caller-supplied state or the legacy NGX default; queue-wide state inheritance remains an integration gate. Unknown pre-initialization indirect signatures are still rejected. OptiScaler's default restore hotfixes are false; integration will keep RestoreComputeSignature, RestoreGraphicSignature and ExtendedStateRestore false because their original-method trampolines can bypass logical-list routing. Actual OptiScaler probes have exposed the frontend gate documented above; no game files have been changed.

Native GPU resource-format conversion (2026-10-01)

pixel_convert_gfx1201.hsaco converts imported D3D12 copy footprints to NGX's RGBA16F/RG16F/R32F arrays and converts output back to the original resource format. Canonical formats retain the existing direct path. Other formats use pitched HIP allocations and native decode/encode kernels; images stay in VRAM. Completion currently synchronizes the host before NGX uses its other streams. The module is installed beside d4r_nvngx.dll; D4R_FORMAT_MODULE can override its absolute path. The diagnostic runner copies it into its owned temporary NGX runtime alongside the shim. No NVIDIA binaries are installed in packages.

Supported storage: RGBA16/32F, RGBA/BGRA8 UNORM, R11G11B10 FLOAT, RGB10A2 UNORM, RG16/32F, RG16 SNORM/UNORM, R16F exposure, R32F/D32 depth, D24/R24 depth and D16/R16 UNORM depth. Typeless R16 means floating-point exposure or UNORM depth, according to the NGX plane. sRGB and D32S8 conversion are explicitly rejected until independently validated. Optional mask textures are not supported yet.

The public d4r_d3d12_pixel_probe tests nineteen plane/format combinations at 259x17, with padded pitches, partial workgroups and row guards. D3D12 typed SRV loads provide independent float32 decode values, with a mathematical binary16 nearest-value search for CUDA RNE conversion. HLSL f32tof16 is not used as an RNE reference: the current driver truncates that operation. Color encode is compared bit-for-bit to typed UAV stores read through a D3D12 consumer SRV. The reference includes HDR limits, subnormals, signed motion endpoints, UNORM rounding/clamping and packed channel permutations. An initial RNE R11 encoder failed this test; truncation now matches the driver, including finite HDR limits. See Microsoft's format-conversion specification.

Results on RX 9070 XT / TheRock:

  • pixel-final-ctest.log: 14/14 PASS (13 hardware tests and one WARP test).
  • pixel-milestone-diagnostics.zip: all fourteen public diagnostic gates PASS.
  • d3d12-m-packed-formats.zip: four M frames, forty native network launches, R11 color/output, RGBA32 motion, R16 exposure, zero shim CPU image copies.
  • d3d12-m-unorm-formats.zip: four M frames with BGRA8 output, RG16 SNORM motion and RGBA32 exposure; forty native launches, frame age zero.
  • d3d12-k-packed-formats.zip: four K frames and forty-four native launches.
  • Each of those three complete runs matches its FP16 baseline after the independent D3D12 resource-format quantisation: RGB max absolute/relative error 0, PSNR infinite. No tolerance was relaxed for packed output.

Reproduce a complete packed M run with locally supplied NVIDIA DLLs:

$env:D4R_ZLUDA_NATIVE_DIR="$PWD/build/native-m-gfx1201"
$env:ZLUDA_CACHE_DIR="$PWD/build/zluda-cache-windows"
powershell -NoProfile -File scripts/windows/test-windows-rdna4.ps1 -RuntimeProfile therock -ZludaRoot "$PWD/dist/zluda-windows-f16-reference" -PackageRoot "$PWD/dist/windows-rdna4-command-list" -NgxCore "$PWD/_nvngx.dll" -DlssDll "$PWD/nvngx_dlss.dll" -NgxMode d3d12 -Preset 13 -NgxOnly -RequireNativeNetwork -CommandListBackend -PixelProfile packed -Trace -Iterations 4 -OutputDirectory "$PWD/test-results/d3d12-m-packed-formats"

One public diagnostic command, without NVIDIA DLLs:

powershell -NoProfile -File scripts/windows/test-windows-rdna4.ps1 -RuntimeProfile therock -ZludaRoot "$PWD/dist/zluda-windows-f16-reference" -PackageRoot "$PWD/dist/windows-rdna4-command-list"

The exact complete-frame comparison uses frame_compare.py --exact with --output-storage r11g11b10f or bgra8. Ordinary comparisons still use the existing FP16 output gates. Game integration next needs command-list initial PSO handling, enhanced-layout tracking, optional mask import and OptiScaler API/state-hook compatibility. The game directory is still untouched.

M temporal precision regression (2026-09-30)

The earlier finite-frame and sampled-layer results did not cover every spatial block. The second enc1 launch has a cancellation-sensitive P/V dot in block 0,4: the old native f32 WMMA route differed by up to 21 e4m3 code steps. NumPy and the independent PTX interpreter agree exactly on that block. SWIN_EXACT_PV stores each wave's sixteen P rows and V rows in LDS, sums sixteen f16 products in f64, rounds directly to f16, then applies the existing e4m3 quantisation. Other GEMMs retain the gfx12 WMMA layout and FP16 widening. The flag is enabled by D4R_M_FP16_BASELINE; upstream fast/Linux defaults are preserved when that flag is absent. Intermediate snapshots are compiled only with D4R_SWIN_DIAGNOSTICS; they are absent from packaged kernels.

The translated reference also differed: first frame, fourth enc3_tube launch, block 0,0, thirty stored codes, maximum fifteen e4m3 steps. Its inputs match the corrected native launch exactly. Patch 0013 adds D4R_ZLUDA_WMMA_F16_REFERENCE=1 for gfx12 f16-accumulator MMA helpers, retaining the established fragment gathers, pair fusion and conversions. It uses f64 sums and integer f16 RNE encoding, including subnormal bits. FP8 GEMMs continue using the existing native WMMA widening. The default upstream helper behavior remains available with this option unset or zero. Windows diagnostics select the reference option by default. All d4r codegen options enter the JIT cache key.

This is a match to the independent mathematical NumPy/PTX baseline. NVIDIA's PTX floating-point MMA specification leaves accumulation order, rounding and subnormal handling unspecified; these checks do not establish bit-exact agreement with NVIDIA hardware.

Recorded results on the RX 9070 XT / TheRock runtime:

  • Public cuda_mma_probe: 512 synthetic matrix cases, 65,536 f16 outputs, zero differing bits with reference accumulation. The old fast WMMA route differs in 23,308 outputs on the same cancellation/subnormal stress fixture.
  • m-native-exact-pv-temporal-reference: all spatial blocks of 40 actual native launches, every stored e4m3 value identical to NumPy, max abs/relative error 0.
  • m-exact-pv-enc1-regression-ptx: original problem block 0,4, independent PTX versus native and versus NumPy both max absolute/relative error 0.
  • m-exact-pv-complete-f16-reference.log: four complete RGB frames against corrected fully translated M, max absolute/relative error 0, PSNR infinite.
  • m-translated-f16-temporal-reference: all blocks of all forty translated M launches exactly match NumPy; no sampled-window exemption.
  • m-temporal-final-ctest.log: 11/11 native Windows hardware tests PASS. Pinned fresh-source application of all twelve ZLUDA patches PASS.
  • d3d12-m-exact-pv-final.zip: four finite frames, forty native launches, no shim CPU image copies, frame age zero. This remains the explicit queue boundary harness; open game command-list support is the next gate.

All captures, extracted PTX and real weights remain in ignored private result directories. To repeat the full temporal scan without editing sources:

$env:PYTHONPATH="$PWD/.tools/python/vendor"
python tools/windows/m_temporal_validate.py --capture-dir test-results/ngx-m-exact-pv-capture/captures --output-dir test-results/m-temporal-reference --exact

The game selected for the next integration test is Silent Hill 2 at D:\Games\SILENT HILL 2\SHProto\Binaries\Win64\SHProto-Win64-Shipping.exe. No game files have been modified at this milestone.

Open D3D12 command lists (2026-09-30)

The backend intercepts documented D3D12 COM methods using pinned open-source MinHook 1.3.4, commit c3fcafdc10146beb5919319d0683e44e3c30d537. No NVIDIA instructions, proprietary DLL contents or private driver interfaces are patched. The typed forwarding code is generated from public SDK CommandList0..7 declarations, with typed CommandList8..10 additions audited in Microsoft's current public DirectX-Headers, adbd6f3ba40795c46a8d0f33af00bcb57ff0f0a4. The AMD runtime exposes CommandList10: eighty public-method hooks now install successfully. SetProgram descriptors are copied by value. Work-graph replay omits INITIALIZE to preserve already initialized backing memory; see the Microsoft work-graph specification. Full GPU work-graph execution is not a tested gate yet.

At NGX Evaluate, the caller's resource references and typed parameter values are copied into an owned snapshot. The recorded prefix is closed. Subsequent calls on the same logical object are forwarded into a fresh native suffix list with its own allocator. State-setting calls are replayed with deep copies of host arrays and retained COM references. Open PIX events are closed in the prefix and reopened in the suffix. At ExecuteCommandLists, preceding lists in the caller's batch execute first, followed by the prefix, actual CUDA evaluation and output copy, then the suffix and following lists. All work completes in the same frame. Completion waits currently stall the host; they do not age frames.

The callback module remains loaded while public D3D12 method interceptions are installed. Original command-list pointers in the routing map are weak; final Release removes metadata, suffixes, allocators and queued feature references. This avoids a reference cycle that would keep every command list alive. Failure at queue submission is logged and prevents submitting the consumer suffix. No previous-frame fallback is substituted.

d3d12-command-foundation passes 32 iterations with no NVIDIA binaries. Each batch contains A, B and C. A produces shader inputs, B dispatches before a boundary, the callback verifies that prefix and replaces inputs on the GPU, the suffix dispatches without rebinding root state, and C reads the result. All values match; a temporary root-constant array may change after recording; live recording metadata returns to zero after every iteration.

d3d12-m-command-list.zip passes four ordinary NGX EvaluateFeature frames with forty native M launches. RGB is bit-exact to the earlier explicit boundary harness. The initial producer remains unsubmitted until the same queue batch, and the caller's Color/Reset parameters are deliberately changed after Evaluate returns, testing snapshot ownership. d3d12-k-command-list.zip also passes four finite frames and all forty-four native K launches; all four RGB frames are bit-exact against d3d12-k-final. Complete CTest: 12/12 PASS (d3d12-command-final-ctest.log).

Enable this backend with D4R_D3D12_COMMAND_BACKEND=1; the diagnostic runner sets it through -CommandListBackend. Before game testing, remaining gates are enhanced barrier layouts, actual game texture formats and interaction with OptiScaler's own state hooks. Closed lists, active render/query scopes, GPU predication and unknown indirect state are currently explicitly rejected instead of guessing their semantics.

Indirect commands and Windows diagnostics (2026-10-01)

CreateCommandSignature interception stores its public argument description using ID3D12Object::SetPrivateData, owned by the original COM object. There is no driver-private introspection or independent signature-lifetime table. After ExecuteIndirect, replay restores exactly the documented zero/NULL values for affected root constants, views, VB slots and IB; unaffected state remains inherited. See Microsoft's indirect drawing specification. Signatures created before interception remain explicitly untracked.

The RX 9070 XT passes 32 queue/backend iterations alternating direct Dispatch and dispatch-only ExecuteIndirect. Bindings, ordering, temporary host argument copies and final Release are verified (d3d12-indirect-plain-final). Microsoft WARP passes 32 backend iterations with an indirect signature that changes a root constant, followed by direct Dispatch without rebinding: both prefix and suffix observe the required zero (d3d12-indirect-root-warp-backend.log). WARP is reported as software, never as gfx1201. CTest now passes 13/13 (twelve physical GPU gates plus the WARP root-reset regression), d3d12-command-v10-final-ctest.log. Four ordinary recorded M frames still execute forty native transformer launches and remain bit-exact against the previous CommandList7 implementation (d3d12-m-command-v10.zip, d3d12-m-command-v10-reference.log).

Unresolved native AMD root-mutating indirect regression: that same valid root-constant/Dispatch signature removes the AMD device (0x887a0006). It also fails with d4r hooks disabled and with HIP omitted, under inbox D3D12Core and Agility 1.619.5, with UPLOAD and DEFAULT argument buffers. DRED stops inside ExecuteIndirect and reports 0x80015c000 when the argument-buffer GPU VA is 0x200057000. The exact fault address is four times that allocation's VA; this is an observation, not a proven driver cause. This workload passes on WARP. Do not classify native root-mutating indirect execution as validated. The default physical test covers dispatch-only signatures; the root mutation case is a separate reproducible diagnostic:

powershell -NoProfile -File scripts/windows/test-d3d12-command.ps1 -NoHooks -NoHip -Mode indirect-root-reset -Iterations 2 -OutputDirectory test-results/amd-root-indirect-reproducer

Logs retain stdout/stderr, device-removed reason, DRED breadcrumbs/fault address, loaded DLL versions and exception minidumps via D4R_DIAG_DIR. -Warp selects the software comparison. No game or NVIDIA DLL is required.

Optional app-local debug target: set D4R_AGILITY_ROOT to unpacked official Microsoft.Direct3D.D3D12 1.619.5. NuGet ZIP SHA256: 0e9bcf32aac9a79343ede9b21e4864950ee54577e3d8e19bfcdf002bb4e9bfd6. On this machine, the public debug interfaces still return SDK_COMPONENT_MISSING despite app-local SDKLayers loading. Installing Windows Graphics Tools failed with DISM's component-store-corrupted error. No repair, reboot, security change or game runtime dependency was introduced. DRED works without that layer.

Source baseline (checked 2026-09-29)

  • d4r: ed1ab60, main, 14 commits; https://github.com/countervolts/d4r.
  • ZLUDA master: ee2f25a180099fa42f36b2346732e1f2470a03ad, 2026-09-22. This is also the base named by d4r's existing patches.
  • Windows binary baseline: ZLUDA v7-preview.11, zluda-windows-ee2f25a.zip, SHA256 7788c1ed43385e62f0cc5f4d1aead24c92b671c02f1d685f63182540dea16d74.
  • Local HIP SDK: C:\Program Files\AMD\ROCm\7.2, headers report 7.2.60201, commit 38d754472. Compiler: AMD clang 21, LLVM commit 590b9320a5be90e40268759c6203c01fde121e68.
  • Keep stable SDK and TheRock installations separate. Select one directory per build and test run; never mix headers, import libraries, runtime or COMGR.
  • Tested isolated TheRock core: 10.2.0a20260929, HIP 7.17.26386, commit 0ad5f73253; wheel SHA256 9623b97ca511eaa176905075a504393eca6fde594222af10b55e4fb1edfe5a25. No machine-wide runtime replacement is performed.
  • CMake 3.31.6, Ninja 1.11.1 (Python package 1.11.1.4).
  • Synthetic K numerical reference: Python 3.11 and local NumPy 2.4.6 (PyPI release); installed only into .tools/python/vendor by setup, outside the game runtime.
  • Windows host toolchain: LLVM-MinGW 20260922, UCRT x64, SHA256 e3ad77d117a4bea19a7a3b333341824d79a5a371004a10e25b8504e7b3047666. This is a portable fallback on this machine, where MSVC is not installed. The device compiler remains the selected AMD HIP clang.

Upstream RDNA4 update (checked 2026-09-30)

Fetched and integrated upstream main commit dbef4b24f4bc974725c3b2bc74ca442a694b901d, "Add RDNA4 (gfx12) support and a 0.1.2 optimization round" (2026-09-30 UTC). It changes 42 files and supplies real per-target fragment layouts rather than renaming gfx11 builtins. Before the merge, an isolated archive was compiled and its enc1/enc2 objects were checked on this RX 9070 XT against our fixtures.

  • kernels/common/wmma_layout.h separates gfx11/gfx12 operands, accumulator rows, weight/activation loading, packing and reconstruction. K, M and native texture tails use it. The gfx11 implementation and layout12 test shim remain.
  • M has an optional native e4m3 FP8 variant, with matching ZLUDA/texture lowering and kernel directory selection. Windows CMake keeps FP16 widening as the baseline; it does not enable native FP8. M arithmetic on this GPU remains unvalidated until K and its full DLSS integration are correct.
  • New ZLUDA patches 0006/0007 add k8 WMMA, prep slots, wave64 for MMA-free kernels, gfx12 helpers and FP8 selection/cache identity. These patches are now built into native Windows ZLUDA. Integer PTX and resource descriptor tests pass on hardware; complete K/M lowering remains to be validated.
  • Upstream restored kernels/tools/model_enc3.py, resolving the missing M reference dependency found in the initial audit. New check/replay utilities cover K/M and texture tails. Texture artifacts still require local DLL/PTX extraction and a patched d4r_emit; they are not built by Windows CMake yet.
  • There is still no native Windows runtime backend in this update. GPU selection still reads KFD topology; Wine, Linux shared descriptors and vkd3d-proton command-list splitting remain in the upstream path.

Upstream explicitly reports gfx1201 emulator checks and gfx1200 compile-only coverage; it does not claim actual RDNA4 hardware verification (native-kernel validation notes). The hardware results below apply only to the named Windows probes and synthetic layers, not to the complete network or the upstream FP8 implementation.

Local integration retains the Windows probes, NGX ABI correction, NVAPI topology and D3D12/HIP interop. K now uses upstream's native gfx12 layout directly; the legacy adapter remains only for its independent diagnostic regression. M gains the same minimal device-header path as K. Its lane-mask constants no longer require a host <type_traits> installation. Public HIP uint2/uint4 storage alignment and qualifiers are reproduced by the device-only header.

Windows CMake compiles all 11 K + 5 M source modules with gfx1201 wave32, -O3 and each source's upstream d4r-build-flags (including -mcumode). Both stable HIP 7.2 and isolated TheRock build successfully. The objects install to experimental/k and experimental/m, outside the ZLUDA override directory. All 11 K layers now have GPU synthetic replay/reference checks (results below).

2026-09-30 integration results on RX 9070 XT, Windows 11:

Check Result
TheRock diagnostic runner with the two local NVIDIA DLLs 11/11 PASS; test-results/upstream-rdna4-merged.zip
TheRock CTest, including D3D12/HIP external memory/fences 8/8 PASS
WMMA raw, legacy adapter and upstream native layout/packing 32 cases, one/two K16 steps, nonzero C; max abs/relative error 0
Upstream K enc1 full / merged reference Max abs 0.000244140625; PSNR 98.21 / 97.63 dB; no NaN/Inf
Upstream K enc2 full / merged reference Max abs 3.81469727e-06; PSNR 130.39 / 132.49 dB; no NaN/Inf
Stable HIP 7.2 non-interop CTest 6/6 PASS
Stable-built K enc1/enc2 with stable runtime 32 identity iterations each + both nonzero references PASS, same errors as TheRock

The previously failing stable compiler/legacy-layout K path is superseded by the native upstream layout: these two current layer fixtures pass under stable HIP 7.2. Stable external-memory mapped-view ownership still requires the runtime fix/TheRock; passing K does not resolve that leak. Build logs remain under each build/windows-rdna4* directory; stable GPU logs/fixtures remain under test-results/upstream-stable-*-gpu.log and test-results/upstream-rdna4-stable.

Next gate: validate K against real DLSS captures with the built Windows ZLUDA, then implement same-frame Windows NGX Evaluate with explicit D3D12 queue submission ownership. Full K precedes M and native FP8/performance work. No complete DLSS or OptiScaler game result is claimed.

Native Windows ZLUDA build and Evaluate work (2026-09-30)

M strict FP16 baseline and independent reference (2026-09-30)

D4R_M_FP16_BASELINE=ON is the Windows CMake default and defines SWIN_EXACT. Activations retain e4m3 requantisation; matrix accumulation rounds to f16 after each K32 step. Gfx1201 WMMA widens FP8 operands to FP16. Native FP8 is disabled until this baseline also passes the D3D12 harness.

All five rrlite_{enc1,enc2,enc3_tube,dec2,dec1}_4x4 modules pass 32 iterations on public synthetic 16x16 fixtures, including nonzero Q/V/WO/MLP weights, decoder expansion/skip and patch merge. Every stored e4m3 code exactly matches the NumPy model; max absolute and relative error are zero. The fixture's patch merge deliberately uses large weights to exercise its output bound.

An independent CPU PTX check exposed an upstream omission: DLSS 310.9's patch merge clamps f16 results to +/- f16(2*pi), before e4m3 rounding. Without this bound, real enc2 merge outputs reached +/-9 or 10 where the PTX stored +/-6.5. The correction is limited to SWIN_EXACT; upstream fast arithmetic stays unchanged. The Windows model enables the same audited bound explicitly; the legacy Linux oracle remains the default. Both implementations now agree with the independent PTX interpreter, rather than merely agreeing with each other.

0011-audited-k-m-windows-replay.patch adds exact M capture ABI sizes (56/88 bytes) and restricts K captures to the eleven audited names. The public CPU PTX interpreter now handles divergent finite backward loops by suspending completed lanes at the loop fallthrough. tools/windows/test_ptx_reference.py verifies lane-specific loop counts and reconvergence with a public synthetic program.

With the user's 310.9 DLL, test-results/ngx-m-bounded-capture.zip passes four frames with native counts enc1=4, enc2=4, enc3_tube=24, dec2=4, dec1=4. No NaN/Inf or missing transformer is accepted. test-results/m-real-final-dual-reference passes 12 NumPy blocks and two independent CPU PTX blocks per layer; all sampled codes agree exactly (max abs/relative error 0, PSNR infinite). Capture files, weights and extracted PTX remain private and must not be redistributed.

Reproduce the layer gates:

& scripts/windows/test-m-replay.ps1
& scripts/windows/stage-native-m.ps1 -DlssDll "$PWD/nvngx_dlss.dll"
$env:D4R_ZLUDA_NATIVE_DIR="$PWD/build/native-m-gfx1201"
$env:D4R_ZLUDA_WMMA='1'; $env:D4R_ZLUDA_WMMA_FP8='1'; $env:D4R_ZLUDA_WMMA_FP8_NATIVE='0'
& scripts/windows/test-windows-rdna4.ps1 -RuntimeProfile therock -NgxOnly -NgxMode evaluate -Preset 13 -Iterations 4 -RequireNativeNetwork -NgxCore "$PWD/_nvngx.dll" -DlssDll "$PWD/nvngx_dlss.dll"

Earlier translated M attempts used incorrect environment names and an unwritable default JIT cache. The runner now defaults to the actual D4R_ZLUDA_WMMA, D4R_ZLUDA_WMMA_FP8, D4R_ZLUDA_WMMA_FP8_NATIVE options (1, 1, 0), records them, and restores the caller's environment. Patch 0012 adds absolute ZLUDA_CACHE_DIR and reports directory/open failures. The diagnostic default is build/zluda-cache-windows; five Rust cache tests and all eleven patches applied to the pinned clean upstream pass. A completed translated M image comparison is not yet claimed. The user selected Silent Hill 2 at D:\Games\SILENT HILL 2\SHProto\Binaries\Win64\SHProto-Win64-Shipping.exe for the later game gate. No game files have been changed yet.

OptiScaler upstream inspected at 45a2001303ddff632e279f77aef85ceede5832cb, 2026-09-30. Its DLSS backend forwards an open command list into Evaluate; its swapchain hooks retain the game queue. A correct same-frame Windows path must preserve submission order when earlier command lists have not yet been submitted. Closing/submitting the current list immediately inside Evaluate is insufficient for a general game integration. The next backend gate is a D3D12 harness with explicit queue boundaries; command-list/queue integration must be validated before the game gate.

Native D3D12 harness milestone (2026-09-30)

The new d4r_nvngx.dll has a Windows backend independent of the Wine shim. d3d12_external.h owns Win32 handles, shared DEFAULT buffers, HIP mappings and the D3D12 fence/semaphore timeline. Canonical color/output RGBA16F, motion RG16F, and depth/exposure R32F remain in VRAM. Texture-to-buffer copies, CUDA array transfers and output copies execute on the GPU. Harness initialization uploads synthetic inputs; final readback is confined to its verifier/output exporter.

The first complete attempt exposed a synchronization race: waiting on a HIP external semaphore on its nonblocking stream and synchronizing that stream did not reliably establish completion for work subsequently submitted through other CUDA streams. Samples read back by the diagnostic could hide the race. The baseline additionally waits for the producer's actual D3D12 fence event before CUDA submission. It waits for completion, without transferring image data or using another frame. cuCtxSynchronize covers NGX's internal streams, followed by HIP fence signaling and a D3D12 queue wait before copying the output texture. Reducing these host completion waits is a later profiling/ordering task.

Private results: test-results/d3d12-k-direct-fence.zip and test-results/d3d12-m-direct-fence.zip, four finite, nonconstant frames each, 44 native K and 40 native M launches. Every RGB value agrees bit-for-bit with ngx-k-native-verified / ngx-m-bounded-capture: max absolute/relative error 0, PSNR infinite. CTest: 10/10 PASS including a five-plane D3D12-to-CUDA array roundtrip and pitched CUDA device/array copies with padding sentinels.

Build/package: dist/windows-rdna4-d3d12. Reproduce K (use preset 13 and the staged native-m-gfx1201 directory for M):

$env:D4R_ZLUDA_NATIVE_DIR="$PWD/build/native-k-gfx1201"
& scripts/windows/test-windows-rdna4.ps1 -RuntimeProfile therock -PackageRoot "$PWD/dist/windows-rdna4-d3d12" -NgxOnly -NgxMode d3d12 -Preset 11 -Iterations 4 -RequireNativeNetwork -NgxCore "$PWD/_nvngx.dll" -DlssDll "$PWD/nvngx_dlss.dll"

The runner places the shim beside the two private NVIDIA DLLs in an owned temporary directory, matching NGX's caller-relative feature lookup. They are never installed into the public package. D4R_INTEROP_VERIFY explicitly enables extra CPU diagnostics and changes the logged copy flag; keep it unset for the normal path. The open-command-list game export still rejects execution until submission ordering is implemented. The explicit harness export requires that all preceding producers have already been submitted. Other texture formats, dynamic resolution and real-game resource-state tracking remain unvalidated.

K real-weight native Evaluate and correctness baseline

The locally supplied DLSS 310.9.1.0 selects all eleven dltss_pwin_* functions with preset 11 (K). 0010-native-identity-replay-windows-cache.patch adds:

  • FNV-1a PTX identity checking against upstream d4r-kernels.txt, with an explicit native miss/translated fallback log. A mismatched version cannot receive an override by function name alone.
  • Owned native modules/images, released with their CUDA function/module, and direct native loading for fully replaced single-entry modules with only LDS declarations. Modules with exported globals or other functions retain JIT.
  • Windows loaded-DLL size/mtime in the translator cache identity. Rebuilding an uncommitted translator no longer reuses its older cached code.
  • Opt-in native Windows K replay capture, before and after a launch, using HIP allocation range queries. Captures are synchronous diagnostics, can contain proprietary weights, and are never enabled in the game fast path. D4R_ZLUDA_VERBOSE=1 logs actual native/translated launches.

The Windows minimal __syncthreads previously omitted HIP's release/acquire memory fences. Real, multi-window captures exposed nondeterministic LDS data and intermediate NaNs, despite the one-window synthetic tests passing. The shim now matches public HIP barrier semantics. Those earlier captures are invalid for correctness claims.

Windows K defaults to D4R_K_FP16_BASELINE=ON: every K16 accumulator step and the L2 reduction tree round to FP16. The norm grouping was independently recovered and checked with the existing CPU PTX interpreter for C=32/64/96/128/160. The reference model supports NORM_FRAGMENT_ORDER=True; its legacy default remains unchanged. The original float norm approximation itself differed from PTX by 0.13965 on one real decoder window, so it cannot serve as a bit-exact oracle. Strict references and the independent PTX gate are both required.

Validated on RX 9070 XT with isolated TheRock:

  • test-results/k-strict-synthetic-final.zip: 11/11, 32 launches per layer, max absolute and relative error 0 with strict references.
  • test-results/k-real-strict-dual-reference: all eleven real-weight layers pass. Up to 12 NumPy windows/layer, plus the two worst NumPy difference windows checked independently through PTX. NumPy PSNR 75.40–103.98 dB; PTX PSNR 67.11–122.39 dB, all selected output elements finite. Max relative error is reported with a 0.001 denominator floor; near-zero values can have a large relative error. Gates require PSNR >=60 dB and max absolute error <=max(0.001, 0.005*reference peak).
  • test-results/ngx-k-strict-norm-final.zip: four K frames, all 44 native transformer launches logged, no NaN/Inf or unwritten output.
  • Complete-frame comparison with translated WMMA K: PSNR 92.91, 81.85, 84.45, 86.10 dB, max absolute error 0.01514. Differences are localized: at most 21 RGB elements exceed 0.002, and at most 0.00294% exceed 1% of peak. These are approximate numerical results, not bit-exact NVIDIA hardware verification. The frame gate requires >=60 dB, max <=2.5% of peak, and no more than 0.01% of RGB elements above 1% of peak. An initial stricter 1% single-element gate failed on these isolated temporal differences; the observed metrics and current bounds are recorded explicitly.
  • test-results/native-identity-final: wrong hash rejects the override and runs translated PTX correctly; matching hash executes 32 native launches.
  • CTest 9/9 and fresh-source application of all nine ZLUDA patches PASS.

Reproduce the actual K layer gate without editing sources:

powershell -NoProfile -ExecutionPolicy Bypass -File scripts/windows/test-k-captures.ps1 `
  -CaptureDirectory C:\Users\Administrator\d4r\test-results\ngx-k-fp16-fenced-capture\replay `
  -DlssDll C:\Users\Administrator\d4r\nvngx_dlss.dll

This is CUDA NGX validation with synthetic image inputs and actual local DLSS weights. It does not claim a completed Windows D3D12 shim, OptiScaler game test, dynamic scene validation, or M support. These are the next gates.

All K layers: native Windows synthetic replay (2026-09-30)

native_replay_probe reads upstream manifest.txt/args.bin/alloc-N.bin, relocates allocation pointers, runs the module's prep and main kernels, and saves GPU allocations for the existing pwin_check/pwin_model references. No NVIDIA DLL, PTX or weights are needed for these synthetic fixtures. Each fixture enables nonzero projections, attention, MLP and the layer's embedding/merge/head operations; it covers one 8x8 window with sparse weights. It does not replace validation with real network weights, multiple windows, shifted borders, textures or complete DLSS output.

Run from the repository:

powershell -NoProfile -ExecutionPolicy Bypass -File scripts/windows/test-k-replay.ps1

Hardware result: test-results/k-all-layers-synthetic.zip, 11/11 PASS, 32 native launches per layer, all output elements finite. The acceptance limit is max absolute error <= 0.001 and PSNR >= 60 dB; relative error uses a 0.001 denominator floor. Validation stops on the first mismatch.

Layer Max absolute error Max relative error PSNR (dB)
enc0 0.00048828125 0.0011682243 88.75
enc1 0 0 exact
enc2 0.0000305175781 0.0009319664 114.40
enc3 0 0 exact
enc4 0 0 exact
dec5 0 0 exact
dec4 0 0 exact
dec3 0 0 exact
dec2 0.0000305175781 0.0008741259 111.42
dec1 0.00048828125 0.0011086475 99.33
dec0 0.000122070312 0.0133333333 100.84

The next K gate is capture/reference validation with actual DLSS weights and proof of native transformer launches during Evaluate. Native overrides must check the originating PTX identity before replacing a function.

The local fork now builds natively under Windows, including d4r patches 0002–0007. New 0008-native-windows-build.patch preserves MSVC/Linux builds and adds LLVM-MinGW support: prebuilt LLVM selection, GNU delay-load flags, Windows LLVM system-library propagation, configurable HiGHS C++ library, public OCKL assertion reporting, and optional TaskDialog lookup. It does not modify NVIDIA binaries. The SDK's long shuffle overloads need an LLP64 fix in a private header mirror; build-zluda-helpers.ps1 applies it without touching the installed HIP SDK. Helper bitcode is rebuilt in all four wave/FP variants.

Pinned additional build dependencies:

  • Portable official Rust/Cargo 1.98.1, x86_64-pc-windows-gnu, release 2026-09-03. setup-rust-toolchain.ps1 verifies SHA256 of rustc, Cargo, rust-std and rust-mingw archives and installs only under .tools.
  • ZLUDA LLVM submodule ff4dc1f7c9e1c64d4d69e40f4ed30c2280a96dfd, llvm-config reports 22.0.0git. AMDGPU/LLVM/LLD are built with LLVM-MinGW 20260922; no Linux build host or runtime is used.
  • HiGHS submodule 364c83a51e44ba6c27def9c8fc1a49b1daf5ad5c.
  • The LLVM IR helper producer is stable HIP 7.2/LLVM 21. The final target is selected by the translator from HIP gfx1201; generic helper generation strips its temporary target attributes, as the existing Linux builder does.
  • dist/zluda-windows-native contains the built CUDA/NVAPI/trace DLLs, d4r_emit.exe, local open-source libc++/libunwind DLLs and build hashes. This directory contains no NVIDIA DLLs, extracted PTX or weights.

Build sequence after preparing the pinned ZLUDA source/submodules:

powershell -NoProfile -File scripts/windows/setup-rust-toolchain.ps1
powershell -NoProfile -File scripts/windows/prepare-zluda-source.ps1
powershell -NoProfile -File scripts/windows/build-zluda-llvm.ps1
powershell -NoProfile -File scripts/windows/build-zluda-helpers.ps1
powershell -NoProfile -File scripts/windows/build-zluda-windows.ps1

prepare-zluda-source.ps1 refuses to reapply patches over a modified checkout. For an already prepared checkout, rebuild only the affected components. Configure/fetch/build logs remain under build/zluda-*.

The NGX probe now accepts --ngx-mode evaluate, --preset 5|11|13 and a frame count. Its synthetic CUDA-array path is a debug harness with host uploads and final readback, not the game's fast path. It initializes output to NaN, checks all RGBA components for finite values, checks RGB variance and saves unmodified .rgba16f plus BMP previews. A successful Evaluate alone is logged as network_validation=pending. The diagnostic exception handler also saves first-chance fault details/minidumps before NGX's own final filter takes over.

The first stock-ZLUDA E test failed during CreateFeature (0xc0000005); trace recorded missing cuda_histogram_kernel/cuda_dldn_engine_histogram_kernel with unrecognized tex.base.2d.v4.f32.s32. This is a captured failure, not a successful DLSS result. Bundle: test-results/ngx-evaluate-e-stock.zip. The first custom build then exposed missing libc++ deployment and an eager Common Controls v6 import; both are corrected. 0009-resource-descriptor-queries implements texture and 2D/3D array queries. Texture descriptors are tracked from creation and removed on destruction: probing a surface as a texture returns an API error instead of dereferencing HIP host metadata. This also preserves CUDA flags/reserved bytes, which HIP's query does not fully initialize.

Hardware evidence with the patched runtime:

  • Full runner native-zluda-descriptors-milestone: 12/12 PASS, with 32 PTX iterations per context, 32 CUDA image iterations and unchanged HIP/K/interop checks. Package/default DLL selection prefers the locally built runtime.
  • cuda-images-kind.stdout.log: 32 iterations of 1/2/4-channel arrays, texture/surface descriptor and storage round trips, plus wrong-kind errors.
  • ngx-evaluate-e-kindfix: requested preset E Create/Evaluate PASS for one synthetic frame, finite RGBA, nonconstant output saved in the private result bundle. This establishes the first native Windows DLSS CUDA execution path. K/M transformer validation and D3D12 game integration are still pending.
  • ngx-evaluate-e-four-frames: four consecutive finite synthetic frames, reset only on frame 0, saved RGBA16F/BMP outputs. CTest after self-contained CUDA dependency lookup: 9/9 PASS. Fresh pinned-source application of all eight patches passes check-zluda-patches.ps1.
  • First-chance capture successfully saved two minidumps for the preceding surface-as-texture HIP crash; ngx-evaluate-e-arraydesc.zip preserves it.

Example focused diagnostic (after the full foundational checks), using the user's local DLLs:

powershell -NoProfile -File scripts/windows/test-windows-rdna4.ps1 -RuntimeProfile therock -NgxOnly -NgxMode evaluate -Preset 5 -Iterations 4 -NgxCore C:\Users\Administrator\d4r\_nvngx.dll -DlssDll C:\Users\Administrator\d4r\nvngx_dlss.dll

-NgxOnly is for iterative NGX debugging; its summary explicitly says that foundational checks were skipped. Private trace bundles can contain extracted NVIDIA PTX/weights and must not be included in public release packages.

Architecture and platform boundaries

Existing path: D3D12 -> OptiScaler -> d4r shim -> NGX CUDA -> Wine nvcuda -> ZLUDA -> HIP. The shim records Vulkan copies through vkd3d-proton interop. A patched vkd3d splits recording into submissions and gates the second part on a semaphore. The Wine bridge translates Windows/SysV ABIs, loads Linux libraries, chooses native kernels from KFD topology and performs fd-based Vulkan memory imports.

Planned Windows path: D3D12 -> OptiScaler -> d4r shim -> NGX CUDA -> Windows ZLUDA -> HIP gfx1201. Platform-independent NGX parameter handling, formats, references, replay format and kernel identity checks should be retained. A Windows backend must use Win32 DLL loading, HIP device properties, shared D3D12 allocations and fences. Wine builtins, KFD, file descriptors, Proton and vkd3d are excluded from runtime.

An NGX Evaluate call receives a recording command list, not a queue that can be submitted halfway through by the shim. Native D3D12 has no equivalent to the vkd3d split extension. Same-frame synchronization therefore needs an explicit submission boundary supplied by the harness and then OptiScaler/queue integration. A HIP wait inserted behind an unsplit D3D12 submission can deadlock. Merely mapping VRAM does not solve command recording/submission ownership.

Audit map and decisions

  • README.md, docs/{architecture,building,native-kernels,performance}.md: Linux-tested baseline; upstream K translation can produce nonfinite results. A successful NGX return alone is not transformer validation.
  • tools/d4r_nvngx_shim.cpp: Windows API/NGX entry points and C++ worker are reusable; Vulkan resource conversion, markers and split-frame functions form the platform boundary. Portable ini paths currently assume Wine translation.
  • tools/wine_nvcuda_bridge.c: loading (dlopen, pthread_once), KFD target selection, descriptor bookkeeping, PTX manifests, replay/profile and CUDA forwarding are interleaved. Preserve identities/instrumentation, replace platform services rather than copy the Wine bridge into Windows.
  • patches/zluda/0002: DLSS arrays/textures/surfaces, PTX instructions, dumps; 0003: bounds and gfx11 MMA; 0004: native override/prep, FP8, extra bitcode, handoffs; 0005: null texture reads. The gfx11 MMA optimization is explicitly architecture-gated. It must not be enabled for gfx12 by changing that gate.
  • patches/vkd3d-proton/0001: submission split, not a portable D3D12 interface.
  • kernels/k: pwin_common.h, layer/position/wide templates and eleven entries. Operands are replicated 16-half rows; accumulator row is 2*i + (lane>>4); operand_from_dt, wtile, weight prep and stores depend on that convention.
  • kernels/m: swin_common.h, swin_block.h, five standalone entries; FP8 weights expanded to FP16, kslot, woff, bload, k32, accumulator reconstruction and xor shuffles need layout audit. Preserve rounding per k32.
  • kernels/tex: enc0 tail/dec0 head also use gfx11 WMMA and output shuffles; changing only K/M would leave part of M incorrect. Generated PTX is private.
  • kernels/build.sh, texture build and scripts/build_zluda_ptx_helpers.sh: Linux tool paths, shell, bitcode cleanup and target assumptions need a Windows build path. Keep existing Linux scripts operational.
  • kernels/tools/{pwin_model,swin_model,ptxsim,psnr,kernel_manifest}.py and dump_runner.cpp, tools/replay_dlss_*: use existing reference semantics and capture relocation format; add finite checks and quantitative comparison.
  • scripts/package_release.sh, install/launch scripts and packaging/: Linux release bundles Proton components. Windows diagnostics/package must be separate and must never include NVIDIA DLLs or extracted NVIDIA PTX/weights.
  • Upstream ZLUDA already has Windows delay-loading for HIP 7 and fallback HIP 6. Its Rust binding calls versioned hipGetDevicePropertiesR0600; a reported gfx1201 crash is not evidence of an ABI bug without a reproducer/trace here.

gfx11 versus gfx12 WMMA

For wave32, gfx11 FP16 A/B are 16 halves per lane with replication across the two 16-lane groups. gfx12 uses 8 halves per lane without replication. The gfx12 builtin has a _gfx12 suffix; its FP32 accumulator is still eight floats, but rows are contiguous within the lane group, rather than gfx11 even/odd rows. The backend must explicitly convert operands and accumulator distribution, or update all dependent loads/stores and intermediate fragments together. Start with FP16 / FP32 accumulate. M native FP8 is a later measured optimization. Compile success is not proof of lane layout or numerical correctness.

The initial kernels/common/wmma_backend.h adapter preserves the gfx11 call and maps d4r's 16-half operand / even-odd accumulator contract to gfx12's 8-half operand / contiguous accumulator contract. The gfx12 mapping uses an unconditional wave32 half-exchange for every source fragment element before selection. Performing the exchange only on lanes selected by a group-dependent branch returned channel 9 in place of channel 1 on this card: the opposite half of the wave was inactive at that instruction. This was caught by the CPU reference. tools/windows/wmma_gfx1201.hip tests raw gfx12 WMMA, the adapter, upstream's native layout/operand packing, the half-exchange and lane ID with nonzero accumulator and one/two K16 steps. Both stable HIP 7.2 and TheRock 10.2 produced exact 16x16 outputs across 16 different inputs; max absolute and relative errors were both zero.

After the upstream merge, kernels/k/pwin_common.h calls the native wmma_layout.h implementation; it no longer converts around every MMA with the legacy adapter. The Windows device-only compiler uses kernels/common/hip_device_minimal.h, exposing only public Clang AMDGPU work-item/grid/barrier builtins and HIP-compatible qualifiers; the ordinary Linux HIP include path remains. CMake builds every K/M module for gfx1201 into experimental/. The k_module_probe resolves and launches prep and transformer for enc1/enc2. The identity fixture verifies all 4096 full-resolution and 1024/1536 merged FP16 values bitwise. A second fixture enables nonzero V projections, position-only attention, Wo, MLP/GELU and patch merge; it checks finite values and a patch identity, then saves all inputs/outputs for k_layer_validate.py. That script runs the existing pwin_model.py and measures max absolute/relative error and PSNR. The code object remains in experimental/k/, outside ZLUDA's override path, until the other K layers and real captured weights/activations pass. The enc2 fixture additionally enables learned Q/K attention and softmax.

External interop blockers

The installed HIP headers define D3D12Resource/D3D12Heap external memory and D3D12Fence external semaphore types. Their presence is not proof the Windows runtime implements them. Validate imports, mapping, GPU waits/signals and cleanup using an independent round trip before modifying the shim. Use HIP/DXGI device identity to prevent importing allocations across adapters. NT HANDLE ownership must be explicit; Win32 import is not fd ownership transfer. Test repeated create/destroy cycles as upstream noted a mapped-buffer leak on Linux ROCm. CPU verification copies are allowed in tests, never in the fast path.

Implemented independent test: DXGI LUID matches HIP, an R32_UINT texture is copied to a shared DEFAULT-heap linear buffer in VRAM, HIP maps that D3D12 resource, checks every input element and XORs it, D3D12 copies it back to the texture and finally to a readback buffer solely for test verification. Shared D3D12 fence values sequence both queues within the same iteration. There is no CPU data copy between the APIs; native tiled texture import is not yet tested. The future shim needs GPU texture/linear conversion or validated direct arrays. The caller closes its original NT HANDLEs after HIP releases imports.

Stable HIP SDK 7.2.60201 fails mapped-buffer lifetime testing. resource and import modes are stable, but map leaks one HANDLE and 262144 bytes per cycle. The runtime's extra view->retain() is the cause; AMD removed it in CLR commit 529f6b1. The source backport is retained at patches/rocm/0001-external-memory-view-ownership.patch. No pointer/refcount or DLL binary hacks are used. Current TheRock passes both the 64-cycle map lifetime test and the 32-cycle synchronized texture round trip. The runner automatically isolates resource/import/stream lifetimes on failure. Do not declare stable SDK 7.2 acceptable for the leak-free fast path.

Windows NGX initialization

tools/windows/ngx_cuda_init_probe.cpp retains the physical HIP/PCI device check, initializes a ZLUDA primary context, loads the user-supplied DLLs, discovers DLSS CUDA capability and tests the existing MSVC parameter accessor. This does not create/evaluate a DLSS feature or assert transformer correctness.

The supplied driver _nvngx.dll 32.0.16.1714 uses the driver/snippet three-argument NVSDK_NGX_CUDA_Init(appId, dataPath, sdkVersion) ABI. The four-argument SDK client interface used by the upstream shim passes a pointer as the version and returns 0xBAD0000C (OutOfDate) for this binary. The two interfaces are distinguished in NVIDIA's public nvsdk_ngx.h by NGX_SNIPPET_BUILD. The Windows backend must keep this distinction. The probe has explicit --ngx-abi driver (default) / sdk; it does not guess and retry.

Upstream Windows ZLUDA NVAPI lacks physical GPU enumeration, architecture and logical GPU/LUID functions used by NGX. The compatibility target nvapi-compat/nvapi64.dll implements those public NVAPI APIs through HIP; unknown queries are logged and forwarded to the supplied ZLUDA NVAPI backend. It validates version/size and includes NV_LOGICAL_GPU_DATA_V1.reserved[8] (568-byte x64 ABI). Concurrent initialization is synchronized. The AD102/AD100 identity is explicitly a CUDA/NGX network profile matching d4r's sm_89 kernels; physical detection and native compilation remain gfx1201. It is currently a probe backend, not a complete game-wide NVAPI replacement. A separate nvapi-trace build forwards every response unchanged for diagnosis.

Driver init's default feature search needs the DLSS DLL next to the executable. The runner creates a unique private %TEMP%/d4r-ngx-<GUID> directory containing the probe and copies of the two supplied DLLs. Paths and original hashes/versions are logged; the directory is removed after the subprocess ends. Neither DLL is placed in dist/, git, or the diagnostics ZIP. No private NVAPI function is invented and no NVIDIA binary is patched.

References: NGX API signatures, public NVAPI ABI, public NVAPI interface IDs.

Authoritative references

Build, test, package

Run from the repository root in PowerShell. The setup installs tools only inside .tools, verifies downloaded SHA256 values, and does not install a driver/SDK.

powershell -NoProfile -File scripts/windows/setup-windows-tools.ps1
powershell -NoProfile -File scripts/windows/build-windows-rdna4.ps1
powershell -NoProfile -File scripts/windows/test-windows-rdna4.ps1

For the currently validated external-memory runtime, use the separate profile:

powershell -NoProfile -File scripts/windows/setup-windows-tools.ps1 -RuntimeProfile therock
powershell -NoProfile -File scripts/windows/build-windows-rdna4.ps1 -RuntimeProfile therock
powershell -NoProfile -File scripts/windows/test-windows-rdna4.ps1 -RuntimeProfile therock

This builds into build/windows-rdna4-therock and installs into dist/windows-rdna4-therock. The stable profile stays available for reproducing the runtime bug. It is expected to return failure at the lifetime gate.

One command adds the local NGX initialization gate after eight diagnostics:

powershell -NoProfile -File scripts/windows/test-windows-rdna4.ps1 -RuntimeProfile therock -NgxCore "C:/Users/Administrator/d4r/_nvngx.dll" -DlssDll "C:/Users/Administrator/d4r/nvngx_dlss.dll"

Success with the two local NGX DLLs requires all eleven tests, including both PASS K_REFERENCE checks and PASS NGX_INIT ... sr_available=1. The NGX probe still reports transformer_executed=0: the standalone K launch has not been integrated into DLSS. On NGX failure, CUDA trace and NVAPI query logs are collected automatically. NVIDIA DLLs remain local test inputs.

The build accepts -HipRoot, -ZludaRoot, -ToolchainRoot, -BuildDirectory and -InstallDirectory. MSVC users can invoke CMake from a Developer Shell without the portable MinGW compiler. Equivalent direct build:

cmake -S . -B build/windows-rdna4 -G Ninja -DCMAKE_BUILD_TYPE=RelWithDebInfo "-DD4R_HIP_ROOT=C:/Program Files/AMD/ROCm/7.2" "-DD4R_ZLUDA_ROOT=C:/path/to/zluda"
cmake --build build/windows-rdna4
ctest --test-dir build/windows-rdna4 --output-on-failure
cmake --install build/windows-rdna4 --prefix dist/windows-rdna4-diagnostics

The one-command diagnostic runner is also installed at dist/windows-rdna4-diagnostics/test-windows-rdna4.ps1. It requires the selected HIP SDK and ZLUDA directory; the developer setup auto-discovers local defaults. Success: exit 0, every selected test passed in summary.json, PASS HIP, PASS CUDA, PASS INTEROP_LIFETIME and PASS INTEROP in stdout. Failure: send the single printed ZIP path; it contains stdout/stderr, timeout/exception exit code, DLL paths/versions/hashes, driver/OS inventory and a minidump for an unhandled exception. Upstream trace is attempted automatically on CUDA failure when trace/nvcuda.dll is available. The trace DLL forwards to the real DLL through ZLUDA_CUDA_LIB; explicit loading no longer bypasses the trace by accidentally passing the real DLL to the launcher.

The HIP module compiler uses the selected SDK, fixed --offload-arch=gfx1201, wave32 and no host/device library dependency. Host code uses the installed HIP header ABI and loads that SDK's amdhip64_7.dll by absolute path. CUDA loads the provided ZLUDA DLL by absolute path, matches the adapter against HIP PCI identity, tests two context lifecycles, JITs embedded PTX and verifies an integer pattern and out-of-range sentinels. No CUDA SDK is required.

No NVIDIA DLL is needed for M1/M2. Later NGX tests accept user-supplied absolute paths; NVIDIA software is never downloaded or added to git by these scripts.

Known limitations and results

2026-09-29: installed hipInfo.exe passed device enumeration in this workspace: RX 9070 XT, gfx1201, warpSize 32, 15.92 GiB total, 15.77 GiB free. 2026-09-29 hardware results: Windows 11 Pro 10.0.26200, AMD display driver 32.0.31041.1004, HIP runtime/driver API 70260201. HIP struct size 1472 bytes; physical device PCI 0000:03:00. Native HIP module: 32 successful iterations, 4099 elements with changing launch counts and seeds, guard verified. CUDA PTX: 32 iterations each in primary/created contexts, same pattern/guards verified, all context/module/memory teardown calls successful. ZLUDA binary SHA256 51dd32dc116a6c14c7a4bf5acf620bba0546ca7ec5f8a6e2148dd68f1714b165. Logs: local test-results/m1-m2.zip; ignored by git.

2026-09-29 M4: TheRock profile passed all HIP/PTX checks plus D3D12/HIP round trip (32 iterations, 16384 elements each), exact integer output and GPU fence synchronization. Map lifetime: 64 import/map/free/destroy cycles, HANDLE count 267 after both warmup and the last cycle, free VRAM 16926011392 bytes throughout the measured steady state. Full interop cycle HANDLE count also stays constant after warmup; stream teardown lowers it. Recreating streams did not resolve the stable runtime mapped-view bug; the fix is the runtime ownership correction.

Local proprietary inputs supplied by the user: nvngx_dlss.dll 310.9.1.0, _nvngx.dll 32.0.16.1714. Neither is packaged or tracked.

2026-09-29 NGX initialization: PASS on gfx1201 with those two DLLs and the native NVAPI topology backend. SR Available=1, FeatureInitResult=0x1, NeedsUpdatedDriver=0, MSVC parameter roundtrip Width=640, checked parameter/context/NGX cleanup. Local logs: test-results/ngx-init-private-runtime.zip. This is only the first part of M3; feature execution, K/M correctness and the Windows shim remain open.

2026-09-29 M5: TheRock full diagnostic run including user-provided NGX DLLs: 8/8 gates PASS (test-results/m5-k-module.zip). CTest: 7/7 PASS. Stable HIP 7.2: 5/5 non-interop gates PASS (HIP, gfx12 WMMA, K module load, both CUDA contexts); stable mapped-view lifetime bug still excludes its interop fast path. WMMA raw and legacy-layout adapter each match the scalar reference exactly over 16 changing input matrices, with both one-step and two-step accumulation. The enc1 K module is built and loaded on gfx1201, with functions resolved; transformer_executed=0 was explicit in the module probe at that milestone. The same K source also compiles for gfx1101 through the unchanged gfx11 builtin branch (compile-only regression; no RDNA3 GPU is present in this Windows machine).

2026-09-29 M6 first kernel: enc1 runs on the RX 9070 XT with zero and nonzero synthetic weights. The nonzero fixture exercises V, position-only attention, Wo, MLP/GELU and patch merge. Compared with pwin_model.py, full output max absolute error 0.000244140625, PSNR 98.21 dB; merged output max absolute error 0.000244140625, PSNR 97.63 dB. No NaN/Inf, all 4096 full and 1024 merged elements written, 3886 full elements changed. TheRock diagnostic bundle test-results/m6-k-enc1-final.zip has 9/9 gates PASS; CTest has 7/7 PASS. Reference dependency: pinned local NumPy 2.4.6 on Python 3.11, installed by setup-windows-tools.ps1 into .tools/python/vendor (not the game runtime). This is a synthetic one-layer check, not proof of complete K or DLSS output.

2026-09-29 M6 second kernel: enc2 exercises nonzero Q/K/V, learned attention and softmax, Wo, MLP/GELU and patch merge on gfx1201. Full output max absolute error 3.81469727e-06, max relative error 0.00166893 (denominator floor 1e-3), PSNR 130.39 dB; merged output max absolute error 3.81469727e-06, PSNR 132.49 dB. All 4096 full and 1536 merged elements written, no NaN/Inf. Both layers pass 32 identity iterations and the nonzero numpy reference. Bundle test-results/m6-k-enc2-final.zip: 11/11 gates PASS. CTest: 8/8 PASS. The generic probe/reference runner selects --kernel-name enc1|enc2; both objects remain under experimental/k and are not used as DLSS overrides yet.

Historical stable HIP SDK 7.2 compiler caveat (pre-upstream legacy adapter): its -O2 code object for enc1 produces NaN already on the identity fixture (first element 0xfe00 instead of 0xbc00). Its -O1 object also miscomputes the identity fixture; -O0 passes but is unsuitable for the fast path. Cross-testing isolates the problem to the stable compiler/code object: the stable-built -O2 object fails under TheRock runtime, while the TheRock-built -O2 object passes under stable HIP runtime. The independent WMMA probe passes under both compilers. That legacy path required the TheRock compiler for native K. The 2026-09-30 native-layout merge supersedes this failing path: current enc1/enc2 fixtures pass with stable's -O3 objects too. Keep TheRock runtime for leak-free interop.

The initial audit found an upstream validation blocker: swin_model.py imported absent model_enc3. Upstream commit dbef4b2 restores this file; the missing dependency is resolved, while real GPU M reference validation is still pending.

Environment-specific issues resolved: sandbox disallows writes to .git and launching the MinGW child compiler, so branch/commit/build require scoped tool approval in this managed environment. HIP_PATH ends in a backslash; build script normalizes it before PowerShell 5 argument quoting. Test runner uses .NET Process to retain reliable exit codes and concurrently drain both diagnostic streams. No end-to-end K/M/DLSS/OptiScaler support is claimed by these diagnostic milestones.