mirror of
https://git.ryujinx.app/kenji-nx/ryujinx.git
synced 2025-12-12 19:37:06 +00:00
Memory Changes part 2
* Slightly refactors RangeLists from the last Memory Changes MR, which fixes issue 61. * Convert as many const size array iterators to span iterators as possible. When iterating over a const size array, every iteration created a Span, now only the first iteration does in most places. * Now using object pooling for a few object types that were rapidly deleted and recreated. * Converted a few flag checks to binary operations to save memory allocations.
This commit is contained in:
parent
01cb33f658
commit
171624e7f0
89 changed files with 2121 additions and 1157 deletions
|
|
@ -26,12 +26,15 @@ namespace Ryujinx.Audio.Renderer.Dsp
|
||||||
ReadOnlySpan<float> inputBuffer,
|
ReadOnlySpan<float> inputBuffer,
|
||||||
uint sampleCount)
|
uint sampleCount)
|
||||||
{
|
{
|
||||||
float a0 = FixedPointHelper.ToFloat(parameter.Numerator[0], FixedPointPrecisionForParameter);
|
Span<short> numeratorSpan = parameter.Numerator.AsSpan();
|
||||||
float a1 = FixedPointHelper.ToFloat(parameter.Numerator[1], FixedPointPrecisionForParameter);
|
Span<short> denominatorSpan = parameter.Denominator.AsSpan();
|
||||||
float a2 = FixedPointHelper.ToFloat(parameter.Numerator[2], FixedPointPrecisionForParameter);
|
|
||||||
|
float a0 = FixedPointHelper.ToFloat(numeratorSpan[0], FixedPointPrecisionForParameter);
|
||||||
|
float a1 = FixedPointHelper.ToFloat(numeratorSpan[1], FixedPointPrecisionForParameter);
|
||||||
|
float a2 = FixedPointHelper.ToFloat(numeratorSpan[2], FixedPointPrecisionForParameter);
|
||||||
|
|
||||||
float b1 = FixedPointHelper.ToFloat(parameter.Denominator[0], FixedPointPrecisionForParameter);
|
float b1 = FixedPointHelper.ToFloat(denominatorSpan[0], FixedPointPrecisionForParameter);
|
||||||
float b2 = FixedPointHelper.ToFloat(parameter.Denominator[1], FixedPointPrecisionForParameter);
|
float b2 = FixedPointHelper.ToFloat(denominatorSpan[1], FixedPointPrecisionForParameter);
|
||||||
|
|
||||||
for (int i = 0; i < sampleCount; i++)
|
for (int i = 0; i < sampleCount; i++)
|
||||||
{
|
{
|
||||||
|
|
@ -64,12 +67,15 @@ namespace Ryujinx.Audio.Renderer.Dsp
|
||||||
uint sampleCount,
|
uint sampleCount,
|
||||||
float volume)
|
float volume)
|
||||||
{
|
{
|
||||||
float a0 = FixedPointHelper.ToFloat(parameter.Numerator[0], FixedPointPrecisionForParameter);
|
Span<short> numeratorSpan = parameter.Numerator.AsSpan();
|
||||||
float a1 = FixedPointHelper.ToFloat(parameter.Numerator[1], FixedPointPrecisionForParameter);
|
Span<short> denominatorSpan = parameter.Denominator.AsSpan();
|
||||||
float a2 = FixedPointHelper.ToFloat(parameter.Numerator[2], FixedPointPrecisionForParameter);
|
|
||||||
|
float a0 = FixedPointHelper.ToFloat(numeratorSpan[0], FixedPointPrecisionForParameter);
|
||||||
|
float a1 = FixedPointHelper.ToFloat(numeratorSpan[1], FixedPointPrecisionForParameter);
|
||||||
|
float a2 = FixedPointHelper.ToFloat(numeratorSpan[2], FixedPointPrecisionForParameter);
|
||||||
|
|
||||||
float b1 = FixedPointHelper.ToFloat(parameter.Denominator[0], FixedPointPrecisionForParameter);
|
float b1 = FixedPointHelper.ToFloat(denominatorSpan[0], FixedPointPrecisionForParameter);
|
||||||
float b2 = FixedPointHelper.ToFloat(parameter.Denominator[1], FixedPointPrecisionForParameter);
|
float b2 = FixedPointHelper.ToFloat(denominatorSpan[1], FixedPointPrecisionForParameter);
|
||||||
|
|
||||||
for (int i = 0; i < sampleCount; i++)
|
for (int i = 0; i < sampleCount; i++)
|
||||||
{
|
{
|
||||||
|
|
@ -107,12 +113,15 @@ namespace Ryujinx.Audio.Renderer.Dsp
|
||||||
float volume,
|
float volume,
|
||||||
float ramp)
|
float ramp)
|
||||||
{
|
{
|
||||||
float a0 = FixedPointHelper.ToFloat(parameter.Numerator[0], FixedPointPrecisionForParameter);
|
Span<short> numeratorSpan = parameter.Numerator.AsSpan();
|
||||||
float a1 = FixedPointHelper.ToFloat(parameter.Numerator[1], FixedPointPrecisionForParameter);
|
Span<short> denominatorSpan = parameter.Denominator.AsSpan();
|
||||||
float a2 = FixedPointHelper.ToFloat(parameter.Numerator[2], FixedPointPrecisionForParameter);
|
|
||||||
|
float a0 = FixedPointHelper.ToFloat(numeratorSpan[0], FixedPointPrecisionForParameter);
|
||||||
|
float a1 = FixedPointHelper.ToFloat(numeratorSpan[1], FixedPointPrecisionForParameter);
|
||||||
|
float a2 = FixedPointHelper.ToFloat(numeratorSpan[2], FixedPointPrecisionForParameter);
|
||||||
|
|
||||||
float b1 = FixedPointHelper.ToFloat(parameter.Denominator[0], FixedPointPrecisionForParameter);
|
float b1 = FixedPointHelper.ToFloat(denominatorSpan[0], FixedPointPrecisionForParameter);
|
||||||
float b2 = FixedPointHelper.ToFloat(parameter.Denominator[1], FixedPointPrecisionForParameter);
|
float b2 = FixedPointHelper.ToFloat(denominatorSpan[1], FixedPointPrecisionForParameter);
|
||||||
|
|
||||||
float mixState = 0f;
|
float mixState = 0f;
|
||||||
|
|
||||||
|
|
@ -157,13 +166,16 @@ namespace Ryujinx.Audio.Renderer.Dsp
|
||||||
BiquadFilterParameter parameter = parameters[stageIndex];
|
BiquadFilterParameter parameter = parameters[stageIndex];
|
||||||
|
|
||||||
ref BiquadFilterState state = ref states[stageIndex];
|
ref BiquadFilterState state = ref states[stageIndex];
|
||||||
|
|
||||||
|
Span<short> numeratorSpan = parameter.Numerator.AsSpan();
|
||||||
|
Span<short> denominatorSpan = parameter.Denominator.AsSpan();
|
||||||
|
|
||||||
float a0 = FixedPointHelper.ToFloat(parameter.Numerator[0], FixedPointPrecisionForParameter);
|
float a0 = FixedPointHelper.ToFloat(numeratorSpan[0], FixedPointPrecisionForParameter);
|
||||||
float a1 = FixedPointHelper.ToFloat(parameter.Numerator[1], FixedPointPrecisionForParameter);
|
float a1 = FixedPointHelper.ToFloat(numeratorSpan[1], FixedPointPrecisionForParameter);
|
||||||
float a2 = FixedPointHelper.ToFloat(parameter.Numerator[2], FixedPointPrecisionForParameter);
|
float a2 = FixedPointHelper.ToFloat(numeratorSpan[2], FixedPointPrecisionForParameter);
|
||||||
|
|
||||||
float b1 = FixedPointHelper.ToFloat(parameter.Denominator[0], FixedPointPrecisionForParameter);
|
float b1 = FixedPointHelper.ToFloat(denominatorSpan[0], FixedPointPrecisionForParameter);
|
||||||
float b2 = FixedPointHelper.ToFloat(parameter.Denominator[1], FixedPointPrecisionForParameter);
|
float b2 = FixedPointHelper.ToFloat(denominatorSpan[1], FixedPointPrecisionForParameter);
|
||||||
|
|
||||||
for (int i = 0; i < sampleCount; i++)
|
for (int i = 0; i < sampleCount; i++)
|
||||||
{
|
{
|
||||||
|
|
@ -201,19 +213,25 @@ namespace Ryujinx.Audio.Renderer.Dsp
|
||||||
uint sampleCount,
|
uint sampleCount,
|
||||||
float volume)
|
float volume)
|
||||||
{
|
{
|
||||||
float a00 = FixedPointHelper.ToFloat(parameter0.Numerator[0], FixedPointPrecisionForParameter);
|
Span<short> numerator0Span = parameter0.Numerator.AsSpan();
|
||||||
float a10 = FixedPointHelper.ToFloat(parameter0.Numerator[1], FixedPointPrecisionForParameter);
|
Span<short> numerator1Span = parameter1.Numerator.AsSpan();
|
||||||
float a20 = FixedPointHelper.ToFloat(parameter0.Numerator[2], FixedPointPrecisionForParameter);
|
Span<short> denominator0Span = parameter0.Denominator.AsSpan();
|
||||||
|
Span<short> denominator1Span = parameter1.Denominator.AsSpan();
|
||||||
|
|
||||||
|
|
||||||
|
float a00 = FixedPointHelper.ToFloat(numerator0Span[0], FixedPointPrecisionForParameter);
|
||||||
|
float a10 = FixedPointHelper.ToFloat(numerator0Span[1], FixedPointPrecisionForParameter);
|
||||||
|
float a20 = FixedPointHelper.ToFloat(numerator0Span[2], FixedPointPrecisionForParameter);
|
||||||
|
|
||||||
float b10 = FixedPointHelper.ToFloat(parameter0.Denominator[0], FixedPointPrecisionForParameter);
|
float b10 = FixedPointHelper.ToFloat(denominator0Span[0], FixedPointPrecisionForParameter);
|
||||||
float b20 = FixedPointHelper.ToFloat(parameter0.Denominator[1], FixedPointPrecisionForParameter);
|
float b20 = FixedPointHelper.ToFloat(denominator0Span[1], FixedPointPrecisionForParameter);
|
||||||
|
|
||||||
float a01 = FixedPointHelper.ToFloat(parameter1.Numerator[0], FixedPointPrecisionForParameter);
|
float a01 = FixedPointHelper.ToFloat(numerator1Span[0], FixedPointPrecisionForParameter);
|
||||||
float a11 = FixedPointHelper.ToFloat(parameter1.Numerator[1], FixedPointPrecisionForParameter);
|
float a11 = FixedPointHelper.ToFloat(numerator1Span[1], FixedPointPrecisionForParameter);
|
||||||
float a21 = FixedPointHelper.ToFloat(parameter1.Numerator[2], FixedPointPrecisionForParameter);
|
float a21 = FixedPointHelper.ToFloat(numerator1Span[2], FixedPointPrecisionForParameter);
|
||||||
|
|
||||||
float b11 = FixedPointHelper.ToFloat(parameter1.Denominator[0], FixedPointPrecisionForParameter);
|
float b11 = FixedPointHelper.ToFloat(denominator1Span[0], FixedPointPrecisionForParameter);
|
||||||
float b21 = FixedPointHelper.ToFloat(parameter1.Denominator[1], FixedPointPrecisionForParameter);
|
float b21 = FixedPointHelper.ToFloat(denominator1Span[1], FixedPointPrecisionForParameter);
|
||||||
|
|
||||||
for (int i = 0; i < sampleCount; i++)
|
for (int i = 0; i < sampleCount; i++)
|
||||||
{
|
{
|
||||||
|
|
@ -261,19 +279,24 @@ namespace Ryujinx.Audio.Renderer.Dsp
|
||||||
float volume,
|
float volume,
|
||||||
float ramp)
|
float ramp)
|
||||||
{
|
{
|
||||||
float a00 = FixedPointHelper.ToFloat(parameter0.Numerator[0], FixedPointPrecisionForParameter);
|
Span<short> numerator0Span = parameter0.Numerator.AsSpan();
|
||||||
float a10 = FixedPointHelper.ToFloat(parameter0.Numerator[1], FixedPointPrecisionForParameter);
|
Span<short> numerator1Span = parameter1.Numerator.AsSpan();
|
||||||
float a20 = FixedPointHelper.ToFloat(parameter0.Numerator[2], FixedPointPrecisionForParameter);
|
Span<short> denominator0Span = parameter0.Denominator.AsSpan();
|
||||||
|
Span<short> denominator1Span = parameter1.Denominator.AsSpan();
|
||||||
|
|
||||||
|
float a00 = FixedPointHelper.ToFloat(numerator0Span[0], FixedPointPrecisionForParameter);
|
||||||
|
float a10 = FixedPointHelper.ToFloat(numerator0Span[1], FixedPointPrecisionForParameter);
|
||||||
|
float a20 = FixedPointHelper.ToFloat(numerator0Span[2], FixedPointPrecisionForParameter);
|
||||||
|
|
||||||
float b10 = FixedPointHelper.ToFloat(parameter0.Denominator[0], FixedPointPrecisionForParameter);
|
float b10 = FixedPointHelper.ToFloat(denominator0Span[0], FixedPointPrecisionForParameter);
|
||||||
float b20 = FixedPointHelper.ToFloat(parameter0.Denominator[1], FixedPointPrecisionForParameter);
|
float b20 = FixedPointHelper.ToFloat(denominator0Span[1], FixedPointPrecisionForParameter);
|
||||||
|
|
||||||
float a01 = FixedPointHelper.ToFloat(parameter1.Numerator[0], FixedPointPrecisionForParameter);
|
float a01 = FixedPointHelper.ToFloat(numerator1Span[0], FixedPointPrecisionForParameter);
|
||||||
float a11 = FixedPointHelper.ToFloat(parameter1.Numerator[1], FixedPointPrecisionForParameter);
|
float a11 = FixedPointHelper.ToFloat(numerator1Span[1], FixedPointPrecisionForParameter);
|
||||||
float a21 = FixedPointHelper.ToFloat(parameter1.Numerator[2], FixedPointPrecisionForParameter);
|
float a21 = FixedPointHelper.ToFloat(numerator1Span[2], FixedPointPrecisionForParameter);
|
||||||
|
|
||||||
float b11 = FixedPointHelper.ToFloat(parameter1.Denominator[0], FixedPointPrecisionForParameter);
|
float b11 = FixedPointHelper.ToFloat(denominator1Span[0], FixedPointPrecisionForParameter);
|
||||||
float b21 = FixedPointHelper.ToFloat(parameter1.Denominator[1], FixedPointPrecisionForParameter);
|
float b21 = FixedPointHelper.ToFloat(denominator1Span[1], FixedPointPrecisionForParameter);
|
||||||
|
|
||||||
float mixState = 0f;
|
float mixState = 0f;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -39,12 +39,14 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
||||||
OutputBufferIndex = outputBufferIndex;
|
OutputBufferIndex = outputBufferIndex;
|
||||||
SampleRate = serverState.SampleRate;
|
SampleRate = serverState.SampleRate;
|
||||||
Pitch = serverState.Pitch;
|
Pitch = serverState.Pitch;
|
||||||
|
|
||||||
|
Span<Server.Voice.WaveBuffer> waveBufferSpan = serverState.WaveBuffers.AsSpan();
|
||||||
|
|
||||||
WaveBuffers = new WaveBuffer[Constants.VoiceWaveBufferCount];
|
WaveBuffers = new WaveBuffer[Constants.VoiceWaveBufferCount];
|
||||||
|
|
||||||
for (int i = 0; i < WaveBuffers.Length; i++)
|
for (int i = 0; i < WaveBuffers.Length; i++)
|
||||||
{
|
{
|
||||||
ref Server.Voice.WaveBuffer voiceWaveBuffer = ref serverState.WaveBuffers[i];
|
ref Server.Voice.WaveBuffer voiceWaveBuffer = ref waveBufferSpan[i];
|
||||||
|
|
||||||
WaveBuffers[i] = voiceWaveBuffer.ToCommon(1);
|
WaveBuffers[i] = voiceWaveBuffer.ToCommon(1);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
using Ryujinx.Audio.Renderer.Parameter.Sink;
|
using Ryujinx.Audio.Renderer.Parameter.Sink;
|
||||||
using Ryujinx.Audio.Renderer.Server.MemoryPool;
|
using Ryujinx.Audio.Renderer.Server.MemoryPool;
|
||||||
|
using System;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
|
|
||||||
namespace Ryujinx.Audio.Renderer.Dsp.Command
|
namespace Ryujinx.Audio.Renderer.Dsp.Command
|
||||||
|
|
@ -28,10 +29,12 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
||||||
|
|
||||||
Input = new ushort[Constants.ChannelCountMax];
|
Input = new ushort[Constants.ChannelCountMax];
|
||||||
InputCount = parameter.InputCount;
|
InputCount = parameter.InputCount;
|
||||||
|
|
||||||
|
Span<byte> inputSpan = parameter.Input.AsSpan();
|
||||||
|
|
||||||
for (int i = 0; i < InputCount; i++)
|
for (int i = 0; i < InputCount; i++)
|
||||||
{
|
{
|
||||||
Input[i] = (ushort)(bufferOffset + parameter.Input[i]);
|
Input[i] = (ushort)(bufferOffset + inputSpan[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
CircularBuffer = circularBufferAddressInfo.GetReference(true);
|
CircularBuffer = circularBufferAddressInfo.GetReference(true);
|
||||||
|
|
|
||||||
|
|
@ -42,11 +42,14 @@ 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];
|
||||||
|
|
||||||
|
Span<byte> inputSpan = _parameter.Input.AsSpan();
|
||||||
|
Span<byte> outputSpan = _parameter.Output.AsSpan();
|
||||||
|
|
||||||
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 + inputSpan[i]);
|
||||||
OutputBufferIndices[i] = (ushort)(bufferOffset + _parameter.Output[i]);
|
OutputBufferIndices[i] = (ushort)(bufferOffset + outputSpan[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -171,10 +174,12 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
||||||
|
|
||||||
statistics.MinimumGain = MathF.Min(statistics.MinimumGain, compressionGain * state.OutputGain);
|
statistics.MinimumGain = MathF.Min(statistics.MinimumGain, compressionGain * state.OutputGain);
|
||||||
statistics.MaximumMean = MathF.Max(statistics.MaximumMean, mean);
|
statistics.MaximumMean = MathF.Max(statistics.MaximumMean, mean);
|
||||||
|
|
||||||
|
Span<float> lastSamplesSpan = statistics.LastSamples.AsSpan();
|
||||||
|
|
||||||
for (int channelIndex = 0; channelIndex < _parameter.ChannelCount; channelIndex++)
|
for (int channelIndex = 0; channelIndex < _parameter.ChannelCount; channelIndex++)
|
||||||
{
|
{
|
||||||
statistics.LastSamples[channelIndex] = MathF.Abs(channelInput[channelIndex] * (1f / 32768f));
|
lastSamplesSpan[channelIndex] = MathF.Abs(channelInput[channelIndex] * (1f / 32768f));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -52,12 +52,14 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
||||||
OutputBufferIndex = (ushort)(channelIndex + outputBufferIndex);
|
OutputBufferIndex = (ushort)(channelIndex + outputBufferIndex);
|
||||||
SampleRate = serverState.SampleRate;
|
SampleRate = serverState.SampleRate;
|
||||||
Pitch = serverState.Pitch;
|
Pitch = serverState.Pitch;
|
||||||
|
|
||||||
|
Span<Server.Voice.WaveBuffer> waveBufferSpan = serverState.WaveBuffers.AsSpan();
|
||||||
|
|
||||||
WaveBuffers = new WaveBuffer[Constants.VoiceWaveBufferCount];
|
WaveBuffers = new WaveBuffer[Constants.VoiceWaveBufferCount];
|
||||||
|
|
||||||
for (int i = 0; i < WaveBuffers.Length; i++)
|
for (int i = 0; i < WaveBuffers.Length; i++)
|
||||||
{
|
{
|
||||||
ref Server.Voice.WaveBuffer voiceWaveBuffer = ref serverState.WaveBuffers[i];
|
ref Server.Voice.WaveBuffer voiceWaveBuffer = ref waveBufferSpan[i];
|
||||||
|
|
||||||
WaveBuffers[i] = voiceWaveBuffer.ToCommon(2);
|
WaveBuffers[i] = voiceWaveBuffer.ToCommon(2);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -42,11 +42,14 @@ 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];
|
||||||
|
|
||||||
|
Span<byte> inputSpan = Parameter.Input.AsSpan();
|
||||||
|
Span<byte> outputSpan = Parameter.Output.AsSpan();
|
||||||
|
|
||||||
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 + inputSpan[i]);
|
||||||
OutputBufferIndices[i] = (ushort)(bufferOffset + Parameter.Output[i]);
|
OutputBufferIndices[i] = (ushort)(bufferOffset + outputSpan[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
DataSourceHelper.RemapLegacyChannelEffectMappingToChannelResourceMapping(newEffectChannelMappingSupported, InputBufferIndices, Parameter.ChannelCount);
|
DataSourceHelper.RemapLegacyChannelEffectMappingToChannelResourceMapping(newEffectChannelMappingSupported, InputBufferIndices, Parameter.ChannelCount);
|
||||||
|
|
|
||||||
|
|
@ -42,14 +42,15 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
||||||
ref VoiceUpdateState state = ref State.Span[0];
|
ref VoiceUpdateState state = ref State.Span[0];
|
||||||
|
|
||||||
Span<float> depopBuffer = DepopBuffer.Span;
|
Span<float> depopBuffer = DepopBuffer.Span;
|
||||||
|
Span<float> lastSamplesSpan = state.LastSamples.AsSpan();
|
||||||
|
|
||||||
for (int i = 0; i < MixBufferCount; i++)
|
for (int i = 0; i < MixBufferCount; i++)
|
||||||
{
|
{
|
||||||
if (state.LastSamples[i] != 0)
|
if (lastSamplesSpan[i] != 0)
|
||||||
{
|
{
|
||||||
depopBuffer[OutputBufferIndices[i]] += state.LastSamples[i];
|
depopBuffer[OutputBufferIndices[i]] += lastSamplesSpan[i];
|
||||||
|
|
||||||
state.LastSamples[i] = 0;
|
lastSamplesSpan[i] = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -34,10 +34,12 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
||||||
SessionId = sessionId;
|
SessionId = sessionId;
|
||||||
InputCount = sink.Parameter.InputCount;
|
InputCount = sink.Parameter.InputCount;
|
||||||
InputBufferIndices = new ushort[InputCount];
|
InputBufferIndices = new ushort[InputCount];
|
||||||
|
|
||||||
|
Span<byte> inputSpan = sink.Parameter.Input.AsSpan();
|
||||||
|
|
||||||
for (int i = 0; i < Math.Min(InputCount, Constants.ChannelCountMax); i++)
|
for (int i = 0; i < Math.Min(InputCount, Constants.ChannelCountMax); i++)
|
||||||
{
|
{
|
||||||
InputBufferIndices[i] = (ushort)(bufferOffset + sink.Parameter.Input[i]);
|
InputBufferIndices[i] = (ushort)(bufferOffset + inputSpan[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sink.UpsamplerState != null)
|
if (sink.UpsamplerState != null)
|
||||||
|
|
|
||||||
|
|
@ -37,11 +37,14 @@ 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];
|
||||||
|
|
||||||
|
Span<byte> inputSpan = _parameter.Input.AsSpan();
|
||||||
|
Span<byte> outputSpan = _parameter.Output.AsSpan();
|
||||||
|
|
||||||
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 + inputSpan[i]);
|
||||||
OutputBufferIndices[i] = (ushort)(bufferOffset + _parameter.Output[i]);
|
OutputBufferIndices[i] = (ushort)(bufferOffset + outputSpan[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -48,11 +48,14 @@ 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];
|
||||||
|
|
||||||
|
Span<byte> inputSpan = _parameter.Input.AsSpan();
|
||||||
|
Span<byte> outputSpan = _parameter.Output.AsSpan();
|
||||||
|
|
||||||
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 + inputSpan[i]);
|
||||||
OutputBufferIndices[i] = (ushort)(bufferOffset + _parameter.Output[i]);
|
OutputBufferIndices[i] = (ushort)(bufferOffset + outputSpan[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -150,8 +153,11 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
||||||
{
|
{
|
||||||
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.InputMax[channelIndex] = Math.Max(statistics.InputMax[channelIndex], sampleInputMax);
|
Span<float> inputMaxSpan = statistics.InputMax.AsSpan();
|
||||||
statistics.CompressionGainMin[channelIndex] = Math.Min(statistics.CompressionGainMin[channelIndex], compressionGain);
|
Span<float> compressionGainMinSpan = statistics.CompressionGainMin.AsSpan();
|
||||||
|
|
||||||
|
inputMaxSpan[channelIndex] = Math.Max(inputMaxSpan[channelIndex], sampleInputMax);
|
||||||
|
compressionGainMinSpan[channelIndex] = Math.Min(compressionGainMinSpan[channelIndex], compressionGain);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -79,6 +79,10 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
||||||
|
|
||||||
public void Process(CommandList context)
|
public void Process(CommandList context)
|
||||||
{
|
{
|
||||||
|
ref VoiceUpdateState state = ref State.Span[0];
|
||||||
|
|
||||||
|
Span<float> lastSamplesSpan = state.LastSamples.AsSpan();
|
||||||
|
|
||||||
for (int i = 0; i < MixBufferCount; i++)
|
for (int i = 0; i < MixBufferCount; i++)
|
||||||
{
|
{
|
||||||
ReadOnlySpan<float> inputBuffer = context.GetBuffer(InputBufferIndices[i]);
|
ReadOnlySpan<float> inputBuffer = context.GetBuffer(InputBufferIndices[i]);
|
||||||
|
|
@ -87,15 +91,13 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
||||||
float volume0 = Volume0[i];
|
float volume0 = Volume0[i];
|
||||||
float volume1 = Volume1[i];
|
float volume1 = Volume1[i];
|
||||||
|
|
||||||
ref VoiceUpdateState state = ref State.Span[0];
|
|
||||||
|
|
||||||
if (volume0 != 0 || volume1 != 0)
|
if (volume0 != 0 || volume1 != 0)
|
||||||
{
|
{
|
||||||
state.LastSamples[i] = ProcessMixRampGrouped(outputBuffer, inputBuffer, volume0, volume1, (int)context.SampleCount);
|
lastSamplesSpan[i] = ProcessMixRampGrouped(outputBuffer, inputBuffer, volume0, volume1, (int)context.SampleCount);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
state.LastSamples[i] = 0;
|
lastSamplesSpan[i] = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -42,10 +42,12 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
||||||
Pitch = serverState.Pitch;
|
Pitch = serverState.Pitch;
|
||||||
|
|
||||||
WaveBuffers = new WaveBuffer[Constants.VoiceWaveBufferCount];
|
WaveBuffers = new WaveBuffer[Constants.VoiceWaveBufferCount];
|
||||||
|
|
||||||
|
Span<Server.Voice.WaveBuffer> waveBufferSpan = serverState.WaveBuffers.AsSpan();
|
||||||
|
|
||||||
for (int i = 0; i < WaveBuffers.Length; i++)
|
for (int i = 0; i < WaveBuffers.Length; i++)
|
||||||
{
|
{
|
||||||
ref Server.Voice.WaveBuffer voiceWaveBuffer = ref serverState.WaveBuffers[i];
|
ref Server.Voice.WaveBuffer voiceWaveBuffer = ref waveBufferSpan[i];
|
||||||
|
|
||||||
WaveBuffers[i] = voiceWaveBuffer.ToCommon(1);
|
WaveBuffers[i] = voiceWaveBuffer.ToCommon(1);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -42,10 +42,12 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
||||||
Pitch = serverState.Pitch;
|
Pitch = serverState.Pitch;
|
||||||
|
|
||||||
WaveBuffers = new WaveBuffer[Constants.VoiceWaveBufferCount];
|
WaveBuffers = new WaveBuffer[Constants.VoiceWaveBufferCount];
|
||||||
|
|
||||||
|
Span<Server.Voice.WaveBuffer> waveBufferSpan = serverState.WaveBuffers.AsSpan();
|
||||||
|
|
||||||
for (int i = 0; i < WaveBuffers.Length; i++)
|
for (int i = 0; i < WaveBuffers.Length; i++)
|
||||||
{
|
{
|
||||||
ref Server.Voice.WaveBuffer voiceWaveBuffer = ref serverState.WaveBuffers[i];
|
ref Server.Voice.WaveBuffer voiceWaveBuffer = ref waveBufferSpan[i];
|
||||||
|
|
||||||
WaveBuffers[i] = voiceWaveBuffer.ToCommon(1);
|
WaveBuffers[i] = voiceWaveBuffer.ToCommon(1);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -65,11 +65,14 @@ 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];
|
||||||
|
|
||||||
|
Span<byte> inputSpan = Parameter.Input.AsSpan();
|
||||||
|
Span<byte> outputSpan = Parameter.Output.AsSpan();
|
||||||
|
|
||||||
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 + inputSpan[i]);
|
||||||
OutputBufferIndices[i] = (ushort)(bufferOffset + Parameter.Output[i]);
|
OutputBufferIndices[i] = (ushort)(bufferOffset + outputSpan[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE: We do the opposite as Nintendo here for now to restore previous behaviour
|
// NOTE: We do the opposite as Nintendo here for now to restore previous behaviour
|
||||||
|
|
|
||||||
|
|
@ -63,11 +63,14 @@ 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];
|
||||||
|
|
||||||
|
Span<byte> inputSpan = Parameter.Input.AsSpan();
|
||||||
|
Span<byte> outputSpan = Parameter.Output.AsSpan();
|
||||||
|
|
||||||
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 + inputSpan[i]);
|
||||||
OutputBufferIndices[i] = (ushort)(bufferOffset + Parameter.Output[i]);
|
OutputBufferIndices[i] = (ushort)(bufferOffset + outputSpan[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
IsLongSizePreDelaySupported = isLongSizePreDelaySupported;
|
IsLongSizePreDelaySupported = isLongSizePreDelaySupported;
|
||||||
|
|
|
||||||
|
|
@ -74,7 +74,7 @@ namespace Ryujinx.Audio.Renderer.Dsp
|
||||||
{
|
{
|
||||||
int tempBufferIndex = 0;
|
int tempBufferIndex = 0;
|
||||||
|
|
||||||
if (!info.DecodingBehaviour.HasFlag(DecodingBehaviour.SkipPitchAndSampleRateConversion))
|
if ((info.DecodingBehaviour & DecodingBehaviour.SkipPitchAndSampleRateConversion) != DecodingBehaviour.SkipPitchAndSampleRateConversion)
|
||||||
{
|
{
|
||||||
voiceState.Pitch.AsSpan()[..pitchMaxLength].CopyTo(tempBuffer);
|
voiceState.Pitch.AsSpan()[..pitchMaxLength].CopyTo(tempBuffer);
|
||||||
tempBufferIndex += pitchMaxLength;
|
tempBufferIndex += pitchMaxLength;
|
||||||
|
|
@ -208,7 +208,7 @@ namespace Ryujinx.Audio.Renderer.Dsp
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (info.DecodingBehaviour.HasFlag(DecodingBehaviour.PlayedSampleCountResetWhenLooping))
|
if ((info.DecodingBehaviour & DecodingBehaviour.PlayedSampleCountResetWhenLooping) == DecodingBehaviour.PlayedSampleCountResetWhenLooping)
|
||||||
{
|
{
|
||||||
playedSampleCount = 0;
|
playedSampleCount = 0;
|
||||||
}
|
}
|
||||||
|
|
@ -222,7 +222,7 @@ namespace Ryujinx.Audio.Renderer.Dsp
|
||||||
|
|
||||||
Span<int> outputSpanInt = MemoryMarshal.Cast<float, int>(outputBuffer[i..]);
|
Span<int> outputSpanInt = MemoryMarshal.Cast<float, int>(outputBuffer[i..]);
|
||||||
|
|
||||||
if (info.DecodingBehaviour.HasFlag(DecodingBehaviour.SkipPitchAndSampleRateConversion))
|
if ((info.DecodingBehaviour & DecodingBehaviour.SkipPitchAndSampleRateConversion) == DecodingBehaviour.SkipPitchAndSampleRateConversion)
|
||||||
{
|
{
|
||||||
for (int j = 0; j < y; j++)
|
for (int j = 0; j < y; j++)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -40,11 +40,12 @@ namespace Ryujinx.Audio.Renderer.Dsp
|
||||||
}
|
}
|
||||||
|
|
||||||
Array20<float> result = new();
|
Array20<float> result = new();
|
||||||
|
Span<float> resultSpan = result.AsSpan();
|
||||||
|
|
||||||
for (int i = 0; i < FilterBankLength; i++)
|
for (int i = 0; i < FilterBankLength; i++)
|
||||||
{
|
{
|
||||||
float x = (Bank0CenterIndex - i) + offset;
|
float x = (Bank0CenterIndex - i) + offset;
|
||||||
result[i] = Sinc(x) * BlackmanWindow(x / FilterBankLength + 0.5f);
|
resultSpan[i] = Sinc(x) * BlackmanWindow(x / FilterBankLength + 0.5f);
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
|
|
@ -77,6 +78,9 @@ namespace Ryujinx.Audio.Renderer.Dsp
|
||||||
|
|
||||||
Debug.Assert(state.History.Length == HistoryLength);
|
Debug.Assert(state.History.Length == HistoryLength);
|
||||||
Debug.Assert(bank.Length == FilterBankLength);
|
Debug.Assert(bank.Length == FilterBankLength);
|
||||||
|
|
||||||
|
Span<float> bankSpan = bank.AsSpan();
|
||||||
|
Span<float> historySpan = state.History.AsSpan();
|
||||||
|
|
||||||
int curIdx = 0;
|
int curIdx = 0;
|
||||||
if (Vector.IsHardwareAccelerated)
|
if (Vector.IsHardwareAccelerated)
|
||||||
|
|
@ -87,15 +91,15 @@ namespace Ryujinx.Audio.Renderer.Dsp
|
||||||
while (curIdx < stopIdx)
|
while (curIdx < stopIdx)
|
||||||
{
|
{
|
||||||
result += Vector.Dot(
|
result += Vector.Dot(
|
||||||
new Vector<float>(bank.AsSpan().Slice(curIdx, Vector<float>.Count)),
|
new Vector<float>(bankSpan[curIdx..(curIdx + Vector<float>.Count)]),
|
||||||
new Vector<float>(state.History.AsSpan().Slice(curIdx, Vector<float>.Count)));
|
new Vector<float>(historySpan[curIdx..(curIdx + Vector<float>.Count)]));
|
||||||
curIdx += Vector<float>.Count;
|
curIdx += Vector<float>.Count;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
while (curIdx < FilterBankLength)
|
while (curIdx < FilterBankLength)
|
||||||
{
|
{
|
||||||
result += bank[curIdx] * state.History[curIdx];
|
result += bankSpan[curIdx] * historySpan[curIdx];
|
||||||
curIdx++;
|
curIdx++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -141,18 +141,20 @@ namespace Ryujinx.Audio.Renderer.Server
|
||||||
{
|
{
|
||||||
bool supportsOptimizedPath = _rendererContext.BehaviourContext.UseMultiTapBiquadFilterProcessing();
|
bool supportsOptimizedPath = _rendererContext.BehaviourContext.UseMultiTapBiquadFilterProcessing();
|
||||||
|
|
||||||
if (supportsOptimizedPath && voiceState.BiquadFilters[0].Enable && voiceState.BiquadFilters[1].Enable)
|
Span<BiquadFilterParameter> biquadFiltersSpan = voiceState.BiquadFilters.AsSpan();
|
||||||
|
|
||||||
|
if (supportsOptimizedPath && biquadFiltersSpan[0].Enable && biquadFiltersSpan[1].Enable)
|
||||||
{
|
{
|
||||||
Memory<byte> biquadStateRawMemory = SpanMemoryManager<byte>.Cast(state)[..(Unsafe.SizeOf<BiquadFilterState>() * Constants.VoiceBiquadFilterCount)];
|
Memory<byte> biquadStateRawMemory = SpanMemoryManager<byte>.Cast(state)[..(Unsafe.SizeOf<BiquadFilterState>() * Constants.VoiceBiquadFilterCount)];
|
||||||
Memory<BiquadFilterState> stateMemory = SpanMemoryManager<BiquadFilterState>.Cast(biquadStateRawMemory);
|
Memory<BiquadFilterState> stateMemory = SpanMemoryManager<BiquadFilterState>.Cast(biquadStateRawMemory);
|
||||||
|
|
||||||
_commandBuffer.GenerateMultiTapBiquadFilter(baseIndex, voiceState.BiquadFilters.AsSpan(), stateMemory, bufferOffset, bufferOffset, voiceState.BiquadFilterNeedInitialization, nodeId);
|
_commandBuffer.GenerateMultiTapBiquadFilter(baseIndex, biquadFiltersSpan, stateMemory, bufferOffset, bufferOffset, voiceState.BiquadFilterNeedInitialization, nodeId);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
for (int i = 0; i < voiceState.BiquadFilters.Length; i++)
|
for (int i = 0; i < biquadFiltersSpan.Length; i++)
|
||||||
{
|
{
|
||||||
ref BiquadFilterParameter filter = ref voiceState.BiquadFilters[i];
|
ref BiquadFilterParameter filter = ref biquadFiltersSpan[i];
|
||||||
|
|
||||||
if (filter.Enable)
|
if (filter.Enable)
|
||||||
{
|
{
|
||||||
|
|
@ -311,12 +313,15 @@ namespace Ryujinx.Audio.Renderer.Server
|
||||||
{
|
{
|
||||||
int nodeId = voiceState.NodeId;
|
int nodeId = voiceState.NodeId;
|
||||||
uint channelsCount = voiceState.ChannelsCount;
|
uint channelsCount = voiceState.ChannelsCount;
|
||||||
|
|
||||||
|
Span<int> channelResourceIdsSpan = voiceState.ChannelResourceIds.AsSpan();
|
||||||
|
Span<BiquadFilterParameter> biquadFiltersSpan = voiceState.BiquadFilters.AsSpan();
|
||||||
|
|
||||||
for (int channelIndex = 0; channelIndex < channelsCount; channelIndex++)
|
for (int channelIndex = 0; channelIndex < channelsCount; channelIndex++)
|
||||||
{
|
{
|
||||||
Memory<VoiceUpdateState> dspStateMemory = _voiceContext.GetUpdateStateForDsp(voiceState.ChannelResourceIds[channelIndex]);
|
Memory<VoiceUpdateState> dspStateMemory = _voiceContext.GetUpdateStateForDsp(channelResourceIdsSpan[channelIndex]);
|
||||||
|
|
||||||
ref VoiceChannelResource channelResource = ref _voiceContext.GetChannelResource(voiceState.ChannelResourceIds[channelIndex]);
|
ref VoiceChannelResource channelResource = ref _voiceContext.GetChannelResource(channelResourceIdsSpan[channelIndex]);
|
||||||
|
|
||||||
PerformanceDetailType dataSourceDetailType = PerformanceDetailType.Adpcm;
|
PerformanceDetailType dataSourceDetailType = PerformanceDetailType.Adpcm;
|
||||||
|
|
||||||
|
|
@ -476,7 +481,7 @@ namespace Ryujinx.Audio.Renderer.Server
|
||||||
|
|
||||||
for (int i = 0; i < voiceState.BiquadFilterNeedInitialization.Length; i++)
|
for (int i = 0; i < voiceState.BiquadFilterNeedInitialization.Length; i++)
|
||||||
{
|
{
|
||||||
voiceState.BiquadFilterNeedInitialization[i] = voiceState.BiquadFilters[i].Enable;
|
voiceState.BiquadFilterNeedInitialization[i] = biquadFiltersSpan[i].Enable;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -526,15 +531,19 @@ namespace Ryujinx.Audio.Renderer.Server
|
||||||
|
|
||||||
if (effect.IsEnabled)
|
if (effect.IsEnabled)
|
||||||
{
|
{
|
||||||
|
Span<float> volumesSpan = effect.Parameter.Volumes.AsSpan();
|
||||||
|
Span<byte> inputSpan = effect.Parameter.Input.AsSpan();
|
||||||
|
Span<byte> outputSpan = effect.Parameter.Output.AsSpan();
|
||||||
|
|
||||||
for (int i = 0; i < effect.Parameter.MixesCount; i++)
|
for (int i = 0; i < effect.Parameter.MixesCount; i++)
|
||||||
{
|
{
|
||||||
if (effect.Parameter.Volumes[i] != 0.0f)
|
if (volumesSpan[i] != 0.0f)
|
||||||
{
|
{
|
||||||
_commandBuffer.GenerateMix(
|
_commandBuffer.GenerateMix(
|
||||||
(uint)bufferOffset + effect.Parameter.Input[i],
|
(uint)bufferOffset + inputSpan[i],
|
||||||
(uint)bufferOffset + effect.Parameter.Output[i],
|
(uint)bufferOffset + outputSpan[i],
|
||||||
nodeId,
|
nodeId,
|
||||||
effect.Parameter.Volumes[i]);
|
volumesSpan[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -554,6 +563,10 @@ namespace Ryujinx.Audio.Renderer.Server
|
||||||
{
|
{
|
||||||
int i = 0;
|
int i = 0;
|
||||||
uint writeOffset = 0;
|
uint writeOffset = 0;
|
||||||
|
|
||||||
|
Span<byte> inputSpan = effect.Parameter.Input.AsSpan();
|
||||||
|
Span<byte> outputSpan = effect.Parameter.Output.AsSpan();
|
||||||
|
|
||||||
for (uint channelIndex = effect.Parameter.ChannelCount; channelIndex != 0; channelIndex--)
|
for (uint channelIndex = effect.Parameter.ChannelCount; channelIndex != 0; channelIndex--)
|
||||||
{
|
{
|
||||||
uint newUpdateCount = writeOffset + _commandBuffer.CommandList.SampleCount;
|
uint newUpdateCount = writeOffset + _commandBuffer.CommandList.SampleCount;
|
||||||
|
|
@ -571,8 +584,8 @@ namespace Ryujinx.Audio.Renderer.Server
|
||||||
|
|
||||||
_commandBuffer.GenerateAuxEffect(
|
_commandBuffer.GenerateAuxEffect(
|
||||||
bufferOffset,
|
bufferOffset,
|
||||||
effect.Parameter.Input[i],
|
inputSpan[i],
|
||||||
effect.Parameter.Output[i],
|
outputSpan[i],
|
||||||
ref effect.State,
|
ref effect.State,
|
||||||
effect.IsEnabled,
|
effect.IsEnabled,
|
||||||
effect.Parameter.BufferStorageSize,
|
effect.Parameter.BufferStorageSize,
|
||||||
|
|
@ -619,6 +632,9 @@ namespace Ryujinx.Audio.Renderer.Server
|
||||||
private void GenerateBiquadFilterEffect(uint bufferOffset, BiquadFilterEffect effect, int nodeId)
|
private void GenerateBiquadFilterEffect(uint bufferOffset, BiquadFilterEffect effect, int nodeId)
|
||||||
{
|
{
|
||||||
Debug.Assert(effect.Type == EffectType.BiquadFilter);
|
Debug.Assert(effect.Type == EffectType.BiquadFilter);
|
||||||
|
|
||||||
|
Span<byte> inputSpan = effect.Parameter.Input.AsSpan();
|
||||||
|
Span<byte> outputSpan = effect.Parameter.Output.AsSpan();
|
||||||
|
|
||||||
if (effect.IsEnabled)
|
if (effect.IsEnabled)
|
||||||
{
|
{
|
||||||
|
|
@ -639,8 +655,8 @@ namespace Ryujinx.Audio.Renderer.Server
|
||||||
(int)bufferOffset,
|
(int)bufferOffset,
|
||||||
ref parameter,
|
ref parameter,
|
||||||
effect.State.Slice(i, 1),
|
effect.State.Slice(i, 1),
|
||||||
effect.Parameter.Input[i],
|
inputSpan[i],
|
||||||
effect.Parameter.Output[i],
|
outputSpan[i],
|
||||||
needInitialization,
|
needInitialization,
|
||||||
nodeId);
|
nodeId);
|
||||||
}
|
}
|
||||||
|
|
@ -649,8 +665,8 @@ namespace Ryujinx.Audio.Renderer.Server
|
||||||
{
|
{
|
||||||
for (int i = 0; i < effect.Parameter.ChannelCount; i++)
|
for (int i = 0; i < effect.Parameter.ChannelCount; i++)
|
||||||
{
|
{
|
||||||
uint inputBufferIndex = bufferOffset + effect.Parameter.Input[i];
|
uint inputBufferIndex = bufferOffset + inputSpan[i];
|
||||||
uint outputBufferIndex = bufferOffset + effect.Parameter.Output[i];
|
uint outputBufferIndex = bufferOffset + outputSpan[i];
|
||||||
|
|
||||||
// If the input and output isn't the same, generate a command.
|
// If the input and output isn't the same, generate a command.
|
||||||
if (inputBufferIndex != outputBufferIndex)
|
if (inputBufferIndex != outputBufferIndex)
|
||||||
|
|
@ -701,6 +717,8 @@ namespace Ryujinx.Audio.Renderer.Server
|
||||||
{
|
{
|
||||||
int i = 0;
|
int i = 0;
|
||||||
uint writeOffset = 0;
|
uint writeOffset = 0;
|
||||||
|
|
||||||
|
Span<byte> inputSpan = effect.Parameter.Input.AsSpan();
|
||||||
|
|
||||||
for (uint channelIndex = effect.Parameter.ChannelCount; channelIndex != 0; channelIndex--)
|
for (uint channelIndex = effect.Parameter.ChannelCount; channelIndex != 0; channelIndex--)
|
||||||
{
|
{
|
||||||
|
|
@ -719,7 +737,7 @@ namespace Ryujinx.Audio.Renderer.Server
|
||||||
|
|
||||||
_commandBuffer.GenerateCaptureEffect(
|
_commandBuffer.GenerateCaptureEffect(
|
||||||
bufferOffset,
|
bufferOffset,
|
||||||
effect.Parameter.Input[i],
|
inputSpan[i],
|
||||||
effect.State.SendBufferInfo,
|
effect.State.SendBufferInfo,
|
||||||
effect.IsEnabled,
|
effect.IsEnabled,
|
||||||
effect.Parameter.BufferStorageSize,
|
effect.Parameter.BufferStorageSize,
|
||||||
|
|
|
||||||
|
|
@ -218,7 +218,8 @@ namespace Ryujinx.Audio.Renderer.Server.Splitter
|
||||||
/// <returns>True if any biquad filter is enabled.</returns>
|
/// <returns>True if any biquad filter is enabled.</returns>
|
||||||
public bool IsBiquadFilterEnabled()
|
public bool IsBiquadFilterEnabled()
|
||||||
{
|
{
|
||||||
return _biquadFilters[0].Enable || _biquadFilters[1].Enable;
|
Span<BiquadFilterParameter> biquadFiltersSpan = _biquadFilters.AsSpan();
|
||||||
|
return biquadFiltersSpan[0].Enable || biquadFiltersSpan[1].Enable;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
|
||||||
|
|
@ -162,9 +162,11 @@ namespace Ryujinx.Audio.Renderer.Server
|
||||||
{
|
{
|
||||||
ref VoiceState currentVoiceState = ref context.GetState(i);
|
ref VoiceState currentVoiceState = ref context.GetState(i);
|
||||||
|
|
||||||
|
Span<int> channelResourceIdsSpan = parameter.ChannelResourceIds.AsSpan();
|
||||||
|
|
||||||
for (int channelResourceIndex = 0; channelResourceIndex < parameter.ChannelCount; channelResourceIndex++)
|
for (int channelResourceIndex = 0; channelResourceIndex < parameter.ChannelCount; channelResourceIndex++)
|
||||||
{
|
{
|
||||||
int channelId = parameter.ChannelResourceIds[channelResourceIndex];
|
int channelId = channelResourceIdsSpan[channelResourceIndex];
|
||||||
|
|
||||||
Debug.Assert(channelId >= 0 && channelId < context.GetCount());
|
Debug.Assert(channelId >= 0 && channelId < context.GetCount());
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -126,9 +126,9 @@ namespace Ryujinx.Audio.Renderer.Server.Voice
|
||||||
_sortedVoices.Span[i] = i;
|
_sortedVoices.Span[i] = i;
|
||||||
}
|
}
|
||||||
|
|
||||||
int[] sortedVoicesTemp = _sortedVoices[..(int)GetCount()].ToArray();
|
Span<int> sortedVoicesTemp = _sortedVoices[..(int)_voiceCount].Span;
|
||||||
|
|
||||||
Array.Sort(sortedVoicesTemp, (a, b) =>
|
sortedVoicesTemp.Sort((a, b) =>
|
||||||
{
|
{
|
||||||
ref VoiceState aState = ref GetState(a);
|
ref VoiceState aState = ref GetState(a);
|
||||||
ref VoiceState bState = ref GetState(b);
|
ref VoiceState bState = ref GetState(b);
|
||||||
|
|
@ -143,7 +143,7 @@ namespace Ryujinx.Audio.Renderer.Server.Voice
|
||||||
return result;
|
return result;
|
||||||
});
|
});
|
||||||
|
|
||||||
sortedVoicesTemp.AsSpan().CopyTo(_sortedVoices.Span);
|
// sortedVoicesTemp.CopyTo(_sortedVoices.Span);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -219,15 +219,17 @@ namespace Ryujinx.Audio.Renderer.Server.Voice
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private void InitializeWaveBuffers()
|
private void InitializeWaveBuffers()
|
||||||
{
|
{
|
||||||
for (int i = 0; i < WaveBuffers.Length; i++)
|
Span<WaveBuffer> waveBuffersSpan = WaveBuffers.AsSpan();
|
||||||
|
|
||||||
|
for (int i = 0; i < waveBuffersSpan.Length; i++)
|
||||||
{
|
{
|
||||||
WaveBuffers[i].StartSampleOffset = 0;
|
waveBuffersSpan[i].StartSampleOffset = 0;
|
||||||
WaveBuffers[i].EndSampleOffset = 0;
|
waveBuffersSpan[i].EndSampleOffset = 0;
|
||||||
WaveBuffers[i].ShouldLoop = false;
|
waveBuffersSpan[i].ShouldLoop = false;
|
||||||
WaveBuffers[i].IsEndOfStream = false;
|
waveBuffersSpan[i].IsEndOfStream = false;
|
||||||
WaveBuffers[i].BufferAddressInfo.Setup(0, 0);
|
waveBuffersSpan[i].BufferAddressInfo.Setup(0, 0);
|
||||||
WaveBuffers[i].ContextAddressInfo.Setup(0, 0);
|
waveBuffersSpan[i].ContextAddressInfo.Setup(0, 0);
|
||||||
WaveBuffers[i].IsSendToAudioProcessor = true;
|
waveBuffersSpan[i].IsSendToAudioProcessor = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -446,10 +448,13 @@ namespace Ryujinx.Audio.Renderer.Server.Voice
|
||||||
}
|
}
|
||||||
|
|
||||||
ref VoiceUpdateState voiceUpdateState = ref voiceUpdateStates[0].Span[0];
|
ref VoiceUpdateState voiceUpdateState = ref voiceUpdateStates[0].Span[0];
|
||||||
|
|
||||||
|
Span<WaveBuffer> waveBuffersSpan = WaveBuffers.AsSpan();
|
||||||
|
Span<WaveBufferInternal> pWaveBuffersSpan = parameter.WaveBuffers.AsSpan();
|
||||||
|
|
||||||
for (int i = 0; i < Constants.VoiceWaveBufferCount; i++)
|
for (int i = 0; i < Constants.VoiceWaveBufferCount; i++)
|
||||||
{
|
{
|
||||||
UpdateWaveBuffer(errorInfos.AsSpan(i * 2, 2), ref WaveBuffers[i], ref parameter.WaveBuffers[i], parameter.SampleFormat, voiceUpdateState.IsWaveBufferValid[i], mapper, ref behaviourContext);
|
UpdateWaveBuffer(errorInfos.AsSpan(i * 2, 2), ref waveBuffersSpan[i], ref pWaveBuffersSpan[i], parameter.SampleFormat, voiceUpdateState.IsWaveBufferValid[i], mapper, ref behaviourContext);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -534,9 +539,11 @@ namespace Ryujinx.Audio.Renderer.Server.Voice
|
||||||
/// <param name="context">The voice context.</param>
|
/// <param name="context">The voice context.</param>
|
||||||
private void ResetResources(VoiceContext context)
|
private void ResetResources(VoiceContext context)
|
||||||
{
|
{
|
||||||
|
Span<int> channelResourceIdsSpan = ChannelResourceIds.AsSpan();
|
||||||
|
|
||||||
for (int i = 0; i < ChannelsCount; i++)
|
for (int i = 0; i < ChannelsCount; i++)
|
||||||
{
|
{
|
||||||
int channelResourceId = ChannelResourceIds[i];
|
int channelResourceId = channelResourceIdsSpan[i];
|
||||||
|
|
||||||
ref VoiceChannelResource voiceChannelResource = ref context.GetChannelResource(channelResourceId);
|
ref VoiceChannelResource voiceChannelResource = ref context.GetChannelResource(channelResourceId);
|
||||||
|
|
||||||
|
|
@ -559,10 +566,12 @@ namespace Ryujinx.Audio.Renderer.Server.Voice
|
||||||
private void FlushWaveBuffers(uint waveBufferCount, Memory<VoiceUpdateState>[] voiceUpdateStates, uint channelCount)
|
private void FlushWaveBuffers(uint waveBufferCount, Memory<VoiceUpdateState>[] voiceUpdateStates, uint channelCount)
|
||||||
{
|
{
|
||||||
uint waveBufferIndex = WaveBuffersIndex;
|
uint waveBufferIndex = WaveBuffersIndex;
|
||||||
|
|
||||||
|
Span<WaveBuffer> waveBuffersSpan = WaveBuffers.AsSpan();
|
||||||
|
|
||||||
for (int i = 0; i < waveBufferCount; i++)
|
for (int i = 0; i < waveBufferCount; i++)
|
||||||
{
|
{
|
||||||
WaveBuffers[(int)waveBufferIndex].IsSendToAudioProcessor = true;
|
waveBuffersSpan[(int)waveBufferIndex].IsSendToAudioProcessor = true;
|
||||||
|
|
||||||
for (int j = 0; j < channelCount; j++)
|
for (int j = 0; j < channelCount; j++)
|
||||||
{
|
{
|
||||||
|
|
@ -591,14 +600,18 @@ namespace Ryujinx.Audio.Renderer.Server.Voice
|
||||||
FlushWaveBufferCount = 0;
|
FlushWaveBufferCount = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Span<WaveBuffer> waveBuffersSpan;
|
||||||
|
|
||||||
switch (PlayState)
|
switch (PlayState)
|
||||||
{
|
{
|
||||||
case PlayState.Started:
|
case PlayState.Started:
|
||||||
for (int i = 0; i < WaveBuffers.Length; i++)
|
waveBuffersSpan = WaveBuffers.AsSpan();
|
||||||
|
|
||||||
|
for (int i = 0; i < waveBuffersSpan.Length; i++)
|
||||||
{
|
{
|
||||||
ref WaveBuffer wavebuffer = ref WaveBuffers[i];
|
ref WaveBuffer waveBuffer = ref waveBuffersSpan[i];
|
||||||
|
|
||||||
if (!wavebuffer.IsSendToAudioProcessor)
|
if (!waveBuffer.IsSendToAudioProcessor)
|
||||||
{
|
{
|
||||||
for (int y = 0; y < ChannelsCount; y++)
|
for (int y = 0; y < ChannelsCount; y++)
|
||||||
{
|
{
|
||||||
|
|
@ -607,7 +620,7 @@ namespace Ryujinx.Audio.Renderer.Server.Voice
|
||||||
voiceUpdateStates[y].Span[0].IsWaveBufferValid[i] = true;
|
voiceUpdateStates[y].Span[0].IsWaveBufferValid[i] = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
wavebuffer.IsSendToAudioProcessor = true;
|
waveBuffer.IsSendToAudioProcessor = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -626,11 +639,13 @@ namespace Ryujinx.Audio.Renderer.Server.Voice
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
case PlayState.Stopping:
|
case PlayState.Stopping:
|
||||||
for (int i = 0; i < WaveBuffers.Length; i++)
|
waveBuffersSpan = WaveBuffers.AsSpan();
|
||||||
|
|
||||||
|
for (int i = 0; i < waveBuffersSpan.Length; i++)
|
||||||
{
|
{
|
||||||
ref WaveBuffer wavebuffer = ref WaveBuffers[i];
|
ref WaveBuffer waveBuffer = ref waveBuffersSpan[i];
|
||||||
|
|
||||||
wavebuffer.IsSendToAudioProcessor = true;
|
waveBuffer.IsSendToAudioProcessor = true;
|
||||||
|
|
||||||
for (int j = 0; j < ChannelsCount; j++)
|
for (int j = 0; j < ChannelsCount; j++)
|
||||||
{
|
{
|
||||||
|
|
@ -702,9 +717,11 @@ namespace Ryujinx.Audio.Renderer.Server.Voice
|
||||||
|
|
||||||
Memory<VoiceUpdateState>[] voiceUpdateStates = new Memory<VoiceUpdateState>[Constants.VoiceChannelCountMax];
|
Memory<VoiceUpdateState>[] voiceUpdateStates = new Memory<VoiceUpdateState>[Constants.VoiceChannelCountMax];
|
||||||
|
|
||||||
|
Span<int> channelResourceIdsSpan = ChannelResourceIds.AsSpan();
|
||||||
|
|
||||||
for (int i = 0; i < ChannelsCount; i++)
|
for (int i = 0; i < ChannelsCount; i++)
|
||||||
{
|
{
|
||||||
voiceUpdateStates[i] = context.GetUpdateStateForDsp(ChannelResourceIds[i]);
|
voiceUpdateStates[i] = context.GetUpdateStateForDsp(channelResourceIdsSpan[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
return UpdateParametersForCommandGeneration(voiceUpdateStates);
|
return UpdateParametersForCommandGeneration(voiceUpdateStates);
|
||||||
|
|
|
||||||
|
|
@ -129,7 +129,6 @@ namespace Ryujinx.Common.Collections
|
||||||
if (parent.Predecessor != null)
|
if (parent.Predecessor != null)
|
||||||
{
|
{
|
||||||
newNode.Predecessor = parent.Predecessor;
|
newNode.Predecessor = parent.Predecessor;
|
||||||
parent.Predecessor = newNode;
|
|
||||||
newNode.Predecessor.Successor = newNode;
|
newNode.Predecessor.Successor = newNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
using System;
|
||||||
|
|
||||||
namespace Ryujinx.Common.Memory
|
namespace Ryujinx.Common.Memory
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -17,5 +19,10 @@ namespace Ryujinx.Common.Memory
|
||||||
/// Number of elements on the array.
|
/// Number of elements on the array.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
int Length { get; }
|
int Length { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Number of elements on the array.
|
||||||
|
/// </summary>
|
||||||
|
public Span<T> AsSpan();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
#nullable enable
|
#nullable enable
|
||||||
using System;
|
using System;
|
||||||
using System.Buffers;
|
using System.Buffers;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics.CodeAnalysis;
|
using System.Diagnostics.CodeAnalysis;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
|
@ -10,11 +11,126 @@ namespace Ryujinx.Common.Memory
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// An <see cref="IMemoryOwner{T}"/> implementation with an embedded length and fast <see cref="Span{T}"/>
|
/// An <see cref="IMemoryOwner{T}"/> implementation with an embedded length and fast <see cref="Span{T}"/>
|
||||||
/// accessor, with memory allocated from <seealso cref="ArrayPool{T}.Shared"/>.
|
/// accessor, with memory allocated from <see cref="ArrayPooling"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <typeparam name="T">The type of item to store.</typeparam>
|
/// <typeparam name="T">The type of item to store.</typeparam>
|
||||||
public sealed class MemoryOwner<T> : IMemoryOwner<T>
|
public sealed class MemoryOwner<T> : IMemoryOwner<T>
|
||||||
{
|
{
|
||||||
|
private static class ArrayPooling
|
||||||
|
{
|
||||||
|
public class Holder(T[]? array = null) : IComparable<Holder>, IComparable<int>
|
||||||
|
{
|
||||||
|
public int SkipCount;
|
||||||
|
public readonly T[]? Array = array;
|
||||||
|
|
||||||
|
public int CompareTo(Holder? other)
|
||||||
|
{
|
||||||
|
return Array!.Length.CompareTo(other!.Array!.Length);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int CompareTo(int other)
|
||||||
|
{
|
||||||
|
int self = Array!.Length;
|
||||||
|
|
||||||
|
if (self < other)
|
||||||
|
{
|
||||||
|
SkipCount++;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (self > other * 4)
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReSharper disable once StaticMemberInGenericType
|
||||||
|
private static int _maxCacheCount = 50;
|
||||||
|
|
||||||
|
private const int MaxSkipCount = 50;
|
||||||
|
|
||||||
|
static readonly List<Holder> _pool = new();
|
||||||
|
|
||||||
|
// ReSharper disable once StaticMemberInGenericType
|
||||||
|
static readonly Lock _lock = new();
|
||||||
|
|
||||||
|
private static int BinarySearch(List<Holder> list, int size)
|
||||||
|
{
|
||||||
|
int min = 0;
|
||||||
|
int max = list.Count-1;
|
||||||
|
|
||||||
|
while (min <= max)
|
||||||
|
{
|
||||||
|
int mid = (min + max) / 2;
|
||||||
|
int comparison = list[mid].CompareTo(size);
|
||||||
|
if (comparison == 0)
|
||||||
|
{
|
||||||
|
return mid;
|
||||||
|
}
|
||||||
|
if (comparison < 0)
|
||||||
|
{
|
||||||
|
min = mid+1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
max = mid-1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ~min;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static T[] Get(int minimumSize)
|
||||||
|
{
|
||||||
|
lock (_lock)
|
||||||
|
{
|
||||||
|
int index = BinarySearch(_pool, minimumSize);
|
||||||
|
|
||||||
|
if (index >= 0)
|
||||||
|
{
|
||||||
|
Holder holder = _pool[index];
|
||||||
|
|
||||||
|
_pool.Remove(holder);
|
||||||
|
return holder.Array!;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new T[minimumSize];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Return(T[] array)
|
||||||
|
{
|
||||||
|
|
||||||
|
lock (_lock)
|
||||||
|
{
|
||||||
|
Holder holder = new(array);
|
||||||
|
int i = _pool.BinarySearch(holder);
|
||||||
|
if (i < 0)
|
||||||
|
{
|
||||||
|
_pool.Insert(~i, holder);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_pool.Count >= _maxCacheCount)
|
||||||
|
{
|
||||||
|
for (int index = 0; index < _pool.Count; index++)
|
||||||
|
{
|
||||||
|
Holder h = _pool[index];
|
||||||
|
|
||||||
|
if (h.SkipCount >= MaxSkipCount)
|
||||||
|
{
|
||||||
|
_pool.Remove(h);
|
||||||
|
index--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_maxCacheCount = _pool.Count * 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private readonly int _length;
|
private readonly int _length;
|
||||||
private T[]? _array;
|
private T[]? _array;
|
||||||
|
|
||||||
|
|
@ -25,7 +141,7 @@ namespace Ryujinx.Common.Memory
|
||||||
private MemoryOwner(int length)
|
private MemoryOwner(int length)
|
||||||
{
|
{
|
||||||
_length = length;
|
_length = length;
|
||||||
_array = ArrayPool<T>.Shared.Rent(length);
|
_array = ArrayPooling.Get(length);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -124,7 +240,7 @@ namespace Ryujinx.Common.Memory
|
||||||
|
|
||||||
if (array is not null)
|
if (array is not null)
|
||||||
{
|
{
|
||||||
ArrayPool<T>.Shared.Return(array, RuntimeHelpers.IsReferenceOrContainsReferences<T>());
|
ArrayPooling.Return(array);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
using System;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using static Ryujinx.Common.Memory.PartialUnmaps.PartialUnmapHelpers;
|
using static Ryujinx.Common.Memory.PartialUnmaps.PartialUnmapHelpers;
|
||||||
|
|
@ -42,10 +43,13 @@ namespace Ryujinx.Common.Memory.PartialUnmaps
|
||||||
public int GetOrReserve(int threadId, T initial)
|
public int GetOrReserve(int threadId, T initial)
|
||||||
{
|
{
|
||||||
// Try get a match first.
|
// Try get a match first.
|
||||||
|
|
||||||
|
Span<int> threadIdsSpan = ThreadIds.AsSpan();
|
||||||
|
Span<T> structsSpan = Structs.AsSpan();
|
||||||
|
|
||||||
for (int i = 0; i < MapSize; i++)
|
for (int i = 0; i < MapSize; i++)
|
||||||
{
|
{
|
||||||
int compare = Interlocked.CompareExchange(ref ThreadIds[i], threadId, threadId);
|
int compare = Interlocked.CompareExchange(ref threadIdsSpan[i], threadId, threadId);
|
||||||
|
|
||||||
if (compare == threadId)
|
if (compare == threadId)
|
||||||
{
|
{
|
||||||
|
|
@ -57,11 +61,11 @@ namespace Ryujinx.Common.Memory.PartialUnmaps
|
||||||
|
|
||||||
for (int i = 0; i < MapSize; i++)
|
for (int i = 0; i < MapSize; i++)
|
||||||
{
|
{
|
||||||
int compare = Interlocked.CompareExchange(ref ThreadIds[i], threadId, 0);
|
int compare = Interlocked.CompareExchange(ref threadIdsSpan[i], threadId, 0);
|
||||||
|
|
||||||
if (compare == 0)
|
if (compare == 0)
|
||||||
{
|
{
|
||||||
Structs[i] = initial;
|
structsSpan[i] = initial;
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -219,13 +219,14 @@ namespace Ryujinx.Graphics.Gpu.Engine.MME
|
||||||
state.Write(LogicOpOffset, 0);
|
state.Write(LogicOpOffset, 0);
|
||||||
|
|
||||||
Array8<Boolean32> enable = new();
|
Array8<Boolean32> enable = new();
|
||||||
|
Span<Boolean32> enableSpan = enable.AsSpan();
|
||||||
|
|
||||||
for (int i = 0; i < 8; i++)
|
for (int i = 0; i < 8; i++)
|
||||||
{
|
{
|
||||||
enable[i] = new Boolean32((uint)(arg0 >> (i + 8)) & 1);
|
enableSpan[i] = new Boolean32((uint)(arg0 >> (i + 8)) & 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
_processor.ThreedClass.UpdateBlendEnable(ref enable);
|
_processor.ThreedClass.UpdateBlendEnable(enableSpan);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -236,13 +237,14 @@ namespace Ryujinx.Graphics.Gpu.Engine.MME
|
||||||
private void UpdateColorMasks(IDeviceState state, int arg0)
|
private void UpdateColorMasks(IDeviceState state, int arg0)
|
||||||
{
|
{
|
||||||
Array8<RtColorMask> masks = new();
|
Array8<RtColorMask> masks = new();
|
||||||
|
Span<RtColorMask> masksSpan = masks.AsSpan();
|
||||||
|
|
||||||
int index = 0;
|
int index = 0;
|
||||||
|
|
||||||
for (int i = 0; i < 4; i++)
|
for (int i = 0; i < 4; i++)
|
||||||
{
|
{
|
||||||
masks[index++] = new RtColorMask((uint)arg0 & 0x1fff);
|
masksSpan[index++] = new RtColorMask((uint)arg0 & 0x1fff);
|
||||||
masks[index++] = new RtColorMask(((uint)arg0 >> 16) & 0x1fff);
|
masksSpan[index++] = new RtColorMask(((uint)arg0 >> 16) & 0x1fff);
|
||||||
|
|
||||||
if (i != 3)
|
if (i != 3)
|
||||||
{
|
{
|
||||||
|
|
@ -250,7 +252,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.MME
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_processor.ThreedClass.UpdateColorMasks(ref masks);
|
_processor.ThreedClass.UpdateColorMasks(masksSpan);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
|
||||||
|
|
@ -75,10 +75,12 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed.Blender
|
||||||
{
|
{
|
||||||
bool constantsMatch = true;
|
bool constantsMatch = true;
|
||||||
|
|
||||||
|
Span<RgbHalf> blendUcodeConstantsSpan = _state.State.BlendUcodeConstants.AsSpan();
|
||||||
|
|
||||||
for (int i = 0; i < entry.Constants.Length; i++)
|
for (int i = 0; i < entry.Constants.Length; i++)
|
||||||
{
|
{
|
||||||
RgbFloat constant = entry.Constants[i];
|
RgbFloat constant = entry.Constants[i];
|
||||||
RgbHalf constant2 = _state.State.BlendUcodeConstants[i];
|
RgbHalf constant2 = blendUcodeConstantsSpan[i];
|
||||||
|
|
||||||
if ((Half)constant.R != constant2.UnpackR() ||
|
if ((Half)constant.R != constant2.UnpackR() ||
|
||||||
(Half)constant.G != constant2.UnpackG() ||
|
(Half)constant.G != constant2.UnpackG() ||
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
using Ryujinx.Graphics.GAL;
|
using Ryujinx.Graphics.GAL;
|
||||||
using Ryujinx.Graphics.Gpu.Memory;
|
using Ryujinx.Graphics.Gpu.Memory;
|
||||||
using Ryujinx.Graphics.Shader;
|
using Ryujinx.Graphics.Shader;
|
||||||
|
using System;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
|
@ -76,9 +77,11 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed.ComputeDraw
|
||||||
/// <param name="componentCount">Number of components that the format has</param>
|
/// <param name="componentCount">Number of components that the format has</param>
|
||||||
public void SetVertexStride(int index, int stride, int componentCount)
|
public void SetVertexStride(int index, int stride, int componentCount)
|
||||||
{
|
{
|
||||||
if (_data.VertexStrides[index].X != stride)
|
Span<Vector4<int>> vertexStridesSpan = _data.VertexStrides.AsSpan();
|
||||||
|
|
||||||
|
if (vertexStridesSpan[index].X != stride)
|
||||||
{
|
{
|
||||||
_data.VertexStrides[index].X = stride;
|
vertexStridesSpan[index].X = stride;
|
||||||
MarkDirty(VertexInfoBuffer.VertexStridesOffset + index * Unsafe.SizeOf<Vector4<int>>(), sizeof(int));
|
MarkDirty(VertexInfoBuffer.VertexStridesOffset + index * Unsafe.SizeOf<Vector4<int>>(), sizeof(int));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -86,7 +89,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed.ComputeDraw
|
||||||
{
|
{
|
||||||
int value = c < componentCount ? 1 : 0;
|
int value = c < componentCount ? 1 : 0;
|
||||||
|
|
||||||
ref int currentValue = ref GetElementRef(ref _data.VertexStrides[index], c);
|
ref int currentValue = ref GetElementRef(ref vertexStridesSpan[index], c);
|
||||||
|
|
||||||
if (currentValue != value)
|
if (currentValue != value)
|
||||||
{
|
{
|
||||||
|
|
@ -104,15 +107,17 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed.ComputeDraw
|
||||||
/// <param name="divisor">If the draw is instanced, should have the vertex divisor value, otherwise should be zero</param>
|
/// <param name="divisor">If the draw is instanced, should have the vertex divisor value, otherwise should be zero</param>
|
||||||
public void SetVertexOffset(int index, int offset, int divisor)
|
public void SetVertexOffset(int index, int offset, int divisor)
|
||||||
{
|
{
|
||||||
if (_data.VertexOffsets[index].X != offset)
|
Span<Vector4<int>> vertexOffsetsSpan = _data.VertexOffsets.AsSpan();
|
||||||
|
|
||||||
|
if (vertexOffsetsSpan[index].X != offset)
|
||||||
{
|
{
|
||||||
_data.VertexOffsets[index].X = offset;
|
vertexOffsetsSpan[index].X = offset;
|
||||||
MarkDirty(VertexInfoBuffer.VertexOffsetsOffset + index * Unsafe.SizeOf<Vector4<int>>(), sizeof(int));
|
MarkDirty(VertexInfoBuffer.VertexOffsetsOffset + index * Unsafe.SizeOf<Vector4<int>>(), sizeof(int));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_data.VertexOffsets[index].Y != divisor)
|
if (vertexOffsetsSpan[index].Y != divisor)
|
||||||
{
|
{
|
||||||
_data.VertexOffsets[index].Y = divisor;
|
vertexOffsetsSpan[index].Y = divisor;
|
||||||
MarkDirty(VertexInfoBuffer.VertexOffsetsOffset + index * Unsafe.SizeOf<Vector4<int>>() + sizeof(int), sizeof(int));
|
MarkDirty(VertexInfoBuffer.VertexOffsetsOffset + index * Unsafe.SizeOf<Vector4<int>>() + sizeof(int), sizeof(int));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -125,9 +125,14 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed.ComputeDraw
|
||||||
_vacContext.VertexInfoBufferUpdater.SetVertexCounts(_count, _instanceCount, _firstVertex, _firstInstance);
|
_vacContext.VertexInfoBufferUpdater.SetVertexCounts(_count, _instanceCount, _firstVertex, _firstInstance);
|
||||||
_vacContext.VertexInfoBufferUpdater.SetGeometryCounts(primitivesCount);
|
_vacContext.VertexInfoBufferUpdater.SetGeometryCounts(primitivesCount);
|
||||||
|
|
||||||
|
Span<VertexAttribState> vertexAttribStateSpan = _state.State.VertexAttribState.AsSpan();
|
||||||
|
Span<GpuVa> vertexBufferEndAddressSpan = _state.State.VertexBufferEndAddress.AsSpan();
|
||||||
|
Span<VertexBufferState> vertexBufferStateSpan = _state.State.VertexBufferState.AsSpan();
|
||||||
|
Span<Boolean32> vertexBufferInstancedSpan = _state.State.VertexBufferInstanced.AsSpan();
|
||||||
|
|
||||||
for (int index = 0; index < Constants.TotalVertexAttribs; index++)
|
for (int index = 0; index < Constants.TotalVertexAttribs; index++)
|
||||||
{
|
{
|
||||||
var vertexAttrib = _state.State.VertexAttribState[index];
|
var vertexAttrib = vertexAttribStateSpan[index];
|
||||||
|
|
||||||
if (!FormatTable.TryGetSingleComponentAttribFormat(vertexAttrib.UnpackFormat(), out Format format, out int componentsCount))
|
if (!FormatTable.TryGetSingleComponentAttribFormat(vertexAttrib.UnpackFormat(), out Format format, out int componentsCount))
|
||||||
{
|
{
|
||||||
|
|
@ -153,9 +158,9 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed.ComputeDraw
|
||||||
|
|
||||||
int bufferIndex = vertexAttrib.UnpackBufferIndex();
|
int bufferIndex = vertexAttrib.UnpackBufferIndex();
|
||||||
|
|
||||||
GpuVa endAddress = _state.State.VertexBufferEndAddress[bufferIndex];
|
GpuVa endAddress = vertexBufferEndAddressSpan[bufferIndex];
|
||||||
var vertexBuffer = _state.State.VertexBufferState[bufferIndex];
|
var vertexBuffer = vertexBufferStateSpan[bufferIndex];
|
||||||
bool instanced = _state.State.VertexBufferInstanced[bufferIndex];
|
bool instanced = vertexBufferInstancedSpan[bufferIndex];
|
||||||
|
|
||||||
ulong address = vertexBuffer.Address.Pack();
|
ulong address = vertexBuffer.Address.Pack();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -821,6 +821,8 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||||
// on the screen scissor state, then we need to force only one texture to be bound to avoid
|
// on the screen scissor state, then we need to force only one texture to be bound to avoid
|
||||||
// host clipping.
|
// host clipping.
|
||||||
var screenScissorState = _state.State.ScreenScissorState;
|
var screenScissorState = _state.State.ScreenScissorState;
|
||||||
|
|
||||||
|
Span<ScissorState> scissorStateSpan = _state.State.ScissorState.AsSpan();
|
||||||
|
|
||||||
bool clearAffectedByStencilMask = (_state.State.ClearFlags & 1) != 0;
|
bool clearAffectedByStencilMask = (_state.State.ClearFlags & 1) != 0;
|
||||||
bool clearAffectedByScissor = (_state.State.ClearFlags & 0x100) != 0;
|
bool clearAffectedByScissor = (_state.State.ClearFlags & 0x100) != 0;
|
||||||
|
|
@ -831,9 +833,9 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||||
|
|
||||||
bool fullClear = screenScissorState.X == 0 && screenScissorState.Y == 0;
|
bool fullClear = screenScissorState.X == 0 && screenScissorState.Y == 0;
|
||||||
|
|
||||||
if (fullClear && clearAffectedByScissor && _state.State.ScissorState[0].Enable)
|
if (fullClear && clearAffectedByScissor && scissorStateSpan[0].Enable)
|
||||||
{
|
{
|
||||||
ref var scissorState = ref _state.State.ScissorState[0];
|
ref var scissorState = ref scissorStateSpan[0];
|
||||||
|
|
||||||
fullClear = scissorState.X1 == screenScissorState.X &&
|
fullClear = scissorState.X1 == screenScissorState.X &&
|
||||||
scissorState.Y1 == screenScissorState.Y &&
|
scissorState.Y1 == screenScissorState.Y &&
|
||||||
|
|
@ -892,9 +894,9 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||||
int scissorW = screenScissorState.Width;
|
int scissorW = screenScissorState.Width;
|
||||||
int scissorH = screenScissorState.Height;
|
int scissorH = screenScissorState.Height;
|
||||||
|
|
||||||
if (clearAffectedByScissor && _state.State.ScissorState[0].Enable)
|
if (clearAffectedByScissor && scissorStateSpan[0].Enable)
|
||||||
{
|
{
|
||||||
ref var scissorState = ref _state.State.ScissorState[0];
|
ref var scissorState = ref scissorStateSpan[0];
|
||||||
|
|
||||||
scissorX = Math.Max(scissorX, scissorState.X1);
|
scissorX = Math.Max(scissorX, scissorState.X1);
|
||||||
scissorY = Math.Max(scissorY, scissorState.Y1);
|
scissorY = Math.Max(scissorY, scissorState.Y1);
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ using Ryujinx.Graphics.GAL;
|
||||||
using Ryujinx.Graphics.Gpu.Engine.Types;
|
using Ryujinx.Graphics.Gpu.Engine.Types;
|
||||||
using Ryujinx.Graphics.Gpu.Shader;
|
using Ryujinx.Graphics.Gpu.Shader;
|
||||||
using Ryujinx.Graphics.Shader;
|
using Ryujinx.Graphics.Shader;
|
||||||
|
using System;
|
||||||
|
|
||||||
namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||||
{
|
{
|
||||||
|
|
@ -214,10 +215,11 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||||
/// Updates the type of the vertex attributes consumed by the shader.
|
/// Updates the type of the vertex attributes consumed by the shader.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="state">The new state</param>
|
/// <param name="state">The new state</param>
|
||||||
public void SetAttributeTypes(ref Array32<VertexAttribState> state)
|
public void SetAttributeTypes(ReadOnlySpan<VertexAttribState> state)
|
||||||
{
|
{
|
||||||
bool changed = false;
|
bool changed = false;
|
||||||
ref Array32<AttributeType> attributeTypes = ref _graphics.AttributeTypes;
|
// ref Array32<AttributeType> attributeTypes = ref _graphics.AttributeTypes;
|
||||||
|
Span<AttributeType> attributeTypesSpan = _graphics.AttributeTypes.AsSpan();
|
||||||
bool mayConvertVtgToCompute = ShaderCache.MayConvertVtgToCompute(ref _context.Capabilities);
|
bool mayConvertVtgToCompute = ShaderCache.MayConvertVtgToCompute(ref _context.Capabilities);
|
||||||
bool supportsScaledFormats = _context.Capabilities.SupportsScaledVertexFormats && !mayConvertVtgToCompute;
|
bool supportsScaledFormats = _context.Capabilities.SupportsScaledVertexFormats && !mayConvertVtgToCompute;
|
||||||
|
|
||||||
|
|
@ -261,9 +263,9 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (attributeTypes[location] != value)
|
if (attributeTypesSpan[location] != value)
|
||||||
{
|
{
|
||||||
attributeTypes[location] = value;
|
attributeTypesSpan[location] = value;
|
||||||
changed = true;
|
changed = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -279,10 +281,12 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="rtControl">The render target control register</param>
|
/// <param name="rtControl">The render target control register</param>
|
||||||
/// <param name="state">The color attachment state</param>
|
/// <param name="state">The color attachment state</param>
|
||||||
public void SetFragmentOutputTypes(RtControl rtControl, ref Array8<RtColorState> state)
|
public void SetFragmentOutputTypes(RtControl rtControl, ReadOnlySpan<RtColorState> state)
|
||||||
{
|
{
|
||||||
bool changed = false;
|
bool changed = false;
|
||||||
int count = rtControl.UnpackCount();
|
int count = rtControl.UnpackCount();
|
||||||
|
|
||||||
|
Span<AttributeType> fragmentOutputTypesSpan = _graphics.FragmentOutputTypes.AsSpan();
|
||||||
|
|
||||||
for (int index = 0; index < Constants.TotalRenderTargets; index++)
|
for (int index = 0; index < Constants.TotalRenderTargets; index++)
|
||||||
{
|
{
|
||||||
|
|
@ -296,9 +300,9 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||||
|
|
||||||
AttributeType type = format.IsInteger() ? (format.IsSint() ? AttributeType.Sint : AttributeType.Uint) : AttributeType.Float;
|
AttributeType type = format.IsInteger() ? (format.IsSint() ? AttributeType.Sint : AttributeType.Uint) : AttributeType.Float;
|
||||||
|
|
||||||
if (type != _graphics.FragmentOutputTypes[index])
|
if (type != fragmentOutputTypesSpan[index])
|
||||||
{
|
{
|
||||||
_graphics.FragmentOutputTypes[index] = type;
|
fragmentOutputTypesSpan[index] = type;
|
||||||
changed = true;
|
changed = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -422,9 +422,11 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private void UpdateTfBufferState()
|
private void UpdateTfBufferState()
|
||||||
{
|
{
|
||||||
|
Span<TfBufferState> tfBufferStateSpan = _state.State.TfBufferState.AsSpan();
|
||||||
|
|
||||||
for (int index = 0; index < Constants.TotalTransformFeedbackBuffers; index++)
|
for (int index = 0; index < Constants.TotalTransformFeedbackBuffers; index++)
|
||||||
{
|
{
|
||||||
TfBufferState tfb = _state.State.TfBufferState[index];
|
TfBufferState tfb = tfBufferStateSpan[index];
|
||||||
|
|
||||||
if (!tfb.Enable)
|
if (!tfb.Enable)
|
||||||
{
|
{
|
||||||
|
|
@ -465,10 +467,10 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||||
var memoryManager = _channel.MemoryManager;
|
var memoryManager = _channel.MemoryManager;
|
||||||
var rtControl = _state.State.RtControl;
|
var rtControl = _state.State.RtControl;
|
||||||
|
|
||||||
bool useControl = updateFlags.HasFlag(RenderTargetUpdateFlags.UseControl);
|
bool useControl = (updateFlags & RenderTargetUpdateFlags.UseControl) == RenderTargetUpdateFlags.UseControl;
|
||||||
bool layered = updateFlags.HasFlag(RenderTargetUpdateFlags.Layered);
|
bool layered = (updateFlags & RenderTargetUpdateFlags.Layered) == RenderTargetUpdateFlags.Layered;
|
||||||
bool singleColor = updateFlags.HasFlag(RenderTargetUpdateFlags.SingleColor);
|
bool singleColor = (updateFlags & RenderTargetUpdateFlags.SingleColor) == RenderTargetUpdateFlags.SingleColor;
|
||||||
bool discard = updateFlags.HasFlag(RenderTargetUpdateFlags.DiscardClip);
|
bool discard = (updateFlags & RenderTargetUpdateFlags.DiscardClip) == RenderTargetUpdateFlags.DiscardClip;
|
||||||
|
|
||||||
int count = useControl ? rtControl.UnpackCount() : Constants.TotalRenderTargets;
|
int count = useControl ? rtControl.UnpackCount() : Constants.TotalRenderTargets;
|
||||||
|
|
||||||
|
|
@ -486,11 +488,13 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||||
bool changedScale = false;
|
bool changedScale = false;
|
||||||
uint rtNoAlphaMask = 0;
|
uint rtNoAlphaMask = 0;
|
||||||
|
|
||||||
|
Span<RtColorState> rtColorStateSpan = _state.State.RtColorState.AsSpan();
|
||||||
|
|
||||||
for (int index = 0; index < Constants.TotalRenderTargets; index++)
|
for (int index = 0; index < Constants.TotalRenderTargets; index++)
|
||||||
{
|
{
|
||||||
int rtIndex = useControl ? rtControl.UnpackPermutationIndex(index) : index;
|
int rtIndex = useControl ? rtControl.UnpackPermutationIndex(index) : index;
|
||||||
|
|
||||||
var colorState = _state.State.RtColorState[rtIndex];
|
var colorState = rtColorStateSpan[rtIndex];
|
||||||
|
|
||||||
if (index >= count || !IsRtEnabled(colorState) || (singleColor && index != singleUse))
|
if (index >= count || !IsRtEnabled(colorState) || (singleColor && index != singleUse))
|
||||||
{
|
{
|
||||||
|
|
@ -538,7 +542,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||||
|
|
||||||
Image.Texture depthStencil = null;
|
Image.Texture depthStencil = null;
|
||||||
|
|
||||||
if (dsEnable && updateFlags.HasFlag(RenderTargetUpdateFlags.UpdateDepthStencil))
|
if (dsEnable && (updateFlags & RenderTargetUpdateFlags.UpdateDepthStencil) == RenderTargetUpdateFlags.UpdateDepthStencil)
|
||||||
{
|
{
|
||||||
var dsState = _state.State.RtDepthStencilState;
|
var dsState = _state.State.RtDepthStencilState;
|
||||||
var dsSize = _state.State.RtDepthStencilSize;
|
var dsSize = _state.State.RtDepthStencilSize;
|
||||||
|
|
@ -598,7 +602,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void UpdateRenderTargetSpecialization()
|
public void UpdateRenderTargetSpecialization()
|
||||||
{
|
{
|
||||||
_currentSpecState.SetFragmentOutputTypes(_state.State.RtControl, ref _state.State.RtColorState);
|
_currentSpecState.SetFragmentOutputTypes(_state.State.RtControl, _state.State.RtColorState.AsSpan());
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -623,10 +627,11 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||||
const int MaxH = 0xffff;
|
const int MaxH = 0xffff;
|
||||||
|
|
||||||
Span<Rectangle<int>> regions = stackalloc Rectangle<int>[Constants.TotalViewports];
|
Span<Rectangle<int>> regions = stackalloc Rectangle<int>[Constants.TotalViewports];
|
||||||
|
Span<ScissorState> scissorStateSpan = _state.State.ScissorState.AsSpan();
|
||||||
|
|
||||||
for (int index = 0; index < Constants.TotalViewports; index++)
|
for (int index = 0; index < Constants.TotalViewports; index++)
|
||||||
{
|
{
|
||||||
ScissorState scissor = _state.State.ScissorState[index];
|
ScissorState scissor = scissorStateSpan[index];
|
||||||
|
|
||||||
bool enable = scissor.Enable && (scissor.X1 != MinX ||
|
bool enable = scissor.Enable && (scissor.X1 != MinX ||
|
||||||
scissor.Y1 != MinY ||
|
scissor.Y1 != MinY ||
|
||||||
|
|
@ -730,6 +735,8 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||||
UpdateDepthMode();
|
UpdateDepthMode();
|
||||||
|
|
||||||
Span<Viewport> viewports = stackalloc Viewport[Constants.TotalViewports];
|
Span<Viewport> viewports = stackalloc Viewport[Constants.TotalViewports];
|
||||||
|
Span<ViewportTransform> viewportTransformSpan = _state.State.ViewportTransform.AsSpan();
|
||||||
|
Span<ViewportExtents> viewportExtentsSpan = _state.State.ViewportExtents.AsSpan();
|
||||||
|
|
||||||
for (int index = 0; index < Constants.TotalViewports; index++)
|
for (int index = 0; index < Constants.TotalViewports; index++)
|
||||||
{
|
{
|
||||||
|
|
@ -744,8 +751,8 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
ref var transform = ref _state.State.ViewportTransform[index];
|
ref var transform = ref viewportTransformSpan[index];
|
||||||
ref var extents = ref _state.State.ViewportExtents[index];
|
ref var extents = ref viewportExtentsSpan[index];
|
||||||
|
|
||||||
float scaleX = MathF.Abs(transform.ScaleX);
|
float scaleX = MathF.Abs(transform.ScaleX);
|
||||||
float scaleY = transform.ScaleY;
|
float scaleY = transform.ScaleY;
|
||||||
|
|
@ -967,10 +974,11 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||||
uint vbEnableMask = _vbEnableMask;
|
uint vbEnableMask = _vbEnableMask;
|
||||||
|
|
||||||
Span<VertexAttribDescriptor> vertexAttribs = stackalloc VertexAttribDescriptor[Constants.TotalVertexAttribs];
|
Span<VertexAttribDescriptor> vertexAttribs = stackalloc VertexAttribDescriptor[Constants.TotalVertexAttribs];
|
||||||
|
Span<VertexAttribState> vertexAttribStateSpan = _state.State.VertexAttribState.AsSpan();
|
||||||
|
|
||||||
for (int index = 0; index < Constants.TotalVertexAttribs; index++)
|
for (int index = 0; index < Constants.TotalVertexAttribs; index++)
|
||||||
{
|
{
|
||||||
var vertexAttrib = _state.State.VertexAttribState[index];
|
var vertexAttrib = vertexAttribStateSpan[index];
|
||||||
|
|
||||||
int bufferIndex = vertexAttrib.UnpackBufferIndex();
|
int bufferIndex = vertexAttrib.UnpackBufferIndex();
|
||||||
|
|
||||||
|
|
@ -1014,7 +1022,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||||
|
|
||||||
_pipeline.SetVertexAttribs(vertexAttribs);
|
_pipeline.SetVertexAttribs(vertexAttribs);
|
||||||
_context.Renderer.Pipeline.SetVertexAttribs(vertexAttribs);
|
_context.Renderer.Pipeline.SetVertexAttribs(vertexAttribs);
|
||||||
_currentSpecState.SetAttributeTypes(ref _state.State.VertexAttribState);
|
_currentSpecState.SetAttributeTypes(_state.State.VertexAttribState.AsSpan());
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -1105,20 +1113,25 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||||
int drawFirstVertex = _drawState.DrawFirstVertex;
|
int drawFirstVertex = _drawState.DrawFirstVertex;
|
||||||
int drawVertexCount = _drawState.DrawVertexCount;
|
int drawVertexCount = _drawState.DrawVertexCount;
|
||||||
uint vbEnableMask = 0;
|
uint vbEnableMask = 0;
|
||||||
|
|
||||||
|
Span<VertexBufferState> vertexBufferStateSpan = _state.State.VertexBufferState.AsSpan();
|
||||||
|
Span<BufferPipelineDescriptor> vertexBuffersSpan = _pipeline.VertexBuffers.AsSpan();
|
||||||
|
Span<GpuVa> vertexBufferEndAddressSpan = _state.State.VertexBufferEndAddress.AsSpan();
|
||||||
|
Span<Boolean32> vertexBufferInstancedSpan = _state.State.VertexBufferInstanced.AsSpan();
|
||||||
|
|
||||||
for (int index = 0; index < Constants.TotalVertexBuffers; index++)
|
for (int index = 0; index < Constants.TotalVertexBuffers; index++)
|
||||||
{
|
{
|
||||||
var vertexBuffer = _state.State.VertexBufferState[index];
|
var vertexBuffer = vertexBufferStateSpan[index];
|
||||||
|
|
||||||
if (!vertexBuffer.UnpackEnable())
|
if (!vertexBuffer.UnpackEnable())
|
||||||
{
|
{
|
||||||
_pipeline.VertexBuffers[index] = new BufferPipelineDescriptor(false, 0, 0);
|
vertexBuffersSpan[index] = new BufferPipelineDescriptor(false, 0, 0);
|
||||||
_channel.BufferManager.SetVertexBuffer(index, 0, 0, 0, 0);
|
_channel.BufferManager.SetVertexBuffer(index, 0, 0, 0, 0);
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
GpuVa endAddress = _state.State.VertexBufferEndAddress[index];
|
GpuVa endAddress = vertexBufferEndAddressSpan[index];
|
||||||
|
|
||||||
ulong address = vertexBuffer.Address.Pack();
|
ulong address = vertexBuffer.Address.Pack();
|
||||||
|
|
||||||
|
|
@ -1129,7 +1142,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||||
|
|
||||||
int stride = vertexBuffer.UnpackStride();
|
int stride = vertexBuffer.UnpackStride();
|
||||||
|
|
||||||
bool instanced = _state.State.VertexBufferInstanced[index];
|
bool instanced = vertexBufferInstancedSpan[index];
|
||||||
|
|
||||||
int divisor = instanced ? vertexBuffer.Divisor : 0;
|
int divisor = instanced ? vertexBuffer.Divisor : 0;
|
||||||
|
|
||||||
|
|
@ -1176,7 +1189,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||||
size = Math.Min(vbSize, (ulong)((firstInstance + drawFirstVertex + drawVertexCount) * stride));
|
size = Math.Min(vbSize, (ulong)((firstInstance + drawFirstVertex + drawVertexCount) * stride));
|
||||||
}
|
}
|
||||||
|
|
||||||
_pipeline.VertexBuffers[index] = new BufferPipelineDescriptor(_channel.MemoryManager.IsMapped(address), stride, divisor);
|
vertexBuffersSpan[index] = new BufferPipelineDescriptor(_channel.MemoryManager.IsMapped(address), stride, divisor);
|
||||||
_channel.BufferManager.SetVertexBuffer(index, address, size, stride, divisor);
|
_channel.BufferManager.SetVertexBuffer(index, address, size, stride, divisor);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1229,10 +1242,12 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||||
bool rtColorMaskShared = _state.State.RtColorMaskShared;
|
bool rtColorMaskShared = _state.State.RtColorMaskShared;
|
||||||
|
|
||||||
Span<uint> componentMasks = stackalloc uint[Constants.TotalRenderTargets];
|
Span<uint> componentMasks = stackalloc uint[Constants.TotalRenderTargets];
|
||||||
|
Span<RtColorMask> rtColorMaskSpan = _state.State.RtColorMask.AsSpan();
|
||||||
|
Span<uint> colorWriteMaskSpan = _pipeline.ColorWriteMask.AsSpan();
|
||||||
|
|
||||||
for (int index = 0; index < Constants.TotalRenderTargets; index++)
|
for (int index = 0; index < Constants.TotalRenderTargets; index++)
|
||||||
{
|
{
|
||||||
var colorMask = _state.State.RtColorMask[rtColorMaskShared ? 0 : index];
|
var colorMask = rtColorMaskSpan[rtColorMaskShared ? 0 : index];
|
||||||
|
|
||||||
uint componentMask;
|
uint componentMask;
|
||||||
|
|
||||||
|
|
@ -1242,7 +1257,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||||
componentMask |= (colorMask.UnpackAlpha() ? 8u : 0u);
|
componentMask |= (colorMask.UnpackAlpha() ? 8u : 0u);
|
||||||
|
|
||||||
componentMasks[index] = componentMask;
|
componentMasks[index] = componentMask;
|
||||||
_pipeline.ColorWriteMask[index] = componentMask;
|
colorWriteMaskSpan[index] = componentMask;
|
||||||
}
|
}
|
||||||
|
|
||||||
_context.Renderer.Pipeline.SetRenderTargetColorMasks(componentMasks);
|
_context.Renderer.Pipeline.SetRenderTargetColorMasks(componentMasks);
|
||||||
|
|
@ -1274,10 +1289,14 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||||
|
|
||||||
if (blendIndependent)
|
if (blendIndependent)
|
||||||
{
|
{
|
||||||
|
Span<Boolean32> blendEnableSpan = _state.State.BlendEnable.AsSpan();
|
||||||
|
Span<BlendState> blendStateSpan = _state.State.BlendState.AsSpan();
|
||||||
|
Span<BlendDescriptor> blendDescriptorsSpan = _pipeline.BlendDescriptors.AsSpan();
|
||||||
|
|
||||||
for (int index = 0; index < Constants.TotalRenderTargets; index++)
|
for (int index = 0; index < Constants.TotalRenderTargets; index++)
|
||||||
{
|
{
|
||||||
bool enable = _state.State.BlendEnable[index];
|
bool enable = blendEnableSpan[index];
|
||||||
var blend = _state.State.BlendState[index];
|
var blend = blendStateSpan[index];
|
||||||
|
|
||||||
var descriptor = new BlendDescriptor(
|
var descriptor = new BlendDescriptor(
|
||||||
enable,
|
enable,
|
||||||
|
|
@ -1298,7 +1317,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||||
dualSourceBlendEnabled = true;
|
dualSourceBlendEnabled = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
_pipeline.BlendDescriptors[index] = descriptor;
|
blendDescriptorsSpan[index] = descriptor;
|
||||||
_context.Renderer.Pipeline.SetBlendState(index, descriptor);
|
_context.Renderer.Pipeline.SetBlendState(index, descriptor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1325,10 +1344,12 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||||
{
|
{
|
||||||
dualSourceBlendEnabled = true;
|
dualSourceBlendEnabled = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Span<BlendDescriptor> blendDescriptorsSpan = _pipeline.BlendDescriptors.AsSpan();
|
||||||
|
|
||||||
for (int index = 0; index < Constants.TotalRenderTargets; index++)
|
for (int index = 0; index < Constants.TotalRenderTargets; index++)
|
||||||
{
|
{
|
||||||
_pipeline.BlendDescriptors[index] = descriptor;
|
blendDescriptorsSpan[index] = descriptor;
|
||||||
_context.Renderer.Pipeline.SetBlendState(index, descriptor);
|
_context.Renderer.Pipeline.SetBlendState(index, descriptor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1414,12 +1435,13 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||||
|
|
||||||
ShaderAddresses addresses = new();
|
ShaderAddresses addresses = new();
|
||||||
Span<ulong> addressesSpan = addresses.AsSpan();
|
Span<ulong> addressesSpan = addresses.AsSpan();
|
||||||
|
Span<ShaderState> shaderStateSpan = _state.State.ShaderState.AsSpan();
|
||||||
|
|
||||||
ulong baseAddress = _state.State.ShaderBaseAddress.Pack();
|
ulong baseAddress = _state.State.ShaderBaseAddress.Pack();
|
||||||
|
|
||||||
for (int index = 0; index < 6; index++)
|
for (int index = 0; index < 6; index++)
|
||||||
{
|
{
|
||||||
var shader = _state.State.ShaderState[index];
|
var shader = shaderStateSpan[index];
|
||||||
if (!shader.UnpackEnable() && index != 1)
|
if (!shader.UnpackEnable() && index != 1)
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
|
|
|
||||||
|
|
@ -242,22 +242,22 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||||
/// <param name="rhs">Second struct</param>
|
/// <param name="rhs">Second struct</param>
|
||||||
/// <returns>True if equal, false otherwise</returns>
|
/// <returns>True if equal, false otherwise</returns>
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
private static bool UnsafeEquals32Byte<T>(ref T lhs, ref T rhs) where T : unmanaged
|
private static bool UnsafeEquals32Byte<T>(Span<T> lhs, Span<T> rhs) where T : unmanaged
|
||||||
{
|
{
|
||||||
if (Vector256.IsHardwareAccelerated)
|
if (Vector256.IsHardwareAccelerated)
|
||||||
{
|
{
|
||||||
return Vector256.EqualsAll(
|
return Vector256.EqualsAll(
|
||||||
Unsafe.As<T, Vector256<uint>>(ref lhs),
|
Unsafe.As<Span<T>, ReadOnlySpan<Vector256<uint>>>(ref lhs)[0],
|
||||||
Unsafe.As<T, Vector256<uint>>(ref rhs)
|
Unsafe.As<Span<T>, ReadOnlySpan<Vector256<uint>>>(ref rhs)[0]
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ref var lhsVec = ref Unsafe.As<T, Vector128<uint>>(ref lhs);
|
var lhsVec = Unsafe.As<Span<T>, ReadOnlySpan<Vector128<uint>>>(ref lhs);
|
||||||
ref var rhsVec = ref Unsafe.As<T, Vector128<uint>>(ref rhs);
|
var rhsVec = Unsafe.As<Span<T>, ReadOnlySpan<Vector128<uint>>>(ref rhs);
|
||||||
|
|
||||||
return Vector128.EqualsAll(lhsVec, rhsVec) &&
|
return Vector128.EqualsAll(lhsVec[0], rhsVec[0]) &&
|
||||||
Vector128.EqualsAll(Unsafe.Add(ref lhsVec, 1), Unsafe.Add(ref rhsVec, 1));
|
Vector128.EqualsAll(lhsVec[1], rhsVec[1]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -265,26 +265,26 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||||
/// Updates blend enable. Respects current shadow mode.
|
/// Updates blend enable. Respects current shadow mode.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="masks">Blend enable</param>
|
/// <param name="masks">Blend enable</param>
|
||||||
public void UpdateBlendEnable(ref Array8<Boolean32> enable)
|
public void UpdateBlendEnable(Span<Boolean32> enable)
|
||||||
{
|
{
|
||||||
var shadow = ShadowMode;
|
var shadow = ShadowMode;
|
||||||
ref var state = ref _state.State.BlendEnable;
|
var state = _state.State.BlendEnable.AsSpan();
|
||||||
|
|
||||||
if (shadow.IsReplay())
|
if (shadow.IsReplay())
|
||||||
{
|
{
|
||||||
enable = _state.ShadowState.BlendEnable;
|
state.CopyTo(enable);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!UnsafeEquals32Byte(ref enable, ref state))
|
if (!UnsafeEquals32Byte(enable, state))
|
||||||
{
|
{
|
||||||
state = enable;
|
enable.CopyTo(state);
|
||||||
|
|
||||||
_stateUpdater.ForceDirty(StateUpdater.BlendStateIndex);
|
_stateUpdater.ForceDirty(StateUpdater.BlendStateIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (shadow.IsTrack())
|
if (shadow.IsTrack())
|
||||||
{
|
{
|
||||||
_state.ShadowState.BlendEnable = enable;
|
enable.CopyTo(state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -292,26 +292,26 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||||
/// Updates color masks. Respects current shadow mode.
|
/// Updates color masks. Respects current shadow mode.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="masks">Color masks</param>
|
/// <param name="masks">Color masks</param>
|
||||||
public void UpdateColorMasks(ref Array8<RtColorMask> masks)
|
public void UpdateColorMasks(Span<RtColorMask> masks)
|
||||||
{
|
{
|
||||||
var shadow = ShadowMode;
|
var shadow = ShadowMode;
|
||||||
ref var state = ref _state.State.RtColorMask;
|
var state = _state.State.RtColorMask.AsSpan();
|
||||||
|
|
||||||
if (shadow.IsReplay())
|
if (shadow.IsReplay())
|
||||||
{
|
{
|
||||||
masks = _state.ShadowState.RtColorMask;
|
state.CopyTo(masks);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!UnsafeEquals32Byte(ref masks, ref state))
|
if (!UnsafeEquals32Byte(masks, state))
|
||||||
{
|
{
|
||||||
state = masks;
|
masks.CopyTo(state);
|
||||||
|
|
||||||
_stateUpdater.ForceDirty(StateUpdater.RtColorMaskIndex);
|
_stateUpdater.ForceDirty(StateUpdater.RtColorMaskIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (shadow.IsTrack())
|
if (shadow.IsTrack())
|
||||||
{
|
{
|
||||||
_state.ShadowState.RtColorMask = masks;
|
masks.CopyTo(state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -72,7 +72,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||||
/// </summary>
|
/// </summary>
|
||||||
class BufferModifiedRangeList : NonOverlappingRangeList<BufferModifiedRange>
|
class BufferModifiedRangeList : NonOverlappingRangeList<BufferModifiedRange>
|
||||||
{
|
{
|
||||||
private new const int BackingInitialSize = 8;
|
private const int BackingInitialSize = 8;
|
||||||
|
|
||||||
private readonly GpuContext _context;
|
private readonly GpuContext _context;
|
||||||
private readonly Buffer _parent;
|
private readonly Buffer _parent;
|
||||||
|
|
@ -80,6 +80,8 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||||
|
|
||||||
private BufferMigration _source;
|
private BufferMigration _source;
|
||||||
private BufferModifiedRangeList _migrationTarget;
|
private BufferModifiedRangeList _migrationTarget;
|
||||||
|
|
||||||
|
private List<RangeItem<BufferModifiedRange>> _overlaps;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Whether the modified range list has any entries or not.
|
/// Whether the modified range list has any entries or not.
|
||||||
|
|
@ -106,6 +108,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||||
_context = context;
|
_context = context;
|
||||||
_parent = parent;
|
_parent = parent;
|
||||||
_flushAction = flushAction;
|
_flushAction = flushAction;
|
||||||
|
_overlaps = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -295,23 +298,24 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||||
/// <param name="rangeAction">The action to call for each modified range</param>
|
/// <param name="rangeAction">The action to call for each modified range</param>
|
||||||
public void GetRanges(ulong address, ulong size, Action<ulong, ulong> rangeAction)
|
public void GetRanges(ulong address, ulong size, Action<ulong, ulong> rangeAction)
|
||||||
{
|
{
|
||||||
List<RangeItem<BufferModifiedRange>> overlaps = [];
|
|
||||||
|
|
||||||
// We use the non-span method here because keeping the lock will cause a deadlock.
|
// We use the non-span method here because keeping the lock will cause a deadlock.
|
||||||
Lock.EnterReadLock();
|
Lock.EnterReadLock();
|
||||||
|
|
||||||
|
_overlaps.Clear();
|
||||||
|
|
||||||
(RangeItem<BufferModifiedRange> first, RangeItem<BufferModifiedRange> last) = FindOverlaps(address, size);
|
(RangeItem<BufferModifiedRange> first, RangeItem<BufferModifiedRange> last) = FindOverlaps(address, size);
|
||||||
|
|
||||||
RangeItem<BufferModifiedRange> current = first;
|
RangeItem<BufferModifiedRange> current = first;
|
||||||
while (last != null && current != last.Next)
|
while (last != null && current != last.Next)
|
||||||
{
|
{
|
||||||
overlaps.Add(current);
|
_overlaps.Add(current);
|
||||||
current = current.Next;
|
current = current.Next;
|
||||||
}
|
}
|
||||||
Lock.ExitReadLock();
|
Lock.ExitReadLock();
|
||||||
|
|
||||||
for (int i = 0; i < overlaps.Count; i++)
|
for (int i = 0; i < _overlaps.Count; i++)
|
||||||
{
|
{
|
||||||
BufferModifiedRange overlap = overlaps[i].Value;
|
BufferModifiedRange overlap = _overlaps[i].Value;
|
||||||
rangeAction(overlap.Address, overlap.Size);
|
rangeAction(overlap.Address, overlap.Size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -57,7 +57,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static BufferStage FromUsage(BufferUsageFlags flags)
|
public static BufferStage FromUsage(BufferUsageFlags flags)
|
||||||
{
|
{
|
||||||
if (flags.HasFlag(BufferUsageFlags.Write))
|
if ((flags & BufferUsageFlags.Write) == BufferUsageFlags.Write)
|
||||||
{
|
{
|
||||||
return BufferStage.StorageWrite;
|
return BufferStage.StorageWrite;
|
||||||
}
|
}
|
||||||
|
|
@ -70,7 +70,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static BufferStage FromUsage(TextureUsageFlags flags)
|
public static BufferStage FromUsage(TextureUsageFlags flags)
|
||||||
{
|
{
|
||||||
if (flags.HasFlag(TextureUsageFlags.ImageStore))
|
if ((flags & TextureUsageFlags.ImageStore) == TextureUsageFlags.ImageStore)
|
||||||
{
|
{
|
||||||
return BufferStage.StorageWrite;
|
return BufferStage.StorageWrite;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
using Ryujinx.Graphics.GAL;
|
using Ryujinx.Graphics.GAL;
|
||||||
using Ryujinx.Graphics.Shader;
|
using Ryujinx.Graphics.Shader;
|
||||||
|
using System;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
|
@ -104,9 +105,11 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||||
/// <param name="scale">Scale value</param>
|
/// <param name="scale">Scale value</param>
|
||||||
public void UpdateRenderScale(int index, float scale)
|
public void UpdateRenderScale(int index, float scale)
|
||||||
{
|
{
|
||||||
if (_data.RenderScale[1 + index].X != scale)
|
Span<Vector4<float>> renderScaleSpan = _data.RenderScale.AsSpan();
|
||||||
|
|
||||||
|
if (renderScaleSpan[1 + index].X != scale)
|
||||||
{
|
{
|
||||||
_data.RenderScale[1 + index].X = scale;
|
renderScaleSpan[1 + index].X = scale;
|
||||||
DirtyRenderScale(1 + index, 1);
|
DirtyRenderScale(1 + index, 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -133,11 +136,13 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||||
/// <param name="isBgra">True if the format is BGRA, false otherwise</param>
|
/// <param name="isBgra">True if the format is BGRA, false otherwise</param>
|
||||||
public void SetRenderTargetIsBgra(int index, bool isBgra)
|
public void SetRenderTargetIsBgra(int index, bool isBgra)
|
||||||
{
|
{
|
||||||
bool isBgraChanged = _data.FragmentIsBgra[index].X != 0 != isBgra;
|
Span<Vector4<int>> fragmentIsBgraSpan = _data.FragmentIsBgra.AsSpan();
|
||||||
|
|
||||||
|
bool isBgraChanged = fragmentIsBgraSpan[index].X != 0 != isBgra;
|
||||||
|
|
||||||
if (isBgraChanged)
|
if (isBgraChanged)
|
||||||
{
|
{
|
||||||
_data.FragmentIsBgra[index].X = isBgra ? 1 : 0;
|
fragmentIsBgraSpan[index].X = isBgra ? 1 : 0;
|
||||||
DirtyFragmentIsBgra(index, 1);
|
DirtyFragmentIsBgra(index, 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
using Ryujinx.Common.Configuration;
|
using Ryujinx.Common.Configuration;
|
||||||
using Ryujinx.Common.Logging;
|
using Ryujinx.Common.Logging;
|
||||||
|
using Ryujinx.Common.Memory;
|
||||||
using Ryujinx.Graphics.GAL;
|
using Ryujinx.Graphics.GAL;
|
||||||
using Ryujinx.Graphics.Gpu.Engine.Threed;
|
using Ryujinx.Graphics.Gpu.Engine.Threed;
|
||||||
using Ryujinx.Graphics.Gpu.Engine.Types;
|
using Ryujinx.Graphics.Gpu.Engine.Types;
|
||||||
|
|
@ -258,21 +259,25 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||||
|
|
||||||
int count = rtControl.UnpackCount();
|
int count = rtControl.UnpackCount();
|
||||||
|
|
||||||
|
Span<RtColorState> rtColorStateSpan = state.RtColorState.AsSpan();
|
||||||
|
Span<bool> attachmentEnableSpan = pipeline.AttachmentEnable.AsSpan();
|
||||||
|
Span<Format> attachmentFormatsSpan = pipeline.AttachmentFormats.AsSpan();
|
||||||
|
|
||||||
for (int index = 0; index < Constants.TotalRenderTargets; index++)
|
for (int index = 0; index < Constants.TotalRenderTargets; index++)
|
||||||
{
|
{
|
||||||
int rtIndex = rtControl.UnpackPermutationIndex(index);
|
int rtIndex = rtControl.UnpackPermutationIndex(index);
|
||||||
|
|
||||||
var colorState = state.RtColorState[rtIndex];
|
var colorState = rtColorStateSpan[rtIndex];
|
||||||
|
|
||||||
if (index >= count || colorState.Format == 0 || colorState.WidthOrStride == 0)
|
if (index >= count || colorState.Format == 0 || colorState.WidthOrStride == 0)
|
||||||
{
|
{
|
||||||
pipeline.AttachmentEnable[index] = false;
|
attachmentEnableSpan[index] = false;
|
||||||
pipeline.AttachmentFormats[index] = Format.R8G8B8A8Unorm;
|
attachmentFormatsSpan[index] = Format.R8G8B8A8Unorm;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
pipeline.AttachmentEnable[index] = true;
|
attachmentEnableSpan[index] = true;
|
||||||
pipeline.AttachmentFormats[index] = colorState.Format.Convert().Format;
|
attachmentFormatsSpan[index] = colorState.Format.Convert().Format;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -580,15 +585,18 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||||
|
|
||||||
TransformFeedbackDescriptor[] descs = new TransformFeedbackDescriptor[Constants.TotalTransformFeedbackBuffers];
|
TransformFeedbackDescriptor[] descs = new TransformFeedbackDescriptor[Constants.TotalTransformFeedbackBuffers];
|
||||||
|
|
||||||
|
Span<TfState> tfStateSpan = state.TfState.AsSpan();
|
||||||
|
Span<Array32<uint>> tfVaryingLocationsSpan = state.TfVaryingLocations.AsSpan();
|
||||||
|
|
||||||
for (int i = 0; i < Constants.TotalTransformFeedbackBuffers; i++)
|
for (int i = 0; i < Constants.TotalTransformFeedbackBuffers; i++)
|
||||||
{
|
{
|
||||||
var tf = state.TfState[i];
|
var tf = tfStateSpan[i];
|
||||||
|
|
||||||
descs[i] = new TransformFeedbackDescriptor(
|
descs[i] = new TransformFeedbackDescriptor(
|
||||||
tf.BufferIndex,
|
tf.BufferIndex,
|
||||||
tf.Stride,
|
tf.Stride,
|
||||||
tf.VaryingsCount,
|
tf.VaryingsCount,
|
||||||
ref state.TfVaryingLocations[i]);
|
ref tfVaryingLocationsSpan[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
return descs;
|
return descs;
|
||||||
|
|
|
||||||
|
|
@ -578,10 +578,13 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||||
|
|
||||||
if (ShaderCache.MayConvertVtgToCompute(ref channel.Capabilities) && !vertexAsCompute)
|
if (ShaderCache.MayConvertVtgToCompute(ref channel.Capabilities) && !vertexAsCompute)
|
||||||
{
|
{
|
||||||
for (int index = 0; index < graphicsState.AttributeTypes.Length; index++)
|
Span<AttributeType> attributeTypesSpan = graphicsState.AttributeTypes.AsSpan();
|
||||||
|
Span<AttributeType> gAttributeTypesSpan = GraphicsState.AttributeTypes.AsSpan();
|
||||||
|
|
||||||
|
for (int index = 0; index < attributeTypesSpan.Length; index++)
|
||||||
{
|
{
|
||||||
AttributeType lType = FilterAttributeType(channel, graphicsState.AttributeTypes[index]);
|
AttributeType lType = FilterAttributeType(channel, attributeTypesSpan[index]);
|
||||||
AttributeType rType = FilterAttributeType(channel, GraphicsState.AttributeTypes[index]);
|
AttributeType rType = FilterAttributeType(channel, gAttributeTypesSpan[index]);
|
||||||
|
|
||||||
if (lType != rType)
|
if (lType != rType)
|
||||||
{
|
{
|
||||||
|
|
@ -727,6 +730,8 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||||
{
|
{
|
||||||
int constantBufferUsePerStageMask = _constantBufferUsePerStage;
|
int constantBufferUsePerStageMask = _constantBufferUsePerStage;
|
||||||
|
|
||||||
|
Span<uint> constantBufferUseSpan = ConstantBufferUse.AsSpan();
|
||||||
|
|
||||||
while (constantBufferUsePerStageMask != 0)
|
while (constantBufferUsePerStageMask != 0)
|
||||||
{
|
{
|
||||||
int index = BitOperations.TrailingZeroCount(constantBufferUsePerStageMask);
|
int index = BitOperations.TrailingZeroCount(constantBufferUsePerStageMask);
|
||||||
|
|
@ -735,7 +740,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||||
? channel.BufferManager.GetComputeUniformBufferUseMask()
|
? channel.BufferManager.GetComputeUniformBufferUseMask()
|
||||||
: channel.BufferManager.GetGraphicsUniformBufferUseMask(index);
|
: channel.BufferManager.GetGraphicsUniformBufferUseMask(index);
|
||||||
|
|
||||||
if (ConstantBufferUse[index] != useMask)
|
if (constantBufferUseSpan[index] != useMask)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
@ -799,7 +804,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||||
{
|
{
|
||||||
if (specializationState != null)
|
if (specializationState != null)
|
||||||
{
|
{
|
||||||
if (specializationState.Value.QueriedFlags.HasFlag(QueriedTextureStateFlags.CoordNormalized) &&
|
if ((specializationState.Value.QueriedFlags & QueriedTextureStateFlags.CoordNormalized) == QueriedTextureStateFlags.CoordNormalized &&
|
||||||
specializationState.Value.CoordNormalized != descriptor.UnpackTextureCoordNormalized())
|
specializationState.Value.CoordNormalized != descriptor.UnpackTextureCoordNormalized())
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -875,10 +880,12 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||||
|
|
||||||
int constantBufferUsePerStageMask = specState._constantBufferUsePerStage;
|
int constantBufferUsePerStageMask = specState._constantBufferUsePerStage;
|
||||||
|
|
||||||
|
Span<uint> constantBufferUseSpan = specState.ConstantBufferUse.AsSpan();
|
||||||
|
|
||||||
while (constantBufferUsePerStageMask != 0)
|
while (constantBufferUsePerStageMask != 0)
|
||||||
{
|
{
|
||||||
int index = BitOperations.TrailingZeroCount(constantBufferUsePerStageMask);
|
int index = BitOperations.TrailingZeroCount(constantBufferUsePerStageMask);
|
||||||
dataReader.Read(ref specState.ConstantBufferUse[index]);
|
dataReader.Read(ref constantBufferUseSpan[index]);
|
||||||
constantBufferUsePerStageMask &= ~(1 << index);
|
constantBufferUsePerStageMask &= ~(1 << index);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -977,11 +984,13 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||||
dataWriter.Write(ref _constantBufferUsePerStage);
|
dataWriter.Write(ref _constantBufferUsePerStage);
|
||||||
|
|
||||||
int constantBufferUsePerStageMask = _constantBufferUsePerStage;
|
int constantBufferUsePerStageMask = _constantBufferUsePerStage;
|
||||||
|
|
||||||
|
Span<uint> constantBufferUseSpan = ConstantBufferUse.AsSpan();
|
||||||
|
|
||||||
while (constantBufferUsePerStageMask != 0)
|
while (constantBufferUsePerStageMask != 0)
|
||||||
{
|
{
|
||||||
int index = BitOperations.TrailingZeroCount(constantBufferUsePerStageMask);
|
int index = BitOperations.TrailingZeroCount(constantBufferUsePerStageMask);
|
||||||
dataWriter.Write(ref ConstantBufferUse[index]);
|
dataWriter.Write(ref constantBufferUseSpan[index]);
|
||||||
constantBufferUsePerStageMask &= ~(1 << index);
|
constantBufferUsePerStageMask &= ~(1 << index);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -92,20 +92,24 @@ namespace Ryujinx.Graphics.Nvdec.FFmpeg.H264
|
||||||
|
|
||||||
if (pictureInfo.ScalingMatrixPresent)
|
if (pictureInfo.ScalingMatrixPresent)
|
||||||
{
|
{
|
||||||
|
Span<Array16<byte>> scalingLists4x4Span = pictureInfo.ScalingLists4x4.AsSpan();
|
||||||
|
|
||||||
for (int index = 0; index < 6; index++)
|
for (int index = 0; index < 6; index++)
|
||||||
{
|
{
|
||||||
writer.WriteBit(true);
|
writer.WriteBit(true);
|
||||||
|
|
||||||
WriteScalingList(ref writer, pictureInfo.ScalingLists4x4[index]);
|
WriteScalingList(ref writer, scalingLists4x4Span[index]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pictureInfo.Transform8x8ModeFlag)
|
if (pictureInfo.Transform8x8ModeFlag)
|
||||||
{
|
{
|
||||||
|
Span<Array64<byte>> scalingLists8x8Span = pictureInfo.ScalingLists8x8.AsSpan();
|
||||||
|
|
||||||
for (int index = 0; index < 2; index++)
|
for (int index = 0; index < 2; index++)
|
||||||
{
|
{
|
||||||
writer.WriteBit(true);
|
writer.WriteBit(true);
|
||||||
|
|
||||||
WriteScalingList(ref writer, pictureInfo.ScalingLists8x8[index]);
|
WriteScalingList(ref writer, scalingLists8x8Span[index]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -144,9 +148,11 @@ namespace Ryujinx.Graphics.Nvdec.FFmpeg.H264
|
||||||
|
|
||||||
int lastScale = 8;
|
int lastScale = 8;
|
||||||
|
|
||||||
for (int index = 0; index < list.Length; index++)
|
Span<byte> listSpan = list.AsSpan();
|
||||||
|
|
||||||
|
for (int index = 0; index < listSpan.Length; index++)
|
||||||
{
|
{
|
||||||
byte value = list[scan[index]];
|
byte value = listSpan[scan[index]];
|
||||||
|
|
||||||
int deltaScale = value - lastScale;
|
int deltaScale = value - lastScale;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -21,49 +21,67 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||||
|
|
||||||
private static void ReadTxModeProbs(ref Vp9EntropyProbs txProbs, ref Reader r)
|
private static void ReadTxModeProbs(ref Vp9EntropyProbs txProbs, ref Reader r)
|
||||||
{
|
{
|
||||||
|
Span<Array1<byte>> tx8x8ProbSpan1 = txProbs.Tx8x8Prob.AsSpan();
|
||||||
|
Span<Array2<byte>> tx16x16ProbSpan1 = txProbs.Tx16x16Prob.AsSpan();
|
||||||
|
Span<Array3<byte>> tx32x32ProbSpan1 = txProbs.Tx32x32Prob.AsSpan();
|
||||||
|
|
||||||
for (int i = 0; i < EntropyMode.TxSizeContexts; ++i)
|
for (int i = 0; i < EntropyMode.TxSizeContexts; ++i)
|
||||||
{
|
{
|
||||||
|
Span<byte> tx8x8ProbSpan2 = tx8x8ProbSpan1[i].AsSpan();
|
||||||
|
|
||||||
for (int j = 0; j < (int)TxSize.TxSizes - 3; ++j)
|
for (int j = 0; j < (int)TxSize.TxSizes - 3; ++j)
|
||||||
{
|
{
|
||||||
r.DiffUpdateProb(ref txProbs.Tx8x8Prob[i][j]);
|
r.DiffUpdateProb(ref tx8x8ProbSpan2[j]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < EntropyMode.TxSizeContexts; ++i)
|
for (int i = 0; i < EntropyMode.TxSizeContexts; ++i)
|
||||||
{
|
{
|
||||||
|
Span<byte> tx16x16ProbSpan2 = tx16x16ProbSpan1[i].AsSpan();
|
||||||
|
|
||||||
for (int j = 0; j < (int)TxSize.TxSizes - 2; ++j)
|
for (int j = 0; j < (int)TxSize.TxSizes - 2; ++j)
|
||||||
{
|
{
|
||||||
r.DiffUpdateProb(ref txProbs.Tx16x16Prob[i][j]);
|
r.DiffUpdateProb(ref tx16x16ProbSpan2[j]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < EntropyMode.TxSizeContexts; ++i)
|
for (int i = 0; i < EntropyMode.TxSizeContexts; ++i)
|
||||||
{
|
{
|
||||||
|
Span<byte> tx32x32ProbSpan2 = tx32x32ProbSpan1[i].AsSpan();
|
||||||
|
|
||||||
for (int j = 0; j < (int)TxSize.TxSizes - 1; ++j)
|
for (int j = 0; j < (int)TxSize.TxSizes - 1; ++j)
|
||||||
{
|
{
|
||||||
r.DiffUpdateProb(ref txProbs.Tx32x32Prob[i][j]);
|
r.DiffUpdateProb(ref tx32x32ProbSpan2[j]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void ReadSwitchableInterpProbs(ref Vp9EntropyProbs fc, ref Reader r)
|
private static void ReadSwitchableInterpProbs(ref Vp9EntropyProbs fc, ref Reader r)
|
||||||
{
|
{
|
||||||
for (int j = 0; j < Constants.SwitchableFilterContexts; ++j)
|
Span<Array2<byte>> switchableInterpProbSpan1 = fc.SwitchableInterpProb.AsSpan();
|
||||||
|
|
||||||
|
for (int i = 0; i < Constants.SwitchableFilterContexts; ++i)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < Constants.SwitchableFilters - 1; ++i)
|
Span<byte> switchableInterpProbSpan2 = switchableInterpProbSpan1[i].AsSpan();
|
||||||
|
|
||||||
|
for (int j = 0; j < Constants.SwitchableFilters - 1; ++j)
|
||||||
{
|
{
|
||||||
r.DiffUpdateProb(ref fc.SwitchableInterpProb[j][i]);
|
r.DiffUpdateProb(ref switchableInterpProbSpan2[j]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void ReadInterModeProbs(ref Vp9EntropyProbs fc, ref Reader r)
|
private static void ReadInterModeProbs(ref Vp9EntropyProbs fc, ref Reader r)
|
||||||
{
|
{
|
||||||
|
Span<Array3<byte>> interModeProbSpan1 = fc.InterModeProb.AsSpan();
|
||||||
|
|
||||||
for (int i = 0; i < Constants.InterModeContexts; ++i)
|
for (int i = 0; i < Constants.InterModeContexts; ++i)
|
||||||
{
|
{
|
||||||
|
Span<byte> interModeProbSpan2 = interModeProbSpan1[i].AsSpan();
|
||||||
|
|
||||||
for (int j = 0; j < Constants.InterModes - 1; ++j)
|
for (int j = 0; j < Constants.InterModes - 1; ++j)
|
||||||
{
|
{
|
||||||
r.DiffUpdateProb( ref fc.InterModeProb[i][j]);
|
r.DiffUpdateProb(ref interModeProbSpan2[j]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -72,30 +90,43 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||||
{
|
{
|
||||||
r.UpdateMvProbs(ctx.Joints.AsSpan(), EntropyMv.Joints - 1);
|
r.UpdateMvProbs(ctx.Joints.AsSpan(), EntropyMv.Joints - 1);
|
||||||
|
|
||||||
for (int i = 0; i < 2; ++i)
|
Span<byte> signSpan = ctx.Sign.AsSpan();
|
||||||
{
|
Span<Array10<byte>> classesSpan = ctx.Classes.AsSpan();
|
||||||
r.UpdateMvProbs(MemoryMarshal.CreateSpan(ref ctx.Sign[i], 1), 1);
|
Span<Array1<byte>> class0Span = ctx.Class0.AsSpan();
|
||||||
r.UpdateMvProbs(ctx.Classes[i].AsSpan(), EntropyMv.Classes - 1);
|
Span<Array10<byte>> bitsSpan = ctx.Bits.AsSpan();
|
||||||
r.UpdateMvProbs(ctx.Class0[i].AsSpan(), EntropyMv.Class0Size - 1);
|
|
||||||
r.UpdateMvProbs(ctx.Bits[i].AsSpan(), EntropyMv.OffsetBits);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < 2; ++i)
|
for (int i = 0; i < 2; ++i)
|
||||||
{
|
{
|
||||||
|
r.UpdateMvProbs(MemoryMarshal.CreateSpan(ref signSpan[i], 1), 1);
|
||||||
|
r.UpdateMvProbs(classesSpan[i].AsSpan(), EntropyMv.Classes - 1);
|
||||||
|
r.UpdateMvProbs(class0Span[i].AsSpan(), EntropyMv.Class0Size - 1);
|
||||||
|
r.UpdateMvProbs(bitsSpan[i].AsSpan(), EntropyMv.OffsetBits);
|
||||||
|
}
|
||||||
|
|
||||||
|
Span<Array2<Array3<byte>>> class0FpSpan1 = ctx.Class0Fp.AsSpan();
|
||||||
|
Span<Array3<byte>> fpSpan = ctx.Fp.AsSpan();
|
||||||
|
|
||||||
|
for (int i = 0; i < 2; ++i)
|
||||||
|
{
|
||||||
|
Span<Array3<byte>> class0FpSpan2 = class0FpSpan1[i].AsSpan();
|
||||||
|
|
||||||
for (int j = 0; j < EntropyMv.Class0Size; ++j)
|
for (int j = 0; j < EntropyMv.Class0Size; ++j)
|
||||||
{
|
{
|
||||||
r.UpdateMvProbs(ctx.Class0Fp[i][j].AsSpan(), EntropyMv.FpSize - 1);
|
r.UpdateMvProbs(class0FpSpan2[j].AsSpan(), EntropyMv.FpSize - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
r.UpdateMvProbs(ctx.Fp[i].AsSpan(), 3);
|
r.UpdateMvProbs(fpSpan[i].AsSpan(), 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (allowHp)
|
if (allowHp)
|
||||||
{
|
{
|
||||||
|
Span<byte> class0HpSpan = ctx.Class0Hp.AsSpan();
|
||||||
|
Span<byte> hpSpan = ctx.Hp.AsSpan();
|
||||||
|
|
||||||
for (int i = 0; i < 2; ++i)
|
for (int i = 0; i < 2; ++i)
|
||||||
{
|
{
|
||||||
r.UpdateMvProbs(MemoryMarshal.CreateSpan(ref ctx.Class0Hp[i], 1), 1);
|
r.UpdateMvProbs(MemoryMarshal.CreateSpan(ref class0HpSpan[i], 1), 1);
|
||||||
r.UpdateMvProbs(MemoryMarshal.CreateSpan(ref ctx.Hp[i], 1), 1);
|
r.UpdateMvProbs(MemoryMarshal.CreateSpan(ref hpSpan[i], 1), 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -751,10 +782,16 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||||
int refr;
|
int refr;
|
||||||
bool isScaled;
|
bool isScaled;
|
||||||
|
|
||||||
|
Span<sbyte> refFrameSpan = mi.RefFrame.AsSpan();
|
||||||
|
Span<Mv> mvSpan = mi.Mv.AsSpan();
|
||||||
|
Span<RefBuffer> frameRefsSpan = cm.FrameRefs.AsSpan();
|
||||||
|
Span<Ptr<RefBuffer>> blockRefsSpan = xd.BlockRefs.AsSpan();
|
||||||
|
Span<MacroBlockDPlane> planeSpan = xd.Plane.AsSpan();
|
||||||
|
|
||||||
for (refr = 0; refr < 1 + isCompound; ++refr)
|
for (refr = 0; refr < 1 + isCompound; ++refr)
|
||||||
{
|
{
|
||||||
int frame = mi.RefFrame[refr];
|
int frame = refFrameSpan[refr];
|
||||||
ref RefBuffer refBuf = ref cm.FrameRefs[frame - Constants.LastFrame];
|
ref RefBuffer refBuf = ref frameRefsSpan[frame - Constants.LastFrame];
|
||||||
ref ScaleFactors sf = ref refBuf.Sf;
|
ref ScaleFactors sf = ref refBuf.Sf;
|
||||||
ref Surface refFrameBuf = ref refBuf.Buf;
|
ref Surface refFrameBuf = ref refBuf.Buf;
|
||||||
|
|
||||||
|
|
@ -767,13 +804,13 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||||
isScaled = sf.IsScaled();
|
isScaled = sf.IsScaled();
|
||||||
ReconInter.SetupPrePlanes(ref xd, refr, ref refFrameBuf, miRow, miCol,
|
ReconInter.SetupPrePlanes(ref xd, refr, ref refFrameBuf, miRow, miCol,
|
||||||
isScaled ? new Ptr<ScaleFactors>(ref sf) : Ptr<ScaleFactors>.Null);
|
isScaled ? new Ptr<ScaleFactors>(ref sf) : Ptr<ScaleFactors>.Null);
|
||||||
xd.BlockRefs[refr] = new Ptr<RefBuffer>(ref refBuf);
|
blockRefsSpan[refr] = new Ptr<RefBuffer>(ref refBuf);
|
||||||
|
|
||||||
if (sbType < BlockSize.Block8x8)
|
if (sbType < BlockSize.Block8x8)
|
||||||
{
|
{
|
||||||
for (plane = 0; plane < Constants.MaxMbPlane; ++plane)
|
for (plane = 0; plane < Constants.MaxMbPlane; ++plane)
|
||||||
{
|
{
|
||||||
ref MacroBlockDPlane pd = ref xd.Plane[plane];
|
ref MacroBlockDPlane pd = ref planeSpan[plane];
|
||||||
ref Buf2D dstBuf = ref pd.Dst;
|
ref Buf2D dstBuf = ref pd.Dst;
|
||||||
int num4x4W = pd.N4W;
|
int num4x4W = pd.N4W;
|
||||||
int num4x4H = pd.N4H;
|
int num4x4H = pd.N4H;
|
||||||
|
|
@ -811,10 +848,10 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Mv mv = mi.Mv[refr];
|
Mv mv = mvSpan[refr];
|
||||||
for (plane = 0; plane < Constants.MaxMbPlane; ++plane)
|
for (plane = 0; plane < Constants.MaxMbPlane; ++plane)
|
||||||
{
|
{
|
||||||
ref MacroBlockDPlane pd = ref xd.Plane[plane];
|
ref MacroBlockDPlane pd = ref planeSpan[plane];
|
||||||
ref Buf2D dstBuf = ref pd.Dst;
|
ref Buf2D dstBuf = ref pd.Dst;
|
||||||
int num4x4W = pd.N4W;
|
int num4x4W = pd.N4W;
|
||||||
int num4x4H = pd.N4H;
|
int num4x4H = pd.N4H;
|
||||||
|
|
@ -847,12 +884,14 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||||
|
|
||||||
private static void SetPlaneN4(ref MacroBlockD xd, int bw, int bh, int bwl, int bhl)
|
private static void SetPlaneN4(ref MacroBlockD xd, int bw, int bh, int bwl, int bhl)
|
||||||
{
|
{
|
||||||
|
Span<MacroBlockDPlane> planeSpan = xd.Plane.AsSpan();
|
||||||
|
|
||||||
for (int i = 0; i < Constants.MaxMbPlane; i++)
|
for (int i = 0; i < Constants.MaxMbPlane; i++)
|
||||||
{
|
{
|
||||||
xd.Plane[i].N4W = (ushort)((bw << 1) >> xd.Plane[i].SubsamplingX);
|
planeSpan[i].N4W = (ushort)((bw << 1) >> planeSpan[i].SubsamplingX);
|
||||||
xd.Plane[i].N4H = (ushort)((bh << 1) >> xd.Plane[i].SubsamplingY);
|
planeSpan[i].N4H = (ushort)((bh << 1) >> planeSpan[i].SubsamplingY);
|
||||||
xd.Plane[i].N4Wl = (byte)(bwl - xd.Plane[i].SubsamplingX);
|
planeSpan[i].N4Wl = (byte)(bwl - planeSpan[i].SubsamplingX);
|
||||||
xd.Plane[i].N4Hl = (byte)(bhl - xd.Plane[i].SubsamplingY);
|
planeSpan[i].N4Hl = (byte)(bhl - planeSpan[i].SubsamplingY);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -892,7 +931,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||||
// as they are always compared to values that are in 1/8th pel units
|
// as they are always compared to values that are in 1/8th pel units
|
||||||
xd.SetMiRowCol(ref tile, miRow, bh, miCol, bw, cm.MiRows, cm.MiCols);
|
xd.SetMiRowCol(ref tile, miRow, bh, miCol, bw, cm.MiRows, cm.MiCols);
|
||||||
|
|
||||||
ReconInter.SetupDstPlanes(ref xd.Plane, ref xd.CurBuf, miRow, miCol);
|
ReconInter.SetupDstPlanes(xd.Plane.AsSpan(), ref xd.CurBuf, miRow, miCol);
|
||||||
return ref xd.Mi[0].Value;
|
return ref xd.Mi[0].Value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -933,10 +972,11 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||||
|
|
||||||
if (!mi.IsInterBlock())
|
if (!mi.IsInterBlock())
|
||||||
{
|
{
|
||||||
int plane;
|
Span<MacroBlockDPlane> planeSpan = xd.Plane.AsSpan();
|
||||||
for (plane = 0; plane < Constants.MaxMbPlane; ++plane)
|
|
||||||
|
for (int plane = 0; plane < Constants.MaxMbPlane; ++plane)
|
||||||
{
|
{
|
||||||
ref MacroBlockDPlane pd = ref xd.Plane[plane];
|
ref MacroBlockDPlane pd = ref planeSpan[plane];
|
||||||
TxSize txSize = plane != 0 ? mi.GetUvTxSize(ref pd) : mi.TxSize;
|
TxSize txSize = plane != 0 ? mi.GetUvTxSize(ref pd) : mi.TxSize;
|
||||||
int num4x4W = pd.N4W;
|
int num4x4W = pd.N4W;
|
||||||
int num4x4H = pd.N4H;
|
int num4x4H = pd.N4H;
|
||||||
|
|
@ -967,12 +1007,13 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||||
// Reconstruction
|
// Reconstruction
|
||||||
if (mi.Skip == 0)
|
if (mi.Skip == 0)
|
||||||
{
|
{
|
||||||
|
Span<MacroBlockDPlane> planeSpan = xd.Plane.AsSpan();
|
||||||
|
|
||||||
int eobtotal = 0;
|
int eobtotal = 0;
|
||||||
int plane;
|
|
||||||
|
|
||||||
for (plane = 0; plane < Constants.MaxMbPlane; ++plane)
|
for (int plane = 0; plane < Constants.MaxMbPlane; ++plane)
|
||||||
{
|
{
|
||||||
ref MacroBlockDPlane pd = ref xd.Plane[plane];
|
ref MacroBlockDPlane pd = ref planeSpan[plane];
|
||||||
TxSize txSize = plane != 0 ? mi.GetUvTxSize(ref pd) : mi.TxSize;
|
TxSize txSize = plane != 0 ? mi.GetUvTxSize(ref pd) : mi.TxSize;
|
||||||
int num4x4W = pd.N4W;
|
int num4x4W = pd.N4W;
|
||||||
int num4x4H = pd.N4H;
|
int num4x4H = pd.N4H;
|
||||||
|
|
@ -1159,22 +1200,30 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void ReadCoefProbsCommon(ref Array2<Array2<Array6<Array6<Array3<byte>>>>> coefProbs,
|
private static void ReadCoefProbsCommon(ReadOnlySpan<Array2<Array6<Array6<Array3<byte>>>>> coefProbs1,
|
||||||
ref Reader r, int txSize)
|
ref Reader r, int txSize)
|
||||||
{
|
{
|
||||||
if (r.ReadBit() != 0)
|
if (r.ReadBit() != 0)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < Constants.PlaneTypes; ++i)
|
for (int i = 0; i < Constants.PlaneTypes; ++i)
|
||||||
{
|
{
|
||||||
|
Span<Array6<Array6<Array3<byte>>>> coefProbs2 = coefProbs1[i].AsSpan();
|
||||||
|
|
||||||
for (int j = 0; j < Entropy.RefTypes; ++j)
|
for (int j = 0; j < Entropy.RefTypes; ++j)
|
||||||
{
|
{
|
||||||
|
Span<Array6<Array3<byte>>> coefProbs3 = coefProbs2[j].AsSpan();
|
||||||
|
|
||||||
for (int k = 0; k < Entropy.CoefBands; ++k)
|
for (int k = 0; k < Entropy.CoefBands; ++k)
|
||||||
{
|
{
|
||||||
|
Span<Array3<byte>> coefProbs4 = coefProbs3[k].AsSpan();
|
||||||
|
|
||||||
for (int l = 0; l < Entropy.BAND_COEFF_CONTEXTS(k); ++l)
|
for (int l = 0; l < Entropy.BAND_COEFF_CONTEXTS(k); ++l)
|
||||||
{
|
{
|
||||||
|
Span<byte> coefProbs5 = coefProbs4[l].AsSpan();
|
||||||
|
|
||||||
for (int m = 0; m < Entropy.UnconstrainedNodes; ++m)
|
for (int m = 0; m < Entropy.UnconstrainedNodes; ++m)
|
||||||
{
|
{
|
||||||
r.DiffUpdateProb( ref coefProbs[i][j][k][l][m]);
|
r.DiffUpdateProb(ref coefProbs5[m]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1185,10 +1234,13 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||||
|
|
||||||
private static void ReadCoefProbs(ref Vp9EntropyProbs fc, TxMode txMode, ref Reader r)
|
private static void ReadCoefProbs(ref Vp9EntropyProbs fc, TxMode txMode, ref Reader r)
|
||||||
{
|
{
|
||||||
|
Span<Array2<Array2<Array6<Array6<Array3<byte>>>>>> coefProbsSpan = fc.CoefProbs.AsSpan();
|
||||||
|
|
||||||
int maxTxSize = (int)Luts.TxModeToBiggestTxSize[(int)txMode];
|
int maxTxSize = (int)Luts.TxModeToBiggestTxSize[(int)txMode];
|
||||||
|
|
||||||
for (int txSize = (int)TxSize.Tx4x4; txSize <= maxTxSize; ++txSize)
|
for (int txSize = (int)TxSize.Tx4x4; txSize <= maxTxSize; ++txSize)
|
||||||
{
|
{
|
||||||
ReadCoefProbsCommon(ref fc.CoefProbs[txSize], ref r, txSize);
|
ReadCoefProbsCommon(coefProbsSpan[txSize].AsSpan(), ref r, txSize);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1207,11 +1259,14 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||||
lf.ModeRefDeltaUpdate = rb.ReadBit() != 0;
|
lf.ModeRefDeltaUpdate = rb.ReadBit() != 0;
|
||||||
if (lf.ModeRefDeltaUpdate)
|
if (lf.ModeRefDeltaUpdate)
|
||||||
{
|
{
|
||||||
|
Span<sbyte> refDeltasSpan = lf.RefDeltas.AsSpan();
|
||||||
|
Span<sbyte> modeDeltasSpan = lf.ModeDeltas.AsSpan();
|
||||||
|
|
||||||
for (int i = 0; i < LoopFilter.MaxRefLfDeltas; i++)
|
for (int i = 0; i < LoopFilter.MaxRefLfDeltas; i++)
|
||||||
{
|
{
|
||||||
if (rb.ReadBit() != 0)
|
if (rb.ReadBit() != 0)
|
||||||
{
|
{
|
||||||
lf.RefDeltas[i] = (sbyte)rb.ReadSignedLiteral(6);
|
refDeltasSpan[i] = (sbyte)rb.ReadSignedLiteral(6);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1219,7 +1274,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||||
{
|
{
|
||||||
if (rb.ReadBit() != 0)
|
if (rb.ReadBit() != 0)
|
||||||
{
|
{
|
||||||
lf.ModeDeltas[i] = (sbyte)rb.ReadSignedLiteral(6);
|
modeDeltasSpan[i] = (sbyte)rb.ReadSignedLiteral(6);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1268,6 +1323,8 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||||
cm.ResizeContextBuffers(allocator, width, height);
|
cm.ResizeContextBuffers(allocator, width, height);
|
||||||
SetupRenderSize(ref cm, ref rb);
|
SetupRenderSize(ref cm, ref rb);
|
||||||
|
|
||||||
|
Span<RefCntBuffer> frameBuffsSpan = pool.FrameBufs.AsSpan();
|
||||||
|
|
||||||
if (cm.GetFrameNewBuffer().ReallocFrameBuffer(
|
if (cm.GetFrameNewBuffer().ReallocFrameBuffer(
|
||||||
allocator,
|
allocator,
|
||||||
cm.Width,
|
cm.Width,
|
||||||
|
|
@ -1277,21 +1334,21 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||||
cm.UseHighBitDepth,
|
cm.UseHighBitDepth,
|
||||||
Surface.DecBorderInPixels,
|
Surface.DecBorderInPixels,
|
||||||
cm.ByteAlignment,
|
cm.ByteAlignment,
|
||||||
new Ptr<VpxCodecFrameBuffer>(ref pool.FrameBufs[cm.NewFbIdx].RawFrameBuffer),
|
new Ptr<VpxCodecFrameBuffer>(ref frameBuffsSpan[cm.NewFbIdx].RawFrameBuffer),
|
||||||
FrameBuffers.GetFrameBuffer,
|
FrameBuffers.GetFrameBuffer,
|
||||||
pool.CbPriv) != 0)
|
pool.CbPriv) != 0)
|
||||||
{
|
{
|
||||||
cm.Error.InternalError(CodecErr.MemError, "Failed to allocate frame buffer");
|
cm.Error.InternalError(CodecErr.MemError, "Failed to allocate frame buffer");
|
||||||
}
|
}
|
||||||
|
|
||||||
pool.FrameBufs[cm.NewFbIdx].Released = 0;
|
frameBuffsSpan[cm.NewFbIdx].Released = 0;
|
||||||
pool.FrameBufs[cm.NewFbIdx].Buf.SubsamplingX = cm.SubsamplingX;
|
frameBuffsSpan[cm.NewFbIdx].Buf.SubsamplingX = cm.SubsamplingX;
|
||||||
pool.FrameBufs[cm.NewFbIdx].Buf.SubsamplingY = cm.SubsamplingY;
|
frameBuffsSpan[cm.NewFbIdx].Buf.SubsamplingY = cm.SubsamplingY;
|
||||||
pool.FrameBufs[cm.NewFbIdx].Buf.BitDepth = (uint)cm.BitDepth;
|
frameBuffsSpan[cm.NewFbIdx].Buf.BitDepth = (uint)cm.BitDepth;
|
||||||
pool.FrameBufs[cm.NewFbIdx].Buf.ColorSpace = cm.ColorSpace;
|
frameBuffsSpan[cm.NewFbIdx].Buf.ColorSpace = cm.ColorSpace;
|
||||||
pool.FrameBufs[cm.NewFbIdx].Buf.ColorRange = cm.ColorRange;
|
frameBuffsSpan[cm.NewFbIdx].Buf.ColorRange = cm.ColorRange;
|
||||||
pool.FrameBufs[cm.NewFbIdx].Buf.RenderWidth = cm.RenderWidth;
|
frameBuffsSpan[cm.NewFbIdx].Buf.RenderWidth = cm.RenderWidth;
|
||||||
pool.FrameBufs[cm.NewFbIdx].Buf.RenderHeight = cm.RenderHeight;
|
frameBuffsSpan[cm.NewFbIdx].Buf.RenderHeight = cm.RenderHeight;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool ValidRefFrameImgFmt(
|
private static bool ValidRefFrameImgFmt(
|
||||||
|
|
@ -1312,13 +1369,15 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||||
|
|
||||||
bool hasValidRefFrame = false;
|
bool hasValidRefFrame = false;
|
||||||
ref BufferPool pool = ref cm.BufferPool.Value;
|
ref BufferPool pool = ref cm.BufferPool.Value;
|
||||||
|
Span<RefBuffer> frameRefsSpan = cm.FrameRefs.AsSpan();
|
||||||
|
|
||||||
for (int i = 0; i < Constants.RefsPerFrame; ++i)
|
for (int i = 0; i < Constants.RefsPerFrame; ++i)
|
||||||
{
|
{
|
||||||
if (rb.ReadBit() != 0)
|
if (rb.ReadBit() != 0)
|
||||||
{
|
{
|
||||||
if (cm.FrameRefs[i].Idx != RefBuffer.InvalidIdx)
|
if (frameRefsSpan[i].Idx != RefBuffer.InvalidIdx)
|
||||||
{
|
{
|
||||||
ref Surface buf = ref cm.FrameRefs[i].Buf;
|
ref Surface buf = ref frameRefsSpan[i].Buf;
|
||||||
width = buf.YCropWidth;
|
width = buf.YCropWidth;
|
||||||
height = buf.YCropHeight;
|
height = buf.YCropHeight;
|
||||||
found = true;
|
found = true;
|
||||||
|
|
@ -1343,7 +1402,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||||
// has valid dimensions.
|
// has valid dimensions.
|
||||||
for (int i = 0; i < Constants.RefsPerFrame; ++i)
|
for (int i = 0; i < Constants.RefsPerFrame; ++i)
|
||||||
{
|
{
|
||||||
ref RefBuffer refFrame = ref cm.FrameRefs[i];
|
ref RefBuffer refFrame = ref frameRefsSpan[i];
|
||||||
hasValidRefFrame |=
|
hasValidRefFrame |=
|
||||||
refFrame.Idx != RefBuffer.InvalidIdx &&
|
refFrame.Idx != RefBuffer.InvalidIdx &&
|
||||||
ScaleFactors.ValidRefFrameSize(refFrame.Buf.YCropWidth, refFrame.Buf.YCropHeight, width,
|
ScaleFactors.ValidRefFrameSize(refFrame.Buf.YCropWidth, refFrame.Buf.YCropHeight, width,
|
||||||
|
|
@ -1357,7 +1416,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||||
|
|
||||||
for (int i = 0; i < Constants.RefsPerFrame; ++i)
|
for (int i = 0; i < Constants.RefsPerFrame; ++i)
|
||||||
{
|
{
|
||||||
ref RefBuffer refFrame = ref cm.FrameRefs[i];
|
ref RefBuffer refFrame = ref frameRefsSpan[i];
|
||||||
if (refFrame.Idx == RefBuffer.InvalidIdx ||
|
if (refFrame.Idx == RefBuffer.InvalidIdx ||
|
||||||
!ValidRefFrameImgFmt(
|
!ValidRefFrameImgFmt(
|
||||||
(BitDepth)refFrame.Buf.BitDepth,
|
(BitDepth)refFrame.Buf.BitDepth,
|
||||||
|
|
@ -1374,6 +1433,8 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||||
|
|
||||||
cm.ResizeContextBuffers(allocator, width, height);
|
cm.ResizeContextBuffers(allocator, width, height);
|
||||||
SetupRenderSize(ref cm, ref rb);
|
SetupRenderSize(ref cm, ref rb);
|
||||||
|
|
||||||
|
Span<RefCntBuffer> frameBuffsSpan = pool.FrameBufs.AsSpan();
|
||||||
|
|
||||||
if (cm.GetFrameNewBuffer().ReallocFrameBuffer(
|
if (cm.GetFrameNewBuffer().ReallocFrameBuffer(
|
||||||
allocator,
|
allocator,
|
||||||
|
|
@ -1384,21 +1445,21 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||||
cm.UseHighBitDepth,
|
cm.UseHighBitDepth,
|
||||||
Surface.DecBorderInPixels,
|
Surface.DecBorderInPixels,
|
||||||
cm.ByteAlignment,
|
cm.ByteAlignment,
|
||||||
new Ptr<VpxCodecFrameBuffer>(ref pool.FrameBufs[cm.NewFbIdx].RawFrameBuffer),
|
new Ptr<VpxCodecFrameBuffer>(ref frameBuffsSpan[cm.NewFbIdx].RawFrameBuffer),
|
||||||
FrameBuffers.GetFrameBuffer,
|
FrameBuffers.GetFrameBuffer,
|
||||||
pool.CbPriv) != 0)
|
pool.CbPriv) != 0)
|
||||||
{
|
{
|
||||||
cm.Error.InternalError(CodecErr.MemError, "Failed to allocate frame buffer");
|
cm.Error.InternalError(CodecErr.MemError, "Failed to allocate frame buffer");
|
||||||
}
|
}
|
||||||
|
|
||||||
pool.FrameBufs[cm.NewFbIdx].Released = 0;
|
frameBuffsSpan[cm.NewFbIdx].Released = 0;
|
||||||
pool.FrameBufs[cm.NewFbIdx].Buf.SubsamplingX = cm.SubsamplingX;
|
frameBuffsSpan[cm.NewFbIdx].Buf.SubsamplingX = cm.SubsamplingX;
|
||||||
pool.FrameBufs[cm.NewFbIdx].Buf.SubsamplingY = cm.SubsamplingY;
|
frameBuffsSpan[cm.NewFbIdx].Buf.SubsamplingY = cm.SubsamplingY;
|
||||||
pool.FrameBufs[cm.NewFbIdx].Buf.BitDepth = (uint)cm.BitDepth;
|
frameBuffsSpan[cm.NewFbIdx].Buf.BitDepth = (uint)cm.BitDepth;
|
||||||
pool.FrameBufs[cm.NewFbIdx].Buf.ColorSpace = cm.ColorSpace;
|
frameBuffsSpan[cm.NewFbIdx].Buf.ColorSpace = cm.ColorSpace;
|
||||||
pool.FrameBufs[cm.NewFbIdx].Buf.ColorRange = cm.ColorRange;
|
frameBuffsSpan[cm.NewFbIdx].Buf.ColorRange = cm.ColorRange;
|
||||||
pool.FrameBufs[cm.NewFbIdx].Buf.RenderWidth = cm.RenderWidth;
|
frameBuffsSpan[cm.NewFbIdx].Buf.RenderWidth = cm.RenderWidth;
|
||||||
pool.FrameBufs[cm.NewFbIdx].Buf.RenderHeight = cm.RenderHeight;
|
frameBuffsSpan[cm.NewFbIdx].Buf.RenderHeight = cm.RenderHeight;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reads the next tile returning its size and adjusting '*data' accordingly
|
// Reads the next tile returning its size and adjusting '*data' accordingly
|
||||||
|
|
@ -1438,7 +1499,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void GetTileBuffers(ref Vp9Common cm, ArrayPtr<byte> data, int tileCols,
|
private static void GetTileBuffers(ref Vp9Common cm, ArrayPtr<byte> data, int tileCols,
|
||||||
ref Array64<TileBuffer> tileBuffers)
|
Span<TileBuffer> tileBuffers)
|
||||||
{
|
{
|
||||||
for (int c = 0; c < tileCols; ++c)
|
for (int c = 0; c < tileCols; ++c)
|
||||||
{
|
{
|
||||||
|
|
@ -1454,14 +1515,16 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||||
ArrayPtr<byte> data,
|
ArrayPtr<byte> data,
|
||||||
int tileCols,
|
int tileCols,
|
||||||
int tileRows,
|
int tileRows,
|
||||||
ref Array4<Array64<TileBuffer>> tileBuffers)
|
Span<Array64<TileBuffer>> tileBuffers1)
|
||||||
{
|
{
|
||||||
for (int r = 0; r < tileRows; ++r)
|
for (int r = 0; r < tileRows; ++r)
|
||||||
{
|
{
|
||||||
|
Span<TileBuffer> tileBuffers2 = tileBuffers1[r].AsSpan();
|
||||||
|
|
||||||
for (int c = 0; c < tileCols; ++c)
|
for (int c = 0; c < tileCols; ++c)
|
||||||
{
|
{
|
||||||
bool isLast = r == tileRows - 1 && c == tileCols - 1;
|
bool isLast = r == tileRows - 1 && c == tileCols - 1;
|
||||||
ref TileBuffer buf = ref tileBuffers[r][c];
|
ref TileBuffer buf = ref tileBuffers2[c];
|
||||||
GetTileBuffer(isLast, ref cm.Error, ref data, ref buf);
|
GetTileBuffer(isLast, ref cm.Error, ref data, ref buf);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1485,15 +1548,20 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||||
MemoryUtil.Fill(cm.AboveSegContext.ToPointer(), (sbyte)0, alignedCols);
|
MemoryUtil.Fill(cm.AboveSegContext.ToPointer(), (sbyte)0, alignedCols);
|
||||||
|
|
||||||
LoopFilter.ResetLfm(ref cm);
|
LoopFilter.ResetLfm(ref cm);
|
||||||
|
|
||||||
|
Span<Array64<TileBuffer>> tileBuffers1 = tileBuffers.AsSpan();
|
||||||
|
Span<TileWorkerData> tileWorkerDataSpan = cm.TileWorkerData.AsSpan();
|
||||||
|
|
||||||
GetTileBuffers(ref cm, data, tileCols, tileRows, ref tileBuffers);
|
GetTileBuffers(ref cm, data, tileCols, tileRows, tileBuffers1);
|
||||||
// Load all tile information into tile_data.
|
// Load all tile information into tile_data.
|
||||||
for (tileRow = 0; tileRow < tileRows; ++tileRow)
|
for (tileRow = 0; tileRow < tileRows; ++tileRow)
|
||||||
{
|
{
|
||||||
|
Span<TileBuffer> tileBuffers2 = tileBuffers1[tileRow].AsSpan();
|
||||||
|
|
||||||
for (tileCol = 0; tileCol < tileCols; ++tileCol)
|
for (tileCol = 0; tileCol < tileCols; ++tileCol)
|
||||||
{
|
{
|
||||||
ref TileBuffer buf = ref tileBuffers[tileRow][tileCol];
|
ref TileBuffer buf = ref tileBuffers2[tileCol];
|
||||||
ref TileWorkerData tileData = ref cm.TileWorkerData[(tileCols * tileRow) + tileCol];
|
ref TileWorkerData tileData = ref tileWorkerDataSpan[(tileCols * tileRow) + tileCol];
|
||||||
tileData.Xd = cm.Mb;
|
tileData.Xd = cm.Mb;
|
||||||
tileData.Xd.Corrupted = false;
|
tileData.Xd.Corrupted = false;
|
||||||
tileData.Xd.Counts = cm.Counts;
|
tileData.Xd.Counts = cm.Counts;
|
||||||
|
|
@ -1513,7 +1581,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||||
for (tileCol = 0; tileCol < tileCols; ++tileCol)
|
for (tileCol = 0; tileCol < tileCols; ++tileCol)
|
||||||
{
|
{
|
||||||
int col = tileCol;
|
int col = tileCol;
|
||||||
ref TileWorkerData tileData = ref cm.TileWorkerData[(tileCols * tileRow) + col];
|
ref TileWorkerData tileData = ref tileWorkerDataSpan[(tileCols * tileRow) + col];
|
||||||
tile.SetCol(ref cm, col);
|
tile.SetCol(ref cm, col);
|
||||||
tileData.Xd.LeftContext = new Array3<Array16<sbyte>>();
|
tileData.Xd.LeftContext = new Array3<Array16<sbyte>>();
|
||||||
tileData.Xd.LeftSegContext = new Array8<sbyte>();
|
tileData.Xd.LeftSegContext = new Array8<sbyte>();
|
||||||
|
|
@ -1532,11 +1600,11 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get last tile data.
|
// Get last tile data.
|
||||||
return cm.TileWorkerData[(tileCols * tileRows) - 1].BitReader.FindEnd();
|
return tileWorkerDataSpan[(tileCols * tileRows) - 1].BitReader.FindEnd();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool DecodeTileCol(ref TileWorkerData tileData, ref Vp9Common cm,
|
private static bool DecodeTileCol(ref TileWorkerData tileData, ref Vp9Common cm,
|
||||||
ref Array64<TileBuffer> tileBuffers)
|
Span<TileBuffer> tileBuffers)
|
||||||
{
|
{
|
||||||
ref TileInfo tile = ref tileData.Xd.Tile;
|
ref TileInfo tile = ref tileData.Xd.Tile;
|
||||||
int finalCol = (1 << cm.Log2TileCols) - 1;
|
int finalCol = (1 << cm.Log2TileCols) - 1;
|
||||||
|
|
@ -1594,10 +1662,12 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||||
|
|
||||||
cm.AboveContext.AsSpan().Clear();
|
cm.AboveContext.AsSpan().Clear();
|
||||||
cm.AboveSegContext.AsSpan().Clear();
|
cm.AboveSegContext.AsSpan().Clear();
|
||||||
|
|
||||||
|
Span<TileWorkerData> tileWorkerDataSpan = cm.TileWorkerData.AsSpan();
|
||||||
|
|
||||||
for (n = 0; n < numWorkers; ++n)
|
for (n = 0; n < numWorkers; ++n)
|
||||||
{
|
{
|
||||||
ref TileWorkerData tileData = ref cm.TileWorkerData[n + totalTiles];
|
ref TileWorkerData tileData = ref tileWorkerDataSpan[n + totalTiles];
|
||||||
|
|
||||||
tileData.Xd = cm.Mb;
|
tileData.Xd = cm.Mb;
|
||||||
tileData.Xd.Counts = new Ptr<Vp9BackwardUpdates>(ref tileData.Counts);
|
tileData.Xd.Counts = new Ptr<Vp9BackwardUpdates>(ref tileData.Counts);
|
||||||
|
|
@ -1605,17 +1675,17 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||||
}
|
}
|
||||||
|
|
||||||
Array64<TileBuffer> tileBuffers = new();
|
Array64<TileBuffer> tileBuffers = new();
|
||||||
|
Span<TileBuffer> tileBuffersSpan = tileBuffers.AsSpan();
|
||||||
|
|
||||||
GetTileBuffers(ref cm, data, tileCols, ref tileBuffers);
|
GetTileBuffers(ref cm, data, tileCols, tileBuffersSpan);
|
||||||
|
|
||||||
tileBuffers.AsSpan().Slice(0, tileCols).Sort(CompareTileBuffers);
|
tileBuffersSpan[..tileCols].Sort(CompareTileBuffers);
|
||||||
|
|
||||||
if (numWorkers == tileCols)
|
if (numWorkers == tileCols)
|
||||||
{
|
{
|
||||||
TileBuffer largest = tileBuffers[0];
|
TileBuffer largest = tileBuffersSpan[0];
|
||||||
Span<TileBuffer> buffers = tileBuffers.AsSpan();
|
tileBuffersSpan[1..].CopyTo(tileBuffersSpan[..^1]);
|
||||||
buffers.Slice(1).CopyTo(buffers.Slice(0, tileBuffers.Length - 1));
|
tileBuffersSpan[tileCols - 1] = largest;
|
||||||
tileBuffers[tileCols - 1] = largest;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
@ -1626,9 +1696,9 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||||
// larger tile implies it is more difficult to decode.
|
// larger tile implies it is more difficult to decode.
|
||||||
while (start < end)
|
while (start < end)
|
||||||
{
|
{
|
||||||
tmp = tileBuffers[start];
|
tmp = tileBuffersSpan[start];
|
||||||
tileBuffers[start] = tileBuffers[end];
|
tileBuffersSpan[start] = tileBuffersSpan[end];
|
||||||
tileBuffers[end] = tmp;
|
tileBuffersSpan[end] = tmp;
|
||||||
start += 2;
|
start += 2;
|
||||||
end -= 2;
|
end -= 2;
|
||||||
}
|
}
|
||||||
|
|
@ -1641,7 +1711,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||||
for (n = 0; n < numWorkers; ++n)
|
for (n = 0; n < numWorkers; ++n)
|
||||||
{
|
{
|
||||||
int count = baseVal + ((remain + n) / numWorkers);
|
int count = baseVal + ((remain + n) / numWorkers);
|
||||||
ref TileWorkerData tileData = ref cm.TileWorkerData[n + totalTiles];
|
ref TileWorkerData tileData = ref tileWorkerDataSpan[n + totalTiles];
|
||||||
|
|
||||||
tileData.BufStart = bufStart;
|
tileData.BufStart = bufStart;
|
||||||
tileData.BufEnd = bufStart + count - 1;
|
tileData.BufEnd = bufStart + count - 1;
|
||||||
|
|
@ -1655,7 +1725,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||||
{
|
{
|
||||||
ref TileWorkerData tileData = ref cmPtr.Value.TileWorkerData[n + totalTiles];
|
ref TileWorkerData tileData = ref cmPtr.Value.TileWorkerData[n + totalTiles];
|
||||||
|
|
||||||
if (!DecodeTileCol(ref tileData, ref cmPtr.Value, ref tileBuffers))
|
if (!DecodeTileCol(ref tileData, ref cmPtr.Value, tileBuffers.AsSpan()))
|
||||||
{
|
{
|
||||||
cmPtr.Value.Mb.Corrupted = true;
|
cmPtr.Value.Mb.Corrupted = true;
|
||||||
}
|
}
|
||||||
|
|
@ -1665,14 +1735,14 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||||
{
|
{
|
||||||
if (bitReaderEnd.IsNull)
|
if (bitReaderEnd.IsNull)
|
||||||
{
|
{
|
||||||
ref TileWorkerData tileData = ref cm.TileWorkerData[n - 1 + totalTiles];
|
ref TileWorkerData tileData = ref tileWorkerDataSpan[n - 1 + totalTiles];
|
||||||
bitReaderEnd = tileData.DataEnd;
|
bitReaderEnd = tileData.DataEnd;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (n = 0; n < numWorkers; ++n)
|
for (n = 0; n < numWorkers; ++n)
|
||||||
{
|
{
|
||||||
ref TileWorkerData tileData = ref cm.TileWorkerData[n + totalTiles];
|
ref TileWorkerData tileData = ref tileWorkerDataSpan[n + totalTiles];
|
||||||
AccumulateFrameCounts(ref cm.Counts.Value, ref tileData.Counts);
|
AccumulateFrameCounts(ref cm.Counts.Value, ref tileData.Counts);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1706,7 +1776,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||||
{
|
{
|
||||||
if (cm.FrameType == FrameType.KeyFrame && cm.CurrentVideoFrame > 0)
|
if (cm.FrameType == FrameType.KeyFrame && cm.CurrentVideoFrame > 0)
|
||||||
{
|
{
|
||||||
ref Array12<RefCntBuffer> frameBufs = ref cm.BufferPool.Value.FrameBufs;
|
Span<RefCntBuffer> frameBuffs = cm.BufferPool.Value.FrameBufs.AsSpan();
|
||||||
ref BufferPool pool = ref cm.BufferPool.Value;
|
ref BufferPool pool = ref cm.BufferPool.Value;
|
||||||
|
|
||||||
for (int i = 0; i < Constants.FrameBuffers; ++i)
|
for (int i = 0; i < Constants.FrameBuffers; ++i)
|
||||||
|
|
@ -1716,11 +1786,11 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
frameBufs[i].RefCount = 0;
|
frameBuffs[i].RefCount = 0;
|
||||||
if (frameBufs[i].Released == 0)
|
if (frameBuffs[i].Released == 0)
|
||||||
{
|
{
|
||||||
FrameBuffers.ReleaseFrameBuffer(pool.CbPriv, ref frameBufs[i].RawFrameBuffer);
|
FrameBuffers.ReleaseFrameBuffer(pool.CbPriv, ref frameBuffs[i].RawFrameBuffer);
|
||||||
frameBufs[i].Released = 1;
|
frameBuffs[i].Released = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1739,7 +1809,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||||
rb.ReadLiteral(8) == SyncCode2;
|
rb.ReadLiteral(8) == SyncCode2;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void RefCntFb(ref Array12<RefCntBuffer> bufs, ref int idx, int newIdx)
|
private static void RefCntFb(Span<RefCntBuffer> bufs, ref int idx, int newIdx)
|
||||||
{
|
{
|
||||||
int refIndex = idx;
|
int refIndex = idx;
|
||||||
|
|
||||||
|
|
@ -1758,13 +1828,15 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||||
{
|
{
|
||||||
ref Vp9Common cm = ref pbi.Common;
|
ref Vp9Common cm = ref pbi.Common;
|
||||||
ref BufferPool pool = ref cm.BufferPool.Value;
|
ref BufferPool pool = ref cm.BufferPool.Value;
|
||||||
ref Array12<RefCntBuffer> frameBufs = ref pool.FrameBufs;
|
Span<RefCntBuffer> frameBuffs = pool.FrameBufs.AsSpan();
|
||||||
int mask, refIndex = 0;
|
int mask, refIndex = 0;
|
||||||
ulong sz;
|
ulong sz;
|
||||||
|
|
||||||
cm.LastFrameType = cm.FrameType;
|
cm.LastFrameType = cm.FrameType;
|
||||||
cm.LastIntraOnly = cm.IntraOnly;
|
cm.LastIntraOnly = cm.IntraOnly;
|
||||||
|
|
||||||
|
Span<int> refFrameSpan = cm.RefFrameMap.AsSpan();
|
||||||
|
|
||||||
if (rb.ReadLiteral(2) != FrameMarker)
|
if (rb.ReadLiteral(2) != FrameMarker)
|
||||||
{
|
{
|
||||||
cm.Error.InternalError(CodecErr.UnsupBitstream, "Invalid frame marker");
|
cm.Error.InternalError(CodecErr.UnsupBitstream, "Invalid frame marker");
|
||||||
|
|
@ -1780,14 +1852,14 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||||
if (cm.ShowExistingFrame != 0)
|
if (cm.ShowExistingFrame != 0)
|
||||||
{
|
{
|
||||||
// Show an existing frame directly.
|
// Show an existing frame directly.
|
||||||
int frameToShow = cm.RefFrameMap[rb.ReadLiteral(3)];
|
int frameToShow = refFrameSpan[rb.ReadLiteral(3)];
|
||||||
if (frameToShow < 0 || frameBufs[frameToShow].RefCount < 1)
|
if (frameToShow < 0 || frameBuffs[frameToShow].RefCount < 1)
|
||||||
{
|
{
|
||||||
cm.Error.InternalError(CodecErr.UnsupBitstream,
|
cm.Error.InternalError(CodecErr.UnsupBitstream,
|
||||||
$"Buffer {frameToShow} does not contain a decoded frame");
|
$"Buffer {frameToShow} does not contain a decoded frame");
|
||||||
}
|
}
|
||||||
|
|
||||||
RefCntFb(ref frameBufs, ref cm.NewFbIdx, frameToShow);
|
RefCntFb(frameBuffs, ref cm.NewFbIdx, frameToShow);
|
||||||
pbi.RefreshFrameFlags = 0;
|
pbi.RefreshFrameFlags = 0;
|
||||||
cm.Lf.FilterLevel = 0;
|
cm.Lf.FilterLevel = 0;
|
||||||
cm.ShowFrame = 1;
|
cm.ShowFrame = 1;
|
||||||
|
|
@ -1809,16 +1881,18 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||||
cm.ReadBitdepthColorspaceSampling(ref rb);
|
cm.ReadBitdepthColorspaceSampling(ref rb);
|
||||||
pbi.RefreshFrameFlags = (1 << Constants.RefFrames) - 1;
|
pbi.RefreshFrameFlags = (1 << Constants.RefFrames) - 1;
|
||||||
|
|
||||||
|
Span<RefBuffer> frameRefsSpan = cm.FrameRefs.AsSpan();
|
||||||
|
|
||||||
for (int i = 0; i < Constants.RefsPerFrame; ++i)
|
for (int i = 0; i < Constants.RefsPerFrame; ++i)
|
||||||
{
|
{
|
||||||
cm.FrameRefs[i].Idx = RefBuffer.InvalidIdx;
|
frameRefsSpan[i].Idx = RefBuffer.InvalidIdx;
|
||||||
cm.FrameRefs[i].Buf = default;
|
frameRefsSpan[i].Buf = default;
|
||||||
}
|
}
|
||||||
|
|
||||||
SetupFrameSize(allocator, ref cm, ref rb);
|
SetupFrameSize(allocator, ref cm, ref rb);
|
||||||
if (pbi.NeedResync != 0)
|
if (pbi.NeedResync != 0)
|
||||||
{
|
{
|
||||||
cm.RefFrameMap.AsSpan().Fill(-1);
|
refFrameSpan.Fill(-1);
|
||||||
FlushAllFbOnKey(ref cm);
|
FlushAllFbOnKey(ref cm);
|
||||||
pbi.NeedResync = 0;
|
pbi.NeedResync = 0;
|
||||||
}
|
}
|
||||||
|
|
@ -1857,22 +1931,25 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||||
SetupFrameSize(allocator, ref cm, ref rb);
|
SetupFrameSize(allocator, ref cm, ref rb);
|
||||||
if (pbi.NeedResync != 0)
|
if (pbi.NeedResync != 0)
|
||||||
{
|
{
|
||||||
cm.RefFrameMap.AsSpan().Fill(-1);
|
refFrameSpan.Fill(-1);
|
||||||
pbi.NeedResync = 0;
|
pbi.NeedResync = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (pbi.NeedResync != 1)
|
else if (pbi.NeedResync != 1)
|
||||||
{
|
{
|
||||||
|
Span<RefBuffer> frameRefsSpan = cm.FrameRefs.AsSpan();
|
||||||
|
Span<sbyte> refFrameSignBiasSpan = cm.RefFrameSignBias.AsSpan();
|
||||||
|
|
||||||
/* Skip if need resync */
|
/* Skip if need resync */
|
||||||
pbi.RefreshFrameFlags = rb.ReadLiteral(Constants.RefFrames);
|
pbi.RefreshFrameFlags = rb.ReadLiteral(Constants.RefFrames);
|
||||||
for (int i = 0; i < Constants.RefsPerFrame; ++i)
|
for (int i = 0; i < Constants.RefsPerFrame; ++i)
|
||||||
{
|
{
|
||||||
int refr = rb.ReadLiteral(Constants.RefFramesLog2);
|
int refr = rb.ReadLiteral(Constants.RefFramesLog2);
|
||||||
int idx = cm.RefFrameMap[refr];
|
int idx = refFrameSpan[refr];
|
||||||
ref RefBuffer refFrame = ref cm.FrameRefs[i];
|
ref RefBuffer refFrame = ref frameRefsSpan[i];
|
||||||
refFrame.Idx = idx;
|
refFrame.Idx = idx;
|
||||||
refFrame.Buf = frameBufs[idx].Buf;
|
refFrame.Buf = frameBuffs[idx].Buf;
|
||||||
cm.RefFrameSignBias[Constants.LastFrame + i] = (sbyte)rb.ReadBit();
|
refFrameSignBiasSpan[Constants.LastFrame + i] = (sbyte)rb.ReadBit();
|
||||||
}
|
}
|
||||||
|
|
||||||
SetupFrameSizeWithRefs(allocator, ref cm, ref rb);
|
SetupFrameSizeWithRefs(allocator, ref cm, ref rb);
|
||||||
|
|
@ -1882,7 +1959,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||||
|
|
||||||
for (int i = 0; i < Constants.RefsPerFrame; ++i)
|
for (int i = 0; i < Constants.RefsPerFrame; ++i)
|
||||||
{
|
{
|
||||||
ref RefBuffer refBuf = ref cm.FrameRefs[i];
|
ref RefBuffer refBuf = ref frameRefsSpan[i];
|
||||||
refBuf.Sf.SetupScaleFactorsForFrame(
|
refBuf.Sf.SetupScaleFactorsForFrame(
|
||||||
refBuf.Buf.YCropWidth,
|
refBuf.Buf.YCropWidth,
|
||||||
refBuf.Buf.YCropHeight,
|
refBuf.Buf.YCropHeight,
|
||||||
|
|
@ -1923,23 +2000,25 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||||
// below, forcing the use of context 0 for those frame types.
|
// below, forcing the use of context 0 for those frame types.
|
||||||
cm.FrameContextIdx = (uint)rb.ReadLiteral(Constants.FrameContextsLog2);
|
cm.FrameContextIdx = (uint)rb.ReadLiteral(Constants.FrameContextsLog2);
|
||||||
|
|
||||||
|
Span<int> nextRefFrameMapSpan = cm.NextRefFrameMap.AsSpan();
|
||||||
|
|
||||||
// Generate next_ref_frame_map.
|
// Generate next_ref_frame_map.
|
||||||
for (mask = pbi.RefreshFrameFlags; mask != 0; mask >>= 1)
|
for (mask = pbi.RefreshFrameFlags; mask != 0; mask >>= 1)
|
||||||
{
|
{
|
||||||
if ((mask & 1) != 0)
|
if ((mask & 1) != 0)
|
||||||
{
|
{
|
||||||
cm.NextRefFrameMap[refIndex] = cm.NewFbIdx;
|
nextRefFrameMapSpan[refIndex] = cm.NewFbIdx;
|
||||||
++frameBufs[cm.NewFbIdx].RefCount;
|
++frameBuffs[cm.NewFbIdx].RefCount;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
cm.NextRefFrameMap[refIndex] = cm.RefFrameMap[refIndex];
|
nextRefFrameMapSpan[refIndex] = cm.RefFrameMap[refIndex];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Current thread holds the reference frame.
|
// Current thread holds the reference frame.
|
||||||
if (cm.RefFrameMap[refIndex] >= 0)
|
if (cm.RefFrameMap[refIndex] >= 0)
|
||||||
{
|
{
|
||||||
++frameBufs[cm.RefFrameMap[refIndex]].RefCount;
|
++frameBuffs[cm.RefFrameMap[refIndex]].RefCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
++refIndex;
|
++refIndex;
|
||||||
|
|
@ -1947,11 +2026,11 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||||
|
|
||||||
for (; refIndex < Constants.RefFrames; ++refIndex)
|
for (; refIndex < Constants.RefFrames; ++refIndex)
|
||||||
{
|
{
|
||||||
cm.NextRefFrameMap[refIndex] = cm.RefFrameMap[refIndex];
|
nextRefFrameMapSpan[refIndex] = refFrameSpan[refIndex];
|
||||||
// Current thread holds the reference frame.
|
// Current thread holds the reference frame.
|
||||||
if (cm.RefFrameMap[refIndex] >= 0)
|
if (refFrameSpan[refIndex] >= 0)
|
||||||
{
|
{
|
||||||
++frameBufs[cm.RefFrameMap[refIndex]].RefCount;
|
++frameBuffs[refFrameSpan[refIndex]].RefCount;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1998,9 +2077,11 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||||
|
|
||||||
ReadCoefProbs(ref fc, cm.TxMode, ref r);
|
ReadCoefProbs(ref fc, cm.TxMode, ref r);
|
||||||
|
|
||||||
|
Span<byte> skipProbSpan = fc.SkipProb.AsSpan();
|
||||||
|
|
||||||
for (int k = 0; k < Constants.SkipContexts; ++k)
|
for (int k = 0; k < Constants.SkipContexts; ++k)
|
||||||
{
|
{
|
||||||
r.DiffUpdateProb(ref fc.SkipProb[k]);
|
r.DiffUpdateProb(ref skipProbSpan[k]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!cm.FrameIsIntraOnly())
|
if (!cm.FrameIsIntraOnly())
|
||||||
|
|
@ -2011,10 +2092,12 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||||
{
|
{
|
||||||
ReadSwitchableInterpProbs(ref fc, ref r);
|
ReadSwitchableInterpProbs(ref fc, ref r);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Span<byte> intraInterProbSpan = fc.IntraInterProb.AsSpan();
|
||||||
|
|
||||||
for (int i = 0; i < Constants.IntraInterContexts; i++)
|
for (int i = 0; i < Constants.IntraInterContexts; i++)
|
||||||
{
|
{
|
||||||
r.DiffUpdateProb( ref fc.IntraInterProb[i]);
|
r.DiffUpdateProb(ref intraInterProbSpan[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
cm.ReferenceMode = cm.ReadFrameReferenceMode(ref r);
|
cm.ReferenceMode = cm.ReadFrameReferenceMode(ref r);
|
||||||
|
|
@ -2024,20 +2107,28 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||||
}
|
}
|
||||||
|
|
||||||
cm.ReadFrameReferenceModeProbs(ref r);
|
cm.ReadFrameReferenceModeProbs(ref r);
|
||||||
|
|
||||||
|
Span<Array9<byte>> yModeProbSpan1 = fc.YModeProb.AsSpan();
|
||||||
|
|
||||||
for (int j = 0; j < EntropyMode.BlockSizeGroups; j++)
|
for (int j = 0; j < EntropyMode.BlockSizeGroups; j++)
|
||||||
{
|
{
|
||||||
|
Span<byte> yModeProbSpan2 = yModeProbSpan1[j].AsSpan();
|
||||||
|
|
||||||
for (int i = 0; i < Constants.IntraModes - 1; ++i)
|
for (int i = 0; i < Constants.IntraModes - 1; ++i)
|
||||||
{
|
{
|
||||||
r.DiffUpdateProb( ref fc.YModeProb[j][i]);
|
r.DiffUpdateProb(ref yModeProbSpan2[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Span<Array3<byte>> partitionProbSpan1 = fc.PartitionProb.AsSpan();
|
||||||
|
|
||||||
for (int j = 0; j < Constants.PartitionContexts; ++j)
|
for (int j = 0; j < Constants.PartitionContexts; ++j)
|
||||||
{
|
{
|
||||||
|
Span<byte> partitionProbSpan2 = partitionProbSpan1[j].AsSpan();
|
||||||
|
|
||||||
for (int i = 0; i < Constants.PartitionTypes - 1; ++i)
|
for (int i = 0; i < Constants.PartitionTypes - 1; ++i)
|
||||||
{
|
{
|
||||||
r.DiffUpdateProb( ref fc.PartitionProb[j][i]);
|
r.DiffUpdateProb(ref partitionProbSpan2[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2095,7 +2186,9 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||||
|
|
||||||
xd.SetupBlockPlanes(cm.SubsamplingX, cm.SubsamplingY);
|
xd.SetupBlockPlanes(cm.SubsamplingX, cm.SubsamplingY);
|
||||||
|
|
||||||
cm.Fc = new Ptr<Vp9EntropyProbs>(ref cm.FrameContexts[(int)cm.FrameContextIdx]);
|
Span<Vp9EntropyProbs> frameContextsSpan = cm.FrameContexts.AsSpan();
|
||||||
|
|
||||||
|
cm.Fc = new Ptr<Vp9EntropyProbs>(ref frameContextsSpan[(int)cm.FrameContextIdx]);
|
||||||
|
|
||||||
xd.Corrupted = false;
|
xd.Corrupted = false;
|
||||||
newFb.Corrupted = ReadCompressedHeader(ref pbi, data, firstPartitionSize) ? 1 : 0;
|
newFb.Corrupted = ReadCompressedHeader(ref pbi, data, firstPartitionSize) ? 1 : 0;
|
||||||
|
|
@ -2164,7 +2257,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||||
// Non frame parallel update frame context here.
|
// Non frame parallel update frame context here.
|
||||||
if (cm.RefreshFrameContext != 0 && contextUpdated == 0)
|
if (cm.RefreshFrameContext != 0 && contextUpdated == 0)
|
||||||
{
|
{
|
||||||
cm.FrameContexts[(int)cm.FrameContextIdx] = cm.Fc.Value;
|
frameContextsSpan[(int)cm.FrameContextIdx] = cm.Fc.Value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -50,9 +50,9 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||||
return PredictionMode.NearestMv + mode;
|
return PredictionMode.NearestMv + mode;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int ReadSegmentId(ref Reader r, ref Array7<byte> segTreeProbs)
|
private static int ReadSegmentId(ref Reader r, ReadOnlySpan<byte> segTreeProbs)
|
||||||
{
|
{
|
||||||
return r.ReadTree(Luts.SegmentTree, segTreeProbs.AsSpan());
|
return r.ReadTree(Luts.SegmentTree, segTreeProbs);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ReadOnlySpan<byte> GetTxProbs(ref Vp9EntropyProbs fc, TxSize maxTxSize, int ctx)
|
private static ReadOnlySpan<byte> GetTxProbs(ref Vp9EntropyProbs fc, TxSize maxTxSize, int ctx)
|
||||||
|
|
@ -181,7 +181,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
segmentId = ReadSegmentId(ref r, ref cm.Fc.Value.SegTreeProb);
|
segmentId = ReadSegmentId(ref r, cm.Fc.Value.SegTreeProb.AsSpan());
|
||||||
SetSegmentId(ref cm, miOffset, xMis, yMis, segmentId);
|
SetSegmentId(ref cm, miOffset, xMis, yMis, segmentId);
|
||||||
return segmentId;
|
return segmentId;
|
||||||
}
|
}
|
||||||
|
|
@ -217,15 +217,15 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||||
|
|
||||||
if (seg.TemporalUpdate)
|
if (seg.TemporalUpdate)
|
||||||
{
|
{
|
||||||
byte predProb = Segmentation.GetPredProbSegId(ref cm.Fc.Value.SegPredProb, ref xd);
|
byte predProb = Segmentation.GetPredProbSegId(cm.Fc.Value.SegPredProb.AsSpan(), ref xd);
|
||||||
mi.SegIdPredicted = (sbyte)r.Read(predProb);
|
mi.SegIdPredicted = (sbyte)r.Read(predProb);
|
||||||
segmentId = mi.SegIdPredicted != 0
|
segmentId = mi.SegIdPredicted != 0
|
||||||
? predictedSegmentId
|
? predictedSegmentId
|
||||||
: ReadSegmentId(ref r, ref cm.Fc.Value.SegTreeProb);
|
: ReadSegmentId(ref r, cm.Fc.Value.SegTreeProb.AsSpan());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
segmentId = ReadSegmentId(ref r, ref cm.Fc.Value.SegTreeProb);
|
segmentId = ReadSegmentId(ref r, cm.Fc.Value.SegTreeProb.AsSpan());
|
||||||
}
|
}
|
||||||
|
|
||||||
SetSegmentId(ref cm, miOffset, xMis, yMis, segmentId);
|
SetSegmentId(ref cm, miOffset, xMis, yMis, segmentId);
|
||||||
|
|
@ -266,10 +266,12 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||||
{
|
{
|
||||||
int n = (int)mvClass + Constants.Class0Bits - 1; // Number of bits
|
int n = (int)mvClass + Constants.Class0Bits - 1; // Number of bits
|
||||||
|
|
||||||
|
Span<byte> bitsSpan = fc.Bits[mvcomp].AsSpan();
|
||||||
|
|
||||||
d = 0;
|
d = 0;
|
||||||
for (int i = 0; i < n; ++i)
|
for (int i = 0; i < n; ++i)
|
||||||
{
|
{
|
||||||
d |= r.Read(fc.Bits[mvcomp][i]) << i;
|
d |= r.Read(bitsSpan[i]) << i;
|
||||||
}
|
}
|
||||||
|
|
||||||
mag = Constants.Class0Size << ((int)mvClass + 2);
|
mag = Constants.Class0Size << ((int)mvClass + 2);
|
||||||
|
|
@ -337,7 +339,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||||
ref MacroBlockD xd,
|
ref MacroBlockD xd,
|
||||||
ref Reader r,
|
ref Reader r,
|
||||||
int segmentId,
|
int segmentId,
|
||||||
ref Array2<sbyte> refFrame)
|
Span<sbyte> refFrame)
|
||||||
{
|
{
|
||||||
ref Vp9EntropyProbs fc = ref cm.Fc.Value;
|
ref Vp9EntropyProbs fc = ref cm.Fc.Value;
|
||||||
|
|
||||||
|
|
@ -412,24 +414,25 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||||
{
|
{
|
||||||
BlockSize bsize = mi.SbType;
|
BlockSize bsize = mi.SbType;
|
||||||
|
|
||||||
|
Span<BModeInfo> bmiSpan = mi.Bmi.AsSpan();
|
||||||
|
|
||||||
switch (bsize)
|
switch (bsize)
|
||||||
{
|
{
|
||||||
case BlockSize.Block4x4:
|
case BlockSize.Block4x4:
|
||||||
for (int i = 0; i < 4; ++i)
|
for (int i = 0; i < 4; ++i)
|
||||||
{
|
{
|
||||||
mi.Bmi[i].Mode = ReadIntraModeY(ref cm, ref xd, ref r, 0);
|
bmiSpan[i].Mode = ReadIntraModeY(ref cm, ref xd, ref r, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
mi.Mode = mi.Bmi[3].Mode;
|
mi.Mode = bmiSpan[3].Mode;
|
||||||
break;
|
break;
|
||||||
case BlockSize.Block4x8:
|
case BlockSize.Block4x8:
|
||||||
mi.Bmi[0].Mode = mi.Bmi[2].Mode = ReadIntraModeY(ref cm, ref xd, ref r, 0);
|
bmiSpan[0].Mode = bmiSpan[2].Mode = ReadIntraModeY(ref cm, ref xd, ref r, 0);
|
||||||
mi.Bmi[1].Mode = mi.Bmi[3].Mode = mi.Mode = ReadIntraModeY(ref cm, ref xd, ref r, 0);
|
bmiSpan[1].Mode = bmiSpan[3].Mode = mi.Mode = ReadIntraModeY(ref cm, ref xd, ref r, 0);
|
||||||
break;
|
break;
|
||||||
case BlockSize.Block8x4:
|
case BlockSize.Block8x4:
|
||||||
mi.Bmi[0].Mode = mi.Bmi[1].Mode = ReadIntraModeY(ref cm, ref xd, ref r, 0);
|
bmiSpan[0].Mode = bmiSpan[1].Mode = ReadIntraModeY(ref cm, ref xd, ref r, 0);
|
||||||
mi.Bmi[2].Mode = mi.Bmi[3].Mode = mi.Mode = ReadIntraModeY(ref cm, ref xd, ref r, 0);
|
bmiSpan[2].Mode = bmiSpan[3].Mode = mi.Mode = ReadIntraModeY(ref cm, ref xd, ref r, 0);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
mi.Mode = ReadIntraModeY(ref cm, ref xd, ref r, Luts.SizeGroupLookup[(int)bsize]);
|
mi.Mode = ReadIntraModeY(ref cm, ref xd, ref r, Luts.SizeGroupLookup[(int)bsize]);
|
||||||
|
|
@ -442,29 +445,19 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||||
// modes in GetPredContextSwitchableInterp()
|
// modes in GetPredContextSwitchableInterp()
|
||||||
mi.InterpFilter = Constants.SwitchableFilters;
|
mi.InterpFilter = Constants.SwitchableFilters;
|
||||||
|
|
||||||
mi.RefFrame[0] = Constants.IntraFrame;
|
Span<sbyte> refFrameSpan = mi.RefFrame.AsSpan();
|
||||||
mi.RefFrame[1] = Constants.None;
|
|
||||||
}
|
refFrameSpan[0] = Constants.IntraFrame;
|
||||||
|
refFrameSpan[1] = Constants.None;
|
||||||
private static void CopyPair(ref Array2<Mv> dst, ref Array2<Mv> src)
|
|
||||||
{
|
|
||||||
dst[0] = src[0];
|
|
||||||
dst[1] = src[1];
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void ZeroPair(ref Array2<Mv> dst)
|
|
||||||
{
|
|
||||||
dst[0] = new Mv();
|
|
||||||
dst[1] = new Mv();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool Assign(
|
private static bool Assign(
|
||||||
ref Vp9Common cm,
|
ref Vp9Common cm,
|
||||||
ref MacroBlockD xd,
|
ref MacroBlockD xd,
|
||||||
PredictionMode mode,
|
PredictionMode mode,
|
||||||
ref Array2<Mv> mv,
|
Span<Mv> mv,
|
||||||
ref Array2<Mv> refMv,
|
Span<Mv> refMv,
|
||||||
ref Array2<Mv> nearNearestMv,
|
Span<Mv> nearNearestMv,
|
||||||
int isCompound,
|
int isCompound,
|
||||||
bool allowHp,
|
bool allowHp,
|
||||||
ref Reader r)
|
ref Reader r)
|
||||||
|
|
@ -486,12 +479,12 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||||
case PredictionMode.NearMv:
|
case PredictionMode.NearMv:
|
||||||
case PredictionMode.NearestMv:
|
case PredictionMode.NearestMv:
|
||||||
{
|
{
|
||||||
CopyPair(ref mv, ref nearNearestMv);
|
nearNearestMv.CopyTo(mv);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case PredictionMode.ZeroMv:
|
case PredictionMode.ZeroMv:
|
||||||
{
|
{
|
||||||
ZeroPair(ref mv);
|
mv.Clear();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default: return false;
|
default: return false;
|
||||||
|
|
@ -553,26 +546,29 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||||
private static bool IsDiffRefFrameAddEb(
|
private static bool IsDiffRefFrameAddEb(
|
||||||
ref ModeInfo mbmi,
|
ref ModeInfo mbmi,
|
||||||
sbyte refFrame,
|
sbyte refFrame,
|
||||||
ref Array4<sbyte> refSignBias,
|
Span<sbyte> refSignBias,
|
||||||
ref int refmvCount,
|
ref int refmvCount,
|
||||||
Span<Mv> mvRefList,
|
Span<Mv> mvRefList,
|
||||||
bool earlyBreak)
|
bool earlyBreak)
|
||||||
{
|
{
|
||||||
if (mbmi.IsInterBlock())
|
if (mbmi.IsInterBlock())
|
||||||
{
|
{
|
||||||
if (mbmi.RefFrame[0] != refFrame)
|
Span<sbyte> refFrameSpan = mbmi.RefFrame.AsSpan();
|
||||||
|
Span<Mv> mvSpan = mbmi.Mv.AsSpan();
|
||||||
|
|
||||||
|
if (refFrameSpan[0] != refFrame)
|
||||||
{
|
{
|
||||||
if (AddRefListEb(mbmi.ScaleMv(0, refFrame, ref refSignBias), ref refmvCount, mvRefList,
|
if (AddRefListEb(mbmi.ScaleMv(0, refFrame, refSignBias), ref refmvCount, mvRefList,
|
||||||
earlyBreak))
|
earlyBreak))
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mbmi.HasSecondRef() && mbmi.RefFrame[1] != refFrame &&
|
if (mbmi.HasSecondRef() && refFrameSpan[1] != refFrame &&
|
||||||
Unsafe.As<Mv, int>(ref mbmi.Mv[1]) != Unsafe.As<Mv, int>(ref mbmi.Mv[0]))
|
Unsafe.As<Mv, int>(ref mvSpan[1]) != Unsafe.As<Mv, int>(ref mvSpan[0]))
|
||||||
{
|
{
|
||||||
if (AddRefListEb(mbmi.ScaleMv(1, refFrame, ref refSignBias), ref refmvCount, mvRefList,
|
if (AddRefListEb(mbmi.ScaleMv(1, refFrame, refSignBias), ref refmvCount, mvRefList,
|
||||||
earlyBreak))
|
earlyBreak))
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
|
|
@ -597,7 +593,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||||
int block,
|
int block,
|
||||||
int isSub8x8)
|
int isSub8x8)
|
||||||
{
|
{
|
||||||
ref Array4<sbyte> refSignBias = ref cm.RefFrameSignBias;
|
Span<sbyte> refSignBias = cm.RefFrameSignBias.AsSpan();
|
||||||
int i, refmvCount = 0;
|
int i, refmvCount = 0;
|
||||||
bool differentRefFound = false;
|
bool differentRefFound = false;
|
||||||
Ptr<MvRef> prevFrameMvs = cm.UsePrevFrameMvs
|
Ptr<MvRef> prevFrameMvs = cm.UsePrevFrameMvs
|
||||||
|
|
@ -624,7 +620,9 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||||
ref ModeInfo candidateMi = ref xd.Mi[mvRef.Col + (mvRef.Row * xd.MiStride)].Value;
|
ref ModeInfo candidateMi = ref xd.Mi[mvRef.Col + (mvRef.Row * xd.MiStride)].Value;
|
||||||
differentRefFound = true;
|
differentRefFound = true;
|
||||||
|
|
||||||
if (candidateMi.RefFrame[0] == refFrame)
|
Span<sbyte> refFrameSpan = candidateMi.RefFrame.AsSpan();
|
||||||
|
|
||||||
|
if (refFrameSpan[0] == refFrame)
|
||||||
{
|
{
|
||||||
if (AddRefListEb(candidateMi.GetSubBlockMv(0, mvRef.Col, block), ref refmvCount,
|
if (AddRefListEb(candidateMi.GetSubBlockMv(0, mvRef.Col, block), ref refmvCount,
|
||||||
mvRefList, earlyBreak))
|
mvRefList, earlyBreak))
|
||||||
|
|
@ -632,7 +630,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||||
goto Done;
|
goto Done;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (candidateMi.RefFrame[1] == refFrame)
|
else if (refFrameSpan[1] == refFrame)
|
||||||
{
|
{
|
||||||
if (AddRefListEb(candidateMi.GetSubBlockMv(1, mvRef.Col, block), ref refmvCount,
|
if (AddRefListEb(candidateMi.GetSubBlockMv(1, mvRef.Col, block), ref refmvCount,
|
||||||
mvRefList, earlyBreak))
|
mvRefList, earlyBreak))
|
||||||
|
|
@ -654,17 +652,20 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||||
{
|
{
|
||||||
ref ModeInfo candidate = ref xd.Mi[mvRef.Col + (mvRef.Row * xd.MiStride)].Value;
|
ref ModeInfo candidate = ref xd.Mi[mvRef.Col + (mvRef.Row * xd.MiStride)].Value;
|
||||||
differentRefFound = true;
|
differentRefFound = true;
|
||||||
|
|
||||||
|
Span<sbyte> refFrameSpan = candidate.RefFrame.AsSpan();
|
||||||
|
Span<Mv> mvSpan = candidate.Mv.AsSpan();
|
||||||
|
|
||||||
if (candidate.RefFrame[0] == refFrame)
|
if (refFrameSpan[0] == refFrame)
|
||||||
{
|
{
|
||||||
if (AddRefListEb(candidate.Mv[0], ref refmvCount, mvRefList, earlyBreak))
|
if (AddRefListEb(mvSpan[0], ref refmvCount, mvRefList, earlyBreak))
|
||||||
{
|
{
|
||||||
goto Done;
|
goto Done;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (candidate.RefFrame[1] == refFrame)
|
else if (refFrameSpan[1] == refFrame)
|
||||||
{
|
{
|
||||||
if (AddRefListEb(candidate.Mv[1], ref refmvCount, mvRefList, earlyBreak))
|
if (AddRefListEb(mvSpan[1], ref refmvCount, mvRefList, earlyBreak))
|
||||||
{
|
{
|
||||||
goto Done;
|
goto Done;
|
||||||
}
|
}
|
||||||
|
|
@ -675,16 +676,19 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||||
// Check the last frame's mode and mv info.
|
// Check the last frame's mode and mv info.
|
||||||
if (!prevFrameMvs.IsNull)
|
if (!prevFrameMvs.IsNull)
|
||||||
{
|
{
|
||||||
if (prevFrameMvs.Value.RefFrame[0] == refFrame)
|
Span<sbyte> refFrameSpan = prevFrameMvs.Value.RefFrame.AsSpan();
|
||||||
|
Span<Mv> mvSpan = prevFrameMvs.Value.Mv.AsSpan();
|
||||||
|
|
||||||
|
if (refFrameSpan[0] == refFrame)
|
||||||
{
|
{
|
||||||
if (AddRefListEb(prevFrameMvs.Value.Mv[0], ref refmvCount, mvRefList, earlyBreak))
|
if (AddRefListEb(mvSpan[0], ref refmvCount, mvRefList, earlyBreak))
|
||||||
{
|
{
|
||||||
goto Done;
|
goto Done;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (prevFrameMvs.Value.RefFrame[1] == refFrame)
|
else if (refFrameSpan[1] == refFrame)
|
||||||
{
|
{
|
||||||
if (AddRefListEb(prevFrameMvs.Value.Mv[1], ref refmvCount, mvRefList, earlyBreak))
|
if (AddRefListEb(mvSpan[1], ref refmvCount, mvRefList, earlyBreak))
|
||||||
{
|
{
|
||||||
goto Done;
|
goto Done;
|
||||||
}
|
}
|
||||||
|
|
@ -704,7 +708,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||||
ref ModeInfo candidate = ref xd.Mi[mvRef.Col + (mvRef.Row * xd.MiStride)].Value;
|
ref ModeInfo candidate = ref xd.Mi[mvRef.Col + (mvRef.Row * xd.MiStride)].Value;
|
||||||
|
|
||||||
// If the candidate is Intra we don't want to consider its mv.
|
// If the candidate is Intra we don't want to consider its mv.
|
||||||
if (IsDiffRefFrameAddEb(ref candidate, refFrame, ref refSignBias, ref refmvCount, mvRefList,
|
if (IsDiffRefFrameAddEb(ref candidate, refFrame, refSignBias, ref refmvCount, mvRefList,
|
||||||
earlyBreak))
|
earlyBreak))
|
||||||
{
|
{
|
||||||
goto Done;
|
goto Done;
|
||||||
|
|
@ -716,10 +720,13 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||||
// Since we still don't have a candidate we'll try the last frame.
|
// Since we still don't have a candidate we'll try the last frame.
|
||||||
if (!prevFrameMvs.IsNull)
|
if (!prevFrameMvs.IsNull)
|
||||||
{
|
{
|
||||||
if (prevFrameMvs.Value.RefFrame[0] != refFrame && prevFrameMvs.Value.RefFrame[0] > Constants.IntraFrame)
|
Span<sbyte> refFrameSpan = prevFrameMvs.Value.RefFrame.AsSpan();
|
||||||
|
Span<Mv> mvSpan = prevFrameMvs.Value.Mv.AsSpan();
|
||||||
|
|
||||||
|
if (refFrameSpan[0] != refFrame && refFrameSpan[0] > Constants.IntraFrame)
|
||||||
{
|
{
|
||||||
Mv mv = prevFrameMvs.Value.Mv[0];
|
Mv mv = mvSpan[0];
|
||||||
if (refSignBias[prevFrameMvs.Value.RefFrame[0]] != refSignBias[refFrame])
|
if (refSignBias[refFrameSpan[0]] != refSignBias[refFrame])
|
||||||
{
|
{
|
||||||
mv.Row *= -1;
|
mv.Row *= -1;
|
||||||
mv.Col *= -1;
|
mv.Col *= -1;
|
||||||
|
|
@ -731,13 +738,13 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (prevFrameMvs.Value.RefFrame[1] > Constants.IntraFrame &&
|
if (refFrameSpan[1] > Constants.IntraFrame &&
|
||||||
prevFrameMvs.Value.RefFrame[1] != refFrame &&
|
refFrameSpan[1] != refFrame &&
|
||||||
Unsafe.As<Mv, int>(ref prevFrameMvs.Value.Mv[1]) !=
|
Unsafe.As<Mv, int>(ref mvSpan[1]) !=
|
||||||
Unsafe.As<Mv, int>(ref prevFrameMvs.Value.Mv[0]))
|
Unsafe.As<Mv, int>(ref mvSpan[0]))
|
||||||
{
|
{
|
||||||
Mv mv = prevFrameMvs.Value.Mv[1];
|
Mv mv = mvSpan[1];
|
||||||
if (refSignBias[prevFrameMvs.Value.RefFrame[1]] != refSignBias[refFrame])
|
if (refSignBias[refFrameSpan[1]] != refSignBias[refFrame])
|
||||||
{
|
{
|
||||||
mv.Row *= -1;
|
mv.Row *= -1;
|
||||||
mv.Col *= -1;
|
mv.Col *= -1;
|
||||||
|
|
@ -783,7 +790,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||||
{
|
{
|
||||||
Span<Mv> mvList = stackalloc Mv[Constants.MaxMvRefCandidates];
|
Span<Mv> mvList = stackalloc Mv[Constants.MaxMvRefCandidates];
|
||||||
ref ModeInfo mi = ref xd.Mi[0].Value;
|
ref ModeInfo mi = ref xd.Mi[0].Value;
|
||||||
ref Array4<BModeInfo> bmi = ref mi.Bmi;
|
Span<BModeInfo> bmi = mi.Bmi.AsSpan();
|
||||||
int refmvCount;
|
int refmvCount;
|
||||||
|
|
||||||
Debug.Assert(Constants.MaxMvRefCandidates == 2);
|
Debug.Assert(Constants.MaxMvRefCandidates == 2);
|
||||||
|
|
@ -878,11 +885,12 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||||
BlockSize bsize = mi.SbType;
|
BlockSize bsize = mi.SbType;
|
||||||
bool allowHp = cm.AllowHighPrecisionMv;
|
bool allowHp = cm.AllowHighPrecisionMv;
|
||||||
Array2<Mv> bestRefMvs = new();
|
Array2<Mv> bestRefMvs = new();
|
||||||
|
Span<Mv> bestRefMvsSpan = bestRefMvs.AsSpan();
|
||||||
int refr, isCompound;
|
int refr, isCompound;
|
||||||
byte interModeCtx;
|
byte interModeCtx;
|
||||||
Span<Position> mvRefSearch = Luts.MvRefBlocks[(int)bsize];
|
Span<Position> mvRefSearch = Luts.MvRefBlocks[(int)bsize];
|
||||||
|
|
||||||
ReadRefFrames(ref cm, ref xd, ref r, mi.SegmentId, ref mi.RefFrame);
|
ReadRefFrames(ref cm, ref xd, ref r, mi.SegmentId, mi.RefFrame.AsSpan());
|
||||||
isCompound = mi.HasSecondRef() ? 1 : 0;
|
isCompound = mi.HasSecondRef() ? 1 : 0;
|
||||||
interModeCtx = GetModeContext(ref cm, ref xd, mvRefSearch, miRow, miCol);
|
interModeCtx = GetModeContext(ref cm, ref xd, mvRefSearch, miRow, miCol);
|
||||||
|
|
||||||
|
|
@ -914,16 +922,17 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||||
if (mi.Mode != PredictionMode.ZeroMv)
|
if (mi.Mode != PredictionMode.ZeroMv)
|
||||||
{
|
{
|
||||||
Span<Mv> tmpMvs = stackalloc Mv[Constants.MaxMvRefCandidates];
|
Span<Mv> tmpMvs = stackalloc Mv[Constants.MaxMvRefCandidates];
|
||||||
|
Span<sbyte> refFrameSpan = mi.RefFrame.AsSpan();
|
||||||
|
|
||||||
for (refr = 0; refr < 1 + isCompound; ++refr)
|
for (refr = 0; refr < 1 + isCompound; ++refr)
|
||||||
{
|
{
|
||||||
sbyte frame = mi.RefFrame[refr];
|
sbyte frame = refFrameSpan[refr];
|
||||||
int refmvCount;
|
int refmvCount;
|
||||||
|
|
||||||
refmvCount = DecFindRefs(ref cm, ref xd, mi.Mode, frame, mvRefSearch, tmpMvs, miRow, miCol,
|
refmvCount = DecFindRefs(ref cm, ref xd, mi.Mode, frame, mvRefSearch, tmpMvs, miRow, miCol,
|
||||||
-1, 0);
|
-1, 0);
|
||||||
|
|
||||||
DecFindBestRefs(allowHp, tmpMvs, ref bestRefMvs[refr], refmvCount);
|
DecFindBestRefs(allowHp, tmpMvs, ref bestRefMvsSpan[refr], refmvCount);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -939,10 +948,12 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||||
int idx, idy;
|
int idx, idy;
|
||||||
PredictionMode bMode = 0;
|
PredictionMode bMode = 0;
|
||||||
Array2<Mv> bestSub8x8 = new();
|
Array2<Mv> bestSub8x8 = new();
|
||||||
|
Span<Mv> bestSub8x8Span = bestSub8x8.AsSpan();
|
||||||
|
Span<BModeInfo> bmiSpan = mi.Bmi.AsSpan();
|
||||||
const uint invalidMv = 0x80008000;
|
const uint invalidMv = 0x80008000;
|
||||||
// Initialize the 2nd element as even though it won't be used meaningfully
|
// Initialize the 2nd element as even though it won't be used meaningfully
|
||||||
// if isCompound is false.
|
// if isCompound is false.
|
||||||
Unsafe.As<Mv, uint>(ref bestSub8x8[1]) = invalidMv;
|
Unsafe.As<Mv, uint>(ref bestSub8x8Span[1]) = invalidMv;
|
||||||
for (idy = 0; idy < 2; idy += num4x4H)
|
for (idy = 0; idy < 2; idy += num4x4H)
|
||||||
{
|
{
|
||||||
for (idx = 0; idx < 2; idx += num4x4W)
|
for (idx = 0; idx < 2; idx += num4x4W)
|
||||||
|
|
@ -955,11 +966,11 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||||
for (refr = 0; refr < 1 + isCompound; ++refr)
|
for (refr = 0; refr < 1 + isCompound; ++refr)
|
||||||
{
|
{
|
||||||
AppendSub8x8ForIdx(ref cm, ref xd, mvRefSearch, bMode, j, refr, miRow, miCol,
|
AppendSub8x8ForIdx(ref cm, ref xd, mvRefSearch, bMode, j, refr, miRow, miCol,
|
||||||
ref bestSub8x8[refr]);
|
ref bestSub8x8Span[refr]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!Assign(ref cm, ref xd, bMode, ref mi.Bmi[j].Mv, ref bestRefMvs, ref bestSub8x8,
|
if (!Assign(ref cm, ref xd, bMode, bmiSpan[j].Mv.AsSpan(), bestRefMvs.AsSpan(), bestSub8x8.AsSpan(),
|
||||||
isCompound, allowHp, ref r))
|
isCompound, allowHp, ref r))
|
||||||
{
|
{
|
||||||
xd.Corrupted |= true;
|
xd.Corrupted |= true;
|
||||||
|
|
@ -968,23 +979,22 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||||
|
|
||||||
if (num4x4H == 2)
|
if (num4x4H == 2)
|
||||||
{
|
{
|
||||||
mi.Bmi[j + 2] = mi.Bmi[j];
|
bmiSpan[j + 2] = bmiSpan[j];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (num4x4W == 2)
|
if (num4x4W == 2)
|
||||||
{
|
{
|
||||||
mi.Bmi[j + 1] = mi.Bmi[j];
|
bmiSpan[j + 1] = bmiSpan[j];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mi.Mode = bMode;
|
mi.Mode = bMode;
|
||||||
|
bmiSpan[3].Mv.AsSpan().CopyTo(mi.Mv.AsSpan());
|
||||||
CopyPair(ref mi.Mv, ref mi.Bmi[3].Mv);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
xd.Corrupted |= !Assign(ref cm, ref xd, mi.Mode, ref mi.Mv, ref bestRefMvs, ref bestRefMvs,
|
xd.Corrupted |= !Assign(ref cm, ref xd, mi.Mode, mi.Mv.AsSpan(), bestRefMvs.AsSpan(), bestRefMvs.AsSpan(),
|
||||||
isCompound, allowHp, ref r);
|
isCompound, allowHp, ref r);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1076,33 +1086,42 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||||
|
|
||||||
int miOffset = (miRow * cm.MiCols) + miCol;
|
int miOffset = (miRow * cm.MiCols) + miCol;
|
||||||
|
|
||||||
|
Span<sbyte> refFrameSpan = mi.Value.RefFrame.AsSpan();
|
||||||
|
|
||||||
mi.Value.SegmentId = (sbyte)ReadIntraSegmentId(ref cm, miOffset, xMis, yMis, ref r);
|
mi.Value.SegmentId = (sbyte)ReadIntraSegmentId(ref cm, miOffset, xMis, yMis, ref r);
|
||||||
mi.Value.Skip = (sbyte)ReadSkip(ref cm, ref xd, mi.Value.SegmentId, ref r);
|
mi.Value.Skip = (sbyte)ReadSkip(ref cm, ref xd, mi.Value.SegmentId, ref r);
|
||||||
mi.Value.TxSize = ReadTxSize(ref cm, ref xd, true, ref r);
|
mi.Value.TxSize = ReadTxSize(ref cm, ref xd, true, ref r);
|
||||||
mi.Value.RefFrame[0] = Constants.IntraFrame;
|
refFrameSpan[0] = Constants.IntraFrame;
|
||||||
mi.Value.RefFrame[1] = Constants.None;
|
refFrameSpan[1] = Constants.None;
|
||||||
|
|
||||||
|
Span<BModeInfo> bmiSpan;
|
||||||
switch (bsize)
|
switch (bsize)
|
||||||
{
|
{
|
||||||
case BlockSize.Block4x4:
|
case BlockSize.Block4x4:
|
||||||
|
bmiSpan = mi.Value.Bmi.AsSpan();
|
||||||
|
|
||||||
for (int i = 0; i < 4; ++i)
|
for (int i = 0; i < 4; ++i)
|
||||||
{
|
{
|
||||||
mi.Value.Bmi[i].Mode =
|
bmiSpan[i].Mode =
|
||||||
ReadIntraMode(ref r, GetYModeProbs(ref cm.Fc.Value, mi, aboveMi, leftMi, i));
|
ReadIntraMode(ref r, GetYModeProbs(ref cm.Fc.Value, mi, aboveMi, leftMi, i));
|
||||||
}
|
}
|
||||||
|
|
||||||
mi.Value.Mode = mi.Value.Bmi[3].Mode;
|
mi.Value.Mode = bmiSpan[3].Mode;
|
||||||
break;
|
break;
|
||||||
case BlockSize.Block4x8:
|
case BlockSize.Block4x8:
|
||||||
mi.Value.Bmi[0].Mode = mi.Value.Bmi[2].Mode =
|
bmiSpan = mi.Value.Bmi.AsSpan();
|
||||||
|
|
||||||
|
bmiSpan[0].Mode = bmiSpan[2].Mode =
|
||||||
ReadIntraMode(ref r, GetYModeProbs(ref cm.Fc.Value, mi, aboveMi, leftMi, 0));
|
ReadIntraMode(ref r, GetYModeProbs(ref cm.Fc.Value, mi, aboveMi, leftMi, 0));
|
||||||
mi.Value.Bmi[1].Mode = mi.Value.Bmi[3].Mode = mi.Value.Mode =
|
bmiSpan[1].Mode = bmiSpan[3].Mode = mi.Value.Mode =
|
||||||
ReadIntraMode(ref r, GetYModeProbs(ref cm.Fc.Value, mi, aboveMi, leftMi, 1));
|
ReadIntraMode(ref r, GetYModeProbs(ref cm.Fc.Value, mi, aboveMi, leftMi, 1));
|
||||||
break;
|
break;
|
||||||
case BlockSize.Block8x4:
|
case BlockSize.Block8x4:
|
||||||
mi.Value.Bmi[0].Mode = mi.Value.Bmi[1].Mode =
|
bmiSpan = mi.Value.Bmi.AsSpan();
|
||||||
|
|
||||||
|
bmiSpan[0].Mode = bmiSpan[1].Mode =
|
||||||
ReadIntraMode(ref r, GetYModeProbs(ref cm.Fc.Value, mi, aboveMi, leftMi, 0));
|
ReadIntraMode(ref r, GetYModeProbs(ref cm.Fc.Value, mi, aboveMi, leftMi, 0));
|
||||||
mi.Value.Bmi[2].Mode = mi.Value.Bmi[3].Mode = mi.Value.Mode =
|
bmiSpan[2].Mode = bmiSpan[3].Mode = mi.Value.Mode =
|
||||||
ReadIntraMode(ref r, GetYModeProbs(ref cm.Fc.Value, mi, aboveMi, leftMi, 2));
|
ReadIntraMode(ref r, GetYModeProbs(ref cm.Fc.Value, mi, aboveMi, leftMi, 2));
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
|
@ -1113,12 +1132,6 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||||
mi.Value.UvMode = ReadIntraMode(ref r, cm.Fc.Value.KfUvModeProb[(int)mi.Value.Mode].AsSpan());
|
mi.Value.UvMode = ReadIntraMode(ref r, cm.Fc.Value.KfUvModeProb[(int)mi.Value.Mode].AsSpan());
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void CopyRefFramePair(ref Array2<sbyte> dst, ref Array2<sbyte> src)
|
|
||||||
{
|
|
||||||
dst[0] = src[0];
|
|
||||||
dst[1] = src[1];
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void ReadModeInfo(
|
public static void ReadModeInfo(
|
||||||
ref TileWorkerData twd,
|
ref TileWorkerData twd,
|
||||||
ref Vp9Common cm,
|
ref Vp9Common cm,
|
||||||
|
|
@ -1145,8 +1158,8 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||||
for (int w = 0; w < xMis; ++w)
|
for (int w = 0; w < xMis; ++w)
|
||||||
{
|
{
|
||||||
ref MvRef mv = ref frameMvs[w];
|
ref MvRef mv = ref frameMvs[w];
|
||||||
CopyRefFramePair(ref mv.RefFrame, ref mi.RefFrame);
|
mi.RefFrame.AsSpan().CopyTo(mv.RefFrame.AsSpan());
|
||||||
CopyPair(ref mv.Mv, ref mi.Mv);
|
mi.Mv.AsSpan().CopyTo(mv.Mv.AsSpan());
|
||||||
}
|
}
|
||||||
|
|
||||||
frameMvs = frameMvs.Slice(cm.MiCols);
|
frameMvs = frameMvs.Slice(cm.MiCols);
|
||||||
|
|
@ -1154,4 +1167,4 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -85,12 +85,10 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||||
cm.Lf.RefDeltas = pictureInfo.RefDeltas;
|
cm.Lf.RefDeltas = pictureInfo.RefDeltas;
|
||||||
cm.Lf.ModeDeltas = pictureInfo.ModeDeltas;
|
cm.Lf.ModeDeltas = pictureInfo.ModeDeltas;
|
||||||
|
|
||||||
cm.Fc = new Ptr<Vp9EntropyProbs>(ref pictureInfo.Entropy);
|
Span<RefBuffer> frameRefsSpan = cm.FrameRefs.AsSpan();
|
||||||
cm.Counts = new Ptr<Vp9BackwardUpdates>(ref pictureInfo.BackwardUpdateCounts);
|
frameRefsSpan[0].Buf = (Surface)pictureInfo.LastReference;
|
||||||
|
frameRefsSpan[1].Buf = (Surface)pictureInfo.GoldenReference;
|
||||||
cm.FrameRefs[0].Buf = (Surface)pictureInfo.LastReference;
|
frameRefsSpan[2].Buf = (Surface)pictureInfo.AltReference;
|
||||||
cm.FrameRefs[1].Buf = (Surface)pictureInfo.GoldenReference;
|
|
||||||
cm.FrameRefs[2].Buf = (Surface)pictureInfo.AltReference;
|
|
||||||
cm.Mb.CurBuf = (Surface)output;
|
cm.Mb.CurBuf = (Surface)output;
|
||||||
|
|
||||||
cm.Mb.SetupBlockPlanes(1, 1);
|
cm.Mb.SetupBlockPlanes(1, 1);
|
||||||
|
|
@ -164,4 +162,4 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||||
_allocator.Dispose();
|
_allocator.Dispose();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||||
PlaneType type,
|
PlaneType type,
|
||||||
Span<int> dqcoeff,
|
Span<int> dqcoeff,
|
||||||
TxSize txSize,
|
TxSize txSize,
|
||||||
ref Array2<short> dq,
|
ReadOnlySpan<short> dq,
|
||||||
int ctx,
|
int ctx,
|
||||||
ReadOnlySpan<short> scan,
|
ReadOnlySpan<short> scan,
|
||||||
ReadOnlySpan<short> nb,
|
ReadOnlySpan<short> nb,
|
||||||
|
|
@ -39,7 +39,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||||
ref Vp9EntropyProbs fc = ref xd.Fc.Value;
|
ref Vp9EntropyProbs fc = ref xd.Fc.Value;
|
||||||
int refr = xd.Mi[0].Value.IsInterBlock() ? 1 : 0;
|
int refr = xd.Mi[0].Value.IsInterBlock() ? 1 : 0;
|
||||||
int band, c = 0;
|
int band, c = 0;
|
||||||
ref Array6<Array6<Array3<byte>>> coefProbs = ref fc.CoefProbs[(int)txSize][(int)type][refr];
|
ReadOnlySpan<Array6<Array3<byte>>> coefProbs = fc.CoefProbs[(int)txSize][(int)type][refr].AsSpan();
|
||||||
Span<byte> tokenCache = stackalloc byte[32 * 32];
|
Span<byte> tokenCache = stackalloc byte[32 * 32];
|
||||||
ReadOnlySpan<byte> bandTranslate = Luts.GetBandTranslate(txSize);
|
ReadOnlySpan<byte> bandTranslate = Luts.GetBandTranslate(txSize);
|
||||||
int dqShift = txSize == TxSize.Tx32x32 ? 1 : 0;
|
int dqShift = txSize == TxSize.Tx32x32 ? 1 : 0;
|
||||||
|
|
@ -56,23 +56,26 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||||
ulong value = r.Value;
|
ulong value = r.Value;
|
||||||
uint range = r.Range;
|
uint range = r.Range;
|
||||||
int count = r.Count;
|
int count = r.Count;
|
||||||
|
|
||||||
|
ReadOnlySpan<Array6<Array4<uint>>> coefSpan = counts.Coef[(int)txSize][(int)type][refr].AsSpan();
|
||||||
|
ReadOnlySpan<Array6<uint>> eobBranchSpan = counts.EobBranch[(int)txSize][(int)type][refr].AsSpan();
|
||||||
|
|
||||||
while (c < maxEob)
|
while (c < maxEob)
|
||||||
{
|
{
|
||||||
int val = -1;
|
int val = -1;
|
||||||
band = bandTranslate[0];
|
band = bandTranslate[0];
|
||||||
bandTranslate = bandTranslate.Slice(1);
|
bandTranslate = bandTranslate.Slice(1);
|
||||||
ref Array3<byte> prob = ref coefProbs[band][ctx];
|
ReadOnlySpan<byte> prob = coefProbs[band][ctx].AsSpan();
|
||||||
if (!xd.Counts.IsNull)
|
if (!xd.Counts.IsNull)
|
||||||
{
|
{
|
||||||
++counts.EobBranch[(int)txSize][(int)type][refr][band][ctx];
|
++eobBranchSpan[band][ctx];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (r.ReadBool(prob[EobContextNode], ref value, ref count, ref range) == 0)
|
if (r.ReadBool(prob[EobContextNode], ref value, ref count, ref range) == 0)
|
||||||
{
|
{
|
||||||
if (!xd.Counts.IsNull)
|
if (!xd.Counts.IsNull)
|
||||||
{
|
{
|
||||||
++counts.Coef[(int)txSize][(int)type][refr][band][ctx][Constants.EobModelToken];
|
++coefSpan[band][ctx][Constants.EobModelToken];
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
@ -82,7 +85,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||||
{
|
{
|
||||||
if (!xd.Counts.IsNull)
|
if (!xd.Counts.IsNull)
|
||||||
{
|
{
|
||||||
++counts.Coef[(int)txSize][(int)type][refr][band][ctx][Constants.ZeroToken];
|
++coefSpan[band][ctx][Constants.ZeroToken];
|
||||||
}
|
}
|
||||||
|
|
||||||
dqv = dq[1];
|
dqv = dq[1];
|
||||||
|
|
@ -99,7 +102,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||||
ctx = GetCoefContext(nb, tokenCache, c);
|
ctx = GetCoefContext(nb, tokenCache, c);
|
||||||
band = bandTranslate[0];
|
band = bandTranslate[0];
|
||||||
bandTranslate = bandTranslate.Slice(1);
|
bandTranslate = bandTranslate.Slice(1);
|
||||||
prob = ref coefProbs[band][ctx];
|
prob = coefProbs[band][ctx].AsSpan();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (r.ReadBool(prob[OneContextNode], ref value, ref count, ref range) != 0)
|
if (r.ReadBool(prob[OneContextNode], ref value, ref count, ref range) != 0)
|
||||||
|
|
@ -107,7 +110,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||||
ReadOnlySpan<byte> p = Luts.Pareto8Full[prob[Constants.PivotNode] - 1];
|
ReadOnlySpan<byte> p = Luts.Pareto8Full[prob[Constants.PivotNode] - 1];
|
||||||
if (!xd.Counts.IsNull)
|
if (!xd.Counts.IsNull)
|
||||||
{
|
{
|
||||||
++counts.Coef[(int)txSize][(int)type][refr][band][ctx][Constants.TwoToken];
|
++coefSpan[band][ctx][Constants.TwoToken];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (r.ReadBool(p[0], ref value, ref count, ref range) != 0)
|
if (r.ReadBool(p[0], ref value, ref count, ref range) != 0)
|
||||||
|
|
@ -175,7 +178,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||||
{
|
{
|
||||||
if (!xd.Counts.IsNull)
|
if (!xd.Counts.IsNull)
|
||||||
{
|
{
|
||||||
++counts.Coef[(int)txSize][(int)type][refr][band][ctx][Constants.OneToken];
|
++coefSpan[band][ctx][Constants.OneToken];
|
||||||
}
|
}
|
||||||
|
|
||||||
tokenCache[scan[c]] = 1;
|
tokenCache[scan[c]] = 1;
|
||||||
|
|
@ -232,7 +235,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||||
ref Reader r = ref twd.BitReader;
|
ref Reader r = ref twd.BitReader;
|
||||||
ref MacroBlockD xd = ref twd.Xd;
|
ref MacroBlockD xd = ref twd.Xd;
|
||||||
ref MacroBlockDPlane pd = ref xd.Plane[plane];
|
ref MacroBlockDPlane pd = ref xd.Plane[plane];
|
||||||
ref Array2<short> dequant = ref pd.SegDequant[segId];
|
Span<short> dequant = pd.SegDequant[segId].AsSpan();
|
||||||
int eob;
|
int eob;
|
||||||
Span<sbyte> a = pd.AboveContext.AsSpan().Slice(x);
|
Span<sbyte> a = pd.AboveContext.AsSpan().Slice(x);
|
||||||
Span<sbyte> l = pd.LeftContext.AsSpan().Slice(y);
|
Span<sbyte> l = pd.LeftContext.AsSpan().Slice(y);
|
||||||
|
|
@ -250,7 +253,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||||
GetPlaneType(plane),
|
GetPlaneType(plane),
|
||||||
pd.DqCoeff.AsSpan(),
|
pd.DqCoeff.AsSpan(),
|
||||||
txSize,
|
txSize,
|
||||||
ref dequant,
|
dequant,
|
||||||
ctx,
|
ctx,
|
||||||
sc.Scan,
|
sc.Scan,
|
||||||
sc.Neighbors,
|
sc.Neighbors,
|
||||||
|
|
@ -266,7 +269,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||||
GetPlaneType(plane),
|
GetPlaneType(plane),
|
||||||
pd.DqCoeff.AsSpan(),
|
pd.DqCoeff.AsSpan(),
|
||||||
txSize,
|
txSize,
|
||||||
ref dequant,
|
dequant,
|
||||||
ctx,
|
ctx,
|
||||||
sc.Scan,
|
sc.Scan,
|
||||||
sc.Neighbors,
|
sc.Neighbors,
|
||||||
|
|
@ -283,7 +286,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||||
GetPlaneType(plane),
|
GetPlaneType(plane),
|
||||||
pd.DqCoeff.AsSpan(),
|
pd.DqCoeff.AsSpan(),
|
||||||
txSize,
|
txSize,
|
||||||
ref dequant,
|
dequant,
|
||||||
ctx,
|
ctx,
|
||||||
sc.Scan,
|
sc.Scan,
|
||||||
sc.Neighbors,
|
sc.Neighbors,
|
||||||
|
|
@ -303,7 +306,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||||
GetPlaneType(plane),
|
GetPlaneType(plane),
|
||||||
pd.DqCoeff.AsSpan(),
|
pd.DqCoeff.AsSpan(),
|
||||||
txSize,
|
txSize,
|
||||||
ref dequant,
|
dequant,
|
||||||
ctx,
|
ctx,
|
||||||
sc.Scan,
|
sc.Scan,
|
||||||
sc.Neighbors,
|
sc.Neighbors,
|
||||||
|
|
@ -320,4 +323,4 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||||
return eob;
|
return eob;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
using Ryujinx.Common.Memory;
|
using Ryujinx.Common.Memory;
|
||||||
using Ryujinx.Graphics.Nvdec.Vp9.Common;
|
using Ryujinx.Graphics.Nvdec.Vp9.Common;
|
||||||
|
using System;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using System.Runtime.Intrinsics;
|
using System.Runtime.Intrinsics;
|
||||||
|
|
@ -129,7 +130,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Dsp
|
||||||
for (int x = 0; x < w; ++x)
|
for (int x = 0; x < w; ++x)
|
||||||
{
|
{
|
||||||
byte* srcX = &src[xQ4 >> SubpelBits];
|
byte* srcX = &src[xQ4 >> SubpelBits];
|
||||||
ref Array8<short> xFilter = ref xFilters[xQ4 & SubpelMask];
|
Span<short> xFilter = xFilters[xQ4 & SubpelMask].AsSpan();
|
||||||
int sum = 0;
|
int sum = 0;
|
||||||
for (int k = 0; k < SubpelTaps; ++k)
|
for (int k = 0; k < SubpelTaps; ++k)
|
||||||
{
|
{
|
||||||
|
|
@ -164,7 +165,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Dsp
|
||||||
for (int x = 0; x < w; ++x)
|
for (int x = 0; x < w; ++x)
|
||||||
{
|
{
|
||||||
byte* srcX = &src[xQ4 >> SubpelBits];
|
byte* srcX = &src[xQ4 >> SubpelBits];
|
||||||
ref Array8<short> xFilter = ref xFilters[xQ4 & SubpelMask];
|
Span<short> xFilter = xFilters[xQ4 & SubpelMask].AsSpan();
|
||||||
int sum = 0;
|
int sum = 0;
|
||||||
for (int k = 0; k < SubpelTaps; ++k)
|
for (int k = 0; k < SubpelTaps; ++k)
|
||||||
{
|
{
|
||||||
|
|
@ -275,7 +276,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Dsp
|
||||||
for (int y = 0; y < h; ++y)
|
for (int y = 0; y < h; ++y)
|
||||||
{
|
{
|
||||||
byte* srcY = &src[(yQ4 >> SubpelBits) * srcStride];
|
byte* srcY = &src[(yQ4 >> SubpelBits) * srcStride];
|
||||||
ref Array8<short> yFilter = ref yFilters[yQ4 & SubpelMask];
|
Span<short> yFilter = yFilters[yQ4 & SubpelMask].AsSpan();
|
||||||
int sum = 0;
|
int sum = 0;
|
||||||
for (int k = 0; k < SubpelTaps; ++k)
|
for (int k = 0; k < SubpelTaps; ++k)
|
||||||
{
|
{
|
||||||
|
|
@ -310,7 +311,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Dsp
|
||||||
for (int y = 0; y < h; ++y)
|
for (int y = 0; y < h; ++y)
|
||||||
{
|
{
|
||||||
byte* srcY = &src[(yQ4 >> SubpelBits) * srcStride];
|
byte* srcY = &src[(yQ4 >> SubpelBits) * srcStride];
|
||||||
ref Array8<short> yFilter = ref yFilters[yQ4 & SubpelMask];
|
Span<short> yFilter = yFilters[yQ4 & SubpelMask].AsSpan();
|
||||||
int sum = 0;
|
int sum = 0;
|
||||||
for (int k = 0; k < SubpelTaps; ++k)
|
for (int k = 0; k < SubpelTaps; ++k)
|
||||||
{
|
{
|
||||||
|
|
@ -619,7 +620,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Dsp
|
||||||
for (int x = 0; x < w; ++x)
|
for (int x = 0; x < w; ++x)
|
||||||
{
|
{
|
||||||
ushort* srcX = &src[xQ4 >> SubpelBits];
|
ushort* srcX = &src[xQ4 >> SubpelBits];
|
||||||
ref Array8<short> xFilter = ref xFilters[xQ4 & SubpelMask];
|
Span<short> xFilter = xFilters[xQ4 & SubpelMask].AsSpan();
|
||||||
int sum = 0;
|
int sum = 0;
|
||||||
for (int k = 0; k < SubpelTaps; ++k)
|
for (int k = 0; k < SubpelTaps; ++k)
|
||||||
{
|
{
|
||||||
|
|
@ -655,7 +656,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Dsp
|
||||||
for (int x = 0; x < w; ++x)
|
for (int x = 0; x < w; ++x)
|
||||||
{
|
{
|
||||||
ushort* srcX = &src[xQ4 >> SubpelBits];
|
ushort* srcX = &src[xQ4 >> SubpelBits];
|
||||||
ref Array8<short> xFilter = ref xFilters[xQ4 & SubpelMask];
|
Span<short> xFilter = xFilters[xQ4 & SubpelMask].AsSpan();
|
||||||
int sum = 0;
|
int sum = 0;
|
||||||
for (int k = 0; k < SubpelTaps; ++k)
|
for (int k = 0; k < SubpelTaps; ++k)
|
||||||
{
|
{
|
||||||
|
|
@ -692,7 +693,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Dsp
|
||||||
for (int y = 0; y < h; ++y)
|
for (int y = 0; y < h; ++y)
|
||||||
{
|
{
|
||||||
ushort* srcY = &src[(yQ4 >> SubpelBits) * srcStride];
|
ushort* srcY = &src[(yQ4 >> SubpelBits) * srcStride];
|
||||||
ref Array8<short> yFilter = ref yFilters[yQ4 & SubpelMask];
|
Span<short> yFilter = yFilters[yQ4 & SubpelMask].AsSpan();
|
||||||
int sum = 0;
|
int sum = 0;
|
||||||
for (int k = 0; k < SubpelTaps; ++k)
|
for (int k = 0; k < SubpelTaps; ++k)
|
||||||
{
|
{
|
||||||
|
|
@ -728,7 +729,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Dsp
|
||||||
for (int y = 0; y < h; ++y)
|
for (int y = 0; y < h; ++y)
|
||||||
{
|
{
|
||||||
ushort* srcY = &src[(yQ4 >> SubpelBits) * srcStride];
|
ushort* srcY = &src[(yQ4 >> SubpelBits) * srcStride];
|
||||||
ref Array8<short> yFilter = ref yFilters[yQ4 & SubpelMask];
|
Span<short> yFilter = yFilters[yQ4 & SubpelMask].AsSpan();
|
||||||
int sum = 0;
|
int sum = 0;
|
||||||
for (int k = 0; k < SubpelTaps; ++k)
|
for (int k = 0; k < SubpelTaps; ++k)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -304,31 +304,40 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static void TxCountsToBranchCounts32x32(ReadOnlySpan<uint> txCount32x32P,
|
internal static void TxCountsToBranchCounts32x32(ReadOnlySpan<uint> txCount32x32P,
|
||||||
ref Array3<Array2<uint>> ct32x32P)
|
ReadOnlySpan<Array2<uint>> ct32x32P)
|
||||||
{
|
{
|
||||||
ct32x32P[0][0] = txCount32x32P[(int)TxSize.Tx4x4];
|
Span<uint> ct32x32PSpan0 = ct32x32P[0].AsSpan();
|
||||||
ct32x32P[0][1] = txCount32x32P[(int)TxSize.Tx8x8] + txCount32x32P[(int)TxSize.Tx16x16] +
|
Span<uint> ct32x32PSpan1 = ct32x32P[1].AsSpan();
|
||||||
txCount32x32P[(int)TxSize.Tx32x32];
|
Span<uint> ct32x32PSpan2 = ct32x32P[2].AsSpan();
|
||||||
ct32x32P[1][0] = txCount32x32P[(int)TxSize.Tx8x8];
|
|
||||||
ct32x32P[1][1] = txCount32x32P[(int)TxSize.Tx16x16] + txCount32x32P[(int)TxSize.Tx32x32];
|
ct32x32PSpan0[0] = txCount32x32P[(int)TxSize.Tx4x4];
|
||||||
ct32x32P[2][0] = txCount32x32P[(int)TxSize.Tx16x16];
|
ct32x32PSpan0[1] = txCount32x32P[(int)TxSize.Tx8x8] + txCount32x32P[(int)TxSize.Tx16x16] +
|
||||||
ct32x32P[2][1] = txCount32x32P[(int)TxSize.Tx32x32];
|
txCount32x32P[(int)TxSize.Tx32x32];
|
||||||
|
ct32x32PSpan1[0] = txCount32x32P[(int)TxSize.Tx8x8];
|
||||||
|
ct32x32PSpan1[1] = txCount32x32P[(int)TxSize.Tx16x16] + txCount32x32P[(int)TxSize.Tx32x32];
|
||||||
|
ct32x32PSpan2[0] = txCount32x32P[(int)TxSize.Tx16x16];
|
||||||
|
ct32x32PSpan2[1] = txCount32x32P[(int)TxSize.Tx32x32];
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static void TxCountsToBranchCounts16x16(ReadOnlySpan<uint> txCount16x16P,
|
internal static void TxCountsToBranchCounts16x16(ReadOnlySpan<uint> txCount16x16P,
|
||||||
ref Array2<Array2<uint>> ct16x16P)
|
ReadOnlySpan<Array2<uint>> ct16x16P)
|
||||||
{
|
{
|
||||||
ct16x16P[0][0] = txCount16x16P[(int)TxSize.Tx4x4];
|
Span<uint> ct16x16PSpan0 = ct16x16P[0].AsSpan();
|
||||||
ct16x16P[0][1] = txCount16x16P[(int)TxSize.Tx8x8] + txCount16x16P[(int)TxSize.Tx16x16];
|
Span<uint> ct16x16PSpan1 = ct16x16P[1].AsSpan();
|
||||||
ct16x16P[1][0] = txCount16x16P[(int)TxSize.Tx8x8];
|
|
||||||
ct16x16P[1][1] = txCount16x16P[(int)TxSize.Tx16x16];
|
ct16x16PSpan0[0] = txCount16x16P[(int)TxSize.Tx4x4];
|
||||||
|
ct16x16PSpan0[1] = txCount16x16P[(int)TxSize.Tx8x8] + txCount16x16P[(int)TxSize.Tx16x16];
|
||||||
|
ct16x16PSpan1[0] = txCount16x16P[(int)TxSize.Tx8x8];
|
||||||
|
ct16x16PSpan1[1] = txCount16x16P[(int)TxSize.Tx16x16];
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static void TxCountsToBranchCounts8x8(ReadOnlySpan<uint> txCount8x8P,
|
internal static void TxCountsToBranchCounts8x8(ReadOnlySpan<uint> txCount8x8P,
|
||||||
ref Array1<Array2<uint>> ct8x8P)
|
ReadOnlySpan<Array2<uint>> ct8x8P)
|
||||||
{
|
{
|
||||||
ct8x8P[0][0] = txCount8x8P[(int)TxSize.Tx4x4];
|
Span<uint> ct8x8PSpan = ct8x8P[0].AsSpan();
|
||||||
ct8x8P[0][1] = txCount8x8P[(int)TxSize.Tx8x8];
|
|
||||||
|
ct8x8PSpan[0] = txCount8x8P[(int)TxSize.Tx4x4];
|
||||||
|
ct8x8PSpan[1] = txCount8x8P[(int)TxSize.Tx8x8];
|
||||||
}
|
}
|
||||||
|
|
||||||
public static unsafe void SetupPastIndependence(ref Vp9Common cm)
|
public static unsafe void SetupPastIndependence(ref Vp9Common cm)
|
||||||
|
|
|
||||||
|
|
@ -378,9 +378,11 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||||
|
|
||||||
int index = shiftY;
|
int index = shiftY;
|
||||||
|
|
||||||
|
Span<byte> lflYSpan = lfm.LflY.AsSpan();
|
||||||
|
|
||||||
for (int i = 0; i < bh; i++)
|
for (int i = 0; i < bh; i++)
|
||||||
{
|
{
|
||||||
MemoryMarshal.CreateSpan(ref lfm.LflY[index], 64 - index).Slice(0, bw).Fill((byte)filterLevel);
|
MemoryMarshal.CreateSpan(ref lflYSpan[index], 64 - index).Slice(0, bw).Fill((byte)filterLevel);
|
||||||
index += 8;
|
index += 8;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -445,25 +447,29 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||||
const ushort leftBorderUv = 0x1111;
|
const ushort leftBorderUv = 0x1111;
|
||||||
const ushort aboveBorderUv = 0x000f;
|
const ushort aboveBorderUv = 0x000f;
|
||||||
|
|
||||||
|
Span<ulong> leftYSpan = lfm.LeftY.AsSpan();
|
||||||
|
Span<ulong> aboveYSpan = lfm.AboveY.AsSpan();
|
||||||
|
Span<ushort> leftUvSpan = lfm.LeftUv.AsSpan();
|
||||||
|
Span<ushort> aboveUvSpan = lfm.AboveUv.AsSpan();
|
||||||
|
|
||||||
// The largest loopfilter we have is 16x16 so we use the 16x16 mask
|
// The largest loopfilter we have is 16x16 so we use the 16x16 mask
|
||||||
// for 32x32 transforms also.
|
// for 32x32 transforms also.
|
||||||
lfm.LeftY[(int)TxSize.Tx16x16] |= lfm.LeftY[(int)TxSize.Tx32x32];
|
leftYSpan[(int)TxSize.Tx16x16] |= leftYSpan[(int)TxSize.Tx32x32];
|
||||||
lfm.AboveY[(int)TxSize.Tx16x16] |= lfm.AboveY[(int)TxSize.Tx32x32];
|
aboveYSpan[(int)TxSize.Tx16x16] |= aboveYSpan[(int)TxSize.Tx32x32];
|
||||||
lfm.LeftUv[(int)TxSize.Tx16x16] |= lfm.LeftUv[(int)TxSize.Tx32x32];
|
leftUvSpan[(int)TxSize.Tx16x16] |= leftUvSpan[(int)TxSize.Tx32x32];
|
||||||
lfm.AboveUv[(int)TxSize.Tx16x16] |= lfm.AboveUv[(int)TxSize.Tx32x32];
|
aboveUvSpan[(int)TxSize.Tx16x16] |= aboveUvSpan[(int)TxSize.Tx32x32];
|
||||||
|
|
||||||
// We do at least 8 tap filter on every 32x32 even if the transform size
|
// We do at least 8 tap filter on every 32x32 even if the transform size
|
||||||
// is 4x4. So if the 4x4 is set on a border pixel add it to the 8x8 and
|
// is 4x4. So if the 4x4 is set on a border pixel add it to the 8x8 and
|
||||||
// remove it from the 4x4.
|
// remove it from the 4x4.
|
||||||
lfm.LeftY[(int)TxSize.Tx8x8] |= lfm.LeftY[(int)TxSize.Tx4x4] & leftBorder;
|
leftYSpan[(int)TxSize.Tx8x8] |= leftYSpan[(int)TxSize.Tx4x4] & leftBorder;
|
||||||
lfm.LeftY[(int)TxSize.Tx4x4] &= ~leftBorder;
|
leftYSpan[(int)TxSize.Tx4x4] &= ~leftBorder;
|
||||||
lfm.AboveY[(int)TxSize.Tx8x8] |= lfm.AboveY[(int)TxSize.Tx4x4] & aboveBorder;
|
aboveYSpan[(int)TxSize.Tx8x8] |= aboveYSpan[(int)TxSize.Tx4x4] & aboveBorder;
|
||||||
lfm.AboveY[(int)TxSize.Tx4x4] &= ~aboveBorder;
|
aboveYSpan[(int)TxSize.Tx4x4] &= ~aboveBorder;
|
||||||
lfm.LeftUv[(int)TxSize.Tx8x8] |= (ushort)(lfm.LeftUv[(int)TxSize.Tx4x4] & leftBorderUv);
|
leftUvSpan[(int)TxSize.Tx8x8] |= (ushort)(leftUvSpan[(int)TxSize.Tx4x4] & leftBorderUv);
|
||||||
lfm.LeftUv[(int)TxSize.Tx4x4] &= unchecked((ushort)~leftBorderUv);
|
leftUvSpan[(int)TxSize.Tx4x4] &= unchecked((ushort)~leftBorderUv);
|
||||||
lfm.AboveUv[(int)TxSize.Tx8x8] |= (ushort)(lfm.AboveUv[(int)TxSize.Tx4x4] & aboveBorderUv);
|
aboveUvSpan[(int)TxSize.Tx8x8] |= (ushort)(aboveUvSpan[(int)TxSize.Tx4x4] & aboveBorderUv);
|
||||||
lfm.AboveUv[(int)TxSize.Tx4x4] &= unchecked((ushort)~aboveBorderUv);
|
aboveUvSpan[(int)TxSize.Tx4x4] &= unchecked((ushort)~aboveBorderUv);
|
||||||
|
|
||||||
// We do some special edge handling.
|
// We do some special edge handling.
|
||||||
if (miRow + Constants.MiBlockSize > cm.MiRows)
|
if (miRow + Constants.MiBlockSize > cm.MiRows)
|
||||||
|
|
@ -477,10 +483,10 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||||
// Remove values completely outside our border.
|
// Remove values completely outside our border.
|
||||||
for (int i = 0; i < (int)TxSize.Tx32x32; i++)
|
for (int i = 0; i < (int)TxSize.Tx32x32; i++)
|
||||||
{
|
{
|
||||||
lfm.LeftY[i] &= maskY;
|
leftYSpan[i] &= maskY;
|
||||||
lfm.AboveY[i] &= maskY;
|
aboveYSpan[i] &= maskY;
|
||||||
lfm.LeftUv[i] &= maskUv;
|
leftUvSpan[i] &= maskUv;
|
||||||
lfm.AboveUv[i] &= maskUv;
|
aboveUvSpan[i] &= maskUv;
|
||||||
}
|
}
|
||||||
|
|
||||||
lfm.Int4x4Y &= maskY;
|
lfm.Int4x4Y &= maskY;
|
||||||
|
|
@ -490,14 +496,14 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||||
// apply the shorter one instead.
|
// apply the shorter one instead.
|
||||||
if (rows == 1)
|
if (rows == 1)
|
||||||
{
|
{
|
||||||
lfm.AboveUv[(int)TxSize.Tx8x8] |= lfm.AboveUv[(int)TxSize.Tx16x16];
|
aboveUvSpan[(int)TxSize.Tx8x8] |= aboveUvSpan[(int)TxSize.Tx16x16];
|
||||||
lfm.AboveUv[(int)TxSize.Tx16x16] = 0;
|
aboveUvSpan[(int)TxSize.Tx16x16] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rows == 5)
|
if (rows == 5)
|
||||||
{
|
{
|
||||||
lfm.AboveUv[(int)TxSize.Tx8x8] |= (ushort)(lfm.AboveUv[(int)TxSize.Tx16x16] & 0xff00);
|
aboveUvSpan[(int)TxSize.Tx8x8] |= (ushort)(aboveUvSpan[(int)TxSize.Tx16x16] & 0xff00);
|
||||||
lfm.AboveUv[(int)TxSize.Tx16x16] &= (ushort)~(lfm.AboveUv[(int)TxSize.Tx16x16] & 0xff00);
|
aboveUvSpan[(int)TxSize.Tx16x16] &= (ushort)~(aboveUvSpan[(int)TxSize.Tx16x16] & 0xff00);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -517,10 +523,10 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||||
// Remove the bits outside the image edge.
|
// Remove the bits outside the image edge.
|
||||||
for (int i = 0; i < (int)TxSize.Tx32x32; i++)
|
for (int i = 0; i < (int)TxSize.Tx32x32; i++)
|
||||||
{
|
{
|
||||||
lfm.LeftY[i] &= maskY;
|
leftYSpan[i] &= maskY;
|
||||||
lfm.AboveY[i] &= maskY;
|
aboveYSpan[i] &= maskY;
|
||||||
lfm.LeftUv[i] &= maskUv;
|
leftUvSpan[i] &= maskUv;
|
||||||
lfm.AboveUv[i] &= maskUv;
|
aboveUvSpan[i] &= maskUv;
|
||||||
}
|
}
|
||||||
|
|
||||||
lfm.Int4x4Y &= maskY;
|
lfm.Int4x4Y &= maskY;
|
||||||
|
|
@ -530,14 +536,14 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||||
// apply the shorter one instead.
|
// apply the shorter one instead.
|
||||||
if (columns == 1)
|
if (columns == 1)
|
||||||
{
|
{
|
||||||
lfm.LeftUv[(int)TxSize.Tx8x8] |= lfm.LeftUv[(int)TxSize.Tx16x16];
|
leftUvSpan[(int)TxSize.Tx8x8] |= leftUvSpan[(int)TxSize.Tx16x16];
|
||||||
lfm.LeftUv[(int)TxSize.Tx16x16] = 0;
|
leftUvSpan[(int)TxSize.Tx16x16] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (columns == 5)
|
if (columns == 5)
|
||||||
{
|
{
|
||||||
lfm.LeftUv[(int)TxSize.Tx8x8] |= (ushort)(lfm.LeftUv[(int)TxSize.Tx16x16] & 0xcccc);
|
leftUvSpan[(int)TxSize.Tx8x8] |= (ushort)(leftUvSpan[(int)TxSize.Tx16x16] & 0xcccc);
|
||||||
lfm.LeftUv[(int)TxSize.Tx16x16] &= (ushort)~(lfm.LeftUv[(int)TxSize.Tx16x16] & 0xcccc);
|
leftUvSpan[(int)TxSize.Tx16x16] &= (ushort)~(leftUvSpan[(int)TxSize.Tx16x16] & 0xcccc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -547,28 +553,28 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||||
{
|
{
|
||||||
for (int i = 0; i < (int)TxSize.Tx32x32; i++)
|
for (int i = 0; i < (int)TxSize.Tx32x32; i++)
|
||||||
{
|
{
|
||||||
lfm.LeftY[i] &= 0xfefefefefefefefeUL;
|
leftYSpan[i] &= 0xfefefefefefefefeUL;
|
||||||
lfm.LeftUv[i] &= 0xeeee;
|
leftUvSpan[i] &= 0xeeee;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Assert if we try to apply 2 different loop filters at the same position.
|
// Assert if we try to apply 2 different loop filters at the same position.
|
||||||
Debug.Assert((lfm.LeftY[(int)TxSize.Tx16x16] & lfm.LeftY[(int)TxSize.Tx8x8]) == 0);
|
Debug.Assert((leftYSpan[(int)TxSize.Tx16x16] & leftYSpan[(int)TxSize.Tx8x8]) == 0);
|
||||||
Debug.Assert((lfm.LeftY[(int)TxSize.Tx16x16] & lfm.LeftY[(int)TxSize.Tx4x4]) == 0);
|
Debug.Assert((leftYSpan[(int)TxSize.Tx16x16] & leftYSpan[(int)TxSize.Tx4x4]) == 0);
|
||||||
Debug.Assert((lfm.LeftY[(int)TxSize.Tx8x8] & lfm.LeftY[(int)TxSize.Tx4x4]) == 0);
|
Debug.Assert((leftYSpan[(int)TxSize.Tx8x8] & leftYSpan[(int)TxSize.Tx4x4]) == 0);
|
||||||
Debug.Assert((lfm.Int4x4Y & lfm.LeftY[(int)TxSize.Tx16x16]) == 0);
|
Debug.Assert((lfm.Int4x4Y & leftYSpan[(int)TxSize.Tx16x16]) == 0);
|
||||||
Debug.Assert((lfm.LeftUv[(int)TxSize.Tx16x16] & lfm.LeftUv[(int)TxSize.Tx8x8]) == 0);
|
Debug.Assert((leftUvSpan[(int)TxSize.Tx16x16] & leftUvSpan[(int)TxSize.Tx8x8]) == 0);
|
||||||
Debug.Assert((lfm.LeftUv[(int)TxSize.Tx16x16] & lfm.LeftUv[(int)TxSize.Tx4x4]) == 0);
|
Debug.Assert((leftUvSpan[(int)TxSize.Tx16x16] & leftUvSpan[(int)TxSize.Tx4x4]) == 0);
|
||||||
Debug.Assert((lfm.LeftUv[(int)TxSize.Tx8x8] & lfm.LeftUv[(int)TxSize.Tx4x4]) == 0);
|
Debug.Assert((leftUvSpan[(int)TxSize.Tx8x8] & leftUvSpan[(int)TxSize.Tx4x4]) == 0);
|
||||||
Debug.Assert((lfm.Int4x4Uv & lfm.LeftUv[(int)TxSize.Tx16x16]) == 0);
|
Debug.Assert((lfm.Int4x4Uv & leftUvSpan[(int)TxSize.Tx16x16]) == 0);
|
||||||
Debug.Assert((lfm.AboveY[(int)TxSize.Tx16x16] & lfm.AboveY[(int)TxSize.Tx8x8]) == 0);
|
Debug.Assert((aboveYSpan[(int)TxSize.Tx16x16] & aboveYSpan[(int)TxSize.Tx8x8]) == 0);
|
||||||
Debug.Assert((lfm.AboveY[(int)TxSize.Tx16x16] & lfm.AboveY[(int)TxSize.Tx4x4]) == 0);
|
Debug.Assert((aboveYSpan[(int)TxSize.Tx16x16] & aboveYSpan[(int)TxSize.Tx4x4]) == 0);
|
||||||
Debug.Assert((lfm.AboveY[(int)TxSize.Tx8x8] & lfm.AboveY[(int)TxSize.Tx4x4]) == 0);
|
Debug.Assert((aboveYSpan[(int)TxSize.Tx8x8] & aboveYSpan[(int)TxSize.Tx4x4]) == 0);
|
||||||
Debug.Assert((lfm.Int4x4Y & lfm.AboveY[(int)TxSize.Tx16x16]) == 0);
|
Debug.Assert((lfm.Int4x4Y & aboveYSpan[(int)TxSize.Tx16x16]) == 0);
|
||||||
Debug.Assert((lfm.AboveUv[(int)TxSize.Tx16x16] & lfm.AboveUv[(int)TxSize.Tx8x8]) == 0);
|
Debug.Assert((aboveUvSpan[(int)TxSize.Tx16x16] & aboveUvSpan[(int)TxSize.Tx8x8]) == 0);
|
||||||
Debug.Assert((lfm.AboveUv[(int)TxSize.Tx16x16] & lfm.AboveUv[(int)TxSize.Tx4x4]) == 0);
|
Debug.Assert((aboveUvSpan[(int)TxSize.Tx16x16] & aboveUvSpan[(int)TxSize.Tx4x4]) == 0);
|
||||||
Debug.Assert((lfm.AboveUv[(int)TxSize.Tx8x8] & lfm.AboveUv[(int)TxSize.Tx4x4]) == 0);
|
Debug.Assert((aboveUvSpan[(int)TxSize.Tx8x8] & aboveUvSpan[(int)TxSize.Tx4x4]) == 0);
|
||||||
Debug.Assert((lfm.Int4x4Uv & lfm.AboveUv[(int)TxSize.Tx16x16]) == 0);
|
Debug.Assert((lfm.Int4x4Uv & aboveUvSpan[(int)TxSize.Tx16x16]) == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static unsafe void ResetLfm(ref Vp9Common cm)
|
public static unsafe void ResetLfm(ref Vp9Common cm)
|
||||||
|
|
@ -584,6 +590,8 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||||
{
|
{
|
||||||
int lvl;
|
int lvl;
|
||||||
|
|
||||||
|
Span<LoopFilterThresh> lFThrSpan = lfi.Lfthr.AsSpan();
|
||||||
|
|
||||||
// For each possible value for the loop filter fill out limits
|
// For each possible value for the loop filter fill out limits
|
||||||
for (lvl = 0; lvl <= MaxLoopFilter; lvl++)
|
for (lvl = 0; lvl <= MaxLoopFilter; lvl++)
|
||||||
{
|
{
|
||||||
|
|
@ -603,8 +611,8 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||||
blockInsideLimit = 1;
|
blockInsideLimit = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
lfi.Lfthr[lvl].Lim.AsSpan().Fill((byte)blockInsideLimit);
|
lFThrSpan[lvl].Lim.AsSpan().Fill((byte)blockInsideLimit);
|
||||||
lfi.Lfthr[lvl].Mblim.AsSpan().Fill((byte)((2 * (lvl + 2)) + blockInsideLimit));
|
lFThrSpan[lvl].Mblim.AsSpan().Fill((byte)((2 * (lvl + 2)) + blockInsideLimit));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -626,6 +634,11 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||||
lf.LastSharpnessLevel = lf.SharpnessLevel;
|
lf.LastSharpnessLevel = lf.SharpnessLevel;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Span<Array4<Array2<byte>>> lvlSpan = lfi.Lvl.AsSpan();
|
||||||
|
Span<sbyte> refDeltasSpan = lf.RefDeltas.AsSpan();
|
||||||
|
Span<sbyte> modeDeltasSpan = lf.ModeDeltas.AsSpan();
|
||||||
|
sbyte intraFrameRefDelta = refDeltasSpan[Constants.IntraFrame];
|
||||||
|
|
||||||
for (segId = 0; segId < Constants.MaxSegments; segId++)
|
for (segId = 0; segId < Constants.MaxSegments; segId++)
|
||||||
{
|
{
|
||||||
int lvlSeg = defaultFiltLvl;
|
int lvlSeg = defaultFiltLvl;
|
||||||
|
|
@ -640,20 +653,24 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||||
{
|
{
|
||||||
// We could get rid of this if we assume that deltas are set to
|
// We could get rid of this if we assume that deltas are set to
|
||||||
// zero when not in use; encoder always uses deltas
|
// zero when not in use; encoder always uses deltas
|
||||||
MemoryMarshal.Cast<Array2<byte>, byte>(lfi.Lvl[segId].AsSpan()).Fill((byte)lvlSeg);
|
MemoryMarshal.Cast<Array2<byte>, byte>(lvlSpan[segId].AsSpan()).Fill((byte)lvlSeg);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
int refr, mode;
|
int refr, mode;
|
||||||
int intraLvl = lvlSeg + (lf.RefDeltas[Constants.IntraFrame] * scale);
|
int intraLvl = lvlSeg + (intraFrameRefDelta * scale);
|
||||||
lfi.Lvl[segId][Constants.IntraFrame][0] = (byte)Math.Clamp(intraLvl, 0, MaxLoopFilter);
|
lvlSpan[segId][Constants.IntraFrame][0] = (byte)Math.Clamp(intraLvl, 0, MaxLoopFilter);
|
||||||
|
|
||||||
|
Span<Array2<byte>> lvlSpan2 = lvlSpan[segId].AsSpan();
|
||||||
|
|
||||||
for (refr = Constants.LastFrame; refr < Constants.MaxRefFrames; ++refr)
|
for (refr = Constants.LastFrame; refr < Constants.MaxRefFrames; ++refr)
|
||||||
{
|
{
|
||||||
|
Span<byte> lvlSpan3 = lvlSpan2[refr].AsSpan();
|
||||||
|
|
||||||
for (mode = 0; mode < MaxModeLfDeltas; ++mode)
|
for (mode = 0; mode < MaxModeLfDeltas; ++mode)
|
||||||
{
|
{
|
||||||
int interLvl = lvlSeg + (lf.RefDeltas[refr] * scale) + (lf.ModeDeltas[mode] * scale);
|
int interLvl = lvlSeg + (refDeltasSpan[refr] * scale) + (modeDeltasSpan[mode] * scale);
|
||||||
lfi.Lvl[segId][refr][mode] = (byte)Math.Clamp(interLvl, 0, MaxLoopFilter);
|
lvlSpan3[mode] = (byte)Math.Clamp(interLvl, 0, MaxLoopFilter);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -812,18 +829,32 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||||
lfis[1] = lfthr[lfl[lflForward]];
|
lfis[1] = lfthr[lfl[lflForward]];
|
||||||
ss[1] = ss[0].Slice(8 * pitch);
|
ss[1] = ss[0].Slice(8 * pitch);
|
||||||
|
|
||||||
|
Span<byte> mblim0Span = lfis[0].Mblim.AsSpan();
|
||||||
|
Span<byte> lim0Span = lfis[0].Lim.AsSpan();
|
||||||
|
Span<byte> hevThr0Span = lfis[0].HevThr.AsSpan();
|
||||||
|
Span<byte> mblim1Span = lfis[1].Mblim.AsSpan();
|
||||||
|
Span<byte> lim1Span = lfis[1].Lim.AsSpan();
|
||||||
|
Span<byte> hevThr1Span = lfis[1].HevThr.AsSpan();
|
||||||
|
|
||||||
if ((mask16x16 & dualOne) != 0)
|
if ((mask16x16 & dualOne) != 0)
|
||||||
{
|
{
|
||||||
if ((mask16x16 & dualOne) == dualOne)
|
if ((mask16x16 & dualOne) == dualOne)
|
||||||
{
|
{
|
||||||
LoopFilterScalar.HighBdLpfVertical16Dual(ss[0], pitch, lfis[0].Mblim[0], lfis[0].Lim[0],
|
LoopFilterScalar.HighBdLpfVertical16Dual(ss[0], pitch, mblim0Span[0], lim0Span[0],
|
||||||
lfis[0].HevThr[0], bd);
|
hevThr0Span[0], bd);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ref LoopFilterThresh lfi = ref lfis[(mask16x16 & 1) == 0 ? 1 : 0];
|
if ((mask16x16 & 1) == 0)
|
||||||
LoopFilterScalar.HighBdLpfVertical16(ss[(mask16x16 & 1) == 0 ? 1 : 0], pitch, lfi.Mblim[0],
|
{
|
||||||
lfi.Lim[0], lfi.HevThr[0], bd);
|
LoopFilterScalar.HighBdLpfVertical16(ss[1], pitch, mblim1Span[0],
|
||||||
|
lim1Span[0], hevThr1Span[0], bd);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LoopFilterScalar.HighBdLpfVertical16(ss[0], pitch, mblim0Span[0],
|
||||||
|
lim0Span[0], hevThr0Span[0], bd);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -834,24 +865,26 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||||
LoopFilterScalar.HighBdLpfVertical8Dual(
|
LoopFilterScalar.HighBdLpfVertical8Dual(
|
||||||
ss[0],
|
ss[0],
|
||||||
pitch,
|
pitch,
|
||||||
lfis[0].Mblim[0],
|
mblim0Span[0],
|
||||||
lfis[0].Lim[0],
|
lim0Span[0],
|
||||||
lfis[0].HevThr[0],
|
hevThr0Span[0],
|
||||||
lfis[1].Mblim[0],
|
mblim1Span[0],
|
||||||
lfis[1].Lim[0],
|
lim1Span[0],
|
||||||
lfis[1].HevThr[0],
|
hevThr1Span[0],
|
||||||
bd);
|
bd);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ref LoopFilterThresh lfi = ref lfis[(mask8x8 & 1) == 0 ? 1 : 0];
|
if ((mask8x8 & 1) == 0)
|
||||||
LoopFilterScalar.HighBdLpfVertical8(
|
{
|
||||||
ss[(mask8x8 & 1) == 0 ? 1 : 0],
|
LoopFilterScalar.HighBdLpfVertical8(ss[1], pitch, mblim1Span[0],
|
||||||
pitch,
|
lim1Span[0], hevThr1Span[0], bd);
|
||||||
lfi.Mblim[0],
|
}
|
||||||
lfi.Lim[0],
|
else
|
||||||
lfi.HevThr[0],
|
{
|
||||||
bd);
|
LoopFilterScalar.HighBdLpfVertical8(ss[0], pitch, mblim0Span[0],
|
||||||
|
lim0Span[0], hevThr0Span[0], bd);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -862,19 +895,26 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||||
LoopFilterScalar.HighBdLpfVertical4Dual(
|
LoopFilterScalar.HighBdLpfVertical4Dual(
|
||||||
ss[0],
|
ss[0],
|
||||||
pitch,
|
pitch,
|
||||||
lfis[0].Mblim[0],
|
mblim0Span[0],
|
||||||
lfis[0].Lim[0],
|
lim0Span[0],
|
||||||
lfis[0].HevThr[0],
|
hevThr0Span[0],
|
||||||
lfis[1].Mblim[0],
|
mblim1Span[0],
|
||||||
lfis[1].Lim[0],
|
lim1Span[0],
|
||||||
lfis[1].HevThr[0],
|
hevThr1Span[0],
|
||||||
bd);
|
bd);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ref LoopFilterThresh lfi = ref lfis[(mask4x4 & 1) == 0 ? 1 : 0];
|
if ((mask4x4 & 1) == 0)
|
||||||
LoopFilterScalar.HighBdLpfVertical4(ss[(mask4x4 & 1) == 0 ? 1 : 0], pitch, lfi.Mblim[0],
|
{
|
||||||
lfi.Lim[0], lfi.HevThr[0], bd);
|
LoopFilterScalar.HighBdLpfVertical4(ss[1], pitch, mblim1Span[0],
|
||||||
|
lim1Span[0], hevThr1Span[0], bd);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LoopFilterScalar.HighBdLpfVertical4(ss[0], pitch, mblim0Span[0],
|
||||||
|
lim0Span[0], hevThr0Span[0], bd);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -885,19 +925,26 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||||
LoopFilterScalar.HighBdLpfVertical4Dual(
|
LoopFilterScalar.HighBdLpfVertical4Dual(
|
||||||
ss[0].Slice(4),
|
ss[0].Slice(4),
|
||||||
pitch,
|
pitch,
|
||||||
lfis[0].Mblim[0],
|
mblim0Span[0],
|
||||||
lfis[0].Lim[0],
|
lim0Span[0],
|
||||||
lfis[0].HevThr[0],
|
hevThr0Span[0],
|
||||||
lfis[1].Mblim[0],
|
mblim1Span[0],
|
||||||
lfis[1].Lim[0],
|
lim1Span[0],
|
||||||
lfis[1].HevThr[0],
|
hevThr1Span[0],
|
||||||
bd);
|
bd);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ref LoopFilterThresh lfi = ref lfis[(mask4x4Int & 1) == 0 ? 1 : 0];
|
if ((mask4x4Int & 1) == 0)
|
||||||
LoopFilterScalar.HighBdLpfVertical4(ss[(mask4x4Int & 1) == 0 ? 1 : 0].Slice(4), pitch,
|
{
|
||||||
lfi.Mblim[0], lfi.Lim[0], lfi.HevThr[0], bd);
|
LoopFilterScalar.HighBdLpfVertical4(ss[1].Slice(4), pitch, mblim1Span[0],
|
||||||
|
lim1Span[0], hevThr1Span[0], bd);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LoopFilterScalar.HighBdLpfVertical4(ss[0].Slice(4), pitch, mblim0Span[0],
|
||||||
|
lim0Span[0], hevThr0Span[0], bd);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1087,18 +1134,22 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||||
if ((mask & 1) != 0)
|
if ((mask & 1) != 0)
|
||||||
{
|
{
|
||||||
LoopFilterThresh lfi = lfthr[lfl[0]];
|
LoopFilterThresh lfi = lfthr[lfl[0]];
|
||||||
|
|
||||||
|
Span<byte> mblimSpan = lfi.Mblim.AsSpan();
|
||||||
|
Span<byte> limSpan = lfi.Lim.AsSpan();
|
||||||
|
Span<byte> hevThrSpan = lfi.HevThr.AsSpan();
|
||||||
|
|
||||||
if ((mask16x16 & 1) != 0)
|
if ((mask16x16 & 1) != 0)
|
||||||
{
|
{
|
||||||
if ((mask16x16 & 3) == 3)
|
if ((mask16x16 & 3) == 3)
|
||||||
{
|
{
|
||||||
LoopFilterScalar.HighBdLpfHorizontal16Dual(s, pitch, lfi.Mblim[0], lfi.Lim[0],
|
LoopFilterScalar.HighBdLpfHorizontal16Dual(s, pitch, mblimSpan[0], limSpan[0],
|
||||||
lfi.HevThr[0], bd);
|
hevThrSpan[0], bd);
|
||||||
count = 2;
|
count = 2;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
LoopFilterScalar.HighBdLpfHorizontal16(s, pitch, lfi.Mblim[0], lfi.Lim[0], lfi.HevThr[0],
|
LoopFilterScalar.HighBdLpfHorizontal16(s, pitch, mblimSpan[0], limSpan[0], hevThrSpan[0],
|
||||||
bd);
|
bd);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1108,16 +1159,20 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||||
{
|
{
|
||||||
// Next block's thresholds.
|
// Next block's thresholds.
|
||||||
LoopFilterThresh lfin = lfthr[lfl[1]];
|
LoopFilterThresh lfin = lfthr[lfl[1]];
|
||||||
|
|
||||||
|
Span<byte> nMblimSpan = lfin.Mblim.AsSpan();
|
||||||
|
Span<byte> nLimSpan = lfin.Lim.AsSpan();
|
||||||
|
Span<byte> nHevThrSpan = lfin.HevThr.AsSpan();
|
||||||
|
|
||||||
LoopFilterScalar.HighBdLpfHorizontal8Dual(
|
LoopFilterScalar.HighBdLpfHorizontal8Dual(
|
||||||
s,
|
s,
|
||||||
pitch,
|
pitch,
|
||||||
lfi.Mblim[0],
|
mblimSpan[0],
|
||||||
lfi.Lim[0],
|
limSpan[0],
|
||||||
lfi.HevThr[0],
|
hevThrSpan[0],
|
||||||
lfin.Mblim[0],
|
nMblimSpan[0],
|
||||||
lfin.Lim[0],
|
nLimSpan[0],
|
||||||
lfin.HevThr[0],
|
nHevThrSpan[0],
|
||||||
bd);
|
bd);
|
||||||
|
|
||||||
if ((mask4x4Int & 3) == 3)
|
if ((mask4x4Int & 3) == 3)
|
||||||
|
|
@ -1125,36 +1180,36 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||||
LoopFilterScalar.HighBdLpfHorizontal4Dual(
|
LoopFilterScalar.HighBdLpfHorizontal4Dual(
|
||||||
s.Slice(4 * pitch),
|
s.Slice(4 * pitch),
|
||||||
pitch,
|
pitch,
|
||||||
lfi.Mblim[0],
|
mblimSpan[0],
|
||||||
lfi.Lim[0],
|
limSpan[0],
|
||||||
lfi.HevThr[0],
|
hevThrSpan[0],
|
||||||
lfin.Mblim[0],
|
nMblimSpan[0],
|
||||||
lfin.Lim[0],
|
nLimSpan[0],
|
||||||
lfin.HevThr[0],
|
nHevThrSpan[0],
|
||||||
bd);
|
bd);
|
||||||
}
|
}
|
||||||
else if ((mask4x4Int & 1) != 0)
|
else if ((mask4x4Int & 1) != 0)
|
||||||
{
|
{
|
||||||
LoopFilterScalar.HighBdLpfHorizontal4(s.Slice(4 * pitch), pitch, lfi.Mblim[0],
|
LoopFilterScalar.HighBdLpfHorizontal4(s.Slice(4 * pitch), pitch, mblimSpan[0],
|
||||||
lfi.Lim[0], lfi.HevThr[0], bd);
|
limSpan[0], hevThrSpan[0], bd);
|
||||||
}
|
}
|
||||||
else if ((mask4x4Int & 2) != 0)
|
else if ((mask4x4Int & 2) != 0)
|
||||||
{
|
{
|
||||||
LoopFilterScalar.HighBdLpfHorizontal4(s.Slice(8 + (4 * pitch)), pitch, lfin.Mblim[0],
|
LoopFilterScalar.HighBdLpfHorizontal4(s.Slice(8 + (4 * pitch)), pitch, nMblimSpan[0],
|
||||||
lfin.Lim[0], lfin.HevThr[0], bd);
|
nLimSpan[0], nHevThrSpan[0], bd);
|
||||||
}
|
}
|
||||||
|
|
||||||
count = 2;
|
count = 2;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
LoopFilterScalar.HighBdLpfHorizontal8(s, pitch, lfi.Mblim[0], lfi.Lim[0], lfi.HevThr[0],
|
LoopFilterScalar.HighBdLpfHorizontal8(s, pitch, mblimSpan[0], limSpan[0], hevThrSpan[0],
|
||||||
bd);
|
bd);
|
||||||
|
|
||||||
if ((mask4x4Int & 1) != 0)
|
if ((mask4x4Int & 1) != 0)
|
||||||
{
|
{
|
||||||
LoopFilterScalar.HighBdLpfHorizontal4(s.Slice(4 * pitch), pitch, lfi.Mblim[0],
|
LoopFilterScalar.HighBdLpfHorizontal4(s.Slice(4 * pitch), pitch, mblimSpan[0],
|
||||||
lfi.Lim[0], lfi.HevThr[0], bd);
|
limSpan[0], hevThrSpan[0], bd);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1164,16 +1219,20 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||||
{
|
{
|
||||||
// Next block's thresholds.
|
// Next block's thresholds.
|
||||||
LoopFilterThresh lfin = lfthr[lfl[1]];
|
LoopFilterThresh lfin = lfthr[lfl[1]];
|
||||||
|
|
||||||
|
Span<byte> nMblimSpan = lfin.Mblim.AsSpan();
|
||||||
|
Span<byte> nLimSpan = lfin.Lim.AsSpan();
|
||||||
|
Span<byte> nHevThrSpan = lfin.HevThr.AsSpan();
|
||||||
|
|
||||||
LoopFilterScalar.HighBdLpfHorizontal4Dual(
|
LoopFilterScalar.HighBdLpfHorizontal4Dual(
|
||||||
s,
|
s,
|
||||||
pitch,
|
pitch,
|
||||||
lfi.Mblim[0],
|
mblimSpan[0],
|
||||||
lfi.Lim[0],
|
limSpan[0],
|
||||||
lfi.HevThr[0],
|
hevThrSpan[0],
|
||||||
lfin.Mblim[0],
|
nMblimSpan[0],
|
||||||
lfin.Lim[0],
|
nLimSpan[0],
|
||||||
lfin.HevThr[0],
|
nHevThrSpan[0],
|
||||||
bd);
|
bd);
|
||||||
|
|
||||||
if ((mask4x4Int & 3) == 3)
|
if ((mask4x4Int & 3) == 3)
|
||||||
|
|
@ -1181,43 +1240,43 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||||
LoopFilterScalar.HighBdLpfHorizontal4Dual(
|
LoopFilterScalar.HighBdLpfHorizontal4Dual(
|
||||||
s.Slice(4 * pitch),
|
s.Slice(4 * pitch),
|
||||||
pitch,
|
pitch,
|
||||||
lfi.Mblim[0],
|
mblimSpan[0],
|
||||||
lfi.Lim[0],
|
limSpan[0],
|
||||||
lfi.HevThr[0],
|
hevThrSpan[0],
|
||||||
lfin.Mblim[0],
|
nMblimSpan[0],
|
||||||
lfin.Lim[0],
|
nLimSpan[0],
|
||||||
lfin.HevThr[0],
|
nHevThrSpan[0],
|
||||||
bd);
|
bd);
|
||||||
}
|
}
|
||||||
else if ((mask4x4Int & 1) != 0)
|
else if ((mask4x4Int & 1) != 0)
|
||||||
{
|
{
|
||||||
LoopFilterScalar.HighBdLpfHorizontal4(s.Slice(4 * pitch), pitch, lfi.Mblim[0],
|
LoopFilterScalar.HighBdLpfHorizontal4(s.Slice(4 * pitch), pitch, mblimSpan[0],
|
||||||
lfi.Lim[0], lfi.HevThr[0], bd);
|
limSpan[0], hevThrSpan[0], bd);
|
||||||
}
|
}
|
||||||
else if ((mask4x4Int & 2) != 0)
|
else if ((mask4x4Int & 2) != 0)
|
||||||
{
|
{
|
||||||
LoopFilterScalar.HighBdLpfHorizontal4(s.Slice(8 + (4 * pitch)), pitch, lfin.Mblim[0],
|
LoopFilterScalar.HighBdLpfHorizontal4(s.Slice(8 + (4 * pitch)), pitch, nMblimSpan[0],
|
||||||
lfin.Lim[0], lfin.HevThr[0], bd);
|
nLimSpan[0], nHevThrSpan[0], bd);
|
||||||
}
|
}
|
||||||
|
|
||||||
count = 2;
|
count = 2;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
LoopFilterScalar.HighBdLpfHorizontal4(s, pitch, lfi.Mblim[0], lfi.Lim[0], lfi.HevThr[0],
|
LoopFilterScalar.HighBdLpfHorizontal4(s, pitch, mblimSpan[0], limSpan[0], hevThrSpan[0],
|
||||||
bd);
|
bd);
|
||||||
|
|
||||||
if ((mask4x4Int & 1) != 0)
|
if ((mask4x4Int & 1) != 0)
|
||||||
{
|
{
|
||||||
LoopFilterScalar.HighBdLpfHorizontal4(s.Slice(4 * pitch), pitch, lfi.Mblim[0],
|
LoopFilterScalar.HighBdLpfHorizontal4(s.Slice(4 * pitch), pitch, mblimSpan[0],
|
||||||
lfi.Lim[0], lfi.HevThr[0], bd);
|
limSpan[0], hevThrSpan[0], bd);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
LoopFilterScalar.HighBdLpfHorizontal4(s.Slice(4 * pitch), pitch, lfi.Mblim[0], lfi.Lim[0],
|
LoopFilterScalar.HighBdLpfHorizontal4(s.Slice(4 * pitch), pitch, mblimSpan[0], limSpan[0],
|
||||||
lfi.HevThr[0], bd);
|
hevThrSpan[0], bd);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1292,26 +1351,30 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||||
for (uint mask = mask16x16 | mask8x8 | mask4x4 | mask4x4Int; mask != 0; mask >>= 1)
|
for (uint mask = mask16x16 | mask8x8 | mask4x4 | mask4x4Int; mask != 0; mask >>= 1)
|
||||||
{
|
{
|
||||||
LoopFilterThresh lfi = lfthr[lfl[0]];
|
LoopFilterThresh lfi = lfthr[lfl[0]];
|
||||||
|
|
||||||
|
Span<byte> mblimSpan = lfi.Mblim.AsSpan();
|
||||||
|
Span<byte> limSpan = lfi.Lim.AsSpan();
|
||||||
|
Span<byte> hevThrSpan = lfi.HevThr.AsSpan();
|
||||||
|
|
||||||
if ((mask & 1) != 0)
|
if ((mask & 1) != 0)
|
||||||
{
|
{
|
||||||
if ((mask16x16 & 1) != 0)
|
if ((mask16x16 & 1) != 0)
|
||||||
{
|
{
|
||||||
LoopFilterScalar.HighBdLpfVertical16(s, pitch, lfi.Mblim[0], lfi.Lim[0], lfi.HevThr[0], bd);
|
LoopFilterScalar.HighBdLpfVertical16(s, pitch, mblimSpan[0], limSpan[0], hevThrSpan[0], bd);
|
||||||
}
|
}
|
||||||
else if ((mask8x8 & 1) != 0)
|
else if ((mask8x8 & 1) != 0)
|
||||||
{
|
{
|
||||||
LoopFilterScalar.HighBdLpfVertical8(s, pitch, lfi.Mblim[0], lfi.Lim[0], lfi.HevThr[0], bd);
|
LoopFilterScalar.HighBdLpfVertical8(s, pitch, mblimSpan[0], limSpan[0], hevThrSpan[0], bd);
|
||||||
}
|
}
|
||||||
else if ((mask4x4 & 1) != 0)
|
else if ((mask4x4 & 1) != 0)
|
||||||
{
|
{
|
||||||
LoopFilterScalar.HighBdLpfVertical4(s, pitch, lfi.Mblim[0], lfi.Lim[0], lfi.HevThr[0], bd);
|
LoopFilterScalar.HighBdLpfVertical4(s, pitch, mblimSpan[0], limSpan[0], hevThrSpan[0], bd);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((mask4x4Int & 1) != 0)
|
if ((mask4x4Int & 1) != 0)
|
||||||
{
|
{
|
||||||
LoopFilterScalar.HighBdLpfVertical4(s.Slice(4), pitch, lfi.Mblim[0], lfi.Lim[0], lfi.HevThr[0], bd);
|
LoopFilterScalar.HighBdLpfVertical4(s.Slice(4), pitch, mblimSpan[0], limSpan[0], hevThrSpan[0], bd);
|
||||||
}
|
}
|
||||||
|
|
||||||
s = s.Slice(8);
|
s = s.Slice(8);
|
||||||
|
|
@ -1557,9 +1620,10 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||||
{
|
{
|
||||||
ref Buf2D dst = ref plane.Dst;
|
ref Buf2D dst = ref plane.Dst;
|
||||||
ArrayPtr<byte> dst0 = dst.Buf;
|
ArrayPtr<byte> dst0 = dst.Buf;
|
||||||
ulong mask16x16 = lfm.LeftY[(int)TxSize.Tx16x16];
|
Span<ulong> leftYSpan = lfm.LeftY.AsSpan();
|
||||||
ulong mask8x8 = lfm.LeftY[(int)TxSize.Tx8x8];
|
ulong mask16x16 = leftYSpan[(int)TxSize.Tx16x16];
|
||||||
ulong mask4x4 = lfm.LeftY[(int)TxSize.Tx4x4];
|
ulong mask8x8 = leftYSpan[(int)TxSize.Tx8x8];
|
||||||
|
ulong mask4x4 = leftYSpan[(int)TxSize.Tx4x4];
|
||||||
ulong mask4x4Int = lfm.Int4x4Y;
|
ulong mask4x4Int = lfm.Int4x4Y;
|
||||||
|
|
||||||
Debug.Assert(plane.SubsamplingX == 0 && plane.SubsamplingY == 0);
|
Debug.Assert(plane.SubsamplingX == 0 && plane.SubsamplingY == 0);
|
||||||
|
|
@ -1606,9 +1670,10 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||||
|
|
||||||
// Horizontal pass
|
// Horizontal pass
|
||||||
dst.Buf = dst0;
|
dst.Buf = dst0;
|
||||||
mask16x16 = lfm.AboveY[(int)TxSize.Tx16x16];
|
Span<ulong> aboveYSpan = lfm.AboveY.AsSpan();
|
||||||
mask8x8 = lfm.AboveY[(int)TxSize.Tx8x8];
|
mask16x16 = aboveYSpan[(int)TxSize.Tx16x16];
|
||||||
mask4x4 = lfm.AboveY[(int)TxSize.Tx4x4];
|
mask8x8 = aboveYSpan[(int)TxSize.Tx8x8];
|
||||||
|
mask4x4 = aboveYSpan[(int)TxSize.Tx4x4];
|
||||||
mask4x4Int = lfm.Int4x4Y;
|
mask4x4Int = lfm.Int4x4Y;
|
||||||
|
|
||||||
for (int r = 0; r < Constants.MiBlockSize && miRow + r < cm.MiRows; r++)
|
for (int r = 0; r < Constants.MiBlockSize && miRow + r < cm.MiRows; r++)
|
||||||
|
|
@ -1671,10 +1736,12 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||||
ArrayPtr<byte> dst0 = dst.Buf;
|
ArrayPtr<byte> dst0 = dst.Buf;
|
||||||
|
|
||||||
Span<byte> lflUv = stackalloc byte[16];
|
Span<byte> lflUv = stackalloc byte[16];
|
||||||
|
Span<byte> lflY = lfm.LflY.AsSpan();
|
||||||
|
|
||||||
ushort mask16x16 = lfm.LeftUv[(int)TxSize.Tx16x16];
|
Span<ushort> leftUvSpan = lfm.LeftUv.AsSpan();
|
||||||
ushort mask8x8 = lfm.LeftUv[(int)TxSize.Tx8x8];
|
ushort mask16x16 = leftUvSpan[(int)TxSize.Tx16x16];
|
||||||
ushort mask4x4 = lfm.LeftUv[(int)TxSize.Tx4x4];
|
ushort mask8x8 = leftUvSpan[(int)TxSize.Tx8x8];
|
||||||
|
ushort mask4x4 = leftUvSpan[(int)TxSize.Tx4x4];
|
||||||
ushort mask4x4Int = lfm.Int4x4Uv;
|
ushort mask4x4Int = lfm.Int4x4Uv;
|
||||||
|
|
||||||
Debug.Assert(plane.SubsamplingX == 1 && plane.SubsamplingY == 1);
|
Debug.Assert(plane.SubsamplingX == 1 && plane.SubsamplingY == 1);
|
||||||
|
|
@ -1684,8 +1751,8 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||||
{
|
{
|
||||||
for (int c = 0; c < Constants.MiBlockSize >> 1; c++)
|
for (int c = 0; c < Constants.MiBlockSize >> 1; c++)
|
||||||
{
|
{
|
||||||
lflUv[(r << 1) + c] = lfm.LflY[(r << 3) + (c << 1)];
|
lflUv[(r << 1) + c] = lflY[(r << 3) + (c << 1)];
|
||||||
lflUv[((r + 2) << 1) + c] = lfm.LflY[((r + 2) << 3) + (c << 1)];
|
lflUv[((r + 2) << 1) + c] = lflY[((r + 2) << 3) + (c << 1)];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cm.UseHighBitDepth)
|
if (cm.UseHighBitDepth)
|
||||||
|
|
@ -1727,9 +1794,10 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||||
|
|
||||||
// Horizontal pass
|
// Horizontal pass
|
||||||
dst.Buf = dst0;
|
dst.Buf = dst0;
|
||||||
mask16x16 = lfm.AboveUv[(int)TxSize.Tx16x16];
|
Span<ushort> aboveUvSpan = lfm.AboveUv.AsSpan();
|
||||||
mask8x8 = lfm.AboveUv[(int)TxSize.Tx8x8];
|
mask16x16 = aboveUvSpan[(int)TxSize.Tx16x16];
|
||||||
mask4x4 = lfm.AboveUv[(int)TxSize.Tx4x4];
|
mask8x8 = aboveUvSpan[(int)TxSize.Tx8x8];
|
||||||
|
mask4x4 = aboveUvSpan[(int)TxSize.Tx4x4];
|
||||||
mask4x4Int = lfm.Int4x4Uv;
|
mask4x4Int = lfm.Int4x4Uv;
|
||||||
|
|
||||||
for (int r = 0; r < Constants.MiBlockSize && miRow + r < cm.MiRows; r += 2)
|
for (int r = 0; r < Constants.MiBlockSize && miRow + r < cm.MiRows; r += 2)
|
||||||
|
|
@ -1808,16 +1876,17 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||||
int sbCols = TileInfo.MiColsAlignedToSb(cm.MiCols) >> Constants.MiBlockSizeLog2;
|
int sbCols = TileInfo.MiColsAlignedToSb(cm.MiCols) >> Constants.MiBlockSizeLog2;
|
||||||
LfPath path;
|
LfPath path;
|
||||||
int miRow, miCol;
|
int miRow, miCol;
|
||||||
|
Span<MacroBlockDPlane> planesSpan = planes.AsSpan();
|
||||||
|
|
||||||
if (yOnly)
|
if (yOnly)
|
||||||
{
|
{
|
||||||
path = LfPath.LfPath444;
|
path = LfPath.LfPath444;
|
||||||
}
|
}
|
||||||
else if (planes[1].SubsamplingY == 1 && planes[1].SubsamplingX == 1)
|
else if (planesSpan[1].SubsamplingY == 1 && planesSpan[1].SubsamplingX == 1)
|
||||||
{
|
{
|
||||||
path = LfPath.LfPath420;
|
path = LfPath.LfPath420;
|
||||||
}
|
}
|
||||||
else if (planes[1].SubsamplingY == 0 && planes[1].SubsamplingX == 0)
|
else if (planesSpan[1].SubsamplingY == 0 && planesSpan[1].SubsamplingX == 0)
|
||||||
{
|
{
|
||||||
path = LfPath.LfPath444;
|
path = LfPath.LfPath444;
|
||||||
}
|
}
|
||||||
|
|
@ -1839,23 +1908,23 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||||
|
|
||||||
lfSync.SyncRead(r, c);
|
lfSync.SyncRead(r, c);
|
||||||
|
|
||||||
ReconInter.SetupDstPlanes(ref planes, ref frameBuffer, miRow, miCol);
|
ReconInter.SetupDstPlanes(planesSpan, ref frameBuffer, miRow, miCol);
|
||||||
|
|
||||||
AdjustMask(ref cm, miRow, miCol, ref lfm[0]);
|
AdjustMask(ref cm, miRow, miCol, ref lfm[0]);
|
||||||
|
|
||||||
FilterBlockPlaneSs00(ref cm, ref planes[0], miRow, ref lfm[0]);
|
FilterBlockPlaneSs00(ref cm, ref planesSpan[0], miRow, ref lfm[0]);
|
||||||
for (plane = 1; plane < numPlanes; ++plane)
|
for (plane = 1; plane < numPlanes; ++plane)
|
||||||
{
|
{
|
||||||
switch (path)
|
switch (path)
|
||||||
{
|
{
|
||||||
case LfPath.LfPath420:
|
case LfPath.LfPath420:
|
||||||
FilterBlockPlaneSs11(ref cm, ref planes[plane], miRow, ref lfm[0]);
|
FilterBlockPlaneSs11(ref cm, ref planesSpan[plane], miRow, ref lfm[0]);
|
||||||
break;
|
break;
|
||||||
case LfPath.LfPath444:
|
case LfPath.LfPath444:
|
||||||
FilterBlockPlaneSs00(ref cm, ref planes[plane], miRow, ref lfm[0]);
|
FilterBlockPlaneSs00(ref cm, ref planesSpan[plane], miRow, ref lfm[0]);
|
||||||
break;
|
break;
|
||||||
case LfPath.LfPathSlow:
|
case LfPath.LfPathSlow:
|
||||||
FilterBlockPlaneNon420(ref cm, ref planes[plane], mi.Slice(miCol), miRow,
|
FilterBlockPlaneNon420(ref cm, ref planesSpan[plane], mi.Slice(miCol), miRow,
|
||||||
miCol);
|
miCol);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -283,16 +283,16 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||||
|
|
||||||
private static Array8<short> NewArray8Short(short e0, short e1, short e2, short e3, short e4, short e5, short e6, short e7)
|
private static Array8<short> NewArray8Short(short e0, short e1, short e2, short e3, short e4, short e5, short e6, short e7)
|
||||||
{
|
{
|
||||||
Array8<short> output = new Array8<short>();
|
Array8<short> output = new();
|
||||||
|
Span<short> outputSpan = output.AsSpan();
|
||||||
output[0] = e0;
|
outputSpan[0] = e0;
|
||||||
output[1] = e1;
|
outputSpan[1] = e1;
|
||||||
output[2] = e2;
|
outputSpan[2] = e2;
|
||||||
output[3] = e3;
|
outputSpan[3] = e3;
|
||||||
output[4] = e4;
|
outputSpan[4] = e4;
|
||||||
output[5] = e5;
|
outputSpan[5] = e5;
|
||||||
output[6] = e6;
|
outputSpan[6] = e6;
|
||||||
output[7] = e7;
|
outputSpan[7] = e7;
|
||||||
|
|
||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
using Ryujinx.Graphics.Nvdec.Vp9.Types;
|
using Ryujinx.Graphics.Nvdec.Vp9.Types;
|
||||||
|
using System;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
|
|
||||||
namespace Ryujinx.Graphics.Nvdec.Vp9
|
namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||||
|
|
@ -109,15 +110,17 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||||
sbyte vrfa = aSg ? xd.AboveMi.Value.RefFrame[0] : xd.AboveMi.Value.RefFrame[varRefIdx];
|
sbyte vrfa = aSg ? xd.AboveMi.Value.RefFrame[0] : xd.AboveMi.Value.RefFrame[varRefIdx];
|
||||||
sbyte vrfl = lSg ? xd.LeftMi.Value.RefFrame[0] : xd.LeftMi.Value.RefFrame[varRefIdx];
|
sbyte vrfl = lSg ? xd.LeftMi.Value.RefFrame[0] : xd.LeftMi.Value.RefFrame[varRefIdx];
|
||||||
|
|
||||||
if (vrfa == vrfl && cm.CompVarRef[1] == vrfa)
|
Span<sbyte> compVarRefSpan = cm.CompVarRef.AsSpan();
|
||||||
|
|
||||||
|
if (vrfa == vrfl && compVarRefSpan[1] == vrfa)
|
||||||
{
|
{
|
||||||
predContext = 0;
|
predContext = 0;
|
||||||
}
|
}
|
||||||
else if (lSg && aSg)
|
else if (lSg && aSg)
|
||||||
{
|
{
|
||||||
// Single/Single
|
// Single/Single
|
||||||
if ((vrfa == cm.CompFixedRef && vrfl == cm.CompVarRef[0]) ||
|
if ((vrfa == cm.CompFixedRef && vrfl == compVarRefSpan[0]) ||
|
||||||
(vrfl == cm.CompFixedRef && vrfa == cm.CompVarRef[0]))
|
(vrfl == cm.CompFixedRef && vrfa == compVarRefSpan[0]))
|
||||||
{
|
{
|
||||||
predContext = 4;
|
predContext = 4;
|
||||||
}
|
}
|
||||||
|
|
@ -135,11 +138,11 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||||
// Single/Comp
|
// Single/Comp
|
||||||
sbyte vrfc = lSg ? vrfa : vrfl;
|
sbyte vrfc = lSg ? vrfa : vrfl;
|
||||||
sbyte rfs = aSg ? vrfa : vrfl;
|
sbyte rfs = aSg ? vrfa : vrfl;
|
||||||
if (vrfc == cm.CompVarRef[1] && rfs != cm.CompVarRef[1])
|
if (vrfc == compVarRefSpan[1] && rfs != compVarRefSpan[1])
|
||||||
{
|
{
|
||||||
predContext = 1;
|
predContext = 1;
|
||||||
}
|
}
|
||||||
else if (rfs == cm.CompVarRef[1] && vrfc != cm.CompVarRef[1])
|
else if (rfs == compVarRefSpan[1] && vrfc != compVarRefSpan[1])
|
||||||
{
|
{
|
||||||
predContext = 2;
|
predContext = 2;
|
||||||
}
|
}
|
||||||
|
|
@ -212,14 +215,15 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||||
{
|
{
|
||||||
// Intra/Inter or Inter/Intra
|
// Intra/Inter or Inter/Intra
|
||||||
ref ModeInfo edgeMi = ref aboveIntra ? ref xd.LeftMi.Value : ref xd.AboveMi.Value;
|
ref ModeInfo edgeMi = ref aboveIntra ? ref xd.LeftMi.Value : ref xd.AboveMi.Value;
|
||||||
|
Span<sbyte> refFrameSpan = edgeMi.RefFrame.AsSpan();
|
||||||
if (!edgeMi.HasSecondRef())
|
if (!edgeMi.HasSecondRef())
|
||||||
{
|
{
|
||||||
predContext = 4 * (edgeMi.RefFrame[0] == Constants.LastFrame ? 1 : 0);
|
predContext = 4 * (refFrameSpan[0] == Constants.LastFrame ? 1 : 0);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
predContext = 1 + (edgeMi.RefFrame[0] == Constants.LastFrame ||
|
predContext = 1 + (refFrameSpan[0] == Constants.LastFrame ||
|
||||||
edgeMi.RefFrame[1] == Constants.LastFrame
|
refFrameSpan[1] == Constants.LastFrame
|
||||||
? 1
|
? 1
|
||||||
: 0);
|
: 0);
|
||||||
}
|
}
|
||||||
|
|
@ -229,10 +233,12 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||||
// Inter/Inter
|
// Inter/Inter
|
||||||
bool aboveHasSecond = xd.AboveMi.Value.HasSecondRef();
|
bool aboveHasSecond = xd.AboveMi.Value.HasSecondRef();
|
||||||
bool leftHasSecond = xd.LeftMi.Value.HasSecondRef();
|
bool leftHasSecond = xd.LeftMi.Value.HasSecondRef();
|
||||||
sbyte above0 = xd.AboveMi.Value.RefFrame[0];
|
Span<sbyte> aRefFrameSpan = xd.AboveMi.Value.RefFrame.AsSpan();
|
||||||
sbyte above1 = xd.AboveMi.Value.RefFrame[1];
|
sbyte above0 = aRefFrameSpan[0];
|
||||||
sbyte left0 = xd.LeftMi.Value.RefFrame[0];
|
sbyte above1 = aRefFrameSpan[1];
|
||||||
sbyte left1 = xd.LeftMi.Value.RefFrame[1];
|
Span<sbyte> lRefFrameSpan = xd.LeftMi.Value.RefFrame.AsSpan();
|
||||||
|
sbyte left0 = lRefFrameSpan[0];
|
||||||
|
sbyte left1 = lRefFrameSpan[1];
|
||||||
|
|
||||||
if (aboveHasSecond && leftHasSecond)
|
if (aboveHasSecond && leftHasSecond)
|
||||||
{
|
{
|
||||||
|
|
@ -281,8 +287,10 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
predContext = 1 + (edgeMi.RefFrame[0] == Constants.LastFrame ||
|
Span<sbyte> refFrameSpan = edgeMi.RefFrame.AsSpan();
|
||||||
edgeMi.RefFrame[1] == Constants.LastFrame
|
|
||||||
|
predContext = 1 + (refFrameSpan[0] == Constants.LastFrame ||
|
||||||
|
refFrameSpan[1] == Constants.LastFrame
|
||||||
? 1
|
? 1
|
||||||
: 0);
|
: 0);
|
||||||
}
|
}
|
||||||
|
|
@ -321,21 +329,22 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||||
{
|
{
|
||||||
// Intra/Inter or Inter/Intra
|
// Intra/Inter or Inter/Intra
|
||||||
ref ModeInfo edgeMi = ref aboveIntra ? ref xd.LeftMi.Value : ref xd.AboveMi.Value;
|
ref ModeInfo edgeMi = ref aboveIntra ? ref xd.LeftMi.Value : ref xd.AboveMi.Value;
|
||||||
|
Span<sbyte> refFrameSpan = edgeMi.RefFrame.AsSpan();
|
||||||
if (!edgeMi.HasSecondRef())
|
if (!edgeMi.HasSecondRef())
|
||||||
{
|
{
|
||||||
if (edgeMi.RefFrame[0] == Constants.LastFrame)
|
if (refFrameSpan[0] == Constants.LastFrame)
|
||||||
{
|
{
|
||||||
predContext = 3;
|
predContext = 3;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
predContext = 4 * (edgeMi.RefFrame[0] == Constants.GoldenFrame ? 1 : 0);
|
predContext = 4 * (refFrameSpan[0] == Constants.GoldenFrame ? 1 : 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
predContext = 1 + (2 * (edgeMi.RefFrame[0] == Constants.GoldenFrame ||
|
predContext = 1 + (2 * (refFrameSpan[0] == Constants.GoldenFrame ||
|
||||||
edgeMi.RefFrame[1] == Constants.GoldenFrame
|
refFrameSpan[1] == Constants.GoldenFrame
|
||||||
? 1
|
? 1
|
||||||
: 0));
|
: 0));
|
||||||
}
|
}
|
||||||
|
|
@ -345,10 +354,12 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||||
// Inter/Inter
|
// Inter/Inter
|
||||||
bool aboveHasSecond = xd.AboveMi.Value.HasSecondRef();
|
bool aboveHasSecond = xd.AboveMi.Value.HasSecondRef();
|
||||||
bool leftHasSecond = xd.LeftMi.Value.HasSecondRef();
|
bool leftHasSecond = xd.LeftMi.Value.HasSecondRef();
|
||||||
sbyte above0 = xd.AboveMi.Value.RefFrame[0];
|
Span<sbyte> aRefFrameSpan = xd.AboveMi.Value.RefFrame.AsSpan();
|
||||||
sbyte above1 = xd.AboveMi.Value.RefFrame[1];
|
sbyte above0 = aRefFrameSpan[0];
|
||||||
sbyte left0 = xd.LeftMi.Value.RefFrame[0];
|
sbyte above1 = aRefFrameSpan[1];
|
||||||
sbyte left1 = xd.LeftMi.Value.RefFrame[1];
|
Span<sbyte> lRefFrameSpan = xd.LeftMi.Value.RefFrame.AsSpan();
|
||||||
|
sbyte left0 = lRefFrameSpan[0];
|
||||||
|
sbyte left1 = lRefFrameSpan[1];
|
||||||
|
|
||||||
if (aboveHasSecond && leftHasSecond)
|
if (aboveHasSecond && leftHasSecond)
|
||||||
{
|
{
|
||||||
|
|
@ -407,19 +418,20 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||||
{
|
{
|
||||||
// One edge available
|
// One edge available
|
||||||
ref ModeInfo edgeMi = ref !xd.AboveMi.IsNull ? ref xd.AboveMi.Value : ref xd.LeftMi.Value;
|
ref ModeInfo edgeMi = ref !xd.AboveMi.IsNull ? ref xd.AboveMi.Value : ref xd.LeftMi.Value;
|
||||||
|
Span<sbyte> refFrameSpan = edgeMi.RefFrame.AsSpan();
|
||||||
|
|
||||||
if (!edgeMi.IsInterBlock() || (edgeMi.RefFrame[0] == Constants.LastFrame && !edgeMi.HasSecondRef()))
|
if (!edgeMi.IsInterBlock() || (refFrameSpan[0] == Constants.LastFrame && !edgeMi.HasSecondRef()))
|
||||||
{
|
{
|
||||||
predContext = 2;
|
predContext = 2;
|
||||||
}
|
}
|
||||||
else if (!edgeMi.HasSecondRef())
|
else if (!edgeMi.HasSecondRef())
|
||||||
{
|
{
|
||||||
predContext = 4 * (edgeMi.RefFrame[0] == Constants.GoldenFrame ? 1 : 0);
|
predContext = 4 * (refFrameSpan[0] == Constants.GoldenFrame ? 1 : 0);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
predContext = 3 * (edgeMi.RefFrame[0] == Constants.GoldenFrame ||
|
predContext = 3 * (refFrameSpan[0] == Constants.GoldenFrame ||
|
||||||
edgeMi.RefFrame[1] == Constants.GoldenFrame
|
refFrameSpan[1] == Constants.GoldenFrame
|
||||||
? 1
|
? 1
|
||||||
: 0);
|
: 0);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -37,7 +37,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||||
return (byte)BitUtils.RoundPowerOfTwo((prob1 * (256 - factor)) + (prob2 * factor), 8);
|
return (byte)BitUtils.RoundPowerOfTwo((prob1 * (256 - factor)) + (prob2 * factor), 8);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static byte MergeProbs(byte preProb, ref Array2<uint> ct, uint countSat, uint maxUpdateFactor)
|
public static byte MergeProbs(byte preProb, ReadOnlySpan<uint> ct, uint countSat, uint maxUpdateFactor)
|
||||||
{
|
{
|
||||||
byte prob = GetBinaryProb(ct[0], ct[1]);
|
byte prob = GetBinaryProb(ct[0], ct[1]);
|
||||||
uint count = Math.Min(ct[0] + ct[1], countSat);
|
uint count = Math.Min(ct[0] + ct[1], countSat);
|
||||||
|
|
@ -53,7 +53,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||||
|
|
||||||
private const int ModeMvCountSat = 20;
|
private const int ModeMvCountSat = 20;
|
||||||
|
|
||||||
public static byte ModeMvMergeProbs(byte preProb, ref Array2<uint> ct)
|
public static byte ModeMvMergeProbs(byte preProb, ReadOnlySpan<uint> ct)
|
||||||
{
|
{
|
||||||
uint den = ct[0] + ct[1];
|
uint den = ct[0] + ct[1];
|
||||||
if (den == 0)
|
if (den == 0)
|
||||||
|
|
@ -81,7 +81,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||||
Array2<uint> ct = new();
|
Array2<uint> ct = new();
|
||||||
ct[0] = leftCount;
|
ct[0] = leftCount;
|
||||||
ct[1] = rightCount;
|
ct[1] = rightCount;
|
||||||
probs[(int)(i >> 1)] = ModeMvMergeProbs(preProbs[(int)(i >> 1)], ref ct);
|
probs[(int)(i >> 1)] = ModeMvMergeProbs(preProbs[(int)(i >> 1)], ct.AsSpan());
|
||||||
return leftCount + rightCount;
|
return leftCount + rightCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -163,7 +163,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void SetupDstPlanes(
|
public static void SetupDstPlanes(
|
||||||
ref Array3<MacroBlockDPlane> planes,
|
Span<MacroBlockDPlane> planes,
|
||||||
ref Surface src,
|
ref Surface src,
|
||||||
int miRow,
|
int miRow,
|
||||||
int miCol)
|
int miCol)
|
||||||
|
|
@ -204,9 +204,11 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||||
strides[1] = src.UvStride;
|
strides[1] = src.UvStride;
|
||||||
strides[2] = src.UvStride;
|
strides[2] = src.UvStride;
|
||||||
|
|
||||||
|
Span<MacroBlockDPlane> planeSpan = xd.Plane.AsSpan();
|
||||||
|
|
||||||
for (int i = 0; i < Constants.MaxMbPlane; ++i)
|
for (int i = 0; i < Constants.MaxMbPlane; ++i)
|
||||||
{
|
{
|
||||||
ref MacroBlockDPlane pd = ref xd.Plane[i];
|
ref MacroBlockDPlane pd = ref planeSpan[i];
|
||||||
SetupPredPlanes(ref pd.Pre[idx], buffers[i], strides[i], miRow, miCol, sf, pd.SubsamplingX,
|
SetupPredPlanes(ref pd.Pre[idx], buffers[i], strides[i], miRow, miCol, sf, pd.SubsamplingX,
|
||||||
pd.SubsamplingY);
|
pd.SubsamplingY);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
using Ryujinx.Common.Memory;
|
using Ryujinx.Common.Memory;
|
||||||
|
using System;
|
||||||
|
|
||||||
namespace Ryujinx.Graphics.Nvdec.Vp9.Types
|
namespace Ryujinx.Graphics.Nvdec.Vp9.Types
|
||||||
{
|
{
|
||||||
|
|
@ -28,13 +29,16 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Types
|
||||||
{
|
{
|
||||||
ModeRefDeltaEnabled = true;
|
ModeRefDeltaEnabled = true;
|
||||||
ModeRefDeltaUpdate = true;
|
ModeRefDeltaUpdate = true;
|
||||||
|
|
||||||
|
Span<sbyte> refDeltasSpan = RefDeltas.AsSpan();
|
||||||
|
Span<sbyte> modeDeltasSpan = ModeDeltas.AsSpan();
|
||||||
|
|
||||||
RefDeltas[Constants.IntraFrame] = 1;
|
refDeltasSpan[Constants.IntraFrame] = 1;
|
||||||
RefDeltas[Constants.LastFrame] = 0;
|
refDeltasSpan[Constants.LastFrame] = 0;
|
||||||
RefDeltas[Constants.GoldenFrame] = -1;
|
refDeltasSpan[Constants.GoldenFrame] = -1;
|
||||||
RefDeltas[Constants.AltRefFrame] = -1;
|
refDeltasSpan[Constants.AltRefFrame] = -1;
|
||||||
ModeDeltas[0] = 0;
|
modeDeltasSpan[0] = 0;
|
||||||
ModeDeltas[1] = 0;
|
modeDeltasSpan[1] = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
using Ryujinx.Common.Memory;
|
using Ryujinx.Common.Memory;
|
||||||
using Ryujinx.Graphics.Nvdec.Vp9.Common;
|
using Ryujinx.Graphics.Nvdec.Vp9.Common;
|
||||||
using Ryujinx.Graphics.Video;
|
using Ryujinx.Graphics.Video;
|
||||||
|
using System;
|
||||||
|
|
||||||
namespace Ryujinx.Graphics.Nvdec.Vp9.Types
|
namespace Ryujinx.Graphics.Nvdec.Vp9.Types
|
||||||
{
|
{
|
||||||
|
|
@ -147,10 +148,12 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Types
|
||||||
|
|
||||||
public void SetupBlockPlanes(int ssX, int ssY)
|
public void SetupBlockPlanes(int ssX, int ssY)
|
||||||
{
|
{
|
||||||
|
Span<MacroBlockDPlane> planeSpan = Plane.AsSpan();
|
||||||
|
|
||||||
for (int i = 0; i < Constants.MaxMbPlane; i++)
|
for (int i = 0; i < Constants.MaxMbPlane; i++)
|
||||||
{
|
{
|
||||||
Plane[i].SubsamplingX = i != 0 ? ssX : 0;
|
planeSpan[i].SubsamplingX = i != 0 ? ssX : 0;
|
||||||
Plane[i].SubsamplingY = i != 0 ? ssY : 0;
|
planeSpan[i].SubsamplingY = i != 0 ? ssY : 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -158,12 +161,16 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Types
|
||||||
{
|
{
|
||||||
int aboveIdx = miCol * 2;
|
int aboveIdx = miCol * 2;
|
||||||
int leftIdx = (miRow * 2) & 15;
|
int leftIdx = (miRow * 2) & 15;
|
||||||
|
|
||||||
|
Span<MacroBlockDPlane> planeSpan = Plane.AsSpan();
|
||||||
|
Span<ArrayPtr<sbyte>> aboveContextSpan = AboveContext.AsSpan();
|
||||||
|
Span<Array16<sbyte>> leftContextSpan = LeftContext.AsSpan();
|
||||||
|
|
||||||
for (int i = 0; i < Constants.MaxMbPlane; ++i)
|
for (int i = 0; i < Constants.MaxMbPlane; ++i)
|
||||||
{
|
{
|
||||||
ref MacroBlockDPlane pd = ref Plane[i];
|
ref MacroBlockDPlane pd = ref planeSpan[i];
|
||||||
pd.AboveContext = AboveContext[i].Slice(aboveIdx >> pd.SubsamplingX);
|
pd.AboveContext = aboveContextSpan[i].Slice(aboveIdx >> pd.SubsamplingX);
|
||||||
pd.LeftContext = new ArrayPtr<sbyte>(ref LeftContext[i][leftIdx >> pd.SubsamplingY],
|
pd.LeftContext = new ArrayPtr<sbyte>(ref leftContextSpan[i][leftIdx >> pd.SubsamplingY],
|
||||||
16 - (leftIdx >> pd.SubsamplingY));
|
16 - (leftIdx >> pd.SubsamplingY));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -182,9 +189,11 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Types
|
||||||
|
|
||||||
public unsafe void DecResetSkipContext()
|
public unsafe void DecResetSkipContext()
|
||||||
{
|
{
|
||||||
|
Span<MacroBlockDPlane> planeSpan = Plane.AsSpan();
|
||||||
|
|
||||||
for (int i = 0; i < Constants.MaxMbPlane; i++)
|
for (int i = 0; i < Constants.MaxMbPlane; i++)
|
||||||
{
|
{
|
||||||
ref MacroBlockDPlane pd = ref Plane[i];
|
ref MacroBlockDPlane pd = ref planeSpan[i];
|
||||||
MemoryUtil.Fill(pd.AboveContext.ToPointer(), (sbyte)0, pd.N4W);
|
MemoryUtil.Fill(pd.AboveContext.ToPointer(), (sbyte)0, pd.N4W);
|
||||||
MemoryUtil.Fill(pd.LeftContext.ToPointer(), (sbyte)0, pd.N4H);
|
MemoryUtil.Fill(pd.LeftContext.ToPointer(), (sbyte)0, pd.N4H);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
using Ryujinx.Common.Memory;
|
using Ryujinx.Common.Memory;
|
||||||
|
using System;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
|
|
||||||
namespace Ryujinx.Graphics.Nvdec.Vp9.Types
|
namespace Ryujinx.Graphics.Nvdec.Vp9.Types
|
||||||
|
|
@ -65,36 +66,41 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Types
|
||||||
|
|
||||||
public Mv MvPredQ4(int idx)
|
public Mv MvPredQ4(int idx)
|
||||||
{
|
{
|
||||||
|
Span<BModeInfo> bmiSpan = Bmi.AsSpan();
|
||||||
|
|
||||||
Mv res = new()
|
Mv res = new()
|
||||||
{
|
{
|
||||||
Row = (short)ReconInter.RoundMvCompQ4(
|
Row = (short)ReconInter.RoundMvCompQ4(
|
||||||
Bmi[0].Mv[idx].Row + Bmi[1].Mv[idx].Row +
|
bmiSpan[0].Mv[idx].Row + bmiSpan[1].Mv[idx].Row +
|
||||||
Bmi[2].Mv[idx].Row + Bmi[3].Mv[idx].Row),
|
bmiSpan[2].Mv[idx].Row + bmiSpan[3].Mv[idx].Row),
|
||||||
Col = (short)ReconInter.RoundMvCompQ4(
|
Col = (short)ReconInter.RoundMvCompQ4(
|
||||||
Bmi[0].Mv[idx].Col + Bmi[1].Mv[idx].Col +
|
bmiSpan[0].Mv[idx].Col + bmiSpan[1].Mv[idx].Col +
|
||||||
Bmi[2].Mv[idx].Col + Bmi[3].Mv[idx].Col)
|
bmiSpan[2].Mv[idx].Col + bmiSpan[3].Mv[idx].Col)
|
||||||
};
|
};
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Mv MvPredQ2(int idx, int block0, int block1)
|
public Mv MvPredQ2(int idx, int block0, int block1)
|
||||||
{
|
{
|
||||||
|
Span<BModeInfo> bmiSpan = Bmi.AsSpan();
|
||||||
|
|
||||||
Mv res = new()
|
Mv res = new()
|
||||||
{
|
{
|
||||||
Row = (short)ReconInter.RoundMvCompQ2(
|
Row = (short)ReconInter.RoundMvCompQ2(
|
||||||
Bmi[block0].Mv[idx].Row +
|
bmiSpan[block0].Mv[idx].Row +
|
||||||
Bmi[block1].Mv[idx].Row),
|
bmiSpan[block1].Mv[idx].Row),
|
||||||
Col = (short)ReconInter.RoundMvCompQ2(
|
Col = (short)ReconInter.RoundMvCompQ2(
|
||||||
Bmi[block0].Mv[idx].Col +
|
bmiSpan[block0].Mv[idx].Col +
|
||||||
Bmi[block1].Mv[idx].Col)
|
bmiSpan[block1].Mv[idx].Col)
|
||||||
};
|
};
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Performs mv sign inversion if indicated by the reference frame combination.
|
// Performs mv sign inversion if indicated by the reference frame combination.
|
||||||
public Mv ScaleMv(int refr, sbyte thisRefFrame, ref Array4<sbyte> refSignBias)
|
public Mv ScaleMv(int refr, sbyte thisRefFrame, Span<sbyte> refSignBias)
|
||||||
{
|
{
|
||||||
Mv mv = Mv[refr];
|
Mv mv = Mv[refr];
|
||||||
|
|
||||||
if (refSignBias[RefFrame[refr]] != refSignBias[thisRefFrame])
|
if (refSignBias[RefFrame[refr]] != refSignBias[thisRefFrame])
|
||||||
{
|
{
|
||||||
mv.Row *= -1;
|
mv.Row *= -1;
|
||||||
|
|
|
||||||
|
|
@ -99,10 +99,12 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Types
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
Span<Array2<uint>> bitsSpan = counts.Bits[comp].AsSpan();
|
||||||
|
|
||||||
int b = c + Constants.Class0Bits - 1; // Number of bits
|
int b = c + Constants.Class0Bits - 1; // Number of bits
|
||||||
for (int i = 0; i < b; ++i)
|
for (int i = 0; i < b; ++i)
|
||||||
{
|
{
|
||||||
counts.Bits[comp][i][(d >> i) & 1] += (uint)incr;
|
bitsSpan[i][(d >> i) & 1] += (uint)incr;
|
||||||
}
|
}
|
||||||
|
|
||||||
counts.Fp[comp][f] += (uint)incr;
|
counts.Fp[comp][f] += (uint)incr;
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Types
|
||||||
public Array8<uint> FeatureMask;
|
public Array8<uint> FeatureMask;
|
||||||
public int AqAvOffset;
|
public int AqAvOffset;
|
||||||
|
|
||||||
public static byte GetPredProbSegId(ref Array3<byte> segPredProbs, ref MacroBlockD xd)
|
public static byte GetPredProbSegId(ReadOnlySpan<byte> segPredProbs, ref MacroBlockD xd)
|
||||||
{
|
{
|
||||||
return segPredProbs[xd.GetPredContextSegId()];
|
return segPredProbs[xd.GetPredContextSegId()];
|
||||||
}
|
}
|
||||||
|
|
@ -105,9 +105,12 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Types
|
||||||
UpdateMap = rb.ReadBit() != 0;
|
UpdateMap = rb.ReadBit() != 0;
|
||||||
if (UpdateMap)
|
if (UpdateMap)
|
||||||
{
|
{
|
||||||
|
Span<byte> segTreeProbSpan = fc.SegTreeProb.AsSpan();
|
||||||
|
Span<byte> segPredProbSpan = fc.SegPredProb.AsSpan();
|
||||||
|
|
||||||
for (int i = 0; i < SegTreeProbs; i++)
|
for (int i = 0; i < SegTreeProbs; i++)
|
||||||
{
|
{
|
||||||
fc.SegTreeProb[i] = rb.ReadBit() != 0
|
segTreeProbSpan[i] = rb.ReadBit() != 0
|
||||||
? (byte)rb.ReadLiteral(8)
|
? (byte)rb.ReadLiteral(8)
|
||||||
: (byte)Prob.MaxProb;
|
: (byte)Prob.MaxProb;
|
||||||
}
|
}
|
||||||
|
|
@ -117,7 +120,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Types
|
||||||
{
|
{
|
||||||
for (int i = 0; i < PredictionProbs; i++)
|
for (int i = 0; i < PredictionProbs; i++)
|
||||||
{
|
{
|
||||||
fc.SegPredProb[i] = rb.ReadBit() != 0
|
segPredProbSpan[i] = rb.ReadBit() != 0
|
||||||
? (byte)rb.ReadLiteral(8)
|
? (byte)rb.ReadLiteral(8)
|
||||||
: (byte)Prob.MaxProb;
|
: (byte)Prob.MaxProb;
|
||||||
}
|
}
|
||||||
|
|
@ -126,7 +129,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Types
|
||||||
{
|
{
|
||||||
for (int i = 0; i < PredictionProbs; i++)
|
for (int i = 0; i < PredictionProbs; i++)
|
||||||
{
|
{
|
||||||
fc.SegPredProb[i] = Prob.MaxProb;
|
segPredProbSpan[i] = Prob.MaxProb;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -155,9 +155,11 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Types
|
||||||
|
|
||||||
public bool CompoundReferenceAllowed()
|
public bool CompoundReferenceAllowed()
|
||||||
{
|
{
|
||||||
|
Span<sbyte> refFrameSignBiasSpan = RefFrameSignBias.AsSpan();
|
||||||
|
|
||||||
for (int i = 1; i < Constants.RefsPerFrame; ++i)
|
for (int i = 1; i < Constants.RefsPerFrame; ++i)
|
||||||
{
|
{
|
||||||
if (RefFrameSignBias[i + 1] != RefFrameSignBias[1])
|
if (refFrameSignBiasSpan[i + 1] != refFrameSignBiasSpan[1])
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
@ -173,13 +175,13 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Types
|
||||||
|
|
||||||
public int GetFreeFb()
|
public int GetFreeFb()
|
||||||
{
|
{
|
||||||
ref Array12<RefCntBuffer> frameBufs = ref BufferPool.Value.FrameBufs;
|
Span<RefCntBuffer> frameBuffs = BufferPool.Value.FrameBufs.AsSpan();
|
||||||
|
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i = 0; i < Constants.FrameBuffers; ++i)
|
for (i = 0; i < Constants.FrameBuffers; ++i)
|
||||||
{
|
{
|
||||||
if (frameBufs[i].RefCount == 0)
|
if (frameBuffs[i].RefCount == 0)
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -187,7 +189,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Types
|
||||||
|
|
||||||
if (i != Constants.FrameBuffers)
|
if (i != Constants.FrameBuffers)
|
||||||
{
|
{
|
||||||
frameBufs[i].RefCount = 1;
|
frameBuffs[i].RefCount = 1;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
@ -240,25 +242,29 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Types
|
||||||
|
|
||||||
private void AllocSegMap(MemoryAllocator allocator, int segMapSize)
|
private void AllocSegMap(MemoryAllocator allocator, int segMapSize)
|
||||||
{
|
{
|
||||||
|
Span<ArrayPtr<byte>> segMapArraySpan = SegMapArray.AsSpan();
|
||||||
|
|
||||||
for (int i = 0; i < Constants.NumPingPongBuffers; ++i)
|
for (int i = 0; i < Constants.NumPingPongBuffers; ++i)
|
||||||
{
|
{
|
||||||
SegMapArray[i] = allocator.Allocate<byte>(segMapSize);
|
segMapArraySpan[i] = allocator.Allocate<byte>(segMapSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Init the index.
|
// Init the index.
|
||||||
SegMapIdx = 0;
|
SegMapIdx = 0;
|
||||||
PrevSegMapIdx = 1;
|
PrevSegMapIdx = 1;
|
||||||
|
|
||||||
CurrentFrameSegMap = SegMapArray[SegMapIdx];
|
CurrentFrameSegMap = segMapArraySpan[SegMapIdx];
|
||||||
LastFrameSegMap = SegMapArray[PrevSegMapIdx];
|
LastFrameSegMap = segMapArraySpan[PrevSegMapIdx];
|
||||||
}
|
}
|
||||||
|
|
||||||
private void FreeSegMap(MemoryAllocator allocator)
|
private void FreeSegMap(MemoryAllocator allocator)
|
||||||
{
|
{
|
||||||
|
Span<ArrayPtr<byte>> segMapArraySpan = SegMapArray.AsSpan();
|
||||||
|
|
||||||
for (int i = 0; i < Constants.NumPingPongBuffers; ++i)
|
for (int i = 0; i < Constants.NumPingPongBuffers; ++i)
|
||||||
{
|
{
|
||||||
allocator.Free(SegMapArray[i]);
|
allocator.Free(segMapArraySpan[i]);
|
||||||
SegMapArray[i] = ArrayPtr<byte>.Null;
|
segMapArraySpan[i] = ArrayPtr<byte>.Null;
|
||||||
}
|
}
|
||||||
|
|
||||||
CurrentFrameSegMap = ArrayPtr<byte>.Null;
|
CurrentFrameSegMap = ArrayPtr<byte>.Null;
|
||||||
|
|
@ -366,18 +372,21 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Types
|
||||||
|
|
||||||
internal void InitMacroBlockD(ref MacroBlockD xd, ArrayPtr<int> dqcoeff)
|
internal void InitMacroBlockD(ref MacroBlockD xd, ArrayPtr<int> dqcoeff)
|
||||||
{
|
{
|
||||||
|
Span<MacroBlockDPlane> planeSpan = xd.Plane.AsSpan();
|
||||||
|
Span<ArrayPtr<sbyte>> aboveContextSpan = xd.AboveContext.AsSpan();
|
||||||
|
|
||||||
for (int i = 0; i < Constants.MaxMbPlane; ++i)
|
for (int i = 0; i < Constants.MaxMbPlane; ++i)
|
||||||
{
|
{
|
||||||
xd.Plane[i].DqCoeff = dqcoeff;
|
planeSpan[i].DqCoeff = dqcoeff;
|
||||||
xd.AboveContext[i] = AboveContext.Slice(i * 2 * TileInfo.MiColsAlignedToSb(MiCols));
|
aboveContextSpan[i] = AboveContext.Slice(i * 2 * TileInfo.MiColsAlignedToSb(MiCols));
|
||||||
|
|
||||||
if (i == 0)
|
if (i == 0)
|
||||||
{
|
{
|
||||||
MemoryUtil.Copy(ref xd.Plane[i].SegDequant, ref YDequant);
|
MemoryUtil.Copy(ref planeSpan[i].SegDequant, ref YDequant);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
MemoryUtil.Copy(ref xd.Plane[i].SegDequant, ref UvDequant);
|
MemoryUtil.Copy(ref planeSpan[i].SegDequant, ref UvDequant);
|
||||||
}
|
}
|
||||||
|
|
||||||
xd.Fc = new Ptr<Vp9EntropyProbs>(ref Fc.Value);
|
xd.Fc = new Ptr<Vp9EntropyProbs>(ref Fc.Value);
|
||||||
|
|
@ -395,32 +404,43 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Types
|
||||||
// Build y/uv dequant values based on segmentation.
|
// Build y/uv dequant values based on segmentation.
|
||||||
if (Seg.Enabled)
|
if (Seg.Enabled)
|
||||||
{
|
{
|
||||||
|
Span<Array2<short>> yDequantSpan1 = YDequant.AsSpan();
|
||||||
|
Span<Array2<short>> uvDequantSpan1 = UvDequant.AsSpan();
|
||||||
|
|
||||||
for (int i = 0; i < Constants.MaxSegments; ++i)
|
for (int i = 0; i < Constants.MaxSegments; ++i)
|
||||||
{
|
{
|
||||||
|
Span<short> yDequantSpan2 = yDequantSpan1[i].AsSpan();
|
||||||
|
Span<short> uvDequantSpan2 = uvDequantSpan1[i].AsSpan();
|
||||||
|
|
||||||
int qindex = Seg.GetQIndex(i, BaseQindex);
|
int qindex = Seg.GetQIndex(i, BaseQindex);
|
||||||
YDequant[i][0] = QuantCommon.DcQuant(qindex, YDcDeltaQ, BitDepth);
|
yDequantSpan2[0] = QuantCommon.DcQuant(qindex, YDcDeltaQ, BitDepth);
|
||||||
YDequant[i][1] = QuantCommon.AcQuant(qindex, 0, BitDepth);
|
yDequantSpan2[1] = QuantCommon.AcQuant(qindex, 0, BitDepth);
|
||||||
UvDequant[i][0] = QuantCommon.DcQuant(qindex, UvDcDeltaQ, BitDepth);
|
uvDequantSpan2[0] = QuantCommon.DcQuant(qindex, UvDcDeltaQ, BitDepth);
|
||||||
UvDequant[i][1] = QuantCommon.AcQuant(qindex, UvAcDeltaQ, BitDepth);
|
uvDequantSpan2[1] = QuantCommon.AcQuant(qindex, UvAcDeltaQ, BitDepth);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
Span<short> yDequantSpan = YDequant[0].AsSpan();
|
||||||
|
Span<short> uvDequantSpan = UvDequant[0].AsSpan();
|
||||||
|
|
||||||
int qindex = BaseQindex;
|
int qindex = BaseQindex;
|
||||||
// When segmentation is disabled, only the first value is used. The
|
// When segmentation is disabled, only the first value is used. The
|
||||||
// remaining are don't cares.
|
// remaining are don't cares.
|
||||||
YDequant[0][0] = QuantCommon.DcQuant(qindex, YDcDeltaQ, BitDepth);
|
yDequantSpan[0] = QuantCommon.DcQuant(qindex, YDcDeltaQ, BitDepth);
|
||||||
YDequant[0][1] = QuantCommon.AcQuant(qindex, 0, BitDepth);
|
yDequantSpan[1] = QuantCommon.AcQuant(qindex, 0, BitDepth);
|
||||||
UvDequant[0][0] = QuantCommon.DcQuant(qindex, UvDcDeltaQ, BitDepth);
|
uvDequantSpan[0] = QuantCommon.DcQuant(qindex, UvDcDeltaQ, BitDepth);
|
||||||
UvDequant[0][1] = QuantCommon.AcQuant(qindex, UvAcDeltaQ, BitDepth);
|
uvDequantSpan[1] = QuantCommon.AcQuant(qindex, UvAcDeltaQ, BitDepth);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetupScaleFactors()
|
public void SetupScaleFactors()
|
||||||
{
|
{
|
||||||
|
Span<RefBuffer> frameRefsSpan = FrameRefs.AsSpan();
|
||||||
|
|
||||||
for (int i = 0; i < Constants.RefsPerFrame; ++i)
|
for (int i = 0; i < Constants.RefsPerFrame; ++i)
|
||||||
{
|
{
|
||||||
ref RefBuffer refBuf = ref FrameRefs[i];
|
ref RefBuffer refBuf = ref frameRefsSpan[i];
|
||||||
refBuf.Sf.SetupScaleFactorsForFrame(refBuf.Buf.Width, refBuf.Buf.Height, Width, Height);
|
refBuf.Sf.SetupScaleFactorsForFrame(refBuf.Buf.Width, refBuf.Buf.Height, Width, Height);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -432,26 +452,34 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Types
|
||||||
|
|
||||||
if (ReferenceMode == ReferenceMode.Select)
|
if (ReferenceMode == ReferenceMode.Select)
|
||||||
{
|
{
|
||||||
|
Span<byte> compInterProbSpan = fc.CompInterProb.AsSpan();
|
||||||
|
|
||||||
for (int i = 0; i < Constants.CompInterContexts; ++i)
|
for (int i = 0; i < Constants.CompInterContexts; ++i)
|
||||||
{
|
{
|
||||||
r.DiffUpdateProb(ref fc.CompInterProb[i]);
|
r.DiffUpdateProb(ref compInterProbSpan[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ReferenceMode != ReferenceMode.Compound)
|
if (ReferenceMode != ReferenceMode.Compound)
|
||||||
{
|
{
|
||||||
|
Span<Array2<byte>> singleRefProbSpan1 = fc.SingleRefProb.AsSpan();
|
||||||
|
|
||||||
for (int i = 0; i < Constants.RefContexts; ++i)
|
for (int i = 0; i < Constants.RefContexts; ++i)
|
||||||
{
|
{
|
||||||
r.DiffUpdateProb(ref fc.SingleRefProb[i][0]);
|
Span<byte> singleRefProbSpan2 = singleRefProbSpan1[i].AsSpan();
|
||||||
r.DiffUpdateProb(ref fc.SingleRefProb[i][1]);
|
|
||||||
|
r.DiffUpdateProb(ref singleRefProbSpan2[0]);
|
||||||
|
r.DiffUpdateProb(ref singleRefProbSpan2[1]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ReferenceMode != ReferenceMode.Single)
|
if (ReferenceMode != ReferenceMode.Single)
|
||||||
{
|
{
|
||||||
|
Span<byte> compRefProbSpan = fc.CompRefProb.AsSpan();
|
||||||
|
|
||||||
for (int i = 0; i < Constants.RefContexts; ++i)
|
for (int i = 0; i < Constants.RefContexts; ++i)
|
||||||
{
|
{
|
||||||
r.DiffUpdateProb(ref fc.CompRefProb[i]);
|
r.DiffUpdateProb(ref compRefProbSpan[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -470,99 +498,124 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Types
|
||||||
|
|
||||||
public void SetupCompoundReferenceMode()
|
public void SetupCompoundReferenceMode()
|
||||||
{
|
{
|
||||||
if (RefFrameSignBias[Constants.LastFrame] == RefFrameSignBias[Constants.GoldenFrame])
|
Span<sbyte> refFrameSignBiasSpan = RefFrameSignBias.AsSpan();
|
||||||
|
Span<sbyte> compVarRefSpan = CompVarRef.AsSpan();
|
||||||
|
|
||||||
|
if (refFrameSignBiasSpan[Constants.LastFrame] == refFrameSignBiasSpan[Constants.GoldenFrame])
|
||||||
{
|
{
|
||||||
CompFixedRef = Constants.AltRefFrame;
|
CompFixedRef = Constants.AltRefFrame;
|
||||||
CompVarRef[0] = Constants.LastFrame;
|
compVarRefSpan[0] = Constants.LastFrame;
|
||||||
CompVarRef[1] = Constants.GoldenFrame;
|
compVarRefSpan[1] = Constants.GoldenFrame;
|
||||||
}
|
}
|
||||||
else if (RefFrameSignBias[Constants.LastFrame] == RefFrameSignBias[Constants.AltRefFrame])
|
else if (refFrameSignBiasSpan[Constants.LastFrame] == refFrameSignBiasSpan[Constants.AltRefFrame])
|
||||||
{
|
{
|
||||||
CompFixedRef = Constants.GoldenFrame;
|
CompFixedRef = Constants.GoldenFrame;
|
||||||
CompVarRef[0] = Constants.LastFrame;
|
compVarRefSpan[0] = Constants.LastFrame;
|
||||||
CompVarRef[1] = Constants.AltRefFrame;
|
compVarRefSpan[1] = Constants.AltRefFrame;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
CompFixedRef = Constants.LastFrame;
|
CompFixedRef = Constants.LastFrame;
|
||||||
CompVarRef[0] = Constants.GoldenFrame;
|
compVarRefSpan[0] = Constants.GoldenFrame;
|
||||||
CompVarRef[1] = Constants.AltRefFrame;
|
compVarRefSpan[1] = Constants.AltRefFrame;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void InitMvProbs()
|
public void InitMvProbs()
|
||||||
{
|
{
|
||||||
Fc.Value.Joints[0] = 32;
|
Span<byte> jointsSpan = Fc.Value.Joints.AsSpan();
|
||||||
Fc.Value.Joints[1] = 64;
|
Span<byte> signSpan = Fc.Value.Sign.AsSpan();
|
||||||
Fc.Value.Joints[2] = 96;
|
Span<Array10<byte>> classesSpan = Fc.Value.Classes.AsSpan();
|
||||||
|
Span<byte> classes0Span = classesSpan[0].AsSpan();
|
||||||
|
Span<byte> classes1Span = classesSpan[1].AsSpan();
|
||||||
|
Span<Array1<byte>> class0Span = Fc.Value.Class0.AsSpan();
|
||||||
|
Span<Array10<byte>> bitsSpan = Fc.Value.Bits.AsSpan();
|
||||||
|
Span<byte> bits0Span = bitsSpan[0].AsSpan();
|
||||||
|
Span<byte> bits1Span = bitsSpan[1].AsSpan();
|
||||||
|
Span<Array2<Array3<byte>>> class0FpSpan = Fc.Value.Class0Fp.AsSpan();
|
||||||
|
Span<Array3<byte>> class0Fp0Span = class0FpSpan[0].AsSpan();
|
||||||
|
Span<Array3<byte>> class0Fp1Span = class0FpSpan[1].AsSpan();
|
||||||
|
Span<byte> class0Fp00Span = class0Fp0Span[0].AsSpan();
|
||||||
|
Span<byte> class0Fp01Span = class0Fp0Span[1].AsSpan();
|
||||||
|
Span<byte> class0Fp10Span = class0Fp1Span[0].AsSpan();
|
||||||
|
Span<byte> class0Fp11Span = class0Fp1Span[1].AsSpan();
|
||||||
|
Span<Array3<byte>> fpSpan = Fc.Value.Fp.AsSpan();
|
||||||
|
Span<byte> fp0Span = fpSpan[0].AsSpan();
|
||||||
|
Span<byte> fp1Span = fpSpan[1].AsSpan();
|
||||||
|
Span<byte> class0HpSpan = Fc.Value.Class0Hp.AsSpan();
|
||||||
|
Span<byte> hpSpan = Fc.Value.Hp.AsSpan();
|
||||||
|
|
||||||
|
jointsSpan[0] = 32;
|
||||||
|
jointsSpan[1] = 64;
|
||||||
|
jointsSpan[2] = 96;
|
||||||
|
|
||||||
Fc.Value.Sign[0] = 128;
|
signSpan[0] = 128;
|
||||||
Fc.Value.Classes[0][0] = 224;
|
classes0Span[0] = 224;
|
||||||
Fc.Value.Classes[0][1] = 144;
|
classes0Span[1] = 144;
|
||||||
Fc.Value.Classes[0][2] = 192;
|
classes0Span[2] = 192;
|
||||||
Fc.Value.Classes[0][3] = 168;
|
classes0Span[3] = 168;
|
||||||
Fc.Value.Classes[0][4] = 192;
|
classes0Span[4] = 192;
|
||||||
Fc.Value.Classes[0][5] = 176;
|
classes0Span[5] = 176;
|
||||||
Fc.Value.Classes[0][6] = 192;
|
classes0Span[6] = 192;
|
||||||
Fc.Value.Classes[0][7] = 198;
|
classes0Span[7] = 198;
|
||||||
Fc.Value.Classes[0][8] = 198;
|
classes0Span[8] = 198;
|
||||||
Fc.Value.Classes[0][9] = 245;
|
classes0Span[9] = 245;
|
||||||
Fc.Value.Class0[0][0] = 216;
|
class0Span[0][0] = 216;
|
||||||
Fc.Value.Bits[0][0] = 136;
|
bits0Span[0] = 136;
|
||||||
Fc.Value.Bits[0][1] = 140;
|
bits0Span[1] = 140;
|
||||||
Fc.Value.Bits[0][2] = 148;
|
bits0Span[2] = 148;
|
||||||
Fc.Value.Bits[0][3] = 160;
|
bits0Span[3] = 160;
|
||||||
Fc.Value.Bits[0][4] = 176;
|
bits0Span[4] = 176;
|
||||||
Fc.Value.Bits[0][5] = 192;
|
bits0Span[5] = 192;
|
||||||
Fc.Value.Bits[0][6] = 224;
|
bits0Span[6] = 224;
|
||||||
Fc.Value.Bits[0][7] = 234;
|
bits0Span[7] = 234;
|
||||||
Fc.Value.Bits[0][8] = 234;
|
bits0Span[8] = 234;
|
||||||
Fc.Value.Bits[0][9] = 240;
|
bits0Span[9] = 240;
|
||||||
Fc.Value.Class0Fp[0][0][0] = 128;
|
class0Fp00Span[0] = 128;
|
||||||
Fc.Value.Class0Fp[0][0][1] = 128;
|
class0Fp00Span[1] = 128;
|
||||||
Fc.Value.Class0Fp[0][0][2] = 64;
|
class0Fp00Span[2] = 64;
|
||||||
Fc.Value.Class0Fp[0][1][0] = 96;
|
class0Fp01Span[0] = 96;
|
||||||
Fc.Value.Class0Fp[0][1][1] = 112;
|
class0Fp01Span[1] = 112;
|
||||||
Fc.Value.Class0Fp[0][1][2] = 64;
|
class0Fp01Span[2] = 64;
|
||||||
Fc.Value.Fp[0][0] = 64;
|
fp0Span[0] = 64;
|
||||||
Fc.Value.Fp[0][1] = 96;
|
fp0Span[1] = 96;
|
||||||
Fc.Value.Fp[0][2] = 64;
|
fp0Span[2] = 64;
|
||||||
Fc.Value.Class0Hp[0] = 160;
|
class0HpSpan[0] = 160;
|
||||||
Fc.Value.Hp[0] = 128;
|
hpSpan[0] = 128;
|
||||||
|
|
||||||
Fc.Value.Sign[1] = 128;
|
signSpan[1] = 128;
|
||||||
Fc.Value.Classes[1][0] = 216;
|
classes1Span[0] = 216;
|
||||||
Fc.Value.Classes[1][1] = 128;
|
classes1Span[1] = 128;
|
||||||
Fc.Value.Classes[1][2] = 176;
|
classes1Span[2] = 176;
|
||||||
Fc.Value.Classes[1][3] = 160;
|
classes1Span[3] = 160;
|
||||||
Fc.Value.Classes[1][4] = 176;
|
classes1Span[4] = 176;
|
||||||
Fc.Value.Classes[1][5] = 176;
|
classes1Span[5] = 176;
|
||||||
Fc.Value.Classes[1][6] = 192;
|
classes1Span[6] = 192;
|
||||||
Fc.Value.Classes[1][7] = 198;
|
classes1Span[7] = 198;
|
||||||
Fc.Value.Classes[1][8] = 198;
|
classes1Span[8] = 198;
|
||||||
Fc.Value.Classes[1][9] = 208;
|
classes1Span[9] = 208;
|
||||||
Fc.Value.Class0[1][0] = 208;
|
class0Span[1][0] = 208;
|
||||||
Fc.Value.Bits[1][0] = 136;
|
bits1Span[0] = 136;
|
||||||
Fc.Value.Bits[1][1] = 140;
|
bits1Span[1] = 140;
|
||||||
Fc.Value.Bits[1][2] = 148;
|
bits1Span[2] = 148;
|
||||||
Fc.Value.Bits[1][3] = 160;
|
bits1Span[3] = 160;
|
||||||
Fc.Value.Bits[1][4] = 176;
|
bits1Span[4] = 176;
|
||||||
Fc.Value.Bits[1][5] = 192;
|
bits1Span[5] = 192;
|
||||||
Fc.Value.Bits[1][6] = 224;
|
bits1Span[6] = 224;
|
||||||
Fc.Value.Bits[1][7] = 234;
|
bits1Span[7] = 234;
|
||||||
Fc.Value.Bits[1][8] = 234;
|
bits1Span[8] = 234;
|
||||||
Fc.Value.Bits[1][9] = 240;
|
bits1Span[9] = 240;
|
||||||
Fc.Value.Class0Fp[1][0][0] = 128;
|
class0Fp10Span[0] = 128;
|
||||||
Fc.Value.Class0Fp[1][0][1] = 128;
|
class0Fp10Span[1] = 128;
|
||||||
Fc.Value.Class0Fp[1][0][2] = 64;
|
class0Fp10Span[2] = 64;
|
||||||
Fc.Value.Class0Fp[1][1][0] = 96;
|
class0Fp11Span[0] = 96;
|
||||||
Fc.Value.Class0Fp[1][1][1] = 112;
|
class0Fp11Span[1] = 112;
|
||||||
Fc.Value.Class0Fp[1][1][2] = 64;
|
class0Fp11Span[2] = 64;
|
||||||
Fc.Value.Fp[1][0] = 64;
|
fp1Span[0] = 64;
|
||||||
Fc.Value.Fp[1][1] = 96;
|
fp1Span[1] = 96;
|
||||||
Fc.Value.Fp[1][2] = 64;
|
fp1Span[2] = 64;
|
||||||
Fc.Value.Class0Hp[1] = 160;
|
class0HpSpan[1] = 160;
|
||||||
Fc.Value.Hp[1] = 128;
|
hpSpan[1] = 128;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void AdaptMvProbs(bool allowHp)
|
public void AdaptMvProbs(bool allowHp)
|
||||||
|
|
@ -577,41 +630,74 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Types
|
||||||
counts.Joints.AsSpan(),
|
counts.Joints.AsSpan(),
|
||||||
fc.Joints.AsSpan());
|
fc.Joints.AsSpan());
|
||||||
|
|
||||||
|
Span<byte> fSignSpan = fc.Sign.AsSpan();
|
||||||
|
Span<byte> pSignSpan = preFc.Sign.AsSpan();
|
||||||
|
Span<Array2<uint>> cSignSpan = counts.Sign.AsSpan();
|
||||||
|
Span<Array10<byte>> fClassesSpan = fc.Classes.AsSpan();
|
||||||
|
Span<Array10<byte>> pClassesSpan = preFc.Classes.AsSpan();
|
||||||
|
Span<Array11<uint>> cClassesSpan = counts.Classes.AsSpan();
|
||||||
|
Span<Array1<byte>> fClass0Span = fc.Class0.AsSpan();
|
||||||
|
Span<Array1<byte>> pClass0Span = preFc.Class0.AsSpan();
|
||||||
|
Span<Array2<uint>> cClass0Span = counts.Class0.AsSpan();
|
||||||
|
Span<Array10<byte>> fBitsSpan1 = fc.Bits.AsSpan();
|
||||||
|
Span<Array10<byte>> pBitsSpan1 = preFc.Bits.AsSpan();
|
||||||
|
Span<Array10<Array2<uint>>> cBitsSpan1 = counts.Bits.AsSpan();
|
||||||
|
Span<Array2<Array3<byte>>> fClass0FpSpan1 = fc.Class0Fp.AsSpan();
|
||||||
|
Span<Array2<Array3<byte>>> pClass0FpSpan1 = preFc.Class0Fp.AsSpan();
|
||||||
|
Span<Array2<Array4<uint>>> cClass0FpSpan1 = counts.Class0Fp.AsSpan();
|
||||||
|
Span<Array3<byte>> fFpSpan = fc.Fp.AsSpan();
|
||||||
|
Span<Array3<byte>> pFpSpan = preFc.Fp.AsSpan();
|
||||||
|
Span<Array4<uint>> cFpSpan = counts.Fp.AsSpan();
|
||||||
|
Span<byte> fClass0HpSpan = fc.Class0Hp.AsSpan();
|
||||||
|
Span<byte> pClass0HpSpan = preFc.Class0Hp.AsSpan();
|
||||||
|
Span<Array2<uint>> cClass0HpSpan = counts.Class0Hp.AsSpan();
|
||||||
|
Span<byte> fHpSpan = fc.Hp.AsSpan();
|
||||||
|
Span<byte> pHpSpan = preFc.Hp.AsSpan();
|
||||||
|
Span<Array2<uint>> cHpSpan = counts.Hp.AsSpan();
|
||||||
|
|
||||||
for (int i = 0; i < 2; ++i)
|
for (int i = 0; i < 2; ++i)
|
||||||
{
|
{
|
||||||
fc.Sign[i] = Prob.ModeMvMergeProbs(preFc.Sign[i], ref counts.Sign[i]);
|
fSignSpan[i] = Prob.ModeMvMergeProbs(pSignSpan[i], cSignSpan[i].AsSpan());
|
||||||
Prob.VpxTreeMergeProbs(
|
Prob.VpxTreeMergeProbs(
|
||||||
EntropyMv.ClassTree,
|
EntropyMv.ClassTree,
|
||||||
preFc.Classes[i].AsSpan(),
|
pClassesSpan[i].AsSpan(),
|
||||||
counts.Classes[i].AsSpan(),
|
cClassesSpan[i].AsSpan(),
|
||||||
fc.Classes[i].AsSpan());
|
fClassesSpan[i].AsSpan());
|
||||||
Prob.VpxTreeMergeProbs(
|
Prob.VpxTreeMergeProbs(
|
||||||
EntropyMv.Class0Tree,
|
EntropyMv.Class0Tree,
|
||||||
preFc.Class0[i].AsSpan(),
|
pClass0Span[i].AsSpan(),
|
||||||
counts.Class0[i].AsSpan(),
|
cClass0Span[i].AsSpan(),
|
||||||
fc.Class0[i].AsSpan());
|
fClass0Span[i].AsSpan());
|
||||||
|
|
||||||
|
Span<byte> fBitsSpan2 = fBitsSpan1[i].AsSpan();
|
||||||
|
Span<byte> pBitsSpan2 = pBitsSpan1[i].AsSpan();
|
||||||
|
Span<Array2<uint>> cBitsSpan2 = cBitsSpan1[i].AsSpan();
|
||||||
|
|
||||||
for (int j = 0; j < EntropyMv.OffsetBits; ++j)
|
for (int j = 0; j < EntropyMv.OffsetBits; ++j)
|
||||||
{
|
{
|
||||||
fc.Bits[i][j] = Prob.ModeMvMergeProbs(preFc.Bits[i][j], ref counts.Bits[i][j]);
|
fBitsSpan2[j] = Prob.ModeMvMergeProbs(pBitsSpan2[j], cBitsSpan2[j].AsSpan());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Span<Array3<byte>> fClass0FpSpan2 = fClass0FpSpan1[i].AsSpan();
|
||||||
|
Span<Array3<byte>> pClass0FpSpan2 = pClass0FpSpan1[i].AsSpan();
|
||||||
|
Span<Array4<uint>> cClass0FpSpan2 = cClass0FpSpan1[i].AsSpan();
|
||||||
|
|
||||||
for (int j = 0; j < EntropyMv.Class0Size; ++j)
|
for (int j = 0; j < EntropyMv.Class0Size; ++j)
|
||||||
{
|
{
|
||||||
Prob.VpxTreeMergeProbs(
|
Prob.VpxTreeMergeProbs(
|
||||||
EntropyMv.FpTree,
|
EntropyMv.FpTree,
|
||||||
preFc.Class0Fp[i][j].AsSpan(),
|
pClass0FpSpan2[j].AsSpan(),
|
||||||
counts.Class0Fp[i][j].AsSpan(),
|
cClass0FpSpan2[j].AsSpan(),
|
||||||
fc.Class0Fp[i][j].AsSpan());
|
fClass0FpSpan2[j].AsSpan());
|
||||||
}
|
}
|
||||||
|
|
||||||
Prob.VpxTreeMergeProbs(EntropyMv.FpTree, preFc.Fp[i].AsSpan(), counts.Fp[i].AsSpan(),
|
Prob.VpxTreeMergeProbs(EntropyMv.FpTree, pFpSpan[i].AsSpan(), cFpSpan[i].AsSpan(),
|
||||||
fc.Fp[i].AsSpan());
|
fFpSpan[i].AsSpan());
|
||||||
|
|
||||||
if (allowHp)
|
if (allowHp)
|
||||||
{
|
{
|
||||||
fc.Class0Hp[i] = Prob.ModeMvMergeProbs(preFc.Class0Hp[i], ref counts.Class0Hp[i]);
|
fClass0HpSpan[i] = Prob.ModeMvMergeProbs(pClass0HpSpan[i], cClass0HpSpan[i].AsSpan());
|
||||||
fc.Hp[i] = Prob.ModeMvMergeProbs(preFc.Hp[i], ref counts.Hp[i]);
|
fHpSpan[i] = Prob.ModeMvMergeProbs(pHpSpan[i], cHpSpan[i].AsSpan());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -771,75 +857,115 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Types
|
||||||
ref Vp9EntropyProbs preFc = ref FrameContexts[(int)FrameContextIdx];
|
ref Vp9EntropyProbs preFc = ref FrameContexts[(int)FrameContextIdx];
|
||||||
ref Vp9BackwardUpdates counts = ref Counts.Value;
|
ref Vp9BackwardUpdates counts = ref Counts.Value;
|
||||||
|
|
||||||
|
Span<byte> fIntraInterProbSpan = fc.IntraInterProb.AsSpan();
|
||||||
|
Span<byte> pIntraInterProbSpan = preFc.IntraInterProb.AsSpan();
|
||||||
|
Span<Array2<uint>> cIntraInterSpan = counts.IntraInter.AsSpan();
|
||||||
|
|
||||||
for (int i = 0; i < Constants.IntraInterContexts; i++)
|
for (int i = 0; i < Constants.IntraInterContexts; i++)
|
||||||
{
|
{
|
||||||
fc.IntraInterProb[i] = Prob.ModeMvMergeProbs(preFc.IntraInterProb[i], ref counts.IntraInter[i]);
|
fIntraInterProbSpan[i] = Prob.ModeMvMergeProbs(pIntraInterProbSpan[i], cIntraInterSpan[i].AsSpan());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Span<byte> fCompInterProbSpan = fc.CompInterProb.AsSpan();
|
||||||
|
Span<byte> pCompInterProbSpan = preFc.CompInterProb.AsSpan();
|
||||||
|
Span<Array2<uint>> cCompInterSpan = counts.CompInter.AsSpan();
|
||||||
|
|
||||||
for (int i = 0; i < Constants.CompInterContexts; i++)
|
for (int i = 0; i < Constants.CompInterContexts; i++)
|
||||||
{
|
{
|
||||||
fc.CompInterProb[i] = Prob.ModeMvMergeProbs(preFc.CompInterProb[i], ref counts.CompInter[i]);
|
fCompInterProbSpan[i] = Prob.ModeMvMergeProbs(pCompInterProbSpan[i], cCompInterSpan[i].AsSpan());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Span<byte> fCompRefProbSpan = fc.CompRefProb.AsSpan();
|
||||||
|
Span<byte> pCompRefProbSpan = preFc.CompRefProb.AsSpan();
|
||||||
|
Span<Array2<uint>> cCompRefSpan = counts.CompRef.AsSpan();
|
||||||
|
|
||||||
for (int i = 0; i < Constants.RefContexts; i++)
|
for (int i = 0; i < Constants.RefContexts; i++)
|
||||||
{
|
{
|
||||||
fc.CompRefProb[i] = Prob.ModeMvMergeProbs(preFc.CompRefProb[i], ref counts.CompRef[i]);
|
fCompRefProbSpan[i] = Prob.ModeMvMergeProbs(pCompRefProbSpan[i], cCompRefSpan[i].AsSpan());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Span<Array2<byte>> fSingleRefProbSpan1 = fc.SingleRefProb.AsSpan();
|
||||||
|
Span<Array2<byte>> pSingleRefProbSpan1 = preFc.SingleRefProb.AsSpan();
|
||||||
|
Span<Array2<Array2<uint>>> cSingleRefSpan1 = counts.SingleRef.AsSpan();
|
||||||
|
|
||||||
for (int i = 0; i < Constants.RefContexts; i++)
|
for (int i = 0; i < Constants.RefContexts; i++)
|
||||||
{
|
{
|
||||||
|
Span<byte> fSingleRefProbSpan2 = fSingleRefProbSpan1[i].AsSpan();
|
||||||
|
Span<byte> pSingleRefProbSpan2 = pSingleRefProbSpan1[i].AsSpan();
|
||||||
|
Span<Array2<uint>> cSingleRefSpan2 = cSingleRefSpan1[i].AsSpan();
|
||||||
|
|
||||||
for (int j = 0; j < 2; j++)
|
for (int j = 0; j < 2; j++)
|
||||||
{
|
{
|
||||||
fc.SingleRefProb[i][j] =
|
fSingleRefProbSpan2[j] =
|
||||||
Prob.ModeMvMergeProbs(preFc.SingleRefProb[i][j], ref counts.SingleRef[i][j]);
|
Prob.ModeMvMergeProbs(pSingleRefProbSpan2[j], cSingleRefSpan2[j].AsSpan());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Span<Array3<byte>> fInterModeProbSpan = fc.InterModeProb.AsSpan();
|
||||||
|
Span<Array3<byte>> pInterModeProbSpan = preFc.InterModeProb.AsSpan();
|
||||||
|
Span<Array4<uint>> cInterModeSpan = counts.InterMode.AsSpan();
|
||||||
|
|
||||||
for (int i = 0; i < Constants.InterModeContexts; i++)
|
for (int i = 0; i < Constants.InterModeContexts; i++)
|
||||||
{
|
{
|
||||||
Prob.VpxTreeMergeProbs(
|
Prob.VpxTreeMergeProbs(
|
||||||
EntropyMode.InterModeTree,
|
EntropyMode.InterModeTree,
|
||||||
preFc.InterModeProb[i].AsSpan(),
|
pInterModeProbSpan[i].AsSpan(),
|
||||||
counts.InterMode[i].AsSpan(),
|
cInterModeSpan[i].AsSpan(),
|
||||||
fc.InterModeProb[i].AsSpan());
|
fInterModeProbSpan[i].AsSpan());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Span<Array9<byte>> fYModeProbSpan = fc.YModeProb.AsSpan();
|
||||||
|
Span<Array9<byte>> pYModeProbSpan = preFc.YModeProb.AsSpan();
|
||||||
|
Span<Array10<uint>> cYModeSpan = counts.YMode.AsSpan();
|
||||||
|
|
||||||
for (int i = 0; i < EntropyMode.BlockSizeGroups; i++)
|
for (int i = 0; i < EntropyMode.BlockSizeGroups; i++)
|
||||||
{
|
{
|
||||||
Prob.VpxTreeMergeProbs(
|
Prob.VpxTreeMergeProbs(
|
||||||
EntropyMode.IntraModeTree,
|
EntropyMode.IntraModeTree,
|
||||||
preFc.YModeProb[i].AsSpan(),
|
pYModeProbSpan[i].AsSpan(),
|
||||||
counts.YMode[i].AsSpan(),
|
cYModeSpan[i].AsSpan(),
|
||||||
fc.YModeProb[i].AsSpan());
|
fYModeProbSpan[i].AsSpan());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Span<Array9<byte>> fUvModeProbSpan = fc.UvModeProb.AsSpan();
|
||||||
|
Span<Array9<byte>> pUvModeProbSpan = preFc.UvModeProb.AsSpan();
|
||||||
|
Span<Array10<uint>> cUvModeSpan = counts.UvMode.AsSpan();
|
||||||
|
|
||||||
for (int i = 0; i < Constants.IntraModes; ++i)
|
for (int i = 0; i < Constants.IntraModes; ++i)
|
||||||
{
|
{
|
||||||
Prob.VpxTreeMergeProbs(
|
Prob.VpxTreeMergeProbs(
|
||||||
EntropyMode.IntraModeTree,
|
EntropyMode.IntraModeTree,
|
||||||
preFc.UvModeProb[i].AsSpan(),
|
pUvModeProbSpan[i].AsSpan(),
|
||||||
counts.UvMode[i].AsSpan(),
|
cUvModeSpan[i].AsSpan(),
|
||||||
fc.UvModeProb[i].AsSpan());
|
fUvModeProbSpan[i].AsSpan());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Span<Array3<byte>> fPartitionProbSpan = fc.PartitionProb.AsSpan();
|
||||||
|
Span<Array3<byte>> pPartitionProbSpan = preFc.PartitionProb.AsSpan();
|
||||||
|
Span<Array4<uint>> cPartitionSpan = counts.Partition.AsSpan();
|
||||||
|
|
||||||
for (int i = 0; i < Constants.PartitionContexts; i++)
|
for (int i = 0; i < Constants.PartitionContexts; i++)
|
||||||
{
|
{
|
||||||
Prob.VpxTreeMergeProbs(
|
Prob.VpxTreeMergeProbs(
|
||||||
EntropyMode.PartitionTree,
|
EntropyMode.PartitionTree,
|
||||||
preFc.PartitionProb[i].AsSpan(),
|
pPartitionProbSpan[i].AsSpan(),
|
||||||
counts.Partition[i].AsSpan(),
|
cPartitionSpan[i].AsSpan(),
|
||||||
fc.PartitionProb[i].AsSpan());
|
fPartitionProbSpan[i].AsSpan());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (InterpFilter == Constants.Switchable)
|
if (InterpFilter == Constants.Switchable)
|
||||||
{
|
{
|
||||||
|
Span<Array2<byte>> fSwitchableInterpProbSpan = fc.SwitchableInterpProb.AsSpan();
|
||||||
|
Span<Array2<byte>> pSwitchableInterpProbSpan = preFc.SwitchableInterpProb.AsSpan();
|
||||||
|
Span<Array3<uint>> cSwitchableInterpSpan = counts.SwitchableInterp.AsSpan();
|
||||||
|
|
||||||
for (int i = 0; i < Constants.SwitchableFilterContexts; i++)
|
for (int i = 0; i < Constants.SwitchableFilterContexts; i++)
|
||||||
{
|
{
|
||||||
Prob.VpxTreeMergeProbs(
|
Prob.VpxTreeMergeProbs(
|
||||||
EntropyMode.SwitchableInterpTree,
|
EntropyMode.SwitchableInterpTree,
|
||||||
preFc.SwitchableInterpProb[i].AsSpan(),
|
pSwitchableInterpProbSpan[i].AsSpan(),
|
||||||
counts.SwitchableInterp[i].AsSpan(),
|
cSwitchableInterpSpan[i].AsSpan(),
|
||||||
fc.SwitchableInterpProb[i].AsSpan());
|
fSwitchableInterpProbSpan[i].AsSpan());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -848,34 +974,62 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Types
|
||||||
Array1<Array2<uint>> branchCt8x8P = new();
|
Array1<Array2<uint>> branchCt8x8P = new();
|
||||||
Array2<Array2<uint>> branchCt16x16P = new();
|
Array2<Array2<uint>> branchCt16x16P = new();
|
||||||
Array3<Array2<uint>> branchCt32x32P = new();
|
Array3<Array2<uint>> branchCt32x32P = new();
|
||||||
|
|
||||||
|
Span<Array2<uint>> branchCt8x8PSpan = branchCt8x8P.AsSpan();
|
||||||
|
Span<Array2<uint>> branchCt16x16PSpan = branchCt16x16P.AsSpan();
|
||||||
|
Span<Array2<uint>> branchCt32x32PSpan = branchCt32x32P.AsSpan();
|
||||||
|
|
||||||
|
Span<Array2<uint>> tx8x8Span = counts.Tx8x8.AsSpan();
|
||||||
|
Span<Array2<uint>> tx16x16Span = counts.Tx8x8.AsSpan();
|
||||||
|
Span<Array2<uint>> tx32x32Span = counts.Tx8x8.AsSpan();
|
||||||
|
|
||||||
|
//There is no need for a Span2, as there is only ever 1 iteration
|
||||||
|
Span<Array1<byte>> fTx8x8ProbSpan = fc.Tx8x8Prob.AsSpan();
|
||||||
|
Span<Array1<byte>> pTx8x8ProbSpan = preFc.Tx8x8Prob.AsSpan();
|
||||||
|
|
||||||
|
Span<Array2<byte>> fTx16x16ProbSpan1 = fc.Tx16x16Prob.AsSpan();
|
||||||
|
Span<Array2<byte>> pTx16x16ProbSpan1 = preFc.Tx16x16Prob.AsSpan();
|
||||||
|
|
||||||
|
Span<Array3<byte>> fTx32x32ProbSpan1 = fc.Tx32x32Prob.AsSpan();
|
||||||
|
Span<Array3<byte>> pTx32x32ProbSpan1 = preFc.Tx32x32Prob.AsSpan();
|
||||||
|
|
||||||
for (int i = 0; i < EntropyMode.TxSizeContexts; ++i)
|
for (int i = 0; i < EntropyMode.TxSizeContexts; ++i)
|
||||||
{
|
{
|
||||||
EntropyMode.TxCountsToBranchCounts8x8(counts.Tx8x8[i].AsSpan(), ref branchCt8x8P);
|
EntropyMode.TxCountsToBranchCounts8x8(tx8x8Span[i].AsSpan(), branchCt8x8P.AsSpan());
|
||||||
for (int j = 0; j < (int)TxSize.TxSizes - 3; ++j)
|
for (int j = 0; j < (int)TxSize.TxSizes - 3; ++j)
|
||||||
{
|
{
|
||||||
fc.Tx8x8Prob[i][j] = Prob.ModeMvMergeProbs(preFc.Tx8x8Prob[i][j], ref branchCt8x8P[j]);
|
fTx8x8ProbSpan[i][j] = Prob.ModeMvMergeProbs(pTx8x8ProbSpan[i][j], branchCt8x8PSpan[j].AsSpan());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Span<byte> fTx16x16ProbSpan2 = fTx16x16ProbSpan1[i].AsSpan();
|
||||||
|
Span<byte> pTx16x16ProbSpan2 = pTx16x16ProbSpan1[i].AsSpan();
|
||||||
|
|
||||||
EntropyMode.TxCountsToBranchCounts16x16(counts.Tx16x16[i].AsSpan(), ref branchCt16x16P);
|
EntropyMode.TxCountsToBranchCounts16x16(tx16x16Span[i].AsSpan(), branchCt16x16P.AsSpan());
|
||||||
for (int j = 0; j < (int)TxSize.TxSizes - 2; ++j)
|
for (int j = 0; j < (int)TxSize.TxSizes - 2; ++j)
|
||||||
{
|
{
|
||||||
fc.Tx16x16Prob[i][j] =
|
fTx16x16ProbSpan2[j] =
|
||||||
Prob.ModeMvMergeProbs(preFc.Tx16x16Prob[i][j], ref branchCt16x16P[j]);
|
Prob.ModeMvMergeProbs(pTx16x16ProbSpan2[j], branchCt16x16PSpan[j].AsSpan());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Span<byte> fTx32x32ProbSpan2 = fTx32x32ProbSpan1[i].AsSpan();
|
||||||
|
Span<byte> pTx32x32ProbSpan2 = pTx32x32ProbSpan1[i].AsSpan();
|
||||||
|
|
||||||
EntropyMode.TxCountsToBranchCounts32x32(counts.Tx32x32[i].AsSpan(), ref branchCt32x32P);
|
EntropyMode.TxCountsToBranchCounts32x32(tx32x32Span[i].AsSpan(), branchCt32x32P.AsSpan());
|
||||||
for (int j = 0; j < (int)TxSize.TxSizes - 1; ++j)
|
for (int j = 0; j < (int)TxSize.TxSizes - 1; ++j)
|
||||||
{
|
{
|
||||||
fc.Tx32x32Prob[i][j] =
|
fTx32x32ProbSpan2[j] =
|
||||||
Prob.ModeMvMergeProbs(preFc.Tx32x32Prob[i][j], ref branchCt32x32P[j]);
|
Prob.ModeMvMergeProbs(pTx32x32ProbSpan2[j], branchCt32x32PSpan[j].AsSpan());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Span<byte> fSkipProbSpan = fc.SkipProb.AsSpan();
|
||||||
|
Span<byte> pSkipProbSpan = preFc.SkipProb.AsSpan();
|
||||||
|
Span<Array2<uint>> cSkipSpan = counts.Skip.AsSpan();
|
||||||
|
|
||||||
for (int i = 0; i < Constants.SkipContexts; ++i)
|
for (int i = 0; i < Constants.SkipContexts; ++i)
|
||||||
{
|
{
|
||||||
fc.SkipProb[i] = Prob.ModeMvMergeProbs(preFc.SkipProb[i], ref counts.Skip[i]);
|
fSkipProbSpan[i] = Prob.ModeMvMergeProbs(pSkipProbSpan[i], cSkipSpan[i].AsSpan());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -918,13 +1072,19 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Types
|
||||||
{
|
{
|
||||||
ref MvRef mv = ref PrevFrameMvs[i];
|
ref MvRef mv = ref PrevFrameMvs[i];
|
||||||
|
|
||||||
mv.Mv[0].Row = mvs[i].Mvs[0].Row;
|
Span<Mv> mvSpan = mv.Mv.AsSpan();
|
||||||
mv.Mv[0].Col = mvs[i].Mvs[0].Col;
|
Span<Vp9Mv> mvsSpan = mvs[i].Mvs.AsSpan();
|
||||||
mv.Mv[1].Row = mvs[i].Mvs[1].Row;
|
|
||||||
mv.Mv[1].Col = mvs[i].Mvs[1].Col;
|
|
||||||
|
|
||||||
mv.RefFrame[0] = (sbyte)mvs[i].RefFrames[0];
|
mvSpan[0].Row = mvsSpan[0].Row;
|
||||||
mv.RefFrame[1] = (sbyte)mvs[i].RefFrames[1];
|
mvSpan[0].Col = mvsSpan[0].Col;
|
||||||
|
mvSpan[1].Row = mvsSpan[1].Row;
|
||||||
|
mvSpan[1].Col = mvsSpan[1].Col;
|
||||||
|
|
||||||
|
Span<sbyte> refFrameSpan = mv.RefFrame.AsSpan();
|
||||||
|
Span<int> refFramesSpan = mvs[i].RefFrames.AsSpan();
|
||||||
|
|
||||||
|
refFrameSpan[0] = (sbyte)refFramesSpan[0];
|
||||||
|
refFrameSpan[1] = (sbyte)refFramesSpan[1];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -939,47 +1099,76 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Types
|
||||||
for (int i = 0; i < mvs.Length; i++)
|
for (int i = 0; i < mvs.Length; i++)
|
||||||
{
|
{
|
||||||
ref MvRef mv = ref CurFrameMvs[i];
|
ref MvRef mv = ref CurFrameMvs[i];
|
||||||
|
|
||||||
|
Span<Mv> mvSpan = mv.Mv.AsSpan();
|
||||||
|
Span<Vp9Mv> mvsSpan = mvs[i].Mvs.AsSpan();
|
||||||
|
|
||||||
mvs[i].Mvs[0].Row = mv.Mv[0].Row;
|
mvsSpan[0].Row = mvSpan[0].Row;
|
||||||
mvs[i].Mvs[0].Col = mv.Mv[0].Col;
|
mvsSpan[0].Col = mvSpan[0].Col;
|
||||||
mvs[i].Mvs[1].Row = mv.Mv[1].Row;
|
mvsSpan[1].Row = mvSpan[1].Row;
|
||||||
mvs[i].Mvs[1].Col = mv.Mv[1].Col;
|
mvsSpan[1].Col = mvSpan[1].Col;
|
||||||
|
|
||||||
|
Span<sbyte> refFrameSpan = mv.RefFrame.AsSpan();
|
||||||
|
Span<int> refFramesSpan = mvs[i].RefFrames.AsSpan();
|
||||||
|
|
||||||
mvs[i].RefFrames[0] = mv.RefFrame[0];
|
refFramesSpan[0] = refFrameSpan[0];
|
||||||
mvs[i].RefFrames[1] = mv.RefFrame[1];
|
refFramesSpan[1] = refFrameSpan[1];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void AdaptCoefProbs(byte txSize, uint countSat, uint updateFactor)
|
private void AdaptCoefProbs(byte txSize, uint countSat, uint updateFactor)
|
||||||
{
|
{
|
||||||
ref Vp9EntropyProbs preFc = ref FrameContexts[(int)FrameContextIdx];
|
ref Vp9EntropyProbs preFc = ref FrameContexts[(int)FrameContextIdx];
|
||||||
ref Array2<Array2<Array6<Array6<Array3<byte>>>>> probs = ref Fc.Value.CoefProbs[txSize];
|
Span<Array2<Array6<Array6<Array3<byte>>>>> probsSpan1 = Fc.Value.CoefProbs[txSize].AsSpan();
|
||||||
ref Array2<Array2<Array6<Array6<Array3<byte>>>>> preProbs = ref preFc.CoefProbs[txSize];
|
Span<Array2<Array6<Array6<Array3<byte>>>>> preProbsSpan1 = preFc.CoefProbs[txSize].AsSpan();
|
||||||
ref Array2<Array2<Array6<Array6<Array4<uint>>>>> counts = ref Counts.Value.Coef[txSize];
|
Span<Array2<Array6<Array6<Array4<uint>>>>> countsSpan1 = Counts.Value.Coef[txSize].AsSpan();
|
||||||
ref Array2<Array2<Array6<Array6<uint>>>> eobCounts = ref Counts.Value.EobBranch[txSize];
|
Span<Array2<Array6<Array6<uint>>>> eobCountsSpan1 = Counts.Value.EobBranch[txSize].AsSpan();
|
||||||
|
|
||||||
for (int i = 0; i < Constants.PlaneTypes; ++i)
|
for (int i = 0; i < Constants.PlaneTypes; ++i)
|
||||||
{
|
{
|
||||||
|
Span<Array6<Array6<Array3<byte>>>> probsSpan2 = probsSpan1[i].AsSpan();
|
||||||
|
Span<Array6<Array6<Array3<byte>>>> preProbsSpan2 = preProbsSpan1[i].AsSpan();
|
||||||
|
Span<Array6<Array6<Array4<uint>>>> countsSpan2 = countsSpan1[i].AsSpan();
|
||||||
|
Span<Array6<Array6<uint>>> eobCountsSpan2 = eobCountsSpan1[i].AsSpan();
|
||||||
|
|
||||||
for (int j = 0; j < Entropy.RefTypes; ++j)
|
for (int j = 0; j < Entropy.RefTypes; ++j)
|
||||||
{
|
{
|
||||||
|
Span<Array6<Array3<byte>>> probsSpan3 = probsSpan2[j].AsSpan();
|
||||||
|
Span<Array6<Array3<byte>>> preProbsSpan3 = preProbsSpan2[j].AsSpan();
|
||||||
|
Span<Array6<Array4<uint>>> countsSpan3 = countsSpan2[j].AsSpan();
|
||||||
|
Span<Array6<uint>> eobCountsSpan3 = eobCountsSpan2[j].AsSpan();
|
||||||
|
|
||||||
for (int k = 0; k < Entropy.CoefBands; ++k)
|
for (int k = 0; k < Entropy.CoefBands; ++k)
|
||||||
{
|
{
|
||||||
|
Span<Array3<byte>> probsSpan4 = probsSpan3[k].AsSpan();
|
||||||
|
Span<Array3<byte>> preProbsSpan4 = preProbsSpan3[k].AsSpan();
|
||||||
|
Span<Array4<uint>> countsSpan4 = countsSpan3[k].AsSpan();
|
||||||
|
Span<uint> eobCountsSpan4 = eobCountsSpan3[k].AsSpan();
|
||||||
|
|
||||||
for (int l = 0; l < Entropy.BAND_COEFF_CONTEXTS(k); ++l)
|
for (int l = 0; l < Entropy.BAND_COEFF_CONTEXTS(k); ++l)
|
||||||
{
|
{
|
||||||
int n0 = (int)counts[i][j][k][l][Entropy.ZeroToken];
|
Span<byte> probsSpan5 = probsSpan4[l].AsSpan();
|
||||||
int n1 = (int)counts[i][j][k][l][Entropy.OneToken];
|
Span<byte> preProbsSpan5 = preProbsSpan4[l].AsSpan();
|
||||||
int n2 = (int)counts[i][j][k][l][Entropy.TwoToken];
|
Span<uint> countsSpan5 = countsSpan4[l].AsSpan();
|
||||||
int neob = (int)counts[i][j][k][l][Entropy.EobModelToken];
|
|
||||||
|
int n0 = (int)countsSpan5[Entropy.ZeroToken];
|
||||||
|
int n1 = (int)countsSpan5[Entropy.OneToken];
|
||||||
|
int n2 = (int)countsSpan5[Entropy.TwoToken];
|
||||||
|
int neob = (int)countsSpan5[Entropy.EobModelToken];
|
||||||
Array3<Array2<uint>> branchCt = new();
|
Array3<Array2<uint>> branchCt = new();
|
||||||
branchCt[0][0] = (uint)neob;
|
Span<Array2<uint>> branchCtSpan = branchCt.AsSpan();
|
||||||
branchCt[0][1] = (uint)(eobCounts[i][j][k][l] - neob);
|
Span<uint> branchCt0Span = branchCtSpan[0].AsSpan();
|
||||||
branchCt[1][0] = (uint)n0;
|
Span<uint> branchCt1Span = branchCtSpan[1].AsSpan();
|
||||||
branchCt[1][1] = (uint)(n1 + n2);
|
Span<uint> branchCt2Span = branchCtSpan[2].AsSpan();
|
||||||
branchCt[2][0] = (uint)n1;
|
branchCt0Span[0] = (uint)neob;
|
||||||
branchCt[2][1] = (uint)n2;
|
branchCt0Span[1] = (uint)(eobCountsSpan4[l] - neob);
|
||||||
|
branchCt1Span[0] = (uint)n0;
|
||||||
|
branchCt1Span[1] = (uint)(n1 + n2);
|
||||||
|
branchCt2Span[0] = (uint)n1;
|
||||||
|
branchCt2Span[1] = (uint)n2;
|
||||||
for (int m = 0; m < Entropy.UnconstrainedNodes; ++m)
|
for (int m = 0; m < Entropy.UnconstrainedNodes; ++m)
|
||||||
{
|
{
|
||||||
probs[i][j][k][l][m] = Prob.MergeProbs(preProbs[i][j][k][l][m], ref branchCt[m],
|
probsSpan5[m] = Prob.MergeProbs(preProbsSpan5[m], branchCt[m].AsSpan(),
|
||||||
countSat, updateFactor);
|
countSat, updateFactor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -996,4 +1185,4 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Types
|
||||||
Entropy.CopyProbs(ref Fc.Value.CoefProbs[(int)TxSize.Tx32x32], Entropy.DefaultCoefProbs32x32);
|
Entropy.CopyProbs(ref Fc.Value.CoefProbs[(int)TxSize.Tx32x32], Entropy.DefaultCoefProbs32x32);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
using Ryujinx.Common.Memory;
|
using Ryujinx.Common.Memory;
|
||||||
using Ryujinx.Graphics.Nvdec.Vp9.Common;
|
using Ryujinx.Graphics.Nvdec.Vp9.Common;
|
||||||
using Ryujinx.Graphics.Video;
|
using Ryujinx.Graphics.Video;
|
||||||
|
using System;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
|
|
||||||
namespace Ryujinx.Graphics.Nvdec.Vp9.Types
|
namespace Ryujinx.Graphics.Nvdec.Vp9.Types
|
||||||
|
|
@ -16,20 +17,20 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Types
|
||||||
public int NeedResync; // Wait for key/intra-only frame.
|
public int NeedResync; // Wait for key/intra-only frame.
|
||||||
public int HoldRefBuf; // Hold the reference buffer.
|
public int HoldRefBuf; // Hold the reference buffer.
|
||||||
|
|
||||||
private static void DecreaseRefCount(int idx, ref Array12<RefCntBuffer> frameBufs, ref BufferPool pool)
|
private static void DecreaseRefCount(int idx, Span<RefCntBuffer> frameBuffs, ref BufferPool pool)
|
||||||
{
|
{
|
||||||
if (idx >= 0 && frameBufs[idx].RefCount > 0)
|
if (idx >= 0 && frameBuffs[idx].RefCount > 0)
|
||||||
{
|
{
|
||||||
--frameBufs[idx].RefCount;
|
--frameBuffs[idx].RefCount;
|
||||||
// A worker may only get a free framebuffer index when calling GetFreeFb.
|
// A worker may only get a free framebuffer index when calling GetFreeFb.
|
||||||
// But the private buffer is not set up until finish decoding header.
|
// But the private buffer is not set up until finish decoding header.
|
||||||
// So any error happens during decoding header, the frame_bufs will not
|
// So any error happens during decoding header, the frame_bufs will not
|
||||||
// have valid priv buffer.
|
// have valid priv buffer.
|
||||||
if (frameBufs[idx].Released == 0 && frameBufs[idx].RefCount == 0 &&
|
if (frameBuffs[idx].Released == 0 && frameBuffs[idx].RefCount == 0 &&
|
||||||
!frameBufs[idx].RawFrameBuffer.Priv.IsNull)
|
!frameBuffs[idx].RawFrameBuffer.Priv.IsNull)
|
||||||
{
|
{
|
||||||
FrameBuffers.ReleaseFrameBuffer(pool.CbPriv, ref frameBufs[idx].RawFrameBuffer);
|
FrameBuffers.ReleaseFrameBuffer(pool.CbPriv, ref frameBuffs[idx].RawFrameBuffer);
|
||||||
frameBufs[idx].Released = 1;
|
frameBuffs[idx].Released = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -43,22 +44,32 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Types
|
||||||
cm.CheckMemError(ref cm.FrameContexts,
|
cm.CheckMemError(ref cm.FrameContexts,
|
||||||
allocator.Allocate<Vp9EntropyProbs>(Constants.FrameContexts));
|
allocator.Allocate<Vp9EntropyProbs>(Constants.FrameContexts));
|
||||||
|
|
||||||
|
Span<Array10<Array9<byte>>> cKfYModeProbSpan1 = cm.Fc.Value.KfYModeProb.AsSpan();
|
||||||
|
|
||||||
for (int i = 0; i < EntropyMode.KfYModeProb.Length; i++)
|
for (int i = 0; i < EntropyMode.KfYModeProb.Length; i++)
|
||||||
{
|
{
|
||||||
|
Span<Array9<byte>> cKfYModeProbSpan2 = cKfYModeProbSpan1[i].AsSpan();
|
||||||
|
|
||||||
for (int j = 0; j < EntropyMode.KfYModeProb[i].Length; j++)
|
for (int j = 0; j < EntropyMode.KfYModeProb[i].Length; j++)
|
||||||
{
|
{
|
||||||
|
Span<byte> cKfYModeProbSpan3 = cKfYModeProbSpan2[j].AsSpan();
|
||||||
|
|
||||||
for (int k = 0; k < EntropyMode.KfYModeProb[i][j].Length; k++)
|
for (int k = 0; k < EntropyMode.KfYModeProb[i][j].Length; k++)
|
||||||
{
|
{
|
||||||
cm.Fc.Value.KfYModeProb[i][j][k] = EntropyMode.KfYModeProb[i][j][k];
|
cKfYModeProbSpan3[k] = EntropyMode.KfYModeProb[i][j][k];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Span<Array9<byte>> cKfUvModeProbSpan1 = cm.Fc.Value.KfUvModeProb.AsSpan();
|
||||||
|
|
||||||
for (int i = 0; i < EntropyMode.KfUvModeProb.Length; i++)
|
for (int i = 0; i < EntropyMode.KfUvModeProb.Length; i++)
|
||||||
{
|
{
|
||||||
|
Span<byte> cKfUvModeProbSpan2 = cKfUvModeProbSpan1[i].AsSpan();
|
||||||
|
|
||||||
for (int j = 0; j < EntropyMode.KfUvModeProb[i].Length; j++)
|
for (int j = 0; j < EntropyMode.KfUvModeProb[i].Length; j++)
|
||||||
{
|
{
|
||||||
cm.Fc.Value.KfUvModeProb[i][j] = EntropyMode.KfUvModeProb[i][j];
|
cKfUvModeProbSpan2[j] = EntropyMode.KfUvModeProb[i][j];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -88,12 +99,16 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Types
|
||||||
[57, 15, 9], // l split, a not split
|
[57, 15, 9], // l split, a not split
|
||||||
[12, 3, 3] // a/l both split
|
[12, 3, 3] // a/l both split
|
||||||
];
|
];
|
||||||
|
|
||||||
|
Span<Array3<byte>> cKfPartitionProbSpan1 = cm.Fc.Value.KfPartitionProb.AsSpan();
|
||||||
|
|
||||||
for (int i = 0; i < KfPartitionProbs.Length; i++)
|
for (int i = 0; i < KfPartitionProbs.Length; i++)
|
||||||
{
|
{
|
||||||
|
Span<byte> cKfPartitionProbSpan2 = cKfPartitionProbSpan1[i].AsSpan();
|
||||||
|
|
||||||
for (int j = 0; j < KfPartitionProbs[i].Length; j++)
|
for (int j = 0; j < KfPartitionProbs[i].Length; j++)
|
||||||
{
|
{
|
||||||
cm.Fc.Value.KfPartitionProb[i][j] = KfPartitionProbs[i][j];
|
cKfPartitionProbSpan2[j] = KfPartitionProbs[i][j];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -101,11 +116,14 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Types
|
||||||
|
|
||||||
NeedResync = 1;
|
NeedResync = 1;
|
||||||
|
|
||||||
|
Span<int> refFrameMapSpan = cm.RefFrameMap.AsSpan();
|
||||||
|
Span<int> nextRefFrameMapSpan = cm.NextRefFrameMap.AsSpan();
|
||||||
|
|
||||||
// Initialize the references to not point to any frame buffers.
|
// Initialize the references to not point to any frame buffers.
|
||||||
for (int i = 0; i < 8; i++)
|
for (int i = 0; i < 8; i++)
|
||||||
{
|
{
|
||||||
cm.RefFrameMap[i] = -1;
|
refFrameMapSpan[i] = -1;
|
||||||
cm.NextRefFrameMap[i] = -1;
|
nextRefFrameMapSpan[i] = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
cm.CurrentVideoFrame = 0;
|
cm.CurrentVideoFrame = 0;
|
||||||
|
|
@ -124,30 +142,34 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Types
|
||||||
int refIndex = 0, mask;
|
int refIndex = 0, mask;
|
||||||
ref Vp9Common cm = ref Common;
|
ref Vp9Common cm = ref Common;
|
||||||
ref BufferPool pool = ref cm.BufferPool.Value;
|
ref BufferPool pool = ref cm.BufferPool.Value;
|
||||||
ref Array12<RefCntBuffer> frameBufs = ref cm.BufferPool.Value.FrameBufs;
|
Span<RefCntBuffer> frameBufs = cm.BufferPool.Value.FrameBufs.AsSpan();
|
||||||
|
|
||||||
|
Span<int> refFrameMapSpan = cm.RefFrameMap.AsSpan();
|
||||||
|
Span<int> nextRefFrameMapSpan = cm.NextRefFrameMap.AsSpan();
|
||||||
|
Span<RefBuffer> frameRefsSpan = cm.FrameRefs.AsSpan();
|
||||||
|
|
||||||
for (mask = RefreshFrameFlags; mask != 0; mask >>= 1)
|
for (mask = RefreshFrameFlags; mask != 0; mask >>= 1)
|
||||||
{
|
{
|
||||||
int oldIdx = cm.RefFrameMap[refIndex];
|
int oldIdx = refFrameMapSpan[refIndex];
|
||||||
// Current thread releases the holding of reference frame.
|
// Current thread releases the holding of reference frame.
|
||||||
DecreaseRefCount(oldIdx, ref frameBufs, ref pool);
|
DecreaseRefCount(oldIdx, frameBufs, ref pool);
|
||||||
|
|
||||||
// Release the reference frame in reference map.
|
// Release the reference frame in reference map.
|
||||||
if ((mask & 1) != 0)
|
if ((mask & 1) != 0)
|
||||||
{
|
{
|
||||||
DecreaseRefCount(oldIdx, ref frameBufs, ref pool);
|
DecreaseRefCount(oldIdx, frameBufs, ref pool);
|
||||||
}
|
}
|
||||||
|
|
||||||
cm.RefFrameMap[refIndex] = cm.NextRefFrameMap[refIndex];
|
refFrameMapSpan[refIndex] = nextRefFrameMapSpan[refIndex];
|
||||||
++refIndex;
|
++refIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Current thread releases the holding of reference frame.
|
// Current thread releases the holding of reference frame.
|
||||||
for (; refIndex < Constants.RefFrames && cm.ShowExistingFrame == 0; ++refIndex)
|
for (; refIndex < Constants.RefFrames && cm.ShowExistingFrame == 0; ++refIndex)
|
||||||
{
|
{
|
||||||
int oldIdx = cm.RefFrameMap[refIndex];
|
int oldIdx = refFrameMapSpan[refIndex];
|
||||||
DecreaseRefCount(oldIdx, ref frameBufs, ref pool);
|
DecreaseRefCount(oldIdx, frameBufs, ref pool);
|
||||||
cm.RefFrameMap[refIndex] = cm.NextRefFrameMap[refIndex];
|
refFrameMapSpan[refIndex] = nextRefFrameMapSpan[refIndex];
|
||||||
}
|
}
|
||||||
|
|
||||||
HoldRefBuf = 0;
|
HoldRefBuf = 0;
|
||||||
|
|
@ -158,7 +180,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Types
|
||||||
// Invalidate these references until the next frame starts.
|
// Invalidate these references until the next frame starts.
|
||||||
for (refIndex = 0; refIndex < 3; refIndex++)
|
for (refIndex = 0; refIndex < 3; refIndex++)
|
||||||
{
|
{
|
||||||
cm.FrameRefs[refIndex].Idx = RefBuffer.InvalidIdx;
|
frameRefsSpan[refIndex].Idx = RefBuffer.InvalidIdx;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -166,7 +188,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Types
|
||||||
{
|
{
|
||||||
ref Vp9Common cm = ref Common;
|
ref Vp9Common cm = ref Common;
|
||||||
ref BufferPool pool = ref cm.BufferPool.Value;
|
ref BufferPool pool = ref cm.BufferPool.Value;
|
||||||
ref Array12<RefCntBuffer> frameBufs = ref cm.BufferPool.Value.FrameBufs;
|
Span<RefCntBuffer> frameBufs = cm.BufferPool.Value.FrameBufs.AsSpan();
|
||||||
ArrayPtr<byte> source = psource;
|
ArrayPtr<byte> source = psource;
|
||||||
CodecErr retcode = 0;
|
CodecErr retcode = 0;
|
||||||
cm.Error.ErrorCode = CodecErr.Ok;
|
cm.Error.ErrorCode = CodecErr.Ok;
|
||||||
|
|
@ -177,10 +199,12 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Types
|
||||||
// We do not know if the missing frame(s) was supposed to update
|
// We do not know if the missing frame(s) was supposed to update
|
||||||
// any of the reference buffers, but we act conservative and
|
// any of the reference buffers, but we act conservative and
|
||||||
// mark only the last buffer as corrupted.
|
// mark only the last buffer as corrupted.
|
||||||
|
|
||||||
|
Span<RefBuffer> frameRefsSpan = cm.FrameRefs.AsSpan();
|
||||||
|
|
||||||
if (cm.FrameRefs[0].Idx > 0)
|
if (frameRefsSpan[0].Idx > 0)
|
||||||
{
|
{
|
||||||
cm.FrameRefs[0].Buf.Corrupted = 1;
|
frameRefsSpan[0].Buf.Corrupted = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -278,9 +302,10 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Types
|
||||||
{
|
{
|
||||||
ArrayPtr<byte> dataStart = data;
|
ArrayPtr<byte> dataStart = data;
|
||||||
Array8<uint> frameSizes = new();
|
Array8<uint> frameSizes = new();
|
||||||
|
Span<uint> frameSizesSpan = frameSizes.AsSpan();
|
||||||
int frameCount = 0;
|
int frameCount = 0;
|
||||||
|
|
||||||
CodecErr res = Decoder.ParseSuperframeIndex(data, (ulong)data.Length, ref frameSizes, out frameCount);
|
CodecErr res = Decoder.ParseSuperframeIndex(data, (ulong)data.Length, frameSizesSpan, out frameCount);
|
||||||
if (res != CodecErr.Ok)
|
if (res != CodecErr.Ok)
|
||||||
{
|
{
|
||||||
return res;
|
return res;
|
||||||
|
|
@ -292,7 +317,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Types
|
||||||
for (int i = 0; i < frameCount; ++i)
|
for (int i = 0; i < frameCount; ++i)
|
||||||
{
|
{
|
||||||
ArrayPtr<byte> dataStartCopy = dataStart;
|
ArrayPtr<byte> dataStartCopy = dataStart;
|
||||||
uint frameSize = frameSizes[i];
|
uint frameSize = frameSizesSpan[i];
|
||||||
if (frameSize > (uint)dataStart.Length)
|
if (frameSize > (uint)dataStart.Length)
|
||||||
{
|
{
|
||||||
return CodecErr.CorruptFrame;
|
return CodecErr.CorruptFrame;
|
||||||
|
|
@ -343,7 +368,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Types
|
||||||
return data[0];
|
return data[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
public static CodecErr ParseSuperframeIndex(ArrayPtr<byte> data, ulong dataSz, ref Array8<uint> sizes, out int count)
|
public static CodecErr ParseSuperframeIndex(ArrayPtr<byte> data, ulong dataSz, Span<uint> sizes, out int count)
|
||||||
{
|
{
|
||||||
// A chunk ending with a byte matching 0xc0 is an invalid chunk unless
|
// A chunk ending with a byte matching 0xc0 is an invalid chunk unless
|
||||||
// it is a super frame index. If the last byte of real video compression
|
// it is a super frame index. If the last byte of real video compression
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
using Ryujinx.Common.Memory;
|
using Ryujinx.Common.Memory;
|
||||||
using Ryujinx.Graphics.Video;
|
using Ryujinx.Graphics.Video;
|
||||||
|
using System;
|
||||||
|
|
||||||
namespace Ryujinx.Graphics.Nvdec.Types.Vp9
|
namespace Ryujinx.Graphics.Nvdec.Types.Vp9
|
||||||
{
|
{
|
||||||
|
|
@ -33,15 +34,24 @@ namespace Ryujinx.Graphics.Nvdec.Types.Vp9
|
||||||
public BackwardUpdates(ref Vp9BackwardUpdates counts)
|
public BackwardUpdates(ref Vp9BackwardUpdates counts)
|
||||||
{
|
{
|
||||||
InterModeCounts = new Array7<Array3<Array2<uint>>>();
|
InterModeCounts = new Array7<Array3<Array2<uint>>>();
|
||||||
|
|
||||||
|
Span<Array3<Array2<uint>>> interModeCountsSpan1 = InterModeCounts.AsSpan();
|
||||||
|
Span<Array4<uint>> interModeSpan1 = counts.InterMode.AsSpan();
|
||||||
|
|
||||||
for (int i = 0; i < 7; i++)
|
for (int i = 0; i < 7; i++)
|
||||||
{
|
{
|
||||||
InterModeCounts[i][0][0] = counts.InterMode[i][2];
|
Span<Array2<uint>> interModeCountsSpan2 = interModeCountsSpan1[i].AsSpan();
|
||||||
InterModeCounts[i][0][1] = counts.InterMode[i][0] + counts.InterMode[i][1] + counts.InterMode[i][3];
|
Span<uint> interModeCountsSpan20 = interModeCountsSpan2[0].AsSpan();
|
||||||
InterModeCounts[i][1][0] = counts.InterMode[i][0];
|
Span<uint> interModeCountsSpan21 = interModeCountsSpan2[1].AsSpan();
|
||||||
InterModeCounts[i][1][1] = counts.InterMode[i][1] + counts.InterMode[i][3];
|
Span<uint> interModeCountsSpan22 = interModeCountsSpan2[2].AsSpan();
|
||||||
InterModeCounts[i][2][0] = counts.InterMode[i][1];
|
Span<uint> interModeSpan2 = interModeSpan1[i].AsSpan();
|
||||||
InterModeCounts[i][2][1] = counts.InterMode[i][3];
|
|
||||||
|
interModeCountsSpan20[0] = interModeSpan2[2];
|
||||||
|
interModeCountsSpan20[1] = interModeSpan2[0] + interModeSpan2[1] + interModeSpan2[3];
|
||||||
|
interModeCountsSpan21[0] = interModeSpan2[0];
|
||||||
|
interModeCountsSpan21[1] = interModeSpan2[1] + interModeSpan2[3];
|
||||||
|
interModeCountsSpan22[0] = interModeSpan2[1];
|
||||||
|
interModeCountsSpan22[1] = interModeSpan2[3];
|
||||||
}
|
}
|
||||||
|
|
||||||
YModeCounts = counts.YMode;
|
YModeCounts = counts.YMode;
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
using Ryujinx.Common.Memory;
|
using Ryujinx.Common.Memory;
|
||||||
using Ryujinx.Graphics.Video;
|
using Ryujinx.Graphics.Video;
|
||||||
|
using System;
|
||||||
|
|
||||||
namespace Ryujinx.Graphics.Nvdec.Types.Vp9
|
namespace Ryujinx.Graphics.Nvdec.Types.Vp9
|
||||||
{
|
{
|
||||||
|
|
@ -46,57 +47,98 @@ namespace Ryujinx.Graphics.Nvdec.Types.Vp9
|
||||||
|
|
||||||
public void Convert(ref Vp9EntropyProbs fc)
|
public void Convert(ref Vp9EntropyProbs fc)
|
||||||
{
|
{
|
||||||
|
Span<Array10<Array9<byte>>> kfYModeProbSpan1 = fc.KfYModeProb.AsSpan();
|
||||||
|
Span<Array10<Array8<byte>>> kfYModeProbE0ToE7Span1 = KfYModeProbE0ToE7.AsSpan();
|
||||||
|
|
||||||
for (int i = 0; i < 10; i++)
|
for (int i = 0; i < 10; i++)
|
||||||
{
|
{
|
||||||
|
Span<Array9<byte>> kfYModeProbSpan2 = kfYModeProbSpan1[i].AsSpan();
|
||||||
|
Span<Array8<byte>> kfYModeProbE0ToE7Span2 = kfYModeProbE0ToE7Span1[i].AsSpan();
|
||||||
|
|
||||||
for (int j = 0; j < 10; j++)
|
for (int j = 0; j < 10; j++)
|
||||||
{
|
{
|
||||||
|
Span<byte> kfYModeProbSpan3 = kfYModeProbSpan2[j].AsSpan();
|
||||||
|
Span<byte> kfYModeProbE0ToE7Span3 = kfYModeProbE0ToE7Span2[j].AsSpan();
|
||||||
|
|
||||||
for (int k = 0; k < 9; k++)
|
for (int k = 0; k < 9; k++)
|
||||||
{
|
{
|
||||||
fc.KfYModeProb[i][j][k] = k < 8 ? KfYModeProbE0ToE7[i][j][k] : KfYModeProbE8[i][j];
|
kfYModeProbSpan3[k] = k < 8 ? kfYModeProbE0ToE7Span3[k] : KfYModeProbE8[i][j];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fc.SegTreeProb = SegTreeProbs;
|
fc.SegTreeProb = SegTreeProbs;
|
||||||
fc.SegPredProb = SegPredProbs;
|
fc.SegPredProb = SegPredProbs;
|
||||||
|
|
||||||
|
Span<Array3<byte>> interModeProbSpan1 = fc.InterModeProb.AsSpan();
|
||||||
|
Span<Array4<byte>> gInterModeProbSpan1 = InterModeProb.AsSpan();
|
||||||
|
|
||||||
for (int i = 0; i < 7; i++)
|
for (int i = 0; i < 7; i++)
|
||||||
{
|
{
|
||||||
|
Span<byte> interModeProbSpan2 = interModeProbSpan1[i].AsSpan();
|
||||||
|
Span<byte> gInterModeProbSpan2 = gInterModeProbSpan1[i].AsSpan();
|
||||||
|
|
||||||
for (int j = 0; j < 3; j++)
|
for (int j = 0; j < 3; j++)
|
||||||
{
|
{
|
||||||
fc.InterModeProb[i][j] = InterModeProb[i][j];
|
interModeProbSpan2[j] = gInterModeProbSpan2[j];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fc.IntraInterProb = IntraInterProb;
|
fc.IntraInterProb = IntraInterProb;
|
||||||
|
|
||||||
|
Span<Array9<byte>> kfUvModeProbSpan1 = fc.KfUvModeProb.AsSpan();
|
||||||
|
Span<Array8<byte>> kfUvModeProbE0ToE7Span1 = KfUvModeProbE0ToE7.AsSpan();
|
||||||
|
Span<Array9<byte>> uvModeProbSpan1 = fc.UvModeProb.AsSpan();
|
||||||
|
Span<Array8<byte>> uvModeProbE0ToE7Span1 = UvModeProbE0ToE7.AsSpan();
|
||||||
|
|
||||||
for (int i = 0; i < 10; i++)
|
for (int i = 0; i < 10; i++)
|
||||||
{
|
{
|
||||||
|
Span<byte> kfUvModeProbSpan2 = kfUvModeProbSpan1[i].AsSpan();
|
||||||
|
Span<byte> kfUvModeProbE0ToE7Span2 = kfUvModeProbE0ToE7Span1[i].AsSpan();
|
||||||
|
Span<byte> uvModeProbSpan2 = uvModeProbSpan1[i].AsSpan();
|
||||||
|
Span<byte> uvModeProbE0ToE7Span2 = uvModeProbE0ToE7Span1[i].AsSpan();
|
||||||
|
|
||||||
for (int j = 0; j < 9; j++)
|
for (int j = 0; j < 9; j++)
|
||||||
{
|
{
|
||||||
fc.KfUvModeProb[i][j] = j < 8 ? KfUvModeProbE0ToE7[i][j] : KfUvModeProbE8[i];
|
kfUvModeProbSpan2[j] = j < 8 ? kfUvModeProbE0ToE7Span2[j] : KfUvModeProbE8[i];
|
||||||
fc.UvModeProb[i][j] = j < 8 ? UvModeProbE0ToE7[i][j] : UvModeProbE8[i];
|
uvModeProbSpan2[j] = j < 8 ? uvModeProbE0ToE7Span2[j] : UvModeProbE8[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fc.Tx8x8Prob = Tx8x8Prob;
|
fc.Tx8x8Prob = Tx8x8Prob;
|
||||||
fc.Tx16x16Prob = Tx16x16Prob;
|
fc.Tx16x16Prob = Tx16x16Prob;
|
||||||
fc.Tx32x32Prob = Tx32x32Prob;
|
fc.Tx32x32Prob = Tx32x32Prob;
|
||||||
|
|
||||||
|
Span<Array9<byte>> yModeProbSpan1 = fc.YModeProb.AsSpan();
|
||||||
|
Span<Array8<byte>> yModeProbE0ToE7Span1 = YModeProbE0ToE7.AsSpan();
|
||||||
|
|
||||||
for (int i = 0; i < 4; i++)
|
for (int i = 0; i < 4; i++)
|
||||||
{
|
{
|
||||||
|
Span<byte> yModeProbSpan2 = yModeProbSpan1[i].AsSpan();
|
||||||
|
Span<byte> yModeProbE0ToE7Span2 = yModeProbE0ToE7Span1[i].AsSpan();
|
||||||
|
|
||||||
for (int j = 0; j < 9; j++)
|
for (int j = 0; j < 9; j++)
|
||||||
{
|
{
|
||||||
fc.YModeProb[i][j] = j < 8 ? YModeProbE0ToE7[i][j] : YModeProbE8[i];
|
yModeProbSpan2[j] = j < 8 ? yModeProbE0ToE7Span2[j] : YModeProbE8[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Span<Array3<byte>> kfPartitionProbSpan1 = fc.KfPartitionProb.AsSpan();
|
||||||
|
Span<Array4<byte>> gKfPartitionProbSpan1 = KfPartitionProb.AsSpan();
|
||||||
|
Span<Array3<byte>> partitionProbSpan1 = fc.PartitionProb.AsSpan();
|
||||||
|
Span<Array4<byte>> gPartitionProbSpan1 = PartitionProb.AsSpan();
|
||||||
|
|
||||||
for (int i = 0; i < 16; i++)
|
for (int i = 0; i < 16; i++)
|
||||||
{
|
{
|
||||||
|
Span<byte> kfPartitionProbSpan2 = kfPartitionProbSpan1[i].AsSpan();
|
||||||
|
Span<byte> gKfPartitionProbSpan2 = gKfPartitionProbSpan1[i].AsSpan();
|
||||||
|
Span<byte> partitionProbSpan2 = partitionProbSpan1[i].AsSpan();
|
||||||
|
Span<byte> gPartitionProbSpan2 = gPartitionProbSpan1[i].AsSpan();
|
||||||
|
|
||||||
for (int j = 0; j < 3; j++)
|
for (int j = 0; j < 3; j++)
|
||||||
{
|
{
|
||||||
fc.KfPartitionProb[i][j] = KfPartitionProb[i][j];
|
kfPartitionProbSpan2[j] = gKfPartitionProbSpan2[j];
|
||||||
fc.PartitionProb[i][j] = PartitionProb[i][j];
|
partitionProbSpan2[j] = gPartitionProbSpan2[j];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -116,20 +158,38 @@ namespace Ryujinx.Graphics.Nvdec.Types.Vp9
|
||||||
fc.Bits = Bits;
|
fc.Bits = Bits;
|
||||||
fc.SingleRefProb = SingleRefProb;
|
fc.SingleRefProb = SingleRefProb;
|
||||||
fc.CompRefProb = CompRefProb;
|
fc.CompRefProb = CompRefProb;
|
||||||
|
|
||||||
|
Span<Array2<Array2<Array6<Array6<Array3<byte>>>>>> coefProbsSpan1 = fc.CoefProbs.AsSpan();
|
||||||
|
Span<Array2<Array2<Array6<Array6<Array4<byte>>>>>> gCoefProbsSpan1 = CoefProbs.AsSpan();
|
||||||
|
|
||||||
for (int i = 0; i < 4; i++)
|
for (int i = 0; i < 4; i++)
|
||||||
{
|
{
|
||||||
|
Span<Array2<Array6<Array6<Array3<byte>>>>> coefProbsSpan2 = coefProbsSpan1[i].AsSpan();
|
||||||
|
Span<Array2<Array6<Array6<Array4<byte>>>>> gCoefProbsSpan2 = gCoefProbsSpan1[i].AsSpan();
|
||||||
|
|
||||||
for (int j = 0; j < 2; j++)
|
for (int j = 0; j < 2; j++)
|
||||||
{
|
{
|
||||||
|
Span<Array6<Array6<Array3<byte>>>> coefProbsSpan3 = coefProbsSpan2[j].AsSpan();
|
||||||
|
Span<Array6<Array6<Array4<byte>>>> gCoefProbsSpan3 = gCoefProbsSpan2[j].AsSpan();
|
||||||
|
|
||||||
for (int k = 0; k < 2; k++)
|
for (int k = 0; k < 2; k++)
|
||||||
{
|
{
|
||||||
|
Span<Array6<Array3<byte>>> coefProbsSpan4 = coefProbsSpan3[k].AsSpan();
|
||||||
|
Span<Array6<Array4<byte>>> gCoefProbsSpan4 = gCoefProbsSpan3[k].AsSpan();
|
||||||
|
|
||||||
for (int l = 0; l < 6; l++)
|
for (int l = 0; l < 6; l++)
|
||||||
{
|
{
|
||||||
|
Span<Array3<byte>> coefProbsSpan5 = coefProbsSpan4[l].AsSpan();
|
||||||
|
Span<Array4<byte>> gCoefProbsSpan5 = gCoefProbsSpan4[l].AsSpan();
|
||||||
|
|
||||||
for (int m = 0; m < 6; m++)
|
for (int m = 0; m < 6; m++)
|
||||||
{
|
{
|
||||||
|
Span<byte> coefProbsSpan6 = coefProbsSpan5[m].AsSpan();
|
||||||
|
Span<byte> gCoefProbsSpan6 = gCoefProbsSpan5[m].AsSpan();
|
||||||
|
|
||||||
for (int n = 0; n < 3; n++)
|
for (int n = 0; n < 3; n++)
|
||||||
{
|
{
|
||||||
fc.CoefProbs[i][j][k][l][m][n] = CoefProbs[i][j][k][l][m][n];
|
coefProbsSpan6[n] = gCoefProbsSpan6[n];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ using System;
|
||||||
|
|
||||||
namespace Ryujinx.Graphics.Shader
|
namespace Ryujinx.Graphics.Shader
|
||||||
{
|
{
|
||||||
|
[Flags]
|
||||||
public enum AttributeType : byte
|
public enum AttributeType : byte
|
||||||
{
|
{
|
||||||
// Generic types.
|
// Generic types.
|
||||||
|
|
|
||||||
|
|
@ -17,12 +17,12 @@ namespace Ryujinx.Graphics.Vic.Image
|
||||||
ResourceManager rm,
|
ResourceManager rm,
|
||||||
ref SlotConfig config,
|
ref SlotConfig config,
|
||||||
ref SlotSurfaceConfig surfaceConfig,
|
ref SlotSurfaceConfig surfaceConfig,
|
||||||
ref Array8<PlaneOffsets> offsets)
|
Span<PlaneOffsets> offsets)
|
||||||
{
|
{
|
||||||
switch (surfaceConfig.SlotPixelFormat)
|
switch (surfaceConfig.SlotPixelFormat)
|
||||||
{
|
{
|
||||||
case PixelFormat.Y8___V8U8_N420:
|
case PixelFormat.Y8___V8U8_N420:
|
||||||
return ReadNv12(rm, ref config, ref surfaceConfig, ref offsets);
|
return ReadNv12(rm, ref config, ref surfaceConfig, offsets);
|
||||||
}
|
}
|
||||||
|
|
||||||
Logger.Error?.Print(LogClass.Vic, $"Unsupported pixel format \"{surfaceConfig.SlotPixelFormat}\".");
|
Logger.Error?.Print(LogClass.Vic, $"Unsupported pixel format \"{surfaceConfig.SlotPixelFormat}\".");
|
||||||
|
|
@ -37,9 +37,9 @@ namespace Ryujinx.Graphics.Vic.Image
|
||||||
ResourceManager rm,
|
ResourceManager rm,
|
||||||
ref SlotConfig config,
|
ref SlotConfig config,
|
||||||
ref SlotSurfaceConfig surfaceConfig,
|
ref SlotSurfaceConfig surfaceConfig,
|
||||||
ref Array8<PlaneOffsets> offsets)
|
Span<PlaneOffsets> offsets)
|
||||||
{
|
{
|
||||||
InputSurface input = ReadSurface(rm, ref config, ref surfaceConfig, ref offsets, 1, 2);
|
InputSurface input = ReadSurface(rm, ref config, ref surfaceConfig, offsets, 1, 2);
|
||||||
|
|
||||||
int width = input.Width;
|
int width = input.Width;
|
||||||
int height = input.Height;
|
int height = input.Height;
|
||||||
|
|
@ -273,7 +273,7 @@ namespace Ryujinx.Graphics.Vic.Image
|
||||||
ResourceManager rm,
|
ResourceManager rm,
|
||||||
ref SlotConfig config,
|
ref SlotConfig config,
|
||||||
ref SlotSurfaceConfig surfaceConfig,
|
ref SlotSurfaceConfig surfaceConfig,
|
||||||
ref Array8<PlaneOffsets> offsets,
|
Span<PlaneOffsets> offsets,
|
||||||
int bytesPerPixel,
|
int bytesPerPixel,
|
||||||
int planes)
|
int planes)
|
||||||
{
|
{
|
||||||
|
|
@ -301,17 +301,17 @@ namespace Ryujinx.Graphics.Vic.Image
|
||||||
|
|
||||||
if (planes > 0)
|
if (planes > 0)
|
||||||
{
|
{
|
||||||
surface.SetBuffer0(ReadBuffer(rm, ref config, ref offsets, linear, 0, lw, lh, bytesPerPixel, gobBlocksInY));
|
surface.SetBuffer0(ReadBuffer(rm, ref config, offsets, linear, 0, lw, lh, bytesPerPixel, gobBlocksInY));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (planes > 1)
|
if (planes > 1)
|
||||||
{
|
{
|
||||||
surface.SetBuffer1(ReadBuffer(rm, ref config, ref offsets, linear, 1, cw, ch, planes == 2 ? 2 : 1, gobBlocksInY));
|
surface.SetBuffer1(ReadBuffer(rm, ref config, offsets, linear, 1, cw, ch, planes == 2 ? 2 : 1, gobBlocksInY));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (planes > 2)
|
if (planes > 2)
|
||||||
{
|
{
|
||||||
surface.SetBuffer2(ReadBuffer(rm, ref config, ref offsets, linear, 2, cw, ch, 1, gobBlocksInY));
|
surface.SetBuffer2(ReadBuffer(rm, ref config, offsets, linear, 2, cw, ch, 1, gobBlocksInY));
|
||||||
}
|
}
|
||||||
|
|
||||||
return surface;
|
return surface;
|
||||||
|
|
@ -320,7 +320,7 @@ namespace Ryujinx.Graphics.Vic.Image
|
||||||
private static RentedBuffer ReadBuffer(
|
private static RentedBuffer ReadBuffer(
|
||||||
ResourceManager rm,
|
ResourceManager rm,
|
||||||
scoped ref SlotConfig config,
|
scoped ref SlotConfig config,
|
||||||
scoped ref Array8<PlaneOffsets> offsets,
|
Span<PlaneOffsets> offsets,
|
||||||
bool linear,
|
bool linear,
|
||||||
int plane,
|
int plane,
|
||||||
int width,
|
int width,
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
using Ryujinx.Common.Memory;
|
||||||
using Ryujinx.Graphics.Device;
|
using Ryujinx.Graphics.Device;
|
||||||
using Ryujinx.Graphics.Vic.Image;
|
using Ryujinx.Graphics.Vic.Image;
|
||||||
using Ryujinx.Graphics.Vic.Types;
|
using Ryujinx.Graphics.Vic.Types;
|
||||||
|
|
@ -34,18 +35,21 @@ namespace Ryujinx.Graphics.Vic
|
||||||
config.OutputSurfaceConfig.OutSurfaceWidth + 1,
|
config.OutputSurfaceConfig.OutSurfaceWidth + 1,
|
||||||
config.OutputSurfaceConfig.OutSurfaceHeight + 1);
|
config.OutputSurfaceConfig.OutSurfaceHeight + 1);
|
||||||
|
|
||||||
for (int i = 0; i < config.SlotStruct.Length; i++)
|
Span<SlotStruct> slotStructSpan = config.SlotStruct.AsSpan();
|
||||||
|
Span<Array8<PlaneOffsets>> setSurfacexSlotxSpan = _state.State.SetSurfacexSlotx.AsSpan();
|
||||||
|
|
||||||
|
for (int i = 0; i < slotStructSpan.Length; i++)
|
||||||
{
|
{
|
||||||
ref SlotStruct slot = ref config.SlotStruct[i];
|
ref SlotStruct slot = ref slotStructSpan[i];
|
||||||
|
|
||||||
if (!slot.SlotConfig.SlotEnable)
|
if (!slot.SlotConfig.SlotEnable)
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
ref var offsets = ref _state.State.SetSurfacexSlotx[i];
|
Span<PlaneOffsets> offsets = setSurfacexSlotxSpan[i].AsSpan();
|
||||||
|
|
||||||
using Surface src = SurfaceReader.Read(_rm, ref slot.SlotConfig, ref slot.SlotSurfaceConfig, ref offsets);
|
using Surface src = SurfaceReader.Read(_rm, ref slot.SlotConfig, ref slot.SlotSurfaceConfig, offsets);
|
||||||
|
|
||||||
int x1 = config.OutputConfig.TargetRectLeft;
|
int x1 = config.OutputConfig.TargetRectLeft;
|
||||||
int y1 = config.OutputConfig.TargetRectTop;
|
int y1 = config.OutputConfig.TargetRectTop;
|
||||||
|
|
|
||||||
|
|
@ -26,13 +26,17 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
public bool BecomesUnsetFrom(in BitMapStruct<T> from, ref BitMapStruct<T> into)
|
public bool BecomesUnsetFrom(in BitMapStruct<T> from, ref BitMapStruct<T> into)
|
||||||
{
|
{
|
||||||
bool result = false;
|
bool result = false;
|
||||||
|
|
||||||
|
Span<long> masksSpan = _masks.AsSpan();
|
||||||
|
Span<long> fMasksSpan = from._masks.AsSpan();
|
||||||
|
Span<long> iMasksSpan = into._masks.AsSpan();
|
||||||
|
|
||||||
int masks = _masks.Length;
|
int masks = masksSpan.Length;
|
||||||
for (int i = 0; i < masks; i++)
|
for (int i = 0; i < masks; i++)
|
||||||
{
|
{
|
||||||
long fromMask = from._masks[i];
|
long fromMask = fMasksSpan[i];
|
||||||
long unsetMask = (~fromMask) & (fromMask ^ _masks[i]);
|
long unsetMask = (~fromMask) & (fromMask ^ masksSpan[i]);
|
||||||
into._masks[i] = unsetMask;
|
iMasksSpan[i] = unsetMask;
|
||||||
|
|
||||||
result |= unsetMask != 0;
|
result |= unsetMask != 0;
|
||||||
}
|
}
|
||||||
|
|
@ -49,11 +53,11 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
// Iterate the set bits in the result, and signal them.
|
// Iterate the set bits in the result, and signal them.
|
||||||
|
|
||||||
int offset = 0;
|
int offset = 0;
|
||||||
int masks = _masks.Length;
|
Span<long> rMasksSpan = result._masks.AsSpan();
|
||||||
ref T resultMasks = ref result._masks;
|
int masks = rMasksSpan.Length;
|
||||||
for (int i = 0; i < masks; i++)
|
for (int i = 0; i < masks; i++)
|
||||||
{
|
{
|
||||||
long value = resultMasks[i];
|
long value = rMasksSpan[i];
|
||||||
while (value != 0)
|
while (value != 0)
|
||||||
{
|
{
|
||||||
int bit = BitOperations.TrailingZeroCount((ulong)value);
|
int bit = BitOperations.TrailingZeroCount((ulong)value);
|
||||||
|
|
@ -75,10 +79,11 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
// Iterate the set bits in the result, and signal them.
|
// Iterate the set bits in the result, and signal them.
|
||||||
|
|
||||||
int offset = 0;
|
int offset = 0;
|
||||||
int masks = _masks.Length;
|
Span<long> masksSpan = _masks.AsSpan();
|
||||||
|
int masks = masksSpan.Length;
|
||||||
for (int i = 0; i < masks; i++)
|
for (int i = 0; i < masks; i++)
|
||||||
{
|
{
|
||||||
long value = _masks[i];
|
long value = masksSpan[i];
|
||||||
while (value != 0)
|
while (value != 0)
|
||||||
{
|
{
|
||||||
int bit = BitOperations.TrailingZeroCount((ulong)value);
|
int bit = BitOperations.TrailingZeroCount((ulong)value);
|
||||||
|
|
@ -94,9 +99,11 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
|
|
||||||
public bool AnySet()
|
public bool AnySet()
|
||||||
{
|
{
|
||||||
for (int i = 0; i < _masks.Length; i++)
|
Span<long> masksSpan = _masks.AsSpan();
|
||||||
|
|
||||||
|
for (int i = 0; i < masksSpan.Length; i++)
|
||||||
{
|
{
|
||||||
if (_masks[i] != 0)
|
if (masksSpan[i] != 0)
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
@ -139,10 +146,12 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Span<long> masksSpan = _masks.AsSpan();
|
||||||
|
|
||||||
for (int i = startIndex + 1; i < endIndex; i++)
|
for (int i = startIndex + 1; i < endIndex; i++)
|
||||||
{
|
{
|
||||||
if (_masks[i] != 0)
|
if (masksSpan[i] != 0)
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
@ -200,21 +209,23 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
int endIndex = end >> IntShift;
|
int endIndex = end >> IntShift;
|
||||||
int endBit = end & IntMask;
|
int endBit = end & IntMask;
|
||||||
long endMask = (long)(ulong.MaxValue >> (IntMask - endBit));
|
long endMask = (long)(ulong.MaxValue >> (IntMask - endBit));
|
||||||
|
|
||||||
|
Span<long> masksSpan = _masks.AsSpan();
|
||||||
|
|
||||||
if (startIndex == endIndex)
|
if (startIndex == endIndex)
|
||||||
{
|
{
|
||||||
_masks[startIndex] |= startMask & endMask;
|
masksSpan[startIndex] |= startMask & endMask;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_masks[startIndex] |= startMask;
|
masksSpan[startIndex] |= startMask;
|
||||||
|
|
||||||
for (int i = startIndex + 1; i < endIndex; i++)
|
for (int i = startIndex + 1; i < endIndex; i++)
|
||||||
{
|
{
|
||||||
_masks[i] |= -1L;
|
masksSpan[i] |= -1L;
|
||||||
}
|
}
|
||||||
|
|
||||||
_masks[endIndex] |= endMask;
|
masksSpan[endIndex] |= endMask;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -222,13 +233,13 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
{
|
{
|
||||||
var result = new BitMapStruct<T>();
|
var result = new BitMapStruct<T>();
|
||||||
|
|
||||||
ref var masks = ref _masks;
|
var masksSpan = _masks.AsSpan();
|
||||||
ref var otherMasks = ref other._masks;
|
var oMasksSpan = other._masks.AsSpan();
|
||||||
ref var newMasks = ref result._masks;
|
var nMasksSpan = result._masks.AsSpan();
|
||||||
|
|
||||||
for (int i = 0; i < masks.Length; i++)
|
for (int i = 0; i < masksSpan.Length; i++)
|
||||||
{
|
{
|
||||||
newMasks[i] = masks[i] | otherMasks[i];
|
nMasksSpan[i] = masksSpan[i] | oMasksSpan[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
|
|
@ -246,17 +257,21 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
|
|
||||||
public void Clear()
|
public void Clear()
|
||||||
{
|
{
|
||||||
for (int i = 0; i < _masks.Length; i++)
|
Span<long> masksSpan = _masks.AsSpan();
|
||||||
|
|
||||||
|
for (int i = 0; i < masksSpan.Length; i++)
|
||||||
{
|
{
|
||||||
_masks[i] = 0;
|
masksSpan[i] = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ClearInt(int start, int end)
|
public void ClearInt(int start, int end)
|
||||||
{
|
{
|
||||||
|
Span<long> masksSpan = _masks.AsSpan();
|
||||||
|
|
||||||
for (int i = start; i <= end; i++)
|
for (int i = start; i <= end; i++)
|
||||||
{
|
{
|
||||||
_masks[i] = 0;
|
masksSpan[i] = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -679,7 +679,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
|
|
||||||
var program = _program;
|
var program = _program;
|
||||||
|
|
||||||
if (_dirty.HasFlag(DirtyFlags.Uniform))
|
if ((_dirty & DirtyFlags.Uniform) == DirtyFlags.Uniform)
|
||||||
{
|
{
|
||||||
if (program.UsePushDescriptors)
|
if (program.UsePushDescriptors)
|
||||||
{
|
{
|
||||||
|
|
@ -691,12 +691,12 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_dirty.HasFlag(DirtyFlags.Storage))
|
if ((_dirty & DirtyFlags.Storage) == DirtyFlags.Storage)
|
||||||
{
|
{
|
||||||
UpdateAndBind(cbs, program, PipelineBase.StorageSetIndex, pbp);
|
UpdateAndBind(cbs, program, PipelineBase.StorageSetIndex, pbp);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_dirty.HasFlag(DirtyFlags.Texture))
|
if ((_dirty & DirtyFlags.Texture) == DirtyFlags.Texture)
|
||||||
{
|
{
|
||||||
if (program.UpdateTexturesWithoutTemplate)
|
if (program.UpdateTexturesWithoutTemplate)
|
||||||
{
|
{
|
||||||
|
|
@ -708,7 +708,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_dirty.HasFlag(DirtyFlags.Image))
|
if ((_dirty & DirtyFlags.Image) == DirtyFlags.Image)
|
||||||
{
|
{
|
||||||
UpdateAndBind(cbs, program, PipelineBase.ImageSetIndex, pbp);
|
UpdateAndBind(cbs, program, PipelineBase.ImageSetIndex, pbp);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -708,9 +708,11 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
|
|
||||||
public void SetBlendState(AdvancedBlendDescriptor blend)
|
public void SetBlendState(AdvancedBlendDescriptor blend)
|
||||||
{
|
{
|
||||||
|
Span<PipelineColorBlendAttachmentState> colorBlendAttachmentStateSpan = _newState.Internal.ColorBlendAttachmentState.AsSpan();
|
||||||
|
|
||||||
for (int index = 0; index < Constants.MaxRenderTargets; index++)
|
for (int index = 0; index < Constants.MaxRenderTargets; index++)
|
||||||
{
|
{
|
||||||
ref var vkBlend = ref _newState.Internal.ColorBlendAttachmentState[index];
|
ref var vkBlend = ref colorBlendAttachmentStateSpan[index];
|
||||||
|
|
||||||
if (index == 0)
|
if (index == 0)
|
||||||
{
|
{
|
||||||
|
|
@ -983,10 +985,12 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
{
|
{
|
||||||
int count = Math.Min(Constants.MaxRenderTargets, componentMask.Length);
|
int count = Math.Min(Constants.MaxRenderTargets, componentMask.Length);
|
||||||
int writtenAttachments = 0;
|
int writtenAttachments = 0;
|
||||||
|
|
||||||
|
Span<PipelineColorBlendAttachmentState> colorBlendAttachmentStateSpan = _newState.Internal.ColorBlendAttachmentState.AsSpan();
|
||||||
|
|
||||||
for (int i = 0; i < count; i++)
|
for (int i = 0; i < count; i++)
|
||||||
{
|
{
|
||||||
ref var vkBlend = ref _newState.Internal.ColorBlendAttachmentState[i];
|
ref var vkBlend = ref colorBlendAttachmentStateSpan[i];
|
||||||
var newMask = (ColorComponentFlags)componentMask[i];
|
var newMask = (ColorComponentFlags)componentMask[i];
|
||||||
|
|
||||||
// When color write mask is 0, remove all blend state to help the pipeline cache.
|
// When color write mask is 0, remove all blend state to help the pipeline cache.
|
||||||
|
|
@ -1164,6 +1168,8 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
|
|
||||||
int count = Math.Min(Constants.MaxVertexAttributes, vertexAttribs.Length);
|
int count = Math.Min(Constants.MaxVertexAttributes, vertexAttribs.Length);
|
||||||
uint dirtyVbSizes = 0;
|
uint dirtyVbSizes = 0;
|
||||||
|
|
||||||
|
Span<VertexInputAttributeDescription> vertexAttributeDescriptionsSpan = _newState.Internal.VertexAttributeDescriptions.AsSpan();
|
||||||
|
|
||||||
for (int i = 0; i < count; i++)
|
for (int i = 0; i < count; i++)
|
||||||
{
|
{
|
||||||
|
|
@ -1177,7 +1183,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
dirtyVbSizes |= 1u << rawIndex;
|
dirtyVbSizes |= 1u << rawIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
_newState.Internal.VertexAttributeDescriptions[i] = new VertexInputAttributeDescription(
|
vertexAttributeDescriptionsSpan[i] = new VertexInputAttributeDescription(
|
||||||
(uint)i,
|
(uint)i,
|
||||||
(uint)bufferIndex,
|
(uint)bufferIndex,
|
||||||
formatCapabilities.ConvertToVertexVkFormat(attribute.Format),
|
formatCapabilities.ConvertToVertexVkFormat(attribute.Format),
|
||||||
|
|
@ -1212,7 +1218,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
int validCount = 1;
|
int validCount = 1;
|
||||||
|
|
||||||
BufferHandle lastHandle = default;
|
BufferHandle lastHandle = default;
|
||||||
Auto<DisposableBuffer> lastBuffer = default;
|
Auto<DisposableBuffer> lastBuffer = null;
|
||||||
|
|
||||||
for (int i = 0; i < count; i++)
|
for (int i = 0; i < count; i++)
|
||||||
{
|
{
|
||||||
|
|
@ -1403,6 +1409,9 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
|
|
||||||
// Look for textures that are masked out.
|
// Look for textures that are masked out.
|
||||||
|
|
||||||
|
Span<PipelineColorBlendAttachmentState> colorBlendAttachmentStateSpan =
|
||||||
|
_newState.Internal.ColorBlendAttachmentState.AsSpan();
|
||||||
|
|
||||||
for (int i = 0; i < colors.Length; i++)
|
for (int i = 0; i < colors.Length; i++)
|
||||||
{
|
{
|
||||||
if (colors[i] == null)
|
if (colors[i] == null)
|
||||||
|
|
@ -1410,7 +1419,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
ref var vkBlend = ref _newState.Internal.ColorBlendAttachmentState[i];
|
ref var vkBlend = ref colorBlendAttachmentStateSpan[i];
|
||||||
|
|
||||||
for (int j = 0; j < i; j++)
|
for (int j = 0; j < i; j++)
|
||||||
{
|
{
|
||||||
|
|
@ -1419,7 +1428,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
if (colors[i] == colors[j])
|
if (colors[i] == colors[j])
|
||||||
{
|
{
|
||||||
// Prefer the binding with no write mask.
|
// Prefer the binding with no write mask.
|
||||||
ref var vkBlend2 = ref _newState.Internal.ColorBlendAttachmentState[j];
|
ref var vkBlend2 = ref colorBlendAttachmentStateSpan[j];
|
||||||
if (vkBlend.ColorWriteMask == 0)
|
if (vkBlend.ColorWriteMask == 0)
|
||||||
{
|
{
|
||||||
colors[i] = null;
|
colors[i] = null;
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,8 @@ using Ryujinx.Common;
|
||||||
using Ryujinx.Graphics.GAL;
|
using Ryujinx.Graphics.GAL;
|
||||||
using Silk.NET.Vulkan;
|
using Silk.NET.Vulkan;
|
||||||
using System;
|
using System;
|
||||||
using Format = Silk.NET.Vulkan.Format;
|
using VulkanFormat = Silk.NET.Vulkan.Format;
|
||||||
|
using GALFormat = Ryujinx.Graphics.GAL.Format;
|
||||||
using PolygonMode = Silk.NET.Vulkan.PolygonMode;
|
using PolygonMode = Silk.NET.Vulkan.PolygonMode;
|
||||||
|
|
||||||
namespace Ryujinx.Graphics.Vulkan
|
namespace Ryujinx.Graphics.Vulkan
|
||||||
|
|
@ -23,7 +24,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
AttachmentReference* attachmentReferences = stackalloc AttachmentReference[MaxAttachments];
|
AttachmentReference* attachmentReferences = stackalloc AttachmentReference[MaxAttachments];
|
||||||
|
|
||||||
Span<int> attachmentIndices = stackalloc int[MaxAttachments];
|
Span<int> attachmentIndices = stackalloc int[MaxAttachments];
|
||||||
Span<Format> attachmentFormats = stackalloc Format[MaxAttachments];
|
Span<VulkanFormat> attachmentFormats = stackalloc VulkanFormat[MaxAttachments];
|
||||||
|
|
||||||
int attachmentCount = 0;
|
int attachmentCount = 0;
|
||||||
int colorCount = 0;
|
int colorCount = 0;
|
||||||
|
|
@ -32,14 +33,17 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
bool isNotMsOrSupportsStorage = gd.Capabilities.SupportsShaderStorageImageMultisample ||
|
bool isNotMsOrSupportsStorage = gd.Capabilities.SupportsShaderStorageImageMultisample ||
|
||||||
!state.DepthStencilFormat.IsImageCompatible();
|
!state.DepthStencilFormat.IsImageCompatible();
|
||||||
|
|
||||||
for (int i = 0; i < state.AttachmentEnable.Length; i++)
|
Span<bool> attachmentEnableSpan = state.AttachmentEnable.AsSpan();
|
||||||
|
Span<GALFormat> attachmentFormatsSpan = state.AttachmentFormats.AsSpan();
|
||||||
|
|
||||||
|
for (int i = 0; i < attachmentEnableSpan.Length; i++)
|
||||||
{
|
{
|
||||||
if (state.AttachmentEnable[i])
|
if (attachmentEnableSpan[i])
|
||||||
{
|
{
|
||||||
bool isNotMsOrSupportsStorageAttachments = gd.Capabilities.SupportsShaderStorageImageMultisample ||
|
bool isNotMsOrSupportsStorageAttachments = gd.Capabilities.SupportsShaderStorageImageMultisample ||
|
||||||
!state.AttachmentFormats[i].IsImageCompatible();
|
!attachmentFormatsSpan[i].IsImageCompatible();
|
||||||
|
|
||||||
attachmentFormats[attachmentCount] = gd.FormatCapabilities.ConvertToVkFormat(state.AttachmentFormats[i], isNotMsOrSupportsStorageAttachments);
|
attachmentFormats[attachmentCount] = gd.FormatCapabilities.ConvertToVkFormat(attachmentFormatsSpan[i], isNotMsOrSupportsStorageAttachments);
|
||||||
|
|
||||||
attachmentIndices[attachmentCount++] = i;
|
attachmentIndices[attachmentCount++] = i;
|
||||||
colorCount++;
|
colorCount++;
|
||||||
|
|
@ -222,13 +226,15 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
int vbCount = Math.Min(Constants.MaxVertexBuffers, state.VertexBufferCount);
|
int vbCount = Math.Min(Constants.MaxVertexBuffers, state.VertexBufferCount);
|
||||||
|
|
||||||
Span<int> vbScalarSizes = stackalloc int[vbCount];
|
Span<int> vbScalarSizes = stackalloc int[vbCount];
|
||||||
|
Span<VertexAttribDescriptor> vertexAttribsSpan = state.VertexAttribs.AsSpan();
|
||||||
|
Span<VertexInputAttributeDescription> vertexAttributeDescriptionsSpan = pipeline.Internal.VertexAttributeDescriptions.AsSpan();
|
||||||
|
|
||||||
for (int i = 0; i < vaCount; i++)
|
for (int i = 0; i < vaCount; i++)
|
||||||
{
|
{
|
||||||
var attribute = state.VertexAttribs[i];
|
var attribute = vertexAttribsSpan[i];
|
||||||
var bufferIndex = attribute.IsZero ? 0 : attribute.BufferIndex + 1;
|
var bufferIndex = attribute.IsZero ? 0 : attribute.BufferIndex + 1;
|
||||||
|
|
||||||
pipeline.Internal.VertexAttributeDescriptions[i] = new VertexInputAttributeDescription(
|
vertexAttributeDescriptionsSpan[i] = new VertexInputAttributeDescription(
|
||||||
(uint)i,
|
(uint)i,
|
||||||
(uint)bufferIndex,
|
(uint)bufferIndex,
|
||||||
gd.FormatCapabilities.ConvertToVertexVkFormat(attribute.Format),
|
gd.FormatCapabilities.ConvertToVertexVkFormat(attribute.Format),
|
||||||
|
|
@ -243,9 +249,12 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
int descriptorIndex = 1;
|
int descriptorIndex = 1;
|
||||||
pipeline.Internal.VertexBindingDescriptions[0] = new VertexInputBindingDescription(0, 0, VertexInputRate.Vertex);
|
pipeline.Internal.VertexBindingDescriptions[0] = new VertexInputBindingDescription(0, 0, VertexInputRate.Vertex);
|
||||||
|
|
||||||
|
Span<BufferPipelineDescriptor> vertexBuffersSpan = state.VertexBuffers.AsSpan();
|
||||||
|
Span<VertexInputBindingDescription> vertexBindingDescriptionsSpan = pipeline.Internal.VertexBindingDescriptions.AsSpan();
|
||||||
|
|
||||||
for (int i = 0; i < vbCount; i++)
|
for (int i = 0; i < vbCount; i++)
|
||||||
{
|
{
|
||||||
var vertexBuffer = state.VertexBuffers[i];
|
var vertexBuffer = vertexBuffersSpan[i];
|
||||||
|
|
||||||
if (vertexBuffer.Enable)
|
if (vertexBuffer.Enable)
|
||||||
{
|
{
|
||||||
|
|
@ -259,7 +268,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Support divisor > 1
|
// TODO: Support divisor > 1
|
||||||
pipeline.Internal.VertexBindingDescriptions[descriptorIndex++] = new VertexInputBindingDescription(
|
vertexBindingDescriptionsSpan[descriptorIndex++] = new VertexInputBindingDescription(
|
||||||
(uint)i + 1,
|
(uint)i + 1,
|
||||||
(uint)alignedStride,
|
(uint)alignedStride,
|
||||||
inputRate);
|
inputRate);
|
||||||
|
|
@ -268,15 +277,19 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
|
|
||||||
pipeline.VertexBindingDescriptionsCount = (uint)descriptorIndex;
|
pipeline.VertexBindingDescriptionsCount = (uint)descriptorIndex;
|
||||||
|
|
||||||
|
Span<BlendDescriptor> blendDescriptorsSpan = state.BlendDescriptors.AsSpan();
|
||||||
|
Span<uint> colorWriteMaskSpan = state.ColorWriteMask.AsSpan();
|
||||||
|
Span<PipelineColorBlendAttachmentState> colorBlendAttachmentStateSpan = pipeline.Internal.ColorBlendAttachmentState.AsSpan();
|
||||||
|
|
||||||
// NOTE: Viewports, Scissors are dynamic.
|
// NOTE: Viewports, Scissors are dynamic.
|
||||||
|
|
||||||
for (int i = 0; i < Constants.MaxRenderTargets; i++)
|
for (int i = 0; i < Constants.MaxRenderTargets; i++)
|
||||||
{
|
{
|
||||||
var blend = state.BlendDescriptors[i];
|
var blend = blendDescriptorsSpan[i];
|
||||||
|
|
||||||
if (blend.Enable && state.ColorWriteMask[i] != 0)
|
if (blend.Enable && colorWriteMaskSpan[i] != 0)
|
||||||
{
|
{
|
||||||
pipeline.Internal.ColorBlendAttachmentState[i] = new PipelineColorBlendAttachmentState(
|
colorBlendAttachmentStateSpan[i] = new PipelineColorBlendAttachmentState(
|
||||||
blend.Enable,
|
blend.Enable,
|
||||||
blend.ColorSrcFactor.Convert(),
|
blend.ColorSrcFactor.Convert(),
|
||||||
blend.ColorDstFactor.Convert(),
|
blend.ColorDstFactor.Convert(),
|
||||||
|
|
@ -284,12 +297,12 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
blend.AlphaSrcFactor.Convert(),
|
blend.AlphaSrcFactor.Convert(),
|
||||||
blend.AlphaDstFactor.Convert(),
|
blend.AlphaDstFactor.Convert(),
|
||||||
blend.AlphaOp.Convert(),
|
blend.AlphaOp.Convert(),
|
||||||
(ColorComponentFlags)state.ColorWriteMask[i]);
|
(ColorComponentFlags)colorWriteMaskSpan[i]);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
pipeline.Internal.ColorBlendAttachmentState[i] = new PipelineColorBlendAttachmentState(
|
colorBlendAttachmentStateSpan[i] = new PipelineColorBlendAttachmentState(
|
||||||
colorWriteMask: (ColorComponentFlags)state.ColorWriteMask[i]);
|
colorWriteMask: (ColorComponentFlags)colorWriteMaskSpan[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -297,23 +310,27 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
int maxColorAttachmentIndex = -1;
|
int maxColorAttachmentIndex = -1;
|
||||||
uint attachmentIntegerFormatMask = 0;
|
uint attachmentIntegerFormatMask = 0;
|
||||||
bool allFormatsFloatOrSrgb = true;
|
bool allFormatsFloatOrSrgb = true;
|
||||||
|
|
||||||
|
Span<bool> attachmentEnableSpan = state.AttachmentEnable.AsSpan();
|
||||||
|
Span<GALFormat> attachmentFormatsSpan = state.AttachmentFormats.AsSpan();
|
||||||
|
Span<VulkanFormat> pAttachmentFormatsSpan = pipeline.Internal.AttachmentFormats.AsSpan();
|
||||||
|
|
||||||
for (int i = 0; i < Constants.MaxRenderTargets; i++)
|
for (int i = 0; i < Constants.MaxRenderTargets; i++)
|
||||||
{
|
{
|
||||||
if (state.AttachmentEnable[i])
|
if (attachmentEnableSpan[i])
|
||||||
{
|
{
|
||||||
bool isNotMsOrSupportsStorage = gd.Capabilities.SupportsShaderStorageImageMultisample ||
|
bool isNotMsOrSupportsStorage = gd.Capabilities.SupportsShaderStorageImageMultisample ||
|
||||||
!state.AttachmentFormats[i].IsImageCompatible();
|
!attachmentFormatsSpan[i].IsImageCompatible();
|
||||||
|
|
||||||
pipeline.Internal.AttachmentFormats[attachmentCount++] = gd.FormatCapabilities.ConvertToVkFormat(state.AttachmentFormats[i], isNotMsOrSupportsStorage);
|
pAttachmentFormatsSpan[attachmentCount++] = gd.FormatCapabilities.ConvertToVkFormat(attachmentFormatsSpan[i], isNotMsOrSupportsStorage);
|
||||||
maxColorAttachmentIndex = i;
|
maxColorAttachmentIndex = i;
|
||||||
|
|
||||||
if (state.AttachmentFormats[i].IsInteger())
|
if (attachmentFormatsSpan[i].IsInteger())
|
||||||
{
|
{
|
||||||
attachmentIntegerFormatMask |= 1u << i;
|
attachmentIntegerFormatMask |= 1u << i;
|
||||||
}
|
}
|
||||||
|
|
||||||
allFormatsFloatOrSrgb &= state.AttachmentFormats[i].IsFloatOrSrgb();
|
allFormatsFloatOrSrgb &= attachmentFormatsSpan[i].IsFloatOrSrgb();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -322,7 +339,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
bool isNotMsOrSupportsStorage = !state.DepthStencilFormat.IsImageCompatible() ||
|
bool isNotMsOrSupportsStorage = !state.DepthStencilFormat.IsImageCompatible() ||
|
||||||
gd.Capabilities.SupportsShaderStorageImageMultisample;
|
gd.Capabilities.SupportsShaderStorageImageMultisample;
|
||||||
|
|
||||||
pipeline.Internal.AttachmentFormats[attachmentCount++] = gd.FormatCapabilities.ConvertToVkFormat(state.DepthStencilFormat, isNotMsOrSupportsStorage);
|
pAttachmentFormatsSpan[attachmentCount++] = gd.FormatCapabilities.ConvertToVkFormat(state.DepthStencilFormat, isNotMsOrSupportsStorage);
|
||||||
}
|
}
|
||||||
|
|
||||||
pipeline.ColorBlendAttachmentStateCount = (uint)(maxColorAttachmentIndex + 1);
|
pipeline.ColorBlendAttachmentStateCount = (uint)(maxColorAttachmentIndex + 1);
|
||||||
|
|
|
||||||
|
|
@ -552,13 +552,11 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
PAttachments = pColorBlendAttachmentState,
|
PAttachments = pColorBlendAttachmentState,
|
||||||
};
|
};
|
||||||
|
|
||||||
PipelineColorBlendAdvancedStateCreateInfoEXT colorBlendAdvancedState;
|
|
||||||
|
|
||||||
if (!AdvancedBlendSrcPreMultiplied ||
|
if (!AdvancedBlendSrcPreMultiplied ||
|
||||||
!AdvancedBlendDstPreMultiplied ||
|
!AdvancedBlendDstPreMultiplied ||
|
||||||
AdvancedBlendOverlap != BlendOverlapEXT.UncorrelatedExt)
|
AdvancedBlendOverlap != BlendOverlapEXT.UncorrelatedExt)
|
||||||
{
|
{
|
||||||
colorBlendAdvancedState = new PipelineColorBlendAdvancedStateCreateInfoEXT
|
PipelineColorBlendAdvancedStateCreateInfoEXT colorBlendAdvancedState = new()
|
||||||
{
|
{
|
||||||
SType = StructureType.PipelineColorBlendAdvancedStateCreateInfoExt,
|
SType = StructureType.PipelineColorBlendAdvancedStateCreateInfoExt,
|
||||||
SrcPremultiplied = AdvancedBlendSrcPreMultiplied,
|
SrcPremultiplied = AdvancedBlendSrcPreMultiplied,
|
||||||
|
|
@ -674,14 +672,21 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
// To work around this, we reduce the format to something that doesn't exceed the stride if possible.
|
// To work around this, we reduce the format to something that doesn't exceed the stride if possible.
|
||||||
// The assumption is that the exceeding components are not actually accessed on the shader.
|
// The assumption is that the exceeding components are not actually accessed on the shader.
|
||||||
|
|
||||||
|
Span<VertexInputAttributeDescription> vertexAttributeDescriptionsSpan =
|
||||||
|
Internal.VertexAttributeDescriptions.AsSpan();
|
||||||
|
Span<VertexInputBindingDescription> vertexBindingDescriptionsSpan =
|
||||||
|
Internal.VertexBindingDescriptions.AsSpan();
|
||||||
|
Span<VertexInputAttributeDescription> vertexAttributeDescriptions2Span =
|
||||||
|
_vertexAttributeDescriptions2.AsSpan();
|
||||||
|
|
||||||
for (int index = 0; index < VertexAttributeDescriptionsCount; index++)
|
for (int index = 0; index < VertexAttributeDescriptionsCount; index++)
|
||||||
{
|
{
|
||||||
var attribute = Internal.VertexAttributeDescriptions[index];
|
var attribute = vertexAttributeDescriptionsSpan[index];
|
||||||
int vbIndex = GetVertexBufferIndex(attribute.Binding);
|
int vbIndex = GetVertexBufferIndex(attribute.Binding);
|
||||||
|
|
||||||
if (vbIndex >= 0)
|
if (vbIndex >= 0)
|
||||||
{
|
{
|
||||||
ref var vb = ref Internal.VertexBindingDescriptions[vbIndex];
|
ref var vb = ref vertexBindingDescriptionsSpan[vbIndex];
|
||||||
|
|
||||||
Format format = attribute.Format;
|
Format format = attribute.Format;
|
||||||
|
|
||||||
|
|
@ -706,15 +711,18 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_vertexAttributeDescriptions2[index] = attribute;
|
vertexAttributeDescriptions2Span[index] = attribute;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private int GetVertexBufferIndex(uint binding)
|
private int GetVertexBufferIndex(uint binding)
|
||||||
{
|
{
|
||||||
|
Span<VertexInputBindingDescription> vertexBindingDescriptionsSpan =
|
||||||
|
Internal.VertexBindingDescriptions.AsSpan();
|
||||||
|
|
||||||
for (int index = 0; index < VertexBindingDescriptionsCount; index++)
|
for (int index = 0; index < VertexBindingDescriptionsCount; index++)
|
||||||
{
|
{
|
||||||
if (Internal.VertexBindingDescriptions[index].Binding == binding)
|
if (vertexBindingDescriptionsSpan[index].Binding == binding)
|
||||||
{
|
{
|
||||||
return index;
|
return index;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -86,37 +86,45 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
Id6 * 23 ^
|
Id6 * 23 ^
|
||||||
Id7 * 23 ^
|
Id7 * 23 ^
|
||||||
Id8 * 23;
|
Id8 * 23;
|
||||||
|
|
||||||
|
ReadOnlySpan<VertexInputAttributeDescription> vertexAttributeDescriptionsSpan = VertexAttributeDescriptions.AsSpan();
|
||||||
|
|
||||||
for (int i = 0; i < (int)VertexAttributeDescriptionsCount; i++)
|
for (int i = 0; i < (int)VertexAttributeDescriptionsCount; i++)
|
||||||
{
|
{
|
||||||
hash64 ^= VertexAttributeDescriptions[i].Binding * 23;
|
hash64 ^= vertexAttributeDescriptionsSpan[i].Binding * 23;
|
||||||
hash64 ^= (uint)VertexAttributeDescriptions[i].Format * 23;
|
hash64 ^= (uint)vertexAttributeDescriptionsSpan[i].Format * 23;
|
||||||
hash64 ^= VertexAttributeDescriptions[i].Location * 23;
|
hash64 ^= vertexAttributeDescriptionsSpan[i].Location * 23;
|
||||||
hash64 ^= VertexAttributeDescriptions[i].Offset * 23;
|
hash64 ^= vertexAttributeDescriptionsSpan[i].Offset * 23;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ReadOnlySpan<VertexInputBindingDescription> vertexBindingDescriptionsSpan = VertexBindingDescriptions.AsSpan();
|
||||||
|
|
||||||
for (int i = 0; i < (int)VertexBindingDescriptionsCount; i++)
|
for (int i = 0; i < (int)VertexBindingDescriptionsCount; i++)
|
||||||
{
|
{
|
||||||
hash64 ^= VertexBindingDescriptions[i].Binding * 23;
|
hash64 ^= vertexBindingDescriptionsSpan[i].Binding * 23;
|
||||||
hash64 ^= (uint)VertexBindingDescriptions[i].InputRate * 23;
|
hash64 ^= (uint)vertexBindingDescriptionsSpan[i].InputRate * 23;
|
||||||
hash64 ^= VertexBindingDescriptions[i].Stride * 23;
|
hash64 ^= vertexBindingDescriptionsSpan[i].Stride * 23;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ReadOnlySpan<PipelineColorBlendAttachmentState> colorBlendAttachmentStateSpan = ColorBlendAttachmentState.AsSpan();
|
||||||
|
|
||||||
for (int i = 0; i < (int)ColorBlendAttachmentStateCount; i++)
|
for (int i = 0; i < (int)ColorBlendAttachmentStateCount; i++)
|
||||||
{
|
{
|
||||||
hash64 ^= ColorBlendAttachmentState[i].BlendEnable * 23;
|
hash64 ^= colorBlendAttachmentStateSpan[i].BlendEnable * 23;
|
||||||
hash64 ^= (uint)ColorBlendAttachmentState[i].SrcColorBlendFactor * 23;
|
hash64 ^= (uint)colorBlendAttachmentStateSpan[i].SrcColorBlendFactor * 23;
|
||||||
hash64 ^= (uint)ColorBlendAttachmentState[i].DstColorBlendFactor * 23;
|
hash64 ^= (uint)colorBlendAttachmentStateSpan[i].DstColorBlendFactor * 23;
|
||||||
hash64 ^= (uint)ColorBlendAttachmentState[i].ColorBlendOp * 23;
|
hash64 ^= (uint)colorBlendAttachmentStateSpan[i].ColorBlendOp * 23;
|
||||||
hash64 ^= (uint)ColorBlendAttachmentState[i].SrcAlphaBlendFactor * 23;
|
hash64 ^= (uint)colorBlendAttachmentStateSpan[i].SrcAlphaBlendFactor * 23;
|
||||||
hash64 ^= (uint)ColorBlendAttachmentState[i].DstAlphaBlendFactor * 23;
|
hash64 ^= (uint)colorBlendAttachmentStateSpan[i].DstAlphaBlendFactor * 23;
|
||||||
hash64 ^= (uint)ColorBlendAttachmentState[i].AlphaBlendOp * 23;
|
hash64 ^= (uint)colorBlendAttachmentStateSpan[i].AlphaBlendOp * 23;
|
||||||
hash64 ^= (uint)ColorBlendAttachmentState[i].ColorWriteMask * 23;
|
hash64 ^= (uint)colorBlendAttachmentStateSpan[i].ColorWriteMask * 23;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ReadOnlySpan<Format> attachmentFormatsSpan = AttachmentFormats.AsSpan();
|
||||||
|
|
||||||
for (int i = 0; i < (int)ColorBlendAttachmentStateCount; i++)
|
for (int i = 0; i < (int)ColorBlendAttachmentStateCount; i++)
|
||||||
{
|
{
|
||||||
hash64 ^= (uint)AttachmentFormats[i] * 23;
|
hash64 ^= (uint)attachmentFormatsSpan[i] * 23;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (int)hash64 ^ ((int)(hash64 >> 32) * 17);
|
return (int)hash64 ^ ((int)(hash64 >> 32) * 17);
|
||||||
|
|
|
||||||
|
|
@ -581,7 +581,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
|
||||||
{
|
{
|
||||||
KThread selectedSuggestedCore = context.Schedulers[suggestedCore]._state.SelectedThread;
|
KThread selectedSuggestedCore = context.Schedulers[suggestedCore]._state.SelectedThread;
|
||||||
|
|
||||||
if (selectedSuggestedCore == suggested || (selectedSuggestedCore != null && selectedSuggestedCore.DynamicPriority < 2))
|
if (selectedSuggestedCore == suggested || selectedSuggestedCore is { DynamicPriority: < 2 })
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
using ARMeilleure.State;
|
||||||
using Ryujinx.Common.Logging;
|
using Ryujinx.Common.Logging;
|
||||||
using Ryujinx.Cpu;
|
using Ryujinx.Cpu;
|
||||||
using Ryujinx.HLE.Debugger;
|
using Ryujinx.HLE.Debugger;
|
||||||
|
|
@ -684,17 +685,20 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
|
||||||
const int MaxFpuRegistersAArch32 = 16;
|
const int MaxFpuRegistersAArch32 = 16;
|
||||||
|
|
||||||
ThreadContext context = new();
|
ThreadContext context = new();
|
||||||
|
|
||||||
|
Span<ulong> registersSpan = context.Registers.AsSpan();
|
||||||
|
Span<V128> fpuRegistersSpan = context.FpuRegisters.AsSpan();
|
||||||
|
|
||||||
if (Owner.Flags.HasFlag(ProcessCreationFlags.Is64Bit))
|
if (Owner.Flags.HasFlag(ProcessCreationFlags.Is64Bit))
|
||||||
{
|
{
|
||||||
for (int i = 0; i < context.Registers.Length; i++)
|
for (int i = 0; i < registersSpan.Length; i++)
|
||||||
{
|
{
|
||||||
context.Registers[i] = Context.GetX(i);
|
registersSpan[i] = Context.GetX(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < context.FpuRegisters.Length; i++)
|
for (int i = 0; i < fpuRegistersSpan.Length; i++)
|
||||||
{
|
{
|
||||||
context.FpuRegisters[i] = Context.GetV(i);
|
fpuRegistersSpan[i] = Context.GetV(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
context.Fp = Context.GetX(29);
|
context.Fp = Context.GetX(29);
|
||||||
|
|
@ -708,12 +712,12 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
|
||||||
{
|
{
|
||||||
for (int i = 0; i < MaxRegistersAArch32; i++)
|
for (int i = 0; i < MaxRegistersAArch32; i++)
|
||||||
{
|
{
|
||||||
context.Registers[i] = (uint)Context.GetX(i);
|
registersSpan[i] = (uint)Context.GetX(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < MaxFpuRegistersAArch32; i++)
|
for (int i = 0; i < MaxFpuRegistersAArch32; i++)
|
||||||
{
|
{
|
||||||
context.FpuRegisters[i] = Context.GetV(i);
|
fpuRegistersSpan[i] = Context.GetV(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
context.Pc = (uint)Context.Pc;
|
context.Pc = (uint)Context.Pc;
|
||||||
|
|
|
||||||
|
|
@ -75,17 +75,21 @@ namespace Ryujinx.HLE.HOS.Services.Fatal
|
||||||
{
|
{
|
||||||
errorReport.AppendLine("\tStackTrace:");
|
errorReport.AppendLine("\tStackTrace:");
|
||||||
|
|
||||||
|
Span<ulong> stackTraceSpan = cpuContext64.StackTrace.AsSpan();
|
||||||
|
|
||||||
for (int i = 0; i < cpuContext64.StackTraceSize; i++)
|
for (int i = 0; i < cpuContext64.StackTraceSize; i++)
|
||||||
{
|
{
|
||||||
errorReport.AppendLine($"\t\t0x{cpuContext64.StackTrace[i]:x16}");
|
errorReport.AppendLine($"\t\t0x{stackTraceSpan[i]:x16}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
errorReport.AppendLine("\tRegisters:");
|
errorReport.AppendLine("\tRegisters:");
|
||||||
|
|
||||||
|
Span<ulong> xSpan = cpuContext64.X.AsSpan();
|
||||||
|
|
||||||
for (int i = 0; i < cpuContext64.X.Length; i++)
|
for (int i = 0; i < xSpan.Length; i++)
|
||||||
{
|
{
|
||||||
errorReport.AppendLine($"\t\tX[{i:d2}]:\t0x{cpuContext64.X[i]:x16}");
|
errorReport.AppendLine($"\t\tX[{i:d2}]:\t0x{xSpan[i]:x16}");
|
||||||
}
|
}
|
||||||
|
|
||||||
errorReport.AppendLine();
|
errorReport.AppendLine();
|
||||||
|
|
@ -109,18 +113,22 @@ namespace Ryujinx.HLE.HOS.Services.Fatal
|
||||||
if (cpuContext32.StackTraceSize > 0)
|
if (cpuContext32.StackTraceSize > 0)
|
||||||
{
|
{
|
||||||
errorReport.AppendLine("\tStackTrace:");
|
errorReport.AppendLine("\tStackTrace:");
|
||||||
|
|
||||||
|
Span<uint> stackTraceSpan = cpuContext32.StackTrace.AsSpan();
|
||||||
|
|
||||||
for (int i = 0; i < cpuContext32.StackTraceSize; i++)
|
for (int i = 0; i < cpuContext32.StackTraceSize; i++)
|
||||||
{
|
{
|
||||||
errorReport.AppendLine($"\t\t0x{cpuContext32.StackTrace[i]:x16}");
|
errorReport.AppendLine($"\t\t0x{stackTraceSpan[i]:x16}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
errorReport.AppendLine("\tRegisters:");
|
errorReport.AppendLine("\tRegisters:");
|
||||||
|
|
||||||
|
Span<uint> xSpan = cpuContext32.X.AsSpan();
|
||||||
|
|
||||||
for (int i = 0; i < cpuContext32.X.Length; i++)
|
for (int i = 0; i < xSpan.Length; i++)
|
||||||
{
|
{
|
||||||
errorReport.AppendLine($"\t\tX[{i:d2}]:\t0x{cpuContext32.X[i]:x16}");
|
errorReport.AppendLine($"\t\tX[{i:d2}]:\t0x{xSpan[i]:x16}");
|
||||||
}
|
}
|
||||||
|
|
||||||
errorReport.AppendLine();
|
errorReport.AppendLine();
|
||||||
|
|
|
||||||
|
|
@ -94,6 +94,8 @@ namespace Ryujinx.HLE.HOS.Services.Hid
|
||||||
primaryIndex = PlayerIndex.Unknown;
|
primaryIndex = PlayerIndex.Unknown;
|
||||||
configuredCount = 0;
|
configuredCount = 0;
|
||||||
|
|
||||||
|
Span<NpadState> nPadsSpan = _device.Hid.SharedMemory.Npads.AsSpan();
|
||||||
|
|
||||||
for (int i = 0; i < MaxControllers; ++i)
|
for (int i = 0; i < MaxControllers; ++i)
|
||||||
{
|
{
|
||||||
ControllerType npad = _configuredTypes[i];
|
ControllerType npad = _configuredTypes[i];
|
||||||
|
|
@ -103,7 +105,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
ControllerType currentType = (ControllerType)_device.Hid.SharedMemory.Npads[i].InternalState.StyleSet;
|
ControllerType currentType = (ControllerType)nPadsSpan[i].InternalState.StyleSet;
|
||||||
|
|
||||||
if (currentType != ControllerType.None && (npad & acceptedTypes) != 0 && _supportedPlayers[i])
|
if (currentType != ControllerType.None && (npad & acceptedTypes) != 0 && _supportedPlayers[i])
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -23,12 +23,14 @@ namespace Ryujinx.HLE.HOS.Services.Hid
|
||||||
{
|
{
|
||||||
newState.TouchesCount = points.Length;
|
newState.TouchesCount = points.Length;
|
||||||
|
|
||||||
int pointsLength = Math.Min(points.Length, newState.Touches.Length);
|
Span<TouchState> touchesSpan = newState.Touches.AsSpan();
|
||||||
|
|
||||||
|
int pointsLength = Math.Min(points.Length, touchesSpan.Length);
|
||||||
|
|
||||||
for (int i = 0; i < pointsLength; ++i)
|
for (int i = 0; i < pointsLength; ++i)
|
||||||
{
|
{
|
||||||
TouchPoint pi = points[i];
|
TouchPoint pi = points[i];
|
||||||
newState.Touches[i] = new TouchState
|
touchesSpan[i] = new TouchState
|
||||||
{
|
{
|
||||||
DeltaTime = newState.SamplingNumber,
|
DeltaTime = newState.SamplingNumber,
|
||||||
Attribute = pi.Attribute,
|
Attribute = pi.Attribute,
|
||||||
|
|
|
||||||
|
|
@ -49,12 +49,14 @@ namespace Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory.Common
|
||||||
}
|
}
|
||||||
|
|
||||||
ulong index = ReadCurrentIndex();
|
ulong index = ReadCurrentIndex();
|
||||||
|
|
||||||
|
Span<AtomicStorage<T>> storageSpan = _storage.AsSpan();
|
||||||
|
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
int inputEntryIndex = (int)((index + MaxEntries + 1 - countAvailaible) % MaxEntries);
|
int inputEntryIndex = (int)((index + MaxEntries + 1 - countAvailaible) % MaxEntries);
|
||||||
|
|
||||||
ref AtomicStorage<T> result = ref _storage[inputEntryIndex];
|
ref AtomicStorage<T> result = ref storageSpan[inputEntryIndex];
|
||||||
|
|
||||||
ulong samplingNumber0 = result.ReadSamplingNumberAtomic();
|
ulong samplingNumber0 = result.ReadSamplingNumberAtomic();
|
||||||
ulong samplingNumber1 = result.ReadSamplingNumberAtomic();
|
ulong samplingNumber1 = result.ReadSamplingNumberAtomic();
|
||||||
|
|
@ -91,15 +93,17 @@ namespace Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory.Common
|
||||||
ulong index = ReadCurrentIndex();
|
ulong index = ReadCurrentIndex();
|
||||||
|
|
||||||
AtomicStorage<T>[] result = new AtomicStorage<T>[countAvailaible];
|
AtomicStorage<T>[] result = new AtomicStorage<T>[countAvailaible];
|
||||||
|
|
||||||
|
Span<AtomicStorage<T>> storageSpan = _storage.AsSpan();
|
||||||
|
|
||||||
for (ulong i = 0; i < countAvailaible; i++)
|
for (ulong i = 0; i < countAvailaible; i++)
|
||||||
{
|
{
|
||||||
int inputEntryIndex = (int)((index + MaxEntries + 1 - countAvailaible + i) % MaxEntries);
|
int inputEntryIndex = (int)((index + MaxEntries + 1 - countAvailaible + i) % MaxEntries);
|
||||||
int outputEntryIndex = (int)(countAvailaible - i - 1);
|
int outputEntryIndex = (int)(countAvailaible - i - 1);
|
||||||
|
|
||||||
ulong samplingNumber0 = _storage[inputEntryIndex].ReadSamplingNumberAtomic();
|
ulong samplingNumber0 = storageSpan[inputEntryIndex].ReadSamplingNumberAtomic();
|
||||||
result[outputEntryIndex] = _storage[inputEntryIndex];
|
result[outputEntryIndex] = storageSpan[inputEntryIndex];
|
||||||
ulong samplingNumber1 = _storage[inputEntryIndex].ReadSamplingNumberAtomic();
|
ulong samplingNumber1 = storageSpan[inputEntryIndex].ReadSamplingNumberAtomic();
|
||||||
|
|
||||||
if (samplingNumber0 != samplingNumber1 && (i > 0 && (result[outputEntryIndex].SamplingNumber - result[outputEntryIndex].SamplingNumber) != 1))
|
if (samplingNumber0 != samplingNumber1 && (i > 0 && (result[outputEntryIndex].SamplingNumber - result[outputEntryIndex].SamplingNumber) != 1))
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ using Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory.Keyboard;
|
||||||
using Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory.Mouse;
|
using Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory.Mouse;
|
||||||
using Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory.Npad;
|
using Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory.Npad;
|
||||||
using Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory.TouchScreen;
|
using Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory.TouchScreen;
|
||||||
|
using System;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
namespace Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory
|
namespace Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory
|
||||||
|
|
@ -54,10 +55,12 @@ namespace Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory
|
||||||
Mouse = RingLifo<MouseState>.Create(),
|
Mouse = RingLifo<MouseState>.Create(),
|
||||||
Keyboard = RingLifo<KeyboardState>.Create(),
|
Keyboard = RingLifo<KeyboardState>.Create(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Span<NpadState> npadsSpan = result.Npads.AsSpan();
|
||||||
|
|
||||||
for (int i = 0; i < result.Npads.Length; i++)
|
for (int i = 0; i < npadsSpan.Length; i++)
|
||||||
{
|
{
|
||||||
result.Npads[i] = NpadState.Create();
|
npadsSpan[i] = NpadState.Create();
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
using Ryujinx.Common.Memory;
|
using Ryujinx.Common.Memory;
|
||||||
|
using System;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
|
|
||||||
|
|
@ -19,20 +20,24 @@ namespace Ryujinx.HLE.HOS.Services.Ldn.Types
|
||||||
{
|
{
|
||||||
lock (_lock)
|
lock (_lock)
|
||||||
{
|
{
|
||||||
|
Span<NodeLatestUpdate> arraySpan = array.AsSpan();
|
||||||
|
Span<NodeInfo> beforeNodesSpan = beforeNodes.AsSpan();
|
||||||
|
Span<NodeInfo> afterNodesSpan = afterNodes.AsSpan();
|
||||||
|
|
||||||
for (int i = 0; i < 8; i++)
|
for (int i = 0; i < 8; i++)
|
||||||
{
|
{
|
||||||
if (beforeNodes[i].IsConnected == 0)
|
if (beforeNodesSpan[i].IsConnected == 0)
|
||||||
{
|
{
|
||||||
if (afterNodes[i].IsConnected != 0)
|
if (afterNodesSpan[i].IsConnected != 0)
|
||||||
{
|
{
|
||||||
array[i].State |= NodeLatestUpdateFlags.Connect;
|
arraySpan[i].State |= NodeLatestUpdateFlags.Connect;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (afterNodes[i].IsConnected == 0)
|
if (afterNodesSpan[i].IsConnected == 0)
|
||||||
{
|
{
|
||||||
array[i].State |= NodeLatestUpdateFlags.Disconnect;
|
arraySpan[i].State |= NodeLatestUpdateFlags.Disconnect;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -45,14 +50,16 @@ namespace Ryujinx.HLE.HOS.Services.Ldn.Types
|
||||||
|
|
||||||
lock (_lock)
|
lock (_lock)
|
||||||
{
|
{
|
||||||
|
Span<NodeLatestUpdate> arraySpan = array.AsSpan();
|
||||||
|
|
||||||
for (int i = 0; i < number; i++)
|
for (int i = 0; i < number; i++)
|
||||||
{
|
{
|
||||||
result[i].Reserved = new Array7<byte>();
|
result[i].Reserved = new Array7<byte>();
|
||||||
|
|
||||||
if (i < LdnConst.NodeCountMax)
|
if (i < LdnConst.NodeCountMax)
|
||||||
{
|
{
|
||||||
result[i].State = array[i].State;
|
result[i].State = arraySpan[i].State;
|
||||||
array[i].State = NodeLatestUpdateFlags.None;
|
arraySpan[i].State = NodeLatestUpdateFlags.None;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -77,9 +77,11 @@ namespace Ryujinx.HLE.HOS.Services.Ldn.UserServiceCreator.LdnMitm
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Span<NodeInfo> nodesSpan = networkInfo.Ldn.Nodes.AsSpan();
|
||||||
|
|
||||||
for (int i = 0; i < LdnConst.NodeCountMax; i++)
|
for (int i = 0; i < LdnConst.NodeCountMax; i++)
|
||||||
{
|
{
|
||||||
networkInfo.Ldn.Nodes[i] = new NodeInfo
|
nodesSpan[i] = new NodeInfo
|
||||||
{
|
{
|
||||||
MacAddress = new Array6<byte>(),
|
MacAddress = new Array6<byte>(),
|
||||||
UserName = new Array33<byte>(),
|
UserName = new Array33<byte>(),
|
||||||
|
|
@ -229,11 +231,13 @@ namespace Ryujinx.HLE.HOS.Services.Ldn.UserServiceCreator.LdnMitm
|
||||||
NetworkInfo.Common.Ssid = _fakeSsid;
|
NetworkInfo.Common.Ssid = _fakeSsid;
|
||||||
|
|
||||||
NetworkInfo.Ldn.Nodes = new Array8<NodeInfo>();
|
NetworkInfo.Ldn.Nodes = new Array8<NodeInfo>();
|
||||||
|
|
||||||
|
Span<NodeInfo> nodesSpan = NetworkInfo.Ldn.Nodes.AsSpan();
|
||||||
|
|
||||||
for (int i = 0; i < LdnConst.NodeCountMax; i++)
|
for (int i = 0; i < LdnConst.NodeCountMax; i++)
|
||||||
{
|
{
|
||||||
NetworkInfo.Ldn.Nodes[i].NodeId = (byte)i;
|
nodesSpan[i].NodeId = (byte)i;
|
||||||
NetworkInfo.Ldn.Nodes[i].IsConnected = 0;
|
nodesSpan[i].IsConnected = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -408,11 +412,11 @@ namespace Ryujinx.HLE.HOS.Services.Ldn.UserServiceCreator.LdnMitm
|
||||||
|
|
||||||
private int LocateEmptyNode()
|
private int LocateEmptyNode()
|
||||||
{
|
{
|
||||||
Array8<NodeInfo> nodes = NetworkInfo.Ldn.Nodes;
|
Span<NodeInfo> nodesSpan = NetworkInfo.Ldn.Nodes.AsSpan();
|
||||||
|
|
||||||
for (int i = 1; i < nodes.Length; i++)
|
for (int i = 1; i < nodesSpan.Length; i++)
|
||||||
{
|
{
|
||||||
if (nodes[i].IsConnected == 0)
|
if (nodesSpan[i].IsConnected == 0)
|
||||||
{
|
{
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -335,9 +335,11 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostAsGpu
|
||||||
writeEntries = (uint)_pageSizes.Length;
|
writeEntries = (uint)_pageSizes.Length;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Span<VaRegion> regionsSpan = arguments.Regions.AsSpan();
|
||||||
|
|
||||||
for (uint i = 0; i < writeEntries; i++)
|
for (uint i = 0; i < writeEntries; i++)
|
||||||
{
|
{
|
||||||
ref var region = ref arguments.Regions[(int)i];
|
ref var region = ref regionsSpan[(int)i];
|
||||||
|
|
||||||
var vmRegion = _vmRegions[i];
|
var vmRegion = _vmRegions[i];
|
||||||
uint pageSize = _pageSizes[i];
|
uint pageSize = _pageSizes[i];
|
||||||
|
|
|
||||||
|
|
@ -30,21 +30,21 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Sfdnsres.Types
|
||||||
{
|
{
|
||||||
Port = IPAddress.HostToNetworkOrder(Port);
|
Port = IPAddress.HostToNetworkOrder(Port);
|
||||||
|
|
||||||
RawIpv4AddressNetworkEndianSwap(ref Address);
|
RawIpv4AddressNetworkEndianSwap(Address.AsSpan());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ToHostOrder()
|
public void ToHostOrder()
|
||||||
{
|
{
|
||||||
Port = IPAddress.NetworkToHostOrder(Port);
|
Port = IPAddress.NetworkToHostOrder(Port);
|
||||||
|
|
||||||
RawIpv4AddressNetworkEndianSwap(ref Address);
|
RawIpv4AddressNetworkEndianSwap(Address.AsSpan());
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void RawIpv4AddressNetworkEndianSwap(ref Array4<byte> address)
|
public static void RawIpv4AddressNetworkEndianSwap(Span<byte> address)
|
||||||
{
|
{
|
||||||
if (BitConverter.IsLittleEndian)
|
if (BitConverter.IsLittleEndian)
|
||||||
{
|
{
|
||||||
address.AsSpan().Reverse();
|
address.Reverse();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -73,7 +73,7 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Sfdnsres.Types
|
||||||
{
|
{
|
||||||
// Nintendo hardcode 4 bytes in that case here.
|
// Nintendo hardcode 4 bytes in that case here.
|
||||||
Array4<byte> address = MemoryMarshal.Read<Array4<byte>>(buffer);
|
Array4<byte> address = MemoryMarshal.Read<Array4<byte>>(buffer);
|
||||||
AddrInfo4.RawIpv4AddressNetworkEndianSwap(ref address);
|
AddrInfo4.RawIpv4AddressNetworkEndianSwap(address.AsSpan());
|
||||||
|
|
||||||
rawIPv4Address = address;
|
rawIPv4Address = address;
|
||||||
|
|
||||||
|
|
@ -115,7 +115,7 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Sfdnsres.Types
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Array4<byte> rawIPv4Address = RawIPv4Address.Value;
|
Array4<byte> rawIPv4Address = RawIPv4Address.Value;
|
||||||
AddrInfo4.RawIpv4AddressNetworkEndianSwap(ref rawIPv4Address);
|
AddrInfo4.RawIpv4AddressNetworkEndianSwap(rawIPv4Address.AsSpan());
|
||||||
|
|
||||||
MemoryMarshal.Write(buffer, in rawIPv4Address);
|
MemoryMarshal.Write(buffer, in rawIPv4Address);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -60,10 +60,10 @@ namespace Ryujinx.HLE.UI.Input
|
||||||
|
|
||||||
public void Update(bool supressEvents = false)
|
public void Update(bool supressEvents = false)
|
||||||
{
|
{
|
||||||
ref var npads = ref _device.Hid.SharedMemory.Npads;
|
int npadsCount = _device.Hid.SharedMemory.Npads.Length;
|
||||||
|
|
||||||
// Process each input individually.
|
// Process each input individually.
|
||||||
for (int npadIndex = 0; npadIndex < npads.Length; npadIndex++)
|
for (int npadIndex = 0; npadIndex < npadsCount; npadIndex++)
|
||||||
{
|
{
|
||||||
UpdateNpad(npadIndex, supressEvents);
|
UpdateNpad(npadIndex, supressEvents);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
using Ryujinx.Common.Memory;
|
using Ryujinx.Common.Memory;
|
||||||
|
using System;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
namespace Ryujinx.Input
|
namespace Ryujinx.Input
|
||||||
|
|
@ -49,7 +50,7 @@ namespace Ryujinx.Input
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public (float, float) GetStick(StickInputId inputId)
|
public (float, float) GetStick(StickInputId inputId)
|
||||||
{
|
{
|
||||||
var result = _joysticksState[(int)inputId];
|
Span<float> result = _joysticksState[(int)inputId].AsSpan();
|
||||||
|
|
||||||
return (result[0], result[1]);
|
return (result[0], result[1]);
|
||||||
}
|
}
|
||||||
|
|
@ -63,8 +64,9 @@ namespace Ryujinx.Input
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public void SetStick(StickInputId inputId, float x, float y)
|
public void SetStick(StickInputId inputId, float x, float y)
|
||||||
{
|
{
|
||||||
_joysticksState[(int)inputId][0] = x;
|
Span<float> stateSpan = _joysticksState[(int)inputId].AsSpan();
|
||||||
_joysticksState[(int)inputId][1] = y;
|
stateSpan[0] = x;
|
||||||
|
stateSpan[1] = y;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -95,25 +95,28 @@ namespace Ryujinx.Input
|
||||||
{
|
{
|
||||||
// NOTE: Update Array size if JoystickInputId is changed.
|
// NOTE: Update Array size if JoystickInputId is changed.
|
||||||
Array3<Array2<float>> joysticksState = default;
|
Array3<Array2<float>> joysticksState = default;
|
||||||
|
Span<Array2<float>> joysticksStateSpan = joysticksState.AsSpan();
|
||||||
|
|
||||||
for (StickInputId inputId = StickInputId.Left; inputId < StickInputId.Count; inputId++)
|
for (StickInputId inputId = StickInputId.Left; inputId < StickInputId.Count; inputId++)
|
||||||
{
|
{
|
||||||
(float state0, float state1) = gamepad.GetStick(inputId);
|
(float state0, float state1) = gamepad.GetStick(inputId);
|
||||||
|
|
||||||
Array2<float> state = default;
|
Array2<float> state = default;
|
||||||
|
Span<float> stateSpan = state.AsSpan();
|
||||||
|
|
||||||
state[0] = state0;
|
stateSpan[0] = state0;
|
||||||
state[1] = state1;
|
stateSpan[1] = state1;
|
||||||
|
|
||||||
joysticksState[(int)inputId] = state;
|
joysticksStateSpan[(int)inputId] = state;
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE: Update Array size if GamepadInputId is changed.
|
// NOTE: Update Array size if GamepadInputId is changed.
|
||||||
Array28<bool> buttonsState = default;
|
Array28<bool> buttonsState = default;
|
||||||
|
Span<bool> buttonsStateSpan = buttonsState.AsSpan();
|
||||||
|
|
||||||
for (GamepadButtonInputId inputId = GamepadButtonInputId.A; inputId < GamepadButtonInputId.Count; inputId++)
|
for (GamepadButtonInputId inputId = GamepadButtonInputId.A; inputId < GamepadButtonInputId.Count; inputId++)
|
||||||
{
|
{
|
||||||
buttonsState[(int)inputId] = gamepad.IsPressed(inputId);
|
buttonsStateSpan[(int)inputId] = gamepad.IsPressed(inputId);
|
||||||
}
|
}
|
||||||
|
|
||||||
return new GamepadStateSnapshot(joysticksState, buttonsState);
|
return new GamepadStateSnapshot(joysticksState, buttonsState);
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@ namespace Ryujinx.Memory.Range
|
||||||
/// A range list that assumes ranges are non-overlapping, with list items that can be split in two to avoid overlaps.
|
/// A range list that assumes ranges are non-overlapping, with list items that can be split in two to avoid overlaps.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <typeparam name="T">Type of the range.</typeparam>
|
/// <typeparam name="T">Type of the range.</typeparam>
|
||||||
public class NonOverlappingRangeList<T> : RangeListBase<T> where T : INonOverlappingRange
|
public unsafe class NonOverlappingRangeList<T> : RangeListBase<T> where T : class, INonOverlappingRange
|
||||||
{
|
{
|
||||||
private readonly Dictionary<ulong, RangeItem<T>> _quickAccess = new(AddressEqualityComparer.Comparer);
|
private readonly Dictionary<ulong, RangeItem<T>> _quickAccess = new(AddressEqualityComparer.Comparer);
|
||||||
private readonly Dictionary<ulong, RangeItem<T>> _fastQuickAccess = new(AddressEqualityComparer.Comparer);
|
private readonly Dictionary<ulong, RangeItem<T>> _fastQuickAccess = new(AddressEqualityComparer.Comparer);
|
||||||
|
|
@ -196,6 +196,16 @@ namespace Ryujinx.Memory.Range
|
||||||
int startIndex = BinarySearch(startItem.Address);
|
int startIndex = BinarySearch(startItem.Address);
|
||||||
int endIndex = BinarySearch(endItem.Address);
|
int endIndex = BinarySearch(endItem.Address);
|
||||||
|
|
||||||
|
for (int i = startIndex; i <= endIndex; i++)
|
||||||
|
{
|
||||||
|
_quickAccess.Remove(Items[i].Address);
|
||||||
|
foreach (ulong addr in Items[i].QuickAccessAddresses)
|
||||||
|
{
|
||||||
|
_quickAccess.Remove(addr);
|
||||||
|
_fastQuickAccess.Remove(addr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (endIndex < Count - 1)
|
if (endIndex < Count - 1)
|
||||||
{
|
{
|
||||||
Items[endIndex + 1].Previous = startIndex > 0 ? Items[startIndex - 1] : null;
|
Items[endIndex + 1].Previous = startIndex > 0 ? Items[startIndex - 1] : null;
|
||||||
|
|
@ -213,17 +223,6 @@ namespace Ryujinx.Memory.Range
|
||||||
}
|
}
|
||||||
|
|
||||||
Count -= endIndex - startIndex + 1;
|
Count -= endIndex - startIndex + 1;
|
||||||
|
|
||||||
while (startItem != endItem.Next)
|
|
||||||
{
|
|
||||||
_quickAccess.Remove(startItem.Address);
|
|
||||||
foreach (ulong addr in startItem.QuickAccessAddresses)
|
|
||||||
{
|
|
||||||
_quickAccess.Remove(addr);
|
|
||||||
_fastQuickAccess.Remove(addr);
|
|
||||||
}
|
|
||||||
startItem = startItem.Next;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -240,19 +239,22 @@ namespace Ryujinx.Memory.Range
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
RangeItem<T> startItem = Items[startIndex];
|
|
||||||
|
|
||||||
int endIndex = startIndex;
|
int endIndex = startIndex;
|
||||||
|
|
||||||
while (startItem is not null && startItem.Address < address + size)
|
while (Items[endIndex] is not null && Items[endIndex].Address < address + size)
|
||||||
{
|
{
|
||||||
_quickAccess.Remove(startItem.Address);
|
_quickAccess.Remove(Items[endIndex].Address);
|
||||||
foreach (ulong addr in startItem.QuickAccessAddresses)
|
foreach (ulong addr in Items[endIndex].QuickAccessAddresses)
|
||||||
{
|
{
|
||||||
_quickAccess.Remove(addr);
|
_quickAccess.Remove(addr);
|
||||||
_fastQuickAccess.Remove(addr);
|
_fastQuickAccess.Remove(addr);
|
||||||
}
|
}
|
||||||
startItem = startItem.Next;
|
|
||||||
|
if (endIndex == Count - 1)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
endIndex++;
|
endIndex++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,37 +6,6 @@ using System.Threading;
|
||||||
|
|
||||||
namespace Ryujinx.Memory.Range
|
namespace Ryujinx.Memory.Range
|
||||||
{
|
{
|
||||||
public class RangeItem<TValue>(TValue value) where TValue : IRange
|
|
||||||
{
|
|
||||||
public RangeItem<TValue> Next;
|
|
||||||
public RangeItem<TValue> Previous;
|
|
||||||
|
|
||||||
public readonly ulong Address = value.Address;
|
|
||||||
public readonly ulong EndAddress = value.Address + value.Size;
|
|
||||||
|
|
||||||
public readonly TValue Value = value;
|
|
||||||
|
|
||||||
public readonly List<ulong> QuickAccessAddresses = [];
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public bool OverlapsWith(ulong address, ulong endAddress)
|
|
||||||
{
|
|
||||||
return Address < endAddress && address < EndAddress;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class AddressEqualityComparer : IEqualityComparer<ulong>
|
|
||||||
{
|
|
||||||
public bool Equals(ulong u1, ulong u2)
|
|
||||||
{
|
|
||||||
return u1 == u2;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int GetHashCode(ulong value) => (int)(value >> 5);
|
|
||||||
|
|
||||||
public static readonly AddressEqualityComparer Comparer = new();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Result of an Overlaps Finder function. WARNING: if the result is from the optimized
|
/// Result of an Overlaps Finder function. WARNING: if the result is from the optimized
|
||||||
/// Overlaps Finder, the StartIndex will be -1 even when the result isn't empty
|
/// Overlaps Finder, the StartIndex will be -1 even when the result isn't empty
|
||||||
|
|
@ -209,43 +178,46 @@ namespace Ryujinx.Memory.Range
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public override void RemoveRange(RangeItem<T> startItem, RangeItem<T> endItem)
|
public override void RemoveRange(RangeItem<T> startItem, RangeItem<T> endItem)
|
||||||
{
|
{
|
||||||
if (endItem.Next is not null)
|
if (startItem is null)
|
||||||
{
|
{
|
||||||
endItem.Next.Previous = startItem.Previous;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (startItem == endItem)
|
||||||
|
{
|
||||||
|
Remove(startItem.Value);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (startItem.Previous is not null)
|
int startIndex = BinarySearch(startItem.Address);
|
||||||
{
|
int endIndex = BinarySearch(endItem.Address);
|
||||||
startItem.Previous.Next = endItem.Next;
|
|
||||||
}
|
|
||||||
|
|
||||||
RangeItem<T> current = startItem;
|
for (int i = startIndex; i <= endIndex; i++)
|
||||||
while (current != endItem.Next)
|
|
||||||
{
|
{
|
||||||
foreach (ulong address in current.QuickAccessAddresses)
|
_quickAccess.Remove(Items[i].Address);
|
||||||
|
foreach (ulong addr in Items[i].QuickAccessAddresses)
|
||||||
{
|
{
|
||||||
_quickAccess.Remove(address);
|
_quickAccess.Remove(addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
current = current.Next;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
RangeItem<T>[] array = [];
|
if (endIndex < Count - 1)
|
||||||
OverlapResult<T> overlapResult = FindOverlaps(startItem.Address, endItem.EndAddress, ref array);
|
{
|
||||||
|
Items[endIndex + 1].Previous = startIndex > 0 ? Items[startIndex - 1] : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (startIndex > 0)
|
||||||
|
{
|
||||||
|
Items[startIndex - 1].Next = endIndex < Count - 1 ? Items[endIndex + 1] : null;
|
||||||
|
}
|
||||||
|
|
||||||
if (overlapResult.EndIndex < Count)
|
|
||||||
|
if (endIndex < Count - 1)
|
||||||
{
|
{
|
||||||
Array.Copy(Items, overlapResult.EndIndex, Items, overlapResult.StartIndex, Count - overlapResult.EndIndex);
|
Array.Copy(Items, endIndex + 1, Items, startIndex, Count - endIndex - 1);
|
||||||
Count -= overlapResult.Count;
|
|
||||||
}
|
|
||||||
else if (overlapResult.EndIndex == Count)
|
|
||||||
{
|
|
||||||
Count = overlapResult.StartIndex;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Debug.Assert(false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Count -= endIndex - startIndex + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
|
||||||
|
|
@ -4,9 +4,40 @@ using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
namespace Ryujinx.Memory.Range
|
namespace Ryujinx.Memory.Range
|
||||||
{
|
{
|
||||||
public abstract class RangeListBase<T> : IEnumerable<T> where T : IRange
|
public class RangeItem<TValue>(TValue value) where TValue : IRange
|
||||||
{
|
{
|
||||||
protected const int BackingInitialSize = 1024;
|
public RangeItem<TValue> Next;
|
||||||
|
public RangeItem<TValue> Previous;
|
||||||
|
|
||||||
|
public readonly ulong Address = value.Address;
|
||||||
|
public readonly ulong EndAddress = value.Address + value.Size;
|
||||||
|
|
||||||
|
public readonly TValue Value = value;
|
||||||
|
|
||||||
|
public readonly List<ulong> QuickAccessAddresses = [];
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public bool OverlapsWith(ulong address, ulong endAddress)
|
||||||
|
{
|
||||||
|
return Address < endAddress && address < EndAddress;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class AddressEqualityComparer : IEqualityComparer<ulong>
|
||||||
|
{
|
||||||
|
public bool Equals(ulong u1, ulong u2)
|
||||||
|
{
|
||||||
|
return u1 == u2;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int GetHashCode(ulong value) => (int)(value >> 5);
|
||||||
|
|
||||||
|
public static readonly AddressEqualityComparer Comparer = new();
|
||||||
|
}
|
||||||
|
|
||||||
|
public unsafe abstract class RangeListBase<T> : IEnumerable<T> where T : IRange
|
||||||
|
{
|
||||||
|
private const int BackingInitialSize = 1024;
|
||||||
|
|
||||||
protected RangeItem<T>[] Items;
|
protected RangeItem<T>[] Items;
|
||||||
protected readonly int BackingGrowthSize;
|
protected readonly int BackingGrowthSize;
|
||||||
|
|
|
||||||
|
|
@ -36,10 +36,12 @@ namespace Ryujinx.Memory.WindowsShared
|
||||||
|
|
||||||
class RangeNode<T> : IntrusiveRedBlackTreeNode<RangeNode<T>>, IComparable<RangeNode<T>>, IComparable<ulong>
|
class RangeNode<T> : IntrusiveRedBlackTreeNode<RangeNode<T>>, IComparable<RangeNode<T>>, IComparable<ulong>
|
||||||
{
|
{
|
||||||
public ulong Start { get; }
|
public ulong Start { get; private set; }
|
||||||
public ulong End { get; private set; }
|
public ulong End { get; private set; }
|
||||||
public T Value { get; }
|
public T Value { get; private set; }
|
||||||
|
|
||||||
|
public RangeNode() { }
|
||||||
|
|
||||||
public RangeNode(ulong start, ulong end, T value)
|
public RangeNode(ulong start, ulong end, T value)
|
||||||
{
|
{
|
||||||
Start = start;
|
Start = start;
|
||||||
|
|
@ -47,6 +49,22 @@ namespace Ryujinx.Memory.WindowsShared
|
||||||
Value = value;
|
Value = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public RangeNode<T> Init(ulong start, ulong end, T value)
|
||||||
|
{
|
||||||
|
Start = start;
|
||||||
|
End = end;
|
||||||
|
Value = value;
|
||||||
|
|
||||||
|
Color = true;
|
||||||
|
Left = null;
|
||||||
|
Right = null;
|
||||||
|
Parent = null;
|
||||||
|
Predecessor = null;
|
||||||
|
Successor = null;
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
public void Extend(ulong sizeDelta)
|
public void Extend(ulong sizeDelta)
|
||||||
{
|
{
|
||||||
End += sizeDelta;
|
End += sizeDelta;
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
using Ryujinx.Common.Collections;
|
using Ryujinx.Common.Collections;
|
||||||
using Ryujinx.Common.Memory.PartialUnmaps;
|
using Ryujinx.Common.Memory.PartialUnmaps;
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using System.Runtime.Versioning;
|
using System.Runtime.Versioning;
|
||||||
|
|
@ -8,6 +9,24 @@ using System.Threading;
|
||||||
|
|
||||||
namespace Ryujinx.Memory.WindowsShared
|
namespace Ryujinx.Memory.WindowsShared
|
||||||
{
|
{
|
||||||
|
public class ObjectPool<T>
|
||||||
|
{
|
||||||
|
private readonly Stack<T> _objects;
|
||||||
|
private readonly Func<T> _objectGenerator;
|
||||||
|
|
||||||
|
public ObjectPool(Func<T> objectGenerator)
|
||||||
|
{
|
||||||
|
_objectGenerator = objectGenerator ?? throw new ArgumentNullException(nameof(objectGenerator));
|
||||||
|
_objects = new Stack<T>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public T Get() => _objects.Count > 0 ? _objects.Pop() : _objectGenerator();
|
||||||
|
|
||||||
|
public void Return(T item) => _objects.Push(item);
|
||||||
|
|
||||||
|
public void Clear() => _objects.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Windows memory placeholder manager.
|
/// Windows memory placeholder manager.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
@ -18,6 +37,7 @@ namespace Ryujinx.Memory.WindowsShared
|
||||||
|
|
||||||
private readonly MappingTree<ulong> _mappings;
|
private readonly MappingTree<ulong> _mappings;
|
||||||
private readonly MappingTree<MemoryPermission> _protections;
|
private readonly MappingTree<MemoryPermission> _protections;
|
||||||
|
private readonly ObjectPool<RangeNode<MemoryPermission>> _protectionObjectPool;
|
||||||
private readonly IntPtr _partialUnmapStatePtr;
|
private readonly IntPtr _partialUnmapStatePtr;
|
||||||
private readonly Thread _partialUnmapTrimThread;
|
private readonly Thread _partialUnmapTrimThread;
|
||||||
|
|
||||||
|
|
@ -28,6 +48,8 @@ namespace Ryujinx.Memory.WindowsShared
|
||||||
{
|
{
|
||||||
_mappings = new MappingTree<ulong>();
|
_mappings = new MappingTree<ulong>();
|
||||||
_protections = new MappingTree<MemoryPermission>();
|
_protections = new MappingTree<MemoryPermission>();
|
||||||
|
|
||||||
|
_protectionObjectPool = new ObjectPool<RangeNode<MemoryPermission>>(() => new RangeNode<MemoryPermission>());
|
||||||
|
|
||||||
_partialUnmapStatePtr = PartialUnmapState.GlobalState;
|
_partialUnmapStatePtr = PartialUnmapState.GlobalState;
|
||||||
|
|
||||||
|
|
@ -70,12 +92,12 @@ namespace Ryujinx.Memory.WindowsShared
|
||||||
{
|
{
|
||||||
lock (_mappings)
|
lock (_mappings)
|
||||||
{
|
{
|
||||||
_mappings.Add(new RangeNode<ulong>(address, address + size, ulong.MaxValue));
|
_mappings.Add(new RangeNode<ulong>().Init(address, address + size, ulong.MaxValue));
|
||||||
}
|
}
|
||||||
|
|
||||||
lock (_protections)
|
lock (_protections)
|
||||||
{
|
{
|
||||||
_protections.Add(new RangeNode<MemoryPermission>(address, address + size, MemoryPermission.None));
|
_protections.Add(_protectionObjectPool.Get().Init(address, address + size, MemoryPermission.None));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -214,8 +236,8 @@ namespace Ryujinx.Memory.WindowsShared
|
||||||
(IntPtr)size,
|
(IntPtr)size,
|
||||||
AllocationType.Release | AllocationType.PreservePlaceholder));
|
AllocationType.Release | AllocationType.PreservePlaceholder));
|
||||||
|
|
||||||
_mappings.Add(new RangeNode<ulong>(overlapStart, address, overlapValue));
|
_mappings.Add(new RangeNode<ulong>().Init(overlapStart, address, overlapValue));
|
||||||
_mappings.Add(new RangeNode<ulong>(endAddress, overlapEnd, AddBackingOffset(overlapValue, endAddress - overlapStart)));
|
_mappings.Add(new RangeNode<ulong>().Init(endAddress, overlapEnd, AddBackingOffset(overlapValue, endAddress - overlapStart)));
|
||||||
}
|
}
|
||||||
else if (overlapStartsBefore)
|
else if (overlapStartsBefore)
|
||||||
{
|
{
|
||||||
|
|
@ -226,7 +248,7 @@ namespace Ryujinx.Memory.WindowsShared
|
||||||
(IntPtr)overlappedSize,
|
(IntPtr)overlappedSize,
|
||||||
AllocationType.Release | AllocationType.PreservePlaceholder));
|
AllocationType.Release | AllocationType.PreservePlaceholder));
|
||||||
|
|
||||||
_mappings.Add(new RangeNode<ulong>(overlapStart, address, overlapValue));
|
_mappings.Add(new RangeNode<ulong>().Init(overlapStart, address, overlapValue));
|
||||||
}
|
}
|
||||||
else if (overlapEndsAfter)
|
else if (overlapEndsAfter)
|
||||||
{
|
{
|
||||||
|
|
@ -237,10 +259,10 @@ namespace Ryujinx.Memory.WindowsShared
|
||||||
(IntPtr)overlappedSize,
|
(IntPtr)overlappedSize,
|
||||||
AllocationType.Release | AllocationType.PreservePlaceholder));
|
AllocationType.Release | AllocationType.PreservePlaceholder));
|
||||||
|
|
||||||
_mappings.Add(new RangeNode<ulong>(endAddress, overlapEnd, AddBackingOffset(overlapValue, overlappedSize)));
|
_mappings.Add(new RangeNode<ulong>().Init(endAddress, overlapEnd, AddBackingOffset(overlapValue, overlappedSize)));
|
||||||
}
|
}
|
||||||
|
|
||||||
_mappings.Add(new RangeNode<ulong>(address, endAddress, backingOffset));
|
_mappings.Add(new RangeNode<ulong>().Init(address, endAddress, backingOffset));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -306,7 +328,7 @@ namespace Ryujinx.Memory.WindowsShared
|
||||||
lock (_mappings)
|
lock (_mappings)
|
||||||
{
|
{
|
||||||
_mappings.Remove(overlap);
|
_mappings.Remove(overlap);
|
||||||
_mappings.Add(new RangeNode<ulong>(overlap.Start, overlap.End, ulong.MaxValue));
|
_mappings.Add(new RangeNode<ulong>().Init(overlap.Start, overlap.End, ulong.MaxValue));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool overlapStartsBefore = overlap.Start < startAddress;
|
bool overlapStartsBefore = overlap.Start < startAddress;
|
||||||
|
|
@ -433,7 +455,7 @@ namespace Ryujinx.Memory.WindowsShared
|
||||||
unmappedCount++;
|
unmappedCount++;
|
||||||
}
|
}
|
||||||
|
|
||||||
_mappings.Add(new RangeNode<ulong>(address, endAddress, ulong.MaxValue));
|
_mappings.Add(new RangeNode<ulong>().Init(address, endAddress, ulong.MaxValue));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (unmappedCount > 1)
|
if (unmappedCount > 1)
|
||||||
|
|
@ -628,14 +650,16 @@ namespace Ryujinx.Memory.WindowsShared
|
||||||
{
|
{
|
||||||
if (startAddress > protAddress)
|
if (startAddress > protAddress)
|
||||||
{
|
{
|
||||||
_protections.Add(new RangeNode<MemoryPermission>(protAddress, startAddress, protPermission));
|
_protections.Add(_protectionObjectPool.Get().Init(protAddress, startAddress, protPermission));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (endAddress < protEndAddress)
|
if (endAddress < protEndAddress)
|
||||||
{
|
{
|
||||||
_protections.Add(new RangeNode<MemoryPermission>(endAddress, protEndAddress, protPermission));
|
_protections.Add(_protectionObjectPool.Get().Init(endAddress, protEndAddress, protPermission));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_protectionObjectPool.Return(protection);
|
||||||
|
|
||||||
if (node.End >= endAddress)
|
if (node.End >= endAddress)
|
||||||
{
|
{
|
||||||
|
|
@ -643,7 +667,7 @@ namespace Ryujinx.Memory.WindowsShared
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_protections.Add(new RangeNode<MemoryPermission>(startAddress, endAddress, permission));
|
_protections.Add(_protectionObjectPool.Get().Init(startAddress, endAddress, permission));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -674,14 +698,16 @@ namespace Ryujinx.Memory.WindowsShared
|
||||||
|
|
||||||
if (address > protAddress)
|
if (address > protAddress)
|
||||||
{
|
{
|
||||||
_protections.Add(new RangeNode<MemoryPermission>(protAddress, address, protPermission));
|
_protections.Add(_protectionObjectPool.Get().Init(protAddress, address, protPermission));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (endAddress < protEndAddress)
|
if (endAddress < protEndAddress)
|
||||||
{
|
{
|
||||||
_protections.Add(new RangeNode<MemoryPermission>(endAddress, protEndAddress, protPermission));
|
_protections.Add(_protectionObjectPool.Get().Init(endAddress, protEndAddress, protPermission));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_protectionObjectPool.Return(protection);
|
||||||
|
|
||||||
if (node.End >= endAddress)
|
if (node.End >= endAddress)
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue