Replayable command lists, a Windows-shaped DLL, and reading Apple's license
Command lists can now run more than once on Metal 4, d3d12.dll is split the way Windows splits it, and passing tests went from 56 to 82 with no new failures.
What changed
- Command lists are recorded, then replayed. A D3D12 command list now records a compact stream of commands in memory. Each execution turns that stream into a fresh Metal 4 command buffer. This fixes the one-shot command-buffer problem from entry 002.
- d3d12.dll matches Windows' layout. On Windows,
d3d12.dllis a small loader and the implementation lives ind3d12core.dll, part of the Agility SDK. I split mine the same way, because one vkd3d-proton test checks which DLL each object's function table comes from. The loader always loads the core from its own folder, so aD3D12Core.dllthat a game ships for Windows is never used against my DXGI. - Windows' less obvious behaviors:
D3D12CreateDevicereturns the same device while one is alive.CheckFeatureSupportreturns Windows' exact error codes.- Root signatures can be serialized.
- Executing a command list that is still open removes the device, as on Windows.
- Apple's Metal Shader Converter license, read and recorded.
The interesting parts
The device singleton has a race condition. While a device is alive, D3D12CreateDevice hands back the same device instead of creating a new one. That makes the singleton a weak pointer, and there is a race: one thread can look up the device just as another releases the last reference. The lookup therefore uses a compare-and-swap that refuses to raise a reference count that is already zero, so a dying device is never brought back to life.
Apple's license says what the converter's dylib may do. Apple's Metal Shader Converter translates DXIL shaders to Metal, and it's what a lot of commercial porting uses. The license bundled with its installer allows distributing the dylibs "for the sole purpose of shader conversion", on Apple hardware only. It forbids reverse engineering or modifying them. The command-line tool is for internal development use only, and the headers are Apache-2.0.
My decision: the converter may become an optional backend that users install from Apple themselves. The default build stays fully open source, and I never bundle the dylib.

Numbers
| Suite | Pass | Fail | Skip |
|---|---|---|---|
| Samples and API tests | 2 | 0 | 0 |
| vkd3d | 27 | 156 | 7 |
| vkd3d-proton | 53 | 311 | 213 |
| Total | 82 | 467 | 220 |
That is 769 tests, from a full run near the end of the session. Compared with entry 003, 26 tests newly pass and none newly fail.
Three tests are still flaky.
- pass
- fail
- skip
suite · share of each row's total
- vkd3d-proton (+19)53 pass, 311 fail, 213 skip of 577
- vkd3d (+6)27 pass, 156 fail, 7 skip of 190
- api (+1)1 pass, 0 fail, 0 skip of 1
- samples1 pass, 0 fail, 0 skip of 1