Compare commits

...

2 Commits

Author SHA1 Message Date
gdkchan
dbe43c1719 Fix SSL GetCertificates with certificate ID set to All (#3727)
* Fix SSL GetCertificates with certificate ID set to All

* Fix last entry status value
2022-09-29 12:45:25 -03:00
riperiperi
f502cfaf62 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
2022-09-29 12:32:49 -03:00
4 changed files with 101 additions and 39 deletions

View File

@@ -68,6 +68,8 @@ namespace Ryujinx.Graphics.Vulkan
private bool _tfEnabled;
private bool _tfActive;
private PipelineColorBlendAttachmentState[] _storedBlend;
public ulong DrawCount { get; private set; }
public unsafe PipelineBase(VulkanRenderer gd, Device device)
@@ -104,6 +106,8 @@ namespace Ryujinx.Graphics.Vulkan
_newState.Initialize();
_newState.LineWidth = 1f;
_newState.SamplesCount = 1;
_storedBlend = new PipelineColorBlendAttachmentState[8];
}
public void Initialize()
@@ -498,13 +502,28 @@ namespace Ryujinx.Graphics.Vulkan
{
ref var vkBlend = ref _newState.Internal.ColorBlendAttachmentState[index];
vkBlend.BlendEnable = blend.Enable;
vkBlend.SrcColorBlendFactor = blend.ColorSrcFactor.Convert();
vkBlend.DstColorBlendFactor = blend.ColorDstFactor.Convert();
vkBlend.ColorBlendOp = blend.ColorOp.Convert();
vkBlend.SrcAlphaBlendFactor = blend.AlphaSrcFactor.Convert();
vkBlend.DstAlphaBlendFactor = blend.AlphaDstFactor.Convert();
vkBlend.AlphaBlendOp = blend.AlphaOp.Convert();
if (blend.Enable)
{
vkBlend.BlendEnable = blend.Enable;
vkBlend.SrcColorBlendFactor = blend.ColorSrcFactor.Convert();
vkBlend.DstColorBlendFactor = blend.ColorDstFactor.Convert();
vkBlend.ColorBlendOp = blend.ColorOp.Convert();
vkBlend.SrcAlphaBlendFactor = blend.AlphaSrcFactor.Convert();
vkBlend.DstAlphaBlendFactor = blend.AlphaDstFactor.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.BlendConstantG = blend.BlendConstant.Green;
@@ -669,8 +688,25 @@ namespace Ryujinx.Graphics.Vulkan
for (int i = 0; i < count; 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)
{

View File

@@ -257,15 +257,23 @@ namespace Ryujinx.Graphics.Vulkan
{
var blend = state.BlendDescriptors[i];
pipeline.Internal.ColorBlendAttachmentState[i] = new PipelineColorBlendAttachmentState(
blend.Enable,
blend.ColorSrcFactor.Convert(),
blend.ColorDstFactor.Convert(),
blend.ColorOp.Convert(),
blend.AlphaSrcFactor.Convert(),
blend.AlphaDstFactor.Convert(),
blend.AlphaOp.Convert(),
(ColorComponentFlags)state.ColorWriteMask[i]);
if (blend.Enable && state.ColorWriteMask[i] != 0)
{
pipeline.Internal.ColorBlendAttachmentState[i] = new PipelineColorBlendAttachmentState(
blend.Enable,
blend.ColorSrcFactor.Convert(),
blend.ColorDstFactor.Convert(),
blend.ColorOp.Convert(),
blend.AlphaSrcFactor.Convert(),
blend.AlphaDstFactor.Convert(),
blend.AlphaOp.Convert(),
(ColorComponentFlags)state.ColorWriteMask[i]);
}
else
{
pipeline.Internal.ColorBlendAttachmentState[i] = new PipelineColorBlendAttachmentState(
colorWriteMask: (ColorComponentFlags)state.ColorWriteMask[i]);
}
}
int maxAttachmentIndex = 0;

View File

@@ -181,7 +181,11 @@ namespace Ryujinx.HLE.HOS.Services.Ssl
}
}
public bool TryGetCertificates(ReadOnlySpan<CaCertificateId> ids, out CertStoreEntry[] entries)
public bool TryGetCertificates(
ReadOnlySpan<CaCertificateId> ids,
out CertStoreEntry[] entries,
out bool hasAllCertificates,
out int requiredSize)
{
lock (_lock)
{
@@ -190,7 +194,8 @@ namespace Ryujinx.HLE.HOS.Services.Ssl
throw new InvalidSystemResourceException(CertStoreTitleMissingErrorMessage);
}
bool hasAllCertificates = false;
requiredSize = 0;
hasAllCertificates = false;
foreach (CaCertificateId id in ids)
{
@@ -205,12 +210,14 @@ namespace Ryujinx.HLE.HOS.Services.Ssl
if (hasAllCertificates)
{
entries = new CertStoreEntry[_certificates.Count];
requiredSize = (_certificates.Count + 1) * Unsafe.SizeOf<BuiltInCertificateInfo>();
int i = 0;
foreach (CertStoreEntry entry in _certificates.Values)
{
entries[i++] = entry;
requiredSize += (entry.Data.Length + 3) & ~3;
}
return true;
@@ -218,6 +225,7 @@ namespace Ryujinx.HLE.HOS.Services.Ssl
else
{
entries = new CertStoreEntry[ids.Length];
requiredSize = ids.Length * Unsafe.SizeOf<BuiltInCertificateInfo>();
for (int i = 0; i < ids.Length; i++)
{
@@ -227,6 +235,7 @@ namespace Ryujinx.HLE.HOS.Services.Ssl
}
entries[i] = entry;
requiredSize += (entry.Data.Length + 3) & ~3;
}
return true;

View File

@@ -29,42 +29,40 @@ namespace Ryujinx.HLE.HOS.Services.Ssl
return ResultCode.Success;
}
private uint ComputeCertificateBufferSizeRequired(ReadOnlySpan<BuiltInCertificateManager.CertStoreEntry> entries)
{
uint totalSize = 0;
for (int i = 0; i < entries.Length; i++)
{
totalSize += (uint)Unsafe.SizeOf<BuiltInCertificateInfo>();
totalSize += (uint)entries[i].Data.Length;
}
return totalSize;
}
[CommandHipc(2)]
// GetCertificates(buffer<CaCertificateId, 5> ids) -> (u32 certificates_count, buffer<bytes, 6> certificates)
public ResultCode GetCertificates(ServiceCtx context)
{
ReadOnlySpan<CaCertificateId> ids = MemoryMarshal.Cast<byte, CaCertificateId>(context.Memory.GetSpan(context.Request.SendBuff[0].Position, (int)context.Request.SendBuff[0].Size));
if (!BuiltInCertificateManager.Instance.TryGetCertificates(ids, out BuiltInCertificateManager.CertStoreEntry[] entries))
if (!BuiltInCertificateManager.Instance.TryGetCertificates(
ids,
out BuiltInCertificateManager.CertStoreEntry[] entries,
out bool hasAllCertificates,
out int requiredSize))
{
throw new InvalidOperationException();
}
if (ComputeCertificateBufferSizeRequired(entries) > context.Request.ReceiveBuff[0].Size)
if ((uint)requiredSize > (uint)context.Request.ReceiveBuff[0].Size)
{
return ResultCode.InvalidCertBufSize;
}
int infosCount = entries.Length;
if (hasAllCertificates)
{
infosCount++;
}
using (WritableRegion region = context.Memory.GetWritableRegion(context.Request.ReceiveBuff[0].Position, (int)context.Request.ReceiveBuff[0].Size))
{
Span<byte> rawData = region.Memory.Span;
Span<BuiltInCertificateInfo> infos = MemoryMarshal.Cast<byte, BuiltInCertificateInfo>(rawData)[..entries.Length];
Span<byte> certificatesData = rawData[(Unsafe.SizeOf<BuiltInCertificateInfo>() * entries.Length)..];
Span<BuiltInCertificateInfo> infos = MemoryMarshal.Cast<byte, BuiltInCertificateInfo>(rawData)[..infosCount];
Span<byte> certificatesData = rawData[(Unsafe.SizeOf<BuiltInCertificateInfo>() * infosCount)..];
for (int i = 0; i < infos.Length; i++)
for (int i = 0; i < entries.Length; i++)
{
entries[i].Data.CopyTo(certificatesData);
@@ -78,6 +76,17 @@ namespace Ryujinx.HLE.HOS.Services.Ssl
certificatesData = certificatesData[entries[i].Data.Length..];
}
if (hasAllCertificates)
{
infos[entries.Length] = new BuiltInCertificateInfo
{
Id = CaCertificateId.All,
Status = TrustedCertStatus.Invalid,
CertificateDataSize = 0,
CertificateDataOffset = 0
};
}
}
context.ResponseData.Write(entries.Length);
@@ -91,12 +100,12 @@ namespace Ryujinx.HLE.HOS.Services.Ssl
{
ReadOnlySpan<CaCertificateId> ids = MemoryMarshal.Cast<byte, CaCertificateId>(context.Memory.GetSpan(context.Request.SendBuff[0].Position, (int)context.Request.SendBuff[0].Size));
if (!BuiltInCertificateManager.Instance.TryGetCertificates(ids, out BuiltInCertificateManager.CertStoreEntry[] entries))
if (!BuiltInCertificateManager.Instance.TryGetCertificates(ids, out _, out _, out int requiredSize))
{
throw new InvalidOperationException();
}
context.ResponseData.Write(ComputeCertificateBufferSizeRequired(entries));
context.ResponseData.Write(requiredSize);
return ResultCode.Success;
}