Any Slate widget that triggers the Slate post-process blur (e.g. a UBackgroundBlur with non-zero strength) hits a fatal D3D12 CreateGraphicsPipelineState failure on first render. The fatal is funneled through PipelineStateCache.cpp:707 (“Shader compilation failures are Fatal”), but the underlying error is E_INVALIDARG (0x80070057) from a VS/PS signature linkage mismatch — not an HLSL compile error.
Root cause
Engine/Shaders/Private/ScreenPass.usf defines ScreenPassVS with FStereoVSOutput StereoOutput. With Instanced Stereo enabled, that expands into VIEW_ID + SV_ViewportArrayIndex outputs at register 1, pushing SV_Position to register 2.
The Slate post-process PS entry points in Engine/Shaders/Private/SlatePostProcessPixelShader.usf were not updated for the stereo contract — they declare only TEXCOORD0 as input, no FStereoPSInput. Affected entry points:
GaussianBlurMain (line 37) — the one that crashes via UBackgroundBlur
OptimizedKawaseUpsampleMain (line 70)
Resample1Main (line 83)
Resample2x2Main (line 89)
Likely ColorDeficiencyMain and the multi-target entry around line 122
The call site is AddSlatePostProcessOldGaussianBlur in Engine/Source/Runtime/SlateRHIRenderer/Private/SlatePostProcessor.cpp:657, which pairs FSlatePostProcessBlurPS with ScreenPassVS via AddDrawScreenPass. The VS↔PS contract assumed by AddDrawScreenPass is exactly what CopyRectPS in ScreenPass.usf honors (it declares FStereoPSInput StereoInput) — the Slate post-process PSes do not.
Proposed fix
One-line patch per entry point in SlatePostProcessPixelShader.usf — add in FStereoPSInput StereoInput to the signature. The function bodies do not need to reference it; the linker just needs the parameter to consume the matching interpolants.
float4 GaussianBlurMain(
in noperspective float4 InUVAndScreenPos : TEXCOORD0,
in FStereoPSInput StereoInput
) : SV_Target0
CopyRectPS is the working model.
Diagnostic steps performed
- Captured the fatal in a Development PCD3D_SM6 cooked build; initial RHI log named the shaders as <unknown> (no symbol info in cooked output).
- Re-launched with -d3ddebug — D3D12 debug layer surfaced the SV_Position mismatched hardware registers error.
- Confirmed it is not a PSO-precache wiring issue: r.PSOPrecaching=0 and r.PSOPrecache.Validation=0 did not change the crash, ruling out the precacher.
- Reproduced in the editor with shader debug info enabled (r.DumpShaderDebugInfo=1, r.DumpShaderDebugShortNames=1, r.Shaders.SymbolsInfo=1, r.Shaders.ExtraData=1 under [Startup] in ConsoleVariables.ini).
- Inspected Saved/ShaderDebugInfo/PCD3D_SM6/Global/ScreenPassVS/0/Output.d3dasm and …/SlatePostBlurPS/0/Output.d3dasm.
VS output signature:
TEXCOORD 0 reg 0
VIEW_ID 0 reg 1
SV_ViewportArrayIndex 0 reg 1
SV_Position 0 reg 2
PS input signature:
TEXCOORD 0 reg 0
Register layouts diverge → D3D12 linkage rejection matches the debug-layer error verbatim.
Walked the engine sources for the call site (SlatePostProcessor.cpp:657 and :817) and the VS HLSL (ScreenPass.usf:12) to confirm the contract mismatch in the source rather than in a cache artifact.
We are temporarily gating UBackgroundBlur usage on engine version until this lands. Disabling Instanced Stereo also avoids the crash but is not viable for our VR project.