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