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:
parent
c7d2957d8f
commit
010fc6ad49
@ -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
|
||||||
|
@ -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;
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user