Add uniform buffers

This commit is contained in:
Piotr Krygier committed 2023-03-08 14:36:30 +01:00
1 parent a94e7a95f5
commit cce4875329
3 files changed
+188 -19

No files matched your search

+9
View File
@@ -43,6 +43,9 @@ enum Errors
VULKAN_SHADER_UNABLE_TO_CREATE_SHADER,
VULKAN_PIPELAYOUT_CREATION_FAILED,
VULKAN_RENDERPASS_CREATION_FAILED,
VULKAN_DESCRIPTOR_POOL_CREATION_FAILED,
VULKAN_DESCRIPTOR_SETS_ALLOCATION_FAILED,
VULKAN_DESCRIPTORSETLAYOUT_CREATION_FAILED,
VULKAN_GRAPHICSPIPELINE_CREATION_FAILED,
VULKAN_FRAMEBUFFERS_CREATION_FAILED,
VULKAN_RECORD_COMMAND_BUFFER_FAILED,
@@ -90,6 +93,12 @@ std::array<std::array<const char*, LAST_MESSAGE>, LAST_LANGUAGE> vulkanErrorMess
"Failed to create pipeline layout",
/* VULKAN_RENDERPASS_CREATION_FAILED */
"Failed to create render pass",
/* VULKAN_DESCRIPTOR_POOL_CREATION_FAILED */
"Failed to create descriptor pool",
/* VULKAN_DESCRIPTOR_SETS_ALLOCATION_FAILED */
"Failed to allocate descriptor sets",
/* VULKAN_DESCRIPTORSETLAYOUT_CREATION_FAILED */
"Failed to create descriptor set layout",
/* VULKAN_GRAPHICSPIPELINE_CREATION_FAILED */
"Failed to create graphics pipeline",
/* VULKAN_FRAMEBUFFERS_CREATION_FAILED */
+7 -1
View File
@@ -1,11 +1,17 @@
#version 450
layout(binding = 0) uniform UniformBufferObject {
mat4 model;
mat4 view;
mat4 proj;
} ubo;
layout(location = 0) in vec2 inPosition;
layout(location = 1) in vec3 inColor;
layout(location = 0) out vec3 fragColor;
void main() {
gl_Position = vec4(inPosition, 0.0, 1.0);
gl_Position = ubo.proj * ubo.view * ubo.model * vec4(inPosition, 0.0, 1.0);
fragColor = inColor;
}
+172 -18
View File
@@ -34,7 +34,9 @@
#include "logger.hpp"
#include "window.hpp"
#define GLM_FORCE_RADIANS
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <vector>
#include <string>
@@ -82,6 +84,9 @@ enum VULKAN_ERROR
VULKAN_ERROR_SHADER_CREATION_FAILED,
VULKAN_ERROR_PIPELINE_LAYOUT_CREATION_FAILED,
VULKAN_ERROR_RENDERPASS_CREATION_FAILED,
VULKAN_ERROR_DESCRIPTOR_POOL_CREATION_FAILED,
VULKAN_ERROR_DESCRIPTOR_SETS_ALLOCATION_FAILED,
VULKAN_ERROR_DESCRIPTORSETLAYOUT_CREATION_FAILED,
VULKAN_ERROR_GRAPHICSPIPELINE_CREATION_FAILED,
VULKAN_ERROR_FRAMEBUFFERS_CREATION_FAILED,
VULKAN_ERROR_RECORD_COMMAND_BUFFER_FAILED,
@@ -131,6 +136,12 @@ struct Vertex
};
struct UniformBufferObject {
alignas(16) glm::mat4 model;
alignas(16) glm::mat4 view;
alignas(16) glm::mat4 proj;
};
/**
* @brief Wrapper for Vulan buffer. Holds allocation data;
*
@@ -207,7 +218,10 @@ VkExtent2D gSwapchainExtent;
std::vector<VkShaderModule> gShaderModules;
VkRenderPass gRenderPass = VK_NULL_HANDLE;
VkPipelineLayout gPipelineLayout = VK_NULL_HANDLE;
VkDescriptorSetLayout gDescriptorSetLayout = VK_NULL_HANDLE;
VkPipeline gGraphicsPipeline = VK_NULL_HANDLE;
VkDescriptorPool gDescriptorPool = {};
std::vector<VkDescriptorSet> gDescriptorSets = {};
std::vector<VkFramebuffer> gSwapchainFramebuffers = {};
std::vector<VkSemaphore> gImageAvailableSemaphores = {};
std::vector<VkSemaphore> gRenderFinishedSemaphores = {};
@@ -218,6 +232,9 @@ Buffer gVertexBuffer = {};
Buffer gVertexStagingBuffer = {};
Buffer gIndexBuffer = {};
Buffer gIndexStagingBuffer = {};
std::vector<Buffer> gUniformBuffers = {};
std::vector<void*> gUniformBuffersMappedMemory = {};
/**
* @brief Helper function. Creates a buffer object
@@ -316,6 +333,13 @@ static uint8_t createVertexBuffer();
*/
static uint8_t createIndexBuffer();
/**
* @brief Create a Uniform Buffers
*
* @return uint8_t VULKAN_ERROR_NO_ERROR on success. Possible errors:
*/
static uint8_t createUniformBuffers();
/**
* @brief Allocate Command Buffers
*
@@ -339,14 +363,6 @@ static uint8_t createSwapchain();
*/
static uint8_t createSwapchainImageViews();
/**
* @brief Creates shader stages from hardcoded shader paths. Changes input
*
* @return uint8_t VULKAN_ERROR_NO_ERROR on success. Possible errors:
* VULKAN_ERROR_SHADER_FILE_OPEN_FAILED
* VULKAN_ERROR_SHADER_CREATION_FAILED
*/
/**
* @brief Creates shader stages from hardcoded shader paths. Changes input
*
@@ -426,6 +442,13 @@ static uint8_t createRenderPass();
*/
static uint8_t createPipelineLayout();
/**
* @brief Create a Descriptor Set Layout
*
* @return uint8_t VULKAN_ERROR_NO_ERROR on success. Possible errors:
*/
static uint8_t createDescriptorSetLayout();
/**
* @brief Create Graphics Pipeline
*
@@ -630,7 +653,7 @@ static uint8_t createInstance()
/* Check if selected layers are supported*/
for (auto &layer : gEnabledInstanceLayersNames) {
if(std::find_if(layerProperties.begin(), layerProperties.end(), [&layer](const VkLayerProperties& lp) {
return strcmp(lp.layerName, layer);
return strcmp(lp.layerName, layer) == 0;
}) == std::end(layerProperties)) {
LOGF << vulkanErrorMesssages[VULKAN_LAYER_NOT_SUPPORTED] << layer;
return VULKAN_ERROR_LAYER_NOT_SUPPORTED;
@@ -640,7 +663,7 @@ static uint8_t createInstance()
/* Check if selected extensions are supported*/
for (auto &extension : gEnabledInstanceExtensionsNames) {
if(std::find_if(extensionsProperties.begin(), extensionsProperties.end(), [&extension](const VkExtensionProperties& ep) {
return strcmp(ep.extensionName, extension);
return strcmp(ep.extensionName, extension) == 0;
}) == std::end(extensionsProperties)) {
LOGF << vulkanErrorMesssages[VULKAN_EXTENSION_NOT_SUPPORTED] << extension;
return VULKAN_ERROR_EXTENSION_NOT_SUPPORTED;
@@ -711,7 +734,8 @@ static uint8_t pickPhysicalDevice()
vkGetPhysicalDeviceFeatures(pPhysicalDevices[physicalDeviceIdx], &deviceFeatures);
/* Expect discrete graphics device type */
if (deviceProperties.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU) {
if (deviceProperties.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU
|| deviceProperties.deviceType == VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU) {
/* Application MUST have geometry shader */
if (deviceFeatures.geometryShader) {
gPhysicalDevice = pPhysicalDevices[physicalDeviceIdx];
@@ -948,6 +972,84 @@ static uint8_t createIndexBuffer()
return VULKAN_ERROR_NO_ERROR;
}
static uint8_t createUniformBuffers()
{
VkDeviceSize bufferSize = sizeof(UniformBufferObject);
gUniformBuffers.resize(SWAP_BUFFER_COUNT);
gUniformBuffersMappedMemory.resize(SWAP_BUFFER_COUNT);
for (size_t i = 0; i < SWAP_BUFFER_COUNT; i++) {
createBuffer(bufferSize,
VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT,
VMA_MEMORY_USAGE_AUTO_PREFER_HOST,
VMA_ALLOCATION_CREATE_MAPPED_BIT | VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT,
gUniformBuffers[i]);
VmaAllocationInfo allocInfo;
vmaGetAllocationInfo(gAllocator, gUniformBuffers[i].allocation, &allocInfo);
gUniformBuffersMappedMemory[i] = allocInfo.pMappedData;
}
return VULKAN_ERROR_NO_ERROR;
}
static uint8_t createDescriptorPool()
{
VkDescriptorPoolSize poolSize{};
poolSize.type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
poolSize.descriptorCount = static_cast<uint32_t>(SWAP_BUFFER_COUNT);
VkDescriptorPoolCreateInfo poolInfo{};
poolInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
poolInfo.poolSizeCount = 1;
poolInfo.pPoolSizes = &poolSize;
poolInfo.maxSets = static_cast<uint32_t>(SWAP_BUFFER_COUNT);
if (vkCreateDescriptorPool(gDevice, &poolInfo, nullptr, &gDescriptorPool) != VK_SUCCESS) {
LOGF << vulkanErrorMesssages[VULKAN_DESCRIPTOR_POOL_CREATION_FAILED];
return VULKAN_ERROR_DESCRIPTOR_POOL_CREATION_FAILED;
}
return VULKAN_ERROR_NO_ERROR;
}
static uint8_t createDescriptorSets()
{
std::vector<VkDescriptorSetLayout> layouts(SWAP_BUFFER_COUNT, gDescriptorSetLayout);
VkDescriptorSetAllocateInfo allocInfo{};
allocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
allocInfo.descriptorPool = gDescriptorPool;
allocInfo.descriptorSetCount = static_cast<uint32_t>(SWAP_BUFFER_COUNT);
allocInfo.pSetLayouts = layouts.data();
gDescriptorSets.resize(SWAP_BUFFER_COUNT);
if (vkAllocateDescriptorSets(gDevice, &allocInfo, gDescriptorSets.data()) != VK_SUCCESS) {
LOGF << vulkanErrorMesssages[VULKAN_DESCRIPTOR_SETS_ALLOCATION_FAILED];
return VULKAN_ERROR_DESCRIPTOR_SETS_ALLOCATION_FAILED;
}
for (size_t i = 0; i < SWAP_BUFFER_COUNT; i++) {
VkDescriptorBufferInfo bufferInfo{};
bufferInfo.buffer = gUniformBuffers[i].buffer;
bufferInfo.offset = 0;
bufferInfo.range = sizeof(UniformBufferObject);
VkWriteDescriptorSet descriptorWrite{};
descriptorWrite.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
descriptorWrite.dstSet = gDescriptorSets[i];
descriptorWrite.dstBinding = 0;
descriptorWrite.dstArrayElement = 0;
descriptorWrite.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
descriptorWrite.descriptorCount = 1;
descriptorWrite.pBufferInfo = &bufferInfo;
vkUpdateDescriptorSets(gDevice, 1, &descriptorWrite, 0, nullptr);
}
return VULKAN_ERROR_NO_ERROR;
}
static uint8_t allocateCommandBuffers()
{
VkCommandBufferAllocateInfo allocateInfo;
@@ -1236,7 +1338,7 @@ static void fillRasterizationInfo(VkPipelineRasterizationStateCreateInfo* raster
rasterizer->rasterizerDiscardEnable = VK_FALSE; /* Disable/Enable output to framebuffer*/
rasterizer->polygonMode = VK_POLYGON_MODE_FILL;
rasterizer->cullMode = VK_CULL_MODE_BACK_BIT;
rasterizer->frontFace = VK_FRONT_FACE_CLOCKWISE;
rasterizer->frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE;
rasterizer->depthBiasEnable = VK_FALSE;
rasterizer->depthBiasConstantFactor = 0.0f;
rasterizer->depthBiasClamp = 0.0f;
@@ -1334,8 +1436,8 @@ static uint8_t createPipelineLayout()
createInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
createInfo.pNext = nullptr;
createInfo.flags = 0U;
createInfo.setLayoutCount = 0;
createInfo.pSetLayouts = nullptr;
createInfo.setLayoutCount = 1U;
createInfo.pSetLayouts = &gDescriptorSetLayout;
createInfo.pushConstantRangeCount = 0U;
createInfo.pPushConstantRanges = nullptr;
@@ -1349,6 +1451,31 @@ static uint8_t createPipelineLayout()
return VULKAN_ERROR_NO_ERROR;
}
static uint8_t createDescriptorSetLayout()
{
VkDescriptorSetLayoutCreateInfo layoutInfo;
VkDescriptorSetLayoutBinding uboLayoutBinding;
uboLayoutBinding.binding = 0;
uboLayoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
uboLayoutBinding.descriptorCount = 1;
uboLayoutBinding.stageFlags = VK_SHADER_STAGE_VERTEX_BIT;
uboLayoutBinding.pImmutableSamplers = nullptr;
layoutInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
layoutInfo.pNext = nullptr;
layoutInfo.flags = 0U;
layoutInfo.bindingCount = 1U;
layoutInfo.pBindings = &uboLayoutBinding;
if (vkCreateDescriptorSetLayout(gDevice, &layoutInfo, nullptr, &gDescriptorSetLayout) != VK_SUCCESS) {
LOGF << vulkanErrorMesssages[VULKAN_DESCRIPTORSETLAYOUT_CREATION_FAILED];
return VULKAN_ERROR_DESCRIPTORSETLAYOUT_CREATION_FAILED;
}
return VULKAN_ERROR_NO_ERROR;
}
static uint8_t createGraphicsPipeline()
{
uint8_t status = VULKAN_ERROR_NO_ERROR;
@@ -1477,6 +1604,7 @@ static uint8_t recordCommandBuffer(VkCommandBuffer commandBuffer, uint32_t image
vkCmdBindVertexBuffers(commandBuffer, 0, 1, vertexBuffers, offsets);
vkCmdBindIndexBuffer(commandBuffer, gIndexBuffer.buffer, 0, VK_INDEX_TYPE_UINT16);
vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, gPipelineLayout, 0, 1, &gDescriptorSets[gCurrentFrame], 0, nullptr);
vkCmdDrawIndexed(commandBuffer, static_cast<uint32_t>(indices.size()), 1, 0, 0, 0);
@@ -1516,6 +1644,21 @@ static uint8_t createSyncObjects()
return VULKAN_ERROR_NO_ERROR;
}
static void updateUniformBuffer(uint32_t currentImage)
{
static auto startTime = std::chrono::high_resolution_clock::now();
auto currentTime = std::chrono::high_resolution_clock::now();
float time = std::chrono::duration<float, std::chrono::seconds::period>(currentTime - startTime).count();
UniformBufferObject ubo{};
ubo.model = glm::rotate(glm::mat4(1.0f), time * glm::radians(90.0f), glm::vec3(0.0f, 0.0f, 1.0f));
ubo.view = glm::lookAt(glm::vec3(2.0f, 2.0f, 2.0f), glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, 0.0f, 1.0f));
ubo.proj = glm::perspective(glm::radians(45.0f), gSwapchainExtent.width / (float) gSwapchainExtent.height, 0.1f, 10.0f);
ubo.proj[1][1] *= -1;
memcpy(gUniformBuffersMappedMemory[currentImage], &ubo, sizeof(ubo));
}
static void cleanupSwapchain()
{
vkDeviceWaitIdle(gDevice);
@@ -1550,16 +1693,20 @@ uint8_t initVulkan()
STATUS_CHECK(pickPhysicalDevice());
STATUS_CHECK(createDevice());
STATUS_CHECK(createMemoryAllocator());
STATUS_CHECK(createCommandPools());
STATUS_CHECK(createVertexBuffer());
STATUS_CHECK(createIndexBuffer());
STATUS_CHECK(allocateCommandBuffers());
STATUS_CHECK(createSwapchain());
STATUS_CHECK(createSwapchainImageViews());
STATUS_CHECK(createRenderPass());
STATUS_CHECK(createDescriptorSetLayout());
STATUS_CHECK(createPipelineLayout());
STATUS_CHECK(createGraphicsPipeline());
STATUS_CHECK(createFrambuffers());
STATUS_CHECK(createCommandPools());
STATUS_CHECK(createVertexBuffer());
STATUS_CHECK(createIndexBuffer());
STATUS_CHECK(createUniformBuffers());
STATUS_CHECK(createDescriptorPool());
STATUS_CHECK(createDescriptorSets());
STATUS_CHECK(allocateCommandBuffers());
STATUS_CHECK(createSyncObjects());
return status;
}
@@ -1580,6 +1727,8 @@ void drawFrame()
return;
}
updateUniformBuffer(gCurrentFrame);
/* Only reset the fence if we are submitting work */
vkResetFences(gDevice, 1, &gInFlightFences[gCurrentFrame]);
@@ -1626,7 +1775,12 @@ void drawFrame()
void deinitVulkan()
{
cleanupSwapchain();
for (size_t i = 0; i < SWAP_BUFFER_COUNT; ++i) {
vmaDestroyBuffer(gAllocator, gUniformBuffers[i].buffer, gUniformBuffers[i].allocation);
}
vkDestroyDescriptorPool(gDevice, gDescriptorPool, nullptr);
vkDestroyDescriptorSetLayout(gDevice, gDescriptorSetLayout, nullptr);
vmaDestroyBuffer(gAllocator, gVertexBuffer.buffer, gVertexBuffer.allocation);
vmaDestroyBuffer(gAllocator, gVertexStagingBuffer.buffer, gVertexStagingBuffer.allocation);
vmaDestroyBuffer(gAllocator, gIndexBuffer.buffer, gIndexBuffer.allocation);