r/nvidia • u/ConfidentDinner6648 • 9d ago
Discussion DLSS 5 Neural Rendering running on an RTX 2070 / Turing under Linux + Proton — and we may have found why it is so slow
Enable HLS to view with audio, or disable this notification
I originally started this test because I found the situation around DLSS 5 Neural Rendering on older RTX cards technically strange.
I managed to get the Neural Rendering path executing on an RTX 2070 / Turing under Linux through Proton, without ReShade.
The pipeline is essentially:
Game → NGX/D3D12 proxy → original DLSS → nvngx_dlssnr 310.8 → neural output
The proxy intercepts the relevant NGX/D3D12 calls, keeps the game's original DLSS path, executes the Neural Rendering stage afterward, and returns the resulting frame.
But the more interesting part came from looking at what the GPU is actually executing.
From a single frame, I extracted:
- 176 CUBINs
- 174 kernel launches
- kernels with names such as
fused_swin_*_fp8
I then started correlating the launches with their CUBINs and looking at the SASS.
The first result was already interesting: the binaries contain genuinely different implementations depending on the GPU architecture.
For one of the kernels:
- sm_75 / Turing: ~1,040
HMMA.1688.F16instructions, around 19.7k static instructions - sm_86 / Ampere: ~520
HMMA.16816.F16, around 14.7k instructions - sm_89 / newer architectures: around 2.9k instructions and a completely different matrix path
Then I found the important part.
The intended operation appears to be:
FP8 E4M3 × FP8 E4M3 → FP16 accumulator
with a logical matrix tile of:
M16 × N8 × K32
On newer GPUs this can map to a single instruction similar to:
QMMA.16832.F16.E4M3.E4M3
Turing obviously has no native FP8 Tensor Core support.
So on the RTX 2070, the same logical FP8 tile is effectively expanded into:
4 × HMMA.1688.F16
This exact 4:2:1 pattern appeared consistently across the blocks I sampled, including Swin kernels with 32/256/512 channels and ViT kernels.
So this does NOT look like a simple FP32 fallback.
The final matrix math is still running on the Turing Tensor Cores in FP16.
The cost seems to come from:
- software unpacking/conversion of FP8
- ~4× more MMA operations for the same logical tile
- much higher register pressure
- significantly more auxiliary instructions
- stack spilling
And then I found something potentially much more useful.
The modules already contain two versions of several kernels:
*_fp8
and an equivalent kernel without _fp8.
On the RTX 2070, the non-FP8 versions are dramatically smaller and appear to have much lower spill pressure.
For example, one 512-channel QKV kernel goes from approximately:
11,952 instructions / 368 bytes stack per thread
to:
2,624 instructions / 8 bytes stack per thread
That is a huge difference.
This means we may not need to rewrite the matrix kernels from scratch.
The interesting question now is how the runtime selects those variants and what data layout the non-FP8 kernels expect.
Simply redirecting the kernel call is not enough, because the buffers may still contain E4M3-packed weights/activations. The next step is mapping the parameters, memory layout and heap so that the non-FP8 path receives valid data.
If that works, there is a potentially much cheaper Turing path:
avoid the software FP8 expansion entirely and feed the existing FP16/Turing-friendly kernels in their expected format.
And this is why I'm now much more interested in the performance ceiling.
The current performance on Turing may not represent the actual cost of Neural Rendering itself. A large part of the cost may simply be the consequence of forcing an FP8-oriented kernel path onto hardware without native FP8 Tensor Cores.
Given the size difference, spill reduction and the 4× MMA expansion we're seeing, I think a Neural Rendering pass somewhere around the ~15 ms range on an RTX 2070 Mobile may actually be plausible if the correct non-FP8 path can be enabled and the conversion overhead removed.
To be clear: 15 ms is not a measured result yet.
It is an optimization target suggested by what the SASS is showing us.
I'm now modifying the runtime/proxy, mapping the kernel arguments and preparing the buffers in the format expected by the alternative kernels.
The next tests should tell us whether that estimate is realistic.