[dxvk] Ignore spec constants that are not used by the current pipeline

May reduce the number of pipeline permutations.
This commit is contained in:
Philip Rebohle 2022-07-30 17:42:46 +02:00
parent 47794b661e
commit 94ca65d587
No known key found for this signature in database
GPG Key ID: C8CC613427A31C99
5 changed files with 112 additions and 21 deletions

View File

@ -90,6 +90,17 @@ namespace dxvk {
DxvkBindingLayoutObjects* getBindings() const {
return m_bindings;
}
/**
* \brief Queries spec constant mask
*
* This only includes user spec constants.
* \returns Bit mask of used spec constants
*/
uint32_t getSpecConstantMask() const {
constexpr uint32_t globalMask = (1u << MaxNumSpecConstants) - 1;
return m_shaders.cs->getSpecConstantMask() & globalMask;
}
/**
* \brief Retrieves pipeline handle

View File

@ -2524,24 +2524,6 @@ namespace dxvk {
}
void DxvkContext::setSpecConstant(
VkPipelineBindPoint pipeline,
uint32_t index,
uint32_t value) {
auto& specConst = pipeline == VK_PIPELINE_BIND_POINT_GRAPHICS
? m_state.gp.state.sc.specConstants[index]
: m_state.cp.state.sc.specConstants[index];
if (specConst != value) {
specConst = value;
m_flags.set(pipeline == VK_PIPELINE_BIND_POINT_GRAPHICS
? DxvkContextFlag::GpDirtyPipelineState
: DxvkContextFlag::CpDirtyPipelineState);
}
}
void DxvkContext::setBarrierControl(DxvkBarrierControlFlags control) {
m_barrierControl = control;
}
@ -4493,6 +4475,12 @@ namespace dxvk {
if (unlikely(!newPipeline))
return false;
if (unlikely(newPipeline->getSpecConstantMask() != m_state.cp.constants.mask))
this->resetSpecConstants<VK_PIPELINE_BIND_POINT_COMPUTE>(newPipeline->getSpecConstantMask());
if (m_flags.test(DxvkContextFlag::CpDirtySpecConstants))
this->updateSpecConstants<VK_PIPELINE_BIND_POINT_COMPUTE>();
// Look up Vulkan pipeline handle for the given compute state
auto pipelineHandle = newPipeline->getPipelineHandle(m_state.cp.state);
@ -4545,6 +4533,9 @@ namespace dxvk {
return false;
}
if (unlikely(newPipeline->getSpecConstantMask() != m_state.gp.constants.mask))
this->resetSpecConstants<VK_PIPELINE_BIND_POINT_GRAPHICS>(newPipeline->getSpecConstantMask());
if (m_state.gp.flags != newPipeline->flags()) {
m_state.gp.flags = newPipeline->flags();
@ -4656,6 +4647,49 @@ namespace dxvk {
}
template<VkPipelineBindPoint BindPoint>
void DxvkContext::resetSpecConstants(
uint32_t newMask) {
auto& scInfo = BindPoint == VK_PIPELINE_BIND_POINT_GRAPHICS ? m_state.gp.state.sc : m_state.cp.state.sc;
auto& scState = BindPoint == VK_PIPELINE_BIND_POINT_GRAPHICS ? m_state.gp.constants : m_state.cp.constants;
// Set all constants to 0 that were used by the previous pipeline
// but are not used by the old one. Any stale data could otherwise
// lead to unnecessary pipeline variants being created.
for (auto i : bit::BitMask(scState.mask & ~newMask))
scInfo.specConstants[i] = 0;
scState.mask = newMask;
auto flag = BindPoint == VK_PIPELINE_BIND_POINT_GRAPHICS
? DxvkContextFlag::GpDirtySpecConstants
: DxvkContextFlag::CpDirtySpecConstants;
if (newMask)
m_flags.set(flag);
else
m_flags.clr(flag);
}
template<VkPipelineBindPoint BindPoint>
void DxvkContext::updateSpecConstants() {
auto& scInfo = BindPoint == VK_PIPELINE_BIND_POINT_GRAPHICS ? m_state.gp.state.sc : m_state.cp.state.sc;
auto& scState = BindPoint == VK_PIPELINE_BIND_POINT_GRAPHICS ? m_state.gp.constants : m_state.cp.constants;
for (auto i : bit::BitMask(scState.mask))
scInfo.specConstants[i] = scState.data[i];
if (BindPoint == VK_PIPELINE_BIND_POINT_GRAPHICS) {
m_flags.clr(DxvkContextFlag::GpDirtySpecConstants);
m_flags.set(DxvkContextFlag::GpDirtyPipelineState);
} else {
m_flags.clr(DxvkContextFlag::CpDirtySpecConstants);
m_flags.set(DxvkContextFlag::CpDirtyPipelineState);
}
}
void DxvkContext::invalidateState() {
this->unbindComputePipeline();
this->unbindGraphicsPipeline();
@ -5348,7 +5382,9 @@ namespace dxvk {
bool DxvkContext::commitComputeState() {
this->spillRenderPass(false);
if (m_flags.test(DxvkContextFlag::CpDirtyPipelineState)) {
if (m_flags.any(
DxvkContextFlag::CpDirtyPipelineState,
DxvkContextFlag::CpDirtySpecConstants)) {
if (unlikely(!this->updateComputePipelineState()))
return false;
}
@ -5397,6 +5433,9 @@ namespace dxvk {
if (m_flags.test(DxvkContextFlag::GpDirtyVertexBuffers))
this->updateVertexBufferBindings();
if (m_flags.test(DxvkContextFlag::GpDirtySpecConstants))
this->updateSpecConstants<VK_PIPELINE_BIND_POINT_GRAPHICS>();
if (m_flags.test(DxvkContextFlag::GpDirtyPipelineState)) {
DxvkGlobalPipelineBarrier barrier = { };

View File

@ -1033,7 +1033,20 @@ namespace dxvk {
void setSpecConstant(
VkPipelineBindPoint pipeline,
uint32_t index,
uint32_t value);
uint32_t value) {
auto& scState = pipeline == VK_PIPELINE_BIND_POINT_GRAPHICS
? m_state.gp.constants : m_state.cp.constants;
if (scState.data[index] != value) {
scState.data[index] = value;
if (scState.mask & (1u << index)) {
m_flags.set(pipeline == VK_PIPELINE_BIND_POINT_GRAPHICS
? DxvkContextFlag::GpDirtySpecConstants
: DxvkContextFlag::CpDirtySpecConstants);
}
}
}
/**
* \brief Sets barrier control flags
@ -1347,7 +1360,14 @@ namespace dxvk {
void unbindGraphicsPipeline();
bool updateGraphicsPipeline();
bool updateGraphicsPipelineState(DxvkGlobalPipelineBarrier srcBarrier);
template<VkPipelineBindPoint BindPoint>
void resetSpecConstants(
uint32_t newMask);
template<VkPipelineBindPoint BindPoint>
void updateSpecConstants();
void invalidateState();
template<VkPipelineBindPoint BindPoint>

View File

@ -37,6 +37,7 @@ namespace dxvk {
GpDirtyStencilRef, ///< Stencil reference has changed
GpDirtyRasterizerState, ///< Cull mode and front face have changed
GpDirtyViewport, ///< Viewport state has changed
GpDirtySpecConstants, ///< Graphics spec constants are out of date
GpDynamicBlendConstants, ///< Blend constants are dynamic
GpDynamicDepthStencilState, ///< Depth-stencil state is dynamic
GpDynamicDepthBias, ///< Depth bias is dynamic
@ -47,6 +48,7 @@ namespace dxvk {
GpIndependentSets, ///< Graphics pipeline layout was created with independent sets
CpDirtyPipelineState, ///< Compute pipeline is out of date
CpDirtySpecConstants, ///< Compute spec constants are out of date
DirtyDrawBuffer, ///< Indirect argument buffer is dirty
DirtyPushConstants, ///< Push constant data has changed
@ -120,11 +122,18 @@ namespace dxvk {
};
struct DxvkSpecConstantState {
uint32_t mask = 0;
std::array<uint32_t, MaxNumSpecConstants> data = { };
};
struct DxvkGraphicsPipelineState {
DxvkGraphicsPipelineShaders shaders;
DxvkGraphicsPipelineStateInfo state;
DxvkGraphicsPipelineFlags flags;
DxvkGraphicsPipeline* pipeline = nullptr;
DxvkSpecConstantState constants;
};
@ -132,6 +141,7 @@ namespace dxvk {
DxvkComputePipelineShaders shaders;
DxvkComputePipelineStateInfo state;
DxvkComputePipeline* pipeline = nullptr;
DxvkSpecConstantState constants;
};

View File

@ -343,6 +343,17 @@ namespace dxvk {
return m_bindings;
}
/**
* \brief Queries spec constant mask
*
* This only includes user spec constants.
* \returns Bit mask of used spec constants
*/
uint32_t getSpecConstantMask() const {
constexpr uint32_t globalMask = (1u << MaxNumSpecConstants) - 1;
return m_specConstantMask & globalMask;
}
/**
* \brief Queries global resource barrier
*