Browse Source

vulkan: fix validation errors in layout transitions for depth-only and stencil-only images.

Sasha Szpakowski 1 year ago
parent
commit
bbaa55f8b8

+ 43 - 6
src/modules/graphics/vulkan/Graphics.cpp

@@ -396,6 +396,7 @@ void Graphics::submitGpuCommands(SubmitMode submitMode, void *screenshotCallback
 			Vulkan::cmdTransitionImageLayout(
 				commandBuffers.at(currentFrame),
 				swapChainImages.at(imageIndex),
+				swapChainPixelFormat,
 				VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
 				VK_IMAGE_LAYOUT_PRESENT_SRC_KHR);
 		else
@@ -425,6 +426,7 @@ void Graphics::submitGpuCommands(SubmitMode submitMode, void *screenshotCallback
 			Vulkan::cmdTransitionImageLayout(
 				commandBuffers.at(currentFrame),
 				swapChainImages.at(imageIndex),
+				swapChainPixelFormat,
 				VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
 				VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);
 
@@ -447,6 +449,7 @@ void Graphics::submitGpuCommands(SubmitMode submitMode, void *screenshotCallback
 			Vulkan::cmdTransitionImageLayout(
 				commandBuffers.at(currentFrame),
 				swapChainImages.at(imageIndex),
+				swapChainPixelFormat,
 				VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
 				VK_IMAGE_LAYOUT_PRESENT_SRC_KHR);
 		}
@@ -1309,6 +1312,7 @@ void Graphics::beginFrame()
 	Vulkan::cmdTransitionImageLayout(
 		commandBuffers.at(currentFrame),
 		swapChainImages[imageIndex],
+		swapChainPixelFormat,
 		VK_IMAGE_LAYOUT_UNDEFINED,
 		VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
 
@@ -1318,6 +1322,7 @@ void Graphics::beginFrame()
 			Vulkan::cmdTransitionImageLayout(
 				commandBuffers.at(currentFrame),
 				depthImage,
+				depthStencilPixelFormat,
 				VK_IMAGE_LAYOUT_UNDEFINED,
 				VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL);
 
@@ -1325,6 +1330,7 @@ void Graphics::beginFrame()
 			Vulkan::cmdTransitionImageLayout(
 				commandBuffers.at(currentFrame),
 				colorImage,
+				swapChainPixelFormat,
 				VK_IMAGE_LAYOUT_UNDEFINED,
 				VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
 
@@ -1488,6 +1494,18 @@ void Graphics::pickPhysicalDevice()
 	deviceApiVersion = properties.apiVersion;
 
 	depthStencilFormat = findDepthFormat();
+	switch (depthStencilFormat)
+	{
+	case VK_FORMAT_D32_SFLOAT_S8_UINT:
+		depthStencilPixelFormat = PIXELFORMAT_DEPTH32_FLOAT_STENCIL8;
+		break;
+	case VK_FORMAT_D24_UNORM_S8_UINT:
+		depthStencilPixelFormat = PIXELFORMAT_DEPTH24_UNORM_STENCIL8;
+		break;
+	default:
+		throw love::Exception("Failed to convert vulkan depth/stencil swapchain pixel format %d to love PixelFormat.", depthStencilFormat);
+		break;
+	}
 }
 
 bool Graphics::checkDeviceExtensionSupport(VkPhysicalDevice device)
@@ -1877,6 +1895,25 @@ void Graphics::createSwapChain()
 	swapChainImageFormat = surfaceFormat.format;
 	swapChainExtent = extent;
 	preTransform = swapChainSupport.capabilities.currentTransform;
+
+	switch (swapChainImageFormat)
+	{
+	case VK_FORMAT_B8G8R8A8_SRGB:
+		swapChainPixelFormat = PIXELFORMAT_BGRA8_sRGB;
+		break;
+	case VK_FORMAT_B8G8R8A8_UNORM:
+		swapChainPixelFormat = PIXELFORMAT_BGRA8_UNORM;
+		break;
+	case VK_FORMAT_R8G8B8A8_SRGB:
+		swapChainPixelFormat = PIXELFORMAT_RGBA8_sRGB;
+		break;
+	case VK_FORMAT_R8G8B8A8_UNORM:
+		swapChainPixelFormat = PIXELFORMAT_RGBA8_UNORM;
+		break;
+	default:
+		throw love::Exception("Failed to convert vulkan depth/stencil swapchain image format %d to love PixelFormat.", swapChainImageFormat);
+		break;
+	}
 }
 
 VkSurfaceFormatKHR Graphics::chooseSwapSurfaceFormat(const std::vector<VkSurfaceFormatKHR> &availableFormats)
@@ -2438,12 +2475,12 @@ void Graphics::setRenderPass(const RenderTargets &rts, int pixelw, int pixelh, b
 
 	FramebufferConfiguration configuration{};
 
-	std::vector<VkImage> transitionImages;
+	std::vector<std::tuple<VkImage, PixelFormat>> transitionImages;
 
 	for (const auto &color : rts.colors)
 	{
 		configuration.colorViews.push_back(dynamic_cast<Texture*>(color.texture)->getRenderTargetView(color.mipmap, color.slice));
-		transitionImages.push_back((VkImage) color.texture->getHandle());
+		transitionImages.push_back({ (VkImage)color.texture->getHandle(), color.texture->getPixelFormat() });
 	}
 	if (rts.depthStencil.texture != nullptr)
 		configuration.staticData.depthView = dynamic_cast<Texture*>(rts.depthStencil.texture)->getRenderTargetView(rts.depthStencil.mipmap, rts.depthStencil.slice);
@@ -2496,8 +2533,8 @@ void Graphics::startRenderPass()
 	renderPassState.framebufferConfiguration.staticData.renderPass = renderPassState.beginInfo.renderPass;
 	renderPassState.beginInfo.framebuffer = getFramebuffer(renderPassState.framebufferConfiguration);
 
-	for (const auto &image : renderPassState.transitionImages)
-		Vulkan::cmdTransitionImageLayout(commandBuffers.at(currentFrame), image, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
+	for (const auto &[image, format] : renderPassState.transitionImages)
+		Vulkan::cmdTransitionImageLayout(commandBuffers.at(currentFrame), image, format, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
 
 	vkCmdBeginRenderPass(commandBuffers.at(currentFrame), &renderPassState.beginInfo, VK_SUBPASS_CONTENTS_INLINE);
 }
@@ -2508,8 +2545,8 @@ void Graphics::endRenderPass()
 
 	vkCmdEndRenderPass(commandBuffers.at(currentFrame));
 
-	for (const auto &image : renderPassState.transitionImages)
-		Vulkan::cmdTransitionImageLayout(commandBuffers.at(currentFrame), image, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
+	for (const auto &[image, format] : renderPassState.transitionImages)
+		Vulkan::cmdTransitionImageLayout(commandBuffers.at(currentFrame), image, format, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
 
 	for (auto &colorAttachment : renderPassState.renderPassConfiguration.colorAttachments)
 		colorAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;

+ 4 - 2
src/modules/graphics/vulkan/Graphics.h

@@ -37,7 +37,7 @@
 #include <memory>
 #include <functional>
 #include <set>
-
+#include <tuple>
 
 namespace love
 {
@@ -236,7 +236,7 @@ struct RenderpassState
 	RenderPassConfiguration renderPassConfiguration{};
 	FramebufferConfiguration framebufferConfiguration{};
 	VkPipeline pipeline = VK_NULL_HANDLE;
-	std::vector<VkImage> transitionImages;
+	std::vector<std::tuple<VkImage, PixelFormat>> transitionImages;
 	uint32_t numColorAttachments = 0;
 	float width = 0.0f;
 	float height = 0.0f;
@@ -397,7 +397,9 @@ private:
 	Matrix4 displayRotation;
 	std::vector<VkImage> swapChainImages;
 	VkFormat swapChainImageFormat = VK_FORMAT_UNDEFINED;
+	PixelFormat swapChainPixelFormat = PIXELFORMAT_UNKNOWN;
 	VkFormat depthStencilFormat = VK_FORMAT_UNDEFINED;
+	PixelFormat depthStencilPixelFormat = PIXELFORMAT_UNKNOWN;
 	VkExtent2D swapChainExtent = VkExtent2D();
 	std::vector<VkImageView> swapChainImageViews;
 	VkSampleCountFlagBits msaaSamples = VK_SAMPLE_COUNT_1_BIT;

+ 12 - 12
src/modules/graphics/vulkan/Texture.cpp

@@ -158,7 +158,7 @@ bool Texture::loadVolatile()
 		else
 			imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
 
-		Vulkan::cmdTransitionImageLayout(commandBuffer, textureImage,
+		Vulkan::cmdTransitionImageLayout(commandBuffer, textureImage, format,
 			VK_IMAGE_LAYOUT_UNDEFINED, imageLayout,
 			0, VK_REMAINING_MIP_LEVELS,
 			0, VK_REMAINING_ARRAY_LAYERS);
@@ -379,7 +379,7 @@ void Texture::clear()
 
 	if (imageLayout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL)
 	{
-		Vulkan::cmdTransitionImageLayout(commandBuffer, textureImage,
+		Vulkan::cmdTransitionImageLayout(commandBuffer, textureImage, format,
 			VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
 			0, VK_REMAINING_MIP_LEVELS, 0, VK_REMAINING_ARRAY_LAYERS);
 
@@ -387,7 +387,7 @@ void Texture::clear()
 
 		vkCmdClearColorImage(commandBuffer, textureImage, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &clearColor, 1, &range);
 
-		Vulkan::cmdTransitionImageLayout(commandBuffer, textureImage,
+		Vulkan::cmdTransitionImageLayout(commandBuffer, textureImage, format,
 			VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
 			0, VK_REMAINING_MIP_LEVELS, 0, VK_REMAINING_ARRAY_LAYERS);
 	}
@@ -399,7 +399,7 @@ void Texture::clear()
 	}
 	else
 	{
-		Vulkan::cmdTransitionImageLayout(commandBuffer, textureImage,
+		Vulkan::cmdTransitionImageLayout(commandBuffer, textureImage, format,
 			imageLayout, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
 			0, VK_REMAINING_MIP_LEVELS, 0, VK_REMAINING_ARRAY_LAYERS);
 
@@ -409,7 +409,7 @@ void Texture::clear()
 
 		vkCmdClearDepthStencilImage(commandBuffer, textureImage, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &depthStencilColor, 1, &range);
 
-		Vulkan::cmdTransitionImageLayout(commandBuffer, textureImage,
+		Vulkan::cmdTransitionImageLayout(commandBuffer, textureImage, format,
 			VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, imageLayout,
 			0, VK_REMAINING_MIP_LEVELS, 0, VK_REMAINING_ARRAY_LAYERS);
 	}
@@ -449,7 +449,7 @@ void Texture::generateMipmapsInternal()
 	auto commandBuffer = vgfx->getCommandBufferForDataTransfer();
 
 	if (imageLayout != VK_IMAGE_LAYOUT_GENERAL)
-		Vulkan::cmdTransitionImageLayout(commandBuffer, textureImage, 
+		Vulkan::cmdTransitionImageLayout(commandBuffer, textureImage, format,
 			VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 
 			0, static_cast<uint32_t>(getMipmapCount()), 0, static_cast<uint32_t>(layerCount));
 
@@ -575,7 +575,7 @@ void Texture::uploadByteData(const void *data, size_t size, int level, int slice
 
 	if (imageLayout != VK_IMAGE_LAYOUT_GENERAL)
 	{
-		Vulkan::cmdTransitionImageLayout(commandBuffer, textureImage, 
+		Vulkan::cmdTransitionImageLayout(commandBuffer, textureImage, format,
 			imageLayout, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 
 			level, 1, baseLayer, 1);
 
@@ -588,7 +588,7 @@ void Texture::uploadByteData(const void *data, size_t size, int level, int slice
 			&region
 		);
 
-		Vulkan::cmdTransitionImageLayout(commandBuffer, textureImage,
+		Vulkan::cmdTransitionImageLayout(commandBuffer, textureImage, format,
 			VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, imageLayout,
 			level, 1, baseLayer, 1);
 	}
@@ -627,11 +627,11 @@ void Texture::copyFromBuffer(graphics::Buffer *source, size_t sourceoffset, int
 
 	if (imageLayout != VK_IMAGE_LAYOUT_GENERAL)
 	{
-		Vulkan::cmdTransitionImageLayout(commandBuffer, textureImage, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
+		Vulkan::cmdTransitionImageLayout(commandBuffer, textureImage, format, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
 
 		vkCmdCopyBufferToImage(commandBuffer, (VkBuffer)source->getHandle(), textureImage, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &region);
 
-		Vulkan::cmdTransitionImageLayout(commandBuffer, textureImage, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
+		Vulkan::cmdTransitionImageLayout(commandBuffer, textureImage, format, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
 	}
 	else
 		vkCmdCopyBufferToImage(commandBuffer, (VkBuffer)source->getHandle(), textureImage, VK_IMAGE_LAYOUT_GENERAL, 1, &region);
@@ -658,11 +658,11 @@ void Texture::copyToBuffer(graphics::Buffer *dest, int slice, int mipmap, const
 
 	if (imageLayout != VK_IMAGE_LAYOUT_GENERAL)
 	{
-		Vulkan::cmdTransitionImageLayout(commandBuffer, textureImage, imageLayout, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);
+		Vulkan::cmdTransitionImageLayout(commandBuffer, textureImage, format, imageLayout, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);
 
 		vkCmdCopyImageToBuffer(commandBuffer, textureImage, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, (VkBuffer) dest->getHandle(), 1, &region);
 
-		Vulkan::cmdTransitionImageLayout(commandBuffer, textureImage, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, imageLayout);
+		Vulkan::cmdTransitionImageLayout(commandBuffer, textureImage, format, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, imageLayout);
 	}
 	else
 		vkCmdCopyImageToBuffer(commandBuffer, textureImage, VK_IMAGE_LAYOUT_GENERAL, (VkBuffer)dest->getHandle(), 1, &region);

+ 14 - 10
src/modules/graphics/vulkan/Vulkan.cpp

@@ -291,6 +291,9 @@ TextureFormat Vulkan::getTextureFormat(PixelFormat format)
 		textureFormat.internalFormatRepresentation = FORMATREPRESENTATION_UINT;
 		break;
 	case PIXELFORMAT_DEPTH24_UNORM:
+		textureFormat.internalFormat = VK_FORMAT_X8_D24_UNORM_PACK32;
+		textureFormat.internalFormatRepresentation = FORMATREPRESENTATION_UINT;
+		break;
 	case PIXELFORMAT_DEPTH24_UNORM_STENCIL8:
 		textureFormat.internalFormat = VK_FORMAT_D24_UNORM_S8_UINT;
 		textureFormat.internalFormatRepresentation = FORMATREPRESENTATION_UINT;
@@ -816,7 +819,7 @@ VkIndexType Vulkan::getVulkanIndexBufferType(IndexDataType type)
 	}
 }
 
-static void setImageLayoutTransitionOptions(bool previous, VkImageLayout layout, VkAccessFlags &accessMask, VkPipelineStageFlags &stageFlags, bool &depthStencil)
+static void setImageLayoutTransitionOptions(bool previous, VkImageLayout layout, VkAccessFlags &accessMask, VkPipelineStageFlags &stageFlags)
 {
 	switch (layout)
 	{
@@ -838,7 +841,6 @@ static void setImageLayoutTransitionOptions(bool previous, VkImageLayout layout,
 		stageFlags = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
 		break;
 	case VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL:
-		depthStencil = true;
 		accessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT;
 		stageFlags = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
 		break;
@@ -863,7 +865,7 @@ static void setImageLayoutTransitionOptions(bool previous, VkImageLayout layout,
 	}
 }
 
-void Vulkan::cmdTransitionImageLayout(VkCommandBuffer commandBuffer, VkImage image, VkImageLayout oldLayout, VkImageLayout newLayout, uint32_t baseLevel, uint32_t levelCount, uint32_t baseLayer, uint32_t layerCount)
+void Vulkan::cmdTransitionImageLayout(VkCommandBuffer commandBuffer, VkImage image, PixelFormat format, VkImageLayout oldLayout, VkImageLayout newLayout, uint32_t baseLevel, uint32_t levelCount, uint32_t baseLayer, uint32_t layerCount)
 {
 	VkImageMemoryBarrier barrier{};
 	barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
@@ -877,17 +879,19 @@ void Vulkan::cmdTransitionImageLayout(VkCommandBuffer commandBuffer, VkImage ima
 	barrier.subresourceRange.baseArrayLayer = baseLayer;
 	barrier.subresourceRange.layerCount = layerCount;
 
-	bool depthStencil = false;
 	VkPipelineStageFlags sourceStage;
 	VkPipelineStageFlags destinationStage;
 
-	setImageLayoutTransitionOptions(true, oldLayout, barrier.srcAccessMask, sourceStage, depthStencil);
-	setImageLayoutTransitionOptions(false, newLayout, barrier.dstAccessMask, destinationStage, depthStencil);
+	setImageLayoutTransitionOptions(true, oldLayout, barrier.srcAccessMask, sourceStage);
+	setImageLayoutTransitionOptions(false, newLayout, barrier.dstAccessMask, destinationStage);
 
-	if (depthStencil)
-		barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
-	else
-		barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
+	const PixelFormatInfo &info = getPixelFormatInfo(format);
+	if (info.color)
+		barrier.subresourceRange.aspectMask |= VK_IMAGE_ASPECT_COLOR_BIT;
+	if (info.depth)
+		barrier.subresourceRange.aspectMask |= VK_IMAGE_ASPECT_DEPTH_BIT;
+	if (info.stencil)
+		barrier.subresourceRange.aspectMask |= VK_IMAGE_ASPECT_STENCIL_BIT;
 
 	vkCmdPipelineBarrier(
 		commandBuffer,

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

@@ -81,7 +81,7 @@ public:
 	static VkIndexType getVulkanIndexBufferType(IndexDataType type);
 
 	static void cmdTransitionImageLayout(
-		VkCommandBuffer, VkImage, VkImageLayout oldLayout, VkImageLayout newLayout,
+		VkCommandBuffer, VkImage, PixelFormat format, VkImageLayout oldLayout, VkImageLayout newLayout,
 		uint32_t baseLevel = 0, uint32_t levelCount = VK_REMAINING_MIP_LEVELS, uint32_t baseLayer = 0, uint32_t layerCount = VK_REMAINING_ARRAY_LAYERS);
 };