MOOR security

Dieser Eintrag ist auf Englisch verfasst.

DXR conformance on an M1: test_raytracing passes, and DispatchRays goes indirect

Entry 035721 of 856 tests pass

vkd3d-proton's main D3D12 ray-tracing conformance test now passes all 1,826 of its checks on the D3D12-on-Metal layer on an M1 Max, and DispatchRays also works from GPU-written argument buffers through ExecuteIndirect.

What changed

  • vkd3d-proton test_raytracing passes. This is the broad DXR test from vkd3d-proton (the D3D12-on-Vulkan project whose test suite this project runs). In an earlier probe, 909 of its 1,826 checks failed. In this session's full run, 0 failed. The fixes:
    • static samplers declared in local root signatures (the arguments stored per shader record);
    • exports that use different global root signatures in one pipeline;
    • pipeline flags that skip triangles or procedural geometry;
    • one rule from the spec: a ray that hits the edge shared by two triangles reports one hit, not two.
  • Indirect DispatchRays. ExecuteIndirect replays commands whose arguments the GPU can write. For DispatchRays, a small GPU kernel copies each command's D3D12_DISPATCH_RAYS_DESC (shader-table addresses and a W×H×D grid) into that command's record and computes the threadgroup counts. A command over D3D12's limit of 2^30 rays gets zero threadgroups. New api test rt_indirect: 66 checks.
  • Review fixes. A later review found that the new root signature references broke the device's deduplication of identical root signatures and could release one twice. It also found that the indirect path skipped the ray limit. Both are fixed.
How an indirect DispatchRays becomes a Metal dispatch.ExecuteIndirect: argument buffer per command: root args + DISPATCH_RAYS_DESC → expand_indirect kernel on the GPU, per command; count buffer → expand_indirect kernel on the GPU, per command; host template: function table, root buffers → expand_indirect kernel on the GPU, per command; expand_indirect kernel on the GPU, per command → per-command record: root block + mtl12_rt_dispatch (copies the desc's 25 words); expand_indirect kernel on the GPU, per command → 0 threadgroups: command dropped (W·H or W·H·D over 2^30); expand_indirect kernel on the GPU, per command → raygen address 0: rays call nothing (raygen size 0); per-command record: root block + mtl12_rt_dispatch → mtl12_dispatch_rays ceil(W/8) × ceil(H/8) × D threadgroups; mtl12_dispatch_rays ceil(W/8) × ceil(H/8) × D threadgroups → shader table walk (raygen, miss, hit records)ExecuteIndirect: argument bufferper command: root args + DISPATCH_RAYS_DESCexpand_indirect kernelon the GPU, per commandcount bufferhost template:function table, root buffersper-command record:root block + mtl12_rt_dispatch0 threadgroups:command droppedraygen address 0:rays call nothingmtl12_dispatch_raysceil(W/8) × ceil(H/8) × D threadgroupsshader table walk(raygen, miss, hit records)copies the desc's 25 wordsW·H or W·H·D over 2^30raygen size 0
How an indirect DispatchRays becomes a Metal dispatch. (Mermaid source)
Scene rtindirect: one ExecuteIndirect of four DispatchRays: three cameras each ray-trace a quarter (closest-hit, shadow miss); the bottom-left command asks for 2^31 rays and is dropped
Gallery scene rtindirect: one ExecuteIndirect of four DispatchRays: three cameras each ray-trace a quarter (closest-hit, shadow miss); the bottom-left command asks for 2^31 rays and is dropped. All scenes in the gallery

The interesting part

One subtest checks reference counts. The D3D12 docs say a pipeline state object holds its root signatures. The test expects the opposite: after the pipeline is created, the root signature's count is still 1. Its comment says native drivers behave that way (vkd3d-proton's d3d12_raytracing.c, line 1573). So the layer now keeps root signatures alive with an internal "hold" that the public count doesn't show.

The dead end: at first, the kernel chose the ray-generation record with raygen_size ? raygen : 0. In about 7 of 10 runs, every ray of test_raytracing_local_rs_static_sampler then missed, even rays aimed at opaque quads. The host now writes address 0 for an empty record, and the kernel doesn't branch. I don't know why the branch broke tracing.

Numbers

  • Full run: 721 pass, 27 fail, 108 skip of 856 tests .
    • It has 0 newly failing and 8 newly passing tests against this session's first run (713 / 27 / 115 of 855). The 8 are rt_indirect and seven vkd3d-proton test_raytracing* tests.
  • Checks: vkd3d-proton 23,882,841 passed and 3,800 failed, the same failures as before. The api suite passed 9,508 checks with none failing.
Tests by suite at the end of this entry: 721 of 856 pass (data as CSV)
  • pass
  • fail
  • skip

suite · share of each row's total

  1. vkd3d-proton (+18)455 pass, 18 fail, 104 skip of 577
  2. vkd3d (+6)177 pass, 9 fail, 4 skip of 190
  3. api (+4)55 pass, 0 fail, 0 skip of 55
  4. apps30 pass, 0 fail, 0 skip of 30
  5. samples4 pass, 0 fail, 0 skip of 4