Skip to content

Commit a7184dc

Browse files
committed
HLSL and DXIL support for ClusterID intrinsic
1 parent 6959b19 commit a7184dc

File tree

1 file changed

+310
-0
lines changed

1 file changed

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

0 commit comments

Comments
 (0)