class new in Git master
#include <Magnum/Vk/Memory.h>
Memory Device memory.
Wraps a VkDeviceMemory and handles its allocation and mapping. Device memory is backing Vulkan buffers, images and other objects.
Memory allocation
By default, the memory will get allocated for you during the creation of Buffer, Image and other objects. In case you want to handle the allocation yourself instead (which you indicate by passing the NoAllocate tag to constructors of these objects), it consists of these steps:
- Querying memory requirements of a particular object, for example using Buffer::
memoryRequirements() or Image:: memoryRequirements() - Picking a memory type satisfying requirements of the object it's being allocated for (such as allowed memory types) and user requirements (whether it should be device-local, host-mappable etc.) using DeviceProperties::
pickMemory() - Allocating a new Memory or taking a (correctly aligned) sub-range of an existing allocation from given memory type
- Binding the memory (sub-range) to the object, using Buffer::
bindMemory(), Image:: bindMemory() and others
The following example allocates a single block memory for two buffers, one containing vertex and the other index data:
#include <Magnum/Vk/MemoryAllocateInfo.h> … /* Create buffers without allocating them */ Vk::Buffer vertices{device, Vk::BufferCreateInfo{Vk::BufferUsage::VertexBuffer, vertexData.size()}, NoAllocate}; Vk::Buffer indices{device, Vk::BufferCreateInfo{Vk::BufferUsage::IndexBuffer, vertexData.size()}, NoAllocate}; /* Query memory requirements of both buffers, calculate max alignment */ Vk::MemoryRequirements verticesRequirements = vertices.memoryRequirements(); Vk::MemoryRequirements indicesRequirements = indices.memoryRequirements(); const UnsignedLong alignment = Math::max(verticesRequirements.alignment(), indicesRequirements.alignment()); /* Allocate memory that's large enough to contain both buffers including the strictest alignment, and is of a type satisfying requirements of both */ Vk::Memory memory{device, Vk::MemoryAllocateInfo{ verticesRequirements.alignedSize(alignment) + indicesRequirements.alignedSize(alignment), device.properties().pickMemory(Vk::MemoryFlag::HostVisible, verticesRequirements.memories() & indicesRequirements.memories()) }}; const UnsignedLong indicesOffset = verticesRequirements.alignedSize(alignment); /* Bind the respective sub-ranges to the buffers */ vertices.bindMemory(memory, 0); indices.bindMemory(memory, indicesOffset);
Memory mapping
If the memory is created with the MemoryFlag::
- One is to first map the vertex buffer sub-range, upload the data, unmap it, and then do the same process for the index buffer sub-range. This way is more encapsulated without having to worry if there's already a mapping and who owns it, but means more work for the driver.
- Another option is to map the whole memory at once and then upload data of particular buffers to correct subranges. Here the mapping has to be owned by some external entity which ensures it's valid for as long as any buffer wants to map its memory sub-range.
The following example maps the memory allocated above and copies index and vertex data to it:
/* The memory gets unmapped again at the end of scope */ { Containers::Array<char, Vk::MemoryMapDeleter> mapped = memory.map(); Utility::copy(vertexData, mapped.prefix(vertexData.size())); Utility::copy(indexData, mapped.slice(indicesOffset, indicesOffset + indexData.size())); }
Public static functions
- static auto wrap(Device& device, VkDeviceMemory handle, UnsignedLong size, HandleFlags flags = {}) -> Memory
- Wrap existing Vulkan handle.
Constructors, destructors, conversion operators
Public functions
- auto operator=(const Memory&) -> Memory& deleted
- Copying is not allowed.
- auto operator=(Memory&& other) -> Memory& noexcept
- Move assignment.
- auto handle() -> VkDeviceMemory
- Underlying VkDeviceMemory handle.
- auto handleFlags() const -> HandleFlags
- Handle flags.
- auto size() const -> UnsignedLong
- Memory allocation size.
-
auto map(UnsignedLong offset,
UnsignedLong size) -> Containers::
Array<char, MemoryMapDeleter> - Map a memory range.
-
auto map() -> Containers::
Array<char, MemoryMapDeleter> - Map the whole memory.
-
auto mapRead(UnsignedLong offset,
UnsignedLong size) -> Containers::
Array<const char, MemoryMapDeleter> - Map a memory range read-only.
-
auto mapRead() -> Containers::
Array<const char, MemoryMapDeleter> - Map the whole memory read-only.
- auto release() -> VkDeviceMemory
- Release the underlying Vulkan memory.
Function documentation
static Memory Magnum:: Vk:: Memory:: wrap(Device& device,
VkDeviceMemory handle,
UnsignedLong size,
HandleFlags flags = {})
Wrap existing Vulkan handle.
Parameters | |
---|---|
device | Vulkan device the memory is allocated on |
handle | The VkDeviceMemory handle |
size | Memory size |
flags | Handle flags |
The handle
is expected to be originating from device
. The size
parameter will be used to properly size the output array coming from map(). If a concrete size
is unknown, use a zero — you will then be able to only use the map(UnsignedLong, UnsignedLong) overload.
Unlike a memory allocated using a constructor, the Vulkan memory is by default not freed on destruction, use flags
for different behavior.
Magnum:: Vk:: Memory:: Memory(Device& device,
const MemoryAllocateInfo& info) explicit
Constructor.
Parameters | |
---|---|
device | Vulkan device to allocate the memory on |
info | Memory allocation info |
Magnum:: Vk:: Memory:: ~Memory()
Destructor.
Frees associated VkDeviceMemory handle, unless the instance was created using wrap() without HandleFlag::
Magnum:: Vk:: Memory:: operator VkDeviceMemory()
This is an overloaded member function, provided for convenience. It differs from the above function only in what argument(s) it accepts.
Containers:: Array<char, MemoryMapDeleter> Magnum:: Vk:: Memory:: map(UnsignedLong offset,
UnsignedLong size)
Map a memory range.
Parameters | |
---|---|
offset | Byte offset |
size | Memory size |
The returned array size is size
and the deleter performs an unmap. For this operation to work, the memory has to be allocated with MemoryFlag::offset
and size
be in bounds for size().
Containers:: Array<char, MemoryMapDeleter> Magnum:: Vk:: Memory:: map()
Map the whole memory.
Equivalent to calling map(UnsignedLong, UnsignedLong) with 0
and size().
Containers:: Array<const char, MemoryMapDeleter> Magnum:: Vk:: Memory:: mapRead(UnsignedLong offset,
UnsignedLong size)
Map a memory range read-only.
Like map(UnsignedLong, UnsignedLong) but returning a const
array. Currently Vulkan doesn't have any flags to control read/write access, so apart from a different return type the behavior is equivalent.
Containers:: Array<const char, MemoryMapDeleter> Magnum:: Vk:: Memory:: mapRead()
Map the whole memory read-only.
Equivalent to calling mapRead(UnsignedLong, UnsignedLong) with 0
and size().
VkDeviceMemory Magnum:: Vk:: Memory:: release()
Release the underlying Vulkan memory.
Releases ownership of the Vulkan memory and returns its handle so vkFreeMemory() is not called on destruction. The internal state is then equivalent to moved-from state.