#include "UniformBuffers.h" #include "VertexUniformBufferObject.h" #include /// Find a memory in `memoryTypeBitsRequirement` that includes all of /// `requiredProperties` see /// https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceMemoryProperties.html int32_t findProperties(const VkPhysicalDeviceMemoryProperties *pMemoryProperties, uint32_t memoryTypeBitsRequirement, VkMemoryPropertyFlags requiredProperties) { const uint32_t memoryCount = pMemoryProperties->memoryTypeCount; for (uint32_t memoryIndex = 0; memoryIndex < memoryCount; ++memoryIndex) { const uint32_t memoryTypeBits = (1 << memoryIndex); const bool isRequiredMemoryType = memoryTypeBitsRequirement & memoryTypeBits; const VkMemoryPropertyFlags properties = pMemoryProperties->memoryTypes[memoryIndex].propertyFlags; const bool hasRequiredProperties = (properties & requiredProperties) == requiredProperties; if (isRequiredMemoryType && hasRequiredProperties) return static_cast(memoryIndex); } // failed to find memory type return -1; } void UniformBuffers::createBuffers(QVulkanWindow *window, QVulkanDeviceFunctions *devFuncs) { VkResult result; VkDeviceSize bufferSize = sizeof(VertexUniformBufferObject); int swapChainImageCount = window->swapChainImageCount(); if (!m_uniformBuffers.empty() || !m_uniformBuffersMemory.empty()) { qFatal("Uniform buffers are allocated! Old buffers need to be destroyed."); } m_uniformBuffers.resize(swapChainImageCount); m_uniformBuffersMemory.resize(swapChainImageCount); VkBufferCreateInfo bufferCreateInfo{}; bufferCreateInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; bufferCreateInfo.size = bufferSize; bufferCreateInfo.usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT; bufferCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; QVulkanFunctions *pFunctions = window->vulkanInstance()->functions(); VkPhysicalDeviceMemoryProperties memProperties; pFunctions->vkGetPhysicalDeviceMemoryProperties(window->physicalDevice(), &memProperties); for (size_t i = 0; i < swapChainImageCount; i++) { result = devFuncs->vkCreateBuffer(window->device(), &bufferCreateInfo, VK_NULL_HANDLE, &m_uniformBuffers[i]); if (result != VK_SUCCESS) { qFatal("Failed to create buffer, code %d", result); } VkMemoryRequirements memRequirements; devFuncs->vkGetBufferMemoryRequirements( window->device(), m_uniformBuffers[i], &memRequirements); VkMemoryAllocateInfo allocInfo{}; allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; allocInfo.allocationSize = memRequirements.size; uint32_t requiredProperties{VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT}; allocInfo.memoryTypeIndex = findProperties( &memProperties, memRequirements.memoryTypeBits, requiredProperties); if (allocInfo.memoryTypeIndex == -1) { qFatal("Unable to find memory type with props %d", requiredProperties); } result = devFuncs->vkAllocateMemory(window->device(), &allocInfo, VK_NULL_HANDLE, &m_uniformBuffersMemory[i]); if (result != VK_SUCCESS) { qFatal("Failed to allocate buffer memory, code %d", result); } result = devFuncs->vkBindBufferMemory(window->device(), m_uniformBuffers[i], m_uniformBuffersMemory[i], 0); if (result != VK_SUCCESS) { qFatal("Failed to bind buffer memory, code %d", result); } } } void UniformBuffers::destroyBuffers(QVulkanWindow *window, QVulkanDeviceFunctions *devFuncs) { for (VkBuffer &buffer : m_uniformBuffers) { devFuncs->vkDestroyBuffer(window->device(), buffer, VK_NULL_HANDLE); } m_uniformBuffers.clear(); for (VkDeviceMemory &memory : m_uniformBuffersMemory) { devFuncs->vkFreeMemory(window->device(), memory, VK_NULL_HANDLE); } m_uniformBuffersMemory.clear(); }