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}