wgpu/api/
tlas.rs

1use crate::{api::blas::TlasInstance, dispatch};
2use crate::{BindingResource, Label};
3use alloc::vec::Vec;
4#[cfg(wgpu_core)]
5use core::ops::Deref;
6use core::ops::{Index, IndexMut, Range};
7use wgt::WasmNotSendSync;
8
9/// Descriptor to create top level acceleration structures.
10pub type CreateTlasDescriptor<'a> = wgt::CreateTlasDescriptor<Label<'a>>;
11static_assertions::assert_impl_all!(CreateTlasDescriptor<'_>: Send, Sync);
12
13#[derive(Debug, Clone)]
14/// Top Level Acceleration Structure (TLAS).
15///
16/// A TLAS contains a series of [TLAS instances], which are a reference to
17/// a BLAS and a transformation matrix placing the geometry in the world.
18///
19/// A TLAS also contains an extra set of TLAS instances in a device readable form, you cant interact
20/// directly with these, instead you have to build the TLAS with [TLAS instances].
21///
22/// [TLAS instances]: TlasInstance
23pub struct Tlas {
24    pub(crate) inner: dispatch::DispatchTlas,
25    pub(crate) instances: Vec<Option<TlasInstance>>,
26    pub(crate) lowest_unmodified: u32,
27}
28static_assertions::assert_impl_all!(Tlas: WasmNotSendSync);
29
30crate::cmp::impl_eq_ord_hash_proxy!(Tlas => .inner);
31
32impl Tlas {
33    /// Get the [`wgpu_hal`] acceleration structure from this `Tlas`.
34    ///
35    /// Find the Api struct corresponding to the active backend in [`wgpu_hal::api`],
36    /// and pass that struct to the to the `A` type parameter.
37    ///
38    /// Returns a guard that dereferences to the type of the hal backend
39    /// which implements [`A::AccelerationStructure`].
40    ///
41    /// # Types
42    ///
43    /// The returned type depends on the backend:
44    ///
45    #[doc = crate::macros::hal_type_vulkan!("AccelerationStructure")]
46    #[doc = crate::macros::hal_type_metal!("AccelerationStructure")]
47    #[doc = crate::macros::hal_type_dx12!("AccelerationStructure")]
48    #[doc = crate::macros::hal_type_gles!("AccelerationStructure")]
49    ///
50    /// # Deadlocks
51    ///
52    /// - The returned guard holds a read-lock on a device-local "destruction"
53    ///   lock, which will cause all calls to `destroy` to block until the
54    ///   guard is released.
55    ///
56    /// # Errors
57    ///
58    /// This method will return None if:
59    /// - The acceleration structure is not from the backend specified by `A`.
60    /// - The acceleration structure is from the `webgpu` or `custom` backend.
61    ///
62    /// # Safety
63    ///
64    /// - The returned resource must not be destroyed unless the guard
65    ///   is the last reference to it and it is not in use by the GPU.
66    ///   The guard and handle may be dropped at any time however.
67    /// - All the safety requirements of wgpu-hal must be upheld.
68    ///
69    /// [`A::AccelerationStructure`]: hal::Api::AccelerationStructure
70    #[cfg(wgpu_core)]
71    pub unsafe fn as_hal<A: hal::Api>(
72        &mut self,
73    ) -> Option<impl Deref<Target = A::AccelerationStructure>> {
74        let tlas = self.inner.as_core_opt()?;
75        unsafe { tlas.context.tlas_as_hal::<A>(tlas) }
76    }
77
78    /// Returns custom implementation of Tlas (if custom backend and is internally T)
79    #[cfg(custom)]
80    pub fn as_custom<T: crate::custom::TlasInterface>(&self) -> Option<&T> {
81        self.inner.as_custom()
82    }
83    /// Returns the index of the first instance that has not been modified since the last build.
84    /// Custom backends use this to perform partial TLAS updates.
85    #[cfg(custom)]
86    pub fn lowest_unmodified(&self) -> u32 {
87        self.lowest_unmodified
88    }
89
90    /// Get a reference to all instances.
91    pub fn get(&self) -> &[Option<TlasInstance>] {
92        &self.instances
93    }
94
95    /// Get a mutable slice to a range of instances.
96    /// Returns None if the range is out of bounds.
97    /// All elements from the lowest accessed index up are marked as modified.
98    // this recommendation is not useful yet, but is likely to be when ability to update arrives or possible optimisations for building get implemented.
99    /// For best performance it is recommended to prefer access to low elements and modify higher elements as little as possible.
100    /// This can be done by ordering instances from the most to the least used. It is recommended
101    /// to use [`Self::index_mut`] unless the option if out of bounds is required
102    pub fn get_mut_slice(&mut self, range: Range<usize>) -> Option<&mut [Option<TlasInstance>]> {
103        if range.end > self.instances.len() {
104            return None;
105        }
106        if range.end as u32 > self.lowest_unmodified {
107            self.lowest_unmodified = range.end as u32;
108        }
109        Some(&mut self.instances[range])
110    }
111
112    /// Get a single mutable reference to an instance.
113    /// Returns None if the range is out of bounds.
114    /// All elements from the lowest accessed index up are marked as modified.
115    // this recommendation is not useful yet, but is likely to be when ability to update arrives or possible optimisations for building get implemented.
116    /// For best performance it is recommended to prefer access to low elements and modify higher elements as little as possible.
117    /// This can be done by ordering instances from the most to the least used. It is recommended
118    /// to use [`Self::index_mut`] unless the option if out of bounds is required
119    pub fn get_mut_single(&mut self, index: usize) -> Option<&mut Option<TlasInstance>> {
120        if index >= self.instances.len() {
121            return None;
122        }
123        if index as u32 + 1 > self.lowest_unmodified {
124            self.lowest_unmodified = index as u32 + 1;
125        }
126        Some(&mut self.instances[index])
127    }
128
129    /// Get the binding resource for the underling acceleration structure, to be used when creating a [`BindGroup`]
130    ///
131    /// [`BindGroup`]: super::BindGroup
132    pub fn as_binding(&self) -> BindingResource<'_> {
133        BindingResource::AccelerationStructure(self)
134    }
135}
136
137impl Index<usize> for Tlas {
138    type Output = Option<TlasInstance>;
139
140    fn index(&self, index: usize) -> &Self::Output {
141        self.instances.index(index)
142    }
143}
144
145impl Index<Range<usize>> for Tlas {
146    type Output = [Option<TlasInstance>];
147
148    fn index(&self, index: Range<usize>) -> &Self::Output {
149        self.instances.index(index)
150    }
151}
152
153impl IndexMut<usize> for Tlas {
154    fn index_mut(&mut self, index: usize) -> &mut Self::Output {
155        let idx = self.instances.index_mut(index);
156        if index as u32 + 1 > self.lowest_unmodified {
157            self.lowest_unmodified = index as u32 + 1;
158        }
159        idx
160    }
161}
162
163impl IndexMut<Range<usize>> for Tlas {
164    fn index_mut(&mut self, index: Range<usize>) -> &mut Self::Output {
165        let idx = self.instances.index_mut(index.clone());
166        if index.end > self.lowest_unmodified as usize {
167            self.lowest_unmodified = index.end as u32;
168        }
169        idx
170    }
171}