mirror of
https://github.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator.git
synced 2025-05-30 08:27:44 +00:00
Added functions vmaCopyMemoryToAllocation, vmaCopyAllocationToMemory
Few other minor fixes and improvements. Regenerated documentation.
This commit is contained in:
parent
484f40312f
commit
b5456bb4e5
190 changed files with 3464 additions and 5181 deletions
|
@ -49,6 +49,7 @@ See also: [product page on GPUOpen](https://gpuopen.com/gaming-product/vulkan-me
|
|||
- [Custom memory pools](@ref choosing_memory_type_custom_memory_pools)
|
||||
- [Dedicated allocations](@ref choosing_memory_type_dedicated_allocations)
|
||||
- \subpage memory_mapping
|
||||
- [Copy functions](@ref memory_mapping_copy_functions)
|
||||
- [Mapping functions](@ref memory_mapping_mapping_functions)
|
||||
- [Persistently mapped memory](@ref memory_mapping_persistently_mapped_memory)
|
||||
- [Cache flush and invalidate](@ref memory_mapping_cache_control)
|
||||
|
@ -2181,6 +2182,61 @@ VMA_CALL_PRE VkResult VMA_CALL_POST vmaInvalidateAllocations(
|
|||
const VkDeviceSize* VMA_NULLABLE VMA_LEN_IF_NOT_NULL(allocationCount) offsets,
|
||||
const VkDeviceSize* VMA_NULLABLE VMA_LEN_IF_NOT_NULL(allocationCount) sizes);
|
||||
|
||||
/** \brief Maps the allocation temporarily if needed, copies data from specified host pointer to it, and flushes the memory from the host caches if needed.
|
||||
|
||||
\param allocator
|
||||
\param pSrcHostPointer Pointer to the host data that become source of the copy.
|
||||
\param dstAllocation Handle to the allocation that becomes destination of the copy.
|
||||
\param dstAllocationLocalOffset Offset within `dstAllocation` where to write copied data, in bytes.
|
||||
\param size Number of bytes to copy.
|
||||
|
||||
This is a convenience function that allows to copy data from a host pointer to an allocation easily.
|
||||
Same behavior can be achieved by calling vmaMapMemory(), `memcpy()`, vmaUnmapMemory(), vmaFlushAllocation().
|
||||
|
||||
This function can be called only for allocations created in a memory type that has `VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT` flag.
|
||||
It can be ensured e.g. by using #VMA_MEMORY_USAGE_AUTO and #VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT or
|
||||
#VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT.
|
||||
Otherwise, the function will fail and generate a Validation Layers error.
|
||||
|
||||
`dstAllocationLocalOffset` is relative to the contents of given `dstAllocation`.
|
||||
If you mean whole allocation, you should pass 0.
|
||||
Do not pass allocation's offset within device memory block this parameter!
|
||||
*/
|
||||
VMA_CALL_PRE VkResult VMA_CALL_POST vmaCopyMemoryToAllocation(
|
||||
VmaAllocator VMA_NOT_NULL allocator,
|
||||
const void* VMA_NOT_NULL pSrcHostPointer,
|
||||
VmaAllocation VMA_NOT_NULL dstAllocation,
|
||||
VkDeviceSize dstAllocationLocalOffset,
|
||||
VkDeviceSize size);
|
||||
|
||||
/** \brief Invalidates memory in the host caches if needed, maps the allocation temporarily if needed, and copies data from it to a specified host pointer.
|
||||
|
||||
\param allocator
|
||||
\param srcAllocation Handle to the allocation that becomes source of the copy.
|
||||
\param srcAllocationLocalOffset Offset within `srcAllocation` where to read copied data, in bytes.
|
||||
\param pDstHostPointer Pointer to the host memory that become destination of the copy.
|
||||
\param size Number of bytes to copy.
|
||||
|
||||
This is a convenience function that allows to copy data from an allocation to a host pointer easily.
|
||||
Same behavior can be achieved by calling vmaInvalidateAllocation(), vmaMapMemory(), `memcpy()`, vmaUnmapMemory().
|
||||
|
||||
This function should be called only for allocations created in a memory type that has `VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT`
|
||||
and `VK_MEMORY_PROPERTY_HOST_CACHED_BIT` flag.
|
||||
It can be ensured e.g. by using #VMA_MEMORY_USAGE_AUTO and #VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT.
|
||||
Otherwise, the function may fail and generate a Validation Layers error.
|
||||
It may also work very slowly when reading from an uncached memory.
|
||||
|
||||
`srcAllocationLocalOffset` is relative to the contents of given `srcAllocation`.
|
||||
If you mean whole allocation, you should pass 0.
|
||||
Do not pass allocation's offset within device memory block as this parameter!
|
||||
*/
|
||||
VMA_CALL_PRE VkResult VMA_CALL_POST vmaCopyAllocationToMemory(
|
||||
VmaAllocator VMA_NOT_NULL allocator,
|
||||
VmaAllocation VMA_NOT_NULL srcAllocation,
|
||||
VkDeviceSize srcAllocationLocalOffset,
|
||||
void* VMA_NOT_NULL pDstHostPointer,
|
||||
VkDeviceSize size);
|
||||
|
||||
/** \brief Checks magic number in margins around all allocations in given memory types (in both default and custom pools) in search for corruptions.
|
||||
|
||||
\param allocator
|
||||
|
@ -4136,7 +4192,7 @@ public:
|
|||
--(*m_Atomic);
|
||||
}
|
||||
|
||||
void Commit() { m_Atomic = nullptr; }
|
||||
void Commit() { m_Atomic = VMA_NULL; }
|
||||
T Increment(AtomicT* atomic)
|
||||
{
|
||||
m_Atomic = atomic;
|
||||
|
@ -4144,7 +4200,7 @@ public:
|
|||
}
|
||||
|
||||
private:
|
||||
AtomicT* m_Atomic = nullptr;
|
||||
AtomicT* m_Atomic = VMA_NULL;
|
||||
};
|
||||
#endif // _VMA_ATOMIC_TRANSACTIONAL_INCREMENT
|
||||
|
||||
|
@ -6210,7 +6266,7 @@ bool VmaDedicatedAllocationList::Validate()
|
|||
|
||||
void VmaDedicatedAllocationList::AddDetailedStatistics(VmaDetailedStatistics& inoutStats)
|
||||
{
|
||||
for(auto* item = m_AllocationList.Front(); item != nullptr; item = DedicatedAllocationLinkedList::GetNext(item))
|
||||
for(auto* item = m_AllocationList.Front(); item != VMA_NULL; item = DedicatedAllocationLinkedList::GetNext(item))
|
||||
{
|
||||
const VkDeviceSize size = item->GetSize();
|
||||
inoutStats.statistics.blockCount++;
|
||||
|
@ -6227,7 +6283,7 @@ void VmaDedicatedAllocationList::AddStatistics(VmaStatistics& inoutStats)
|
|||
inoutStats.blockCount += allocCount;
|
||||
inoutStats.allocationCount += allocCount;
|
||||
|
||||
for(auto* item = m_AllocationList.Front(); item != nullptr; item = DedicatedAllocationLinkedList::GetNext(item))
|
||||
for(auto* item = m_AllocationList.Front(); item != VMA_NULL; item = DedicatedAllocationLinkedList::GetNext(item))
|
||||
{
|
||||
const VkDeviceSize size = item->GetSize();
|
||||
inoutStats.blockBytes += size;
|
||||
|
@ -10078,6 +10134,17 @@ public:
|
|||
const VkDeviceSize* offsets, const VkDeviceSize* sizes,
|
||||
VMA_CACHE_OPERATION op);
|
||||
|
||||
VkResult CopyMemoryToAllocation(
|
||||
const void* pSrcHostPointer,
|
||||
VmaAllocation dstAllocation,
|
||||
VkDeviceSize dstAllocationLocalOffset,
|
||||
VkDeviceSize size);
|
||||
VkResult CopyAllocationToMemory(
|
||||
VmaAllocation srcAllocation,
|
||||
VkDeviceSize srcAllocationLocalOffset,
|
||||
void* pDstHostPointer,
|
||||
VkDeviceSize size);
|
||||
|
||||
void FillAllocation(const VmaAllocation hAllocation, uint8_t pattern);
|
||||
|
||||
/*
|
||||
|
@ -10177,7 +10244,7 @@ private:
|
|||
VkFlags dedicatedBufferImageUsage,
|
||||
size_t allocationCount,
|
||||
VmaAllocation* pAllocations,
|
||||
const void* pNextChain = nullptr);
|
||||
const void* pNextChain = VMA_NULL);
|
||||
|
||||
void FreeDedicatedMemory(const VmaAllocation allocation);
|
||||
|
||||
|
@ -10352,7 +10419,7 @@ bool VmaDeviceMemoryBlock::Validate() const
|
|||
|
||||
VkResult VmaDeviceMemoryBlock::CheckCorruption(VmaAllocator hAllocator)
|
||||
{
|
||||
void* pData = nullptr;
|
||||
void* pData = VMA_NULL;
|
||||
VkResult res = Map(hAllocator, 1, &pData);
|
||||
if (res != VK_SUCCESS)
|
||||
{
|
||||
|
@ -14304,6 +14371,43 @@ VkResult VmaAllocator_T::FlushOrInvalidateAllocations(
|
|||
return res;
|
||||
}
|
||||
|
||||
VkResult VmaAllocator_T::CopyMemoryToAllocation(
|
||||
const void* pSrcHostPointer,
|
||||
VmaAllocation dstAllocation,
|
||||
VkDeviceSize dstAllocationLocalOffset,
|
||||
VkDeviceSize size)
|
||||
{
|
||||
void* dstMappedData = VMA_NULL;
|
||||
VkResult res = Map(dstAllocation, &dstMappedData);
|
||||
if(res == VK_SUCCESS)
|
||||
{
|
||||
memcpy((char*)dstMappedData + dstAllocationLocalOffset, pSrcHostPointer, (size_t)size);
|
||||
Unmap(dstAllocation);
|
||||
res = FlushOrInvalidateAllocation(dstAllocation, dstAllocationLocalOffset, size, VMA_CACHE_FLUSH);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
VkResult VmaAllocator_T::CopyAllocationToMemory(
|
||||
VmaAllocation srcAllocation,
|
||||
VkDeviceSize srcAllocationLocalOffset,
|
||||
void* pDstHostPointer,
|
||||
VkDeviceSize size)
|
||||
{
|
||||
void* srcMappedData = VMA_NULL;
|
||||
VkResult res = Map(srcAllocation, &srcMappedData);
|
||||
if(res == VK_SUCCESS)
|
||||
{
|
||||
res = FlushOrInvalidateAllocation(srcAllocation, srcAllocationLocalOffset, size, VMA_CACHE_INVALIDATE);
|
||||
if(res == VK_SUCCESS)
|
||||
{
|
||||
memcpy(pDstHostPointer, (const char*)srcMappedData + srcAllocationLocalOffset, (size_t)size);
|
||||
Unmap(srcAllocation);
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
void VmaAllocator_T::FreeDedicatedMemory(const VmaAllocation allocation)
|
||||
{
|
||||
VMA_ASSERT(allocation && allocation->GetType() == VmaAllocation_T::ALLOCATION_TYPE_DEDICATED);
|
||||
|
@ -15405,9 +15509,7 @@ VMA_CALL_PRE VkResult VMA_CALL_POST vmaFlushAllocation(
|
|||
|
||||
VMA_DEBUG_GLOBAL_MUTEX_LOCK
|
||||
|
||||
const VkResult res = allocator->FlushOrInvalidateAllocation(allocation, offset, size, VMA_CACHE_FLUSH);
|
||||
|
||||
return res;
|
||||
return allocator->FlushOrInvalidateAllocation(allocation, offset, size, VMA_CACHE_FLUSH);
|
||||
}
|
||||
|
||||
VMA_CALL_PRE VkResult VMA_CALL_POST vmaInvalidateAllocation(
|
||||
|
@ -15422,9 +15524,7 @@ VMA_CALL_PRE VkResult VMA_CALL_POST vmaInvalidateAllocation(
|
|||
|
||||
VMA_DEBUG_GLOBAL_MUTEX_LOCK
|
||||
|
||||
const VkResult res = allocator->FlushOrInvalidateAllocation(allocation, offset, size, VMA_CACHE_INVALIDATE);
|
||||
|
||||
return res;
|
||||
return allocator->FlushOrInvalidateAllocation(allocation, offset, size, VMA_CACHE_INVALIDATE);
|
||||
}
|
||||
|
||||
VMA_CALL_PRE VkResult VMA_CALL_POST vmaFlushAllocations(
|
||||
|
@ -15447,9 +15547,7 @@ VMA_CALL_PRE VkResult VMA_CALL_POST vmaFlushAllocations(
|
|||
|
||||
VMA_DEBUG_GLOBAL_MUTEX_LOCK
|
||||
|
||||
const VkResult res = allocator->FlushOrInvalidateAllocations(allocationCount, allocations, offsets, sizes, VMA_CACHE_FLUSH);
|
||||
|
||||
return res;
|
||||
return allocator->FlushOrInvalidateAllocations(allocationCount, allocations, offsets, sizes, VMA_CACHE_FLUSH);
|
||||
}
|
||||
|
||||
VMA_CALL_PRE VkResult VMA_CALL_POST vmaInvalidateAllocations(
|
||||
|
@ -15472,9 +15570,49 @@ VMA_CALL_PRE VkResult VMA_CALL_POST vmaInvalidateAllocations(
|
|||
|
||||
VMA_DEBUG_GLOBAL_MUTEX_LOCK
|
||||
|
||||
const VkResult res = allocator->FlushOrInvalidateAllocations(allocationCount, allocations, offsets, sizes, VMA_CACHE_INVALIDATE);
|
||||
return allocator->FlushOrInvalidateAllocations(allocationCount, allocations, offsets, sizes, VMA_CACHE_INVALIDATE);
|
||||
}
|
||||
|
||||
return res;
|
||||
VMA_CALL_PRE VkResult VMA_CALL_POST vmaCopyMemoryToAllocation(
|
||||
VmaAllocator allocator,
|
||||
const void* pSrcHostPointer,
|
||||
VmaAllocation dstAllocation,
|
||||
VkDeviceSize dstAllocationLocalOffset,
|
||||
VkDeviceSize size)
|
||||
{
|
||||
VMA_ASSERT(allocator && pSrcHostPointer && dstAllocation);
|
||||
|
||||
if(size == 0)
|
||||
{
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
|
||||
VMA_DEBUG_LOG("vmaCopyMemoryToAllocation");
|
||||
|
||||
VMA_DEBUG_GLOBAL_MUTEX_LOCK
|
||||
|
||||
return allocator->CopyMemoryToAllocation(pSrcHostPointer, dstAllocation, dstAllocationLocalOffset, size);
|
||||
}
|
||||
|
||||
VMA_CALL_PRE VkResult VMA_CALL_POST vmaCopyAllocationToMemory(
|
||||
VmaAllocator allocator,
|
||||
VmaAllocation srcAllocation,
|
||||
VkDeviceSize srcAllocationLocalOffset,
|
||||
void* pDstHostPointer,
|
||||
VkDeviceSize size)
|
||||
{
|
||||
VMA_ASSERT(allocator && srcAllocation && pDstHostPointer);
|
||||
|
||||
if(size == 0)
|
||||
{
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
|
||||
VMA_DEBUG_LOG("vmaCopyAllocationToMemory");
|
||||
|
||||
VMA_DEBUG_GLOBAL_MUTEX_LOCK
|
||||
|
||||
return allocator->CopyAllocationToMemory(srcAllocation, srcAllocationLocalOffset, pDstHostPointer, size);
|
||||
}
|
||||
|
||||
VMA_CALL_PRE VkResult VMA_CALL_POST vmaCheckCorruption(
|
||||
|
@ -16602,6 +16740,7 @@ You can use them directly with memory allocated by this library,
|
|||
but it is not recommended because of following issue:
|
||||
Mapping the same `VkDeviceMemory` block multiple times is illegal - only one mapping at a time is allowed.
|
||||
This includes mapping disjoint regions. Mapping is not reference-counted internally by Vulkan.
|
||||
It is also not thread-safe.
|
||||
Because of this, Vulkan Memory Allocator provides following facilities:
|
||||
|
||||
\note If you want to be able to map an allocation, you need to specify one of the flags
|
||||
|
@ -16609,11 +16748,44 @@ Because of this, Vulkan Memory Allocator provides following facilities:
|
|||
in VmaAllocationCreateInfo::flags. These flags are required for an allocation to be mappable
|
||||
when using #VMA_MEMORY_USAGE_AUTO or other `VMA_MEMORY_USAGE_AUTO*` enum values.
|
||||
For other usage values they are ignored and every such allocation made in `HOST_VISIBLE` memory type is mappable,
|
||||
but they can still be used for consistency.
|
||||
but these flags can still be used for consistency.
|
||||
|
||||
\section memory_mapping_copy_functions Copy functions
|
||||
|
||||
The easiest way to copy data from a host pointer to an allocation is to use convenience function vmaCopyMemoryToAllocation().
|
||||
It automatically maps the Vulkan memory temporarily (if not already mapped), performs `memcpy`,
|
||||
and calls `vkFlushMappedMemoryRanges` (if required - if memory type is not `HOST_COHERENT`).
|
||||
|
||||
It is also the safest one, because using `memcpy` avoids a risk of accidentally introducing memory reads
|
||||
(e.g. by doing `pMappedVectors[i] += v`), which may be very slow on memory types that are not `HOST_CACHED`.
|
||||
|
||||
\code
|
||||
struct ConstantBuffer
|
||||
{
|
||||
...
|
||||
};
|
||||
ConstantBuffer constantBufferData = ...
|
||||
|
||||
VkBufferCreateInfo bufCreateInfo = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO };
|
||||
bufCreateInfo.size = sizeof(ConstantBuffer);
|
||||
bufCreateInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
|
||||
|
||||
VmaAllocationCreateInfo allocCreateInfo = {};
|
||||
allocCreateInfo.usage = VMA_MEMORY_USAGE_AUTO;
|
||||
allocCreateInfo.flags = VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT;
|
||||
|
||||
VkBuffer buf;
|
||||
VmaAllocation alloc;
|
||||
vmaCreateBuffer(allocator, &bufCreateInfo, &allocCreateInfo, &buf, &alloc, nullptr);
|
||||
|
||||
vmaCopyMemoryToAllocation(allocator, &constantBufferData, alloc, 0, sizeof(ConstantBuffer));
|
||||
\endcode
|
||||
|
||||
Copy in the other direction - from an allocation to a host pointer can be performed the same way using function vmaCopyAllocationToMemory().
|
||||
|
||||
\section memory_mapping_mapping_functions Mapping functions
|
||||
|
||||
The library provides following functions for mapping of a specific #VmaAllocation: vmaMapMemory(), vmaUnmapMemory().
|
||||
The library provides following functions for mapping of a specific allocation: vmaMapMemory(), vmaUnmapMemory().
|
||||
They are safer and more convenient to use than standard Vulkan functions.
|
||||
You can map an allocation multiple times simultaneously - mapping is reference-counted internally.
|
||||
You can also map different allocations simultaneously regardless of whether they use the same `VkDeviceMemory` block.
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue