NR runtimes 310.8 and 310.9.16: static analysis (full technical)

Back to the report · ControlMask how-to · Noisy-domain NR feasibility

Written by Claude Opus 5.5 (Claude Code, high effort) on behalf of GrimsVerk, who skimmed it. The research, the test-build code changes, the measurements and this text are Claude's work.

Files: nvngx_dlssnr.dll 310.8.0.0 (CL 38718415, 165,840,496 bytes, SHA-256 4b8d19bc3eff58a084f5eca7489c921501c203450169fb82ff4f649a4482ba05) and 310.9.16.0 (CL 39025366, 266,424,944 bytes, SHA-256 2bc19bc09a7b89dd44f73e2ac0108fcc586e2154bdd0830f242f4f040e28789f).

Method:

"Seen in game" means the runtime's own NGX log confirmed it in The Witcher 3. The log was switched on with the __NGX_LOG_LEVEL environment variable, set in-process by the research build.

About line numbers. "l.NNNN" refers to a full decompile export (every function, Ghidra 12.1.4 default analysis, in address order). They only help if you make the same export. Function names and addresses (FUN_18xxxxxxx) are the stable reference: they are identical in any Ghidra project of the same file with the same base.

1. Summary

2. PE inventory

310.8 310.9.16
File size 165,840,496 266,424,944
FileVersion / OriginalFilename 310.8.0.0 / CL 38718415 310.9.16.0 / CL 39025366
Source branch (paths in strings) snippets/rel_310_8 snippets/rel_310_9
NGXAppId (version resource) literal APP_ID_HASH 241534723
NGXGpuArchitecture / NGXApiVersion / NGXMinimumDriverVersion Blackwell2 / 0x13 / 615.00 same
TimeDateStamp 1786480171 1790318716
SizeOfImage 0x9e42000 0xfe2f000
Exports 55, identical names: D3D11/D3D12/Vulkan/CUDA entry points, GetAPIVersion, GetApplicationId, GetDriverVersionEx, GetGPUArchitecture, GetSnippetVersion, SetOverrideStatusCallback, SetRuntimeParamsCallback, SetTelemetryEvaluateCallback same 55
Imports KERNEL32 (120), ADVAPI32 (3), USER32 (1), VERSION (3). CUDA/D3D/Vulkan only through NGX core callbacks same
.text (VA / raw size) 0x1000 / 0xaae00 0x1000 / 0xd5400
.rdata 0xac000 / 0x33800 0xd7000 / 0x38800
.data 0xe0000 / 0x1062800 (16.5 MB, entropy 5.3) 0x110000 / 0x380a00 (3.7 MB, entropy 8.0)
.rsrc 0x1165000 / 0x8cdae00 0x4b4000 / 0xf978e00

Resources (type 10 = RCDATA):

Resource 310.8 RVA / file offset / size 310.9.16 RVA / file offset / size
WEIGHTS_HT 0x1165560 / 0x114a160 / 147,695,410 0x4b45b8 / 0x498db8 / 147,695,410 (identical bytes)
WEIGHTS_CC_SMALL_FP8 absent 0x918ecf0 / 0x91734f0 / 113,893,343
VS_VERSION_INFO 0x11650c0 / 0x1149cc0 / 1184 0x4b4110 / 0x498910 / 1188

CUDA fatbins (magic 50 ED 55 BA). Payloads are zstd-compressed. 310.8: each fatbin has sm_89 SASS + sm_120 PTX + sm_120 SASS. 310.9.16: sm_120 PTX + sm_120 SASS only. File offsets:

PTX entry points: 310.8 has 231 (FP16 + FP8 variants); 310.9.16 has 120 (FP8 only, plus cc_cb_clear, cg2r_copy_kernel, cg2r_post_process_kernel, and the cuda_capture_*/cuda_font_kernel NGX helpers). Every 310.9.16 kernel name also exists in 310.8. No ONNX, TensorRT plans, LZ4 or DXBC were found. There is one SPIR-V blob in each (NGX helper).

Weights container format (both resources): u64 total size, then per tensor u64 name length, name, u64 record length, [u64 record length, u64 data length, u32 flag, data, 20-byte trailer: u64 0, u64 1, u32 element count]. Tensors are named blockN.layerM.layer, plus one blockN.layer0.blend_scale (2 bytes). Element counts equal data length / 2.

