vulkan: move cached PSO ownership to shaders.

Fixes issues with state corruption when a shader is created with the same memory address as a recently deleted shader.
This commit is contained in:
Sasha Szpakowski
2024-06-24 18:31:34 -03:00
parent 5ee6c5befd
commit 35f20eb053
4 changed files with 85 additions and 89 deletions
+15 -37
View File
@@ -2315,13 +2315,14 @@ void Graphics::prepareDraw(const VertexAttributes &attributes, const BufferBindi
if (!renderPassState.active)
startRenderPass();
usedShadersInFrame.insert((dynamic_cast<Shader*>(Shader::current)));
auto s = dynamic_cast<Shader*>(Shader::current);
usedShadersInFrame.insert(s);
GraphicsPipelineConfiguration configuration{};
configuration.renderPass = renderPassState.beginInfo.renderPass;
configuration.vertexAttributes = attributes;
configuration.shader = (Shader*)Shader::current;
configuration.wireFrame = states.back().wireframe;
configuration.blendState = states.back().blend;
configuration.colorChannelMask = states.back().colorMask;
@@ -2341,11 +2342,15 @@ void Graphics::prepareDraw(const VertexAttributes &attributes, const BufferBindi
configuration.dynamicState.cullmode = cullmode;
}
configuration.shader->setMainTex(texture);
VkPipeline pipeline = s->getCachedGraphicsPipeline(this, configuration);
if (pipeline != renderPassState.pipeline)
{
vkCmdBindPipeline(commandBuffers.at(currentFrame), VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
renderPassState.pipeline = pipeline;
}
ensureGraphicsPipelineConfiguration(configuration);
configuration.shader->cmdPushDescriptorSets(commandBuffers.at(currentFrame), VK_PIPELINE_BIND_POINT_GRAPHICS);
s->setMainTex(texture);
s->cmdPushDescriptorSets(commandBuffers.at(currentFrame), VK_PIPELINE_BIND_POINT_GRAPHICS);
VkBuffer vkbuffers[BufferBindings::MAX];
VkDeviceSize vkoffsets[BufferBindings::MAX];
@@ -2640,7 +2645,6 @@ void Graphics::cleanupUnusedObjects()
{
eraseUnusedObjects(renderPasses, renderPassUsages, vkDestroyRenderPass, device);
eraseUnusedObjects(framebuffers, framebufferUsages, vkDestroyFramebuffer, device);
eraseUnusedObjects(graphicsPipelines, pipelineUsages, vkDestroyPipeline, device);
}
void Graphics::requestSwapchainRecreation()
@@ -2670,17 +2674,17 @@ VkSampler Graphics::getCachedSampler(const SamplerState &samplerState)
}
}
VkPipeline Graphics::createGraphicsPipeline(GraphicsPipelineConfiguration &configuration)
VkPipeline Graphics::createGraphicsPipeline(Shader *shader, const GraphicsPipelineConfiguration &configuration)
{
VkGraphicsPipelineCreateInfo pipelineInfo{};
pipelineInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
auto &shaderStages = configuration.shader->getShaderStages();
auto &shaderStages = shader->getShaderStages();
std::vector<VkVertexInputBindingDescription> bindingDescriptions;
std::vector<VkVertexInputAttributeDescription> attributeDescriptions;
createVulkanVertexFormat(configuration.shader, configuration.vertexAttributes, bindingDescriptions, attributeDescriptions);
createVulkanVertexFormat(shader, configuration.vertexAttributes, bindingDescriptions, attributeDescriptions);
VkPipelineVertexInputStateCreateInfo vertexInputInfo{};
vertexInputInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
@@ -2812,7 +2816,7 @@ VkPipeline Graphics::createGraphicsPipeline(GraphicsPipelineConfiguration &confi
pipelineInfo.pMultisampleState = &multisampling;
pipelineInfo.pColorBlendState = &colorBlending;
pipelineInfo.pDynamicState = &dynamicState;
pipelineInfo.layout = configuration.shader->getGraphicsPipelineLayout();
pipelineInfo.layout = shader->getGraphicsPipelineLayout();
pipelineInfo.subpass = 0;
pipelineInfo.basePipelineHandle = VK_NULL_HANDLE;
pipelineInfo.basePipelineIndex = -1;
@@ -2824,28 +2828,6 @@ VkPipeline Graphics::createGraphicsPipeline(GraphicsPipelineConfiguration &confi
return graphicsPipeline;
}
void Graphics::ensureGraphicsPipelineConfiguration(GraphicsPipelineConfiguration &configuration)
{
auto it = graphicsPipelines.find(configuration);
if (it != graphicsPipelines.end())
{
if (it->second != renderPassState.pipeline)
{
vkCmdBindPipeline(commandBuffers.at(currentFrame), VK_PIPELINE_BIND_POINT_GRAPHICS, it->second);
renderPassState.pipeline = it->second;
pipelineUsages[it->second] = true;
}
}
else
{
VkPipeline pipeline = createGraphicsPipeline(configuration);
graphicsPipelines.insert({configuration, pipeline});
vkCmdBindPipeline(commandBuffers.at(currentFrame), VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
renderPassState.pipeline = pipeline;
pipelineUsages[pipeline] = true;
}
}
VkSampleCountFlagBits Graphics::getMsaaCount(int requestedMsaa) const
{
VkPhysicalDeviceProperties physicalDeviceProperties;
@@ -3112,10 +3094,6 @@ void Graphics::cleanup()
for (const auto &entry : framebuffers)
vkDestroyFramebuffer(device, entry.second, nullptr);
framebuffers.clear();
for (auto const &p : graphicsPipelines)
vkDestroyPipeline(device, p.second, nullptr);
graphicsPipelines.clear();
vkDestroyCommandPool(device, commandPool, nullptr);
vkDestroyPipelineCache(device, pipelineCache, nullptr);