MOOR security

Dieser Eintrag ist auf Englisch verfasst.

Shader Model 6.8 was already there: it took two flags and one validation rule

Entry 066851 of 954 tests pass

The layer now tells D3D12 applications it supports Shader Model 6.8. The shader translation already handled everything 6.8 adds; the one fix needed was letting buffers start in the unordered-access state.

What changed

A D3D12 device reports the highest Shader Model (the version of the GPU program language) it supports, and applications choose their shaders by that answer. Ours said 6.7. It now says 6.8.

6.8 requires two things:

  • SV_StartVertexLocation and SV_StartInstanceLocation. A vertex shader can read the first vertex and first instance its draw call was given. Instancing means drawing the same mesh several times in one call.
  • Wave size ranges. A compute shader can say "I run with between 16 and 64 threads in lockstep" instead of naming one number.

It also adds an optional feature, comparison sampling with a mip bias or explicit gradients (SampleCmpBias, SampleCmpGrad). That is the depth-texture lookup used for shadows.

How the start locations reach Metal, and where the root-offset path splits off.D3D12 draw StartVertexLocation or BaseVertexLocation, StartInstanceLocation → Metal draw baseVertex, baseInstance; HLSL (SM 6.8) SV_StartVertexLocation, SV_StartInstanceLocation → dxil-spirv BaseVertex, BaseInstance; dxil-spirv BaseVertex, BaseInstance → SPIRV-Cross [[base_vertex]], [[base_instance]]; Metal draw baseVertex, baseInstance → SPIRV-Cross [[base_vertex]], [[base_instance]]; SPIRV-Cross [[base_vertex]], [[base_instance]] → does the vertex shader read the start instance?; does the vertex shader read the start instance? → root offsets: baseInstance carries the root block offset (no); does the vertex shader read the start instance? → baseInstance stays the D3D12 start instance (yes)D3D12 drawStartVertexLocation or BaseVertexLocation,StartInstanceLocationMetal drawbaseVertex, baseInstanceHLSL (SM 6.8)SV_StartVertexLocation,SV_StartInstanceLocationdxil-spirvBaseVertex, BaseInstanceSPIRV-Cross[[base_vertex]], [[base_instance]]does the vertex shaderread the start instance?root offsets: baseInstance carriesthe root block offsetbaseInstance stays theD3D12 start instancenoyes
How the start locations reach Metal, and where the root-offset path splits off. (Mermaid source)
Scene startlocations: nine draws, direct and indexed, in six rows: each reads SV_StartVertexLocation (StartVertexLocation, or BaseVertexLocation when indexed, is 6 x row) for its row and SV_StartInstanceLocation for its first column, so every quad sits at column StartInstanceLocation + SV_InstanceID; each draw's instance 0 is lighter; gaps fall between draws in rows 2 and 4
Gallery scene startlocations: nine draws, direct and indexed, in six rows: each reads SV_StartVertexLocation (StartVertexLocation, or BaseVertexLocation when indexed, is 6 x row) for its row and SV_StartInstanceLocation for its first column, so every quad sits at column StartInstanceLocation + SV_InstanceID; each draw's instance 0 is lighter; gaps fall between draws in rows 2 and 4. All scenes in the gallery

The interesting part

The shader path already handled all of it. dxil-spirv, the translator from D3D12's shader format to SPIR-V, already turns the two start locations into Vulkan's BaseVertex and BaseInstance. SPIRV-Cross, which writes Metal source from SPIR-V, maps those to Metal's [[base_vertex]] and [[base_instance]]. Compute pipelines already compared wave sizes against Apple's fixed 32 lanes. The comparison sampling becomes Metal's sample_compare with bias() or gradient2d(). So the change is two feature bits and the version cap.

The one bug was elsewhere. vkd3d-proton's draw-parameter test failed before drawing anything: it creates a buffer in the UNORDERED_ACCESS state (writable from shaders) without the flag that allows unordered access, and we rejected that. Microsoft's enhanced-barriers spec says a buffer's initial state is treated as COMMON, so that's legal. We now accept it for buffers; textures still need the flag.

One interaction needed a check: entry 063's design hides a per-draw offset in the base instance. A shader that reads the start instance must not see that offset. That design already keeps such shaders on the old path. The new api/draw_parameters test covers a shader that reads only the start vertex, which keeps the offset path and still gets correct values.

One assumption is unverified: in non-indexed draws the test expects SV_VertexID to count from 0, not from the start vertex. dxil-spirv and vkd3d-shader both do that, but I haven't checked native Windows.

Numbers

  • vkd3d-proton test_sm68_draw_parameters (55 checks) and test_sm68_sample_cmp_bias_grad (210) pass. test_sm68_wave_size_range passes its ranges that contain 32 and skips four that don't.
  • api/draw_parameters: 70 checks pass.
  • Full suite: 851 pass, 29 fail, 74 skip of 954, against 849/28/76 of 953. 3 newly passing. 1 newly failing: apps/bgfx-29-debugdraw, 343 pixels off at the left edge. That is a flake under load recorded before, and it passed three solo reruns.
Tests by suite at the end of this entry: 851 of 954 pass (data as CSV)
  • pass
  • fail
  • skip

suite · share of each row's total

  1. vkd3d-proton (+2)492 pass, 15 fail, 70 skip of 577
  2. vkd3d177 pass, 9 fail, 4 skip of 190
  3. api (+1)83 pass, 0 fail, 0 skip of 83
  4. apps (-1)79 pass, 1 fail, 0 skip of 80
  5. wine-dxgi16 pass, 4 fail, 0 skip of 20
  6. samples4 pass, 0 fail, 0 skip of 4