Add support for buffer device address, together with documentation and tests

Added VMA_ALLOCATOR_CREATE_BUFFER_DEVICE_ADDRESS_BIT.
diff --git a/src/VulkanSample.cpp b/src/VulkanSample.cpp
index ccab048..e393877 100644
--- a/src/VulkanSample.cpp
+++ b/src/VulkanSample.cpp
@@ -53,7 +53,13 @@
 bool VK_KHR_bind_memory2_enabled = false;

 bool VK_EXT_memory_budget_enabled = false;

 bool VK_AMD_device_coherent_memory_enabled = false;

+bool VK_EXT_buffer_device_address_enabled = false;

+bool VK_KHR_buffer_device_address_enabled = false;

 bool g_SparseBindingEnabled = false;

+bool g_BufferDeviceAddressEnabled = false;

+

+// # Pointers to functions from extensions

+PFN_vkGetBufferDeviceAddressEXT g_vkGetBufferDeviceAddressEXT;

 

 static HINSTANCE g_hAppInstance;

 static HWND g_hWnd;

@@ -594,16 +600,13 @@
     assert(g_pvkDebugReportMessageEXT);

     assert(g_pvkDestroyDebugReportCallbackEXT);

 

-    VkDebugReportCallbackCreateInfoEXT callbackCreateInfo;

-    callbackCreateInfo.sType = VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT;

-    callbackCreateInfo.pNext = nullptr;

+    VkDebugReportCallbackCreateInfoEXT callbackCreateInfo = { VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT };

     callbackCreateInfo.flags = //VK_DEBUG_REPORT_INFORMATION_BIT_EXT |

         VK_DEBUG_REPORT_ERROR_BIT_EXT |

         VK_DEBUG_REPORT_WARNING_BIT_EXT |

         VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT /*|

         VK_DEBUG_REPORT_DEBUG_BIT_EXT*/;

     callbackCreateInfo.pfnCallback = &MyDebugReportCallback;

-    callbackCreateInfo.pUserData   = nullptr;

 

     ERR_GUARD_VULKAN( g_pvkCreateDebugReportCallbackEXT(g_hVulkanInstance, &callbackCreateInfo, g_Allocs, &g_hCallback) );

 }

@@ -1134,6 +1137,7 @@
 {

     wprintf(L"Validation layer: %d\n", g_EnableValidationLayer ? 1 : 0);

     wprintf(L"Sparse binding: %d\n", g_SparseBindingEnabled ? 1 : 0);

+    wprintf(L"Buffer device address: %d\n", g_BufferDeviceAddressEnabled ? 1 : 0);

     if(GetVulkanApiVersion() == VK_API_VERSION_1_0)

     {

         wprintf(L"VK_KHR_get_memory_requirements2: %d\n", VK_KHR_get_memory_requirements2_enabled ? 1 : 0);

@@ -1143,6 +1147,8 @@
     }

     wprintf(L"VK_EXT_memory_budget: %d\n", VK_EXT_memory_budget_enabled ? 1 : 0);

     wprintf(L"VK_AMD_device_coherent_memory: %d\n", VK_AMD_device_coherent_memory_enabled ? 1 : 0);

+    wprintf(L"VK_KHR_buffer_device_address: %d\n", VK_KHR_buffer_device_address_enabled ? 1 : 0);

+    wprintf(L"VK_EXT_buffer_device_address: %d\n", VK_EXT_buffer_device_address_enabled ? 1 : 0);

 }

 

 void SetAllocatorCreateInfo(VmaAllocatorCreateInfo& outInfo)

@@ -1173,6 +1179,10 @@
     {

         outInfo.flags |= VMA_ALLOCATOR_CREATE_AMD_DEVICE_COHERENT_MEMORY_BIT;

     }

+    if(g_BufferDeviceAddressEnabled)

