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]>
45 lines
1.8 KiB
Python
45 lines
1.8 KiB
Python
#!/usr/bin/env python3
|
|
"""Compare full native frame results, including the engine's own temporal feedback.
|
|
|
|
test_frame.py CASE_DIR RESULT_DIR [--min-psnr 50]
|
|
Exits nonzero for missing data, nonfinite output, or a PSNR regression.
|
|
"""
|
|
import argparse
|
|
import json
|
|
from pathlib import Path
|
|
import numpy as np
|
|
|
|
|
|
def compare(reference, output):
|
|
a = np.fromfile(reference, np.float16).astype(np.float64)
|
|
b = np.fromfile(output, np.float16).astype(np.float64)
|
|
if a.shape != b.shape or not a.size:
|
|
raise ValueError(f'{output}: size differs from reference')
|
|
if not np.isfinite(a).all() or not np.isfinite(b).all():
|
|
raise ValueError(f'{output}: nonfinite reference or result')
|
|
error = np.abs(a - b)
|
|
peak = max(np.abs(a).max(), 1e-9)
|
|
psnr = 10 * np.log10(peak**2 / max((error**2).mean(), 1e-30))
|
|
return psnr, error.max(), error.mean()
|
|
|
|
|
|
def main():
|
|
p = argparse.ArgumentParser(description=__doc__)
|
|
p.add_argument('case', type=Path)
|
|
p.add_argument('results', type=Path)
|
|
p.add_argument('--min-psnr', type=float, default=50)
|
|
a = p.parse_args()
|
|
references = json.loads((a.case / 'references.json').read_text())
|
|
if not references: raise ValueError('no reference frames')
|
|
failed = False
|
|
names = {'288': 'history color', '296': 'hi-res luma', '304': 'token feature', '312': 'final RGB'}
|
|
for i, refs in enumerate(references):
|
|
for off, reference in refs.items():
|
|
psnr, maximum, mean = compare(reference, a.results / f'frame-{i}.{off}.bin')
|
|
print(f'frame {i} {names[off]:14s}: {psnr:6.1f} dB PSNR; max error {maximum:.5g}; mean {mean:.5g}')
|
|
failed |= psnr < a.min_psnr
|
|
if failed: raise SystemExit(f'frame validation failed: PSNR below {a.min_psnr:g} dB')
|
|
|
|
|
|
if __name__ == '__main__': main()
|