diff --git a/MobileGL/MG_Backend/DirectVulkan/Renderer/UniformDescriptorBinder.cpp b/MobileGL/MG_Backend/DirectVulkan/Renderer/UniformDescriptorBinder.cpp index 727a358f..964253b3 100644 --- a/MobileGL/MG_Backend/DirectVulkan/Renderer/UniformDescriptorBinder.cpp +++ b/MobileGL/MG_Backend/DirectVulkan/Renderer/UniformDescriptorBinder.cpp @@ -481,13 +481,21 @@ namespace MobileGL::MG_Backend::DirectVulkan { return false; } - if (m_framebufferManager->Transition(commandBuffer, - VkRenderTargetManager::TransitionResource::OffscreenColorTexture, - VkRenderTargetManager::TransitionUsage::ShaderRead, - texture->GetExternalIndex())) { - VkImageView offscreenView = VK_NULL_HANDLE; - if (m_framebufferManager->GetOffscreenColorViewByTexture(texture->GetExternalIndex(), offscreenView) && - offscreenView != VK_NULL_HANDLE) { + VkImageView offscreenView = VK_NULL_HANDLE; + VkImage offscreenImage = 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{}; if (!m_textureManager->SyncTextureAndGetDescriptor(*texture, sampledInfo)) { return false; diff --git a/MobileGL/MG_Backend/DirectVulkan/Renderer/VkRenderTargetManager.cpp b/MobileGL/MG_Backend/DirectVulkan/Renderer/VkRenderTargetManager.cpp index bee4bcdc..7e0ac264 100644 --- a/MobileGL/MG_Backend/DirectVulkan/Renderer/VkRenderTargetManager.cpp +++ b/MobileGL/MG_Backend/DirectVulkan/Renderer/VkRenderTargetManager.cpp @@ -8,8 +8,6 @@ #include "VkRenderTargetManager.h" -#include "VkTextureManager.h" - #include #include @@ -48,128 +46,41 @@ namespace MobileGL::MG_Backend::DirectVulkan { return RecreateOffscreenColorTarget(target, glFbo, colorAttachment, objectVersion); } - Bool VkRenderTargetManager::Transition(VkCommandBuffer commandBuffer, TransitionResource resource, - TransitionUsage usage, Uint externalIndex) { - auto resolveDepthStencilAspectMask = [](VkFormat format) { - VkImageAspectFlags aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; - if (format == VK_FORMAT_D24_UNORM_S8_UINT || format == VK_FORMAT_D32_SFLOAT_S8_UINT) { - aspectMask |= VK_IMAGE_ASPECT_STENCIL_BIT; - } - return aspectMask; - }; - - if (resource == TransitionResource::OffscreenColorTexture) { - if (usage != TransitionUsage::ShaderRead) { - MGLOG_W("VkFramebufferManager::Transition skipped: unsupported usage %d for texture %u", - static_cast(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); + Bool VkRenderTargetManager::GetOffscreenRenderSurfaceState(Uint glFboExternalIndex, VkImage& outColorImage, + VkImageLayout*& outColorLayout, + VkImage& outDepthStencilImage, + VkImageLayout*& outDepthStencilLayout, + VkFormat& outDepthStencilFormat) { + auto it = m_offscreenColorTargets.find(glFboExternalIndex); if (it == m_offscreenColorTargets.end()) { - MGLOG_W("VkFramebufferManager::Transition skipped: FBO %u not found", externalIndex); return false; } auto& target = it->second; - - 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; - } - if (target.depthStencilImage == VK_NULL_HANDLE) { - 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 (target.image == VK_NULL_HANDLE) { + return false; } - if (resource == TransitionResource::OffscreenDepthStencil) { - if (target.depthStencilImage == VK_NULL_HANDLE) { - return false; - } - const VkImageAspectFlags aspectMask = resolveDepthStencilAspectMask(target.depthStencilFormat); - switch (usage) { - case TransitionUsage::TransferSrc: - 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 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; - } - } + outColorImage = target.image; + outColorLayout = &target.layout; + outDepthStencilImage = target.depthStencilImage; + outDepthStencilLayout = &target.depthStencilLayout; + outDepthStencilFormat = target.depthStencilFormat; + return true; + } + Bool VkRenderTargetManager::GetOffscreenColorTargetStateByTexture(Uint textureExternalIndex, + VkImageView& outImageView, VkImage& outImage, + VkImageLayout*& outLayout) { + for (auto& [_, target] : m_offscreenColorTargets) { + if (target.colorTextureExternalIndex != textureExternalIndex || target.image == VK_NULL_HANDLE || + target.imageView == VK_NULL_HANDLE) { + continue; + } + outImageView = target.imageView; + outImage = target.image; + outLayout = &target.layout; + return true; + } return false; } diff --git a/MobileGL/MG_Backend/DirectVulkan/Renderer/VkRenderTargetManager.h b/MobileGL/MG_Backend/DirectVulkan/Renderer/VkRenderTargetManager.h index 42f17bab..0e731f52 100644 --- a/MobileGL/MG_Backend/DirectVulkan/Renderer/VkRenderTargetManager.h +++ b/MobileGL/MG_Backend/DirectVulkan/Renderer/VkRenderTargetManager.h @@ -16,20 +16,6 @@ namespace MobileGL::MG_Backend::DirectVulkan { class VkRenderTargetManager { public: - enum class TransitionResource { - OffscreenColor, - OffscreenDepthStencil, - OffscreenColorTexture - }; - - enum class TransitionUsage { - Attachment, - TransferSrc, - TransferDst, - General, - ShaderRead - }; - struct InitInfo { VkDevice device = VK_NULL_HANDLE; VkPhysicalDevice physicalDevice = VK_NULL_HANDLE; @@ -43,8 +29,12 @@ namespace MobileGL::MG_Backend::DirectVulkan { void Shutdown(); Bool EnsureOffscreenColorTarget(Uint glFboExternalIndex, const MG_State::GLState::FramebufferObject& glFbo); - Bool Transition(VkCommandBuffer commandBuffer, TransitionResource resource, TransitionUsage usage, - Uint externalIndex); + Bool GetOffscreenRenderSurfaceState(Uint glFboExternalIndex, VkImage& outColorImage, + 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 GetOffscreenRenderSurface(Uint glFboExternalIndex, VkImageView& outColorView, VkFormat& outColorFormat, VkImageView& outDepthStencilView, VkFormat& outDepthStencilFormat, diff --git a/MobileGL/MG_Backend/DirectVulkan/Renderer/VulkanRenderer.cpp b/MobileGL/MG_Backend/DirectVulkan/Renderer/VulkanRenderer.cpp index 94602dc6..71ccc86c 100644 --- a/MobileGL/MG_Backend/DirectVulkan/Renderer/VulkanRenderer.cpp +++ b/MobileGL/MG_Backend/DirectVulkan/Renderer/VulkanRenderer.cpp @@ -480,13 +480,45 @@ namespace MobileGL::MG_Backend::DirectVulkan { return; } - if (!m_framebufferManager->Transition(commandBuffer, VkRenderTargetManager::TransitionResource::OffscreenColor, - VkRenderTargetManager::TransitionUsage::Attachment, - drawFboExternalIndex)) { + VkImage offscreenColorImage = VK_NULL_HANDLE; + VkImageLayout* offscreenColorLayout = nullptr; + 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", drawFboExternalIndex); 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, offscreenExtent); m_isMainRenderPassActive = true; @@ -1226,12 +1258,40 @@ namespace MobileGL::MG_Backend::DirectVulkan { offscreenFramebuffer, offscreenExtent, offscreenDepthStencilFormat)) { return false; } - if (!m_framebufferManager->Transition(commandBuffer, - VkRenderTargetManager::TransitionResource::OffscreenColor, - VkRenderTargetManager::TransitionUsage::Attachment, - targetFboExternalIndex)) { + VkImage offscreenColorImage = VK_NULL_HANDLE; + VkImageLayout* offscreenColorLayout = nullptr; + VkImage offscreenDepthStencilImage = VK_NULL_HANDLE; + VkImageLayout* offscreenDepthStencilLayout = nullptr; + VkFormat offscreenDepthStencilStateFormat = VK_FORMAT_UNDEFINED; + if (!m_framebufferManager->GetOffscreenRenderSurfaceState( + targetFboExternalIndex, offscreenColorImage, offscreenColorLayout, offscreenDepthStencilImage, + offscreenDepthStencilLayout, offscreenDepthStencilStateFormat) || + offscreenColorLayout == nullptr) { 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); if (swapchainOldLayout != VK_IMAGE_LAYOUT_PRESENT_SRC_KHR &&