feat: handle resizing

This commit is contained in:
2020-05-31 15:15:03 +02:00
parent 0a034170d9
commit cfb54f0e00
4 changed files with 114 additions and 19 deletions

View File

@@ -10,6 +10,7 @@
#define GLFW_INCLUDE_VULKAN #define GLFW_INCLUDE_VULKAN
#include <GLFW/glfw3.h> #include <GLFW/glfw3.h>
#include <iostream>
#include "queues.h" #include "queues.h"
#include "util.h" #include "util.h"
@@ -31,18 +32,21 @@ void HelloTriangleApplication::run() {
this->myVkInstance = new MyVkInstance(); this->myVkInstance = new MyVkInstance();
this->myVkInstance->init(); this->myVkInstance->init();
initVulkan(); initVulkan();
this->myVkInstance->registerResizeCallback(this, frameBufferResizeCallback);
mainLoop(); mainLoop();
cleanup(); cleanup();
this->myVkInstance->cleanup(); this->myVkInstance->cleanup();
} }
void HelloTriangleApplication::createSwapChain() { void HelloTriangleApplication::createSwapChain() {
int width, height;
uint32_t queueFamilyIndices[] = {myVkInstance->indices.graphicsFamily.value(), myVkInstance->indices.presentFamily.value()}; uint32_t queueFamilyIndices[] = {myVkInstance->indices.graphicsFamily.value(), myVkInstance->indices.presentFamily.value()};
SwapChainSupportDetails swapChainSupportDetails = querySwapChainSupport(myVkInstance->physicalDevice, myVkInstance->surface); SwapChainSupportDetails swapChainSupportDetails = querySwapChainSupport(myVkInstance->physicalDevice, myVkInstance->surface);
VkSurfaceFormatKHR surfaceFormat = chooseSwapSurfaceFormat(swapChainSupportDetails.formats); VkSurfaceFormatKHR surfaceFormat = chooseSwapSurfaceFormat(swapChainSupportDetails.formats);
VkPresentModeKHR presentMode = chooseSwapChainPresentMode(swapChainSupportDetails.presentModes); VkPresentModeKHR presentMode = chooseSwapChainPresentMode(swapChainSupportDetails.presentModes);
VkExtent2D extent = chooseSwapExtent(swapChainSupportDetails.capabilities, WIDTH, HEIGHT); myVkInstance->getFrameBufferSize(&width, &height);
VkExtent2D extent = chooseSwapExtent(swapChainSupportDetails.capabilities, width, height);
uint32_t imageCount = swapChainSupportDetails.capabilities.minImageCount + 1; uint32_t imageCount = swapChainSupportDetails.capabilities.minImageCount + 1;
if (swapChainSupportDetails.capabilities.maxImageCount > 0 && if (swapChainSupportDetails.capabilities.maxImageCount > 0 &&
imageCount > swapChainSupportDetails.capabilities.maxImageCount) { imageCount > swapChainSupportDetails.capabilities.maxImageCount) {
@@ -423,6 +427,44 @@ void HelloTriangleApplication::initVulkan() {
createSyncObjects(); createSyncObjects();
} }
void HelloTriangleApplication::recreateSwapChain() {
frameBufferResized = false;
int width = 0, height = 0;
while (width == 0 || height == 0) {
this->myVkInstance->getFrameBufferSize(&width, &height);
MyVkInstance::waitEvents();
}
vkDeviceWaitIdle(this->myVkInstance->device);
cleanupSwapChain();
createSwapChain();
createImageViews();
createRenderPass();
createGraphicsPipeline();
createFrameBuffers();
createCommandBuffers();
}
void HelloTriangleApplication::cleanupSwapChain() {
for (auto & swapChainFrameBuffer : swapChainFrameBuffers) {
vkDestroyFramebuffer(myVkInstance->device, swapChainFrameBuffer, nullptr);
}
vkFreeCommandBuffers(myVkInstance->device, commandPool, static_cast<uint32_t>(commandBuffers.size()), commandBuffers.data());
vkDestroyPipeline(myVkInstance->device, graphicsPipeline, nullptr);
vkDestroyPipelineLayout(myVkInstance->device, pipelineLayout, nullptr);
vkDestroyRenderPass(myVkInstance->device, renderPass, nullptr);
for (auto imageView : swapChainImageViews) {
vkDestroyImageView(myVkInstance->device, imageView, nullptr);
}
vkDestroySwapchainKHR(myVkInstance->device, swapChain, nullptr);
}
void HelloTriangleApplication::mainLoop() { void HelloTriangleApplication::mainLoop() {
while (!glfwWindowShouldClose(myVkInstance->window)) { while (!glfwWindowShouldClose(myVkInstance->window)) {
glfwPollEvents(); glfwPollEvents();
@@ -434,7 +476,18 @@ void HelloTriangleApplication::mainLoop() {
void HelloTriangleApplication::drawFrame() { void HelloTriangleApplication::drawFrame() {
vkWaitForFences(myVkInstance->device, 1, &inFlightFences[currentFrame], VK_TRUE, UINT64_MAX); vkWaitForFences(myVkInstance->device, 1, &inFlightFences[currentFrame], VK_TRUE, UINT64_MAX);
uint32_t imageIndex; uint32_t imageIndex;
vkAcquireNextImageKHR(myVkInstance->device, swapChain, UINT64_MAX, imageAvailableSemaphores[currentFrame], VK_NULL_HANDLE, &imageIndex); VkResult acquireNextImageResult = vkAcquireNextImageKHR(myVkInstance->device, swapChain, UINT64_MAX,
imageAvailableSemaphores[currentFrame], VK_NULL_HANDLE, &imageIndex);
switch (acquireNextImageResult) {
case VK_ERROR_OUT_OF_DATE_KHR:
recreateSwapChain();
return;
case VK_SUCCESS:
case VK_SUBOPTIMAL_KHR: // todo handle
break;
default:
throw std::runtime_error("Failed to acquire swap chain image!");
}
if (imagesInFlight[currentFrame] != VK_NULL_HANDLE) { if (imagesInFlight[currentFrame] != VK_NULL_HANDLE) {
vkWaitForFences(myVkInstance->device, 1, &imagesInFlight[currentFrame], VK_TRUE, UINT64_MAX); vkWaitForFences(myVkInstance->device, 1, &imagesInFlight[currentFrame], VK_TRUE, UINT64_MAX);
@@ -472,27 +525,35 @@ void HelloTriangleApplication::drawFrame() {
.pResults = nullptr, .pResults = nullptr,
}; };
vkQueuePresentKHR(myVkInstance->presentQueue, &presentInfo); VkResult queuePresentResult = vkQueuePresentKHR(myVkInstance->presentQueue, &presentInfo);
switch (queuePresentResult) {
case VK_ERROR_OUT_OF_DATE_KHR:
case VK_SUBOPTIMAL_KHR:
recreateSwapChain();
break;
case VK_SUCCESS:
break;
default:
throw std::runtime_error("Failed to present queue");
}
if (frameBufferResized) {
recreateSwapChain();
}
// vkQueueWaitIdle(presentQueue); // vkQueueWaitIdle(presentQueue);
currentFrame = (currentFrame + 1) % MAX_FRAMES_IN_FLIGHT; currentFrame = (currentFrame + 1) % MAX_FRAMES_IN_FLIGHT;
} }
void HelloTriangleApplication::cleanup() { void HelloTriangleApplication::cleanup() {
cleanupSwapChain();
for (int i = 0; i < MAX_FRAMES_IN_FLIGHT; ++i) { for (int i = 0; i < MAX_FRAMES_IN_FLIGHT; ++i) {
vkDestroySemaphore(myVkInstance->device, renderFinishedSemaphores[i], nullptr); vkDestroySemaphore(myVkInstance->device, renderFinishedSemaphores[i], nullptr);
vkDestroySemaphore(myVkInstance->device, imageAvailableSemaphores[i], nullptr); vkDestroySemaphore(myVkInstance->device, imageAvailableSemaphores[i], nullptr);
vkDestroyFence(myVkInstance->device, inFlightFences[i], nullptr); vkDestroyFence(myVkInstance->device, inFlightFences[i], nullptr);
} }
vkDestroyCommandPool(myVkInstance->device, commandPool, nullptr); vkDestroyCommandPool(myVkInstance->device, commandPool, nullptr);
for (auto frameBuffer : swapChainFrameBuffers) { }
vkDestroyFramebuffer(myVkInstance->device, frameBuffer, nullptr);
} void HelloTriangleApplication::frameBufferResizeCallback(void* thisptr, int width, int height) {
vkDestroyPipeline(myVkInstance->device, graphicsPipeline, nullptr); static_cast<HelloTriangleApplication*>(thisptr)->frameBufferResized = true;
vkDestroyPipelineLayout(myVkInstance->device, pipelineLayout, nullptr);
vkDestroyRenderPass(myVkInstance->device, renderPass, nullptr);
for (auto imageView : swapChainImageViews) {
vkDestroyImageView(myVkInstance->device, imageView, nullptr);
}
vkDestroySwapchainKHR(myVkInstance->device, swapChain, nullptr);
} }

View File

@@ -14,13 +14,11 @@
const int MAX_FRAMES_IN_FLIGHT = 2; const int MAX_FRAMES_IN_FLIGHT = 2;
const int WIDTH = 800;
const int HEIGHT = 600;
class HelloTriangleApplication { class HelloTriangleApplication {
public: public:
void run(); void run();
bool frameBufferResized = false;
private: private:
MyVkInstance *myVkInstance; MyVkInstance *myVkInstance;
VkSwapchainKHR swapChain; VkSwapchainKHR swapChain;
@@ -43,7 +41,6 @@ private:
int currentFrame = 0; int currentFrame = 0;
// Vulkan initialisation // Vulkan initialisation
void createSurface();
void createSwapChain(); void createSwapChain();
void createImageViews(); void createImageViews();
void createRenderPass(); void createRenderPass();
@@ -54,6 +51,9 @@ private:
void createSyncObjects(); void createSyncObjects();
void initVulkan(); void initVulkan();
void recreateSwapChain();
void cleanupSwapChain();
// main loop // main loop
void mainLoop(); void mainLoop();
void drawFrame(); void drawFrame();
@@ -64,6 +64,7 @@ private:
// utility functions // utility functions
VkShaderModule createShaderModule(const std::vector<char> &code); VkShaderModule createShaderModule(const std::vector<char> &code);
static void frameBufferResizeCallback(void *thisptr, int width, int height);
}; };

View File

@@ -74,7 +74,7 @@ void MyVkInstance::init() {
void MyVkInstance::initWindow() { void MyVkInstance::initWindow() {
glfwInit(); glfwInit();
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE); glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE);
window = glfwCreateWindow(this->width, this->height, this->title.c_str(), nullptr, nullptr); window = glfwCreateWindow(this->width, this->height, this->title.c_str(), nullptr, nullptr);
@@ -197,3 +197,25 @@ void MyVkInstance::cleanup() {
glfwDestroyWindow(window); glfwDestroyWindow(window);
glfwTerminate(); glfwTerminate();
} }
void MyVkInstance::getFrameBufferSize(int *pWidth, int *pHeight) const {
glfwGetFramebufferSize(this->window, pWidth, pHeight);
}
void MyVkInstance::frameBufferResizeCallbackHandler(GLFWwindow *glfwWindow, int mWidth, int mHeight) {
auto ptr = reinterpret_cast<MyVkInstance*>(glfwGetWindowUserPointer(glfwWindow));
ptr->width = mWidth;
ptr->height = mHeight;
if (ptr->framebufferResizeCallback != nullptr) {
ptr->framebufferResizeCallback(ptr->framebufferResizeCallbackThis, mWidth, mHeight);
}
}
void MyVkInstance::registerResizeCallback(void* thisValue, void (*callback)(void*, int, int)) {
this->framebufferResizeCallbackThis = thisValue;
this->framebufferResizeCallback = callback;
}
void MyVkInstance::waitEvents() {
glfwWaitEvents();
}

View File

@@ -20,6 +20,9 @@ public:
void cleanup(); void cleanup();
void getFrameBufferSize(int *pWidth, int *pHeight) const;
void registerResizeCallback(void*, void (*callback)(void*, int, int));
VkInstance instance{}; VkInstance instance{};
VkDevice device{}; VkDevice device{};
VkPhysicalDevice physicalDevice = VK_NULL_HANDLE; VkPhysicalDevice physicalDevice = VK_NULL_HANDLE;
@@ -29,10 +32,15 @@ public:
GLFWwindow* window{}; GLFWwindow* window{};
QueueFamilyIndices indices; QueueFamilyIndices indices;
static void waitEvents();
private: private:
int width{}; int width{};
int height{}; int height{};
std::string title; std::string title;
void *framebufferResizeCallbackThis;
void (*framebufferResizeCallback)(void*, int, int) = nullptr;
#ifdef WITH_VALIDATION_LAYERS #ifdef WITH_VALIDATION_LAYERS
VkDebugUtilsMessengerEXT debugMessenger; VkDebugUtilsMessengerEXT debugMessenger;
@@ -47,6 +55,9 @@ private:
void createSurface(); void createSurface();
void pickPhysicalDevice(); void pickPhysicalDevice();
void createLogicalDevice(); void createLogicalDevice();
static void frameBufferResizeCallbackHandler(GLFWwindow *glfwWindow, int width, int height);
}; };