Water/NiagaraFluids: Grid2D_SW_ComputeBottomContour comes out inverted on NVIDIA D3D12 drivers 610.88+, so shallow-water sims stay dry (driver miscompile, workaround inside)

Summary

On current NVIDIA drivers under D3D12, the NiagaraFluids ShallowWater module Grid2D_SW_ComputeBottomContour (used by WaterAdvanced Grid2D_SW_River) produces an inverted bottom contour, so the shallow-water simulation never holds water. This is an NVIDIA shader-compiler bug, not an error in Epic’s math, but it affects every project using these systems on D3D12 with NVIDIA driver 610.88 or newer. Reported to NVIDIA as NVIDIA Developer bug 6942488.

  • The module’s TopDown arm computes Z - depth, where depth = inBounds ? sampledDepth : 0.
  • DXC (SM 6.6, -O3, fast-math) lowers this to fsub fast -0.0, sample → select(inBounds, -sample, -0.0) → fadd fast (Z - L), sel.
  • The NVIDIA D3D12 driver drops the negation of the fetched value, so the contour becomes Z + depth (about +30000 cm instead of about -15 cm in our scene). Every cell reads as ground far above the water and the solver zeroes it.
  • Affected: Windows, D3D12, NVIDIA RTX 5080, drivers 610.88 (32.0.16.1088) and 617.42 (32.0.16.1742, latest). Not affected: driver 591.86 on D3D12, Vulkan on the same PC and driver, and Linux/Vulkan (RTX 3080, 595.91).
  • A standalone D3D12 app with no Unreal code reproduces the miscompile on the NVIDIA GPU and gives correct results on WARP.

What Type of Bug are you experiencing?

Rendering (Graphics / Niagara)

Steps to Reproduce

  1. Windows, D3D12 RHI (default), NVIDIA GPU with driver 610.88 or newer (tested: RTX 5080 on 617.42).
  2. Play the stock WaterAdvanced Grid2D_SW_River Niagara system over terrain (or any system using Grid2D_SW_ComputeBottomContour).
  3. Watch the simulation grid: it never gets water. Reading back the solver grid, dry cells hold a contour of about +30000 (captureZ + depth) instead of the terrain height.
  4. Run the same content with -vulkan, or on driver 591.86: the simulation fills normally.

Expected Result

The shallow-water simulation holds water; the bottom contour of dry cells equals the terrain height (captureZ - depth).

Observed Result

The simulation never holds water on NVIDIA 610.88 and 617.42 under D3D12. The bottom contour equals captureZ + depth (about 30 m above the terrain in our scene), so every cell is zeroed. Vulkan on the same machine and driver is correct.

Affects Versions

5.7

Platform(s)

Windows

Additional Notes

Workaround (one line, in a copy of the module so engine content stays untouched): in the TopDown arm of Grid2D_SW_ComputeBottomContour, replace Z - depth with -(depth - Z). It is bit-identical in IEEE arithmetic and makes DXC emit a select without the negation, which the driver handles correctly. Note that Z + (-depth) does not help, because DXC folds it back to the failing form. Verified on 617.42 in our UE 5.7 project: contour back to terrain values, lakes and rivers wet, packaged build too.

Failing DXIL:
%39 = fsub fast float -0.000000e+00, %36 ; -d (from sampleLevel/textureLoad)
%40 = select i1 %32, float %39, float -0.000000e+00 ; inBounds ? -d : -0.0
%41 = fadd fast float %40, %37 ; Z + sel
Working DXIL (after the rewrite):
%37 = select i1 %32, float %36, float 0.000000e+00 ; inBounds ? d : 0
%41 = fsub fast float %38, %40 ; Z - (L + sel)

Not verified: a clean repro in an empty Epic project (we drove the stock Grid2D_SW_River through our own harness), and behaviour on other GPUs or driver branches. Unreal Engine 5.7.4, Windows 11 26300.9711. The standalone D3D12 repro and full DXIL listings are available on request; they were sent to NVIDIA with bug 6942488.