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