diff --git a/src/modules/graphics/vulkan/Graphics.cpp b/src/modules/graphics/vulkan/Graphics.cpp index 7a0d680a4..f7ed76d97 100644 --- a/src/modules/graphics/vulkan/Graphics.cpp +++ b/src/modules/graphics/vulkan/Graphics.cpp @@ -74,37 +74,22 @@ namespace love { } Graphics::~Graphics() { - if (init) { - for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) { - vkDestroySemaphore(device, renderFinishedSemaphores[i], nullptr); - vkDestroySemaphore(device, imageAvailableSemaphores[i], nullptr); - vkDestroyFence(device, inFlightFences[i], nullptr); - } - if (vkDeviceWaitIdle(device) != VK_SUCCESS) { - throw love::Exception("vkDeviceWaitIdle failed"); - } - vkDestroyCommandPool(device, commandPool, nullptr); - for (auto framebuffer : swapChainFramBuffers) { - vkDestroyFramebuffer(device, framebuffer, nullptr); - } - vkDestroyPipeline(device, graphicsPipeline, nullptr); - vkDestroyPipelineLayout(device, pipelineLayout, nullptr); - vkDestroyRenderPass(device, renderPass, nullptr); - for (auto imageView : swapChainImageViews) { - vkDestroyImageView(device, imageView, nullptr); - } - vkDestroySwapchainKHR(device, swapChain, nullptr); - vkDestroyDevice(device, nullptr); - vkDestroySurfaceKHR(instance, surface, nullptr); - vkDestroyInstance(instance, nullptr); - } + cleanup(); } void Graphics::present(void* screenshotCallbackdata) { vkWaitForFences(device, 1, &inFlightFences[currentFrame], VK_TRUE, UINT64_MAX); uint32_t imageIndex; - vkAcquireNextImageKHR(device, swapChain, UINT64_MAX, imageAvailableSemaphores[currentFrame], VK_NULL_HANDLE, &imageIndex); + VkResult result = vkAcquireNextImageKHR(device, swapChain, UINT64_MAX, imageAvailableSemaphores[currentFrame], VK_NULL_HANDLE, &imageIndex); + + if (result == VK_ERROR_OUT_OF_DATE_KHR) { + recreateSwapChain(); + return; + } + else if (result != VK_SUCCESS && result != VK_SUBOPTIMAL_KHR) { + throw love::Exception("failed to acquire swap chain image"); + } if (imagesInFlight[imageIndex] != VK_NULL_HANDLE) { vkWaitForFences(device, 1, &imagesInFlight[imageIndex], VK_TRUE, UINT64_MAX); @@ -145,11 +130,23 @@ namespace love { presentInfo.pImageIndices = &imageIndex; - vkQueuePresentKHR(presentQueue, &presentInfo); + result = vkQueuePresentKHR(presentQueue, &presentInfo); + + if (result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR || framebufferResized) { + framebufferResized = false; + recreateSwapChain(); + } + else if (result != VK_SUCCESS) { + throw love::Exception("failed to present swap chain image"); + } currentFrame = (currentFrame + 1) % MAX_FRAMES_IN_FLIGHT; } + void Graphics::setViewportSize(int width, int height, int pixelwidth, int pixelheight) { + recreateSwapChain(); + } + void Graphics::createVulkanInstance() { if (enableValidationLayers && !checkValidationSupport()) { throw love::Exception("validation layers requested, but not available"); @@ -831,6 +828,45 @@ namespace love { } } + void Graphics::cleanup() { + cleanupSwapChain(); + + for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) { + vkDestroySemaphore(device, renderFinishedSemaphores[i], nullptr); + vkDestroySemaphore(device, imageAvailableSemaphores[i], nullptr); + vkDestroyFence(device, inFlightFences[i], nullptr); + } + vkDestroyCommandPool(device, commandPool, nullptr); + vkDestroyDevice(device, nullptr); + vkDestroySurfaceKHR(instance, surface, nullptr); + vkDestroyInstance(instance, nullptr); + } + + void Graphics::cleanupSwapChain() { + for (size_t i = 0; i < swapChainFramBuffers.size(); i++) { + vkDestroyFramebuffer(device, swapChainFramBuffers[i], nullptr); + } + vkFreeCommandBuffers(device, commandPool, static_cast(commandBuffers.size()), commandBuffers.data()); + vkDestroyPipeline(device, graphicsPipeline, nullptr); + vkDestroyPipelineLayout(device, pipelineLayout, nullptr); + vkDestroyRenderPass(device, renderPass, nullptr); + for (size_t i = 0; i < swapChainImageViews.size(); i++) { + vkDestroyImageView(device, swapChainImageViews[i], nullptr); + } + vkDestroySwapchainKHR(device, swapChain, nullptr); + } + + void Graphics::recreateSwapChain() { + vkDeviceWaitIdle(device); + + createSwapChain(); + createImageViews(); + createRenderPass(); + createGraphicsPipeline(); + createFramebuffers(); + createCommandBuffers(); + } + love::graphics::Graphics* createInstance() { love::graphics::Graphics* instance = nullptr; diff --git a/src/modules/graphics/vulkan/Graphics.h b/src/modules/graphics/vulkan/Graphics.h index a7a14dc8a..7d8667ec0 100644 --- a/src/modules/graphics/vulkan/Graphics.h +++ b/src/modules/graphics/vulkan/Graphics.h @@ -34,7 +34,7 @@ namespace love { void clear(const std::vector& colors, OptionalInt stencil, OptionalDouble depth) override {} void discard(const std::vector& colorbuffers, bool depthstencil) override {} void present(void* screenshotCallbackdata) override; - void setViewportSize(int width, int height, int pixelwidth, int pixelheight) override {} + void setViewportSize(int width, int height, int pixelwidth, int pixelheight) override; bool setMode(void* context, int width, int height, int pixelwidth, int pixelheight, bool windowhasstencil, int msaa) override { return false; } void unSetMode() override {} void setActive(bool active) override {} @@ -109,6 +109,9 @@ namespace love { void createCommandPool(); void createCommandBuffers(); void createSyncObjects(); + void cleanup(); + void cleanupSwapChain(); + void recreateSwapChain(); VkInstance instance; VkPhysicalDevice physicalDevice = VK_NULL_HANDLE; @@ -133,6 +136,7 @@ namespace love { std::vector inFlightFences; std::vector imagesInFlight; size_t currentFrame = 0; + bool framebufferResized = false; }; } } diff --git a/src/modules/window/sdl/Window.cpp b/src/modules/window/sdl/Window.cpp index 1e150bca6..1b8fbbe17 100644 --- a/src/modules/window/sdl/Window.cpp +++ b/src/modules/window/sdl/Window.cpp @@ -378,7 +378,7 @@ bool Window::createWindowAndContext(int x, int y, int w, int h, Uint32 windowfla return true; #else - window = SDL_CreateWindow(title.c_str(), x, y, w, h, SDL_WINDOW_VULKAN); + window = SDL_CreateWindow(title.c_str(), x, y, w, h, windowflags | SDL_WINDOW_VULKAN); love::graphics::Graphics* gfx = graphics.get(); love::graphics::vulkan::Graphics* vgfx = (love::graphics::vulkan::Graphics*)gfx;