diff --git a/Common/GPU/Vulkan/VulkanQueueRunner.cpp b/Common/GPU/Vulkan/VulkanQueueRunner.cpp index 584600e45b..ecc81765db 100644 --- a/Common/GPU/Vulkan/VulkanQueueRunner.cpp +++ b/Common/GPU/Vulkan/VulkanQueueRunner.cpp @@ -841,9 +841,11 @@ void VulkanQueueRunner::LogRenderPass(const VKRStep &pass, bool verbose) { case VKRRenderCommand::REMOVED: INFO_LOG(G3D, " (Removed)"); break; - - case VKRRenderCommand::BIND_PIPELINE: - INFO_LOG(G3D, " BindPipeline(%x)", (int)(intptr_t)cmd.pipeline.pipeline); + case VKRRenderCommand::BIND_GRAPHICS_PIPELINE: + INFO_LOG(G3D, " BindGraphicsPipeline(%x)", (int)(intptr_t)cmd.graphics_pipeline.pipeline); + break; + case VKRRenderCommand::BIND_COMPUTE_PIPELINE: + INFO_LOG(G3D, " BindComputePipeline(%x)", (int)(intptr_t)cmd.compute_pipeline.pipeline); break; case VKRRenderCommand::BLEND: INFO_LOG(G3D, " BlendColor(%08x)", cmd.blendColor.color); @@ -1236,6 +1238,9 @@ void VulkanQueueRunner::PerformRenderPass(const VKRStep &step, VkCommandBuffer c VKRFramebuffer *fb = step.render.framebuffer; + VkPipeline lastGraphicsPipeline = VK_NULL_HANDLE; + VkPipeline lastComputePipeline = VK_NULL_HANDLE; + auto &commands = step.commands; // We can do a little bit of state tracking here to eliminate some calls into the driver. @@ -1251,16 +1256,54 @@ void VulkanQueueRunner::PerformRenderPass(const VKRStep &step, VkCommandBuffer c case VKRRenderCommand::REMOVED: break; + // Still here to support binding of non-async pipelines. case VKRRenderCommand::BIND_PIPELINE: - if (c.pipeline.pipeline != lastPipeline) { - vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, c.pipeline.pipeline); - lastPipeline = c.pipeline.pipeline; + { + VkPipeline pipeline = c.pipeline.pipeline; + if (pipeline != lastGraphicsPipeline) { + vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline); + lastGraphicsPipeline = pipeline; // Reset dynamic state so it gets refreshed with the new pipeline. lastStencilWriteMask = -1; lastStencilCompareMask = -1; lastStencilReference = -1; } break; + } + + case VKRRenderCommand::BIND_GRAPHICS_PIPELINE: + { + VKRGraphicsPipeline *pipeline = c.graphics_pipeline.pipeline; + if (!pipeline->pipeline) { + // Late! Compile it. + if (!pipeline->Create(vulkan_)) + break; + } + if (pipeline->pipeline != lastGraphicsPipeline) { + vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline->pipeline); + lastGraphicsPipeline = pipeline->pipeline; + // Reset dynamic state so it gets refreshed with the new pipeline. + lastStencilWriteMask = -1; + lastStencilCompareMask = -1; + lastStencilReference = -1; + } + break; + } + + case VKRRenderCommand::BIND_COMPUTE_PIPELINE: + { + VKRComputePipeline *pipeline = c.compute_pipeline.pipeline; + if (!pipeline->pipeline) { + // Late! Compile it. + if (!pipeline->Create(vulkan_)) + break; + } + if (pipeline->pipeline != lastComputePipeline) { + vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_COMPUTE, pipeline->pipeline); + lastComputePipeline = pipeline->pipeline; + } + break; + } case VKRRenderCommand::VIEWPORT: if (fb != nullptr) { diff --git a/Common/GPU/Vulkan/VulkanQueueRunner.h b/Common/GPU/Vulkan/VulkanQueueRunner.h index 912a6044d9..f582a3322d 100644 --- a/Common/GPU/Vulkan/VulkanQueueRunner.h +++ b/Common/GPU/Vulkan/VulkanQueueRunner.h @@ -9,6 +9,8 @@ #include "Common/GPU/DataFormat.h" class VKRFramebuffer; +struct VKRGraphicsPipeline; +struct VKRComputePipeline; struct VKRImage; enum { @@ -20,7 +22,9 @@ enum { enum class VKRRenderCommand : uint8_t { REMOVED, - BIND_PIPELINE, + BIND_PIPELINE, // raw pipeline + BIND_GRAPHICS_PIPELINE, // async + BIND_COMPUTE_PIPELINE, // async STENCIL, BLEND, VIEWPORT, @@ -45,6 +49,12 @@ struct VkRenderData { struct { VkPipeline pipeline; } pipeline; + struct { + VKRGraphicsPipeline *pipeline; + } graphics_pipeline; + struct { + VKRComputePipeline *pipeline; + } compute_pipeline; struct { VkPipelineLayout pipelineLayout; VkDescriptorSet ds; diff --git a/Common/GPU/Vulkan/VulkanRenderManager.cpp b/Common/GPU/Vulkan/VulkanRenderManager.cpp index dd80120ade..475feaa2a0 100644 --- a/Common/GPU/Vulkan/VulkanRenderManager.cpp +++ b/Common/GPU/Vulkan/VulkanRenderManager.cpp @@ -22,6 +22,43 @@ using namespace PPSSPP_VK; +bool VKRGraphicsPipeline::Create(VulkanContext *vulkan) { + if (!desc) { + // Already failed to create this one. + return false; + } + VkResult result = vkCreateGraphicsPipelines(vulkan->GetDevice(), desc->pipelineCache, 1, &desc->pipe, nullptr, &pipeline); + delete desc; + desc = nullptr; + if (result == VK_INCOMPLETE) { + // Bad return value seen on Adreno in Burnout :( Try to ignore? + // Create a placeholder to avoid creating over and over if something is broken. + pipeline = VK_NULL_HANDLE; + return true; + } else if (result != VK_SUCCESS) { + pipeline = VK_NULL_HANDLE; + ERROR_LOG(G3D, "Failed creating graphics pipeline! result='%s'", VulkanResultToString(result)); + return false; + } else { + return true; + } +} + +bool VKRComputePipeline::Create(VulkanContext *vulkan) { + if (!desc) { + // Already failed to create this one. + return false; + } + VkResult result = vkCreateComputePipelines(vulkan->GetDevice(), desc->pipelineCache, 1, &desc->pipe, nullptr, &pipeline); + delete desc; + desc = nullptr; + if (result != VK_SUCCESS) { + pipeline = VK_NULL_HANDLE; + return false; + } + return true; +} + VKRFramebuffer::VKRFramebuffer(VulkanContext *vk, VkCommandBuffer initCmd, VkRenderPass renderPass, int _width, int _height, const char *tag) : vulkan_(vk) { width = _width; height = _height; diff --git a/Common/GPU/Vulkan/VulkanRenderManager.h b/Common/GPU/Vulkan/VulkanRenderManager.h index 2c13d155d6..7b7a870233 100644 --- a/Common/GPU/Vulkan/VulkanRenderManager.h +++ b/Common/GPU/Vulkan/VulkanRenderManager.h @@ -109,6 +109,46 @@ struct BoundingRect { } }; +// All the data needed to create a graphics pipeline. +struct VKRGraphicsPipelineDesc { + VkPipelineCache pipelineCache = VK_NULL_HANDLE; + VkPipelineColorBlendStateCreateInfo cbs{ VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO }; + VkPipelineColorBlendAttachmentState blend0{}; + VkPipelineDepthStencilStateCreateInfo dss{ VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO }; + VkDynamicState dynamicStates[6]{}; + VkPipelineDynamicStateCreateInfo ds{ VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO }; + VkPipelineRasterizationStateCreateInfo rs{ VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO }; + VkPipelineMultisampleStateCreateInfo ms{ VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO }; + VkPipelineShaderStageCreateInfo shaderStageInfo[2]{}; + VkPipelineInputAssemblyStateCreateInfo inputAssembly{ VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO }; + VkVertexInputAttributeDescription attrs[8]{}; + VkVertexInputBindingDescription ibd{}; + VkPipelineVertexInputStateCreateInfo vis{ VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO }; + VkPipelineViewportStateCreateInfo views{ VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO }; + VkGraphicsPipelineCreateInfo pipe{ VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO }; +}; + +// All the data needed to create a compute pipeline. +struct VKRComputePipelineDesc { + VkPipelineCache pipelineCache; + VkComputePipelineCreateInfo pipe{ VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO }; +}; + +// Wrapped pipeline, which will later allow for background compilation while emulating the rest of the frame. +struct VKRGraphicsPipeline { + VKRGraphicsPipelineDesc *desc = nullptr; // While non-zero, is pending and pipeline isn't valid. + VkPipeline pipeline = VK_NULL_HANDLE; + + bool Create(VulkanContext *vulkan); +}; + +struct VKRComputePipeline { + VKRComputePipelineDesc *desc = nullptr; + VkPipeline pipeline = VK_NULL_HANDLE; + + bool Create(VulkanContext *vulkan); +}; + class VulkanRenderManager { public: VulkanRenderManager(VulkanContext *vulkan); @@ -152,6 +192,14 @@ public: void CopyFramebuffer(VKRFramebuffer *src, VkRect2D srcRect, VKRFramebuffer *dst, VkOffset2D dstPos, VkImageAspectFlags aspectMask, const char *tag); void BlitFramebuffer(VKRFramebuffer *src, VkRect2D srcRect, VKRFramebuffer *dst, VkRect2D dstRect, VkImageAspectFlags aspectMask, VkFilter filter, const char *tag); + // Deferred creation, like in GL. Unlike GL though, the purpose is to allow background creation and avoiding + // stalling the emulation thread as much as possible. + VKRGraphicsPipeline *CreateGraphicsPipeline(VKRGraphicsPipelineDesc *desc) { + VKRGraphicsPipeline *pipeline = new VKRGraphicsPipeline(); + pipeline->desc = desc; + return pipeline; + } + void BindPipeline(VkPipeline pipeline, PipelineFlags flags) { _dbg_assert_(curRenderStep_ && curRenderStep_->stepType == VKRStepType::RENDER); _dbg_assert_(pipeline != VK_NULL_HANDLE); @@ -161,6 +209,24 @@ public: curRenderStep_->commands.push_back(data); } + void BindPipeline(VKRGraphicsPipeline *pipeline, PipelineFlags flags) { + _dbg_assert_(curRenderStep_ && curRenderStep_->stepType == VKRStepType::RENDER); + _dbg_assert_(pipeline != nullptr); + VkRenderData data{ VKRRenderCommand::BIND_GRAPHICS_PIPELINE }; + data.graphics_pipeline.pipeline = pipeline; + curPipelineFlags_ |= flags; + curRenderStep_->commands.push_back(data); + } + + void BindPipeline(VKRComputePipeline *pipeline, PipelineFlags flags) { + _dbg_assert_(curRenderStep_ && curRenderStep_->stepType == VKRStepType::RENDER); + _dbg_assert_(pipeline != nullptr); + VkRenderData data{ VKRRenderCommand::BIND_COMPUTE_PIPELINE }; + data.compute_pipeline.pipeline = pipeline; + curPipelineFlags_ |= flags; + curRenderStep_->commands.push_back(data); + } + void SetViewport(const VkViewport &vp) { _dbg_assert_(curRenderStep_ && curRenderStep_->stepType == VKRStepType::RENDER); _dbg_assert_((int)vp.width >= 0); diff --git a/GPU/Vulkan/DrawEngineVulkan.cpp b/GPU/Vulkan/DrawEngineVulkan.cpp index 6cc77e2784..56633ffc7b 100644 --- a/GPU/Vulkan/DrawEngineVulkan.cpp +++ b/GPU/Vulkan/DrawEngineVulkan.cpp @@ -826,7 +826,7 @@ void DrawEngineVulkan::DoFlush() { Draw::NativeObject object = framebufferManager_->UseBufferedRendering() ? Draw::NativeObject::FRAMEBUFFER_RENDERPASS : Draw::NativeObject::BACKBUFFER_RENDERPASS; VkRenderPass renderPass = (VkRenderPass)draw_->GetNativeObject(object); - VulkanPipeline *pipeline = pipelineManager_->GetOrCreatePipeline(pipelineLayout_, renderPass, pipelineKey_, &dec_->decFmt, vshader, fshader, true); + VulkanPipeline *pipeline = pipelineManager_->GetOrCreatePipeline(renderManager, pipelineLayout_, renderPass, pipelineKey_, &dec_->decFmt, vshader, fshader, true); if (!pipeline || !pipeline->pipeline) { // Already logged, let's bail out. return; @@ -957,7 +957,7 @@ void DrawEngineVulkan::DoFlush() { } Draw::NativeObject object = framebufferManager_->UseBufferedRendering() ? Draw::NativeObject::FRAMEBUFFER_RENDERPASS : Draw::NativeObject::BACKBUFFER_RENDERPASS; VkRenderPass renderPass = (VkRenderPass)draw_->GetNativeObject(object); - VulkanPipeline *pipeline = pipelineManager_->GetOrCreatePipeline(pipelineLayout_, renderPass, pipelineKey_, &dec_->decFmt, vshader, fshader, false); + VulkanPipeline *pipeline = pipelineManager_->GetOrCreatePipeline(renderManager, pipelineLayout_, renderPass, pipelineKey_, &dec_->decFmt, vshader, fshader, false); if (!pipeline || !pipeline->pipeline) { // Already logged, let's bail out. return; diff --git a/GPU/Vulkan/PipelineManagerVulkan.cpp b/GPU/Vulkan/PipelineManagerVulkan.cpp index 0c333d4bb4..e2723ea028 100644 --- a/GPU/Vulkan/PipelineManagerVulkan.cpp +++ b/GPU/Vulkan/PipelineManagerVulkan.cpp @@ -34,8 +34,10 @@ void PipelineManagerVulkan::Clear() { // store the keys. pipelines_.Iterate([&](const VulkanPipelineKey &key, VulkanPipeline *value) { - if (value->pipeline) - vulkan_->Delete().QueueDeletePipeline(value->pipeline); + if (value->pipeline) { + vulkan_->Delete().QueueDeletePipeline(value->pipeline->pipeline); + delete value->pipeline; + } delete value; }); @@ -163,13 +165,16 @@ static std::string CutFromMain(std::string str) { return rebuilt; } -static VulkanPipeline *CreateVulkanPipeline(VkDevice device, VkPipelineCache pipelineCache, +static VulkanPipeline *CreateVulkanPipeline(VulkanRenderManager *renderManager, VkPipelineCache pipelineCache, VkPipelineLayout layout, VkRenderPass renderPass, const VulkanPipelineRasterStateKey &key, const DecVtxFormat *decFmt, VulkanVertexShader *vs, VulkanFragmentShader *fs, bool useHwTransform) { + VKRGraphicsPipelineDesc *desc = new VKRGraphicsPipelineDesc(); + desc->pipelineCache = pipelineCache; + PROFILE_THIS_SCOPE("pipelinebuild"); bool useBlendConstant = false; - VkPipelineColorBlendAttachmentState blend0{}; + VkPipelineColorBlendAttachmentState &blend0 = desc->blend0; blend0.blendEnable = key.blendEnable; if (key.blendEnable) { blend0.colorBlendOp = (VkBlendOp)key.blendOpColor; @@ -181,7 +186,7 @@ static VulkanPipeline *CreateVulkanPipeline(VkDevice device, VkPipelineCache pip } blend0.colorWriteMask = key.colorWriteMask; - VkPipelineColorBlendStateCreateInfo cbs{ VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO }; + VkPipelineColorBlendStateCreateInfo &cbs = desc->cbs; cbs.flags = 0; cbs.pAttachments = &blend0; cbs.attachmentCount = 1; @@ -191,7 +196,7 @@ static VulkanPipeline *CreateVulkanPipeline(VkDevice device, VkPipelineCache pip else cbs.logicOp = VK_LOGIC_OP_COPY; - VkPipelineDepthStencilStateCreateInfo dss{ VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO }; + VkPipelineDepthStencilStateCreateInfo &dss = desc->dss; dss.depthBoundsTestEnable = false; dss.stencilTestEnable = key.stencilTestEnable; if (key.stencilTestEnable) { @@ -208,7 +213,7 @@ static VulkanPipeline *CreateVulkanPipeline(VkDevice device, VkPipelineCache pip dss.depthWriteEnable = key.depthWriteEnable; } - VkDynamicState dynamicStates[8]{}; + VkDynamicState *dynamicStates = &desc->dynamicStates[0]; int numDyn = 0; if (key.blendEnable && (UsesBlendConstant(key.srcAlpha) || UsesBlendConstant(key.srcColor) || UsesBlendConstant(key.destAlpha) || UsesBlendConstant(key.destColor))) { @@ -223,12 +228,12 @@ static VulkanPipeline *CreateVulkanPipeline(VkDevice device, VkPipelineCache pip dynamicStates[numDyn++] = VK_DYNAMIC_STATE_STENCIL_REFERENCE; } - VkPipelineDynamicStateCreateInfo ds{ VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO }; + VkPipelineDynamicStateCreateInfo &ds = desc->ds; ds.flags = 0; ds.pDynamicStates = dynamicStates; ds.dynamicStateCount = numDyn; - VkPipelineRasterizationStateCreateInfo rs{ VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO }; + VkPipelineRasterizationStateCreateInfo &rs = desc->rs; rs.flags = 0; rs.depthBiasEnable = false; rs.cullMode = key.cullMode; @@ -238,11 +243,11 @@ static VulkanPipeline *CreateVulkanPipeline(VkDevice device, VkPipelineCache pip rs.polygonMode = VK_POLYGON_MODE_FILL; rs.depthClampEnable = key.depthClampEnable; - VkPipelineMultisampleStateCreateInfo ms{ VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO }; + VkPipelineMultisampleStateCreateInfo &ms = desc->ms; ms.pSampleMask = nullptr; ms.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT; - VkPipelineShaderStageCreateInfo ss[2]{}; + VkPipelineShaderStageCreateInfo *ss = &desc->shaderStageInfo[0]; ss[0].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; ss[0].stage = VK_SHADER_STAGE_VERTEX_BIT; ss[0].pSpecializationInfo = nullptr; @@ -265,13 +270,14 @@ static VulkanPipeline *CreateVulkanPipeline(VkDevice device, VkPipelineCache pip return nullPipeline; } - VkPipelineInputAssemblyStateCreateInfo inputAssembly{ VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO }; + VkPipelineInputAssemblyStateCreateInfo &inputAssembly = desc->inputAssembly; inputAssembly.flags = 0; inputAssembly.topology = (VkPrimitiveTopology)key.topology; inputAssembly.primitiveRestartEnable = false; int vertexStride = 0; - VkVertexInputAttributeDescription attrs[8]; + VkVertexInputAttributeDescription *attrs = &desc->attrs[0]; + int attributeCount; if (useHwTransform) { attributeCount = SetupVertexAttribs(attrs, *decFmt); @@ -284,66 +290,49 @@ static VulkanPipeline *CreateVulkanPipeline(VkDevice device, VkPipelineCache pip vertexStride = (int)sizeof(TransformedVertex); } - VkVertexInputBindingDescription ibd{}; + VkVertexInputBindingDescription &ibd = desc->ibd; ibd.binding = 0; ibd.inputRate = VK_VERTEX_INPUT_RATE_VERTEX; ibd.stride = vertexStride; - VkPipelineVertexInputStateCreateInfo vis{ VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO }; + VkPipelineVertexInputStateCreateInfo &vis = desc->vis; vis.flags = 0; vis.vertexBindingDescriptionCount = 1; - vis.pVertexBindingDescriptions = &ibd; + vis.pVertexBindingDescriptions = &desc->ibd; vis.vertexAttributeDescriptionCount = attributeCount; vis.pVertexAttributeDescriptions = attrs; - VkPipelineViewportStateCreateInfo views{ VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO }; + VkPipelineViewportStateCreateInfo &views = desc->views; views.flags = 0; views.viewportCount = 1; views.scissorCount = 1; views.pViewports = nullptr; // dynamic views.pScissors = nullptr; // dynamic - VkGraphicsPipelineCreateInfo pipe{ VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO }; + VkGraphicsPipelineCreateInfo &pipe = desc->pipe; pipe.flags = 0; pipe.stageCount = 2; pipe.pStages = ss; pipe.basePipelineIndex = 0; - pipe.pColorBlendState = &cbs; - pipe.pDepthStencilState = &dss; - pipe.pRasterizationState = &rs; + pipe.pColorBlendState = &desc->cbs; + pipe.pDepthStencilState = &desc->dss; + pipe.pRasterizationState = &desc->rs; // We will use dynamic viewport state. - pipe.pVertexInputState = &vis; - pipe.pViewportState = &views; + pipe.pVertexInputState = &desc->vis; + pipe.pViewportState = &desc->views; pipe.pTessellationState = nullptr; - pipe.pDynamicState = &ds; - pipe.pInputAssemblyState = &inputAssembly; - pipe.pMultisampleState = &ms; + pipe.pDynamicState = &desc->ds; + pipe.pInputAssemblyState = &desc->inputAssembly; + pipe.pMultisampleState = &desc->ms; pipe.layout = layout; pipe.basePipelineHandle = VK_NULL_HANDLE; pipe.basePipelineIndex = 0; pipe.renderPass = renderPass; pipe.subpass = 0; - VkPipeline pipeline; - VkResult result = vkCreateGraphicsPipelines(device, pipelineCache, 1, &pipe, nullptr, &pipeline); - if (result != VK_SUCCESS) { - ERROR_LOG(G3D, "Failed creating graphics pipeline! result='%s'", VulkanResultToString(result)); - if (result == VK_INCOMPLETE) { - // Typical Adreno return value. It'll usually also log something vague, like "Failed to link shaders". - // Let's log some stuff and try to stumble along. - ERROR_LOG(G3D, "VS source code:\n%s\n", CutFromMain(vs->GetShaderString(SHADER_STRING_SOURCE_CODE)).c_str()); - ERROR_LOG(G3D, "FS source code:\n%s\n", CutFromMain(fs->GetShaderString(SHADER_STRING_SOURCE_CODE)).c_str()); - } else { - _dbg_assert_msg_(false, "Failed creating graphics pipeline! result='%s'", VulkanResultToString(result)); - } - // Create a placeholder to avoid creating over and over if something is broken. - VulkanPipeline *nullPipeline = new VulkanPipeline(); - nullPipeline->pipeline = VK_NULL_HANDLE; - nullPipeline->flags = 0; - return nullPipeline; - } + VKRGraphicsPipeline *pipeline = renderManager->CreateGraphicsPipeline(desc); VulkanPipeline *vulkanPipeline = new VulkanPipeline(); vulkanPipeline->pipeline = pipeline; @@ -358,7 +347,7 @@ static VulkanPipeline *CreateVulkanPipeline(VkDevice device, VkPipelineCache pip return vulkanPipeline; } -VulkanPipeline *PipelineManagerVulkan::GetOrCreatePipeline(VkPipelineLayout layout, VkRenderPass renderPass, const VulkanPipelineRasterStateKey &rasterKey, const DecVtxFormat *decFmt, VulkanVertexShader *vs, VulkanFragmentShader *fs, bool useHwTransform) { +VulkanPipeline *PipelineManagerVulkan::GetOrCreatePipeline(VulkanRenderManager *renderManager, VkPipelineLayout layout, VkRenderPass renderPass, const VulkanPipelineRasterStateKey &rasterKey, const DecVtxFormat *decFmt, VulkanVertexShader *vs, VulkanFragmentShader *fs, bool useHwTransform) { if (!pipelineCache_) { VkPipelineCacheCreateInfo pc{ VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO }; VkResult res = vkCreatePipelineCache(vulkan_->GetDevice(), &pc, nullptr, &pipelineCache_); @@ -380,7 +369,7 @@ VulkanPipeline *PipelineManagerVulkan::GetOrCreatePipeline(VkPipelineLayout layo return iter; VulkanPipeline *pipeline = CreateVulkanPipeline( - vulkan_->GetDevice(), pipelineCache_, layout, renderPass, + renderManager, pipelineCache_, layout, renderPass, rasterKey, decFmt, vs, fs, useHwTransform); pipelines_.Insert(key, pipeline); @@ -772,7 +761,7 @@ bool PipelineManagerVulkan::LoadCache(FILE *file, bool loadRawPipelineCache, Sha DecVtxFormat fmt; fmt.InitializeFromID(key.vtxFmtId); - VulkanPipeline *pipeline = GetOrCreatePipeline(layout, rp, key.raster, + VulkanPipeline *pipeline = GetOrCreatePipeline(rm, layout, rp, key.raster, key.useHWTransform ? &fmt : 0, vs, fs, key.useHWTransform); if (!pipeline) { diff --git a/GPU/Vulkan/PipelineManagerVulkan.h b/GPU/Vulkan/PipelineManagerVulkan.h index 929914643e..37d542e9a0 100644 --- a/GPU/Vulkan/PipelineManagerVulkan.h +++ b/GPU/Vulkan/PipelineManagerVulkan.h @@ -25,9 +25,11 @@ #include "GPU/Common/ShaderCommon.h" #include "GPU/Vulkan/VulkanUtil.h" #include "GPU/Vulkan/StateMappingVulkan.h" - #include "GPU/Vulkan/VulkanQueueRunner.h" +struct VKRGraphicsPipeline; +class VulkanRenderManager; + struct VulkanPipelineKey { VulkanPipelineRasterStateKey raster; // prim is included here VkRenderPass renderPass; @@ -48,7 +50,7 @@ struct VulkanPipelineKey { // Simply wraps a Vulkan pipeline, providing some metadata. struct VulkanPipeline { - VkPipeline pipeline; + VKRGraphicsPipeline *pipeline; int flags; // PipelineFlags enum above. bool UsesBlendConstant() const { return (flags & PIPELINE_FLAG_USES_BLEND_CONSTANT) != 0; } @@ -67,7 +69,7 @@ public: PipelineManagerVulkan(VulkanContext *ctx); ~PipelineManagerVulkan(); - VulkanPipeline *GetOrCreatePipeline(VkPipelineLayout layout, VkRenderPass renderPass, const VulkanPipelineRasterStateKey &rasterKey, const DecVtxFormat *decFmt, VulkanVertexShader *vs, VulkanFragmentShader *fs, bool useHwTransform); + VulkanPipeline *GetOrCreatePipeline(VulkanRenderManager *renderManager, VkPipelineLayout layout, VkRenderPass renderPass, const VulkanPipelineRasterStateKey &rasterKey, const DecVtxFormat *decFmt, VulkanVertexShader *vs, VulkanFragmentShader *fs, bool useHwTransform); int GetNumPipelines() const { return (int)pipelines_.size(); } void Clear();