Compare commits

...

12 Commits

Author SHA1 Message Date
riperiperi
1ca0517c99 Vulkan: Fix some issues with CacheByRange (#3743)
* Fix some issues with CacheByRange

- Cache now clears under more circumstances, the most important being the fast path write.
- Cache supports partial clear which should help when more buffers join.
- Fixed an issue with I8->I16 conversion where it wouldn't register the buffer for use on dispose.

Should hopefully fix issues with https://github.com/Ryujinx/Ryujinx-Games-List/issues/4010 and maybe others.

* Fix collection modified exception

* Fix accidental use of parameterless constructor

* Replay DynamicState when restoring from helper shader
2022-10-08 11:28:27 -03:00
gdkchan
599d485bff Change NvMap ID allocation to match nvservices (#3741)
* Change NvMap ID allocation to match nvservices

* Move NvMapIdDictionary to Types
2022-10-05 17:49:18 -03:00
gdkchan
60e16c15b6 Fix memory corruption in BCAT and FS Read methods when buffer is larger than needed (#3739)
* Fix memory corruption in FS Read methods when buffer is larger than needed

* PR feedback

* nit: Don't move this around
2022-10-04 20:12:54 -03:00
gdkchan
2068445939 Fix shader SULD (bindless) instruction using wrong register as handle (#3732)
* GLSL: Do not generate scale helpers if we have no textures

* Fix shader SULD (bindless) instruction using wrong register as handle
2022-10-03 20:40:22 -03:00
gdkchan
a4fc9f8050 Support use of buffer ranges with size 0 (#3736) 2022-10-03 20:08:38 -03:00
gdkchan
5437d6cb13 Vulkan: Fix buffer texture storage not being updated on buffer handle reuse (#3731) 2022-10-03 19:45:33 -03:00
Emmanuel Hansen
7539e26144 Avalonia - Fixes updater (#3670)
* update avalonia

* fix updater

* fix spacing

* addressed review

* convert permission value to octal

* Add missing comma

* revert package updates
2022-10-03 11:25:25 -03:00
Luna
1c3697b6a4 Update AboutWindow.axaml (#3724) 2022-10-02 22:02:11 +00:00
gdkchan
81f848e54f Allow Surface Flinger frame enqueue after process has exited (#3733) 2022-10-02 21:50:03 +00:00
MutantAura
358a781639 Volume Hotkeys (#3500)
* Initial GTK implementation

* Less messy and Avalonia imp

* Move clamping to HLE and streamline imps

* Make viewmodel update consistent

* Fix rebase and add an english locale.

Co-authored-by: Mary-nyan <mary@mary.zone>
2022-10-02 09:38:37 +00:00
Wunk
45ce540b9b ARMeilleure: Add gfni acceleration (#3669)
* ARMeilleure: Add `GFNI` detection

This is intended for utilizing the `gf2p8affineqb` instruction

* ARMeilleure: Add `gf2p8affineqb`

Not using the VEX or EVEX-form of this instruction is intentional. There
are `GFNI`-chips that do not support AVX(so no VEX encoding) such as
Tremont(Lakefield) chips as well as Jasper Lake.

13df339fe7/GenuineIntel/GenuineIntel00806A1_Lakefield_LC_InstLatX64.txt (L1297-L1299)

13df339fe7/GenuineIntel/GenuineIntel00906C0_JasperLake_InstLatX64.txt (L1252-L1254)

* ARMeilleure: Add `gfni` acceleration of `Rbit_V`

Passes all `Rbit_V*` unit tests on my `i9-11900k`

* ARMeilleure: Add `gfni` acceleration of `S{l,r}i_V`

Also added a fast-path for when the shift amount is greater than the
size of the element.

* ARMeilleure: Add `gfni` acceleration of `Shl_V` and `Sshr_V`

* ARMeilleure: Increment InternalVersion

* ARMeilleure: Fix Intrinsic and Assembler Table alignment

`gf2p8affineqb` is the longest instruction name I know of. It shouldn't
get any wider than this.

* ARMeilleure: Remove SSE2+SHA requirement for GFNI

* ARMeilleure Add `X86GetGf2p8LogicalShiftLeft`

Used to generate GF(2^8) 8x8 bit-matrices for bit-shifting for the `gf2p8affineqb` instruction.

* ARMeilleure: Append `FeatureInfo7Ecx` to `FeatureInfo`
2022-10-02 11:17:19 +02:00
mageven
96bf7f8522 Avoid allocating unmanaged string per shader (#3730)
* Avoid reallocating same unmanaged string per shader

* Address PR feedback

* Rename to _disposed
2022-10-02 10:59:34 +02:00
50 changed files with 1105 additions and 757 deletions

View File

@@ -113,6 +113,7 @@ namespace ARMeilleure.CodeGen.X86
Add(X86Instruction.Divps, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f5e, InstructionFlags.Vex)); 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.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.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.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.Haddps, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f7c, InstructionFlags.Vex | InstructionFlags.PrefixF2));
Add(X86Instruction.Idiv, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x070000f7, InstructionFlags.None)); Add(X86Instruction.Idiv, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x070000f7, InstructionFlags.None));

View File

@@ -20,8 +20,9 @@ namespace ARMeilleure.CodeGen.X86
if (maxNum >= 7) if (maxNum >= 7)
{ {
(_, int ebx7, _, _) = X86Base.CpuId(0x00000007, 0x00000000); (_, int ebx7, int ecx7, _) = X86Base.CpuId(0x00000007, 0x00000000);
FeatureInfo7Ebx = (FeatureFlags7Ebx)ebx7; FeatureInfo7Ebx = (FeatureFlags7Ebx)ebx7;
FeatureInfo7Ecx = (FeatureFlags7Ecx)ecx7;
} }
} }
@@ -54,9 +55,16 @@ namespace ARMeilleure.CodeGen.X86
Sha = 1 << 29 Sha = 1 << 29
} }
[Flags]
public enum FeatureFlags7Ecx
{
Gfni = 1 << 8,
}
public static FeatureFlags1Edx FeatureInfo1Edx { get; } public static FeatureFlags1Edx FeatureInfo1Edx { get; }
public static FeatureFlags1Ecx FeatureInfo1Ecx { get; } public static FeatureFlags1Ecx FeatureInfo1Ecx { get; }
public static FeatureFlags7Ebx FeatureInfo7Ebx { get; } = 0; public static FeatureFlags7Ebx FeatureInfo7Ebx { get; } = 0;
public static FeatureFlags7Ecx FeatureInfo7Ecx { get; } = 0;
public static bool SupportsSse => FeatureInfo1Edx.HasFlag(FeatureFlags1Edx.Sse); public static bool SupportsSse => FeatureInfo1Edx.HasFlag(FeatureFlags1Edx.Sse);
public static bool SupportsSse2 => FeatureInfo1Edx.HasFlag(FeatureFlags1Edx.Sse2); 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 SupportsAvx2 => FeatureInfo7Ebx.HasFlag(FeatureFlags7Ebx.Avx2) && SupportsAvx;
public static bool SupportsF16c => FeatureInfo1Ecx.HasFlag(FeatureFlags1Ecx.F16c); public static bool SupportsF16c => FeatureInfo1Ecx.HasFlag(FeatureFlags1Ecx.F16c);
public static bool SupportsSha => FeatureInfo7Ebx.HasFlag(FeatureFlags7Ebx.Sha); public static bool SupportsSha => FeatureInfo7Ebx.HasFlag(FeatureFlags7Ebx.Sha);
public static bool SupportsGfni => FeatureInfo7Ecx.HasFlag(FeatureFlags7Ecx.Gfni);
public static bool ForceLegacySse { get; set; } public static bool ForceLegacySse { get; set; }

View File

@@ -58,6 +58,7 @@ namespace ARMeilleure.CodeGen.X86
Add(Intrinsic.X86Divps, new IntrinsicInfo(X86Instruction.Divps, IntrinsicType.Binary)); Add(Intrinsic.X86Divps, new IntrinsicInfo(X86Instruction.Divps, IntrinsicType.Binary));
Add(Intrinsic.X86Divsd, new IntrinsicInfo(X86Instruction.Divsd, IntrinsicType.Binary)); Add(Intrinsic.X86Divsd, new IntrinsicInfo(X86Instruction.Divsd, IntrinsicType.Binary));
Add(Intrinsic.X86Divss, new IntrinsicInfo(X86Instruction.Divss, 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.X86Haddpd, new IntrinsicInfo(X86Instruction.Haddpd, IntrinsicType.Binary));
Add(Intrinsic.X86Haddps, new IntrinsicInfo(X86Instruction.Haddps, IntrinsicType.Binary)); Add(Intrinsic.X86Haddps, new IntrinsicInfo(X86Instruction.Haddps, IntrinsicType.Binary));
Add(Intrinsic.X86Insertps, new IntrinsicInfo(X86Instruction.Insertps, IntrinsicType.TernaryImm)); Add(Intrinsic.X86Insertps, new IntrinsicInfo(X86Instruction.Insertps, IntrinsicType.TernaryImm));

View File

@@ -54,6 +54,7 @@ namespace ARMeilleure.CodeGen.X86
Divps, Divps,
Divsd, Divsd,
Divss, Divss,
Gf2p8affineqb,
Haddpd, Haddpd,
Haddps, Haddps,
Idiv, Idiv,

View File

@@ -243,6 +243,21 @@ namespace ARMeilleure.Instructions
throw new ArgumentException($"Invalid rounding mode \"{roundMode}\"."); 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.). public static Operand EmitCountSetBits8(ArmEmitterContext context, Operand op) // "size" is 8 (SIMD&FP Inst.).
{ {
Debug.Assert(op.Type == OperandType.I32 || op.Type == OperandType.I64); Debug.Assert(op.Type == OperandType.I32 || op.Type == OperandType.I64);

View File

@@ -336,8 +336,32 @@ namespace ARMeilleure.Instructions
{ {
OpCodeSimd op = (OpCodeSimd)context.CurrOp; 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; int elems = op.RegisterSize == RegisterSize.Simd128 ? 16 : 8;
for (int index = 0; index < elems; index++) for (int index = 0; index < elems; index++)
@@ -351,6 +375,7 @@ namespace ARMeilleure.Instructions
context.Copy(GetVec(op.Rd), res); context.Copy(GetVec(op.Rd), res);
} }
}
private static Operand EmitReverseBits8Op(ArmEmitterContext context, Operand op) private static Operand EmitReverseBits8Op(ArmEmitterContext context, Operand op)
{ {

View File

@@ -88,8 +88,35 @@ namespace ARMeilleure.Instructions
OpCodeSimdShImm op = (OpCodeSimdShImm)context.CurrOp; OpCodeSimdShImm op = (OpCodeSimdShImm)context.CurrOp;
int shift = GetImmShl(op); 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); Operand n = GetVec(op.Rn);
@@ -396,10 +423,40 @@ namespace ARMeilleure.Instructions
{ {
OpCodeSimdShImm op = (OpCodeSimdShImm)context.CurrOp; OpCodeSimdShImm op = (OpCodeSimdShImm)context.CurrOp;
if (Optimizations.UseSse2 && op.Size > 0 && op.Size < 3)
{
int shift = GetImmShr(op); 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); Operand n = GetVec(op.Rn);
Intrinsic sraInst = X86PsraInstruction[op.Size]; Intrinsic sraInst = X86PsraInstruction[op.Size];
@@ -929,10 +986,44 @@ namespace ARMeilleure.Instructions
OpCodeSimdShImm op = (OpCodeSimdShImm)context.CurrOp; OpCodeSimdShImm op = (OpCodeSimdShImm)context.CurrOp;
int shift = GetImmShl(op); int shift = GetImmShl(op);
int eSize = 8 << op.Size;
ulong mask = shift != 0 ? ulong.MaxValue >> (64 - shift) : 0UL; 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 d = GetVec(op.Rd);
Operand n = GetVec(op.Rn); Operand n = GetVec(op.Rn);
@@ -988,7 +1079,40 @@ namespace ARMeilleure.Instructions
ulong mask = (ulong.MaxValue << (eSize - shift)) & (ulong.MaxValue >> (64 - eSize)); 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 d = GetVec(op.Rd);
Operand n = GetVec(op.Rn); Operand n = GetVec(op.Rn);

View File

@@ -47,6 +47,7 @@ namespace ARMeilleure.IntermediateRepresentation
X86Divps, X86Divps,
X86Divsd, X86Divsd,
X86Divss, X86Divss,
X86Gf2p8affineqb,
X86Haddpd, X86Haddpd,
X86Haddps, X86Haddps,
X86Insertps, X86Insertps,

View File

@@ -22,6 +22,7 @@ namespace ARMeilleure
public static bool UseAesniIfAvailable { get; set; } = true; public static bool UseAesniIfAvailable { get; set; } = true;
public static bool UsePclmulqdqIfAvailable { get; set; } = true; public static bool UsePclmulqdqIfAvailable { get; set; } = true;
public static bool UseShaIfAvailable { get; set; } = true; public static bool UseShaIfAvailable { get; set; } = true;
public static bool UseGfniIfAvailable { get; set; } = true;
public static bool ForceLegacySse public static bool ForceLegacySse
{ {
@@ -42,5 +43,6 @@ namespace ARMeilleure
internal static bool UseAesni => UseAesniIfAvailable && HardwareCapabilities.SupportsAesni; internal static bool UseAesni => UseAesniIfAvailable && HardwareCapabilities.SupportsAesni;
internal static bool UsePclmulqdq => UsePclmulqdqIfAvailable && HardwareCapabilities.SupportsPclmulqdq; internal static bool UsePclmulqdq => UsePclmulqdqIfAvailable && HardwareCapabilities.SupportsPclmulqdq;
internal static bool UseSha => UseShaIfAvailable && HardwareCapabilities.SupportsSha; internal static bool UseSha => UseShaIfAvailable && HardwareCapabilities.SupportsSha;
internal static bool UseGfni => UseGfniIfAvailable && HardwareCapabilities.SupportsGfni;
} }
} }

View File

@@ -27,7 +27,7 @@ namespace ARMeilleure.Translation.PTC
private const string OuterHeaderMagicString = "PTCohd\0\0"; private const string OuterHeaderMagicString = "PTCohd\0\0";
private const string InnerHeaderMagicString = "PTCihd\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 ActualDir = "0";
private const string BackupDir = "1"; private const string BackupDir = "1";
@@ -951,7 +951,8 @@ namespace ARMeilleure.Translation.PTC
return new FeatureInfo( return new FeatureInfo(
(uint)HardwareCapabilities.FeatureInfo1Ecx, (uint)HardwareCapabilities.FeatureInfo1Ecx,
(uint)HardwareCapabilities.FeatureInfo1Edx, (uint)HardwareCapabilities.FeatureInfo1Edx,
(uint)HardwareCapabilities.FeatureInfo7Ebx); (uint)HardwareCapabilities.FeatureInfo7Ebx,
(uint)HardwareCapabilities.FeatureInfo7Ecx);
} }
private static byte GetMemoryManagerMode() private static byte GetMemoryManagerMode()
@@ -971,7 +972,7 @@ namespace ARMeilleure.Translation.PTC
return osPlatform; return osPlatform;
} }
[StructLayout(LayoutKind.Sequential, Pack = 1/*, Size = 54*/)] [StructLayout(LayoutKind.Sequential, Pack = 1/*, Size = 58*/)]
private struct OuterHeader private struct OuterHeader
{ {
public ulong Magic; public ulong Magic;
@@ -1002,8 +1003,8 @@ namespace ARMeilleure.Translation.PTC
} }
} }
[StructLayout(LayoutKind.Sequential, Pack = 1/*, Size = 12*/)] [StructLayout(LayoutKind.Sequential, Pack = 1/*, Size = 16*/)]
private record struct FeatureInfo(uint FeatureInfo0, uint FeatureInfo1, uint FeatureInfo2); private record struct FeatureInfo(uint FeatureInfo0, uint FeatureInfo1, uint FeatureInfo2, uint FeatureInfo3);
[StructLayout(LayoutKind.Sequential, Pack = 1/*, Size = 128*/)] [StructLayout(LayoutKind.Sequential, Pack = 1/*, Size = 128*/)]
private struct InnerHeader private struct InnerHeader