+    {

+        outInfo.flags |= VMA_ALLOCATOR_CREATE_BUFFER_DEVICE_ADDRESS_BIT;

+    }

 

     if(USE_CUSTOM_CPU_ALLOCATION_CALLBACKS)

     {

@@ -1306,7 +1316,7 @@
 

     g_hPhysicalDevice = physicalDevices[0];

 

-    // Query for extensions

+    // Query for device extensions

 

     uint32_t physicalDeviceExtensionPropertyCount = 0;

     ERR_GUARD_VULKAN( vkEnumerateDeviceExtensionProperties(g_hPhysicalDevice, nullptr, &physicalDeviceExtensionPropertyCount, nullptr) );

@@ -1347,8 +1357,25 @@
             VK_EXT_memory_budget_enabled = true;

         else if(strcmp(physicalDeviceExtensionProperties[i].extensionName, VK_AMD_DEVICE_COHERENT_MEMORY_EXTENSION_NAME) == 0)

             VK_AMD_device_coherent_memory_enabled = true;

+        else if(strcmp(physicalDeviceExtensionProperties[i].extensionName, VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME) == 0)

+        {

+            if(GetVulkanApiVersion() < VK_API_VERSION_1_2)

+            {

+                VK_KHR_buffer_device_address_enabled = true;

+            }

+        }

+        else if(strcmp(physicalDeviceExtensionProperties[i].extensionName, VK_EXT_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME) == 0)

+        {

+            if(GetVulkanApiVersion() < VK_API_VERSION_1_2)

+            {

+                VK_EXT_buffer_device_address_enabled = true;

+            }

+        }

     }

 

+    if(VK_EXT_buffer_device_address_enabled && VK_KHR_buffer_device_address_enabled)

+        VK_EXT_buffer_device_address_enabled = false;

+

     // Query for features

 

     VkPhysicalDeviceProperties physicalDeviceProperties = {};

@@ -1357,12 +1384,19 @@
     PrintPhysicalDeviceProperties(physicalDeviceProperties);

 

     VkPhysicalDeviceFeatures2 physicalDeviceFeatures = { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2 };

+    

     VkPhysicalDeviceCoherentMemoryFeaturesAMD physicalDeviceCoherentMemoryFeatures = { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COHERENT_MEMORY_FEATURES_AMD };

     if(VK_AMD_device_coherent_memory_enabled)

     {

-        physicalDeviceCoherentMemoryFeatures.pNext = physicalDeviceFeatures.pNext;

-        physicalDeviceFeatures.pNext = &physicalDeviceCoherentMemoryFeatures;

+        PnextChainPushFront(&physicalDeviceFeatures, &physicalDeviceCoherentMemoryFeatures);

     }

+    

+    VkPhysicalDeviceBufferDeviceAddressFeaturesEXT physicalDeviceBufferDeviceAddressFeatures = { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BUFFER_DEVICE_ADDRESS_FEATURES_EXT };

+    if(VK_KHR_buffer_device_address_enabled || VK_EXT_buffer_device_address_enabled || GetVulkanApiVersion() >= VK_API_VERSION_1_2)

+    {

+        PnextChainPushFront(&physicalDeviceFeatures, &physicalDeviceBufferDeviceAddressFeatures);

+    }

+

     vkGetPhysicalDeviceFeatures2(g_hPhysicalDevice, &physicalDeviceFeatures);

 

     g_SparseBindingEnabled = physicalDeviceFeatures.features.sparseBinding != 0;

@@ -1370,6 +1404,8 @@
     // The extension is supported as fake with no real support for this feature? Don't use it.

     if(VK_AMD_device_coherent_memory_enabled && !physicalDeviceCoherentMemoryFeatures.deviceCoherentMemory)

         VK_AMD_device_coherent_memory_enabled = false;

+    if(VK_KHR_buffer_device_address_enabled || VK_EXT_buffer_device_address_enabled || GetVulkanApiVersion() >= VK_API_VERSION_1_2)

+        g_BufferDeviceAddressEnabled = physicalDeviceBufferDeviceAddressFeatures.bufferDeviceAddress != VK_FALSE;

 

     // Find queue family index

 

@@ -1458,6 +1494,10 @@
         enabledDeviceExtensions.push_back(VK_EXT_MEMORY_BUDGET_EXTENSION_NAME);

     if(VK_AMD_device_coherent_memory_enabled)

         enabledDeviceExtensions.push_back(VK_AMD_DEVICE_COHERENT_MEMORY_EXTENSION_NAME);

+    if(VK_KHR_buffer_device_address_enabled)

+        enabledDeviceExtensions.push_back(VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME);

+    if(VK_EXT_buffer_device_address_enabled)

+        enabledDeviceExtensions.push_back(VK_EXT_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME);

 

     VkPhysicalDeviceFeatures2 deviceFeatures = { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2 };

     deviceFeatures.features.samplerAnisotropy = VK_TRUE;

