Compare commits
8 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
2068445939 | ||
|
a4fc9f8050 | ||
|
5437d6cb13 | ||
|
7539e26144 | ||
|
1c3697b6a4 | ||
|
81f848e54f | ||
|
358a781639 | ||
|
45ce540b9b |
@@ -113,6 +113,7 @@ namespace ARMeilleure.CodeGen.X86
|
||||
Add(X86Instruction.Divps, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f5e, InstructionFlags.Vex));
|
||||
Add(X86Instruction.Divsd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f5e, InstructionFlags.Vex | InstructionFlags.PrefixF2));
|
||||
Add(X86Instruction.Divss, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f5e, InstructionFlags.Vex | InstructionFlags.PrefixF3));
|
||||
Add(X86Instruction.Gf2p8affineqb, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f3ace, InstructionFlags.Prefix66));
|
||||
Add(X86Instruction.Haddpd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f7c, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||
Add(X86Instruction.Haddps, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f7c, InstructionFlags.Vex | InstructionFlags.PrefixF2));
|
||||
Add(X86Instruction.Idiv, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x070000f7, InstructionFlags.None));
|
||||
|
@@ -20,8 +20,9 @@ namespace ARMeilleure.CodeGen.X86
|
||||
|
||||
if (maxNum >= 7)
|
||||
{
|
||||
(_, int ebx7, _, _) = X86Base.CpuId(0x00000007, 0x00000000);
|
||||
(_, int ebx7, int ecx7, _) = X86Base.CpuId(0x00000007, 0x00000000);
|
||||
FeatureInfo7Ebx = (FeatureFlags7Ebx)ebx7;
|
||||
FeatureInfo7Ecx = (FeatureFlags7Ecx)ecx7;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -54,9 +55,16 @@ namespace ARMeilleure.CodeGen.X86
|
||||
Sha = 1 << 29
|
||||
}
|
||||
|
||||
[Flags]
|
||||
public enum FeatureFlags7Ecx
|
||||
{
|
||||
Gfni = 1 << 8,
|
||||
}
|
||||
|
||||
public static FeatureFlags1Edx FeatureInfo1Edx { get; }
|
||||
public static FeatureFlags1Ecx FeatureInfo1Ecx { get; }
|
||||
public static FeatureFlags7Ebx FeatureInfo7Ebx { get; } = 0;
|
||||
public static FeatureFlags7Ecx FeatureInfo7Ecx { get; } = 0;
|
||||
|
||||
public static bool SupportsSse => FeatureInfo1Edx.HasFlag(FeatureFlags1Edx.Sse);
|
||||
public static bool SupportsSse2 => FeatureInfo1Edx.HasFlag(FeatureFlags1Edx.Sse2);
|
||||
@@ -72,6 +80,7 @@ namespace ARMeilleure.CodeGen.X86
|
||||
public static bool SupportsAvx2 => FeatureInfo7Ebx.HasFlag(FeatureFlags7Ebx.Avx2) && SupportsAvx;
|
||||
public static bool SupportsF16c => FeatureInfo1Ecx.HasFlag(FeatureFlags1Ecx.F16c);
|
||||
public static bool SupportsSha => FeatureInfo7Ebx.HasFlag(FeatureFlags7Ebx.Sha);
|
||||
public static bool SupportsGfni => FeatureInfo7Ecx.HasFlag(FeatureFlags7Ecx.Gfni);
|
||||
|
||||
public static bool ForceLegacySse { get; set; }
|
||||
|
||||
|
@@ -58,6 +58,7 @@ namespace ARMeilleure.CodeGen.X86
|
||||
Add(Intrinsic.X86Divps, new IntrinsicInfo(X86Instruction.Divps, IntrinsicType.Binary));
|
||||
Add(Intrinsic.X86Divsd, new IntrinsicInfo(X86Instruction.Divsd, IntrinsicType.Binary));
|
||||
Add(Intrinsic.X86Divss, new IntrinsicInfo(X86Instruction.Divss, IntrinsicType.Binary));
|
||||
Add(Intrinsic.X86Gf2p8affineqb, new IntrinsicInfo(X86Instruction.Gf2p8affineqb, IntrinsicType.TernaryImm));
|
||||
Add(Intrinsic.X86Haddpd, new IntrinsicInfo(X86Instruction.Haddpd, IntrinsicType.Binary));
|
||||
Add(Intrinsic.X86Haddps, new IntrinsicInfo(X86Instruction.Haddps, IntrinsicType.Binary));
|
||||
Add(Intrinsic.X86Insertps, new IntrinsicInfo(X86Instruction.Insertps, IntrinsicType.TernaryImm));
|
||||
|
@@ -54,6 +54,7 @@ namespace ARMeilleure.CodeGen.X86
|
||||
Divps,
|
||||
Divsd,
|
||||
Divss,
|
||||
Gf2p8affineqb,
|
||||
Haddpd,
|
||||
Haddps,
|
||||
Idiv,
|
||||
|
@@ -243,6 +243,21 @@ namespace ARMeilleure.Instructions
|
||||
throw new ArgumentException($"Invalid rounding mode \"{roundMode}\".");
|
||||
}
|
||||
|
||||
public static ulong X86GetGf2p8LogicalShiftLeft(int shift)
|
||||
{
|
||||
ulong identity =
|
||||
(0b00000001UL << 56) |
|
||||
(0b00000010UL << 48) |
|
||||
(0b00000100UL << 40) |
|
||||
(0b00001000UL << 32) |
|
||||
(0b00010000UL << 24) |
|
||||
(0b00100000UL << 16) |
|
||||
(0b01000000UL << 8) |
|
||||
(0b10000000UL << 0);
|
||||
|
||||
return shift >= 0 ? identity >> (shift * 8) : identity << (-shift * 8);
|
||||
}
|
||||
|
||||
public static Operand EmitCountSetBits8(ArmEmitterContext context, Operand op) // "size" is 8 (SIMD&FP Inst.).
|
||||
{
|
||||
Debug.Assert(op.Type == OperandType.I32 || op.Type == OperandType.I64);
|
||||
|
@@ -336,8 +336,32 @@ namespace ARMeilleure.Instructions
|
||||
{
|
||||
OpCodeSimd op = (OpCodeSimd)context.CurrOp;
|
||||
|
||||
Operand res = context.VectorZero();
|
||||
if (Optimizations.UseGfni)
|
||||
{
|
||||
const long bitMatrix =
|
||||
(0b10000000L << 56) |
|
||||
(0b01000000L << 48) |
|
||||
(0b00100000L << 40) |
|
||||
(0b00010000L << 32) |
|
||||
(0b00001000L << 24) |
|
||||
(0b00000100L << 16) |
|
||||
(0b00000010L << 8) |
|
||||
(0b00000001L << 0);
|
||||
|
||||
Operand vBitMatrix = X86GetAllElements(context, bitMatrix);
|
||||
|
||||
Operand res = context.AddIntrinsic(Intrinsic.X86Gf2p8affineqb, GetVec(op.Rn), vBitMatrix, Const(0));
|
||||
|
||||
if (op.RegisterSize == RegisterSize.Simd64)
|
||||
{
|
||||
res = context.VectorZeroUpper64(res);
|
||||
}
|
||||
|
||||
context.Copy(GetVec(op.Rd), res);
|
||||
}
|
||||
else
|
||||
{
|
||||
Operand res = context.VectorZero();
|
||||
int elems = op.RegisterSize == RegisterSize.Simd128 ? 16 : 8;
|
||||
|
||||
for (int index = 0; index < elems; index++)
|
||||
@@ -351,6 +375,7 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
context.Copy(GetVec(op.Rd), res);
|
||||
}
|
||||
}
|
||||
|
||||
private static Operand EmitReverseBits8Op(ArmEmitterContext context, Operand op)
|
||||
{
|
||||
|
@@ -88,8 +88,35 @@ namespace ARMeilleure.Instructions
|
||||
OpCodeSimdShImm op = (OpCodeSimdShImm)context.CurrOp;
|
||||
|
||||
int shift = GetImmShl(op);
|
||||
int eSize = 8 << op.Size;
|
||||
|
||||
if (Optimizations.UseSse2 && op.Size > 0)
|
||||
if (shift >= eSize)
|
||||
{
|
||||
if ((op.RegisterSize == RegisterSize.Simd64))
|
||||
{
|
||||
Operand res = context.VectorZeroUpper64(GetVec(op.Rd));
|
||||
|
||||
context.Copy(GetVec(op.Rd), res);
|
||||
}
|
||||
}
|
||||
else if (Optimizations.UseGfni && op.Size == 0)
|
||||
{
|
||||
Operand n = GetVec(op.Rn);
|
||||
|
||||
ulong bitMatrix = X86GetGf2p8LogicalShiftLeft(shift);
|
||||
|
||||
Operand vBitMatrix = X86GetElements(context, bitMatrix, bitMatrix);
|
||||
|
||||
Operand res = context.AddIntrinsic(Intrinsic.X86Gf2p8affineqb, n, vBitMatrix, Const(0));
|
||||
|
||||
if (op.RegisterSize == RegisterSize.Simd64)
|
||||
{
|
||||
res = context.VectorZeroUpper64(res);
|
||||
}
|
||||
|
||||
context.Copy(GetVec(op.Rd), res);
|
||||
}
|
||||
else if (Optimizations.UseSse2 && op.Size > 0)
|
||||
{
|
||||
Operand n = GetVec(op.Rn);
|
||||
|
||||
@@ -396,10 +423,40 @@ namespace ARMeilleure.Instructions
|
||||
{
|
||||
OpCodeSimdShImm op = (OpCodeSimdShImm)context.CurrOp;
|
||||
|
||||
if (Optimizations.UseSse2 && op.Size > 0 && op.Size < 3)
|
||||
{
|
||||
int shift = GetImmShr(op);
|
||||
|
||||
if (Optimizations.UseGfni && op.Size == 0)
|
||||
{
|
||||
Operand n = GetVec(op.Rn);
|
||||
|
||||
ulong bitMatrix;
|
||||
|
||||
if (shift < 8)
|
||||
{
|
||||
bitMatrix = X86GetGf2p8LogicalShiftLeft(-shift);
|
||||
|
||||
// Extend sign-bit
|
||||
bitMatrix |= 0x8080808080808080UL >> (64 - shift * 8);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Replicate sign-bit into all bits
|
||||
bitMatrix = 0x8080808080808080UL;
|
||||
}
|
||||
|
||||
Operand vBitMatrix = X86GetElements(context, bitMatrix, bitMatrix);
|
||||
|
||||
Operand res = context.AddIntrinsic(Intrinsic.X86Gf2p8affineqb, n, vBitMatrix, Const(0));
|
||||
|
||||
if (op.RegisterSize == RegisterSize.Simd64)
|
||||
{
|
||||
res = context.VectorZeroUpper64(res);
|
||||
}
|
||||
|
||||
context.Copy(GetVec(op.Rd), res);
|
||||
}
|
||||
else if (Optimizations.UseSse2 && op.Size > 0 && op.Size < 3)
|
||||
{
|
||||
Operand n = GetVec(op.Rn);
|
||||
|
||||
Intrinsic sraInst = X86PsraInstruction[op.Size];
|
||||
@@ -929,10 +986,44 @@ namespace ARMeilleure.Instructions
|
||||
OpCodeSimdShImm op = (OpCodeSimdShImm)context.CurrOp;
|
||||
|
||||
int shift = GetImmShl(op);
|
||||
int eSize = 8 << op.Size;
|
||||
|
||||
ulong mask = shift != 0 ? ulong.MaxValue >> (64 - shift) : 0UL;
|
||||
|
||||
if (Optimizations.UseSse2 && op.Size > 0)
|
||||
if (shift >= eSize)
|
||||
{
|
||||
if ((op.RegisterSize == RegisterSize.Simd64) || scalar)
|
||||
{
|
||||
Operand res = context.VectorZeroUpper64(GetVec(op.Rd));
|
||||
|
||||
context.Copy(GetVec(op.Rd), res);
|
||||
}
|
||||
}
|
||||
else if (Optimizations.UseGfni && op.Size == 0)
|
||||
{
|
||||
Operand d = GetVec(op.Rd);
|
||||
Operand n = GetVec(op.Rn);
|
||||
|
||||
ulong bitMatrix = X86GetGf2p8LogicalShiftLeft(shift);
|
||||
|
||||
Operand vBitMatrix = X86GetElements(context, bitMatrix, bitMatrix);
|
||||
|
||||
Operand nShifted = context.AddIntrinsic(Intrinsic.X86Gf2p8affineqb, n, vBitMatrix, Const(0));
|
||||
|
||||
Operand dMask = X86GetAllElements(context, (long)mask * _masks_SliSri[op.Size]);
|
||||
|
||||
Operand dMasked = context.AddIntrinsic(Intrinsic.X86Pand, d, dMask);
|
||||
|
||||
Operand res = context.AddIntrinsic(Intrinsic.X86Por, nShifted, dMasked);
|
||||
|
||||
if ((op.RegisterSize == RegisterSize.Simd64) || scalar)
|
||||
{
|
||||
res = context.VectorZeroUpper64(res);
|
||||
}
|
||||
|
||||
context.Copy(d, res);
|
||||
}
|
||||
else if (Optimizations.UseSse2 && op.Size > 0)
|
||||
{
|
||||
Operand d = GetVec(op.Rd);
|
||||
Operand n = GetVec(op.Rn);
|
||||
@@ -988,7 +1079,40 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
ulong mask = (ulong.MaxValue << (eSize - shift)) & (ulong.MaxValue >> (64 - eSize));
|
||||
|
||||
if (Optimizations.UseSse2 && op.Size > 0)
|
||||
if (shift >= eSize)
|
||||
{
|
||||
if ((op.RegisterSize == RegisterSize.Simd64) || scalar)
|
||||
{
|
||||
Operand res = context.VectorZeroUpper64(GetVec(op.Rd));
|
||||
|
||||
context.Copy(GetVec(op.Rd), res);
|
||||
}
|
||||
}
|
||||
else if (Optimizations.UseGfni && op.Size == 0)
|
||||
{
|
||||
Operand d = GetVec(op.Rd);
|
||||
Operand n = GetVec(op.Rn);
|
||||
|
||||
ulong bitMatrix = X86GetGf2p8LogicalShiftLeft(-shift);
|
||||
|
||||
Operand vBitMatrix = X86GetElements(context, bitMatrix, bitMatrix);
|
||||
|
||||
Operand nShifted = context.AddIntrinsic(Intrinsic.X86Gf2p8affineqb, n, vBitMatrix, Const(0));
|
||||
|
||||
Operand dMask = X86GetAllElements(context, (long)mask * _masks_SliSri[op.Size]);
|
||||
|
||||
Operand dMasked = context.AddIntrinsic(Intrinsic.X86Pand, d, dMask);
|
||||
|
||||
Operand res = context.AddIntrinsic(Intrinsic.X86Por, nShifted, dMasked);
|
||||
|
||||
if ((op.RegisterSize == RegisterSize.Simd64) || scalar)
|
||||
{
|
||||
res = context.VectorZeroUpper64(res);
|
||||
}
|
||||
|
||||
context.Copy(d, res);
|
||||
}
|
||||
else if (Optimizations.UseSse2 && op.Size > 0)
|
||||
{
|
||||
Operand d = GetVec(op.Rd);
|
||||
Operand n = GetVec(op.Rn);
|
||||
|
@@ -47,6 +47,7 @@ namespace ARMeilleure.IntermediateRepresentation
|
||||
X86Divps,
|
||||
X86Divsd,
|
||||
X86Divss,
|
||||
X86Gf2p8affineqb,
|
||||
X86Haddpd,
|
||||
X86Haddps,
|
||||
X86Insertps,
|
||||
|
@@ -22,6 +22,7 @@ namespace ARMeilleure
|
||||
public static bool UseAesniIfAvailable { get; set; } = true;
|
||||
public static bool UsePclmulqdqIfAvailable { get; set; } = true;
|
||||
public static bool UseShaIfAvailable { get; set; } = true;
|
||||
public static bool UseGfniIfAvailable { get; set; } = true;
|
||||
|
||||
public static bool ForceLegacySse
|
||||
{
|
||||
@@ -42,5 +43,6 @@ namespace ARMeilleure
|
||||
internal static bool UseAesni => UseAesniIfAvailable && HardwareCapabilities.SupportsAesni;
|
||||
internal static bool UsePclmulqdq => UsePclmulqdqIfAvailable && HardwareCapabilities.SupportsPclmulqdq;
|
||||
internal static bool UseSha => UseShaIfAvailable && HardwareCapabilities.SupportsSha;
|
||||
internal static bool UseGfni => UseGfniIfAvailable && HardwareCapabilities.SupportsGfni;
|
||||
}
|
||||
}
|
@@ -27,7 +27,7 @@ namespace ARMeilleure.Translation.PTC
|
||||
private const string OuterHeaderMagicString = "PTCohd\0\0";
|
||||
private const string InnerHeaderMagicString = "PTCihd\0\0";
|
||||
|
||||
private const uint InternalVersion = 3703; //! To be incremented manually for each change to the ARMeilleure project.
|
||||
private const uint InternalVersion = 3710; //! To be incremented manually for each change to the ARMeilleure project.
|
||||
|
||||
private const string ActualDir = "0";
|
||||
private const string BackupDir = "1";
|
||||
@@ -951,7 +951,8 @@ namespace ARMeilleure.Translation.PTC
|
||||
return new FeatureInfo(
|
||||
(uint)HardwareCapabilities.FeatureInfo1Ecx,
|
||||
(uint)HardwareCapabilities.FeatureInfo1Edx,
|
||||
(uint)HardwareCapabilities.FeatureInfo7Ebx);
|
||||
(uint)HardwareCapabilities.FeatureInfo7Ebx,
|
||||
(uint)HardwareCapabilities.FeatureInfo7Ecx);
|
||||
}
|
||||
|
||||
private static byte GetMemoryManagerMode()
|
||||
@@ -971,7 +972,7 @@ namespace ARMeilleure.Translation.PTC
|
||||
return osPlatform;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1/*, Size = 54*/)]
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1/*, Size = 58*/)]
|
||||
private struct OuterHeader
|
||||
{
|
||||
public ulong Magic;
|
||||
@@ -1002,8 +1003,8 @@ namespace ARMeilleure.Translation.PTC
|
||||
}
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1/*, Size = 12*/)]
|
||||
private record struct FeatureInfo(uint FeatureInfo0, uint FeatureInfo1, uint FeatureInfo2);
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1/*, Size = 16*/)]
|
||||
private record struct FeatureInfo(uint FeatureInfo0, uint FeatureInfo1, uint FeatureInfo2, uint FeatureInfo3);
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1/*, Size = 128*/)]
|
||||
private struct InnerHeader
|
||||
|
@@ -58,6 +58,8 @@ namespace Ryujinx.Ava
|
||||
private const float MaxResolutionScale = 4.0f; // Max resolution hotkeys can scale to before wrapping.
|
||||
private const int TargetFps = 60;
|
||||
|
||||
private const float VolumeDelta = 0.05f;
|
||||
|
||||
private static readonly Cursor InvisibleCursor = new Cursor(StandardCursorType.None);
|
||||
|
||||
private readonly long _ticksPerFrame;
|
||||
@@ -73,6 +75,7 @@ namespace Ryujinx.Ava
|
||||
private bool _isStopped;
|
||||
private bool _isActive;
|
||||
private long _lastCursorMoveTime;
|
||||
private float _newVolume;
|
||||
private long _ticks = 0;
|
||||
|
||||
private KeyboardHotkeyState _prevHotkeyState;
|
||||
@@ -1003,6 +1006,18 @@ namespace Ryujinx.Ava
|
||||
GraphicsConfig.ResScale =
|
||||
(MaxResolutionScale + GraphicsConfig.ResScale - 2) % MaxResolutionScale + 1;
|
||||
break;
|
||||
case KeyboardHotkeyState.VolumeUp:
|
||||
_newVolume = MathF.Round((Device.GetVolume() + VolumeDelta), 2);
|
||||
Device.SetVolume(_newVolume);
|
||||
|
||||
_parent.ViewModel.Volume = Device.GetVolume();
|
||||
break;
|
||||
case KeyboardHotkeyState.VolumeDown:
|
||||
_newVolume = MathF.Round((Device.GetVolume() - VolumeDelta), 2);
|
||||
Device.SetVolume(_newVolume);
|
||||
|
||||
_parent.ViewModel.Volume = Device.GetVolume();
|
||||
break;
|
||||
case KeyboardHotkeyState.None:
|
||||
(_keyboardInterface as AvaloniaKeyboard).Clear();
|
||||
break;
|
||||
@@ -1068,6 +1083,14 @@ namespace Ryujinx.Ava
|
||||
{
|
||||
state = KeyboardHotkeyState.ResScaleDown;
|
||||
}
|
||||
else if (_keyboardInterface.IsPressed((Key)ConfigurationState.Instance.Hid.Hotkeys.Value.VolumeUp))
|
||||
{
|
||||
state = KeyboardHotkeyState.VolumeUp;
|
||||
}
|
||||
else if (_keyboardInterface.IsPressed((Key)ConfigurationState.Instance.Hid.Hotkeys.Value.VolumeDown))
|
||||
{
|
||||
state = KeyboardHotkeyState.VolumeDown;
|
||||
}
|
||||
|
||||
return state;
|
||||
}
|
||||
|
@@ -589,5 +589,8 @@
|
||||
"SettingsAppRequiredRestartMessage": "Ryujinx Restart Required",
|
||||
"SettingsGpuBackendRestartMessage": "Graphics Backend or Gpu settings have been modified. This will require a restart to be applied",
|
||||
"SettingsGpuBackendRestartSubMessage": "Do you want to restart now?",
|
||||
"RyujinxUpdaterMessage": "Do you want to update Ryujinx to the latest version?",
|
||||
"SettingsTabHotkeysVolumeUpHotkey": "Increase Volume:",
|
||||
"SettingsTabHotkeysVolumeDownHotkey": "Decrease Volume:",
|
||||
"VolumeShort": "Vol"
|
||||
}
|
||||
|
@@ -9,6 +9,8 @@
|
||||
Pause,
|
||||
ToggleMute,
|
||||
ResScaleUp,
|
||||
ResScaleDown
|
||||
ResScaleDown,
|
||||
VolumeUp,
|
||||
VolumeDown
|
||||
}
|
||||
}
|
@@ -1,4 +1,6 @@
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Threading;
|
||||
using FluentAvalonia.UI.Controls;
|
||||
using ICSharpCode.SharpZipLib.GZip;
|
||||
using ICSharpCode.SharpZipLib.Tar;
|
||||
using ICSharpCode.SharpZipLib.Zip;
|
||||
@@ -11,11 +13,13 @@ using Ryujinx.Common;
|
||||
using Ryujinx.Common.Logging;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Net.NetworkInformation;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
@@ -40,6 +44,8 @@ namespace Ryujinx.Modules
|
||||
|
||||
private static readonly string[] WindowsDependencyDirs = Array.Empty<string>();
|
||||
|
||||
public static bool UpdateSuccessful { get; private set; }
|
||||
|
||||
public static async Task BeginParse(MainWindow mainWindow, bool showVersionUpToDate)
|
||||
{
|
||||
if (Running)
|
||||
@@ -198,11 +204,18 @@ namespace Ryujinx.Modules
|
||||
_buildSize = -1;
|
||||
}
|
||||
}
|
||||
|
||||
Dispatcher.UIThread.Post(async () =>
|
||||
{
|
||||
// Show a message asking the user if they want to update
|
||||
UpdaterWindow updateDialog = new(mainWindow, newVersion, _buildUrl);
|
||||
await updateDialog.ShowDialog(mainWindow);
|
||||
var shouldUpdate = await ContentDialogHelper.CreateChoiceDialog(LocaleManager.Instance["RyujinxUpdater"],
|
||||
LocaleManager.Instance["RyujinxUpdaterMessage"],
|
||||
$"{Program.Version} -> {newVersion}");
|
||||
|
||||
if (shouldUpdate)
|
||||
{
|
||||
UpdateRyujinx(mainWindow, _buildUrl);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -216,8 +229,10 @@ namespace Ryujinx.Modules
|
||||
return result;
|
||||
}
|
||||
|
||||
public static void UpdateRyujinx(UpdaterWindow updateDialog, string downloadUrl)
|
||||
public static async void UpdateRyujinx(Window parent, string downloadUrl)
|
||||
{
|
||||
UpdateSuccessful = false;
|
||||
|
||||
// Empty update dir, although it shouldn't ever have anything inside it
|
||||
if (Directory.Exists(UpdateDir))
|
||||
{
|
||||
@@ -228,25 +243,56 @@ namespace Ryujinx.Modules
|
||||
|
||||
string updateFile = Path.Combine(UpdateDir, "update.bin");
|
||||
|
||||
// Download the update .zip
|
||||
updateDialog.MainText.Text = LocaleManager.Instance["UpdaterDownloading"];
|
||||
updateDialog.ProgressBar.Value = 0;
|
||||
updateDialog.ProgressBar.Maximum = 100;
|
||||
var taskDialog = new TaskDialog()
|
||||
{
|
||||
Header = LocaleManager.Instance["RyujinxUpdater"],
|
||||
SubHeader = LocaleManager.Instance["UpdaterDownloading"],
|
||||
IconSource = new SymbolIconSource { Symbol = Symbol.Download },
|
||||
Buttons = { },
|
||||
ShowProgressBar = true
|
||||
};
|
||||
|
||||
Task.Run(() =>
|
||||
taskDialog.XamlRoot = parent;
|
||||
|
||||
taskDialog.Opened += (s, e) =>
|
||||
{
|
||||
if (_buildSize >= 0)
|
||||
{
|
||||
DoUpdateWithMultipleThreads(updateDialog, downloadUrl, updateFile);
|
||||
DoUpdateWithMultipleThreads(taskDialog, downloadUrl, updateFile);
|
||||
}
|
||||
else
|
||||
{
|
||||
DoUpdateWithSingleThread(updateDialog, downloadUrl, updateFile);
|
||||
DoUpdateWithSingleThread(taskDialog, downloadUrl, updateFile);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
await taskDialog.ShowAsync(true);
|
||||
|
||||
if (UpdateSuccessful)
|
||||
{
|
||||
var shouldRestart = await ContentDialogHelper.CreateChoiceDialog(LocaleManager.Instance["RyujinxUpdater"],
|
||||
LocaleManager.Instance["DialogUpdaterCompleteMessage"],
|
||||
LocaleManager.Instance["DialogUpdaterRestartMessage"]);
|
||||
|
||||
if (shouldRestart)
|
||||
{
|
||||
string ryuName = Path.GetFileName(Environment.ProcessPath);
|
||||
string ryuExe = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, ryuName);
|
||||
string ryuArg = string.Join(" ", Environment.GetCommandLineArgs().Skip(1).ToArray());
|
||||
|
||||
if (!OperatingSystem.IsWindows())
|
||||
{
|
||||
chmod(ryuExe, Convert.ToUInt32("0777", 8));
|
||||
}
|
||||
|
||||
private static void DoUpdateWithMultipleThreads(UpdaterWindow updateDialog, string downloadUrl, string updateFile)
|
||||
Process.Start(ryuExe, ryuArg);
|
||||
|
||||
Environment.Exit(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void DoUpdateWithMultipleThreads(TaskDialog taskDialog, string downloadUrl, string updateFile)
|
||||
{
|
||||
// Multi-Threaded Updater
|
||||
long chunkSize = _buildSize / ConnectionCount;
|
||||
@@ -290,7 +336,7 @@ namespace Ryujinx.Modules
|
||||
Interlocked.Exchange(ref progressPercentage[index], args.ProgressPercentage);
|
||||
Interlocked.Add(ref totalProgressPercentage, args.ProgressPercentage);
|
||||
|
||||
updateDialog.ProgressBar.Value = totalProgressPercentage / ConnectionCount;
|
||||
taskDialog.SetProgressBarState(totalProgressPercentage / ConnectionCount, TaskDialogProgressState.Normal);
|
||||
};
|
||||
|
||||
client.DownloadDataCompleted += (_, args) =>
|
||||
@@ -301,6 +347,8 @@ namespace Ryujinx.Modules
|
||||
{
|
||||
webClients[index].Dispose();
|
||||
|
||||
taskDialog.Hide();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -320,14 +368,14 @@ namespace Ryujinx.Modules
|
||||
|
||||
try
|
||||
{
|
||||
InstallUpdate(updateDialog, updateFile);
|
||||
InstallUpdate(taskDialog, updateFile);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.Warning?.Print(LogClass.Application, e.Message);
|
||||
Logger.Warning?.Print(LogClass.Application, "Multi-Threaded update failed, falling back to single-threaded updater.");
|
||||
|
||||
DoUpdateWithSingleThread(updateDialog, downloadUrl, updateFile);
|
||||
DoUpdateWithSingleThread(taskDialog, downloadUrl, updateFile);
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -348,7 +396,7 @@ namespace Ryujinx.Modules
|
||||
webClients[j].CancelAsync();
|
||||
}
|
||||
|
||||
DoUpdateWithSingleThread(updateDialog, downloadUrl, updateFile);
|
||||
DoUpdateWithSingleThread(taskDialog, downloadUrl, updateFile);
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -356,7 +404,7 @@ namespace Ryujinx.Modules
|
||||
}
|
||||
}
|
||||
|
||||
private static void DoUpdateWithSingleThreadWorker(UpdaterWindow updateDialog, string downloadUrl, string updateFile)
|
||||
private static void DoUpdateWithSingleThreadWorker(TaskDialog taskDialog, string downloadUrl, string updateFile)
|
||||
{
|
||||
using (HttpClient client = new HttpClient())
|
||||
{
|
||||
@@ -384,19 +432,26 @@ namespace Ryujinx.Modules
|
||||
|
||||
byteWritten += readSize;
|
||||
|
||||
updateDialog.ProgressBar.Value = ((double)byteWritten / totalBytes) * 100;
|
||||
taskDialog.SetProgressBarState(GetPercentage(byteWritten, totalBytes), TaskDialogProgressState.Normal);
|
||||
|
||||
updateFileStream.Write(buffer, 0, readSize);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
InstallUpdate(updateDialog, updateFile);
|
||||
InstallUpdate(taskDialog, updateFile);
|
||||
}
|
||||
}
|
||||
|
||||
private static void DoUpdateWithSingleThread(UpdaterWindow updateDialog, string downloadUrl, string updateFile)
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static double GetPercentage(double value, double max)
|
||||
{
|
||||
Thread worker = new Thread(() => DoUpdateWithSingleThreadWorker(updateDialog, downloadUrl, updateFile));
|
||||
return max == 0 ? 0 : value / max * 100;
|
||||
}
|
||||
|
||||
private static void DoUpdateWithSingleThread(TaskDialog taskDialog, string downloadUrl, string updateFile)
|
||||
{
|
||||
Thread worker = new Thread(() => DoUpdateWithSingleThreadWorker(taskDialog, downloadUrl, updateFile));
|
||||
worker.Name = "Updater.SingleThreadWorker";
|
||||
worker.Start();
|
||||
}
|
||||
@@ -414,11 +469,11 @@ namespace Ryujinx.Modules
|
||||
}
|
||||
}
|
||||
|
||||
private static async void InstallUpdate(UpdaterWindow updateDialog, string updateFile)
|
||||
private static async void InstallUpdate(TaskDialog taskDialog, string updateFile)
|
||||
{
|
||||
// Extract Update
|
||||
updateDialog.MainText.Text = LocaleManager.Instance["UpdaterExtracting"];
|
||||
updateDialog.ProgressBar.Value = 0;
|
||||
taskDialog.SubHeader = LocaleManager.Instance["UpdaterExtracting"];
|
||||
taskDialog.SetProgressBarState(0, TaskDialogProgressState.Normal);
|
||||
|
||||
if (OperatingSystem.IsLinux())
|
||||
{
|
||||
@@ -426,8 +481,6 @@ namespace Ryujinx.Modules
|
||||
using (Stream gzipStream = new GZipInputStream(inStream))
|
||||
using (TarInputStream tarStream = new TarInputStream(gzipStream, Encoding.ASCII))
|
||||
{
|
||||
updateDialog.ProgressBar.Maximum = inStream.Length;
|
||||
|
||||
await Task.Run(() =>
|
||||
{
|
||||
TarEntry tarEntry;
|
||||
@@ -450,12 +503,12 @@ namespace Ryujinx.Modules
|
||||
|
||||
Dispatcher.UIThread.Post(() =>
|
||||
{
|
||||
updateDialog.ProgressBar.Value += entry.Size;
|
||||
taskDialog.SetProgressBarState(GetPercentage(entry.Size, inStream.Length), TaskDialogProgressState.Normal);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
updateDialog.ProgressBar.Value = inStream.Length;
|
||||
taskDialog.SetProgressBarState(100, TaskDialogProgressState.Normal);
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -463,12 +516,12 @@ namespace Ryujinx.Modules
|
||||
using (Stream inStream = File.OpenRead(updateFile))
|
||||
using (ZipFile zipFile = new ZipFile(inStream))
|
||||
{
|
||||
updateDialog.ProgressBar.Maximum = zipFile.Count;
|
||||
|
||||
await Task.Run(() =>
|
||||
{
|
||||
double count = 0;
|
||||
foreach (ZipEntry zipEntry in zipFile)
|
||||
{
|
||||
count++;
|
||||
if (zipEntry.IsDirectory) continue;
|
||||
|
||||
string outPath = Path.Combine(UpdateDir, zipEntry.Name);
|
||||
@@ -485,7 +538,7 @@ namespace Ryujinx.Modules
|
||||
|
||||
Dispatcher.UIThread.Post(() =>
|
||||
{
|
||||
updateDialog.ProgressBar.Value++;
|
||||
taskDialog.SetProgressBarState(GetPercentage(count, zipFile.Count), TaskDialogProgressState.Normal);
|
||||
});
|
||||
}
|
||||
});
|
||||
@@ -497,22 +550,23 @@ namespace Ryujinx.Modules
|
||||
|
||||
List<string> allFiles = EnumerateFilesToDelete().ToList();
|
||||
|
||||
updateDialog.MainText.Text = LocaleManager.Instance["UpdaterRenaming"];
|
||||
updateDialog.ProgressBar.Value = 0;
|
||||
updateDialog.ProgressBar.Maximum = allFiles.Count;
|
||||
taskDialog.SubHeader = LocaleManager.Instance["UpdaterRenaming"];
|
||||
taskDialog.SetProgressBarState(0, TaskDialogProgressState.Normal);
|
||||
|
||||
// Replace old files
|
||||
await Task.Run(() =>
|
||||
{
|
||||
double count = 0;
|
||||
foreach (string file in allFiles)
|
||||
{
|
||||
count++;
|
||||
try
|
||||
{
|
||||
File.Move(file, file + ".ryuold");
|
||||
|
||||
Dispatcher.UIThread.Post(() =>
|
||||
{
|
||||
updateDialog.ProgressBar.Value++;
|
||||
taskDialog.SetProgressBarState(GetPercentage(count, allFiles.Count), TaskDialogProgressState.Normal);
|
||||
});
|
||||
}
|
||||
catch
|
||||
@@ -523,23 +577,20 @@ namespace Ryujinx.Modules
|
||||
|
||||
Dispatcher.UIThread.Post(() =>
|
||||
{
|
||||
updateDialog.MainText.Text = LocaleManager.Instance["UpdaterAddingFiles"];
|
||||
updateDialog.ProgressBar.Value = 0;
|
||||
updateDialog.ProgressBar.Maximum = Directory.GetFiles(UpdatePublishDir, "*", SearchOption.AllDirectories).Length;
|
||||
taskDialog.SubHeader = LocaleManager.Instance["UpdaterAddingFiles"];
|
||||
taskDialog.SetProgressBarState(0, TaskDialogProgressState.Normal);
|
||||
});
|
||||
|
||||
MoveAllFilesOver(UpdatePublishDir, HomeDir, updateDialog);
|
||||
MoveAllFilesOver(UpdatePublishDir, HomeDir, taskDialog);
|
||||
});
|
||||
|
||||
Directory.Delete(UpdateDir, true);
|
||||
|
||||
SetUnixPermissions();
|
||||
|
||||
updateDialog.MainText.Text = LocaleManager.Instance["DialogUpdaterCompleteMessage"];
|
||||
updateDialog.SecondaryText.Text = LocaleManager.Instance["DialogUpdaterRestartMessage"];
|
||||
UpdateSuccessful = true;
|
||||
|
||||
updateDialog.ProgressBar.IsVisible = false;
|
||||
updateDialog.ButtonBox.IsVisible = true;
|
||||
taskDialog.Hide();
|
||||
}
|
||||
|
||||
#pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
|
||||
@@ -618,8 +669,9 @@ namespace Ryujinx.Modules
|
||||
return files;
|
||||
}
|
||||
|
||||
private static void MoveAllFilesOver(string root, string dest, UpdaterWindow dialog)
|
||||
private static void MoveAllFilesOver(string root, string dest, TaskDialog taskDialog)
|
||||
{
|
||||
var total = Directory.GetFiles(root, "*", SearchOption.AllDirectories).Length;
|
||||
foreach (string directory in Directory.GetDirectories(root))
|
||||
{
|
||||
string dirName = Path.GetFileName(directory);
|
||||
@@ -629,16 +681,18 @@ namespace Ryujinx.Modules
|
||||
Directory.CreateDirectory(Path.Combine(dest, dirName));
|
||||
}
|
||||
|
||||
MoveAllFilesOver(directory, Path.Combine(dest, dirName), dialog);
|
||||
MoveAllFilesOver(directory, Path.Combine(dest, dirName), taskDialog);
|
||||
}
|
||||
|
||||
double count = 0;
|
||||
foreach (string file in Directory.GetFiles(root))
|
||||
{
|
||||
count++;
|
||||
File.Move(file, Path.Combine(dest, Path.GetFileName(file)), true);
|
||||
|
||||
Dispatcher.UIThread.InvokeAsync(() =>
|
||||
{
|
||||
dialog.ProgressBar.Value++;
|
||||
taskDialog.SetProgressBarState(GetPercentage(count, total), TaskDialogProgressState.Normal);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@@ -6,7 +6,6 @@
|
||||
xmlns:locale="clr-namespace:Ryujinx.Ava.Common.Locale"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:window="clr-namespace:Ryujinx.Ava.Ui.Windows"
|
||||
Title="Ryujinx - About"
|
||||
Width="850"
|
||||
Height="550"
|
||||
MinWidth="500"
|
||||
|
@@ -257,6 +257,22 @@
|
||||
TextAlignment="Center" />
|
||||
</ToggleButton>
|
||||
</StackPanel>
|
||||
<StackPanel Margin="10,0,0,0" Orientation="Horizontal">
|
||||
<TextBlock VerticalAlignment="Center" Text="{locale:Locale SettingsTabHotkeysVolumeUpHotkey}" Width="230" />
|
||||
<ToggleButton Width="90" Height="27" Checked="Button_Checked" Unchecked="Button_Unchecked">
|
||||
<TextBlock
|
||||
Text="{Binding KeyboardHotkeys.VolumeUp, Mode=TwoWay, Converter={StaticResource Key}}"
|
||||
TextAlignment="Center" />
|
||||
</ToggleButton>
|
||||
</StackPanel>
|
||||
<StackPanel Margin="10,0,0,0" Orientation="Horizontal">
|
||||
<TextBlock VerticalAlignment="Center" Text="{locale:Locale SettingsTabHotkeysVolumeDownHotkey}" Width="230" />
|
||||
<ToggleButton Width="90" Height="27" Checked="Button_Checked" Unchecked="Button_Unchecked">
|
||||
<TextBlock
|
||||
Text="{Binding KeyboardHotkeys.VolumeDown, Mode=TwoWay, Converter={StaticResource Key}}"
|
||||
TextAlignment="Center" />
|
||||
</ToggleButton>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</ScrollViewer>
|
||||
|
@@ -1,66 +0,0 @@
|
||||
<window:StyleableWindow
|
||||
x:Class="Ryujinx.Ava.Ui.Windows.UpdaterWindow"
|
||||
xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:locale="clr-namespace:Ryujinx.Ava.Common.Locale"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:window="clr-namespace:Ryujinx.Ava.Ui.Windows"
|
||||
Title="Ryujinx Updater"
|
||||
Width="500"
|
||||
Height="500"
|
||||
MinWidth="500"
|
||||
MinHeight="500"
|
||||
d:DesignHeight="350"
|
||||
d:DesignWidth="400"
|
||||
CanResize="False"
|
||||
SizeToContent="Height"
|
||||
WindowStartupLocation="CenterOwner"
|
||||
mc:Ignorable="d">
|
||||
<Grid
|
||||
Margin="20"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Stretch">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition />
|
||||
<RowDefinition />
|
||||
<RowDefinition />
|
||||
<RowDefinition />
|
||||
<RowDefinition />
|
||||
</Grid.RowDefinitions>
|
||||
<TextBlock
|
||||
Name="MainText"
|
||||
Grid.Row="1"
|
||||
Height="20"
|
||||
HorizontalAlignment="Stretch"
|
||||
TextAlignment="Center" />
|
||||
<TextBlock
|
||||
Name="SecondaryText"
|
||||
Grid.Row="2"
|
||||
Height="20"
|
||||
HorizontalAlignment="Stretch"
|
||||
TextAlignment="Center" />
|
||||
<ProgressBar
|
||||
Name="ProgressBar"
|
||||
Grid.Row="3"
|
||||
Margin="20"
|
||||
HorizontalAlignment="Stretch"
|
||||
IsVisible="False"
|
||||
Maximum="100"
|
||||
Minimum="0" />
|
||||
<StackPanel
|
||||
Name="ButtonBox"
|
||||
Grid.Row="4"
|
||||
HorizontalAlignment="Right"
|
||||
IsVisible="False"
|
||||
Orientation="Horizontal"
|
||||
Spacing="20">
|
||||
<Button MinWidth="50" Command="{Binding YesPressed}">
|
||||
<TextBlock Text="{locale:Locale InputDialogYes}" TextAlignment="Center" />
|
||||
</Button>
|
||||
<Button MinWidth="50" Command="{Binding NoPressed}">
|
||||
<TextBlock Text="{locale:Locale InputDialogNo}" TextAlignment="Center" />
|
||||
</Button>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</window:StyleableWindow>
|
@@ -1,73 +0,0 @@
|
||||
using Ryujinx.Ava.Common.Locale;
|
||||
using Ryujinx.Modules;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Ryujinx.Ava.Ui.Windows
|
||||
{
|
||||
public partial class UpdaterWindow : StyleableWindow
|
||||
{
|
||||
private readonly string _buildUrl;
|
||||
private readonly MainWindow _mainWindow;
|
||||
private readonly Version _newVersion;
|
||||
private bool _restartQuery;
|
||||
|
||||
public UpdaterWindow()
|
||||
{
|
||||
DataContext = this;
|
||||
|
||||
InitializeComponent();
|
||||
|
||||
Title = LocaleManager.Instance["RyujinxUpdater"];
|
||||
}
|
||||
|
||||
public UpdaterWindow(MainWindow mainWindow, Version newVersion, string buildUrl) : this()
|
||||
{
|
||||
_mainWindow = mainWindow;
|
||||
_newVersion = newVersion;
|
||||
_buildUrl = buildUrl;
|
||||
}
|
||||
|
||||
[DllImport("libc", SetLastError = true)]
|
||||
private static extern int chmod(string path, uint mode);
|
||||
|
||||
public void YesPressed()
|
||||
{
|
||||
if (_restartQuery)
|
||||
{
|
||||
string ryuName = OperatingSystem.IsWindows() ? "Ryujinx.Ava.exe" : "Ryujinx.Ava";
|
||||
string ryuExe = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, ryuName);
|
||||
string ryuArg = string.Join(" ", Environment.GetCommandLineArgs().AsEnumerable().Skip(1).ToArray());
|
||||
|
||||
if (!OperatingSystem.IsWindows())
|
||||
{
|
||||
chmod(ryuExe, 0777);
|
||||
}
|
||||
|
||||
Process.Start(ryuExe, ryuArg);
|
||||
|
||||
Environment.Exit(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
ButtonBox.IsVisible = false;
|
||||
ProgressBar.IsVisible = true;
|
||||
|
||||
SecondaryText.Text = "";
|
||||
_restartQuery = true;
|
||||
|
||||
Updater.UpdateRyujinx(this, _buildUrl);
|
||||
}
|
||||
}
|
||||
|
||||
public void NoPressed()
|
||||
{
|
||||
_mainWindow.UpdateMenuItem.IsEnabled = true;
|
||||
|
||||
Close();
|
||||
}
|
||||
}
|
||||
}
|
@@ -9,5 +9,7 @@
|
||||
public Key ToggleMute { get; set; }
|
||||
public Key ResScaleUp { get; set; }
|
||||
public Key ResScaleDown { get; set; }
|
||||
public Key VolumeUp { get; set; }
|
||||
public Key VolumeDown { get; set; }
|
||||
}
|
||||
}
|
||||
|
@@ -22,7 +22,7 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache
|
||||
private const ushort FileFormatVersionMajor = 1;
|
||||
private const ushort FileFormatVersionMinor = 2;
|
||||
private const uint FileFormatVersionPacked = ((uint)FileFormatVersionMajor << 16) | FileFormatVersionMinor;
|
||||
private const uint CodeGenVersion = 3728;
|
||||
private const uint CodeGenVersion = 3732;
|
||||
|
||||
private const string SharedTocFileName = "shared.toc";
|
||||
private const string SharedDataFileName = "shared.data";
|
||||
|
@@ -123,7 +123,8 @@ namespace Ryujinx.Graphics.Gpu
|
||||
/// <param name="releaseCallback">Texture release callback</param>
|
||||
/// <param name="userObj">User defined object passed to the release callback</param>
|
||||
/// <exception cref="ArgumentException">Thrown when <paramref name="pid"/> is invalid</exception>
|
||||
public void EnqueueFrameThreadSafe(
|
||||
/// <returns>True if the frame was added to the queue, false otherwise</returns>
|
||||
public bool EnqueueFrameThreadSafe(
|
||||
ulong pid,
|
||||
ulong address,
|
||||
int width,
|
||||
@@ -140,7 +141,7 @@ namespace Ryujinx.Graphics.Gpu
|
||||
{
|
||||
if (!_context.PhysicalMemoryRegistry.TryGetValue(pid, out var physicalMemory))
|
||||
{
|
||||
throw new ArgumentException("The PID is invalid or the process was not registered", nameof(pid));
|
||||
return false;
|
||||
}
|
||||
|
||||
FormatInfo formatInfo = new FormatInfo(format, 1, 1, bytesPerPixel, 4);
|
||||
@@ -184,6 +185,8 @@ namespace Ryujinx.Graphics.Gpu
|
||||
acquireCallback,
|
||||
releaseCallback,
|
||||
userObj));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@@ -257,7 +257,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
|
||||
|
||||
DeclareSupportUniformBlock(context, context.Config.Stage, scaleElements);
|
||||
|
||||
if (context.Config.UsedFeatures.HasFlag(FeatureFlags.IntegerSampling))
|
||||
if (context.Config.UsedFeatures.HasFlag(FeatureFlags.IntegerSampling) && scaleElements != 0)
|
||||
{
|
||||
AppendHelperFunction(context, $"Ryujinx.Graphics.Shader/CodeGen/Glsl/HelperFunctions/TexelFetchScale_{stage}.glsl");
|
||||
context.AppendLine();
|
||||
|
@@ -279,16 +279,16 @@ namespace Ryujinx.Graphics.Shader.Decoders
|
||||
Add("1110101110xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.SuatomB2, InstEmit.SuatomB2, InstProps.Rd | InstProps.Ra | InstProps.Rb | InstProps.Rc);
|
||||
Add("1110101011010xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.SuatomCasB, InstEmit.SuatomCasB, InstProps.Rd | InstProps.Ra | InstProps.Rb | InstProps.Rc | InstProps.SPd);
|
||||
Add("1110101x1xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.SuatomCas, InstEmit.SuatomCas, InstProps.Rd | InstProps.Ra | InstProps.Rb | InstProps.SPd);
|
||||
Add("111010110001xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.SuldDB, InstEmit.SuldDB, InstProps.Rd | InstProps.Ra | InstProps.Rc | InstProps.SPd | InstProps.TexB);
|
||||
Add("1110101100010xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.SuldDB, InstEmit.SuldDB, InstProps.Rd | InstProps.Ra | InstProps.Rc | InstProps.SPd | InstProps.TexB);
|
||||
Add("1110101100011xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.SuldD, InstEmit.SuldD, InstProps.Rd | InstProps.Ra | InstProps.SPd | InstProps.Tex);
|
||||
Add("11101011000xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.SuldB, InstEmit.SuldB, InstProps.Rd | InstProps.Ra | InstProps.Rc | InstProps.SPd | InstProps.TexB);
|
||||
Add("11101011000x1xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Suld, InstEmit.Suld, InstProps.Rd | InstProps.Ra | InstProps.SPd | InstProps.Tex);
|
||||
Add("111010110101xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.SuredB, InstEmit.SuredB, InstProps.Rd | InstProps.Ra | InstProps.Rc);
|
||||
Add("1110101100000xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.SuldB, InstEmit.SuldB, InstProps.Rd | InstProps.Ra | InstProps.Rc | InstProps.SPd | InstProps.TexB);
|
||||
Add("1110101100001xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Suld, InstEmit.Suld, InstProps.Rd | InstProps.Ra | InstProps.SPd | InstProps.Tex);
|
||||
Add("1110101101010xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.SuredB, InstEmit.SuredB, InstProps.Rd | InstProps.Ra | InstProps.Rc);
|
||||
Add("1110101101011xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Sured, InstEmit.Sured, InstProps.Rd | InstProps.Ra);
|
||||
Add("111010110011xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.SustDB, InstEmit.SustDB, InstProps.Rd | InstProps.Ra | InstProps.Rc | InstProps.TexB);
|
||||
Add("1110101100110xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.SustDB, InstEmit.SustDB, InstProps.Rd | InstProps.Ra | InstProps.Rc | InstProps.TexB);
|
||||
Add("1110101100111xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.SustD, InstEmit.SustD, InstProps.Rd | InstProps.Ra | InstProps.Tex);
|
||||
Add("11101011001xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.SustB, InstEmit.SustB, InstProps.Rd | InstProps.Ra | InstProps.Rc | InstProps.TexB);
|
||||
Add("11101011001x1xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Sust, InstEmit.Sust, InstProps.Rd | InstProps.Ra | InstProps.Tex);
|
||||
Add("1110101100100xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.SustB, InstEmit.SustB, InstProps.Rd | InstProps.Ra | InstProps.Rc | InstProps.TexB);
|
||||
Add("1110101100101xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Sust, InstEmit.Sust, InstProps.Rd | InstProps.Ra | InstProps.Tex);
|
||||
Add("1111000011111xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Sync, InstEmit.Sync, InstProps.Bra);
|
||||
Add("11000xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Tex, InstEmit.Tex, InstProps.Rd | InstProps.Ra | InstProps.Rb | InstProps.TPd | InstProps.Tex);
|
||||
Add("1101111010xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.TexB, InstEmit.TexB, InstProps.Rd | InstProps.Ra | InstProps.Rb | InstProps.TPd | InstProps.TexB);
|
||||
|
@@ -123,7 +123,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
|
||||
{
|
||||
InstSuldB op = context.GetOp<InstSuldB>();
|
||||
|
||||
EmitSuld(context, op.CacheOp, op.Dim, 0, 0, op.Rgba, op.SrcA, op.Dest, 0, useComponents: true, false, isBindless: true);
|
||||
EmitSuld(context, op.CacheOp, op.Dim, 0, 0, op.Rgba, op.SrcA, op.Dest, op.SrcC, useComponents: true, false, isBindless: true);
|
||||
}
|
||||
|
||||
public static void Suld(EmitterContext context)
|
||||
|
@@ -38,6 +38,8 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
|
||||
private readonly IdList<BufferHolder> _buffers;
|
||||
|
||||
public int BufferCount { get; private set; }
|
||||
|
||||
public StagingBuffer StagingBuffer { get; }
|
||||
|
||||
public BufferManager(VulkanRenderer gd, PhysicalDevice physicalDevice, Device device)
|
||||
@@ -56,6 +58,8 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
return BufferHandle.Null;
|
||||
}
|
||||
|
||||
BufferCount++;
|
||||
|
||||
ulong handle64 = (uint)_buffers.Add(holder);
|
||||
|
||||
return Unsafe.As<ulong, BufferHandle>(ref handle64);
|
||||
|
@@ -24,6 +24,11 @@
|
||||
|
||||
public void Add(int cbIndex, int offset, int size)
|
||||
{
|
||||
if (size == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Some usages can be out of bounds (vertex buffer on amd), so bound if necessary.
|
||||
if (offset + size > _size)
|
||||
{
|
||||
@@ -39,6 +44,11 @@
|
||||
|
||||
public bool OverlapsWith(int cbIndex, int offset, int size)
|
||||
{
|
||||
if (size == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
int cbBase = cbIndex * _bitsPerCb;
|
||||
int start = cbBase + offset / _granularity;
|
||||
int end = cbBase + (offset + size - 1) / _granularity;
|
||||
|
@@ -16,6 +16,8 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
private Auto<DisposableBufferView> _bufferView;
|
||||
private Dictionary<GAL.Format, Auto<DisposableBufferView>> _selfManagedViews;
|
||||
|
||||
private int _bufferCount;
|
||||
|
||||
public int Width { get; }
|
||||
public int Height { get; }
|
||||
|
||||
@@ -107,7 +109,8 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
{
|
||||
if (_bufferHandle == buffer.Handle &&
|
||||
_offset == buffer.Offset &&
|
||||
_size == buffer.Size)
|
||||
_size == buffer.Size &&
|
||||
_bufferCount == _gd.BufferManager.BufferCount)
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -115,6 +118,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
_bufferHandle = buffer.Handle;
|
||||
_offset = buffer.Offset;
|
||||
_size = buffer.Size;
|
||||
_bufferCount = _gd.BufferManager.BufferCount;
|
||||
|
||||
ReleaseImpl();
|
||||
}
|
||||
|
@@ -453,7 +453,7 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
|
||||
Item = item
|
||||
};
|
||||
|
||||
_device.Gpu.Window.EnqueueFrameThreadSafe(
|
||||
if (_device.Gpu.Window.EnqueueFrameThreadSafe(
|
||||
layer.Owner,
|
||||
frameBufferAddress,
|
||||
frameBufferWidth,
|
||||
@@ -466,8 +466,8 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
|
||||
crop,
|
||||
AcquireBuffer,
|
||||
ReleaseBuffer,
|
||||
textureCallbackInformation);
|
||||
|
||||
textureCallbackInformation))
|
||||
{
|
||||
if (item.Fence.FenceCount == 0)
|
||||
{
|
||||
_device.Gpu.Window.SignalFrameReady();
|
||||
@@ -482,6 +482,11 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
|
||||
});
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ReleaseBuffer(textureCallbackInformation);
|
||||
}
|
||||
}
|
||||
|
||||
private void ReleaseBuffer(object obj)
|
||||
{
|
||||
|
@@ -124,7 +124,7 @@ namespace Ryujinx.HLE
|
||||
|
||||
public void SetVolume(float volume)
|
||||
{
|
||||
System.SetVolume(volume);
|
||||
System.SetVolume(Math.Clamp(volume, 0, 1));
|
||||
}
|
||||
|
||||
public float GetVolume()
|
||||
|
@@ -14,7 +14,7 @@ namespace Ryujinx.Ui.Common.Configuration
|
||||
/// <summary>
|
||||
/// The current version of the file format
|
||||
/// </summary>
|
||||
public const int CurrentVersion = 40;
|
||||
public const int CurrentVersion = 41;
|
||||
|
||||
/// <summary>
|
||||
/// Version of the configuration file format
|
||||
|
@@ -677,7 +677,9 @@ namespace Ryujinx.Ui.Common.Configuration
|
||||
ShowUi = Key.F4,
|
||||
Pause = Key.F5,
|
||||
ResScaleUp = Key.Unbound,
|
||||
ResScaleDown = Key.Unbound
|
||||
ResScaleDown = Key.Unbound,
|
||||
VolumeUp = Key.Unbound,
|
||||
VolumeDown = Key.Unbound
|
||||
};
|
||||
Hid.InputConfig.Value = new List<InputConfig>
|
||||
{
|
||||
@@ -1156,6 +1158,24 @@ namespace Ryujinx.Ui.Common.Configuration
|
||||
configurationFileUpdated = true;
|
||||
}
|
||||
|
||||
if (configurationFileFormat.Version < 41)
|
||||
{
|
||||
Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 41.");
|
||||
|
||||
configurationFileFormat.Hotkeys = new KeyboardHotkeys
|
||||
{
|
||||
ToggleVsync = configurationFileFormat.Hotkeys.ToggleVsync,
|
||||
Screenshot = configurationFileFormat.Hotkeys.Screenshot,
|
||||
ShowUi = configurationFileFormat.Hotkeys.ShowUi,
|
||||
Pause = configurationFileFormat.Hotkeys.Pause,
|
||||
ToggleMute = configurationFileFormat.Hotkeys.ToggleMute,
|
||||
ResScaleUp = configurationFileFormat.Hotkeys.ResScaleUp,
|
||||
ResScaleDown = configurationFileFormat.Hotkeys.ResScaleDown,
|
||||
VolumeUp = Key.Unbound,
|
||||
VolumeDown = Key.Unbound
|
||||
};
|
||||
}
|
||||
|
||||
Logger.EnableFileLog.Value = configurationFileFormat.EnableFileLog;
|
||||
Graphics.ResScale.Value = configurationFileFormat.ResScale;
|
||||
Graphics.ResScaleCustom.Value = configurationFileFormat.ResScaleCustom;
|
||||
|
@@ -35,6 +35,7 @@ namespace Ryujinx.Ui
|
||||
private const int SwitchPanelHeight = 720;
|
||||
private const int TargetFps = 60;
|
||||
private const float MaxResolutionScale = 4.0f; // Max resolution hotkeys can scale to before wrapping.
|
||||
private const float VolumeDelta = 0.05f;
|
||||
|
||||
public ManualResetEvent WaitEvent { get; set; }
|
||||
public NpadManager NpadManager { get; }
|
||||
@@ -57,6 +58,7 @@ namespace Ryujinx.Ui
|
||||
private readonly long _ticksPerFrame;
|
||||
|
||||
private long _ticks = 0;
|
||||
private float _newVolume;
|
||||
|
||||
private readonly Stopwatch _chrono;
|
||||
|
||||
@@ -643,6 +645,20 @@ namespace Ryujinx.Ui
|
||||
(MaxResolutionScale + GraphicsConfig.ResScale - 2) % MaxResolutionScale + 1;
|
||||
}
|
||||
|
||||
if (currentHotkeyState.HasFlag(KeyboardHotkeyState.VolumeUp) &&
|
||||
!_prevHotkeyState.HasFlag(KeyboardHotkeyState.VolumeUp))
|
||||
{
|
||||
_newVolume = MathF.Round((Device.GetVolume() + VolumeDelta), 2);
|
||||
Device.SetVolume(_newVolume);
|
||||
}
|
||||
|
||||
if (currentHotkeyState.HasFlag(KeyboardHotkeyState.VolumeDown) &&
|
||||
!_prevHotkeyState.HasFlag(KeyboardHotkeyState.VolumeDown))
|
||||
{
|
||||
_newVolume = MathF.Round((Device.GetVolume() - VolumeDelta), 2);
|
||||
Device.SetVolume(_newVolume);
|
||||
}
|
||||
|
||||
_prevHotkeyState = currentHotkeyState;
|
||||
}
|
||||
|
||||
@@ -675,7 +691,9 @@ namespace Ryujinx.Ui
|
||||
Pause = 1 << 3,
|
||||
ToggleMute = 1 << 4,
|
||||
ResScaleUp = 1 << 5,
|
||||
ResScaleDown = 1 << 6
|
||||
ResScaleDown = 1 << 6,
|
||||
VolumeUp = 1 << 7,
|
||||
VolumeDown = 1 << 8
|
||||
}
|
||||
|
||||
private KeyboardHotkeyState GetHotkeyState()
|
||||
@@ -717,6 +735,16 @@ namespace Ryujinx.Ui
|
||||
state |= KeyboardHotkeyState.ResScaleDown;
|
||||
}
|
||||
|
||||
if (_keyboardInterface.IsPressed((Key)ConfigurationState.Instance.Hid.Hotkeys.Value.VolumeUp))
|
||||
{
|
||||
state |= KeyboardHotkeyState.VolumeUp;
|
||||
}
|
||||
|
||||
if (_keyboardInterface.IsPressed((Key)ConfigurationState.Instance.Hid.Hotkeys.Value.VolumeDown))
|
||||
{
|
||||
state |= KeyboardHotkeyState.VolumeDown;
|
||||
}
|
||||
|
||||
return state;
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user