#include "app.h" #include #include #include #include #include "vulkan/vulkan.hpp" void Application::run() { initWindow(); initVulkan(); mainLoop(); cleanup(); } void Application::initVulkan() { createInstance(); setupDebugMessenger(); createSurface(); pickPhysicalDevice(); createLogicalDevice(); createSwapChain(); createImageViews(); createGraphicsPipeline(); createCommandPool(); createCommandBuffer(); createSyncObjects(); } void Application::mainLoop() { // Loop until the window should be closed while (!glfwWindowShouldClose(m_window)) { // Poll for new window events glfwPollEvents(); // Draw the next frame drawFrame(); } // Once the window is closed, its time to clean up everything. Which once we are out of this function GPU objects // are de-allocated Since there is a high chance the GPU is still working on stuff, we need to wait for the device // to idle before we return. m_device.waitIdle(); } void Application::drawFrame() { // Wait for the previous frame to end auto fenceResult = m_device.waitForFences(*m_inFlightFences[m_frameIndex], vk::True, UINT64_MAX); // Get the next image in the swapchain auto [result, imageIndex] = m_swapchain.acquireNextImage(UINT64_MAX, *m_presentCompleteSemaphores[m_frameIndex], nullptr); // Check to make sure the swapchain didn't report an eErrorOutOfDateKHR error if (result == vk::Result::eErrorOutOfDateKHR) { // Recreate the swapchain recreateSwapchain(); return; } // If the result isn't a eSuccess or eSuboptimalKHR, something has gone wrong and we should report on it. if (result != vk::Result::eSuccess && result != vk::Result::eSuboptimalKHR) { throw std::runtime_error("Failed to acquire next swapchain image"); } // Reset the fence of the current image m_device.resetFences(*m_inFlightFences[m_frameIndex]); // Record the command buffer recordCommandBuffer(imageIndex); // Submit the command buffer to the queue vk::PipelineStageFlags waitDestinationStageMask(vk::PipelineStageFlagBits::eColorAttachmentOutput); const vk::SubmitInfo submitInfo{// Wait for the current frames present semaphore .waitSemaphoreCount = 1, .pWaitSemaphores = &*m_presentCompleteSemaphores[m_frameIndex], // Set our destination .pWaitDstStageMask = &waitDestinationStageMask, // Pass the command buffer/s to submit .commandBufferCount = 1, .pCommandBuffers = &*m_commandBuffers[m_frameIndex], // Pass the rendering semaphore to signal when done .signalSemaphoreCount = 1, .pSignalSemaphores = &*m_renderFinishedSemaphores[imageIndex]}; // Submit to the graphics queue m_queue.submit(submitInfo, *m_inFlightFences[m_frameIndex]); // Present the image try { const vk::PresentInfoKHR presentInfo{ // Wait for the rendering semaphore .waitSemaphoreCount = 1, .pWaitSemaphores = &*m_renderFinishedSemaphores[imageIndex], // Pass the swapchain we want to present with .swapchainCount = 1, .pSwapchains = &*m_swapchain, // Pass the imageIndex of image we want to present in the swapchain .pImageIndices = &imageIndex, .pResults = nullptr // Optional, allows you to specify an array of vk::Result values to check for every // swapchain. We only have one so we can just use the vk::Result returned from the // present function }; result = m_queue.presentKHR(presentInfo); // If the result is eErrorOutOfDateKHR || eSuboptimalKHR || if the windows framebuffer has been resized we need // to recreate the swapchain if (result == vk::Result::eErrorOutOfDateKHR || result == vk::Result::eSuboptimalKHR || m_framebufferResized) { m_framebufferResized = false; recreateSwapchain(); } else if (result != vk::Result::eSuccess) { // If we get any other error, we should error out throw std::runtime_error("Failed to present swapchain image"); } } catch (const vk::SystemError &e) { // There is a chance that a SystemError will be thrown when presenting. The SystemError.code() could also be a // eErrorOutOfDateKHR as well, so that should also be checked for so we can just recreate the swapchain as // normal. All other errors should crash out. if (e.code().value() == static_cast(vk::Result::eErrorOutOfDateKHR)) { recreateSwapchain(); } else { throw; } } // Rotate the frame index m_frameIndex = (m_frameIndex + 1) % MAX_FRAMES_IN_FLIGHT; } void Application::cleanup() { // Destroy the swapchain cleanupSwapchain(); // Destroy the window glfwDestroyWindow(m_window); // Terminate GLFW glfwTerminate(); }