1use {
4 super::{Buffer, BufferInfo, DriverError, device::Device, pipeline_stage_access_flags},
5 ash::vk,
6 derive_builder::Builder,
7 log::warn,
8 std::{
9 ffi::c_void,
10 fmt::{Debug, Formatter},
11 mem::size_of_val,
12 thread::panicking,
13 },
14 vk_sync::AccessType,
15};
16
17#[cfg(feature = "parking_lot")]
18use parking_lot::{Mutex, MutexGuard};
19
20#[cfg(not(feature = "parking_lot"))]
21use std::sync::{Mutex, MutexGuard};
22
23fn accel_struct_sync_flags_for_access(
24 access: AccessType,
25) -> (vk::PipelineStageFlags, vk::AccessFlags) {
26 match access {
27 AccessType::VertexShaderReadOther => (
28 vk::PipelineStageFlags::VERTEX_SHADER,
29 vk::AccessFlags::ACCELERATION_STRUCTURE_READ_KHR,
30 ),
31 AccessType::TessellationControlShaderReadOther => (
32 vk::PipelineStageFlags::TESSELLATION_CONTROL_SHADER,
33 vk::AccessFlags::ACCELERATION_STRUCTURE_READ_KHR,
34 ),
35 AccessType::TessellationEvaluationShaderReadOther => (
36 vk::PipelineStageFlags::TESSELLATION_EVALUATION_SHADER,
37 vk::AccessFlags::ACCELERATION_STRUCTURE_READ_KHR,
38 ),
39 AccessType::GeometryShaderReadOther => (
40 vk::PipelineStageFlags::GEOMETRY_SHADER,
41 vk::AccessFlags::ACCELERATION_STRUCTURE_READ_KHR,
42 ),
43 AccessType::FragmentShaderReadOther => (
44 vk::PipelineStageFlags::FRAGMENT_SHADER,
45 vk::AccessFlags::ACCELERATION_STRUCTURE_READ_KHR,
46 ),
47 AccessType::ComputeShaderReadOther => (
48 vk::PipelineStageFlags::COMPUTE_SHADER,
49 vk::AccessFlags::ACCELERATION_STRUCTURE_READ_KHR,
50 ),
51 AccessType::AnyShaderReadOther => (
52 vk::PipelineStageFlags::ALL_COMMANDS,
53 vk::AccessFlags::ACCELERATION_STRUCTURE_READ_KHR,
54 ),
55 AccessType::RayTracingShaderReadOther => (
56 vk::PipelineStageFlags::RAY_TRACING_SHADER_KHR,
57 vk::AccessFlags::ACCELERATION_STRUCTURE_READ_KHR,
58 ),
59 AccessType::MeshShaderReadOther => (
60 vk::PipelineStageFlags::MESH_SHADER_EXT,
61 vk::AccessFlags::ACCELERATION_STRUCTURE_READ_KHR,
62 ),
63 AccessType::TaskShaderReadOther => (
64 vk::PipelineStageFlags::TASK_SHADER_EXT,
65 vk::AccessFlags::ACCELERATION_STRUCTURE_READ_KHR,
66 ),
67 _ => pipeline_stage_access_flags(access),
68 }
69}
70
71#[read_only::cast]
93pub struct AccelerationStructure {
94 accesses: Mutex<Vec<AccessType>>,
96
97 #[readonly]
101 pub buffer: Buffer,
102
103 #[readonly]
107 pub handle: vk::AccelerationStructureKHR,
108
109 #[readonly]
113 pub info: AccelerationStructureInfo,
114}
115
116impl AccelerationStructure {
117 #[profiling::function]
140 pub fn create(
141 device: &Device,
142 info: impl Into<AccelerationStructureInfo>,
143 ) -> Result<Self, DriverError> {
144 debug_assert!(device.physical.vk_khr_acceleration_structure.is_some());
145
146 let info = info.into();
147
148 let buffer = Buffer::create(
149 device,
150 BufferInfo::device_mem(
151 info.size,
152 vk::BufferUsageFlags::ACCELERATION_STRUCTURE_STORAGE_KHR
153 | vk::BufferUsageFlags::SHADER_DEVICE_ADDRESS,
154 ),
155 )?;
156
157 let handle = {
158 let create_info = vk::AccelerationStructureCreateInfoKHR::default()
159 .ty(info.acceleration_structure_type)
160 .buffer(buffer.handle)
161 .size(info.size);
162
163 let khr_acceleration_structure = Device::expect_vk_khr_acceleration_structure(device);
164
165 unsafe {
166 khr_acceleration_structure
167 .create_acceleration_structure(&create_info, None)
168 .map_err(|err| {
169 warn!("unable to create acceleration structure: {err}");
170
171 match err {
172 vk::Result::ERROR_INVALID_OPAQUE_CAPTURE_ADDRESS => {
173 warn!(
174 "invalid acceleration structure opaque capture address: {err}"
175 );
176 DriverError::InvalidData
177 }
178 vk::Result::ERROR_OUT_OF_HOST_MEMORY => DriverError::OutOfMemory,
179 _ => {
180 warn!("unsupported acceleration structure creation: {err}");
181 DriverError::Unsupported
182 }
183 }
184 })?
185 }
186 };
187
188 Ok(Self {
189 accesses: Mutex::new(vec![AccessType::Nothing]),
190 buffer,
191 handle,
192 info,
193 })
194 }
195
196 #[profiling::function]
220 pub fn device_address(&self) -> vk::DeviceAddress {
221 let khr_acceleration_structure =
222 Device::expect_vk_khr_acceleration_structure(&self.buffer.device);
223
224 unsafe {
225 khr_acceleration_structure.get_acceleration_structure_device_address(
226 &vk::AccelerationStructureDeviceAddressInfoKHR::default()
227 .acceleration_structure(self.handle),
228 )
229 }
230 }
231
232 pub fn instance_slice(instances: &[vk::AccelerationStructureInstanceKHR]) -> &[u8] {
234 use std::slice::from_raw_parts;
235
236 unsafe { from_raw_parts(instances.as_ptr() as *const _, size_of_val(instances)) }
237 }
238
239 fn lock_accesses(&self) -> MutexGuard<'_, Vec<AccessType>> {
240 let accesses = self.accesses.lock();
241
242 #[cfg(not(feature = "parking_lot"))]
243 let accesses = accesses.expect("poisoned acceleration structure access lock");
244
245 accesses
246 }
247
248 pub fn set_debug_name(&self, name: impl AsRef<str>) {
250 Device::try_set_debug_utils_object_name(&self.buffer.device, self.handle, &name);
251 Device::try_set_private_data_object_name(
252 &self.buffer.device,
253 vk::ObjectType::ACCELERATION_STRUCTURE_KHR,
254 self.handle,
255 &name,
256 );
257 }
258
259 #[profiling::function]
309 pub fn size_of(
310 device: &Device,
311 info: &AccelerationStructureGeometryInfo<impl AsRef<AccelerationStructureGeometry>>,
312 ) -> AccelerationStructureSize {
313 use std::cell::RefCell;
314
315 #[derive(Default)]
316 struct Tls {
317 geometries: Vec<vk::AccelerationStructureGeometryKHR<'static>>,
318 max_primitive_counts: Vec<u32>,
319 }
320
321 thread_local! {
322 static TLS: RefCell<Tls> = Default::default();
323 }
324
325 TLS.with_borrow_mut(|tls| {
326 tls.geometries.clear();
327 tls.max_primitive_counts.clear();
328
329 for info in info.geometries.iter().map(AsRef::as_ref) {
330 tls.geometries.push(info.into());
331 tls.max_primitive_counts.push(info.max_primitive_count);
332 }
333
334 let info = vk::AccelerationStructureBuildGeometryInfoKHR::default()
335 .ty(info.acceleration_structure_type)
336 .flags(info.flags)
337 .geometries(&tls.geometries);
338 let mut sizes = vk::AccelerationStructureBuildSizesInfoKHR::default();
339 let khr_acceleration_structure = Device::expect_vk_khr_acceleration_structure(device);
340
341 unsafe {
342 khr_acceleration_structure.get_acceleration_structure_build_sizes(
343 vk::AccelerationStructureBuildTypeKHR::HOST_OR_DEVICE,
344 &info,
345 &tls.max_primitive_counts,
346 &mut sizes,
347 );
348 }
349
350 AccelerationStructureSize {
351 create_size: sizes.acceleration_structure_size,
352 build_size: sizes.build_scratch_size,
353 update_size: sizes.update_scratch_size,
354 }
355 })
356 }
357
358 #[profiling::function]
363 pub(crate) fn swap_access(
364 &self,
365 next_access: AccessType,
366 ) -> impl Iterator<Item = AccessType> + '_ {
367 AccessIter::one(self.lock_accesses(), next_access)
368 }
369
370 pub(crate) fn swap_accesses(
371 &self,
372 next_accesses: &[AccessType],
373 ) -> impl Iterator<Item = AccessType> + '_ {
374 AccessIter::new(self.lock_accesses(), next_accesses)
375 }
376
377 pub fn sync_info(&self) -> AccelerationStructureSyncInfo {
379 AccelerationStructureSyncInfo::from_accesses(self.lock_accesses().iter().copied())
380 }
381
382 pub fn with_debug_name(self, name: impl AsRef<str>) -> Self {
384 self.set_debug_name(name);
385
386 self
387 }
388}
389
390impl Debug for AccelerationStructure {
391 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
392 let mut res = f.debug_struct(stringify!(AccelerationStructure));
393
394 if let Some(debug_name) = &Device::private_data_object_name(
395 &self.buffer.device,
396 vk::ObjectType::ACCELERATION_STRUCTURE_KHR,
397 self.handle,
398 ) {
399 res.field("debug_name", debug_name);
400 }
401
402 res.field("handle", &self.handle).finish_non_exhaustive()
403 }
404}
405
406impl Drop for AccelerationStructure {
407 #[profiling::function]
408 fn drop(&mut self) {
409 if panicking() {
410 return;
411 }
412
413 Device::try_clear_private_data_object_name(
414 &self.buffer.device,
415 vk::ObjectType::ACCELERATION_STRUCTURE_KHR,
416 self.handle,
417 );
418
419 let khr_acceleration_structure =
420 Device::expect_vk_khr_acceleration_structure(&self.buffer.device);
421
422 unsafe {
423 khr_acceleration_structure.destroy_acceleration_structure(self.handle, None);
424 }
425 }
426}
427
428impl Eq for AccelerationStructure {}
429
430impl PartialEq for AccelerationStructure {
431 fn eq(&self, other: &Self) -> bool {
432 self.handle == other.handle
433 }
434}
435
436#[derive(Clone, Copy, Debug)]
440pub struct AccelerationStructureGeometry {
441 pub max_primitive_count: u32,
443
444 pub flags: vk::GeometryFlagsKHR,
446
447 pub geometry: AccelerationStructureGeometryData,
449}
450
451impl AccelerationStructureGeometry {
452 pub fn new(max_primitive_count: u32, geometry: AccelerationStructureGeometryData) -> Self {
454 let flags = Default::default();
455
456 Self {
457 max_primitive_count,
458 flags,
459 geometry,
460 }
461 }
462
463 pub fn opaque(max_primitive_count: u32, geometry: AccelerationStructureGeometryData) -> Self {
466 Self::new(max_primitive_count, geometry).flags(vk::GeometryFlagsKHR::OPAQUE)
467 }
468
469 pub fn flags(mut self, flags: vk::GeometryFlagsKHR) -> Self {
471 self.flags = flags;
472
473 self
474 }
475}
476
477impl<T> AsRef<AccelerationStructureGeometry> for (AccelerationStructureGeometry, T) {
478 fn as_ref(&self) -> &AccelerationStructureGeometry {
479 &self.0
480 }
481}
482
483impl<'b> From<&'b AccelerationStructureGeometry> for vk::AccelerationStructureGeometryKHR<'_> {
484 fn from(&value: &'b AccelerationStructureGeometry) -> Self {
485 value.into()
486 }
487}
488
489impl From<AccelerationStructureGeometry> for vk::AccelerationStructureGeometryKHR<'_> {
490 fn from(value: AccelerationStructureGeometry) -> Self {
491 Self::default()
492 .flags(value.flags)
493 .geometry(value.geometry.into())
494 .geometry_type(value.geometry.into())
495 }
496}
497
498#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
502pub enum AccelerationStructureGeometryData {
503 AABBs {
507 addr: DeviceOrHostAddress,
510
511 stride: vk::DeviceSize,
515 },
516
517 Instances {
521 addr: DeviceOrHostAddress,
529
530 array_of_pointers: bool,
532 },
533
534 Triangles {
538 index_addr: DeviceOrHostAddress,
540
541 index_type: vk::IndexType,
545
546 max_vertex: u32,
549
550 transform_addr: Option<DeviceOrHostAddress>,
557
558 vertex_addr: DeviceOrHostAddress,
560
561 vertex_format: vk::Format,
565
566 vertex_stride: vk::DeviceSize,
568 },
569}
570
571impl AccelerationStructureGeometryData {
572 pub fn aabbs(addr: impl Into<DeviceOrHostAddress>, stride: vk::DeviceSize) -> Self {
574 let addr = addr.into();
575
576 Self::AABBs { addr, stride }
577 }
578
579 pub fn instances(addr: impl Into<DeviceOrHostAddress>) -> Self {
581 let addr = addr.into();
582
583 Self::Instances {
584 addr,
585 array_of_pointers: false,
586 }
587 }
588
589 pub fn instance_pointers(addr: impl Into<DeviceOrHostAddress>) -> Self {
591 let addr = addr.into();
592
593 Self::Instances {
594 addr,
595 array_of_pointers: true,
596 }
597 }
598
599 pub fn triangles(
601 index_addr: impl Into<DeviceOrHostAddress>,
602 index_type: vk::IndexType,
603 max_vertex: u32,
604 transform_addr: impl Into<Option<DeviceOrHostAddress>>,
605 vertex_addr: impl Into<DeviceOrHostAddress>,
606 vertex_format: vk::Format,
607 vertex_stride: vk::DeviceSize,
608 ) -> Self {
609 let index_addr = index_addr.into();
610 let transform_addr = transform_addr.into();
611 let vertex_addr = vertex_addr.into();
612
613 Self::Triangles {
614 index_addr,
615 index_type,
616 max_vertex,
617 transform_addr,
618 vertex_addr,
619 vertex_format,
620 vertex_stride,
621 }
622 }
623}
624
625impl From<AccelerationStructureGeometryData> for vk::GeometryTypeKHR {
626 fn from(value: AccelerationStructureGeometryData) -> Self {
627 match value {
628 AccelerationStructureGeometryData::AABBs { .. } => Self::AABBS,
629 AccelerationStructureGeometryData::Instances { .. } => Self::INSTANCES,
630 AccelerationStructureGeometryData::Triangles { .. } => Self::TRIANGLES,
631 }
632 }
633}
634
635impl From<AccelerationStructureGeometryData> for vk::AccelerationStructureGeometryDataKHR<'_> {
636 fn from(value: AccelerationStructureGeometryData) -> Self {
637 match value {
638 AccelerationStructureGeometryData::AABBs { addr, stride } => Self {
639 aabbs: vk::AccelerationStructureGeometryAabbsDataKHR::default()
640 .data(addr.into())
641 .stride(stride),
642 },
643 AccelerationStructureGeometryData::Instances {
644 addr,
645 array_of_pointers,
646 } => Self {
647 instances: vk::AccelerationStructureGeometryInstancesDataKHR::default()
648 .array_of_pointers(array_of_pointers)
649 .data(addr.into()),
650 },
651 AccelerationStructureGeometryData::Triangles {
652 index_addr,
653 index_type,
654 max_vertex,
655 transform_addr,
656 vertex_addr,
657 vertex_format,
658 vertex_stride,
659 } => Self {
660 triangles: vk::AccelerationStructureGeometryTrianglesDataKHR::default()
661 .index_data(index_addr.into())
662 .index_type(index_type)
663 .max_vertex(max_vertex)
664 .transform_data(transform_addr.map(Into::into).unwrap_or_default())
665 .vertex_data(vertex_addr.into())
666 .vertex_format(vertex_format)
667 .vertex_stride(vertex_stride),
668 },
669 }
670 }
671}
672
673#[derive(Clone, Debug)]
675pub struct AccelerationStructureGeometryInfo<G> {
676 pub acceleration_structure_type: vk::AccelerationStructureTypeKHR,
678
679 pub flags: vk::BuildAccelerationStructureFlagsKHR,
681
682 pub geometries: Box<[G]>,
684}
685
686impl<G> AccelerationStructureGeometryInfo<G> {
687 pub fn blas(geometries: impl Into<Box<[G]>>) -> Self {
689 let geometries = geometries.into();
690
691 Self {
692 acceleration_structure_type: vk::AccelerationStructureTypeKHR::BOTTOM_LEVEL,
693 flags: Default::default(),
694 geometries,
695 }
696 }
697
698 pub fn tlas(geometries: impl Into<Box<[G]>>) -> Self {
701 let geometries = geometries.into();
702
703 Self {
704 acceleration_structure_type: vk::AccelerationStructureTypeKHR::TOP_LEVEL,
705 flags: Default::default(),
706 geometries,
707 }
708 }
709
710 pub fn flags(mut self, flags: vk::BuildAccelerationStructureFlagsKHR) -> Self {
712 self.flags = flags;
713 self
714 }
715}
716
717#[derive(Builder, Clone, Copy, Debug, Eq, Hash, PartialEq)]
721#[builder(
722 build_fn(private, name = "fallible_build"),
723 derive(Clone, Copy, Debug),
724 pattern = "owned"
725)]
726pub struct AccelerationStructureInfo {
727 #[builder(default = "vk::AccelerationStructureTypeKHR::GENERIC")]
729 pub acceleration_structure_type: vk::AccelerationStructureTypeKHR,
730
731 #[builder(default)]
735 pub size: vk::DeviceSize,
736}
737
738impl AccelerationStructureInfo {
739 #[inline(always)]
742 pub const fn blas(size: vk::DeviceSize) -> Self {
743 Self {
744 acceleration_structure_type: vk::AccelerationStructureTypeKHR::BOTTOM_LEVEL,
745 size,
746 }
747 }
748
749 pub fn builder() -> AccelerationStructureInfoBuilder {
751 Default::default()
752 }
753
754 #[inline(always)]
757 pub const fn tlas(size: vk::DeviceSize) -> Self {
758 Self {
759 acceleration_structure_type: vk::AccelerationStructureTypeKHR::TOP_LEVEL,
760 size,
761 }
762 }
763
764 pub fn into_builder(self) -> AccelerationStructureInfoBuilder {
766 AccelerationStructureInfoBuilder {
767 acceleration_structure_type: Some(self.acceleration_structure_type),
768 size: Some(self.size),
769 }
770 }
771}
772
773impl From<AccelerationStructureInfoBuilder> for AccelerationStructureInfo {
774 fn from(info: AccelerationStructureInfoBuilder) -> Self {
775 info.build()
776 }
777}
778
779impl From<AccelerationStructureInfo> for () {
780 fn from(_: AccelerationStructureInfo) -> Self {}
781}
782
783impl AccelerationStructureInfoBuilder {
784 #[inline(always)]
786 pub fn build(self) -> AccelerationStructureInfo {
787 self.fallible_build().expect("all fields have defaults")
788 }
789}
790
791#[derive(Clone, Copy, Debug)]
793pub struct AccelerationStructureSize {
794 pub build_size: vk::DeviceSize,
797
798 pub create_size: vk::DeviceSize,
801
802 pub update_size: vk::DeviceSize,
805}
806
807#[derive(Clone, Copy, Debug)]
809pub struct AccelerationStructureSyncInfo {
810 pub stage_mask: vk::PipelineStageFlags,
812
813 pub access_mask: vk::AccessFlags,
815
816 pub queue_family_index: Option<u32>,
818}
819
820impl AccelerationStructureSyncInfo {
821 fn from_accesses(accesses: impl IntoIterator<Item = AccessType>) -> Self {
822 let mut stage_mask = vk::PipelineStageFlags::empty();
823 let mut access_mask = vk::AccessFlags::empty();
824
825 for access in accesses {
826 let (stages, mask) = accel_struct_sync_flags_for_access(access);
827 stage_mask |= stages;
828 access_mask |= mask;
829 }
830
831 Self {
832 stage_mask,
833 access_mask,
834 queue_family_index: None,
835 }
836 }
837}
838
839struct AccessIter<'a> {
840 accesses: MutexGuard<'a, Vec<AccessType>>,
841 idx: usize,
842 previous_len: usize,
843}
844
845impl<'a> AccessIter<'a> {
846 fn one(mut accesses: MutexGuard<'a, Vec<AccessType>>, next_access: AccessType) -> Self {
847 let previous_len = accesses.len();
848 accesses.push(next_access);
849
850 Self {
851 accesses,
852 idx: 0,
853 previous_len,
854 }
855 }
856
857 fn new(mut accesses: MutexGuard<'a, Vec<AccessType>>, next_accesses: &[AccessType]) -> Self {
858 let previous_len = accesses.len();
859
860 if next_accesses.is_empty() {
861 accesses.push(AccessType::Nothing);
862 } else {
863 for &next_access in next_accesses {
864 if !accesses[previous_len..].contains(&next_access) {
865 accesses.push(next_access);
866 }
867 }
868 }
869
870 Self {
871 accesses,
872 idx: 0,
873 previous_len,
874 }
875 }
876}
877
878impl Iterator for AccessIter<'_> {
879 type Item = AccessType;
880
881 fn next(&mut self) -> Option<Self::Item> {
882 if self.idx == self.previous_len {
883 return None;
884 }
885
886 let access = self.accesses[self.idx];
887 self.idx += 1;
888
889 Some(access)
890 }
891
892 fn size_hint(&self) -> (usize, Option<usize>) {
893 let len = self.len();
894
895 (len, Some(len))
896 }
897}
898
899impl ExactSizeIterator for AccessIter<'_> {
900 fn len(&self) -> usize {
901 self.previous_len - self.idx
902 }
903}
904
905impl Drop for AccessIter<'_> {
906 fn drop(&mut self) {
907 self.accesses.drain(..self.previous_len);
908 }
909}
910
911#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
915pub enum DeviceOrHostAddress {
916 DeviceAddress(vk::DeviceAddress),
918
919 HostAddress(*mut c_void),
921}
922
923impl From<vk::DeviceAddress> for DeviceOrHostAddress {
924 fn from(device_address: vk::DeviceAddress) -> Self {
925 Self::DeviceAddress(device_address)
926 }
927}
928
929impl From<*mut c_void> for DeviceOrHostAddress {
930 fn from(host_address: *mut c_void) -> Self {
931 Self::HostAddress(host_address)
932 }
933}
934
935unsafe impl Send for DeviceOrHostAddress {}
937unsafe impl Sync for DeviceOrHostAddress {}
938
939impl From<DeviceOrHostAddress> for vk::DeviceOrHostAddressConstKHR {
940 fn from(value: DeviceOrHostAddress) -> Self {
941 match value {
942 DeviceOrHostAddress::DeviceAddress(device_address) => Self { device_address },
943 DeviceOrHostAddress::HostAddress(host_address) => Self { host_address },
944 }
945 }
946}
947
948impl From<DeviceOrHostAddress> for vk::DeviceOrHostAddressKHR {
949 fn from(value: DeviceOrHostAddress) -> Self {
950 match value {
951 DeviceOrHostAddress::DeviceAddress(device_address) => Self { device_address },
952 DeviceOrHostAddress::HostAddress(host_address) => Self { host_address },
953 }
954 }
955}
956
957#[cfg(test)]
958mod test {
959 use super::*;
960
961 type Info = AccelerationStructureInfo;
962 type Builder = AccelerationStructureInfoBuilder;
963
964 #[test]
965 pub fn accel_struct_info() {
966 let info = Info::blas(32);
967 let builder = info.into_builder().build();
968
969 assert_eq!(info, builder);
970 }
971
972 #[test]
973 pub fn accel_struct_info_builder() {
974 let info = Info {
975 size: 32,
976 acceleration_structure_type: vk::AccelerationStructureTypeKHR::GENERIC,
977 };
978 let builder = Builder::default().size(32).build();
979
980 assert_eq!(info, builder);
981 }
982
983 #[test]
984 pub fn accel_struct_info_builder_default_size() {
985 let info = Info {
986 size: 0,
987 acceleration_structure_type: vk::AccelerationStructureTypeKHR::GENERIC,
988 };
989
990 assert_eq!(Builder::default().build(), info);
991 }
992}