screen_13/driver/accel_struct.rs
1//! Acceleration structure resource types
2
3use {
4 super::{Buffer, BufferInfo, DriverError, device::Device, vk_sync::AccessType},
5 ash::vk,
6 derive_builder::{Builder, UninitializedFieldError},
7 log::warn,
8 std::{
9 ffi::c_void,
10 mem::{replace, size_of_val},
11 ops::Deref,
12 sync::Arc,
13 thread::panicking,
14 },
15};
16
17#[cfg(feature = "parking_lot")]
18use parking_lot::Mutex;
19
20#[cfg(not(feature = "parking_lot"))]
21use std::sync::Mutex;
22
23/// Smart pointer handle to an [acceleration structure] object.
24///
25/// Also contains the backing buffer and information about the object.
26///
27/// ## `Deref` behavior
28///
29/// `AccelerationStructure` automatically dereferences to [`vk::AccelerationStructureKHR`] (via the
30/// [`Deref`] trait), so you can call `vk::AccelerationStructureKHR`'s methods on a value of
31/// type `AccelerationStructure`. To avoid name clashes with `vk::AccelerationStructureKHR`'s
32/// methods, the methods of `AccelerationStructure` itself are associated functions, called using
33/// [fully qualified syntax]:
34///
35/// ```no_run
36/// # use std::sync::Arc;
37/// # use ash::vk;
38/// # use screen_13::driver::{AccessType, DriverError};
39/// # use screen_13::driver::device::{Device, DeviceInfo};
40/// # use screen_13::driver::accel_struct::{AccelerationStructure, AccelerationStructureInfo};
41/// # fn main() -> Result<(), DriverError> {
42/// # let device = Arc::new(Device::create_headless(DeviceInfo::default())?);
43/// # const SIZE: vk::DeviceSize = 1024;
44/// # let info = AccelerationStructureInfo::blas(SIZE);
45/// # let my_accel_struct = AccelerationStructure::create(&device, info)?;
46/// let addr = AccelerationStructure::device_address(&my_accel_struct);
47/// # Ok(()) }
48/// ```
49///
50/// [acceleration structure]: https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkAccelerationStructureKHR.html
51/// [deref]: core::ops::Deref
52/// [fully qualified syntax]: https://doc.rust-lang.org/book/ch19-03-advanced-traits.html#fully-qualified-syntax-for-disambiguation-calling-methods-with-the-same-name
53#[derive(Debug)]
54pub struct AccelerationStructure {
55 access: Mutex<AccessType>,
56 accel_struct: (vk::AccelerationStructureKHR, Buffer),
57 device: Arc<Device>,
58
59 /// Information used to create this object.
60 pub info: AccelerationStructureInfo,
61}
62
63impl AccelerationStructure {
64 /// Creates a new acceleration structure on the given device.
65 ///
66 /// # Examples
67 ///
68 /// Basic usage:
69 ///
70 /// ```no_run
71 /// # use std::sync::Arc;
72 /// # use ash::vk;
73 /// # use screen_13::driver::DriverError;
74 /// # use screen_13::driver::device::{Device, DeviceInfo};
75 /// # use screen_13::driver::accel_struct::{AccelerationStructure, AccelerationStructureInfo};
76 /// # fn main() -> Result<(), DriverError> {
77 /// # let device = Arc::new(Device::create_headless(DeviceInfo::default())?);
78 /// const SIZE: vk::DeviceSize = 1024;
79 /// let info = AccelerationStructureInfo::blas(SIZE);
80 /// let accel_struct = AccelerationStructure::create(&device, info)?;
81 ///
82 /// assert_ne!(*accel_struct, vk::AccelerationStructureKHR::null());
83 /// assert_eq!(accel_struct.info.size, SIZE);
84 /// # Ok(()) }
85 /// ```
86 #[profiling::function]
87 pub fn create(
88 device: &Arc<Device>,
89 info: impl Into<AccelerationStructureInfo>,
90 ) -> Result<Self, DriverError> {
91 debug_assert!(device.physical_device.accel_struct_properties.is_some());
92
93 let info = info.into();
94
95 let buffer = Buffer::create(
96 device,
97 BufferInfo::device_mem(
98 info.size,
99 vk::BufferUsageFlags::ACCELERATION_STRUCTURE_STORAGE_KHR
100 | vk::BufferUsageFlags::SHADER_DEVICE_ADDRESS,
101 ),
102 )?;
103
104 let accel_struct = {
105 let create_info = vk::AccelerationStructureCreateInfoKHR::default()
106 .ty(info.ty)
107 .buffer(*buffer)
108 .size(info.size);
109
110 let accel_struct_ext = Device::expect_accel_struct_ext(device);
111
112 unsafe { accel_struct_ext.create_acceleration_structure(&create_info, None) }.map_err(
113 |err| {
114 warn!("{err}");
115
116 match err {
117 vk::Result::ERROR_INVALID_OPAQUE_CAPTURE_ADDRESS => {
118 DriverError::InvalidData
119 }
120 vk::Result::ERROR_OUT_OF_HOST_MEMORY => DriverError::OutOfMemory,
121 _ => DriverError::Unsupported,
122 }
123 },
124 )?
125 };
126
127 let device = Arc::clone(device);
128
129 Ok(AccelerationStructure {
130 access: Mutex::new(AccessType::Nothing),
131 accel_struct: (accel_struct, buffer),
132 device,
133 info,
134 })
135 }
136
137 /// Keeps track of some `next_access` which affects this object.
138 ///
139 /// Returns the previous access for which a pipeline barrier should be used to prevent data
140 /// corruption.
141 ///
142 /// # Note
143 ///
144 /// Used to maintain object state when passing a _Screen 13_-created
145 /// `vk::AccelerationStructureKHR` handle to external code such as [_Ash_] or [_Erupt_]
146 /// bindings.
147 ///
148 /// # Examples
149 ///
150 /// Basic usage:
151 ///
152 /// ```no_run
153 /// # use std::sync::Arc;
154 /// # use ash::vk;
155 /// # use screen_13::driver::{AccessType, DriverError};
156 /// # use screen_13::driver::device::{Device, DeviceInfo};
157 /// # use screen_13::driver::accel_struct::{AccelerationStructure, AccelerationStructureInfo};
158 /// # fn main() -> Result<(), DriverError> {
159 /// # let device = Arc::new(Device::create_headless(DeviceInfo::default())?);
160 /// # const SIZE: vk::DeviceSize = 1024;
161 /// # let info = AccelerationStructureInfo::blas(SIZE);
162 /// # let my_accel_struct = AccelerationStructure::create(&device, info)?;
163 /// // Initially we want to "Build Write"
164 /// let next = AccessType::AccelerationStructureBuildWrite;
165 /// let prev = AccelerationStructure::access(&my_accel_struct, next);
166 /// assert_eq!(prev, AccessType::Nothing);
167 ///
168 /// // External code may now "Build Write"; no barrier required
169 ///
170 /// // Subsequently we want to "Build Read"
171 /// let next = AccessType::AccelerationStructureBuildRead;
172 /// let prev = AccelerationStructure::access(&my_accel_struct, next);
173 /// assert_eq!(prev, AccessType::AccelerationStructureBuildWrite);
174 ///
175 /// // A barrier on "Build Write" before "Build Read" is required!
176 /// # Ok(()) }
177 /// ```
178 ///
179 /// [_Ash_]: https://crates.io/crates/ash
180 /// [_Erupt_]: https://crates.io/crates/erupt
181 #[profiling::function]
182 pub fn access(this: &Self, access: AccessType) -> AccessType {
183 #[cfg_attr(not(feature = "parking_lot"), allow(unused_mut))]
184 let mut access_guard = this.access.lock();
185
186 #[cfg(not(feature = "parking_lot"))]
187 let mut access_guard = access_guard.unwrap();
188
189 replace(&mut access_guard, access)
190 }
191
192 /// Returns the device address of this object.
193 ///
194 /// # Examples
195 ///
196 /// Basic usage:
197 ///
198 /// ```no_run
199 /// # use std::sync::Arc;
200 /// # use ash::vk;
201 /// # use screen_13::driver::{AccessType, DriverError};
202 /// # use screen_13::driver::device::{Device, DeviceInfo};
203 /// # use screen_13::driver::accel_struct::{AccelerationStructure, AccelerationStructureInfo};
204 /// # fn main() -> Result<(), DriverError> {
205 /// # let device = Arc::new(Device::create_headless(DeviceInfo::default())?);
206 /// # const SIZE: vk::DeviceSize = 1024;
207 /// # let info = AccelerationStructureInfo::blas(SIZE);
208 /// # let my_accel_struct = AccelerationStructure::create(&device, info)?;
209 /// let addr = AccelerationStructure::device_address(&my_accel_struct);
210 ///
211 /// assert_ne!(addr, 0);
212 /// # Ok(()) }
213 /// ```
214 #[profiling::function]
215 pub fn device_address(this: &Self) -> vk::DeviceAddress {
216 let accel_struct_ext = Device::expect_accel_struct_ext(&this.device);
217
218 unsafe {
219 accel_struct_ext.get_acceleration_structure_device_address(
220 &vk::AccelerationStructureDeviceAddressInfoKHR::default()
221 .acceleration_structure(this.accel_struct.0),
222 )
223 }
224 }
225
226 /// Helper function which is used to prepare instance buffers.
227 pub fn instance_slice(instances: &[vk::AccelerationStructureInstanceKHR]) -> &[u8] {
228 use std::slice::from_raw_parts;
229
230 unsafe { from_raw_parts(instances.as_ptr() as *const _, size_of_val(instances)) }
231 }
232
233 /// Returns the size of some geometry info which is then used to create a new
234 /// [AccelerationStructure] instance or update an existing instance.
235 ///
236 /// # Examples
237 ///
238 /// Basic usage:
239 ///
240 /// ```no_run
241 /// # use std::sync::Arc;
242 /// # use ash::vk;
243 /// # use screen_13::driver::DriverError;
244 /// # use screen_13::driver::device::{Device, DeviceInfo};
245 /// # use screen_13::driver::accel_struct::{AccelerationStructure, AccelerationStructureGeometry, AccelerationStructureGeometryData, AccelerationStructureGeometryInfo, DeviceOrHostAddress};
246 /// # fn main() -> Result<(), DriverError> {
247 /// # let device = Arc::new(Device::create_headless(DeviceInfo::default())?);
248 /// # let my_geom_triangles = AccelerationStructureGeometryData::Triangles {
249 /// # index_addr: DeviceOrHostAddress::DeviceAddress(0),
250 /// # index_type: vk::IndexType::UINT32,
251 /// # max_vertex: 1,
252 /// # transform_addr: None,
253 /// # vertex_addr: DeviceOrHostAddress::DeviceAddress(0),
254 /// # vertex_format: vk::Format::R32G32B32_SFLOAT,
255 /// # vertex_stride: 12,
256 /// # };
257 /// let my_geom = AccelerationStructureGeometry {
258 /// max_primitive_count: 1,
259 /// flags: vk::GeometryFlagsKHR::OPAQUE,
260 /// geometry: my_geom_triangles,
261 /// };
262 /// let build_range = vk::AccelerationStructureBuildRangeInfoKHR {
263 /// primitive_count: 1,
264 /// primitive_offset: 0,
265 /// first_vertex: 0,
266 /// transform_offset: 0,
267 /// };
268 /// let my_info = AccelerationStructureGeometryInfo::blas([(my_geom, build_range)]);
269 /// let res = AccelerationStructure::size_of(&device, &my_info);
270 ///
271 /// assert_eq!(res.create_size, 2432);
272 /// assert_eq!(res.build_size, 640);
273 /// assert_eq!(res.update_size, 0);
274 /// # Ok(()) }
275 /// ```
276 #[profiling::function]
277 pub fn size_of(
278 device: &Device,
279 info: &AccelerationStructureGeometryInfo<impl AsRef<AccelerationStructureGeometry>>,
280 ) -> AccelerationStructureSize {
281 use std::cell::RefCell;
282
283 #[derive(Default)]
284 struct Tls {
285 geometries: Vec<vk::AccelerationStructureGeometryKHR<'static>>,
286 max_primitive_counts: Vec<u32>,
287 }
288
289 thread_local! {
290 static TLS: RefCell<Tls> = Default::default();
291 }
292
293 TLS.with_borrow_mut(|tls| {
294 tls.geometries.clear();
295 tls.max_primitive_counts.clear();
296
297 for info in info.geometries.iter().map(AsRef::as_ref) {
298 tls.geometries.push(info.into());
299 tls.max_primitive_counts.push(info.max_primitive_count);
300 }
301
302 let info = vk::AccelerationStructureBuildGeometryInfoKHR::default()
303 .ty(info.ty)
304 .flags(info.flags)
305 .geometries(&tls.geometries);
306 let mut sizes = vk::AccelerationStructureBuildSizesInfoKHR::default();
307 let accel_struct_ext = Device::expect_accel_struct_ext(device);
308
309 unsafe {
310 accel_struct_ext.get_acceleration_structure_build_sizes(
311 vk::AccelerationStructureBuildTypeKHR::HOST_OR_DEVICE,
312 &info,
313 &tls.max_primitive_counts,
314 &mut sizes,
315 );
316 }
317
318 AccelerationStructureSize {
319 create_size: sizes.acceleration_structure_size,
320 build_size: sizes.build_scratch_size,
321 update_size: sizes.update_scratch_size,
322 }
323 })
324 }
325}
326
327impl Deref for AccelerationStructure {
328 type Target = vk::AccelerationStructureKHR;
329
330 fn deref(&self) -> &Self::Target {
331 &self.accel_struct.0
332 }
333}
334
335impl Drop for AccelerationStructure {
336 #[profiling::function]
337 fn drop(&mut self) {
338 if panicking() {
339 return;
340 }
341
342 let accel_struct_ext = Device::expect_accel_struct_ext(&self.device);
343
344 unsafe {
345 accel_struct_ext.destroy_acceleration_structure(self.accel_struct.0, None);
346 }
347 }
348}
349
350/// Structure specifying geometries to be built into an acceleration structure.
351///
352/// See
353/// [VkAccelerationStructureGeometryKHR](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkAccelerationStructureGeometryKHR.html)
354/// for more information.
355#[derive(Clone, Copy, Debug)]
356pub struct AccelerationStructureGeometry {
357 /// The number of primitives built into each geometry.
358 pub max_primitive_count: u32,
359
360 /// Describes additional properties of how the geometry should be built.
361 pub flags: vk::GeometryFlagsKHR,
362
363 /// Specifies acceleration structure geometry data.
364 pub geometry: AccelerationStructureGeometryData,
365}
366
367impl AccelerationStructureGeometry {
368 /// Creates a new acceleration structure geometry instance.
369 pub fn new(max_primitive_count: u32, geometry: AccelerationStructureGeometryData) -> Self {
370 let flags = Default::default();
371
372 Self {
373 max_primitive_count,
374 flags,
375 geometry,
376 }
377 }
378
379 /// Creates a new acceleration structure geometry instance with the
380 /// [vk::GeometryFlagsKHR::OPAQUE] flag set.
381 pub fn opaque(max_primitive_count: u32, geometry: AccelerationStructureGeometryData) -> Self {
382 Self::new(max_primitive_count, geometry).flags(vk::GeometryFlagsKHR::OPAQUE)
383 }
384
385 /// Sets the instance flags.
386 pub fn flags(mut self, flags: vk::GeometryFlagsKHR) -> Self {
387 self.flags = flags;
388
389 self
390 }
391}
392
393impl<T> AsRef<AccelerationStructureGeometry> for (AccelerationStructureGeometry, T) {
394 fn as_ref(&self) -> &AccelerationStructureGeometry {
395 &self.0
396 }
397}
398
399impl<'b> From<&'b AccelerationStructureGeometry> for vk::AccelerationStructureGeometryKHR<'_> {
400 fn from(&value: &'b AccelerationStructureGeometry) -> Self {
401 value.into()
402 }
403}
404
405impl From<AccelerationStructureGeometry> for vk::AccelerationStructureGeometryKHR<'_> {
406 fn from(value: AccelerationStructureGeometry) -> Self {
407 Self::default()
408 .flags(value.flags)
409 .geometry(value.geometry.into())
410 .geometry_type(value.geometry.into())
411 }
412}
413
414/// Specifies acceleration structure geometry data.
415///
416/// See
417/// [VkAccelerationStructureGeometryDataKHR](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkAccelerationStructureGeometryDataKHR.html)
418/// for more information.
419#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
420pub enum AccelerationStructureGeometryData {
421 /// Axis-aligned bounding box geometry in a bottom-level acceleration structure.
422 ///
423 /// See
424 /// [VkAccelerationStructureGeometryAabbsDataKHR](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkAccelerationStructureGeometryAabbsDataKHR.html)
425 /// for more information.
426 AABBs {
427 /// A device or host address to memory containing [vk::AabbPositionsKHR] structures
428 /// containing position data for each axis-aligned bounding box in the geometry.
429 addr: DeviceOrHostAddress,
430
431 /// Stride in bytes between each entry in data.
432 ///
433 /// The stride must be a multiple of `8`.
434 stride: vk::DeviceSize,
435 },
436
437 /// Geometry consisting of instances of other acceleration structures.
438 ///
439 /// See [VkAccelerationStructureGeometryInstancesDataKHR](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkAccelerationStructureGeometryInstancesDataKHR.html)
440 /// for more information.
441 Instances {
442 /// Either the address of an array of device referencing individual
443 /// VkAccelerationStructureInstanceKHR structures or packed motion instance information as
444 /// described in
445 /// [motion instances](https://registry.khronos.org/vulkan/specs/1.3-extensions/html/vkspec.html#acceleration-structure-motion-instances)
446 /// if `array_of_pointers` is `true`, or the address of an array of
447 /// VkAccelerationStructureInstanceKHR structures.
448 ///
449 /// Addresses and VkAccelerationStructureInstanceKHR structures are tightly packed.
450 addr: DeviceOrHostAddress,
451
452 /// Specifies whether data is used as an array of addresses or just an array.
453 array_of_pointers: bool,
454 },
455
456 /// A triangle geometry in a bottom-level acceleration structure.
457 ///
458 /// See
459 /// [VkAccelerationStructureGeometryTrianglesDataKHR](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkAccelerationStructureGeometryTrianglesDataKHR.html)
460 /// for more information.
461 Triangles {
462 /// A device or host address to memory containing index data for this geometry.
463 index_addr: DeviceOrHostAddress,
464
465 /// The
466 /// [VkIndexType](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkIndexType.html)
467 /// of each index element.
468 index_type: vk::IndexType,
469
470 /// The highest index of a vertex that will be addressed by a build command using this structure.
471 max_vertex: u32,
472
473 /// A device or host address to memory containing an optional reference to a
474 /// [VkTransformMatrixKHR](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkTransformMatrixKHR.html)
475 /// structure describing a transformation from the space in which the vertices in this
476 /// geometry are described to the space in which the acceleration structure is defined.
477 transform_addr: Option<DeviceOrHostAddress>,
478
479 /// A device or host address to memory containing vertex data for this geometry.
480 vertex_addr: DeviceOrHostAddress,
481
482 /// The
483 /// [VkFormat](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkFormat.html)
484 /// of each vertex element.
485 vertex_format: vk::Format,
486
487 /// The stride in bytes between each vertex.
488 vertex_stride: vk::DeviceSize,
489 },
490}
491
492impl AccelerationStructureGeometryData {
493 /// Specifies acceleration structure geometry data as AABBs.
494 pub fn aabbs(addr: impl Into<DeviceOrHostAddress>, stride: vk::DeviceSize) -> Self {
495 let addr = addr.into();
496
497 Self::AABBs { addr, stride }
498 }
499
500 /// Specifies acceleration structure geometry data as instances.
501 pub fn instances(addr: impl Into<DeviceOrHostAddress>) -> Self {
502 let addr = addr.into();
503
504 Self::Instances {
505 addr,
506 array_of_pointers: false,
507 }
508 }
509
510 /// Specifies acceleration structure geometry data as an array of instance pointers.
511 pub fn instance_pointers(addr: impl Into<DeviceOrHostAddress>) -> Self {
512 let addr = addr.into();
513
514 Self::Instances {
515 addr,
516 array_of_pointers: true,
517 }
518 }
519
520 /// Specifies acceleration structure geometry data as triangles.
521 pub fn triangles(
522 index_addr: impl Into<DeviceOrHostAddress>,
523 index_type: vk::IndexType,
524 max_vertex: u32,
525 transform_addr: impl Into<Option<DeviceOrHostAddress>>,
526 vertex_addr: impl Into<DeviceOrHostAddress>,
527 vertex_format: vk::Format,
528 vertex_stride: vk::DeviceSize,
529 ) -> Self {
530 let index_addr = index_addr.into();
531 let transform_addr = transform_addr.into();
532 let vertex_addr = vertex_addr.into();
533
534 Self::Triangles {
535 index_addr,
536 index_type,
537 max_vertex,
538 transform_addr,
539 vertex_addr,
540 vertex_format,
541 vertex_stride,
542 }
543 }
544}
545
546impl From<AccelerationStructureGeometryData> for vk::GeometryTypeKHR {
547 fn from(value: AccelerationStructureGeometryData) -> Self {
548 match value {
549 AccelerationStructureGeometryData::AABBs { .. } => Self::AABBS,
550 AccelerationStructureGeometryData::Instances { .. } => Self::INSTANCES,
551 AccelerationStructureGeometryData::Triangles { .. } => Self::TRIANGLES,
552 }
553 }
554}
555
556impl From<AccelerationStructureGeometryData> for vk::AccelerationStructureGeometryDataKHR<'_> {
557 fn from(value: AccelerationStructureGeometryData) -> Self {
558 match value {
559 AccelerationStructureGeometryData::AABBs { addr, stride } => Self {
560 aabbs: vk::AccelerationStructureGeometryAabbsDataKHR::default()
561 .data(addr.into())
562 .stride(stride),
563 },
564 AccelerationStructureGeometryData::Instances {
565 addr,
566 array_of_pointers,
567 } => Self {
568 instances: vk::AccelerationStructureGeometryInstancesDataKHR::default()
569 .array_of_pointers(array_of_pointers)
570 .data(addr.into()),
571 },
572 AccelerationStructureGeometryData::Triangles {
573 index_addr,
574 index_type,
575 max_vertex,
576 transform_addr,
577 vertex_addr,
578 vertex_format,
579 vertex_stride,
580 } => Self {
581 triangles: vk::AccelerationStructureGeometryTrianglesDataKHR::default()
582 .index_data(index_addr.into())
583 .index_type(index_type)
584 .max_vertex(max_vertex)
585 .transform_data(transform_addr.map(Into::into).unwrap_or_default())
586 .vertex_data(vertex_addr.into())
587 .vertex_format(vertex_format)
588 .vertex_stride(vertex_stride),
589 },
590 }
591 }
592}
593
594/// Specifies the geometry data of an acceleration structure.
595#[derive(Clone, Debug)]
596pub struct AccelerationStructureGeometryInfo<G> {
597 /// Type of acceleration structure.
598 pub ty: vk::AccelerationStructureTypeKHR,
599
600 /// Specifies additional parameters of the acceleration structure.
601 pub flags: vk::BuildAccelerationStructureFlagsKHR,
602
603 /// A slice of geometry structures.
604 pub geometries: Box<[G]>,
605}
606
607impl<G> AccelerationStructureGeometryInfo<G> {
608 /// A bottom-level acceleration structure containing the AABBs or geometry to be intersected.
609 pub fn blas(geometries: impl Into<Box<[G]>>) -> Self {
610 let geometries = geometries.into();
611
612 Self {
613 ty: vk::AccelerationStructureTypeKHR::BOTTOM_LEVEL,
614 flags: Default::default(),
615 geometries,
616 }
617 }
618
619 /// A top-level acceleration structure containing instance data referring to bottom-level
620 /// acceleration structures.
621 pub fn tlas(geometries: impl Into<Box<[G]>>) -> Self {
622 let geometries = geometries.into();
623
624 Self {
625 ty: vk::AccelerationStructureTypeKHR::TOP_LEVEL,
626 flags: Default::default(),
627 geometries,
628 }
629 }
630
631 /// Sets the flags on this instance.
632 pub fn flags(mut self, flags: vk::BuildAccelerationStructureFlagsKHR) -> Self {
633 self.flags = flags;
634 self
635 }
636}
637
638/// Information used to create an [`AccelerationStructure`] instance.
639#[derive(Builder, Clone, Copy, Debug, Eq, Hash, PartialEq)]
640#[builder(
641 build_fn(
642 private,
643 name = "fallible_build",
644 error = "AccelerationStructureInfoBuilderError"
645 ),
646 derive(Clone, Copy, Debug),
647 pattern = "owned"
648)]
649#[non_exhaustive]
650pub struct AccelerationStructureInfo {
651 /// Type of acceleration structure.
652 #[builder(default = "vk::AccelerationStructureTypeKHR::GENERIC")]
653 pub ty: vk::AccelerationStructureTypeKHR,
654
655 /// The size of the backing buffer that will store the acceleration structure.
656 ///
657 /// Use [`AccelerationStructure::size_of`] to calculate this value.
658 pub size: vk::DeviceSize,
659}
660
661impl AccelerationStructureInfo {
662 /// Specifies a [`vk::AccelerationStructureTypeKHR::BOTTOM_LEVEL`] acceleration structure of the
663 /// given size.
664 #[inline(always)]
665 pub const fn blas(size: vk::DeviceSize) -> Self {
666 Self {
667 ty: vk::AccelerationStructureTypeKHR::BOTTOM_LEVEL,
668 size,
669 }
670 }
671
672 /// Creates a default `AccelerationStructureInfoBuilder`.
673 #[allow(clippy::new_ret_no_self)]
674 pub fn builder() -> AccelerationStructureInfoBuilder {
675 Default::default()
676 }
677
678 /// Specifies a [`vk::AccelerationStructureTypeKHR::TOP_LEVEL`] acceleration structure of the
679 /// given size.
680 #[inline(always)]
681 pub const fn tlas(size: vk::DeviceSize) -> Self {
682 Self {
683 ty: vk::AccelerationStructureTypeKHR::TOP_LEVEL,
684 size,
685 }
686 }
687
688 /// Converts an `AccelerationStructureInfo` into an `AccelerationStructureInfoBuilder`.
689 #[inline(always)]
690 pub fn to_builder(self) -> AccelerationStructureInfoBuilder {
691 AccelerationStructureInfoBuilder {
692 ty: Some(self.ty),
693 size: Some(self.size),
694 }
695 }
696}
697
698impl From<AccelerationStructureInfo> for () {
699 fn from(_: AccelerationStructureInfo) -> Self {}
700}
701
702impl AccelerationStructureInfoBuilder {
703 /// Builds a new `AccelerationStructureInfo`.
704 ///
705 /// # Panics
706 ///
707 /// If any of the following values have not been set this function will panic:
708 ///
709 /// * `size`
710 #[inline(always)]
711 pub fn build(self) -> AccelerationStructureInfo {
712 match self.fallible_build() {
713 Err(AccelerationStructureInfoBuilderError(err)) => panic!("{err}"),
714 Ok(info) => info,
715 }
716 }
717}
718
719#[derive(Debug)]
720struct AccelerationStructureInfoBuilderError(UninitializedFieldError);
721
722impl From<UninitializedFieldError> for AccelerationStructureInfoBuilderError {
723 fn from(err: UninitializedFieldError) -> Self {
724 Self(err)
725 }
726}
727
728/// Holds the results of the [`AccelerationStructure::size_of`] function.
729#[derive(Clone, Copy, Debug)]
730pub struct AccelerationStructureSize {
731 /// The size of the scratch buffer required when building an acceleration structure using the
732 /// [`Acceleration::build_structure`](super::super::graph::pass_ref::Acceleration::build_structure)
733 /// function.
734 pub build_size: vk::DeviceSize,
735
736 /// The value of `size` parameter needed by [`AccelerationStructureInfo`] for use with the
737 /// [`AccelerationStructure::create`] function.
738 pub create_size: vk::DeviceSize,
739
740 /// The size of the scratch buffer required when updating an acceleration structure using the
741 /// [`Acceleration::update_structure`](super::super::graph::pass_ref::Acceleration::update_structure)
742 /// function.
743 pub update_size: vk::DeviceSize,
744}
745
746/// Specifies a constant device or host address.
747///
748/// See
749/// [VkDeviceOrHostAddressKHR](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkDeviceOrHostAddressKHR.html)
750/// for more information.
751#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
752pub enum DeviceOrHostAddress {
753 /// An address value returned from [`AccelerationStructure::device_address`].
754 DeviceAddress(vk::DeviceAddress),
755
756 /// A host memory address.
757 HostAddress(*mut c_void),
758}
759
760impl From<vk::DeviceAddress> for DeviceOrHostAddress {
761 fn from(device_address: vk::DeviceAddress) -> Self {
762 Self::DeviceAddress(device_address)
763 }
764}
765
766impl From<*mut c_void> for DeviceOrHostAddress {
767 fn from(host_address: *mut c_void) -> Self {
768 Self::HostAddress(host_address)
769 }
770}
771
772// Safety: The entire purpose of DeviceOrHostAddress is to share memory with Vulkan
773unsafe impl Send for DeviceOrHostAddress {}
774unsafe impl Sync for DeviceOrHostAddress {}
775
776impl From<DeviceOrHostAddress> for vk::DeviceOrHostAddressConstKHR {
777 fn from(value: DeviceOrHostAddress) -> Self {
778 match value {
779 DeviceOrHostAddress::DeviceAddress(device_address) => Self { device_address },
780 DeviceOrHostAddress::HostAddress(host_address) => Self { host_address },
781 }
782 }
783}
784
785impl From<DeviceOrHostAddress> for vk::DeviceOrHostAddressKHR {
786 fn from(value: DeviceOrHostAddress) -> Self {
787 match value {
788 DeviceOrHostAddress::DeviceAddress(device_address) => Self { device_address },
789 DeviceOrHostAddress::HostAddress(host_address) => Self { host_address },
790 }
791 }
792}
793
794#[cfg(test)]
795mod tests {
796 use super::*;
797
798 type Info = AccelerationStructureInfo;
799 type Builder = AccelerationStructureInfoBuilder;
800
801 #[test]
802 pub fn accel_struct_info() {
803 let info = Info::blas(32);
804 let builder = info.to_builder().build();
805
806 assert_eq!(info, builder);
807 }
808
809 #[test]
810 pub fn accel_struct_info_builder() {
811 let info = Info {
812 size: 32,
813 ty: vk::AccelerationStructureTypeKHR::GENERIC,
814 };
815 let builder = Builder::default().size(32).build();
816
817 assert_eq!(info, builder);
818 }
819
820 #[test]
821 #[should_panic(expected = "Field not initialized: size")]
822 pub fn accel_struct_info_builder_uninit_size() {
823 Builder::default().build();
824 }
825}