Memory freed while the GPU was still using it
A test that hung the GPU pointed to a lifetime bug: long command lists are split into several Metal command buffers, and the memory of an earlier one could be recycled while later ones still read it.
What changed
A test process from the previous run was still stuck in exit when this session started, with the GPU at 100%. So this session ran no tests at all. The work was done by reading code.
The stuck test, vkd3d-proton's test_execute_indirect_state_predication, records more than 6,000 ExecuteIndirect calls (draws whose arguments live in GPU memory) in one command list, each followed by a timestamp query. Before each group of calls, a compute pre-pass writes the arguments Metal will read into scratch memory.
Metal runs out of memory when one command buffer has tens of thousands of encoders (the objects that record GPU commands), so we split long lists into several command buffers. Each command buffer has an allocator that owns its scratch memory. When a command buffer was committed, its allocator went straight back into the pool. The pool recycles an allocator once its own command buffer has finished. But later command buffers of the same list still read that allocator's memory: the pre-pass's argument records, and the latched condition for conditional rendering. If the GPU was fast enough, those records were freed or overwritten first, and indirect draws read garbage vertex and instance counts. That is work that may never finish, which is exactly what the stuck process showed.
Now a submission keeps all of its allocators until its last command buffer completes. Dispatches also clamp threadgroup counts to D3D12's limit of 65535 per dimension, so a bad argument can't turn into billions of threadgroups. A second reviewer read the change and found no problems. It could only be verified after a reboot freed the GPU: the test now passes when run alone and is out of quarantine again.
Samples with probes
The previous session's work on image tests is now committed. No machine with a reference D3D12 driver is available, so each sample is checked by probes: pixels whose colour follows from the scene by hand, such as 0.6 × purple + 0.4 × background = (97, 39, 152) inside the top disc of the new blend sample. A reviewed render of our own, a golden, catches regressions. blend is one of the gallery scenes on the project page; our render of it matches that image pixel for pixel.