Add configuration for custom memory_type_bits masks (#2311)

This commit is contained in:
marc0246 2023-08-26 17:12:54 +02:00 committed by GitHub
parent c74eedbdf4
commit e1daac6690
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -612,6 +612,12 @@ pub struct AllocationCreateInfo {
/// The default value is [`MemoryTypeFilter::PREFER_DEVICE`]. /// The default value is [`MemoryTypeFilter::PREFER_DEVICE`].
pub memory_type_filter: MemoryTypeFilter, pub memory_type_filter: MemoryTypeFilter,
/// Allows you to further constrain the possible choices of memory types, by only allowing the
/// memory type indices that have a corresponding bit at the same index set to 1.
///
/// The default value is [`u32::MAX`].
pub memory_type_bits: u32,
/// How eager the allocator should be to allocate [`DeviceMemory`]. /// How eager the allocator should be to allocate [`DeviceMemory`].
/// ///
/// The default value is [`MemoryAllocatePreference::Unknown`]. /// The default value is [`MemoryAllocatePreference::Unknown`].
@ -625,6 +631,7 @@ impl Default for AllocationCreateInfo {
fn default() -> Self { fn default() -> Self {
AllocationCreateInfo { AllocationCreateInfo {
memory_type_filter: MemoryTypeFilter::PREFER_DEVICE, memory_type_filter: MemoryTypeFilter::PREFER_DEVICE,
memory_type_bits: u32::MAX,
allocate_preference: MemoryAllocatePreference::Unknown, allocate_preference: MemoryAllocatePreference::Unknown,
_ne: crate::NonExhaustive(()), _ne: crate::NonExhaustive(()),
} }
@ -734,6 +741,24 @@ pub type StandardMemoryAllocator = GenericMemoryAllocator<Arc<FreeListAllocator>
impl StandardMemoryAllocator { impl StandardMemoryAllocator {
/// Creates a new `StandardMemoryAllocator` with default configuration. /// Creates a new `StandardMemoryAllocator` with default configuration.
pub fn new_default(device: Arc<Device>) -> Self { pub fn new_default(device: Arc<Device>) -> Self {
let memory_types = &device.physical_device().memory_properties().memory_types;
let mut memory_type_bits = u32::MAX;
for (index, MemoryType { property_flags, .. }) in memory_types.iter().enumerate() {
if property_flags.intersects(
MemoryPropertyFlags::LAZILY_ALLOCATED
| MemoryPropertyFlags::PROTECTED
| MemoryPropertyFlags::DEVICE_COHERENT
| MemoryPropertyFlags::RDMA_CAPABLE,
) {
// VUID-VkMemoryAllocateInfo-memoryTypeIndex-01872
// VUID-vkAllocateMemory-deviceCoherentMemory-02790
// Lazily allocated memory would just cause problems for suballocation in general.
memory_type_bits &= !(1 << index);
}
}
#[allow(clippy::erasing_op, clippy::identity_op)] #[allow(clippy::erasing_op, clippy::identity_op)]
let create_info = GenericMemoryAllocatorCreateInfo { let create_info = GenericMemoryAllocatorCreateInfo {
#[rustfmt::skip] #[rustfmt::skip]
@ -741,6 +766,7 @@ impl StandardMemoryAllocator {
(0 * B, 64 * M), (0 * B, 64 * M),
(1 * G, 256 * M), (1 * G, 256 * M),
], ],
memory_type_bits,
..Default::default() ..Default::default()
}; };
@ -859,6 +885,7 @@ impl<S: Suballocator> GenericMemoryAllocator<S> {
) -> Self { ) -> Self {
let GenericMemoryAllocatorCreateInfo { let GenericMemoryAllocatorCreateInfo {
block_sizes, block_sizes,
memory_type_bits,
allocation_type, allocation_type,
dedicated_allocation, dedicated_allocation,
export_handle_types, export_handle_types,
@ -872,6 +899,7 @@ impl<S: Suballocator> GenericMemoryAllocator<S> {
} = device.physical_device().memory_properties(); } = device.physical_device().memory_properties();
let mut pools = ArrayVec::new(memory_types.len(), [Self::EMPTY_POOL; MAX_MEMORY_TYPES]); let mut pools = ArrayVec::new(memory_types.len(), [Self::EMPTY_POOL; MAX_MEMORY_TYPES]);
for (i, memory_type) in memory_types.iter().enumerate() { for (i, memory_type) in memory_types.iter().enumerate() {
pools[i].memory_type = ash::vk::MemoryType { pools[i].memory_type = ash::vk::MemoryType {
property_flags: memory_type.property_flags.into(), property_flags: memory_type.property_flags.into(),
@ -913,22 +941,6 @@ impl<S: Suballocator> GenericMemoryAllocator<S> {
device_address &= device_address &=
device.api_version() >= Version::V1_1 || device.enabled_extensions().khr_device_group; device.api_version() >= Version::V1_1 || device.enabled_extensions().khr_device_group;
let mut memory_type_bits = u32::MAX;
for (index, MemoryType { property_flags, .. }) in memory_types.iter().enumerate() {
if property_flags.intersects(
MemoryPropertyFlags::LAZILY_ALLOCATED
| MemoryPropertyFlags::PROTECTED
| MemoryPropertyFlags::DEVICE_COHERENT
| MemoryPropertyFlags::DEVICE_UNCACHED
| MemoryPropertyFlags::RDMA_CAPABLE,
) {
// VUID-VkMemoryAllocateInfo-memoryTypeIndex-01872
// VUID-vkAllocateMemory-deviceCoherentMemory-02790
// Lazily allocated memory would just cause problems for suballocation in general.
memory_type_bits &= !(1 << index);
}
}
let flags = if device_address { let flags = if device_address {
MemoryAllocateFlags::DEVICE_ADDRESS MemoryAllocateFlags::DEVICE_ADDRESS
} else { } else {
@ -1236,8 +1248,12 @@ unsafe impl<S: Suballocator> MemoryAllocator for GenericMemoryAllocator<S> {
requires_dedicated_allocation, requires_dedicated_allocation,
} = requirements; } = requirements;
memory_type_bits &= self.memory_type_bits;
memory_type_bits &= create_info.memory_type_bits;
let AllocationCreateInfo { let AllocationCreateInfo {
memory_type_filter, memory_type_filter,
memory_type_bits: _,
allocate_preference, allocate_preference,
_ne: _, _ne: _,
} = create_info; } = create_info;
@ -1249,7 +1265,6 @@ unsafe impl<S: Suballocator> MemoryAllocator for GenericMemoryAllocator<S> {
}; };
let size = layout.size(); let size = layout.size();
memory_type_bits &= self.memory_type_bits;
let mut memory_type_index = self let mut memory_type_index = self
.find_memory_type_index(memory_type_bits, memory_type_filter) .find_memory_type_index(memory_type_bits, memory_type_filter)
@ -1485,6 +1500,19 @@ pub struct GenericMemoryAllocatorCreateInfo<'b, 'e> {
/// The default value is `&[]`, which must be overridden. /// The default value is `&[]`, which must be overridden.
pub block_sizes: &'b [(Threshold, BlockSize)], pub block_sizes: &'b [(Threshold, BlockSize)],
/// Lets you configure the allocator's global mask of memory type indices. Only the memory type
/// indices that have a corresponding bit at the same index set will be allocated from when
/// calling [`allocate`], otherwise [`MemoryAllocatorError::FindMemoryType`] is returned.
///
/// You may use this to disallow problematic memory types, for instance ones with the
/// [`PROTECTED`] flag, or any other flags you don't want.
///
/// The default value is [`u32::MAX`].
///
/// [`allocate`]: struct.GenericMemoryAllocator.html#method.allocate
/// [`PROTECTED`]: MemoryPropertyFlags::DEVICE_COHERENT
pub memory_type_bits: u32,
/// The allocation type that should be used for root allocations. /// The allocation type that should be used for root allocations.
/// ///
/// You only need to worry about this if you're using [`PoolAllocator`] as the suballocator, as /// You only need to worry about this if you're using [`PoolAllocator`] as the suballocator, as
@ -1563,6 +1591,7 @@ impl GenericMemoryAllocatorCreateInfo<'_, '_> {
pub(crate) fn validate(&self, device: &Device) -> Result<(), Box<ValidationError>> { pub(crate) fn validate(&self, device: &Device) -> Result<(), Box<ValidationError>> {
let &Self { let &Self {
block_sizes, block_sizes,
memory_type_bits: _,
allocation_type: _, allocation_type: _,
dedicated_allocation: _, dedicated_allocation: _,
export_handle_types, export_handle_types,
@ -1621,6 +1650,7 @@ impl Default for GenericMemoryAllocatorCreateInfo<'_, '_> {
fn default() -> Self { fn default() -> Self {
GenericMemoryAllocatorCreateInfo { GenericMemoryAllocatorCreateInfo {
block_sizes: &[], block_sizes: &[],
memory_type_bits: u32::MAX,
allocation_type: AllocationType::Unknown, allocation_type: AllocationType::Unknown,
dedicated_allocation: true, dedicated_allocation: true,
export_handle_types: &[], export_handle_types: &[],