1
0
mirror of https://github.com/doitsujin/dxvk.git synced 2025-01-31 14:52:11 +01:00

[dxvk] Implement DxvkGraphicsPipelineInstance

This should come in handy when compiling an optimized version of
a pipeline asynchronously. This can be extended to hold multiple
pipeline handles, i.e. one optimized one and one without opts.

Collateral damage: We're not using derivative pipelines anymore,
needs to be re-added at a later point.
This commit is contained in:
Philip Rebohle 2018-05-09 22:23:50 +02:00
parent c7d2957d8f
commit 010fc6ad49
No known key found for this signature in database
GPG Key ID: C8CC613427A31C99
2 changed files with 110 additions and 43 deletions

View File

@ -34,6 +34,22 @@ namespace dxvk {
} }
DxvkGraphicsPipelineInstance::DxvkGraphicsPipelineInstance(
const Rc<vk::DeviceFn>& 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( DxvkGraphicsPipeline::DxvkGraphicsPipeline(
const DxvkDevice* device, const DxvkDevice* device,
const Rc<DxvkPipelineCache>& cache, const Rc<DxvkPipelineCache>& cache,
@ -71,7 +87,7 @@ namespace dxvk {
DxvkGraphicsPipeline::~DxvkGraphicsPipeline() { DxvkGraphicsPipeline::~DxvkGraphicsPipeline() {
this->destroyPipelines();
} }
@ -79,55 +95,58 @@ namespace dxvk {
const DxvkGraphicsPipelineStateInfo& state, const DxvkGraphicsPipelineStateInfo& state,
const DxvkRenderPass& renderPass, const DxvkRenderPass& renderPass,
DxvkStatCounters& stats) { DxvkStatCounters& stats) {
VkPipeline pipeline = VK_NULL_HANDLE;
VkRenderPass renderPassHandle = renderPass.getDefaultHandle(); VkRenderPass renderPassHandle = renderPass.getDefaultHandle();
{ std::lock_guard<sync::Spinlock> lock(m_mutex); { std::lock_guard<sync::Spinlock> lock(m_mutex);
if (this->findPipeline(state, renderPassHandle, pipeline)) DxvkGraphicsPipelineInstance* pipeline =
return pipeline; this->findInstance(state, renderPassHandle);
if (pipeline != nullptr)
return pipeline->getPipeline();
} }
// If no pipeline exists with the given state vector, // If the pipeline state vector is invalid, don't try
// create a new one and add it to the pipeline set. // to create a new pipeline, it won't work anyway.
VkPipeline newPipeline = this->validatePipelineState(state) if (!this->validatePipelineState(state))
? this->compilePipeline(state, renderPassHandle, m_basePipeline) return VK_NULL_HANDLE;
: VK_NULL_HANDLE;
// If no pipeline instance exists with the given state
// vector, create a new one and add it to the list.
Rc<DxvkGraphicsPipelineInstance> newPipeline =
new DxvkGraphicsPipelineInstance(m_device->vkd(), state, renderPassHandle);
newPipeline->setPipeline(this->compilePipeline(
state, renderPassHandle, VK_NULL_HANDLE));
{ std::lock_guard<sync::Spinlock> lock(m_mutex); { std::lock_guard<sync::Spinlock> lock(m_mutex);
// Discard the pipeline if another thread // Discard the pipeline if another thread
// was faster compiling the same pipeline // was faster compiling the same pipeline
if (this->findPipeline(state, renderPassHandle, pipeline)) { DxvkGraphicsPipelineInstance* pipeline =
m_vkd->vkDestroyPipeline(m_vkd->device(), newPipeline, nullptr); this->findInstance(state, renderPassHandle);
return pipeline;
} if (pipeline != nullptr)
return pipeline->getPipeline();
// Add new pipeline to the set // Add new pipeline to the set
m_pipelines.push_back({ state, renderPassHandle, newPipeline }); m_pipelines.push_back(newPipeline);
if (m_basePipeline == VK_NULL_HANDLE)
m_basePipeline = newPipeline;
stats.addCtr(DxvkStatCounter::PipeCountGraphics, 1); stats.addCtr(DxvkStatCounter::PipeCountGraphics, 1);
return newPipeline; return newPipeline->getPipeline();
} }
} }
bool DxvkGraphicsPipeline::findPipeline( DxvkGraphicsPipelineInstance* DxvkGraphicsPipeline::findInstance(
const DxvkGraphicsPipelineStateInfo& state, const DxvkGraphicsPipelineStateInfo& state,
VkRenderPass renderPass, VkRenderPass renderPass) const {
VkPipeline& pipeline) const { for (const auto& pipeline : m_pipelines) {
for (const PipelineStruct& pair : m_pipelines) { if (pipeline->isCompatible(state, renderPass))
if (pair.stateVector == state return pipeline.ptr();
&& pair.renderPass == renderPass) {
pipeline = pair.pipeline;
return true;
}
} }
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( bool DxvkGraphicsPipeline::validatePipelineState(
const DxvkGraphicsPipelineStateInfo& state) const { const DxvkGraphicsPipelineStateInfo& state) const {
// Validate vertex input - each input slot consumed by the // Validate vertex input - each input slot consumed by the

View File

@ -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<vk::DeviceFn>& 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<vk::DeviceFn> m_vkd;
DxvkGraphicsPipelineStateInfo m_stateVector;
VkRenderPass m_renderPass;
VkPipeline m_pipeline = VK_NULL_HANDLE;
};
/** /**
* \brief Graphics pipeline * \brief Graphics pipeline
* *
@ -163,23 +222,18 @@ namespace dxvk {
DxvkGraphicsCommonPipelineStateInfo m_common; DxvkGraphicsCommonPipelineStateInfo m_common;
sync::Spinlock m_mutex; sync::Spinlock m_mutex;
std::vector<PipelineStruct> m_pipelines; std::vector<Rc<DxvkGraphicsPipelineInstance>> m_pipelines;
VkPipeline m_basePipeline = VK_NULL_HANDLE; DxvkGraphicsPipelineInstance* findInstance(
bool findPipeline(
const DxvkGraphicsPipelineStateInfo& state, const DxvkGraphicsPipelineStateInfo& state,
VkRenderPass renderPass, VkRenderPass renderPass) const;
VkPipeline& pipeline) const;
VkPipeline compilePipeline( VkPipeline compilePipeline(
const DxvkGraphicsPipelineStateInfo& state, const DxvkGraphicsPipelineStateInfo& state,
VkRenderPass renderPass, VkRenderPass renderPass,
VkPipeline baseHandle) const; VkPipeline baseHandle) const;
void destroyPipelines();
bool validatePipelineState( bool validatePipelineState(
const DxvkGraphicsPipelineStateInfo& state) const; const DxvkGraphicsPipelineStateInfo& state) const;