vulkano/buffer/
sys.rs

1//! Low level implementation of buffers.
2//!
3//! This module contains low-level wrappers around the Vulkan buffer types. All
4//! other buffer types of this library, and all custom buffer types
5//! that you create must wrap around the types in this module.
6
7use super::{Buffer, BufferCreateFlags, BufferMemory, BufferUsage};
8use crate::{
9    buffer::ExternalBufferInfo,
10    device::{Device, DeviceOwned},
11    instance::InstanceOwnedDebugWrapper,
12    macros::impl_id_counter,
13    memory::{
14        allocator::AllocationType, is_aligned, DedicatedTo, ExternalMemoryHandleTypes,
15        MemoryAllocateFlags, MemoryPropertyFlags, MemoryRequirements, ResourceMemory,
16    },
17    sync::Sharing,
18    DeviceSize, Requires, RequiresAllOf, RequiresOneOf, Validated, ValidationError, Version,
19    VulkanError, VulkanObject,
20};
21use smallvec::SmallVec;
22use std::{marker::PhantomData, mem::MaybeUninit, num::NonZeroU64, ptr, sync::Arc};
23
24/// A raw buffer, with no memory backing it.
25///
26/// This is the basic buffer type, a direct translation of a `VkBuffer` object, but it is mostly
27/// useless in this form. After creating a raw buffer, you must call `bind_memory` to make a
28/// complete buffer object.
29#[derive(Debug)]
30pub struct RawBuffer {
31    handle: ash::vk::Buffer,
32    device: InstanceOwnedDebugWrapper<Arc<Device>>,
33    id: NonZeroU64,
34
35    flags: BufferCreateFlags,
36    size: DeviceSize,
37    usage: BufferUsage,
38    sharing: Sharing<SmallVec<[u32; 4]>>,
39    external_memory_handle_types: ExternalMemoryHandleTypes,
40
41    memory_requirements: MemoryRequirements,
42    needs_destruction: bool,
43}
44
45impl RawBuffer {
46    /// Creates a new `RawBuffer`.
47    ///
48    /// # Panics
49    ///
50    /// - Panics if `create_info.sharing` is [`Concurrent`](Sharing::Concurrent) with less than 2
51    ///   items.
52    /// - Panics if `create_info.size` is zero.
53    /// - Panics if `create_info.usage` is empty.
54    #[inline]
55    pub fn new(
56        device: Arc<Device>,
57        create_info: BufferCreateInfo,
58    ) -> Result<Self, Validated<VulkanError>> {
59        Self::validate_new(&device, &create_info)?;
60
61        Ok(unsafe { Self::new_unchecked(device, create_info) }?)
62    }
63
64    fn validate_new(
65        device: &Device,
66        create_info: &BufferCreateInfo,
67    ) -> Result<(), Box<ValidationError>> {
68        create_info
69            .validate(device)
70            .map_err(|err| err.add_context("create_info"))?;
71
72        // TODO: sparse_address_space_size and extended_sparse_address_space_size limits
73        // VUID-vkCreateBuffer-flags-00911
74        // VUID-vkCreateBuffer-flags-09383
75        // VUID-vkCreateBuffer-flags-09384
76
77        Ok(())
78    }
79
80    #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
81    pub unsafe fn new_unchecked(
82        device: Arc<Device>,
83        create_info: BufferCreateInfo,
84    ) -> Result<Self, VulkanError> {
85        let mut extensions_vk = create_info.to_vk_extensions();
86        let create_info_vk = create_info.to_vk(&mut extensions_vk);
87
88        let handle = {
89            let fns = device.fns();
90            let mut output = MaybeUninit::uninit();
91            unsafe {
92                (fns.v1_0.create_buffer)(
93                    device.handle(),
94                    &create_info_vk,
95                    ptr::null(),
96                    output.as_mut_ptr(),
97                )
98            }
99            .result()
100            .map_err(VulkanError::from)?;
101            unsafe { output.assume_init() }
102        };
103
104        Ok(unsafe { Self::from_handle(device, handle, create_info) })
105    }
106
107    /// Creates a new `RawBuffer` from a raw object handle.
108    ///
109    /// # Safety
110    ///
111    /// - `handle` must be a valid Vulkan object handle created from `device`.
112    /// - `create_info` must match the info used to create the object.
113    /// - If the buffer has memory bound to it, `bind_memory` must not be called on the returned
114    ///   `RawBuffer`.
115    #[inline]
116    pub unsafe fn from_handle(
117        device: Arc<Device>,
118        handle: ash::vk::Buffer,
119        create_info: BufferCreateInfo,
120    ) -> Self {
121        unsafe { Self::from_handle_with_destruction(device, handle, create_info, true) }
122    }
123
124    /// Creates a new `RawBuffer` from a raw object handle. Unlike `from_handle`, the created
125    /// `RawBuffer` does not destroy the inner buffer when dropped.
126    ///
127    /// # Safety
128    ///
129    /// - `handle` must be a valid Vulkan object handle created from `device`.
130    /// - `create_info` must match the info used to create the object.
131    /// - If the buffer has memory bound to it, `bind_memory` must not be called on the returned
132    ///   `RawBuffer`.
133    /// - Caller must ensure that the handle will not be destroyed for the lifetime of returned
134    ///   `RawBuffer`.
135    #[inline]
136    pub unsafe fn from_handle_borrowed(
137        device: Arc<Device>,
138        handle: ash::vk::Buffer,
139        create_info: BufferCreateInfo,
140    ) -> Self {
141        unsafe { Self::from_handle_with_destruction(device, handle, create_info, false) }
142    }
143
144    unsafe fn from_handle_with_destruction(
145        device: Arc<Device>,
146        handle: ash::vk::Buffer,
147        create_info: BufferCreateInfo,
148        needs_destruction: bool,
149    ) -> Self {
150        let BufferCreateInfo {
151            flags,
152            size,
153            usage,
154            sharing,
155            external_memory_handle_types,
156            _ne: _,
157        } = create_info;
158
159        let mut memory_requirements = Self::get_memory_requirements(&device, handle);
160
161        debug_assert!(memory_requirements.layout.size() >= size);
162        debug_assert!(memory_requirements.memory_type_bits != 0);
163
164        // We have to manually enforce some additional requirements for some buffer types.
165        let properties = device.physical_device().properties();
166        if usage.intersects(BufferUsage::UNIFORM_TEXEL_BUFFER | BufferUsage::STORAGE_TEXEL_BUFFER) {
167            memory_requirements.layout = memory_requirements
168                .layout
169                .align_to(properties.min_texel_buffer_offset_alignment)
170                .unwrap();
171        }
172
173        if usage.intersects(BufferUsage::STORAGE_BUFFER) {
174            memory_requirements.layout = memory_requirements
175                .layout
176                .align_to(properties.min_storage_buffer_offset_alignment)
177                .unwrap();
178        }
179
180        if usage.intersects(BufferUsage::UNIFORM_BUFFER) {
181            memory_requirements.layout = memory_requirements
182                .layout
183                .align_to(properties.min_uniform_buffer_offset_alignment)
184                .unwrap();
185        }
186
187        RawBuffer {
188            handle,
189            device: InstanceOwnedDebugWrapper(device),
190            id: Self::next_id(),
191            flags,
192            size,
193            usage,
194            sharing,
195            external_memory_handle_types,
196            memory_requirements,
197            needs_destruction,
198        }
199    }
200
201    fn get_memory_requirements(device: &Device, handle: ash::vk::Buffer) -> MemoryRequirements {
202        let info_vk = ash::vk::BufferMemoryRequirementsInfo2::default().buffer(handle);
203
204        let mut memory_requirements2_extensions_vk =
205            MemoryRequirements::to_mut_vk2_extensions(device);
206        let mut memory_requirements2_vk =
207            MemoryRequirements::to_mut_vk2(&mut memory_requirements2_extensions_vk);
208
209        let fns = device.fns();
210
211        if device.api_version() >= Version::V1_1
212            || device.enabled_extensions().khr_get_memory_requirements2
213        {
214            if device.api_version() >= Version::V1_1 {
215                unsafe {
216                    (fns.v1_1.get_buffer_memory_requirements2)(
217                        device.handle(),
218                        &info_vk,
219                        &mut memory_requirements2_vk,
220                    )
221                };
222            } else {
223                unsafe {
224                    (fns.khr_get_memory_requirements2
225                        .get_buffer_memory_requirements2_khr)(
226                        device.handle(),
227                        &info_vk,
228                        &mut memory_requirements2_vk,
229                    )
230                };
231            }
232        } else {
233            unsafe {
234                (fns.v1_0.get_buffer_memory_requirements)(
235                    device.handle(),
236                    handle,
237                    &mut memory_requirements2_vk.memory_requirements,
238                )
239            };
240        }
241
242        // Unborrow
243        let memory_requirements2_vk = ash::vk::MemoryRequirements2 {
244            _marker: PhantomData,
245            ..memory_requirements2_vk
246        };
247
248        MemoryRequirements::from_vk2(
249            &memory_requirements2_vk,
250            &memory_requirements2_extensions_vk,
251        )
252    }
253
254    /// Binds device memory to this buffer.
255    #[inline]
256    pub fn bind_memory(
257        self,
258        allocation: ResourceMemory,
259    ) -> Result<Buffer, (Validated<VulkanError>, RawBuffer, ResourceMemory)> {
260        if let Err(err) = self.validate_bind_memory(&allocation) {
261            return Err((err.into(), self, allocation));
262        }
263
264        unsafe { self.bind_memory_unchecked(allocation) }
265            .map_err(|(err, buffer, allocation)| (err.into(), buffer, allocation))
266    }
267
268    fn validate_bind_memory(
269        &self,
270        allocation: &ResourceMemory,
271    ) -> Result<(), Box<ValidationError>> {
272        if self.flags().intersects(BufferCreateFlags::SPARSE_BINDING) {
273            return Err(Box::new(ValidationError {
274                context: "self.flags()".into(),
275                problem: "contains `BufferCreateFlags::SPARSE_BINDING`".into(),
276                vuids: &["VUID-VkBindBufferMemoryInfo-buffer-01030"],
277                ..Default::default()
278            }));
279        }
280
281        assert_ne!(allocation.allocation_type(), AllocationType::NonLinear);
282
283        let physical_device = self.device().physical_device();
284
285        let memory_requirements = &self.memory_requirements;
286        let memory = allocation.device_memory();
287        let memory_offset = allocation.offset();
288        let memory_type =
289            &physical_device.memory_properties().memory_types[memory.memory_type_index() as usize];
290
291        // VUID-VkBindBufferMemoryInfo-commonparent
292        assert_eq!(self.device(), memory.device());
293
294        // VUID-VkBindBufferMemoryInfo-buffer-07459
295        // Ensured by taking ownership of `RawBuffer`.
296
297        // VUID-VkBindBufferMemoryInfo-memoryOffset-01031
298        // Assume that `allocation` was created correctly.
299
300        if memory_requirements.memory_type_bits & (1 << memory.memory_type_index()) == 0 {
301            return Err(Box::new(ValidationError {
302                problem: "`allocation.device_memory().memory_type_index()` is not a bit set in \
303                    `self.memory_requirements().memory_type_bits`"
304                    .into(),
305                vuids: &["VUID-VkBindBufferMemoryInfo-memory-01035"],
306                ..Default::default()
307            }));
308        }
309
310        if !is_aligned(memory_offset, memory_requirements.layout.alignment()) {
311            return Err(Box::new(ValidationError {
312                problem: "`allocation.offset()` is not aligned according to \
313                    `self.memory_requirements().layout.alignment()`"
314                    .into(),
315                vuids: &["VUID-VkBindBufferMemoryInfo-memoryOffset-01036"],
316                ..Default::default()
317            }));
318        }
319
320        if allocation.size() < memory_requirements.layout.size() {
321            return Err(Box::new(ValidationError {
322                problem: "`allocation.size()` is less than \
323                    `self.memory_requirements().layout.size()`"
324                    .into(),
325                vuids: &["VUID-VkBindBufferMemoryInfo-size-01037"],
326                ..Default::default()
327            }));
328        }
329
330        if let Some(dedicated_to) = memory.dedicated_to() {
331            match dedicated_to {
332                DedicatedTo::Buffer(id) if id == self.id => {}
333                _ => {
334                    return Err(Box::new(ValidationError {
335                        problem: "`allocation.device_memory()` is a dedicated allocation, but \
336                            it is not dedicated to this buffer"
337                            .into(),
338                        vuids: &["VUID-VkBindBufferMemoryInfo-memory-01508"],
339                        ..Default::default()
340                    }));
341                }
342            }
343            debug_assert!(memory_offset == 0); // This should be ensured by the allocator
344        } else {
345            if memory_requirements.requires_dedicated_allocation {
346                return Err(Box::new(ValidationError {
347                    problem: "`self.memory_requirements().requires_dedicated_allocation` is \
348                        `true`, but `allocation.device_memory()` is not a dedicated allocation"
349                        .into(),
350                    vuids: &["VUID-VkBindBufferMemoryInfo-buffer-01444"],
351                    ..Default::default()
352                }));
353            }
354        }
355
356        if memory_type
357            .property_flags
358            .intersects(MemoryPropertyFlags::PROTECTED)
359        {
360            return Err(Box::new(ValidationError {
361                problem: "the `property_flags` of the memory type of \
362                    `allocation.device_memory()` contains `MemoryPropertyFlags::PROTECTED`"
363                    .into(),
364                vuids: &["VUID-VkBindBufferMemoryInfo-None-01899"],
365                ..Default::default()
366            }));
367        }
368
369        if !memory.export_handle_types().is_empty() {
370            if !self
371                .external_memory_handle_types
372                .intersects(memory.export_handle_types())
373            {
374                return Err(Box::new(ValidationError {
375                    problem:
376                        "`allocation.device_memory().export_handle_types()` is not empty, but \
377                        it does not share at least one handle type with \
378                        `self.external_memory_handle_types()`"
379                            .into(),
380                    vuids: &["VUID-VkBindBufferMemoryInfo-memory-02726"],
381                    ..Default::default()
382                }));
383            }
384
385            for handle_type in memory.export_handle_types() {
386                let external_buffer_properties = unsafe {
387                    physical_device.external_buffer_properties_unchecked(ExternalBufferInfo {
388                        flags: self.flags,
389                        usage: self.usage,
390                        handle_type,
391                        _ne: crate::NonExhaustive(()),
392                    })
393                };
394
395                if external_buffer_properties
396                    .external_memory_properties
397                    .dedicated_only
398                    && !memory.is_dedicated()
399                {
400                    return Err(Box::new(ValidationError {
401                        problem: format!(
402                            "`allocation.device_memory().export_handle_types()` has the `{:?}` \
403                            flag set, which requires a dedicated allocation as returned by \
404                            `PhysicalDevice::external_buffer_properties`, but \
405                            `allocation.device_memory()` is not a dedicated allocation",
406                            handle_type,
407                        )
408                        .into(),
409                        vuids: &["VUID-VkMemoryAllocateInfo-pNext-00639"],
410                        ..Default::default()
411                    }));
412                }
413
414                if !external_buffer_properties
415                    .external_memory_properties
416                    .exportable
417                {
418                    return Err(Box::new(ValidationError {
419                        problem: format!(
420                            "`allocation.device_memory().export_handle_types()` has the `{:?}` \
421                            flag set, but the flag is not supported for exporting, as returned by \
422                            `PhysicalDevice::external_buffer_properties`",
423                            handle_type,
424                        )
425                        .into(),
426                        vuids: &["VUID-VkExportMemoryAllocateInfo-handleTypes-00656"],
427                        ..Default::default()
428                    }));
429                }
430
431                if !external_buffer_properties
432                    .external_memory_properties
433                    .compatible_handle_types
434                    .contains(memory.export_handle_types())
435                {
436                    return Err(Box::new(ValidationError {
437                        problem: format!(
438                            "`allocation.device_memory().export_handle_types()` has the `{:?}` \
439                            flag set, but the flag is not compatible with the other flags set, as \
440                            returned by `PhysicalDevice::external_buffer_properties`",
441                            handle_type,
442                        )
443                        .into(),
444                        vuids: &["VUID-VkExportMemoryAllocateInfo-handleTypes-00656"],
445                        ..Default::default()
446                    }));
447                }
448            }
449        }
450
451        if let Some(handle_type) = memory.imported_handle_type() {
452            if !self.external_memory_handle_types.contains_enum(handle_type) {
453                return Err(Box::new(ValidationError {
454                    problem: "`allocation.device_memory()` is imported, but \
455                        `self.external_memory_handle_types()` does not contain the imported \
456                        handle type"
457                        .into(),
458                    vuids: &["VUID-VkBindBufferMemoryInfo-memory-02985"],
459                    ..Default::default()
460                }));
461            }
462        }
463
464        if !self.device.enabled_extensions().ext_buffer_device_address
465            && self.usage.intersects(BufferUsage::SHADER_DEVICE_ADDRESS)
466            && !memory
467                .flags()
468                .intersects(MemoryAllocateFlags::DEVICE_ADDRESS)
469        {
470            return Err(Box::new(ValidationError {
471                problem: "`self.usage()` contains `BufferUsage::SHADER_DEVICE_ADDRESS`, but \
472                    `allocation.device_memory().flags()` does not contain \
473                    `MemoryAllocateFlags::DEVICE_ADDRESS`"
474                    .into(),
475                vuids: &["VUID-VkBindBufferMemoryInfo-bufferDeviceAddress-03339"],
476                ..Default::default()
477            }));
478        }
479
480        Ok(())
481    }
482
483    #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
484    pub unsafe fn bind_memory_unchecked(
485        self,
486        allocation: ResourceMemory,
487    ) -> Result<Buffer, (VulkanError, RawBuffer, ResourceMemory)> {
488        let bind_info_vk = allocation.to_vk_bind_buffer_memory_info(self.handle());
489
490        let fns = self.device.fns();
491
492        let result = if self.device.api_version() >= Version::V1_1
493            || self.device.enabled_extensions().khr_bind_memory2
494        {
495            let bind_infos_vk = [bind_info_vk];
496
497            if self.device.api_version() >= Version::V1_1 {
498                unsafe {
499                    (fns.v1_1.bind_buffer_memory2)(
500                        self.device.handle(),
501                        bind_infos_vk.len() as u32,
502                        bind_infos_vk.as_ptr(),
503                    )
504                }
505            } else {
506                unsafe {
507                    (fns.khr_bind_memory2.bind_buffer_memory2_khr)(
508                        self.device.handle(),
509                        bind_infos_vk.len() as u32,
510                        bind_infos_vk.as_ptr(),
511                    )
512                }
513            }
514        } else {
515            unsafe {
516                (fns.v1_0.bind_buffer_memory)(
517                    self.device.handle(),
518                    bind_info_vk.buffer,
519                    bind_info_vk.memory,
520                    bind_info_vk.memory_offset,
521                )
522            }
523        }
524        .result();
525
526        if let Err(err) = result {
527            return Err((VulkanError::from(err), self, allocation));
528        }
529
530        Ok(Buffer::from_raw(self, BufferMemory::Normal(allocation)))
531    }
532
533    /// Converts a raw buffer into a full buffer without binding any memory.
534    ///
535    /// # Safety
536    ///
537    /// If `self.flags()` does not contain [`BufferCreateFlags::SPARSE_BINDING`]:
538    ///
539    /// - The buffer must already have a suitable memory allocation bound to it.
540    ///
541    /// If `self.flags()` does contain [`BufferCreateFlags::SPARSE_BINDING`]:
542    ///
543    /// - If `self.flags()` does not contain [`BufferCreateFlags::SPARSE_RESIDENCY`], then the
544    ///   buffer must be fully bound with memory before its memory is accessed by the device.
545    /// - If `self.flags()` contains [`BufferCreateFlags::SPARSE_RESIDENCY`], then you must ensure
546    ///   that any reads from the buffer are prepared to handle unexpected or inconsistent values,
547    ///   as determined by the [`residency_non_resident_strict`] device property.
548    ///
549    /// [`residency_non_resident_strict`]: crate::device::DeviceProperties::residency_non_resident_strict
550    pub unsafe fn assume_bound(self) -> Buffer {
551        let memory = if self.flags().intersects(BufferCreateFlags::SPARSE_BINDING) {
552            BufferMemory::Sparse
553        } else {
554            BufferMemory::External
555        };
556
557        Buffer::from_raw(self, memory)
558    }
559
560    /// Returns the memory requirements for this buffer.
561    pub fn memory_requirements(&self) -> &MemoryRequirements {
562        &self.memory_requirements
563    }
564
565    /// Returns the flags the buffer was created with.
566    #[inline]
567    pub fn flags(&self) -> BufferCreateFlags {
568        self.flags
569    }
570
571    /// Returns the size of the buffer in bytes.
572    #[inline]
573    pub fn size(&self) -> DeviceSize {
574        self.size
575    }
576
577    /// Returns the usage the buffer was created with.
578    #[inline]
579    pub fn usage(&self) -> BufferUsage {
580        self.usage
581    }
582
583    /// Returns the sharing the buffer was created with.
584    #[inline]
585    pub fn sharing(&self) -> &Sharing<SmallVec<[u32; 4]>> {
586        &self.sharing
587    }
588
589    /// Returns the external memory handle types that are supported with this buffer.
590    #[inline]
591    pub fn external_memory_handle_types(&self) -> ExternalMemoryHandleTypes {
592        self.external_memory_handle_types
593    }
594}
595
596impl Drop for RawBuffer {
597    #[inline]
598    fn drop(&mut self) {
599        if self.needs_destruction {
600            let fns = self.device.fns();
601            unsafe { (fns.v1_0.destroy_buffer)(self.device.handle(), self.handle, ptr::null()) };
602        }
603    }
604}
605
606unsafe impl VulkanObject for RawBuffer {
607    type Handle = ash::vk::Buffer;
608
609    #[inline]
610    fn handle(&self) -> Self::Handle {
611        self.handle
612    }
613}
614
615unsafe impl DeviceOwned for RawBuffer {
616    #[inline]
617    fn device(&self) -> &Arc<Device> {
618        &self.device
619    }
620}
621
622impl_id_counter!(RawBuffer);
623
624/// Parameters to create a new [`Buffer`].
625#[derive(Clone, Debug)]
626pub struct BufferCreateInfo {
627    /// Additional properties of the buffer.
628    ///
629    /// The default value is empty.
630    pub flags: BufferCreateFlags,
631
632    /// Whether the buffer can be shared across multiple queues, or is limited to a single queue.
633    ///
634    /// The default value is [`Sharing::Exclusive`].
635    pub sharing: Sharing<SmallVec<[u32; 4]>>,
636
637    /// The size in bytes of the buffer.
638    ///
639    /// When using the [`Buffer`] constructors, you must leave this at `0`. They fill this field
640    /// based on the data type of the contents and the other parameters you provide, and then pass
641    /// this create-info to [`RawBuffer::new`]. You must override the default when constructing
642    /// [`RawBuffer`] directly.
643    ///
644    /// The default value is `0`.
645    pub size: DeviceSize,
646
647    /// How the buffer is going to be used.
648    ///
649    /// The default value is [`BufferUsage::empty()`], which must be overridden.
650    pub usage: BufferUsage,
651
652    /// The external memory handle types that are going to be used with the buffer.
653    ///
654    /// If this value is not empty, then the device API version must be at least 1.1, or the
655    /// [`khr_external_memory`] extension must be enabled on the device.
656    ///
657    /// The default value is [`ExternalMemoryHandleTypes::empty()`].
658    ///
659    /// [`khr_external_memory`]: crate::device::DeviceExtensions::khr_external_memory
660    pub external_memory_handle_types: ExternalMemoryHandleTypes,
661
662    pub _ne: crate::NonExhaustive,
663}
664
665impl Default for BufferCreateInfo {
666    #[inline]
667    fn default() -> Self {
668        Self {
669            flags: BufferCreateFlags::empty(),
670            sharing: Sharing::Exclusive,
671            size: 0,
672            usage: BufferUsage::empty(),
673            external_memory_handle_types: ExternalMemoryHandleTypes::empty(),
674            _ne: crate::NonExhaustive(()),
675        }
676    }
677}
678
679impl BufferCreateInfo {
680    pub(crate) fn validate(&self, device: &Device) -> Result<(), Box<ValidationError>> {
681        let &Self {
682            flags,
683            ref sharing,
684            size,
685            usage,
686            external_memory_handle_types,
687            _ne: _,
688        } = self;
689
690        flags.validate_device(device).map_err(|err| {
691            err.add_context("flags")
692                .set_vuids(&["VUID-VkBufferCreateInfo-flags-parameter"])
693        })?;
694
695        usage.validate_device(device).map_err(|err| {
696            err.add_context("usage")
697                .set_vuids(&["VUID-VkBufferCreateInfo-usage-parameter"])
698        })?;
699
700        if usage.is_empty() {
701            return Err(Box::new(ValidationError {
702                context: "usage".into(),
703                problem: "is empty".into(),
704                vuids: &["VUID-VkBufferCreateInfo-usage-requiredbitmask"],
705                ..Default::default()
706            }));
707        }
708
709        if size == 0 {
710            return Err(Box::new(ValidationError {
711                context: "size".into(),
712                problem: "is zero".into(),
713                vuids: &["VUID-VkBufferCreateInfo-size-00912"],
714                ..Default::default()
715            }));
716        }
717
718        match sharing {
719            Sharing::Exclusive => (),
720            Sharing::Concurrent(queue_family_indices) => {
721                if queue_family_indices.len() < 2 {
722                    return Err(Box::new(ValidationError {
723                        context: "sharing".into(),
724                        problem: "is `Sharing::Concurrent`, but contains less than 2 elements"
725                            .into(),
726                        vuids: &["VUID-VkBufferCreateInfo-sharingMode-00914"],
727                        ..Default::default()
728                    }));
729                }
730
731                let queue_family_count =
732                    device.physical_device().queue_family_properties().len() as u32;
733
734                for (index, &queue_family_index) in queue_family_indices.iter().enumerate() {
735                    if queue_family_indices[..index].contains(&queue_family_index) {
736                        return Err(Box::new(ValidationError {
737                            context: "queue_family_indices".into(),
738                            problem: format!(
739                                "the queue family index in the list at index {} is contained in \
740                                the list more than once",
741                                index,
742                            )
743                            .into(),
744                            vuids: &["VUID-VkBufferCreateInfo-sharingMode-01419"],
745                            ..Default::default()
746                        }));
747                    }
748
749                    if queue_family_index >= queue_family_count {
750                        return Err(Box::new(ValidationError {
751                            context: format!("sharing[{}]", index).into(),
752                            problem: "is not less than the number of queue families in the device"
753                                .into(),
754                            vuids: &["VUID-VkBufferCreateInfo-sharingMode-01419"],
755                            ..Default::default()
756                        }));
757                    }
758                }
759            }
760        }
761
762        if flags.intersects(BufferCreateFlags::SPARSE_BINDING) {
763            if !device.enabled_features().sparse_binding {
764                return Err(Box::new(ValidationError {
765                    context: "flags".into(),
766                    problem: "contains `BufferCreateFlags::SPARSE_BINDING`".into(),
767                    requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::DeviceFeature(
768                        "sparse_binding",
769                    )])]),
770                    vuids: &["VUID-VkBufferCreateInfo-flags-00915"],
771                }));
772            }
773        }
774
775        if flags.intersects(BufferCreateFlags::SPARSE_RESIDENCY) {
776            if !flags.intersects(BufferCreateFlags::SPARSE_BINDING) {
777                return Err(Box::new(ValidationError {
778                    context: "flags".into(),
779                    problem: "contains `BufferCreateFlags::SPARSE_RESIDENCY`, but does not also \
780                        contain `BufferCreateFlags::SPARSE_BINDING`"
781                        .into(),
782                    vuids: &["VUID-VkBufferCreateInfo-flags-00918"],
783                    ..Default::default()
784                }));
785            }
786
787            if !device.enabled_features().sparse_residency_buffer {
788                return Err(Box::new(ValidationError {
789                    context: "flags".into(),
790                    problem: "contains `BufferCreateFlags::SPARSE_RESIDENCY`".into(),
791                    requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::DeviceFeature(
792                        "sparse_residency_buffer",
793                    )])]),
794                    vuids: &["VUID-VkBufferCreateInfo-flags-00916"],
795                }));
796            }
797        }
798
799        if let Some(max_buffer_size) = device.physical_device().properties().max_buffer_size {
800            if size > max_buffer_size {
801                return Err(Box::new(ValidationError {
802                    context: "size".into(),
803                    problem: "exceeds the `max_buffer_size` limit".into(),
804                    vuids: &["VUID-VkBufferCreateInfo-size-06409"],
805                    ..Default::default()
806                }));
807            }
808        }
809
810        if !external_memory_handle_types.is_empty() {
811            if !(device.api_version() >= Version::V1_1
812                || device.enabled_extensions().khr_external_memory)
813            {
814                return Err(Box::new(ValidationError {
815                    context: "external_memory_handle_types".into(),
816                    problem: "is not empty".into(),
817                    requires_one_of: RequiresOneOf(&[
818                        RequiresAllOf(&[Requires::APIVersion(Version::V1_1)]),
819                        RequiresAllOf(&[Requires::DeviceExtension("khr_external_memory")]),
820                    ]),
821                    ..Default::default()
822                }));
823            }
824
825            external_memory_handle_types
826                .validate_device(device)
827                .map_err(|err| {
828                    err.add_context("external_memory_handle_types")
829                        .set_vuids(&["VUID-VkExternalMemoryBufferCreateInfo-handleTypes-parameter"])
830                })?;
831
832            // TODO:
833            // VUID-VkBufferCreateInfo-pNext-00920
834        }
835
836        Ok(())
837    }
838
839    pub(crate) fn to_vk<'a>(
840        &'a self,
841        extensions_vk: &'a mut BufferCreateInfoExtensionsVk,
842    ) -> ash::vk::BufferCreateInfo<'a> {
843        let &Self {
844            flags,
845            ref sharing,
846            size,
847            usage,
848            external_memory_handle_types: _,
849            _ne: _,
850        } = self;
851
852        let (sharing_mode_vk, queue_family_indices) = sharing.to_vk();
853
854        let mut val_vk = ash::vk::BufferCreateInfo::default()
855            .flags(flags.into())
856            .size(size)
857            .usage(usage.into())
858            .sharing_mode(sharing_mode_vk)
859            .queue_family_indices(queue_family_indices);
860
861        let BufferCreateInfoExtensionsVk { external_memory_vk } = extensions_vk;
862
863        if let Some(next) = external_memory_vk {
864            val_vk = val_vk.push_next(next);
865        }
866
867        val_vk
868    }
869
870    pub(crate) fn to_vk_extensions(&self) -> BufferCreateInfoExtensionsVk {
871        let &Self {
872            external_memory_handle_types,
873            ..
874        } = self;
875
876        let external_memory_vk = (!external_memory_handle_types.is_empty()).then(|| {
877            ash::vk::ExternalMemoryBufferCreateInfo::default()
878                .handle_types(external_memory_handle_types.into())
879        });
880
881        BufferCreateInfoExtensionsVk { external_memory_vk }
882    }
883}
884
885pub(crate) struct BufferCreateInfoExtensionsVk {
886    pub(crate) external_memory_vk: Option<ash::vk::ExternalMemoryBufferCreateInfo<'static>>,
887}
888
889#[cfg(test)]
890mod tests {
891    use super::{BufferCreateInfo, BufferUsage, RawBuffer};
892    use crate::device::DeviceOwned;
893
894    #[test]
895    fn create() {
896        let (device, _) = gfx_dev_and_queue!();
897        let buf = RawBuffer::new(
898            device.clone(),
899            BufferCreateInfo {
900                size: 128,
901                usage: BufferUsage::TRANSFER_DST,
902                ..Default::default()
903            },
904        )
905        .unwrap();
906        let reqs = buf.memory_requirements();
907
908        assert!(reqs.layout.size() >= 128);
909        assert_eq!(buf.size(), 128);
910        assert_eq!(buf.device(), &device);
911    }
912
913    /* Re-enable when sparse binding is properly implemented
914    #[test]
915    fn missing_feature_sparse_binding() {
916        let (device, _) = gfx_dev_and_queue!();
917        match RawBuffer::new(
918            device,
919            BufferCreateInfo {
920                size: 128,
921                sparse: Some(BufferCreateFlags::empty()),
922                usage: BufferUsage::transfer_dst,
923                ..Default::default()
924            },
925        ) {
926            Err(BufferError::RequirementNotMet {
927                requires_one_of: RequiresOneOf { features, .. },
928                ..
929            }) if features.contains(&"sparse_binding") => (),
930            _ => panic!(),
931        }
932    }
933
934    #[test]
935    fn missing_feature_sparse_residency() {
936        let (device, _) = gfx_dev_and_queue!(sparse_binding);
937        match RawBuffer::new(
938            device,
939            BufferCreateInfo {
940                size: 128,
941                sparse: Some(BufferCreateFlags {
942                    sparse_residency: true,
943                    sparse_aliased: false,
944                    ..Default::default()
945                }),
946                usage: BufferUsage::transfer_dst,
947                ..Default::default()
948            },
949        ) {
950            Err(BufferError::RequirementNotMet {
951                requires_one_of: RequiresOneOf { features, .. },
952                ..
953            }) if features.contains(&"sparse_residency_buffer") => (),
954            _ => panic!(),
955        }
956    }
957
958    #[test]
959    fn missing_feature_sparse_aliased() {
960        let (device, _) = gfx_dev_and_queue!(sparse_binding);
961        match RawBuffer::new(
962            device,
963            BufferCreateInfo {
964                size: 128,
965                sparse: Some(BufferCreateFlags {
966                    sparse_residency: false,
967                    sparse_aliased: true,
968                    ..Default::default()
969                }),
970                usage: BufferUsage::transfer_dst,
971                ..Default::default()
972            },
973        ) {
974            Err(BufferError::RequirementNotMet {
975                requires_one_of: RequiresOneOf { features, .. },
976                ..
977            }) if features.contains(&"sparse_residency_aliased") => (),
978            _ => panic!(),
979        }
980    }
981    */
982
983    #[test]
984    fn create_empty_buffer() {
985        let (device, _) = gfx_dev_and_queue!();
986
987        if RawBuffer::new(
988            device,
989            BufferCreateInfo {
990                size: 0,
991                usage: BufferUsage::TRANSFER_DST,
992                ..Default::default()
993            },
994        )
995        .is_ok()
996        {
997            panic!()
998        }
999    }
1000}