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