#!/usr/bin/env python3 """What a preset F model takes from a capture, read from nvngx_dlssd.dll 310.9 instead: the argument-block templates (.args), encoder 0's second table (enc0-aux.bin, argument 104) and the stages' plane-arena regions. usage: rr2_templates.py NVNGX_DLSSD_DLL OUT_DIR write the templates and enc0-aux.bin rr2_templates.py NVNGX_DLSSD_DLL --check MODEL_DIR compare with a model compile_rr2.py built from a capture engine/runtime_rr2.inc fills every field of the blocks that depends on the frame, the geometry or the bound inputs. Across the preset F captures (2026-10-14: capF, capF900, capF1440, capF4K, capFQ and the capFX* input variants) what is left is per stage: network stages binary16 s0 (byte 92), s1 (94), s2 (96) and, for the decoders, s3 (98) (engine/rr/rr2_ref.py) enc0 two float32 (572, 576), two binary16 widened to float32 (580, 584), 1.0 (588, 1072), 1 (1036) dec0_1 8.0 (208) and exp(t) (212); post: exp(t') (128); down / downp: 0.25 (204), 1.0 (296, 300) NGX's model description is built by one routine of plain stores (mov [rdx + d], imm32 / ax / a pointer); describe() replays it. It holds every tensor's pointer and size, s1 / s2 of each stage at 0x220 + 0x238 * n (a decoder level's two kernels side by side, its s3 behind them), encoder 0's float32 pair at 0x230 and the binary16 pair at 0x185a, and three one-value tensors (t at 0x1838, t' at 0x1848). s0 sits in the weights, before each encoder's relative position tables (encoder 0: 16 bytes before; a decoder level uses its encoder's). enc0-aux.bin is preset E's noise table (engine/rr/dll_weights.py) and then encoder 0's embedding, both branches: Wd (32 x 64 FP8 codes, 43 inputs used), bd, Wu (32 x 32 FP8), bu (once, after the first branch), the FP8 matrices in the kernel's fragment order: a fixed permutation of the index bits of the natural [in][out] order (FRAG_WD, FRAG_WU). Everything written is derived from the user's DLL and stays on their machine. """ import math import struct import sys from pathlib import Path import numpy as np sys.path.insert(0, str(Path(__file__).resolve().parent)) from dll_weights import noise_table # noqa: E402 from enc1_ref import inter # noqa: E402 from rr2_ref import ORDER, dll_weights, find_tables # noqa: E402 H = np.float16 NETWORK = ORDER # enc0 ... enc5, dec4_0, dec4_1, ... dec0_1 ARG_BYTES = dict({s: 104 for s in NETWORK}, enc0=1088, dec0_1=216, post=320, down=416, downp=416, pooled=32) # the plane-arena regions of the network stages: argument offset -> region start in units of 1/3152 of NGX's arena # (W0 * H0 / 32 bytes; the same on every capture) ARENA = { 'enc0': '32:0,40:1024,64:2560,72:2240', 'enc1': '8:0,32:1536,40:2048,48:2240,64:3008,72:2304', 'enc2': '8:2048,32:1024,40:1216,48:2304,64:1472,72:1364', 'enc3': '8:1216,32:1280,40:1344,48:1364,64:1368,72:1372', 'enc4': '8:1344,32:1236,40:1216,48:1372,64:1261,72:1221', 'enc5': '8:1216,32:1256,48:1221,64:1262', 'dec4_0': '8:1256,16:1236,32:1216', 'dec4_1': '8:1216,32:1344,48:1262,56:1261,64:1364', 'dec3_0': '8:1344,16:1280,32:1216', 'dec3_1': '8:1216,32:1408,48:1364,56:1368,64:1488', 'dec2_0': '8:1408,16:1024,32:1216', 'dec2_1': '8:1216,32:2816,48:1488,56:1472,64:3136', 'dec1_0': '8:2816,16:1536,32:1024', 'dec1_1': '8:1024,32:2048,48:3136,56:3008,64:3072', 'dec0_0': '8:2048,16:0,32:1024', 'dec0_1': '8:1024,48:3072,56:2560,64:2816', } # fragment order of encoder 0's FP8 matrices in enc0-aux.bin: bit j of the table index is bit FRAG[j] of the natural # index in * 32 + out (found on 310.9.1 and checked on every entry of both branches) FRAG_WD = [5, 9, 8, 3, 6, 7, 0, 1, 2, 10, 4] FRAG_WU = [5, 9, 8, 3, 6, 7, 0, 1, 2, 4] def sections(dll): pe = struct.unpack_from('> 6, (m >> 3) & 7, m & 7 if rm == 4 or (mod == 0 and rm == 5) or mod == 3: raise ValueError base = {2: 'rdx', 1: 'rcx'}.get(rm) if mod == 0: return base, reg, 0, 1 if mod == 1: return base, reg, struct.unpack_from('> 6 == 3 else 6); continue if op == 0xc7: # mov [rdx + d], imm32 base, _, d, n = modrm(b, j + 1) if base == 'rdx': stores[d] = struct.pack('= 0: start = dll.rfind(b'\xcc\xcc', 0, at) + 2 try: stores, pointers = replay(dll, start, None) if 0x220 in stores and 0x1858 in stores: found.append((stores, pointers)) except ValueError: pass at = dll.find(marker, at + 1) if len(found) != 1: raise SystemExit(f'found {len(found)} preset F model descriptions in the DLL (expected one): not a layout this ' 'builder knows') return found[0] def h16(b): return np.frombuffer(b, H)[0] def values(dll): """{stage: {argument offset: bytes}} of every constant the runtime keeps""" stores, pointers = describe(dll) image = bytearray(max(d + len(v) for d, v in stores.items())) for d in sorted(stores): image[d:d + len(stores[d])] = stores[d] word = lambda d: bytes(image[d:d + 2]) tables = find_tables(dll) s0 = {} for n, stage in enumerate(['enc0', 'enc1', 'enc2', 'enc3', 'enc4', 'enc5']): at = tables[stage] - (16 if stage == 'enc0' else 8) s0[stage] = dll[at:at + 2] out = {} for n, stage in enumerate(NETWORK): v = {} if stage.startswith('enc'): k = int(stage[3]) v[92] = s0[stage] d = 0x220 + 0x238 * k v[94] = bytes(image[d:d + 4]) else: level, half = int(stage[3]), int(stage[5]) v[92] = s0[f'enc{level + 1}'] d = 0x220 + 0x238 * (10 - level) v[94] = bytes(image[d + 4 * half:d + 4 * half + 4]) v[98] = word(d + 8) out[stage] = v f16f32 = lambda b: struct.pack(' the table's order: bit j of the table index is bit bits[j] of the natural index""" flat = natural.ravel() idx = np.arange(flat.size) src = np.zeros_like(idx) for j, b in enumerate(bits): src |= ((idx >> j) & 1) << b return flat[src].tobytes() def aux_table(dll): noise = noise_table(dll) if noise is None: raise SystemExit('no noise table found in the DLL') w = dll_weights(dll, 'enc0') def natural(b_operand): # B = q8(mat).T[inter(k)] (k x n) -> [in][out] n = np.empty_like(b_operand) n[np.asarray(inter(b_operand.shape[0]))] = b_operand return n out = [noise] for b in range(2): out += [frag(natural(np.asarray(w['ewd'][b])), FRAG_WD), np.asarray(w['ebd'][b], H).tobytes(), frag(natural(np.asarray(w['ewu'][b])), FRAG_WU)] if b == 0: out.append(np.asarray(w['ebu'], H).tobytes()) return b''.join(out) def main(): if len(sys.argv) < 3: raise SystemExit(__doc__) dll = Path(sys.argv[1]).read_bytes() blocks, aux = templates(dll), aux_table(dll) if sys.argv[2] == '--check': model, bad = Path(sys.argv[3]), 0 theirs = (model / 'enc0-aux.bin').read_bytes() print('enc0-aux.bin:', 'same' if theirs == aux else 'DIFFERENT'); bad += theirs != aux for stage, ours in blocks.items(): path = model / f'{stage}.args' if not path.exists(): continue t = path.read_bytes()[:len(ours)] diff = [i for i in range(len(ours)) if ours[i] != t[i]] words = sorted({i // 4 * 4 for i in diff}) print(f'{stage}: ' + ('same' if not diff else f'{len(words)} words differ: {words[:40]}')) sys.exit(1 if bad else 0) out = Path(sys.argv[2]) out.mkdir(parents=True, exist_ok=True) for stage, b in blocks.items(): (out / f'{stage}.args').write_bytes(b) (out / 'enc0-aux.bin').write_bytes(aux) if __name__ == '__main__': main()