llvm / llvm/offload-test-suite

[EPIC]: Bring-up and test coverage for PSO-based raytracing

Open
#1,268 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
C++
Stars
18
Forks
39
Avg merge
2d 18h
Merged PRs (30d)
40

Description

Companion to the inline-RT epic in #1258. That issue is scoped to `RayQuery` / `TraceRayInline` inside a regular compute shader; the test framework already treats it as a `Compute` pipeline that happens to bind an acceleration structure. PSO-based raytracing is a different beast β€” it introduces an entirely new pipeline kind, new shader stages, a shader binding table, and the `DispatchRays` command. The framework has none of that today, so this issue tracks both the bring-up work and the shader-visible test surface that becomes unlockable as bring-up progresses.

Reuses the AS YAML / abstraction layers from the inline-RT bring-up (#1214, #1232, #1245), so this work starts above that line.

Legend:
- [ ] Not started
- [ ] In progress πŸ—οΈ
- [ ] In review πŸ‘€
- [x] Finished (merged in main)
- πŸ‘ testable on top of the bring-up below
- πŸ—οΈ requires additional framework work first

## Bring-up PRs (foundation for everything below)
- [ ] Add `ShaderPipelineKind::RayTracing`, six new RT `Stages`, HitGroups / RayTracingPipelineConfig / ShaderBindingTable YAML schema, `%dxc_target_lib` substitution, the `raytracing-pipeline` lit feature, and a foundational `XFAIL: *` smoke test πŸ‘€
- #1270
- [ ] Vulkan RT pipeline + SBT + `dispatchRays` (drops Vulkan from the smoke test's XFAIL list) πŸ‘€
- #1273
- [ ] D3D12 state object + SBT + `DispatchRays` (drops DirectX from the smoke test's XFAIL list) πŸ‘€
- #1275
- [ ] Metal RT pipeline + SBT + `dispatchRays` via `metal_irconverter` (drops Metal from the smoke test's XFAIL list) πŸ‘€
- #1281
- [ ] First PSO RT test batch: DispatchRays index/dimensions + SBT miss/hit-group routing πŸ‘€
- #1277
- [ ] ClosestHit ray system values: barycentrics, PrimitiveIndex, WorldRay πŸ‘€
- #1278
- [ ] PSO-only RT surface: TraceRay recursion, RAY_FLAG_SKIP_CLOSEST_HIT_SHADER, callable shaders πŸ‘€
- #1279

## Framework bring-up

### Pipeline / stage model
- [ ] Add `ShaderPipelineKind::RayTracing` alongside `Compute` / `TraditionalRaster` / `MeshShaderRaster` in `Support/Pipeline.h` πŸ‘€
- [ ] Add new `Stages`: `RayGeneration`, `Miss`, `ClosestHit`, `AnyHit`, `Intersection`, `Callable` πŸ‘€
- [ ] Extend `validatePipelineKind` to require β‰₯1 raygen entry and at least one of {miss, hit-group} when the pipeline is RT πŸ‘€
- [ ] YAML mapping for the new stages and pipeline kind πŸ‘€

### Shader compilation
- [ ] Add a `lib_6_3` (or `lib_6_5`) target so `clang-dxc` / `dxc` emits a DXIL library with multiple entry points
- [ ] `%dxc_target_lib` substitution analogous to `%dxc_target` πŸ‘€
- [ ] Lit feature `raytracing-pipeline` (mirrors `acceleration-structure`) gated on the device feature + library-target support πŸ‘€

### Hit groups, payloads, attributes, recursion config
- [ ] YAML `HitGroups:` list (`Name`, `Type: Triangles|Procedural`, `ClosestHit`, optional `AnyHit`, optional `Intersection`) πŸ‘€
- [ ] YAML `RayTracingPipelineConfig:` block (`MaxTraceRecursionDepth`, `MaxPayloadSizeInBytes`, `MaxAttributeSizeInBytes`, optional `PipelineFlags`) πŸ‘€
- [ ] Local root signatures (per shader-record root args) β€” at minimum a schema that lets a test record SBT-local constants πŸ—οΈ
- [ ] Validate payload/attr sizes against shader-declared sizes at YAML parse time

### State Object / RT pipeline creation
- [ ] D3D12 backend: build a `ID3D12StateObject` from the YAML (DXIL library subobject, hit-group subobjects, global/local root signatures, raytracing pipeline + shader config subobjects)
- [ ] Vulkan backend: `VkRayTracingPipelineKHR` + `vkGetRayTracingShaderGroupHandlesKHR`, pipeline-library plumbing if needed; `VK_KHR_ray_tracing_pipeline` feature gate
- [ ] Metal backend: route through `metal_irconverter` for DXILβ†’AIR β€” it lowers `DispatchRays` into a compute dispatch backed by `MTLVisibleFunctionTable` / `MTLIntersectionFunctionTable` standing in for hit-groups, miss shaders, and callables. The backend work covers emitting the converter-expected compute dispatch and building those function tables. πŸ‘€ (#1281)

### Shader binding table
- [ ] Abstract `ShaderBindingTable` resource owned by the RT pipeline
- [ ] YAML `ShaderBindingTable:` block describing raygen / miss / hit-group / callable records, each with `ShaderName`, optional local-root data πŸ‘€
- [ ] Per-backend SBT builders:
- D3D12: identifier from `ID3D12StateObjectProperties::GetShaderIdentifier`, 32-byte aligned records, programmer-managed stride
- Vulkan: `VkStridedDeviceAddressRegionKHR`, alignment from `rayTracingPipelineProperties`
- Metal: visible function tables / intersection function tables
- [ ] Compute SBT record stride from declared local-root data size

### DispatchRays command
- [ ] New `RayTracingEncoder` (or extend `ComputeEncoder`) with `dispatchRays(width, height, depth, sbt)`
- [ ] YAML dispatch parameters: `RayTracingDispatch: { Width, Height, Depth }` β€” currently reusing `DispatchParameters.DispatchGroupCount` as `{Width, Height, Depth}` for RT pipelines per #1270; a dedicated `RayTracingDispatch` block can come later if useful.
- [ ] Resource-state / barrier handling for SBT and AS reads

### Resource binding parity
- [ ] AS binding from raygen / miss / hit / callable stages (the inline-RT work only wires it up for compute)
- [ ] UAV / SRV / CBV / sampler tables from each new stage
- [ ] Verify cross-API root-signature layout matches between D3D12/Vulkan so the same DXIL works unmodified

## Shader-observable spec surface

Each test asserts behavior visible from a raygen / miss / hit / callable shader. Coverage parallels the inline-RT epic where the same concept appears (e.g. ray flags), then adds the PSO-only surface (payloads, recursion, etc.).

### `TraceRay` (host-side intrinsic)
- [ ] `RayFlags` parameter behaves the same as in `RayQuery<>` β€” re-run the same flag matrix from #1258 β€” πŸ‘ once bring-up lands
- [ ] `InstanceInclusionMask` filtering β€” πŸ‘
- [ ] `RayContributionToHitGroupIndex` selects the right hit-group record β€” πŸ‘
- [ ] `MultiplierForGeometryContributionToHitGroupIndex` (per-geometry hit-group striding) β€” πŸ—οΈ (multi-geometry BLAS)
- [ ] `MissShaderIndex` selects the right miss record β€” πŸ‘
- [ ] `RayDesc` corners: `TMin > 0`, `TMax` clip, NaN/Inf direction β€” πŸ‘
- [ ] Recursive `TraceRay` up to `MaxTraceRecursionDepth` β€” πŸ‘
- [ ] Recursion beyond declared `MaxTraceRecursionDepth` is undefined; verify that the in-spec maximum value works β€” πŸ‘

### Raygen shader (`[shader("raygeneration")]`)
- [ ] `DispatchRaysIndex()` matches the dispatch x/y/z lane β€” πŸ‘
- [ ] `DispatchRaysDimensions()` echoes the host-side width/height/depth β€” πŸ‘
- [ ] Multiple raygen entries, one selected per pipeline β€” πŸ‘
- [ ] Writes to UAV indexed by `DispatchRaysIndex` β€” πŸ‘
- [ ] Calls `TraceRay` and consumes the returned payload β€” πŸ‘

### Miss shader (`[shader("miss")]`)
- [ ] Miss runs when no geometry is hit and payload is observable in raygen β€” πŸ‘
- [ ] Multiple miss shaders, `MissShaderIndex` selects between them β€” πŸ‘
- [ ] Miss-side ray-system-values: `WorldRayOrigin`, `WorldRayDirection`, `RayTMin`, `RayTCurrent`, `RayFlags`, `DispatchRaysIndex` β€” πŸ‘

### Closest-hit shader (`[shader("closesthit")]`)
- [ ] Runs exactly once per accepted hit; payload mutation observable in raygen β€” πŸ‘
- [ ] Hit-side ray-system-values: all of the miss-side ones plus `InstanceIndex`, `InstanceID`, `PrimitiveIndex`, `GeometryIndex`, `HitKind`, `ObjectRayOrigin/Direction`, `ObjectToWorld3x4/4x3`, `WorldToObject3x4/4x3` β€” πŸ‘
- [ ] `BuiltInTriangleIntersectionAttributes.barycentrics` at known points β€” πŸ‘
- [ ] Hit-group routing: distinct closest-hit per hit-group, selected by `RayContributionToHitGroupIndex` + instance contribution β€” πŸ‘
- [ ] Closest-hit calls `TraceRay` to spawn a secondary ray (recursion) β€” πŸ‘

### Any-hit shader (`[shader("anyhit")]`)
- [ ] Any-hit fires for non-opaque geometry only β€” πŸ—οΈ (non-opaque YAML)
- [ ] `IgnoreHit()` skips a candidate; closest-hit sees next hit β€” πŸ—οΈ
- [ ] `AcceptHitAndEndSearch()` ends traversal immediately β€” πŸ—οΈ
- [ ] Any-hit can mutate payload before `IgnoreHit` (and the mutation must be discarded per spec) β€” πŸ—οΈ
- [ ] Per-geometry `NO_DUPLICATE_ANYHIT_INVOCATION` β€” πŸ—οΈ (geometry flag YAML)

### Intersection shader (`[shader("intersection")]`)
- [ ] `ReportHit(t, kind, attrs)` with custom hit-attribute struct β€” πŸ—οΈ (procedural geometry)
- [ ] Custom `HitKind` value flows through to closest-hit / any-hit β€” πŸ—οΈ
- [ ] `ReportHit` returns true/false based on TMin/TMax + any-hit decision β€” πŸ—οΈ
- [ ] Intersection-side ray-system-values match the rest β€” πŸ—οΈ

### Callable shader (`[shader("callable")]`)
- [ ] `CallShader(index, params)` runs the right callable record β€” πŸ‘
- [ ] Callable can be invoked from raygen, miss, closest-hit, callable β€” πŸ‘
- [ ] `DispatchRaysIndex` / `Dimensions` visible inside callable β€” πŸ‘

### Payload + attribute mechanics
- [ ] Trivial payload (single `uint`) round-trip β€” πŸ‘
- [ ] Large payload near `MaxPayloadSizeInBytes` β€” πŸ‘
- [ ] `[payload]` qualifier `in` / `out` / `inout` semantics β€” πŸ‘
- [ ] Custom hit attribute struct from an intersection shader β€” πŸ—οΈ
- [ ] Payload struct with mixed types (float/int/half) β€” πŸ‘

### Hit-group / SBT selection (shader-observable)
- [ ] `InstanceContributionToHitGroupIndex` selects per-instance hit group β€” πŸ—οΈ (YAML field shared with #1258)
- [ ] `RayContributionToHitGroupIndex` per `TraceRay` call β€” πŸ‘
- [ ] `MultiplierForGeometryContributionToHitGroupIndex` across multi-geom BLAS β€” πŸ—οΈ (multi-geom YAML)
- [ ] Local-root constants in an SBT record are visible to the shader β€” πŸ‘

### Shader control flow / vendor edges
- [ ] Divergent rays per lane (different hit-groups invoked) β€” πŸ‘
- [ ] Conditional `TraceRay` (lane mask) β€” πŸ‘
- [ ] `TraceRay` with `RAY_FLAG_SKIP_CLOSEST_HIT_SHADER` (PSO-only flag) β€” πŸ‘
- [ ] Mix of opaque and non-opaque BLAS in one pipeline β€” πŸ—οΈ
- [ ] Same ray flag matrix as #1258 for parity β€” πŸ‘

## Out of scope (intentionally)

- AS build flags / compaction / refit / clone / serialize β€” not shader-visible; same reasoning as #1258.
- DXR 1.2 / `SER` (ShaderExecutionReordering) β€” future epic once base PSO RT works on all three backends.
- Work-graph dispatched RT β€” separate feature.

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up β€” it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with Support/Pipeline.h and the foundational ray-tracing smoke test described under the bring-up PRs, then read #1270 and the related backend work. The epic is done when the framework supports the listed PSO ray-tracing pipelines, shader binding tables, DispatchRays, and the specified shader-observable coverage across the three backends.

Written by the indexing model from the issue text.

Assessment

Tech stack
cpp
Domain
computer-graphics, testing-qa
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Quiet
Clarity
Needs clarification
Newbie friendliness
25/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.