View File

@@ -58,6 +58,8 @@ namespace Ryujinx.Ava
private const float MaxResolutionScale = 4.0f; // Max resolution hotkeys can scale to before wrapping. private const float MaxResolutionScale = 4.0f; // Max resolution hotkeys can scale to before wrapping.
private const int TargetFps = 60; private const int TargetFps = 60;
private const float VolumeDelta = 0.05f;
private static readonly Cursor InvisibleCursor = new Cursor(StandardCursorType.None); private static readonly Cursor InvisibleCursor = new Cursor(StandardCursorType.None);
private readonly long _ticksPerFrame; private readonly long _ticksPerFrame;
@@ -73,6 +75,7 @@ namespace Ryujinx.Ava
private bool _isStopped; private bool _isStopped;
private bool _isActive; private bool _isActive;
private long _lastCursorMoveTime; private long _lastCursorMoveTime;
private float _newVolume;
private long _ticks = 0; private long _ticks = 0;
private KeyboardHotkeyState _prevHotkeyState; private KeyboardHotkeyState _prevHotkeyState;
@@ -1003,6 +1006,18 @@ namespace Ryujinx.Ava
GraphicsConfig.ResScale = GraphicsConfig.ResScale =
(MaxResolutionScale + GraphicsConfig.ResScale - 2) % MaxResolutionScale + 1; (MaxResolutionScale + GraphicsConfig.ResScale - 2) % MaxResolutionScale + 1;
break; 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: case KeyboardHotkeyState.None:
(_keyboardInterface as AvaloniaKeyboard).Clear(); (_keyboardInterface as AvaloniaKeyboard).Clear();
break; break;
@@ -1068,6 +1083,14 @@ namespace Ryujinx.Ava
{ {
state = KeyboardHotkeyState.ResScaleDown; 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; return state;
} }

View File

@@ -579,7 +579,7 @@
"SettingsTabHotkeysResScaleUpHotkey": "Increase resolution:", "SettingsTabHotkeysResScaleUpHotkey": "Increase resolution:",
"SettingsTabHotkeysResScaleDownHotkey": "Decrease resolution:", "SettingsTabHotkeysResScaleDownHotkey": "Decrease resolution:",
"UserProfilesName": "Name:", "UserProfilesName": "Name:",
"UserProfilesUserId" : "User Id:", "UserProfilesUserId": "User Id:",
"SettingsTabGraphicsBackend": "Graphics Backend", "SettingsTabGraphicsBackend": "Graphics Backend",
"SettingsTabGraphicsBackendTooltip": "Graphics Backend to use", "SettingsTabGraphicsBackendTooltip": "Graphics Backend to use",
"SettingsEnableTextureRecompression": "Enable Texture Recompression", "SettingsEnableTextureRecompression": "Enable Texture Recompression",
@@ -589,5 +589,8 @@
"SettingsAppRequiredRestartMessage": "Ryujinx Restart Required", "SettingsAppRequiredRestartMessage": "Ryujinx Restart Required",
"SettingsGpuBackendRestartMessage": "Graphics Backend or Gpu settings have been modified. This will require a restart to be applied", "SettingsGpuBackendRestartMessage": "Graphics Backend or Gpu settings have been modified. This will require a restart to be applied",
"SettingsGpuBackendRestartSubMessage": "Do you want to restart now?", "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" "VolumeShort": "Vol"
} }

View File

@@ -9,6 +9,8 @@
Pause, Pause,
ToggleMute, ToggleMute,
ResScaleUp, ResScaleUp,
ResScaleDown ResScaleDown,
VolumeUp,
VolumeDown
} }
} }

View File

