From bbaa55f8b8f6bc93fcffa191a4f8654d7980ac06 Mon Sep 17 00:00:00 2001 From: Sasha Szpakowski Date: Thu, 21 Mar 2024 21:32:03 -0300 Subject: [PATCH] vulkan: fix validation errors in layout transitions for depth-only and stencil-only images. --- src/modules/graphics/vulkan/Graphics.cpp | 49 +++++++++++++++++++++--- src/modules/graphics/vulkan/Graphics.h | 6 ++- src/modules/graphics/vulkan/Texture.cpp | 24 ++++++------ src/modules/graphics/vulkan/Vulkan.cpp | 24 +++++++----- src/modules/graphics/vulkan/Vulkan.h | 2 +- 5 files changed, 74 insertions(+), 31 deletions(-) diff --git a/src/modules/graphics/vulkan/Graphics.cpp b/src/modules/graphics/vulkan/Graphics.cpp index b8a56b06c..a00d6dc6c 100644 --- a/src/modules/graphics/vulkan/Graphics.cpp +++ b/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 &availableFormats) @@ -2438,12 +2475,12 @@ void Graphics::setRenderPass(const RenderTargets &rts, int pixelw, int pixelh, b FramebufferConfiguration configuration{}; - std::vector transitionImages; + std::vector> transitionImages; for (const auto &color : rts.colors) { configuration.colorViews.push_back(dynamic_cast(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(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; diff --git a/src/modules/graphics/vulkan/Graphics.h b/src/modules/graphics/vulkan/Graphics.h index d33a889fd..ca8b8e3a5 100644 --- a/src/modules/graphics/vulkan/Graphics.h +++ b/src/modules/graphics/vulkan/Graphics.h @@ -37,7 +37,7 @@ #include #include #include - +#include namespace love { @@ -236,7 +236,7 @@ struct RenderpassState RenderPassConfiguration renderPassConfiguration{}; FramebufferConfiguration framebufferConfiguration{}; VkPipeline pipeline = VK_NULL_HANDLE; - std::vector transitionImages; + std::vector> transitionImages; uint32_t numColorAttachments = 0; float width = 0.0f; float height = 0.0f; @@ -397,7 +397,9 @@ private: Matrix4 displayRotation; std::vector swapChainImages; VkFormat swapChainImageFormat = VK_FORMAT_UNDEFINED; + PixelFormat swapChainPixelFormat = PIXELFORMAT_UNKNOWN; VkFormat depthStencilFormat = VK_FORMAT_UNDEFINED; + PixelFormat depthStencilPixelFormat = PIXELFORMAT_UNKNOWN; VkExtent2D swapChainExtent = VkExtent2D(); std::vector swapChainImageViews; VkSampleCountFlagBits msaaSamples = VK_SAMPLE_COUNT_1_BIT; diff --git a/src/modules/graphics/vulkan/Texture.cpp b/src/modules/graphics/vulkan/Texture.cpp index a728b0212..7400a1464 100644 --- a/src/modules/graphics/vulkan/Texture.cpp +++ b/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(getMipmapCount()), 0, static_cast(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 ®ion ); - 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, ®ion); - 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, ®ion); @@ -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, ®ion); - 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, ®ion); diff --git a/src/modules/graphics/vulkan/Vulkan.cpp b/src/modules/graphics/vulkan/Vulkan.cpp index 576308eae..f73f1f5cc 100644 --- a/src/modules/graphics/vulkan/Vulkan.cpp +++ b/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, diff --git a/src/modules/graphics/vulkan/Vulkan.h b/src/modules/graphics/vulkan/Vulkan.h index f148ef730..7e4db7c70 100644 --- a/src/modules/graphics/vulkan/Vulkan.h +++ b/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); };