在Volk中使用Vulkan Memory Allocator创建VmaAllocator报错求助
我正尝试将Volk(Vulkan元加载器)与Vulkan Memory Allocator(VMA)配合使用,编译无错误,但运行时调用vmaCreateAllocator触发访问违例错误。
相关代码
void VulkApp::Init(PipelineFlags t_Conf, entt::registry& t_reg) { volkInitialize(); WindowProps props = {}; props.Height = 600; props.Width = 800; props.Title = "Engine"; currentWindow = EngWindow::Create(props); //Create all physical, logical, instance for vulkan Prepare(); VolkDeviceTable test; volkLoadDeviceTable(&test, m_LogicalDevice->GetVkDevice()); VmaAllocatorCreateInfo allocatorCreateInfo = {}; allocatorCreateInfo.vulkanApiVersion = VK_API_VERSION_1_2; allocatorCreateInfo.physicalDevice = m_PhysicalDevice->GetVkPhysicalDevice(); allocatorCreateInfo.device = m_LogicalDevice->GetVkDevice(); allocatorCreateInfo.instance = m_Instance->GetRawVkInstance(); allocatorCreateInfo.pVulkanFunctions = reinterpret_cast<const VmaVulkanFunctions*> (&test); VmaAllocator allocator; vmaCreateAllocator(&allocatorCreateInfo, &allocator); BuildRenderPipelines(t_Conf, t_reg); } void VulkApp::Prepare() { m_Instance = std::make_unique<VulkInst>(); volkLoadInstance(m_Instance->GetRawVkInstance()); currentWindow->CreateSurface(m_Instance->GetRawVkInstance(), &m_Surface); m_PhysicalDevice = std::make_unique<PhysicalDevice>(*m_Instance); m_LogicalDevice = std::make_unique<LogicalDevice>(*m_Instance, *m_PhysicalDevice, m_Surface); volkLoadDevice(m_LogicalDevice->GetVkDevice()); m_SwapChain = std::make_unique<SwapChain>(ChooseSwapExtent(), *m_LogicalDevice, *m_PhysicalDevice, m_Surface); GraphicsHelpers::CreateCommandPool(m_CommandPool, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT); //TODO: added Transient bit CreateFrameSyncResources(); /* Create Camera */ BuildSwapChainResources(); }
错误信息
Exception raised at 0x00007FFAB0CD836B (VkLayer_khronos_validation.dll) in My_Game.exe : 0xC0000005 : access violation reading location 0x0000000000000120.
错误停在vk_mem_alloc.h第14082行:
(*m_VulkanFunctions.vkGetPhysicalDeviceMemoryProperties)(m_PhysicalDevice, &m_MemProps);
程序已启用所有Vulkan验证功能,以下是排查思路:
核心问题:函数表类型不匹配
VolkDeviceTable仅包含Vulkan设备级函数指针,而vkGetPhysicalDeviceMemoryProperties是实例级函数,不在该表中。直接将VolkDeviceTable强转为VmaVulkanFunctions会导致实例级函数指针全部为空,调用时触发访问违例。正确填充VMA函数表的两种方式
- 手动合并实例与设备表:
- 创建
VolkInstanceTable并调用volkLoadInstanceTable加载实例级函数 - 创建
VmaVulkanFunctions结构体,将实例表和设备表的对应函数指针分别赋值到结构体的实例级、设备级字段中 - 将填充好的
VmaVulkanFunctions指针传给allocatorCreateInfo.pVulkanFunctions
- 创建
- 让VMA自动使用Volk全局加载:
如果你已经调用了volkLoadInstance和volkLoadDevice,Volk已经全局hook了Vulkan函数的加载逻辑。此时可以直接将allocatorCreateInfo.pVulkanFunctions设为nullptr,VMA会自动通过标准方式获取函数指针,而Volk会拦截这些调用并返回正确的加载后的指针。
- 手动合并实例与设备表:
验证函数指针有效性
在调用vmaCreateAllocator前,检查VmaVulkanFunctions中的vkGetPhysicalDeviceMemoryProperties等实例级函数指针是否不为空,为空则说明加载方式错误。排查句柄有效性
确认allocatorCreateInfo中的instance、physicalDevice、device都是有效的非空句柄,可通过打印句柄值或查看验证层日志确认。简化场景排查
暂时注释Prepare函数中SwapChain、CommandPool等无关资源的创建代码,只保留实例、物理设备、逻辑设备的初始化和Volk加载,再尝试创建VMA分配器,逐步排查是否有其他代码干扰了句柄或函数表。
内容的提问来源于stack exchange,提问作者miyoku

