From 83631f940e0ebf857b88f88f20f13de93b5aeb26 Mon Sep 17 00:00:00 2001 From: Mars Date: Sat, 5 Oct 2024 23:08:12 -0400 Subject: [PATCH] resizing works now yay --- src/main.cpp | 141 ++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 105 insertions(+), 36 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index f105a9f..3006221 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -8,6 +8,8 @@ #include #include "util/types.h" + +#define VKFW_NO_STD_FUNCTION_CALLBACKS #include "vkfw.hpp" namespace vk { @@ -17,6 +19,8 @@ namespace vk { constexpr i32 WIDTH = 800; constexpr i32 HEIGHT = 600; +constexpr i32 MAX_FRAMES_IN_FLIGHT = 2; + constexpr std::array validationLayers = { "VK_LAYER_KHRONOS_validation" }; #ifdef __APPLE__ @@ -67,12 +71,15 @@ class VulkanApp { vk::UniquePipelineLayout mPipelineLayout; vk::UniquePipeline mGraphicsPipeline; - vk::UniqueCommandPool mCommandPool; - vk::UniqueCommandBuffer mCommandBuffer; + vk::UniqueCommandPool mCommandPool; + std::vector mCommandBuffers; - vk::UniqueSemaphore mImageAvailableSemaphore; - vk::UniqueSemaphore mRenderFinishedSemaphore; - vk::UniqueFence mInFlightFence; + std::vector mImageAvailableSemaphores; + std::vector mRenderFinishedSemaphores; + std::vector mInFlightFences; + + bool mFramebufferResized = false; + u32 mCurrentFrame = 0; struct QueueFamilyIndices { std::optional graphics_family; @@ -110,9 +117,17 @@ class VulkanApp { vkfw::WindowHints hints; hints.clientAPI = vkfw::ClientAPI::eNone; - hints.resizable = false; + // hints.resizable = false; mWindow = vkfw::createWindowUnique(WIDTH, HEIGHT, "Vulkan", hints); + mWindow->setUserPointer(this); + mWindow->setFramebufferSizeCallback(framebufferResizeCallback); + } + + static fn framebufferResizeCallback(GLFWwindow* window, int /*width*/, int /*height*/) -> void { + auto* app = std::bit_cast(glfwGetWindowUserPointer(window)); + + app->mFramebufferResized = true; } fn initVulkan() -> void { @@ -127,7 +142,7 @@ class VulkanApp { createGraphicsPipeline(); createFramebuffers(); createCommandPool(); - createCommandBuffer(); + createCommandBuffers(); createSyncObjects(); } @@ -140,6 +155,37 @@ class VulkanApp { mDevice->waitIdle(); } + fn cleanupSwapChain() -> void { + for (vk::UniqueHandle& mSwapChainFramebuffer : + mSwapChainFramebuffers) { + mSwapChainFramebuffer.reset(); + } + for (vk::UniqueHandle& mSwapChainImageView : + mSwapChainImageViews) { + mSwapChainImageView.reset(); + } + + mSwapChain.reset(); + } + + fn recreateSwapChain() -> void { + u32 width = 0, height = 0; + std::tie(width, height) = mWindow->getFramebufferSize(); + + while (width == 0 || height == 0) { + std::tie(width, height) = mWindow->getFramebufferSize(); + vkfw::waitEvents(); + } + + mDevice->waitIdle(); + + cleanupSwapChain(); + + createSwapChain(); + createImageViews(); + createFramebuffers(); + } + fn createInstance() -> void { if (enableValidationLayers && !checkValidationLayerSupport()) throw std::runtime_error("Validation layers requested, but not available!"); @@ -489,14 +535,15 @@ class VulkanApp { mCommandPool = mDevice->createCommandPoolUnique(poolInfo); } - fn createCommandBuffer() -> void { - vk::CommandBufferAllocateInfo allocInfo { - .commandPool = mCommandPool.get(), - .level = vk::CommandBufferLevel::ePrimary, - .commandBufferCount = 1, - }; + fn createCommandBuffers() -> void { + mCommandBuffers.resize(MAX_FRAMES_IN_FLIGHT); - mCommandBuffer = std::move(mDevice->allocateCommandBuffersUnique(allocInfo)[0]); + vk::CommandBufferAllocateInfo allocInfo { .commandPool = mCommandPool.get(), + .level = vk::CommandBufferLevel::ePrimary, + .commandBufferCount = + static_cast(mCommandBuffers.size()) }; + + mCommandBuffers = mDevice->allocateCommandBuffersUnique(allocInfo); } fn recordCommandBuffer(vk::CommandBuffer commandBuffer, u32 imageIndex) -> void { @@ -540,55 +587,77 @@ class VulkanApp { } fn createSyncObjects() -> void { + mImageAvailableSemaphores.resize(MAX_FRAMES_IN_FLIGHT); + mRenderFinishedSemaphores.resize(MAX_FRAMES_IN_FLIGHT); + mInFlightFences.resize(MAX_FRAMES_IN_FLIGHT); + vk::SemaphoreCreateInfo semaphoreInfo {}; vk::FenceCreateInfo fenceInfo { .flags = vk::FenceCreateFlagBits::eSignaled }; - mImageAvailableSemaphore = mDevice->createSemaphoreUnique(semaphoreInfo); - mRenderFinishedSemaphore = mDevice->createSemaphoreUnique(semaphoreInfo); - mInFlightFence = mDevice->createFenceUnique(fenceInfo); + for (usize idx = 0; idx < MAX_FRAMES_IN_FLIGHT; idx++) { + mImageAvailableSemaphores[idx] = mDevice->createSemaphoreUnique(semaphoreInfo); + mRenderFinishedSemaphores[idx] = mDevice->createSemaphoreUnique(semaphoreInfo); + mInFlightFences[idx] = mDevice->createFenceUnique(fenceInfo); + } } fn drawFrame() -> void { - vk::Result result = mDevice->waitForFences(mInFlightFence.get(), vk::Bool32(vk::True), UINT64_MAX); + vk::Result result = + mDevice->waitForFences(mInFlightFences[mCurrentFrame].get(), vk::Bool32(vk::True), UINT64_MAX); if (result != vk::Result::eSuccess) throw std::runtime_error("Failed to wait for fences!"); - mDevice->resetFences(mInFlightFence.get()); + vk::ResultValue imageIndex = mDevice->acquireNextImageKHR( + mSwapChain.get(), UINT64_MAX, mImageAvailableSemaphores[mCurrentFrame].get(), nullptr + ); - u32 imageIndex = - mDevice->acquireNextImageKHR(mSwapChain.get(), UINT64_MAX, mImageAvailableSemaphore.get(), nullptr) - .value; + if (imageIndex.result == vk::Result::eErrorOutOfDateKHR) { + recreateSwapChain(); + return; + } - mCommandBuffer->reset(vk::CommandBufferResetFlagBits::eReleaseResources); - recordCommandBuffer(mCommandBuffer.get(), imageIndex); + if (imageIndex.result != vk::Result::eSuccess && imageIndex.result != vk::Result::eSuboptimalKHR) + throw std::runtime_error("Failed to acquire swap chain image!"); + + mDevice->resetFences(mInFlightFences[mCurrentFrame].get()); + + mCommandBuffers[mCurrentFrame]->reset(vk::CommandBufferResetFlagBits::eReleaseResources); + recordCommandBuffer(mCommandBuffers[mCurrentFrame].get(), imageIndex.value); std::array waitStages = { vk::PipelineStageFlagBits::eColorAttachmentOutput }; vk::SubmitInfo submitInfo { .waitSemaphoreCount = 1, - .pWaitSemaphores = &mImageAvailableSemaphore.get(), + .pWaitSemaphores = &mImageAvailableSemaphores[mCurrentFrame].get(), .pWaitDstStageMask = waitStages.data(), .commandBufferCount = 1, - .pCommandBuffers = &mCommandBuffer.get(), + .pCommandBuffers = &mCommandBuffers[mCurrentFrame].get(), .signalSemaphoreCount = 1, - .pSignalSemaphores = &mRenderFinishedSemaphore.get(), + .pSignalSemaphores = &mRenderFinishedSemaphores[mCurrentFrame].get(), }; - mGraphicsQueue.submit(submitInfo, mInFlightFence.get()); + mGraphicsQueue.submit(submitInfo, mInFlightFences[mCurrentFrame].get()); vk::PresentInfoKHR presentInfo { .waitSemaphoreCount = 1, - .pWaitSemaphores = &mRenderFinishedSemaphore.get(), + .pWaitSemaphores = &mRenderFinishedSemaphores[mCurrentFrame].get(), .swapchainCount = 1, .pSwapchains = &mSwapChain.get(), - .pImageIndices = &imageIndex, + .pImageIndices = &imageIndex.value, }; vk::Result presentResult = mPresentQueue.presentKHR(presentInfo); - if (presentResult != vk::Result::eSuccess) + if (presentResult == vk::Result::eErrorOutOfDateKHR || presentResult == vk::Result::eSuboptimalKHR || mFramebufferResized) { + mFramebufferResized = false; + recreateSwapChain(); + } else if (presentResult != vk::Result::eSuccess){ + std::cout << presentResult << '\n'; throw std::runtime_error("Failed to present swap chain image!"); + } + + mCurrentFrame = (mCurrentFrame + 1) % MAX_FRAMES_IN_FLIGHT; } fn createShaderModule(const std::vector& code) -> vk::UniqueShaderModule { @@ -598,8 +667,8 @@ class VulkanApp { return mDevice->createShaderModuleUnique(createInfo); } - static fn chooseSwapSurfaceFormat(const std::vector& availableFormats) - -> vk::SurfaceFormatKHR { + static fn chooseSwapSurfaceFormat(const std::vector& availableFormats + ) -> vk::SurfaceFormatKHR { for (const auto& availableFormat : availableFormats) if (availableFormat.format == vk::Format::eB8G8R8A8Srgb && availableFormat.colorSpace == vk::ColorSpaceKHR::eSrgbNonlinear) @@ -608,8 +677,8 @@ class VulkanApp { return availableFormats[0]; } - static fn chooseSwapPresentMode(const std::vector& availablePresentModes) - -> vk::PresentModeKHR { + static fn chooseSwapPresentMode(const std::vector& availablePresentModes + ) -> vk::PresentModeKHR { for (const auto& availablePresentMode : availablePresentModes) if (availablePresentMode == vk::PresentModeKHR::eMailbox) return availablePresentMode; @@ -738,7 +807,7 @@ fn main() -> i32 { try { app.run(); } catch (const std::exception& e) { - std::cerr << e.what() << std::endl; + fmt::println("{}", e.what()); return EXIT_FAILURE; }