mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-11-07 01:53:24 +09:00
- Layout only: token streams match up to split literals, continuations and using order - The size totals fall, so the structure baseline is lowered
156 lines
7.6 KiB
C++
156 lines
7.6 KiB
C++
// MobileGL - MobileGL/MG_Backend/DirectVulkan/Renderer/VkRenderPassManager.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 "VkRenderPassManager.h"
|
|
#include "RenderPassGuard.h"
|
|
#include <atomic>
|
|
|
|
#include "MG_Impl/GLImpl/Framebuffer/GL_Framebuffer.h"
|
|
#include "MG_State/GLState/TextureState/TextureObject2D.h"
|
|
#include "MG_Util/Converters/MGToStr/FramebufferEnumConverter.h"
|
|
#include "MG_Util/Converters/MGToVk/TextureEnumConverter.h"
|
|
#include "MG_Util/Metrics/TextureMetrics.h"
|
|
#include <MG_Backend/MGPipe/PipeInputs.h>
|
|
|
|
namespace MobileGL::MG_Backend::DirectVulkan {
|
|
[[maybe_unused]] static Float ResolveColorClearAlpha(const MG_State::GLState::ITextureObject* texture,
|
|
Float requestedAlpha) {
|
|
if (texture != nullptr && MG_Util::GetBaseInternalFormatComponentCount(texture->GetFormat()) == 3) {
|
|
return 1.0f;
|
|
}
|
|
return requestedAlpha;
|
|
}
|
|
|
|
// ResolveAttachmentLayerCount lives in VkTextureManager.h, beside ToVulkanLevelExtent, because
|
|
// VkClearManager needs the SAME answer: its pending-clear key's layerCount becomes a real
|
|
// VkImageSubresourceRange when a clear is materialised outside a render pass. See the header.
|
|
|
|
DepthStencilAttachmentLoadInfo ResolveDepthStencilAttachmentLoadInfo(VkImageLayout trackedLayout, Bool clearDepth,
|
|
Bool clearStencil) {
|
|
DepthStencilAttachmentLoadInfo info{};
|
|
info.depthLoadOp = clearDepth ? VK_ATTACHMENT_LOAD_OP_CLEAR
|
|
: (trackedLayout == VK_IMAGE_LAYOUT_UNDEFINED ? VK_ATTACHMENT_LOAD_OP_DONT_CARE
|
|
: VK_ATTACHMENT_LOAD_OP_LOAD);
|
|
info.stencilLoadOp = clearStencil
|
|
? VK_ATTACHMENT_LOAD_OP_CLEAR
|
|
: (trackedLayout == VK_IMAGE_LAYOUT_UNDEFINED ? VK_ATTACHMENT_LOAD_OP_DONT_CARE
|
|
: VK_ATTACHMENT_LOAD_OP_LOAD);
|
|
info.initialLayout = (trackedLayout == VK_IMAGE_LAYOUT_UNDEFINED || (clearDepth && clearStencil))
|
|
? VK_IMAGE_LAYOUT_UNDEFINED
|
|
: trackedLayout;
|
|
return info;
|
|
}
|
|
|
|
IntVec2 ResolveRenderPassFramebufferExtent(Bool isDefaultFbo, const TextureSize& attachmentExtent,
|
|
VkExtent2D swapchainExtent) {
|
|
if (isDefaultFbo) {
|
|
return {static_cast<Int>(swapchainExtent.width), static_cast<Int>(swapchainExtent.height)};
|
|
}
|
|
return {attachmentExtent.x(), attachmentExtent.y()};
|
|
}
|
|
|
|
VkRenderPassManager::VkRenderPassManager(VkDevice device, VkPhysicalDevice physicalDevice, VmaAllocator allocator,
|
|
const VulkanRendererConfig& config, VkTextureManager& textureManager,
|
|
SwapchainObject& swapchainObject)
|
|
: m_device(device), m_physicalDevice(physicalDevice), m_allocator(allocator), m_config(config),
|
|
m_textureManager(textureManager), m_swapchainObject(swapchainObject) {
|
|
RenderPassEntry::s_device.Get() = m_device;
|
|
s_textureManager.Get() = &m_textureManager;
|
|
s_swapchainObject.Get() = &m_swapchainObject;
|
|
s_renderPassManager.Get() = this;
|
|
}
|
|
|
|
VkRenderPassManager::~VkRenderPassManager() {}
|
|
|
|
Bool VkRenderPassManager::Initialize() {
|
|
return true;
|
|
}
|
|
|
|
void VkRenderPassManager::Shutdown() {
|
|
s_activeRenderPass.Get() = {};
|
|
s_hasActiveRenderPass.Get() = false;
|
|
}
|
|
|
|
Bool VkRenderPassManager::BeginRenderPass(VkCommandBuffer commandBuffer, RenderPassEntry& renderPassEntry) {
|
|
// TODO: Transition all the attachments into proper layout before starting the render pass
|
|
VkRenderPassBeginInfo renderPassBeginInfo;
|
|
renderPassBeginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
|
|
renderPassBeginInfo.pNext = nullptr;
|
|
renderPassBeginInfo.renderPass = renderPassEntry.renderPass;
|
|
renderPassBeginInfo.framebuffer = renderPassEntry.framebuffer;
|
|
renderPassBeginInfo.renderArea.offset = {0, 0};
|
|
renderPassBeginInfo.renderArea.extent = {(Uint32)renderPassEntry.extent.x(),
|
|
(Uint32)renderPassEntry.extent.y()};
|
|
|
|
Vector<VkClearValue> clearValues(renderPassEntry.attachmentCount);
|
|
for (auto& clearValue : clearValues) {
|
|
clearValue.color = {0.0f, 0.0f, 0.0f, 1.0f};
|
|
clearValue.depthStencil = {1.0f, 0};
|
|
}
|
|
renderPassBeginInfo.clearValueCount = static_cast<Uint32>(clearValues.size());
|
|
renderPassBeginInfo.pClearValues = clearValues.data();
|
|
|
|
vkCmdBeginRenderPass(commandBuffer, &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
|
|
s_activeRenderPass.Get().commandBuffer = commandBuffer;
|
|
s_activeRenderPass.Get().hash = renderPassEntry.hash;
|
|
s_activeRenderPass.Get().compatibilityHash = renderPassEntry.compatibilityHash;
|
|
s_activeRenderPass.Get().extent = renderPassEntry.extent;
|
|
s_hasActiveRenderPass.Get() = true;
|
|
|
|
return true;
|
|
}
|
|
|
|
Bool VkRenderPassManager::BeginRenderPass(VkCommandBuffer commandBuffer, RenderPassEntry& renderPassEntry,
|
|
VkRenderPass renderPass, const VkClearValue* clearValues,
|
|
Uint32 clearValueCount) {
|
|
VkRenderPassBeginInfo begin{VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO};
|
|
begin.renderPass = renderPass;
|
|
begin.framebuffer = renderPassEntry.framebuffer;
|
|
begin.renderArea = {
|
|
{0, 0}, {static_cast<Uint32>(renderPassEntry.extent.x()), static_cast<Uint32>(renderPassEntry.extent.y())}};
|
|
begin.clearValueCount = clearValueCount;
|
|
begin.pClearValues = clearValues;
|
|
vkCmdBeginRenderPass(commandBuffer, &begin, VK_SUBPASS_CONTENTS_INLINE);
|
|
s_activeRenderPass.Get().commandBuffer = commandBuffer;
|
|
s_activeRenderPass.Get().hash = renderPassEntry.hash;
|
|
s_activeRenderPass.Get().compatibilityHash = renderPassEntry.compatibilityHash;
|
|
s_activeRenderPass.Get().extent = renderPassEntry.extent;
|
|
s_hasActiveRenderPass.Get() = true;
|
|
return true;
|
|
}
|
|
|
|
Bool VkRenderPassManager::EndRenderPass(VkCommandBuffer commandBuffer) {
|
|
BumpWireImageWriteEpoch();
|
|
vkCmdEndRenderPass(commandBuffer);
|
|
s_activeRenderPass.Get() = {};
|
|
s_hasActiveRenderPass.Get() = false;
|
|
return true;
|
|
}
|
|
|
|
ActiveRenderPassInfo* VkRenderPassManager::GetActiveRenderPass() {
|
|
return s_hasActiveRenderPass.Get() ? &s_activeRenderPass.Get() : nullptr;
|
|
}
|
|
namespace {
|
|
std::atomic<Uint64> g_wireImageWriteEpoch{1};
|
|
} // namespace
|
|
Uint64 WireImageWriteEpoch() {
|
|
return g_wireImageWriteEpoch.load(std::memory_order_relaxed);
|
|
}
|
|
void BumpWireImageWriteEpoch() {
|
|
g_wireImageWriteEpoch.fetch_add(1, std::memory_order_relaxed);
|
|
}
|
|
|
|
void EndActiveRenderPassOn(VkCommandBuffer commandBuffer) {
|
|
BumpWireImageWriteEpoch();
|
|
const auto* active = VkRenderPassManager::GetActiveRenderPass();
|
|
if (active != nullptr && active->commandBuffer == commandBuffer && commandBuffer != VK_NULL_HANDLE)
|
|
VkRenderPassManager::EndRenderPass(commandBuffer);
|
|
}
|
|
|
|
} // namespace MobileGL::MG_Backend::DirectVulkan
|