1
0
forked from 0ad/0ad

Moves single descriptor set binding management for Vulkan to a separate class.

Differential Revision: https://code.wildfiregames.com/D5163
This was SVN commit r27921.
This commit is contained in:
Vladislav Belov 2023-11-07 21:43:52 +00:00
parent c78ad51057
commit a905932712
4 changed files with 110 additions and 54 deletions

View File

@ -18,7 +18,9 @@
#ifndef INCLUDED_RENDERER_BACKEND_VULKAN_DESCRIPTORMANAGER
#define INCLUDED_RENDERER_BACKEND_VULKAN_DESCRIPTORMANAGER
#include "ps/CStrIntern.h"
#include "renderer/backend/Sampler.h"
#include "renderer/backend/vulkan/Device.h"
#include "renderer/backend/vulkan/Texture.h"
#include <glad/vulkan.h>
@ -136,6 +138,73 @@ private:
std::unique_ptr<ITexture> m_ErrorTexture;
};
// TODO: ideally we might want to separate a set and its mapping.
template<typename DeviceObject>
class CSingleTypeDescriptorSetBinding
{
public:
CSingleTypeDescriptorSetBinding(CDevice* device, const VkDescriptorType type,
const uint32_t size, std::unordered_map<CStrIntern, uint32_t> mapping)
: m_Device{device}, m_Type{type}, m_Mapping{std::move(mapping)}
{
m_BoundDeviceObjects.resize(size);
m_BoundUIDs.resize(size);
m_DescriptorSetLayout =
m_Device->GetDescriptorManager().GetSingleTypeDescritorSetLayout(m_Type, size);
}
int32_t GetBindingSlot(const CStrIntern name) const
{
const auto it = m_Mapping.find(name);
return it != m_Mapping.end() ? it->second : -1;
}
void SetObject(const int32_t bindingSlot, DeviceObject* object)
{
if (m_BoundUIDs[bindingSlot] == object->GetUID())
return;
m_BoundUIDs[bindingSlot] = object->GetUID();
m_BoundDeviceObjects[bindingSlot] = object;
m_Outdated = true;
}
bool IsOutdated() const { return m_Outdated; }
VkDescriptorSet UpdateAndReturnDescriptorSet()
{
ENSURE(m_Outdated);
m_Outdated = false;
VkDescriptorSet descriptorSet =
m_Device->GetDescriptorManager().GetSingleTypeDescritorSet(
m_Type, m_DescriptorSetLayout, m_BoundUIDs, m_BoundDeviceObjects);
ENSURE(descriptorSet != VK_NULL_HANDLE);
return descriptorSet;
}
void Unbind()
{
std::fill(m_BoundDeviceObjects.begin(), m_BoundDeviceObjects.end(), nullptr);
std::fill(m_BoundUIDs.begin(), m_BoundUIDs.end(), INVALID_DEVICE_OBJECT_UID);
m_Outdated = true;
}
VkDescriptorSetLayout GetDescriptorSetLayout() { return m_DescriptorSetLayout; }
private:
CDevice* const m_Device;
const VkDescriptorType m_Type;
const std::unordered_map<CStrIntern, uint32_t> m_Mapping;
bool m_Outdated{true};
VkDescriptorSetLayout m_DescriptorSetLayout{VK_NULL_HANDLE};
std::vector<DeviceObject*> m_BoundDeviceObjects;
std::vector<DeviceObjectUID> m_BoundUIDs;
};
} // namespace Vulkan
} // namespace Backend

View File

