From 9e0b0af5e81ca6aa89aff4a88f8e4f773e79a1af Mon Sep 17 00:00:00 2001 From: Benjamin Kraft Date: Thu, 5 Sep 2024 20:51:45 +0200 Subject: [PATCH] uniform buffer object --- shaders/shader.vert | 8 ++- src/main.cpp | 1 + src/vulkan/application.cpp | 127 ++++++++++++++++++++++--------------- src/vulkan/application.hpp | 10 ++- src/vulkan/pipeline.cpp | 76 ++++++++++++++++++++-- src/vulkan/pipeline.hpp | 22 ++++++- src/vulkan/vertex.cpp | 26 +++++++- src/vulkan/vertex.hpp | 25 +------- 8 files changed, 208 insertions(+), 87 deletions(-) diff --git a/shaders/shader.vert b/shaders/shader.vert index 804b6da..4509126 100644 --- a/shaders/shader.vert +++ b/shaders/shader.vert @@ -5,7 +5,13 @@ layout (location = 1) in vec3 inColor; layout (location = 0) out vec3 fragColor; +layout (binding = 0) uniform UniformBufferObject { + mat4 model; + mat4 view; + mat4 projection; +} ubo; + void main() { - gl_Position = vec4(inPosition, 0.0, 1.0); + gl_Position = ubo.projection * ubo.view * ubo.model * vec4(inPosition, 0.0, 1.0); fragColor = inColor; } \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index 42520e2..598e934 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -4,4 +4,5 @@ int main() { Application application; + application.mainLoop(); } diff --git a/src/vulkan/application.cpp b/src/vulkan/application.cpp index 25e92cf..d0e8ba9 100644 --- a/src/vulkan/application.cpp +++ b/src/vulkan/application.cpp @@ -19,6 +19,14 @@ Application::Application() { VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); + VkDeviceSize bufferSize = sizeof(UniformBufferObject); + + uniformBuffer = new Buffer(instance, bufferSize, + VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, + VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT); + vkMapMemory(instance->device, uniformBuffer->memory, 0, bufferSize, 0, &uniformBufferMapped); + + pipeline->createDescriptorSet(uniformBuffer); commandPool = new CommandPool(instance); stagedVertexBuffer->copyTo(vertexBuffer, commandPool); @@ -28,16 +36,68 @@ Application::Application() { delete stagedIndexBuffer; createSyncObjects(); +} + +void Application::updateUniformBuffer() { + static float elapsed = 0; - mainLoop(); + elapsed += 0.007; + + UniformBufferObject ubo {}; + ubo.model = glm::rotate(glm::mat4(1), elapsed * glm::radians(90.f), glm::vec3(0, 0, 1)); + ubo.view = glm::lookAt(glm::vec3(2), glm::vec3(0), glm::vec3(0, 0, 1)); + ubo.projection = glm::perspective(glm::radians(45.f), + static_cast(swapchain->extent.width) / static_cast(swapchain->extent.height), + 0.1f, 10.f); + ubo.projection[1][1] *= -1; + + memcpy(uniformBufferMapped, &ubo, sizeof(UniformBufferObject)); } -void Application::mainLoop() { - while (!glfwWindowShouldClose(instance->window)){ - glfwPollEvents(); - drawFrame(); - } - vkDeviceWaitIdle(instance->device); +void Application::recordCommandBuffer(VkCommandBuffer commandBuffer, uint32_t imageIndex) { + VkCommandBufferBeginInfo beginInfo {}; + beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; + + vkBeginCommandBuffer(commandBuffer, &beginInfo); + + VkRenderPassBeginInfo renderPassInfo {}; + renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; + renderPassInfo.renderPass = swapchain->renderPass; + renderPassInfo.framebuffer = swapchain->frameBuffers[imageIndex]; + renderPassInfo.renderArea.offset = {0, 0}; + renderPassInfo.renderArea.extent = swapchain->extent; + + VkClearValue clearColor = {{{0, 0, 0, 1}}}; + renderPassInfo.clearValueCount = 1; + renderPassInfo.pClearValues = &clearColor; + + vkCmdBeginRenderPass(commandBuffer, &renderPassInfo, VK_SUBPASS_CONTENTS_INLINE); + vkCmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline->handle); + + VkViewport viewport {}; + viewport.x = 0; + viewport.y = 0; + viewport.width = static_cast(swapchain->extent.width); + viewport.height = static_cast(swapchain->extent.height); + viewport.minDepth = 0; + viewport.maxDepth = 1; + vkCmdSetViewport(commandBuffer, 0, 1, &viewport); + + VkRect2D scissor {}; + scissor.offset = {0, 0}; + scissor.extent = swapchain->extent; + vkCmdSetScissor(commandBuffer, 0, 1, &scissor); + + VkBuffer buffers[] = {vertexBuffer->handle}; + VkDeviceSize offsets[] = {0}; + vkCmdBindVertexBuffers(commandBuffer, 0, 1, buffers, offsets); + vkCmdBindIndexBuffer(commandBuffer, indexBuffer->handle, 0, VK_INDEX_TYPE_UINT32); + vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline->layout, 0, 1, &pipeline->descriptorSet, 0, nullptr); + + vkCmdDrawIndexed(commandBuffer, indices.size(), 1, 0, 0, 0); + + vkCmdEndRenderPass(commandBuffer); + vkEndCommandBuffer(commandBuffer); } void Application::drawFrame() { @@ -55,6 +115,8 @@ void Application::drawFrame() { vkResetCommandBuffer(commandPool->buffers[currentFrame], 0); recordCommandBuffer(commandPool->buffers[currentFrame], imageIndex); + updateUniformBuffer(); + VkSubmitInfo submitInfo {}; submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; @@ -110,50 +172,12 @@ void Application::createSyncObjects() { } } -void Application::recordCommandBuffer(VkCommandBuffer commandBuffer, uint32_t imageIndex) { - VkCommandBufferBeginInfo beginInfo {}; - beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; - - vkBeginCommandBuffer(commandBuffer, &beginInfo); - - VkRenderPassBeginInfo renderPassInfo {}; - renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; - renderPassInfo.renderPass = swapchain->renderPass; - renderPassInfo.framebuffer = swapchain->frameBuffers[imageIndex]; - renderPassInfo.renderArea.offset = {0, 0}; - renderPassInfo.renderArea.extent = swapchain->extent; - - VkClearValue clearColor = {{{0, 0, 0, 1}}}; - renderPassInfo.clearValueCount = 1; - renderPassInfo.pClearValues = &clearColor; - - vkCmdBeginRenderPass(commandBuffer, &renderPassInfo, VK_SUBPASS_CONTENTS_INLINE); - vkCmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline->graphicsPipeline); - - VkViewport viewport {}; - viewport.x = 0; - viewport.y = 0; - viewport.width = static_cast(swapchain->extent.width); - viewport.height = static_cast(swapchain->extent.height); - viewport.minDepth = 0; - viewport.maxDepth = 1; - vkCmdSetViewport(commandBuffer, 0, 1, &viewport); - - VkRect2D scissor {}; - scissor.offset = {0, 0}; - scissor.extent = swapchain->extent; - vkCmdSetScissor(commandBuffer, 0, 1, &scissor); - - VkBuffer buffers[] = {vertexBuffer->handle}; - VkDeviceSize offsets[] = {0}; - vkCmdBindVertexBuffers(commandBuffer, 0, 1, buffers, offsets); - - vkCmdBindIndexBuffer(commandBuffer, indexBuffer->handle, 0, VK_INDEX_TYPE_UINT32); - - vkCmdDrawIndexed(commandBuffer, indices.size(), 1, 0, 0, 0); - - vkCmdEndRenderPass(commandBuffer); - vkEndCommandBuffer(commandBuffer); +void Application::mainLoop() { + while (!glfwWindowShouldClose(instance->window)){ + glfwPollEvents(); + drawFrame(); + } + vkDeviceWaitIdle(instance->device); } Application::~Application() { @@ -166,6 +190,7 @@ Application::~Application() { delete commandPool; delete vertexBuffer; delete indexBuffer; + delete uniformBuffer; delete pipeline; delete instance; } diff --git a/src/vulkan/application.hpp b/src/vulkan/application.hpp index 603bf58..a617824 100644 --- a/src/vulkan/application.hpp +++ b/src/vulkan/application.hpp @@ -22,7 +22,7 @@ class Pipeline; class Buffer; class CommandPool; -constexpr int MAX_FRAMES_IN_FLIGHT = 2; +constexpr int MAX_FRAMES_IN_FLIGHT = 1; class Timer { public: @@ -40,6 +40,7 @@ private: class Application { public: explicit Application(); + void mainLoop(); ~Application(); private: Instance* instance = nullptr; @@ -47,8 +48,13 @@ private: Pipeline* pipeline = nullptr; Buffer* vertexBuffer = nullptr; Buffer* indexBuffer = nullptr; + Buffer* uniformBuffer = nullptr; CommandPool* commandPool = nullptr; + void* uniformBufferMapped = nullptr; + + void updateUniformBuffer(); + void recordCommandBuffer(VkCommandBuffer commandBuffer, uint32_t imageIndex); std::vector imageAvailableSemaphores; @@ -59,6 +65,4 @@ private: void drawFrame(); void createSyncObjects(); - - void mainLoop(); }; diff --git a/src/vulkan/pipeline.cpp b/src/vulkan/pipeline.cpp index 14a63a7..e82296a 100644 --- a/src/vulkan/pipeline.cpp +++ b/src/vulkan/pipeline.cpp @@ -3,6 +3,7 @@ #include "pipeline.hpp" #include "vertex.hpp" #include "instance.hpp" +#include "buffer.hpp" std::vector readFile(const std::string& fileName){ std::ifstream file(fileName, std::ios::ate | std::ios::binary); @@ -22,6 +23,9 @@ std::vector readFile(const std::string& fileName){ } Pipeline::Pipeline(Instance* instance, VkRenderPass renderPass) : instance(instance) { + createDescriptorSetLayout(); + createDescriptorPool(); + auto vertShaderCode = readFile("shaders/vert.spv"); auto fragShaderCode = readFile("shaders/frag.spv"); @@ -80,7 +84,7 @@ Pipeline::Pipeline(Instance* instance, VkRenderPass renderPass) : instance(insta rasterizer.polygonMode = VK_POLYGON_MODE_FILL; rasterizer.lineWidth = 1; rasterizer.cullMode = VK_CULL_MODE_BACK_BIT; - rasterizer.frontFace = VK_FRONT_FACE_CLOCKWISE; + rasterizer.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE; rasterizer.depthBiasClamp = VK_FALSE; VkPipelineMultisampleStateCreateInfo multisample {}; @@ -100,8 +104,10 @@ Pipeline::Pipeline(Instance* instance, VkRenderPass renderPass) : instance(insta VkPipelineLayoutCreateInfo pipelineLayoutInfo {}; pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; + pipelineLayoutInfo.setLayoutCount = 1; + pipelineLayoutInfo.pSetLayouts = &descriptorSetLayout; - vkCreatePipelineLayout(instance->device, &pipelineLayoutInfo, nullptr, &pipelineLayout); + vkCreatePipelineLayout(instance->device, &pipelineLayoutInfo, nullptr, &layout); VkGraphicsPipelineCreateInfo pipelineInfo {}; { @@ -118,13 +124,13 @@ Pipeline::Pipeline(Instance* instance, VkRenderPass renderPass) : instance(insta pipelineInfo.pColorBlendState = &colorBlending; pipelineInfo.pDynamicState = &dynamicState; - pipelineInfo.layout = pipelineLayout; + pipelineInfo.layout = layout; pipelineInfo.renderPass = renderPass; pipelineInfo.subpass = 0; } - vkCreateGraphicsPipelines(instance->device, VK_NULL_HANDLE, 1, &pipelineInfo, nullptr, &graphicsPipeline); + vkCreateGraphicsPipelines(instance->device, VK_NULL_HANDLE, 1, &pipelineInfo, nullptr, &handle); vkDestroyShaderModule(instance->device, vertShaderModule, nullptr); vkDestroyShaderModule(instance->device, fragShaderModule, nullptr); @@ -142,9 +148,65 @@ VkShaderModule Pipeline::createShaderModule(const std::vector &code) { return shaderModule; } - Pipeline::~Pipeline() { - vkDestroyPipeline(instance->device, graphicsPipeline, nullptr); - vkDestroyPipelineLayout(instance->device, pipelineLayout, nullptr); + vkDestroyDescriptorPool(instance->device, descriptorPool, nullptr); + vkDestroyDescriptorSetLayout(instance->device, descriptorSetLayout, nullptr); + vkDestroyPipeline(instance->device, handle, nullptr); + vkDestroyPipelineLayout(instance->device, layout, nullptr); +} + +void Pipeline::createDescriptorSetLayout() { + VkDescriptorSetLayoutBinding uboLayoutBinding {}; + uboLayoutBinding.binding = 0; + uboLayoutBinding.descriptorCount = 1; + uboLayoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; + uboLayoutBinding.stageFlags = VK_SHADER_STAGE_VERTEX_BIT; + + VkDescriptorSetLayoutCreateInfo layoutCreateInfo {}; + layoutCreateInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; + layoutCreateInfo.bindingCount = 1; + layoutCreateInfo.pBindings = &uboLayoutBinding; + + vkCreateDescriptorSetLayout(instance->device, &layoutCreateInfo, nullptr, &descriptorSetLayout); +} + +void Pipeline::createDescriptorPool() { + VkDescriptorPoolSize poolSize {}; + poolSize.descriptorCount = 1; + poolSize.type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; + + VkDescriptorPoolCreateInfo poolInfo {}; + poolInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; + poolInfo.pPoolSizes = &poolSize; + poolInfo.poolSizeCount = 1; + poolInfo.maxSets = 1; + + vkCreateDescriptorPool(instance->device, &poolInfo, nullptr, &descriptorPool); +} + +void Pipeline::createDescriptorSet(Buffer *buffer) { + VkDescriptorSetAllocateInfo allocateInfo {}; + allocateInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; + allocateInfo.descriptorPool = descriptorPool; + allocateInfo.descriptorSetCount = 1; + allocateInfo.pSetLayouts = &descriptorSetLayout; + + vkAllocateDescriptorSets(instance->device, &allocateInfo, &descriptorSet); + + VkDescriptorBufferInfo bufferInfo {}; + bufferInfo.buffer = buffer->handle; + bufferInfo.offset = 0; + bufferInfo.range = sizeof(UniformBufferObject); + + VkWriteDescriptorSet descriptorWrite {}; + descriptorWrite.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + descriptorWrite.dstSet = descriptorSet; + descriptorWrite.dstBinding = 0; + descriptorWrite.dstArrayElement = 0; + descriptorWrite.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; + descriptorWrite.descriptorCount = 1; + descriptorWrite.pBufferInfo = &bufferInfo; + + vkUpdateDescriptorSets(instance->device, 1, &descriptorWrite, 0, nullptr); } diff --git a/src/vulkan/pipeline.hpp b/src/vulkan/pipeline.hpp index 3e3b7bd..4fecaf9 100644 --- a/src/vulkan/pipeline.hpp +++ b/src/vulkan/pipeline.hpp @@ -1,16 +1,34 @@ #pragma once #include +#include class Instance; +class Buffer; + +struct UniformBufferObject { + alignas(16) glm::mat4 model; + glm::mat4 view; + glm::mat4 projection; +}; + class Pipeline { public: explicit Pipeline(Instance* instance, VkRenderPass renderPass); ~Pipeline(); - VkPipeline graphicsPipeline = VK_NULL_HANDLE; + VkPipeline handle = VK_NULL_HANDLE; + VkPipelineLayout layout = VK_NULL_HANDLE; + VkDescriptorSet descriptorSet = VK_NULL_HANDLE; + void createDescriptorSet(Buffer* buffer); private: VkShaderModule createShaderModule(const std::vector &code); - VkPipelineLayout pipelineLayout = VK_NULL_HANDLE; + + VkDescriptorPool descriptorPool = VK_NULL_HANDLE; + VkDescriptorSetLayout descriptorSetLayout = VK_NULL_HANDLE; + Instance* instance = nullptr; + void createDescriptorSetLayout(); + void createDescriptorPool(); + }; \ No newline at end of file diff --git a/src/vulkan/vertex.cpp b/src/vulkan/vertex.cpp index 450ddb8..0129df7 100644 --- a/src/vulkan/vertex.cpp +++ b/src/vulkan/vertex.cpp @@ -1 +1,25 @@ -#include "vertex.hpp" \ No newline at end of file +#include "vertex.hpp" + +VkVertexInputBindingDescription Vertex::getBindingDescription() { + VkVertexInputBindingDescription bindingDescription {}; + bindingDescription.binding = 0; + bindingDescription.stride = sizeof(Vertex); + bindingDescription.inputRate = VK_VERTEX_INPUT_RATE_VERTEX; + return bindingDescription; +} + +std::array Vertex::getAttributeDescriptions() { + std::array attributeDescriptions {}; + + attributeDescriptions[0].binding = 0; + attributeDescriptions[0].location = 0; + attributeDescriptions[0].format = VK_FORMAT_R32G32B32_SFLOAT; + attributeDescriptions[0].offset = offsetof(Vertex, pos); + + attributeDescriptions[1].binding = 0; + attributeDescriptions[1].location = 1; + attributeDescriptions[1].format = VK_FORMAT_R32G32B32_SFLOAT; + attributeDescriptions[1].offset = offsetof(Vertex, color); + + return attributeDescriptions; +} diff --git a/src/vulkan/vertex.hpp b/src/vulkan/vertex.hpp index c90d343..4459995 100644 --- a/src/vulkan/vertex.hpp +++ b/src/vulkan/vertex.hpp @@ -1,5 +1,6 @@ #pragma once +#define GLM_FORCE_RADIANS #include #include #include @@ -8,27 +9,7 @@ struct Vertex { glm::vec2 pos; glm::vec3 color; - static VkVertexInputBindingDescription getBindingDescription(){ - VkVertexInputBindingDescription bindingDescription {}; - bindingDescription.binding = 0; - bindingDescription.stride = sizeof(Vertex); - bindingDescription.inputRate = VK_VERTEX_INPUT_RATE_VERTEX; - return bindingDescription; - } + static VkVertexInputBindingDescription getBindingDescription(); - static std::array getAttributeDescriptions(){ - std::array attributeDescriptions {}; - - attributeDescriptions[0].binding = 0; - attributeDescriptions[0].location = 0; - attributeDescriptions[0].format = VK_FORMAT_R32G32_SFLOAT; - attributeDescriptions[0].offset = offsetof(Vertex, pos); - - attributeDescriptions[1].binding = 0; - attributeDescriptions[1].location = 1; - attributeDescriptions[1].format = VK_FORMAT_R32G32B32_SFLOAT; - attributeDescriptions[1].offset = offsetof(Vertex, color); - - return attributeDescriptions; - } + static std::array getAttributeDescriptions(); }; \ No newline at end of file