From 038396338ebb5a013fc1a0c9a769786b17259e54 Mon Sep 17 00:00:00 2001 From: Pasha Bibko <156938226+PashaBibko@users.noreply.github.com> Date: Sun, 16 Nov 2025 17:06:24 +0000 Subject: [PATCH] Finished basic Vulkan setup --- CMakeLists.txt | 3 +- main.cpp | 3 + src/VulkanRenderer.h | 1 + src/managers/VulkanManager.h | 9 +++ ...ulkanManager.cpp => VulkanManagerInit.cpp} | 47 ++++++++---- src/managers/VulkanManagerRender.cpp | 76 +++++++++++++++++++ 6 files changed, 125 insertions(+), 14 deletions(-) rename src/managers/{VulkanManager.cpp => VulkanManagerInit.cpp} (93%) create mode 100644 src/managers/VulkanManagerRender.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index bb4a50e..4f0102b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -33,7 +33,8 @@ add_executable(VulkanRenderer main.cpp src/managers/GLFWManager.h src/managers/GLFWManager.cpp - src/managers/VulkanManager.cpp + src/managers/VulkanManagerInit.cpp + src/managers/VulkanManagerRender.cpp src/managers/VulkanManager.h src/VulkanRenderer.h ) diff --git a/main.cpp b/main.cpp index 6a36d5b..697dcfe 100644 --- a/main.cpp +++ b/main.cpp @@ -37,6 +37,9 @@ int main() while (!glfwWindowShouldClose(window)) { glfwPollEvents(); + + if (!VulkanManager::RenderPass(window)) + CleanupAllAndExit(EXIT_FAILURE); } /* Cleans up GLFW and Vulkan */ diff --git a/src/VulkanRenderer.h b/src/VulkanRenderer.h index 0d6c381..330dcb0 100644 --- a/src/VulkanRenderer.h +++ b/src/VulkanRenderer.h @@ -9,6 +9,7 @@ /* Commonly used C++ STD files */ +#include #include #include #include diff --git a/src/managers/VulkanManager.h b/src/managers/VulkanManager.h index 672523c..1b1fc42 100644 --- a/src/managers/VulkanManager.h +++ b/src/managers/VulkanManager.h @@ -25,6 +25,9 @@ namespace PB::Renderer class VulkanManager { public: + VulkanManager() = delete; + ~VulkanManager() = delete; + static bool InitAll(GLFWwindow* window); static std::optional Init(); static bool Cleanup(); @@ -38,6 +41,9 @@ namespace PB::Renderer static bool CreateFramebuffer(); static bool CreateGraphicsPipeline(); static bool CreateCommandBuffers(); + static void CreateSemaphores(); + + static bool RenderPass(GLFWwindow* window); private: static bool IsDeviceSuitable(VkPhysicalDevice device, VkSurfaceKHR surface); @@ -76,5 +82,8 @@ namespace PB::Renderer static VkCommandPool s_CommandPool; static std::vector s_CommandBuffers; + + static VkSemaphore s_ImageAvailableSemaphore; + static VkSemaphore s_RenderFinishedSemaphore; }; } diff --git a/src/managers/VulkanManager.cpp b/src/managers/VulkanManagerInit.cpp similarity index 93% rename from src/managers/VulkanManager.cpp rename to src/managers/VulkanManagerInit.cpp index 83ef66b..2792d80 100644 --- a/src/managers/VulkanManager.cpp +++ b/src/managers/VulkanManagerInit.cpp @@ -28,6 +28,9 @@ namespace PB::Renderer VkCommandPool VulkanManager::s_CommandPool = VK_NULL_HANDLE; std::vector VulkanManager::s_CommandBuffers = {}; + VkSemaphore VulkanManager::s_ImageAvailableSemaphore = VK_NULL_HANDLE; + VkSemaphore VulkanManager::s_RenderFinishedSemaphore = VK_NULL_HANDLE; + bool VulkanManager::InitAll(GLFWwindow* window) { if (const std::optional instance = VulkanManager::Init(); !instance) @@ -37,19 +40,19 @@ namespace PB::Renderer return false; if (!( - VulkanManager::PickPhysicalDevice() || - VulkanManager::PickPhysicalDevice() || - VulkanManager::CreateLogicalDevice() || - VulkanManager::CreateSwapChain(window) || - VulkanManager::CreateImageViews() || - VulkanManager::CreateRenderPass() || - VulkanManager::CreateFramebuffer() || - VulkanManager::CreateGraphicsPipeline() || + VulkanManager::PickPhysicalDevice() && + VulkanManager::CreateLogicalDevice() && + VulkanManager::CreateSwapChain(window) && + VulkanManager::CreateImageViews() && + VulkanManager::CreateRenderPass() && + VulkanManager::CreateFramebuffer() && + VulkanManager::CreateGraphicsPipeline() && VulkanManager::CreateCommandBuffers() )) { return false; } + VulkanManager::CreateSemaphores(); return true; } @@ -533,8 +536,8 @@ namespace PB::Renderer bool VulkanManager::CreateGraphicsPipeline() { - VkShaderModule vertShaderModule = CreateShaderModule("shaders/vert.spv"); - VkShaderModule fragShaderModule = CreateShaderModule("shaders/frag.spv"); + VkShaderModule vertShaderModule = CreateShaderModule("../shaders/vert.spv"); + VkShaderModule fragShaderModule = CreateShaderModule("../shaders/frag.spv"); VkPipelineShaderStageCreateInfo vertShaderStageInfo{}; vertShaderStageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; @@ -641,7 +644,8 @@ namespace PB::Renderer std::ifstream file(filename, std::ios::ate | std::ios::binary); if (!file.is_open()) { - throw std::runtime_error("Failed to open shader file: " + filename); + std::cout << "Failed to open shader file at '" << std::filesystem::absolute(filename) << "'" << std::endl; + return VK_NULL_HANDLE; } const size_t fileSize = file.tellg(); @@ -666,6 +670,14 @@ namespace PB::Renderer bool VulkanManager::CreateCommandBuffers() { + VkCommandPoolCreateInfo poolInfo{}; + poolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; + poolInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; + poolInfo.queueFamilyIndex = s_QueueIndices.graphicsFamily.value(); + + if (vkCreateCommandPool(s_Device, &poolInfo, nullptr, &s_CommandPool) != VK_SUCCESS) + return false; + s_CommandBuffers.resize(s_Framebuffers.size()); VkCommandBufferAllocateInfo allocInfo{}; @@ -674,7 +686,7 @@ namespace PB::Renderer allocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; allocInfo.commandBufferCount = static_cast(s_CommandBuffers.size()); - if (vkAllocateCommandBuffers(s_Device, &allocInfo, s_CommandBuffers.data()) != VK_SUCCESS) + if (vkAllocateCommandBuffers(s_Device, &allocInfo, s_CommandBuffers.data()) != VK_SUCCESS) // <- Crashes here return false; for (size_t i = 0; i < s_CommandBuffers.size(); i++) @@ -691,7 +703,7 @@ namespace PB::Renderer renderPassInfo.renderArea.offset = {0, 0}; renderPassInfo.renderArea.extent = s_SwapChainExtent; - VkClearValue clearColor = {{{0.0f, 0.0f, 0.0f, 1.0f}}}; + VkClearValue clearColor = {0.0f, 0.0f, 0.0f, 1.0f}; renderPassInfo.clearValueCount = 1; renderPassInfo.pClearValues = &clearColor; @@ -709,4 +721,13 @@ namespace PB::Renderer return true; } + + void VulkanManager::CreateSemaphores() + { + VkSemaphoreCreateInfo createInfo{}; + createInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; + + vkCreateSemaphore(s_Device, &createInfo, nullptr, &s_ImageAvailableSemaphore); + vkCreateSemaphore(s_Device, &createInfo, nullptr, &s_RenderFinishedSemaphore); + } } diff --git a/src/managers/VulkanManagerRender.cpp b/src/managers/VulkanManagerRender.cpp new file mode 100644 index 0000000..619f748 --- /dev/null +++ b/src/managers/VulkanManagerRender.cpp @@ -0,0 +1,76 @@ +#include "VulkanManager.h" + +namespace PB::Renderer +{ + bool VulkanManager::RenderPass(GLFWwindow* window) + { + uint32_t imageIndex; + VkResult result = vkAcquireNextImageKHR( + s_Device, + s_SwapChain, + UINT64_MAX, + s_ImageAvailableSemaphore, + VK_NULL_HANDLE, + &imageIndex + ); + + if (result == VK_ERROR_OUT_OF_DATE_KHR) + { + return false; + } + + if (result != VK_SUCCESS && result != VK_SUBOPTIMAL_KHR) + { + std::cout << "PB::Renderer::VulkanManager::RenderPass(): Failed to acquire swap chain image!" << std::endl; + return false; + } + + VkSubmitInfo submitInfo{}; + submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; + + VkSemaphore waitSemaphores[] = { s_ImageAvailableSemaphore }; + VkPipelineStageFlags waitStages[] = { VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT }; + submitInfo.waitSemaphoreCount = 1; + submitInfo.pWaitSemaphores = waitSemaphores; + submitInfo.pWaitDstStageMask = waitStages; + + submitInfo.commandBufferCount = 1; + submitInfo.pCommandBuffers = &s_CommandBuffers[imageIndex]; + + VkSemaphore signalSemaphores[] = { s_RenderFinishedSemaphore }; + submitInfo.signalSemaphoreCount = 1; + submitInfo.pSignalSemaphores = signalSemaphores; + + if (vkQueueSubmit(s_GraphicsQueue, 1, &submitInfo, VK_NULL_HANDLE) != VK_SUCCESS) + { + std::cout << "PB::Renderer::VulkanManager::RenderPass(): Failed to submit draw command buffer!" << std::endl; + return false; + } + + VkPresentInfoKHR presentInfo{}; + presentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR; + presentInfo.waitSemaphoreCount = 1; + presentInfo.pWaitSemaphores = signalSemaphores; + + VkSwapchainKHR swapChains[] = { s_SwapChain }; + presentInfo.swapchainCount = 1; + presentInfo.pSwapchains = swapChains; + presentInfo.pImageIndices = &imageIndex; + + result = vkQueuePresentKHR(s_PresentQueue, &presentInfo); + + if (result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR) + { + return false; + } + + else if (result != VK_SUCCESS) + { + std::cout << "PB::Renderer::VulkanManager::RenderPass(): Failed to present swap chain image!" << std::endl; + return false; + } + + vkQueueWaitIdle(s_PresentQueue); + return true; + } +}