[Chore] (MG_Backend/DirectVulkan): move TransitionImageLayout to VkTextureManager

This commit is contained in:
2026-02-27 09:44:23 +08:00
parent 9b23594415
commit 2c848ab44b
4 changed files with 67 additions and 83 deletions
@@ -8,6 +8,8 @@
#include "VkRenderTargetManager.h"
#include "VkTextureManager.h"
#include <MG_State/GLState/RenderbufferState/RenderbufferObject.h>
#include <MG_State/GLState/TextureState/TextureEnum.h>
@@ -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;
@@ -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,
@@ -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, &copy);
}
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);
@@ -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;