Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion Doxyfile
Original file line number Diff line number Diff line change
Expand Up @@ -2469,7 +2469,8 @@ PREDEFINED = VMA_CALL_PRE= \
VMA_EXTERNAL_MEMORY_WIN32=1 \
VMA_EXTERNAL_MEMORY=1 \
VMA_EXTENDS_VK_STRUCT= \
VMA_STATS_STRING_ENABLED=1
VMA_STATS_STRING_ENABLED=1 \
VOLK_HEADER_VERSION=304

# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this
# tag can be used to specify a list of macro names that should be expanded. The
Expand Down
162 changes: 159 additions & 3 deletions include/vk_mem_alloc.h
Original file line number Diff line number Diff line change
Expand Up @@ -1669,6 +1669,62 @@ typedef struct VmaVirtualAllocationInfo
@{
*/

#ifdef VOLK_HEADER_VERSION
/** \brief Fully initializes `pDstVulkanFunctions` structure with Vulkan functions needed by VMA
using [volk library](https://github.com/zeux/volk).

This function is defined in VMA header only if "volk.h" was included before it.

To use this function properly:

-# Initialize volk and Vulkan:
-# Call `volkInitialize()`
-# Create `VkInstance` object
-# Call `volkLoadInstance()`
-# Create `VkDevice` object
-# Call `volkLoadDevice()`
-# Fill in structure #VmaAllocatorCreateInfo, especially members:
- VmaAllocatorCreateInfo::device
- VmaAllocatorCreateInfo::vulkanApiVersion
- VmaAllocatorCreateInfo::flags - set appropriate flags for the Vulkan extensions you enabled
-# Create an instance of the #VmaVulkanFunctions structure.
-# Call vmaImportVulkanFunctionsFromVolk().
Parameter `pAllocatorCreateInfo` is read to find out which functions should be fetched for
appropriate Vulkan version and extensions.
Parameter `pDstVulkanFunctions` is filled with those function pointers, or null if not applicable.
-# Attach the #VmaVulkanFunctions structure to VmaAllocatorCreateInfo::pVulkanFunctions.
-# Call vmaCreateAllocator() to create the #VmaAllocator object.

Example:

\code
VmaAllocatorCreateInfo allocatorCreateInfo = {};
allocatorCreateInfo.physicalDevice = myPhysicalDevice;
allocatorCreateInfo.device = myDevice;
allocatorCreateInfo.instance = myInstance;
allocatorCreateInfo.vulkanApiVersion = VK_API_VERSION_1_3;
allocatorCreateInfo.flags = VMA_ALLOCATOR_CREATE_EXT_MEMORY_BUDGET_BIT |
VMA_ALLOCATOR_CREATE_EXT_MEMORY_PRIORITY_BIT |
VMA_ALLOCATOR_CREATE_KHR_EXTERNAL_MEMORY_WIN32_BIT;

VmaVulkanFunctions vulkanFunctions;
VkResult res = vmaImportVulkanFunctionsFromVolk(&allocatorCreateInfo, &vulkanFunctions);
// Check res...
allocatorCreateInfo.pVulkanFunctions = &vulkanFunctions;

VmaAllocator allocator;
res = vmaCreateAllocator(&allocatorCreateInfo, &allocator);
// Check res...
\endcode

Internally in this function, pointers to functions related to the entire Vulkan instance are fetched using global function definitions,
while pointers to functions related to the Vulkan device are fetched using `volkLoadDeviceTable()` for given `pAllocatorCreateInfo->device`.
*/
VMA_CALL_PRE VkResult VMA_CALL_POST vmaImportVulkanFunctionsFromVolk(
const VmaAllocatorCreateInfo* VMA_NOT_NULL pAllocatorCreateInfo,
VmaVulkanFunctions* VMA_NOT_NULL pDstVulkanFunctions);
#endif

/// Creates #VmaAllocator object.
VMA_CALL_PRE VkResult VMA_CALL_POST vmaCreateAllocator(
const VmaAllocatorCreateInfo* VMA_NOT_NULL pCreateInfo,
Expand Down Expand Up @@ -15082,6 +15138,103 @@ void VmaAllocator_T::PrintDetailedMap(VmaJsonWriter& json)


#ifndef _VMA_PUBLIC_INTERFACE

#ifdef VOLK_HEADER_VERSION

VMA_CALL_PRE VkResult VMA_CALL_POST vmaImportVulkanFunctionsFromVolk(
const VmaAllocatorCreateInfo* VMA_NOT_NULL pAllocatorCreateInfo,
VmaVulkanFunctions* VMA_NOT_NULL pDstVulkanFunctions)
{
VMA_ASSERT(pAllocatorCreateInfo != VMA_NULL);
VMA_ASSERT(pAllocatorCreateInfo->instance != VK_NULL_HANDLE);
VMA_ASSERT(pAllocatorCreateInfo->device != VK_NULL_HANDLE);

memset(pDstVulkanFunctions, 0, sizeof(*pDstVulkanFunctions));

VolkDeviceTable src = {};
volkLoadDeviceTable(&src, pAllocatorCreateInfo->device);

#define COPY_GLOBAL_TO_VMA_FUNC(volkName, vmaName) if(!pDstVulkanFunctions->vmaName) pDstVulkanFunctions->vmaName = volkName;
#define COPY_DEVICE_TO_VMA_FUNC(volkName, vmaName) if(!pDstVulkanFunctions->vmaName) pDstVulkanFunctions->vmaName = src.volkName;

COPY_GLOBAL_TO_VMA_FUNC(vkGetInstanceProcAddr, vkGetInstanceProcAddr)
COPY_GLOBAL_TO_VMA_FUNC(vkGetDeviceProcAddr, vkGetDeviceProcAddr)
COPY_GLOBAL_TO_VMA_FUNC(vkGetPhysicalDeviceProperties, vkGetPhysicalDeviceProperties)
COPY_GLOBAL_TO_VMA_FUNC(vkGetPhysicalDeviceMemoryProperties, vkGetPhysicalDeviceMemoryProperties)
COPY_DEVICE_TO_VMA_FUNC(vkAllocateMemory, vkAllocateMemory)
COPY_DEVICE_TO_VMA_FUNC(vkFreeMemory, vkFreeMemory)
COPY_DEVICE_TO_VMA_FUNC(vkMapMemory, vkMapMemory)
COPY_DEVICE_TO_VMA_FUNC(vkUnmapMemory, vkUnmapMemory)
COPY_DEVICE_TO_VMA_FUNC(vkFlushMappedMemoryRanges, vkFlushMappedMemoryRanges)
COPY_DEVICE_TO_VMA_FUNC(vkInvalidateMappedMemoryRanges, vkInvalidateMappedMemoryRanges)
COPY_DEVICE_TO_VMA_FUNC(vkBindBufferMemory, vkBindBufferMemory)
COPY_DEVICE_TO_VMA_FUNC(vkBindImageMemory, vkBindImageMemory)
COPY_DEVICE_TO_VMA_FUNC(vkGetBufferMemoryRequirements, vkGetBufferMemoryRequirements)
COPY_DEVICE_TO_VMA_FUNC(vkGetImageMemoryRequirements, vkGetImageMemoryRequirements)
COPY_DEVICE_TO_VMA_FUNC(vkCreateBuffer, vkCreateBuffer)
COPY_DEVICE_TO_VMA_FUNC(vkDestroyBuffer, vkDestroyBuffer)
COPY_DEVICE_TO_VMA_FUNC(vkCreateImage, vkCreateImage)
COPY_DEVICE_TO_VMA_FUNC(vkDestroyImage, vkDestroyImage)
COPY_DEVICE_TO_VMA_FUNC(vkCmdCopyBuffer, vkCmdCopyBuffer)
#if VMA_VULKAN_VERSION >= 1001000
if (pAllocatorCreateInfo->vulkanApiVersion >= VK_MAKE_VERSION(1, 1, 0))
{
COPY_GLOBAL_TO_VMA_FUNC(vkGetPhysicalDeviceMemoryProperties2, vkGetPhysicalDeviceMemoryProperties2KHR)
COPY_DEVICE_TO_VMA_FUNC(vkGetBufferMemoryRequirements2, vkGetBufferMemoryRequirements2KHR)
COPY_DEVICE_TO_VMA_FUNC(vkGetImageMemoryRequirements2, vkGetImageMemoryRequirements2KHR)
COPY_DEVICE_TO_VMA_FUNC(vkBindBufferMemory2, vkBindBufferMemory2KHR)
COPY_DEVICE_TO_VMA_FUNC(vkBindImageMemory2, vkBindImageMemory2KHR)
}
#endif
#if VMA_VULKAN_VERSION >= 1003000
if (pAllocatorCreateInfo->vulkanApiVersion >= VK_MAKE_VERSION(1, 3, 0))
{
COPY_DEVICE_TO_VMA_FUNC(vkGetDeviceBufferMemoryRequirements, vkGetDeviceBufferMemoryRequirements)
COPY_DEVICE_TO_VMA_FUNC(vkGetDeviceImageMemoryRequirements, vkGetDeviceImageMemoryRequirements)
}
#endif
#if VMA_KHR_MAINTENANCE4
if((pAllocatorCreateInfo->flags & VMA_ALLOCATOR_CREATE_KHR_MAINTENANCE4_BIT) != 0)
{
COPY_DEVICE_TO_VMA_FUNC(vkGetDeviceBufferMemoryRequirementsKHR, vkGetDeviceBufferMemoryRequirements)
COPY_DEVICE_TO_VMA_FUNC(vkGetDeviceImageMemoryRequirementsKHR, vkGetDeviceImageMemoryRequirements)
}
#endif
#if VMA_DEDICATED_ALLOCATION
if ((pAllocatorCreateInfo->flags & VMA_ALLOCATOR_CREATE_KHR_DEDICATED_ALLOCATION_BIT) != 0)
{
COPY_DEVICE_TO_VMA_FUNC(vkGetBufferMemoryRequirements2KHR, vkGetBufferMemoryRequirements2KHR)
COPY_DEVICE_TO_VMA_FUNC(vkGetImageMemoryRequirements2KHR, vkGetImageMemoryRequirements2KHR)
}
#endif
#if VMA_BIND_MEMORY2
if ((pAllocatorCreateInfo->flags & VMA_ALLOCATOR_CREATE_KHR_BIND_MEMORY2_BIT) != 0)
{
COPY_DEVICE_TO_VMA_FUNC(vkBindBufferMemory2KHR, vkBindBufferMemory2KHR)
COPY_DEVICE_TO_VMA_FUNC(vkBindImageMemory2KHR, vkBindImageMemory2KHR)
}
#endif
#if VMA_MEMORY_BUDGET
if ((pAllocatorCreateInfo->flags & VMA_ALLOCATOR_CREATE_EXT_MEMORY_BUDGET_BIT) != 0)
{
COPY_GLOBAL_TO_VMA_FUNC(vkGetPhysicalDeviceMemoryProperties2KHR, vkGetPhysicalDeviceMemoryProperties2KHR)
}
#endif
#if VMA_EXTERNAL_MEMORY_WIN32
if ((pAllocatorCreateInfo->flags & VMA_ALLOCATOR_CREATE_KHR_EXTERNAL_MEMORY_WIN32_BIT) != 0)
{
COPY_DEVICE_TO_VMA_FUNC(vkGetMemoryWin32HandleKHR, vkGetMemoryWin32HandleKHR)
}
#endif

#undef COPY_DEVICE_TO_VMA_FUNC
#undef COPY_GLOBAL_TO_VMA_FUNC

return VK_SUCCESS;
}

#endif // #ifdef VOLK_HEADER_VERSION

VMA_CALL_PRE VkResult VMA_CALL_POST vmaCreateAllocator(
const VmaAllocatorCreateInfo* pCreateInfo,
VmaAllocator* pAllocator)
Expand Down Expand Up @@ -16796,7 +16949,7 @@ See code sample below.

\subsection quick_start_initialization_importing_vulkan_functions Importing Vulkan functions

You may need to configure importing Vulkan functions. There are 3 ways to do this:
You may need to configure importing Vulkan functions. There are 4 ways to do this:

-# **If you link with Vulkan static library** (e.g. "vulkan-1.lib" on Windows):
- You don't need to do anything.
Expand All @@ -16807,10 +16960,13 @@ You may need to configure importing Vulkan functions. There are 3 ways to do thi
- Provide pointers to these two functions via VmaVulkanFunctions::vkGetInstanceProcAddr,
VmaVulkanFunctions::vkGetDeviceProcAddr.
- The library will fetch pointers to all other functions it needs internally.
-# **If you fetch pointers to all Vulkan functions in a custom way**, e.g. using some loader like
[Volk](https://github.com/zeux/volk):
-# **If you fetch pointers to all Vulkan functions in a custom way**:
- Define `VMA_STATIC_VULKAN_FUNCTIONS` and `VMA_DYNAMIC_VULKAN_FUNCTIONS` to 0.
- Pass these pointers via structure #VmaVulkanFunctions.
-# **If you use [volk library](https://github.com/zeux/volk)**:
- Define `VMA_STATIC_VULKAN_FUNCTIONS` and `VMA_DYNAMIC_VULKAN_FUNCTIONS` to 0.
- Use function vmaImportVulkanFunctionsFromVolk() to fill in the structure #VmaVulkanFunctions.
For more information, see the description of this function.

\subsection quick_start_initialization_enabling_extensions Enabling extensions

Expand Down
11 changes: 11 additions & 0 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@

option(VMA_STATIC_VULKAN_FUNCTIONS "Link statically with Vulkan API" ON)
option(VMA_DYNAMIC_VULKAN_FUNCTIONS "Fetch pointers to Vulkan functions internally (no static linking)" OFF)
set(VMA_VOLK_HEADER_PATH "" CACHE STRING "Path to volk.h file from the volk library (optional)")
option(VMA_DEBUG_ALWAYS_DEDICATED_MEMORY "Every allocation will have its own memory block" OFF)
option(VMA_DEBUG_INITIALIZE_ALLOCATIONS "Automatically fill new allocations and destroyed allocations with some bit pattern" OFF)
option(VMA_DEBUG_GLOBAL_MUTEX "Enable single mutex protecting all entry calls to the library" OFF)
Expand Down Expand Up @@ -50,6 +51,7 @@ target_sources(VmaSample PRIVATE
Tests.h
VmaUsage.cpp
VmaUsage.h
VolkUsage.cpp
VulkanSample.cpp
../include/vk_mem_alloc.h
)
Expand Down Expand Up @@ -78,6 +80,15 @@ target_sources(VmaSample PRIVATE vk_mem_alloc.natvis)
add_subdirectory(Shaders)
add_dependencies(VmaSample VmaSampleShaders)

if(NOT "${VMA_VOLK_HEADER_PATH}" STREQUAL "")
if(EXISTS "${VMA_VOLK_HEADER_PATH}")
message(STATUS "File volk.h found and used from path: ${VMA_VOLK_HEADER_PATH}")
target_compile_definitions(VmaSample PRIVATE VMA_VOLK_HEADER_PATH="${VMA_VOLK_HEADER_PATH}")
else()
message(FATAL_ERROR "File volk.h not found in path: ${VMA_VOLK_HEADER_PATH}")
endif()
endif()

# Use Unicode instead of multibyte set
add_compile_definitions(UNICODE _UNICODE)

Expand Down
5 changes: 5 additions & 0 deletions src/Tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3902,6 +3902,11 @@ void TestHeapSizeLimit()
allocatorCreateInfo.device = g_hDevice;
allocatorCreateInfo.instance = g_hVulkanInstance;
allocatorCreateInfo.pHeapSizeLimit = heapSizeLimit;
#ifdef VOLK_HEADER_VERSION
VmaVulkanFunctions vulkanFunctions = {};
vmaImportVulkanFunctionsFromVolk(&allocatorCreateInfo, &vulkanFunctions);
allocatorCreateInfo.pVulkanFunctions = &vulkanFunctions;
#endif
#if VMA_DYNAMIC_VULKAN_FUNCTIONS
VmaVulkanFunctions vulkanFunctions = {};
vulkanFunctions.vkGetInstanceProcAddr = vkGetInstanceProcAddr;
Expand Down
8 changes: 6 additions & 2 deletions src/VmaUsage.h
Original file line number Diff line number Diff line change
Expand Up @@ -96,10 +96,14 @@ include all public interface declarations. Example:
#pragma clang diagnostic ignored "-Wnullability-completeness"
#endif

#include <vulkan/vulkan.h>
#ifdef VMA_VOLK_HEADER_PATH
#include VMA_VOLK_HEADER_PATH
#else
#include <vulkan/vulkan.h>
#endif

#ifdef _WIN32
#include <vulkan/vulkan_win32.h>
#include <vulkan/vulkan_win32.h>
#endif // #ifdef _WIN32

#include "vk_mem_alloc.h"
Expand Down
28 changes: 28 additions & 0 deletions src/VolkUsage.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
//
// Copyright (c) 2017-2025 Advanced Micro Devices, Inc. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//

#ifdef VMA_VOLK_HEADER_PATH

#define VOLK_IMPLEMENTATION
#include "VmaUsage.h"

#endif // #ifdef VMA_VOLK_HEADER_PATH
21 changes: 20 additions & 1 deletion src/VulkanSample.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -426,6 +426,10 @@ void VulkanUsage::Init()
g_Allocs = &g_CpuAllocationCallbacks;
}

#ifdef VOLK_HEADER_VERSION
ERR_GUARD_VULKAN(volkInitialize());
#endif

uint32_t instanceLayerPropCount = 0;
ERR_GUARD_VULKAN( vkEnumerateInstanceLayerProperties(&instanceLayerPropCount, nullptr) );
std::vector<VkLayerProperties> instanceLayerProps(instanceLayerPropCount);
Expand Down Expand Up @@ -513,6 +517,10 @@ void VulkanUsage::Init()

ERR_GUARD_VULKAN( vkCreateInstance(&instInfo, g_Allocs, &g_hVulkanInstance) );

#ifdef VOLK_HEADER_VERSION
volkLoadInstance(g_hVulkanInstance);
#endif

if(VK_EXT_debug_utils_enabled)
{
RegisterDebugCallbacks();
Expand Down Expand Up @@ -1511,12 +1519,18 @@ void SetAllocatorCreateInfo(VmaAllocatorCreateInfo& outInfo)
outInfo.pAllocationCallbacks = &g_CpuAllocationCallbacks;
}

#ifdef VOLK_HEADER_VERSION
static VmaVulkanFunctions vulkanFunctions = {};
vmaImportVulkanFunctionsFromVolk(&outInfo, &vulkanFunctions);
outInfo.pVulkanFunctions = &vulkanFunctions;
#endif // #ifdef VOLK_HEADER_VERSION

#if VMA_DYNAMIC_VULKAN_FUNCTIONS
static VmaVulkanFunctions vulkanFunctions = {};
vulkanFunctions.vkGetInstanceProcAddr = vkGetInstanceProcAddr;
vulkanFunctions.vkGetDeviceProcAddr = vkGetDeviceProcAddr;
outInfo.pVulkanFunctions = &vulkanFunctions;
#endif
#endif // #if VMA_DYNAMIC_VULKAN_FUNCTIONS

// Uncomment to enable HeapSizeLimit.
/*
Expand Down Expand Up @@ -2083,6 +2097,11 @@ static void InitializeApplication()
deviceCreateInfo.pQueueCreateInfos = queueCreateInfo;

ERR_GUARD_VULKAN( vkCreateDevice(g_hPhysicalDevice, &deviceCreateInfo, g_Allocs, &g_hDevice) );

#ifdef VOLK_HEADER_VERSION
volkLoadDevice(g_hDevice);
#endif

SetDebugUtilsObjectName(VK_OBJECT_TYPE_DEVICE, reinterpret_cast<std::uint64_t>(g_hDevice), "g_hDevice");
// Only now that SetDebugUtilsObjectName is loaded, we can assign a name to g_hVulkanInstance as well
SetDebugUtilsObjectName(VK_OBJECT_TYPE_INSTANCE, reinterpret_cast<std::uint64_t>(g_hVulkanInstance), "g_hVulkanInstance");
Expand Down