1
0
mirror of https://github.com/doitsujin/dxvk.git synced 2024-12-05 01:24:14 +01:00

[dxvk] Enable dynamic multisample state if supported by the device

Eliminates stutter in situations where sample rate shading is used with MSAA.
This commit is contained in:
Philip Rebohle 2023-01-06 20:53:28 +01:00
parent f269cde749
commit 196fefec4c
6 changed files with 120 additions and 26 deletions

View File

@ -798,7 +798,13 @@ namespace dxvk {
m_vkd->vkCmdUpdateBuffer(getCmdBuffer(cmdBuffer),
dstBuffer, dstOffset, dataSize, pData);
}
void cmdSetAlphaToCoverageState(
VkBool32 alphaToCoverageEnable) {
m_vkd->vkCmdSetAlphaToCoverageEnableEXT(m_cmd.execBuffer, alphaToCoverageEnable);
}
void cmdSetBlendConstants(const float blendConstants[4]) {
m_vkd->vkCmdSetBlendConstants(m_cmd.execBuffer, blendConstants);
@ -868,6 +874,14 @@ namespace dxvk {
}
void cmdSetMultisampleState(
VkSampleCountFlagBits sampleCount,
VkSampleMask sampleMask) {
m_vkd->vkCmdSetRasterizationSamplesEXT(m_cmd.execBuffer, sampleCount);
m_vkd->vkCmdSetSampleMaskEXT(m_cmd.execBuffer, sampleCount, &sampleMask);
}
void cmdSetRasterizerState(
VkCullModeFlags cullMode,
VkFrontFace frontFace) {

View File

@ -2465,8 +2465,11 @@ namespace dxvk {
m_flags.set(DxvkContextFlag::GpDirtyRasterizerState);
}
if (unlikely(!m_features.test(DxvkContextFeature::VariableMultisampleRate))) {
if (rs.sampleCount != m_state.gp.state.rs.sampleCount())
if (unlikely(rs.sampleCount != m_state.gp.state.rs.sampleCount())) {
if (!m_state.gp.state.ms.sampleCount())
m_flags.set(DxvkContextFlag::GpDirtyMultisampleState);
if (!m_features.test(DxvkContextFeature::VariableMultisampleRate))
m_flags.set(DxvkContextFlag::GpDirtyFramebuffer);
}
@ -2497,7 +2500,9 @@ namespace dxvk {
ms.sampleMask,
ms.enableAlphaToCoverage);
m_flags.set(DxvkContextFlag::GpDirtyPipelineState);
m_flags.set(
DxvkContextFlag::GpDirtyPipelineState,
DxvkContextFlag::GpDirtyMultisampleState);
}
@ -4382,6 +4387,7 @@ namespace dxvk {
DxvkContextFlag::GpDirtyXfbBuffers,
DxvkContextFlag::GpDirtyBlendConstants,
DxvkContextFlag::GpDirtyStencilRef,
DxvkContextFlag::GpDirtyMultisampleState,
DxvkContextFlag::GpDirtyRasterizerState,
DxvkContextFlag::GpDirtyViewport,
DxvkContextFlag::GpDirtyDepthBias,
@ -4810,6 +4816,7 @@ namespace dxvk {
DxvkContextFlag::GpDirtyXfbBuffers,
DxvkContextFlag::GpDirtyBlendConstants,
DxvkContextFlag::GpDirtyStencilRef,
DxvkContextFlag::GpDirtyMultisampleState,
DxvkContextFlag::GpDirtyRasterizerState,
DxvkContextFlag::GpDirtyViewport,
DxvkContextFlag::GpDirtyDepthBias,
@ -4873,6 +4880,7 @@ namespace dxvk {
DxvkContextFlag::GpDynamicDepthBias,
DxvkContextFlag::GpDynamicDepthBounds,
DxvkContextFlag::GpDynamicStencilRef,
DxvkContextFlag::GpDynamicMultisampleState,
DxvkContextFlag::GpDynamicRasterizerState,
DxvkContextFlag::GpIndependentSets);
@ -4905,6 +4913,10 @@ namespace dxvk {
if (m_device->features().core.features.depthBounds)
m_flags.set(DxvkContextFlag::GpDynamicDepthBounds);
if (m_device->features().extExtendedDynamicState3.extendedDynamicState3RasterizationSamples
&& m_device->features().extExtendedDynamicState3.extendedDynamicState3SampleMask)
m_flags.set(DxvkContextFlag::GpDynamicMultisampleState);
} else {
m_flags.set(m_state.gp.state.useDynamicDepthBias()
? DxvkContextFlag::GpDynamicDepthBias
@ -4918,7 +4930,9 @@ namespace dxvk {
? DxvkContextFlag::GpDynamicStencilRef
: DxvkContextFlag::GpDirtyStencilRef);
m_flags.set(DxvkContextFlag::GpDirtyDepthStencilState);
m_flags.set(
DxvkContextFlag::GpDirtyDepthStencilState,
DxvkContextFlag::GpDirtyMultisampleState);
}
// If necessary, dirty descriptor sets due to layout incompatibilities
@ -5616,6 +5630,27 @@ namespace dxvk {
}
}
if (unlikely(m_flags.all(DxvkContextFlag::GpDirtyMultisampleState,
DxvkContextFlag::GpDynamicMultisampleState))) {
m_flags.clr(DxvkContextFlag::GpDirtyMultisampleState);
// Infer actual sample count from both the multisample state
// and rasterizer state, just like during pipeline creation
VkSampleCountFlagBits sampleCount = VkSampleCountFlagBits(m_state.gp.state.ms.sampleCount());
if (!sampleCount) {
sampleCount = m_state.gp.state.rs.sampleCount()
? VkSampleCountFlagBits(m_state.gp.state.rs.sampleCount())
: VK_SAMPLE_COUNT_1_BIT;
}
VkSampleMask sampleMask = m_state.gp.state.ms.sampleMask() & ((1u << sampleCount) - 1u);
m_cmd->cmdSetMultisampleState(sampleCount, sampleMask);
if (m_device->features().extExtendedDynamicState3.extendedDynamicState3AlphaToCoverageEnable)
m_cmd->cmdSetAlphaToCoverageState(m_state.gp.state.ms.enableAlphaToCoverage());
}
if (unlikely(m_flags.all(DxvkContextFlag::GpDirtyBlendConstants,
DxvkContextFlag::GpDynamicBlendConstants))) {
m_flags.clr(DxvkContextFlag::GpDirtyBlendConstants);
@ -6210,6 +6245,7 @@ namespace dxvk {
DxvkContextFlag::GpDirtyXfbBuffers,
DxvkContextFlag::GpDirtyBlendConstants,
DxvkContextFlag::GpDirtyStencilRef,
DxvkContextFlag::GpDirtyMultisampleState,
DxvkContextFlag::GpDirtyRasterizerState,
DxvkContextFlag::GpDirtyViewport,
DxvkContextFlag::GpDirtyDepthBias,

View File

@ -35,6 +35,7 @@ namespace dxvk {
GpDirtyDepthBias, ///< Depth bias has changed
GpDirtyDepthBounds, ///< Depth bounds have changed
GpDirtyStencilRef, ///< Stencil reference has changed
GpDirtyMultisampleState, ///< Multisample state has changed
GpDirtyRasterizerState, ///< Cull mode and front face have changed
GpDirtyViewport, ///< Viewport state has changed
GpDirtySpecConstants, ///< Graphics spec constants are out of date
@ -43,6 +44,7 @@ namespace dxvk {
GpDynamicDepthBias, ///< Depth bias is dynamic
GpDynamicDepthBounds, ///< Depth bounds are dynamic
GpDynamicStencilRef, ///< Stencil reference is dynamic
GpDynamicMultisampleState, ///< Multisample state is dynamic
GpDynamicRasterizerState, ///< Cull mode and front face are dynamic
GpDynamicVertexStrides, ///< Vertex buffer strides are dynamic
GpIndependentSets, ///< Graphics pipeline layout was created with independent sets

View File

@ -288,12 +288,13 @@ namespace dxvk {
// Set up multisample state based on shader info as well
// as rasterization state and render target sample counts.
if (state.ms.sampleCount())
msInfo.rasterizationSamples = VkSampleCountFlagBits(state.ms.sampleCount());
else if (state.rs.sampleCount())
msInfo.rasterizationSamples = VkSampleCountFlagBits(state.rs.sampleCount());
else
msInfo.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
msInfo.rasterizationSamples = VkSampleCountFlagBits(state.ms.sampleCount());
if (!msInfo.rasterizationSamples) {
msInfo.rasterizationSamples = state.rs.sampleCount()
? VkSampleCountFlagBits(state.rs.sampleCount())
: VK_SAMPLE_COUNT_1_BIT;
}
if (fs && fs->flags().test(DxvkShaderFlag::HasSampleRateShading)) {
msInfo.sampleShadingEnable = VK_TRUE;
@ -392,12 +393,26 @@ namespace dxvk {
: m_device(device) {
auto vk = m_device->vkd();
VkDynamicState dynamicState = VK_DYNAMIC_STATE_BLEND_CONSTANTS;
uint32_t dynamicStateCount = 0;
std::array<VkDynamicState, 4> dynamicStates = { };
if (m_device->features().extExtendedDynamicState3.extendedDynamicState3RasterizationSamples
&& m_device->features().extExtendedDynamicState3.extendedDynamicState3SampleMask) {
dynamicStates[dynamicStateCount++] = VK_DYNAMIC_STATE_RASTERIZATION_SAMPLES_EXT;
dynamicStates[dynamicStateCount++] = VK_DYNAMIC_STATE_SAMPLE_MASK_EXT;
if (device->features().extExtendedDynamicState3.extendedDynamicState3AlphaToCoverageEnable)
dynamicStates[dynamicStateCount++] = VK_DYNAMIC_STATE_ALPHA_TO_COVERAGE_ENABLE_EXT;
}
if (state.cbUseDynamicBlendConstants)
dynamicStates[dynamicStateCount++] = VK_DYNAMIC_STATE_BLEND_CONSTANTS;
VkPipelineDynamicStateCreateInfo dyInfo = { VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO };
if (state.cbUseDynamicBlendConstants) {
dyInfo.dynamicStateCount = 1;
dyInfo.pDynamicStates = &dynamicState;
if (dynamicStateCount) {
dyInfo.dynamicStateCount = dynamicStateCount;
dyInfo.pDynamicStates = dynamicStates.data();
}
VkPipelineCreateFlags flags = VK_PIPELINE_CREATE_LIBRARY_BIT_KHR;
@ -1095,12 +1110,23 @@ namespace dxvk {
if (state.rs.flatShading() && m_shaders.fs->info().flatShadingInputs)
return false;
// Multisample state must match in this case, and the
// library assumes that MSAA is disabled in this case.
// If dynamic multisample state is not supported and sample shading
// is enabled, the library is compiled with a sample count of 1.
if (m_shaders.fs->flags().test(DxvkShaderFlag::HasSampleRateShading)) {
if (state.ms.sampleCount() != VK_SAMPLE_COUNT_1_BIT
|| state.ms.sampleMask() == 0
|| state.ms.enableAlphaToCoverage())
bool canUseDynamicMultisampleState =
m_device->features().extExtendedDynamicState3.extendedDynamicState3RasterizationSamples &&
m_device->features().extExtendedDynamicState3.extendedDynamicState3SampleMask;
bool canUseDynamicAlphaToCoverage = canUseDynamicMultisampleState &&
m_device->features().extExtendedDynamicState3.extendedDynamicState3AlphaToCoverageEnable;
if (!canUseDynamicMultisampleState
&& (state.ms.sampleCount() != VK_SAMPLE_COUNT_1_BIT
|| state.ms.sampleMask() == 0))
return false;
if (!canUseDynamicAlphaToCoverage
&& (state.ms.enableAlphaToCoverage()))
return false;
}
}

View File

@ -113,7 +113,7 @@ namespace dxvk {
VkPipelineColorBlendStateCreateInfo cbInfo = { VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO };
VkPipelineMultisampleStateCreateInfo msInfo = { VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO };
uint32_t msSampleMask = 0u;
VkSampleMask msSampleMask = 0u;
VkBool32 cbUseDynamicBlendConstants = VK_FALSE;
std::array<VkPipelineColorBlendAttachmentState, MaxNumRenderTargets> cbAttachments = { };

View File

@ -1151,7 +1151,7 @@ namespace dxvk {
// Set up dynamic state. We do not know any pipeline state
// at this time, so make as much state dynamic as we can.
uint32_t dynamicStateCount = 0;
std::array<VkDynamicState, 10> dynamicStates;
std::array<VkDynamicState, 13> dynamicStates;
dynamicStates[dynamicStateCount++] = VK_DYNAMIC_STATE_DEPTH_TEST_ENABLE;
dynamicStates[dynamicStateCount++] = VK_DYNAMIC_STATE_DEPTH_WRITE_ENABLE;
@ -1167,6 +1167,19 @@ namespace dxvk {
dynamicStates[dynamicStateCount++] = VK_DYNAMIC_STATE_DEPTH_BOUNDS;
}
bool hasSampleRateShading = m_shader && m_shader->flags().test(DxvkShaderFlag::HasSampleRateShading);
bool hasDynamicMultisampleState = hasSampleRateShading
&& m_device->features().extExtendedDynamicState3.extendedDynamicState3RasterizationSamples
&& m_device->features().extExtendedDynamicState3.extendedDynamicState3SampleMask;
if (hasDynamicMultisampleState) {
dynamicStates[dynamicStateCount++] = VK_DYNAMIC_STATE_RASTERIZATION_SAMPLES_EXT;
dynamicStates[dynamicStateCount++] = VK_DYNAMIC_STATE_SAMPLE_MASK_EXT;
if (m_device->features().extExtendedDynamicState3.extendedDynamicState3AlphaToCoverageEnable)
dynamicStates[dynamicStateCount++] = VK_DYNAMIC_STATE_ALPHA_TO_COVERAGE_ENABLE_EXT;
}
VkPipelineDynamicStateCreateInfo dyInfo = { VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO };
dyInfo.dynamicStateCount = dynamicStateCount;
dyInfo.pDynamicStates = dynamicStates.data();
@ -1174,14 +1187,17 @@ namespace dxvk {
// Set up multisample state. If sample shading is enabled, assume that
// we only have one sample enabled, with a non-zero sample mask and no
// alpha-to-coverage.
uint32_t msSampleMask = 0x1;
VkSampleMask msSampleMask = 0x1;
VkPipelineMultisampleStateCreateInfo msInfo = { VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO };
msInfo.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
msInfo.pSampleMask = &msSampleMask;
msInfo.sampleShadingEnable = VK_TRUE;
msInfo.minSampleShading = 1.0f;
if (!hasDynamicMultisampleState) {
msInfo.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
msInfo.pSampleMask = &msSampleMask;
}
// All depth-stencil state is dynamic, so no need to initialize this.
// Depth bounds testing is disabled on devices which don't support it.
VkPipelineDepthStencilStateCreateInfo dsInfo = { VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO };
@ -1201,7 +1217,7 @@ namespace dxvk {
info.layout = m_layout->getPipelineLayout(true);
info.basePipelineIndex = -1;
if (m_shader && m_shader->flags().test(DxvkShaderFlag::HasSampleRateShading))
if (hasSampleRateShading)
info.pMultisampleState = &msInfo;
VkPipeline pipeline = VK_NULL_HANDLE;