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