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