engine: Super Resolution presets E and F, the DLSS 3 CNN, on RDNA2

Presets E (5) and F (6) run on d4r's own Vulkan engine without cooperative
matrices: the input and reconstruction kernels translated from the user's DLL
(engine/compile_sr_e.py, rr/ptx2rr.py), the network engine/sr/e_net.comp with
packed v_pk_fma_f16 accumulation (engine/cnn_sr/mma_f16.glsl, the default
head; --head-accumulation f32 keeps the f32 head). Runtime runtime_e.inc
(EModel/EEngine), game adapter game_e.cpp, replay d4r-e; the shim serves them
from engine\e and engine\f (D4R_ENGINE_MODEL_E_DIR / _F_DIR), LDR or HDR, any
render size, not with AutoExposure. build-engine-models.sh builds both.

Translator fixes that apply to every translated kernel: .relu on f16/f16x2
fma/add/mul was ignored; add.rz was always taken for the roundf idiom (lost
the log1pf correction term); formatted image stores expand at the call site
(SPIR-V image type fix); f16 mma.sync m16n8k8/k16, .const loads, shared
16-bit stores, aligned 32-bit arena words (D4R_WORD_ARENA), unified arena.

Steam Deck gfx1033: 2.55 ms at 640x360 -> 1280x720, 6.20 ms at 1080p
output; Rounded Quality sizes take mid_3x3 (reconstruction 2.44 -> 1.23 ms).
Ray Reconstruction CNN presets A-C (compile_rr3.py, the packed RR flavor)
stay out of this commit; engine/README.md already documents their tuning.
This commit is contained in:
woutermans committed 2026-10-18 20:39:26 +02:00
1 parent 0e851b7f90
commit b9254f7f96
25 files changed
+2406 -36

No files matched your search

