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 /// # Deadlocks
42 ///
43 /// - The returned guard holds a read-lock on a device-local "destruction"
44 /// lock, which will cause all calls to `destroy` to block until the
45 /// guard is released.
46 ///
47 /// # Errors
48 ///
49 /// This method will return None if:
50 /// - The acceleration structure is not from the backend specified by `A`.
51 /// - The acceleration structure is from the `webgpu` or `custom` backend.
52 ///
53 /// # Safety
54 ///
55 /// - The returned resource must not be destroyed unless the guard
56 /// is the last reference to it and it is not in use by the GPU.
57 /// The guard and handle may be dropped at any time however.
58 /// - All the safety requirements of wgpu-hal must be upheld.
59 ///
60 /// [`A::AccelerationStructure`]: hal::Api::AccelerationStructure
61 #[cfg(wgpu_core)]
62 pub unsafe fn as_hal<A: wgc::hal_api::HalApi>(
63 &mut self,
64 ) -> Option<impl Deref<Target = A::AccelerationStructure>> {
65 let tlas = self.inner.as_core_opt()?;
66 unsafe { tlas.context.tlas_as_hal::<A>(tlas) }
67 }
68
69 #[cfg(custom)]
70 /// Returns custom implementation of Tlas (if custom backend and is internally T)
71 pub fn as_custom<T: crate::custom::TlasInterface>(&self) -> Option<&T> {
72 self.inner.as_custom()
73 }
74
75 /// Get a reference to all instances.
76 pub fn get(&self) -> &[Option<TlasInstance>] {
77 &self.instances
78 }
79
80 /// Get a mutable slice to a range of instances.
81 /// Returns None if the range is out of bounds.
82 /// All elements from the lowest accessed index up are marked as modified.
83 // this recommendation is not useful yet, but is likely to be when ability to update arrives or possible optimisations for building get implemented.
84 /// For best performance it is recommended to prefer access to low elements and modify higher elements as little as possible.
85 /// This can be done by ordering instances from the most to the least used. It is recommended
86 /// to use [`Self::index_mut`] unless the option if out of bounds is required
87 pub fn get_mut_slice(&mut self, range: Range<usize>) -> Option<&mut [Option<TlasInstance>]> {
88 if range.end > self.instances.len() {
89 return None;
90 }
91 if range.end as u32 > self.lowest_unmodified {
92 self.lowest_unmodified = range.end as u32;
93 }
94 Some(&mut self.instances[range])
95 }
96
97 /// Get a single mutable reference to an instance.
98 /// Returns None if the range is out of bounds.
99 /// All elements from the lowest accessed index up are marked as modified.
100 // this recommendation is not useful yet, but is likely to be when ability to update arrives or possible optimisations for building get implemented.
101 /// For best performance it is recommended to prefer access to low elements and modify higher elements as little as possible.
102 /// This can be done by ordering instances from the most to the least used. It is recommended
103 /// to use [`Self::index_mut`] unless the option if out of bounds is required
104 pub fn get_mut_single(&mut self, index: usize) -> Option<&mut Option<TlasInstance>> {
105 if index >= self.instances.len() {
106 return None;
107 }
108 if index as u32 + 1 > self.lowest_unmodified {
109 self.lowest_unmodified = index as u32 + 1;
110 }
111 Some(&mut self.instances[index])
112 }
113
114 /// Get the binding resource for the underling acceleration structure, to be used when creating a [`BindGroup`]
115 ///
116 /// [`BindGroup`]: super::BindGroup
117 pub fn as_binding(&self) -> BindingResource<'_> {
118 BindingResource::AccelerationStructure(self)
119 }
120}
121
122impl Index<usize> for Tlas {
123 type Output = Option<TlasInstance>;
124
125 fn index(&self, index: usize) -> &Self::Output {
126 self.instances.index(index)
127 }
128}
129
130impl Index<Range<usize>> for Tlas {
131 type Output = [Option<TlasInstance>];
132
133 fn index(&self, index: Range<usize>) -> &Self::Output {
134 self.instances.index(index)
135 }
136}
137
138impl IndexMut<usize> for Tlas {
139 fn index_mut(&mut self, index: usize) -> &mut Self::Output {
140 let idx = self.instances.index_mut(index);
141 if index as u32 + 1 > self.lowest_unmodified {
142 self.lowest_unmodified = index as u32 + 1;
143 }
144 idx
145 }
146}
147
148impl IndexMut<Range<usize>> for Tlas {
149 fn index_mut(&mut self, index: Range<usize>) -> &mut Self::Output {
150 let idx = self.instances.index_mut(index.clone());
151 if index.end > self.lowest_unmodified as usize {
152 self.lowest_unmodified = index.end as u32;
153 }
154 idx
155 }
156}