wgpu_core/
ray_tracing.rs

1// Ray tracing
2// Major missing optimizations (no api surface changes needed):
3// - use custom tracker to track build state
4// - no forced rebuilt (build mode deduction)
5// - lazy instance buffer allocation
6// - maybe share scratch and instance staging buffer allocation
7// - partial instance buffer uploads (api surface already designed with this in mind)
8// - ([non performance] extract function in build (rust function extraction with guards is a pain))
9
10use alloc::{boxed::Box, sync::Arc, vec::Vec};
11
12use thiserror::Error;
13use wgt::{AccelerationStructureGeometryFlags, BufferAddress, IndexFormat, VertexFormat};
14
15use crate::{
16    command::CommandEncoderError,
17    device::{DeviceError, MissingFeatures},
18    id::{BlasId, BufferId, TlasId},
19    resource::{
20        Blas, DestroyedResourceError, InvalidResourceError, MissingBufferUsageError,
21        ResourceErrorIdent, Tlas,
22    },
23};
24
25#[derive(Clone, Debug, Error)]
26pub enum CreateBlasError {
27    #[error(transparent)]
28    Device(#[from] DeviceError),
29    #[error(transparent)]
30    MissingFeatures(#[from] MissingFeatures),
31    #[error(
32        "Only one of 'index_count' and 'index_format' was provided (either provide both or none)"
33    )]
34    MissingIndexData,
35    #[error("Provided format was not within allowed formats. Provided format: {0:?}. Allowed formats: {1:?}")]
36    InvalidVertexFormat(VertexFormat, Vec<VertexFormat>),
37}
38
39#[derive(Clone, Debug, Error)]
40pub enum CreateTlasError {
41    #[error(transparent)]
42    Device(#[from] DeviceError),
43    #[error(transparent)]
44    MissingFeatures(#[from] MissingFeatures),
45    #[error("Flag {0:?} is not allowed on a TLAS")]
46    DisallowedFlag(wgt::AccelerationStructureFlags),
47}
48
49/// Error encountered while attempting to do a copy on a command encoder.
50#[derive(Clone, Debug, Error)]
51pub enum BuildAccelerationStructureError {
52    #[error(transparent)]
53    Encoder(#[from] CommandEncoderError),
54
55    #[error(transparent)]
56    Device(#[from] DeviceError),
57
58    #[error(transparent)]
59    InvalidResource(#[from] InvalidResourceError),
60
61    #[error(transparent)]
62    DestroyedResource(#[from] DestroyedResourceError),
63
64    #[error(transparent)]
65    MissingBufferUsage(#[from] MissingBufferUsageError),
66
67    #[error(transparent)]
68    MissingFeatures(#[from] MissingFeatures),
69
70    #[error(
71        "Buffer {0:?} size is insufficient for provided size information (size: {1}, required: {2}"
72    )]
73    InsufficientBufferSize(ResourceErrorIdent, u64, u64),
74
75    #[error("Buffer {0:?} associated offset doesn't align with the index type")]
76    UnalignedIndexBufferOffset(ResourceErrorIdent),
77
78    #[error("Buffer {0:?} associated offset is unaligned")]
79    UnalignedTransformBufferOffset(ResourceErrorIdent),
80
81    #[error("Buffer {0:?} associated index count not divisible by 3 (count: {1}")]
82    InvalidIndexCount(ResourceErrorIdent, u32),
83
84    #[error("Buffer {0:?} associated data contains None")]
85    MissingAssociatedData(ResourceErrorIdent),
86
87    #[error(
88        "Blas {0:?} build sizes to may be greater than the descriptor at build time specified"
89    )]
90    IncompatibleBlasBuildSizes(ResourceErrorIdent),
91
92    #[error("Blas {0:?} flags are different, creation flags: {1:?}, provided: {2:?}")]
93    IncompatibleBlasFlags(
94        ResourceErrorIdent,
95        AccelerationStructureGeometryFlags,
96        AccelerationStructureGeometryFlags,
97    ),
98
99    #[error("Blas {0:?} build vertex count is greater than creation count (needs to be less than or equal to), creation: {1:?}, build: {2:?}")]
100    IncompatibleBlasVertexCount(ResourceErrorIdent, u32, u32),
101
102    #[error("Blas {0:?} vertex formats are different, creation format: {1:?}, provided: {2:?}")]
103    DifferentBlasVertexFormats(ResourceErrorIdent, VertexFormat, VertexFormat),
104
105    #[error("Blas {0:?} index count was provided at creation or building, but not the other")]
106    BlasIndexCountProvidedMismatch(ResourceErrorIdent),
107
108    #[error("Blas {0:?} build index count is greater than creation count (needs to be less than or equal to), creation: {1:?}, build: {2:?}")]
109    IncompatibleBlasIndexCount(ResourceErrorIdent, u32, u32),
110
111    #[error("Blas {0:?} index formats are different, creation format: {1:?}, provided: {2:?}")]
112    DifferentBlasIndexFormats(ResourceErrorIdent, Option<IndexFormat>, Option<IndexFormat>),
113
114    #[error("Blas {0:?} build sizes require index buffer but none was provided")]
115    MissingIndexBuffer(ResourceErrorIdent),
116
117    #[error(
118        "Tlas {0:?} an associated instances contains an invalid custom index (more than 24bits)"
119    )]
120    TlasInvalidCustomIndex(ResourceErrorIdent),
121
122    #[error(
123        "Tlas {0:?} has {1} active instances but only {2} are allowed as specified by the descriptor at creation"
124    )]
125    TlasInstanceCountExceeded(ResourceErrorIdent, u32, u32),
126
127    #[error("Blas {0:?} has flag USE_TRANSFORM but the transform buffer is missing")]
128    TransformMissing(ResourceErrorIdent),
129
130    #[error("Blas {0:?} is missing the flag USE_TRANSFORM but the transform buffer is set")]
131    UseTransformMissing(ResourceErrorIdent),
132    #[error(
133        "Tlas {0:?} dependent {1:?} is missing AccelerationStructureFlags::ALLOW_RAY_HIT_VERTEX_RETURN"
134    )]
135    TlasDependentMissingVertexReturn(ResourceErrorIdent, ResourceErrorIdent),
136}
137
138#[derive(Clone, Debug, Error)]
139pub enum ValidateAsActionsError {
140    #[error(transparent)]
141    DestroyedResource(#[from] DestroyedResourceError),
142
143    #[error("Tlas {0:?} is used before it is built")]
144    UsedUnbuiltTlas(ResourceErrorIdent),
145
146    #[error("Blas {0:?} is used before it is built (in Tlas {1:?})")]
147    UsedUnbuiltBlas(ResourceErrorIdent, ResourceErrorIdent),
148
149    #[error("Blas {0:?} is newer than the containing Tlas {1:?}")]
150    BlasNewerThenTlas(ResourceErrorIdent, ResourceErrorIdent),
151}
152
153#[derive(Debug)]
154pub struct BlasTriangleGeometry<'a> {
155    pub size: &'a wgt::BlasTriangleGeometrySizeDescriptor,
156    pub vertex_buffer: BufferId,
157    pub index_buffer: Option<BufferId>,
158    pub transform_buffer: Option<BufferId>,
159    pub first_vertex: u32,
160    pub vertex_stride: BufferAddress,
161    pub first_index: Option<u32>,
162    pub transform_buffer_offset: Option<BufferAddress>,
163}
164
165pub enum BlasGeometries<'a> {
166    TriangleGeometries(Box<dyn Iterator<Item = BlasTriangleGeometry<'a>> + 'a>),
167}
168
169pub struct BlasBuildEntry<'a> {
170    pub blas_id: BlasId,
171    pub geometries: BlasGeometries<'a>,
172}
173
174#[derive(Debug, Clone)]
175#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
176pub struct TlasBuildEntry {
177    pub tlas_id: TlasId,
178    pub instance_buffer_id: BufferId,
179    pub instance_count: u32,
180}
181
182#[derive(Debug)]
183pub struct TlasInstance<'a> {
184    pub blas_id: BlasId,
185    pub transform: &'a [f32; 12],
186    pub custom_data: u32,
187    pub mask: u8,
188}
189
190pub struct TlasPackage<'a> {
191    pub tlas_id: TlasId,
192    pub instances: Box<dyn Iterator<Item = Option<TlasInstance<'a>>> + 'a>,
193    pub lowest_unmodified: u32,
194}
195
196#[derive(Debug, Clone)]
197pub(crate) struct TlasBuild {
198    pub tlas: Arc<Tlas>,
199    pub dependencies: Vec<Arc<Blas>>,
200}
201
202#[derive(Debug, Clone, Default)]
203pub(crate) struct AsBuild {
204    pub blas_s_built: Vec<Arc<Blas>>,
205    pub tlas_s_built: Vec<TlasBuild>,
206}
207
208#[derive(Debug, Clone)]
209pub(crate) enum AsAction {
210    Build(AsBuild),
211    UseTlas(Arc<Tlas>),
212}
213
214#[derive(Debug, Clone)]
215#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
216pub struct TraceBlasTriangleGeometry {
217    pub size: wgt::BlasTriangleGeometrySizeDescriptor,
218    pub vertex_buffer: BufferId,
219    pub index_buffer: Option<BufferId>,
220    pub transform_buffer: Option<BufferId>,
221    pub first_vertex: u32,
222    pub vertex_stride: BufferAddress,
223    pub first_index: Option<u32>,
224    pub transform_buffer_offset: Option<BufferAddress>,
225}
226
227#[derive(Debug, Clone)]
228#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
229pub enum TraceBlasGeometries {
230    TriangleGeometries(Vec<TraceBlasTriangleGeometry>),
231}
232
233#[derive(Debug, Clone)]
234#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
235pub struct TraceBlasBuildEntry {
236    pub blas_id: BlasId,
237    pub geometries: TraceBlasGeometries,
238}
239
240#[derive(Debug, Clone)]
241#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
242pub struct TraceTlasInstance {
243    pub blas_id: BlasId,
244    pub transform: [f32; 12],
245    pub custom_data: u32,
246    pub mask: u8,
247}
248
249#[derive(Debug, Clone)]
250#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
251pub struct TraceTlasPackage {
252    pub tlas_id: TlasId,
253    pub instances: Vec<Option<TraceTlasInstance>>,
254    pub lowest_unmodified: u32,
255}