@ -1073,7 +1073,7 @@ void CDeviceCommandContext::PreDraw()
{
ENSURE(m_InsidePass);
ApplyPipelineStateIfDirty();
m_ShaderProgram->PreDraw(m_CommandContext->GetCommandBuffer());
m_ShaderProgram->PreDraw(*m_CommandContext);
if (m_ShaderProgram->IsMaterialConstantsDataOutdated())
{
const VkDeviceSize alignment =

View File

@ -21,6 +21,7 @@
#include "graphics/ShaderDefines.h"
#include "ps/CLogger.h"
#include "ps/containers/StaticVector.h"
#include "ps/CStr.h"
#include "ps/CStrInternStatic.h"
#include "ps/Filesystem.h"
@ -28,6 +29,7 @@
#include "ps/XML/Xeromyces.h"
#include "renderer/backend/vulkan/DescriptorManager.h"
#include "renderer/backend/vulkan/Device.h"
#include "renderer/backend/vulkan/RingCommandContext.h"
#include "renderer/backend/vulkan/Texture.h"
#include "renderer/backend/vulkan/Utilities.h"
@ -226,6 +228,9 @@ std::unique_ptr<CShaderProgram> CShaderProgram::Create(
return true;
};
uint32_t texturesDescriptorSetSize = 0;
std::unordered_map<CStrIntern, uint32_t> textureMapping;
auto addDescriptorSets = [&](const XMBElement& element) -> bool
{
const bool useDescriptorIndexing =
@ -300,9 +305,9 @@ std::unique_ptr<CShaderProgram> CShaderProgram::Create(
return false;
}
const CStrIntern name{attributes.GetNamedItem(at_name)};
shaderProgram->m_TextureMapping[name] = binding;
shaderProgram->m_TexturesDescriptorSetSize =
std::max(shaderProgram->m_TexturesDescriptorSetSize, binding + 1);
textureMapping[name] = binding;
texturesDescriptorSetSize =
std::max(texturesDescriptorSetSize, binding + 1);
}
else
{
@ -470,16 +475,12 @@ std::unique_ptr<CShaderProgram> CShaderProgram::Create(
std::vector<VkDescriptorSetLayout> layouts =
device->GetDescriptorManager().GetDescriptorSetLayouts();
if (shaderProgram->m_TexturesDescriptorSetSize > 0)
if (texturesDescriptorSetSize > 0)
{
ENSURE(!device->GetDescriptorManager().UseDescriptorIndexing());
shaderProgram->m_BoundTextures.resize(shaderProgram->m_TexturesDescriptorSetSize);
shaderProgram->m_BoundTexturesUID.resize(shaderProgram->m_TexturesDescriptorSetSize);
shaderProgram->m_BoundTexturesOutdated = true;
shaderProgram->m_TexturesDescriptorSetLayout =
device->GetDescriptorManager().GetSingleTypeDescritorSetLayout(
VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, shaderProgram->m_TexturesDescriptorSetSize);
layouts.emplace_back(shaderProgram->m_TexturesDescriptorSetLayout);
shaderProgram->m_TextureBinding.emplace(
device, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, texturesDescriptorSetSize, std::move(textureMapping));
layouts.emplace_back(shaderProgram->m_TextureBinding->GetDescriptorSetLayout());
}
VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo{};
@ -524,8 +525,8 @@ int32_t CShaderProgram::GetBindingSlot(const CStrIntern name) const
return it->second;
if (auto it = m_UniformMapping.find(name); it != m_UniformMapping.end())
return it->second + m_PushConstants.size();
if (auto it = m_TextureMapping.find(name); it != m_TextureMapping.end())
return it->second + m_PushConstants.size() + m_UniformMapping.size();
if (const int32_t bindingSlot = m_TextureBinding.has_value() ? m_TextureBinding->GetBindingSlot(name) : -1; bindingSlot != -1)
return bindingSlot + m_PushConstants.size() + m_UniformMapping.size();
return -1;
}
@ -548,19 +549,13 @@ void CShaderProgram::Bind()
void CShaderProgram::Unbind()
{
if (m_TexturesDescriptorSetSize > 0)
{
for (CTexture*& texture : m_BoundTextures)
texture = nullptr;
for (DeviceObjectUID& uid : m_BoundTexturesUID)
uid = 0;
m_BoundTexturesOutdated = true;
}
if (m_TextureBinding.has_value())
m_TextureBinding->Unbind();
}
void CShaderProgram::PreDraw(VkCommandBuffer commandBuffer)
void CShaderProgram::PreDraw(CRingCommandContext& commandContext)
{
UpdateActiveDescriptorSet(commandBuffer);
BindOutdatedDescriptorSets(commandContext);
if (m_PushConstantDataMask)
{
for (uint32_t index = 0; index < 32;)
@ -574,7 +569,7 @@ void CShaderProgram::PreDraw(VkCommandBuffer commandBuffer)
while (indexEnd < 32 && (m_PushConstantDataMask & (1 << indexEnd)) && m_PushConstantDataFlags[index] == m_PushConstantDataFlags[indexEnd])
++indexEnd;
vkCmdPushConstants(
commandBuffer, GetPipelineLayout(),
commandContext.GetCommandBuffer(), GetPipelineLayout(),
m_PushConstantDataFlags[index],
index * 4, (indexEnd - index) * 4, m_PushConstantData.data() + index * 4);
index = indexEnd;
@ -583,22 +578,22 @@ void CShaderProgram::PreDraw(VkCommandBuffer commandBuffer)
}
}
void CShaderProgram::UpdateActiveDescriptorSet(
VkCommandBuffer commandBuffer)
void CShaderProgram::BindOutdatedDescriptorSets(
CRingCommandContext& commandContext)
{
if (m_BoundTexturesOutdated)
// TODO: combine calls after more sets to bind.
PS::StaticVector<std::tuple<uint32_t, VkDescriptorSet>, 1> descriptortSets;
if (m_TextureBinding.has_value() && m_TextureBinding->IsOutdated())
{
m_BoundTexturesOutdated = false;
m_ActiveTexturesDescriptorSet =
m_Device->GetDescriptorManager().GetSingleTypeDescritorSet(
VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, m_TexturesDescriptorSetLayout,
m_BoundTexturesUID, m_BoundTextures);
ENSURE(m_ActiveTexturesDescriptorSet != VK_NULL_HANDLE);
constexpr uint32_t TEXTURE_BINDING_SET = 1u;
descriptortSets.emplace_back(TEXTURE_BINDING_SET, m_TextureBinding->UpdateAndReturnDescriptorSet());
}
for (const auto [firstSet, descriptorSet] : descriptortSets)
{
vkCmdBindDescriptorSets(
commandBuffer, GetPipelineBindPoint(), GetPipelineLayout(),
1, 1, &m_ActiveTexturesDescriptorSet, 0, nullptr);
commandContext.GetCommandBuffer(), GetPipelineBindPoint(), GetPipelineLayout(),
firstSet, 1, &descriptorSet, 0, nullptr);
}
}
@ -686,13 +681,9 @@ void CShaderProgram::SetTexture(const int32_t bindingSlot, CTexture* texture)
else
{
ENSURE(bindingSlot >= static_cast<int32_t>(m_PushConstants.size() + m_UniformMapping.size()));
ENSURE(m_TextureBinding.has_value());
const uint32_t index = bindingSlot - (m_PushConstants.size() + m_UniformMapping.size());
if (m_BoundTexturesUID[index] != texture->GetUID())
{
m_BoundTextures[index] = texture;
m_BoundTexturesUID[index] = texture->GetUID();
m_BoundTexturesOutdated = true;
}
m_TextureBinding->SetObject(index, texture);
}
}

View File

@ -19,12 +19,14 @@
#define INCLUDED_RENDERER_BACKEND_VULKAN_SHADERPROGRAM
#include "renderer/backend/IShaderProgram.h"
#include "renderer/backend/vulkan/DescriptorManager.h"
#include "renderer/backend/vulkan/Texture.h"
#include <array>
#include <cstddef>
#include <glad/vulkan.h>
#include <memory>
#include <optional>
#include <unordered_map>
#include <vector>
@ -41,6 +43,7 @@ namespace Vulkan
{
class CDevice;
class CRingCommandContext;
class CVertexInputLayout : public IVertexInputLayout
{
@ -91,7 +94,7 @@ public:
void Bind();
void Unbind();
void PreDraw(VkCommandBuffer commandBuffer);
void PreDraw(CRingCommandContext& commandContext);
VkPipelineLayout GetPipelineLayout() const { return m_PipelineLayout; }
VkPipelineBindPoint GetPipelineBindPoint() const { return VK_PIPELINE_BIND_POINT_GRAPHICS; }
@ -131,8 +134,8 @@ private:
static std::unique_ptr<CShaderProgram> Create(
CDevice* device, const CStr& name, const CShaderDefines& defines);
void UpdateActiveDescriptorSet(
VkCommandBuffer commandBuffer);
void BindOutdatedDescriptorSets(
CRingCommandContext& commandContext);
CDevice* m_Device = nullptr;
@ -166,14 +169,7 @@ private:
std::unordered_map<CStrIntern, uint32_t> m_UniformMapping;
std::unordered_map<CStrIntern, uint32_t> m_PushConstantMapping;
uint32_t m_TexturesDescriptorSetSize = 0;
bool m_BoundTexturesOutdated = false;
VkDescriptorSetLayout m_TexturesDescriptorSetLayout = VK_NULL_HANDLE;
std::vector<CTexture*> m_BoundTextures;
std::vector<DeviceObjectUID> m_BoundTexturesUID;
VkDescriptorSet m_ActiveTexturesDescriptorSet = VK_NULL_HANDLE;
std::unordered_map<CStrIntern, uint32_t> m_TextureMapping;
std::optional<CSingleTypeDescriptorSetBinding<CTexture>> m_TextureBinding;
std::unordered_map<VertexAttributeStream, uint32_t> m_StreamLocations;
};