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}