Potential GPU Crash in Nanite voxel brick rasterizer: out-of-bounds groupshared read in MicropolyRasterize (NaniteRasterizer.usf) → GPU DEVICE_HUNG (LDS 0xD74)

[Root cause] NaniteRasterizer.usf, BRICK_TRACE_WORK_REDISTRIBUTION path in
MicropolyRasterize.

Groupshared declarations:
  groupshared uint  GroupWorkEnd[32];
  groupshared uint3 GroupBrickData[32];
  groupshared uint  GroupSourceLaneAndPixelPos[64];

Inside the per-32-pixel work-redistribution loop:
  const uint MarkBufferValue = GroupWorkEnd[ GroupThreadIndex ]; // unmarked = 0xFFFFFFFF
  const uint BrickStartMask  = WaveBallot( MarkBufferValue != 0xFFFFFFFFu ).x;
  const int  BrickStartIndex = firstbitlow( BrickStartMask & LaneMask );
  const uint BrickLaneData   = WaveReadLaneAt( MarkBufferValue, BrickStartIndex );
  const uint BrickLane       = BrickLaneData & 0xFFu;
  const uint3 BrickData      = GroupBrickData[ BrickLane ];      // <-- OOB read

For the tail lanes of the final (partial) 32-pixel chunk, no end-mark exists at or
after the lane, so:
  - BrickStartMask & LaneMask == 0  -> firstbitlow(0) == -1
  - WaveReadLaneAt(x, -1) is undefined; on NVIDIA the shuffle index is masked (& 31)
    -> reads lane 31, which is unmarked (0xFFFFFFFF)
  - BrickLane = 0xFF = 255
  - GroupBrickData[255] indexes a 32-element array -> LDS out-of-bounds.
    Byte offset = 384 + 255*12 = 3444 = 0xD74, exactly the Aftermath fault address.

BrickData is only *used* under `if (bActive)` (bActive = PixelIndex < TotalPixels),
which is false for exactly these tail lanes, so the read value is dead. In normal
execution the OOB LDS read is silently tolerated; under Aftermath / GPU-crash-
debugging bounds checking (and/or on Blackwell) it becomes a hard out-of-range fault
and hangs the device.

The sibling unpack site in ProcessBrickPixelBatchFromQueue already masks the same
lane value with `& 31u`; the read in the redistribution loop is missing the guard.

[Suggested fix]
  const uint3 BrickData = GroupBrickData[ BrickLane & 31u ];
or skip lanes where (BrickStartMask & LaneMask) == 0. Behavior-preserving: such lanes
always fail the following bActive test.

[Attachment Removed]

重现步骤

Environment:
- UE 5.8.0 (GitHub source, release branch, CL ab58c879a25b / 5.8.0-0+UE5)
- D3D12, SM6, Nanite enabled, r.Nanite.Foliage=1
- GPU: NVIDIA RTX 5060 Ti (Blackwell); seen on drivers 591.86 and 610.62(but should happen on every NVIDIA cards regardless of driver versions)
- Editor launched with: -nvaftermathall -gpucrashdebugging

Steps:
1. Open a scene containing Nanite foliage that exercises the Nanite voxel (brick)
   rasterizer (breadcrumb path Nanite::VisBuffer > DrawGeometry > PatchSplit).
2. Launch with -gpucrashdebugging -nvaftermathall so GPU-side bounds checking traps
   the out-of-range access.
3. Render the foliage in the viewport / PIE. The GPU hangs within seconds to minutes.

Result: DXGI_ERROR_DEVICE_HUNG, deterministic (identical fault address every time).

On the clean-repro requirement: the defect is entirely inside stock engine shader
code (Engine/Shaders/Private/Nanite/NaniteRasterizer.usf); no third-party plugins or
project content are involved, and the code can be verified directly in your 5.8
source. The source-level OOB read exists regardless of GPU/driver -- GPU crash
debugging / Blackwell is only what turns the silent OOB into a hard fault. We can
provide the exact foliage asset + GPU dump on request.

[Attachment Removed]

Hi, thanks for calling this out. We have encountered this crash ourselves and shipped a patch for this issue in 5.8.1. If you don’t plan to get the hotfix, you can still grab CL 55449171 and apply it to your own build. I hope that helps, but please let me know if you have any further questions.

[Attachment Removed]

No worries! If anything, it gives others an opportunity to find a solution to this bug on our forums now, so it’s still good that you reached out. I’ll close out this ticket then, since I assume everything is resolved.

[Attachment Removed]

Hi, thanks for the reply. The patch helps a lot!

I figured out the bug several weeks ago and fixed it in our own build, but my eps account expired then so I uploaded this bug until today when the account restored but I forgot to check the github log, apologies​:joy:

Thanks again!

[Attachment Removed]