1use alloc::{boxed::Box, sync::Arc, vec::Vec};
12
13use thiserror::Error;
14use wgt::{
15 error::{ErrorType, WebGpuError},
16 AccelerationStructureGeometryFlags, BufferAddress, IndexFormat, VertexFormat,
17};
18
19use crate::{
20 command::EncoderStateError,
21 device::{DeviceError, MissingFeatures},
22 id::{BlasId, BufferId, TlasId},
23 resource::{
24 Blas, BlasCompactCallback, BlasPrepareCompactResult, Buffer, DestroyedResourceError,
25 InvalidResourceError, MissingBufferUsageError, ResourceErrorIdent, Tlas,
26 },
27};
28
29#[derive(Clone, Debug, Error)]
30pub enum CreateBlasError {
31 #[error(transparent)]
32 Device(#[from] DeviceError),
33 #[error(transparent)]
34 MissingFeatures(#[from] MissingFeatures),
35 #[error(
36 "Only one of 'index_count' and 'index_format' was provided (either provide both or none)"
37 )]
38 MissingIndexData,
39 #[error("Provided format was not within allowed formats. Provided format: {0:?}. Allowed formats: {1:?}")]
40 InvalidVertexFormat(VertexFormat, Vec<VertexFormat>),
41 #[error("Limit `max_blas_geometry_count` is {0}, but the BLAS had {1} geometries")]
42 TooManyGeometries(u32, u32),
43 #[error(
44 "Limit `max_blas_primitive_count` is {0}, but the BLAS had a maximum of {1} primitives"
45 )]
46 TooManyPrimitives(u32, u32),
47}
48
49impl WebGpuError for CreateBlasError {
50 fn webgpu_error_type(&self) -> ErrorType {
51 let e: &dyn WebGpuError = match self {
52 Self::Device(e) => e,
53 Self::MissingFeatures(e) => e,
54 Self::MissingIndexData
55 | Self::InvalidVertexFormat(..)
56 | Self::TooManyGeometries(..)
57 | Self::TooManyPrimitives(..) => return ErrorType::Validation,
58 };
59 e.webgpu_error_type()
60 }
61}
62
63#[derive(Clone, Debug, Error)]
64pub enum CreateTlasError {
65 #[error(transparent)]
66 Device(#[from] DeviceError),
67 #[error(transparent)]
68 MissingFeatures(#[from] MissingFeatures),
69 #[error("Flag {0:?} is not allowed on a TLAS")]
70 DisallowedFlag(wgt::AccelerationStructureFlags),
71 #[error("Limit `max_tlas_instance_count` is {0}, but the TLAS had a maximum of {1} instances")]
72 TooManyInstances(u32, u32),
73}
74
75impl WebGpuError for CreateTlasError {
76 fn webgpu_error_type(&self) -> ErrorType {
77 let e: &dyn WebGpuError = match self {
78 Self::Device(e) => e,
79 Self::MissingFeatures(e) => e,
80 Self::DisallowedFlag(..) | Self::TooManyInstances(..) => return ErrorType::Validation,
81 };
82 e.webgpu_error_type()
83 }
84}
85
86#[derive(Clone, Debug, Error)]
88pub enum BuildAccelerationStructureError {
89 #[error(transparent)]
90 EncoderState(#[from] EncoderStateError),
91
92 #[error(transparent)]
93 Device(#[from] DeviceError),
94
95 #[error(transparent)]
96 InvalidResource(#[from] InvalidResourceError),
97
98 #[error(transparent)]
99 DestroyedResource(#[from] DestroyedResourceError),
100
101 #[error(transparent)]
102 MissingBufferUsage(#[from] MissingBufferUsageError),
103
104 #[error(transparent)]
105 MissingFeatures(#[from] MissingFeatures),
106
107 #[error(
108 "Buffer {0:?} size is insufficient for provided size information (size: {1}, required: {2}"
109 )]
110 InsufficientBufferSize(ResourceErrorIdent, u64, u64),
111
112 #[error("Buffer {0:?} associated offset doesn't align with the index type")]
113 UnalignedIndexBufferOffset(ResourceErrorIdent),
114
115 #[error("Buffer {0:?} associated offset is unaligned")]
116 UnalignedTransformBufferOffset(ResourceErrorIdent),
117
118 #[error("Buffer {0:?} associated index count not divisible by 3 (count: {1}")]
119 InvalidIndexCount(ResourceErrorIdent, u32),
120
121 #[error("Buffer {0:?} associated data contains None")]
122 MissingAssociatedData(ResourceErrorIdent),
123
124 #[error(
125 "Blas {0:?} build sizes to may be greater than the descriptor at build time specified"
126 )]
127 IncompatibleBlasBuildSizes(ResourceErrorIdent),
128
129 #[error("Blas {0:?} flags are different, creation flags: {1:?}, provided: {2:?}")]
130 IncompatibleBlasFlags(
131 ResourceErrorIdent,
132 AccelerationStructureGeometryFlags,
133 AccelerationStructureGeometryFlags,
134 ),
135
136 #[error("Blas {0:?} build vertex count is greater than creation count (needs to be less than or equal to), creation: {1:?}, build: {2:?}")]
137 IncompatibleBlasVertexCount(ResourceErrorIdent, u32, u32),
138
139 #[error("Blas {0:?} vertex formats are different, creation format: {1:?}, provided: {2:?}")]
140 DifferentBlasVertexFormats(ResourceErrorIdent, VertexFormat, VertexFormat),
141
142 #[error("Blas {0:?} stride was required to be at least {1} but stride given was {2}")]
143 VertexStrideTooSmall(ResourceErrorIdent, u64, u64),
144
145 #[error("Blas {0:?} stride was required to be a multiple of {1} but stride given was {2}")]
146 VertexStrideUnaligned(ResourceErrorIdent, u64, u64),
147
148 #[error("Blas {0:?} index count was provided at creation or building, but not the other")]
149 BlasIndexCountProvidedMismatch(ResourceErrorIdent),
150
151 #[error("Blas {0:?} build index count is greater than creation count (needs to be less than or equal to), creation: {1:?}, build: {2:?}")]
152 IncompatibleBlasIndexCount(ResourceErrorIdent, u32, u32),
153
154 #[error("Blas {0:?} index formats are different, creation format: {1:?}, provided: {2:?}")]
155 DifferentBlasIndexFormats(ResourceErrorIdent, Option<IndexFormat>, Option<IndexFormat>),
156
157 #[error("Blas {0:?} is compacted and so cannot be built")]
158 CompactedBlas(ResourceErrorIdent),
159
160 #[error("Blas {0:?} build sizes require index buffer but none was provided")]
161 MissingIndexBuffer(ResourceErrorIdent),
162
163 #[error(
164 "Tlas {0:?} an associated instances contains an invalid custom index (more than 24bits)"
165 )]
166 TlasInvalidCustomIndex(ResourceErrorIdent),
167
168 #[error(
169 "Tlas {0:?} has {1} active instances but only {2} are allowed as specified by the descriptor at creation"
170 )]
171 TlasInstanceCountExceeded(ResourceErrorIdent, u32, u32),
172
173 #[error("Blas {0:?} has flag USE_TRANSFORM but the transform buffer is missing")]
174 TransformMissing(ResourceErrorIdent),
175
176 #[error("Blas {0:?} is missing the flag USE_TRANSFORM but the transform buffer is set")]
177 UseTransformMissing(ResourceErrorIdent),
178 #[error(
179 "Tlas {0:?} dependent {1:?} is missing AccelerationStructureFlags::ALLOW_RAY_HIT_VERTEX_RETURN"
180 )]
181 TlasDependentMissingVertexReturn(ResourceErrorIdent, ResourceErrorIdent),
182}
183
184impl WebGpuError for BuildAccelerationStructureError {
185 fn webgpu_error_type(&self) -> ErrorType {
186 let e: &dyn WebGpuError = match self {
187 Self::EncoderState(e) => e,
188 Self::Device(e) => e,
189 Self::InvalidResource(e) => e,
190 Self::DestroyedResource(e) => e,
191 Self::MissingBufferUsage(e) => e,
192 Self::MissingFeatures(e) => e,
193 Self::InsufficientBufferSize(..)
194 | Self::UnalignedIndexBufferOffset(..)
195 | Self::UnalignedTransformBufferOffset(..)
196 | Self::InvalidIndexCount(..)
197 | Self::MissingAssociatedData(..)
198 | Self::IncompatibleBlasBuildSizes(..)
199 | Self::IncompatibleBlasFlags(..)
200 | Self::IncompatibleBlasVertexCount(..)
201 | Self::DifferentBlasVertexFormats(..)
202 | Self::VertexStrideTooSmall(..)
203 | Self::VertexStrideUnaligned(..)
204 | Self::BlasIndexCountProvidedMismatch(..)
205 | Self::IncompatibleBlasIndexCount(..)
206 | Self::DifferentBlasIndexFormats(..)
207 | Self::CompactedBlas(..)
208 | Self::MissingIndexBuffer(..)
209 | Self::TlasInvalidCustomIndex(..)
210 | Self::TlasInstanceCountExceeded(..)
211 | Self::TransformMissing(..)
212 | Self::UseTransformMissing(..)
213 | Self::TlasDependentMissingVertexReturn(..) => return ErrorType::Validation,
214 };
215 e.webgpu_error_type()
216 }
217}
218
219#[derive(Clone, Debug, Error)]
220pub enum ValidateAsActionsError {
221 #[error(transparent)]
222 DestroyedResource(#[from] DestroyedResourceError),
223
224 #[error("Tlas {0:?} is used before it is built")]
225 UsedUnbuiltTlas(ResourceErrorIdent),
226
227 #[error("Blas {0:?} is used before it is built (in Tlas {1:?})")]
228 UsedUnbuiltBlas(ResourceErrorIdent, ResourceErrorIdent),
229
230 #[error("Blas {0:?} is newer than the containing Tlas {1:?}")]
231 BlasNewerThenTlas(ResourceErrorIdent, ResourceErrorIdent),
232}
233
234impl WebGpuError for ValidateAsActionsError {
235 fn webgpu_error_type(&self) -> ErrorType {
236 let e: &dyn WebGpuError = match self {
237 Self::DestroyedResource(e) => e,
238 Self::UsedUnbuiltTlas(..) | Self::UsedUnbuiltBlas(..) | Self::BlasNewerThenTlas(..) => {
239 return ErrorType::Validation
240 }
241 };
242 e.webgpu_error_type()
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
301#[derive(Debug, Clone)]
302pub(crate) enum AsAction {
303 Build(AsBuild),
304 UseTlas(Arc<Tlas>),
305}
306
307#[derive(Debug, Clone)]
309#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
310pub struct TraceBlasTriangleGeometry {
311 pub size: wgt::BlasTriangleGeometrySizeDescriptor,
312 pub vertex_buffer: BufferId,
313 pub index_buffer: Option<BufferId>,
314 pub transform_buffer: Option<BufferId>,
315 pub first_vertex: u32,
316 pub vertex_stride: BufferAddress,
317 pub first_index: Option<u32>,
318 pub transform_buffer_offset: Option<BufferAddress>,
319}
320
321#[derive(Debug, Clone)]
322#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
323pub enum TraceBlasGeometries {
324 TriangleGeometries(Vec<TraceBlasTriangleGeometry>),
325}
326
327#[derive(Debug, Clone)]
328#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
329pub struct TraceBlasBuildEntry {
330 pub blas_id: BlasId,
331 pub geometries: TraceBlasGeometries,
332}
333
334#[derive(Debug, Clone)]
335#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
336pub struct TraceTlasInstance {
337 pub blas_id: BlasId,
338 pub transform: [f32; 12],
339 pub custom_data: u32,
340 pub mask: u8,
341}
342
343#[derive(Debug, Clone)]
344#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
345pub struct TraceTlasPackage {
346 pub tlas_id: TlasId,
347 pub instances: Vec<Option<TraceTlasInstance>>,
348 pub lowest_unmodified: u32,
349}
350
351#[derive(Debug, Clone)]
353pub struct ArcBlasTriangleGeometry {
354 pub size: wgt::BlasTriangleGeometrySizeDescriptor,
355 pub vertex_buffer: Arc<Buffer>,
356 pub index_buffer: Option<Arc<Buffer>>,
357 pub transform_buffer: Option<Arc<Buffer>>,
358 pub first_vertex: u32,
359 pub vertex_stride: BufferAddress,
360 pub first_index: Option<u32>,
361 pub transform_buffer_offset: Option<BufferAddress>,
362}
363
364#[derive(Debug, Clone)]
366pub struct BlasTriangleGeometryInfo {
367 pub size: wgt::BlasTriangleGeometrySizeDescriptor,
368 pub first_vertex: u32,
369 pub vertex_stride: BufferAddress,
370 pub first_index: Option<u32>,
371 pub transform_buffer_offset: Option<BufferAddress>,
372}
373
374#[derive(Debug, Clone)]
375pub enum ArcBlasGeometries {
376 TriangleGeometries(Vec<ArcBlasTriangleGeometry>),
377}
378
379#[derive(Debug, Clone)]
380pub struct ArcBlasBuildEntry {
381 pub blas: Arc<Blas>,
382 pub geometries: ArcBlasGeometries,
383}
384
385#[derive(Debug, Clone)]
386pub struct ArcTlasInstance {
387 pub blas: Arc<Blas>,
388 pub transform: [f32; 12],
389 pub custom_data: u32,
390 pub mask: u8,
391}
392
393#[derive(Debug, Clone)]
394pub struct ArcTlasPackage {
395 pub tlas: Arc<Tlas>,
396 pub instances: Vec<Option<ArcTlasInstance>>,
397 pub lowest_unmodified: u32,
398}
399
400#[derive(Clone, Debug, Error)]
401pub enum BlasPrepareCompactError {
402 #[error(transparent)]
403 Device(#[from] DeviceError),
404 #[error(transparent)]
405 InvalidResource(#[from] InvalidResourceError),
406 #[error("Compaction is already being prepared")]
407 CompactionPreparingAlready,
408 #[error("Cannot compact an already compacted BLAS")]
409 DoubleCompaction,
410 #[error("BLAS is not yet built")]
411 NotBuilt,
412 #[error("BLAS does not support compaction (is AccelerationStructureFlags::ALLOW_COMPACTION missing?)")]
413 CompactionUnsupported,
414}
415
416impl WebGpuError for BlasPrepareCompactError {
417 fn webgpu_error_type(&self) -> ErrorType {
418 let e: &dyn WebGpuError = match self {
419 Self::Device(e) => e,
420 Self::InvalidResource(e) => e,
421 Self::CompactionPreparingAlready
422 | Self::DoubleCompaction
423 | Self::NotBuilt
424 | Self::CompactionUnsupported => return ErrorType::Validation,
425 };
426 e.webgpu_error_type()
427 }
428}
429
430#[derive(Clone, Debug, Error)]
431pub enum CompactBlasError {
432 #[error(transparent)]
433 Encoder(#[from] EncoderStateError),
434
435 #[error(transparent)]
436 Device(#[from] DeviceError),
437
438 #[error(transparent)]
439 InvalidResource(#[from] InvalidResourceError),
440
441 #[error(transparent)]
442 DestroyedResource(#[from] DestroyedResourceError),
443
444 #[error(transparent)]
445 MissingFeatures(#[from] MissingFeatures),
446
447 #[error("BLAS was not prepared for compaction")]
448 BlasNotReady,
449}
450
451impl WebGpuError for CompactBlasError {
452 fn webgpu_error_type(&self) -> ErrorType {
453 let e: &dyn WebGpuError = match self {
454 Self::Encoder(e) => e,
455 Self::Device(e) => e,
456 Self::InvalidResource(e) => e,
457 Self::DestroyedResource(e) => e,
458 Self::MissingFeatures(e) => e,
459 Self::BlasNotReady => return ErrorType::Validation,
460 };
461 e.webgpu_error_type()
462 }
463}
464
465pub type BlasCompactReadyPendingClosure = (Option<BlasCompactCallback>, BlasPrepareCompactResult);