Skip to content

Commit 6f97146

Browse files
jenatalidamyanp
andauthored
[0045] ClusterID() support (#630)
Replaces #560 and #561 with a merged spec. Replaces sponsor. This one in particular should be pretty straightforward, it's just a scalar accessor that follows the existing patterns for all other raytracing scalar accessors. --------- Co-authored-by: Damyan Pepper <[email protected]>
1 parent 0c7753e commit 6f97146

File tree

1 file changed

+274
-0
lines changed

1 file changed

+274
-0
lines changed
Lines changed: 274 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,274 @@
1+
---
2+
title: 0045 - HLSL support for Clustered Geometry in Raytracing
3+
params:
4+
authors:
5+
- jschmid-nvidia: Jan Schmid
6+
- simoll: Simon Moll
7+
sponsors:
8+
- jenatali: Jesse Natalie
9+
status: Under Review
10+
---
11+
12+
## Introduction
13+
14+
Acceleration structure build times can become a bottleneck in raytracing
15+
applications that require large amounts of dynamic geometry. Example scenarios
16+
include new geometry being streamed in from disk, high numbers of animated
17+
objects, level-of-detail systems, or dynamic tessellation.
18+
19+
Clustered Geometry is a proposed future DXR feature that aims to address this
20+
issue by enabling the application to construct bottom-level acceleration structures
21+
from previously generated clusters of primitives, resulting in significant speedups
22+
in acceleration structure build times. The DXR spec details for this are not available
23+
yet, but as an example for now see [NVIDIA's blog](https://developer.nvidia.com/blog/nvidia-rtx-mega-geometry-now-available-with-new-vulkan-samples/) describing the overall concept of clustered
24+
geometry (among other topics).
25+
26+
How clustered geometry gets exposed in D3D overall is to be determined but this document is
27+
certainly a part: a proposal for the HLSL operations needed for clustered geometry.
28+
29+
## Motivation
30+
31+
Clustered Geometry refers to a building block for Bottom Level Acceleration Structures
32+
(BLASes). Most of the details of what a cluster is are out of scope for this spec.
33+
What's relevant is that the application can build BLASes out of cluster building
34+
blocks. When raytracing, hit shaders will want to know the ID of the cluster that is hit
35+
so the shader can do things like look up cluster-specific user data. Hence the need for a `ClusterID()` intrinsic.
36+
37+
This isn't an index into the clusters in a given BLAS but rather an ID assigned by
38+
the user for each cluster in a BLAS. Different BLASs could reuse simmilar building blocks, and
39+
thus share cluster ID.
40+
41+
## HLSL
42+
43+
### Enums
44+
45+
```C
46+
enum CLUSTER_ID_CONSTANTS : uint
47+
{
48+
CLUSTER_ID_INVALID = 0xffffffff,
49+
};
50+
```
51+
52+
ClusterID values returned by [ClusterID()](#clusterid) with predefined meaning
53+
54+
Value | Definition
55+
----- | ----
56+
`CLUSTER_ID_INVALID` | Returned if a BLAS was intersected that was not constructed from CLAS
57+
58+
### DXR 1.0 System Value Intrinsics
59+
60+
A new DXR System Value Intrinsic is added to support fetching the `ClusterID` of an intersected CLAS.
61+
62+
#### ClusterID
63+
64+
```C
65+
uint ClusterID()
66+
```
67+
68+
Returns a `uint` containing the user-defined `ClusterID` value a CLAS was
69+
built with. If a non-clustered BLAS was intersected, `CLUSTER_ID_INVALID`
70+
is returned.
71+
72+
The following table shows which shaders can access it:
73+
| **values \\ shaders** | ray generation | intersection | any hit | closest hit | miss | callable |
74+
|:---------------------------------------------------------:|:--------------:|:------------:|:-------:|:-----------:|:----:|:--------:|
75+
| *Primitive/object space system values:* | | | | | | |
76+
| uint [ClusterID()](#clusterid) | | | \* | \* | | |
77+
78+
## Extension to DXR 1.1 RayQuery API
79+
80+
New intrinsics [CandidateClusterID()](#rayquery-candidateclusterid) and
81+
[CommittedClusterID()](#rayquery-committedclusterid) are added to `RayQuery`.
82+
Behavior of all other intrinsics is unchanged.
83+
84+
### RayQuery intrinsics
85+
86+
The following table lists intrinsics available when
87+
[RayQuery::Proceed()](https://github.com/microsoft/DirectX-Specs/blob/master/d3d/Raytracing.md#rayquery-proceed) returned `TRUE`,
88+
meaning a type of hit candidate that requires shader evaluation has been found.
89+
Methods named `Committed*()` in this table may actually not be available
90+
depending on the current [CommittedStatus()](https://github.com/microsoft/DirectX-Specs/blob/master/d3d/Raytracing.md#rayquery-committedstatus)
91+
(i.e. what type of hit has been committed yet, if any) - this is further
92+
clarified in another table further below.
93+
94+
| **Intrinsic** \ **CandidateType()** | `HIT_CANDIDATE_NON_OPAQUE_TRIANGLE` | `HIT_CANDIDATE_PROCEDURAL_PRIMITIVE` |
95+
|:---------------------------------------------------------|:-----------------------------------:|:------------------------------------:|
96+
| uint [CandidateClusterID()](#rayquery-candidateclusterid)| \* | |
97+
| uint [CommittedClusterID()](#rayquery-committedclusterid)| \* | |
98+
99+
The following table lists intrinsics available depending on the current
100+
[COMMITTED_STATUS](https://github.com/microsoft/DirectX-Specs/blob/master/d3d/Raytracing.md#committed_status) (i.e. what type of
101+
hit has been committed, if any). This applies regardless of whether
102+
[RayQuery::Proceed()](https://github.com/microsoft/DirectX-Specs/blob/master/d3d/Raytracing.md#rayquery-proceed) has returned
103+
`TRUE` (shader evaluation needed for traversal), or `FALSE` (traversal
104+
complete). If `TRUE`, additional methods than those shown below are
105+
available (see the above table).
106+
107+
| **Intrinsic** \ **CommittedStatus()** | `COMMITTED_TRIANGLE_HIT` | `COMMITTED_PROCEDURAL_PRIMITIVE_HIT` | `COMMITTED_NOTHING` |
108+
|:---------------------------------------------------------|:------------------------:|:------------------------------------:|:-------------------:|
109+
| uint [CommittedClusterID()](#rayquery-committedclusterid)| \* | | |
110+
111+
#### RayQuery CandidateClusterID
112+
113+
The user-provided `ClusterID` of the intersected CLAS, if a Cluster BLAS was
114+
intersected for the current hit candidate.
115+
Returns `CLUSTER_ID_INVALID` if a non-Cluster BLAS was intersected.
116+
117+
```C++
118+
uint RayQuery::CandidateClusterID();
119+
```
120+
121+
[RayQuery intrinsics](#rayquery-intrinsics) illustrates when this is valid to
122+
call.
123+
Lowers to [RayQuery_CandidateClusterID DXIL Opcode](#rayquery_candidateclusterid-dxil-opcode).
124+
125+
#### RayQuery CommittedClusterID
126+
127+
The user-provided `ClusterID` of the intersected CLAS, if a Cluster BLAS was
128+
intersected for the closest hit committed so far.
129+
Returns `CLUSTER_ID_INVALID` if a non-Cluster BLAS was intersected.
130+
131+
```C++
132+
uint RayQuery::CommittedClusterID();
133+
```
134+
135+
[RayQuery intrinsics](#rayquery-intrinsics) illustrates when this is valid to
136+
call.
137+
Lowers to [RayQuery_CommittedClusterID DXIL Opcode](#rayquery_committedclusterid-dxil-opcode).
138+
139+
### Extension to the DXR 1.2 HitObject API
140+
141+
Cluster Geometries are also supported with the HitObject feature.
142+
The following intrinsic is added to `HitObject` type.
143+
144+
#### HitObject::GetClusterID
145+
146+
```C
147+
uint HitObject::GetClusterID();
148+
```
149+
150+
Returns the user-provided `ClusterID` of the intersected CLAS of a hit.
151+
Returns `CLUSTER_ID_INVALID` if a non-Cluster BLAS was intersected or if
152+
the `HitObject` does not encode a hit.
153+
Lowers to [HitObject_ClusterID DXIL Opcode](#hitobject_clusterid-dxil-opcode).
154+
155+
### Diagnostic Changes
156+
157+
This proposal does not introduce or remove diagnostics or warnings.
158+
159+
## Testing
160+
161+
### Unit Tests
162+
163+
#### CodeGen & AST Tests
164+
165+
* Expected AST for new implicit HLSL ops.
166+
* Lowering from HLSL to HL.
167+
* Lowering from HL to DXIL.
168+
* Lowering from HLSL to DXIL.
169+
170+
#### Diagnostics Tests
171+
172+
* Expected error when ClusterID builtins called from unsupported shader kinds.
173+
174+
### DXIL
175+
176+
| Opcode | Opcode name | Description
177+
|:--- |:--- |:---
178+
XXX | ClusterID | Returns the cluster ID of this hit
179+
XXX + 1 | RayQuery_CandidateClusterID | Returns the candidate hit cluster ID
180+
XXX + 2 | RayQuery_CommittedClusterID | Returns the committed hit cluster ID
181+
XXX + 2 | HitObject_ClusterID | Returns the cluster ID of this committed hit
182+
183+
#### ClusterID DXIL Opcode
184+
185+
```DXIL
186+
declare i32 @dx.op.clusterID(
187+
i32) ; Opcode (ClusterID)
188+
nounwind readnone
189+
```
190+
191+
Valid shader kinds defined in [ClusterID HLSL](#clusterid).
192+
193+
#### RayQuery_CandidateClusterID DXIL Opcode
194+
195+
```DXIL
196+
declare i32 @dx.op.rayQuery_StateScalar.i32(
197+
i32, ; Opcode (RayQuery_CandidateClusterID)
198+
i32) ; RayQuery handle
199+
nounwind readonly
200+
```
201+
202+
Validation errors:
203+
* Validate that the RayQuery handle is not `undef`.
204+
205+
#### RayQuery_CommittedClusterID DXIL Opcode
206+
207+
```DXIL
208+
declare i32 @dx.op.rayQuery_StateScalar.i32(
209+
i32, ; Opcode (RayQuery_CommittedClusterID)
210+
i32) ; RayQuery handle
211+
nounwind readonly
212+
```
213+
214+
Validation errors:
215+
* Validate that the RayQuery handle is not `undef`.
216+
217+
#### HitObject_ClusterID DXIL Opcode
218+
219+
```DXIL
220+
declare i32 @dx.op.hitObject_StateScalar.i32(
221+
i32, ; Opcode (HitObject_ClusterID)
222+
%dx.types.HitObject) ; HitObject
223+
nounwind readnone
224+
```
225+
226+
Validation errors:
227+
* Validate that the HitObject is not `undef`.
228+
229+
### Diagnostic Changes
230+
231+
This proposal does not introduce or remove diagnostics or warnings.
232+
233+
### Runtime Additions
234+
235+
TODO: link the DXR spec proposal when available
236+
237+
Note: No unique raytracing tier is required to use this intrinsic. If the device does not support clustered geometry, it must still support returning `CLUSTER_ID_INVALID` from this intrinsic.
238+
239+
## Testing
240+
241+
### Validation Tests
242+
243+
* Valid calls to new DXIL ops pass validation.
244+
* Invalid calls fail validation (undef `i32` RayQuery handle or `%dx.types.HitObject` HitObject parameter).
245+
* Calls in invalid shader stages fail validation.
246+
247+
### Execution Tests
248+
249+
#### ClusterID Execution Tests
250+
251+
Test in both `anyhit` and `closesthit` shader kinds.
252+
253+
* Query for CLAS hit returns expected Cluster ID.
254+
* Query for non-clustered BLAS hit returns `CLUSTER_ID_INVALID`.
255+
256+
#### RayQuery Execution Tests
257+
258+
Test both [RayQuery::CandidateClusterID](#rayquery-candidateclusterid) and [RayQuery::CommittedClusterID](#rayquery-committedclusterid).
259+
Builtins to test in the these RayQuery object states:
260+
261+
* Queries for CLAS committed hits return expected Cluster ID (`COMMITTED_TRIANGLE_HIT`).
262+
* Query for committed cluster ID in no-hit-committed state returns `CLUSTER_ID_INVALID`.
263+
* Queries for candidate cluster ID for CLAS candidate hits return expected Cluster ID (`CANDIDATE_NON_OPAQUE_TRIANGLE` and when first call to `Proceed` returns `FALSE` ).
264+
* Queries for non-clustered BLAS candidate/committed hits return `CLUSTER_ID_INVALID`.
265+
266+
#### HitObject Execution Tests
267+
268+
Test CLAS and non-CLAS hit return expected values for candidate hit.
269+
Builtin [HitObject::GetClusterID](#hitobjectgetclusterid) to test in these HitObject setups:
270+
271+
* Add `HitObject::FromRayQuery` + `HitObject::GetClusterID` variants in [RayQuery execution tests](#rayquery-execution-tests).
272+
* Test expected cluster ID value for HitObject obtained from `HitObject::TraceRay` (CLAS hit, CLAS miss, non-CLAS hit).
273+
* Test `CLUSTER_ID_INVALID` for HitObject constructed from `HitObject::MakeMiss` and `HitObject::MakeNop`.
274+

0 commit comments

Comments
 (0)