Inline ray queries on an M1, which has no ray-tracing hardware
D3D12 acceleration structures and DXR 1.1 inline ray queries now run on the D3D12-on-Metal layer on an M1 Max, which has no ray-tracing hardware. They use Metal's ray-tracing API and find each structure through a small header written at its D3D12 GPU address.
What changed
- Acceleration structures and ray queries (the first tier of the ray-tracing plan).
- A D3D12 application builds bottom-level and top-level acceleration structures (BLAS, TLAS) into ordinary buffers. It then traces rays against them from any shader with
RayQuery. - mtl12, this project's D3D12-to-Metal 4 layer, now does both through Metal's ray-tracing API. That API runs on the M1 without ray-tracing hardware.
- Updates (refits), clones, compaction and the postbuild size queries work too. A review found three problems, since fixed:
- a contribution-table read without a bounds check;
- a structure freed before the side queue finished with it;
- a run of AS commands that had to be split where a later command depends on an earlier one.
- The feature stays behind
MTL12_RAYTRACING=1. Reporting ray-tracing tier 1.1 tells applications that DXR pipelines (TraceRaywith shader tables) exist, and those do not yet.
- A D3D12 application builds bottom-level and top-level acceleration structures (BLAS, TLAS) into ordinary buffers. It then traces rays against them from any shader with
- Enhanced barriers.
ID3D12GraphicsCommandList7::Barrierrecords the same conservative full barrier as the olderResourceBarrier. OPTIONS12 reports support. - Relaxed format casting. A resource can be created with a list of formats it may later be viewed as.
- Views in those formats become Metal pixel-format views.
- The lists are validated with the rules from vkd3d-proton's tests.
- Metal can view a block-compressed texture only as its sRGB or signed twin, so other views of such a texture become null descriptors.
The interesting part
D3D12 names an acceleration structure by a 64-bit GPU address. Metal names it by an opaque object. A shader reaches a D3D12 structure only through the address, whether from a root argument or read out of a descriptor heap. So the Metal shader has to turn a number into a structure.
- A spike came first. A Metal 4 compute kernel read a
MTLResourceIDfrom device memory, used it as aninstance_acceleration_structure, and queried a structure built on a Metal 3 queue. That worked, so the layer now writes a 16-byte header at the start of every D3D12 destination buffer:{MTLResourceID, instance count}. For a TLAS, a table of each instance's hit-group contribution follows the header. A patched SPIRV-Cross turns the address into a structure by reading the header. - One gap took a second patch.
RayQuery::CommittedInstanceContributionToHitGroupIndexhas no Metal counterpart. MSL'sintersection_querycan't be a struct member or a base class, so it can't carry the address along.- dxil-spirv patch 0002 gives each ray query a companion variable that remembers the address it traced.
- The contribution is then read from the table after the header.
- Builds run on a Metal 3 queue beside the Metal 4 one. Shared events order the two queues. Before the build, Metal 4 kernels gather the triangles into packed float3 scratch. That way every D3D12 vertex format, stride and transform takes one path.
Numbers
- Full run: 699 pass, 27 fail, 124 skip of 850 tests, against 682 / 27 / 137 of 846 at the end of entry 032. None newly failing. 17 newly passing:
- 4 new api tests: rt_ray_query (146 checks), rt_as_ops (85), enhanced_barriers (7) and castable_formats (42);
- vkd3d-proton test_rayquery_root_desc and test_rayquery_root_table (738 checks each);
- vkd3d-proton test_raytracing_acceleration_structure_validation;
- all 10 vkd3d-proton test_enhanced_barrier_* tests.
- Metal format views, probed on the M1 Max: every same-size uncompressed colour cast tried is allowed. Of block-compressed formats, only the sRGB or signed twin is allowed. Depth ↔ colour views are not allowed.
Not covered: DXR 1.0 pipelines (state objects, shader tables, DispatchRays). 19 vkd3d-proton test_raytracing_* tests still skip, most of them because they need pipelines. Compaction destinations are not yet sized from the compacted size. Uncompressed views of BC textures, which applications use to write compressed blocks from shaders, read zeros.
- pass
- fail
- skip
suite · share of each row's total
- vkd3d-proton (+13)439 pass, 18 fail, 120 skip of 577
- vkd3d177 pass, 9 fail, 4 skip of 190
- api (+4)49 pass, 0 fail, 0 skip of 49
- apps30 pass, 0 fail, 0 skip of 30
- samples4 pass, 0 fail, 0 skip of 4