GPU compositor can't start on DirectX 12 (FXC fails on the pointwise kernel) #613
Copy link
Copy link
Open
Description
What happens
On Windows, when egui-wgpu's device is DirectX 12, GpuContext::new fails while building the compute pipelines. The app then quietly composites on the CPU. session.accel_note reads:
GPU compositor unavailable: GPU initialization (pointwise): Validation Error
In Device::create_compute_pipeline, label = 'pointwise'
Internal error: FXC D3DCompile error (Unspecified error (0x80004005)):
…effectcraft kernels(69,12-24): warning X3571: pow(f, e) will not work for negative f, …
internal error: compilation aborted unexpectedly
Where seen
- Windows 11, EffectCraft
mainat 1446e27 (10 October 2026), on a laptop with an RTX 4060 Laptop GPU. - First seen on WARP (Microsoft Basic Render Driver) on DirectX 12. That is what egui_kittest picks in
ui_gpu. - Reproduced in the desktop app by starting it with
WGPU_BACKEND=dx12.render.backendthen reports"active": "cpu"and the error above aswhy. - Started normally, the same build picks Vulkan (
NVIDIA GeForce RTX 4060 Laptop GPU (Vulkan)) and the GPU compositor works. - So any setup where the window's device lands on DirectX 12 should hit it, for example a machine without a working Vulkan driver.
Why
FXC (the legacy D3D shader compiler wgpu uses for DirectX 12 by default) aborts on the HLSL that naga generates for pointwise. DXC usually compiles such kernels.
Possible directions (maintainers' call)
- Select DXC for DirectX 12 in the window's
InstanceDescriptor(backend_options.dx12.shader_compiler). This needs DXC shipped or statically linked. - Prefer Vulkan over DirectX 12 for the window when both are available.
- Or find which construct in
pointwisetrips FXC and work around it there.
🤖 Generated with Claude Code
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
No labels
Activity
7n4xt commentedon Oct 10, 2026
I am experiencing the same issue, with the same RTX 4060 laptop GPU on the 0,7 version of Effectcraft
GPU: an effect kernel the shader compiler rejects no longer turns the…
bflatastic commentedon Oct 10, 2026
Thanks for the precise report, @KattKnight! #667 (on main) makes this non-fatal. An effect kernel that fails to build on a backend (here
pointwiseunder FXC on DX12) no longer switches off the whole GPU compositor. The compositor starts, and only the effects that need that kernel render on the CPU, matching the CPU output. The FXC incompatibility itself still needs bisecting on a Windows/DX12 machine, so we're keeping this open. If you can share the FXC error text from the log, that would help a lot.Generated by Claude Code
KattKnight commentedon Oct 10, 2026
Thanks! Here's the FXC text, plus a bit more from this Windows/DX12 machine, because on
mainthe compositor still doesn't start on DX12.1. On
main(d024a16, with #667), DX12 still falls back to the CPUA small probe that calls
GpuContext::request()withWGPU_BACKEND=dx12(RTX 4060 Laptop, Windows 11):pointwiseis optional now, butclassic3dis inEXT_ENTRIES, which are still required (the?on theENTRIES/EXT_ENTRIEScollect). So the build now stops there instead. WithWGPU_BACKEND=vulkanthe same build starts.2. The FXC text for
pointwiseThat's all FXC prints: the abort comes with no error code.
3. All 224 kernels through FXC: 12 fail
I compiled every compute entry point in the module the way wgpu does on DX12:
Cargo.lock) writes the HLSL for one entry point with wgpu's default options;fxc /T cs_5_1 /Ges(ENABLE_STRICTNESS, as inwgpu-hal'scompile_fxc), Windows SDK 10.0.26100.classic3dpointwisefxc_pointfxc_kl_finalfxd_pointfg2_segsfxk_pointfxl_pointfxn_median_huangfxt_pointfxv_genfxw_warpfxw_style: not all control paths return a valueTurning off naga's
force_loop_boundingandrestrict_indexingdoesn't fix any of them.All 12 compile with DXC (
dxc -T cs_6_0 -Ges, naga at shader model 6.0).4. Shipping DXC fixes it with no code change
wgpu 30's default
Dx12Compiler::Autouses DXC whenever it can loaddxcompiler.dll. I checked this on the same probe build, on DX12:dxcompiler.dll, FXC is used and the compositor fails atclassic3d(above);dxcompiler.dll(1.8.2502) next to the exe, it starts, and every kernel builds (unavailable_kernels()is empty).So either option fixes this:
dxcompiler.dllwith the Windows build. wgpu needs 1.8.2502 or newer; the redistributable is on DirectXShaderCompiler's releases;static-dxcfeature. wgpu doesn't offer it onaarch64-pc-windows, so the ARM64 build would need the DLL or FXC.5. The
pointwiseabort, bisectedIt's an FXC bug. A vector component written with a runtime index, inside a loop, inside a
switchcase, aborts the compiler. This is enough:The same loop compiles inside an
if, and so does a read (c[i]) or a write to anarray<f32, 3>. Moving the loop into a helper function doesn't help, because FXC inlines it. Inpointwise, cases 2, 4, 5 and 8 each hit it. Withoasarray<f32, 3>in those four cases (8 lines changed, same math),pointwisecompiles under FXC. The other five aborts (fxc_point,fxd_point,fxk_point,fxt_point,fxv_gen) each have the same ingredients (aswitch, loops and indexed writes), but I haven't bisected them one by one.So the options as I see them, your call:
static-dxc): fixes all 12 at once.switch+ loop ones likepointwise;classic3dand the unroll failures need their loops reworked.classic3doptional like the effect kernels, so the compositor at least starts on FXC.Happy to open a PR for whichever you prefer.
🤖 Generated with Claude Code
didpublishing commentedon Oct 10, 2026
@KattKnight thanks for the thorough write-up: the per-kernel FXC table, the DXC check and the
switch+ loop bisect make this very tractable.I'd like to help without duplicating your work, so before writing any code: are you already working on a PR for this, and if so for which option? I'm on Windows 11 with an RTX 3060, so I can run DirectX 12 with
WGPU_BACKEND=dx12and check results on a second machine.If you're not planning to, this is how I'd split the options (the first needs a maintainer decision):
dxcompiler.dllwith the Windows build (worth checking whetherdxil.dllis needed too, for validation on other machines), orstatic-dxc, which builds C++ and isn't available on aarch64-pc-windows, so it sits uneasily with the Pure Rust rule and the ARM64 build.switch+ indexed-write pattern first:pointwise(cases 2, 4, 5, 8 witharray<f32, 3>), thenfxc_point,fxd_point,fxk_point,fxt_pointandfxv_gen, bisecting each as you did, with the CPU output as the oracle for each kernel.classic3doptional, so the compositor starts on FXC even before the loop-unrolling kernels (classic3d,fg2_segs,fxl_point,fxn_median_huang) are reworked. That one probably belongs with whoever owns the required-kernel list from Fix community-reported issues: Light theme contrast, macOS Sync with System, Timeline eyedropper, DX12 kernel fallback #667.My suggestion would be 3 plus 2 for the
switchkernels as the quick win, with 1 decided separately. I won't start until I've heard from you, so we don't both open a PR. If you'd rather do it all yourself, I'm happy to review and test on DX12 here instead.GPU storytold#591 storytold#613: bound retained resources and link DX…
GPU storytold#613: restrict linked DXC to its published x64 MSVC target
GPU storytold#613: verify DXC pointwise execution as well as compilation
GPU storytold#613: document pixel-level acceptance check
didpublishing commentedon Oct 11, 2026
Confirming on a second machine, plus one thing for the DXC option. Windows 11, RTX 3060 (driver 32.0.16.1060),
mainat 21681e9 (includes #667), release build ofeffectcraft-cli,WGPU_BACKENDas shown,info --gpu(it callsGpu::try_headless()):vulkandx12, no DXCclassic3d: FXC X3550 / X3511 "forced to unroll loop, but unrolling failed", the same errors as in the comment above.pointwiseis optional since #667, so the build now stops at the first required kerneldx12,dxcompiler.dll1.9.2607 next to the exebench --gpurenders onNVIDIA GeForce RTX 3060 (Dx12)across the demo comps, including the 3D ones that useclassic3d; GPU vs CPU differs by 0.000 to 0.008% of pixelsdx12, the Windows SDK's olddxcompiler.dll1.5.0 next to the exeno device: Parent device is lostSo your DXC result reproduces here. The last row matters for the DXC option: wgpu picks up any
dxcompiler.dllit can load, and a stale one is worse than none. Without a DLL the app falls back to the CPU compositor cleanly; with an old one device creation fails outright. If DXC is shipped, the version needs to be pinned (your 1.8.2502 minimum is right, and 1.9 works), and it's worth checking what happens when an older copy is also on the DLL search path.Details and caveats: the 1.9.2607 DLL came from a Chromium-based browser installed on this machine, used only in a scratch folder to test (I'm not suggesting redistributing it). That browser ships no
dxil.dll, so that run paired it with the SDK's olddxil.dll(101.5.x), which suggestsdxil.dlldoesn't have to match, but I only tried that one combination. I tested only the CLI path, not the desktop window, and haven't touched the WGSL workarounds. Still holding off on code until I hear whether you're already on a PR.KattKnight commentedon Oct 11, 2026
@didpublishing thanks for checking it on a second machine, and for the old-
dxcompiler.dllresult: I hadn't tried a stale copy, and "worse than none" is worth knowing before anyone ships the DLL.I'm not working on a PR for this, so please go ahead with your plan: 3 (
classic3doptional) plus 2 for theswitchkernels. That sounds right to me. Option 1 is @bflatastic's packaging call.I'm happy to test your PR here on DX12 (RTX 4060 Laptop, Windows 11), in both the CLI and the desktop app with
WGPU_BACKEND=dx12, against the CPU output. Tag me when it's up.davidlilja commentedon Oct 11, 2026
One more data point from the desktop app (not the CLI), because the FXC failure on
classic3dalso makes the app look like it never starts.Setup: EffectCraft 0.8.0,
effectcraft-0.8.0-windows-x64-portable.zip(sha25602fb4491…b0d2), Windows 11 Pro 26H2 (build 26300), NVIDIA GeForce RTX 5060 Ti, driver 616.92.RUST_LOG=info, freshEFFECTCRAFT_CONFIG_DIRfor every run, window visibility polled once a second withEnumWindows+IsWindowVisibleon theWindow Classwindow.dxcompiler.dll+dxil.dllfound on the user PATH, see below)d3dcompiler_47.dll, no DXC reachable)classic3dX3550 / X3511 as in the comment aboveLog excerpt for the FXC run (timestamps in seconds):
So on a DX12-only machine the CPU fallback is clean, but it costs 68 s of FXC unrolling attempts during which there is no window, no splash and nothing in the log at the default level. A user who gives up and closes the process in that time trips the launch guard (#247 / #589): the next launch is on OpenGL, without the compositor, until they find Settings ▸ Startup & Repair ▸ Window Graphics.
Two things that may be worth considering alongside the kernel work:
dxcompiler.dll+dxil.dllpair that a third-party audio plug-in had put in the user PATH. wgpu loaded it silently from there, in line with the "wgpu picks up anydxcompiler.dllit can load" finding above. It worked this time, but photocraft Color picker (Character panel Fill/Stroke) has no eyedropper — add viewer color sampling #712 shows the same mechanism crashing, so a pinned, shipped copy (orstatic-dxc) seems safer than relying on whatever is on PATH.Happy to re-run any of this on DX12 against a branch.
Measurements and draft prepared with Claude Code; I read and checked them before posting.
beziergrin commentedon Oct 11, 2026
Possibly the browser counterpart of this issue: on Windows/Chrome the web build loses its GPU device on load and hangs Chrome's GPU process (also with
?nogpuworkers).Chrome's WebGPU on Windows runs on Dawn's D3D12 backend. If a compositor kernel trips the D3D shader compiler there too, the browser outcome is much worse than the desktop's quiet CPU fallback.
What happens
The web build starts normally. The console logs
restored the last session (untitled),event handlers installed.andGPU compositor: (BrowserWebGpu), and the title changes toEffectCraft - Untitled Project.ecproj. Within about a second the page stops painting, and DevTools-protocol screenshots of the tab time out after 30 s.The hang takes Chrome's GPU process with it: the whole browser stops responding, and a browser extension using the tab lost its connection. Once Chrome recovered, the page showed the device-lost notice from #237:
Afterwards,
navigator.gpu.requestAdapter()returnsnullin every tab until Chrome restarts. Chrome has disabled WebGPU for the session.What I tried
//?nogpuworkerseffectcraft.info()just before the hang:gpu: {compositor: " (BrowserWebGpu)", viewerOnGpu: false},frameWorkers: {alive: 2, gpu: [null, null], …},workers: {gpu: null}. Only the page's device was in use./?webglI couldn't find a URL flag that keeps EffectCraft's page off WebGPU. A
?webgl/?cpuflag for the page would give users a workaround.On the same machine and browser, the other Craft web builds work, all of them on
BrowserWebGpu: PhotoCraft, VectorCraft, FilmCraft, PdfCraft, WordCraft, DeckCraft, GridCraft, CADCraft, DesignCraft, LightCraft and SoundCraft. EffectCraft is the only one that uses WebGPU compute (the GPU compositor), which points at the compositor's pipelines or the first compute dispatch.Environment
mainat67434e90388b6dca4417555346fa6850b6f96033(2026-10-11), workspace version 0.8.0.cargo xtask webwith Rust 1.99 and wasm-bindgen-cli 0.2.129. Reproduced with and withoutwasm-opt(binaryen version_133,-O2as in xtask), with wasm sizes of 60.2 MB and 46.9 MB..wasmserved asapplication/wasm, gzipped.platformVersion19.0.0), Google Chrome 155.0.8059.27, x64.Related: #225 / #237. The device-lost notice appears as designed; the problem is that the loss hangs the browser first.
I can run any diagnostic build or URL flag you'd like.
🤖 Generated with Claude Code
beziergrin commentedon Oct 11, 2026
GPU details for the browser report above (from
chrome://gpu, after restarting Chrome, which is now 155.0.8059.40):VENDOR=0x8086 DEVICE=0x5917, Gen 9, integrated. No discrete GPU (Has Discrete GPU: no). Driver 31.0.101.2134.<Integrated GPU> D3D12 backend - Intel(R) UHD Graphics 620, status Available. Vulkan isn't supported by this driver, so D3D12 is the only WebGPU path. The D3D11 and Microsoft Basic Render Driver adapters are blocklisted.use_dxcandd3d12_use_hlsl_2021, so the browser path compiles with DXC rather than FXC. That makes this probably not the same FXC abort as the desktop case above. It's more likely the compositor's first compute work hitting a TDR or out-of-memory condition on a low-end iGPU.exit_on_context_loston this machine ("Some drivers are unable to reset the D3D device in the GPU process sandbox"). That fits with the GPU process going down rather than recovering in place.Every other Craft web app runs on this same adapter, so a smaller first dispatch or a
?cpuescape hatch for the page would probably be enough here.🤖 Generated with Claude Code
beziergrin commentedon Oct 11, 2026
Also reproduces on macOS, so it's not specific to D3D12 or DXC.
I opened the same build (
67434e9, served the same way) in Chrome 155.0.8059.39 on macOS 15.7.8. The machine is a 2018 Intel Mac mini (4 cores, 8 GB). WebGPU adapter:vendor: intel, architecture: gen-9on Dawn's Metal backend.It behaved the same as on Windows, only a bit faster: the app started, then the whole browser froze.
Both failing machines use Intel Gen 9 integrated GPUs:
Every other Craft web app runs on both machines. That suggests the GPU compositor's first work is something Gen 9 iGPUs can't handle (dispatch size, memory, or a feature they handle badly), not a problem with the backend or shader compiler. A
?cpuflag for the page would still be a useful escape hatch for this class of hardware.🤖 Generated with Claude Code
2 remaining items
MatejKozlovsky commentedon Oct 15, 2026
@didpublishing are you still working on this? I traced the
classic3dfailure to a single line: inocclusion,o[k] = …writes a vector component through a loop index. FXC can't do that natively (X3550), so it tries to unroll every loop around the call, which fails with the X3511 errors. Computing the three channels as onevec3makesclassic3dcompile with FXC, and the output is unchanged. I also haveclassic3dfalling back to the CPU like the effect kernels if a compiler still rejects it.If you already have a branch, I'm happy to hand this over or fold it into yours. Otherwise I can open a small PR. It doesn't touch the
switchkernels you mentioned.GPU: pointwise builds with FXC, so colour effects run on DirectX 12 (s…
GPU: nine more kernels build with FXC on DirectX 12 (storytold#613)
Launch guard: two early stops before OpenGL; Window Graphics ▸ Vulkan
MatejKozlovsky commentedon Oct 16, 2026
Reproduced this on current
main(8f02f52), on an RTX 3090 / Ryzen 7 5800X, Windows 10 22H2 (19045), NVIDIA 595.97, with nodxcompiler.dllanywhere.effectcraft-cli info --gpuwithWGPU_BACKEND=dx12fails after about 38 s, and addingWGPU_DX12_COMPILER=fxcgives the identical error (Vulkan is fine):Mapped to the source with naga 30.0.1: the X3550 is
classic3d.wgsl:265(o[k] = …inocclusion()'sfor k < 3loop), which naga emits as a dynamically indexed write that FXC can't address. FXC then has to unroll the runtime-bounded loops around it and fails: lines 274 (shadow_of), 317 (shade_texel), 386 and 400 (classic3d).On packaging: the v0.10.0
windows-x64-portable.zipandwindows-x64.msicontain onlyeffectcraft.exeandeffectcraft-cli.exe, with nodxcompiler.dllordxil.dll. So release users who land on DX12 always get FXC unless they have DXC installed themselves. In an earlier run on the same machine (2959ec7a), DXC 1.9.2609 (dxcompiler.dll+dxil.dllnext to the exe) worked on DX12.#1571 fixes the
occlusionwrite (onevec3instead ofo[k]), makesclassic3doptional, and reworks the other kernels FXC rejects, so it should cover this without DXC. It doesn't ship DXC, though. I haven't re-run this 3090 against the #1571 branch yet.GPU: precise atan2 for CC Environment and CC Bend It on DirectX 12 (s…
GPU: Classic 3D builds with FXC, so the GPU compositor starts on Dire…
GPU: fxw_warp builds with FXC; ignored DX12 kernel report test (story…
GPU: DXC compiles kernels with IEEE strictness (patched wgpu-hal 30.0…
GPU: UAV barrier between write-only storage-texture writes on DX12 (p…
GPU tests: log wgpu output (storytold#613)
GPU: pointwise builds with FXC, so colour effects run on DirectX 12 (s…
GPU: nine more kernels build with FXC on DirectX 12 (storytold#613)
GPU: precise atan2 for CC Environment and CC Bend It on DirectX 12 (s…
Pin the patched wgpu-hal exactly (storytold#613)