Compare commits
32 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
c6f1908e0f | ||
|
851d81d24a | ||
|
459c4caeba | ||
|
539b22ef7b | ||
|
872f036d64 | ||
|
dca96122bf | ||
|
e752959109 | ||
|
cf01664698 | ||
|
b283a4adcd | ||
|
8428bb6541 | ||
|
9a0330f7f8 | ||
|
57fc996337 | ||
|
1f3b860f06 | ||
|
abe3c02ab4 | ||
|
45b417b2b4 | ||
|
d076339e3e | ||
|
837836431d | ||
|
9f555db5cd | ||
|
bf7fa60dfc | ||
|
752b93d3b7 | ||
|
f23b2878cc | ||
|
e211c3f00a | ||
|
d3709a753f | ||
|
ab676d58ea | ||
|
2372c194f1 | ||
|
40311310d1 | ||
|
dde9bb5c69 | ||
|
266338a7c9 | ||
|
90156eea4c | ||
|
071c01c235 | ||
|
de06ffb0f7 | ||
|
8a7de35e3f |
1
.github/workflows/release.yml
vendored
1
.github/workflows/release.yml
vendored
@@ -11,6 +11,7 @@ on:
|
|||||||
- '*.yml'
|
- '*.yml'
|
||||||
- 'README.md'
|
- 'README.md'
|
||||||
|
|
||||||
|
concurrency: release
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
release:
|
release:
|
||||||
|
@@ -1341,7 +1341,7 @@ namespace ARMeilleure.Decoders
|
|||||||
{
|
{
|
||||||
string reversedEncoding = encoding.Substring(16) + encoding.Substring(0, 16);
|
string reversedEncoding = encoding.Substring(16) + encoding.Substring(0, 16);
|
||||||
MakeOp reversedMakeOp =
|
MakeOp reversedMakeOp =
|
||||||
(InstDescriptor inst, ulong address, int opCode)
|
(inst, address, opCode)
|
||||||
=> makeOp(inst, address, (int)BitOperations.RotateRight((uint)opCode, 16));
|
=> makeOp(inst, address, (int)BitOperations.RotateRight((uint)opCode, 16));
|
||||||
Set(reversedEncoding, AllInstT32, new InstDescriptor(name, emitter), reversedMakeOp);
|
Set(reversedEncoding, AllInstT32, new InstDescriptor(name, emitter), reversedMakeOp);
|
||||||
}
|
}
|
||||||
|
@@ -48,6 +48,11 @@ namespace Ryujinx.Audio.Renderer.Common
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Effect to capture mixes (via auxiliary buffers).
|
/// Effect to capture mixes (via auxiliary buffers).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
CaptureBuffer
|
CaptureBuffer,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Effect applying a compressor filter (DRC).
|
||||||
|
/// </summary>
|
||||||
|
Compressor,
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -14,6 +14,7 @@ namespace Ryujinx.Audio.Renderer.Common
|
|||||||
Reverb3d,
|
Reverb3d,
|
||||||
PcmFloat,
|
PcmFloat,
|
||||||
Limiter,
|
Limiter,
|
||||||
CaptureBuffer
|
CaptureBuffer,
|
||||||
|
Compressor
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -31,6 +31,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
|||||||
LimiterVersion1,
|
LimiterVersion1,
|
||||||
LimiterVersion2,
|
LimiterVersion2,
|
||||||
GroupedBiquadFilter,
|
GroupedBiquadFilter,
|
||||||
CaptureBuffer
|
CaptureBuffer,
|
||||||
|
Compressor
|
||||||
}
|
}
|
||||||
}
|
}
|
173
Ryujinx.Audio/Renderer/Dsp/Command/CompressorCommand.cs
Normal file
173
Ryujinx.Audio/Renderer/Dsp/Command/CompressorCommand.cs
Normal file
@@ -0,0 +1,173 @@
|
|||||||
|
using System;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using Ryujinx.Audio.Renderer.Dsp.Effect;
|
||||||
|
using Ryujinx.Audio.Renderer.Dsp.State;
|
||||||
|
using Ryujinx.Audio.Renderer.Parameter.Effect;
|
||||||
|
|
||||||
|
namespace Ryujinx.Audio.Renderer.Dsp.Command
|
||||||
|
{
|
||||||
|
public class CompressorCommand : ICommand
|
||||||
|
{
|
||||||
|
private const int FixedPointPrecision = 15;
|
||||||
|
|
||||||
|
public bool Enabled { get; set; }
|
||||||
|
|
||||||
|
public int NodeId { get; }
|
||||||
|
|
||||||
|
public CommandType CommandType => CommandType.Compressor;
|
||||||
|
|
||||||
|
public uint EstimatedProcessingTime { get; set; }
|
||||||
|
|
||||||
|
public CompressorParameter Parameter => _parameter;
|
||||||
|
public Memory<CompressorState> State { get; }
|
||||||
|
public ushort[] OutputBufferIndices { get; }
|
||||||
|
public ushort[] InputBufferIndices { get; }
|
||||||
|
public bool IsEffectEnabled { get; }
|
||||||
|
|
||||||
|
private CompressorParameter _parameter;
|
||||||
|
|
||||||
|
public CompressorCommand(uint bufferOffset, CompressorParameter parameter, Memory<CompressorState> state, bool isEnabled, int nodeId)
|
||||||
|
{
|
||||||
|
Enabled = true;
|
||||||
|
NodeId = nodeId;
|
||||||
|
_parameter = parameter;
|
||||||
|
State = state;
|
||||||
|
|
||||||
|
IsEffectEnabled = isEnabled;
|
||||||
|
|
||||||
|
InputBufferIndices = new ushort[Constants.VoiceChannelCountMax];
|
||||||
|
OutputBufferIndices = new ushort[Constants.VoiceChannelCountMax];
|
||||||
|
|
||||||
|
for (int i = 0; i < _parameter.ChannelCount; i++)
|
||||||
|
{
|
||||||
|
InputBufferIndices[i] = (ushort)(bufferOffset + _parameter.Input[i]);
|
||||||
|
OutputBufferIndices[i] = (ushort)(bufferOffset + _parameter.Output[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Process(CommandList context)
|
||||||
|
{
|
||||||
|
ref CompressorState state = ref State.Span[0];
|
||||||
|
|
||||||
|
if (IsEffectEnabled)
|
||||||
|
{
|
||||||
|
if (_parameter.Status == Server.Effect.UsageState.Invalid)
|
||||||
|
{
|
||||||
|
state = new CompressorState(ref _parameter);
|
||||||
|
}
|
||||||
|
else if (_parameter.Status == Server.Effect.UsageState.New)
|
||||||
|
{
|
||||||
|
state.UpdateParameter(ref _parameter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ProcessCompressor(context, ref state);
|
||||||
|
}
|
||||||
|
|
||||||
|
private unsafe void ProcessCompressor(CommandList context, ref CompressorState state)
|
||||||
|
{
|
||||||
|
Debug.Assert(_parameter.IsChannelCountValid());
|
||||||
|
|
||||||
|
if (IsEffectEnabled && _parameter.IsChannelCountValid())
|
||||||
|
{
|
||||||
|
Span<IntPtr> inputBuffers = stackalloc IntPtr[Parameter.ChannelCount];
|
||||||
|
Span<IntPtr> outputBuffers = stackalloc IntPtr[Parameter.ChannelCount];
|
||||||
|
Span<float> channelInput = stackalloc float[Parameter.ChannelCount];
|
||||||
|
ExponentialMovingAverage inputMovingAverage = state.InputMovingAverage;
|
||||||
|
float unknown4 = state.Unknown4;
|
||||||
|
ExponentialMovingAverage compressionGainAverage = state.CompressionGainAverage;
|
||||||
|
float previousCompressionEmaAlpha = state.PreviousCompressionEmaAlpha;
|
||||||
|
|
||||||
|
for (int i = 0; i < _parameter.ChannelCount; i++)
|
||||||
|
{
|
||||||
|
inputBuffers[i] = context.GetBufferPointer(InputBufferIndices[i]);
|
||||||
|
outputBuffers[i] = context.GetBufferPointer(OutputBufferIndices[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int sampleIndex = 0; sampleIndex < context.SampleCount; sampleIndex++)
|
||||||
|
{
|
||||||
|
for (int channelIndex = 0; channelIndex < _parameter.ChannelCount; channelIndex++)
|
||||||
|
{
|
||||||
|
channelInput[channelIndex] = *((float*)inputBuffers[channelIndex] + sampleIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
float newMean = inputMovingAverage.Update(FloatingPointHelper.MeanSquare(channelInput), _parameter.InputGain);
|
||||||
|
float y = FloatingPointHelper.Log10(newMean) * 10.0f;
|
||||||
|
float z = 0.0f;
|
||||||
|
|
||||||
|
bool unknown10OutOfRange = false;
|
||||||
|
|
||||||
|
if (newMean < 1.0e-10f)
|
||||||
|
{
|
||||||
|
z = 1.0f;
|
||||||
|
|
||||||
|
unknown10OutOfRange = state.Unknown10 < -100.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (y >= state.Unknown10 || unknown10OutOfRange)
|
||||||
|
{
|
||||||
|
float tmpGain;
|
||||||
|
|
||||||
|
if (y >= state.Unknown14)
|
||||||
|
{
|
||||||
|
tmpGain = ((1.0f / Parameter.Ratio) - 1.0f) * (y - Parameter.Threshold);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
tmpGain = (y - state.Unknown10) * ((y - state.Unknown10) * -state.CompressorGainReduction);
|
||||||
|
}
|
||||||
|
|
||||||
|
z = FloatingPointHelper.DecibelToLinearExtended(tmpGain);
|
||||||
|
}
|
||||||
|
|
||||||
|
float unknown4New = z;
|
||||||
|
float compressionEmaAlpha;
|
||||||
|
|
||||||
|
if ((unknown4 - z) <= 0.08f)
|
||||||
|
{
|
||||||
|
compressionEmaAlpha = Parameter.ReleaseCoefficient;
|
||||||
|
|
||||||
|
if ((unknown4 - z) >= -0.08f)
|
||||||
|
{
|
||||||
|
if (MathF.Abs(compressionGainAverage.Read() - z) >= 0.001f)
|
||||||
|
{
|
||||||
|
unknown4New = unknown4;
|
||||||
|
}
|
||||||
|
|
||||||
|
compressionEmaAlpha = previousCompressionEmaAlpha;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
compressionEmaAlpha = Parameter.AttackCoefficient;
|
||||||
|
}
|
||||||
|
|
||||||
|
float compressionGain = compressionGainAverage.Update(z, compressionEmaAlpha);
|
||||||
|
|
||||||
|
for (int channelIndex = 0; channelIndex < Parameter.ChannelCount; channelIndex++)
|
||||||
|
{
|
||||||
|
*((float*)outputBuffers[channelIndex] + sampleIndex) = channelInput[channelIndex] * compressionGain * state.OutputGain;
|
||||||
|
}
|
||||||
|
|
||||||
|
unknown4 = unknown4New;
|
||||||
|
previousCompressionEmaAlpha = compressionEmaAlpha;
|
||||||
|
}
|
||||||
|
|
||||||
|
state.InputMovingAverage = inputMovingAverage;
|
||||||
|
state.Unknown4 = unknown4;
|
||||||
|
state.CompressionGainAverage = compressionGainAverage;
|
||||||
|
state.PreviousCompressionEmaAlpha = previousCompressionEmaAlpha;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (int i = 0; i < Parameter.ChannelCount; i++)
|
||||||
|
{
|
||||||
|
if (InputBufferIndices[i] != OutputBufferIndices[i])
|
||||||
|
{
|
||||||
|
context.CopyBuffer(OutputBufferIndices[i], InputBufferIndices[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -90,32 +90,31 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
|||||||
|
|
||||||
float inputCoefficient = Parameter.ReleaseCoefficient;
|
float inputCoefficient = Parameter.ReleaseCoefficient;
|
||||||
|
|
||||||
if (sampleInputMax > state.DectectorAverage[channelIndex])
|
if (sampleInputMax > state.DetectorAverage[channelIndex].Read())
|
||||||
{
|
{
|
||||||
inputCoefficient = Parameter.AttackCoefficient;
|
inputCoefficient = Parameter.AttackCoefficient;
|
||||||
}
|
}
|
||||||
|
|
||||||
state.DectectorAverage[channelIndex] += inputCoefficient * (sampleInputMax - state.DectectorAverage[channelIndex]);
|
float detectorValue = state.DetectorAverage[channelIndex].Update(sampleInputMax, inputCoefficient);
|
||||||
|
|
||||||
float attenuation = 1.0f;
|
float attenuation = 1.0f;
|
||||||
|
|
||||||
if (state.DectectorAverage[channelIndex] > Parameter.Threshold)
|
if (detectorValue > Parameter.Threshold)
|
||||||
{
|
{
|
||||||
attenuation = Parameter.Threshold / state.DectectorAverage[channelIndex];
|
attenuation = Parameter.Threshold / detectorValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
float outputCoefficient = Parameter.ReleaseCoefficient;
|
float outputCoefficient = Parameter.ReleaseCoefficient;
|
||||||
|
|
||||||
if (state.CompressionGain[channelIndex] > attenuation)
|
if (state.CompressionGainAverage[channelIndex].Read() > attenuation)
|
||||||
{
|
{
|
||||||
outputCoefficient = Parameter.AttackCoefficient;
|
outputCoefficient = Parameter.AttackCoefficient;
|
||||||
}
|
}
|
||||||
|
|
||||||
state.CompressionGain[channelIndex] += outputCoefficient * (attenuation - state.CompressionGain[channelIndex]);
|
float compressionGain = state.CompressionGainAverage[channelIndex].Update(attenuation, outputCoefficient);
|
||||||
|
|
||||||
ref float delayedSample = ref state.DelayedSampleBuffer[channelIndex * Parameter.DelayBufferSampleCountMax + state.DelayedSampleBufferPosition[channelIndex]];
|
ref float delayedSample = ref state.DelayedSampleBuffer[channelIndex * Parameter.DelayBufferSampleCountMax + state.DelayedSampleBufferPosition[channelIndex]];
|
||||||
|
|
||||||
float outputSample = delayedSample * state.CompressionGain[channelIndex] * Parameter.OutputGain;
|
float outputSample = delayedSample * compressionGain * Parameter.OutputGain;
|
||||||
|
|
||||||
*((float*)outputBuffers[channelIndex] + sampleIndex) = outputSample * short.MaxValue;
|
*((float*)outputBuffers[channelIndex] + sampleIndex) = outputSample * short.MaxValue;
|
||||||
|
|
||||||
|
@@ -101,32 +101,31 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
|||||||
|
|
||||||
float inputCoefficient = Parameter.ReleaseCoefficient;
|
float inputCoefficient = Parameter.ReleaseCoefficient;
|
||||||
|
|
||||||
if (sampleInputMax > state.DectectorAverage[channelIndex])
|
if (sampleInputMax > state.DetectorAverage[channelIndex].Read())
|
||||||
{
|
{
|
||||||
inputCoefficient = Parameter.AttackCoefficient;
|
inputCoefficient = Parameter.AttackCoefficient;
|
||||||
}
|
}
|
||||||
|
|
||||||
state.DectectorAverage[channelIndex] += inputCoefficient * (sampleInputMax - state.DectectorAverage[channelIndex]);
|
float detectorValue = state.DetectorAverage[channelIndex].Update(sampleInputMax, inputCoefficient);
|
||||||
|
|
||||||
float attenuation = 1.0f;
|
float attenuation = 1.0f;
|
||||||
|
|
||||||
if (state.DectectorAverage[channelIndex] > Parameter.Threshold)
|
if (detectorValue > Parameter.Threshold)
|
||||||
{
|
{
|
||||||
attenuation = Parameter.Threshold / state.DectectorAverage[channelIndex];
|
attenuation = Parameter.Threshold / detectorValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
float outputCoefficient = Parameter.ReleaseCoefficient;
|
float outputCoefficient = Parameter.ReleaseCoefficient;
|
||||||
|
|
||||||
if (state.CompressionGain[channelIndex] > attenuation)
|
if (state.CompressionGainAverage[channelIndex].Read() > attenuation)
|
||||||
{
|
{
|
||||||
outputCoefficient = Parameter.AttackCoefficient;
|
outputCoefficient = Parameter.AttackCoefficient;
|
||||||
}
|
}
|
||||||
|
|
||||||
state.CompressionGain[channelIndex] += outputCoefficient * (attenuation - state.CompressionGain[channelIndex]);
|
float compressionGain = state.CompressionGainAverage[channelIndex].Update(attenuation, outputCoefficient);
|
||||||
|
|
||||||
ref float delayedSample = ref state.DelayedSampleBuffer[channelIndex * Parameter.DelayBufferSampleCountMax + state.DelayedSampleBufferPosition[channelIndex]];
|
ref float delayedSample = ref state.DelayedSampleBuffer[channelIndex * Parameter.DelayBufferSampleCountMax + state.DelayedSampleBufferPosition[channelIndex]];
|
||||||
|
|
||||||
float outputSample = delayedSample * state.CompressionGain[channelIndex] * Parameter.OutputGain;
|
float outputSample = delayedSample * compressionGain * Parameter.OutputGain;
|
||||||
|
|
||||||
*((float*)outputBuffers[channelIndex] + sampleIndex) = outputSample * short.MaxValue;
|
*((float*)outputBuffers[channelIndex] + sampleIndex) = outputSample * short.MaxValue;
|
||||||
|
|
||||||
@@ -144,7 +143,7 @@ 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);
|
statistics.InputMax[channelIndex] = Math.Max(statistics.InputMax[channelIndex], sampleInputMax);
|
||||||
statistics.CompressionGainMin[channelIndex] = Math.Min(statistics.CompressionGainMin[channelIndex], state.CompressionGain[channelIndex]);
|
statistics.CompressionGainMin[channelIndex] = Math.Min(statistics.CompressionGainMin[channelIndex], compressionGain);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -0,0 +1,26 @@
|
|||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
|
namespace Ryujinx.Audio.Renderer.Dsp.Effect
|
||||||
|
{
|
||||||
|
public struct ExponentialMovingAverage
|
||||||
|
{
|
||||||
|
private float _mean;
|
||||||
|
|
||||||
|
public ExponentialMovingAverage(float mean)
|
||||||
|
{
|
||||||
|
_mean = mean;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float Read()
|
||||||
|
{
|
||||||
|
return _mean;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float Update(float value, float alpha)
|
||||||
|
{
|
||||||
|
_mean += alpha * (value - _mean);
|
||||||
|
|
||||||
|
return _mean;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -16,6 +16,12 @@ namespace Ryujinx.Audio.Renderer.Dsp
|
|||||||
return (float)value / (1 << qBits);
|
return (float)value / (1 << qBits);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static float ConvertFloat(float value, int qBits)
|
||||||
|
{
|
||||||
|
return value / (1 << qBits);
|
||||||
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static int ToFixed(float value, int qBits)
|
public static int ToFixed(float value, int qBits)
|
||||||
{
|
{
|
||||||
|
@@ -1,4 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Reflection.Metadata;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
namespace Ryujinx.Audio.Renderer.Dsp
|
namespace Ryujinx.Audio.Renderer.Dsp
|
||||||
@@ -46,6 +47,53 @@ namespace Ryujinx.Audio.Renderer.Dsp
|
|||||||
return MathF.Pow(10, x);
|
return MathF.Pow(10, x);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static float Log10(float x)
|
||||||
|
{
|
||||||
|
// NOTE: Nintendo uses an approximation of log10, we don't.
|
||||||
|
// As such, we support the same ranges as Nintendo to avoid unexpected behaviours.
|
||||||
|
return MathF.Pow(10, MathF.Max(x, 1.0e-10f));
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static float MeanSquare(ReadOnlySpan<float> inputs)
|
||||||
|
{
|
||||||
|
float res = 0.0f;
|
||||||
|
|
||||||
|
foreach (float input in inputs)
|
||||||
|
{
|
||||||
|
res += (input * input);
|
||||||
|
}
|
||||||
|
|
||||||
|
res /= inputs.Length;
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Map decibel to linear.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="db">The decibel value to convert</param>
|
||||||
|
/// <returns>Converted linear value/returns>
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static float DecibelToLinear(float db)
|
||||||
|
{
|
||||||
|
return MathF.Pow(10.0f, db / 20.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Map decibel to linear in [0, 2] range.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="db">The decibel value to convert</param>
|
||||||
|
/// <returns>Converted linear value in [0, 2] range</returns>
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static float DecibelToLinearExtended(float db)
|
||||||
|
{
|
||||||
|
float tmp = MathF.Log2(DecibelToLinear(db));
|
||||||
|
|
||||||
|
return MathF.Truncate(tmp) + MathF.Pow(2.0f, tmp - MathF.Truncate(tmp));
|
||||||
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static float DegreesToRadians(float degrees)
|
public static float DegreesToRadians(float degrees)
|
||||||
{
|
{
|
||||||
|
51
Ryujinx.Audio/Renderer/Dsp/State/CompressorState.cs
Normal file
51
Ryujinx.Audio/Renderer/Dsp/State/CompressorState.cs
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
using Ryujinx.Audio.Renderer.Dsp.Effect;
|
||||||
|
using Ryujinx.Audio.Renderer.Parameter.Effect;
|
||||||
|
|
||||||
|
namespace Ryujinx.Audio.Renderer.Dsp.State
|
||||||
|
{
|
||||||
|
public class CompressorState
|
||||||
|
{
|
||||||
|
public ExponentialMovingAverage InputMovingAverage;
|
||||||
|
public float Unknown4;
|
||||||
|
public ExponentialMovingAverage CompressionGainAverage;
|
||||||
|
public float CompressorGainReduction;
|
||||||
|
public float Unknown10;
|
||||||
|
public float Unknown14;
|
||||||
|
public float PreviousCompressionEmaAlpha;
|
||||||
|
public float MakeupGain;
|
||||||
|
public float OutputGain;
|
||||||
|
|
||||||
|
public CompressorState(ref CompressorParameter parameter)
|
||||||
|
{
|
||||||
|
InputMovingAverage = new ExponentialMovingAverage(0.0f);
|
||||||
|
Unknown4 = 1.0f;
|
||||||
|
CompressionGainAverage = new ExponentialMovingAverage(1.0f);
|
||||||
|
|
||||||
|
UpdateParameter(ref parameter);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void UpdateParameter(ref CompressorParameter parameter)
|
||||||
|
{
|
||||||
|
float threshold = parameter.Threshold;
|
||||||
|
float ratio = 1.0f / parameter.Ratio;
|
||||||
|
float attackCoefficient = parameter.AttackCoefficient;
|
||||||
|
float makeupGain;
|
||||||
|
|
||||||
|
if (parameter.MakeupGainEnabled)
|
||||||
|
{
|
||||||
|
makeupGain = (threshold * 0.5f * (ratio - 1.0f)) - 3.0f;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
makeupGain = 0.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
PreviousCompressionEmaAlpha = attackCoefficient;
|
||||||
|
MakeupGain = makeupGain;
|
||||||
|
CompressorGainReduction = (1.0f - ratio) / Constants.ChannelCountMax;
|
||||||
|
Unknown10 = threshold - 1.5f;
|
||||||
|
Unknown14 = threshold + 1.5f;
|
||||||
|
OutputGain = FloatingPointHelper.DecibelToLinearExtended(parameter.OutputGain + makeupGain);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -1,3 +1,4 @@
|
|||||||
|
using Ryujinx.Audio.Renderer.Dsp.Effect;
|
||||||
using Ryujinx.Audio.Renderer.Parameter.Effect;
|
using Ryujinx.Audio.Renderer.Parameter.Effect;
|
||||||
using System;
|
using System;
|
||||||
|
|
||||||
@@ -5,20 +6,20 @@ namespace Ryujinx.Audio.Renderer.Dsp.State
|
|||||||
{
|
{
|
||||||
public class LimiterState
|
public class LimiterState
|
||||||
{
|
{
|
||||||
public float[] DectectorAverage;
|
public ExponentialMovingAverage[] DetectorAverage;
|
||||||
public float[] CompressionGain;
|
public ExponentialMovingAverage[] CompressionGainAverage;
|
||||||
public float[] DelayedSampleBuffer;
|
public float[] DelayedSampleBuffer;
|
||||||
public int[] DelayedSampleBufferPosition;
|
public int[] DelayedSampleBufferPosition;
|
||||||
|
|
||||||
public LimiterState(ref LimiterParameter parameter, ulong workBuffer)
|
public LimiterState(ref LimiterParameter parameter, ulong workBuffer)
|
||||||
{
|
{
|
||||||
DectectorAverage = new float[parameter.ChannelCount];
|
DetectorAverage = new ExponentialMovingAverage[parameter.ChannelCount];
|
||||||
CompressionGain = new float[parameter.ChannelCount];
|
CompressionGainAverage = new ExponentialMovingAverage[parameter.ChannelCount];
|
||||||
DelayedSampleBuffer = new float[parameter.ChannelCount * parameter.DelayBufferSampleCountMax];
|
DelayedSampleBuffer = new float[parameter.ChannelCount * parameter.DelayBufferSampleCountMax];
|
||||||
DelayedSampleBufferPosition = new int[parameter.ChannelCount];
|
DelayedSampleBufferPosition = new int[parameter.ChannelCount];
|
||||||
|
|
||||||
DectectorAverage.AsSpan().Fill(0.0f);
|
DetectorAverage.AsSpan().Fill(new ExponentialMovingAverage(0.0f));
|
||||||
CompressionGain.AsSpan().Fill(1.0f);
|
CompressionGainAverage.AsSpan().Fill(new ExponentialMovingAverage(1.0f));
|
||||||
DelayedSampleBufferPosition.AsSpan().Fill(0);
|
DelayedSampleBufferPosition.AsSpan().Fill(0);
|
||||||
DelayedSampleBuffer.AsSpan().Fill(0.0f);
|
DelayedSampleBuffer.AsSpan().Fill(0.0f);
|
||||||
|
|
||||||
|
115
Ryujinx.Audio/Renderer/Parameter/Effect/CompressorParameter.cs
Normal file
115
Ryujinx.Audio/Renderer/Parameter/Effect/CompressorParameter.cs
Normal file
@@ -0,0 +1,115 @@
|
|||||||
|
using Ryujinx.Audio.Renderer.Server.Effect;
|
||||||
|
using Ryujinx.Common.Memory;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
namespace Ryujinx.Audio.Renderer.Parameter.Effect
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// <see cref="IEffectInParameter.SpecificData"/> for <see cref="Common.EffectType.Compressor"/>.
|
||||||
|
/// </summary>
|
||||||
|
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||||
|
public struct CompressorParameter
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The input channel indices that will be used by the <see cref="Dsp.AudioProcessor"/>.
|
||||||
|
/// </summary>
|
||||||
|
public Array6<byte> Input;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The output channel indices that will be used by the <see cref="Dsp.AudioProcessor"/>.
|
||||||
|
/// </summary>
|
||||||
|
public Array6<byte> Output;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The maximum number of channels supported.
|
||||||
|
/// </summary>
|
||||||
|
public ushort ChannelCountMax;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The total channel count used.
|
||||||
|
/// </summary>
|
||||||
|
public ushort ChannelCount;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The target sample rate.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>This is in kHz.</remarks>
|
||||||
|
public int SampleRate;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The threshold.
|
||||||
|
/// </summary>
|
||||||
|
public float Threshold;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The compressor ratio.
|
||||||
|
/// </summary>
|
||||||
|
public float Ratio;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The attack time.
|
||||||
|
/// <remarks>This is in microseconds.</remarks>
|
||||||
|
/// </summary>
|
||||||
|
public int AttackTime;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The release time.
|
||||||
|
/// <remarks>This is in microseconds.</remarks>
|
||||||
|
/// </summary>
|
||||||
|
public int ReleaseTime;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The input gain.
|
||||||
|
/// </summary>
|
||||||
|
public float InputGain;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The attack coefficient.
|
||||||
|
/// </summary>
|
||||||
|
public float AttackCoefficient;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The release coefficient.
|
||||||
|
/// </summary>
|
||||||
|
public float ReleaseCoefficient;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The output gain.
|
||||||
|
/// </summary>
|
||||||
|
public float OutputGain;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The current usage status of the effect on the client side.
|
||||||
|
/// </summary>
|
||||||
|
public UsageState Status;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Indicate if the makeup gain should be used.
|
||||||
|
/// </summary>
|
||||||
|
[MarshalAs(UnmanagedType.I1)]
|
||||||
|
public bool MakeupGainEnabled;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Reserved/padding.
|
||||||
|
/// </summary>
|
||||||
|
private Array2<byte> _reserved;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Check if the <see cref="ChannelCount"/> is valid.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>Returns true if the <see cref="ChannelCount"/> is valid.</returns>
|
||||||
|
public bool IsChannelCountValid()
|
||||||
|
{
|
||||||
|
return EffectInParameterVersion1.IsChannelCountValid(ChannelCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Check if the <see cref="ChannelCountMax"/> is valid.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>Returns true if the <see cref="ChannelCountMax"/> is valid.</returns>
|
||||||
|
public bool IsChannelCountMaxValid()
|
||||||
|
{
|
||||||
|
return EffectInParameterVersion1.IsChannelCountValid(ChannelCountMax);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -93,6 +93,7 @@ namespace Ryujinx.Audio.Renderer.Server
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// REV11:
|
/// REV11:
|
||||||
/// The "legacy" effects (Delay, Reverb and Reverb 3D) were updated to match the standard channel mapping used by the audio renderer.
|
/// The "legacy" effects (Delay, Reverb and Reverb 3D) were updated to match the standard channel mapping used by the audio renderer.
|
||||||
|
/// A new effect was added: Compressor. This effect is effectively implemented with a DRC.
|
||||||
/// A new version of the command estimator was added to address timing changes caused by the legacy effects changes.
|
/// A new version of the command estimator was added to address timing changes caused by the legacy effects changes.
|
||||||
/// A voice drop parameter was added in 15.0.0: This allows an application to amplify or attenuate the estimated time of DSP commands.
|
/// A voice drop parameter was added in 15.0.0: This allows an application to amplify or attenuate the estimated time of DSP commands.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@@ -469,6 +469,18 @@ namespace Ryujinx.Audio.Renderer.Server
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void GenerateCompressorEffect(uint bufferOffset, CompressorParameter parameter, Memory<CompressorState> state, bool isEnabled, int nodeId)
|
||||||
|
{
|
||||||
|
if (parameter.IsChannelCountValid())
|
||||||
|
{
|
||||||
|
CompressorCommand command = new CompressorCommand(bufferOffset, parameter, state, isEnabled, nodeId);
|
||||||
|
|
||||||
|
command.EstimatedProcessingTime = _commandProcessingTimeEstimator.Estimate(command);
|
||||||
|
|
||||||
|
AddCommand(command);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Generate a new <see cref="VolumeCommand"/>.
|
/// Generate a new <see cref="VolumeCommand"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@@ -606,6 +606,17 @@ namespace Ryujinx.Audio.Renderer.Server
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void GenerateCompressorEffect(uint bufferOffset, CompressorEffect effect, int nodeId)
|
||||||
|
{
|
||||||
|
Debug.Assert(effect.Type == EffectType.Compressor);
|
||||||
|
|
||||||
|
_commandBuffer.GenerateCompressorEffect(bufferOffset,
|
||||||
|
effect.Parameter,
|
||||||
|
effect.State,
|
||||||
|
effect.IsEnabled,
|
||||||
|
nodeId);
|
||||||
|
}
|
||||||
|
|
||||||
private void GenerateEffect(ref MixState mix, int effectId, BaseEffect effect)
|
private void GenerateEffect(ref MixState mix, int effectId, BaseEffect effect)
|
||||||
{
|
{
|
||||||
int nodeId = mix.NodeId;
|
int nodeId = mix.NodeId;
|
||||||
@@ -650,6 +661,9 @@ namespace Ryujinx.Audio.Renderer.Server
|
|||||||
case EffectType.CaptureBuffer:
|
case EffectType.CaptureBuffer:
|
||||||
GenerateCaptureEffect(mix.BufferOffset, (CaptureBufferEffect)effect, nodeId);
|
GenerateCaptureEffect(mix.BufferOffset, (CaptureBufferEffect)effect, nodeId);
|
||||||
break;
|
break;
|
||||||
|
case EffectType.Compressor:
|
||||||
|
GenerateCompressorEffect(mix.BufferOffset, (CompressorEffect)effect, nodeId);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
throw new NotImplementedException($"Unsupported effect type {effect.Type}");
|
throw new NotImplementedException($"Unsupported effect type {effect.Type}");
|
||||||
}
|
}
|
||||||
|
@@ -179,5 +179,10 @@ namespace Ryujinx.Audio.Renderer.Server
|
|||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public uint Estimate(CompressorCommand command)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -543,5 +543,10 @@ namespace Ryujinx.Audio.Renderer.Server
|
|||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public uint Estimate(CompressorCommand command)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -747,5 +747,10 @@ namespace Ryujinx.Audio.Renderer.Server
|
|||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public virtual uint Estimate(CompressorCommand command)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -232,5 +232,79 @@ namespace Ryujinx.Audio.Renderer.Server
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override uint Estimate(CompressorCommand command)
|
||||||
|
{
|
||||||
|
Debug.Assert(_sampleCount == 160 || _sampleCount == 240);
|
||||||
|
|
||||||
|
if (_sampleCount == 160)
|
||||||
|
{
|
||||||
|
if (command.Enabled)
|
||||||
|
{
|
||||||
|
switch (command.Parameter.ChannelCount)
|
||||||
|
{
|
||||||
|
case 1:
|
||||||
|
return 34431;
|
||||||
|
case 2:
|
||||||
|
return 44253;
|
||||||
|
case 4:
|
||||||
|
return 63827;
|
||||||
|
case 6:
|
||||||
|
return 83361;
|
||||||
|
default:
|
||||||
|
throw new NotImplementedException($"{command.Parameter.ChannelCount}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
switch (command.Parameter.ChannelCount)
|
||||||
|
{
|
||||||
|
case 1:
|
||||||
|
return (uint)630.12f;
|
||||||
|
case 2:
|
||||||
|
return (uint)638.27f;
|
||||||
|
case 4:
|
||||||
|
return (uint)705.86f;
|
||||||
|
case 6:
|
||||||
|
return (uint)782.02f;
|
||||||
|
default:
|
||||||
|
throw new NotImplementedException($"{command.Parameter.ChannelCount}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (command.Enabled)
|
||||||
|
{
|
||||||
|
switch (command.Parameter.ChannelCount)
|
||||||
|
{
|
||||||
|
case 1:
|
||||||
|
return 51095;
|
||||||
|
case 2:
|
||||||
|
return 65693;
|
||||||
|
case 4:
|
||||||
|
return 95383;
|
||||||
|
case 6:
|
||||||
|
return 124510;
|
||||||
|
default:
|
||||||
|
throw new NotImplementedException($"{command.Parameter.ChannelCount}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
switch (command.Parameter.ChannelCount)
|
||||||
|
{
|
||||||
|
case 1:
|
||||||
|
return (uint)840.14f;
|
||||||
|
case 2:
|
||||||
|
return (uint)826.1f;
|
||||||
|
case 4:
|
||||||
|
return (uint)901.88f;
|
||||||
|
case 6:
|
||||||
|
return (uint)965.29f;
|
||||||
|
default:
|
||||||
|
throw new NotImplementedException($"{command.Parameter.ChannelCount}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -262,6 +262,8 @@ namespace Ryujinx.Audio.Renderer.Server.Effect
|
|||||||
return PerformanceDetailType.Limiter;
|
return PerformanceDetailType.Limiter;
|
||||||
case EffectType.CaptureBuffer:
|
case EffectType.CaptureBuffer:
|
||||||
return PerformanceDetailType.CaptureBuffer;
|
return PerformanceDetailType.CaptureBuffer;
|
||||||
|
case EffectType.Compressor:
|
||||||
|
return PerformanceDetailType.Compressor;
|
||||||
default:
|
default:
|
||||||
throw new NotImplementedException($"{Type}");
|
throw new NotImplementedException($"{Type}");
|
||||||
}
|
}
|
||||||
|
67
Ryujinx.Audio/Renderer/Server/Effect/CompressorEffect.cs
Normal file
67
Ryujinx.Audio/Renderer/Server/Effect/CompressorEffect.cs
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
using Ryujinx.Audio.Renderer.Common;
|
||||||
|
using Ryujinx.Audio.Renderer.Dsp.State;
|
||||||
|
using Ryujinx.Audio.Renderer.Parameter.Effect;
|
||||||
|
using Ryujinx.Audio.Renderer.Parameter;
|
||||||
|
using Ryujinx.Audio.Renderer.Server.MemoryPool;
|
||||||
|
using System;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
namespace Ryujinx.Audio.Renderer.Server.Effect
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Server state for a compressor effect.
|
||||||
|
/// </summary>
|
||||||
|
public class CompressorEffect : BaseEffect
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The compressor parameter.
|
||||||
|
/// </summary>
|
||||||
|
public CompressorParameter Parameter;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The compressor state.
|
||||||
|
/// </summary>
|
||||||
|
public Memory<CompressorState> State { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Create a new <see cref="CompressorEffect"/>.
|
||||||
|
/// </summary>
|
||||||
|
public CompressorEffect()
|
||||||
|
{
|
||||||
|
State = new CompressorState[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
public override EffectType TargetEffectType => EffectType.Compressor;
|
||||||
|
|
||||||
|
public override ulong GetWorkBuffer(int index)
|
||||||
|
{
|
||||||
|
return GetSingleBuffer();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Update(out BehaviourParameter.ErrorInfo updateErrorInfo, ref EffectInParameterVersion1 parameter, PoolMapper mapper)
|
||||||
|
{
|
||||||
|
// Nintendo doesn't do anything here but we still require updateErrorInfo to be initialised.
|
||||||
|
updateErrorInfo = new BehaviourParameter.ErrorInfo();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Update(out BehaviourParameter.ErrorInfo updateErrorInfo, ref EffectInParameterVersion2 parameter, PoolMapper mapper)
|
||||||
|
{
|
||||||
|
Debug.Assert(IsTypeValid(ref parameter));
|
||||||
|
|
||||||
|
UpdateParameterBase(ref parameter);
|
||||||
|
|
||||||
|
Parameter = MemoryMarshal.Cast<byte, CompressorParameter>(parameter.SpecificData)[0];
|
||||||
|
IsEnabled = parameter.IsEnabled;
|
||||||
|
|
||||||
|
updateErrorInfo = new BehaviourParameter.ErrorInfo();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void UpdateForCommandGeneration()
|
||||||
|
{
|
||||||
|
UpdateUsageStateForCommandGeneration();
|
||||||
|
|
||||||
|
Parameter.Status = UsageState.Enabled;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -35,5 +35,6 @@ namespace Ryujinx.Audio.Renderer.Server
|
|||||||
uint Estimate(LimiterCommandVersion2 command);
|
uint Estimate(LimiterCommandVersion2 command);
|
||||||
uint Estimate(GroupedBiquadFilterCommand command);
|
uint Estimate(GroupedBiquadFilterCommand command);
|
||||||
uint Estimate(CaptureBufferCommand command);
|
uint Estimate(CaptureBufferCommand command);
|
||||||
|
uint Estimate(CompressorCommand command);
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -240,6 +240,10 @@ namespace Ryujinx.Audio.Renderer.Server
|
|||||||
case EffectType.CaptureBuffer:
|
case EffectType.CaptureBuffer:
|
||||||
effect = new CaptureBufferEffect();
|
effect = new CaptureBufferEffect();
|
||||||
break;
|
break;
|
||||||
|
case EffectType.Compressor:
|
||||||
|
effect = new CompressorEffect();
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
throw new NotImplementedException($"EffectType {parameter.Type} not implemented!");
|
throw new NotImplementedException($"EffectType {parameter.Type} not implemented!");
|
||||||
}
|
}
|
||||||
|
@@ -125,7 +125,7 @@ namespace Ryujinx.Ava
|
|||||||
_inputManager = inputManager;
|
_inputManager = inputManager;
|
||||||
_accountManager = accountManager;
|
_accountManager = accountManager;
|
||||||
_userChannelPersistence = userChannelPersistence;
|
_userChannelPersistence = userChannelPersistence;
|
||||||
_renderingThread = new Thread(RenderLoop) { Name = "GUI.RenderThread" };
|
_renderingThread = new Thread(RenderLoop, 1 * 1024 * 1024) { Name = "GUI.RenderThread" };
|
||||||
_hideCursorOnIdle = ConfigurationState.Instance.HideCursorOnIdle;
|
_hideCursorOnIdle = ConfigurationState.Instance.HideCursorOnIdle;
|
||||||
_lastCursorMoveTime = Stopwatch.GetTimestamp();
|
_lastCursorMoveTime = Stopwatch.GetTimestamp();
|
||||||
_glLogLevel = ConfigurationState.Instance.Logger.GraphicsDebugLevel;
|
_glLogLevel = ConfigurationState.Instance.Logger.GraphicsDebugLevel;
|
||||||
|
@@ -157,11 +157,10 @@
|
|||||||
"SettingsTabLoggingEnableFsAccessLogs": "Aktiviere Fs Zugriff-Logs",
|
"SettingsTabLoggingEnableFsAccessLogs": "Aktiviere Fs Zugriff-Logs",
|
||||||
"SettingsTabLoggingFsGlobalAccessLogMode": "Fs Globaler Zugriff-Log-Modus:",
|
"SettingsTabLoggingFsGlobalAccessLogMode": "Fs Globaler Zugriff-Log-Modus:",
|
||||||
"SettingsTabLoggingDeveloperOptions": "Entwickleroptionen (WARNUNG: Beeinträchtigt die Leistung)",
|
"SettingsTabLoggingDeveloperOptions": "Entwickleroptionen (WARNUNG: Beeinträchtigt die Leistung)",
|
||||||
"SettingsTabLoggingOpenglLogLevel": "OpenGL Logstufe:",
|
"SettingsTabLoggingGraphicsBackendLogLevelNone": "Keine",
|
||||||
"SettingsTabLoggingOpenglLogLevelNone": "Keine",
|
"SettingsTabLoggingGraphicsBackendLogLevelError": "Fehler",
|
||||||
"SettingsTabLoggingOpenglLogLevelError": "Fehler",
|
"SettingsTabLoggingGraphicsBackendLogLevelPerformance": "Verlangsamungen",
|
||||||
"SettingsTabLoggingOpenglLogLevelPerformance": "Verlangsamungen",
|
"SettingsTabLoggingGraphicsBackendLogLevelAll": "Alle",
|
||||||
"SettingsTabLoggingOpenglLogLevelAll": "Alle",
|
|
||||||
"SettingsTabLoggingEnableDebugLogs": "Aktiviere Debug-Log",
|
"SettingsTabLoggingEnableDebugLogs": "Aktiviere Debug-Log",
|
||||||
"SettingsTabInput": "Eingabe",
|
"SettingsTabInput": "Eingabe",
|
||||||
"SettingsTabInputEnableDockedMode": "Docked Modus",
|
"SettingsTabInputEnableDockedMode": "Docked Modus",
|
||||||
|
@@ -157,11 +157,10 @@
|
|||||||
"SettingsTabLoggingEnableFsAccessLogs": "Ενεργοποίηση Καταγραφής Πρόσβασης FS",
|
"SettingsTabLoggingEnableFsAccessLogs": "Ενεργοποίηση Καταγραφής Πρόσβασης FS",
|
||||||
"SettingsTabLoggingFsGlobalAccessLogMode": "Λειτουργία Καταγραφής Καθολικής Πρόσβασης FS:",
|
"SettingsTabLoggingFsGlobalAccessLogMode": "Λειτουργία Καταγραφής Καθολικής Πρόσβασης FS:",
|
||||||
"SettingsTabLoggingDeveloperOptions": "Επιλογές Προγραμματιστή (ΠΡΟΕΙΔΟΠΟΙΗΣΗ: Η απόδοση Θα μειωθεί)",
|
"SettingsTabLoggingDeveloperOptions": "Επιλογές Προγραμματιστή (ΠΡΟΕΙΔΟΠΟΙΗΣΗ: Η απόδοση Θα μειωθεί)",
|
||||||
"SettingsTabLoggingOpenglLogLevel": "Επίπεδο Καταγραφής OpenGL:",
|
"SettingsTabLoggingGraphicsBackendLogLevelNone": "Κανένα",
|
||||||
"SettingsTabLoggingOpenglLogLevelNone": "Κανένα",
|
"SettingsTabLoggingGraphicsBackendLogLevelError": "Σφάλμα",
|
||||||
"SettingsTabLoggingOpenglLogLevelError": "Σφάλμα",
|
"SettingsTabLoggingGraphicsBackendLogLevelPerformance": "Επιβραδύνσεις",
|
||||||
"SettingsTabLoggingOpenglLogLevelPerformance": "Επιβραδύνσεις",
|
"SettingsTabLoggingGraphicsBackendLogLevelAll": "Όλα",
|
||||||
"SettingsTabLoggingOpenglLogLevelAll": "Όλα",
|
|
||||||
"SettingsTabLoggingEnableDebugLogs": "Ενεργοποίηση Αρχείων Καταγραφής Εντοπισμού Σφαλμάτων",
|
"SettingsTabLoggingEnableDebugLogs": "Ενεργοποίηση Αρχείων Καταγραφής Εντοπισμού Σφαλμάτων",
|
||||||
"SettingsTabInput": "Χειρισμός",
|
"SettingsTabInput": "Χειρισμός",
|
||||||
"SettingsTabInputEnableDockedMode": "Ενεργοποίηση Docked Mode",
|
"SettingsTabInputEnableDockedMode": "Ενεργοποίηση Docked Mode",
|
||||||
|
@@ -157,11 +157,11 @@
|
|||||||
"SettingsTabLoggingEnableFsAccessLogs": "Enable Fs Access Logs",
|
"SettingsTabLoggingEnableFsAccessLogs": "Enable Fs Access Logs",
|
||||||
"SettingsTabLoggingFsGlobalAccessLogMode": "Fs Global Access Log Mode:",
|
"SettingsTabLoggingFsGlobalAccessLogMode": "Fs Global Access Log Mode:",
|
||||||
"SettingsTabLoggingDeveloperOptions": "Developer Options (WARNING: Will reduce performance)",
|
"SettingsTabLoggingDeveloperOptions": "Developer Options (WARNING: Will reduce performance)",
|
||||||
"SettingsTabLoggingOpenglLogLevel": "OpenGL Log Level:",
|
"SettingsTabLoggingGraphicsBackendLogLevel": "Graphics Backend Log Level:",
|
||||||
"SettingsTabLoggingOpenglLogLevelNone": "None",
|
"SettingsTabLoggingGraphicsBackendLogLevelNone": "None",
|
||||||
"SettingsTabLoggingOpenglLogLevelError": "Error",
|
"SettingsTabLoggingGraphicsBackendLogLevelError": "Error",
|
||||||
"SettingsTabLoggingOpenglLogLevelPerformance": "Slowdowns",
|
"SettingsTabLoggingGraphicsBackendLogLevelPerformance": "Slowdowns",
|
||||||
"SettingsTabLoggingOpenglLogLevelAll": "All",
|
"SettingsTabLoggingGraphicsBackendLogLevelAll": "All",
|
||||||
"SettingsTabLoggingEnableDebugLogs": "Enable Debug Logs",
|
"SettingsTabLoggingEnableDebugLogs": "Enable Debug Logs",
|
||||||
"SettingsTabInput": "Input",
|
"SettingsTabInput": "Input",
|
||||||
"SettingsTabInputEnableDockedMode": "Docked Mode",
|
"SettingsTabInputEnableDockedMode": "Docked Mode",
|
||||||
@@ -315,7 +315,7 @@
|
|||||||
"DialogUpdaterConvertFailedMessage": "Failed to convert the current Ryujinx version.",
|
"DialogUpdaterConvertFailedMessage": "Failed to convert the current Ryujinx version.",
|
||||||
"DialogUpdaterCancelUpdateMessage": "Cancelling Update!",
|
"DialogUpdaterCancelUpdateMessage": "Cancelling Update!",
|
||||||
"DialogUpdaterAlreadyOnLatestVersionMessage": "You are already using the most updated version of Ryujinx!",
|
"DialogUpdaterAlreadyOnLatestVersionMessage": "You are already using the most updated version of Ryujinx!",
|
||||||
"DialogUpdaterFailedToGetVersionMessage": "An error has occurred when trying to get release information from Github Release. This can be caused if a new release is being compiled by GitHub Actions. Try again in a few minutes.",
|
"DialogUpdaterFailedToGetVersionMessage": "An error has occurred when trying to get release information from GitHub Release. This can be caused if a new release is being compiled by GitHub Actions. Try again in a few minutes.",
|
||||||
"DialogUpdaterConvertFailedGithubMessage": "Failed to convert the received Ryujinx version from Github Release.",
|
"DialogUpdaterConvertFailedGithubMessage": "Failed to convert the received Ryujinx version from Github Release.",
|
||||||
"DialogUpdaterDownloadingMessage": "Downloading Update...",
|
"DialogUpdaterDownloadingMessage": "Downloading Update...",
|
||||||
"DialogUpdaterExtractionMessage": "Extracting Update...",
|
"DialogUpdaterExtractionMessage": "Extracting Update...",
|
||||||
|
@@ -157,11 +157,10 @@
|
|||||||
"SettingsTabLoggingEnableFsAccessLogs": "Habilitar registros de Fs Access",
|
"SettingsTabLoggingEnableFsAccessLogs": "Habilitar registros de Fs Access",
|
||||||
"SettingsTabLoggingFsGlobalAccessLogMode": "Modo de registros Fs Global Access:",
|
"SettingsTabLoggingFsGlobalAccessLogMode": "Modo de registros Fs Global Access:",
|
||||||
"SettingsTabLoggingDeveloperOptions": "Opciones de desarrollador (ADVERTENCIA: empeorarán el rendimiento)",
|
"SettingsTabLoggingDeveloperOptions": "Opciones de desarrollador (ADVERTENCIA: empeorarán el rendimiento)",
|
||||||
"SettingsTabLoggingOpenglLogLevel": "Nivel de registro de OpenGL:",
|
"SettingsTabLoggingGraphicsBackendLogLevelNone": "Nada",
|
||||||
"SettingsTabLoggingOpenglLogLevelNone": "Nada",
|
"SettingsTabLoggingGraphicsBackendLogLevelError": "Errores",
|
||||||
"SettingsTabLoggingOpenglLogLevelError": "Errores",
|
"SettingsTabLoggingGraphicsBackendLogLevelPerformance": "Ralentizaciones",
|
||||||
"SettingsTabLoggingOpenglLogLevelPerformance": "Ralentizaciones",
|
"SettingsTabLoggingGraphicsBackendLogLevelAll": "Todo",
|
||||||
"SettingsTabLoggingOpenglLogLevelAll": "Todo",
|
|
||||||
"SettingsTabLoggingEnableDebugLogs": "Habilitar registros de debug",
|
"SettingsTabLoggingEnableDebugLogs": "Habilitar registros de debug",
|
||||||
"SettingsTabInput": "Entrada",
|
"SettingsTabInput": "Entrada",
|
||||||
"SettingsTabInputEnableDockedMode": "Modo dock/TV",
|
"SettingsTabInputEnableDockedMode": "Modo dock/TV",
|
||||||
|
@@ -150,11 +150,10 @@
|
|||||||
"SettingsTabLoggingEnableFsAccessLogs": "Activer les journaux des accès au système de fichiers",
|
"SettingsTabLoggingEnableFsAccessLogs": "Activer les journaux des accès au système de fichiers",
|
||||||
"SettingsTabLoggingFsGlobalAccessLogMode": "Niveau des journaux des accès au système de fichiers:",
|
"SettingsTabLoggingFsGlobalAccessLogMode": "Niveau des journaux des accès au système de fichiers:",
|
||||||
"SettingsTabLoggingDeveloperOptions": "Options développeur (ATTENTION: Cela peut réduire les performances)",
|
"SettingsTabLoggingDeveloperOptions": "Options développeur (ATTENTION: Cela peut réduire les performances)",
|
||||||
"SettingsTabLoggingOpenglLogLevel": "Niveau des journaux OpenGL:",
|
"SettingsTabLoggingGraphicsBackendLogLevelNone": "Aucun",
|
||||||
"SettingsTabLoggingOpenglLogLevelNone": "Aucun",
|
"SettingsTabLoggingGraphicsBackendLogLevelError": "Erreur",
|
||||||
"SettingsTabLoggingOpenglLogLevelError": "Erreur",
|
"SettingsTabLoggingGraphicsBackendLogLevelPerformance": "Ralentissements",
|
||||||
"SettingsTabLoggingOpenglLogLevelPerformance": "Ralentissements",
|
"SettingsTabLoggingGraphicsBackendLogLevelAll": "Tout",
|
||||||
"SettingsTabLoggingOpenglLogLevelAll": "Tout",
|
|
||||||
"SettingsTabLoggingEnableDebugLogs": "Activer les journaux de debug",
|
"SettingsTabLoggingEnableDebugLogs": "Activer les journaux de debug",
|
||||||
"SettingsTabInput": "Contrôles",
|
"SettingsTabInput": "Contrôles",
|
||||||
"SettingsTabInputEnableDockedMode": "Active le mode station d'accueil",
|
"SettingsTabInputEnableDockedMode": "Active le mode station d'accueil",
|
||||||
|
@@ -157,11 +157,10 @@
|
|||||||
"SettingsTabLoggingEnableFsAccessLogs": "Attiva Fs Access Logs",
|
"SettingsTabLoggingEnableFsAccessLogs": "Attiva Fs Access Logs",
|
||||||
"SettingsTabLoggingFsGlobalAccessLogMode": "Modalità log accesso globale Fs:",
|
"SettingsTabLoggingFsGlobalAccessLogMode": "Modalità log accesso globale Fs:",
|
||||||
"SettingsTabLoggingDeveloperOptions": "Opzioni da sviluppatore (AVVISO: Ridurrà le prestazioni)",
|
"SettingsTabLoggingDeveloperOptions": "Opzioni da sviluppatore (AVVISO: Ridurrà le prestazioni)",
|
||||||
"SettingsTabLoggingOpenglLogLevel": "Livello di log OpenGL:",
|
"SettingsTabLoggingGraphicsBackendLogLevelNone": "Nessuno",
|
||||||
"SettingsTabLoggingOpenglLogLevelNone": "Nessuno",
|
"SettingsTabLoggingGraphicsBackendLogLevelError": "Errore",
|
||||||
"SettingsTabLoggingOpenglLogLevelError": "Errore",
|
"SettingsTabLoggingGraphicsBackendLogLevelPerformance": "Rallentamenti",
|
||||||
"SettingsTabLoggingOpenglLogLevelPerformance": "Rallentamenti",
|
"SettingsTabLoggingGraphicsBackendLogLevelAll": "Tutto",
|
||||||
"SettingsTabLoggingOpenglLogLevelAll": "Tutto",
|
|
||||||
"SettingsTabLoggingEnableDebugLogs": "Attiva logs di debug",
|
"SettingsTabLoggingEnableDebugLogs": "Attiva logs di debug",
|
||||||
"SettingsTabInput": "Input",
|
"SettingsTabInput": "Input",
|
||||||
"SettingsTabInputEnableDockedMode": "Attiva modalità TV",
|
"SettingsTabInputEnableDockedMode": "Attiva modalità TV",
|
||||||
@@ -558,8 +557,8 @@
|
|||||||
"SettingsSelectThemeFileDialogTitle" : "Seleziona file del tema",
|
"SettingsSelectThemeFileDialogTitle" : "Seleziona file del tema",
|
||||||
"SettingsXamlThemeFile" : "File del tema xaml",
|
"SettingsXamlThemeFile" : "File del tema xaml",
|
||||||
"SettingsTabHotkeysResScaleUpHotkey": "Aumentare la risoluzione:",
|
"SettingsTabHotkeysResScaleUpHotkey": "Aumentare la risoluzione:",
|
||||||
"SettingsTabHotkeysResScaleDownHotkey": "Diminuire la risoluzione:"
|
"SettingsTabHotkeysResScaleDownHotkey": "Diminuire la risoluzione:",
|
||||||
"AvatarWindowTitle": "Gestisci account - Avatar"
|
"AvatarWindowTitle": "Gestisci account - Avatar",
|
||||||
"Amiibo": "Amiibo",
|
"Amiibo": "Amiibo",
|
||||||
"Unknown": "Sconosciuto",
|
"Unknown": "Sconosciuto",
|
||||||
"Usage": "Utilizzo",
|
"Usage": "Utilizzo",
|
||||||
|
@@ -157,11 +157,10 @@
|
|||||||
"SettingsTabLoggingEnableFsAccessLogs": "Fs アクセスログを有効",
|
"SettingsTabLoggingEnableFsAccessLogs": "Fs アクセスログを有効",
|
||||||
"SettingsTabLoggingFsGlobalAccessLogMode": "Fs グローバルアクセスログモード:",
|
"SettingsTabLoggingFsGlobalAccessLogMode": "Fs グローバルアクセスログモード:",
|
||||||
"SettingsTabLoggingDeveloperOptions": "開発者オプション (警告: パフォーマンスが低下します)",
|
"SettingsTabLoggingDeveloperOptions": "開発者オプション (警告: パフォーマンスが低下します)",
|
||||||
"SettingsTabLoggingOpenglLogLevel": "OpenGL ログレベル:",
|
"SettingsTabLoggingGraphicsBackendLogLevelNone": "なし",
|
||||||
"SettingsTabLoggingOpenglLogLevelNone": "なし",
|
"SettingsTabLoggingGraphicsBackendLogLevelError": "エラー",
|
||||||
"SettingsTabLoggingOpenglLogLevelError": "エラー",
|
"SettingsTabLoggingGraphicsBackendLogLevelPerformance": "パフォーマンス低下",
|
||||||
"SettingsTabLoggingOpenglLogLevelPerformance": "パフォーマンス低下",
|
"SettingsTabLoggingGraphicsBackendLogLevelAll": "すべて",
|
||||||
"SettingsTabLoggingOpenglLogLevelAll": "すべて",
|
|
||||||
"SettingsTabLoggingEnableDebugLogs": "デバッグログを有効",
|
"SettingsTabLoggingEnableDebugLogs": "デバッグログを有効",
|
||||||
"SettingsTabInput": "入力",
|
"SettingsTabInput": "入力",
|
||||||
"SettingsTabInputEnableDockedMode": "ドッキングモード",
|
"SettingsTabInputEnableDockedMode": "ドッキングモード",
|
||||||
|
@@ -156,11 +156,10 @@
|
|||||||
"SettingsTabLoggingEnableFsAccessLogs": "Fs 액세스 로그 켜기",
|
"SettingsTabLoggingEnableFsAccessLogs": "Fs 액세스 로그 켜기",
|
||||||
"SettingsTabLoggingFsGlobalAccessLogMode": "Fs 전역 액세스 로그 모드 :",
|
"SettingsTabLoggingFsGlobalAccessLogMode": "Fs 전역 액세스 로그 모드 :",
|
||||||
"SettingsTabLoggingDeveloperOptions": "개발자 옵션 (경고 : 성능이 저하됩니다.)",
|
"SettingsTabLoggingDeveloperOptions": "개발자 옵션 (경고 : 성능이 저하됩니다.)",
|
||||||
"SettingsTabLoggingOpenglLogLevel": "OpenGL 로그 수준 :",
|
"SettingsTabLoggingGraphicsBackendLogLevelNone": "없음",
|
||||||
"SettingsTabLoggingOpenglLogLevelNone": "없음",
|
"SettingsTabLoggingGraphicsBackendLogLevelError": "오류",
|
||||||
"SettingsTabLoggingOpenglLogLevelError": "오류",
|
"SettingsTabLoggingGraphicsBackendLogLevelPerformance": "감속",
|
||||||
"SettingsTabLoggingOpenglLogLevelPerformance": "감속",
|
"SettingsTabLoggingGraphicsBackendLogLevelAll": "모두",
|
||||||
"SettingsTabLoggingOpenglLogLevelAll": "모두",
|
|
||||||
"SettingsTabLoggingEnableDebugLogs": "디버그 로그 사용",
|
"SettingsTabLoggingEnableDebugLogs": "디버그 로그 사용",
|
||||||
"SettingsTabInput": "입력",
|
"SettingsTabInput": "입력",
|
||||||
"SettingsTabInputEnableDockedMode": "도킹 모드 활성화",
|
"SettingsTabInputEnableDockedMode": "도킹 모드 활성화",
|
||||||
|
@@ -157,11 +157,10 @@
|
|||||||
"SettingsTabLoggingEnableFsAccessLogs": "Włącz Logi Dostępu do Systemu Plików",
|
"SettingsTabLoggingEnableFsAccessLogs": "Włącz Logi Dostępu do Systemu Plików",
|
||||||
"SettingsTabLoggingFsGlobalAccessLogMode": "Tryb Globalnych Logów Systemu Plików:",
|
"SettingsTabLoggingFsGlobalAccessLogMode": "Tryb Globalnych Logów Systemu Plików:",
|
||||||
"SettingsTabLoggingDeveloperOptions": "Opcje programistyczne (OSTRZEŻENIE: Zmniejszą wydajność)",
|
"SettingsTabLoggingDeveloperOptions": "Opcje programistyczne (OSTRZEŻENIE: Zmniejszą wydajność)",
|
||||||
"SettingsTabLoggingOpenglLogLevel": "Poziom Logów OpenGL:",
|
"SettingsTabLoggingGraphicsBackendLogLevelNone": "Żadne",
|
||||||
"SettingsTabLoggingOpenglLogLevelNone": "Żadne",
|
"SettingsTabLoggingGraphicsBackendLogLevelError": "Błędy",
|
||||||
"SettingsTabLoggingOpenglLogLevelError": "Błędy",
|
"SettingsTabLoggingGraphicsBackendLogLevelPerformance": "Spowolnienia",
|
||||||
"SettingsTabLoggingOpenglLogLevelPerformance": "Spowolnienia",
|
"SettingsTabLoggingGraphicsBackendLogLevelAll": "Wszystkie",
|
||||||
"SettingsTabLoggingOpenglLogLevelAll": "Wszystkie",
|
|
||||||
"SettingsTabLoggingEnableDebugLogs": "Włącz Logi Debugowania",
|
"SettingsTabLoggingEnableDebugLogs": "Włącz Logi Debugowania",
|
||||||
"SettingsTabInput": "Sterowanie",
|
"SettingsTabInput": "Sterowanie",
|
||||||
"SettingsTabInputEnableDockedMode": "Tryb Zadokowany",
|
"SettingsTabInputEnableDockedMode": "Tryb Zadokowany",
|
||||||
|
@@ -157,11 +157,10 @@
|
|||||||
"SettingsTabLoggingEnableFsAccessLogs": "Habilitar logs de acesso ao sistema de arquivos",
|
"SettingsTabLoggingEnableFsAccessLogs": "Habilitar logs de acesso ao sistema de arquivos",
|
||||||
"SettingsTabLoggingFsGlobalAccessLogMode": "Modo global de logs do sistema de arquivos:",
|
"SettingsTabLoggingFsGlobalAccessLogMode": "Modo global de logs do sistema de arquivos:",
|
||||||
"SettingsTabLoggingDeveloperOptions": "Opções do desenvolvedor (AVISO: Vai reduzir a performance)",
|
"SettingsTabLoggingDeveloperOptions": "Opções do desenvolvedor (AVISO: Vai reduzir a performance)",
|
||||||
"SettingsTabLoggingOpenglLogLevel": "Nível de log do OpenGL:",
|
"SettingsTabLoggingGraphicsBackendLogLevelNone": "Nenhum",
|
||||||
"SettingsTabLoggingOpenglLogLevelNone": "Nenhum",
|
"SettingsTabLoggingGraphicsBackendLogLevelError": "Erro",
|
||||||
"SettingsTabLoggingOpenglLogLevelError": "Erro",
|
"SettingsTabLoggingGraphicsBackendLogLevelPerformance": "Lentidão",
|
||||||
"SettingsTabLoggingOpenglLogLevelPerformance": "Lentidão",
|
"SettingsTabLoggingGraphicsBackendLogLevelAll": "Todos",
|
||||||
"SettingsTabLoggingOpenglLogLevelAll": "Todos",
|
|
||||||
"SettingsTabLoggingEnableDebugLogs": "Habilitar logs de depuração",
|
"SettingsTabLoggingEnableDebugLogs": "Habilitar logs de depuração",
|
||||||
"SettingsTabInput": "Controle",
|
"SettingsTabInput": "Controle",
|
||||||
"SettingsTabInputEnableDockedMode": "Habilitar modo TV",
|
"SettingsTabInputEnableDockedMode": "Habilitar modo TV",
|
||||||
|
@@ -156,11 +156,10 @@
|
|||||||
"SettingsTabLoggingEnableFsAccessLogs": "Включить журналы доступа Fs",
|
"SettingsTabLoggingEnableFsAccessLogs": "Включить журналы доступа Fs",
|
||||||
"SettingsTabLoggingFsGlobalAccessLogMode": "Режим журнала глобального доступа Fs:",
|
"SettingsTabLoggingFsGlobalAccessLogMode": "Режим журнала глобального доступа Fs:",
|
||||||
"SettingsTabLoggingDeveloperOptions": "Параметры разработчика (ВНИМАНИЕ: снизит производительность)",
|
"SettingsTabLoggingDeveloperOptions": "Параметры разработчика (ВНИМАНИЕ: снизит производительность)",
|
||||||
"SettingsTabLoggingOpenglLogLevel": "Уровень журнала OpenGL:",
|
"SettingsTabLoggingGraphicsBackendLogLevelNone": "Ничего",
|
||||||
"SettingsTabLoggingOpenglLogLevelNone": "Ничего",
|
"SettingsTabLoggingGraphicsBackendLogLevelError": "Ошибка",
|
||||||
"SettingsTabLoggingOpenglLogLevelError": "Ошибка",
|
"SettingsTabLoggingGraphicsBackendLogLevelPerformance": "Замедления",
|
||||||
"SettingsTabLoggingOpenglLogLevelPerformance": "Замедления",
|
"SettingsTabLoggingGraphicsBackendLogLevelAll": "Всё",
|
||||||
"SettingsTabLoggingOpenglLogLevelAll": "Всё",
|
|
||||||
"SettingsTabLoggingEnableDebugLogs": "Включить журналы отладки",
|
"SettingsTabLoggingEnableDebugLogs": "Включить журналы отладки",
|
||||||
"SettingsTabInput": "Управление",
|
"SettingsTabInput": "Управление",
|
||||||
"SettingsTabInputEnableDockedMode": "Включить режим закрепления",
|
"SettingsTabInputEnableDockedMode": "Включить режим закрепления",
|
||||||
|
@@ -157,11 +157,10 @@
|
|||||||
"SettingsTabLoggingEnableFsAccessLogs": "Fs Erişim Loglarını Etkinleştir",
|
"SettingsTabLoggingEnableFsAccessLogs": "Fs Erişim Loglarını Etkinleştir",
|
||||||
"SettingsTabLoggingFsGlobalAccessLogMode": "Fs Evrensel Erişim Log Modu:",
|
"SettingsTabLoggingFsGlobalAccessLogMode": "Fs Evrensel Erişim Log Modu:",
|
||||||
"SettingsTabLoggingDeveloperOptions": "Geliştirici Seçenekleri (UYARI: Performansı düşürecektir)",
|
"SettingsTabLoggingDeveloperOptions": "Geliştirici Seçenekleri (UYARI: Performansı düşürecektir)",
|
||||||
"SettingsTabLoggingOpenglLogLevel": "OpenGL Log Seviyesi:",
|
"SettingsTabLoggingGraphicsBackendLogLevelNone": "Hiç",
|
||||||
"SettingsTabLoggingOpenglLogLevelNone": "Hiç",
|
"SettingsTabLoggingGraphicsBackendLogLevelError": "Hata",
|
||||||
"SettingsTabLoggingOpenglLogLevelError": "Hata",
|
"SettingsTabLoggingGraphicsBackendLogLevelPerformance": "Yavaşlamalar",
|
||||||
"SettingsTabLoggingOpenglLogLevelPerformance": "Yavaşlamalar",
|
"SettingsTabLoggingGraphicsBackendLogLevelAll": "Her Şey",
|
||||||
"SettingsTabLoggingOpenglLogLevelAll": "Her Şey",
|
|
||||||
"SettingsTabLoggingEnableDebugLogs": "Hata Ayıklama Loglarını Etkinleştir",
|
"SettingsTabLoggingEnableDebugLogs": "Hata Ayıklama Loglarını Etkinleştir",
|
||||||
"SettingsTabInput": "Giriş Yöntemi",
|
"SettingsTabInput": "Giriş Yöntemi",
|
||||||
"SettingsTabInputEnableDockedMode": "Docked Modunu Etkinleştir",
|
"SettingsTabInputEnableDockedMode": "Docked Modunu Etkinleştir",
|
||||||
|
@@ -157,11 +157,10 @@
|
|||||||
"SettingsTabLoggingEnableFsAccessLogs": "记录文件访问",
|
"SettingsTabLoggingEnableFsAccessLogs": "记录文件访问",
|
||||||
"SettingsTabLoggingFsGlobalAccessLogMode": "记录全局文件访问模式:",
|
"SettingsTabLoggingFsGlobalAccessLogMode": "记录全局文件访问模式:",
|
||||||
"SettingsTabLoggingDeveloperOptions": "开发者选项 (警告: 会降低性能)",
|
"SettingsTabLoggingDeveloperOptions": "开发者选项 (警告: 会降低性能)",
|
||||||
"SettingsTabLoggingOpenglLogLevel": "OpenGL日志级别:",
|
"SettingsTabLoggingGraphicsBackendLogLevelNone": "无",
|
||||||
"SettingsTabLoggingOpenglLogLevelNone": "无",
|
"SettingsTabLoggingGraphicsBackendLogLevelError": "错误",
|
||||||
"SettingsTabLoggingOpenglLogLevelError": "错误",
|
"SettingsTabLoggingGraphicsBackendLogLevelPerformance": "减速",
|
||||||
"SettingsTabLoggingOpenglLogLevelPerformance": "减速",
|
"SettingsTabLoggingGraphicsBackendLogLevelAll": "全部",
|
||||||
"SettingsTabLoggingOpenglLogLevelAll": "全部",
|
|
||||||
"SettingsTabLoggingEnableDebugLogs": "启用调试日志",
|
"SettingsTabLoggingEnableDebugLogs": "启用调试日志",
|
||||||
"SettingsTabInput": "输入",
|
"SettingsTabInput": "输入",
|
||||||
"SettingsTabInputEnableDockedMode": "主机模式",
|
"SettingsTabInputEnableDockedMode": "主机模式",
|
||||||
|
@@ -157,11 +157,10 @@
|
|||||||
"SettingsTabLoggingEnableFsAccessLogs": "記錄檔案存取",
|
"SettingsTabLoggingEnableFsAccessLogs": "記錄檔案存取",
|
||||||
"SettingsTabLoggingFsGlobalAccessLogMode": "記錄全域檔案存取模式:",
|
"SettingsTabLoggingFsGlobalAccessLogMode": "記錄全域檔案存取模式:",
|
||||||
"SettingsTabLoggingDeveloperOptions": "開發者選項 (警告: 會降低效能)",
|
"SettingsTabLoggingDeveloperOptions": "開發者選項 (警告: 會降低效能)",
|
||||||
"SettingsTabLoggingOpenglLogLevel": "OpenGL 日誌級別:",
|
"SettingsTabLoggingGraphicsBackendLogLevelNone": "無",
|
||||||
"SettingsTabLoggingOpenglLogLevelNone": "無",
|
"SettingsTabLoggingGraphicsBackendLogLevelError": "錯誤",
|
||||||
"SettingsTabLoggingOpenglLogLevelError": "錯誤",
|
"SettingsTabLoggingGraphicsBackendLogLevelPerformance": "減速",
|
||||||
"SettingsTabLoggingOpenglLogLevelPerformance": "減速",
|
"SettingsTabLoggingGraphicsBackendLogLevelAll": "全部",
|
||||||
"SettingsTabLoggingOpenglLogLevelAll": "全部",
|
|
||||||
"SettingsTabLoggingEnableDebugLogs": "啟用除錯日誌",
|
"SettingsTabLoggingEnableDebugLogs": "啟用除錯日誌",
|
||||||
"SettingsTabInput": "輸入",
|
"SettingsTabInput": "輸入",
|
||||||
"SettingsTabInputEnableDockedMode": "Docked 模式",
|
"SettingsTabInputEnableDockedMode": "Docked 模式",
|
||||||
|
@@ -161,6 +161,7 @@
|
|||||||
<Style Selector="MenuItem">
|
<Style Selector="MenuItem">
|
||||||
<Setter Property="Height" Value="{DynamicResource MenuItemHeight}" />
|
<Setter Property="Height" Value="{DynamicResource MenuItemHeight}" />
|
||||||
<Setter Property="Padding" Value="{DynamicResource MenuItemPadding}" />
|
<Setter Property="Padding" Value="{DynamicResource MenuItemPadding}" />
|
||||||
|
<Setter Property="FontSize" Value="12" />
|
||||||
</Style>
|
</Style>
|
||||||
<Style Selector="MenuItem:selected /template/ Border#root">
|
<Style Selector="MenuItem:selected /template/ Border#root">
|
||||||
<Setter Property="Background" Value="{DynamicResource ThemeControlBorderColor}" />
|
<Setter Property="Background" Value="{DynamicResource ThemeControlBorderColor}" />
|
||||||
|
127
Ryujinx.Ava/Helper/MetalHelper.cs
Normal file
127
Ryujinx.Ava/Helper/MetalHelper.cs
Normal file
@@ -0,0 +1,127 @@
|
|||||||
|
using System;
|
||||||
|
using System.Runtime.Versioning;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using Avalonia;
|
||||||
|
|
||||||
|
namespace Ryujinx.Ava.Ui.Helper
|
||||||
|
{
|
||||||
|
public delegate void UpdateBoundsCallbackDelegate(Rect rect);
|
||||||
|
|
||||||
|
[SupportedOSPlatform("macos")]
|
||||||
|
static class MetalHelper
|
||||||
|
{
|
||||||
|
private const string LibObjCImport = "/usr/lib/libobjc.A.dylib";
|
||||||
|
|
||||||
|
private struct Selector
|
||||||
|
{
|
||||||
|
public readonly IntPtr NativePtr;
|
||||||
|
|
||||||
|
public unsafe Selector(string value)
|
||||||
|
{
|
||||||
|
int size = System.Text.Encoding.UTF8.GetMaxByteCount(value.Length);
|
||||||
|
byte* data = stackalloc byte[size];
|
||||||
|
|
||||||
|
fixed (char* pValue = value)
|
||||||
|
{
|
||||||
|
System.Text.Encoding.UTF8.GetBytes(pValue, value.Length, data, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
NativePtr = sel_registerName(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static implicit operator Selector(string value) => new Selector(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static unsafe IntPtr GetClass(string value)
|
||||||
|
{
|
||||||
|
int size = System.Text.Encoding.UTF8.GetMaxByteCount(value.Length);
|
||||||
|
byte* data = stackalloc byte[size];
|
||||||
|
|
||||||
|
fixed (char* pValue = value)
|
||||||
|
{
|
||||||
|
System.Text.Encoding.UTF8.GetBytes(pValue, value.Length, data, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
return objc_getClass(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
private struct NSPoint
|
||||||
|
{
|
||||||
|
public double X;
|
||||||
|
public double Y;
|
||||||
|
|
||||||
|
public NSPoint(double x, double y)
|
||||||
|
{
|
||||||
|
X = x;
|
||||||
|
Y = y;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private struct NSRect
|
||||||
|
{
|
||||||
|
public NSPoint Pos;
|
||||||
|
public NSPoint Size;
|
||||||
|
|
||||||
|
public NSRect(double x, double y, double width, double height)
|
||||||
|
{
|
||||||
|
Pos = new NSPoint(x, y);
|
||||||
|
Size = new NSPoint(width, height);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IntPtr GetMetalLayer(out IntPtr nsView, out UpdateBoundsCallbackDelegate updateBounds)
|
||||||
|
{
|
||||||
|
// Create a new CAMetalLayer.
|
||||||
|
IntPtr layerClass = GetClass("CAMetalLayer");
|
||||||
|
IntPtr metalLayer = IntPtr_objc_msgSend(layerClass, "alloc");
|
||||||
|
objc_msgSend(metalLayer, "init");
|
||||||
|
|
||||||
|
// Create a child NSView to render into.
|
||||||
|
IntPtr nsViewClass = GetClass("NSView");
|
||||||
|
IntPtr child = IntPtr_objc_msgSend(nsViewClass, "alloc");
|
||||||
|
objc_msgSend(child, "init", new NSRect(0, 0, 0, 0));
|
||||||
|
|
||||||
|
// Make its renderer our metal layer.
|
||||||
|
objc_msgSend(child, "setWantsLayer:", (byte)1);
|
||||||
|
objc_msgSend(child, "setLayer:", metalLayer);
|
||||||
|
objc_msgSend(metalLayer, "setContentsScale:", Program.DesktopScaleFactor);
|
||||||
|
|
||||||
|
// Ensure the scale factor is up to date.
|
||||||
|
updateBounds = (Rect rect) => {
|
||||||
|
objc_msgSend(metalLayer, "setContentsScale:", Program.DesktopScaleFactor);
|
||||||
|
};
|
||||||
|
|
||||||
|
nsView = child;
|
||||||
|
return metalLayer;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void DestroyMetalLayer(IntPtr nsView, IntPtr metalLayer)
|
||||||
|
{
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
[DllImport(LibObjCImport)]
|
||||||
|
private static unsafe extern IntPtr sel_registerName(byte* data);
|
||||||
|
|
||||||
|
[DllImport(LibObjCImport)]
|
||||||
|
private static unsafe extern IntPtr objc_getClass(byte* data);
|
||||||
|
|
||||||
|
[DllImport(LibObjCImport)]
|
||||||
|
private static extern void objc_msgSend(IntPtr receiver, Selector selector);
|
||||||
|
|
||||||
|
[DllImport(LibObjCImport)]
|
||||||
|
private static extern void objc_msgSend(IntPtr receiver, Selector selector, byte value);
|
||||||
|
|
||||||
|
[DllImport(LibObjCImport)]
|
||||||
|
private static extern void objc_msgSend(IntPtr receiver, Selector selector, IntPtr value);
|
||||||
|
|
||||||
|
[DllImport(LibObjCImport)]
|
||||||
|
private static extern void objc_msgSend(IntPtr receiver, Selector selector, NSRect point);
|
||||||
|
|
||||||
|
[DllImport(LibObjCImport)]
|
||||||
|
private static extern void objc_msgSend(IntPtr receiver, Selector selector, double value);
|
||||||
|
|
||||||
|
[DllImport(LibObjCImport, EntryPoint = "objc_msgSend")]
|
||||||
|
private static extern IntPtr IntPtr_objc_msgSend(IntPtr receiver, Selector selector);
|
||||||
|
}
|
||||||
|
}
|
@@ -4,7 +4,6 @@ using Ryujinx.Input;
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Numerics;
|
using System.Numerics;
|
||||||
|
|
||||||
using ConfigKey = Ryujinx.Common.Configuration.Hid.Key;
|
using ConfigKey = Ryujinx.Common.Configuration.Hid.Key;
|
||||||
using Key = Ryujinx.Input.Key;
|
using Key = Ryujinx.Input.Key;
|
||||||
|
|
||||||
@@ -14,30 +13,37 @@ namespace Ryujinx.Ava.Input
|
|||||||
{
|
{
|
||||||
private readonly List<ButtonMappingEntry> _buttonsUserMapping;
|
private readonly List<ButtonMappingEntry> _buttonsUserMapping;
|
||||||
private readonly AvaloniaKeyboardDriver _driver;
|
private readonly AvaloniaKeyboardDriver _driver;
|
||||||
|
|
||||||
private readonly object _userMappingLock = new();
|
|
||||||
|
|
||||||
private StandardKeyboardInputConfig _configuration;
|
private StandardKeyboardInputConfig _configuration;
|
||||||
|
|
||||||
private bool HasConfiguration => _configuration != null;
|
private readonly object _userMappingLock = new();
|
||||||
|
|
||||||
public string Id { get; }
|
public string Id { get; }
|
||||||
public string Name { get; }
|
public string Name { get; }
|
||||||
|
|
||||||
public bool IsConnected => true;
|
public bool IsConnected => true;
|
||||||
|
|
||||||
public GamepadFeaturesFlag Features => GamepadFeaturesFlag.None;
|
public GamepadFeaturesFlag Features => GamepadFeaturesFlag.None;
|
||||||
|
|
||||||
|
private class ButtonMappingEntry
|
||||||
|
{
|
||||||
|
public readonly Key From;
|
||||||
|
public readonly GamepadButtonInputId To;
|
||||||
|
|
||||||
|
public ButtonMappingEntry(GamepadButtonInputId to, Key from)
|
||||||
|
{
|
||||||
|
To = to;
|
||||||
|
From = from;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public AvaloniaKeyboard(AvaloniaKeyboardDriver driver, string id, string name)
|
public AvaloniaKeyboard(AvaloniaKeyboardDriver driver, string id, string name)
|
||||||
{
|
{
|
||||||
|
_buttonsUserMapping = new List<ButtonMappingEntry>();
|
||||||
|
|
||||||
_driver = driver;
|
_driver = driver;
|
||||||
Id = id;
|
Id = id;
|
||||||
Name = name;
|
Name = name;
|
||||||
_buttonsUserMapping = new List<ButtonMappingEntry>();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Dispose() { }
|
|
||||||
|
|
||||||
public KeyboardStateSnapshot GetKeyboardStateSnapshot()
|
public KeyboardStateSnapshot GetKeyboardStateSnapshot()
|
||||||
{
|
{
|
||||||
return IKeyboard.GetStateSnapshot(this);
|
return IKeyboard.GetStateSnapshot(this);
|
||||||
@@ -50,7 +56,7 @@ namespace Ryujinx.Ava.Input
|
|||||||
|
|
||||||
lock (_userMappingLock)
|
lock (_userMappingLock)
|
||||||
{
|
{
|
||||||
if (!HasConfiguration)
|
if (_configuration == null)
|
||||||
{
|
{
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@@ -62,7 +68,7 @@ namespace Ryujinx.Ava.Input
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Do not touch state of the button already pressed
|
// NOTE: Do not touch state of the button already pressed.
|
||||||
if (!result.IsPressed(entry.To))
|
if (!result.IsPressed(entry.To))
|
||||||
{
|
{
|
||||||
result.SetPressed(entry.To, rawState.IsPressed(entry.From));
|
result.SetPressed(entry.To, rawState.IsPressed(entry.From));
|
||||||
@@ -114,7 +120,7 @@ namespace Ryujinx.Ava.Input
|
|||||||
|
|
||||||
_buttonsUserMapping.Clear();
|
_buttonsUserMapping.Clear();
|
||||||
|
|
||||||
// Left joycon
|
// Left JoyCon
|
||||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.LeftStick, (Key)_configuration.LeftJoyconStick.StickButton));
|
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.LeftStick, (Key)_configuration.LeftJoyconStick.StickButton));
|
||||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.DpadUp, (Key)_configuration.LeftJoycon.DpadUp));
|
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.DpadUp, (Key)_configuration.LeftJoycon.DpadUp));
|
||||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.DpadDown, (Key)_configuration.LeftJoycon.DpadDown));
|
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.DpadDown, (Key)_configuration.LeftJoycon.DpadDown));
|
||||||
@@ -126,7 +132,7 @@ namespace Ryujinx.Ava.Input
|
|||||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.SingleRightTrigger0, (Key)_configuration.LeftJoycon.ButtonSr));
|
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.SingleRightTrigger0, (Key)_configuration.LeftJoycon.ButtonSr));
|
||||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.SingleLeftTrigger0, (Key)_configuration.LeftJoycon.ButtonSl));
|
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.SingleLeftTrigger0, (Key)_configuration.LeftJoycon.ButtonSl));
|
||||||
|
|
||||||
// Finally right joycon
|
// Right JoyCon
|
||||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.RightStick, (Key)_configuration.RightJoyconStick.StickButton));
|
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.RightStick, (Key)_configuration.RightJoyconStick.StickButton));
|
||||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.A, (Key)_configuration.RightJoycon.ButtonA));
|
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.A, (Key)_configuration.RightJoycon.ButtonA));
|
||||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.B, (Key)_configuration.RightJoycon.ButtonB));
|
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.B, (Key)_configuration.RightJoycon.ButtonB));
|
||||||
@@ -190,16 +196,6 @@ namespace Ryujinx.Ava.Input
|
|||||||
_driver?.ResetKeys();
|
_driver?.ResetKeys();
|
||||||
}
|
}
|
||||||
|
|
||||||
private class ButtonMappingEntry
|
public void Dispose() { }
|
||||||
{
|
|
||||||
public readonly Key From;
|
|
||||||
public readonly GamepadButtonInputId To;
|
|
||||||
|
|
||||||
public ButtonMappingEntry(GamepadButtonInputId to, Key from)
|
|
||||||
{
|
|
||||||
To = to;
|
|
||||||
From = from;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -4,7 +4,6 @@ using Ryujinx.Ava.Common.Locale;
|
|||||||
using Ryujinx.Input;
|
using Ryujinx.Input;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|
||||||
using AvaKey = Avalonia.Input.Key;
|
using AvaKey = Avalonia.Input.Key;
|
||||||
using Key = Ryujinx.Input.Key;
|
using Key = Ryujinx.Input.Key;
|
||||||
|
|
||||||
@@ -20,8 +19,7 @@ namespace Ryujinx.Ava.Input
|
|||||||
public event EventHandler<KeyEventArgs> KeyRelease;
|
public event EventHandler<KeyEventArgs> KeyRelease;
|
||||||
public event EventHandler<string> TextInput;
|
public event EventHandler<string> TextInput;
|
||||||
|
|
||||||
public string DriverName => "Avalonia";
|
public string DriverName => "AvaloniaKeyboardDriver";
|
||||||
|
|
||||||
public ReadOnlySpan<string> GamepadsIds => _keyboardIdentifers;
|
public ReadOnlySpan<string> GamepadsIds => _keyboardIdentifers;
|
||||||
|
|
||||||
public AvaloniaKeyboardDriver(Control control)
|
public AvaloniaKeyboardDriver(Control control)
|
||||||
@@ -51,11 +49,6 @@ namespace Ryujinx.Ava.Input
|
|||||||
remove { }
|
remove { }
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
Dispose(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
public IGamepad GetGamepad(string id)
|
public IGamepad GetGamepad(string id)
|
||||||
{
|
{
|
||||||
if (!_keyboardIdentifers[0].Equals(id))
|
if (!_keyboardIdentifers[0].Equals(id))
|
||||||
@@ -77,8 +70,6 @@ namespace Ryujinx.Ava.Input
|
|||||||
|
|
||||||
protected void OnKeyPress(object sender, KeyEventArgs args)
|
protected void OnKeyPress(object sender, KeyEventArgs args)
|
||||||
{
|
{
|
||||||
AvaKey key = args.Key;
|
|
||||||
|
|
||||||
_pressedKeys.Add(args.Key);
|
_pressedKeys.Add(args.Key);
|
||||||
|
|
||||||
KeyPressed?.Invoke(this, args);
|
KeyPressed?.Invoke(this, args);
|
||||||
@@ -98,7 +89,7 @@ namespace Ryujinx.Ava.Input
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
AvaloniaMappingHelper.TryGetAvaKey(key, out var nativeKey);
|
AvaloniaKeyboardMappingHelper.TryGetAvaKey(key, out var nativeKey);
|
||||||
|
|
||||||
return _pressedKeys.Contains(nativeKey);
|
return _pressedKeys.Contains(nativeKey);
|
||||||
}
|
}
|
||||||
@@ -107,5 +98,10 @@ namespace Ryujinx.Ava.Input
|
|||||||
{
|
{
|
||||||
_pressedKeys.Clear();
|
_pressedKeys.Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
Dispose(true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -5,7 +5,7 @@ using AvaKey = Avalonia.Input.Key;
|
|||||||
|
|
||||||
namespace Ryujinx.Ava.Input
|
namespace Ryujinx.Ava.Input
|
||||||
{
|
{
|
||||||
internal static class AvaloniaMappingHelper
|
internal static class AvaloniaKeyboardMappingHelper
|
||||||
{
|
{
|
||||||
private static readonly AvaKey[] _keyMapping = new AvaKey[(int)Key.Count]
|
private static readonly AvaKey[] _keyMapping = new AvaKey[(int)Key.Count]
|
||||||
{
|
{
|
||||||
@@ -149,11 +149,11 @@ namespace Ryujinx.Ava.Input
|
|||||||
|
|
||||||
private static readonly Dictionary<AvaKey, Key> _avaKeyMapping;
|
private static readonly Dictionary<AvaKey, Key> _avaKeyMapping;
|
||||||
|
|
||||||
static AvaloniaMappingHelper()
|
static AvaloniaKeyboardMappingHelper()
|
||||||
{
|
{
|
||||||
var inputKeys = Enum.GetValues(typeof(Key));
|
var inputKeys = Enum.GetValues(typeof(Key));
|
||||||
|
|
||||||
// Avalonia.Input.Key is not contiguous and quite large, so use a dictionary instead of an array.
|
// NOTE: Avalonia.Input.Key is not contiguous and quite large, so use a dictionary instead of an array.
|
||||||
_avaKeyMapping = new Dictionary<AvaKey, Key>();
|
_avaKeyMapping = new Dictionary<AvaKey, Key>();
|
||||||
|
|
||||||
foreach (var key in inputKeys)
|
foreach (var key in inputKeys)
|
||||||
@@ -167,15 +167,13 @@ namespace Ryujinx.Ava.Input
|
|||||||
|
|
||||||
public static bool TryGetAvaKey(Key key, out AvaKey avaKey)
|
public static bool TryGetAvaKey(Key key, out AvaKey avaKey)
|
||||||
{
|
{
|
||||||
var keyExist = (int)key < _keyMapping.Length;
|
avaKey = AvaKey.None;
|
||||||
|
|
||||||
|
bool keyExist = (int)key < _keyMapping.Length;
|
||||||
if (keyExist)
|
if (keyExist)
|
||||||
{
|
{
|
||||||
avaKey = _keyMapping[(int)key];
|
avaKey = _keyMapping[(int)key];
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
avaKey = AvaKey.None;
|
|
||||||
}
|
|
||||||
|
|
||||||
return keyExist;
|
return keyExist;
|
||||||
}
|
}
|
@@ -10,14 +10,11 @@ namespace Ryujinx.Ava.Input
|
|||||||
{
|
{
|
||||||
private AvaloniaMouseDriver _driver;
|
private AvaloniaMouseDriver _driver;
|
||||||
|
|
||||||
public GamepadFeaturesFlag Features => throw new NotImplementedException();
|
|
||||||
|
|
||||||
public string Id => "0";
|
public string Id => "0";
|
||||||
|
|
||||||
public string Name => "AvaloniaMouse";
|
public string Name => "AvaloniaMouse";
|
||||||
|
|
||||||
public bool IsConnected => true;
|
public bool IsConnected => true;
|
||||||
|
public GamepadFeaturesFlag Features => throw new NotImplementedException();
|
||||||
public bool[] Buttons => _driver.PressedButtons;
|
public bool[] Buttons => _driver.PressedButtons;
|
||||||
|
|
||||||
public AvaloniaMouse(AvaloniaMouseDriver driver)
|
public AvaloniaMouse(AvaloniaMouseDriver driver)
|
||||||
|
@@ -17,10 +17,12 @@ namespace Ryujinx.Ava.Input
|
|||||||
private readonly Window _window;
|
private readonly Window _window;
|
||||||
|
|
||||||
public bool[] PressedButtons { get; }
|
public bool[] PressedButtons { get; }
|
||||||
|
|
||||||
public Vector2 CurrentPosition { get; private set; }
|
public Vector2 CurrentPosition { get; private set; }
|
||||||
public Vector2 Scroll { get; private set; }
|
public Vector2 Scroll { get; private set; }
|
||||||
|
|
||||||
|
public string DriverName => "AvaloniaMouseDriver";
|
||||||
|
public ReadOnlySpan<string> GamepadsIds => new[] { "0" };
|
||||||
|
|
||||||
public AvaloniaMouseDriver(Window window, Control parent)
|
public AvaloniaMouseDriver(Window window, Control parent)
|
||||||
{
|
{
|
||||||
_widget = parent;
|
_widget = parent;
|
||||||
@@ -39,7 +41,20 @@ namespace Ryujinx.Ava.Input
|
|||||||
PressedButtons = new bool[(int)MouseButton.Count];
|
PressedButtons = new bool[(int)MouseButton.Count];
|
||||||
|
|
||||||
_size = new Size((int)parent.Bounds.Width, (int)parent.Bounds.Height);
|
_size = new Size((int)parent.Bounds.Width, (int)parent.Bounds.Height);
|
||||||
parent.GetObservable(Control.BoundsProperty).Subscribe(Resized);
|
|
||||||
|
parent.GetObservable(Visual.BoundsProperty).Subscribe(Resized);
|
||||||
|
}
|
||||||
|
|
||||||
|
public event Action<string> OnGamepadConnected
|
||||||
|
{
|
||||||
|
add { }
|
||||||
|
remove { }
|
||||||
|
}
|
||||||
|
|
||||||
|
public event Action<string> OnGamepadDisconnected
|
||||||
|
{
|
||||||
|
add { }
|
||||||
|
remove { }
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Resized(Rect rect)
|
private void Resized(Rect rect)
|
||||||
@@ -59,14 +74,12 @@ namespace Ryujinx.Ava.Input
|
|||||||
|
|
||||||
private void Parent_PointerPressEvent(object o, PointerPressedEventArgs args)
|
private void Parent_PointerPressEvent(object o, PointerPressedEventArgs args)
|
||||||
{
|
{
|
||||||
var pointerProperties = args.GetCurrentPoint(_widget).Properties;
|
PressedButtons[(int)args.GetCurrentPoint(_widget).Properties.PointerUpdateKind] = true;
|
||||||
|
|
||||||
PressedButtons[(int)pointerProperties.PointerUpdateKind] = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Parent_PointerMovedEvent(object o, PointerEventArgs args)
|
private void Parent_PointerMovedEvent(object o, PointerEventArgs args)
|
||||||
{
|
{
|
||||||
var position = args.GetPosition(_widget);
|
Point position = args.GetPosition(_widget);
|
||||||
|
|
||||||
CurrentPosition = new Vector2((float)position.X, (float)position.Y);
|
CurrentPosition = new Vector2((float)position.X, (float)position.Y);
|
||||||
}
|
}
|
||||||
@@ -96,22 +109,6 @@ namespace Ryujinx.Ava.Input
|
|||||||
return _size;
|
return _size;
|
||||||
}
|
}
|
||||||
|
|
||||||
public string DriverName => "Avalonia";
|
|
||||||
|
|
||||||
public event Action<string> OnGamepadConnected
|
|
||||||
{
|
|
||||||
add { }
|
|
||||||
remove { }
|
|
||||||
}
|
|
||||||
|
|
||||||
public event Action<string> OnGamepadDisconnected
|
|
||||||
{
|
|
||||||
add { }
|
|
||||||
remove { }
|
|
||||||
}
|
|
||||||
|
|
||||||
public ReadOnlySpan<string> GamepadsIds => new[] { "0" };
|
|
||||||
|
|
||||||
public IGamepad GetGamepad(string id)
|
public IGamepad GetGamepad(string id)
|
||||||
{
|
{
|
||||||
return new AvaloniaMouse(this);
|
return new AvaloniaMouse(this);
|
||||||
|
@@ -355,7 +355,7 @@ namespace Ryujinx.Modules
|
|||||||
list[index] = args.Result;
|
list[index] = args.Result;
|
||||||
Interlocked.Increment(ref completedRequests);
|
Interlocked.Increment(ref completedRequests);
|
||||||
|
|
||||||
if (Interlocked.Equals(completedRequests, ConnectionCount))
|
if (Equals(completedRequests, ConnectionCount))
|
||||||
{
|
{
|
||||||
byte[] mergedFileBytes = new byte[_buildSize];
|
byte[] mergedFileBytes = new byte[_buildSize];
|
||||||
for (int connectionIndex = 0, destinationOffset = 0; connectionIndex < ConnectionCount; connectionIndex++)
|
for (int connectionIndex = 0, destinationOffset = 0; connectionIndex < ConnectionCount; connectionIndex++)
|
||||||
|
@@ -23,6 +23,7 @@ namespace Ryujinx.Ava
|
|||||||
internal class Program
|
internal class Program
|
||||||
{
|
{
|
||||||
public static double WindowScaleFactor { get; set; }
|
public static double WindowScaleFactor { get; set; }
|
||||||
|
public static double DesktopScaleFactor { get; set; } = 1.0;
|
||||||
public static string Version { get; private set; }
|
public static string Version { get; private set; }
|
||||||
public static string ConfigurationPath { get; private set; }
|
public static string ConfigurationPath { get; private set; }
|
||||||
public static bool PreviewerDetached { get; private set; }
|
public static bool PreviewerDetached { get; private set; }
|
||||||
@@ -81,8 +82,8 @@ namespace Ryujinx.Ava
|
|||||||
Console.Title = $"Ryujinx Console {Version}";
|
Console.Title = $"Ryujinx Console {Version}";
|
||||||
|
|
||||||
// Hook unhandled exception and process exit events.
|
// Hook unhandled exception and process exit events.
|
||||||
AppDomain.CurrentDomain.UnhandledException += (object sender, UnhandledExceptionEventArgs e) => ProcessUnhandledException(e.ExceptionObject as Exception, e.IsTerminating);
|
AppDomain.CurrentDomain.UnhandledException += (sender, e) => ProcessUnhandledException(e.ExceptionObject as Exception, e.IsTerminating);
|
||||||
AppDomain.CurrentDomain.ProcessExit += (object sender, EventArgs e) => Exit();
|
AppDomain.CurrentDomain.ProcessExit += (sender, e) => Exit();
|
||||||
|
|
||||||
// Setup base data directory.
|
// Setup base data directory.
|
||||||
AppDataManager.Initialize(CommandLineState.BaseDirPathArg);
|
AppDataManager.Initialize(CommandLineState.BaseDirPathArg);
|
||||||
|
@@ -26,19 +26,23 @@
|
|||||||
<PackageReference Include="Avalonia.Svg" Version="0.10.18" />
|
<PackageReference Include="Avalonia.Svg" Version="0.10.18" />
|
||||||
<PackageReference Include="Avalonia.Svg.Skia" Version="0.10.18" />
|
<PackageReference Include="Avalonia.Svg.Skia" Version="0.10.18" />
|
||||||
<PackageReference Include="jp2masa.Avalonia.Flexbox" Version="0.2.0" />
|
<PackageReference Include="jp2masa.Avalonia.Flexbox" Version="0.2.0" />
|
||||||
<PackageReference Include="DynamicData" Version="7.12.8" />
|
<PackageReference Include="DynamicData" Version="7.12.11" />
|
||||||
<PackageReference Include="FluentAvaloniaUI" Version="1.4.5" />
|
<PackageReference Include="FluentAvaloniaUI" Version="1.4.5" />
|
||||||
<PackageReference Include="XamlNameReferenceGenerator" Version="1.4.2" />
|
<PackageReference Include="XamlNameReferenceGenerator" Version="1.5.1" />
|
||||||
|
|
||||||
<PackageReference Include="OpenTK.Core" Version="4.7.5" />
|
<PackageReference Include="OpenTK.Core" Version="4.7.5" />
|
||||||
<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' AND '$(RuntimeIdentifier)' != 'osx-arm64'" />
|
||||||
<PackageReference Include="Ryujinx.Graphics.Nvdec.Dependencies" Version="5.0.1-build10" Condition="'$(RuntimeIdentifier)' != 'linux-x64' AND '$(RuntimeIdentifier)' != 'osx-x64'" />
|
<PackageReference Include="Ryujinx.Graphics.Nvdec.Dependencies" Version="5.0.1-build12" />
|
||||||
|
<PackageReference Include="Ryujinx.Graphics.Vulkan.Dependencies.MoltenVK" Version="1.2.0" Condition="'$(RuntimeIdentifier)' != 'linux-x64' AND '$(RuntimeIdentifier)' != 'win10-x64'" />
|
||||||
<PackageReference Include="Silk.NET.Vulkan" Version="2.16.0" />
|
<PackageReference Include="Silk.NET.Vulkan" Version="2.16.0" />
|
||||||
<PackageReference Include="Silk.NET.Vulkan.Extensions.EXT" Version="2.16.0" />
|
<PackageReference Include="Silk.NET.Vulkan.Extensions.EXT" Version="2.16.0" />
|
||||||
<PackageReference Include="Silk.NET.Vulkan.Extensions.KHR" Version="2.16.0" />
|
<PackageReference Include="Silk.NET.Vulkan.Extensions.KHR" Version="2.16.0" />
|
||||||
<PackageReference Include="SPB" Version="0.0.4-build28" />
|
<PackageReference Include="SPB" Version="0.0.4-build28" />
|
||||||
<PackageReference Include="SharpZipLib" Version="1.4.1" />
|
<PackageReference Include="SharpZipLib" Version="1.4.1" />
|
||||||
<PackageReference Include="SixLabors.ImageSharp" Version="1.0.4" />
|
<PackageReference Include="SixLabors.ImageSharp" Version="1.0.4" />
|
||||||
|
|
||||||
|
<!--NOTE: DO NOT REMOVE, THIS IS REQUIRED AS A RESULT OF A TRIMMING ISSUE IN AVALONIA -->
|
||||||
|
<PackageReference Include="System.Drawing.Common" Version="7.0.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
@@ -57,14 +61,18 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ContentWithTargetPath Include="..\distribution\windows\alsoft.ini" Condition="'$(RuntimeIdentifier)' != 'linux-x64' AND '$(RuntimeIdentifier)' != 'osx-x64'">
|
<Content Include="..\distribution\windows\alsoft.ini" Condition="'$(RuntimeIdentifier)' != 'linux-x64' AND '$(RuntimeIdentifier)' != 'osx-x64'">
|
||||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
<TargetPath>alsoft.ini</TargetPath>
|
<TargetPath>alsoft.ini</TargetPath>
|
||||||
</ContentWithTargetPath>
|
</Content>
|
||||||
<ContentWithTargetPath Include="..\distribution\legal\THIRDPARTY.md">
|
<Content Include="..\distribution\legal\THIRDPARTY.md">
|
||||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
<TargetPath>THIRDPARTY.md</TargetPath>
|
<TargetPath>THIRDPARTY.md</TargetPath>
|
||||||
</ContentWithTargetPath>
|
</Content>
|
||||||
|
<Content Include="..\LICENSE.txt">
|
||||||
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
|
<TargetPath>LICENSE.txt</TargetPath>
|
||||||
|
</Content>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
@@ -66,9 +66,9 @@ namespace Ryujinx.Ava.Ui.Applet
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void AvaloniaDynamicTextInputHandler_KeyRelease(object sender, Avalonia.Input.KeyEventArgs e)
|
private void AvaloniaDynamicTextInputHandler_KeyRelease(object sender, KeyEventArgs e)
|
||||||
{
|
{
|
||||||
var key = (HidKey)AvaloniaMappingHelper.ToInputKey(e.Key);
|
var key = (HidKey)AvaloniaKeyboardMappingHelper.ToInputKey(e.Key);
|
||||||
|
|
||||||
if (!(KeyReleasedEvent?.Invoke(key)).GetValueOrDefault(true))
|
if (!(KeyReleasedEvent?.Invoke(key)).GetValueOrDefault(true))
|
||||||
{
|
{
|
||||||
@@ -88,7 +88,7 @@ namespace Ryujinx.Ava.Ui.Applet
|
|||||||
|
|
||||||
private void AvaloniaDynamicTextInputHandler_KeyPressed(object sender, KeyEventArgs e)
|
private void AvaloniaDynamicTextInputHandler_KeyPressed(object sender, KeyEventArgs e)
|
||||||
{
|
{
|
||||||
var key = (HidKey)AvaloniaMappingHelper.ToInputKey(e.Key);
|
var key = (HidKey)AvaloniaKeyboardMappingHelper.ToInputKey(e.Key);
|
||||||
|
|
||||||
if (!(KeyPressedEvent?.Invoke(key)).GetValueOrDefault(true))
|
if (!(KeyPressedEvent?.Invoke(key)).GetValueOrDefault(true))
|
||||||
{
|
{
|
||||||
|
@@ -222,7 +222,7 @@ namespace Ryujinx.Ava.Ui.Controls
|
|||||||
|
|
||||||
content.MinHeight = 80;
|
content.MinHeight = 80;
|
||||||
|
|
||||||
SymbolIcon icon = new SymbolIcon { Symbol = (Symbol)symbol, Margin = new Avalonia.Thickness(10) };
|
SymbolIcon icon = new SymbolIcon { Symbol = (Symbol)symbol, Margin = new Thickness(10) };
|
||||||
icon.FontSize = 40;
|
icon.FontSize = 40;
|
||||||
icon.VerticalAlignment = Avalonia.Layout.VerticalAlignment.Center;
|
icon.VerticalAlignment = Avalonia.Layout.VerticalAlignment.Center;
|
||||||
Grid.SetColumn(icon, 0);
|
Grid.SetColumn(icon, 0);
|
||||||
@@ -232,15 +232,15 @@ namespace Ryujinx.Ava.Ui.Controls
|
|||||||
TextBlock primaryLabel = new TextBlock()
|
TextBlock primaryLabel = new TextBlock()
|
||||||
{
|
{
|
||||||
Text = primaryText,
|
Text = primaryText,
|
||||||
Margin = new Avalonia.Thickness(5),
|
Margin = new Thickness(5),
|
||||||
TextWrapping = Avalonia.Media.TextWrapping.Wrap,
|
TextWrapping = TextWrapping.Wrap,
|
||||||
MaxWidth = 450
|
MaxWidth = 450
|
||||||
};
|
};
|
||||||
TextBlock secondaryLabel = new TextBlock()
|
TextBlock secondaryLabel = new TextBlock()
|
||||||
{
|
{
|
||||||
Text = secondaryText,
|
Text = secondaryText,
|
||||||
Margin = new Avalonia.Thickness(5),
|
Margin = new Thickness(5),
|
||||||
TextWrapping = Avalonia.Media.TextWrapping.Wrap,
|
TextWrapping = TextWrapping.Wrap,
|
||||||
MaxWidth = 450
|
MaxWidth = 450
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -2,11 +2,10 @@ using Avalonia;
|
|||||||
using Avalonia.Controls;
|
using Avalonia.Controls;
|
||||||
using Avalonia.Input;
|
using Avalonia.Input;
|
||||||
using Avalonia.Platform;
|
using Avalonia.Platform;
|
||||||
|
using Ryujinx.Ava.Ui.Helper;
|
||||||
using SPB.Graphics;
|
using SPB.Graphics;
|
||||||
using SPB.Platform;
|
using SPB.Platform;
|
||||||
using SPB.Platform.GLX;
|
using SPB.Platform.GLX;
|
||||||
using SPB.Platform.X11;
|
|
||||||
using SPB.Windowing;
|
|
||||||
using System;
|
using System;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using System.Runtime.Versioning;
|
using System.Runtime.Versioning;
|
||||||
@@ -23,6 +22,10 @@ namespace Ryujinx.Ava.Ui.Controls
|
|||||||
protected GLXWindow X11Window { get; set; }
|
protected GLXWindow X11Window { get; set; }
|
||||||
protected IntPtr WindowHandle { get; set; }
|
protected IntPtr WindowHandle { get; set; }
|
||||||
protected IntPtr X11Display { get; set; }
|
protected IntPtr X11Display { get; set; }
|
||||||
|
protected IntPtr NsView { get; set; }
|
||||||
|
protected IntPtr MetalLayer { get; set; }
|
||||||
|
|
||||||
|
private UpdateBoundsCallbackDelegate _updateBoundsCallback;
|
||||||
|
|
||||||
public event EventHandler<IntPtr> WindowCreated;
|
public event EventHandler<IntPtr> WindowCreated;
|
||||||
public event EventHandler<Size> SizeChanged;
|
public event EventHandler<Size> SizeChanged;
|
||||||
@@ -36,7 +39,7 @@ namespace Ryujinx.Ava.Ui.Controls
|
|||||||
|
|
||||||
public EmbeddedWindow()
|
public EmbeddedWindow()
|
||||||
{
|
{
|
||||||
var stateObserverable = this.GetObservable(Control.BoundsProperty);
|
var stateObserverable = this.GetObservable(BoundsProperty);
|
||||||
|
|
||||||
stateObserverable.Subscribe(StateChanged);
|
stateObserverable.Subscribe(StateChanged);
|
||||||
|
|
||||||
@@ -58,6 +61,7 @@ namespace Ryujinx.Ava.Ui.Controls
|
|||||||
private void StateChanged(Rect rect)
|
private void StateChanged(Rect rect)
|
||||||
{
|
{
|
||||||
SizeChanged?.Invoke(this, rect.Size);
|
SizeChanged?.Invoke(this, rect.Size);
|
||||||
|
_updateBoundsCallback?.Invoke(rect);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override IPlatformHandle CreateNativeControlCore(IPlatformHandle parent)
|
protected override IPlatformHandle CreateNativeControlCore(IPlatformHandle parent)
|
||||||
@@ -70,6 +74,11 @@ namespace Ryujinx.Ava.Ui.Controls
|
|||||||
{
|
{
|
||||||
return CreateWin32(parent);
|
return CreateWin32(parent);
|
||||||
}
|
}
|
||||||
|
else if (OperatingSystem.IsMacOS())
|
||||||
|
{
|
||||||
|
return CreateMacOs(parent);
|
||||||
|
}
|
||||||
|
|
||||||
return base.CreateNativeControlCore(parent);
|
return base.CreateNativeControlCore(parent);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -85,6 +94,10 @@ namespace Ryujinx.Ava.Ui.Controls
|
|||||||
{
|
{
|
||||||
DestroyWin32(control);
|
DestroyWin32(control);
|
||||||
}
|
}
|
||||||
|
else if (OperatingSystem.IsMacOS())
|
||||||
|
{
|
||||||
|
DestroyMacOS();
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
base.DestroyNativeControlCore(control);
|
base.DestroyNativeControlCore(control);
|
||||||
@@ -152,7 +165,7 @@ namespace Ryujinx.Ava.Ui.Controls
|
|||||||
isLeft = msg == WindowsMessages.LBUTTONDOWN;
|
isLeft = msg == WindowsMessages.LBUTTONDOWN;
|
||||||
this.RaiseEvent(new PointerPressedEventArgs(
|
this.RaiseEvent(new PointerPressedEventArgs(
|
||||||
this,
|
this,
|
||||||
new Avalonia.Input.Pointer(0, PointerType.Mouse, true),
|
new Pointer(0, PointerType.Mouse, true),
|
||||||
root,
|
root,
|
||||||
this.TranslatePoint(point, root).Value,
|
this.TranslatePoint(point, root).Value,
|
||||||
(ulong)Environment.TickCount64,
|
(ulong)Environment.TickCount64,
|
||||||
@@ -164,7 +177,7 @@ namespace Ryujinx.Ava.Ui.Controls
|
|||||||
isLeft = msg == WindowsMessages.LBUTTONUP;
|
isLeft = msg == WindowsMessages.LBUTTONUP;
|
||||||
this.RaiseEvent(new PointerReleasedEventArgs(
|
this.RaiseEvent(new PointerReleasedEventArgs(
|
||||||
this,
|
this,
|
||||||
new Avalonia.Input.Pointer(0, PointerType.Mouse, true),
|
new Pointer(0, PointerType.Mouse, true),
|
||||||
root,
|
root,
|
||||||
this.TranslatePoint(point, root).Value,
|
this.TranslatePoint(point, root).Value,
|
||||||
(ulong)Environment.TickCount64,
|
(ulong)Environment.TickCount64,
|
||||||
@@ -176,7 +189,7 @@ namespace Ryujinx.Ava.Ui.Controls
|
|||||||
this.RaiseEvent(new PointerEventArgs(
|
this.RaiseEvent(new PointerEventArgs(
|
||||||
PointerMovedEvent,
|
PointerMovedEvent,
|
||||||
this,
|
this,
|
||||||
new Avalonia.Input.Pointer(0, PointerType.Mouse, true),
|
new Pointer(0, PointerType.Mouse, true),
|
||||||
root,
|
root,
|
||||||
this.TranslatePoint(point, root).Value,
|
this.TranslatePoint(point, root).Value,
|
||||||
(ulong)Environment.TickCount64,
|
(ulong)Environment.TickCount64,
|
||||||
@@ -187,6 +200,16 @@ namespace Ryujinx.Ava.Ui.Controls
|
|||||||
return DefWindowProc(hWnd, msg, (IntPtr)wParam, (IntPtr)lParam);
|
return DefWindowProc(hWnd, msg, (IntPtr)wParam, (IntPtr)lParam);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[SupportedOSPlatform("macos")]
|
||||||
|
IPlatformHandle CreateMacOs(IPlatformHandle parent)
|
||||||
|
{
|
||||||
|
MetalLayer = MetalHelper.GetMetalLayer(out IntPtr nsView, out _updateBoundsCallback);
|
||||||
|
|
||||||
|
NsView = nsView;
|
||||||
|
|
||||||
|
return new PlatformHandle(nsView, "NSView");
|
||||||
|
}
|
||||||
|
|
||||||
void DestroyLinux()
|
void DestroyLinux()
|
||||||
{
|
{
|
||||||
X11Window?.Dispose();
|
X11Window?.Dispose();
|
||||||
@@ -198,5 +221,11 @@ namespace Ryujinx.Ava.Ui.Controls
|
|||||||
DestroyWindow(handle.Handle);
|
DestroyWindow(handle.Handle);
|
||||||
UnregisterClass(_className, GetModuleHandle(null));
|
UnregisterClass(_className, GetModuleHandle(null));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[SupportedOSPlatform("macos")]
|
||||||
|
void DestroyMacOS()
|
||||||
|
{
|
||||||
|
MetalHelper.DestroyMetalLayer(NsView, MetalLayer);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -138,6 +138,9 @@
|
|||||||
<Style Selector="ListBoxItem:selected /template/ ContentPresenter">
|
<Style Selector="ListBoxItem:selected /template/ ContentPresenter">
|
||||||
<Setter Property="Background" Value="{DynamicResource AppListBackgroundColor}" />
|
<Setter Property="Background" Value="{DynamicResource AppListBackgroundColor}" />
|
||||||
</Style>
|
</Style>
|
||||||
|
<Style Selector="ListBoxItem:selected /template/ Border#SelectionIndicator">
|
||||||
|
<Setter Property="MinHeight" Value="100" />
|
||||||
|
</Style>
|
||||||
<Style Selector="ListBoxItem:pointerover /template/ ContentPresenter">
|
<Style Selector="ListBoxItem:pointerover /template/ ContentPresenter">
|
||||||
<Setter Property="Background" Value="{DynamicResource AppListHoverBackgroundColor}" />
|
<Setter Property="Background" Value="{DynamicResource AppListHoverBackgroundColor}" />
|
||||||
</Style>
|
</Style>
|
||||||
|
@@ -3,6 +3,7 @@ using Ryujinx.Ava.Ui.Controls;
|
|||||||
using Silk.NET.Vulkan;
|
using Silk.NET.Vulkan;
|
||||||
using SPB.Graphics.Vulkan;
|
using SPB.Graphics.Vulkan;
|
||||||
using SPB.Platform.GLX;
|
using SPB.Platform.GLX;
|
||||||
|
using SPB.Platform.Metal;
|
||||||
using SPB.Platform.Win32;
|
using SPB.Platform.Win32;
|
||||||
using SPB.Platform.X11;
|
using SPB.Platform.X11;
|
||||||
using SPB.Windowing;
|
using SPB.Windowing;
|
||||||
@@ -37,6 +38,10 @@ namespace Ryujinx.Ava.Ui
|
|||||||
{
|
{
|
||||||
_window = new SimpleX11Window(new NativeHandle(X11Display), new NativeHandle(WindowHandle));
|
_window = new SimpleX11Window(new NativeHandle(X11Display), new NativeHandle(WindowHandle));
|
||||||
}
|
}
|
||||||
|
else if (OperatingSystem.IsMacOS())
|
||||||
|
{
|
||||||
|
_window = new SimpleMetalWindow(new NativeHandle(NsView), new NativeHandle(MetalLayer));
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
throw new PlatformNotSupportedException();
|
throw new PlatformNotSupportedException();
|
||||||
|
@@ -1,45 +0,0 @@
|
|||||||
using Ryujinx.Ui.App.Common;
|
|
||||||
using System.Collections;
|
|
||||||
|
|
||||||
namespace Ryujinx.Ava.Ui.Models
|
|
||||||
{
|
|
||||||
internal class FileSizeSortComparer : IComparer
|
|
||||||
{
|
|
||||||
public int Compare(object x, object y)
|
|
||||||
{
|
|
||||||
string aValue = (x as ApplicationData).TimePlayed;
|
|
||||||
string bValue = (y as ApplicationData).TimePlayed;
|
|
||||||
|
|
||||||
if (aValue[^3..] == "GiB")
|
|
||||||
{
|
|
||||||
aValue = (float.Parse(aValue[0..^3]) * 1024).ToString();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
aValue = aValue[0..^3];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (bValue[^3..] == "GiB")
|
|
||||||
{
|
|
||||||
bValue = (float.Parse(bValue[0..^3]) * 1024).ToString();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
bValue = bValue[0..^3];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (float.Parse(aValue) > float.Parse(bValue))
|
|
||||||
{
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
else if (float.Parse(bValue) > float.Parse(aValue))
|
|
||||||
{
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,50 +0,0 @@
|
|||||||
using Ryujinx.Ui.App.Common;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
|
|
||||||
namespace Ryujinx.Ava.Ui.Models.Generic
|
|
||||||
{
|
|
||||||
internal class FileSizeSortComparer : IComparer<ApplicationData>
|
|
||||||
{
|
|
||||||
public FileSizeSortComparer() { }
|
|
||||||
public FileSizeSortComparer(bool isAscending) { _order = isAscending ? 1 : -1; }
|
|
||||||
|
|
||||||
private int _order;
|
|
||||||
|
|
||||||
public int Compare(ApplicationData x, ApplicationData y)
|
|
||||||
{
|
|
||||||
string aValue = x.FileSize;
|
|
||||||
string bValue = y.FileSize;
|
|
||||||
|
|
||||||
if (aValue[^3..] == "GiB")
|
|
||||||
{
|
|
||||||
aValue = (float.Parse(aValue[0..^3]) * 1024).ToString();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
aValue = aValue[0..^3];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (bValue[^3..] == "GiB")
|
|
||||||
{
|
|
||||||
bValue = (float.Parse(bValue[0..^3]) * 1024).ToString();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
bValue = bValue[0..^3];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (float.Parse(aValue) > float.Parse(bValue))
|
|
||||||
{
|
|
||||||
return -1 * _order;
|
|
||||||
}
|
|
||||||
else if (float.Parse(bValue) > float.Parse(aValue))
|
|
||||||
{
|
|
||||||
return 1 * _order;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,66 +0,0 @@
|
|||||||
using Ryujinx.Ui.App.Common;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
|
|
||||||
namespace Ryujinx.Ava.Ui.Models.Generic
|
|
||||||
{
|
|
||||||
internal class TimePlayedSortComparer : IComparer<ApplicationData>
|
|
||||||
{
|
|
||||||
public TimePlayedSortComparer() { }
|
|
||||||
public TimePlayedSortComparer(bool isAscending) { _order = isAscending ? 1 : -1; }
|
|
||||||
|
|
||||||
private int _order;
|
|
||||||
|
|
||||||
public int Compare(ApplicationData x, ApplicationData y)
|
|
||||||
{
|
|
||||||
string aValue = x.TimePlayed;
|
|
||||||
string bValue = y.TimePlayed;
|
|
||||||
|
|
||||||
if (aValue.Length > 4 && aValue[^4..] == "mins")
|
|
||||||
{
|
|
||||||
aValue = (float.Parse(aValue[0..^5]) * 60).ToString();
|
|
||||||
}
|
|
||||||
else if (aValue.Length > 3 && aValue[^3..] == "hrs")
|
|
||||||
{
|
|
||||||
aValue = (float.Parse(aValue[0..^4]) * 3600).ToString();
|
|
||||||
}
|
|
||||||
else if (aValue.Length > 4 && aValue[^4..] == "days")
|
|
||||||
{
|
|
||||||
aValue = (float.Parse(aValue[0..^5]) * 86400).ToString();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
aValue = aValue[0..^1];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (bValue.Length > 4 && bValue[^4..] == "mins")
|
|
||||||
{
|
|
||||||
bValue = (float.Parse(bValue[0..^5]) * 60).ToString();
|
|
||||||
}
|
|
||||||
else if (bValue.Length > 3 && bValue[^3..] == "hrs")
|
|
||||||
{
|
|
||||||
bValue = (float.Parse(bValue[0..^4]) * 3600).ToString();
|
|
||||||
}
|
|
||||||
else if (bValue.Length > 4 && bValue[^4..] == "days")
|
|
||||||
{
|
|
||||||
bValue = (float.Parse(bValue[0..^5]) * 86400).ToString();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
bValue = bValue[0..^1];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (float.Parse(aValue) > float.Parse(bValue))
|
|
||||||
{
|
|
||||||
return -1 * _order;
|
|
||||||
}
|
|
||||||
else if (float.Parse(bValue) > float.Parse(aValue))
|
|
||||||
{
|
|
||||||
return 1 * _order;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,27 +0,0 @@
|
|||||||
using Ryujinx.Ui.App.Common;
|
|
||||||
using System;
|
|
||||||
using System.Collections;
|
|
||||||
|
|
||||||
namespace Ryujinx.Ava.Ui.Models
|
|
||||||
{
|
|
||||||
internal class LastPlayedSortComparer : IComparer
|
|
||||||
{
|
|
||||||
public int Compare(object x, object y)
|
|
||||||
{
|
|
||||||
string aValue = (x as ApplicationData).LastPlayed;
|
|
||||||
string bValue = (y as ApplicationData).LastPlayed;
|
|
||||||
|
|
||||||
if (aValue == "Never")
|
|
||||||
{
|
|
||||||
aValue = DateTime.UnixEpoch.ToString();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (bValue == "Never")
|
|
||||||
{
|
|
||||||
bValue = DateTime.UnixEpoch.ToString();
|
|
||||||
}
|
|
||||||
|
|
||||||
return DateTime.Compare(DateTime.Parse(bValue), DateTime.Parse(aValue));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,61 +0,0 @@
|
|||||||
using Ryujinx.Ui.App.Common;
|
|
||||||
using System.Collections;
|
|
||||||
|
|
||||||
namespace Ryujinx.Ava.Ui.Models
|
|
||||||
{
|
|
||||||
internal class TimePlayedSortComparer : IComparer
|
|
||||||
{
|
|
||||||
public int Compare(object x, object y)
|
|
||||||
{
|
|
||||||
string aValue = (x as ApplicationData).TimePlayed;
|
|
||||||
string bValue = (y as ApplicationData).TimePlayed;
|
|
||||||
|
|
||||||
if (aValue.Length > 4 && aValue[^4..] == "mins")
|
|
||||||
{
|
|
||||||
aValue = (float.Parse(aValue[0..^5]) * 60).ToString();
|
|
||||||
}
|
|
||||||
else if (aValue.Length > 3 && aValue[^3..] == "hrs")
|
|
||||||
{
|
|
||||||
aValue = (float.Parse(aValue[0..^4]) * 3600).ToString();
|
|
||||||
}
|
|
||||||
else if (aValue.Length > 4 && aValue[^4..] == "days")
|
|
||||||
{
|
|
||||||
aValue = (float.Parse(aValue[0..^5]) * 86400).ToString();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
aValue = aValue[0..^1];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (bValue.Length > 4 && bValue[^4..] == "mins")
|
|
||||||
{
|
|
||||||
bValue = (float.Parse(bValue[0..^5]) * 60).ToString();
|
|
||||||
}
|
|
||||||
else if (bValue.Length > 3 && bValue[^3..] == "hrs")
|
|
||||||
{
|
|
||||||
bValue = (float.Parse(bValue[0..^4]) * 3600).ToString();
|
|
||||||
}
|
|
||||||
else if (bValue.Length > 4 && bValue[^4..] == "days")
|
|
||||||
{
|
|
||||||
bValue = (float.Parse(bValue[0..^5]) * 86400).ToString();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
bValue = bValue[0..^1];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (float.Parse(aValue) > float.Parse(bValue))
|
|
||||||
{
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
else if (float.Parse(bValue) > float.Parse(aValue))
|
|
||||||
{
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@@ -545,7 +545,7 @@ namespace Ryujinx.Ava.Ui.ViewModels
|
|||||||
|
|
||||||
config = new StandardKeyboardInputConfig
|
config = new StandardKeyboardInputConfig
|
||||||
{
|
{
|
||||||
Version = Ryujinx.Common.Configuration.Hid.InputConfig.CurrentVersion,
|
Version = InputConfig.CurrentVersion,
|
||||||
Backend = InputBackendType.WindowKeyboard,
|
Backend = InputBackendType.WindowKeyboard,
|
||||||
Id = id,
|
Id = id,
|
||||||
ControllerType = ControllerType.ProController,
|
ControllerType = ControllerType.ProController,
|
||||||
@@ -600,7 +600,7 @@ namespace Ryujinx.Ava.Ui.ViewModels
|
|||||||
|
|
||||||
config = new StandardControllerInputConfig
|
config = new StandardControllerInputConfig
|
||||||
{
|
{
|
||||||
Version = Ryujinx.Common.Configuration.Hid.InputConfig.CurrentVersion,
|
Version = InputConfig.CurrentVersion,
|
||||||
Backend = InputBackendType.GamepadSDL2,
|
Backend = InputBackendType.GamepadSDL2,
|
||||||
Id = id,
|
Id = id,
|
||||||
ControllerType = ControllerType.ProController,
|
ControllerType = ControllerType.ProController,
|
||||||
|
@@ -502,8 +502,10 @@ namespace Ryujinx.Ava.Ui.ViewModels
|
|||||||
return SortMode switch
|
return SortMode switch
|
||||||
{
|
{
|
||||||
ApplicationSort.LastPlayed => new Models.Generic.LastPlayedSortComparer(IsAscending),
|
ApplicationSort.LastPlayed => new Models.Generic.LastPlayedSortComparer(IsAscending),
|
||||||
ApplicationSort.FileSize => new Models.Generic.FileSizeSortComparer(IsAscending),
|
ApplicationSort.FileSize => IsAscending ? SortExpressionComparer<ApplicationData>.Ascending(app => app.FileSizeBytes)
|
||||||
ApplicationSort.TotalTimePlayed => new Models.Generic.TimePlayedSortComparer(IsAscending),
|
: SortExpressionComparer<ApplicationData>.Descending(app => app.FileSizeBytes),
|
||||||
|
ApplicationSort.TotalTimePlayed => IsAscending ? SortExpressionComparer<ApplicationData>.Ascending(app => app.TimePlayedNum)
|
||||||
|
: SortExpressionComparer<ApplicationData>.Descending(app => app.TimePlayedNum),
|
||||||
ApplicationSort.Title => IsAscending ? SortExpressionComparer<ApplicationData>.Ascending(app => app.TitleName)
|
ApplicationSort.Title => IsAscending ? SortExpressionComparer<ApplicationData>.Ascending(app => app.TitleName)
|
||||||
: SortExpressionComparer<ApplicationData>.Descending(app => app.TitleName),
|
: SortExpressionComparer<ApplicationData>.Descending(app => app.TitleName),
|
||||||
ApplicationSort.Favorite => !IsAscending ? SortExpressionComparer<ApplicationData>.Ascending(app => app.Favorite)
|
ApplicationSort.Favorite => !IsAscending ? SortExpressionComparer<ApplicationData>.Ascending(app => app.Favorite)
|
||||||
@@ -881,17 +883,17 @@ namespace Ryujinx.Ava.Ui.ViewModels
|
|||||||
|
|
||||||
public void LoadConfigurableHotKeys()
|
public void LoadConfigurableHotKeys()
|
||||||
{
|
{
|
||||||
if (AvaloniaMappingHelper.TryGetAvaKey((Ryujinx.Input.Key)ConfigurationState.Instance.Hid.Hotkeys.Value.ShowUi, out var showUiKey))
|
if (AvaloniaKeyboardMappingHelper.TryGetAvaKey((Ryujinx.Input.Key)ConfigurationState.Instance.Hid.Hotkeys.Value.ShowUi, out var showUiKey))
|
||||||
{
|
{
|
||||||
ShowUiKey = new KeyGesture(showUiKey, KeyModifiers.None);
|
ShowUiKey = new KeyGesture(showUiKey, KeyModifiers.None);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (AvaloniaMappingHelper.TryGetAvaKey((Ryujinx.Input.Key)ConfigurationState.Instance.Hid.Hotkeys.Value.Screenshot, out var screenshotKey))
|
if (AvaloniaKeyboardMappingHelper.TryGetAvaKey((Ryujinx.Input.Key)ConfigurationState.Instance.Hid.Hotkeys.Value.Screenshot, out var screenshotKey))
|
||||||
{
|
{
|
||||||
ScreenshotKey = new KeyGesture(screenshotKey, KeyModifiers.None);
|
ScreenshotKey = new KeyGesture(screenshotKey, KeyModifiers.None);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (AvaloniaMappingHelper.TryGetAvaKey((Ryujinx.Input.Key)ConfigurationState.Instance.Hid.Hotkeys.Value.Pause, out var pauseKey))
|
if (AvaloniaKeyboardMappingHelper.TryGetAvaKey((Ryujinx.Input.Key)ConfigurationState.Instance.Hid.Hotkeys.Value.Pause, out var pauseKey))
|
||||||
{
|
{
|
||||||
PauseKey = new KeyGesture(pauseKey, KeyModifiers.None);
|
PauseKey = new KeyGesture(pauseKey, KeyModifiers.None);
|
||||||
}
|
}
|
||||||
|
@@ -108,6 +108,8 @@ namespace Ryujinx.Ava.Ui.ViewModels
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool IsOpenGLAvailable => !OperatingSystem.IsMacOS();
|
||||||
|
|
||||||
public bool DirectoryChanged
|
public bool DirectoryChanged
|
||||||
{
|
{
|
||||||
get => _directoryChanged;
|
get => _directoryChanged;
|
||||||
|
@@ -104,11 +104,11 @@ namespace Ryujinx.Ava.Ui.Windows
|
|||||||
|
|
||||||
var device = ViewModel.Devices[ViewModel.Device];
|
var device = ViewModel.Devices[ViewModel.Device];
|
||||||
|
|
||||||
if (device.Type == Models.DeviceType.Keyboard)
|
if (device.Type == DeviceType.Keyboard)
|
||||||
{
|
{
|
||||||
assigner = new KeyboardKeyAssigner((IKeyboard)ViewModel.SelectedGamepad);
|
assigner = new KeyboardKeyAssigner((IKeyboard)ViewModel.SelectedGamepad);
|
||||||
}
|
}
|
||||||
else if (device.Type == Models.DeviceType.Controller)
|
else if (device.Type == DeviceType.Controller)
|
||||||
{
|
{
|
||||||
assigner = new GamepadButtonAssigner(ViewModel.SelectedGamepad, (ViewModel.Config as StandardControllerInputConfig).TriggerThreshold, forStick);
|
assigner = new GamepadButtonAssigner(ViewModel.SelectedGamepad, (ViewModel.Config as StandardControllerInputConfig).TriggerThreshold, forStick);
|
||||||
}
|
}
|
||||||
|
@@ -12,9 +12,9 @@
|
|||||||
xmlns:window="clr-namespace:Ryujinx.Ava.Ui.Windows"
|
xmlns:window="clr-namespace:Ryujinx.Ava.Ui.Windows"
|
||||||
Title="Ryujinx"
|
Title="Ryujinx"
|
||||||
Width="1280"
|
Width="1280"
|
||||||
Height="785"
|
Height="777"
|
||||||
MinWidth="1092"
|
MinWidth="1092"
|
||||||
MinHeight="680"
|
MinHeight="672"
|
||||||
d:DesignHeight="720"
|
d:DesignHeight="720"
|
||||||
d:DesignWidth="1280"
|
d:DesignWidth="1280"
|
||||||
x:CompileBindings="True"
|
x:CompileBindings="True"
|
||||||
@@ -552,9 +552,8 @@
|
|||||||
<Grid
|
<Grid
|
||||||
Name="StatusBar"
|
Name="StatusBar"
|
||||||
Grid.Row="2"
|
Grid.Row="2"
|
||||||
MinHeight="30"
|
Margin="0"
|
||||||
Height="30"
|
MinHeight="22"
|
||||||
Margin="0,0"
|
|
||||||
HorizontalAlignment="Stretch"
|
HorizontalAlignment="Stretch"
|
||||||
VerticalAlignment="Bottom"
|
VerticalAlignment="Bottom"
|
||||||
Background="{DynamicResource ThemeContentBackgroundColor}"
|
Background="{DynamicResource ThemeContentBackgroundColor}"
|
||||||
@@ -568,7 +567,7 @@
|
|||||||
</Grid.ColumnDefinitions>
|
</Grid.ColumnDefinitions>
|
||||||
<StackPanel
|
<StackPanel
|
||||||
Grid.Column="0"
|
Grid.Column="0"
|
||||||
Margin="10,0"
|
Margin="5"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
IsVisible="{Binding EnableNonGameRunningControls}">
|
IsVisible="{Binding EnableNonGameRunningControls}">
|
||||||
<Grid Margin="0">
|
<Grid Margin="0">
|
||||||
@@ -610,14 +609,14 @@
|
|||||||
</StackPanel>
|
</StackPanel>
|
||||||
<StackPanel
|
<StackPanel
|
||||||
Grid.Column="1"
|
Grid.Column="1"
|
||||||
Margin="10,0"
|
Margin="0,2"
|
||||||
HorizontalAlignment="Left"
|
HorizontalAlignment="Left"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
IsVisible="{Binding IsGameRunning}"
|
IsVisible="{Binding IsGameRunning}"
|
||||||
Orientation="Horizontal">
|
Orientation="Horizontal">
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Name="VsyncStatus"
|
Name="VsyncStatus"
|
||||||
Margin="0,0,5,0"
|
Margin="5,0,5,0"
|
||||||
HorizontalAlignment="Left"
|
HorizontalAlignment="Left"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
Foreground="{Binding VsyncColor}"
|
Foreground="{Binding VsyncColor}"
|
||||||
@@ -628,7 +627,7 @@
|
|||||||
<Border
|
<Border
|
||||||
Width="2"
|
Width="2"
|
||||||
Height="12"
|
Height="12"
|
||||||
Margin="2,0"
|
Margin="0"
|
||||||
BorderBrush="Gray"
|
BorderBrush="Gray"
|
||||||
BorderThickness="1"
|
BorderThickness="1"
|
||||||
IsVisible="{Binding !ShowLoadProgress}" />
|
IsVisible="{Binding !ShowLoadProgress}" />
|
||||||
@@ -644,7 +643,7 @@
|
|||||||
<Border
|
<Border
|
||||||
Width="2"
|
Width="2"
|
||||||
Height="12"
|
Height="12"
|
||||||
Margin="2,0"
|
Margin="0"
|
||||||
BorderBrush="Gray"
|
BorderBrush="Gray"
|
||||||
BorderThickness="1"
|
BorderThickness="1"
|
||||||
IsVisible="{Binding !ShowLoadProgress}" />
|
IsVisible="{Binding !ShowLoadProgress}" />
|
||||||
@@ -660,13 +659,13 @@
|
|||||||
<Border
|
<Border
|
||||||
Width="2"
|
Width="2"
|
||||||
Height="12"
|
Height="12"
|
||||||
Margin="2,0"
|
Margin="0"
|
||||||
BorderBrush="Gray"
|
BorderBrush="Gray"
|
||||||
BorderThickness="1"
|
BorderThickness="1"
|
||||||
IsVisible="{Binding !ShowLoadProgress}" />
|
IsVisible="{Binding !ShowLoadProgress}" />
|
||||||
<ui:ToggleSplitButton
|
<ui:ToggleSplitButton
|
||||||
Name="VolumeStatus"
|
Name="VolumeStatus"
|
||||||
Padding="5"
|
Padding="5,0,5,0"
|
||||||
HorizontalAlignment="Left"
|
HorizontalAlignment="Left"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
VerticalContentAlignment="Center"
|
VerticalContentAlignment="Center"
|
||||||
@@ -679,6 +678,7 @@
|
|||||||
<Flyout Placement="Bottom" ShowMode="TransientWithDismissOnPointerMoveAway">
|
<Flyout Placement="Bottom" ShowMode="TransientWithDismissOnPointerMoveAway">
|
||||||
<Grid Margin="0">
|
<Grid Margin="0">
|
||||||
<Slider
|
<Slider
|
||||||
|
MaxHeight="40"
|
||||||
Width="150"
|
Width="150"
|
||||||
Margin="0"
|
Margin="0"
|
||||||
Padding="0"
|
Padding="0"
|
||||||
@@ -697,7 +697,7 @@
|
|||||||
<Border
|
<Border
|
||||||
Width="2"
|
Width="2"
|
||||||
Height="12"
|
Height="12"
|
||||||
Margin="2,0"
|
Margin="0"
|
||||||
BorderBrush="Gray"
|
BorderBrush="Gray"
|
||||||
BorderThickness="1"
|
BorderThickness="1"
|
||||||
IsVisible="{Binding !ShowLoadProgress}" />
|
IsVisible="{Binding !ShowLoadProgress}" />
|
||||||
@@ -711,7 +711,7 @@
|
|||||||
<Border
|
<Border
|
||||||
Width="2"
|
Width="2"
|
||||||
Height="12"
|
Height="12"
|
||||||
Margin="2,0"
|
Margin="0"
|
||||||
BorderBrush="Gray"
|
BorderBrush="Gray"
|
||||||
BorderThickness="1"
|
BorderThickness="1"
|
||||||
IsVisible="{Binding !ShowLoadProgress}" />
|
IsVisible="{Binding !ShowLoadProgress}" />
|
||||||
@@ -725,7 +725,7 @@
|
|||||||
<Border
|
<Border
|
||||||
Width="2"
|
Width="2"
|
||||||
Height="12"
|
Height="12"
|
||||||
Margin="2,0"
|
Margin="0"
|
||||||
BorderBrush="Gray"
|
BorderBrush="Gray"
|
||||||
BorderThickness="1"
|
BorderThickness="1"
|
||||||
IsVisible="{Binding !ShowLoadProgress}" />
|
IsVisible="{Binding !ShowLoadProgress}" />
|
||||||
@@ -739,7 +739,7 @@
|
|||||||
<Border
|
<Border
|
||||||
Width="2"
|
Width="2"
|
||||||
Height="12"
|
Height="12"
|
||||||
Margin="2,0"
|
Margin="0"
|
||||||
BorderBrush="Gray"
|
BorderBrush="Gray"
|
||||||
BorderThickness="1"
|
BorderThickness="1"
|
||||||
IsVisible="{Binding !ShowLoadProgress}" />
|
IsVisible="{Binding !ShowLoadProgress}" />
|
||||||
@@ -753,7 +753,7 @@
|
|||||||
</StackPanel>
|
</StackPanel>
|
||||||
<StackPanel
|
<StackPanel
|
||||||
Grid.Column="3"
|
Grid.Column="3"
|
||||||
Margin="10,0"
|
Margin="0,0,5,0"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
IsVisible="{Binding ShowFirmwareStatus}"
|
IsVisible="{Binding ShowFirmwareStatus}"
|
||||||
Orientation="Horizontal">
|
Orientation="Horizontal">
|
||||||
|
@@ -154,6 +154,12 @@ namespace Ryujinx.Ava.Ui.Windows
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override void HandleScalingChanged(double scale)
|
||||||
|
{
|
||||||
|
Program.DesktopScaleFactor = scale;
|
||||||
|
base.HandleScalingChanged(scale);
|
||||||
|
}
|
||||||
|
|
||||||
public void Application_Opened(object sender, ApplicationOpenedEventArgs args)
|
public void Application_Opened(object sender, ApplicationOpenedEventArgs args)
|
||||||
{
|
{
|
||||||
if (args.Application != null)
|
if (args.Application != null)
|
||||||
|
@@ -540,7 +540,7 @@
|
|||||||
<ComboBoxItem IsVisible="{Binding IsVulkanAvailable}">
|
<ComboBoxItem IsVisible="{Binding IsVulkanAvailable}">
|
||||||
<TextBlock Text="Vulkan" />
|
<TextBlock Text="Vulkan" />
|
||||||
</ComboBoxItem>
|
</ComboBoxItem>
|
||||||
<ComboBoxItem>
|
<ComboBoxItem IsEnabled="{Binding IsOpenGLAvailable}">
|
||||||
<TextBlock Text="OpenGL" />
|
<TextBlock Text="OpenGL" />
|
||||||
</ComboBoxItem>
|
</ComboBoxItem>
|
||||||
</ComboBox>
|
</ComboBox>
|
||||||
@@ -876,7 +876,7 @@
|
|||||||
</StackPanel>
|
</StackPanel>
|
||||||
<StackPanel Margin="0,10,0,0" Orientation="Horizontal">
|
<StackPanel Margin="0,10,0,0" Orientation="Horizontal">
|
||||||
<TextBlock VerticalAlignment="Center"
|
<TextBlock VerticalAlignment="Center"
|
||||||
Text="{locale:Locale SettingsTabLoggingOpenglLogLevel}"
|
Text="{locale:Locale SettingsTabLoggingGraphicsBackendLogLevel}"
|
||||||
ToolTip.Tip="{locale:Locale OpenGlLogLevel}"
|
ToolTip.Tip="{locale:Locale OpenGlLogLevel}"
|
||||||
Width="285" />
|
Width="285" />
|
||||||
<ComboBox SelectedIndex="{Binding OpenglDebugLevel}"
|
<ComboBox SelectedIndex="{Binding OpenglDebugLevel}"
|
||||||
@@ -884,17 +884,17 @@
|
|||||||
HorizontalContentAlignment="Left"
|
HorizontalContentAlignment="Left"
|
||||||
ToolTip.Tip="{locale:Locale OpenGlLogLevel}">
|
ToolTip.Tip="{locale:Locale OpenGlLogLevel}">
|
||||||
<ComboBoxItem>
|
<ComboBoxItem>
|
||||||
<TextBlock Text="{locale:Locale SettingsTabLoggingOpenglLogLevelNone}" />
|
<TextBlock Text="{locale:Locale SettingsTabLoggingGraphicsBackendLogLevelNone}" />
|
||||||
</ComboBoxItem>
|
</ComboBoxItem>
|
||||||
<ComboBoxItem>
|
<ComboBoxItem>
|
||||||
<TextBlock Text="{locale:Locale SettingsTabLoggingOpenglLogLevelError}" />
|
<TextBlock Text="{locale:Locale SettingsTabLoggingGraphicsBackendLogLevelError}" />
|
||||||
</ComboBoxItem>
|
</ComboBoxItem>
|
||||||
<ComboBoxItem>
|
<ComboBoxItem>
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Text="{locale:Locale SettingsTabLoggingOpenglLogLevelPerformance}" />
|
Text="{locale:Locale SettingsTabLoggingGraphicsBackendLogLevelPerformance}" />
|
||||||
</ComboBoxItem>
|
</ComboBoxItem>
|
||||||
<ComboBoxItem>
|
<ComboBoxItem>
|
||||||
<TextBlock Text="{locale:Locale SettingsTabLoggingOpenglLogLevelAll}" />
|
<TextBlock Text="{locale:Locale SettingsTabLoggingGraphicsBackendLogLevelAll}" />
|
||||||
</ComboBoxItem>
|
</ComboBoxItem>
|
||||||
</ComboBox>
|
</ComboBox>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
@@ -45,7 +45,14 @@ namespace Ryujinx.Common.Configuration
|
|||||||
|
|
||||||
public static void Initialize(string baseDirPath)
|
public static void Initialize(string baseDirPath)
|
||||||
{
|
{
|
||||||
string userProfilePath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), DefaultBaseDir);
|
string appDataPath = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
|
||||||
|
|
||||||
|
if (appDataPath.Length == 0)
|
||||||
|
{
|
||||||
|
appDataPath = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile);
|
||||||
|
}
|
||||||
|
|
||||||
|
string userProfilePath = Path.Combine(appDataPath, DefaultBaseDir);
|
||||||
string portablePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, DefaultPortableDir);
|
string portablePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, DefaultPortableDir);
|
||||||
|
|
||||||
if (Directory.Exists(portablePath))
|
if (Directory.Exists(portablePath))
|
||||||
|
@@ -8,7 +8,7 @@ namespace Ryujinx.Common.Memory.PartialUnmaps
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// A simple implementation of a ReaderWriterLock which can be used from native code.
|
/// A simple implementation of a ReaderWriterLock which can be used from native code.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
[StructLayout(LayoutKind.Sequential, Pack = 4)]
|
||||||
public struct NativeReaderWriterLock
|
public struct NativeReaderWriterLock
|
||||||
{
|
{
|
||||||
public int WriteLock;
|
public int WriteLock;
|
||||||
|
@@ -7,7 +7,6 @@
|
|||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="MsgPack.Cli" Version="1.0.1" />
|
<PackageReference Include="MsgPack.Cli" Version="1.0.1" />
|
||||||
<PackageReference Include="System.Drawing.Common" Version="6.0.0" />
|
|
||||||
<PackageReference Include="System.Management" Version="7.0.0" />
|
<PackageReference Include="System.Management" Version="7.0.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
@@ -1,6 +1,5 @@
|
|||||||
using Ryujinx.Common.Logging;
|
using Ryujinx.Common.Logging;
|
||||||
using System;
|
using System;
|
||||||
using System.Drawing;
|
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
@@ -51,7 +50,7 @@ namespace Ryujinx.Common.System
|
|||||||
{
|
{
|
||||||
if (OperatingSystem.IsWindows())
|
if (OperatingSystem.IsWindows())
|
||||||
{
|
{
|
||||||
userDpiScale = Graphics.FromHwnd(IntPtr.Zero).DpiX;
|
userDpiScale = GdiPlusHelper.GetDpiX(IntPtr.Zero);
|
||||||
}
|
}
|
||||||
else if (OperatingSystem.IsLinux())
|
else if (OperatingSystem.IsLinux())
|
||||||
{
|
{
|
||||||
|
76
Ryujinx.Common/System/GdiPlusHelper.cs
Normal file
76
Ryujinx.Common/System/GdiPlusHelper.cs
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
using System;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using System.Runtime.Versioning;
|
||||||
|
|
||||||
|
namespace Ryujinx.Common.System
|
||||||
|
{
|
||||||
|
[SupportedOSPlatform("windows")]
|
||||||
|
public static class GdiPlusHelper
|
||||||
|
{
|
||||||
|
private const string LibraryName = "gdiplus.dll";
|
||||||
|
|
||||||
|
private static readonly IntPtr _initToken;
|
||||||
|
|
||||||
|
static GdiPlusHelper()
|
||||||
|
{
|
||||||
|
CheckStatus(GdiplusStartup(out _initToken, StartupInputEx.Default, out _));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void CheckStatus(int gdiStatus)
|
||||||
|
{
|
||||||
|
if (gdiStatus != 0)
|
||||||
|
{
|
||||||
|
throw new Exception($"GDI Status Error: {gdiStatus}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private struct StartupInputEx
|
||||||
|
{
|
||||||
|
public int GdiplusVersion;
|
||||||
|
|
||||||
|
#pragma warning disable CS0649
|
||||||
|
public IntPtr DebugEventCallback;
|
||||||
|
public int SuppressBackgroundThread;
|
||||||
|
public int SuppressExternalCodecs;
|
||||||
|
public int StartupParameters;
|
||||||
|
#pragma warning restore CS0649
|
||||||
|
|
||||||
|
public static StartupInputEx Default => new StartupInputEx
|
||||||
|
{
|
||||||
|
// We assume Windows 8 and upper
|
||||||
|
GdiplusVersion = 2,
|
||||||
|
DebugEventCallback = IntPtr.Zero,
|
||||||
|
SuppressBackgroundThread = 0,
|
||||||
|
SuppressExternalCodecs = 0,
|
||||||
|
StartupParameters = 0,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private struct StartupOutput
|
||||||
|
{
|
||||||
|
public IntPtr NotificationHook;
|
||||||
|
public IntPtr NotificationUnhook;
|
||||||
|
}
|
||||||
|
|
||||||
|
[DllImport(LibraryName)]
|
||||||
|
private static extern int GdiplusStartup(out IntPtr token, in StartupInputEx input, out StartupOutput output);
|
||||||
|
|
||||||
|
[DllImport(LibraryName)]
|
||||||
|
private static extern int GdipCreateFromHWND(IntPtr hwnd, out IntPtr graphics);
|
||||||
|
|
||||||
|
[DllImport(LibraryName)]
|
||||||
|
private static extern int GdipDeleteGraphics(IntPtr graphics);
|
||||||
|
|
||||||
|
[DllImport(LibraryName)]
|
||||||
|
private static extern int GdipGetDpiX(IntPtr graphics, out float dpi);
|
||||||
|
|
||||||
|
public static float GetDpiX(IntPtr hwnd)
|
||||||
|
{
|
||||||
|
CheckStatus(GdipCreateFromHWND(hwnd, out IntPtr graphicsHandle));
|
||||||
|
CheckStatus(GdipGetDpiX(graphicsHandle, out float result));
|
||||||
|
CheckStatus(GdipDeleteGraphics(graphicsHandle));
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -50,186 +50,186 @@ namespace Ryujinx.Graphics.GAL.Multithreading
|
|||||||
|
|
||||||
private static void InitLookup()
|
private static void InitLookup()
|
||||||
{
|
{
|
||||||
_lookup[(int)CommandType.Action] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
_lookup[(int)CommandType.Action] = (memory, threaded, renderer) =>
|
||||||
ActionCommand.Run(ref GetCommand<ActionCommand>(memory), threaded, renderer);
|
ActionCommand.Run(ref GetCommand<ActionCommand>(memory), threaded, renderer);
|
||||||
_lookup[(int)CommandType.CreateBuffer] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
_lookup[(int)CommandType.CreateBuffer] = (memory, threaded, renderer) =>
|
||||||
CreateBufferCommand.Run(ref GetCommand<CreateBufferCommand>(memory), threaded, renderer);
|
CreateBufferCommand.Run(ref GetCommand<CreateBufferCommand>(memory), threaded, renderer);
|
||||||
_lookup[(int)CommandType.CreateProgram] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
_lookup[(int)CommandType.CreateProgram] = (memory, threaded, renderer) =>
|
||||||
CreateProgramCommand.Run(ref GetCommand<CreateProgramCommand>(memory), threaded, renderer);
|
CreateProgramCommand.Run(ref GetCommand<CreateProgramCommand>(memory), threaded, renderer);
|
||||||
_lookup[(int)CommandType.CreateSampler] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
_lookup[(int)CommandType.CreateSampler] = (memory, threaded, renderer) =>
|
||||||
CreateSamplerCommand.Run(ref GetCommand<CreateSamplerCommand>(memory), threaded, renderer);
|
CreateSamplerCommand.Run(ref GetCommand<CreateSamplerCommand>(memory), threaded, renderer);
|
||||||
_lookup[(int)CommandType.CreateSync] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
_lookup[(int)CommandType.CreateSync] = (memory, threaded, renderer) =>
|
||||||
CreateSyncCommand.Run(ref GetCommand<CreateSyncCommand>(memory), threaded, renderer);
|
CreateSyncCommand.Run(ref GetCommand<CreateSyncCommand>(memory), threaded, renderer);
|
||||||
_lookup[(int)CommandType.CreateTexture] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
_lookup[(int)CommandType.CreateTexture] = (memory, threaded, renderer) =>
|
||||||
CreateTextureCommand.Run(ref GetCommand<CreateTextureCommand>(memory), threaded, renderer);
|
CreateTextureCommand.Run(ref GetCommand<CreateTextureCommand>(memory), threaded, renderer);
|
||||||
_lookup[(int)CommandType.GetCapabilities] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
_lookup[(int)CommandType.GetCapabilities] = (memory, threaded, renderer) =>
|
||||||
GetCapabilitiesCommand.Run(ref GetCommand<GetCapabilitiesCommand>(memory), threaded, renderer);
|
GetCapabilitiesCommand.Run(ref GetCommand<GetCapabilitiesCommand>(memory), threaded, renderer);
|
||||||
_lookup[(int)CommandType.PreFrame] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
_lookup[(int)CommandType.PreFrame] = (memory, threaded, renderer) =>
|
||||||
PreFrameCommand.Run(ref GetCommand<PreFrameCommand>(memory), threaded, renderer);
|
PreFrameCommand.Run(ref GetCommand<PreFrameCommand>(memory), threaded, renderer);
|
||||||
_lookup[(int)CommandType.ReportCounter] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
_lookup[(int)CommandType.ReportCounter] = (memory, threaded, renderer) =>
|
||||||
ReportCounterCommand.Run(ref GetCommand<ReportCounterCommand>(memory), threaded, renderer);
|
ReportCounterCommand.Run(ref GetCommand<ReportCounterCommand>(memory), threaded, renderer);
|
||||||
_lookup[(int)CommandType.ResetCounter] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
_lookup[(int)CommandType.ResetCounter] = (memory, threaded, renderer) =>
|
||||||
ResetCounterCommand.Run(ref GetCommand<ResetCounterCommand>(memory), threaded, renderer);
|
ResetCounterCommand.Run(ref GetCommand<ResetCounterCommand>(memory), threaded, renderer);
|
||||||
_lookup[(int)CommandType.UpdateCounters] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
_lookup[(int)CommandType.UpdateCounters] = (memory, threaded, renderer) =>
|
||||||
UpdateCountersCommand.Run(ref GetCommand<UpdateCountersCommand>(memory), threaded, renderer);
|
UpdateCountersCommand.Run(ref GetCommand<UpdateCountersCommand>(memory), threaded, renderer);
|
||||||
|
|
||||||
_lookup[(int)CommandType.BufferDispose] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
_lookup[(int)CommandType.BufferDispose] = (memory, threaded, renderer) =>
|
||||||
BufferDisposeCommand.Run(ref GetCommand<BufferDisposeCommand>(memory), threaded, renderer);
|
BufferDisposeCommand.Run(ref GetCommand<BufferDisposeCommand>(memory), threaded, renderer);
|
||||||
_lookup[(int)CommandType.BufferGetData] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
_lookup[(int)CommandType.BufferGetData] = (memory, threaded, renderer) =>
|
||||||
BufferGetDataCommand.Run(ref GetCommand<BufferGetDataCommand>(memory), threaded, renderer);
|
BufferGetDataCommand.Run(ref GetCommand<BufferGetDataCommand>(memory), threaded, renderer);
|
||||||
_lookup[(int)CommandType.BufferSetData] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
_lookup[(int)CommandType.BufferSetData] = (memory, threaded, renderer) =>
|
||||||
BufferSetDataCommand.Run(ref GetCommand<BufferSetDataCommand>(memory), threaded, renderer);
|
BufferSetDataCommand.Run(ref GetCommand<BufferSetDataCommand>(memory), threaded, renderer);
|
||||||
|
|
||||||
_lookup[(int)CommandType.CounterEventDispose] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
_lookup[(int)CommandType.CounterEventDispose] = (memory, threaded, renderer) =>
|
||||||
CounterEventDisposeCommand.Run(ref GetCommand<CounterEventDisposeCommand>(memory), threaded, renderer);
|
CounterEventDisposeCommand.Run(ref GetCommand<CounterEventDisposeCommand>(memory), threaded, renderer);
|
||||||
_lookup[(int)CommandType.CounterEventFlush] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
_lookup[(int)CommandType.CounterEventFlush] = (memory, threaded, renderer) =>
|
||||||
CounterEventFlushCommand.Run(ref GetCommand<CounterEventFlushCommand>(memory), threaded, renderer);
|
CounterEventFlushCommand.Run(ref GetCommand<CounterEventFlushCommand>(memory), threaded, renderer);
|
||||||
|
|
||||||
_lookup[(int)CommandType.ProgramDispose] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
_lookup[(int)CommandType.ProgramDispose] = (memory, threaded, renderer) =>
|
||||||
ProgramDisposeCommand.Run(ref GetCommand<ProgramDisposeCommand>(memory), threaded, renderer);
|
ProgramDisposeCommand.Run(ref GetCommand<ProgramDisposeCommand>(memory), threaded, renderer);
|
||||||
_lookup[(int)CommandType.ProgramGetBinary] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
_lookup[(int)CommandType.ProgramGetBinary] = (memory, threaded, renderer) =>
|
||||||
ProgramGetBinaryCommand.Run(ref GetCommand<ProgramGetBinaryCommand>(memory), threaded, renderer);
|
ProgramGetBinaryCommand.Run(ref GetCommand<ProgramGetBinaryCommand>(memory), threaded, renderer);
|
||||||
_lookup[(int)CommandType.ProgramCheckLink] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
_lookup[(int)CommandType.ProgramCheckLink] = (memory, threaded, renderer) =>
|
||||||
ProgramCheckLinkCommand.Run(ref GetCommand<ProgramCheckLinkCommand>(memory), threaded, renderer);
|
ProgramCheckLinkCommand.Run(ref GetCommand<ProgramCheckLinkCommand>(memory), threaded, renderer);
|
||||||
|
|
||||||
_lookup[(int)CommandType.SamplerDispose] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
_lookup[(int)CommandType.SamplerDispose] = (memory, threaded, renderer) =>
|
||||||
SamplerDisposeCommand.Run(ref GetCommand<SamplerDisposeCommand>(memory), threaded, renderer);
|
SamplerDisposeCommand.Run(ref GetCommand<SamplerDisposeCommand>(memory), threaded, renderer);
|
||||||
|
|
||||||
_lookup[(int)CommandType.TextureCopyTo] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
_lookup[(int)CommandType.TextureCopyTo] = (memory, threaded, renderer) =>
|
||||||
TextureCopyToCommand.Run(ref GetCommand<TextureCopyToCommand>(memory), threaded, renderer);
|
TextureCopyToCommand.Run(ref GetCommand<TextureCopyToCommand>(memory), threaded, renderer);
|
||||||
_lookup[(int)CommandType.TextureCopyToScaled] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
_lookup[(int)CommandType.TextureCopyToScaled] = (memory, threaded, renderer) =>
|
||||||
TextureCopyToScaledCommand.Run(ref GetCommand<TextureCopyToScaledCommand>(memory), threaded, renderer);
|
TextureCopyToScaledCommand.Run(ref GetCommand<TextureCopyToScaledCommand>(memory), threaded, renderer);
|
||||||
_lookup[(int)CommandType.TextureCopyToSlice] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
_lookup[(int)CommandType.TextureCopyToSlice] = (memory, threaded, renderer) =>
|
||||||
TextureCopyToSliceCommand.Run(ref GetCommand<TextureCopyToSliceCommand>(memory), threaded, renderer);
|
TextureCopyToSliceCommand.Run(ref GetCommand<TextureCopyToSliceCommand>(memory), threaded, renderer);
|
||||||
_lookup[(int)CommandType.TextureCreateView] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
_lookup[(int)CommandType.TextureCreateView] = (memory, threaded, renderer) =>
|
||||||
TextureCreateViewCommand.Run(ref GetCommand<TextureCreateViewCommand>(memory), threaded, renderer);
|
TextureCreateViewCommand.Run(ref GetCommand<TextureCreateViewCommand>(memory), threaded, renderer);
|
||||||
_lookup[(int)CommandType.TextureGetData] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
_lookup[(int)CommandType.TextureGetData] = (memory, threaded, renderer) =>
|
||||||
TextureGetDataCommand.Run(ref GetCommand<TextureGetDataCommand>(memory), threaded, renderer);
|
TextureGetDataCommand.Run(ref GetCommand<TextureGetDataCommand>(memory), threaded, renderer);
|
||||||
_lookup[(int)CommandType.TextureGetDataSlice] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
_lookup[(int)CommandType.TextureGetDataSlice] = (memory, threaded, renderer) =>
|
||||||
TextureGetDataSliceCommand.Run(ref GetCommand<TextureGetDataSliceCommand>(memory), threaded, renderer);
|
TextureGetDataSliceCommand.Run(ref GetCommand<TextureGetDataSliceCommand>(memory), threaded, renderer);
|
||||||
_lookup[(int)CommandType.TextureRelease] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
_lookup[(int)CommandType.TextureRelease] = (memory, threaded, renderer) =>
|
||||||
TextureReleaseCommand.Run(ref GetCommand<TextureReleaseCommand>(memory), threaded, renderer);
|
TextureReleaseCommand.Run(ref GetCommand<TextureReleaseCommand>(memory), threaded, renderer);
|
||||||
_lookup[(int)CommandType.TextureSetData] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
_lookup[(int)CommandType.TextureSetData] = (memory, threaded, renderer) =>
|
||||||
TextureSetDataCommand.Run(ref GetCommand<TextureSetDataCommand>(memory), threaded, renderer);
|
TextureSetDataCommand.Run(ref GetCommand<TextureSetDataCommand>(memory), threaded, renderer);
|
||||||
_lookup[(int)CommandType.TextureSetDataSlice] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
_lookup[(int)CommandType.TextureSetDataSlice] = (memory, threaded, renderer) =>
|
||||||
TextureSetDataSliceCommand.Run(ref GetCommand<TextureSetDataSliceCommand>(memory), threaded, renderer);
|
TextureSetDataSliceCommand.Run(ref GetCommand<TextureSetDataSliceCommand>(memory), threaded, renderer);
|
||||||
_lookup[(int)CommandType.TextureSetDataSliceRegion] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
_lookup[(int)CommandType.TextureSetDataSliceRegion] = (memory, threaded, renderer) =>
|
||||||
TextureSetDataSliceRegionCommand.Run(ref GetCommand<TextureSetDataSliceRegionCommand>(memory), threaded, renderer);
|
TextureSetDataSliceRegionCommand.Run(ref GetCommand<TextureSetDataSliceRegionCommand>(memory), threaded, renderer);
|
||||||
_lookup[(int)CommandType.TextureSetStorage] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
_lookup[(int)CommandType.TextureSetStorage] = (memory, threaded, renderer) =>
|
||||||
TextureSetStorageCommand.Run(ref GetCommand<TextureSetStorageCommand>(memory), threaded, renderer);
|
TextureSetStorageCommand.Run(ref GetCommand<TextureSetStorageCommand>(memory), threaded, renderer);
|
||||||
|
|
||||||
_lookup[(int)CommandType.WindowPresent] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
_lookup[(int)CommandType.WindowPresent] = (memory, threaded, renderer) =>
|
||||||
WindowPresentCommand.Run(ref GetCommand<WindowPresentCommand>(memory), threaded, renderer);
|
WindowPresentCommand.Run(ref GetCommand<WindowPresentCommand>(memory), threaded, renderer);
|
||||||
|
|
||||||
_lookup[(int)CommandType.Barrier] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
_lookup[(int)CommandType.Barrier] = (memory, threaded, renderer) =>
|
||||||
BarrierCommand.Run(ref GetCommand<BarrierCommand>(memory), threaded, renderer);
|
BarrierCommand.Run(ref GetCommand<BarrierCommand>(memory), threaded, renderer);
|
||||||
_lookup[(int)CommandType.BeginTransformFeedback] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
_lookup[(int)CommandType.BeginTransformFeedback] = (memory, threaded, renderer) =>
|
||||||
BeginTransformFeedbackCommand.Run(ref GetCommand<BeginTransformFeedbackCommand>(memory), threaded, renderer);
|
BeginTransformFeedbackCommand.Run(ref GetCommand<BeginTransformFeedbackCommand>(memory), threaded, renderer);
|
||||||
_lookup[(int)CommandType.ClearBuffer] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
_lookup[(int)CommandType.ClearBuffer] = (memory, threaded, renderer) =>
|
||||||
ClearBufferCommand.Run(ref GetCommand<ClearBufferCommand>(memory), threaded, renderer);
|
ClearBufferCommand.Run(ref GetCommand<ClearBufferCommand>(memory), threaded, renderer);
|
||||||
_lookup[(int)CommandType.ClearRenderTargetColor] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
_lookup[(int)CommandType.ClearRenderTargetColor] = (memory, threaded, renderer) =>
|
||||||
ClearRenderTargetColorCommand.Run(ref GetCommand<ClearRenderTargetColorCommand>(memory), threaded, renderer);
|
ClearRenderTargetColorCommand.Run(ref GetCommand<ClearRenderTargetColorCommand>(memory), threaded, renderer);
|
||||||
_lookup[(int)CommandType.ClearRenderTargetDepthStencil] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
_lookup[(int)CommandType.ClearRenderTargetDepthStencil] = (memory, threaded, renderer) =>
|
||||||
ClearRenderTargetDepthStencilCommand.Run(ref GetCommand<ClearRenderTargetDepthStencilCommand>(memory), threaded, renderer);
|
ClearRenderTargetDepthStencilCommand.Run(ref GetCommand<ClearRenderTargetDepthStencilCommand>(memory), threaded, renderer);
|
||||||
_lookup[(int)CommandType.CommandBufferBarrier] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
_lookup[(int)CommandType.CommandBufferBarrier] = (memory, threaded, renderer) =>
|
||||||
CommandBufferBarrierCommand.Run(ref GetCommand<CommandBufferBarrierCommand>(memory), threaded, renderer);
|
CommandBufferBarrierCommand.Run(ref GetCommand<CommandBufferBarrierCommand>(memory), threaded, renderer);
|
||||||
_lookup[(int)CommandType.CopyBuffer] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
_lookup[(int)CommandType.CopyBuffer] = (memory, threaded, renderer) =>
|
||||||
CopyBufferCommand.Run(ref GetCommand<CopyBufferCommand>(memory), threaded, renderer);
|
CopyBufferCommand.Run(ref GetCommand<CopyBufferCommand>(memory), threaded, renderer);
|
||||||
_lookup[(int)CommandType.DispatchCompute] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
_lookup[(int)CommandType.DispatchCompute] = (memory, threaded, renderer) =>
|
||||||
DispatchComputeCommand.Run(ref GetCommand<DispatchComputeCommand>(memory), threaded, renderer);
|
DispatchComputeCommand.Run(ref GetCommand<DispatchComputeCommand>(memory), threaded, renderer);
|
||||||
_lookup[(int)CommandType.Draw] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
_lookup[(int)CommandType.Draw] = (memory, threaded, renderer) =>
|
||||||
DrawCommand.Run(ref GetCommand<DrawCommand>(memory), threaded, renderer);
|
DrawCommand.Run(ref GetCommand<DrawCommand>(memory), threaded, renderer);
|
||||||
_lookup[(int)CommandType.DrawIndexed] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
_lookup[(int)CommandType.DrawIndexed] = (memory, threaded, renderer) =>
|
||||||
DrawIndexedCommand.Run(ref GetCommand<DrawIndexedCommand>(memory), threaded, renderer);
|
DrawIndexedCommand.Run(ref GetCommand<DrawIndexedCommand>(memory), threaded, renderer);
|
||||||
_lookup[(int)CommandType.DrawIndexedIndirect] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
_lookup[(int)CommandType.DrawIndexedIndirect] = (memory, threaded, renderer) =>
|
||||||
DrawIndexedIndirectCommand.Run(ref GetCommand<DrawIndexedIndirectCommand>(memory), threaded, renderer);
|
DrawIndexedIndirectCommand.Run(ref GetCommand<DrawIndexedIndirectCommand>(memory), threaded, renderer);
|
||||||
_lookup[(int)CommandType.DrawIndexedIndirectCount] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
_lookup[(int)CommandType.DrawIndexedIndirectCount] = (memory, threaded, renderer) =>
|
||||||
DrawIndexedIndirectCountCommand.Run(ref GetCommand<DrawIndexedIndirectCountCommand>(memory), threaded, renderer);
|
DrawIndexedIndirectCountCommand.Run(ref GetCommand<DrawIndexedIndirectCountCommand>(memory), threaded, renderer);
|
||||||
_lookup[(int)CommandType.DrawIndirect] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
_lookup[(int)CommandType.DrawIndirect] = (memory, threaded, renderer) =>
|
||||||
DrawIndirectCommand.Run(ref GetCommand<DrawIndirectCommand>(memory), threaded, renderer);
|
DrawIndirectCommand.Run(ref GetCommand<DrawIndirectCommand>(memory), threaded, renderer);
|
||||||
_lookup[(int)CommandType.DrawIndirectCount] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
_lookup[(int)CommandType.DrawIndirectCount] = (memory, threaded, renderer) =>
|
||||||
DrawIndirectCountCommand.Run(ref GetCommand<DrawIndirectCountCommand>(memory), threaded, renderer);
|
DrawIndirectCountCommand.Run(ref GetCommand<DrawIndirectCountCommand>(memory), threaded, renderer);
|
||||||
_lookup[(int)CommandType.DrawTexture] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
_lookup[(int)CommandType.DrawTexture] = (memory, threaded, renderer) =>
|
||||||
DrawTextureCommand.Run(ref GetCommand<DrawTextureCommand>(memory), threaded, renderer);
|
DrawTextureCommand.Run(ref GetCommand<DrawTextureCommand>(memory), threaded, renderer);
|
||||||
_lookup[(int)CommandType.EndHostConditionalRendering] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
_lookup[(int)CommandType.EndHostConditionalRendering] = (memory, threaded, renderer) =>
|
||||||
EndHostConditionalRenderingCommand.Run(renderer);
|
EndHostConditionalRenderingCommand.Run(renderer);
|
||||||
_lookup[(int)CommandType.EndTransformFeedback] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
_lookup[(int)CommandType.EndTransformFeedback] = (memory, threaded, renderer) =>
|
||||||
EndTransformFeedbackCommand.Run(ref GetCommand<EndTransformFeedbackCommand>(memory), threaded, renderer);
|
EndTransformFeedbackCommand.Run(ref GetCommand<EndTransformFeedbackCommand>(memory), threaded, renderer);
|
||||||
_lookup[(int)CommandType.SetAlphaTest] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
_lookup[(int)CommandType.SetAlphaTest] = (memory, threaded, renderer) =>
|
||||||
SetAlphaTestCommand.Run(ref GetCommand<SetAlphaTestCommand>(memory), threaded, renderer);
|
SetAlphaTestCommand.Run(ref GetCommand<SetAlphaTestCommand>(memory), threaded, renderer);
|
||||||
_lookup[(int)CommandType.SetBlendState] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
_lookup[(int)CommandType.SetBlendState] = (memory, threaded, renderer) =>
|
||||||
SetBlendStateCommand.Run(ref GetCommand<SetBlendStateCommand>(memory), threaded, renderer);
|
SetBlendStateCommand.Run(ref GetCommand<SetBlendStateCommand>(memory), threaded, renderer);
|
||||||
_lookup[(int)CommandType.SetDepthBias] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
_lookup[(int)CommandType.SetDepthBias] = (memory, threaded, renderer) =>
|
||||||
SetDepthBiasCommand.Run(ref GetCommand<SetDepthBiasCommand>(memory), threaded, renderer);
|
SetDepthBiasCommand.Run(ref GetCommand<SetDepthBiasCommand>(memory), threaded, renderer);
|
||||||
_lookup[(int)CommandType.SetDepthClamp] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
_lookup[(int)CommandType.SetDepthClamp] = (memory, threaded, renderer) =>
|
||||||
SetDepthClampCommand.Run(ref GetCommand<SetDepthClampCommand>(memory), threaded, renderer);
|
SetDepthClampCommand.Run(ref GetCommand<SetDepthClampCommand>(memory), threaded, renderer);
|
||||||
_lookup[(int)CommandType.SetDepthMode] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
_lookup[(int)CommandType.SetDepthMode] = (memory, threaded, renderer) =>
|
||||||
SetDepthModeCommand.Run(ref GetCommand<SetDepthModeCommand>(memory), threaded, renderer);
|
SetDepthModeCommand.Run(ref GetCommand<SetDepthModeCommand>(memory), threaded, renderer);
|
||||||
_lookup[(int)CommandType.SetDepthTest] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
_lookup[(int)CommandType.SetDepthTest] = (memory, threaded, renderer) =>
|
||||||
SetDepthTestCommand.Run(ref GetCommand<SetDepthTestCommand>(memory), threaded, renderer);
|
SetDepthTestCommand.Run(ref GetCommand<SetDepthTestCommand>(memory), threaded, renderer);
|
||||||
_lookup[(int)CommandType.SetFaceCulling] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
_lookup[(int)CommandType.SetFaceCulling] = (memory, threaded, renderer) =>
|
||||||
SetFaceCullingCommand.Run(ref GetCommand<SetFaceCullingCommand>(memory), threaded, renderer);
|
SetFaceCullingCommand.Run(ref GetCommand<SetFaceCullingCommand>(memory), threaded, renderer);
|
||||||
_lookup[(int)CommandType.SetFrontFace] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
_lookup[(int)CommandType.SetFrontFace] = (memory, threaded, renderer) =>
|
||||||
SetFrontFaceCommand.Run(ref GetCommand<SetFrontFaceCommand>(memory), threaded, renderer);
|
SetFrontFaceCommand.Run(ref GetCommand<SetFrontFaceCommand>(memory), threaded, renderer);
|
||||||
_lookup[(int)CommandType.SetStorageBuffers] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
_lookup[(int)CommandType.SetStorageBuffers] = (memory, threaded, renderer) =>
|
||||||
SetStorageBuffersCommand.Run(ref GetCommand<SetStorageBuffersCommand>(memory), threaded, renderer);
|
SetStorageBuffersCommand.Run(ref GetCommand<SetStorageBuffersCommand>(memory), threaded, renderer);
|
||||||
_lookup[(int)CommandType.SetTransformFeedbackBuffers] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
_lookup[(int)CommandType.SetTransformFeedbackBuffers] = (memory, threaded, renderer) =>
|
||||||
SetTransformFeedbackBuffersCommand.Run(ref GetCommand<SetTransformFeedbackBuffersCommand>(memory), threaded, renderer);
|
SetTransformFeedbackBuffersCommand.Run(ref GetCommand<SetTransformFeedbackBuffersCommand>(memory), threaded, renderer);
|
||||||
_lookup[(int)CommandType.SetUniformBuffers] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
_lookup[(int)CommandType.SetUniformBuffers] = (memory, threaded, renderer) =>
|
||||||
SetUniformBuffersCommand.Run(ref GetCommand<SetUniformBuffersCommand>(memory), threaded, renderer);
|
SetUniformBuffersCommand.Run(ref GetCommand<SetUniformBuffersCommand>(memory), threaded, renderer);
|
||||||
_lookup[(int)CommandType.SetImage] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
_lookup[(int)CommandType.SetImage] = (memory, threaded, renderer) =>
|
||||||
SetImageCommand.Run(ref GetCommand<SetImageCommand>(memory), threaded, renderer);
|
SetImageCommand.Run(ref GetCommand<SetImageCommand>(memory), threaded, renderer);
|
||||||
_lookup[(int)CommandType.SetIndexBuffer] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
_lookup[(int)CommandType.SetIndexBuffer] = (memory, threaded, renderer) =>
|
||||||
SetIndexBufferCommand.Run(ref GetCommand<SetIndexBufferCommand>(memory), threaded, renderer);
|
SetIndexBufferCommand.Run(ref GetCommand<SetIndexBufferCommand>(memory), threaded, renderer);
|
||||||
_lookup[(int)CommandType.SetLineParameters] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
_lookup[(int)CommandType.SetLineParameters] = (memory, threaded, renderer) =>
|
||||||
SetLineParametersCommand.Run(ref GetCommand<SetLineParametersCommand>(memory), threaded, renderer);
|
SetLineParametersCommand.Run(ref GetCommand<SetLineParametersCommand>(memory), threaded, renderer);
|
||||||
_lookup[(int)CommandType.SetLogicOpState] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
_lookup[(int)CommandType.SetLogicOpState] = (memory, threaded, renderer) =>
|
||||||
SetLogicOpStateCommand.Run(ref GetCommand<SetLogicOpStateCommand>(memory), threaded, renderer);
|
SetLogicOpStateCommand.Run(ref GetCommand<SetLogicOpStateCommand>(memory), threaded, renderer);
|
||||||
_lookup[(int)CommandType.SetMultisampleState] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
_lookup[(int)CommandType.SetMultisampleState] = (memory, threaded, renderer) =>
|
||||||
SetMultisampleStateCommand.Run(ref GetCommand<SetMultisampleStateCommand>(memory), threaded, renderer);
|
SetMultisampleStateCommand.Run(ref GetCommand<SetMultisampleStateCommand>(memory), threaded, renderer);
|
||||||
_lookup[(int)CommandType.SetPatchParameters] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
_lookup[(int)CommandType.SetPatchParameters] = (memory, threaded, renderer) =>
|
||||||
SetPatchParametersCommand.Run(ref GetCommand<SetPatchParametersCommand>(memory), threaded, renderer);
|
SetPatchParametersCommand.Run(ref GetCommand<SetPatchParametersCommand>(memory), threaded, renderer);
|
||||||
_lookup[(int)CommandType.SetPointParameters] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
_lookup[(int)CommandType.SetPointParameters] = (memory, threaded, renderer) =>
|
||||||
SetPointParametersCommand.Run(ref GetCommand<SetPointParametersCommand>(memory), threaded, renderer);
|
SetPointParametersCommand.Run(ref GetCommand<SetPointParametersCommand>(memory), threaded, renderer);
|
||||||
_lookup[(int)CommandType.SetPolygonMode] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
_lookup[(int)CommandType.SetPolygonMode] = (memory, threaded, renderer) =>
|
||||||
SetPolygonModeCommand.Run(ref GetCommand<SetPolygonModeCommand>(memory), threaded, renderer);
|
SetPolygonModeCommand.Run(ref GetCommand<SetPolygonModeCommand>(memory), threaded, renderer);
|
||||||
_lookup[(int)CommandType.SetPrimitiveRestart] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
_lookup[(int)CommandType.SetPrimitiveRestart] = (memory, threaded, renderer) =>
|
||||||
SetPrimitiveRestartCommand.Run(ref GetCommand<SetPrimitiveRestartCommand>(memory), threaded, renderer);
|
SetPrimitiveRestartCommand.Run(ref GetCommand<SetPrimitiveRestartCommand>(memory), threaded, renderer);
|
||||||
_lookup[(int)CommandType.SetPrimitiveTopology] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
_lookup[(int)CommandType.SetPrimitiveTopology] = (memory, threaded, renderer) =>
|
||||||
SetPrimitiveTopologyCommand.Run(ref GetCommand<SetPrimitiveTopologyCommand>(memory), threaded, renderer);
|
SetPrimitiveTopologyCommand.Run(ref GetCommand<SetPrimitiveTopologyCommand>(memory), threaded, renderer);
|
||||||
_lookup[(int)CommandType.SetProgram] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
_lookup[(int)CommandType.SetProgram] = (memory, threaded, renderer) =>
|
||||||
SetProgramCommand.Run(ref GetCommand<SetProgramCommand>(memory), threaded, renderer);
|
SetProgramCommand.Run(ref GetCommand<SetProgramCommand>(memory), threaded, renderer);
|
||||||
_lookup[(int)CommandType.SetRasterizerDiscard] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
_lookup[(int)CommandType.SetRasterizerDiscard] = (memory, threaded, renderer) =>
|
||||||
SetRasterizerDiscardCommand.Run(ref GetCommand<SetRasterizerDiscardCommand>(memory), threaded, renderer);
|
SetRasterizerDiscardCommand.Run(ref GetCommand<SetRasterizerDiscardCommand>(memory), threaded, renderer);
|
||||||
_lookup[(int)CommandType.SetRenderTargetColorMasks] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
_lookup[(int)CommandType.SetRenderTargetColorMasks] = (memory, threaded, renderer) =>
|
||||||
SetRenderTargetColorMasksCommand.Run(ref GetCommand<SetRenderTargetColorMasksCommand>(memory), threaded, renderer);
|
SetRenderTargetColorMasksCommand.Run(ref GetCommand<SetRenderTargetColorMasksCommand>(memory), threaded, renderer);
|
||||||
_lookup[(int)CommandType.SetRenderTargetScale] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
_lookup[(int)CommandType.SetRenderTargetScale] = (memory, threaded, renderer) =>
|
||||||
SetRenderTargetScaleCommand.Run(ref GetCommand<SetRenderTargetScaleCommand>(memory), threaded, renderer);
|
SetRenderTargetScaleCommand.Run(ref GetCommand<SetRenderTargetScaleCommand>(memory), threaded, renderer);
|
||||||
_lookup[(int)CommandType.SetRenderTargets] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
_lookup[(int)CommandType.SetRenderTargets] = (memory, threaded, renderer) =>
|
||||||
SetRenderTargetsCommand.Run(ref GetCommand<SetRenderTargetsCommand>(memory), threaded, renderer);
|
SetRenderTargetsCommand.Run(ref GetCommand<SetRenderTargetsCommand>(memory), threaded, renderer);
|
||||||
_lookup[(int)CommandType.SetScissor] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
_lookup[(int)CommandType.SetScissor] = (memory, threaded, renderer) =>
|
||||||
SetScissorsCommand.Run(ref GetCommand<SetScissorsCommand>(memory), threaded, renderer);
|
SetScissorsCommand.Run(ref GetCommand<SetScissorsCommand>(memory), threaded, renderer);
|
||||||
_lookup[(int)CommandType.SetStencilTest] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
_lookup[(int)CommandType.SetStencilTest] = (memory, threaded, renderer) =>
|
||||||
SetStencilTestCommand.Run(ref GetCommand<SetStencilTestCommand>(memory), threaded, renderer);
|
SetStencilTestCommand.Run(ref GetCommand<SetStencilTestCommand>(memory), threaded, renderer);
|
||||||
_lookup[(int)CommandType.SetTextureAndSampler] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
_lookup[(int)CommandType.SetTextureAndSampler] = (memory, threaded, renderer) =>
|
||||||
SetTextureAndSamplerCommand.Run(ref GetCommand<SetTextureAndSamplerCommand>(memory), threaded, renderer);
|
SetTextureAndSamplerCommand.Run(ref GetCommand<SetTextureAndSamplerCommand>(memory), threaded, renderer);
|
||||||
_lookup[(int)CommandType.SetUserClipDistance] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
_lookup[(int)CommandType.SetUserClipDistance] = (memory, threaded, renderer) =>
|
||||||
SetUserClipDistanceCommand.Run(ref GetCommand<SetUserClipDistanceCommand>(memory), threaded, renderer);
|
SetUserClipDistanceCommand.Run(ref GetCommand<SetUserClipDistanceCommand>(memory), threaded, renderer);
|
||||||
_lookup[(int)CommandType.SetVertexAttribs] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
_lookup[(int)CommandType.SetVertexAttribs] = (memory, threaded, renderer) =>
|
||||||
SetVertexAttribsCommand.Run(ref GetCommand<SetVertexAttribsCommand>(memory), threaded, renderer);
|
SetVertexAttribsCommand.Run(ref GetCommand<SetVertexAttribsCommand>(memory), threaded, renderer);
|
||||||
_lookup[(int)CommandType.SetVertexBuffers] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
_lookup[(int)CommandType.SetVertexBuffers] = (memory, threaded, renderer) =>
|
||||||
SetVertexBuffersCommand.Run(ref GetCommand<SetVertexBuffersCommand>(memory), threaded, renderer);
|
SetVertexBuffersCommand.Run(ref GetCommand<SetVertexBuffersCommand>(memory), threaded, renderer);
|
||||||
_lookup[(int)CommandType.SetViewports] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
_lookup[(int)CommandType.SetViewports] = (memory, threaded, renderer) =>
|
||||||
SetViewportsCommand.Run(ref GetCommand<SetViewportsCommand>(memory), threaded, renderer);
|
SetViewportsCommand.Run(ref GetCommand<SetViewportsCommand>(memory), threaded, renderer);
|
||||||
_lookup[(int)CommandType.TextureBarrier] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
_lookup[(int)CommandType.TextureBarrier] = (memory, threaded, renderer) =>
|
||||||
TextureBarrierCommand.Run(ref GetCommand<TextureBarrierCommand>(memory), threaded, renderer);
|
TextureBarrierCommand.Run(ref GetCommand<TextureBarrierCommand>(memory), threaded, renderer);
|
||||||
_lookup[(int)CommandType.TextureBarrierTiled] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
_lookup[(int)CommandType.TextureBarrierTiled] = (memory, threaded, renderer) =>
|
||||||
TextureBarrierTiledCommand.Run(ref GetCommand<TextureBarrierTiledCommand>(memory), threaded, renderer);
|
TextureBarrierTiledCommand.Run(ref GetCommand<TextureBarrierTiledCommand>(memory), threaded, renderer);
|
||||||
_lookup[(int)CommandType.TryHostConditionalRendering] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
_lookup[(int)CommandType.TryHostConditionalRendering] = (memory, threaded, renderer) =>
|
||||||
TryHostConditionalRenderingCommand.Run(ref GetCommand<TryHostConditionalRenderingCommand>(memory), threaded, renderer);
|
TryHostConditionalRenderingCommand.Run(ref GetCommand<TryHostConditionalRenderingCommand>(memory), threaded, renderer);
|
||||||
_lookup[(int)CommandType.TryHostConditionalRenderingFlush] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
_lookup[(int)CommandType.TryHostConditionalRenderingFlush] = (memory, threaded, renderer) =>
|
||||||
TryHostConditionalRenderingFlushCommand.Run(ref GetCommand<TryHostConditionalRenderingFlushCommand>(memory), threaded, renderer);
|
TryHostConditionalRenderingFlushCommand.Run(ref GetCommand<TryHostConditionalRenderingFlushCommand>(memory), threaded, renderer);
|
||||||
_lookup[(int)CommandType.UpdateRenderScale] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
_lookup[(int)CommandType.UpdateRenderScale] = (memory, threaded, renderer) =>
|
||||||
UpdateRenderScaleCommand.Run(ref GetCommand<UpdateRenderScaleCommand>(memory), threaded, renderer);
|
UpdateRenderScaleCommand.Run(ref GetCommand<UpdateRenderScaleCommand>(memory), threaded, renderer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -72,7 +72,7 @@ namespace Ryujinx.Graphics.GAL.Multithreading
|
|||||||
{
|
{
|
||||||
_baseRenderer = renderer;
|
_baseRenderer = renderer;
|
||||||
|
|
||||||
renderer.ScreenCaptured += (object sender, ScreenCaptureImageInfo info) => ScreenCaptured?.Invoke(this, info);
|
renderer.ScreenCaptured += (sender, info) => ScreenCaptured?.Invoke(this, info);
|
||||||
|
|
||||||
Pipeline = new ThreadedPipeline(this, renderer.Pipeline);
|
Pipeline = new ThreadedPipeline(this, renderer.Pipeline);
|
||||||
Window = new ThreadedWindow(this, renderer);
|
Window = new ThreadedWindow(this, renderer);
|
||||||
|
@@ -61,7 +61,7 @@ namespace Ryujinx.Graphics.GAL
|
|||||||
AddressMode.ClampToEdge,
|
AddressMode.ClampToEdge,
|
||||||
AddressMode.ClampToEdge,
|
AddressMode.ClampToEdge,
|
||||||
CompareMode.None,
|
CompareMode.None,
|
||||||
GAL.CompareOp.Always,
|
CompareOp.Always,
|
||||||
new ColorF(0f, 0f, 0f, 0f),
|
new ColorF(0f, 0f, 0f, 0f),
|
||||||
0f,
|
0f,
|
||||||
0f,
|
0f,
|
||||||
|
@@ -253,14 +253,19 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
|||||||
/// Indicates that any storage buffer use is unaligned.
|
/// Indicates that any storage buffer use is unaligned.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="value">The new value</param>
|
/// <param name="value">The new value</param>
|
||||||
public void SetHasUnalignedStorageBuffer(bool value)
|
/// <returns>True if the unaligned state changed, false otherwise</returns>
|
||||||
|
public bool SetHasUnalignedStorageBuffer(bool value)
|
||||||
{
|
{
|
||||||
if (value != _graphics.HasUnalignedStorageBuffer)
|
if (value != _graphics.HasUnalignedStorageBuffer)
|
||||||
{
|
{
|
||||||
_graphics.HasUnalignedStorageBuffer = value;
|
_graphics.HasUnalignedStorageBuffer = value;
|
||||||
|
|
||||||
Signal();
|
Signal();
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@@ -304,14 +304,12 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
private void CommitBindings()
|
private void CommitBindings()
|
||||||
{
|
{
|
||||||
var buffers = _channel.BufferManager;
|
|
||||||
var hasUnaligned = buffers.HasUnalignedStorageBuffers;
|
|
||||||
|
|
||||||
UpdateStorageBuffers();
|
UpdateStorageBuffers();
|
||||||
|
|
||||||
if (!_channel.TextureManager.CommitGraphicsBindings(_shaderSpecState) || (buffers.HasUnalignedStorageBuffers != hasUnaligned))
|
bool unalignedChanged = _currentSpecState.SetHasUnalignedStorageBuffer(_channel.BufferManager.HasUnalignedStorageBuffers);
|
||||||
|
|
||||||
|
if (!_channel.TextureManager.CommitGraphicsBindings(_shaderSpecState) || unalignedChanged)
|
||||||
{
|
{
|
||||||
_currentSpecState.SetHasUnalignedStorageBuffer(buffers.HasUnalignedStorageBuffers);
|
|
||||||
// Shader must be reloaded. _vtgWritesRtLayer should not change.
|
// Shader must be reloaded. _vtgWritesRtLayer should not change.
|
||||||
UpdateShaderState();
|
UpdateShaderState();
|
||||||
}
|
}
|
||||||
|
@@ -22,7 +22,7 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache
|
|||||||
private const ushort FileFormatVersionMajor = 1;
|
private const ushort FileFormatVersionMajor = 1;
|
||||||
private const ushort FileFormatVersionMinor = 2;
|
private const ushort FileFormatVersionMinor = 2;
|
||||||
private const uint FileFormatVersionPacked = ((uint)FileFormatVersionMajor << 16) | FileFormatVersionMinor;
|
private const uint FileFormatVersionPacked = ((uint)FileFormatVersionMajor << 16) | FileFormatVersionMinor;
|
||||||
private const uint CodeGenVersion = 4011;
|
private const uint CodeGenVersion = 4069;
|
||||||
|
|
||||||
private const string SharedTocFileName = "shared.toc";
|
private const string SharedTocFileName = "shared.toc";
|
||||||
private const string SharedDataFileName = "shared.data";
|
private const string SharedDataFileName = "shared.data";
|
||||||
|
@@ -110,7 +110,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Texture target.
|
/// Texture target.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Image.TextureTarget TextureTarget;
|
public TextureTarget TextureTarget;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Indicates if the coordinates used to sample the texture are normalized or not (0.0..1.0 or 0..Width/Height).
|
/// Indicates if the coordinates used to sample the texture are normalized or not (0.0..1.0 or 0..Width/Height).
|
||||||
@@ -331,7 +331,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
|||||||
int cbufSlot,
|
int cbufSlot,
|
||||||
uint format,
|
uint format,
|
||||||
bool formatSrgb,
|
bool formatSrgb,
|
||||||
Image.TextureTarget target,
|
TextureTarget target,
|
||||||
bool coordNormalized)
|
bool coordNormalized)
|
||||||
{
|
{
|
||||||
Box<TextureSpecializationState> state = GetOrCreateTextureSpecState(stageIndex, handle, cbufSlot);
|
Box<TextureSpecializationState> state = GetOrCreateTextureSpecState(stageIndex, handle, cbufSlot);
|
||||||
@@ -415,7 +415,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
|||||||
/// <param name="stageIndex">Shader stage where the texture is used</param>
|
/// <param name="stageIndex">Shader stage where the texture is used</param>
|
||||||
/// <param name="handle">Offset in words of the texture handle on the texture buffer</param>
|
/// <param name="handle">Offset in words of the texture handle on the texture buffer</param>
|
||||||
/// <param name="cbufSlot">Slot of the texture buffer constant buffer</param>
|
/// <param name="cbufSlot">Slot of the texture buffer constant buffer</param>
|
||||||
public Image.TextureTarget GetTextureTarget(int stageIndex, int handle, int cbufSlot)
|
public TextureTarget GetTextureTarget(int stageIndex, int handle, int cbufSlot)
|
||||||
{
|
{
|
||||||
return GetTextureSpecState(stageIndex, handle, cbufSlot).Value.TextureTarget;
|
return GetTextureSpecState(stageIndex, handle, cbufSlot).Value.TextureTarget;
|
||||||
}
|
}
|
||||||
|
@@ -2,6 +2,6 @@ float Helper_SwizzleAdd(float x, float y, int mask)
|
|||||||
{
|
{
|
||||||
vec4 xLut = vec4(1.0, -1.0, 1.0, 0.0);
|
vec4 xLut = vec4(1.0, -1.0, 1.0, 0.0);
|
||||||
vec4 yLut = vec4(1.0, 1.0, -1.0, 1.0);
|
vec4 yLut = vec4(1.0, 1.0, -1.0, 1.0);
|
||||||
int lutIdx = mask >> int($SUBGROUP_INVOCATION$ & 3u) * 2;
|
int lutIdx = (mask >> (int($SUBGROUP_INVOCATION$ & 3u) * 2)) & 3;
|
||||||
return x * xLut[lutIdx] + y * yLut[lutIdx];
|
return x * xLut[lutIdx] + y * yLut[lutIdx];
|
||||||
}
|
}
|
@@ -10,8 +10,6 @@ using static Spv.Specification;
|
|||||||
|
|
||||||
namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
||||||
{
|
{
|
||||||
using SpvInstruction = Spv.Generator.Instruction;
|
|
||||||
|
|
||||||
static class Declarations
|
static class Declarations
|
||||||
{
|
{
|
||||||
// At least 16 attributes are guaranteed by the spec.
|
// At least 16 attributes are guaranteed by the spec.
|
||||||
@@ -60,7 +58,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
|||||||
for (int funcIndex = 0; funcIndex < functions.Count; funcIndex++)
|
for (int funcIndex = 0; funcIndex < functions.Count; funcIndex++)
|
||||||
{
|
{
|
||||||
StructuredFunction function = functions[funcIndex];
|
StructuredFunction function = functions[funcIndex];
|
||||||
SpvInstruction[] locals = new SpvInstruction[function.InArguments.Length];
|
Instruction[] locals = new Instruction[function.InArguments.Length];
|
||||||
|
|
||||||
for (int i = 0; i < function.InArguments.Length; i++)
|
for (int i = 0; i < function.InArguments.Length; i++)
|
||||||
{
|
{
|
||||||
@@ -122,7 +120,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
|||||||
context.SharedMemory = DeclareMemory(context, StorageClass.Workgroup, size);
|
context.SharedMemory = DeclareMemory(context, StorageClass.Workgroup, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static SpvInstruction DeclareMemory(CodeGenContext context, StorageClass storage, int size)
|
private static Instruction DeclareMemory(CodeGenContext context, StorageClass storage, int size)
|
||||||
{
|
{
|
||||||
var arrayType = context.TypeArray(context.TypeU32(), context.Constant(context.TypeU32(), size));
|
var arrayType = context.TypeArray(context.TypeU32(), context.Constant(context.TypeU32(), size));
|
||||||
var pointerType = context.TypePointer(storage, arrayType);
|
var pointerType = context.TypePointer(storage, arrayType);
|
||||||
|
@@ -1449,10 +1449,13 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
|||||||
var xLut = context.ConstantComposite(v4float, one, minusOne, one, zero);
|
var xLut = context.ConstantComposite(v4float, one, minusOne, one, zero);
|
||||||
var yLut = context.ConstantComposite(v4float, one, one, minusOne, one);
|
var yLut = context.ConstantComposite(v4float, one, one, minusOne, one);
|
||||||
|
|
||||||
|
var three = context.Constant(context.TypeU32(), 3);
|
||||||
|
|
||||||
var threadId = context.GetAttribute(AggregateType.U32, AttributeConsts.LaneId, false);
|
var threadId = context.GetAttribute(AggregateType.U32, AttributeConsts.LaneId, false);
|
||||||
var shift = context.BitwiseAnd(context.TypeU32(), threadId, context.Constant(context.TypeU32(), 3));
|
var shift = context.BitwiseAnd(context.TypeU32(), threadId, three);
|
||||||
shift = context.ShiftLeftLogical(context.TypeU32(), shift, context.Constant(context.TypeU32(), 1));
|
shift = context.ShiftLeftLogical(context.TypeU32(), shift, context.Constant(context.TypeU32(), 1));
|
||||||
var lutIdx = context.ShiftRightLogical(context.TypeU32(), mask, shift);
|
var lutIdx = context.ShiftRightLogical(context.TypeU32(), mask, shift);
|
||||||
|
lutIdx = context.BitwiseAnd(context.TypeU32(), lutIdx, three);
|
||||||
|
|
||||||
var xLutValue = context.VectorExtractDynamic(context.TypeFP32(), xLut, lutIdx);
|
var xLutValue = context.VectorExtractDynamic(context.TypeFP32(), xLut, lutIdx);
|
||||||
var yLutValue = context.VectorExtractDynamic(context.TypeFP32(), yLut, lutIdx);
|
var yLutValue = context.VectorExtractDynamic(context.TypeFP32(), yLut, lutIdx);
|
||||||
|
@@ -8,6 +8,7 @@ namespace Ryujinx.Graphics.Shader.Translation
|
|||||||
public const int TessLevelOuter3 = 0x00c;
|
public const int TessLevelOuter3 = 0x00c;
|
||||||
public const int TessLevelInner0 = 0x010;
|
public const int TessLevelInner0 = 0x010;
|
||||||
public const int TessLevelInner1 = 0x014;
|
public const int TessLevelInner1 = 0x014;
|
||||||
|
public const int PrimitiveId = 0x060;
|
||||||
public const int Layer = 0x064;
|
public const int Layer = 0x064;
|
||||||
public const int ViewportIndex = 0x068;
|
public const int ViewportIndex = 0x068;
|
||||||
public const int PointSize = 0x06c;
|
public const int PointSize = 0x06c;
|
||||||
@@ -85,8 +86,7 @@ namespace Ryujinx.Graphics.Shader.Translation
|
|||||||
public const int LaneId = 0x2000020;
|
public const int LaneId = 0x2000020;
|
||||||
|
|
||||||
public const int InvocationId = 0x2000024;
|
public const int InvocationId = 0x2000024;
|
||||||
public const int PrimitiveId = 0x2000028;
|
public const int PatchVerticesIn = 0x2000028;
|
||||||
public const int PatchVerticesIn = 0x200002c;
|
|
||||||
|
|
||||||
public const int EqMask = 0x2000030;
|
public const int EqMask = 0x2000030;
|
||||||
public const int GeMask = 0x2000034;
|
public const int GeMask = 0x2000034;
|
||||||
|
@@ -48,5 +48,10 @@ namespace Ryujinx.Graphics.Shader.Translation
|
|||||||
_ => 0
|
_ => 0
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static int GetConstantUbeOffset(int slot)
|
||||||
|
{
|
||||||
|
return UbeBaseOffset + slot * StorageDescSize;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -8,11 +8,14 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
|
|||||||
{
|
{
|
||||||
static class GlobalToStorage
|
static class GlobalToStorage
|
||||||
{
|
{
|
||||||
public static void RunPass(BasicBlock block, ShaderConfig config, ref int sbUseMask)
|
public static void RunPass(BasicBlock block, ShaderConfig config, ref int sbUseMask, ref int ubeUseMask)
|
||||||
{
|
{
|
||||||
int sbStart = GetStorageBaseCbOffset(config.Stage);
|
int sbStart = GetStorageBaseCbOffset(config.Stage);
|
||||||
int sbEnd = sbStart + StorageDescsSize;
|
int sbEnd = sbStart + StorageDescsSize;
|
||||||
|
|
||||||
|
int ubeStart = UbeBaseOffset;
|
||||||
|
int ubeEnd = UbeBaseOffset + UbeDescsSize;
|
||||||
|
|
||||||
for (LinkedListNode<INode> node = block.Operations.First; node != null; node = node.Next)
|
for (LinkedListNode<INode> node = block.Operations.First; node != null; node = node.Next)
|
||||||
{
|
{
|
||||||
for (int index = 0; index < node.Value.SourcesCount; index++)
|
for (int index = 0; index < node.Value.SourcesCount; index++)
|
||||||
@@ -25,6 +28,16 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
|
|||||||
{
|
{
|
||||||
sbUseMask |= 1 << storageIndex;
|
sbUseMask |= 1 << storageIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (config.Stage == ShaderStage.Compute)
|
||||||
|
{
|
||||||
|
int constantIndex = GetStorageIndex(src, ubeStart, ubeEnd);
|
||||||
|
|
||||||
|
if (constantIndex >= 0)
|
||||||
|
{
|
||||||
|
ubeUseMask |= 1 << constantIndex;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(node.Value is Operation operation))
|
if (!(node.Value is Operation operation))
|
||||||
@@ -54,7 +67,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
|
|||||||
// so NVN "emulates" more constant buffers using global memory access.
|
// so NVN "emulates" more constant buffers using global memory access.
|
||||||
// Here we try to replace the global access back to a constant buffer
|
// Here we try to replace the global access back to a constant buffer
|
||||||
// load.
|
// load.
|
||||||
storageIndex = SearchForStorageBase(block, source, UbeBaseOffset, UbeBaseOffset + UbeDescsSize);
|
storageIndex = SearchForStorageBase(block, source, ubeStart, ubeStart + ubeEnd);
|
||||||
|
|
||||||
if (storageIndex >= 0)
|
if (storageIndex >= 0)
|
||||||
{
|
{
|
||||||
@@ -64,7 +77,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
config.SetAccessibleStorageBuffersMask(sbUseMask);
|
config.SetAccessibleBufferMasks(sbUseMask, ubeUseMask);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static LinkedListNode<INode> ReplaceGlobalWithStorage(BasicBlock block, LinkedListNode<INode> node, ShaderConfig config, int storageIndex)
|
private static LinkedListNode<INode> ReplaceGlobalWithStorage(BasicBlock block, LinkedListNode<INode> node, ShaderConfig config, int storageIndex)
|
||||||
|
@@ -12,16 +12,17 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
|
|||||||
RunOptimizationPasses(blocks);
|
RunOptimizationPasses(blocks);
|
||||||
|
|
||||||
int sbUseMask = 0;
|
int sbUseMask = 0;
|
||||||
|
int ubeUseMask = 0;
|
||||||
|
|
||||||
// Those passes are looking for specific patterns and only needs to run once.
|
// Those passes are looking for specific patterns and only needs to run once.
|
||||||
for (int blkIndex = 0; blkIndex < blocks.Length; blkIndex++)
|
for (int blkIndex = 0; blkIndex < blocks.Length; blkIndex++)
|
||||||
{
|
{
|
||||||
GlobalToStorage.RunPass(blocks[blkIndex], config, ref sbUseMask);
|
GlobalToStorage.RunPass(blocks[blkIndex], config, ref sbUseMask, ref ubeUseMask);
|
||||||
BindlessToIndexed.RunPass(blocks[blkIndex], config);
|
BindlessToIndexed.RunPass(blocks[blkIndex], config);
|
||||||
BindlessElimination.RunPass(blocks[blkIndex], config);
|
BindlessElimination.RunPass(blocks[blkIndex], config);
|
||||||
}
|
}
|
||||||
|
|
||||||
config.SetAccessibleStorageBuffersMask(sbUseMask);
|
config.SetAccessibleBufferMasks(sbUseMask, ubeUseMask);
|
||||||
|
|
||||||
// Run optimizations one last time to remove any code that is now optimizable after above passes.
|
// Run optimizations one last time to remove any code that is now optimizable after above passes.
|
||||||
RunOptimizationPasses(blocks);
|
RunOptimizationPasses(blocks);
|
||||||
|
@@ -1,3 +1,4 @@
|
|||||||
|
using Ryujinx.Graphics.Shader.Decoders;
|
||||||
using Ryujinx.Graphics.Shader.IntermediateRepresentation;
|
using Ryujinx.Graphics.Shader.IntermediateRepresentation;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
@@ -21,10 +22,11 @@ namespace Ryujinx.Graphics.Shader.Translation
|
|||||||
{
|
{
|
||||||
BasicBlock block = blocks[blkIndex];
|
BasicBlock block = blocks[blkIndex];
|
||||||
|
|
||||||
for (LinkedListNode<INode> node = block.Operations.First; node != null; node = node.Next)
|
for (LinkedListNode<INode> node = block.Operations.First; node != null;)
|
||||||
{
|
{
|
||||||
if (node.Value is not Operation operation)
|
if (node.Value is not Operation operation)
|
||||||
{
|
{
|
||||||
|
node = node.Next;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -43,10 +45,7 @@ namespace Ryujinx.Graphics.Shader.Translation
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (UsesGlobalMemory(operation.Inst))
|
LinkedListNode<INode> nextNode = node.Next;
|
||||||
{
|
|
||||||
node = RewriteGlobalAccess(node, config);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (operation is TextureOperation texOp)
|
if (operation is TextureOperation texOp)
|
||||||
{
|
{
|
||||||
@@ -59,7 +58,15 @@ namespace Ryujinx.Graphics.Shader.Translation
|
|||||||
node = InsertSnormNormalization(node, config);
|
node = InsertSnormNormalization(node, config);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nextNode = node.Next;
|
||||||
}
|
}
|
||||||
|
else if (UsesGlobalMemory(operation.Inst))
|
||||||
|
{
|
||||||
|
nextNode = RewriteGlobalAccess(node, config)?.Next ?? nextNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
node = nextNode;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -72,7 +79,7 @@ namespace Ryujinx.Graphics.Shader.Translation
|
|||||||
bool isStg16Or8 = operation.Inst == Instruction.StoreGlobal16 || operation.Inst == Instruction.StoreGlobal8;
|
bool isStg16Or8 = operation.Inst == Instruction.StoreGlobal16 || operation.Inst == Instruction.StoreGlobal8;
|
||||||
bool isWrite = isAtomic || operation.Inst == Instruction.StoreGlobal || isStg16Or8;
|
bool isWrite = isAtomic || operation.Inst == Instruction.StoreGlobal || isStg16Or8;
|
||||||
|
|
||||||
Operation storageOp;
|
Operation storageOp = null;
|
||||||
|
|
||||||
Operand PrependOperation(Instruction inst, params Operand[] sources)
|
Operand PrependOperation(Instruction inst, params Operand[] sources)
|
||||||
{
|
{
|
||||||
@@ -83,12 +90,42 @@ namespace Ryujinx.Graphics.Shader.Translation
|
|||||||
return local;
|
return local;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Operand PrependExistingOperation(Operation operation)
|
||||||
|
{
|
||||||
|
Operand local = Local();
|
||||||
|
|
||||||
|
operation.Dest = local;
|
||||||
|
node.List.AddBefore(node, operation);
|
||||||
|
|
||||||
|
return local;
|
||||||
|
}
|
||||||
|
|
||||||
Operand addrLow = operation.GetSource(0);
|
Operand addrLow = operation.GetSource(0);
|
||||||
Operand addrHigh = operation.GetSource(1);
|
Operand addrHigh = operation.GetSource(1);
|
||||||
|
|
||||||
Operand sbBaseAddrLow = Const(0);
|
Operand sbBaseAddrLow = Const(0);
|
||||||
Operand sbSlot = Const(0);
|
Operand sbSlot = Const(0);
|
||||||
|
|
||||||
|
Operand alignMask = Const(-config.GpuAccessor.QueryHostStorageBufferOffsetAlignment());
|
||||||
|
|
||||||
|
Operand BindingRangeCheck(int cbOffset, out Operand baseAddrLow)
|
||||||
|
{
|
||||||
|
baseAddrLow = Cbuf(0, cbOffset);
|
||||||
|
Operand baseAddrHigh = Cbuf(0, cbOffset + 1);
|
||||||
|
Operand size = Cbuf(0, cbOffset + 2);
|
||||||
|
|
||||||
|
Operand offset = PrependOperation(Instruction.Subtract, addrLow, baseAddrLow);
|
||||||
|
Operand borrow = PrependOperation(Instruction.CompareLessU32, addrLow, baseAddrLow);
|
||||||
|
|
||||||
|
Operand inRangeLow = PrependOperation(Instruction.CompareLessU32, offset, size);
|
||||||
|
|
||||||
|
Operand addrHighBorrowed = PrependOperation(Instruction.Add, addrHigh, borrow);
|
||||||
|
|
||||||
|
Operand inRangeHigh = PrependOperation(Instruction.CompareEqual, addrHighBorrowed, baseAddrHigh);
|
||||||
|
|
||||||
|
return PrependOperation(Instruction.BitwiseAnd, inRangeLow, inRangeHigh);
|
||||||
|
}
|
||||||
|
|
||||||
int sbUseMask = config.AccessibleStorageBuffersMask;
|
int sbUseMask = config.AccessibleStorageBuffersMask;
|
||||||
|
|
||||||
while (sbUseMask != 0)
|
while (sbUseMask != 0)
|
||||||
@@ -101,27 +138,14 @@ namespace Ryujinx.Graphics.Shader.Translation
|
|||||||
|
|
||||||
int cbOffset = GetStorageCbOffset(config.Stage, slot);
|
int cbOffset = GetStorageCbOffset(config.Stage, slot);
|
||||||
|
|
||||||
Operand baseAddrLow = Cbuf(0, cbOffset);
|
Operand inRange = BindingRangeCheck(cbOffset, out Operand baseAddrLow);
|
||||||
Operand baseAddrHigh = Cbuf(0, cbOffset + 1);
|
|
||||||
Operand size = Cbuf(0, cbOffset + 2);
|
|
||||||
|
|
||||||
Operand offset = PrependOperation(Instruction.Subtract, addrLow, baseAddrLow);
|
|
||||||
Operand borrow = PrependOperation(Instruction.CompareLessU32, addrLow, baseAddrLow);
|
|
||||||
|
|
||||||
Operand inRangeLow = PrependOperation(Instruction.CompareLessU32, offset, size);
|
|
||||||
|
|
||||||
Operand addrHighBorrowed = PrependOperation(Instruction.Add, addrHigh, borrow);
|
|
||||||
|
|
||||||
Operand inRangeHigh = PrependOperation(Instruction.CompareEqual, addrHighBorrowed, baseAddrHigh);
|
|
||||||
|
|
||||||
Operand inRange = PrependOperation(Instruction.BitwiseAnd, inRangeLow, inRangeHigh);
|
|
||||||
|
|
||||||
sbBaseAddrLow = PrependOperation(Instruction.ConditionalSelect, inRange, baseAddrLow, sbBaseAddrLow);
|
sbBaseAddrLow = PrependOperation(Instruction.ConditionalSelect, inRange, baseAddrLow, sbBaseAddrLow);
|
||||||
sbSlot = PrependOperation(Instruction.ConditionalSelect, inRange, Const(slot), sbSlot);
|
sbSlot = PrependOperation(Instruction.ConditionalSelect, inRange, Const(slot), sbSlot);
|
||||||
}
|
}
|
||||||
|
|
||||||
Operand alignMask = Const(-config.GpuAccessor.QueryHostStorageBufferOffsetAlignment());
|
if (config.AccessibleStorageBuffersMask != 0)
|
||||||
|
{
|
||||||
Operand baseAddrTrunc = PrependOperation(Instruction.BitwiseAnd, sbBaseAddrLow, alignMask);
|
Operand baseAddrTrunc = PrependOperation(Instruction.BitwiseAnd, sbBaseAddrLow, alignMask);
|
||||||
Operand byteOffset = PrependOperation(Instruction.Subtract, addrLow, baseAddrTrunc);
|
Operand byteOffset = PrependOperation(Instruction.Subtract, addrLow, baseAddrTrunc);
|
||||||
|
|
||||||
@@ -164,6 +188,51 @@ namespace Ryujinx.Graphics.Shader.Translation
|
|||||||
|
|
||||||
storageOp = new Operation(storeInst, null, sources);
|
storageOp = new Operation(storeInst, null, sources);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
else if (operation.Dest != null)
|
||||||
|
{
|
||||||
|
storageOp = new Operation(Instruction.Copy, operation.Dest, Const(0));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (operation.Inst == Instruction.LoadGlobal)
|
||||||
|
{
|
||||||
|
int cbeUseMask = config.AccessibleConstantBuffersMask;
|
||||||
|
|
||||||
|
while (cbeUseMask != 0)
|
||||||
|
{
|
||||||
|
int slot = BitOperations.TrailingZeroCount(cbeUseMask);
|
||||||
|
int cbSlot = UbeFirstCbuf + slot;
|
||||||
|
|
||||||
|
cbeUseMask &= ~(1 << slot);
|
||||||
|
|
||||||
|
config.SetUsedConstantBuffer(cbSlot);
|
||||||
|
|
||||||
|
Operand previousResult = PrependExistingOperation(storageOp);
|
||||||
|
|
||||||
|
int cbOffset = GetConstantUbeOffset(slot);
|
||||||
|
|
||||||
|
Operand inRange = BindingRangeCheck(cbOffset, out Operand baseAddrLow);
|
||||||
|
|
||||||
|
Operand baseAddrTruncConst = PrependOperation(Instruction.BitwiseAnd, baseAddrLow, alignMask);
|
||||||
|
Operand byteOffsetConst = PrependOperation(Instruction.Subtract, addrLow, baseAddrTruncConst);
|
||||||
|
|
||||||
|
Operand cbIndex = PrependOperation(Instruction.ShiftRightU32, byteOffsetConst, Const(2));
|
||||||
|
|
||||||
|
Operand[] sourcesCb = new Operand[operation.SourcesCount];
|
||||||
|
|
||||||
|
sourcesCb[0] = Const(cbSlot);
|
||||||
|
sourcesCb[1] = cbIndex;
|
||||||
|
|
||||||
|
for (int index = 2; index < operation.SourcesCount; index++)
|
||||||
|
{
|
||||||
|
sourcesCb[index] = operation.GetSource(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
Operand ldcResult = PrependOperation(Instruction.LoadConstant, sourcesCb);
|
||||||
|
|
||||||
|
storageOp = new Operation(Instruction.ConditionalSelect, operation.Dest, inRange, ldcResult, previousResult);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for (int index = 0; index < operation.SourcesCount; index++)
|
for (int index = 0; index < operation.SourcesCount; index++)
|
||||||
{
|
{
|
||||||
@@ -171,10 +240,18 @@ namespace Ryujinx.Graphics.Shader.Translation
|
|||||||
}
|
}
|
||||||
|
|
||||||
LinkedListNode<INode> oldNode = node;
|
LinkedListNode<INode> oldNode = node;
|
||||||
|
LinkedList<INode> oldNodeList = oldNode.List;
|
||||||
|
|
||||||
|
if (storageOp != null)
|
||||||
|
{
|
||||||
node = node.List.AddBefore(node, storageOp);
|
node = node.List.AddBefore(node, storageOp);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
node = null;
|
||||||
|
}
|
||||||
|
|
||||||
node.List.Remove(oldNode);
|
oldNodeList.Remove(oldNode);
|
||||||
|
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
@@ -66,6 +66,7 @@ namespace Ryujinx.Graphics.Shader.Translation
|
|||||||
public UInt128 ThisInputAttributesComponents { get; private set; }
|
public UInt128 ThisInputAttributesComponents { get; private set; }
|
||||||
|
|
||||||
public int AccessibleStorageBuffersMask { get; private set; }
|
public int AccessibleStorageBuffersMask { get; private set; }
|
||||||
|
public int AccessibleConstantBuffersMask { get; private set; }
|
||||||
|
|
||||||
private int _usedConstantBuffers;
|
private int _usedConstantBuffers;
|
||||||
private int _usedStorageBuffers;
|
private int _usedStorageBuffers;
|
||||||
@@ -101,6 +102,7 @@ namespace Ryujinx.Graphics.Shader.Translation
|
|||||||
Options = options;
|
Options = options;
|
||||||
|
|
||||||
AccessibleStorageBuffersMask = (1 << GlobalMemory.StorageMaxCount) - 1;
|
AccessibleStorageBuffersMask = (1 << GlobalMemory.StorageMaxCount) - 1;
|
||||||
|
AccessibleConstantBuffersMask = (1 << GlobalMemory.UbeMaxCount) - 1;
|
||||||
|
|
||||||
UsedInputAttributesPerPatch = new HashSet<int>();
|
UsedInputAttributesPerPatch = new HashSet<int>();
|
||||||
UsedOutputAttributesPerPatch = new HashSet<int>();
|
UsedOutputAttributesPerPatch = new HashSet<int>();
|
||||||
@@ -121,6 +123,11 @@ namespace Ryujinx.Graphics.Shader.Translation
|
|||||||
OutputTopology = outputTopology;
|
OutputTopology = outputTopology;
|
||||||
MaxOutputVertices = maxOutputVertices;
|
MaxOutputVertices = maxOutputVertices;
|
||||||
TransformFeedbackEnabled = gpuAccessor.QueryTransformFeedbackEnabled();
|
TransformFeedbackEnabled = gpuAccessor.QueryTransformFeedbackEnabled();
|
||||||
|
|
||||||
|
if (Stage != ShaderStage.Compute)
|
||||||
|
{
|
||||||
|
AccessibleConstantBuffersMask = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public ShaderConfig(ShaderHeader header, IGpuAccessor gpuAccessor, TranslationOptions options) : this(gpuAccessor, options)
|
public ShaderConfig(ShaderHeader header, IGpuAccessor gpuAccessor, TranslationOptions options) : this(gpuAccessor, options)
|
||||||
@@ -404,9 +411,10 @@ namespace Ryujinx.Graphics.Shader.Translation
|
|||||||
UsedFeatures |= flags;
|
UsedFeatures |= flags;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetAccessibleStorageBuffersMask(int mask)
|
public void SetAccessibleBufferMasks(int sbMask, int ubeMask)
|
||||||
{
|
{
|
||||||
AccessibleStorageBuffersMask = mask;
|
AccessibleStorageBuffersMask = sbMask;
|
||||||
|
AccessibleConstantBuffersMask = ubeMask;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetUsedConstantBuffer(int slot)
|
public void SetUsedConstantBuffer(int slot)
|
||||||
|
@@ -272,7 +272,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
_gd,
|
_gd,
|
||||||
cbs.CommandBuffer,
|
cbs.CommandBuffer,
|
||||||
dstBuffer,
|
dstBuffer,
|
||||||
BufferHolder.DefaultAccessFlags,
|
DefaultAccessFlags,
|
||||||
AccessFlags.TransferWriteBit,
|
AccessFlags.TransferWriteBit,
|
||||||
PipelineStageFlags.AllCommandsBit,
|
PipelineStageFlags.AllCommandsBit,
|
||||||
PipelineStageFlags.TransferBit,
|
PipelineStageFlags.TransferBit,
|
||||||
@@ -294,7 +294,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
cbs.CommandBuffer,
|
cbs.CommandBuffer,
|
||||||
dstBuffer,
|
dstBuffer,
|
||||||
AccessFlags.TransferWriteBit,
|
AccessFlags.TransferWriteBit,
|
||||||
BufferHolder.DefaultAccessFlags,
|
DefaultAccessFlags,
|
||||||
PipelineStageFlags.TransferBit,
|
PipelineStageFlags.TransferBit,
|
||||||
PipelineStageFlags.AllCommandsBit,
|
PipelineStageFlags.AllCommandsBit,
|
||||||
dstOffset,
|
dstOffset,
|
||||||
@@ -319,7 +319,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
gd,
|
gd,
|
||||||
cbs.CommandBuffer,
|
cbs.CommandBuffer,
|
||||||
dstBuffer,
|
dstBuffer,
|
||||||
BufferHolder.DefaultAccessFlags,
|
DefaultAccessFlags,
|
||||||
AccessFlags.TransferWriteBit,
|
AccessFlags.TransferWriteBit,
|
||||||
PipelineStageFlags.AllCommandsBit,
|
PipelineStageFlags.AllCommandsBit,
|
||||||
PipelineStageFlags.TransferBit,
|
PipelineStageFlags.TransferBit,
|
||||||
@@ -335,7 +335,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
cbs.CommandBuffer,
|
cbs.CommandBuffer,
|
||||||
dstBuffer,
|
dstBuffer,
|
||||||
AccessFlags.TransferWriteBit,
|
AccessFlags.TransferWriteBit,
|
||||||
BufferHolder.DefaultAccessFlags,
|
DefaultAccessFlags,
|
||||||
PipelineStageFlags.TransferBit,
|
PipelineStageFlags.TransferBit,
|
||||||
PipelineStageFlags.AllCommandsBit,
|
PipelineStageFlags.AllCommandsBit,
|
||||||
dstOffset,
|
dstOffset,
|
||||||
|
@@ -97,7 +97,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
_dummyBuffer = gd.BufferManager.Create(gd, 0x10000, forConditionalRendering: false, deviceLocal: true);
|
_dummyBuffer = gd.BufferManager.Create(gd, 0x10000, forConditionalRendering: false, deviceLocal: true);
|
||||||
}
|
}
|
||||||
|
|
||||||
_dummyTexture = gd.CreateTextureView(new GAL.TextureCreateInfo(
|
_dummyTexture = gd.CreateTextureView(new TextureCreateInfo(
|
||||||
1,
|
1,
|
||||||
1,
|
1,
|
||||||
1,
|
1,
|
||||||
|
@@ -3,7 +3,7 @@ using System;
|
|||||||
|
|
||||||
namespace Ryujinx.Graphics.Vulkan
|
namespace Ryujinx.Graphics.Vulkan
|
||||||
{
|
{
|
||||||
readonly struct DisposableBufferView : System.IDisposable
|
readonly struct DisposableBufferView : IDisposable
|
||||||
{
|
{
|
||||||
private readonly Vk _api;
|
private readonly Vk _api;
|
||||||
private readonly Device _device;
|
private readonly Device _device;
|
||||||
|
@@ -86,7 +86,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
iter++;
|
iter++;
|
||||||
}
|
}
|
||||||
|
|
||||||
DescriptorSetLayout[] layouts = new DescriptorSetLayout[PipelineFull.DescriptorSetLayouts];
|
DescriptorSetLayout[] layouts = new DescriptorSetLayout[PipelineBase.DescriptorSetLayouts];
|
||||||
|
|
||||||
var uDescriptorSetLayoutCreateInfo = new DescriptorSetLayoutCreateInfo()
|
var uDescriptorSetLayoutCreateInfo = new DescriptorSetLayoutCreateInfo()
|
||||||
{
|
{
|
||||||
@@ -117,10 +117,10 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
BindingCount = (uint)iCount
|
BindingCount = (uint)iCount
|
||||||
};
|
};
|
||||||
|
|
||||||
gd.Api.CreateDescriptorSetLayout(device, uDescriptorSetLayoutCreateInfo, null, out layouts[PipelineFull.UniformSetIndex]).ThrowOnError();
|
gd.Api.CreateDescriptorSetLayout(device, uDescriptorSetLayoutCreateInfo, null, out layouts[PipelineBase.UniformSetIndex]).ThrowOnError();
|
||||||
gd.Api.CreateDescriptorSetLayout(device, sDescriptorSetLayoutCreateInfo, null, out layouts[PipelineFull.StorageSetIndex]).ThrowOnError();
|
gd.Api.CreateDescriptorSetLayout(device, sDescriptorSetLayoutCreateInfo, null, out layouts[PipelineBase.StorageSetIndex]).ThrowOnError();
|
||||||
gd.Api.CreateDescriptorSetLayout(device, tDescriptorSetLayoutCreateInfo, null, out layouts[PipelineFull.TextureSetIndex]).ThrowOnError();
|
gd.Api.CreateDescriptorSetLayout(device, tDescriptorSetLayoutCreateInfo, null, out layouts[PipelineBase.TextureSetIndex]).ThrowOnError();
|
||||||
gd.Api.CreateDescriptorSetLayout(device, iDescriptorSetLayoutCreateInfo, null, out layouts[PipelineFull.ImageSetIndex]).ThrowOnError();
|
gd.Api.CreateDescriptorSetLayout(device, iDescriptorSetLayoutCreateInfo, null, out layouts[PipelineBase.ImageSetIndex]).ThrowOnError();
|
||||||
|
|
||||||
fixed (DescriptorSetLayout* pLayouts = layouts)
|
fixed (DescriptorSetLayout* pLayouts = layouts)
|
||||||
{
|
{
|
||||||
@@ -128,7 +128,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
{
|
{
|
||||||
SType = StructureType.PipelineLayoutCreateInfo,
|
SType = StructureType.PipelineLayoutCreateInfo,
|
||||||
PSetLayouts = pLayouts,
|
PSetLayouts = pLayouts,
|
||||||
SetLayoutCount = PipelineFull.DescriptorSetLayouts
|
SetLayoutCount = PipelineBase.DescriptorSetLayouts
|
||||||
};
|
};
|
||||||
|
|
||||||
gd.Api.CreatePipelineLayout(device, &pipelineLayoutCreateInfo, null, out layout).ThrowOnError();
|
gd.Api.CreatePipelineLayout(device, &pipelineLayoutCreateInfo, null, out layout).ThrowOnError();
|
||||||
@@ -191,7 +191,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
Set(iLayoutBindings, DescriptorType.StorageImage, ref iIndex, shader.Bindings.ImageBindings);
|
Set(iLayoutBindings, DescriptorType.StorageImage, ref iIndex, shader.Bindings.ImageBindings);
|
||||||
}
|
}
|
||||||
|
|
||||||
DescriptorSetLayout[] layouts = new DescriptorSetLayout[PipelineFull.DescriptorSetLayouts];
|
DescriptorSetLayout[] layouts = new DescriptorSetLayout[PipelineBase.DescriptorSetLayouts];
|
||||||
|
|
||||||
var uDescriptorSetLayoutCreateInfo = new DescriptorSetLayoutCreateInfo()
|
var uDescriptorSetLayoutCreateInfo = new DescriptorSetLayoutCreateInfo()
|
||||||
{
|
{
|
||||||
@@ -221,10 +221,10 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
BindingCount = (uint)iCount
|
BindingCount = (uint)iCount
|
||||||
};
|
};
|
||||||
|
|
||||||
gd.Api.CreateDescriptorSetLayout(device, uDescriptorSetLayoutCreateInfo, null, out layouts[PipelineFull.UniformSetIndex]).ThrowOnError();
|
gd.Api.CreateDescriptorSetLayout(device, uDescriptorSetLayoutCreateInfo, null, out layouts[PipelineBase.UniformSetIndex]).ThrowOnError();
|
||||||
gd.Api.CreateDescriptorSetLayout(device, sDescriptorSetLayoutCreateInfo, null, out layouts[PipelineFull.StorageSetIndex]).ThrowOnError();
|
gd.Api.CreateDescriptorSetLayout(device, sDescriptorSetLayoutCreateInfo, null, out layouts[PipelineBase.StorageSetIndex]).ThrowOnError();
|
||||||
gd.Api.CreateDescriptorSetLayout(device, tDescriptorSetLayoutCreateInfo, null, out layouts[PipelineFull.TextureSetIndex]).ThrowOnError();
|
gd.Api.CreateDescriptorSetLayout(device, tDescriptorSetLayoutCreateInfo, null, out layouts[PipelineBase.TextureSetIndex]).ThrowOnError();
|
||||||
gd.Api.CreateDescriptorSetLayout(device, iDescriptorSetLayoutCreateInfo, null, out layouts[PipelineFull.ImageSetIndex]).ThrowOnError();
|
gd.Api.CreateDescriptorSetLayout(device, iDescriptorSetLayoutCreateInfo, null, out layouts[PipelineBase.ImageSetIndex]).ThrowOnError();
|
||||||
|
|
||||||
fixed (DescriptorSetLayout* pLayouts = layouts)
|
fixed (DescriptorSetLayout* pLayouts = layouts)
|
||||||
{
|
{
|
||||||
@@ -232,7 +232,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
{
|
{
|
||||||
SType = StructureType.PipelineLayoutCreateInfo,
|
SType = StructureType.PipelineLayoutCreateInfo,
|
||||||
PSetLayouts = pLayouts,
|
PSetLayouts = pLayouts,
|
||||||
SetLayoutCount = PipelineFull.DescriptorSetLayouts
|
SetLayoutCount = PipelineBase.DescriptorSetLayouts
|
||||||
};
|
};
|
||||||
|
|
||||||
gd.Api.CreatePipelineLayout(device, &pipelineLayoutCreateInfo, null, out layout).ThrowOnError();
|
gd.Api.CreatePipelineLayout(device, &pipelineLayoutCreateInfo, null, out layout).ThrowOnError();
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
using Ryujinx.Common.Configuration;
|
using Ryujinx.Common.Configuration;
|
||||||
using Ryujinx.Common.Logging;
|
using Ryujinx.Common.Logging;
|
||||||
using Ryujinx.Graphics.GAL;
|
using Ryujinx.Graphics.GAL;
|
||||||
using Silk.NET.Vulkan;
|
using Silk.NET.Vulkan;
|
||||||
@@ -21,6 +21,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
{
|
{
|
||||||
ExtConditionalRendering.ExtensionName,
|
ExtConditionalRendering.ExtensionName,
|
||||||
ExtExtendedDynamicState.ExtensionName,
|
ExtExtendedDynamicState.ExtensionName,
|
||||||
|
ExtTransformFeedback.ExtensionName,
|
||||||
KhrDrawIndirectCount.ExtensionName,
|
KhrDrawIndirectCount.ExtensionName,
|
||||||
KhrPushDescriptor.ExtensionName,
|
KhrPushDescriptor.ExtensionName,
|
||||||
"VK_EXT_custom_border_color",
|
"VK_EXT_custom_border_color",
|
||||||
@@ -36,8 +37,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
|
|
||||||
public static string[] RequiredExtensions { get; } = new string[]
|
public static string[] RequiredExtensions { get; } = new string[]
|
||||||
{
|
{
|
||||||
KhrSwapchain.ExtensionName,
|
KhrSwapchain.ExtensionName
|
||||||
ExtTransformFeedback.ExtensionName
|
|
||||||
};
|
};
|
||||||
|
|
||||||
private static string[] _excludedMessages = new string[]
|
private static string[] _excludedMessages = new string[]
|
||||||
@@ -382,12 +382,12 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
DepthClamp = true,
|
DepthClamp = true,
|
||||||
DualSrcBlend = true,
|
DualSrcBlend = true,
|
||||||
FragmentStoresAndAtomics = true,
|
FragmentStoresAndAtomics = true,
|
||||||
GeometryShader = true,
|
GeometryShader = supportedFeatures.GeometryShader,
|
||||||
ImageCubeArray = true,
|
ImageCubeArray = true,
|
||||||
IndependentBlend = true,
|
IndependentBlend = true,
|
||||||
LogicOp = true,
|
LogicOp = supportedFeatures.LogicOp,
|
||||||
MultiViewport = true,
|
MultiViewport = true,
|
||||||
PipelineStatisticsQuery = true,
|
PipelineStatisticsQuery = supportedFeatures.PipelineStatisticsQuery,
|
||||||
SamplerAnisotropy = true,
|
SamplerAnisotropy = true,
|
||||||
ShaderClipDistance = true,
|
ShaderClipDistance = true,
|
||||||
ShaderFloat64 = supportedFeatures.ShaderFloat64,
|
ShaderFloat64 = supportedFeatures.ShaderFloat64,
|
||||||
|
@@ -39,13 +39,11 @@ namespace Ryujinx.HLE.FileSystem
|
|||||||
{
|
{
|
||||||
public readonly string ContainerPath;
|
public readonly string ContainerPath;
|
||||||
public readonly string NcaPath;
|
public readonly string NcaPath;
|
||||||
public bool Enabled;
|
|
||||||
|
|
||||||
public AocItem(string containerPath, string ncaPath, bool enabled)
|
public AocItem(string containerPath, string ncaPath)
|
||||||
{
|
{
|
||||||
ContainerPath = containerPath;
|
ContainerPath = containerPath;
|
||||||
NcaPath = ncaPath;
|
NcaPath = ncaPath;
|
||||||
Enabled = enabled;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -53,7 +51,7 @@ namespace Ryujinx.HLE.FileSystem
|
|||||||
|
|
||||||
private VirtualFileSystem _virtualFileSystem;
|
private VirtualFileSystem _virtualFileSystem;
|
||||||
|
|
||||||
private readonly object _lock = new object();
|
private readonly object _lock = new();
|
||||||
|
|
||||||
public ContentManager(VirtualFileSystem virtualFileSystem)
|
public ContentManager(VirtualFileSystem virtualFileSystem)
|
||||||
{
|
{
|
||||||
@@ -226,27 +224,21 @@ namespace Ryujinx.HLE.FileSystem
|
|||||||
pfs0.OpenFile(ref cnmtFile.Ref(), pfs0.EnumerateEntries().Single().FullPath.ToU8Span(), OpenMode.Read);
|
pfs0.OpenFile(ref cnmtFile.Ref(), pfs0.EnumerateEntries().Single().FullPath.ToU8Span(), OpenMode.Read);
|
||||||
|
|
||||||
var cnmt = new Cnmt(cnmtFile.Get.AsStream());
|
var cnmt = new Cnmt(cnmtFile.Get.AsStream());
|
||||||
|
|
||||||
if (cnmt.Type != ContentMetaType.AddOnContent || (cnmt.TitleId & 0xFFFFFFFFFFFFE000) != aocBaseId)
|
if (cnmt.Type != ContentMetaType.AddOnContent || (cnmt.TitleId & 0xFFFFFFFFFFFFE000) != aocBaseId)
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
string ncaId = BitConverter.ToString(cnmt.ContentEntries[0].NcaId).Replace("-", "").ToLower();
|
string ncaId = BitConverter.ToString(cnmt.ContentEntries[0].NcaId).Replace("-", "").ToLower();
|
||||||
if (!_aocData.TryAdd(cnmt.TitleId, new AocItem(containerPath, $"{ncaId}.nca", true)))
|
|
||||||
{
|
AddAocItem(cnmt.TitleId, containerPath, $"{ncaId}.nca", true);
|
||||||
Logger.Warning?.Print(LogClass.Application, $"Duplicate AddOnContent detected. TitleId {cnmt.TitleId:X16}");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Logger.Info?.Print(LogClass.Application, $"Found AddOnContent with TitleId {cnmt.TitleId:X16}");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void AddAocItem(ulong titleId, string containerPath, string ncaPath, bool enabled)
|
public void AddAocItem(ulong titleId, string containerPath, string ncaPath, bool mergedToContainer = false)
|
||||||
{
|
{
|
||||||
if (!_aocData.TryAdd(titleId, new AocItem(containerPath, ncaPath, enabled)))
|
// TODO: Check Aoc version.
|
||||||
|
if (!_aocData.TryAdd(titleId, new AocItem(containerPath, ncaPath)))
|
||||||
{
|
{
|
||||||
Logger.Warning?.Print(LogClass.Application, $"Duplicate AddOnContent detected. TitleId {titleId:X16}");
|
Logger.Warning?.Print(LogClass.Application, $"Duplicate AddOnContent detected. TitleId {titleId:X16}");
|
||||||
}
|
}
|
||||||
@@ -254,25 +246,27 @@ namespace Ryujinx.HLE.FileSystem
|
|||||||
{
|
{
|
||||||
Logger.Info?.Print(LogClass.Application, $"Found AddOnContent with TitleId {titleId:X16}");
|
Logger.Info?.Print(LogClass.Application, $"Found AddOnContent with TitleId {titleId:X16}");
|
||||||
|
|
||||||
using (FileStream fileStream = File.OpenRead(containerPath))
|
if (!mergedToContainer)
|
||||||
using (PartitionFileSystem pfs = new PartitionFileSystem(fileStream.AsStorage()))
|
|
||||||
{
|
{
|
||||||
_virtualFileSystem.ImportTickets(pfs);
|
using FileStream fileStream = File.OpenRead(containerPath);
|
||||||
|
using PartitionFileSystem partitionFileSystem = new(fileStream.AsStorage());
|
||||||
|
|
||||||
|
_virtualFileSystem.ImportTickets(partitionFileSystem);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ClearAocData() => _aocData.Clear();
|
public void ClearAocData() => _aocData.Clear();
|
||||||
|
|
||||||
public int GetAocCount() => _aocData.Where(e => e.Value.Enabled).Count();
|
public int GetAocCount() => _aocData.Count;
|
||||||
|
|
||||||
public IList<ulong> GetAocTitleIds() => _aocData.Where(e => e.Value.Enabled).Select(e => e.Key).ToList();
|
public IList<ulong> GetAocTitleIds() => _aocData.Select(e => e.Key).ToList();
|
||||||
|
|
||||||
public bool GetAocDataStorage(ulong aocTitleId, out IStorage aocStorage, IntegrityCheckLevel integrityCheckLevel)
|
public bool GetAocDataStorage(ulong aocTitleId, out IStorage aocStorage, IntegrityCheckLevel integrityCheckLevel)
|
||||||
{
|
{
|
||||||
aocStorage = null;
|
aocStorage = null;
|
||||||
|
|
||||||
if (_aocData.TryGetValue(aocTitleId, out AocItem aoc) && aoc.Enabled)
|
if (_aocData.TryGetValue(aocTitleId, out AocItem aoc))
|
||||||
{
|
{
|
||||||
var file = new FileStream(aoc.ContainerPath, FileMode.Open, FileAccess.Read);
|
var file = new FileStream(aoc.ContainerPath, FileMode.Open, FileAccess.Read);
|
||||||
using var ncaFile = new UniqueRef<IFile>();
|
using var ncaFile = new UniqueRef<IFile>();
|
||||||
|
Binary file not shown.
After Width: | Height: | Size: 52 KiB |
@@ -11,7 +11,6 @@ using System.Numerics;
|
|||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using SixLabors.ImageSharp.PixelFormats;
|
using SixLabors.ImageSharp.PixelFormats;
|
||||||
using Ryujinx.Common;
|
|
||||||
|
|
||||||
namespace Ryujinx.HLE.HOS.Applets.SoftwareKeyboard
|
namespace Ryujinx.HLE.HOS.Applets.SoftwareKeyboard
|
||||||
{
|
{
|
||||||
@@ -68,8 +67,8 @@ namespace Ryujinx.HLE.HOS.Applets.SoftwareKeyboard
|
|||||||
{
|
{
|
||||||
int ryujinxLogoSize = 32;
|
int ryujinxLogoSize = 32;
|
||||||
|
|
||||||
Stream logoStream = EmbeddedResources.GetStream("Ryujinx.Ui.Common/Resources/Logo_Ryujinx.png");
|
string ryujinxIconPath = "Ryujinx.HLE.HOS.Applets.SoftwareKeyboard.Resources.Logo_Ryujinx.png";
|
||||||
_ryujinxLogo = LoadResource(logoStream, ryujinxLogoSize, ryujinxLogoSize);
|
_ryujinxLogo = LoadResource(Assembly.GetExecutingAssembly(), ryujinxIconPath, ryujinxLogoSize, ryujinxLogoSize);
|
||||||
|
|
||||||
string padAcceptIconPath = "Ryujinx.HLE.HOS.Applets.SoftwareKeyboard.Resources.Icon_BtnA.png";
|
string padAcceptIconPath = "Ryujinx.HLE.HOS.Applets.SoftwareKeyboard.Resources.Icon_BtnA.png";
|
||||||
string padCancelIconPath = "Ryujinx.HLE.HOS.Applets.SoftwareKeyboard.Resources.Icon_BtnB.png";
|
string padCancelIconPath = "Ryujinx.HLE.HOS.Applets.SoftwareKeyboard.Resources.Icon_BtnB.png";
|
||||||
@@ -117,7 +116,8 @@ namespace Ryujinx.HLE.HOS.Applets.SoftwareKeyboard
|
|||||||
uiThemeFontFamily,
|
uiThemeFontFamily,
|
||||||
"Liberation Sans",
|
"Liberation Sans",
|
||||||
"FreeSans",
|
"FreeSans",
|
||||||
"DejaVu Sans"
|
"DejaVu Sans",
|
||||||
|
"Lucida Grande"
|
||||||
};
|
};
|
||||||
|
|
||||||
foreach (string fontFamily in availableFonts)
|
foreach (string fontFamily in availableFonts)
|
||||||
|
@@ -426,9 +426,9 @@ namespace Ryujinx.HLE.HOS
|
|||||||
{
|
{
|
||||||
foreach (DownloadableContentNca downloadableContentNca in downloadableContentContainer.DownloadableContentNcaList)
|
foreach (DownloadableContentNca downloadableContentNca in downloadableContentContainer.DownloadableContentNcaList)
|
||||||
{
|
{
|
||||||
if (File.Exists(downloadableContentContainer.ContainerPath))
|
if (File.Exists(downloadableContentContainer.ContainerPath) && downloadableContentNca.Enabled)
|
||||||
{
|
{
|
||||||
_device.Configuration.ContentManager.AddAocItem(downloadableContentNca.TitleId, downloadableContentContainer.ContainerPath, downloadableContentNca.FullPath, downloadableContentNca.Enabled);
|
_device.Configuration.ContentManager.AddAocItem(downloadableContentNca.TitleId, downloadableContentContainer.ContainerPath, downloadableContentNca.FullPath);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@@ -1,8 +1,12 @@
|
|||||||
using Ryujinx.Common;
|
using Ryujinx.Common;
|
||||||
using Ryujinx.Common.Logging;
|
using Ryujinx.Common.Logging;
|
||||||
using Ryujinx.Cpu;
|
using Ryujinx.Cpu;
|
||||||
|
using Ryujinx.HLE.HOS.Kernel.Threading;
|
||||||
using Ryujinx.HLE.HOS.Services.Account.Acc.AccountService;
|
using Ryujinx.HLE.HOS.Services.Account.Acc.AccountService;
|
||||||
|
using Ryujinx.HLE.HOS.Services.Account.Acc.AsyncContext;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace Ryujinx.HLE.HOS.Services.Account.Acc
|
namespace Ryujinx.HLE.HOS.Services.Account.Acc
|
||||||
{
|
{
|
||||||
@@ -142,6 +146,28 @@ namespace Ryujinx.HLE.HOS.Services.Account.Acc
|
|||||||
return ResultCode.Success;
|
return ResultCode.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ResultCode CheckNetworkServiceAvailabilityAsync(ServiceCtx context, out IAsyncContext asyncContext)
|
||||||
|
{
|
||||||
|
KEvent asyncEvent = new(context.Device.System.KernelContext);
|
||||||
|
AsyncExecution asyncExecution = new(asyncEvent);
|
||||||
|
|
||||||
|
asyncExecution.Initialize(1000, CheckNetworkServiceAvailabilityAsyncImpl);
|
||||||
|
|
||||||
|
asyncContext = new IAsyncContext(asyncExecution);
|
||||||
|
|
||||||
|
// return ResultCode.NullObject if the IAsyncContext pointer is null. Doesn't occur in our case.
|
||||||
|
|
||||||
|
return ResultCode.Success;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task CheckNetworkServiceAvailabilityAsyncImpl(CancellationToken token)
|
||||||
|
{
|
||||||
|
Logger.Stub?.PrintStub(LogClass.ServiceAcc);
|
||||||
|
|
||||||
|
// TODO: Use a real function instead, with the CancellationToken.
|
||||||
|
await Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
public ResultCode StoreSaveDataThumbnail(ServiceCtx context)
|
public ResultCode StoreSaveDataThumbnail(ServiceCtx context)
|
||||||
{
|
{
|
||||||
ResultCode resultCode = CheckUserId(context, out UserId _);
|
ResultCode resultCode = CheckUserId(context, out UserId _);
|
||||||
|
@@ -124,6 +124,20 @@ namespace Ryujinx.HLE.HOS.Services.Account.Acc
|
|||||||
return ResultCode.Success;
|
return ResultCode.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[CommandHipc(103)] // 4.0.0+
|
||||||
|
// CheckNetworkServiceAvailabilityAsync() -> object<nn::account::detail::IAsyncContext>
|
||||||
|
public ResultCode CheckNetworkServiceAvailabilityAsync(ServiceCtx context)
|
||||||
|
{
|
||||||
|
ResultCode resultCode = _applicationServiceServer.CheckNetworkServiceAvailabilityAsync(context, out IAsyncContext asyncContext);
|
||||||
|
|
||||||
|
if (resultCode == ResultCode.Success)
|
||||||
|
{
|
||||||
|
MakeObject(context, asyncContext);
|
||||||
|
}
|
||||||
|
|
||||||
|
return resultCode;
|
||||||
|
}
|
||||||
|
|
||||||
[CommandHipc(110)]
|
[CommandHipc(110)]
|
||||||
// StoreSaveDataThumbnail(nn::account::Uid, buffer<bytes, 5>)
|
// StoreSaveDataThumbnail(nn::account::Uid, buffer<bytes, 5>)
|
||||||
public ResultCode StoreSaveDataThumbnail(ServiceCtx context)
|
public ResultCode StoreSaveDataThumbnail(ServiceCtx context)
|
||||||
|
@@ -157,7 +157,7 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletOE.ApplicationProxyService.Applicati
|
|||||||
int supportedLanguages = (int)context.Device.Application.ControlData.Value.SupportedLanguageFlag;
|
int supportedLanguages = (int)context.Device.Application.ControlData.Value.SupportedLanguageFlag;
|
||||||
int firstSupported = BitOperations.TrailingZeroCount(supportedLanguages);
|
int firstSupported = BitOperations.TrailingZeroCount(supportedLanguages);
|
||||||
|
|
||||||
if (firstSupported > (int)SystemState.TitleLanguage.BrazilianPortuguese)
|
if (firstSupported > (int)TitleLanguage.BrazilianPortuguese)
|
||||||
{
|
{
|
||||||
Logger.Warning?.Print(LogClass.ServiceAm, "Application has zero supported languages");
|
Logger.Warning?.Print(LogClass.ServiceAm, "Application has zero supported languages");
|
||||||
|
|
||||||
@@ -170,7 +170,7 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletOE.ApplicationProxyService.Applicati
|
|||||||
// TODO: In the future, a GUI could enable user-specified search priority
|
// TODO: In the future, a GUI could enable user-specified search priority
|
||||||
if (((1 << (int)context.Device.System.State.DesiredTitleLanguage) & supportedLanguages) == 0)
|
if (((1 << (int)context.Device.System.State.DesiredTitleLanguage) & supportedLanguages) == 0)
|
||||||
{
|
{
|
||||||
SystemLanguage newLanguage = Enum.Parse<SystemLanguage>(Enum.GetName(typeof(SystemState.TitleLanguage), firstSupported));
|
SystemLanguage newLanguage = Enum.Parse<SystemLanguage>(Enum.GetName(typeof(TitleLanguage), firstSupported));
|
||||||
desiredLanguageCode = SystemStateMgr.GetLanguageCode((int)newLanguage);
|
desiredLanguageCode = SystemStateMgr.GetLanguageCode((int)newLanguage);
|
||||||
|
|
||||||
Logger.Info?.Print(LogClass.ServiceAm, $"Application doesn't support configured language. Using {newLanguage}");
|
Logger.Info?.Print(LogClass.ServiceAm, $"Application doesn't support configured language. Using {newLanguage}");
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user