mirror of
https://github.com/vulkano-rs/vulkano.git
synced 2024-11-22 06:45:23 +00:00
Make GenericMemoryAllocatorCreateInfo::block_sizes
more flexible (#2319)
This commit is contained in:
parent
28224138f2
commit
aecb7a476a
@ -238,7 +238,7 @@ use crate::{
|
|||||||
DeviceSize, Requires, RequiresAllOf, RequiresOneOf, Validated, ValidationError, Version,
|
DeviceSize, Requires, RequiresAllOf, RequiresOneOf, Validated, ValidationError, Version,
|
||||||
VulkanError,
|
VulkanError,
|
||||||
};
|
};
|
||||||
use ash::vk::{MAX_MEMORY_HEAPS, MAX_MEMORY_TYPES};
|
use ash::vk::MAX_MEMORY_TYPES;
|
||||||
use parking_lot::Mutex;
|
use parking_lot::Mutex;
|
||||||
use std::{
|
use std::{
|
||||||
error::Error,
|
error::Error,
|
||||||
@ -249,11 +249,6 @@ use std::{
|
|||||||
sync::Arc,
|
sync::Arc,
|
||||||
};
|
};
|
||||||
|
|
||||||
const B: DeviceSize = 1;
|
|
||||||
const K: DeviceSize = 1024 * B;
|
|
||||||
const M: DeviceSize = 1024 * K;
|
|
||||||
const G: DeviceSize = 1024 * M;
|
|
||||||
|
|
||||||
/// General-purpose memory allocators which allocate from any memory type dynamically as needed.
|
/// General-purpose memory allocators which allocate from any memory type dynamically as needed.
|
||||||
///
|
///
|
||||||
/// # Safety
|
/// # Safety
|
||||||
@ -821,12 +816,26 @@ pub type StandardMemoryAllocator = GenericMemoryAllocator<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 MemoryProperties {
|
||||||
|
memory_types,
|
||||||
|
memory_heaps,
|
||||||
|
} = device.physical_device().memory_properties();
|
||||||
|
|
||||||
|
let mut block_sizes = [0; MAX_MEMORY_TYPES];
|
||||||
let mut memory_type_bits = u32::MAX;
|
let mut memory_type_bits = u32::MAX;
|
||||||
|
|
||||||
for (index, MemoryType { property_flags, .. }) in memory_types.iter().enumerate() {
|
for (index, memory_type) in memory_types.iter().enumerate() {
|
||||||
if property_flags.intersects(
|
const LARGE_HEAP_THRESHOLD: DeviceSize = 1024 * 1024 * 1024;
|
||||||
|
|
||||||
|
let heap_size = memory_heaps[memory_type.heap_index as usize].size;
|
||||||
|
|
||||||
|
block_sizes[index] = if heap_size >= LARGE_HEAP_THRESHOLD {
|
||||||
|
256 * 1024 * 1024
|
||||||
|
} else {
|
||||||
|
64 * 1024 * 1024
|
||||||
|
};
|
||||||
|
|
||||||
|
if memory_type.property_flags.intersects(
|
||||||
MemoryPropertyFlags::LAZILY_ALLOCATED
|
MemoryPropertyFlags::LAZILY_ALLOCATED
|
||||||
| MemoryPropertyFlags::PROTECTED
|
| MemoryPropertyFlags::PROTECTED
|
||||||
| MemoryPropertyFlags::DEVICE_COHERENT
|
| MemoryPropertyFlags::DEVICE_COHERENT
|
||||||
@ -839,13 +848,8 @@ impl StandardMemoryAllocator {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(clippy::erasing_op, clippy::identity_op)]
|
|
||||||
let create_info = GenericMemoryAllocatorCreateInfo {
|
let create_info = GenericMemoryAllocatorCreateInfo {
|
||||||
#[rustfmt::skip]
|
block_sizes: &block_sizes,
|
||||||
block_sizes: &[
|
|
||||||
(0 * B, 64 * M),
|
|
||||||
(1 * G, 256 * M),
|
|
||||||
],
|
|
||||||
memory_type_bits,
|
memory_type_bits,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
@ -894,8 +898,6 @@ pub struct GenericMemoryAllocator<S> {
|
|||||||
buffer_image_granularity: DeviceAlignment,
|
buffer_image_granularity: DeviceAlignment,
|
||||||
// Each memory type has a pool of `DeviceMemory` blocks.
|
// Each memory type has a pool of `DeviceMemory` blocks.
|
||||||
pools: ArrayVec<Pool<S>, MAX_MEMORY_TYPES>,
|
pools: ArrayVec<Pool<S>, MAX_MEMORY_TYPES>,
|
||||||
// Each memory heap has its own block size.
|
|
||||||
block_sizes: ArrayVec<DeviceSize, MAX_MEMORY_HEAPS>,
|
|
||||||
// Global mask of memory types.
|
// Global mask of memory types.
|
||||||
memory_type_bits: u32,
|
memory_type_bits: u32,
|
||||||
dedicated_allocation: bool,
|
dedicated_allocation: bool,
|
||||||
@ -909,8 +911,9 @@ pub struct GenericMemoryAllocator<S> {
|
|||||||
struct Pool<S> {
|
struct Pool<S> {
|
||||||
blocks: Mutex<Vec<Box<Block<S>>>>,
|
blocks: Mutex<Vec<Box<Block<S>>>>,
|
||||||
// This is cached here for faster access, so we don't need to hop through 3 pointers.
|
// This is cached here for faster access, so we don't need to hop through 3 pointers.
|
||||||
memory_type: ash::vk::MemoryType,
|
property_flags: MemoryPropertyFlags,
|
||||||
atom_size: DeviceAlignment,
|
atom_size: DeviceAlignment,
|
||||||
|
block_size: DeviceSize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S> GenericMemoryAllocator<S> {
|
impl<S> GenericMemoryAllocator<S> {
|
||||||
@ -918,11 +921,9 @@ impl<S> GenericMemoryAllocator<S> {
|
|||||||
#[allow(clippy::declare_interior_mutable_const)]
|
#[allow(clippy::declare_interior_mutable_const)]
|
||||||
const EMPTY_POOL: Pool<S> = Pool {
|
const EMPTY_POOL: Pool<S> = Pool {
|
||||||
blocks: Mutex::new(Vec::new()),
|
blocks: Mutex::new(Vec::new()),
|
||||||
memory_type: ash::vk::MemoryType {
|
property_flags: MemoryPropertyFlags::empty(),
|
||||||
property_flags: ash::vk::MemoryPropertyFlags::empty(),
|
|
||||||
heap_index: 0,
|
|
||||||
},
|
|
||||||
atom_size: DeviceAlignment::MIN,
|
atom_size: DeviceAlignment::MIN,
|
||||||
|
block_size: 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Creates a new `GenericMemoryAllocator<S>` using the provided suballocator `S` for
|
/// Creates a new `GenericMemoryAllocator<S>` using the provided suballocator `S` for
|
||||||
@ -930,12 +931,13 @@ impl<S> GenericMemoryAllocator<S> {
|
|||||||
///
|
///
|
||||||
/// # Panics
|
/// # Panics
|
||||||
///
|
///
|
||||||
/// - Panics if `create_info.block_sizes` is not sorted by threshold.
|
/// - Panics if `create_info.block_sizes` doesn't contain as many elements as the number of
|
||||||
/// - Panics if `create_info.block_sizes` contains duplicate thresholds.
|
/// memory types.
|
||||||
/// - Panics if `create_info.block_sizes` does not contain a baseline threshold of `0`.
|
/// - Panics if `create_info.export_handle_types` is non-empty and doesn't contain as many
|
||||||
|
/// elements as the number of memory types.
|
||||||
pub fn new(
|
pub fn new(
|
||||||
device: Arc<Device>,
|
device: Arc<Device>,
|
||||||
create_info: GenericMemoryAllocatorCreateInfo<'_, '_>,
|
create_info: GenericMemoryAllocatorCreateInfo<'_>,
|
||||||
) -> Result<Self, Box<ValidationError>> {
|
) -> Result<Self, Box<ValidationError>> {
|
||||||
Self::validate_new(&device, &create_info)?;
|
Self::validate_new(&device, &create_info)?;
|
||||||
|
|
||||||
@ -944,7 +946,7 @@ impl<S> GenericMemoryAllocator<S> {
|
|||||||
|
|
||||||
fn validate_new(
|
fn validate_new(
|
||||||
device: &Device,
|
device: &Device,
|
||||||
create_info: &GenericMemoryAllocatorCreateInfo<'_, '_>,
|
create_info: &GenericMemoryAllocatorCreateInfo<'_>,
|
||||||
) -> Result<(), Box<ValidationError>> {
|
) -> Result<(), Box<ValidationError>> {
|
||||||
create_info
|
create_info
|
||||||
.validate(device)
|
.validate(device)
|
||||||
@ -956,7 +958,7 @@ impl<S> GenericMemoryAllocator<S> {
|
|||||||
#[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
|
#[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
|
||||||
pub unsafe fn new_unchecked(
|
pub unsafe fn new_unchecked(
|
||||||
device: Arc<Device>,
|
device: Arc<Device>,
|
||||||
create_info: GenericMemoryAllocatorCreateInfo<'_, '_>,
|
create_info: GenericMemoryAllocatorCreateInfo<'_>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let GenericMemoryAllocatorCreateInfo {
|
let GenericMemoryAllocatorCreateInfo {
|
||||||
block_sizes,
|
block_sizes,
|
||||||
@ -972,47 +974,23 @@ impl<S> GenericMemoryAllocator<S> {
|
|||||||
.properties()
|
.properties()
|
||||||
.buffer_image_granularity;
|
.buffer_image_granularity;
|
||||||
|
|
||||||
let MemoryProperties {
|
let memory_types = &device.physical_device().memory_properties().memory_types;
|
||||||
memory_types,
|
|
||||||
memory_heaps,
|
|
||||||
} = 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 (
|
for (index, &MemoryType { property_flags, .. }) in memory_types.iter().enumerate() {
|
||||||
i,
|
pools[index].property_flags = property_flags;
|
||||||
&MemoryType {
|
|
||||||
property_flags,
|
|
||||||
heap_index,
|
|
||||||
},
|
|
||||||
) in memory_types.iter().enumerate()
|
|
||||||
{
|
|
||||||
pools[i].memory_type = ash::vk::MemoryType {
|
|
||||||
property_flags: property_flags.into(),
|
|
||||||
heap_index,
|
|
||||||
};
|
|
||||||
|
|
||||||
if property_flags.intersects(MemoryPropertyFlags::HOST_VISIBLE)
|
if property_flags.intersects(MemoryPropertyFlags::HOST_VISIBLE)
|
||||||
&& !property_flags.intersects(MemoryPropertyFlags::HOST_COHERENT)
|
&& !property_flags.intersects(MemoryPropertyFlags::HOST_COHERENT)
|
||||||
{
|
{
|
||||||
pools[i].atom_size = device.physical_device().properties().non_coherent_atom_size;
|
pools[index].atom_size =
|
||||||
|
device.physical_device().properties().non_coherent_atom_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pools[index].block_size = block_sizes[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
let block_sizes = {
|
|
||||||
let mut sizes = ArrayVec::new(memory_heaps.len(), [0; MAX_MEMORY_HEAPS]);
|
|
||||||
|
|
||||||
for (i, memory_heap) in memory_heaps.iter().enumerate() {
|
|
||||||
let idx = match block_sizes.binary_search_by_key(&memory_heap.size, |&(t, _)| t) {
|
|
||||||
Ok(idx) => idx,
|
|
||||||
Err(idx) => idx.saturating_sub(1),
|
|
||||||
};
|
|
||||||
sizes[i] = block_sizes[idx].1;
|
|
||||||
}
|
|
||||||
|
|
||||||
sizes
|
|
||||||
};
|
|
||||||
|
|
||||||
let export_handle_types = {
|
let export_handle_types = {
|
||||||
let mut types = ArrayVec::new(
|
let mut types = ArrayVec::new(
|
||||||
export_handle_types.len(),
|
export_handle_types.len(),
|
||||||
@ -1046,7 +1024,6 @@ impl<S> GenericMemoryAllocator<S> {
|
|||||||
device: InstanceOwnedDebugWrapper(device),
|
device: InstanceOwnedDebugWrapper(device),
|
||||||
buffer_image_granularity,
|
buffer_image_granularity,
|
||||||
pools,
|
pools,
|
||||||
block_sizes,
|
|
||||||
dedicated_allocation,
|
dedicated_allocation,
|
||||||
export_handle_types,
|
export_handle_types,
|
||||||
flags,
|
flags,
|
||||||
@ -1076,9 +1053,8 @@ impl<S> GenericMemoryAllocator<S> {
|
|||||||
)?;
|
)?;
|
||||||
|
|
||||||
if self.pools[memory_type_index as usize]
|
if self.pools[memory_type_index as usize]
|
||||||
.memory_type
|
|
||||||
.property_flags
|
.property_flags
|
||||||
.intersects(ash::vk::MemoryPropertyFlags::HOST_VISIBLE)
|
.intersects(MemoryPropertyFlags::HOST_VISIBLE)
|
||||||
{
|
{
|
||||||
// SAFETY:
|
// SAFETY:
|
||||||
// - We checked that the memory is host-visible.
|
// - We checked that the memory is host-visible.
|
||||||
@ -1109,7 +1085,7 @@ unsafe impl<S: Suballocator + Send + 'static> MemoryAllocator for GenericMemoryA
|
|||||||
|
|
||||||
self.pools
|
self.pools
|
||||||
.iter()
|
.iter()
|
||||||
.map(|pool| pool.memory_type.property_flags)
|
.map(|pool| ash::vk::MemoryPropertyFlags::from(pool.property_flags))
|
||||||
.enumerate()
|
.enumerate()
|
||||||
// Filter out memory types which are supported by the memory type bits and have the
|
// Filter out memory types which are supported by the memory type bits and have the
|
||||||
// required flags set.
|
// required flags set.
|
||||||
@ -1163,9 +1139,8 @@ unsafe impl<S: Suballocator + Send + 'static> MemoryAllocator for GenericMemoryA
|
|||||||
) -> Result<MemoryAlloc, MemoryAllocatorError> {
|
) -> Result<MemoryAlloc, MemoryAllocatorError> {
|
||||||
let size = layout.size();
|
let size = layout.size();
|
||||||
let pool = &self.pools[memory_type_index as usize];
|
let pool = &self.pools[memory_type_index as usize];
|
||||||
let block_size = self.block_sizes[pool.memory_type.heap_index as usize];
|
|
||||||
|
|
||||||
if size > block_size {
|
if size > pool.block_size {
|
||||||
return Err(MemoryAllocatorError::BlockSizeExceeded);
|
return Err(MemoryAllocatorError::BlockSizeExceeded);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1199,7 +1174,7 @@ unsafe impl<S: Suballocator + Send + 'static> MemoryAllocator for GenericMemoryA
|
|||||||
let mut i = 0;
|
let mut i = 0;
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
let allocation_size = block_size >> i;
|
let allocation_size = pool.block_size >> i;
|
||||||
|
|
||||||
match self.allocate_device_memory(
|
match self.allocate_device_memory(
|
||||||
memory_type_index,
|
memory_type_index,
|
||||||
@ -1214,7 +1189,7 @@ unsafe impl<S: Suballocator + Send + 'static> MemoryAllocator for GenericMemoryA
|
|||||||
// resulting size is still large enough.
|
// resulting size is still large enough.
|
||||||
Err(Validated::Error(
|
Err(Validated::Error(
|
||||||
VulkanError::OutOfHostMemory | VulkanError::OutOfDeviceMemory,
|
VulkanError::OutOfHostMemory | VulkanError::OutOfDeviceMemory,
|
||||||
)) if i < 3 && block_size >> (i + 1) >= size => {
|
)) if i < 3 && pool.block_size >> (i + 1) >= size => {
|
||||||
i += 1;
|
i += 1;
|
||||||
}
|
}
|
||||||
Err(err) => return Err(MemoryAllocatorError::AllocateDeviceMemory(err)),
|
Err(err) => return Err(MemoryAllocatorError::AllocateDeviceMemory(err)),
|
||||||
@ -1330,8 +1305,7 @@ unsafe impl<S: Suballocator + Send + 'static> MemoryAllocator for GenericMemoryA
|
|||||||
};
|
};
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
let memory_type = self.pools[memory_type_index as usize].memory_type;
|
let pool = &self.pools[memory_type_index as usize];
|
||||||
let block_size = self.block_sizes[memory_type.heap_index as usize];
|
|
||||||
|
|
||||||
let res = match allocate_preference {
|
let res = match allocate_preference {
|
||||||
MemoryAllocatePreference::Unknown => {
|
MemoryAllocatePreference::Unknown => {
|
||||||
@ -1345,11 +1319,11 @@ unsafe impl<S: Suballocator + Send + 'static> MemoryAllocator for GenericMemoryA
|
|||||||
export_handle_types,
|
export_handle_types,
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
if size > block_size / 2 {
|
if size > pool.block_size / 2 {
|
||||||
prefers_dedicated_allocation = true;
|
prefers_dedicated_allocation = true;
|
||||||
}
|
}
|
||||||
if self.device.allocation_count() > self.max_allocations
|
if self.device.allocation_count() > self.max_allocations
|
||||||
&& size <= block_size
|
&& size <= pool.block_size
|
||||||
{
|
{
|
||||||
prefers_dedicated_allocation = false;
|
prefers_dedicated_allocation = false;
|
||||||
}
|
}
|
||||||
@ -1589,17 +1563,12 @@ impl<S: Suballocator> Block<S> {
|
|||||||
|
|
||||||
/// Parameters to create a new [`GenericMemoryAllocator`].
|
/// Parameters to create a new [`GenericMemoryAllocator`].
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct GenericMemoryAllocatorCreateInfo<'b, 'e> {
|
pub struct GenericMemoryAllocatorCreateInfo<'a> {
|
||||||
/// Lets you configure the block sizes for various heap size classes.
|
/// Lets you configure the block sizes for each memory type.
|
||||||
///
|
///
|
||||||
/// Each entry is a pair of the threshold for the heap size and the block size that should be
|
/// Must contain one entry for each memory type. The allocator keeps a pool of [`DeviceMemory`]
|
||||||
/// used for that heap. Must be sorted by threshold and all thresholds must be unique. Must
|
/// blocks for each memory type, and every time a new block is allocated, the block size
|
||||||
/// contain a baseline threshold of 0.
|
/// corresponding to the memory type index is looked up here and used for the allocation.
|
||||||
///
|
|
||||||
/// The allocator keeps a pool of [`DeviceMemory`] blocks for each memory type, so each memory
|
|
||||||
/// type that resides in a heap whose size crosses one of the thresholds will use the
|
|
||||||
/// corresponding block size. If multiple thresholds apply to a given heap, the block size
|
|
||||||
/// corresponding to the largest threshold is chosen.
|
|
||||||
///
|
///
|
||||||
/// The block size is going to be the maximum size of a `DeviceMemory` block that is tried. If
|
/// The block size is going to be the maximum size of a `DeviceMemory` block that is tried. If
|
||||||
/// allocating a block with the size fails, the allocator tries 1/2, 1/4 and 1/8 of the block
|
/// allocating a block with the size fails, the allocator tries 1/2, 1/4 and 1/8 of the block
|
||||||
@ -1609,7 +1578,7 @@ pub struct GenericMemoryAllocatorCreateInfo<'b, 'e> {
|
|||||||
/// [`MemoryAllocatePreference::NeverAllocate`] however.
|
/// [`MemoryAllocatePreference::NeverAllocate`] however.
|
||||||
///
|
///
|
||||||
/// 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: &'a [DeviceSize],
|
||||||
|
|
||||||
/// Lets you configure the allocator's global mask of memory type indices. Only the memory type
|
/// 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
|
/// indices that have a corresponding bit at the same index set will be allocated from when
|
||||||
@ -1654,7 +1623,7 @@ pub struct GenericMemoryAllocatorCreateInfo<'b, 'e> {
|
|||||||
/// here and used for the allocation.
|
/// here and used for the allocation.
|
||||||
///
|
///
|
||||||
/// The default value is `&[]`.
|
/// The default value is `&[]`.
|
||||||
pub export_handle_types: &'e [ExternalMemoryHandleTypes],
|
pub export_handle_types: &'a [ExternalMemoryHandleTypes],
|
||||||
|
|
||||||
/// Whether the allocator should allocate the [`DeviceMemory`] blocks with the
|
/// Whether the allocator should allocate the [`DeviceMemory`] blocks with the
|
||||||
/// [`DEVICE_ADDRESS`] flag set.
|
/// [`DEVICE_ADDRESS`] flag set.
|
||||||
@ -1679,11 +1648,7 @@ pub struct GenericMemoryAllocatorCreateInfo<'b, 'e> {
|
|||||||
pub _ne: crate::NonExhaustive,
|
pub _ne: crate::NonExhaustive,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type Threshold = DeviceSize;
|
impl GenericMemoryAllocatorCreateInfo<'_> {
|
||||||
|
|
||||||
pub type BlockSize = DeviceSize;
|
|
||||||
|
|
||||||
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,
|
||||||
@ -1694,13 +1659,11 @@ impl GenericMemoryAllocatorCreateInfo<'_, '_> {
|
|||||||
_ne: _,
|
_ne: _,
|
||||||
} = self;
|
} = self;
|
||||||
|
|
||||||
|
let memory_types = &device.physical_device().memory_properties().memory_types;
|
||||||
|
|
||||||
assert!(
|
assert!(
|
||||||
block_sizes.windows(2).all(|win| win[0].0 < win[1].0),
|
block_sizes.len() == memory_types.len(),
|
||||||
"`create_info.block_sizes` must be sorted by threshold without duplicates",
|
"`create_info.block_sizes` must contain as many elements as the number of memory types",
|
||||||
);
|
|
||||||
assert!(
|
|
||||||
matches!(block_sizes.first(), Some((0, _))),
|
|
||||||
"`create_info.block_sizes` must contain a baseline threshold `0`",
|
|
||||||
);
|
);
|
||||||
|
|
||||||
if !export_handle_types.is_empty() {
|
if !export_handle_types.is_empty() {
|
||||||
@ -1719,12 +1682,7 @@ impl GenericMemoryAllocatorCreateInfo<'_, '_> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
assert!(
|
assert!(
|
||||||
export_handle_types.len()
|
export_handle_types.len() == memory_types.len(),
|
||||||
== device
|
|
||||||
.physical_device()
|
|
||||||
.memory_properties()
|
|
||||||
.memory_types
|
|
||||||
.len(),
|
|
||||||
"`create_info.export_handle_types` must contain as many elements as the number of \
|
"`create_info.export_handle_types` must contain as many elements as the number of \
|
||||||
memory types if not empty",
|
memory types if not empty",
|
||||||
);
|
);
|
||||||
@ -1740,7 +1698,7 @@ impl GenericMemoryAllocatorCreateInfo<'_, '_> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for GenericMemoryAllocatorCreateInfo<'_, '_> {
|
impl Default for GenericMemoryAllocatorCreateInfo<'_> {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
GenericMemoryAllocatorCreateInfo {
|
GenericMemoryAllocatorCreateInfo {
|
||||||
|
Loading…
Reference in New Issue
Block a user