Video formats, honest format caps, and the 1024th sampler
Apple's GPU lets you create more samplers than shaders can use, and says nothing: sampler 1024 and later return garbage.
What changed
mtl12 translates Direct3D 12 (Microsoft's low-level graphics API) to Apple's Metal, so Windows games can run under Wine on Apple Silicon. This session added four things:
- Heaps over existing memory. A heap can now be opened over memory the application already owns. A review found that the file-mapping version aliased pages it didn't own; it now keeps its own alias of those pages.
- Residency calls. They now complete immediately, because Metal already keeps the memory resident.
- Video formats. NV12, P010 and P016 store brightness at full size and colour at half size. Each part (a "plane") now becomes its own Metal texture.
- Format caps. The driver now reports what each format can do: sampling, blending, multisampling, and shader writes.
The last change mattered more than it sounds. Test suites check these capability bits and quietly skip what the driver says it can't do. One vkd3d-proton UAV-clear test went from 9 checks to 33,437 (a UAV is a shader-writable view). That surfaced a real bug: clearing a 16-bit float texture to a very large but finite value wrote infinity. D3D12 wants the largest finite value.

The interesting part
D3D12 lets a shader index a table of up to 2048 samplers (a sampler is the object that says how a texture is filtered and addressed). Metal reports a budget of 1024 unique samplers for argument buffers, its equivalent of those tables, on an M1 Max.
An earlier spike (a throwaway experiment) had created 4096 samplers without any error, and I took that as good news. It wasn't. The new test uses 2048 samplers that each give a different result. Samplers 0–1022 return the right values, and from index 1023 on they return garbage such as 0, 147 and 323. Metal gives no error and no validation message.
The same test showed a second detail: Metal rounds a sampler's minimum level of detail to 1/64 steps. My first test design used 1/256 steps, so samplers that D3D12 considers different looked identical.
The fix isn't done. The plan is to move the level-of-detail clamps out of the Metal sampler and into the shader, so fewer distinct Metal samplers are needed. For now the driver logs an error once the budget is exceeded, and the test stays red on purpose.
Numbers
- Full run: 508 pass, 92 fail, 182 skip of 782 tests. In the previous full run (entry 014): 501/93/184 of 778. 0 newly failing.
- vkd3d-proton test_clear_unordered_access_view_image: 9 checks with 85 skipped → 33,437 checks with 0 failed.
- Sampler budget: the device reports maxArgumentBufferSamplerCount = 1024. api/sampler_heap_2048 fails 9 checks.
- pass
- fail
- skip
suite · share of each row's total
- vkd3d-proton (+4)343 pass, 62 fail, 172 skip of 577
- vkd3d151 pass, 29 fail, 10 skip of 190
- api (+3)11 pass, 1 fail, 0 skip of 12
- samples3 pass, 0 fail, 0 skip of 3