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:
woutermans committed 2026-10-10 20:54:01 +02:00
1 parent 16cfc1f063
commit e0d1549a21
82 files changed
+13335 -96

No files matched your search

+68
View File
@@ -0,0 +1,68 @@
#!/usr/bin/env python3
"""Generate activation_m.glsl's ACT table: binary16 sigmoid, tanh and gate of every E4M3 code.
usage: gen_activation_m.py print the ACT declaration
gen_activation_m.py --check exit 1 unless engine/activation_m.glsl holds exactly this table
Row c is uvec2(tanh << 16 | sigmoid, gate) for the E4M3 value of code c:
sigmoid 1 / (1 + exp2(-1.442695 * x)) in f32, rounded to binary16
tanh correctly rounded binary16 tanh(x)
gate .5 * tanh(.5 * x) + .5 with each operation rounded to binary16
The NaN codes (127, 255) give quiet NaN; the sigmoid keeps the input's sign, as f32 arithmetic propagates it.
"""
import math
from pathlib import Path
import re
import sys
import numpy as np
GLSL = Path(__file__).resolve().parent / 'activation_m.glsl'
NAN_ROWS = {127: (0x7e007e00, 0x7e00), 255: (0x7e00fe00, 0x7e00)}
def e4m3(code):
sign = -1.0 if code & 128 else 1.0
exponent, mantissa = (code >> 3) & 15, code & 7
if exponent == 0:
return sign * mantissa / 8 * 2.0 ** -6
return sign * (1 + mantissa / 8) * 2.0 ** (exponent - 7)
def bits(value):
return int(np.array(value, dtype=np.float16).view(np.uint16))
def row(code):
if code in NAN_ROWS:
return NAN_ROWS[code]
x = e4m3(code)
with np.errstate(over='ignore'):
sigmoid = np.float32(1) / (np.float32(1) + np.exp2(np.float32(-1.442695) * np.float32(x), dtype=np.float32))
# float64 tanh rounded once to binary16 is correctly rounded for every E4M3 input (no value lies near a tie).
tanh = np.float16(math.tanh(x))
half = np.float16(0.5)
gate = np.float16(np.float16(half * np.float16(math.tanh(float(half * np.float16(x))))) + half)
return bits(tanh) << 16 | bits(sigmoid), bits(gate)
def declaration():
rows = ',\n'.join(f' uvec2(0x{x:08x}u, 0x{y:08x}u)' for x, y in map(row, range(256)))
return f'const uvec2 ACT[256] = uvec2[256](\n{rows}\n);'
def main(argv):
if argv == ['--check']:
match = re.search(r'const uvec2 ACT\[256\] = uvec2\[256\]\(.*?\n\);', GLSL.read_text(), re.S)
if match is None or match.group(0) != declaration():
print(f'{GLSL} does not hold the generated table', file=sys.stderr)
return 1
return 0
if argv:
sys.exit(__doc__)
print(declaration())
return 0
if __name__ == '__main__':
sys.exit(main(sys.argv[1:]))