diff --git a/vulkano/src/buffer/cpu_access.rs b/vulkano/src/buffer/cpu_access.rs index 1caaeb5eaf..8201638394 100644 --- a/vulkano/src/buffer/cpu_access.rs +++ b/vulkano/src/buffer/cpu_access.rs @@ -77,6 +77,8 @@ where /// # Panics /// /// - Panics if `T` has zero size. + /// - Panics if `usage.shader_device_address` is `true`. + // TODO: ^ pub fn from_data( device: Arc, usage: BufferUsage, @@ -130,6 +132,8 @@ where /// /// - Panics if `T` has zero size. /// - Panics if `data` is empty. + /// - Panics if `usage.shader_device_address` is `true`. + // TODO: ^ pub fn from_iter( device: Arc, usage: BufferUsage, @@ -172,6 +176,8 @@ where /// /// - Panics if `T` has zero size. /// - Panics if `len` is zero. + /// - Panics if `usage.shader_device_address` is `true`. + // TODO: ^ pub unsafe fn uninitialized_array( device: Arc, len: DeviceSize, @@ -201,6 +207,8 @@ where /// # Panics /// /// - Panics if `size` is zero. + /// - Panics if `usage.shader_device_address` is `true`. + // TODO: ^ pub unsafe fn raw( device: Arc, size: DeviceSize, diff --git a/vulkano/src/buffer/cpu_pool.rs b/vulkano/src/buffer/cpu_pool.rs index 9245433eb3..ea4f36e557 100644 --- a/vulkano/src/buffer/cpu_pool.rs +++ b/vulkano/src/buffer/cpu_pool.rs @@ -197,9 +197,12 @@ where /// # Panics /// /// - Panics if `T` has zero size. + /// - Panics if `usage.shader_device_address` is `true`. + // TODO: ^ #[inline] pub fn new(device: Arc, usage: BufferUsage) -> CpuBufferPool { assert!(size_of::() > 0); + assert!(!usage.shader_device_address); let pool = device.standard_memory_pool(); CpuBufferPool { diff --git a/vulkano/src/buffer/device_local.rs b/vulkano/src/buffer/device_local.rs index d63803db5a..db690af6ca 100644 --- a/vulkano/src/buffer/device_local.rs +++ b/vulkano/src/buffer/device_local.rs @@ -181,6 +181,11 @@ where /// the initial upload operation. In order to be allowed to use the `DeviceLocalBuffer`, you /// must either submit your operation after this future, or execute this future and wait for it /// to be finished before submitting your own operation. + /// + /// # Panics + /// + /// - Panics if `usage.shader_device_address` is `true`. + // TODO: ^ pub fn from_buffer( source: Arc, usage: BufferUsage, @@ -235,6 +240,8 @@ where /// # Panics /// /// - Panics if `T` has zero size. + /// - Panics if `usage.shader_device_address` is `true`. + // TODO: ^ pub fn from_data( data: T, usage: BufferUsage, @@ -264,6 +271,8 @@ where /// /// - Panics if `T` has zero size. /// - Panics if `data` is empty. + /// - Panics if `usage.shader_device_address` is `true`. + // TODO: ^ pub fn from_iter( data: D, usage: BufferUsage, @@ -297,6 +306,8 @@ where /// /// - Panics if `T` has zero size. /// - Panics if `len` is zero. + /// - Panics if `usage.shader_device_address` is `true`. + // TODO: ^ pub fn array( device: Arc, len: DeviceSize, @@ -327,6 +338,8 @@ where /// # Panics /// /// - Panics if `size` is zero. + /// - Panics if `usage.shader_device_address` is `true`. + // TODO: ^ pub unsafe fn raw( device: Arc, size: DeviceSize, @@ -367,6 +380,8 @@ where /// # Panics /// /// - Panics if `size` is zero. + /// - Panics if `usage.shader_device_address` is `true`. + // TODO: ^ pub unsafe fn raw_with_exportable_fd( device: Arc, size: DeviceSize, diff --git a/vulkano/src/buffer/sys.rs b/vulkano/src/buffer/sys.rs index 837127a119..ed74926d15 100644 --- a/vulkano/src/buffer/sys.rs +++ b/vulkano/src/buffer/sys.rs @@ -399,6 +399,15 @@ impl UnsafeBuffer { } /// Binds device memory to this buffer. + /// + /// # Panics + /// + /// - Panics if `self.usage.shader_device_address` is `true` and the `memory` was not allocated + /// with the [`device_address`] flag set and the [`ext_buffer_device_address`] extension is + /// not enabled on the device. + /// + /// [`device_address`]: crate::memory::MemoryAllocateFlags::device_address + /// [`ext_buffer_device_address`]: crate::device::DeviceExtensions::ext_buffer_device_address pub unsafe fn bind_memory( &self, memory: &DeviceMemory, @@ -435,6 +444,13 @@ impl UnsafeBuffer { } } + // VUID-vkBindBufferMemory-bufferDeviceAddress-03339 + if self.usage.shader_device_address + && !self.device.enabled_extensions().ext_buffer_device_address + { + assert!(memory.flags().device_address); + } + (fns.v1_0.bind_buffer_memory)( self.device.internal_object(), self.handle, diff --git a/vulkano/src/buffer/traits.rs b/vulkano/src/buffer/traits.rs index 2cc915d5c4..cd39b11feb 100644 --- a/vulkano/src/buffer/traits.rs +++ b/vulkano/src/buffer/traits.rs @@ -8,7 +8,7 @@ // according to those terms. use super::{sys::UnsafeBuffer, BufferContents, BufferSlice, BufferUsage}; -use crate::{device::DeviceOwned, DeviceSize, RequiresOneOf, SafeDeref, VulkanObject}; +use crate::{device::DeviceOwned, DeviceSize, RequiresOneOf, SafeDeref, Version, VulkanObject}; use std::{ error::Error, fmt::{Debug, Display, Error as FmtError, Formatter}, @@ -100,13 +100,17 @@ pub unsafe trait BufferAccess: DeviceOwned + Send + Sync { ..Default::default() }; let fns = device.fns(); - let ptr = (fns.ext_buffer_device_address.get_buffer_device_address_ext)( - device.internal_object(), - &info, - ); + let f = if device.api_version() >= Version::V1_2 { + fns.v1_2.get_buffer_device_address + } else if device.enabled_extensions().khr_buffer_device_address { + fns.khr_buffer_device_address.get_buffer_device_address_khr + } else { + fns.ext_buffer_device_address.get_buffer_device_address_ext + }; + let ptr = f(device.internal_object(), &info); if ptr == 0 { - panic!("got null ptr from a valid GetBufferDeviceAddressEXT call"); + panic!("got null ptr from a valid GetBufferDeviceAddress call"); } Ok(NonZeroU64::new_unchecked(ptr + inner.offset)) diff --git a/vulkano/src/buffer/usage.rs b/vulkano/src/buffer/usage.rs index 9ffbba0dc6..8ac9793d19 100644 --- a/vulkano/src/buffer/usage.rs +++ b/vulkano/src/buffer/usage.rs @@ -44,6 +44,13 @@ vulkan_bitflags! { indirect_buffer = INDIRECT_BUFFER, /// The buffer's device address can be retrieved. + /// + /// A buffer created with this usage can only be bound to device memory allocated with the + /// [`device_address`] flag set unless the [`ext_buffer_device_address`] extension is enabled + /// on the device. + /// + /// [`device_address`]: crate::memory::MemoryAllocateFlags::device_address + /// [`ext_buffer_device_address`]: crate::device::DeviceExtensions::ext_buffer_device_address shader_device_address = SHADER_DEVICE_ADDRESS { api_version: V1_2, device_extensions: [khr_buffer_device_address, ext_buffer_device_address], diff --git a/vulkano/src/memory/device_memory.rs b/vulkano/src/memory/device_memory.rs index 4145741229..65d0b9fc0a 100644 --- a/vulkano/src/memory/device_memory.rs +++ b/vulkano/src/memory/device_memory.rs @@ -55,6 +55,7 @@ pub struct DeviceMemory { allocation_size: DeviceSize, memory_type_index: u32, export_handle_types: ExternalMemoryHandleTypes, + flags: MemoryAllocateFlags, } impl DeviceMemory { @@ -80,16 +81,17 @@ impl DeviceMemory { memory_type_index, dedicated_allocation: _, export_handle_types, + flags, _ne: _, } = allocate_info; Ok(DeviceMemory { handle, device, - allocation_size, memory_type_index, export_handle_types, + flags, }) } @@ -99,6 +101,7 @@ impl DeviceMemory { /// /// - `handle` must be a valid Vulkan object handle created from `device`. /// - `allocate_info` must match the info used to create the object. + #[inline] pub unsafe fn from_handle( device: Arc, handle: ash::vk::DeviceMemory, @@ -109,16 +112,17 @@ impl DeviceMemory { memory_type_index, dedicated_allocation: _, export_handle_types, + flags, _ne: _, } = allocate_info; DeviceMemory { handle, device, - allocation_size, memory_type_index, export_handle_types, + flags, } } @@ -146,16 +150,17 @@ impl DeviceMemory { memory_type_index, dedicated_allocation: _, export_handle_types, + flags, _ne: _, } = allocate_info; Ok(DeviceMemory { handle, device, - allocation_size, memory_type_index, export_handle_types, + flags, }) } @@ -169,6 +174,7 @@ impl DeviceMemory { memory_type_index, ref mut dedicated_allocation, export_handle_types, + flags, _ne: _, } = allocate_info; @@ -379,6 +385,44 @@ impl DeviceMemory { } } + if !flags.is_empty() + && device.physical_device().api_version() < Version::V1_1 + && !device.enabled_extensions().khr_device_group + { + return Err(DeviceMemoryError::RequirementNotMet { + required_for: "`allocate_info.flags` is not empty", + requires_one_of: RequiresOneOf { + api_version: Some(Version::V1_1), + device_extensions: &["khr_device_group"], + ..Default::default() + }, + }); + } + + if flags.device_address { + // VUID-VkMemoryAllocateInfo-flags-03331 + if !device.enabled_features().buffer_device_address { + return Err(DeviceMemoryError::RequirementNotMet { + required_for: "`allocate_info.flags.device_address` is `true`", + requires_one_of: RequiresOneOf { + features: &["buffer_device_address"], + ..Default::default() + }, + }); + } + + if device.enabled_extensions().ext_buffer_device_address { + return Err(DeviceMemoryError::RequirementNotMet { + required_for: "`allocate_info.flags.device_address` is `true`", + requires_one_of: RequiresOneOf { + api_version: Some(Version::V1_2), + device_extensions: &["khr_buffer_device_address"], + ..Default::default() + }, + }); + } + } + Ok(()) } @@ -392,6 +436,7 @@ impl DeviceMemory { memory_type_index, dedicated_allocation, export_handle_types, + flags, _ne: _, } = allocate_info; @@ -466,6 +511,15 @@ impl DeviceMemory { allocate_info = allocate_info.push_next(info); } + let mut flags_info = ash::vk::MemoryAllocateFlagsInfo { + flags: flags.into(), + ..Default::default() + }; + + if !flags.is_empty() { + allocate_info = allocate_info.push_next(&mut flags_info); + } + let mut allocation_count = device.allocation_count().lock(); // VUID-vkAllocateMemory-maxMemoryAllocationCount-04101 @@ -516,6 +570,12 @@ impl DeviceMemory { self.export_handle_types } + /// Returns the flags the memory was allocated with. + #[inline] + pub fn flags(&self) -> MemoryAllocateFlags { + self.flags + } + /// Retrieves the amount of lazily-allocated memory that is currently commited to this /// memory object. /// @@ -692,6 +752,15 @@ pub struct MemoryAllocateInfo<'d> { /// The handle types that can be exported from the allocated memory. pub export_handle_types: ExternalMemoryHandleTypes, + /// Additional flags for the memory allocation. + /// + /// If not empty, the device API version must be at least 1.1, or the + /// [`khr_device_group`](crate::device::DeviceExtensions::khr_device_group) extension must be + /// enabled on the device. + /// + /// The default value is [`MemoryAllocateFlags::empty()`]. + pub flags: MemoryAllocateFlags, + pub _ne: crate::NonExhaustive, } @@ -703,6 +772,7 @@ impl Default for MemoryAllocateInfo<'static> { memory_type_index: u32::MAX, dedicated_allocation: None, export_handle_types: ExternalMemoryHandleTypes::empty(), + flags: MemoryAllocateFlags::empty(), _ne: crate::NonExhaustive(()), } } @@ -717,6 +787,7 @@ impl<'d> MemoryAllocateInfo<'d> { memory_type_index: u32::MAX, dedicated_allocation: Some(dedicated_allocation), export_handle_types: ExternalMemoryHandleTypes::empty(), + flags: MemoryAllocateFlags::empty(), _ne: crate::NonExhaustive(()), } } @@ -936,6 +1007,28 @@ impl ExternalMemoryHandleTypes { } } +vulkan_bitflags! { + /// A mask specifying flags for device memory allocation. + #[non_exhaustive] + MemoryAllocateFlags = MemoryAllocateFlags(u32); + + // TODO: implement + // device_mask = DEVICE_MASK, + + /// Specifies that the allocated device memory can be bound to a buffer created with the + /// [`shader_device_address`] usage. This requires that the [`buffer_device_address`] feature + /// is enabled on the device and the [`ext_buffer_device_address`] extension is not enabled on + /// the device. + /// + /// [`shader_device_address`]: crate::buffer::BufferUsage::shader_device_address + /// [`buffer_device_address`]: crate::device::Features::buffer_device_address + /// [`ext_buffer_device_address`]: crate::device::DeviceExtensions::ext_buffer_device_address + device_address = DEVICE_ADDRESS, + + // TODO: implement + // device_address_capture_replay = DEVICE_ADDRESS_CAPTURE_REPLAY, +} + /// Error type returned by functions related to `DeviceMemory`. #[derive(Clone, Debug, PartialEq, Eq)] pub enum DeviceMemoryError { diff --git a/vulkano/src/memory/mod.rs b/vulkano/src/memory/mod.rs index b3dfe47f85..69736ccab2 100644 --- a/vulkano/src/memory/mod.rs +++ b/vulkano/src/memory/mod.rs @@ -95,7 +95,8 @@ pub use self::{ device_memory::{ DeviceMemory, DeviceMemoryError, ExternalMemoryHandleType, ExternalMemoryHandleTypes, - MappedDeviceMemory, MemoryAllocateInfo, MemoryImportInfo, MemoryMapError, + MappedDeviceMemory, MemoryAllocateFlags, MemoryAllocateInfo, MemoryImportInfo, + MemoryMapError, }, pool::MemoryPool, };