1
0
mirror of https://github.com/doitsujin/dxvk.git synced 2025-01-19 05: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(
const DxvkDevice* device,
const Rc<DxvkPipelineCache>& 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<sync::Spinlock> 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<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);
// 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

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
*
@ -163,23 +222,18 @@ namespace dxvk {
DxvkGraphicsCommonPipelineStateInfo m_common;
sync::Spinlock m_mutex;
std::vector<PipelineStruct> m_pipelines;
sync::Spinlock m_mutex;
std::vector<Rc<DxvkGraphicsPipelineInstance>> 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;