Add uniform buffers
This commit is contained in:
1 parent
a94e7a95f5
commit
cce4875329
3 files changed
+188
-19
No files matched your search
+172
-18
@@ -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);
|
||||
|
||||
Reference in new issue
Block a user