vulkano/
acceleration_structure.rs

1//! An opaque data structure that is used to accelerate spatial queries on geometry data.
2//!
3//! Acceleration structures contain geometry data, arranged in such a way that the device can
4//! easily search through the data and check for intersections between the geometry and rays
5//! (lines). The geometry data can consist of either triangles, or axis-aligned bounding boxes
6//! (AABBs).
7//!
8//! Acceleration structures come in two forms: top-level and bottom-level. A bottom-level
9//! acceleration structure holds the actual geometry data, while a top-level structure contains
10//! instances of (references to) one or more bottom-level structures. A top-level structure is
11//! intended to contain the whole rendered scene (or the relevant parts of it), while a
12//! bottom-level structure may contain individual objects within the scene. This two-level
13//! arrangement allows you to easily rearrange the scene, adding and removing parts of it as
14//! needed.
15//!
16//! # Building an acceleration structure
17//!
18//! When an acceleration structure object is created, it is in an uninitialized state and contains
19//! garbage data. To be able to use it for anything, you must first *build* the structure on the
20//! device, using the [`build_acceleration_structure`] or [`build_acceleration_structure_indirect`]
21//! command buffer commands. You use [`BuildAccelerationStructureMode::Build`] to build a structure
22//! from scratch.
23//!
24//! When specifying geometry data for an acceleration structure build, certain triangle, AABB or
25//! instance values mark that item as *inactive*. An inactive item is completely ignored within
26//! the acceleration structure, and acts as if it's not there. The following special values
27//! make an item inactive:
28//! - For triangles, if the vertex format is a floating-point type, then the triangle is inactive
29//!   if any of its vertices have NaN as their first coordinate. For integer vertex formats, it is
30//!   not possible to mark triangles as inactive.
31//! - For AABBs, if [`AabbPositions::min[0]`](AabbPositions::min) is NaN.
32//! - For instances, if [`AccelerationStructureInstance::acceleration_structure_reference`] is 0.
33//!
34//! # Updating an acceleration structure
35//!
36//! Once an acceleration structure is built, if it was built previously with the
37//! [`BuildAccelerationStructureFlags::ALLOW_UPDATE`] flag, then it is possible to update the
38//! structure with new data. You use [`BuildAccelerationStructureMode::Update`] for this, which
39//! specifies the source acceleration structure to use as a starting point for the update.
40//! This can be the same as the destination structure (the update will happen in-place), or a
41//! different one.
42//!
43//! An update operation is limited in which parts of the data it may change. You may change most
44//! buffers and their contents, as well as strides and offsets:
45//! - [`AccelerationStructureBuildGeometryInfo::scratch_data`]
46//! - [`AccelerationStructureGeometryTrianglesData::vertex_data`]
47//! - [`AccelerationStructureGeometryTrianglesData::vertex_stride`]
48//! - [`AccelerationStructureGeometryTrianglesData::transform_data`] (but the variant of `Option`
49//!   must not change)
50//! - [`AccelerationStructureGeometryAabbsData::data`]
51//! - [`AccelerationStructureGeometryAabbsData::stride`]
52//! - [`AccelerationStructureGeometryInstancesData::data`]
53//! - [`AccelerationStructureBuildRangeInfo::primitive_offset`]
54//! - [`AccelerationStructureBuildRangeInfo::first_vertex`] if no index buffer is used
55//! - [`AccelerationStructureBuildRangeInfo::transform_offset`]
56//!
57//! No other values may be changed, including in particular the variant or number of elements in
58//! [`AccelerationStructureBuildGeometryInfo::geometries`], and the value of
59//! [`AccelerationStructureBuildRangeInfo::primitive_count`].
60//! The enum variants and data in [`AccelerationStructureGeometryTrianglesData::index_data`] must
61//! not be changed, but it is allowed to specify a new index buffer, as long as it contains the
62//! exact same indices as the old one.
63//!
64//! An update operation may not change the inactive status of an item: active items must remain
65//! active in the update and inactive items must remain inactive.
66//!
67//! # Accessing an acceleration structure in a shader
68//!
69//! Acceleration structures can be bound to and accessed in any shader type. They are accessed
70//! as descriptors, like buffers and images, and are declared in GLSL with
71//! ```glsl
72//! layout (set = N, binding = N) uniform accelerationStructureEXT nameOfTheVariable;
73//! ```
74//! You must enable either the `GL_EXT_ray_query` or the `GL_EXT_ray_tracing` GLSL extensions in
75//! the shader to use this.
76//!
77//! On the Vulkano side, you can then create a descriptor set layout using
78//! [`DescriptorType::AccelerationStructure`] as a descriptor type, and write the
79//! acceleration structure to a descriptor set using
80//! [`WriteDescriptorSet::acceleration_structure`].
81//!
82//! [`build_acceleration_structure`]: crate::command_buffer::AutoCommandBufferBuilder::build_acceleration_structure
83//! [`build_acceleration_structure_indirect`]: crate::command_buffer::AutoCommandBufferBuilder::build_acceleration_structure_indirect
84//! [`DescriptorType::AccelerationStructure`]: crate::descriptor_set::layout::DescriptorType::AccelerationStructure
85//! [`WriteDescriptorSet::acceleration_structure`]: crate::descriptor_set::WriteDescriptorSet::acceleration_structure
86
87use crate::{
88    buffer::{BufferCreateFlags, BufferUsage, IndexBuffer, Subbuffer},
89    device::{Device, DeviceOwned},
90    format::{Format, FormatFeatures},
91    instance::InstanceOwnedDebugWrapper,
92    macros::{impl_id_counter, vulkan_bitflags, vulkan_enum},
93    DeviceAddress, DeviceSize, NonNullDeviceAddress, Packed24_8, Requires, RequiresAllOf,
94    RequiresOneOf, Validated, ValidationError, VulkanError, VulkanObject,
95};
96use bytemuck::{Pod, Zeroable};
97use std::{fmt::Debug, hash::Hash, mem::MaybeUninit, num::NonZeroU64, ptr, sync::Arc};
98
99/// An opaque data structure that is used to accelerate spatial queries on geometry data.
100#[derive(Debug)]
101pub struct AccelerationStructure {
102    device: InstanceOwnedDebugWrapper<Arc<Device>>,
103    handle: ash::vk::AccelerationStructureKHR,
104    id: NonZeroU64,
105
106    create_flags: AccelerationStructureCreateFlags,
107    buffer: Subbuffer<[u8]>,
108    ty: AccelerationStructureType,
109}
110
111impl AccelerationStructure {
112    /// Creates a new `AccelerationStructure`.
113    ///
114    /// The [`acceleration_structure`] feature must be enabled on the device.
115    ///
116    /// # Safety
117    ///
118    /// - `create_info.buffer` (and any subbuffer it overlaps with) must not be accessed while it
119    ///   is bound to the acceleration structure.
120    ///
121    /// [`acceleration_structure`]: crate::device::DeviceFeatures::acceleration_structure
122    #[inline]
123    pub unsafe fn new(
124        device: Arc<Device>,
125        create_info: AccelerationStructureCreateInfo,
126    ) -> Result<Arc<Self>, Validated<VulkanError>> {
127        Self::validate_new(&device, &create_info)?;
128
129        Ok(unsafe { Self::new_unchecked(device, create_info) }?)
130    }
131
132    fn validate_new(
133        device: &Device,
134        create_info: &AccelerationStructureCreateInfo,
135    ) -> Result<(), Box<ValidationError>> {
136        if !device.enabled_extensions().khr_acceleration_structure {
137            return Err(Box::new(ValidationError {
138                requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::DeviceExtension(
139                    "khr_acceleration_structure",
140                )])]),
141                ..Default::default()
142            }));
143        }
144
145        if !device.enabled_features().acceleration_structure {
146            return Err(Box::new(ValidationError {
147                requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::DeviceFeature(
148                    "acceleration_structure",
149                )])]),
150                vuids: &["VUID-vkCreateAccelerationStructureKHR-accelerationStructure-03611"],
151                ..Default::default()
152            }));
153        }
154
155        // VUID-vkCreateAccelerationStructureKHR-pCreateInfo-parameter
156        create_info
157            .validate(device)
158            .map_err(|err| err.add_context("create_info"))?;
159
160        Ok(())
161    }
162
163    #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
164    pub unsafe fn new_unchecked(
165        device: Arc<Device>,
166        create_info: AccelerationStructureCreateInfo,
167    ) -> Result<Arc<Self>, VulkanError> {
168        let create_info_vk = create_info.to_vk();
169
170        let handle = {
171            let fns = device.fns();
172            let mut output = MaybeUninit::uninit();
173            unsafe {
174                (fns.khr_acceleration_structure
175                    .create_acceleration_structure_khr)(
176                    device.handle(),
177                    &create_info_vk,
178                    ptr::null(),
179                    output.as_mut_ptr(),
180                )
181            }
182            .result()
183            .map_err(VulkanError::from)?;
184            unsafe { output.assume_init() }
185        };
186
187        Ok(unsafe { Self::from_handle(device, handle, create_info) })
188    }
189
190    /// Creates a new `AccelerationStructure` from a raw object handle.
191    ///
192    /// # Safety
193    ///
194    /// - `handle` must be a valid Vulkan object handle created from `device`.
195    /// - `create_info` must match the info used to create the object.
196    pub unsafe fn from_handle(
197        device: Arc<Device>,
198        handle: ash::vk::AccelerationStructureKHR,
199        create_info: AccelerationStructureCreateInfo,
200    ) -> Arc<Self> {
201        let AccelerationStructureCreateInfo {
202            create_flags,
203            buffer,
204            ty,
205            _ne: _,
206        } = create_info;
207
208        Arc::new(Self {
209            device: InstanceOwnedDebugWrapper(device),
210            handle,
211            id: Self::next_id(),
212
213            create_flags,
214            buffer,
215            ty,
216        })
217    }
218
219    /// Returns the flags the acceleration structure was created with.
220    #[inline]
221    pub fn create_flags(&self) -> AccelerationStructureCreateFlags {
222        self.create_flags
223    }
224
225    /// Returns the subbuffer that the acceleration structure is stored on.
226    #[inline]
227    pub fn buffer(&self) -> &Subbuffer<[u8]> {
228        &self.buffer
229    }
230
231    /// Returns the size of the acceleration structure.
232    #[inline]
233    pub fn size(&self) -> DeviceSize {
234        self.buffer.size()
235    }
236
237    /// Returns the type of the acceleration structure.
238    #[inline]
239    pub fn ty(&self) -> AccelerationStructureType {
240        self.ty
241    }
242
243    /// Returns the device address of the acceleration structure.
244    ///
245    /// The device address of the acceleration structure may be different from the device address
246    /// of the underlying buffer.
247    pub fn device_address(&self) -> NonNullDeviceAddress {
248        let info_vk = ash::vk::AccelerationStructureDeviceAddressInfoKHR::default()
249            .acceleration_structure(self.handle);
250        let fns = self.device.fns();
251        let ptr = unsafe {
252            (fns.khr_acceleration_structure
253                .get_acceleration_structure_device_address_khr)(
254                self.device.handle(), &info_vk
255            )
256        };
257
258        NonNullDeviceAddress::new(ptr).unwrap()
259    }
260}
261
262impl Drop for AccelerationStructure {
263    #[inline]
264    fn drop(&mut self) {
265        let fns = self.device.fns();
266        unsafe {
267            (fns.khr_acceleration_structure
268                .destroy_acceleration_structure_khr)(
269                self.device.handle(), self.handle, ptr::null()
270            )
271        }
272    }
273}
274
275unsafe impl VulkanObject for AccelerationStructure {
276    type Handle = ash::vk::AccelerationStructureKHR;
277
278    #[inline]
279    fn handle(&self) -> Self::Handle {
280        self.handle
281    }
282}
283
284unsafe impl DeviceOwned for AccelerationStructure {
285    #[inline]
286    fn device(&self) -> &Arc<Device> {
287        &self.device
288    }
289}
290
291impl_id_counter!(AccelerationStructure);
292
293vulkan_enum! {
294    #[non_exhaustive]
295
296    /// The type of an acceleration structure.
297    AccelerationStructureType = AccelerationStructureTypeKHR(i32);
298
299    /// Refers to bottom-level acceleration structures. This type can be bound to a descriptor.
300    TopLevel = TOP_LEVEL,
301
302    /// Contains AABBs or geometry to be intersected.
303    BottomLevel = BOTTOM_LEVEL,
304
305    /// The type is determined at build time.
306    ///
307    /// Use of this type is discouraged, it is preferred to specify the type at create time.
308    Generic = GENERIC,
309}
310
311/// Parameters to create a new `AccelerationStructure`.
312#[derive(Clone, Debug)]
313pub struct AccelerationStructureCreateInfo {
314    /// Specifies how to create the acceleration structure.
315    ///
316    /// The default value is empty.
317    pub create_flags: AccelerationStructureCreateFlags,
318
319    /// The subbuffer to store the acceleration structure on.
320    ///
321    /// The subbuffer must have an `offset` that is a multiple of 256, and its `usage` must include
322    /// [`BufferUsage::ACCELERATION_STRUCTURE_STORAGE`]. It must not be accessed while it is bound
323    /// to the acceleration structure.
324    ///
325    /// There is no default value.
326    pub buffer: Subbuffer<[u8]>,
327
328    /// The type of acceleration structure to create.
329    ///
330    /// The default value is [`AccelerationStructureType::Generic`].
331    pub ty: AccelerationStructureType,
332
333    /* TODO: enable
334    // TODO: document
335    pub device_address: DeviceAddress, */
336    pub _ne: crate::NonExhaustive,
337}
338
339impl AccelerationStructureCreateInfo {
340    /// Returns a `AccelerationStructureCreateInfo` with the specified `buffer`.
341    #[inline]
342    pub fn new(buffer: Subbuffer<[u8]>) -> Self {
343        Self {
344            create_flags: AccelerationStructureCreateFlags::empty(),
345            buffer,
346            ty: AccelerationStructureType::Generic,
347            _ne: crate::NonExhaustive(()),
348        }
349    }
350
351    pub(crate) fn validate(&self, device: &Device) -> Result<(), Box<ValidationError>> {
352        let &Self {
353            create_flags,
354            ref buffer,
355            ty,
356            _ne: _,
357        } = self;
358
359        create_flags.validate_device(device).map_err(|err| {
360            err.add_context("create_flags")
361                .set_vuids(&["VUID-VkAccelerationStructureCreateInfoKHR-createFlags-parameter"])
362        })?;
363
364        ty.validate_device(device).map_err(|err| {
365            err.add_context("ty")
366                .set_vuids(&["VUID-VkAccelerationStructureCreateInfoKHR-type-parameter"])
367        })?;
368
369        if !buffer
370            .buffer()
371            .usage()
372            .intersects(BufferUsage::ACCELERATION_STRUCTURE_STORAGE)
373        {
374            return Err(Box::new(ValidationError {
375                context: "buffer".into(),
376                problem: "the buffer was not created with the `ACCELERATION_STRUCTURE_STORAGE` \
377                    usage"
378                    .into(),
379                vuids: &["VUID-VkAccelerationStructureCreateInfoKHR-buffer-03614"],
380                ..Default::default()
381            }));
382        }
383
384        if buffer
385            .buffer()
386            .flags()
387            .intersects(BufferCreateFlags::SPARSE_RESIDENCY)
388        {
389            return Err(Box::new(ValidationError {
390                context: "buffer.buffer().flags()".into(),
391                problem: "contains `BufferCreateFlags::SPARSE_RESIDENCY`".into(),
392                vuids: &["VUID-VkAccelerationStructureCreateInfoKHR-buffer-03615"],
393                ..Default::default()
394            }));
395        }
396
397        // VUID-VkAccelerationStructureCreateInfoKHR-offset-03616
398        // Ensured by the definition of `Subbuffer`.
399
400        if buffer.offset() % 256 != 0 {
401            return Err(Box::new(ValidationError {
402                context: "buffer".into(),
403                problem: "the offset of the buffer is not a multiple of 256".into(),
404                vuids: &["VUID-VkAccelerationStructureCreateInfoKHR-offset-03734"],
405                ..Default::default()
406            }));
407        }
408
409        Ok(())
410    }
411
412    pub(crate) fn to_vk(&self) -> ash::vk::AccelerationStructureCreateInfoKHR<'static> {
413        let &Self {
414            create_flags,
415            ref buffer,
416            ty,
417            _ne: _,
418        } = self;
419
420        ash::vk::AccelerationStructureCreateInfoKHR::default()
421            .create_flags(create_flags.into())
422            .buffer(buffer.buffer().handle())
423            .offset(buffer.offset())
424            .size(buffer.size())
425            .ty(ty.into())
426            .device_address(0) // TODO: allow user to specify
427    }
428}
429
430vulkan_bitflags! {
431    #[non_exhaustive]
432
433    /// Flags that control how an acceleration structure is created.
434    AccelerationStructureCreateFlags = AccelerationStructureCreateFlagsKHR(u32);
435
436    /* TODO: enable
437    // TODO: document
438    DEVICE_ADDRESS_CAPTURE_REPLAY = DEVICE_ADDRESS_CAPTURE_REPLAY_KHR, */
439
440    /* TODO: enable
441    // TODO: document
442    DESCRIPTOR_BUFFER_CAPTURE_REPLAY = DESCRIPTOR_BUFFER_CAPTURE_REPLAY_EXT
443    RequiresOneOf([
444        RequiresAllOf([DeviceExtension(ext_descriptor_buffer)]),
445    ]),*/
446
447    /* TODO: enable
448    // TODO: document
449    MOTION = MOTION_NV
450    RequiresOneOf([
451        RequiresAllOf([DeviceExtension(nv_ray_tracing_motion_blur)]),
452    ]),*/
453}
454
455/// Geometries and other parameters for an acceleration structure build operation.
456#[derive(Clone, Debug)]
457pub struct AccelerationStructureBuildGeometryInfo {
458    /// Specifies how to build the acceleration structure.
459    ///
460    /// The default value is empty.
461    pub flags: BuildAccelerationStructureFlags,
462
463    /// The mode that the build command should operate in.
464    ///
465    /// This is ignored when calling [`Device::acceleration_structure_build_sizes`].
466    ///
467    /// The default value is [`BuildAccelerationStructureMode::Build`].
468    pub mode: BuildAccelerationStructureMode,
469
470    /// The acceleration structure to build or update.
471    ///
472    /// This can be `None` when calling [`Device::acceleration_structure_build_sizes`],
473    /// but must be `Some` otherwise.
474    ///
475    /// There is no default value.
476    pub dst_acceleration_structure: Option<Arc<AccelerationStructure>>,
477
478    /// The geometries that will be built into `dst_acceleration_structure`.
479    ///
480    /// The geometry type must match the `ty` that was specified when the acceleration structure
481    /// was created:
482    /// - `Instances` must be used with `TopLevel` or `Generic`.
483    /// - `Triangles` and `Aabbs` must be used with `BottomLevel` or `Generic`.
484    ///
485    /// There is no default value.
486    pub geometries: AccelerationStructureGeometries,
487
488    /// Scratch memory to be used for the build.
489    ///
490    /// This can be `None` when calling [`Device::acceleration_structure_build_sizes`],
491    /// but must be `Some` otherwise.
492    ///
493    /// The default value is `None`.
494    pub scratch_data: Option<Subbuffer<[u8]>>,
495
496    pub _ne: crate::NonExhaustive,
497}
498
499impl AccelerationStructureBuildGeometryInfo {
500    /// Returns a `AccelerationStructureBuildGeometryInfo` with the specified `geometries`.
501    #[inline]
502    pub fn new(geometries: AccelerationStructureGeometries) -> Self {
503        Self {
504            flags: BuildAccelerationStructureFlags::empty(),
505            mode: BuildAccelerationStructureMode::Build,
506            dst_acceleration_structure: None,
507            geometries,
508            scratch_data: None,
509            _ne: crate::NonExhaustive(()),
510        }
511    }
512
513    pub(crate) fn validate(&self, device: &Device) -> Result<(), Box<ValidationError>> {
514        let &Self {
515            flags,
516            ref mode,
517            ref dst_acceleration_structure,
518            ref geometries,
519            scratch_data: _,
520            _ne: _,
521        } = self;
522
523        flags.validate_device(device).map_err(|err| {
524            err.add_context("flags")
525                .set_vuids(&["VUID-VkAccelerationStructureBuildGeometryInfoKHR-flags-parameter"])
526        })?;
527
528        let max_geometry_count = device
529            .physical_device()
530            .properties()
531            .max_geometry_count
532            .unwrap();
533
534        match geometries {
535            // VUID-VkAccelerationStructureGeometryKHR-triangles-parameter
536            AccelerationStructureGeometries::Triangles(geometries) => {
537                for (index, triangles_data) in geometries.iter().enumerate() {
538                    triangles_data
539                        .validate(device)
540                        .map_err(|err| err.add_context(format!("geometries[{}]", index)))?;
541                }
542
543                if geometries.len() as u64 > max_geometry_count {
544                    return Err(Box::new(ValidationError {
545                        context: "geometries".into(),
546                        problem: "the length exceeds the `max_geometry_count` limit".into(),
547                        vuids: &["VUID-VkAccelerationStructureBuildGeometryInfoKHR-type-03793"],
548                        ..Default::default()
549                    }));
550                }
551
552                // VUID-VkAccelerationStructureBuildGeometryInfoKHR-type-03795
553                // Is checked in the top-level functions.
554            }
555
556            // VUID-VkAccelerationStructureGeometryKHR-aabbs-parameter
557            AccelerationStructureGeometries::Aabbs(geometries) => {
558                for (index, aabbs_data) in geometries.iter().enumerate() {
559                    aabbs_data
560                        .validate(device)
561                        .map_err(|err| err.add_context(format!("geometries[{}]", index)))?;
562                }
563
564                if geometries.len() as u64 > max_geometry_count {
565                    return Err(Box::new(ValidationError {
566                        context: "geometries".into(),
567                        problem: "the length exceeds the `max_geometry_count` limit".into(),
568                        vuids: &["VUID-VkAccelerationStructureBuildGeometryInfoKHR-type-03793"],
569                        ..Default::default()
570                    }));
571                }
572
573                // VUID-VkAccelerationStructureBuildGeometryInfoKHR-type-03794
574                // Is checked in the top-level functions.
575            }
576
577            // VUID-VkAccelerationStructureGeometryKHR-instances-parameter
578            AccelerationStructureGeometries::Instances(instances_data) => {
579                instances_data
580                    .validate(device)
581                    .map_err(|err| err.add_context("geometries"))?;
582            }
583        }
584
585        if let Some(dst_acceleration_structure) = dst_acceleration_structure {
586            // VUID-VkAccelerationStructureBuildGeometryInfoKHR-commonparent
587            assert_eq!(device, dst_acceleration_structure.device().as_ref());
588        }
589
590        if let BuildAccelerationStructureMode::Update(src_acceleration_structure) = mode {
591            assert_eq!(device, src_acceleration_structure.device().as_ref());
592        }
593
594        if flags.contains(
595            BuildAccelerationStructureFlags::PREFER_FAST_TRACE
596                | BuildAccelerationStructureFlags::PREFER_FAST_BUILD,
597        ) {
598            return Err(Box::new(ValidationError {
599                context: "flags".into(),
600                problem: "contains both `BuildAccelerationStructureFlags::PREFER_FAST_TRACE` and \
601                    `BuildAccelerationStructureFlags::PREFER_FAST_BUILD`"
602                    .into(),
603                vuids: &["VUID-VkAccelerationStructureBuildGeometryInfoKHR-flags-03796"],
604                ..Default::default()
605            }));
606        }
607
608        Ok(())
609    }
610
611    pub(crate) fn to_vk<'a>(
612        &self,
613        fields1_vk: &'a AccelerationStructureBuildGeometryInfoFields1Vk,
614    ) -> ash::vk::AccelerationStructureBuildGeometryInfoKHR<'a> {
615        let &Self {
616            flags,
617            ref mode,
618            ref dst_acceleration_structure,
619            ref geometries,
620            ref scratch_data,
621            _ne: _,
622        } = self;
623        let AccelerationStructureBuildGeometryInfoFields1Vk { geometries_vk } = fields1_vk;
624
625        ash::vk::AccelerationStructureBuildGeometryInfoKHR::default()
626            .ty(geometries.to_vk_ty())
627            .flags(flags.into())
628            .mode(mode.to_vk())
629            .src_acceleration_structure(match mode {
630                BuildAccelerationStructureMode::Build => Default::default(),
631                BuildAccelerationStructureMode::Update(src_acceleration_structure) => {
632                    src_acceleration_structure.handle()
633                }
634            })
635            .dst_acceleration_structure(
636                dst_acceleration_structure
637                    .as_ref()
638                    .map_or_else(Default::default, VulkanObject::handle),
639            )
640            .geometries(geometries_vk)
641            .scratch_data(
642                scratch_data
643                    .as_ref()
644                    .map_or_else(Default::default, Subbuffer::to_vk_device_or_host_address),
645            )
646    }
647
648    pub(crate) fn to_vk_fields1(&self) -> AccelerationStructureBuildGeometryInfoFields1Vk {
649        let Self { geometries, .. } = self;
650
651        let geometries_vk = match geometries {
652            AccelerationStructureGeometries::Triangles(geometries) => geometries
653                .iter()
654                .map(AccelerationStructureGeometryTrianglesData::to_vk)
655                .collect(),
656
657            AccelerationStructureGeometries::Aabbs(geometries) => geometries
658                .iter()
659                .map(AccelerationStructureGeometryAabbsData::to_vk)
660                .collect(),
661
662            AccelerationStructureGeometries::Instances(instances_data) => {
663                [instances_data.to_vk()].into_iter().collect()
664            }
665        };
666
667        AccelerationStructureBuildGeometryInfoFields1Vk { geometries_vk }
668    }
669}
670
671pub(crate) struct AccelerationStructureBuildGeometryInfoFields1Vk {
672    pub(crate) geometries_vk: Vec<ash::vk::AccelerationStructureGeometryKHR<'static>>,
673}
674
675vulkan_bitflags! {
676    #[non_exhaustive]
677
678    /// Flags to control how an acceleration structure should be built.
679    BuildAccelerationStructureFlags = BuildAccelerationStructureFlagsKHR(u32);
680
681    /// The built acceleration structure can be updated later by building it again with
682    /// [`BuildAccelerationStructureMode::Update`].
683    ///
684    /// The building process may take more time and memory than normal.
685    ALLOW_UPDATE = ALLOW_UPDATE,
686
687    /// The built acceleration structure can be used later as the source in a copy operation with
688    /// [`CopyAccelerationStructureMode::Compact`].
689    ///
690    /// The building process may take more time and memory than normal.
691    ALLOW_COMPACTION = ALLOW_COMPACTION,
692
693    /// Prioritize for best trace performance, with possibly longer build times.
694    PREFER_FAST_TRACE = PREFER_FAST_TRACE,
695
696    /// Prioritize for shorter build time, with possibly suboptimal trace performance.
697    PREFER_FAST_BUILD = PREFER_FAST_BUILD,
698
699    /// Prioritize low acceleration structure and scratch memory size, with possibly longer build
700    /// times or suboptimal trace performance.
701    LOW_MEMORY = LOW_MEMORY,
702
703    /* TODO: enable
704    // TODO: document
705    MOTION = MOTION_NV
706    RequiresOneOf([
707        RequiresAllOf([DeviceExtension(nv_ray_tracing_motion_blur)]),
708    ]), */
709
710    /* TODO: enable
711    // TODO: document
712    ALLOW_OPACITY_MICROMAP_UPDATE = ALLOW_OPACITY_MICROMAP_UPDATE_EXT
713    RequiresOneOf([
714        RequiresAllOf([DeviceExtension(ext_opacity_micromap)]),
715    ]), */
716
717    /* TODO: enable
718    // TODO: document
719    ALLOW_DISABLE_OPACITY_MICROMAPS = ALLOW_DISABLE_OPACITY_MICROMAPS_EXT
720    RequiresOneOf([
721        RequiresAllOf([DeviceExtension(ext_opacity_micromap)]),
722    ]), */
723
724    /* TODO: enable
725    // TODO: document
726    ALLOW_OPACITY_MICROMAP_DATA_UPDATE = ALLOW_OPACITY_MICROMAP_DATA_UPDATE_EXT
727    RequiresOneOf([
728        RequiresAllOf([DeviceExtension(ext_opacity_micromap)]),
729    ]), */
730
731    /* TODO: enable
732    // TODO: document
733    ALLOW_DISPLACEMENT_MICROMAP_UPDATE = ALLOW_DISPLACEMENT_MICROMAP_UPDATE_NV
734    RequiresOneOf([
735        RequiresAllOf([DeviceExtension(nv_displacement_micromap)]),
736    ]), */
737}
738
739/// What mode an acceleration structure build command should operate in.
740#[derive(Clone, Debug)]
741#[repr(i32)]
742pub enum BuildAccelerationStructureMode {
743    /// Build a new acceleration structure from scratch.
744    Build = ash::vk::BuildAccelerationStructureModeKHR::BUILD.as_raw(),
745
746    /// Update a previously built source acceleration structure with new data, storing the
747    /// updated structure in the destination. The source and destination acceleration structures
748    /// may be the same, which will do the update in-place.
749    ///
750    /// The destination acceleration structure must have been built with the
751    /// [`BuildAccelerationStructureFlags::ALLOW_UPDATE`] flag.
752    Update(Arc<AccelerationStructure>) =
753        ash::vk::BuildAccelerationStructureModeKHR::UPDATE.as_raw(),
754}
755
756impl BuildAccelerationStructureMode {
757    pub(crate) fn to_vk(&self) -> ash::vk::BuildAccelerationStructureModeKHR {
758        match self {
759            BuildAccelerationStructureMode::Build => {
760                ash::vk::BuildAccelerationStructureModeKHR::BUILD
761            }
762            BuildAccelerationStructureMode::Update(_) => {
763                ash::vk::BuildAccelerationStructureModeKHR::UPDATE
764            }
765        }
766    }
767}
768
769/// The type of geometry data in an acceleration structure.
770#[derive(Clone, Debug)]
771pub enum AccelerationStructureGeometries {
772    /// The geometries consist of bottom-level triangles data.
773    Triangles(Vec<AccelerationStructureGeometryTrianglesData>),
774
775    /// The geometries consist of bottom-level axis-aligned bounding box data.
776    Aabbs(Vec<AccelerationStructureGeometryAabbsData>),
777
778    /// The geometries consist of top-level instance data.
779    Instances(AccelerationStructureGeometryInstancesData),
780}
781
782impl AccelerationStructureGeometries {
783    /// Returns the number of geometries.
784    #[inline]
785    pub fn len(&self) -> usize {
786        match self {
787            AccelerationStructureGeometries::Triangles(geometries) => geometries.len(),
788            AccelerationStructureGeometries::Aabbs(geometries) => geometries.len(),
789            AccelerationStructureGeometries::Instances(_) => 1,
790        }
791    }
792
793    pub(crate) fn to_vk_ty(&self) -> ash::vk::AccelerationStructureTypeKHR {
794        match self {
795            AccelerationStructureGeometries::Triangles(_) => {
796                ash::vk::AccelerationStructureTypeKHR::BOTTOM_LEVEL
797            }
798            AccelerationStructureGeometries::Aabbs(_) => {
799                ash::vk::AccelerationStructureTypeKHR::BOTTOM_LEVEL
800            }
801            AccelerationStructureGeometries::Instances(_) => {
802                ash::vk::AccelerationStructureTypeKHR::TOP_LEVEL
803            }
804        }
805    }
806}
807
808impl From<Vec<AccelerationStructureGeometryTrianglesData>> for AccelerationStructureGeometries {
809    #[inline]
810    fn from(value: Vec<AccelerationStructureGeometryTrianglesData>) -> Self {
811        Self::Triangles(value)
812    }
813}
814
815impl From<Vec<AccelerationStructureGeometryAabbsData>> for AccelerationStructureGeometries {
816    #[inline]
817    fn from(value: Vec<AccelerationStructureGeometryAabbsData>) -> Self {
818        Self::Aabbs(value)
819    }
820}
821
822impl From<AccelerationStructureGeometryInstancesData> for AccelerationStructureGeometries {
823    #[inline]
824    fn from(value: AccelerationStructureGeometryInstancesData) -> Self {
825        Self::Instances(value)
826    }
827}
828
829vulkan_bitflags! {
830    #[non_exhaustive]
831
832    /// Flags to control how an acceleration structure geometry should be built.
833    GeometryFlags = GeometryFlagsKHR(u32);
834
835    /// The geometry does not invoke the any-hit shaders, even if it is present in a hit group.
836    OPAQUE = OPAQUE,
837
838    /// The any-hit shader will never be called more than once for each primitive in the geometry.
839    NO_DUPLICATE_ANY_HIT_INVOCATION = NO_DUPLICATE_ANY_HIT_INVOCATION,
840}
841
842/// A bottom-level geometry consisting of triangles.
843#[derive(Clone, Debug)]
844pub struct AccelerationStructureGeometryTrianglesData {
845    /// Specifies how the geometry should be built.
846    ///
847    /// The default value is empty.
848    pub flags: GeometryFlags,
849
850    /// The format of each vertex in `vertex_data`.
851    ///
852    /// This works in the same way as formats for vertex buffers.
853    ///
854    /// There is no default value.
855    pub vertex_format: Format,
856
857    /// The vertex data itself, consisting of an array of `vertex_format` values.
858    ///
859    /// This can be `None` when calling [`Device::acceleration_structure_build_sizes`],
860    /// but must be `Some` otherwise.
861    ///
862    /// The default value is `None`.
863    pub vertex_data: Option<Subbuffer<[u8]>>,
864
865    /// The number of bytes between the start of successive elements in `vertex_data`.
866    ///
867    /// This must be a multiple of the smallest component size (in bytes) of `vertex_format`.
868    ///
869    /// The default value is 0, which must be overridden.
870    pub vertex_stride: u32,
871
872    /// The highest vertex index that may be read from `vertex_data`.
873    ///
874    /// The default value is 0, which must be overridden.
875    pub max_vertex: u32,
876
877    /// If indices are to be used, the buffer holding the index data.
878    ///
879    /// The indices will be used to index into the elements of `vertex_data`.
880    ///
881    /// The default value is `None`.
882    pub index_data: Option<IndexBuffer>,
883
884    /// Optionally, a 3x4 matrix that will be used to transform the vertices in
885    /// `vertex_data` to the space in which the acceleration structure is defined.
886    ///
887    /// The first three columns must be a 3x3 invertible matrix.
888    ///
889    /// The default value is `None`.
890    pub transform_data: Option<Subbuffer<TransformMatrix>>,
891
892    pub _ne: crate::NonExhaustive,
893}
894
895impl AccelerationStructureGeometryTrianglesData {
896    /// Returns a `AccelerationStructureGeometryTrianglesData` with the specified
897    /// `vertex_format`.
898    #[inline]
899    pub fn new(vertex_format: Format) -> Self {
900        Self {
901            flags: GeometryFlags::empty(),
902            vertex_format,
903            vertex_data: None,
904            vertex_stride: 0,
905            max_vertex: 0,
906            index_data: None,
907            transform_data: None,
908            _ne: crate::NonExhaustive(()),
909        }
910    }
911
912    pub(crate) fn validate(&self, device: &Device) -> Result<(), Box<ValidationError>> {
913        let &Self {
914            flags,
915            vertex_format,
916            vertex_data: _,
917            vertex_stride,
918            max_vertex: _,
919            ref index_data,
920            transform_data: _,
921            _ne: _,
922        } = self;
923
924        flags.validate_device(device).map_err(|err| {
925            err.add_context("flags")
926                .set_vuids(&["VUID-VkAccelerationStructureGeometryKHR-flags-parameter"])
927        })?;
928
929        vertex_format.validate_device(device).map_err(|err| {
930            err.add_context("vertex_format").set_vuids(&[
931                "VUID-VkAccelerationStructureGeometryTrianglesDataKHR-vertexFormat-parameter",
932            ])
933        })?;
934
935        let format_properties = unsafe {
936            device
937                .physical_device()
938                .format_properties_unchecked(vertex_format)
939        };
940
941        if !format_properties
942            .buffer_features
943            .intersects(FormatFeatures::ACCELERATION_STRUCTURE_VERTEX_BUFFER)
944        {
945            return Err(Box::new(ValidationError {
946                context: "vertex_format".into(),
947                problem: "format features do not contain \
948                    `FormatFeature::ACCELERATION_STRUCTURE_VERTEX_BUFFER`"
949                    .into(),
950                vuids: &["VUID-VkAccelerationStructureGeometryTrianglesDataKHR-vertexFormat-03797"],
951                ..Default::default()
952            }));
953        }
954
955        let smallest_component_bits = vertex_format
956            .components()
957            .into_iter()
958            .filter(|&c| c != 0)
959            .min()
960            .unwrap() as u32;
961        let smallest_component_bytes = ((smallest_component_bits + 7) & !7) / 8;
962
963        if vertex_stride % smallest_component_bytes != 0 {
964            return Err(Box::new(ValidationError {
965                problem: "`vertex_stride` is not a multiple of the byte size of the \
966                    smallest component of `vertex_format`"
967                    .into(),
968                vuids: &["VUID-VkAccelerationStructureGeometryTrianglesDataKHR-vertexStride-03735"],
969                ..Default::default()
970            }));
971        }
972
973        if let Some(index_data) = index_data.as_ref() {
974            if !matches!(index_data, IndexBuffer::U16(_) | IndexBuffer::U32(_)) {
975                return Err(Box::new(ValidationError {
976                    context: "index_data".into(),
977                    problem: "is not `IndexBuffer::U16` or `IndexBuffer::U32`".into(),
978                    vuids: &[
979                        "VUID-VkAccelerationStructureGeometryTrianglesDataKHR-indexType-03798",
980                    ],
981                    ..Default::default()
982                }));
983            }
984        }
985
986        Ok(())
987    }
988
989    pub(crate) fn to_vk(&self) -> ash::vk::AccelerationStructureGeometryKHR<'static> {
990        let &AccelerationStructureGeometryTrianglesData {
991            flags,
992            vertex_format,
993            ref vertex_data,
994            vertex_stride,
995            max_vertex,
996            ref index_data,
997            ref transform_data,
998            _ne,
999        } = self;
1000
1001        ash::vk::AccelerationStructureGeometryKHR::default()
1002            .geometry_type(ash::vk::GeometryTypeKHR::TRIANGLES)
1003            .geometry(ash::vk::AccelerationStructureGeometryDataKHR {
1004                triangles: ash::vk::AccelerationStructureGeometryTrianglesDataKHR::default()
1005                    .vertex_format(vertex_format.into())
1006                    .vertex_data(vertex_data.as_ref().map_or_else(
1007                        Default::default,
1008                        Subbuffer::to_vk_device_or_host_address_const,
1009                    ))
1010                    .vertex_stride(vertex_stride as DeviceSize)
1011                    .max_vertex(max_vertex)
1012                    .index_type(
1013                        index_data
1014                            .as_ref()
1015                            .map_or(ash::vk::IndexType::NONE_KHR, |index_data| {
1016                                index_data.index_type().into()
1017                            }),
1018                    )
1019                    .index_data(index_data.as_ref().map(IndexBuffer::as_bytes).map_or_else(
1020                        Default::default,
1021                        Subbuffer::to_vk_device_or_host_address_const,
1022                    ))
1023                    .transform_data(transform_data.as_ref().map_or_else(
1024                        Default::default,
1025                        Subbuffer::to_vk_device_or_host_address_const,
1026                    )),
1027            })
1028            .flags(flags.into())
1029    }
1030}
1031
1032/// A 3x4 transformation matrix.
1033///
1034/// The first three columns must be a 3x3 invertible matrix.
1035pub type TransformMatrix = [[f32; 4]; 3];
1036
1037/// A bottom-level geometry consisting of axis-aligned bounding boxes.
1038#[derive(Clone, Debug)]
1039pub struct AccelerationStructureGeometryAabbsData {
1040    /// Specifies how the geometry should be built.
1041    ///
1042    /// The default value is empty.
1043    pub flags: GeometryFlags,
1044
1045    /// The AABB data itself, consisting of an array of [`AabbPositions`] structs.
1046    ///
1047    /// This can be `None` when calling [`Device::acceleration_structure_build_sizes`],
1048    /// but must be `Some` otherwise.
1049    ///
1050    /// The default value is `None`.
1051    pub data: Option<Subbuffer<[u8]>>,
1052
1053    /// The number of bytes between the start of successive elements in `data`.
1054    ///
1055    /// This must be a multiple of 8.
1056    ///
1057    /// The default value is 0, which must be overridden.
1058    pub stride: u32,
1059
1060    pub _ne: crate::NonExhaustive,
1061}
1062
1063impl Default for AccelerationStructureGeometryAabbsData {
1064    #[inline]
1065    fn default() -> Self {
1066        Self {
1067            flags: GeometryFlags::empty(),
1068            data: None,
1069            stride: 0,
1070            _ne: crate::NonExhaustive(()),
1071        }
1072    }
1073}
1074
1075impl AccelerationStructureGeometryAabbsData {
1076    pub(crate) fn validate(&self, device: &Device) -> Result<(), Box<ValidationError>> {
1077        let &Self {
1078            flags,
1079            data: _,
1080            stride,
1081            _ne: _,
1082        } = self;
1083
1084        flags.validate_device(device).map_err(|err| {
1085            err.add_context("flags")
1086                .set_vuids(&["VUID-VkAccelerationStructureGeometryKHR-flags-parameter"])
1087        })?;
1088
1089        if stride % 8 != 0 {
1090            return Err(Box::new(ValidationError {
1091                context: "stride".into(),
1092                problem: "is not a multiple of 8".into(),
1093                vuids: &["VUID-VkAccelerationStructureGeometryAabbsDataKHR-stride-03545"],
1094                ..Default::default()
1095            }));
1096        }
1097
1098        Ok(())
1099    }
1100
1101    pub(crate) fn to_vk(&self) -> ash::vk::AccelerationStructureGeometryKHR<'static> {
1102        let &Self {
1103            flags,
1104            ref data,
1105            stride,
1106            _ne: _,
1107        } = self;
1108
1109        ash::vk::AccelerationStructureGeometryKHR::default()
1110            .geometry_type(ash::vk::GeometryTypeKHR::AABBS)
1111            .geometry(ash::vk::AccelerationStructureGeometryDataKHR {
1112                aabbs: ash::vk::AccelerationStructureGeometryAabbsDataKHR::default()
1113                    .data(data.as_ref().map_or_else(
1114                        Default::default,
1115                        Subbuffer::to_vk_device_or_host_address_const,
1116                    ))
1117                    .stride(stride as DeviceSize),
1118            })
1119            .flags(flags.into())
1120    }
1121}
1122
1123/// Specifies two opposing corners of an axis-aligned bounding box.
1124///
1125/// Each value in `min` must be less than or equal to the corresponding value in `max`.
1126#[derive(Clone, Copy, Debug, Default, PartialEq, Zeroable, Pod)]
1127#[repr(C)]
1128pub struct AabbPositions {
1129    /// The minimum of the corner coordinates of the bounding box.
1130    ///
1131    /// The default value is `[0.0; 3]`.
1132    pub min: [f32; 3],
1133
1134    /// The maximum of the corner coordinates of the bounding box.
1135    ///
1136    /// The default value is `[0.0; 3]`.
1137    pub max: [f32; 3],
1138}
1139
1140/// A top-level geometry consisting of instances of bottom-level acceleration structures.
1141#[derive(Clone, Debug)]
1142pub struct AccelerationStructureGeometryInstancesData {
1143    /// Specifies how the geometry should be built.
1144    ///
1145    /// The default value is empty.
1146    pub flags: GeometryFlags,
1147
1148    /// The instance data itself.
1149    ///
1150    /// There is no default value.
1151    pub data: AccelerationStructureGeometryInstancesDataType,
1152
1153    pub _ne: crate::NonExhaustive,
1154}
1155
1156impl AccelerationStructureGeometryInstancesData {
1157    /// Returns a `AccelerationStructureGeometryInstancesData` with the specified `data`.
1158    #[inline]
1159    pub fn new(data: AccelerationStructureGeometryInstancesDataType) -> Self {
1160        Self {
1161            flags: GeometryFlags::empty(),
1162            data,
1163            _ne: crate::NonExhaustive(()),
1164        }
1165    }
1166
1167    pub(crate) fn validate(&self, device: &Device) -> Result<(), Box<ValidationError>> {
1168        let &Self {
1169            flags,
1170            data: _,
1171            _ne: _,
1172        } = self;
1173
1174        flags.validate_device(device).map_err(|err| {
1175            err.add_context("flags")
1176                .set_vuids(&["VUID-VkAccelerationStructureGeometryKHR-flags-parameter"])
1177        })?;
1178
1179        Ok(())
1180    }
1181
1182    pub(crate) fn to_vk(&self) -> ash::vk::AccelerationStructureGeometryKHR<'static> {
1183        let &Self {
1184            flags,
1185            ref data,
1186            _ne: _,
1187        } = self;
1188
1189        let (array_of_pointers_vk, data_vk) = data.to_vk();
1190
1191        ash::vk::AccelerationStructureGeometryKHR::default()
1192            .geometry_type(ash::vk::GeometryTypeKHR::INSTANCES)
1193            .geometry(ash::vk::AccelerationStructureGeometryDataKHR {
1194                instances: ash::vk::AccelerationStructureGeometryInstancesDataKHR::default()
1195                    .array_of_pointers(array_of_pointers_vk)
1196                    .data(data_vk),
1197            })
1198            .flags(flags.into())
1199    }
1200}
1201
1202/// The data type of an instances geometry.
1203#[derive(Clone, Debug)]
1204pub enum AccelerationStructureGeometryInstancesDataType {
1205    /// The data buffer contains an array of [`AccelerationStructureInstance`] structures directly.
1206    ///
1207    /// The inner value can be `None` when calling [`Device::acceleration_structure_build_sizes`],
1208    /// but must be `Some` otherwise.
1209    Values(Option<Subbuffer<[AccelerationStructureInstance]>>),
1210
1211    /// The data buffer contains an array of pointers to [`AccelerationStructureInstance`]
1212    /// structures.
1213    ///
1214    /// The inner value can be `None` when calling [`Device::acceleration_structure_build_sizes`],
1215    /// but must be `Some` otherwise.
1216    Pointers(Option<Subbuffer<[DeviceSize]>>),
1217}
1218
1219impl AccelerationStructureGeometryInstancesDataType {
1220    pub(crate) fn to_vk(&self) -> (bool, ash::vk::DeviceOrHostAddressConstKHR) {
1221        match self {
1222            AccelerationStructureGeometryInstancesDataType::Values(data) => (
1223                false,
1224                data.as_ref().map_or_else(
1225                    Default::default,
1226                    Subbuffer::to_vk_device_or_host_address_const,
1227                ),
1228            ),
1229            AccelerationStructureGeometryInstancesDataType::Pointers(data) => (
1230                true,
1231                data.as_ref().map_or_else(
1232                    Default::default,
1233                    Subbuffer::to_vk_device_or_host_address_const,
1234                ),
1235            ),
1236        }
1237    }
1238}
1239
1240impl From<Subbuffer<[AccelerationStructureInstance]>>
1241    for AccelerationStructureGeometryInstancesDataType
1242{
1243    #[inline]
1244    fn from(value: Subbuffer<[AccelerationStructureInstance]>) -> Self {
1245        Self::Values(Some(value))
1246    }
1247}
1248
1249impl From<Subbuffer<[DeviceSize]>> for AccelerationStructureGeometryInstancesDataType {
1250    #[inline]
1251    fn from(value: Subbuffer<[DeviceSize]>) -> Self {
1252        Self::Pointers(Some(value))
1253    }
1254}
1255
1256/// Specifies a bottom-level acceleration structure instance when
1257/// building a top-level structure.
1258#[derive(Clone, Copy, Debug, PartialEq, Zeroable, Pod)]
1259#[repr(C)]
1260pub struct AccelerationStructureInstance {
1261    /// A 3x4 transformation matrix to be applied to the bottom-level acceleration structure.
1262    ///
1263    /// The first three columns must be a 3x3 invertible matrix.
1264    ///
1265    /// The default value is a 3x3 identity matrix, with the fourth column filled with zeroes.
1266    pub transform: TransformMatrix,
1267
1268    /// Low 24 bits: A custom index value to be accessible via the `InstanceCustomIndexKHR`
1269    /// built-in variable in ray shaders. The default value is 0.
1270    ///
1271    /// High 8 bits: A visibility mask for the geometry. The instance will not be hit if the
1272    /// cull mask ANDed with this mask is zero. The default value is 0xFF.
1273    pub instance_custom_index_and_mask: Packed24_8,
1274
1275    /// Low 24 bits: An offset used in calculating the binding table index of the hit shader.
1276    /// The default value is 0.
1277    ///
1278    /// High 8 bits: [`GeometryInstanceFlags`] to apply to the instance. The `From` trait can be
1279    /// used to convert the flags into a `u8` value. The default value is empty.
1280    pub instance_shader_binding_table_record_offset_and_flags: Packed24_8,
1281
1282    /// The device address of the bottom-level acceleration structure in this instance.
1283    ///
1284    /// The default value is 0 (null).
1285    pub acceleration_structure_reference: DeviceAddress,
1286}
1287
1288impl Default for AccelerationStructureInstance {
1289    #[inline]
1290    fn default() -> Self {
1291        Self {
1292            transform: [
1293                [1.0, 0.0, 0.0, 0.0],
1294                [0.0, 1.0, 0.0, 0.0],
1295                [0.0, 0.0, 1.0, 0.0],
1296            ],
1297            instance_custom_index_and_mask: Packed24_8::new(0, 0xff),
1298            instance_shader_binding_table_record_offset_and_flags: Packed24_8::new(0, 0),
1299            acceleration_structure_reference: 0,
1300        }
1301    }
1302}
1303
1304vulkan_bitflags! {
1305    #[non_exhaustive]
1306
1307    /// Flags for an instance in a top-level acceleration structure.
1308    GeometryInstanceFlags = GeometryInstanceFlagsKHR(u32);
1309
1310    /// Disable face culling for the instance.
1311    TRIANGLE_FACING_CULL_DISABLE = TRIANGLE_FACING_CULL_DISABLE,
1312
1313    /// Flip the facing (front vs back) of triangles.
1314    TRIANGLE_FLIP_FACING = TRIANGLE_FLIP_FACING,
1315
1316    /// Geometries in this instance will act as if [`GeometryFlags::OPAQUE`] were specified.
1317    FORCE_OPAQUE = FORCE_OPAQUE,
1318
1319    /// Geometries in this instance will act as if [`GeometryFlags::OPAQUE`] were not specified.
1320    FORCE_NO_OPAQUE = FORCE_NO_OPAQUE,
1321
1322    /* TODO: enable
1323    // TODO: document
1324    FORCE_OPACITY_MICROMAP_2_STATE = FORCE_OPACITY_MICROMAP_2_STATE_EXT
1325    RequiresOneOf([
1326        RequiresAllOf([DeviceExtension(ext_opacity_micromap)]),
1327    ]), */
1328
1329    /* TODO: enable
1330    // TODO: document
1331    DISABLE_OPACITY_MICROMAPS = DISABLE_OPACITY_MICROMAPS_EXT
1332    RequiresOneOf([
1333        RequiresAllOf([DeviceExtension(ext_opacity_micromap)]),
1334    ]), */
1335}
1336
1337impl From<GeometryInstanceFlags> for u8 {
1338    #[inline]
1339    fn from(value: GeometryInstanceFlags) -> Self {
1340        value.0 as u8
1341    }
1342}
1343
1344/// Counts and offsets for an acceleration structure build operation.
1345#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Zeroable, Pod)]
1346#[repr(C)]
1347pub struct AccelerationStructureBuildRangeInfo {
1348    /// The number of primitives.
1349    ///
1350    /// The default value is 0.
1351    pub primitive_count: u32,
1352
1353    /// The offset (in bytes) into the buffer holding geometry data,
1354    /// to where the first primitive is stored.
1355    ///
1356    /// The default value is 0.
1357    pub primitive_offset: u32,
1358
1359    /// The index of the first vertex to build from.
1360    ///
1361    /// This is used only for triangle geometries.
1362    ///
1363    /// The default value is 0.
1364    pub first_vertex: u32,
1365
1366    /// The offset (in bytes) into the buffer holding transform matrices,
1367    /// to where the matrix is stored.
1368    ///
1369    /// This is used only for triangle geometries.
1370    ///
1371    /// The default value is 0.
1372    pub transform_offset: u32,
1373}
1374
1375impl AccelerationStructureBuildRangeInfo {
1376    #[allow(clippy::wrong_self_convention)]
1377    pub(crate) fn to_vk(&self) -> ash::vk::AccelerationStructureBuildRangeInfoKHR {
1378        let &Self {
1379            primitive_count,
1380            primitive_offset,
1381            first_vertex,
1382            transform_offset,
1383        } = self;
1384
1385        ash::vk::AccelerationStructureBuildRangeInfoKHR {
1386            primitive_count,
1387            primitive_offset,
1388            first_vertex,
1389            transform_offset,
1390        }
1391    }
1392}
1393
1394/// Parameters for copying an acceleration structure.
1395#[derive(Clone, Debug)]
1396pub struct CopyAccelerationStructureInfo {
1397    /// The acceleration structure to copy from.
1398    ///
1399    /// There is no default value.
1400    pub src: Arc<AccelerationStructure>,
1401
1402    /// The acceleration structure to copy into.
1403    ///
1404    /// There is no default value.
1405    pub dst: Arc<AccelerationStructure>,
1406
1407    /// Additional operations to perform during the copy.
1408    ///
1409    /// The default value is [`CopyAccelerationStructureMode::Clone`].
1410    pub mode: CopyAccelerationStructureMode,
1411
1412    pub _ne: crate::NonExhaustive,
1413}
1414
1415impl CopyAccelerationStructureInfo {
1416    /// Returns a `CopyAccelerationStructureInfo` with the specified `src` and `dst`.
1417    #[inline]
1418    pub fn new(src: Arc<AccelerationStructure>, dst: Arc<AccelerationStructure>) -> Self {
1419        Self {
1420            src,
1421            dst,
1422            mode: CopyAccelerationStructureMode::Clone,
1423            _ne: crate::NonExhaustive(()),
1424        }
1425    }
1426
1427    pub(crate) fn validate(&self, device: &Device) -> Result<(), Box<ValidationError>> {
1428        let &Self {
1429            ref src,
1430            ref dst,
1431            mode,
1432            _ne: _,
1433        } = self;
1434
1435        // VUID-VkCopyAccelerationStructureInfoKHR-commonparent
1436        assert_eq!(device, src.device().as_ref());
1437        assert_eq!(device, dst.device().as_ref());
1438
1439        mode.validate_device(device).map_err(|err| {
1440            err.add_context("mode")
1441                .set_vuids(&["VUID-VkCopyAccelerationStructureInfoKHR-mode-parameter"])
1442        })?;
1443
1444        if !matches!(
1445            mode,
1446            CopyAccelerationStructureMode::Compact | CopyAccelerationStructureMode::Clone
1447        ) {
1448            return Err(Box::new(ValidationError {
1449                context: "mode".into(),
1450                problem: "is not `CopyAccelerationStructureMode::Compact` or \
1451                    `CopyAccelerationStructureMode::Clone`"
1452                    .into(),
1453                vuids: &["VUID-VkCopyAccelerationStructureInfoKHR-mode-03410"],
1454                ..Default::default()
1455            }));
1456        }
1457
1458        if src.buffer() == dst.buffer() {
1459            return Err(Box::new(ValidationError {
1460                problem: "`src` and `dst` share the same buffer".into(),
1461                vuids: &["VUID-VkCopyAccelerationStructureInfoKHR-dst-07791"],
1462                ..Default::default()
1463            }));
1464        }
1465
1466        // VUID-VkCopyAccelerationStructureInfoKHR-src-04963
1467        // TODO: unsafe
1468
1469        // VUID-VkCopyAccelerationStructureInfoKHR-src-03411
1470        // TODO: unsafe
1471
1472        Ok(())
1473    }
1474
1475    pub(crate) fn to_vk(&self) -> ash::vk::CopyAccelerationStructureInfoKHR<'static> {
1476        let &Self {
1477            ref src,
1478            ref dst,
1479            mode,
1480            _ne: _,
1481        } = self;
1482
1483        ash::vk::CopyAccelerationStructureInfoKHR::default()
1484            .src(src.handle())
1485            .dst(dst.handle())
1486            .mode(mode.into())
1487    }
1488}
1489
1490/// Parameters for copying from an acceleration structure into memory.
1491#[derive(Clone, Debug)]
1492pub struct CopyAccelerationStructureToMemoryInfo {
1493    /// The acceleration structure to copy from.
1494    ///
1495    /// There is no default value.
1496    pub src: Arc<AccelerationStructure>,
1497
1498    /// The memory to copy the structure to.
1499    ///
1500    /// There is no default value.
1501    pub dst: Subbuffer<[u8]>,
1502
1503    /// Additional operations to perform during the copy.
1504    ///
1505    /// The default value is [`CopyAccelerationStructureMode::Serialize`].
1506    pub mode: CopyAccelerationStructureMode,
1507
1508    pub _ne: crate::NonExhaustive,
1509}
1510
1511impl CopyAccelerationStructureToMemoryInfo {
1512    /// Returns a `CopyAccelerationStructureToMemoryInfo` with the specified `src` and `dst`.
1513    #[inline]
1514    pub fn new(src: Arc<AccelerationStructure>, dst: Subbuffer<[u8]>) -> Self {
1515        Self {
1516            src,
1517            dst,
1518            mode: CopyAccelerationStructureMode::Serialize,
1519            _ne: crate::NonExhaustive(()),
1520        }
1521    }
1522
1523    pub(crate) fn validate(&self, device: &Device) -> Result<(), Box<ValidationError>> {
1524        let &Self {
1525            ref src,
1526            ref dst,
1527            mode,
1528            _ne: _,
1529        } = self;
1530
1531        assert_eq!(device, src.device().as_ref());
1532        assert_eq!(device, dst.device().as_ref());
1533
1534        mode.validate_device(device).map_err(|err| {
1535            err.add_context("mode")
1536                .set_vuids(&["VUID-VkCopyAccelerationStructureToMemoryInfoKHR-mode-parameter"])
1537        })?;
1538
1539        if !matches!(mode, CopyAccelerationStructureMode::Serialize) {
1540            return Err(Box::new(ValidationError {
1541                context: "mode".into(),
1542                problem: "is not `CopyAccelerationStructureMode::Serialize`".into(),
1543                vuids: &["VUID-VkCopyAccelerationStructureToMemoryInfoKHR-mode-03412"],
1544                ..Default::default()
1545            }));
1546        }
1547
1548        // VUID-VkCopyAccelerationStructureToMemoryInfoKHR-src-04959
1549        // TODO: unsafe
1550
1551        // VUID-VkCopyAccelerationStructureToMemoryInfoKHR-dst-03561
1552        // TODO: unsafe
1553
1554        Ok(())
1555    }
1556
1557    pub(crate) fn to_vk(&self) -> ash::vk::CopyAccelerationStructureToMemoryInfoKHR<'static> {
1558        let &Self {
1559            ref src,
1560            ref dst,
1561            mode,
1562            _ne: _,
1563        } = self;
1564
1565        ash::vk::CopyAccelerationStructureToMemoryInfoKHR::default()
1566            .src(src.handle())
1567            .dst(dst.to_vk_device_or_host_address())
1568            .mode(mode.into())
1569    }
1570}
1571
1572/// Parameters for copying from memory into an acceleration structure.
1573#[derive(Clone, Debug)]
1574pub struct CopyMemoryToAccelerationStructureInfo {
1575    /// The memory to copy the structure from.
1576    ///
1577    /// There is no default value.
1578    pub src: Subbuffer<[u8]>,
1579
1580    /// The acceleration structure to copy into.
1581    ///
1582    /// There is no default value.
1583    pub dst: Arc<AccelerationStructure>,
1584
1585    /// Additional operations to perform during the copy.
1586    ///
1587    /// The default value is [`CopyAccelerationStructureMode::Deserialize`].
1588    pub mode: CopyAccelerationStructureMode,
1589
1590    pub _ne: crate::NonExhaustive,
1591}
1592
1593impl CopyMemoryToAccelerationStructureInfo {
1594    /// Returns a `CopyMemoryToAccelerationStructureInfo` with the specified `src` and `dst`.
1595    #[inline]
1596    pub fn new(src: Subbuffer<[u8]>, dst: Arc<AccelerationStructure>) -> Self {
1597        Self {
1598            src,
1599            dst,
1600            mode: CopyAccelerationStructureMode::Deserialize,
1601            _ne: crate::NonExhaustive(()),
1602        }
1603    }
1604
1605    pub(crate) fn validate(&self, device: &Device) -> Result<(), Box<ValidationError>> {
1606        let &Self {
1607            ref src,
1608            ref dst,
1609            mode,
1610            _ne: _,
1611        } = self;
1612
1613        assert_eq!(device, src.device().as_ref());
1614        assert_eq!(device, dst.device().as_ref());
1615
1616        mode.validate_device(device).map_err(|err| {
1617            err.add_context("mode")
1618                .set_vuids(&["VUID-VkCopyMemoryToAccelerationStructureInfoKHR-mode-parameter"])
1619        })?;
1620
1621        if !matches!(mode, CopyAccelerationStructureMode::Deserialize) {
1622            return Err(Box::new(ValidationError {
1623                context: "mode".into(),
1624                problem: "is not `CopyAccelerationStructureMode::Deserialize`".into(),
1625                vuids: &["VUID-VkCopyMemoryToAccelerationStructureInfoKHR-mode-03413"],
1626                ..Default::default()
1627            }));
1628        }
1629
1630        // VUID-VkCopyMemoryToAccelerationStructureInfoKHR-src-04960
1631        // TODO: unsafe
1632
1633        // VUID-VkCopyMemoryToAccelerationStructureInfoKHR-pInfo-03414
1634        // TODO: unsafe
1635
1636        // VUID-VkCopyMemoryToAccelerationStructureInfoKHR-dst-03746
1637        // TODO: unsafe
1638
1639        Ok(())
1640    }
1641
1642    pub(crate) fn to_vk(&self) -> ash::vk::CopyMemoryToAccelerationStructureInfoKHR<'static> {
1643        let &Self {
1644            ref src,
1645            ref dst,
1646            mode,
1647            _ne: _,
1648        } = self;
1649
1650        ash::vk::CopyMemoryToAccelerationStructureInfoKHR::default()
1651            .src(src.to_vk_device_or_host_address_const())
1652            .dst(dst.handle())
1653            .mode(mode.into())
1654    }
1655}
1656
1657vulkan_enum! {
1658    #[non_exhaustive]
1659
1660    /// What mode an acceleration structure copy command should operate in.
1661    CopyAccelerationStructureMode = CopyAccelerationStructureModeKHR(i32);
1662
1663    /// Copy the source into the destination.
1664    /// This is a shallow copy: if the source holds references to other acceleration structures,
1665    /// only the references are copied, not the other acceleration structures.
1666    ///
1667    /// Both source and destination must have been created with the same
1668    /// [`AccelerationStructureCreateInfo`].
1669    Clone = CLONE,
1670
1671    /// Create a more compact version of the source in the destination.
1672    /// This is a shallow copy: if the source holds references to other acceleration structures,
1673    /// only the references are copied, not the other acceleration structures.
1674    ///
1675    /// The source acceleration structure must have been built with the
1676    /// [`BuildAccelerationStructureFlags::ALLOW_COMPACTION`] flag.
1677    Compact = COMPACT,
1678
1679    /// Serialize the acceleration structure into data in a semi-opaque format,
1680    /// that can be deserialized by a compatible Vulkan implementation.
1681    Serialize = SERIALIZE,
1682
1683    /// Deserialize data back into an acceleration structure.
1684    Deserialize = DESERIALIZE,
1685}
1686
1687vulkan_enum! {
1688    #[non_exhaustive]
1689
1690    /// Where the building of an acceleration structure will take place.
1691    AccelerationStructureBuildType = AccelerationStructureBuildTypeKHR(i32);
1692
1693    /// Building will take place on the host.
1694    Host = HOST,
1695
1696    /// Building will take place on the device.
1697    Device = DEVICE,
1698
1699    /// Building will take place on either the host or the device.
1700    HostOrDevice = HOST_OR_DEVICE,
1701}
1702
1703/// The minimum sizes needed for various resources during an acceleration structure build
1704/// operation.
1705#[derive(Clone, Debug)]
1706pub struct AccelerationStructureBuildSizesInfo {
1707    /// The minimum required size of the acceleration structure for a build or update operation.
1708    pub acceleration_structure_size: DeviceSize,
1709
1710    /// The minimum required size of the scratch data buffer for an update operation.
1711    pub update_scratch_size: DeviceSize,
1712
1713    /// The minimum required size of the scratch data buffer for a build operation.
1714    pub build_scratch_size: DeviceSize,
1715
1716    pub _ne: crate::NonExhaustive,
1717}
1718
1719impl AccelerationStructureBuildSizesInfo {
1720    pub(crate) fn to_mut_vk() -> ash::vk::AccelerationStructureBuildSizesInfoKHR<'static> {
1721        ash::vk::AccelerationStructureBuildSizesInfoKHR::default()
1722    }
1723
1724    pub(crate) fn from_vk(val_vk: &ash::vk::AccelerationStructureBuildSizesInfoKHR<'_>) -> Self {
1725        let &ash::vk::AccelerationStructureBuildSizesInfoKHR {
1726            acceleration_structure_size,
1727            update_scratch_size,
1728            build_scratch_size,
1729            ..
1730        } = val_vk;
1731
1732        AccelerationStructureBuildSizesInfo {
1733            acceleration_structure_size,
1734            update_scratch_size,
1735            build_scratch_size,
1736            _ne: crate::NonExhaustive(()),
1737        }
1738    }
1739}