Compare commits

...

2 Commits

Author SHA1 Message Date
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
gdkchan
1fd5cf2b4a Fix ListOpenContextStoredUsers and stub LoadOpenContext (#3718)
* Fix ListOpenContextStoredUsers and stub LoadOpenContext

* Remove nonsensical comment
2022-09-27 21:24:52 -03:00
6 changed files with 93 additions and 32 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

@@ -22,7 +22,8 @@ namespace Ryujinx.HLE.HOS.Services.Account.Acc
// outside of the AccountManager.
private readonly HorizonClient _horizonClient;
private ConcurrentDictionary<string, UserProfile> _profiles;
private readonly ConcurrentDictionary<string, UserProfile> _profiles;
private UserProfile[] _storedOpenedUsers;
public UserProfile LastOpenedUser { get; private set; }
@@ -31,6 +32,7 @@ namespace Ryujinx.HLE.HOS.Services.Account.Acc
_horizonClient = horizonClient;
_profiles = new ConcurrentDictionary<string, UserProfile>();
_storedOpenedUsers = Array.Empty<UserProfile>();
_accountSaveDataManager = new AccountSaveDataManager(_profiles);
@@ -44,9 +46,9 @@ namespace Ryujinx.HLE.HOS.Services.Account.Acc
}
else
{
UserId commandLineUserProfileOverride = default;
UserId commandLineUserProfileOverride = default;
if (!string.IsNullOrEmpty(initialProfileName))
{
{
commandLineUserProfileOverride = _profiles.Values.FirstOrDefault(x => x.Name == initialProfileName)?.UserId ?? default;
if (commandLineUserProfileOverride.IsNull)
Logger.Warning?.Print(LogClass.Application, $"The command line specified profile named '{initialProfileName}' was not found");
@@ -221,6 +223,16 @@ namespace Ryujinx.HLE.HOS.Services.Account.Acc
return _profiles.Values.Where(x => x.AccountState == AccountState.Open);
}
internal IEnumerable<UserProfile> GetStoredOpenedUsers()
{
return _storedOpenedUsers;
}
internal void StoreOpenedUsers()
{
_storedOpenedUsers = _profiles.Values.Where(x => x.AccountState == AccountState.Open).ToArray();
}
internal UserProfile GetFirst()
{
return _profiles.First().Value;

View File

@@ -162,7 +162,7 @@ namespace Ryujinx.HLE.HOS.Services.Account.Acc.AccountService
public ResultCode StoreOpenContext(ServiceCtx context)
{
Logger.Stub?.PrintStub(LogClass.ServiceAcc);
context.Device.System.AccountManager.StoreOpenedUsers();
return ResultCode.Success;
}

View File

@@ -201,6 +201,11 @@ namespace Ryujinx.HLE.HOS.Services.Account.Acc
return ResultCode.Success;
}
public ResultCode ListOpenContextStoredUsers(ServiceCtx context)
{
return WriteUserList(context, context.Device.System.AccountManager.GetStoredOpenedUsers());
}
public ResultCode ListQualifiedUsers(ServiceCtx context)
{
// TODO: Determine how users are "qualified". We assume all users are "qualified" for now.

View File

@@ -1,5 +1,4 @@
using Ryujinx.Common.Logging;
using Ryujinx.Cpu;
using Ryujinx.HLE.HOS.Services.Account.Acc.AccountService;
using Ryujinx.HLE.HOS.Services.Arp;
@@ -139,20 +138,21 @@ namespace Ryujinx.HLE.HOS.Services.Account.Acc
return _applicationServiceServer.ClearSaveDataThumbnail(context);
}
[CommandHipc(130)] // 5.0.0+
// LoadOpenContext(nn::account::Uid)
public ResultCode LoadOpenContext(ServiceCtx context)
{
Logger.Stub?.PrintStub(LogClass.ServiceAcc);
return ResultCode.Success;
}
[CommandHipc(60)] // 5.0.0-5.1.0
[CommandHipc(131)] // 6.0.0+
// ListOpenContextStoredUsers() -> array<nn::account::Uid, 0xa>
public ResultCode ListOpenContextStoredUsers(ServiceCtx context)
{
ulong outputPosition = context.Request.RecvListBuff[0].Position;
ulong outputSize = context.Request.RecvListBuff[0].Size;
MemoryHelper.FillWithZeros(context.Memory, outputPosition, (int)outputSize);
// TODO: This seems to write stored userids of the OpenContext in the buffer. We needs to determine them.
Logger.Stub?.PrintStub(LogClass.ServiceAcc);
return ResultCode.Success;
return _applicationServiceServer.ListOpenContextStoredUsers(context);
}
[CommandHipc(141)] // 6.0.0+