Uniform buffer creation, set up rudimentary MVP matrix

This commit is contained in:
Lillian Salehi 2024-10-11 22:41:29 -05:00
parent 6b8b24da65
commit 086adae47a
8 changed files with 184 additions and 20 deletions

View File

@ -1,5 +1,5 @@
#include "entrypoint.h" #include "entrypoint.h"
#include "graphics/buffers.h" #include "global.h"
DeviceControl::devicelibrary deviceLibs; DeviceControl::devicelibrary deviceLibs;
Debug::vulkandebuglibs debugController; Debug::vulkandebuglibs debugController;
Graphics::graphicspipeline graphicsPipeline; Graphics::graphicspipeline graphicsPipeline;
@ -59,11 +59,15 @@ void initVulkan() {
deviceLibs.createSwapChain(Global::window); deviceLibs.createSwapChain(Global::window);
deviceLibs.createImageViews(); deviceLibs.createImageViews();
graphicsPipeline.createRenderPass(); graphicsPipeline.createRenderPass();
buffers.createDescriptorSetLayout();
graphicsPipeline.createGraphicsPipeline(); graphicsPipeline.createGraphicsPipeline();
graphicsPipeline.createFramebuffers(); graphicsPipeline.createFramebuffers();
graphicsPipeline.createCommandPool(); graphicsPipeline.createCommandPool();
buffers.createVertexBuffer(); buffers.createVertexBuffer();
buffers.createIndexBuffer(); buffers.createIndexBuffer();
buffers.createUniformBuffers();
buffers.createDescriptorPool();
buffers.createDescriptorSets();
graphicsPipeline.createCommandBuffer(); graphicsPipeline.createCommandBuffer();
renderPresentation.createSyncObject(); renderPresentation.createSyncObject();
} }
@ -78,6 +82,9 @@ void mainLoop() { // This loop jus
void cleanup() { // Similar to the last handoff, destroy the utils in a safe manner in the library! void cleanup() { // Similar to the last handoff, destroy the utils in a safe manner in the library!
renderPresentation.cleanupSwapChain(); renderPresentation.cleanupSwapChain();
buffers.destroyUniformBuffer();
buffers.destroyDescriptorPool();
vkDestroyDescriptorSetLayout(Global::device, Global::descriptorSetLayout, nullptr);
graphicsPipeline.destroyGraphicsPipeline(); graphicsPipeline.destroyGraphicsPipeline();
graphicsPipeline.destroyRenderPass(); graphicsPipeline.destroyRenderPass();

View File

@ -21,7 +21,9 @@ namespace Global {
VkQueue graphicsQueue; VkQueue graphicsQueue;
VkQueue presentQueue; VkQueue presentQueue;
GLFWwindow* window; GLFWwindow* window;
VkDescriptorSetLayout descriptorSetLayout;
std::vector<VkDescriptorSet> descriptorSets;
uint32_t currentFrame = 0;
Global::QueueFamilyIndices findQueueFamilies(VkPhysicalDevice device) { Global::QueueFamilyIndices findQueueFamilies(VkPhysicalDevice device) {
// First we feed in a integer we want to use to hold the number of queued items, that fills it, then we create that amount of default constructed *VkQueueFamilyProperties* structs. // First we feed in a integer we want to use to hold the number of queued items, that fills it, then we create that amount of default constructed *VkQueueFamilyProperties* structs.

View File

@ -1,4 +1,5 @@
#pragma once #pragma once
#include <cstdint>
#include <glm/detail/qualifier.hpp> #include <glm/detail/qualifier.hpp>
#include <glm/ext/vector_float2.hpp> #include <glm/ext/vector_float2.hpp>
#include <glm/ext/vector_float3.hpp> #include <glm/ext/vector_float3.hpp>
@ -7,6 +8,7 @@
#include <optional> #include <optional>
#include <vulkan/vulkan_core.h> #include <vulkan/vulkan_core.h>
#include "debug/vulkandebuglibs.h" #include "debug/vulkandebuglibs.h"
#include <glm/gtc/matrix_transform.hpp>
#include <array> #include <array>
#define GLFW_INCLUDE_VULKAN #define GLFW_INCLUDE_VULKAN
@ -24,7 +26,15 @@ namespace Global {
extern VkQueue presentQueue; extern VkQueue presentQueue;
const int MAX_FRAMES_IN_FLIGHT = 2; const int MAX_FRAMES_IN_FLIGHT = 2;
extern GLFWwindow* window; extern GLFWwindow* window;
extern VkDescriptorSetLayout descriptorSetLayout;
extern uint32_t currentFrame;
extern std::vector<VkDescriptorSet> descriptorSets;
struct UniformBufferObject {
glm::mat4 model;
glm::mat4 view;
glm::mat4 proj;
};
struct Vertex { struct Vertex {
glm::vec2 pos; glm::vec2 pos;
glm::vec3 color; glm::vec3 color;

View File

@ -1,14 +1,24 @@
#include "buffers.h" #include "buffers.h"
#include <chrono>
#include <cstdint> #include <cstdint>
#include <vector>
#include <vulkan/vulkan_core.h> #include <vulkan/vulkan_core.h>
#include "../devicelibrary.h"
VkBuffer vertexBuffer; VkBuffer vertexBuffer;
VkDeviceMemory vertexBufferMemory; VkDeviceMemory vertexBufferMemory;
VkBuffer indexBuffer; VkBuffer indexBuffer;
VkDeviceMemory indexBufferMemory; VkDeviceMemory indexBufferMemory;
VkDescriptorPool descriptorPool;
DeviceControl::devicelibrary deviceLibrary;
std::vector<VkBuffer> uniformBuffers;
std::vector<VkDeviceMemory> uniformBuffersMemory;
std::vector<void*> uniformBuffersMapped;
namespace Buffers { namespace Buffers {
const std::vector<Global::Vertex> vertices = { const std::vector<Global::Vertex> vertices = {
{{-0.5f, -0.5f}, {1.0f, 0.0f, 0.0f}}, {{-0.5f, -0.5f}, {1.0f, 0.0f, 0.0f}},
{{0.5f, -0.5f}, {0.0f, 1.0f, 0.0f}}, {{0.5f, -0.5f}, {0.0f, 1.0f, 0.0f}},
@ -155,4 +165,119 @@ namespace Buffers {
std::vector<uint16_t> bufferslibrary::getIndices() { std::vector<uint16_t> bufferslibrary::getIndices() {
return indices; return indices;
} }
void bufferslibrary::createDescriptorSetLayout() {
// Create a table of pointers to data, a Descriptor Set!
VkDescriptorSetLayoutBinding uboLayoutBinding{};
uboLayoutBinding.binding = 0;
uboLayoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
// Model-View-Projection matrix is in a single uniform buffer, so just 1 descriptor.
uboLayoutBinding.descriptorCount = 1;
// We are only using this buffer in the vertex shader, so set the flags thus.
uboLayoutBinding.stageFlags = VK_SHADER_STAGE_VERTEX_BIT;
// Immutable Samplers is relevant for image sampling.
uboLayoutBinding.pImmutableSamplers = nullptr;
VkDescriptorSetLayoutCreateInfo layoutInfo{};
layoutInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
layoutInfo.bindingCount = 1;
layoutInfo.pBindings = &uboLayoutBinding;
if(vkCreateDescriptorSetLayout(Global::device, &layoutInfo, nullptr, &Global::descriptorSetLayout) != VK_SUCCESS) {
throw std::runtime_error("Failed to create descriptor set layout!");
}
}
//void createMVPDescriptor() {
//}
void bufferslibrary::createUniformBuffers() {
VkDeviceSize bufferSize = sizeof(Global::UniformBufferObject);
uniformBuffers.resize(Global::MAX_FRAMES_IN_FLIGHT);
uniformBuffersMemory.resize(Global::MAX_FRAMES_IN_FLIGHT);
uniformBuffersMapped.resize(Global::MAX_FRAMES_IN_FLIGHT);
for(size_t i = 0; i < Global::MAX_FRAMES_IN_FLIGHT; i++) {
createBuffer(bufferSize, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, uniformBuffers[i], uniformBuffersMemory[i]);
vkMapMemory(Global::device, uniformBuffersMemory[i], 0, bufferSize, 0, &uniformBuffersMapped[i]);
}
}
void bufferslibrary::updateUniformBuffer(uint32_t currentImage) {
static auto startTime = std::chrono::high_resolution_clock::now();
// Calculate the time in seconds since rendering has began to floating point precision.
auto currentTime = std::chrono::high_resolution_clock::now();
float time = std::chrono::duration<float, std::chrono::seconds::period>(currentTime - startTime).count();
Global::UniformBufferObject ubo{};
// Modify the model projection transformation to rotate around the Z over time.
ubo.model = glm::rotate(glm::mat4(1.0f), time * glm::radians(90.0f), glm::vec3(0.0f, 0.0f, 1.0f));
// Modify the view transformation to look at the object from above at a 45 degree angle.
// This takes the eye position, center position, and the up direction.
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));
// 45 degree field of view, set aspect ratio, and near and far clipping range.
ubo.proj = glm::perspective(glm::radians(45.0f), deviceLibrary.getSwapChainExtent().width / (float) deviceLibrary.getSwapChainExtent().height, 0.1f, 10.0f);
// GLM was created for OpenGL, where the Y coordinate was inverted. This simply flips the sign.
ubo.proj[1][1] *= -1;
memcpy(uniformBuffersMapped[currentImage], &ubo, sizeof(ubo));
}
void bufferslibrary::destroyUniformBuffer() {
for(size_t i = 0; i < Global::MAX_FRAMES_IN_FLIGHT; i++) {
vkDestroyBuffer(Global::device, uniformBuffers[i],nullptr);
vkFreeMemory(Global::device, uniformBuffersMemory[i], nullptr);
}
}
void bufferslibrary::createDescriptorPool() {
VkDescriptorPoolSize poolSize{};
poolSize.type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
poolSize.descriptorCount = static_cast<uint32_t>(Global::MAX_FRAMES_IN_FLIGHT);
VkDescriptorPoolCreateInfo poolInfo{};
poolInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
poolInfo.poolSizeCount = 1;
poolInfo.pPoolSizes = &poolSize;
poolInfo.maxSets = static_cast<uint32_t>(Global::MAX_FRAMES_IN_FLIGHT);
if (vkCreateDescriptorPool(Global::device, &poolInfo, nullptr, &descriptorPool) != VK_SUCCESS) {
throw std::runtime_error("failed to create descriptor pool!");
}
}
void bufferslibrary::createDescriptorSets() {
std::vector<VkDescriptorSetLayout> layouts(Global::MAX_FRAMES_IN_FLIGHT, Global::descriptorSetLayout);
VkDescriptorSetAllocateInfo allocInfo{};
allocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
allocInfo.descriptorPool = descriptorPool;
allocInfo.descriptorSetCount = static_cast<uint32_t>(Global::MAX_FRAMES_IN_FLIGHT);
allocInfo.pSetLayouts = layouts.data();
Global::descriptorSets.resize(Global::MAX_FRAMES_IN_FLIGHT);
if (vkAllocateDescriptorSets(Global::device, &allocInfo, Global::descriptorSets.data()) != VK_SUCCESS) {
throw std::runtime_error("failed to allocate descriptor sets!");
}
for(size_t i = 0; i < Global::MAX_FRAMES_IN_FLIGHT; i++) {
VkDescriptorBufferInfo bufferInfo{};
bufferInfo.buffer = uniformBuffers[i];
bufferInfo.offset = 0;
bufferInfo.range = sizeof(Global::UniformBufferObject);
VkWriteDescriptorSet descriptorWrite{};
descriptorWrite.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
descriptorWrite.dstSet = Global::descriptorSets[i];
descriptorWrite.dstBinding = 0;
descriptorWrite.dstArrayElement = 0;
descriptorWrite.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
descriptorWrite.descriptorCount = 1;
descriptorWrite.pBufferInfo = &bufferInfo;
descriptorWrite.pImageInfo = nullptr; // Optional
descriptorWrite.pTexelBufferView = nullptr; // Optional
vkUpdateDescriptorSets(Global::device, 1, &descriptorWrite, 0, nullptr);
}
}
void bufferslibrary::destroyDescriptorPool() {
vkDestroyDescriptorPool(Global::device, descriptorPool, nullptr);
}
} }

View File

@ -1,5 +1,6 @@
#pragma once #pragma once
#include "../global.h" #include "../global.h"
#include <cstdint>
namespace Buffers { namespace Buffers {
class bufferslibrary { class bufferslibrary {
@ -11,5 +12,12 @@ namespace Buffers {
VkBuffer getIndexBuffer(); VkBuffer getIndexBuffer();
std::vector<Global::Vertex> getVertices(); std::vector<Global::Vertex> getVertices();
std::vector<uint16_t> getIndices(); std::vector<uint16_t> getIndices();
void createDescriptorSetLayout();
void createUniformBuffers();
void updateUniformBuffer(uint32_t currentImage);
void destroyUniformBuffer();
void createDescriptorPool();
void createDescriptorSets();
void destroyDescriptorPool();
}; };
} }

View File

@ -96,11 +96,11 @@ namespace Graphics {
rasterizer.depthClampEnable = VK_FALSE; rasterizer.depthClampEnable = VK_FALSE;
rasterizer.rasterizerDiscardEnable = VK_FALSE; rasterizer.rasterizerDiscardEnable = VK_FALSE;
// MODE_FILL, fill polygons, MODE_LINE, draw wireframe, MODE_POINT, draw vertices. Anything other than fill requires GPU feature *fillModeNonSolid* // MODE_FILL, fill polygons, MODE_LINE, draw wireframe, MODE_POINT, draw vertices. Anything other than fill requires GPU feature *fillModeNonSolid*
rasterizer.polygonMode = VK_POLYGON_MODE_LINE; rasterizer.polygonMode = VK_POLYGON_MODE_FILL;
rasterizer.lineWidth = 2.0f; rasterizer.lineWidth = 2.0f;
// How to cull the faces, right here we cull the back faces and tell the rasterizer front facing vertices are ordered clockwise. // How to cull the faces, right here we cull the back faces and tell the rasterizer front facing vertices are ordered clockwise.
rasterizer.cullMode = VK_CULL_MODE_BACK_BIT; rasterizer.cullMode = VK_CULL_MODE_BACK_BIT;
rasterizer.frontFace = VK_FRONT_FACE_CLOCKWISE; rasterizer.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE;
// Whether or not to add depth values. e.x. for shadow maps. // Whether or not to add depth values. e.x. for shadow maps.
rasterizer.depthBiasEnable = VK_FALSE; rasterizer.depthBiasEnable = VK_FALSE;
@ -147,8 +147,8 @@ namespace Graphics {
VkPipelineLayoutCreateInfo pipelineLayoutInfo{}; VkPipelineLayoutCreateInfo pipelineLayoutInfo{};
pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
pipelineLayoutInfo.setLayoutCount = 0; pipelineLayoutInfo.setLayoutCount = 1;
pipelineLayoutInfo.pushConstantRangeCount = 0; pipelineLayoutInfo.pSetLayouts = &Global::descriptorSetLayout;
if (vkCreatePipelineLayout(Global::device, &pipelineLayoutInfo, nullptr, &pipelineLayout) != VK_SUCCESS) { if (vkCreatePipelineLayout(Global::device, &pipelineLayoutInfo, nullptr, &pipelineLayout) != VK_SUCCESS) {
throw std::runtime_error("failed to create pipeline layout!"); throw std::runtime_error("failed to create pipeline layout!");
@ -309,6 +309,8 @@ namespace Graphics {
VkDeviceSize offsets[] = {0}; VkDeviceSize offsets[] = {0};
vkCmdBindVertexBuffers(commandBuffer, 0, 1, vertexBuffers, offsets); vkCmdBindVertexBuffers(commandBuffer, 0, 1, vertexBuffers, offsets);
vkCmdBindIndexBuffer(commandBuffer, buffers.getIndexBuffer(), 0, VK_INDEX_TYPE_UINT16); vkCmdBindIndexBuffer(commandBuffer, buffers.getIndexBuffer(), 0, VK_INDEX_TYPE_UINT16);
vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, 1, &Global::descriptorSets[Global::currentFrame], 0, nullptr);
vkCmdDrawIndexed(commandBuffer, static_cast<uint32_t>(buffers.getIndices().size()), 1, 0, 0, 0); vkCmdDrawIndexed(commandBuffer, static_cast<uint32_t>(buffers.getIndices().size()), 1, 0, 0, 0);
vkCmdEndRenderPass(commandBuffer); vkCmdEndRenderPass(commandBuffer);

View File

@ -9,7 +9,7 @@ namespace RenderPresent {
std::vector<VkFence> inFlightFences; std::vector<VkFence> inFlightFences;
Graphics::graphicspipeline pipeline; Graphics::graphicspipeline pipeline;
DeviceControl::devicelibrary deviceLibs; DeviceControl::devicelibrary deviceLibs;
uint32_t currentFrame = 0; Buffers::bufferslibrary buffers;
void recreateSwapChain() { void recreateSwapChain() {
int width = 0, height = 0; int width = 0, height = 0;
@ -38,39 +38,42 @@ namespace RenderPresent {
// submit the recorded command buffer and present the image! // submit the recorded command buffer and present the image!
void render::drawFrame() { void render::drawFrame() {
vkWaitForFences(Global::device, 1, &inFlightFences[currentFrame], VK_TRUE, UINT64_MAX); vkWaitForFences(Global::device, 1, &inFlightFences[Global::currentFrame], VK_TRUE, UINT64_MAX);
vkResetFences(Global::device, 1, &inFlightFences[currentFrame]); vkResetFences(Global::device, 1, &inFlightFences[Global::currentFrame]);
uint32_t imageIndex; uint32_t imageIndex;
VkResult result = vkAcquireNextImageKHR(Global::device, Global::swapChain, UINT64_MAX, imageAvailableSemaphores[currentFrame], VK_NULL_HANDLE, &imageIndex); VkResult result = vkAcquireNextImageKHR(Global::device, Global::swapChain, UINT64_MAX, imageAvailableSemaphores[Global::currentFrame], VK_NULL_HANDLE, &imageIndex);
if (result == VK_ERROR_OUT_OF_DATE_KHR) { if (result == VK_ERROR_OUT_OF_DATE_KHR) {
recreateSwapChain(); recreateSwapChain();
return; return;
} else if (result != VK_SUCCESS && result != VK_SUBOPTIMAL_KHR) { } else if (result != VK_SUCCESS && result != VK_SUBOPTIMAL_KHR) {
throw std::runtime_error("failed to acquire swap chain image!"); throw std::runtime_error("failed to acquire swap chain image!");
} }
vkResetFences(Global::device, 1, &inFlightFences[currentFrame]);
vkResetCommandBuffer(Global::commandBuffers[currentFrame], /*VkCommandBufferResetFlagBits*/ 0); buffers.updateUniformBuffer(Global::currentFrame);
pipeline.recordCommandBuffer(Global::commandBuffers[currentFrame], imageIndex);
vkResetFences(Global::device, 1, &inFlightFences[Global::currentFrame]);
vkResetCommandBuffer(Global::commandBuffers[Global::currentFrame], /*VkCommandBufferResetFlagBits*/ 0);
pipeline.recordCommandBuffer(Global::commandBuffers[Global::currentFrame], imageIndex);
VkSubmitInfo submitInfo{}; VkSubmitInfo submitInfo{};
submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
VkSemaphore waitSemaphores[] = {imageAvailableSemaphores[currentFrame]}; VkSemaphore waitSemaphores[] = {imageAvailableSemaphores[Global::currentFrame]};
VkPipelineStageFlags waitStages[] = {VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT}; VkPipelineStageFlags waitStages[] = {VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT};
submitInfo.waitSemaphoreCount = 1; submitInfo.waitSemaphoreCount = 1;
submitInfo.pWaitSemaphores = waitSemaphores; submitInfo.pWaitSemaphores = waitSemaphores;
submitInfo.pWaitDstStageMask = waitStages; submitInfo.pWaitDstStageMask = waitStages;
submitInfo.commandBufferCount = 1; submitInfo.commandBufferCount = 1;
submitInfo.pCommandBuffers = &Global::commandBuffers[currentFrame]; submitInfo.pCommandBuffers = &Global::commandBuffers[Global::currentFrame];
VkSemaphore signalSemaphores[] = {renderFinishedSemaphores[currentFrame]}; VkSemaphore signalSemaphores[] = {renderFinishedSemaphores[Global::currentFrame]};
submitInfo.signalSemaphoreCount = 1; submitInfo.signalSemaphoreCount = 1;
submitInfo.pSignalSemaphores = signalSemaphores; submitInfo.pSignalSemaphores = signalSemaphores;
if (vkQueueSubmit(Global::graphicsQueue, 1, &submitInfo, inFlightFences[currentFrame]) != VK_SUCCESS) { if (vkQueueSubmit(Global::graphicsQueue, 1, &submitInfo, inFlightFences[Global::currentFrame]) != VK_SUCCESS) {
throw std::runtime_error("failed to submit draw command buffer!"); throw std::runtime_error("failed to submit draw command buffer!");
} }
@ -93,7 +96,7 @@ namespace RenderPresent {
} else if (result != VK_SUCCESS) { } else if (result != VK_SUCCESS) {
throw std::runtime_error("failed to present swap chain image!"); throw std::runtime_error("failed to present swap chain image!");
} }
currentFrame = (currentFrame + 1) % Global::MAX_FRAMES_IN_FLIGHT; Global::currentFrame = (Global::currentFrame + 1) % Global::MAX_FRAMES_IN_FLIGHT;
} }
#pragma info #pragma info
// SEMAPHORES // SEMAPHORES

View File

@ -1,4 +1,10 @@
#version 450 #version 450
layout(binding = 0) uniform UniformBufferObject {
mat4 model;
mat4 view;
mat4 proj;
} ubo;
// inPosition and inColor are vertex attributes, per-vertex properties defined in the vertex buffer! // inPosition and inColor are vertex attributes, per-vertex properties defined in the vertex buffer!
// Layout assigns indices to access these inputs, dvec3 takes 2 slots so we must index it at 2. https://www.khronos.org/opengl/wiki/Layout_Qualifier_(GLSL) // Layout assigns indices to access these inputs, dvec3 takes 2 slots so we must index it at 2. https://www.khronos.org/opengl/wiki/Layout_Qualifier_(GLSL)
layout(location = 0) in vec2 inPosition; layout(location = 0) in vec2 inPosition;
@ -7,6 +13,7 @@ layout(location = 1) in vec3 inColor;
layout(location = 0) out vec3 fragColor; layout(location = 0) out vec3 fragColor;
void main() { 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; fragColor = inColor;
} }