1
0
forked from 0ad/0ad
0ad/source/renderer/backend/vulkan/RenderPassManager.cpp

201 lines
6.7 KiB
C++

/* Copyright (C) 2023 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* 0 A.D. is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
*/
#include "precompiled.h"
#include "RenderPassManager.h"
#include "lib/hash.h"
#include "ps/containers/StaticVector.h"
#include "renderer/backend/vulkan/Device.h"
#include "renderer/backend/vulkan/Mapping.h"
#include "renderer/backend/vulkan/Texture.h"
#include "renderer/backend/vulkan/Utilities.h"
namespace Renderer
{
namespace Backend
{
namespace Vulkan
{
size_t CRenderPassManager::DescHash::operator()(const Desc& desc) const
{
size_t seed = 0;
hash_combine(seed, desc.sampleCount);
if (desc.colorAttachment.has_value())
{
hash_combine(seed, (*desc.colorAttachment).format);
hash_combine(seed, (*desc.colorAttachment).loadOp);
hash_combine(seed, (*desc.colorAttachment).storeOp);
}
else
hash_combine(seed, VK_FORMAT_UNDEFINED);
if (desc.depthStencilAttachment.has_value())
{
hash_combine(seed, (*desc.depthStencilAttachment).format);
hash_combine(seed, (*desc.depthStencilAttachment).loadOp);
hash_combine(seed, (*desc.depthStencilAttachment).storeOp);
}
else
hash_combine(seed, VK_FORMAT_UNDEFINED);
return seed;
}
bool CRenderPassManager::DescEqual::operator()(const Desc& lhs, const Desc& rhs) const
{
auto compareAttachments = [](const std::optional<Attachment>& lhs, const std::optional<Attachment>& rhs) -> bool
{
if (lhs.has_value() != rhs.has_value())
return false;
if (!lhs.has_value())
return true;
return
(*lhs).format == (*rhs).format &&
(*lhs).loadOp == (*rhs).loadOp &&
(*lhs).storeOp == (*rhs).storeOp;
};
if (!compareAttachments(lhs.colorAttachment, rhs.colorAttachment))
return false;
if (!compareAttachments(lhs.depthStencilAttachment, rhs.depthStencilAttachment))
return false;
return lhs.sampleCount == rhs.sampleCount;
}
CRenderPassManager::CRenderPassManager(CDevice* device)
: m_Device(device)
{
}
CRenderPassManager::~CRenderPassManager()
{
for (const auto& it : m_RenderPassMap)
if (it.second != VK_NULL_HANDLE)
{
m_Device->ScheduleObjectToDestroy(
VK_OBJECT_TYPE_RENDER_PASS, it.second, VK_NULL_HANDLE);
}
m_RenderPassMap.clear();
}
VkRenderPass CRenderPassManager::GetOrCreateRenderPass(
SColorAttachment* colorAttachment,
SDepthStencilAttachment* depthStencilAttachment)
{
Desc desc{};
if (colorAttachment)
{
CTexture* colorAttachmentTexture = colorAttachment->texture->As<CTexture>();
desc.sampleCount = colorAttachmentTexture->GetSampleCount();
desc.colorAttachment.emplace(Attachment{
colorAttachmentTexture->GetVkFormat(),
colorAttachment->loadOp,
colorAttachment->storeOp});
}
if (depthStencilAttachment)
{
CTexture* depthStencilAttachmentTexture = depthStencilAttachment->texture->As<CTexture>();
desc.sampleCount = depthStencilAttachmentTexture->GetSampleCount();
desc.depthStencilAttachment.emplace(Attachment{
depthStencilAttachmentTexture->GetVkFormat(),
depthStencilAttachment->loadOp,
depthStencilAttachment->storeOp});
}
auto it = m_RenderPassMap.find(desc);
if (it != m_RenderPassMap.end())
return it->second;
uint32_t attachmentCount = 0;
PS::StaticVector<VkAttachmentDescription, 4> attachmentDescs;
std::optional<VkAttachmentReference> colorAttachmentRef;
std::optional<VkAttachmentReference> depthStencilAttachmentRef;
if (colorAttachment)
{
CTexture* colorAttachmentTexture = colorAttachment->texture->As<CTexture>();
VkAttachmentDescription colorAttachmentDesc{};
colorAttachmentDesc.format = colorAttachmentTexture->GetVkFormat();
colorAttachmentDesc.samples = Mapping::FromSampleCount(colorAttachmentTexture->GetSampleCount());
colorAttachmentDesc.loadOp = Mapping::FromAttachmentLoadOp(colorAttachment->loadOp);
colorAttachmentDesc.storeOp = Mapping::FromAttachmentStoreOp(colorAttachment->storeOp);
colorAttachmentDesc.initialLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
colorAttachmentDesc.finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
attachmentDescs.emplace_back(std::move(colorAttachmentDesc));
colorAttachmentRef.emplace(VkAttachmentReference{
attachmentCount++, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL});
}
if (depthStencilAttachment)
{
CTexture* depthStencilAttachmentTexture = depthStencilAttachment->texture->As<CTexture>();
VkAttachmentDescription depthStencilAttachmentDesc{};
depthStencilAttachmentDesc.format = depthStencilAttachmentTexture->GetVkFormat();
depthStencilAttachmentDesc.samples = Mapping::FromSampleCount(depthStencilAttachmentTexture->GetSampleCount());
depthStencilAttachmentDesc.loadOp = Mapping::FromAttachmentLoadOp(depthStencilAttachment->loadOp);
depthStencilAttachmentDesc.storeOp = Mapping::FromAttachmentStoreOp(depthStencilAttachment->storeOp);
depthStencilAttachmentDesc.stencilLoadOp = depthStencilAttachmentDesc.loadOp;
depthStencilAttachmentDesc.stencilStoreOp = depthStencilAttachmentDesc.storeOp;
depthStencilAttachmentDesc.initialLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
depthStencilAttachmentDesc.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
attachmentDescs.emplace_back(std::move(depthStencilAttachmentDesc));
depthStencilAttachmentRef.emplace(VkAttachmentReference{
attachmentCount++, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL});
}
VkSubpassDescription subpassDesc{};
subpassDesc.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
if (colorAttachment)
{
subpassDesc.colorAttachmentCount = 1;
subpassDesc.pColorAttachments = &(*colorAttachmentRef);
}
if (depthStencilAttachment)
subpassDesc.pDepthStencilAttachment = &(*depthStencilAttachmentRef);
VkRenderPassCreateInfo renderPassCreateInfo{};
renderPassCreateInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
renderPassCreateInfo.attachmentCount = attachmentDescs.size();
renderPassCreateInfo.pAttachments = attachmentDescs.data();
renderPassCreateInfo.subpassCount = 1;
renderPassCreateInfo.pSubpasses = &subpassDesc;
VkRenderPass renderPass = VK_NULL_HANDLE;
ENSURE_VK_SUCCESS(
vkCreateRenderPass(
m_Device->GetVkDevice(), &renderPassCreateInfo, nullptr, &renderPass));
it = m_RenderPassMap.emplace(desc, renderPass).first;
return renderPass;
}
} // namespace Vulkan
} // namespace Backend
} // namespace Renderer