137 lines
5.3 KiB
C++
137 lines
5.3 KiB
C++
#include "app.h"
|
|
#include <cstdint>
|
|
#include <stdexcept>
|
|
#include <vulkan/vulkan.hpp>
|
|
#include <vulkan/vulkan_core.h>
|
|
#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<int>(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();
|
|
}
|