wgpu/api/tlas.rs
1use alloc::{sync::Arc, vec, vec::Vec};
2use core::ops::{Index, IndexMut, Range};
3
4use crate::{api::blas::TlasInstance, dispatch};
5use crate::{BindingResource, Buffer, Label};
6use wgt::WasmNotSendSync;
7
8/// Descriptor to create top level acceleration structures.
9pub type CreateTlasDescriptor<'a> = wgt::CreateTlasDescriptor<Label<'a>>;
10static_assertions::assert_impl_all!(CreateTlasDescriptor<'_>: Send, Sync);
11
12#[derive(Debug)]
13pub(crate) struct TlasShared {
14 pub(crate) inner: dispatch::DispatchTlas,
15 pub(crate) max_instances: u32,
16}
17
18#[derive(Debug, Clone)]
19/// Top Level Acceleration Structure (TLAS).
20///
21/// A TLAS contains a series of [TLAS instances], which are a reference to
22/// a BLAS and a transformation matrix placing the geometry in the world.
23///
24/// A TLAS contains TLAS instances in a device readable form, you cant interact
25/// directly with these, instead you have to build the TLAS with [TLAS instances].
26///
27/// [TLAS instances]: TlasInstance
28pub struct Tlas {
29 pub(crate) shared: Arc<TlasShared>,
30}
31static_assertions::assert_impl_all!(Tlas: WasmNotSendSync);
32
33crate::cmp::impl_eq_ord_hash_proxy!(Tlas => .shared.inner);
34
35impl Tlas {
36 /// Returns the inner hal Acceleration Structure using a callback. The hal acceleration structure
37 /// will be `None` if the backend type argument does not match with this wgpu Tlas
38 ///
39 /// This method will start the wgpu_core level command recording.
40 ///
41 /// # Safety
42 ///
43 /// - The raw handle obtained from the hal Acceleration Structure must not be manually destroyed
44 /// - If the raw handle is build,
45 #[cfg(wgpu_core)]
46 pub unsafe fn as_hal<
47 A: wgc::hal_api::HalApi,
48 F: FnOnce(Option<&A::AccelerationStructure>) -> R,
49 R,
50 >(
51 &mut self,
52 hal_tlas_callback: F,
53 ) -> R {
54 if let Some(tlas) = self.shared.inner.as_core_opt() {
55 unsafe { tlas.context.tlas_as_hal::<A, F, R>(tlas, hal_tlas_callback) }
56 } else {
57 hal_tlas_callback(None)
58 }
59 }
60}
61
62/// Entry for a top level acceleration structure build.
63/// Used with raw instance buffers for an unvalidated builds.
64/// See [`TlasPackage`] for the safe version.
65pub struct TlasBuildEntry<'a> {
66 /// Reference to the acceleration structure.
67 pub tlas: &'a Tlas,
68 /// Reference to the raw instance buffer, each instance is similar to [`TlasInstance`] but contains a handle to the BLAS.
69 pub instance_buffer: &'a Buffer,
70 /// Number of instances in the instance buffer.
71 pub instance_count: u32,
72}
73static_assertions::assert_impl_all!(TlasBuildEntry<'_>: WasmNotSendSync);
74
75/// The safe version of [`TlasBuildEntry`], containing [`TlasInstance`]s instead of a raw buffer.
76pub struct TlasPackage {
77 pub(crate) tlas: Tlas,
78 pub(crate) instances: Vec<Option<TlasInstance>>,
79 pub(crate) lowest_unmodified: u32,
80}
81static_assertions::assert_impl_all!(TlasPackage: WasmNotSendSync);
82
83impl TlasPackage {
84 /// Construct [`TlasPackage`] consuming the [`Tlas`] (prevents modification of the [`Tlas`] without using this package).
85 pub fn new(tlas: Tlas) -> Self {
86 let max_instances = tlas.shared.max_instances;
87 Self::new_with_instances(tlas, vec![None; max_instances as usize])
88 }
89
90 /// Construct [`TlasPackage`] consuming the [`Tlas`] (prevents modification of the [`Tlas`] without using this package).
91 /// This constructor moves the instances into the package (the number of instances needs to fit into tlas,
92 /// otherwise when building a validation error will be raised).
93 pub fn new_with_instances(tlas: Tlas, instances: Vec<Option<TlasInstance>>) -> Self {
94 Self {
95 tlas,
96 lowest_unmodified: instances.len() as u32,
97 instances,
98 }
99 }
100
101 /// Get a reference to all instances.
102 pub fn get(&self) -> &[Option<TlasInstance>] {
103 &self.instances
104 }
105
106 /// Get a mutable slice to a range of instances.
107 /// Returns None if the range is out of bounds.
108 /// All elements from the lowest accessed index up are marked as modified.
109 // this recommendation is not useful yet, but is likely to be when ability to update arrives or possible optimisations for building get implemented.
110 /// For best performance it is recommended to prefer access to low elements and modify higher elements as little as possible.
111 /// This can be done by ordering instances from the most to the least used. It is recommended
112 /// to use [`Self::index_mut`] unless the option if out of bounds is required
113 pub fn get_mut_slice(&mut self, range: Range<usize>) -> Option<&mut [Option<TlasInstance>]> {
114 if range.end > self.instances.len() {
115 return None;
116 }
117 if range.end as u32 > self.lowest_unmodified {
118 self.lowest_unmodified = range.end as u32;
119 }
120 Some(&mut self.instances[range])
121 }
122
123 /// Get a single mutable reference to an instance.
124 /// Returns None if the range is out of bounds.
125 /// All elements from the lowest accessed index up are marked as modified.
126 // this recommendation is not useful yet, but is likely to be when ability to update arrives or possible optimisations for building get implemented.
127 /// For best performance it is recommended to prefer access to low elements and modify higher elements as little as possible.
128 /// This can be done by ordering instances from the most to the least used. It is recommended
129 /// to use [`Self::index_mut`] unless the option if out of bounds is required
130 pub fn get_mut_single(&mut self, index: usize) -> Option<&mut Option<TlasInstance>> {
131 if index >= self.instances.len() {
132 return None;
133 }
134 if index as u32 + 1 > self.lowest_unmodified {
135 self.lowest_unmodified = index as u32 + 1;
136 }
137 Some(&mut self.instances[index])
138 }
139
140 /// Get the binding resource for the underling acceleration structure, to be used when creating a [`BindGroup`]
141 ///
142 /// [`BindGroup`]: super::BindGroup
143 pub fn as_binding(&self) -> BindingResource<'_> {
144 BindingResource::AccelerationStructure(&self.tlas)
145 }
146
147 /// Get a reference to the underling [`Tlas`].
148 pub fn tlas(&self) -> &Tlas {
149 &self.tlas
150 }
151}
152
153impl Index<usize> for TlasPackage {
154 type Output = Option<TlasInstance>;
155
156 fn index(&self, index: usize) -> &Self::Output {
157 self.instances.index(index)
158 }
159}
160
161impl Index<Range<usize>> for TlasPackage {
162 type Output = [Option<TlasInstance>];
163
164 fn index(&self, index: Range<usize>) -> &Self::Output {
165 self.instances.index(index)
166 }
167}
168
169impl IndexMut<usize> for TlasPackage {
170 fn index_mut(&mut self, index: usize) -> &mut Self::Output {
171 let idx = self.instances.index_mut(index);
172 if index as u32 + 1 > self.lowest_unmodified {
173 self.lowest_unmodified = index as u32 + 1;
174 }
175 idx
176 }
177}
178
179impl IndexMut<Range<usize>> for TlasPackage {
180 fn index_mut(&mut self, index: Range<usize>) -> &mut Self::Output {
181 let idx = self.instances.index_mut(index.clone());
182 if index.end > self.lowest_unmodified as usize {
183 self.lowest_unmodified = index.end as u32;
184 }
185 idx
186 }
187}