Skip to main content

vk_graph/driver/
accel_struct.rs

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