Amadeus: DSP code generation improvements (#2460)
This improve RyuJIT codegen drastically on the DSP side. This may reduce CPU usage of the DSP thread quite a lot.
This commit is contained in:
parent
97a2133207
commit
b8ad676fb8
29 changed files with 319 additions and 265 deletions
|
@ -21,7 +21,6 @@ using Ryujinx.Audio.Renderer.Dsp.State;
|
|||
using Ryujinx.Common.Logging;
|
||||
using Ryujinx.Memory;
|
||||
using System;
|
||||
using System.Buffers;
|
||||
using System.Diagnostics;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
@ -36,50 +35,43 @@ namespace Ryujinx.Audio.Renderer.Dsp
|
|||
{
|
||||
private const int FixedPointPrecision = 15;
|
||||
|
||||
public class WaveBufferInformation
|
||||
public struct WaveBufferInformation
|
||||
{
|
||||
public Memory<VoiceUpdateState> State;
|
||||
public uint SourceSampleRate;
|
||||
public SampleFormat SampleFormat;
|
||||
public float Pitch;
|
||||
public DecodingBehaviour DecodingBehaviour;
|
||||
public WaveBuffer[] WaveBuffers;
|
||||
public ulong ExtraParameter;
|
||||
public ulong ExtraParameterSize;
|
||||
public int ChannelIndex;
|
||||
public int ChannelCount;
|
||||
public DecodingBehaviour DecodingBehaviour;
|
||||
public SampleRateConversionQuality SrcQuality;
|
||||
public SampleFormat SampleFormat;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static int GetPitchLimitBySrcQuality(SampleRateConversionQuality quality)
|
||||
{
|
||||
switch (quality)
|
||||
return quality switch
|
||||
{
|
||||
case SampleRateConversionQuality.Default:
|
||||
case SampleRateConversionQuality.Low:
|
||||
return 4;
|
||||
case SampleRateConversionQuality.High:
|
||||
return 8;
|
||||
default:
|
||||
throw new ArgumentException($"{quality}");
|
||||
}
|
||||
SampleRateConversionQuality.Default or SampleRateConversionQuality.Low => 4,
|
||||
SampleRateConversionQuality.High => 8,
|
||||
_ => throw new ArgumentException(quality.ToString()),
|
||||
};
|
||||
}
|
||||
|
||||
public static void ProcessWaveBuffers(IVirtualMemoryManager memoryManager, Span<float> outputBuffer, WaveBufferInformation info, uint targetSampleRate, int sampleCount)
|
||||
public static void ProcessWaveBuffers(IVirtualMemoryManager memoryManager, Span<float> outputBuffer, ref WaveBufferInformation info, Span<WaveBuffer> wavebuffers, ref VoiceUpdateState voiceState, uint targetSampleRate, int sampleCount)
|
||||
{
|
||||
const int tempBufferSize = 0x3F00;
|
||||
|
||||
ref VoiceUpdateState state = ref info.State.Span[0];
|
||||
Span<short> tempBuffer = stackalloc short[tempBufferSize];
|
||||
|
||||
short[] tempBuffer = ArrayPool<short>.Shared.Rent(tempBufferSize);
|
||||
float sampleRateRatio = (float)info.SourceSampleRate / targetSampleRate * info.Pitch;
|
||||
|
||||
float sampleRateRatio = ((float)info.SourceSampleRate / targetSampleRate * info.Pitch);
|
||||
|
||||
float fraction = state.Fraction;
|
||||
int waveBufferIndex = (int)state.WaveBufferIndex;
|
||||
ulong playedSampleCount = state.PlayedSampleCount;
|
||||
int offset = state.Offset;
|
||||
uint waveBufferConsumed = state.WaveBufferConsumed;
|
||||
float fraction = voiceState.Fraction;
|
||||
int waveBufferIndex = (int)voiceState.WaveBufferIndex;
|
||||
ulong playedSampleCount = voiceState.PlayedSampleCount;
|
||||
int offset = voiceState.Offset;
|
||||
uint waveBufferConsumed = voiceState.WaveBufferConsumed;
|
||||
|
||||
int pitchMaxLength = GetPitchLimitBySrcQuality(info.SrcQuality);
|
||||
|
||||
|
@ -101,7 +93,7 @@ namespace Ryujinx.Audio.Renderer.Dsp
|
|||
|
||||
if (!info.DecodingBehaviour.HasFlag(DecodingBehaviour.SkipPitchAndSampleRateConversion))
|
||||
{
|
||||
state.Pitch.ToSpan().Slice(0, pitchMaxLength).CopyTo(tempBuffer.AsSpan());
|
||||
voiceState.Pitch.ToSpan().Slice(0, pitchMaxLength).CopyTo(tempBuffer);
|
||||
tempBufferIndex += pitchMaxLength;
|
||||
}
|
||||
|
||||
|
@ -115,33 +107,31 @@ namespace Ryujinx.Audio.Renderer.Dsp
|
|||
{
|
||||
if (waveBufferIndex >= Constants.VoiceWaveBufferCount)
|
||||
{
|
||||
Logger.Error?.Print(LogClass.AudioRenderer, $"Invalid WaveBuffer index {waveBufferIndex}");
|
||||
|
||||
waveBufferIndex = 0;
|
||||
playedSampleCount = 0;
|
||||
}
|
||||
|
||||
if (!state.IsWaveBufferValid[waveBufferIndex])
|
||||
if (!voiceState.IsWaveBufferValid[waveBufferIndex])
|
||||
{
|
||||
isStarving = true;
|
||||
break;
|
||||
}
|
||||
|
||||
ref WaveBuffer waveBuffer = ref info.WaveBuffers[waveBufferIndex];
|
||||
ref WaveBuffer waveBuffer = ref wavebuffers[waveBufferIndex];
|
||||
|
||||
if (offset == 0 && info.SampleFormat == SampleFormat.Adpcm && waveBuffer.Context != 0)
|
||||
{
|
||||
state.LoopContext = memoryManager.Read<AdpcmLoopContext>(waveBuffer.Context);
|
||||
voiceState.LoopContext = memoryManager.Read<AdpcmLoopContext>(waveBuffer.Context);
|
||||
}
|
||||
|
||||
Span<short> tempSpan = tempBuffer.AsSpan().Slice(tempBufferIndex + y);
|
||||
Span<short> tempSpan = tempBuffer.Slice(tempBufferIndex + y);
|
||||
|
||||
int decodedSampleCount = -1;
|
||||
|
||||
int targetSampleStartOffset;
|
||||
int targetSampleEndOffset;
|
||||
|
||||
if (state.LoopCount > 0 && waveBuffer.LoopStartSampleOffset != 0 && waveBuffer.LoopEndSampleOffset != 0 && waveBuffer.LoopStartSampleOffset <= waveBuffer.LoopEndSampleOffset)
|
||||
if (voiceState.LoopCount > 0 && waveBuffer.LoopStartSampleOffset != 0 && waveBuffer.LoopEndSampleOffset != 0 && waveBuffer.LoopStartSampleOffset <= waveBuffer.LoopEndSampleOffset)
|
||||
{
|
||||
targetSampleStartOffset = (int)waveBuffer.LoopStartSampleOffset;
|
||||
targetSampleEndOffset = (int)waveBuffer.LoopEndSampleOffset;
|
||||
|
@ -166,7 +156,7 @@ namespace Ryujinx.Audio.Renderer.Dsp
|
|||
}
|
||||
|
||||
ReadOnlySpan<short> coefficients = MemoryMarshal.Cast<byte, short>(memoryManager.GetSpan(info.ExtraParameter, (int)info.ExtraParameterSize));
|
||||
decodedSampleCount = AdpcmHelper.Decode(tempSpan, waveBufferAdpcm, targetSampleStartOffset, targetSampleEndOffset, offset, sampleCountToDecode - y, coefficients, ref state.LoopContext);
|
||||
decodedSampleCount = AdpcmHelper.Decode(tempSpan, waveBufferAdpcm, targetSampleStartOffset, targetSampleEndOffset, offset, sampleCountToDecode - y, coefficients, ref voiceState.LoopContext);
|
||||
break;
|
||||
case SampleFormat.PcmInt16:
|
||||
ReadOnlySpan<short> waveBufferPcm16 = ReadOnlySpan<short>.Empty;
|
||||
|
@ -195,7 +185,7 @@ namespace Ryujinx.Audio.Renderer.Dsp
|
|||
decodedSampleCount = PcmHelper.Decode(tempSpan, waveBufferPcmFloat, targetSampleStartOffset, targetSampleEndOffset, info.ChannelIndex, info.ChannelCount);
|
||||
break;
|
||||
default:
|
||||
Logger.Warning?.Print(LogClass.AudioRenderer, $"Unsupported sample format {info.SampleFormat}");
|
||||
Logger.Error?.Print(LogClass.AudioRenderer, $"Unsupported sample format " + info.SampleFormat);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -203,9 +193,9 @@ namespace Ryujinx.Audio.Renderer.Dsp
|
|||
|
||||
if (decodedSampleCount < 0)
|
||||
{
|
||||
Logger.Warning?.Print(LogClass.AudioRenderer, $"Decoding failed, skipping WaveBuffer");
|
||||
Logger.Warning?.Print(LogClass.AudioRenderer, "Decoding failed, skipping WaveBuffer");
|
||||
|
||||
state.MarkEndOfBufferWaveBufferProcessing(ref waveBuffer, ref waveBufferIndex, ref waveBufferConsumed, ref playedSampleCount);
|
||||
voiceState.MarkEndOfBufferWaveBufferProcessing(ref waveBuffer, ref waveBufferIndex, ref waveBufferConsumed, ref playedSampleCount);
|
||||
decodedSampleCount = 0;
|
||||
}
|
||||
|
||||
|
@ -219,13 +209,13 @@ namespace Ryujinx.Audio.Renderer.Dsp
|
|||
|
||||
if (waveBuffer.Looping)
|
||||
{
|
||||
state.LoopCount++;
|
||||
voiceState.LoopCount++;
|
||||
|
||||
if (waveBuffer.LoopCount >= 0)
|
||||
{
|
||||
if (decodedSampleCount == 0 || state.LoopCount > waveBuffer.LoopCount)
|
||||
if (decodedSampleCount == 0 || voiceState.LoopCount > waveBuffer.LoopCount)
|
||||
{
|
||||
state.MarkEndOfBufferWaveBufferProcessing(ref waveBuffer, ref waveBufferIndex, ref waveBufferConsumed, ref playedSampleCount);
|
||||
voiceState.MarkEndOfBufferWaveBufferProcessing(ref waveBuffer, ref waveBufferIndex, ref waveBufferConsumed, ref playedSampleCount);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -242,13 +232,12 @@ namespace Ryujinx.Audio.Renderer.Dsp
|
|||
}
|
||||
else
|
||||
{
|
||||
state.MarkEndOfBufferWaveBufferProcessing(ref waveBuffer, ref waveBufferIndex, ref waveBufferConsumed, ref playedSampleCount);
|
||||
voiceState.MarkEndOfBufferWaveBufferProcessing(ref waveBuffer, ref waveBufferIndex, ref waveBufferConsumed, ref playedSampleCount);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Span<float> outputSpan = outputBuffer.Slice(i);
|
||||
Span<int> outputSpanInt = MemoryMarshal.Cast<float, int>(outputSpan);
|
||||
Span<int> outputSpanInt = MemoryMarshal.Cast<float, int>(outputBuffer.Slice(i));
|
||||
|
||||
if (info.DecodingBehaviour.HasFlag(DecodingBehaviour.SkipPitchAndSampleRateConversion))
|
||||
{
|
||||
|
@ -259,7 +248,7 @@ namespace Ryujinx.Audio.Renderer.Dsp
|
|||
}
|
||||
else
|
||||
{
|
||||
Span<short> tempSpan = tempBuffer.AsSpan().Slice(tempBufferIndex + y);
|
||||
Span<short> tempSpan = tempBuffer.Slice(tempBufferIndex + y);
|
||||
|
||||
tempSpan.Slice(0, sampleCountToDecode - y).Fill(0);
|
||||
|
||||
|
@ -267,7 +256,7 @@ namespace Ryujinx.Audio.Renderer.Dsp
|
|||
|
||||
ResamplerHelper.Resample(outputBuffer, tempBuffer, sampleRateRatio, ref fraction, sampleCountToProcess, info.SrcQuality, y != sourceSampleCountToProcess || info.Pitch != 1.0f);
|
||||
|
||||
tempBuffer.AsSpan().Slice(sampleCountToDecode, pitchMaxLength).CopyTo(state.Pitch.ToSpan());
|
||||
tempBuffer.Slice(sampleCountToDecode, pitchMaxLength).CopyTo(voiceState.Pitch.ToSpan());
|
||||
}
|
||||
|
||||
i += sampleCountToProcess;
|
||||
|
@ -275,16 +264,15 @@ namespace Ryujinx.Audio.Renderer.Dsp
|
|||
|
||||
Debug.Assert(sourceSampleCountToProcess == i || !isStarving);
|
||||
|
||||
state.WaveBufferConsumed = waveBufferConsumed;
|
||||
state.Offset = offset;
|
||||
state.PlayedSampleCount = playedSampleCount;
|
||||
state.WaveBufferIndex = (uint)waveBufferIndex;
|
||||
state.Fraction = fraction;
|
||||
voiceState.WaveBufferConsumed = waveBufferConsumed;
|
||||
voiceState.Offset = offset;
|
||||
voiceState.PlayedSampleCount = playedSampleCount;
|
||||
voiceState.WaveBufferIndex = (uint)waveBufferIndex;
|
||||
voiceState.Fraction = fraction;
|
||||
}
|
||||
|
||||
ArrayPool<short>.Shared.Return(tempBuffer);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static void ToFloatAvx(Span<float> output, ReadOnlySpan<int> input, int sampleCount)
|
||||
{
|
||||
ReadOnlySpan<Vector256<int>> inputVec = MemoryMarshal.Cast<int, Vector256<int>>(input);
|
||||
|
@ -303,6 +291,7 @@ namespace Ryujinx.Audio.Renderer.Dsp
|
|||
}
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static void ToFloatSse2(Span<float> output, ReadOnlySpan<int> input, int sampleCount)
|
||||
{
|
||||
ReadOnlySpan<Vector128<int>> inputVec = MemoryMarshal.Cast<int, Vector128<int>>(input);
|
||||
|
@ -321,6 +310,7 @@ namespace Ryujinx.Audio.Renderer.Dsp
|
|||
}
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static void ToFloatAdvSimd(Span<float> output, ReadOnlySpan<int> input, int sampleCount)
|
||||
{
|
||||
ReadOnlySpan<Vector128<int>> inputVec = MemoryMarshal.Cast<int, Vector128<int>>(input);
|
||||
|
@ -348,6 +338,7 @@ namespace Ryujinx.Audio.Renderer.Dsp
|
|||
}
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void ToFloat(Span<float> output, ReadOnlySpan<int> input, int sampleCount)
|
||||
{
|
||||
if (Avx.IsSupported)
|
||||
|
@ -368,6 +359,7 @@ namespace Ryujinx.Audio.Renderer.Dsp
|
|||
}
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void ToIntAvx(Span<int> output, ReadOnlySpan<float> input, int sampleCount)
|
||||
{
|
||||
ReadOnlySpan<Vector256<float>> inputVec = MemoryMarshal.Cast<float, Vector256<float>>(input);
|
||||
|
@ -386,6 +378,7 @@ namespace Ryujinx.Audio.Renderer.Dsp
|
|||
}
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void ToIntSse2(Span<int> output, ReadOnlySpan<float> input, int sampleCount)
|
||||
{
|
||||
ReadOnlySpan<Vector128<float>> inputVec = MemoryMarshal.Cast<float, Vector128<float>>(input);
|
||||
|
@ -404,6 +397,7 @@ namespace Ryujinx.Audio.Renderer.Dsp
|
|||
}
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void ToIntAdvSimd(Span<int> output, ReadOnlySpan<float> input, int sampleCount)
|
||||
{
|
||||
ReadOnlySpan<Vector128<float>> inputVec = MemoryMarshal.Cast<float, Vector128<float>>(input);
|
||||
|
@ -431,6 +425,7 @@ namespace Ryujinx.Audio.Renderer.Dsp
|
|||
}
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void ToInt(Span<int> output, ReadOnlySpan<float> input, int sampleCount)
|
||||
{
|
||||
if (Avx.IsSupported)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue