1use alloc::{boxed::Box, sync::Arc, vec::Vec};
12
13#[cfg(feature = "serde")]
14use macro_rules_attribute::apply;
15use thiserror::Error;
16use wgt::{
17 error::{ErrorType, WebGpuError},
18 AccelerationStructureGeometryFlags, BufferAddress, IndexFormat, VertexFormat,
19};
20
21#[cfg(feature = "serde")]
22use crate::command::serde_object_reference_struct;
23use crate::{
24 command::{ArcReferences, EncoderStateError, IdReferences, ReferenceType},
25 device::{DeviceError, MissingFeatures},
26 id::{BlasId, BufferId, TlasId},
27 resource::{
28 Blas, BlasCompactCallback, BlasPrepareCompactResult, DestroyedResourceError,
29 InvalidResourceError, MissingBufferUsageError, ResourceErrorIdent, Tlas,
30 },
31};
32
33#[derive(Clone, Debug, Error)]
34pub enum CreateBlasError {
35 #[error(transparent)]
36 Device(#[from] DeviceError),
37 #[error(transparent)]
38 MissingFeatures(#[from] MissingFeatures),
39 #[error(
40 "Only one of 'index_count' and 'index_format' was provided (either provide both or none)"
41 )]
42 MissingIndexData,
43 #[error("Provided format was not within allowed formats. Provided format: {0:?}. Allowed formats: {1:?}")]
44 InvalidVertexFormat(VertexFormat, Vec<VertexFormat>),
45 #[error("Limit `max_blas_geometry_count` is {0}, but the BLAS had {1} geometries")]
46 TooManyGeometries(u32, u32),
47 #[error(
48 "Limit `max_blas_primitive_count` is {0}, but the BLAS had a maximum of {1} primitives"
49 )]
50 TooManyPrimitives(u32, u32),
51 #[error("AABB geometry stride {0} is invalid (must be >= {1} and a multiple of 8)")]
52 InvalidAabbStride(BufferAddress, BufferAddress),
53}
54
55impl WebGpuError for CreateBlasError {
56 fn webgpu_error_type(&self) -> ErrorType {
57 match self {
58 Self::Device(e) => e.webgpu_error_type(),
59 Self::MissingFeatures(e) => e.webgpu_error_type(),
60 Self::MissingIndexData
61 | Self::InvalidVertexFormat(..)
62 | Self::TooManyGeometries(..)
63 | Self::TooManyPrimitives(..)
64 | Self::InvalidAabbStride(..) => ErrorType::Validation,
65 }
66 }
67}
68
69#[derive(Clone, Debug, Error)]
70pub enum CreateTlasError {
71 #[error(transparent)]
72 Device(#[from] DeviceError),
73 #[error(transparent)]
74 MissingFeatures(#[from] MissingFeatures),
75 #[error("Flag {0:?} is not allowed on a TLAS")]
76 DisallowedFlag(wgt::AccelerationStructureFlags),
77 #[error("Limit `max_tlas_instance_count` is {0}, but the TLAS had a maximum of {1} instances")]
78 TooManyInstances(u32, u32),
79}
80
81impl WebGpuError for CreateTlasError {
82 fn webgpu_error_type(&self) -> ErrorType {
83 match self {
84 Self::Device(e) => e.webgpu_error_type(),
85 Self::MissingFeatures(e) => e.webgpu_error_type(),
86 Self::DisallowedFlag(..) | Self::TooManyInstances(..) => ErrorType::Validation,
87 }
88 }
89}
90
91#[derive(Clone, Debug, Error)]
93pub enum BuildAccelerationStructureError {
94 #[error(transparent)]
95 EncoderState(#[from] EncoderStateError),
96
97 #[error(transparent)]
98 Device(#[from] DeviceError),
99
100 #[error(transparent)]
101 InvalidResource(#[from] InvalidResourceError),
102
103 #[error(transparent)]
104 DestroyedResource(#[from] DestroyedResourceError),
105
106 #[error(transparent)]
107 MissingBufferUsage(#[from] MissingBufferUsageError),
108
109 #[error(transparent)]
110 MissingFeatures(#[from] MissingFeatures),
111
112 #[error(
113 "Data range of {region_size} B starting at offset {offset} would overrun the size {buffer_size} of buffer {buffer_ident:?}"
114 )]
115 InsufficientBufferSize {
116 buffer_ident: ResourceErrorIdent,
117 offset: BufferAddress,
118 region_size: BufferAddress,
119 buffer_size: BufferAddress,
120 },
121
122 #[error(
123 "Offset {offset}, computed as {count} times {stride} B, exceeds the maximum addressable offset 2^32 - 1 within buffer {buffer_ident:?}"
124 )]
125 OffsetLimitedTo4GB {
126 buffer_ident: ResourceErrorIdent,
127 offset: BufferAddress,
128 count: BufferAddress,
129 stride: BufferAddress,
130 },
131
132 #[error("Buffer {0:?} associated offset doesn't align with the index type")]
133 UnalignedIndexBufferOffset(ResourceErrorIdent),
134
135 #[error("Buffer {0:?} associated offset is unaligned")]
136 UnalignedTransformBufferOffset(ResourceErrorIdent),
137
138 #[error("Buffer {0:?} associated index count not divisible by 3 (count: {1}")]
139 InvalidIndexCount(ResourceErrorIdent, u32),
140
141 #[error("Buffer {0:?} associated data contains None")]
142 MissingAssociatedData(ResourceErrorIdent),
143
144 #[error(
145 "Blas {0:?} build sizes to may be greater than the descriptor at build time specified"
146 )]
147 IncompatibleBlasBuildSizes(ResourceErrorIdent),
148
149 #[error("Blas {0:?} flags are different, creation flags: {1:?}, provided: {2:?}")]
150 IncompatibleBlasFlags(
151 ResourceErrorIdent,
152 AccelerationStructureGeometryFlags,
153 AccelerationStructureGeometryFlags,
154 ),
155
156 #[error("Blas {0:?} build vertex count is greater than creation count (needs to be less than or equal to), creation: {1:?}, build: {2:?}")]
157 IncompatibleBlasVertexCount(ResourceErrorIdent, u32, u32),
158
159 #[error("Blas {0:?} vertex formats are different, creation format: {1:?}, provided: {2:?}")]
160 DifferentBlasVertexFormats(ResourceErrorIdent, VertexFormat, VertexFormat),
161
162 #[error("Blas {0:?} stride was required to be at least {1} but stride given was {2}")]
163 VertexStrideTooSmall(ResourceErrorIdent, u64, u64),
164
165 #[error("Blas {0:?} stride was required to be a multiple of {1} but stride given was {2}")]
166 VertexStrideUnaligned(ResourceErrorIdent, u64, u64),
167
168 #[error("Blas {0:?} index count was provided at creation or building, but not the other")]
169 BlasIndexCountProvidedMismatch(ResourceErrorIdent),
170
171 #[error("Blas {0:?} build index count is greater than creation count (needs to be less than or equal to), creation: {1:?}, build: {2:?}")]
172 IncompatibleBlasIndexCount(ResourceErrorIdent, u32, u32),
173
174 #[error("Blas {0:?} index formats are different, creation format: {1:?}, provided: {2:?}")]
175 DifferentBlasIndexFormats(ResourceErrorIdent, Option<IndexFormat>, Option<IndexFormat>),
176
177 #[error("Blas {0:?} is compacted and so cannot be built")]
178 CompactedBlas(ResourceErrorIdent),
179
180 #[error("Blas {0:?} build sizes require index buffer but none was provided")]
181 MissingIndexBuffer(ResourceErrorIdent),
182
183 #[error(
184 "Tlas {0:?} an associated instances contains an invalid custom index (more than 24bits)"
185 )]
186 TlasInvalidCustomIndex(ResourceErrorIdent),
187
188 #[error(
189 "Tlas {0:?} has {1} active instances but only {2} are allowed as specified by the descriptor at creation"
190 )]
191 TlasInstanceCountExceeded(ResourceErrorIdent, u32, u32),
192
193 #[error("Blas {0:?} has flag USE_TRANSFORM but the transform buffer is missing")]
194 TransformMissing(ResourceErrorIdent),
195
196 #[error("Blas {0:?} is missing the flag USE_TRANSFORM but the transform buffer is set")]
197 UseTransformMissing(ResourceErrorIdent),
198 #[error(
199 "Tlas {0:?} dependent {1:?} is missing AccelerationStructureFlags::ALLOW_RAY_HIT_VERTEX_RETURN"
200 )]
201 TlasDependentMissingVertexReturn(ResourceErrorIdent, ResourceErrorIdent),
202
203 #[error("Blas {0:?} geometry kind at creation does not match build (triangles vs AABBs)")]
204 BlasGeometryKindMismatch(ResourceErrorIdent),
205
206 #[error(
207 "Blas {0:?} build AABB primitive count is greater than creation count (creation: {1}, build: {2})"
208 )]
209 IncompatibleBlasAabbPrimitiveCount(ResourceErrorIdent, u32, u32),
210
211 #[error("Blas {0:?} AABB primitive offset must be a multiple of 8")]
212 UnalignedAabbPrimitiveOffset(ResourceErrorIdent),
213
214 #[error("Blas {0:?} AABB stride is invalid (must be >= {1} and a multiple of 8)")]
215 InvalidAabbStride(ResourceErrorIdent, BufferAddress),
216}
217
218impl WebGpuError for BuildAccelerationStructureError {
219 fn webgpu_error_type(&self) -> ErrorType {
220 match self {
221 Self::EncoderState(e) => e.webgpu_error_type(),
222 Self::Device(e) => e.webgpu_error_type(),
223 Self::InvalidResource(e) => e.webgpu_error_type(),
224 Self::DestroyedResource(e) => e.webgpu_error_type(),
225 Self::MissingBufferUsage(e) => e.webgpu_error_type(),
226 Self::MissingFeatures(e) => e.webgpu_error_type(),
227 Self::InsufficientBufferSize { .. }
228 | Self::OffsetLimitedTo4GB { .. }
229 | Self::UnalignedIndexBufferOffset(..)
230 | Self::UnalignedTransformBufferOffset(..)
231 | Self::InvalidIndexCount(..)
232 | Self::MissingAssociatedData(..)
233 | Self::IncompatibleBlasBuildSizes(..)
234 | Self::IncompatibleBlasFlags(..)
235 | Self::IncompatibleBlasVertexCount(..)
236 | Self::DifferentBlasVertexFormats(..)
237 | Self::VertexStrideTooSmall(..)
238 | Self::VertexStrideUnaligned(..)
239 | Self::BlasIndexCountProvidedMismatch(..)
240 | Self::IncompatibleBlasIndexCount(..)
241 | Self::DifferentBlasIndexFormats(..)
242 | Self::CompactedBlas(..)
243 | Self::MissingIndexBuffer(..)
244 | Self::TlasInvalidCustomIndex(..)
245 | Self::TlasInstanceCountExceeded(..)
246 | Self::TransformMissing(..)
247 | Self::UseTransformMissing(..)
248 | Self::TlasDependentMissingVertexReturn(..)
249 | Self::BlasGeometryKindMismatch(..)
250 | Self::IncompatibleBlasAabbPrimitiveCount(..)
251 | Self::UnalignedAabbPrimitiveOffset(..)
252 | Self::InvalidAabbStride(..) => ErrorType::Validation,
253 }
254 }
255}
256
257#[derive(Clone, Debug, Error)]
258pub enum ValidateAsActionsError {
259 #[error(transparent)]
260 DestroyedResource(#[from] DestroyedResourceError),
261
262 #[error("Tlas {0:?} is used before it is built")]
263 UsedUnbuiltTlas(ResourceErrorIdent),
264
265 #[error("Blas {0:?} is used before it is built (in Tlas {1:?})")]
266 UsedUnbuiltBlas(ResourceErrorIdent, ResourceErrorIdent),
267
268 #[error("Blas {0:?} is newer than the containing Tlas {1:?}")]
269 BlasNewerThenTlas(ResourceErrorIdent, ResourceErrorIdent),
270}
271
272impl WebGpuError for ValidateAsActionsError {
273 fn webgpu_error_type(&self) -> ErrorType {
274 match self {
275 Self::DestroyedResource(e) => e.webgpu_error_type(),
276 Self::UsedUnbuiltTlas(..) | Self::UsedUnbuiltBlas(..) | Self::BlasNewerThenTlas(..) => {
277 ErrorType::Validation
278 }
279 }
280 }
281}
282
283#[derive(Debug)]
284pub struct BlasTriangleGeometry<'a> {
285 pub size: &'a wgt::BlasTriangleGeometrySizeDescriptor,
286 pub vertex_buffer: BufferId,
287 pub index_buffer: Option<BufferId>,
288 pub transform_buffer: Option<BufferId>,
289 pub first_vertex: u32,
290 pub vertex_stride: BufferAddress,
291 pub first_index: Option<u32>,
292 pub transform_buffer_offset: Option<BufferAddress>,
293}
294
295#[derive(Debug)]
296pub struct BlasAabbGeometry<'a> {
297 pub size: &'a wgt::BlasAABBGeometrySizeDescriptor,
298 pub stride: BufferAddress,
299 pub aabb_buffer: BufferId,
300 pub primitive_offset: u32,
301}
302
303pub enum BlasGeometries<'a> {
304 TriangleGeometries(Box<dyn Iterator<Item = BlasTriangleGeometry<'a>> + 'a>),
305 AabbGeometries(Box<dyn Iterator<Item = BlasAabbGeometry<'a>> + 'a>),
306}
307
308pub struct BlasBuildEntry<'a> {
309 pub blas_id: BlasId,
310 pub geometries: BlasGeometries<'a>,
311}
312
313#[derive(Debug, Clone)]
314#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
315pub struct TlasBuildEntry {
316 pub tlas_id: TlasId,
317 pub instance_buffer_id: BufferId,
318 pub instance_count: u32,
319}
320
321#[derive(Debug)]
322pub struct TlasInstance<'a> {
323 pub blas_id: BlasId,
324 pub transform: &'a [f32; 12],
325 pub custom_data: u32,
326 pub mask: u8,
327}
328
329pub struct TlasPackage<'a> {
330 pub tlas_id: TlasId,
331 pub instances: Box<dyn Iterator<Item = Option<TlasInstance<'a>>> + 'a>,
332 pub lowest_unmodified: u32,
333}
334
335#[derive(Debug, Clone)]
336pub(crate) struct TlasBuild {
337 pub tlas: Arc<Tlas>,
338 pub dependencies: Vec<Arc<Blas>>,
339}
340
341#[derive(Debug, Clone, Default)]
342pub(crate) struct AsBuild {
343 pub blas_s_built: Vec<Arc<Blas>>,
344 pub tlas_s_built: Vec<TlasBuild>,
345}
346
347impl AsBuild {
348 pub(crate) fn with_capacity(blas: usize, tlas: usize) -> Self {
349 Self {
350 blas_s_built: Vec::with_capacity(blas),
351 tlas_s_built: Vec::with_capacity(tlas),
352 }
353 }
354}
355
356#[derive(Debug, Clone)]
357pub(crate) enum AsAction {
358 Build(AsBuild),
359 UseTlas(Arc<Tlas>),
360}
361
362#[derive(Debug, Clone)]
364#[cfg_attr(feature = "serde", apply(serde_object_reference_struct))]
365pub struct OwnedBlasTriangleGeometry<R: ReferenceType> {
366 pub size: wgt::BlasTriangleGeometrySizeDescriptor,
367 pub vertex_buffer: R::Buffer,
368 pub index_buffer: Option<R::Buffer>,
369 pub transform_buffer: Option<R::Buffer>,
370 pub first_vertex: u32,
371 pub vertex_stride: BufferAddress,
372 pub first_index: Option<u32>,
373 pub transform_buffer_offset: Option<BufferAddress>,
374}
375
376pub type ArcBlasTriangleGeometry = OwnedBlasTriangleGeometry<ArcReferences>;
377pub type TraceBlasTriangleGeometry = OwnedBlasTriangleGeometry<IdReferences>;
378
379#[derive(Debug, Clone)]
380#[cfg_attr(feature = "serde", apply(serde_object_reference_struct))]
381pub struct OwnedBlasAabbGeometry<R: ReferenceType> {
382 pub size: wgt::BlasAABBGeometrySizeDescriptor,
383 pub stride: BufferAddress,
384 pub aabb_buffer: R::Buffer,
385 pub primitive_offset: u32,
386}
387
388pub type ArcBlasAabbGeometry = OwnedBlasAabbGeometry<ArcReferences>;
389pub type TraceBlasAabbGeometry = OwnedBlasAabbGeometry<IdReferences>;
390
391#[derive(Debug, Clone)]
392#[cfg_attr(feature = "serde", apply(serde_object_reference_struct))]
393pub enum OwnedBlasGeometries<R: ReferenceType> {
394 TriangleGeometries(Vec<OwnedBlasTriangleGeometry<R>>),
395 AabbGeometries(Vec<OwnedBlasAabbGeometry<R>>),
396}
397
398pub type ArcBlasGeometries = OwnedBlasGeometries<ArcReferences>;
399pub type TraceBlasGeometries = OwnedBlasGeometries<IdReferences>;
400
401#[derive(Debug, Clone)]
402#[cfg_attr(feature = "serde", apply(serde_object_reference_struct))]
403pub struct OwnedBlasBuildEntry<R: ReferenceType> {
404 pub blas: R::Blas,
405 pub geometries: OwnedBlasGeometries<R>,
406}
407
408pub type ArcBlasBuildEntry = OwnedBlasBuildEntry<ArcReferences>;
409pub type TraceBlasBuildEntry = OwnedBlasBuildEntry<IdReferences>;
410
411#[derive(Debug, Clone)]
412#[cfg_attr(feature = "serde", apply(serde_object_reference_struct))]
413pub struct OwnedTlasInstance<R: ReferenceType> {
414 pub blas: R::Blas,
415 pub transform: [f32; 12],
416 pub custom_data: u32,
417 pub mask: u8,
418}
419
420pub type ArcTlasInstance = OwnedTlasInstance<ArcReferences>;
421pub type TraceTlasInstance = OwnedTlasInstance<IdReferences>;
422
423#[derive(Debug, Clone)]
424#[cfg_attr(feature = "serde", apply(serde_object_reference_struct))]
425pub struct OwnedTlasPackage<R: ReferenceType> {
426 pub tlas: R::Tlas,
427 pub instances: Vec<Option<OwnedTlasInstance<R>>>,
428 pub lowest_unmodified: u32,
429}
430
431pub type TraceTlasPackage = OwnedTlasPackage<IdReferences>;
432pub type ArcTlasPackage = OwnedTlasPackage<ArcReferences>;
433
434#[derive(Debug, Clone)]
436pub struct BlasTriangleGeometryInfo {
437 pub size: wgt::BlasTriangleGeometrySizeDescriptor,
438 pub first_vertex: u32,
439 pub vertex_stride: BufferAddress,
440 pub first_index: Option<u32>,
441 pub transform_buffer_offset: Option<BufferAddress>,
442}
443
444#[derive(Clone, Debug, Error)]
445pub enum BlasPrepareCompactError {
446 #[error(transparent)]
447 Device(#[from] DeviceError),
448 #[error(transparent)]
449 InvalidResource(#[from] InvalidResourceError),
450 #[error("Compaction is already being prepared")]
451 CompactionPreparingAlready,
452 #[error("Cannot compact an already compacted BLAS")]
453 DoubleCompaction,
454 #[error("BLAS is not yet built")]
455 NotBuilt,
456 #[error("BLAS does not support compaction (is AccelerationStructureFlags::ALLOW_COMPACTION missing?)")]
457 CompactionUnsupported,
458}
459
460impl WebGpuError for BlasPrepareCompactError {
461 fn webgpu_error_type(&self) -> ErrorType {
462 match self {
463 Self::Device(e) => e.webgpu_error_type(),
464 Self::InvalidResource(e) => e.webgpu_error_type(),
465 Self::CompactionPreparingAlready
466 | Self::DoubleCompaction
467 | Self::NotBuilt
468 | Self::CompactionUnsupported => ErrorType::Validation,
469 }
470 }
471}
472
473#[derive(Clone, Debug, Error)]
474pub enum CompactBlasError {
475 #[error(transparent)]
476 Encoder(#[from] EncoderStateError),
477
478 #[error(transparent)]
479 Device(#[from] DeviceError),
480
481 #[error(transparent)]
482 InvalidResource(#[from] InvalidResourceError),
483
484 #[error(transparent)]
485 DestroyedResource(#[from] DestroyedResourceError),
486
487 #[error(transparent)]
488 MissingFeatures(#[from] MissingFeatures),
489
490 #[error("BLAS was not prepared for compaction")]
491 BlasNotReady,
492}
493
494impl WebGpuError for CompactBlasError {
495 fn webgpu_error_type(&self) -> ErrorType {
496 match self {
497 Self::Encoder(e) => e.webgpu_error_type(),
498 Self::Device(e) => e.webgpu_error_type(),
499 Self::InvalidResource(e) => e.webgpu_error_type(),
500 Self::DestroyedResource(e) => e.webgpu_error_type(),
501 Self::MissingFeatures(e) => e.webgpu_error_type(),
502 Self::BlasNotReady => ErrorType::Validation,
503 }
504 }
505}
506
507pub type BlasCompactReadyPendingClosure = (Option<BlasCompactCallback>, BlasPrepareCompactResult);