diff --git a/NothinFancy/CMakeLists.txt b/NothinFancy/CMakeLists.txt index ef6762d..a55624e 100644 --- a/NothinFancy/CMakeLists.txt +++ b/NothinFancy/CMakeLists.txt @@ -1,5 +1,5 @@ # NF library CMakeLists.txt -add_library(NothinFancy STATIC "src/Engine.cpp" "src/include/nf.h" "src/pch.h" "src/util.h" "src/util/log.h" "src/util/log.cpp" "src/include/nf/config.h" "src/util/util.cpp" "src/util/file.h" "src/util/file.cpp" "src/client/Client.h" "src/client/Client.cpp" "src/client/Window.h" "src/client/Window.cpp" "src/client/render/RenderEngine.h" "src/client/render/RenderEngine.cpp" "src/client/render/ShaderModule.h" "src/client/render/ShaderModule.cpp") +add_library(NothinFancy STATIC "src/Engine.cpp" "src/include/nf.h" "src/pch.h" "src/util.h" "src/util/log.h" "src/util/log.cpp" "src/include/nf/config.h" "src/util/util.cpp" "src/util/file.h" "src/util/file.cpp" "src/client/Client.h" "src/client/Client.cpp" "src/client/Window.h" "src/client/Window.cpp" "src/client/render/RenderEngine.h" "src/client/render/RenderEngine.cpp" "src/client/render/ShaderModule.h" "src/client/render/ShaderModule.cpp" "src/client/render/VulkanResource.h" "src/client/render/Buffer.h" "src/client/render/Buffer.cpp") # Use C++20 set_property(TARGET NothinFancy PROPERTY CXX_STANDARD 20) diff --git a/NothinFancy/src/client/render/Buffer.cpp b/NothinFancy/src/client/render/Buffer.cpp new file mode 100644 index 0000000..3abfe4b --- /dev/null +++ b/NothinFancy/src/client/render/Buffer.cpp @@ -0,0 +1,110 @@ +// Buffer class implementation +#include "pch.h" + +#include "Buffer.h" +#include "util.h" + +namespace nf::client::render { + Buffer::Buffer(const VkDevice& device, const VkPhysicalDevice& physicalDevice, const VkCommandPool& commandPool, const VkQueue& queue, void* bufferData, size_t bufferSize) + : VulkanResource(device) + , m_handle() + , m_memory() + { + VkBuffer stagingBuffer = nullptr; + VkDeviceMemory stagingBufferMemory = nullptr; + createBuffer(bufferSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, physicalDevice, stagingBuffer, stagingBufferMemory); + + void* bufferPointer = nullptr; + vkMapMemory(m_device, stagingBufferMemory, 0, bufferSize, 0, &bufferPointer); + std::memcpy(bufferPointer, bufferData, bufferSize); + vkUnmapMemory(m_device, stagingBufferMemory); + + createBuffer(bufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, physicalDevice, m_handle, m_memory); + + copyBuffer(stagingBuffer, m_handle, bufferSize, commandPool, queue); + + destroyBuffer(stagingBuffer, stagingBufferMemory); + } + + const VkBuffer& Buffer::getHandle() const { + return m_handle; + } + + void Buffer::createBuffer(VkDeviceSize size, VkBufferUsageFlags usage, VkMemoryPropertyFlags memoryProperties, VkPhysicalDevice physicalDevice, VkBuffer& buffer, VkDeviceMemory& bufferMemory) { + VkBufferCreateInfo bufferCI = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO }; + bufferCI.size = size; + bufferCI.usage = usage; + + if (vkCreateBuffer(m_device, &bufferCI, nullptr, &buffer) != VK_SUCCESS) + NFError("Could not create vertex buffer."); + + VkMemoryRequirements memoryRequirements = {}; + vkGetBufferMemoryRequirements(m_device, buffer, &memoryRequirements); + + VkMemoryAllocateInfo allocateInfo = { VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO }; + allocateInfo.allocationSize = memoryRequirements.size; + allocateInfo.memoryTypeIndex = findMemoryType(physicalDevice, memoryRequirements.memoryTypeBits, memoryProperties); + + if (allocateInfo.memoryTypeIndex == -1) + NFError("Could not find suitable memory type."); + + if (vkAllocateMemory(m_device, &allocateInfo, nullptr, &bufferMemory) != VK_SUCCESS) + NFError("Could not allocate buffer memory."); + + vkBindBufferMemory(m_device, buffer, bufferMemory, 0); + } + + uint32_t Buffer::findMemoryType(VkPhysicalDevice physicalDevice, uint32_t typeFilter, VkMemoryPropertyFlags properties) { + VkPhysicalDeviceMemoryProperties memoryProperties = {}; + vkGetPhysicalDeviceMemoryProperties(physicalDevice, &memoryProperties); + + for (int i = 0; i < memoryProperties.memoryTypeCount; i++) + if (typeFilter & (1 << i) && (memoryProperties.memoryTypes[i].propertyFlags & properties) == properties) + return i; + + return -1; + } + + void Buffer::copyBuffer(VkBuffer bufferSource, VkBuffer bufferDestination, VkDeviceSize size, VkCommandPool commandPool, VkQueue queue) { + VkCommandBuffer commandBuffer = nullptr; + VkCommandBufferAllocateInfo commandBufferAI = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO }; + commandBufferAI.commandPool = commandPool; + commandBufferAI.commandBufferCount = 1; + + if (vkAllocateCommandBuffers(m_device, &commandBufferAI, &commandBuffer) != VK_SUCCESS) + NFError("Could not create command buffer."); + + VkCommandBufferBeginInfo commandBufferBI = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO }; + commandBufferBI.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; + + if (vkBeginCommandBuffer(commandBuffer, &commandBufferBI) != VK_SUCCESS) + NFError("Could not begin recording command buffer."); + + VkBufferCopy bufferCopyRegion = {}; + bufferCopyRegion.size = size; + vkCmdCopyBuffer(commandBuffer, bufferSource, bufferDestination, 1, &bufferCopyRegion); + + if (vkEndCommandBuffer(commandBuffer) != VK_SUCCESS) + NFError("Could not end command buffer."); + + VkSubmitInfo submitInfo = { VK_STRUCTURE_TYPE_SUBMIT_INFO }; + submitInfo.commandBufferCount = 1; + submitInfo.pCommandBuffers = &commandBuffer; + + if (vkQueueSubmit(queue, 1, &submitInfo, nullptr) != VK_SUCCESS) + NFError("Could not submit to Vulkan queue."); + + vkQueueWaitIdle(queue); + + vkFreeCommandBuffers(m_device, commandPool, 1, &commandBuffer); + } + + void Buffer::destroyBuffer(VkBuffer buffer, VkDeviceMemory bufferMemory) { + vkFreeMemory(m_device, bufferMemory, nullptr); + vkDestroyBuffer(m_device, buffer, nullptr); + } + + Buffer::~Buffer() { + destroyBuffer(m_handle, m_memory); + } +} diff --git a/NothinFancy/src/client/render/Buffer.h b/NothinFancy/src/client/render/Buffer.h new file mode 100644 index 0000000..f3d11fa --- /dev/null +++ b/NothinFancy/src/client/render/Buffer.h @@ -0,0 +1,24 @@ +// Buffer class header +#pragma once + +#include "VulkanResource.h" + +namespace nf::client::render { + class Buffer : VulkanResource { + public: + Buffer(const VkDevice& device, const VkPhysicalDevice& physicalDevice, const VkCommandPool& commandPool, const VkQueue& queue, void* bufferData, size_t bufferSize); + + const VkBuffer& getHandle() const; + + ~Buffer(); + private: + void createBuffer(VkDeviceSize size, VkBufferUsageFlags usage, VkMemoryPropertyFlags memoryProperties, VkPhysicalDevice physicalDevice, VkBuffer& buffer, VkDeviceMemory& bufferMemory); + uint32_t findMemoryType(VkPhysicalDevice physicalDevice, uint32_t typeFilter, VkMemoryPropertyFlags properties); + void copyBuffer(VkBuffer sourceBuffer, VkBuffer destinationBuffer, VkDeviceSize size, VkCommandPool commandPool, VkQueue queue); + + void destroyBuffer(VkBuffer buffer, VkDeviceMemory bufferMemory); + + VkBuffer m_handle; + VkDeviceMemory m_memory; + }; +} diff --git a/NothinFancy/src/client/render/RenderEngine.cpp b/NothinFancy/src/client/render/RenderEngine.cpp index 0fd0f3e..4ed4bef 100644 --- a/NothinFancy/src/client/render/RenderEngine.cpp +++ b/NothinFancy/src/client/render/RenderEngine.cpp @@ -37,7 +37,6 @@ namespace nf::client::render { , m_frameExecutors() , m_currentFrameExecutor() , m_bufferVertex() - , m_memoryVertexBuffer() { NFLog("Initializing render engine"); m_window->setDisplay(m_display); @@ -450,100 +449,8 @@ namespace nf::client::render { {{-0.5, 0.5}, {0.0, 0.0, 1.0}} }; - VkBuffer stagingBuffer = nullptr; - VkBufferCreateInfo bufferCI = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO }; - bufferCI.size = sizeof(triangleData[0]) * triangleData.size(); - bufferCI.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT; - - if (vkCreateBuffer(m_device, &bufferCI, nullptr, &stagingBuffer) != VK_SUCCESS) - NFError("Could not create vertex buffer."); - - VkMemoryRequirements memoryRequirements = {}; - vkGetBufferMemoryRequirements(m_device, stagingBuffer, &memoryRequirements); - - VkPhysicalDeviceMemoryProperties memoryProperties = {}; - vkGetPhysicalDeviceMemoryProperties(m_physicalDevice, &memoryProperties); - - VkMemoryPropertyFlags properties = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT; - std::optional memoryTypeIndex; - for (int i = 0; i < memoryProperties.memoryTypeCount; i++) - if (memoryRequirements.memoryTypeBits & (1 << i) && (memoryProperties.memoryTypes[i].propertyFlags & properties) == properties) - memoryTypeIndex = i; - - if (!memoryTypeIndex.has_value()) - NFError("Could not find suitable memory type."); - - VkDeviceMemory stagingBufferMemory = nullptr; - VkMemoryAllocateInfo allocateInfo = { VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO }; - allocateInfo.allocationSize = memoryRequirements.size; - allocateInfo.memoryTypeIndex = memoryTypeIndex.value(); - - if (vkAllocateMemory(m_device, &allocateInfo, nullptr, &stagingBufferMemory) != VK_SUCCESS) - NFError("Could not allocate video memory."); - - vkBindBufferMemory(m_device, stagingBuffer, stagingBufferMemory, 0); - - void* bufferPointer = nullptr; - vkMapMemory(m_device, stagingBufferMemory, 0, bufferCI.size, 0, &bufferPointer); - std::memcpy(bufferPointer, triangleData.data(), bufferCI.size); - vkUnmapMemory(m_device, stagingBufferMemory); - - bufferCI.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT; - if (vkCreateBuffer(m_device, &bufferCI, nullptr, &m_bufferVertex) != VK_SUCCESS) - NFError("Could not create vertex buffer."); - - vkGetBufferMemoryRequirements(m_device, m_bufferVertex, &memoryRequirements); - - properties = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; - memoryTypeIndex.reset(); - for (int i = 0; i < memoryProperties.memoryTypeCount; i++) - if (memoryRequirements.memoryTypeBits & (1 << i) && (memoryProperties.memoryTypes[i].propertyFlags & properties) == properties) - memoryTypeIndex = i; - - if (!memoryTypeIndex.has_value()) - NFError("Could not find suitable memory type."); - - allocateInfo.allocationSize = memoryRequirements.size; - allocateInfo.memoryTypeIndex = memoryTypeIndex.value(); - - if (vkAllocateMemory(m_device, &allocateInfo, nullptr, &m_memoryVertexBuffer) != VK_SUCCESS) - NFError("Could not allocate video memory."); - - vkBindBufferMemory(m_device, m_bufferVertex, m_memoryVertexBuffer, 0); - - VkCommandBuffer commandBuffer = nullptr; - VkCommandBufferAllocateInfo commandBufferAI = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO }; - commandBufferAI.commandPool = m_commandPool; - commandBufferAI.commandBufferCount = 1; - - if (vkAllocateCommandBuffers(m_device, &commandBufferAI, &commandBuffer) != VK_SUCCESS) - NFError("Could not create command buffer."); - - VkCommandBufferBeginInfo commandBufferBI = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO }; - commandBufferBI.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; - - if (vkBeginCommandBuffer(commandBuffer, &commandBufferBI) != VK_SUCCESS) - NFError("Could not begin recording command buffer."); - - VkBufferCopy bufferCopyRegion = {}; - bufferCopyRegion.size = bufferCI.size; - vkCmdCopyBuffer(commandBuffer, stagingBuffer, m_bufferVertex, 1, &bufferCopyRegion); - - if (vkEndCommandBuffer(commandBuffer) != VK_SUCCESS) - NFError("Could not end command buffer."); - - VkSubmitInfo submitInfo = { VK_STRUCTURE_TYPE_SUBMIT_INFO }; - submitInfo.commandBufferCount = 1; - submitInfo.pCommandBuffers = &commandBuffer; - - if (vkQueueSubmit(m_queueGraphics, 1, &submitInfo, nullptr) != VK_SUCCESS) - NFError("Could not submit to Vulkan queue."); - - vkQueueWaitIdle(m_queueGraphics); - - vkFreeCommandBuffers(m_device, m_commandPool, 1, &commandBuffer); - vkFreeMemory(m_device, stagingBufferMemory, nullptr); - vkDestroyBuffer(m_device, stagingBuffer, nullptr); + size_t triangleDataSize = sizeof(triangleData[0]) * triangleData.size(); + m_bufferVertex = new Buffer(m_device, m_physicalDevice, m_commandPool, m_queueGraphics, triangleData.data(), triangleDataSize); } void RenderEngine::doFrame() { @@ -595,7 +502,7 @@ namespace nf::client::render { // Bind vertex buffer VkDeviceSize vertexBufferOffset = 0; - vkCmdBindVertexBuffers(commandBuffer, 0, 1, &m_bufferVertex, &vertexBufferOffset); + vkCmdBindVertexBuffers(commandBuffer, 0, 1, &m_bufferVertex->getHandle(), &vertexBufferOffset); // Draw vkCmdDraw(commandBuffer, 3, 1, 0, 0); @@ -676,8 +583,7 @@ namespace nf::client::render { vkDestroySemaphore(m_device, m_frameExecutors[i].semaphoreImageAvailable, nullptr); } - vkFreeMemory(m_device, m_memoryVertexBuffer, nullptr); - vkDestroyBuffer(m_device, m_bufferVertex, nullptr); + delete m_bufferVertex; destroySwapchain(); vkDestroyCommandPool(m_device, m_commandPool, nullptr); diff --git a/NothinFancy/src/client/render/RenderEngine.h b/NothinFancy/src/client/render/RenderEngine.h index 42e2e0a..e4cd1db 100644 --- a/NothinFancy/src/client/render/RenderEngine.h +++ b/NothinFancy/src/client/render/RenderEngine.h @@ -3,6 +3,7 @@ #include "client/Window.h" #include "nf/config.h" +#include "Buffer.h" namespace nf::client::render { struct FrameExecutor { @@ -67,7 +68,6 @@ namespace nf::client::render { std::vector m_frameExecutors; uint32_t m_currentFrameExecutor; - VkBuffer m_bufferVertex; - VkDeviceMemory m_memoryVertexBuffer; + Buffer* m_bufferVertex; }; } diff --git a/NothinFancy/src/client/render/ShaderModule.cpp b/NothinFancy/src/client/render/ShaderModule.cpp index 6ac5e37..16f231e 100644 --- a/NothinFancy/src/client/render/ShaderModule.cpp +++ b/NothinFancy/src/client/render/ShaderModule.cpp @@ -6,7 +6,7 @@ namespace nf::client::render { ShaderModule::ShaderModule(const VkDevice& device, const std::string& shaderBinary) - : m_device(device) + : VulkanResource(device) , m_shaderModule() { VkShaderModuleCreateInfo shaderModuleCI = { VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO }; diff --git a/NothinFancy/src/client/render/ShaderModule.h b/NothinFancy/src/client/render/ShaderModule.h index 61f4c53..63c642e 100644 --- a/NothinFancy/src/client/render/ShaderModule.h +++ b/NothinFancy/src/client/render/ShaderModule.h @@ -1,8 +1,10 @@ // ShaderModule class header #pragma once +#include "VulkanResource.h" + namespace nf::client::render { - class ShaderModule { + class ShaderModule : VulkanResource { public: ShaderModule(const VkDevice& device, const std::string& shaderBinary); @@ -10,8 +12,6 @@ namespace nf::client::render { ~ShaderModule(); private: - const VkDevice& m_device; - VkShaderModule m_shaderModule; }; } diff --git a/NothinFancy/src/client/render/VulkanResource.h b/NothinFancy/src/client/render/VulkanResource.h new file mode 100644 index 0000000..7700f7e --- /dev/null +++ b/NothinFancy/src/client/render/VulkanResource.h @@ -0,0 +1,14 @@ +// Vulkan resource base class header +#pragma once + +namespace nf::client::render { + class VulkanResource { + public: + VulkanResource(const VkDevice& device) + : m_device(device) + {} + + protected: + const VkDevice& m_device; + }; +}