Skip to main content

vk_graph/driver/
buffer.rs

1//! Buffer resource types
2
3use {
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/// Smart pointer handle to a [buffer] object.
29///
30/// Also contains information about the object.
31///
32/// ```no_run
33/// # use ash::vk;
34/// # use vk_graph::driver::DriverError;
35/// # use vk_graph::driver::device::{Device, DeviceInfo};
36/// # use vk_graph::driver::buffer::{Buffer, BufferInfo};
37/// # fn main() -> Result<(), DriverError> {
38/// # let device = Device::new(DeviceInfo::default())?;
39/// let info = BufferInfo::device_mem(1_024, vk::BufferUsageFlags::STORAGE_BUFFER);
40/// let my_buf = Buffer::create(&device, info)?;
41///
42/// assert_eq!(my_buf.info, info);
43/// assert_ne!(my_buf.handle, vk::Buffer::null());
44/// # Ok(()) }
45/// ```
46///
47/// [buffer]: https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkBuffer.html
48#[read_only::cast]
49pub struct Buffer {
50    accesses: Mutex<BufferAccess>,
51    allocation: ManuallyDrop<Allocation>,
52
53    /// The device which owns this buffer resource.
54    ///
55    /// _Note:_ This field is read-only.
56    #[readonly]
57    pub device: Device,
58
59    /// The native Vulkan resource handle of this buffer.
60    ///
61    /// _Note:_ This field is read-only.
62    #[readonly]
63    pub handle: vk::Buffer,
64
65    /// Information used to create this resource.
66    ///
67    /// _Note:_ This field is read-only.
68    #[readonly]
69    pub info: BufferInfo,
70
71    /// A name for debugging purposes.
72    pub name: Option<String>,
73}
74
75impl Buffer {
76    /// Creates a new buffer on the given device.
77    ///
78    /// # Examples
79    ///
80    /// Basic usage:
81    ///
82    /// ```no_run
83    /// # use std::sync::Arc;
84    /// # use ash::vk;
85    /// # use vk_graph::driver::DriverError;
86    /// # use vk_graph::driver::device::{Device, DeviceInfo};
87    /// # use vk_graph::driver::buffer::{Buffer, BufferInfo};
88    /// # fn main() -> Result<(), DriverError> {
89    /// # let device = Device::new(DeviceInfo::default())?;
90    /// const SIZE: vk::DeviceSize = 1024;
91    /// let info = BufferInfo::host_mem(SIZE, vk::BufferUsageFlags::UNIFORM_BUFFER);
92    /// let buf = Buffer::create(&device, info)?;
93    ///
94    /// assert_ne!(buf.handle, vk::Buffer::null());
95    /// assert_eq!(buf.info.size, SIZE);
96    /// # Ok(()) }
97    /// ```
98    #[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, // Buffers are always linear
144                        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    /// Creates a new mappable buffer on the given device and fills it with the data in `slice`.
194    ///
195    /// # Examples
196    ///
197    /// Basic usage:
198    ///
199    /// ```no_run
200    /// # use std::sync::Arc;
201    /// # use ash::vk;
202    /// # use vk_graph::driver::DriverError;
203    /// # use vk_graph::driver::device::{Device, DeviceInfo};
204    /// # use vk_graph::driver::buffer::{Buffer, BufferInfo};
205    /// # fn main() -> Result<(), DriverError> {
206    /// # let device = Device::new(DeviceInfo::default())?;
207    /// const DATA: [u8; 4] = [0xfe, 0xed, 0xbe, 0xef];
208    /// let buf = Buffer::create_from_slice(&device, vk::BufferUsageFlags::UNIFORM_BUFFER, &DATA)?;
209    ///
210    /// assert_ne!(buf.handle, vk::Buffer::null());
211    /// assert_eq!(buf.info.size, 4);
212    /// assert_eq!(Buffer::mapped_slice(&buf), &DATA);
213    /// # Ok(()) }
214    /// ```
215    #[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    /// Keeps track of some `next_access` which affects this object.
230    ///
231    /// Returns the previous access for which a pipeline barrier should be used to prevent data
232    /// corruption.
233    ///
234    /// # Note
235    ///
236    /// Used to maintain object state when passing a _vk-graph_-created `vk::Buffer` handle to
237    /// external code such as [_Ash_] or [_Erupt_] bindings.
238    ///
239    /// # Examples
240    ///
241    /// Basic usage:
242    ///
243    /// ```no_run
244    /// # use std::sync::Arc;
245    /// # use ash::vk;
246    /// # use vk_graph::driver::{AccessType, DriverError};
247    /// # use vk_graph::driver::device::{Device, DeviceInfo};
248    /// # use vk_graph::driver::buffer::{Buffer, BufferInfo, BufferSubresourceRange};
249    /// # fn main() -> Result<(), DriverError> {
250    /// # let device = Device::new(DeviceInfo::default())?;
251    /// # const SIZE: vk::DeviceSize = 1024;
252    /// # let info = BufferInfo::device_mem(SIZE, vk::BufferUsageFlags::STORAGE_BUFFER);
253    /// # let my_buf = Buffer::create(&device, info)?;
254    /// // Initially we want to "write"
255    /// let access = AccessType::ComputeShaderWrite;
256    /// let access_range = BufferSubresourceRange { start: 0, end: SIZE };
257    /// let mut accesses = Buffer::access(&my_buf, access, access_range);
258    ///
259    /// assert_eq!(accesses.next(), Some((AccessType::Nothing, access_range)));
260    /// assert!(accesses.next().is_none());
261    ///
262    /// // External code may now "write"; no barrier required in this case
263    ///
264    /// // Subsequently we want to "read"
265    /// let access = AccessType::ComputeShaderReadOther;
266    /// let mut accesses = Buffer::access(&my_buf, access, access_range);
267    ///
268    /// assert_eq!(accesses.next(), Some((AccessType::ComputeShaderWrite, access_range)));
269    /// assert!(accesses.next().is_none());
270    ///
271    /// // A barrier on "write" before "read" is required! A render graph will do this
272    /// // automatically when resovled, but manual access like this requires manual barriers
273    /// # Ok(()) }
274    /// ```
275    ///
276    /// [_Ash_]: https://crates.io/crates/ash
277    /// [_Erupt_]: https://crates.io/crates/erupt
278    #[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    /// Updates a mappable buffer starting at `offset` with the data in `slice`.
294    ///
295    /// # Panics
296    ///
297    /// Panics if the buffer was not created with the `mappable` flag set to `true`.
298    ///
299    /// # Examples
300    ///
301    /// Basic usage:
302    ///
303    /// ```no_run
304    /// # use std::sync::Arc;
305    /// # use ash::vk;
306    /// # use vk_graph::driver::DriverError;
307    /// # use vk_graph::driver::device::{Device, DeviceInfo};
308    /// # use vk_graph::driver::buffer::{Buffer, BufferInfo};
309    /// # fn main() -> Result<(), DriverError> {
310    /// # let device = Device::new(DeviceInfo::default())?;
311    /// # let info = BufferInfo::host_mem(4, vk::BufferUsageFlags::empty());
312    /// # let mut my_buf = Buffer::create(&device, info)?;
313    /// const DATA: [u8; 4] = [0xde, 0xad, 0xc0, 0xde];
314    /// Buffer::copy_from_slice(&mut my_buf, 0, &DATA);
315    ///
316    /// assert_eq!(Buffer::mapped_slice(&my_buf), &DATA);
317    /// # Ok(()) }
318    /// ```
319    #[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    /// Returns the device address of this object.
328    ///
329    /// # Panics
330    ///
331    /// Panics if the buffer was not created with the `SHADER_DEVICE_ADDRESS` usage flag.
332    ///
333    /// # Examples
334    ///
335    /// Basic usage:
336    ///
337    /// ```no_run
338    /// # use std::sync::Arc;
339    /// # use ash::vk;
340    /// # use vk_graph::driver::DriverError;
341    /// # use vk_graph::driver::device::{Device, DeviceInfo};
342    /// # use vk_graph::driver::buffer::{Buffer, BufferInfo};
343    /// # fn main() -> Result<(), DriverError> {
344    /// # let device = Device::new(DeviceInfo::default())?;
345    /// # let info = BufferInfo::host_mem(4, vk::BufferUsageFlags::SHADER_DEVICE_ADDRESS);
346    /// # let my_buf = Buffer::create(&device, info)?;
347    /// let addr = my_buf.device_address();
348    ///
349    /// assert_ne!(addr, 0);
350    /// # Ok(()) }
351    /// ```
352    #[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    /// Returns a mapped slice.
377    ///
378    /// # Panics
379    ///
380    /// Panics if the buffer was not created with the `mappable` flag set to `true`.
381    ///
382    /// # Examples
383    ///
384    /// Basic usage:
385    ///
386    /// ```no_run
387    /// # use std::sync::Arc;
388    /// # use ash::vk;
389    /// # use vk_graph::driver::DriverError;
390    /// # use vk_graph::driver::device::{Device, DeviceInfo};
391    /// # use vk_graph::driver::buffer::{Buffer, BufferInfo};
392    /// # fn main() -> Result<(), DriverError> {
393    /// # let device = Device::new(DeviceInfo::default())?;
394    /// # const DATA: [u8; 4] = [0; 4];
395    /// # let my_buf = Buffer::create_from_slice(&device, vk::BufferUsageFlags::empty(), &DATA)?;
396    /// // my_buf is mappable and filled with four zeroes
397    /// let data = Buffer::mapped_slice(&my_buf);
398    ///
399    /// assert_eq!(data.len(), 4);
400    /// assert_eq!(data[0], 0x00);
401    /// # Ok(()) }
402    /// ```
403    #[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    /// Returns a mapped mutable slice.
417    ///
418    /// # Panics
419    ///
420    /// Panics if the buffer was not created with the `mappable` flag set to `true`.
421    ///
422    /// # Examples
423    ///
424    /// Basic usage:
425    ///
426    /// ```no_run
427    /// # use std::sync::Arc;
428    /// # use ash::vk;
429    /// # use glam::Mat4;
430    /// # use vk_graph::driver::DriverError;
431    /// # use vk_graph::driver::device::{Device, DeviceInfo};
432    /// # use vk_graph::driver::buffer::{Buffer, BufferInfo};
433    /// # fn main() -> Result<(), DriverError> {
434    /// # let device = Device::new(DeviceInfo::default())?;
435    /// # const DATA: [u8; 4] = [0; 4];
436    /// # let mut my_buf = Buffer::create_from_slice(
437    /// #     &device,
438    /// #     vk::BufferUsageFlags::empty(),
439    /// #     &DATA,
440    /// # )?;
441    /// let mut data = Buffer::mapped_slice_mut(&mut my_buf);
442    /// data.copy_from_slice(&42f32.to_be_bytes());
443    ///
444    /// assert_eq!(data.len(), 4);
445    /// assert_eq!(data[0], 0x42);
446    /// # Ok(()) }
447    /// ```
448    #[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    /// Sets the debugging name assigned to this buffer.
462    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            // Custom is-sorted-by key to additionally check that all access starts are unique
547            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        // The needle will always be odd, and the probe always even, the result will always be err
558        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        // The first access will always be at start == 0, which is even, so idx cannot be 0
568        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/// Information used to create a [`Buffer`] instance.
728#[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    /// Byte alignment of the base device address of the buffer.
736    ///
737    /// Must be a power of two.
738    #[builder(default = "1")]
739    pub alignment: vk::DeviceSize,
740
741    /// Specifies a dedicated memory allocation managed by the Vulkan driver and not by the
742    /// internal memory allocation pool transient resources share.
743    ///
744    /// The driver may optimize access to dedicated buffers.
745    #[builder(default)]
746    pub dedicated: bool,
747
748    /// Specifies a buffer whose memory is host visible and may be mapped.
749    ///
750    /// Memory optimal for CPU readback of data may be used.
751    #[builder(default)]
752    pub host_read: bool,
753
754    /// Specifies a buffer whose memory is host visible and may be mapped.
755    ///
756    /// Memory optimal for uploading data to the GPU and potentially for constant buffers may be
757    /// used.
758    #[builder(default)]
759    pub host_write: bool,
760
761    /// Size in bytes of the buffer to be created.
762    pub size: vk::DeviceSize,
763
764    /// A bitmask of specifying allowed usages of the buffer.
765    #[builder(default)]
766    pub usage: vk::BufferUsageFlags,
767}
768
769impl BufferInfo {
770    /// Specifies a non-mappable buffer with the given `size` and `usage` values.
771    ///
772    /// Device-local memory (located on the GPU) is used.
773    #[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    /// Specifies a mappable buffer with the given `size` and `usage` values.
786    ///
787    /// Host-local memory (located in CPU-accesible RAM) is used.
788    ///
789    /// # Note
790    ///
791    /// For convenience the given usage value will be bitwise OR'd with
792    /// `TRANSFER_DST | TRANSFER_SRC`.
793    #[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    /// Creates a default `BufferInfoBuilder`.
812    pub fn builder() -> BufferInfoBuilder {
813        Default::default()
814    }
815
816    /// Returns `true` if this information specifies host-accessible memory.
817    pub fn is_host_mem(&self) -> bool {
818        self.host_read | self.host_write
819    }
820
821    /// Converts a `BufferInfo` into a `BufferInfoBuilder`.
822    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    /// Builds a new `BufferInfo`.
848    ///    
849    /// # Panics
850    ///
851    /// If any of the following values have not been set this function will panic:
852    ///
853    /// * `size`
854    ///
855    /// If `alignment` is not a power to two this function will panic.
856    #[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/// Specifies a range of buffer data.
882#[derive(Clone, Copy, Debug, PartialEq)]
883pub struct BufferSubresourceRange {
884    /// The start of range.
885    pub start: vk::DeviceSize,
886
887    /// The non-inclusive end of the range.
888    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            // println!("{access:?} {access_start}..{access_end}");
1284
1285            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                // println!("\t{access:?} {}..{}", access_range.start, access_range.end);
1293                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}