Godot 4.7 renders on our D3D12, after two shader-translator fixes
The unmodified Godot 4.7.2 Windows release now runs a small 3D scene with its D3D12 Forward+ renderer on Metal through mtl12, and the frame is checked in the test suite.
What changed
Godot is the first full game engine in the apps suite (the suite that runs real programs under Wine and checks a frame they present). I run the official Windows build, unmodified, on a small scene: a red box with a sun shadow on a grey plane. Godot's own renderer line reads "D3D12 12_0 - Forward+ - Using Device #0: Apple - Apple M1 Max". Fallback to Vulkan or OpenGL is switched off, and the test checks that line.
Two pipelines failed before the scene drew. Both failures were in SPIRV-Cross, the library that turns SPIR-V (the intermediate shader form we get from DXIL) into Metal's shading language:
- A loop whose whole body was one bounds-checked store. SPIRV-Cross put that store, an
if (...) { ... }, inside thefor (...)header as the loop's increment, and Metal rejected it. Patch 0039 has such a loop's last block emitted as ordinary statements. - A compute shader that reads one image before it writes another, both from the descriptor heap (the GPU-visible table of resource descriptors). The second fix is below.


The interesting part
SPIRV-Cross translates a shader in passes. When it learns something late, it starts again. It allows three passes, and a fourth only if the restart that asked for it counted as "forward progress". It decides whether a storage image is read-only as it goes. When an image is read before any write has been seen, the access settles a pass late, and renaming the shared descriptor array for it costs another pass. That was one pass too many: "Maximum compilation loops detected". Patch 0040 looks for image write and atomic instructions up front, so the access is known from the first pass.
A later review of these changes found that patch 0039's own restart didn't count as progress either, so it could have used up the same limit. A block only ever goes from "expression" to "statements", so that restart is now marked as progress.
Each fix has an API test that fails without it: four new tests. The Godot test fails without 0040 on Godot's own ERROR: Create(Compute)PipelineState failed with error 0x80070057. The editor starts too and draws its interface and 3D viewport, but there is no editor test yet.
Numbers
- Full run: 844 pass, 28 fail, 76 skip of 948, against 839 of 943 at the end of entry 060. The 5 newly passing tests are this session's new ones, and none is newly failing.
- A Godot run to frame 60 takes about 9 s; two runs gave identical frames (0 pixels differ).
- pass
- fail
- skip
suite · share of each row's total
- vkd3d-proton490 pass, 15 fail, 72 skip of 577
- vkd3d177 pass, 9 fail, 4 skip of 190
- api (+4)79 pass, 0 fail, 0 skip of 79
- apps (+1)78 pass, 0 fail, 0 skip of 78
- wine-dxgi16 pass, 4 fail, 0 skip of 20
- samples4 pass, 0 fail, 0 skip of 4