+93
View File
@@ -0,0 +1,93 @@
"""Opt-in Vulkan regression for CNN f16 fragments, including independent concurrent waves.
D4R_RUN_GPU_TESTS=1 D4R_EVK=/path/to/evk python3 -m unittest tests.test_cnn_mma_gpu
Build evk with: g++ -O2 engine/evk.cpp -lvulkan -o build/evk
"""
import os
from pathlib import Path
import subprocess
import tempfile
import unittest
ROOT = Path(__file__).resolve().parents[1]
@unittest.skipUnless(os.environ.get('D4R_RUN_GPU_TESTS') == '1', 'opt-in GPU test')
class CnnMatrixGpuTests(unittest.TestCase):
def test_fragment_mapping_accumulation_and_wave_isolation(self):
self.check_fragments(packed=False)
def test_packed_fragment_rounding_and_wave_isolation(self):
self.check_fragments(packed=True)
def check_fragments(self, packed):
import numpy as np
rng = np.random.default_rng(412)
fragments = np.empty((8, 32, 8), dtype='<u4')
expected = np.empty((8, 32, 4), dtype='<u4')
def packed(values):
return np.ascontiguousarray(values, dtype='<f2').view('<u4')[0]
for wave in range(8):
a = rng.normal(0, 0.7, (16, 16)).astype(np.float16)
b = rng.normal(0, 0.7, (16, 8)).astype(np.float16)
c = rng.normal(0, 0.7, (16, 8)).astype(np.float16)
sums = c.astype(np.float32)
results = []
for k in range(16):
if packed:
# A half FMA rounds the exact product plus accumulator once to half.
sums = (sums.astype(float) + a[:, k:k+1].astype(float) * b[k:k+1, :].astype(float)).astype(np.float16).astype(np.float32)
else:
# A product of two finite binary16 values is exact in binary32.
sums = (sums + a[:, k:k+1].astype(np.float32) * b[k:k+1, :].astype(np.float32)).astype(np.float32)
if k in (7, 15):
results.append(sums.astype(np.float16))
for lane in range(32):
g, t = lane // 4, lane % 4
fragments[wave, lane] = [
packed(a[g, 2*t:2*t+2]), packed(a[g+8, 2*t:2*t+2]),
packed(a[g, 2*t+8:2*t+10]), packed(a[g+8, 2*t+8:2*t+10]),
packed(b[2*t:2*t+2, g]), packed(b[2*t+8:2*t+10, g]),
packed(c[g, 2*t:2*t+2]), packed(c[g+8, 2*t:2*t+2]),
]
expected[wave, lane, 0:2] = [packed(results[0][g, 2*t:2*t+2]), packed(results[0][g+8, 2*t:2*t+2])]
expected[wave, lane, 2:4] = [packed(results[1][g, 2*t:2*t+2]), packed(results[1][g+8, 2*t:2*t+2])]
source = '''#version 460
#extension GL_GOOGLE_include_directive : require
#extension GL_EXT_shader_explicit_arithmetic_types : require
#extension GL_EXT_control_flow_attributes : require
#extension GL_KHR_shader_subgroup_basic : require
#extension GL_KHR_shader_subgroup_shuffle : require
#include "../round_half.glsl"
#include "mma_f16.glsl"
layout(local_size_x = 128) in;
layout(binding=0,std430) readonly buffer In { uint v[]; } src;
layout(binding=1,std430) writeonly buffer Out { uint v[]; } dst;
void main() {
uint i=gl_GlobalInvocationID.x, at=i*8u, outAt=i*4u;
uint d0,d1;
mma_f16_m16n8k8(src.v[at],src.v[at+1u],src.v[at+4u],src.v[at+6u],src.v[at+7u],d0,d1);
dst.v[outAt]=d0;dst.v[outAt+1u]=d1;
mma_f16_m16n8k16(src.v[at],src.v[at+1u],src.v[at+2u],src.v[at+3u],src.v[at+4u],src.v[at+5u],src.v[at+6u],src.v[at+7u],d0,d1);
dst.v[outAt+2u]=d0;dst.v[outAt+3u]=d1;
}
'''
with tempfile.TemporaryDirectory() as temporary:
d = Path(temporary)
shader, spv = d/'matrix.comp', d/'matrix.spv'
shader.write_text(source)
fragments.tofile(d/'in.bin')
subprocess.run(['glslangValidator', '-V', '--target-env', 'vulkan1.3',
*(['-DD4R_MMA_PACKED'] if packed else []), '-I'+str(ROOT/'engine/cnn_sr'), str(shader), '-o', str(spv)], check=True, capture_output=True)
subprocess.run([os.environ.get('D4R_EVK', str(ROOT/'build/evk')), str(spv), '2', '1', '1',
'in:0='+str(d/'in.bin'), 'out:1='+str(d/'out.bin')+':'+str(expected.nbytes)],
check=True, capture_output=True)
actual = np.fromfile(d/'out.bin', dtype='<u4').reshape(expected.shape)
np.testing.assert_array_equal(actual, expected)
if __name__ == '__main__':
unittest.main()
+52
View File
@@ -0,0 +1,52 @@
"""Compile translated surface stores with their real Vulkan image types."""
from pathlib import Path
import shutil
import subprocess
import sys
import tempfile
import unittest
ROOT = Path(__file__).resolve().parents[1]
@unittest.skipUnless(shutil.which('glslangValidator') and shutil.which('spirv-val'), 'SPIR-V tools required')
class CnnShaderTypeTests(unittest.TestCase):
def test_mixed_formatted_and_binary_surface_stores_validate(self):
# A function taking an unformatted image2D loses the concrete format type.
# Exercise both RG16F and RGBA16F, including the binary half store helper.
ptx = '''.version 8.0
.target sm_80
.address_size 64
.visible .entry surface_test(.param .align 8 .b8 args[32])
.maxntid 32, 1, 1
{
.reg .b64 %rd<4>;
.reg .b32 %r<4>;
.reg .f32 %f<2>;
ld.param.u64 %rd0, [args+0];
ld.param.u64 %rd1, [args+8];
mov.u32 %r0, 0;
mov.u32 %r1, 15360;
mov.f32 %f0, 0f3F800000;
sust.b.2d.v2.b16.zero [%rd0, {%r0, %r0}], {%r1, %r1};
sust.p.2d.v4.b32.zero [%rd1, {%r0, %r0}], {%f0, %f0, %f0, %f0};
ret;
}
'''
with tempfile.TemporaryDirectory() as temporary:
d = Path(temporary)
(d/'surface.ptx').write_text(ptx)
subprocess.run([sys.executable, str(ROOT/'engine/rr/ptx2rr.py'), str(d/'surface.ptx'), 'surface_test',
str(d/'surface.comp'), '--block', '32,1,1', '--weights-arg', '999',
'--surface=0=rg16f', '--surface=8=rgba16f'], check=True, capture_output=True)
for packed in (False, True):
with self.subTest(packed=packed):
subprocess.run(['glslangValidator', '-V', '--target-env', 'vulkan1.3',
*(['-DD4R_WORD_ARENA', '-DD4R_MMA_PACKED'] if packed else []),
str(d/'surface.comp'), '-o', str(d/'surface.spv')], check=True, capture_output=True)
subprocess.run(['spirv-val', '--target-env', 'vulkan1.3', str(d/'surface.spv')],
check=True, capture_output=True)
if __name__ == '__main__':
unittest.main()
+72
View File
@@ -0,0 +1,72 @@
"""Opt-in rounded Quality reconstruction regression against the generic kernel.
D4R_RUN_GPU_TESTS=1 D4R_SR_E_MODEL=/private/model/e \
D4R_SR_REPLAY=/path/to/d4r-e python3 -m unittest tests.test_sr_reconstruction_gpu
Optionally set D4R_SR_F_MODEL to exercise preset F too. No proprietary fixtures are needed.
"""
import os
from pathlib import Path
import subprocess
import tempfile
import unittest
ROOT = Path(__file__).resolve().parents[1]
@unittest.skipUnless(os.environ.get('D4R_RUN_GPU_TESTS') == '1', 'opt-in GPU test')
class SrReconstructionGpuTests(unittest.TestCase):
def test_rounded_quality_e(self):
self.check_model('D4R_SR_E_MODEL')
def test_rounded_quality_f(self):
self.check_model('D4R_SR_F_MODEL')
def check_model(self, variable):
import numpy as np
if not os.environ.get(variable):
self.skipTest(f'{variable} must name a private compiled model')
model = Path(os.environ[variable]).resolve()
replay = Path(os.environ.get('D4R_SR_REPLAY', ROOT / 'build/native-engine/d4r-e')).resolve()
env = dict(os.environ, D4R_E_TIME_REPEAT='1', ENABLE_VKBASALT='0')
# Test automatic selection, independent of development overrides in the shell.
env.pop('D4R_ENGINE_E_FINAL', None)
shapes = [(1280, 800), (129, 65), (128, 64), (127, 63)]
jitters = [(-.5, -.5), (.5, .5), (-.499, .499), (.499, -.499), (0, 0), (.25, -.25)]
for ow, oh in shapes:
# Independently round each render axis down/up; also exercise mixed rounding.
for upx, upy in [(0, 0), (1, 1), (0, 1), (1, 0)]:
rw, rh = (2 * ow + 2 * upx) // 3, (2 * oh + 2 * upy) // 3
for hdr, low in [(0, 1), (1, 1), (0, 0), (1, 0)]:
with self.subTest(size=(rw, rh, ow, oh), hdr=hdr, low_motion=low):
with tempfile.TemporaryDirectory() as temporary:
case = Path(temporary)
mw, mh = (rw, rh) if low else (ow, oh)
rng = np.random.default_rng(123)
lines = [f'size {rw} {rh} {ow} {oh} {hdr} {low} {mw} {mh}']
for frame, (jx, jy) in enumerate(jitters, 1):
color = rng.random((rh, rw, 4), dtype=np.float32) * (8 if hdr else 1)
color[..., 3] = 1
color.astype('<f2').tofile(case / f'{frame}-color.bin')
rng.uniform(-12, 12, (mh, mw, 2)).astype('<f2').tofile(case / f'{frame}-motion.bin')
rng.uniform(.01, 1, (rh, rw)).astype('<f4').tofile(case / f'{frame}-depth.bin')
lines.append(f'frame {frame} {jx} {jy} 1 1 {int(frame in (1, 6))}')
(case / 'frames.txt').write_text('\n'.join(lines) + '\n')
for name, override in [('reference', {'D4R_ENGINE_E_FINAL': '3x3_256'}), ('auto', {})]:
out = case / name
out.mkdir()
result = subprocess.run([str(replay), str(model), str(case), str(out)],
env=dict(env, **override), capture_output=True, text=True, timeout=90)
self.assertEqual(result.returncode, 0, result.stdout + result.stderr)
for frame in range(1, len(jitters) + 1):
name = f'{frame}-out.bin'
reference = np.fromfile(case / 'reference' / name, '<f2')
actual = np.fromfile(case / 'auto' / name, '<f2')
self.assertEqual(actual.size, ow * oh * 4)
self.assertTrue(np.isfinite(reference).all())
self.assertTrue(np.isfinite(actual).all())
self.assertTrue(np.any(actual.reshape(-1, 4)[:, :3] != 0))
np.testing.assert_array_equal(actual.view("<u2"), reference.view("<u2"), err_msg=name)
if __name__ == '__main__':
unittest.main()