From ad085901978e9ac7baa0e36738f4266b0ebe9626 Mon Sep 17 00:00:00 2001 From: Flyinghead Date: Sun, 13 Mar 2022 11:39:30 +0100 Subject: [PATCH] vulkan: cache per-poly desc sets in map avoid desc set pool exhaustion in per-triangle --- core/rend/vulkan/drawer.cpp | 4 +- core/rend/vulkan/drawer.h | 6 +- core/rend/vulkan/oit/oit_drawer.cpp | 4 +- core/rend/vulkan/oit/oit_drawer.h | 2 +- core/rend/vulkan/oit/oit_pipeline.h | 99 +++++++++++++++++------------ core/rend/vulkan/pipeline.h | 84 ++++++++++++++---------- 6 files changed, 117 insertions(+), 82 deletions(-) diff --git a/core/rend/vulkan/drawer.cpp b/core/rend/vulkan/drawer.cpp index d8a694946..e72d04222 100644 --- a/core/rend/vulkan/drawer.cpp +++ b/core/rend/vulkan/drawer.cpp @@ -281,8 +281,8 @@ void Drawer::UploadMainBuffer(const VertexShaderUniforms& vertexUniforms, const std::vector n2lights; if (settings.platform.isNaomi2()) { - uploadNaomi2Uniforms(packer, offsets, n2uniforms, false); - offsets.lightsOffset = uploadNaomi2Lights(packer, n2lights); + packNaomi2Uniforms(packer, offsets, n2uniforms, false); + offsets.lightsOffset = packNaomi2Lights(packer, n2lights); } BufferData *buffer = GetMainBuffer(packer.size()); diff --git a/core/rend/vulkan/drawer.h b/core/rend/vulkan/drawer.h index a1afb2425..6a160c562 100644 --- a/core/rend/vulkan/drawer.h +++ b/core/rend/vulkan/drawer.h @@ -73,7 +73,7 @@ protected: } template - void uploadNaomi2Uniforms(BufferPacker& packer, Offsets& offsets, std::vector& n2uniforms, bool trModVolIncluded) + void packNaomi2Uniforms(BufferPacker& packer, Offsets& offsets, std::vector& n2uniforms, bool trModVolIncluded) { size_t n2UniformSize = sizeof(N2VertexShaderUniforms) + align(sizeof(N2VertexShaderUniforms), GetContext()->GetUniformBufferAlignment()); int items = pvrrc.global_param_op.used() + pvrrc.global_param_pt.used() + pvrrc.global_param_tr.used() + pvrrc.global_param_mvo.used(); @@ -139,7 +139,7 @@ protected: offsets.naomi2TrModVolOffset = offsets.naomi2OpaqueOffset + trMvOffset; } - vk::DeviceSize uploadNaomi2Lights(BufferPacker& packer, std::vector& n2lights) + vk::DeviceSize packNaomi2Lights(BufferPacker& packer, std::vector& n2lights) { size_t n2LightSize = sizeof(VkN2LightConstants) + align(sizeof(VkN2LightConstants), GetContext()->GetUniformBufferAlignment()); n2lights.resize(pvrrc.lightModels.used() * n2LightSize); @@ -202,7 +202,7 @@ protected: virtual vk::CommandBuffer BeginRenderPass() = 0; void NewImage() { - descriptorSets.reset(); + descriptorSets.nextFrame(); imageIndex = (imageIndex + 1) % GetSwapChainSize(); if (perStripSorting != config::PerStripSorting) { diff --git a/core/rend/vulkan/oit/oit_drawer.cpp b/core/rend/vulkan/oit/oit_drawer.cpp index ab15a96fc..e5d36c199 100644 --- a/core/rend/vulkan/oit/oit_drawer.cpp +++ b/core/rend/vulkan/oit/oit_drawer.cpp @@ -241,8 +241,8 @@ void OITDrawer::UploadMainBuffer(const OITDescriptorSets::VertexShaderUniforms& std::vector n2lights; if (settings.platform.isNaomi2()) { - uploadNaomi2Uniforms(packer, offsets, n2uniforms, true); - offsets.lightsOffset = uploadNaomi2Lights(packer, n2lights); + packNaomi2Uniforms(packer, offsets, n2uniforms, true); + offsets.lightsOffset = packNaomi2Lights(packer, n2lights); } BufferData *buffer = GetMainBuffer(packer.size()); diff --git a/core/rend/vulkan/oit/oit_drawer.h b/core/rend/vulkan/oit/oit_drawer.h index 7c708567d..4c36f77ab 100644 --- a/core/rend/vulkan/oit/oit_drawer.h +++ b/core/rend/vulkan/oit/oit_drawer.h @@ -75,7 +75,7 @@ protected: void NewImage() { - descriptorSets.reset(); + descriptorSets.nextFrame(); imageIndex = (imageIndex + 1) % GetContext()->GetSwapChainSize(); renderPass = 0; } diff --git a/core/rend/vulkan/oit/oit_pipeline.h b/core/rend/vulkan/oit/oit_pipeline.h index 5e2949d16..88b182bba 100644 --- a/core/rend/vulkan/oit/oit_pipeline.h +++ b/core/rend/vulkan/oit/oit_pipeline.h @@ -27,6 +27,7 @@ #include "../desc_set.h" #include +#include class OITDescriptorSets { @@ -154,44 +155,51 @@ public: void bindPerPolyDescriptorSets(vk::CommandBuffer cmdBuffer, const PolyParam& poly, int polyNumber, vk::Buffer buffer, vk::DeviceSize uniformOffset, vk::DeviceSize lightOffset) { - vk::DescriptorSet perPolyDescSet = perPolyAlloc.alloc(); - std::vector writeDescriptorSets; - - vk::DescriptorImageInfo imageInfo0; - if (poly.texture != nullptr) + vk::DescriptorSet perPolyDescSet; + auto it = perPolyDescSets.find(&poly); + if (it == perPolyDescSets.end()) { - imageInfo0 = vk::DescriptorImageInfo{ samplerManager->GetSampler(poly.tsp), ((Texture *)poly.texture)->GetReadOnlyImageView(), - vk::ImageLayout::eShaderReadOnlyOptimal }; - writeDescriptorSets.emplace_back(perPolyDescSet, 0, 0, 1, vk::DescriptorType::eCombinedImageSampler, &imageInfo0, nullptr, nullptr); - } - vk::DescriptorImageInfo imageInfo1; - if (poly.texture1 != nullptr) - { - imageInfo1 = vk::DescriptorImageInfo{ samplerManager->GetSampler(poly.tsp1), ((Texture *)poly.texture1)->GetReadOnlyImageView(), - vk::ImageLayout::eShaderReadOnlyOptimal }; - writeDescriptorSets.emplace_back(perPolyDescSet, 1, 0, 1, vk::DescriptorType::eCombinedImageSampler, &imageInfo1, nullptr, nullptr); - } + perPolyDescSet = perPolyAlloc.alloc(); + std::vector writeDescriptorSets; - vk::DescriptorBufferInfo uniBufferInfo; - vk::DescriptorBufferInfo lightBufferInfo; - if (poly.isNaomi2()) - { - const vk::DeviceSize uniformAlignment = VulkanContext::Instance()->GetUniformBufferAlignment(); - size_t size = sizeof(N2VertexShaderUniforms) + align(sizeof(N2VertexShaderUniforms), uniformAlignment); - uniBufferInfo = vk::DescriptorBufferInfo{ buffer, uniformOffset + polyNumber * size, sizeof(N2VertexShaderUniforms) }; - writeDescriptorSets.emplace_back(perPolyDescSet, 2, 0, 1, vk::DescriptorType::eUniformBuffer, nullptr, &uniBufferInfo, nullptr); - - if (poly.lightModel != nullptr) + vk::DescriptorImageInfo imageInfo0; + if (poly.texture != nullptr) { - size = sizeof(VkN2LightConstants) + align(sizeof(VkN2LightConstants), uniformAlignment); - lightBufferInfo = vk::DescriptorBufferInfo{ buffer, lightOffset + (poly.lightModel - pvrrc.lightModels.head()) * size, sizeof(VkN2LightConstants) }; - writeDescriptorSets.emplace_back(perPolyDescSet, 3, 0, 1, vk::DescriptorType::eUniformBuffer, nullptr, &lightBufferInfo, nullptr); + imageInfo0 = vk::DescriptorImageInfo{ samplerManager->GetSampler(poly.tsp), ((Texture *)poly.texture)->GetReadOnlyImageView(), + vk::ImageLayout::eShaderReadOnlyOptimal }; + writeDescriptorSets.emplace_back(perPolyDescSet, 0, 0, 1, vk::DescriptorType::eCombinedImageSampler, &imageInfo0, nullptr, nullptr); } - // TODO no light + vk::DescriptorImageInfo imageInfo1; + if (poly.texture1 != nullptr) + { + imageInfo1 = vk::DescriptorImageInfo{ samplerManager->GetSampler(poly.tsp1), ((Texture *)poly.texture1)->GetReadOnlyImageView(), + vk::ImageLayout::eShaderReadOnlyOptimal }; + writeDescriptorSets.emplace_back(perPolyDescSet, 1, 0, 1, vk::DescriptorType::eCombinedImageSampler, &imageInfo1, nullptr, nullptr); + } + + vk::DescriptorBufferInfo uniBufferInfo; + vk::DescriptorBufferInfo lightBufferInfo; + if (poly.isNaomi2()) + { + const vk::DeviceSize uniformAlignment = VulkanContext::Instance()->GetUniformBufferAlignment(); + size_t size = sizeof(N2VertexShaderUniforms) + align(sizeof(N2VertexShaderUniforms), uniformAlignment); + uniBufferInfo = vk::DescriptorBufferInfo{ buffer, uniformOffset + polyNumber * size, sizeof(N2VertexShaderUniforms) }; + writeDescriptorSets.emplace_back(perPolyDescSet, 2, 0, 1, vk::DescriptorType::eUniformBuffer, nullptr, &uniBufferInfo, nullptr); + + if (poly.lightModel != nullptr) + { + size = sizeof(VkN2LightConstants) + align(sizeof(VkN2LightConstants), uniformAlignment); + lightBufferInfo = vk::DescriptorBufferInfo{ buffer, lightOffset + (poly.lightModel - pvrrc.lightModels.head()) * size, sizeof(VkN2LightConstants) }; + writeDescriptorSets.emplace_back(perPolyDescSet, 3, 0, 1, vk::DescriptorType::eUniformBuffer, nullptr, &lightBufferInfo, nullptr); + } + // TODO no light + } + + getContext()->GetDevice().updateDescriptorSets(writeDescriptorSets, nullptr); + perPolyDescSets[&poly] = perPolyDescSet; } - - getContext()->GetDevice().updateDescriptorSets(writeDescriptorSets, nullptr); - + else + perPolyDescSet = it->second; cmdBuffer.bindDescriptorSets(vk::PipelineBindPoint::eGraphics, pipelineLayout, 1, 1, &perPolyDescSet, 0, nullptr); } @@ -199,15 +207,22 @@ public: { if (!mvParam.isNaomi2()) return; - vk::DescriptorSet perPolyDescSet = perPolyAlloc.alloc(); + vk::DescriptorSet perPolyDescSet; + auto it = perPolyDescSets.find(&mvParam); + if (it == perPolyDescSets.end()) + { + perPolyDescSet = perPolyAlloc.alloc(); - const vk::DeviceSize uniformAlignment = VulkanContext::Instance()->GetUniformBufferAlignment(); - size_t size = sizeof(N2VertexShaderUniforms) + align(sizeof(N2VertexShaderUniforms), uniformAlignment); - vk::DescriptorBufferInfo uniBufferInfo{ buffer, uniformOffset + polyNumber * size, sizeof(N2VertexShaderUniforms) }; - vk::WriteDescriptorSet writeDescriptorSet(perPolyDescSet, 2, 0, 1, vk::DescriptorType::eUniformBuffer, nullptr, &uniBufferInfo, nullptr); - - getContext()->GetDevice().updateDescriptorSets(1, &writeDescriptorSet, 0, nullptr); + const vk::DeviceSize uniformAlignment = VulkanContext::Instance()->GetUniformBufferAlignment(); + size_t size = sizeof(N2VertexShaderUniforms) + align(sizeof(N2VertexShaderUniforms), uniformAlignment); + vk::DescriptorBufferInfo uniBufferInfo{ buffer, uniformOffset + polyNumber * size, sizeof(N2VertexShaderUniforms) }; + vk::WriteDescriptorSet writeDescriptorSet(perPolyDescSet, 2, 0, 1, vk::DescriptorType::eUniformBuffer, nullptr, &uniBufferInfo, nullptr); + getContext()->GetDevice().updateDescriptorSets(1, &writeDescriptorSet, 0, nullptr); + perPolyDescSets[&mvParam] = perPolyDescSet; + } + else + perPolyDescSet = it->second; cmdBuffer.bindDescriptorSets(vk::PipelineBindPoint::eGraphics, pipelineLayout, 1, 1, &perPolyDescSet, 0, nullptr); } @@ -221,11 +236,12 @@ public: cmdBuffer.bindDescriptorSets(vk::PipelineBindPoint::eGraphics, pipelineLayout, 2, 1, &colorInputDescSets[index], 0, nullptr); } - void reset() + void nextFrame() { perFrameDescSet = vk::DescriptorSet{}; colorInputDescSets[0] = vk::DescriptorSet{}; colorInputDescSets[1] = vk::DescriptorSet{}; + perPolyDescSets.clear(); perFrameAlloc.nextFrame(); perPolyAlloc.nextFrame(); colorInputAlloc.nextFrame(); @@ -248,6 +264,7 @@ private: DynamicDescSetAlloc perPolyAlloc; DynamicDescSetAlloc colorInputAlloc; vk::DescriptorSet perFrameDescSet = {}; + std::unordered_map perPolyDescSets; SamplerManager* samplerManager; }; diff --git a/core/rend/vulkan/pipeline.h b/core/rend/vulkan/pipeline.h index f0ba26de7..136b13501 100644 --- a/core/rend/vulkan/pipeline.h +++ b/core/rend/vulkan/pipeline.h @@ -26,6 +26,7 @@ #include "vulkan_context.h" #include "desc_set.h" #include +#include class DescriptorSets { @@ -78,36 +79,44 @@ public: void bindPerPolyDescriptorSets(vk::CommandBuffer cmdBuffer, const PolyParam& poly, int polyNumber, vk::Buffer buffer, vk::DeviceSize uniformOffset, vk::DeviceSize lightOffset) { - vk::DescriptorSet perPolyDescSet = perPolyAlloc.alloc(); - std::vector writeDescriptorSets; - - vk::DescriptorImageInfo imageInfo; - if (poly.texture != nullptr) + vk::DescriptorSet perPolyDescSet; + auto it = perPolyDescSets.find(&poly); + if (it == perPolyDescSets.end()) { - imageInfo = vk::DescriptorImageInfo(samplerManager->GetSampler(poly.tsp), - ((Texture *)poly.texture)->GetReadOnlyImageView(), vk::ImageLayout::eShaderReadOnlyOptimal); - writeDescriptorSets.emplace_back(perPolyDescSet, 0, 0, 1, vk::DescriptorType::eCombinedImageSampler, &imageInfo, nullptr, nullptr); - } + perPolyDescSet = perPolyAlloc.alloc(); + std::vector writeDescriptorSets; - vk::DescriptorBufferInfo uniBufferInfo; - vk::DescriptorBufferInfo lightBufferInfo; - if (poly.isNaomi2()) - { - const vk::DeviceSize uniformAlignment = VulkanContext::Instance()->GetUniformBufferAlignment(); - size_t size = sizeof(N2VertexShaderUniforms) + align(sizeof(N2VertexShaderUniforms), uniformAlignment); - uniBufferInfo = vk::DescriptorBufferInfo{ buffer, uniformOffset + polyNumber * size, sizeof(N2VertexShaderUniforms) }; - writeDescriptorSets.emplace_back(perPolyDescSet, 2, 0, 1, vk::DescriptorType::eUniformBuffer, nullptr, &uniBufferInfo, nullptr); - - if (poly.lightModel != nullptr) + vk::DescriptorImageInfo imageInfo; + if (poly.texture != nullptr) { - size = sizeof(VkN2LightConstants) + align(sizeof(VkN2LightConstants), uniformAlignment); - lightBufferInfo = vk::DescriptorBufferInfo{ buffer, lightOffset + (poly.lightModel - pvrrc.lightModels.head()) * size, sizeof(VkN2LightConstants) }; - writeDescriptorSets.emplace_back(perPolyDescSet, 3, 0, 1, vk::DescriptorType::eUniformBuffer, nullptr, &lightBufferInfo, nullptr); + imageInfo = vk::DescriptorImageInfo(samplerManager->GetSampler(poly.tsp), + ((Texture *)poly.texture)->GetReadOnlyImageView(), vk::ImageLayout::eShaderReadOnlyOptimal); + writeDescriptorSets.emplace_back(perPolyDescSet, 0, 0, 1, vk::DescriptorType::eCombinedImageSampler, &imageInfo, nullptr, nullptr); } - // TODO no light - } - getContext()->GetDevice().updateDescriptorSets(writeDescriptorSets, nullptr); + vk::DescriptorBufferInfo uniBufferInfo; + vk::DescriptorBufferInfo lightBufferInfo; + if (poly.isNaomi2()) + { + const vk::DeviceSize uniformAlignment = VulkanContext::Instance()->GetUniformBufferAlignment(); + size_t size = sizeof(N2VertexShaderUniforms) + align(sizeof(N2VertexShaderUniforms), uniformAlignment); + uniBufferInfo = vk::DescriptorBufferInfo{ buffer, uniformOffset + polyNumber * size, sizeof(N2VertexShaderUniforms) }; + writeDescriptorSets.emplace_back(perPolyDescSet, 2, 0, 1, vk::DescriptorType::eUniformBuffer, nullptr, &uniBufferInfo, nullptr); + + if (poly.lightModel != nullptr) + { + size = sizeof(VkN2LightConstants) + align(sizeof(VkN2LightConstants), uniformAlignment); + lightBufferInfo = vk::DescriptorBufferInfo{ buffer, lightOffset + (poly.lightModel - pvrrc.lightModels.head()) * size, sizeof(VkN2LightConstants) }; + writeDescriptorSets.emplace_back(perPolyDescSet, 3, 0, 1, vk::DescriptorType::eUniformBuffer, nullptr, &lightBufferInfo, nullptr); + } + // TODO no light + } + + getContext()->GetDevice().updateDescriptorSets(writeDescriptorSets, nullptr); + perPolyDescSets[&poly] = perPolyDescSet; + } + else + perPolyDescSet = it->second; cmdBuffer.bindDescriptorSets(vk::PipelineBindPoint::eGraphics, pipelineLayout, 1, 1, &perPolyDescSet, 0, nullptr); } @@ -116,15 +125,22 @@ public: { if (!mvParam.isNaomi2()) return; - vk::DescriptorSet perPolyDescSet = perPolyAlloc.alloc(); + vk::DescriptorSet perPolyDescSet; + auto it = perPolyDescSets.find(&mvParam); + if (it == perPolyDescSets.end()) + { + perPolyDescSet = perPolyAlloc.alloc(); - const vk::DeviceSize uniformAlignment = VulkanContext::Instance()->GetUniformBufferAlignment(); - size_t size = sizeof(N2VertexShaderUniforms) + align(sizeof(N2VertexShaderUniforms), uniformAlignment); - vk::DescriptorBufferInfo uniBufferInfo{ buffer, uniformOffset + polyNumber * size, sizeof(N2VertexShaderUniforms) }; - vk::WriteDescriptorSet writeDescriptorSet(perPolyDescSet, 2, 0, 1, vk::DescriptorType::eUniformBuffer, nullptr, &uniBufferInfo, nullptr); - - getContext()->GetDevice().updateDescriptorSets(1, &writeDescriptorSet, 0, nullptr); + const vk::DeviceSize uniformAlignment = VulkanContext::Instance()->GetUniformBufferAlignment(); + size_t size = sizeof(N2VertexShaderUniforms) + align(sizeof(N2VertexShaderUniforms), uniformAlignment); + vk::DescriptorBufferInfo uniBufferInfo{ buffer, uniformOffset + polyNumber * size, sizeof(N2VertexShaderUniforms) }; + vk::WriteDescriptorSet writeDescriptorSet(perPolyDescSet, 2, 0, 1, vk::DescriptorType::eUniformBuffer, nullptr, &uniBufferInfo, nullptr); + getContext()->GetDevice().updateDescriptorSets(1, &writeDescriptorSet, 0, nullptr); + perPolyDescSets[&mvParam] = perPolyDescSet; + } + else + perPolyDescSet = it->second; cmdBuffer.bindDescriptorSets(vk::PipelineBindPoint::eGraphics, pipelineLayout, 1, 1, &perPolyDescSet, 0, nullptr); } @@ -133,11 +149,12 @@ public: cmdBuffer.bindDescriptorSets(vk::PipelineBindPoint::eGraphics, pipelineLayout, 0, 1, &perFrameDescSet, 0, nullptr); } - void reset() + void nextFrame() { perFrameAlloc.nextFrame(); perPolyAlloc.nextFrame(); perFrameDescSet = vk::DescriptorSet{}; + perPolyDescSets.clear(); } void term() @@ -153,6 +170,7 @@ private: DynamicDescSetAlloc perFrameAlloc; DynamicDescSetAlloc perPolyAlloc; vk::DescriptorSet perFrameDescSet = {}; + std::unordered_map perPolyDescSets; SamplerManager* samplerManager = nullptr; };