diff --git a/src/dxvk/dxvk_pipemanager.cpp b/src/dxvk/dxvk_pipemanager.cpp index 7aa02b81..a2980ebc 100644 --- a/src/dxvk/dxvk_pipemanager.cpp +++ b/src/dxvk/dxvk_pipemanager.cpp @@ -268,6 +268,11 @@ namespace dxvk { void DxvkPipelineManager::registerShader( const Rc& shader) { + if (m_device->canUseGraphicsPipelineLibrary() && shader->canUsePipelineLibrary()) { + auto library = createPipelineLibrary(shader); + m_workers.compilePipelineLibrary(library); + } + m_stateCache.registerShader(shader); } @@ -320,5 +325,21 @@ namespace dxvk { std::tuple(m_device, layout, setLayouts.data())); return &iter.first->second; } + + + DxvkShaderPipelineLibrary* DxvkPipelineManager::createPipelineLibrary( + const Rc& shader) { + std::lock_guard lock(m_mutex); + auto layout = createPipelineLayout(shader->getBindings()); + + DxvkShaderPipelineLibraryKey key; + key.shader = shader; + + auto iter = m_shaderLibraries.emplace( + std::piecewise_construct, + std::tuple(key), + std::tuple(m_device, shader.ptr(), layout)); + return &iter.first->second; + } } diff --git a/src/dxvk/dxvk_pipemanager.h b/src/dxvk/dxvk_pipemanager.h index 9d643432..b10389a7 100644 --- a/src/dxvk/dxvk_pipemanager.h +++ b/src/dxvk/dxvk_pipemanager.h @@ -257,12 +257,20 @@ namespace dxvk { DxvkGraphicsPipelineFragmentOutputLibrary, DxvkHash, DxvkEq> m_fragmentOutputLibraries; + std::unordered_map< + DxvkShaderPipelineLibraryKey, + DxvkShaderPipelineLibrary, + DxvkHash, DxvkEq> m_shaderLibraries; + DxvkBindingSetLayout* createDescriptorSetLayout( const DxvkBindingSetLayoutKey& key); DxvkBindingLayoutObjects* createPipelineLayout( const DxvkBindingLayout& layout); + DxvkShaderPipelineLibrary* createPipelineLibrary( + const Rc& shader); + }; } \ No newline at end of file diff --git a/src/dxvk/dxvk_shader.cpp b/src/dxvk/dxvk_shader.cpp index aca093b2..88336505 100644 --- a/src/dxvk/dxvk_shader.cpp +++ b/src/dxvk/dxvk_shader.cpp @@ -202,6 +202,20 @@ namespace dxvk { } + bool DxvkShader::canUsePipelineLibrary() const { + // Pipeline libraries are unsupported for geometry and + // tessellation stages since we'd need to compile them + // all into one library + if (m_info.stage != VK_SHADER_STAGE_VERTEX_BIT + && m_info.stage != VK_SHADER_STAGE_FRAGMENT_BIT + && m_info.stage != VK_SHADER_STAGE_COMPUTE_BIT) + return false; + + // Ignore shaders that have user-defined spec constants + return !m_flags.test(DxvkShaderFlag::HasSpecConstants); + } + + void DxvkShader::dump(std::ostream& outputStream) const { m_code.decompress().store(outputStream); } diff --git a/src/dxvk/dxvk_shader.h b/src/dxvk/dxvk_shader.h index 56e0f6f5..0a0d29c5 100644 --- a/src/dxvk/dxvk_shader.h +++ b/src/dxvk/dxvk_shader.h @@ -150,6 +150,15 @@ namespace dxvk { const DxvkBindingLayoutObjects* layout, const DxvkShaderModuleCreateInfo& info); + /** + * \brief Tests whether this shader supports pipeline libraries + * + * This is true for any vertex, fragment, or compute shader that does not + * require additional pipeline state to be compiled into something useful. + * \returns \c true if this shader can be used with pipeline libraries + */ + bool canUsePipelineLibrary() const; + /** * \brief Dumps SPIR-V shader * @@ -305,6 +314,22 @@ namespace dxvk { }; + /** + * \brief Shader pipeline library key + */ + struct DxvkShaderPipelineLibraryKey { + Rc shader; + + bool eq(const DxvkShaderPipelineLibraryKey& other) const { + return shader == other.shader; + } + + size_t hash() const { + return DxvkShader::getHash(shader); + } + }; + + /** * \brief Shader pipeline library *