Skip to main content

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