瀏覽代碼

vulkan: populate oldSwapchain field during swap chain creation. Also fix crash if window is already closed, when quitting.

Fixes #2174
Sasha Szpakowski 3 月之前
父節點
當前提交
ae2e68f414
共有 2 個文件被更改,包括 41 次插入9 次删除
  1. 40 8
      src/modules/graphics/vulkan/Graphics.cpp
  2. 1 1
      src/modules/graphics/vulkan/Graphics.h

+ 40 - 8
src/modules/graphics/vulkan/Graphics.cpp

@@ -815,8 +815,13 @@ void Graphics::unSetMode()
 
 
 	created = false;
 	created = false;
 
 
-	cleanupSwapChain();
-	vkDestroySurfaceKHR(instance, surface, nullptr);
+	cleanupSwapChain(true);
+
+	if (surface != VK_NULL_HANDLE)
+	{
+		vkDestroySurfaceKHR(instance, surface, nullptr);
+		surface = VK_NULL_HANDLE;
+	}
 }
 }
 
 
 void Graphics::setActive(bool enable)
 void Graphics::setActive(bool enable)
@@ -2021,18 +2026,34 @@ void Graphics::createSwapChain()
 		createInfo.compositeAlpha = chooseCompositeAlpha(swapChainSupport.capabilities);
 		createInfo.compositeAlpha = chooseCompositeAlpha(swapChainSupport.capabilities);
 		createInfo.presentMode = presentMode;
 		createInfo.presentMode = presentMode;
 		createInfo.clipped = VK_TRUE;
 		createInfo.clipped = VK_TRUE;
-		createInfo.oldSwapchain = VK_NULL_HANDLE;
+		createInfo.oldSwapchain = swapChain;
+
+		VkSwapchainKHR newSwapChain = VK_NULL_HANDLE;
+		VkResult result = vkCreateSwapchainKHR(device, &createInfo, nullptr, &newSwapChain);
 
 
-		VkResult result = vkCreateSwapchainKHR(device, &createInfo, nullptr, &swapChain);
 		if (result != VK_SUCCESS)
 		if (result != VK_SUCCESS)
 			throw love::Exception("Failed to create Vulkan swap chain: %s", Vulkan::getErrorString(result));
 			throw love::Exception("Failed to create Vulkan swap chain: %s", Vulkan::getErrorString(result));
 
 
+		if (swapChain != VK_NULL_HANDLE)
+		{
+			vkDestroySwapchainKHR(device, swapChain, nullptr);
+			swapChain = VK_NULL_HANDLE;
+		}
+
+		swapChain = newSwapChain;
+
 		vkGetSwapchainImagesKHR(device, swapChain, &imageCount, nullptr);
 		vkGetSwapchainImagesKHR(device, swapChain, &imageCount, nullptr);
 		swapChainImages.resize(imageCount);
 		swapChainImages.resize(imageCount);
 		vkGetSwapchainImagesKHR(device, swapChain, &imageCount, swapChainImages.data());
 		vkGetSwapchainImagesKHR(device, swapChain, &imageCount, swapChainImages.data());
 	}
 	}
 	else
 	else
 	{
 	{
+		if (swapChain != VK_NULL_HANDLE)
+		{
+			vkDestroySwapchainKHR(device, swapChain, nullptr);
+			swapChain = VK_NULL_HANDLE;
+		}
+
 		// Use a fake backbuffer. Creation is deferred until startRecordingGraphicsCommands
 		// Use a fake backbuffer. Creation is deferred until startRecordingGraphicsCommands
 		// because newTexture needs an active command buffer to do its initial
 		// because newTexture needs an active command buffer to do its initial
 		// layout transitions.
 		// layout transitions.
@@ -3424,19 +3445,27 @@ void Graphics::cleanup()
 	}
 	}
 }
 }
 
 
-void Graphics::cleanupSwapChain()
+void Graphics::cleanupSwapChain(bool destroySwapChainObject)
 {
 {
 	if (colorImage)
 	if (colorImage)
 	{
 	{
 		cleanupFramebuffers(colorImageView, swapChainPixelFormat);
 		cleanupFramebuffers(colorImageView, swapChainPixelFormat);
+
 		vkDestroyImageView(device, colorImageView, nullptr);
 		vkDestroyImageView(device, colorImageView, nullptr);
+		colorImageView = VK_NULL_HANDLE;
+
 		vmaDestroyImage(vmaAllocator, colorImage, colorImageAllocation);
 		vmaDestroyImage(vmaAllocator, colorImage, colorImageAllocation);
+		colorImage = VK_NULL_HANDLE;
 	}
 	}
 	if (depthImage)
 	if (depthImage)
 	{
 	{
 		cleanupFramebuffers(depthImageView, depthStencilPixelFormat);
 		cleanupFramebuffers(depthImageView, depthStencilPixelFormat);
+
 		vkDestroyImageView(device, depthImageView, nullptr);
 		vkDestroyImageView(device, depthImageView, nullptr);
+		depthImageView = VK_NULL_HANDLE;
+
 		vmaDestroyImage(vmaAllocator, depthImage, depthImageAllocation);
 		vmaDestroyImage(vmaAllocator, depthImage, depthImageAllocation);
+		depthImage = VK_NULL_HANDLE;
 	}
 	}
 	for (const auto &swapChainImageView : swapChainImageViews)
 	for (const auto &swapChainImageView : swapChainImageViews)
 	{
 	{
@@ -3444,18 +3473,21 @@ void Graphics::cleanupSwapChain()
 		vkDestroyImageView(device, swapChainImageView, nullptr);
 		vkDestroyImageView(device, swapChainImageView, nullptr);
 	}
 	}
 	swapChainImageViews.clear();
 	swapChainImageViews.clear();
-	vkDestroySwapchainKHR(device, swapChain, nullptr);
 	swapChainImages.clear();
 	swapChainImages.clear();
 	fakeBackbuffer.set(nullptr);
 	fakeBackbuffer.set(nullptr);
 
 
-	swapChain = VK_NULL_HANDLE;
+	if (destroySwapChainObject && swapChain != VK_NULL_HANDLE)
+	{
+		vkDestroySwapchainKHR(device, swapChain, nullptr);
+		swapChain = VK_NULL_HANDLE;
+	}
 }
 }
 
 
 void Graphics::recreateSwapChain()
 void Graphics::recreateSwapChain()
 {
 {
 	vkDeviceWaitIdle(device);
 	vkDeviceWaitIdle(device);
 
 
-	cleanupSwapChain();
+	cleanupSwapChain(false);
 
 
 	createSwapChain();
 	createSwapChain();
 	createImageViews();
 	createImageViews();

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

@@ -337,7 +337,7 @@ private:
 	void createCommandBuffers();
 	void createCommandBuffers();
 	void createSyncObjects();
 	void createSyncObjects();
 	void cleanup();
 	void cleanup();
-	void cleanupSwapChain();
+	void cleanupSwapChain(bool destroySwapChainObject);
 	void recreateSwapChain();
 	void recreateSwapChain();
 	void initDynamicState();
 	void initDynamicState();
 	void beginSwapChainFrame();
 	void beginSwapChainFrame();