104 lines
4.1 KiB
C++
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();
|
|
}
|