aboutsummaryrefslogtreecommitdiff
path: root/Ryujinx.Audio/Renderer/Server
diff options
context:
space:
mode:
authorMary <me@thog.eu>2021-05-25 19:01:09 +0200
committerGitHub <noreply@github.com>2021-05-25 19:01:09 +0200
commitf3b0b4831c323a20393aa0388f947317354372b7 (patch)
tree478412fd3a8c2de6eab5e54dd47944f59bf1a836 /Ryujinx.Audio/Renderer/Server
parent54ea2285f05ef6f59a6f1c63df4a7bdd77d7b883 (diff)
amadeus: Update to REV9 (#2309)
* amadeus: Update to REV9 This implements all the changes made with REV9 on 12.0.0. * Address Ac_k's comments
Diffstat (limited to 'Ryujinx.Audio/Renderer/Server')
-rw-r--r--Ryujinx.Audio/Renderer/Server/AudioRenderSystem.cs7
-rw-r--r--Ryujinx.Audio/Renderer/Server/BehaviourContext.cs19
-rw-r--r--Ryujinx.Audio/Renderer/Server/CommandBuffer.cs43
-rw-r--r--Ryujinx.Audio/Renderer/Server/CommandGenerator.cs25
-rw-r--r--Ryujinx.Audio/Renderer/Server/CommandProcessingTimeEstimatorVersion1.cs10
-rw-r--r--Ryujinx.Audio/Renderer/Server/CommandProcessingTimeEstimatorVersion2.cs10
-rw-r--r--Ryujinx.Audio/Renderer/Server/CommandProcessingTimeEstimatorVersion3.cs123
-rw-r--r--Ryujinx.Audio/Renderer/Server/Effect/AuxiliaryBufferEffect.cs12
-rw-r--r--Ryujinx.Audio/Renderer/Server/Effect/BaseEffect.cs46
-rw-r--r--Ryujinx.Audio/Renderer/Server/Effect/BiquadFilterEffect.cs12
-rw-r--r--Ryujinx.Audio/Renderer/Server/Effect/BufferMixEffect.cs12
-rw-r--r--Ryujinx.Audio/Renderer/Server/Effect/DelayEffect.cs12
-rw-r--r--Ryujinx.Audio/Renderer/Server/Effect/EffectContext.cs60
-rw-r--r--Ryujinx.Audio/Renderer/Server/Effect/LimiterEffect.cs112
-rw-r--r--Ryujinx.Audio/Renderer/Server/Effect/Reverb3dEffect.cs12
-rw-r--r--Ryujinx.Audio/Renderer/Server/Effect/ReverbEffect.cs12
-rw-r--r--Ryujinx.Audio/Renderer/Server/ICommandProcessingTimeEstimator.cs2
-rw-r--r--Ryujinx.Audio/Renderer/Server/Performance/PerformanceManager.cs1
-rw-r--r--Ryujinx.Audio/Renderer/Server/StateUpdater.cs83
19 files changed, 586 insertions, 27 deletions
diff --git a/Ryujinx.Audio/Renderer/Server/AudioRenderSystem.cs b/Ryujinx.Audio/Renderer/Server/AudioRenderSystem.cs
index 112b0e44..943a2d78 100644
--- a/Ryujinx.Audio/Renderer/Server/AudioRenderSystem.cs
+++ b/Ryujinx.Audio/Renderer/Server/AudioRenderSystem.cs
@@ -307,7 +307,7 @@ namespace Ryujinx.Audio.Renderer.Server
_upsamplerManager = new UpsamplerManager(upSamplerWorkBuffer, _upsamplerCount);
- _effectContext.Initialize(parameter.EffectCount);
+ _effectContext.Initialize(parameter.EffectCount, _behaviourContext.IsEffectInfoVersion2Supported() ? parameter.EffectCount : 0);
_sinkContext.Initialize(parameter.SinkCount);
Memory<VoiceUpdateState> voiceUpdateStatesDsp = workBufferAllocator.Allocate<VoiceUpdateState>(parameter.VoiceCount, VoiceUpdateState.Align);
@@ -636,6 +636,11 @@ namespace Ryujinx.Audio.Renderer.Server
_voiceContext.UpdateForCommandGeneration();
+ if (_behaviourContext.IsEffectInfoVersion2Supported())
+ {
+ _effectContext.UpdateResultStateForCommandGeneration();
+ }
+
ulong endTicks = GetSystemTicks();
_totalElapsedTicks = endTicks - startTicks;
diff --git a/Ryujinx.Audio/Renderer/Server/BehaviourContext.cs b/Ryujinx.Audio/Renderer/Server/BehaviourContext.cs
index b31f9e9f..ed1f402e 100644
--- a/Ryujinx.Audio/Renderer/Server/BehaviourContext.cs
+++ b/Ryujinx.Audio/Renderer/Server/BehaviourContext.cs
@@ -90,9 +90,17 @@ namespace Ryujinx.Audio.Renderer.Server
public const int Revision8 = 8 << 24;
/// <summary>
+ /// REV9:
+ /// EffectInfo parameters were revisited with a new revision (version 2) allowing more data control between the client and server.
+ /// A new effect was added: Limiter. This effect is effectively implemented with a DRC while providing statistics on the processing on <see cref="Parameter.EffectOutStatusVersion2"/>.
+ /// </summary>
+ /// <remarks>This was added in system update 12.0.0</remarks>
+ public const int Revision9 = 9 << 24;
+
+ /// <summary>
/// Last revision supported by the implementation.
/// </summary>
- public const int LastRevision = Revision8;
+ public const int LastRevision = Revision9;
/// <summary>
/// Target revision magic supported by the implementation.
@@ -331,6 +339,15 @@ namespace Ryujinx.Audio.Renderer.Server
}
/// <summary>
+ /// Check if the audio renderer should use the new effect info format.
+ /// </summary>
+ /// <returns>True if the audio renderer should use the new effect info format.</returns>
+ public bool IsEffectInfoVersion2Supported()
+ {
+ return CheckFeatureSupported(UserRevision, BaseRevisionMagic + Revision9);
+ }
+
+ /// <summary>
/// Get the version of the <see cref="ICommandProcessingTimeEstimator"/>.
/// </summary>
/// <returns>The version of the <see cref="ICommandProcessingTimeEstimator"/>.</returns>
diff --git a/Ryujinx.Audio/Renderer/Server/CommandBuffer.cs b/Ryujinx.Audio/Renderer/Server/CommandBuffer.cs
index ca37e090..24cc93af 100644
--- a/Ryujinx.Audio/Renderer/Server/CommandBuffer.cs
+++ b/Ryujinx.Audio/Renderer/Server/CommandBuffer.cs
@@ -372,6 +372,49 @@ namespace Ryujinx.Audio.Renderer.Server
}
/// <summary>
+ /// Generate a new <see cref="LimiterCommandVersion1"/>.
+ /// </summary>
+ /// <param name="bufferOffset">The target buffer offset.</param>
+ /// <param name="parameter">The limiter parameter.</param>
+ /// <param name="state">The limiter state.</param>
+ /// <param name="isEnabled">Set to true if the effect should be active.</param>
+ /// <param name="workBuffer">The work buffer to use for processing.</param>
+ /// <param name="nodeId">The node id associated to this command.</param>
+ public void GenerateLimiterEffectVersion1(uint bufferOffset, LimiterParameter parameter, Memory<LimiterState> state, bool isEnabled, ulong workBuffer, int nodeId)
+ {
+ if (parameter.IsChannelCountValid())
+ {
+ LimiterCommandVersion1 command = new LimiterCommandVersion1(bufferOffset, parameter, state, isEnabled, workBuffer, nodeId);
+
+ command.EstimatedProcessingTime = _commandProcessingTimeEstimator.Estimate(command);
+
+ AddCommand(command);
+ }
+ }
+
+ /// <summary>
+ /// Generate a new <see cref="LimiterCommandVersion2"/>.
+ /// </summary>
+ /// <param name="bufferOffset">The target buffer offset.</param>
+ /// <param name="parameter">The limiter parameter.</param>
+ /// <param name="state">The limiter state.</param>
+ /// <param name="effectResultState">The DSP effect result state.</param>
+ /// <param name="isEnabled">Set to true if the effect should be active.</param>
+ /// <param name="workBuffer">The work buffer to use for processing.</param>
+ /// <param name="nodeId">The node id associated to this command.</param>
+ public void GenerateLimiterEffectVersion2(uint bufferOffset, LimiterParameter parameter, Memory<LimiterState> state, Memory<EffectResultState> effectResultState, bool isEnabled, ulong workBuffer, int nodeId)
+ {
+ if (parameter.IsChannelCountValid())
+ {
+ LimiterCommandVersion2 command = new LimiterCommandVersion2(bufferOffset, parameter, state, effectResultState, isEnabled, workBuffer, nodeId);
+
+ command.EstimatedProcessingTime = _commandProcessingTimeEstimator.Estimate(command);
+
+ AddCommand(command);
+ }
+ }
+
+ /// <summary>
/// Generate a new <see cref="AuxiliaryBufferCommand"/>.
/// </summary>
/// <param name="bufferOffset">The target buffer offset.</param>
diff --git a/Ryujinx.Audio/Renderer/Server/CommandGenerator.cs b/Ryujinx.Audio/Renderer/Server/CommandGenerator.cs
index d2499c1d..01e7c927 100644
--- a/Ryujinx.Audio/Renderer/Server/CommandGenerator.cs
+++ b/Ryujinx.Audio/Renderer/Server/CommandGenerator.cs
@@ -538,7 +538,25 @@ namespace Ryujinx.Audio.Renderer.Server
}
}
- private void GenerateEffect(ref MixState mix, BaseEffect effect)
+ private void GenerateLimiterEffect(uint bufferOffset, LimiterEffect effect, int nodeId, int effectId)
+ {
+ Debug.Assert(effect.Type == EffectType.Limiter);
+
+ ulong workBuffer = effect.GetWorkBuffer(-1);
+
+ if (_rendererContext.BehaviourContext.IsEffectInfoVersion2Supported())
+ {
+ Memory<EffectResultState> dspResultState = _effectContext.GetDspStateMemory(effectId);
+
+ _commandBuffer.GenerateLimiterEffectVersion2(bufferOffset, effect.Parameter, effect.State, dspResultState, effect.IsEnabled, workBuffer, nodeId);
+ }
+ else
+ {
+ _commandBuffer.GenerateLimiterEffectVersion1(bufferOffset, effect.Parameter, effect.State, effect.IsEnabled, workBuffer, nodeId);
+ }
+ }
+
+ private void GenerateEffect(ref MixState mix, int effectId, BaseEffect effect)
{
int nodeId = mix.NodeId;
@@ -576,6 +594,9 @@ namespace Ryujinx.Audio.Renderer.Server
case EffectType.BiquadFilter:
GenerateBiquadFilterEffect(mix.BufferOffset, (BiquadFilterEffect)effect, nodeId);
break;
+ case EffectType.Limiter:
+ GenerateLimiterEffect(mix.BufferOffset, (LimiterEffect)effect, nodeId, effectId);
+ break;
default:
throw new NotImplementedException($"Unsupported effect type {effect.Type}");
}
@@ -611,7 +632,7 @@ namespace Ryujinx.Audio.Renderer.Server
if (!effect.ShouldSkip())
{
- GenerateEffect(ref mix, effect);
+ GenerateEffect(ref mix, effectOrder, effect);
}
}
}
diff --git a/Ryujinx.Audio/Renderer/Server/CommandProcessingTimeEstimatorVersion1.cs b/Ryujinx.Audio/Renderer/Server/CommandProcessingTimeEstimatorVersion1.cs
index 81d3b57b..feb3706f 100644
--- a/Ryujinx.Audio/Renderer/Server/CommandProcessingTimeEstimatorVersion1.cs
+++ b/Ryujinx.Audio/Renderer/Server/CommandProcessingTimeEstimatorVersion1.cs
@@ -176,5 +176,15 @@ namespace Ryujinx.Audio.Renderer.Server
{
return 0;
}
+
+ public uint Estimate(LimiterCommandVersion1 command)
+ {
+ return 0;
+ }
+
+ public uint Estimate(LimiterCommandVersion2 command)
+ {
+ return 0;
+ }
}
}
diff --git a/Ryujinx.Audio/Renderer/Server/CommandProcessingTimeEstimatorVersion2.cs b/Ryujinx.Audio/Renderer/Server/CommandProcessingTimeEstimatorVersion2.cs
index 0f4fe3c2..227f3c81 100644
--- a/Ryujinx.Audio/Renderer/Server/CommandProcessingTimeEstimatorVersion2.cs
+++ b/Ryujinx.Audio/Renderer/Server/CommandProcessingTimeEstimatorVersion2.cs
@@ -540,5 +540,15 @@ namespace Ryujinx.Audio.Renderer.Server
{
return 0;
}
+
+ public uint Estimate(LimiterCommandVersion1 command)
+ {
+ return 0;
+ }
+
+ public uint Estimate(LimiterCommandVersion2 command)
+ {
+ return 0;
+ }
}
}
diff --git a/Ryujinx.Audio/Renderer/Server/CommandProcessingTimeEstimatorVersion3.cs b/Ryujinx.Audio/Renderer/Server/CommandProcessingTimeEstimatorVersion3.cs
index b48ff8b5..e00fcf7b 100644
--- a/Ryujinx.Audio/Renderer/Server/CommandProcessingTimeEstimatorVersion3.cs
+++ b/Ryujinx.Audio/Renderer/Server/CommandProcessingTimeEstimatorVersion3.cs
@@ -18,6 +18,7 @@
using Ryujinx.Audio.Common;
using Ryujinx.Audio.Renderer.Common;
using Ryujinx.Audio.Renderer.Dsp.Command;
+using Ryujinx.Audio.Renderer.Parameter.Effect;
using System;
using System.Diagnostics;
using static Ryujinx.Audio.Renderer.Parameter.VoiceInParameter;
@@ -632,5 +633,127 @@ namespace Ryujinx.Audio.Renderer.Server
throw new NotImplementedException($"{format}");
}
}
+
+ private uint EstimateLimiterCommandCommon(LimiterParameter parameter, bool enabled)
+ {
+ Debug.Assert(_sampleCount == 160 || _sampleCount == 240);
+
+ if (_sampleCount == 160)
+ {
+ if (enabled)
+ {
+ switch (parameter.ChannelCount)
+ {
+ case 1:
+ return (uint)21392.0f;
+ case 2:
+ return (uint)26829.0f;
+ case 4:
+ return (uint)32405.0f;
+ case 6:
+ return (uint)52219.0f;
+ default:
+ throw new NotImplementedException($"{parameter.ChannelCount}");
+ }
+ }
+ else
+ {
+ switch (parameter.ChannelCount)
+ {
+ case 1:
+ return (uint)897.0f;
+ case 2:
+ return (uint)931.55f;
+ case 4:
+ return (uint)975.39f;
+ case 6:
+ return (uint)1016.8f;
+ default:
+ throw new NotImplementedException($"{parameter.ChannelCount}");
+ }
+ }
+ }
+
+ if (enabled)
+ {
+ switch (parameter.ChannelCount)
+ {
+ case 1:
+ return (uint)30556.0f;
+ case 2:
+ return (uint)39011.0f;
+ case 4:
+ return (uint)48270.0f;
+ case 6:
+ return (uint)76712.0f;
+ default:
+ throw new NotImplementedException($"{parameter.ChannelCount}");
+ }
+ }
+ else
+ {
+ switch (parameter.ChannelCount)
+ {
+ case 1:
+ return (uint)874.43f;
+ case 2:
+ return (uint)921.55f;
+ case 4:
+ return (uint)945.26f;
+ case 6:
+ return (uint)992.26f;
+ default:
+ throw new NotImplementedException($"{parameter.ChannelCount}");
+ }
+ }
+ }
+
+ public uint Estimate(LimiterCommandVersion1 command)
+ {
+ Debug.Assert(_sampleCount == 160 || _sampleCount == 240);
+
+ return EstimateLimiterCommandCommon(command.Parameter, command.IsEffectEnabled);
+ }
+
+ public uint Estimate(LimiterCommandVersion2 command)
+ {
+ Debug.Assert(_sampleCount == 160 || _sampleCount == 240);
+
+ if (!command.Parameter.StatisticsEnabled || !command.IsEffectEnabled)
+ {
+ return EstimateLimiterCommandCommon(command.Parameter, command.IsEffectEnabled);
+ }
+
+ if (_sampleCount == 160)
+ {
+ switch (command.Parameter.ChannelCount)
+ {
+ case 1:
+ return (uint)23309.0f;
+ case 2:
+ return (uint)29954.0f;
+ case 4:
+ return (uint)35807.0f;
+ case 6:
+ return (uint)58340.0f;
+ default:
+ throw new NotImplementedException($"{command.Parameter.ChannelCount}");
+ }
+ }
+
+ switch (command.Parameter.ChannelCount)
+ {
+ case 1:
+ return (uint)33526.0f;
+ case 2:
+ return (uint)43549.0f;
+ case 4:
+ return (uint)52190.0f;
+ case 6:
+ return (uint)85527.0f;
+ default:
+ throw new NotImplementedException($"{command.Parameter.ChannelCount}");
+ }
+ }
}
}
diff --git a/Ryujinx.Audio/Renderer/Server/Effect/AuxiliaryBufferEffect.cs b/Ryujinx.Audio/Renderer/Server/Effect/AuxiliaryBufferEffect.cs
index df82945b..eac1708e 100644
--- a/Ryujinx.Audio/Renderer/Server/Effect/AuxiliaryBufferEffect.cs
+++ b/Ryujinx.Audio/Renderer/Server/Effect/AuxiliaryBufferEffect.cs
@@ -50,7 +50,17 @@ namespace Ryujinx.Audio.Renderer.Server.Effect
return WorkBuffers[index].GetReference(true);
}
- public override void Update(out BehaviourParameter.ErrorInfo updateErrorInfo, ref EffectInParameter parameter, PoolMapper mapper)
+ public override void Update(out BehaviourParameter.ErrorInfo updateErrorInfo, ref EffectInParameterVersion1 parameter, PoolMapper mapper)
+ {
+ Update(out updateErrorInfo, ref parameter, mapper);
+ }
+
+ public override void Update(out BehaviourParameter.ErrorInfo updateErrorInfo, ref EffectInParameterVersion2 parameter, PoolMapper mapper)
+ {
+ Update(out updateErrorInfo, ref parameter, mapper);
+ }
+
+ public void Update<T>(out BehaviourParameter.ErrorInfo updateErrorInfo, ref T parameter, PoolMapper mapper) where T : unmanaged, IEffectInParameter
{
Debug.Assert(IsTypeValid(ref parameter));
diff --git a/Ryujinx.Audio/Renderer/Server/Effect/BaseEffect.cs b/Ryujinx.Audio/Renderer/Server/Effect/BaseEffect.cs
index 7529f894..c7b06e7a 100644
--- a/Ryujinx.Audio/Renderer/Server/Effect/BaseEffect.cs
+++ b/Ryujinx.Audio/Renderer/Server/Effect/BaseEffect.cs
@@ -98,7 +98,7 @@ namespace Ryujinx.Audio.Renderer.Server.Effect
/// </summary>
/// <param name="parameter">The user parameter.</param>
/// <returns>Returns true if the <see cref="EffectType"/> sent by the user matches the internal <see cref="EffectType"/>.</returns>
- public bool IsTypeValid(ref EffectInParameter parameter)
+ public bool IsTypeValid<T>(ref T parameter) where T: unmanaged, IEffectInParameter
{
return parameter.Type == TargetEffectType;
}
@@ -115,7 +115,7 @@ namespace Ryujinx.Audio.Renderer.Server.Effect
/// Update the internal common parameters from a user parameter.
/// </summary>
/// <param name="parameter">The user parameter.</param>
- protected void UpdateParameterBase(ref EffectInParameter parameter)
+ protected void UpdateParameterBase<T>(ref T parameter) where T : unmanaged, IEffectInParameter
{
MixId = parameter.MixId;
ProcessingOrder = parameter.ProcessingOrder;
@@ -154,12 +154,38 @@ namespace Ryujinx.Audio.Renderer.Server.Effect
}
/// <summary>
- /// Update the internal state from a user parameter.
+ /// Initialize the given <paramref name="state"/> result state.
+ /// </summary>
+ /// <param name="state">The state to initalize</param>
+ public virtual void InitializeResultState(ref EffectResultState state) {}
+
+ /// <summary>
+ /// Update the <paramref name="destState"/> result state with <paramref name="srcState"/>.
+ /// </summary>
+ /// <param name="destState">The destination result state</param>
+ /// <param name="srcState">The source result state</param>
+ public virtual void UpdateResultState(ref EffectResultState destState, ref EffectResultState srcState) {}
+
+ /// <summary>
+ /// Update the internal state from a user version 1 parameter.
+ /// </summary>
+ /// <param name="updateErrorInfo">The possible <see cref="ErrorInfo"/> that was generated.</param>
+ /// <param name="parameter">The user parameter.</param>
+ /// <param name="mapper">The mapper to use.</param>
+ public virtual void Update(out ErrorInfo updateErrorInfo, ref EffectInParameterVersion1 parameter, PoolMapper mapper)
+ {
+ Debug.Assert(IsTypeValid(ref parameter));
+
+ updateErrorInfo = new ErrorInfo();
+ }
+
+ /// <summary>
+ /// Update the internal state from a user version 2 parameter.
/// </summary>
/// <param name="updateErrorInfo">The possible <see cref="ErrorInfo"/> that was generated.</param>
/// <param name="parameter">The user parameter.</param>
/// <param name="mapper">The mapper to use.</param>
- public virtual void Update(out ErrorInfo updateErrorInfo, ref EffectInParameter parameter, PoolMapper mapper)
+ public virtual void Update(out ErrorInfo updateErrorInfo, ref EffectInParameterVersion2 parameter, PoolMapper mapper)
{
Debug.Assert(IsTypeValid(ref parameter));
@@ -206,26 +232,26 @@ namespace Ryujinx.Audio.Renderer.Server.Effect
/// </summary>
/// <param name="outStatus">The given user output.</param>
/// <param name="isAudioRendererActive">If set to true, the <see cref="AudioRenderSystem"/> is active.</param>
- public void StoreStatus(ref EffectOutStatus outStatus, bool isAudioRendererActive)
+ public void StoreStatus<T>(ref T outStatus, bool isAudioRendererActive) where T: unmanaged, IEffectOutStatus
{
if (isAudioRendererActive)
{
if (UsageState == UsageState.Disabled)
{
- outStatus.State = EffectOutStatus.EffectState.Disabled;
+ outStatus.State = EffectState.Disabled;
}
else
{
- outStatus.State = EffectOutStatus.EffectState.Enabled;
+ outStatus.State = EffectState.Enabled;
}
}
else if (UsageState == UsageState.New)
{
- outStatus.State = EffectOutStatus.EffectState.Enabled;
+ outStatus.State = EffectState.Enabled;
}
else
{
- outStatus.State = EffectOutStatus.EffectState.Disabled;
+ outStatus.State = EffectState.Disabled;
}
}
@@ -249,6 +275,8 @@ namespace Ryujinx.Audio.Renderer.Server.Effect
return PerformanceDetailType.Reverb3d;
case EffectType.BufferMix:
return PerformanceDetailType.Mix;
+ case EffectType.Limiter:
+ return PerformanceDetailType.Limiter;
default:
throw new NotImplementedException($"{Type}");
}
diff --git a/Ryujinx.Audio/Renderer/Server/Effect/BiquadFilterEffect.cs b/Ryujinx.Audio/Renderer/Server/Effect/BiquadFilterEffect.cs
index 35ba8a0d..6c91b607 100644
--- a/Ryujinx.Audio/Renderer/Server/Effect/BiquadFilterEffect.cs
+++ b/Ryujinx.Audio/Renderer/Server/Effect/BiquadFilterEffect.cs
@@ -52,7 +52,17 @@ namespace Ryujinx.Audio.Renderer.Server.Effect
public override EffectType TargetEffectType => EffectType.BiquadFilter;
- public override void Update(out BehaviourParameter.ErrorInfo updateErrorInfo, ref EffectInParameter parameter, PoolMapper mapper)
+ public override void Update(out BehaviourParameter.ErrorInfo updateErrorInfo, ref EffectInParameterVersion1 parameter, PoolMapper mapper)
+ {
+ Update(out updateErrorInfo, ref parameter, mapper);
+ }
+
+ public override void Update(out BehaviourParameter.ErrorInfo updateErrorInfo, ref EffectInParameterVersion2 parameter, PoolMapper mapper)
+ {
+ Update(out updateErrorInfo, ref parameter, mapper);
+ }
+
+ public void Update<T>(out BehaviourParameter.ErrorInfo updateErrorInfo, ref T parameter, PoolMapper mapper) where T : unmanaged, IEffectInParameter
{
Debug.Assert(IsTypeValid(ref parameter));
diff --git a/Ryujinx.Audio/Renderer/Server/Effect/BufferMixEffect.cs b/Ryujinx.Audio/Renderer/Server/Effect/BufferMixEffect.cs
index 14ed3950..05cccad9 100644
--- a/Ryujinx.Audio/Renderer/Server/Effect/BufferMixEffect.cs
+++ b/Ryujinx.Audio/Renderer/Server/Effect/BufferMixEffect.cs
@@ -36,7 +36,17 @@ namespace Ryujinx.Audio.Renderer.Server.Effect
public override EffectType TargetEffectType => EffectType.BufferMix;
- public override void Update(out BehaviourParameter.ErrorInfo updateErrorInfo, ref EffectInParameter parameter, PoolMapper mapper)
+ public override void Update(out BehaviourParameter.ErrorInfo updateErrorInfo, ref EffectInParameterVersion1 parameter, PoolMapper mapper)
+ {
+ Update(out updateErrorInfo, ref parameter, mapper);
+ }
+
+ public override void Update(out BehaviourParameter.ErrorInfo updateErrorInfo, ref EffectInParameterVersion2 parameter, PoolMapper mapper)
+ {
+ Update(out updateErrorInfo, ref parameter, mapper);
+ }
+
+ public void Update<T>(out BehaviourParameter.ErrorInfo updateErrorInfo, ref T parameter, PoolMapper mapper) where T : unmanaged, IEffectInParameter
{
Debug.Assert(IsTypeValid(ref parameter));
diff --git a/Ryujinx.Audio/Renderer/Server/Effect/DelayEffect.cs b/Ryujinx.Audio/Renderer/Server/Effect/DelayEffect.cs
index df3e5ee7..a5b3dbc5 100644
--- a/Ryujinx.Audio/Renderer/Server/Effect/DelayEffect.cs
+++ b/Ryujinx.Audio/Renderer/Server/Effect/DelayEffect.cs
@@ -54,7 +54,17 @@ namespace Ryujinx.Audio.Renderer.Server.Effect
return GetSingleBuffer();
}
- public override void Update(out BehaviourParameter.ErrorInfo updateErrorInfo, ref EffectInParameter parameter, PoolMapper mapper)
+ public override void Update(out BehaviourParameter.ErrorInfo updateErrorInfo, ref EffectInParameterVersion1 parameter, PoolMapper mapper)
+ {
+ Update(out updateErrorInfo, ref parameter, mapper);
+ }
+
+ public override void Update(out BehaviourParameter.ErrorInfo updateErrorInfo, ref EffectInParameterVersion2 parameter, PoolMapper mapper)
+ {
+ Update(out updateErrorInfo, ref parameter, mapper);
+ }
+
+ public void Update<T>(out BehaviourParameter.ErrorInfo updateErrorInfo, ref T parameter, PoolMapper mapper) where T : unmanaged, IEffectInParameter
{
Debug.Assert(IsTypeValid(ref parameter));
diff --git a/Ryujinx.Audio/Renderer/Server/Effect/EffectContext.cs b/Ryujinx.Audio/Renderer/Server/Effect/EffectContext.cs
index ff6051ae..074f4375 100644
--- a/Ryujinx.Audio/Renderer/Server/Effect/EffectContext.cs
+++ b/Ryujinx.Audio/Renderer/Server/Effect/EffectContext.cs
@@ -15,6 +15,9 @@
// along with this program. If not, see <https://www.gnu.org/licenses/>.
//
+using Ryujinx.Audio.Renderer.Parameter;
+using Ryujinx.Audio.Renderer.Utils;
+using System;
using System.Diagnostics;
namespace Ryujinx.Audio.Renderer.Server.Effect
@@ -34,6 +37,9 @@ namespace Ryujinx.Audio.Renderer.Server.Effect
/// </summary>
private uint _effectCount;
+ private EffectResultState[] _resultStatesCpu;
+ private EffectResultState[] _resultStatesDsp;
+
/// <summary>
/// Create a new <see cref="EffectContext"/>.
/// </summary>
@@ -47,7 +53,8 @@ namespace Ryujinx.Audio.Renderer.Server.Effect
/// Initialize the <see cref="EffectContext"/>.
/// </summary>
/// <param name="effectCount">The total effect count.</param>
- public void Initialize(uint effectCount)
+ /// <param name="resultStateCount">The total result state count.</param>
+ public void Initialize(uint effectCount, uint resultStateCount)
{
_effectCount = effectCount;
_effects = new BaseEffect[effectCount];
@@ -56,6 +63,9 @@ namespace Ryujinx.Audio.Renderer.Server.Effect
{
_effects[i] = new BaseEffect();
}
+
+ _resultStatesCpu = new EffectResultState[resultStateCount];
+ _resultStatesDsp = new EffectResultState[resultStateCount];
}
/// <summary>
@@ -78,5 +88,53 @@ namespace Ryujinx.Audio.Renderer.Server.Effect
return ref _effects[index];
}
+
+ /// <summary>
+ /// Get a reference to a <see cref="EffectResultState"/> at the given <paramref name="index"/>.
+ /// </summary>
+ /// <param name="index">The index to use.</param>
+ /// <returns>A reference to a <see cref="EffectResultState"/> at the given <paramref name="index"/>.</returns>
+ /// <remarks>The returned <see cref="EffectResultState"/> should only be used when updating the server state.</remarks>
+ public ref EffectResultState GetState(int index)
+ {
+ Debug.Assert(index >= 0 && index < _resultStatesCpu.Length);
+
+ return ref _resultStatesCpu[index];
+ }
+
+ /// <summary>
+ /// Get a reference to a <see cref="EffectResultState"/> at the given <paramref name="index"/>.
+ /// </summary>
+ /// <param name="index">The index to use.</param>
+ /// <returns>A reference to a <see cref="EffectResultState"/> at the given <paramref name="index"/>.</returns>
+ /// <remarks>The returned <see cref="EffectResultState"/> should only be used in the context of processing on the <see cref="Dsp.AudioProcessor"/>.</remarks>
+ public ref EffectResultState GetDspState(int index)
+ {
+ Debug.Assert(index >= 0 && index < _resultStatesDsp.Length);
+
+ return ref _resultStatesDsp[index];
+ }
+
+ /// <summary>
+ /// Get a memory instance to a <see cref="EffectResultState"/> at the given <paramref name="index"/>.
+ /// </summary>
+ /// <param name="index">The index to use.</param>
+ /// <returns>A memory instance to a <see cref="EffectResultState"/> at the given <paramref name="index"/>.</returns>
+ /// <remarks>The returned <see cref="Memory{EffectResultState}"/> should only be used in the context of processing on the <see cref="Dsp.AudioProcessor"/>.</remarks>
+ public Memory<EffectResultState> GetDspStateMemory(int index)
+ {
+ return SpanIOHelper.GetMemory(_resultStatesDsp.AsMemory(), index, (uint)_resultStatesDsp.Length);
+ }
+
+ /// <summary>
+ /// Update internal state during command generation.
+ /// </summary>
+ public void UpdateResultStateForCommandGeneration()
+ {
+ for (int index = 0; index < _resultStatesCpu.Length; index++)
+ {
+ _effects[index].UpdateResultState(ref _resultStatesCpu[index], ref _resultStatesDsp[index]);
+ }
+ }
}
}
diff --git a/Ryujinx.Audio/Renderer/Server/Effect/LimiterEffect.cs b/Ryujinx.Audio/Renderer/Server/Effect/LimiterEffect.cs
new file mode 100644
index 00000000..fa04c027
--- /dev/null
+++ b/Ryujinx.Audio/Renderer/Server/Effect/LimiterEffect.cs
@@ -0,0 +1,112 @@
+//
+// Copyright (c) 2019-2021 Ryujinx
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with this program. If not, see <https://www.gnu.org/licenses/>.
+//
+
+using Ryujinx.Audio.Renderer.Common;
+using Ryujinx.Audio.Renderer.Dsp.State;
+using Ryujinx.Audio.Renderer.Parameter;
+using Ryujinx.Audio.Renderer.Parameter.Effect;
+using Ryujinx.Audio.Renderer.Server.MemoryPool;
+using System;
+using System.Diagnostics;
+using System.Runtime.InteropServices;
+
+namespace Ryujinx.Audio.Renderer.Server.Effect
+{
+ /// <summary>
+ /// Server state for a limiter effect.
+ /// </summary>
+ public class LimiterEffect : BaseEffect
+ {
+ /// <summary>
+ /// The limiter parameter.
+ /// </summary>
+ public LimiterParameter Parameter;
+
+ /// <summary>
+ /// The limiter state.
+ /// </summary>
+ public Memory<LimiterState> State { get; }
+
+ /// <summary>
+ /// Create a new <see cref="LimiterEffect"/>.
+ /// </summary>
+ public LimiterEffect()
+ {
+ State = new LimiterState[1];
+ }
+
+ public override EffectType TargetEffectType => EffectType.Limiter;
+
+ public override ulong GetWorkBuffer(int index)
+ {
+ return GetSingleBuffer();
+ }
+
+ public override void Update(out BehaviourParameter.ErrorInfo updateErrorInfo, ref EffectInParameterVersion1 parameter, PoolMapper mapper)
+ {
+ Update(out updateErrorInfo, ref parameter, mapper);
+ }
+
+ public override void Update(out BehaviourParameter.ErrorInfo updateErrorInfo, ref EffectInParameterVersion2 parameter, PoolMapper mapper)
+ {
+ Update(out updateErrorInfo, ref parameter, mapper);
+ }
+
+ public void Update<T>(out BehaviourParameter.ErrorInfo updateErrorInfo, ref T parameter, PoolMapper mapper) where T : unmanaged, IEffectInParameter
+ {
+ Debug.Assert(IsTypeValid(ref parameter));
+
+ ref LimiterParameter limiterParameter = ref MemoryMarshal.Cast<byte, LimiterParameter>(parameter.SpecificData)[0];
+
+ updateErrorInfo = new BehaviourParameter.ErrorInfo();
+
+ UpdateParameterBase(ref parameter);
+
+ Parameter = limiterParameter;
+
+ IsEnabled = parameter.IsEnabled;
+
+ if (BufferUnmapped || parameter.IsNew)
+ {
+ UsageState = UsageState.New;
+ Parameter.Status = UsageState.Invalid;
+
+ BufferUnmapped = !mapper.TryAttachBuffer(out updateErrorInfo, ref WorkBuffers[0], parameter.BufferBase, parameter.BufferSize);
+ }
+ }
+
+ public override void UpdateForCommandGeneration()
+ {
+ UpdateUsageStateForCommandGeneration();
+
+ Parameter.Status = UsageState.Enabled;
+ Parameter.StatisticsReset = false;
+ }
+
+ public override void InitializeResultState(ref EffectResultState state)
+ {
+ ref LimiterStatistics statistics = ref MemoryMarshal.Cast<byte, LimiterStatistics>(state.SpecificData)[0];
+
+ statistics.Reset();
+ }
+
+ public override void UpdateResultState(ref EffectResultState destState, ref EffectResultState srcState)
+ {
+ destState = srcState;
+ }
+ }
+}
diff --git a/Ryujinx.Audio/Renderer/Server/Effect/Reverb3dEffect.cs b/Ryujinx.Audio/Renderer/Server/Effect/Reverb3dEffect.cs
index d9f23799..7b8fd6c4 100644
--- a/Ryujinx.Audio/Renderer/Server/Effect/Reverb3dEffect.cs
+++ b/Ryujinx.Audio/Renderer/Server/Effect/Reverb3dEffect.cs
@@ -53,7 +53,17 @@ namespace Ryujinx.Audio.Renderer.Server.Effect
return GetSingleBuffer();
}
- public override void Update(out BehaviourParameter.ErrorInfo updateErrorInfo, ref EffectInParameter parameter, PoolMapper mapper)
+ public override void Update(out BehaviourParameter.ErrorInfo updateErrorInfo, ref EffectInParameterVersion1 parameter, PoolMapper mapper)
+ {
+ Update(out updateErrorInfo, ref parameter, mapper);
+ }
+
+ public override void Update(out BehaviourParameter.ErrorInfo updateErrorInfo, ref EffectInParameterVersion2 parameter, PoolMapper mapper)
+ {
+ Update(out updateErrorInfo, ref parameter, mapper);
+ }
+
+ public void Update<T>(out BehaviourParameter.ErrorInfo updateErrorInfo, ref T parameter, PoolMapper mapper) where T: unmanaged, IEffectInParameter
{
Debug.Assert(IsTypeValid(ref parameter));
diff --git a/Ryujinx.Audio/Renderer/Server/Effect/ReverbEffect.cs b/Ryujinx.Audio/Renderer/Server/Effect/ReverbEffect.cs
index 4c81f729..30908396 100644
--- a/Ryujinx.Audio/Renderer/Server/Effect/ReverbEffect.cs
+++ b/Ryujinx.Audio/Renderer/Server/Effect/ReverbEffect.cs
@@ -56,7 +56,17 @@ namespace Ryujinx.Audio.Renderer.Server.Effect
return GetSingleBuffer();
}
- public override void Update(out BehaviourParameter.ErrorInfo updateErrorInfo, ref EffectInParameter parameter, PoolMapper mapper)
+ public override void Update(out BehaviourParameter.ErrorInfo updateErrorInfo, ref EffectInParameterVersion1 parameter, PoolMapper mapper)
+ {
+ Update(out updateErrorInfo, ref parameter, mapper);
+ }
+
+ public override void Update(out BehaviourParameter.ErrorInfo updateErrorInfo, ref EffectInParameterVersion2 parameter, PoolMapper mapper)
+ {
+ Update(out updateErrorInfo, ref parameter, mapper);
+ }
+
+ public void Update<T>(out BehaviourParameter.ErrorInfo updateErrorInfo, ref T parameter, PoolMapper mapper) where T : unmanaged, IEffectInParameter
{
Debug.Assert(IsTypeValid(ref parameter));
diff --git a/Ryujinx.Audio/Renderer/Server/ICommandProcessingTimeEstimator.cs b/Ryujinx.Audio/Renderer/Server/ICommandProcessingTimeEstimator.cs
index 119ec907..eae48be6 100644
--- a/Ryujinx.Audio/Renderer/Server/ICommandProcessingTimeEstimator.cs
+++ b/Ryujinx.Audio/Renderer/Server/ICommandProcessingTimeEstimator.cs
@@ -48,5 +48,7 @@ namespace Ryujinx.Audio.Renderer.Server
uint Estimate(DeviceSinkCommand command);
uint Estimate(DownMixSurroundToStereoCommand command);
uint Estimate(UpsampleCommand command);
+ uint Estimate(LimiterCommandVersion1 command);
+ uint Estimate(LimiterCommandVersion2 command);
}
}
diff --git a/Ryujinx.Audio/Renderer/Server/Performance/PerformanceManager.cs b/Ryujinx.Audio/Renderer/Server/Performance/PerformanceManager.cs
index 3a336af3..fd7c93b1 100644
--- a/Ryujinx.Audio/Renderer/Server/Performance/PerformanceManager.cs
+++ b/Ryujinx.Audio/Renderer/Server/Performance/PerformanceManager.cs
@@ -18,7 +18,6 @@
using Ryujinx.Audio.Renderer.Common;
using Ryujinx.Audio.Renderer.Parameter;
using System;
-using System.Runtime.CompilerServices;
namespace Ryujinx.Audio.Renderer.Server.Performance
{
diff --git a/Ryujinx.Audio/Renderer/Server/StateUpdater.cs b/Ryujinx.Audio/Renderer/Server/StateUpdater.cs
index 77935b75..e7a982c4 100644
--- a/Ryujinx.Audio/Renderer/Server/StateUpdater.cs
+++ b/Ryujinx.Audio/Renderer/Server/StateUpdater.cs
@@ -224,7 +224,7 @@ namespace Ryujinx.Audio.Renderer.Server
return ResultCode.Success;
}
- private static void ResetEffect(ref BaseEffect effect, ref EffectInParameter parameter, PoolMapper mapper)
+ private static void ResetEffect<T>(ref BaseEffect effect, ref T parameter, PoolMapper mapper) where T: unmanaged, IEffectInParameter
{
effect.ForceUnmapBuffers(mapper);
@@ -251,6 +251,9 @@ namespace Ryujinx.Audio.Renderer.Server
case EffectType.BiquadFilter:
effect = new BiquadFilterEffect();
break;
+ case EffectType.Limiter:
+ effect = new LimiterEffect();
+ break;
default:
throw new NotImplementedException($"EffectType {parameter.Type} not implemented!");
}
@@ -258,14 +261,82 @@ namespace Ryujinx.Audio.Renderer.Server
public ResultCode UpdateEffects(EffectContext context, bool isAudioRendererActive, Memory<MemoryPoolState> memoryPools)
{
- if (context.GetCount() * Unsafe.SizeOf<EffectInParameter>() != _inputHeader.EffectsSize)
+ if (_behaviourContext.IsEffectInfoVersion2Supported())
+ {
+ return UpdateEffectsVersion2(context, isAudioRendererActive, memoryPools);
+ }
+ else
+ {
+ return UpdateEffectsVersion1(context, isAudioRendererActive, memoryPools);
+ }
+ }
+
+ public ResultCode UpdateEffectsVersion2(EffectContext context, bool isAudioRendererActive, Memory<MemoryPoolState> memoryPools)
+ {
+ if (context.GetCount() * Unsafe.SizeOf<EffectInParameterVersion2>() != _inputHeader.EffectsSize)
+ {
+ return ResultCode.InvalidUpdateInfo;
+ }
+
+ int initialOutputSize = _output.Length;
+
+ ReadOnlySpan<EffectInParameterVersion2> parameters = MemoryMarshal.Cast<byte, EffectInParameterVersion2>(_input.Slice(0, (int)_inputHeader.EffectsSize).Span);
+
+ _input = _input.Slice((int)_inputHeader.EffectsSize);
+
+ PoolMapper mapper = new PoolMapper(_processHandle, memoryPools, _behaviourContext.IsMemoryPoolForceMappingEnabled());
+
+ for (int i = 0; i < context.GetCount(); i++)
+ {
+ EffectInParameterVersion2 parameter = parameters[i];
+
+ ref EffectOutStatusVersion2 outStatus = ref SpanIOHelper.GetWriteRef<EffectOutStatusVersion2>(ref _output)[0];
+
+ ref BaseEffect effect = ref context.GetEffect(i);
+
+ if (!effect.IsTypeValid(ref parameter))
+ {
+ ResetEffect(ref effect, ref parameter, mapper);
+ }
+
+ effect.Update(out ErrorInfo updateErrorInfo, ref parameter, mapper);
+
+ if (updateErrorInfo.ErrorCode != ResultCode.Success)
+ {
+ _behaviourContext.AppendError(ref updateErrorInfo);
+ }
+
+ effect.StoreStatus(ref outStatus, isAudioRendererActive);
+
+ if (parameter.IsNew)
+ {
+ effect.InitializeResultState(ref context.GetDspState(i));
+ effect.InitializeResultState(ref context.GetState(i));
+ }
+
+ effect.UpdateResultState(ref outStatus.ResultState, ref context.GetState(i));
+ }
+
+ int currentOutputSize = _output.Length;
+
+ OutputHeader.EffectsSize = (uint)(Unsafe.SizeOf<EffectOutStatusVersion2>() * context.GetCount());
+ OutputHeader.TotalSize += OutputHeader.EffectsSize;
+
+ Debug.Assert((initialOutputSize - currentOutputSize) == OutputHeader.EffectsSize);
+
+ return ResultCode.Success;
+ }
+
+ public ResultCode UpdateEffectsVersion1(EffectContext context, bool isAudioRendererActive, Memory<MemoryPoolState> memoryPools)
+ {
+ if (context.GetCount() * Unsafe.SizeOf<EffectInParameterVersion1>() != _inputHeader.EffectsSize)
{
return ResultCode.InvalidUpdateInfo;
}
int initialOutputSize = _output.Length;
- ReadOnlySpan<EffectInParameter> parameters = MemoryMarshal.Cast<byte, EffectInParameter>(_input.Slice(0, (int)_inputHeader.EffectsSize).Span);
+ ReadOnlySpan<EffectInParameterVersion1> parameters = MemoryMarshal.Cast<byte, EffectInParameterVersion1>(_input.Slice(0, (int)_inputHeader.EffectsSize).Span);
_input = _input.Slice((int)_inputHeader.EffectsSize);
@@ -273,9 +344,9 @@ namespace Ryujinx.Audio.Renderer.Server
for (int i = 0; i < context.GetCount(); i++)
{
- EffectInParameter parameter = parameters[i];
+ EffectInParameterVersion1 parameter = parameters[i];
- ref EffectOutStatus outStatus = ref SpanIOHelper.GetWriteRef<EffectOutStatus>(ref _output)[0];
+ ref EffectOutStatusVersion1 outStatus = ref SpanIOHelper.GetWriteRef<EffectOutStatusVersion1>(ref _output)[0];
ref BaseEffect effect = ref context.GetEffect(i);
@@ -296,7 +367,7 @@ namespace Ryujinx.Audio.Renderer.Server
int currentOutputSize = _output.Length;
- OutputHeader.EffectsSize = (uint)(Unsafe.SizeOf<EffectOutStatus>() * context.GetCount());
+ OutputHeader.EffectsSize = (uint)(Unsafe.SizeOf<EffectOutStatusVersion1>() * context.GetCount());
OutputHeader.TotalSize += OutputHeader.EffectsSize;
Debug.Assert((initialOutputSize - currentOutputSize) == OutputHeader.EffectsSize);