MOOR security

Dieser Eintrag ist auf Englisch verfasst.

Integer border colours on a GPU with three fixed ones

Entry 025580 of 807 tests pass

Shaders can now sample integer textures with any integer border colour on Metal, which only offers black, transparent black and white.

What changed

mtl12 translates Direct3D 12 to Apple's Metal, so Windows games can run under Wine on Apple Silicon. This entry covers one short session; its gallery scene, diagram and note were committed the session after.

Shader Model 6.7 bundles four texture features under one cap, AdvancedTextureOps: sampling integer textures, raw gathers (reading four texels' bits unconverted), offsets computed at run time, and a depth comparison at an explicit mip level. With the cap simply switched on, three of the four already worked: the shader translators (dxil-spirv and SPIRV-Cross) produce Metal code the compiler accepts. One piece did not: integer border colours, the value a sampler returns when the coordinate falls outside the texture and the address mode is "border".

Scene intborder: a uint texture point-sampled past its edges through three UINT border colours; the third (0x01000007) survives only as bits
Gallery scene intborder: a uint texture point-sampled past its edges through three UINT border colours; the third (0x01000007) survives only as bits. All scenes in the gallery

The interesting part

Metal has exactly three border colours and no custom one. For float textures the project already emulated arbitrary colours: sample once with a black border and once with a white one, and blend between them with the colour as weight.

Integer sampling is point-filtered (it never blends neighbouring texels), so that trick becomes a select. Inside the texture both samples return the same texel. Outside, one returns 0 and the other 1, so any channel where the two differ is border, and it takes the colour. SPIRV-Cross patch 0021 emits that select for integer results.

The trap was in storage. The sampler record used to hold the border colour as floats, and a 32-bit float holds integers exactly only up to 2^24. The gallery scene's third border, 0x01000007, would round to 0x01000008 and its low bits, which pick the colour, would turn it grey. The record now keeps the bits.

The new test also hit a Metal assertion on a view with an empty mip range, which hangs under Wine; such views now become null views.

Integer border colours from two samples and a per-channel select, never through a float.shader (SPIRV-Cross patch 0021): a = sample with transparent-black border, per channel: a ≠ b ? c : a, b = sample with opaque-white border; CreateSampler2 UINT_BORDER_COLOR c → sampler record [sampler][white sampler][c as bits]; a = sample with transparent-black border → per channel: a ≠ b ? c : a; b = sample with opaque-white border → per channel: a ≠ b ? c : a; sampler record [sampler][white sampler][c as bits] → a = sample with transparent-black border; sampler record [sampler][white sampler][c as bits] → b = sample with opaque-white border; per channel: a ≠ b ? c : a → uint4 result texel, or c outside; float path: a + (b − a)·c → per channel: a ≠ b ? c : a (integer results are point sampled)CreateSampler2UINT_BORDER_COLOR csampler record[sampler][white sampler][c as bits]a = sample withtransparent-black borderper channel:a ≠ b ? c : ab = sample withopaque-white borderuint4 resulttexel, or c outsidefloat path:a + (b − a)·cshader (SPIRV-Cross patch 0021)integer resultsare point sampled
Integer border colours from two samples and a per-channel select, never through a float. (Mermaid source)

Numbers

  • The new api test advanced_texture_ops: 45 checks. Before patch 0021 only the 4 custom-colour checks failed; with it all pass.
  • Full run at the end: 580 pass, 82 fail, 145 skip of 807. Against the previous full run: vkd3d-proton test_sm67_sample_cmp_level and test_sm67_dynamic_texture_offset go from skip to pass, and the new api test passes. Nothing that passed before fails.
Tests by suite at the end of entry 025: 580 of 807 pass (data as CSV)
  • pass
  • fail
  • skip

suite · share of each row's total

  1. vkd3d-proton (+2)381 pass, 57 fail, 139 skip of 577
  2. vkd3d159 pass, 25 fail, 6 skip of 190
  3. api (+1)36 pass, 0 fail, 0 skip of 36
  4. samples4 pass, 0 fail, 0 skip of 4