Crash on AMD RX 580: push constants exceed the 128-byte maxPushConstantsSize limit #238

Closed
opened 2026-10-02 06:14:01 +00:00 by sky_line · 2 comments
Owner

Problem

Crashes on AMD RX 580 (Polaris / GCN4). On that hardware/driver VkPhysicalDeviceLimits::maxPushConstantsSize is 128 bytes (the Vulkan spec minimum; NVIDIA and RADV expose 256). Several of our pipeline layouts declare push-constant ranges larger than 128 B, so pipeline-layout creation / draws are invalid and the driver crashes.

Offending push blocks (vulkan-port-tb, 2026-10-02)

Struct Size Used by
VKDrawPush (vkgfx/llcleanrenderervk.h) 240 B every world draw (opaque / mask / rigged / alpha / water / particles / probes / mirror / shadows), VS+FS
VKCullPush (llcleanrenderervk.h) 200 B clean_cull.comp (main / HUD / mirror / probe / shadow culls); grew with the probe shared-cull work (probeperf2)
TAAPush (llcleanrenderervk.cpp ~9608) 192 B clean_taa.comp (grew with params2 for the native anti-flicker lock + glow resolve)

Everything else is <= 128 B already (RtMaskPushData, AOPush, god-ray TempPush, RtDebugPush are exactly 128 -- keep them there).

vk_descpool.cpp:268 already compares the push range against maxPushConstantsSize when creating layouts, but only reports; it doesn't prevent the crash.

Fix

  • Standard approach: keep push constants <= 128 B and move the rest to a per-pass / per-view UBO or SSBO (or the existing frame-info buffer), indexed by a small push (view index / pass id).
    • VKDrawPush: view_proj + camera + sun + misc per view -> a per-view UBO array (main, mirror, probe faces, cascades, projector tiles) indexed by a push uint view_id + a few per-draw-set words. Most of the 240 B is constant for a whole pass.
    • VKCullPush: same -- per-cull parameters into a small cull-params buffer slot per dispatch (we already record many culls per frame: main, HUD, mirror, 6 probe faces, cascades).
    • TAAPush: move reproj / water plane / params into a TAA UBO.
  • Add a hard startup check: if any layout exceeds maxPushConstantsSize, log a clear error instead of crashing (and/or fall back to the UBO path everywhere -- preferred: single path for all hardware, no 256 B assumption).
  • Add static_assert(sizeof(X) <= 128) on every push struct so this can't regress.

Notes

  • Related to broader hardware support (feature-tiered, not lowest-common-denominator): this one is a hard limit, so the UBO path should simply be the only path.
  • Test on Polaris (RX 470/480/570/580) with the AMD Windows driver and on RADV; check vulkaninfo | grep maxPushConstantsSize.
## Problem Crashes on AMD RX 580 (Polaris / GCN4). On that hardware/driver `VkPhysicalDeviceLimits::maxPushConstantsSize` is **128 bytes** (the Vulkan spec minimum; NVIDIA and RADV expose 256). Several of our pipeline layouts declare push-constant ranges larger than 128 B, so pipeline-layout creation / draws are invalid and the driver crashes. ## Offending push blocks (vulkan-port-tb, 2026-10-02) | Struct | Size | Used by | |---|---|---| | `VKDrawPush` (`vkgfx/llcleanrenderervk.h`) | **240 B** | every world draw (opaque / mask / rigged / alpha / water / particles / probes / mirror / shadows), VS+FS | | `VKCullPush` (`llcleanrenderervk.h`) | **200 B** | `clean_cull.comp` (main / HUD / mirror / probe / shadow culls); grew with the probe shared-cull work (probeperf2) | | `TAAPush` (`llcleanrenderervk.cpp` ~9608) | **192 B** | `clean_taa.comp` (grew with `params2` for the native anti-flicker lock + glow resolve) | Everything else is <= 128 B already (`RtMaskPushData`, `AOPush`, god-ray `TempPush`, `RtDebugPush` are exactly 128 -- keep them there). `vk_descpool.cpp:268` already compares the push range against `maxPushConstantsSize` when creating layouts, but only reports; it doesn't prevent the crash. ## Fix - Standard approach: keep push constants <= 128 B and move the rest to a **per-pass / per-view UBO or SSBO** (or the existing frame-info buffer), indexed by a small push (view index / pass id). - `VKDrawPush`: view_proj + camera + sun + misc per *view* -> a per-view UBO array (main, mirror, probe faces, cascades, projector tiles) indexed by a push `uint view_id` + a few per-draw-set words. Most of the 240 B is constant for a whole pass. - `VKCullPush`: same -- per-cull parameters into a small cull-params buffer slot per dispatch (we already record many culls per frame: main, HUD, mirror, 6 probe faces, cascades). - `TAAPush`: move reproj / water plane / params into a TAA UBO. - Add a hard startup check: if any layout exceeds `maxPushConstantsSize`, log a clear error instead of crashing (and/or fall back to the UBO path everywhere -- preferred: single path for all hardware, no 256 B assumption). - Add `static_assert(sizeof(X) <= 128)` on every push struct so this can't regress. ## Notes - Related to broader hardware support (feature-tiered, not lowest-common-denominator): this one is a hard limit, so the UBO path should simply be the only path. - Test on Polaris (RX 470/480/570/580) with the AMD Windows driver and on RADV; check `vulkaninfo | grep maxPushConstantsSize`.
Author
Owner

Status check (verification sweep): the push-constant fix shipped in v1.0.0-beta.1:

  • per-view draw / cull / TAA params moved out of push constants, so every push block is <= 128 B (4a8ae7dc10);
  • budget guards, a startup limit log and static_asserts (797b423808);
  • the regen scripts fail on any block over 128 B (bd3a959ec0);
  • further Polaris / GCN fixes: 32 KiB alpha-sort variant, probe capture split, bounds checks, blend-header race, bloom target layouts (b20960b291, c4f608c616, 1e2875a7fb, 513e03fcdd, 194d10542e).

Still outstanding: confirmation on real RX 470/480/570/580 hardware (AMD Windows driver and/or RADV) that the viewer runs. Close once a tester confirms.

Status check (verification sweep): the push-constant fix shipped in v1.0.0-beta.1: - per-view draw / cull / TAA params moved out of push constants, so every push block is <= 128 B (4a8ae7dc10); - budget guards, a startup limit log and static_asserts (797b423808); - the regen scripts fail on any block over 128 B (bd3a959ec0); - further Polaris / GCN fixes: 32 KiB alpha-sort variant, probe capture split, bounds checks, blend-header race, bloom target layouts (b20960b291, c4f608c616, 1e2875a7fb, 513e03fcdd, 194d10542e). Still outstanding: confirmation on real RX 470/480/570/580 hardware (AMD Windows driver and/or RADV) that the viewer runs. Close once a tester confirms.
Author
Owner

Confirmed fixed on real hardware: the RX 580 (Polaris) reporter confirms Slipstream now runs on their machine. Fix: push blocks capped at 128 B with static_asserts (4a8ae7dc10, 797b423808, bd3a959ec0) plus the Polaris fallbacks (32 KiB shared-memory alpha sort variant, probe capture split, metadata bounds). Shipped in the 1.0.0 betas.

Confirmed fixed on real hardware: the RX 580 (Polaris) reporter confirms Slipstream now runs on their machine. Fix: push blocks capped at 128 B with static_asserts (4a8ae7dc10, 797b423808, bd3a959ec0) plus the Polaris fallbacks (32 KiB shared-memory alpha sort variant, probe capture split, metadata bounds). Shipped in the 1.0.0 betas.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
sky_line/Slipstream#238
No description provided.