From b634908e355e6f3bc4042993eaa85129a1d4502e Mon Sep 17 00:00:00 2001 From: Alexander Solovets Date: Sun, 17 May 2026 08:53:49 +1000 Subject: [PATCH] Fix Device::availableMemory crash on Vulkan 1.0 instances vkGetPhysicalDeviceMemoryProperties2 and VkPhysicalDeviceMemoryBudgetPropertiesEXT were called unconditionally, but the former requires Vulkan 1.1 and the latter requires VK_EXT_memory_budget. On a 1.0 instance this triggered undefined behaviour and crashed Lavapipe during scene compilation. Cache the combined precondition as a Device::memory_budget bool, and fall back to vkGetPhysicalDeviceMemoryProperties with heap sizes when it is unset. --- include/vsg/vk/Device.h | 3 +++ src/vsg/vk/Device.cpp | 34 ++++++++++++++++++++++++---------- 2 files changed, 27 insertions(+), 10 deletions(-) diff --git a/include/vsg/vk/Device.h b/include/vsg/vk/Device.h index 92b97bfce..30d9cee4f 100644 --- a/include/vsg/vk/Device.h +++ b/include/vsg/vk/Device.h @@ -85,6 +85,9 @@ namespace vsg /// return true if Device was created with specified extension bool supportsDeviceExtension(const char* extensionName) const; + /// commonly checked extensions cached at construction + const bool memory_budget = false; // VK_EXT_memory_budget usable on this Device + /// return the amount of remaining memory, compatible with specified flags, available that can be allocated. VkDeviceSize availableMemory(VkMemoryPropertyFlags memoryPropertiesFlags, double allocatedMemoryLimit = 1.0) const; diff --git a/src/vsg/vk/Device.cpp b/src/vsg/vk/Device.cpp index 9fe862597..0ba7420a2 100644 --- a/src/vsg/vk/Device.cpp +++ b/src/vsg/vk/Device.cpp @@ -163,6 +163,11 @@ Device::Device(PhysicalDevice* physicalDevice, const QueueSettings& queueSetting } _extensions = DeviceExtensions::create(this); + + // Cache extension/version probes used on hot paths. VK_EXT_memory_budget piggy-backs on + // vkGetPhysicalDeviceMemoryProperties2 which requires Vulkan 1.1 (or the KHR variant). + const_cast(memory_budget) = supportsApiVersion(VK_API_VERSION_1_1) && + supportsDeviceExtension(VK_EXT_MEMORY_BUDGET_EXTENSION_NAME); } Device::~Device() @@ -208,17 +213,24 @@ bool Device::supportsDeviceExtension(const char* extensionName) const VkDeviceSize Device::availableMemory(VkMemoryPropertyFlags memoryPropertiesFlags, double allocatedMemoryLimit) const { - VkPhysicalDeviceMemoryBudgetPropertiesEXT memoryBudget; - memoryBudget.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_BUDGET_PROPERTIES_EXT; - memoryBudget.pNext = nullptr; + VkPhysicalDeviceMemoryProperties memoryProperties; + VkPhysicalDeviceMemoryBudgetPropertiesEXT memoryBudget = {}; - VkPhysicalDeviceMemoryProperties2 dmp; - dmp.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_PROPERTIES_2; - dmp.pNext = &memoryBudget; + if (memory_budget) + { + memoryBudget.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_BUDGET_PROPERTIES_EXT; - vkGetPhysicalDeviceMemoryProperties2(*(getPhysicalDevice()), &dmp); + VkPhysicalDeviceMemoryProperties2 dmp = {}; + dmp.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_PROPERTIES_2; + dmp.pNext = &memoryBudget; - auto& memoryProperties = dmp.memoryProperties; + vkGetPhysicalDeviceMemoryProperties2(*(getPhysicalDevice()), &dmp); + memoryProperties = dmp.memoryProperties; + } + else + { + vkGetPhysicalDeviceMemoryProperties(*(getPhysicalDevice()), &memoryProperties); + } VkDeviceSize availableSpace = 0; for (uint32_t i = 0; i < memoryProperties.memoryTypeCount; ++i) @@ -227,8 +239,10 @@ VkDeviceSize Device::availableMemory(VkMemoryPropertyFlags memoryPropertiesFlags { uint32_t heapIndex = memoryProperties.memoryTypes[i].heapIndex; - VkDeviceSize heapBudget = static_cast(static_cast(memoryBudget.heapBudget[heapIndex]) * allocatedMemoryLimit); - VkDeviceSize heapUsage = memoryBudget.heapUsage[heapIndex]; + VkDeviceSize heapBudget = memory_budget ? memoryBudget.heapBudget[heapIndex] : memoryProperties.memoryHeaps[heapIndex].size; + VkDeviceSize heapUsage = memory_budget ? memoryBudget.heapUsage[heapIndex] : 0; + + heapBudget = static_cast(static_cast(heapBudget) * allocatedMemoryLimit); VkDeviceSize heapAvailable = (heapUsage < heapBudget) ? heapBudget - heapUsage : 0; availableSpace += heapAvailable;