Vulkan: Zero blend state when disabled or write mask is 0 (#3719)
* Zero blend state when disabled or write mask is 0 Any difference in the blend state when blend is disabled is meaningless, but Ryujinx would compare different disabled blends and compile them as separate pipelines. This change ensures that all pipelines where blend state is meaningless record it as such, which avoids compiling a bunch of pipelines that are essentially identical. The NVIDIA driver is pretty forgiving when it comes to silly pipeline misses like this, but other drivers don't offer the same level of kindness. This should reduce stuttering on those drivers, and might improve overall performance very slightly due to less pipeline variants being in the hash table. * Fix blend possibly being wrong when an attachment is unmasked
This commit is contained in:
parent
1fd5cf2b4a
commit
f502cfaf62
2 changed files with 61 additions and 17 deletions
|
@ -68,6 +68,8 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
private bool _tfEnabled;
|
private bool _tfEnabled;
|
||||||
private bool _tfActive;
|
private bool _tfActive;
|
||||||
|
|
||||||
|
private PipelineColorBlendAttachmentState[] _storedBlend;
|
||||||
|
|
||||||
public ulong DrawCount { get; private set; }
|
public ulong DrawCount { get; private set; }
|
||||||
|
|
||||||
public unsafe PipelineBase(VulkanRenderer gd, Device device)
|
public unsafe PipelineBase(VulkanRenderer gd, Device device)
|
||||||
|
@ -104,6 +106,8 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
_newState.Initialize();
|
_newState.Initialize();
|
||||||
_newState.LineWidth = 1f;
|
_newState.LineWidth = 1f;
|
||||||
_newState.SamplesCount = 1;
|
_newState.SamplesCount = 1;
|
||||||
|
|
||||||
|
_storedBlend = new PipelineColorBlendAttachmentState[8];
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Initialize()
|
public void Initialize()
|
||||||
|
@ -498,6 +502,8 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
{
|
{
|
||||||
ref var vkBlend = ref _newState.Internal.ColorBlendAttachmentState[index];
|
ref var vkBlend = ref _newState.Internal.ColorBlendAttachmentState[index];
|
||||||
|
|
||||||
|
if (blend.Enable)
|
||||||
|
{
|
||||||
vkBlend.BlendEnable = blend.Enable;
|
vkBlend.BlendEnable = blend.Enable;
|
||||||
vkBlend.SrcColorBlendFactor = blend.ColorSrcFactor.Convert();
|
vkBlend.SrcColorBlendFactor = blend.ColorSrcFactor.Convert();
|
||||||
vkBlend.DstColorBlendFactor = blend.ColorDstFactor.Convert();
|
vkBlend.DstColorBlendFactor = blend.ColorDstFactor.Convert();
|
||||||
|
@ -505,6 +511,19 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
vkBlend.SrcAlphaBlendFactor = blend.AlphaSrcFactor.Convert();
|
vkBlend.SrcAlphaBlendFactor = blend.AlphaSrcFactor.Convert();
|
||||||
vkBlend.DstAlphaBlendFactor = blend.AlphaDstFactor.Convert();
|
vkBlend.DstAlphaBlendFactor = blend.AlphaDstFactor.Convert();
|
||||||
vkBlend.AlphaBlendOp = blend.AlphaOp.Convert();
|
vkBlend.AlphaBlendOp = blend.AlphaOp.Convert();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
vkBlend = new PipelineColorBlendAttachmentState(
|
||||||
|
colorWriteMask: vkBlend.ColorWriteMask);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (vkBlend.ColorWriteMask == 0)
|
||||||
|
{
|
||||||
|
_storedBlend[index] = vkBlend;
|
||||||
|
|
||||||
|
vkBlend = new PipelineColorBlendAttachmentState();
|
||||||
|
}
|
||||||
|
|
||||||
_newState.BlendConstantR = blend.BlendConstant.Red;
|
_newState.BlendConstantR = blend.BlendConstant.Red;
|
||||||
_newState.BlendConstantG = blend.BlendConstant.Green;
|
_newState.BlendConstantG = blend.BlendConstant.Green;
|
||||||
|
@ -669,8 +688,25 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
for (int i = 0; i < count; i++)
|
for (int i = 0; i < count; i++)
|
||||||
{
|
{
|
||||||
ref var vkBlend = ref _newState.Internal.ColorBlendAttachmentState[i];
|
ref var vkBlend = ref _newState.Internal.ColorBlendAttachmentState[i];
|
||||||
|
var newMask = (ColorComponentFlags)componentMask[i];
|
||||||
|
|
||||||
vkBlend.ColorWriteMask = (ColorComponentFlags)componentMask[i];
|
// When color write mask is 0, remove all blend state to help the pipeline cache.
|
||||||
|
// Restore it when the mask becomes non-zero.
|
||||||
|
if (vkBlend.ColorWriteMask != newMask)
|
||||||
|
{
|
||||||
|
if (newMask == 0)
|
||||||
|
{
|
||||||
|
_storedBlend[i] = vkBlend;
|
||||||
|
|
||||||
|
vkBlend = new PipelineColorBlendAttachmentState();
|
||||||
|
}
|
||||||
|
else if (vkBlend.ColorWriteMask == 0)
|
||||||
|
{
|
||||||
|
vkBlend = _storedBlend[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
vkBlend.ColorWriteMask = newMask;
|
||||||
|
|
||||||
if (componentMask[i] != 0)
|
if (componentMask[i] != 0)
|
||||||
{
|
{
|
||||||
|
|
|
@ -257,6 +257,8 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
{
|
{
|
||||||
var blend = state.BlendDescriptors[i];
|
var blend = state.BlendDescriptors[i];
|
||||||
|
|
||||||
|
if (blend.Enable && state.ColorWriteMask[i] != 0)
|
||||||
|
{
|
||||||
pipeline.Internal.ColorBlendAttachmentState[i] = new PipelineColorBlendAttachmentState(
|
pipeline.Internal.ColorBlendAttachmentState[i] = new PipelineColorBlendAttachmentState(
|
||||||
blend.Enable,
|
blend.Enable,
|
||||||
blend.ColorSrcFactor.Convert(),
|
blend.ColorSrcFactor.Convert(),
|
||||||
|
@ -267,6 +269,12 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
blend.AlphaOp.Convert(),
|
blend.AlphaOp.Convert(),
|
||||||
(ColorComponentFlags)state.ColorWriteMask[i]);
|
(ColorComponentFlags)state.ColorWriteMask[i]);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pipeline.Internal.ColorBlendAttachmentState[i] = new PipelineColorBlendAttachmentState(
|
||||||
|
colorWriteMask: (ColorComponentFlags)state.ColorWriteMask[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int maxAttachmentIndex = 0;
|
int maxAttachmentIndex = 0;
|
||||||
for (int i = 0; i < 8; i++)
|
for (int i = 0; i < 8; i++)
|
||||||
|
|
Reference in a new issue