From edfbddea55fe511385426ae18ea8160706f480f7 Mon Sep 17 00:00:00 2001 From: Lillian Salehi Date: Thu, 10 Oct 2024 02:26:13 -0500 Subject: [PATCH] Index buffer support to allow for reusing of the same vertices. Next commits will be refactors and documentation, graphs and flows of execution --- src/devicelibrary.cpp | 2 +- src/entrypoint.cpp | 8 +- src/graphics/buffers.cpp | 146 ++++++++++++++++++++++++------ src/graphics/buffers.h | 5 +- src/graphics/graphicspipeline.cpp | 7 +- src/graphics/render.cpp | 2 +- src/shaders/fragment.spv | Bin 0 -> 572 bytes src/shaders/vertex.spv | Bin 0 -> 1080 bytes 8 files changed, 131 insertions(+), 39 deletions(-) create mode 100644 src/shaders/fragment.spv create mode 100644 src/shaders/vertex.spv diff --git a/src/devicelibrary.cpp b/src/devicelibrary.cpp index 395020f..6e096cb 100644 --- a/src/devicelibrary.cpp +++ b/src/devicelibrary.cpp @@ -269,7 +269,7 @@ namespace DeviceControl { createSwapChainInfo.clipped = VK_TRUE; // This is something that needs to be implemented later, operations like resizing the window invalidate the swap chain and // require you to recreate it and reference the old one specified here, will revisit in a few days. - createSwapChainInfo.oldSwapchain = VK_NULL_HANDLE; + //createSwapChainInfo.oldSwapchain = VK_NULL_HANDLE; if(vkCreateSwapchainKHR(Global::device, &createSwapChainInfo, nullptr, &Global::swapChain) != VK_SUCCESS) { throw std::runtime_error("Failed to create the swap chain!!"); diff --git a/src/entrypoint.cpp b/src/entrypoint.cpp index fb9e3cd..3704c8c 100644 --- a/src/entrypoint.cpp +++ b/src/entrypoint.cpp @@ -16,15 +16,13 @@ bool EntryApp::getFramebufferResized() const { } static void framebufferResizeCallback(GLFWwindow* window, int width, int height) { auto app = reinterpret_cast(glfwGetWindowUserPointer(window)); - app->EntryApp::getInstance().setFramebufferResized(true); + app->setFramebufferResized(true); } // Initialize GLFW Window. First, Initialize GLFW lib, disable resizing for // now, and create window. void initWindow() { glfwInit(); glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); - glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE); - // Settings for the window are set, create window reference. Global::window = glfwCreateWindow(Global::WIDTH, Global::HEIGHT, "Vulkan", nullptr, nullptr); glfwSetWindowUserPointer(Global::window, &EntryApp::getInstance()); @@ -65,6 +63,7 @@ void initVulkan() { graphicsPipeline.createFramebuffers(); graphicsPipeline.createCommandPool(); buffers.createVertexBuffer(); + buffers.createIndexBuffer(); graphicsPipeline.createCommandBuffer(); renderPresentation.createSyncObject(); } @@ -79,9 +78,10 @@ void mainLoop() { // This loop jus void cleanup() { // Similar to the last handoff, destroy the utils in a safe manner in the library! renderPresentation.cleanupSwapChain(); - buffers.destroyVertexBuffer(); graphicsPipeline.destroyGraphicsPipeline(); graphicsPipeline.destroyRenderPass(); + + buffers.destroyBuffers(); renderPresentation.destroyFenceSemaphores(); graphicsPipeline.destroyCommandPool(); diff --git a/src/graphics/buffers.cpp b/src/graphics/buffers.cpp index 940b84c..a805cc5 100644 --- a/src/graphics/buffers.cpp +++ b/src/graphics/buffers.cpp @@ -1,16 +1,26 @@ #include "buffers.h" -#include +#include +#include #include VkBuffer vertexBuffer; VkDeviceMemory vertexBufferMemory; +VkBuffer indexBuffer; +VkDeviceMemory indexBufferMemory; + namespace Buffers { const std::vector vertices = { {{-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, 0.0f, 1.0f}} + {{0.5f, 0.5f}, {0.0f, 0.0f, 1.0f}}, + {{-0.5f, 0.5f}, {1.0f, 1.0f, 1.0f}} + }; + // Index buffer definition, showing which points to reuse. + const std::vector indices = { + 0, 1, 2, 2, 3, 0 }; + uint32_t findMemoryType(uint32_t typeFilter, VkMemoryPropertyFlags properties) { // Graphics cards offer different types of memory to allocate from, here we query to find the right type of memory for our needs. // Query the available types of memory to iterate over. @@ -25,47 +35,125 @@ namespace Buffers { throw std::runtime_error("failed to find suitable memory type!"); } + void copyBuffer(VkBuffer srcBuffer, VkBuffer dstBuffer, VkDeviceSize size) { + VkCommandBufferAllocateInfo allocInfo{}; + allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; + allocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; + allocInfo.commandPool = Global::commandPool; + allocInfo.commandBufferCount = 1; + + VkCommandBuffer commandBuffer; + vkAllocateCommandBuffers(Global::device, &allocInfo, &commandBuffer); + + VkCommandBufferBeginInfo beginInfo{}; + beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; + beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; + + vkBeginCommandBuffer(commandBuffer, &beginInfo); + + VkBufferCopy copyRegion{}; + copyRegion.size = size; + vkCmdCopyBuffer(commandBuffer, srcBuffer, dstBuffer, 1, ©Region); + + vkEndCommandBuffer(commandBuffer); + + VkSubmitInfo submitInfo{}; + submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; + submitInfo.commandBufferCount = 1; + submitInfo.pCommandBuffers = &commandBuffer; + + vkQueueSubmit(Global::graphicsQueue, 1, &submitInfo, VK_NULL_HANDLE); + vkQueueWaitIdle(Global::graphicsQueue); + + vkFreeCommandBuffers(Global::device, Global::commandPool, 1, &commandBuffer); + } + + void createBuffer(VkDeviceSize size, VkBufferUsageFlags usage, VkMemoryPropertyFlags properties, VkBuffer& buffer, VkDeviceMemory& bufferMemory) { + VkBufferCreateInfo bufferInfo{}; + bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; + bufferInfo.size = size; + bufferInfo.usage = usage; + bufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + + if (vkCreateBuffer(Global::device, &bufferInfo, nullptr, &buffer) != VK_SUCCESS) { + throw std::runtime_error("failed to create buffer!"); + } + + VkMemoryRequirements memRequirements; + vkGetBufferMemoryRequirements(Global::device, buffer, &memRequirements); + + VkMemoryAllocateInfo allocInfo{}; + allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; + allocInfo.allocationSize = memRequirements.size; + allocInfo.memoryTypeIndex = findMemoryType(memRequirements.memoryTypeBits, properties); + + if (vkAllocateMemory(Global::device, &allocInfo, nullptr, &bufferMemory) != VK_SUCCESS) { + throw std::runtime_error("failed to allocate buffer memory!"); + } + + vkBindBufferMemory(Global::device, buffer, bufferMemory, 0); + } + + void bufferslibrary::createIndexBuffer() { + VkDeviceSize bufferSize = sizeof(indices[0]) * indices.size(); + + VkBuffer stagingBuffer; + VkDeviceMemory stagingBufferMemory; + + createBuffer(bufferSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, stagingBuffer, stagingBufferMemory); + + void* data; + vkMapMemory(Global::device, stagingBufferMemory, 0, bufferSize, 0, &data); + memcpy(data, indices.data(), (size_t) bufferSize); + vkUnmapMemory(Global::device, stagingBufferMemory); + + createBuffer(bufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, indexBuffer, indexBufferMemory); + + copyBuffer(stagingBuffer, indexBuffer, bufferSize); + + vkDestroyBuffer(Global::device, stagingBuffer, nullptr); + vkFreeMemory(Global::device, stagingBufferMemory, nullptr); + } void bufferslibrary::createVertexBuffer() { // Create a Vertex Buffer to hold the vertex information in memory so it doesn't have to be hardcoded! // Size denotes the size of the buffer in bytes, usage in this case is the buffer behaviour, using a bitwise OR. // Sharing mode denostes the same as the images in the swap chain! in this case, only the graphics queue uses this buffer, so we make it exclusive. - VkBufferCreateInfo bufferInfo; - bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; - bufferInfo.size = sizeof(vertices[0]) * vertices.size(); - bufferInfo.usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT; - bufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; - bufferInfo.pNext = NULL; - std::cerr << &bufferInfo << " " << &vertexBuffer << "\n"; - if (vkCreateBuffer(Global::device, &bufferInfo, nullptr, &vertexBuffer) != VK_SUCCESS) { - throw std::runtime_error("failed to create vertex buffer!"); - } - // Query the memory requirements of the buffer. - VkMemoryRequirements memRequirements; - vkGetBufferMemoryRequirements(Global::device, vertexBuffer, &memRequirements); - - VkMemoryAllocateInfo allocInfo{}; - allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; - allocInfo.allocationSize = memRequirements.size; - allocInfo.memoryTypeIndex = findMemoryType(memRequirements.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT); - - if (vkAllocateMemory(Global::device, &allocInfo, nullptr, &vertexBufferMemory) != VK_SUCCESS) { - throw std::runtime_error("failed to allocate vertex buffer memory!"); - } - vkBindBufferMemory(Global::device, vertexBuffer, vertexBufferMemory, 0); + VkDeviceSize bufferSize = sizeof(vertices[0]) * vertices.size(); + + VkBuffer stagingBuffer; + VkDeviceMemory stagingBufferMemory; + createBuffer(bufferSize, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, stagingBuffer, stagingBufferMemory); void* data; - vkMapMemory(Global::device, vertexBufferMemory, 0, bufferInfo.size, 0, &data); - memcpy(data, vertices.data(), (size_t) bufferInfo.size); - vkUnmapMemory(Global::device, vertexBufferMemory); + vkMapMemory(Global::device, stagingBufferMemory, 0, bufferSize, 0, &data); + memcpy(data, vertices.data(), (size_t) bufferSize); + vkUnmapMemory(Global::device, stagingBufferMemory); + + createBuffer(bufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, vertexBuffer, vertexBufferMemory); + + copyBuffer(stagingBuffer, vertexBuffer, bufferSize); + + vkDestroyBuffer(Global::device, stagingBuffer, nullptr); + vkFreeMemory(Global::device, stagingBufferMemory, nullptr); } - void bufferslibrary::destroyVertexBuffer() { + + void bufferslibrary::destroyBuffers() { + vkDestroyBuffer(Global::device, indexBuffer, nullptr); + vkFreeMemory(Global::device, indexBufferMemory, nullptr); + vkDestroyBuffer(Global::device, vertexBuffer, nullptr); vkFreeMemory(Global::device, vertexBufferMemory, nullptr); } VkBuffer bufferslibrary::getVertexBuffer() { return vertexBuffer; } + VkBuffer bufferslibrary::getIndexBuffer() { + return indexBuffer; + } std::vector bufferslibrary::getVertices() { return vertices; } + std::vector bufferslibrary::getIndices() { + return indices; + } } diff --git a/src/graphics/buffers.h b/src/graphics/buffers.h index 6fa0d46..fb8cfd2 100644 --- a/src/graphics/buffers.h +++ b/src/graphics/buffers.h @@ -4,9 +4,12 @@ namespace Buffers { class bufferslibrary { public: + void createIndexBuffer(); void createVertexBuffer(); - void destroyVertexBuffer(); + void destroyBuffers(); VkBuffer getVertexBuffer(); + VkBuffer getIndexBuffer(); std::vector getVertices(); + std::vector getIndices(); }; } diff --git a/src/graphics/graphicspipeline.cpp b/src/graphics/graphicspipeline.cpp index 62c018c..94f8331 100644 --- a/src/graphics/graphicspipeline.cpp +++ b/src/graphics/graphicspipeline.cpp @@ -96,8 +96,8 @@ namespace Graphics { rasterizer.depthClampEnable = 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* - rasterizer.polygonMode = VK_POLYGON_MODE_FILL; - rasterizer.lineWidth = 1.0f; + rasterizer.polygonMode = VK_POLYGON_MODE_LINE; + 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. rasterizer.cullMode = VK_CULL_MODE_BACK_BIT; rasterizer.frontFace = VK_FRONT_FACE_CLOCKWISE; @@ -308,8 +308,9 @@ namespace Graphics { VkBuffer vertexBuffers[] = {buffers.getVertexBuffer()}; VkDeviceSize offsets[] = {0}; vkCmdBindVertexBuffers(commandBuffer, 0, 1, vertexBuffers, offsets); + vkCmdBindIndexBuffer(commandBuffer, buffers.getIndexBuffer(), 0, VK_INDEX_TYPE_UINT16); - vkCmdDraw(commandBuffer, static_cast(buffers.getVertices().size()), 1, 0, 0); + vkCmdDrawIndexed(commandBuffer, static_cast(buffers.getIndices().size()), 1, 0, 0, 0); vkCmdEndRenderPass(commandBuffer); if (vkEndCommandBuffer(commandBuffer) != VK_SUCCESS) { diff --git a/src/graphics/render.cpp b/src/graphics/render.cpp index ffe5009..6cca75e 100644 --- a/src/graphics/render.cpp +++ b/src/graphics/render.cpp @@ -144,8 +144,8 @@ namespace RenderPresent { } void render::destroyFenceSemaphores() { for (size_t i = 0; i < Global::MAX_FRAMES_IN_FLIGHT; i++) { - vkDestroySemaphore(Global::device, imageAvailableSemaphores[i], nullptr); vkDestroySemaphore(Global::device, renderFinishedSemaphores[i], nullptr); + vkDestroySemaphore(Global::device, imageAvailableSemaphores[i], nullptr); vkDestroyFence(Global::device, inFlightFences[i], nullptr); } } diff --git a/src/shaders/fragment.spv b/src/shaders/fragment.spv new file mode 100644 index 0000000000000000000000000000000000000000..da37f7ede672fe162b5322c32f5938a7836409a7 GIT binary patch literal 572 zcmYk2PfNo<6vUrx)7IAhv!FMrcod2U6+zU4NG^dYet=MtD1q3NHWj@2+5A*q1n0LV z(uK*}H#=`OEEHA71Yeo8+BI6MPEqd}+{a8uKdhAl0+aGA( z6gLqLrRPob_)qk0tMXUiuge|}IP@J=^z`Vvs`?d8?$9vrfp75ak{1=#0cAVIvm}O&R6;T{N2S{GCHQ} z63N*!JI=1@|9)yyoVH|N@=EerQq`{_{iK4LX_{~ph2wEJ`V!5S%V?GVPU0xBX&lXM z7SD3~GbXRGk!RCc@-W{_2$ZooGZ5F7X51ywB+kCaSswqAE409|i7i$(w~JJ0-Q{x! zhubv2wSP33nj!{g#jX>(ys@i%n$F^Nj13TbNRo9d&^@_3C(w@_*mOP8VeI5bHod!E zB#X@D)!dG3S|DGQ#XUG)d#rd9UdtGd!I3=pcnlki{e+5OlNSns(}{$G51&n+_rhmJ zPgT^Nss}x>4`ppj4*H}gv-Rwj>{|hG6#Q8!hzQ_Y39J0eqCuefYT43U4T(f?tz5k{l4=aFR6bao7r%s z|4V6Vz=$80HaPw9*{zTJo%%RFyJr4-y*WJDA%~j3LIUYeLgCz#!1tR_<{p-q)EXO< u7(FLq3fJcna*1(2?sTOd+~-KbPTAXMO~oglneZG+;7E+S;Qtfj50d|?qgO8g literal 0 HcmV?d00001