diff --git a/CMakeLists.txt b/CMakeLists.txt index cbb1302c..8a50ad45 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -162,6 +162,7 @@ set(SOURCE_FILES MobileGL/MG_Util/Converters/GLToMG/RenderStateEnumConverter.cpp MobileGL/MG_Util/Converters/GLToMG/ProgramEnumConverter.cpp MobileGL/MG_Util/Converters/MGToMG/TextureEnumConverter.cpp + MobileGL/MG_Util/Converters/MGToVk/TextureEnumConverter.cpp MobileGL/MG_Util/Classifiers/TextureEnumClassifier.cpp @@ -225,11 +226,10 @@ set(SOURCE_FILES MobileGL/MG_Backend/DirectVulkan/Renderer/VertexInputStateBuilder.cpp MobileGL/MG_Backend/DirectVulkan/Renderer/VertexInputStateFactory.cpp MobileGL/MG_Backend/DirectVulkan/Renderer/VkBufferObject.cpp - MobileGL/MG_Backend/DirectVulkan/Renderer/VkRenderTargetManager.cpp - MobileGL/MG_Backend/DirectVulkan/Renderer/VkRenderPassManager.cpp MobileGL/MG_Backend/DirectVulkan/Renderer/VkTextureManager.cpp MobileGL/MG_Backend/DirectVulkan/Renderer/VkSamplerManager.cpp MobileGL/MG_Backend/DirectVulkan/Renderer/VkClearManager.cpp + MobileGL/MG_Backend/DirectVulkan/Renderer/VkRenderPassManager.cpp MobileGL/MG_State/GLState/Core.cpp MobileGL/MG_State/GLState/ErrorState/Error.cpp diff --git a/MobileGL/MG_Backend/DirectVulkan/Renderer/UniformDescriptorBinder.cpp b/MobileGL/MG_Backend/DirectVulkan/Renderer/UniformDescriptorBinder.cpp index 964253b3..d0fd6aa8 100644 --- a/MobileGL/MG_Backend/DirectVulkan/Renderer/UniformDescriptorBinder.cpp +++ b/MobileGL/MG_Backend/DirectVulkan/Renderer/UniformDescriptorBinder.cpp @@ -8,7 +8,6 @@ #include "UniformDescriptorBinder.h" -#include "VkRenderTargetManager.h" #include "MG_State/GLState/Core.h" #include "MG_State/GLState/ProgramState/ProgramObject.h" #include "MG_Util/ShaderTranspiler/Types.h" @@ -138,8 +137,7 @@ namespace MobileGL::MG_Backend::DirectVulkan { Bool UniformDescriptorBinder::Initialize(VkDevice device, VmaAllocator allocator, VkDeviceSize minUniformBufferOffsetAlignment, Uint32 frameCount, Uint32 maxBindings, Uint32 setsPerFrame, VkDeviceSize perFrameUploadBytes, - VkTextureManager* textureManager, VkSamplerManager* samplerManager, - VkRenderTargetManager* framebufferManager) { + VkTextureManager* textureManager, VkSamplerManager* samplerManager) { Shutdown(); MOBILEGL_ASSERT(device != VK_NULL_HANDLE, "UniformDescriptorBinder::Initialize requires valid VkDevice"); @@ -151,8 +149,6 @@ namespace MobileGL::MG_Backend::DirectVulkan { "UniformDescriptorBinder::Initialize requires valid texture manager"); MOBILEGL_ASSERT(samplerManager != nullptr, "UniformDescriptorBinder::Initialize requires valid sampler manager"); - MOBILEGL_ASSERT(framebufferManager != nullptr, - "UniformDescriptorBinder::Initialize requires valid framebuffer manager"); m_device = device; m_allocator = allocator; @@ -164,7 +160,6 @@ namespace MobileGL::MG_Backend::DirectVulkan { m_peakDescriptorSetsObserved = 0; m_textureManager = textureManager; m_samplerManager = samplerManager; - m_framebufferManager = framebufferManager; m_frames.resize(m_frameCount); for (Uint32 frameIndex = 0; frameIndex < m_frameCount; ++frameIndex) { @@ -228,7 +223,6 @@ namespace MobileGL::MG_Backend::DirectVulkan { m_peakDescriptorSetsObserved = 0; m_textureManager = nullptr; m_samplerManager = nullptr; - m_framebufferManager = nullptr; } void UniformDescriptorBinder::BeginFrame(Uint32 frameIndex) { @@ -451,6 +445,7 @@ namespace MobileGL::MG_Backend::DirectVulkan { const MG_State::GLState::ProgramObject& program, const ProgramLayout& layout, Uint32 binding, VkDescriptorImageInfo& outImageInfo) const { + (void)commandBuffer; MOBILEGL_ASSERT(m_textureManager != nullptr, "ResolveSamplerDescriptor: texture manager is null"); MOBILEGL_ASSERT(m_samplerManager != nullptr, "ResolveSamplerDescriptor: sampler manager is null"); if (!MG_State::pGLContext || binding >= layout.samplerUniformLocationByBinding.size()) { @@ -481,36 +476,6 @@ namespace MobileGL::MG_Backend::DirectVulkan { return false; } - 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; - } - sampledInfo.sampler = m_samplerManager->GetOrCreateSampler(*samplerToUse); - if (sampledInfo.sampler == VK_NULL_HANDLE) { - return false; - } - sampledInfo.imageView = offscreenView; - sampledInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; - outImageInfo = sampledInfo; - return true; - } - } - if (!m_textureManager->SyncTextureAndGetDescriptor(*texture, outImageInfo)) { return false; } diff --git a/MobileGL/MG_Backend/DirectVulkan/Renderer/UniformDescriptorBinder.h b/MobileGL/MG_Backend/DirectVulkan/Renderer/UniformDescriptorBinder.h index 3336dca1..49eb7e1f 100644 --- a/MobileGL/MG_Backend/DirectVulkan/Renderer/UniformDescriptorBinder.h +++ b/MobileGL/MG_Backend/DirectVulkan/Renderer/UniformDescriptorBinder.h @@ -20,8 +20,6 @@ namespace MobileGL::MG_State::GLState { } namespace MobileGL::MG_Backend::DirectVulkan { - class VkRenderTargetManager; - class UniformDescriptorBinder { public: enum class BindingKind : Uint8 { @@ -33,8 +31,7 @@ namespace MobileGL::MG_Backend::DirectVulkan { Bool Initialize(VkDevice device, VmaAllocator allocator, VkDeviceSize minUniformBufferOffsetAlignment, Uint32 frameCount, Uint32 maxBindings = 16, Uint32 setsPerFrame = 64, VkDeviceSize perFrameUploadBytes = 4 * 1024 * 1024, - VkTextureManager* textureManager = nullptr, VkSamplerManager* samplerManager = nullptr, - VkRenderTargetManager* framebufferManager = nullptr); + VkTextureManager* textureManager = nullptr, VkSamplerManager* samplerManager = nullptr); void Shutdown(); void BeginFrame(Uint32 frameIndex); @@ -100,7 +97,6 @@ namespace MobileGL::MG_Backend::DirectVulkan { Uint32 m_peakDescriptorSetsObserved = 0; VkTextureManager* m_textureManager = nullptr; VkSamplerManager* m_samplerManager = nullptr; - VkRenderTargetManager* m_framebufferManager = nullptr; }; } // namespace MobileGL::MG_Backend::DirectVulkan diff --git a/MobileGL/MG_Backend/DirectVulkan/Renderer/VkClearManager.cpp b/MobileGL/MG_Backend/DirectVulkan/Renderer/VkClearManager.cpp index 929ec571..2ff99e66 100644 --- a/MobileGL/MG_Backend/DirectVulkan/Renderer/VkClearManager.cpp +++ b/MobileGL/MG_Backend/DirectVulkan/Renderer/VkClearManager.cpp @@ -61,14 +61,23 @@ namespace MobileGL::MG_Backend::DirectVulkan { m_pendingClears[pTexture] = clearPayload; } - Bool VkClearManager::DequeueClear(MG_State::GLState::ITextureObject* texture, ClearAttachmentPayload& outPayload) { - if (m_aliveObjects.find(texture) == m_aliveObjects.end()) + Bool VkClearManager::HasPendingClear(MG_State::GLState::ITextureObject* texture) { + return m_pendingClears.find(texture) != m_pendingClears.end(); + } + + Bool VkClearManager::GetPendingClear(MG_State::GLState::ITextureObject* texture, ClearAttachmentPayload& outPayload) { + if (m_aliveObjects.find(texture) == m_aliveObjects.end() || + m_pendingClears.find(texture) == m_pendingClears.end()) { return false; + } outPayload = m_pendingClears[texture]; + return true; + } + + void VkClearManager::PopPendingClear(MG_State::GLState::ITextureObject* texture) { m_aliveObjects.erase(texture); m_pendingClears.erase(texture); - return true; } SizeT VkClearManager::CollectGarbage() { diff --git a/MobileGL/MG_Backend/DirectVulkan/Renderer/VkClearManager.h b/MobileGL/MG_Backend/DirectVulkan/Renderer/VkClearManager.h index f4906f9c..9bfcf2ff 100644 --- a/MobileGL/MG_Backend/DirectVulkan/Renderer/VkClearManager.h +++ b/MobileGL/MG_Backend/DirectVulkan/Renderer/VkClearManager.h @@ -40,7 +40,9 @@ namespace MobileGL::MG_Backend::DirectVulkan { void QueueClear( const ClearAttachmentPayload& clearPayload, const SharedPtr& texture); - Bool DequeueClear(MG_State::GLState::ITextureObject* texture, ClearAttachmentPayload& outPayload); + Bool HasPendingClear(MG_State::GLState::ITextureObject* texture); + Bool GetPendingClear(MG_State::GLState::ITextureObject* texture, ClearAttachmentPayload& outPayload); + void PopPendingClear(MG_State::GLState::ITextureObject* texture); SizeT CollectGarbage(); private: UnorderedMap m_pendingClears; diff --git a/MobileGL/MG_Backend/DirectVulkan/Renderer/VkRenderPassManager.cpp b/MobileGL/MG_Backend/DirectVulkan/Renderer/VkRenderPassManager.cpp index 4571b817..dc6da422 100644 --- a/MobileGL/MG_Backend/DirectVulkan/Renderer/VkRenderPassManager.cpp +++ b/MobileGL/MG_Backend/DirectVulkan/Renderer/VkRenderPassManager.cpp @@ -8,327 +8,234 @@ #include "VkRenderPassManager.h" +#include "MG_Impl/GLImpl/Framebuffer/GL_Framebuffer.h" +#include "MG_State/GLState/TextureState/TextureObject2D.h" +#include "MG_Util/Converters/MGToVk/TextureEnumConverter.h" + namespace MobileGL::MG_Backend::DirectVulkan { - Bool VkRenderPassManager::Initialize(const InitInfo& initInfo) { - Shutdown(); + VkRenderPassManager::VkRenderPassManager(VkDevice device, + const VulkanRendererConfig& config, VkClearManager& clearManager, VkTextureManager& textureManager): + m_device(device), m_config(config), m_clearManager(clearManager), m_textureManager(textureManager) { + RenderPassEntry::s_device = m_device; + } - if (initInfo.device == VK_NULL_HANDLE || initInfo.colorFormat == VK_FORMAT_UNDEFINED || - initInfo.depthStencilFormat == VK_FORMAT_UNDEFINED) { - return false; - } + VkRenderPassManager::~VkRenderPassManager() {} - m_device = initInfo.device; - m_colorFormat = initInfo.colorFormat; - m_depthStencilFormat = initInfo.depthStencilFormat; - m_renderPassLoad = CreateDefaultRenderPass(VK_ATTACHMENT_LOAD_OP_LOAD); - MGLOG_D("VkRenderPassManager: RenderPasses created (LOAD/CLEAR)."); - return m_renderPassLoad != VK_NULL_HANDLE; + Bool VkRenderPassManager::Initialize() { + return true; } void VkRenderPassManager::Shutdown() { - DestroyDefaultFramebuffers(); - for (auto& [_, target] : m_offscreenRenderTargets) { - DestroyOffscreenRenderTarget(target); - } - m_offscreenRenderTargets.clear(); + } - if (m_device != VK_NULL_HANDLE) { - if (m_renderPassLoad != VK_NULL_HANDLE) { - vkDestroyRenderPass(m_device, m_renderPassLoad, nullptr); + VkRenderPassManager::HashType VkRenderPassManager::ComputeHash( + const MG_State::GLState::FramebufferObject& fbo) const { + XXHASH_VERIFY(XXH64_reset(m_hashState, m_config.CacheVersion)); + auto& drawBuffers = fbo.GetDrawBuffers(); + XXHASH_VERIFY(XXH64_update(m_hashState, drawBuffers.data(), drawBuffers.size() * sizeof(drawBuffers[0]))); + auto readBuffer = fbo.GetReadBuffer(); + XXHASH_VERIFY(XXH64_update(m_hashState, &readBuffer, sizeof(FramebufferAttachmentType))); + Int validDrawBufCount = 0; + for (Int i = 0; i < drawBuffers.size(); ++i) { + auto drawbuf = drawBuffers[i]; + if (drawbuf != FramebufferAttachmentType::None) + validDrawBufCount = std::max(validDrawBufCount, i + 1); + } + XXHASH_VERIFY(XXH64_update(m_hashState, &validDrawBufCount, sizeof(validDrawBufCount))); + + auto combineFramebufferAttachmentObjHash = [&](FramebufferAttachmentType attachment) { + auto& att = fbo.GetAttachment(attachment); + + Int type = 0; + if (att.IsEmpty()) type = 0; + else if (att.IsTexture()) type = 1; + else if (att.IsRenderbuffer()) type = 2; + XXHASH_VERIFY(XXH64_update(m_hashState, &type, sizeof(type))); + void* contentPtr = nullptr; + if (att.IsTexture()) + contentPtr = att.GetTexture().get(); + else if (att.IsRenderbuffer()) + contentPtr = att.GetRenderbuffer().get(); + XXHASH_VERIFY(XXH64_update(m_hashState, &contentPtr, sizeof(contentPtr))); + + if (att.IsTexture()) { + auto hasClear = m_clearManager.HasPendingClear(att.GetTexture().get()); + XXHASH_VERIFY(XXH64_update(m_hashState, &hasClear, sizeof(hasClear))); } + }; + + for (Int i = 0; i < validDrawBufCount; ++i) { + auto drawbuf = drawBuffers[i]; + combineFramebufferAttachmentObjHash(drawbuf); } - m_renderPassLoad = VK_NULL_HANDLE; - m_colorFormat = VK_FORMAT_UNDEFINED; - m_depthStencilFormat = VK_FORMAT_UNDEFINED; - m_defaultExtent = {0, 0}; - m_device = VK_NULL_HANDLE; + combineFramebufferAttachmentObjHash(FramebufferAttachmentType::Depth); + combineFramebufferAttachmentObjHash(FramebufferAttachmentType::Stencil); + + return XXH64_digest(m_hashState); } - Bool VkRenderPassManager::RecreateDefaultFramebuffers(const Vector& colorViews, - const Vector& depthStencilViews, - VkExtent2D extent) { - DestroyDefaultFramebuffers(); + RenderPassEntry& VkRenderPassManager::GetOrCreateRenderPass(const MG_State::GLState::FramebufferObject& fbo) { + // retrieve from cache first + auto hash = ComputeHash(fbo); + auto it = m_renderPasses.find(hash); + if (it != m_renderPasses.end()) + return it->second; - if (m_device == VK_NULL_HANDLE || m_renderPassLoad == VK_NULL_HANDLE || extent.width == 0 || - extent.height == 0 || colorViews.empty() || colorViews.size() != depthStencilViews.size()) { - return false; + Bool isDefaultFbo = (&fbo == MG_Impl::GLImpl::FramebufferImpl::pDefaultFramebufferInfo->defaultFBO.get()); + // Color attachment + auto& drawbufs = fbo.GetDrawBuffers(); + Int validDrawBufCount = 0; + for (Int i = 0; i < drawbufs.size(); ++i) { + auto drawbuf = drawbufs[i]; + if (drawbuf != FramebufferAttachmentType::None) + validDrawBufCount = std::max(validDrawBufCount, i + 1); } - m_defaultFramebuffers.reserve(colorViews.size()); - for (SizeT i = 0; i < colorViews.size(); ++i) { - if (colorViews[i] == VK_NULL_HANDLE || depthStencilViews[i] == VK_NULL_HANDLE) { - DestroyDefaultFramebuffers(); - return false; + Int width = 0; + Int height = 0; + Vector colorAttachmentDescriptions(validDrawBufCount); + Vector colorAttachmentRefs(validDrawBufCount); + Vector descriptorImageInfo(validDrawBufCount); + // This should automatically work on default & offscreen FBO + // assuming default FBO has the right param + for (Int i = 0; i < validDrawBufCount; ++i) { + auto drawbuf = drawbufs[i]; + if (drawbuf == FramebufferAttachmentType::None || + fbo.GetAttachment(drawbuf).IsRenderbuffer()) + continue; + + auto& att = fbo.GetAttachment(drawbuf); + auto* texture = att.GetTexture().get(); + const auto textureTarget = texture->GetTarget(); + + // Color attachment description + VkAttachmentDescription& desc = colorAttachmentDescriptions[i]; + switch (textureTarget) { + case TextureTarget::Texture2D: { + auto* texture2d = + static_cast(texture); + desc.format = + MG_Util::ConvertTextureInternalFormatToVkEnum( + texture2d->GetFormat()); + desc.samples = VK_SAMPLE_COUNT_1_BIT; + Bool hasClear = m_clearManager.HasPendingClear(texture); + 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.finalLayout = isDefaultFbo ? + VK_IMAGE_LAYOUT_PRESENT_SRC_KHR : + VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + if (width == 0) + width = texture2d->GetBaseSize().x(); + if (height == 0) + height = texture2d->GetBaseSize().y(); + + Bool ok = m_textureManager.SyncTextureAndGetDescriptor(*texture, descriptorImageInfo[i]); + MOBILEGL_ASSERT(ok, "GetOrCreateRenderPass: SyncTextureAndGetDescriptor failed"); + + break; + } + default: + MOBILEGL_ASSERT(false, "Unsupported texture target"); } - VkImageView attachments[] = {colorViews[i], depthStencilViews[i]}; - VkFramebufferCreateInfo createInfo{VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO}; - createInfo.renderPass = m_renderPassLoad; - createInfo.attachmentCount = static_cast(std::size(attachments)); - createInfo.pAttachments = attachments; - createInfo.width = extent.width; - createInfo.height = extent.height; - createInfo.layers = 1; - VkFramebuffer framebuffer = VK_NULL_HANDLE; - if (vkCreateFramebuffer(m_device, &createInfo, nullptr, &framebuffer) != VK_SUCCESS) { - DestroyDefaultFramebuffers(); - return false; - } - m_defaultFramebuffers.push_back(framebuffer); - } - m_defaultExtent = extent; - return true; - } - Bool VkRenderPassManager::GetDefaultRenderTarget(Uint32 imageIndex, VkRenderPass& outRenderPass, - VkFramebuffer& outFramebuffer, VkExtent2D& outExtent, - VkFormat& outDepthStencilFormat) const { - if (imageIndex >= m_defaultFramebuffers.size() || m_renderPassLoad == VK_NULL_HANDLE) { - return false; - } - outRenderPass = m_renderPassLoad; - outFramebuffer = m_defaultFramebuffers[imageIndex]; - outExtent = m_defaultExtent; - outDepthStencilFormat = m_depthStencilFormat; - return outFramebuffer != VK_NULL_HANDLE; - } - - Bool VkRenderPassManager::EnsureOffscreenRenderTarget(const OffscreenRenderTargetInfo& targetInfo) { - if (m_device == VK_NULL_HANDLE || targetInfo.colorView == VK_NULL_HANDLE || - targetInfo.colorFormat == VK_FORMAT_UNDEFINED || targetInfo.extent.width == 0 || - targetInfo.extent.height == 0) { - return false; + // Attachment reference + VkAttachmentReference& attachmentRef = colorAttachmentRefs[i]; + attachmentRef.attachment = i; + attachmentRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; } - const Bool hasDepthStencil = - targetInfo.depthStencilView != VK_NULL_HANDLE && targetInfo.depthStencilFormat != VK_FORMAT_UNDEFINED; - auto& target = m_offscreenRenderTargets[targetInfo.targetExternalIndex]; - if (target.framebuffer != VK_NULL_HANDLE && target.renderPassLoad != VK_NULL_HANDLE && - target.targetVersion == targetInfo.targetVersion && target.colorView == targetInfo.colorView && - target.colorFormat == targetInfo.colorFormat && target.depthStencilView == targetInfo.depthStencilView && - target.depthStencilFormat == targetInfo.depthStencilFormat && - target.extent.width == targetInfo.extent.width && target.extent.height == targetInfo.extent.height) { - return true; - } - DestroyOffscreenRenderTarget(target); + // Depth attachment description + VkAttachmentDescription depthAttachmentDescription; + auto& depthAtt = fbo.GetAttachment(FramebufferAttachmentType::Depth); + depthAttachmentDescription.format = + MG_Util::ConvertTextureInternalFormatToVkEnum(depthAtt.GetTexture()->GetFormat()); + depthAttachmentDescription.samples = VK_SAMPLE_COUNT_1_BIT; + depthAttachmentDescription.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; + 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.finalLayout = isDefaultFbo ? + VK_IMAGE_LAYOUT_PRESENT_SRC_KHR : + VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; - const VkFormat depthStencilFormat = hasDepthStencil ? targetInfo.depthStencilFormat : VK_FORMAT_UNDEFINED; - target.renderPassLoad = CreateRenderPass(targetInfo.colorFormat, depthStencilFormat, VK_ATTACHMENT_LOAD_OP_LOAD, - VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); - if (target.renderPassLoad == VK_NULL_HANDLE) { - return false; - } + // Depth attachment ref + VkAttachmentReference depthAttachmentRef; + depthAttachmentRef.attachment = 1; + depthAttachmentRef.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; - Array attachments{}; - attachments[0] = targetInfo.colorView; - Uint32 attachmentCount = 1; - if (hasDepthStencil) { - attachments[1] = targetInfo.depthStencilView; - attachmentCount = 2; - } + // Subpass + VkSubpassDescription subpassDesc; + subpassDesc.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; + subpassDesc.colorAttachmentCount = colorAttachmentRefs.size(); + subpassDesc.pColorAttachments = colorAttachmentRefs.data(); + subpassDesc.pDepthStencilAttachment = &depthAttachmentRef; - VkFramebufferCreateInfo framebufferInfo{VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO}; - framebufferInfo.renderPass = target.renderPassLoad; - framebufferInfo.attachmentCount = attachmentCount; - framebufferInfo.pAttachments = attachments.data(); - framebufferInfo.width = targetInfo.extent.width; - framebufferInfo.height = targetInfo.extent.height; - framebufferInfo.layers = 1; - VK_VERIFY(vkCreateFramebuffer(m_device, &framebufferInfo, nullptr, &target.framebuffer), - "vkCreateFramebuffer(offscreen)"); - - target.targetVersion = targetInfo.targetVersion; - target.colorView = targetInfo.colorView; - target.colorFormat = targetInfo.colorFormat; - target.depthStencilView = targetInfo.depthStencilView; - target.depthStencilFormat = targetInfo.depthStencilFormat; - target.extent = targetInfo.extent; - return true; - } - - Bool VkRenderPassManager::GetOffscreenRenderTarget(Uint targetExternalIndex, VkRenderPass& outRenderPass, - VkFramebuffer& outFramebuffer, VkExtent2D& outExtent, - VkFormat& outDepthStencilFormat) const { - auto it = m_offscreenRenderTargets.find(targetExternalIndex); - if (it == m_offscreenRenderTargets.end() || it->second.renderPassLoad == VK_NULL_HANDLE || - it->second.framebuffer == VK_NULL_HANDLE) { - return false; - } - - outRenderPass = it->second.renderPassLoad; - outFramebuffer = it->second.framebuffer; - outExtent = it->second.extent; - outDepthStencilFormat = it->second.depthStencilFormat; - return true; - } - - void VkRenderPassManager::RemoveOffscreenRenderTarget(Uint targetExternalIndex) { - auto it = m_offscreenRenderTargets.find(targetExternalIndex); - if (it == m_offscreenRenderTargets.end()) { - return; - } - DestroyOffscreenRenderTarget(it->second); - m_offscreenRenderTargets.erase(it); - } - - void VkRenderPassManager::BeginRenderPass(VkCommandBuffer commandBuffer, VkRenderPass renderPass, - VkFramebuffer framebuffer, VkExtent2D extent) const { - VkRenderPassBeginInfo beginInfo{}; - beginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; - beginInfo.renderPass = renderPass; - beginInfo.framebuffer = framebuffer; - beginInfo.renderArea.offset = {0, 0}; - beginInfo.renderArea.extent = extent; - beginInfo.clearValueCount = 0; - beginInfo.pClearValues = nullptr; - vkCmdBeginRenderPass(commandBuffer, &beginInfo, VK_SUBPASS_CONTENTS_INLINE); - } - - void VkRenderPassManager::EndRenderPass(VkCommandBuffer commandBuffer) const { - vkCmdEndRenderPass(commandBuffer); - } - - void VkRenderPassManager::RecordColorClear(VkCommandBuffer commandBuffer, VkExtent2D extent, - const VkClearColorValue& clearColor) const { - VkClearAttachment clearAttachment{}; - clearAttachment.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - clearAttachment.colorAttachment = 0; - clearAttachment.clearValue.color = clearColor; - - VkClearRect clearRect{}; - clearRect.rect.offset = {0, 0}; - clearRect.rect.extent = extent; - clearRect.baseArrayLayer = 0; - clearRect.layerCount = 1; - - vkCmdClearAttachments(commandBuffer, 1, &clearAttachment, 1, &clearRect); - } - - void VkRenderPassManager::RecordDepthStencilClear(VkCommandBuffer commandBuffer, VkExtent2D extent, GLbitfield mask, - Float depth, Uint32 stencil, VkFormat depthStencilFormat) const { - if (depthStencilFormat == VK_FORMAT_UNDEFINED) { - return; - } - - VkImageAspectFlags aspectMask = 0; - if ((mask & GL_DEPTH_BUFFER_BIT) != 0) { - aspectMask |= VK_IMAGE_ASPECT_DEPTH_BIT; - } - if ((mask & GL_STENCIL_BUFFER_BIT) != 0 && HasStencilComponent(depthStencilFormat)) { - aspectMask |= VK_IMAGE_ASPECT_STENCIL_BIT; - } - if (aspectMask == 0) { - return; - } - - VkClearAttachment clearAttachment{}; - clearAttachment.aspectMask = aspectMask; - clearAttachment.clearValue.depthStencil.depth = depth; - clearAttachment.clearValue.depthStencil.stencil = stencil; - - VkClearRect clearRect{}; - clearRect.rect.offset = {0, 0}; - clearRect.rect.extent = extent; - clearRect.baseArrayLayer = 0; - clearRect.layerCount = 1; - - vkCmdClearAttachments(commandBuffer, 1, &clearAttachment, 1, &clearRect); - } - - VkRenderPass VkRenderPassManager::CreateDefaultRenderPass(VkAttachmentLoadOp colorLoadOp) const { - MOBILEGL_ASSERT(m_device != VK_NULL_HANDLE, "VkRenderPassManager: device is null"); - MOBILEGL_ASSERT(m_colorFormat != VK_FORMAT_UNDEFINED, "VkRenderPassManager: color format is undefined"); - MOBILEGL_ASSERT(m_depthStencilFormat != VK_FORMAT_UNDEFINED, - "VkRenderPassManager: depth/stencil format is undefined"); - return CreateRenderPass(m_colorFormat, m_depthStencilFormat, colorLoadOp, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR); - } - - VkRenderPass VkRenderPassManager::CreateRenderPass(VkFormat colorFormat, VkFormat depthStencilFormat, - VkAttachmentLoadOp colorLoadOp, - VkImageLayout colorFinalLayout) const { - VkAttachmentDescription color{}; - color.format = colorFormat; - color.samples = VK_SAMPLE_COUNT_1_BIT; - color.loadOp = colorLoadOp; - color.storeOp = VK_ATTACHMENT_STORE_OP_STORE; - color.initialLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; - color.finalLayout = colorFinalLayout; - color.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; - color.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; - - const Bool hasDepthStencil = depthStencilFormat != VK_FORMAT_UNDEFINED; - VkAttachmentDescription depthStencil{}; - if (hasDepthStencil) { - depthStencil.format = depthStencilFormat; - depthStencil.samples = VK_SAMPLE_COUNT_1_BIT; - depthStencil.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD; - depthStencil.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; - depthStencil.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_LOAD; - depthStencil.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; - depthStencil.initialLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; - depthStencil.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; - } - - VkAttachmentReference colorRef{0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL}; - VkAttachmentReference depthStencilRef{1, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL}; - - VkSubpassDescription subpass{}; - subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; - subpass.colorAttachmentCount = 1; - subpass.pColorAttachments = &colorRef; - if (hasDepthStencil) { - subpass.pDepthStencilAttachment = &depthStencilRef; - } - - Array attachments{}; - attachments[0] = color; - Uint32 attachmentCount = 1; - if (hasDepthStencil) { - attachments[1] = depthStencil; - attachmentCount = 2; - } - - VkRenderPassCreateInfo createInfo{VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO}; - createInfo.attachmentCount = attachmentCount; - createInfo.pAttachments = attachments.data(); - createInfo.subpassCount = 1; - createInfo.pSubpasses = &subpass; + // Render Pass + VkRenderPassCreateInfo renderPassCreateInfo; + renderPassCreateInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; + renderPassCreateInfo.attachmentCount = colorAttachmentDescriptions.size(); + renderPassCreateInfo.pAttachments = colorAttachmentDescriptions.data(); + renderPassCreateInfo.subpassCount = 1; + renderPassCreateInfo.pSubpasses = &subpassDesc; VkRenderPass renderPass = VK_NULL_HANDLE; - VK_VERIFY(vkCreateRenderPass(m_device, &createInfo, nullptr, &renderPass), "vkCreateRenderPass"); - return renderPass; + VK_VERIFY(vkCreateRenderPass(m_device, &renderPassCreateInfo, nullptr, &renderPass)); + + Vector attachmentViews(descriptorImageInfo.size(), VK_NULL_HANDLE); + for (Int i = 0; i < descriptorImageInfo.size(); i++) { + attachmentViews[i] = descriptorImageInfo[i].imageView; + } + + // Framebuffer + VkFramebufferCreateInfo framebufferCreateInfo; + framebufferCreateInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; + framebufferCreateInfo.renderPass = renderPass; + framebufferCreateInfo.attachmentCount = attachmentViews.size(); + framebufferCreateInfo.pAttachments = attachmentViews.data(); + framebufferCreateInfo.width = width; + framebufferCreateInfo.height = height; + VkFramebuffer framebuffer = VK_NULL_HANDLE; + VK_VERIFY(vkCreateFramebuffer(m_device, &framebufferCreateInfo, nullptr, &framebuffer)); + IntVec2 extent = {width, height}; + m_renderPasses[hash] = { renderPass, framebuffer, Move(descriptorImageInfo), extent }; + return m_renderPasses[hash]; } - void VkRenderPassManager::DestroyDefaultFramebuffers() { - for (auto framebuffer : m_defaultFramebuffers) { - if (framebuffer != VK_NULL_HANDLE) { - vkDestroyFramebuffer(m_device, framebuffer, nullptr); - } - } - m_defaultFramebuffers.clear(); - m_defaultExtent = {0, 0}; + Bool VkRenderPassManager::StartRenderPass(VkCommandBuffer commandBuffer, RenderPassEntry& renderPassEntry) { + if (m_activeRenderPass != nullptr) + return false; + + m_activeRenderPass = &renderPassEntry; + VkRenderPassBeginInfo renderPassBeginInfo; + renderPassBeginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; + renderPassBeginInfo.renderPass = m_activeRenderPass->renderPass; + renderPassBeginInfo.framebuffer = m_activeRenderPass->framebuffer; + renderPassBeginInfo.renderArea.offset = { 0, 0 }; + renderPassBeginInfo.renderArea.extent = { + (Uint32)m_activeRenderPass->extent.x(), (Uint32)m_activeRenderPass->extent.y() }; + + // TODO: should query proper clear color + VkClearValue clearValue; + clearValue.color = { 0.0f, 0.0f, 0.0f, 1.0f }; + clearValue.depthStencil = { 1.0f, 0 }; + vkCmdBeginRenderPass(commandBuffer, &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE); + + return true; } - void VkRenderPassManager::DestroyOffscreenRenderTarget(OffscreenRenderTarget& target) { - if (target.framebuffer != VK_NULL_HANDLE) { - vkDestroyFramebuffer(m_device, target.framebuffer, nullptr); - target.framebuffer = VK_NULL_HANDLE; - } - if (target.renderPassLoad != VK_NULL_HANDLE) { - vkDestroyRenderPass(m_device, target.renderPassLoad, nullptr); - target.renderPassLoad = VK_NULL_HANDLE; - } - target.targetVersion = 0; - target.colorView = VK_NULL_HANDLE; - target.colorFormat = VK_FORMAT_UNDEFINED; - target.depthStencilView = VK_NULL_HANDLE; - target.depthStencilFormat = VK_FORMAT_UNDEFINED; - target.extent = {0, 0}; - } - - Bool VkRenderPassManager::HasStencilComponent(VkFormat format) { - return format == VK_FORMAT_D24_UNORM_S8_UINT || format == VK_FORMAT_D32_SFLOAT_S8_UINT; + Bool VkRenderPassManager::EndRenderPass(VkCommandBuffer commandBuffer) { + if (m_activeRenderPass == nullptr) + return false; + vkCmdEndRenderPass(commandBuffer); + return true; } } // namespace MobileGL::MG_Backend::DirectVulkan diff --git a/MobileGL/MG_Backend/DirectVulkan/Renderer/VkRenderPassManager.h b/MobileGL/MG_Backend/DirectVulkan/Renderer/VkRenderPassManager.h index d7329761..f1fceb23 100644 --- a/MobileGL/MG_Backend/DirectVulkan/Renderer/VkRenderPassManager.h +++ b/MobileGL/MG_Backend/DirectVulkan/Renderer/VkRenderPassManager.h @@ -8,75 +8,54 @@ #pragma once +#include "VkClearManager.h" +#include "VkTextureManager.h" #include "../VkIncludes.h" +#include "../VulkanRendererConfig.h" +#include "MG_State/GLState/FramebufferState/FramebufferObject.h" + #include namespace MobileGL::MG_Backend::DirectVulkan { + struct RenderPassEntry { + static inline VkDevice s_device; + VkRenderPass renderPass = VK_NULL_HANDLE; + VkFramebuffer framebuffer = VK_NULL_HANDLE; + Vector descriptorImageInfo; + IntVec2 extent = {0, 0}; + + ~RenderPassEntry() { + if (renderPass != VK_NULL_HANDLE) { + vkDestroyRenderPass(s_device, renderPass, nullptr); + } + if (framebuffer != VK_NULL_HANDLE) { + vkDestroyFramebuffer(s_device, framebuffer, nullptr); + } + } + }; + class VkRenderPassManager { public: - struct InitInfo { - VkDevice device = VK_NULL_HANDLE; - VkFormat colorFormat = VK_FORMAT_UNDEFINED; - VkFormat depthStencilFormat = VK_FORMAT_UNDEFINED; - }; + using HashType = Uint64; + VkRenderPassManager(VkDevice device, + const VulkanRendererConfig& config, VkClearManager& clearManager, VkTextureManager& textureManager); + ~VkRenderPassManager(); - struct OffscreenRenderTargetInfo { - Uint targetExternalIndex = 0; - Uint16 targetVersion = 0; - VkImageView colorView = VK_NULL_HANDLE; - VkFormat colorFormat = VK_FORMAT_UNDEFINED; - VkImageView depthStencilView = VK_NULL_HANDLE; - VkFormat depthStencilFormat = VK_FORMAT_UNDEFINED; - VkExtent2D extent = {0, 0}; - }; - - Bool Initialize(const InitInfo& initInfo); + Bool Initialize(); void Shutdown(); - Bool RecreateDefaultFramebuffers(const Vector& colorViews, - const Vector& depthStencilViews, VkExtent2D extent); - Bool GetDefaultRenderTarget(Uint32 imageIndex, VkRenderPass& outRenderPass, VkFramebuffer& outFramebuffer, - VkExtent2D& outExtent, VkFormat& outDepthStencilFormat) const; - - Bool EnsureOffscreenRenderTarget(const OffscreenRenderTargetInfo& targetInfo); - Bool GetOffscreenRenderTarget(Uint targetExternalIndex, VkRenderPass& outRenderPass, - VkFramebuffer& outFramebuffer, VkExtent2D& outExtent, - VkFormat& outDepthStencilFormat) const; - void RemoveOffscreenRenderTarget(Uint targetExternalIndex); - - void BeginRenderPass(VkCommandBuffer commandBuffer, VkRenderPass renderPass, VkFramebuffer framebuffer, - VkExtent2D extent) const; - void EndRenderPass(VkCommandBuffer commandBuffer) const; - void RecordColorClear(VkCommandBuffer commandBuffer, VkExtent2D extent, - const VkClearColorValue& clearColor) const; - void RecordDepthStencilClear(VkCommandBuffer commandBuffer, VkExtent2D extent, GLbitfield mask, Float depth, - Uint32 stencil, VkFormat depthStencilFormat) const; - + HashType ComputeHash(const MG_State::GLState::FramebufferObject& fbo) const; + RenderPassEntry& GetOrCreateRenderPass(const MG_State::GLState::FramebufferObject& fbo); + RenderPassEntry* GetActiveRenderPass() const { return m_activeRenderPass; } + Bool StartRenderPass(VkCommandBuffer commandBuffer, RenderPassEntry& renderPassEntry); + Bool EndRenderPass(VkCommandBuffer commandBuffer); private: - struct OffscreenRenderTarget { - Uint16 targetVersion = 0; - VkImageView colorView = VK_NULL_HANDLE; - VkFormat colorFormat = VK_FORMAT_UNDEFINED; - VkImageView depthStencilView = VK_NULL_HANDLE; - VkFormat depthStencilFormat = VK_FORMAT_UNDEFINED; - VkExtent2D extent = {0, 0}; - VkRenderPass renderPassLoad = VK_NULL_HANDLE; - VkFramebuffer framebuffer = VK_NULL_HANDLE; - }; - - VkRenderPass CreateDefaultRenderPass(VkAttachmentLoadOp colorLoadOp) const; - VkRenderPass CreateRenderPass(VkFormat colorFormat, VkFormat depthStencilFormat, VkAttachmentLoadOp colorLoadOp, - VkImageLayout colorFinalLayout) const; - void DestroyDefaultFramebuffers(); - void DestroyOffscreenRenderTarget(OffscreenRenderTarget& target); - static Bool HasStencilComponent(VkFormat format); - VkDevice m_device = VK_NULL_HANDLE; - VkFormat m_colorFormat = VK_FORMAT_UNDEFINED; - VkFormat m_depthStencilFormat = VK_FORMAT_UNDEFINED; - VkRenderPass m_renderPassLoad = VK_NULL_HANDLE; - Vector m_defaultFramebuffers; - VkExtent2D m_defaultExtent = {0, 0}; - UnorderedMap m_offscreenRenderTargets; + const VulkanRendererConfig& m_config; + VkClearManager& m_clearManager; + VkTextureManager& m_textureManager; + UnorderedMap m_renderPasses; + RenderPassEntry* m_activeRenderPass = nullptr; + static inline XXH64_state_t* m_hashState = XXH64_createState(); }; } // namespace MobileGL::MG_Backend::DirectVulkan diff --git a/MobileGL/MG_Backend/DirectVulkan/Renderer/VkRenderTargetManager.cpp b/MobileGL/MG_Backend/DirectVulkan/Renderer/VkRenderTargetManager.cpp deleted file mode 100644 index 7c26a7b0..00000000 --- a/MobileGL/MG_Backend/DirectVulkan/Renderer/VkRenderTargetManager.cpp +++ /dev/null @@ -1,325 +0,0 @@ -// MobileGL - MobileGL/MG_Backend/DirectVulkan/Renderer/VkFramebufferManager.cpp -// Copyright (c) 2025-2026 MobileGL-Dev -// Licensed under the GNU Lesser General Public License v3.0: -// https://www.gnu.org/licenses/gpl-3.0.txt -// https://www.gnu.org/licenses/lgpl-3.0.txt -// SPDX-License-Identifier: LGPL-3.0-only -// End of Source File Header - -#include "VkRenderTargetManager.h" - -#include -#include - -namespace MobileGL::MG_Backend::DirectVulkan { - Bool VkRenderTargetManager::Initialize(const InitInfo& initInfo) { - m_device = initInfo.device; - m_physicalDevice = initInfo.physicalDevice; - m_allocator = initInfo.allocator; - return m_device != VK_NULL_HANDLE && m_physicalDevice != VK_NULL_HANDLE && m_allocator != nullptr; - } - - void VkRenderTargetManager::Shutdown() { - for (auto& [_, target] : m_offscreenColorTargets) { - DestroyOffscreenColorTarget(target); - } - m_offscreenColorTargets.clear(); - m_device = VK_NULL_HANDLE; - m_physicalDevice = VK_NULL_HANDLE; - m_allocator = nullptr; - } - - Bool VkRenderTargetManager::EnsureOffscreenColorTarget(Uint glFboExternalIndex, - const MG_State::GLState::FramebufferObject& glFbo) { - const auto& colorAttachment = glFbo.GetAttachment(FramebufferAttachmentType::Color0); - if (!colorAttachment.IsValid() || colorAttachment.IsEmpty()) { - MGLOG_W("VkFramebufferManager: FBO %u has no valid COLOR0 attachment", glFboExternalIndex); - return false; - } - - const auto objectVersion = glFbo.GetObjectVersion(); - auto& target = m_offscreenColorTargets[glFboExternalIndex]; - if (target.image != VK_NULL_HANDLE && target.glObjectVersion == objectVersion) { - return true; - } - - return RecreateOffscreenColorTarget(target, glFbo, colorAttachment, objectVersion); - } - - 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()) { - return false; - } - auto& target = it->second; - if (target.image == VK_NULL_HANDLE) { - 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; - } - - Bool VkRenderTargetManager::GetOffscreenRenderSurface(Uint glFboExternalIndex, VkImageView& outColorView, - VkFormat& outColorFormat, VkImageView& outDepthStencilView, - VkFormat& outDepthStencilFormat, VkExtent2D& outExtent) const { - auto it = m_offscreenColorTargets.find(glFboExternalIndex); - if (it == m_offscreenColorTargets.end() || it->second.imageView == VK_NULL_HANDLE) { - return false; - } - outColorView = it->second.imageView; - outColorFormat = it->second.format; - outDepthStencilView = it->second.depthStencilImageView; - outExtent = it->second.extent; - outDepthStencilFormat = it->second.depthStencilFormat; - return true; - } - - Bool VkRenderTargetManager::RecreateOffscreenColorTarget( - OffscreenColorTarget& target, const MG_State::GLState::FramebufferObject& glFbo, - const MG_State::GLState::FramebufferAttachmentObject& colorAttachment, Uint16 glObjectVersion) { - DestroyOffscreenColorTarget(target); - - const auto size = colorAttachment.GetSize(); - if (size.x() <= 0 || size.y() <= 0) { - MGLOG_W("VkFramebufferManager: COLOR0 attachment size is invalid (%d, %d)", size.x(), size.y()); - return false; - } - - const VkFormat format = ResolveColorFormat(colorAttachment); - if (format == VK_FORMAT_UNDEFINED) { - MGLOG_W("VkFramebufferManager: COLOR0 attachment format is unsupported for Vulkan clear"); - return false; - } - - VkImageCreateInfo imageInfo{}; - imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; - imageInfo.imageType = VK_IMAGE_TYPE_2D; - imageInfo.extent.width = static_cast(size.x()); - imageInfo.extent.height = static_cast(size.y()); - imageInfo.extent.depth = 1; - imageInfo.mipLevels = 1; - imageInfo.arrayLayers = 1; - imageInfo.format = format; - imageInfo.tiling = VK_IMAGE_TILING_OPTIMAL; - imageInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; - imageInfo.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | - VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_SAMPLED_BIT; - imageInfo.samples = VK_SAMPLE_COUNT_1_BIT; - imageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; - VmaAllocationCreateInfo colorAllocationInfo{}; - colorAllocationInfo.usage = VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE; - colorAllocationInfo.requiredFlags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; - VK_VERIFY(vmaCreateImage(m_allocator, &imageInfo, &colorAllocationInfo, &target.image, &target.allocation, nullptr), - "vmaCreateImage(offscreen color)"); - - VkImageViewCreateInfo viewInfo{}; - viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; - viewInfo.image = target.image; - viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D; - viewInfo.format = format; - viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - viewInfo.subresourceRange.baseMipLevel = 0; - viewInfo.subresourceRange.levelCount = 1; - viewInfo.subresourceRange.baseArrayLayer = 0; - viewInfo.subresourceRange.layerCount = 1; - VK_VERIFY(vkCreateImageView(m_device, &viewInfo, nullptr, &target.imageView), - "vkCreateImageView(offscreen color)"); - - const auto& depthAttachment = glFbo.GetAttachment(FramebufferAttachmentType::Depth); - const auto& stencilAttachment = glFbo.GetAttachment(FramebufferAttachmentType::Stencil); - const Bool requestedDepthStencil = (depthAttachment.IsValid() && !depthAttachment.IsEmpty()) || - (stencilAttachment.IsValid() && !stencilAttachment.IsEmpty()); - VkFormat depthStencilFormat = ResolveDepthStencilFormat(depthAttachment, stencilAttachment); - if (depthStencilFormat == VK_FORMAT_D24_UNORM_S8_UINT) { - depthStencilFormat = - FindSupportedDepthStencilFormat({VK_FORMAT_D24_UNORM_S8_UINT, VK_FORMAT_D32_SFLOAT_S8_UINT}); - } else if (depthStencilFormat == VK_FORMAT_D32_SFLOAT) { - depthStencilFormat = FindSupportedDepthStencilFormat({VK_FORMAT_D32_SFLOAT, VK_FORMAT_D16_UNORM}); - } - const Bool hasDepthStencil = (depthStencilFormat != VK_FORMAT_UNDEFINED); - if (requestedDepthStencil && !hasDepthStencil) { - MGLOG_W("VkFramebufferManager: FBO %u depth/stencil attachment exists but format is unsupported", - glFbo.GetExternalIndex()); - } - if (hasDepthStencil) { - VkImageCreateInfo depthImageInfo{}; - depthImageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; - depthImageInfo.imageType = VK_IMAGE_TYPE_2D; - depthImageInfo.extent.width = static_cast(size.x()); - depthImageInfo.extent.height = static_cast(size.y()); - depthImageInfo.extent.depth = 1; - depthImageInfo.mipLevels = 1; - depthImageInfo.arrayLayers = 1; - depthImageInfo.format = depthStencilFormat; - depthImageInfo.tiling = VK_IMAGE_TILING_OPTIMAL; - depthImageInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; - depthImageInfo.usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; - depthImageInfo.samples = VK_SAMPLE_COUNT_1_BIT; - depthImageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; - VmaAllocationCreateInfo depthAllocationInfo{}; - depthAllocationInfo.usage = VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE; - depthAllocationInfo.requiredFlags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; - VK_VERIFY(vmaCreateImage(m_allocator, &depthImageInfo, &depthAllocationInfo, &target.depthStencilImage, - &target.depthStencilAllocation, nullptr), - "vmaCreateImage(offscreen depth/stencil)"); - - VkImageAspectFlags depthAspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; - if (depthStencilFormat == VK_FORMAT_D24_UNORM_S8_UINT || - depthStencilFormat == VK_FORMAT_D32_SFLOAT_S8_UINT) { - depthAspectMask |= VK_IMAGE_ASPECT_STENCIL_BIT; - } - VkImageViewCreateInfo depthViewInfo{}; - depthViewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; - depthViewInfo.image = target.depthStencilImage; - depthViewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D; - depthViewInfo.format = depthStencilFormat; - depthViewInfo.subresourceRange.aspectMask = depthAspectMask; - depthViewInfo.subresourceRange.baseMipLevel = 0; - depthViewInfo.subresourceRange.levelCount = 1; - depthViewInfo.subresourceRange.baseArrayLayer = 0; - depthViewInfo.subresourceRange.layerCount = 1; - VK_VERIFY(vkCreateImageView(m_device, &depthViewInfo, nullptr, &target.depthStencilImageView), - "vkCreateImageView(offscreen depth/stencil)"); - } - - target.layout = VK_IMAGE_LAYOUT_UNDEFINED; - target.extent = {static_cast(size.x()), static_cast(size.y())}; - target.format = format; - target.depthStencilLayout = VK_IMAGE_LAYOUT_UNDEFINED; - target.depthStencilFormat = depthStencilFormat; - target.glObjectVersion = glObjectVersion; - target.colorTextureExternalIndex = (colorAttachment.IsTexture() && colorAttachment.GetTexture()) - ? colorAttachment.GetTexture()->GetExternalIndex() - : 0; - return true; - } - - void VkRenderTargetManager::DestroyOffscreenColorTarget(OffscreenColorTarget& target) { - if (target.imageView != VK_NULL_HANDLE) { - vkDestroyImageView(m_device, target.imageView, nullptr); - target.imageView = VK_NULL_HANDLE; - } - if (target.depthStencilImageView != VK_NULL_HANDLE) { - vkDestroyImageView(m_device, target.depthStencilImageView, nullptr); - target.depthStencilImageView = VK_NULL_HANDLE; - } - if (target.image != VK_NULL_HANDLE) { - vmaDestroyImage(m_allocator, target.image, target.allocation); - target.image = VK_NULL_HANDLE; - } - if (target.depthStencilImage != VK_NULL_HANDLE) { - vmaDestroyImage(m_allocator, target.depthStencilImage, target.depthStencilAllocation); - target.depthStencilImage = VK_NULL_HANDLE; - } - target.allocation = nullptr; - target.depthStencilAllocation = nullptr; - target.layout = VK_IMAGE_LAYOUT_UNDEFINED; - target.depthStencilLayout = VK_IMAGE_LAYOUT_UNDEFINED; - target.extent = {0, 0}; - target.format = VK_FORMAT_UNDEFINED; - target.depthStencilFormat = VK_FORMAT_UNDEFINED; - target.glObjectVersion = 0; - target.colorTextureExternalIndex = 0; - } - - VkFormat VkRenderTargetManager::ResolveColorFormat( - const MG_State::GLState::FramebufferAttachmentObject& colorAttachment) { - TextureInternalFormat internalFormat = TextureInternalFormat::Unknown; - if (colorAttachment.IsTexture()) { - const auto texture = colorAttachment.GetTexture(); - internalFormat = texture ? texture->GetFormat() : TextureInternalFormat::Unknown; - } else if (colorAttachment.IsRenderbuffer()) { - const auto renderbuffer = colorAttachment.GetRenderbuffer(); - internalFormat = renderbuffer ? renderbuffer->GetInternalFormat() : TextureInternalFormat::Unknown; - } - - switch (internalFormat) { - case TextureInternalFormat::RGBA: - case TextureInternalFormat::RGBA8: - case TextureInternalFormat::SRGB8Alpha8: - return VK_FORMAT_R8G8B8A8_UNORM; - default: - return VK_FORMAT_UNDEFINED; - } - } - - VkFormat VkRenderTargetManager::ResolveDepthStencilFormat( - const MG_State::GLState::FramebufferAttachmentObject& depthAttachment, - const MG_State::GLState::FramebufferAttachmentObject& stencilAttachment) { - const auto resolveAttachmentFormat = [](const MG_State::GLState::FramebufferAttachmentObject& attachment) { - TextureInternalFormat internalFormat = TextureInternalFormat::Unknown; - if (attachment.IsTexture()) { - const auto texture = attachment.GetTexture(); - internalFormat = texture ? texture->GetFormat() : TextureInternalFormat::Unknown; - } else if (attachment.IsRenderbuffer()) { - const auto renderbuffer = attachment.GetRenderbuffer(); - internalFormat = renderbuffer ? renderbuffer->GetInternalFormat() : TextureInternalFormat::Unknown; - } - return internalFormat; - }; - - const auto depthFormat = resolveAttachmentFormat(depthAttachment); - const auto stencilFormat = resolveAttachmentFormat(stencilAttachment); - - switch (depthFormat) { - case TextureInternalFormat::Depth24Stencil8: - case TextureInternalFormat::Depth32FStencil8: - case TextureInternalFormat::DepthStencil: - return VK_FORMAT_D24_UNORM_S8_UINT; - case TextureInternalFormat::DepthComponent16: - return VK_FORMAT_D16_UNORM; - case TextureInternalFormat::DepthComponent24: - case TextureInternalFormat::DepthComponent32: - case TextureInternalFormat::DepthComponent32F: - case TextureInternalFormat::DepthComponent: - return VK_FORMAT_D32_SFLOAT; - default: - break; - } - - switch (stencilFormat) { - case TextureInternalFormat::Depth24Stencil8: - case TextureInternalFormat::Depth32FStencil8: - case TextureInternalFormat::DepthStencil: - return VK_FORMAT_D24_UNORM_S8_UINT; - default: - return VK_FORMAT_UNDEFINED; - } - } - - VkFormat VkRenderTargetManager::FindSupportedDepthStencilFormat(const Vector& candidates) const { - for (auto format : candidates) { - VkFormatProperties properties{}; - vkGetPhysicalDeviceFormatProperties(m_physicalDevice, format, &properties); - if ((properties.optimalTilingFeatures & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT) != 0) { - return format; - } - } - return VK_FORMAT_UNDEFINED; - } -} // namespace MobileGL::MG_Backend::DirectVulkan diff --git a/MobileGL/MG_Backend/DirectVulkan/Renderer/VkRenderTargetManager.h b/MobileGL/MG_Backend/DirectVulkan/Renderer/VkRenderTargetManager.h deleted file mode 100644 index 93ec4e31..00000000 --- a/MobileGL/MG_Backend/DirectVulkan/Renderer/VkRenderTargetManager.h +++ /dev/null @@ -1,75 +0,0 @@ -// MobileGL - MobileGL/MG_Backend/DirectVulkan/Renderer/VkFramebufferManager.h -// Copyright (c) 2025-2026 MobileGL-Dev -// Licensed under the GNU Lesser General Public License v3.0: -// https://www.gnu.org/licenses/gpl-3.0.txt -// https://www.gnu.org/licenses/lgpl-3.0.txt -// SPDX-License-Identifier: LGPL-3.0-only -// End of Source File Header - -#pragma once - -#include "../VkIncludes.h" -#include -#include -#include - -namespace MobileGL::MG_Backend::DirectVulkan { - class VkRenderTargetManager { - public: - struct InitInfo { - VkDevice device = VK_NULL_HANDLE; - VkPhysicalDevice physicalDevice = VK_NULL_HANDLE; - VmaAllocator allocator = nullptr; - }; - - VkRenderTargetManager() = default; - ~VkRenderTargetManager() = default; - - Bool Initialize(const InitInfo& initInfo); - void Shutdown(); - - Bool EnsureOffscreenColorTarget(Uint glFboExternalIndex, const MG_State::GLState::FramebufferObject& glFbo); - 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 GetOffscreenRenderSurface(Uint glFboExternalIndex, VkImageView& outColorView, VkFormat& outColorFormat, - VkImageView& outDepthStencilView, VkFormat& outDepthStencilFormat, - VkExtent2D& outExtent) const; - - private: - struct OffscreenColorTarget { - VkImage image = VK_NULL_HANDLE; - VmaAllocation allocation = nullptr; - VkImageView imageView = VK_NULL_HANDLE; - VkImageLayout layout = VK_IMAGE_LAYOUT_UNDEFINED; - VkExtent2D extent = {0, 0}; - VkFormat format = VK_FORMAT_UNDEFINED; - VkImage depthStencilImage = VK_NULL_HANDLE; - VmaAllocation depthStencilAllocation = nullptr; - VkImageView depthStencilImageView = VK_NULL_HANDLE; - VkImageLayout depthStencilLayout = VK_IMAGE_LAYOUT_UNDEFINED; - VkFormat depthStencilFormat = VK_FORMAT_UNDEFINED; - Uint16 glObjectVersion = 0; - Uint colorTextureExternalIndex = 0; - }; - - Bool RecreateOffscreenColorTarget(OffscreenColorTarget& target, - const MG_State::GLState::FramebufferObject& glFbo, - const MG_State::GLState::FramebufferAttachmentObject& colorAttachment, - Uint16 glObjectVersion); - void DestroyOffscreenColorTarget(OffscreenColorTarget& target); - static VkFormat ResolveColorFormat(const MG_State::GLState::FramebufferAttachmentObject& colorAttachment); - static VkFormat ResolveDepthStencilFormat( - const MG_State::GLState::FramebufferAttachmentObject& depthAttachment, - const MG_State::GLState::FramebufferAttachmentObject& stencilAttachment); - VkFormat FindSupportedDepthStencilFormat(const Vector& candidates) const; - - VkDevice m_device = VK_NULL_HANDLE; - VkPhysicalDevice m_physicalDevice = VK_NULL_HANDLE; - VmaAllocator m_allocator = nullptr; - UnorderedMap m_offscreenColorTargets; - }; -} // namespace MobileGL::MG_Backend::DirectVulkan diff --git a/MobileGL/MG_Backend/DirectVulkan/Renderer/VkTextureManager.cpp b/MobileGL/MG_Backend/DirectVulkan/Renderer/VkTextureManager.cpp index 056cab11..c008ebfb 100644 --- a/MobileGL/MG_Backend/DirectVulkan/Renderer/VkTextureManager.cpp +++ b/MobileGL/MG_Backend/DirectVulkan/Renderer/VkTextureManager.cpp @@ -62,7 +62,9 @@ namespace MobileGL::MG_Backend::DirectVulkan { outImageInfo.sampler = VK_NULL_HANDLE; outImageInfo.imageView = it->second.view; - outImageInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + // Will be VK_IMAGE_LAYOUT_UNDEFINED or VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL + // Shouldn't hardcode VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL here + // outImageInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; return true; } Bool VkTextureManager::TransitionImageLayout(VkCommandBuffer commandBuffer, VkImage image, @@ -298,6 +300,7 @@ namespace MobileGL::MG_Backend::DirectVulkan { VK_ACCESS_TRANSFER_READ_BIT, VK_IMAGE_ASPECT_COLOR_BIT); MOBILEGL_ASSERT(ok, "TransitionImageLayout to VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL failed"); + outResource.layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; return ok; }); diff --git a/MobileGL/MG_Backend/DirectVulkan/Renderer/VulkanRenderer.cpp b/MobileGL/MG_Backend/DirectVulkan/Renderer/VulkanRenderer.cpp index 71ccc86c..7ad6173b 100644 --- a/MobileGL/MG_Backend/DirectVulkan/Renderer/VulkanRenderer.cpp +++ b/MobileGL/MG_Backend/DirectVulkan/Renderer/VulkanRenderer.cpp @@ -205,8 +205,20 @@ namespace MobileGL::MG_Backend::DirectVulkan { CreateAllocator(); CreateCommandPool(); - m_renderPassManager = MakeUnique(); + m_textureManager = MakeUnique(); + MOBILEGL_ASSERT(m_textureManager != nullptr, "VkTextureManager creation failed."); + auto succeeded = false; + succeeded = m_textureManager->Initialize( + {m_device, m_physicalDevice.handle, m_allocator, m_commandPool, m_graphicsQueue}); + MOBILEGL_ASSERT(succeeded, "VkTextureManager initialization failed."); + m_clearManager = MakeUnique(); + MOBILEGL_ASSERT(m_clearManager != nullptr, "VkClearManager creation failed."); + succeeded = m_clearManager->Initialize(); + MOBILEGL_ASSERT(succeeded, "VkClearManager initialization failed."); + m_renderPassManager = MakeUnique(m_device, m_config, *m_clearManager, *m_textureManager); MOBILEGL_ASSERT(m_renderPassManager != nullptr, "VkRenderPassManager creation failed."); + succeeded = m_renderPassManager->Initialize(); + MOBILEGL_ASSERT(succeeded, "VkRenderPassManager initialization failed."); RecreateSwapchain(); @@ -214,30 +226,18 @@ namespace MobileGL::MG_Backend::DirectVulkan { MOBILEGL_ASSERT(m_pipelineFactory != nullptr, "PipelineFactory creation failed."); m_programFactory = MakeUnique(m_device, m_config); MOBILEGL_ASSERT(m_programFactory != nullptr, "ProgramFactory creation failed."); - m_textureManager = MakeUnique(); - MOBILEGL_ASSERT(m_textureManager != nullptr, "VkTextureManager creation failed."); - auto succeeded = false; - succeeded = m_textureManager->Initialize( - {m_device, m_physicalDevice.handle, m_allocator, m_commandPool, m_graphicsQueue}); - MOBILEGL_ASSERT(succeeded, "VkTextureManager initialization failed."); m_samplerManager = MakeUnique(); MOBILEGL_ASSERT(m_samplerManager != nullptr, "VkSamplerManager creation failed."); succeeded = m_samplerManager->Initialize({m_device, &m_config}); MOBILEGL_ASSERT(succeeded, "VkSamplerManager initialization failed."); - m_framebufferManager = MakeUnique(); - MOBILEGL_ASSERT(m_framebufferManager != nullptr, "VkFramebufferManager creation failed."); - succeeded = m_framebufferManager->Initialize({m_device, m_physicalDevice.handle, m_allocator}); - MOBILEGL_ASSERT(succeeded, "VkFramebufferManager initialization failed."); - m_uniformDescriptorBinder = MakeUnique(); MOBILEGL_ASSERT(m_uniformDescriptorBinder != nullptr, "UniformDescriptorBinder creation failed."); succeeded = m_uniformDescriptorBinder->Initialize(m_device, m_allocator, m_physicalDevice.properties.limits.minUniformBufferOffsetAlignment, m_config.MaxFramesInFlight, 16, 64, 4 * 1024 * 1024, - m_textureManager.get(), m_samplerManager.get(), - m_framebufferManager.get()); + m_textureManager.get(), m_samplerManager.get()); MOBILEGL_ASSERT(succeeded, "UniformDescriptorBinder initialization failed."); m_vertexInputStateFactory = MakeUnique(m_config); MOBILEGL_ASSERT(m_vertexInputStateFactory != nullptr, "VertexInputStateFactory creation failed."); @@ -292,11 +292,10 @@ namespace MobileGL::MG_Backend::DirectVulkan { ShutdownSwapchain(); m_renderPassManager.reset(); - if (m_framebufferManager) { - m_framebufferManager->Shutdown(); - m_framebufferManager.reset(); + if (m_clearManager) { + m_clearManager->Shutdown(); + m_clearManager.reset(); } - if (m_commandPool != VK_NULL_HANDLE) { vkDestroyCommandPool(m_device, m_commandPool, nullptr); m_commandPool = VK_NULL_HANDLE; @@ -353,6 +352,29 @@ namespace MobileGL::MG_Backend::DirectVulkan { pending.drawFboExternalIndex = drawFboExternalIndex; pending.targetsDefaultFramebuffer = isDefaultFramebufferTarget; pending.mask |= requestMask; + + if (m_clearManager == nullptr) { + return; + } + const auto* defaultFboInfo = MG_Impl::GLImpl::FramebufferImpl::pDefaultFramebufferInfo; + const auto* defaultFbo = defaultFboInfo ? defaultFboInfo->defaultFBO.get() : nullptr; + const MG_State::GLState::FramebufferObject* drawFbo = nullptr; + if (isDefaultFramebufferTarget) { + drawFbo = defaultFbo; + } else { + drawFbo = MG_State::pGLContext->GetFramebufferObject(drawFboExternalIndex).get(); + } + if (drawFbo == nullptr) { + return; + } + m_clearManager->QueueClear( + requestMask, + { + .color = color, + .depth = depth, + .stencil = stencil, + }, + *drawFbo); } Bool VulkanRenderer::ConsumePendingColorClear(VkClearColorValue& outClearColor) { @@ -370,6 +392,51 @@ namespace MobileGL::MG_Backend::DirectVulkan { return false; } + void VulkanRenderer::ApplyPendingClearsForActiveTarget(VkCommandBuffer commandBuffer, Uint64 drawTargetKey) { + if (m_activeRenderExtent.width == 0 || m_activeRenderExtent.height == 0) { + return; + } + auto pendingIt = m_pendingClears.find(drawTargetKey); + if (pendingIt == m_pendingClears.end()) { + return; + } + + VkClearRect clearRect{}; + clearRect.rect.offset = {0, 0}; + clearRect.rect.extent = m_activeRenderExtent; + clearRect.baseArrayLayer = 0; + clearRect.layerCount = 1; + + if ((pendingIt->second.mask & GL_COLOR_BUFFER_BIT) != 0) { + VkClearAttachment colorAttachment{}; + colorAttachment.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + colorAttachment.colorAttachment = 0; + colorAttachment.clearValue.color = pendingIt->second.color; + vkCmdClearAttachments(commandBuffer, 1, &colorAttachment, 1, &clearRect); + pendingIt->second.mask &= ~GL_COLOR_BUFFER_BIT; + } + + if ((pendingIt->second.mask & (GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT)) != 0) { + VkClearAttachment depthStencilAttachment{}; + depthStencilAttachment.aspectMask = 0; + if ((pendingIt->second.mask & GL_DEPTH_BUFFER_BIT) != 0) { + depthStencilAttachment.aspectMask |= VK_IMAGE_ASPECT_DEPTH_BIT; + } + if ((pendingIt->second.mask & GL_STENCIL_BUFFER_BIT) != 0) { + depthStencilAttachment.aspectMask |= VK_IMAGE_ASPECT_STENCIL_BIT; + } + depthStencilAttachment.colorAttachment = 0; + depthStencilAttachment.clearValue.depthStencil.depth = pendingIt->second.depth; + depthStencilAttachment.clearValue.depthStencil.stencil = pendingIt->second.stencil; + vkCmdClearAttachments(commandBuffer, 1, &depthStencilAttachment, 1, &clearRect); + pendingIt->second.mask &= ~(GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); + } + + if (pendingIt->second.mask == 0) { + m_pendingClears.erase(pendingIt); + } + } + void VulkanRenderer::TransitionSwapchainImageToColorAttachment(VkCommandBuffer commandBuffer, Uint32 imageIndex) { auto layout = m_swapchainObject.GetImageLayout(imageIndex); Bool ok = VkTextureManager::TransitionImageLayout(commandBuffer, m_swapchainObject.GetImage(imageIndex), @@ -469,119 +536,42 @@ namespace MobileGL::MG_Backend::DirectVulkan { m_swapchainObject.SetImageLayout(m_imageIndexAcquired, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR); } - VkRenderPass offscreenRenderPass = VK_NULL_HANDLE; - VkFramebuffer offscreenFramebuffer = VK_NULL_HANDLE; - VkExtent2D offscreenExtent{}; - VkFormat offscreenDepthStencilFormat = VK_FORMAT_UNDEFINED; - if (!EnsureOffscreenRenderTarget(drawFboExternalIndex, *drawFbo, offscreenRenderPass, offscreenFramebuffer, - offscreenExtent, offscreenDepthStencilFormat)) { - MGLOG_D("EnsureFrameRecordingStarted skipped: offscreen render target for FBO %u is unavailable", - drawFboExternalIndex); - return; - } - - 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); + MOBILEGL_ASSERT(m_renderPassManager != nullptr, "EnsureFrameRecordingStarted: manager is null"); + auto& renderPassEntry = m_renderPassManager->GetOrCreateRenderPass(*drawFbo); + Bool started = m_renderPassManager->StartRenderPass(commandBuffer, renderPassEntry); + MOBILEGL_ASSERT(started, "EnsureFrameRecordingStarted: StartRenderPass for offscreen target failed"); m_isMainRenderPassActive = true; - m_activeRenderPass = offscreenRenderPass; - m_activeRenderExtent = offscreenExtent; - m_activeDepthStencilFormat = offscreenDepthStencilFormat; + m_activeRenderPass = renderPassEntry.renderPass; + m_activeRenderExtent = { + static_cast(renderPassEntry.extent.x() > 0 ? renderPassEntry.extent.x() : 0), + static_cast(renderPassEntry.extent.y() > 0 ? renderPassEntry.extent.y() : 0)}; + m_activeDepthStencilFormat = VK_FORMAT_UNDEFINED; m_activeRenderTargetIsDefault = false; m_activeDrawFboExternalIndex = drawFboExternalIndex; - auto pendingIt = m_pendingClears.find(drawTargetKey); - if (pendingIt != m_pendingClears.end()) { - if ((pendingIt->second.mask & GL_COLOR_BUFFER_BIT) != 0) { - m_renderPassManager->RecordColorClear(commandBuffer, m_activeRenderExtent, pendingIt->second.color); - pendingIt->second.mask &= ~GL_COLOR_BUFFER_BIT; - } - if ((pendingIt->second.mask & (GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT)) != 0) { - m_renderPassManager->RecordDepthStencilClear(commandBuffer, m_activeRenderExtent, - pendingIt->second.mask, pendingIt->second.depth, - pendingIt->second.stencil, m_activeDepthStencilFormat); - pendingIt->second.mask &= ~(GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); - } - if (pendingIt->second.mask == 0) { - m_pendingClears.erase(pendingIt); - } - } + ApplyPendingClearsForActiveTarget(commandBuffer, drawTargetKey); return; } TransitionSwapchainImageToColorAttachment(commandBuffer, m_imageIndexAcquired); TransitionDepthStencilImageToAttachment(commandBuffer, m_imageIndexAcquired); - VkRenderPass defaultRenderPass = VK_NULL_HANDLE; - VkFramebuffer defaultFramebuffer = VK_NULL_HANDLE; - VkExtent2D defaultExtent{}; - VkFormat defaultDepthStencilFormat = VK_FORMAT_UNDEFINED; - if (!GetDefaultRenderTargetForCurrentImage(defaultRenderPass, defaultFramebuffer, defaultExtent, - defaultDepthStencilFormat)) { + if (!defaultFbo) { MGLOG_D("EnsureFrameRecordingStarted skipped: default render target unavailable"); return; } MOBILEGL_ASSERT(m_renderPassManager != nullptr, "EnsureFrameRecordingStarted: manager is null"); - m_renderPassManager->BeginRenderPass(commandBuffer, defaultRenderPass, defaultFramebuffer, defaultExtent); + auto& renderPassEntry = m_renderPassManager->GetOrCreateRenderPass(*defaultFbo); + Bool started = m_renderPassManager->StartRenderPass(commandBuffer, renderPassEntry); + MOBILEGL_ASSERT(started, "EnsureFrameRecordingStarted: StartRenderPass for default target failed"); m_isMainRenderPassActive = true; - m_activeRenderPass = defaultRenderPass; - m_activeRenderExtent = defaultExtent; - m_activeDepthStencilFormat = defaultDepthStencilFormat; + m_activeRenderPass = renderPassEntry.renderPass; + m_activeRenderExtent = { + static_cast(renderPassEntry.extent.x() > 0 ? renderPassEntry.extent.x() : 0), + static_cast(renderPassEntry.extent.y() > 0 ? renderPassEntry.extent.y() : 0)}; + m_activeDepthStencilFormat = m_swapchainObject.GetDepthStencilFormat(); m_activeRenderTargetIsDefault = true; m_activeDrawFboExternalIndex = drawFboExternalIndex; - auto pendingIt = m_pendingClears.find(drawTargetKey); - if (pendingIt != m_pendingClears.end()) { - if ((pendingIt->second.mask & GL_COLOR_BUFFER_BIT) != 0) { - m_renderPassManager->RecordColorClear(commandBuffer, m_activeRenderExtent, pendingIt->second.color); - pendingIt->second.mask &= ~GL_COLOR_BUFFER_BIT; - } - if ((pendingIt->second.mask & (GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT)) != 0) { - m_renderPassManager->RecordDepthStencilClear(commandBuffer, m_activeRenderExtent, - pendingIt->second.mask, pendingIt->second.depth, - pendingIt->second.stencil, m_activeDepthStencilFormat); - pendingIt->second.mask &= ~(GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); - } - if (pendingIt->second.mask == 0) { - m_pendingClears.erase(pendingIt); - } - } + ApplyPendingClearsForActiveTarget(commandBuffer, drawTargetKey); } void VulkanRenderer::EndFrameRecordingIfNeeded() { @@ -1227,71 +1217,31 @@ namespace MobileGL::MG_Backend::DirectVulkan { TransitionSwapchainImageToColorAttachment(commandBuffer, m_imageIndexAcquired); TransitionDepthStencilImageToAttachment(commandBuffer, m_imageIndexAcquired); - VkRenderPass renderPass = VK_NULL_HANDLE; - VkFramebuffer framebuffer = VK_NULL_HANDLE; - VkExtent2D extent{}; - VkFormat depthStencilFormat = VK_FORMAT_UNDEFINED; - if (!GetDefaultRenderTargetForCurrentImage(renderPass, framebuffer, extent, depthStencilFormat)) { + const auto* defaultFboInfo = MG_Impl::GLImpl::FramebufferImpl::pDefaultFramebufferInfo; + const auto* defaultFbo = defaultFboInfo ? defaultFboInfo->defaultFBO.get() : nullptr; + if (defaultFbo == nullptr) { + return false; + } + auto& renderPassEntry = m_renderPassManager->GetOrCreateRenderPass(*defaultFbo); + const Bool started = m_renderPassManager->StartRenderPass(commandBuffer, renderPassEntry); + if (!started) { return false; } - m_renderPassManager->BeginRenderPass(commandBuffer, renderPass, framebuffer, extent); m_isMainRenderPassActive = true; - m_activeRenderPass = renderPass; - m_activeRenderExtent = extent; - m_activeDepthStencilFormat = depthStencilFormat; + m_activeRenderPass = renderPassEntry.renderPass; + m_activeRenderExtent = { + static_cast(renderPassEntry.extent.x() > 0 ? renderPassEntry.extent.x() : 0), + static_cast(renderPassEntry.extent.y() > 0 ? renderPassEntry.extent.y() : 0)}; + m_activeDepthStencilFormat = m_swapchainObject.GetDepthStencilFormat(); m_activeRenderTargetIsDefault = true; m_activeDrawFboExternalIndex = 0; return true; } - MOBILEGL_ASSERT(m_framebufferManager != nullptr, "Present: framebuffer manager is null"); - const auto pendingFbo = MG_State::pGLContext->GetFramebufferObject(targetFboExternalIndex); if (!pendingFbo) { return false; } - VkRenderPass offscreenRenderPass = VK_NULL_HANDLE; - VkFramebuffer offscreenFramebuffer = VK_NULL_HANDLE; - VkExtent2D offscreenExtent{}; - VkFormat offscreenDepthStencilFormat = VK_FORMAT_UNDEFINED; - if (!EnsureOffscreenRenderTarget(targetFboExternalIndex, *pendingFbo, offscreenRenderPass, - offscreenFramebuffer, offscreenExtent, offscreenDepthStencilFormat)) { - return false; - } - 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 && @@ -1316,12 +1266,17 @@ namespace MobileGL::MG_Backend::DirectVulkan { m_swapchainObject.SetImageLayout(m_imageIndexAcquired, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR); } - m_renderPassManager->BeginRenderPass(commandBuffer, offscreenRenderPass, offscreenFramebuffer, - offscreenExtent); + auto& renderPassEntry = m_renderPassManager->GetOrCreateRenderPass(*pendingFbo); + const Bool started = m_renderPassManager->StartRenderPass(commandBuffer, renderPassEntry); + if (!started) { + return false; + } m_isMainRenderPassActive = true; - m_activeRenderPass = offscreenRenderPass; - m_activeRenderExtent = offscreenExtent; - m_activeDepthStencilFormat = offscreenDepthStencilFormat; + m_activeRenderPass = renderPassEntry.renderPass; + m_activeRenderExtent = { + static_cast(renderPassEntry.extent.x() > 0 ? renderPassEntry.extent.x() : 0), + static_cast(renderPassEntry.extent.y() > 0 ? renderPassEntry.extent.y() : 0)}; + m_activeDepthStencilFormat = VK_FORMAT_UNDEFINED; m_activeRenderTargetIsDefault = false; m_activeDrawFboExternalIndex = targetFboExternalIndex; return true; @@ -1353,20 +1308,7 @@ namespace MobileGL::MG_Backend::DirectVulkan { continue; } - if ((activePendingIt->second.mask & GL_COLOR_BUFFER_BIT) != 0) { - m_renderPassManager->RecordColorClear(frame.commandBuffer, m_activeRenderExtent, - activePendingIt->second.color); - activePendingIt->second.mask &= ~GL_COLOR_BUFFER_BIT; - } - if ((activePendingIt->second.mask & (GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT)) != 0) { - m_renderPassManager->RecordDepthStencilClear( - frame.commandBuffer, m_activeRenderExtent, activePendingIt->second.mask, - activePendingIt->second.depth, activePendingIt->second.stencil, m_activeDepthStencilFormat); - activePendingIt->second.mask &= ~(GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); - } - if (activePendingIt->second.mask == 0) { - m_pendingClears.erase(activePendingIt); - } + ApplyPendingClearsForActiveTarget(frame.commandBuffer, activeKey); } } EndFrameRecordingIfNeeded(); @@ -1777,51 +1719,6 @@ namespace MobileGL::MG_Backend::DirectVulkan { MGLOG_I("Command pool created"); } - Bool VulkanRenderer::GetDefaultRenderTargetForCurrentImage(VkRenderPass& outRenderPass, - VkFramebuffer& outFramebuffer, VkExtent2D& outExtent, - VkFormat& outDepthStencilFormat) const { - MOBILEGL_ASSERT(m_renderPassManager != nullptr, "GetDefaultRenderTargetForCurrentImage: manager is null"); - return m_renderPassManager->GetDefaultRenderTarget(m_imageIndexAcquired, outRenderPass, outFramebuffer, - outExtent, outDepthStencilFormat); - } - - Bool VulkanRenderer::EnsureOffscreenRenderTarget(Uint glFboExternalIndex, - const MG_State::GLState::FramebufferObject& glFbo, - VkRenderPass& outRenderPass, VkFramebuffer& outFramebuffer, - VkExtent2D& outExtent, VkFormat& outDepthStencilFormat) { - MOBILEGL_ASSERT(m_framebufferManager != nullptr, "EnsureOffscreenRenderTarget: framebuffer manager is null"); - MOBILEGL_ASSERT(m_renderPassManager != nullptr, "EnsureOffscreenRenderTarget: render pass manager is null"); - - if (!m_framebufferManager->EnsureOffscreenColorTarget(glFboExternalIndex, glFbo)) { - return false; - } - - VkImageView colorView = VK_NULL_HANDLE; - VkFormat colorFormat = VK_FORMAT_UNDEFINED; - VkImageView depthStencilView = VK_NULL_HANDLE; - VkFormat depthStencilFormat = VK_FORMAT_UNDEFINED; - VkExtent2D extent{}; - if (!m_framebufferManager->GetOffscreenRenderSurface(glFboExternalIndex, colorView, colorFormat, - depthStencilView, depthStencilFormat, extent)) { - return false; - } - - VkRenderPassManager::OffscreenRenderTargetInfo targetInfo{}; - targetInfo.targetExternalIndex = glFboExternalIndex; - targetInfo.targetVersion = glFbo.GetObjectVersion(); - targetInfo.colorView = colorView; - targetInfo.colorFormat = colorFormat; - targetInfo.depthStencilView = depthStencilView; - targetInfo.depthStencilFormat = depthStencilFormat; - targetInfo.extent = extent; - if (!m_renderPassManager->EnsureOffscreenRenderTarget(targetInfo)) { - return false; - } - - return m_renderPassManager->GetOffscreenRenderTarget(glFboExternalIndex, outRenderPass, outFramebuffer, - outExtent, outDepthStencilFormat); - } - void VulkanRenderer::CreateSurface() { #if defined VK_USE_PLATFORM_ANDROID_KHR auto* nativeWindow = static_cast(m_window); @@ -1990,16 +1887,8 @@ namespace MobileGL::MG_Backend::DirectVulkan { static_cast(m_swapchainObject.GetImageCount())), "RecreateSwapchain, InitializeSwapchainSemaphores"); MOBILEGL_ASSERT(m_renderPassManager != nullptr, "RecreateSwapchain: render pass manager is null"); - VkRenderPassManager::InitInfo renderPassInitInfo{}; - renderPassInitInfo.device = m_device; - renderPassInitInfo.colorFormat = m_swapchainObject.GetSurfaceFormat().format; - renderPassInitInfo.depthStencilFormat = m_swapchainObject.GetDepthStencilFormat(); - Bool ok = m_renderPassManager->Initialize(renderPassInitInfo); + Bool ok = m_renderPassManager->Initialize(); MOBILEGL_ASSERT(ok, "RecreateSwapchain: render pass manager initialization failed"); - ok = m_renderPassManager->RecreateDefaultFramebuffers(m_swapchainObject.GetImageViews(), - m_swapchainObject.GetDepthStencilImageViews(), - m_swapchainObject.GetExtent()); - MOBILEGL_ASSERT(ok, "RecreateSwapchain: default framebuffers initialization failed"); if (m_pipelineFactory) { m_pipelineFactory->DestroyAll(); } diff --git a/MobileGL/MG_Backend/DirectVulkan/Renderer/VulkanRenderer.h b/MobileGL/MG_Backend/DirectVulkan/Renderer/VulkanRenderer.h index e82ecaf4..ee0da8bd 100644 --- a/MobileGL/MG_Backend/DirectVulkan/Renderer/VulkanRenderer.h +++ b/MobileGL/MG_Backend/DirectVulkan/Renderer/VulkanRenderer.h @@ -15,7 +15,7 @@ #include "UniformDescriptorBinder.h" #include "VertexInputStateFactory.h" #include "VkBufferObject.h" -#include "VkRenderTargetManager.h" +#include "VkClearManager.h" #include "VkRenderPassManager.h" #include "VkSamplerManager.h" #include "VkTextureManager.h" @@ -143,7 +143,7 @@ namespace MobileGL::MG_Backend::DirectVulkan { UniquePtr m_programFactory; UniquePtr m_uniformDescriptorBinder; UniquePtr m_vertexInputStateFactory; - UniquePtr m_framebufferManager; + UniquePtr m_clearManager; UniquePtr m_renderPassManager; UniquePtr m_textureManager; UniquePtr m_samplerManager; @@ -160,11 +160,6 @@ namespace MobileGL::MG_Backend::DirectVulkan { void CreateSwapchain(); void CreateCommandPool(); void CreateFrameContexts(); - Bool GetDefaultRenderTargetForCurrentImage(VkRenderPass& outRenderPass, VkFramebuffer& outFramebuffer, - VkExtent2D& outExtent, VkFormat& outDepthStencilFormat) const; - Bool EnsureOffscreenRenderTarget(Uint glFboExternalIndex, const MG_State::GLState::FramebufferObject& glFbo, - VkRenderPass& outRenderPass, VkFramebuffer& outFramebuffer, - VkExtent2D& outExtent, VkFormat& outDepthStencilFormat); VkPipeline GetOrCreatePipeline(const MG_State::GLState::ProgramObject& program, VkPipelineLayout pipelineLayout, Uint64 vertexInputHash, const VkPipelineVertexInputStateCreateInfo& vertexInputState); @@ -177,6 +172,7 @@ namespace MobileGL::MG_Backend::DirectVulkan { VkDeviceSize minCapacity, VkBufferUsageFlags usage); Bool UploadAndBindVertexStreams(const VertexInputStateFactory::BackendVertexInputState& vertexInputState, const DrawArrayPayload& payload, VkCommandBuffer commandBuffer); + void ApplyPendingClearsForActiveTarget(VkCommandBuffer commandBuffer, Uint64 drawTargetKey); void ShutdownSwapchain(); diff --git a/MobileGL/MG_Util/Converters/MGToVk/TextureEnumConverter.cpp b/MobileGL/MG_Util/Converters/MGToVk/TextureEnumConverter.cpp new file mode 100644 index 00000000..05a7154f --- /dev/null +++ b/MobileGL/MG_Util/Converters/MGToVk/TextureEnumConverter.cpp @@ -0,0 +1,436 @@ +// MobileGL - MobileGL/MG_Util/Converters/MGToVk/TextureEnumConverter.cpp +// Copyright (c) 2025-2026 MobileGL-Dev +// Licensed under the GNU Lesser General Public License v3.0: +// https://www.gnu.org/licenses/gpl-3.0.txt +// https://www.gnu.org/licenses/lgpl-3.0.txt +// SPDX-License-Identifier: LGPL-3.0-only +// End of Source File Header + +#include "TextureEnumConverter.h" +#include "MG_Util/Types.h" + +namespace MobileGL { + namespace MG_Util { + VkImageViewType ConvertTextureTargetToVkEnum(TextureTarget target) { + switch (target) { + case TextureTarget::Texture1D: + return VK_IMAGE_VIEW_TYPE_1D; + case TextureTarget::Texture2D: + return VK_IMAGE_VIEW_TYPE_2D; + case TextureTarget::Texture3D: + return VK_IMAGE_VIEW_TYPE_3D; + case TextureTarget::TextureCubeMap: + return VK_IMAGE_VIEW_TYPE_CUBE; + case TextureTarget::Texture2DArray: + return VK_IMAGE_VIEW_TYPE_2D_ARRAY; + case TextureTarget::Texture2DMultisample: + return VK_IMAGE_VIEW_TYPE_2D; + case TextureTarget::TextureCubeMapArray: + return VK_IMAGE_VIEW_TYPE_CUBE_ARRAY; + case TextureTarget::Texture1DArray: + return VK_IMAGE_VIEW_TYPE_1D_ARRAY; + case TextureTarget::TextureRectangle: + return VK_IMAGE_VIEW_TYPE_2D; + case TextureTarget::Texture2DMultisampleArray: + return VK_IMAGE_VIEW_TYPE_2D_ARRAY; + case TextureTarget::TextureBuffer: + default: + return VK_IMAGE_VIEW_TYPE_MAX_ENUM; + } + } + + VkFormat ConvertTextureInputFormatToVkEnum(TextureInputFormat format) { + switch (format) { + case TextureInputFormat::Red: + return VK_FORMAT_R8_UNORM; + case TextureInputFormat::RG: + return VK_FORMAT_R8G8_UNORM; + case TextureInputFormat::RGB: + return VK_FORMAT_R8G8B8_UNORM; + case TextureInputFormat::BGR: + return VK_FORMAT_B8G8R8_UNORM; + case TextureInputFormat::RGBA: + return VK_FORMAT_R8G8B8A8_UNORM; + case TextureInputFormat::BGRA: + return VK_FORMAT_B8G8R8A8_UNORM; + case TextureInputFormat::RInteger: + return VK_FORMAT_R8_UINT; + case TextureInputFormat::RGInteger: + return VK_FORMAT_R8G8_UINT; + case TextureInputFormat::RGBInteger: + return VK_FORMAT_R8G8B8_UINT; + case TextureInputFormat::BGRInteger: + return VK_FORMAT_B8G8R8_UINT; + case TextureInputFormat::RGBAInteger: + return VK_FORMAT_R8G8B8A8_UINT; + case TextureInputFormat::BGRAInteger: + return VK_FORMAT_B8G8R8A8_UINT; + case TextureInputFormat::StencilIndex: + return VK_FORMAT_S8_UINT; + case TextureInputFormat::DepthComponent: + return VK_FORMAT_D32_SFLOAT; + case TextureInputFormat::DepthStencil: + return VK_FORMAT_D24_UNORM_S8_UINT; + default: + return VK_FORMAT_UNDEFINED; + } + } + + VkFormat ConvertTextureInternalFormatToVkEnum(TextureInternalFormat format) { + switch (format) { + case TextureInternalFormat::R8: + return VK_FORMAT_R8_UNORM; + case TextureInternalFormat::R8Snorm: + return VK_FORMAT_R8_SNORM; + case TextureInternalFormat::R16: + return VK_FORMAT_R16_UNORM; + case TextureInternalFormat::R16Snorm: + return VK_FORMAT_R16_SNORM; + case TextureInternalFormat::RG8: + return VK_FORMAT_R8G8_UNORM; + case TextureInternalFormat::RG8Snorm: + return VK_FORMAT_R8G8_SNORM; + case TextureInternalFormat::RG16: + return VK_FORMAT_R16G16_UNORM; + case TextureInternalFormat::RG16Snorm: + return VK_FORMAT_R16G16_SNORM; + case TextureInternalFormat::R3G3B2: + return VK_FORMAT_UNDEFINED; + case TextureInternalFormat::RGB4: + return VK_FORMAT_UNDEFINED; + case TextureInternalFormat::RGB5: + return VK_FORMAT_UNDEFINED; + case TextureInternalFormat::RGB8: + return VK_FORMAT_R8G8B8_UNORM; + case TextureInternalFormat::RGB8Snorm: + return VK_FORMAT_R8G8B8_SNORM; + case TextureInternalFormat::RGB10: + return VK_FORMAT_UNDEFINED; + case TextureInternalFormat::RGB12: + return VK_FORMAT_UNDEFINED; + case TextureInternalFormat::RGB16: + return VK_FORMAT_UNDEFINED; + case TextureInternalFormat::RGB16Snorm: + return VK_FORMAT_UNDEFINED; + case TextureInternalFormat::RGBA2: + return VK_FORMAT_UNDEFINED; + case TextureInternalFormat::RGBA4: + return VK_FORMAT_R4G4B4A4_UNORM_PACK16; + case TextureInternalFormat::RGB5A1: + return VK_FORMAT_R5G5B5A1_UNORM_PACK16; + case TextureInternalFormat::RGBA8: + return VK_FORMAT_R8G8B8A8_UNORM; + case TextureInternalFormat::RGBA8Snorm: + return VK_FORMAT_R8G8B8A8_SNORM; + case TextureInternalFormat::RGB10A2: + return VK_FORMAT_A2R10G10B10_UNORM_PACK32; + case TextureInternalFormat::RGB10A2UI: + return VK_FORMAT_A2R10G10B10_UINT_PACK32; + case TextureInternalFormat::RGBA12: + return VK_FORMAT_UNDEFINED; + case TextureInternalFormat::RGBA16: + return VK_FORMAT_R16G16B16A16_UNORM; + case TextureInternalFormat::SRGB8: + return VK_FORMAT_R8G8B8_SRGB; + case TextureInternalFormat::SRGB8Alpha8: + return VK_FORMAT_R8G8B8A8_SRGB; + case TextureInternalFormat::R16F: + return VK_FORMAT_R16_SFLOAT; + case TextureInternalFormat::RG16F: + return VK_FORMAT_R16G16_SFLOAT; + case TextureInternalFormat::RGB16F: + return VK_FORMAT_R16G16B16_SFLOAT; + case TextureInternalFormat::RGBA16F: + return VK_FORMAT_R16G16B16A16_SFLOAT; + case TextureInternalFormat::R32F: + return VK_FORMAT_R32_SFLOAT; + case TextureInternalFormat::RG32F: + return VK_FORMAT_R32G32_SFLOAT; + case TextureInternalFormat::RGB32F: + return VK_FORMAT_R32G32B32_SFLOAT; + case TextureInternalFormat::RGBA32F: + return VK_FORMAT_R32G32B32A32_SFLOAT; + case TextureInternalFormat::R11FG11FB10F: + return VK_FORMAT_B10G11R11_UFLOAT_PACK32; + case TextureInternalFormat::RGB9E5: + return VK_FORMAT_E5B9G9R9_UFLOAT_PACK32; + case TextureInternalFormat::R8I: + return VK_FORMAT_R8_SINT; + case TextureInternalFormat::R8UI: + return VK_FORMAT_R8_UINT; + case TextureInternalFormat::R16I: + return VK_FORMAT_R16_SINT; + case TextureInternalFormat::R16UI: + return VK_FORMAT_R16_UINT; + case TextureInternalFormat::R32I: + return VK_FORMAT_R32_SINT; + case TextureInternalFormat::R32UI: + return VK_FORMAT_R32_UINT; + case TextureInternalFormat::RG8I: + return VK_FORMAT_R8G8_SINT; + case TextureInternalFormat::RG8UI: + return VK_FORMAT_R8G8_UINT; + case TextureInternalFormat::RG16I: + return VK_FORMAT_R16G16_SINT; + case TextureInternalFormat::RG16UI: + return VK_FORMAT_R16G16_UINT; + case TextureInternalFormat::RG32I: + return VK_FORMAT_R32G32_SINT; + case TextureInternalFormat::RG32UI: + return VK_FORMAT_R32G32_UINT; + case TextureInternalFormat::RGB8I: + return VK_FORMAT_R8G8B8_SINT; + case TextureInternalFormat::RGB8UI: + return VK_FORMAT_R8G8B8_UINT; + case TextureInternalFormat::RGB16I: + return VK_FORMAT_R16G16B16_SINT; + case TextureInternalFormat::RGB16UI: + return VK_FORMAT_R16G16B16_UINT; + case TextureInternalFormat::RGB32I: + return VK_FORMAT_R32G32B32_SINT; + case TextureInternalFormat::RGB32UI: + return VK_FORMAT_R32G32B32_UINT; + case TextureInternalFormat::RGBA8I: + return VK_FORMAT_R8G8B8A8_SINT; + case TextureInternalFormat::RGBA8UI: + return VK_FORMAT_R8G8B8A8_UINT; + case TextureInternalFormat::RGBA16I: + return VK_FORMAT_R16G16B16A16_SINT; + case TextureInternalFormat::RGBA16UI: + return VK_FORMAT_R16G16B16A16_UINT; + case TextureInternalFormat::RGBA32I: + return VK_FORMAT_R32G32B32A32_SINT; + case TextureInternalFormat::RGBA32UI: + return VK_FORMAT_R32G32B32A32_UINT; + case TextureInternalFormat::DepthComponent: + return VK_FORMAT_D32_SFLOAT; + case TextureInternalFormat::DepthComponent16: + return VK_FORMAT_D16_UNORM; + case TextureInternalFormat::DepthComponent24: + return VK_FORMAT_X8_D24_UNORM_PACK32; + case TextureInternalFormat::DepthComponent32F: + return VK_FORMAT_D32_SFLOAT; + case TextureInternalFormat::Depth24Stencil8: + return VK_FORMAT_D24_UNORM_S8_UINT; + case TextureInternalFormat::Depth32FStencil8: + return VK_FORMAT_D32_SFLOAT_S8_UINT; + case TextureInternalFormat::DepthComponent32: + return VK_FORMAT_D32_SFLOAT; + case TextureInternalFormat::DepthStencil: + return VK_FORMAT_D24_UNORM_S8_UINT; + case TextureInternalFormat::Red: + return VK_FORMAT_R8_UNORM; + case TextureInternalFormat::RG: + return VK_FORMAT_R8G8_UNORM; + case TextureInternalFormat::RGB: + return VK_FORMAT_R8G8B8_UNORM; + case TextureInternalFormat::RGBA: + return VK_FORMAT_R8G8B8A8_UNORM; + default: + return VK_FORMAT_UNDEFINED; + } + } + + VkFormat ConvertTexturePixelDataTypeToVkEnum(TexturePixelDataType type) { + switch (type) { + case TexturePixelDataType::UnsignedByte: + return VK_FORMAT_R8_UINT; + case TexturePixelDataType::Byte: + return VK_FORMAT_R8_SINT; + case TexturePixelDataType::UnsignedShort: + return VK_FORMAT_R16_UINT; + case TexturePixelDataType::Short: + return VK_FORMAT_R16_SINT; + case TexturePixelDataType::UnsignedInt: + return VK_FORMAT_R32_UINT; + case TexturePixelDataType::Int: + return VK_FORMAT_R32_SINT; + case TexturePixelDataType::Float: + return VK_FORMAT_R32_SFLOAT; + case TexturePixelDataType::HalfFloat: + return VK_FORMAT_R16_SFLOAT; + case TexturePixelDataType::UnsignedInt248: + return VK_FORMAT_D24_UNORM_S8_UINT; + case TexturePixelDataType::UnsignedByte332: + return VK_FORMAT_R8_UINT; + case TexturePixelDataType::UnsignedByte233Rev: + return VK_FORMAT_R8_UINT; + case TexturePixelDataType::UnsignedShort565: + return VK_FORMAT_R5G6B5_UNORM_PACK16; + case TexturePixelDataType::UnsignedShort565Rev: + return VK_FORMAT_R5G6B5_UNORM_PACK16; + case TexturePixelDataType::UnsignedShort4444: + return VK_FORMAT_R4G4B4A4_UNORM_PACK16; + case TexturePixelDataType::UnsignedShort4444Rev: + return VK_FORMAT_R4G4B4A4_UNORM_PACK16; + case TexturePixelDataType::UnsignedShort5551: + return VK_FORMAT_R5G5B5A1_UNORM_PACK16; + case TexturePixelDataType::UnsignedShort1555Rev: + return VK_FORMAT_R5G5B5A1_UNORM_PACK16; + case TexturePixelDataType::UnsignedInt8888: + return VK_FORMAT_R8G8B8A8_UINT; + case TexturePixelDataType::UnsignedInt8888Rev: + return VK_FORMAT_R8G8B8A8_UINT; + case TexturePixelDataType::UnsignedInt1010102: + return VK_FORMAT_A2R10G10B10_UINT_PACK32; + case TexturePixelDataType::UnsignedInt2101010Rev: + return VK_FORMAT_A2R10G10B10_UINT_PACK32; + case TexturePixelDataType::UnsignedInt101111Rev: + return VK_FORMAT_B10G11R11_UFLOAT_PACK32; + case TexturePixelDataType::UnsignedInt5999Rev: + return VK_FORMAT_E5B9G9R9_UFLOAT_PACK32; + case TexturePixelDataType::Float32UnsignedInt248Rev: + return VK_FORMAT_D32_SFLOAT_S8_UINT; + default: + return VK_FORMAT_UNDEFINED; + } + } + + VkImageViewType ConvertTextureUploadTargetToVkEnum(TextureUploadTarget target) { + switch (target) { + case TextureUploadTarget::Texture2D: + return VK_IMAGE_VIEW_TYPE_2D; + case TextureUploadTarget::Texture1D: + return VK_IMAGE_VIEW_TYPE_1D; + case TextureUploadTarget::Texture3D: + return VK_IMAGE_VIEW_TYPE_3D; + case TextureUploadTarget::ProxyTexture2D: + return VK_IMAGE_VIEW_TYPE_2D; + case TextureUploadTarget::Texture1DArray: + return VK_IMAGE_VIEW_TYPE_1D_ARRAY; + case TextureUploadTarget::ProxyTexture1DArray: + return VK_IMAGE_VIEW_TYPE_1D_ARRAY; + case TextureUploadTarget::TextureRectangle: + return VK_IMAGE_VIEW_TYPE_2D; + case TextureUploadTarget::ProxyTextureRectangle: + return VK_IMAGE_VIEW_TYPE_2D; + case TextureUploadTarget::CubeMapPositiveX: + return VK_IMAGE_VIEW_TYPE_CUBE; + case TextureUploadTarget::CubeMapNegativeX: + return VK_IMAGE_VIEW_TYPE_CUBE; + case TextureUploadTarget::CubeMapPositiveY: + return VK_IMAGE_VIEW_TYPE_CUBE; + case TextureUploadTarget::CubeMapNegativeY: + return VK_IMAGE_VIEW_TYPE_CUBE; + case TextureUploadTarget::CubeMapPositiveZ: + return VK_IMAGE_VIEW_TYPE_CUBE; + case TextureUploadTarget::CubeMapNegativeZ: + return VK_IMAGE_VIEW_TYPE_CUBE; + case TextureUploadTarget::ProxyCubeMap: + return VK_IMAGE_VIEW_TYPE_CUBE; + case TextureUploadTarget::Texture2DMultisample: + return VK_IMAGE_VIEW_TYPE_2D; + case TextureUploadTarget::ProxyTexture2DMultisample: + return VK_IMAGE_VIEW_TYPE_2D; + case TextureUploadTarget::CubeMapArray: + return VK_IMAGE_VIEW_TYPE_CUBE_ARRAY; + case TextureUploadTarget::ProxyCubeMapArray: + return VK_IMAGE_VIEW_TYPE_CUBE_ARRAY; + case TextureUploadTarget::Texture2DArray: + return VK_IMAGE_VIEW_TYPE_2D_ARRAY; + case TextureUploadTarget::ProxyTexture2DArray: + return VK_IMAGE_VIEW_TYPE_2D_ARRAY; + case TextureUploadTarget::Texture2DMultisampleArray: + return VK_IMAGE_VIEW_TYPE_2D_ARRAY; + case TextureUploadTarget::ProxyTexture2DMultisampleArray: + return VK_IMAGE_VIEW_TYPE_2D_ARRAY; + default: + return VK_IMAGE_VIEW_TYPE_MAX_ENUM; + } + } + + VkFilter ConvertSamplerFilterModeToVkEnum(SamplerFilterMode filter, SamplerMipmapMode mipmap) { + (void)mipmap; + switch (filter) { + case SamplerFilterMode::Nearest: + return VK_FILTER_NEAREST; + case SamplerFilterMode::Linear: + return VK_FILTER_LINEAR; + default: + return VK_FILTER_NEAREST; + } + } + + VkSamplerMipmapMode ConvertSamplerMipmapModeToVkEnum(SamplerMipmapMode v) { + switch (v) { + case SamplerMipmapMode::Nearest: + return VK_SAMPLER_MIPMAP_MODE_NEAREST; + case SamplerMipmapMode::Linear: + return VK_SAMPLER_MIPMAP_MODE_LINEAR; + case SamplerMipmapMode::None: + default: + return VK_SAMPLER_MIPMAP_MODE_NEAREST; + } + } + + VkSamplerAddressMode ConvertSamplerWrapModeToVkEnum(SamplerWrapMode v) { + switch (v) { + case SamplerWrapMode::ClampToEdge: + return VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; + case SamplerWrapMode::MirroredRepeat: + return VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT; + case SamplerWrapMode::Repeat: + return VK_SAMPLER_ADDRESS_MODE_REPEAT; + case SamplerWrapMode::ClampToBorder: + return VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER; + case SamplerWrapMode::MirrorClampToEdge: + return VK_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE; + default: + return VK_SAMPLER_ADDRESS_MODE_REPEAT; + } + } + + VkBool32 ConvertSamplerCompareModeToVkEnum(SamplerCompareMode v) { + switch (v) { + case SamplerCompareMode::None: + return VK_FALSE; + case SamplerCompareMode::CompareToTexture: + return VK_TRUE; + default: + return VK_FALSE; + } + } + + VkCompareOp ConvertSamplerCompareFuncToVkEnum(SamplerCompareFunc v) { + switch (v) { + case SamplerCompareFunc::Never: + return VK_COMPARE_OP_NEVER; + case SamplerCompareFunc::Less: + return VK_COMPARE_OP_LESS; + case SamplerCompareFunc::Equal: + return VK_COMPARE_OP_EQUAL; + case SamplerCompareFunc::LessEqual: + return VK_COMPARE_OP_LESS_OR_EQUAL; + case SamplerCompareFunc::Greater: + return VK_COMPARE_OP_GREATER; + case SamplerCompareFunc::NotEqual: + return VK_COMPARE_OP_NOT_EQUAL; + case SamplerCompareFunc::GreaterEqual: + return VK_COMPARE_OP_GREATER_OR_EQUAL; + case SamplerCompareFunc::Always: + return VK_COMPARE_OP_ALWAYS; + default: + return VK_COMPARE_OP_ALWAYS; + } + } + + VkComponentSwizzle ConvertTextureSwizzleParamToVkEnum(TextureSwizzleParam v) { + switch (v) { + case TextureSwizzleParam::Red: + return VK_COMPONENT_SWIZZLE_R; + case TextureSwizzleParam::Green: + return VK_COMPONENT_SWIZZLE_G; + case TextureSwizzleParam::Blue: + return VK_COMPONENT_SWIZZLE_B; + case TextureSwizzleParam::Alpha: + return VK_COMPONENT_SWIZZLE_A; + case TextureSwizzleParam::Zero: + return VK_COMPONENT_SWIZZLE_ZERO; + case TextureSwizzleParam::One: + return VK_COMPONENT_SWIZZLE_ONE; + default: + return VK_COMPONENT_SWIZZLE_IDENTITY; + } + } + } // namespace MG_Util +} // namespace MobileGL diff --git a/MobileGL/MG_Util/Converters/MGToVk/TextureEnumConverter.h b/MobileGL/MG_Util/Converters/MGToVk/TextureEnumConverter.h new file mode 100644 index 00000000..1890c9a9 --- /dev/null +++ b/MobileGL/MG_Util/Converters/MGToVk/TextureEnumConverter.h @@ -0,0 +1,27 @@ +// MobileGL - MobileGL/MG_Util/Converters/MGToVk/TextureEnumConverter.h +// Copyright (c) 2025-2026 MobileGL-Dev +// Licensed under the GNU Lesser General Public License v3.0: +// https://www.gnu.org/licenses/gpl-3.0.txt +// https://www.gnu.org/licenses/lgpl-3.0.txt +// SPDX-License-Identifier: LGPL-3.0-only +// End of Source File Header + +#pragma once +#include +#include + +namespace MobileGL { + namespace MG_Util { + VkImageViewType ConvertTextureTargetToVkEnum(TextureTarget target); + VkFormat ConvertTextureInputFormatToVkEnum(TextureInputFormat format); + VkFormat ConvertTextureInternalFormatToVkEnum(TextureInternalFormat internalformat); + VkFormat ConvertTexturePixelDataTypeToVkEnum(TexturePixelDataType type); + VkImageViewType ConvertTextureUploadTargetToVkEnum(TextureUploadTarget target); + VkFilter ConvertSamplerFilterModeToVkEnum(SamplerFilterMode filter, SamplerMipmapMode mipmap); + VkSamplerMipmapMode ConvertSamplerMipmapModeToVkEnum(SamplerMipmapMode value); + VkSamplerAddressMode ConvertSamplerWrapModeToVkEnum(SamplerWrapMode value); + VkBool32 ConvertSamplerCompareModeToVkEnum(SamplerCompareMode value); + VkCompareOp ConvertSamplerCompareFuncToVkEnum(SamplerCompareFunc value); + VkComponentSwizzle ConvertTextureSwizzleParamToVkEnum(TextureSwizzleParam value); + } // namespace MG_Util +} // namespace MobileGL