Don't replace shaders for incomplete pipeline libraries

Before, RenderDoc would treat these incomplete pipeline libraries as if
they were complete pipelines, and thus attempt to create pipelines with
incomplete data, producing several validation errors and on some devices
crashes.

For instance, a pipeline library that only contains a vertex or fragment
shader but not input assembly state would use invalid input assembly
state (specifically, VulkanShaderCache::MakeGraphicsPipelineInfo would
use the topology value from VulkanCreationInfo::Pipeline, which is set
to VK_PRIMITIVE_TOPOLOGY_MAX_ENUM (0x7fffffff) if the pipeline has no
input assembly state by VulkanCreationInfo::Pipeline::Init).

Additionally, those pipeline libraries were treated as complete graphics
pipelines, not libraries, as VulkanShaderCache::MakeGraphicsPipelineInfo
removes VK_PIPELINE_CREATE_LIBRARY_BIT_KHR and no
VkGraphicsPipelineLibraryCreateInfoEXT was added to the pNext chain.

RenderDoc already merges the pipeline libraries into complete graphics
pipelines, so there is no reason to recreate the libraries with modified
shaders.
This commit is contained in:
William Pearson
2024-05-09 14:13:11 -07:00
committed by Baldur Karlsson
parent 91c13a0e9f
commit 3b2bb46d9a
3 changed files with 21 additions and 11 deletions
+9 -10
View File
@@ -966,17 +966,16 @@ void VulkanCreationInfo::Pipeline::Init(VulkanResourceManager *resourceMan,
// this is used to e.g. filter specified dynamic states so we only consider the ones valid for
// this pipeline. If we're not using libraries, all states are valid
VkGraphicsPipelineLibraryFlagsEXT availStages =
VK_GRAPHICS_PIPELINE_LIBRARY_VERTEX_INPUT_INTERFACE_BIT_EXT |
VK_GRAPHICS_PIPELINE_LIBRARY_PRE_RASTERIZATION_SHADERS_BIT_EXT |
VK_GRAPHICS_PIPELINE_LIBRARY_FRAGMENT_SHADER_BIT_EXT |
VK_GRAPHICS_PIPELINE_LIBRARY_FRAGMENT_OUTPUT_INTERFACE_BIT_EXT;
availStages = VK_GRAPHICS_PIPELINE_LIBRARY_VERTEX_INPUT_INTERFACE_BIT_EXT |
VK_GRAPHICS_PIPELINE_LIBRARY_PRE_RASTERIZATION_SHADERS_BIT_EXT |
VK_GRAPHICS_PIPELINE_LIBRARY_FRAGMENT_SHADER_BIT_EXT |
VK_GRAPHICS_PIPELINE_LIBRARY_FRAGMENT_OUTPUT_INTERFACE_BIT_EXT;
const VkGraphicsPipelineLibraryCreateInfoEXT *graphicsLibraryCreate =
(const VkGraphicsPipelineLibraryCreateInfoEXT *)FindNextStruct(
pCreateInfo, VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_LIBRARY_CREATE_INFO_EXT);
if(graphicsLibraryCreate)
availStages = libraryFlags = graphicsLibraryCreate->flags;
availStages = graphicsLibraryCreate->flags;
vertLayout = fragLayout = GetResID(pCreateInfo->layout);
renderpass = GetResID(pCreateInfo->renderPass);
@@ -1451,7 +1450,7 @@ void VulkanCreationInfo::Pipeline::Init(VulkanResourceManager *resourceMan,
for(size_t i = 0; i < VkDynamicCount; i++)
dynamicStates[i] |= pipeInfo.dynamicStates[i];
if(pipeInfo.libraryFlags & VK_GRAPHICS_PIPELINE_LIBRARY_VERTEX_INPUT_INTERFACE_BIT_EXT)
if(pipeInfo.availStages & VK_GRAPHICS_PIPELINE_LIBRARY_VERTEX_INPUT_INTERFACE_BIT_EXT)
{
vertexBindings = pipeInfo.vertexBindings;
vertexAttrs = pipeInfo.vertexAttrs;
@@ -1460,7 +1459,7 @@ void VulkanCreationInfo::Pipeline::Init(VulkanResourceManager *resourceMan,
primitiveRestartEnable = pipeInfo.primitiveRestartEnable;
}
if(pipeInfo.libraryFlags & VK_GRAPHICS_PIPELINE_LIBRARY_PRE_RASTERIZATION_SHADERS_BIT_EXT)
if(pipeInfo.availStages & VK_GRAPHICS_PIPELINE_LIBRARY_PRE_RASTERIZATION_SHADERS_BIT_EXT)
{
renderpass = pipeInfo.renderpass;
subpass = pipeInfo.subpass;
@@ -1511,7 +1510,7 @@ void VulkanCreationInfo::Pipeline::Init(VulkanResourceManager *resourceMan,
flags |= pipeInfo.flags;
}
if(pipeInfo.libraryFlags & VK_GRAPHICS_PIPELINE_LIBRARY_FRAGMENT_SHADER_BIT_EXT)
if(pipeInfo.availStages & VK_GRAPHICS_PIPELINE_LIBRARY_FRAGMENT_SHADER_BIT_EXT)
{
renderpass = pipeInfo.renderpass;
subpass = pipeInfo.subpass;
@@ -1540,7 +1539,7 @@ void VulkanCreationInfo::Pipeline::Init(VulkanResourceManager *resourceMan,
flags |= pipeInfo.flags;
}
if(pipeInfo.libraryFlags & VK_GRAPHICS_PIPELINE_LIBRARY_FRAGMENT_OUTPUT_INTERFACE_BIT_EXT)
if(pipeInfo.availStages & VK_GRAPHICS_PIPELINE_LIBRARY_FRAGMENT_OUTPUT_INTERFACE_BIT_EXT)
{
renderpass = pipeInfo.renderpass;
subpass = pipeInfo.subpass;
+1 -1
View File
@@ -240,7 +240,7 @@ struct VulkanCreationInfo
bool graphicsPipe = false;
// VkGraphicsPipelineLibraryCreateInfoEXT
VkGraphicsPipelineLibraryFlagsEXT libraryFlags;
VkGraphicsPipelineLibraryFlagsEXT availStages;
rdcarray<ResourceId> parentLibraries;
ResourceId compLayout;
+11
View File
@@ -4850,6 +4850,17 @@ void VulkanReplay::RefreshDerivedReplacements()
ResourceId pipesrcid = it->first;
const VulkanCreationInfo::Pipeline &pipeInfo = it->second;
// don't replace incomplete pipeline libraries (we already pull the full state into the final
// pipeline, so these are not used in replay; the libraries contain invalid dummy data for the
// non-available parts)
if(!(pipeInfo.availStages & VK_GRAPHICS_PIPELINE_LIBRARY_VERTEX_INPUT_INTERFACE_BIT_EXT) ||
!(pipeInfo.availStages & VK_GRAPHICS_PIPELINE_LIBRARY_PRE_RASTERIZATION_SHADERS_BIT_EXT) ||
!(pipeInfo.availStages & VK_GRAPHICS_PIPELINE_LIBRARY_FRAGMENT_SHADER_BIT_EXT) ||
!(pipeInfo.availStages & VK_GRAPHICS_PIPELINE_LIBRARY_FRAGMENT_OUTPUT_INTERFACE_BIT_EXT))
{
continue;
}
ResourceId origsrcid = rm->GetOriginalID(pipesrcid);
// only look at pipelines from the capture, no replay-time programs.