engine/rr: native Ray Reconstruction stages with capture/replay and shim integration

- engine/rr: d4r's own shaders for the denoiser frame (exposure, six encoders,
  five decoders, hkpn output stage) at NGX layouts, plus PTX->GLSL/HIP packing
  scripts, reference implementations and weight extraction
- runtime.h/runtime_rr.inc, game_rr.{h,cpp}: GameDenoiser wired into the engine
  build (d4r-rr replay binary) and the D3D12 shim's feature-13 path
- shim: answer GetFeatureRequirements from d4r's own state only (the old
  cross-binary CUDA handoff crashed OptiScaler's scan); drop the core's
  CUDA GetFeatureRequirements import
- shim/harness: exact guide capture/replay of a frame's RR inputs
- kernels/rr: expanded enc0/engine prototypes; kernels/tools: ptxsim rewrite
  plus rrsim and an engine test; vulkan: ptx2glsl FP8/cooperative-matrix
  support, kvk inout buffers and KVK_DISABLE_OPTIMIZATION
- bridge: report the surface array in cuSurfObjectCreate traces
- packaging: RR settings and the ICU launch overrides in D4R_README
This commit is contained in:
woutermans committed 2026-10-12 12:47:53 +02:00
1 parent 30472ae195
commit 50fa65d87b
67 files changed
+11926 -504

No files matched your search

