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, 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)]
308#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
309pub struct TraceBlasTriangleGeometry {
310 pub size: wgt::BlasTriangleGeometrySizeDescriptor,
311 pub vertex_buffer: BufferId,
312 pub index_buffer: Option<BufferId>,
313 pub transform_buffer: Option<BufferId>,
314 pub first_vertex: u32,
315 pub vertex_stride: BufferAddress,
316 pub first_index: Option<u32>,
317 pub transform_buffer_offset: Option<BufferAddress>,
318}
319
320#[derive(Debug, Clone)]
321#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
322pub enum TraceBlasGeometries {
323 TriangleGeometries(Vec<TraceBlasTriangleGeometry>),
324}
325
326#[derive(Debug, Clone)]
327#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
328pub struct TraceBlasBuildEntry {
329 pub blas_id: BlasId,
330 pub geometries: TraceBlasGeometries,
331}
332
333#[derive(Debug, Clone)]
334#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
335pub struct TraceTlasInstance {
336 pub blas_id: BlasId,
337 pub transform: [f32; 12],
338 pub custom_data: u32,
339 pub mask: u8,
340}
341
342#[derive(Debug, Clone)]
343#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
344pub struct TraceTlasPackage {
345 pub tlas_id: TlasId,
346 pub instances: Vec<Option<TraceTlasInstance>>,
347 pub lowest_unmodified: u32,
348}
349
350#[derive(Clone, Debug, Error)]
351pub enum BlasPrepareCompactError {
352 #[error(transparent)]
353 Device(#[from] DeviceError),
354 #[error(transparent)]
355 InvalidResource(#[from] InvalidResourceError),
356 #[error("Compaction is already being prepared")]
357 CompactionPreparingAlready,
358 #[error("Cannot compact an already compacted BLAS")]
359 DoubleCompaction,
360 #[error("BLAS is not yet built")]
361 NotBuilt,
362 #[error("BLAS does not support compaction (is AccelerationStructureFlags::ALLOW_COMPACTION missing?)")]
363 CompactionUnsupported,
364}
365
366impl WebGpuError for BlasPrepareCompactError {
367 fn webgpu_error_type(&self) -> ErrorType {
368 let e: &dyn WebGpuError = match self {
369 Self::Device(e) => e,
370 Self::InvalidResource(e) => e,
371 Self::CompactionPreparingAlready
372 | Self::DoubleCompaction
373 | Self::NotBuilt
374 | Self::CompactionUnsupported => return ErrorType::Validation,
375 };
376 e.webgpu_error_type()
377 }
378}
379
380#[derive(Clone, Debug, Error)]
381pub enum CompactBlasError {
382 #[error(transparent)]
383 Encoder(#[from] EncoderStateError),
384
385 #[error(transparent)]
386 Device(#[from] DeviceError),
387
388 #[error(transparent)]
389 InvalidResource(#[from] InvalidResourceError),
390
391 #[error(transparent)]
392 DestroyedResource(#[from] DestroyedResourceError),
393
394 #[error(transparent)]
395 MissingFeatures(#[from] MissingFeatures),
396
397 #[error("BLAS was not prepared for compaction")]
398 BlasNotReady,
399}
400
401impl WebGpuError for CompactBlasError {
402 fn webgpu_error_type(&self) -> ErrorType {
403 let e: &dyn WebGpuError = match self {
404 Self::Encoder(e) => e,
405 Self::Device(e) => e,
406 Self::InvalidResource(e) => e,
407 Self::DestroyedResource(e) => e,
408 Self::MissingFeatures(e) => e,
409 Self::BlasNotReady => return ErrorType::Validation,
410 };
411 e.webgpu_error_type()
412 }
413}
414
415pub type BlasCompactReadyPendingClosure = (Option<BlasCompactCallback>, BlasPrepareCompactResult);