@@ -1465,9 +1505,14 @@
 

     if(VK_AMD_device_coherent_memory_enabled)

     {

-        physicalDeviceCoherentMemoryFeatures.pNext = deviceFeatures.pNext;

-        deviceFeatures.pNext = &physicalDeviceCoherentMemoryFeatures;

         physicalDeviceCoherentMemoryFeatures.deviceCoherentMemory = VK_TRUE;

+        PnextChainPushBack(&deviceFeatures, &physicalDeviceCoherentMemoryFeatures);

+    }

+    if(g_BufferDeviceAddressEnabled)

+    {

+        physicalDeviceBufferDeviceAddressFeatures = { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BUFFER_DEVICE_ADDRESS_FEATURES_EXT };

+        physicalDeviceBufferDeviceAddressFeatures.bufferDeviceAddress = VK_TRUE;

+        PnextChainPushBack(&deviceFeatures, &physicalDeviceBufferDeviceAddressFeatures);

     }

 

     VkDeviceCreateInfo deviceCreateInfo = { VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO };

@@ -1481,6 +1526,51 @@
 

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

 

+    // Fetch pointers to extension functions

+    if(g_BufferDeviceAddressEnabled)

+    {

+        if(GetVulkanApiVersion() >= VK_API_VERSION_1_2)

+        {

+            g_vkGetBufferDeviceAddressEXT = (PFN_vkGetBufferDeviceAddressEXT)vkGetDeviceProcAddr(g_hDevice, "vkGetBufferDeviceAddress");

+            //assert(g_vkGetBufferDeviceAddressEXT != nullptr);

+            /*

+            For some reason this doesn't work, the pointer is NULL :( None of the below methods help.

+

+            Validation layers also report following error:

+            [ VUID-VkMemoryAllocateInfo-flags-03331 ] Object: VK_NULL_HANDLE (Type = 0) | If VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT_KHR is set, bufferDeviceAddress must be enabled. The Vulkan spec states: If VkMemoryAllocateFlagsInfo::flags includes VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT, the bufferDeviceAddress feature must be enabled (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkMemoryAllocateInfo-flags-03331)

+            Despite I'm posting VkPhysicalDeviceBufferDeviceAddressFeaturesEXT::bufferDeviceAddress = VK_TRUE in VkDeviceCreateInfo::pNext chain.

+

+            if(g_vkGetBufferDeviceAddressEXT == nullptr)

+            {

+                g_vkGetBufferDeviceAddressEXT = &vkGetBufferDeviceAddress; // Doesn't run, cannot find entry point...

+            }

+

+            if(g_vkGetBufferDeviceAddressEXT == nullptr)

+            {

+                g_vkGetBufferDeviceAddressEXT = (PFN_vkGetBufferDeviceAddressEXT)vkGetInstanceProcAddr(g_hVulkanInstance, "vkGetBufferDeviceAddress");

+            }

+            if(g_vkGetBufferDeviceAddressEXT == nullptr)

+            {

+                g_vkGetBufferDeviceAddressEXT = (PFN_vkGetBufferDeviceAddressEXT)vkGetDeviceProcAddr(g_hDevice, "vkGetBufferDeviceAddressKHR");

+            }

+            if(g_vkGetBufferDeviceAddressEXT == nullptr)

+            {

+                g_vkGetBufferDeviceAddressEXT = (PFN_vkGetBufferDeviceAddressEXT)vkGetDeviceProcAddr(g_hDevice, "vkGetBufferDeviceAddressEXT");

+            }

+            */

+        }

+        else if(VK_KHR_buffer_device_address_enabled)

+        {

+            g_vkGetBufferDeviceAddressEXT = (PFN_vkGetBufferDeviceAddressEXT)vkGetDeviceProcAddr(g_hDevice, "vkGetBufferDeviceAddressKHR");

+            assert(g_vkGetBufferDeviceAddressEXT != nullptr);

+        }

+        else if(VK_EXT_buffer_device_address_enabled)

+        {

+            g_vkGetBufferDeviceAddressEXT = (PFN_vkGetBufferDeviceAddressEXT)vkGetDeviceProcAddr(g_hDevice, "vkGetBufferDeviceAddressEXT");

+            assert(g_vkGetBufferDeviceAddressEXT != nullptr);

+        }

+    }

+

     // Create memory allocator

 

     VmaAllocatorCreateInfo allocatorInfo = {};