diff --git a/Common/Data/Collections/Hashmaps.h b/Common/Data/Collections/Hashmaps.h index d7de958c1b..8368c83db5 100644 --- a/Common/Data/Collections/Hashmaps.h +++ b/Common/Data/Collections/Hashmaps.h @@ -136,6 +136,7 @@ public: } } + // Note! Does NOT delete any pointed-to data (in case you stored pointers in the map). void Clear() { memset(state.data(), (int)BucketState::FREE, state.size()); count_ = 0; diff --git a/Common/GPU/Vulkan/VulkanRenderManager.cpp b/Common/GPU/Vulkan/VulkanRenderManager.cpp index 21a444f894..3a808656db 100644 --- a/Common/GPU/Vulkan/VulkanRenderManager.cpp +++ b/Common/GPU/Vulkan/VulkanRenderManager.cpp @@ -96,9 +96,14 @@ bool VKRGraphicsPipeline::Create(VulkanContext *vulkan, VkRenderPass compatibleR ERROR_LOG(G3D, "Failed creating graphics pipeline! result='%s'", VulkanResultToString(result)); success = false; } else { + // Success! + if (!tag.empty()) { + vulkan->SetDebugName(vkpipeline, VK_OBJECT_TYPE_PIPELINE, tag.c_str()); + } pipeline[rpType]->Post(vkpipeline); } + // Having the desc stick around can be useful for debugging. #ifndef _DEBUG delete desc; @@ -107,6 +112,29 @@ bool VKRGraphicsPipeline::Create(VulkanContext *vulkan, VkRenderPass compatibleR return success; } +void VKRGraphicsPipeline::QueueForDeletion(VulkanContext *vulkan) { + for (int i = 0; i < RP_TYPE_COUNT; i++) { + if (!pipeline[i]) + continue; + VkPipeline pipeline = this->pipeline[i]->BlockUntilReady(); + vulkan->Delete().QueueDeletePipeline(pipeline); + vulkan->Delete().QueueCallback([](void *p) { + VKRGraphicsPipeline *pipeline = (VKRGraphicsPipeline *)p; + delete pipeline; + }, this); + } +} + +u32 VKRGraphicsPipeline::GetVariantsBitmask() const { + u32 bitmask = 0; + for (int i = 0; i < RP_TYPE_COUNT; i++) { + if (pipeline[i]) { + bitmask |= 1 << i; + } + } + return bitmask; +} + bool VKRComputePipeline::Create(VulkanContext *vulkan) { if (!desc) { // Already failed to create this one. @@ -693,11 +721,12 @@ VkCommandBuffer VulkanRenderManager::GetInitCmd() { return frameData_[curFrame].initCmd; } -VKRGraphicsPipeline *VulkanRenderManager::CreateGraphicsPipeline(VKRGraphicsPipelineDesc *desc, uint32_t variantBitmask) { +VKRGraphicsPipeline *VulkanRenderManager::CreateGraphicsPipeline(VKRGraphicsPipelineDesc *desc, uint32_t variantBitmask, const char *tag) { VKRGraphicsPipeline *pipeline = new VKRGraphicsPipeline(); _dbg_assert_(desc->vertexShader); _dbg_assert_(desc->fragmentShader); pipeline->desc = desc; + pipeline->tag = tag; if (curRenderStep_) { // The common case pipelinesToCheck_.push_back(pipeline); diff --git a/Common/GPU/Vulkan/VulkanRenderManager.h b/Common/GPU/Vulkan/VulkanRenderManager.h index 24a3fca123..dc4bad101f 100644 --- a/Common/GPU/Vulkan/VulkanRenderManager.h +++ b/Common/GPU/Vulkan/VulkanRenderManager.h @@ -155,31 +155,20 @@ struct VKRComputePipelineDesc { VkComputePipelineCreateInfo pipe{ VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO }; }; -// Wrapped pipeline. +// Wrapped pipeline. Doesn't own desc. struct VKRGraphicsPipeline { - VKRGraphicsPipeline() { - for (int i = 0; i < RP_TYPE_COUNT; i++) { - pipeline[i] = nullptr; - } - } - ~VKRGraphicsPipeline() { - delete desc; - } - - u32 GetVariantsBitmask() const { - u32 bitmask = 0; - for (int i = 0; i < RP_TYPE_COUNT; i++) { - if (pipeline[i]) { - bitmask |= 1 << i; - } - } - return bitmask; - } - - VKRGraphicsPipelineDesc *desc = nullptr; - Promise *pipeline[RP_TYPE_COUNT]; + ~VKRGraphicsPipeline() {} bool Create(VulkanContext *vulkan, VkRenderPass compatibleRenderPass, RenderPassType rpType); + + // This deletes the whole VKRGraphicsPipeline, you must remove your last pointer to it when doing this. + void QueueForDeletion(VulkanContext *vulkan); + + u32 GetVariantsBitmask() const; + + VKRGraphicsPipelineDesc *desc = nullptr; + Promise *pipeline[RP_TYPE_COUNT]{}; + std::string tag; }; struct VKRComputePipeline { @@ -260,7 +249,7 @@ public: // We delay creating pipelines until the end of the current render pass, so we can create the right type immediately. // Unless a variantBitmask is passed in, in which case we can just go ahead. // WARNING: desc must stick around during the lifetime of the pipeline! It's not enough to build it on the stack and drop it. - VKRGraphicsPipeline *CreateGraphicsPipeline(VKRGraphicsPipelineDesc *desc, uint32_t variantBitmask); + VKRGraphicsPipeline *CreateGraphicsPipeline(VKRGraphicsPipelineDesc *desc, uint32_t variantBitmask, const char *tag); VKRComputePipeline *CreateComputePipeline(VKRComputePipelineDesc *desc); void NudgeCompilerThread() { diff --git a/Common/GPU/Vulkan/thin3d_vulkan.cpp b/Common/GPU/Vulkan/thin3d_vulkan.cpp index d456aadcfb..eb847df025 100644 --- a/Common/GPU/Vulkan/thin3d_vulkan.cpp +++ b/Common/GPU/Vulkan/thin3d_vulkan.cpp @@ -249,12 +249,14 @@ public: class VKPipeline : public Pipeline { public: - VKPipeline(VulkanRenderManager *rm, size_t size, PipelineFlags _flags) : rm_(rm), flags(_flags) { + VKPipeline(VulkanContext *vulkan, size_t size, PipelineFlags _flags) : vulkan_(vulkan), flags(_flags) { uboSize_ = (int)size; ubo_ = new uint8_t[uboSize_]; } ~VKPipeline() { - // TODO: Right now we just leak the pipeline! This is not good. + if (pipeline) { + pipeline->QueueForDeletion(vulkan_); + } delete[] ubo_; } @@ -282,7 +284,7 @@ public: bool usesStencil = false; private: - VulkanRenderManager *rm_; + VulkanContext *vulkan_; uint8_t *ubo_; int uboSize_; }; @@ -1040,7 +1042,7 @@ Pipeline *VKContext::CreateGraphicsPipeline(const PipelineDesc &desc) { pipelineFlags |= PIPELINE_FLAG_USES_DEPTH_STENCIL; } - VKPipeline *pipeline = new VKPipeline(&renderManager_, desc.uniformDesc ? desc.uniformDesc->uniformBufferSize : 16 * sizeof(float), (PipelineFlags)pipelineFlags); + VKPipeline *pipeline = new VKPipeline(vulkan_, desc.uniformDesc ? desc.uniformDesc->uniformBufferSize : 16 * sizeof(float), (PipelineFlags)pipelineFlags); VKRGraphicsPipelineDesc &gDesc = pipeline->vkrDesc; @@ -1110,7 +1112,7 @@ Pipeline *VKContext::CreateGraphicsPipeline(const PipelineDesc &desc) { VkPipelineRasterizationStateCreateInfo rs{ VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO }; raster->ToVulkan(&gDesc.rs); - pipeline->pipeline = renderManager_.CreateGraphicsPipeline(&gDesc, 1 << RP_TYPE_BACKBUFFER); + pipeline->pipeline = renderManager_.CreateGraphicsPipeline(&gDesc, 1 << RP_TYPE_BACKBUFFER, "thin3d"); if (desc.uniformDesc) { pipeline->dynamicUniformSize = (int)desc.uniformDesc->uniformBufferSize; diff --git a/GPU/Vulkan/PipelineManagerVulkan.cpp b/GPU/Vulkan/PipelineManagerVulkan.cpp index 76423fae84..9279fca6d4 100644 --- a/GPU/Vulkan/PipelineManagerVulkan.cpp +++ b/GPU/Vulkan/PipelineManagerVulkan.cpp @@ -35,21 +35,12 @@ PipelineManagerVulkan::~PipelineManagerVulkan() { void PipelineManagerVulkan::Clear() { pipelines_.Iterate([&](const VulkanPipelineKey &key, VulkanPipeline *value) { - for (int i = 0; i < RP_TYPE_COUNT; i++) { - if (value->pipeline) { - if (value->pipeline->pipeline[i]) { - VkPipeline pipeline = value->pipeline->pipeline[i]->BlockUntilReady(); - vulkan_->Delete().QueueDeletePipeline(pipeline); - vulkan_->Delete().QueueCallback([](void *p) { - VKRGraphicsPipeline *pipeline = (VKRGraphicsPipeline *)p; - delete pipeline; - }, value->pipeline); - } - } else { - // Something went wrong. - ERROR_LOG(G3D, "Null pipeline found in PipelineManagerVulkan::Clear - didn't wait for asyncs?"); - } + if (!value->pipeline) { + // Something went wrong. + ERROR_LOG(G3D, "Null pipeline found in PipelineManagerVulkan::Clear - didn't wait for asyncs?"); + delete value; } + value->pipeline->QueueForDeletion(vulkan_); delete value; }); @@ -181,7 +172,8 @@ static std::string CutFromMain(std::string str) { static VulkanPipeline *CreateVulkanPipeline(VulkanRenderManager *renderManager, VkPipelineCache pipelineCache, VkPipelineLayout layout, const VulkanPipelineRasterStateKey &key, const DecVtxFormat *decFmt, VulkanVertexShader *vs, VulkanFragmentShader *fs, bool useHwTransform, u32 variantBitmask) { - VKRGraphicsPipelineDesc *desc = new VKRGraphicsPipelineDesc(); + VulkanPipeline *vulkanPipeline = new VulkanPipeline(); + VKRGraphicsPipelineDesc *desc = &vulkanPipeline->desc; desc->pipelineCache = pipelineCache; PROFILE_THIS_SCOPE("pipelinebuild"); @@ -304,9 +296,8 @@ static VulkanPipeline *CreateVulkanPipeline(VulkanRenderManager *renderManager, desc->pipelineLayout = layout; - VKRGraphicsPipeline *pipeline = renderManager->CreateGraphicsPipeline(desc, variantBitmask); + VKRGraphicsPipeline *pipeline = renderManager->CreateGraphicsPipeline(desc, variantBitmask, "game"); - VulkanPipeline *vulkanPipeline = new VulkanPipeline(); vulkanPipeline->pipeline = pipeline; vulkanPipeline->flags = 0; if (useBlendConstant) diff --git a/GPU/Vulkan/PipelineManagerVulkan.h b/GPU/Vulkan/PipelineManagerVulkan.h index da4a59af62..af32aa81bd 100644 --- a/GPU/Vulkan/PipelineManagerVulkan.h +++ b/GPU/Vulkan/PipelineManagerVulkan.h @@ -28,6 +28,7 @@ #include "GPU/Vulkan/VulkanUtil.h" #include "GPU/Vulkan/StateMappingVulkan.h" #include "GPU/Vulkan/VulkanQueueRunner.h" +#include "GPU/Vulkan/VulkanRenderManager.h" struct VKRGraphicsPipeline; class VulkanRenderManager; @@ -53,6 +54,7 @@ struct VulkanPipelineKey { // Simply wraps a Vulkan pipeline, providing some metadata. struct VulkanPipeline { VKRGraphicsPipeline *pipeline; + VKRGraphicsPipelineDesc desc; int flags; // PipelineFlags enum above. bool UsesBlendConstant() const { return (flags & PIPELINE_FLAG_USES_BLEND_CONSTANT) != 0; }