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:
parent
f269cde749
commit
196fefec4c
@ -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) {
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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 = { };
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user