@@ -1,4 +1,6 @@
using Avalonia.Controls;
using Avalonia.Threading; using Avalonia.Threading;
using FluentAvalonia.UI.Controls;
using ICSharpCode.SharpZipLib.GZip; using ICSharpCode.SharpZipLib.GZip;
using ICSharpCode.SharpZipLib.Tar; using ICSharpCode.SharpZipLib.Tar;
using ICSharpCode.SharpZipLib.Zip; using ICSharpCode.SharpZipLib.Zip;
@@ -11,11 +13,13 @@ using Ryujinx.Common;
using Ryujinx.Common.Logging; using Ryujinx.Common.Logging;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Net; using System.Net;
using System.Net.Http; using System.Net.Http;
using System.Net.NetworkInformation; using System.Net.NetworkInformation;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Text; using System.Text;
using System.Threading; using System.Threading;
@@ -40,6 +44,8 @@ namespace Ryujinx.Modules
private static readonly string[] WindowsDependencyDirs = Array.Empty<string>(); private static readonly string[] WindowsDependencyDirs = Array.Empty<string>();
public static bool UpdateSuccessful { get; private set; }
public static async Task BeginParse(MainWindow mainWindow, bool showVersionUpToDate) public static async Task BeginParse(MainWindow mainWindow, bool showVersionUpToDate)
{ {
if (Running) if (Running)
@@ -198,11 +204,18 @@ namespace Ryujinx.Modules
_buildSize = -1; _buildSize = -1;
} }
} }
Dispatcher.UIThread.Post(async () => Dispatcher.UIThread.Post(async () =>
{ {
// Show a message asking the user if they want to update // Show a message asking the user if they want to update
UpdaterWindow updateDialog = new(mainWindow, newVersion, _buildUrl); var shouldUpdate = await ContentDialogHelper.CreateChoiceDialog(LocaleManager.Instance["RyujinxUpdater"],
await updateDialog.ShowDialog(mainWindow); LocaleManager.Instance["RyujinxUpdaterMessage"],
$"{Program.Version} -> {newVersion}");
if (shouldUpdate)
{
UpdateRyujinx(mainWindow, _buildUrl);
}
}); });
} }
@@ -216,8 +229,10 @@ namespace Ryujinx.Modules
return result; 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 // Empty update dir, although it shouldn't ever have anything inside it
if (Directory.Exists(UpdateDir)) if (Directory.Exists(UpdateDir))
{ {
@@ -228,25 +243,56 @@ namespace Ryujinx.Modules
string updateFile = Path.Combine(UpdateDir, "update.bin"); string updateFile = Path.Combine(UpdateDir, "update.bin");
// Download the update .zip var taskDialog = new TaskDialog()
updateDialog.MainText.Text = LocaleManager.Instance["UpdaterDownloading"]; {
updateDialog.ProgressBar.Value = 0; Header = LocaleManager.Instance["RyujinxUpdater"],
updateDialog.ProgressBar.Maximum = 100; 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) if (_buildSize >= 0)
{ {
DoUpdateWithMultipleThreads(updateDialog, downloadUrl, updateFile); DoUpdateWithMultipleThreads(taskDialog, downloadUrl, updateFile);
} }
else 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 // Multi-Threaded Updater
long chunkSize = _buildSize / ConnectionCount; long chunkSize = _buildSize / ConnectionCount;
@@ -290,7 +336,7 @@ namespace Ryujinx.Modules
Interlocked.Exchange(ref progressPercentage[index], args.ProgressPercentage); Interlocked.Exchange(ref progressPercentage[index], args.ProgressPercentage);
Interlocked.Add(ref totalProgressPercentage, args.ProgressPercentage); Interlocked.Add(ref totalProgressPercentage, args.ProgressPercentage);
updateDialog.ProgressBar.Value = totalProgressPercentage / ConnectionCount; taskDialog.SetProgressBarState(totalProgressPercentage / ConnectionCount, TaskDialogProgressState.Normal);
}; };
client.DownloadDataCompleted += (_, args) => client.DownloadDataCompleted += (_, args) =>
@@ -301,6 +347,8 @@ namespace Ryujinx.Modules
{ {
webClients[index].Dispose(); webClients[index].Dispose();
taskDialog.Hide();
return; return;
} }
@@ -320,14 +368,14 @@ namespace Ryujinx.Modules
try try
{ {
InstallUpdate(updateDialog, updateFile); InstallUpdate(taskDialog, updateFile);
} }
catch (Exception e) catch (Exception e)
{ {
Logger.Warning?.Print(LogClass.Application, e.Message); Logger.Warning?.Print(LogClass.Application, e.Message);
Logger.Warning?.Print(LogClass.Application, "Multi-Threaded update failed, falling back to single-threaded updater."); Logger.Warning?.Print(LogClass.Application, "Multi-Threaded update failed, falling back to single-threaded updater.");
DoUpdateWithSingleThread(updateDialog, downloadUrl, updateFile); DoUpdateWithSingleThread(taskDialog, downloadUrl, updateFile);
return; return;
} }
@@ -348,7 +396,7 @@ namespace Ryujinx.Modules
webClients[j].CancelAsync(); webClients[j].CancelAsync();
} }
DoUpdateWithSingleThread(updateDialog, downloadUrl, updateFile); DoUpdateWithSingleThread(taskDialog, downloadUrl, updateFile);
return; 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()) using (HttpClient client = new HttpClient())
{ {
@@ -384,19 +432,26 @@ namespace Ryujinx.Modules
byteWritten += readSize; byteWritten += readSize;
updateDialog.ProgressBar.Value = ((double)byteWritten / totalBytes) * 100; taskDialog.SetProgressBarState(GetPercentage(byteWritten, totalBytes), TaskDialogProgressState.Normal);
updateFileStream.Write(buffer, 0, readSize); 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.Name = "Updater.SingleThreadWorker";
worker.Start(); 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 // Extract Update
updateDialog.MainText.Text = LocaleManager.Instance["UpdaterExtracting"]; taskDialog.SubHeader = LocaleManager.Instance["UpdaterExtracting"];
updateDialog.ProgressBar.Value = 0; taskDialog.SetProgressBarState(0, TaskDialogProgressState.Normal);
if (OperatingSystem.IsLinux()) if (OperatingSystem.IsLinux())
{ {
@@ -426,8 +481,6 @@ namespace Ryujinx.Modules
using (Stream gzipStream = new GZipInputStream(inStream)) using (Stream gzipStream = new GZipInputStream(inStream))
using (TarInputStream tarStream = new TarInputStream(gzipStream, Encoding.ASCII)) using (TarInputStream tarStream = new TarInputStream(gzipStream, Encoding.ASCII))
{ {
updateDialog.ProgressBar.Maximum = inStream.Length;
await Task.Run(() => await Task.Run(() =>
{ {
TarEntry tarEntry; TarEntry tarEntry;
@@ -450,12 +503,12 @@ namespace Ryujinx.Modules
Dispatcher.UIThread.Post(() => 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 else
@@ -463,12 +516,12 @@ namespace Ryujinx.Modules
using (Stream inStream = File.OpenRead(updateFile)) using (Stream inStream = File.OpenRead(updateFile))
using (ZipFile zipFile = new ZipFile(inStream)) using (ZipFile zipFile = new ZipFile(inStream))
{ {
updateDialog.ProgressBar.Maximum = zipFile.Count;
await Task.Run(() => await Task.Run(() =>
{ {
double count = 0;
foreach (ZipEntry zipEntry in zipFile) foreach (ZipEntry zipEntry in zipFile)
{ {
count++;
if (zipEntry.IsDirectory) continue; if (zipEntry.IsDirectory) continue;
string outPath = Path.Combine(UpdateDir, zipEntry.Name); string outPath = Path.Combine(UpdateDir, zipEntry.Name);
@@ -485,7 +538,7 @@ namespace Ryujinx.Modules
Dispatcher.UIThread.Post(() => 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(); List<string> allFiles = EnumerateFilesToDelete().ToList();
updateDialog.MainText.Text = LocaleManager.Instance["UpdaterRenaming"]; taskDialog.SubHeader = LocaleManager.Instance["UpdaterRenaming"];
updateDialog.ProgressBar.Value = 0; taskDialog.SetProgressBarState(0, TaskDialogProgressState.Normal);
updateDialog.ProgressBar.Maximum = allFiles.Count;
// Replace old files // Replace old files
await Task.Run(() => await Task.Run(() =>
{ {
double count = 0;
foreach (string file in allFiles) foreach (string file in allFiles)
{ {
count++;
try try
{ {
File.Move(file, file + ".ryuold"); File.Move(file, file + ".ryuold");
Dispatcher.UIThread.Post(() => Dispatcher.UIThread.Post(() =>
{ {
updateDialog.ProgressBar.Value++; taskDialog.SetProgressBarState(GetPercentage(count, allFiles.Count), TaskDialogProgressState.Normal);
}); });
} }
catch catch
@@ -523,23 +577,20 @@ namespace Ryujinx.Modules
Dispatcher.UIThread.Post(() => Dispatcher.UIThread.Post(() =>
{ {
updateDialog.MainText.Text = LocaleManager.Instance["UpdaterAddingFiles"]; taskDialog.SubHeader = LocaleManager.Instance["UpdaterAddingFiles"];
updateDialog.ProgressBar.Value = 0; taskDialog.SetProgressBarState(0, TaskDialogProgressState.Normal);
updateDialog.ProgressBar.Maximum = Directory.GetFiles(UpdatePublishDir, "*", SearchOption.AllDirectories).Length;
}); });
MoveAllFilesOver(UpdatePublishDir, HomeDir, updateDialog); MoveAllFilesOver(UpdatePublishDir, HomeDir, taskDialog);
}); });
Directory.Delete(UpdateDir, true); Directory.Delete(UpdateDir, true);
SetUnixPermissions(); SetUnixPermissions();
updateDialog.MainText.Text = LocaleManager.Instance["DialogUpdaterCompleteMessage"]; UpdateSuccessful = true;
updateDialog.SecondaryText.Text = LocaleManager.Instance["DialogUpdaterRestartMessage"];
updateDialog.ProgressBar.IsVisible = false; taskDialog.Hide();
updateDialog.ButtonBox.IsVisible = true;
} }
#pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed #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; 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)) foreach (string directory in Directory.GetDirectories(root))
{ {
string dirName = Path.GetFileName(directory); string dirName = Path.GetFileName(directory);
@@ -629,16 +681,18 @@ namespace Ryujinx.Modules
Directory.CreateDirectory(Path.Combine(dest, dirName)); 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)) foreach (string file in Directory.GetFiles(root))
{ {
count++;
File.Move(file, Path.Combine(dest, Path.GetFileName(file)), true); File.Move(file, Path.Combine(dest, Path.GetFileName(file)), true);
Dispatcher.UIThread.InvokeAsync(() => Dispatcher.UIThread.InvokeAsync(() =>
{ {
dialog.ProgressBar.Value++; taskDialog.SetProgressBarState(GetPercentage(count, total), TaskDialogProgressState.Normal);
}); });
} }
} }

View File

@@ -6,7 +6,6 @@
xmlns:locale="clr-namespace:Ryujinx.Ava.Common.Locale" xmlns:locale="clr-namespace:Ryujinx.Ava.Common.Locale"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:window="clr-namespace:Ryujinx.Ava.Ui.Windows" xmlns:window="clr-namespace:Ryujinx.Ava.Ui.Windows"
Title="Ryujinx - About"
Width="850" Width="850"
Height="550" Height="550"
MinWidth="500" MinWidth="500"

View File

@@ -257,6 +257,22 @@
TextAlignment="Center" /> TextAlignment="Center" />
</ToggleButton> </ToggleButton>
</StackPanel> </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> </StackPanel>
</Border> </Border>
</ScrollViewer> </ScrollViewer>

View File

@@ -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>

View File

@@ -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();
}
}
}

View File

@@ -9,5 +9,7 @@
public Key ToggleMute { get; set; } public Key ToggleMute { get; set; }
public Key ResScaleUp { get; set; } public Key ResScaleUp { get; set; }
public Key ResScaleDown { get; set; } public Key ResScaleDown { get; set; }
public Key VolumeUp { get; set; }
public Key VolumeDown { get; set; }
} }
} }

View File

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

View File

@@ -123,7 +123,8 @@ namespace Ryujinx.Graphics.Gpu
/// <param name="releaseCallback">Texture release callback</param> /// <param name="releaseCallback">Texture release callback</param>
/// <param name="userObj">User defined object passed to the 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> /// <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 pid,
ulong address, ulong address,
int width, int width,
@@ -140,7 +141,7 @@ namespace Ryujinx.Graphics.Gpu
{ {
if (!_context.PhysicalMemoryRegistry.TryGetValue(pid, out var physicalMemory)) 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); FormatInfo formatInfo = new FormatInfo(format, 1, 1, bytesPerPixel, 4);
@@ -184,6 +185,8 @@ namespace Ryujinx.Graphics.Gpu
acquireCallback, acquireCallback,
releaseCallback, releaseCallback,
userObj)); userObj));
return true;
} }
/// <summary> /// <summary>

View File

@@ -257,7 +257,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
DeclareSupportUniformBlock(context, context.Config.Stage, scaleElements); 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"); AppendHelperFunction(context, $"Ryujinx.Graphics.Shader/CodeGen/Glsl/HelperFunctions/TexelFetchScale_{stage}.glsl");
context.AppendLine(); context.AppendLine();

View File

@@ -279,16 +279,16 @@ namespace Ryujinx.Graphics.Shader.Decoders
Add("1110101110xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.SuatomB2, InstEmit.SuatomB2, InstProps.Rd | InstProps.Ra | InstProps.Rb | InstProps.Rc); 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("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("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("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("1110101100000xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", 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("1110101100001xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", 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("1110101101010xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.SuredB, InstEmit.SuredB, InstProps.Rd | InstProps.Ra | InstProps.Rc);
Add("1110101101011xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Sured, InstEmit.Sured, InstProps.Rd | InstProps.Ra); 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("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("1110101100100xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", 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("1110101100101xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Sust, InstEmit.Sust, InstProps.Rd | InstProps.Ra | InstProps.Tex);
Add("1111000011111xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Sync, InstEmit.Sync, InstProps.Bra); 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("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); Add("1101111010xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.TexB, InstEmit.TexB, InstProps.Rd | InstProps.Ra | InstProps.Rb | InstProps.TPd | InstProps.TexB);

View File

@@ -123,7 +123,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
{ {
InstSuldB op = context.GetOp<InstSuldB>(); 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) public static void Suld(EmitterContext context)

View File

@@ -109,12 +109,34 @@ namespace Ryujinx.Graphics.Vulkan
{ {
if (isWrite) if (isWrite)
{ {
_cachedConvertedBuffers.Clear(); SignalWrite(0, Size);
} }
return _buffer; return _buffer;
} }
public Auto<DisposableBuffer> GetBuffer(CommandBuffer commandBuffer, int offset, int size, bool isWrite = false)
{
if (isWrite)
{
SignalWrite(offset, size);
}
return _buffer;
}
public void SignalWrite(int offset, int size)
{
if (offset == 0 && size == Size)
{
_cachedConvertedBuffers.Clear();
}
else
{
_cachedConvertedBuffers.ClearRange(offset, size);
}
}
public BufferHandle GetHandle() public BufferHandle GetHandle()
{ {
var handle = _bufferHandle; var handle = _bufferHandle;
@@ -183,6 +205,8 @@ namespace Ryujinx.Graphics.Vulkan
data.Slice(0, dataSize).CopyTo(new Span<byte>((void*)(_map + offset), dataSize)); data.Slice(0, dataSize).CopyTo(new Span<byte>((void*)(_map + offset), dataSize));
SignalWrite(offset, dataSize);
return; return;
} }
} }
@@ -240,7 +264,7 @@ namespace Ryujinx.Graphics.Vulkan
endRenderPass?.Invoke(); endRenderPass?.Invoke();
var dstBuffer = GetBuffer(cbs.CommandBuffer, true).Get(cbs, dstOffset, data.Length).Value; var dstBuffer = GetBuffer(cbs.CommandBuffer, dstOffset, data.Length, true).Get(cbs, dstOffset, data.Length).Value;
InsertBufferBarrier( InsertBufferBarrier(
_gd, _gd,
@@ -364,7 +388,7 @@ namespace Ryujinx.Graphics.Vulkan
public Auto<DisposableBuffer> GetBufferI8ToI16(CommandBufferScoped cbs, int offset, int size) public Auto<DisposableBuffer> GetBufferI8ToI16(CommandBufferScoped cbs, int offset, int size)
{ {
var key = new I8ToI16CacheKey(); var key = new I8ToI16CacheKey(_gd);
if (!_cachedConvertedBuffers.TryGetValue(offset, size, key, out var holder)) if (!_cachedConvertedBuffers.TryGetValue(offset, size, key, out var holder))
{ {
@@ -373,6 +397,8 @@ namespace Ryujinx.Graphics.Vulkan
_gd.PipelineInternal.EndRenderPass(); _gd.PipelineInternal.EndRenderPass();
_gd.HelperShader.ConvertI8ToI16(_gd, cbs, this, holder, offset, size); _gd.HelperShader.ConvertI8ToI16(_gd, cbs, this, holder, offset, size);
key.SetBuffer(holder.GetBuffer());
_cachedConvertedBuffers.Add(offset, size, key, holder); _cachedConvertedBuffers.Add(offset, size, key, holder);
} }
@@ -417,6 +443,8 @@ namespace Ryujinx.Graphics.Vulkan
_gd.PipelineInternal.EndRenderPass(); _gd.PipelineInternal.EndRenderPass();
_gd.HelperShader.ConvertIndexBuffer(_gd, cbs, this, holder, pattern, indexSize, offset, indexCount); _gd.HelperShader.ConvertIndexBuffer(_gd, cbs, this, holder, pattern, indexSize, offset, indexCount);
key.SetBuffer(holder.GetBuffer());
_cachedConvertedBuffers.Add(offset, size, key, holder); _cachedConvertedBuffers.Add(offset, size, key, holder);
} }

View File

@@ -38,6 +38,8 @@ namespace Ryujinx.Graphics.Vulkan
private readonly IdList<BufferHolder> _buffers; private readonly IdList<BufferHolder> _buffers;
public int BufferCount { get; private set; }
public StagingBuffer StagingBuffer { get; } public StagingBuffer StagingBuffer { get; }
public BufferManager(VulkanRenderer gd, PhysicalDevice physicalDevice, Device device) public BufferManager(VulkanRenderer gd, PhysicalDevice physicalDevice, Device device)
@@ -56,6 +58,8 @@ namespace Ryujinx.Graphics.Vulkan
return BufferHandle.Null; return BufferHandle.Null;
} }
BufferCount++;
ulong handle64 = (uint)_buffers.Add(holder); ulong handle64 = (uint)_buffers.Add(holder);
return Unsafe.As<ulong, BufferHandle>(ref handle64); return Unsafe.As<ulong, BufferHandle>(ref handle64);
@@ -120,6 +124,16 @@ namespace Ryujinx.Graphics.Vulkan
return null; return null;
} }
public Auto<DisposableBuffer> GetBuffer(CommandBuffer commandBuffer, BufferHandle handle, int offset, int size, bool isWrite)
{
if (TryGetBuffer(handle, out var holder))
{
return holder.GetBuffer(commandBuffer, offset, size, isWrite);
}
return null;
}
public Auto<DisposableBuffer> GetBufferI8ToI16(CommandBufferScoped cbs, BufferHandle handle, int offset, int size) public Auto<DisposableBuffer> GetBufferI8ToI16(CommandBufferScoped cbs, BufferHandle handle, int offset, int size)
{ {
if (TryGetBuffer(handle, out var holder)) if (TryGetBuffer(handle, out var holder))

View File

@@ -24,6 +24,11 @@
public void Add(int cbIndex, int offset, int size) 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. // Some usages can be out of bounds (vertex buffer on amd), so bound if necessary.
if (offset + size > _size) if (offset + size > _size)
{ {
@@ -39,6 +44,11 @@
public bool OverlapsWith(int cbIndex, int offset, int size) public bool OverlapsWith(int cbIndex, int offset, int size)
{ {
if (size == 0)
{
return false;
}
int cbBase = cbIndex * _bitsPerCb; int cbBase = cbIndex * _bitsPerCb;
int start = cbBase + offset / _granularity; int start = cbBase + offset / _granularity;
int end = cbBase + (offset + size - 1) / _granularity; int end = cbBase + (offset + size - 1) / _granularity;

View File

@@ -25,6 +25,11 @@ namespace Ryujinx.Graphics.Vulkan
return other is I8ToI16CacheKey; return other is I8ToI16CacheKey;
} }
public void SetBuffer(Auto<DisposableBuffer> buffer)
{
_buffer = buffer;
}
public void Dispose() public void Dispose()
{ {
_gd.PipelineInternal.DirtyIndexBuffer(_buffer); _gd.PipelineInternal.DirtyIndexBuffer(_buffer);
@@ -160,6 +165,44 @@ namespace Ryujinx.Graphics.Vulkan
} }
} }
public void ClearRange(int offset, int size)
{
if (_ranges != null && _ranges.Count > 0)
{
int end = offset + size;
List<ulong> toRemove = null;
foreach (KeyValuePair<ulong, List<Entry>> range in _ranges)
{
(int rOffset, int rSize) = UnpackRange(range.Key);
int rEnd = rOffset + rSize;
if (rEnd > offset && rOffset < end)
{
List<Entry> entries = range.Value;
foreach (Entry entry in entries)
{
entry.Key.Dispose();
entry.Value.Dispose();
}
(toRemove ??= new List<ulong>()).Add(range.Key);
}
}
if (toRemove != null)
{
foreach (ulong range in toRemove)
{
_ranges.Remove(range);
}
}
}
}
private List<Entry> GetEntries(int offset, int size) private List<Entry> GetEntries(int offset, int size)
{ {
if (_ranges == null) if (_ranges == null)
@@ -184,6 +227,11 @@ namespace Ryujinx.Graphics.Vulkan
return (uint)offset | ((ulong)size << 32); return (uint)offset | ((ulong)size << 32);
} }
private static (int offset, int size) UnpackRange(ulong range)
{
return ((int)range, (int)(range >> 32));
}
public void Dispose() public void Dispose()
{ {
Clear(); Clear();

View File

@@ -21,7 +21,7 @@ namespace Ryujinx.Graphics.Vulkan
protected readonly AutoFlushCounter AutoFlush; protected readonly AutoFlushCounter AutoFlush;
private PipelineDynamicState _dynamicState; protected PipelineDynamicState DynamicState;
private PipelineState _newState; private PipelineState _newState;
private bool _stateDirty; private bool _stateDirty;
private GAL.PrimitiveTopology _topology; private GAL.PrimitiveTopology _topology;
@@ -150,7 +150,7 @@ namespace Ryujinx.Graphics.Vulkan
{ {
EndRenderPass(); EndRenderPass();
var dst = Gd.BufferManager.GetBuffer(CommandBuffer, destination, true).Get(Cbs, offset, size).Value; var dst = Gd.BufferManager.GetBuffer(CommandBuffer, destination, offset, size, true).Get(Cbs, offset, size).Value;
BufferHolder.InsertBufferBarrier( BufferHolder.InsertBufferBarrier(
Gd, Gd,
@@ -238,8 +238,8 @@ namespace Ryujinx.Graphics.Vulkan
{ {
EndRenderPass(); EndRenderPass();
var src = Gd.BufferManager.GetBuffer(CommandBuffer, source, false); var src = Gd.BufferManager.GetBuffer(CommandBuffer, source, srcOffset, size, false);
var dst = Gd.BufferManager.GetBuffer(CommandBuffer, destination, true); var dst = Gd.BufferManager.GetBuffer(CommandBuffer, destination, dstOffset, size, true);
BufferHolder.Copy(Gd, Cbs, src, dst, srcOffset, dstOffset, size); BufferHolder.Copy(Gd, Cbs, src, dst, srcOffset, dstOffset, size);
} }
@@ -388,7 +388,7 @@ namespace Ryujinx.Graphics.Vulkan
var oldDepthTestEnable = _newState.DepthTestEnable; var oldDepthTestEnable = _newState.DepthTestEnable;
var oldDepthWriteEnable = _newState.DepthWriteEnable; var oldDepthWriteEnable = _newState.DepthWriteEnable;
var oldTopology = _newState.Topology; var oldTopology = _newState.Topology;
var oldViewports = _dynamicState.Viewports; var oldViewports = DynamicState.Viewports;
var oldViewportsCount = _newState.ViewportsCount; var oldViewportsCount = _newState.ViewportsCount;
_newState.CullMode = CullModeFlags.CullModeNone; _newState.CullMode = CullModeFlags.CullModeNone;
@@ -411,9 +411,9 @@ namespace Ryujinx.Graphics.Vulkan
_newState.DepthWriteEnable = oldDepthWriteEnable; _newState.DepthWriteEnable = oldDepthWriteEnable;
_newState.Topology = oldTopology; _newState.Topology = oldTopology;
_dynamicState.Viewports = oldViewports; DynamicState.Viewports = oldViewports;
_dynamicState.ViewportsCount = (int)oldViewportsCount; DynamicState.ViewportsCount = (int)oldViewportsCount;
_dynamicState.SetViewportsDirty(); DynamicState.SetViewportsDirty();
_newState.ViewportsCount = oldViewportsCount; _newState.ViewportsCount = oldViewportsCount;
SignalStateChange(); SignalStateChange();
@@ -448,8 +448,13 @@ namespace Ryujinx.Graphics.Vulkan
ResumeTransformFeedbackInternal(); ResumeTransformFeedbackInternal();
DrawCount++; DrawCount++;
var buffer = Gd.BufferManager.GetBuffer(CommandBuffer, indirectBuffer.Handle, true).Get(Cbs, indirectBuffer.Offset, indirectBuffer.Size).Value; var buffer = Gd.BufferManager
var countBuffer = Gd.BufferManager.GetBuffer(CommandBuffer, parameterBuffer.Handle, true).Get(Cbs, parameterBuffer.Offset, parameterBuffer.Size).Value; .GetBuffer(CommandBuffer, indirectBuffer.Handle, indirectBuffer.Offset, indirectBuffer.Size, true)
.Get(Cbs, indirectBuffer.Offset, indirectBuffer.Size).Value;
var countBuffer = Gd.BufferManager
.GetBuffer(CommandBuffer, parameterBuffer.Handle, parameterBuffer.Offset, parameterBuffer.Size, true)
.Get(Cbs, parameterBuffer.Offset, parameterBuffer.Size).Value;
Gd.DrawIndirectCountApi.CmdDrawIndirectCount( Gd.DrawIndirectCountApi.CmdDrawIndirectCount(
CommandBuffer, CommandBuffer,
@@ -478,8 +483,13 @@ namespace Ryujinx.Graphics.Vulkan
ResumeTransformFeedbackInternal(); ResumeTransformFeedbackInternal();
DrawCount++; DrawCount++;
var buffer = Gd.BufferManager.GetBuffer(CommandBuffer, indirectBuffer.Handle, true).Get(Cbs, indirectBuffer.Offset, indirectBuffer.Size).Value; var buffer = Gd.BufferManager
var countBuffer = Gd.BufferManager.GetBuffer(CommandBuffer, parameterBuffer.Handle, true).Get(Cbs, parameterBuffer.Offset, parameterBuffer.Size).Value; .GetBuffer(CommandBuffer, indirectBuffer.Handle, parameterBuffer.Offset, parameterBuffer.Size, true)
.Get(Cbs, indirectBuffer.Offset, indirectBuffer.Size).Value;
var countBuffer = Gd.BufferManager
.GetBuffer(CommandBuffer, parameterBuffer.Handle, parameterBuffer.Offset, parameterBuffer.Size, true)
.Get(Cbs, parameterBuffer.Offset, parameterBuffer.Size).Value;
Gd.DrawIndirectCountApi.CmdDrawIndexedIndirectCount( Gd.DrawIndirectCountApi.CmdDrawIndexedIndirectCount(
CommandBuffer, CommandBuffer,
@@ -535,7 +545,7 @@ namespace Ryujinx.Graphics.Vulkan
public void SetDepthBias(PolygonModeMask enables, float factor, float units, float clamp) public void SetDepthBias(PolygonModeMask enables, float factor, float units, float clamp)
{ {
_dynamicState.SetDepthBias(factor, units, clamp); DynamicState.SetDepthBias(factor, units, clamp);
_newState.DepthBiasEnable = enables != 0; _newState.DepthBiasEnable = enables != 0;
SignalStateChange(); SignalStateChange();
@@ -753,10 +763,10 @@ namespace Ryujinx.Graphics.Vulkan
var offset = new Offset2D(region.X, region.Y); var offset = new Offset2D(region.X, region.Y);
var extent = new Extent2D((uint)region.Width, (uint)region.Height); var extent = new Extent2D((uint)region.Width, (uint)region.Height);
_dynamicState.SetScissor(i, new Rect2D(offset, extent)); DynamicState.SetScissor(i, new Rect2D(offset, extent));
} }
_dynamicState.ScissorsCount = count; DynamicState.ScissorsCount = count;
_newState.ScissorsCount = (uint)count; _newState.ScissorsCount = (uint)count;
SignalStateChange(); SignalStateChange();
@@ -764,7 +774,7 @@ namespace Ryujinx.Graphics.Vulkan
public void SetStencilTest(StencilTestDescriptor stencilTest) public void SetStencilTest(StencilTestDescriptor stencilTest)
{ {
_dynamicState.SetStencilMasks( DynamicState.SetStencilMasks(
(uint)stencilTest.BackFuncMask, (uint)stencilTest.BackFuncMask,
(uint)stencilTest.BackMask, (uint)stencilTest.BackMask,
(uint)stencilTest.BackFuncRef, (uint)stencilTest.BackFuncRef,
@@ -813,7 +823,8 @@ namespace Ryujinx.Graphics.Vulkan
if (range.Handle != BufferHandle.Null) if (range.Handle != BufferHandle.Null)
{ {
_transformFeedbackBuffers[i] = new BufferState(Gd.BufferManager.GetBuffer(CommandBuffer, range.Handle, true), range.Offset, range.Size); _transformFeedbackBuffers[i] =
new BufferState(Gd.BufferManager.GetBuffer(CommandBuffer, range.Handle, range.Offset, range.Size, true), range.Offset, range.Size);
_transformFeedbackBuffers[i].BindTransformFeedbackBuffer(Gd, Cbs, (uint)i); _transformFeedbackBuffers[i].BindTransformFeedbackBuffer(Gd, Cbs, (uint)i);
} }
else else
@@ -975,7 +986,7 @@ namespace Ryujinx.Graphics.Vulkan
{ {
var viewport = viewports[i]; var viewport = viewports[i];
_dynamicState.SetViewport(i, new Silk.NET.Vulkan.Viewport( DynamicState.SetViewport(i, new Silk.NET.Vulkan.Viewport(
viewport.Region.X, viewport.Region.X,
viewport.Region.Y, viewport.Region.Y,
viewport.Region.Width == 0f ? 1f : viewport.Region.Width, viewport.Region.Width == 0f ? 1f : viewport.Region.Width,
@@ -984,7 +995,7 @@ namespace Ryujinx.Graphics.Vulkan
Clamp(viewport.DepthFar))); Clamp(viewport.DepthFar)));
} }
_dynamicState.ViewportsCount = count; DynamicState.ViewportsCount = count;
float disableTransformF = disableTransform ? 1.0f : 0.0f; float disableTransformF = disableTransform ? 1.0f : 0.0f;
if (SupportBufferUpdater.Data.ViewportInverse.W != disableTransformF || disableTransform) if (SupportBufferUpdater.Data.ViewportInverse.W != disableTransformF || disableTransform)
@@ -1063,7 +1074,7 @@ namespace Ryujinx.Graphics.Vulkan
_vertexBuffersDirty = ulong.MaxValue >> (64 - _vertexBuffers.Length); _vertexBuffersDirty = ulong.MaxValue >> (64 - _vertexBuffers.Length);
_descriptorSetUpdater.SignalCommandBufferChange(); _descriptorSetUpdater.SignalCommandBufferChange();
_dynamicState.ForceAllDirty(); DynamicState.ForceAllDirty();
_currentPipelineHandle = 0; _currentPipelineHandle = 0;
} }
@@ -1201,7 +1212,7 @@ namespace Ryujinx.Graphics.Vulkan
private void RecreatePipelineIfNeeded(PipelineBindPoint pbp) private void RecreatePipelineIfNeeded(PipelineBindPoint pbp)
{ {
_dynamicState.ReplayIfDirty(Gd.Api, CommandBuffer); DynamicState.ReplayIfDirty(Gd.Api, CommandBuffer);
// Commit changes to the support buffer before drawing. // Commit changes to the support buffer before drawing.
SupportBufferUpdater.Commit(); SupportBufferUpdater.Commit();

View File

@@ -204,6 +204,8 @@ namespace Ryujinx.Graphics.Vulkan
} }
SignalCommandBufferChange(); SignalCommandBufferChange();
DynamicState.ReplayIfDirty(Gd.Api, CommandBuffer);
} }
public void FlushCommandsImpl() public void FlushCommandsImpl()

View File

@@ -9,17 +9,19 @@ using System.Threading.Tasks;
namespace Ryujinx.Graphics.Vulkan namespace Ryujinx.Graphics.Vulkan
{ {
class Shader class Shader : IDisposable
{ {
// The shaderc.net dependency's Options constructor and dispose are not thread safe. // The shaderc.net dependency's Options constructor and dispose are not thread safe.
// Take this lock when using them. // Take this lock when using them.
private static object _shaderOptionsLock = new object(); private static object _shaderOptionsLock = new object();
private static readonly IntPtr _ptrMainEntryPointName = Marshal.StringToHGlobalAnsi("main");
private readonly Vk _api; private readonly Vk _api;
private readonly Device _device; private readonly Device _device;
private readonly ShaderStageFlags _stage; private readonly ShaderStageFlags _stage;
private IntPtr _entryPointName; private bool _disposed;
private ShaderModule _module; private ShaderModule _module;
public ShaderStageFlags StageFlags => _stage; public ShaderStageFlags StageFlags => _stage;
@@ -39,7 +41,6 @@ namespace Ryujinx.Graphics.Vulkan
CompileStatus = ProgramLinkStatus.Incomplete; CompileStatus = ProgramLinkStatus.Incomplete;
_stage = shaderSource.Stage.Convert(); _stage = shaderSource.Stage.Convert();
_entryPointName = Marshal.StringToHGlobalAnsi("main");
CompileTask = Task.Run(() => CompileTask = Task.Run(() =>
{ {
@@ -145,7 +146,7 @@ namespace Ryujinx.Graphics.Vulkan
SType = StructureType.PipelineShaderStageCreateInfo, SType = StructureType.PipelineShaderStageCreateInfo,
Stage = _stage, Stage = _stage,
Module = _module, Module = _module,
PName = (byte*)_entryPointName PName = (byte*)_ptrMainEntryPointName
}; };
} }
@@ -156,11 +157,10 @@ namespace Ryujinx.Graphics.Vulkan
public unsafe void Dispose() public unsafe void Dispose()
{ {
if (_entryPointName != IntPtr.Zero) if (!_disposed)
{ {
_api.DestroyShaderModule(_device, _module, null); _api.DestroyShaderModule(_device, _module, null);
Marshal.FreeHGlobal(_entryPointName); _disposed = true;
_entryPointName = IntPtr.Zero;
} }
} }
} }

View File

@@ -87,7 +87,7 @@ namespace Ryujinx.Graphics.Vulkan
private void PushDataImpl(CommandBufferScoped cbs, BufferHolder dst, int dstOffset, ReadOnlySpan<byte> data) private void PushDataImpl(CommandBufferScoped cbs, BufferHolder dst, int dstOffset, ReadOnlySpan<byte> data)
{ {
var srcBuffer = _buffer.GetBuffer(); var srcBuffer = _buffer.GetBuffer();
var dstBuffer = dst.GetBuffer(); var dstBuffer = dst.GetBuffer(cbs.CommandBuffer, dstOffset, data.Length, true);
int offset = _freeOffset; int offset = _freeOffset;
int capacity = BufferSize - offset; int capacity = BufferSize - offset;

View File

@@ -16,6 +16,8 @@ namespace Ryujinx.Graphics.Vulkan
private Auto<DisposableBufferView> _bufferView; private Auto<DisposableBufferView> _bufferView;
private Dictionary<GAL.Format, Auto<DisposableBufferView>> _selfManagedViews; private Dictionary<GAL.Format, Auto<DisposableBufferView>> _selfManagedViews;
private int _bufferCount;
public int Width { get; } public int Width { get; }
public int Height { get; } public int Height { get; }
@@ -107,7 +109,8 @@ namespace Ryujinx.Graphics.Vulkan
{ {
if (_bufferHandle == buffer.Handle && if (_bufferHandle == buffer.Handle &&
_offset == buffer.Offset && _offset == buffer.Offset &&
_size == buffer.Size) _size == buffer.Size &&
_bufferCount == _gd.BufferManager.BufferCount)
{ {
return; return;
} }
@@ -115,6 +118,7 @@ namespace Ryujinx.Graphics.Vulkan
_bufferHandle = buffer.Handle; _bufferHandle = buffer.Handle;
_offset = buffer.Offset; _offset = buffer.Offset;
_size = buffer.Size; _size = buffer.Size;
_bufferCount = _gd.BufferManager.BufferCount;
ReleaseImpl(); ReleaseImpl();
} }

View File

@@ -38,19 +38,18 @@ namespace Ryujinx.HLE.HOS.Services.Bcat.ServiceCreator
// Read() -> (u32, buffer<nn::bcat::DeliveryCacheDirectoryEntry, 6>) // Read() -> (u32, buffer<nn::bcat::DeliveryCacheDirectoryEntry, 6>)
public ResultCode Read(ServiceCtx context) public ResultCode Read(ServiceCtx context)
{ {
ulong position = context.Request.ReceiveBuff[0].Position; ulong bufferAddress = context.Request.ReceiveBuff[0].Position;
ulong size = context.Request.ReceiveBuff[0].Size; ulong bufferLen = context.Request.ReceiveBuff[0].Size;
byte[] data = new byte[size]; using (var region = context.Memory.GetWritableRegion(bufferAddress, (int)bufferLen, true))
{
Result result = _base.Get.Read(out int entriesRead, MemoryMarshal.Cast<byte, DeliveryCacheDirectoryEntry>(data)); Result result = _base.Get.Read(out int entriesRead, MemoryMarshal.Cast<byte, DeliveryCacheDirectoryEntry>(region.Memory.Span));
context.Memory.Write(position, data);
context.ResponseData.Write(entriesRead); context.ResponseData.Write(entriesRead);
return (ResultCode)result.Value; return (ResultCode)result.Value;
} }
}
[CommandHipc(2)] [CommandHipc(2)]
// GetCount() -> u32 // GetCount() -> u32

View File

@@ -38,21 +38,20 @@ namespace Ryujinx.HLE.HOS.Services.Bcat.ServiceCreator
// Read(u64) -> (u64, buffer<bytes, 6>) // Read(u64) -> (u64, buffer<bytes, 6>)
public ResultCode Read(ServiceCtx context) public ResultCode Read(ServiceCtx context)
{ {
ulong position = context.Request.ReceiveBuff[0].Position; ulong bufferAddress = context.Request.ReceiveBuff[0].Position;
ulong size = context.Request.ReceiveBuff[0].Size; ulong bufferLen = context.Request.ReceiveBuff[0].Size;
long offset = context.RequestData.ReadInt64(); long offset = context.RequestData.ReadInt64();
byte[] data = new byte[size]; using (var region = context.Memory.GetWritableRegion(bufferAddress, (int)bufferLen, true))
{
Result result = _base.Get.Read(out long bytesRead, offset, data); Result result = _base.Get.Read(out long bytesRead, offset, region.Memory.Span);
context.Memory.Write(position, data);
context.ResponseData.Write(bytesRead); context.ResponseData.Write(bytesRead);
return (ResultCode)result.Value; return (ResultCode)result.Value;
} }
}
[CommandHipc(2)] [CommandHipc(2)]
// GetSize() -> u64 // GetSize() -> u64

View File

@@ -50,19 +50,18 @@ namespace Ryujinx.HLE.HOS.Services.Bcat.ServiceCreator
// EnumerateDeliveryCacheDirectory() -> (u32, buffer<nn::bcat::DirectoryName, 6>) // EnumerateDeliveryCacheDirectory() -> (u32, buffer<nn::bcat::DirectoryName, 6>)
public ResultCode EnumerateDeliveryCacheDirectory(ServiceCtx context) public ResultCode EnumerateDeliveryCacheDirectory(ServiceCtx context)
{ {
ulong position = context.Request.ReceiveBuff[0].Position; ulong bufferAddress = context.Request.ReceiveBuff[0].Position;
ulong size = context.Request.ReceiveBuff[0].Size; ulong bufferLen = context.Request.ReceiveBuff[0].Size;
byte[] data = new byte[size]; using (var region = context.Memory.GetWritableRegion(bufferAddress, (int)bufferLen, true))
{
Result result = _base.Get.EnumerateDeliveryCacheDirectory(out int count, MemoryMarshal.Cast<byte, DirectoryName>(data)); Result result = _base.Get.EnumerateDeliveryCacheDirectory(out int count, MemoryMarshal.Cast<byte, DirectoryName>(region.Memory.Span));
context.Memory.Write(position, data);
context.ResponseData.Write(count); context.ResponseData.Write(count);
return (ResultCode)result.Value; return (ResultCode)result.Value;
} }
}
protected override void Dispose(bool isDisposing) protected override void Dispose(bool isDisposing)
{ {

View File

@@ -17,18 +17,18 @@ namespace Ryujinx.HLE.HOS.Services.Fs.FileSystemProxy
// Read() -> (u64 count, buffer<nn::fssrv::sf::IDirectoryEntry, 6, 0> entries) // Read() -> (u64 count, buffer<nn::fssrv::sf::IDirectoryEntry, 6, 0> entries)
public ResultCode Read(ServiceCtx context) public ResultCode Read(ServiceCtx context)
{ {
ulong bufferPosition = context.Request.ReceiveBuff[0].Position; ulong bufferAddress = context.Request.ReceiveBuff[0].Position;
ulong bufferLen = context.Request.ReceiveBuff[0].Size; ulong bufferLen = context.Request.ReceiveBuff[0].Size;
byte[] entryBuffer = new byte[bufferLen]; using (var region = context.Memory.GetWritableRegion(bufferAddress, (int)bufferLen, true))
{
Result result = _baseDirectory.Get.Read(out long entriesRead, new OutBuffer(region.Memory.Span));
Result result = _baseDirectory.Get.Read(out long entriesRead, new OutBuffer(entryBuffer));
context.Memory.Write(bufferPosition, entryBuffer);
context.ResponseData.Write(entriesRead); context.ResponseData.Write(entriesRead);
return (ResultCode)result.Value; return (ResultCode)result.Value;
} }
}
[CommandHipc(1)] [CommandHipc(1)]
// GetEntryCount() -> u64 // GetEntryCount() -> u64

View File

@@ -19,7 +19,8 @@ namespace Ryujinx.HLE.HOS.Services.Fs.FileSystemProxy
// Read(u32 readOption, u64 offset, u64 size) -> (u64 out_size, buffer<u8, 0x46, 0> out_buf) // Read(u32 readOption, u64 offset, u64 size) -> (u64 out_size, buffer<u8, 0x46, 0> out_buf)
public ResultCode Read(ServiceCtx context) public ResultCode Read(ServiceCtx context)
{ {
ulong position = context.Request.ReceiveBuff[0].Position; ulong bufferAddress = context.Request.ReceiveBuff[0].Position;
ulong bufferLen = context.Request.ReceiveBuff[0].Size;
ReadOption readOption = context.RequestData.ReadStruct<ReadOption>(); ReadOption readOption = context.RequestData.ReadStruct<ReadOption>();
context.RequestData.BaseStream.Position += 4; context.RequestData.BaseStream.Position += 4;
@@ -27,16 +28,15 @@ namespace Ryujinx.HLE.HOS.Services.Fs.FileSystemProxy
long offset = context.RequestData.ReadInt64(); long offset = context.RequestData.ReadInt64();
long size = context.RequestData.ReadInt64(); long size = context.RequestData.ReadInt64();
byte[] data = new byte[context.Request.ReceiveBuff[0].Size]; using (var region = context.Memory.GetWritableRegion(bufferAddress, (int)bufferLen, true))
{
Result result = _baseFile.Get.Read(out long bytesRead, offset, new OutBuffer(data), size, readOption); Result result = _baseFile.Get.Read(out long bytesRead, offset, new OutBuffer(region.Memory.Span), size, readOption);
context.Memory.Write(position, data);
context.ResponseData.Write(bytesRead); context.ResponseData.Write(bytesRead);
return (ResultCode)result.Value; return (ResultCode)result.Value;
} }
}
[CommandHipc(1)] [CommandHipc(1)]
// Write(u32 writeOption, u64 offset, u64 size, buffer<u8, 0x45, 0>) // Write(u32 writeOption, u64 offset, u64 size, buffer<u8, 0x45, 0>)

View File

@@ -197,13 +197,7 @@ namespace Ryujinx.HLE.HOS.Services.Fs.FileSystemProxy
context.ResponseData.Write(timestamp.Created); context.ResponseData.Write(timestamp.Created);
context.ResponseData.Write(timestamp.Modified); context.ResponseData.Write(timestamp.Modified);
context.ResponseData.Write(timestamp.Accessed); context.ResponseData.Write(timestamp.Accessed);
context.ResponseData.Write(1L); // Is valid?
byte[] data = new byte[8];
// is valid?
data[0] = 1;
context.ResponseData.Write(data);
return (ResultCode)result.Value; return (ResultCode)result.Value;
} }

View File

@@ -23,22 +23,22 @@ namespace Ryujinx.HLE.HOS.Services.Fs.FileSystemProxy
if (context.Request.ReceiveBuff.Count > 0) if (context.Request.ReceiveBuff.Count > 0)
{ {
IpcBuffDesc buffDesc = context.Request.ReceiveBuff[0]; ulong bufferAddress = context.Request.ReceiveBuff[0].Position;
ulong bufferLen = context.Request.ReceiveBuff[0].Size;
// Use smaller length to avoid overflows. // Use smaller length to avoid overflows.
if (size > buffDesc.Size) if (size > bufferLen)
{ {
size = buffDesc.Size; size = bufferLen;
} }
byte[] data = new byte[size]; using (var region = context.Memory.GetWritableRegion(bufferAddress, (int)bufferLen, true))
{
Result result = _baseStorage.Get.Read((long)offset, new OutBuffer(data), (long)size); Result result = _baseStorage.Get.Read((long)offset, new OutBuffer(region.Memory.Span), (long)size);
context.Memory.Write(buffDesc.Position, data);
return (ResultCode)result.Value; return (ResultCode)result.Value;
} }
}
return ResultCode.Success; return ResultCode.Success;
} }

View File

@@ -500,16 +500,16 @@ namespace Ryujinx.HLE.HOS.Services.Fs
SaveDataSpaceId spaceId = (SaveDataSpaceId)context.RequestData.ReadInt64(); SaveDataSpaceId spaceId = (SaveDataSpaceId)context.RequestData.ReadInt64();
SaveDataFilter filter = context.RequestData.ReadStruct<SaveDataFilter>(); SaveDataFilter filter = context.RequestData.ReadStruct<SaveDataFilter>();
ulong bufferPosition = context.Request.ReceiveBuff[0].Position; ulong bufferAddress = context.Request.ReceiveBuff[0].Position;
ulong bufferLen = context.Request.ReceiveBuff[0].Size; ulong bufferLen = context.Request.ReceiveBuff[0].Size;
byte[] infoBuffer = new byte[bufferLen]; using (var region = context.Memory.GetWritableRegion(bufferAddress, (int)bufferLen, true))
{
Result result = _baseFileSystemProxy.Get.FindSaveDataWithFilter(out long count, new OutBuffer(infoBuffer), spaceId, in filter); Result result = _baseFileSystemProxy.Get.FindSaveDataWithFilter(out long count, new OutBuffer(region.Memory.Span), spaceId, in filter);
if (result.IsFailure()) return (ResultCode)result.Value; if (result.IsFailure()) return (ResultCode)result.Value;
context.Memory.Write(bufferPosition, infoBuffer);
context.ResponseData.Write(count); context.ResponseData.Write(count);
}
return ResultCode.Success; return ResultCode.Success;
} }

View File

@@ -17,18 +17,18 @@ namespace Ryujinx.HLE.HOS.Services.Fs
// ReadSaveDataInfo() -> (u64, buffer<unknown, 6>) // ReadSaveDataInfo() -> (u64, buffer<unknown, 6>)
public ResultCode ReadSaveDataInfo(ServiceCtx context) public ResultCode ReadSaveDataInfo(ServiceCtx context)
{ {
ulong bufferPosition = context.Request.ReceiveBuff[0].Position; ulong bufferAddress = context.Request.ReceiveBuff[0].Position;
ulong bufferLen = context.Request.ReceiveBuff[0].Size; ulong bufferLen = context.Request.ReceiveBuff[0].Size;
byte[] infoBuffer = new byte[bufferLen]; using (var region = context.Memory.GetWritableRegion(bufferAddress, (int)bufferLen, true))
{
Result result = _baseReader.Get.Read(out long readCount, new OutBuffer(region.Memory.Span));
Result result = _baseReader.Get.Read(out long readCount, new OutBuffer(infoBuffer));
context.Memory.Write(bufferPosition, infoBuffer);
context.ResponseData.Write(readCount); context.ResponseData.Write(readCount);
return (ResultCode)result.Value; return (ResultCode)result.Value;
} }
}
protected override void Dispose(bool isDisposing) protected override void Dispose(bool isDisposing)
{ {

View File

@@ -3,7 +3,6 @@ using Ryujinx.Common.Logging;
using Ryujinx.Graphics.Gpu.Memory; using Ryujinx.Graphics.Gpu.Memory;
using Ryujinx.Memory; using Ryujinx.Memory;
using System; using System;
using System.Collections.Concurrent;
namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvMap namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvMap
{ {
@@ -11,13 +10,10 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvMap
{ {
private const int FlagNotFreedYet = 1; private const int FlagNotFreedYet = 1;
private static ConcurrentDictionary<ulong, IdDictionary> _maps = new ConcurrentDictionary<ulong, IdDictionary>(); private static NvMapIdDictionary _maps = new NvMapIdDictionary();
public NvMapDeviceFile(ServiceCtx context, IVirtualMemoryManager memory, ulong owner) : base(context, owner) public NvMapDeviceFile(ServiceCtx context, IVirtualMemoryManager memory, ulong owner) : base(context, owner)
{ {
IdDictionary dict = _maps.GetOrAdd(Owner, (key) => new IdDictionary());
dict.Add(0, new NvMapHandle());
} }
public override NvInternalResult Ioctl(NvIoctl command, Span<byte> arguments) public override NvInternalResult Ioctl(NvIoctl command, Span<byte> arguments)
@@ -232,19 +228,12 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvMap
private int CreateHandleFromMap(NvMapHandle map) private int CreateHandleFromMap(NvMapHandle map)
{ {
IdDictionary dict = _maps.GetOrAdd(Owner, (key) => new IdDictionary()); return _maps.Add(map);
return dict.Add(map);
} }
private static bool DeleteMapWithHandle(ulong pid, int handle) private static bool DeleteMapWithHandle(ulong pid, int handle)
{ {
if (_maps.TryGetValue(pid, out IdDictionary dict)) return _maps.Delete(handle) != null;
{
return dict.Delete(handle) != null;
}
return false;
} }
public static void IncrementMapRefCount(ulong pid, int handle) public static void IncrementMapRefCount(ulong pid, int handle)
@@ -277,12 +266,7 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvMap
public static NvMapHandle GetMapFromHandle(ulong pid, int handle) public static NvMapHandle GetMapFromHandle(ulong pid, int handle)
{ {
if (_maps.TryGetValue(pid, out IdDictionary dict)) return _maps.Get(handle);
{
return dict.GetData<NvMapHandle>(handle);
}
return null;
} }
} }
} }

View File

@@ -0,0 +1,61 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Threading;
namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvMap
{
class NvMapIdDictionary
{
private readonly ConcurrentDictionary<int, NvMapHandle> _nvmapHandles;
private int _id;
public ICollection<NvMapHandle> Values => _nvmapHandles.Values;
public NvMapIdDictionary()
{
_nvmapHandles = new ConcurrentDictionary<int, NvMapHandle>();
}
public int Add(NvMapHandle handle)
{
int id = Interlocked.Add(ref _id, 4);
if (id != 0 && _nvmapHandles.TryAdd(id, handle))
{
return id;
}
throw new InvalidOperationException("NvMap ID overflow.");
}
public NvMapHandle Get(int id)
{
if (_nvmapHandles.TryGetValue(id, out NvMapHandle handle))
{
return handle;
}
return null;
}
public NvMapHandle Delete(int id)
{
if (_nvmapHandles.TryRemove(id, out NvMapHandle handle))
{
return handle;
}
return null;
}
public ICollection<NvMapHandle> Clear()
{
ICollection<NvMapHandle> values = _nvmapHandles.Values;
_nvmapHandles.Clear();
return values;
}
}
}

View File

@@ -142,14 +142,13 @@ namespace Ryujinx.HLE.HOS.Services.Ssl.SslService
// GetHostName(buffer<bytes, 6>) -> u32 // GetHostName(buffer<bytes, 6>) -> u32
public ResultCode GetHostName(ServiceCtx context) public ResultCode GetHostName(ServiceCtx context)
{ {
ulong hostNameDataPosition = context.Request.ReceiveBuff[0].Position; ulong bufferAddress = context.Request.ReceiveBuff[0].Position;
ulong hostNameDataSize = context.Request.ReceiveBuff[0].Size; ulong bufferLen = context.Request.ReceiveBuff[0].Size;
byte[] hostNameData = new byte[hostNameDataSize]; using (var region = context.Memory.GetWritableRegion(bufferAddress, (int)bufferLen, true))
{
Encoding.ASCII.GetBytes(_hostName, hostNameData); Encoding.ASCII.GetBytes(_hostName, region.Memory.Span);
}
context.Memory.Write(hostNameDataPosition, hostNameData);
context.ResponseData.Write((uint)_hostName.Length); context.ResponseData.Write((uint)_hostName.Length);

View File

@@ -453,7 +453,7 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
Item = item Item = item
}; };
_device.Gpu.Window.EnqueueFrameThreadSafe( if (_device.Gpu.Window.EnqueueFrameThreadSafe(
layer.Owner, layer.Owner,
frameBufferAddress, frameBufferAddress,
frameBufferWidth, frameBufferWidth,
@@ -466,8 +466,8 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
crop, crop,
AcquireBuffer, AcquireBuffer,
ReleaseBuffer, ReleaseBuffer,
textureCallbackInformation); textureCallbackInformation))
{
if (item.Fence.FenceCount == 0) if (item.Fence.FenceCount == 0)
{ {
_device.Gpu.Window.SignalFrameReady(); _device.Gpu.Window.SignalFrameReady();
@@ -482,6 +482,11 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
}); });
} }
} }
else
{
ReleaseBuffer(textureCallbackInformation);
}
}
private void ReleaseBuffer(object obj) private void ReleaseBuffer(object obj)
{ {

View File

@@ -124,7 +124,7 @@ namespace Ryujinx.HLE
public void SetVolume(float volume) public void SetVolume(float volume)
{ {
System.SetVolume(volume); System.SetVolume(Math.Clamp(volume, 0, 1));
} }
public float GetVolume() public float GetVolume()

View File

@@ -14,7 +14,7 @@ namespace Ryujinx.Ui.Common.Configuration
/// <summary> /// <summary>
/// The current version of the file format /// The current version of the file format
/// </summary> /// </summary>
public const int CurrentVersion = 40; public const int CurrentVersion = 41;
/// <summary> /// <summary>
/// Version of the configuration file format /// Version of the configuration file format

View File

@@ -677,7 +677,9 @@ namespace Ryujinx.Ui.Common.Configuration
ShowUi = Key.F4, ShowUi = Key.F4,
Pause = Key.F5, Pause = Key.F5,
ResScaleUp = Key.Unbound, ResScaleUp = Key.Unbound,
ResScaleDown = Key.Unbound ResScaleDown = Key.Unbound,
VolumeUp = Key.Unbound,
VolumeDown = Key.Unbound
}; };
Hid.InputConfig.Value = new List<InputConfig> Hid.InputConfig.Value = new List<InputConfig>
{ {
@@ -1156,6 +1158,24 @@ namespace Ryujinx.Ui.Common.Configuration
configurationFileUpdated = true; 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; Logger.EnableFileLog.Value = configurationFileFormat.EnableFileLog;
Graphics.ResScale.Value = configurationFileFormat.ResScale; Graphics.ResScale.Value = configurationFileFormat.ResScale;
Graphics.ResScaleCustom.Value = configurationFileFormat.ResScaleCustom; Graphics.ResScaleCustom.Value = configurationFileFormat.ResScaleCustom;

View File

@@ -35,6 +35,7 @@ namespace Ryujinx.Ui
private const int SwitchPanelHeight = 720; private const int SwitchPanelHeight = 720;
private const int TargetFps = 60; private const int TargetFps = 60;
private const float MaxResolutionScale = 4.0f; // Max resolution hotkeys can scale to before wrapping. 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 ManualResetEvent WaitEvent { get; set; }
public NpadManager NpadManager { get; } public NpadManager NpadManager { get; }
@@ -57,6 +58,7 @@ namespace Ryujinx.Ui
private readonly long _ticksPerFrame; private readonly long _ticksPerFrame;
private long _ticks = 0; private long _ticks = 0;
private float _newVolume;
private readonly Stopwatch _chrono; private readonly Stopwatch _chrono;
@@ -643,6 +645,20 @@ namespace Ryujinx.Ui
(MaxResolutionScale + GraphicsConfig.ResScale - 2) % MaxResolutionScale + 1; (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; _prevHotkeyState = currentHotkeyState;
} }
@@ -675,7 +691,9 @@ namespace Ryujinx.Ui
Pause = 1 << 3, Pause = 1 << 3,
ToggleMute = 1 << 4, ToggleMute = 1 << 4,
ResScaleUp = 1 << 5, ResScaleUp = 1 << 5,
ResScaleDown = 1 << 6 ResScaleDown = 1 << 6,
VolumeUp = 1 << 7,
VolumeDown = 1 << 8
} }
private KeyboardHotkeyState GetHotkeyState() private KeyboardHotkeyState GetHotkeyState()
@@ -717,6 +735,16 @@ namespace Ryujinx.Ui
state |= KeyboardHotkeyState.ResScaleDown; 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; return state;
} }
} }