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