pub struct MemoryTypeFilter {
pub required_flags: MemoryPropertyFlags,
pub preferred_flags: MemoryPropertyFlags,
pub not_preferred_flags: MemoryPropertyFlags,
}
Expand description
Describes what memory property flags are required, preferred and not preferred when picking a memory type index.
§Examples
§Direct device access only
For resources that the device frequently accesses, e.g. textures, render targets, or intermediary buffers, you want device-local memory without any host access:
let texture = Image::new(
memory_allocator.clone(),
ImageCreateInfo {
format,
extent,
usage: ImageUsage::TRANSFER_DST | ImageUsage::SAMPLED,
..Default::default()
},
AllocationCreateInfo {
memory_type_filter: MemoryTypeFilter::PREFER_DEVICE,
..Default::default()
},
)
.unwrap();
§Sequential writes from host, indirect device access
For staging, the resource is only ever written to sequentially. Also, since the device will only read the staging resource once, it would yield no benefit to place it in device-local memory, in fact it would be wasteful. Therefore, it’s best to put it in host-local memory:
let staging_buffer = Buffer::new_sized(
memory_allocator.clone(),
BufferCreateInfo {
usage: BufferUsage::TRANSFER_SRC,
..Default::default()
},
AllocationCreateInfo {
memory_type_filter: MemoryTypeFilter::PREFER_HOST |
MemoryTypeFilter::HOST_SEQUENTIAL_WRITE,
..Default::default()
},
)
.unwrap();
§Sequential writes from host, direct device access
For resources that the device accesses directly, aka a buffer/image used for anything other than transfers, it’s probably best to put it in device-local memory:
let uniform_buffer = Buffer::new_sized(
memory_allocator.clone(),
BufferCreateInfo {
usage: BufferUsage::UNIFORM_BUFFER,
..Default::default()
},
AllocationCreateInfo {
memory_type_filter: MemoryTypeFilter::PREFER_DEVICE |
MemoryTypeFilter::HOST_SEQUENTIAL_WRITE,
..Default::default()
},
)
.unwrap();
§Readback to host
For readback, e.g. getting the results of a compute shader back to the host:
let readback_buffer = Buffer::new_sized(
memory_allocator.clone(),
BufferCreateInfo {
usage: BufferUsage::TRANSFER_DST,
..Default::default()
},
AllocationCreateInfo {
memory_type_filter: MemoryTypeFilter::PREFER_HOST |
MemoryTypeFilter::HOST_RANDOM_ACCESS,
..Default::default()
},
)
.unwrap();
Fields§
§required_flags: MemoryPropertyFlags
§preferred_flags: MemoryPropertyFlags
§not_preferred_flags: MemoryPropertyFlags
Implementations§
Source§impl MemoryTypeFilter
impl MemoryTypeFilter
Sourcepub const PREFER_DEVICE: Self
pub const PREFER_DEVICE: Self
Prefers picking a memory type with the DEVICE_LOCAL
flag. It does not affect whether
the memory is host-visible. You need to combine this with either the
HOST_SEQUENTIAL_WRITE
or HOST_RANDOM_ACCESS
filter for that.
Memory being device-local means that it is fastest to access for the device. However, for dedicated GPUs, getting memory in and out of VRAM requires to go through the PCIe bus, which is very slow and should therefore only be done when necessary.
This filter is best suited for anything that the host doesn’t access, but the device accesses frequently. For example textures, render targets, and intermediary buffers.
For memory that the host does access but less frequently than the device, such as updating
a uniform buffer each frame, device-local memory may also be preferred. In this case,
because the memory is only written once before being consumed by the device and becoming
outdated, it doesn’t matter that the data is potentially transferred over the PCIe bus
since it only happens once. Since this is only a preference, if you have some requirements
such as the memory being HOST_VISIBLE
, those requirements will take precedence.
For memory that the host doesn’t access, and the device doesn’t access directly, you may still prefer device-local memory if the memory is used regularly. For instance, an image that is swapped each frame.
Keep in mind that for implementations with unified memory, there’s only system RAM. That
means that even if the implementation reports a memory type that is not HOST_VISIBLE
and
is DEVICE_LOCAL
, its still the same unified memory as all other memory. However, it may
still be faster to access. On the other hand, some such implementations don’t report any
memory types that are not HOST_VISIBLE
, which makes sense since it’s all system RAM. In
that case you wouldn’t need to do staging.
Don’t use this together with PREFER_HOST
, that makes no sense.
Sourcepub const PREFER_HOST: Self
pub const PREFER_HOST: Self
Prefers picking a memory type without the DEVICE_LOCAL
flag. It does not affect
whether the memory is host-visible. You need to combine this with either the
HOST_SEQUENTIAL_WRITE
or HOST_RANDOM_ACCESS
filter for that.
This option is best suited for resources that the host does access, but device doesn’t access directly, such as staging buffers and readback buffers.
For memory that the host does access but less frequently than the device, such as updating a uniform buffer each frame, you may still get away with using host-local memory if the updates are small and local enough. In such cases, the memory should be able to be quickly cached by the device, such that the data potentially being transferred over the PCIe bus wouldn’t matter.
For memory that the host doesn’t access, and the device doesn’t access directly, you may still prefer host-local memory if the memory is rarely used, such as for manually paging parts of device-local memory out in order to free up space on the device.
Don’t use this together with PREFER_DEVICE
, that makes no sense.
Sourcepub const HOST_SEQUENTIAL_WRITE: Self
pub const HOST_SEQUENTIAL_WRITE: Self
This guarantees picking a memory type that has the HOST_VISIBLE
flag. It does not
affect whether the memory is device-local or host-local. You need to combine this with
either the PREFER_DEVICE
or PREFER_HOST
filter for that.
Using this filter allows the allocator to pick a memory type that is uncached and
write-combined, which is ideal for sequential writes. However, this optimization might lead
to poor performance for anything else. What counts as a sequential write is any kind of
loop that writes memory locations in order, such as iterating over a slice while writing
each element in order, or equivalently using slice::copy_from_slice
. Copying sized data
also counts, as rustc should write the memory locations in order. If you have a struct,
make sure you write it member-by-member.
Example use cases include staging buffers, as well as any other kind of buffer that you only write to from the host, like a uniform or vertex buffer.
Don’t use this together with HOST_RANDOM_ACCESS
, that makes no sense. If you do both a
sequential write and read or random access, then you should use HOST_RANDOM_ACCESS
instead. However, you could also consider using different allocations for the two purposes
to get the most performance out, if that’s possible.
Sourcepub const HOST_RANDOM_ACCESS: Self
pub const HOST_RANDOM_ACCESS: Self
This guarantees picking a memory type that has the HOST_VISIBLE
and HOST_CACHED
flags, which is best suited for readback and/or random access. It does not affect whether
the memory is device-local or host-local. You need to combine this with either the
PREFER_DEVICE
or PREFER_HOST
filter for that.
Example use cases include using the device for things other than rendering and getting the results back to the host. That might be compute shading, or image or video manipulation, or screenshotting.
Don’t use this together with HOST_SEQUENTIAL_WRITE
, that makes no sense. If you are
sure you only ever need to sequentially write to the allocation, then using
HOST_SEQUENTIAL_WRITE
instead will yield better performance.
Trait Implementations§
Source§impl BitOr for MemoryTypeFilter
impl BitOr for MemoryTypeFilter
Source§impl Clone for MemoryTypeFilter
impl Clone for MemoryTypeFilter
Source§fn clone(&self) -> MemoryTypeFilter
fn clone(&self) -> MemoryTypeFilter
1.0.0 · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source
. Read more