diff --git a/src/dxvk/dxvk_graphics.cpp b/src/dxvk/dxvk_graphics.cpp index 0962d2f9d..8d7575261 100644 --- a/src/dxvk/dxvk_graphics.cpp +++ b/src/dxvk/dxvk_graphics.cpp @@ -34,6 +34,22 @@ namespace dxvk { } + DxvkGraphicsPipelineInstance::DxvkGraphicsPipelineInstance( + const Rc& vkd, + const DxvkGraphicsPipelineStateInfo& stateVector, + VkRenderPass renderPass) + : m_vkd (vkd), + m_stateVector (stateVector), + m_renderPass (renderPass) { + + } + + + DxvkGraphicsPipelineInstance::~DxvkGraphicsPipelineInstance() { + m_vkd->vkDestroyPipeline(m_vkd->device(), m_pipeline, nullptr); + } + + DxvkGraphicsPipeline::DxvkGraphicsPipeline( const DxvkDevice* device, const Rc& cache, @@ -71,7 +87,7 @@ namespace dxvk { DxvkGraphicsPipeline::~DxvkGraphicsPipeline() { - this->destroyPipelines(); + } @@ -79,55 +95,58 @@ namespace dxvk { const DxvkGraphicsPipelineStateInfo& state, const DxvkRenderPass& renderPass, DxvkStatCounters& stats) { - VkPipeline pipeline = VK_NULL_HANDLE; VkRenderPass renderPassHandle = renderPass.getDefaultHandle(); { std::lock_guard lock(m_mutex); - if (this->findPipeline(state, renderPassHandle, pipeline)) - return pipeline; + DxvkGraphicsPipelineInstance* pipeline = + this->findInstance(state, renderPassHandle); + + if (pipeline != nullptr) + return pipeline->getPipeline(); } - // If no pipeline exists with the given state vector, - // create a new one and add it to the pipeline set. - VkPipeline newPipeline = this->validatePipelineState(state) - ? this->compilePipeline(state, renderPassHandle, m_basePipeline) - : VK_NULL_HANDLE; + // If the pipeline state vector is invalid, don't try + // to create a new pipeline, it won't work anyway. + if (!this->validatePipelineState(state)) + return VK_NULL_HANDLE; + + // If no pipeline instance exists with the given state + // vector, create a new one and add it to the list. + Rc newPipeline = + new DxvkGraphicsPipelineInstance(m_device->vkd(), state, renderPassHandle); + + newPipeline->setPipeline(this->compilePipeline( + state, renderPassHandle, VK_NULL_HANDLE)); { std::lock_guard lock(m_mutex); // Discard the pipeline if another thread // was faster compiling the same pipeline - if (this->findPipeline(state, renderPassHandle, pipeline)) { - m_vkd->vkDestroyPipeline(m_vkd->device(), newPipeline, nullptr); - return pipeline; - } + DxvkGraphicsPipelineInstance* pipeline = + this->findInstance(state, renderPassHandle); + + if (pipeline != nullptr) + return pipeline->getPipeline(); // Add new pipeline to the set - m_pipelines.push_back({ state, renderPassHandle, newPipeline }); - - if (m_basePipeline == VK_NULL_HANDLE) - m_basePipeline = newPipeline; + m_pipelines.push_back(newPipeline); stats.addCtr(DxvkStatCounter::PipeCountGraphics, 1); - return newPipeline; + return newPipeline->getPipeline(); } } - bool DxvkGraphicsPipeline::findPipeline( + DxvkGraphicsPipelineInstance* DxvkGraphicsPipeline::findInstance( const DxvkGraphicsPipelineStateInfo& state, - VkRenderPass renderPass, - VkPipeline& pipeline) const { - for (const PipelineStruct& pair : m_pipelines) { - if (pair.stateVector == state - && pair.renderPass == renderPass) { - pipeline = pair.pipeline; - return true; - } + VkRenderPass renderPass) const { + for (const auto& pipeline : m_pipelines) { + if (pipeline->isCompatible(state, renderPass)) + return pipeline.ptr(); } - return false; + return nullptr; } @@ -328,12 +347,6 @@ namespace dxvk { } - void DxvkGraphicsPipeline::destroyPipelines() { - for (const PipelineStruct& pair : m_pipelines) - m_vkd->vkDestroyPipeline(m_vkd->device(), pair.pipeline, nullptr); - } - - bool DxvkGraphicsPipeline::validatePipelineState( const DxvkGraphicsPipelineStateInfo& state) const { // Validate vertex input - each input slot consumed by the diff --git a/src/dxvk/dxvk_graphics.h b/src/dxvk/dxvk_graphics.h index cee384d96..0a02675eb 100644 --- a/src/dxvk/dxvk_graphics.h +++ b/src/dxvk/dxvk_graphics.h @@ -90,6 +90,65 @@ namespace dxvk { }; + /** + * \brief Graphics pipeline instance + * + * Stores a state vector and the corresponding + * pipeline handles. + */ + class DxvkGraphicsPipelineInstance : public RcObject { + + public: + + DxvkGraphicsPipelineInstance( + const Rc& vkd, + const DxvkGraphicsPipelineStateInfo& stateVector, + VkRenderPass renderPass); + + ~DxvkGraphicsPipelineInstance(); + + /** + * \brief Checks for matching pipeline state + * + * \param [in] stateVector Graphics pipeline state + * \param [in] renderPass Render pass handle + * \returns \c true if the specialization is compatible + */ + bool isCompatible( + const DxvkGraphicsPipelineStateInfo& stateVector, + VkRenderPass renderPass) const { + return m_renderPass == renderPass + && m_stateVector == stateVector; + } + + /** + * \brief Sets the pipeline handle + * \param [in] pipeline The pipeline + */ + void setPipeline(VkPipeline pipeline) { + m_pipeline = pipeline; + } + + /** + * \brief Retrieves pipeline + * \returns The pipeline + */ + VkPipeline getPipeline() const { + return m_pipeline; + } + + private: + + const Rc m_vkd; + + DxvkGraphicsPipelineStateInfo m_stateVector; + VkRenderPass m_renderPass; + + VkPipeline m_pipeline = VK_NULL_HANDLE; + + }; + + /** * \brief Graphics pipeline * @@ -163,23 +222,18 @@ namespace dxvk { DxvkGraphicsCommonPipelineStateInfo m_common; - sync::Spinlock m_mutex; - std::vector m_pipelines; + sync::Spinlock m_mutex; + std::vector> m_pipelines; - VkPipeline m_basePipeline = VK_NULL_HANDLE; - - bool findPipeline( + DxvkGraphicsPipelineInstance* findInstance( const DxvkGraphicsPipelineStateInfo& state, - VkRenderPass renderPass, - VkPipeline& pipeline) const; + VkRenderPass renderPass) const; VkPipeline compilePipeline( const DxvkGraphicsPipelineStateInfo& state, VkRenderPass renderPass, VkPipeline baseHandle) const; - void destroyPipelines(); - bool validatePipelineState( const DxvkGraphicsPipelineStateInfo& state) const;