+70 -41
View File
@@ -287,7 +287,7 @@ class T:
def stmt(self, s):
if s.startswith('.reg'):
m = re.match(r'\.reg\s+\.(\w+)\s+(.*)$', s)
m = re.match(r'\.reg\s*\.(\w+)\s*(.*)$', s)
ty, names = m.groups()
if '<' in names:
return
@@ -714,10 +714,7 @@ class T:
raise Err('store ' + '.'.join(o))
# ---------------------------------------------------------------- output
def emit(self, tex_filter):
nb = len(self.blocks)
out = []
w = out.append
def preamble(self, w, tex_filter):
w('#version 460')
# scripts/check_redistributable.py refuses files carrying this line: they are NVIDIA's code.
w(f'// Generated by vulkan/ptx2glsl.py from NVIDIA PTX ({self.kernel}); do not commit or redistribute.')
@@ -741,7 +738,15 @@ class T:
w(f'layout(set = 0, binding = {b}, scalar) readonly buffer ExpLut {{ uint16_t e[65536]; }} explut;')
w('uint ex2_lut(uint u) { return uint(explut.e[u & 0xffffu]) | (uint(explut.e[u >> 16]) << 16); }')
w(f'shared uint sh[{max(self.shared_bytes // 4, 1)}];')
w(RUNTIME)
def runtime(self):
return RUNTIME
def emit(self, tex_filter):
nb = len(self.blocks)
out = []
w = out.append
self.preamble(w, tex_filter)
w(self.runtime())
w('void main()\n{')
if getattr(self, 'local_bytes', 0):
w(f' uint loc[{(self.local_bytes + 3) // 4}];')
@@ -749,7 +754,7 @@ class T:
names = sorted(n for n, t in self.regs.items() if t == g)
for i in range(0, len(names), 24):
init = {'float': '0.0', 'float16_t': '0.0hf', 'f16vec2': 'f16vec2(0.0hf)', 'uint': '0u', 'uint64_t': '0ul', 'bool': 'false'}[g]
w(f' {"precise " if g in ("float", "float16_t", "f16vec2") and not self.fast else ""}{g} ' + ', '.join(f'{n} = {init}' for n in names[i:i + 24]) + ';')
w(f' {"precise " if (g in ("float", "float16_t", "f16vec2") or getattr(self, "precise_all", False) and g != "bool") and not self.fast else ""}{g} ' + ', '.join(f'{n} = {init}' for n in names[i:i + 24]) + ';')
# control flow graph over the blocks; END is block nb
succ = []
for i, blk in enumerate(self.blocks):
@@ -780,26 +785,45 @@ class T:
headers = sorted({h for _, h in back})
cont = {h: END + 1 + i for i, h in enumerate(headers)}
g = {n: [(cont[m] if (n, m) in back else m) for m in succ[n]] for n in nodes}
for h in headers:
latches = [n for n, m in back if m == h]
exits = {m for n in latches for m in succ[n] if (n, m) not in back}
if len(exits) != 1:
raise Err('loop without a single latch exit')
g[cont[h]] = [exits.pop()]
g[END] = []
allnodes = list(g)
# immediate post-dominators (iterative, on the acyclic graph g)
rpo, seen = [], set()
def dfs(n):
stack = [(n, iter(g[n]))]; seen.add(n)
while stack:
x, it = stack[-1]
for m in it:
if m not in seen:
seen.add(m); stack.append((m, iter(g[m]))); break
else:
rpo.append(x); stack.pop()
dfs(0)
for h in headers:
g[cont[h]] = [END] # provisional, replaced below
def postorder():
rpo, seen = [], set()
def dfs(n):
stack = [(n, iter(g[n]))]; seen.add(n)
while stack:
x, it = stack[-1]
for m in it:
if m not in seen:
seen.add(m); stack.append((m, iter(g[m]))); break
else:
rpo.append(x); stack.pop()
dfs(0)
return rpo
# A loop may leave through its header as well as through its latches. Its body is the set of nodes that
# reach a latch without passing the header; the loop region ends at the nearest node that post-dominates
# every exit of the body (for a loop with one latch exit this is that exit, as before).
preds = {}
for n in nodes:
for m in succ[n]:
preds.setdefault(m, []).append(n)
pdom = {END: {END}}
for n in postorder(): # successors first
if n != END:
pdom[n] = {n} | set.intersection(*(pdom[m] for m in g[n]))
for h in headers:
body, work = {h}, [n for n, m in back if m == h]
while work:
n = work.pop()
if n not in body:
body.add(n); work += preds.get(n, [])
exits = {m for n in body for m in succ[n] if m not in body}
if not exits:
raise Err('loop without an exit')
common = set.intersection(*(pdom[e] for e in exits))
g[cont[h]] = [max(common, key=lambda c: len(pdom[c]))]
rpo = postorder()
topo = rpo[::-1] # entry first
index = {n: i for i, n in enumerate(topo)}
ipdom = {END: END}
@@ -928,21 +952,10 @@ void sust_b(writeonly uimage2D s, int xb, int y, uint v)
}
'''
if __name__ == '__main__':
filt = {}
args = sys.argv[1:]
while '--tex' in args:
i = args.index('--tex'); k, v = args[i + 1].split(':'); filt[int(k)] = v; del args[i:i + 2]
lut = '--exp-lut' in args
if lut:
args.remove('--exp-lut')
fast = '--fast' in args
if fast:
args.remove('--fast')
src = open(args[0]).read()
t = T(src, args[1])
def build(make, lut, fast, no_half):
t = make()
t.exp_lut = lut
if '--no-half-types' not in args:
if not no_half:
t.collect = True
t.translate()
parent = {}
@@ -961,8 +974,24 @@ if __name__ == '__main__':
half = {x for x in set(t.ctx) | set(parent) if x in t.width and groups[find(x)] == {'h'}}
sys.stderr.write(f'half-typed registers: {len(half)} of {len(t.width)}\n')
lut2 = t.exp_lut
t = T(src, args[1]); t.exp_lut = lut2; t.half = half
t = make(); t.exp_lut = lut2; t.half = half
t.fast = fast
t.translate()
return t
if __name__ == '__main__':
filt = {}
args = sys.argv[1:]
while '--tex' in args:
i = args.index('--tex'); k, v = args[i + 1].split(':'); filt[int(k)] = v; del args[i:i + 2]
lut = '--exp-lut' in args
if lut:
args.remove('--exp-lut')
fast = '--fast' in args
if fast:
args.remove('--fast')
src = open(args[0]).read()
t = build(lambda: T(src, args[1]), lut, fast, '--no-half-types' in args)
sys.stdout.write(t.emit(filt))
sys.stderr.write(f'blocks={len(t.blocks)} textures={sorted(t.textures)} surfaces={t.surfaces} shared={t.shared_bytes}\n')