3. The two models

honest tench (preset 1) crazy cuckoo small (preset 2, 310.9.16 default)
In 310.8 / 310.9.16 yes / yes no / yes
Tensors 153 (71 blocks) 77 (31 blocks)
Weight bytes 147.7 MB 113.9 MB
GPU weight heap (seen in game) 140.9 MB 108.6 MB
GPU work pool at 3840x2160 (seen in game) 727.7 MB in 310.8 · 528.5 MB in 310.9.16 526.6 MB
Descriptor templates (blocks per stage) {4, 4, 6, 8, 8} {2, 2, 2, 2, 2}
Bottleneck 8 transformer blocks at 1024 channels (q/k/v + FFN 4096) the same 8 blocks
Registry entry 310.8 0x1800b0d80 (stride 0x288); 310.9.16 0x1800dbe30 (stride 0x290) 310.9.16 0x1800dbe30 + 0x290
Arch tag string CC_SILVER_AARDWOLD CC_SMALL_FP8
Scale 310.8 310.9.16
0.875 583 MB not logged
0.75 433 MB 311 MB
0.625 310 MB 222 MB
0.5 203 MB 144 MB
0.33 86 MB 62 MB

Registry entry layout (310.9.16; 310.8 is the same minus 8 bytes):

Offset Content
+0 config name
+8 preset id
+16 resource name
+24 arch tag
+0x20 1 (tone/structure inputs, likely)
+0x21 1 (automask channel path, likely)
+0x24 15 (input channel layout, likely)
+0x28 1 (style conditioning, likely)
+0x2c 3 (style count, certain)
from +0x38 8 style-grade slots of 14 floats each

4. Every parameter the runtime reads

"Create" = read in CreateFeature (310.9.16 FUN_180017b20, 310.8 FUN_180017e20). "Eval" = read by the per-evaluation parser (310.9.16 FUN_18001a020, 310.8 FUN_180019f30). "v0.3.8" = what OptiScaler-NR v0.3.8 sends.

