forked from pupbrained/vulkan-test
resizing works now yay
This commit is contained in:
parent
14ca81b3cb
commit
83631f940e
141
src/main.cpp
141
src/main.cpp
|
@ -8,6 +8,8 @@
|
||||||
#include <vulkan/vulkan.hpp>
|
#include <vulkan/vulkan.hpp>
|
||||||
|
|
||||||
#include "util/types.h"
|
#include "util/types.h"
|
||||||
|
|
||||||
|
#define VKFW_NO_STD_FUNCTION_CALLBACKS
|
||||||
#include "vkfw.hpp"
|
#include "vkfw.hpp"
|
||||||
|
|
||||||
namespace vk {
|
namespace vk {
|
||||||
|
@ -17,6 +19,8 @@ namespace vk {
|
||||||
constexpr i32 WIDTH = 800;
|
constexpr i32 WIDTH = 800;
|
||||||
constexpr i32 HEIGHT = 600;
|
constexpr i32 HEIGHT = 600;
|
||||||
|
|
||||||
|
constexpr i32 MAX_FRAMES_IN_FLIGHT = 2;
|
||||||
|
|
||||||
constexpr std::array<const char*, 1> validationLayers = { "VK_LAYER_KHRONOS_validation" };
|
constexpr std::array<const char*, 1> validationLayers = { "VK_LAYER_KHRONOS_validation" };
|
||||||
|
|
||||||
#ifdef __APPLE__
|
#ifdef __APPLE__
|
||||||
|
@ -67,12 +71,15 @@ class VulkanApp {
|
||||||
vk::UniquePipelineLayout mPipelineLayout;
|
vk::UniquePipelineLayout mPipelineLayout;
|
||||||
vk::UniquePipeline mGraphicsPipeline;
|
vk::UniquePipeline mGraphicsPipeline;
|
||||||
|
|
||||||
vk::UniqueCommandPool mCommandPool;
|
vk::UniqueCommandPool mCommandPool;
|
||||||
vk::UniqueCommandBuffer mCommandBuffer;
|
std::vector<vk::UniqueCommandBuffer> mCommandBuffers;
|
||||||
|
|
||||||
vk::UniqueSemaphore mImageAvailableSemaphore;
|
std::vector<vk::UniqueSemaphore> mImageAvailableSemaphores;
|
||||||
vk::UniqueSemaphore mRenderFinishedSemaphore;
|
std::vector<vk::UniqueSemaphore> mRenderFinishedSemaphores;
|
||||||
vk::UniqueFence mInFlightFence;
|
std::vector<vk::UniqueFence> mInFlightFences;
|
||||||
|
|
||||||
|
bool mFramebufferResized = false;
|
||||||
|
u32 mCurrentFrame = 0;
|
||||||
|
|
||||||
struct QueueFamilyIndices {
|
struct QueueFamilyIndices {
|
||||||
std::optional<u32> graphics_family;
|
std::optional<u32> graphics_family;
|
||||||
|
@ -110,9 +117,17 @@ class VulkanApp {
|
||||||
vkfw::WindowHints hints;
|
vkfw::WindowHints hints;
|
||||||
|
|
||||||
hints.clientAPI = vkfw::ClientAPI::eNone;
|
hints.clientAPI = vkfw::ClientAPI::eNone;
|
||||||
hints.resizable = false;
|
// hints.resizable = false;
|
||||||
|
|
||||||
mWindow = vkfw::createWindowUnique(WIDTH, HEIGHT, "Vulkan", hints);
|
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<VulkanApp*>(glfwGetWindowUserPointer(window));
|
||||||
|
|
||||||
|
app->mFramebufferResized = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn initVulkan() -> void {
|
fn initVulkan() -> void {
|
||||||
|
@ -127,7 +142,7 @@ class VulkanApp {
|
||||||
createGraphicsPipeline();
|
createGraphicsPipeline();
|
||||||
createFramebuffers();
|
createFramebuffers();
|
||||||
createCommandPool();
|
createCommandPool();
|
||||||
createCommandBuffer();
|
createCommandBuffers();
|
||||||
createSyncObjects();
|
createSyncObjects();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -140,6 +155,37 @@ class VulkanApp {
|
||||||
mDevice->waitIdle();
|
mDevice->waitIdle();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn cleanupSwapChain() -> void {
|
||||||
|
for (vk::UniqueHandle<vk::Framebuffer, vk::DispatchLoaderStatic>& mSwapChainFramebuffer :
|
||||||
|
mSwapChainFramebuffers) {
|
||||||
|
mSwapChainFramebuffer.reset();
|
||||||
|
}
|
||||||
|
for (vk::UniqueHandle<vk::ImageView, vk::DispatchLoaderStatic>& 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 {
|
fn createInstance() -> void {
|
||||||
if (enableValidationLayers && !checkValidationLayerSupport())
|
if (enableValidationLayers && !checkValidationLayerSupport())
|
||||||
throw std::runtime_error("Validation layers requested, but not available!");
|
throw std::runtime_error("Validation layers requested, but not available!");
|
||||||
|
@ -489,14 +535,15 @@ class VulkanApp {
|
||||||
mCommandPool = mDevice->createCommandPoolUnique(poolInfo);
|
mCommandPool = mDevice->createCommandPoolUnique(poolInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn createCommandBuffer() -> void {
|
fn createCommandBuffers() -> void {
|
||||||
vk::CommandBufferAllocateInfo allocInfo {
|
mCommandBuffers.resize(MAX_FRAMES_IN_FLIGHT);
|
||||||
.commandPool = mCommandPool.get(),
|
|
||||||
.level = vk::CommandBufferLevel::ePrimary,
|
|
||||||
.commandBufferCount = 1,
|
|
||||||
};
|
|
||||||
|
|
||||||
mCommandBuffer = std::move(mDevice->allocateCommandBuffersUnique(allocInfo)[0]);
|
vk::CommandBufferAllocateInfo allocInfo { .commandPool = mCommandPool.get(),
|
||||||
|
.level = vk::CommandBufferLevel::ePrimary,
|
||||||
|
.commandBufferCount =
|
||||||
|
static_cast<u32>(mCommandBuffers.size()) };
|
||||||
|
|
||||||
|
mCommandBuffers = mDevice->allocateCommandBuffersUnique(allocInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn recordCommandBuffer(vk::CommandBuffer commandBuffer, u32 imageIndex) -> void {
|
fn recordCommandBuffer(vk::CommandBuffer commandBuffer, u32 imageIndex) -> void {
|
||||||
|
@ -540,55 +587,77 @@ class VulkanApp {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn createSyncObjects() -> void {
|
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::SemaphoreCreateInfo semaphoreInfo {};
|
||||||
vk::FenceCreateInfo fenceInfo { .flags = vk::FenceCreateFlagBits::eSignaled };
|
vk::FenceCreateInfo fenceInfo { .flags = vk::FenceCreateFlagBits::eSignaled };
|
||||||
|
|
||||||
mImageAvailableSemaphore = mDevice->createSemaphoreUnique(semaphoreInfo);
|
for (usize idx = 0; idx < MAX_FRAMES_IN_FLIGHT; idx++) {
|
||||||
mRenderFinishedSemaphore = mDevice->createSemaphoreUnique(semaphoreInfo);
|
mImageAvailableSemaphores[idx] = mDevice->createSemaphoreUnique(semaphoreInfo);
|
||||||
mInFlightFence = mDevice->createFenceUnique(fenceInfo);
|
mRenderFinishedSemaphores[idx] = mDevice->createSemaphoreUnique(semaphoreInfo);
|
||||||
|
mInFlightFences[idx] = mDevice->createFenceUnique(fenceInfo);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn drawFrame() -> void {
|
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)
|
if (result != vk::Result::eSuccess)
|
||||||
throw std::runtime_error("Failed to wait for fences!");
|
throw std::runtime_error("Failed to wait for fences!");
|
||||||
|
|
||||||
mDevice->resetFences(mInFlightFence.get());
|
vk::ResultValue<uint32_t> imageIndex = mDevice->acquireNextImageKHR(
|
||||||
|
mSwapChain.get(), UINT64_MAX, mImageAvailableSemaphores[mCurrentFrame].get(), nullptr
|
||||||
|
);
|
||||||
|
|
||||||
u32 imageIndex =
|
if (imageIndex.result == vk::Result::eErrorOutOfDateKHR) {
|
||||||
mDevice->acquireNextImageKHR(mSwapChain.get(), UINT64_MAX, mImageAvailableSemaphore.get(), nullptr)
|
recreateSwapChain();
|
||||||
.value;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
mCommandBuffer->reset(vk::CommandBufferResetFlagBits::eReleaseResources);
|
if (imageIndex.result != vk::Result::eSuccess && imageIndex.result != vk::Result::eSuboptimalKHR)
|
||||||
recordCommandBuffer(mCommandBuffer.get(), imageIndex);
|
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<vk::PipelineStageFlags, 1> waitStages = { vk::PipelineStageFlagBits::eColorAttachmentOutput };
|
std::array<vk::PipelineStageFlags, 1> waitStages = { vk::PipelineStageFlagBits::eColorAttachmentOutput };
|
||||||
|
|
||||||
vk::SubmitInfo submitInfo {
|
vk::SubmitInfo submitInfo {
|
||||||
.waitSemaphoreCount = 1,
|
.waitSemaphoreCount = 1,
|
||||||
.pWaitSemaphores = &mImageAvailableSemaphore.get(),
|
.pWaitSemaphores = &mImageAvailableSemaphores[mCurrentFrame].get(),
|
||||||
.pWaitDstStageMask = waitStages.data(),
|
.pWaitDstStageMask = waitStages.data(),
|
||||||
.commandBufferCount = 1,
|
.commandBufferCount = 1,
|
||||||
.pCommandBuffers = &mCommandBuffer.get(),
|
.pCommandBuffers = &mCommandBuffers[mCurrentFrame].get(),
|
||||||
.signalSemaphoreCount = 1,
|
.signalSemaphoreCount = 1,
|
||||||
.pSignalSemaphores = &mRenderFinishedSemaphore.get(),
|
.pSignalSemaphores = &mRenderFinishedSemaphores[mCurrentFrame].get(),
|
||||||
};
|
};
|
||||||
|
|
||||||
mGraphicsQueue.submit(submitInfo, mInFlightFence.get());
|
mGraphicsQueue.submit(submitInfo, mInFlightFences[mCurrentFrame].get());
|
||||||
|
|
||||||
vk::PresentInfoKHR presentInfo {
|
vk::PresentInfoKHR presentInfo {
|
||||||
.waitSemaphoreCount = 1,
|
.waitSemaphoreCount = 1,
|
||||||
.pWaitSemaphores = &mRenderFinishedSemaphore.get(),
|
.pWaitSemaphores = &mRenderFinishedSemaphores[mCurrentFrame].get(),
|
||||||
.swapchainCount = 1,
|
.swapchainCount = 1,
|
||||||
.pSwapchains = &mSwapChain.get(),
|
.pSwapchains = &mSwapChain.get(),
|
||||||
.pImageIndices = &imageIndex,
|
.pImageIndices = &imageIndex.value,
|
||||||
};
|
};
|
||||||
|
|
||||||
vk::Result presentResult = mPresentQueue.presentKHR(presentInfo);
|
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!");
|
throw std::runtime_error("Failed to present swap chain image!");
|
||||||
|
}
|
||||||
|
|
||||||
|
mCurrentFrame = (mCurrentFrame + 1) % MAX_FRAMES_IN_FLIGHT;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn createShaderModule(const std::vector<char>& code) -> vk::UniqueShaderModule {
|
fn createShaderModule(const std::vector<char>& code) -> vk::UniqueShaderModule {
|
||||||
|
@ -598,8 +667,8 @@ class VulkanApp {
|
||||||
return mDevice->createShaderModuleUnique(createInfo);
|
return mDevice->createShaderModuleUnique(createInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
static fn chooseSwapSurfaceFormat(const std::vector<vk::SurfaceFormatKHR>& availableFormats)
|
static fn chooseSwapSurfaceFormat(const std::vector<vk::SurfaceFormatKHR>& availableFormats
|
||||||
-> vk::SurfaceFormatKHR {
|
) -> vk::SurfaceFormatKHR {
|
||||||
for (const auto& availableFormat : availableFormats)
|
for (const auto& availableFormat : availableFormats)
|
||||||
if (availableFormat.format == vk::Format::eB8G8R8A8Srgb &&
|
if (availableFormat.format == vk::Format::eB8G8R8A8Srgb &&
|
||||||
availableFormat.colorSpace == vk::ColorSpaceKHR::eSrgbNonlinear)
|
availableFormat.colorSpace == vk::ColorSpaceKHR::eSrgbNonlinear)
|
||||||
|
@ -608,8 +677,8 @@ class VulkanApp {
|
||||||
return availableFormats[0];
|
return availableFormats[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
static fn chooseSwapPresentMode(const std::vector<vk::PresentModeKHR>& availablePresentModes)
|
static fn chooseSwapPresentMode(const std::vector<vk::PresentModeKHR>& availablePresentModes
|
||||||
-> vk::PresentModeKHR {
|
) -> vk::PresentModeKHR {
|
||||||
for (const auto& availablePresentMode : availablePresentModes)
|
for (const auto& availablePresentMode : availablePresentModes)
|
||||||
if (availablePresentMode == vk::PresentModeKHR::eMailbox)
|
if (availablePresentMode == vk::PresentModeKHR::eMailbox)
|
||||||
return availablePresentMode;
|
return availablePresentMode;
|
||||||
|
@ -738,7 +807,7 @@ fn main() -> i32 {
|
||||||
try {
|
try {
|
||||||
app.run();
|
app.run();
|
||||||
} catch (const std::exception& e) {
|
} catch (const std::exception& e) {
|
||||||
std::cerr << e.what() << std::endl;
|
fmt::println("{}", e.what());
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue