From f17b772c56cf73ac539b4c8c47e0a7c8f29dae5a Mon Sep 17 00:00:00 2001 From: Ac_K Date: Fri, 20 Sep 2019 01:49:05 +0200 Subject: [PATCH] audren: Fix AudioRenderer implementation (#773) * Fix AudioRenderer implementation According to RE: - `GetAudioRendererWorkBufferSize` is updated and improved to support `REV7` - `RequestUpdateAudioRenderer` is updated to `REV7` too Should improve results on recent game and close #718 and #707 * Fix NodeStates.GetWorkBufferSize * Use BitUtils instead of IntUtils * Nits --- .../AudioRendererCommon.cs | 9 ++ .../AudioRendererManager/BehaviorInfo.cs | 30 +++++ .../AudioRendererManager/CommandGenerator.cs | 16 +++ .../Audio/AudioRendererManager/EdgeMatrix.cs | 19 +++ .../AudioRendererManager/IAudioRenderer.cs | 35 ++++-- .../Audio/AudioRendererManager/NodeStates.cs | 19 +++ .../PerformanceManager.cs | 30 +++++ .../AudioRendererManager/SplitterContext.cs | 25 ++++ .../AudioRendererManager/Types/AudioConsts.cs | 8 -- .../Types/AudioRendererConsts.cs | 17 +++ .../Types/AudioRendererParameter.cs | 4 +- .../AudioRendererManager/Types/SupportTags.cs | 11 ++ .../Types/UpdateDataHeader.cs | 2 +- .../AudioRendererManager/VoiceContext.cs | 12 +- .../Services/Audio/IAudioRendererManager.cs | 117 ++++++------------ 15 files changed, 244 insertions(+), 110 deletions(-) create mode 100644 Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/AudioRendererCommon.cs create mode 100644 Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/BehaviorInfo.cs create mode 100644 Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/CommandGenerator.cs create mode 100644 Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/EdgeMatrix.cs create mode 100644 Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/NodeStates.cs create mode 100644 Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/PerformanceManager.cs create mode 100644 Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/SplitterContext.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/Types/AudioConsts.cs create mode 100644 Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/Types/AudioRendererConsts.cs create mode 100644 Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/Types/SupportTags.cs diff --git a/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/AudioRendererCommon.cs b/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/AudioRendererCommon.cs new file mode 100644 index 000000000..c884b4650 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/AudioRendererCommon.cs @@ -0,0 +1,9 @@ +namespace Ryujinx.HLE.HOS.Services.Audio.AudioRendererManager +{ + static class AudioRendererCommon + { + public static bool CheckValidRevision(AudioRendererParameter parameters) => GetRevisionVersion(parameters.Revision) <= AudioRendererConsts.Revision; + public static bool CheckFeatureSupported(int revision, int supportedRevision) => revision >= supportedRevision; + public static int GetRevisionVersion(int revision) => (revision - AudioRendererConsts.Rev0Magic) >> 24; + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/BehaviorInfo.cs b/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/BehaviorInfo.cs new file mode 100644 index 000000000..461e43370 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/BehaviorInfo.cs @@ -0,0 +1,30 @@ +namespace Ryujinx.HLE.HOS.Services.Audio.AudioRendererManager +{ + class BehaviorInfo + { + private const int _revision = AudioRendererConsts.Revision; + + private int _userRevision = 0; + + public BehaviorInfo() + { + /* TODO: this class got a size of 0xC0 + 0x00 - uint - Internal Revision + 0x04 - uint - User Revision + 0x08 - ... unknown ... + */ + } + + public bool IsSplitterSupported() => AudioRendererCommon.CheckFeatureSupported(_userRevision, SupportTags.Splitter); + public bool IsSplitterBugFixed() => AudioRendererCommon.CheckFeatureSupported(_userRevision, SupportTags.SplitterBugFix); + public bool IsVariadicCommandBufferSizeSupported() => AudioRendererCommon.CheckFeatureSupported(_userRevision, SupportTags.VariadicCommandBufferSize); + public bool IsElapsedFrameCountSupported() => AudioRendererCommon.CheckFeatureSupported(_userRevision, SupportTags.ElapsedFrameCount); + + public int GetPerformanceMetricsDataFormat() => AudioRendererCommon.CheckFeatureSupported(_userRevision, SupportTags.PerformanceMetricsDataFormatVersion2) ? 2 : 1; + + public void SetUserLibRevision(int revision) + { + _userRevision = AudioRendererCommon.GetRevisionVersion(revision); + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/CommandGenerator.cs b/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/CommandGenerator.cs new file mode 100644 index 000000000..b09b990b6 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/CommandGenerator.cs @@ -0,0 +1,16 @@ +namespace Ryujinx.HLE.HOS.Services.Audio.AudioRendererManager +{ + static class CommandGenerator + { + public static long CalculateCommandBufferSize(AudioRendererParameter parameters) + { + return parameters.EffectCount * 0x840 + + parameters.SubMixCount * 0x5A38 + + parameters.SinkCount * 0x148 + + parameters.SplitterDestinationDataCount * 0x540 + + (parameters.SplitterCount * 0x68 + 0x2E0) * parameters.VoiceCount + + ((parameters.VoiceCount + parameters.SubMixCount + parameters.EffectCount + parameters.SinkCount + 0x65) << 6) + + 0x3F8; + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/EdgeMatrix.cs b/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/EdgeMatrix.cs new file mode 100644 index 000000000..3f87ae04f --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/EdgeMatrix.cs @@ -0,0 +1,19 @@ +using Ryujinx.Common; + +namespace Ryujinx.HLE.HOS.Services.Audio.AudioRendererManager +{ + static class EdgeMatrix + { + public static int GetWorkBufferSize(int totalMixCount) + { + int size = BitUtils.AlignUp(totalMixCount * totalMixCount, AudioRendererConsts.BufferAlignment); + + if (size < 0) + { + size |= 7; + } + + return size / 8; + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/IAudioRenderer.cs b/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/IAudioRenderer.cs index 975992aa9..0075fd5f0 100644 --- a/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/IAudioRenderer.cs +++ b/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/IAudioRenderer.cs @@ -51,8 +51,8 @@ namespace Ryujinx.HLE.HOS.Services.Audio.AudioRendererManager _params = Params; _track = audioOut.OpenTrack( - AudioConsts.HostSampleRate, - AudioConsts.HostChannelsCount, + AudioRendererConsts.HostSampleRate, + AudioRendererConsts.HostChannelsCount, AudioCallback); _memoryPools = CreateArray(Params.EffectCount + Params.VoiceCount * 4); @@ -86,7 +86,7 @@ namespace Ryujinx.HLE.HOS.Services.Audio.AudioRendererManager // GetMixBufferCount() -> u32 public ResultCode GetMixBufferCount(ServiceCtx context) { - context.ResponseData.Write(_params.MixCount); + context.ResponseData.Write(_params.SubMixCount); return ResultCode.Success; } @@ -145,6 +145,10 @@ namespace Ryujinx.HLE.HOS.Services.Audio.AudioRendererManager UpdateDataHeader inputHeader = reader.Read(); + BehaviorInfo behaviorInfo = new BehaviorInfo(); + + behaviorInfo.SetUserLibRevision(inputHeader.Revision); + reader.Read(inputHeader.BehaviorSize); MemoryPoolIn[] memoryPoolsIn = reader.Read(inputHeader.MemoryPoolSize); @@ -207,20 +211,27 @@ namespace Ryujinx.HLE.HOS.Services.Audio.AudioRendererManager int updateHeaderSize = Marshal.SizeOf(); - outputHeader.Revision = IAudioRendererManager.RevMagic; + outputHeader.Revision = AudioRendererConsts.RevMagic; outputHeader.BehaviorSize = 0xb0; outputHeader.MemoryPoolSize = (_params.EffectCount + _params.VoiceCount * 4) * 0x10; outputHeader.VoiceSize = _params.VoiceCount * 0x10; outputHeader.EffectSize = _params.EffectCount * 0x10; outputHeader.SinkSize = _params.SinkCount * 0x20; outputHeader.PerformanceManagerSize = 0x10; - outputHeader.TotalSize = updateHeaderSize + - outputHeader.BehaviorSize + - outputHeader.MemoryPoolSize + - outputHeader.VoiceSize + - outputHeader.EffectSize + - outputHeader.SinkSize + - outputHeader.PerformanceManagerSize; + + if (behaviorInfo.IsElapsedFrameCountSupported()) + { + outputHeader.ElapsedFrameCountInfoSize = 0x10; + } + + outputHeader.TotalSize = updateHeaderSize + + outputHeader.BehaviorSize + + outputHeader.MemoryPoolSize + + outputHeader.VoiceSize + + outputHeader.EffectSize + + outputHeader.SinkSize + + outputHeader.PerformanceManagerSize + + outputHeader.ElapsedFrameCountInfoSize; writer.Write(outputHeader); @@ -305,7 +316,7 @@ namespace Ryujinx.HLE.HOS.Services.Audio.AudioRendererManager private void AppendMixedBuffer(long tag) { - int[] mixBuffer = new int[MixBufferSamplesCount * AudioConsts.HostChannelsCount]; + int[] mixBuffer = new int[MixBufferSamplesCount * AudioRendererConsts.HostChannelsCount]; foreach (VoiceContext voice in _voices) { diff --git a/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/NodeStates.cs b/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/NodeStates.cs new file mode 100644 index 000000000..7ae9aeea5 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/NodeStates.cs @@ -0,0 +1,19 @@ +using Ryujinx.Common; + +namespace Ryujinx.HLE.HOS.Services.Audio.AudioRendererManager +{ + static class NodeStates + { + public static long GetWorkBufferSize(int totalMixCount) + { + int size = BitUtils.AlignUp(totalMixCount, AudioRendererConsts.BufferAlignment); + + if (size < 0) + { + size |= 7; + } + + return 4 * (totalMixCount * totalMixCount) + 12 * totalMixCount + 2 * (size / 8); + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/PerformanceManager.cs b/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/PerformanceManager.cs new file mode 100644 index 000000000..1b8c8a7cc --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/PerformanceManager.cs @@ -0,0 +1,30 @@ +using Ryujinx.Common.Logging; + +namespace Ryujinx.HLE.HOS.Services.Audio.AudioRendererManager +{ + static class PerformanceManager + { + public static long GetRequiredBufferSizeForPerformanceMetricsPerFrame(BehaviorInfo behaviorInfo, AudioRendererParameter parameters) + { + int performanceMetricsDataFormat = behaviorInfo.GetPerformanceMetricsDataFormat(); + + if (performanceMetricsDataFormat == 2) + { + return 24 * (parameters.VoiceCount + + parameters.EffectCount + + parameters.SubMixCount + + parameters.SinkCount + 1) + 0x990; + } + + if (performanceMetricsDataFormat != 1) + { + Logger.PrintWarning(LogClass.ServiceAudio, $"PerformanceMetricsDataFormat: {performanceMetricsDataFormat} is not supported!"); + } + + return (((parameters.VoiceCount + + parameters.EffectCount + + parameters.SubMixCount + + parameters.SinkCount + 1) << 32) >> 0x1C) + 0x658; + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/SplitterContext.cs b/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/SplitterContext.cs new file mode 100644 index 000000000..e46af4432 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/SplitterContext.cs @@ -0,0 +1,25 @@ +using Ryujinx.Common; + +namespace Ryujinx.HLE.HOS.Services.Audio.AudioRendererManager +{ + class SplitterContext + { + public static long CalcWorkBufferSize(BehaviorInfo behaviorInfo, AudioRendererParameter parameters) + { + if (!behaviorInfo.IsSplitterSupported()) + { + return 0; + } + + long size = parameters.SplitterDestinationDataCount * 0xE0 + + parameters.SplitterCount * 0x20; + + if (!behaviorInfo.IsSplitterBugFixed()) + { + size += BitUtils.AlignUp(4 * parameters.SplitterDestinationDataCount, 16); + } + + return size; + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/Types/AudioConsts.cs b/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/Types/AudioConsts.cs deleted file mode 100644 index f3b6995c7..000000000 --- a/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/Types/AudioConsts.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace Ryujinx.HLE.HOS.Services.Audio.AudioRendererManager -{ - static class AudioConsts - { - public const int HostSampleRate = 48000; - public const int HostChannelsCount = 2; - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/Types/AudioRendererConsts.cs b/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/Types/AudioRendererConsts.cs new file mode 100644 index 000000000..7e8b89bd2 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/Types/AudioRendererConsts.cs @@ -0,0 +1,17 @@ +namespace Ryujinx.HLE.HOS.Services.Audio.AudioRendererManager +{ + static class AudioRendererConsts + { + // Revision Consts + public const int Revision = 7; + public const int Rev0Magic = ('R' << 0) | ('E' << 8) | ('V' << 16) | ('0' << 24); + public const int RevMagic = Rev0Magic + (Revision << 24); + + // Misc Consts + public const int BufferAlignment = 0x40; + + // Host Consts + public const int HostSampleRate = 48000; + public const int HostChannelsCount = 2; + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/Types/AudioRendererParameter.cs b/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/Types/AudioRendererParameter.cs index 9772f786a..2cfbc4b70 100644 --- a/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/Types/AudioRendererParameter.cs +++ b/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/Types/AudioRendererParameter.cs @@ -7,8 +7,8 @@ namespace Ryujinx.HLE.HOS.Services.Audio.AudioRendererManager { public int SampleRate; public int SampleCount; - public int Unknown8; - public int MixCount; + public int MixBufferCount; + public int SubMixCount; public int VoiceCount; public int SinkCount; public int EffectCount; diff --git a/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/Types/SupportTags.cs b/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/Types/SupportTags.cs new file mode 100644 index 000000000..a418d89e6 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/Types/SupportTags.cs @@ -0,0 +1,11 @@ +namespace Ryujinx.HLE.HOS.Services.Audio.AudioRendererManager +{ + static class SupportTags + { + public const int Splitter = 2; + public const int SplitterBugFix = 5; + public const int PerformanceMetricsDataFormatVersion2 = 5; + public const int VariadicCommandBufferSize = 5; + public const int ElapsedFrameCount = 5; + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/Types/UpdateDataHeader.cs b/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/Types/UpdateDataHeader.cs index b1f149843..1c5b2903f 100644 --- a/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/Types/UpdateDataHeader.cs +++ b/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/Types/UpdateDataHeader.cs @@ -12,7 +12,7 @@ public int SinkSize; public int PerformanceManagerSize; public int Unknown24; - public int Unknown28; + public int ElapsedFrameCountInfoSize; public int Unknown2C; public int Unknown30; public int Unknown34; diff --git a/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/VoiceContext.cs b/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/VoiceContext.cs index c9fb85028..4bf15a59e 100644 --- a/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/VoiceContext.cs +++ b/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/VoiceContext.cs @@ -85,7 +85,7 @@ namespace Ryujinx.HLE.HOS.Services.Audio.AudioRendererManager int maxSize = _samples.Length - _offset; - int size = maxSamples * AudioConsts.HostChannelsCount; + int size = maxSamples * AudioRendererConsts.HostChannelsCount; if (size > maxSize) { @@ -96,7 +96,7 @@ namespace Ryujinx.HLE.HOS.Services.Audio.AudioRendererManager Array.Copy(_samples, _offset, output, 0, size); - samplesCount = size / AudioConsts.HostChannelsCount; + samplesCount = size / AudioRendererConsts.HostChannelsCount; _outStatus.PlayedSamplesCount += samplesCount; @@ -140,7 +140,7 @@ namespace Ryujinx.HLE.HOS.Services.Audio.AudioRendererManager { int samplesCount = (int)(wb.Size / (sizeof(short) * ChannelsCount)); - _samples = new int[samplesCount * AudioConsts.HostChannelsCount]; + _samples = new int[samplesCount * AudioRendererConsts.HostChannelsCount]; if (ChannelsCount == 1) { @@ -171,19 +171,19 @@ namespace Ryujinx.HLE.HOS.Services.Audio.AudioRendererManager throw new InvalidOperationException(); } - if (SampleRate != AudioConsts.HostSampleRate) + if (SampleRate != AudioRendererConsts.HostSampleRate) { // TODO: We should keep the frames being discarded (see the 4 below) // on a buffer and include it on the next samples buffer, to allow // the resampler to do seamless interpolation between wave buffers. - int samplesCount = _samples.Length / AudioConsts.HostChannelsCount; + int samplesCount = _samples.Length / AudioRendererConsts.HostChannelsCount; samplesCount = Math.Max(samplesCount - 4, 0); _samples = Resampler.Resample2Ch( _samples, SampleRate, - AudioConsts.HostSampleRate, + AudioRendererConsts.HostSampleRate, samplesCount, ref _resamplerFracPart); } diff --git a/Ryujinx.HLE/HOS/Services/Audio/IAudioRendererManager.cs b/Ryujinx.HLE/HOS/Services/Audio/IAudioRendererManager.cs index de1c35b5c..563ba7e15 100644 --- a/Ryujinx.HLE/HOS/Services/Audio/IAudioRendererManager.cs +++ b/Ryujinx.HLE/HOS/Services/Audio/IAudioRendererManager.cs @@ -1,22 +1,13 @@ using Ryujinx.Audio; +using Ryujinx.Common; using Ryujinx.Common.Logging; using Ryujinx.HLE.HOS.Services.Audio.AudioRendererManager; -using Ryujinx.HLE.Utilities; namespace Ryujinx.HLE.HOS.Services.Audio { [Service("audren:u")] class IAudioRendererManager : IpcService { - private const int Rev0Magic = ('R' << 0) | - ('E' << 8) | - ('V' << 16) | - ('0' << 24); - - private const int Rev = 5; - - public const int RevMagic = Rev0Magic + (Rev << 24); - public IAudioRendererManager(ServiceCtx context) { } [Command(0)] @@ -41,69 +32,57 @@ namespace Ryujinx.HLE.HOS.Services.Audio // GetWorkBufferSize(nn::audio::detail::AudioRendererParameterInternal) -> u64 public ResultCode GetAudioRendererWorkBufferSize(ServiceCtx context) { - AudioRendererParameter Params = GetAudioRendererParameter(context); + AudioRendererParameter parameters = GetAudioRendererParameter(context); - int revision = (Params.Revision - Rev0Magic) >> 24; - - if (revision <= Rev) + if (AudioRendererCommon.CheckValidRevision(parameters)) { - bool isSplitterSupported = revision >= 3; - bool isVariadicCommandBufferSizeSupported = revision >= 5; - + BehaviorInfo behaviorInfo = new BehaviorInfo(); + + behaviorInfo.SetUserLibRevision(parameters.Revision); + long size; - size = IntUtils.AlignUp(Params.Unknown8 * 4, 64); - size += Params.MixCount * 0x400; - size += (Params.MixCount + 1) * 0x940; - size += Params.VoiceCount * 0x3F0; - size += IntUtils.AlignUp((Params.MixCount + 1) * 8, 16); - size += IntUtils.AlignUp(Params.VoiceCount * 8, 16); - size += IntUtils.AlignUp( - ((Params.SinkCount + Params.MixCount) * 0x3C0 + Params.SampleCount * 4) * - (Params.Unknown8 + 6), 64); - size += (Params.SinkCount + Params.MixCount) * 0x2C0; - size += (Params.EffectCount + Params.VoiceCount * 4) * 0x30 + 0x50; + int totalMixCount = parameters.SubMixCount + 1; - if (isSplitterSupported) + size = BitUtils.AlignUp(parameters.MixBufferCount * 4, AudioRendererConsts.BufferAlignment) + + parameters.SubMixCount * 0x400 + + totalMixCount * 0x940 + + parameters.VoiceCount * 0x3F0 + + BitUtils.AlignUp(totalMixCount * 8, 16) + + BitUtils.AlignUp(parameters.VoiceCount * 8, 16) + + BitUtils.AlignUp(((parameters.SinkCount + parameters.SubMixCount) * 0x3C0 + parameters.SampleCount * 4) * + (parameters.MixBufferCount + 6), AudioRendererConsts.BufferAlignment) + + (parameters.SinkCount + parameters.SubMixCount) * 0x2C0 + + (parameters.EffectCount + parameters.VoiceCount * 4) * 0x30 + + 0x50; + + if (behaviorInfo.IsSplitterSupported()) { - size += IntUtils.AlignUp(( - NodeStatesGetWorkBufferSize(Params.MixCount + 1) + - EdgeMatrixGetWorkBufferSize(Params.MixCount + 1)), 16); - - size += Params.SplitterDestinationDataCount * 0xE0; - size += Params.SplitterCount * 0x20; - size += IntUtils.AlignUp(Params.SplitterDestinationDataCount * 4, 16); + size += BitUtils.AlignUp(NodeStates.GetWorkBufferSize(totalMixCount) + EdgeMatrix.GetWorkBufferSize(totalMixCount), 16); } - size = Params.EffectCount * 0x4C0 + - Params.SinkCount * 0x170 + - Params.VoiceCount * 0x100 + - IntUtils.AlignUp(size, 64) + 0x40; + size = parameters.SinkCount * 0x170 + + (parameters.SinkCount + parameters.SubMixCount) * 0x280 + + parameters.EffectCount * 0x4C0 + + ((size + SplitterContext.CalcWorkBufferSize(behaviorInfo, parameters) + 0x30 * parameters.EffectCount + (4 * parameters.VoiceCount) + 0x8F) & ~0x3FL) + + ((parameters.VoiceCount << 8) | 0x40); - if (Params.PerformanceManagerCount >= 1) + if (parameters.PerformanceManagerCount >= 1) { - size += (((Params.EffectCount + - Params.SinkCount + - Params.VoiceCount + - Params.MixCount + 1) * 16 + 0x658) * - (Params.PerformanceManagerCount + 1) + 0x13F) & ~0x3FL; + size += (PerformanceManager.GetRequiredBufferSizeForPerformanceMetricsPerFrame(behaviorInfo, parameters) * + (parameters.PerformanceManagerCount + 1) + 0xFF) & ~0x3FL; } - if (isVariadicCommandBufferSizeSupported) + if (behaviorInfo.IsVariadicCommandBufferSizeSupported()) { - size += Params.EffectCount * 0x840 + - Params.MixCount * 0x5A38 + - Params.SinkCount * 0x148 + - Params.SplitterDestinationDataCount * 0x540 + - Params.VoiceCount * (Params.SplitterCount * 0x68 + 0x2E0) + - ((Params.VoiceCount + Params.MixCount + Params.EffectCount + Params.SinkCount + 0x65) << 6) + 0x3F8 + 0x7E; + size += CommandGenerator.CalculateCommandBufferSize(parameters) + 0x7E; } else { size += 0x1807E; } - size = size & ~0xFFFL; + size = BitUtils.AlignUp(size, 0x1000); context.ResponseData.Write(size); @@ -115,7 +94,7 @@ namespace Ryujinx.HLE.HOS.Services.Audio { context.ResponseData.Write(0L); - Logger.PrintWarning(LogClass.ServiceAudio, $"Library Revision 0x{Params.Revision:x8} is not supported!"); + Logger.PrintWarning(LogClass.ServiceAudio, $"Library Revision REV{AudioRendererCommon.GetRevisionVersion(parameters.Revision)} is not supported!"); return ResultCode.UnsupportedRevision; } @@ -127,8 +106,8 @@ namespace Ryujinx.HLE.HOS.Services.Audio { SampleRate = context.RequestData.ReadInt32(), SampleCount = context.RequestData.ReadInt32(), - Unknown8 = context.RequestData.ReadInt32(), - MixCount = context.RequestData.ReadInt32(), + MixBufferCount = context.RequestData.ReadInt32(), + SubMixCount = context.RequestData.ReadInt32(), VoiceCount = context.RequestData.ReadInt32(), SinkCount = context.RequestData.ReadInt32(), EffectCount = context.RequestData.ReadInt32(), @@ -143,30 +122,6 @@ namespace Ryujinx.HLE.HOS.Services.Audio return Params; } - private static int NodeStatesGetWorkBufferSize(int value) - { - int result = IntUtils.AlignUp(value, 64); - - if (result < 0) - { - result |= 7; - } - - return 4 * (value * value) + 0x12 * value + 2 * (result / 8); - } - - private static int EdgeMatrixGetWorkBufferSize(int value) - { - int result = IntUtils.AlignUp(value * value, 64); - - if (result < 0) - { - result |= 7; - } - - return result / 8; - } - [Command(2)] // GetAudioDeviceService(nn::applet::AppletResourceUserId) -> object public ResultCode GetAudioDeviceService(ServiceCtx context)