Parameter Type Read Default Values / range What it does 310.8 310.9.16 v0.3.8
CreationNodeMask, VisibilityNodeMask uint Create 1 node masks multi-GPU only yes yes 1 / 1
DLSSNR.Width / Height uint Create output size > 0 allocation size; the network runs at the active rect size and grows past this with a warning yes yes work size
DLSSNR.Hint.Render.Preset uint (& 0x7fffffff) Create 0 310.8: 1; 310.9.16: 1, 2 picks the model; unknown values fall back to the shipping default (310.8: 1, 310.9.16: 2). Lookup: 310.9.16 FUN_180023c20, 310.8 FUN_180023a40 no effect (one model) 1 = honest tench, 2 = small 0 (→ 2)
DLSSNR.Color resource Eval required display-referred RGB in [0,1] the picture to edit. Encoded (c - 0.5)/8; no exposure, sRGB, PQ or HDR handling; output always clamped to [0,1], alpha written as 1 yes yes HUD-less picture
DLSSNR.Output resource Eval required same size as Color result yes yes yes
DLSSNR.MVec + subrect resource Eval none pixel units × MVecScale / MVec size temporal history: previous network output fetched (Catmull-Rom) at uv + mv·scale/size; without MVec, or with Reset, history = current colour yes yes game's DLSS vectors
DLSSNR.MVecScaleX / Y float Eval 1.0 see MVec yes yes game's values
DLSSNR.Depth + subrect resource Eval none not used. The pre-block kernel's depth slot is passed a literal 0 (310.9.16 l.26416) read, unused read, unused passed
DLSSNR.DepthInverted uint Eval 1 0/1 no effect (only feeds dead depth code) yes yes passed
DLSSNR.Intensity float Eval 1.0 effective 0..1 final lerp: out = orig + sat(I [× mask.r]) · (NR − orig). Not a network input; > 1 does nothing yes yes 1
DLSSNR.LocalToneStrength float Eval 1.0 unclamped network input (channel 11, × ControlMask.g); also scales the style grade by clamp(tone, 0, 1) yes yes 1
DLSSNR.LocalStructureStrength float Eval 1.0 unclamped network input (channels 12-14) yes yes 1
DLSSNR.SkinStructureStrength float Eval -1 -1 = follow structure; else unclamped skin structure (channel 13) yes yes -1
DLSSNR.UseAutoMask uint Eval 0 0/1 1: separate skin/structure channels (13, 14). 0: those are -1 and structure goes into channel 12. A ControlMask forces it to 0 (310.8 always; 310.9.16 only with MaskBlendMode 0) yes yes 1
DLSSNR.MaskBlendMode uint Eval 0 0..3 (> 3 → 0) new. With a ControlMask and AutoMask on: m = mask.b × structure is combined with the automatic skin/structure values, 1 average, 2 min, 3 max. 0 = the mask replaces AutoMask no yes not sent
DLSSNR.ControlMask + subrect resource Eval none RGBA per-pixel controls: r = intensity, g = tone, b = structure, a unused (see controlmask.html) yes yes null
DLSSNR.Style uint Eval 0 0, 1, 2 (≥ 3 → 2) network input (channel 10 = style/128) and a colour grade on the result, × clamp(tone, 0, 1): 0 = none; 1 = exposure −0.1 EV, contrast −0.25, saturation −10 %; 2 = saturation −15 %. A change resets history yes yes 1
DLSSNR.Reset uint Eval 0 0/1 drops temporal history for this frame yes yes on first frame
DLSSNR.Enabled uint Eval 1 0/1 0 copies Backbuffer or Color straight to Output yes yes 1
DLSSNR.UICorrection uint Eval 0 0/1 with UI/UIAlpha (+ Backbuffer): NR is faded under UI by (1 − alpha), result rebuilt on the Backbuffer. With a Backbuffer and no UI, the network runs on the Backbuffer yes yes 1 (no UI given)
DLSSNR.UI / UIAlpha / Backbuffer + subrects resource Eval none see UICorrection; alpha = UIAlpha.r, else UI.a yes yes null
DLSSNR.BidirectionalDistortionField + subrect resource Eval none no effect (one telemetry bit, l.20074) yes yes not sent
DLSSNR.ScalingRatio float Eval (310.8) / never (310.9.16) 1.0 no effect. 310.8 reads it and overwrites it with 1.0; 310.9.16 never reads it. Only the ComputeScalingRatio callback writes it (310.9.16 FUN_180012740, 310.8 FUN_180012e80): PerfQualityValue 2/5 → 1.0, 4 → 0.85 (0x1800d9848), else error; 310.8 → 1.0 (0x1800ad684) for 0/1/2/4/5 no effect no effect not sent
DLSS.Indicator.Invert.X / Y.Axis uint Eval 0 0/1 moves the on-screen indicator only yes yes not sent

Evaluate parser struct P (310.9.16, 0x160 bytes):

Offset Field
+0 Color
+0x18 MVec
+0x30 Depth
+0x48 Output
+0x60 ControlMask
+0x78 UI
+0x90 UIAlpha
+0xa8 Backbuffer
+0xc0 BDF
+0xd8 / +0xdc MVecScale X / Y
+0xe0 Intensity
+0xe4 Tone
+0xe8 Structure
+0xec Style
+0xf0 AutoMask
+0xf4 MaskBlendMode
+0xf8 Skin
+0xfc / +0x100 effective skin / structure (both −1.0 when AutoMask is off)
+0x104 Reset
+0x108 DepthInverted
+0x10c Enabled
+0x110 UICorrection
+0x114 / +0x118 indicator invert X / Y
+0x120 downscale flag (always 0)
+0x124 scale (always 1.0, clamped to [0.5, 1.0] by the constants at 0x1800d9844 and 0x1800d877c)
+0x128..+0x15c 14-float grade vector

Network input, 16 channels per pixel (same layout in both versions)

Built by the pre-block parameter setup (310.9.16 FUN_1800834b0, called via FUN_1800620c0 → FUN_180083ee0; pre-block PTX in the fatbin at 0x10e6d0, ~l.130-610 of the PTX):

Channel Content
0-2 Gaussian noise (Box-Muller), seeded every frame from x, y and a frame counter: part of the "detail" is sampled
3 1.0
4-6 colour, encoded (c − 0.5) · 0.125
7-9 warped history (previous network output, Catmull-Rom)
10 Style / 128
11 Tone × ControlMask.g
12 AutoMask on: 1.0; off: structure × ControlMask.b
13 skin structure (AutoMask on), else −1
14 structure (AutoMask on), else −1
15 0

