From 20c986fc06164ba702778ec8f5496c82e8723323 Mon Sep 17 00:00:00 2001 From: baldurk Date: Thu, 28 Oct 2021 16:08:39 +0100 Subject: [PATCH] Add support for EXT_graphics_pipeline_library --- renderdoc/api/replay/vk_pipestate.h | 14 +- renderdoc/driver/vulkan/extension_support.md | 2 +- renderdoc/driver/vulkan/vk_common.h | 8 + renderdoc/driver/vulkan/vk_core.cpp | 5 +- renderdoc/driver/vulkan/vk_debug.cpp | 25 +- renderdoc/driver/vulkan/vk_info.cpp | 329 +++++++++++++++++- renderdoc/driver/vulkan/vk_info.h | 25 +- renderdoc/driver/vulkan/vk_next_chains.cpp | 72 ++-- renderdoc/driver/vulkan/vk_overlay.cpp | 8 +- renderdoc/driver/vulkan/vk_postvs.cpp | 6 +- renderdoc/driver/vulkan/vk_replay.cpp | 29 +- renderdoc/driver/vulkan/vk_serialise.cpp | 119 ++++++- renderdoc/driver/vulkan/vk_shader_cache.cpp | 42 ++- renderdoc/driver/vulkan/vk_shader_cache.h | 4 + .../driver/vulkan/vk_shader_feedback.cpp | 22 +- renderdoc/driver/vulkan/vk_shaderdebug.cpp | 32 +- renderdoc/driver/vulkan/vk_state.cpp | 8 +- renderdoc/driver/vulkan/vk_stringise.cpp | 66 ++++ .../driver/vulkan/wrappers/vk_cmd_funcs.cpp | 12 +- .../vulkan/wrappers/vk_device_funcs.cpp | 7 + .../vulkan/wrappers/vk_shader_funcs.cpp | 89 ++++- renderdoc/replay/renderdoc_serialise.inl | 8 +- 22 files changed, 820 insertions(+), 112 deletions(-) diff --git a/renderdoc/api/replay/vk_pipestate.h b/renderdoc/api/replay/vk_pipestate.h index babd54188..e1f90f28c 100644 --- a/renderdoc/api/replay/vk_pipestate.h +++ b/renderdoc/api/replay/vk_pipestate.h @@ -352,8 +352,18 @@ struct Pipeline DOCUMENT("The :class:`ResourceId` of the pipeline object."); ResourceId pipelineResourceId; - DOCUMENT("The :class:`ResourceId` of the pipeline layout object."); - ResourceId pipelineLayoutResourceId; + DOCUMENT("The :class:`ResourceId` of the compute pipeline layout object."); + ResourceId pipelineComputeLayoutResourceId; + DOCUMENT(R"(The :class:`ResourceId` of the pre-rasterization pipeline layout object. + +When not using pipeline libraries, this will be identical to :data:`pipelineFragmentLayoutResourceId`. +)"); + ResourceId pipelinePreRastLayoutResourceId; + DOCUMENT(R"(The :class:`ResourceId` of the fragment pipeline layout object. + +When not using pipeline libraries, this will be identical to :data:`pipelinePreRastLayoutResourceId`. +)"); + ResourceId pipelineFragmentLayoutResourceId; DOCUMENT("The flags used to create the pipeline object."); uint32_t flags = 0; diff --git a/renderdoc/driver/vulkan/extension_support.md b/renderdoc/driver/vulkan/extension_support.md index 5a6826ad1..925d8dca4 100644 --- a/renderdoc/driver/vulkan/extension_support.md +++ b/renderdoc/driver/vulkan/extension_support.md @@ -51,6 +51,7 @@ Maintainers can update this file by updating vk.xml in this folder and running ` * `VK_EXT_full_screen_exclusive` * `VK_EXT_global_priority` * `VK_EXT_global_priority_query` +* `VK_EXT_graphics_pipeline_library` * `VK_EXT_hdr_metadata` * `VK_EXT_headless_surface` * `VK_EXT_host_query_reset` @@ -236,7 +237,6 @@ Ray tracing extensions are now standard and will likely be supported at some poi * `VK_EXT_image_drm_format_modifier` * `VK_EXT_image_view_min_lod` * `VK_EXT_multi_draw` -* `VK_EXT_graphics_pipeline_library` * `VK_EXT_pageable_device_local_memory` * `VK_EXT_physical_device_drm` * `VK_EXT_primitive_topology_list_restart` diff --git a/renderdoc/driver/vulkan/vk_common.h b/renderdoc/driver/vulkan/vk_common.h index 1a016814f..f6b331710 100644 --- a/renderdoc/driver/vulkan/vk_common.h +++ b/renderdoc/driver/vulkan/vk_common.h @@ -888,6 +888,7 @@ DECLARE_REFLECTION_STRUCT(VkFramebufferAttachmentImageInfo); DECLARE_REFLECTION_STRUCT(VkFramebufferAttachmentsCreateInfo); DECLARE_REFLECTION_STRUCT(VkFramebufferCreateInfo); DECLARE_REFLECTION_STRUCT(VkGraphicsPipelineCreateInfo); +DECLARE_REFLECTION_STRUCT(VkGraphicsPipelineLibraryCreateInfoEXT); DECLARE_REFLECTION_STRUCT(VkHdrMetadataEXT); DECLARE_REFLECTION_STRUCT(VkImageBlit2); DECLARE_REFLECTION_STRUCT(VkImageCopy2); @@ -965,6 +966,8 @@ DECLARE_REFLECTION_STRUCT(VkPhysicalDeviceFragmentDensityMapOffsetPropertiesQCOM DECLARE_REFLECTION_STRUCT(VkPhysicalDeviceFragmentShaderBarycentricFeaturesNV); DECLARE_REFLECTION_STRUCT(VkPhysicalDeviceFragmentShaderInterlockFeaturesEXT); DECLARE_REFLECTION_STRUCT(VkPhysicalDeviceGlobalPriorityQueryFeaturesKHR); +DECLARE_REFLECTION_STRUCT(VkPhysicalDeviceGraphicsPipelineLibraryFeaturesEXT); +DECLARE_REFLECTION_STRUCT(VkPhysicalDeviceGraphicsPipelineLibraryPropertiesEXT); DECLARE_REFLECTION_STRUCT(VkPhysicalDeviceGroupProperties); DECLARE_REFLECTION_STRUCT(VkPhysicalDeviceHostQueryResetFeatures); DECLARE_REFLECTION_STRUCT(VkPhysicalDeviceFragmentShadingRateKHR); @@ -1263,6 +1266,7 @@ DECLARE_DESERIALISE_TYPE(VkFramebufferAttachmentImageInfo); DECLARE_DESERIALISE_TYPE(VkFramebufferAttachmentsCreateInfo); DECLARE_DESERIALISE_TYPE(VkFramebufferCreateInfo); DECLARE_DESERIALISE_TYPE(VkGraphicsPipelineCreateInfo); +DECLARE_DESERIALISE_TYPE(VkGraphicsPipelineLibraryCreateInfoEXT); DECLARE_DESERIALISE_TYPE(VkImageBlit2); DECLARE_DESERIALISE_TYPE(VkImageCopy2); DECLARE_DESERIALISE_TYPE(VkImageCreateInfo); @@ -1336,6 +1340,8 @@ DECLARE_DESERIALISE_TYPE(VkPhysicalDeviceFragmentDensityMapOffsetPropertiesQCOM) DECLARE_DESERIALISE_TYPE(VkPhysicalDeviceFragmentShaderBarycentricFeaturesNV); DECLARE_DESERIALISE_TYPE(VkPhysicalDeviceFragmentShaderInterlockFeaturesEXT); DECLARE_DESERIALISE_TYPE(VkPhysicalDeviceGlobalPriorityQueryFeaturesKHR); +DECLARE_DESERIALISE_TYPE(VkPhysicalDeviceGraphicsPipelineLibraryFeaturesEXT); +DECLARE_DESERIALISE_TYPE(VkPhysicalDeviceGraphicsPipelineLibraryPropertiesEXT); DECLARE_DESERIALISE_TYPE(VkPhysicalDeviceGroupProperties); DECLARE_DESERIALISE_TYPE(VkPhysicalDeviceHostQueryResetFeatures); DECLARE_DESERIALISE_TYPE(VkPhysicalDeviceFragmentShadingRateKHR); @@ -1754,6 +1760,7 @@ DECLARE_REFLECTION_ENUM(VkFormatFeatureFlagBits); DECLARE_REFLECTION_ENUM(VkFormatFeatureFlagBits2); DECLARE_REFLECTION_ENUM(VkFragmentShadingRateCombinerOpKHR); DECLARE_REFLECTION_ENUM(VkFramebufferCreateFlagBits); +DECLARE_REFLECTION_ENUM(VkGraphicsPipelineLibraryFlagBitsEXT); DECLARE_REFLECTION_ENUM(VkFrontFace); DECLARE_REFLECTION_ENUM(VkImageAspectFlagBits); DECLARE_REFLECTION_ENUM(VkImageCreateFlagBits); @@ -1769,6 +1776,7 @@ DECLARE_REFLECTION_ENUM(VkLogicOp); DECLARE_REFLECTION_ENUM(VkMemoryAllocateFlagBits); DECLARE_REFLECTION_ENUM(VkMemoryHeapFlagBits); DECLARE_REFLECTION_ENUM(VkMemoryPropertyFlagBits); +DECLARE_REFLECTION_ENUM(VkObjectType); DECLARE_REFLECTION_ENUM(VkPerformanceCounterDescriptionFlagBitsKHR); DECLARE_REFLECTION_ENUM(VkPerformanceCounterScopeKHR); DECLARE_REFLECTION_ENUM(VkPerformanceCounterStorageKHR); diff --git a/renderdoc/driver/vulkan/vk_core.cpp b/renderdoc/driver/vulkan/vk_core.cpp index 20b53ccee..209ebcd01 100644 --- a/renderdoc/driver/vulkan/vk_core.cpp +++ b/renderdoc/driver/vulkan/vk_core.cpp @@ -956,6 +956,9 @@ static const VkExtensionProperties supportedExtensions[] = { { VK_EXT_GLOBAL_PRIORITY_QUERY_EXTENSION_NAME, VK_EXT_GLOBAL_PRIORITY_QUERY_SPEC_VERSION, }, + { + VK_EXT_GRAPHICS_PIPELINE_LIBRARY_EXTENSION_NAME, VK_EXT_GRAPHICS_PIPELINE_LIBRARY_SPEC_VERSION, + }, { VK_EXT_HDR_METADATA_EXTENSION_NAME, VK_EXT_HDR_METADATA_SPEC_VERSION, }, @@ -4554,7 +4557,7 @@ void WrappedVulkan::AddUsage(VulkanActionTreeNode &actionNode, rdcarray= (int32_t)descSets.size()) + if(bindset >= (int32_t)descSets.size() || descSets[bindset].descSet == ResourceId()) { msg.description = StringFormat::Fmt("Shader referenced a descriptor set %i that was not bound", bindset); diff --git a/renderdoc/driver/vulkan/vk_debug.cpp b/renderdoc/driver/vulkan/vk_debug.cpp index e078b3173..473cccab5 100644 --- a/renderdoc/driver/vulkan/vk_debug.cpp +++ b/renderdoc/driver/vulkan/vk_debug.cpp @@ -2416,16 +2416,13 @@ void VulkanReplay::PatchReservedDescriptors(const VulkanStatePipeline &pipe, poolSizes[newBindings[i].descriptorType].descriptorCount += newBindings[i].descriptorCount; } - const rdcarray &pipeDescSetLayouts = - creationInfo.m_PipelineLayout[pipeInfo.layout].descSetLayouts; - // need to add our added bindings to the first descriptor set rdcarray bindings(newBindings, newBindingsCount); // if there are fewer sets bound than were declared in the pipeline layout, only process the // bound sets (as otherwise we'd fail to copy from them). Assume the application knew what it // was doing and the other sets are statically unused. - setLayouts.resize(RDCMIN(pipe.descSets.size(), pipeDescSetLayouts.size())); + setLayouts.resize(RDCMIN(pipe.descSets.size(), pipeInfo.descSetLayouts.size())); size_t boundDescs = setLayouts.size(); @@ -2572,9 +2569,15 @@ void VulkanReplay::PatchReservedDescriptors(const VulkanStatePipeline &pipe, // if the shader had no descriptor sets at all, i will be invalid, so just skip and add a set // with only our own bindings. - if(i < pipeDescSetLayouts.size() && i < pipe.descSets.size() && + if(i < pipeInfo.descSetLayouts.size() && i < pipe.descSets.size() && pipe.descSets[i].pipeLayout != ResourceId()) { + const VulkanCreationInfo::PipelineLayout &pipelineLayoutInfo = + creationInfo.m_PipelineLayout[pipe.descSets[i].pipeLayout]; + + if(pipelineLayoutInfo.descSetLayouts[i] == ResourceId()) + continue; + // use the descriptor set layout from when it was bound. If the pipeline layout declared a // descriptor set layout for this set, but it's statically unused, it may be complete // garbage and doesn't match what the shader uses. However the pipeline layout at descriptor @@ -2582,8 +2585,7 @@ void VulkanReplay::PatchReservedDescriptors(const VulkanStatePipeline &pipe, // then the pipeline layout at bind time must be compatible with the pipeline's pipeline // layout, so we're fine too. const DescSetLayout &origLayout = - creationInfo.m_DescSetLayout[creationInfo.m_PipelineLayout[pipe.descSets[i].pipeLayout] - .descSetLayouts[i]]; + creationInfo.m_DescSetLayout[pipelineLayoutInfo.descSetLayouts[i]]; WrappedVulkan::DescriptorSetInfo &setInfo = m_pDriver->m_DescriptorSetState[pipe.descSets[i].descSet]; @@ -2768,13 +2770,18 @@ void VulkanReplay::PatchReservedDescriptors(const VulkanStatePipeline &pipe, if(pipe.descSets[i].descSet == ResourceId()) continue; + const VulkanCreationInfo::PipelineLayout &pipelineLayoutInfo = + creationInfo.m_PipelineLayout[pipe.descSets[i].pipeLayout]; + + if(pipelineLayoutInfo.descSetLayouts[i] == ResourceId()) + continue; + // as above we use the pipeline layout that was originally used to bind this descriptor set // and not the pipeline layout from the pipeline, in case the pipeline statically doesn't use // this set and so its descriptor set layout is garbage (doesn't match the actual bound // descriptor set) const DescSetLayout &origLayout = - creationInfo.m_DescSetLayout[creationInfo.m_PipelineLayout[pipe.descSets[i].pipeLayout] - .descSetLayouts[i]]; + creationInfo.m_DescSetLayout[pipelineLayoutInfo.descSetLayouts[i]]; WrappedVulkan::DescriptorSetInfo &setInfo = m_pDriver->m_DescriptorSetState[pipe.descSets[i].descSet]; diff --git a/renderdoc/driver/vulkan/vk_info.cpp b/renderdoc/driver/vulkan/vk_info.cpp index f106f2584..edb0551c3 100644 --- a/renderdoc/driver/vulkan/vk_info.cpp +++ b/renderdoc/driver/vulkan/vk_info.cpp @@ -133,6 +133,67 @@ VulkanDynamicStateIndex ConvertDynamicState(VkDynamicState state) return VkDynamicCount; } +static VkGraphicsPipelineLibraryFlagsEXT DynamicStateValidState(VkDynamicState state) +{ + const VkGraphicsPipelineLibraryFlagsEXT vinput = + VK_GRAPHICS_PIPELINE_LIBRARY_VERTEX_INPUT_INTERFACE_BIT_EXT; + const VkGraphicsPipelineLibraryFlagsEXT vert = + VK_GRAPHICS_PIPELINE_LIBRARY_PRE_RASTERIZATION_SHADERS_BIT_EXT; + const VkGraphicsPipelineLibraryFlagsEXT frag = VK_GRAPHICS_PIPELINE_LIBRARY_FRAGMENT_SHADER_BIT_EXT; + const VkGraphicsPipelineLibraryFlagsEXT colout = + VK_GRAPHICS_PIPELINE_LIBRARY_FRAGMENT_OUTPUT_INTERFACE_BIT_EXT; + + switch(state) + { + case VK_DYNAMIC_STATE_VIEWPORT: return vert; + case VK_DYNAMIC_STATE_SCISSOR: return vert; + case VK_DYNAMIC_STATE_LINE_WIDTH: return frag; + case VK_DYNAMIC_STATE_DEPTH_BIAS: return frag; + case VK_DYNAMIC_STATE_BLEND_CONSTANTS: return colout; + case VK_DYNAMIC_STATE_DEPTH_BOUNDS: return frag; + case VK_DYNAMIC_STATE_STENCIL_COMPARE_MASK: return frag; + case VK_DYNAMIC_STATE_STENCIL_WRITE_MASK: return frag; + case VK_DYNAMIC_STATE_STENCIL_REFERENCE: return frag; + case VK_DYNAMIC_STATE_VIEWPORT_W_SCALING_NV: return vert; + case VK_DYNAMIC_STATE_DISCARD_RECTANGLE_EXT: return vert; + case VK_DYNAMIC_STATE_SAMPLE_LOCATIONS_EXT: return frag | colout; + case VK_DYNAMIC_STATE_RAY_TRACING_PIPELINE_STACK_SIZE_KHR: + return (VkGraphicsPipelineLibraryFlagsEXT)0; + case VK_DYNAMIC_STATE_VIEWPORT_SHADING_RATE_PALETTE_NV: return vert; + case VK_DYNAMIC_STATE_VIEWPORT_COARSE_SAMPLE_ORDER_NV: return vert; + case VK_DYNAMIC_STATE_EXCLUSIVE_SCISSOR_NV: return vert; + case VK_DYNAMIC_STATE_FRAGMENT_SHADING_RATE_KHR: return vert | frag; + case VK_DYNAMIC_STATE_LINE_STIPPLE_EXT: return vert; + case VK_DYNAMIC_STATE_CULL_MODE: return vert; + case VK_DYNAMIC_STATE_FRONT_FACE: return vert; + case VK_DYNAMIC_STATE_PRIMITIVE_TOPOLOGY: return vinput; + case VK_DYNAMIC_STATE_VIEWPORT_WITH_COUNT: return vert; + case VK_DYNAMIC_STATE_SCISSOR_WITH_COUNT: return vert; + case VK_DYNAMIC_STATE_VERTEX_INPUT_BINDING_STRIDE: return vinput; + case VK_DYNAMIC_STATE_DEPTH_TEST_ENABLE: return frag; + case VK_DYNAMIC_STATE_DEPTH_WRITE_ENABLE: return frag; + case VK_DYNAMIC_STATE_DEPTH_COMPARE_OP: return frag; + case VK_DYNAMIC_STATE_DEPTH_BOUNDS_TEST_ENABLE: return frag; + case VK_DYNAMIC_STATE_STENCIL_TEST_ENABLE: return frag; + case VK_DYNAMIC_STATE_STENCIL_OP: return frag; + case VK_DYNAMIC_STATE_VERTEX_INPUT_EXT: return vinput; + case VK_DYNAMIC_STATE_PATCH_CONTROL_POINTS_EXT: return vert; + case VK_DYNAMIC_STATE_RASTERIZER_DISCARD_ENABLE: return vert; + case VK_DYNAMIC_STATE_DEPTH_BIAS_ENABLE: return frag; + case VK_DYNAMIC_STATE_LOGIC_OP_EXT: return colout; + case VK_DYNAMIC_STATE_PRIMITIVE_RESTART_ENABLE: return vinput; + case VK_DYNAMIC_STATE_COLOR_WRITE_ENABLE_EXT: return colout; + case VK_DYNAMIC_STATE_MAX_ENUM: break; + } + + RDCERR("Unexpected vulkan state %u", state); + + return 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; +} + void DescSetLayout::Init(VulkanResourceManager *resourceMan, VulkanCreationInfo &info, const VkDescriptorSetLayoutCreateInfo *pCreateInfo) { @@ -142,6 +203,8 @@ void DescSetLayout::Init(VulkanResourceManager *resourceMan, VulkanCreationInfo flags = pCreateInfo->flags; + anyStageFlags = 0; + VkDescriptorSetLayoutBindingFlagsCreateInfo *bindingFlags = (VkDescriptorSetLayoutBindingFlagsCreateInfo *)FindNextStruct( pCreateInfo, VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_BINDING_FLAGS_CREATE_INFO); @@ -165,6 +228,8 @@ void DescSetLayout::Init(VulkanResourceManager *resourceMan, VulkanCreationInfo bindings[b].descriptorType = pCreateInfo->pBindings[i].descriptorType; bindings[b].stageFlags = pCreateInfo->pBindings[i].stageFlags; + anyStageFlags |= bindings[b].stageFlags; + if(bindings[b].descriptorType == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC || bindings[b].descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC) dynamicCount++; @@ -361,7 +426,21 @@ void VulkanCreationInfo::Pipeline::Init(VulkanResourceManager *resourceMan, graphicsPipe = true; - layout = GetResID(pCreateInfo->layout); + // 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; + + const VkGraphicsPipelineLibraryCreateInfoEXT *graphicsLibraryCreate = + (const VkGraphicsPipelineLibraryCreateInfoEXT *)FindNextStruct( + pCreateInfo, VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_LIBRARY_CREATE_INFO_EXT); + if(graphicsLibraryCreate) + availStages = libraryFlags = graphicsLibraryCreate->flags; + + vertLayout = fragLayout = GetResID(pCreateInfo->layout); renderpass = GetResID(pCreateInfo->renderPass); subpass = pCreateInfo->subpass; @@ -388,7 +467,16 @@ void VulkanCreationInfo::Pipeline::Init(VulkanResourceManager *resourceMan, if(pCreateInfo->pDynamicState) { for(uint32_t i = 0; i < pCreateInfo->pDynamicState->dynamicStateCount; i++) - dynamicStates[ConvertDynamicState(pCreateInfo->pDynamicState->pDynamicStates[i])] = true; + { + VkDynamicState d = pCreateInfo->pDynamicState->pDynamicStates[i]; + + // ignore dynamic states not available for this library (e.g. + // VK_DYNAMIC_STATE_VERTEX_INPUT_EXT in a library with only FRAGMENT_OUTPUT_INTERFACE_BIT_EXT) + if((DynamicStateValidState(d) & availStages) == 0) + continue; + + dynamicStates[ConvertDynamicState(d)] = true; + } // if the viewports and counts are dynamic this supersets the viewport only being dynamic. For // ease of code elsewhere, turn off the older one if both are specified so that we don't call @@ -486,8 +574,16 @@ void VulkanCreationInfo::Pipeline::Init(VulkanResourceManager *resourceMan, } } - topology = pCreateInfo->pInputAssemblyState->topology; - primitiveRestartEnable = pCreateInfo->pInputAssemblyState->primitiveRestartEnable ? true : false; + if(pCreateInfo->pInputAssemblyState) + { + topology = pCreateInfo->pInputAssemblyState->topology; + primitiveRestartEnable = pCreateInfo->pInputAssemblyState->primitiveRestartEnable ? true : false; + } + else + { + topology = VK_PRIMITIVE_TOPOLOGY_MAX_ENUM; + primitiveRestartEnable = false; + } if(pCreateInfo->pTessellationState) patchControlPoints = pCreateInfo->pTessellationState->patchControlPoints; @@ -553,16 +649,33 @@ void VulkanCreationInfo::Pipeline::Init(VulkanResourceManager *resourceMan, } // VkPipelineRasterStateCreateInfo - depthClampEnable = pCreateInfo->pRasterizationState->depthClampEnable ? true : false; - rasterizerDiscardEnable = pCreateInfo->pRasterizationState->rasterizerDiscardEnable ? true : false; - polygonMode = pCreateInfo->pRasterizationState->polygonMode; - cullMode = pCreateInfo->pRasterizationState->cullMode; - frontFace = pCreateInfo->pRasterizationState->frontFace; - depthBiasEnable = pCreateInfo->pRasterizationState->depthBiasEnable ? true : false; - depthBiasConstantFactor = pCreateInfo->pRasterizationState->depthBiasConstantFactor; - depthBiasClamp = pCreateInfo->pRasterizationState->depthBiasClamp; - depthBiasSlopeFactor = pCreateInfo->pRasterizationState->depthBiasSlopeFactor; - lineWidth = pCreateInfo->pRasterizationState->lineWidth; + if(pCreateInfo->pRasterizationState) + { + depthClampEnable = pCreateInfo->pRasterizationState->depthClampEnable ? true : false; + rasterizerDiscardEnable = + pCreateInfo->pRasterizationState->rasterizerDiscardEnable ? true : false; + polygonMode = pCreateInfo->pRasterizationState->polygonMode; + cullMode = pCreateInfo->pRasterizationState->cullMode; + frontFace = pCreateInfo->pRasterizationState->frontFace; + depthBiasEnable = pCreateInfo->pRasterizationState->depthBiasEnable ? true : false; + depthBiasConstantFactor = pCreateInfo->pRasterizationState->depthBiasConstantFactor; + depthBiasClamp = pCreateInfo->pRasterizationState->depthBiasClamp; + depthBiasSlopeFactor = pCreateInfo->pRasterizationState->depthBiasSlopeFactor; + lineWidth = pCreateInfo->pRasterizationState->lineWidth; + } + else + { + depthClampEnable = false; + rasterizerDiscardEnable = false; + polygonMode = VK_POLYGON_MODE_FILL; + cullMode = VK_CULL_MODE_NONE; + frontFace = VK_FRONT_FACE_CLOCKWISE; + depthBiasEnable = false; + depthBiasConstantFactor = 0.0f; + depthBiasClamp = 0.0f; + depthBiasSlopeFactor = 0.0f; + lineWidth = 1.0f; + } // VkPipelineRasterizationStateStreamCreateInfoEXT rasterizationStream = 0; @@ -752,6 +865,188 @@ void VulkanCreationInfo::Pipeline::Init(VulkanResourceManager *resourceMan, attachments[i].channelWriteMask = 0; } } + + const VkPipelineLibraryCreateInfoKHR *libraryReference = + (const VkPipelineLibraryCreateInfoKHR *)FindNextStruct( + pCreateInfo, VK_STRUCTURE_TYPE_PIPELINE_LIBRARY_CREATE_INFO_KHR); + if(libraryReference) + { + // unconditionally pull in state from libraries - the state must not overlap (or must be + // identical where overlap is inevitable) + for(uint32_t l = 0; l < libraryReference->libraryCount; l++) + { + ResourceId pipeid = GetResID(libraryReference->pLibraries[l]); + + parentLibraries.push_back(pipeid); + + const Pipeline &pipeInfo = info.m_Pipeline[pipeid]; + + 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) + { + vertexBindings = pipeInfo.vertexBindings; + vertexAttrs = pipeInfo.vertexAttrs; + + topology = pipeInfo.topology; + primitiveRestartEnable = pipeInfo.primitiveRestartEnable; + } + + if(pipeInfo.libraryFlags & VK_GRAPHICS_PIPELINE_LIBRARY_PRE_RASTERIZATION_SHADERS_BIT_EXT) + { + renderpass = pipeInfo.renderpass; + subpass = pipeInfo.subpass; + + for(uint32_t i = 0; i < 5; i++) + shaders[i] = pipeInfo.shaders[i]; + + vertLayout = pipeInfo.vertLayout; + + viewportCount = pipeInfo.viewportCount; + viewports = pipeInfo.viewports; + scissors = pipeInfo.scissors; + + depthClampEnable = pipeInfo.depthClampEnable; + rasterizerDiscardEnable = pipeInfo.rasterizerDiscardEnable; + polygonMode = pipeInfo.polygonMode; + cullMode = pipeInfo.cullMode; + frontFace = pipeInfo.frontFace; + depthBiasEnable = pipeInfo.depthBiasEnable; + depthBiasConstantFactor = pipeInfo.depthBiasConstantFactor; + depthBiasClamp = pipeInfo.depthBiasClamp; + depthBiasSlopeFactor = pipeInfo.depthBiasSlopeFactor; + lineWidth = pipeInfo.lineWidth; + + rasterizationStream = pipeInfo.rasterizationStream; + depthClipEnable = pipeInfo.depthClipEnable; + patchControlPoints = pipeInfo.patchControlPoints; + tessellationDomainOrigin = pipeInfo.tessellationDomainOrigin; + + conservativeRasterizationMode = pipeInfo.conservativeRasterizationMode; + extraPrimitiveOverestimationSize = pipeInfo.extraPrimitiveOverestimationSize; + + lineRasterMode = pipeInfo.lineRasterMode; + stippleEnabled = pipeInfo.stippleEnabled; + stippleFactor = pipeInfo.stippleFactor; + stipplePattern = pipeInfo.stipplePattern; + + discardRectangles = pipeInfo.discardRectangles; + discardMode = pipeInfo.discardMode; + } + + if(pipeInfo.libraryFlags & VK_GRAPHICS_PIPELINE_LIBRARY_FRAGMENT_SHADER_BIT_EXT) + { + renderpass = pipeInfo.renderpass; + subpass = pipeInfo.subpass; + + shaders[4] = pipeInfo.shaders[4]; + + fragLayout = pipeInfo.fragLayout; + + rasterizationSamples = pipeInfo.rasterizationSamples; + sampleShadingEnable = pipeInfo.sampleShadingEnable; + minSampleShading = pipeInfo.minSampleShading; + sampleMask = pipeInfo.sampleMask; + alphaToCoverageEnable = pipeInfo.alphaToCoverageEnable; + alphaToOneEnable = pipeInfo.alphaToOneEnable; + + sampleLocations = pipeInfo.sampleLocations; + + depthTestEnable = pipeInfo.depthTestEnable; + depthWriteEnable = pipeInfo.depthWriteEnable; + depthCompareOp = pipeInfo.depthCompareOp; + depthBoundsEnable = pipeInfo.depthBoundsEnable; + stencilTestEnable = pipeInfo.stencilTestEnable; + front = pipeInfo.front; + back = pipeInfo.back; + minDepthBounds = pipeInfo.minDepthBounds; + maxDepthBounds = pipeInfo.maxDepthBounds; + } + + if(pipeInfo.libraryFlags & VK_GRAPHICS_PIPELINE_LIBRARY_FRAGMENT_OUTPUT_INTERFACE_BIT_EXT) + { + renderpass = pipeInfo.renderpass; + subpass = pipeInfo.subpass; + + rasterizationSamples = pipeInfo.rasterizationSamples; + sampleShadingEnable = pipeInfo.sampleShadingEnable; + minSampleShading = pipeInfo.minSampleShading; + sampleMask = pipeInfo.sampleMask; + alphaToCoverageEnable = pipeInfo.alphaToCoverageEnable; + alphaToOneEnable = pipeInfo.alphaToOneEnable; + + logicOpEnable = pipeInfo.logicOpEnable; + logicOp = pipeInfo.logicOp; + memcpy(blendConst, pipeInfo.blendConst, sizeof(blendConst)); + + attachments = pipeInfo.attachments; + + viewMask = pipeInfo.viewMask; + colorFormats = pipeInfo.colorFormats; + depthFormat = pipeInfo.depthFormat; + stencilFormat = pipeInfo.stencilFormat; + } + } + } + + // calculate descSetLayouts. If only one layout is set, just copy the layouts from it + if(vertLayout == ResourceId()) + { + descSetLayouts = info.m_PipelineLayout[fragLayout].descSetLayouts; + } + else if(fragLayout == ResourceId()) + { + descSetLayouts = info.m_PipelineLayout[vertLayout].descSetLayouts; + } + // if they're both the same (both must be non-empty or we would have hit a case above) it doesn't + // matter + else if(vertLayout == fragLayout) + { + descSetLayouts = info.m_PipelineLayout[vertLayout].descSetLayouts; + } + else + { + // in this case vertLayout is not the same as fragLayout, so we have independent sets and this + // is the linked pipeline + // fortunately one of the requirements of independent set is that any descriptor sets which + // contain any fragment visible descriptors are present in the fragment layout, and vice-versa + // for non-fragment. Any sets which contain both must be identical in both. + // That means we can start by picking all the set layouts from the fragment pipeline layout that + // reference fragments (ignoring any others that may be empty or not but are ignored), then for + // all other sets unconditionally pick the one from the vertex layout + + const rdcarray &vSets = info.m_PipelineLayout[vertLayout].descSetLayouts; + const rdcarray &fSets = info.m_PipelineLayout[fragLayout].descSetLayouts; + + descSetLayouts.resize(RDCMAX(vSets.size(), fSets.size())); + + for(size_t i = 0; i < fSets.size(); i++) + { + if((info.m_DescSetLayout[fSets[i]].anyStageFlags & VK_SHADER_STAGE_FRAGMENT_BIT) != 0) + descSetLayouts[i] = fSets[i]; + } + + for(size_t i = 0; i < vSets.size(); i++) + { + if(descSetLayouts[i] == ResourceId()) + descSetLayouts[i] = vSets[i]; + } + + // it's possible we have sets which are unused by both - maybe empty, dummy, or they only appear + // in the layout which ignores them. Pick from whichever layout contained that element as it + // doesn't matter. + for(size_t i = 0; i < descSetLayouts.size(); i++) + { + if(descSetLayouts[i] == ResourceId()) + { + if(i < vSets.size()) + descSetLayouts[i] = vSets[i]; + else + descSetLayouts[i] = fSets[i]; + } + } + } } void VulkanCreationInfo::Pipeline::Init(VulkanResourceManager *resourceMan, VulkanCreationInfo &info, @@ -761,7 +1056,9 @@ void VulkanCreationInfo::Pipeline::Init(VulkanResourceManager *resourceMan, Vulk graphicsPipe = false; - layout = GetResID(pCreateInfo->layout); + compLayout = GetResID(pCreateInfo->layout); + + descSetLayouts = info.m_PipelineLayout[compLayout].descSetLayouts; // need to figure out which states are valid to be NULL @@ -847,6 +1144,8 @@ void VulkanCreationInfo::PipelineLayout::Init(VulkanResourceManager *resourceMan VulkanCreationInfo &info, const VkPipelineLayoutCreateInfo *pCreateInfo) { + flags = pCreateInfo->flags; + if(pCreateInfo->pSetLayouts) { descSetLayouts.resize(pCreateInfo->setLayoutCount); diff --git a/renderdoc/driver/vulkan/vk_info.h b/renderdoc/driver/vulkan/vk_info.h index c94a056b6..add20a6a7 100644 --- a/renderdoc/driver/vulkan/vk_info.h +++ b/renderdoc/driver/vulkan/vk_info.h @@ -160,6 +160,9 @@ struct DescSetLayout uint32_t inlineCount; uint32_t inlineByteSize; + // the cummulative stageFlags for all bindings in this layout + VkShaderStageFlags anyStageFlags; + bool operator==(const DescSetLayout &other) const; bool operator!=(const DescSetLayout &other) const { return !(*this == other); } }; @@ -254,7 +257,26 @@ struct VulkanCreationInfo bool graphicsPipe = false; - ResourceId layout; + // VkGraphicsPipelineLibraryCreateInfoEXT + VkGraphicsPipelineLibraryFlagsEXT libraryFlags; + rdcarray parentLibraries; + + ResourceId compLayout; + + // these will be the same in some cases, but can be different if the application is using + // INDEPENDENT_SETS_BIT_KHR + ResourceId vertLayout; + ResourceId fragLayout; + + // this is the list of descriptor set layouts for a 'complete' pipeline. + // when vertLayout == fragLayout (i.e. no independent sets), for compute pipelines, or if only + // one is set, then this will be trivially equal to the set of layouts in the pipeline layout. + // when they are different and both non-empty, it will be the list of descriptor sets + // cherry-picked from each. Specifically all of the descriptor sets that have fragment shader + // bindings taken from the fragment layout, and then all of the remaining sets from the vertex + // layout + rdcarray descSetLayouts; + ResourceId renderpass; uint32_t subpass; @@ -415,6 +437,7 @@ struct VulkanCreationInfo void Init(VulkanResourceManager *resourceMan, VulkanCreationInfo &info, const VkPipelineLayoutCreateInfo *pCreateInfo); + VkPipelineLayoutCreateFlags flags; rdcarray pushRanges; rdcarray descSetLayouts; }; diff --git a/renderdoc/driver/vulkan/vk_next_chains.cpp b/renderdoc/driver/vulkan/vk_next_chains.cpp index 4414873f4..17e26aaff 100644 --- a/renderdoc/driver/vulkan/vk_next_chains.cpp +++ b/renderdoc/driver/vulkan/vk_next_chains.cpp @@ -168,6 +168,8 @@ static void AppendModifiedChainedStruct(byte *&tempMem, VkStruct *outputStruct, VkFragmentShadingRateAttachmentInfoKHR); \ COPY_STRUCT(VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2, VkFormatProperties2); \ COPY_STRUCT(VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_3, VkFormatProperties3); \ + COPY_STRUCT(VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_LIBRARY_CREATE_INFO_EXT, \ + VkGraphicsPipelineLibraryCreateInfoEXT); \ COPY_STRUCT(VK_STRUCTURE_TYPE_HDR_METADATA_EXT, VkHdrMetadataEXT) \ COPY_STRUCT(VK_STRUCTURE_TYPE_IMAGE_BLIT_2, VkImageBlit2); \ COPY_STRUCT(VK_STRUCTURE_TYPE_IMAGE_COPY_2, VkImageCopy2); \ @@ -254,6 +256,10 @@ static void AppendModifiedChainedStruct(byte *&tempMem, VkStruct *outputStruct, VkPhysicalDeviceFragmentShaderBarycentricFeaturesNV) \ COPY_STRUCT(VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GLOBAL_PRIORITY_QUERY_FEATURES_KHR, \ VkPhysicalDeviceGlobalPriorityQueryFeaturesKHR) \ + COPY_STRUCT(VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GRAPHICS_PIPELINE_LIBRARY_FEATURES_EXT, \ + VkPhysicalDeviceGraphicsPipelineLibraryFeaturesEXT) \ + COPY_STRUCT(VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GRAPHICS_PIPELINE_LIBRARY_PROPERTIES_EXT, \ + VkPhysicalDeviceGraphicsPipelineLibraryPropertiesEXT) \ COPY_STRUCT(VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GROUP_PROPERTIES, VkPhysicalDeviceGroupProperties) \ COPY_STRUCT(VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_FLOAT16_INT8_FEATURES, \ VkPhysicalDeviceShaderFloat16Int8Features); \ @@ -742,7 +748,6 @@ static void AppendModifiedChainedStruct(byte *&tempMem, VkStruct *outputStruct, case VK_STRUCTURE_TYPE_GEOMETRY_NV: \ case VK_STRUCTURE_TYPE_GEOMETRY_TRIANGLES_NV: \ case VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_SHADER_GROUPS_CREATE_INFO_NV: \ - case VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_LIBRARY_CREATE_INFO_EXT: \ case VK_STRUCTURE_TYPE_GRAPHICS_SHADER_GROUP_CREATE_INFO_NV: \ case VK_STRUCTURE_TYPE_HEADLESS_SURFACE_CREATE_INFO_EXT: \ case VK_STRUCTURE_TYPE_IMAGE_CONSTRAINTS_INFO_FUCHSIA: \ @@ -791,8 +796,6 @@ static void AppendModifiedChainedStruct(byte *&tempMem, VkStruct *outputStruct, case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_MEMORY_RDMA_FEATURES_NV: \ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_ENUMS_FEATURES_NV: \ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_ENUMS_PROPERTIES_NV: \ - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GRAPHICS_PIPELINE_LIBRARY_FEATURES_EXT: \ - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GRAPHICS_PIPELINE_LIBRARY_PROPERTIES_EXT: \ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_2D_VIEW_OF_3D_FEATURES_EXT: \ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_DRM_FORMAT_MODIFIER_INFO_EXT: \ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_VIEW_MIN_LOD_FEATURES_EXT: \ @@ -1076,24 +1079,51 @@ size_t GetNextPatchSize(const void *pNext) memSize += GetNextPatchSize(info->pStages[s].pNext); // need to copy the base struct of each of these so we can potentially patch pNext inside it - memSize += sizeof(*info->pVertexInputState); - memSize += GetNextPatchSize(info->pVertexInputState->pNext); - memSize += sizeof(*info->pInputAssemblyState); - memSize += GetNextPatchSize(info->pInputAssemblyState->pNext); - memSize += sizeof(*info->pTessellationState); - memSize += GetNextPatchSize(info->pTessellationState->pNext); - memSize += sizeof(*info->pViewportState); - memSize += GetNextPatchSize(info->pViewportState->pNext); - memSize += sizeof(*info->pRasterizationState); - memSize += GetNextPatchSize(info->pRasterizationState->pNext); - memSize += sizeof(*info->pMultisampleState); - memSize += GetNextPatchSize(info->pMultisampleState->pNext); - memSize += sizeof(*info->pDepthStencilState); - memSize += GetNextPatchSize(info->pDepthStencilState->pNext); - memSize += sizeof(*info->pColorBlendState); - memSize += GetNextPatchSize(info->pColorBlendState->pNext); - memSize += sizeof(*info->pDynamicState); - memSize += GetNextPatchSize(info->pDynamicState->pNext); + if(info->pVertexInputState) + { + memSize += sizeof(*info->pVertexInputState); + memSize += GetNextPatchSize(info->pVertexInputState->pNext); + } + if(info->pInputAssemblyState) + { + memSize += sizeof(*info->pInputAssemblyState); + memSize += GetNextPatchSize(info->pInputAssemblyState->pNext); + } + if(info->pTessellationState) + { + memSize += sizeof(*info->pTessellationState); + memSize += GetNextPatchSize(info->pTessellationState->pNext); + } + if(info->pViewportState) + { + memSize += sizeof(*info->pViewportState); + memSize += GetNextPatchSize(info->pViewportState->pNext); + } + if(info->pRasterizationState) + { + memSize += sizeof(*info->pRasterizationState); + memSize += GetNextPatchSize(info->pRasterizationState->pNext); + } + if(info->pMultisampleState) + { + memSize += sizeof(*info->pMultisampleState); + memSize += GetNextPatchSize(info->pMultisampleState->pNext); + } + if(info->pDepthStencilState) + { + memSize += sizeof(*info->pDepthStencilState); + memSize += GetNextPatchSize(info->pDepthStencilState->pNext); + } + if(info->pColorBlendState) + { + memSize += sizeof(*info->pColorBlendState); + memSize += GetNextPatchSize(info->pColorBlendState->pNext); + } + if(info->pDynamicState) + { + memSize += sizeof(*info->pDynamicState); + memSize += GetNextPatchSize(info->pDynamicState->pNext); + } break; } case VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO: diff --git a/renderdoc/driver/vulkan/vk_overlay.cpp b/renderdoc/driver/vulkan/vk_overlay.cpp index 99a0bf0b1..0d720cf3e 100644 --- a/renderdoc/driver/vulkan/vk_overlay.cpp +++ b/renderdoc/driver/vulkan/vk_overlay.cpp @@ -85,20 +85,20 @@ struct VulkanQuadOverdrawCallback : public VulkanActionCallback VkDescriptorSetLayout *descSetLayouts; // descSet will be the index of our new descriptor set - uint32_t descSet = - (uint32_t)m_pDriver->GetDebugManager()->GetPipelineLayoutInfo(p.layout).descSetLayouts.size(); + uint32_t descSet = (uint32_t)p.descSetLayouts.size(); descSetLayouts = new VkDescriptorSetLayout[descSet + 1]; for(uint32_t i = 0; i < descSet; i++) descSetLayouts[i] = m_pDriver->GetResourceManager()->GetCurrentHandle( - m_pDriver->GetDebugManager()->GetPipelineLayoutInfo(p.layout).descSetLayouts[i]); + p.descSetLayouts[i]); // this layout has storage image and descSetLayouts[descSet] = m_DescSetLayout; + // don't have to handle separate vert/frag layouts as push constant ranges must be identical const rdcarray &push = - m_pDriver->GetDebugManager()->GetPipelineLayoutInfo(p.layout).pushRanges; + m_pDriver->GetDebugManager()->GetPipelineLayoutInfo(p.vertLayout).pushRanges; VkPipelineLayoutCreateInfo pipeLayoutInfo = { VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, diff --git a/renderdoc/driver/vulkan/vk_postvs.cpp b/renderdoc/driver/vulkan/vk_postvs.cpp index 00dd6297e..22c632dd2 100644 --- a/renderdoc/driver/vulkan/vk_postvs.cpp +++ b/renderdoc/driver/vulkan/vk_postvs.cpp @@ -1585,7 +1585,8 @@ void VulkanReplay::FetchVSOut(uint32_t eventId, VulkanRenderState &state) // VERTEX_BIT. Find it, and make it COMPUTE_BIT VkPushConstantRange push; uint32_t numPush = 0; - rdcarray oldPush = creationInfo.m_PipelineLayout[pipeInfo.layout].pushRanges; + rdcarray oldPush = + creationInfo.m_PipelineLayout[pipeInfo.vertLayout].pushRanges; // ensure the push range is visible to the compute shader for(const VkPushConstantRange &range : oldPush) @@ -1632,7 +1633,8 @@ void VulkanReplay::FetchVSOut(uint32_t eventId, VulkanRenderState &state) // To get around this we patch descriptor set layouts at create time so that COMPUTE_BIT is // present wherever VERTEX_BIT was, so we can use the application's descriptor sets and layouts - const rdcarray &sets = creationInfo.m_PipelineLayout[pipeInfo.layout].descSetLayouts; + const rdcarray &sets = + creationInfo.m_PipelineLayout[pipeInfo.vertLayout].descSetLayouts; setLayouts.reserve(sets.size()); diff --git a/renderdoc/driver/vulkan/vk_replay.cpp b/renderdoc/driver/vulkan/vk_replay.cpp index 0e833373d..4234c1e46 100644 --- a/renderdoc/driver/vulkan/vk_replay.cpp +++ b/renderdoc/driver/vulkan/vk_replay.cpp @@ -1096,9 +1096,7 @@ void VulkanReplay::SavePipelineState(uint32_t eventId) { const VulkanCreationInfo::Pipeline &p = c.m_Pipeline[state.compute.pipeline]; - ret.compute.pipelineLayoutResourceId = rm->GetOriginalID(p.layout); - - const VulkanCreationInfo::PipelineLayout &pl = c.m_PipelineLayout[p.layout]; + ret.compute.pipelineComputeLayoutResourceId = rm->GetOriginalID(p.compLayout); ret.compute.flags = p.flags; @@ -1116,7 +1114,7 @@ void VulkanReplay::SavePipelineState(uint32_t eventId) stage.reflection = p.shaders[i].refl; stage.pushConstantRangeByteOffset = stage.pushConstantRangeByteSize = 0; - for(const VkPushConstantRange &pr : pl.pushRanges) + for(const VkPushConstantRange &pr : c.m_PipelineLayout[p.compLayout].pushRanges) { if(pr.stageFlags & VK_SHADER_STAGE_COMPUTE_BIT) { @@ -1166,7 +1164,7 @@ void VulkanReplay::SavePipelineState(uint32_t eventId) } else { - ret.compute.pipelineLayoutResourceId = ResourceId(); + ret.compute.pipelineComputeLayoutResourceId = ResourceId(); ret.compute.flags = 0; ret.computeShader = VKPipe::Shader(); } @@ -1175,9 +1173,8 @@ void VulkanReplay::SavePipelineState(uint32_t eventId) { const VulkanCreationInfo::Pipeline &p = c.m_Pipeline[state.graphics.pipeline]; - ret.graphics.pipelineLayoutResourceId = rm->GetOriginalID(p.layout); - - const VulkanCreationInfo::PipelineLayout &pl = c.m_PipelineLayout[p.layout]; + ret.graphics.pipelinePreRastLayoutResourceId = rm->GetOriginalID(p.vertLayout); + ret.graphics.pipelineFragmentLayoutResourceId = rm->GetOriginalID(p.fragLayout); ret.graphics.flags = p.flags; @@ -1235,7 +1232,8 @@ void VulkanReplay::SavePipelineState(uint32_t eventId) stages[i]->reflection = p.shaders[i].refl; stages[i]->pushConstantRangeByteOffset = stages[i]->pushConstantRangeByteSize = 0; - for(const VkPushConstantRange &pr : pl.pushRanges) + // don't have to handle separate vert/frag layouts as push constant ranges must be identical + for(const VkPushConstantRange &pr : c.m_PipelineLayout[p.vertLayout].pushRanges) { if(pr.stageFlags & ShaderMaskFromIndex(i)) { @@ -1543,7 +1541,8 @@ void VulkanReplay::SavePipelineState(uint32_t eventId) } else { - ret.graphics.pipelineLayoutResourceId = ResourceId(); + ret.graphics.pipelinePreRastLayoutResourceId = ResourceId(); + ret.graphics.pipelineFragmentLayoutResourceId = ResourceId(); ret.graphics.flags = 0; @@ -1901,6 +1900,16 @@ void VulkanReplay::SavePipelineState(uint32_t eventId) const uint32_t *srcOffset = (*srcs[p])[i].offsets.begin(); VKPipe::DescriptorSet &dst = (*dsts[p])[i]; + if(src == ResourceId()) + { + dst.inlineData.clear(); + dst.descriptorSetResourceId = ResourceId(); + dst.pushDescriptor = false; + dst.layoutResourceId = ResourceId(); + dst.bindings.clear(); + continue; + } + dst.inlineData = m_pDriver->m_DescriptorSetState[src].data.inlineBytes; curBind.bindset = (uint32_t)i; diff --git a/renderdoc/driver/vulkan/vk_serialise.cpp b/renderdoc/driver/vulkan/vk_serialise.cpp index 0be0c6942..a95f8cd9d 100644 --- a/renderdoc/driver/vulkan/vk_serialise.cpp +++ b/renderdoc/driver/vulkan/vk_serialise.cpp @@ -163,6 +163,7 @@ DECL_VKFLAG(VkSubmit); DECL_VKFLAG_EXT(VkPipelineStage, 2); DECL_VKFLAG_EXT(VkAccess, 2); DECL_VKFLAG_EXT(VkFormatFeature, 2); +DECL_VKFLAG_EXT(VkGraphicsPipelineLibrary, EXT); DECL_VKFLAG(VkRendering); // serialise a member as flags - cast to the Bits enum for serialisation so the stringification @@ -678,6 +679,14 @@ SERIALISE_VK_HANDLES(); PNEXT_STRUCT(VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADER_INTERLOCK_FEATURES_EXT, \ VkPhysicalDeviceFragmentShaderInterlockFeaturesEXT) \ \ + /* VK_EXT_graphics_pipeline_library */ \ + PNEXT_STRUCT(VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GRAPHICS_PIPELINE_LIBRARY_FEATURES_EXT, \ + VkPhysicalDeviceGraphicsPipelineLibraryFeaturesEXT) \ + PNEXT_STRUCT(VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GRAPHICS_PIPELINE_LIBRARY_PROPERTIES_EXT, \ + VkPhysicalDeviceGraphicsPipelineLibraryPropertiesEXT) \ + PNEXT_STRUCT(VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_LIBRARY_CREATE_INFO_EXT, \ + VkGraphicsPipelineLibraryCreateInfoEXT) \ + \ /* VK_EXT_hdr_metadata */ \ PNEXT_STRUCT(VK_STRUCTURE_TYPE_HDR_METADATA_EXT, VkHdrMetadataEXT) \ \ @@ -1354,11 +1363,6 @@ SERIALISE_VK_HANDLES(); PNEXT_UNSUPPORTED(VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_VIEW_MIN_LOD_FEATURES_EXT) \ PNEXT_UNSUPPORTED(VK_STRUCTURE_TYPE_IMAGE_VIEW_MIN_LOD_CREATE_INFO_EXT) \ \ - /* VK_EXT_graphics_pipeline_library */ \ - PNEXT_UNSUPPORTED(VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GRAPHICS_PIPELINE_LIBRARY_FEATURES_EXT) \ - PNEXT_UNSUPPORTED(VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GRAPHICS_PIPELINE_LIBRARY_PROPERTIES_EXT) \ - PNEXT_UNSUPPORTED(VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_LIBRARY_CREATE_INFO_EXT) \ - \ /* VK_EXT_multi_draw */ \ PNEXT_UNSUPPORTED(VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTI_DRAW_FEATURES_EXT) \ PNEXT_UNSUPPORTED(VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTI_DRAW_PROPERTIES_EXT) \ @@ -1801,10 +1805,13 @@ void DoSerialise(SerialiserType &ser, VkDebugMarkerObjectTagInfoEXT &el) template void DoSerialise(SerialiserType &ser, VkDebugUtilsObjectNameInfoEXT &el) { - RDCERR("Serialising VkDebugUtilsObjectNameInfoEXT - this should be handled specially"); + RDCASSERT(ser.IsReading() || el.sType == VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT); + SerialiseNext(ser, el.sType, el.pNext); + + SERIALISE_MEMBER(objectType); // can't handle it here without duplicating objectType logic - RDCEraseEl(el); - el.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT; + SERIALISE_MEMBER_EMPTY(objectHandle); + SERIALISE_MEMBER(pObjectName).Important(); } template <> @@ -3197,7 +3204,7 @@ void DoSerialise(SerialiserType &ser, VkGraphicsPipelineCreateInfo &el) // present. // this bool just means "we can use SERIALISE_MEMBER_OPT" - i.e. the struct is present, or NULL. - const bool hasValidRasterization = + bool hasValidRasterization = ser.IsReading() || (ser.IsWriting() && el.pRasterizationState && el.pRasterizationState->rasterizerDiscardEnable == VK_FALSE); @@ -3240,16 +3247,52 @@ void DoSerialise(SerialiserType &ser, VkGraphicsPipelineCreateInfo &el) SERIALISE_MEMBER_OPT(pRasterizationState); - if(hasValidRasterization) + bool forceMSAAState = false; + bool forceDepthState = false; + bool forceBlendState = false; + + const VkGraphicsPipelineLibraryCreateInfoEXT *graphicsLibraryCreate = + (const VkGraphicsPipelineLibraryCreateInfoEXT *)FindNextStruct( + &el, VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_LIBRARY_CREATE_INFO_EXT); + if(graphicsLibraryCreate) + { + if(graphicsLibraryCreate->flags & VK_GRAPHICS_PIPELINE_LIBRARY_FRAGMENT_SHADER_BIT_EXT) + { + forceMSAAState = true; + forceDepthState = true; + } + + if(graphicsLibraryCreate->flags & VK_GRAPHICS_PIPELINE_LIBRARY_FRAGMENT_OUTPUT_INTERFACE_BIT_EXT) + { + forceMSAAState = true; + forceBlendState = true; + } + } + + if(hasValidRasterization || forceMSAAState) { SERIALISE_MEMBER_OPT(pMultisampleState); - SERIALISE_MEMBER_OPT(pDepthStencilState); - SERIALISE_MEMBER_OPT(pColorBlendState); } else { SERIALISE_MEMBER_OPT_EMPTY(pMultisampleState); + } + + if(hasValidRasterization || forceDepthState) + { + SERIALISE_MEMBER_OPT(pDepthStencilState); + } + else + { SERIALISE_MEMBER_OPT_EMPTY(pDepthStencilState); + } + + if(hasValidRasterization || forceBlendState) + { + SERIALISE_MEMBER_OPT(pColorBlendState); + } + else + { SERIALISE_MEMBER_OPT_EMPTY(pColorBlendState); } @@ -6088,6 +6131,55 @@ void Deserialise(const VkDisplayNativeHdrSurfaceCapabilitiesAMD &el) DeserialiseNext(el.pNext); } +template +void DoSerialise(SerialiserType &ser, VkPhysicalDeviceGraphicsPipelineLibraryFeaturesEXT &el) +{ + RDCASSERT(ser.IsReading() || + el.sType == VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GRAPHICS_PIPELINE_LIBRARY_FEATURES_EXT); + SerialiseNext(ser, el.sType, el.pNext); + + SERIALISE_MEMBER(graphicsPipelineLibrary); +} + +template <> +void Deserialise(const VkPhysicalDeviceGraphicsPipelineLibraryFeaturesEXT &el) +{ + DeserialiseNext(el.pNext); +} + +template +void DoSerialise(SerialiserType &ser, VkPhysicalDeviceGraphicsPipelineLibraryPropertiesEXT &el) +{ + RDCASSERT(ser.IsReading() || + el.sType == VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GRAPHICS_PIPELINE_LIBRARY_PROPERTIES_EXT); + SerialiseNext(ser, el.sType, el.pNext); + + SERIALISE_MEMBER(graphicsPipelineLibraryFastLinking); + SERIALISE_MEMBER(graphicsPipelineLibraryIndependentInterpolationDecoration); +} + +template <> +void Deserialise(const VkPhysicalDeviceGraphicsPipelineLibraryPropertiesEXT &el) +{ + DeserialiseNext(el.pNext); +} + +template +void DoSerialise(SerialiserType &ser, VkGraphicsPipelineLibraryCreateInfoEXT &el) +{ + RDCASSERT(ser.IsReading() || + el.sType == VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_LIBRARY_CREATE_INFO_EXT); + SerialiseNext(ser, el.sType, el.pNext); + + SERIALISE_MEMBER_VKFLAGS(VkGraphicsPipelineLibraryFlagsEXT, flags); +} + +template <> +void Deserialise(const VkGraphicsPipelineLibraryCreateInfoEXT &el) +{ + DeserialiseNext(el.pNext); +} + template void DoSerialise(SerialiserType &ser, VkImageFormatListCreateInfo &el) { @@ -10309,6 +10401,7 @@ INSTANTIATE_SERIALISE_TYPE(VkFramebufferAttachmentImageInfo); INSTANTIATE_SERIALISE_TYPE(VkFramebufferAttachmentsCreateInfo); INSTANTIATE_SERIALISE_TYPE(VkFramebufferCreateInfo); INSTANTIATE_SERIALISE_TYPE(VkGraphicsPipelineCreateInfo); +INSTANTIATE_SERIALISE_TYPE(VkGraphicsPipelineLibraryCreateInfoEXT); INSTANTIATE_SERIALISE_TYPE(VkHdrMetadataEXT); INSTANTIATE_SERIALISE_TYPE(VkImageBlit2); INSTANTIATE_SERIALISE_TYPE(VkImageCopy2); @@ -10386,6 +10479,8 @@ INSTANTIATE_SERIALISE_TYPE(VkPhysicalDeviceFragmentDensityMapOffsetPropertiesQCO INSTANTIATE_SERIALISE_TYPE(VkPhysicalDeviceFragmentShaderBarycentricFeaturesNV); INSTANTIATE_SERIALISE_TYPE(VkPhysicalDeviceFragmentShaderInterlockFeaturesEXT); INSTANTIATE_SERIALISE_TYPE(VkPhysicalDeviceGlobalPriorityQueryFeaturesKHR); +INSTANTIATE_SERIALISE_TYPE(VkPhysicalDeviceGraphicsPipelineLibraryFeaturesEXT); +INSTANTIATE_SERIALISE_TYPE(VkPhysicalDeviceGraphicsPipelineLibraryPropertiesEXT); INSTANTIATE_SERIALISE_TYPE(VkPhysicalDeviceGroupProperties); INSTANTIATE_SERIALISE_TYPE(VkPhysicalDeviceHostQueryResetFeatures); INSTANTIATE_SERIALISE_TYPE(VkPhysicalDeviceFragmentShadingRateKHR); diff --git a/renderdoc/driver/vulkan/vk_shader_cache.cpp b/renderdoc/driver/vulkan/vk_shader_cache.cpp index dd5494da8..39ffd5cc2 100644 --- a/renderdoc/driver/vulkan/vk_shader_cache.cpp +++ b/renderdoc/driver/vulkan/vk_shader_cache.cpp @@ -869,13 +869,51 @@ void VulkanShaderCache::MakeGraphicsPipelineInfo(VkGraphicsPipelineCreateInfo &p &ds, &cb, &dyn, - rm->GetCurrentHandle(pipeInfo.layout), + VK_NULL_HANDLE, rm->GetCurrentHandle(pipeInfo.renderpass), pipeInfo.subpass, VK_NULL_HANDLE, // base pipeline handle 0, // base pipeline index }; + // if the layouts are the same object (non-library case) we can just use it directly + if(pipeInfo.vertLayout == pipeInfo.fragLayout) + { + ret.layout = rm->GetCurrentHandle(pipeInfo.vertLayout); + } + else + { + ret.layout = m_CombinedPipeLayouts[pipeline]; + if(ret.layout == VK_NULL_HANDLE) + { + rdcarray descSetLayouts; + + for(ResourceId setLayout : pipeInfo.descSetLayouts) + descSetLayouts.push_back(rm->GetCurrentHandle(setLayout)); + + // don't have to handle separate vert/frag layouts as push constant ranges must be identical + const VulkanCreationInfo::PipelineLayout &pipeLayoutInfo = + m_pDriver->m_CreationInfo.m_PipelineLayout[pipeInfo.vertLayout]; + const rdcarray &push = pipeLayoutInfo.pushRanges; + + VkPipelineLayoutCreateInfo pipeLayoutCreateInfo = { + VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, + NULL, + pipeLayoutInfo.flags, + (uint32_t)descSetLayouts.size(), + descSetLayouts.data(), + (uint32_t)push.size(), + push.data(), + }; + + VkResult vkr = m_pDriver->vkCreatePipelineLayout(m_pDriver->GetDev(), &pipeLayoutCreateInfo, + NULL, &m_CombinedPipeLayouts[pipeline]); + m_pDriver->CheckVkResult(vkr); + + ret.layout = m_CombinedPipeLayouts[pipeline]; + } + } + static VkFormat colFormats[16] = {}; static VkPipelineRenderingCreateInfo dynRenderCreate = { VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO, NULL, pipeInfo.viewMask, 0, colFormats, @@ -987,7 +1025,7 @@ void VulkanShaderCache::MakeComputePipelineInfo(VkComputePipelineCreateInfo &pip NULL, pipeInfo.flags, stage, - rm->GetCurrentHandle(pipeInfo.layout), + rm->GetCurrentHandle(pipeInfo.compLayout), VK_NULL_HANDLE, // base pipeline handle 0, // base pipeline index }; diff --git a/renderdoc/driver/vulkan/vk_shader_cache.h b/renderdoc/driver/vulkan/vk_shader_cache.h index 186881b8a..2aa3fb8c1 100644 --- a/renderdoc/driver/vulkan/vk_shader_cache.h +++ b/renderdoc/driver/vulkan/vk_shader_cache.h @@ -124,6 +124,10 @@ private: WrappedVulkan *m_pDriver = NULL; VkDevice m_Device = VK_NULL_HANDLE; + // combined pipeline layouts constructed out of independent set pipeline layouts, for use in a + // single combined graphics pipeline create info + std::map m_CombinedPipeLayouts; + bytebuf m_PipeCacheBlob; VkPipelineCache m_PipelineCache = VK_NULL_HANDLE; diff --git a/renderdoc/driver/vulkan/vk_shader_feedback.cpp b/renderdoc/driver/vulkan/vk_shader_feedback.cpp index a5bb16cb6..4ab4aae8f 100644 --- a/renderdoc/driver/vulkan/vk_shader_feedback.cpp +++ b/renderdoc/driver/vulkan/vk_shader_feedback.cpp @@ -1413,17 +1413,28 @@ void VulkanReplay::FetchShaderFeedback(uint32_t eventId) feedbackStorageSize += 16 + Vulkan_Debug_PrintfBufferSize() + 1024; } + ResourceId pipeLayouts[] = {pipeInfo.vertLayout, pipeInfo.fragLayout}; + if(result.compute) { - const rdcarray &descSetLayoutIds = - creationInfo.m_PipelineLayout[pipeInfo.layout].descSetLayouts; + pipeLayouts[0] = pipeInfo.compLayout; + pipeLayouts[1] = ResourceId(); + } + + if(pipeInfo.vertLayout == pipeInfo.fragLayout) + pipeLayouts[1] = ResourceId(); + + for(size_t i = 0; i < ARRAY_COUNT(pipeLayouts); i++) + { + if(pipeLayouts[i] == ResourceId()) + continue; rdcspv::Binding key; - for(size_t set = 0; set < descSetLayoutIds.size(); set++) + for(size_t set = 0; set < pipeInfo.descSetLayouts.size(); set++) { key.set = (uint32_t)set; - const DescSetLayout &layout = creationInfo.m_DescSetLayout[descSetLayoutIds[set]]; + const DescSetLayout &layout = creationInfo.m_DescSetLayout[pipeInfo.descSetLayouts[set]]; for(size_t binding = 0; binding < layout.bindings.size(); binding++) { @@ -1533,7 +1544,8 @@ void VulkanReplay::FetchShaderFeedback(uint32_t eventId) // create pipeline layout with new descriptor set layouts { const rdcarray &push = - creationInfo.m_PipelineLayout[pipeInfo.layout].pushRanges; + creationInfo.m_PipelineLayout[result.compute ? pipeInfo.compLayout : pipeInfo.vertLayout] + .pushRanges; VkPipelineLayoutCreateInfo pipeLayoutInfo = { VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, diff --git a/renderdoc/driver/vulkan/vk_shaderdebug.cpp b/renderdoc/driver/vulkan/vk_shaderdebug.cpp index bcba3e013..7153344f0 100644 --- a/renderdoc/driver/vulkan/vk_shaderdebug.cpp +++ b/renderdoc/driver/vulkan/vk_shaderdebug.cpp @@ -165,21 +165,26 @@ public: const VulkanCreationInfo::Pipeline &pipe = m_Creation.m_Pipeline[compute ? state.compute.pipeline : state.graphics.pipeline]; - const VulkanCreationInfo::PipelineLayout &pipeLayout = m_Creation.m_PipelineLayout[pipe.layout]; - for(const VkPushConstantRange &range : pipeLayout.pushRanges) { - if(range.stageFlags & stage) + // don't have to handle separate vert/frag layouts as push constant ranges must be identical + const VulkanCreationInfo::PipelineLayout &pipeLayout = + m_Creation.m_PipelineLayout[compute ? pipe.compLayout : pipe.vertLayout]; + + for(const VkPushConstantRange &range : pipeLayout.pushRanges) { - pushData.resize(RDCMAX((uint32_t)pushData.size(), range.offset + range.size)); + if(range.stageFlags & stage) + { + pushData.resize(RDCMAX((uint32_t)pushData.size(), range.offset + range.size)); - RDCASSERT(range.offset + range.size < sizeof(state.pushconsts)); + RDCASSERT(range.offset + range.size < sizeof(state.pushconsts)); - memcpy(pushData.data() + range.offset, state.pushconsts + range.offset, range.size); + memcpy(pushData.data() + range.offset, state.pushconsts + range.offset, range.size); + } } } - m_DescSets.resize(RDCMIN(descSets.size(), pipeLayout.descSetLayouts.size())); + m_DescSets.resize(RDCMIN(descSets.size(), pipe.descSetLayouts.size())); for(size_t set = 0; set < m_DescSets.size(); set++) { uint32_t dynamicOffset = 0; @@ -189,6 +194,12 @@ public: if(descSets[set].descSet == ResourceId() || descSets[set].pipeLayout == ResourceId()) continue; + const VulkanCreationInfo::PipelineLayout &pipeLayoutInfo = + m_Creation.m_PipelineLayout[descSets[set].pipeLayout]; + + if(pipeLayoutInfo.descSetLayouts[set] == ResourceId()) + continue; + DescSetSnapshot &dstSet = m_DescSets[set]; const BindingStorage &bindStorage = @@ -202,9 +213,7 @@ public: // set bind time must have been compatible and valid so we can use it. If this set *is* used // then the pipeline layout at bind time must be compatible with the pipeline's pipeline // layout, so we're fine too. - const DescSetLayout &setLayout = - m_Creation - .m_DescSetLayout[m_Creation.m_PipelineLayout[descSets[set].pipeLayout].descSetLayouts[set]]; + const DescSetLayout &setLayout = m_Creation.m_DescSetLayout[pipeLayoutInfo.descSetLayouts[set]]; for(size_t bind = 0; bind < setLayout.bindings.size(); bind++) { @@ -4304,7 +4313,8 @@ ShaderDebugTrace *VulkanReplay::DebugPixel(uint32_t eventId, uint32_t x, uint32_ } // create pipeline layout with new descriptor set layouts - const rdcarray &push = c.m_PipelineLayout[pipe.layout].pushRanges; + // don't have to handle separate vert/frag layouts as push constant ranges must be identical + const rdcarray &push = c.m_PipelineLayout[pipe.vertLayout].pushRanges; VkPipelineLayoutCreateInfo pipeLayoutInfo = { VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, diff --git a/renderdoc/driver/vulkan/vk_state.cpp b/renderdoc/driver/vulkan/vk_state.cpp index efbe0db70..4e5fb48d0 100644 --- a/renderdoc/driver/vulkan/vk_state.cpp +++ b/renderdoc/driver/vulkan/vk_state.cpp @@ -286,7 +286,8 @@ void VulkanRenderState::BindPipeline(WrappedVulkan *vk, VkCommandBuffer cmd, ObjDisp(cmd)->CmdBindPipeline(Unwrap(cmd), VK_PIPELINE_BIND_POINT_GRAPHICS, Unwrap(pipe)); - ResourceId pipeLayoutId = pipeinfo.layout; + // don't have to handle separate vert/frag layouts as push constant ranges must be identical + ResourceId pipeLayoutId = pipeinfo.vertLayout; VkPipelineLayout layout = vk->GetResourceManager()->GetCurrentHandle(pipeLayoutId); @@ -524,7 +525,7 @@ void VulkanRenderState::BindPipeline(WrappedVulkan *vk, VkCommandBuffer cmd, Unwrap(cmd), VK_PIPELINE_BIND_POINT_COMPUTE, Unwrap(vk->GetResourceManager()->GetCurrentHandle(compute.pipeline))); - ResourceId pipeLayoutId = vk->GetDebugManager()->GetPipelineInfo(compute.pipeline).layout; + ResourceId pipeLayoutId = vk->GetDebugManager()->GetPipelineInfo(compute.pipeline).compLayout; VkPipelineLayout layout = vk->GetResourceManager()->GetCurrentHandle(pipeLayoutId); @@ -544,9 +545,8 @@ void VulkanRenderState::BindPipeline(WrappedVulkan *vk, VkCommandBuffer cmd, void VulkanRenderState::BindDescriptorSets(WrappedVulkan *vk, VkCommandBuffer cmd, VulkanStatePipeline &pipe, VkPipelineBindPoint bindPoint) { - ResourceId pipeLayoutId = vk->GetDebugManager()->GetPipelineInfo(pipe.pipeline).layout; const rdcarray &descSetLayouts = - vk->GetDebugManager()->GetPipelineLayoutInfo(pipeLayoutId).descSetLayouts; + vk->GetDebugManager()->GetPipelineInfo(pipe.pipeline).descSetLayouts; for(size_t i = 0; i < descSetLayouts.size(); i++) { diff --git a/renderdoc/driver/vulkan/vk_stringise.cpp b/renderdoc/driver/vulkan/vk_stringise.cpp index c8ba0070c..197cf8ec7 100644 --- a/renderdoc/driver/vulkan/vk_stringise.cpp +++ b/renderdoc/driver/vulkan/vk_stringise.cpp @@ -2078,6 +2078,59 @@ rdcstr DoStringise(const VkStructureType &el) END_ENUM_STRINGISE(); } +template <> +rdcstr DoStringise(const VkObjectType &el) +{ + BEGIN_ENUM_STRINGISE(VkObjectType); + { + STRINGISE_ENUM(VK_OBJECT_TYPE_UNKNOWN) + STRINGISE_ENUM(VK_OBJECT_TYPE_INSTANCE) + STRINGISE_ENUM(VK_OBJECT_TYPE_PHYSICAL_DEVICE) + STRINGISE_ENUM(VK_OBJECT_TYPE_DEVICE) + STRINGISE_ENUM(VK_OBJECT_TYPE_QUEUE) + STRINGISE_ENUM(VK_OBJECT_TYPE_SEMAPHORE) + STRINGISE_ENUM(VK_OBJECT_TYPE_COMMAND_BUFFER) + STRINGISE_ENUM(VK_OBJECT_TYPE_FENCE) + STRINGISE_ENUM(VK_OBJECT_TYPE_DEVICE_MEMORY) + STRINGISE_ENUM(VK_OBJECT_TYPE_BUFFER) + STRINGISE_ENUM(VK_OBJECT_TYPE_IMAGE) + STRINGISE_ENUM(VK_OBJECT_TYPE_EVENT) + STRINGISE_ENUM(VK_OBJECT_TYPE_QUERY_POOL) + STRINGISE_ENUM(VK_OBJECT_TYPE_BUFFER_VIEW) + STRINGISE_ENUM(VK_OBJECT_TYPE_IMAGE_VIEW) + STRINGISE_ENUM(VK_OBJECT_TYPE_SHADER_MODULE) + STRINGISE_ENUM(VK_OBJECT_TYPE_PIPELINE_CACHE) + STRINGISE_ENUM(VK_OBJECT_TYPE_PIPELINE_LAYOUT) + STRINGISE_ENUM(VK_OBJECT_TYPE_RENDER_PASS) + STRINGISE_ENUM(VK_OBJECT_TYPE_PIPELINE) + STRINGISE_ENUM(VK_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT) + STRINGISE_ENUM(VK_OBJECT_TYPE_SAMPLER) + STRINGISE_ENUM(VK_OBJECT_TYPE_DESCRIPTOR_POOL) + STRINGISE_ENUM(VK_OBJECT_TYPE_DESCRIPTOR_SET) + STRINGISE_ENUM(VK_OBJECT_TYPE_FRAMEBUFFER) + STRINGISE_ENUM(VK_OBJECT_TYPE_COMMAND_POOL) + STRINGISE_ENUM(VK_OBJECT_TYPE_SAMPLER_YCBCR_CONVERSION) + STRINGISE_ENUM(VK_OBJECT_TYPE_DESCRIPTOR_UPDATE_TEMPLATE) + STRINGISE_ENUM(VK_OBJECT_TYPE_SURFACE_KHR) + STRINGISE_ENUM(VK_OBJECT_TYPE_SWAPCHAIN_KHR) + STRINGISE_ENUM(VK_OBJECT_TYPE_DISPLAY_KHR) + STRINGISE_ENUM(VK_OBJECT_TYPE_DISPLAY_MODE_KHR) + STRINGISE_ENUM(VK_OBJECT_TYPE_DEBUG_REPORT_CALLBACK_EXT) + STRINGISE_ENUM(VK_OBJECT_TYPE_CU_MODULE_NVX) + STRINGISE_ENUM(VK_OBJECT_TYPE_CU_FUNCTION_NVX) + STRINGISE_ENUM(VK_OBJECT_TYPE_DEBUG_UTILS_MESSENGER_EXT) + STRINGISE_ENUM(VK_OBJECT_TYPE_ACCELERATION_STRUCTURE_KHR) + STRINGISE_ENUM(VK_OBJECT_TYPE_VALIDATION_CACHE_EXT) + STRINGISE_ENUM(VK_OBJECT_TYPE_ACCELERATION_STRUCTURE_NV) + STRINGISE_ENUM(VK_OBJECT_TYPE_PERFORMANCE_CONFIGURATION_INTEL) + STRINGISE_ENUM(VK_OBJECT_TYPE_DEFERRED_OPERATION_KHR) + STRINGISE_ENUM(VK_OBJECT_TYPE_INDIRECT_COMMANDS_LAYOUT_NV) + STRINGISE_ENUM(VK_OBJECT_TYPE_PRIVATE_DATA_SLOT_EXT) + STRINGISE_ENUM(VK_OBJECT_TYPE_BUFFER_COLLECTION_FUCHSIA) + } + END_ENUM_STRINGISE(); +} + template <> rdcstr DoStringise(const VkComponentSwizzle &el) { @@ -3270,6 +3323,19 @@ rdcstr DoStringise(const VkFormatFeatureFlagBits2 &el) END_BITFIELD_STRINGISE(); } +template <> +rdcstr DoStringise(const VkGraphicsPipelineLibraryFlagBitsEXT &el) +{ + BEGIN_BITFIELD_STRINGISE(VkGraphicsPipelineLibraryFlagBitsEXT); + { + STRINGISE_BITFIELD_BIT(VK_GRAPHICS_PIPELINE_LIBRARY_VERTEX_INPUT_INTERFACE_BIT_EXT); + STRINGISE_BITFIELD_BIT(VK_GRAPHICS_PIPELINE_LIBRARY_PRE_RASTERIZATION_SHADERS_BIT_EXT); + STRINGISE_BITFIELD_BIT(VK_GRAPHICS_PIPELINE_LIBRARY_FRAGMENT_SHADER_BIT_EXT); + STRINGISE_BITFIELD_BIT(VK_GRAPHICS_PIPELINE_LIBRARY_FRAGMENT_OUTPUT_INTERFACE_BIT_EXT); + } + END_BITFIELD_STRINGISE(); +} + template <> rdcstr DoStringise(const VkRenderingFlagBits &el) { diff --git a/renderdoc/driver/vulkan/wrappers/vk_cmd_funcs.cpp b/renderdoc/driver/vulkan/wrappers/vk_cmd_funcs.cpp index c6aa8e938..28e73982d 100644 --- a/renderdoc/driver/vulkan/wrappers/vk_cmd_funcs.cpp +++ b/renderdoc/driver/vulkan/wrappers/vk_cmd_funcs.cpp @@ -3277,6 +3277,11 @@ bool WrappedVulkan::Serialise_vkCmdBindDescriptorSets( { descsets[firstSet + i].pipeLayout = GetResID(layout); descsets[firstSet + i].descSet = GetResID(pDescriptorSets[i]); + descsets[firstSet + i].offsets.clear(); + + if(descSetLayouts[firstSet + i] == ResourceId()) + continue; + uint32_t dynCount = m_CreationInfo.m_DescSetLayout[descSetLayouts[firstSet + i]].dynamicCount; descsets[firstSet + i].offsets.assign(offsIter, dynCount); @@ -3340,8 +3345,11 @@ void WrappedVulkan::vkCmdBindDescriptorSets(VkCommandBuffer commandBuffer, record->AddChunk(scope.Get(&record->cmdInfo->alloc)); record->MarkResourceFrameReferenced(GetResID(layout), eFrameRef_Read); for(uint32_t i = 0; i < setCount; i++) - record->cmdInfo->boundDescSets.insert( - {GetResID(pDescriptorSets[i]), GetRecord(pDescriptorSets[i])}); + { + if(pDescriptorSets[i] != VK_NULL_HANDLE) + record->cmdInfo->boundDescSets.insert( + {GetResID(pDescriptorSets[i]), GetRecord(pDescriptorSets[i])}); + } } } diff --git a/renderdoc/driver/vulkan/wrappers/vk_device_funcs.cpp b/renderdoc/driver/vulkan/wrappers/vk_device_funcs.cpp index 842ed148f..90c618a76 100644 --- a/renderdoc/driver/vulkan/wrappers/vk_device_funcs.cpp +++ b/renderdoc/driver/vulkan/wrappers/vk_device_funcs.cpp @@ -2872,6 +2872,13 @@ bool WrappedVulkan::Serialise_vkCreateDevice(SerialiserType &ser, VkPhysicalDevi } END_PHYS_EXT_CHECK(); + BEGIN_PHYS_EXT_CHECK(VkPhysicalDeviceGraphicsPipelineLibraryFeaturesEXT, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GRAPHICS_PIPELINE_LIBRARY_FEATURES_EXT); + { + CHECK_PHYS_EXT_FEATURE(graphicsPipelineLibrary); + } + END_PHYS_EXT_CHECK(); + BEGIN_PHYS_EXT_CHECK(VkPhysicalDeviceDynamicRenderingFeatures, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DYNAMIC_RENDERING_FEATURES); { diff --git a/renderdoc/driver/vulkan/wrappers/vk_shader_funcs.cpp b/renderdoc/driver/vulkan/wrappers/vk_shader_funcs.cpp index 2200378eb..d3d35a335 100644 --- a/renderdoc/driver/vulkan/wrappers/vk_shader_funcs.cpp +++ b/renderdoc/driver/vulkan/wrappers/vk_shader_funcs.cpp @@ -23,6 +23,7 @@ ******************************************************************************/ #include "../vk_core.h" +#include "../vk_replay.h" #include "driver/shaders/spirv/spirv_reflect.h" template <> @@ -157,7 +158,10 @@ bool WrappedVulkan::Serialise_vkCreatePipelineLayout(SerialiserType &ser, VkDevi AddResource(PipelineLayout, ResourceType::ShaderBinding, "Pipeline Layout"); DerivedResource(device, PipelineLayout); for(uint32_t i = 0; i < CreateInfo.setLayoutCount; i++) - DerivedResource(CreateInfo.pSetLayouts[i], PipelineLayout); + { + if(CreateInfo.pSetLayouts[i] != VK_NULL_HANDLE) + DerivedResource(CreateInfo.pSetLayouts[i], PipelineLayout); + } } return true; @@ -198,9 +202,16 @@ VkResult WrappedVulkan::vkCreatePipelineLayout(VkDevice device, for(uint32_t i = 0; i < pCreateInfo->setLayoutCount; i++) { VkResourceRecord *layoutrecord = GetRecord(pCreateInfo->pSetLayouts[i]); - record->AddParent(layoutrecord); + if(layoutrecord) + { + record->AddParent(layoutrecord); - record->pipeLayoutInfo->layouts.push_back(*layoutrecord->descInfo->layout); + record->pipeLayoutInfo->layouts.push_back(*layoutrecord->descInfo->layout); + } + else + { + record->pipeLayoutInfo->layouts.push_back(DescSetLayout()); + } } } else @@ -447,6 +458,8 @@ bool WrappedVulkan::Serialise_vkCreateGraphicsPipelines( VkResult ret = ObjDisp(device)->CreateGraphicsPipelines(Unwrap(device), Unwrap(pipelineCache), 1, unwrapped, NULL, &pipe); + AddResource(Pipeline, ResourceType::PipelineState, "Graphics Pipeline"); + if(ret != VK_SUCCESS) { RDCERR("Failed on resource serialise-creation, VkResult: %s", ToStr(ret).c_str()); @@ -472,9 +485,57 @@ bool WrappedVulkan::Serialise_vkCreateGraphicsPipelines( live = GetResourceManager()->WrapResource(Unwrap(device), pipe); GetResourceManager()->AddLiveResource(Pipeline, pipe); + VkGraphicsPipelineCreateInfo shadInstantiatedInfo = CreateInfo; + VkPipelineShaderStageCreateInfo shadInstantiations[6]; + + // search for inline shaders, and create shader modules for them so we have objects to pull + // out for recreating graphics pipelines (and to replace for shader editing) + for(uint32_t s = 0; s < shadInstantiatedInfo.stageCount; s++) + { + shadInstantiations[s] = shadInstantiatedInfo.pStages[s]; + + if(shadInstantiations[s].module == VK_NULL_HANDLE) + { + const VkShaderModuleCreateInfo *inlineShad = + (const VkShaderModuleCreateInfo *)FindNextStruct( + &shadInstantiations[s], VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO); + const VkDebugUtilsObjectNameInfoEXT *shadName = + (const VkDebugUtilsObjectNameInfoEXT *)FindNextStruct( + &shadInstantiations[s], VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT); + if(inlineShad) + { + vkCreateShaderModule(device, inlineShad, NULL, &shadInstantiations[s].module); + + // this will be a replay ID, there is no equivalent original ID + ResourceId shadId = GetResID(shadInstantiations[s].module); + + AddResource(shadId, ResourceType::Shader, "Shader Module"); + DerivedResource(device, shadId); + DerivedResource(pipe, shadId); + + const char *names[] = {" vertex shader", " tess control shader", " tess eval shader", + " geometry shader", " fragment shader"}; + + if(shadName) + GetReplay()->GetResourceDesc(shadId).SetCustomName(shadName->pObjectName); + else + GetReplay()->GetResourceDesc(shadId).name = + GetReplay()->GetResourceDesc(Pipeline).name + + names[StageIndex(shadInstantiations[s].stage)]; + } + else + { + RDCERR("NULL module in stage %s (entry %s) with no linked module create info", + ToStr(shadInstantiations[s].stage).c_str(), shadInstantiations[s].pName); + } + } + } + + shadInstantiatedInfo.pStages = shadInstantiations; + VulkanCreationInfo::Pipeline &pipeInfo = m_CreationInfo.m_Pipeline[live]; - pipeInfo.Init(GetResourceManager(), m_CreationInfo, live, &CreateInfo); + pipeInfo.Init(GetResourceManager(), m_CreationInfo, live, &shadInstantiatedInfo); ResourceId renderPassID = GetResID(CreateInfo.renderPass); @@ -498,7 +559,6 @@ bool WrappedVulkan::Serialise_vkCreateGraphicsPipelines( } } - AddResource(Pipeline, ResourceType::PipelineState, "Graphics Pipeline"); DerivedResource(device, Pipeline); if(origCache != VK_NULL_HANDLE) DerivedResource(origCache, Pipeline); @@ -512,7 +572,21 @@ bool WrappedVulkan::Serialise_vkCreateGraphicsPipelines( if(CreateInfo.layout != VK_NULL_HANDLE) DerivedResource(CreateInfo.layout, Pipeline); for(uint32_t i = 0; i < CreateInfo.stageCount; i++) - DerivedResource(CreateInfo.pStages[i].module, Pipeline); + { + if(CreateInfo.pStages[i].module != VK_NULL_HANDLE) + DerivedResource(CreateInfo.pStages[i].module, Pipeline); + } + + VkPipelineLibraryCreateInfoKHR *libraryInfo = (VkPipelineLibraryCreateInfoKHR *)FindNextStruct( + &CreateInfo, VK_STRUCTURE_TYPE_PIPELINE_LIBRARY_CREATE_INFO_KHR); + + if(libraryInfo) + { + for(uint32_t l = 0; l < libraryInfo->libraryCount; l++) + { + DerivedResource(libraryInfo->pLibraries[l], Pipeline); + } + } } return true; @@ -618,7 +692,8 @@ VkResult WrappedVulkan::vkCreateGraphicsPipelines(VkDevice device, VkPipelineCac for(uint32_t s = 0; s < pCreateInfos[i].stageCount; s++) { VkResourceRecord *modulerecord = GetRecord(pCreateInfos[i].pStages[s].module); - record->AddParent(modulerecord); + if(modulerecord) + record->AddParent(modulerecord); } VkPipelineLibraryCreateInfoKHR *libraryInfo = diff --git a/renderdoc/replay/renderdoc_serialise.inl b/renderdoc/replay/renderdoc_serialise.inl index 02bedba21..6f21c8f51 100644 --- a/renderdoc/replay/renderdoc_serialise.inl +++ b/renderdoc/replay/renderdoc_serialise.inl @@ -1992,12 +1992,14 @@ template void DoSerialise(SerialiserType &ser, VKPipe::Pipeline &el) { SERIALISE_MEMBER(pipelineResourceId); - SERIALISE_MEMBER(pipelineLayoutResourceId); + SERIALISE_MEMBER(pipelineComputeLayoutResourceId); + SERIALISE_MEMBER(pipelinePreRastLayoutResourceId); + SERIALISE_MEMBER(pipelineFragmentLayoutResourceId); SERIALISE_MEMBER(flags); SERIALISE_MEMBER(descriptorSets); - SIZE_CHECK(48); + SIZE_CHECK(64); } template @@ -2346,7 +2348,7 @@ void DoSerialise(SerialiserType &ser, VKPipe::State &el) SERIALISE_MEMBER(conditionalRendering); - SIZE_CHECK(2064); + SIZE_CHECK(2096); } #pragma endregion Vulkan pipeline state