[Chore] (MG_Backend/DirectVulkan): remove "transition" stuff in VkRenderTargetManager

This commit is contained in:
2026-02-27 16:34:09 +08:00
parent 918b39bb63
commit 2935279603
4 changed files with 116 additions and 147 deletions
@@ -481,13 +481,21 @@ namespace MobileGL::MG_Backend::DirectVulkan {
return false; return false;
} }
if (m_framebufferManager->Transition(commandBuffer,
VkRenderTargetManager::TransitionResource::OffscreenColorTexture,
VkRenderTargetManager::TransitionUsage::ShaderRead,
texture->GetExternalIndex())) {
VkImageView offscreenView = VK_NULL_HANDLE; VkImageView offscreenView = VK_NULL_HANDLE;
if (m_framebufferManager->GetOffscreenColorViewByTexture(texture->GetExternalIndex(), offscreenView) && VkImage offscreenImage = VK_NULL_HANDLE;
offscreenView != VK_NULL_HANDLE) { VkImageLayout* offscreenLayout = nullptr;
if (m_framebufferManager->GetOffscreenColorTargetStateByTexture(texture->GetExternalIndex(), offscreenView,
offscreenImage, offscreenLayout) &&
offscreenView != VK_NULL_HANDLE && offscreenLayout != nullptr) {
const Bool fromUndefined = (*offscreenLayout == VK_IMAGE_LAYOUT_UNDEFINED);
if (VkTextureManager::TransitionImageLayout(
commandBuffer, offscreenImage, *offscreenLayout, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
fromUndefined
? VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT
: (VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_TRANSFER_BIT),
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
fromUndefined ? 0 : (VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_TRANSFER_WRITE_BIT),
VK_ACCESS_SHADER_READ_BIT, VK_IMAGE_ASPECT_COLOR_BIT)) {
VkDescriptorImageInfo sampledInfo{}; VkDescriptorImageInfo sampledInfo{};
if (!m_textureManager->SyncTextureAndGetDescriptor(*texture, sampledInfo)) { if (!m_textureManager->SyncTextureAndGetDescriptor(*texture, sampledInfo)) {
return false; return false;
@@ -8,8 +8,6 @@
#include "VkRenderTargetManager.h" #include "VkRenderTargetManager.h"
#include "VkTextureManager.h"
#include <MG_State/GLState/RenderbufferState/RenderbufferObject.h> #include <MG_State/GLState/RenderbufferState/RenderbufferObject.h>
#include <MG_State/GLState/TextureState/TextureEnum.h> #include <MG_State/GLState/TextureState/TextureEnum.h>
@@ -48,128 +46,41 @@ namespace MobileGL::MG_Backend::DirectVulkan {
return RecreateOffscreenColorTarget(target, glFbo, colorAttachment, objectVersion); return RecreateOffscreenColorTarget(target, glFbo, colorAttachment, objectVersion);
} }
Bool VkRenderTargetManager::Transition(VkCommandBuffer commandBuffer, TransitionResource resource, Bool VkRenderTargetManager::GetOffscreenRenderSurfaceState(Uint glFboExternalIndex, VkImage& outColorImage,
TransitionUsage usage, Uint externalIndex) { VkImageLayout*& outColorLayout,
auto resolveDepthStencilAspectMask = [](VkFormat format) { VkImage& outDepthStencilImage,
VkImageAspectFlags aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; VkImageLayout*& outDepthStencilLayout,
if (format == VK_FORMAT_D24_UNORM_S8_UINT || format == VK_FORMAT_D32_SFLOAT_S8_UINT) { VkFormat& outDepthStencilFormat) {
aspectMask |= VK_IMAGE_ASPECT_STENCIL_BIT; auto it = m_offscreenColorTargets.find(glFboExternalIndex);
}
return aspectMask;
};
if (resource == TransitionResource::OffscreenColorTexture) {
if (usage != TransitionUsage::ShaderRead) {
MGLOG_W("VkFramebufferManager::Transition skipped: unsupported usage %d for texture %u",
static_cast<Int>(usage), externalIndex);
return false;
}
for (auto& [_, target] : m_offscreenColorTargets) {
if (target.colorTextureExternalIndex != externalIndex || target.image == VK_NULL_HANDLE) {
continue;
}
const Bool fromUndefined = (target.layout == VK_IMAGE_LAYOUT_UNDEFINED);
return VkTextureManager::TransitionImageLayout(
commandBuffer, target.image, target.layout, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
fromUndefined
? VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT
: (VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_TRANSFER_BIT),
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
fromUndefined ? 0 : (VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_TRANSFER_WRITE_BIT),
VK_ACCESS_SHADER_READ_BIT, VK_IMAGE_ASPECT_COLOR_BIT);
}
return false;
}
auto it = m_offscreenColorTargets.find(externalIndex);
if (it == m_offscreenColorTargets.end()) { if (it == m_offscreenColorTargets.end()) {
MGLOG_W("VkFramebufferManager::Transition skipped: FBO %u not found", externalIndex);
return false; return false;
} }
auto& target = it->second; auto& target = it->second;
if (target.image == VK_NULL_HANDLE) {
if (resource == TransitionResource::OffscreenColor) {
switch (usage) {
case TransitionUsage::Attachment: {
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,
VK_IMAGE_ASPECT_COLOR_BIT)) {
return false; return false;
} }
if (target.depthStencilImage == VK_NULL_HANDLE) {
outColorImage = target.image;
outColorLayout = &target.layout;
outDepthStencilImage = target.depthStencilImage;
outDepthStencilLayout = &target.depthStencilLayout;
outDepthStencilFormat = target.depthStencilFormat;
return true; return true;
} }
const VkImageAspectFlags aspectMask = resolveDepthStencilAspectMask(target.depthStencilFormat);
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,
VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
aspectMask);
}
case TransitionUsage::TransferSrc:
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 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 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 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);
default:
return false;
}
}
if (resource == TransitionResource::OffscreenDepthStencil) { Bool VkRenderTargetManager::GetOffscreenColorTargetStateByTexture(Uint textureExternalIndex,
if (target.depthStencilImage == VK_NULL_HANDLE) { VkImageView& outImageView, VkImage& outImage,
return false; VkImageLayout*& outLayout) {
for (auto& [_, target] : m_offscreenColorTargets) {
if (target.colorTextureExternalIndex != textureExternalIndex || target.image == VK_NULL_HANDLE ||
target.imageView == VK_NULL_HANDLE) {
continue;
} }
const VkImageAspectFlags aspectMask = resolveDepthStencilAspectMask(target.depthStencilFormat); outImageView = target.imageView;
switch (usage) { outImage = target.image;
case TransitionUsage::TransferSrc: outLayout = &target.layout;
return VkTextureManager::TransitionImageLayout(commandBuffer, target.depthStencilImage, target.depthStencilLayout, return true;
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 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 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 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,
VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
aspectMask);
case TransitionUsage::ShaderRead:
return false;
default:
return false;
} }
}
return false; return false;
} }
@@ -16,20 +16,6 @@
namespace MobileGL::MG_Backend::DirectVulkan { namespace MobileGL::MG_Backend::DirectVulkan {
class VkRenderTargetManager { class VkRenderTargetManager {
public: public:
enum class TransitionResource {
OffscreenColor,
OffscreenDepthStencil,
OffscreenColorTexture
};
enum class TransitionUsage {
Attachment,
TransferSrc,
TransferDst,
General,
ShaderRead
};
struct InitInfo { struct InitInfo {
VkDevice device = VK_NULL_HANDLE; VkDevice device = VK_NULL_HANDLE;
VkPhysicalDevice physicalDevice = VK_NULL_HANDLE; VkPhysicalDevice physicalDevice = VK_NULL_HANDLE;
@@ -43,8 +29,12 @@ namespace MobileGL::MG_Backend::DirectVulkan {
void Shutdown(); void Shutdown();
Bool EnsureOffscreenColorTarget(Uint glFboExternalIndex, const MG_State::GLState::FramebufferObject& glFbo); Bool EnsureOffscreenColorTarget(Uint glFboExternalIndex, const MG_State::GLState::FramebufferObject& glFbo);
Bool Transition(VkCommandBuffer commandBuffer, TransitionResource resource, TransitionUsage usage, Bool GetOffscreenRenderSurfaceState(Uint glFboExternalIndex, VkImage& outColorImage,
Uint externalIndex); VkImageLayout*& outColorLayout, VkImage& outDepthStencilImage,
VkImageLayout*& outDepthStencilLayout,
VkFormat& outDepthStencilFormat);
Bool GetOffscreenColorTargetStateByTexture(Uint textureExternalIndex, VkImageView& outImageView,
VkImage& outImage, VkImageLayout*& outLayout);
Bool GetOffscreenColorViewByTexture(Uint textureExternalIndex, VkImageView& outImageView) const; Bool GetOffscreenColorViewByTexture(Uint textureExternalIndex, VkImageView& outImageView) const;
Bool GetOffscreenRenderSurface(Uint glFboExternalIndex, VkImageView& outColorView, VkFormat& outColorFormat, Bool GetOffscreenRenderSurface(Uint glFboExternalIndex, VkImageView& outColorView, VkFormat& outColorFormat,
VkImageView& outDepthStencilView, VkFormat& outDepthStencilFormat, VkImageView& outDepthStencilView, VkFormat& outDepthStencilFormat,
@@ -480,13 +480,45 @@ namespace MobileGL::MG_Backend::DirectVulkan {
return; return;
} }
if (!m_framebufferManager->Transition(commandBuffer, VkRenderTargetManager::TransitionResource::OffscreenColor, VkImage offscreenColorImage = VK_NULL_HANDLE;
VkRenderTargetManager::TransitionUsage::Attachment, VkImageLayout* offscreenColorLayout = nullptr;
drawFboExternalIndex)) { VkImage offscreenDepthStencilImage = VK_NULL_HANDLE;
VkImageLayout* offscreenDepthStencilLayout = nullptr;
VkFormat offscreenDepthStencilStateFormat = VK_FORMAT_UNDEFINED;
if (!m_framebufferManager->GetOffscreenRenderSurfaceState(
drawFboExternalIndex, offscreenColorImage, offscreenColorLayout, offscreenDepthStencilImage,
offscreenDepthStencilLayout, offscreenDepthStencilStateFormat) ||
offscreenColorLayout == nullptr) {
MGLOG_D("EnsureFrameRecordingStarted skipped: failed to transition offscreen FBO %u for attachment", MGLOG_D("EnsureFrameRecordingStarted skipped: failed to transition offscreen FBO %u for attachment",
drawFboExternalIndex); drawFboExternalIndex);
return; return;
} }
if (!VkTextureManager::TransitionImageLayout(
commandBuffer, offscreenColorImage, *offscreenColorLayout, 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,
VK_IMAGE_ASPECT_COLOR_BIT)) {
MGLOG_D("EnsureFrameRecordingStarted skipped: failed to transition offscreen color for FBO %u",
drawFboExternalIndex);
return;
}
if (offscreenDepthStencilImage != VK_NULL_HANDLE && offscreenDepthStencilLayout != nullptr) {
VkImageAspectFlags depthStencilAspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
if (offscreenDepthStencilStateFormat == VK_FORMAT_D24_UNORM_S8_UINT ||
offscreenDepthStencilStateFormat == VK_FORMAT_D32_SFLOAT_S8_UINT) {
depthStencilAspectMask |= VK_IMAGE_ASPECT_STENCIL_BIT;
}
if (!VkTextureManager::TransitionImageLayout(
commandBuffer, offscreenDepthStencilImage, *offscreenDepthStencilLayout,
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,
VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
depthStencilAspectMask)) {
MGLOG_D("EnsureFrameRecordingStarted skipped: failed to transition offscreen depth/stencil for FBO %u",
drawFboExternalIndex);
return;
}
}
m_renderPassManager->BeginRenderPass(commandBuffer, offscreenRenderPass, offscreenFramebuffer, m_renderPassManager->BeginRenderPass(commandBuffer, offscreenRenderPass, offscreenFramebuffer,
offscreenExtent); offscreenExtent);
m_isMainRenderPassActive = true; m_isMainRenderPassActive = true;
@@ -1226,12 +1258,40 @@ namespace MobileGL::MG_Backend::DirectVulkan {
offscreenFramebuffer, offscreenExtent, offscreenDepthStencilFormat)) { offscreenFramebuffer, offscreenExtent, offscreenDepthStencilFormat)) {
return false; return false;
} }
if (!m_framebufferManager->Transition(commandBuffer, VkImage offscreenColorImage = VK_NULL_HANDLE;
VkRenderTargetManager::TransitionResource::OffscreenColor, VkImageLayout* offscreenColorLayout = nullptr;
VkRenderTargetManager::TransitionUsage::Attachment, VkImage offscreenDepthStencilImage = VK_NULL_HANDLE;
targetFboExternalIndex)) { VkImageLayout* offscreenDepthStencilLayout = nullptr;
VkFormat offscreenDepthStencilStateFormat = VK_FORMAT_UNDEFINED;
if (!m_framebufferManager->GetOffscreenRenderSurfaceState(
targetFboExternalIndex, offscreenColorImage, offscreenColorLayout, offscreenDepthStencilImage,
offscreenDepthStencilLayout, offscreenDepthStencilStateFormat) ||
offscreenColorLayout == nullptr) {
return false; return false;
} }
if (!VkTextureManager::TransitionImageLayout(
commandBuffer, offscreenColorImage, *offscreenColorLayout,
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,
VK_IMAGE_ASPECT_COLOR_BIT)) {
return false;
}
if (offscreenDepthStencilImage != VK_NULL_HANDLE && offscreenDepthStencilLayout != nullptr) {
VkImageAspectFlags depthStencilAspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
if (offscreenDepthStencilStateFormat == VK_FORMAT_D24_UNORM_S8_UINT ||
offscreenDepthStencilStateFormat == VK_FORMAT_D32_SFLOAT_S8_UINT) {
depthStencilAspectMask |= VK_IMAGE_ASPECT_STENCIL_BIT;
}
if (!VkTextureManager::TransitionImageLayout(
commandBuffer, offscreenDepthStencilImage, *offscreenDepthStencilLayout,
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,
VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
depthStencilAspectMask)) {
return false;
}
}
const auto swapchainOldLayout = m_swapchainObject.GetImageLayout(m_imageIndexAcquired); const auto swapchainOldLayout = m_swapchainObject.GetImageLayout(m_imageIndexAcquired);
if (swapchainOldLayout != VK_IMAGE_LAYOUT_PRESENT_SRC_KHR && if (swapchainOldLayout != VK_IMAGE_LAYOUT_PRESENT_SRC_KHR &&