diff --git a/source/renderer/backend/vulkan/DescriptorManager.h b/source/renderer/backend/vulkan/DescriptorManager.h index 442ae4aff9..f3dee9c121 100644 --- a/source/renderer/backend/vulkan/DescriptorManager.h +++ b/source/renderer/backend/vulkan/DescriptorManager.h @@ -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 @@ -136,6 +138,73 @@ private: std::unique_ptr m_ErrorTexture; }; +// TODO: ideally we might want to separate a set and its mapping. +template +class CSingleTypeDescriptorSetBinding +{ +public: + CSingleTypeDescriptorSetBinding(CDevice* device, const VkDescriptorType type, + const uint32_t size, std::unordered_map 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 m_Mapping; + + bool m_Outdated{true}; + + VkDescriptorSetLayout m_DescriptorSetLayout{VK_NULL_HANDLE}; + + std::vector m_BoundDeviceObjects; + std::vector m_BoundUIDs; +}; + } // namespace Vulkan } // namespace Backend diff --git a/source/renderer/backend/vulkan/DeviceCommandContext.cpp b/source/renderer/backend/vulkan/DeviceCommandContext.cpp index b3a2e06fbf..0037a04367 100644 --- a/source/renderer/backend/vulkan/DeviceCommandContext.cpp +++ b/source/renderer/backend/vulkan/DeviceCommandContext.cpp @@ -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 = diff --git a/source/renderer/backend/vulkan/ShaderProgram.cpp b/source/renderer/backend/vulkan/ShaderProgram.cpp index 399cb4c2ce..18d92117d9 100644 --- a/source/renderer/backend/vulkan/ShaderProgram.cpp +++ b/source/renderer/backend/vulkan/ShaderProgram.cpp @@ -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::Create( return true; }; + uint32_t texturesDescriptorSetSize = 0; + std::unordered_map textureMapping; + auto addDescriptorSets = [&](const XMBElement& element) -> bool { const bool useDescriptorIndexing = @@ -300,9 +305,9 @@ std::unique_ptr 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::Create( std::vector 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, 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(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); } } diff --git a/source/renderer/backend/vulkan/ShaderProgram.h b/source/renderer/backend/vulkan/ShaderProgram.h index d623f50f59..f3e3471c2c 100644 --- a/source/renderer/backend/vulkan/ShaderProgram.h +++ b/source/renderer/backend/vulkan/ShaderProgram.h @@ -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 #include #include #include +#include #include #include @@ -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 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 m_UniformMapping; std::unordered_map m_PushConstantMapping; - uint32_t m_TexturesDescriptorSetSize = 0; - bool m_BoundTexturesOutdated = false; - - VkDescriptorSetLayout m_TexturesDescriptorSetLayout = VK_NULL_HANDLE; - std::vector m_BoundTextures; - std::vector m_BoundTexturesUID; - VkDescriptorSet m_ActiveTexturesDescriptorSet = VK_NULL_HANDLE; - std::unordered_map m_TextureMapping; + std::optional> m_TextureBinding; std::unordered_map m_StreamLocations; };