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