Pre-block kernel parameters (272 bytes in 310.9.16, 264 in 310.8):

Offset Content
+0 Color
+8 previous output
+16 MVec
+24 Depth (always 0)
+32 ControlMask
+40 MaskBlendMode (310.9.16)
+164 / +168 MVecScale ÷ MVec size
+172 DepthInverted
+176 Tone
+180 Structure
+184 Style/128
+188 / +192 effective skin / structure
+196 15
+200 registry +0x21
+204 0.0625
+208 frame counter

The network output is a residual: x = enc(Color) + k·net, decoded as clamp(x·8 + 0.5, 0, 1), then blended with the warped history by a learned sigmoid weight (post-block PTX, ~l.13895-14125).

The final blend has two paths:

5. Hidden and debug switches (complete list)

Switch Where Effect
env __NGX_LOG_LEVEL; registry LogLevel, EnableConsoleLogging (HKLM\SOFTWARE\NVIDIA Corporation\Global\NGXCore) both (310.9.16 l.11377-11394) log level = max(registry, env, Init level). With 0, nothing is logged. Logging writes two lines per evaluation
env __NGX_ENABLE_OVERRIDE_LOG_PATH + __NGX_LOG_PATH_OVERRIDE; registry EnableLogPathOverride + LogPath both (l.5971-5991) log folder; files nvngx_dlssnr_<version>.log
registry ShowDlssIndicator = 0x400 310.9.16 FUN_18006ac20 (l.81091-81131), drawn by FUN_18001c120 overlay "DLSSNR v.. (default) on/off · W x H · active/alloc · weights: "
registry ShowDlssWeights (non-zero) 310.9.16 only the "weights: " line; crazy cuckoo is shown as almond-eagle-11m
env __NGX_SHOW_INDICATOR, __NGX_CUBIN_DISABLE_RESOURCE_CACHE; registry NgxCubinDisableResourceCache both (l.81120-81125) indicator; kernel cache
export NVSDK_NGX_SetRuntimeParamsCallback both 310.8: NGXCG2R::PollRuntimeParams (FUN_18001ac30), called from EvaluateFeature (FUN_180018620, l.19254 of the 310.8 export) after the parser, queries the callback with feature 0x12 and 8 entries of 24 bytes {1, 2, id, present, double value}. Ids: 0 Enabled → +0x108, 1 Tone → +0xe4, 2 Structure → +0xe8, 3 Intensity → +0xe0, 4 Style → +0xec, 5 AutoMask → +0xf0, 6 Skin/1000 → +0xf4, 7 scale/1000 → +0x120 (divisor 1000.0 at 0x1800afc30). The NGX core in the game never set it (logged: "callback is NULL (core did not set it)"). The scale override does nothing: the network size is hard-wired to the output size (local_5d8 = 1.0). 310.9.16: the pointer is stored at 0x1804a0a80 and never read.
weight files on disk, config files, forced presets, debug views, alternative kernels none in either version weights only come from the embedded resources

6. Runtime-side reduced resolution and guided upsample (dead code)

310.9.16 contains a complete reduced-resolution path (local_816, l.19225-19268 and 19819-19923):

It is unreachable. P+0x124 is only written at parser initialisation (1.0, l.20203, disassembly 0x18001a12e) and clamped, so P+0x120 is always 0. DLSSNR.ScalingRatio is only written by the callback (l.14441) and never read. 310.8 ships the same transferTile code but also hard-wires the network size.

7. GPU architecture and precision

310.8 310.9.16
Arch accepted by CreateFeature 0x190 (Ada) and 0x1B0 (Blackwell) 0x1B0 only (error "Unsupported GPU architecture 0x%x, minimum required 0x%x")
SASS / PTX shipped sm_89 + sm_120 / sm_120 sm_120 / sm_120
Kernel precision FP8 used (FP16 present, unused) FP8 only
Kernel families Swin "tinlayout" fused blocks, split Swin 16-head 512 ch, ViT (2-D and 1-D token) 1024 ch, decoder upsample, CG2R post-process and copy same, plus cc_vit_1d_* / mma-token1d-* / splitk-f16-* for the small model

8. Key functions (Ghidra names, image base 0x180000000)

