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

[dxvk] Add dirty tracking for dynamic depth-stencil state

Significantly reduces the number of API calls and potentially
context rolls when switching between different base pipelines.
This commit is contained in:
Philip Rebohle 2022-07-16 13:25:19 +02:00
parent 2fabc90f46
commit dadc1bc8ff
No known key found for this signature in database
GPG Key ID: C8CC613427A31C99
4 changed files with 84 additions and 63 deletions

View File

@ -100,6 +100,7 @@ namespace dxvk {
DxvkContextFlag::GpDirtyViewport,
DxvkContextFlag::GpDirtyDepthBias,
DxvkContextFlag::GpDirtyDepthBounds,
DxvkContextFlag::GpDirtyDepthStencilState,
DxvkContextFlag::CpDirtyPipeline,
DxvkContextFlag::CpDirtyPipelineState,
DxvkContextFlag::DirtyDrawBuffer);
@ -2437,6 +2438,12 @@ namespace dxvk {
if (!m_state.gp.state.rs.eq(rsInfo)) {
m_flags.set(DxvkContextFlag::GpDirtyPipelineState);
// Since depth bias enable is only dynamic for base pipelines,
// it is applied as part of the dynamic depth-stencil state
if (m_state.gp.state.rs.depthBiasEnable() != rs.depthBiasEnable)
m_flags.set(DxvkContextFlag::GpDirtyDepthStencilState);
m_state.gp.state.rs = rsInfo;
}
}
@ -2463,7 +2470,9 @@ namespace dxvk {
m_state.gp.state.dsFront = DxvkDsStencilOp(ds.stencilOpFront);
m_state.gp.state.dsBack = DxvkDsStencilOp(ds.stencilOpBack);
m_flags.set(DxvkContextFlag::GpDirtyPipelineState);
m_flags.set(
DxvkContextFlag::GpDirtyPipelineState,
DxvkContextFlag::GpDirtyDepthStencilState);
}
@ -4015,6 +4024,7 @@ namespace dxvk {
DxvkContextFlag::GpDirtyViewport,
DxvkContextFlag::GpDirtyDepthBias,
DxvkContextFlag::GpDirtyDepthBounds,
DxvkContextFlag::GpDirtyDepthStencilState,
DxvkContextFlag::DirtyPushConstants);
m_flags.clr(
@ -4440,7 +4450,8 @@ namespace dxvk {
DxvkContextFlag::GpDirtyRasterizerState,
DxvkContextFlag::GpDirtyViewport,
DxvkContextFlag::GpDirtyDepthBias,
DxvkContextFlag::GpDirtyDepthBounds);
DxvkContextFlag::GpDirtyDepthBounds,
DxvkContextFlag::GpDirtyDepthStencilState);
m_state.gp.pipeline = nullptr;
}
@ -4489,6 +4500,7 @@ namespace dxvk {
// Check which dynamic states need to be active. States that
// are not dynamic will be invalidated in the command buffer.
m_flags.clr(DxvkContextFlag::GpDynamicBlendConstants,
DxvkContextFlag::GpDynamicDepthStencilState,
DxvkContextFlag::GpDynamicDepthBias,
DxvkContextFlag::GpDynamicDepthBounds,
DxvkContextFlag::GpDynamicStencilRef,
@ -4499,18 +4511,6 @@ namespace dxvk {
? DxvkContextFlag::GpDynamicBlendConstants
: DxvkContextFlag::GpDirtyBlendConstants);
m_flags.set(m_state.gp.state.useDynamicDepthBias()
? DxvkContextFlag::GpDynamicDepthBias
: DxvkContextFlag::GpDirtyDepthBias);
m_flags.set(m_state.gp.state.useDynamicDepthBounds()
? DxvkContextFlag::GpDynamicDepthBounds
: DxvkContextFlag::GpDirtyDepthBounds);
m_flags.set(m_state.gp.state.useDynamicStencilRef()
? DxvkContextFlag::GpDynamicStencilRef
: DxvkContextFlag::GpDirtyStencilRef);
m_flags.set((!m_state.gp.flags.test(DxvkGraphicsPipelineFlag::HasRasterizerDiscard))
? DxvkContextFlag::GpDynamicRasterizerState
: DxvkContextFlag::GpDirtyRasterizerState);
@ -4525,43 +4525,31 @@ namespace dxvk {
VK_PIPELINE_BIND_POINT_GRAPHICS,
pipelineInfo.first);
// For pipelines created from graphics pipeline libraries, we need
// to apply a bunch of dynamic state that is otherwise static
// For pipelines created from graphics pipeline libraries, we need to
// apply a bunch of dynamic state that is otherwise static or unused
if (pipelineInfo.second == DxvkGraphicsPipelineType::BasePipeline) {
VkImageAspectFlags dsReadOnlyAspects = m_state.gp.state.rt.getDepthStencilReadOnlyAspects();
m_cmd->cmdSetDepthState(
m_state.gp.state.ds.enableDepthTest(),
m_state.gp.state.ds.enableDepthWrite() &&
!(dsReadOnlyAspects & VK_IMAGE_ASPECT_DEPTH_BIT),
m_state.gp.state.ds.depthCompareOp());
if (m_device->features().core.features.depthBounds) {
m_cmd->cmdSetDepthBoundsState(
m_state.gp.state.ds.enableDepthBoundsTest());
m_flags.set(DxvkContextFlag::GpDynamicDepthBounds);
}
VkStencilOpState dsFront = m_state.gp.state.dsFront.state();
VkStencilOpState dsBack = m_state.gp.state.dsBack.state();
if (dsReadOnlyAspects & VK_IMAGE_ASPECT_STENCIL_BIT) {
dsFront.writeMask = 0;
dsBack.writeMask = 0;
}
m_cmd->cmdSetStencilState(
m_state.gp.state.ds.enableStencilTest(),
dsFront, dsBack);
m_cmd->cmdSetDepthBiasState(
m_state.gp.state.rs.depthBiasEnable());
m_flags.set(
DxvkContextFlag::GpDynamicDepthStencilState,
DxvkContextFlag::GpDynamicDepthBias,
DxvkContextFlag::GpDynamicStencilRef,
DxvkContextFlag::GpIndependentSets);
if (m_device->features().core.features.depthBounds)
m_flags.set(DxvkContextFlag::GpDynamicDepthBounds);
} else {
m_flags.set(m_state.gp.state.useDynamicDepthBias()
? DxvkContextFlag::GpDynamicDepthBias
: DxvkContextFlag::GpDirtyDepthBias);
m_flags.set(m_state.gp.state.useDynamicDepthBounds()
? DxvkContextFlag::GpDynamicDepthBounds
: DxvkContextFlag::GpDirtyDepthBounds);
m_flags.set(m_state.gp.state.useDynamicStencilRef()
? DxvkContextFlag::GpDynamicStencilRef
: DxvkContextFlag::GpDirtyStencilRef);
m_flags.set(DxvkContextFlag::GpDirtyDepthStencilState);
}
// If necessary, dirty descriptor sets due to layout incompatibilities
@ -5181,6 +5169,39 @@ namespace dxvk {
m_cmd->cmdSetScissor(m_state.vp.viewportCount, m_state.vp.scissorRects.data());
}
if (m_flags.all(DxvkContextFlag::GpDirtyDepthStencilState,
DxvkContextFlag::GpDynamicDepthStencilState)) {
m_flags.clr(DxvkContextFlag::GpDirtyDepthStencilState);
// Make sure to not enable writes to aspects that cannot be
// written in the current depth-stencil attachment layout.
// This mirrors what we do for monolithic pipelines.
VkImageAspectFlags dsReadOnlyAspects = m_state.gp.state.rt.getDepthStencilReadOnlyAspects();
bool enableDepthWrites = !(dsReadOnlyAspects & VK_IMAGE_ASPECT_DEPTH_BIT);
bool enableStencilWrites = !(dsReadOnlyAspects & VK_IMAGE_ASPECT_STENCIL_BIT);
m_cmd->cmdSetDepthState(
m_state.gp.state.ds.enableDepthTest(),
m_state.gp.state.ds.enableDepthWrite() && enableDepthWrites,
m_state.gp.state.ds.depthCompareOp());
if (m_device->features().core.features.depthBounds) {
m_cmd->cmdSetDepthBoundsState(
m_state.gp.state.ds.enableDepthBoundsTest());
m_flags.set(DxvkContextFlag::GpDynamicDepthBounds);
}
m_cmd->cmdSetStencilState(
m_state.gp.state.ds.enableStencilTest(),
m_state.gp.state.dsFront.state(enableStencilWrites),
m_state.gp.state.dsBack.state(enableStencilWrites));
m_cmd->cmdSetDepthBiasState(
m_state.gp.state.rs.depthBiasEnable());
}
if (m_flags.all(DxvkContextFlag::GpDirtyRasterizerState,
DxvkContextFlag::GpDynamicRasterizerState)) {
m_flags.clr(DxvkContextFlag::GpDirtyRasterizerState);
@ -5333,10 +5354,11 @@ namespace dxvk {
if (m_flags.any(
DxvkContextFlag::GpDirtyViewport,
DxvkContextFlag::GpDirtyBlendConstants,
DxvkContextFlag::GpDirtyStencilRef,
DxvkContextFlag::GpDirtyDepthBias,
DxvkContextFlag::GpDirtyDepthBounds,
DxvkContextFlag::GpDirtyRasterizerState))
DxvkContextFlag::GpDirtyDepthStencilState,
DxvkContextFlag::GpDirtyRasterizerState,
DxvkContextFlag::GpDirtyStencilRef))
this->updateDynamicState();
if (m_flags.test(DxvkContextFlag::DirtyPushConstants))

View File

@ -31,12 +31,14 @@ namespace dxvk {
GpDirtyIndexBuffer, ///< Index buffer binding are out of date
GpDirtyXfbBuffers, ///< Transform feedback buffer bindings are out of date
GpDirtyBlendConstants, ///< Blend constants have changed
GpDirtyDepthStencilState, ///< Depth-stencil state has changed
GpDirtyDepthBias, ///< Depth bias has changed
GpDirtyDepthBounds, ///< Depth bounds have changed
GpDirtyStencilRef, ///< Stencil reference has changed
GpDirtyRasterizerState, ///< Cull mode and front face have changed
GpDirtyViewport, ///< Viewport state has changed
GpDynamicBlendConstants, ///< Blend constants are dynamic
GpDynamicDepthStencilState, ///< Depth-stencil state is dynamic
GpDynamicDepthBias, ///< Depth bias is dynamic
GpDynamicDepthBounds, ///< Depth bounds are dynamic
GpDynamicStencilRef, ///< Stencil reference is dynamic

View File

@ -470,21 +470,18 @@ namespace dxvk {
DxvkGraphicsPipelineFragmentShaderState::DxvkGraphicsPipelineFragmentShaderState(
const DxvkDevice* device,
const DxvkGraphicsPipelineStateInfo& state) {
VkImageAspectFlags dsReadOnlyAspects = state.rt.getDepthStencilReadOnlyAspects();
bool enableDepthWrites = !(dsReadOnlyAspects & VK_IMAGE_ASPECT_DEPTH_BIT);
bool enableStencilWrites = !(dsReadOnlyAspects & VK_IMAGE_ASPECT_STENCIL_BIT);
dsInfo.depthTestEnable = state.ds.enableDepthTest();
dsInfo.depthWriteEnable = state.ds.enableDepthWrite();
dsInfo.depthWriteEnable = state.ds.enableDepthWrite() && enableDepthWrites;
dsInfo.depthCompareOp = state.ds.depthCompareOp();
dsInfo.depthBoundsTestEnable = state.ds.enableDepthBoundsTest();
dsInfo.stencilTestEnable = state.ds.enableStencilTest();
dsInfo.front = state.dsFront.state();
dsInfo.back = state.dsBack.state();
if ((state.rt.getDepthStencilReadOnlyAspects() & VK_IMAGE_ASPECT_DEPTH_BIT))
dsInfo.depthWriteEnable = VK_FALSE;
if ((state.rt.getDepthStencilReadOnlyAspects() & VK_IMAGE_ASPECT_STENCIL_BIT)) {
dsInfo.front.writeMask = 0;
dsInfo.back.writeMask = 0;
}
dsInfo.front = state.dsFront.state(enableStencilWrites);
dsInfo.back = state.dsBack.state(enableStencilWrites);
}
@ -1162,8 +1159,8 @@ namespace dxvk {
if (state.ds.enableStencilTest()) {
std::array<VkStencilOpState, 2> states = {{
state.dsFront.state(),
state.dsBack.state(),
state.dsFront.state(true),
state.dsBack.state(true),
}};
for (size_t i = 0; i < states.size(); i++) {

View File

@ -395,14 +395,14 @@ namespace dxvk {
m_compareMask (uint32_t(state.compareMask)),
m_writeMask (uint32_t(state.writeMask)) { }
VkStencilOpState state() const {
VkStencilOpState state(bool write) const {
VkStencilOpState result;
result.failOp = VkStencilOp(m_failOp);
result.passOp = VkStencilOp(m_passOp);
result.depthFailOp = VkStencilOp(m_depthFailOp);
result.compareOp = VkCompareOp(m_compareOp);
result.compareMask = m_compareMask;
result.writeMask = m_writeMask;
result.writeMask = write ? m_writeMask : 0;
result.reference = 0;
return result;
}