MOOR security

Dieser Eintrag ist auf Englisch verfasst.

Faking a 96-bit format Metal doesn't have, and a sentinel that looked like an error

Entry 021544 of 792 tests pass

Direct3D 12's three-channel 32-bit formats now work on Metal, which has no 96-bit format, and shaders that index the descriptor heap directly (Shader Model 6.6) now bind correctly.

What changed

mtl12 translates Direct3D 12 to Apple's Metal so that Windows games can run under Wine on Apple Silicon.

  • R32G32B32 textures. D3D12 allows textures with three 32-bit channels (12 bytes per texel). Metal has no 96-bit pixel format, so these become four-channel textures. Copies between buffers and these textures go through two small GPU kernels: one widens 12-byte texels to 16 bytes, the other packs them back. Shader views return 1 for the missing alpha channel, as D3D12 requires.
  • R32G32B32 typed buffers. A typed buffer view (a buffer read as an array of formatted elements) can't use the four-channel trick, because the element stride in memory is fixed at 12 bytes. Instead the view becomes a one-channel 32-bit buffer, and the shader reads three consecutive texels per element. That needed a patch to SPIRV-Cross, the shader translator (patch 0015). A review found that typeless formats took the new path by mistake; that is fixed.
  • Shader Model 6.6 heap indexing. SM 6.6 shaders can index the whole descriptor heap directly (ResourceDescriptorHeap[i]) instead of going through a root signature table. The first version of this failed to bind.
Copies between buffers with 12-byte texels and four-channel Metal textures.buffer → texture: application buffer 12-byte texels, scratch 16-byte texels, RGBA32 Metal texture; texture → buffer: RGBA32 Metal texture, scratch 16-byte texels, application buffer 12-byte texels; application buffer 12-byte texels → scratch 16-byte texels (rgb32_expand kernel); scratch 16-byte texels → RGBA32 Metal texture (blit); RGBA32 Metal texture → scratch 16-byte texels (blit); scratch 16-byte texels → application buffer 12-byte texels (rgb32_pack kernel)buffer → texturetexture → bufferapplication buffer12-byte texelsscratch16-byte texelsRGBA32 Metal textureRGBA32 Metal texturescratch16-byte texelsapplication buffer12-byte texelsrgb32_expand kernelblitblitrgb32_pack kernel
Copies between buffers with 12-byte texels and four-channel Metal textures. (Mermaid source)

The interesting part

For heap indexing, dxil-spirv (the DXIL-to-SPIR-V compiler this project uses) asks mtl12 where each resource lives. For heap references it passes register number, register space and range size all set to 0xFFFFFFFF. My lookup searched the root signature for a matching range, found none, and refused the binding. So "no register at all" looked like "a register nobody declared". The fix recognises the sentinel and points the binding at the start of the heap. A new test reads a constant buffer, structured, typed and raw buffers, a texture, a UAV counter and two samplers through the heap. It failed before the fix and passes after it (api/descriptor_heap_sm66).

The device still reports Shader Model 6.0. For one run I reported 6.6 to see what it unlocks. Ten skipped vkd3d-proton tests ran; one passed outright, two passed after this fix, and seven still fail for separate reasons. Shaders that use 6.6 features compile anyway, so applications that don't check the reported model get heap indexing now.

Numbers

  • Full run: 544 pass, 78 fail, 170 skip of 792, against 540 / 80 / 170 of 790 at the previous entry.
  • vkd3d test_resource_alignment: 442 failed checks → 0 (same logs).
  • Failed checks in the two conformance suites: 3,793 → 3,322 (same logs).
  • One vkd3d-proton tiled-resource test failed intermittently in the full run and passed 13 of 13 runs on its own; it is logged as flaky, not fixed.
Failed checks in the conformance suites, end of entry 020 and end of entry 021 (data as CSV)
  • entry 020
  • entry 021

suite · failed checks

  1. vkd3d595 entry 020, 153 entry 021
  2. vkd3d-proton3,198 entry 020, 3,169 entry 021
Tests by suite at the end of entry 021: 544 of 792 pass (data as CSV)
  • pass
  • fail
  • skip

suite · share of each row's total

  1. vkd3d-proton (+1)360 pass, 53 fail, 164 skip of 577
  2. vkd3d (+1)159 pass, 25 fail, 6 skip of 190
  3. api (+2)22 pass, 0 fail, 0 skip of 22
  4. samples3 pass, 0 fail, 0 skip of 3