Browse Source

handle resizing correctly

niki 3 years ago
parent
commit
b80ef89e8d

+ 62 - 26
src/modules/graphics/vulkan/Graphics.cpp

@@ -87,37 +87,22 @@ namespace love {
 			}
 			}
 
 
 			Graphics::~Graphics() {
 			Graphics::~Graphics() {
-				if (init) {
-					for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) {
-						vkDestroySemaphore(device, renderFinishedSemaphores.at(i), nullptr);
-						vkDestroySemaphore(device, imageAvailableSemaphores.at(i), nullptr);
-						vkDestroyFence(device, inFlightFences.at(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) {
 			void Graphics::present(void* screenshotCallbackdata) {
 				vkWaitForFences(device, 1, &inFlightFences[currentFrame], VK_TRUE, UINT64_MAX);
 				vkWaitForFences(device, 1, &inFlightFences[currentFrame], VK_TRUE, UINT64_MAX);
 
 
 				uint32_t imageIndex;
 				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) {
 				if (imagesInFlight[imageIndex] != VK_NULL_HANDLE) {
 					vkWaitForFences(device, 1, &imagesInFlight.at(imageIndex), VK_TRUE, UINT64_MAX);
 					vkWaitForFences(device, 1, &imagesInFlight.at(imageIndex), VK_TRUE, UINT64_MAX);
@@ -158,11 +143,23 @@ namespace love {
 
 
 				presentInfo.pImageIndices = &imageIndex;
 				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;
 				currentFrame = (currentFrame + 1) % MAX_FRAMES_IN_FLIGHT;
 			}
 			}
 
 
+			void Graphics::setViewportSize(int width, int height, int pixelwidth, int pixelheight) {
+				recreateSwapChain();
+			}
+
 			void Graphics::createVulkanInstance() {
 			void Graphics::createVulkanInstance() {
 				if (enableValidationLayers && !checkValidationSupport()) {
 				if (enableValidationLayers && !checkValidationSupport()) {
 					throw love::Exception("validation layers requested, but not available");
 					throw love::Exception("validation layers requested, but not available");
@@ -844,6 +841,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<uint32_t>(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* createInstance() {
 				love::graphics::Graphics* instance = nullptr;
 				love::graphics::Graphics* instance = nullptr;
 
 

+ 5 - 1
src/modules/graphics/vulkan/Graphics.h

@@ -35,7 +35,7 @@ namespace love {
 				Matrix4 computeDeviceProjection(const Matrix4& projection, bool rendertotexture) const override { return Matrix4(); }
 				Matrix4 computeDeviceProjection(const Matrix4& projection, bool rendertotexture) const override { return Matrix4(); }
 				void discard(const std::vector<bool>& colorbuffers, bool depthstencil) override { }
 				void discard(const std::vector<bool>& colorbuffers, bool depthstencil) override { }
 				void present(void* screenshotCallbackdata) 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;  }
 				bool setMode(void* context, int width, int height, int pixelwidth, int pixelheight, bool windowhasstencil, int msaa) override { return false;  }
 				void unSetMode() override {}
 				void unSetMode() override {}
 				void setActive(bool active) override {}
 				void setActive(bool active) override {}
@@ -108,6 +108,9 @@ namespace love {
 				void createCommandPool();
 				void createCommandPool();
 				void createCommandBuffers();
 				void createCommandBuffers();
 				void createSyncObjects();
 				void createSyncObjects();
+				void cleanup();
+				void cleanupSwapChain();
+				void recreateSwapChain();
 
 
 				VkInstance instance;
 				VkInstance instance;
 				VkPhysicalDevice physicalDevice = VK_NULL_HANDLE;
 				VkPhysicalDevice physicalDevice = VK_NULL_HANDLE;
@@ -132,6 +135,7 @@ namespace love {
 				std::vector<VkFence> inFlightFences;
 				std::vector<VkFence> inFlightFences;
 				std::vector<VkFence> imagesInFlight;
 				std::vector<VkFence> imagesInFlight;
 				size_t currentFrame = 0;
 				size_t currentFrame = 0;
+				bool framebufferResized = false;
 			};
 			};
 		}
 		}
 	}
 	}

+ 1 - 1
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;
 		return true;
 
 
 #else
 #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::Graphics* gfx = graphics.get();
 		love::graphics::vulkan::Graphics* vgfx = (love::graphics::vulkan::Graphics*)gfx;
 		love::graphics::vulkan::Graphics* vgfx = (love::graphics::vulkan::Graphics*)gfx;