From 2c848ab44b389a145c22cba2aae2b086fe31a25d Mon Sep 17 00:00:00 2001 From: Swung0x48 Date: Fri, 27 Feb 2026 09:44:23 +0800 Subject: [PATCH] [Chore] (MG_Backend/DirectVulkan): move `TransitionImageLayout` to VkTextureManager --- .../Renderer/VkRenderTargetManager.cpp | 56 +++--------- .../Renderer/VkRenderTargetManager.h | 4 - .../Renderer/VkTextureManager.cpp | 85 +++++++++++-------- .../DirectVulkan/Renderer/VkTextureManager.h | 5 ++ 4 files changed, 67 insertions(+), 83 deletions(-) diff --git a/MobileGL/MG_Backend/DirectVulkan/Renderer/VkRenderTargetManager.cpp b/MobileGL/MG_Backend/DirectVulkan/Renderer/VkRenderTargetManager.cpp index 1a50c3f9..78a57e8a 100644 --- a/MobileGL/MG_Backend/DirectVulkan/Renderer/VkRenderTargetManager.cpp +++ b/MobileGL/MG_Backend/DirectVulkan/Renderer/VkRenderTargetManager.cpp @@ -8,6 +8,8 @@ #include "VkRenderTargetManager.h" +#include "VkTextureManager.h" + #include #include @@ -68,7 +70,7 @@ namespace MobileGL::MG_Backend::DirectVulkan { continue; } const Bool fromUndefined = (target.layout == VK_IMAGE_LAYOUT_UNDEFINED); - return TransitionImageLayout( + return VkTextureManager::TransitionImageLayout( commandBuffer, target.image, target.layout, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, fromUndefined ? VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT @@ -90,7 +92,7 @@ namespace MobileGL::MG_Backend::DirectVulkan { if (resource == TransitionResource::OffscreenColor) { switch (usage) { case TransitionUsage::Attachment: { - if (!TransitionImageLayout( + if (!VkTextureManager::TransitionImageLayout( commandBuffer, target.image, target.layout, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, 0, VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, @@ -101,7 +103,7 @@ namespace MobileGL::MG_Backend::DirectVulkan { return true; } const VkImageAspectFlags aspectMask = resolveDepthStencilAspectMask(target.depthStencilFormat); - return TransitionImageLayout( + return VkTextureManager::TransitionImageLayout( commandBuffer, target.depthStencilImage, target.depthStencilLayout, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT, 0, @@ -109,22 +111,22 @@ namespace MobileGL::MG_Backend::DirectVulkan { aspectMask); } case TransitionUsage::TransferSrc: - return TransitionImageLayout(commandBuffer, target.image, target.layout, + return VkTextureManager::TransitionImageLayout(commandBuffer, target.image, target.layout, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, VK_ACCESS_TRANSFER_READ_BIT, VK_IMAGE_ASPECT_COLOR_BIT); case TransitionUsage::TransferDst: - return TransitionImageLayout(commandBuffer, target.image, target.layout, + return VkTextureManager::TransitionImageLayout(commandBuffer, target.image, target.layout, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, VK_ACCESS_TRANSFER_WRITE_BIT, VK_IMAGE_ASPECT_COLOR_BIT); case TransitionUsage::General: - return TransitionImageLayout(commandBuffer, target.image, target.layout, VK_IMAGE_LAYOUT_GENERAL, + return VkTextureManager::TransitionImageLayout(commandBuffer, target.image, target.layout, VK_IMAGE_LAYOUT_GENERAL, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, VK_ACCESS_TRANSFER_READ_BIT | VK_ACCESS_TRANSFER_WRITE_BIT, VK_IMAGE_ASPECT_COLOR_BIT); case TransitionUsage::ShaderRead: - return TransitionImageLayout(commandBuffer, target.image, target.layout, + return VkTextureManager::TransitionImageLayout(commandBuffer, target.image, target.layout, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0, VK_ACCESS_SHADER_READ_BIT, VK_IMAGE_ASPECT_COLOR_BIT); @@ -140,22 +142,22 @@ namespace MobileGL::MG_Backend::DirectVulkan { const VkImageAspectFlags aspectMask = resolveDepthStencilAspectMask(target.depthStencilFormat); switch (usage) { case TransitionUsage::TransferSrc: - return TransitionImageLayout(commandBuffer, target.depthStencilImage, target.depthStencilLayout, + return VkTextureManager::TransitionImageLayout(commandBuffer, target.depthStencilImage, target.depthStencilLayout, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, VK_ACCESS_TRANSFER_READ_BIT, aspectMask); case TransitionUsage::TransferDst: - return TransitionImageLayout(commandBuffer, target.depthStencilImage, target.depthStencilLayout, + return VkTextureManager::TransitionImageLayout(commandBuffer, target.depthStencilImage, target.depthStencilLayout, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, VK_ACCESS_TRANSFER_WRITE_BIT, aspectMask); case TransitionUsage::General: - return TransitionImageLayout(commandBuffer, target.depthStencilImage, target.depthStencilLayout, + return VkTextureManager::TransitionImageLayout(commandBuffer, target.depthStencilImage, target.depthStencilLayout, VK_IMAGE_LAYOUT_GENERAL, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, VK_ACCESS_TRANSFER_READ_BIT | VK_ACCESS_TRANSFER_WRITE_BIT, aspectMask); case TransitionUsage::Attachment: - return TransitionImageLayout( + return VkTextureManager::TransitionImageLayout( commandBuffer, target.depthStencilImage, target.depthStencilLayout, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT, 0, @@ -369,38 +371,6 @@ namespace MobileGL::MG_Backend::DirectVulkan { target.colorTextureExternalIndex = 0; } - Bool VkRenderTargetManager::TransitionImageLayout(VkCommandBuffer commandBuffer, VkImage image, - VkImageLayout& trackedLayout, VkImageLayout newLayout, - VkPipelineStageFlags srcStageMask, - VkPipelineStageFlags dstStageMask, VkAccessFlags srcAccessMask, - VkAccessFlags dstAccessMask, VkImageAspectFlags aspectMask) { - if (image == VK_NULL_HANDLE) { - return false; - } - if (trackedLayout == newLayout) { - return true; - } - - VkImageMemoryBarrier barrier{}; - barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; - barrier.srcAccessMask = srcAccessMask; - barrier.dstAccessMask = dstAccessMask; - barrier.oldLayout = trackedLayout; - barrier.newLayout = newLayout; - barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - barrier.image = image; - barrier.subresourceRange.aspectMask = aspectMask; - barrier.subresourceRange.baseMipLevel = 0; - barrier.subresourceRange.levelCount = 1; - barrier.subresourceRange.baseArrayLayer = 0; - barrier.subresourceRange.layerCount = 1; - vkCmdPipelineBarrier(commandBuffer, srcStageMask, dstStageMask, 0, 0, nullptr, 0, nullptr, 1, &barrier); - - trackedLayout = newLayout; - return true; - } - VkFormat VkRenderTargetManager::ResolveColorFormat( const MG_State::GLState::FramebufferAttachmentObject& colorAttachment) { TextureInternalFormat internalFormat = TextureInternalFormat::Unknown; diff --git a/MobileGL/MG_Backend/DirectVulkan/Renderer/VkRenderTargetManager.h b/MobileGL/MG_Backend/DirectVulkan/Renderer/VkRenderTargetManager.h index c586e8cf..f7c73ef0 100644 --- a/MobileGL/MG_Backend/DirectVulkan/Renderer/VkRenderTargetManager.h +++ b/MobileGL/MG_Backend/DirectVulkan/Renderer/VkRenderTargetManager.h @@ -75,10 +75,6 @@ namespace MobileGL::MG_Backend::DirectVulkan { const MG_State::GLState::FramebufferAttachmentObject& colorAttachment, Uint16 glObjectVersion); void DestroyOffscreenColorTarget(OffscreenColorTarget& target); - static Bool TransitionImageLayout(VkCommandBuffer commandBuffer, VkImage image, VkImageLayout& trackedLayout, - VkImageLayout newLayout, VkPipelineStageFlags srcStageMask, - VkPipelineStageFlags dstStageMask, VkAccessFlags srcAccessMask, - VkAccessFlags dstAccessMask, VkImageAspectFlags aspectMask); static VkFormat ResolveColorFormat(const MG_State::GLState::FramebufferAttachmentObject& colorAttachment); static VkFormat ResolveDepthStencilFormat( const MG_State::GLState::FramebufferAttachmentObject& depthAttachment, diff --git a/MobileGL/MG_Backend/DirectVulkan/Renderer/VkTextureManager.cpp b/MobileGL/MG_Backend/DirectVulkan/Renderer/VkTextureManager.cpp index 334e38e8..056cab11 100644 --- a/MobileGL/MG_Backend/DirectVulkan/Renderer/VkTextureManager.cpp +++ b/MobileGL/MG_Backend/DirectVulkan/Renderer/VkTextureManager.cpp @@ -65,6 +65,36 @@ namespace MobileGL::MG_Backend::DirectVulkan { outImageInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; return true; } + Bool VkTextureManager::TransitionImageLayout(VkCommandBuffer commandBuffer, VkImage image, + VkImageLayout& trackedLayout, VkImageLayout newLayout, + VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask, + VkAccessFlags srcAccessMask, VkAccessFlags dstAccessMask, + VkImageAspectFlags aspectMask) { + MOBILEGL_ASSERT(image != VK_NULL_HANDLE, "TransitionImageLayout: m_image == VK_NULL_HANDLE"); + + if (trackedLayout == newLayout) { + return true; + } + + VkImageMemoryBarrier barrier{}; + barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; + barrier.srcAccessMask = srcAccessMask; + barrier.dstAccessMask = dstAccessMask; + barrier.oldLayout = trackedLayout; + barrier.newLayout = newLayout; + barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + barrier.image = image; + barrier.subresourceRange.aspectMask = aspectMask; + barrier.subresourceRange.baseMipLevel = 0; + barrier.subresourceRange.levelCount = 1; + barrier.subresourceRange.baseArrayLayer = 0; + barrier.subresourceRange.layerCount = 1; + vkCmdPipelineBarrier(commandBuffer, srcStageMask, dstStageMask, 0, 0, nullptr, 0, nullptr, 1, &barrier); + + trackedLayout = newLayout; + return true; + } Bool VkTextureManager::SyncTexture(MG_State::GLState::ITextureObject &texture, TextureResource &outResource) { @@ -234,26 +264,15 @@ namespace MobileGL::MG_Backend::DirectVulkan { // TODO: Could be uploaded asynchronously? const Bool ok = ExecuteCmdBufImmediate([&](VkCommandBuffer commandBuffer) { - VkImageMemoryBarrier toTransferDst{}; - toTransferDst.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; - toTransferDst.srcAccessMask = - outResource.layout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL ? VK_ACCESS_SHADER_READ_BIT : 0; - toTransferDst.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; - toTransferDst.oldLayout = outResource.layout; - toTransferDst.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; - toTransferDst.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - toTransferDst.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - toTransferDst.image = outResource.image; - toTransferDst.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - toTransferDst.subresourceRange.baseMipLevel = 0; - toTransferDst.subresourceRange.levelCount = outResource.mipLevels; - toTransferDst.subresourceRange.baseArrayLayer = 0; - toTransferDst.subresourceRange.layerCount = 1; - const VkPipelineStageFlags srcStage = - outResource.layout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL ? VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT - : VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT; - vkCmdPipelineBarrier(commandBuffer, srcStage, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, nullptr, 0, nullptr, 1, - &toTransferDst); + Bool ok = TransitionImageLayout(commandBuffer, outResource.image, + outResource.layout, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL ? VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT : VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, + VK_PIPELINE_STAGE_TRANSFER_BIT, + outResource.layout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL ? VK_ACCESS_SHADER_READ_BIT : 0, + VK_ACCESS_TRANSFER_WRITE_BIT, + VK_IMAGE_ASPECT_COLOR_BIT); + MOBILEGL_ASSERT(ok, "TransitionImageLayout to VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL failed"); for (const auto& item : uploadItems) { VkBufferImageCopy copy{}; @@ -270,22 +289,16 @@ namespace MobileGL::MG_Backend::DirectVulkan { 1, ©); } - VkImageMemoryBarrier toSampled{}; - toSampled.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; - toSampled.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; - toSampled.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; - toSampled.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; - toSampled.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; - toSampled.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - toSampled.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - toSampled.image = outResource.image; - toSampled.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - toSampled.subresourceRange.baseMipLevel = 0; - toSampled.subresourceRange.levelCount = outResource.mipLevels; - toSampled.subresourceRange.baseArrayLayer = 0; - toSampled.subresourceRange.layerCount = 1; - vkCmdPipelineBarrier(commandBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0, - 0, nullptr, 0, nullptr, 1, &toSampled); + ok = TransitionImageLayout(commandBuffer, outResource.image, + outResource.layout, + VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, + VK_PIPELINE_STAGE_TRANSFER_BIT, + VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, + VK_ACCESS_TRANSFER_WRITE_BIT, + VK_ACCESS_TRANSFER_READ_BIT, + VK_IMAGE_ASPECT_COLOR_BIT); + MOBILEGL_ASSERT(ok, "TransitionImageLayout to VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL failed"); + return ok; }); vmaDestroyBuffer(m_allocator, stagingBuffer, stagingAllocation); diff --git a/MobileGL/MG_Backend/DirectVulkan/Renderer/VkTextureManager.h b/MobileGL/MG_Backend/DirectVulkan/Renderer/VkTextureManager.h index a2330d22..98298f17 100644 --- a/MobileGL/MG_Backend/DirectVulkan/Renderer/VkTextureManager.h +++ b/MobileGL/MG_Backend/DirectVulkan/Renderer/VkTextureManager.h @@ -33,6 +33,11 @@ public: Bool SyncTextureAndGetDescriptor(MG_State::GLState::ITextureObject& texture, VkDescriptorImageInfo& outImageInfo); + + static Bool TransitionImageLayout(VkCommandBuffer commandBuffer, VkImage image, VkImageLayout& trackedLayout, + VkImageLayout newLayout, VkPipelineStageFlags srcStageMask, + VkPipelineStageFlags dstStageMask, VkAccessFlags srcAccessMask, + VkAccessFlags dstAccessMask, VkImageAspectFlags aspectMask); private: struct TextureResource { VkImage image = VK_NULL_HANDLE;