feat: handle resizing
This commit is contained in:
@@ -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);
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -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();
|
||||||
|
}
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user