Compare commits

..

10 Commits

Author SHA1 Message Date
Mary
868919e101 misc: Update GtkSharp.Dependencies and speed up initial Windows build (#3128)
Update GtkSharp.Dependencies to fix between menu flickering and enable
the SkipInstallGtk in csproj to avoid downloading unused GTK3 install
locally.
2022-02-17 22:10:48 +01:00
Berkan Diler
9ca040c0ff Use ReadOnlySpan<byte> compiler optimization for static data (#3130) 2022-02-17 21:38:50 +01:00
riperiperi
7e9011673b Use a basic cubic interpolation for the audren upsampler (#3129)
Before, it was selecting nearest neighbour, which sounded terrible. This is likely temporary til the upsampling algorithm used by the switch is reversed.

Fixes bad audio in Skyward Sword HD.
2022-02-17 20:19:29 +01:00
Mary
741db8e43d amadeus: Fix PCMFloat datasource command v1 (#3127)
Really simple copy pasta error here.

Shouldn't affect anything as float support was added at the same REV as
datasource command v2.
2022-02-16 23:55:40 +01:00
gdkchan
3bd357045f Do not allow render targets not explicitly written by the fragment shader to be modified (#3063)
* Do not allow render targets not explicitly written by the fragment shader to be modified

* Shader cache version bump

* Remove blank lines

* Avoid redundant color mask updates

* HostShaderCacheEntry can be null

* Avoid more redundant glColorMask calls

* nit: Mask -> Masks

* Fix currentComponentMask

* More efficient way to update _currentComponentMasks
2022-02-16 23:15:39 +01:00
Mary
ab5d77c0c4 amadeus: Fix limiter correctness (#3126)
This fixes missing audio on Nintendo Switch Sports Online Play Test.
2022-02-16 21:38:45 +01:00
gdkchan
7bfb5f79b8 When copying linear textures, DMA should ignore region X/Y (#3121) 2022-02-16 11:13:45 +01:00
skrek
8cc2479825 Adjusting how deadzones are calculated (#3079)
* Making deadzones feel nice and smooth + adding rider files to .gitignore

* removing unnecessary parentheses and fixing possibility of divide by 0

* formatting :)

* fixing up ClampAxis

* fixing up ClampAxis
2022-02-16 11:06:52 +01:00
Berkan Diler
8f35345729 Use Enum and Delegate.CreateDelegate generic overloads (#3111)
* Use Enum generic overloads

* Remove EnumExtensions.cs

* Use Delegate.CreateDelegate generic overloads
2022-02-13 10:50:07 -03:00
merry
ce71f9144e InstEmitMemory32: Literal loads always have word-aligned PC (#3104) 2022-02-11 17:51:03 -03:00
51 changed files with 323 additions and 209 deletions

3
.gitignore vendored
View File

@@ -74,6 +74,9 @@ _TeamCity*
# DotCover is a Code Coverage Tool # DotCover is a Code Coverage Tool
*.dotCover *.dotCover
# Rider is a Visual Studio alternative
.idea/*
# NCrunch # NCrunch
*.ncrunch* *.ncrunch*
.*crunch*.local.xml .*crunch*.local.xml

View File

@@ -1,13 +1,14 @@
// https://www.intel.com/content/dam/doc/white-paper/advanced-encryption-standard-new-instructions-set-paper.pdf // https://www.intel.com/content/dam/doc/white-paper/advanced-encryption-standard-new-instructions-set-paper.pdf
using ARMeilleure.State; using ARMeilleure.State;
using System;
namespace ARMeilleure.Instructions namespace ARMeilleure.Instructions
{ {
static class CryptoHelper static class CryptoHelper
{ {
#region "LookUp Tables" #region "LookUp Tables"
private static readonly byte[] _sBox = new byte[] private static ReadOnlySpan<byte> _sBox => new byte[]
{ {
0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76, 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76,
0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0,
@@ -27,7 +28,7 @@ namespace ARMeilleure.Instructions
0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16
}; };
private static readonly byte[] _invSBox = new byte[] private static ReadOnlySpan<byte> _invSBox => new byte[]
{ {
0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb, 0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb,
0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb, 0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb,
@@ -47,7 +48,7 @@ namespace ARMeilleure.Instructions
0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d 0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d
}; };
private static readonly byte[] _gfMul02 = new byte[] private static ReadOnlySpan<byte> _gfMul02 => new byte[]
{ {
0x00, 0x02, 0x04, 0x06, 0x08, 0x0a, 0x0c, 0x0e, 0x10, 0x12, 0x14, 0x16, 0x18, 0x1a, 0x1c, 0x1e, 0x00, 0x02, 0x04, 0x06, 0x08, 0x0a, 0x0c, 0x0e, 0x10, 0x12, 0x14, 0x16, 0x18, 0x1a, 0x1c, 0x1e,
0x20, 0x22, 0x24, 0x26, 0x28, 0x2a, 0x2c, 0x2e, 0x30, 0x32, 0x34, 0x36, 0x38, 0x3a, 0x3c, 0x3e, 0x20, 0x22, 0x24, 0x26, 0x28, 0x2a, 0x2c, 0x2e, 0x30, 0x32, 0x34, 0x36, 0x38, 0x3a, 0x3c, 0x3e,
@@ -67,7 +68,7 @@ namespace ARMeilleure.Instructions
0xfb, 0xf9, 0xff, 0xfd, 0xf3, 0xf1, 0xf7, 0xf5, 0xeb, 0xe9, 0xef, 0xed, 0xe3, 0xe1, 0xe7, 0xe5 0xfb, 0xf9, 0xff, 0xfd, 0xf3, 0xf1, 0xf7, 0xf5, 0xeb, 0xe9, 0xef, 0xed, 0xe3, 0xe1, 0xe7, 0xe5
}; };
private static readonly byte[] _gfMul03 = new byte[] private static ReadOnlySpan<byte> _gfMul03 => new byte[]
{ {
0x00, 0x03, 0x06, 0x05, 0x0c, 0x0f, 0x0a, 0x09, 0x18, 0x1b, 0x1e, 0x1d, 0x14, 0x17, 0x12, 0x11, 0x00, 0x03, 0x06, 0x05, 0x0c, 0x0f, 0x0a, 0x09, 0x18, 0x1b, 0x1e, 0x1d, 0x14, 0x17, 0x12, 0x11,
0x30, 0x33, 0x36, 0x35, 0x3c, 0x3f, 0x3a, 0x39, 0x28, 0x2b, 0x2e, 0x2d, 0x24, 0x27, 0x22, 0x21, 0x30, 0x33, 0x36, 0x35, 0x3c, 0x3f, 0x3a, 0x39, 0x28, 0x2b, 0x2e, 0x2d, 0x24, 0x27, 0x22, 0x21,
@@ -87,7 +88,7 @@ namespace ARMeilleure.Instructions
0x0b, 0x08, 0x0d, 0x0e, 0x07, 0x04, 0x01, 0x02, 0x13, 0x10, 0x15, 0x16, 0x1f, 0x1c, 0x19, 0x1a 0x0b, 0x08, 0x0d, 0x0e, 0x07, 0x04, 0x01, 0x02, 0x13, 0x10, 0x15, 0x16, 0x1f, 0x1c, 0x19, 0x1a
}; };
private static readonly byte[] _gfMul09 = new byte[] private static ReadOnlySpan<byte> _gfMul09 => new byte[]
{ {
0x00, 0x09, 0x12, 0x1b, 0x24, 0x2d, 0x36, 0x3f, 0x48, 0x41, 0x5a, 0x53, 0x6c, 0x65, 0x7e, 0x77, 0x00, 0x09, 0x12, 0x1b, 0x24, 0x2d, 0x36, 0x3f, 0x48, 0x41, 0x5a, 0x53, 0x6c, 0x65, 0x7e, 0x77,
0x90, 0x99, 0x82, 0x8b, 0xb4, 0xbd, 0xa6, 0xaf, 0xd8, 0xd1, 0xca, 0xc3, 0xfc, 0xf5, 0xee, 0xe7, 0x90, 0x99, 0x82, 0x8b, 0xb4, 0xbd, 0xa6, 0xaf, 0xd8, 0xd1, 0xca, 0xc3, 0xfc, 0xf5, 0xee, 0xe7,
@@ -107,7 +108,7 @@ namespace ARMeilleure.Instructions
0x31, 0x38, 0x23, 0x2a, 0x15, 0x1c, 0x07, 0x0e, 0x79, 0x70, 0x6b, 0x62, 0x5d, 0x54, 0x4f, 0x46 0x31, 0x38, 0x23, 0x2a, 0x15, 0x1c, 0x07, 0x0e, 0x79, 0x70, 0x6b, 0x62, 0x5d, 0x54, 0x4f, 0x46
}; };
private static readonly byte[] _gfMul0B = new byte[] private static ReadOnlySpan<byte> _gfMul0B => new byte[]
{ {
0x00, 0x0b, 0x16, 0x1d, 0x2c, 0x27, 0x3a, 0x31, 0x58, 0x53, 0x4e, 0x45, 0x74, 0x7f, 0x62, 0x69, 0x00, 0x0b, 0x16, 0x1d, 0x2c, 0x27, 0x3a, 0x31, 0x58, 0x53, 0x4e, 0x45, 0x74, 0x7f, 0x62, 0x69,
0xb0, 0xbb, 0xa6, 0xad, 0x9c, 0x97, 0x8a, 0x81, 0xe8, 0xe3, 0xfe, 0xf5, 0xc4, 0xcf, 0xd2, 0xd9, 0xb0, 0xbb, 0xa6, 0xad, 0x9c, 0x97, 0x8a, 0x81, 0xe8, 0xe3, 0xfe, 0xf5, 0xc4, 0xcf, 0xd2, 0xd9,
@@ -127,7 +128,7 @@ namespace ARMeilleure.Instructions
0xca, 0xc1, 0xdc, 0xd7, 0xe6, 0xed, 0xf0, 0xfb, 0x92, 0x99, 0x84, 0x8f, 0xbe, 0xb5, 0xa8, 0xa3 0xca, 0xc1, 0xdc, 0xd7, 0xe6, 0xed, 0xf0, 0xfb, 0x92, 0x99, 0x84, 0x8f, 0xbe, 0xb5, 0xa8, 0xa3
}; };
private static readonly byte[] _gfMul0D = new byte[] private static ReadOnlySpan<byte> _gfMul0D => new byte[]
{ {
0x00, 0x0d, 0x1a, 0x17, 0x34, 0x39, 0x2e, 0x23, 0x68, 0x65, 0x72, 0x7f, 0x5c, 0x51, 0x46, 0x4b, 0x00, 0x0d, 0x1a, 0x17, 0x34, 0x39, 0x2e, 0x23, 0x68, 0x65, 0x72, 0x7f, 0x5c, 0x51, 0x46, 0x4b,
0xd0, 0xdd, 0xca, 0xc7, 0xe4, 0xe9, 0xfe, 0xf3, 0xb8, 0xb5, 0xa2, 0xaf, 0x8c, 0x81, 0x96, 0x9b, 0xd0, 0xdd, 0xca, 0xc7, 0xe4, 0xe9, 0xfe, 0xf3, 0xb8, 0xb5, 0xa2, 0xaf, 0x8c, 0x81, 0x96, 0x9b,
@@ -147,7 +148,7 @@ namespace ARMeilleure.Instructions
0xdc, 0xd1, 0xc6, 0xcb, 0xe8, 0xe5, 0xf2, 0xff, 0xb4, 0xb9, 0xae, 0xa3, 0x80, 0x8d, 0x9a, 0x97 0xdc, 0xd1, 0xc6, 0xcb, 0xe8, 0xe5, 0xf2, 0xff, 0xb4, 0xb9, 0xae, 0xa3, 0x80, 0x8d, 0x9a, 0x97
}; };
private static readonly byte[] _gfMul0E = new byte[] private static ReadOnlySpan<byte> _gfMul0E => new byte[]
{ {
0x00, 0x0e, 0x1c, 0x12, 0x38, 0x36, 0x24, 0x2a, 0x70, 0x7e, 0x6c, 0x62, 0x48, 0x46, 0x54, 0x5a, 0x00, 0x0e, 0x1c, 0x12, 0x38, 0x36, 0x24, 0x2a, 0x70, 0x7e, 0x6c, 0x62, 0x48, 0x46, 0x54, 0x5a,
0xe0, 0xee, 0xfc, 0xf2, 0xd8, 0xd6, 0xc4, 0xca, 0x90, 0x9e, 0x8c, 0x82, 0xa8, 0xa6, 0xb4, 0xba, 0xe0, 0xee, 0xfc, 0xf2, 0xd8, 0xd6, 0xc4, 0xca, 0x90, 0x9e, 0x8c, 0x82, 0xa8, 0xa6, 0xb4, 0xba,
@@ -167,12 +168,12 @@ namespace ARMeilleure.Instructions
0xd7, 0xd9, 0xcb, 0xc5, 0xef, 0xe1, 0xf3, 0xfd, 0xa7, 0xa9, 0xbb, 0xb5, 0x9f, 0x91, 0x83, 0x8d 0xd7, 0xd9, 0xcb, 0xc5, 0xef, 0xe1, 0xf3, 0xfd, 0xa7, 0xa9, 0xbb, 0xb5, 0x9f, 0x91, 0x83, 0x8d
}; };
private static readonly byte[] _srPerm = new byte[] private static ReadOnlySpan<byte> _srPerm => new byte[]
{ {
0, 13, 10, 7, 4, 1, 14, 11, 8, 5, 2, 15, 12, 9, 6, 3 0, 13, 10, 7, 4, 1, 14, 11, 8, 5, 2, 15, 12, 9, 6, 3
}; };
private static readonly byte[] _isrPerm = new byte[] private static ReadOnlySpan<byte> _isrPerm => new byte[]
{ {
0, 5, 10, 15, 4, 9, 14, 3, 8, 13, 2, 7, 12, 1, 6, 11 0, 5, 10, 15, 4, 9, 14, 3, 8, 13, 2, 7, 12, 1, 6, 11
}; };

View File

@@ -47,6 +47,20 @@ namespace ARMeilleure.Instructions
} }
} }
public static Operand GetIntA32AlignedPC(ArmEmitterContext context, int regIndex)
{
if (regIndex == RegisterAlias.Aarch32Pc)
{
OpCode32 op = (OpCode32)context.CurrOp;
return Const((int)(op.GetPc() & 0xfffffffc));
}
else
{
return Register(GetRegisterAlias(context.Mode, regIndex), RegisterType.Integer, OperandType.I32);
}
}
public static Operand GetVecA32(int regIndex) public static Operand GetVecA32(int regIndex)
{ {
return Register(regIndex, RegisterType.Vector, OperandType.V128); return Register(regIndex, RegisterType.Vector, OperandType.V128);

View File

@@ -153,7 +153,7 @@ namespace ARMeilleure.Instructions
{ {
OpCode32Mem op = (OpCode32Mem)context.CurrOp; OpCode32Mem op = (OpCode32Mem)context.CurrOp;
Operand n = context.Copy(GetIntA32(context, op.Rn)); Operand n = context.Copy(GetIntA32AlignedPC(context, op.Rn));
Operand m = GetMemM(context, setCarry: false); Operand m = GetMemM(context, setCarry: false);
Operand temp = default; Operand temp = default;

View File

@@ -824,7 +824,7 @@ namespace ARMeilleure.Instructions
return (ulong)(size - 1); return (ulong)(size - 1);
} }
private static readonly byte[] ClzNibbleTbl = { 4, 3, 2, 2, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0 }; private static ReadOnlySpan<byte> ClzNibbleTbl => new byte[] { 4, 3, 2, 2, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0 };
public static ulong CountLeadingZeros(ulong value, int size) // size is 8, 16, 32 or 64 (SIMD&FP or Base Inst.). public static ulong CountLeadingZeros(ulong value, int size) // size is 8, 16, 32 or 64 (SIMD&FP or Base Inst.).
{ {

View File

@@ -100,9 +100,11 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
{ {
for (int sampleIndex = 0; sampleIndex < context.SampleCount; sampleIndex++) for (int sampleIndex = 0; sampleIndex < context.SampleCount; sampleIndex++)
{ {
float inputSample = *((float*)inputBuffers[channelIndex] + sampleIndex); float rawInputSample = *((float*)inputBuffers[channelIndex] + sampleIndex);
float sampleInputMax = Math.Abs(inputSample * Parameter.InputGain); float inputSample = (rawInputSample / short.MaxValue) * Parameter.InputGain;
float sampleInputMax = Math.Abs(inputSample);
float inputCoefficient = Parameter.ReleaseCoefficient; float inputCoefficient = Parameter.ReleaseCoefficient;
@@ -131,7 +133,9 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
ref float delayedSample = ref state.DelayedSampleBuffer[channelIndex * Parameter.DelayBufferSampleCountMax + state.DelayedSampleBufferPosition[channelIndex]]; ref float delayedSample = ref state.DelayedSampleBuffer[channelIndex * Parameter.DelayBufferSampleCountMax + state.DelayedSampleBufferPosition[channelIndex]];
*((float*)outputBuffers[channelIndex] + sampleIndex) = delayedSample * state.CompressionGain[channelIndex] * Parameter.OutputGain; float outputSample = delayedSample * state.CompressionGain[channelIndex] * Parameter.OutputGain;
*((float*)outputBuffers[channelIndex] + sampleIndex) = outputSample * short.MaxValue;
delayedSample = inputSample; delayedSample = inputSample;

View File

@@ -111,9 +111,11 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
{ {
for (int sampleIndex = 0; sampleIndex < context.SampleCount; sampleIndex++) for (int sampleIndex = 0; sampleIndex < context.SampleCount; sampleIndex++)
{ {
float inputSample = *((float*)inputBuffers[channelIndex] + sampleIndex); float rawInputSample = *((float*)inputBuffers[channelIndex] + sampleIndex);
float sampleInputMax = Math.Abs(inputSample * Parameter.InputGain); float inputSample = (rawInputSample / short.MaxValue) * Parameter.InputGain;
float sampleInputMax = Math.Abs(inputSample);
float inputCoefficient = Parameter.ReleaseCoefficient; float inputCoefficient = Parameter.ReleaseCoefficient;
@@ -142,7 +144,9 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
ref float delayedSample = ref state.DelayedSampleBuffer[channelIndex * Parameter.DelayBufferSampleCountMax + state.DelayedSampleBufferPosition[channelIndex]]; ref float delayedSample = ref state.DelayedSampleBuffer[channelIndex * Parameter.DelayBufferSampleCountMax + state.DelayedSampleBufferPosition[channelIndex]];
*((float*)outputBuffers[channelIndex] + sampleIndex) = delayedSample * state.CompressionGain[channelIndex] * Parameter.OutputGain; float outputSample = delayedSample * state.CompressionGain[channelIndex] * Parameter.OutputGain;
*((float*)outputBuffers[channelIndex] + sampleIndex) = outputSample * short.MaxValue;
delayedSample = inputSample; delayedSample = inputSample;

View File

@@ -76,7 +76,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
DataSourceHelper.WaveBufferInformation info = new DataSourceHelper.WaveBufferInformation DataSourceHelper.WaveBufferInformation info = new DataSourceHelper.WaveBufferInformation
{ {
SourceSampleRate = SampleRate, SourceSampleRate = SampleRate,
SampleFormat = SampleFormat.PcmInt16, SampleFormat = SampleFormat.PcmFloat,
Pitch = Pitch, Pitch = Pitch,
DecodingBehaviour = DecodingBehaviour, DecodingBehaviour = DecodingBehaviour,
ExtraParameter = 0, ExtraParameter = 0,

View File

@@ -600,19 +600,42 @@ namespace Ryujinx.Audio.Renderer.Dsp
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void ResampleForUpsampler(Span<float> outputBuffer, ReadOnlySpan<float> inputBuffer, float ratio, ref float fraction, int sampleCount) public static void ResampleForUpsampler(Span<float> outputBuffer, ReadOnlySpan<float> inputBuffer, float ratio, ref float fraction, int sampleCount)
{ {
// TODO: use a bandwidth filter to have better resampling. // Currently a simple cubic interpolation, assuming duplicated values at edges.
// TODO: Discover and use algorithm that the switch uses.
int inputBufferIndex = 0; int inputBufferIndex = 0;
int maxIndex = inputBuffer.Length - 1;
int cubicEnd = inputBuffer.Length - 3;
for (int i = 0; i < sampleCount; i++) for (int i = 0; i < sampleCount; i++)
{ {
float outputData = inputBuffer[inputBufferIndex]; float s0, s1, s2, s3;
if (fraction > 1.0f) s1 = inputBuffer[inputBufferIndex];
if (inputBufferIndex == 0 || inputBufferIndex > cubicEnd)
{ {
outputData = inputBuffer[inputBufferIndex + 1]; // Clamp interplation values at the ends of the input buffer.
s0 = inputBuffer[Math.Max(0, inputBufferIndex - 1)];
s2 = inputBuffer[Math.Min(maxIndex, inputBufferIndex + 1)];
s3 = inputBuffer[Math.Min(maxIndex, inputBufferIndex + 2)];
}
else
{
s0 = inputBuffer[inputBufferIndex - 1];
s2 = inputBuffer[inputBufferIndex + 1];
s3 = inputBuffer[inputBufferIndex + 2];
} }
outputBuffer[i] = outputData; float a = s3 - s2 - s0 + s1;
float b = s0 - s1 - a;
float c = s2 - s0;
float d = s1;
float f2 = fraction * fraction;
float f3 = f2 * fraction;
outputBuffer[i] = a * f3 + b * f2 + c * fraction + d;
fraction += ratio; fraction += ratio;
inputBufferIndex += (int)MathF.Truncate(fraction); inputBufferIndex += (int)MathF.Truncate(fraction);

View File

@@ -37,6 +37,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.State
DectectorAverage.AsSpan().Fill(0.0f); DectectorAverage.AsSpan().Fill(0.0f);
CompressionGain.AsSpan().Fill(1.0f); CompressionGain.AsSpan().Fill(1.0f);
DelayedSampleBufferPosition.AsSpan().Fill(0); DelayedSampleBufferPosition.AsSpan().Fill(0);
DelayedSampleBuffer.AsSpan().Fill(0.0f);
UpdateParameter(ref parameter); UpdateParameter(ref parameter);
} }

View File

@@ -558,7 +558,16 @@ namespace Ryujinx.Audio.Renderer.Server
if (_rendererContext.BehaviourContext.IsEffectInfoVersion2Supported()) if (_rendererContext.BehaviourContext.IsEffectInfoVersion2Supported())
{ {
Memory<EffectResultState> dspResultState = _effectContext.GetDspStateMemory(effectId); Memory<EffectResultState> dspResultState;
if (effect.Parameter.StatisticsEnabled)
{
dspResultState = _effectContext.GetDspStateMemory(effectId);
}
else
{
dspResultState = Memory<EffectResultState>.Empty;
}
_commandBuffer.GenerateLimiterEffectVersion2(bufferOffset, effect.Parameter, effect.State, dspResultState, effect.IsEnabled, workBuffer, nodeId); _commandBuffer.GenerateLimiterEffectVersion2(bufferOffset, effect.Parameter, effect.State, dspResultState, effect.IsEnabled, workBuffer, nodeId);
} }

View File

@@ -1,12 +0,0 @@
using System;
namespace Ryujinx.Common
{
public static class EnumExtensions
{
public static T[] GetValues<T>()
{
return (T[])Enum.GetValues(typeof(T));
}
}
}

View File

@@ -94,7 +94,7 @@ namespace Ryujinx.Common.Logging
static Logger() static Logger()
{ {
m_EnabledClasses = new bool[Enum.GetNames(typeof(LogClass)).Length]; m_EnabledClasses = new bool[Enum.GetNames<LogClass>().Length];
for (int index = 0; index < m_EnabledClasses.Length; index++) for (int index = 0; index < m_EnabledClasses.Length; index++)
{ {

View File

@@ -1,8 +1,10 @@
using System;
namespace Ryujinx.Common namespace Ryujinx.Common
{ {
public static class BitUtils public static class BitUtils
{ {
private static readonly byte[] ClzNibbleTbl = { 4, 3, 2, 2, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0 }; private static ReadOnlySpan<byte> ClzNibbleTbl => new byte[] { 4, 3, 2, 2, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0 };
public static uint AlignUp(uint value, int size) public static uint AlignUp(uint value, int size)
{ {

View File

@@ -43,7 +43,7 @@ namespace Ryujinx.Common
Prime32_1 Prime32_1
}; };
private static readonly byte[] Xxh3KSecret = new byte[] private static ReadOnlySpan<byte> Xxh3KSecret => new byte[]
{ {
0xb8, 0xfe, 0x6c, 0x39, 0x23, 0xa4, 0x4b, 0xbe, 0x7c, 0x01, 0x81, 0x2c, 0xf7, 0x21, 0xad, 0x1c, 0xb8, 0xfe, 0x6c, 0x39, 0x23, 0xa4, 0x4b, 0xbe, 0x7c, 0x01, 0x81, 0x2c, 0xf7, 0x21, 0xad, 0x1c,
0xde, 0xd4, 0x6d, 0xe9, 0x83, 0x90, 0x97, 0xdb, 0x72, 0x40, 0xa4, 0xa4, 0xb7, 0xb3, 0x67, 0x1f, 0xde, 0xd4, 0x6d, 0xe9, 0x83, 0x90, 0x97, 0xdb, 0x72, 0x40, 0xa4, 0xa4, 0xb7, 0xb3, 0x67, 0x1f,

View File

@@ -20,7 +20,7 @@ namespace Ryujinx.Graphics.GAL
BufferHandle CreateBuffer(int size); BufferHandle CreateBuffer(int size);
IProgram CreateProgram(IShader[] shaders); IProgram CreateProgram(IShader[] shaders, ShaderInfo info);
ISampler CreateSampler(SamplerCreateInfo info); ISampler CreateSampler(SamplerCreateInfo info);
ITexture CreateTexture(TextureCreateInfo info, float scale); ITexture CreateTexture(TextureCreateInfo info, float scale);
@@ -33,7 +33,7 @@ namespace Ryujinx.Graphics.GAL
Capabilities GetCapabilities(); Capabilities GetCapabilities();
IProgram LoadProgramBinary(byte[] programBinary); IProgram LoadProgramBinary(byte[] programBinary, bool hasFragmentShader, ShaderInfo info);
void SetBufferData(BufferHandle buffer, int offset, ReadOnlySpan<byte> data); void SetBufferData(BufferHandle buffer, int offset, ReadOnlySpan<byte> data);

View File

@@ -5,17 +5,21 @@
public ThreadedProgram Threaded { get; set; } public ThreadedProgram Threaded { get; set; }
private byte[] _data; private byte[] _data;
private bool _hasFragmentShader;
private ShaderInfo _info;
public BinaryProgramRequest(ThreadedProgram program, byte[] data) public BinaryProgramRequest(ThreadedProgram program, byte[] data, bool hasFragmentShader, ShaderInfo info)
{ {
Threaded = program; Threaded = program;
_data = data; _data = data;
_hasFragmentShader = hasFragmentShader;
_info = info;
} }
public IProgram Create(IRenderer renderer) public IProgram Create(IRenderer renderer)
{ {
return renderer.LoadProgramBinary(_data); return renderer.LoadProgramBinary(_data, _hasFragmentShader, _info);
} }
} }
} }

View File

@@ -7,12 +7,14 @@ namespace Ryujinx.Graphics.GAL.Multithreading.Resources.Programs
public ThreadedProgram Threaded { get; set; } public ThreadedProgram Threaded { get; set; }
private IShader[] _shaders; private IShader[] _shaders;
private ShaderInfo _info;
public SourceProgramRequest(ThreadedProgram program, IShader[] shaders) public SourceProgramRequest(ThreadedProgram program, IShader[] shaders, ShaderInfo info)
{ {
Threaded = program; Threaded = program;
_shaders = shaders; _shaders = shaders;
_info = info;
} }
public IProgram Create(IRenderer renderer) public IProgram Create(IRenderer renderer)
@@ -24,7 +26,7 @@ namespace Ryujinx.Graphics.GAL.Multithreading.Resources.Programs
return threaded?.Base; return threaded?.Base;
}).ToArray(); }).ToArray();
return renderer.CreateProgram(shaders); return renderer.CreateProgram(shaders, _info);
} }
} }
} }

View File

@@ -268,10 +268,10 @@ namespace Ryujinx.Graphics.GAL.Multithreading
return handle; return handle;
} }
public IProgram CreateProgram(IShader[] shaders) public IProgram CreateProgram(IShader[] shaders, ShaderInfo info)
{ {
var program = new ThreadedProgram(this); var program = new ThreadedProgram(this);
SourceProgramRequest request = new SourceProgramRequest(program, shaders); SourceProgramRequest request = new SourceProgramRequest(program, shaders, info);
Programs.Add(request); Programs.Add(request);
New<CreateProgramCommand>().Set(Ref((IProgramRequest)request)); New<CreateProgramCommand>().Set(Ref((IProgramRequest)request));
@@ -355,11 +355,11 @@ namespace Ryujinx.Graphics.GAL.Multithreading
_baseRenderer.Initialize(logLevel); _baseRenderer.Initialize(logLevel);
} }
public IProgram LoadProgramBinary(byte[] programBinary) public IProgram LoadProgramBinary(byte[] programBinary, bool hasFragmentShader, ShaderInfo info)
{ {
var program = new ThreadedProgram(this); var program = new ThreadedProgram(this);
BinaryProgramRequest request = new BinaryProgramRequest(program, programBinary); BinaryProgramRequest request = new BinaryProgramRequest(program, programBinary, hasFragmentShader, info);
Programs.Add(request); Programs.Add(request);
New<CreateProgramCommand>().Set(Ref((IProgramRequest)request)); New<CreateProgramCommand>().Set(Ref((IProgramRequest)request));

View File

@@ -0,0 +1,12 @@
namespace Ryujinx.Graphics.GAL
{
public struct ShaderInfo
{
public int FragmentOutputMap { get; }
public ShaderInfo(int fragmentOutputMap)
{
FragmentOutputMap = fragmentOutputMap;
}
}
}

View File

@@ -85,9 +85,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Dma
} }
int alignWidth = Constants.StrideAlignment / bpp; int alignWidth = Constants.StrideAlignment / bpp;
return tex.RegionX == 0 && return stride / bpp == BitUtils.AlignUp(xCount, alignWidth);
tex.RegionY == 0 &&
stride / bpp == BitUtils.AlignUp(xCount, alignWidth);
} }
else else
{ {
@@ -161,6 +159,20 @@ namespace Ryujinx.Graphics.Gpu.Engine.Dma
var dst = Unsafe.As<uint, DmaTexture>(ref _state.State.SetDstBlockSize); var dst = Unsafe.As<uint, DmaTexture>(ref _state.State.SetDstBlockSize);
var src = Unsafe.As<uint, DmaTexture>(ref _state.State.SetSrcBlockSize); var src = Unsafe.As<uint, DmaTexture>(ref _state.State.SetSrcBlockSize);
int srcRegionX = 0, srcRegionY = 0, dstRegionX = 0, dstRegionY = 0;
if (!srcLinear)
{
srcRegionX = src.RegionX;
srcRegionY = src.RegionY;
}
if (!dstLinear)
{
dstRegionX = dst.RegionX;
dstRegionY = dst.RegionY;
}
int srcStride = (int)_state.State.PitchIn; int srcStride = (int)_state.State.PitchIn;
int dstStride = (int)_state.State.PitchOut; int dstStride = (int)_state.State.PitchOut;
@@ -182,8 +194,8 @@ namespace Ryujinx.Graphics.Gpu.Engine.Dma
dst.MemoryLayout.UnpackGobBlocksInZ(), dst.MemoryLayout.UnpackGobBlocksInZ(),
dstBpp); dstBpp);
(int srcBaseOffset, int srcSize) = srcCalculator.GetRectangleRange(src.RegionX, src.RegionY, xCount, yCount); (int srcBaseOffset, int srcSize) = srcCalculator.GetRectangleRange(srcRegionX, srcRegionY, xCount, yCount);
(int dstBaseOffset, int dstSize) = dstCalculator.GetRectangleRange(dst.RegionX, dst.RegionY, xCount, yCount); (int dstBaseOffset, int dstSize) = dstCalculator.GetRectangleRange(dstRegionX, dstRegionY, xCount, yCount);
if (srcLinear && srcStride < 0) if (srcLinear && srcStride < 0)
{ {
@@ -272,13 +284,13 @@ namespace Ryujinx.Graphics.Gpu.Engine.Dma
for (int y = 0; y < yCount; y++) for (int y = 0; y < yCount; y++)
{ {
srcCalculator.SetY(src.RegionY + y); srcCalculator.SetY(srcRegionY + y);
dstCalculator.SetY(dst.RegionY + y); dstCalculator.SetY(dstRegionY + y);
for (int x = 0; x < xCount; x++) for (int x = 0; x < xCount; x++)
{ {
int srcOffset = srcCalculator.GetOffset(src.RegionX + x); int srcOffset = srcCalculator.GetOffset(srcRegionX + x);
int dstOffset = dstCalculator.GetOffset(dst.RegionX + x); int dstOffset = dstCalculator.GetOffset(dstRegionX + x);
*(T*)(dstBase + dstOffset) = *(T*)(srcBase + srcOffset); *(T*)(dstBase + dstOffset) = *(T*)(srcBase + srcOffset);
} }

View File

@@ -112,7 +112,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.MME
_ilGen.Emit(OpCodes.Ret); _ilGen.Emit(OpCodes.Ret);
} }
return (MacroExecute)_meth.CreateDelegate(typeof(MacroExecute)); return _meth.CreateDelegate<MacroExecute>();
} }
/// <summary> /// <summary>

View File

@@ -77,7 +77,8 @@ namespace Ryujinx.Graphics.Gpu.Shader.Cache.Definition
programInfo.Images.Count, programInfo.Images.Count,
programInfo.UsesInstanceId, programInfo.UsesInstanceId,
programInfo.UsesRtLayer, programInfo.UsesRtLayer,
programInfo.ClipDistancesWritten); programInfo.ClipDistancesWritten,
programInfo.FragmentOutputMap);
CBuffers = programInfo.CBuffers.ToArray(); CBuffers = programInfo.CBuffers.ToArray();
SBuffers = programInfo.SBuffers.ToArray(); SBuffers = programInfo.SBuffers.ToArray();
Textures = programInfo.Textures.ToArray(); Textures = programInfo.Textures.ToArray();
@@ -97,7 +98,8 @@ namespace Ryujinx.Graphics.Gpu.Shader.Cache.Definition
Images, Images,
Header.UseFlags.HasFlag(UseFlags.InstanceId), Header.UseFlags.HasFlag(UseFlags.InstanceId),
Header.UseFlags.HasFlag(UseFlags.RtLayer), Header.UseFlags.HasFlag(UseFlags.RtLayer),
Header.ClipDistancesWritten); Header.ClipDistancesWritten,
Header.FragmentOutputMap);
} }
/// <summary> /// <summary>

View File

@@ -26,7 +26,7 @@ namespace Ryujinx.Graphics.Gpu.Shader.Cache.Definition
/// <summary> /// <summary>
/// Host shader entry header used for binding information. /// Host shader entry header used for binding information.
/// </summary> /// </summary>
[StructLayout(LayoutKind.Sequential, Pack = 1, Size = 0x14)] [StructLayout(LayoutKind.Sequential, Pack = 1, Size = 0x18)]
struct HostShaderCacheEntryHeader struct HostShaderCacheEntryHeader
{ {
/// <summary> /// <summary>
@@ -70,6 +70,11 @@ namespace Ryujinx.Graphics.Gpu.Shader.Cache.Definition
/// </summary> /// </summary>
public byte Reserved; public byte Reserved;
/// <summary>
/// Mask of components written by the fragment shader stage.
/// </summary>
public int FragmentOutputMap;
/// <summary> /// <summary>
/// Create a new host shader cache entry header. /// Create a new host shader cache entry header.
/// </summary> /// </summary>
@@ -78,6 +83,8 @@ namespace Ryujinx.Graphics.Gpu.Shader.Cache.Definition
/// <param name="texturesCount">Count of texture descriptors</param> /// <param name="texturesCount">Count of texture descriptors</param>
/// <param name="imagesCount">Count of image descriptors</param> /// <param name="imagesCount">Count of image descriptors</param>
/// <param name="usesInstanceId">Set to true if the shader uses instance id</param> /// <param name="usesInstanceId">Set to true if the shader uses instance id</param>
/// <param name="clipDistancesWritten">Mask of clip distances that are written to on the shader</param>
/// <param name="fragmentOutputMap">Mask of components written by the fragment shader stage</param>
public HostShaderCacheEntryHeader( public HostShaderCacheEntryHeader(
int cBuffersCount, int cBuffersCount,
int sBuffersCount, int sBuffersCount,
@@ -85,13 +92,15 @@ namespace Ryujinx.Graphics.Gpu.Shader.Cache.Definition
int imagesCount, int imagesCount,
bool usesInstanceId, bool usesInstanceId,
bool usesRtLayer, bool usesRtLayer,
byte clipDistancesWritten) : this() byte clipDistancesWritten,
int fragmentOutputMap) : this()
{ {
CBuffersCount = cBuffersCount; CBuffersCount = cBuffersCount;
SBuffersCount = sBuffersCount; SBuffersCount = sBuffersCount;
TexturesCount = texturesCount; TexturesCount = texturesCount;
ImagesCount = imagesCount; ImagesCount = imagesCount;
ClipDistancesWritten = clipDistancesWritten; ClipDistancesWritten = clipDistancesWritten;
FragmentOutputMap = fragmentOutputMap;
InUse = true; InUse = true;
UseFlags = usesInstanceId ? UseFlags.InstanceId : UseFlags.None; UseFlags = usesInstanceId ? UseFlags.InstanceId : UseFlags.None;

View File

@@ -40,7 +40,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
/// <summary> /// <summary>
/// Version of the codegen (to be changed when codegen or guest format change). /// Version of the codegen (to be changed when codegen or guest format change).
/// </summary> /// </summary>
private const ulong ShaderCodeGenVersion = 3106; private const ulong ShaderCodeGenVersion = 3063;
// Progress reporting helpers // Progress reporting helpers
private volatile int _shaderCount; private volatile int _shaderCount;
@@ -188,7 +188,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
{ {
hostShaderEntries = HostShaderCacheEntry.Parse(hostProgramBinary, out ReadOnlySpan<byte> hostProgramBinarySpan); hostShaderEntries = HostShaderCacheEntry.Parse(hostProgramBinary, out ReadOnlySpan<byte> hostProgramBinarySpan);
hostProgramBinary = hostProgramBinarySpan.ToArray(); hostProgramBinary = hostProgramBinarySpan.ToArray();
hostProgram = _context.Renderer.LoadProgramBinary(hostProgramBinary); hostProgram = _context.Renderer.LoadProgramBinary(hostProgramBinary, false, new ShaderInfo(-1));
} }
ShaderCompileTask task = new ShaderCompileTask(taskDoneEvent); ShaderCompileTask task = new ShaderCompileTask(taskDoneEvent);
@@ -252,7 +252,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
// Compile shader and create program as the shader program binary got invalidated. // Compile shader and create program as the shader program binary got invalidated.
shader.HostShader = _context.Renderer.CompileShader(ShaderStage.Compute, program.Code); shader.HostShader = _context.Renderer.CompileShader(ShaderStage.Compute, program.Code);
hostProgram = _context.Renderer.CreateProgram(new IShader[] { shader.HostShader }); hostProgram = _context.Renderer.CreateProgram(new IShader[] { shader.HostShader }, new ShaderInfo(-1));
task.OnCompiled(hostProgram, (bool isNewProgramValid, ShaderCompileTask task) => task.OnCompiled(hostProgram, (bool isNewProgramValid, ShaderCompileTask task) =>
{ {
@@ -303,7 +303,18 @@ namespace Ryujinx.Graphics.Gpu.Shader
{ {
hostShaderEntries = HostShaderCacheEntry.Parse(hostProgramBinary, out ReadOnlySpan<byte> hostProgramBinarySpan); hostShaderEntries = HostShaderCacheEntry.Parse(hostProgramBinary, out ReadOnlySpan<byte> hostProgramBinarySpan);
hostProgramBinary = hostProgramBinarySpan.ToArray(); hostProgramBinary = hostProgramBinarySpan.ToArray();
hostProgram = _context.Renderer.LoadProgramBinary(hostProgramBinary);
bool hasFragmentShader = false;
int fragmentOutputMap = -1;
int fragmentIndex = (int)ShaderStage.Fragment - 1;
if (hostShaderEntries[fragmentIndex] != null && hostShaderEntries[fragmentIndex].Header.InUse)
{
hasFragmentShader = true;
fragmentOutputMap = hostShaderEntries[fragmentIndex].Header.FragmentOutputMap;
}
hostProgram = _context.Renderer.LoadProgramBinary(hostProgramBinary, hasFragmentShader, new ShaderInfo(fragmentOutputMap));
} }
ShaderCompileTask task = new ShaderCompileTask(taskDoneEvent); ShaderCompileTask task = new ShaderCompileTask(taskDoneEvent);
@@ -426,7 +437,15 @@ namespace Ryujinx.Graphics.Gpu.Shader
hostShaders.Add(hostShader); hostShaders.Add(hostShader);
} }
hostProgram = _context.Renderer.CreateProgram(hostShaders.ToArray()); int fragmentIndex = (int)ShaderStage.Fragment - 1;
int fragmentOutputMap = -1;
if (shaders[fragmentIndex] != null)
{
fragmentOutputMap = shaders[fragmentIndex].Info.FragmentOutputMap;
}
hostProgram = _context.Renderer.CreateProgram(hostShaders.ToArray(), new ShaderInfo(fragmentOutputMap));
task.OnCompiled(hostProgram, (bool isNewProgramValid, ShaderCompileTask task) => task.OnCompiled(hostProgram, (bool isNewProgramValid, ShaderCompileTask task) =>
{ {
@@ -617,7 +636,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
shader.HostShader = _context.Renderer.CompileShader(ShaderStage.Compute, shader.Program.Code); shader.HostShader = _context.Renderer.CompileShader(ShaderStage.Compute, shader.Program.Code);
IProgram hostProgram = _context.Renderer.CreateProgram(new IShader[] { shader.HostShader }); IProgram hostProgram = _context.Renderer.CreateProgram(new IShader[] { shader.HostShader }, new ShaderInfo(-1));
cpShader = new ShaderBundle(hostProgram, shader); cpShader = new ShaderBundle(hostProgram, shader);
@@ -755,7 +774,15 @@ namespace Ryujinx.Graphics.Gpu.Shader
hostShaders.Add(hostShader); hostShaders.Add(hostShader);
} }
IProgram hostProgram = _context.Renderer.CreateProgram(hostShaders.ToArray()); int fragmentIndex = (int)ShaderStage.Fragment - 1;
int fragmentOutputMap = -1;
if (shaders[fragmentIndex] != null)
{
fragmentOutputMap = shaders[fragmentIndex].Info.FragmentOutputMap;
}
IProgram hostProgram = _context.Renderer.CreateProgram(hostShaders.ToArray(), new ShaderInfo(fragmentOutputMap));
gpShaders = new ShaderBundle(hostProgram, shaders); gpShaders = new ShaderBundle(hostProgram, shaders);

View File

@@ -118,7 +118,7 @@ namespace Ryujinx.Graphics.Nvdec.FFmpeg.H264
} }
// ZigZag LUTs from libavcodec. // ZigZag LUTs from libavcodec.
private static readonly byte[] ZigZagDirect = new byte[] private static ReadOnlySpan<byte> ZigZagDirect => new byte[]
{ {
0, 1, 8, 16, 9, 2, 3, 10, 0, 1, 8, 16, 9, 2, 3, 10,
17, 24, 32, 25, 18, 11, 4, 5, 17, 24, 32, 25, 18, 11, 4, 5,
@@ -130,7 +130,7 @@ namespace Ryujinx.Graphics.Nvdec.FFmpeg.H264
53, 60, 61, 54, 47, 55, 62, 63 53, 60, 61, 54, 47, 55, 62, 63
}; };
private static readonly byte[] ZigZagScan = new byte[] private static ReadOnlySpan<byte> ZigZagScan => new byte[]
{ {
0 + 0 * 4, 1 + 0 * 4, 0 + 1 * 4, 0 + 2 * 4, 0 + 0 * 4, 1 + 0 * 4, 0 + 1 * 4, 0 + 2 * 4,
1 + 1 * 4, 2 + 0 * 4, 3 + 0 * 4, 2 + 1 * 4, 1 + 1 * 4, 2 + 0 * 4, 3 + 0 * 4, 2 + 1 * 4,
@@ -140,7 +140,7 @@ namespace Ryujinx.Graphics.Nvdec.FFmpeg.H264
private static void WriteScalingList(ref H264BitStreamWriter writer, IArray<byte> list) private static void WriteScalingList(ref H264BitStreamWriter writer, IArray<byte> list)
{ {
byte[] scan = list.Length == 16 ? ZigZagScan : ZigZagDirect; ReadOnlySpan<byte> scan = list.Length == 16 ? ZigZagScan : ZigZagDirect;
int lastScale = 8; int lastScale = 8;

View File

@@ -15,7 +15,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
public ISurface CreateSurface(int width, int height) => new Surface(width, height); public ISurface CreateSurface(int width, int height) => new Surface(width, height);
private static readonly byte[] LiteralToFilter = new byte[] private static ReadOnlySpan<byte> LiteralToFilter => new byte[]
{ {
Constants.EightTapSmooth, Constants.EightTapSmooth,
Constants.EightTap, Constants.EightTap,

View File

@@ -1,5 +1,6 @@
using Ryujinx.Graphics.Nvdec.Vp9.Common; using Ryujinx.Graphics.Nvdec.Vp9.Common;
using Ryujinx.Graphics.Nvdec.Vp9.Types; using Ryujinx.Graphics.Nvdec.Vp9.Types;
using System;
using static Ryujinx.Graphics.Nvdec.Vp9.Dsp.IntraPred; using static Ryujinx.Graphics.Nvdec.Vp9.Dsp.IntraPred;
namespace Ryujinx.Graphics.Nvdec.Vp9 namespace Ryujinx.Graphics.Nvdec.Vp9
@@ -24,7 +25,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
private const int NeedAbove = 1 << 2; private const int NeedAbove = 1 << 2;
private const int NeedAboveRight = 1 << 3; private const int NeedAboveRight = 1 << 3;
private static readonly byte[] ExtendModes = new byte[] private static ReadOnlySpan<byte> ExtendModes => new byte[]
{ {
NeedAbove | NeedLeft, // DC NeedAbove | NeedLeft, // DC
NeedAbove, // V NeedAbove, // V

View File

@@ -10,7 +10,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Types
public short Row; public short Row;
public short Col; public short Col;
private static readonly byte[] LogInBase2 = new byte[] private static ReadOnlySpan<byte> LogInBase2 => new byte[]
{ {
0, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,

View File

@@ -11,7 +11,7 @@ namespace Ryujinx.Graphics.OpenGL
static FormatTable() static FormatTable()
{ {
int tableSize = Enum.GetNames(typeof(Format)).Length; int tableSize = Enum.GetNames<Format>().Length;
Table = new FormatInfo[tableSize]; Table = new FormatInfo[tableSize];
TableImage = new SizedInternalFormat[tableSize]; TableImage = new SizedInternalFormat[tableSize];

View File

@@ -53,7 +53,9 @@ namespace Ryujinx.Graphics.OpenGL
private ClipOrigin _clipOrigin; private ClipOrigin _clipOrigin;
private ClipDepthMode _clipDepthMode; private ClipDepthMode _clipDepthMode;
private readonly uint[] _componentMasks; private uint _fragmentOutputMap;
private uint _componentMasks;
private uint _currentComponentMasks;
private uint _scissorEnables; private uint _scissorEnables;
@@ -73,12 +75,8 @@ namespace Ryujinx.Graphics.OpenGL
_clipOrigin = ClipOrigin.LowerLeft; _clipOrigin = ClipOrigin.LowerLeft;
_clipDepthMode = ClipDepthMode.NegativeOneToOne; _clipDepthMode = ClipDepthMode.NegativeOneToOne;
_componentMasks = new uint[Constants.MaxRenderTargets]; _fragmentOutputMap = uint.MaxValue;
_componentMasks = uint.MaxValue;
for (int index = 0; index < Constants.MaxRenderTargets; index++)
{
_componentMasks[index] = 0xf;
}
var defaultScale = new Vector4<float> { X = 1f, Y = 0f, Z = 0f, W = 0f }; var defaultScale = new Vector4<float> { X = 1f, Y = 0f, Z = 0f, W = 0f };
new Span<Vector4<float>>(_renderScale).Fill(defaultScale); new Span<Vector4<float>>(_renderScale).Fill(defaultScale);
@@ -1001,18 +999,30 @@ namespace Ryujinx.Graphics.OpenGL
public void SetProgram(IProgram program) public void SetProgram(IProgram program)
{ {
_program = (Program)program; Program prg = (Program)program;
if (_tfEnabled) if (_tfEnabled)
{ {
GL.EndTransformFeedback(); GL.EndTransformFeedback();
_program.Bind(); prg.Bind();
GL.BeginTransformFeedback(_tfTopology); GL.BeginTransformFeedback(_tfTopology);
} }
else else
{ {
_program.Bind(); prg.Bind();
} }
if (prg.HasFragmentShader && _fragmentOutputMap != (uint)prg.FragmentOutputMap)
{
_fragmentOutputMap = (uint)prg.FragmentOutputMap;
for (int index = 0; index < Constants.MaxRenderTargets; index++)
{
RestoreComponentMask(index, force: false);
}
}
_program = prg;
} }
public void SetRasterizerDiscard(bool discard) public void SetRasterizerDiscard(bool discard)
@@ -1037,11 +1047,13 @@ namespace Ryujinx.Graphics.OpenGL
public void SetRenderTargetColorMasks(ReadOnlySpan<uint> componentMasks) public void SetRenderTargetColorMasks(ReadOnlySpan<uint> componentMasks)
{ {
_componentMasks = 0;
for (int index = 0; index < componentMasks.Length; index++) for (int index = 0; index < componentMasks.Length; index++)
{ {
_componentMasks[index] = componentMasks[index]; _componentMasks |= componentMasks[index] << (index * 4);
RestoreComponentMask(index); RestoreComponentMask(index, force: false);
} }
} }
@@ -1436,18 +1448,34 @@ namespace Ryujinx.Graphics.OpenGL
} }
} }
public void RestoreComponentMask(int index) public void RestoreComponentMask(int index, bool force = true)
{ {
// If the bound render target is bgra, swap the red and blue masks. // If the bound render target is bgra, swap the red and blue masks.
uint redMask = _fpIsBgra[index].X == 0 ? 1u : 4u; uint redMask = _fpIsBgra[index].X == 0 ? 1u : 4u;
uint blueMask = _fpIsBgra[index].X == 0 ? 4u : 1u; uint blueMask = _fpIsBgra[index].X == 0 ? 4u : 1u;
int shift = index * 4;
uint componentMask = _componentMasks & _fragmentOutputMap;
uint checkMask = 0xfu << shift;
uint componentMaskAtIndex = componentMask & checkMask;
if (!force && componentMaskAtIndex == (_currentComponentMasks & checkMask))
{
return;
}
componentMask >>= shift;
componentMask &= 0xfu;
GL.ColorMask( GL.ColorMask(
index, index,
(_componentMasks[index] & redMask) != 0, (componentMask & redMask) != 0,
(_componentMasks[index] & 2u) != 0, (componentMask & 2u) != 0,
(_componentMasks[index] & blueMask) != 0, (componentMask & blueMask) != 0,
(_componentMasks[index] & 8u) != 0); (componentMask & 8u) != 0);
_currentComponentMasks &= ~checkMask;
_currentComponentMasks |= componentMaskAtIndex;
} }
public void RestoreScissor0Enable() public void RestoreScissor0Enable()

View File

@@ -1,11 +1,8 @@
using OpenTK.Graphics.OpenGL; using OpenTK.Graphics.OpenGL;
using Ryujinx.Common.Logging; using Ryujinx.Common.Logging;
using Ryujinx.Graphics.GAL; using Ryujinx.Graphics.GAL;
using Ryujinx.Graphics.Shader.CodeGen.Glsl;
using System; using System;
using System.Buffers.Binary; using System.Buffers.Binary;
using System.Collections.Generic;
using System.Linq;
namespace Ryujinx.Graphics.OpenGL namespace Ryujinx.Graphics.OpenGL
{ {
@@ -29,7 +26,10 @@ namespace Ryujinx.Graphics.OpenGL
private ProgramLinkStatus _status = ProgramLinkStatus.Incomplete; private ProgramLinkStatus _status = ProgramLinkStatus.Incomplete;
private IShader[] _shaders; private IShader[] _shaders;
public Program(IShader[] shaders) public bool HasFragmentShader;
public int FragmentOutputMap { get; }
public Program(IShader[] shaders, int fragmentOutputMap)
{ {
Handle = GL.CreateProgram(); Handle = GL.CreateProgram();
@@ -37,17 +37,23 @@ namespace Ryujinx.Graphics.OpenGL
for (int index = 0; index < shaders.Length; index++) for (int index = 0; index < shaders.Length; index++)
{ {
int shaderHandle = ((Shader)shaders[index]).Handle; Shader shader = (Shader)shaders[index];
GL.AttachShader(Handle, shaderHandle); if (shader.IsFragment)
{
HasFragmentShader = true;
}
GL.AttachShader(Handle, shader.Handle);
} }
GL.LinkProgram(Handle); GL.LinkProgram(Handle);
_shaders = shaders; _shaders = shaders;
FragmentOutputMap = fragmentOutputMap;
} }
public Program(ReadOnlySpan<byte> code) public Program(ReadOnlySpan<byte> code, bool hasFragmentShader, int fragmentOutputMap)
{ {
BinaryFormat binaryFormat = (BinaryFormat)BinaryPrimitives.ReadInt32LittleEndian(code.Slice(code.Length - 4, 4)); BinaryFormat binaryFormat = (BinaryFormat)BinaryPrimitives.ReadInt32LittleEndian(code.Slice(code.Length - 4, 4));
@@ -60,6 +66,9 @@ namespace Ryujinx.Graphics.OpenGL
GL.ProgramBinary(Handle, binaryFormat, (IntPtr)ptr, code.Length - 4); GL.ProgramBinary(Handle, binaryFormat, (IntPtr)ptr, code.Length - 4);
} }
} }
HasFragmentShader = hasFragmentShader;
FragmentOutputMap = fragmentOutputMap;
} }
public void Bind() public void Bind()

View File

@@ -9,7 +9,7 @@ namespace Ryujinx.Graphics.OpenGL.Queries
public Counters() public Counters()
{ {
int count = Enum.GetNames(typeof(CounterType)).Length; int count = Enum.GetNames<CounterType>().Length;
_counterQueues = new CounterQueue[count]; _counterQueues = new CounterQueue[count];
} }

View File

@@ -66,9 +66,9 @@ namespace Ryujinx.Graphics.OpenGL
return Buffer.Create(size); return Buffer.Create(size);
} }
public IProgram CreateProgram(IShader[] shaders) public IProgram CreateProgram(IShader[] shaders, ShaderInfo info)
{ {
return new Program(shaders); return new Program(shaders, info.FragmentOutputMap);
} }
public ISampler CreateSampler(SamplerCreateInfo info) public ISampler CreateSampler(SamplerCreateInfo info)
@@ -202,9 +202,9 @@ namespace Ryujinx.Graphics.OpenGL
_sync.Dispose(); _sync.Dispose();
} }
public IProgram LoadProgramBinary(byte[] programBinary) public IProgram LoadProgramBinary(byte[] programBinary, bool hasFragmentShader, ShaderInfo info)
{ {
return new Program(programBinary); return new Program(programBinary, hasFragmentShader, info.FragmentOutputMap);
} }
public void CreateSync(ulong id) public void CreateSync(ulong id)

View File

@@ -7,6 +7,7 @@ namespace Ryujinx.Graphics.OpenGL
class Shader : IShader class Shader : IShader
{ {
public int Handle { get; private set; } public int Handle { get; private set; }
public bool IsFragment { get; }
public Shader(ShaderStage stage, string code) public Shader(ShaderStage stage, string code)
{ {
@@ -22,6 +23,7 @@ namespace Ryujinx.Graphics.OpenGL
}; };
Handle = GL.CreateShader(type); Handle = GL.CreateShader(type);
IsFragment = stage == ShaderStage.Fragment;
GL.ShaderSource(Handle, code); GL.ShaderSource(Handle, code);
GL.CompileShader(Handle); GL.CompileShader(Handle);

View File

@@ -5,32 +5,35 @@ namespace Ryujinx.Graphics.Shader
{ {
public class ShaderProgramInfo public class ShaderProgramInfo
{ {
public ReadOnlyCollection<BufferDescriptor> CBuffers { get; } public ReadOnlyCollection<BufferDescriptor> CBuffers { get; }
public ReadOnlyCollection<BufferDescriptor> SBuffers { get; } public ReadOnlyCollection<BufferDescriptor> SBuffers { get; }
public ReadOnlyCollection<TextureDescriptor> Textures { get; } public ReadOnlyCollection<TextureDescriptor> Textures { get; }
public ReadOnlyCollection<TextureDescriptor> Images { get; } public ReadOnlyCollection<TextureDescriptor> Images { get; }
public bool UsesInstanceId { get; } public bool UsesInstanceId { get; }
public bool UsesRtLayer { get; } public bool UsesRtLayer { get; }
public byte ClipDistancesWritten { get; } public byte ClipDistancesWritten { get; }
public int FragmentOutputMap { get; }
public ShaderProgramInfo( public ShaderProgramInfo(
BufferDescriptor[] cBuffers, BufferDescriptor[] cBuffers,
BufferDescriptor[] sBuffers, BufferDescriptor[] sBuffers,
TextureDescriptor[] textures, TextureDescriptor[] textures,
TextureDescriptor[] images, TextureDescriptor[] images,
bool usesInstanceId, bool usesInstanceId,
bool usesRtLayer, bool usesRtLayer,
byte clipDistancesWritten) byte clipDistancesWritten,
int fragmentOutputMap)
{ {
CBuffers = Array.AsReadOnly(cBuffers); CBuffers = Array.AsReadOnly(cBuffers);
SBuffers = Array.AsReadOnly(sBuffers); SBuffers = Array.AsReadOnly(sBuffers);
Textures = Array.AsReadOnly(textures); Textures = Array.AsReadOnly(textures);
Images = Array.AsReadOnly(images); Images = Array.AsReadOnly(images);
UsesInstanceId = usesInstanceId; UsesInstanceId = usesInstanceId;
UsesRtLayer = usesRtLayer; UsesRtLayer = usesRtLayer;
ClipDistancesWritten = clipDistancesWritten; ClipDistancesWritten = clipDistancesWritten;
FragmentOutputMap = fragmentOutputMap;
} }
} }
} }

View File

@@ -172,11 +172,10 @@ namespace Ryujinx.Graphics.Shader.Translation
for (int rtIndex = 0; rtIndex < 8; rtIndex++) for (int rtIndex = 0; rtIndex < 8; rtIndex++)
{ {
OmapTarget target = Config.OmapTargets[rtIndex];
for (int component = 0; component < 4; component++) for (int component = 0; component < 4; component++)
{ {
if (!target.ComponentEnabled(component)) bool componentEnabled = (Config.OmapTargets & (1 << (rtIndex * 4 + component))) != 0;
if (!componentEnabled)
{ {
continue; continue;
} }
@@ -210,7 +209,8 @@ namespace Ryujinx.Graphics.Shader.Translation
} }
} }
if (target.Enabled) bool targetEnabled = (Config.OmapTargets & (0xf << (rtIndex * 4))) != 0;
if (targetEnabled)
{ {
Config.SetOutputUserAttribute(rtIndex, perPatch: false); Config.SetOutputUserAttribute(rtIndex, perPatch: false);
regIndexBase += 4; regIndexBase += 4;

View File

@@ -25,9 +25,9 @@ namespace Ryujinx.Graphics.Shader.Translation
public ImapPixelType[] ImapTypes { get; } public ImapPixelType[] ImapTypes { get; }
public OmapTarget[] OmapTargets { get; } public int OmapTargets { get; }
public bool OmapSampleMask { get; } public bool OmapSampleMask { get; }
public bool OmapDepth { get; } public bool OmapDepth { get; }
public IGpuAccessor GpuAccessor { get; } public IGpuAccessor GpuAccessor { get; }
@@ -135,21 +135,8 @@ namespace Ryujinx.Graphics.Shader.Translation
public int GetDepthRegister() public int GetDepthRegister()
{ {
int count = 0;
for (int index = 0; index < OmapTargets.Length; index++)
{
for (int component = 0; component < 4; component++)
{
if (OmapTargets[index].ComponentEnabled(component))
{
count++;
}
}
}
// The depth register is always two registers after the last color output. // The depth register is always two registers after the last color output.
return count + 1; return BitOperations.PopCount((uint)OmapTargets) + 1;
} }
public TextureFormat GetTextureFormat(int handle, int cbufSlot = -1) public TextureFormat GetTextureFormat(int handle, int cbufSlot = -1)

View File

@@ -36,37 +36,6 @@ namespace Ryujinx.Graphics.Shader.Translation
} }
} }
struct OmapTarget
{
public bool Red { get; }
public bool Green { get; }
public bool Blue { get; }
public bool Alpha { get; }
public bool Enabled => Red || Green || Blue || Alpha;
public OmapTarget(bool red, bool green, bool blue, bool alpha)
{
Red = red;
Green = green;
Blue = blue;
Alpha = alpha;
}
public bool ComponentEnabled(int component)
{
switch (component)
{
case 0: return Red;
case 1: return Green;
case 2: return Blue;
case 3: return Alpha;
}
throw new ArgumentOutOfRangeException(nameof(component));
}
}
class ShaderHeader class ShaderHeader
{ {
public int SphType { get; } public int SphType { get; }
@@ -85,7 +54,7 @@ namespace Ryujinx.Graphics.Shader.Translation
public bool GpPassthrough { get; } public bool GpPassthrough { get; }
public bool DoesLoadOrStore { get; } public bool DoesLoadOrStore { get; }
public bool DoesFp64 { get; } public bool DoesFp64 { get; }
public int StreamOutMask { get; } public int StreamOutMask { get; }
@@ -104,13 +73,13 @@ namespace Ryujinx.Graphics.Shader.Translation
public int MaxOutputVertexCount { get; } public int MaxOutputVertexCount { get; }
public int StoreReqStart { get; } public int StoreReqStart { get; }
public int StoreReqEnd { get; } public int StoreReqEnd { get; }
public ImapPixelType[] ImapTypes { get; } public ImapPixelType[] ImapTypes { get; }
public OmapTarget[] OmapTargets { get; } public int OmapTargets { get; }
public bool OmapSampleMask { get; } public bool OmapSampleMask { get; }
public bool OmapDepth { get; } public bool OmapDepth { get; }
public ShaderHeader(IGpuAccessor gpuAccessor, ulong address) public ShaderHeader(IGpuAccessor gpuAccessor, ulong address)
{ {
@@ -144,7 +113,7 @@ namespace Ryujinx.Graphics.Shader.Translation
GpPassthrough = commonWord0.Extract(24); GpPassthrough = commonWord0.Extract(24);
DoesLoadOrStore = commonWord0.Extract(26); DoesLoadOrStore = commonWord0.Extract(26);
DoesFp64 = commonWord0.Extract(27); DoesFp64 = commonWord0.Extract(27);
StreamOutMask = commonWord0.Extract(28, 4); StreamOutMask = commonWord0.Extract(28, 4);
@@ -163,7 +132,7 @@ namespace Ryujinx.Graphics.Shader.Translation
MaxOutputVertexCount = commonWord4.Extract(0, 12); MaxOutputVertexCount = commonWord4.Extract(0, 12);
StoreReqStart = commonWord4.Extract(12, 8); StoreReqStart = commonWord4.Extract(12, 8);
StoreReqEnd = commonWord4.Extract(24, 8); StoreReqEnd = commonWord4.Extract(24, 8);
ImapTypes = new ImapPixelType[32]; ImapTypes = new ImapPixelType[32];
@@ -179,21 +148,11 @@ namespace Ryujinx.Graphics.Shader.Translation
} }
int type2OmapTarget = header[18]; int type2OmapTarget = header[18];
int type2Omap = header[19]; int type2Omap = header[19];
OmapTargets = new OmapTarget[8];
for (int offset = 0; offset < OmapTargets.Length * 4; offset += 4)
{
OmapTargets[offset >> 2] = new OmapTarget(
type2OmapTarget.Extract(offset + 0),
type2OmapTarget.Extract(offset + 1),
type2OmapTarget.Extract(offset + 2),
type2OmapTarget.Extract(offset + 3));
}
OmapTargets = type2OmapTarget;
OmapSampleMask = type2Omap.Extract(0); OmapSampleMask = type2Omap.Extract(0);
OmapDepth = type2Omap.Extract(1); OmapDepth = type2Omap.Extract(1);
} }
} }
} }

View File

@@ -105,7 +105,8 @@ namespace Ryujinx.Graphics.Shader.Translation
config.GetImageDescriptors(), config.GetImageDescriptors(),
config.UsedFeatures.HasFlag(FeatureFlags.InstanceId), config.UsedFeatures.HasFlag(FeatureFlags.InstanceId),
config.UsedFeatures.HasFlag(FeatureFlags.RtLayer), config.UsedFeatures.HasFlag(FeatureFlags.RtLayer),
config.ClipDistancesWritten); config.ClipDistancesWritten,
config.OmapTargets);
return program; return program;
} }

View File

@@ -102,7 +102,7 @@ namespace Ryujinx.HLE.FileSystem.Content
_contentDictionary = new SortedDictionary<(ulong, NcaContentType), string>(); _contentDictionary = new SortedDictionary<(ulong, NcaContentType), string>();
_locationEntries = new Dictionary<StorageId, LinkedList<LocationEntry>>(); _locationEntries = new Dictionary<StorageId, LinkedList<LocationEntry>>();
foreach (StorageId storageId in Enum.GetValues(typeof(StorageId))) foreach (StorageId storageId in Enum.GetValues<StorageId>())
{ {
string contentDirectory = null; string contentDirectory = null;
string contentPathString = null; string contentPathString = null;

View File

@@ -433,7 +433,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
generator.Emit(OpCodes.Ret); generator.Emit(OpCodes.Ret);
return (Action<T, ExecutionContext>)method.CreateDelegate(typeof(Action<T, ExecutionContext>)); return method.CreateDelegate<Action<T, ExecutionContext>>();
} }
private static void CheckIfTypeIsSupported(Type type, string svcName) private static void CheckIfTypeIsSupported(Type type, string svcName)

View File

@@ -1021,7 +1021,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid
HidVibrationDeviceType vibrationDeviceType = HidVibrationDeviceType.None; HidVibrationDeviceType vibrationDeviceType = HidVibrationDeviceType.None;
if (Enum.IsDefined(typeof(NpadStyleIndex), deviceType)) if (Enum.IsDefined<NpadStyleIndex>(deviceType))
{ {
vibrationDeviceType = HidVibrationDeviceType.LinearResonantActuator; vibrationDeviceType = HidVibrationDeviceType.LinearResonantActuator;
} }

View File

@@ -60,7 +60,7 @@ namespace Ryujinx.HLE.HOS.SystemState
SystemLanguage.TraditionalChinese => TitleLanguage.Taiwanese, SystemLanguage.TraditionalChinese => TitleLanguage.Taiwanese,
SystemLanguage.Chinese or SystemLanguage.Chinese or
SystemLanguage.SimplifiedChinese => TitleLanguage.Chinese, SystemLanguage.SimplifiedChinese => TitleLanguage.Chinese,
_ => Enum.Parse<TitleLanguage>(Enum.GetName(typeof(SystemLanguage), language)), _ => Enum.Parse<TitleLanguage>(Enum.GetName<SystemLanguage>(language)),
}; };
} }

View File

@@ -391,24 +391,29 @@ namespace Ryujinx.Input.HLE
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
private static JoystickPosition ApplyDeadzone(float x, float y, float deadzone) private static JoystickPosition ApplyDeadzone(float x, float y, float deadzone)
{ {
return new JoystickPosition float magnitudeClamped = Math.Min(MathF.Sqrt(x * x + y * y), 1f);
if (magnitudeClamped <= deadzone)
{ {
Dx = ClampAxis(MathF.Abs(x) > deadzone ? x : 0.0f), return new JoystickPosition() {Dx = 0, Dy = 0};
Dy = ClampAxis(MathF.Abs(y) > deadzone ? y : 0.0f) }
return new JoystickPosition()
{
Dx = ClampAxis((x / magnitudeClamped) * ((magnitudeClamped - deadzone) / (1 - deadzone))),
Dy = ClampAxis((y / magnitudeClamped) * ((magnitudeClamped - deadzone) / (1 - deadzone)))
}; };
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
private static short ClampAxis(float value) private static short ClampAxis(float value)
{ {
if (value <= -short.MaxValue) if (Math.Sign(value) < 0)
{ {
return -short.MaxValue; return (short)Math.Max(value * -short.MinValue, short.MinValue);
}
else
{
return (short)(value * short.MaxValue);
} }
return (short)Math.Min(value * short.MaxValue, short.MaxValue);
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]

View File

@@ -27,8 +27,8 @@ namespace Ryujinx.Input.Motion.CemuHook
private readonly Dictionary<int, Dictionary<int, MotionInput>> _motionData; private readonly Dictionary<int, Dictionary<int, MotionInput>> _motionData;
private readonly Dictionary<int, UdpClient> _clients; private readonly Dictionary<int, UdpClient> _clients;
private readonly bool[] _clientErrorStatus = new bool[Enum.GetValues(typeof(PlayerIndex)).Length]; private readonly bool[] _clientErrorStatus = new bool[Enum.GetValues<PlayerIndex>().Length];
private readonly long[] _clientRetryTimer = new long[Enum.GetValues(typeof(PlayerIndex)).Length]; private readonly long[] _clientRetryTimer = new long[Enum.GetValues<PlayerIndex>().Length];
private NpadManager _npadManager; private NpadManager _npadManager;
public Client(NpadManager npadManager) public Client(NpadManager npadManager)

View File

@@ -58,7 +58,7 @@ namespace Ryujinx.Configuration
{ {
bool noFilter = e.NewValue.Length == 0; bool noFilter = e.NewValue.Length == 0;
foreach (var logClass in EnumExtensions.GetValues<LogClass>()) foreach (var logClass in Enum.GetValues<LogClass>())
{ {
Logger.SetEnable(logClass, noFilter); Logger.SetEnable(logClass, noFilter);
} }

View File

@@ -150,7 +150,7 @@ namespace Ryujinx.Input.GTK3
static GTK3MappingHelper() static GTK3MappingHelper()
{ {
var inputKeys = Enum.GetValues(typeof(Key)); var inputKeys = Enum.GetValues<Key>();
// GtkKey is not contiguous and quite large, so use a dictionary instead of an array. // GtkKey is not contiguous and quite large, so use a dictionary instead of an array.
_gtkKeyMapping = new Dictionary<GtkKey, Key>(); _gtkKeyMapping = new Dictionary<GtkKey, Key>();

View File

@@ -9,6 +9,8 @@
<TieredCompilation>false</TieredCompilation> <TieredCompilation>false</TieredCompilation>
<TieredCompilationQuickJit>false</TieredCompilationQuickJit> <TieredCompilationQuickJit>false</TieredCompilationQuickJit>
<DefineConstants Condition=" '$(ExtraDefineConstants)' != '' ">$(DefineConstants);$(ExtraDefineConstants)</DefineConstants> <DefineConstants Condition=" '$(ExtraDefineConstants)' != '' ">$(DefineConstants);$(ExtraDefineConstants)</DefineConstants>
<!-- As we already provide GTK3 on Windows via GtkSharp.Dependencies this is redundant. -->
<SkipGtkInstall>true</SkipGtkInstall>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(RuntimeIdentifier)' != ''"> <PropertyGroup Condition="'$(RuntimeIdentifier)' != ''">
@@ -19,7 +21,7 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="DiscordRichPresence" Version="1.0.175" /> <PackageReference Include="DiscordRichPresence" Version="1.0.175" />
<PackageReference Include="GtkSharp" Version="3.22.25.128" /> <PackageReference Include="GtkSharp" Version="3.22.25.128" />
<PackageReference Include="GtkSharp.Dependencies" Version="1.1.0" Condition="'$(RuntimeIdentifier)' != 'linux-x64' AND '$(RuntimeIdentifier)' != 'osx-x64'" /> <PackageReference Include="GtkSharp.Dependencies" Version="1.1.1" Condition="'$(RuntimeIdentifier)' != 'linux-x64' AND '$(RuntimeIdentifier)' != 'osx-x64'" />
<PackageReference Include="Ryujinx.Graphics.Nvdec.Dependencies" Version="4.4.0-build9" Condition="'$(RuntimeIdentifier)' != 'linux-x64' AND '$(RuntimeIdentifier)' != 'osx-x64'" /> <PackageReference Include="Ryujinx.Graphics.Nvdec.Dependencies" Version="4.4.0-build9" Condition="'$(RuntimeIdentifier)' != 'linux-x64' AND '$(RuntimeIdentifier)' != 'osx-x64'" />
<PackageReference Include="Ryujinx.Audio.OpenAL.Dependencies" Version="1.21.0.1" Condition="'$(RuntimeIdentifier)' != 'linux-x64' AND '$(RuntimeIdentifier)' != 'osx-x64'" /> <PackageReference Include="Ryujinx.Audio.OpenAL.Dependencies" Version="1.21.0.1" Condition="'$(RuntimeIdentifier)' != 'linux-x64' AND '$(RuntimeIdentifier)' != 'osx-x64'" />
<PackageReference Include="OpenTK.Graphics" Version="4.5.0" /> <PackageReference Include="OpenTK.Graphics" Version="4.5.0" />

View File

@@ -1209,7 +1209,7 @@ namespace Ryujinx.Ui
{ {
AspectRatio aspectRatio = ConfigurationState.Instance.Graphics.AspectRatio.Value; AspectRatio aspectRatio = ConfigurationState.Instance.Graphics.AspectRatio.Value;
ConfigurationState.Instance.Graphics.AspectRatio.Value = ((int)aspectRatio + 1) > Enum.GetNames(typeof(AspectRatio)).Length - 1 ? AspectRatio.Fixed4x3 : aspectRatio + 1; ConfigurationState.Instance.Graphics.AspectRatio.Value = ((int)aspectRatio + 1) > Enum.GetNames<AspectRatio>().Length - 1 ? AspectRatio.Fixed4x3 : aspectRatio + 1;
} }
private void Row_Clicked(object sender, ButtonReleaseEventArgs args) private void Row_Clicked(object sender, ButtonReleaseEventArgs args)

View File

@@ -181,7 +181,7 @@ namespace Ryujinx.Ui.Windows
_fsAccessLogToggle.Click(); _fsAccessLogToggle.Click();
} }
foreach (GraphicsDebugLevel level in Enum.GetValues(typeof(GraphicsDebugLevel))) foreach (GraphicsDebugLevel level in Enum.GetValues<GraphicsDebugLevel>())
{ {
_graphicsDebugLevel.Append(level.ToString(), level.ToString()); _graphicsDebugLevel.Append(level.ToString(), level.ToString());
} }