diff --git a/Common/GPU/Vulkan/VulkanQueueRunner.cpp b/Common/GPU/Vulkan/VulkanQueueRunner.cpp index 1ce5f05ea5..c38a2bd6d9 100644 --- a/Common/GPU/Vulkan/VulkanQueueRunner.cpp +++ b/Common/GPU/Vulkan/VulkanQueueRunner.cpp @@ -1241,7 +1241,7 @@ void VulkanQueueRunner::PerformRenderPass(const VKRStep &step, VkCommandBuffer c if (pipeline != VK_NULL_HANDLE) { vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline); - pipelineLayout = c.pipeline.pipelineLayout; + pipelineLayout = c.pipeline.pipelineLayout->pipelineLayout; lastGraphicsPipeline = graphicsPipeline; pipelineOK = true; } else { @@ -1263,7 +1263,7 @@ void VulkanQueueRunner::PerformRenderPass(const VKRStep &step, VkCommandBuffer c VkPipeline pipeline = computePipeline->pipeline->BlockUntilReady(); if (pipeline != VK_NULL_HANDLE) { vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_COMPUTE, pipeline); - pipelineLayout = c.pipeline.pipelineLayout; + pipelineLayout = c.pipeline.pipelineLayout->pipelineLayout; lastComputePipeline = computePipeline; } } diff --git a/Common/GPU/Vulkan/VulkanQueueRunner.h b/Common/GPU/Vulkan/VulkanQueueRunner.h index 7b0d3bf0ed..4ce030e370 100644 --- a/Common/GPU/Vulkan/VulkanQueueRunner.h +++ b/Common/GPU/Vulkan/VulkanQueueRunner.h @@ -19,6 +19,7 @@ class VKRFramebuffer; struct VKRGraphicsPipeline; struct VKRComputePipeline; struct VKRImage; +struct VKRPipelineLayout; struct FrameData; enum { @@ -58,15 +59,15 @@ struct VkRenderData { union { struct { VkPipeline pipeline; - VkPipelineLayout pipelineLayout; + VKRPipelineLayout *pipelineLayout; } pipeline; struct { VKRGraphicsPipeline *pipeline; - VkPipelineLayout pipelineLayout; + VKRPipelineLayout *pipelineLayout; } graphics_pipeline; struct { VKRComputePipeline *pipeline; - VkPipelineLayout pipelineLayout; + VKRPipelineLayout *pipelineLayout; } compute_pipeline; struct { VkDescriptorSet ds; diff --git a/Common/GPU/Vulkan/VulkanRenderManager.cpp b/Common/GPU/Vulkan/VulkanRenderManager.cpp index 4414af64f9..ecd4765f96 100644 --- a/Common/GPU/Vulkan/VulkanRenderManager.cpp +++ b/Common/GPU/Vulkan/VulkanRenderManager.cpp @@ -116,7 +116,7 @@ bool VKRGraphicsPipeline::Create(VulkanContext *vulkan, VkRenderPass compatibleR pipe.pDynamicState = &desc->ds; pipe.pInputAssemblyState = &inputAssembly; pipe.pMultisampleState = &ms; - pipe.layout = desc->pipelineLayout; + pipe.layout = desc->pipelineLayout->pipelineLayout; pipe.basePipelineHandle = VK_NULL_HANDLE; pipe.basePipelineIndex = 0; pipe.subpass = 0; @@ -192,7 +192,7 @@ void VKRGraphicsPipeline::DestroyVariantsInstant(VkDevice device) { VKRGraphicsPipeline::~VKRGraphicsPipeline() { // This is called from the callbacked queued in QueueForDeletion. - // Here we are free to directly delete stuff, don't need to queue. + // When we reach here, we should already be empty, so let's assert on that. for (size_t i = 0; i < (size_t)RenderPassType::TYPE_COUNT; i++) { _assert_(!pipeline[i]); } diff --git a/Common/GPU/Vulkan/VulkanRenderManager.h b/Common/GPU/Vulkan/VulkanRenderManager.h index 53a213e68f..e86b5ef97c 100644 --- a/Common/GPU/Vulkan/VulkanRenderManager.h +++ b/Common/GPU/Vulkan/VulkanRenderManager.h @@ -106,7 +106,7 @@ public: VkPipelineVertexInputStateCreateInfo vis{ VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO }; VkPipelineViewportStateCreateInfo views{ VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO }; - VkPipelineLayout pipelineLayout = VK_NULL_HANDLE; + VKRPipelineLayout *pipelineLayout = nullptr; // Does not include the render pass type, it's passed in separately since the // desc is persistent. @@ -168,6 +168,21 @@ struct VKRComputePipeline { } }; +struct VKRPipelineLayout { + ~VKRPipelineLayout() { + _assert_(!pipelineLayout && !descriptorSetLayout); + } + + void Destroy(VulkanContext *vulkan) { + vulkan->Delete().QueueDeletePipelineLayout(pipelineLayout); + vulkan->Delete().QueueDeleteDescriptorSetLayout(descriptorSetLayout); + } + + VkPipelineLayout pipelineLayout; + VkDescriptorSetLayout descriptorSetLayout; // only support 1 for now. + int pushConstSize; +}; + struct CompileQueueEntry { CompileQueueEntry(VKRGraphicsPipeline *p, VkRenderPass _compatibleRenderPass, RenderPassType _renderPassType, VkSampleCountFlagBits _sampleCount) : type(Type::GRAPHICS), graphics(p), compatibleRenderPass(_compatibleRenderPass), renderPassType(_renderPassType), sampleCount(_sampleCount) {} @@ -237,6 +252,13 @@ public: // 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, PipelineFlags pipelineFlags, uint32_t variantBitmask, VkSampleCountFlagBits sampleCount, bool cacheLoad, const char *tag); VKRComputePipeline *CreateComputePipeline(VKRComputePipelineDesc *desc); + + VKRPipelineLayout *CreatePipelineLayout(VkPipelineLayout pipelineLayout, VkDescriptorSetLayout descSetLayout) { + VKRPipelineLayout *layout = new VKRPipelineLayout(); + layout->pipelineLayout = pipelineLayout; + layout->descriptorSetLayout = descSetLayout; + return layout; + } void ReportBadStateForDraw(); @@ -249,7 +271,7 @@ public: // This is the first call in a draw operation. Instead of asserting like we used to, you can now check the // return value and skip the draw if we're in a bad state. In that case, call ReportBadState. // The old assert wasn't very helpful in figuring out what caused it anyway... - bool BindPipeline(VKRGraphicsPipeline *pipeline, PipelineFlags flags, VkPipelineLayout pipelineLayout) { + bool BindPipeline(VKRGraphicsPipeline *pipeline, PipelineFlags flags, VKRPipelineLayout *pipelineLayout) { _dbg_assert_(curRenderStep_ && curRenderStep_->stepType == VKRStepType::RENDER && pipeline != nullptr); if (!curRenderStep_ || curRenderStep_->stepType != VKRStepType::RENDER) { return false; @@ -267,7 +289,7 @@ public: return true; } - void BindPipeline(VKRComputePipeline *pipeline, PipelineFlags flags, VkPipelineLayout pipelineLayout) { + void BindPipeline(VKRComputePipeline *pipeline, PipelineFlags flags, VKRPipelineLayout *pipelineLayout) { _dbg_assert_(curRenderStep_ && curRenderStep_->stepType == VKRStepType::RENDER); _dbg_assert_(pipeline != nullptr); VkRenderData &data = curRenderStep_->commands.push_uninitialized(); diff --git a/Common/GPU/Vulkan/thin3d_vulkan.cpp b/Common/GPU/Vulkan/thin3d_vulkan.cpp index a4cdeedf8d..ad2ebecb69 100644 --- a/Common/GPU/Vulkan/thin3d_vulkan.cpp +++ b/Common/GPU/Vulkan/thin3d_vulkan.cpp @@ -546,8 +546,7 @@ private: AutoRef curIBuffer_; int curIBufferOffset_ = 0; - VkDescriptorSetLayout descriptorSetLayout_ = VK_NULL_HANDLE; - VkPipelineLayout pipelineLayout_ = VK_NULL_HANDLE; + VKRPipelineLayout *pipelineLayout_ = nullptr; VkPipelineCache pipelineCache_ = VK_NULL_HANDLE; AutoRef curFramebuffer_; @@ -1077,24 +1076,28 @@ VKContext::VKContext(VulkanContext *vulkan, bool useRenderThread) bindings[i + 1].binding = i + 1; } + VkDescriptorSetLayout descSetLayout; VkDescriptorSetLayoutCreateInfo dsl = { VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO }; dsl.bindingCount = ARRAY_SIZE(bindings); dsl.pBindings = bindings; - VkResult res = vkCreateDescriptorSetLayout(device_, &dsl, nullptr, &descriptorSetLayout_); + VkResult res = vkCreateDescriptorSetLayout(device_, &dsl, nullptr, &descSetLayout); _assert_(VK_SUCCESS == res); - vulkan_->SetDebugName(descriptorSetLayout_, VK_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT, "thin3d_d_layout"); + vulkan_->SetDebugName(descSetLayout, VK_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT, "thin3d_d_layout"); + VkPipelineLayout pipelineLayout; VkPipelineLayoutCreateInfo pl = { VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO }; pl.pPushConstantRanges = nullptr; pl.pushConstantRangeCount = 0; - VkDescriptorSetLayout setLayouts[1] = { descriptorSetLayout_ }; + VkDescriptorSetLayout setLayouts[1] = { descSetLayout }; pl.setLayoutCount = ARRAY_SIZE(setLayouts); pl.pSetLayouts = setLayouts; - res = vkCreatePipelineLayout(device_, &pl, nullptr, &pipelineLayout_); + res = vkCreatePipelineLayout(device_, &pl, nullptr, &pipelineLayout); _assert_(VK_SUCCESS == res); - vulkan_->SetDebugName(pipelineLayout_, VK_OBJECT_TYPE_PIPELINE_LAYOUT, "thin3d_p_layout"); + vulkan_->SetDebugName(pipelineLayout, VK_OBJECT_TYPE_PIPELINE_LAYOUT, "thin3d_p_layout"); + + pipelineLayout_ = renderManager_.CreatePipelineLayout(pipelineLayout, descSetLayout); VkPipelineCacheCreateInfo pc{ VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO }; res = vkCreatePipelineCache(vulkan_->GetDevice(), &pc, nullptr, &pipelineCache_); @@ -1111,8 +1114,7 @@ VKContext::~VKContext() { } push_->Destroy(); delete push_; - vulkan_->Delete().QueueDeleteDescriptorSetLayout(descriptorSetLayout_); - vulkan_->Delete().QueueDeletePipelineLayout(pipelineLayout_); + pipelineLayout_->Destroy(vulkan_); vulkan_->Delete().QueueDeletePipelineCache(pipelineCache_); } @@ -1181,7 +1183,7 @@ VkDescriptorSet VKContext::GetOrCreateDescriptorSet(VkBuffer buf) { return iter->second; } - VkDescriptorSet descSet = frame->descriptorPool.Allocate(1, &descriptorSetLayout_, "thin3d_descset"); + VkDescriptorSet descSet = frame->descriptorPool.Allocate(1, &pipelineLayout_->descriptorSetLayout, "thin3d_descset"); if (descSet == VK_NULL_HANDLE) { ERROR_LOG(G3D, "GetOrCreateDescriptorSet failed"); return VK_NULL_HANDLE; diff --git a/GPU/Vulkan/DrawEngineVulkan.cpp b/GPU/Vulkan/DrawEngineVulkan.cpp index 1f9a1f26dc..f8407b743c 100644 --- a/GPU/Vulkan/DrawEngineVulkan.cpp +++ b/GPU/Vulkan/DrawEngineVulkan.cpp @@ -127,12 +127,13 @@ void DrawEngineVulkan::InitDeviceObjects() { VulkanContext *vulkan = (VulkanContext *)draw_->GetNativeObject(Draw::NativeObject::CONTEXT); VkDevice device = vulkan->GetDevice(); + VkDescriptorSetLayout descriptorSetLayout; VkDescriptorSetLayoutCreateInfo dsl{ VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO }; dsl.bindingCount = ARRAY_SIZE(bindings); dsl.pBindings = bindings; - VkResult res = vkCreateDescriptorSetLayout(device, &dsl, nullptr, &descriptorSetLayout_); + VkResult res = vkCreateDescriptorSetLayout(device, &dsl, nullptr, &descriptorSetLayout); _dbg_assert_(VK_SUCCESS == res); - vulkan->SetDebugName(descriptorSetLayout_, VK_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT, "drawengine_d_layout"); + vulkan->SetDebugName(descriptorSetLayout, VK_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT, "drawengine_d_layout"); static constexpr int DEFAULT_DESC_POOL_SIZE = 512; std::vector dpTypes; @@ -168,15 +169,20 @@ void DrawEngineVulkan::InitDeviceObjects() { VkPipelineLayoutCreateInfo pl{ VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO }; pl.pPushConstantRanges = nullptr; pl.pushConstantRangeCount = 0; - VkDescriptorSetLayout layouts[1] = { descriptorSetLayout_}; + VkDescriptorSetLayout layouts[1] = { descriptorSetLayout }; pl.setLayoutCount = ARRAY_SIZE(layouts); pl.pSetLayouts = layouts; pl.flags = 0; - res = vkCreatePipelineLayout(device, &pl, nullptr, &pipelineLayout_); + VkPipelineLayout pipelineLayout; + res = vkCreatePipelineLayout(device, &pl, nullptr, &pipelineLayout); _dbg_assert_(VK_SUCCESS == res); - vulkan->SetDebugName(pipelineLayout_, VK_OBJECT_TYPE_PIPELINE_LAYOUT, "drawengine_p_layout"); + vulkan->SetDebugName(pipelineLayout, VK_OBJECT_TYPE_PIPELINE_LAYOUT, "drawengine_p_layout"); + + VulkanRenderManager *renderManager = (VulkanRenderManager *)draw_->GetNativeObject(Draw::NativeObject::RENDER_MANAGER); + + pipelineLayout_ = renderManager->CreatePipelineLayout(pipelineLayout, descriptorSetLayout); VkSamplerCreateInfo samp{ VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO }; samp.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; @@ -193,6 +199,7 @@ void DrawEngineVulkan::InitDeviceObjects() { res = vkCreateSampler(device, &samp, nullptr, &nullSampler_); _dbg_assert_(VK_SUCCESS == res); + vertexCache_ = new VulkanPushBuffer(vulkan, "pushVertexCache", VERTEX_CACHE_SIZE, VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT); tessDataTransferVulkan = new TessellationDataTransferVulkan(vulkan); @@ -246,10 +253,7 @@ void DrawEngineVulkan::DestroyDeviceObjects() { vulkan->Delete().QueueDeleteSampler(samplerSecondaryLinear_); if (nullSampler_ != VK_NULL_HANDLE) vulkan->Delete().QueueDeleteSampler(nullSampler_); - if (pipelineLayout_ != VK_NULL_HANDLE) - vulkan->Delete().QueueDeletePipelineLayout(pipelineLayout_); - if (descriptorSetLayout_ != VK_NULL_HANDLE) - vulkan->Delete().QueueDeleteDescriptorSetLayout(descriptorSetLayout_); + pipelineLayout_->Destroy(vulkan); if (vertexCache_) { vertexCache_->Destroy(vulkan); delete vertexCache_; @@ -391,7 +395,7 @@ VkDescriptorSet DrawEngineVulkan::GetOrCreateDescriptorSet(VkImageView imageView // Didn't find one in the frame descriptor set cache, let's make a new one. // We wipe the cache on every frame. - VkDescriptorSet desc = frame.descPool.Allocate(1, &descriptorSetLayout_, "game_descset"); + VkDescriptorSet desc = frame.descPool.Allocate(1, &pipelineLayout_->descriptorSetLayout, "game_descset"); // Even in release mode, this is bad. _assert_msg_(desc != VK_NULL_HANDLE, "Ran out of descriptor space in pool. sz=%d", (int)frame.descSets.size()); diff --git a/GPU/Vulkan/DrawEngineVulkan.h b/GPU/Vulkan/DrawEngineVulkan.h index e98489c7a5..7e8bbf5e10 100644 --- a/GPU/Vulkan/DrawEngineVulkan.h +++ b/GPU/Vulkan/DrawEngineVulkan.h @@ -189,7 +189,7 @@ public: DoFlush(); } - VkPipelineLayout GetPipelineLayout() const { + VKRPipelineLayout *GetPipelineLayout() const { return pipelineLayout_; } @@ -244,10 +244,7 @@ private: Draw::DrawContext *draw_; // We use a shared descriptor set layouts for all PSP draws. - // Descriptors created from descriptorSetLayout_ is rebound all the time at set 1. - VkDescriptorSetLayout descriptorSetLayout_; - - VkPipelineLayout pipelineLayout_; + VKRPipelineLayout *pipelineLayout_; VulkanPipeline *lastPipeline_; VkDescriptorSet lastDs_ = VK_NULL_HANDLE; diff --git a/GPU/Vulkan/PipelineManagerVulkan.cpp b/GPU/Vulkan/PipelineManagerVulkan.cpp index 75d2805903..b899c4e4d0 100644 --- a/GPU/Vulkan/PipelineManagerVulkan.cpp +++ b/GPU/Vulkan/PipelineManagerVulkan.cpp @@ -187,7 +187,7 @@ static std::string CutFromMain(std::string str) { } static VulkanPipeline *CreateVulkanPipeline(VulkanRenderManager *renderManager, VkPipelineCache pipelineCache, - VkPipelineLayout layout, PipelineFlags pipelineFlags, VkSampleCountFlagBits sampleCount, const VulkanPipelineRasterStateKey &key, + VKRPipelineLayout *layout, PipelineFlags pipelineFlags, VkSampleCountFlagBits sampleCount, const VulkanPipelineRasterStateKey &key, const DecVtxFormat *decFmt, VulkanVertexShader *vs, VulkanFragmentShader *fs, VulkanGeometryShader *gs, bool useHwTransform, u32 variantBitmask, bool cacheLoad) { _assert_(fs && vs); @@ -351,7 +351,7 @@ static VulkanPipeline *CreateVulkanPipeline(VulkanRenderManager *renderManager, return vulkanPipeline; } -VulkanPipeline *PipelineManagerVulkan::GetOrCreatePipeline(VulkanRenderManager *renderManager, VkPipelineLayout layout, const VulkanPipelineRasterStateKey &rasterKey, const DecVtxFormat *decFmt, VulkanVertexShader *vs, VulkanFragmentShader *fs, VulkanGeometryShader *gs, bool useHwTransform, u32 variantBitmask, int multiSampleLevel, bool cacheLoad) { +VulkanPipeline *PipelineManagerVulkan::GetOrCreatePipeline(VulkanRenderManager *renderManager, VKRPipelineLayout *layout, const VulkanPipelineRasterStateKey &rasterKey, const DecVtxFormat *decFmt, VulkanVertexShader *vs, VulkanFragmentShader *fs, VulkanGeometryShader *gs, bool useHwTransform, u32 variantBitmask, int multiSampleLevel, bool cacheLoad) { if (!pipelineCache_) { VkPipelineCacheCreateInfo pc{ VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO }; VkResult res = vkCreatePipelineCache(vulkan_->GetDevice(), &pc, nullptr, &pipelineCache_); @@ -717,7 +717,7 @@ void PipelineManagerVulkan::SavePipelineCache(FILE *file, bool saveRawPipelineCa } } -bool PipelineManagerVulkan::LoadPipelineCache(FILE *file, bool loadRawPipelineCache, ShaderManagerVulkan *shaderManager, Draw::DrawContext *drawContext, VkPipelineLayout layout, int multiSampleLevel) { +bool PipelineManagerVulkan::LoadPipelineCache(FILE *file, bool loadRawPipelineCache, ShaderManagerVulkan *shaderManager, Draw::DrawContext *drawContext, VKRPipelineLayout *layout, int multiSampleLevel) { VulkanRenderManager *rm = (VulkanRenderManager *)drawContext->GetNativeObject(Draw::NativeObject::RENDER_MANAGER); VulkanQueueRunner *queueRunner = rm->GetQueueRunner(); diff --git a/GPU/Vulkan/PipelineManagerVulkan.h b/GPU/Vulkan/PipelineManagerVulkan.h index b61a3faa10..cd9311af50 100644 --- a/GPU/Vulkan/PipelineManagerVulkan.h +++ b/GPU/Vulkan/PipelineManagerVulkan.h @@ -85,7 +85,7 @@ public: ~PipelineManagerVulkan(); // variantMask is only used when loading pipelines from cache. - VulkanPipeline *GetOrCreatePipeline(VulkanRenderManager *renderManager, VkPipelineLayout layout, const VulkanPipelineRasterStateKey &rasterKey, const DecVtxFormat *decFmt, VulkanVertexShader *vs, VulkanFragmentShader *fs, VulkanGeometryShader *gs, bool useHwTransform, u32 variantMask, int multiSampleLevel, bool cacheLoad); + VulkanPipeline *GetOrCreatePipeline(VulkanRenderManager *renderManager, VKRPipelineLayout *layout, const VulkanPipelineRasterStateKey &rasterKey, const DecVtxFormat *decFmt, VulkanVertexShader *vs, VulkanFragmentShader *fs, VulkanGeometryShader *gs, bool useHwTransform, u32 variantMask, int multiSampleLevel, bool cacheLoad); int GetNumPipelines() const { return (int)pipelines_.size(); } void Clear(); @@ -100,7 +100,7 @@ public: // Saves data for faster creation next time. void SavePipelineCache(FILE *file, bool saveRawPipelineCache, ShaderManagerVulkan *shaderManager, Draw::DrawContext *drawContext); - bool LoadPipelineCache(FILE *file, bool loadRawPipelineCache, ShaderManagerVulkan *shaderManager, Draw::DrawContext *drawContext, VkPipelineLayout layout, int multiSampleLevel); + bool LoadPipelineCache(FILE *file, bool loadRawPipelineCache, ShaderManagerVulkan *shaderManager, Draw::DrawContext *drawContext, VKRPipelineLayout *layout, int multiSampleLevel); private: DenseHashMap pipelines_;