1use 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#[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 #[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 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 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 #[inline]
221 pub fn create_flags(&self) -> AccelerationStructureCreateFlags {
222 self.create_flags
223 }
224
225 #[inline]
227 pub fn buffer(&self) -> &Subbuffer<[u8]> {
228 &self.buffer
229 }
230
231 #[inline]
233 pub fn size(&self) -> DeviceSize {
234 self.buffer.size()
235 }
236
237 #[inline]
239 pub fn ty(&self) -> AccelerationStructureType {
240 self.ty
241 }
242
243 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 AccelerationStructureType = AccelerationStructureTypeKHR(i32);
298
299 TopLevel = TOP_LEVEL,
301
302 BottomLevel = BOTTOM_LEVEL,
304
305 Generic = GENERIC,
309}
310
311#[derive(Clone, Debug)]
313pub struct AccelerationStructureCreateInfo {
314 pub create_flags: AccelerationStructureCreateFlags,
318
319 pub buffer: Subbuffer<[u8]>,
327
328 pub ty: AccelerationStructureType,
332
333 pub _ne: crate::NonExhaustive,
337}
338
339impl AccelerationStructureCreateInfo {
340 #[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 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) }
428}
429
430vulkan_bitflags! {
431 #[non_exhaustive]
432
433 AccelerationStructureCreateFlags = AccelerationStructureCreateFlagsKHR(u32);
435
436 }
454
455#[derive(Clone, Debug)]
457pub struct AccelerationStructureBuildGeometryInfo {
458 pub flags: BuildAccelerationStructureFlags,
462
463 pub mode: BuildAccelerationStructureMode,
469
470 pub dst_acceleration_structure: Option<Arc<AccelerationStructure>>,
477
478 pub geometries: AccelerationStructureGeometries,
487
488 pub scratch_data: Option<Subbuffer<[u8]>>,
495
496 pub _ne: crate::NonExhaustive,
497}
498
499impl AccelerationStructureBuildGeometryInfo {
500 #[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 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 }
555
556 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 }
576
577 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 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 BuildAccelerationStructureFlags = BuildAccelerationStructureFlagsKHR(u32);
680
681 ALLOW_UPDATE = ALLOW_UPDATE,
686
687 ALLOW_COMPACTION = ALLOW_COMPACTION,
692
693 PREFER_FAST_TRACE = PREFER_FAST_TRACE,
695
696 PREFER_FAST_BUILD = PREFER_FAST_BUILD,
698
699 LOW_MEMORY = LOW_MEMORY,
702
703 }
738
739#[derive(Clone, Debug)]
741#[repr(i32)]
742pub enum BuildAccelerationStructureMode {
743 Build = ash::vk::BuildAccelerationStructureModeKHR::BUILD.as_raw(),
745
746 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#[derive(Clone, Debug)]
771pub enum AccelerationStructureGeometries {
772 Triangles(Vec<AccelerationStructureGeometryTrianglesData>),
774
775 Aabbs(Vec<AccelerationStructureGeometryAabbsData>),
777
778 Instances(AccelerationStructureGeometryInstancesData),
780}
781
782impl AccelerationStructureGeometries {
783 #[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 GeometryFlags = GeometryFlagsKHR(u32);
834
835 OPAQUE = OPAQUE,
837
838 NO_DUPLICATE_ANY_HIT_INVOCATION = NO_DUPLICATE_ANY_HIT_INVOCATION,
840}
841
842#[derive(Clone, Debug)]
844pub struct AccelerationStructureGeometryTrianglesData {
845 pub flags: GeometryFlags,
849
850 pub vertex_format: Format,
856
857 pub vertex_data: Option<Subbuffer<[u8]>>,
864
865 pub vertex_stride: u32,
871
872 pub max_vertex: u32,
876
877 pub index_data: Option<IndexBuffer>,
883
884 pub transform_data: Option<Subbuffer<TransformMatrix>>,
891
892 pub _ne: crate::NonExhaustive,
893}
894
895impl AccelerationStructureGeometryTrianglesData {
896 #[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
1032pub type TransformMatrix = [[f32; 4]; 3];
1036
1037#[derive(Clone, Debug)]
1039pub struct AccelerationStructureGeometryAabbsData {
1040 pub flags: GeometryFlags,
1044
1045 pub data: Option<Subbuffer<[u8]>>,
1052
1053 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#[derive(Clone, Copy, Debug, Default, PartialEq, Zeroable, Pod)]
1127#[repr(C)]
1128pub struct AabbPositions {
1129 pub min: [f32; 3],
1133
1134 pub max: [f32; 3],
1138}
1139
1140#[derive(Clone, Debug)]
1142pub struct AccelerationStructureGeometryInstancesData {
1143 pub flags: GeometryFlags,
1147
1148 pub data: AccelerationStructureGeometryInstancesDataType,
1152
1153 pub _ne: crate::NonExhaustive,
1154}
1155
1156impl AccelerationStructureGeometryInstancesData {
1157 #[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#[derive(Clone, Debug)]
1204pub enum AccelerationStructureGeometryInstancesDataType {
1205 Values(Option<Subbuffer<[AccelerationStructureInstance]>>),
1210
1211 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#[derive(Clone, Copy, Debug, PartialEq, Zeroable, Pod)]
1259#[repr(C)]
1260pub struct AccelerationStructureInstance {
1261 pub transform: TransformMatrix,
1267
1268 pub instance_custom_index_and_mask: Packed24_8,
1274
1275 pub instance_shader_binding_table_record_offset_and_flags: Packed24_8,
1281
1282 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 GeometryInstanceFlags = GeometryInstanceFlagsKHR(u32);
1309
1310 TRIANGLE_FACING_CULL_DISABLE = TRIANGLE_FACING_CULL_DISABLE,
1312
1313 TRIANGLE_FLIP_FACING = TRIANGLE_FLIP_FACING,
1315
1316 FORCE_OPAQUE = FORCE_OPAQUE,
1318
1319 FORCE_NO_OPAQUE = FORCE_NO_OPAQUE,
1321
1322 }
1336
1337impl From<GeometryInstanceFlags> for u8 {
1338 #[inline]
1339 fn from(value: GeometryInstanceFlags) -> Self {
1340 value.0 as u8
1341 }
1342}
1343
1344#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Zeroable, Pod)]
1346#[repr(C)]
1347pub struct AccelerationStructureBuildRangeInfo {
1348 pub primitive_count: u32,
1352
1353 pub primitive_offset: u32,
1358
1359 pub first_vertex: u32,
1365
1366 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#[derive(Clone, Debug)]
1396pub struct CopyAccelerationStructureInfo {
1397 pub src: Arc<AccelerationStructure>,
1401
1402 pub dst: Arc<AccelerationStructure>,
1406
1407 pub mode: CopyAccelerationStructureMode,
1411
1412 pub _ne: crate::NonExhaustive,
1413}
1414
1415impl CopyAccelerationStructureInfo {
1416 #[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 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 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#[derive(Clone, Debug)]
1492pub struct CopyAccelerationStructureToMemoryInfo {
1493 pub src: Arc<AccelerationStructure>,
1497
1498 pub dst: Subbuffer<[u8]>,
1502
1503 pub mode: CopyAccelerationStructureMode,
1507
1508 pub _ne: crate::NonExhaustive,
1509}
1510
1511impl CopyAccelerationStructureToMemoryInfo {
1512 #[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 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#[derive(Clone, Debug)]
1574pub struct CopyMemoryToAccelerationStructureInfo {
1575 pub src: Subbuffer<[u8]>,
1579
1580 pub dst: Arc<AccelerationStructure>,
1584
1585 pub mode: CopyAccelerationStructureMode,
1589
1590 pub _ne: crate::NonExhaustive,
1591}
1592
1593impl CopyMemoryToAccelerationStructureInfo {
1594 #[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 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 CopyAccelerationStructureMode = CopyAccelerationStructureModeKHR(i32);
1662
1663 Clone = CLONE,
1670
1671 Compact = COMPACT,
1678
1679 Serialize = SERIALIZE,
1682
1683 Deserialize = DESERIALIZE,
1685}
1686
1687vulkan_enum! {
1688 #[non_exhaustive]
1689
1690 AccelerationStructureBuildType = AccelerationStructureBuildTypeKHR(i32);
1692
1693 Host = HOST,
1695
1696 Device = DEVICE,
1698
1699 HostOrDevice = HOST_OR_DEVICE,
1701}
1702
1703#[derive(Clone, Debug)]
1706pub struct AccelerationStructureBuildSizesInfo {
1707 pub acceleration_structure_size: DeviceSize,
1709
1710 pub update_scratch_size: DeviceSize,
1712
1713 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}