0
0
Fork 0

Compare commits

..

No commits in common. "a2c003501371463fd1f98d2e5a7602ae19c21d7c" and "ef81658fbd5b2aa23bf7e71b22a636da9a16c67b" have entirely different histories.

51 changed files with 187 additions and 582 deletions

View file

@ -23,7 +23,7 @@ body:
attributes: attributes:
label: Log file label: Log file
description: A log file will help our developers to better diagnose and fix the issue. description: A log file will help our developers to better diagnose and fix the issue.
placeholder: Logs files can be found under "Logs" folder in Ryujinx program folder. They can also be accessed by opening Ryujinx, then going to File > Open Logs Folder. You can drag and drop the log on to the text area (do not copy paste). placeholder: Logs files can be found under "Logs" folder in Ryujinx program folder. You can drag and drop the log on to the text area
validations: validations:
required: true required: true
- type: input - type: input
@ -83,4 +83,4 @@ body:
- Additional info about your environment: - Additional info about your environment:
- Any other information relevant to your issue. - Any other information relevant to your issue.
validations: validations:
required: false required: false

View file

@ -1,11 +1,9 @@
using Ryujinx.Audio.Renderer.Dsp.Effect; using Ryujinx.Audio.Renderer.Dsp.Effect;
using Ryujinx.Audio.Renderer.Dsp.State; using Ryujinx.Audio.Renderer.Dsp.State;
using Ryujinx.Audio.Renderer.Parameter;
using Ryujinx.Audio.Renderer.Parameter.Effect; using Ryujinx.Audio.Renderer.Parameter.Effect;
using Ryujinx.Audio.Renderer.Server.Effect; using Ryujinx.Audio.Renderer.Server.Effect;
using System; using System;
using System.Diagnostics; using System.Diagnostics;
using System.Runtime.InteropServices;
namespace Ryujinx.Audio.Renderer.Dsp.Command namespace Ryujinx.Audio.Renderer.Dsp.Command
{ {
@ -23,20 +21,18 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
public CompressorParameter Parameter => _parameter; public CompressorParameter Parameter => _parameter;
public Memory<CompressorState> State { get; } public Memory<CompressorState> State { get; }
public Memory<EffectResultState> ResultState { get; }
public ushort[] OutputBufferIndices { get; } public ushort[] OutputBufferIndices { get; }
public ushort[] InputBufferIndices { get; } public ushort[] InputBufferIndices { get; }
public bool IsEffectEnabled { get; } public bool IsEffectEnabled { get; }
private CompressorParameter _parameter; private CompressorParameter _parameter;
public CompressorCommand(uint bufferOffset, CompressorParameter parameter, Memory<CompressorState> state, Memory<EffectResultState> resultState, bool isEnabled, int nodeId) public CompressorCommand(uint bufferOffset, CompressorParameter parameter, Memory<CompressorState> state, bool isEnabled, int nodeId)
{ {
Enabled = true; Enabled = true;
NodeId = nodeId; NodeId = nodeId;
_parameter = parameter; _parameter = parameter;
State = state; State = state;
ResultState = resultState;
IsEffectEnabled = isEnabled; IsEffectEnabled = isEnabled;
@ -75,16 +71,9 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
if (IsEffectEnabled && _parameter.IsChannelCountValid()) if (IsEffectEnabled && _parameter.IsChannelCountValid())
{ {
if (!ResultState.IsEmpty && _parameter.StatisticsReset) Span<IntPtr> inputBuffers = stackalloc IntPtr[Parameter.ChannelCount];
{ Span<IntPtr> outputBuffers = stackalloc IntPtr[Parameter.ChannelCount];
ref CompressorStatistics statistics = ref MemoryMarshal.Cast<byte, CompressorStatistics>(ResultState.Span[0].SpecificData)[0]; Span<float> channelInput = stackalloc float[Parameter.ChannelCount];
statistics.Reset(_parameter.ChannelCount);
}
Span<IntPtr> inputBuffers = stackalloc IntPtr[_parameter.ChannelCount];
Span<IntPtr> outputBuffers = stackalloc IntPtr[_parameter.ChannelCount];
Span<float> channelInput = stackalloc float[_parameter.ChannelCount];
ExponentialMovingAverage inputMovingAverage = state.InputMovingAverage; ExponentialMovingAverage inputMovingAverage = state.InputMovingAverage;
float unknown4 = state.Unknown4; float unknown4 = state.Unknown4;
ExponentialMovingAverage compressionGainAverage = state.CompressionGainAverage; ExponentialMovingAverage compressionGainAverage = state.CompressionGainAverage;
@ -103,8 +92,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
channelInput[channelIndex] = *((float*)inputBuffers[channelIndex] + sampleIndex); channelInput[channelIndex] = *((float*)inputBuffers[channelIndex] + sampleIndex);
} }
float mean = FloatingPointHelper.MeanSquare(channelInput); float newMean = inputMovingAverage.Update(FloatingPointHelper.MeanSquare(channelInput), _parameter.InputGain);
float newMean = inputMovingAverage.Update(mean, _parameter.InputGain);
float y = FloatingPointHelper.Log10(newMean) * 10.0f; float y = FloatingPointHelper.Log10(newMean) * 10.0f;
float z = 1.0f; float z = 1.0f;
@ -123,7 +111,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
if (y >= state.Unknown14) if (y >= state.Unknown14)
{ {
tmpGain = ((1.0f / _parameter.Ratio) - 1.0f) * (y - _parameter.Threshold); tmpGain = ((1.0f / Parameter.Ratio) - 1.0f) * (y - Parameter.Threshold);
} }
else else
{ {
@ -138,7 +126,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
if ((unknown4 - z) <= 0.08f) if ((unknown4 - z) <= 0.08f)
{ {
compressionEmaAlpha = _parameter.ReleaseCoefficient; compressionEmaAlpha = Parameter.ReleaseCoefficient;
if ((unknown4 - z) >= -0.08f) if ((unknown4 - z) >= -0.08f)
{ {
@ -152,31 +140,18 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
} }
else else
{ {
compressionEmaAlpha = _parameter.AttackCoefficient; compressionEmaAlpha = Parameter.AttackCoefficient;
} }
float compressionGain = compressionGainAverage.Update(z, compressionEmaAlpha); float compressionGain = compressionGainAverage.Update(z, compressionEmaAlpha);
for (int channelIndex = 0; channelIndex < _parameter.ChannelCount; channelIndex++) for (int channelIndex = 0; channelIndex < Parameter.ChannelCount; channelIndex++)
{ {
*((float*)outputBuffers[channelIndex] + sampleIndex) = channelInput[channelIndex] * compressionGain * state.OutputGain; *((float*)outputBuffers[channelIndex] + sampleIndex) = channelInput[channelIndex] * compressionGain * state.OutputGain;
} }
unknown4 = unknown4New; unknown4 = unknown4New;
previousCompressionEmaAlpha = compressionEmaAlpha; previousCompressionEmaAlpha = compressionEmaAlpha;
if (!ResultState.IsEmpty)
{
ref CompressorStatistics statistics = ref MemoryMarshal.Cast<byte, CompressorStatistics>(ResultState.Span[0].SpecificData)[0];
statistics.MinimumGain = MathF.Min(statistics.MinimumGain, compressionGain * state.OutputGain);
statistics.MaximumMean = MathF.Max(statistics.MaximumMean, mean);
for (int channelIndex = 0; channelIndex < _parameter.ChannelCount; channelIndex++)
{
statistics.LastSamples[channelIndex] = MathF.Abs(channelInput[channelIndex] * (1f / 32768f));
}
}
} }
state.InputMovingAverage = inputMovingAverage; state.InputMovingAverage = inputMovingAverage;
@ -186,7 +161,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
} }
else else
{ {
for (int i = 0; i < _parameter.ChannelCount; i++) for (int i = 0; i < Parameter.ChannelCount; i++)
{ {
if (InputBufferIndices[i] != OutputBufferIndices[i]) if (InputBufferIndices[i] != OutputBufferIndices[i])
{ {

View file

@ -38,10 +38,10 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
InputBufferIndices = new ushort[Constants.VoiceChannelCountMax]; InputBufferIndices = new ushort[Constants.VoiceChannelCountMax];
OutputBufferIndices = new ushort[Constants.VoiceChannelCountMax]; OutputBufferIndices = new ushort[Constants.VoiceChannelCountMax];
for (int i = 0; i < _parameter.ChannelCount; i++) for (int i = 0; i < Parameter.ChannelCount; i++)
{ {
InputBufferIndices[i] = (ushort)(bufferOffset + _parameter.Input[i]); InputBufferIndices[i] = (ushort)(bufferOffset + Parameter.Input[i]);
OutputBufferIndices[i] = (ushort)(bufferOffset + _parameter.Output[i]); OutputBufferIndices[i] = (ushort)(bufferOffset + Parameter.Output[i]);
} }
} }
@ -51,11 +51,11 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
if (IsEffectEnabled) if (IsEffectEnabled)
{ {
if (_parameter.Status == UsageState.Invalid) if (Parameter.Status == UsageState.Invalid)
{ {
state = new LimiterState(ref _parameter, WorkBuffer); state = new LimiterState(ref _parameter, WorkBuffer);
} }
else if (_parameter.Status == UsageState.New) else if (Parameter.Status == UsageState.New)
{ {
LimiterState.UpdateParameter(ref _parameter); LimiterState.UpdateParameter(ref _parameter);
} }
@ -66,56 +66,56 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
private unsafe void ProcessLimiter(CommandList context, ref LimiterState state) private unsafe void ProcessLimiter(CommandList context, ref LimiterState state)
{ {
Debug.Assert(_parameter.IsChannelCountValid()); Debug.Assert(Parameter.IsChannelCountValid());
if (IsEffectEnabled && _parameter.IsChannelCountValid()) if (IsEffectEnabled && Parameter.IsChannelCountValid())
{ {
Span<IntPtr> inputBuffers = stackalloc IntPtr[_parameter.ChannelCount]; Span<IntPtr> inputBuffers = stackalloc IntPtr[Parameter.ChannelCount];
Span<IntPtr> outputBuffers = stackalloc IntPtr[_parameter.ChannelCount]; Span<IntPtr> outputBuffers = stackalloc IntPtr[Parameter.ChannelCount];
for (int i = 0; i < _parameter.ChannelCount; i++) for (int i = 0; i < Parameter.ChannelCount; i++)
{ {
inputBuffers[i] = context.GetBufferPointer(InputBufferIndices[i]); inputBuffers[i] = context.GetBufferPointer(InputBufferIndices[i]);
outputBuffers[i] = context.GetBufferPointer(OutputBufferIndices[i]); outputBuffers[i] = context.GetBufferPointer(OutputBufferIndices[i]);
} }
for (int channelIndex = 0; channelIndex < _parameter.ChannelCount; channelIndex++) for (int channelIndex = 0; channelIndex < Parameter.ChannelCount; channelIndex++)
{ {
for (int sampleIndex = 0; sampleIndex < context.SampleCount; sampleIndex++) for (int sampleIndex = 0; sampleIndex < context.SampleCount; sampleIndex++)
{ {
float rawInputSample = *((float*)inputBuffers[channelIndex] + sampleIndex); float rawInputSample = *((float*)inputBuffers[channelIndex] + sampleIndex);
float inputSample = (rawInputSample / short.MaxValue) * _parameter.InputGain; float inputSample = (rawInputSample / short.MaxValue) * Parameter.InputGain;
float sampleInputMax = Math.Abs(inputSample); float sampleInputMax = Math.Abs(inputSample);
float inputCoefficient = _parameter.ReleaseCoefficient; float inputCoefficient = Parameter.ReleaseCoefficient;
if (sampleInputMax > state.DetectorAverage[channelIndex].Read()) if (sampleInputMax > state.DetectorAverage[channelIndex].Read())
{ {
inputCoefficient = _parameter.AttackCoefficient; inputCoefficient = Parameter.AttackCoefficient;
} }
float detectorValue = state.DetectorAverage[channelIndex].Update(sampleInputMax, inputCoefficient); float detectorValue = state.DetectorAverage[channelIndex].Update(sampleInputMax, inputCoefficient);
float attenuation = 1.0f; float attenuation = 1.0f;
if (detectorValue > _parameter.Threshold) if (detectorValue > Parameter.Threshold)
{ {
attenuation = _parameter.Threshold / detectorValue; attenuation = Parameter.Threshold / detectorValue;
} }
float outputCoefficient = _parameter.ReleaseCoefficient; float outputCoefficient = Parameter.ReleaseCoefficient;
if (state.CompressionGainAverage[channelIndex].Read() > attenuation) if (state.CompressionGainAverage[channelIndex].Read() > attenuation)
{ {
outputCoefficient = _parameter.AttackCoefficient; outputCoefficient = Parameter.AttackCoefficient;
} }
float compressionGain = state.CompressionGainAverage[channelIndex].Update(attenuation, outputCoefficient); float compressionGain = state.CompressionGainAverage[channelIndex].Update(attenuation, outputCoefficient);
ref float delayedSample = ref state.DelayedSampleBuffer[channelIndex * _parameter.DelayBufferSampleCountMax + state.DelayedSampleBufferPosition[channelIndex]]; ref float delayedSample = ref state.DelayedSampleBuffer[channelIndex * Parameter.DelayBufferSampleCountMax + state.DelayedSampleBufferPosition[channelIndex]];
float outputSample = delayedSample * compressionGain * _parameter.OutputGain; float outputSample = delayedSample * compressionGain * Parameter.OutputGain;
*((float*)outputBuffers[channelIndex] + sampleIndex) = outputSample * short.MaxValue; *((float*)outputBuffers[channelIndex] + sampleIndex) = outputSample * short.MaxValue;
@ -123,16 +123,16 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
state.DelayedSampleBufferPosition[channelIndex]++; state.DelayedSampleBufferPosition[channelIndex]++;
while (state.DelayedSampleBufferPosition[channelIndex] >= _parameter.DelayBufferSampleCountMin) while (state.DelayedSampleBufferPosition[channelIndex] >= Parameter.DelayBufferSampleCountMin)
{ {
state.DelayedSampleBufferPosition[channelIndex] -= _parameter.DelayBufferSampleCountMin; state.DelayedSampleBufferPosition[channelIndex] -= Parameter.DelayBufferSampleCountMin;
} }
} }
} }
} }
else else
{ {
for (int i = 0; i < _parameter.ChannelCount; i++) for (int i = 0; i < Parameter.ChannelCount; i++)
{ {
if (InputBufferIndices[i] != OutputBufferIndices[i]) if (InputBufferIndices[i] != OutputBufferIndices[i])
{ {

View file

@ -49,10 +49,10 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
InputBufferIndices = new ushort[Constants.VoiceChannelCountMax]; InputBufferIndices = new ushort[Constants.VoiceChannelCountMax];
OutputBufferIndices = new ushort[Constants.VoiceChannelCountMax]; OutputBufferIndices = new ushort[Constants.VoiceChannelCountMax];
for (int i = 0; i < _parameter.ChannelCount; i++) for (int i = 0; i < Parameter.ChannelCount; i++)
{ {
InputBufferIndices[i] = (ushort)(bufferOffset + _parameter.Input[i]); InputBufferIndices[i] = (ushort)(bufferOffset + Parameter.Input[i]);
OutputBufferIndices[i] = (ushort)(bufferOffset + _parameter.Output[i]); OutputBufferIndices[i] = (ushort)(bufferOffset + Parameter.Output[i]);
} }
} }
@ -62,11 +62,11 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
if (IsEffectEnabled) if (IsEffectEnabled)
{ {
if (_parameter.Status == UsageState.Invalid) if (Parameter.Status == UsageState.Invalid)
{ {
state = new LimiterState(ref _parameter, WorkBuffer); state = new LimiterState(ref _parameter, WorkBuffer);
} }
else if (_parameter.Status == UsageState.New) else if (Parameter.Status == UsageState.New)
{ {
LimiterState.UpdateParameter(ref _parameter); LimiterState.UpdateParameter(ref _parameter);
} }
@ -77,63 +77,63 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
private unsafe void ProcessLimiter(CommandList context, ref LimiterState state) private unsafe void ProcessLimiter(CommandList context, ref LimiterState state)
{ {
Debug.Assert(_parameter.IsChannelCountValid()); Debug.Assert(Parameter.IsChannelCountValid());
if (IsEffectEnabled && _parameter.IsChannelCountValid()) if (IsEffectEnabled && Parameter.IsChannelCountValid())
{ {
if (!ResultState.IsEmpty && _parameter.StatisticsReset) if (!ResultState.IsEmpty && Parameter.StatisticsReset)
{ {
ref LimiterStatistics statistics = ref MemoryMarshal.Cast<byte, LimiterStatistics>(ResultState.Span[0].SpecificData)[0]; ref LimiterStatistics statistics = ref MemoryMarshal.Cast<byte, LimiterStatistics>(ResultState.Span[0].SpecificData)[0];
statistics.Reset(); statistics.Reset();
} }
Span<IntPtr> inputBuffers = stackalloc IntPtr[_parameter.ChannelCount]; Span<IntPtr> inputBuffers = stackalloc IntPtr[Parameter.ChannelCount];
Span<IntPtr> outputBuffers = stackalloc IntPtr[_parameter.ChannelCount]; Span<IntPtr> outputBuffers = stackalloc IntPtr[Parameter.ChannelCount];
for (int i = 0; i < _parameter.ChannelCount; i++) for (int i = 0; i < Parameter.ChannelCount; i++)
{ {
inputBuffers[i] = context.GetBufferPointer(InputBufferIndices[i]); inputBuffers[i] = context.GetBufferPointer(InputBufferIndices[i]);
outputBuffers[i] = context.GetBufferPointer(OutputBufferIndices[i]); outputBuffers[i] = context.GetBufferPointer(OutputBufferIndices[i]);
} }
for (int channelIndex = 0; channelIndex < _parameter.ChannelCount; channelIndex++) for (int channelIndex = 0; channelIndex < Parameter.ChannelCount; channelIndex++)
{ {
for (int sampleIndex = 0; sampleIndex < context.SampleCount; sampleIndex++) for (int sampleIndex = 0; sampleIndex < context.SampleCount; sampleIndex++)
{ {
float rawInputSample = *((float*)inputBuffers[channelIndex] + sampleIndex); float rawInputSample = *((float*)inputBuffers[channelIndex] + sampleIndex);
float inputSample = (rawInputSample / short.MaxValue) * _parameter.InputGain; float inputSample = (rawInputSample / short.MaxValue) * Parameter.InputGain;
float sampleInputMax = Math.Abs(inputSample); float sampleInputMax = Math.Abs(inputSample);
float inputCoefficient = _parameter.ReleaseCoefficient; float inputCoefficient = Parameter.ReleaseCoefficient;
if (sampleInputMax > state.DetectorAverage[channelIndex].Read()) if (sampleInputMax > state.DetectorAverage[channelIndex].Read())
{ {
inputCoefficient = _parameter.AttackCoefficient; inputCoefficient = Parameter.AttackCoefficient;
} }
float detectorValue = state.DetectorAverage[channelIndex].Update(sampleInputMax, inputCoefficient); float detectorValue = state.DetectorAverage[channelIndex].Update(sampleInputMax, inputCoefficient);
float attenuation = 1.0f; float attenuation = 1.0f;
if (detectorValue > _parameter.Threshold) if (detectorValue > Parameter.Threshold)
{ {
attenuation = _parameter.Threshold / detectorValue; attenuation = Parameter.Threshold / detectorValue;
} }
float outputCoefficient = _parameter.ReleaseCoefficient; float outputCoefficient = Parameter.ReleaseCoefficient;
if (state.CompressionGainAverage[channelIndex].Read() > attenuation) if (state.CompressionGainAverage[channelIndex].Read() > attenuation)
{ {
outputCoefficient = _parameter.AttackCoefficient; outputCoefficient = Parameter.AttackCoefficient;
} }
float compressionGain = state.CompressionGainAverage[channelIndex].Update(attenuation, outputCoefficient); float compressionGain = state.CompressionGainAverage[channelIndex].Update(attenuation, outputCoefficient);
ref float delayedSample = ref state.DelayedSampleBuffer[channelIndex * _parameter.DelayBufferSampleCountMax + state.DelayedSampleBufferPosition[channelIndex]]; ref float delayedSample = ref state.DelayedSampleBuffer[channelIndex * Parameter.DelayBufferSampleCountMax + state.DelayedSampleBufferPosition[channelIndex]];
float outputSample = delayedSample * compressionGain * _parameter.OutputGain; float outputSample = delayedSample * compressionGain * Parameter.OutputGain;
*((float*)outputBuffers[channelIndex] + sampleIndex) = outputSample * short.MaxValue; *((float*)outputBuffers[channelIndex] + sampleIndex) = outputSample * short.MaxValue;
@ -141,9 +141,9 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
state.DelayedSampleBufferPosition[channelIndex]++; state.DelayedSampleBufferPosition[channelIndex]++;
while (state.DelayedSampleBufferPosition[channelIndex] >= _parameter.DelayBufferSampleCountMin) while (state.DelayedSampleBufferPosition[channelIndex] >= Parameter.DelayBufferSampleCountMin)
{ {
state.DelayedSampleBufferPosition[channelIndex] -= _parameter.DelayBufferSampleCountMin; state.DelayedSampleBufferPosition[channelIndex] -= Parameter.DelayBufferSampleCountMin;
} }
if (!ResultState.IsEmpty) if (!ResultState.IsEmpty)
@ -158,7 +158,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
} }
else else
{ {
for (int i = 0; i < _parameter.ChannelCount; i++) for (int i = 0; i < Parameter.ChannelCount; i++)
{ {
if (InputBufferIndices[i] != OutputBufferIndices[i]) if (InputBufferIndices[i] != OutputBufferIndices[i])
{ {

View file

@ -90,16 +90,9 @@ namespace Ryujinx.Audio.Renderer.Parameter.Effect
public bool MakeupGainEnabled; public bool MakeupGainEnabled;
/// <summary> /// <summary>
/// Indicate if the compressor effect should output statistics. /// Reserved/padding.
/// </summary> /// </summary>
[MarshalAs(UnmanagedType.I1)] private Array2<byte> _reserved;
public bool StatisticsEnabled;
/// <summary>
/// Indicate to the DSP that the user did a statistics reset.
/// </summary>
[MarshalAs(UnmanagedType.I1)]
public bool StatisticsReset;
/// <summary> /// <summary>
/// Check if the <see cref="ChannelCount"/> is valid. /// Check if the <see cref="ChannelCount"/> is valid.

View file

@ -1,38 +0,0 @@
using Ryujinx.Common.Memory;
using System.Runtime.InteropServices;
namespace Ryujinx.Audio.Renderer.Parameter.Effect
{
/// <summary>
/// Effect result state for <seealso cref="Common.EffectType.Compressor"/>.
/// </summary>
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct CompressorStatistics
{
/// <summary>
/// Maximum input mean value since last reset.
/// </summary>
public float MaximumMean;
/// <summary>
/// Minimum output gain since last reset.
/// </summary>
public float MinimumGain;
/// <summary>
/// Last processed input sample, per channel.
/// </summary>
public Array6<float> LastSamples;
/// <summary>
/// Reset the statistics.
/// </summary>
/// <param name="channelCount">Number of channels to reset.</param>
public void Reset(ushort channelCount)
{
MaximumMean = 0.0f;
MinimumGain = 1.0f;
LastSamples.AsSpan()[..channelCount].Clear();
}
}
}

View file

@ -28,11 +28,6 @@ namespace Ryujinx.Audio.Renderer.Parameter
/// </summary> /// </summary>
bool IsUsed { get; } bool IsUsed { get; }
/// <summary>
/// Set to true to force resetting the previous mix volumes.
/// </summary>
bool ResetPrevVolume { get; }
/// <summary> /// <summary>
/// Mix buffer volumes. /// Mix buffer volumes.
/// </summary> /// </summary>

View file

@ -37,16 +37,10 @@ namespace Ryujinx.Audio.Renderer.Parameter
[MarshalAs(UnmanagedType.I1)] [MarshalAs(UnmanagedType.I1)]
public bool IsUsed; public bool IsUsed;
/// <summary>
/// Set to true to force resetting the previous mix volumes.
/// </summary>
[MarshalAs(UnmanagedType.I1)]
public bool ResetPrevVolume;
/// <summary> /// <summary>
/// Reserved/padding. /// Reserved/padding.
/// </summary> /// </summary>
private unsafe fixed byte _reserved[2]; private unsafe fixed byte _reserved[3];
[StructLayout(LayoutKind.Sequential, Size = sizeof(float) * Constants.MixBufferCountMax, Pack = 1)] [StructLayout(LayoutKind.Sequential, Size = sizeof(float) * Constants.MixBufferCountMax, Pack = 1)]
private struct MixArray { } private struct MixArray { }
@ -64,7 +58,6 @@ namespace Ryujinx.Audio.Renderer.Parameter
readonly Array2<BiquadFilterParameter> ISplitterDestinationInParameter.BiquadFilters => default; readonly Array2<BiquadFilterParameter> ISplitterDestinationInParameter.BiquadFilters => default;
readonly bool ISplitterDestinationInParameter.IsUsed => IsUsed; readonly bool ISplitterDestinationInParameter.IsUsed => IsUsed;
readonly bool ISplitterDestinationInParameter.ResetPrevVolume => ResetPrevVolume;
/// <summary> /// <summary>
/// The expected constant of any input header. /// The expected constant of any input header.

View file

@ -42,16 +42,10 @@ namespace Ryujinx.Audio.Renderer.Parameter
[MarshalAs(UnmanagedType.I1)] [MarshalAs(UnmanagedType.I1)]
public bool IsUsed; public bool IsUsed;
/// <summary>
/// Set to true to force resetting the previous mix volumes.
/// </summary>
[MarshalAs(UnmanagedType.I1)]
public bool ResetPrevVolume;
/// <summary> /// <summary>
/// Reserved/padding. /// Reserved/padding.
/// </summary> /// </summary>
private unsafe fixed byte _reserved[10]; private unsafe fixed byte _reserved[11];
[StructLayout(LayoutKind.Sequential, Size = sizeof(float) * Constants.MixBufferCountMax, Pack = 1)] [StructLayout(LayoutKind.Sequential, Size = sizeof(float) * Constants.MixBufferCountMax, Pack = 1)]
private struct MixArray { } private struct MixArray { }
@ -69,7 +63,6 @@ namespace Ryujinx.Audio.Renderer.Parameter
readonly Array2<BiquadFilterParameter> ISplitterDestinationInParameter.BiquadFilters => BiquadFilters; readonly Array2<BiquadFilterParameter> ISplitterDestinationInParameter.BiquadFilters => BiquadFilters;
readonly bool ISplitterDestinationInParameter.IsUsed => IsUsed; readonly bool ISplitterDestinationInParameter.IsUsed => IsUsed;
readonly bool ISplitterDestinationInParameter.ResetPrevVolume => ResetPrevVolume;
/// <summary> /// <summary>
/// The expected constant of any input header. /// The expected constant of any input header.

View file

@ -108,18 +108,10 @@ namespace Ryujinx.Audio.Renderer.Server
/// <remarks>This was added in system update 17.0.0</remarks> /// <remarks>This was added in system update 17.0.0</remarks>
public const int Revision12 = 12 << 24; public const int Revision12 = 12 << 24;
/// <summary>
/// REV13:
/// The compressor effect can now output statistics.
/// Splitter destinations now explicitly reset the previous mix volume, instead of doing so on first use.
/// </summary>
/// <remarks>This was added in system update 18.0.0</remarks>
public const int Revision13 = 13 << 24;
/// <summary> /// <summary>
/// Last revision supported by the implementation. /// Last revision supported by the implementation.
/// </summary> /// </summary>
public const int LastRevision = Revision13; public const int LastRevision = Revision12;
/// <summary> /// <summary>
/// Target revision magic supported by the implementation. /// Target revision magic supported by the implementation.
@ -392,15 +384,6 @@ namespace Ryujinx.Audio.Renderer.Server
return CheckFeatureSupported(UserRevision, BaseRevisionMagic + Revision12); return CheckFeatureSupported(UserRevision, BaseRevisionMagic + Revision12);
} }
/// <summary>
/// Check if the audio renderer should support explicit previous mix volume reset on splitter.
/// </summary>
/// <returns>True if the audio renderer support explicit previous mix volume reset on splitter</returns>
public bool IsSplitterPrevVolumeResetSupported()
{
return CheckFeatureSupported(UserRevision, BaseRevisionMagic + Revision13);
}
/// <summary> /// <summary>
/// Get the version of the <see cref="ICommandProcessingTimeEstimator"/>. /// Get the version of the <see cref="ICommandProcessingTimeEstimator"/>.
/// </summary> /// </summary>

View file

@ -583,20 +583,11 @@ namespace Ryujinx.Audio.Renderer.Server
} }
} }
/// <summary> public void GenerateCompressorEffect(uint bufferOffset, CompressorParameter parameter, Memory<CompressorState> state, bool isEnabled, int nodeId)
/// Generate a new <see cref="CompressorCommand"/>.
/// </summary>
/// <param name="bufferOffset">The target buffer offset.</param>
/// <param name="parameter">The compressor parameter.</param>
/// <param name="state">The compressor 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="nodeId">The node id associated to this command.</param>
public void GenerateCompressorEffect(uint bufferOffset, CompressorParameter parameter, Memory<CompressorState> state, Memory<EffectResultState> effectResultState, bool isEnabled, int nodeId)
{ {
if (parameter.IsChannelCountValid()) if (parameter.IsChannelCountValid())
{ {
CompressorCommand command = new(bufferOffset, parameter, state, effectResultState, isEnabled, nodeId); CompressorCommand command = new(bufferOffset, parameter, state, isEnabled, nodeId);
command.EstimatedProcessingTime = _commandProcessingTimeEstimator.Estimate(command); command.EstimatedProcessingTime = _commandProcessingTimeEstimator.Estimate(command);

View file

@ -735,26 +735,14 @@ namespace Ryujinx.Audio.Renderer.Server
} }
} }
private void GenerateCompressorEffect(uint bufferOffset, CompressorEffect effect, int nodeId, int effectId) private void GenerateCompressorEffect(uint bufferOffset, CompressorEffect effect, int nodeId)
{ {
Debug.Assert(effect.Type == EffectType.Compressor); Debug.Assert(effect.Type == EffectType.Compressor);
Memory<EffectResultState> dspResultState;
if (effect.Parameter.StatisticsEnabled)
{
dspResultState = _effectContext.GetDspStateMemory(effectId);
}
else
{
dspResultState = Memory<EffectResultState>.Empty;
}
_commandBuffer.GenerateCompressorEffect( _commandBuffer.GenerateCompressorEffect(
bufferOffset, bufferOffset,
effect.Parameter, effect.Parameter,
effect.State, effect.State,
dspResultState,
effect.IsEnabled, effect.IsEnabled,
nodeId); nodeId);
} }
@ -807,7 +795,7 @@ namespace Ryujinx.Audio.Renderer.Server
GenerateCaptureEffect(mix.BufferOffset, (CaptureBufferEffect)effect, nodeId); GenerateCaptureEffect(mix.BufferOffset, (CaptureBufferEffect)effect, nodeId);
break; break;
case EffectType.Compressor: case EffectType.Compressor:
GenerateCompressorEffect(mix.BufferOffset, (CompressorEffect)effect, nodeId, effectId); GenerateCompressorEffect(mix.BufferOffset, (CompressorEffect)effect, nodeId);
break; break;
default: default:
throw new NotImplementedException($"Unsupported effect type {effect.Type}"); throw new NotImplementedException($"Unsupported effect type {effect.Type}");

View file

@ -169,28 +169,14 @@ namespace Ryujinx.Audio.Renderer.Server
{ {
if (command.Enabled) if (command.Enabled)
{ {
if (command.Parameter.StatisticsEnabled) return command.Parameter.ChannelCount switch
{ {
return command.Parameter.ChannelCount switch 1 => 34431,
{ 2 => 44253,
1 => 22100, 4 => 63827,
2 => 33211, 6 => 83361,
4 => 41587, _ => throw new NotImplementedException($"{command.Parameter.ChannelCount}"),
6 => 58819, };
_ => throw new NotImplementedException($"{command.Parameter.ChannelCount}"),
};
}
else
{
return command.Parameter.ChannelCount switch
{
1 => 19052,
2 => 29852,
4 => 37904,
6 => 55020,
_ => throw new NotImplementedException($"{command.Parameter.ChannelCount}"),
};
}
} }
return command.Parameter.ChannelCount switch return command.Parameter.ChannelCount switch
@ -205,28 +191,14 @@ namespace Ryujinx.Audio.Renderer.Server
if (command.Enabled) if (command.Enabled)
{ {
if (command.Parameter.StatisticsEnabled) return command.Parameter.ChannelCount switch
{ {
return command.Parameter.ChannelCount switch 1 => 51095,
{ 2 => 65693,
1 => 32518, 4 => 95383,
2 => 49102, 6 => 124510,
4 => 61685, _ => throw new NotImplementedException($"{command.Parameter.ChannelCount}"),
6 => 87250, };
_ => throw new NotImplementedException($"{command.Parameter.ChannelCount}"),
};
}
else
{
return command.Parameter.ChannelCount switch
{
1 => 27963,
2 => 44016,
4 => 56183,
6 => 81862,
_ => throw new NotImplementedException($"{command.Parameter.ChannelCount}"),
};
}
} }
return command.Parameter.ChannelCount switch return command.Parameter.ChannelCount switch

View file

@ -62,19 +62,6 @@ namespace Ryujinx.Audio.Renderer.Server.Effect
UpdateUsageStateForCommandGeneration(); UpdateUsageStateForCommandGeneration();
Parameter.Status = UsageState.Enabled; Parameter.Status = UsageState.Enabled;
Parameter.StatisticsReset = false;
}
public override void InitializeResultState(ref EffectResultState state)
{
ref CompressorStatistics statistics = ref MemoryMarshal.Cast<byte, CompressorStatistics>(state.SpecificData)[0];
statistics.Reset(Parameter.ChannelCount);
}
public override void UpdateResultState(ref EffectResultState destState, ref EffectResultState srcState)
{
destState = srcState;
} }
} }
} }

View file

@ -51,11 +51,6 @@ namespace Ryujinx.Audio.Renderer.Server.Splitter
/// </summary> /// </summary>
public bool IsBugFixed { get; private set; } public bool IsBugFixed { get; private set; }
/// <summary>
/// If set to true, the previous mix volume is explicitly resetted using the input parameter, instead of implicitly on first use.
/// </summary>
public bool IsSplitterPrevVolumeResetSupported { get; private set; }
/// <summary> /// <summary>
/// Initialize <see cref="SplitterContext"/>. /// Initialize <see cref="SplitterContext"/>.
/// </summary> /// </summary>
@ -144,8 +139,6 @@ namespace Ryujinx.Audio.Renderer.Server.Splitter
} }
} }
IsSplitterPrevVolumeResetSupported = behaviourContext.IsSplitterPrevVolumeResetSupported();
SplitterState.InitializeSplitters(splitters.Span); SplitterState.InitializeSplitters(splitters.Span);
Setup(splitters, splitterDestinationsV1, splitterDestinationsV2, behaviourContext.IsSplitterBugFixed()); Setup(splitters, splitterDestinationsV1, splitterDestinationsV2, behaviourContext.IsSplitterBugFixed());
@ -284,7 +277,7 @@ namespace Ryujinx.Audio.Renderer.Server.Splitter
{ {
SplitterDestination destination = GetDestination(parameter.Id); SplitterDestination destination = GetDestination(parameter.Id);
destination.Update(parameter, IsSplitterPrevVolumeResetSupported); destination.Update(parameter);
} }
return true; return true;

View file

@ -184,16 +184,15 @@ namespace Ryujinx.Audio.Renderer.Server.Splitter
/// Update the splitter destination data from user parameter. /// Update the splitter destination data from user parameter.
/// </summary> /// </summary>
/// <param name="parameter">The user parameter.</param> /// <param name="parameter">The user parameter.</param>
/// <param name="isPrevVolumeResetSupported">Indicates that the audio renderer revision in use supports explicitly resetting the volume.</param> public void Update<T>(in T parameter) where T : ISplitterDestinationInParameter
public void Update<T>(in T parameter, bool isPrevVolumeResetSupported) where T : ISplitterDestinationInParameter
{ {
if (Unsafe.IsNullRef(ref _v2)) if (Unsafe.IsNullRef(ref _v2))
{ {
_v1.Update(parameter, isPrevVolumeResetSupported); _v1.Update(parameter);
} }
else else
{ {
_v2.Update(parameter, isPrevVolumeResetSupported); _v2.Update(parameter);
} }
} }

View file

@ -93,8 +93,7 @@ namespace Ryujinx.Audio.Renderer.Server.Splitter
/// Update the <see cref="SplitterDestinationVersion1"/> from user parameter. /// Update the <see cref="SplitterDestinationVersion1"/> from user parameter.
/// </summary> /// </summary>
/// <param name="parameter">The user parameter.</param> /// <param name="parameter">The user parameter.</param>
/// <param name="isPrevVolumeResetSupported">Indicates that the audio renderer revision in use supports explicitly resetting the volume.</param> public void Update<T>(in T parameter) where T : ISplitterDestinationInParameter
public void Update<T>(in T parameter, bool isPrevVolumeResetSupported) where T : ISplitterDestinationInParameter
{ {
Debug.Assert(Id == parameter.Id); Debug.Assert(Id == parameter.Id);
@ -104,8 +103,7 @@ namespace Ryujinx.Audio.Renderer.Server.Splitter
parameter.MixBufferVolume.CopyTo(MixBufferVolume); parameter.MixBufferVolume.CopyTo(MixBufferVolume);
bool resetPrevVolume = isPrevVolumeResetSupported ? parameter.ResetPrevVolume : !IsUsed && parameter.IsUsed; if (!IsUsed && parameter.IsUsed)
if (resetPrevVolume)
{ {
MixBufferVolume.CopyTo(PreviousMixBufferVolume); MixBufferVolume.CopyTo(PreviousMixBufferVolume);

View file

@ -98,8 +98,7 @@ namespace Ryujinx.Audio.Renderer.Server.Splitter
/// Update the <see cref="SplitterDestinationVersion2"/> from user parameter. /// Update the <see cref="SplitterDestinationVersion2"/> from user parameter.
/// </summary> /// </summary>
/// <param name="parameter">The user parameter.</param> /// <param name="parameter">The user parameter.</param>
/// <param name="isPrevVolumeResetSupported">Indicates that the audio renderer revision in use supports explicitly resetting the volume.</param> public void Update<T>(in T parameter) where T : ISplitterDestinationInParameter
public void Update<T>(in T parameter, bool isPrevVolumeResetSupported) where T : ISplitterDestinationInParameter
{ {
Debug.Assert(Id == parameter.Id); Debug.Assert(Id == parameter.Id);
@ -111,8 +110,7 @@ namespace Ryujinx.Audio.Renderer.Server.Splitter
_biquadFilters = parameter.BiquadFilters; _biquadFilters = parameter.BiquadFilters;
bool resetPrevVolume = isPrevVolumeResetSupported ? parameter.ResetPrevVolume : !IsUsed && parameter.IsUsed; if (!IsUsed && parameter.IsUsed)
if (resetPrevVolume)
{ {
MixBufferVolume.CopyTo(PreviousMixBufferVolume); MixBufferVolume.CopyTo(PreviousMixBufferVolume);

View file

@ -71,8 +71,6 @@ namespace Ryujinx.Graphics.GAL
public readonly int GatherBiasPrecision; public readonly int GatherBiasPrecision;
public readonly ulong MaximumGpuMemory;
public Capabilities( public Capabilities(
TargetApi api, TargetApi api,
string vendorName, string vendorName,
@ -133,8 +131,7 @@ namespace Ryujinx.Graphics.GAL
int shaderSubgroupSize, int shaderSubgroupSize,
int storageBufferOffsetAlignment, int storageBufferOffsetAlignment,
int textureBufferOffsetAlignment, int textureBufferOffsetAlignment,
int gatherBiasPrecision, int gatherBiasPrecision)
ulong maximumGpuMemory)
{ {
Api = api; Api = api;
VendorName = vendorName; VendorName = vendorName;
@ -196,7 +193,6 @@ namespace Ryujinx.Graphics.GAL
StorageBufferOffsetAlignment = storageBufferOffsetAlignment; StorageBufferOffsetAlignment = storageBufferOffsetAlignment;
TextureBufferOffsetAlignment = textureBufferOffsetAlignment; TextureBufferOffsetAlignment = textureBufferOffsetAlignment;
GatherBiasPrecision = gatherBiasPrecision; GatherBiasPrecision = gatherBiasPrecision;
MaximumGpuMemory = maximumGpuMemory;
} }
} }
} }

View file

@ -1,4 +1,4 @@
using Ryujinx.Common.Memory; using System.Buffers;
namespace Ryujinx.Graphics.GAL namespace Ryujinx.Graphics.GAL
{ {
@ -18,30 +18,30 @@ namespace Ryujinx.Graphics.GAL
PinnedSpan<byte> GetData(int layer, int level); PinnedSpan<byte> GetData(int layer, int level);
/// <summary> /// <summary>
/// Sets the texture data. The data passed as a <see cref="MemoryOwner{Byte}" /> will be disposed when /// Sets the texture data. The data passed as a <see cref="IMemoryOwner{Byte}" /> will be disposed when
/// the operation completes. /// the operation completes.
/// </summary> /// </summary>
/// <param name="data">Texture data bytes</param> /// <param name="data">Texture data bytes</param>
void SetData(MemoryOwner<byte> data); void SetData(IMemoryOwner<byte> data);
/// <summary> /// <summary>
/// Sets the texture data. The data passed as a <see cref="MemoryOwner{Byte}" /> will be disposed when /// Sets the texture data. The data passed as a <see cref="IMemoryOwner{Byte}" /> will be disposed when
/// the operation completes. /// the operation completes.
/// </summary> /// </summary>
/// <param name="data">Texture data bytes</param> /// <param name="data">Texture data bytes</param>
/// <param name="layer">Target layer</param> /// <param name="layer">Target layer</param>
/// <param name="level">Target level</param> /// <param name="level">Target level</param>
void SetData(MemoryOwner<byte> data, int layer, int level); void SetData(IMemoryOwner<byte> data, int layer, int level);
/// <summary> /// <summary>
/// Sets the texture data. The data passed as a <see cref="MemoryOwner{Byte}" /> will be disposed when /// Sets the texture data. The data passed as a <see cref="IMemoryOwner{Byte}" /> will be disposed when
/// the operation completes. /// the operation completes.
/// </summary> /// </summary>
/// <param name="data">Texture data bytes</param> /// <param name="data">Texture data bytes</param>
/// <param name="layer">Target layer</param> /// <param name="layer">Target layer</param>
/// <param name="level">Target level</param> /// <param name="level">Target level</param>
/// <param name="region">Target sub-region of the texture to update</param> /// <param name="region">Target sub-region of the texture to update</param>
void SetData(MemoryOwner<byte> data, int layer, int level, Rectangle<int> region); void SetData(IMemoryOwner<byte> data, int layer, int level, Rectangle<int> region);
void SetStorage(BufferRange buffer); void SetStorage(BufferRange buffer);

View file

@ -1,6 +1,6 @@
using Ryujinx.Common.Memory;
using Ryujinx.Graphics.GAL.Multithreading.Model; using Ryujinx.Graphics.GAL.Multithreading.Model;
using Ryujinx.Graphics.GAL.Multithreading.Resources; using Ryujinx.Graphics.GAL.Multithreading.Resources;
using System.Buffers;
namespace Ryujinx.Graphics.GAL.Multithreading.Commands.Texture namespace Ryujinx.Graphics.GAL.Multithreading.Commands.Texture
{ {
@ -8,9 +8,9 @@ namespace Ryujinx.Graphics.GAL.Multithreading.Commands.Texture
{ {
public readonly CommandType CommandType => CommandType.TextureSetData; public readonly CommandType CommandType => CommandType.TextureSetData;
private TableRef<ThreadedTexture> _texture; private TableRef<ThreadedTexture> _texture;
private TableRef<MemoryOwner<byte>> _data; private TableRef<IMemoryOwner<byte>> _data;
public void Set(TableRef<ThreadedTexture> texture, TableRef<MemoryOwner<byte>> data) public void Set(TableRef<ThreadedTexture> texture, TableRef<IMemoryOwner<byte>> data)
{ {
_texture = texture; _texture = texture;
_data = data; _data = data;

View file

@ -1,6 +1,6 @@
using Ryujinx.Common.Memory;
using Ryujinx.Graphics.GAL.Multithreading.Model; using Ryujinx.Graphics.GAL.Multithreading.Model;
using Ryujinx.Graphics.GAL.Multithreading.Resources; using Ryujinx.Graphics.GAL.Multithreading.Resources;
using System.Buffers;
namespace Ryujinx.Graphics.GAL.Multithreading.Commands.Texture namespace Ryujinx.Graphics.GAL.Multithreading.Commands.Texture
{ {
@ -8,11 +8,11 @@ namespace Ryujinx.Graphics.GAL.Multithreading.Commands.Texture
{ {
public readonly CommandType CommandType => CommandType.TextureSetDataSlice; public readonly CommandType CommandType => CommandType.TextureSetDataSlice;
private TableRef<ThreadedTexture> _texture; private TableRef<ThreadedTexture> _texture;
private TableRef<MemoryOwner<byte>> _data; private TableRef<IMemoryOwner<byte>> _data;
private int _layer; private int _layer;
private int _level; private int _level;
public void Set(TableRef<ThreadedTexture> texture, TableRef<MemoryOwner<byte>> data, int layer, int level) public void Set(TableRef<ThreadedTexture> texture, TableRef<IMemoryOwner<byte>> data, int layer, int level)
{ {
_texture = texture; _texture = texture;
_data = data; _data = data;

View file

@ -1,6 +1,6 @@
using Ryujinx.Common.Memory;
using Ryujinx.Graphics.GAL.Multithreading.Model; using Ryujinx.Graphics.GAL.Multithreading.Model;
using Ryujinx.Graphics.GAL.Multithreading.Resources; using Ryujinx.Graphics.GAL.Multithreading.Resources;
using System.Buffers;
namespace Ryujinx.Graphics.GAL.Multithreading.Commands.Texture namespace Ryujinx.Graphics.GAL.Multithreading.Commands.Texture
{ {
@ -8,12 +8,12 @@ namespace Ryujinx.Graphics.GAL.Multithreading.Commands.Texture
{ {
public readonly CommandType CommandType => CommandType.TextureSetDataSliceRegion; public readonly CommandType CommandType => CommandType.TextureSetDataSliceRegion;
private TableRef<ThreadedTexture> _texture; private TableRef<ThreadedTexture> _texture;
private TableRef<MemoryOwner<byte>> _data; private TableRef<IMemoryOwner<byte>> _data;
private int _layer; private int _layer;
private int _level; private int _level;
private Rectangle<int> _region; private Rectangle<int> _region;
public void Set(TableRef<ThreadedTexture> texture, TableRef<MemoryOwner<byte>> data, int layer, int level, Rectangle<int> region) public void Set(TableRef<ThreadedTexture> texture, TableRef<IMemoryOwner<byte>> data, int layer, int level, Rectangle<int> region)
{ {
_texture = texture; _texture = texture;
_data = data; _data = data;

View file

@ -1,6 +1,6 @@
using Ryujinx.Common.Memory;
using Ryujinx.Graphics.GAL.Multithreading.Commands.Texture; using Ryujinx.Graphics.GAL.Multithreading.Commands.Texture;
using Ryujinx.Graphics.GAL.Multithreading.Model; using Ryujinx.Graphics.GAL.Multithreading.Model;
using System.Buffers;
namespace Ryujinx.Graphics.GAL.Multithreading.Resources namespace Ryujinx.Graphics.GAL.Multithreading.Resources
{ {
@ -111,21 +111,21 @@ namespace Ryujinx.Graphics.GAL.Multithreading.Resources
} }
/// <inheritdoc/> /// <inheritdoc/>
public void SetData(MemoryOwner<byte> data) public void SetData(IMemoryOwner<byte> data)
{ {
_renderer.New<TextureSetDataCommand>().Set(Ref(this), Ref(data)); _renderer.New<TextureSetDataCommand>().Set(Ref(this), Ref(data));
_renderer.QueueCommand(); _renderer.QueueCommand();
} }
/// <inheritdoc/> /// <inheritdoc/>
public void SetData(MemoryOwner<byte> data, int layer, int level) public void SetData(IMemoryOwner<byte> data, int layer, int level)
{ {
_renderer.New<TextureSetDataSliceCommand>().Set(Ref(this), Ref(data), layer, level); _renderer.New<TextureSetDataSliceCommand>().Set(Ref(this), Ref(data), layer, level);
_renderer.QueueCommand(); _renderer.QueueCommand();
} }
/// <inheritdoc/> /// <inheritdoc/>
public void SetData(MemoryOwner<byte> data, int layer, int level, Rectangle<int> region) public void SetData(IMemoryOwner<byte> data, int layer, int level, Rectangle<int> region)
{ {
_renderer.New<TextureSetDataSliceRegionCommand>().Set(Ref(this), Ref(data), layer, level, region); _renderer.New<TextureSetDataSliceRegionCommand>().Set(Ref(this), Ref(data), layer, level, region);
_renderer.QueueCommand(); _renderer.QueueCommand();

View file

@ -1,10 +1,10 @@
using Ryujinx.Common; using Ryujinx.Common;
using Ryujinx.Common.Memory;
using Ryujinx.Graphics.Device; using Ryujinx.Graphics.Device;
using Ryujinx.Graphics.Gpu.Engine.Threed; using Ryujinx.Graphics.Gpu.Engine.Threed;
using Ryujinx.Graphics.Gpu.Memory; using Ryujinx.Graphics.Gpu.Memory;
using Ryujinx.Graphics.Texture; using Ryujinx.Graphics.Texture;
using System; using System;
using System.Buffers;
using System.Collections.Generic; using System.Collections.Generic;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
@ -353,7 +353,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Dma
if (target != null) if (target != null)
{ {
MemoryOwner<byte> data; IMemoryOwner<byte> data;
if (srcLinear) if (srcLinear)
{ {
data = LayoutConverter.ConvertLinearStridedToLinear( data = LayoutConverter.ConvertLinearStridedToLinear(

View file

@ -1,4 +1,3 @@
using System;
using System.Collections; using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
@ -47,11 +46,7 @@ namespace Ryujinx.Graphics.Gpu.Image
{ {
private const int MinCountForDeletion = 32; private const int MinCountForDeletion = 32;
private const int MaxCapacity = 2048; private const int MaxCapacity = 2048;
private const ulong MinTextureSizeCapacity = 512 * 1024 * 1024; private const ulong MaxTextureSizeCapacity = 1024 * 1024 * 1024; // MB;
private const ulong MaxTextureSizeCapacity = 4UL * 1024 * 1024 * 1024;
private const ulong DefaultTextureSizeCapacity = 1UL * 1024 * 1024 * 1024;
private const float MemoryScaleFactor = 0.50f;
private ulong _maxCacheMemoryUsage = 0;
private readonly LinkedList<Texture> _textures; private readonly LinkedList<Texture> _textures;
private ulong _totalSize; private ulong _totalSize;
@ -61,25 +56,6 @@ namespace Ryujinx.Graphics.Gpu.Image
private readonly Dictionary<TextureDescriptor, ShortTextureCacheEntry> _shortCacheLookup; private readonly Dictionary<TextureDescriptor, ShortTextureCacheEntry> _shortCacheLookup;
/// <summary>
/// Initializes the cache, setting the maximum texture capacity for the specified GPU context.
/// </summary>
/// <remarks>
/// If the backend GPU has 0 memory capacity, the cache size defaults to `DefaultTextureSizeCapacity`.
/// </remarks>
/// <param name="context">The GPU context that the cache belongs to</param>
public void Initialize(GpuContext context)
{
var cacheMemory = (ulong)(context.Capabilities.MaximumGpuMemory * MemoryScaleFactor);
_maxCacheMemoryUsage = Math.Clamp(cacheMemory, MinTextureSizeCapacity, MaxTextureSizeCapacity);
if (context.Capabilities.MaximumGpuMemory == 0)
{
_maxCacheMemoryUsage = DefaultTextureSizeCapacity;
}
}
/// <summary> /// <summary>
/// Creates a new instance of the automatic deletion cache. /// Creates a new instance of the automatic deletion cache.
/// </summary> /// </summary>
@ -109,7 +85,7 @@ namespace Ryujinx.Graphics.Gpu.Image
texture.CacheNode = _textures.AddLast(texture); texture.CacheNode = _textures.AddLast(texture);
if (_textures.Count > MaxCapacity || if (_textures.Count > MaxCapacity ||
(_totalSize > _maxCacheMemoryUsage && _textures.Count >= MinCountForDeletion)) (_totalSize > MaxTextureSizeCapacity && _textures.Count >= MinCountForDeletion))
{ {
RemoveLeastUsedTexture(); RemoveLeastUsedTexture();
} }
@ -134,7 +110,7 @@ namespace Ryujinx.Graphics.Gpu.Image
_textures.AddLast(texture.CacheNode); _textures.AddLast(texture.CacheNode);
} }
if (_totalSize > _maxCacheMemoryUsage && _textures.Count >= MinCountForDeletion) if (_totalSize > MaxTextureSizeCapacity && _textures.Count >= MinCountForDeletion)
{ {
RemoveLeastUsedTexture(); RemoveLeastUsedTexture();
} }

View file

@ -13,11 +13,6 @@ namespace Ryujinx.Graphics.Gpu.Image
/// </summary> /// </summary>
public bool IsDisposed { get; private set; } public bool IsDisposed { get; private set; }
/// <summary>
/// True if the sampler has sRGB conversion enabled, false otherwise.
/// </summary>
public bool IsSrgb { get; }
/// <summary> /// <summary>
/// Host sampler object. /// Host sampler object.
/// </summary> /// </summary>
@ -35,8 +30,6 @@ namespace Ryujinx.Graphics.Gpu.Image
/// <param name="descriptor">The Maxwell sampler descriptor</param> /// <param name="descriptor">The Maxwell sampler descriptor</param>
public Sampler(GpuContext context, SamplerDescriptor descriptor) public Sampler(GpuContext context, SamplerDescriptor descriptor)
{ {
IsSrgb = descriptor.UnpackSrgb();
MinFilter minFilter = descriptor.UnpackMinFilter(); MinFilter minFilter = descriptor.UnpackMinFilter();
MagFilter magFilter = descriptor.UnpackMagFilter(); MagFilter magFilter = descriptor.UnpackMagFilter();

View file

@ -113,15 +113,6 @@ namespace Ryujinx.Graphics.Gpu.Image
return (CompareOp)(((Word0 >> 10) & 7) + 1); return (CompareOp)(((Word0 >> 10) & 7) + 1);
} }
/// <summary>
/// Unpacks the sampler sRGB format flag.
/// </summary>
/// <returns>True if the has sampler is sRGB conversion enabled, false otherwise</returns>
public readonly bool UnpackSrgb()
{
return (Word0 & (1 << 13)) != 0;
}
/// <summary> /// <summary>
/// Unpacks and converts the maximum anisotropy value used for texture anisotropic filtering. /// Unpacks and converts the maximum anisotropy value used for texture anisotropic filtering.
/// </summary> /// </summary>

View file

@ -7,6 +7,7 @@ using Ryujinx.Graphics.Texture.Astc;
using Ryujinx.Memory; using Ryujinx.Memory;
using Ryujinx.Memory.Range; using Ryujinx.Memory.Range;
using System; using System;
using System.Buffers;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.Linq; using System.Linq;
@ -661,7 +662,7 @@ namespace Ryujinx.Graphics.Gpu.Image
} }
} }
MemoryOwner<byte> result = ConvertToHostCompatibleFormat(data); IMemoryOwner<byte> result = ConvertToHostCompatibleFormat(data);
if (ScaleFactor != 1f && AllowScaledSetData()) if (ScaleFactor != 1f && AllowScaledSetData())
{ {
@ -684,7 +685,7 @@ namespace Ryujinx.Graphics.Gpu.Image
/// Uploads new texture data to the host GPU. /// Uploads new texture data to the host GPU.
/// </summary> /// </summary>
/// <param name="data">New data</param> /// <param name="data">New data</param>
public void SetData(MemoryOwner<byte> data) public void SetData(IMemoryOwner<byte> data)
{ {
BlacklistScale(); BlacklistScale();
@ -703,7 +704,7 @@ namespace Ryujinx.Graphics.Gpu.Image
/// <param name="data">New data</param> /// <param name="data">New data</param>
/// <param name="layer">Target layer</param> /// <param name="layer">Target layer</param>
/// <param name="level">Target level</param> /// <param name="level">Target level</param>
public void SetData(MemoryOwner<byte> data, int layer, int level) public void SetData(IMemoryOwner<byte> data, int layer, int level)
{ {
BlacklistScale(); BlacklistScale();
@ -721,7 +722,7 @@ namespace Ryujinx.Graphics.Gpu.Image
/// <param name="layer">Target layer</param> /// <param name="layer">Target layer</param>
/// <param name="level">Target level</param> /// <param name="level">Target level</param>
/// <param name="region">Target sub-region of the texture to update</param> /// <param name="region">Target sub-region of the texture to update</param>
public void SetData(MemoryOwner<byte> data, int layer, int level, Rectangle<int> region) public void SetData(IMemoryOwner<byte> data, int layer, int level, Rectangle<int> region)
{ {
BlacklistScale(); BlacklistScale();
@ -739,7 +740,7 @@ namespace Ryujinx.Graphics.Gpu.Image
/// <param name="level">Mip level to convert</param> /// <param name="level">Mip level to convert</param>
/// <param name="single">True to convert a single slice</param> /// <param name="single">True to convert a single slice</param>
/// <returns>Converted data</returns> /// <returns>Converted data</returns>
public MemoryOwner<byte> ConvertToHostCompatibleFormat(ReadOnlySpan<byte> data, int level = 0, bool single = false) public IMemoryOwner<byte> ConvertToHostCompatibleFormat(ReadOnlySpan<byte> data, int level = 0, bool single = false)
{ {
int width = Info.Width; int width = Info.Width;
int height = Info.Height; int height = Info.Height;
@ -754,7 +755,7 @@ namespace Ryujinx.Graphics.Gpu.Image
int sliceDepth = single ? 1 : depth; int sliceDepth = single ? 1 : depth;
MemoryOwner<byte> linear; IMemoryOwner<byte> linear;
if (Info.IsLinear) if (Info.IsLinear)
{ {
@ -787,7 +788,7 @@ namespace Ryujinx.Graphics.Gpu.Image
data); data);
} }
MemoryOwner<byte> result = linear; IMemoryOwner<byte> result = linear;
// Handle compressed cases not supported by the host: // Handle compressed cases not supported by the host:
// - ASTC is usually not supported on desktop cards. // - ASTC is usually not supported on desktop cards.
@ -831,19 +832,19 @@ namespace Ryujinx.Graphics.Gpu.Image
case Format.Etc2RgbaUnorm: case Format.Etc2RgbaUnorm:
using (result) using (result)
{ {
return ETC2Decoder.DecodeRgba(result.Span, width, height, sliceDepth, levels, layers); return ETC2Decoder.DecodeRgba(result.Memory.Span, width, height, sliceDepth, levels, layers);
} }
case Format.Etc2RgbPtaSrgb: case Format.Etc2RgbPtaSrgb:
case Format.Etc2RgbPtaUnorm: case Format.Etc2RgbPtaUnorm:
using (result) using (result)
{ {
return ETC2Decoder.DecodePta(result.Span, width, height, sliceDepth, levels, layers); return ETC2Decoder.DecodePta(result.Memory.Span, width, height, sliceDepth, levels, layers);
} }
case Format.Etc2RgbSrgb: case Format.Etc2RgbSrgb:
case Format.Etc2RgbUnorm: case Format.Etc2RgbUnorm:
using (result) using (result)
{ {
return ETC2Decoder.DecodeRgb(result.Span, width, height, sliceDepth, levels, layers); return ETC2Decoder.DecodeRgb(result.Memory.Span, width, height, sliceDepth, levels, layers);
} }
} }
} }
@ -855,43 +856,43 @@ namespace Ryujinx.Graphics.Gpu.Image
case Format.Bc1RgbaUnorm: case Format.Bc1RgbaUnorm:
using (result) using (result)
{ {
return BCnDecoder.DecodeBC1(result.Span, width, height, sliceDepth, levels, layers); return BCnDecoder.DecodeBC1(result.Memory.Span, width, height, sliceDepth, levels, layers);
} }
case Format.Bc2Srgb: case Format.Bc2Srgb:
case Format.Bc2Unorm: case Format.Bc2Unorm:
using (result) using (result)
{ {
return BCnDecoder.DecodeBC2(result.Span, width, height, sliceDepth, levels, layers); return BCnDecoder.DecodeBC2(result.Memory.Span, width, height, sliceDepth, levels, layers);
} }
case Format.Bc3Srgb: case Format.Bc3Srgb:
case Format.Bc3Unorm: case Format.Bc3Unorm:
using (result) using (result)
{ {
return BCnDecoder.DecodeBC3(result.Span, width, height, sliceDepth, levels, layers); return BCnDecoder.DecodeBC3(result.Memory.Span, width, height, sliceDepth, levels, layers);
} }
case Format.Bc4Snorm: case Format.Bc4Snorm:
case Format.Bc4Unorm: case Format.Bc4Unorm:
using (result) using (result)
{ {
return BCnDecoder.DecodeBC4(result.Span, width, height, sliceDepth, levels, layers, Format == Format.Bc4Snorm); return BCnDecoder.DecodeBC4(result.Memory.Span, width, height, sliceDepth, levels, layers, Format == Format.Bc4Snorm);
} }
case Format.Bc5Snorm: case Format.Bc5Snorm:
case Format.Bc5Unorm: case Format.Bc5Unorm:
using (result) using (result)
{ {
return BCnDecoder.DecodeBC5(result.Span, width, height, sliceDepth, levels, layers, Format == Format.Bc5Snorm); return BCnDecoder.DecodeBC5(result.Memory.Span, width, height, sliceDepth, levels, layers, Format == Format.Bc5Snorm);
} }
case Format.Bc6HSfloat: case Format.Bc6HSfloat:
case Format.Bc6HUfloat: case Format.Bc6HUfloat:
using (result) using (result)
{ {
return BCnDecoder.DecodeBC6(result.Span, width, height, sliceDepth, levels, layers, Format == Format.Bc6HSfloat); return BCnDecoder.DecodeBC6(result.Memory.Span, width, height, sliceDepth, levels, layers, Format == Format.Bc6HSfloat);
} }
case Format.Bc7Srgb: case Format.Bc7Srgb:
case Format.Bc7Unorm: case Format.Bc7Unorm:
using (result) using (result)
{ {
return BCnDecoder.DecodeBC7(result.Span, width, height, sliceDepth, levels, layers); return BCnDecoder.DecodeBC7(result.Memory.Span, width, height, sliceDepth, levels, layers);
} }
} }
} }
@ -899,7 +900,7 @@ namespace Ryujinx.Graphics.Gpu.Image
{ {
using (result) using (result)
{ {
var converted = PixelConverter.ConvertR4G4ToR4G4B4A4(result.Span, width); var converted = PixelConverter.ConvertR4G4ToR4G4B4A4(result.Memory.Span, width);
if (_context.Capabilities.SupportsR4G4B4A4Format) if (_context.Capabilities.SupportsR4G4B4A4Format)
{ {
@ -909,7 +910,7 @@ namespace Ryujinx.Graphics.Gpu.Image
{ {
using (converted) using (converted)
{ {
return PixelConverter.ConvertR4G4B4A4ToR8G8B8A8(converted.Span, width); return PixelConverter.ConvertR4G4B4A4ToR8G8B8A8(converted.Memory.Span, width);
} }
} }
} }
@ -920,7 +921,7 @@ namespace Ryujinx.Graphics.Gpu.Image
{ {
using (result) using (result)
{ {
return PixelConverter.ConvertR4G4B4A4ToR8G8B8A8(result.Span, width); return PixelConverter.ConvertR4G4B4A4ToR8G8B8A8(result.Memory.Span, width);
} }
} }
} }
@ -932,24 +933,24 @@ namespace Ryujinx.Graphics.Gpu.Image
case Format.R5G6B5Unorm: case Format.R5G6B5Unorm:
using (result) using (result)
{ {
return PixelConverter.ConvertR5G6B5ToR8G8B8A8(result.Span, width); return PixelConverter.ConvertR5G6B5ToR8G8B8A8(result.Memory.Span, width);
} }
case Format.B5G5R5A1Unorm: case Format.B5G5R5A1Unorm:
case Format.R5G5B5X1Unorm: case Format.R5G5B5X1Unorm:
case Format.R5G5B5A1Unorm: case Format.R5G5B5A1Unorm:
using (result) using (result)
{ {
return PixelConverter.ConvertR5G5B5ToR8G8B8A8(result.Span, width, Format == Format.R5G5B5X1Unorm); return PixelConverter.ConvertR5G5B5ToR8G8B8A8(result.Memory.Span, width, Format == Format.R5G5B5X1Unorm);
} }
case Format.A1B5G5R5Unorm: case Format.A1B5G5R5Unorm:
using (result) using (result)
{ {
return PixelConverter.ConvertA1B5G5R5ToR8G8B8A8(result.Span, width); return PixelConverter.ConvertA1B5G5R5ToR8G8B8A8(result.Memory.Span, width);
} }
case Format.R4G4B4A4Unorm: case Format.R4G4B4A4Unorm:
using (result) using (result)
{ {
return PixelConverter.ConvertR4G4B4A4ToR8G8B8A8(result.Span, width); return PixelConverter.ConvertR4G4B4A4ToR8G8B8A8(result.Memory.Span, width);
} }
} }
} }

View file

@ -187,9 +187,7 @@ namespace Ryujinx.Graphics.Gpu.Image
{ {
(TexturePool texturePool, SamplerPool samplerPool) = GetPools(); (TexturePool texturePool, SamplerPool samplerPool) = GetPools();
Sampler sampler = samplerPool?.Get(samplerId); return (texturePool.Get(textureId), samplerPool.Get(samplerId));
return (texturePool.Get(textureId, sampler?.IsSrgb ?? true), sampler);
} }
/// <summary> /// <summary>
@ -510,12 +508,12 @@ namespace Ryujinx.Graphics.Gpu.Image
state.TextureHandle = textureId; state.TextureHandle = textureId;
state.SamplerHandle = samplerId; state.SamplerHandle = samplerId;
Sampler sampler = samplerPool?.Get(samplerId); ref readonly TextureDescriptor descriptor = ref texturePool.GetForBinding(textureId, out Texture texture);
ref readonly TextureDescriptor descriptor = ref texturePool.GetForBinding(textureId, sampler?.IsSrgb ?? true, out Texture texture);
specStateMatches &= specState.MatchesTexture(stage, index, descriptor); specStateMatches &= specState.MatchesTexture(stage, index, descriptor);
Sampler sampler = samplerPool?.Get(samplerId);
ITexture hostTexture = texture?.GetTargetTexture(bindingInfo.Target); ITexture hostTexture = texture?.GetTargetTexture(bindingInfo.Target);
ISampler hostSampler = sampler?.GetHostSampler(texture); ISampler hostSampler = sampler?.GetHostSampler(texture);

View file

@ -68,14 +68,6 @@ namespace Ryujinx.Graphics.Gpu.Image
_cache = new AutoDeleteCache(); _cache = new AutoDeleteCache();
} }
/// <summary>
/// Initializes the cache, setting the maximum texture capacity for the specified GPU context.
/// </summary>
public void Initialize()
{
_cache.Initialize(_context);
}
/// <summary> /// <summary>
/// Handles marking of textures written to a memory region being (partially) remapped. /// Handles marking of textures written to a memory region being (partially) remapped.
/// </summary> /// </summary>

View file

@ -1,4 +1,3 @@
using Ryujinx.Common.Memory;
using Ryujinx.Graphics.GAL; using Ryujinx.Graphics.GAL;
using Ryujinx.Graphics.Gpu.Memory; using Ryujinx.Graphics.Gpu.Memory;
using Ryujinx.Graphics.Texture; using Ryujinx.Graphics.Texture;
@ -6,6 +5,7 @@ using Ryujinx.Memory;
using Ryujinx.Memory.Range; using Ryujinx.Memory.Range;
using Ryujinx.Memory.Tracking; using Ryujinx.Memory.Tracking;
using System; using System;
using System.Buffers;
using System.Collections.Generic; using System.Collections.Generic;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
@ -445,7 +445,7 @@ namespace Ryujinx.Graphics.Gpu.Image
ReadOnlySpan<byte> data = dataSpan[(offset - spanBase)..]; ReadOnlySpan<byte> data = dataSpan[(offset - spanBase)..];
MemoryOwner<byte> result = Storage.ConvertToHostCompatibleFormat(data, info.BaseLevel + level, true); IMemoryOwner<byte> result = Storage.ConvertToHostCompatibleFormat(data, info.BaseLevel + level, true);
Storage.SetData(result, info.BaseLayer + layer, info.BaseLevel + level); Storage.SetData(result, info.BaseLayer + layer, info.BaseLevel + level);
} }

View file

@ -227,17 +227,6 @@ namespace Ryujinx.Graphics.Gpu.Image
/// <param name="id">ID of the texture. This is effectively a zero-based index</param> /// <param name="id">ID of the texture. This is effectively a zero-based index</param>
/// <returns>The texture with the given ID</returns> /// <returns>The texture with the given ID</returns>
public override Texture Get(int id) public override Texture Get(int id)
{
return Get(id, srgbSampler: true);
}
/// <summary>
/// Gets the texture with the given ID.
/// </summary>
/// <param name="id">ID of the texture. This is effectively a zero-based index</param>
/// <param name="srgbSampler">Whether the texture is being accessed with a sampler that has sRGB conversion enabled</param>
/// <returns>The texture with the given ID</returns>
public Texture Get(int id, bool srgbSampler)
{ {
if ((uint)id >= Items.Length) if ((uint)id >= Items.Length)
{ {
@ -251,7 +240,7 @@ namespace Ryujinx.Graphics.Gpu.Image
SynchronizeMemory(); SynchronizeMemory();
} }
GetForBinding(id, srgbSampler, out Texture texture); GetInternal(id, out Texture texture);
return texture; return texture;
} }
@ -263,10 +252,9 @@ namespace Ryujinx.Graphics.Gpu.Image
/// This method assumes that the pool has been manually synchronized before doing binding. /// This method assumes that the pool has been manually synchronized before doing binding.
/// </remarks> /// </remarks>
/// <param name="id">ID of the texture. This is effectively a zero-based index</param> /// <param name="id">ID of the texture. This is effectively a zero-based index</param>
/// <param name="srgbSampler">Whether the texture is being accessed with a sampler that has sRGB conversion enabled</param>
/// <param name="texture">The texture with the given ID</param> /// <param name="texture">The texture with the given ID</param>
/// <returns>The texture descriptor with the given ID</returns> /// <returns>The texture descriptor with the given ID</returns>
public ref readonly TextureDescriptor GetForBinding(int id, bool srgbSampler, out Texture texture) public ref readonly TextureDescriptor GetForBinding(int id, out Texture texture)
{ {
if ((uint)id >= Items.Length) if ((uint)id >= Items.Length)
{ {
@ -276,18 +264,6 @@ namespace Ryujinx.Graphics.Gpu.Image
// When getting for binding, assume the pool has already been synchronized. // When getting for binding, assume the pool has already been synchronized.
if (!srgbSampler)
{
// If the sampler does not have the sRGB bit enabled, then the texture can't use a sRGB format.
ref readonly TextureDescriptor tempDescriptor = ref GetDescriptorRef(id);
if (tempDescriptor.UnpackSrgb() && FormatTable.TryGetTextureFormat(tempDescriptor.UnpackFormat(), isSrgb: false, out FormatInfo formatInfo))
{
// Get a view of the texture with the right format.
return ref GetForBinding(id, formatInfo, out texture);
}
}
return ref GetInternal(id, out texture); return ref GetInternal(id, out texture);
} }

View file

@ -1,5 +1,4 @@
using Ryujinx.Common.Memory; using Ryujinx.Common.Memory;
using Ryujinx.Graphics.Gpu.Image;
using Ryujinx.Memory; using Ryujinx.Memory;
using Ryujinx.Memory.Range; using Ryujinx.Memory.Range;
using System; using System;
@ -65,7 +64,6 @@ namespace Ryujinx.Graphics.Gpu.Memory
MemoryUnmapped += Physical.BufferCache.MemoryUnmappedHandler; MemoryUnmapped += Physical.BufferCache.MemoryUnmappedHandler;
MemoryUnmapped += VirtualRangeCache.MemoryUnmappedHandler; MemoryUnmapped += VirtualRangeCache.MemoryUnmappedHandler;
MemoryUnmapped += CounterCache.MemoryUnmappedHandler; MemoryUnmapped += CounterCache.MemoryUnmappedHandler;
Physical.TextureCache.Initialize();
} }
/// <summary> /// <summary>

View file

@ -22,7 +22,7 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache
private const ushort FileFormatVersionMajor = 1; private const ushort FileFormatVersionMajor = 1;
private const ushort FileFormatVersionMinor = 2; private const ushort FileFormatVersionMinor = 2;
private const uint FileFormatVersionPacked = ((uint)FileFormatVersionMajor << 16) | FileFormatVersionMinor; private const uint FileFormatVersionPacked = ((uint)FileFormatVersionMajor << 16) | FileFormatVersionMinor;
private const uint CodeGenVersion = 7353; private const uint CodeGenVersion = 7320;
private const string SharedTocFileName = "shared.toc"; private const string SharedTocFileName = "shared.toc";
private const string SharedDataFileName = "shared.data"; private const string SharedDataFileName = "shared.data";

View file

@ -743,7 +743,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
constantBufferUsePerStageMask &= ~(1 << index); constantBufferUsePerStageMask &= ~(1 << index);
} }
if (checkTextures && _allTextures.Length > 0) if (checkTextures)
{ {
TexturePool pool = channel.TextureManager.GetTexturePool(poolState.TexturePoolGpuVa, poolState.TexturePoolMaximumId); TexturePool pool = channel.TextureManager.GetTexturePool(poolState.TexturePoolGpuVa, poolState.TexturePoolMaximumId);

View file

@ -1,7 +1,7 @@
using OpenTK.Graphics.OpenGL; using OpenTK.Graphics.OpenGL;
using Ryujinx.Common.Memory;
using Ryujinx.Graphics.GAL; using Ryujinx.Graphics.GAL;
using System; using System;
using System.Buffers;
namespace Ryujinx.Graphics.OpenGL.Image namespace Ryujinx.Graphics.OpenGL.Image
{ {
@ -55,9 +55,9 @@ namespace Ryujinx.Graphics.OpenGL.Image
} }
/// <inheritdoc/> /// <inheritdoc/>
public void SetData(MemoryOwner<byte> data) public void SetData(IMemoryOwner<byte> data)
{ {
var dataSpan = data.Span; var dataSpan = data.Memory.Span;
Buffer.SetData(_buffer, _bufferOffset, dataSpan[..Math.Min(dataSpan.Length, _bufferSize)]); Buffer.SetData(_buffer, _bufferOffset, dataSpan[..Math.Min(dataSpan.Length, _bufferSize)]);
@ -65,13 +65,13 @@ namespace Ryujinx.Graphics.OpenGL.Image
} }
/// <inheritdoc/> /// <inheritdoc/>
public void SetData(MemoryOwner<byte> data, int layer, int level) public void SetData(IMemoryOwner<byte> data, int layer, int level)
{ {
throw new NotSupportedException(); throw new NotSupportedException();
} }
/// <inheritdoc/> /// <inheritdoc/>
public void SetData(MemoryOwner<byte> data, int layer, int level, Rectangle<int> region) public void SetData(IMemoryOwner<byte> data, int layer, int level, Rectangle<int> region)
{ {
throw new NotSupportedException(); throw new NotSupportedException();
} }

View file

@ -1,8 +1,8 @@
using OpenTK.Graphics.OpenGL; using OpenTK.Graphics.OpenGL;
using Ryujinx.Common; using Ryujinx.Common;
using Ryujinx.Common.Memory;
using Ryujinx.Graphics.GAL; using Ryujinx.Graphics.GAL;
using System; using System;
using System.Buffers;
using System.Diagnostics; using System.Diagnostics;
namespace Ryujinx.Graphics.OpenGL.Image namespace Ryujinx.Graphics.OpenGL.Image
@ -448,13 +448,13 @@ namespace Ryujinx.Graphics.OpenGL.Image
} }
} }
public void SetData(MemoryOwner<byte> data) public void SetData(IMemoryOwner<byte> data)
{ {
using (data = EnsureDataFormat(data)) using (data = EnsureDataFormat(data))
{ {
unsafe unsafe
{ {
var dataSpan = data.Span; var dataSpan = data.Memory.Span;
fixed (byte* ptr = dataSpan) fixed (byte* ptr = dataSpan)
{ {
ReadFrom((IntPtr)ptr, dataSpan.Length); ReadFrom((IntPtr)ptr, dataSpan.Length);
@ -463,13 +463,13 @@ namespace Ryujinx.Graphics.OpenGL.Image
} }
} }
public void SetData(MemoryOwner<byte> data, int layer, int level) public void SetData(IMemoryOwner<byte> data, int layer, int level)
{ {
using (data = EnsureDataFormat(data)) using (data = EnsureDataFormat(data))
{ {
unsafe unsafe
{ {
fixed (byte* ptr = data.Span) fixed (byte* ptr = data.Memory.Span)
{ {
int width = Math.Max(Info.Width >> level, 1); int width = Math.Max(Info.Width >> level, 1);
int height = Math.Max(Info.Height >> level, 1); int height = Math.Max(Info.Height >> level, 1);
@ -480,7 +480,7 @@ namespace Ryujinx.Graphics.OpenGL.Image
} }
} }
public void SetData(MemoryOwner<byte> data, int layer, int level, Rectangle<int> region) public void SetData(IMemoryOwner<byte> data, int layer, int level, Rectangle<int> region)
{ {
using (data = EnsureDataFormat(data)) using (data = EnsureDataFormat(data))
{ {
@ -489,7 +489,7 @@ namespace Ryujinx.Graphics.OpenGL.Image
unsafe unsafe
{ {
fixed (byte* ptr = data.Span) fixed (byte* ptr = data.Memory.Span)
{ {
ReadFrom2D( ReadFrom2D(
(IntPtr)ptr, (IntPtr)ptr,
@ -522,13 +522,13 @@ namespace Ryujinx.Graphics.OpenGL.Image
ReadFrom2D(data, layer, level, x, y, width, height, mipSize); ReadFrom2D(data, layer, level, x, y, width, height, mipSize);
} }
private MemoryOwner<byte> EnsureDataFormat(MemoryOwner<byte> data) private IMemoryOwner<byte> EnsureDataFormat(IMemoryOwner<byte> data)
{ {
if (Format == Format.S8UintD24Unorm) if (Format == Format.S8UintD24Unorm)
{ {
using (data) using (data)
{ {
return FormatConverter.ConvertS8D24ToD24S8(data.Span); return FormatConverter.ConvertS8D24ToD24S8(data.Memory.Span);
} }
} }

View file

@ -202,8 +202,7 @@ namespace Ryujinx.Graphics.OpenGL
shaderSubgroupSize: Constants.MaxSubgroupSize, shaderSubgroupSize: Constants.MaxSubgroupSize,
storageBufferOffsetAlignment: HwCapabilities.StorageBufferOffsetAlignment, storageBufferOffsetAlignment: HwCapabilities.StorageBufferOffsetAlignment,
textureBufferOffsetAlignment: HwCapabilities.TextureBufferOffsetAlignment, textureBufferOffsetAlignment: HwCapabilities.TextureBufferOffsetAlignment,
gatherBiasPrecision: intelWindows || amdWindows ? 8 : 0, // Precision is 8 for these vendors on Vulkan. gatherBiasPrecision: intelWindows || amdWindows ? 8 : 0); // Precision is 8 for these vendors on Vulkan.
maximumGpuMemory: 0);
} }
public void SetBufferData(BufferHandle buffer, int offset, ReadOnlySpan<byte> data) public void SetBufferData(BufferHandle buffer, int offset, ReadOnlySpan<byte> data)

View file

@ -138,8 +138,6 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
// Ensure that conditions met for that branch are also met for the current one. // Ensure that conditions met for that branch are also met for the current one.
// Prefer the latest sources for the phi node. // Prefer the latest sources for the phi node.
int undefCount = 0;
for (int i = phiNode.SourcesCount - 1; i >= 0; i--) for (int i = phiNode.SourcesCount - 1; i >= 0; i--)
{ {
BasicBlock phiBlock = phiNode.GetBlock(i); BasicBlock phiBlock = phiNode.GetBlock(i);
@ -161,26 +159,6 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
return match; return match;
} }
} }
else if (phiSource.Type == OperandType.Undefined)
{
undefCount++;
}
}
// If all sources but one are undefined, we can assume that the one
// that is not undefined is the right one.
if (undefCount == phiNode.SourcesCount - 1)
{
for (int i = phiNode.SourcesCount - 1; i >= 0; i--)
{
Operand phiSource = phiNode.GetSource(i);
if (phiSource.Type != OperandType.Undefined)
{
return phiSource;
}
}
} }
} }

View file

@ -190,7 +190,7 @@ namespace Ryujinx.Graphics.Shader.Translation
if (stage == ShaderStage.Vertex) if (stage == ShaderStage.Vertex)
{ {
InitializeVertexOutputs(context); InitializePositionOutput(context);
} }
UInt128 usedAttributes = context.TranslatorContext.AttributeUsage.NextInputAttributesComponents; UInt128 usedAttributes = context.TranslatorContext.AttributeUsage.NextInputAttributesComponents;
@ -236,20 +236,12 @@ namespace Ryujinx.Graphics.Shader.Translation
} }
} }
private static void InitializeVertexOutputs(EmitterContext context) private static void InitializePositionOutput(EmitterContext context)
{ {
for (int c = 0; c < 4; c++) for (int c = 0; c < 4; c++)
{ {
context.Store(StorageKind.Output, IoVariable.Position, null, Const(c), ConstF(c == 3 ? 1f : 0f)); context.Store(StorageKind.Output, IoVariable.Position, null, Const(c), ConstF(c == 3 ? 1f : 0f));
} }
if (context.Program.ClipDistancesWritten != 0)
{
for (int i = 0; i < 8; i++)
{
context.Store(StorageKind.Output, IoVariable.ClipDistance, null, Const(i), ConstF(0f));
}
}
} }
private static void InitializeOutput(EmitterContext context, int location, bool perPatch) private static void InitializeOutput(EmitterContext context, int location, bool perPatch)

View file

@ -636,9 +636,9 @@ namespace Ryujinx.Graphics.Vulkan
var oldStencilTestEnable = _newState.StencilTestEnable; var oldStencilTestEnable = _newState.StencilTestEnable;
var oldDepthTestEnable = _newState.DepthTestEnable; var oldDepthTestEnable = _newState.DepthTestEnable;
var oldDepthWriteEnable = _newState.DepthWriteEnable; var oldDepthWriteEnable = _newState.DepthWriteEnable;
var oldTopology = _newState.Topology;
var oldViewports = DynamicState.Viewports; var oldViewports = DynamicState.Viewports;
var oldViewportsCount = _newState.ViewportsCount; var oldViewportsCount = _newState.ViewportsCount;
var oldTopology = _topology;
_newState.CullMode = CullModeFlags.None; _newState.CullMode = CullModeFlags.None;
_newState.StencilTestEnable = false; _newState.StencilTestEnable = false;
@ -658,7 +658,7 @@ namespace Ryujinx.Graphics.Vulkan
_newState.StencilTestEnable = oldStencilTestEnable; _newState.StencilTestEnable = oldStencilTestEnable;
_newState.DepthTestEnable = oldDepthTestEnable; _newState.DepthTestEnable = oldDepthTestEnable;
_newState.DepthWriteEnable = oldDepthWriteEnable; _newState.DepthWriteEnable = oldDepthWriteEnable;
SetPrimitiveTopology(oldTopology); _newState.Topology = oldTopology;
DynamicState.SetViewports(ref oldViewports, oldViewportsCount); DynamicState.SetViewports(ref oldViewports, oldViewportsCount);

View file

@ -1,7 +1,7 @@
using Ryujinx.Common.Memory;
using Ryujinx.Graphics.GAL; using Ryujinx.Graphics.GAL;
using Silk.NET.Vulkan; using Silk.NET.Vulkan;
using System; using System;
using System.Buffers;
using System.Collections.Generic; using System.Collections.Generic;
using Format = Ryujinx.Graphics.GAL.Format; using Format = Ryujinx.Graphics.GAL.Format;
using VkFormat = Silk.NET.Vulkan.Format; using VkFormat = Silk.NET.Vulkan.Format;
@ -84,20 +84,20 @@ namespace Ryujinx.Graphics.Vulkan
} }
/// <inheritdoc/> /// <inheritdoc/>
public void SetData(MemoryOwner<byte> data) public void SetData(IMemoryOwner<byte> data)
{ {
_gd.SetBufferData(_bufferHandle, _offset, data.Span); _gd.SetBufferData(_bufferHandle, _offset, data.Memory.Span);
data.Dispose(); data.Dispose();
} }
/// <inheritdoc/> /// <inheritdoc/>
public void SetData(MemoryOwner<byte> data, int layer, int level) public void SetData(IMemoryOwner<byte> data, int layer, int level)
{ {
throw new NotSupportedException(); throw new NotSupportedException();
} }
/// <inheritdoc/> /// <inheritdoc/>
public void SetData(MemoryOwner<byte> data, int layer, int level, Rectangle<int> region) public void SetData(IMemoryOwner<byte> data, int layer, int level, Rectangle<int> region)
{ {
throw new NotSupportedException(); throw new NotSupportedException();
} }

View file

@ -1,7 +1,7 @@
using Ryujinx.Common.Memory;
using Ryujinx.Graphics.GAL; using Ryujinx.Graphics.GAL;
using Silk.NET.Vulkan; using Silk.NET.Vulkan;
using System; using System;
using System.Buffers;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Threading; using System.Threading;
@ -746,23 +746,23 @@ namespace Ryujinx.Graphics.Vulkan
} }
/// <inheritdoc/> /// <inheritdoc/>
public void SetData(MemoryOwner<byte> data) public void SetData(IMemoryOwner<byte> data)
{ {
SetData(data.Span, 0, 0, Info.GetLayers(), Info.Levels, singleSlice: false); SetData(data.Memory.Span, 0, 0, Info.GetLayers(), Info.Levels, singleSlice: false);
data.Dispose(); data.Dispose();
} }
/// <inheritdoc/> /// <inheritdoc/>
public void SetData(MemoryOwner<byte> data, int layer, int level) public void SetData(IMemoryOwner<byte> data, int layer, int level)
{ {
SetData(data.Span, layer, level, 1, 1, singleSlice: true); SetData(data.Memory.Span, layer, level, 1, 1, singleSlice: true);
data.Dispose(); data.Dispose();
} }
/// <inheritdoc/> /// <inheritdoc/>
public void SetData(MemoryOwner<byte> data, int layer, int level, Rectangle<int> region) public void SetData(IMemoryOwner<byte> data, int layer, int level, Rectangle<int> region)
{ {
SetData(data.Span, layer, level, 1, 1, singleSlice: true, region); SetData(data.Memory.Span, layer, level, 1, 1, singleSlice: true, region);
data.Dispose(); data.Dispose();
} }

View file

@ -781,26 +781,7 @@ namespace Ryujinx.Graphics.Vulkan
shaderSubgroupSize: (int)Capabilities.SubgroupSize, shaderSubgroupSize: (int)Capabilities.SubgroupSize,
storageBufferOffsetAlignment: (int)limits.MinStorageBufferOffsetAlignment, storageBufferOffsetAlignment: (int)limits.MinStorageBufferOffsetAlignment,
textureBufferOffsetAlignment: (int)limits.MinTexelBufferOffsetAlignment, textureBufferOffsetAlignment: (int)limits.MinTexelBufferOffsetAlignment,
gatherBiasPrecision: IsIntelWindows || IsAmdWindows ? (int)Capabilities.SubTexelPrecisionBits : 0, gatherBiasPrecision: IsIntelWindows || IsAmdWindows ? (int)Capabilities.SubTexelPrecisionBits : 0);
maximumGpuMemory: GetTotalGPUMemory());
}
private ulong GetTotalGPUMemory()
{
ulong totalMemory = 0;
Api.GetPhysicalDeviceMemoryProperties(_physicalDevice.PhysicalDevice, out PhysicalDeviceMemoryProperties memoryProperties);
for (int i = 0; i < memoryProperties.MemoryHeapCount; i++)
{
var heap = memoryProperties.MemoryHeaps[i];
if ((heap.Flags & MemoryHeapFlags.DeviceLocalBit) == MemoryHeapFlags.DeviceLocalBit)
{
totalMemory += heap.Size;
}
}
return totalMemory;
} }
public HardwareInfo GetHardwareInfo() public HardwareInfo GetHardwareInfo()
@ -884,7 +865,6 @@ namespace Ryujinx.Graphics.Vulkan
private void PrintGpuInformation() private void PrintGpuInformation()
{ {
Logger.Notice.Print(LogClass.Gpu, $"{GpuVendor} {GpuRenderer} ({GpuVersion})"); Logger.Notice.Print(LogClass.Gpu, $"{GpuVendor} {GpuRenderer} ({GpuVersion})");
Logger.Notice.Print(LogClass.Gpu, $"GPU Memory: {GetTotalGPUMemory() / (1024 * 1024)} MiB");
} }
public void Initialize(GraphicsDebugLevel logLevel) public void Initialize(GraphicsDebugLevel logLevel)

View file

@ -14,7 +14,7 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
{ {
private readonly MemoryOwner<byte> _rawDataOwner; private readonly MemoryOwner<byte> _rawDataOwner;
private Span<byte> Raw => _rawDataOwner.Span; private Span<byte> Raw => _rawDataOwner.Memory.Span;
private ref ParcelHeader Header => ref MemoryMarshal.Cast<byte, ParcelHeader>(Raw)[0]; private ref ParcelHeader Header => ref MemoryMarshal.Cast<byte, ParcelHeader>(Raw)[0];

View file

@ -8,6 +8,5 @@ namespace Ryujinx.Horizon.Sdk.Audio
public static Result DeviceNotFound => new(ModuleId, 1); public static Result DeviceNotFound => new(ModuleId, 1);
public static Result UnsupportedRevision => new(ModuleId, 2); public static Result UnsupportedRevision => new(ModuleId, 2);
public static Result NotImplemented => new(ModuleId, 513);
} }
} }

View file

@ -233,48 +233,6 @@ namespace Ryujinx.Horizon.Sdk.Audio.Detail
return Result.Success; return Result.Success;
} }
[CmifCommand(15)] // 17.0.0+
public Result AcquireAudioOutputDeviceNotification([CopyHandle] out int eventHandle, ulong deviceId)
{
eventHandle = 0;
return AudioResult.NotImplemented;
}
[CmifCommand(16)] // 17.0.0+
public Result ReleaseAudioOutputDeviceNotification(ulong deviceId)
{
return AudioResult.NotImplemented;
}
[CmifCommand(17)] // 17.0.0+
public Result AcquireAudioInputDeviceNotification([CopyHandle] out int eventHandle, ulong deviceId)
{
eventHandle = 0;
return AudioResult.NotImplemented;
}
[CmifCommand(18)] // 17.0.0+
public Result ReleaseAudioInputDeviceNotification(ulong deviceId)
{
return AudioResult.NotImplemented;
}
[CmifCommand(19)] // 18.0.0+
public Result SetAudioDeviceOutputVolumeAutoTuneEnabled(bool enabled)
{
return AudioResult.NotImplemented;
}
[CmifCommand(20)] // 18.0.0+
public Result IsAudioDeviceOutputVolumeAutoTuneEnabled(out bool enabled)
{
enabled = false;
return AudioResult.NotImplemented;
}
protected virtual void Dispose(bool disposing) protected virtual void Dispose(bool disposing)
{ {
if (disposing) if (disposing)

View file

@ -1,5 +1,5 @@
using Ryujinx.Common.Memory;
using System; using System;
using System.Buffers;
namespace Ryujinx.Memory namespace Ryujinx.Memory
{ {
@ -7,7 +7,7 @@ namespace Ryujinx.Memory
{ {
private readonly IWritableBlock _block; private readonly IWritableBlock _block;
private readonly ulong _va; private readonly ulong _va;
private readonly MemoryOwner<byte> _memoryOwner; private readonly IMemoryOwner<byte> _memoryOwner;
private readonly bool _tracked; private readonly bool _tracked;
private bool NeedsWriteback => _block != null; private bool NeedsWriteback => _block != null;
@ -22,7 +22,7 @@ namespace Ryujinx.Memory
Memory = memory; Memory = memory;
} }
public WritableRegion(IWritableBlock block, ulong va, MemoryOwner<byte> memoryOwner, bool tracked = false) public WritableRegion(IWritableBlock block, ulong va, IMemoryOwner<byte> memoryOwner, bool tracked = false)
: this(block, va, memoryOwner.Memory, tracked) : this(block, va, memoryOwner.Memory, tracked)
{ {
_memoryOwner = memoryOwner; _memoryOwner = memoryOwner;

View file

@ -53,7 +53,6 @@ namespace Ryujinx.SDL2.Common
return; return;
} }
SDL_SetHint(SDL_HINT_APP_NAME, "Ryujinx");
SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_PS4_RUMBLE, "1"); SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_PS4_RUMBLE, "1");
SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_PS5_RUMBLE, "1"); SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_PS5_RUMBLE, "1");
SDL_SetHint(SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS, "1"); SDL_SetHint(SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS, "1");

View file

@ -55,7 +55,6 @@ namespace Ryujinx.Tests.Audio.Renderer.Server
Assert.IsFalse(behaviourContext.UseMultiTapBiquadFilterProcessing()); Assert.IsFalse(behaviourContext.UseMultiTapBiquadFilterProcessing());
Assert.IsFalse(behaviourContext.IsNewEffectChannelMappingSupported()); Assert.IsFalse(behaviourContext.IsNewEffectChannelMappingSupported());
Assert.IsFalse(behaviourContext.IsBiquadFilterParameterForSplitterEnabled()); Assert.IsFalse(behaviourContext.IsBiquadFilterParameterForSplitterEnabled());
Assert.IsFalse(behaviourContext.IsSplitterPrevVolumeResetSupported());
Assert.AreEqual(0.70f, behaviourContext.GetAudioRendererProcessingTimeLimit()); Assert.AreEqual(0.70f, behaviourContext.GetAudioRendererProcessingTimeLimit());
Assert.AreEqual(1, behaviourContext.GetCommandProcessingTimeEstimatorVersion()); Assert.AreEqual(1, behaviourContext.GetCommandProcessingTimeEstimatorVersion());
@ -84,7 +83,6 @@ namespace Ryujinx.Tests.Audio.Renderer.Server
Assert.IsFalse(behaviourContext.UseMultiTapBiquadFilterProcessing()); Assert.IsFalse(behaviourContext.UseMultiTapBiquadFilterProcessing());
Assert.IsFalse(behaviourContext.IsNewEffectChannelMappingSupported()); Assert.IsFalse(behaviourContext.IsNewEffectChannelMappingSupported());
Assert.IsFalse(behaviourContext.IsBiquadFilterParameterForSplitterEnabled()); Assert.IsFalse(behaviourContext.IsBiquadFilterParameterForSplitterEnabled());
Assert.IsFalse(behaviourContext.IsSplitterPrevVolumeResetSupported());
Assert.AreEqual(0.70f, behaviourContext.GetAudioRendererProcessingTimeLimit()); Assert.AreEqual(0.70f, behaviourContext.GetAudioRendererProcessingTimeLimit());
Assert.AreEqual(1, behaviourContext.GetCommandProcessingTimeEstimatorVersion()); Assert.AreEqual(1, behaviourContext.GetCommandProcessingTimeEstimatorVersion());
@ -113,7 +111,6 @@ namespace Ryujinx.Tests.Audio.Renderer.Server
Assert.IsFalse(behaviourContext.UseMultiTapBiquadFilterProcessing()); Assert.IsFalse(behaviourContext.UseMultiTapBiquadFilterProcessing());
Assert.IsFalse(behaviourContext.IsNewEffectChannelMappingSupported()); Assert.IsFalse(behaviourContext.IsNewEffectChannelMappingSupported());
Assert.IsFalse(behaviourContext.IsBiquadFilterParameterForSplitterEnabled()); Assert.IsFalse(behaviourContext.IsBiquadFilterParameterForSplitterEnabled());
Assert.IsFalse(behaviourContext.IsSplitterPrevVolumeResetSupported());
Assert.AreEqual(0.70f, behaviourContext.GetAudioRendererProcessingTimeLimit()); Assert.AreEqual(0.70f, behaviourContext.GetAudioRendererProcessingTimeLimit());
Assert.AreEqual(1, behaviourContext.GetCommandProcessingTimeEstimatorVersion()); Assert.AreEqual(1, behaviourContext.GetCommandProcessingTimeEstimatorVersion());
@ -142,7 +139,6 @@ namespace Ryujinx.Tests.Audio.Renderer.Server
Assert.IsFalse(behaviourContext.UseMultiTapBiquadFilterProcessing()); Assert.IsFalse(behaviourContext.UseMultiTapBiquadFilterProcessing());
Assert.IsFalse(behaviourContext.IsNewEffectChannelMappingSupported()); Assert.IsFalse(behaviourContext.IsNewEffectChannelMappingSupported());
Assert.IsFalse(behaviourContext.IsBiquadFilterParameterForSplitterEnabled()); Assert.IsFalse(behaviourContext.IsBiquadFilterParameterForSplitterEnabled());
Assert.IsFalse(behaviourContext.IsSplitterPrevVolumeResetSupported());
Assert.AreEqual(0.75f, behaviourContext.GetAudioRendererProcessingTimeLimit()); Assert.AreEqual(0.75f, behaviourContext.GetAudioRendererProcessingTimeLimit());
Assert.AreEqual(1, behaviourContext.GetCommandProcessingTimeEstimatorVersion()); Assert.AreEqual(1, behaviourContext.GetCommandProcessingTimeEstimatorVersion());
@ -171,7 +167,6 @@ namespace Ryujinx.Tests.Audio.Renderer.Server
Assert.IsFalse(behaviourContext.UseMultiTapBiquadFilterProcessing()); Assert.IsFalse(behaviourContext.UseMultiTapBiquadFilterProcessing());
Assert.IsFalse(behaviourContext.IsNewEffectChannelMappingSupported()); Assert.IsFalse(behaviourContext.IsNewEffectChannelMappingSupported());
Assert.IsFalse(behaviourContext.IsBiquadFilterParameterForSplitterEnabled()); Assert.IsFalse(behaviourContext.IsBiquadFilterParameterForSplitterEnabled());
Assert.IsFalse(behaviourContext.IsSplitterPrevVolumeResetSupported());
Assert.AreEqual(0.80f, behaviourContext.GetAudioRendererProcessingTimeLimit()); Assert.AreEqual(0.80f, behaviourContext.GetAudioRendererProcessingTimeLimit());
Assert.AreEqual(2, behaviourContext.GetCommandProcessingTimeEstimatorVersion()); Assert.AreEqual(2, behaviourContext.GetCommandProcessingTimeEstimatorVersion());
@ -200,7 +195,6 @@ namespace Ryujinx.Tests.Audio.Renderer.Server
Assert.IsFalse(behaviourContext.UseMultiTapBiquadFilterProcessing()); Assert.IsFalse(behaviourContext.UseMultiTapBiquadFilterProcessing());
Assert.IsFalse(behaviourContext.IsNewEffectChannelMappingSupported()); Assert.IsFalse(behaviourContext.IsNewEffectChannelMappingSupported());
Assert.IsFalse(behaviourContext.IsBiquadFilterParameterForSplitterEnabled()); Assert.IsFalse(behaviourContext.IsBiquadFilterParameterForSplitterEnabled());
Assert.IsFalse(behaviourContext.IsSplitterPrevVolumeResetSupported());
Assert.AreEqual(0.80f, behaviourContext.GetAudioRendererProcessingTimeLimit()); Assert.AreEqual(0.80f, behaviourContext.GetAudioRendererProcessingTimeLimit());
Assert.AreEqual(2, behaviourContext.GetCommandProcessingTimeEstimatorVersion()); Assert.AreEqual(2, behaviourContext.GetCommandProcessingTimeEstimatorVersion());
@ -229,7 +223,6 @@ namespace Ryujinx.Tests.Audio.Renderer.Server
Assert.IsFalse(behaviourContext.UseMultiTapBiquadFilterProcessing()); Assert.IsFalse(behaviourContext.UseMultiTapBiquadFilterProcessing());
Assert.IsFalse(behaviourContext.IsNewEffectChannelMappingSupported()); Assert.IsFalse(behaviourContext.IsNewEffectChannelMappingSupported());
Assert.IsFalse(behaviourContext.IsBiquadFilterParameterForSplitterEnabled()); Assert.IsFalse(behaviourContext.IsBiquadFilterParameterForSplitterEnabled());
Assert.IsFalse(behaviourContext.IsSplitterPrevVolumeResetSupported());
Assert.AreEqual(0.80f, behaviourContext.GetAudioRendererProcessingTimeLimit()); Assert.AreEqual(0.80f, behaviourContext.GetAudioRendererProcessingTimeLimit());
Assert.AreEqual(2, behaviourContext.GetCommandProcessingTimeEstimatorVersion()); Assert.AreEqual(2, behaviourContext.GetCommandProcessingTimeEstimatorVersion());
@ -258,7 +251,6 @@ namespace Ryujinx.Tests.Audio.Renderer.Server
Assert.IsFalse(behaviourContext.UseMultiTapBiquadFilterProcessing()); Assert.IsFalse(behaviourContext.UseMultiTapBiquadFilterProcessing());
Assert.IsFalse(behaviourContext.IsNewEffectChannelMappingSupported()); Assert.IsFalse(behaviourContext.IsNewEffectChannelMappingSupported());
Assert.IsFalse(behaviourContext.IsBiquadFilterParameterForSplitterEnabled()); Assert.IsFalse(behaviourContext.IsBiquadFilterParameterForSplitterEnabled());
Assert.IsFalse(behaviourContext.IsSplitterPrevVolumeResetSupported());
Assert.AreEqual(0.80f, behaviourContext.GetAudioRendererProcessingTimeLimit()); Assert.AreEqual(0.80f, behaviourContext.GetAudioRendererProcessingTimeLimit());
Assert.AreEqual(3, behaviourContext.GetCommandProcessingTimeEstimatorVersion()); Assert.AreEqual(3, behaviourContext.GetCommandProcessingTimeEstimatorVersion());
@ -287,7 +279,6 @@ namespace Ryujinx.Tests.Audio.Renderer.Server
Assert.IsFalse(behaviourContext.UseMultiTapBiquadFilterProcessing()); Assert.IsFalse(behaviourContext.UseMultiTapBiquadFilterProcessing());
Assert.IsFalse(behaviourContext.IsNewEffectChannelMappingSupported()); Assert.IsFalse(behaviourContext.IsNewEffectChannelMappingSupported());
Assert.IsFalse(behaviourContext.IsBiquadFilterParameterForSplitterEnabled()); Assert.IsFalse(behaviourContext.IsBiquadFilterParameterForSplitterEnabled());
Assert.IsFalse(behaviourContext.IsSplitterPrevVolumeResetSupported());
Assert.AreEqual(0.80f, behaviourContext.GetAudioRendererProcessingTimeLimit()); Assert.AreEqual(0.80f, behaviourContext.GetAudioRendererProcessingTimeLimit());
Assert.AreEqual(3, behaviourContext.GetCommandProcessingTimeEstimatorVersion()); Assert.AreEqual(3, behaviourContext.GetCommandProcessingTimeEstimatorVersion());
@ -316,7 +307,6 @@ namespace Ryujinx.Tests.Audio.Renderer.Server
Assert.IsTrue(behaviourContext.UseMultiTapBiquadFilterProcessing()); Assert.IsTrue(behaviourContext.UseMultiTapBiquadFilterProcessing());
Assert.IsFalse(behaviourContext.IsNewEffectChannelMappingSupported()); Assert.IsFalse(behaviourContext.IsNewEffectChannelMappingSupported());
Assert.IsFalse(behaviourContext.IsBiquadFilterParameterForSplitterEnabled()); Assert.IsFalse(behaviourContext.IsBiquadFilterParameterForSplitterEnabled());
Assert.IsFalse(behaviourContext.IsSplitterPrevVolumeResetSupported());
Assert.AreEqual(0.80f, behaviourContext.GetAudioRendererProcessingTimeLimit()); Assert.AreEqual(0.80f, behaviourContext.GetAudioRendererProcessingTimeLimit());
Assert.AreEqual(4, behaviourContext.GetCommandProcessingTimeEstimatorVersion()); Assert.AreEqual(4, behaviourContext.GetCommandProcessingTimeEstimatorVersion());
@ -345,7 +335,6 @@ namespace Ryujinx.Tests.Audio.Renderer.Server
Assert.IsTrue(behaviourContext.UseMultiTapBiquadFilterProcessing()); Assert.IsTrue(behaviourContext.UseMultiTapBiquadFilterProcessing());
Assert.IsTrue(behaviourContext.IsNewEffectChannelMappingSupported()); Assert.IsTrue(behaviourContext.IsNewEffectChannelMappingSupported());
Assert.IsFalse(behaviourContext.IsBiquadFilterParameterForSplitterEnabled()); Assert.IsFalse(behaviourContext.IsBiquadFilterParameterForSplitterEnabled());
Assert.IsFalse(behaviourContext.IsSplitterPrevVolumeResetSupported());
Assert.AreEqual(0.80f, behaviourContext.GetAudioRendererProcessingTimeLimit()); Assert.AreEqual(0.80f, behaviourContext.GetAudioRendererProcessingTimeLimit());
Assert.AreEqual(5, behaviourContext.GetCommandProcessingTimeEstimatorVersion()); Assert.AreEqual(5, behaviourContext.GetCommandProcessingTimeEstimatorVersion());
@ -374,36 +363,6 @@ namespace Ryujinx.Tests.Audio.Renderer.Server
Assert.IsTrue(behaviourContext.UseMultiTapBiquadFilterProcessing()); Assert.IsTrue(behaviourContext.UseMultiTapBiquadFilterProcessing());
Assert.IsTrue(behaviourContext.IsNewEffectChannelMappingSupported()); Assert.IsTrue(behaviourContext.IsNewEffectChannelMappingSupported());
Assert.IsTrue(behaviourContext.IsBiquadFilterParameterForSplitterEnabled()); Assert.IsTrue(behaviourContext.IsBiquadFilterParameterForSplitterEnabled());
Assert.IsFalse(behaviourContext.IsSplitterPrevVolumeResetSupported());
Assert.AreEqual(0.80f, behaviourContext.GetAudioRendererProcessingTimeLimit());
Assert.AreEqual(5, behaviourContext.GetCommandProcessingTimeEstimatorVersion());
Assert.AreEqual(2, behaviourContext.GetPerformanceMetricsDataFormat());
}
[Test]
public void TestRevision13()
{
BehaviourContext behaviourContext = new();
behaviourContext.SetUserRevision(BehaviourContext.BaseRevisionMagic + BehaviourContext.Revision13);
Assert.IsTrue(behaviourContext.IsAdpcmLoopContextBugFixed());
Assert.IsTrue(behaviourContext.IsSplitterSupported());
Assert.IsTrue(behaviourContext.IsLongSizePreDelaySupported());
Assert.IsTrue(behaviourContext.IsAudioUsbDeviceOutputSupported());
Assert.IsTrue(behaviourContext.IsFlushVoiceWaveBuffersSupported());
Assert.IsTrue(behaviourContext.IsSplitterBugFixed());
Assert.IsTrue(behaviourContext.IsElapsedFrameCountSupported());
Assert.IsTrue(behaviourContext.IsDecodingBehaviourFlagSupported());
Assert.IsTrue(behaviourContext.IsBiquadFilterEffectStateClearBugFixed());
Assert.IsTrue(behaviourContext.IsMixInParameterDirtyOnlyUpdateSupported());
Assert.IsTrue(behaviourContext.IsWaveBufferVersion2Supported());
Assert.IsTrue(behaviourContext.IsEffectInfoVersion2Supported());
Assert.IsTrue(behaviourContext.UseMultiTapBiquadFilterProcessing());
Assert.IsTrue(behaviourContext.IsNewEffectChannelMappingSupported());
Assert.IsTrue(behaviourContext.IsBiquadFilterParameterForSplitterEnabled());
Assert.IsTrue(behaviourContext.IsSplitterPrevVolumeResetSupported());
Assert.AreEqual(0.80f, behaviourContext.GetAudioRendererProcessingTimeLimit()); Assert.AreEqual(0.80f, behaviourContext.GetAudioRendererProcessingTimeLimit());
Assert.AreEqual(5, behaviourContext.GetCommandProcessingTimeEstimatorVersion()); Assert.AreEqual(5, behaviourContext.GetCommandProcessingTimeEstimatorVersion());