Engine: native presets K and M in the D3D12 shim, wider game coverage
A standalone Vulkan inference engine (engine/) for DLSS presets K and M that runs from weights extracted from the user's own nvngx_dlss.dll, with d4r's own input, network and reconstruction shaders or the native HIP network layers, recorded into the game's command list by the shim. Opt-in ([Engine] Enabled / D4R_ENGINE=1); anything uncovered falls back to the CUDA/ZLUDA path with the reason logged. Byte-identical to NGX's CUDA backend under the phase-capable reference (1706x960 -> 2560x1440, native HIP network, eleven frames, RX 9070 XT): - K render- and display-resolution motion vectors, HDR and LDR - K game-supplied exposure and automatic exposure with any pre-exposure and exposure scale (one residual: effective exposure exactly 2 or 4) - K and M with the DLSS indicator's inverted-axis parameters - M with any exposure settings (NGX ignores them for M) K packages need the current compile_k.py (marker D4RO0003). Also: HIP shared buffers are pooled across feature recreation (ROCm leaks destroyed imports), hipnet.bin must match the preset, M-only games do not load the K model, install_d4r_runtime.sh stages k, k-ldr, m, m-ldr with hip/, the activation table has a generator (gen_activation_m.py), and package_release.sh can bundle the engine's shaders (never its weights). Signed-off-by: woutermans <[email protected]>
This commit is contained in:
1 parent
16cfc1f063
commit
e0d1549a21
82 files changed
+13335
-96
No files matched your search
@@ -0,0 +1,68 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Build a kvk manifest for one captured launch and compare kvk's outputs with the capture.
|
||||
|
||||
usage: kcase.py make CAPTURE_DIR KERNEL FRAME OUTDIR [--tex OFF:linear ...] (FRAME counts that kernel's launches from 0)
|
||||
kcase.py cmp OUTDIR
|
||||
CAPTURE_DIR holds dump/ (D4R_CUDA_LAUNCH_DUMP_DIR) and replay/ (D4R_CUDA_REPLAY_DUMP_DIR) of the same run.
|
||||
"""
|
||||
import glob, os, re, sys
|
||||
import numpy as np
|
||||
PING = set()
|
||||
|
||||
def launches(cap, kernel):
|
||||
return sorted({int(re.match(r'launch-(\d+)-', os.path.basename(f)).group(1)) for f in glob.glob(f'{cap}/dump/launch-*-{kernel}-arg*')})
|
||||
|
||||
def res(cap, kernel, seq):
|
||||
out = {}
|
||||
for f in glob.glob(f'{cap}/dump/launch-{seq:03d}-{kernel}-arg*'):
|
||||
m = re.search(r'-arg(\d+)-(texture|surface|buffer)-(.*)-fmt(-?\d+)\.bin$', f)
|
||||
out[int(m.group(1))] = (m.group(2), m.group(3), int(m.group(4)), f)
|
||||
return out
|
||||
|
||||
if sys.argv[1] == 'make':
|
||||
cap, kernel, frame, outdir = sys.argv[2], sys.argv[3], int(sys.argv[4]), sys.argv[5]
|
||||
linear = {int(a.split(':')[0]) for a in sys.argv[6:] if a.endswith(':linear')}
|
||||
os.makedirs(outdir, exist_ok=True)
|
||||
seqs = launches(cap, kernel); seq = seqs[frame]
|
||||
cur = res(cap, kernel, seq)
|
||||
man = open(f'{cap}/replay/replay-{seq:06d}-{kernel}/manifest.txt').read().split('\n')
|
||||
grid = next(l for l in man if l.startswith('launch')).split()
|
||||
lines = [f'param {cap}/replay/replay-{seq:06d}-{kernel}/args.bin', f'grid {grid[1]} {grid[2]}']
|
||||
ptr = {int(l.split()[1]): int(l.split()[3]) for l in man if l.startswith('pointer')}
|
||||
expect = []
|
||||
for off, (kind, shape, fmt, f) in sorted(cur.items()):
|
||||
if kind == 'buffer':
|
||||
lines.append(f'buf {off} {f} {ptr[off]}'); continue
|
||||
w, h, c = (int(x) for x in shape.split('x'))
|
||||
bits = {32: 32, 194: 8, 192: 8, 193: 8, 200: 9, 198: 9, 199: 9}.get(fmt, 16) # 19x: UNORM8, 198..200: SNORM8
|
||||
if kind == 'texture':
|
||||
lines.append(f'tex {off} {f} {w} {h} {c} {bits} {"linear" if off in linear else "nearest"}')
|
||||
else:
|
||||
# the surface's contents before this launch: its dump from the latest earlier launch that had the same data layout
|
||||
init = '-'
|
||||
for s in reversed([s for s in seqs if s < seq]):
|
||||
prev = res(cap, kernel, s)
|
||||
# ping-pong surfaces alternate; take the one whose size matches and which is not this frame's input
|
||||
if off in prev and prev[off][1] == shape and (s == seqs[frame - 2] if frame >= 2 and off in PING else True):
|
||||
init = prev[off][3]; break
|
||||
lines.append(f'surf {off} {w} {h} {c} {bits} {init} {outdir}/out-{off}.bin')
|
||||
expect.append((off, f, c, bits))
|
||||
open(f'{outdir}/manifest', 'w').write('\n'.join(lines) + '\n')
|
||||
open(f'{outdir}/expect', 'w').write('\n'.join(f'{o} {f} {c} {b}' for o, f, c, b in expect) + '\n')
|
||||
print('\n'.join(lines))
|
||||
else:
|
||||
outdir = sys.argv[2]
|
||||
ok = True
|
||||
for l in open(f'{outdir}/expect').read().split('\n'):
|
||||
if not l:
|
||||
continue
|
||||
off, f, c, bits = l.split()
|
||||
dt = np.uint16 if bits == '16' else np.uint32
|
||||
a = np.fromfile(f, dtype=dt); b = np.fromfile(f'{outdir}/out-{off}.bin', dtype=dt)
|
||||
diff = a != b
|
||||
fa = a.view(np.float16 if bits == '16' else np.float32).astype(np.float64); fb = b.view(np.float16 if bits == '16' else np.float32).astype(np.float64)
|
||||
with np.errstate(invalid='ignore'):
|
||||
d = np.abs(fa - fb); d = d[np.isfinite(d)]
|
||||
ok &= not diff.any()
|
||||
print(f'surface {off}: {a.size} values, {int(diff.sum())} differ ({diff.mean() * 100:.4f}%), max |diff| {d.max() if d.size else 0:.6g}, mean |ref| {np.nanmean(np.abs(fa[np.isfinite(fa)])):.4g}')
|
||||
print('BYTE-IDENTICAL' if ok else 'DIFFERENT')
|
||||
Reference in new issue
Block a user