diff --git a/docs/html/_v_k__k_h_r_dedicated_allocation.html b/docs/html/_v_k__k_h_r_dedicated_allocation.html index ca38bb3..fded3c2 100644 --- a/docs/html/_v_k__k_h_r_dedicated_allocation.html +++ b/docs/html/_v_k__k_h_r_dedicated_allocation.html @@ -82,6 +82,8 @@ $(function() {
Other members of this structure can be null as long as you leave VMA_STATIC_VULKAN_FUNCTIONS
defined to 1, which is the default.
3 . Use VMA_ALLOCATOR_CREATE_KHR_DEDICATED_ALLOCATION_BIT
flag when creating your VmaAllocator
to inform the library that you enabled required extensions and you want the library to use them.
That's all. The extension will be automatically used whenever you create a buffer using vmaCreateBuffer() or image using vmaCreateImage().
+When using the extension together with Vulkan Validation Layer, you will receive warnings like this:
vkBindBufferMemory(): Binding memory to buffer 0x33 but vkGetBufferMemoryRequirements() has not been called on that buffer. +
It is OK, you should just ignore it. It happens because you use function vkGetBufferMemoryRequirements2KHR()
instead of standard vkGetBufferMemoryRequirements()
, while the validation layer seems to be unaware of it.
To learn more about this extension, see:
Example:
-.// Create a pool that could have at most 2 blocks, 128 MB each. -VmaPoolCreateInfo poolCreateInfo = {}; -poolCreateInfo.memoryTypeIndex = ... -poolCreateInfo.blockSize = 128ull * 1024 * 1024; -poolCreateInfo.maxBlockCount = 2; - -VmaPool pool; -vmaCreatePool(allocator, &poolCreateInfo, &pool); - -.// Allocate a buffer out of it. -VkBufferCreateInfo bufCreateInfo = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO }; -bufCreateInfo.size = 1024; -bufCreateInfo.usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT; - -VmaAllocationCreateInfo allocCreateInfo = {}; -allocCreateInfo.pool = pool; - -VkBuffer buf; -VmaAllocation alloc; -VmaAllocationInfo allocInfo; -vmaCreateBuffer(allocator, &bufCreateInfo, &allocCreateInfo, &buf, &alloc, &allocInfo); -
You have to free all allocations made from this pool before destroying it.
-vmaDestroyBuffer(allocator, buf, alloc); -vmaDestroyPool(allocator, pool);+
You have to free all allocations made from this pool before destroying it.
+How do you inform the library when new frame starts?
You need to call function vmaSetCurrentFrameIndex().
Example code:
-struct MyBuffer -{ - VkBuffer m_Buf = nullptr; - VmaAllocation m_Alloc = nullptr; - - .// Called when the buffer is really needed in the current frame. - void EnsureBuffer(); -}; - -void MyBuffer::EnsureBuffer() -{ - .// Buffer has been created. - if(m_Buf != VK_NULL_HANDLE) - { - .// Check if its allocation is not lost + mark it as used in current frame. - VmaAllocationInfo allocInfo; - vmaGetAllocationInfo(allocator, m_Alloc, &allocInfo); - if(allocInfo.deviceMemory != VK_NULL_HANDLE) - { - .// It's all OK - safe to use m_Buf. - return; - } - } - - .// Buffer not yet exists or lost - destroy and recreate it. - - vmaDestroyBuffer(allocator, m_Buf, m_Alloc); - - VkBufferCreateInfo bufCreateInfo = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO }; - bufCreateInfo.size = 1024; - bufCreateInfo.usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT; - - VmaAllocationCreateInfo allocCreateInfo = {}; - allocCreateInfo.usage = VMA_MEMORY_USAGE_GPU_ONLY; - allocCreateInfo.flags = VMA_ALLOCATION_CREATE_CAN_BECOME_LOST_BIT | - VMA_ALLOCATION_CREATE_CAN_MAKE_OTHER_LOST_BIT; - - vmaCreateBuffer(allocator, &bufCreateInfo, &allocCreateInfo, &m_Buf, &m_Alloc, nullptr); -} -
When using lost allocations, you may see some Vulkan validation layer warnings about overlapping regions of memory bound to different kinds of buffers and images. This is still valid as long as you implement proper handling of lost allocations (like in the example above) and don't use them.
+When using lost allocations, you may see some Vulkan validation layer warnings about overlapping regions of memory bound to different kinds of buffers and images. This is still valid as long as you implement proper handling of lost allocations (like in the example above) and don't use them.
The library uses following algorithm for allocation, in order:
If you need to map memory on host, it may happen that two allocations are assigned to the same VkDeviceMemory
block, so if you map them both at the same time, it will cause error because mapping single memory block multiple times is illegal in Vulkan.
It is safer, more convenient and more efficient to use special feature designed for that: persistently mapped memory. Allocations made with VMA_ALLOCATION_CREATE_PERSISTENT_MAP_BIT
flag set in VmaAllocationCreateInfo::flags are returned from device memory blocks that stay mapped all the time, so you can just access CPU pointer to it. VmaAllocationInfo::pMappedData pointer is already offseted to the beginning of particular allocation. Example:
VkBufferCreateInfo bufCreateInfo = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO }; -bufCreateInfo.size = 1024; -bufCreateInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT; - -VmaAllocationCreateInfo allocCreateInfo = {}; -allocCreateInfo.usage = VMA_MEMORY_USAGE_CPU_ONLY; -allocCreateInfo.flags = VMA_ALLOCATION_CREATE_PERSISTENT_MAP_BIT; - -VkBuffer buf; -VmaAllocation alloc; -VmaAllocationInfo allocInfo; -vmaCreateBuffer(allocator, &bufCreateInfo, &allocCreateInfo, &buf, &alloc, &allocInfo); - -.// Buffer is immediately mapped. You can access its memory. -memcpy(allocInfo.pMappedData, myData, 1024); -
Memory in Vulkan doesn't need to be unmapped before using it e.g. for transfers, but if you are not sure whether it's HOST_COHERENT
(here is surely is because it's created with VMA_MEMORY_USAGE_CPU_ONLY
), you should check it. If it's not, you should call vkInvalidateMappedMemoryRanges()
before reading and vkFlushMappedMemoryRanges()
after writing to mapped memory on CPU. Example:
VkMemoryPropertyFlags memFlags; -vmaGetMemoryTypeProperties(allocator, allocInfo.memoryType, &memFlags); -if((memFlags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT) == 0) -{ - VkMappedMemoryRange memRange = { VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE }; - memRange.memory = allocInfo.deviceMemory; - memRange.offset = allocInfo.offset; - memRange.size = allocInfo.size; - vkFlushMappedMemoryRanges(device, 1, &memRange); -} -
On AMD GPUs on Windows, Vulkan memory from the type that has both DEVICE_LOCAL
and HOST_VISIBLE
flags should not be mapped for the time of any call to vkQueueSubmit()
or vkQueuePresent()
. Although legal, that would cause performance degradation because WDDM migrates such memory to system RAM. To ensure this, you can unmap all persistently mapped memory using just one function call. For details, see function vmaUnmapPersistentlyMappedMemory(), vmaMapPersistentlyMappedMemory().
Memory in Vulkan doesn't need to be unmapped before using it e.g. for transfers, but if you are not sure whether it's HOST_COHERENT
(here is surely is because it's created with VMA_MEMORY_USAGE_CPU_ONLY
), you should check it. If it's not, you should call vkInvalidateMappedMemoryRanges()
before reading and vkFlushMappedMemoryRanges()
after writing to mapped memory on CPU. Example:
On AMD GPUs on Windows, Vulkan memory from the type that has both DEVICE_LOCAL
and HOST_VISIBLE
flags should not be mapped for the time of any call to vkQueueSubmit()
or vkQueuePresent()
. Although legal, that would cause performance degradation because WDDM migrates such memory to system RAM. To ensure this, you can unmap all persistently mapped memory using just one function call. For details, see function vmaUnmapPersistentlyMappedMemory(), vmaMapPersistentlyMappedMemory().
#define VMA_IMPLEMENTATION -#include "vk_mem_alloc.h" -
At program startup:
+At program startup:
VkPhysicalDevice
and VkDevice
object.VmaAllocator
object by calling vmaCreateAllocator().VmaAllocatorCreateInfo allocatorInfo = {}; -allocatorInfo.physicalDevice = physicalDevice; -allocatorInfo.device = device; - -VmaAllocator allocator; -vmaCreateAllocator(&allocatorInfo, &allocator); -
When you want to create a buffer or image:
+When you want to create a buffer or image:
VkBufferCreateInfo
/ VkImageCreateInfo
structure.VkBuffer
/VkImage
with memory already allocated and bound to it.VkBufferCreateInfo bufferInfo = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO }; -bufferInfo.size = 65536; -bufferInfo.usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT; - -VmaAllocationCreateInfo allocInfo = {}; -allocInfo.usage = VMA_MEMORY_USAGE_GPU_ONLY; - -VkBuffer buffer; -VmaAllocation allocation; -vmaCreateBuffer(allocator, &bufferInfo, &allocInfo, &buffer, &allocation, nullptr); -
Don't forget to destroy your objects when no longer needed:
-vmaDestroyBuffer(allocator, buffer, allocation); -vmaDestroyAllocator(allocator);+
Don't forget to destroy your objects when no longer needed:
+The function also frees empty VkDeviceMemory
blocks.
After allocation has been moved, its VmaAllocationInfo::deviceMemory and/or VmaAllocationInfo::offset changes. You must query them again using vmaGetAllocationInfo() if you need them.
If an allocation has been moved, data in memory is copied to new place automatically, but if it was bound to a buffer or an image, you must destroy that object yourself, create new one and bind it to the new memory pointed by the allocation. You must use vkDestroyBuffer()
, vkDestroyImage()
, vkCreateBuffer()
, vkCreateImage()
for that purpose and NOT vmaDestroyBuffer(), vmaDestroyImage(), vmaCreateBuffer(), vmaCreateImage()! Example:
VkDevice device = ...; -VmaAllocator allocator = ...; -std::vector<VkBuffer> buffers = ...; -std::vector<VmaAllocation> allocations = ...; - -std::vector<VkBool32> allocationsChanged(allocations.size()); -vmaDefragment(allocator, allocations.data(), allocations.size(), allocationsChanged.data(), nullptr, nullptr); - -for(size_t i = 0; i < allocations.size(); ++i) -{ - if(allocationsChanged[i]) - { - VmaAllocationInfo allocInfo; - vmaGetAllocationInfo(allocator, allocations[i], &allocInfo); - - vkDestroyBuffer(device, buffers[i], nullptr); - - VkBufferCreateInfo bufferInfo = ...; - vkCreateBuffer(device, &bufferInfo, nullptr, &buffers[i]); - - .// You can make dummy call to vkGetBufferMemoryRequirements here to silence validation layer warning. - - vkBindBufferMemory(device, buffers[i], allocInfo.deviceMemory, allocInfo.offset); - } -} -
This function may be time-consuming, so you shouldn't call it too often (like every frame or after every resource creation/destruction), but rater you can call it on special occasions (like when reloading a game level, when you just destroyed a lot of objects).
+This function may be time-consuming, so you shouldn't call it too often (like every frame or after every resource creation/destruction), but rater you can call it on special occasions (like when reloading a game level, when you just destroyed a lot of objects).
@@ -1373,8 +1348,7 @@ for(size_t i = 0; i < allocations.size(); ++i)Destroys Vulkan buffer and frees allocated memory.
This is just a convenience function equivalent to:
-vkDestroyBuffer(device, buffer, allocationCallbacks); -vmaFreeMemory(allocator, allocation);+
Destroys Vulkan image and frees allocated memory.
This is just a convenience function equivalent to:
-vkDestroyImage(device, image, allocationCallbacks); -vmaFreeMemory(allocator, allocation);+
Unmaps persistently mapped memory of types that are HOST_COHERENT
and DEVICE_LOCAL
.
This is optional performance optimization. On AMD GPUs on Windows, Vulkan memory from the type that has both DEVICE_LOCAL
and HOST_VISIBLE
flags should not be mapped for the time of any call to vkQueueSubmit()
or vkQueuePresent()
. Although legal, that would cause performance degradation because WDDM migrates such memory to system RAM. To ensure this, you can unmap all persistently mapped memory using this function. Example:
vmaUnmapPersistentlyMappedMemory(allocator); -vkQueueSubmit(...) -vmaMapPersistentlyMappedMemory(allocator); -
After this call VmaAllocationInfo::pMappedData of some allocations may become null.
+After this call VmaAllocationInfo::pMappedData of some allocations may become null.
This call is reference-counted. Memory is mapped again after you call vmaMapPersistentlyMappedMemory() same number of times that you called vmaUnmapPersistentlyMappedMemory().
diff --git a/docs/html/vk__mem__alloc_8h_source.html b/docs/html/vk__mem__alloc_8h_source.html index d06c214..211939f 100644 --- a/docs/html/vk__mem__alloc_8h_source.html +++ b/docs/html/vk__mem__alloc_8h_source.html @@ -62,156 +62,156 @@ $(function() {