1use {
4 super::{DriverError, device::Device},
5 ash::vk,
6 derive_builder::{Builder, UninitializedFieldError},
7 gpu_allocator::{
8 MemoryLocation,
9 vulkan::{Allocation, AllocationCreateDesc, AllocationScheme},
10 },
11 log::trace,
12 log::warn,
13 std::{
14 fmt::{Debug, Formatter},
15 mem::ManuallyDrop,
16 ops::{DerefMut, Range},
17 thread::panicking,
18 },
19 vk_sync::AccessType,
20};
21
22#[cfg(feature = "parking_lot")]
23use parking_lot::{Mutex, MutexGuard};
24
25#[cfg(not(feature = "parking_lot"))]
26use std::sync::{Mutex, MutexGuard};
27
28#[read_only::cast]
49pub struct Buffer {
50 accesses: Mutex<BufferAccess>,
51 allocation: ManuallyDrop<Allocation>,
52
53 #[readonly]
57 pub device: Device,
58
59 #[readonly]
63 pub handle: vk::Buffer,
64
65 #[readonly]
69 pub info: BufferInfo,
70
71 pub name: Option<String>,
73}
74
75impl Buffer {
76 #[profiling::function]
99 pub fn create(device: &Device, info: impl Into<BufferInfo>) -> Result<Self, DriverError> {
100 let info = info.into();
101
102 trace!("create: {:?}", info);
103
104 debug_assert_ne!(info.size, 0, "Size must be non-zero");
105
106 let device = device.clone();
107 let buffer_info = vk::BufferCreateInfo::default()
108 .size(info.size)
109 .usage(info.usage)
110 .sharing_mode(vk::SharingMode::CONCURRENT)
111 .queue_family_indices(&device.physical_device.queue_family_indices);
112 let handle = unsafe {
113 device.create_buffer(&buffer_info, None).map_err(|err| {
114 warn!("unable to create buffer: {err}");
115
116 DriverError::Unsupported
117 })?
118 };
119 let mut requirements = unsafe { device.get_buffer_memory_requirements(handle) };
120 requirements.alignment = requirements.alignment.max(info.alignment);
121
122 let allocation_scheme = if info.dedicated {
123 AllocationScheme::DedicatedBuffer(handle)
124 } else {
125 AllocationScheme::GpuAllocatorManaged
126 };
127 let location = if info.host_write {
128 MemoryLocation::CpuToGpu
129 } else if info.host_read {
130 MemoryLocation::GpuToCpu
131 } else {
132 MemoryLocation::GpuOnly
133 };
134 let allocation = {
135 profiling::scope!("allocate");
136
137 Device::with_allocator(&device, |allocator| {
138 allocator
139 .allocate(&AllocationCreateDesc {
140 name: "buffer",
141 requirements,
142 location,
143 linear: true, allocation_scheme,
145 })
146 .map_err(|err| {
147 warn!("unable to allocate buffer memory: {err}");
148
149 unsafe {
150 device.destroy_buffer(handle, None);
151 }
152
153 DriverError::from_alloc_err(err)
154 })
155 .and_then(|allocation| {
156 if let Err(err) = unsafe {
157 device.bind_buffer_memory(
158 handle,
159 allocation.memory(),
160 allocation.offset(),
161 )
162 } {
163 warn!("unable to bind buffer memory: {err}");
164
165 if let Err(err) = allocator.free(allocation) {
166 warn!("unable to free buffer allocation: {err}")
167 }
168
169 unsafe {
170 device.destroy_buffer(handle, None);
171 }
172
173 Err(DriverError::OutOfMemory)
174 } else {
175 Ok(allocation)
176 }
177 })
178 })
179 }?;
180
181 debug_assert_ne!(handle, vk::Buffer::null());
182
183 Ok(Self {
184 accesses: Mutex::new(BufferAccess::new(info.size)),
185 allocation: ManuallyDrop::new(allocation),
186 device,
187 handle,
188 info,
189 name: None,
190 })
191 }
192
193 #[profiling::function]
216 pub fn create_from_slice(
217 device: &Device,
218 usage: vk::BufferUsageFlags,
219 data: &[u8],
220 ) -> Result<Self, DriverError> {
221 let info = BufferInfo::host_mem(data.len() as _, usage);
222 let mut buffer = Self::create(device, info)?;
223
224 Self::copy_from_slice(&mut buffer, 0, data);
225
226 Ok(buffer)
227 }
228
229 #[profiling::function]
279 pub fn access(
280 &self,
281 access: AccessType,
282 access_range: impl Into<BufferSubresourceRange>,
283 ) -> impl Iterator<Item = (AccessType, BufferSubresourceRange)> + '_ {
284 let mut access_range: BufferSubresourceRange = access_range.into();
285
286 if access_range.end == vk::WHOLE_SIZE {
287 access_range.end = self.info.size;
288 }
289
290 BufferAccessIter::new(self.lock_accesses(), access, access_range)
291 }
292
293 #[profiling::function]
320 pub fn copy_from_slice(&mut self, offset: vk::DeviceSize, data: &[u8]) {
321 let range = offset as _..offset as usize + data.len();
322 let mapped_data = self.mapped_slice_mut();
323
324 mapped_data[range].copy_from_slice(data);
325 }
326
327 #[profiling::function]
353 pub fn device_address(&self) -> vk::DeviceAddress {
354 debug_assert!(
355 self.info
356 .usage
357 .contains(vk::BufferUsageFlags::SHADER_DEVICE_ADDRESS)
358 );
359
360 unsafe {
361 self.device.get_buffer_device_address(
362 &vk::BufferDeviceAddressInfo::default().buffer(self.handle),
363 )
364 }
365 }
366
367 fn lock_accesses(&self) -> MutexGuard<'_, BufferAccess> {
368 let accesses = self.accesses.lock();
369
370 #[cfg(not(feature = "parking_lot"))]
371 let accesses = accesses.expect("poisoned buffer access lock");
372
373 accesses
374 }
375
376 #[profiling::function]
404 pub fn mapped_slice(&self) -> &[u8] {
405 debug_assert!(
406 self.info.host_read,
407 "Buffer is not readable - create using host_read flag"
408 );
409
410 &self
411 .allocation
412 .mapped_slice()
413 .expect("missing mapped buffer memory")[0..self.info.size as usize]
414 }
415
416 #[profiling::function]
449 pub fn mapped_slice_mut(&mut self) -> &mut [u8] {
450 debug_assert!(
451 self.info.host_write,
452 "Buffer is not writable - create using host_write flag"
453 );
454
455 &mut self
456 .allocation
457 .mapped_slice_mut()
458 .expect("missing mapped buffer memory")[0..self.info.size as usize]
459 }
460
461 pub fn debug_name(mut self, name: impl Into<String>) -> Self {
463 self.name = Some(name.into());
464
465 self
466 }
467}
468
469impl Debug for Buffer {
470 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
471 if let Some(name) = &self.name {
472 write!(f, "{} ({:?})", name, self.handle)
473 } else {
474 write!(f, "{:?}", self.handle)
475 }
476 }
477}
478
479impl Drop for Buffer {
480 #[profiling::function]
481 fn drop(&mut self) {
482 if panicking() {
483 return;
484 }
485
486 {
487 profiling::scope!("deallocate");
488
489 Device::with_allocator(&self.device, |allocator| {
490 allocator.free(unsafe { ManuallyDrop::take(&mut self.allocation) })
491 })
492 }
493 .unwrap_or_else(|err| warn!("unable to free buffer allocation: {err}"));
494
495 unsafe {
496 self.device.destroy_buffer(self.handle, None);
497 }
498 }
499}
500
501impl Eq for Buffer {}
502
503impl PartialEq for Buffer {
504 fn eq(&self, other: &Self) -> bool {
505 self.handle == other.handle
506 }
507}
508
509#[derive(Debug)]
510struct BufferAccess {
511 accesses: Vec<(AccessType, vk::DeviceSize)>,
512 size: vk::DeviceSize,
513}
514
515impl BufferAccess {
516 fn new(size: vk::DeviceSize) -> Self {
517 Self {
518 accesses: vec![(AccessType::Nothing, 0)],
519 size,
520 }
521 }
522}
523
524struct BufferAccessIter<T> {
525 access: AccessType,
526 access_range: BufferSubresourceRange,
527 buffer: T,
528 idx: usize,
529}
530
531impl<T> BufferAccessIter<T>
532where
533 T: DerefMut<Target = BufferAccess>,
534{
535 fn new(buffer: T, access: AccessType, access_range: BufferSubresourceRange) -> Self {
536 debug_assert!(access_range.start < access_range.end);
537 debug_assert!(access_range.end <= buffer.size);
538
539 #[cfg(debug_assertions)]
540 {
541 let access_start = |(_, access_start): &(AccessType, vk::DeviceSize)| *access_start;
542
543 assert_eq!(buffer.accesses.first().map(access_start), Some(0));
544 assert!(buffer.accesses.last().map(access_start).unwrap() < buffer.size);
545
546 let (mut prev_access, mut prev_start) = buffer.accesses.first().copied().unwrap();
548 for (next_access, next_start) in buffer.accesses.iter().skip(1).copied() {
549 debug_assert_ne!(prev_access, next_access);
550 debug_assert!(prev_start < next_start);
551
552 prev_access = next_access;
553 prev_start = next_start;
554 }
555 };
556
557 let needle = (access_range.start << 1) | 1;
559 let idx = buffer
560 .accesses
561 .binary_search_by(|(_, probe)| (probe << 1).cmp(&needle));
562
563 debug_assert!(idx.is_err());
564
565 let mut idx = unsafe { idx.unwrap_err_unchecked() };
566
567 debug_assert_ne!(idx, 0);
569
570 idx -= 1;
571
572 Self {
573 access,
574 access_range,
575 buffer,
576 idx,
577 }
578 }
579}
580
581impl<T> Iterator for BufferAccessIter<T>
582where
583 T: DerefMut<Target = BufferAccess>,
584{
585 type Item = (AccessType, BufferSubresourceRange);
586
587 fn next(&mut self) -> Option<Self::Item> {
588 debug_assert!(self.access_range.start <= self.access_range.end);
589 debug_assert!(self.access_range.end <= self.buffer.size);
590
591 if self.access_range.start == self.access_range.end {
592 return None;
593 }
594
595 debug_assert!(self.buffer.accesses.get(self.idx).is_some());
596
597 let (access, access_start) = unsafe { *self.buffer.accesses.get_unchecked(self.idx) };
598 let access_end = self
599 .buffer
600 .accesses
601 .get(self.idx + 1)
602 .map(|(_, access_start)| *access_start)
603 .unwrap_or(self.buffer.size);
604 let mut access_range = self.access_range;
605
606 access_range.end = access_range.end.min(access_end);
607 self.access_range.start = access_range.end;
608
609 if access == self.access {
610 self.idx += 1;
611 } else if access_start < access_range.start {
612 if let Some((_, access_start)) = self
613 .buffer
614 .accesses
615 .get_mut(self.idx + 1)
616 .filter(|(access, _)| *access == self.access && access_end == access_range.end)
617 {
618 *access_start = access_range.start;
619 self.idx += 1;
620 } else {
621 self.idx += 1;
622 self.buffer
623 .accesses
624 .insert(self.idx, (self.access, access_range.start));
625
626 if access_end > access_range.end {
627 self.buffer
628 .accesses
629 .insert(self.idx + 1, (access, access_range.end));
630 }
631
632 self.idx += 1;
633 }
634 } else if self.idx > 0 {
635 if self
636 .buffer
637 .accesses
638 .get(self.idx - 1)
639 .filter(|(access, _)| *access == self.access)
640 .is_some()
641 {
642 if access_end == access_range.end {
643 self.buffer.accesses.remove(self.idx);
644
645 if self
646 .buffer
647 .accesses
648 .get(self.idx)
649 .filter(|(access, _)| *access == self.access)
650 .is_some()
651 {
652 self.buffer.accesses.remove(self.idx);
653 self.idx -= 1;
654 }
655 } else {
656 debug_assert!(self.buffer.accesses.get(self.idx).is_some());
657
658 let (_, access_start) =
659 unsafe { self.buffer.accesses.get_unchecked_mut(self.idx) };
660 *access_start = access_range.end;
661 }
662 } else if access_end == access_range.end {
663 debug_assert!(self.buffer.accesses.get(self.idx).is_some());
664
665 let (access, _) = unsafe { self.buffer.accesses.get_unchecked_mut(self.idx) };
666 *access = self.access;
667
668 if self
669 .buffer
670 .accesses
671 .get(self.idx + 1)
672 .filter(|(access, _)| *access == self.access)
673 .is_some()
674 {
675 self.buffer.accesses.remove(self.idx + 1);
676 } else {
677 self.idx += 1;
678 }
679 } else {
680 if let Some((_, access_start)) = self.buffer.accesses.get_mut(self.idx) {
681 *access_start = access_range.end;
682 }
683
684 self.buffer
685 .accesses
686 .insert(self.idx, (self.access, access_range.start));
687 self.idx += 2;
688 }
689 } else if let Some((_, access_start)) = self
690 .buffer
691 .accesses
692 .get_mut(1)
693 .filter(|(access, _)| *access == self.access && access_end == access_range.end)
694 {
695 *access_start = 0;
696 self.buffer.accesses.remove(0);
697 } else if access_end > access_range.end {
698 self.buffer.accesses.insert(0, (self.access, 0));
699
700 debug_assert!(self.buffer.accesses.get(1).is_some());
701
702 let (_, access_start) = unsafe { self.buffer.accesses.get_unchecked_mut(1) };
703 *access_start = access_range.end;
704 } else {
705 debug_assert!(!self.buffer.accesses.is_empty());
706
707 let (access, _) = unsafe { self.buffer.accesses.get_unchecked_mut(0) };
708 *access = self.access;
709
710 if self
711 .buffer
712 .accesses
713 .get(1)
714 .filter(|(access, _)| *access == self.access)
715 .is_some()
716 {
717 self.buffer.accesses.remove(1);
718 } else {
719 self.idx += 1;
720 }
721 }
722
723 Some((access, access_range))
724 }
725}
726
727#[derive(Builder, Clone, Copy, Debug, Eq, Hash, PartialEq)]
729#[builder(
730 build_fn(private, name = "fallible_build", error = "BufferInfoBuilderError"),
731 derive(Clone, Copy, Debug),
732 pattern = "owned"
733)]
734pub struct BufferInfo {
735 #[builder(default = "1")]
739 pub alignment: vk::DeviceSize,
740
741 #[builder(default)]
746 pub dedicated: bool,
747
748 #[builder(default)]
752 pub host_read: bool,
753
754 #[builder(default)]
759 pub host_write: bool,
760
761 pub size: vk::DeviceSize,
763
764 #[builder(default)]
766 pub usage: vk::BufferUsageFlags,
767}
768
769impl BufferInfo {
770 #[inline(always)]
774 pub const fn device_mem(size: vk::DeviceSize, usage: vk::BufferUsageFlags) -> BufferInfo {
775 BufferInfo {
776 alignment: 1,
777 dedicated: false,
778 host_read: false,
779 host_write: false,
780 size,
781 usage,
782 }
783 }
784
785 #[inline(always)]
794 pub const fn host_mem(size: vk::DeviceSize, usage: vk::BufferUsageFlags) -> BufferInfo {
795 let usage = vk::BufferUsageFlags::from_raw(
796 usage.as_raw()
797 | vk::BufferUsageFlags::TRANSFER_DST.as_raw()
798 | vk::BufferUsageFlags::TRANSFER_SRC.as_raw(),
799 );
800
801 BufferInfo {
802 alignment: 1,
803 dedicated: false,
804 host_read: true,
805 host_write: true,
806 size,
807 usage,
808 }
809 }
810
811 pub fn builder() -> BufferInfoBuilder {
813 Default::default()
814 }
815
816 pub fn is_host_mem(&self) -> bool {
818 self.host_read | self.host_write
819 }
820
821 pub fn into_builder(self) -> BufferInfoBuilder {
823 BufferInfoBuilder {
824 alignment: Some(self.alignment),
825 dedicated: Some(self.dedicated),
826 host_read: Some(self.host_read),
827 host_write: Some(self.host_write),
828 size: Some(self.size),
829 usage: Some(self.usage),
830 }
831 }
832
833 #[deprecated = "use into_builder function"]
834 #[doc(hidden)]
835 pub fn to_builder(self) -> BufferInfoBuilder {
836 self.into_builder()
837 }
838}
839
840impl From<BufferInfoBuilder> for BufferInfo {
841 fn from(info: BufferInfoBuilder) -> Self {
842 info.build()
843 }
844}
845
846impl BufferInfoBuilder {
847 #[inline(always)]
857 pub fn build(self) -> BufferInfo {
858 let res = match self.fallible_build() {
859 Err(BufferInfoBuilderError(err)) => panic!("{err}"),
860 Ok(info) => info,
861 };
862
863 assert!(
864 res.alignment.is_power_of_two(),
865 "Alignment must be a power of two"
866 );
867
868 res
869 }
870}
871
872#[derive(Debug)]
873struct BufferInfoBuilderError(UninitializedFieldError);
874
875impl From<UninitializedFieldError> for BufferInfoBuilderError {
876 fn from(err: UninitializedFieldError) -> Self {
877 Self(err)
878 }
879}
880
881#[derive(Clone, Copy, Debug, PartialEq)]
883pub struct BufferSubresourceRange {
884 pub start: vk::DeviceSize,
886
887 pub end: vk::DeviceSize,
889}
890
891impl BufferSubresourceRange {
892 #[cfg(test)]
893 pub(crate) fn intersects(self, other: Self) -> bool {
894 self.start < other.end && self.end > other.start
895 }
896}
897
898impl From<BufferInfo> for BufferSubresourceRange {
899 fn from(info: BufferInfo) -> Self {
900 Self {
901 start: 0,
902 end: info.size,
903 }
904 }
905}
906
907impl From<Range<vk::DeviceSize>> for BufferSubresourceRange {
908 fn from(range: Range<vk::DeviceSize>) -> Self {
909 Self {
910 start: range.start,
911 end: range.end,
912 }
913 }
914}
915
916impl From<BufferSubresourceRange> for Range<vk::DeviceSize> {
917 fn from(subresource: BufferSubresourceRange) -> Self {
918 subresource.start..subresource.end
919 }
920}
921
922#[cfg(test)]
923mod test {
924 use {
925 super::*,
926 rand::{Rng, SeedableRng, rngs::SmallRng},
927 };
928
929 type Info = BufferInfo;
930 type Builder = BufferInfoBuilder;
931
932 const FUZZ_COUNT: usize = 100_000;
933
934 #[test]
935 pub fn buffer_access() {
936 let mut buffer = BufferAccess::new(100);
937
938 {
939 let mut accesses = BufferAccessIter::new(
940 &mut buffer,
941 AccessType::TransferWrite,
942 buffer_subresource_range(0..10),
943 );
944
945 assert_eq!(accesses.buffer.accesses, vec![(AccessType::Nothing, 0)]);
946 assert_eq!(
947 accesses.next().unwrap(),
948 (AccessType::Nothing, buffer_subresource_range(0..10))
949 );
950 assert_eq!(
951 accesses.buffer.accesses,
952 vec![(AccessType::TransferWrite, 0), (AccessType::Nothing, 10)]
953 );
954 assert!(accesses.next().is_none());
955 }
956
957 {
958 let mut accesses = BufferAccessIter::new(
959 &mut buffer,
960 AccessType::TransferRead,
961 buffer_subresource_range(5..15),
962 );
963
964 assert_eq!(
965 accesses.buffer.accesses,
966 vec![(AccessType::TransferWrite, 0), (AccessType::Nothing, 10)]
967 );
968 assert_eq!(
969 accesses.next().unwrap(),
970 (AccessType::TransferWrite, buffer_subresource_range(5..10))
971 );
972 assert_eq!(
973 accesses.buffer.accesses,
974 vec![
975 (AccessType::TransferWrite, 0),
976 (AccessType::TransferRead, 5),
977 (AccessType::Nothing, 10)
978 ]
979 );
980 assert_eq!(
981 accesses.next().unwrap(),
982 (AccessType::Nothing, buffer_subresource_range(10..15))
983 );
984 assert_eq!(
985 accesses.buffer.accesses,
986 vec![
987 (AccessType::TransferWrite, 0),
988 (AccessType::TransferRead, 5),
989 (AccessType::Nothing, 15)
990 ]
991 );
992 assert!(accesses.next().is_none());
993 }
994
995 {
996 let mut accesses = BufferAccessIter::new(
997 &mut buffer,
998 AccessType::HostRead,
999 buffer_subresource_range(0..100),
1000 );
1001
1002 assert_eq!(
1003 accesses.buffer.accesses,
1004 vec![
1005 (AccessType::TransferWrite, 0),
1006 (AccessType::TransferRead, 5),
1007 (AccessType::Nothing, 15)
1008 ]
1009 );
1010 assert_eq!(
1011 accesses.next().unwrap(),
1012 (AccessType::TransferWrite, buffer_subresource_range(0..5))
1013 );
1014 assert_eq!(
1015 accesses.buffer.accesses,
1016 vec![
1017 (AccessType::HostRead, 0),
1018 (AccessType::TransferRead, 5),
1019 (AccessType::Nothing, 15)
1020 ]
1021 );
1022 assert_eq!(
1023 accesses.next().unwrap(),
1024 (AccessType::TransferRead, buffer_subresource_range(5..15))
1025 );
1026 assert_eq!(
1027 accesses.buffer.accesses,
1028 vec![(AccessType::HostRead, 0), (AccessType::Nothing, 15)]
1029 );
1030 assert_eq!(
1031 accesses.next().unwrap(),
1032 (AccessType::Nothing, buffer_subresource_range(15..100))
1033 );
1034 assert_eq!(accesses.buffer.accesses, vec![(AccessType::HostRead, 0),]);
1035 assert!(accesses.next().is_none());
1036 }
1037
1038 {
1039 let mut accesses = BufferAccessIter::new(
1040 &mut buffer,
1041 AccessType::HostWrite,
1042 buffer_subresource_range(0..100),
1043 );
1044
1045 assert_eq!(accesses.buffer.accesses, vec![(AccessType::HostRead, 0)]);
1046 assert_eq!(
1047 accesses.next().unwrap(),
1048 (AccessType::HostRead, buffer_subresource_range(0..100))
1049 );
1050 assert_eq!(accesses.buffer.accesses, vec![(AccessType::HostWrite, 0)]);
1051 assert!(accesses.next().is_none());
1052 }
1053
1054 {
1055 let mut accesses = BufferAccessIter::new(
1056 &mut buffer,
1057 AccessType::HostWrite,
1058 buffer_subresource_range(0..100),
1059 );
1060
1061 assert_eq!(accesses.buffer.accesses, vec![(AccessType::HostWrite, 0)]);
1062 assert_eq!(
1063 accesses.next().unwrap(),
1064 (AccessType::HostWrite, buffer_subresource_range(0..100))
1065 );
1066 assert_eq!(accesses.buffer.accesses, vec![(AccessType::HostWrite, 0)]);
1067 assert!(accesses.next().is_none());
1068 }
1069
1070 {
1071 let mut accesses = BufferAccessIter::new(
1072 &mut buffer,
1073 AccessType::HostWrite,
1074 buffer_subresource_range(1..99),
1075 );
1076
1077 assert_eq!(accesses.buffer.accesses, vec![(AccessType::HostWrite, 0)]);
1078 assert_eq!(
1079 accesses.next().unwrap(),
1080 (AccessType::HostWrite, buffer_subresource_range(1..99))
1081 );
1082 assert_eq!(accesses.buffer.accesses, vec![(AccessType::HostWrite, 0)]);
1083 assert!(accesses.next().is_none());
1084 }
1085
1086 {
1087 let mut accesses = BufferAccessIter::new(
1088 &mut buffer,
1089 AccessType::HostRead,
1090 buffer_subresource_range(1..99),
1091 );
1092
1093 assert_eq!(accesses.buffer.accesses, vec![(AccessType::HostWrite, 0)]);
1094 assert_eq!(
1095 accesses.next().unwrap(),
1096 (AccessType::HostWrite, buffer_subresource_range(1..99))
1097 );
1098 assert_eq!(
1099 accesses.buffer.accesses,
1100 vec![
1101 (AccessType::HostWrite, 0),
1102 (AccessType::HostRead, 1),
1103 (AccessType::HostWrite, 99)
1104 ]
1105 );
1106 assert!(accesses.next().is_none());
1107 }
1108
1109 {
1110 let mut accesses = BufferAccessIter::new(
1111 &mut buffer,
1112 AccessType::Nothing,
1113 buffer_subresource_range(0..100),
1114 );
1115
1116 assert_eq!(
1117 accesses.next().unwrap(),
1118 (AccessType::HostWrite, buffer_subresource_range(0..1))
1119 );
1120 assert_eq!(
1121 accesses.next().unwrap(),
1122 (AccessType::HostRead, buffer_subresource_range(1..99))
1123 );
1124 assert_eq!(
1125 accesses.next().unwrap(),
1126 (AccessType::HostWrite, buffer_subresource_range(99..100))
1127 );
1128 assert!(accesses.next().is_none());
1129 }
1130
1131 {
1132 let mut accesses = BufferAccessIter::new(
1133 &mut buffer,
1134 AccessType::AnyShaderWrite,
1135 buffer_subresource_range(0..100),
1136 );
1137
1138 assert_eq!(
1139 accesses.next().unwrap(),
1140 (AccessType::Nothing, buffer_subresource_range(0..100))
1141 );
1142 assert!(accesses.next().is_none());
1143 }
1144
1145 {
1146 let mut accesses = BufferAccessIter::new(
1147 &mut buffer,
1148 AccessType::AnyShaderReadOther,
1149 buffer_subresource_range(1..2),
1150 );
1151
1152 assert_eq!(
1153 accesses.next().unwrap(),
1154 (AccessType::AnyShaderWrite, buffer_subresource_range(1..2))
1155 );
1156 assert!(accesses.next().is_none());
1157 }
1158
1159 {
1160 let mut accesses = BufferAccessIter::new(
1161 &mut buffer,
1162 AccessType::AnyShaderReadOther,
1163 buffer_subresource_range(3..4),
1164 );
1165
1166 assert_eq!(
1167 accesses.next().unwrap(),
1168 (AccessType::AnyShaderWrite, buffer_subresource_range(3..4))
1169 );
1170 assert!(accesses.next().is_none());
1171 }
1172
1173 {
1174 let mut accesses = BufferAccessIter::new(
1175 &mut buffer,
1176 AccessType::Nothing,
1177 buffer_subresource_range(0..5),
1178 );
1179
1180 assert_eq!(
1181 accesses.next().unwrap(),
1182 (AccessType::AnyShaderWrite, buffer_subresource_range(0..1))
1183 );
1184 assert_eq!(
1185 accesses.next().unwrap(),
1186 (
1187 AccessType::AnyShaderReadOther,
1188 buffer_subresource_range(1..2)
1189 )
1190 );
1191 assert_eq!(
1192 accesses.next().unwrap(),
1193 (AccessType::AnyShaderWrite, buffer_subresource_range(2..3))
1194 );
1195 assert_eq!(
1196 accesses.next().unwrap(),
1197 (
1198 AccessType::AnyShaderReadOther,
1199 buffer_subresource_range(3..4)
1200 )
1201 );
1202 assert_eq!(
1203 accesses.next().unwrap(),
1204 (AccessType::AnyShaderWrite, buffer_subresource_range(4..5))
1205 );
1206 assert!(accesses.next().is_none());
1207 }
1208 }
1209
1210 #[test]
1211 pub fn buffer_access_basic() {
1212 let mut buffer = BufferAccess::new(5);
1213
1214 buffer.accesses = vec![
1215 (AccessType::ColorAttachmentRead, 0),
1216 (AccessType::AnyShaderWrite, 4),
1217 ];
1218
1219 {
1220 let mut accesses = BufferAccessIter::new(
1221 &mut buffer,
1222 AccessType::AnyShaderWrite,
1223 buffer_subresource_range(0..2),
1224 );
1225
1226 assert_eq!(
1227 accesses.next().unwrap(),
1228 (
1229 AccessType::ColorAttachmentRead,
1230 buffer_subresource_range(0..2)
1231 )
1232 );
1233 assert!(accesses.next().is_none());
1234 }
1235
1236 {
1237 let mut accesses = BufferAccessIter::new(
1238 &mut buffer,
1239 AccessType::HostWrite,
1240 buffer_subresource_range(0..5),
1241 );
1242
1243 assert_eq!(
1244 accesses.next().unwrap(),
1245 (AccessType::AnyShaderWrite, buffer_subresource_range(0..2))
1246 );
1247 assert_eq!(
1248 accesses.next().unwrap(),
1249 (
1250 AccessType::ColorAttachmentRead,
1251 buffer_subresource_range(2..4)
1252 )
1253 );
1254 assert_eq!(
1255 accesses.next().unwrap(),
1256 (AccessType::AnyShaderWrite, buffer_subresource_range(4..5))
1257 );
1258
1259 assert!(accesses.next().is_none());
1260 }
1261 }
1262
1263 fn buffer_access_fuzz(buffer_size: vk::DeviceSize) {
1264 static ACCESS_TYPES: &[AccessType] = &[
1265 AccessType::AnyShaderReadOther,
1266 AccessType::AnyShaderWrite,
1267 AccessType::ColorAttachmentRead,
1268 AccessType::ColorAttachmentWrite,
1269 AccessType::HostRead,
1270 AccessType::HostWrite,
1271 AccessType::Nothing,
1272 ];
1273
1274 let mut rng = SmallRng::seed_from_u64(42);
1275 let mut buffer = BufferAccess::new(buffer_size);
1276 let mut data = vec![AccessType::Nothing; buffer_size as usize];
1277
1278 for _ in 0..FUZZ_COUNT {
1279 let access = ACCESS_TYPES[rng.random_range(..ACCESS_TYPES.len())];
1280 let access_start = rng.random_range(..buffer_size);
1281 let access_end = rng.random_range(access_start + 1..=buffer_size);
1282
1283 let accesses = BufferAccessIter::new(
1286 &mut buffer,
1287 access,
1288 buffer_subresource_range(access_start..access_end),
1289 );
1290
1291 for (access, access_range) in accesses {
1292 assert!(
1294 data[access_range.start as usize..access_range.end as usize]
1295 .iter()
1296 .all(|data| *data == access),
1297 "{:?}",
1298 &data[access_range.start as usize..access_range.end as usize]
1299 );
1300 }
1301
1302 for data in &mut data[access_start as usize..access_end as usize] {
1303 *data = access;
1304 }
1305 }
1306 }
1307
1308 #[test]
1309 pub fn buffer_access_fuzz_small() {
1310 buffer_access_fuzz(5);
1311 }
1312
1313 #[test]
1314 pub fn buffer_access_fuzz_medium() {
1315 buffer_access_fuzz(101);
1316 }
1317
1318 #[test]
1319 pub fn buffer_access_fuzz_large() {
1320 buffer_access_fuzz(10_000);
1321 }
1322
1323 #[test]
1324 pub fn buffer_info() {
1325 let info = Info::device_mem(0, vk::BufferUsageFlags::empty());
1326 let builder = info.into_builder().build();
1327
1328 assert_eq!(info, builder);
1329 }
1330
1331 #[test]
1332 pub fn buffer_info_alignment() {
1333 let info = Info::device_mem(0, vk::BufferUsageFlags::empty());
1334
1335 assert_eq!(info.alignment, 1);
1336 }
1337
1338 #[test]
1339 pub fn buffer_info_builder() {
1340 let info = Info::device_mem(0, vk::BufferUsageFlags::empty());
1341 let builder = Builder::default().size(0).build();
1342
1343 assert_eq!(info, builder);
1344 }
1345
1346 #[test]
1347 #[should_panic(expected = "Alignment must be a power of two")]
1348 pub fn buffer_info_builder_alignment_0() {
1349 Builder::default().size(0).alignment(0).build();
1350 }
1351
1352 #[test]
1353 #[should_panic(expected = "Alignment must be a power of two")]
1354 pub fn buffer_info_builder_alignment_42() {
1355 Builder::default().size(0).alignment(42).build();
1356 }
1357
1358 #[test]
1359 pub fn buffer_info_builder_alignment_256() {
1360 let mut info = Info::device_mem(42, vk::BufferUsageFlags::empty());
1361 info.alignment = 256;
1362
1363 let builder = Builder::default().size(42).alignment(256).build();
1364
1365 assert_eq!(info, builder);
1366 }
1367
1368 #[test]
1369 #[should_panic(expected = "Field not initialized: size")]
1370 pub fn buffer_info_builder_uninit_size() {
1371 Builder::default().build();
1372 }
1373
1374 fn buffer_subresource_range(
1375 Range { start, end }: Range<vk::DeviceSize>,
1376 ) -> BufferSubresourceRange {
1377 BufferSubresourceRange { start, end }
1378 }
1379
1380 #[test]
1381 pub fn buffer_subresource_range_intersects() {
1382 use BufferSubresourceRange as B;
1383
1384 assert!(!B { start: 10, end: 20 }.intersects(B { start: 0, end: 5 }));
1385 assert!(!B { start: 10, end: 20 }.intersects(B { start: 5, end: 10 }));
1386 assert!(B { start: 10, end: 20 }.intersects(B { start: 10, end: 15 }));
1387 assert!(B { start: 10, end: 20 }.intersects(B { start: 15, end: 20 }));
1388 assert!(!B { start: 10, end: 20 }.intersects(B { start: 20, end: 25 }));
1389 assert!(!B { start: 10, end: 20 }.intersects(B { start: 25, end: 30 }));
1390
1391 assert!(!B { start: 5, end: 10 }.intersects(B { start: 10, end: 20 }));
1392 assert!(B { start: 5, end: 25 }.intersects(B { start: 10, end: 20 }));
1393 assert!(B { start: 5, end: 15 }.intersects(B { start: 10, end: 20 }));
1394 assert!(B { start: 10, end: 20 }.intersects(B { start: 10, end: 20 }));
1395 assert!(B { start: 11, end: 19 }.intersects(B { start: 10, end: 20 }));
1396 assert!(B { start: 15, end: 25 }.intersects(B { start: 10, end: 20 }));
1397 assert!(!B { start: 20, end: 25 }.intersects(B { start: 10, end: 20 }));
1398 }
1399}