cpp-vulkan-setup/src/UniformBuffers.cpp

104 lines
4.1 KiB
C++

#include "UniformBuffers.h"
#include "VertexUniformBufferObject.h"
#include <QVulkanDeviceFunctions>
/// 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<int32_t>(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();
}