Skip to content

Releases: Rayz0rum/OptiScalerVFI

OptiNR + Test Build 1.5

Pre-release

Choose a tag to compare

@Rayz0rum Rayz0rum released this 31 Aug 15:20

DLSS 5 Neural Rendering for OptiScaler — a detail-synthesis pass that runs on the upscaler's output, before the interface is drawn.

The D3D12 core is Dagherbou's, from OptiScaler_DLSSNR (dlssnr-pr), and it is unchanged here. Everything else in this list is built on top of it.

Install

Extract into the game folder, run setup_windows.bat, then supply nvngx_dlssnr.dll yourself — NVIDIA's model, ~165 MB, from a driver package. It is not ours to redistribute.

Two files, one character apart:

| | |
| nvngx_dlssnr.dll | NVIDIA's model. You supply this in the OptiScaler folder on the game folder root. |
| nvngx.dll_dlssnr.dll | The forwarder, 110 KB. Included. Game folder root, beside OptiScaler.dll. |

The forwarder exists because the model resolves whichever module owns its caller's return address and refuses any whose path does not contain nvngx.dll. Nothing named OptiScaler gets through, so every call is made from that file instead.

New

Vulkan backend. Native, not bridged. The snippet exports a complete Vulkan surface and the model runs on it. The colour codec is not copied for it — build_vk_shader.pl extracts the same HLSL the D3D paths compile at runtime and compiles it ahead of time, so all three backends share one shader source.

Four placements, selectable in the overlay:

  • Post-process — the model on the finished frame. The default, unchanged, and the only one that works with a game's native DLSS passing straight through.
  • Upscale with DLSS-SR — the model at render resolution, Super Resolution enlarging its result, so the upscaler's temporal accumulation works on enhanced pixels.
  • Multi-pass Rendering — a 1:1 first pass, the model, then a second Super Resolution feature for the single enlargement.
  • Multi-pass Rendering (Custom) — the first pass held below render resolution, its inputs resampled to match. A performance control, not a quality one.

Multi-pass edit transfer. Chaining two temporal passes cannot preserve jitter for the second one: the first pass resolves it, which is what DLAA and Ray Reconstruction are for. So the model's edit is measured on the resolved frame as a brightness ratio and applied to the game's original jittered frame, which still carries its subpixel sampling. The enlargement then gets properly jittered input with the model's work riding on it.

Highlight colour guard. The encode normalises luminance but not individual channels, so a bright saturated pixel keeps a channel above 1.0 in the picture the model is shown — outside its trained range. It returns near-white, and the highlight branch faithfully carries that whiteness up to full brightness, turning neon lights white. The guard acts only on pixels that actually left the model's range, so the model's colour work is kept everywhere else. This is about the game's frame buffer, not your monitor: it fires wherever a game renders in linear HDR, which many do while tone-mapping to SDR at the end.

Fixed

  • The upscaler feature is rebuilt when the placement changes. The target resolution and the HDR/exposure flags latch at creation and nothing else noticed, so the pipeline routed output into a render-resolution buffer while the feature still wrote display resolution — FAIL_InvalidParameter, every frame.
  • No longer asks virtual functions of a half-constructed feature. SetInitParameters runs from a constructor, where Api() and GetUpscalerType() are still pure virtual; calling them aborted the process with "pure virtual function being called".
  • The second upscaler forwards the game's declared motion vector resolution instead of assuming render-resolution. Assuming it made DLSS read a display-sized vector field as render-sized and smear the whole frame radially on camera movement.
  • The reordered placements work on the render rect, not the whole colour allocation. A game commonly allocates that buffer at display size and renders into a corner of it; the rest is memory nobody wrote.
  • Those placements also render into a buffer of their own rather than the game's colour buffer, which a game does not generally create with unordered access.
  • Non-finite values are bounded in the colour codec. A sun arrives as infinity in an open-ended linear buffer, and the normalisation then computes Inf × 0.
  • Multi-pass Custom resamples the first pass's inputs instead of letting DLSS crop the corner of each. Depth is point-sampled — a filtered depth tap that straddles a silhouette returns a distance where no surface is.

Known limits

  • Native D3D11 does not work. The snippet's own D3D11 init returns FAIL_FeatureNotSupported — it declining the API. On a D3D11 game, set Dx11Upscaler to a _12 option and the D3D11-on-D3D12 bridge carries the pass.
  • NVIDIA RTX only. The model is an NGX snippet.
  • Anything but post-process needs OptiScaler's own upscaler to be DLSS or Ray Reconstruction; otherwise it falls back and logs why.
  • Multi-pass with Ray Reconstruction: the edit transfer is available but a brightness ratio cannot carry a denoise, so watch for path-trace noise returning. Unmeasured.

Unverified

Said plainly, because a test build should not overstate itself. The Vulkan backend, all four placements, the edit transfer and the colour guard have had very little time on real hardware. They build, and the reasoning behind each is in the source, but that is a different claim from working. MultiPassAlign in particular has 1, -1 and 0 because the jitter sign convention differs by engine and the wrong one doubles the error it exists to remove — if 1 looks worse than 0, the answer is -1.

Attribution

The colour composition — the two-branch luminance ratio, the OkLab hue correction, and the blend between a luminance-only result and the model's own colour — is taken from RenoDX's DLSS 5 addon by clshortfuse. It is their design. See Licenses/RenoDX_ATTRIBUTION.txt.

The D3D12 module, the forwarder and the colour codec are Dagherbou's.

Neural Rendering is undocumented and driven directly through its snippet. None of it is supported by NVIDIA.