diff --git a/docs/html/annotated.html b/docs/html/annotated.html index 3e5adda..20a707d 100644 --- a/docs/html/annotated.html +++ b/docs/html/annotated.html @@ -64,10 +64,14 @@ $(function() {
Here are the classes, structs, unions and interfaces with brief descriptions:
- - - - + + + + + + + +
 CVmaAllocatorCreateInfoDescription of a Allocator to be created
 CVmaMemoryRequirements
 CVmaStatInfo
 CVmaStatsGeneral statistics from current state of Allocator
 CVmaAllocationInfoParameters of VmaAllocation objects, that can be retrieved using function vmaGetAllocationInfo()
 CVmaAllocatorCreateInfoDescription of a Allocator to be created
 CVmaDefragmentationInfoOptional configuration parameters to be passed to function vmaDefragment()
 CVmaDefragmentationStatsStatistics returned by function vmaDefragment()
 CVmaDeviceMemoryCallbacksSet of callbacks that the library will call for vkAllocateMemory and vkFreeMemory
 CVmaMemoryRequirements
 CVmaStatInfo
 CVmaStatsGeneral statistics from current state of Allocator
diff --git a/docs/html/classes.html b/docs/html/classes.html index fb0f1ec..67a1270 100644 --- a/docs/html/classes.html +++ b/docs/html/classes.html @@ -65,10 +65,10 @@ $(function() {
v
- - - + + + +
  v  
-
VmaMemoryRequirements   VmaStats   
VmaStatInfo   
VmaAllocatorCreateInfo   
VmaAllocatorCreateInfo   VmaDefragmentationStats   VmaMemoryRequirements   VmaStats   
VmaDefragmentationInfo   VmaDeviceMemoryCallbacks   VmaStatInfo   
VmaAllocationInfo   
v
diff --git a/docs/html/functions.html b/docs/html/functions.html index 89c1389..a924d1f 100644 --- a/docs/html/functions.html +++ b/docs/html/functions.html @@ -58,31 +58,92 @@ $(function() {
-
Here is a list of all class members with links to the classes they belong to:
+ + +

◆ VmaAllocatorFlagBits

+ +
+
+ + + + +
typedef enum VmaAllocatorFlagBits VmaAllocatorFlagBits
+
+ +

Flags for created VmaAllocator.

+ +
+
+ +

◆ VmaAllocatorFlags

+ +
+
+ + + + +
typedef VkFlags VmaAllocatorFlags
+
+ +
+
+ +

◆ VmaDeviceMemoryCallbacks

+ +
+
+ + + + +
typedef struct VmaDeviceMemoryCallbacks VmaDeviceMemoryCallbacks
+
+ +

Set of callbacks that the library will call for vkAllocateMemory and vkFreeMemory.

+

Provided for informative purpose, e.g. to gather statistics about number of allocations or total amount of memory allocated in Vulkan.

+
@@ -161,6 +266,29 @@ Functions
+
+ +

Enumeration Type Documentation

+ +

◆ VmaAllocatorFlagBits

+ +
+
+ + + + +
enum VmaAllocatorFlagBits
+
+ +

Flags for created VmaAllocator.

+ + + +
Enumerator
VMA_ALLOCATOR_EXTERNALLY_SYNCHRONIZED_BIT 

Allocator and all objects created from it will not be synchronized internally, so you must guarantee they are used from only one thread at a time or synchronized externally by you.

+

Using this flag may increase performance because internal mutexes are not used.

+
VMA_ALLOCATOR_FLAG_BITS_MAX_ENUM 
+

Function Documentation

diff --git a/docs/html/group__layer1.html b/docs/html/group__layer1.html index b27b4a0..a1f5fc5 100644 --- a/docs/html/group__layer1.html +++ b/docs/html/group__layer1.html @@ -77,6 +77,11 @@ Classes Typedefs typedef enum VmaMemoryUsage VmaMemoryUsage   +typedef enum VmaMemoryRequirementFlagBits VmaMemoryRequirementFlagBits + Flags to be passed as VmaMemoryRequirements::flags. More...
+  +typedef VkFlags VmaMemoryRequirementFlags +  typedef struct VmaMemoryRequirements VmaMemoryRequirements   @@ -93,6 +98,13 @@ Enumerations
} + + +
 
enum  VmaMemoryRequirementFlagBits { VMA_MEMORY_REQUIREMENT_OWN_MEMORY_BIT = 0x00000001, +VMA_MEMORY_REQUIREMENT_NEVER_ALLOCATE_BIT = 0x00000002, +VMA_MEMORY_REQUIREMENT_PERSISTENT_MAP_BIT = 0x00000004, +VMA_MEMORY_REQUIREMENT_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF + }
 Flags to be passed as VmaMemoryRequirements::flags. More...
 
@@ -101,6 +113,36 @@ Functions

Functions

Detailed Description

Typedef Documentation

+ +

◆ VmaMemoryRequirementFlagBits

+ +
+
+ + + + +
typedef enum VmaMemoryRequirementFlagBits VmaMemoryRequirementFlagBits
+
+ +

Flags to be passed as VmaMemoryRequirements::flags.

+ +
+
+ +

◆ VmaMemoryRequirementFlags

+ +
+
+ + + + +
typedef VkFlags VmaMemoryRequirementFlags
+
+ +
+

◆ VmaMemoryRequirements

@@ -130,6 +172,36 @@ Functions

Enumeration Type Documentation

+ +

◆ VmaMemoryRequirementFlagBits

+ +
+
+ + + + +
enum VmaMemoryRequirementFlagBits
+
+ +

Flags to be passed as VmaMemoryRequirements::flags.

+ + + + + +
Enumerator
VMA_MEMORY_REQUIREMENT_OWN_MEMORY_BIT 

Set this flag if the allocation should have its own memory block.

+

Use it for special, big resources, like fullscreen images used as attachments.

+

This flag must also be used for host visible resources that you want to map simultaneously because otherwise they might end up as regions of the same VkDeviceMemory, while mapping same VkDeviceMemory multiple times is illegal.

+
VMA_MEMORY_REQUIREMENT_NEVER_ALLOCATE_BIT 

Set this flag to only try to allocate from existing VkDeviceMemory blocks and never create new such block.

+

If new allocation cannot be placed in any of the existing blocks, allocation fails with VK_ERROR_OUT_OF_DEVICE_MEMORY error.

+

It makes no sense to set VMA_MEMORY_REQUIREMENT_OWN_MEMORY_BIT and VMA_MEMORY_REQUIREMENT_NEVER_ALLOCATE_BIT at the same time.

+
VMA_MEMORY_REQUIREMENT_PERSISTENT_MAP_BIT 

Set to use a memory that will be persistently mapped and retrieve pointer to it.

+

Pointer to mapped memory will be returned through ppMappedData. You cannot map the memory on your own as multiple maps of a single VkDeviceMemory are illegal.

+
VMA_MEMORY_REQUIREMENT_FLAG_BITS_MAX_ENUM 
+ +
+

◆ VmaMemoryUsage

@@ -147,10 +219,13 @@ Functions VMA_MEMORY_USAGE_GPU_ONLY 

Memory will be used on device only, no need to be mapped on host.

VMA_MEMORY_USAGE_CPU_ONLY 

Memory will be mapped on host. Could be used for transfer to device.

+

Guarantees to be HOST_VISIBLE and HOST_COHERENT.

VMA_MEMORY_USAGE_CPU_TO_GPU 

Memory will be used for frequent (dynamic) updates from host and reads on device.

+

Guarantees to be HOST_VISIBLE.

VMA_MEMORY_USAGE_GPU_TO_CPU 

Memory will be used for writing on device and readback on host.

+

Guarantees to be HOST_VISIBLE.

VMA_MEMORY_USAGE_MAX_ENUM  diff --git a/docs/html/group__layer2.html b/docs/html/group__layer2.html index 18ab2b6..c03ac57 100644 --- a/docs/html/group__layer2.html +++ b/docs/html/group__layer2.html @@ -59,34 +59,124 @@ $(function() {
+Classes | +Typedefs | Functions
Layer 2 Allocating Memory
+ + + + + + + + + + +

+Classes

struct  VmaAllocationInfo
 Parameters of VmaAllocation objects, that can be retrieved using function vmaGetAllocationInfo(). More...
 
struct  VmaDefragmentationInfo
 Optional configuration parameters to be passed to function vmaDefragment(). More...
 
struct  VmaDefragmentationStats
 Statistics returned by function vmaDefragment(). More...
 
+ + + + + + + + + + +

+Typedefs

typedef struct VmaAllocationInfo VmaAllocationInfo
 Parameters of VmaAllocation objects, that can be retrieved using function vmaGetAllocationInfo(). More...
 
typedef struct VmaDefragmentationInfo VmaDefragmentationInfo
 Optional configuration parameters to be passed to function vmaDefragment(). More...
 
typedef struct VmaDefragmentationStats VmaDefragmentationStats
 Statistics returned by function vmaDefragment(). More...
 
- - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Functions

VkResult vmaAllocateMemory (VmaAllocator allocator, const VkMemoryRequirements *pVkMemoryRequirements, const VmaMemoryRequirements *pVmaMemoryRequirements, VkMappedMemoryRange *pMemory, uint32_t *pMemoryTypeIndex)
 General purpose memory allocation. More...
 
VkResult vmaAllocateMemoryForBuffer (VmaAllocator allocator, VkBuffer buffer, const VmaMemoryRequirements *pMemoryRequirements, VkMappedMemoryRange *pMemory, uint32_t *pMemoryTypeIndex)
 
VkResult vmaAllocateMemoryForImage (VmaAllocator allocator, VkImage image, const VmaMemoryRequirements *pMemoryRequirements, VkMappedMemoryRange *pMemory, uint32_t *pMemoryTypeIndex)
 Function similar to vmaAllocateMemoryForBuffer(). More...
 
void vmaFreeMemory (VmaAllocator allocator, const VkMappedMemoryRange *pMemory)
 Frees memory previously allocated using vmaAllocateMemoryForBuffer() or vmaAllocateMemoryForImage(). More...
 
VkResult vmaMapMemory (VmaAllocator allocator, const VkMappedMemoryRange *pMemory, void **ppData)
 
void vmaUnmapMemory (VmaAllocator allocator, const VkMappedMemoryRange *pMemory)
 
VkResult vmaAllocateMemory (VmaAllocator allocator, const VkMemoryRequirements *pVkMemoryRequirements, const VmaMemoryRequirements *pVmaMemoryRequirements, VmaAllocation *pAllocation, VmaAllocationInfo *pAllocationInfo)
 General purpose memory allocation. More...
 
VkResult vmaAllocateMemoryForBuffer (VmaAllocator allocator, VkBuffer buffer, const VmaMemoryRequirements *pMemoryRequirements, VmaAllocation *pAllocation, VmaAllocationInfo *pAllocationInfo)
 
VkResult vmaAllocateMemoryForImage (VmaAllocator allocator, VkImage image, const VmaMemoryRequirements *pMemoryRequirements, VmaAllocation *pAllocation, VmaAllocationInfo *pAllocationInfo)
 Function similar to vmaAllocateMemoryForBuffer(). More...
 
void vmaFreeMemory (VmaAllocator allocator, VmaAllocation allocation)
 Frees memory previously allocated using vmaAllocateMemory(), vmaAllocateMemoryForBuffer(), or vmaAllocateMemoryForImage(). More...
 
void vmaGetAllocationInfo (VmaAllocator allocator, VmaAllocation allocation, VmaAllocationInfo *pAllocationInfo)
 Returns current information about specified allocation. More...
 
void vmaSetAllocationUserData (VmaAllocator allocator, VmaAllocation allocation, void *pUserData)
 Sets pUserData in given allocation to new value. More...
 
VkResult vmaMapMemory (VmaAllocator allocator, VmaAllocation allocation, void **ppData)
 
void vmaUnmapMemory (VmaAllocator allocator, VmaAllocation allocation)
 
void vmaUnmapPersistentlyMappedMemory (VmaAllocator allocator)
 Unmaps persistently mapped memory of types that is HOST_COHERENT and DEVICE_LOCAL. More...
 
VkResult vmaMapPersistentlyMappedMemory (VmaAllocator allocator)
 Maps back persistently mapped memory of types that is HOST_COHERENT and DEVICE_LOCAL. More...
 
VkResult vmaDefragment (VmaAllocator allocator, VmaAllocation *pAllocations, size_t allocationCount, VkBool32 *pAllocationsChanged, const VmaDefragmentationInfo *pDefragmentationInfo, VmaDefragmentationStats *pDefragmentationStats)
 Compacts memory by moving allocations. More...
 

Detailed Description

+

Typedef Documentation

+ +

◆ VmaAllocationInfo

+ +
+
+ + + + +
typedef struct VmaAllocationInfo VmaAllocationInfo
+
+ +

Parameters of VmaAllocation objects, that can be retrieved using function vmaGetAllocationInfo().

+ +
+
+ +

◆ VmaDefragmentationInfo

+ +
+
+ +

Optional configuration parameters to be passed to function vmaDefragment().

+ +
+
+ +

◆ VmaDefragmentationStats

+ +
+
+ +

Statistics returned by function vmaDefragment().

+ +
+

Function Documentation

- -

◆ vmaAllocateMemory()

+ +

◆ vmaAllocateMemory()

@@ -112,14 +202,14 @@ Functions - VkMappedMemoryRange *  - pMemory, + VmaAllocation *  + pAllocation, - uint32_t *  - pMemoryTypeIndex  + VmaAllocationInfo *  + pAllocationInfo  @@ -132,19 +222,18 @@ Functions

General purpose memory allocation.

Parameters
- - + +
[out]pMemoryAllocated memory.
[out]pMemoryTypeIndexOptional. Index of memory type that has been chosen for this allocation.
[out]pAllocationHandle to allocated memory.
[out]pAllocationInfoOptional. Information about allocated memory. It can be later fetched using function VmaGetAllocationInfo().
-

You should free the memory using vmaFreeMemory().

-

All allocated memory is also automatically freed in vmaDestroyAllocator().

-

It is recommended to use vmaAllocateMemoryForBuffer(), vmaAllocateMemoryForImage(), vmaCreateBuffer(), vmaCreateImage() instead whenever possible.

+

You should free the memory using vmaFreeMemory().

+

It is recommended to use vmaAllocateMemoryForBuffer(), vmaAllocateMemoryForImage(), vmaCreateBuffer(), vmaCreateImage() instead whenever possible.

- -

◆ vmaAllocateMemoryForBuffer()

+ +

◆ vmaAllocateMemoryForBuffer()

@@ -170,14 +259,14 @@ Functions - VkMappedMemoryRange *  - pMemory, + VmaAllocation *  + pAllocation, - uint32_t *  - pMemoryTypeIndex  + VmaAllocationInfo *  + pAllocationInfo  @@ -188,17 +277,17 @@ Functions
Parameters
- + +
[out]pMemoryTypeIndexOptional. Pass null if you don't need this information.
[out]pAllocationHandle to allocated memory.
[out]pAllocationInfoOptional. Information about allocated memory. It can be later fetched using function VmaGetAllocationInfo().
-

You should free the memory using vmaFreeMemory().

-

All allocated memory is also automatically freed in vmaDestroyAllocator().

+

You should free the memory using vmaFreeMemory().

- -

◆ vmaAllocateMemoryForImage()

+ +

◆ vmaAllocateMemoryForImage()

@@ -224,14 +313,14 @@ Functions - VkMappedMemoryRange *  - pMemory, + VmaAllocation *  + pAllocation, - uint32_t *  - pMemoryTypeIndex  + VmaAllocationInfo *  + pAllocationInfo  @@ -241,12 +330,113 @@ Functions
-

Function similar to vmaAllocateMemoryForBuffer().

+

Function similar to vmaAllocateMemoryForBuffer().

- -

◆ vmaFreeMemory()

+ +

◆ vmaDefragment()

+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
VkResult vmaDefragment (VmaAllocator allocator,
VmaAllocation * pAllocations,
size_t allocationCount,
VkBool32 * pAllocationsChanged,
const VmaDefragmentationInfopDefragmentationInfo,
VmaDefragmentationStatspDefragmentationStats 
)
+
+ +

Compacts memory by moving allocations.

+
Parameters
+ + + + + + +
pAllocationsArray of allocations that can be moved during this compation.
allocationCountNumber of elements in pAllocations and pAllocationsChanged arrays.
[out]pAllocationsChangedArray of boolean values that will indicate whether matching allocation in pAllocations array has been moved. This parameter is optional. Pass null if you don't need this information.
pDefragmentationInfoConfiguration parameters. Optional - pass null to use default values.
[out]pDefragmentationStatsStatistics returned by the function. Optional - pass null if you don't need this information.
+
+
+
Returns
VK_SUCCESS if completed, VK_INCOMPLETE if succeeded but didn't make all possible optimizations because limits specified in pDefragmentationInfo have been reached, negative error code in case of error.
+

This function works by moving allocations to different places (different VkDeviceMemory objects and/or different offsets) in order to optimize memory usage. Only allocations that are in pAllocations array can be moved. All other allocations are considered nonmovable in this call. Basic rules:

+
    +
  • Only allocations made in memory types that have VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT flag can be compacted. You may pass other allocations but it makes no sense - these will never be moved.
  • +
  • You may pass allocations made with VMA_MEMORY_REQUIREMENT_OWN_MEMORY_BIT but it makes no sense - they will never be moved.
  • +
  • Both allocations made with or without VMA_MEMORY_REQUIREMENT_PERSISTENT_MAP_BIT flag can be compacted. If not persistently mapped, memory will be mapped temporarily inside this function if needed, so it shouldn't be mapped by you for the time of this call.
  • +
  • You must not pass same VmaAllocation object multiple times in pAllocations array.
  • +
+

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).

+ +
+
+ +

◆ vmaFreeMemory()

@@ -260,8 +450,8 @@ Functions - const VkMappedMemoryRange *  - pMemory  + VmaAllocation  + allocation  @@ -271,12 +461,48 @@ Functions
-

Frees memory previously allocated using vmaAllocateMemoryForBuffer() or vmaAllocateMemoryForImage().

+

Frees memory previously allocated using vmaAllocateMemory(), vmaAllocateMemoryForBuffer(), or vmaAllocateMemoryForImage().

- -

◆ vmaMapMemory()

+ +

◆ vmaGetAllocationInfo()

+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + +
void vmaGetAllocationInfo (VmaAllocator allocator,
VmaAllocation allocation,
VmaAllocationInfopAllocationInfo 
)
+
+ +

Returns current information about specified allocation.

+ +
+
+ +

◆ vmaMapMemory()

@@ -290,8 +516,8 @@ Functions - const VkMappedMemoryRange *  - pMemory, + VmaAllocation  + allocation, @@ -306,12 +532,71 @@ Functions
-

Feel free to use vkMapMemory on these memory blocks on you own if you want, but just for convenience and to make sure correct offset and size is always specified, usage of vmaMapMemory() / vmaUnmapMemory() is recommended.

+

Feel free to use vkMapMemory on these memory blocks on you own if you want, but just for convenience and to make sure correct offset and size is always specified, usage of vmaMapMemory() / vmaUnmapMemory() is recommended.

+

Do not use it on memory allocated with VMA_MEMORY_REQUIREMENT_PERSISTENT_MAP_BIT as multiple maps to same VkDeviceMemory is illegal.

- -

◆ vmaUnmapMemory()

+ +

◆ vmaMapPersistentlyMappedMemory()

+ +
+
+ + + + + + + + +
VkResult vmaMapPersistentlyMappedMemory (VmaAllocator allocator)
+
+ +

Maps back persistently mapped memory of types that is HOST_COHERENT and DEVICE_LOCAL.

+

See vmaUnmapPersistentlyMappedMemory().

+

After this call VmaAllocationInfo::pMappedData of some allocation may have value different than before calling vmaUnmapPersistentlyMappedMemory().

+ +
+
+ +

◆ vmaSetAllocationUserData()

+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + +
void vmaSetAllocationUserData (VmaAllocator allocator,
VmaAllocation allocation,
void * pUserData 
)
+
+ +

Sets pUserData in given allocation to new value.

+ +
+
+ +

◆ vmaUnmapMemory()

@@ -325,8 +610,8 @@ Functions - const VkMappedMemoryRange *  - pMemory  + VmaAllocation  + allocation  @@ -336,6 +621,29 @@ Functions
+
+
+ +

◆ vmaUnmapPersistentlyMappedMemory()

+ +
+
+ + + + + + + + +
void vmaUnmapPersistentlyMappedMemory (VmaAllocator allocator)
+
+ +

Unmaps persistently mapped memory of types that is HOST_COHERENT and DEVICE_LOCAL.

+

This is optional performance optimization. You should call it on Windows for time of call to vkQueueSubmit and vkQueuePresent, for performance reasons, because of the internal behavior of WDDM.

+

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/group__layer3.html b/docs/html/group__layer3.html index 854b6e2..e7aa1f0 100644 --- a/docs/html/group__layer3.html +++ b/docs/html/group__layer3.html @@ -67,20 +67,20 @@ $(function() { - - - - - - - - - + + + + + + + + +

Functions

VkResult vmaCreateBuffer (VmaAllocator allocator, const VkBufferCreateInfo *pCreateInfo, const VmaMemoryRequirements *pMemoryRequirements, VkBuffer *pBuffer, VkMappedMemoryRange *pMemory, uint32_t *pMemoryTypeIndex)
 
void vmaDestroyBuffer (VmaAllocator allocator, VkBuffer buffer)
 
VkResult vmaCreateImage (VmaAllocator allocator, const VkImageCreateInfo *pCreateInfo, const VmaMemoryRequirements *pMemoryRequirements, VkImage *pImage, VkMappedMemoryRange *pMemory, uint32_t *pMemoryTypeIndex)
 Function similar to vmaCreateBuffer(). More...
 
void vmaDestroyImage (VmaAllocator allocator, VkImage image)
 
VkResult vmaCreateBuffer (VmaAllocator allocator, const VkBufferCreateInfo *pCreateInfo, const VmaMemoryRequirements *pMemoryRequirements, VkBuffer *pBuffer, VmaAllocation *pAllocation, VmaAllocationInfo *pAllocationInfo)
 
void vmaDestroyBuffer (VmaAllocator allocator, VkBuffer buffer, VmaAllocation allocation)
 
VkResult vmaCreateImage (VmaAllocator allocator, const VkImageCreateInfo *pCreateInfo, const VmaMemoryRequirements *pMemoryRequirements, VkImage *pImage, VmaAllocation *pAllocation, VmaAllocationInfo *pAllocationInfo)
 Function similar to vmaCreateBuffer(). More...
 
void vmaDestroyImage (VmaAllocator allocator, VkImage image, VmaAllocation allocation)
 

Detailed Description

Function Documentation

- -

◆ vmaCreateBuffer()

+ +

◆ vmaCreateBuffer()

@@ -112,14 +112,14 @@ Functions - VkMappedMemoryRange *  - pMemory, + VmaAllocation *  + pAllocation, - uint32_t *  - pMemoryTypeIndex  + VmaAllocationInfo *  + pAllocationInfo  @@ -130,8 +130,9 @@ Functions
Parameters
- - + + +
[out]pMemoryOptional. Pass null if you don't need this information.
[out]pMemoryTypeIndexOptional. Pass null if you don't need this information.
[out]pBufferBuffer that was created.
[out]pAllocationAllocation that was created.
[out]pAllocationInfoOptional. Information about allocated memory. It can be later fetched using function VmaGetAllocationInfo().
@@ -141,13 +142,12 @@ Functions
  • Allocates appropriate memory for it.
  • Binds the buffer/image with the memory.
  • -

    You do not (and should not) pass returned pMemory to vmaFreeMemory. Only calling vmaDestroyBuffer() / vmaDestroyImage() is required for objects created using vmaCreateBuffer() / vmaCreateImage().

    -

    All allocated buffers and images are also automatically destroyed in vmaDestroyAllocator(), along with their memory allocations.

    +

    You do not (and should not) pass returned pMemory to vmaFreeMemory. Only calling vmaDestroyBuffer() / vmaDestroyImage() is required for objects created using vmaCreateBuffer() / vmaCreateImage().

    - -

    ◆ vmaCreateImage()

    + +

    ◆ vmaCreateImage()

    @@ -179,14 +179,14 @@ Functions - VkMappedMemoryRange *  - pMemory, + VmaAllocation *  + pAllocation, - uint32_t *  - pMemoryTypeIndex  + VmaAllocationInfo *  + pAllocationInfo  @@ -196,12 +196,12 @@ Functions
    -

    Function similar to vmaCreateBuffer().

    +

    Function similar to vmaCreateBuffer().

    - -

    ◆ vmaDestroyBuffer()

    + +

    ◆ vmaDestroyBuffer()

    @@ -216,7 +216,13 @@ Functions VkBuffer  - buffer  + buffer, + + + + + VmaAllocation  + allocation  @@ -228,8 +234,8 @@ Functions
    - -

    ◆ vmaDestroyImage()

    + +

    ◆ vmaDestroyImage()

    @@ -244,7 +250,13 @@ Functions VkImage  - image  + image, + + + + + VmaAllocation  + allocation  diff --git a/docs/html/index.html b/docs/html/index.html index 69b9e9c..20a1a2b 100644 --- a/docs/html/index.html +++ b/docs/html/index.html @@ -62,7 +62,7 @@ $(function() {
    Vulkan Memory Allocator
    -

    Version 1.0.1 (2017-07-04)

    +

    Version 2.0.0-alpha.2 (2017-07-11)

    Members grouped: see Modules.

    All members: see vk_mem_alloc.h.

    @@ -72,7 +72,6 @@ Problem Statement

  • It requires a lot of boilerplate code, just like everything else in Vulkan, because it is a low-level and high-performance API.
  • There is additional level of indirection: VkDeviceMemory is allocated separately from creating VkBuffer/VkImage and they must be bound together. The binding cannot be changed later - resource must be recreated.
  • Driver must be queried for supported memory heaps and memory types. Different IHV-s provide different types of it.
  • -
  • Resources that don't fit in VRAM are not automatically evicted to RAM. Developer must handle out-of-memory errors on his own.
  • It is recommended practice to allocate bigger chunks of memory and assign parts of them to particular resources.
  • @@ -122,7 +121,7 @@ vmaCreateAllocator(&allocatorInfo, &allocator);
    1. Fill VkBufferCreateInfo / VkImageCreateInfo structure.
    2. Fill VmaMemoryRequirements structure.
    3. -
    4. Call vmaCreateBuffer() / vmaCreateImage() to get VkBuffer/VkImage with memory already allocated and bound to it.
    5. +
    6. Call vmaCreateBuffer() / vmaCreateImage() to get VkBuffer/VkImage with memory already allocated and bound to it.
    VkBufferCreateInfo bufferInfo = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO };
     bufferInfo.size = myBufferSize;
    @@ -132,9 +131,11 @@ VmaMemoryRequirements memReq = {};
     memReq.usage = VMA_MEMORY_USAGE_GPU_ONLY;
     
     VkBuffer buffer;
    -vmaCreateBuffer(allocator, &bufferInfo, &memReq, &buffer, nullptr, nullptr);
    -

    When no longer needed, destroy your buffer or image using vmaDestroyBuffer() / vmaDestroyImage(). This function would also free memory bound to it.

    -
    vmaDestroyBuffer(allocator, buffer);
    +VmaAllocation allocation;
    +vmaCreateBuffer(allocator, &bufferInfo, &memReq, &buffer, &allocation, nullptr);
    +

    Don't forget to destroy your objects:

    +
    vmaDestroyBuffer(allocator, buffer, allocation);
    +vmaDestroyAllocator(allocator);
     

    Configuration

    Please check "CONFIGURATION SECTION" in the code to find macros that you can define before each #include of this file or change directly in this file to provide your own implementation of basic facilities like assert, min and max functions, mutex etc. C++ STL is used by default, but changing these allows you to get rid of any STL usage if you want, as many game developers tend to do.

    @@ -145,7 +146,9 @@ Custom memory allocator Thread safety
    • The library has no global state, so separate VmaAllocator objects can be used independently.
    • -
    • All calls to functions that take VmaAllocator as first parameter are safe to call from multiple threads simultaneously because they are synchronized internally when needed.
    • +
    • By default, all calls to functions that take VmaAllocator as first parameter are safe to call from multiple threads simultaneously because they are synchronized internally when needed.
    • +
    • When the allocator is created with VMA_ALLOCATOR_EXTERNALLY_SYNCHRONIZED_BIT flag, calls to functions that take such VmaAllocator object must be synchronized externally.
    • +
    • Access to a VmaAllocation object must be externally synchronized. For example, you must not call vmaGetAllocationInfo() and vmaDefragment() from different threads at the same time if you pass the same VmaAllocation object to these functions.
    diff --git a/docs/html/menudata.js b/docs/html/menudata.js index eb3b37b..196cc20 100644 --- a/docs/html/menudata.js +++ b/docs/html/menudata.js @@ -5,12 +5,35 @@ var menudata={children:[ {text:"Class List",url:"annotated.html"}, {text:"Class Index",url:"classes.html"}, {text:"Class Members",url:"functions.html",children:[ -{text:"All",url:"functions.html"}, -{text:"Variables",url:"functions_vars.html"}]}]}, +{text:"All",url:"functions.html",children:[ +{text:"a",url:"functions.html#index_a"}, +{text:"b",url:"functions.html#index_b"}, +{text:"d",url:"functions.html#index_d"}, +{text:"f",url:"functions.html#index_f"}, +{text:"m",url:"functions.html#index_m"}, +{text:"o",url:"functions.html#index_o"}, +{text:"p",url:"functions.html#index_p"}, +{text:"r",url:"functions.html#index_r"}, +{text:"s",url:"functions.html#index_s"}, +{text:"t",url:"functions.html#index_t"}, +{text:"u",url:"functions.html#index_u"}]}, +{text:"Variables",url:"functions_vars.html",children:[ +{text:"a",url:"functions_vars.html#index_a"}, +{text:"b",url:"functions_vars.html#index_b"}, +{text:"d",url:"functions_vars.html#index_d"}, +{text:"f",url:"functions_vars.html#index_f"}, +{text:"m",url:"functions_vars.html#index_m"}, +{text:"o",url:"functions_vars.html#index_o"}, +{text:"p",url:"functions_vars.html#index_p"}, +{text:"r",url:"functions_vars.html#index_r"}, +{text:"s",url:"functions_vars.html#index_s"}, +{text:"t",url:"functions_vars.html#index_t"}, +{text:"u",url:"functions_vars.html#index_u"}]}]}]}, {text:"Files",url:"files.html",children:[ {text:"File List",url:"files.html"}, {text:"File Members",url:"globals.html",children:[ {text:"All",url:"globals.html",children:[ +{text:"p",url:"globals.html#index_p"}, {text:"v",url:"globals.html#index_v"}]}, {text:"Functions",url:"globals_func.html"}, {text:"Typedefs",url:"globals_type.html"}, diff --git a/docs/html/search/all_0.js b/docs/html/search/all_0.js index e5008cc..d65975f 100644 --- a/docs/html/search/all_0.js +++ b/docs/html/search/all_0.js @@ -1,4 +1,5 @@ var searchData= [ - ['allocationcount',['AllocationCount',['../struct_vma_stat_info.html#a240402222ac6777e4079653c5d542cb0',1,'VmaStatInfo']]] + ['allocationcount',['AllocationCount',['../struct_vma_stat_info.html#a240402222ac6777e4079653c5d542cb0',1,'VmaStatInfo']]], + ['allocationsmoved',['allocationsMoved',['../struct_vma_defragmentation_stats.html#aefeabf130022008eadd75999478af3f9',1,'VmaDefragmentationStats']]] ]; diff --git a/docs/html/search/all_1.js b/docs/html/search/all_1.js index b72b6f4..cb221fc 100644 --- a/docs/html/search/all_1.js +++ b/docs/html/search/all_1.js @@ -1,4 +1,5 @@ var searchData= [ - ['device',['device',['../struct_vma_allocator_create_info.html#ad924ddd77b04039c88d0c09b0ffcd500',1,'VmaAllocatorCreateInfo']]] + ['bytesfreed',['bytesFreed',['../struct_vma_defragmentation_stats.html#ab0cb9ac0dbc106c77e384ea676422f28',1,'VmaDefragmentationStats']]], + ['bytesmoved',['bytesMoved',['../struct_vma_defragmentation_stats.html#a36f9d5df2a10ba2a36b16e126d60572d',1,'VmaDefragmentationStats']]] ]; diff --git a/docs/html/search/all_2.js b/docs/html/search/all_2.js index 025ecae..ae5f1ff 100644 --- a/docs/html/search/all_2.js +++ b/docs/html/search/all_2.js @@ -1,4 +1,6 @@ var searchData= [ - ['general',['General',['../group__general.html',1,'']]] + ['device',['device',['../struct_vma_allocator_create_info.html#ad924ddd77b04039c88d0c09b0ffcd500',1,'VmaAllocatorCreateInfo']]], + ['devicememory',['deviceMemory',['../struct_vma_allocation_info.html#ae0bfb7dfdf79a76ffefc9a94677a2f67',1,'VmaAllocationInfo']]], + ['devicememoryblocksfreed',['deviceMemoryBlocksFreed',['../struct_vma_defragmentation_stats.html#a0113f1877904a5d1ee8f409216ff276b',1,'VmaDefragmentationStats']]] ]; diff --git a/docs/html/search/all_3.js b/docs/html/search/all_3.js index 058f893..60408e6 100644 --- a/docs/html/search/all_3.js +++ b/docs/html/search/all_3.js @@ -1,6 +1,4 @@ var searchData= [ - ['layer_201_20choosing_20memory_20type',['Layer 1 Choosing Memory Type',['../group__layer1.html',1,'']]], - ['layer_202_20allocating_20memory',['Layer 2 Allocating Memory',['../group__layer2.html',1,'']]], - ['layer_203_20creating_20buffers_20and_20images',['Layer 3 Creating Buffers and Images',['../group__layer3.html',1,'']]] + ['flags',['flags',['../struct_vma_allocator_create_info.html#a35d3b42ac5a3be3758926819dc053859',1,'VmaAllocatorCreateInfo::flags()'],['../struct_vma_memory_requirements.html#a53c9ea8c3cbcc12dddbe9ae23bb85eb6',1,'VmaMemoryRequirements::flags()']]] ]; diff --git a/docs/html/search/all_4.js b/docs/html/search/all_4.js index 5b8d8f2..025ecae 100644 --- a/docs/html/search/all_4.js +++ b/docs/html/search/all_4.js @@ -1,5 +1,4 @@ var searchData= [ - ['memoryheap',['memoryHeap',['../struct_vma_stats.html#a0e6611508c29a187f0fd14ff1a0329c0',1,'VmaStats']]], - ['memorytype',['memoryType',['../struct_vma_stats.html#a13e3caf754be79352c42408756309331',1,'VmaStats']]] + ['general',['General',['../group__general.html',1,'']]] ]; diff --git a/docs/html/search/all_5.js b/docs/html/search/all_5.js index 523d148..058f893 100644 --- a/docs/html/search/all_5.js +++ b/docs/html/search/all_5.js @@ -1,4 +1,6 @@ var searchData= [ - ['neverallocate',['neverAllocate',['../struct_vma_memory_requirements.html#a2259df9db140839199fa43b651c58447',1,'VmaMemoryRequirements']]] + ['layer_201_20choosing_20memory_20type',['Layer 1 Choosing Memory Type',['../group__layer1.html',1,'']]], + ['layer_202_20allocating_20memory',['Layer 2 Allocating Memory',['../group__layer2.html',1,'']]], + ['layer_203_20creating_20buffers_20and_20images',['Layer 3 Creating Buffers and Images',['../group__layer3.html',1,'']]] ]; diff --git a/docs/html/search/all_6.js b/docs/html/search/all_6.js index 44a7a9b..b23ec17 100644 --- a/docs/html/search/all_6.js +++ b/docs/html/search/all_6.js @@ -1,4 +1,7 @@ var searchData= [ - ['ownmemory',['ownMemory',['../struct_vma_memory_requirements.html#a401cdf684f8a13c8ff3bb469a1759153',1,'VmaMemoryRequirements']]] + ['maxallocationstomove',['maxAllocationsToMove',['../struct_vma_defragmentation_info.html#aa7c7304e13c71f604c907196c4e28fbc',1,'VmaDefragmentationInfo']]], + ['maxbytestomove',['maxBytesToMove',['../struct_vma_defragmentation_info.html#acb311c940a777270e67e1b81c5ab6a1d',1,'VmaDefragmentationInfo']]], + ['memoryheap',['memoryHeap',['../struct_vma_stats.html#a0e6611508c29a187f0fd14ff1a0329c0',1,'VmaStats']]], + ['memorytype',['memoryType',['../struct_vma_stats.html#a13e3caf754be79352c42408756309331',1,'VmaStats::memoryType()'],['../struct_vma_allocation_info.html#a7f6b0aa58c135e488e6b40a388dad9d5',1,'VmaAllocationInfo::memoryType()']]] ]; diff --git a/docs/html/search/all_7.js b/docs/html/search/all_7.js index a6df7a8..c9c4229 100644 --- a/docs/html/search/all_7.js +++ b/docs/html/search/all_7.js @@ -1,8 +1,4 @@ var searchData= [ - ['pallocationcallbacks',['pAllocationCallbacks',['../struct_vma_allocator_create_info.html#a6e409087e3be55400d0e4ccbe43c608d',1,'VmaAllocatorCreateInfo']]], - ['physicaldevice',['physicalDevice',['../struct_vma_allocator_create_info.html#a08230f04ae6ccf8a78150a9e829a7156',1,'VmaAllocatorCreateInfo']]], - ['preferredflags',['preferredFlags',['../struct_vma_memory_requirements.html#a6e105f836c2288034c711815b18226dc',1,'VmaMemoryRequirements']]], - ['preferredlargeheapblocksize',['preferredLargeHeapBlockSize',['../struct_vma_allocator_create_info.html#a8e4714298e3121cdd8b214a1ae7a637a',1,'VmaAllocatorCreateInfo']]], - ['preferredsmallheapblocksize',['preferredSmallHeapBlockSize',['../struct_vma_allocator_create_info.html#ab435423d84d5ab26e2c347c51771f90a',1,'VmaAllocatorCreateInfo']]] + ['offset',['offset',['../struct_vma_allocation_info.html#a4a3c732388dbdc7a23f9365b00825268',1,'VmaAllocationInfo']]] ]; diff --git a/docs/html/search/all_8.js b/docs/html/search/all_8.js index 0a576b4..4093397 100644 --- a/docs/html/search/all_8.js +++ b/docs/html/search/all_8.js @@ -1,4 +1,15 @@ var searchData= [ - ['requiredflags',['requiredFlags',['../struct_vma_memory_requirements.html#a8876c1b0f112e13a277f16967064cfe0',1,'VmaMemoryRequirements']]] + ['pallocationcallbacks',['pAllocationCallbacks',['../struct_vma_allocator_create_info.html#a6e409087e3be55400d0e4ccbe43c608d',1,'VmaAllocatorCreateInfo']]], + ['pdevicememorycallbacks',['pDeviceMemoryCallbacks',['../struct_vma_allocator_create_info.html#af1380969b5e1ea4c3184a877892d260e',1,'VmaAllocatorCreateInfo']]], + ['pfn_5fvmaallocatedevicememoryfunction',['PFN_vmaAllocateDeviceMemoryFunction',['../group__general.html#gab6a6477cda1ce775b30bde96d766203b',1,'vk_mem_alloc.h']]], + ['pfn_5fvmafreedevicememoryfunction',['PFN_vmaFreeDeviceMemoryFunction',['../group__general.html#gaef2545dc2e9dd4f29ab9ba6ac6fe2f49',1,'vk_mem_alloc.h']]], + ['pfnallocate',['pfnAllocate',['../struct_vma_device_memory_callbacks.html#a4f17f7b255101e733b44d5633aceabfb',1,'VmaDeviceMemoryCallbacks']]], + ['pfnfree',['pfnFree',['../struct_vma_device_memory_callbacks.html#abe8a3328bbc916f6f712fdb6b299444c',1,'VmaDeviceMemoryCallbacks']]], + ['physicaldevice',['physicalDevice',['../struct_vma_allocator_create_info.html#a08230f04ae6ccf8a78150a9e829a7156',1,'VmaAllocatorCreateInfo']]], + ['pmappeddata',['pMappedData',['../struct_vma_allocation_info.html#a5eeffbe2d2f30f53370ff14aefbadbe2',1,'VmaAllocationInfo']]], + ['preferredflags',['preferredFlags',['../struct_vma_memory_requirements.html#a6e105f836c2288034c711815b18226dc',1,'VmaMemoryRequirements']]], + ['preferredlargeheapblocksize',['preferredLargeHeapBlockSize',['../struct_vma_allocator_create_info.html#a8e4714298e3121cdd8b214a1ae7a637a',1,'VmaAllocatorCreateInfo']]], + ['preferredsmallheapblocksize',['preferredSmallHeapBlockSize',['../struct_vma_allocator_create_info.html#ab435423d84d5ab26e2c347c51771f90a',1,'VmaAllocatorCreateInfo']]], + ['puserdata',['pUserData',['../struct_vma_memory_requirements.html#a8470093e93ed07ed2557490cdc67566a',1,'VmaMemoryRequirements::pUserData()'],['../struct_vma_allocation_info.html#adc507656149c04de7ed95d0042ba2a13',1,'VmaAllocationInfo::pUserData()']]] ]; diff --git a/docs/html/search/all_9.js b/docs/html/search/all_9.js index 619cc95..0a576b4 100644 --- a/docs/html/search/all_9.js +++ b/docs/html/search/all_9.js @@ -1,7 +1,4 @@ var searchData= [ - ['suballocationcount',['SuballocationCount',['../struct_vma_stat_info.html#a09fb04b5491661c2e838d098d51bcead',1,'VmaStatInfo']]], - ['suballocationsizeavg',['SuballocationSizeAvg',['../struct_vma_stat_info.html#abb6c3e160a136787f474a18a8264d83b',1,'VmaStatInfo']]], - ['suballocationsizemax',['SuballocationSizeMax',['../struct_vma_stat_info.html#a6be7faf2b7fcff5a9bc017d90aed9271',1,'VmaStatInfo']]], - ['suballocationsizemin',['SuballocationSizeMin',['../struct_vma_stat_info.html#a9dc0b50fab2f10ab99366b79424bf14b',1,'VmaStatInfo']]] + ['requiredflags',['requiredFlags',['../struct_vma_memory_requirements.html#a8876c1b0f112e13a277f16967064cfe0',1,'VmaMemoryRequirements']]] ]; diff --git a/docs/html/search/all_a.js b/docs/html/search/all_a.js index f8fbe3d..5261aad 100644 --- a/docs/html/search/all_a.js +++ b/docs/html/search/all_a.js @@ -1,4 +1,8 @@ var searchData= [ - ['total',['total',['../struct_vma_stats.html#a2e8f5b3353f2fefef3c27f29e245a1f9',1,'VmaStats']]] + ['size',['size',['../struct_vma_allocation_info.html#aac76d113a6a5ccbb09fea00fb25fd18f',1,'VmaAllocationInfo']]], + ['suballocationcount',['SuballocationCount',['../struct_vma_stat_info.html#a09fb04b5491661c2e838d098d51bcead',1,'VmaStatInfo']]], + ['suballocationsizeavg',['SuballocationSizeAvg',['../struct_vma_stat_info.html#abb6c3e160a136787f474a18a8264d83b',1,'VmaStatInfo']]], + ['suballocationsizemax',['SuballocationSizeMax',['../struct_vma_stat_info.html#a6be7faf2b7fcff5a9bc017d90aed9271',1,'VmaStatInfo']]], + ['suballocationsizemin',['SuballocationSizeMin',['../struct_vma_stat_info.html#a9dc0b50fab2f10ab99366b79424bf14b',1,'VmaStatInfo']]] ]; diff --git a/docs/html/search/all_b.js b/docs/html/search/all_b.js index cc1a3e7..f8fbe3d 100644 --- a/docs/html/search/all_b.js +++ b/docs/html/search/all_b.js @@ -1,10 +1,4 @@ var searchData= [ - ['unusedbytes',['UnusedBytes',['../struct_vma_stat_info.html#a394d2aef4348cb58abf73764804b4f2d',1,'VmaStatInfo']]], - ['unusedrangecount',['UnusedRangeCount',['../struct_vma_stat_info.html#a56c4fb4dba646479180b601854cde2a6',1,'VmaStatInfo']]], - ['unusedrangesizeavg',['UnusedRangeSizeAvg',['../struct_vma_stat_info.html#a88ad9bdc2b3a98964a4d0c338c0c9060',1,'VmaStatInfo']]], - ['unusedrangesizemax',['UnusedRangeSizeMax',['../struct_vma_stat_info.html#a10c52c0841f01ca704e8ddb1ea6a635d',1,'VmaStatInfo']]], - ['unusedrangesizemin',['UnusedRangeSizeMin',['../struct_vma_stat_info.html#a07c508f42a4d3424bd0c259784a7f2d6',1,'VmaStatInfo']]], - ['usage',['usage',['../struct_vma_memory_requirements.html#ab588497177a57847ed04e0a1aef54bbe',1,'VmaMemoryRequirements']]], - ['usedbytes',['UsedBytes',['../struct_vma_stat_info.html#a86f82cb9cffd456b9da63eaf26c9ff04',1,'VmaStatInfo']]] + ['total',['total',['../struct_vma_stats.html#a2e8f5b3353f2fefef3c27f29e245a1f9',1,'VmaStats']]] ]; diff --git a/docs/html/search/all_c.js b/docs/html/search/all_c.js index ad59006..cc1a3e7 100644 --- a/docs/html/search/all_c.js +++ b/docs/html/search/all_c.js @@ -1,36 +1,10 @@ var searchData= [ - ['vulkan_20memory_20allocator',['Vulkan Memory Allocator',['../index.html',1,'']]], - ['vk_5fmem_5falloc_2eh',['vk_mem_alloc.h',['../vk__mem__alloc_8h.html',1,'']]], - ['vma_5fmemory_5fusage_5fcpu_5fonly',['VMA_MEMORY_USAGE_CPU_ONLY',['../group__layer1.html#ggaa5846affa1e9da3800e3e78fae2305cca40bdf4cddeffeb12f43d45ca1286e0a5',1,'vk_mem_alloc.h']]], - ['vma_5fmemory_5fusage_5fcpu_5fto_5fgpu',['VMA_MEMORY_USAGE_CPU_TO_GPU',['../group__layer1.html#ggaa5846affa1e9da3800e3e78fae2305cca9066b52c5a7079bb74a69aaf8b92ff67',1,'vk_mem_alloc.h']]], - ['vma_5fmemory_5fusage_5fgpu_5fonly',['VMA_MEMORY_USAGE_GPU_ONLY',['../group__layer1.html#ggaa5846affa1e9da3800e3e78fae2305ccac6b5dc1432d88647aa4cd456246eadf7',1,'vk_mem_alloc.h']]], - ['vma_5fmemory_5fusage_5fgpu_5fto_5fcpu',['VMA_MEMORY_USAGE_GPU_TO_CPU',['../group__layer1.html#ggaa5846affa1e9da3800e3e78fae2305cca7b586d2fdaf82a463b58f581ed72be27',1,'vk_mem_alloc.h']]], - ['vma_5fmemory_5fusage_5fmax_5fenum',['VMA_MEMORY_USAGE_MAX_ENUM',['../group__layer1.html#ggaa5846affa1e9da3800e3e78fae2305cca091e69437ef693e8d0d287f1c719ba6e',1,'vk_mem_alloc.h']]], - ['vma_5fmemory_5fusage_5funknown',['VMA_MEMORY_USAGE_UNKNOWN',['../group__layer1.html#ggaa5846affa1e9da3800e3e78fae2305ccaf50d27e34e0925cf3a63db8c839121dd',1,'vk_mem_alloc.h']]], - ['vma_5fstats_5fstring_5fenabled',['VMA_STATS_STRING_ENABLED',['../group__general.html#gae25f0d55fd91cb166f002b63244800e1',1,'vk_mem_alloc.h']]], - ['vmaallocatememory',['vmaAllocateMemory',['../group__layer2.html#gab7d80a26f1059f60c1e3a6999b5f7be1',1,'vk_mem_alloc.h']]], - ['vmaallocatememoryforbuffer',['vmaAllocateMemoryForBuffer',['../group__layer2.html#gac2d43581abef651398409ed3f71a7b95',1,'vk_mem_alloc.h']]], - ['vmaallocatememoryforimage',['vmaAllocateMemoryForImage',['../group__layer2.html#gad0d2f5b794dd454f0fa5ba308d644af3',1,'vk_mem_alloc.h']]], - ['vmaallocatorcreateinfo',['VmaAllocatorCreateInfo',['../struct_vma_allocator_create_info.html',1,'VmaAllocatorCreateInfo'],['../group__general.html#gae0f6d1d733dded220d28134da46b4283',1,'VmaAllocatorCreateInfo(): vk_mem_alloc.h']]], - ['vmabuildstatsstring',['vmaBuildStatsString',['../group__general.html#gaa4fee7eb5253377599ef4fd38c93c2a0',1,'vk_mem_alloc.h']]], - ['vmacalculatestats',['vmaCalculateStats',['../group__general.html#ga333b61c1788cb23559177531e6a93ca3',1,'vk_mem_alloc.h']]], - ['vmacreateallocator',['vmaCreateAllocator',['../group__general.html#ga200692051ddb34240248234f5f4c17bb',1,'vk_mem_alloc.h']]], - ['vmacreatebuffer',['vmaCreateBuffer',['../group__layer3.html#ga6cafa3a644324a1e0c9165494db11648',1,'vk_mem_alloc.h']]], - ['vmacreateimage',['vmaCreateImage',['../group__layer3.html#ga9646281a3d9abc9f4d0bc5632db117de',1,'vk_mem_alloc.h']]], - ['vmadestroyallocator',['vmaDestroyAllocator',['../group__general.html#gaa8d164061c88f22fb1fd3c8f3534bc1d',1,'vk_mem_alloc.h']]], - ['vmadestroybuffer',['vmaDestroyBuffer',['../group__layer3.html#ga967857c06b8232b2a54936daf36d1535',1,'vk_mem_alloc.h']]], - ['vmadestroyimage',['vmaDestroyImage',['../group__layer3.html#ga9377799736c4a1262b41ee441e5fc877',1,'vk_mem_alloc.h']]], - ['vmafindmemorytypeindex',['vmaFindMemoryTypeIndex',['../group__layer1.html#gadf80663373e94bcef382f17534b8694e',1,'vk_mem_alloc.h']]], - ['vmafreememory',['vmaFreeMemory',['../group__layer2.html#gaf5896cec102b83ca87ae07002d96e230',1,'vk_mem_alloc.h']]], - ['vmafreestatsstring',['vmaFreeStatsString',['../group__general.html#ga3104eb30d8122c84dd8541063f145288',1,'vk_mem_alloc.h']]], - ['vmagetmemoryproperties',['vmaGetMemoryProperties',['../group__general.html#gab88db292a17974f911182543fda52d19',1,'vk_mem_alloc.h']]], - ['vmagetmemorytypeproperties',['vmaGetMemoryTypeProperties',['../group__general.html#ga8701444752eb5de4464adb5a2b514bca',1,'vk_mem_alloc.h']]], - ['vmagetphysicaldeviceproperties',['vmaGetPhysicalDeviceProperties',['../group__general.html#gaecabf7b6e91ea87d0316fa0a9e014fe0',1,'vk_mem_alloc.h']]], - ['vmamapmemory',['vmaMapMemory',['../group__layer2.html#ga17739a61a7647553258235e6142c428c',1,'vk_mem_alloc.h']]], - ['vmamemoryrequirements',['VmaMemoryRequirements',['../struct_vma_memory_requirements.html',1,'VmaMemoryRequirements'],['../group__layer1.html#gae9ee98bebd6e474aa0ef679e10f1d8ca',1,'VmaMemoryRequirements(): vk_mem_alloc.h']]], - ['vmamemoryusage',['VmaMemoryUsage',['../group__layer1.html#gaa5846affa1e9da3800e3e78fae2305cc',1,'VmaMemoryUsage(): vk_mem_alloc.h'],['../group__layer1.html#gad63b2113c0bfdbeade1cb498f5a8580d',1,'VmaMemoryUsage(): vk_mem_alloc.h']]], - ['vmastatinfo',['VmaStatInfo',['../struct_vma_stat_info.html',1,'VmaStatInfo'],['../group__general.html#ga810b009a788ee8aac72a25b42ffbe31c',1,'VmaStatInfo(): vk_mem_alloc.h']]], - ['vmastats',['VmaStats',['../struct_vma_stats.html',1,'']]], - ['vmaunmapmemory',['vmaUnmapMemory',['../group__layer2.html#gac2d386fd6ed3b7905892fc77db0b8514',1,'vk_mem_alloc.h']]] + ['unusedbytes',['UnusedBytes',['../struct_vma_stat_info.html#a394d2aef4348cb58abf73764804b4f2d',1,'VmaStatInfo']]], + ['unusedrangecount',['UnusedRangeCount',['../struct_vma_stat_info.html#a56c4fb4dba646479180b601854cde2a6',1,'VmaStatInfo']]], + ['unusedrangesizeavg',['UnusedRangeSizeAvg',['../struct_vma_stat_info.html#a88ad9bdc2b3a98964a4d0c338c0c9060',1,'VmaStatInfo']]], + ['unusedrangesizemax',['UnusedRangeSizeMax',['../struct_vma_stat_info.html#a10c52c0841f01ca704e8ddb1ea6a635d',1,'VmaStatInfo']]], + ['unusedrangesizemin',['UnusedRangeSizeMin',['../struct_vma_stat_info.html#a07c508f42a4d3424bd0c259784a7f2d6',1,'VmaStatInfo']]], + ['usage',['usage',['../struct_vma_memory_requirements.html#ab588497177a57847ed04e0a1aef54bbe',1,'VmaMemoryRequirements']]], + ['usedbytes',['UsedBytes',['../struct_vma_stat_info.html#a86f82cb9cffd456b9da63eaf26c9ff04',1,'VmaStatInfo']]] ]; diff --git a/docs/html/search/all_d.html b/docs/html/search/all_d.html new file mode 100644 index 0000000..9986c9c --- /dev/null +++ b/docs/html/search/all_d.html @@ -0,0 +1,26 @@ + + + + + + + + + +
    +
    Loading...
    +
    + +
    Searching...
    +
    No Matches
    + +
    + + diff --git a/docs/html/search/all_d.js b/docs/html/search/all_d.js new file mode 100644 index 0000000..dbd1fed --- /dev/null +++ b/docs/html/search/all_d.js @@ -0,0 +1,55 @@ +var searchData= +[ + ['vulkan_20memory_20allocator',['Vulkan Memory Allocator',['../index.html',1,'']]], + ['vk_5fmem_5falloc_2eh',['vk_mem_alloc.h',['../vk__mem__alloc_8h.html',1,'']]], + ['vma_5fallocator_5fexternally_5fsynchronized_5fbit',['VMA_ALLOCATOR_EXTERNALLY_SYNCHRONIZED_BIT',['../group__general.html#gga34fff29c218d23a7ff7dff44b77b6b6fabe92b706180652ceb320da5bc383aef4',1,'vk_mem_alloc.h']]], + ['vma_5fallocator_5fflag_5fbits_5fmax_5fenum',['VMA_ALLOCATOR_FLAG_BITS_MAX_ENUM',['../group__general.html#gga34fff29c218d23a7ff7dff44b77b6b6fa914e905a08c2e578f76b9d6c418626cc',1,'vk_mem_alloc.h']]], + ['vma_5fmemory_5frequirement_5fflag_5fbits_5fmax_5fenum',['VMA_MEMORY_REQUIREMENT_FLAG_BITS_MAX_ENUM',['../group__layer1.html#ggadec54ccdb0fd3901e89ac6d38c2619eda11f849416519c61bebd90e2e7ecbab21',1,'vk_mem_alloc.h']]], + ['vma_5fmemory_5frequirement_5fnever_5fallocate_5fbit',['VMA_MEMORY_REQUIREMENT_NEVER_ALLOCATE_BIT',['../group__layer1.html#ggadec54ccdb0fd3901e89ac6d38c2619edae1a503c29619c0c9885521d371e9b4c4',1,'vk_mem_alloc.h']]], + ['vma_5fmemory_5frequirement_5fown_5fmemory_5fbit',['VMA_MEMORY_REQUIREMENT_OWN_MEMORY_BIT',['../group__layer1.html#ggadec54ccdb0fd3901e89ac6d38c2619eda9831d98a698347b0cd1594db6a29e8ed',1,'vk_mem_alloc.h']]], + ['vma_5fmemory_5frequirement_5fpersistent_5fmap_5fbit',['VMA_MEMORY_REQUIREMENT_PERSISTENT_MAP_BIT',['../group__layer1.html#ggadec54ccdb0fd3901e89ac6d38c2619edae75c9dde227c9d4f64693b1e004106dc',1,'vk_mem_alloc.h']]], + ['vma_5fmemory_5fusage_5fcpu_5fonly',['VMA_MEMORY_USAGE_CPU_ONLY',['../group__layer1.html#ggaa5846affa1e9da3800e3e78fae2305cca40bdf4cddeffeb12f43d45ca1286e0a5',1,'vk_mem_alloc.h']]], + ['vma_5fmemory_5fusage_5fcpu_5fto_5fgpu',['VMA_MEMORY_USAGE_CPU_TO_GPU',['../group__layer1.html#ggaa5846affa1e9da3800e3e78fae2305cca9066b52c5a7079bb74a69aaf8b92ff67',1,'vk_mem_alloc.h']]], + ['vma_5fmemory_5fusage_5fgpu_5fonly',['VMA_MEMORY_USAGE_GPU_ONLY',['../group__layer1.html#ggaa5846affa1e9da3800e3e78fae2305ccac6b5dc1432d88647aa4cd456246eadf7',1,'vk_mem_alloc.h']]], + ['vma_5fmemory_5fusage_5fgpu_5fto_5fcpu',['VMA_MEMORY_USAGE_GPU_TO_CPU',['../group__layer1.html#ggaa5846affa1e9da3800e3e78fae2305cca7b586d2fdaf82a463b58f581ed72be27',1,'vk_mem_alloc.h']]], + ['vma_5fmemory_5fusage_5fmax_5fenum',['VMA_MEMORY_USAGE_MAX_ENUM',['../group__layer1.html#ggaa5846affa1e9da3800e3e78fae2305cca091e69437ef693e8d0d287f1c719ba6e',1,'vk_mem_alloc.h']]], + ['vma_5fmemory_5fusage_5funknown',['VMA_MEMORY_USAGE_UNKNOWN',['../group__layer1.html#ggaa5846affa1e9da3800e3e78fae2305ccaf50d27e34e0925cf3a63db8c839121dd',1,'vk_mem_alloc.h']]], + ['vma_5fstats_5fstring_5fenabled',['VMA_STATS_STRING_ENABLED',['../group__general.html#gae25f0d55fd91cb166f002b63244800e1',1,'vk_mem_alloc.h']]], + ['vmaallocatememory',['vmaAllocateMemory',['../group__layer2.html#ga1a7d45920877a53e9a8fbefd6a536119',1,'vk_mem_alloc.h']]], + ['vmaallocatememoryforbuffer',['vmaAllocateMemoryForBuffer',['../group__layer2.html#ga3536b4da2a2744dc3f3f138be555af02',1,'vk_mem_alloc.h']]], + ['vmaallocatememoryforimage',['vmaAllocateMemoryForImage',['../group__layer2.html#ga801f98c24eb928642742bb1e5615e86e',1,'vk_mem_alloc.h']]], + ['vmaallocationinfo',['VmaAllocationInfo',['../struct_vma_allocation_info.html',1,'VmaAllocationInfo'],['../group__layer2.html#ga795e6ff02a21d5486c0565f403dd9255',1,'VmaAllocationInfo(): vk_mem_alloc.h']]], + ['vmaallocatorcreateinfo',['VmaAllocatorCreateInfo',['../struct_vma_allocator_create_info.html',1,'VmaAllocatorCreateInfo'],['../group__general.html#gae0f6d1d733dded220d28134da46b4283',1,'VmaAllocatorCreateInfo(): vk_mem_alloc.h']]], + ['vmaallocatorflagbits',['VmaAllocatorFlagBits',['../group__general.html#ga34fff29c218d23a7ff7dff44b77b6b6f',1,'VmaAllocatorFlagBits(): vk_mem_alloc.h'],['../group__general.html#gac51ae2c316ee760ec5aebbae06d31253',1,'VmaAllocatorFlagBits(): vk_mem_alloc.h']]], + ['vmaallocatorflags',['VmaAllocatorFlags',['../group__general.html#ga6ffbcb80208bf4467a1104087396cf59',1,'vk_mem_alloc.h']]], + ['vmabuildstatsstring',['vmaBuildStatsString',['../group__general.html#gaa4fee7eb5253377599ef4fd38c93c2a0',1,'vk_mem_alloc.h']]], + ['vmacalculatestats',['vmaCalculateStats',['../group__general.html#ga333b61c1788cb23559177531e6a93ca3',1,'vk_mem_alloc.h']]], + ['vmacreateallocator',['vmaCreateAllocator',['../group__general.html#ga200692051ddb34240248234f5f4c17bb',1,'vk_mem_alloc.h']]], + ['vmacreatebuffer',['vmaCreateBuffer',['../group__layer3.html#ga2f711e32e95cf9bf8dff4917230c2e9b',1,'vk_mem_alloc.h']]], + ['vmacreateimage',['vmaCreateImage',['../group__layer3.html#ga9e34bc318ff4b25d1958e79b9db3f1aa',1,'vk_mem_alloc.h']]], + ['vmadefragment',['vmaDefragment',['../group__layer2.html#ga6aced90fcc7b39882b6654a740a0b9bb',1,'vk_mem_alloc.h']]], + ['vmadefragmentationinfo',['VmaDefragmentationInfo',['../struct_vma_defragmentation_info.html',1,'VmaDefragmentationInfo'],['../group__layer2.html#gae67f8573a0cf20f16f0a1eecbca566a0',1,'VmaDefragmentationInfo(): vk_mem_alloc.h']]], + ['vmadefragmentationstats',['VmaDefragmentationStats',['../struct_vma_defragmentation_stats.html',1,'VmaDefragmentationStats'],['../group__layer2.html#gab0f9b06441c840fee560de4a2967f8c9',1,'VmaDefragmentationStats(): vk_mem_alloc.h']]], + ['vmadestroyallocator',['vmaDestroyAllocator',['../group__general.html#gaa8d164061c88f22fb1fd3c8f3534bc1d',1,'vk_mem_alloc.h']]], + ['vmadestroybuffer',['vmaDestroyBuffer',['../group__layer3.html#ga0d9f4e4ba5bf9aab1f1c746387753d77',1,'vk_mem_alloc.h']]], + ['vmadestroyimage',['vmaDestroyImage',['../group__layer3.html#gae50d2cb3b4a3bfd4dd40987234e50e7e',1,'vk_mem_alloc.h']]], + ['vmadevicememorycallbacks',['VmaDeviceMemoryCallbacks',['../struct_vma_device_memory_callbacks.html',1,'VmaDeviceMemoryCallbacks'],['../group__general.html#ga5e2eb68d727cfd4df25702b027b7aa31',1,'VmaDeviceMemoryCallbacks(): vk_mem_alloc.h']]], + ['vmafindmemorytypeindex',['vmaFindMemoryTypeIndex',['../group__layer1.html#gadf80663373e94bcef382f17534b8694e',1,'vk_mem_alloc.h']]], + ['vmafreememory',['vmaFreeMemory',['../group__layer2.html#ga11f0fbc034fa81a4efedd73d61ce7568',1,'vk_mem_alloc.h']]], + ['vmafreestatsstring',['vmaFreeStatsString',['../group__general.html#ga3104eb30d8122c84dd8541063f145288',1,'vk_mem_alloc.h']]], + ['vmagetallocationinfo',['vmaGetAllocationInfo',['../group__layer2.html#ga86dd08aba8633bfa4ad0df2e76481d8b',1,'vk_mem_alloc.h']]], + ['vmagetmemoryproperties',['vmaGetMemoryProperties',['../group__general.html#gab88db292a17974f911182543fda52d19',1,'vk_mem_alloc.h']]], + ['vmagetmemorytypeproperties',['vmaGetMemoryTypeProperties',['../group__general.html#ga8701444752eb5de4464adb5a2b514bca',1,'vk_mem_alloc.h']]], + ['vmagetphysicaldeviceproperties',['vmaGetPhysicalDeviceProperties',['../group__general.html#gaecabf7b6e91ea87d0316fa0a9e014fe0',1,'vk_mem_alloc.h']]], + ['vmamapmemory',['vmaMapMemory',['../group__layer2.html#gad5bd1243512d099706de88168992f069',1,'vk_mem_alloc.h']]], + ['vmamappersistentlymappedmemory',['vmaMapPersistentlyMappedMemory',['../group__layer2.html#ga03366170bb8e186605518d2f5d65b85a',1,'vk_mem_alloc.h']]], + ['vmamemoryrequirementflagbits',['VmaMemoryRequirementFlagBits',['../group__layer1.html#gadec54ccdb0fd3901e89ac6d38c2619ed',1,'VmaMemoryRequirementFlagBits(): vk_mem_alloc.h'],['../group__layer1.html#gaecb50b7fdb759cc4c4346c40819bf00b',1,'VmaMemoryRequirementFlagBits(): vk_mem_alloc.h']]], + ['vmamemoryrequirementflags',['VmaMemoryRequirementFlags',['../group__layer1.html#gab96b90d34cd1bd0f340fc48f8ca2664a',1,'vk_mem_alloc.h']]], + ['vmamemoryrequirements',['VmaMemoryRequirements',['../struct_vma_memory_requirements.html',1,'VmaMemoryRequirements'],['../group__layer1.html#gae9ee98bebd6e474aa0ef679e10f1d8ca',1,'VmaMemoryRequirements(): vk_mem_alloc.h']]], + ['vmamemoryusage',['VmaMemoryUsage',['../group__layer1.html#gaa5846affa1e9da3800e3e78fae2305cc',1,'VmaMemoryUsage(): vk_mem_alloc.h'],['../group__layer1.html#gad63b2113c0bfdbeade1cb498f5a8580d',1,'VmaMemoryUsage(): vk_mem_alloc.h']]], + ['vmasetallocationuserdata',['vmaSetAllocationUserData',['../group__layer2.html#gaf9147d31ffc11d62fc187bde283ed14f',1,'vk_mem_alloc.h']]], + ['vmastatinfo',['VmaStatInfo',['../struct_vma_stat_info.html',1,'VmaStatInfo'],['../group__general.html#ga810b009a788ee8aac72a25b42ffbe31c',1,'VmaStatInfo(): vk_mem_alloc.h']]], + ['vmastats',['VmaStats',['../struct_vma_stats.html',1,'']]], + ['vmaunmapmemory',['vmaUnmapMemory',['../group__layer2.html#ga9bc268595cb33f6ec4d519cfce81ff45',1,'vk_mem_alloc.h']]], + ['vmaunmappersistentlymappedmemory',['vmaUnmapPersistentlyMappedMemory',['../group__layer2.html#ga26b87244491c1fe77f11fe9ab5779c27',1,'vk_mem_alloc.h']]] +]; diff --git a/docs/html/search/classes_0.js b/docs/html/search/classes_0.js index 7cf7430..079a70a 100644 --- a/docs/html/search/classes_0.js +++ b/docs/html/search/classes_0.js @@ -1,6 +1,10 @@ var searchData= [ + ['vmaallocationinfo',['VmaAllocationInfo',['../struct_vma_allocation_info.html',1,'']]], ['vmaallocatorcreateinfo',['VmaAllocatorCreateInfo',['../struct_vma_allocator_create_info.html',1,'']]], + ['vmadefragmentationinfo',['VmaDefragmentationInfo',['../struct_vma_defragmentation_info.html',1,'']]], + ['vmadefragmentationstats',['VmaDefragmentationStats',['../struct_vma_defragmentation_stats.html',1,'']]], + ['vmadevicememorycallbacks',['VmaDeviceMemoryCallbacks',['../struct_vma_device_memory_callbacks.html',1,'']]], ['vmamemoryrequirements',['VmaMemoryRequirements',['../struct_vma_memory_requirements.html',1,'']]], ['vmastatinfo',['VmaStatInfo',['../struct_vma_stat_info.html',1,'']]], ['vmastats',['VmaStats',['../struct_vma_stats.html',1,'']]] diff --git a/docs/html/search/enums_0.js b/docs/html/search/enums_0.js index 9c9ac7f..f6e10b1 100644 --- a/docs/html/search/enums_0.js +++ b/docs/html/search/enums_0.js @@ -1,4 +1,6 @@ var searchData= [ + ['vmaallocatorflagbits',['VmaAllocatorFlagBits',['../group__general.html#ga34fff29c218d23a7ff7dff44b77b6b6f',1,'vk_mem_alloc.h']]], + ['vmamemoryrequirementflagbits',['VmaMemoryRequirementFlagBits',['../group__layer1.html#gadec54ccdb0fd3901e89ac6d38c2619ed',1,'vk_mem_alloc.h']]], ['vmamemoryusage',['VmaMemoryUsage',['../group__layer1.html#gaa5846affa1e9da3800e3e78fae2305cc',1,'vk_mem_alloc.h']]] ]; diff --git a/docs/html/search/enumvalues_0.js b/docs/html/search/enumvalues_0.js index 0d98b0a..13bd7ca 100644 --- a/docs/html/search/enumvalues_0.js +++ b/docs/html/search/enumvalues_0.js @@ -1,5 +1,11 @@ var searchData= [ + ['vma_5fallocator_5fexternally_5fsynchronized_5fbit',['VMA_ALLOCATOR_EXTERNALLY_SYNCHRONIZED_BIT',['../group__general.html#gga34fff29c218d23a7ff7dff44b77b6b6fabe92b706180652ceb320da5bc383aef4',1,'vk_mem_alloc.h']]], + ['vma_5fallocator_5fflag_5fbits_5fmax_5fenum',['VMA_ALLOCATOR_FLAG_BITS_MAX_ENUM',['../group__general.html#gga34fff29c218d23a7ff7dff44b77b6b6fa914e905a08c2e578f76b9d6c418626cc',1,'vk_mem_alloc.h']]], + ['vma_5fmemory_5frequirement_5fflag_5fbits_5fmax_5fenum',['VMA_MEMORY_REQUIREMENT_FLAG_BITS_MAX_ENUM',['../group__layer1.html#ggadec54ccdb0fd3901e89ac6d38c2619eda11f849416519c61bebd90e2e7ecbab21',1,'vk_mem_alloc.h']]], + ['vma_5fmemory_5frequirement_5fnever_5fallocate_5fbit',['VMA_MEMORY_REQUIREMENT_NEVER_ALLOCATE_BIT',['../group__layer1.html#ggadec54ccdb0fd3901e89ac6d38c2619edae1a503c29619c0c9885521d371e9b4c4',1,'vk_mem_alloc.h']]], + ['vma_5fmemory_5frequirement_5fown_5fmemory_5fbit',['VMA_MEMORY_REQUIREMENT_OWN_MEMORY_BIT',['../group__layer1.html#ggadec54ccdb0fd3901e89ac6d38c2619eda9831d98a698347b0cd1594db6a29e8ed',1,'vk_mem_alloc.h']]], + ['vma_5fmemory_5frequirement_5fpersistent_5fmap_5fbit',['VMA_MEMORY_REQUIREMENT_PERSISTENT_MAP_BIT',['../group__layer1.html#ggadec54ccdb0fd3901e89ac6d38c2619edae75c9dde227c9d4f64693b1e004106dc',1,'vk_mem_alloc.h']]], ['vma_5fmemory_5fusage_5fcpu_5fonly',['VMA_MEMORY_USAGE_CPU_ONLY',['../group__layer1.html#ggaa5846affa1e9da3800e3e78fae2305cca40bdf4cddeffeb12f43d45ca1286e0a5',1,'vk_mem_alloc.h']]], ['vma_5fmemory_5fusage_5fcpu_5fto_5fgpu',['VMA_MEMORY_USAGE_CPU_TO_GPU',['../group__layer1.html#ggaa5846affa1e9da3800e3e78fae2305cca9066b52c5a7079bb74a69aaf8b92ff67',1,'vk_mem_alloc.h']]], ['vma_5fmemory_5fusage_5fgpu_5fonly',['VMA_MEMORY_USAGE_GPU_ONLY',['../group__layer1.html#ggaa5846affa1e9da3800e3e78fae2305ccac6b5dc1432d88647aa4cd456246eadf7',1,'vk_mem_alloc.h']]], diff --git a/docs/html/search/functions_0.js b/docs/html/search/functions_0.js index 6a8494b..070a2a6 100644 --- a/docs/html/search/functions_0.js +++ b/docs/html/search/functions_0.js @@ -1,22 +1,27 @@ var searchData= [ - ['vmaallocatememory',['vmaAllocateMemory',['../group__layer2.html#gab7d80a26f1059f60c1e3a6999b5f7be1',1,'vk_mem_alloc.h']]], - ['vmaallocatememoryforbuffer',['vmaAllocateMemoryForBuffer',['../group__layer2.html#gac2d43581abef651398409ed3f71a7b95',1,'vk_mem_alloc.h']]], - ['vmaallocatememoryforimage',['vmaAllocateMemoryForImage',['../group__layer2.html#gad0d2f5b794dd454f0fa5ba308d644af3',1,'vk_mem_alloc.h']]], + ['vmaallocatememory',['vmaAllocateMemory',['../group__layer2.html#ga1a7d45920877a53e9a8fbefd6a536119',1,'vk_mem_alloc.h']]], + ['vmaallocatememoryforbuffer',['vmaAllocateMemoryForBuffer',['../group__layer2.html#ga3536b4da2a2744dc3f3f138be555af02',1,'vk_mem_alloc.h']]], + ['vmaallocatememoryforimage',['vmaAllocateMemoryForImage',['../group__layer2.html#ga801f98c24eb928642742bb1e5615e86e',1,'vk_mem_alloc.h']]], ['vmabuildstatsstring',['vmaBuildStatsString',['../group__general.html#gaa4fee7eb5253377599ef4fd38c93c2a0',1,'vk_mem_alloc.h']]], ['vmacalculatestats',['vmaCalculateStats',['../group__general.html#ga333b61c1788cb23559177531e6a93ca3',1,'vk_mem_alloc.h']]], ['vmacreateallocator',['vmaCreateAllocator',['../group__general.html#ga200692051ddb34240248234f5f4c17bb',1,'vk_mem_alloc.h']]], - ['vmacreatebuffer',['vmaCreateBuffer',['../group__layer3.html#ga6cafa3a644324a1e0c9165494db11648',1,'vk_mem_alloc.h']]], - ['vmacreateimage',['vmaCreateImage',['../group__layer3.html#ga9646281a3d9abc9f4d0bc5632db117de',1,'vk_mem_alloc.h']]], + ['vmacreatebuffer',['vmaCreateBuffer',['../group__layer3.html#ga2f711e32e95cf9bf8dff4917230c2e9b',1,'vk_mem_alloc.h']]], + ['vmacreateimage',['vmaCreateImage',['../group__layer3.html#ga9e34bc318ff4b25d1958e79b9db3f1aa',1,'vk_mem_alloc.h']]], + ['vmadefragment',['vmaDefragment',['../group__layer2.html#ga6aced90fcc7b39882b6654a740a0b9bb',1,'vk_mem_alloc.h']]], ['vmadestroyallocator',['vmaDestroyAllocator',['../group__general.html#gaa8d164061c88f22fb1fd3c8f3534bc1d',1,'vk_mem_alloc.h']]], - ['vmadestroybuffer',['vmaDestroyBuffer',['../group__layer3.html#ga967857c06b8232b2a54936daf36d1535',1,'vk_mem_alloc.h']]], - ['vmadestroyimage',['vmaDestroyImage',['../group__layer3.html#ga9377799736c4a1262b41ee441e5fc877',1,'vk_mem_alloc.h']]], + ['vmadestroybuffer',['vmaDestroyBuffer',['../group__layer3.html#ga0d9f4e4ba5bf9aab1f1c746387753d77',1,'vk_mem_alloc.h']]], + ['vmadestroyimage',['vmaDestroyImage',['../group__layer3.html#gae50d2cb3b4a3bfd4dd40987234e50e7e',1,'vk_mem_alloc.h']]], ['vmafindmemorytypeindex',['vmaFindMemoryTypeIndex',['../group__layer1.html#gadf80663373e94bcef382f17534b8694e',1,'vk_mem_alloc.h']]], - ['vmafreememory',['vmaFreeMemory',['../group__layer2.html#gaf5896cec102b83ca87ae07002d96e230',1,'vk_mem_alloc.h']]], + ['vmafreememory',['vmaFreeMemory',['../group__layer2.html#ga11f0fbc034fa81a4efedd73d61ce7568',1,'vk_mem_alloc.h']]], ['vmafreestatsstring',['vmaFreeStatsString',['../group__general.html#ga3104eb30d8122c84dd8541063f145288',1,'vk_mem_alloc.h']]], + ['vmagetallocationinfo',['vmaGetAllocationInfo',['../group__layer2.html#ga86dd08aba8633bfa4ad0df2e76481d8b',1,'vk_mem_alloc.h']]], ['vmagetmemoryproperties',['vmaGetMemoryProperties',['../group__general.html#gab88db292a17974f911182543fda52d19',1,'vk_mem_alloc.h']]], ['vmagetmemorytypeproperties',['vmaGetMemoryTypeProperties',['../group__general.html#ga8701444752eb5de4464adb5a2b514bca',1,'vk_mem_alloc.h']]], ['vmagetphysicaldeviceproperties',['vmaGetPhysicalDeviceProperties',['../group__general.html#gaecabf7b6e91ea87d0316fa0a9e014fe0',1,'vk_mem_alloc.h']]], - ['vmamapmemory',['vmaMapMemory',['../group__layer2.html#ga17739a61a7647553258235e6142c428c',1,'vk_mem_alloc.h']]], - ['vmaunmapmemory',['vmaUnmapMemory',['../group__layer2.html#gac2d386fd6ed3b7905892fc77db0b8514',1,'vk_mem_alloc.h']]] + ['vmamapmemory',['vmaMapMemory',['../group__layer2.html#gad5bd1243512d099706de88168992f069',1,'vk_mem_alloc.h']]], + ['vmamappersistentlymappedmemory',['vmaMapPersistentlyMappedMemory',['../group__layer2.html#ga03366170bb8e186605518d2f5d65b85a',1,'vk_mem_alloc.h']]], + ['vmasetallocationuserdata',['vmaSetAllocationUserData',['../group__layer2.html#gaf9147d31ffc11d62fc187bde283ed14f',1,'vk_mem_alloc.h']]], + ['vmaunmapmemory',['vmaUnmapMemory',['../group__layer2.html#ga9bc268595cb33f6ec4d519cfce81ff45',1,'vk_mem_alloc.h']]], + ['vmaunmappersistentlymappedmemory',['vmaUnmapPersistentlyMappedMemory',['../group__layer2.html#ga26b87244491c1fe77f11fe9ab5779c27',1,'vk_mem_alloc.h']]] ]; diff --git a/docs/html/search/searchdata.js b/docs/html/search/searchdata.js index 57471c8..a0bcb94 100644 --- a/docs/html/search/searchdata.js +++ b/docs/html/search/searchdata.js @@ -1,11 +1,11 @@ var indexSectionsWithContent = { - 0: "adglmnoprstuv", + 0: "abdfglmoprstuv", 1: "v", 2: "v", 3: "v", - 4: "admnoprstu", - 5: "v", + 4: "abdfmoprstu", + 5: "pv", 6: "v", 7: "v", 8: "gl", diff --git a/docs/html/search/typedefs_0.js b/docs/html/search/typedefs_0.js index 4f030fd..debe3da 100644 --- a/docs/html/search/typedefs_0.js +++ b/docs/html/search/typedefs_0.js @@ -1,7 +1,5 @@ var searchData= [ - ['vmaallocatorcreateinfo',['VmaAllocatorCreateInfo',['../group__general.html#gae0f6d1d733dded220d28134da46b4283',1,'vk_mem_alloc.h']]], - ['vmamemoryrequirements',['VmaMemoryRequirements',['../group__layer1.html#gae9ee98bebd6e474aa0ef679e10f1d8ca',1,'vk_mem_alloc.h']]], - ['vmamemoryusage',['VmaMemoryUsage',['../group__layer1.html#gad63b2113c0bfdbeade1cb498f5a8580d',1,'vk_mem_alloc.h']]], - ['vmastatinfo',['VmaStatInfo',['../group__general.html#ga810b009a788ee8aac72a25b42ffbe31c',1,'vk_mem_alloc.h']]] + ['pfn_5fvmaallocatedevicememoryfunction',['PFN_vmaAllocateDeviceMemoryFunction',['../group__general.html#gab6a6477cda1ce775b30bde96d766203b',1,'vk_mem_alloc.h']]], + ['pfn_5fvmafreedevicememoryfunction',['PFN_vmaFreeDeviceMemoryFunction',['../group__general.html#gaef2545dc2e9dd4f29ab9ba6ac6fe2f49',1,'vk_mem_alloc.h']]] ]; diff --git a/docs/html/search/typedefs_1.html b/docs/html/search/typedefs_1.html new file mode 100644 index 0000000..b77c533 --- /dev/null +++ b/docs/html/search/typedefs_1.html @@ -0,0 +1,26 @@ + + + + + + + + + +
    +
    Loading...
    +
    + +
    Searching...
    +
    No Matches
    + +
    + + diff --git a/docs/html/search/typedefs_1.js b/docs/html/search/typedefs_1.js new file mode 100644 index 0000000..639050c --- /dev/null +++ b/docs/html/search/typedefs_1.js @@ -0,0 +1,15 @@ +var searchData= +[ + ['vmaallocationinfo',['VmaAllocationInfo',['../group__layer2.html#ga795e6ff02a21d5486c0565f403dd9255',1,'vk_mem_alloc.h']]], + ['vmaallocatorcreateinfo',['VmaAllocatorCreateInfo',['../group__general.html#gae0f6d1d733dded220d28134da46b4283',1,'vk_mem_alloc.h']]], + ['vmaallocatorflagbits',['VmaAllocatorFlagBits',['../group__general.html#gac51ae2c316ee760ec5aebbae06d31253',1,'vk_mem_alloc.h']]], + ['vmaallocatorflags',['VmaAllocatorFlags',['../group__general.html#ga6ffbcb80208bf4467a1104087396cf59',1,'vk_mem_alloc.h']]], + ['vmadefragmentationinfo',['VmaDefragmentationInfo',['../group__layer2.html#gae67f8573a0cf20f16f0a1eecbca566a0',1,'vk_mem_alloc.h']]], + ['vmadefragmentationstats',['VmaDefragmentationStats',['../group__layer2.html#gab0f9b06441c840fee560de4a2967f8c9',1,'vk_mem_alloc.h']]], + ['vmadevicememorycallbacks',['VmaDeviceMemoryCallbacks',['../group__general.html#ga5e2eb68d727cfd4df25702b027b7aa31',1,'vk_mem_alloc.h']]], + ['vmamemoryrequirementflagbits',['VmaMemoryRequirementFlagBits',['../group__layer1.html#gaecb50b7fdb759cc4c4346c40819bf00b',1,'vk_mem_alloc.h']]], + ['vmamemoryrequirementflags',['VmaMemoryRequirementFlags',['../group__layer1.html#gab96b90d34cd1bd0f340fc48f8ca2664a',1,'vk_mem_alloc.h']]], + ['vmamemoryrequirements',['VmaMemoryRequirements',['../group__layer1.html#gae9ee98bebd6e474aa0ef679e10f1d8ca',1,'vk_mem_alloc.h']]], + ['vmamemoryusage',['VmaMemoryUsage',['../group__layer1.html#gad63b2113c0bfdbeade1cb498f5a8580d',1,'vk_mem_alloc.h']]], + ['vmastatinfo',['VmaStatInfo',['../group__general.html#ga810b009a788ee8aac72a25b42ffbe31c',1,'vk_mem_alloc.h']]] +]; diff --git a/docs/html/search/variables_0.js b/docs/html/search/variables_0.js index e5008cc..d65975f 100644 --- a/docs/html/search/variables_0.js +++ b/docs/html/search/variables_0.js @@ -1,4 +1,5 @@ var searchData= [ - ['allocationcount',['AllocationCount',['../struct_vma_stat_info.html#a240402222ac6777e4079653c5d542cb0',1,'VmaStatInfo']]] + ['allocationcount',['AllocationCount',['../struct_vma_stat_info.html#a240402222ac6777e4079653c5d542cb0',1,'VmaStatInfo']]], + ['allocationsmoved',['allocationsMoved',['../struct_vma_defragmentation_stats.html#aefeabf130022008eadd75999478af3f9',1,'VmaDefragmentationStats']]] ]; diff --git a/docs/html/search/variables_1.js b/docs/html/search/variables_1.js index b72b6f4..cb221fc 100644 --- a/docs/html/search/variables_1.js +++ b/docs/html/search/variables_1.js @@ -1,4 +1,5 @@ var searchData= [ - ['device',['device',['../struct_vma_allocator_create_info.html#ad924ddd77b04039c88d0c09b0ffcd500',1,'VmaAllocatorCreateInfo']]] + ['bytesfreed',['bytesFreed',['../struct_vma_defragmentation_stats.html#ab0cb9ac0dbc106c77e384ea676422f28',1,'VmaDefragmentationStats']]], + ['bytesmoved',['bytesMoved',['../struct_vma_defragmentation_stats.html#a36f9d5df2a10ba2a36b16e126d60572d',1,'VmaDefragmentationStats']]] ]; diff --git a/docs/html/search/variables_2.js b/docs/html/search/variables_2.js index 5b8d8f2..ae5f1ff 100644 --- a/docs/html/search/variables_2.js +++ b/docs/html/search/variables_2.js @@ -1,5 +1,6 @@ var searchData= [ - ['memoryheap',['memoryHeap',['../struct_vma_stats.html#a0e6611508c29a187f0fd14ff1a0329c0',1,'VmaStats']]], - ['memorytype',['memoryType',['../struct_vma_stats.html#a13e3caf754be79352c42408756309331',1,'VmaStats']]] + ['device',['device',['../struct_vma_allocator_create_info.html#ad924ddd77b04039c88d0c09b0ffcd500',1,'VmaAllocatorCreateInfo']]], + ['devicememory',['deviceMemory',['../struct_vma_allocation_info.html#ae0bfb7dfdf79a76ffefc9a94677a2f67',1,'VmaAllocationInfo']]], + ['devicememoryblocksfreed',['deviceMemoryBlocksFreed',['../struct_vma_defragmentation_stats.html#a0113f1877904a5d1ee8f409216ff276b',1,'VmaDefragmentationStats']]] ]; diff --git a/docs/html/search/variables_3.js b/docs/html/search/variables_3.js index 523d148..60408e6 100644 --- a/docs/html/search/variables_3.js +++ b/docs/html/search/variables_3.js @@ -1,4 +1,4 @@ var searchData= [ - ['neverallocate',['neverAllocate',['../struct_vma_memory_requirements.html#a2259df9db140839199fa43b651c58447',1,'VmaMemoryRequirements']]] + ['flags',['flags',['../struct_vma_allocator_create_info.html#a35d3b42ac5a3be3758926819dc053859',1,'VmaAllocatorCreateInfo::flags()'],['../struct_vma_memory_requirements.html#a53c9ea8c3cbcc12dddbe9ae23bb85eb6',1,'VmaMemoryRequirements::flags()']]] ]; diff --git a/docs/html/search/variables_4.js b/docs/html/search/variables_4.js index 44a7a9b..b23ec17 100644 --- a/docs/html/search/variables_4.js +++ b/docs/html/search/variables_4.js @@ -1,4 +1,7 @@ var searchData= [ - ['ownmemory',['ownMemory',['../struct_vma_memory_requirements.html#a401cdf684f8a13c8ff3bb469a1759153',1,'VmaMemoryRequirements']]] + ['maxallocationstomove',['maxAllocationsToMove',['../struct_vma_defragmentation_info.html#aa7c7304e13c71f604c907196c4e28fbc',1,'VmaDefragmentationInfo']]], + ['maxbytestomove',['maxBytesToMove',['../struct_vma_defragmentation_info.html#acb311c940a777270e67e1b81c5ab6a1d',1,'VmaDefragmentationInfo']]], + ['memoryheap',['memoryHeap',['../struct_vma_stats.html#a0e6611508c29a187f0fd14ff1a0329c0',1,'VmaStats']]], + ['memorytype',['memoryType',['../struct_vma_stats.html#a13e3caf754be79352c42408756309331',1,'VmaStats::memoryType()'],['../struct_vma_allocation_info.html#a7f6b0aa58c135e488e6b40a388dad9d5',1,'VmaAllocationInfo::memoryType()']]] ]; diff --git a/docs/html/search/variables_5.js b/docs/html/search/variables_5.js index a6df7a8..c9c4229 100644 --- a/docs/html/search/variables_5.js +++ b/docs/html/search/variables_5.js @@ -1,8 +1,4 @@ var searchData= [ - ['pallocationcallbacks',['pAllocationCallbacks',['../struct_vma_allocator_create_info.html#a6e409087e3be55400d0e4ccbe43c608d',1,'VmaAllocatorCreateInfo']]], - ['physicaldevice',['physicalDevice',['../struct_vma_allocator_create_info.html#a08230f04ae6ccf8a78150a9e829a7156',1,'VmaAllocatorCreateInfo']]], - ['preferredflags',['preferredFlags',['../struct_vma_memory_requirements.html#a6e105f836c2288034c711815b18226dc',1,'VmaMemoryRequirements']]], - ['preferredlargeheapblocksize',['preferredLargeHeapBlockSize',['../struct_vma_allocator_create_info.html#a8e4714298e3121cdd8b214a1ae7a637a',1,'VmaAllocatorCreateInfo']]], - ['preferredsmallheapblocksize',['preferredSmallHeapBlockSize',['../struct_vma_allocator_create_info.html#ab435423d84d5ab26e2c347c51771f90a',1,'VmaAllocatorCreateInfo']]] + ['offset',['offset',['../struct_vma_allocation_info.html#a4a3c732388dbdc7a23f9365b00825268',1,'VmaAllocationInfo']]] ]; diff --git a/docs/html/search/variables_6.js b/docs/html/search/variables_6.js index 0a576b4..7119d4d 100644 --- a/docs/html/search/variables_6.js +++ b/docs/html/search/variables_6.js @@ -1,4 +1,13 @@ var searchData= [ - ['requiredflags',['requiredFlags',['../struct_vma_memory_requirements.html#a8876c1b0f112e13a277f16967064cfe0',1,'VmaMemoryRequirements']]] + ['pallocationcallbacks',['pAllocationCallbacks',['../struct_vma_allocator_create_info.html#a6e409087e3be55400d0e4ccbe43c608d',1,'VmaAllocatorCreateInfo']]], + ['pdevicememorycallbacks',['pDeviceMemoryCallbacks',['../struct_vma_allocator_create_info.html#af1380969b5e1ea4c3184a877892d260e',1,'VmaAllocatorCreateInfo']]], + ['pfnallocate',['pfnAllocate',['../struct_vma_device_memory_callbacks.html#a4f17f7b255101e733b44d5633aceabfb',1,'VmaDeviceMemoryCallbacks']]], + ['pfnfree',['pfnFree',['../struct_vma_device_memory_callbacks.html#abe8a3328bbc916f6f712fdb6b299444c',1,'VmaDeviceMemoryCallbacks']]], + ['physicaldevice',['physicalDevice',['../struct_vma_allocator_create_info.html#a08230f04ae6ccf8a78150a9e829a7156',1,'VmaAllocatorCreateInfo']]], + ['pmappeddata',['pMappedData',['../struct_vma_allocation_info.html#a5eeffbe2d2f30f53370ff14aefbadbe2',1,'VmaAllocationInfo']]], + ['preferredflags',['preferredFlags',['../struct_vma_memory_requirements.html#a6e105f836c2288034c711815b18226dc',1,'VmaMemoryRequirements']]], + ['preferredlargeheapblocksize',['preferredLargeHeapBlockSize',['../struct_vma_allocator_create_info.html#a8e4714298e3121cdd8b214a1ae7a637a',1,'VmaAllocatorCreateInfo']]], + ['preferredsmallheapblocksize',['preferredSmallHeapBlockSize',['../struct_vma_allocator_create_info.html#ab435423d84d5ab26e2c347c51771f90a',1,'VmaAllocatorCreateInfo']]], + ['puserdata',['pUserData',['../struct_vma_memory_requirements.html#a8470093e93ed07ed2557490cdc67566a',1,'VmaMemoryRequirements::pUserData()'],['../struct_vma_allocation_info.html#adc507656149c04de7ed95d0042ba2a13',1,'VmaAllocationInfo::pUserData()']]] ]; diff --git a/docs/html/search/variables_7.js b/docs/html/search/variables_7.js index 619cc95..0a576b4 100644 --- a/docs/html/search/variables_7.js +++ b/docs/html/search/variables_7.js @@ -1,7 +1,4 @@ var searchData= [ - ['suballocationcount',['SuballocationCount',['../struct_vma_stat_info.html#a09fb04b5491661c2e838d098d51bcead',1,'VmaStatInfo']]], - ['suballocationsizeavg',['SuballocationSizeAvg',['../struct_vma_stat_info.html#abb6c3e160a136787f474a18a8264d83b',1,'VmaStatInfo']]], - ['suballocationsizemax',['SuballocationSizeMax',['../struct_vma_stat_info.html#a6be7faf2b7fcff5a9bc017d90aed9271',1,'VmaStatInfo']]], - ['suballocationsizemin',['SuballocationSizeMin',['../struct_vma_stat_info.html#a9dc0b50fab2f10ab99366b79424bf14b',1,'VmaStatInfo']]] + ['requiredflags',['requiredFlags',['../struct_vma_memory_requirements.html#a8876c1b0f112e13a277f16967064cfe0',1,'VmaMemoryRequirements']]] ]; diff --git a/docs/html/search/variables_8.js b/docs/html/search/variables_8.js index f8fbe3d..5261aad 100644 --- a/docs/html/search/variables_8.js +++ b/docs/html/search/variables_8.js @@ -1,4 +1,8 @@ var searchData= [ - ['total',['total',['../struct_vma_stats.html#a2e8f5b3353f2fefef3c27f29e245a1f9',1,'VmaStats']]] + ['size',['size',['../struct_vma_allocation_info.html#aac76d113a6a5ccbb09fea00fb25fd18f',1,'VmaAllocationInfo']]], + ['suballocationcount',['SuballocationCount',['../struct_vma_stat_info.html#a09fb04b5491661c2e838d098d51bcead',1,'VmaStatInfo']]], + ['suballocationsizeavg',['SuballocationSizeAvg',['../struct_vma_stat_info.html#abb6c3e160a136787f474a18a8264d83b',1,'VmaStatInfo']]], + ['suballocationsizemax',['SuballocationSizeMax',['../struct_vma_stat_info.html#a6be7faf2b7fcff5a9bc017d90aed9271',1,'VmaStatInfo']]], + ['suballocationsizemin',['SuballocationSizeMin',['../struct_vma_stat_info.html#a9dc0b50fab2f10ab99366b79424bf14b',1,'VmaStatInfo']]] ]; diff --git a/docs/html/search/variables_9.js b/docs/html/search/variables_9.js index cc1a3e7..f8fbe3d 100644 --- a/docs/html/search/variables_9.js +++ b/docs/html/search/variables_9.js @@ -1,10 +1,4 @@ var searchData= [ - ['unusedbytes',['UnusedBytes',['../struct_vma_stat_info.html#a394d2aef4348cb58abf73764804b4f2d',1,'VmaStatInfo']]], - ['unusedrangecount',['UnusedRangeCount',['../struct_vma_stat_info.html#a56c4fb4dba646479180b601854cde2a6',1,'VmaStatInfo']]], - ['unusedrangesizeavg',['UnusedRangeSizeAvg',['../struct_vma_stat_info.html#a88ad9bdc2b3a98964a4d0c338c0c9060',1,'VmaStatInfo']]], - ['unusedrangesizemax',['UnusedRangeSizeMax',['../struct_vma_stat_info.html#a10c52c0841f01ca704e8ddb1ea6a635d',1,'VmaStatInfo']]], - ['unusedrangesizemin',['UnusedRangeSizeMin',['../struct_vma_stat_info.html#a07c508f42a4d3424bd0c259784a7f2d6',1,'VmaStatInfo']]], - ['usage',['usage',['../struct_vma_memory_requirements.html#ab588497177a57847ed04e0a1aef54bbe',1,'VmaMemoryRequirements']]], - ['usedbytes',['UsedBytes',['../struct_vma_stat_info.html#a86f82cb9cffd456b9da63eaf26c9ff04',1,'VmaStatInfo']]] + ['total',['total',['../struct_vma_stats.html#a2e8f5b3353f2fefef3c27f29e245a1f9',1,'VmaStats']]] ]; diff --git a/docs/html/search/variables_a.html b/docs/html/search/variables_a.html new file mode 100644 index 0000000..0892488 --- /dev/null +++ b/docs/html/search/variables_a.html @@ -0,0 +1,26 @@ + + + + + + + + + +
    +
    Loading...
    +
    + +
    Searching...
    +
    No Matches
    + +
    + + diff --git a/docs/html/search/variables_a.js b/docs/html/search/variables_a.js new file mode 100644 index 0000000..cc1a3e7 --- /dev/null +++ b/docs/html/search/variables_a.js @@ -0,0 +1,10 @@ +var searchData= +[ + ['unusedbytes',['UnusedBytes',['../struct_vma_stat_info.html#a394d2aef4348cb58abf73764804b4f2d',1,'VmaStatInfo']]], + ['unusedrangecount',['UnusedRangeCount',['../struct_vma_stat_info.html#a56c4fb4dba646479180b601854cde2a6',1,'VmaStatInfo']]], + ['unusedrangesizeavg',['UnusedRangeSizeAvg',['../struct_vma_stat_info.html#a88ad9bdc2b3a98964a4d0c338c0c9060',1,'VmaStatInfo']]], + ['unusedrangesizemax',['UnusedRangeSizeMax',['../struct_vma_stat_info.html#a10c52c0841f01ca704e8ddb1ea6a635d',1,'VmaStatInfo']]], + ['unusedrangesizemin',['UnusedRangeSizeMin',['../struct_vma_stat_info.html#a07c508f42a4d3424bd0c259784a7f2d6',1,'VmaStatInfo']]], + ['usage',['usage',['../struct_vma_memory_requirements.html#ab588497177a57847ed04e0a1aef54bbe',1,'VmaMemoryRequirements']]], + ['usedbytes',['UsedBytes',['../struct_vma_stat_info.html#a86f82cb9cffd456b9da63eaf26c9ff04',1,'VmaStatInfo']]] +]; diff --git a/docs/html/struct_vma_allocation_info-members.html b/docs/html/struct_vma_allocation_info-members.html new file mode 100644 index 0000000..0ad42b1 --- /dev/null +++ b/docs/html/struct_vma_allocation_info-members.html @@ -0,0 +1,82 @@ + + + + + + + +Vulkan Memory Allocator: Member List + + + + + + + + + +
    +
    + + + + + + +
    +
    Vulkan Memory Allocator +
    +
    +
    + + + + + + + + +
    +
    + + +
    + +
    + +
    +
    +
    +
    VmaAllocationInfo Member List
    +
    +
    + +

    This is the complete list of members for VmaAllocationInfo, including all inherited members.

    + + + + + + + +
    deviceMemoryVmaAllocationInfo
    memoryTypeVmaAllocationInfo
    offsetVmaAllocationInfo
    pMappedDataVmaAllocationInfo
    pUserDataVmaAllocationInfo
    sizeVmaAllocationInfo
    + + + + diff --git a/docs/html/struct_vma_allocation_info.html b/docs/html/struct_vma_allocation_info.html new file mode 100644 index 0000000..aff38a5 --- /dev/null +++ b/docs/html/struct_vma_allocation_info.html @@ -0,0 +1,212 @@ + + + + + + + +Vulkan Memory Allocator: VmaAllocationInfo Struct Reference + + + + + + + + + +
    +
    + + + + + + +
    +
    Vulkan Memory Allocator +
    +
    +
    + + + + + + + + +
    +
    + + +
    + +
    + +
    +
    + +
    +
    VmaAllocationInfo Struct Reference
    +
    +
    + +

    Parameters of VmaAllocation objects, that can be retrieved using function vmaGetAllocationInfo(). + More...

    + +

    #include <vk_mem_alloc.h>

    + + + + + + + + + + + + + + + + + + + + +

    +Public Attributes

    uint32_t memoryType
     Memory type index that this allocation was allocated from. More...
     
    VkDeviceMemory deviceMemory
     Handle to Vulkan memory object. More...
     
    VkDeviceSize offset
     Offset into deviceMemory object to the beginning of this allocation, in bytes. (deviceMemory, offset) pair is unique to this allocation. More...
     
    VkDeviceSize size
     Size of this allocation, in bytes. More...
     
    void * pMappedData
     Pointer to the beginning of this allocation as mapped data. Null if this alloaction is not persistently mapped. More...
     
    void * pUserData
     Custom general-purpose pointer that was passed as VmaMemoryRequirements::pUserData or set using vmaSetAllocationUserData(). More...
     
    +

    Detailed Description

    +

    Parameters of VmaAllocation objects, that can be retrieved using function vmaGetAllocationInfo().

    +

    Member Data Documentation

    + +

    ◆ deviceMemory

    + +
    +
    + + + + +
    VkDeviceMemory VmaAllocationInfo::deviceMemory
    +
    + +

    Handle to Vulkan memory object.

    +

    Same memory object can be shared by multiple allocations.

    +

    It can change after call to vmaDefragment() if this allocation is passed to the function.

    + +
    +
    + +

    ◆ memoryType

    + +
    +
    + + + + +
    uint32_t VmaAllocationInfo::memoryType
    +
    + +

    Memory type index that this allocation was allocated from.

    +

    It never changes.

    + +
    +
    + +

    ◆ offset

    + +
    +
    + + + + +
    VkDeviceSize VmaAllocationInfo::offset
    +
    + +

    Offset into deviceMemory object to the beginning of this allocation, in bytes. (deviceMemory, offset) pair is unique to this allocation.

    +

    It can change after call to vmaDefragment() if this allocation is passed to the function.

    + +
    +
    + +

    ◆ pMappedData

    + +
    +
    + + + + +
    void* VmaAllocationInfo::pMappedData
    +
    + +

    Pointer to the beginning of this allocation as mapped data. Null if this alloaction is not persistently mapped.

    +

    It can change after call to vmaUnmapPersistentlyMappedMemory(), vmaMapPersistentlyMappedMemory(). It can also change after call to vmaDefragment() if this allocation is passed to the function.

    + +
    +
    + +

    ◆ pUserData

    + +
    +
    + + + + +
    void* VmaAllocationInfo::pUserData
    +
    + +

    Custom general-purpose pointer that was passed as VmaMemoryRequirements::pUserData or set using vmaSetAllocationUserData().

    +

    It can change after call to vmaSetAllocationUserData() for this allocation.

    + +
    +
    + +

    ◆ size

    + +
    +
    + + + + +
    VkDeviceSize VmaAllocationInfo::size
    +
    + +

    Size of this allocation, in bytes.

    +

    It never changes.

    + +
    +
    +
    The documentation for this struct was generated from the following file: +
    + + + + diff --git a/docs/html/struct_vma_allocator_create_info-members.html b/docs/html/struct_vma_allocator_create_info-members.html index 31b25c0..dbc84dd 100644 --- a/docs/html/struct_vma_allocator_create_info-members.html +++ b/docs/html/struct_vma_allocator_create_info-members.html @@ -66,7 +66,9 @@ $(function() {

    This is the complete list of members for VmaAllocatorCreateInfo, including all inherited members.

    - + + + diff --git a/docs/html/struct_vma_allocator_create_info.html b/docs/html/struct_vma_allocator_create_info.html index c60e132..ec129b1 100644 --- a/docs/html/struct_vma_allocator_create_info.html +++ b/docs/html/struct_vma_allocator_create_info.html @@ -73,6 +73,9 @@ $(function() {
    deviceVmaAllocatorCreateInfo
    pAllocationCallbacksVmaAllocatorCreateInfo
    flagsVmaAllocatorCreateInfo
    pAllocationCallbacksVmaAllocatorCreateInfo
    pDeviceMemoryCallbacksVmaAllocatorCreateInfo
    physicalDeviceVmaAllocatorCreateInfo
    preferredLargeHeapBlockSizeVmaAllocatorCreateInfo
    preferredSmallHeapBlockSizeVmaAllocatorCreateInfo
    + + + @@ -88,6 +91,9 @@ Public Attributes + + +

    Public Attributes

    VmaAllocatorFlags flags
     Flags for created allocator. Use VmaAllocatorFlagBits enum. More...
     
    VkPhysicalDevice physicalDevice
     Vulkan physical device. More...
     
    const VkAllocationCallbacks * pAllocationCallbacks
     Custom allocation callbacks. More...
     
    const VmaDeviceMemoryCallbackspDeviceMemoryCallbacks
     Informative callbacks for vkAllocateMemory, vkFreeMemory. More...
     

    Detailed Description

    Description of a Allocator to be created.

    @@ -107,6 +113,22 @@ Public Attributes

    Vulkan device.

    It must be valid throughout whole lifetime of created Allocator.

    +
    +
    + +

    ◆ flags

    + +
    +
    + + + + +
    VmaAllocatorFlags VmaAllocatorCreateInfo::flags
    +
    + +

    Flags for created allocator. Use VmaAllocatorFlagBits enum.

    +
    @@ -124,6 +146,23 @@ Public Attributes

    Custom allocation callbacks.

    Optional, can be null. When specified, will also be used for all CPU-side memory allocations.

    + + + +

    ◆ pDeviceMemoryCallbacks

    + +
    +
    + + + + +
    const VmaDeviceMemoryCallbacks* VmaAllocatorCreateInfo::pDeviceMemoryCallbacks
    +
    + +

    Informative callbacks for vkAllocateMemory, vkFreeMemory.

    +

    Optional, can be null.

    +
    diff --git a/docs/html/struct_vma_defragmentation_info-members.html b/docs/html/struct_vma_defragmentation_info-members.html new file mode 100644 index 0000000..8b5fac6 --- /dev/null +++ b/docs/html/struct_vma_defragmentation_info-members.html @@ -0,0 +1,78 @@ + + + + + + + +Vulkan Memory Allocator: Member List + + + + + + + + + +
    +
    + + + + + + +
    +
    Vulkan Memory Allocator +
    +
    +
    + + + + + + + + +
    +
    + + +
    + +
    + +
    +
    +
    +
    VmaDefragmentationInfo Member List
    +
    +
    + +

    This is the complete list of members for VmaDefragmentationInfo, including all inherited members.

    + + + +
    maxAllocationsToMoveVmaDefragmentationInfo
    maxBytesToMoveVmaDefragmentationInfo
    + + + + diff --git a/docs/html/struct_vma_defragmentation_info.html b/docs/html/struct_vma_defragmentation_info.html new file mode 100644 index 0000000..e4be271 --- /dev/null +++ b/docs/html/struct_vma_defragmentation_info.html @@ -0,0 +1,131 @@ + + + + + + + +Vulkan Memory Allocator: VmaDefragmentationInfo Struct Reference + + + + + + + + + +
    +
    + + + + + + +
    +
    Vulkan Memory Allocator +
    +
    +
    + + + + + + + + +
    +
    + + +
    + +
    + +
    +
    +
    +Public Attributes | +List of all members
    +
    +
    VmaDefragmentationInfo Struct Reference
    +
    +
    + +

    Optional configuration parameters to be passed to function vmaDefragment(). + More...

    + +

    #include <vk_mem_alloc.h>

    + + + + + + + + +

    +Public Attributes

    VkDeviceSize maxBytesToMove
     Maximum total numbers of bytes that can be copied while moving allocations to different places. More...
     
    uint32_t maxAllocationsToMove
     Maximum number of allocations that can be moved to different place. More...
     
    +

    Detailed Description

    +

    Optional configuration parameters to be passed to function vmaDefragment().

    +

    Member Data Documentation

    + +

    ◆ maxAllocationsToMove

    + +
    +
    + + + + +
    uint32_t VmaDefragmentationInfo::maxAllocationsToMove
    +
    + +

    Maximum number of allocations that can be moved to different place.

    +

    Default is UINT32_MAX, which means no limit.

    + +
    +
    + +

    ◆ maxBytesToMove

    + +
    +
    + + + + +
    VkDeviceSize VmaDefragmentationInfo::maxBytesToMove
    +
    + +

    Maximum total numbers of bytes that can be copied while moving allocations to different places.

    +

    Default is VK_WHOLE_SIZE, which means no limit.

    + +
    +
    +
    The documentation for this struct was generated from the following file: +
    + + + + diff --git a/docs/html/struct_vma_defragmentation_stats-members.html b/docs/html/struct_vma_defragmentation_stats-members.html new file mode 100644 index 0000000..c823a39 --- /dev/null +++ b/docs/html/struct_vma_defragmentation_stats-members.html @@ -0,0 +1,80 @@ + + + + + + + +Vulkan Memory Allocator: Member List + + + + + + + + + +
    +
    + + + + + + +
    +
    Vulkan Memory Allocator +
    +
    +
    + + + + + + + + +
    +
    + + +
    + +
    + +
    +
    +
    +
    VmaDefragmentationStats Member List
    +
    +
    + +

    This is the complete list of members for VmaDefragmentationStats, including all inherited members.

    + + + + + +
    allocationsMovedVmaDefragmentationStats
    bytesFreedVmaDefragmentationStats
    bytesMovedVmaDefragmentationStats
    deviceMemoryBlocksFreedVmaDefragmentationStats
    + + + + diff --git a/docs/html/struct_vma_defragmentation_stats.html b/docs/html/struct_vma_defragmentation_stats.html new file mode 100644 index 0000000..7c92ff4 --- /dev/null +++ b/docs/html/struct_vma_defragmentation_stats.html @@ -0,0 +1,167 @@ + + + + + + + +Vulkan Memory Allocator: VmaDefragmentationStats Struct Reference + + + + + + + + + +
    +
    + + + + + + +
    +
    Vulkan Memory Allocator +
    +
    +
    + + + + + + + + +
    +
    + + +
    + +
    + +
    +
    +
    +Public Attributes | +List of all members
    +
    +
    VmaDefragmentationStats Struct Reference
    +
    +
    + +

    Statistics returned by function vmaDefragment(). + More...

    + +

    #include <vk_mem_alloc.h>

    + + + + + + + + + + + + + + +

    +Public Attributes

    VkDeviceSize bytesMoved
     Total number of bytes that have been copied while moving allocations to different places. More...
     
    VkDeviceSize bytesFreed
     Total number of bytes that have been released to the system by freeing empty VkDeviceMemory objects. More...
     
    uint32_t allocationsMoved
     Number of allocations that have been moved to different places. More...
     
    uint32_t deviceMemoryBlocksFreed
     Number of empty VkDeviceMemory objects that have been released to the system. More...
     
    +

    Detailed Description

    +

    Statistics returned by function vmaDefragment().

    +

    Member Data Documentation

    + +

    ◆ allocationsMoved

    + +
    +
    + + + + +
    uint32_t VmaDefragmentationStats::allocationsMoved
    +
    + +

    Number of allocations that have been moved to different places.

    + +
    +
    + +

    ◆ bytesFreed

    + +
    +
    + + + + +
    VkDeviceSize VmaDefragmentationStats::bytesFreed
    +
    + +

    Total number of bytes that have been released to the system by freeing empty VkDeviceMemory objects.

    + +
    +
    + +

    ◆ bytesMoved

    + +
    +
    + + + + +
    VkDeviceSize VmaDefragmentationStats::bytesMoved
    +
    + +

    Total number of bytes that have been copied while moving allocations to different places.

    + +
    +
    + +

    ◆ deviceMemoryBlocksFreed

    + +
    +
    + + + + +
    uint32_t VmaDefragmentationStats::deviceMemoryBlocksFreed
    +
    + +

    Number of empty VkDeviceMemory objects that have been released to the system.

    + +
    +
    +
    The documentation for this struct was generated from the following file: +
    + + + + diff --git a/docs/html/struct_vma_device_memory_callbacks-members.html b/docs/html/struct_vma_device_memory_callbacks-members.html new file mode 100644 index 0000000..10c56e5 --- /dev/null +++ b/docs/html/struct_vma_device_memory_callbacks-members.html @@ -0,0 +1,78 @@ + + + + + + + +Vulkan Memory Allocator: Member List + + + + + + + + + +
    +
    + + + + + + +
    +
    Vulkan Memory Allocator +
    +
    +
    + + + + + + + + +
    +
    + + +
    + +
    + +
    +
    +
    +
    VmaDeviceMemoryCallbacks Member List
    +
    +
    + +

    This is the complete list of members for VmaDeviceMemoryCallbacks, including all inherited members.

    + + + +
    pfnAllocateVmaDeviceMemoryCallbacks
    pfnFreeVmaDeviceMemoryCallbacks
    + + + + diff --git a/docs/html/struct_vma_device_memory_callbacks.html b/docs/html/struct_vma_device_memory_callbacks.html new file mode 100644 index 0000000..edbe682 --- /dev/null +++ b/docs/html/struct_vma_device_memory_callbacks.html @@ -0,0 +1,130 @@ + + + + + + + +Vulkan Memory Allocator: VmaDeviceMemoryCallbacks Struct Reference + + + + + + + + + +
    +
    + + + + + + +
    +
    Vulkan Memory Allocator +
    +
    +
    + + + + + + + + +
    +
    + + +
    + +
    + +
    +
    +
    +Public Attributes | +List of all members
    +
    +
    VmaDeviceMemoryCallbacks Struct Reference
    +
    +
    + +

    Set of callbacks that the library will call for vkAllocateMemory and vkFreeMemory. + More...

    + +

    #include <vk_mem_alloc.h>

    + + + + + + + + +

    +Public Attributes

    PFN_vmaAllocateDeviceMemoryFunction pfnAllocate
     Optional, can be null. More...
     
    PFN_vmaFreeDeviceMemoryFunction pfnFree
     Optional, can be null. More...
     
    +

    Detailed Description

    +

    Set of callbacks that the library will call for vkAllocateMemory and vkFreeMemory.

    +

    Provided for informative purpose, e.g. to gather statistics about number of allocations or total amount of memory allocated in Vulkan.

    +

    Member Data Documentation

    + +

    ◆ pfnAllocate

    + +
    +
    + + + + +
    PFN_vmaAllocateDeviceMemoryFunction VmaDeviceMemoryCallbacks::pfnAllocate
    +
    + +

    Optional, can be null.

    + +
    +
    + +

    ◆ pfnFree

    + +
    +
    + + + + +
    PFN_vmaFreeDeviceMemoryFunction VmaDeviceMemoryCallbacks::pfnFree
    +
    + +

    Optional, can be null.

    + +
    +
    +
    The documentation for this struct was generated from the following file: +
    + + + + diff --git a/docs/html/struct_vma_memory_requirements-members.html b/docs/html/struct_vma_memory_requirements-members.html index 1404da1..aefd96c 100644 --- a/docs/html/struct_vma_memory_requirements-members.html +++ b/docs/html/struct_vma_memory_requirements-members.html @@ -65,9 +65,9 @@ $(function() {

    This is the complete list of members for VmaMemoryRequirements, including all inherited members.

    - - - + + +
    neverAllocateVmaMemoryRequirements
    ownMemoryVmaMemoryRequirements
    preferredFlagsVmaMemoryRequirements
    flagsVmaMemoryRequirements
    preferredFlagsVmaMemoryRequirements
    pUserDataVmaMemoryRequirements
    requiredFlagsVmaMemoryRequirements
    usageVmaMemoryRequirements
    diff --git a/docs/html/struct_vma_memory_requirements.html b/docs/html/struct_vma_memory_requirements.html index b3b2324..c3572f1 100644 --- a/docs/html/struct_vma_memory_requirements.html +++ b/docs/html/struct_vma_memory_requirements.html @@ -70,9 +70,8 @@ $(function() { - - - + + @@ -82,45 +81,23 @@ Public Attributes - - - + + +

    Public Attributes

    VkBool32 ownMemory
     Set to true if this allocation should have its own memory block. More...
     
    VmaMemoryRequirementFlags flags
     
    VmaMemoryUsage usage
     Intended usage of memory. More...
     
    VkMemoryPropertyFlags preferredFlags
     Flags that preferably should be set in a Memory Type chosen for an allocation. More...
     
    VkBool32 neverAllocate
     Set this flag to only try to allocate from existing VkDeviceMemory blocks and never create new such block. More...
     
    void * pUserData
     Custom general-purpose pointer that will be stored in VmaAllocation, can be read as VmaAllocationInfo::pUserData and changed using vmaSetAllocationUserData(). More...
     

    Member Data Documentation

    - -

    ◆ neverAllocate

    + +

    ◆ flags

    - +
    VkBool32 VmaMemoryRequirements::neverAllocateVmaMemoryRequirementFlags VmaMemoryRequirements::flags
    -

    Set this flag to only try to allocate from existing VkDeviceMemory blocks and never create new such block.

    -

    If new allocation cannot be placed in any of the existing blocks, allocation fails with VK_ERROR_OUT_OF_DEVICE_MEMORY error.

    -

    It makes no sense to set ownMemory and neverAllocate at the same time.

    - -
    -
    - -

    ◆ ownMemory

    - -
    -
    - - - - -
    VkBool32 VmaMemoryRequirements::ownMemory
    -
    - -

    Set to true if this allocation should have its own memory block.

    -

    Use it for special, big resources, like fullscreen images used as attachments.

    -

    This flag must also be used for host visible resources that you want to map simultaneously because otherwise they might end up as regions of the same VkDeviceMemory, while mapping same VkDeviceMemory multiple times is illegal.

    -
    @@ -138,6 +115,22 @@ Public Attributes

    Flags that preferably should be set in a Memory Type chosen for an allocation.

    Set to 0 if no additional flags are prefered and only requiredFlags should be used. If not 0, it must be a superset or equal to requiredFlags.

    + + + +

    ◆ pUserData

    + +
    +
    + + + + +
    void* VmaMemoryRequirements::pUserData
    +
    + +

    Custom general-purpose pointer that will be stored in VmaAllocation, can be read as VmaAllocationInfo::pUserData and changed using vmaSetAllocationUserData().

    +
    diff --git a/docs/html/vk__mem__alloc_8h.html b/docs/html/vk__mem__alloc_8h.html index c0df697..db24e33 100644 --- a/docs/html/vk__mem__alloc_8h.html +++ b/docs/html/vk__mem__alloc_8h.html @@ -74,6 +74,9 @@ $(function() { + + + @@ -84,6 +87,15 @@ Classes + + + + + + + + +

    Classes

    struct  VmaDeviceMemoryCallbacks
     Set of callbacks that the library will call for vkAllocateMemory and vkFreeMemory. More...
     
    struct  VmaAllocatorCreateInfo
     Description of a Allocator to be created. More...
     
     
    struct  VmaMemoryRequirements
     
    struct  VmaAllocationInfo
     Parameters of VmaAllocation objects, that can be retrieved using function vmaGetAllocationInfo(). More...
     
    struct  VmaDefragmentationInfo
     Optional configuration parameters to be passed to function vmaDefragment(). More...
     
    struct  VmaDefragmentationStats
     Statistics returned by function vmaDefragment(). More...
     
    @@ -92,6 +104,20 @@ Macros

    Macros

    + + + + + + + + + + + + + + @@ -99,11 +125,30 @@ Typedefs + + + + + + + + + + + + + +

    Typedefs

    typedef void(VKAPI_PTR * PFN_vmaAllocateDeviceMemoryFunction) (VmaAllocator allocator, uint32_t memoryType, VkDeviceMemory memory, VkDeviceSize size)
     Callback function called after successful vkAllocateMemory. More...
     
    typedef void(VKAPI_PTR * PFN_vmaFreeDeviceMemoryFunction) (VmaAllocator allocator, uint32_t memoryType, VkDeviceMemory memory, VkDeviceSize size)
     Callback function called before vkFreeMemory. More...
     
    typedef struct VmaDeviceMemoryCallbacks VmaDeviceMemoryCallbacks
     Set of callbacks that the library will call for vkAllocateMemory and vkFreeMemory. More...
     
    typedef enum VmaAllocatorFlagBits VmaAllocatorFlagBits
     Flags for created VmaAllocator. More...
     
    typedef VkFlags VmaAllocatorFlags
     
    typedef struct VmaAllocatorCreateInfo VmaAllocatorCreateInfo
     Description of a Allocator to be created. More...
     
     
    typedef enum VmaMemoryUsage VmaMemoryUsage
     
    typedef enum VmaMemoryRequirementFlagBits VmaMemoryRequirementFlagBits
     Flags to be passed as VmaMemoryRequirements::flags. More...
     
    typedef VkFlags VmaMemoryRequirementFlags
     
    typedef struct VmaMemoryRequirements VmaMemoryRequirements
     
    typedef struct VmaAllocationInfo VmaAllocationInfo
     Parameters of VmaAllocation objects, that can be retrieved using function vmaGetAllocationInfo(). More...
     
    typedef struct VmaDefragmentationInfo VmaDefragmentationInfo
     Optional configuration parameters to be passed to function vmaDefragment(). More...
     
    typedef struct VmaDefragmentationStats VmaDefragmentationStats
     Statistics returned by function vmaDefragment(). More...
     
    + + +
    } + + +

    Enumerations

    enum  VmaAllocatorFlagBits { VMA_ALLOCATOR_EXTERNALLY_SYNCHRONIZED_BIT = 0x00000001, +VMA_ALLOCATOR_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF + }
     Flags for created VmaAllocator. More...
     
    enum  VmaMemoryUsage {
      VMA_MEMORY_USAGE_UNKNOWN = 0, VMA_MEMORY_USAGE_GPU_ONLY = 1, @@ -115,6 +160,13 @@ Enumerations
     
    enum  VmaMemoryRequirementFlagBits { VMA_MEMORY_REQUIREMENT_OWN_MEMORY_BIT = 0x00000001, +VMA_MEMORY_REQUIREMENT_NEVER_ALLOCATE_BIT = 0x00000002, +VMA_MEMORY_REQUIREMENT_PERSISTENT_MAP_BIT = 0x00000004, +VMA_MEMORY_REQUIREMENT_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF + }
     Flags to be passed as VmaMemoryRequirements::flags. More...
     
    @@ -141,30 +193,45 @@ Functions - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

    Functions

     
    VkResult vmaFindMemoryTypeIndex (VmaAllocator allocator, uint32_t memoryTypeBits, const VmaMemoryRequirements *pMemoryRequirements, uint32_t *pMemoryTypeIndex)
     
    VkResult vmaAllocateMemory (VmaAllocator allocator, const VkMemoryRequirements *pVkMemoryRequirements, const VmaMemoryRequirements *pVmaMemoryRequirements, VkMappedMemoryRange *pMemory, uint32_t *pMemoryTypeIndex)
     General purpose memory allocation. More...
     
    VkResult vmaAllocateMemoryForBuffer (VmaAllocator allocator, VkBuffer buffer, const VmaMemoryRequirements *pMemoryRequirements, VkMappedMemoryRange *pMemory, uint32_t *pMemoryTypeIndex)
     
    VkResult vmaAllocateMemoryForImage (VmaAllocator allocator, VkImage image, const VmaMemoryRequirements *pMemoryRequirements, VkMappedMemoryRange *pMemory, uint32_t *pMemoryTypeIndex)
     Function similar to vmaAllocateMemoryForBuffer(). More...
     
    void vmaFreeMemory (VmaAllocator allocator, const VkMappedMemoryRange *pMemory)
     Frees memory previously allocated using vmaAllocateMemoryForBuffer() or vmaAllocateMemoryForImage(). More...
     
    VkResult vmaMapMemory (VmaAllocator allocator, const VkMappedMemoryRange *pMemory, void **ppData)
     
    void vmaUnmapMemory (VmaAllocator allocator, const VkMappedMemoryRange *pMemory)
     
    VkResult vmaCreateBuffer (VmaAllocator allocator, const VkBufferCreateInfo *pCreateInfo, const VmaMemoryRequirements *pMemoryRequirements, VkBuffer *pBuffer, VkMappedMemoryRange *pMemory, uint32_t *pMemoryTypeIndex)
     
    void vmaDestroyBuffer (VmaAllocator allocator, VkBuffer buffer)
     
    VkResult vmaCreateImage (VmaAllocator allocator, const VkImageCreateInfo *pCreateInfo, const VmaMemoryRequirements *pMemoryRequirements, VkImage *pImage, VkMappedMemoryRange *pMemory, uint32_t *pMemoryTypeIndex)
     Function similar to vmaCreateBuffer(). More...
     
    void vmaDestroyImage (VmaAllocator allocator, VkImage image)
     
    VkResult vmaAllocateMemory (VmaAllocator allocator, const VkMemoryRequirements *pVkMemoryRequirements, const VmaMemoryRequirements *pVmaMemoryRequirements, VmaAllocation *pAllocation, VmaAllocationInfo *pAllocationInfo)
     General purpose memory allocation. More...
     
    VkResult vmaAllocateMemoryForBuffer (VmaAllocator allocator, VkBuffer buffer, const VmaMemoryRequirements *pMemoryRequirements, VmaAllocation *pAllocation, VmaAllocationInfo *pAllocationInfo)
     
    VkResult vmaAllocateMemoryForImage (VmaAllocator allocator, VkImage image, const VmaMemoryRequirements *pMemoryRequirements, VmaAllocation *pAllocation, VmaAllocationInfo *pAllocationInfo)
     Function similar to vmaAllocateMemoryForBuffer(). More...
     
    void vmaFreeMemory (VmaAllocator allocator, VmaAllocation allocation)
     Frees memory previously allocated using vmaAllocateMemory(), vmaAllocateMemoryForBuffer(), or vmaAllocateMemoryForImage(). More...
     
    void vmaGetAllocationInfo (VmaAllocator allocator, VmaAllocation allocation, VmaAllocationInfo *pAllocationInfo)
     Returns current information about specified allocation. More...
     
    void vmaSetAllocationUserData (VmaAllocator allocator, VmaAllocation allocation, void *pUserData)
     Sets pUserData in given allocation to new value. More...
     
    VkResult vmaMapMemory (VmaAllocator allocator, VmaAllocation allocation, void **ppData)
     
    void vmaUnmapMemory (VmaAllocator allocator, VmaAllocation allocation)
     
    void vmaUnmapPersistentlyMappedMemory (VmaAllocator allocator)
     Unmaps persistently mapped memory of types that is HOST_COHERENT and DEVICE_LOCAL. More...
     
    VkResult vmaMapPersistentlyMappedMemory (VmaAllocator allocator)
     Maps back persistently mapped memory of types that is HOST_COHERENT and DEVICE_LOCAL. More...
     
    VkResult vmaDefragment (VmaAllocator allocator, VmaAllocation *pAllocations, size_t allocationCount, VkBool32 *pAllocationsChanged, const VmaDefragmentationInfo *pDefragmentationInfo, VmaDefragmentationStats *pDefragmentationStats)
     Compacts memory by moving allocations. More...
     
    VkResult vmaCreateBuffer (VmaAllocator allocator, const VkBufferCreateInfo *pCreateInfo, const VmaMemoryRequirements *pMemoryRequirements, VkBuffer *pBuffer, VmaAllocation *pAllocation, VmaAllocationInfo *pAllocationInfo)
     
    void vmaDestroyBuffer (VmaAllocator allocator, VkBuffer buffer, VmaAllocation allocation)
     
    VkResult vmaCreateImage (VmaAllocator allocator, const VkImageCreateInfo *pCreateInfo, const VmaMemoryRequirements *pMemoryRequirements, VkImage *pImage, VmaAllocation *pAllocation, VmaAllocationInfo *pAllocationInfo)
     Function similar to vmaCreateBuffer(). More...
     
    void vmaDestroyImage (VmaAllocator allocator, VkImage image, VmaAllocation allocation)
     
    diff --git a/docs/html/vk__mem__alloc_8h_source.html b/docs/html/vk__mem__alloc_8h_source.html index 2294272..461fcdd 100644 --- a/docs/html/vk__mem__alloc_8h_source.html +++ b/docs/html/vk__mem__alloc_8h_source.html @@ -62,63 +62,104 @@ $(function() {
    vk_mem_alloc.h
    -Go to the documentation of this file.
    1 //
    2 // Copyright (c) 2017 Advanced Micro Devices, Inc. All rights reserved.
    3 //
    4 // Permission is hereby granted, free of charge, to any person obtaining a copy
    5 // of this software and associated documentation files (the "Software"), to deal
    6 // in the Software without restriction, including without limitation the rights
    7 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
    8 // copies of the Software, and to permit persons to whom the Software is
    9 // furnished to do so, subject to the following conditions:
    10 //
    11 // The above copyright notice and this permission notice shall be included in
    12 // all copies or substantial portions of the Software.
    13 //
    14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    15 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    16 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    17 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    18 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    19 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
    20 // THE SOFTWARE.
    21 //
    22 
    23 #ifndef AMD_VULKAN_MEMORY_ALLOCATOR_H
    24 #define AMD_VULKAN_MEMORY_ALLOCATOR_H
    25 
    155 #include <vulkan/vulkan.h>
    156 
    158 
    162 VK_DEFINE_HANDLE(VmaAllocator)
    163 
    164 typedef struct VmaAllocatorCreateInfo
    166 {
    168 
    169  VkPhysicalDevice physicalDevice;
    171 
    172  VkDevice device;
    174 
    177 
    180 
    181  const VkAllocationCallbacks* pAllocationCallbacks;
    183 
    185 VkResult vmaCreateAllocator(
    186  const VmaAllocatorCreateInfo* pCreateInfo,
    187  VmaAllocator* pAllocator);
    188 
    191  VmaAllocator allocator);
    192 
    198  VmaAllocator allocator,
    199  const VkPhysicalDeviceProperties** ppPhysicalDeviceProperties);
    200 
    206  VmaAllocator allocator,
    207  const VkPhysicalDeviceMemoryProperties** ppPhysicalDeviceMemoryProperties);
    208 
    216  VmaAllocator allocator,
    217  uint32_t memoryTypeIndex,
    218  VkMemoryPropertyFlags* pFlags);
    219 
    220 typedef struct VmaStatInfo
    221 {
    222  uint32_t AllocationCount;
    225  VkDeviceSize UsedBytes;
    226  VkDeviceSize UnusedBytes;
    227  VkDeviceSize SuballocationSizeMin, SuballocationSizeAvg, SuballocationSizeMax;
    228  VkDeviceSize UnusedRangeSizeMin, UnusedRangeSizeAvg, UnusedRangeSizeMax;
    229 } VmaStatInfo;
    230 
    232 struct VmaStats
    233 {
    234  VmaStatInfo memoryType[VK_MAX_MEMORY_TYPES];
    235  VmaStatInfo memoryHeap[VK_MAX_MEMORY_HEAPS];
    237 };
    238 
    240 void vmaCalculateStats(
    241  VmaAllocator allocator,
    242  VmaStats* pStats);
    243 
    244 #ifndef VMA_STATS_STRING_ENABLED
    245  #define VMA_STATS_STRING_ENABLED 1
    246 #endif
    247 
    248 #if VMA_STATS_STRING_ENABLED
    249 
    251 
    254  VmaAllocator allocator,
    255  char** ppStatsString,
    256  VkBool32 detailedMap);
    257 
    258 void vmaFreeStatsString(
    259  VmaAllocator allocator,
    260  char* pStatsString);
    261 
    262 #endif // #if VMA_STATS_STRING_ENABLED
    263 
    266 
    271 typedef enum VmaMemoryUsage
    272 {
    285 
    286 typedef struct VmaMemoryRequirements
    287 {
    296  VkBool32 ownMemory;
    305  VkMemoryPropertyFlags requiredFlags;
    310  VkMemoryPropertyFlags preferredFlags;
    317  VkBool32 neverAllocate;
    319 
    334 VkResult vmaFindMemoryTypeIndex(
    335  VmaAllocator allocator,
    336  uint32_t memoryTypeBits,
    337  const VmaMemoryRequirements* pMemoryRequirements,
    338  uint32_t* pMemoryTypeIndex);
    339 
    342 
    359 VkResult vmaAllocateMemory(
    360  VmaAllocator allocator,
    361  const VkMemoryRequirements* pVkMemoryRequirements,
    362  const VmaMemoryRequirements* pVmaMemoryRequirements,
    363  VkMappedMemoryRange* pMemory,
    364  uint32_t* pMemoryTypeIndex);
    365 
    374  VmaAllocator allocator,
    375  VkBuffer buffer,
    376  const VmaMemoryRequirements* pMemoryRequirements,
    377  VkMappedMemoryRange* pMemory,
    378  uint32_t* pMemoryTypeIndex);
    379 
    382  VmaAllocator allocator,
    383  VkImage image,
    384  const VmaMemoryRequirements* pMemoryRequirements,
    385  VkMappedMemoryRange* pMemory,
    386  uint32_t* pMemoryTypeIndex);
    387 
    389 void vmaFreeMemory(
    390  VmaAllocator allocator,
    391  const VkMappedMemoryRange* pMemory);
    392 
    398 VkResult vmaMapMemory(
    399  VmaAllocator allocator,
    400  const VkMappedMemoryRange* pMemory,
    401  void** ppData);
    402 
    403 void vmaUnmapMemory(
    404  VmaAllocator allocator,
    405  const VkMappedMemoryRange* pMemory);
    406 
    409 
    431 VkResult vmaCreateBuffer(
    432  VmaAllocator allocator,
    433  const VkBufferCreateInfo* pCreateInfo,
    434  const VmaMemoryRequirements* pMemoryRequirements,
    435  VkBuffer* pBuffer,
    436  VkMappedMemoryRange* pMemory,
    437  uint32_t* pMemoryTypeIndex);
    438 
    439 void vmaDestroyBuffer(
    440  VmaAllocator allocator,
    441  VkBuffer buffer);
    442 
    444 VkResult vmaCreateImage(
    445  VmaAllocator allocator,
    446  const VkImageCreateInfo* pCreateInfo,
    447  const VmaMemoryRequirements* pMemoryRequirements,
    448  VkImage* pImage,
    449  VkMappedMemoryRange* pMemory,
    450  uint32_t* pMemoryTypeIndex);
    451 
    452 void vmaDestroyImage(
    453  VmaAllocator allocator,
    454  VkImage image);
    455 
    458 #ifdef VMA_IMPLEMENTATION
    459 
    460 #include <cstdint>
    461 #include <cstdlib>
    462 
    463 /*******************************************************************************
    464 CONFIGURATION SECTION
    465 
    466 Define some of these macros before each #include of this header or change them
    467 here if you need other then default behavior depending on your environment.
    468 */
    469 
    470 // Define this macro to 1 to make the library use STL containers instead of its own implementation.
    471 //#define VMA_USE_STL_CONTAINERS 1
    472 
    473 /* Set this macro to 1 to make the library including and using STL containers:
    474 std::pair, std::vector, std::list, std::unordered_map.
    475 
    476 Set it to 0 or undefined to make the library using its own implementation of
    477 the containers.
    478 */
    479 #if VMA_USE_STL_CONTAINERS
    480  #define VMA_USE_STL_VECTOR 1
    481  #define VMA_USE_STL_UNORDERED_MAP 1
    482  #define VMA_USE_STL_LIST 1
    483 #endif
    484 
    485 #if VMA_USE_STL_VECTOR
    486  #include <vector>
    487 #endif
    488 
    489 #if VMA_USE_STL_UNORDERED_MAP
    490  #include <unordered_map>
    491 #endif
    492 
    493 #if VMA_USE_STL_LIST
    494  #include <list>
    495 #endif
    496 
    497 /*
    498 Following headers are used in this CONFIGURATION section only, so feel free to
    499 remove them if not needed.
    500 */
    501 #include <cassert> // for assert
    502 #include <algorithm> // for min, max
    503 #include <mutex> // for std::mutex
    504 
    505 #if !defined(_WIN32)
    506  #include <malloc.h> // for aligned_alloc()
    507 #endif
    508 
    509 // Normal assert to check for programmer's errors, especially in Debug configuration.
    510 #ifndef VMA_ASSERT
    511  #ifdef _DEBUG
    512  #define VMA_ASSERT(expr) assert(expr)
    513  #else
    514  #define VMA_ASSERT(expr)
    515  #endif
    516 #endif
    517 
    518 // Assert that will be called very often, like inside data structures e.g. operator[].
    519 // Making it non-empty can make program slow.
    520 #ifndef VMA_HEAVY_ASSERT
    521  #ifdef _DEBUG
    522  #define VMA_HEAVY_ASSERT(expr) //VMA_ASSERT(expr)
    523  #else
    524  #define VMA_HEAVY_ASSERT(expr)
    525  #endif
    526 #endif
    527 
    528 #ifndef VMA_NULL
    529  // Value used as null pointer. Define it to e.g.: nullptr, NULL, 0, (void*)0.
    530  #define VMA_NULL nullptr
    531 #endif
    532 
    533 #ifndef VMA_ALIGN_OF
    534  #define VMA_ALIGN_OF(type) (__alignof(type))
    535 #endif
    536 
    537 #ifndef VMA_SYSTEM_ALIGNED_MALLOC
    538  #if defined(_WIN32)
    539  #define VMA_SYSTEM_ALIGNED_MALLOC(size, alignment) (_aligned_malloc((size), (alignment)))
    540  #else
    541  #define VMA_SYSTEM_ALIGNED_MALLOC(size, alignment) (aligned_alloc((alignment), (size) ))
    542  #endif
    543 #endif
    544 
    545 #ifndef VMA_SYSTEM_FREE
    546  #if defined(_WIN32)
    547  #define VMA_SYSTEM_FREE(ptr) _aligned_free(ptr)
    548  #else
    549  #define VMA_SYSTEM_FREE(ptr) free(ptr)
    550  #endif
    551 #endif
    552 
    553 #ifndef VMA_MIN
    554  #define VMA_MIN(v1, v2) (std::min((v1), (v2)))
    555 #endif
    556 
    557 #ifndef VMA_MAX
    558  #define VMA_MAX(v1, v2) (std::max((v1), (v2)))
    559 #endif
    560 
    561 #ifndef VMA_SWAP
    562  #define VMA_SWAP(v1, v2) std::swap((v1), (v2))
    563 #endif
    564 
    565 #ifndef VMA_DEBUG_LOG
    566  #define VMA_DEBUG_LOG(format, ...)
    567  /*
    568  #define VMA_DEBUG_LOG(format, ...) do { \
    569  printf(format, __VA_ARGS__); \
    570  printf("\n"); \
    571  } while(false)
    572  */
    573 #endif
    574 
    575 // Define this macro to 1 to enable functions: vmaBuildStatsString, vmaFreeStatsString.
    576 #if VMA_STATS_STRING_ENABLED
    577  static inline void VmaUint32ToStr(char* outStr, size_t strLen, uint32_t num)
    578  {
    579  _ultoa_s(num, outStr, strLen, 10);
    580  }
    581  static inline void VmaUint64ToStr(char* outStr, size_t strLen, uint64_t num)
    582  {
    583  _ui64toa_s(num, outStr, strLen, 10);
    584  }
    585 #endif
    586 
    587 #ifndef VMA_MUTEX
    588  class VmaMutex
    589  {
    590  public:
    591  VmaMutex() { }
    592  ~VmaMutex() { }
    593  void Lock() { m_Mutex.lock(); }
    594  void Unlock() { m_Mutex.unlock(); }
    595  private:
    596  std::mutex m_Mutex;
    597  };
    598  #define VMA_MUTEX VmaMutex
    599 #endif
    600 
    601 #ifndef VMA_BEST_FIT
    602 
    614  #define VMA_BEST_FIT (1)
    615 #endif
    616 
    617 #ifndef VMA_DEBUG_ALWAYS_OWN_MEMORY
    618 
    622  #define VMA_DEBUG_ALWAYS_OWN_MEMORY (0)
    623 #endif
    624 
    625 #ifndef VMA_DEBUG_ALIGNMENT
    626 
    630  #define VMA_DEBUG_ALIGNMENT (1)
    631 #endif
    632 
    633 #ifndef VMA_DEBUG_MARGIN
    634 
    638  #define VMA_DEBUG_MARGIN (0)
    639 #endif
    640 
    641 #ifndef VMA_DEBUG_GLOBAL_MUTEX
    642 
    646  #define VMA_DEBUG_GLOBAL_MUTEX (0)
    647 #endif
    648 
    649 #ifndef VMA_DEBUG_MIN_BUFFER_IMAGE_GRANULARITY
    650 
    654  #define VMA_DEBUG_MIN_BUFFER_IMAGE_GRANULARITY (1)
    655 #endif
    656 
    657 #ifndef VMA_SMALL_HEAP_MAX_SIZE
    658  #define VMA_SMALL_HEAP_MAX_SIZE (512 * 1024 * 1024)
    660 #endif
    661 
    662 #ifndef VMA_DEFAULT_LARGE_HEAP_BLOCK_SIZE
    663  #define VMA_DEFAULT_LARGE_HEAP_BLOCK_SIZE (256 * 1024 * 1024)
    665 #endif
    666 
    667 #ifndef VMA_DEFAULT_SMALL_HEAP_BLOCK_SIZE
    668  #define VMA_DEFAULT_SMALL_HEAP_BLOCK_SIZE (64 * 1024 * 1024)
    670 #endif
    671 
    672 /*******************************************************************************
    673 END OF CONFIGURATION
    674 */
    675 
    676 static VkAllocationCallbacks VmaEmptyAllocationCallbacks = {
    677  VMA_NULL, VMA_NULL, VMA_NULL, VMA_NULL, VMA_NULL, VMA_NULL };
    678 
    679 // Returns number of bits set to 1 in (v).
    680 static inline uint32_t CountBitsSet(uint32_t v)
    681 {
    682  uint32_t c = v - ((v >> 1) & 0x55555555);
    683  c = ((c >> 2) & 0x33333333) + (c & 0x33333333);
    684  c = ((c >> 4) + c) & 0x0F0F0F0F;
    685  c = ((c >> 8) + c) & 0x00FF00FF;
    686  c = ((c >> 16) + c) & 0x0000FFFF;
    687  return c;
    688 }
    689 
    690 // Aligns given value up to nearest multiply of align value. For example: VmaAlignUp(11, 8) = 16.
    691 // Use types like uint32_t, uint64_t as T.
    692 template <typename T>
    693 static inline T VmaAlignUp(T val, T align)
    694 {
    695  return (val + align - 1) / align * align;
    696 }
    697 
    698 // Division with mathematical rounding to nearest number.
    699 template <typename T>
    700 inline T VmaRoundDiv(T x, T y)
    701 {
    702  return (x + (y / (T)2)) / y;
    703 }
    704 /*
    705 Returns true if two memory blocks occupy overlapping pages.
    706 ResourceA must be in less memory offset than ResourceB.
    707 
    708 Algorithm is based on "Vulkan 1.0.39 - A Specification (with all registered Vulkan extensions)"
    709 chapter 11.6 "Resource Memory Association", paragraph "Buffer-Image Granularity".
    710 */
    711 static inline bool VmaBlocksOnSamePage(
    712  VkDeviceSize resourceAOffset,
    713  VkDeviceSize resourceASize,
    714  VkDeviceSize resourceBOffset,
    715  VkDeviceSize pageSize)
    716 {
    717  VMA_ASSERT(resourceAOffset + resourceASize <= resourceBOffset && resourceASize > 0 && pageSize > 0);
    718  VkDeviceSize resourceAEnd = resourceAOffset + resourceASize - 1;
    719  VkDeviceSize resourceAEndPage = resourceAEnd & ~(pageSize - 1);
    720  VkDeviceSize resourceBStart = resourceBOffset;
    721  VkDeviceSize resourceBStartPage = resourceBStart & ~(pageSize - 1);
    722  return resourceAEndPage == resourceBStartPage;
    723 }
    724 
    725 enum VmaSuballocationType
    726 {
    727  VMA_SUBALLOCATION_TYPE_FREE = 0,
    728  VMA_SUBALLOCATION_TYPE_UNKNOWN = 1,
    729  VMA_SUBALLOCATION_TYPE_BUFFER = 2,
    730  VMA_SUBALLOCATION_TYPE_IMAGE_UNKNOWN = 3,
    731  VMA_SUBALLOCATION_TYPE_IMAGE_LINEAR = 4,
    732  VMA_SUBALLOCATION_TYPE_IMAGE_OPTIMAL = 5,
    733  VMA_SUBALLOCATION_TYPE_MAX_ENUM = 0x7FFFFFFF
    734 };
    735 
    736 /*
    737 Returns true if given suballocation types could conflict and must respect
    738 VkPhysicalDeviceLimits::bufferImageGranularity. They conflict if one is buffer
    739 or linear image and another one is optimal image. If type is unknown, behave
    740 conservatively.
    741 */
    742 static inline bool VmaIsBufferImageGranularityConflict(
    743  VmaSuballocationType suballocType1,
    744  VmaSuballocationType suballocType2)
    745 {
    746  if(suballocType1 > suballocType2)
    747  VMA_SWAP(suballocType1, suballocType2);
    748 
    749  switch(suballocType1)
    750  {
    751  case VMA_SUBALLOCATION_TYPE_FREE:
    752  return false;
    753  case VMA_SUBALLOCATION_TYPE_UNKNOWN:
    754  return true;
    755  case VMA_SUBALLOCATION_TYPE_BUFFER:
    756  return
    757  suballocType2 == VMA_SUBALLOCATION_TYPE_IMAGE_UNKNOWN ||
    758  suballocType2 == VMA_SUBALLOCATION_TYPE_IMAGE_OPTIMAL;
    759  case VMA_SUBALLOCATION_TYPE_IMAGE_UNKNOWN:
    760  return
    761  suballocType2 == VMA_SUBALLOCATION_TYPE_IMAGE_UNKNOWN ||
    762  suballocType2 == VMA_SUBALLOCATION_TYPE_IMAGE_LINEAR ||
    763  suballocType2 == VMA_SUBALLOCATION_TYPE_IMAGE_OPTIMAL;
    764  case VMA_SUBALLOCATION_TYPE_IMAGE_LINEAR:
    765  return
    766  suballocType2 == VMA_SUBALLOCATION_TYPE_IMAGE_OPTIMAL;
    767  case VMA_SUBALLOCATION_TYPE_IMAGE_OPTIMAL:
    768  return false;
    769  default:
    770  VMA_ASSERT(0);
    771  return true;
    772  }
    773 }
    774 
    775 // Helper RAII class to lock a mutex in constructor and unlock it in destructor (at the end of scope).
    776 struct VmaMutexLock
    777 {
    778 public:
    779  VmaMutexLock(VMA_MUTEX& mutex) : m_Mutex(mutex) { mutex.Lock(); }
    780  ~VmaMutexLock() { m_Mutex.Unlock(); }
    781 
    782 private:
    783  VMA_MUTEX& m_Mutex;
    784 };
    785 
    786 #if VMA_DEBUG_GLOBAL_MUTEX
    787  static VMA_MUTEX gDebugGlobalMutex;
    788  #define VMA_DEBUG_GLOBAL_MUTEX_LOCK VmaMutexLock debugGlobalMutexLock(gDebugGlobalMutex);
    789 #else
    790  #define VMA_DEBUG_GLOBAL_MUTEX_LOCK
    791 #endif
    792 
    793 // Minimum size of a free suballocation to register it in the free suballocation collection.
    794 static const VkDeviceSize VMA_MIN_FREE_SUBALLOCATION_SIZE_TO_REGISTER = 16;
    795 
    796 /*
    797 Performs binary search and returns iterator to first element that is greater or
    798 equal to (key), according to comparison (cmp).
    799 
    800 Cmp should return true if first argument is less than second argument.
    801 
    802 Returned value is the found element, if present in the collection or place where
    803 new element with value (key) should be inserted.
    804 */
    805 template <typename IterT, typename KeyT, typename CmpT>
    806 static IterT VmaBinaryFindFirstNotLess(IterT beg, IterT end, const KeyT &key, CmpT cmp)
    807 {
    808  size_t down = 0, up = (end - beg);
    809  while(down < up)
    810  {
    811  const size_t mid = (down + up) / 2;
    812  if(cmp(*(beg+mid), key))
    813  down = mid + 1;
    814  else
    815  up = mid;
    816  }
    817  return beg + down;
    818 }
    819 
    821 // Memory allocation
    822 
    823 static void* VmaMalloc(const VkAllocationCallbacks* pAllocationCallbacks, size_t size, size_t alignment)
    824 {
    825  if((pAllocationCallbacks != VMA_NULL) &&
    826  (pAllocationCallbacks->pfnAllocation != VMA_NULL))
    827  {
    828  return (*pAllocationCallbacks->pfnAllocation)(
    829  pAllocationCallbacks->pUserData,
    830  size,
    831  alignment,
    832  VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
    833  }
    834  else
    835  {
    836  return VMA_SYSTEM_ALIGNED_MALLOC(size, alignment);
    837  }
    838 }
    839 
    840 static void VmaFree(const VkAllocationCallbacks* pAllocationCallbacks, void* ptr)
    841 {
    842  if((pAllocationCallbacks != VMA_NULL) &&
    843  (pAllocationCallbacks->pfnFree != VMA_NULL))
    844  {
    845  (*pAllocationCallbacks->pfnFree)(pAllocationCallbacks->pUserData, ptr);
    846  }
    847  else
    848  {
    849  VMA_SYSTEM_FREE(ptr);
    850  }
    851 }
    852 
    853 template<typename T>
    854 static T* VmaAllocate(const VkAllocationCallbacks* pAllocationCallbacks)
    855 {
    856  return (T*)VmaMalloc(pAllocationCallbacks, sizeof(T), VMA_ALIGN_OF(T));
    857 }
    858 
    859 template<typename T>
    860 static T* VmaAllocateArray(const VkAllocationCallbacks* pAllocationCallbacks, size_t count)
    861 {
    862  return (T*)VmaMalloc(pAllocationCallbacks, sizeof(T) * count, VMA_ALIGN_OF(T));
    863 }
    864 
    865 #define vma_new(allocator, type) new(VmaAllocate<type>(allocator))(type)
    866 
    867 #define vma_new_array(allocator, type, count) new(VmaAllocateArray<type>((allocator), (count)))(type)
    868 
    869 template<typename T>
    870 static void vma_delete(const VkAllocationCallbacks* pAllocationCallbacks, T* ptr)
    871 {
    872  ptr->~T();
    873  VmaFree(pAllocationCallbacks, ptr);
    874 }
    875 
    876 template<typename T>
    877 static void vma_delete_array(const VkAllocationCallbacks* pAllocationCallbacks, T* ptr, size_t count)
    878 {
    879  if(ptr != VMA_NULL)
    880  {
    881  for(size_t i = count; i--; )
    882  ptr[i].~T();
    883  VmaFree(pAllocationCallbacks, ptr);
    884  }
    885 }
    886 
    887 // STL-compatible allocator.
    888 template<typename T>
    889 class VmaStlAllocator
    890 {
    891 public:
    892  const VkAllocationCallbacks* const m_pCallbacks;
    893  typedef T value_type;
    894 
    895  VmaStlAllocator(const VkAllocationCallbacks* pCallbacks) : m_pCallbacks(pCallbacks) { }
    896  template<typename U> VmaStlAllocator(const VmaStlAllocator<U>& src) : m_pCallbacks(src.m_pCallbacks) { }
    897 
    898  T* allocate(size_t n) { return VmaAllocateArray<T>(m_pCallbacks, n); }
    899  void deallocate(T* p, size_t n) { VmaFree(m_pCallbacks, p); }
    900 
    901  template<typename U>
    902  bool operator==(const VmaStlAllocator<U>& rhs) const
    903  {
    904  return m_pCallbacks == rhs.m_pCallbacks;
    905  }
    906  template<typename U>
    907  bool operator!=(const VmaStlAllocator<U>& rhs) const
    908  {
    909  return m_pCallbacks != rhs.m_pCallbacks;
    910  }
    911 
    912  VmaStlAllocator& operator=(const VmaStlAllocator& x) = delete;
    913 };
    914 
    915 #if VMA_USE_STL_VECTOR
    916 
    917 #define VmaVector std::vector
    918 
    919 template<typename T, typename allocatorT>
    920 static void VectorInsert(std::vector<T, allocatorT>& vec, size_t index, const T& item)
    921 {
    922  vec.insert(vec.begin() + index, item);
    923 }
    924 
    925 template<typename T, typename allocatorT>
    926 static void VectorRemove(std::vector<T, allocatorT>& vec, size_t index)
    927 {
    928  vec.erase(vec.begin() + index);
    929 }
    930 
    931 #else // #if VMA_USE_STL_VECTOR
    932 
    933 /* Class with interface compatible with subset of std::vector.
    934 T must be POD because constructors and destructors are not called and memcpy is
    935 used for these objects. */
    936 template<typename T, typename AllocatorT>
    937 class VmaVector
    938 {
    939 public:
    940  VmaVector(const AllocatorT& allocator) :
    941  m_Allocator(allocator),
    942  m_pArray(VMA_NULL),
    943  m_Count(0),
    944  m_Capacity(0)
    945  {
    946  }
    947 
    948  VmaVector(AllocatorT& allocator) :
    949  m_Allocator(allocator),
    950  m_pArray(VMA_NULL),
    951  m_Count(0),
    952  m_Capacity(0)
    953  {
    954  }
    955 
    956  VmaVector(size_t count, AllocatorT& allocator) :
    957  m_Allocator(allocator),
    958  m_pArray(count ? (T*)VmaAllocateArray<T>(allocator->m_pCallbacks, count) : VMA_NULL),
    959  m_Count(count),
    960  m_Capacity(count)
    961  {
    962  }
    963 
    964  VmaVector(const VmaVector<T, AllocatorT>& src) :
    965  m_Allocator(src.m_Allocator),
    966  m_pArray(src.m_Count ? (T*)VmaAllocateArray<T>(src->m_pCallbacks, src.m_Count) : VMA_NULL),
    967  m_Count(src.m_Count),
    968  m_Capacity(src.m_Count)
    969  {
    970  if(m_Count != 0)
    971  memcpy(m_pArray, src.m_pArray, m_Count * sizeof(T));
    972  }
    973 
    974  ~VmaVector()
    975  {
    976  VmaFree(m_Allocator.m_pCallbacks, m_pArray);
    977  }
    978 
    979  VmaVector& operator=(const VmaVector<T, AllocatorT>& rhs)
    980  {
    981  if(&rhs != this)
    982  {
    983  Resize(rhs.m_Count);
    984  if(m_Count != 0)
    985  memcpy(m_pArray, rhs.m_pArray, m_Count * sizeof(T));
    986  }
    987  return *this;
    988  }
    989 
    990  bool empty() const { return m_Count == 0; }
    991  size_t size() const { return m_Count; }
    992  T* data() { return m_pArray; }
    993  const T* data() const { return m_pArray; }
    994 
    995  T& operator[](size_t index)
    996  {
    997  VMA_HEAVY_ASSERT(index < m_Count);
    998  return m_pArray[index];
    999  }
    1000  const T& operator[](size_t index) const
    1001  {
    1002  VMA_HEAVY_ASSERT(index < m_Count);
    1003  return m_pArray[index];
    1004  }
    1005 
    1006  T& front()
    1007  {
    1008  VMA_HEAVY_ASSERT(m_Count > 0);
    1009  return m_pArray[0];
    1010  }
    1011  const T& front() const
    1012  {
    1013  VMA_HEAVY_ASSERT(m_Count > 0);
    1014  return m_pArray[0];
    1015  }
    1016  T& back()
    1017  {
    1018  VMA_HEAVY_ASSERT(m_Count > 0);
    1019  return m_pArray[m_Count - 1];
    1020  }
    1021  const T& back() const
    1022  {
    1023  VMA_HEAVY_ASSERT(m_Count > 0);
    1024  return m_pArray[m_Count - 1];
    1025  }
    1026 
    1027  void reserve(size_t newCapacity, bool freeMemory = false)
    1028  {
    1029  newCapacity = VMA_MAX(newCapacity, m_Count);
    1030 
    1031  if((newCapacity < m_Capacity) && !freeMemory)
    1032  newCapacity = m_Capacity;
    1033 
    1034  if(newCapacity != m_Capacity)
    1035  {
    1036  T* const newArray = newCapacity ? VmaAllocateArray<T>(m_Allocator, newCapacity) : VMA_NULL;
    1037  if(m_Count != 0)
    1038  memcpy(newArray, m_pArray, m_Count * sizeof(T));
    1039  VmaFree(m_Allocator.m_pCallbacks, m_pArray);
    1040  m_Capacity = newCapacity;
    1041  m_pArray = newArray;
    1042  }
    1043  }
    1044 
    1045  void resize(size_t newCount, bool freeMemory = false)
    1046  {
    1047  size_t newCapacity = m_Capacity;
    1048  if(newCount > m_Capacity)
    1049  newCapacity = VMA_MAX(newCount, VMA_MAX(m_Capacity * 3 / 2, (size_t)8));
    1050  else if(freeMemory)
    1051  newCapacity = newCount;
    1052 
    1053  if(newCapacity != m_Capacity)
    1054  {
    1055  T* const newArray = newCapacity ? VmaAllocateArray<T>(m_Allocator.m_pCallbacks, newCapacity) : VMA_NULL;
    1056  const size_t elementsToCopy = VMA_MIN(m_Count, newCount);
    1057  if(elementsToCopy != 0)
    1058  memcpy(newArray, m_pArray, elementsToCopy * sizeof(T));
    1059  VmaFree(m_Allocator.m_pCallbacks, m_pArray);
    1060  m_Capacity = newCapacity;
    1061  m_pArray = newArray;
    1062  }
    1063 
    1064  m_Count = newCount;
    1065  }
    1066 
    1067  void clear(bool freeMemory = false)
    1068  {
    1069  resize(0, freeMemory);
    1070  }
    1071 
    1072  void insert(size_t index, const T& src)
    1073  {
    1074  VMA_HEAVY_ASSERT(index <= m_Count);
    1075  const size_t oldCount = size();
    1076  resize(oldCount + 1);
    1077  if(index < oldCount)
    1078  memmove(m_pArray + (index + 1), m_pArray + index, (oldCount - index) * sizeof(T));
    1079  m_pArray[index] = src;
    1080  }
    1081 
    1082  void remove(size_t index)
    1083  {
    1084  VMA_HEAVY_ASSERT(index < m_Count);
    1085  const size_t oldCount = size();
    1086  if(index < oldCount - 1)
    1087  memmove(m_pArray + index, m_pArray + (index + 1), (oldCount - index - 1) * sizeof(T));
    1088  resize(oldCount - 1);
    1089  }
    1090 
    1091  void push_back(const T& src)
    1092  {
    1093  const size_t newIndex = size();
    1094  resize(newIndex + 1);
    1095  m_pArray[newIndex] = src;
    1096  }
    1097 
    1098  void pop_back()
    1099  {
    1100  VMA_HEAVY_ASSERT(m_Count > 0);
    1101  resize(size() - 1);
    1102  }
    1103 
    1104  void push_front(const T& src)
    1105  {
    1106  insert(0, src);
    1107  }
    1108 
    1109  void pop_front()
    1110  {
    1111  VMA_HEAVY_ASSERT(m_Count > 0);
    1112  remove(0);
    1113  }
    1114 
    1115  typedef T* iterator;
    1116 
    1117  iterator begin() { return m_pArray; }
    1118  iterator end() { return m_pArray + m_Count; }
    1119 
    1120 private:
    1121  AllocatorT m_Allocator;
    1122  T* m_pArray;
    1123  size_t m_Count;
    1124  size_t m_Capacity;
    1125 };
    1126 
    1127 template<typename T, typename allocatorT>
    1128 static void VectorInsert(VmaVector<T, allocatorT>& vec, size_t index, const T& item)
    1129 {
    1130  vec.insert(index, item);
    1131 }
    1132 
    1133 template<typename T, typename allocatorT>
    1134 static void VectorRemove(VmaVector<T, allocatorT>& vec, size_t index)
    1135 {
    1136  vec.remove(index);
    1137 }
    1138 
    1139 #endif // #if VMA_USE_STL_VECTOR
    1140 
    1142 // class VmaPoolAllocator
    1143 
    1144 /*
    1145 Allocator for objects of type T using a list of arrays (pools) to speed up
    1146 allocation. Number of elements that can be allocated is not bounded because
    1147 allocator can create multiple blocks.
    1148 */
    1149 template<typename T>
    1150 class VmaPoolAllocator
    1151 {
    1152 public:
    1153  VmaPoolAllocator(const VkAllocationCallbacks* pAllocationCallbacks, size_t itemsPerBlock);
    1154  ~VmaPoolAllocator();
    1155  void Clear();
    1156  T* Alloc();
    1157  void Free(T* ptr);
    1158 
    1159 private:
    1160  union Item
    1161  {
    1162  uint32_t NextFreeIndex;
    1163  T Value;
    1164  };
    1165 
    1166  struct ItemBlock
    1167  {
    1168  Item* pItems;
    1169  uint32_t FirstFreeIndex;
    1170  };
    1171 
    1172  const VkAllocationCallbacks* m_pAllocationCallbacks;
    1173  size_t m_ItemsPerBlock;
    1174  VmaVector< ItemBlock, VmaStlAllocator<ItemBlock> > m_ItemBlocks;
    1175 
    1176  ItemBlock& CreateNewBlock();
    1177 };
    1178 
    1179 template<typename T>
    1180 VmaPoolAllocator<T>::VmaPoolAllocator(const VkAllocationCallbacks* pAllocationCallbacks, size_t itemsPerBlock) :
    1181  m_pAllocationCallbacks(pAllocationCallbacks),
    1182  m_ItemsPerBlock(itemsPerBlock),
    1183  m_ItemBlocks(VmaStlAllocator<ItemBlock>(pAllocationCallbacks))
    1184 {
    1185  VMA_ASSERT(itemsPerBlock > 0);
    1186 }
    1187 
    1188 template<typename T>
    1189 VmaPoolAllocator<T>::~VmaPoolAllocator()
    1190 {
    1191  Clear();
    1192 }
    1193 
    1194 template<typename T>
    1195 void VmaPoolAllocator<T>::Clear()
    1196 {
    1197  for(size_t i = m_ItemBlocks.size(); i--; )
    1198  vma_delete_array(m_pAllocationCallbacks, m_ItemBlocks[i].pItems, m_ItemsPerBlock);
    1199  m_ItemBlocks.clear();
    1200 }
    1201 
    1202 template<typename T>
    1203 T* VmaPoolAllocator<T>::Alloc()
    1204 {
    1205  for(size_t i = m_ItemBlocks.size(); i--; )
    1206  {
    1207  ItemBlock& block = m_ItemBlocks[i];
    1208  // This block has some free items: Use first one.
    1209  if(block.FirstFreeIndex != UINT32_MAX)
    1210  {
    1211  Item* const pItem = &block.pItems[block.FirstFreeIndex];
    1212  block.FirstFreeIndex = pItem->NextFreeIndex;
    1213  return &pItem->Value;
    1214  }
    1215  }
    1216 
    1217  // No block has free item: Create new one and use it.
    1218  ItemBlock& newBlock = CreateNewBlock();
    1219  Item* const pItem = &newBlock.pItems[0];
    1220  newBlock.FirstFreeIndex = pItem->NextFreeIndex;
    1221  return &pItem->Value;
    1222 }
    1223 
    1224 template<typename T>
    1225 void VmaPoolAllocator<T>::Free(T* ptr)
    1226 {
    1227  // Search all memory blocks to find ptr.
    1228  for(size_t i = 0; i < m_ItemBlocks.size(); ++i)
    1229  {
    1230  ItemBlock& block = m_ItemBlocks[i];
    1231 
    1232  // Casting to union.
    1233  Item* pItemPtr;
    1234  memcpy(&pItemPtr, &ptr, sizeof(pItemPtr));
    1235 
    1236  // Check if pItemPtr is in address range of this block.
    1237  if((pItemPtr >= block.pItems) && (pItemPtr < block.pItems + m_ItemsPerBlock))
    1238  {
    1239  const uint32_t index = static_cast<uint32_t>(pItemPtr - block.pItems);
    1240  pItemPtr->NextFreeIndex = block.FirstFreeIndex;
    1241  block.FirstFreeIndex = index;
    1242  return;
    1243  }
    1244  }
    1245  VMA_ASSERT(0 && "Pointer doesn't belong to this memory pool.");
    1246 }
    1247 
    1248 template<typename T>
    1249 typename VmaPoolAllocator<T>::ItemBlock& VmaPoolAllocator<T>::CreateNewBlock()
    1250 {
    1251  ItemBlock newBlock = {
    1252  vma_new_array(m_pAllocationCallbacks, Item, m_ItemsPerBlock), 0 };
    1253 
    1254  m_ItemBlocks.push_back(newBlock);
    1255 
    1256  // Setup singly-linked list of all free items in this block.
    1257  for(uint32_t i = 0; i < m_ItemsPerBlock - 1; ++i)
    1258  newBlock.pItems[i].NextFreeIndex = i + 1;
    1259  newBlock.pItems[m_ItemsPerBlock - 1].NextFreeIndex = UINT32_MAX;
    1260  return m_ItemBlocks.back();
    1261 }
    1262 
    1264 // class VmaRawList, VmaList
    1265 
    1266 #if VMA_USE_STL_LIST
    1267 
    1268 #define VmaList std::list
    1269 
    1270 #else // #if VMA_USE_STL_LIST
    1271 
    1272 template<typename T>
    1273 struct VmaListItem
    1274 {
    1275  VmaListItem* pPrev;
    1276  VmaListItem* pNext;
    1277  T Value;
    1278 };
    1279 
    1280 // Doubly linked list.
    1281 template<typename T>
    1282 class VmaRawList
    1283 {
    1284 public:
    1285  typedef VmaListItem<T> ItemType;
    1286 
    1287  VmaRawList(const VkAllocationCallbacks* pAllocationCallbacks);
    1288  ~VmaRawList();
    1289  void Clear();
    1290 
    1291  size_t GetCount() const { return m_Count; }
    1292  bool IsEmpty() const { return m_Count == 0; }
    1293 
    1294  ItemType* Front() { return m_pFront; }
    1295  const ItemType* Front() const { return m_pFront; }
    1296  ItemType* Back() { return m_pBack; }
    1297  const ItemType* Back() const { return m_pBack; }
    1298 
    1299  ItemType* PushBack();
    1300  ItemType* PushFront();
    1301  ItemType* PushBack(const T& value);
    1302  ItemType* PushFront(const T& value);
    1303  void PopBack();
    1304  void PopFront();
    1305 
    1306  // Item can be null - it means PushBack.
    1307  ItemType* InsertBefore(ItemType* pItem);
    1308  // Item can be null - it means PushFront.
    1309  ItemType* InsertAfter(ItemType* pItem);
    1310 
    1311  ItemType* InsertBefore(ItemType* pItem, const T& value);
    1312  ItemType* InsertAfter(ItemType* pItem, const T& value);
    1313 
    1314  void Remove(ItemType* pItem);
    1315 
    1316 private:
    1317  const VkAllocationCallbacks* const m_pAllocationCallbacks;
    1318  VmaPoolAllocator<ItemType> m_ItemAllocator;
    1319  ItemType* m_pFront;
    1320  ItemType* m_pBack;
    1321  size_t m_Count;
    1322 
    1323  // Declared not defined, to block copy constructor and assignment operator.
    1324  VmaRawList(const VmaRawList<T>& src);
    1325  VmaRawList<T>& operator=(const VmaRawList<T>& rhs);
    1326 };
    1327 
    1328 template<typename T>
    1329 VmaRawList<T>::VmaRawList(const VkAllocationCallbacks* pAllocationCallbacks) :
    1330  m_pAllocationCallbacks(pAllocationCallbacks),
    1331  m_ItemAllocator(pAllocationCallbacks, 128),
    1332  m_pFront(VMA_NULL),
    1333  m_pBack(VMA_NULL),
    1334  m_Count(0)
    1335 {
    1336 }
    1337 
    1338 template<typename T>
    1339 VmaRawList<T>::~VmaRawList()
    1340 {
    1341  // Intentionally not calling Clear, because that would be unnecessary
    1342  // computations to return all items to m_ItemAllocator as free.
    1343 }
    1344 
    1345 template<typename T>
    1346 void VmaRawList<T>::Clear()
    1347 {
    1348  if(IsEmpty() == false)
    1349  {
    1350  ItemType* pItem = m_pBack;
    1351  while(pItem != VMA_NULL)
    1352  {
    1353  ItemType* const pPrevItem = pItem->pPrev;
    1354  m_ItemAllocator.Free(pItem);
    1355  pItem = pPrevItem;
    1356  }
    1357  m_pFront = VMA_NULL;
    1358  m_pBack = VMA_NULL;
    1359  m_Count = 0;
    1360  }
    1361 }
    1362 
    1363 template<typename T>
    1364 VmaListItem<T>* VmaRawList<T>::PushBack()
    1365 {
    1366  ItemType* const pNewItem = m_ItemAllocator.Alloc();
    1367  pNewItem->pNext = VMA_NULL;
    1368  if(IsEmpty())
    1369  {
    1370  pNewItem->pPrev = VMA_NULL;
    1371  m_pFront = pNewItem;
    1372  m_pBack = pNewItem;
    1373  m_Count = 1;
    1374  }
    1375  else
    1376  {
    1377  pNewItem->pPrev = m_pBack;
    1378  m_pBack->pNext = pNewItem;
    1379  m_pBack = pNewItem;
    1380  ++m_Count;
    1381  }
    1382  return pNewItem;
    1383 }
    1384 
    1385 template<typename T>
    1386 VmaListItem<T>* VmaRawList<T>::PushFront()
    1387 {
    1388  ItemType* const pNewItem = m_ItemAllocator.Alloc();
    1389  pNewItem->pPrev = VMA_NULL;
    1390  if(IsEmpty())
    1391  {
    1392  pNewItem->pNext = VMA_NULL;
    1393  m_pFront = pNewItem;
    1394  m_pBack = pNewItem;
    1395  m_Count = 1;
    1396  }
    1397  else
    1398  {
    1399  pNewItem->pNext = m_pFront;
    1400  m_pFront->pPrev = pNewItem;
    1401  m_pFront = pNewItem;
    1402  ++m_Count;
    1403  }
    1404  return pNewItem;
    1405 }
    1406 
    1407 template<typename T>
    1408 VmaListItem<T>* VmaRawList<T>::PushBack(const T& value)
    1409 {
    1410  ItemType* const pNewItem = PushBack();
    1411  pNewItem->Value = value;
    1412  return pNewItem;
    1413 }
    1414 
    1415 template<typename T>
    1416 VmaListItem<T>* VmaRawList<T>::PushFront(const T& value)
    1417 {
    1418  ItemType* const pNewItem = PushFront();
    1419  pNewItem->Value = value;
    1420  return pNewItem;
    1421 }
    1422 
    1423 template<typename T>
    1424 void VmaRawList<T>::PopBack()
    1425 {
    1426  VMA_HEAVY_ASSERT(m_Count > 0);
    1427  ItemType* const pBackItem = m_pBack;
    1428  ItemType* const pPrevItem = pBackItem->pPrev;
    1429  if(pPrevItem != VMA_NULL)
    1430  pPrevItem->pNext = VMA_NULL;
    1431  m_pBack = pPrevItem;
    1432  m_ItemAllocator.Free(pBackItem);
    1433  --m_Count;
    1434 }
    1435 
    1436 template<typename T>
    1437 void VmaRawList<T>::PopFront()
    1438 {
    1439  VMA_HEAVY_ASSERT(m_Count > 0);
    1440  ItemType* const pFrontItem = m_pFront;
    1441  ItemType* const pNextItem = pFrontItem->pNext;
    1442  if(pNextItem != VMA_NULL)
    1443  pNextItem->pPrev = VMA_NULL;
    1444  m_pFront = pNextItem;
    1445  m_ItemAllocator.Free(pFrontItem);
    1446  --m_Count;
    1447 }
    1448 
    1449 template<typename T>
    1450 void VmaRawList<T>::Remove(ItemType* pItem)
    1451 {
    1452  VMA_HEAVY_ASSERT(pItem != VMA_NULL);
    1453  VMA_HEAVY_ASSERT(m_Count > 0);
    1454 
    1455  if(pItem->pPrev != VMA_NULL)
    1456  pItem->pPrev->pNext = pItem->pNext;
    1457  else
    1458  {
    1459  VMA_HEAVY_ASSERT(m_pFront == pItem);
    1460  m_pFront = pItem->pNext;
    1461  }
    1462 
    1463  if(pItem->pNext != VMA_NULL)
    1464  pItem->pNext->pPrev = pItem->pPrev;
    1465  else
    1466  {
    1467  VMA_HEAVY_ASSERT(m_pBack == pItem);
    1468  m_pBack = pItem->pPrev;
    1469  }
    1470 
    1471  m_ItemAllocator.Free(pItem);
    1472  --m_Count;
    1473 }
    1474 
    1475 template<typename T>
    1476 VmaListItem<T>* VmaRawList<T>::InsertBefore(ItemType* pItem)
    1477 {
    1478  if(pItem != VMA_NULL)
    1479  {
    1480  ItemType* const prevItem = pItem->pPrev;
    1481  ItemType* const newItem = m_ItemAllocator.Alloc();
    1482  newItem->pPrev = prevItem;
    1483  newItem->pNext = pItem;
    1484  pItem->pPrev = newItem;
    1485  if(prevItem != VMA_NULL)
    1486  prevItem->pNext = newItem;
    1487  else
    1488  {
    1489  VMA_HEAVY_ASSERT(m_pFront = pItem);
    1490  m_pFront = newItem;
    1491  }
    1492  ++m_Count;
    1493  return newItem;
    1494  }
    1495  else
    1496  return PushBack();
    1497 }
    1498 
    1499 template<typename T>
    1500 VmaListItem<T>* VmaRawList<T>::InsertAfter(ItemType* pItem)
    1501 {
    1502  if(pItem != VMA_NULL)
    1503  {
    1504  ItemType* const nextItem = pItem->pNext;
    1505  ItemType* const newItem = m_ItemAllocator.Alloc();
    1506  newItem->pNext = nextItem;
    1507  newItem->pPrev = pItem;
    1508  pItem->pNext = newItem;
    1509  if(nextItem != VMA_NULL)
    1510  nextItem->pPrev = newItem;
    1511  else
    1512  {
    1513  VMA_HEAVY_ASSERT(m_pBack = pItem);
    1514  m_pBack = newItem;
    1515  }
    1516  ++m_Count;
    1517  return newItem;
    1518  }
    1519  else
    1520  return PushFront();
    1521 }
    1522 
    1523 template<typename T>
    1524 VmaListItem<T>* VmaRawList<T>::InsertBefore(ItemType* pItem, const T& value)
    1525 {
    1526  ItemType* const newItem = InsertBefore(pItem);
    1527  newItem->Value = value;
    1528  return newItem;
    1529 }
    1530 
    1531 template<typename T>
    1532 VmaListItem<T>* VmaRawList<T>::InsertAfter(ItemType* pItem, const T& value)
    1533 {
    1534  ItemType* const newItem = InsertAfter(pItem);
    1535  newItem->Value = value;
    1536  return newItem;
    1537 }
    1538 
    1539 template<typename T, typename AllocatorT>
    1540 class VmaList
    1541 {
    1542 public:
    1543  class iterator
    1544  {
    1545  public:
    1546  iterator() :
    1547  m_pList(VMA_NULL),
    1548  m_pItem(VMA_NULL)
    1549  {
    1550  }
    1551 
    1552  T& operator*() const
    1553  {
    1554  VMA_HEAVY_ASSERT(m_pItem != VMA_NULL);
    1555  return m_pItem->Value;
    1556  }
    1557  T* operator->() const
    1558  {
    1559  VMA_HEAVY_ASSERT(m_pItem != VMA_NULL);
    1560  return &m_pItem->Value;
    1561  }
    1562 
    1563  iterator& operator++()
    1564  {
    1565  VMA_HEAVY_ASSERT(m_pItem != VMA_NULL);
    1566  m_pItem = m_pItem->pNext;
    1567  return *this;
    1568  }
    1569  iterator& operator--()
    1570  {
    1571  if(m_pItem != VMA_NULL)
    1572  m_pItem = m_pItem->pPrev;
    1573  else
    1574  {
    1575  VMA_HEAVY_ASSERT(!m_pList.IsEmpty());
    1576  m_pItem = m_pList->Back();
    1577  }
    1578  return *this;
    1579  }
    1580 
    1581  iterator operator++(int)
    1582  {
    1583  iterator result = *this;
    1584  ++*this;
    1585  return result;
    1586  }
    1587  iterator operator--(int)
    1588  {
    1589  iterator result = *this;
    1590  --*this;
    1591  return result;
    1592  }
    1593 
    1594  bool operator==(const iterator& rhs) const
    1595  {
    1596  VMA_HEAVY_ASSERT(m_pList == rhs.m_pList);
    1597  return m_pItem == rhs.m_pItem;
    1598  }
    1599  bool operator!=(const iterator& rhs) const
    1600  {
    1601  VMA_HEAVY_ASSERT(m_pList == rhs.m_pList);
    1602  return m_pItem != rhs.m_pItem;
    1603  }
    1604 
    1605  private:
    1606  VmaRawList<T>* m_pList;
    1607  VmaListItem<T>* m_pItem;
    1608 
    1609  iterator(VmaRawList<T>* pList, VmaListItem<T>* pItem) :
    1610  m_pList(pList),
    1611  m_pItem(pItem)
    1612  {
    1613  }
    1614 
    1615  friend class VmaList<T, AllocatorT>;
    1616  friend class VmaList<T, AllocatorT>:: const_iterator;
    1617  };
    1618 
    1619  class const_iterator
    1620  {
    1621  public:
    1622  const_iterator() :
    1623  m_pList(VMA_NULL),
    1624  m_pItem(VMA_NULL)
    1625  {
    1626  }
    1627 
    1628  const_iterator(const iterator& src) :
    1629  m_pList(src.m_pList),
    1630  m_pItem(src.m_pItem)
    1631  {
    1632  }
    1633 
    1634  const T& operator*() const
    1635  {
    1636  VMA_HEAVY_ASSERT(m_pItem != VMA_NULL);
    1637  return m_pItem->Value;
    1638  }
    1639  const T* operator->() const
    1640  {
    1641  VMA_HEAVY_ASSERT(m_pItem != VMA_NULL);
    1642  return &m_pItem->Value;
    1643  }
    1644 
    1645  const_iterator& operator++()
    1646  {
    1647  VMA_HEAVY_ASSERT(m_pItem != VMA_NULL);
    1648  m_pItem = m_pItem->pNext;
    1649  return *this;
    1650  }
    1651  const_iterator& operator--()
    1652  {
    1653  if(m_pItem != VMA_NULL)
    1654  m_pItem = m_pItem->pPrev;
    1655  else
    1656  {
    1657  VMA_HEAVY_ASSERT(!m_pList->IsEmpty());
    1658  m_pItem = m_pList->Back();
    1659  }
    1660  return *this;
    1661  }
    1662 
    1663  const_iterator operator++(int)
    1664  {
    1665  const_iterator result = *this;
    1666  ++*this;
    1667  return result;
    1668  }
    1669  const_iterator operator--(int)
    1670  {
    1671  const_iterator result = *this;
    1672  --*this;
    1673  return result;
    1674  }
    1675 
    1676  bool operator==(const const_iterator& rhs) const
    1677  {
    1678  VMA_HEAVY_ASSERT(m_pList == rhs.m_pList);
    1679  return m_pItem == rhs.m_pItem;
    1680  }
    1681  bool operator!=(const const_iterator& rhs) const
    1682  {
    1683  VMA_HEAVY_ASSERT(m_pList == rhs.m_pList);
    1684  return m_pItem != rhs.m_pItem;
    1685  }
    1686 
    1687  private:
    1688  const_iterator(const VmaRawList<T>* pList, const VmaListItem<T>* pItem) :
    1689  m_pList(pList),
    1690  m_pItem(pItem)
    1691  {
    1692  }
    1693 
    1694  const VmaRawList<T>* m_pList;
    1695  const VmaListItem<T>* m_pItem;
    1696 
    1697  friend class VmaList<T, AllocatorT>;
    1698  };
    1699 
    1700  VmaList(AllocatorT& allocator) : m_RawList(allocator.m_pCallbacks) { }
    1701  VmaList(const AllocatorT& allocator) : m_RawList(allocator.m_pCallbacks) { }
    1702 
    1703  bool empty() const { return m_RawList.IsEmpty(); }
    1704  size_t size() const { return m_RawList.GetCount(); }
    1705 
    1706  iterator begin() { return iterator(&m_RawList, m_RawList.Front()); }
    1707  iterator end() { return iterator(&m_RawList, VMA_NULL); }
    1708 
    1709  const_iterator cbegin() const { return const_iterator(&m_RawList, m_RawList.Front()); }
    1710  const_iterator cend() const { return const_iterator(&m_RawList, VMA_NULL); }
    1711 
    1712  void clear() { m_RawList.Clear(); }
    1713  void push_back(const T& value) { m_RawList.PushBack(value); }
    1714  void erase(iterator it) { m_RawList.Remove(it.m_pItem); }
    1715  iterator insert(iterator it, const T& value) { return iterator(&m_RawList, m_RawList.InsertBefore(it.m_pItem, value)); }
    1716 
    1717 private:
    1718  VmaRawList<T> m_RawList;
    1719 };
    1720 
    1721 #endif // #if VMA_USE_STL_LIST
    1722 
    1724 // class VmaMap
    1725 
    1726 #if VMA_USE_STL_UNORDERED_MAP
    1727 
    1728 #define VmaPair std::pair
    1729 
    1730 #define VMA_MAP_TYPE(KeyT, ValueT) \
    1731  std::unordered_map< KeyT, ValueT, std::hash<KeyT>, std::equal_to<KeyT>, VmaStlAllocator< std::pair<KeyT, ValueT> > >
    1732 
    1733 #else // #if VMA_USE_STL_UNORDERED_MAP
    1734 
    1735 template<typename T1, typename T2>
    1736 struct VmaPair
    1737 {
    1738  T1 first;
    1739  T2 second;
    1740 
    1741  VmaPair() : first(), second() { }
    1742  VmaPair(const T1& firstSrc, const T2& secondSrc) : first(firstSrc), second(secondSrc) { }
    1743 };
    1744 
    1745 /* Class compatible with subset of interface of std::unordered_map.
    1746 KeyT, ValueT must be POD because they will be stored in VmaVector.
    1747 */
    1748 template<typename KeyT, typename ValueT>
    1749 class VmaMap
    1750 {
    1751 public:
    1752  typedef VmaPair<KeyT, ValueT> PairType;
    1753  typedef PairType* iterator;
    1754 
    1755  VmaMap(VmaStlAllocator<PairType>& allocator) : m_Vector(allocator) { }
    1756  VmaMap(const VmaStlAllocator<PairType>& allocator) : m_Vector(allocator) { }
    1757 
    1758  iterator begin() { return m_Vector.begin(); }
    1759  iterator end() { return m_Vector.end(); }
    1760 
    1761  void insert(const PairType& pair);
    1762  iterator find(const KeyT& key);
    1763  void erase(iterator it);
    1764 
    1765 private:
    1766  VmaVector< PairType, VmaStlAllocator<PairType> > m_Vector;
    1767 };
    1768 
    1769 #define VMA_MAP_TYPE(KeyT, ValueT) VmaMap<KeyT, ValueT>
    1770 
    1771 template<typename FirstT, typename SecondT>
    1772 struct VmaPairFirstLess
    1773 {
    1774  bool operator()(const VmaPair<FirstT, SecondT>& lhs, const VmaPair<FirstT, SecondT>& rhs) const
    1775  {
    1776  return lhs.first < rhs.first;
    1777  }
    1778  bool operator()(const VmaPair<FirstT, SecondT>& lhs, const FirstT& rhsFirst) const
    1779  {
    1780  return lhs.first < rhsFirst;
    1781  }
    1782 };
    1783 
    1784 template<typename KeyT, typename ValueT>
    1785 void VmaMap<KeyT, ValueT>::insert(const PairType& pair)
    1786 {
    1787  const size_t indexToInsert = VmaBinaryFindFirstNotLess(
    1788  m_Vector.data(),
    1789  m_Vector.data() + m_Vector.size(),
    1790  pair,
    1791  VmaPairFirstLess<KeyT, ValueT>()) - m_Vector.data();
    1792  VectorInsert(m_Vector, indexToInsert, pair);
    1793 }
    1794 
    1795 template<typename KeyT, typename ValueT>
    1796 VmaPair<KeyT, ValueT>* VmaMap<KeyT, ValueT>::find(const KeyT& key)
    1797 {
    1798  PairType* it = VmaBinaryFindFirstNotLess(
    1799  m_Vector.data(),
    1800  m_Vector.data() + m_Vector.size(),
    1801  key,
    1802  VmaPairFirstLess<KeyT, ValueT>());
    1803  if((it != m_Vector.end()) && (it->first == key))
    1804  return it;
    1805  else
    1806  return m_Vector.end();
    1807 }
    1808 
    1809 template<typename KeyT, typename ValueT>
    1810 void VmaMap<KeyT, ValueT>::erase(iterator it)
    1811 {
    1812  VectorRemove(m_Vector, it - m_Vector.begin());
    1813 }
    1814 
    1815 #endif // #if VMA_USE_STL_UNORDERED_MAP
    1816 
    1817 /*
    1818 Represents a region of VmaAllocation that is either assigned and returned as
    1819 allocated memory block or free.
    1820 */
    1821 struct VmaSuballocation
    1822 {
    1823  VkDeviceSize offset;
    1824  VkDeviceSize size;
    1825  VmaSuballocationType type;
    1826 };
    1827 
    1828 typedef VmaList< VmaSuballocation, VmaStlAllocator<VmaSuballocation> > VmaSuballocationList;
    1829 
    1830 // Parameters of an allocation.
    1831 struct VmaAllocationRequest
    1832 {
    1833  VmaSuballocationList::iterator freeSuballocationItem;
    1834  VkDeviceSize offset;
    1835 };
    1836 
    1837 /* Single block of memory - VkDeviceMemory with all the data about its regions
    1838 assigned or free. */
    1839 class VmaAllocation
    1840 {
    1841 public:
    1842  VkDeviceMemory m_hMemory;
    1843  VkDeviceSize m_Size;
    1844  uint32_t m_FreeCount;
    1845  VkDeviceSize m_SumFreeSize;
    1846  VmaSuballocationList m_Suballocations;
    1847  // Suballocations that are free and have size greater than certain threshold.
    1848  // Sorted by size, ascending.
    1849  VmaVector< VmaSuballocationList::iterator, VmaStlAllocator< VmaSuballocationList::iterator > > m_FreeSuballocationsBySize;
    1850 
    1851  VmaAllocation(VmaAllocator hAllocator);
    1852 
    1853  ~VmaAllocation()
    1854  {
    1855  VMA_ASSERT(m_hMemory == VK_NULL_HANDLE);
    1856  }
    1857 
    1858  // Always call after construction.
    1859  void Init(VkDeviceMemory newMemory, VkDeviceSize newSize);
    1860  // Always call before destruction.
    1861  void Destroy(VmaAllocator allocator);
    1862 
    1863  // Validates all data structures inside this object. If not valid, returns false.
    1864  bool Validate() const;
    1865 
    1866  // Tries to find a place for suballocation with given parameters inside this allocation.
    1867  // If succeeded, fills pAllocationRequest and returns true.
    1868  // If failed, returns false.
    1869  bool CreateAllocationRequest(
    1870  VkDeviceSize bufferImageGranularity,
    1871  VkDeviceSize allocSize,
    1872  VkDeviceSize allocAlignment,
    1873  VmaSuballocationType allocType,
    1874  VmaAllocationRequest* pAllocationRequest);
    1875 
    1876  // Checks if requested suballocation with given parameters can be placed in given pFreeSuballocItem.
    1877  // If yes, fills pOffset and returns true. If no, returns false.
    1878  bool CheckAllocation(
    1879  VkDeviceSize bufferImageGranularity,
    1880  VkDeviceSize allocSize,
    1881  VkDeviceSize allocAlignment,
    1882  VmaSuballocationType allocType,
    1883  VmaSuballocationList::const_iterator freeSuballocItem,
    1884  VkDeviceSize* pOffset) const;
    1885 
    1886  // Returns true if this allocation is empty - contains only single free suballocation.
    1887  bool IsEmpty() const;
    1888 
    1889  // Makes actual allocation based on request. Request must already be checked
    1890  // and valid.
    1891  void Alloc(
    1892  const VmaAllocationRequest& request,
    1893  VmaSuballocationType type,
    1894  VkDeviceSize allocSize);
    1895 
    1896  // Frees suballocation assigned to given memory region.
    1897  void Free(const VkMappedMemoryRange* pMemory);
    1898 
    1899 #if VMA_STATS_STRING_ENABLED
    1900  void PrintDetailedMap(class VmaStringBuilder& sb) const;
    1901 #endif
    1902 
    1903 private:
    1904  // Given free suballocation, it merges it with following one, which must also be free.
    1905  void MergeFreeWithNext(VmaSuballocationList::iterator item);
    1906  // Releases given suballocation, making it free. Merges it with adjacent free
    1907  // suballocations if applicable.
    1908  void FreeSuballocation(VmaSuballocationList::iterator suballocItem);
    1909  // Given free suballocation, it inserts it into sorted list of
    1910  // m_FreeSuballocationsBySize if it's suitable.
    1911  void RegisterFreeSuballocation(VmaSuballocationList::iterator item);
    1912  // Given free suballocation, it removes it from sorted list of
    1913  // m_FreeSuballocationsBySize if it's suitable.
    1914  void UnregisterFreeSuballocation(VmaSuballocationList::iterator item);
    1915 };
    1916 
    1917 // Allocation for an object that has its own private VkDeviceMemory.
    1918 struct VmaOwnAllocation
    1919 {
    1920  VkDeviceMemory m_hMemory;
    1921  VkDeviceSize m_Size;
    1922  VmaSuballocationType m_Type;
    1923 };
    1924 
    1925 struct VmaOwnAllocationMemoryHandleLess
    1926 {
    1927  bool operator()(const VmaOwnAllocation& lhs, const VmaOwnAllocation& rhs) const
    1928  {
    1929  return lhs.m_hMemory < rhs.m_hMemory;
    1930  }
    1931  bool operator()(const VmaOwnAllocation& lhs, VkDeviceMemory rhsMem) const
    1932  {
    1933  return lhs.m_hMemory < rhsMem;
    1934  }
    1935 };
    1936 
    1937 /* Sequence of VmaAllocation. Represents memory blocks allocated for a specific
    1938 Vulkan memory type. */
    1939 struct VmaAllocationVector
    1940 {
    1941  // Incrementally sorted by sumFreeSize, ascending.
    1942  VmaVector< VmaAllocation*, VmaStlAllocator<VmaAllocation*> > m_Allocations;
    1943 
    1944  VmaAllocationVector(VmaAllocator hAllocator);
    1945  ~VmaAllocationVector();
    1946 
    1947  bool IsEmpty() const { return m_Allocations.empty(); }
    1948 
    1949  // Tries to free memory from any if its Allocations.
    1950  // Returns index of Allocation that the memory was freed from, or -1 if not found.
    1951  size_t Free(const VkMappedMemoryRange* pMemory);
    1952 
    1953  // Performs single step in sorting m_Allocations. They may not be fully sorted
    1954  // after this call.
    1955  void IncrementallySortAllocations();
    1956 
    1957  // Adds statistics of this AllocationVector to pStats.
    1958  void AddStats(VmaStats* pStats, uint32_t memTypeIndex, uint32_t memHeapIndex) const;
    1959 
    1960 #if VMA_STATS_STRING_ENABLED
    1961  void PrintDetailedMap(class VmaStringBuilder& sb) const;
    1962 #endif
    1963 
    1964 private:
    1965  VmaAllocator m_hAllocator;
    1966 };
    1967 
    1968 // Main allocator object.
    1969 struct VmaAllocator_T
    1970 {
    1971  VkDevice m_hDevice;
    1972  bool m_AllocationCallbacksSpecified;
    1973  VkAllocationCallbacks m_AllocationCallbacks;
    1974  VkDeviceSize m_PreferredLargeHeapBlockSize;
    1975  VkDeviceSize m_PreferredSmallHeapBlockSize;
    1976 
    1977  VkPhysicalDeviceProperties m_PhysicalDeviceProperties;
    1978  VkPhysicalDeviceMemoryProperties m_MemProps;
    1979 
    1980  VmaAllocationVector* m_pAllocations[VK_MAX_MEMORY_TYPES];
    1981  /* There can be at most one allocation that is completely empty - a
    1982  hysteresis to avoid pessimistic case of alternating creation and destruction
    1983  of a VkDeviceMemory. */
    1984  bool m_HasEmptyAllocation[VK_MAX_MEMORY_TYPES];
    1985  VMA_MUTEX m_AllocationsMutex[VK_MAX_MEMORY_TYPES];
    1986 
    1987  // Each vector is sorted by memory (handle value).
    1988  typedef VmaVector< VmaOwnAllocation, VmaStlAllocator<VmaOwnAllocation> > OwnAllocationVectorType;
    1989  OwnAllocationVectorType* m_pOwnAllocations[VK_MAX_MEMORY_TYPES];
    1990  VMA_MUTEX m_OwnAllocationsMutex[VK_MAX_MEMORY_TYPES];
    1991 
    1992  // Sorted by first (VkBuffer handle value).
    1993  VMA_MAP_TYPE(VkBuffer, VkMappedMemoryRange) m_BufferToMemoryMap;
    1994  VMA_MUTEX m_BufferToMemoryMapMutex;
    1995  // Sorted by first (VkImage handle value).
    1996  VMA_MAP_TYPE(VkImage, VkMappedMemoryRange) m_ImageToMemoryMap;
    1997  VMA_MUTEX m_ImageToMemoryMapMutex;
    1998 
    1999  VmaAllocator_T(const VmaAllocatorCreateInfo* pCreateInfo);
    2000  ~VmaAllocator_T();
    2001 
    2002  const VkAllocationCallbacks* GetAllocationCallbacks() const
    2003  {
    2004  return m_AllocationCallbacksSpecified ? &m_AllocationCallbacks : 0;
    2005  }
    2006 
    2007  VkDeviceSize GetPreferredBlockSize(uint32_t memTypeIndex) const;
    2008 
    2009  VkDeviceSize GetBufferImageGranularity() const
    2010  {
    2011  return VMA_MAX(
    2012  static_cast<VkDeviceSize>(VMA_DEBUG_MIN_BUFFER_IMAGE_GRANULARITY),
    2013  m_PhysicalDeviceProperties.limits.bufferImageGranularity);
    2014  }
    2015 
    2016  uint32_t GetMemoryHeapCount() const { return m_MemProps.memoryHeapCount; }
    2017  uint32_t GetMemoryTypeCount() const { return m_MemProps.memoryTypeCount; }
    2018 
    2019  // Main allocation function.
    2020  VkResult AllocateMemory(
    2021  const VkMemoryRequirements& vkMemReq,
    2022  const VmaMemoryRequirements& vmaMemReq,
    2023  VmaSuballocationType suballocType,
    2024  VkMappedMemoryRange* pMemory,
    2025  uint32_t* pMemoryTypeIndex);
    2026 
    2027  // Main deallocation function.
    2028  void FreeMemory(const VkMappedMemoryRange* pMemory);
    2029 
    2030  void CalculateStats(VmaStats* pStats);
    2031 
    2032 #if VMA_STATS_STRING_ENABLED
    2033  void PrintDetailedMap(class VmaStringBuilder& sb);
    2034 #endif
    2035 
    2036 private:
    2037  VkPhysicalDevice m_PhysicalDevice;
    2038 
    2039  VkResult AllocateMemoryOfType(
    2040  const VkMemoryRequirements& vkMemReq,
    2041  const VmaMemoryRequirements& vmaMemReq,
    2042  uint32_t memTypeIndex,
    2043  VmaSuballocationType suballocType,
    2044  VkMappedMemoryRange* pMemory);
    2045 
    2046  // Allocates and registers new VkDeviceMemory specifically for single allocation.
    2047  VkResult AllocateOwnMemory(
    2048  VkDeviceSize size,
    2049  VmaSuballocationType suballocType,
    2050  uint32_t memTypeIndex,
    2051  VkMappedMemoryRange* pMemory);
    2052 
    2053  // Tries to free pMemory as Own Memory. Returns true if found and freed.
    2054  bool FreeOwnMemory(const VkMappedMemoryRange* pMemory);
    2055 };
    2056 
    2058 // Memory allocation #2 after VmaAllocator_T definition
    2059 
    2060 static void* VmaMalloc(VmaAllocator hAllocator, size_t size, size_t alignment)
    2061 {
    2062  return VmaMalloc(&hAllocator->m_AllocationCallbacks, size, alignment);
    2063 }
    2064 
    2065 static void VmaFree(VmaAllocator hAllocator, void* ptr)
    2066 {
    2067  VmaFree(&hAllocator->m_AllocationCallbacks, ptr);
    2068 }
    2069 
    2070 template<typename T>
    2071 static T* VmaAllocate(VmaAllocator hAllocator)
    2072 {
    2073  return (T*)VmaMalloc(hAllocator, sizeof(T), VMA_ALIGN_OF(T));
    2074 }
    2075 
    2076 template<typename T>
    2077 static T* VmaAllocateArray(VmaAllocator hAllocator, size_t count)
    2078 {
    2079  return (T*)VmaMalloc(hAllocator, sizeof(T) * count, VMA_ALIGN_OF(T));
    2080 }
    2081 
    2082 template<typename T>
    2083 static void vma_delete(VmaAllocator hAllocator, T* ptr)
    2084 {
    2085  if(ptr != VMA_NULL)
    2086  {
    2087  ptr->~T();
    2088  VmaFree(hAllocator, ptr);
    2089  }
    2090 }
    2091 
    2092 template<typename T>
    2093 static void vma_delete_array(VmaAllocator hAllocator, T* ptr, size_t count)
    2094 {
    2095  if(ptr != VMA_NULL)
    2096  {
    2097  for(size_t i = count; i--; )
    2098  ptr[i].~T();
    2099  VmaFree(hAllocator, ptr);
    2100  }
    2101 }
    2102 
    2104 // VmaStringBuilder
    2105 
    2106 #if VMA_STATS_STRING_ENABLED
    2107 
    2108 class VmaStringBuilder
    2109 {
    2110 public:
    2111  VmaStringBuilder(VmaAllocator alloc) : m_Data(VmaStlAllocator<char>(alloc->GetAllocationCallbacks())) { }
    2112  size_t GetLength() const { return m_Data.size(); }
    2113  const char* GetData() const { return m_Data.data(); }
    2114 
    2115  void Add(char ch) { m_Data.push_back(ch); }
    2116  void Add(const char* pStr);
    2117  void AddNewLine() { Add('\n'); }
    2118  void AddNumber(uint32_t num);
    2119  void AddNumber(uint64_t num);
    2120  void AddBool(bool b) { Add(b ? "true" : "false"); }
    2121  void AddNull() { Add("null"); }
    2122  void AddString(const char* pStr);
    2123 
    2124 private:
    2125  VmaVector< char, VmaStlAllocator<char> > m_Data;
    2126 };
    2127 
    2128 void VmaStringBuilder::Add(const char* pStr)
    2129 {
    2130  const size_t strLen = strlen(pStr);
    2131  if(strLen > 0)
    2132  {
    2133  const size_t oldCount = m_Data.size();
    2134  m_Data.resize(oldCount + strLen);
    2135  memcpy(m_Data.data() + oldCount, pStr, strLen);
    2136  }
    2137 }
    2138 
    2139 void VmaStringBuilder::AddNumber(uint32_t num)
    2140 {
    2141  char buf[11];
    2142  VmaUint32ToStr(buf, sizeof(buf), num);
    2143  Add(buf);
    2144 }
    2145 
    2146 void VmaStringBuilder::AddNumber(uint64_t num)
    2147 {
    2148  char buf[21];
    2149  VmaUint64ToStr(buf, sizeof(buf), num);
    2150  Add(buf);
    2151 }
    2152 
    2153 void VmaStringBuilder::AddString(const char* pStr)
    2154 {
    2155  Add('"');
    2156  const size_t strLen = strlen(pStr);
    2157  for(size_t i = 0; i < strLen; ++i)
    2158  {
    2159  char ch = pStr[i];
    2160  if(ch == '\'')
    2161  Add("\\\\");
    2162  else if(ch == '"')
    2163  Add("\\\"");
    2164  else if(ch >= 32)
    2165  Add(ch);
    2166  else switch(ch)
    2167  {
    2168  case '\n':
    2169  Add("\\n");
    2170  break;
    2171  case '\r':
    2172  Add("\\r");
    2173  break;
    2174  case '\t':
    2175  Add("\\t");
    2176  break;
    2177  default:
    2178  VMA_ASSERT(0 && "Character not currently supported.");
    2179  break;
    2180  }
    2181  }
    2182  Add('"');
    2183 }
    2184 
    2186 
    2187 // Correspond to values of enum VmaSuballocationType.
    2188 static const char* VMA_SUBALLOCATION_TYPE_NAMES[] = {
    2189  "FREE",
    2190  "UNKNOWN",
    2191  "BUFFER",
    2192  "IMAGE_UNKNOWN",
    2193  "IMAGE_LINEAR",
    2194  "IMAGE_OPTIMAL",
    2195 };
    2196 
    2197 static void VmaPrintStatInfo(VmaStringBuilder& sb, const VmaStatInfo& stat)
    2198 {
    2199  sb.Add("{ \"Allocations\": ");
    2200  sb.AddNumber(stat.AllocationCount);
    2201  sb.Add(", \"Suballocations\": ");
    2202  sb.AddNumber(stat.SuballocationCount);
    2203  sb.Add(", \"UnusedRanges\": ");
    2204  sb.AddNumber(stat.UnusedRangeCount);
    2205  sb.Add(", \"UsedBytes\": ");
    2206  sb.AddNumber(stat.UsedBytes);
    2207  sb.Add(", \"UnusedBytes\": ");
    2208  sb.AddNumber(stat.UnusedBytes);
    2209  sb.Add(", \"SuballocationSize\": { \"Min\": ");
    2210  sb.AddNumber(stat.SuballocationSizeMin);
    2211  sb.Add(", \"Avg\": ");
    2212  sb.AddNumber(stat.SuballocationSizeAvg);
    2213  sb.Add(", \"Max\": ");
    2214  sb.AddNumber(stat.SuballocationSizeMax);
    2215  sb.Add(" }, \"UnusedRangeSize\": { \"Min\": ");
    2216  sb.AddNumber(stat.UnusedRangeSizeMin);
    2217  sb.Add(", \"Avg\": ");
    2218  sb.AddNumber(stat.UnusedRangeSizeAvg);
    2219  sb.Add(", \"Max\": ");
    2220  sb.AddNumber(stat.UnusedRangeSizeMax);
    2221  sb.Add(" } }");
    2222 }
    2223 
    2224 #endif // #if VMA_STATS_STRING_ENABLED
    2225 
    2226 struct VmaSuballocationItemSizeLess
    2227 {
    2228  bool operator()(
    2229  const VmaSuballocationList::iterator lhs,
    2230  const VmaSuballocationList::iterator rhs) const
    2231  {
    2232  return lhs->size < rhs->size;
    2233  }
    2234  bool operator()(
    2235  const VmaSuballocationList::iterator lhs,
    2236  VkDeviceSize rhsSize) const
    2237  {
    2238  return lhs->size < rhsSize;
    2239  }
    2240 };
    2241 
    2242 VmaAllocation::VmaAllocation(VmaAllocator hAllocator) :
    2243  m_hMemory(VK_NULL_HANDLE),
    2244  m_Size(0),
    2245  m_FreeCount(0),
    2246  m_SumFreeSize(0),
    2247  m_Suballocations(VmaStlAllocator<VmaSuballocation>(hAllocator->GetAllocationCallbacks())),
    2248  m_FreeSuballocationsBySize(VmaStlAllocator<VmaSuballocationList::iterator>(hAllocator->GetAllocationCallbacks()))
    2249 {
    2250 }
    2251 
    2252 void VmaAllocation::Init(VkDeviceMemory newMemory, VkDeviceSize newSize)
    2253 {
    2254  VMA_ASSERT(m_hMemory == VK_NULL_HANDLE);
    2255 
    2256  m_hMemory = newMemory;
    2257  m_Size = newSize;
    2258  m_FreeCount = 1;
    2259  m_SumFreeSize = newSize;
    2260 
    2261  m_Suballocations.clear();
    2262  m_FreeSuballocationsBySize.clear();
    2263 
    2264  VmaSuballocation suballoc = {};
    2265  suballoc.offset = 0;
    2266  suballoc.size = newSize;
    2267  suballoc.type = VMA_SUBALLOCATION_TYPE_FREE;
    2268 
    2269  m_Suballocations.push_back(suballoc);
    2270  VmaSuballocationList::iterator suballocItem = m_Suballocations.end();
    2271  --suballocItem;
    2272  m_FreeSuballocationsBySize.push_back(suballocItem);
    2273 }
    2274 
    2275 void VmaAllocation::Destroy(VmaAllocator allocator)
    2276 {
    2277  VMA_ASSERT(m_hMemory != VK_NULL_HANDLE);
    2278  vkFreeMemory(allocator->m_hDevice, m_hMemory, allocator->GetAllocationCallbacks());
    2279  m_hMemory = VK_NULL_HANDLE;
    2280 }
    2281 
    2282 bool VmaAllocation::Validate() const
    2283 {
    2284  if((m_hMemory == VK_NULL_HANDLE) ||
    2285  (m_Size == 0) ||
    2286  m_Suballocations.empty())
    2287  {
    2288  return false;
    2289  }
    2290 
    2291  // Expected offset of new suballocation as calculates from previous ones.
    2292  VkDeviceSize calculatedOffset = 0;
    2293  // Expected number of free suballocations as calculated from traversing their list.
    2294  uint32_t calculatedFreeCount = 0;
    2295  // Expected sum size of free suballocations as calculated from traversing their list.
    2296  VkDeviceSize calculatedSumFreeSize = 0;
    2297  // Expected number of free suballocations that should be registered in
    2298  // m_FreeSuballocationsBySize calculated from traversing their list.
    2299  size_t freeSuballocationsToRegister = 0;
    2300  // True if previous visisted suballocation was free.
    2301  bool prevFree = false;
    2302 
    2303  for(VmaSuballocationList::const_iterator suballocItem = m_Suballocations.cbegin();
    2304  suballocItem != m_Suballocations.cend();
    2305  ++suballocItem)
    2306  {
    2307  const VmaSuballocation& subAlloc = *suballocItem;
    2308 
    2309  // Actual offset of this suballocation doesn't match expected one.
    2310  if(subAlloc.offset != calculatedOffset)
    2311  return false;
    2312 
    2313  const bool currFree = (subAlloc.type == VMA_SUBALLOCATION_TYPE_FREE);
    2314  // Two adjacent free suballocations are invalid. They should be merged.
    2315  if(prevFree && currFree)
    2316  return false;
    2317  prevFree = currFree;
    2318 
    2319  if(currFree)
    2320  {
    2321  calculatedSumFreeSize += subAlloc.size;
    2322  ++calculatedFreeCount;
    2323  if(subAlloc.size >= VMA_MIN_FREE_SUBALLOCATION_SIZE_TO_REGISTER)
    2324  ++freeSuballocationsToRegister;
    2325  }
    2326 
    2327  calculatedOffset += subAlloc.size;
    2328  }
    2329 
    2330  // Number of free suballocations registered in m_FreeSuballocationsBySize doesn't
    2331  // match expected one.
    2332  if(m_FreeSuballocationsBySize.size() != freeSuballocationsToRegister)
    2333  return false;
    2334 
    2335  VkDeviceSize lastSize = 0;
    2336  for(size_t i = 0; i < m_FreeSuballocationsBySize.size(); ++i)
    2337  {
    2338  VmaSuballocationList::iterator suballocItem = m_FreeSuballocationsBySize[i];
    2339 
    2340  // Only free suballocations can be registered in m_FreeSuballocationsBySize.
    2341  if(suballocItem->type != VMA_SUBALLOCATION_TYPE_FREE)
    2342  return false;
    2343  // They must be sorted by size ascending.
    2344  if(suballocItem->size < lastSize)
    2345  return false;
    2346 
    2347  lastSize = suballocItem->size;
    2348  }
    2349 
    2350  // Check if totals match calculacted values.
    2351  return
    2352  (calculatedOffset == m_Size) &&
    2353  (calculatedSumFreeSize == m_SumFreeSize) &&
    2354  (calculatedFreeCount == m_FreeCount);
    2355 }
    2356 
    2357 /*
    2358 How many suitable free suballocations to analyze before choosing best one.
    2359 - Set to 1 to use First-Fit algorithm - first suitable free suballocation will
    2360  be chosen.
    2361 - Set to UINT32_MAX to use Best-Fit/Worst-Fit algorithm - all suitable free
    2362  suballocations will be analized and best one will be chosen.
    2363 - Any other value is also acceptable.
    2364 */
    2365 //static const uint32_t MAX_SUITABLE_SUBALLOCATIONS_TO_CHECK = 8;
    2366 
    2367 bool VmaAllocation::CreateAllocationRequest(
    2368  VkDeviceSize bufferImageGranularity,
    2369  VkDeviceSize allocSize,
    2370  VkDeviceSize allocAlignment,
    2371  VmaSuballocationType allocType,
    2372  VmaAllocationRequest* pAllocationRequest)
    2373 {
    2374  VMA_ASSERT(allocSize > 0);
    2375  VMA_ASSERT(allocType != VMA_SUBALLOCATION_TYPE_FREE);
    2376  VMA_ASSERT(pAllocationRequest != VMA_NULL);
    2377  VMA_HEAVY_ASSERT(Validate());
    2378 
    2379  // There is not enough total free space in this allocation to fullfill the request: Early return.
    2380  if(m_SumFreeSize < allocSize)
    2381  return false;
    2382 
    2383  // Old brute-force algorithm, linearly searching suballocations.
    2384  /*
    2385  uint32_t suitableSuballocationsFound = 0;
    2386  for(VmaSuballocationList::iterator suballocItem = suballocations.Front();
    2387  suballocItem != VMA_NULL &&
    2388  suitableSuballocationsFound < MAX_SUITABLE_SUBALLOCATIONS_TO_CHECK;
    2389  suballocItem = suballocItem->Next)
    2390  {
    2391  if(suballocItem->Value.type == VMA_SUBALLOCATION_TYPE_FREE)
    2392  {
    2393  VkDeviceSize offset = 0, cost = 0;
    2394  if(CheckAllocation(bufferImageGranularity, allocSize, allocAlignment, allocType, suballocItem, &offset, &cost))
    2395  {
    2396  ++suitableSuballocationsFound;
    2397  if(cost < costLimit)
    2398  {
    2399  pAllocationRequest->freeSuballocationItem = suballocItem;
    2400  pAllocationRequest->offset = offset;
    2401  pAllocationRequest->cost = cost;
    2402  if(cost == 0)
    2403  return true;
    2404  costLimit = cost;
    2405  betterSuballocationFound = true;
    2406  }
    2407  }
    2408  }
    2409  }
    2410  */
    2411 
    2412  // New algorithm, efficiently searching freeSuballocationsBySize.
    2413  const size_t freeSuballocCount = m_FreeSuballocationsBySize.size();
    2414  if(freeSuballocCount > 0)
    2415  {
    2416  if(VMA_BEST_FIT)
    2417  {
    2418  // Find first free suballocation with size not less than allocSize.
    2419  VmaSuballocationList::iterator* const it = VmaBinaryFindFirstNotLess(
    2420  m_FreeSuballocationsBySize.data(),
    2421  m_FreeSuballocationsBySize.data() + freeSuballocCount,
    2422  allocSize,
    2423  VmaSuballocationItemSizeLess());
    2424  size_t index = it - m_FreeSuballocationsBySize.data();
    2425  for(; index < freeSuballocCount; ++index)
    2426  {
    2427  VkDeviceSize offset = 0;
    2428  const VmaSuballocationList::iterator suballocItem = m_FreeSuballocationsBySize[index];
    2429  if(CheckAllocation(bufferImageGranularity, allocSize, allocAlignment, allocType, suballocItem, &offset))
    2430  {
    2431  pAllocationRequest->freeSuballocationItem = suballocItem;
    2432  pAllocationRequest->offset = offset;
    2433  return true;
    2434  }
    2435  }
    2436  }
    2437  else
    2438  {
    2439  // Search staring from biggest suballocations.
    2440  for(size_t index = freeSuballocCount; index--; )
    2441  {
    2442  VkDeviceSize offset = 0;
    2443  const VmaSuballocationList::iterator suballocItem = m_FreeSuballocationsBySize[index];
    2444  if(CheckAllocation(bufferImageGranularity, allocSize, allocAlignment, allocType, suballocItem, &offset))
    2445  {
    2446  pAllocationRequest->freeSuballocationItem = suballocItem;
    2447  pAllocationRequest->offset = offset;
    2448  return true;
    2449  }
    2450  }
    2451  }
    2452  }
    2453 
    2454  return false;
    2455 }
    2456 
    2457 bool VmaAllocation::CheckAllocation(
    2458  VkDeviceSize bufferImageGranularity,
    2459  VkDeviceSize allocSize,
    2460  VkDeviceSize allocAlignment,
    2461  VmaSuballocationType allocType,
    2462  VmaSuballocationList::const_iterator freeSuballocItem,
    2463  VkDeviceSize* pOffset) const
    2464 {
    2465  VMA_ASSERT(allocSize > 0);
    2466  VMA_ASSERT(allocType != VMA_SUBALLOCATION_TYPE_FREE);
    2467  VMA_ASSERT(freeSuballocItem != m_Suballocations.cend());
    2468  VMA_ASSERT(pOffset != VMA_NULL);
    2469 
    2470  const VmaSuballocation& suballoc = *freeSuballocItem;
    2471  VMA_ASSERT(suballoc.type == VMA_SUBALLOCATION_TYPE_FREE);
    2472 
    2473  // Size of this suballocation is too small for this request: Early return.
    2474  if(suballoc.size < allocSize)
    2475  return false;
    2476 
    2477  // Start from offset equal to beginning of this suballocation.
    2478  *pOffset = suballoc.offset;
    2479 
    2480  // Apply VMA_DEBUG_MARGIN at the beginning.
    2481  if((VMA_DEBUG_MARGIN > 0) && freeSuballocItem != m_Suballocations.cbegin())
    2482  *pOffset += VMA_DEBUG_MARGIN;
    2483 
    2484  // Apply alignment.
    2485  const VkDeviceSize alignment = VMA_MAX(allocAlignment, static_cast<VkDeviceSize>(VMA_DEBUG_ALIGNMENT));
    2486  *pOffset = VmaAlignUp(*pOffset, alignment);
    2487 
    2488  // Check previous suballocations for BufferImageGranularity conflicts.
    2489  // Make bigger alignment if necessary.
    2490  if(bufferImageGranularity > 1)
    2491  {
    2492  bool bufferImageGranularityConflict = false;
    2493  VmaSuballocationList::const_iterator prevSuballocItem = freeSuballocItem;
    2494  while(prevSuballocItem != m_Suballocations.cbegin())
    2495  {
    2496  --prevSuballocItem;
    2497  const VmaSuballocation& prevSuballoc = *prevSuballocItem;
    2498  if(VmaBlocksOnSamePage(prevSuballoc.offset, prevSuballoc.size, *pOffset, bufferImageGranularity))
    2499  {
    2500  if(VmaIsBufferImageGranularityConflict(prevSuballoc.type, allocType))
    2501  {
    2502  bufferImageGranularityConflict = true;
    2503  break;
    2504  }
    2505  }
    2506  else
    2507  // Already on previous page.
    2508  break;
    2509  }
    2510  if(bufferImageGranularityConflict)
    2511  *pOffset = VmaAlignUp(*pOffset, bufferImageGranularity);
    2512  }
    2513 
    2514  // Calculate padding at the beginning based on current offset.
    2515  const VkDeviceSize paddingBegin = *pOffset - suballoc.offset;
    2516 
    2517  // Calculate required margin at the end if this is not last suballocation.
    2518  VmaSuballocationList::const_iterator next = freeSuballocItem;
    2519  ++next;
    2520  const VkDeviceSize requiredEndMargin =
    2521  (next != m_Suballocations.cend()) ? VMA_DEBUG_MARGIN : 0;
    2522 
    2523  // Fail if requested size plus margin before and after is bigger than size of this suballocation.
    2524  if(paddingBegin + allocSize + requiredEndMargin > suballoc.size)
    2525  return false;
    2526 
    2527  // Check next suballocations for BufferImageGranularity conflicts.
    2528  // If conflict exists, allocation cannot be made here.
    2529  if(bufferImageGranularity > 1)
    2530  {
    2531  VmaSuballocationList::const_iterator nextSuballocItem = freeSuballocItem;
    2532  ++nextSuballocItem;
    2533  while(nextSuballocItem != m_Suballocations.cend())
    2534  {
    2535  const VmaSuballocation& nextSuballoc = *nextSuballocItem;
    2536  if(VmaBlocksOnSamePage(*pOffset, allocSize, nextSuballoc.offset, bufferImageGranularity))
    2537  {
    2538  if(VmaIsBufferImageGranularityConflict(allocType, nextSuballoc.type))
    2539  return false;
    2540  }
    2541  else
    2542  // Already on next page.
    2543  break;
    2544  ++nextSuballocItem;
    2545  }
    2546  }
    2547 
    2548  // All tests passed: Success. pOffset is already filled.
    2549  return true;
    2550 }
    2551 
    2552 bool VmaAllocation::IsEmpty() const
    2553 {
    2554  return (m_Suballocations.size() == 1) && (m_FreeCount == 1);
    2555 }
    2556 
    2557 void VmaAllocation::Alloc(
    2558  const VmaAllocationRequest& request,
    2559  VmaSuballocationType type,
    2560  VkDeviceSize allocSize)
    2561 {
    2562  VMA_ASSERT(request.freeSuballocationItem != m_Suballocations.end());
    2563  VmaSuballocation& suballoc = *request.freeSuballocationItem;
    2564  // Given suballocation is a free block.
    2565  VMA_ASSERT(suballoc.type == VMA_SUBALLOCATION_TYPE_FREE);
    2566  // Given offset is inside this suballocation.
    2567  VMA_ASSERT(request.offset >= suballoc.offset);
    2568  const VkDeviceSize paddingBegin = request.offset - suballoc.offset;
    2569  VMA_ASSERT(suballoc.size >= paddingBegin + allocSize);
    2570  const VkDeviceSize paddingEnd = suballoc.size - paddingBegin - allocSize;
    2571 
    2572  // Unregister this free suballocation from m_FreeSuballocationsBySize and update
    2573  // it to become used.
    2574  UnregisterFreeSuballocation(request.freeSuballocationItem);
    2575 
    2576  suballoc.offset = request.offset;
    2577  suballoc.size = allocSize;
    2578  suballoc.type = type;
    2579 
    2580  // If there are any free bytes remaining at the end, insert new free suballocation after current one.
    2581  if(paddingEnd)
    2582  {
    2583  VmaSuballocation paddingSuballoc = {};
    2584  paddingSuballoc.offset = request.offset + allocSize;
    2585  paddingSuballoc.size = paddingEnd;
    2586  paddingSuballoc.type = VMA_SUBALLOCATION_TYPE_FREE;
    2587  VmaSuballocationList::iterator next = request.freeSuballocationItem;
    2588  ++next;
    2589  const VmaSuballocationList::iterator paddingEndItem =
    2590  m_Suballocations.insert(next, paddingSuballoc);
    2591  RegisterFreeSuballocation(paddingEndItem);
    2592  }
    2593 
    2594  // If there are any free bytes remaining at the beginning, insert new free suballocation before current one.
    2595  if(paddingBegin)
    2596  {
    2597  VmaSuballocation paddingSuballoc = {};
    2598  paddingSuballoc.offset = request.offset - paddingBegin;
    2599  paddingSuballoc.size = paddingBegin;
    2600  paddingSuballoc.type = VMA_SUBALLOCATION_TYPE_FREE;
    2601  const VmaSuballocationList::iterator paddingBeginItem =
    2602  m_Suballocations.insert(request.freeSuballocationItem, paddingSuballoc);
    2603  RegisterFreeSuballocation(paddingBeginItem);
    2604  }
    2605 
    2606  // Update totals.
    2607  m_FreeCount = m_FreeCount - 1;
    2608  if(paddingBegin > 0)
    2609  ++m_FreeCount;
    2610  if(paddingEnd > 0)
    2611  ++m_FreeCount;
    2612  m_SumFreeSize -= allocSize;
    2613 }
    2614 
    2615 void VmaAllocation::FreeSuballocation(VmaSuballocationList::iterator suballocItem)
    2616 {
    2617  // Change this suballocation to be marked as free.
    2618  VmaSuballocation& suballoc = *suballocItem;
    2619  suballoc.type = VMA_SUBALLOCATION_TYPE_FREE;
    2620 
    2621  // Update totals.
    2622  ++m_FreeCount;
    2623  m_SumFreeSize += suballoc.size;
    2624 
    2625  // Merge with previous and/or next suballocation if it's also free.
    2626  bool mergeWithNext = false;
    2627  bool mergeWithPrev = false;
    2628 
    2629  VmaSuballocationList::iterator nextItem = suballocItem;
    2630  ++nextItem;
    2631  if((nextItem != m_Suballocations.end()) && (nextItem->type == VMA_SUBALLOCATION_TYPE_FREE))
    2632  mergeWithNext = true;
    2633 
    2634  VmaSuballocationList::iterator prevItem = suballocItem;
    2635  if(suballocItem != m_Suballocations.begin())
    2636  {
    2637  --prevItem;
    2638  if(prevItem->type == VMA_SUBALLOCATION_TYPE_FREE)
    2639  mergeWithPrev = true;
    2640  }
    2641 
    2642  if(mergeWithNext)
    2643  {
    2644  UnregisterFreeSuballocation(nextItem);
    2645  MergeFreeWithNext(suballocItem);
    2646  }
    2647 
    2648  if(mergeWithPrev)
    2649  {
    2650  UnregisterFreeSuballocation(prevItem);
    2651  MergeFreeWithNext(prevItem);
    2652  RegisterFreeSuballocation(prevItem);
    2653  }
    2654  else
    2655  RegisterFreeSuballocation(suballocItem);
    2656 }
    2657 
    2658 void VmaAllocation::Free(const VkMappedMemoryRange* pMemory)
    2659 {
    2660  for(VmaSuballocationList::iterator suballocItem = m_Suballocations.begin();
    2661  suballocItem != m_Suballocations.end();
    2662  ++suballocItem)
    2663  {
    2664  VmaSuballocation& suballoc = *suballocItem;
    2665  if(suballoc.offset == pMemory->offset)
    2666  {
    2667  FreeSuballocation(suballocItem);
    2668  VMA_HEAVY_ASSERT(Validate());
    2669  return;
    2670  }
    2671  }
    2672  VMA_ASSERT(0 && "Not found!");
    2673 }
    2674 
    2675 #if VMA_STATS_STRING_ENABLED
    2676 
    2677 void VmaAllocation::PrintDetailedMap(class VmaStringBuilder& sb) const
    2678 {
    2679  sb.Add("{\n\t\t\t\"Bytes\": ");
    2680  sb.AddNumber(m_Size);
    2681  sb.Add(",\n\t\t\t\"FreeBytes\": ");
    2682  sb.AddNumber(m_SumFreeSize);
    2683  sb.Add(",\n\t\t\t\"Suballocations\": ");
    2684  sb.AddNumber(m_Suballocations.size());
    2685  sb.Add(",\n\t\t\t\"FreeSuballocations\": ");
    2686  sb.AddNumber(m_FreeCount);
    2687  sb.Add(",\n\t\t\t\"SuballocationList\": [");
    2688 
    2689  size_t i = 0;
    2690  for(VmaSuballocationList::const_iterator suballocItem = m_Suballocations.cbegin();
    2691  suballocItem != m_Suballocations.cend();
    2692  ++suballocItem, ++i)
    2693  {
    2694  if(i > 0)
    2695  sb.Add(",\n\t\t\t\t{ \"Type\": ");
    2696  else
    2697  sb.Add("\n\t\t\t\t{ \"Type\": ");
    2698  sb.AddString(VMA_SUBALLOCATION_TYPE_NAMES[suballocItem->type]);
    2699  sb.Add(", \"Size\": ");
    2700  sb.AddNumber(suballocItem->size);
    2701  sb.Add(", \"Offset\": ");
    2702  sb.AddNumber(suballocItem->offset);
    2703  sb.Add(" }");
    2704  }
    2705 
    2706  sb.Add("\n\t\t\t]\n\t\t}");
    2707 }
    2708 
    2709 #endif // #if VMA_STATS_STRING_ENABLED
    2710 
    2711 void VmaAllocation::MergeFreeWithNext(VmaSuballocationList::iterator item)
    2712 {
    2713  VMA_ASSERT(item != m_Suballocations.end());
    2714  VMA_ASSERT(item->type == VMA_SUBALLOCATION_TYPE_FREE);
    2715 
    2716  VmaSuballocationList::iterator nextItem = item;
    2717  ++nextItem;
    2718  VMA_ASSERT(nextItem != m_Suballocations.end());
    2719  VMA_ASSERT(nextItem->type == VMA_SUBALLOCATION_TYPE_FREE);
    2720 
    2721  item->size += nextItem->size;
    2722  --m_FreeCount;
    2723  m_Suballocations.erase(nextItem);
    2724 }
    2725 
    2726 void VmaAllocation::RegisterFreeSuballocation(VmaSuballocationList::iterator item)
    2727 {
    2728  VMA_ASSERT(item->type == VMA_SUBALLOCATION_TYPE_FREE);
    2729  VMA_ASSERT(item->size > 0);
    2730 
    2731  if(item->size >= VMA_MIN_FREE_SUBALLOCATION_SIZE_TO_REGISTER)
    2732  {
    2733  if(m_FreeSuballocationsBySize.empty())
    2734  m_FreeSuballocationsBySize.push_back(item);
    2735  else
    2736  {
    2737  VmaSuballocationList::iterator* const it = VmaBinaryFindFirstNotLess(
    2738  m_FreeSuballocationsBySize.data(),
    2739  m_FreeSuballocationsBySize.data() + m_FreeSuballocationsBySize.size(),
    2740  item,
    2741  VmaSuballocationItemSizeLess());
    2742  size_t index = it - m_FreeSuballocationsBySize.data();
    2743  VectorInsert(m_FreeSuballocationsBySize, index, item);
    2744  }
    2745  }
    2746 }
    2747 
    2748 void VmaAllocation::UnregisterFreeSuballocation(VmaSuballocationList::iterator item)
    2749 {
    2750  VMA_ASSERT(item->type == VMA_SUBALLOCATION_TYPE_FREE);
    2751  VMA_ASSERT(item->size > 0);
    2752 
    2753  if(item->size >= VMA_MIN_FREE_SUBALLOCATION_SIZE_TO_REGISTER)
    2754  {
    2755  VmaSuballocationList::iterator* const it = VmaBinaryFindFirstNotLess(
    2756  m_FreeSuballocationsBySize.data(),
    2757  m_FreeSuballocationsBySize.data() + m_FreeSuballocationsBySize.size(),
    2758  item,
    2759  VmaSuballocationItemSizeLess());
    2760  for(size_t index = it - m_FreeSuballocationsBySize.data();
    2761  index < m_FreeSuballocationsBySize.size();
    2762  ++index)
    2763  {
    2764  if(m_FreeSuballocationsBySize[index] == item)
    2765  {
    2766  VectorRemove(m_FreeSuballocationsBySize, index);
    2767  return;
    2768  }
    2769  VMA_ASSERT((m_FreeSuballocationsBySize[index]->size == item->size) && "Not found.");
    2770  }
    2771  VMA_ASSERT(0 && "Not found.");
    2772  }
    2773 }
    2774 
    2775 static void InitStatInfo(VmaStatInfo& outInfo)
    2776 {
    2777  memset(&outInfo, 0, sizeof(outInfo));
    2778  outInfo.SuballocationSizeMin = UINT64_MAX;
    2779  outInfo.UnusedRangeSizeMin = UINT64_MAX;
    2780 }
    2781 
    2782 static void CalcAllocationStatInfo(VmaStatInfo& outInfo, const VmaAllocation& alloc)
    2783 {
    2784  outInfo.AllocationCount = 1;
    2785 
    2786  const uint32_t rangeCount = (uint32_t)alloc.m_Suballocations.size();
    2787  outInfo.SuballocationCount = rangeCount - alloc.m_FreeCount;
    2788  outInfo.UnusedRangeCount = alloc.m_FreeCount;
    2789 
    2790  outInfo.UnusedBytes = alloc.m_SumFreeSize;
    2791  outInfo.UsedBytes = alloc.m_Size - outInfo.UnusedBytes;
    2792 
    2793  outInfo.SuballocationSizeMin = UINT64_MAX;
    2794  outInfo.SuballocationSizeMax = 0;
    2795  outInfo.UnusedRangeSizeMin = UINT64_MAX;
    2796  outInfo.UnusedRangeSizeMax = 0;
    2797 
    2798  for(VmaSuballocationList::const_iterator suballocItem = alloc.m_Suballocations.cbegin();
    2799  suballocItem != alloc.m_Suballocations.cend();
    2800  ++suballocItem)
    2801  {
    2802  const VmaSuballocation& suballoc = *suballocItem;
    2803  if(suballoc.type != VMA_SUBALLOCATION_TYPE_FREE)
    2804  {
    2805  outInfo.SuballocationSizeMin = VMA_MIN(outInfo.SuballocationSizeMin, suballoc.size);
    2806  outInfo.SuballocationSizeMax = VMA_MAX(outInfo.SuballocationSizeMax, suballoc.size);
    2807  }
    2808  else
    2809  {
    2810  outInfo.UnusedRangeSizeMin = VMA_MIN(outInfo.UnusedRangeSizeMin, suballoc.size);
    2811  outInfo.UnusedRangeSizeMax = VMA_MAX(outInfo.UnusedRangeSizeMax, suballoc.size);
    2812  }
    2813  }
    2814 }
    2815 
    2816 // Adds statistics srcInfo into inoutInfo, like: inoutInfo += srcInfo.
    2817 static void VmaAddStatInfo(VmaStatInfo& inoutInfo, const VmaStatInfo& srcInfo)
    2818 {
    2819  inoutInfo.AllocationCount += srcInfo.AllocationCount;
    2820  inoutInfo.SuballocationCount += srcInfo.SuballocationCount;
    2821  inoutInfo.UnusedRangeCount += srcInfo.UnusedRangeCount;
    2822  inoutInfo.UsedBytes += srcInfo.UsedBytes;
    2823  inoutInfo.UnusedBytes += srcInfo.UnusedBytes;
    2824  inoutInfo.SuballocationSizeMin = VMA_MIN(inoutInfo.SuballocationSizeMin, srcInfo.SuballocationSizeMin);
    2825  inoutInfo.SuballocationSizeMax = VMA_MAX(inoutInfo.SuballocationSizeMax, srcInfo.SuballocationSizeMax);
    2826  inoutInfo.UnusedRangeSizeMin = VMA_MIN(inoutInfo.UnusedRangeSizeMin, srcInfo.UnusedRangeSizeMin);
    2827  inoutInfo.UnusedRangeSizeMax = VMA_MAX(inoutInfo.UnusedRangeSizeMax, srcInfo.UnusedRangeSizeMax);
    2828 }
    2829 
    2830 static void VmaPostprocessCalcStatInfo(VmaStatInfo& inoutInfo)
    2831 {
    2832  inoutInfo.SuballocationSizeAvg = (inoutInfo.SuballocationCount > 0) ?
    2833  VmaRoundDiv<VkDeviceSize>(inoutInfo.UsedBytes, inoutInfo.SuballocationCount) : 0;
    2834  inoutInfo.UnusedRangeSizeAvg = (inoutInfo.UnusedRangeCount > 0) ?
    2835  VmaRoundDiv<VkDeviceSize>(inoutInfo.UnusedBytes, inoutInfo.UnusedRangeCount) : 0;
    2836 }
    2837 
    2838 VmaAllocationVector::VmaAllocationVector(VmaAllocator hAllocator) :
    2839  m_hAllocator(hAllocator),
    2840  m_Allocations(VmaStlAllocator<VmaAllocation*>(hAllocator->GetAllocationCallbacks()))
    2841 {
    2842 }
    2843 
    2844 VmaAllocationVector::~VmaAllocationVector()
    2845 {
    2846  for(size_t i = m_Allocations.size(); i--; )
    2847  {
    2848  m_Allocations[i]->Destroy(m_hAllocator);
    2849  vma_delete(m_hAllocator, m_Allocations[i]);
    2850  }
    2851 }
    2852 
    2853 size_t VmaAllocationVector::Free(const VkMappedMemoryRange* pMemory)
    2854 {
    2855  for(uint32_t allocIndex = 0; allocIndex < m_Allocations.size(); ++allocIndex)
    2856  {
    2857  VmaAllocation* const pAlloc = m_Allocations[allocIndex];
    2858  VMA_ASSERT(pAlloc);
    2859  if(pAlloc->m_hMemory == pMemory->memory)
    2860  {
    2861  pAlloc->Free(pMemory);
    2862  VMA_HEAVY_ASSERT(pAlloc->Validate());
    2863  return allocIndex;
    2864  }
    2865  }
    2866 
    2867  return (size_t)-1;
    2868 }
    2869 
    2870 void VmaAllocationVector::IncrementallySortAllocations()
    2871 {
    2872  // Bubble sort only until first swap.
    2873  for(size_t i = 1; i < m_Allocations.size(); ++i)
    2874  {
    2875  if(m_Allocations[i - 1]->m_SumFreeSize > m_Allocations[i]->m_SumFreeSize)
    2876  {
    2877  VMA_SWAP(m_Allocations[i - 1], m_Allocations[i]);
    2878  return;
    2879  }
    2880  }
    2881 }
    2882 
    2883 #if VMA_STATS_STRING_ENABLED
    2884 
    2885 void VmaAllocationVector::PrintDetailedMap(class VmaStringBuilder& sb) const
    2886 {
    2887  for(size_t i = 0; i < m_Allocations.size(); ++i)
    2888  {
    2889  if(i > 0)
    2890  sb.Add(",\n\t\t");
    2891  else
    2892  sb.Add("\n\t\t");
    2893  m_Allocations[i]->PrintDetailedMap(sb);
    2894  }
    2895 }
    2896 
    2897 #endif // #if VMA_STATS_STRING_ENABLED
    2898 
    2899 void VmaAllocationVector::AddStats(VmaStats* pStats, uint32_t memTypeIndex, uint32_t memHeapIndex) const
    2900 {
    2901  for(uint32_t allocIndex = 0; allocIndex < m_Allocations.size(); ++allocIndex)
    2902  {
    2903  const VmaAllocation* const pAlloc = m_Allocations[allocIndex];
    2904  VMA_ASSERT(pAlloc);
    2905  VMA_HEAVY_ASSERT(pAlloc->Validate());
    2906  VmaStatInfo allocationStatInfo;
    2907  CalcAllocationStatInfo(allocationStatInfo, *pAlloc);
    2908  VmaAddStatInfo(pStats->total, allocationStatInfo);
    2909  VmaAddStatInfo(pStats->memoryType[memTypeIndex], allocationStatInfo);
    2910  VmaAddStatInfo(pStats->memoryHeap[memHeapIndex], allocationStatInfo);
    2911  }
    2912 }
    2913 
    2915 // VmaAllocator_T
    2916 
    2917 VmaAllocator_T::VmaAllocator_T(const VmaAllocatorCreateInfo* pCreateInfo) :
    2918  m_PhysicalDevice(pCreateInfo->physicalDevice),
    2919  m_hDevice(pCreateInfo->device),
    2920  m_AllocationCallbacksSpecified(pCreateInfo->pAllocationCallbacks != VMA_NULL),
    2921  m_AllocationCallbacks(pCreateInfo->pAllocationCallbacks ?
    2922  *pCreateInfo->pAllocationCallbacks : VmaEmptyAllocationCallbacks),
    2923  m_PreferredLargeHeapBlockSize(0),
    2924  m_PreferredSmallHeapBlockSize(0),
    2925  m_BufferToMemoryMap(VmaStlAllocator< VmaPair<VkBuffer, VkMappedMemoryRange> >(pCreateInfo->pAllocationCallbacks)),
    2926  m_ImageToMemoryMap(VmaStlAllocator< VmaPair<VkImage, VkMappedMemoryRange> >(pCreateInfo->pAllocationCallbacks))
    2927 {
    2928  VMA_ASSERT(pCreateInfo->physicalDevice && pCreateInfo->device);
    2929 
    2930  memset(&m_MemProps, 0, sizeof(m_MemProps));
    2931  memset(&m_PhysicalDeviceProperties, 0, sizeof(m_PhysicalDeviceProperties));
    2932 
    2933  memset(&m_pAllocations, 0, sizeof(m_pAllocations));
    2934  memset(&m_HasEmptyAllocation, 0, sizeof(m_HasEmptyAllocation));
    2935  memset(&m_pOwnAllocations, 0, sizeof(m_pOwnAllocations));
    2936 
    2937  m_PreferredLargeHeapBlockSize = (pCreateInfo->preferredLargeHeapBlockSize != 0) ?
    2938  pCreateInfo->preferredLargeHeapBlockSize : static_cast<VkDeviceSize>(VMA_DEFAULT_LARGE_HEAP_BLOCK_SIZE);
    2939  m_PreferredSmallHeapBlockSize = (pCreateInfo->preferredSmallHeapBlockSize != 0) ?
    2940  pCreateInfo->preferredSmallHeapBlockSize : static_cast<VkDeviceSize>(VMA_DEFAULT_SMALL_HEAP_BLOCK_SIZE);
    2941 
    2942  vkGetPhysicalDeviceProperties(m_PhysicalDevice, &m_PhysicalDeviceProperties);
    2943  vkGetPhysicalDeviceMemoryProperties(m_PhysicalDevice, &m_MemProps);
    2944 
    2945  for(size_t i = 0; i < GetMemoryTypeCount(); ++i)
    2946  {
    2947  m_pAllocations[i] = vma_new(this, VmaAllocationVector)(this);
    2948  m_pOwnAllocations[i] = vma_new(this, OwnAllocationVectorType)(VmaStlAllocator<VmaOwnAllocation>(GetAllocationCallbacks()));
    2949  }
    2950 }
    2951 
    2952 VmaAllocator_T::~VmaAllocator_T()
    2953 {
    2954  for(VMA_MAP_TYPE(VkImage, VkMappedMemoryRange)::iterator it = m_ImageToMemoryMap.begin();
    2955  it != m_ImageToMemoryMap.end();
    2956  ++it)
    2957  {
    2958  vkDestroyImage(m_hDevice, it->first, GetAllocationCallbacks());
    2959  }
    2960 
    2961  for(VMA_MAP_TYPE(VkBuffer, VkMappedMemoryRange)::iterator it = m_BufferToMemoryMap.begin();
    2962  it != m_BufferToMemoryMap.end();
    2963  ++it)
    2964  {
    2965  vkDestroyBuffer(m_hDevice, it->first, GetAllocationCallbacks());
    2966  }
    2967 
    2968  for(uint32_t typeIndex = 0; typeIndex < GetMemoryTypeCount(); ++typeIndex)
    2969  {
    2970  OwnAllocationVectorType* pOwnAllocations = m_pOwnAllocations[typeIndex];
    2971  VMA_ASSERT(pOwnAllocations);
    2972  for(size_t allocationIndex = 0; allocationIndex < pOwnAllocations->size(); ++allocationIndex)
    2973  {
    2974  const VmaOwnAllocation& ownAlloc = (*pOwnAllocations)[allocationIndex];
    2975  vkFreeMemory(m_hDevice, ownAlloc.m_hMemory, GetAllocationCallbacks());
    2976  }
    2977  }
    2978 
    2979  for(size_t i = GetMemoryTypeCount(); i--; )
    2980  {
    2981  vma_delete(this, m_pAllocations[i]);
    2982  vma_delete(this, m_pOwnAllocations[i]);
    2983  }
    2984 }
    2985 
    2986 VkDeviceSize VmaAllocator_T::GetPreferredBlockSize(uint32_t memTypeIndex) const
    2987 {
    2988  VkDeviceSize heapSize = m_MemProps.memoryHeaps[m_MemProps.memoryTypes[memTypeIndex].heapIndex].size;
    2989  return (heapSize <= VMA_SMALL_HEAP_MAX_SIZE) ?
    2990  m_PreferredSmallHeapBlockSize : m_PreferredLargeHeapBlockSize;
    2991 }
    2992 
    2993 VkResult VmaAllocator_T::AllocateMemoryOfType(
    2994  const VkMemoryRequirements& vkMemReq,
    2995  const VmaMemoryRequirements& vmaMemReq,
    2996  uint32_t memTypeIndex,
    2997  VmaSuballocationType suballocType,
    2998  VkMappedMemoryRange* pMemory)
    2999 {
    3000  VMA_DEBUG_LOG(" AllocateMemory: MemoryTypeIndex=%u, Size=%llu", memTypeIndex, vkMemReq.size);
    3001 
    3002  pMemory->sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE;
    3003  pMemory->pNext = VMA_NULL;
    3004  pMemory->size = vkMemReq.size;
    3005 
    3006  const VkDeviceSize preferredBlockSize = GetPreferredBlockSize(memTypeIndex);
    3007  // Heuristics: Allocate own memory if requested size if greater than half of preferred block size.
    3008  const bool ownMemory =
    3009  vmaMemReq.ownMemory ||
    3010  VMA_DEBUG_ALWAYS_OWN_MEMORY ||
    3011  ((vmaMemReq.neverAllocate == false) && (vkMemReq.size > preferredBlockSize / 2));
    3012 
    3013  if(ownMemory)
    3014  {
    3015  if(vmaMemReq.neverAllocate)
    3016  return VK_ERROR_OUT_OF_DEVICE_MEMORY;
    3017  else
    3018  return AllocateOwnMemory(vkMemReq.size, suballocType, memTypeIndex, pMemory);
    3019  }
    3020  else
    3021  {
    3022  VmaMutexLock lock(m_AllocationsMutex[memTypeIndex]);
    3023  VmaAllocationVector* const allocationVector = m_pAllocations[memTypeIndex];
    3024  VMA_ASSERT(allocationVector);
    3025 
    3026  // 1. Search existing allocations.
    3027  // Forward order - prefer blocks with smallest amount of free space.
    3028  for(size_t allocIndex = 0; allocIndex < allocationVector->m_Allocations.size(); ++allocIndex )
    3029  {
    3030  VmaAllocation* const pAlloc = allocationVector->m_Allocations[allocIndex];
    3031  VMA_ASSERT(pAlloc);
    3032  VmaAllocationRequest allocRequest = {};
    3033  // Check if can allocate from pAlloc.
    3034  if(pAlloc->CreateAllocationRequest(
    3035  GetBufferImageGranularity(),
    3036  vkMemReq.size,
    3037  vkMemReq.alignment,
    3038  suballocType,
    3039  &allocRequest))
    3040  {
    3041  // We no longer have an empty Allocation.
    3042  if(pAlloc->IsEmpty())
    3043  m_HasEmptyAllocation[memTypeIndex] = false;
    3044  // Allocate from this pAlloc.
    3045  pAlloc->Alloc(allocRequest, suballocType, vkMemReq.size);
    3046  // Return VkDeviceMemory and offset (size already filled above).
    3047  pMemory->memory = pAlloc->m_hMemory;
    3048  pMemory->offset = allocRequest.offset;
    3049  VMA_HEAVY_ASSERT(pAlloc->Validate());
    3050  VMA_DEBUG_LOG(" Returned from existing allocation #%u", (uint32_t)allocIndex);
    3051  return VK_SUCCESS;
    3052  }
    3053  }
    3054 
    3055  // 2. Create new Allocation.
    3056  if(vmaMemReq.neverAllocate)
    3057  {
    3058  VMA_DEBUG_LOG(" FAILED due to VmaMemoryRequirements::neverAllocate");
    3059  return VK_ERROR_OUT_OF_DEVICE_MEMORY;
    3060  }
    3061  else
    3062  {
    3063  // Start with full preferredBlockSize.
    3064  VkMemoryAllocateInfo allocInfo = { VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO };
    3065  allocInfo.memoryTypeIndex = memTypeIndex;
    3066  allocInfo.allocationSize = preferredBlockSize;
    3067  VkDeviceMemory mem = VK_NULL_HANDLE;
    3068  VkResult res = vkAllocateMemory(m_hDevice, &allocInfo, GetAllocationCallbacks(), &mem);
    3069  if(res < 0)
    3070  {
    3071  // 3. Try half the size.
    3072  allocInfo.allocationSize /= 2;
    3073  if(allocInfo.allocationSize >= vkMemReq.size)
    3074  {
    3075  res = vkAllocateMemory(m_hDevice, &allocInfo, GetAllocationCallbacks(), &mem);
    3076  if(res < 0)
    3077  {
    3078  // 4. Try quarter the size.
    3079  allocInfo.allocationSize /= 2;
    3080  if(allocInfo.allocationSize >= vkMemReq.size)
    3081  {
    3082  res = vkAllocateMemory(m_hDevice, &allocInfo, GetAllocationCallbacks(), &mem);
    3083  }
    3084  }
    3085  }
    3086  }
    3087  if(res < 0)
    3088  {
    3089  // 5. Try OwnAlloc.
    3090  res = AllocateOwnMemory(vkMemReq.size, suballocType, memTypeIndex, pMemory);
    3091  if(res == VK_SUCCESS)
    3092  {
    3093  // Succeeded: AllocateOwnMemory function already filld pMemory, nothing more to do here.
    3094  VMA_DEBUG_LOG(" Allocated as OwnMemory");
    3095  return VK_SUCCESS;
    3096  }
    3097  else
    3098  {
    3099  // Everything failed: Return error code.
    3100  VMA_DEBUG_LOG(" vkAllocateMemory FAILED");
    3101  return res;
    3102  }
    3103  }
    3104 
    3105  // New VkDeviceMemory successfully created. Create new Allocation for it.
    3106  VmaAllocation* const pAlloc = vma_new(this, VmaAllocation)(this);
    3107  pAlloc->Init(mem, allocInfo.allocationSize);
    3108 
    3109  allocationVector->m_Allocations.push_back(pAlloc);
    3110 
    3111  // Allocate from pAlloc. Because it is empty, allocRequest can be trivially filled.
    3112  VmaAllocationRequest allocRequest = {};
    3113  allocRequest.freeSuballocationItem = pAlloc->m_Suballocations.begin();
    3114  allocRequest.offset = 0;
    3115  pAlloc->Alloc(allocRequest, suballocType, vkMemReq.size);
    3116  pMemory->memory = mem;
    3117  pMemory->offset = allocRequest.offset;
    3118  VMA_HEAVY_ASSERT(pAlloc->Validate());
    3119  VMA_DEBUG_LOG(" Created new allocation Size=%llu", allocInfo.allocationSize);
    3120  return VK_SUCCESS;
    3121  }
    3122  }
    3123 }
    3124 
    3125 VkResult VmaAllocator_T::AllocateOwnMemory(
    3126  VkDeviceSize size,
    3127  VmaSuballocationType suballocType,
    3128  uint32_t memTypeIndex,
    3129  VkMappedMemoryRange* pMemory)
    3130 {
    3131  VkMemoryAllocateInfo allocInfo = { VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO };
    3132  allocInfo.memoryTypeIndex = memTypeIndex;
    3133  allocInfo.allocationSize = size;
    3134 
    3135  // Allocate VkDeviceMemory.
    3136  VmaOwnAllocation ownAlloc = {};
    3137  ownAlloc.m_Size = size;
    3138  ownAlloc.m_Type = suballocType;
    3139  VkResult res = vkAllocateMemory(m_hDevice, &allocInfo, GetAllocationCallbacks(), &ownAlloc.m_hMemory);
    3140  if(res < 0)
    3141  {
    3142  VMA_DEBUG_LOG(" vkAllocateMemory FAILED");
    3143  return res;
    3144  }
    3145 
    3146  // Register it in m_pOwnAllocations.
    3147  VmaMutexLock lock(m_OwnAllocationsMutex[memTypeIndex]);
    3148  OwnAllocationVectorType* ownAllocations = m_pOwnAllocations[memTypeIndex];
    3149  VMA_ASSERT(ownAllocations);
    3150  VmaOwnAllocation* const pOwnAllocationsBeg = ownAllocations->data();
    3151  VmaOwnAllocation* const pOwnAllocationsEnd = pOwnAllocationsBeg + ownAllocations->size();
    3152  const size_t indexToInsert = VmaBinaryFindFirstNotLess(
    3153  pOwnAllocationsBeg,
    3154  pOwnAllocationsEnd,
    3155  ownAlloc,
    3156  VmaOwnAllocationMemoryHandleLess()) - pOwnAllocationsBeg;
    3157  VectorInsert(*ownAllocations, indexToInsert, ownAlloc);
    3158 
    3159  // Return parameters of the allocation.
    3160  pMemory->sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE;
    3161  pMemory->pNext = VMA_NULL;
    3162  pMemory->memory = ownAlloc.m_hMemory;
    3163  pMemory->offset = 0;
    3164  pMemory->size = size;
    3165 
    3166  VMA_DEBUG_LOG(" Allocated OwnMemory MemoryTypeIndex=#%u", memTypeIndex);
    3167 
    3168  return VK_SUCCESS;
    3169 }
    3170 
    3171 VkResult VmaAllocator_T::AllocateMemory(
    3172  const VkMemoryRequirements& vkMemReq,
    3173  const VmaMemoryRequirements& vmaMemReq,
    3174  VmaSuballocationType suballocType,
    3175  VkMappedMemoryRange* pMemory,
    3176  uint32_t* pMemoryTypeIndex)
    3177 {
    3178  if(vmaMemReq.ownMemory && vmaMemReq.neverAllocate)
    3179  {
    3180  VMA_ASSERT(0 && "Specifying VmaMemoryRequirements::ownMemory && VmaMemoryRequirements::neverAllocate makes no sense.");
    3181  return VK_ERROR_OUT_OF_DEVICE_MEMORY;
    3182  }
    3183 
    3184  // Bit mask of memory Vulkan types acceptable for this allocation.
    3185  uint32_t memoryTypeBits = vkMemReq.memoryTypeBits;
    3186  uint32_t memTypeIndex = UINT32_MAX;
    3187  VkResult res = vmaFindMemoryTypeIndex(this, memoryTypeBits, &vmaMemReq, &memTypeIndex);
    3188  if(res == VK_SUCCESS)
    3189  {
    3190  res = AllocateMemoryOfType(vkMemReq, vmaMemReq, memTypeIndex, suballocType, pMemory);
    3191  // Succeeded on first try.
    3192  if(res == VK_SUCCESS)
    3193  {
    3194  if(pMemoryTypeIndex != VMA_NULL)
    3195  *pMemoryTypeIndex = memTypeIndex;
    3196  return res;
    3197  }
    3198  // Allocation from this memory type failed. Try other compatible memory types.
    3199  else
    3200  {
    3201  for(;;)
    3202  {
    3203  // Remove old memTypeIndex from list of possibilities.
    3204  memoryTypeBits &= ~(1u << memTypeIndex);
    3205  // Find alternative memTypeIndex.
    3206  res = vmaFindMemoryTypeIndex(this, memoryTypeBits, &vmaMemReq, &memTypeIndex);
    3207  if(res == VK_SUCCESS)
    3208  {
    3209  res = AllocateMemoryOfType(vkMemReq, vmaMemReq, memTypeIndex, suballocType, pMemory);
    3210  // Allocation from this alternative memory type succeeded.
    3211  if(res == VK_SUCCESS)
    3212  {
    3213  if(pMemoryTypeIndex != VMA_NULL)
    3214  *pMemoryTypeIndex = memTypeIndex;
    3215  return res;
    3216  }
    3217  // else: Allocation from this memory type failed. Try next one - next loop iteration.
    3218  }
    3219  // No other matching memory type index could be found.
    3220  else
    3221  // Not returning res, which is VK_ERROR_FEATURE_NOT_PRESENT, because we already failed to allocate once.
    3222  return VK_ERROR_OUT_OF_DEVICE_MEMORY;
    3223  }
    3224  }
    3225  }
    3226  // Can't find any single memory type maching requirements. res is VK_ERROR_FEATURE_NOT_PRESENT.
    3227  else
    3228  return res;
    3229 }
    3230 
    3231 void VmaAllocator_T::FreeMemory(const VkMappedMemoryRange* pMemory)
    3232 {
    3233  uint32_t memTypeIndex = 0;
    3234  bool found = false;
    3235  VmaAllocation* allocationToDelete = VMA_NULL;
    3236  // Check all memory types because we don't know which one does pMemory come from.
    3237  for(; memTypeIndex < GetMemoryTypeCount(); ++memTypeIndex)
    3238  {
    3239  VmaMutexLock lock(m_AllocationsMutex[memTypeIndex]);
    3240  VmaAllocationVector* const pAllocationVector = m_pAllocations[memTypeIndex];
    3241  VMA_ASSERT(pAllocationVector);
    3242  // Try to free pMemory from pAllocationVector.
    3243  const size_t allocIndex = pAllocationVector->Free(pMemory);
    3244  if(allocIndex != (size_t)-1)
    3245  {
    3246  VMA_DEBUG_LOG(" Freed from MemoryTypeIndex=%u", memTypeIndex);
    3247  found = true;
    3248  VmaAllocation* const pAlloc = pAllocationVector->m_Allocations[allocIndex];
    3249  VMA_ASSERT(pAlloc);
    3250  // pAlloc became empty after this deallocation.
    3251  if(pAlloc->IsEmpty())
    3252  {
    3253  // Already has empty Allocation. We don't want to have two, so delete this one.
    3254  if(m_HasEmptyAllocation[memTypeIndex])
    3255  {
    3256  allocationToDelete = pAlloc;
    3257  VectorRemove(pAllocationVector->m_Allocations, allocIndex);
    3258  break;
    3259  }
    3260  // We now have first empty Allocation.
    3261  else
    3262  m_HasEmptyAllocation[memTypeIndex] = true;
    3263  }
    3264  // Must be called after allocIndex is used, because later it may become invalid!
    3265  pAllocationVector->IncrementallySortAllocations();
    3266  break;
    3267  }
    3268  }
    3269  if(found)
    3270  {
    3271  // Destruction of a free Allocation. Deferred until this point, outside of mutex
    3272  // lock, for performance reason.
    3273  if(allocationToDelete != VMA_NULL)
    3274  {
    3275  VMA_DEBUG_LOG(" Deleted empty allocation");
    3276  allocationToDelete->Destroy(this);
    3277  vma_delete(this, allocationToDelete);
    3278  }
    3279  return;
    3280  }
    3281 
    3282  // pMemory not found in allocations. Try free it as Own Memory.
    3283  if(FreeOwnMemory(pMemory))
    3284  return;
    3285 
    3286  // pMemory not found as Own Memory either.
    3287  VMA_ASSERT(0 && "Not found. Trying to free memory not allocated using this allocator (or some other bug).");
    3288 }
    3289 
    3290 void VmaAllocator_T::CalculateStats(VmaStats* pStats)
    3291 {
    3292  InitStatInfo(pStats->total);
    3293  for(size_t i = 0; i < VK_MAX_MEMORY_TYPES; ++i)
    3294  InitStatInfo(pStats->memoryType[i]);
    3295  for(size_t i = 0; i < VK_MAX_MEMORY_HEAPS; ++i)
    3296  InitStatInfo(pStats->memoryHeap[i]);
    3297 
    3298  for(uint32_t memTypeIndex = 0; memTypeIndex < GetMemoryTypeCount(); ++memTypeIndex)
    3299  {
    3300  VmaMutexLock allocationsLock(m_AllocationsMutex[memTypeIndex]);
    3301  const uint32_t heapIndex = m_MemProps.memoryTypes[memTypeIndex].heapIndex;
    3302  const VmaAllocationVector* const allocVector = m_pAllocations[memTypeIndex];
    3303  VMA_ASSERT(allocVector);
    3304  allocVector->AddStats(pStats, memTypeIndex, heapIndex);
    3305  }
    3306 
    3307  VmaPostprocessCalcStatInfo(pStats->total);
    3308  for(size_t i = 0; i < GetMemoryTypeCount(); ++i)
    3309  VmaPostprocessCalcStatInfo(pStats->memoryType[i]);
    3310  for(size_t i = 0; i < GetMemoryHeapCount(); ++i)
    3311  VmaPostprocessCalcStatInfo(pStats->memoryHeap[i]);
    3312 }
    3313 
    3314 bool VmaAllocator_T::FreeOwnMemory(const VkMappedMemoryRange* pMemory)
    3315 {
    3316  VkDeviceMemory vkMemory = VK_NULL_HANDLE;
    3317 
    3318  // Check all memory types because we don't know which one does pMemory come from.
    3319  for(uint32_t memTypeIndex = 0; memTypeIndex < GetMemoryTypeCount(); ++memTypeIndex)
    3320  {
    3321  VmaMutexLock lock(m_OwnAllocationsMutex[memTypeIndex]);
    3322  OwnAllocationVectorType* const pOwnAllocations = m_pOwnAllocations[memTypeIndex];
    3323  VMA_ASSERT(pOwnAllocations);
    3324  VmaOwnAllocation* const pOwnAllocationsBeg = pOwnAllocations->data();
    3325  VmaOwnAllocation* const pOwnAllocationsEnd = pOwnAllocationsBeg + pOwnAllocations->size();
    3326  VmaOwnAllocation* const pOwnAllocationIt = VmaBinaryFindFirstNotLess(
    3327  pOwnAllocationsBeg,
    3328  pOwnAllocationsEnd,
    3329  pMemory->memory,
    3330  VmaOwnAllocationMemoryHandleLess());
    3331  if((pOwnAllocationIt != pOwnAllocationsEnd) &&
    3332  (pOwnAllocationIt->m_hMemory == pMemory->memory))
    3333  {
    3334  VMA_ASSERT(pMemory->size == pOwnAllocationIt->m_Size && pMemory->offset == 0);
    3335  vkMemory = pOwnAllocationIt->m_hMemory;
    3336  const size_t ownAllocationIndex = pOwnAllocationIt - pOwnAllocationsBeg;
    3337  VectorRemove(*pOwnAllocations, ownAllocationIndex);
    3338  VMA_DEBUG_LOG(" Freed OwnMemory MemoryTypeIndex=%u", memTypeIndex);
    3339  break;
    3340  }
    3341  }
    3342 
    3343  // Found. Free VkDeviceMemory deferred until this point, outside of mutex lock,
    3344  // for performance reason.
    3345  if(vkMemory != VK_NULL_HANDLE)
    3346  {
    3347  vkFreeMemory(m_hDevice, vkMemory, GetAllocationCallbacks());
    3348  return true;
    3349  }
    3350  else
    3351  return false;
    3352 }
    3353 
    3354 #if VMA_STATS_STRING_ENABLED
    3355 
    3356 void VmaAllocator_T::PrintDetailedMap(VmaStringBuilder& sb)
    3357 {
    3358  bool ownAllocationsStarted = false;
    3359  for(size_t memTypeIndex = 0; memTypeIndex < GetMemoryTypeCount(); ++memTypeIndex)
    3360  {
    3361  VmaMutexLock ownAllocationsLock(m_OwnAllocationsMutex[memTypeIndex]);
    3362  OwnAllocationVectorType* const pOwnAllocVector = m_pOwnAllocations[memTypeIndex];
    3363  VMA_ASSERT(pOwnAllocVector);
    3364  if(pOwnAllocVector->empty() == false)
    3365  {
    3366  if(ownAllocationsStarted)
    3367  sb.Add(",\n\t\"Type ");
    3368  else
    3369  {
    3370  sb.Add(",\n\"OwnAllocations\": {\n\t\"Type ");
    3371  ownAllocationsStarted = true;
    3372  }
    3373  sb.AddNumber(memTypeIndex);
    3374  sb.Add("\": [");
    3375 
    3376  for(size_t i = 0; i < pOwnAllocVector->size(); ++i)
    3377  {
    3378  const VmaOwnAllocation& ownAlloc = (*pOwnAllocVector)[i];
    3379  if(i > 0)
    3380  sb.Add(",\n\t\t{ \"Size\": ");
    3381  else
    3382  sb.Add("\n\t\t{ \"Size\": ");
    3383  sb.AddNumber(ownAlloc.m_Size);
    3384  sb.Add(", \"Type\": ");
    3385  sb.AddString(VMA_SUBALLOCATION_TYPE_NAMES[ownAlloc.m_Type]);
    3386  sb.Add(" }");
    3387  }
    3388 
    3389  sb.Add("\n\t]");
    3390  }
    3391  }
    3392  if(ownAllocationsStarted)
    3393  sb.Add("\n}");
    3394 
    3395  {
    3396  bool allocationsStarted = false;
    3397  for(size_t memTypeIndex = 0; memTypeIndex < GetMemoryTypeCount(); ++memTypeIndex)
    3398  {
    3399  VmaMutexLock globalAllocationsLock(m_AllocationsMutex[memTypeIndex]);
    3400  if(m_pAllocations[memTypeIndex]->IsEmpty() == false)
    3401  {
    3402  if(allocationsStarted)
    3403  sb.Add(",\n\t\"Type ");
    3404  else
    3405  {
    3406  sb.Add(",\n\"Allocations\": {\n\t\"Type ");
    3407  allocationsStarted = true;
    3408  }
    3409  sb.AddNumber(memTypeIndex);
    3410  sb.Add("\": [");
    3411 
    3412  m_pAllocations[memTypeIndex]->PrintDetailedMap(sb);
    3413 
    3414  sb.Add("\n\t]");
    3415  }
    3416  }
    3417  if(allocationsStarted)
    3418  sb.Add("\n}");
    3419  }
    3420 }
    3421 
    3422 #endif // #if VMA_STATS_STRING_ENABLED
    3423 
    3424 static VkResult AllocateMemoryForImage(
    3425  VmaAllocator allocator,
    3426  VkImage image,
    3427  const VmaMemoryRequirements* pMemoryRequirements,
    3428  VmaSuballocationType suballocType,
    3429  VkMappedMemoryRange* pMemory,
    3430  uint32_t* pMemoryTypeIndex)
    3431 {
    3432  VMA_ASSERT(allocator && image != VK_NULL_HANDLE && pMemoryRequirements && pMemory);
    3433 
    3434  VkMemoryRequirements vkMemReq = {};
    3435  vkGetImageMemoryRequirements(allocator->m_hDevice, image, &vkMemReq);
    3436 
    3437  return allocator->AllocateMemory(
    3438  vkMemReq,
    3439  *pMemoryRequirements,
    3440  suballocType,
    3441  pMemory,
    3442  pMemoryTypeIndex);
    3443 }
    3444 
    3446 // Public interface
    3447 
    3448 VkResult vmaCreateAllocator(
    3449  const VmaAllocatorCreateInfo* pCreateInfo,
    3450  VmaAllocator* pAllocator)
    3451 {
    3452  VMA_ASSERT(pCreateInfo && pAllocator);
    3453  VMA_DEBUG_LOG("vmaCreateAllocator");
    3454  *pAllocator = vma_new(pCreateInfo->pAllocationCallbacks, VmaAllocator_T)(pCreateInfo);
    3455  return VK_SUCCESS;
    3456 }
    3457 
    3458 void vmaDestroyAllocator(
    3459  VmaAllocator allocator)
    3460 {
    3461  if(allocator != VK_NULL_HANDLE)
    3462  {
    3463  VMA_DEBUG_LOG("vmaDestroyAllocator");
    3464  VkAllocationCallbacks allocationCallbacks = allocator->m_AllocationCallbacks;
    3465  vma_delete(&allocationCallbacks, allocator);
    3466  }
    3467 }
    3468 
    3470  VmaAllocator allocator,
    3471  const VkPhysicalDeviceProperties **ppPhysicalDeviceProperties)
    3472 {
    3473  VMA_ASSERT(allocator && ppPhysicalDeviceProperties);
    3474  *ppPhysicalDeviceProperties = &allocator->m_PhysicalDeviceProperties;
    3475 }
    3476 
    3478  VmaAllocator allocator,
    3479  const VkPhysicalDeviceMemoryProperties** ppPhysicalDeviceMemoryProperties)
    3480 {
    3481  VMA_ASSERT(allocator && ppPhysicalDeviceMemoryProperties);
    3482  *ppPhysicalDeviceMemoryProperties = &allocator->m_MemProps;
    3483 }
    3484 
    3486  VmaAllocator allocator,
    3487  uint32_t memoryTypeIndex,
    3488  VkMemoryPropertyFlags* pFlags)
    3489 {
    3490  VMA_ASSERT(allocator && pFlags);
    3491  VMA_ASSERT(memoryTypeIndex < allocator->GetMemoryTypeCount());
    3492  *pFlags = allocator->m_MemProps.memoryTypes[memoryTypeIndex].propertyFlags;
    3493 }
    3494 
    3495 void vmaCalculateStats(
    3496  VmaAllocator allocator,
    3497  VmaStats* pStats)
    3498 {
    3499  VMA_ASSERT(allocator && pStats);
    3500  VMA_DEBUG_GLOBAL_MUTEX_LOCK
    3501  allocator->CalculateStats(pStats);
    3502 }
    3503 
    3504 #if VMA_STATS_STRING_ENABLED
    3505 
    3506 void vmaBuildStatsString(
    3507  VmaAllocator allocator,
    3508  char** ppStatsString,
    3509  VkBool32 detailedMap)
    3510 {
    3511  VMA_ASSERT(allocator && ppStatsString);
    3512  VMA_DEBUG_GLOBAL_MUTEX_LOCK
    3513 
    3514  VmaStringBuilder sb(allocator);
    3515  {
    3516  VmaStats stats;
    3517  allocator->CalculateStats(&stats);
    3518 
    3519  sb.Add("{\n\"Total\": ");
    3520  VmaPrintStatInfo(sb, stats.total);
    3521 
    3522  for(uint32_t heapIndex = 0; heapIndex < allocator->GetMemoryHeapCount(); ++heapIndex)
    3523  {
    3524  sb.Add(",\n\"Heap ");
    3525  sb.AddNumber(heapIndex);
    3526  sb.Add("\": {\n\t\"Size\": ");
    3527  sb.AddNumber(allocator->m_MemProps.memoryHeaps[heapIndex].size);
    3528  sb.Add(",\n\t\"Flags\": ");
    3529  if((allocator->m_MemProps.memoryHeaps[heapIndex].flags & VK_MEMORY_HEAP_DEVICE_LOCAL_BIT) != 0)
    3530  sb.AddString("DEVICE_LOCAL");
    3531  else
    3532  sb.AddString("");
    3533  if(stats.memoryHeap[heapIndex].AllocationCount > 0)
    3534  {
    3535  sb.Add(",\n\t\"Stats:\": ");
    3536  VmaPrintStatInfo(sb, stats.memoryHeap[heapIndex]);
    3537  }
    3538 
    3539  for(uint32_t typeIndex = 0; typeIndex < allocator->GetMemoryTypeCount(); ++typeIndex)
    3540  {
    3541  if(allocator->m_MemProps.memoryTypes[typeIndex].heapIndex == heapIndex)
    3542  {
    3543  sb.Add(",\n\t\"Type ");
    3544  sb.AddNumber(typeIndex);
    3545  sb.Add("\": {\n\t\t\"Flags\": \"");
    3546  VkMemoryPropertyFlags flags = allocator->m_MemProps.memoryTypes[typeIndex].propertyFlags;
    3547  if((flags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) != 0)
    3548  sb.Add(" DEVICE_LOCAL");
    3549  if((flags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) != 0)
    3550  sb.Add(" HOST_VISIBLE");
    3551  if((flags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT) != 0)
    3552  sb.Add(" HOST_COHERENT");
    3553  if((flags & VK_MEMORY_PROPERTY_HOST_CACHED_BIT) != 0)
    3554  sb.Add(" HOST_CACHED");
    3555  if((flags & VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT) != 0)
    3556  sb.Add(" LAZILY_ALLOCATED");
    3557  sb.Add("\"");
    3558  if(stats.memoryType[typeIndex].AllocationCount > 0)
    3559  {
    3560  sb.Add(",\n\t\t\"Stats\": ");
    3561  VmaPrintStatInfo(sb, stats.memoryType[typeIndex]);
    3562  }
    3563  sb.Add("\n\t}");
    3564  }
    3565  }
    3566  sb.Add("\n}");
    3567  }
    3568  if(detailedMap == VK_TRUE)
    3569  allocator->PrintDetailedMap(sb);
    3570  sb.Add("\n}\n");
    3571  }
    3572 
    3573  const size_t len = sb.GetLength();
    3574  char* const pChars = vma_new_array(allocator, char, len + 1);
    3575  if(len > 0)
    3576  memcpy(pChars, sb.GetData(), len);
    3577  pChars[len] = '\0';
    3578  *ppStatsString = pChars;
    3579 }
    3580 
    3581 void vmaFreeStatsString(
    3582  VmaAllocator allocator,
    3583  char* pStatsString)
    3584 {
    3585  if(pStatsString != VMA_NULL)
    3586  {
    3587  VMA_ASSERT(allocator);
    3588  size_t len = strlen(pStatsString);
    3589  vma_delete_array(allocator, pStatsString, len + 1);
    3590  }
    3591 }
    3592 
    3593 #endif // #if VMA_STATS_STRING_ENABLED
    3594 
    3597 VkResult vmaFindMemoryTypeIndex(
    3598  VmaAllocator allocator,
    3599  uint32_t memoryTypeBits,
    3600  const VmaMemoryRequirements* pMemoryRequirements,
    3601  uint32_t* pMemoryTypeIndex)
    3602 {
    3603  VMA_ASSERT(allocator != VK_NULL_HANDLE);
    3604  VMA_ASSERT(pMemoryRequirements != VMA_NULL);
    3605  VMA_ASSERT(pMemoryTypeIndex != VMA_NULL);
    3606 
    3607  uint32_t requiredFlags = pMemoryRequirements->requiredFlags;
    3608  uint32_t preferredFlags = pMemoryRequirements->preferredFlags;
    3609  if(preferredFlags == 0)
    3610  preferredFlags = requiredFlags;
    3611  // preferredFlags, if not 0, must be a superset of requiredFlags.
    3612  VMA_ASSERT((requiredFlags & ~preferredFlags) == 0);
    3613 
    3614  // Convert usage to requiredFlags and preferredFlags.
    3615  switch(pMemoryRequirements->usage)
    3616  {
    3618  break;
    3620  preferredFlags |= VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
    3621  break;
    3623  requiredFlags |= VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
    3624  break;
    3626  requiredFlags |= VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT;
    3627  preferredFlags |= VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
    3628  break;
    3630  requiredFlags |= VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT;
    3631  preferredFlags |= VK_MEMORY_PROPERTY_HOST_COHERENT_BIT | VK_MEMORY_PROPERTY_HOST_CACHED_BIT;
    3632  break;
    3633  default:
    3634  break;
    3635  }
    3636 
    3637  *pMemoryTypeIndex = UINT32_MAX;
    3638  uint32_t minCost = UINT32_MAX;
    3639  for(uint32_t memTypeIndex = 0, memTypeBit = 1;
    3640  memTypeIndex < allocator->GetMemoryTypeCount();
    3641  ++memTypeIndex, memTypeBit <<= 1)
    3642  {
    3643  // This memory type is acceptable according to memoryTypeBits bitmask.
    3644  if((memTypeBit & memoryTypeBits) != 0)
    3645  {
    3646  const VkMemoryPropertyFlags currFlags =
    3647  allocator->m_MemProps.memoryTypes[memTypeIndex].propertyFlags;
    3648  // This memory type contains requiredFlags.
    3649  if((requiredFlags & ~currFlags) == 0)
    3650  {
    3651  // Calculate cost as number of bits from preferredFlags not present in this memory type.
    3652  uint32_t currCost = CountBitsSet(preferredFlags & ~currFlags);
    3653  // Remember memory type with lowest cost.
    3654  if(currCost < minCost)
    3655  {
    3656  *pMemoryTypeIndex = memTypeIndex;
    3657  if(currCost == 0)
    3658  return VK_SUCCESS;
    3659  minCost = currCost;
    3660  }
    3661  }
    3662  }
    3663  }
    3664  return (*pMemoryTypeIndex != UINT32_MAX) ? VK_SUCCESS : VK_ERROR_FEATURE_NOT_PRESENT;
    3665 }
    3666 
    3667 VkResult vmaAllocateMemory(
    3668  VmaAllocator allocator,
    3669  const VkMemoryRequirements* pVkMemoryRequirements,
    3670  const VmaMemoryRequirements* pVmaMemoryRequirements,
    3671  VkMappedMemoryRange* pMemory,
    3672  uint32_t* pMemoryTypeIndex)
    3673 {
    3674  VMA_ASSERT(allocator && pVkMemoryRequirements && pVmaMemoryRequirements && pMemory);
    3675 
    3676  VMA_DEBUG_LOG("vmaAllocateMemory");
    3677 
    3678  VMA_DEBUG_GLOBAL_MUTEX_LOCK
    3679 
    3680  return allocator->AllocateMemory(
    3681  *pVkMemoryRequirements,
    3682  *pVmaMemoryRequirements,
    3683  VMA_SUBALLOCATION_TYPE_UNKNOWN,
    3684  pMemory,
    3685  pMemoryTypeIndex);
    3686 }
    3687 
    3689  VmaAllocator allocator,
    3690  VkBuffer buffer,
    3691  const VmaMemoryRequirements* pMemoryRequirements,
    3692  VkMappedMemoryRange* pMemory,
    3693  uint32_t* pMemoryTypeIndex)
    3694 {
    3695  VMA_ASSERT(allocator && buffer != VK_NULL_HANDLE && pMemoryRequirements && pMemory);
    3696 
    3697  VMA_DEBUG_LOG("vmaAllocateMemoryForBuffer");
    3698 
    3699  VMA_DEBUG_GLOBAL_MUTEX_LOCK
    3700 
    3701  VkMemoryRequirements vkMemReq = {};
    3702  vkGetBufferMemoryRequirements(allocator->m_hDevice, buffer, &vkMemReq);
    3703 
    3704  return allocator->AllocateMemory(
    3705  vkMemReq,
    3706  *pMemoryRequirements,
    3707  VMA_SUBALLOCATION_TYPE_BUFFER,
    3708  pMemory,
    3709  pMemoryTypeIndex);
    3710 }
    3711 
    3712 VkResult vmaAllocateMemoryForImage(
    3713  VmaAllocator allocator,
    3714  VkImage image,
    3715  const VmaMemoryRequirements* pMemoryRequirements,
    3716  VkMappedMemoryRange* pMemory,
    3717  uint32_t* pMemoryTypeIndex)
    3718 {
    3719  VMA_ASSERT(allocator && image != VK_NULL_HANDLE && pMemoryRequirements);
    3720 
    3721  VMA_DEBUG_LOG("vmaAllocateMemoryForImage");
    3722 
    3723  VMA_DEBUG_GLOBAL_MUTEX_LOCK
    3724 
    3725  return AllocateMemoryForImage(
    3726  allocator,
    3727  image,
    3728  pMemoryRequirements,
    3729  VMA_SUBALLOCATION_TYPE_IMAGE_UNKNOWN,
    3730  pMemory,
    3731  pMemoryTypeIndex);
    3732 }
    3733 
    3734 void vmaFreeMemory(
    3735  VmaAllocator allocator,
    3736  const VkMappedMemoryRange* pMemory)
    3737 {
    3738  VMA_ASSERT(allocator && pMemory);
    3739 
    3740  VMA_DEBUG_LOG("vmaFreeMemory");
    3741 
    3742  VMA_DEBUG_GLOBAL_MUTEX_LOCK
    3743 
    3744  allocator->FreeMemory(pMemory);
    3745 }
    3746 
    3747 VkResult vmaMapMemory(
    3748  VmaAllocator allocator,
    3749  const VkMappedMemoryRange* pMemory,
    3750  void** ppData)
    3751 {
    3752  VMA_ASSERT(allocator && pMemory && ppData);
    3753 
    3754  VMA_DEBUG_GLOBAL_MUTEX_LOCK
    3755 
    3756  return vkMapMemory(allocator->m_hDevice, pMemory->memory,
    3757  pMemory->offset, pMemory->size, 0, ppData);
    3758 }
    3759 
    3760 void vmaUnmapMemory(
    3761  VmaAllocator allocator,
    3762  const VkMappedMemoryRange* pMemory)
    3763 {
    3764  VMA_ASSERT(allocator && pMemory);
    3765 
    3766  VMA_DEBUG_GLOBAL_MUTEX_LOCK
    3767 
    3768  vkUnmapMemory(allocator->m_hDevice, pMemory->memory);
    3769 }
    3770 
    3771 VkResult vmaCreateBuffer(
    3772  VmaAllocator allocator,
    3773  const VkBufferCreateInfo* pCreateInfo,
    3774  const VmaMemoryRequirements* pMemoryRequirements,
    3775  VkBuffer* pBuffer,
    3776  VkMappedMemoryRange* pMemory,
    3777  uint32_t* pMemoryTypeIndex)
    3778 {
    3779  VMA_ASSERT(allocator && pCreateInfo && pMemoryRequirements);
    3780 
    3781  VMA_DEBUG_LOG("vmaCreateBuffer");
    3782 
    3783  VMA_DEBUG_GLOBAL_MUTEX_LOCK
    3784 
    3785  // 1. Create VkBuffer.
    3786  VkResult res = vkCreateBuffer(allocator->m_hDevice, pCreateInfo, allocator->GetAllocationCallbacks(), pBuffer);
    3787  if(res >= 0)
    3788  {
    3789  VkMappedMemoryRange mem = {};
    3790 
    3791  // 2. vkGetBufferMemoryRequirements.
    3792  VkMemoryRequirements vkMemReq = {};
    3793  vkGetBufferMemoryRequirements(allocator->m_hDevice, *pBuffer, &vkMemReq);
    3794 
    3795  // 3. Allocate memory using allocator.
    3796  res = allocator->AllocateMemory(
    3797  vkMemReq,
    3798  *pMemoryRequirements,
    3799  VMA_SUBALLOCATION_TYPE_BUFFER,
    3800  &mem,
    3801  pMemoryTypeIndex);
    3802  if(res >= 0)
    3803  {
    3804  if(pMemory != VMA_NULL)
    3805  {
    3806  *pMemory = mem;
    3807  }
    3808  // 3. Bind buffer with memory.
    3809  res = vkBindBufferMemory(allocator->m_hDevice, *pBuffer, mem.memory, mem.offset);
    3810  if(res >= 0)
    3811  {
    3812  // All steps succeeded.
    3813  VmaMutexLock lock(allocator->m_BufferToMemoryMapMutex);
    3814  allocator->m_BufferToMemoryMap.insert(VmaPair<VkBuffer, VkMappedMemoryRange>(*pBuffer, mem));
    3815  return VK_SUCCESS;
    3816  }
    3817  allocator->FreeMemory(&mem);
    3818  return res;
    3819  }
    3820  vkDestroyBuffer(allocator->m_hDevice, *pBuffer, allocator->GetAllocationCallbacks());
    3821  return res;
    3822  }
    3823  return res;
    3824 }
    3825 
    3826 void vmaDestroyBuffer(
    3827  VmaAllocator allocator,
    3828  VkBuffer buffer)
    3829 {
    3830  if(buffer != VK_NULL_HANDLE)
    3831  {
    3832  VMA_ASSERT(allocator);
    3833 
    3834  VMA_DEBUG_LOG("vmaDestroyBuffer");
    3835 
    3836  VMA_DEBUG_GLOBAL_MUTEX_LOCK
    3837 
    3838  VkMappedMemoryRange mem = {};
    3839  {
    3840  VmaMutexLock lock(allocator->m_BufferToMemoryMapMutex);
    3841  VMA_MAP_TYPE(VkBuffer, VkMappedMemoryRange)::iterator it = allocator->m_BufferToMemoryMap.find(buffer);
    3842  if(it == allocator->m_BufferToMemoryMap.end())
    3843  {
    3844  VMA_ASSERT(0 && "Trying to destroy buffer that was not created using vmaCreateBuffer or already freed.");
    3845  return;
    3846  }
    3847  mem = it->second;
    3848  allocator->m_BufferToMemoryMap.erase(it);
    3849  }
    3850 
    3851  vkDestroyBuffer(allocator->m_hDevice, buffer, allocator->GetAllocationCallbacks());
    3852 
    3853  allocator->FreeMemory(&mem);
    3854  }
    3855 }
    3856 
    3857 VkResult vmaCreateImage(
    3858  VmaAllocator allocator,
    3859  const VkImageCreateInfo* pCreateInfo,
    3860  const VmaMemoryRequirements* pMemoryRequirements,
    3861  VkImage* pImage,
    3862  VkMappedMemoryRange* pMemory,
    3863  uint32_t* pMemoryTypeIndex)
    3864 {
    3865  VMA_ASSERT(allocator && pCreateInfo && pMemoryRequirements);
    3866 
    3867  VMA_DEBUG_LOG("vmaCreateImage");
    3868 
    3869  VMA_DEBUG_GLOBAL_MUTEX_LOCK
    3870 
    3871  // 1. Create VkImage.
    3872  VkResult res = vkCreateImage(allocator->m_hDevice, pCreateInfo, allocator->GetAllocationCallbacks(), pImage);
    3873  if(res >= 0)
    3874  {
    3875  VkMappedMemoryRange mem = {};
    3876  VmaSuballocationType suballocType = pCreateInfo->tiling == VK_IMAGE_TILING_OPTIMAL ?
    3877  VMA_SUBALLOCATION_TYPE_IMAGE_OPTIMAL :
    3878  VMA_SUBALLOCATION_TYPE_IMAGE_LINEAR;
    3879 
    3880  // 2. Allocate memory using allocator.
    3881  res = AllocateMemoryForImage(allocator, *pImage, pMemoryRequirements, suballocType, &mem, pMemoryTypeIndex);
    3882  if(res >= 0)
    3883  {
    3884  if(pMemory != VMA_NULL)
    3885  *pMemory = mem;
    3886  // 3. Bind image with memory.
    3887  res = vkBindImageMemory(allocator->m_hDevice, *pImage, mem.memory, mem.offset);
    3888  if(res >= 0)
    3889  {
    3890  // All steps succeeded.
    3891  VmaMutexLock lock(allocator->m_ImageToMemoryMapMutex);
    3892  allocator->m_ImageToMemoryMap.insert(VmaPair<VkImage, VkMappedMemoryRange>(*pImage, mem));
    3893  return VK_SUCCESS;
    3894  }
    3895  allocator->FreeMemory(&mem);
    3896  return res;
    3897  }
    3898  vkDestroyImage(allocator->m_hDevice, *pImage, allocator->GetAllocationCallbacks());
    3899  return res;
    3900  }
    3901  return res;
    3902 }
    3903 
    3904 void vmaDestroyImage(
    3905  VmaAllocator allocator,
    3906  VkImage image)
    3907 {
    3908  if(image != VK_NULL_HANDLE)
    3909  {
    3910  VMA_ASSERT(allocator);
    3911 
    3912  VMA_DEBUG_LOG("vmaDestroyImage");
    3913 
    3914  VMA_DEBUG_GLOBAL_MUTEX_LOCK
    3915 
    3916  VkMappedMemoryRange mem = {};
    3917  {
    3918  VmaMutexLock lock(allocator->m_ImageToMemoryMapMutex);
    3919  VMA_MAP_TYPE(VkImage, VkMappedMemoryRange)::iterator it = allocator->m_ImageToMemoryMap.find(image);
    3920  if(it == allocator->m_ImageToMemoryMap.end())
    3921  {
    3922  VMA_ASSERT(0 && "Trying to destroy buffer that was not created using vmaCreateBuffer or already freed.");
    3923  return;
    3924  }
    3925  mem = it->second;
    3926  allocator->m_ImageToMemoryMap.erase(it);
    3927  }
    3928 
    3929  vkDestroyImage(allocator->m_hDevice, image, allocator->GetAllocationCallbacks());
    3930 
    3931  allocator->FreeMemory(&mem);
    3932  }
    3933 }
    3934 
    3935 #endif // #ifdef VMA_IMPLEMENTATION
    3936 
    3937 #endif // AMD_VULKAN_MEMORY_ALLOCATOR_H
    struct VmaMemoryRequirements VmaMemoryRequirements
    -
    void vmaUnmapMemory(VmaAllocator allocator, const VkMappedMemoryRange *pMemory)
    -
    VkPhysicalDevice physicalDevice
    Vulkan physical device.
    Definition: vk_mem_alloc.h:169
    -
    VkResult vmaMapMemory(VmaAllocator allocator, const VkMappedMemoryRange *pMemory, void **ppData)
    -
    Memory will be used for writing on device and readback on host.
    Definition: vk_mem_alloc.h:282
    -
    VmaMemoryUsage usage
    Intended usage of memory.
    Definition: vk_mem_alloc.h:301
    -
    VkResult vmaAllocateMemoryForImage(VmaAllocator allocator, VkImage image, const VmaMemoryRequirements *pMemoryRequirements, VkMappedMemoryRange *pMemory, uint32_t *pMemoryTypeIndex)
    Function similar to vmaAllocateMemoryForBuffer().
    -
    const VkAllocationCallbacks * pAllocationCallbacks
    Custom allocation callbacks.
    Definition: vk_mem_alloc.h:181
    -
    Description of a Allocator to be created.
    Definition: vk_mem_alloc.h:165
    -
    VkDeviceSize preferredSmallHeapBlockSize
    Size of a single memory block to allocate for resources from a small heap <= 512 MB.
    Definition: vk_mem_alloc.h:178
    -
    VmaStatInfo total
    Definition: vk_mem_alloc.h:236
    -
    VkDevice device
    Vulkan device.
    Definition: vk_mem_alloc.h:172
    -
    VkResult vmaAllocateMemory(VmaAllocator allocator, const VkMemoryRequirements *pVkMemoryRequirements, const VmaMemoryRequirements *pVmaMemoryRequirements, VkMappedMemoryRange *pMemory, uint32_t *pMemoryTypeIndex)
    General purpose memory allocation.
    +Go to the documentation of this file.
    1 //
    2 // Copyright (c) 2017 Advanced Micro Devices, Inc. All rights reserved.
    3 //
    4 // Permission is hereby granted, free of charge, to any person obtaining a copy
    5 // of this software and associated documentation files (the "Software"), to deal
    6 // in the Software without restriction, including without limitation the rights
    7 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
    8 // copies of the Software, and to permit persons to whom the Software is
    9 // furnished to do so, subject to the following conditions:
    10 //
    11 // The above copyright notice and this permission notice shall be included in
    12 // all copies or substantial portions of the Software.
    13 //
    14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    15 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    16 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    17 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    18 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    19 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
    20 // THE SOFTWARE.
    21 //
    22 
    23 #ifndef AMD_VULKAN_MEMORY_ALLOCATOR_H
    24 #define AMD_VULKAN_MEMORY_ALLOCATOR_H
    25 
    161 #include <vulkan/vulkan.h>
    162 
    164 
    168 VK_DEFINE_HANDLE(VmaAllocator)
    169 
    170 typedef void (VKAPI_PTR *PFN_vmaAllocateDeviceMemoryFunction)(
    172  VmaAllocator allocator,
    173  uint32_t memoryType,
    174  VkDeviceMemory memory,
    175  VkDeviceSize size);
    177 typedef void (VKAPI_PTR *PFN_vmaFreeDeviceMemoryFunction)(
    178  VmaAllocator allocator,
    179  uint32_t memoryType,
    180  VkDeviceMemory memory,
    181  VkDeviceSize size);
    182 
    188 typedef struct VmaDeviceMemoryCallbacks {
    194 
    196 typedef enum VmaAllocatorFlagBits {
    202 
    205 typedef VkFlags VmaAllocatorFlags;
    206 
    209 {
    213 
    214  VkPhysicalDevice physicalDevice;
    216 
    217  VkDevice device;
    219 
    222 
    225 
    226  const VkAllocationCallbacks* pAllocationCallbacks;
    228 
    231 
    233 VkResult vmaCreateAllocator(
    234  const VmaAllocatorCreateInfo* pCreateInfo,
    235  VmaAllocator* pAllocator);
    236 
    239  VmaAllocator allocator);
    240 
    246  VmaAllocator allocator,
    247  const VkPhysicalDeviceProperties** ppPhysicalDeviceProperties);
    248 
    254  VmaAllocator allocator,
    255  const VkPhysicalDeviceMemoryProperties** ppPhysicalDeviceMemoryProperties);
    256 
    264  VmaAllocator allocator,
    265  uint32_t memoryTypeIndex,
    266  VkMemoryPropertyFlags* pFlags);
    267 
    268 typedef struct VmaStatInfo
    269 {
    270  uint32_t AllocationCount;
    273  VkDeviceSize UsedBytes;
    274  VkDeviceSize UnusedBytes;
    275  VkDeviceSize SuballocationSizeMin, SuballocationSizeAvg, SuballocationSizeMax;
    276  VkDeviceSize UnusedRangeSizeMin, UnusedRangeSizeAvg, UnusedRangeSizeMax;
    277 } VmaStatInfo;
    278 
    280 struct VmaStats
    281 {
    282  VmaStatInfo memoryType[VK_MAX_MEMORY_TYPES];
    283  VmaStatInfo memoryHeap[VK_MAX_MEMORY_HEAPS];
    285 };
    286 
    288 void vmaCalculateStats(
    289  VmaAllocator allocator,
    290  VmaStats* pStats);
    291 
    292 #define VMA_STATS_STRING_ENABLED 1
    293 
    294 #if VMA_STATS_STRING_ENABLED
    295 
    297 
    300  VmaAllocator allocator,
    301  char** ppStatsString,
    302  VkBool32 detailedMap);
    303 
    304 void vmaFreeStatsString(
    305  VmaAllocator allocator,
    306  char* pStatsString);
    307 
    308 #endif // #if VMA_STATS_STRING_ENABLED
    309 
    312 
    317 typedef enum VmaMemoryUsage
    318 {
    324 
    327 
    330 
    334 
    346 
    362 
    366 
    367 typedef struct VmaMemoryRequirements
    368 {
    378  VkMemoryPropertyFlags requiredFlags;
    383  VkMemoryPropertyFlags preferredFlags;
    385  void* pUserData;
    387 
    402 VkResult vmaFindMemoryTypeIndex(
    403  VmaAllocator allocator,
    404  uint32_t memoryTypeBits,
    405  const VmaMemoryRequirements* pMemoryRequirements,
    406  uint32_t* pMemoryTypeIndex);
    407 
    410 
    415 VK_DEFINE_HANDLE(VmaAllocation)
    416 
    417 
    419 typedef struct VmaAllocationInfo {
    424  uint32_t memoryType;
    431  VkDeviceMemory deviceMemory;
    436  VkDeviceSize offset;
    441  VkDeviceSize size;
    447  void* pMappedData;
    452  void* pUserData;
    454 
    465 VkResult vmaAllocateMemory(
    466  VmaAllocator allocator,
    467  const VkMemoryRequirements* pVkMemoryRequirements,
    468  const VmaMemoryRequirements* pVmaMemoryRequirements,
    469  VmaAllocation* pAllocation,
    470  VmaAllocationInfo* pAllocationInfo);
    471 
    479  VmaAllocator allocator,
    480  VkBuffer buffer,
    481  const VmaMemoryRequirements* pMemoryRequirements,
    482  VmaAllocation* pAllocation,
    483  VmaAllocationInfo* pAllocationInfo);
    484 
    487  VmaAllocator allocator,
    488  VkImage image,
    489  const VmaMemoryRequirements* pMemoryRequirements,
    490  VmaAllocation* pAllocation,
    491  VmaAllocationInfo* pAllocationInfo);
    492 
    494 void vmaFreeMemory(
    495  VmaAllocator allocator,
    496  VmaAllocation allocation);
    497 
    500  VmaAllocator allocator,
    501  VmaAllocation allocation,
    502  VmaAllocationInfo* pAllocationInfo);
    503 
    506  VmaAllocator allocator,
    507  VmaAllocation allocation,
    508  void* pUserData);
    509 
    518 VkResult vmaMapMemory(
    519  VmaAllocator allocator,
    520  VmaAllocation allocation,
    521  void** ppData);
    522 
    523 void vmaUnmapMemory(
    524  VmaAllocator allocator,
    525  VmaAllocation allocation);
    526 
    539 void vmaUnmapPersistentlyMappedMemory(VmaAllocator allocator);
    540 
    548 VkResult vmaMapPersistentlyMappedMemory(VmaAllocator allocator);
    549 
    551 typedef struct VmaDefragmentationInfo {
    556  VkDeviceSize maxBytesToMove;
    563 
    565 typedef struct VmaDefragmentationStats {
    567  VkDeviceSize bytesMoved;
    569  VkDeviceSize bytesFreed;
    575 
    646 VkResult vmaDefragment(
    647  VmaAllocator allocator,
    648  VmaAllocation* pAllocations,
    649  size_t allocationCount,
    650  VkBool32* pAllocationsChanged,
    651  const VmaDefragmentationInfo *pDefragmentationInfo,
    652  VmaDefragmentationStats* pDefragmentationStats);
    653 
    656 
    676 VkResult vmaCreateBuffer(
    677  VmaAllocator allocator,
    678  const VkBufferCreateInfo* pCreateInfo,
    679  const VmaMemoryRequirements* pMemoryRequirements,
    680  VkBuffer* pBuffer,
    681  VmaAllocation* pAllocation,
    682  VmaAllocationInfo* pAllocationInfo);
    683 
    684 void vmaDestroyBuffer(
    685  VmaAllocator allocator,
    686  VkBuffer buffer,
    687  VmaAllocation allocation);
    688 
    690 VkResult vmaCreateImage(
    691  VmaAllocator allocator,
    692  const VkImageCreateInfo* pCreateInfo,
    693  const VmaMemoryRequirements* pMemoryRequirements,
    694  VkImage* pImage,
    695  VmaAllocation* pAllocation,
    696  VmaAllocationInfo* pAllocationInfo);
    697 
    698 void vmaDestroyImage(
    699  VmaAllocator allocator,
    700  VkImage image,
    701  VmaAllocation allocation);
    702 
    705 #endif // AMD_VULKAN_MEMORY_ALLOCATOR_H
    706 
    707 #ifdef VMA_IMPLEMENTATION
    708 #undef VMA_IMPLEMENTATION
    709 
    710 #include <cstdint>
    711 #include <cstdlib>
    712 
    713 /*******************************************************************************
    714 CONFIGURATION SECTION
    715 
    716 Define some of these macros before each #include of this header or change them
    717 here if you need other then default behavior depending on your environment.
    718 */
    719 
    720 // Define this macro to 1 to make the library use STL containers instead of its own implementation.
    721 //#define VMA_USE_STL_CONTAINERS 1
    722 
    723 /* Set this macro to 1 to make the library including and using STL containers:
    724 std::pair, std::vector, std::list, std::unordered_map.
    725 
    726 Set it to 0 or undefined to make the library using its own implementation of
    727 the containers.
    728 */
    729 #if VMA_USE_STL_CONTAINERS
    730  #define VMA_USE_STL_VECTOR 1
    731  #define VMA_USE_STL_UNORDERED_MAP 1
    732  #define VMA_USE_STL_LIST 1
    733 #endif
    734 
    735 #if VMA_USE_STL_VECTOR
    736  #include <vector>
    737 #endif
    738 
    739 #if VMA_USE_STL_UNORDERED_MAP
    740  #include <unordered_map>
    741 #endif
    742 
    743 #if VMA_USE_STL_LIST
    744  #include <list>
    745 #endif
    746 
    747 /*
    748 Following headers are used in this CONFIGURATION section only, so feel free to
    749 remove them if not needed.
    750 */
    751 #include <cassert> // for assert
    752 #include <algorithm> // for min, max
    753 #include <mutex> // for std::mutex
    754 
    755 #if !defined(_WIN32)
    756  #include <malloc.h> // for aligned_alloc()
    757 #endif
    758 
    759 // Normal assert to check for programmer's errors, especially in Debug configuration.
    760 #ifndef VMA_ASSERT
    761  #ifdef _DEBUG
    762  #define VMA_ASSERT(expr) assert(expr)
    763  #else
    764  #define VMA_ASSERT(expr)
    765  #endif
    766 #endif
    767 
    768 // Assert that will be called very often, like inside data structures e.g. operator[].
    769 // Making it non-empty can make program slow.
    770 #ifndef VMA_HEAVY_ASSERT
    771  #ifdef _DEBUG
    772  #define VMA_HEAVY_ASSERT(expr) //VMA_ASSERT(expr)
    773  #else
    774  #define VMA_HEAVY_ASSERT(expr)
    775  #endif
    776 #endif
    777 
    778 #ifndef VMA_NULL
    779  // Value used as null pointer. Define it to e.g.: nullptr, NULL, 0, (void*)0.
    780  #define VMA_NULL nullptr
    781 #endif
    782 
    783 #ifndef VMA_ALIGN_OF
    784  #define VMA_ALIGN_OF(type) (__alignof(type))
    785 #endif
    786 
    787 #ifndef VMA_SYSTEM_ALIGNED_MALLOC
    788  #if defined(_WIN32)
    789  #define VMA_SYSTEM_ALIGNED_MALLOC(size, alignment) (_aligned_malloc((size), (alignment)))
    790  #else
    791  #define VMA_SYSTEM_ALIGNED_MALLOC(size, alignment) (aligned_alloc((alignment), (size) ))
    792  #endif
    793 #endif
    794 
    795 #ifndef VMA_SYSTEM_FREE
    796  #if defined(_WIN32)
    797  #define VMA_SYSTEM_FREE(ptr) _aligned_free(ptr)
    798  #else
    799  #define VMA_SYSTEM_FREE(ptr) free(ptr)
    800  #endif
    801 #endif
    802 
    803 #ifndef VMA_MIN
    804  #define VMA_MIN(v1, v2) (std::min((v1), (v2)))
    805 #endif
    806 
    807 #ifndef VMA_MAX
    808  #define VMA_MAX(v1, v2) (std::max((v1), (v2)))
    809 #endif
    810 
    811 #ifndef VMA_SWAP
    812  #define VMA_SWAP(v1, v2) std::swap((v1), (v2))
    813 #endif
    814 
    815 #ifndef VMA_SORT
    816  #define VMA_SORT(beg, end, cmp) std::sort(beg, end, cmp)
    817 #endif
    818 
    819 #ifndef VMA_DEBUG_LOG
    820  #define VMA_DEBUG_LOG(format, ...)
    821  /*
    822  #define VMA_DEBUG_LOG(format, ...) do { \
    823  printf(format, __VA_ARGS__); \
    824  printf("\n"); \
    825  } while(false)
    826  */
    827 #endif
    828 
    829 // Define this macro to 1 to enable functions: vmaBuildStatsString, vmaFreeStatsString.
    830 #if VMA_STATS_STRING_ENABLED
    831  static inline void VmaUint32ToStr(char* outStr, size_t strLen, uint32_t num)
    832  {
    833  _ultoa_s(num, outStr, strLen, 10);
    834  }
    835  static inline void VmaUint64ToStr(char* outStr, size_t strLen, uint64_t num)
    836  {
    837  _ui64toa_s(num, outStr, strLen, 10);
    838  }
    839 #endif
    840 
    841 #ifndef VMA_MUTEX
    842  class VmaMutex
    843  {
    844  public:
    845  VmaMutex() { }
    846  ~VmaMutex() { }
    847  void Lock() { m_Mutex.lock(); }
    848  void Unlock() { m_Mutex.unlock(); }
    849  private:
    850  std::mutex m_Mutex;
    851  };
    852  #define VMA_MUTEX VmaMutex
    853 #endif
    854 
    855 #ifndef VMA_BEST_FIT
    856 
    868  #define VMA_BEST_FIT (1)
    869 #endif
    870 
    871 #ifndef VMA_DEBUG_ALWAYS_OWN_MEMORY
    872 
    876  #define VMA_DEBUG_ALWAYS_OWN_MEMORY (0)
    877 #endif
    878 
    879 #ifndef VMA_DEBUG_ALIGNMENT
    880 
    884  #define VMA_DEBUG_ALIGNMENT (1)
    885 #endif
    886 
    887 #ifndef VMA_DEBUG_MARGIN
    888 
    892  #define VMA_DEBUG_MARGIN (0)
    893 #endif
    894 
    895 #ifndef VMA_DEBUG_GLOBAL_MUTEX
    896 
    900  #define VMA_DEBUG_GLOBAL_MUTEX (0)
    901 #endif
    902 
    903 #ifndef VMA_DEBUG_MIN_BUFFER_IMAGE_GRANULARITY
    904 
    908  #define VMA_DEBUG_MIN_BUFFER_IMAGE_GRANULARITY (1)
    909 #endif
    910 
    911 #ifndef VMA_SMALL_HEAP_MAX_SIZE
    912  #define VMA_SMALL_HEAP_MAX_SIZE (512 * 1024 * 1024)
    914 #endif
    915 
    916 #ifndef VMA_DEFAULT_LARGE_HEAP_BLOCK_SIZE
    917  #define VMA_DEFAULT_LARGE_HEAP_BLOCK_SIZE (256 * 1024 * 1024)
    919 #endif
    920 
    921 #ifndef VMA_DEFAULT_SMALL_HEAP_BLOCK_SIZE
    922  #define VMA_DEFAULT_SMALL_HEAP_BLOCK_SIZE (64 * 1024 * 1024)
    924 #endif
    925 
    926 /*******************************************************************************
    927 END OF CONFIGURATION
    928 */
    929 
    930 static VkAllocationCallbacks VmaEmptyAllocationCallbacks = {
    931  VMA_NULL, VMA_NULL, VMA_NULL, VMA_NULL, VMA_NULL, VMA_NULL };
    932 
    933 // Returns number of bits set to 1 in (v).
    934 static inline uint32_t CountBitsSet(uint32_t v)
    935 {
    936  uint32_t c = v - ((v >> 1) & 0x55555555);
    937  c = ((c >> 2) & 0x33333333) + (c & 0x33333333);
    938  c = ((c >> 4) + c) & 0x0F0F0F0F;
    939  c = ((c >> 8) + c) & 0x00FF00FF;
    940  c = ((c >> 16) + c) & 0x0000FFFF;
    941  return c;
    942 }
    943 
    944 // Aligns given value up to nearest multiply of align value. For example: VmaAlignUp(11, 8) = 16.
    945 // Use types like uint32_t, uint64_t as T.
    946 template <typename T>
    947 static inline T VmaAlignUp(T val, T align)
    948 {
    949  return (val + align - 1) / align * align;
    950 }
    951 
    952 // Division with mathematical rounding to nearest number.
    953 template <typename T>
    954 inline T VmaRoundDiv(T x, T y)
    955 {
    956  return (x + (y / (T)2)) / y;
    957 }
    958 
    959 #ifndef VMA_SORT
    960 
    961 template<typename Iterator, typename Compare>
    962 Iterator VmaQuickSortPartition(Iterator beg, Iterator end, Compare cmp)
    963 {
    964  Iterator centerValue = end; --centerValue;
    965  Iterator insertIndex = beg;
    966  for(Iterator i = beg; i < centerValue; ++i)
    967  {
    968  if(cmp(*i, *centerValue))
    969  {
    970  if(insertIndex != i)
    971  {
    972  VMA_SWAP(*i, *insertIndex);
    973  }
    974  ++insertIndex;
    975  }
    976  }
    977  if(insertIndex != centerValue)
    978  {
    979  VMA_SWAP(*insertIndex, *centerValue);
    980  }
    981  return insertIndex;
    982 }
    983 
    984 template<typename Iterator, typename Compare>
    985 void VmaQuickSort(Iterator beg, Iterator end, Compare cmp)
    986 {
    987  if(beg < end)
    988  {
    989  Iterator it = VmaQuickSortPartition<Iterator, Compare>(beg, end, cmp);
    990  VmaQuickSort<Iterator, Compare>(beg, it, cmp);
    991  VmaQuickSort<Iterator, Compare>(it + 1, end, cmp);
    992  }
    993 }
    994 
    995 #define VMA_SORT(beg, end, cmp) VmaQuickSort(beg, end, cmp)
    996 
    997 #endif // #ifndef VMA_SORT
    998 
    999 /*
    1000 Returns true if two memory blocks occupy overlapping pages.
    1001 ResourceA must be in less memory offset than ResourceB.
    1002 
    1003 Algorithm is based on "Vulkan 1.0.39 - A Specification (with all registered Vulkan extensions)"
    1004 chapter 11.6 "Resource Memory Association", paragraph "Buffer-Image Granularity".
    1005 */
    1006 static inline bool VmaBlocksOnSamePage(
    1007  VkDeviceSize resourceAOffset,
    1008  VkDeviceSize resourceASize,
    1009  VkDeviceSize resourceBOffset,
    1010  VkDeviceSize pageSize)
    1011 {
    1012  VMA_ASSERT(resourceAOffset + resourceASize <= resourceBOffset && resourceASize > 0 && pageSize > 0);
    1013  VkDeviceSize resourceAEnd = resourceAOffset + resourceASize - 1;
    1014  VkDeviceSize resourceAEndPage = resourceAEnd & ~(pageSize - 1);
    1015  VkDeviceSize resourceBStart = resourceBOffset;
    1016  VkDeviceSize resourceBStartPage = resourceBStart & ~(pageSize - 1);
    1017  return resourceAEndPage == resourceBStartPage;
    1018 }
    1019 
    1020 enum VmaSuballocationType
    1021 {
    1022  VMA_SUBALLOCATION_TYPE_FREE = 0,
    1023  VMA_SUBALLOCATION_TYPE_UNKNOWN = 1,
    1024  VMA_SUBALLOCATION_TYPE_BUFFER = 2,
    1025  VMA_SUBALLOCATION_TYPE_IMAGE_UNKNOWN = 3,
    1026  VMA_SUBALLOCATION_TYPE_IMAGE_LINEAR = 4,
    1027  VMA_SUBALLOCATION_TYPE_IMAGE_OPTIMAL = 5,
    1028  VMA_SUBALLOCATION_TYPE_MAX_ENUM = 0x7FFFFFFF
    1029 };
    1030 
    1031 /*
    1032 Returns true if given suballocation types could conflict and must respect
    1033 VkPhysicalDeviceLimits::bufferImageGranularity. They conflict if one is buffer
    1034 or linear image and another one is optimal image. If type is unknown, behave
    1035 conservatively.
    1036 */
    1037 static inline bool VmaIsBufferImageGranularityConflict(
    1038  VmaSuballocationType suballocType1,
    1039  VmaSuballocationType suballocType2)
    1040 {
    1041  if(suballocType1 > suballocType2)
    1042  {
    1043  VMA_SWAP(suballocType1, suballocType2);
    1044  }
    1045 
    1046  switch(suballocType1)
    1047  {
    1048  case VMA_SUBALLOCATION_TYPE_FREE:
    1049  return false;
    1050  case VMA_SUBALLOCATION_TYPE_UNKNOWN:
    1051  return true;
    1052  case VMA_SUBALLOCATION_TYPE_BUFFER:
    1053  return
    1054  suballocType2 == VMA_SUBALLOCATION_TYPE_IMAGE_UNKNOWN ||
    1055  suballocType2 == VMA_SUBALLOCATION_TYPE_IMAGE_OPTIMAL;
    1056  case VMA_SUBALLOCATION_TYPE_IMAGE_UNKNOWN:
    1057  return
    1058  suballocType2 == VMA_SUBALLOCATION_TYPE_IMAGE_UNKNOWN ||
    1059  suballocType2 == VMA_SUBALLOCATION_TYPE_IMAGE_LINEAR ||
    1060  suballocType2 == VMA_SUBALLOCATION_TYPE_IMAGE_OPTIMAL;
    1061  case VMA_SUBALLOCATION_TYPE_IMAGE_LINEAR:
    1062  return
    1063  suballocType2 == VMA_SUBALLOCATION_TYPE_IMAGE_OPTIMAL;
    1064  case VMA_SUBALLOCATION_TYPE_IMAGE_OPTIMAL:
    1065  return false;
    1066  default:
    1067  VMA_ASSERT(0);
    1068  return true;
    1069  }
    1070 }
    1071 
    1072 // Helper RAII class to lock a mutex in constructor and unlock it in destructor (at the end of scope).
    1073 struct VmaMutexLock
    1074 {
    1075 public:
    1076  VmaMutexLock(VMA_MUTEX& mutex, bool useMutex) :
    1077  m_pMutex(useMutex ? &mutex : VMA_NULL)
    1078  {
    1079  if(m_pMutex)
    1080  {
    1081  m_pMutex->Lock();
    1082  }
    1083  }
    1084 
    1085  ~VmaMutexLock()
    1086  {
    1087  if(m_pMutex)
    1088  {
    1089  m_pMutex->Unlock();
    1090  }
    1091  }
    1092 
    1093 private:
    1094  VMA_MUTEX* m_pMutex;
    1095 };
    1096 
    1097 #if VMA_DEBUG_GLOBAL_MUTEX
    1098  static VMA_MUTEX gDebugGlobalMutex;
    1099  #define VMA_DEBUG_GLOBAL_MUTEX_LOCK VmaMutexLock debugGlobalMutexLock(gDebugGlobalMutex);
    1100 #else
    1101  #define VMA_DEBUG_GLOBAL_MUTEX_LOCK
    1102 #endif
    1103 
    1104 // Minimum size of a free suballocation to register it in the free suballocation collection.
    1105 static const VkDeviceSize VMA_MIN_FREE_SUBALLOCATION_SIZE_TO_REGISTER = 16;
    1106 
    1107 /*
    1108 Performs binary search and returns iterator to first element that is greater or
    1109 equal to (key), according to comparison (cmp).
    1110 
    1111 Cmp should return true if first argument is less than second argument.
    1112 
    1113 Returned value is the found element, if present in the collection or place where
    1114 new element with value (key) should be inserted.
    1115 */
    1116 template <typename IterT, typename KeyT, typename CmpT>
    1117 static IterT VmaBinaryFindFirstNotLess(IterT beg, IterT end, const KeyT &key, CmpT cmp)
    1118 {
    1119  size_t down = 0, up = (end - beg);
    1120  while(down < up)
    1121  {
    1122  const size_t mid = (down + up) / 2;
    1123  if(cmp(*(beg+mid), key))
    1124  {
    1125  down = mid + 1;
    1126  }
    1127  else
    1128  {
    1129  up = mid;
    1130  }
    1131  }
    1132  return beg + down;
    1133 }
    1134 
    1136 // Memory allocation
    1137 
    1138 static void* VmaMalloc(const VkAllocationCallbacks* pAllocationCallbacks, size_t size, size_t alignment)
    1139 {
    1140  if((pAllocationCallbacks != VMA_NULL) &&
    1141  (pAllocationCallbacks->pfnAllocation != VMA_NULL))
    1142  {
    1143  return (*pAllocationCallbacks->pfnAllocation)(
    1144  pAllocationCallbacks->pUserData,
    1145  size,
    1146  alignment,
    1147  VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
    1148  }
    1149  else
    1150  {
    1151  return VMA_SYSTEM_ALIGNED_MALLOC(size, alignment);
    1152  }
    1153 }
    1154 
    1155 static void VmaFree(const VkAllocationCallbacks* pAllocationCallbacks, void* ptr)
    1156 {
    1157  if((pAllocationCallbacks != VMA_NULL) &&
    1158  (pAllocationCallbacks->pfnFree != VMA_NULL))
    1159  {
    1160  (*pAllocationCallbacks->pfnFree)(pAllocationCallbacks->pUserData, ptr);
    1161  }
    1162  else
    1163  {
    1164  VMA_SYSTEM_FREE(ptr);
    1165  }
    1166 }
    1167 
    1168 template<typename T>
    1169 static T* VmaAllocate(const VkAllocationCallbacks* pAllocationCallbacks)
    1170 {
    1171  return (T*)VmaMalloc(pAllocationCallbacks, sizeof(T), VMA_ALIGN_OF(T));
    1172 }
    1173 
    1174 template<typename T>
    1175 static T* VmaAllocateArray(const VkAllocationCallbacks* pAllocationCallbacks, size_t count)
    1176 {
    1177  return (T*)VmaMalloc(pAllocationCallbacks, sizeof(T) * count, VMA_ALIGN_OF(T));
    1178 }
    1179 
    1180 #define vma_new(allocator, type) new(VmaAllocate<type>(allocator))(type)
    1181 
    1182 #define vma_new_array(allocator, type, count) new(VmaAllocateArray<type>((allocator), (count)))(type)
    1183 
    1184 template<typename T>
    1185 static void vma_delete(const VkAllocationCallbacks* pAllocationCallbacks, T* ptr)
    1186 {
    1187  ptr->~T();
    1188  VmaFree(pAllocationCallbacks, ptr);
    1189 }
    1190 
    1191 template<typename T>
    1192 static void vma_delete_array(const VkAllocationCallbacks* pAllocationCallbacks, T* ptr, size_t count)
    1193 {
    1194  if(ptr != VMA_NULL)
    1195  {
    1196  for(size_t i = count; i--; )
    1197  {
    1198  ptr[i].~T();
    1199  }
    1200  VmaFree(pAllocationCallbacks, ptr);
    1201  }
    1202 }
    1203 
    1204 // STL-compatible allocator.
    1205 template<typename T>
    1206 class VmaStlAllocator
    1207 {
    1208 public:
    1209  const VkAllocationCallbacks* const m_pCallbacks;
    1210  typedef T value_type;
    1211 
    1212  VmaStlAllocator(const VkAllocationCallbacks* pCallbacks) : m_pCallbacks(pCallbacks) { }
    1213  template<typename U> VmaStlAllocator(const VmaStlAllocator<U>& src) : m_pCallbacks(src.m_pCallbacks) { }
    1214 
    1215  T* allocate(size_t n) { return VmaAllocateArray<T>(m_pCallbacks, n); }
    1216  void deallocate(T* p, size_t n) { VmaFree(m_pCallbacks, p); }
    1217 
    1218  template<typename U>
    1219  bool operator==(const VmaStlAllocator<U>& rhs) const
    1220  {
    1221  return m_pCallbacks == rhs.m_pCallbacks;
    1222  }
    1223  template<typename U>
    1224  bool operator!=(const VmaStlAllocator<U>& rhs) const
    1225  {
    1226  return m_pCallbacks != rhs.m_pCallbacks;
    1227  }
    1228 
    1229  VmaStlAllocator& operator=(const VmaStlAllocator& x) = delete;
    1230 };
    1231 
    1232 #if VMA_USE_STL_VECTOR
    1233 
    1234 #define VmaVector std::vector
    1235 
    1236 template<typename T, typename allocatorT>
    1237 static void VectorInsert(std::vector<T, allocatorT>& vec, size_t index, const T& item)
    1238 {
    1239  vec.insert(vec.begin() + index, item);
    1240 }
    1241 
    1242 template<typename T, typename allocatorT>
    1243 static void VectorRemove(std::vector<T, allocatorT>& vec, size_t index)
    1244 {
    1245  vec.erase(vec.begin() + index);
    1246 }
    1247 
    1248 #else // #if VMA_USE_STL_VECTOR
    1249 
    1250 /* Class with interface compatible with subset of std::vector.
    1251 T must be POD because constructors and destructors are not called and memcpy is
    1252 used for these objects. */
    1253 template<typename T, typename AllocatorT>
    1254 class VmaVector
    1255 {
    1256 public:
    1257  VmaVector(const AllocatorT& allocator) :
    1258  m_Allocator(allocator),
    1259  m_pArray(VMA_NULL),
    1260  m_Count(0),
    1261  m_Capacity(0)
    1262  {
    1263  }
    1264 
    1265  VmaVector(size_t count, const AllocatorT& allocator) :
    1266  m_Allocator(allocator),
    1267  m_pArray(count ? (T*)VmaAllocateArray<T>(allocator->m_pCallbacks, count) : VMA_NULL),
    1268  m_Count(count),
    1269  m_Capacity(count)
    1270  {
    1271  }
    1272 
    1273  VmaVector(const VmaVector<T, AllocatorT>& src) :
    1274  m_Allocator(src.m_Allocator),
    1275  m_pArray(src.m_Count ? (T*)VmaAllocateArray<T>(src->m_pCallbacks, src.m_Count) : VMA_NULL),
    1276  m_Count(src.m_Count),
    1277  m_Capacity(src.m_Count)
    1278  {
    1279  if(m_Count != 0)
    1280  {
    1281  memcpy(m_pArray, src.m_pArray, m_Count * sizeof(T));
    1282  }
    1283  }
    1284 
    1285  ~VmaVector()
    1286  {
    1287  VmaFree(m_Allocator.m_pCallbacks, m_pArray);
    1288  }
    1289 
    1290  VmaVector& operator=(const VmaVector<T, AllocatorT>& rhs)
    1291  {
    1292  if(&rhs != this)
    1293  {
    1294  Resize(rhs.m_Count);
    1295  if(m_Count != 0)
    1296  {
    1297  memcpy(m_pArray, rhs.m_pArray, m_Count * sizeof(T));
    1298  }
    1299  }
    1300  return *this;
    1301  }
    1302 
    1303  bool empty() const { return m_Count == 0; }
    1304  size_t size() const { return m_Count; }
    1305  T* data() { return m_pArray; }
    1306  const T* data() const { return m_pArray; }
    1307 
    1308  T& operator[](size_t index)
    1309  {
    1310  VMA_HEAVY_ASSERT(index < m_Count);
    1311  return m_pArray[index];
    1312  }
    1313  const T& operator[](size_t index) const
    1314  {
    1315  VMA_HEAVY_ASSERT(index < m_Count);
    1316  return m_pArray[index];
    1317  }
    1318 
    1319  T& front()
    1320  {
    1321  VMA_HEAVY_ASSERT(m_Count > 0);
    1322  return m_pArray[0];
    1323  }
    1324  const T& front() const
    1325  {
    1326  VMA_HEAVY_ASSERT(m_Count > 0);
    1327  return m_pArray[0];
    1328  }
    1329  T& back()
    1330  {
    1331  VMA_HEAVY_ASSERT(m_Count > 0);
    1332  return m_pArray[m_Count - 1];
    1333  }
    1334  const T& back() const
    1335  {
    1336  VMA_HEAVY_ASSERT(m_Count > 0);
    1337  return m_pArray[m_Count - 1];
    1338  }
    1339 
    1340  void reserve(size_t newCapacity, bool freeMemory = false)
    1341  {
    1342  newCapacity = VMA_MAX(newCapacity, m_Count);
    1343 
    1344  if((newCapacity < m_Capacity) && !freeMemory)
    1345  {
    1346  newCapacity = m_Capacity;
    1347  }
    1348 
    1349  if(newCapacity != m_Capacity)
    1350  {
    1351  T* const newArray = newCapacity ? VmaAllocateArray<T>(m_Allocator, newCapacity) : VMA_NULL;
    1352  if(m_Count != 0)
    1353  {
    1354  memcpy(newArray, m_pArray, m_Count * sizeof(T));
    1355  }
    1356  VmaFree(m_Allocator.m_pCallbacks, m_pArray);
    1357  m_Capacity = newCapacity;
    1358  m_pArray = newArray;
    1359  }
    1360  }
    1361 
    1362  void resize(size_t newCount, bool freeMemory = false)
    1363  {
    1364  size_t newCapacity = m_Capacity;
    1365  if(newCount > m_Capacity)
    1366  {
    1367  newCapacity = VMA_MAX(newCount, VMA_MAX(m_Capacity * 3 / 2, (size_t)8));
    1368  }
    1369  else if(freeMemory)
    1370  {
    1371  newCapacity = newCount;
    1372  }
    1373 
    1374  if(newCapacity != m_Capacity)
    1375  {
    1376  T* const newArray = newCapacity ? VmaAllocateArray<T>(m_Allocator.m_pCallbacks, newCapacity) : VMA_NULL;
    1377  const size_t elementsToCopy = VMA_MIN(m_Count, newCount);
    1378  if(elementsToCopy != 0)
    1379  {
    1380  memcpy(newArray, m_pArray, elementsToCopy * sizeof(T));
    1381  }
    1382  VmaFree(m_Allocator.m_pCallbacks, m_pArray);
    1383  m_Capacity = newCapacity;
    1384  m_pArray = newArray;
    1385  }
    1386 
    1387  m_Count = newCount;
    1388  }
    1389 
    1390  void clear(bool freeMemory = false)
    1391  {
    1392  resize(0, freeMemory);
    1393  }
    1394 
    1395  void insert(size_t index, const T& src)
    1396  {
    1397  VMA_HEAVY_ASSERT(index <= m_Count);
    1398  const size_t oldCount = size();
    1399  resize(oldCount + 1);
    1400  if(index < oldCount)
    1401  {
    1402  memmove(m_pArray + (index + 1), m_pArray + index, (oldCount - index) * sizeof(T));
    1403  }
    1404  m_pArray[index] = src;
    1405  }
    1406 
    1407  void remove(size_t index)
    1408  {
    1409  VMA_HEAVY_ASSERT(index < m_Count);
    1410  const size_t oldCount = size();
    1411  if(index < oldCount - 1)
    1412  {
    1413  memmove(m_pArray + index, m_pArray + (index + 1), (oldCount - index - 1) * sizeof(T));
    1414  }
    1415  resize(oldCount - 1);
    1416  }
    1417 
    1418  void push_back(const T& src)
    1419  {
    1420  const size_t newIndex = size();
    1421  resize(newIndex + 1);
    1422  m_pArray[newIndex] = src;
    1423  }
    1424 
    1425  void pop_back()
    1426  {
    1427  VMA_HEAVY_ASSERT(m_Count > 0);
    1428  resize(size() - 1);
    1429  }
    1430 
    1431  void push_front(const T& src)
    1432  {
    1433  insert(0, src);
    1434  }
    1435 
    1436  void pop_front()
    1437  {
    1438  VMA_HEAVY_ASSERT(m_Count > 0);
    1439  remove(0);
    1440  }
    1441 
    1442  typedef T* iterator;
    1443 
    1444  iterator begin() { return m_pArray; }
    1445  iterator end() { return m_pArray + m_Count; }
    1446 
    1447 private:
    1448  AllocatorT m_Allocator;
    1449  T* m_pArray;
    1450  size_t m_Count;
    1451  size_t m_Capacity;
    1452 };
    1453 
    1454 template<typename T, typename allocatorT>
    1455 static void VectorInsert(VmaVector<T, allocatorT>& vec, size_t index, const T& item)
    1456 {
    1457  vec.insert(index, item);
    1458 }
    1459 
    1460 template<typename T, typename allocatorT>
    1461 static void VectorRemove(VmaVector<T, allocatorT>& vec, size_t index)
    1462 {
    1463  vec.remove(index);
    1464 }
    1465 
    1466 #endif // #if VMA_USE_STL_VECTOR
    1467 
    1469 // class VmaPoolAllocator
    1470 
    1471 /*
    1472 Allocator for objects of type T using a list of arrays (pools) to speed up
    1473 allocation. Number of elements that can be allocated is not bounded because
    1474 allocator can create multiple blocks.
    1475 */
    1476 template<typename T>
    1477 class VmaPoolAllocator
    1478 {
    1479 public:
    1480  VmaPoolAllocator(const VkAllocationCallbacks* pAllocationCallbacks, size_t itemsPerBlock);
    1481  ~VmaPoolAllocator();
    1482  void Clear();
    1483  T* Alloc();
    1484  void Free(T* ptr);
    1485 
    1486 private:
    1487  union Item
    1488  {
    1489  uint32_t NextFreeIndex;
    1490  T Value;
    1491  };
    1492 
    1493  struct ItemBlock
    1494  {
    1495  Item* pItems;
    1496  uint32_t FirstFreeIndex;
    1497  };
    1498 
    1499  const VkAllocationCallbacks* m_pAllocationCallbacks;
    1500  size_t m_ItemsPerBlock;
    1501  VmaVector< ItemBlock, VmaStlAllocator<ItemBlock> > m_ItemBlocks;
    1502 
    1503  ItemBlock& CreateNewBlock();
    1504 };
    1505 
    1506 template<typename T>
    1507 VmaPoolAllocator<T>::VmaPoolAllocator(const VkAllocationCallbacks* pAllocationCallbacks, size_t itemsPerBlock) :
    1508  m_pAllocationCallbacks(pAllocationCallbacks),
    1509  m_ItemsPerBlock(itemsPerBlock),
    1510  m_ItemBlocks(VmaStlAllocator<ItemBlock>(pAllocationCallbacks))
    1511 {
    1512  VMA_ASSERT(itemsPerBlock > 0);
    1513 }
    1514 
    1515 template<typename T>
    1516 VmaPoolAllocator<T>::~VmaPoolAllocator()
    1517 {
    1518  Clear();
    1519 }
    1520 
    1521 template<typename T>
    1522 void VmaPoolAllocator<T>::Clear()
    1523 {
    1524  for(size_t i = m_ItemBlocks.size(); i--; )
    1525  vma_delete_array(m_pAllocationCallbacks, m_ItemBlocks[i].pItems, m_ItemsPerBlock);
    1526  m_ItemBlocks.clear();
    1527 }
    1528 
    1529 template<typename T>
    1530 T* VmaPoolAllocator<T>::Alloc()
    1531 {
    1532  for(size_t i = m_ItemBlocks.size(); i--; )
    1533  {
    1534  ItemBlock& block = m_ItemBlocks[i];
    1535  // This block has some free items: Use first one.
    1536  if(block.FirstFreeIndex != UINT32_MAX)
    1537  {
    1538  Item* const pItem = &block.pItems[block.FirstFreeIndex];
    1539  block.FirstFreeIndex = pItem->NextFreeIndex;
    1540  return &pItem->Value;
    1541  }
    1542  }
    1543 
    1544  // No block has free item: Create new one and use it.
    1545  ItemBlock& newBlock = CreateNewBlock();
    1546  Item* const pItem = &newBlock.pItems[0];
    1547  newBlock.FirstFreeIndex = pItem->NextFreeIndex;
    1548  return &pItem->Value;
    1549 }
    1550 
    1551 template<typename T>
    1552 void VmaPoolAllocator<T>::Free(T* ptr)
    1553 {
    1554  // Search all memory blocks to find ptr.
    1555  for(size_t i = 0; i < m_ItemBlocks.size(); ++i)
    1556  {
    1557  ItemBlock& block = m_ItemBlocks[i];
    1558 
    1559  // Casting to union.
    1560  Item* pItemPtr;
    1561  memcpy(&pItemPtr, &ptr, sizeof(pItemPtr));
    1562 
    1563  // Check if pItemPtr is in address range of this block.
    1564  if((pItemPtr >= block.pItems) && (pItemPtr < block.pItems + m_ItemsPerBlock))
    1565  {
    1566  const uint32_t index = static_cast<uint32_t>(pItemPtr - block.pItems);
    1567  pItemPtr->NextFreeIndex = block.FirstFreeIndex;
    1568  block.FirstFreeIndex = index;
    1569  return;
    1570  }
    1571  }
    1572  VMA_ASSERT(0 && "Pointer doesn't belong to this memory pool.");
    1573 }
    1574 
    1575 template<typename T>
    1576 typename VmaPoolAllocator<T>::ItemBlock& VmaPoolAllocator<T>::CreateNewBlock()
    1577 {
    1578  ItemBlock newBlock = {
    1579  vma_new_array(m_pAllocationCallbacks, Item, m_ItemsPerBlock), 0 };
    1580 
    1581  m_ItemBlocks.push_back(newBlock);
    1582 
    1583  // Setup singly-linked list of all free items in this block.
    1584  for(uint32_t i = 0; i < m_ItemsPerBlock - 1; ++i)
    1585  newBlock.pItems[i].NextFreeIndex = i + 1;
    1586  newBlock.pItems[m_ItemsPerBlock - 1].NextFreeIndex = UINT32_MAX;
    1587  return m_ItemBlocks.back();
    1588 }
    1589 
    1591 // class VmaRawList, VmaList
    1592 
    1593 #if VMA_USE_STL_LIST
    1594 
    1595 #define VmaList std::list
    1596 
    1597 #else // #if VMA_USE_STL_LIST
    1598 
    1599 template<typename T>
    1600 struct VmaListItem
    1601 {
    1602  VmaListItem* pPrev;
    1603  VmaListItem* pNext;
    1604  T Value;
    1605 };
    1606 
    1607 // Doubly linked list.
    1608 template<typename T>
    1609 class VmaRawList
    1610 {
    1611 public:
    1612  typedef VmaListItem<T> ItemType;
    1613 
    1614  VmaRawList(const VkAllocationCallbacks* pAllocationCallbacks);
    1615  ~VmaRawList();
    1616  void Clear();
    1617 
    1618  size_t GetCount() const { return m_Count; }
    1619  bool IsEmpty() const { return m_Count == 0; }
    1620 
    1621  ItemType* Front() { return m_pFront; }
    1622  const ItemType* Front() const { return m_pFront; }
    1623  ItemType* Back() { return m_pBack; }
    1624  const ItemType* Back() const { return m_pBack; }
    1625 
    1626  ItemType* PushBack();
    1627  ItemType* PushFront();
    1628  ItemType* PushBack(const T& value);
    1629  ItemType* PushFront(const T& value);
    1630  void PopBack();
    1631  void PopFront();
    1632 
    1633  // Item can be null - it means PushBack.
    1634  ItemType* InsertBefore(ItemType* pItem);
    1635  // Item can be null - it means PushFront.
    1636  ItemType* InsertAfter(ItemType* pItem);
    1637 
    1638  ItemType* InsertBefore(ItemType* pItem, const T& value);
    1639  ItemType* InsertAfter(ItemType* pItem, const T& value);
    1640 
    1641  void Remove(ItemType* pItem);
    1642 
    1643 private:
    1644  const VkAllocationCallbacks* const m_pAllocationCallbacks;
    1645  VmaPoolAllocator<ItemType> m_ItemAllocator;
    1646  ItemType* m_pFront;
    1647  ItemType* m_pBack;
    1648  size_t m_Count;
    1649 
    1650  // Declared not defined, to block copy constructor and assignment operator.
    1651  VmaRawList(const VmaRawList<T>& src);
    1652  VmaRawList<T>& operator=(const VmaRawList<T>& rhs);
    1653 };
    1654 
    1655 template<typename T>
    1656 VmaRawList<T>::VmaRawList(const VkAllocationCallbacks* pAllocationCallbacks) :
    1657  m_pAllocationCallbacks(pAllocationCallbacks),
    1658  m_ItemAllocator(pAllocationCallbacks, 128),
    1659  m_pFront(VMA_NULL),
    1660  m_pBack(VMA_NULL),
    1661  m_Count(0)
    1662 {
    1663 }
    1664 
    1665 template<typename T>
    1666 VmaRawList<T>::~VmaRawList()
    1667 {
    1668  // Intentionally not calling Clear, because that would be unnecessary
    1669  // computations to return all items to m_ItemAllocator as free.
    1670 }
    1671 
    1672 template<typename T>
    1673 void VmaRawList<T>::Clear()
    1674 {
    1675  if(IsEmpty() == false)
    1676  {
    1677  ItemType* pItem = m_pBack;
    1678  while(pItem != VMA_NULL)
    1679  {
    1680  ItemType* const pPrevItem = pItem->pPrev;
    1681  m_ItemAllocator.Free(pItem);
    1682  pItem = pPrevItem;
    1683  }
    1684  m_pFront = VMA_NULL;
    1685  m_pBack = VMA_NULL;
    1686  m_Count = 0;
    1687  }
    1688 }
    1689 
    1690 template<typename T>
    1691 VmaListItem<T>* VmaRawList<T>::PushBack()
    1692 {
    1693  ItemType* const pNewItem = m_ItemAllocator.Alloc();
    1694  pNewItem->pNext = VMA_NULL;
    1695  if(IsEmpty())
    1696  {
    1697  pNewItem->pPrev = VMA_NULL;
    1698  m_pFront = pNewItem;
    1699  m_pBack = pNewItem;
    1700  m_Count = 1;
    1701  }
    1702  else
    1703  {
    1704  pNewItem->pPrev = m_pBack;
    1705  m_pBack->pNext = pNewItem;
    1706  m_pBack = pNewItem;
    1707  ++m_Count;
    1708  }
    1709  return pNewItem;
    1710 }
    1711 
    1712 template<typename T>
    1713 VmaListItem<T>* VmaRawList<T>::PushFront()
    1714 {
    1715  ItemType* const pNewItem = m_ItemAllocator.Alloc();
    1716  pNewItem->pPrev = VMA_NULL;
    1717  if(IsEmpty())
    1718  {
    1719  pNewItem->pNext = VMA_NULL;
    1720  m_pFront = pNewItem;
    1721  m_pBack = pNewItem;
    1722  m_Count = 1;
    1723  }
    1724  else
    1725  {
    1726  pNewItem->pNext = m_pFront;
    1727  m_pFront->pPrev = pNewItem;
    1728  m_pFront = pNewItem;
    1729  ++m_Count;
    1730  }
    1731  return pNewItem;
    1732 }
    1733 
    1734 template<typename T>
    1735 VmaListItem<T>* VmaRawList<T>::PushBack(const T& value)
    1736 {
    1737  ItemType* const pNewItem = PushBack();
    1738  pNewItem->Value = value;
    1739  return pNewItem;
    1740 }
    1741 
    1742 template<typename T>
    1743 VmaListItem<T>* VmaRawList<T>::PushFront(const T& value)
    1744 {
    1745  ItemType* const pNewItem = PushFront();
    1746  pNewItem->Value = value;
    1747  return pNewItem;
    1748 }
    1749 
    1750 template<typename T>
    1751 void VmaRawList<T>::PopBack()
    1752 {
    1753  VMA_HEAVY_ASSERT(m_Count > 0);
    1754  ItemType* const pBackItem = m_pBack;
    1755  ItemType* const pPrevItem = pBackItem->pPrev;
    1756  if(pPrevItem != VMA_NULL)
    1757  {
    1758  pPrevItem->pNext = VMA_NULL;
    1759  }
    1760  m_pBack = pPrevItem;
    1761  m_ItemAllocator.Free(pBackItem);
    1762  --m_Count;
    1763 }
    1764 
    1765 template<typename T>
    1766 void VmaRawList<T>::PopFront()
    1767 {
    1768  VMA_HEAVY_ASSERT(m_Count > 0);
    1769  ItemType* const pFrontItem = m_pFront;
    1770  ItemType* const pNextItem = pFrontItem->pNext;
    1771  if(pNextItem != VMA_NULL)
    1772  {
    1773  pNextItem->pPrev = VMA_NULL;
    1774  }
    1775  m_pFront = pNextItem;
    1776  m_ItemAllocator.Free(pFrontItem);
    1777  --m_Count;
    1778 }
    1779 
    1780 template<typename T>
    1781 void VmaRawList<T>::Remove(ItemType* pItem)
    1782 {
    1783  VMA_HEAVY_ASSERT(pItem != VMA_NULL);
    1784  VMA_HEAVY_ASSERT(m_Count > 0);
    1785 
    1786  if(pItem->pPrev != VMA_NULL)
    1787  {
    1788  pItem->pPrev->pNext = pItem->pNext;
    1789  }
    1790  else
    1791  {
    1792  VMA_HEAVY_ASSERT(m_pFront == pItem);
    1793  m_pFront = pItem->pNext;
    1794  }
    1795 
    1796  if(pItem->pNext != VMA_NULL)
    1797  {
    1798  pItem->pNext->pPrev = pItem->pPrev;
    1799  }
    1800  else
    1801  {
    1802  VMA_HEAVY_ASSERT(m_pBack == pItem);
    1803  m_pBack = pItem->pPrev;
    1804  }
    1805 
    1806  m_ItemAllocator.Free(pItem);
    1807  --m_Count;
    1808 }
    1809 
    1810 template<typename T>
    1811 VmaListItem<T>* VmaRawList<T>::InsertBefore(ItemType* pItem)
    1812 {
    1813  if(pItem != VMA_NULL)
    1814  {
    1815  ItemType* const prevItem = pItem->pPrev;
    1816  ItemType* const newItem = m_ItemAllocator.Alloc();
    1817  newItem->pPrev = prevItem;
    1818  newItem->pNext = pItem;
    1819  pItem->pPrev = newItem;
    1820  if(prevItem != VMA_NULL)
    1821  {
    1822  prevItem->pNext = newItem;
    1823  }
    1824  else
    1825  {
    1826  VMA_HEAVY_ASSERT(m_pFront == pItem);
    1827  m_pFront = newItem;
    1828  }
    1829  ++m_Count;
    1830  return newItem;
    1831  }
    1832  else
    1833  return PushBack();
    1834 }
    1835 
    1836 template<typename T>
    1837 VmaListItem<T>* VmaRawList<T>::InsertAfter(ItemType* pItem)
    1838 {
    1839  if(pItem != VMA_NULL)
    1840  {
    1841  ItemType* const nextItem = pItem->pNext;
    1842  ItemType* const newItem = m_ItemAllocator.Alloc();
    1843  newItem->pNext = nextItem;
    1844  newItem->pPrev = pItem;
    1845  pItem->pNext = newItem;
    1846  if(nextItem != VMA_NULL)
    1847  {
    1848  nextItem->pPrev = newItem;
    1849  }
    1850  else
    1851  {
    1852  VMA_HEAVY_ASSERT(m_pBack == pItem);
    1853  m_pBack = newItem;
    1854  }
    1855  ++m_Count;
    1856  return newItem;
    1857  }
    1858  else
    1859  return PushFront();
    1860 }
    1861 
    1862 template<typename T>
    1863 VmaListItem<T>* VmaRawList<T>::InsertBefore(ItemType* pItem, const T& value)
    1864 {
    1865  ItemType* const newItem = InsertBefore(pItem);
    1866  newItem->Value = value;
    1867  return newItem;
    1868 }
    1869 
    1870 template<typename T>
    1871 VmaListItem<T>* VmaRawList<T>::InsertAfter(ItemType* pItem, const T& value)
    1872 {
    1873  ItemType* const newItem = InsertAfter(pItem);
    1874  newItem->Value = value;
    1875  return newItem;
    1876 }
    1877 
    1878 template<typename T, typename AllocatorT>
    1879 class VmaList
    1880 {
    1881 public:
    1882  class iterator
    1883  {
    1884  public:
    1885  iterator() :
    1886  m_pList(VMA_NULL),
    1887  m_pItem(VMA_NULL)
    1888  {
    1889  }
    1890 
    1891  T& operator*() const
    1892  {
    1893  VMA_HEAVY_ASSERT(m_pItem != VMA_NULL);
    1894  return m_pItem->Value;
    1895  }
    1896  T* operator->() const
    1897  {
    1898  VMA_HEAVY_ASSERT(m_pItem != VMA_NULL);
    1899  return &m_pItem->Value;
    1900  }
    1901 
    1902  iterator& operator++()
    1903  {
    1904  VMA_HEAVY_ASSERT(m_pItem != VMA_NULL);
    1905  m_pItem = m_pItem->pNext;
    1906  return *this;
    1907  }
    1908  iterator& operator--()
    1909  {
    1910  if(m_pItem != VMA_NULL)
    1911  {
    1912  m_pItem = m_pItem->pPrev;
    1913  }
    1914  else
    1915  {
    1916  VMA_HEAVY_ASSERT(!m_pList.IsEmpty());
    1917  m_pItem = m_pList->Back();
    1918  }
    1919  return *this;
    1920  }
    1921 
    1922  iterator operator++(int)
    1923  {
    1924  iterator result = *this;
    1925  ++*this;
    1926  return result;
    1927  }
    1928  iterator operator--(int)
    1929  {
    1930  iterator result = *this;
    1931  --*this;
    1932  return result;
    1933  }
    1934 
    1935  bool operator==(const iterator& rhs) const
    1936  {
    1937  VMA_HEAVY_ASSERT(m_pList == rhs.m_pList);
    1938  return m_pItem == rhs.m_pItem;
    1939  }
    1940  bool operator!=(const iterator& rhs) const
    1941  {
    1942  VMA_HEAVY_ASSERT(m_pList == rhs.m_pList);
    1943  return m_pItem != rhs.m_pItem;
    1944  }
    1945 
    1946  private:
    1947  VmaRawList<T>* m_pList;
    1948  VmaListItem<T>* m_pItem;
    1949 
    1950  iterator(VmaRawList<T>* pList, VmaListItem<T>* pItem) :
    1951  m_pList(pList),
    1952  m_pItem(pItem)
    1953  {
    1954  }
    1955 
    1956  friend class VmaList<T, AllocatorT>;
    1957  friend class VmaList<T, AllocatorT>:: const_iterator;
    1958  };
    1959 
    1960  class const_iterator
    1961  {
    1962  public:
    1963  const_iterator() :
    1964  m_pList(VMA_NULL),
    1965  m_pItem(VMA_NULL)
    1966  {
    1967  }
    1968 
    1969  const_iterator(const iterator& src) :
    1970  m_pList(src.m_pList),
    1971  m_pItem(src.m_pItem)
    1972  {
    1973  }
    1974 
    1975  const T& operator*() const
    1976  {
    1977  VMA_HEAVY_ASSERT(m_pItem != VMA_NULL);
    1978  return m_pItem->Value;
    1979  }
    1980  const T* operator->() const
    1981  {
    1982  VMA_HEAVY_ASSERT(m_pItem != VMA_NULL);
    1983  return &m_pItem->Value;
    1984  }
    1985 
    1986  const_iterator& operator++()
    1987  {
    1988  VMA_HEAVY_ASSERT(m_pItem != VMA_NULL);
    1989  m_pItem = m_pItem->pNext;
    1990  return *this;
    1991  }
    1992  const_iterator& operator--()
    1993  {
    1994  if(m_pItem != VMA_NULL)
    1995  {
    1996  m_pItem = m_pItem->pPrev;
    1997  }
    1998  else
    1999  {
    2000  VMA_HEAVY_ASSERT(!m_pList->IsEmpty());
    2001  m_pItem = m_pList->Back();
    2002  }
    2003  return *this;
    2004  }
    2005 
    2006  const_iterator operator++(int)
    2007  {
    2008  const_iterator result = *this;
    2009  ++*this;
    2010  return result;
    2011  }
    2012  const_iterator operator--(int)
    2013  {
    2014  const_iterator result = *this;
    2015  --*this;
    2016  return result;
    2017  }
    2018 
    2019  bool operator==(const const_iterator& rhs) const
    2020  {
    2021  VMA_HEAVY_ASSERT(m_pList == rhs.m_pList);
    2022  return m_pItem == rhs.m_pItem;
    2023  }
    2024  bool operator!=(const const_iterator& rhs) const
    2025  {
    2026  VMA_HEAVY_ASSERT(m_pList == rhs.m_pList);
    2027  return m_pItem != rhs.m_pItem;
    2028  }
    2029 
    2030  private:
    2031  const_iterator(const VmaRawList<T>* pList, const VmaListItem<T>* pItem) :
    2032  m_pList(pList),
    2033  m_pItem(pItem)
    2034  {
    2035  }
    2036 
    2037  const VmaRawList<T>* m_pList;
    2038  const VmaListItem<T>* m_pItem;
    2039 
    2040  friend class VmaList<T, AllocatorT>;
    2041  };
    2042 
    2043  VmaList(const AllocatorT& allocator) : m_RawList(allocator.m_pCallbacks) { }
    2044 
    2045  bool empty() const { return m_RawList.IsEmpty(); }
    2046  size_t size() const { return m_RawList.GetCount(); }
    2047 
    2048  iterator begin() { return iterator(&m_RawList, m_RawList.Front()); }
    2049  iterator end() { return iterator(&m_RawList, VMA_NULL); }
    2050 
    2051  const_iterator cbegin() const { return const_iterator(&m_RawList, m_RawList.Front()); }
    2052  const_iterator cend() const { return const_iterator(&m_RawList, VMA_NULL); }
    2053 
    2054  void clear() { m_RawList.Clear(); }
    2055  void push_back(const T& value) { m_RawList.PushBack(value); }
    2056  void erase(iterator it) { m_RawList.Remove(it.m_pItem); }
    2057  iterator insert(iterator it, const T& value) { return iterator(&m_RawList, m_RawList.InsertBefore(it.m_pItem, value)); }
    2058 
    2059 private:
    2060  VmaRawList<T> m_RawList;
    2061 };
    2062 
    2063 #endif // #if VMA_USE_STL_LIST
    2064 
    2066 // class VmaMap
    2067 
    2068 #if VMA_USE_STL_UNORDERED_MAP
    2069 
    2070 #define VmaPair std::pair
    2071 
    2072 #define VMA_MAP_TYPE(KeyT, ValueT) \
    2073  std::unordered_map< KeyT, ValueT, std::hash<KeyT>, std::equal_to<KeyT>, VmaStlAllocator< std::pair<KeyT, ValueT> > >
    2074 
    2075 #else // #if VMA_USE_STL_UNORDERED_MAP
    2076 
    2077 template<typename T1, typename T2>
    2078 struct VmaPair
    2079 {
    2080  T1 first;
    2081  T2 second;
    2082 
    2083  VmaPair() : first(), second() { }
    2084  VmaPair(const T1& firstSrc, const T2& secondSrc) : first(firstSrc), second(secondSrc) { }
    2085 };
    2086 
    2087 /* Class compatible with subset of interface of std::unordered_map.
    2088 KeyT, ValueT must be POD because they will be stored in VmaVector.
    2089 */
    2090 template<typename KeyT, typename ValueT>
    2091 class VmaMap
    2092 {
    2093 public:
    2094  typedef VmaPair<KeyT, ValueT> PairType;
    2095  typedef PairType* iterator;
    2096 
    2097  VmaMap(const VmaStlAllocator<PairType>& allocator) : m_Vector(allocator) { }
    2098 
    2099  iterator begin() { return m_Vector.begin(); }
    2100  iterator end() { return m_Vector.end(); }
    2101 
    2102  void insert(const PairType& pair);
    2103  iterator find(const KeyT& key);
    2104  void erase(iterator it);
    2105 
    2106 private:
    2107  VmaVector< PairType, VmaStlAllocator<PairType> > m_Vector;
    2108 };
    2109 
    2110 #define VMA_MAP_TYPE(KeyT, ValueT) VmaMap<KeyT, ValueT>
    2111 
    2112 template<typename FirstT, typename SecondT>
    2113 struct VmaPairFirstLess
    2114 {
    2115  bool operator()(const VmaPair<FirstT, SecondT>& lhs, const VmaPair<FirstT, SecondT>& rhs) const
    2116  {
    2117  return lhs.first < rhs.first;
    2118  }
    2119  bool operator()(const VmaPair<FirstT, SecondT>& lhs, const FirstT& rhsFirst) const
    2120  {
    2121  return lhs.first < rhsFirst;
    2122  }
    2123 };
    2124 
    2125 template<typename KeyT, typename ValueT>
    2126 void VmaMap<KeyT, ValueT>::insert(const PairType& pair)
    2127 {
    2128  const size_t indexToInsert = VmaBinaryFindFirstNotLess(
    2129  m_Vector.data(),
    2130  m_Vector.data() + m_Vector.size(),
    2131  pair,
    2132  VmaPairFirstLess<KeyT, ValueT>()) - m_Vector.data();
    2133  VectorInsert(m_Vector, indexToInsert, pair);
    2134 }
    2135 
    2136 template<typename KeyT, typename ValueT>
    2137 VmaPair<KeyT, ValueT>* VmaMap<KeyT, ValueT>::find(const KeyT& key)
    2138 {
    2139  PairType* it = VmaBinaryFindFirstNotLess(
    2140  m_Vector.data(),
    2141  m_Vector.data() + m_Vector.size(),
    2142  key,
    2143  VmaPairFirstLess<KeyT, ValueT>());
    2144  if((it != m_Vector.end()) && (it->first == key))
    2145  {
    2146  return it;
    2147  }
    2148  else
    2149  {
    2150  return m_Vector.end();
    2151  }
    2152 }
    2153 
    2154 template<typename KeyT, typename ValueT>
    2155 void VmaMap<KeyT, ValueT>::erase(iterator it)
    2156 {
    2157  VectorRemove(m_Vector, it - m_Vector.begin());
    2158 }
    2159 
    2160 #endif // #if VMA_USE_STL_UNORDERED_MAP
    2161 
    2163 
    2164 class VmaBlock;
    2165 
    2166 enum VMA_BLOCK_VECTOR_TYPE
    2167 {
    2168  VMA_BLOCK_VECTOR_TYPE_UNMAPPED,
    2169  VMA_BLOCK_VECTOR_TYPE_MAPPED,
    2170  VMA_BLOCK_VECTOR_TYPE_COUNT
    2171 };
    2172 
    2173 static VMA_BLOCK_VECTOR_TYPE VmaMemoryRequirementFlagsToBlockVectorType(VmaMemoryRequirementFlags flags)
    2174 {
    2175  return (flags & VMA_MEMORY_REQUIREMENT_PERSISTENT_MAP_BIT) != 0 ?
    2176  VMA_BLOCK_VECTOR_TYPE_MAPPED :
    2177  VMA_BLOCK_VECTOR_TYPE_UNMAPPED;
    2178 }
    2179 
    2180 struct VmaAllocation_T
    2181 {
    2182 public:
    2183  enum ALLOCATION_TYPE
    2184  {
    2185  ALLOCATION_TYPE_NONE,
    2186  ALLOCATION_TYPE_BLOCK,
    2187  ALLOCATION_TYPE_OWN,
    2188  };
    2189 
    2190  VmaAllocation_T()
    2191  {
    2192  memset(this, 0, sizeof(VmaAllocation_T));
    2193  }
    2194 
    2195  void InitBlockAllocation(
    2196  VmaBlock* block,
    2197  VkDeviceSize offset,
    2198  VkDeviceSize alignment,
    2199  VkDeviceSize size,
    2200  VmaSuballocationType suballocationType,
    2201  void* pUserData)
    2202  {
    2203  VMA_ASSERT(m_Type == ALLOCATION_TYPE_NONE);
    2204  VMA_ASSERT(block != VMA_NULL);
    2205  m_Type = ALLOCATION_TYPE_BLOCK;
    2206  m_Alignment = alignment;
    2207  m_Size = size;
    2208  m_pUserData = pUserData;
    2209  m_SuballocationType = suballocationType;
    2210  m_BlockAllocation.m_Block = block;
    2211  m_BlockAllocation.m_Offset = offset;
    2212  }
    2213 
    2214  void ChangeBlockAllocation(
    2215  VmaBlock* block,
    2216  VkDeviceSize offset)
    2217  {
    2218  VMA_ASSERT(block != VMA_NULL);
    2219  VMA_ASSERT(m_Type == ALLOCATION_TYPE_BLOCK);
    2220  m_BlockAllocation.m_Block = block;
    2221  m_BlockAllocation.m_Offset = offset;
    2222  }
    2223 
    2224  void InitOwnAllocation(
    2225  uint32_t memoryTypeIndex,
    2226  VkDeviceMemory hMemory,
    2227  VmaSuballocationType suballocationType,
    2228  bool persistentMap,
    2229  void* pMappedData,
    2230  VkDeviceSize size,
    2231  void* pUserData)
    2232  {
    2233  VMA_ASSERT(m_Type == ALLOCATION_TYPE_NONE);
    2234  VMA_ASSERT(hMemory != VK_NULL_HANDLE);
    2235  m_Type = ALLOCATION_TYPE_OWN;
    2236  m_Alignment = 0;
    2237  m_Size = size;
    2238  m_pUserData = pUserData;
    2239  m_SuballocationType = suballocationType;
    2240  m_OwnAllocation.m_MemoryTypeIndex = memoryTypeIndex;
    2241  m_OwnAllocation.m_hMemory = hMemory;
    2242  m_OwnAllocation.m_PersistentMap = persistentMap;
    2243  m_OwnAllocation.m_pMappedData = pMappedData;
    2244  }
    2245 
    2246  ALLOCATION_TYPE GetType() const { return m_Type; }
    2247  VkDeviceSize GetAlignment() const { return m_Alignment; }
    2248  VkDeviceSize GetSize() const { return m_Size; }
    2249  void* GetUserData() const { return m_pUserData; }
    2250  void SetUserData(void* pUserData) { m_pUserData = pUserData; }
    2251  VmaSuballocationType GetSuballocationType() const { return m_SuballocationType; }
    2252 
    2253  VmaBlock* GetBlock() const
    2254  {
    2255  VMA_ASSERT(m_Type == ALLOCATION_TYPE_BLOCK);
    2256  return m_BlockAllocation.m_Block;
    2257  }
    2258  VkDeviceSize GetOffset() const
    2259  {
    2260  return (m_Type == ALLOCATION_TYPE_BLOCK) ? m_BlockAllocation.m_Offset : 0;
    2261  }
    2262  VkDeviceMemory GetMemory() const;
    2263  uint32_t GetMemoryTypeIndex() const;
    2264  VMA_BLOCK_VECTOR_TYPE GetBlockVectorType() const;
    2265  void* GetMappedData() const;
    2266 
    2267  VkResult OwnAllocMapPersistentlyMappedMemory(VkDevice hDevice)
    2268  {
    2269  VMA_ASSERT(m_Type == ALLOCATION_TYPE_OWN);
    2270  if(m_OwnAllocation.m_PersistentMap)
    2271  {
    2272  return vkMapMemory(hDevice, m_OwnAllocation.m_hMemory, 0, VK_WHOLE_SIZE, 0, &m_OwnAllocation.m_pMappedData);
    2273  }
    2274  return VK_SUCCESS;
    2275  }
    2276  void OwnAllocUnmapPersistentlyMappedMemory(VkDevice hDevice)
    2277  {
    2278  VMA_ASSERT(m_Type == ALLOCATION_TYPE_OWN);
    2279  if(m_OwnAllocation.m_pMappedData)
    2280  {
    2281  VMA_ASSERT(m_OwnAllocation.m_PersistentMap);
    2282  vkUnmapMemory(hDevice, m_OwnAllocation.m_hMemory);
    2283  m_OwnAllocation.m_pMappedData = VMA_NULL;
    2284  }
    2285  }
    2286 
    2287 private:
    2288  VkDeviceSize m_Alignment;
    2289  VkDeviceSize m_Size;
    2290  void* m_pUserData;
    2291  ALLOCATION_TYPE m_Type;
    2292  VmaSuballocationType m_SuballocationType;
    2293 
    2294  union
    2295  {
    2296  // Allocation out of VmaBlock.
    2297  struct BlockAllocation
    2298  {
    2299  VmaBlock* m_Block;
    2300  VkDeviceSize m_Offset;
    2301  } m_BlockAllocation;
    2302 
    2303  // Allocation for an object that has its own private VkDeviceMemory.
    2304  struct OwnAllocation
    2305  {
    2306  uint32_t m_MemoryTypeIndex;
    2307  VkDeviceMemory m_hMemory;
    2308  bool m_PersistentMap;
    2309  void* m_pMappedData;
    2310  } m_OwnAllocation;
    2311  };
    2312 };
    2313 
    2314 /*
    2315 Represents a region of VmaBlock that is either assigned and returned as
    2316 allocated memory block or free.
    2317 */
    2318 struct VmaSuballocation
    2319 {
    2320  VkDeviceSize offset;
    2321  VkDeviceSize size;
    2322  VmaSuballocationType type;
    2323 };
    2324 
    2325 typedef VmaList< VmaSuballocation, VmaStlAllocator<VmaSuballocation> > VmaSuballocationList;
    2326 
    2327 // Parameters of an allocation.
    2328 struct VmaAllocationRequest
    2329 {
    2330  VmaSuballocationList::iterator freeSuballocationItem;
    2331  VkDeviceSize offset;
    2332 };
    2333 
    2334 /* Single block of memory - VkDeviceMemory with all the data about its regions
    2335 assigned or free. */
    2336 class VmaBlock
    2337 {
    2338 public:
    2339  uint32_t m_MemoryTypeIndex;
    2340  VMA_BLOCK_VECTOR_TYPE m_BlockVectorType;
    2341  VkDeviceMemory m_hMemory;
    2342  VkDeviceSize m_Size;
    2343  bool m_PersistentMap;
    2344  void* m_pMappedData;
    2345  uint32_t m_FreeCount;
    2346  VkDeviceSize m_SumFreeSize;
    2347  VmaSuballocationList m_Suballocations;
    2348  // Suballocations that are free and have size greater than certain threshold.
    2349  // Sorted by size, ascending.
    2350  VmaVector< VmaSuballocationList::iterator, VmaStlAllocator< VmaSuballocationList::iterator > > m_FreeSuballocationsBySize;
    2351 
    2352  VmaBlock(VmaAllocator hAllocator);
    2353 
    2354  ~VmaBlock()
    2355  {
    2356  VMA_ASSERT(m_hMemory == VK_NULL_HANDLE);
    2357  }
    2358 
    2359  // Always call after construction.
    2360  void Init(
    2361  uint32_t newMemoryTypeIndex,
    2362  VMA_BLOCK_VECTOR_TYPE newBlockVectorType,
    2363  VkDeviceMemory newMemory,
    2364  VkDeviceSize newSize,
    2365  bool persistentMap,
    2366  void* pMappedData);
    2367  // Always call before destruction.
    2368  void Destroy(VmaAllocator allocator);
    2369 
    2370  // Validates all data structures inside this object. If not valid, returns false.
    2371  bool Validate() const;
    2372 
    2373  // Tries to find a place for suballocation with given parameters inside this allocation.
    2374  // If succeeded, fills pAllocationRequest and returns true.
    2375  // If failed, returns false.
    2376  bool CreateAllocationRequest(
    2377  VkDeviceSize bufferImageGranularity,
    2378  VkDeviceSize allocSize,
    2379  VkDeviceSize allocAlignment,
    2380  VmaSuballocationType allocType,
    2381  VmaAllocationRequest* pAllocationRequest);
    2382 
    2383  // Checks if requested suballocation with given parameters can be placed in given pFreeSuballocItem.
    2384  // If yes, fills pOffset and returns true. If no, returns false.
    2385  bool CheckAllocation(
    2386  VkDeviceSize bufferImageGranularity,
    2387  VkDeviceSize allocSize,
    2388  VkDeviceSize allocAlignment,
    2389  VmaSuballocationType allocType,
    2390  VmaSuballocationList::const_iterator freeSuballocItem,
    2391  VkDeviceSize* pOffset) const;
    2392 
    2393  // Returns true if this allocation is empty - contains only single free suballocation.
    2394  bool IsEmpty() const;
    2395 
    2396  // Makes actual allocation based on request. Request must already be checked
    2397  // and valid.
    2398  void Alloc(
    2399  const VmaAllocationRequest& request,
    2400  VmaSuballocationType type,
    2401  VkDeviceSize allocSize);
    2402 
    2403  // Frees suballocation assigned to given memory region.
    2404  void Free(const VmaAllocation allocation);
    2405 
    2406 #if VMA_STATS_STRING_ENABLED
    2407  void PrintDetailedMap(class VmaStringBuilder& sb) const;
    2408 #endif
    2409 
    2410 private:
    2411  // Given free suballocation, it merges it with following one, which must also be free.
    2412  void MergeFreeWithNext(VmaSuballocationList::iterator item);
    2413  // Releases given suballocation, making it free. Merges it with adjacent free
    2414  // suballocations if applicable.
    2415  void FreeSuballocation(VmaSuballocationList::iterator suballocItem);
    2416  // Given free suballocation, it inserts it into sorted list of
    2417  // m_FreeSuballocationsBySize if it's suitable.
    2418  void RegisterFreeSuballocation(VmaSuballocationList::iterator item);
    2419  // Given free suballocation, it removes it from sorted list of
    2420  // m_FreeSuballocationsBySize if it's suitable.
    2421  void UnregisterFreeSuballocation(VmaSuballocationList::iterator item);
    2422 };
    2423 
    2424 struct VmaPointerLess
    2425 {
    2426  bool operator()(const void* lhs, const void* rhs) const
    2427  {
    2428  return lhs < rhs;
    2429  }
    2430 };
    2431 
    2432 /* Sequence of VmaBlock. Represents memory blocks allocated for a specific
    2433 Vulkan memory type. */
    2434 struct VmaBlockVector
    2435 {
    2436  // Incrementally sorted by sumFreeSize, ascending.
    2437  VmaVector< VmaBlock*, VmaStlAllocator<VmaBlock*> > m_Blocks;
    2438 
    2439  VmaBlockVector(VmaAllocator hAllocator);
    2440  ~VmaBlockVector();
    2441 
    2442  bool IsEmpty() const { return m_Blocks.empty(); }
    2443 
    2444  // Finds and removes given block from vector.
    2445  void Remove(VmaBlock* pBlock);
    2446 
    2447  // Performs single step in sorting m_Blocks. They may not be fully sorted
    2448  // after this call.
    2449  void IncrementallySortBlocks();
    2450 
    2451  // Adds statistics of this BlockVector to pStats.
    2452  void AddStats(VmaStats* pStats, uint32_t memTypeIndex, uint32_t memHeapIndex) const;
    2453 
    2454 #if VMA_STATS_STRING_ENABLED
    2455  void PrintDetailedMap(class VmaStringBuilder& sb) const;
    2456 #endif
    2457 
    2458  void UnmapPersistentlyMappedMemory();
    2459  VkResult MapPersistentlyMappedMemory();
    2460 
    2461 private:
    2462  VmaAllocator m_hAllocator;
    2463 };
    2464 
    2465 // Main allocator object.
    2466 struct VmaAllocator_T
    2467 {
    2468  bool m_UseMutex;
    2469  VkDevice m_hDevice;
    2470  bool m_AllocationCallbacksSpecified;
    2471  VkAllocationCallbacks m_AllocationCallbacks;
    2472  VmaDeviceMemoryCallbacks m_DeviceMemoryCallbacks;
    2473  VkDeviceSize m_PreferredLargeHeapBlockSize;
    2474  VkDeviceSize m_PreferredSmallHeapBlockSize;
    2475  // Non-zero when we are inside UnmapPersistentlyMappedMemory...MapPersistentlyMappedMemory.
    2476  // Counter to allow nested calls to these functions.
    2477  uint32_t m_UnmapPersistentlyMappedMemoryCounter;
    2478 
    2479  VkPhysicalDeviceProperties m_PhysicalDeviceProperties;
    2480  VkPhysicalDeviceMemoryProperties m_MemProps;
    2481 
    2482  VmaBlockVector* m_pBlockVectors[VK_MAX_MEMORY_TYPES][VMA_BLOCK_VECTOR_TYPE_COUNT];
    2483  /* There can be at most one allocation that is completely empty - a
    2484  hysteresis to avoid pessimistic case of alternating creation and destruction
    2485  of a VkDeviceMemory. */
    2486  bool m_HasEmptyBlock[VK_MAX_MEMORY_TYPES];
    2487  VMA_MUTEX m_BlocksMutex[VK_MAX_MEMORY_TYPES];
    2488 
    2489  // Each vector is sorted by memory (handle value).
    2490  typedef VmaVector< VmaAllocation, VmaStlAllocator<VmaAllocation> > AllocationVectorType;
    2491  AllocationVectorType* m_pOwnAllocations[VK_MAX_MEMORY_TYPES][VMA_BLOCK_VECTOR_TYPE_COUNT];
    2492  VMA_MUTEX m_OwnAllocationsMutex[VK_MAX_MEMORY_TYPES];
    2493 
    2494  VmaAllocator_T(const VmaAllocatorCreateInfo* pCreateInfo);
    2495  ~VmaAllocator_T();
    2496 
    2497  const VkAllocationCallbacks* GetAllocationCallbacks() const
    2498  {
    2499  return m_AllocationCallbacksSpecified ? &m_AllocationCallbacks : 0;
    2500  }
    2501 
    2502  VkDeviceSize GetPreferredBlockSize(uint32_t memTypeIndex) const;
    2503 
    2504  VkDeviceSize GetBufferImageGranularity() const
    2505  {
    2506  return VMA_MAX(
    2507  static_cast<VkDeviceSize>(VMA_DEBUG_MIN_BUFFER_IMAGE_GRANULARITY),
    2508  m_PhysicalDeviceProperties.limits.bufferImageGranularity);
    2509  }
    2510 
    2511  uint32_t GetMemoryHeapCount() const { return m_MemProps.memoryHeapCount; }
    2512  uint32_t GetMemoryTypeCount() const { return m_MemProps.memoryTypeCount; }
    2513 
    2514  // Main allocation function.
    2515  VkResult AllocateMemory(
    2516  const VkMemoryRequirements& vkMemReq,
    2517  const VmaMemoryRequirements& vmaMemReq,
    2518  VmaSuballocationType suballocType,
    2519  VmaAllocation* pAllocation);
    2520 
    2521  // Main deallocation function.
    2522  void FreeMemory(const VmaAllocation allocation);
    2523 
    2524  void CalculateStats(VmaStats* pStats);
    2525 
    2526 #if VMA_STATS_STRING_ENABLED
    2527  void PrintDetailedMap(class VmaStringBuilder& sb);
    2528 #endif
    2529 
    2530  void UnmapPersistentlyMappedMemory();
    2531  VkResult MapPersistentlyMappedMemory();
    2532 
    2533  VkResult Defragment(
    2534  VmaAllocation* pAllocations,
    2535  size_t allocationCount,
    2536  VkBool32* pAllocationsChanged,
    2537  const VmaDefragmentationInfo* pDefragmentationInfo,
    2538  VmaDefragmentationStats* pDefragmentationStats);
    2539 
    2540  static void GetAllocationInfo(VmaAllocation hAllocation, VmaAllocationInfo* pAllocationInfo);
    2541 
    2542 private:
    2543  VkPhysicalDevice m_PhysicalDevice;
    2544 
    2545  VkResult AllocateMemoryOfType(
    2546  const VkMemoryRequirements& vkMemReq,
    2547  const VmaMemoryRequirements& vmaMemReq,
    2548  uint32_t memTypeIndex,
    2549  VmaSuballocationType suballocType,
    2550  VmaAllocation* pAllocation);
    2551 
    2552  // Allocates and registers new VkDeviceMemory specifically for single allocation.
    2553  VkResult AllocateOwnMemory(
    2554  VkDeviceSize size,
    2555  VmaSuballocationType suballocType,
    2556  uint32_t memTypeIndex,
    2557  bool map,
    2558  void* pUserData,
    2559  VmaAllocation* pAllocation);
    2560 
    2561  // Tries to free pMemory as Own Memory. Returns true if found and freed.
    2562  void FreeOwnMemory(VmaAllocation allocation);
    2563 };
    2564 
    2566 // Memory allocation #2 after VmaAllocator_T definition
    2567 
    2568 static void* VmaMalloc(VmaAllocator hAllocator, size_t size, size_t alignment)
    2569 {
    2570  return VmaMalloc(&hAllocator->m_AllocationCallbacks, size, alignment);
    2571 }
    2572 
    2573 static void VmaFree(VmaAllocator hAllocator, void* ptr)
    2574 {
    2575  VmaFree(&hAllocator->m_AllocationCallbacks, ptr);
    2576 }
    2577 
    2578 template<typename T>
    2579 static T* VmaAllocate(VmaAllocator hAllocator)
    2580 {
    2581  return (T*)VmaMalloc(hAllocator, sizeof(T), VMA_ALIGN_OF(T));
    2582 }
    2583 
    2584 template<typename T>
    2585 static T* VmaAllocateArray(VmaAllocator hAllocator, size_t count)
    2586 {
    2587  return (T*)VmaMalloc(hAllocator, sizeof(T) * count, VMA_ALIGN_OF(T));
    2588 }
    2589 
    2590 template<typename T>
    2591 static void vma_delete(VmaAllocator hAllocator, T* ptr)
    2592 {
    2593  if(ptr != VMA_NULL)
    2594  {
    2595  ptr->~T();
    2596  VmaFree(hAllocator, ptr);
    2597  }
    2598 }
    2599 
    2600 template<typename T>
    2601 static void vma_delete_array(VmaAllocator hAllocator, T* ptr, size_t count)
    2602 {
    2603  if(ptr != VMA_NULL)
    2604  {
    2605  for(size_t i = count; i--; )
    2606  ptr[i].~T();
    2607  VmaFree(hAllocator, ptr);
    2608  }
    2609 }
    2610 
    2612 // VmaStringBuilder
    2613 
    2614 #if VMA_STATS_STRING_ENABLED
    2615 
    2616 class VmaStringBuilder
    2617 {
    2618 public:
    2619  VmaStringBuilder(VmaAllocator alloc) : m_Data(VmaStlAllocator<char>(alloc->GetAllocationCallbacks())) { }
    2620  size_t GetLength() const { return m_Data.size(); }
    2621  const char* GetData() const { return m_Data.data(); }
    2622 
    2623  void Add(char ch) { m_Data.push_back(ch); }
    2624  void Add(const char* pStr);
    2625  void AddNewLine() { Add('\n'); }
    2626  void AddNumber(uint32_t num);
    2627  void AddNumber(uint64_t num);
    2628  void AddBool(bool b) { Add(b ? "true" : "false"); }
    2629  void AddNull() { Add("null"); }
    2630  void AddString(const char* pStr);
    2631 
    2632 private:
    2633  VmaVector< char, VmaStlAllocator<char> > m_Data;
    2634 };
    2635 
    2636 void VmaStringBuilder::Add(const char* pStr)
    2637 {
    2638  const size_t strLen = strlen(pStr);
    2639  if(strLen > 0)
    2640  {
    2641  const size_t oldCount = m_Data.size();
    2642  m_Data.resize(oldCount + strLen);
    2643  memcpy(m_Data.data() + oldCount, pStr, strLen);
    2644  }
    2645 }
    2646 
    2647 void VmaStringBuilder::AddNumber(uint32_t num)
    2648 {
    2649  char buf[11];
    2650  VmaUint32ToStr(buf, sizeof(buf), num);
    2651  Add(buf);
    2652 }
    2653 
    2654 void VmaStringBuilder::AddNumber(uint64_t num)
    2655 {
    2656  char buf[21];
    2657  VmaUint64ToStr(buf, sizeof(buf), num);
    2658  Add(buf);
    2659 }
    2660 
    2661 void VmaStringBuilder::AddString(const char* pStr)
    2662 {
    2663  Add('"');
    2664  const size_t strLen = strlen(pStr);
    2665  for(size_t i = 0; i < strLen; ++i)
    2666  {
    2667  char ch = pStr[i];
    2668  if(ch == '\'')
    2669  {
    2670  Add("\\\\");
    2671  }
    2672  else if(ch == '"')
    2673  {
    2674  Add("\\\"");
    2675  }
    2676  else if(ch >= 32)
    2677  {
    2678  Add(ch);
    2679  }
    2680  else switch(ch)
    2681  {
    2682  case '\n':
    2683  Add("\\n");
    2684  break;
    2685  case '\r':
    2686  Add("\\r");
    2687  break;
    2688  case '\t':
    2689  Add("\\t");
    2690  break;
    2691  default:
    2692  VMA_ASSERT(0 && "Character not currently supported.");
    2693  break;
    2694  }
    2695  }
    2696  Add('"');
    2697 }
    2698 
    2700 
    2701 VkDeviceMemory VmaAllocation_T::GetMemory() const
    2702 {
    2703  return (m_Type == ALLOCATION_TYPE_BLOCK) ?
    2704  m_BlockAllocation.m_Block->m_hMemory : m_OwnAllocation.m_hMemory;
    2705 }
    2706 
    2707 uint32_t VmaAllocation_T::GetMemoryTypeIndex() const
    2708 {
    2709  return (m_Type == ALLOCATION_TYPE_BLOCK) ?
    2710  m_BlockAllocation.m_Block->m_MemoryTypeIndex : m_OwnAllocation.m_MemoryTypeIndex;
    2711 }
    2712 
    2713 VMA_BLOCK_VECTOR_TYPE VmaAllocation_T::GetBlockVectorType() const
    2714 {
    2715  return (m_Type == ALLOCATION_TYPE_BLOCK) ?
    2716  m_BlockAllocation.m_Block->m_BlockVectorType :
    2717  (m_OwnAllocation.m_PersistentMap ? VMA_BLOCK_VECTOR_TYPE_MAPPED : VMA_BLOCK_VECTOR_TYPE_UNMAPPED);
    2718 }
    2719 
    2720 void* VmaAllocation_T::GetMappedData() const
    2721 {
    2722  switch(m_Type)
    2723  {
    2724  case ALLOCATION_TYPE_BLOCK:
    2725  if(m_BlockAllocation.m_Block->m_pMappedData != VMA_NULL)
    2726  {
    2727  return (char*)m_BlockAllocation.m_Block->m_pMappedData + m_BlockAllocation.m_Offset;
    2728  }
    2729  else
    2730  {
    2731  return VMA_NULL;
    2732  }
    2733  break;
    2734  case ALLOCATION_TYPE_OWN:
    2735  return m_OwnAllocation.m_pMappedData;
    2736  default:
    2737  VMA_ASSERT(0);
    2738  return VMA_NULL;
    2739  }
    2740 }
    2741 
    2742 // Correspond to values of enum VmaSuballocationType.
    2743 static const char* VMA_SUBALLOCATION_TYPE_NAMES[] = {
    2744  "FREE",
    2745  "UNKNOWN",
    2746  "BUFFER",
    2747  "IMAGE_UNKNOWN",
    2748  "IMAGE_LINEAR",
    2749  "IMAGE_OPTIMAL",
    2750 };
    2751 
    2752 static void VmaPrintStatInfo(VmaStringBuilder& sb, const VmaStatInfo& stat)
    2753 {
    2754  sb.Add("{ \"Allocations\": ");
    2755  sb.AddNumber(stat.AllocationCount);
    2756  sb.Add(", \"Suballocations\": ");
    2757  sb.AddNumber(stat.SuballocationCount);
    2758  sb.Add(", \"UnusedRanges\": ");
    2759  sb.AddNumber(stat.UnusedRangeCount);
    2760  sb.Add(", \"UsedBytes\": ");
    2761  sb.AddNumber(stat.UsedBytes);
    2762  sb.Add(", \"UnusedBytes\": ");
    2763  sb.AddNumber(stat.UnusedBytes);
    2764  sb.Add(", \"SuballocationSize\": { \"Min\": ");
    2765  sb.AddNumber(stat.SuballocationSizeMin);
    2766  sb.Add(", \"Avg\": ");
    2767  sb.AddNumber(stat.SuballocationSizeAvg);
    2768  sb.Add(", \"Max\": ");
    2769  sb.AddNumber(stat.SuballocationSizeMax);
    2770  sb.Add(" }, \"UnusedRangeSize\": { \"Min\": ");
    2771  sb.AddNumber(stat.UnusedRangeSizeMin);
    2772  sb.Add(", \"Avg\": ");
    2773  sb.AddNumber(stat.UnusedRangeSizeAvg);
    2774  sb.Add(", \"Max\": ");
    2775  sb.AddNumber(stat.UnusedRangeSizeMax);
    2776  sb.Add(" } }");
    2777 }
    2778 
    2779 #endif // #if VMA_STATS_STRING_ENABLED
    2780 
    2781 struct VmaSuballocationItemSizeLess
    2782 {
    2783  bool operator()(
    2784  const VmaSuballocationList::iterator lhs,
    2785  const VmaSuballocationList::iterator rhs) const
    2786  {
    2787  return lhs->size < rhs->size;
    2788  }
    2789  bool operator()(
    2790  const VmaSuballocationList::iterator lhs,
    2791  VkDeviceSize rhsSize) const
    2792  {
    2793  return lhs->size < rhsSize;
    2794  }
    2795 };
    2796 
    2797 VmaBlock::VmaBlock(VmaAllocator hAllocator) :
    2798  m_MemoryTypeIndex(UINT32_MAX),
    2799  m_BlockVectorType(VMA_BLOCK_VECTOR_TYPE_COUNT),
    2800  m_hMemory(VK_NULL_HANDLE),
    2801  m_Size(0),
    2802  m_PersistentMap(false),
    2803  m_pMappedData(VMA_NULL),
    2804  m_FreeCount(0),
    2805  m_SumFreeSize(0),
    2806  m_Suballocations(VmaStlAllocator<VmaSuballocation>(hAllocator->GetAllocationCallbacks())),
    2807  m_FreeSuballocationsBySize(VmaStlAllocator<VmaSuballocationList::iterator>(hAllocator->GetAllocationCallbacks()))
    2808 {
    2809 }
    2810 
    2811 void VmaBlock::Init(
    2812  uint32_t newMemoryTypeIndex,
    2813  VMA_BLOCK_VECTOR_TYPE newBlockVectorType,
    2814  VkDeviceMemory newMemory,
    2815  VkDeviceSize newSize,
    2816  bool persistentMap,
    2817  void* pMappedData)
    2818 {
    2819  VMA_ASSERT(m_hMemory == VK_NULL_HANDLE);
    2820 
    2821  m_MemoryTypeIndex = newMemoryTypeIndex;
    2822  m_BlockVectorType = newBlockVectorType;
    2823  m_hMemory = newMemory;
    2824  m_Size = newSize;
    2825  m_PersistentMap = persistentMap;
    2826  m_pMappedData = pMappedData;
    2827  m_FreeCount = 1;
    2828  m_SumFreeSize = newSize;
    2829 
    2830  m_Suballocations.clear();
    2831  m_FreeSuballocationsBySize.clear();
    2832 
    2833  VmaSuballocation suballoc = {};
    2834  suballoc.offset = 0;
    2835  suballoc.size = newSize;
    2836  suballoc.type = VMA_SUBALLOCATION_TYPE_FREE;
    2837 
    2838  m_Suballocations.push_back(suballoc);
    2839  VmaSuballocationList::iterator suballocItem = m_Suballocations.end();
    2840  --suballocItem;
    2841  m_FreeSuballocationsBySize.push_back(suballocItem);
    2842 }
    2843 
    2844 void VmaBlock::Destroy(VmaAllocator allocator)
    2845 {
    2846  VMA_ASSERT(m_hMemory != VK_NULL_HANDLE);
    2847  if(m_pMappedData != VMA_NULL)
    2848  {
    2849  vkUnmapMemory(allocator->m_hDevice, m_hMemory);
    2850  m_pMappedData = VMA_NULL;
    2851  }
    2852 
    2853  // Callback.
    2854  if(allocator->m_DeviceMemoryCallbacks.pfnFree != VMA_NULL)
    2855  {
    2856  (*allocator->m_DeviceMemoryCallbacks.pfnFree)(allocator, m_MemoryTypeIndex, m_hMemory, m_Size);
    2857  }
    2858 
    2859  vkFreeMemory(allocator->m_hDevice, m_hMemory, allocator->GetAllocationCallbacks());
    2860  m_hMemory = VK_NULL_HANDLE;
    2861 }
    2862 
    2863 bool VmaBlock::Validate() const
    2864 {
    2865  if((m_hMemory == VK_NULL_HANDLE) ||
    2866  (m_Size == 0) ||
    2867  m_Suballocations.empty())
    2868  {
    2869  return false;
    2870  }
    2871 
    2872  // Expected offset of new suballocation as calculates from previous ones.
    2873  VkDeviceSize calculatedOffset = 0;
    2874  // Expected number of free suballocations as calculated from traversing their list.
    2875  uint32_t calculatedFreeCount = 0;
    2876  // Expected sum size of free suballocations as calculated from traversing their list.
    2877  VkDeviceSize calculatedSumFreeSize = 0;
    2878  // Expected number of free suballocations that should be registered in
    2879  // m_FreeSuballocationsBySize calculated from traversing their list.
    2880  size_t freeSuballocationsToRegister = 0;
    2881  // True if previous visisted suballocation was free.
    2882  bool prevFree = false;
    2883 
    2884  for(VmaSuballocationList::const_iterator suballocItem = m_Suballocations.cbegin();
    2885  suballocItem != m_Suballocations.cend();
    2886  ++suballocItem)
    2887  {
    2888  const VmaSuballocation& subAlloc = *suballocItem;
    2889 
    2890  // Actual offset of this suballocation doesn't match expected one.
    2891  if(subAlloc.offset != calculatedOffset)
    2892  {
    2893  return false;
    2894  }
    2895 
    2896  const bool currFree = (subAlloc.type == VMA_SUBALLOCATION_TYPE_FREE);
    2897  // Two adjacent free suballocations are invalid. They should be merged.
    2898  if(prevFree && currFree)
    2899  {
    2900  return false;
    2901  }
    2902  prevFree = currFree;
    2903 
    2904  if(currFree)
    2905  {
    2906  calculatedSumFreeSize += subAlloc.size;
    2907  ++calculatedFreeCount;
    2908  if(subAlloc.size >= VMA_MIN_FREE_SUBALLOCATION_SIZE_TO_REGISTER)
    2909  {
    2910  ++freeSuballocationsToRegister;
    2911  }
    2912  }
    2913 
    2914  calculatedOffset += subAlloc.size;
    2915  }
    2916 
    2917  // Number of free suballocations registered in m_FreeSuballocationsBySize doesn't
    2918  // match expected one.
    2919  if(m_FreeSuballocationsBySize.size() != freeSuballocationsToRegister)
    2920  {
    2921  return false;
    2922  }
    2923 
    2924  VkDeviceSize lastSize = 0;
    2925  for(size_t i = 0; i < m_FreeSuballocationsBySize.size(); ++i)
    2926  {
    2927  VmaSuballocationList::iterator suballocItem = m_FreeSuballocationsBySize[i];
    2928 
    2929  // Only free suballocations can be registered in m_FreeSuballocationsBySize.
    2930  if(suballocItem->type != VMA_SUBALLOCATION_TYPE_FREE)
    2931  {
    2932  return false;
    2933  }
    2934  // They must be sorted by size ascending.
    2935  if(suballocItem->size < lastSize)
    2936  {
    2937  return false;
    2938  }
    2939 
    2940  lastSize = suballocItem->size;
    2941  }
    2942 
    2943  // Check if totals match calculacted values.
    2944  return
    2945  (calculatedOffset == m_Size) &&
    2946  (calculatedSumFreeSize == m_SumFreeSize) &&
    2947  (calculatedFreeCount == m_FreeCount);
    2948 }
    2949 
    2950 /*
    2951 How many suitable free suballocations to analyze before choosing best one.
    2952 - Set to 1 to use First-Fit algorithm - first suitable free suballocation will
    2953  be chosen.
    2954 - Set to UINT32_MAX to use Best-Fit/Worst-Fit algorithm - all suitable free
    2955  suballocations will be analized and best one will be chosen.
    2956 - Any other value is also acceptable.
    2957 */
    2958 //static const uint32_t MAX_SUITABLE_SUBALLOCATIONS_TO_CHECK = 8;
    2959 
    2960 bool VmaBlock::CreateAllocationRequest(
    2961  VkDeviceSize bufferImageGranularity,
    2962  VkDeviceSize allocSize,
    2963  VkDeviceSize allocAlignment,
    2964  VmaSuballocationType allocType,
    2965  VmaAllocationRequest* pAllocationRequest)
    2966 {
    2967  VMA_ASSERT(allocSize > 0);
    2968  VMA_ASSERT(allocType != VMA_SUBALLOCATION_TYPE_FREE);
    2969  VMA_ASSERT(pAllocationRequest != VMA_NULL);
    2970  VMA_HEAVY_ASSERT(Validate());
    2971 
    2972  // There is not enough total free space in this allocation to fullfill the request: Early return.
    2973  if(m_SumFreeSize < allocSize)
    2974  {
    2975  return false;
    2976  }
    2977 
    2978  // Old brute-force algorithm, linearly searching suballocations.
    2979  /*
    2980  uint32_t suitableSuballocationsFound = 0;
    2981  for(VmaSuballocationList::iterator suballocItem = suballocations.Front();
    2982  suballocItem != VMA_NULL &&
    2983  suitableSuballocationsFound < MAX_SUITABLE_SUBALLOCATIONS_TO_CHECK;
    2984  suballocItem = suballocItem->Next)
    2985  {
    2986  if(suballocItem->Value.type == VMA_SUBALLOCATION_TYPE_FREE)
    2987  {
    2988  VkDeviceSize offset = 0, cost = 0;
    2989  if(CheckAllocation(bufferImageGranularity, allocSize, allocAlignment, allocType, suballocItem, &offset, &cost))
    2990  {
    2991  ++suitableSuballocationsFound;
    2992  if(cost < costLimit)
    2993  {
    2994  pAllocationRequest->freeSuballocationItem = suballocItem;
    2995  pAllocationRequest->offset = offset;
    2996  pAllocationRequest->cost = cost;
    2997  if(cost == 0)
    2998  return true;
    2999  costLimit = cost;
    3000  betterSuballocationFound = true;
    3001  }
    3002  }
    3003  }
    3004  }
    3005  */
    3006 
    3007  // New algorithm, efficiently searching freeSuballocationsBySize.
    3008  const size_t freeSuballocCount = m_FreeSuballocationsBySize.size();
    3009  if(freeSuballocCount > 0)
    3010  {
    3011  if(VMA_BEST_FIT)
    3012  {
    3013  // Find first free suballocation with size not less than allocSize.
    3014  VmaSuballocationList::iterator* const it = VmaBinaryFindFirstNotLess(
    3015  m_FreeSuballocationsBySize.data(),
    3016  m_FreeSuballocationsBySize.data() + freeSuballocCount,
    3017  allocSize,
    3018  VmaSuballocationItemSizeLess());
    3019  size_t index = it - m_FreeSuballocationsBySize.data();
    3020  for(; index < freeSuballocCount; ++index)
    3021  {
    3022  VkDeviceSize offset = 0;
    3023  const VmaSuballocationList::iterator suballocItem = m_FreeSuballocationsBySize[index];
    3024  if(CheckAllocation(bufferImageGranularity, allocSize, allocAlignment, allocType, suballocItem, &offset))
    3025  {
    3026  pAllocationRequest->freeSuballocationItem = suballocItem;
    3027  pAllocationRequest->offset = offset;
    3028  return true;
    3029  }
    3030  }
    3031  }
    3032  else
    3033  {
    3034  // Search staring from biggest suballocations.
    3035  for(size_t index = freeSuballocCount; index--; )
    3036  {
    3037  VkDeviceSize offset = 0;
    3038  const VmaSuballocationList::iterator suballocItem = m_FreeSuballocationsBySize[index];
    3039  if(CheckAllocation(bufferImageGranularity, allocSize, allocAlignment, allocType, suballocItem, &offset))
    3040  {
    3041  pAllocationRequest->freeSuballocationItem = suballocItem;
    3042  pAllocationRequest->offset = offset;
    3043  return true;
    3044  }
    3045  }
    3046  }
    3047  }
    3048 
    3049  return false;
    3050 }
    3051 
    3052 bool VmaBlock::CheckAllocation(
    3053  VkDeviceSize bufferImageGranularity,
    3054  VkDeviceSize allocSize,
    3055  VkDeviceSize allocAlignment,
    3056  VmaSuballocationType allocType,
    3057  VmaSuballocationList::const_iterator freeSuballocItem,
    3058  VkDeviceSize* pOffset) const
    3059 {
    3060  VMA_ASSERT(allocSize > 0);
    3061  VMA_ASSERT(allocType != VMA_SUBALLOCATION_TYPE_FREE);
    3062  VMA_ASSERT(freeSuballocItem != m_Suballocations.cend());
    3063  VMA_ASSERT(pOffset != VMA_NULL);
    3064 
    3065  const VmaSuballocation& suballoc = *freeSuballocItem;
    3066  VMA_ASSERT(suballoc.type == VMA_SUBALLOCATION_TYPE_FREE);
    3067 
    3068  // Size of this suballocation is too small for this request: Early return.
    3069  if(suballoc.size < allocSize)
    3070  {
    3071  return false;
    3072  }
    3073 
    3074  // Start from offset equal to beginning of this suballocation.
    3075  *pOffset = suballoc.offset;
    3076 
    3077  // Apply VMA_DEBUG_MARGIN at the beginning.
    3078  if((VMA_DEBUG_MARGIN > 0) && freeSuballocItem != m_Suballocations.cbegin())
    3079  {
    3080  *pOffset += VMA_DEBUG_MARGIN;
    3081  }
    3082 
    3083  // Apply alignment.
    3084  const VkDeviceSize alignment = VMA_MAX(allocAlignment, static_cast<VkDeviceSize>(VMA_DEBUG_ALIGNMENT));
    3085  *pOffset = VmaAlignUp(*pOffset, alignment);
    3086 
    3087  // Check previous suballocations for BufferImageGranularity conflicts.
    3088  // Make bigger alignment if necessary.
    3089  if(bufferImageGranularity > 1)
    3090  {
    3091  bool bufferImageGranularityConflict = false;
    3092  VmaSuballocationList::const_iterator prevSuballocItem = freeSuballocItem;
    3093  while(prevSuballocItem != m_Suballocations.cbegin())
    3094  {
    3095  --prevSuballocItem;
    3096  const VmaSuballocation& prevSuballoc = *prevSuballocItem;
    3097  if(VmaBlocksOnSamePage(prevSuballoc.offset, prevSuballoc.size, *pOffset, bufferImageGranularity))
    3098  {
    3099  if(VmaIsBufferImageGranularityConflict(prevSuballoc.type, allocType))
    3100  {
    3101  bufferImageGranularityConflict = true;
    3102  break;
    3103  }
    3104  }
    3105  else
    3106  // Already on previous page.
    3107  break;
    3108  }
    3109  if(bufferImageGranularityConflict)
    3110  {
    3111  *pOffset = VmaAlignUp(*pOffset, bufferImageGranularity);
    3112  }
    3113  }
    3114 
    3115  // Calculate padding at the beginning based on current offset.
    3116  const VkDeviceSize paddingBegin = *pOffset - suballoc.offset;
    3117 
    3118  // Calculate required margin at the end if this is not last suballocation.
    3119  VmaSuballocationList::const_iterator next = freeSuballocItem;
    3120  ++next;
    3121  const VkDeviceSize requiredEndMargin =
    3122  (next != m_Suballocations.cend()) ? VMA_DEBUG_MARGIN : 0;
    3123 
    3124  // Fail if requested size plus margin before and after is bigger than size of this suballocation.
    3125  if(paddingBegin + allocSize + requiredEndMargin > suballoc.size)
    3126  {
    3127  return false;
    3128  }
    3129 
    3130  // Check next suballocations for BufferImageGranularity conflicts.
    3131  // If conflict exists, allocation cannot be made here.
    3132  if(bufferImageGranularity > 1)
    3133  {
    3134  VmaSuballocationList::const_iterator nextSuballocItem = freeSuballocItem;
    3135  ++nextSuballocItem;
    3136  while(nextSuballocItem != m_Suballocations.cend())
    3137  {
    3138  const VmaSuballocation& nextSuballoc = *nextSuballocItem;
    3139  if(VmaBlocksOnSamePage(*pOffset, allocSize, nextSuballoc.offset, bufferImageGranularity))
    3140  {
    3141  if(VmaIsBufferImageGranularityConflict(allocType, nextSuballoc.type))
    3142  {
    3143  return false;
    3144  }
    3145  }
    3146  else
    3147  {
    3148  // Already on next page.
    3149  break;
    3150  }
    3151  ++nextSuballocItem;
    3152  }
    3153  }
    3154 
    3155  // All tests passed: Success. pOffset is already filled.
    3156  return true;
    3157 }
    3158 
    3159 bool VmaBlock::IsEmpty() const
    3160 {
    3161  return (m_Suballocations.size() == 1) && (m_FreeCount == 1);
    3162 }
    3163 
    3164 void VmaBlock::Alloc(
    3165  const VmaAllocationRequest& request,
    3166  VmaSuballocationType type,
    3167  VkDeviceSize allocSize)
    3168 {
    3169  VMA_ASSERT(request.freeSuballocationItem != m_Suballocations.end());
    3170  VmaSuballocation& suballoc = *request.freeSuballocationItem;
    3171  // Given suballocation is a free block.
    3172  VMA_ASSERT(suballoc.type == VMA_SUBALLOCATION_TYPE_FREE);
    3173  // Given offset is inside this suballocation.
    3174  VMA_ASSERT(request.offset >= suballoc.offset);
    3175  const VkDeviceSize paddingBegin = request.offset - suballoc.offset;
    3176  VMA_ASSERT(suballoc.size >= paddingBegin + allocSize);
    3177  const VkDeviceSize paddingEnd = suballoc.size - paddingBegin - allocSize;
    3178 
    3179  // Unregister this free suballocation from m_FreeSuballocationsBySize and update
    3180  // it to become used.
    3181  UnregisterFreeSuballocation(request.freeSuballocationItem);
    3182 
    3183  suballoc.offset = request.offset;
    3184  suballoc.size = allocSize;
    3185  suballoc.type = type;
    3186 
    3187  // If there are any free bytes remaining at the end, insert new free suballocation after current one.
    3188  if(paddingEnd)
    3189  {
    3190  VmaSuballocation paddingSuballoc = {};
    3191  paddingSuballoc.offset = request.offset + allocSize;
    3192  paddingSuballoc.size = paddingEnd;
    3193  paddingSuballoc.type = VMA_SUBALLOCATION_TYPE_FREE;
    3194  VmaSuballocationList::iterator next = request.freeSuballocationItem;
    3195  ++next;
    3196  const VmaSuballocationList::iterator paddingEndItem =
    3197  m_Suballocations.insert(next, paddingSuballoc);
    3198  RegisterFreeSuballocation(paddingEndItem);
    3199  }
    3200 
    3201  // If there are any free bytes remaining at the beginning, insert new free suballocation before current one.
    3202  if(paddingBegin)
    3203  {
    3204  VmaSuballocation paddingSuballoc = {};
    3205  paddingSuballoc.offset = request.offset - paddingBegin;
    3206  paddingSuballoc.size = paddingBegin;
    3207  paddingSuballoc.type = VMA_SUBALLOCATION_TYPE_FREE;
    3208  const VmaSuballocationList::iterator paddingBeginItem =
    3209  m_Suballocations.insert(request.freeSuballocationItem, paddingSuballoc);
    3210  RegisterFreeSuballocation(paddingBeginItem);
    3211  }
    3212 
    3213  // Update totals.
    3214  m_FreeCount = m_FreeCount - 1;
    3215  if(paddingBegin > 0)
    3216  {
    3217  ++m_FreeCount;
    3218  }
    3219  if(paddingEnd > 0)
    3220  {
    3221  ++m_FreeCount;
    3222  }
    3223  m_SumFreeSize -= allocSize;
    3224 }
    3225 
    3226 void VmaBlock::FreeSuballocation(VmaSuballocationList::iterator suballocItem)
    3227 {
    3228  // Change this suballocation to be marked as free.
    3229  VmaSuballocation& suballoc = *suballocItem;
    3230  suballoc.type = VMA_SUBALLOCATION_TYPE_FREE;
    3231 
    3232  // Update totals.
    3233  ++m_FreeCount;
    3234  m_SumFreeSize += suballoc.size;
    3235 
    3236  // Merge with previous and/or next suballocation if it's also free.
    3237  bool mergeWithNext = false;
    3238  bool mergeWithPrev = false;
    3239 
    3240  VmaSuballocationList::iterator nextItem = suballocItem;
    3241  ++nextItem;
    3242  if((nextItem != m_Suballocations.end()) && (nextItem->type == VMA_SUBALLOCATION_TYPE_FREE))
    3243  {
    3244  mergeWithNext = true;
    3245  }
    3246 
    3247  VmaSuballocationList::iterator prevItem = suballocItem;
    3248  if(suballocItem != m_Suballocations.begin())
    3249  {
    3250  --prevItem;
    3251  if(prevItem->type == VMA_SUBALLOCATION_TYPE_FREE)
    3252  {
    3253  mergeWithPrev = true;
    3254  }
    3255  }
    3256 
    3257  if(mergeWithNext)
    3258  {
    3259  UnregisterFreeSuballocation(nextItem);
    3260  MergeFreeWithNext(suballocItem);
    3261  }
    3262 
    3263  if(mergeWithPrev)
    3264  {
    3265  UnregisterFreeSuballocation(prevItem);
    3266  MergeFreeWithNext(prevItem);
    3267  RegisterFreeSuballocation(prevItem);
    3268  }
    3269  else
    3270  RegisterFreeSuballocation(suballocItem);
    3271 }
    3272 
    3273 void VmaBlock::Free(const VmaAllocation allocation)
    3274 {
    3275  const VkDeviceSize allocationOffset = allocation->GetOffset();
    3276  for(VmaSuballocationList::iterator suballocItem = m_Suballocations.begin();
    3277  suballocItem != m_Suballocations.end();
    3278  ++suballocItem)
    3279  {
    3280  VmaSuballocation& suballoc = *suballocItem;
    3281  if(suballoc.offset == allocationOffset)
    3282  {
    3283  FreeSuballocation(suballocItem);
    3284  VMA_HEAVY_ASSERT(Validate());
    3285  return;
    3286  }
    3287  }
    3288  VMA_ASSERT(0 && "Not found!");
    3289 }
    3290 
    3291 #if VMA_STATS_STRING_ENABLED
    3292 
    3293 void VmaBlock::PrintDetailedMap(class VmaStringBuilder& sb) const
    3294 {
    3295  sb.Add("{\n\t\t\t\"Bytes\": ");
    3296  sb.AddNumber(m_Size);
    3297  sb.Add(",\n\t\t\t\"FreeBytes\": ");
    3298  sb.AddNumber(m_SumFreeSize);
    3299  sb.Add(",\n\t\t\t\"Suballocations\": ");
    3300  sb.AddNumber(m_Suballocations.size());
    3301  sb.Add(",\n\t\t\t\"FreeSuballocations\": ");
    3302  sb.AddNumber(m_FreeCount);
    3303  sb.Add(",\n\t\t\t\"SuballocationList\": [");
    3304 
    3305  size_t i = 0;
    3306  for(VmaSuballocationList::const_iterator suballocItem = m_Suballocations.cbegin();
    3307  suballocItem != m_Suballocations.cend();
    3308  ++suballocItem, ++i)
    3309  {
    3310  if(i > 0)
    3311  {
    3312  sb.Add(",\n\t\t\t\t{ \"Type\": ");
    3313  }
    3314  else
    3315  {
    3316  sb.Add("\n\t\t\t\t{ \"Type\": ");
    3317  }
    3318  sb.AddString(VMA_SUBALLOCATION_TYPE_NAMES[suballocItem->type]);
    3319  sb.Add(", \"Size\": ");
    3320  sb.AddNumber(suballocItem->size);
    3321  sb.Add(", \"Offset\": ");
    3322  sb.AddNumber(suballocItem->offset);
    3323  sb.Add(" }");
    3324  }
    3325 
    3326  sb.Add("\n\t\t\t]\n\t\t}");
    3327 }
    3328 
    3329 #endif // #if VMA_STATS_STRING_ENABLED
    3330 
    3331 void VmaBlock::MergeFreeWithNext(VmaSuballocationList::iterator item)
    3332 {
    3333  VMA_ASSERT(item != m_Suballocations.end());
    3334  VMA_ASSERT(item->type == VMA_SUBALLOCATION_TYPE_FREE);
    3335 
    3336  VmaSuballocationList::iterator nextItem = item;
    3337  ++nextItem;
    3338  VMA_ASSERT(nextItem != m_Suballocations.end());
    3339  VMA_ASSERT(nextItem->type == VMA_SUBALLOCATION_TYPE_FREE);
    3340 
    3341  item->size += nextItem->size;
    3342  --m_FreeCount;
    3343  m_Suballocations.erase(nextItem);
    3344 }
    3345 
    3346 void VmaBlock::RegisterFreeSuballocation(VmaSuballocationList::iterator item)
    3347 {
    3348  VMA_ASSERT(item->type == VMA_SUBALLOCATION_TYPE_FREE);
    3349  VMA_ASSERT(item->size > 0);
    3350 
    3351  if(item->size >= VMA_MIN_FREE_SUBALLOCATION_SIZE_TO_REGISTER)
    3352  {
    3353  if(m_FreeSuballocationsBySize.empty())
    3354  {
    3355  m_FreeSuballocationsBySize.push_back(item);
    3356  }
    3357  else
    3358  {
    3359  VmaSuballocationList::iterator* const it = VmaBinaryFindFirstNotLess(
    3360  m_FreeSuballocationsBySize.data(),
    3361  m_FreeSuballocationsBySize.data() + m_FreeSuballocationsBySize.size(),
    3362  item,
    3363  VmaSuballocationItemSizeLess());
    3364  size_t index = it - m_FreeSuballocationsBySize.data();
    3365  VectorInsert(m_FreeSuballocationsBySize, index, item);
    3366  }
    3367  }
    3368 }
    3369 
    3370 void VmaBlock::UnregisterFreeSuballocation(VmaSuballocationList::iterator item)
    3371 {
    3372  VMA_ASSERT(item->type == VMA_SUBALLOCATION_TYPE_FREE);
    3373  VMA_ASSERT(item->size > 0);
    3374 
    3375  if(item->size >= VMA_MIN_FREE_SUBALLOCATION_SIZE_TO_REGISTER)
    3376  {
    3377  VmaSuballocationList::iterator* const it = VmaBinaryFindFirstNotLess(
    3378  m_FreeSuballocationsBySize.data(),
    3379  m_FreeSuballocationsBySize.data() + m_FreeSuballocationsBySize.size(),
    3380  item,
    3381  VmaSuballocationItemSizeLess());
    3382  for(size_t index = it - m_FreeSuballocationsBySize.data();
    3383  index < m_FreeSuballocationsBySize.size();
    3384  ++index)
    3385  {
    3386  if(m_FreeSuballocationsBySize[index] == item)
    3387  {
    3388  VectorRemove(m_FreeSuballocationsBySize, index);
    3389  return;
    3390  }
    3391  VMA_ASSERT((m_FreeSuballocationsBySize[index]->size == item->size) && "Not found.");
    3392  }
    3393  VMA_ASSERT(0 && "Not found.");
    3394  }
    3395 }
    3396 
    3397 static void InitStatInfo(VmaStatInfo& outInfo)
    3398 {
    3399  memset(&outInfo, 0, sizeof(outInfo));
    3400  outInfo.SuballocationSizeMin = UINT64_MAX;
    3401  outInfo.UnusedRangeSizeMin = UINT64_MAX;
    3402 }
    3403 
    3404 static void CalcAllocationStatInfo(VmaStatInfo& outInfo, const VmaBlock& alloc)
    3405 {
    3406  outInfo.AllocationCount = 1;
    3407 
    3408  const uint32_t rangeCount = (uint32_t)alloc.m_Suballocations.size();
    3409  outInfo.SuballocationCount = rangeCount - alloc.m_FreeCount;
    3410  outInfo.UnusedRangeCount = alloc.m_FreeCount;
    3411 
    3412  outInfo.UnusedBytes = alloc.m_SumFreeSize;
    3413  outInfo.UsedBytes = alloc.m_Size - outInfo.UnusedBytes;
    3414 
    3415  outInfo.SuballocationSizeMin = UINT64_MAX;
    3416  outInfo.SuballocationSizeMax = 0;
    3417  outInfo.UnusedRangeSizeMin = UINT64_MAX;
    3418  outInfo.UnusedRangeSizeMax = 0;
    3419 
    3420  for(VmaSuballocationList::const_iterator suballocItem = alloc.m_Suballocations.cbegin();
    3421  suballocItem != alloc.m_Suballocations.cend();
    3422  ++suballocItem)
    3423  {
    3424  const VmaSuballocation& suballoc = *suballocItem;
    3425  if(suballoc.type != VMA_SUBALLOCATION_TYPE_FREE)
    3426  {
    3427  outInfo.SuballocationSizeMin = VMA_MIN(outInfo.SuballocationSizeMin, suballoc.size);
    3428  outInfo.SuballocationSizeMax = VMA_MAX(outInfo.SuballocationSizeMax, suballoc.size);
    3429  }
    3430  else
    3431  {
    3432  outInfo.UnusedRangeSizeMin = VMA_MIN(outInfo.UnusedRangeSizeMin, suballoc.size);
    3433  outInfo.UnusedRangeSizeMax = VMA_MAX(outInfo.UnusedRangeSizeMax, suballoc.size);
    3434  }
    3435  }
    3436 }
    3437 
    3438 // Adds statistics srcInfo into inoutInfo, like: inoutInfo += srcInfo.
    3439 static void VmaAddStatInfo(VmaStatInfo& inoutInfo, const VmaStatInfo& srcInfo)
    3440 {
    3441  inoutInfo.AllocationCount += srcInfo.AllocationCount;
    3442  inoutInfo.SuballocationCount += srcInfo.SuballocationCount;
    3443  inoutInfo.UnusedRangeCount += srcInfo.UnusedRangeCount;
    3444  inoutInfo.UsedBytes += srcInfo.UsedBytes;
    3445  inoutInfo.UnusedBytes += srcInfo.UnusedBytes;
    3446  inoutInfo.SuballocationSizeMin = VMA_MIN(inoutInfo.SuballocationSizeMin, srcInfo.SuballocationSizeMin);
    3447  inoutInfo.SuballocationSizeMax = VMA_MAX(inoutInfo.SuballocationSizeMax, srcInfo.SuballocationSizeMax);
    3448  inoutInfo.UnusedRangeSizeMin = VMA_MIN(inoutInfo.UnusedRangeSizeMin, srcInfo.UnusedRangeSizeMin);
    3449  inoutInfo.UnusedRangeSizeMax = VMA_MAX(inoutInfo.UnusedRangeSizeMax, srcInfo.UnusedRangeSizeMax);
    3450 }
    3451 
    3452 static void VmaPostprocessCalcStatInfo(VmaStatInfo& inoutInfo)
    3453 {
    3454  inoutInfo.SuballocationSizeAvg = (inoutInfo.SuballocationCount > 0) ?
    3455  VmaRoundDiv<VkDeviceSize>(inoutInfo.UsedBytes, inoutInfo.SuballocationCount) : 0;
    3456  inoutInfo.UnusedRangeSizeAvg = (inoutInfo.UnusedRangeCount > 0) ?
    3457  VmaRoundDiv<VkDeviceSize>(inoutInfo.UnusedBytes, inoutInfo.UnusedRangeCount) : 0;
    3458 }
    3459 
    3460 VmaBlockVector::VmaBlockVector(VmaAllocator hAllocator) :
    3461  m_hAllocator(hAllocator),
    3462  m_Blocks(VmaStlAllocator<VmaBlock*>(hAllocator->GetAllocationCallbacks()))
    3463 {
    3464 }
    3465 
    3466 VmaBlockVector::~VmaBlockVector()
    3467 {
    3468  for(size_t i = m_Blocks.size(); i--; )
    3469  {
    3470  m_Blocks[i]->Destroy(m_hAllocator);
    3471  vma_delete(m_hAllocator, m_Blocks[i]);
    3472  }
    3473 }
    3474 
    3475 void VmaBlockVector::Remove(VmaBlock* pBlock)
    3476 {
    3477  for(uint32_t blockIndex = 0; blockIndex < m_Blocks.size(); ++blockIndex)
    3478  {
    3479  if(m_Blocks[blockIndex] == pBlock)
    3480  {
    3481  VectorRemove(m_Blocks, blockIndex);
    3482  return;
    3483  }
    3484  }
    3485  VMA_ASSERT(0);
    3486 }
    3487 
    3488 void VmaBlockVector::IncrementallySortBlocks()
    3489 {
    3490  // Bubble sort only until first swap.
    3491  for(size_t i = 1; i < m_Blocks.size(); ++i)
    3492  {
    3493  if(m_Blocks[i - 1]->m_SumFreeSize > m_Blocks[i]->m_SumFreeSize)
    3494  {
    3495  VMA_SWAP(m_Blocks[i - 1], m_Blocks[i]);
    3496  return;
    3497  }
    3498  }
    3499 }
    3500 
    3501 #if VMA_STATS_STRING_ENABLED
    3502 
    3503 void VmaBlockVector::PrintDetailedMap(class VmaStringBuilder& sb) const
    3504 {
    3505  for(size_t i = 0; i < m_Blocks.size(); ++i)
    3506  {
    3507  if(i > 0)
    3508  {
    3509  sb.Add(",\n\t\t");
    3510  }
    3511  else
    3512  {
    3513  sb.Add("\n\t\t");
    3514  }
    3515  m_Blocks[i]->PrintDetailedMap(sb);
    3516  }
    3517 }
    3518 
    3519 #endif // #if VMA_STATS_STRING_ENABLED
    3520 
    3521 void VmaBlockVector::UnmapPersistentlyMappedMemory()
    3522 {
    3523  for(size_t i = m_Blocks.size(); i--; )
    3524  {
    3525  VmaBlock* pBlock = m_Blocks[i];
    3526  if(pBlock->m_pMappedData != VMA_NULL)
    3527  {
    3528  VMA_ASSERT(pBlock->m_PersistentMap != false);
    3529  vkUnmapMemory(m_hAllocator->m_hDevice, pBlock->m_hMemory);
    3530  pBlock->m_pMappedData = VMA_NULL;
    3531  }
    3532  }
    3533 }
    3534 
    3535 VkResult VmaBlockVector::MapPersistentlyMappedMemory()
    3536 {
    3537  VkResult finalResult = VK_SUCCESS;
    3538  for(size_t i = 0, count = m_Blocks.size(); i < count; ++i)
    3539  {
    3540  VmaBlock* pBlock = m_Blocks[i];
    3541  if(pBlock->m_PersistentMap)
    3542  {
    3543  VMA_ASSERT(pBlock->m_pMappedData == nullptr);
    3544  VkResult localResult = vkMapMemory(m_hAllocator->m_hDevice, pBlock->m_hMemory, 0, VK_WHOLE_SIZE, 0, &pBlock->m_pMappedData);
    3545  if(localResult != VK_SUCCESS)
    3546  {
    3547  finalResult = localResult;
    3548  }
    3549  }
    3550  }
    3551  return finalResult;
    3552 }
    3553 
    3554 void VmaBlockVector::AddStats(VmaStats* pStats, uint32_t memTypeIndex, uint32_t memHeapIndex) const
    3555 {
    3556  for(uint32_t allocIndex = 0; allocIndex < m_Blocks.size(); ++allocIndex)
    3557  {
    3558  const VmaBlock* const pBlock = m_Blocks[allocIndex];
    3559  VMA_ASSERT(pBlock);
    3560  VMA_HEAVY_ASSERT(pBlock->Validate());
    3561  VmaStatInfo allocationStatInfo;
    3562  CalcAllocationStatInfo(allocationStatInfo, *pBlock);
    3563  VmaAddStatInfo(pStats->total, allocationStatInfo);
    3564  VmaAddStatInfo(pStats->memoryType[memTypeIndex], allocationStatInfo);
    3565  VmaAddStatInfo(pStats->memoryHeap[memHeapIndex], allocationStatInfo);
    3566  }
    3567 }
    3568 
    3570 // VmaDefragmentator
    3571 
    3572 class VmaDefragmentator
    3573 {
    3574  VkDevice m_hDevice;
    3575  const VkAllocationCallbacks* m_pAllocationCallbacks;
    3576  VkDeviceSize m_BufferImageGranularity;
    3577  uint32_t m_MemTypeIndex;
    3578  VMA_BLOCK_VECTOR_TYPE m_BlockVectorType;
    3579  VkDeviceSize m_BytesMoved;
    3580  uint32_t m_AllocationsMoved;
    3581 
    3582  struct AllocationInfo
    3583  {
    3584  VmaAllocation m_hAllocation;
    3585  VkBool32* m_pChanged;
    3586 
    3587  AllocationInfo() :
    3588  m_hAllocation(VK_NULL_HANDLE),
    3589  m_pChanged(VMA_NULL)
    3590  {
    3591  }
    3592  };
    3593 
    3594  struct AllocationInfoSizeGreater
    3595  {
    3596  bool operator()(const AllocationInfo& lhs, const AllocationInfo& rhs) const
    3597  {
    3598  return lhs.m_hAllocation->GetSize() > rhs.m_hAllocation->GetSize();
    3599  }
    3600  };
    3601 
    3602  // Used between AddAllocation and Defragment.
    3603  VmaVector< AllocationInfo, VmaStlAllocator<AllocationInfo> > m_Allocations;
    3604 
    3605  struct BlockInfo
    3606  {
    3607  VmaBlock* m_pBlock;
    3608  bool m_HasNonMovableAllocations;
    3609  VmaVector< AllocationInfo, VmaStlAllocator<AllocationInfo> > m_Allocations;
    3610 
    3611  BlockInfo(const VkAllocationCallbacks* pAllocationCallbacks) :
    3612  m_pBlock(VMA_NULL),
    3613  m_HasNonMovableAllocations(true),
    3614  m_Allocations(pAllocationCallbacks),
    3615  m_pMappedDataForDefragmentation(VMA_NULL)
    3616  {
    3617  }
    3618 
    3619  void CalcHasNonMovableAllocations()
    3620  {
    3621  const size_t blockAllocCount =
    3622  m_pBlock->m_Suballocations.size() - m_pBlock->m_FreeCount;
    3623  const size_t defragmentAllocCount = m_Allocations.size();
    3624  m_HasNonMovableAllocations = blockAllocCount != defragmentAllocCount;
    3625  }
    3626 
    3627  void SortAllocationsBySizeDescecnding()
    3628  {
    3629  VMA_SORT(m_Allocations.begin(), m_Allocations.end(), AllocationInfoSizeGreater());
    3630  }
    3631 
    3632  VkResult EnsureMapping(VkDevice hDevice, void** ppMappedData)
    3633  {
    3634  // It has already been mapped for defragmentation.
    3635  if(m_pMappedDataForDefragmentation)
    3636  {
    3637  *ppMappedData = m_pMappedDataForDefragmentation;
    3638  return VK_SUCCESS;
    3639  }
    3640 
    3641  // It is persistently mapped.
    3642  if(m_pBlock->m_PersistentMap)
    3643  {
    3644  VMA_ASSERT(m_pBlock->m_pMappedData != VMA_NULL);
    3645  *ppMappedData = m_pBlock->m_pMappedData;
    3646  return VK_SUCCESS;
    3647  }
    3648 
    3649  // Map on first usage.
    3650  VkResult res = vkMapMemory(hDevice, m_pBlock->m_hMemory, 0, VK_WHOLE_SIZE, 0, &m_pMappedDataForDefragmentation);
    3651  *ppMappedData = m_pMappedDataForDefragmentation;
    3652  return res;
    3653  }
    3654 
    3655  void Unmap(VkDevice hDevice)
    3656  {
    3657  if(m_pMappedDataForDefragmentation != VMA_NULL)
    3658  {
    3659  vkUnmapMemory(hDevice, m_pBlock->m_hMemory);
    3660  }
    3661  }
    3662 
    3663  private:
    3664  // Not null if mapped for defragmentation only, not persistently mapped.
    3665  void* m_pMappedDataForDefragmentation;
    3666  };
    3667 
    3668  struct BlockPointerLess
    3669  {
    3670  bool operator()(const BlockInfo* pLhsBlockInfo, const VmaBlock* pRhsBlock) const
    3671  {
    3672  return pLhsBlockInfo->m_pBlock < pRhsBlock;
    3673  }
    3674  bool operator()(const BlockInfo* pLhsBlockInfo, const BlockInfo* pRhsBlockInfo) const
    3675  {
    3676  return pLhsBlockInfo->m_pBlock < pRhsBlockInfo->m_pBlock;
    3677  }
    3678  };
    3679 
    3680  // 1. Blocks with some non-movable allocations go first.
    3681  // 2. Blocks with smaller sumFreeSize go first.
    3682  struct BlockInfoCompareMoveDestination
    3683  {
    3684  bool operator()(const BlockInfo* pLhsBlockInfo, const BlockInfo* pRhsBlockInfo) const
    3685  {
    3686  if(pLhsBlockInfo->m_HasNonMovableAllocations && !pRhsBlockInfo->m_HasNonMovableAllocations)
    3687  {
    3688  return true;
    3689  }
    3690  if(!pLhsBlockInfo->m_HasNonMovableAllocations && pRhsBlockInfo->m_HasNonMovableAllocations)
    3691  {
    3692  return false;
    3693  }
    3694  if(pLhsBlockInfo->m_pBlock->m_SumFreeSize < pRhsBlockInfo->m_pBlock->m_SumFreeSize)
    3695  {
    3696  return true;
    3697  }
    3698  return false;
    3699  }
    3700  };
    3701 
    3702  typedef VmaVector< BlockInfo*, VmaStlAllocator<BlockInfo*> > BlockInfoVector;
    3703  BlockInfoVector m_Blocks;
    3704 
    3705  VkResult DefragmentRound(
    3706  VkDeviceSize maxBytesToMove,
    3707  uint32_t maxAllocationsToMove);
    3708 
    3709  static bool MoveMakesSense(
    3710  size_t dstBlockIndex, VkDeviceSize dstOffset,
    3711  size_t srcBlockIndex, VkDeviceSize srcOffset);
    3712 
    3713 public:
    3714  VmaDefragmentator(
    3715  VkDevice hDevice,
    3716  const VkAllocationCallbacks* pAllocationCallbacks,
    3717  VkDeviceSize bufferImageGranularity,
    3718  uint32_t memTypeIndex,
    3719  VMA_BLOCK_VECTOR_TYPE blockVectorType);
    3720 
    3721  ~VmaDefragmentator();
    3722 
    3723  VkDeviceSize GetBytesMoved() const { return m_BytesMoved; }
    3724  uint32_t GetAllocationsMoved() const { return m_AllocationsMoved; }
    3725 
    3726  void AddAllocation(VmaAllocation hAlloc, VkBool32* pChanged);
    3727 
    3728  VkResult Defragment(
    3729  VmaBlockVector* pBlockVector,
    3730  VkDeviceSize maxBytesToMove,
    3731  uint32_t maxAllocationsToMove);
    3732 };
    3733 
    3734 VmaDefragmentator::VmaDefragmentator(
    3735  VkDevice hDevice,
    3736  const VkAllocationCallbacks* pAllocationCallbacks,
    3737  VkDeviceSize bufferImageGranularity,
    3738  uint32_t memTypeIndex,
    3739  VMA_BLOCK_VECTOR_TYPE blockVectorType) :
    3740  m_hDevice(hDevice),
    3741  m_pAllocationCallbacks(pAllocationCallbacks),
    3742  m_BufferImageGranularity(bufferImageGranularity),
    3743  m_MemTypeIndex(memTypeIndex),
    3744  m_BlockVectorType(blockVectorType),
    3745  m_BytesMoved(0),
    3746  m_AllocationsMoved(0),
    3747  m_Allocations(VmaStlAllocator<AllocationInfo>(pAllocationCallbacks)),
    3748  m_Blocks(VmaStlAllocator<BlockInfo*>(pAllocationCallbacks))
    3749 {
    3750 }
    3751 
    3752 VmaDefragmentator::~VmaDefragmentator()
    3753 {
    3754  for(size_t i = m_Blocks.size(); i--; )
    3755  {
    3756  vma_delete(m_pAllocationCallbacks, m_Blocks[i]);
    3757  }
    3758 }
    3759 
    3760 void VmaDefragmentator::AddAllocation(VmaAllocation hAlloc, VkBool32* pChanged)
    3761 {
    3762  AllocationInfo allocInfo;
    3763  allocInfo.m_hAllocation = hAlloc;
    3764  allocInfo.m_pChanged = pChanged;
    3765  m_Allocations.push_back(allocInfo);
    3766 }
    3767 
    3768 VkResult VmaDefragmentator::DefragmentRound(
    3769  VkDeviceSize maxBytesToMove,
    3770  uint32_t maxAllocationsToMove)
    3771 {
    3772  if(m_Blocks.empty())
    3773  {
    3774  return VK_SUCCESS;
    3775  }
    3776 
    3777  size_t srcBlockIndex = m_Blocks.size() - 1;
    3778  size_t srcAllocIndex = SIZE_MAX;
    3779  for(;;)
    3780  {
    3781  // 1. Find next allocation to move.
    3782  // 1.1. Start from last to first m_Blocks - they are sorted from most "destination" to most "source".
    3783  // 1.2. Then start from last to first m_Allocations - they are sorted from largest to smallest.
    3784  while(srcAllocIndex >= m_Blocks[srcBlockIndex]->m_Allocations.size())
    3785  {
    3786  if(m_Blocks[srcBlockIndex]->m_Allocations.empty())
    3787  {
    3788  // Finished: no more allocations to process.
    3789  if(srcBlockIndex == 0)
    3790  {
    3791  return VK_SUCCESS;
    3792  }
    3793  else
    3794  {
    3795  --srcBlockIndex;
    3796  srcAllocIndex = SIZE_MAX;
    3797  }
    3798  }
    3799  else
    3800  {
    3801  srcAllocIndex = m_Blocks[srcBlockIndex]->m_Allocations.size() - 1;
    3802  }
    3803  }
    3804 
    3805  BlockInfo* pSrcBlockInfo = m_Blocks[srcBlockIndex];
    3806  AllocationInfo& allocInfo = pSrcBlockInfo->m_Allocations[srcAllocIndex];
    3807 
    3808  const VkDeviceSize size = allocInfo.m_hAllocation->GetSize();
    3809  const VkDeviceSize srcOffset = allocInfo.m_hAllocation->GetOffset();
    3810  const VkDeviceSize alignment = allocInfo.m_hAllocation->GetAlignment();
    3811  const VmaSuballocationType suballocType = allocInfo.m_hAllocation->GetSuballocationType();
    3812 
    3813  // 2. Try to find new place for this allocation in preceding or current block.
    3814  for(size_t dstBlockIndex = 0; dstBlockIndex <= srcBlockIndex; ++dstBlockIndex)
    3815  {
    3816  BlockInfo* pDstBlockInfo = m_Blocks[dstBlockIndex];
    3817  VmaAllocationRequest dstAllocRequest;
    3818  if(pDstBlockInfo->m_pBlock->CreateAllocationRequest(
    3819  m_BufferImageGranularity,
    3820  size,
    3821  alignment,
    3822  suballocType,
    3823  &dstAllocRequest) &&
    3824  MoveMakesSense(
    3825  dstBlockIndex, dstAllocRequest.offset, srcBlockIndex, srcOffset))
    3826  {
    3827  // Reached limit on number of allocations or bytes to move.
    3828  if((m_AllocationsMoved + 1 > maxAllocationsToMove) ||
    3829  (m_BytesMoved + size > maxBytesToMove))
    3830  {
    3831  return VK_INCOMPLETE;
    3832  }
    3833 
    3834  void* pDstMappedData = VMA_NULL;
    3835  VkResult res = pDstBlockInfo->EnsureMapping(m_hDevice, &pDstMappedData);
    3836  if(res != VK_SUCCESS)
    3837  {
    3838  return res;
    3839  }
    3840 
    3841  void* pSrcMappedData = VMA_NULL;
    3842  res = pSrcBlockInfo->EnsureMapping(m_hDevice, &pSrcMappedData);
    3843  if(res != VK_SUCCESS)
    3844  {
    3845  return res;
    3846  }
    3847 
    3848  // THE PLACE WHERE ACTUAL DATA COPY HAPPENS.
    3849  memcpy(
    3850  reinterpret_cast<char*>(pDstMappedData) + dstAllocRequest.offset,
    3851  reinterpret_cast<char*>(pSrcMappedData) + srcOffset,
    3852  size);
    3853 
    3854  pDstBlockInfo->m_pBlock->Alloc(dstAllocRequest, suballocType, size);
    3855  pSrcBlockInfo->m_pBlock->Free(allocInfo.m_hAllocation);
    3856 
    3857  allocInfo.m_hAllocation->ChangeBlockAllocation(pDstBlockInfo->m_pBlock, dstAllocRequest.offset);
    3858 
    3859  if(allocInfo.m_pChanged != VMA_NULL)
    3860  {
    3861  *allocInfo.m_pChanged = VK_TRUE;
    3862  }
    3863 
    3864  ++m_AllocationsMoved;
    3865  m_BytesMoved += size;
    3866 
    3867  VectorRemove(pSrcBlockInfo->m_Allocations, srcAllocIndex);
    3868 
    3869  break;
    3870  }
    3871  }
    3872 
    3873  // If not processed, this allocInfo remains in pBlockInfo->m_Allocations for next round.
    3874 
    3875  if(srcAllocIndex > 0)
    3876  {
    3877  --srcAllocIndex;
    3878  }
    3879  else
    3880  {
    3881  if(srcBlockIndex > 0)
    3882  {
    3883  --srcBlockIndex;
    3884  srcAllocIndex = SIZE_MAX;
    3885  }
    3886  else
    3887  {
    3888  return VK_SUCCESS;
    3889  }
    3890  }
    3891  }
    3892 }
    3893 
    3894 VkResult VmaDefragmentator::Defragment(
    3895  VmaBlockVector* pBlockVector,
    3896  VkDeviceSize maxBytesToMove,
    3897  uint32_t maxAllocationsToMove)
    3898 {
    3899  if(m_Allocations.empty())
    3900  {
    3901  return VK_SUCCESS;
    3902  }
    3903 
    3904  // Create block info for each block.
    3905  const size_t blockCount = pBlockVector->m_Blocks.size();
    3906  for(size_t blockIndex = 0; blockIndex < blockCount; ++blockIndex)
    3907  {
    3908  BlockInfo* pBlockInfo = vma_new(m_pAllocationCallbacks, BlockInfo)(m_pAllocationCallbacks);
    3909  pBlockInfo->m_pBlock = pBlockVector->m_Blocks[blockIndex];
    3910  m_Blocks.push_back(pBlockInfo);
    3911  }
    3912 
    3913  // Sort them by m_pBlock pointer value.
    3914  VMA_SORT(m_Blocks.begin(), m_Blocks.end(), BlockPointerLess());
    3915 
    3916  // Move allocation infos from m_Allocations to appropriate m_Blocks[i].m_Allocations.
    3917  for(size_t allocIndex = 0, allocCount = m_Allocations.size(); allocIndex < allocCount; ++allocIndex)
    3918  {
    3919  AllocationInfo& allocInfo = m_Allocations[allocIndex];
    3920  VmaBlock* pBlock = allocInfo.m_hAllocation->GetBlock();
    3921  BlockInfoVector::iterator it = VmaBinaryFindFirstNotLess(m_Blocks.begin(), m_Blocks.end(), pBlock, BlockPointerLess());
    3922  if(it != m_Blocks.end() && (*it)->m_pBlock == pBlock)
    3923  {
    3924  (*it)->m_Allocations.push_back(allocInfo);
    3925  }
    3926  else
    3927  {
    3928  VMA_ASSERT(0);
    3929  }
    3930  }
    3931  m_Allocations.clear();
    3932 
    3933  for(size_t blockIndex = 0; blockIndex < blockCount; ++blockIndex)
    3934  {
    3935  BlockInfo* pBlockInfo = m_Blocks[blockIndex];
    3936  pBlockInfo->CalcHasNonMovableAllocations();
    3937  pBlockInfo->SortAllocationsBySizeDescecnding();
    3938  }
    3939 
    3940  // Sort m_Blocks this time by the main criterium, from most "destination" to most "source" blocks.
    3941  VMA_SORT(m_Blocks.begin(), m_Blocks.end(), BlockInfoCompareMoveDestination());
    3942 
    3943  // Execute defragmentation round (the main part).
    3944  VkResult result = VK_SUCCESS;
    3945  for(size_t round = 0; (round < 2) && (result == VK_SUCCESS); ++round)
    3946  {
    3947  result = DefragmentRound(maxBytesToMove, maxAllocationsToMove);
    3948  }
    3949 
    3950  // Unmap blocks that were mapped for defragmentation.
    3951  for(size_t blockIndex = 0; blockIndex < blockCount; ++blockIndex)
    3952  {
    3953  m_Blocks[blockIndex]->Unmap(m_hDevice);
    3954  }
    3955 
    3956  return result;
    3957 }
    3958 
    3959 bool VmaDefragmentator::MoveMakesSense(
    3960  size_t dstBlockIndex, VkDeviceSize dstOffset,
    3961  size_t srcBlockIndex, VkDeviceSize srcOffset)
    3962 {
    3963  if(dstBlockIndex < srcBlockIndex)
    3964  {
    3965  return true;
    3966  }
    3967  if(dstBlockIndex > srcBlockIndex)
    3968  {
    3969  return false;
    3970  }
    3971  if(dstOffset < srcOffset)
    3972  {
    3973  return true;
    3974  }
    3975  return false;
    3976 }
    3977 
    3979 // VmaAllocator_T
    3980 
    3981 VmaAllocator_T::VmaAllocator_T(const VmaAllocatorCreateInfo* pCreateInfo) :
    3982  m_UseMutex((pCreateInfo->flags & VMA_ALLOCATOR_EXTERNALLY_SYNCHRONIZED_BIT) == 0),
    3983  m_PhysicalDevice(pCreateInfo->physicalDevice),
    3984  m_hDevice(pCreateInfo->device),
    3985  m_AllocationCallbacksSpecified(pCreateInfo->pAllocationCallbacks != VMA_NULL),
    3986  m_AllocationCallbacks(pCreateInfo->pAllocationCallbacks ?
    3987  *pCreateInfo->pAllocationCallbacks : VmaEmptyAllocationCallbacks),
    3988  m_PreferredLargeHeapBlockSize(0),
    3989  m_PreferredSmallHeapBlockSize(0),
    3990  m_UnmapPersistentlyMappedMemoryCounter(0)
    3991 {
    3992  VMA_ASSERT(pCreateInfo->physicalDevice && pCreateInfo->device);
    3993 
    3994  memset(&m_DeviceMemoryCallbacks, 0 ,sizeof(m_DeviceMemoryCallbacks));
    3995  memset(&m_MemProps, 0, sizeof(m_MemProps));
    3996  memset(&m_PhysicalDeviceProperties, 0, sizeof(m_PhysicalDeviceProperties));
    3997 
    3998  memset(&m_pBlockVectors, 0, sizeof(m_pBlockVectors));
    3999  memset(&m_HasEmptyBlock, 0, sizeof(m_HasEmptyBlock));
    4000  memset(&m_pOwnAllocations, 0, sizeof(m_pOwnAllocations));
    4001 
    4002  if(pCreateInfo->pDeviceMemoryCallbacks != VMA_NULL)
    4003  {
    4004  m_DeviceMemoryCallbacks.pfnAllocate = pCreateInfo->pDeviceMemoryCallbacks->pfnAllocate;
    4005  m_DeviceMemoryCallbacks.pfnFree = pCreateInfo->pDeviceMemoryCallbacks->pfnFree;
    4006  }
    4007 
    4008  m_PreferredLargeHeapBlockSize = (pCreateInfo->preferredLargeHeapBlockSize != 0) ?
    4009  pCreateInfo->preferredLargeHeapBlockSize : static_cast<VkDeviceSize>(VMA_DEFAULT_LARGE_HEAP_BLOCK_SIZE);
    4010  m_PreferredSmallHeapBlockSize = (pCreateInfo->preferredSmallHeapBlockSize != 0) ?
    4011  pCreateInfo->preferredSmallHeapBlockSize : static_cast<VkDeviceSize>(VMA_DEFAULT_SMALL_HEAP_BLOCK_SIZE);
    4012 
    4013  vkGetPhysicalDeviceProperties(m_PhysicalDevice, &m_PhysicalDeviceProperties);
    4014  vkGetPhysicalDeviceMemoryProperties(m_PhysicalDevice, &m_MemProps);
    4015 
    4016  for(size_t i = 0; i < GetMemoryTypeCount(); ++i)
    4017  {
    4018  for(size_t j = 0; j < VMA_BLOCK_VECTOR_TYPE_COUNT; ++j)
    4019  {
    4020  m_pBlockVectors[i][j] = vma_new(this, VmaBlockVector)(this);
    4021  m_pOwnAllocations[i][j] = vma_new(this, AllocationVectorType)(VmaStlAllocator<VmaAllocation>(GetAllocationCallbacks()));
    4022  }
    4023  }
    4024 }
    4025 
    4026 VmaAllocator_T::~VmaAllocator_T()
    4027 {
    4028  for(size_t i = GetMemoryTypeCount(); i--; )
    4029  {
    4030  for(size_t j = VMA_BLOCK_VECTOR_TYPE_COUNT; j--; )
    4031  {
    4032  vma_delete(this, m_pOwnAllocations[i][j]);
    4033  vma_delete(this, m_pBlockVectors[i][j]);
    4034  }
    4035  }
    4036 }
    4037 
    4038 VkDeviceSize VmaAllocator_T::GetPreferredBlockSize(uint32_t memTypeIndex) const
    4039 {
    4040  VkDeviceSize heapSize = m_MemProps.memoryHeaps[m_MemProps.memoryTypes[memTypeIndex].heapIndex].size;
    4041  return (heapSize <= VMA_SMALL_HEAP_MAX_SIZE) ?
    4042  m_PreferredSmallHeapBlockSize : m_PreferredLargeHeapBlockSize;
    4043 }
    4044 
    4045 VkResult VmaAllocator_T::AllocateMemoryOfType(
    4046  const VkMemoryRequirements& vkMemReq,
    4047  const VmaMemoryRequirements& vmaMemReq,
    4048  uint32_t memTypeIndex,
    4049  VmaSuballocationType suballocType,
    4050  VmaAllocation* pAllocation)
    4051 {
    4052  VMA_ASSERT(pAllocation != VMA_NULL);
    4053  VMA_DEBUG_LOG(" AllocateMemory: MemoryTypeIndex=%u, Size=%llu", memTypeIndex, vkMemReq.size);
    4054 
    4055  const VkDeviceSize preferredBlockSize = GetPreferredBlockSize(memTypeIndex);
    4056  // Heuristics: Allocate own memory if requested size if greater than half of preferred block size.
    4057  const bool ownMemory =
    4058  (vmaMemReq.flags & VMA_MEMORY_REQUIREMENT_OWN_MEMORY_BIT) != 0 ||
    4059  VMA_DEBUG_ALWAYS_OWN_MEMORY ||
    4060  ((vmaMemReq.flags & VMA_MEMORY_REQUIREMENT_NEVER_ALLOCATE_BIT) == 0 &&
    4061  vkMemReq.size > preferredBlockSize / 2);
    4062 
    4063  if(ownMemory)
    4064  {
    4065  if((vmaMemReq.flags & VMA_MEMORY_REQUIREMENT_NEVER_ALLOCATE_BIT) != 0)
    4066  {
    4067  return VK_ERROR_OUT_OF_DEVICE_MEMORY;
    4068  }
    4069  else
    4070  {
    4071  return AllocateOwnMemory(
    4072  vkMemReq.size,
    4073  suballocType,
    4074  memTypeIndex,
    4076  vmaMemReq.pUserData,
    4077  pAllocation);
    4078  }
    4079  }
    4080  else
    4081  {
    4082  uint32_t blockVectorType = VmaMemoryRequirementFlagsToBlockVectorType(vmaMemReq.flags);
    4083 
    4084  VmaMutexLock lock(m_BlocksMutex[memTypeIndex], m_UseMutex);
    4085  VmaBlockVector* const blockVector = m_pBlockVectors[memTypeIndex][blockVectorType];
    4086  VMA_ASSERT(blockVector);
    4087 
    4088  // 1. Search existing allocations.
    4089  // Forward order - prefer blocks with smallest amount of free space.
    4090  for(size_t allocIndex = 0; allocIndex < blockVector->m_Blocks.size(); ++allocIndex )
    4091  {
    4092  VmaBlock* const pBlock = blockVector->m_Blocks[allocIndex];
    4093  VMA_ASSERT(pBlock);
    4094  VmaAllocationRequest allocRequest = {};
    4095  // Check if can allocate from pBlock.
    4096  if(pBlock->CreateAllocationRequest(
    4097  GetBufferImageGranularity(),
    4098  vkMemReq.size,
    4099  vkMemReq.alignment,
    4100  suballocType,
    4101  &allocRequest))
    4102  {
    4103  // We no longer have an empty Allocation.
    4104  if(pBlock->IsEmpty())
    4105  {
    4106  m_HasEmptyBlock[memTypeIndex] = false;
    4107  }
    4108  // Allocate from this pBlock.
    4109  pBlock->Alloc(allocRequest, suballocType, vkMemReq.size);
    4110  *pAllocation = vma_new(this, VmaAllocation_T)();
    4111  (*pAllocation)->InitBlockAllocation(
    4112  pBlock,
    4113  allocRequest.offset,
    4114  vkMemReq.alignment,
    4115  vkMemReq.size,
    4116  suballocType,
    4117  vmaMemReq.pUserData);
    4118  VMA_HEAVY_ASSERT(pBlock->Validate());
    4119  VMA_DEBUG_LOG(" Returned from existing allocation #%u", (uint32_t)allocIndex);
    4120  return VK_SUCCESS;
    4121  }
    4122  }
    4123 
    4124  // 2. Create new Allocation.
    4125  if((vmaMemReq.flags & VMA_MEMORY_REQUIREMENT_NEVER_ALLOCATE_BIT) != 0)
    4126  {
    4127  VMA_DEBUG_LOG(" FAILED due to VMA_MEMORY_REQUIREMENT_NEVER_ALLOCATE_BIT");
    4128  return VK_ERROR_OUT_OF_DEVICE_MEMORY;
    4129  }
    4130  else
    4131  {
    4132  // Start with full preferredBlockSize.
    4133  VkMemoryAllocateInfo allocInfo = { VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO };
    4134  allocInfo.memoryTypeIndex = memTypeIndex;
    4135  allocInfo.allocationSize = preferredBlockSize;
    4136  VkDeviceMemory mem = VK_NULL_HANDLE;
    4137  VkResult res = vkAllocateMemory(m_hDevice, &allocInfo, GetAllocationCallbacks(), &mem);
    4138  if(res < 0)
    4139  {
    4140  // 3. Try half the size.
    4141  allocInfo.allocationSize /= 2;
    4142  if(allocInfo.allocationSize >= vkMemReq.size)
    4143  {
    4144  res = vkAllocateMemory(m_hDevice, &allocInfo, GetAllocationCallbacks(), &mem);
    4145  if(res < 0)
    4146  {
    4147  // 4. Try quarter the size.
    4148  allocInfo.allocationSize /= 2;
    4149  if(allocInfo.allocationSize >= vkMemReq.size)
    4150  {
    4151  res = vkAllocateMemory(m_hDevice, &allocInfo, GetAllocationCallbacks(), &mem);
    4152  }
    4153  }
    4154  }
    4155  }
    4156  if(res < 0)
    4157  {
    4158  // 5. Try OwnAlloc.
    4159  res = AllocateOwnMemory(
    4160  vkMemReq.size,
    4161  suballocType,
    4162  memTypeIndex,
    4164  vmaMemReq.pUserData,
    4165  pAllocation);
    4166  if(res == VK_SUCCESS)
    4167  {
    4168  // Succeeded: AllocateOwnMemory function already filld pMemory, nothing more to do here.
    4169  VMA_DEBUG_LOG(" Allocated as OwnMemory");
    4170  return VK_SUCCESS;
    4171  }
    4172  else
    4173  {
    4174  // Everything failed: Return error code.
    4175  VMA_DEBUG_LOG(" vkAllocateMemory FAILED");
    4176  return res;
    4177  }
    4178  }
    4179 
    4180  // New VkDeviceMemory successfully created.
    4181 
    4182  // Map memory if needed.
    4183  void* pMappedData = VMA_NULL;
    4184  const bool persistentMap = (vmaMemReq.flags & VMA_MEMORY_REQUIREMENT_PERSISTENT_MAP_BIT) != 0;
    4185  if(persistentMap && m_UnmapPersistentlyMappedMemoryCounter == 0)
    4186  {
    4187  res = vkMapMemory(m_hDevice, mem, 0, VK_WHOLE_SIZE, 0, &pMappedData);
    4188  if(res < 0)
    4189  {
    4190  VMA_DEBUG_LOG(" vkMapMemory FAILED");
    4191  vkFreeMemory(m_hDevice, mem, GetAllocationCallbacks());
    4192  return res;
    4193  }
    4194  }
    4195 
    4196  // Callback.
    4197  if(m_DeviceMemoryCallbacks.pfnAllocate != VMA_NULL)
    4198  {
    4199  (*m_DeviceMemoryCallbacks.pfnAllocate)(this, memTypeIndex, mem, allocInfo.allocationSize);
    4200  }
    4201 
    4202  // Create new Allocation for it.
    4203  VmaBlock* const pBlock = vma_new(this, VmaBlock)(this);
    4204  pBlock->Init(
    4205  memTypeIndex,
    4206  (VMA_BLOCK_VECTOR_TYPE)blockVectorType,
    4207  mem,
    4208  allocInfo.allocationSize,
    4209  persistentMap,
    4210  pMappedData);
    4211 
    4212  blockVector->m_Blocks.push_back(pBlock);
    4213 
    4214  // Allocate from pBlock. Because it is empty, dstAllocRequest can be trivially filled.
    4215  VmaAllocationRequest allocRequest = {};
    4216  allocRequest.freeSuballocationItem = pBlock->m_Suballocations.begin();
    4217  allocRequest.offset = 0;
    4218  pBlock->Alloc(allocRequest, suballocType, vkMemReq.size);
    4219  *pAllocation = vma_new(this, VmaAllocation_T)();
    4220  (*pAllocation)->InitBlockAllocation(
    4221  pBlock,
    4222  allocRequest.offset,
    4223  vkMemReq.alignment,
    4224  vkMemReq.size,
    4225  suballocType,
    4226  vmaMemReq.pUserData);
    4227  VMA_HEAVY_ASSERT(pBlock->Validate());
    4228  VMA_DEBUG_LOG(" Created new allocation Size=%llu", allocInfo.allocationSize);
    4229  return VK_SUCCESS;
    4230  }
    4231  }
    4232 }
    4233 
    4234 VkResult VmaAllocator_T::AllocateOwnMemory(
    4235  VkDeviceSize size,
    4236  VmaSuballocationType suballocType,
    4237  uint32_t memTypeIndex,
    4238  bool map,
    4239  void* pUserData,
    4240  VmaAllocation* pAllocation)
    4241 {
    4242  VMA_ASSERT(pAllocation);
    4243 
    4244  VkMemoryAllocateInfo allocInfo = { VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO };
    4245  allocInfo.memoryTypeIndex = memTypeIndex;
    4246  allocInfo.allocationSize = size;
    4247 
    4248  // Allocate VkDeviceMemory.
    4249  VkDeviceMemory hMemory = VK_NULL_HANDLE;
    4250  VkResult res = vkAllocateMemory(m_hDevice, &allocInfo, GetAllocationCallbacks(), &hMemory);
    4251  if(res < 0)
    4252  {
    4253  VMA_DEBUG_LOG(" vkAllocateMemory FAILED");
    4254  return res;
    4255  }
    4256 
    4257  void* pMappedData = nullptr;
    4258  if(map)
    4259  {
    4260  if(m_UnmapPersistentlyMappedMemoryCounter == 0)
    4261  {
    4262  res = vkMapMemory(m_hDevice, hMemory, 0, VK_WHOLE_SIZE, 0, &pMappedData);
    4263  if(res < 0)
    4264  {
    4265  VMA_DEBUG_LOG(" vkMapMemory FAILED");
    4266  vkFreeMemory(m_hDevice, hMemory, GetAllocationCallbacks());
    4267  return res;
    4268  }
    4269  }
    4270  }
    4271 
    4272  // Callback.
    4273  if(m_DeviceMemoryCallbacks.pfnAllocate != VMA_NULL)
    4274  {
    4275  (*m_DeviceMemoryCallbacks.pfnAllocate)(this, memTypeIndex, hMemory, size);
    4276  }
    4277 
    4278  *pAllocation = vma_new(this, VmaAllocation_T)();
    4279  (*pAllocation)->InitOwnAllocation(memTypeIndex, hMemory, suballocType, map, pMappedData, size, pUserData);
    4280 
    4281  // Register it in m_pOwnAllocations.
    4282  {
    4283  VmaMutexLock lock(m_OwnAllocationsMutex[memTypeIndex], m_UseMutex);
    4284  AllocationVectorType* pOwnAllocations = m_pOwnAllocations[memTypeIndex][map ? VMA_BLOCK_VECTOR_TYPE_MAPPED : VMA_BLOCK_VECTOR_TYPE_UNMAPPED];
    4285  VMA_ASSERT(pOwnAllocations);
    4286  VmaAllocation* const pOwnAllocationsBeg = pOwnAllocations->data();
    4287  VmaAllocation* const pOwnAllocationsEnd = pOwnAllocationsBeg + pOwnAllocations->size();
    4288  const size_t indexToInsert = VmaBinaryFindFirstNotLess(
    4289  pOwnAllocationsBeg,
    4290  pOwnAllocationsEnd,
    4291  *pAllocation,
    4292  VmaPointerLess()) - pOwnAllocationsBeg;
    4293  VectorInsert(*pOwnAllocations, indexToInsert, *pAllocation);
    4294  }
    4295 
    4296  VMA_DEBUG_LOG(" Allocated OwnMemory MemoryTypeIndex=#%u", memTypeIndex);
    4297 
    4298  return VK_SUCCESS;
    4299 }
    4300 
    4301 VkResult VmaAllocator_T::AllocateMemory(
    4302  const VkMemoryRequirements& vkMemReq,
    4303  const VmaMemoryRequirements& vmaMemReq,
    4304  VmaSuballocationType suballocType,
    4305  VmaAllocation* pAllocation)
    4306 {
    4307  if((vmaMemReq.flags & VMA_MEMORY_REQUIREMENT_OWN_MEMORY_BIT) != 0 &&
    4309  {
    4310  VMA_ASSERT(0 && "Specifying VMA_MEMORY_REQUIREMENT_OWN_MEMORY_BIT together with VMA_MEMORY_REQUIREMENT_NEVER_ALLOCATE_BIT makes no sense.");
    4311  return VK_ERROR_OUT_OF_DEVICE_MEMORY;
    4312  }
    4313 
    4314  // Bit mask of memory Vulkan types acceptable for this allocation.
    4315  uint32_t memoryTypeBits = vkMemReq.memoryTypeBits;
    4316  uint32_t memTypeIndex = UINT32_MAX;
    4317  VkResult res = vmaFindMemoryTypeIndex(this, memoryTypeBits, &vmaMemReq, &memTypeIndex);
    4318  if(res == VK_SUCCESS)
    4319  {
    4320  res = AllocateMemoryOfType(vkMemReq, vmaMemReq, memTypeIndex, suballocType, pAllocation);
    4321  // Succeeded on first try.
    4322  if(res == VK_SUCCESS)
    4323  {
    4324  return res;
    4325  }
    4326  // Allocation from this memory type failed. Try other compatible memory types.
    4327  else
    4328  {
    4329  for(;;)
    4330  {
    4331  // Remove old memTypeIndex from list of possibilities.
    4332  memoryTypeBits &= ~(1u << memTypeIndex);
    4333  // Find alternative memTypeIndex.
    4334  res = vmaFindMemoryTypeIndex(this, memoryTypeBits, &vmaMemReq, &memTypeIndex);
    4335  if(res == VK_SUCCESS)
    4336  {
    4337  res = AllocateMemoryOfType(vkMemReq, vmaMemReq, memTypeIndex, suballocType, pAllocation);
    4338  // Allocation from this alternative memory type succeeded.
    4339  if(res == VK_SUCCESS)
    4340  {
    4341  return res;
    4342  }
    4343  // else: Allocation from this memory type failed. Try next one - next loop iteration.
    4344  }
    4345  // No other matching memory type index could be found.
    4346  else
    4347  {
    4348  // Not returning res, which is VK_ERROR_FEATURE_NOT_PRESENT, because we already failed to allocate once.
    4349  return VK_ERROR_OUT_OF_DEVICE_MEMORY;
    4350  }
    4351  }
    4352  }
    4353  }
    4354  // Can't find any single memory type maching requirements. res is VK_ERROR_FEATURE_NOT_PRESENT.
    4355  else
    4356  return res;
    4357 }
    4358 
    4359 void VmaAllocator_T::FreeMemory(const VmaAllocation allocation)
    4360 {
    4361  VMA_ASSERT(allocation);
    4362 
    4363  if(allocation->GetType() == VmaAllocation_T::ALLOCATION_TYPE_BLOCK)
    4364  {
    4365  VmaBlock* pBlockToDelete = VMA_NULL;
    4366 
    4367  const uint32_t memTypeIndex = allocation->GetMemoryTypeIndex();
    4368  const VMA_BLOCK_VECTOR_TYPE blockVectorType = allocation->GetBlockVectorType();
    4369  {
    4370  VmaMutexLock lock(m_BlocksMutex[memTypeIndex], m_UseMutex);
    4371 
    4372  VmaBlockVector* pBlockVector = m_pBlockVectors[memTypeIndex][blockVectorType];
    4373  VmaBlock* pBlock = allocation->GetBlock();
    4374 
    4375  pBlock->Free(allocation);
    4376  VMA_HEAVY_ASSERT(pBlock->Validate());
    4377 
    4378  VMA_DEBUG_LOG(" Freed from MemoryTypeIndex=%u", memTypeIndex);
    4379 
    4380  // pBlock became empty after this deallocation.
    4381  if(pBlock->IsEmpty())
    4382  {
    4383  // Already has empty Allocation. We don't want to have two, so delete this one.
    4384  if(m_HasEmptyBlock[memTypeIndex])
    4385  {
    4386  pBlockToDelete = pBlock;
    4387  pBlockVector->Remove(pBlock);
    4388  }
    4389  // We now have first empty Allocation.
    4390  else
    4391  {
    4392  m_HasEmptyBlock[memTypeIndex] = true;
    4393  }
    4394  }
    4395  // Must be called after srcBlockIndex is used, because later it may become invalid!
    4396  pBlockVector->IncrementallySortBlocks();
    4397  }
    4398  // Destruction of a free Allocation. Deferred until this point, outside of mutex
    4399  // lock, for performance reason.
    4400  if(pBlockToDelete != VMA_NULL)
    4401  {
    4402  VMA_DEBUG_LOG(" Deleted empty allocation");
    4403  pBlockToDelete->Destroy(this);
    4404  vma_delete(this, pBlockToDelete);
    4405  }
    4406 
    4407  vma_delete(this, allocation);
    4408  }
    4409  else // VmaAllocation_T::ALLOCATION_TYPE_OWN
    4410  {
    4411  FreeOwnMemory(allocation);
    4412  }
    4413 }
    4414 
    4415 void VmaAllocator_T::CalculateStats(VmaStats* pStats)
    4416 {
    4417  InitStatInfo(pStats->total);
    4418  for(size_t i = 0; i < VK_MAX_MEMORY_TYPES; ++i)
    4419  InitStatInfo(pStats->memoryType[i]);
    4420  for(size_t i = 0; i < VK_MAX_MEMORY_HEAPS; ++i)
    4421  InitStatInfo(pStats->memoryHeap[i]);
    4422 
    4423  for(uint32_t memTypeIndex = 0; memTypeIndex < GetMemoryTypeCount(); ++memTypeIndex)
    4424  {
    4425  VmaMutexLock allocationsLock(m_BlocksMutex[memTypeIndex], m_UseMutex);
    4426  const uint32_t heapIndex = m_MemProps.memoryTypes[memTypeIndex].heapIndex;
    4427  for(uint32_t blockVectorType = 0; blockVectorType < VMA_BLOCK_VECTOR_TYPE_COUNT; ++blockVectorType)
    4428  {
    4429  const VmaBlockVector* const pBlockVector = m_pBlockVectors[memTypeIndex][blockVectorType];
    4430  VMA_ASSERT(pBlockVector);
    4431  pBlockVector->AddStats(pStats, memTypeIndex, heapIndex);
    4432  }
    4433  }
    4434 
    4435  VmaPostprocessCalcStatInfo(pStats->total);
    4436  for(size_t i = 0; i < GetMemoryTypeCount(); ++i)
    4437  VmaPostprocessCalcStatInfo(pStats->memoryType[i]);
    4438  for(size_t i = 0; i < GetMemoryHeapCount(); ++i)
    4439  VmaPostprocessCalcStatInfo(pStats->memoryHeap[i]);
    4440 }
    4441 
    4442 static const uint32_t VMA_VENDOR_ID_AMD = 4098;
    4443 
    4444 void VmaAllocator_T::UnmapPersistentlyMappedMemory()
    4445 {
    4446  if(m_UnmapPersistentlyMappedMemoryCounter++ == 0)
    4447  {
    4448  if(m_PhysicalDeviceProperties.vendorID == VMA_VENDOR_ID_AMD)
    4449  {
    4450  for(size_t memTypeIndex = m_MemProps.memoryTypeCount; memTypeIndex--; )
    4451  {
    4452  const VkMemoryPropertyFlags memFlags = m_MemProps.memoryTypes[memTypeIndex].propertyFlags;
    4453  if((memFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) != 0 &&
    4454  (memFlags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) != 0)
    4455  {
    4456  // Process OwnAllocations.
    4457  {
    4458  VmaMutexLock lock(m_OwnAllocationsMutex[memTypeIndex], m_UseMutex);
    4459  AllocationVectorType* pOwnAllocationsVector = m_pOwnAllocations[memTypeIndex][VMA_BLOCK_VECTOR_TYPE_MAPPED];
    4460  for(size_t ownAllocIndex = pOwnAllocationsVector->size(); ownAllocIndex--; )
    4461  {
    4462  VmaAllocation hAlloc = (*pOwnAllocationsVector)[ownAllocIndex];
    4463  hAlloc->OwnAllocUnmapPersistentlyMappedMemory(m_hDevice);
    4464  }
    4465  }
    4466 
    4467  // Process normal Allocations.
    4468  {
    4469  VmaMutexLock lock(m_BlocksMutex[memTypeIndex], m_UseMutex);
    4470  VmaBlockVector* pBlockVector = m_pBlockVectors[memTypeIndex][VMA_BLOCK_VECTOR_TYPE_MAPPED];
    4471  pBlockVector->UnmapPersistentlyMappedMemory();
    4472  }
    4473  }
    4474  }
    4475  }
    4476  }
    4477 }
    4478 
    4479 VkResult VmaAllocator_T::MapPersistentlyMappedMemory()
    4480 {
    4481  VMA_ASSERT(m_UnmapPersistentlyMappedMemoryCounter > 0);
    4482  if(--m_UnmapPersistentlyMappedMemoryCounter == 0)
    4483  {
    4484  VkResult finalResult = VK_SUCCESS;
    4485  if(m_PhysicalDeviceProperties.vendorID == VMA_VENDOR_ID_AMD)
    4486  {
    4487  for(size_t memTypeIndex = 0; memTypeIndex < m_MemProps.memoryTypeCount; ++memTypeIndex)
    4488  {
    4489  const VkMemoryPropertyFlags memFlags = m_MemProps.memoryTypes[memTypeIndex].propertyFlags;
    4490  if((memFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) != 0 &&
    4491  (memFlags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) != 0)
    4492  {
    4493  // Process OwnAllocations.
    4494  {
    4495  VmaMutexLock lock(m_OwnAllocationsMutex[memTypeIndex], m_UseMutex);
    4496  AllocationVectorType* pAllocationsVector = m_pOwnAllocations[memTypeIndex][VMA_BLOCK_VECTOR_TYPE_MAPPED];
    4497  for(size_t ownAllocIndex = 0, ownAllocCount = pAllocationsVector->size(); ownAllocIndex < ownAllocCount; ++ownAllocIndex)
    4498  {
    4499  VmaAllocation hAlloc = (*pAllocationsVector)[ownAllocIndex];
    4500  hAlloc->OwnAllocMapPersistentlyMappedMemory(m_hDevice);
    4501  }
    4502  }
    4503 
    4504  // Process normal Allocations.
    4505  {
    4506  VmaMutexLock lock(m_BlocksMutex[memTypeIndex], m_UseMutex);
    4507  VmaBlockVector* pBlockVector = m_pBlockVectors[memTypeIndex][VMA_BLOCK_VECTOR_TYPE_MAPPED];
    4508  VkResult localResult = pBlockVector->MapPersistentlyMappedMemory();
    4509  if(localResult != VK_SUCCESS)
    4510  {
    4511  finalResult = localResult;
    4512  }
    4513  }
    4514  }
    4515  }
    4516  }
    4517  return finalResult;
    4518  }
    4519  else
    4520  return VK_SUCCESS;
    4521 }
    4522 
    4523 VkResult VmaAllocator_T::Defragment(
    4524  VmaAllocation* pAllocations,
    4525  size_t allocationCount,
    4526  VkBool32* pAllocationsChanged,
    4527  const VmaDefragmentationInfo* pDefragmentationInfo,
    4528  VmaDefragmentationStats* pDefragmentationStats)
    4529 {
    4530  if(pAllocationsChanged != VMA_NULL)
    4531  {
    4532  memset(pAllocationsChanged, 0, sizeof(*pAllocationsChanged));
    4533  }
    4534  if(pDefragmentationStats != VMA_NULL)
    4535  {
    4536  memset(pDefragmentationStats, 0, sizeof(*pDefragmentationStats));
    4537  }
    4538 
    4539  if(m_UnmapPersistentlyMappedMemoryCounter > 0)
    4540  {
    4541  VMA_DEBUG_LOG("ERROR: Cannot defragment when inside vmaUnmapPersistentlyMappedMemory.");
    4542  return VK_ERROR_MEMORY_MAP_FAILED;
    4543  }
    4544 
    4545  // Initialize defragmentators per memory type.
    4546  const VkDeviceSize bufferImageGranularity = GetBufferImageGranularity();
    4547  VmaDefragmentator* pDefragmentators[VK_MAX_MEMORY_TYPES][VMA_BLOCK_VECTOR_TYPE_COUNT];
    4548  memset(pDefragmentators, 0, sizeof(pDefragmentators));
    4549  for(uint32_t memTypeIndex = 0; memTypeIndex < GetMemoryTypeCount(); ++memTypeIndex)
    4550  {
    4551  // Only HOST_VISIBLE memory types can be defragmented.
    4552  if((m_MemProps.memoryTypes[memTypeIndex].propertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) != 0)
    4553  {
    4554  for(uint32_t blockVectorType = 0; blockVectorType < VMA_BLOCK_VECTOR_TYPE_COUNT; ++blockVectorType)
    4555  {
    4556  pDefragmentators[memTypeIndex][blockVectorType] = vma_new(this, VmaDefragmentator)(
    4557  m_hDevice,
    4558  GetAllocationCallbacks(),
    4559  bufferImageGranularity,
    4560  memTypeIndex,
    4561  (VMA_BLOCK_VECTOR_TYPE)blockVectorType);
    4562  }
    4563  }
    4564  }
    4565 
    4566  // Dispatch pAllocations among defragmentators.
    4567  for(size_t allocIndex = 0; allocIndex < allocationCount; ++allocIndex)
    4568  {
    4569  VmaAllocation hAlloc = pAllocations[allocIndex];
    4570  VMA_ASSERT(hAlloc);
    4571  if(hAlloc->GetType() == VmaAllocation_T::ALLOCATION_TYPE_BLOCK)
    4572  {
    4573  const uint32_t memTypeIndex = hAlloc->GetMemoryTypeIndex();
    4574  // Only HOST_VISIBLE memory types can be defragmented.
    4575  if((m_MemProps.memoryTypes[memTypeIndex].propertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) != 0)
    4576  {
    4577  const VMA_BLOCK_VECTOR_TYPE blockVectorType = hAlloc->GetBlockVectorType();
    4578  VkBool32* pChanged = (pAllocationsChanged != VMA_NULL) ?
    4579  &pAllocationsChanged[allocIndex] : VMA_NULL;
    4580  pDefragmentators[memTypeIndex][blockVectorType]->AddAllocation(hAlloc, pChanged);
    4581  }
    4582  // else: skip this allocation, cannot move it.
    4583  }
    4584  // else ALLOCATION_TYPE_OWN: skip this allocation, nothing to defragment.
    4585  }
    4586 
    4587  VkResult result = VK_SUCCESS;
    4588 
    4589  // Main processing.
    4590  VkDeviceSize maxBytesToMove = SIZE_MAX;
    4591  uint32_t maxAllocationsToMove = UINT32_MAX;
    4592  if(pDefragmentationInfo != VMA_NULL)
    4593  {
    4594  maxBytesToMove = pDefragmentationInfo->maxBytesToMove;
    4595  maxAllocationsToMove = pDefragmentationInfo->maxAllocationsToMove;
    4596  }
    4597  for(uint32_t memTypeIndex = 0;
    4598  (memTypeIndex < GetMemoryTypeCount()) && (result == VK_SUCCESS);
    4599  ++memTypeIndex)
    4600  {
    4601  // Only HOST_VISIBLE memory types can be defragmented.
    4602  if((m_MemProps.memoryTypes[memTypeIndex].propertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) != 0)
    4603  {
    4604  VmaMutexLock lock(m_BlocksMutex[memTypeIndex], m_UseMutex);
    4605 
    4606  for(uint32_t blockVectorType = 0;
    4607  (blockVectorType < VMA_BLOCK_VECTOR_TYPE_COUNT) && (result == VK_SUCCESS);
    4608  ++blockVectorType)
    4609  {
    4610  VmaBlockVector* pBlockVector = m_pBlockVectors[memTypeIndex][blockVectorType];
    4611 
    4612  // Defragment.
    4613  result = pDefragmentators[memTypeIndex][blockVectorType]->Defragment(pBlockVector, maxBytesToMove, maxAllocationsToMove);
    4614 
    4615  // Accumulate statistics.
    4616  if(pDefragmentationStats != VMA_NULL)
    4617  {
    4618  const VkDeviceSize bytesMoved = pDefragmentators[memTypeIndex][blockVectorType]->GetBytesMoved();
    4619  const uint32_t allocationsMoved = pDefragmentators[memTypeIndex][blockVectorType]->GetAllocationsMoved();
    4620  pDefragmentationStats->bytesMoved += bytesMoved;
    4621  pDefragmentationStats->allocationsMoved += allocationsMoved;
    4622  VMA_ASSERT(bytesMoved <= maxBytesToMove);
    4623  VMA_ASSERT(allocationsMoved <= maxAllocationsToMove);
    4624  maxBytesToMove -= bytesMoved;
    4625  maxAllocationsToMove -= allocationsMoved;
    4626  }
    4627 
    4628  // Free empty blocks.
    4629  for(size_t blockIndex = pBlockVector->m_Blocks.size(); blockIndex--; )
    4630  {
    4631  VmaBlock* pBlock = pBlockVector->m_Blocks[blockIndex];
    4632  if(pBlock->IsEmpty())
    4633  {
    4634  if(pDefragmentationStats != VMA_NULL)
    4635  {
    4636  ++pDefragmentationStats->deviceMemoryBlocksFreed;
    4637  pDefragmentationStats->bytesFreed += pBlock->m_Size;
    4638  }
    4639 
    4640  VectorRemove(pBlockVector->m_Blocks, blockIndex);
    4641  pBlock->Destroy(this);
    4642  vma_delete(this, pBlock);
    4643  }
    4644  }
    4645 
    4646  // All block vector types processed: we can be sure that all empty allocations have been freed.
    4647  if(blockVectorType == VMA_BLOCK_VECTOR_TYPE_COUNT - 1)
    4648  {
    4649  m_HasEmptyBlock[memTypeIndex] = false;
    4650  }
    4651  }
    4652  }
    4653  }
    4654 
    4655  // Destroy defragmentators.
    4656  for(uint32_t memTypeIndex = GetMemoryTypeCount(); memTypeIndex--; )
    4657  {
    4658  for(size_t blockVectorType = VMA_BLOCK_VECTOR_TYPE_COUNT; blockVectorType--; )
    4659  {
    4660  vma_delete(this, pDefragmentators[memTypeIndex][blockVectorType]);
    4661  }
    4662  }
    4663 
    4664  return result;
    4665 }
    4666 
    4667 void VmaAllocator_T::GetAllocationInfo(VmaAllocation hAllocation, VmaAllocationInfo* pAllocationInfo)
    4668 {
    4669  pAllocationInfo->memoryType = hAllocation->GetMemoryTypeIndex();
    4670  pAllocationInfo->deviceMemory = hAllocation->GetMemory();
    4671  pAllocationInfo->offset = hAllocation->GetOffset();
    4672  pAllocationInfo->size = hAllocation->GetSize();
    4673  pAllocationInfo->pMappedData = hAllocation->GetMappedData();
    4674  pAllocationInfo->pUserData = hAllocation->GetUserData();
    4675 }
    4676 
    4677 void VmaAllocator_T::FreeOwnMemory(VmaAllocation allocation)
    4678 {
    4679  VMA_ASSERT(allocation && allocation->GetType() == VmaAllocation_T::ALLOCATION_TYPE_OWN);
    4680 
    4681  const uint32_t memTypeIndex = allocation->GetMemoryTypeIndex();
    4682  {
    4683  VmaMutexLock lock(m_OwnAllocationsMutex[memTypeIndex], m_UseMutex);
    4684  AllocationVectorType* const pOwnAllocations = m_pOwnAllocations[memTypeIndex][allocation->GetBlockVectorType()];
    4685  VMA_ASSERT(pOwnAllocations);
    4686  VmaAllocation* const pOwnAllocationsBeg = pOwnAllocations->data();
    4687  VmaAllocation* const pOwnAllocationsEnd = pOwnAllocationsBeg + pOwnAllocations->size();
    4688  VmaAllocation* const pOwnAllocationIt = VmaBinaryFindFirstNotLess(
    4689  pOwnAllocationsBeg,
    4690  pOwnAllocationsEnd,
    4691  allocation,
    4692  VmaPointerLess());
    4693  if(pOwnAllocationIt != pOwnAllocationsEnd)
    4694  {
    4695  const size_t ownAllocationIndex = pOwnAllocationIt - pOwnAllocationsBeg;
    4696  VectorRemove(*pOwnAllocations, ownAllocationIndex);
    4697  }
    4698  else
    4699  {
    4700  VMA_ASSERT(0);
    4701  }
    4702  }
    4703 
    4704  VkDeviceMemory hMemory = allocation->GetMemory();
    4705 
    4706  // Callback.
    4707  if(m_DeviceMemoryCallbacks.pfnFree != VMA_NULL)
    4708  {
    4709  (*m_DeviceMemoryCallbacks.pfnFree)(this, memTypeIndex, hMemory, allocation->GetSize());
    4710  }
    4711 
    4712  if(allocation->GetMappedData() != VMA_NULL)
    4713  {
    4714  vkUnmapMemory(m_hDevice, hMemory);
    4715  }
    4716 
    4717  vkFreeMemory(m_hDevice, hMemory, GetAllocationCallbacks());
    4718 
    4719  VMA_DEBUG_LOG(" Freed OwnMemory MemoryTypeIndex=%u", memTypeIndex);
    4720 
    4721  vma_delete(this, allocation);
    4722 }
    4723 
    4724 #if VMA_STATS_STRING_ENABLED
    4725 
    4726 void VmaAllocator_T::PrintDetailedMap(VmaStringBuilder& sb)
    4727 {
    4728  bool ownAllocationsStarted = false;
    4729  for(size_t memTypeIndex = 0; memTypeIndex < GetMemoryTypeCount(); ++memTypeIndex)
    4730  {
    4731  VmaMutexLock ownAllocationsLock(m_OwnAllocationsMutex[memTypeIndex], m_UseMutex);
    4732  for(uint32_t blockVectorType = 0; blockVectorType < VMA_BLOCK_VECTOR_TYPE_COUNT; ++blockVectorType)
    4733  {
    4734  AllocationVectorType* const pOwnAllocVector = m_pOwnAllocations[memTypeIndex][blockVectorType];
    4735  VMA_ASSERT(pOwnAllocVector);
    4736  if(pOwnAllocVector->empty() == false)
    4737  {
    4738  if(ownAllocationsStarted)
    4739  {
    4740  sb.Add(",\n\t\"Type ");
    4741  }
    4742  else
    4743  {
    4744  sb.Add(",\n\"OwnAllocations\": {\n\t\"Type ");
    4745  ownAllocationsStarted = true;
    4746  }
    4747  sb.AddNumber(memTypeIndex);
    4748  if(blockVectorType == VMA_BLOCK_VECTOR_TYPE_MAPPED)
    4749  {
    4750  sb.Add(" Mapped");
    4751  }
    4752  sb.Add("\": [");
    4753 
    4754  for(size_t i = 0; i < pOwnAllocVector->size(); ++i)
    4755  {
    4756  const VmaAllocation hAlloc = (*pOwnAllocVector)[i];
    4757  if(i > 0)
    4758  {
    4759  sb.Add(",\n\t\t{ \"Size\": ");
    4760  }
    4761  else
    4762  {
    4763  sb.Add("\n\t\t{ \"Size\": ");
    4764  }
    4765  sb.AddNumber(hAlloc->GetSize());
    4766  sb.Add(", \"Type\": ");
    4767  sb.AddString(VMA_SUBALLOCATION_TYPE_NAMES[hAlloc->GetSuballocationType()]);
    4768  sb.Add(" }");
    4769  }
    4770 
    4771  sb.Add("\n\t]");
    4772  }
    4773  }
    4774  }
    4775  if(ownAllocationsStarted)
    4776  {
    4777  sb.Add("\n}");
    4778  }
    4779 
    4780  {
    4781  bool allocationsStarted = false;
    4782  for(size_t memTypeIndex = 0; memTypeIndex < GetMemoryTypeCount(); ++memTypeIndex)
    4783  {
    4784  VmaMutexLock globalAllocationsLock(m_BlocksMutex[memTypeIndex], m_UseMutex);
    4785  for(uint32_t blockVectorType = 0; blockVectorType < VMA_BLOCK_VECTOR_TYPE_COUNT; ++blockVectorType)
    4786  {
    4787  if(m_pBlockVectors[memTypeIndex][blockVectorType]->IsEmpty() == false)
    4788  {
    4789  if(allocationsStarted)
    4790  {
    4791  sb.Add(",\n\t\"Type ");
    4792  }
    4793  else
    4794  {
    4795  sb.Add(",\n\"Allocations\": {\n\t\"Type ");
    4796  allocationsStarted = true;
    4797  }
    4798  sb.AddNumber(memTypeIndex);
    4799  if(blockVectorType == VMA_BLOCK_VECTOR_TYPE_MAPPED)
    4800  {
    4801  sb.Add(" Mapped");
    4802  }
    4803  sb.Add("\": [");
    4804 
    4805  m_pBlockVectors[memTypeIndex][blockVectorType]->PrintDetailedMap(sb);
    4806 
    4807  sb.Add("\n\t]");
    4808  }
    4809  }
    4810  }
    4811  if(allocationsStarted)
    4812  {
    4813  sb.Add("\n}");
    4814  }
    4815  }
    4816 }
    4817 
    4818 #endif // #if VMA_STATS_STRING_ENABLED
    4819 
    4820 static VkResult AllocateMemoryForImage(
    4821  VmaAllocator allocator,
    4822  VkImage image,
    4823  const VmaMemoryRequirements* pMemoryRequirements,
    4824  VmaSuballocationType suballocType,
    4825  VmaAllocation* pAllocation)
    4826 {
    4827  VMA_ASSERT(allocator && (image != VK_NULL_HANDLE) && pMemoryRequirements && pAllocation);
    4828 
    4829  VkMemoryRequirements vkMemReq = {};
    4830  vkGetImageMemoryRequirements(allocator->m_hDevice, image, &vkMemReq);
    4831 
    4832  return allocator->AllocateMemory(
    4833  vkMemReq,
    4834  *pMemoryRequirements,
    4835  suballocType,
    4836  pAllocation);
    4837 }
    4838 
    4840 // Public interface
    4841 
    4842 VkResult vmaCreateAllocator(
    4843  const VmaAllocatorCreateInfo* pCreateInfo,
    4844  VmaAllocator* pAllocator)
    4845 {
    4846  VMA_ASSERT(pCreateInfo && pAllocator);
    4847  VMA_DEBUG_LOG("vmaCreateAllocator");
    4848  *pAllocator = vma_new(pCreateInfo->pAllocationCallbacks, VmaAllocator_T)(pCreateInfo);
    4849  return VK_SUCCESS;
    4850 }
    4851 
    4852 void vmaDestroyAllocator(
    4853  VmaAllocator allocator)
    4854 {
    4855  if(allocator != VK_NULL_HANDLE)
    4856  {
    4857  VMA_DEBUG_LOG("vmaDestroyAllocator");
    4858  VkAllocationCallbacks allocationCallbacks = allocator->m_AllocationCallbacks;
    4859  vma_delete(&allocationCallbacks, allocator);
    4860  }
    4861 }
    4862 
    4864  VmaAllocator allocator,
    4865  const VkPhysicalDeviceProperties **ppPhysicalDeviceProperties)
    4866 {
    4867  VMA_ASSERT(allocator && ppPhysicalDeviceProperties);
    4868  *ppPhysicalDeviceProperties = &allocator->m_PhysicalDeviceProperties;
    4869 }
    4870 
    4872  VmaAllocator allocator,
    4873  const VkPhysicalDeviceMemoryProperties** ppPhysicalDeviceMemoryProperties)
    4874 {
    4875  VMA_ASSERT(allocator && ppPhysicalDeviceMemoryProperties);
    4876  *ppPhysicalDeviceMemoryProperties = &allocator->m_MemProps;
    4877 }
    4878 
    4880  VmaAllocator allocator,
    4881  uint32_t memoryTypeIndex,
    4882  VkMemoryPropertyFlags* pFlags)
    4883 {
    4884  VMA_ASSERT(allocator && pFlags);
    4885  VMA_ASSERT(memoryTypeIndex < allocator->GetMemoryTypeCount());
    4886  *pFlags = allocator->m_MemProps.memoryTypes[memoryTypeIndex].propertyFlags;
    4887 }
    4888 
    4889 void vmaCalculateStats(
    4890  VmaAllocator allocator,
    4891  VmaStats* pStats)
    4892 {
    4893  VMA_ASSERT(allocator && pStats);
    4894  VMA_DEBUG_GLOBAL_MUTEX_LOCK
    4895  allocator->CalculateStats(pStats);
    4896 }
    4897 
    4898 #if VMA_STATS_STRING_ENABLED
    4899 
    4900 void vmaBuildStatsString(
    4901  VmaAllocator allocator,
    4902  char** ppStatsString,
    4903  VkBool32 detailedMap)
    4904 {
    4905  VMA_ASSERT(allocator && ppStatsString);
    4906  VMA_DEBUG_GLOBAL_MUTEX_LOCK
    4907 
    4908  VmaStringBuilder sb(allocator);
    4909  {
    4910  VmaStats stats;
    4911  allocator->CalculateStats(&stats);
    4912 
    4913  sb.Add("{\n\"Total\": ");
    4914  VmaPrintStatInfo(sb, stats.total);
    4915 
    4916  for(uint32_t heapIndex = 0; heapIndex < allocator->GetMemoryHeapCount(); ++heapIndex)
    4917  {
    4918  sb.Add(",\n\"Heap ");
    4919  sb.AddNumber(heapIndex);
    4920  sb.Add("\": {\n\t\"Size\": ");
    4921  sb.AddNumber(allocator->m_MemProps.memoryHeaps[heapIndex].size);
    4922  sb.Add(",\n\t\"Flags\": ");
    4923  if((allocator->m_MemProps.memoryHeaps[heapIndex].flags & VK_MEMORY_HEAP_DEVICE_LOCAL_BIT) != 0)
    4924  {
    4925  sb.AddString("DEVICE_LOCAL");
    4926  }
    4927  else
    4928  {
    4929  sb.AddString("");
    4930  }
    4931  if(stats.memoryHeap[heapIndex].AllocationCount > 0)
    4932  {
    4933  sb.Add(",\n\t\"Stats:\": ");
    4934  VmaPrintStatInfo(sb, stats.memoryHeap[heapIndex]);
    4935  }
    4936 
    4937  for(uint32_t typeIndex = 0; typeIndex < allocator->GetMemoryTypeCount(); ++typeIndex)
    4938  {
    4939  if(allocator->m_MemProps.memoryTypes[typeIndex].heapIndex == heapIndex)
    4940  {
    4941  sb.Add(",\n\t\"Type ");
    4942  sb.AddNumber(typeIndex);
    4943  sb.Add("\": {\n\t\t\"Flags\": \"");
    4944  VkMemoryPropertyFlags flags = allocator->m_MemProps.memoryTypes[typeIndex].propertyFlags;
    4945  if((flags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) != 0)
    4946  {
    4947  sb.Add(" DEVICE_LOCAL");
    4948  }
    4949  if((flags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) != 0)
    4950  {
    4951  sb.Add(" HOST_VISIBLE");
    4952  }
    4953  if((flags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT) != 0)
    4954  {
    4955  sb.Add(" HOST_COHERENT");
    4956  }
    4957  if((flags & VK_MEMORY_PROPERTY_HOST_CACHED_BIT) != 0)
    4958  {
    4959  sb.Add(" HOST_CACHED");
    4960  }
    4961  if((flags & VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT) != 0)
    4962  {
    4963  sb.Add(" LAZILY_ALLOCATED");
    4964  }
    4965  sb.Add("\"");
    4966  if(stats.memoryType[typeIndex].AllocationCount > 0)
    4967  {
    4968  sb.Add(",\n\t\t\"Stats\": ");
    4969  VmaPrintStatInfo(sb, stats.memoryType[typeIndex]);
    4970  }
    4971  sb.Add("\n\t}");
    4972  }
    4973  }
    4974  sb.Add("\n}");
    4975  }
    4976  if(detailedMap == VK_TRUE)
    4977  {
    4978  allocator->PrintDetailedMap(sb);
    4979  }
    4980  sb.Add("\n}\n");
    4981  }
    4982 
    4983  const size_t len = sb.GetLength();
    4984  char* const pChars = vma_new_array(allocator, char, len + 1);
    4985  if(len > 0)
    4986  {
    4987  memcpy(pChars, sb.GetData(), len);
    4988  }
    4989  pChars[len] = '\0';
    4990  *ppStatsString = pChars;
    4991 }
    4992 
    4993 void vmaFreeStatsString(
    4994  VmaAllocator allocator,
    4995  char* pStatsString)
    4996 {
    4997  if(pStatsString != VMA_NULL)
    4998  {
    4999  VMA_ASSERT(allocator);
    5000  size_t len = strlen(pStatsString);
    5001  vma_delete_array(allocator, pStatsString, len + 1);
    5002  }
    5003 }
    5004 
    5005 #endif // #if VMA_STATS_STRING_ENABLED
    5006 
    5009 VkResult vmaFindMemoryTypeIndex(
    5010  VmaAllocator allocator,
    5011  uint32_t memoryTypeBits,
    5012  const VmaMemoryRequirements* pMemoryRequirements,
    5013  uint32_t* pMemoryTypeIndex)
    5014 {
    5015  VMA_ASSERT(allocator != VK_NULL_HANDLE);
    5016  VMA_ASSERT(pMemoryRequirements != VMA_NULL);
    5017  VMA_ASSERT(pMemoryTypeIndex != VMA_NULL);
    5018 
    5019  uint32_t requiredFlags = pMemoryRequirements->requiredFlags;
    5020  uint32_t preferredFlags = pMemoryRequirements->preferredFlags;
    5021  if(preferredFlags == 0)
    5022  {
    5023  preferredFlags = requiredFlags;
    5024  }
    5025  // preferredFlags, if not 0, must be a superset of requiredFlags.
    5026  VMA_ASSERT((requiredFlags & ~preferredFlags) == 0);
    5027 
    5028  // Convert usage to requiredFlags and preferredFlags.
    5029  switch(pMemoryRequirements->usage)
    5030  {
    5032  break;
    5034  preferredFlags |= VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
    5035  break;
    5037  requiredFlags |= VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
    5038  break;
    5040  requiredFlags |= VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT;
    5041  preferredFlags |= VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
    5042  break;
    5044  requiredFlags |= VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT;
    5045  preferredFlags |= VK_MEMORY_PROPERTY_HOST_COHERENT_BIT | VK_MEMORY_PROPERTY_HOST_CACHED_BIT;
    5046  break;
    5047  default:
    5048  break;
    5049  }
    5050 
    5051  if((pMemoryRequirements->flags & VMA_MEMORY_REQUIREMENT_PERSISTENT_MAP_BIT) != 0)
    5052  {
    5053  requiredFlags |= VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT;
    5054  }
    5055 
    5056  *pMemoryTypeIndex = UINT32_MAX;
    5057  uint32_t minCost = UINT32_MAX;
    5058  for(uint32_t memTypeIndex = 0, memTypeBit = 1;
    5059  memTypeIndex < allocator->GetMemoryTypeCount();
    5060  ++memTypeIndex, memTypeBit <<= 1)
    5061  {
    5062  // This memory type is acceptable according to memoryTypeBits bitmask.
    5063  if((memTypeBit & memoryTypeBits) != 0)
    5064  {
    5065  const VkMemoryPropertyFlags currFlags =
    5066  allocator->m_MemProps.memoryTypes[memTypeIndex].propertyFlags;
    5067  // This memory type contains requiredFlags.
    5068  if((requiredFlags & ~currFlags) == 0)
    5069  {
    5070  // Calculate cost as number of bits from preferredFlags not present in this memory type.
    5071  uint32_t currCost = CountBitsSet(preferredFlags & ~currFlags);
    5072  // Remember memory type with lowest cost.
    5073  if(currCost < minCost)
    5074  {
    5075  *pMemoryTypeIndex = memTypeIndex;
    5076  if(currCost == 0)
    5077  {
    5078  return VK_SUCCESS;
    5079  }
    5080  minCost = currCost;
    5081  }
    5082  }
    5083  }
    5084  }
    5085  return (*pMemoryTypeIndex != UINT32_MAX) ? VK_SUCCESS : VK_ERROR_FEATURE_NOT_PRESENT;
    5086 }
    5087 
    5088 VkResult vmaAllocateMemory(
    5089  VmaAllocator allocator,
    5090  const VkMemoryRequirements* pVkMemoryRequirements,
    5091  const VmaMemoryRequirements* pVmaMemoryRequirements,
    5092  VmaAllocation* pAllocation,
    5093  VmaAllocationInfo* pAllocationInfo)
    5094 {
    5095  VMA_ASSERT(allocator && pVkMemoryRequirements && pVmaMemoryRequirements && pAllocation);
    5096 
    5097  VMA_DEBUG_LOG("vmaAllocateMemory");
    5098 
    5099  VMA_DEBUG_GLOBAL_MUTEX_LOCK
    5100 
    5101  return allocator->AllocateMemory(
    5102  *pVkMemoryRequirements,
    5103  *pVmaMemoryRequirements,
    5104  VMA_SUBALLOCATION_TYPE_UNKNOWN,
    5105  pAllocation);
    5106 
    5107  if(pAllocationInfo)
    5108  {
    5109  allocator->GetAllocationInfo(*pAllocation, pAllocationInfo);
    5110  }
    5111 }
    5112 
    5114  VmaAllocator allocator,
    5115  VkBuffer buffer,
    5116  const VmaMemoryRequirements* pMemoryRequirements,
    5117  VmaAllocation* pAllocation,
    5118  VmaAllocationInfo* pAllocationInfo)
    5119 {
    5120  VMA_ASSERT(allocator && buffer != VK_NULL_HANDLE && pMemoryRequirements && pAllocation);
    5121 
    5122  VMA_DEBUG_LOG("vmaAllocateMemoryForBuffer");
    5123 
    5124  VMA_DEBUG_GLOBAL_MUTEX_LOCK
    5125 
    5126  VkMemoryRequirements vkMemReq = {};
    5127  vkGetBufferMemoryRequirements(allocator->m_hDevice, buffer, &vkMemReq);
    5128 
    5129  return allocator->AllocateMemory(
    5130  vkMemReq,
    5131  *pMemoryRequirements,
    5132  VMA_SUBALLOCATION_TYPE_BUFFER,
    5133  pAllocation);
    5134 
    5135  if(pAllocationInfo)
    5136  {
    5137  allocator->GetAllocationInfo(*pAllocation, pAllocationInfo);
    5138  }
    5139 }
    5140 
    5141 VkResult vmaAllocateMemoryForImage(
    5142  VmaAllocator allocator,
    5143  VkImage image,
    5144  const VmaMemoryRequirements* pMemoryRequirements,
    5145  VmaAllocation* pAllocation,
    5146  VmaAllocationInfo* pAllocationInfo)
    5147 {
    5148  VMA_ASSERT(allocator && image != VK_NULL_HANDLE && pMemoryRequirements && pAllocation);
    5149 
    5150  VMA_DEBUG_LOG("vmaAllocateMemoryForImage");
    5151 
    5152  VMA_DEBUG_GLOBAL_MUTEX_LOCK
    5153 
    5154  return AllocateMemoryForImage(
    5155  allocator,
    5156  image,
    5157  pMemoryRequirements,
    5158  VMA_SUBALLOCATION_TYPE_IMAGE_UNKNOWN,
    5159  pAllocation);
    5160 
    5161  if(pAllocationInfo)
    5162  {
    5163  allocator->GetAllocationInfo(*pAllocation, pAllocationInfo);
    5164  }
    5165 }
    5166 
    5167 void vmaFreeMemory(
    5168  VmaAllocator allocator,
    5169  VmaAllocation allocation)
    5170 {
    5171  VMA_ASSERT(allocator && allocation);
    5172 
    5173  VMA_DEBUG_LOG("vmaFreeMemory");
    5174 
    5175  VMA_DEBUG_GLOBAL_MUTEX_LOCK
    5176 
    5177  allocator->FreeMemory(allocation);
    5178 }
    5179 
    5181  VmaAllocator allocator,
    5182  VmaAllocation allocation,
    5183  VmaAllocationInfo* pAllocationInfo)
    5184 {
    5185  VMA_ASSERT(allocator && allocation && pAllocationInfo);
    5186 
    5187  VMA_DEBUG_GLOBAL_MUTEX_LOCK
    5188 
    5189  allocator->GetAllocationInfo(allocation, pAllocationInfo);
    5190 }
    5191 
    5193  VmaAllocator allocator,
    5194  VmaAllocation allocation,
    5195  void* pUserData)
    5196 {
    5197  VMA_ASSERT(allocator && allocation);
    5198 
    5199  VMA_DEBUG_GLOBAL_MUTEX_LOCK
    5200 
    5201  allocation->SetUserData(pUserData);
    5202 }
    5203 
    5204 VkResult vmaMapMemory(
    5205  VmaAllocator allocator,
    5206  VmaAllocation allocation,
    5207  void** ppData)
    5208 {
    5209  VMA_ASSERT(allocator && allocation && ppData);
    5210 
    5211  VMA_DEBUG_GLOBAL_MUTEX_LOCK
    5212 
    5213  return vkMapMemory(allocator->m_hDevice, allocation->GetMemory(),
    5214  allocation->GetOffset(), allocation->GetSize(), 0, ppData);
    5215 }
    5216 
    5217 void vmaUnmapMemory(
    5218  VmaAllocator allocator,
    5219  VmaAllocation allocation)
    5220 {
    5221  VMA_ASSERT(allocator && allocation);
    5222 
    5223  VMA_DEBUG_GLOBAL_MUTEX_LOCK
    5224 
    5225  vkUnmapMemory(allocator->m_hDevice, allocation->GetMemory());
    5226 }
    5227 
    5228 void vmaUnmapPersistentlyMappedMemory(VmaAllocator allocator)
    5229 {
    5230  VMA_ASSERT(allocator);
    5231 
    5232  VMA_DEBUG_GLOBAL_MUTEX_LOCK
    5233 
    5234  allocator->UnmapPersistentlyMappedMemory();
    5235 }
    5236 
    5237 VkResult vmaMapPersistentlyMappedMemory(VmaAllocator allocator)
    5238 {
    5239  VMA_ASSERT(allocator);
    5240 
    5241  VMA_DEBUG_GLOBAL_MUTEX_LOCK
    5242 
    5243  return allocator->MapPersistentlyMappedMemory();
    5244 }
    5245 
    5246 VkResult vmaDefragment(
    5247  VmaAllocator allocator,
    5248  VmaAllocation* pAllocations,
    5249  size_t allocationCount,
    5250  VkBool32* pAllocationsChanged,
    5251  const VmaDefragmentationInfo *pDefragmentationInfo,
    5252  VmaDefragmentationStats* pDefragmentationStats)
    5253 {
    5254  VMA_ASSERT(allocator && pAllocations);
    5255 
    5256  VMA_DEBUG_LOG("vmaDefragment");
    5257 
    5258  VMA_DEBUG_GLOBAL_MUTEX_LOCK
    5259 
    5260  return allocator->Defragment(pAllocations, allocationCount, pAllocationsChanged, pDefragmentationInfo, pDefragmentationStats);
    5261 }
    5262 
    5263 VkResult vmaCreateBuffer(
    5264  VmaAllocator allocator,
    5265  const VkBufferCreateInfo* pCreateInfo,
    5266  const VmaMemoryRequirements* pMemoryRequirements,
    5267  VkBuffer* pBuffer,
    5268  VmaAllocation* pAllocation,
    5269  VmaAllocationInfo* pAllocationInfo)
    5270 {
    5271  VMA_ASSERT(allocator && pCreateInfo && pMemoryRequirements && pBuffer && pAllocation);
    5272 
    5273  VMA_DEBUG_LOG("vmaCreateBuffer");
    5274 
    5275  VMA_DEBUG_GLOBAL_MUTEX_LOCK
    5276 
    5277  // 1. Create VkBuffer.
    5278  VkResult res = vkCreateBuffer(allocator->m_hDevice, pCreateInfo, allocator->GetAllocationCallbacks(), pBuffer);
    5279  if(res >= 0)
    5280  {
    5281  // 2. vkGetBufferMemoryRequirements.
    5282  VkMemoryRequirements vkMemReq = {};
    5283  vkGetBufferMemoryRequirements(allocator->m_hDevice, *pBuffer, &vkMemReq);
    5284 
    5285  // 3. Allocate memory using allocator.
    5286  res = allocator->AllocateMemory(
    5287  vkMemReq,
    5288  *pMemoryRequirements,
    5289  VMA_SUBALLOCATION_TYPE_BUFFER,
    5290  pAllocation);
    5291  if(res >= 0)
    5292  {
    5293  // 3. Bind buffer with memory.
    5294  res = vkBindBufferMemory(allocator->m_hDevice, *pBuffer, (*pAllocation)->GetMemory(), (*pAllocation)->GetOffset());
    5295  if(res >= 0)
    5296  {
    5297  // All steps succeeded.
    5298  if(pAllocationInfo != VMA_NULL)
    5299  {
    5300  allocator->GetAllocationInfo(*pAllocation, pAllocationInfo);
    5301  }
    5302  return VK_SUCCESS;
    5303  }
    5304  allocator->FreeMemory(*pAllocation);
    5305  return res;
    5306  }
    5307  vkDestroyBuffer(allocator->m_hDevice, *pBuffer, allocator->GetAllocationCallbacks());
    5308  return res;
    5309  }
    5310  return res;
    5311 }
    5312 
    5313 void vmaDestroyBuffer(
    5314  VmaAllocator allocator,
    5315  VkBuffer buffer,
    5316  VmaAllocation allocation)
    5317 {
    5318  if(buffer != VK_NULL_HANDLE)
    5319  {
    5320  VMA_ASSERT(allocator);
    5321 
    5322  VMA_DEBUG_LOG("vmaDestroyBuffer");
    5323 
    5324  VMA_DEBUG_GLOBAL_MUTEX_LOCK
    5325 
    5326  vkDestroyBuffer(allocator->m_hDevice, buffer, allocator->GetAllocationCallbacks());
    5327 
    5328  allocator->FreeMemory(allocation);
    5329  }
    5330 }
    5331 
    5332 VkResult vmaCreateImage(
    5333  VmaAllocator allocator,
    5334  const VkImageCreateInfo* pCreateInfo,
    5335  const VmaMemoryRequirements* pMemoryRequirements,
    5336  VkImage* pImage,
    5337  VmaAllocation* pAllocation,
    5338  VmaAllocationInfo* pAllocationInfo)
    5339 {
    5340  VMA_ASSERT(allocator && pCreateInfo && pMemoryRequirements && pImage && pAllocation);
    5341 
    5342  VMA_DEBUG_LOG("vmaCreateImage");
    5343 
    5344  VMA_DEBUG_GLOBAL_MUTEX_LOCK
    5345 
    5346  // 1. Create VkImage.
    5347  VkResult res = vkCreateImage(allocator->m_hDevice, pCreateInfo, allocator->GetAllocationCallbacks(), pImage);
    5348  if(res >= 0)
    5349  {
    5350  VkMappedMemoryRange mem = {};
    5351  VmaSuballocationType suballocType = pCreateInfo->tiling == VK_IMAGE_TILING_OPTIMAL ?
    5352  VMA_SUBALLOCATION_TYPE_IMAGE_OPTIMAL :
    5353  VMA_SUBALLOCATION_TYPE_IMAGE_LINEAR;
    5354 
    5355  // 2. Allocate memory using allocator.
    5356  res = AllocateMemoryForImage(allocator, *pImage, pMemoryRequirements, suballocType, pAllocation);
    5357  if(res >= 0)
    5358  {
    5359  // 3. Bind image with memory.
    5360  res = vkBindImageMemory(allocator->m_hDevice, *pImage, (*pAllocation)->GetMemory(), (*pAllocation)->GetOffset());
    5361  if(res >= 0)
    5362  {
    5363  // All steps succeeded.
    5364  if(pAllocationInfo != VMA_NULL)
    5365  {
    5366  allocator->GetAllocationInfo(*pAllocation, pAllocationInfo);
    5367  }
    5368  return VK_SUCCESS;
    5369  }
    5370  allocator->FreeMemory(*pAllocation);
    5371  return res;
    5372  }
    5373  vkDestroyImage(allocator->m_hDevice, *pImage, allocator->GetAllocationCallbacks());
    5374  return res;
    5375  }
    5376  return res;
    5377 }
    5378 
    5379 void vmaDestroyImage(
    5380  VmaAllocator allocator,
    5381  VkImage image,
    5382  VmaAllocation allocation)
    5383 {
    5384  if(image != VK_NULL_HANDLE)
    5385  {
    5386  VMA_ASSERT(allocator);
    5387 
    5388  VMA_DEBUG_LOG("vmaDestroyImage");
    5389 
    5390  VMA_DEBUG_GLOBAL_MUTEX_LOCK
    5391 
    5392  vkDestroyImage(allocator->m_hDevice, image, allocator->GetAllocationCallbacks());
    5393 
    5394  allocator->FreeMemory(allocation);
    5395  }
    5396 }
    5397 
    5398 #endif // #ifdef VMA_IMPLEMENTATION
    VmaMemoryRequirementFlagBits
    Flags to be passed as VmaMemoryRequirements::flags.
    Definition: vk_mem_alloc.h:336
    +
    Set this flag if the allocation should have its own memory block.
    Definition: vk_mem_alloc.h:345
    +
    struct VmaMemoryRequirements VmaMemoryRequirements
    +
    VkPhysicalDevice physicalDevice
    Vulkan physical device.
    Definition: vk_mem_alloc.h:214
    +
    VkResult vmaCreateBuffer(VmaAllocator allocator, const VkBufferCreateInfo *pCreateInfo, const VmaMemoryRequirements *pMemoryRequirements, VkBuffer *pBuffer, VmaAllocation *pAllocation, VmaAllocationInfo *pAllocationInfo)
    +
    Memory will be used for writing on device and readback on host.
    Definition: vk_mem_alloc.h:331
    +
    VmaMemoryUsage usage
    Intended usage of memory.
    Definition: vk_mem_alloc.h:374
    +
    VkDeviceMemory deviceMemory
    Handle to Vulkan memory object.
    Definition: vk_mem_alloc.h:431
    +
    uint32_t maxAllocationsToMove
    Maximum number of allocations that can be moved to different place.
    Definition: vk_mem_alloc.h:561
    +
    void vmaGetAllocationInfo(VmaAllocator allocator, VmaAllocation allocation, VmaAllocationInfo *pAllocationInfo)
    Returns current information about specified allocation.
    +
    void vmaUnmapPersistentlyMappedMemory(VmaAllocator allocator)
    Unmaps persistently mapped memory of types that is HOST_COHERENT and DEVICE_LOCAL.
    +
    void vmaDestroyImage(VmaAllocator allocator, VkImage image, VmaAllocation allocation)
    +
    struct VmaDefragmentationInfo VmaDefragmentationInfo
    Optional configuration parameters to be passed to function vmaDefragment().
    +
    void(VKAPI_PTR * PFN_vmaFreeDeviceMemoryFunction)(VmaAllocator allocator, uint32_t memoryType, VkDeviceMemory memory, VkDeviceSize size)
    Callback function called before vkFreeMemory.
    Definition: vk_mem_alloc.h:177
    +
    const VkAllocationCallbacks * pAllocationCallbacks
    Custom allocation callbacks.
    Definition: vk_mem_alloc.h:226
    +
    VkResult vmaAllocateMemoryForBuffer(VmaAllocator allocator, VkBuffer buffer, const VmaMemoryRequirements *pMemoryRequirements, VmaAllocation *pAllocation, VmaAllocationInfo *pAllocationInfo)
    +
    Description of a Allocator to be created.
    Definition: vk_mem_alloc.h:208
    +
    VkDeviceSize preferredSmallHeapBlockSize
    Size of a single memory block to allocate for resources from a small heap <= 512 MB.
    Definition: vk_mem_alloc.h:223
    +
    VmaMemoryRequirementFlags flags
    Definition: vk_mem_alloc.h:369
    +
    VkFlags VmaAllocatorFlags
    Definition: vk_mem_alloc.h:205
    +
    Statistics returned by function vmaDefragment().
    Definition: vk_mem_alloc.h:565
    +
    VmaStatInfo total
    Definition: vk_mem_alloc.h:284
    +
    uint32_t deviceMemoryBlocksFreed
    Number of empty VkDeviceMemory objects that have been released to the system.
    Definition: vk_mem_alloc.h:573
    +
    VkDeviceSize maxBytesToMove
    Maximum total numbers of bytes that can be copied while moving allocations to different places...
    Definition: vk_mem_alloc.h:556
    +
    VkDevice device
    Vulkan device.
    Definition: vk_mem_alloc.h:217
    +
    VkDeviceSize size
    Size of this allocation, in bytes.
    Definition: vk_mem_alloc.h:441
    +
    void vmaFreeMemory(VmaAllocator allocator, VmaAllocation allocation)
    Frees memory previously allocated using vmaAllocateMemory(), vmaAllocateMemoryForBuffer(), or vmaAllocateMemoryForImage().
    +
    Set this flag to only try to allocate from existing VkDeviceMemory blocks and never create new such b...
    Definition: vk_mem_alloc.h:354
    void vmaBuildStatsString(VmaAllocator allocator, char **ppStatsString, VkBool32 detailedMap)
    Builds and returns statistics as string in JSON format.
    -
    void vmaDestroyBuffer(VmaAllocator allocator, VkBuffer buffer)
    -
    VkResult vmaCreateImage(VmaAllocator allocator, const VkImageCreateInfo *pCreateInfo, const VmaMemoryRequirements *pMemoryRequirements, VkImage *pImage, VkMappedMemoryRange *pMemory, uint32_t *pMemoryTypeIndex)
    Function similar to vmaCreateBuffer().
    -
    General statistics from current state of Allocator.
    Definition: vk_mem_alloc.h:232
    +
    Optional configuration parameters to be passed to function vmaDefragment().
    Definition: vk_mem_alloc.h:551
    +
    VkDeviceSize bytesFreed
    Total number of bytes that have been released to the system by freeing empty VkDeviceMemory objects...
    Definition: vk_mem_alloc.h:569
    +
    Definition: vk_mem_alloc.h:363
    +
    void * pUserData
    Custom general-purpose pointer that will be stored in VmaAllocation, can be read as VmaAllocationInfo...
    Definition: vk_mem_alloc.h:385
    +
    General statistics from current state of Allocator.
    Definition: vk_mem_alloc.h:280
    VkResult vmaCreateAllocator(const VmaAllocatorCreateInfo *pCreateInfo, VmaAllocator *pAllocator)
    Creates Allocator object.
    -
    VkMemoryPropertyFlags preferredFlags
    Flags that preferably should be set in a Memory Type chosen for an allocation.
    Definition: vk_mem_alloc.h:310
    -
    VmaMemoryUsage
    Definition: vk_mem_alloc.h:271
    +
    VkMemoryPropertyFlags preferredFlags
    Flags that preferably should be set in a Memory Type chosen for an allocation.
    Definition: vk_mem_alloc.h:383
    +
    uint32_t allocationsMoved
    Number of allocations that have been moved to different places.
    Definition: vk_mem_alloc.h:571
    +
    VmaMemoryUsage
    Definition: vk_mem_alloc.h:317
    void vmaDestroyAllocator(VmaAllocator allocator)
    Destroys allocator object.
    -
    VkResult vmaCreateBuffer(VmaAllocator allocator, const VkBufferCreateInfo *pCreateInfo, const VmaMemoryRequirements *pMemoryRequirements, VkBuffer *pBuffer, VkMappedMemoryRange *pMemory, uint32_t *pMemoryTypeIndex)
    +
    Allocator and all objects created from it will not be synchronized internally, so you must guarantee ...
    Definition: vk_mem_alloc.h:201
    void vmaCalculateStats(VmaAllocator allocator, VmaStats *pStats)
    Retrieves statistics from current state of the Allocator.
    -
    Definition: vk_mem_alloc.h:220
    -
    VkMemoryPropertyFlags requiredFlags
    Flags that must be set in a Memory Type chosen for an allocation.
    Definition: vk_mem_alloc.h:305
    -
    Definition: vk_mem_alloc.h:286
    -
    VkBool32 neverAllocate
    Set this flag to only try to allocate from existing VkDeviceMemory blocks and never create new such b...
    Definition: vk_mem_alloc.h:317
    -
    VkDeviceSize UnusedRangeSizeMax
    Definition: vk_mem_alloc.h:228
    -
    VkDeviceSize SuballocationSizeMax
    Definition: vk_mem_alloc.h:227
    +
    VmaAllocatorFlagBits
    Flags for created VmaAllocator.
    Definition: vk_mem_alloc.h:196
    +
    void vmaSetAllocationUserData(VmaAllocator allocator, VmaAllocation allocation, void *pUserData)
    Sets pUserData in given allocation to new value.
    +
    Definition: vk_mem_alloc.h:268
    +
    Set of callbacks that the library will call for vkAllocateMemory and vkFreeMemory.
    Definition: vk_mem_alloc.h:188
    +
    VkMemoryPropertyFlags requiredFlags
    Flags that must be set in a Memory Type chosen for an allocation.
    Definition: vk_mem_alloc.h:378
    +
    Definition: vk_mem_alloc.h:367
    +
    PFN_vmaFreeDeviceMemoryFunction pfnFree
    Optional, can be null.
    Definition: vk_mem_alloc.h:192
    +
    VkResult vmaMapPersistentlyMappedMemory(VmaAllocator allocator)
    Maps back persistently mapped memory of types that is HOST_COHERENT and DEVICE_LOCAL.
    +
    VkFlags VmaMemoryRequirementFlags
    Definition: vk_mem_alloc.h:365
    +
    VkDeviceSize UnusedRangeSizeMax
    Definition: vk_mem_alloc.h:276
    +
    VkDeviceSize SuballocationSizeMax
    Definition: vk_mem_alloc.h:275
    struct VmaAllocatorCreateInfo VmaAllocatorCreateInfo
    Description of a Allocator to be created.
    -
    VkBool32 ownMemory
    Set to true if this allocation should have its own memory block.
    Definition: vk_mem_alloc.h:296
    -
    VmaStatInfo memoryType[VK_MAX_MEMORY_TYPES]
    Definition: vk_mem_alloc.h:234
    -
    void vmaDestroyImage(VmaAllocator allocator, VkImage image)
    -
    uint32_t AllocationCount
    Definition: vk_mem_alloc.h:222
    +
    void(VKAPI_PTR * PFN_vmaAllocateDeviceMemoryFunction)(VmaAllocator allocator, uint32_t memoryType, VkDeviceMemory memory, VkDeviceSize size)
    Callback function called after successful vkAllocateMemory.
    Definition: vk_mem_alloc.h:171
    +
    VkResult vmaAllocateMemory(VmaAllocator allocator, const VkMemoryRequirements *pVkMemoryRequirements, const VmaMemoryRequirements *pVmaMemoryRequirements, VmaAllocation *pAllocation, VmaAllocationInfo *pAllocationInfo)
    General purpose memory allocation.
    +
    const VmaDeviceMemoryCallbacks * pDeviceMemoryCallbacks
    Informative callbacks for vkAllocateMemory, vkFreeMemory.
    Definition: vk_mem_alloc.h:229
    +
    VmaStatInfo memoryType[VK_MAX_MEMORY_TYPES]
    Definition: vk_mem_alloc.h:282
    +
    uint32_t AllocationCount
    Definition: vk_mem_alloc.h:270
    +
    VkResult vmaMapMemory(VmaAllocator allocator, VmaAllocation allocation, void **ppData)
    +
    PFN_vmaAllocateDeviceMemoryFunction pfnAllocate
    Optional, can be null.
    Definition: vk_mem_alloc.h:190
    +
    VmaAllocatorFlags flags
    Flags for created allocator. Use VmaAllocatorFlagBits enum.
    Definition: vk_mem_alloc.h:211
    void vmaGetPhysicalDeviceProperties(VmaAllocator allocator, const VkPhysicalDeviceProperties **ppPhysicalDeviceProperties)
    -
    VkDeviceSize UsedBytes
    Definition: vk_mem_alloc.h:225
    -
    VkDeviceSize preferredLargeHeapBlockSize
    Size of a single memory block to allocate for resources.
    Definition: vk_mem_alloc.h:175
    -
    uint32_t UnusedRangeCount
    Definition: vk_mem_alloc.h:224
    -
    Memory will be mapped on host. Could be used for transfer to device.
    Definition: vk_mem_alloc.h:278
    +
    VkDeviceSize UsedBytes
    Definition: vk_mem_alloc.h:273
    +
    void * pUserData
    Custom general-purpose pointer that was passed as VmaMemoryRequirements::pUserData or set using vmaSe...
    Definition: vk_mem_alloc.h:452
    +
    VkDeviceSize preferredLargeHeapBlockSize
    Size of a single memory block to allocate for resources.
    Definition: vk_mem_alloc.h:220
    +
    VkResult vmaAllocateMemoryForImage(VmaAllocator allocator, VkImage image, const VmaMemoryRequirements *pMemoryRequirements, VmaAllocation *pAllocation, VmaAllocationInfo *pAllocationInfo)
    Function similar to vmaAllocateMemoryForBuffer().
    +
    uint32_t UnusedRangeCount
    Definition: vk_mem_alloc.h:272
    +
    Memory will be mapped on host. Could be used for transfer to device.
    Definition: vk_mem_alloc.h:325
    void vmaGetMemoryProperties(VmaAllocator allocator, const VkPhysicalDeviceMemoryProperties **ppPhysicalDeviceMemoryProperties)
    -
    uint32_t SuballocationCount
    Definition: vk_mem_alloc.h:223
    -
    VkDeviceSize UnusedRangeSizeAvg
    Definition: vk_mem_alloc.h:228
    -
    VkDeviceSize SuballocationSizeMin
    Definition: vk_mem_alloc.h:227
    -
    VkResult vmaAllocateMemoryForBuffer(VmaAllocator allocator, VkBuffer buffer, const VmaMemoryRequirements *pMemoryRequirements, VkMappedMemoryRange *pMemory, uint32_t *pMemoryTypeIndex)
    -
    VkDeviceSize SuballocationSizeAvg
    Definition: vk_mem_alloc.h:227
    +
    uint32_t SuballocationCount
    Definition: vk_mem_alloc.h:271
    +
    VkDeviceSize UnusedRangeSizeAvg
    Definition: vk_mem_alloc.h:276
    +
    VkDeviceSize offset
    Offset into deviceMemory object to the beginning of this allocation, in bytes. (deviceMemory, offset) pair is unique to this allocation.
    Definition: vk_mem_alloc.h:436
    +
    VkDeviceSize bytesMoved
    Total number of bytes that have been copied while moving allocations to different places...
    Definition: vk_mem_alloc.h:567
    +
    VkResult vmaDefragment(VmaAllocator allocator, VmaAllocation *pAllocations, size_t allocationCount, VkBool32 *pAllocationsChanged, const VmaDefragmentationInfo *pDefragmentationInfo, VmaDefragmentationStats *pDefragmentationStats)
    Compacts memory by moving allocations.
    +
    struct VmaDeviceMemoryCallbacks VmaDeviceMemoryCallbacks
    Set of callbacks that the library will call for vkAllocateMemory and vkFreeMemory.
    +
    VkDeviceSize SuballocationSizeMin
    Definition: vk_mem_alloc.h:275
    +
    VkResult vmaCreateImage(VmaAllocator allocator, const VkImageCreateInfo *pCreateInfo, const VmaMemoryRequirements *pMemoryRequirements, VkImage *pImage, VmaAllocation *pAllocation, VmaAllocationInfo *pAllocationInfo)
    Function similar to vmaCreateBuffer().
    +
    void * pMappedData
    Pointer to the beginning of this allocation as mapped data. Null if this alloaction is not persistent...
    Definition: vk_mem_alloc.h:447
    +
    VkDeviceSize SuballocationSizeAvg
    Definition: vk_mem_alloc.h:275
    void vmaFreeStatsString(VmaAllocator allocator, char *pStatsString)
    -
    No intended memory usage specified.
    Definition: vk_mem_alloc.h:274
    -
    Definition: vk_mem_alloc.h:283
    -
    Memory will be used for frequent (dynamic) updates from host and reads on device. ...
    Definition: vk_mem_alloc.h:280
    +
    Set to use a memory that will be persistently mapped and retrieve pointer to it.
    Definition: vk_mem_alloc.h:361
    +
    No intended memory usage specified.
    Definition: vk_mem_alloc.h:320
    +
    Definition: vk_mem_alloc.h:332
    +
    Parameters of VmaAllocation objects, that can be retrieved using function vmaGetAllocationInfo().
    Definition: vk_mem_alloc.h:419
    +
    Memory will be used for frequent (dynamic) updates from host and reads on device. ...
    Definition: vk_mem_alloc.h:328
    +
    Definition: vk_mem_alloc.h:203
    +
    struct VmaAllocationInfo VmaAllocationInfo
    Parameters of VmaAllocation objects, that can be retrieved using function vmaGetAllocationInfo().
    void vmaGetMemoryTypeProperties(VmaAllocator allocator, uint32_t memoryTypeIndex, VkMemoryPropertyFlags *pFlags)
    Given Memory Type Index, returns Property Flags of this memory type.
    -
    Memory will be used on device only, no need to be mapped on host.
    Definition: vk_mem_alloc.h:276
    +
    Memory will be used on device only, no need to be mapped on host.
    Definition: vk_mem_alloc.h:322
    struct VmaStatInfo VmaStatInfo
    -
    VkDeviceSize UnusedBytes
    Definition: vk_mem_alloc.h:226
    -
    VmaStatInfo memoryHeap[VK_MAX_MEMORY_HEAPS]
    Definition: vk_mem_alloc.h:235
    +
    VkDeviceSize UnusedBytes
    Definition: vk_mem_alloc.h:274
    +
    void vmaUnmapMemory(VmaAllocator allocator, VmaAllocation allocation)
    +
    VmaStatInfo memoryHeap[VK_MAX_MEMORY_HEAPS]
    Definition: vk_mem_alloc.h:283
    VkResult vmaFindMemoryTypeIndex(VmaAllocator allocator, uint32_t memoryTypeBits, const VmaMemoryRequirements *pMemoryRequirements, uint32_t *pMemoryTypeIndex)
    -
    void vmaFreeMemory(VmaAllocator allocator, const VkMappedMemoryRange *pMemory)
    Frees memory previously allocated using vmaAllocateMemoryForBuffer() or vmaAllocateMemoryForImage().
    -
    VkDeviceSize UnusedRangeSizeMin
    Definition: vk_mem_alloc.h:228
    +
    struct VmaDefragmentationStats VmaDefragmentationStats
    Statistics returned by function vmaDefragment().
    +
    void vmaDestroyBuffer(VmaAllocator allocator, VkBuffer buffer, VmaAllocation allocation)
    +
    VkDeviceSize UnusedRangeSizeMin
    Definition: vk_mem_alloc.h:276
    +
    uint32_t memoryType
    Memory type index that this allocation was allocated from.
    Definition: vk_mem_alloc.h:424