Role 310.9.16 310.8
NGXCG2R::CreateFeature (reads Width/Height/Preset, arch check) FUN_180017b20 FUN_180017e20
NGXCG2R::EvaluateFeature FUN_180018250 FUN_180018620
Evaluate parameter parser FUN_18001a020 FUN_180019f30
Reset temporal history on control change FUN_1800176c0
Create previous-output texture FUN_1800173b0
CG2RNetworkManager::CreateNetwork / ResolvePresetToDescriptor FUN_180021000
CG2RNetworkManager::Evaluate FUN_180021df0
CG2RFindWeightByPreset (fallback preset 2 / 1) FUN_180023c20 FUN_180023a40
Weight registry lookup by name FUN_180023b80 FUN_1800239a0
CG2RLoadWeightBlob (FindResourceA type 10) FUN_180023ca0 FUN_180023ac0
Descriptor list builder FUN_1800602e0 FUN_18003d670
Backbone/template builder FUN_18005c5a0 FUN_180039780
Convert to FP8 kernels FUN_1800572f0 FUN_180032e20
Style grade lookup / write FUN_18001d8a0 / FUN_18001d6d0
Fused blend mode select FUN_18001d2e0
Post-process dispatch FUN_18001ca00
Pre-block parameters FUN_1800834b0
Indicator text / registry read FUN_18001c120 / FUN_18006ac20
ComputeScalingRatio callback FUN_180012740 FUN_180012e80
PollRuntimeParams (removed) FUN_18001ac30
Log sink / log init FUN_18000df60 / the function around l.11290
Weight registry table 0x1800dbe30, 2 × 0x290 0x1800b0d80, 1 × 0x288

Useful constants (310.9.16):

Address Value
0x1800d9844 0.5
0x1800d877c 1.0
0x1800d9848 0.85
0x1800dad8c 0.9999
0x1800dad98 −1.0

Appendix A: 310.9.16 parameter trace (line numbers = full decompile export)

Line numbers refer to the full 310.9.16 decompile export unless noted. "PTX" = cg2r_post_process_kernel (fatbin at file offset 0x47d340); "pre/post PTX" = the fused pre/post-block kernels (fatbin at file offset 0x10e6d0); PTX line numbers count from the start of that PTX text. CERTAIN = seen in code/data; LIKELY = inferred.

Corrections

Q1 Style

Q2 Strengths

Pre-block params (FUN_1800834b0, 272 B): 0 Color; 8 previous network output (history); 16 MVec; 24 Depth = always 0 (literal, l.26416); 32 ControlMask; 40 MaskBlendMode; 164/168 MVecScale / MVec size; 172 DepthInverted; 176 LocalTone (raw); 180 LocalStructure (raw); 184 Style/128; 188/192 effective skin / effective structure; 196 = 15 (registry +0x24); 200 registry +0x21; 204 0.0625; 208 frame counter (noise seed). CERTAIN.

Input channels per pixel (pre PTX l.130-610), CERTAIN: | ch | content | |---|---| | 0-2 | Gaussian noise (Box-Muller, seeded by x, y, frame) | | 3 | 1.0 | | 4-6 | colour, encoded (c-0.5)0.125 | | 7-9 | history: Catmull-Rom at uv + mvscale/size; copy of colour if no MVec / no valid history / Reset | | 10 | Style/128 | | 11 | Tone x mask.g | | 12 | AutoMask on: 1.0; off: structure x mask.b | | 13 | skin (or structure if skin < 0); -1 when AutoMask off | | 14 | structure; -1 when AutoMask off | | 15 | 0 |

Q3 Working scale

Q4 Inputs

Q5 Hidden switches

Q6 Preset 1 in FP8

Appendix B: what OptiScaler-NR v0.3.8 does not send, and what the tests showed

Parameter Result
Preset 1 on 310.9.16 the old model inside the new runtime: the same picture as 310.8, about 3 % faster than 310.8, about 70 % more GPU time than preset 2
ControlMask + MaskBlendMode works exactly as traced; see controlmask.html
Tone / Structure / Skin above 2 unclamped network inputs; Structure 4 breaks the small model's picture (+60 brightness, heavy flicker)
Style 0 removes the built-in grade: visibly more colour and contrast than Style 1
Depth, DepthInverted, BidirectionalDistortionField, ScalingRatio, Intensity > 1 no effect in either version