diff --git a/src/dxvk/dxvk_compute.cpp b/src/dxvk/dxvk_compute.cpp index 50ffbd96..9341f82c 100644 --- a/src/dxvk/dxvk_compute.cpp +++ b/src/dxvk/dxvk_compute.cpp @@ -119,7 +119,7 @@ namespace dxvk { VkComputePipelineCreateInfo info = { VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO }; info.stage = *stageInfo.getStageInfos(); - info.layout = m_bindings->getPipelineLayout(); + info.layout = m_bindings->getPipelineLayout(false); info.basePipelineIndex = -1; // Time pipeline compilation for debugging purposes diff --git a/src/dxvk/dxvk_context.cpp b/src/dxvk/dxvk_context.cpp index f00fbb57..74e887aa 100644 --- a/src/dxvk/dxvk_context.cpp +++ b/src/dxvk/dxvk_context.cpp @@ -84,7 +84,8 @@ namespace dxvk { // before any draw or dispatch command is recorded. m_flags.clr( DxvkContextFlag::GpRenderPassBound, - DxvkContextFlag::GpXfbActive); + DxvkContextFlag::GpXfbActive, + DxvkContextFlag::GpIndependentSets); m_flags.set( DxvkContextFlag::GpDirtyFramebuffer, @@ -3995,6 +3996,7 @@ namespace dxvk { m_flags.set( DxvkContextFlag::GpRenderPassBound, + DxvkContextFlag::GpDirtyPipeline, DxvkContextFlag::GpDirtyPipelineState, DxvkContextFlag::GpDirtyVertexBuffers, DxvkContextFlag::GpDirtyIndexBuffer, @@ -4006,7 +4008,9 @@ namespace dxvk { DxvkContextFlag::GpDirtyDepthBounds, DxvkContextFlag::DirtyPushConstants); - m_flags.clr(DxvkContextFlag::GpRenderPassSuspended); + m_flags.clr( + DxvkContextFlag::GpRenderPassSuspended, + DxvkContextFlag::GpIndependentSets); this->renderPassBindFramebuffer( m_state.om.framebufferInfo, @@ -4470,18 +4474,21 @@ namespace dxvk { bool DxvkContext::updateGraphicsPipelineState(DxvkGlobalPipelineBarrier srcBarrier) { + bool oldIndependentSets = m_flags.test(DxvkContextFlag::GpIndependentSets); + // Set up vertex buffer strides for active bindings for (uint32_t i = 0; i < m_state.gp.state.il.bindingCount(); i++) { const uint32_t binding = m_state.gp.state.ilBindings[i].binding(); m_state.gp.state.ilBindings[i].setStride(m_state.vi.vertexStrides[binding]); } - + // Check which dynamic states need to be active. States that // are not dynamic will be invalidated in the command buffer. m_flags.clr(DxvkContextFlag::GpDynamicBlendConstants, DxvkContextFlag::GpDynamicDepthBias, DxvkContextFlag::GpDynamicDepthBounds, - DxvkContextFlag::GpDynamicStencilRef); + DxvkContextFlag::GpDynamicStencilRef, + DxvkContextFlag::GpIndependentSets); m_flags.set(m_state.gp.state.useDynamicBlendConstants() ? DxvkContextFlag::GpDynamicBlendConstants @@ -4533,8 +4540,16 @@ namespace dxvk { if (!m_state.gp.state.rs.depthBiasEnable()) m_cmd->cmdSetDepthBias(0.0f, 0.0f, 0.0f); + + m_flags.set(DxvkContextFlag::GpIndependentSets); } + // If necessary, dirty descriptor sets due to layout incompatibilities + bool newIndependentSets = m_flags.test(DxvkContextFlag::GpIndependentSets); + + if (newIndependentSets != oldIndependentSets) + m_descriptorState.dirtyStages(VK_SHADER_STAGE_ALL_GRAPHICS); + // Emit barrier based on pipeline properties, in order to avoid // accidental write-after-read hazards after the render pass. DxvkGlobalPipelineBarrier pipelineBarrier = m_state.gp.pipeline->getGlobalBarrier(m_state.gp.state); @@ -4570,6 +4585,9 @@ namespace dxvk { // For 64-bit applications, using templates is slower on some drivers. constexpr bool useDescriptorTemplates = env::is32BitHostPlatform(); + bool independentSets = BindPoint == VK_PIPELINE_BIND_POINT_GRAPHICS + && m_flags.test(DxvkContextFlag::GpIndependentSets); + uint32_t layoutSetMask = layout->getSetMask(); uint32_t dirtySetMask = BindPoint == VK_PIPELINE_BIND_POINT_GRAPHICS ? m_descriptorState.getDirtyGraphicsSets() @@ -4752,7 +4770,7 @@ namespace dxvk { uint32_t firstSet = setIndex + 1 - bindCount; m_cmd->cmdBindDescriptorSets(BindPoint, - layout->getPipelineLayout(), + layout->getPipelineLayout(independentSets), firstSet, bindCount, &sets[firstSet], 0, nullptr); @@ -5147,9 +5165,11 @@ namespace dxvk { if (!pushConstRange.size) return; - + + // Push constants should be compatible between complete and + // independent layouts, so always ask for the complete one m_cmd->cmdPushConstants( - bindings->getPipelineLayout(), + bindings->getPipelineLayout(false), pushConstRange.stageFlags, pushConstRange.offset, pushConstRange.size, diff --git a/src/dxvk/dxvk_context_state.h b/src/dxvk/dxvk_context_state.h index 762b1ab1..9694369c 100644 --- a/src/dxvk/dxvk_context_state.h +++ b/src/dxvk/dxvk_context_state.h @@ -39,6 +39,7 @@ namespace dxvk { GpDynamicDepthBias, ///< Depth bias is dynamic GpDynamicDepthBounds, ///< Depth bounds are dynamic GpDynamicStencilRef, ///< Stencil reference is dynamic + GpIndependentSets, ///< Graphics pipeline layout was created with independent sets CpDirtyPipeline, ///< Compute pipeline binding are out of date CpDirtyPipelineState, ///< Compute pipeline needs to be recompiled diff --git a/src/dxvk/dxvk_descriptor.cpp b/src/dxvk/dxvk_descriptor.cpp index fa1e1e77..112011cb 100644 --- a/src/dxvk/dxvk_descriptor.cpp +++ b/src/dxvk/dxvk_descriptor.cpp @@ -164,14 +164,14 @@ namespace dxvk { DxvkDescriptorSetMap* DxvkDescriptorPool::getSetMap( const DxvkBindingLayoutObjects* layout) { - auto pair = m_setMaps.find(layout->getPipelineLayout()); + auto pair = m_setMaps.find(layout->getPipelineLayout(false)); if (likely(pair != m_setMaps.end())) { return &pair->second; } auto iter = m_setMaps.emplace( std::piecewise_construct, - std::tuple(layout->getPipelineLayout()), + std::tuple(layout->getPipelineLayout(false)), std::tuple()); for (uint32_t i = 0; i < DxvkDescriptorSets::SetCount; i++) { diff --git a/src/dxvk/dxvk_graphics.cpp b/src/dxvk/dxvk_graphics.cpp index e651f0c5..80048c8e 100644 --- a/src/dxvk/dxvk_graphics.cpp +++ b/src/dxvk/dxvk_graphics.cpp @@ -698,10 +698,12 @@ namespace dxvk { }}; VkPipelineLibraryCreateInfoKHR libInfo = { VK_STRUCTURE_TYPE_PIPELINE_LIBRARY_CREATE_INFO_KHR }; - libInfo.libraryCount = libraries.size(); - libInfo.pLibraries = libraries.data(); + libInfo.libraryCount = libraries.size(); + libInfo.pLibraries = libraries.data(); VkGraphicsPipelineCreateInfo info = { VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, &libInfo }; + info.layout = m_bindings->getPipelineLayout(true); + info.basePipelineIndex = -1; VkPipeline pipeline = VK_NULL_HANDLE; @@ -790,7 +792,7 @@ namespace dxvk { info.pDepthStencilState = &fsState.dsInfo; info.pColorBlendState = &foState.cbInfo; info.pDynamicState = &dyInfo; - info.layout = m_bindings->getPipelineLayout(); + info.layout = m_bindings->getPipelineLayout(false); info.basePipelineIndex = -1; if (!prState.tsInfo.patchControlPoints) diff --git a/src/dxvk/dxvk_pipelayout.cpp b/src/dxvk/dxvk_pipelayout.cpp index 40736635..895b685b 100644 --- a/src/dxvk/dxvk_pipelayout.cpp +++ b/src/dxvk/dxvk_pipelayout.cpp @@ -323,29 +323,40 @@ namespace dxvk { } } + // Create pipeline layout objects VkPushConstantRange pushConst = m_layout.getPushConstantRange(); VkPipelineLayoutCreateInfo pipelineLayoutInfo = { VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO }; pipelineLayoutInfo.setLayoutCount = setLayouts.size(); pipelineLayoutInfo.pSetLayouts = setLayouts.data(); - if (m_layout.getSetMask() != (1u << DxvkDescriptorSets::SetCount) - 1) - pipelineLayoutInfo.flags = VK_PIPELINE_LAYOUT_CREATE_INDEPENDENT_SETS_BIT_EXT; - if (pushConst.stageFlags && pushConst.size) { pipelineLayoutInfo.pushConstantRangeCount = 1; pipelineLayoutInfo.pPushConstantRanges = &pushConst; } - if (vk->vkCreatePipelineLayout(vk->device(), &pipelineLayoutInfo, nullptr, &m_pipelineLayout)) - throw DxvkError("DxvkBindingLayoutObjects: Failed to create pipeline layout"); + // If the full set is defined, create a layout without INDEPENDENT_SET_BITS + if (m_layout.getSetMask() == (1u << DxvkDescriptorSets::SetCount) - 1) { + if (vk->vkCreatePipelineLayout(vk->device(), &pipelineLayoutInfo, nullptr, &m_completeLayout)) + throw DxvkError("DxvkBindingLayoutObjects: Failed to create pipeline layout"); + } + + // If graphics pipeline libraries are supported, also create a variand with the + // bit. It will be used to create shader-based libraries and link pipelines. + if (m_device->canUseGraphicsPipelineLibrary() && (m_layout.getStages() & VK_SHADER_STAGE_ALL_GRAPHICS)) { + pipelineLayoutInfo.flags = VK_PIPELINE_LAYOUT_CREATE_INDEPENDENT_SETS_BIT_EXT; + + if (vk->vkCreatePipelineLayout(vk->device(), &pipelineLayoutInfo, nullptr, &m_independentLayout)) + throw DxvkError("DxvkBindingLayoutObjects: Failed to create pipeline layout"); + } } DxvkBindingLayoutObjects::~DxvkBindingLayoutObjects() { auto vk = m_device->vkd(); - vk->vkDestroyPipelineLayout(vk->device(), m_pipelineLayout, nullptr); + vk->vkDestroyPipelineLayout(vk->device(), m_completeLayout, nullptr); + vk->vkDestroyPipelineLayout(vk->device(), m_independentLayout, nullptr); } diff --git a/src/dxvk/dxvk_pipelayout.h b/src/dxvk/dxvk_pipelayout.h index ae4ad78f..4cfcf50f 100644 --- a/src/dxvk/dxvk_pipelayout.h +++ b/src/dxvk/dxvk_pipelayout.h @@ -304,6 +304,14 @@ namespace dxvk { return m_pushConst; } + /** + * \brief Queries shader stages + * \returns Shader stages + */ + VkShaderStageFlags getStages() const { + return m_stages; + } + /** * \brief Queries defined descriptor set layouts * @@ -433,10 +441,14 @@ namespace dxvk { /** * \brief Retrieves pipeline layout - * \returns Pipeline layout + * + * \param [in] independent Request INDEPENDENT_SETS_BIT + * \returns Pipeline layout handle */ - VkPipelineLayout getPipelineLayout() const { - return m_pipelineLayout; + VkPipelineLayout getPipelineLayout(bool independent) const { + return independent + ? m_independentLayout + : m_completeLayout; } /** @@ -468,9 +480,10 @@ namespace dxvk { DxvkDevice* m_device; DxvkBindingLayout m_layout; - VkPipelineLayout m_pipelineLayout = VK_NULL_HANDLE; + VkPipelineLayout m_completeLayout = VK_NULL_HANDLE; + VkPipelineLayout m_independentLayout = VK_NULL_HANDLE; - uint32_t m_setMask = 0; + uint32_t m_setMask = 0; std::array m_bindingObjects = { }; diff --git a/src/dxvk/dxvk_shader.cpp b/src/dxvk/dxvk_shader.cpp index 361cbd9e..4ad9d063 100644 --- a/src/dxvk/dxvk_shader.cpp +++ b/src/dxvk/dxvk_shader.cpp @@ -547,7 +547,7 @@ namespace dxvk { info.pViewportState = &vpInfo; info.pRasterizationState = &rsInfo; info.pDynamicState = &dyInfo; - info.layout = m_layout->getPipelineLayout(); + info.layout = m_layout->getPipelineLayout(true); info.basePipelineIndex = -1; VkPipeline pipeline = VK_NULL_HANDLE; @@ -625,7 +625,7 @@ namespace dxvk { info.pStages = stageInfo.getStageInfos(); info.pDepthStencilState = &dsInfo; info.pDynamicState = &dyInfo; - info.layout = m_layout->getPipelineLayout(); + info.layout = m_layout->getPipelineLayout(true); info.basePipelineIndex = -1; if (m_shader && m_shader->flags().test(DxvkShaderFlag::HasSampleRateShading)) @@ -650,7 +650,7 @@ namespace dxvk { // Compile the compute pipeline as normal VkComputePipelineCreateInfo info = { VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO }; info.stage = *stageInfo.getStageInfos(); - info.layout = m_layout->getPipelineLayout(); + info.layout = m_layout->getPipelineLayout(false); info.basePipelineIndex = -1; VkPipeline pipeline = VK_NULL_HANDLE;