diff --git a/MobileGL/MG_Backend/DirectVulkan/Renderer/VkClearManager.cpp b/MobileGL/MG_Backend/DirectVulkan/Renderer/VkClearManager.cpp index 392ba807..fe6dddc9 100644 --- a/MobileGL/MG_Backend/DirectVulkan/Renderer/VkClearManager.cpp +++ b/MobileGL/MG_Backend/DirectVulkan/Renderer/VkClearManager.cpp @@ -47,7 +47,7 @@ namespace MobileGL::MG_Backend::DirectVulkan { QueueClear({ .stencil = clearPayload.stencil, .attachmentType = FramebufferAttachmentType::Stencil, - }, drawFbo.GetAttachment(FramebufferAttachmentType::Depth).GetTexture()); + }, drawFbo.GetAttachment(FramebufferAttachmentType::Stencil).GetTexture()); } } diff --git a/MobileGL/MG_Backend/DirectVulkan/Renderer/VkRenderPassManager.cpp b/MobileGL/MG_Backend/DirectVulkan/Renderer/VkRenderPassManager.cpp index 91755136..5d114c3a 100644 --- a/MobileGL/MG_Backend/DirectVulkan/Renderer/VkRenderPassManager.cpp +++ b/MobileGL/MG_Backend/DirectVulkan/Renderer/VkRenderPassManager.cpp @@ -19,6 +19,7 @@ namespace MobileGL::MG_Backend::DirectVulkan { m_device(device), m_config(config), m_clearManager(clearManager), m_textureManager(textureManager), m_swapchainObject(swapchainObject) { RenderPassEntry::s_device = m_device; + s_clearManager = &m_clearManager; } VkRenderPassManager::~VkRenderPassManager() {} @@ -65,8 +66,18 @@ namespace MobileGL::MG_Backend::DirectVulkan { XXHASH_VERIFY(XXH64_update(m_hashState, &contentPtr, sizeof(contentPtr))); if (att.IsTexture()) { - auto hasClear = m_clearManager.HasPendingClear(att.GetTexture().get()); + auto* texture = att.GetTexture().get(); + auto hasClear = m_clearManager.HasPendingClear(texture); XXHASH_VERIFY(XXH64_update(m_hashState, &hasClear, sizeof(hasClear))); + if (hasClear) { + ClearAttachmentPayload clearPayload{}; + Bool hasPayload = m_clearManager.GetPendingClear(texture, clearPayload); + XXHASH_VERIFY(XXH64_update(m_hashState, &hasPayload, sizeof(hasPayload))); + if (hasPayload) { + XXHASH_VERIFY(XXH64_update( + m_hashState, &clearPayload.attachmentType, sizeof(clearPayload.attachmentType))); + } + } } }; @@ -103,6 +114,7 @@ namespace MobileGL::MG_Backend::DirectVulkan { Int height = 0; Vector attachmentDescriptions(validDrawBufCount); Vector colorAttachmentRefs(validDrawBufCount); + Vector pendingClearAttachments; Vector textureResources(validDrawBufCount, nullptr); Vector attachmentViews(validDrawBufCount, VK_NULL_HANDLE); // This should automatically work on default & offscreen FBO @@ -128,17 +140,26 @@ namespace MobileGL::MG_Backend::DirectVulkan { MG_Util::ConvertTextureInternalFormatToVkEnum( texture2d->GetFormat()); desc.samples = VK_SAMPLE_COUNT_1_BIT; - Bool hasClear = m_clearManager.HasPendingClear(texture); + ClearAttachmentPayload clearPayload{}; + Bool hasClear = m_clearManager.GetPendingClear(texture, clearPayload); desc.loadOp = hasClear ? VK_ATTACHMENT_LOAD_OP_CLEAR : VK_ATTACHMENT_LOAD_OP_LOAD; desc.storeOp = VK_ATTACHMENT_STORE_OP_STORE; desc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; desc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; - desc.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + desc.initialLayout = hasClear ? + VK_IMAGE_LAYOUT_UNDEFINED : + VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; desc.finalLayout = isDefaultFbo ? VK_IMAGE_LAYOUT_PRESENT_SRC_KHR : VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + if (hasClear) { + pendingClearAttachments.emplace_back(PendingClearAttachmentInfo { + .attachmentIndex = static_cast(i), + .texture = texture + }); + } if (width == 0) width = texture2d->GetBaseSize().x(); if (height == 0) @@ -171,19 +192,39 @@ namespace MobileGL::MG_Backend::DirectVulkan { // Depth attachment description auto& depthAtt = fbo.GetAttachment(FramebufferAttachmentType::Depth); VkAttachmentDescription depthAttachmentDescription; + VkAttachmentReference depthAttachmentRef; + depthAttachmentRef.attachment = VK_ATTACHMENT_UNUSED; + depthAttachmentRef.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; VkTextureManager::TextureResource* depthTextureResource = nullptr; if (depthAtt.IsComplete() && depthAtt.IsTexture()) { auto& texture = *depthAtt.GetTexture(); + const Uint32 depthAttachmentIndex = static_cast(attachmentDescriptions.size()); + ClearAttachmentPayload clearPayload{}; + Bool hasClear = m_clearManager.GetPendingClear(&texture, clearPayload); + Bool clearDepth = hasClear && clearPayload.attachmentType == FramebufferAttachmentType::Depth; + Bool clearStencil = hasClear && clearPayload.attachmentType == FramebufferAttachmentType::Stencil; depthAttachmentDescription.flags = 0; depthAttachmentDescription.format = MG_Util::ConvertTextureInternalFormatToVkEnum(texture.GetFormat()); depthAttachmentDescription.samples = VK_SAMPLE_COUNT_1_BIT; - depthAttachmentDescription.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; + depthAttachmentDescription.loadOp = clearDepth ? + VK_ATTACHMENT_LOAD_OP_CLEAR : + VK_ATTACHMENT_LOAD_OP_LOAD; depthAttachmentDescription.storeOp = VK_ATTACHMENT_STORE_OP_STORE; - depthAttachmentDescription.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; - depthAttachmentDescription.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; - depthAttachmentDescription.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + depthAttachmentDescription.stencilLoadOp = clearStencil ? + VK_ATTACHMENT_LOAD_OP_CLEAR : + VK_ATTACHMENT_LOAD_OP_LOAD; + depthAttachmentDescription.stencilStoreOp = VK_ATTACHMENT_STORE_OP_STORE; + depthAttachmentDescription.initialLayout = hasClear ? + VK_IMAGE_LAYOUT_UNDEFINED : + VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; depthAttachmentDescription.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; + if (hasClear) { + pendingClearAttachments.emplace_back(PendingClearAttachmentInfo { + .attachmentIndex = depthAttachmentIndex, + .texture = &texture + }); + } if (isDefaultFbo) { attachmentViews.emplace_back(m_swapchainObject.GetDepthStencilImageView(swapchainImageIndex)); } else { @@ -192,15 +233,16 @@ namespace MobileGL::MG_Backend::DirectVulkan { "GetOrCreateRenderPass: SyncTextureAndGetDescriptor failed at depth attachment"); textureResources.emplace_back(depthTextureResource); attachmentViews.emplace_back(depthTextureResource->view); + if (width == 0 || height == 0) { + auto texture2d = static_cast(&texture); + width = texture2d->GetBaseSize().x(); + height = texture2d->GetBaseSize().y(); + } } attachmentDescriptions.emplace_back(depthAttachmentDescription); + depthAttachmentRef.attachment = depthAttachmentIndex; } - // Depth attachment ref - VkAttachmentReference depthAttachmentRef; - depthAttachmentRef.attachment = 1; - depthAttachmentRef.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; - // Subpass VkSubpassDescription subpassDesc; subpassDesc.flags = 0; @@ -244,7 +286,13 @@ namespace MobileGL::MG_Backend::DirectVulkan { VK_VERIFY(vkCreateFramebuffer(m_device, &framebufferCreateInfo, nullptr, &framebuffer)); IntVec2 extent = {width, height}; RenderPassEntry renderPassEntry { - renderPass, framebuffer, Move(textureResources), static_cast(attachmentViews.size()), extent, 1 }; + renderPass, + framebuffer, + Move(textureResources), + Move(pendingClearAttachments), + static_cast(attachmentViews.size()), + extent, + 1 }; auto [insertedIt, _] = m_renderPasses.emplace(hash, Move(renderPassEntry)); return insertedIt->second; } @@ -260,16 +308,45 @@ namespace MobileGL::MG_Backend::DirectVulkan { renderPassBeginInfo.renderArea.extent = { (Uint32)renderPassEntry.extent.x(), (Uint32)renderPassEntry.extent.y() }; - // TODO: should query proper clear color - VkClearValue defaultClearValue; - defaultClearValue.color = { 0.0f, 0.0f, 0.0f, 1.0f }; - defaultClearValue.depthStencil = { 1.0f, 0 }; - Vector clearValue(renderPassEntry.attachmentCount, defaultClearValue); + Vector clearValues(renderPassEntry.attachmentCount); + for (auto& clearValue: clearValues) { + clearValue.color = {0.0f, 0.0f, 0.0f, 1.0f}; + clearValue.depthStencil = {1.0f, 0}; + } + if (s_clearManager) { + for (const auto& pending: renderPassEntry.pendingClearAttachments) { + if (!pending.texture || pending.attachmentIndex >= clearValues.size()) { + continue; + } + ClearAttachmentPayload clearPayload{}; + if (!s_clearManager->GetPendingClear(pending.texture, clearPayload)) { + continue; + } + if (clearPayload.attachmentType >= FramebufferAttachmentType::Color0 && + clearPayload.attachmentType <= FramebufferAttachmentType::Color31) { + clearValues[pending.attachmentIndex].color = { + clearPayload.color.x(), + clearPayload.color.y(), + clearPayload.color.z(), + clearPayload.color.w() + }; + } else if (clearPayload.attachmentType == FramebufferAttachmentType::Depth) { + clearValues[pending.attachmentIndex].depthStencil.depth = clearPayload.depth; + } else if (clearPayload.attachmentType == FramebufferAttachmentType::Stencil) { + clearValues[pending.attachmentIndex].depthStencil.stencil = clearPayload.stencil; + } + } + } - renderPassBeginInfo.clearValueCount = clearValue.size(); - renderPassBeginInfo.pClearValues = clearValue.data(); + renderPassBeginInfo.clearValueCount = static_cast(clearValues.size()); + renderPassBeginInfo.pClearValues = clearValues.data(); vkCmdBeginRenderPass(commandBuffer, &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE); + if (s_clearManager) { + for (const auto& pending: renderPassEntry.pendingClearAttachments) { + s_clearManager->PopPendingClear(pending.texture); + } + } s_activeRenderPass = &renderPassEntry; return true; diff --git a/MobileGL/MG_Backend/DirectVulkan/Renderer/VkRenderPassManager.h b/MobileGL/MG_Backend/DirectVulkan/Renderer/VkRenderPassManager.h index 435f1060..9fdfe469 100644 --- a/MobileGL/MG_Backend/DirectVulkan/Renderer/VkRenderPassManager.h +++ b/MobileGL/MG_Backend/DirectVulkan/Renderer/VkRenderPassManager.h @@ -18,12 +18,18 @@ #include namespace MobileGL::MG_Backend::DirectVulkan { + struct PendingClearAttachmentInfo { + Uint32 attachmentIndex = 0; + MG_State::GLState::ITextureObject* texture = nullptr; + }; + struct RenderPassEntry { static inline VkDevice s_device; VkRenderPass renderPass = VK_NULL_HANDLE; VkFramebuffer framebuffer = VK_NULL_HANDLE; // Should we hold pointer-to-resource here? Vector textureResources; + Vector pendingClearAttachments; Uint32 attachmentCount = 0; IntVec2 extent = {0, 0}; Uint32 subpass = 0; @@ -34,6 +40,7 @@ namespace MobileGL::MG_Backend::DirectVulkan { std::swap(renderPass, that.renderPass); std::swap(framebuffer, that.framebuffer); std::swap(textureResources, that.textureResources); + std::swap(pendingClearAttachments, that.pendingClearAttachments); std::swap(attachmentCount, that.attachmentCount); std::swap(extent, that.extent); std::swap(subpass, that.subpass); @@ -42,11 +49,13 @@ namespace MobileGL::MG_Backend::DirectVulkan { VkRenderPass renderpass, VkFramebuffer framebuffer, const std::vector& textureResources, + const Vector& pendingClearAttachments, Uint32 attachmentCount, IntVec2 extent, int subpass): renderPass(renderpass), framebuffer(framebuffer), textureResources(Move(textureResources)), + pendingClearAttachments(Move(pendingClearAttachments)), attachmentCount(attachmentCount), extent(extent), subpass(subpass) @@ -87,5 +96,6 @@ namespace MobileGL::MG_Backend::DirectVulkan { UnorderedMap m_renderPasses; static inline XXH64_state_t* m_hashState = XXH64_createState(); static inline RenderPassEntry* s_activeRenderPass = nullptr; + static inline VkClearManager* s_clearManager = nullptr; }; } // namespace MobileGL::MG_Backend::DirectVulkan