Compare commits
54 Commits
Author | SHA1 | Date | |
---|---|---|---|
121296834a | |||
bbb24d8c7e | |||
4da44e09cb | |||
ae13f0ab4d | |||
a2a35f1be6 | |||
aedfadaaf7 | |||
5c0fb0cec3 | |||
17a1cab5d2 | |||
73aed239c3 | |||
9ac66336a2 | |||
4965681e06 | |||
3868a00206 | |||
933e5144a9 | |||
73a42c85c4 | |||
39ba11054b | |||
c250e3392c | |||
e56b069081 | |||
204c031fef | |||
d9053bbe37 | |||
c25e8427aa | |||
21a081b185 | |||
b540ea80d1 | |||
d692a9b83e | |||
9677ddaa5d | |||
ce92e8cd04 | |||
456fc04007 | |||
458452279c | |||
817b89767a | |||
3fb583c98c | |||
d2686e0a5b | |||
4905101df1 | |||
8750b90a7f | |||
af01100050 | |||
c0821fee1f | |||
a5c2aead67 | |||
d41c95dcff | |||
fbf2b09706 | |||
1fc0f569de | |||
dff138229c | |||
472119c8da | |||
1865ea87e5 | |||
18b61aff59 | |||
cb22629ac1 | |||
6f0f99ee2b | |||
70f2da8fdf | |||
5d3ef7761b | |||
476b4683cf | |||
5fb5079730 | |||
3fbacd0f49 | |||
7aa6abc120 | |||
548bfd60a2 | |||
65778a6b78 | |||
f4e879a1e6 | |||
a1ddaa2736 |
@ -89,6 +89,7 @@ csharp_style_conditional_delegate_call = true:suggestion
|
|||||||
# Modifier preferences
|
# Modifier preferences
|
||||||
csharp_prefer_static_local_function = true:suggestion
|
csharp_prefer_static_local_function = true:suggestion
|
||||||
csharp_preferred_modifier_order = public,private,protected,internal,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,volatile,async:silent
|
csharp_preferred_modifier_order = public,private,protected,internal,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,volatile,async:silent
|
||||||
|
csharp_style_prefer_readonly_struct = true
|
||||||
|
|
||||||
# Code-block preferences
|
# Code-block preferences
|
||||||
csharp_prefer_braces = true:silent
|
csharp_prefer_braces = true:silent
|
||||||
|
2
.github/ISSUE_TEMPLATE/bug_report.md
vendored
2
.github/ISSUE_TEMPLATE/bug_report.md
vendored
@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
name: Bug Report
|
name: Bug Report
|
||||||
about: Something doesn't work correctly in Ryujinx. Note that game-specific issues should be instead posted on the Game Compatibility List at https://github.com/Ryujinx/Ryujinx-Games-List, unless it is a provable regression.
|
about: Something doesn't work correctly in Ryujinx. Game-specific issues should be posted at https://github.com/Ryujinx/Ryujinx-Games-List instead, unless it is a provable regression.
|
||||||
#assignees:
|
#assignees:
|
||||||
---
|
---
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
namespace ARMeilleure.CodeGen.RegisterAllocators
|
namespace ARMeilleure.CodeGen.RegisterAllocators
|
||||||
{
|
{
|
||||||
struct AllocationResult
|
readonly struct AllocationResult
|
||||||
{
|
{
|
||||||
public int IntUsedRegisters { get; }
|
public int IntUsedRegisters { get; }
|
||||||
public int VecUsedRegisters { get; }
|
public int VecUsedRegisters { get; }
|
||||||
|
@ -11,7 +11,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
|
|||||||
{
|
{
|
||||||
private class ParallelCopy
|
private class ParallelCopy
|
||||||
{
|
{
|
||||||
private struct Copy
|
private readonly struct Copy
|
||||||
{
|
{
|
||||||
public Register Dest { get; }
|
public Register Dest { get; }
|
||||||
public Register Source { get; }
|
public Register Source { get; }
|
||||||
|
@ -11,7 +11,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
|
|||||||
{
|
{
|
||||||
class HybridAllocator : IRegisterAllocator
|
class HybridAllocator : IRegisterAllocator
|
||||||
{
|
{
|
||||||
private struct BlockInfo
|
private readonly struct BlockInfo
|
||||||
{
|
{
|
||||||
public bool HasCall { get; }
|
public bool HasCall { get; }
|
||||||
|
|
||||||
|
@ -3,7 +3,7 @@ using System;
|
|||||||
|
|
||||||
namespace ARMeilleure.CodeGen.RegisterAllocators
|
namespace ARMeilleure.CodeGen.RegisterAllocators
|
||||||
{
|
{
|
||||||
struct RegisterMasks
|
readonly struct RegisterMasks
|
||||||
{
|
{
|
||||||
public int IntAvailableRegisters { get; }
|
public int IntAvailableRegisters { get; }
|
||||||
public int VecAvailableRegisters { get; }
|
public int VecAvailableRegisters { get; }
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
namespace ARMeilleure.CodeGen.X86
|
namespace ARMeilleure.CodeGen.X86
|
||||||
{
|
{
|
||||||
struct IntrinsicInfo
|
readonly struct IntrinsicInfo
|
||||||
{
|
{
|
||||||
public X86Instruction Inst { get; }
|
public X86Instruction Inst { get; }
|
||||||
public IntrinsicType Type { get; }
|
public IntrinsicType Type { get; }
|
||||||
|
@ -2,7 +2,7 @@ using ARMeilleure.Instructions;
|
|||||||
|
|
||||||
namespace ARMeilleure.Decoders
|
namespace ARMeilleure.Decoders
|
||||||
{
|
{
|
||||||
struct InstDescriptor
|
readonly struct InstDescriptor
|
||||||
{
|
{
|
||||||
public static InstDescriptor Undefined => new InstDescriptor(InstName.Und, InstEmit.Und);
|
public static InstDescriptor Undefined => new InstDescriptor(InstName.Und, InstEmit.Und);
|
||||||
|
|
||||||
|
@ -11,7 +11,7 @@ namespace ARMeilleure.Decoders
|
|||||||
|
|
||||||
private const int FastLookupSize = 0x1000;
|
private const int FastLookupSize = 0x1000;
|
||||||
|
|
||||||
private struct InstInfo
|
private readonly struct InstInfo
|
||||||
{
|
{
|
||||||
public int Mask { get; }
|
public int Mask { get; }
|
||||||
public int Value { get; }
|
public int Value { get; }
|
||||||
|
@ -6,7 +6,7 @@ namespace ARMeilleure.Diagnostics
|
|||||||
{
|
{
|
||||||
static class Symbols
|
static class Symbols
|
||||||
{
|
{
|
||||||
private struct RangedSymbol
|
private readonly struct RangedSymbol
|
||||||
{
|
{
|
||||||
public readonly ulong Start;
|
public readonly ulong Start;
|
||||||
public readonly ulong End;
|
public readonly ulong End;
|
||||||
|
@ -3,7 +3,7 @@ using static ARMeilleure.IntermediateRepresentation.Operand.Factory;
|
|||||||
|
|
||||||
namespace ARMeilleure.IntermediateRepresentation
|
namespace ARMeilleure.IntermediateRepresentation
|
||||||
{
|
{
|
||||||
struct PhiOperation
|
readonly struct PhiOperation
|
||||||
{
|
{
|
||||||
private readonly Operation _operation;
|
private readonly Operation _operation;
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@ using System;
|
|||||||
|
|
||||||
namespace ARMeilleure.IntermediateRepresentation
|
namespace ARMeilleure.IntermediateRepresentation
|
||||||
{
|
{
|
||||||
struct Register : IEquatable<Register>
|
readonly struct Register : IEquatable<Register>
|
||||||
{
|
{
|
||||||
public int Index { get; }
|
public int Index { get; }
|
||||||
|
|
||||||
|
@ -4,7 +4,7 @@ using System.Diagnostics.CodeAnalysis;
|
|||||||
|
|
||||||
namespace ARMeilleure.Translation.Cache
|
namespace ARMeilleure.Translation.Cache
|
||||||
{
|
{
|
||||||
struct CacheEntry : IComparable<CacheEntry>
|
readonly struct CacheEntry : IComparable<CacheEntry>
|
||||||
{
|
{
|
||||||
public int Offset { get; }
|
public int Offset { get; }
|
||||||
public int Size { get; }
|
public int Size { get; }
|
||||||
|
@ -6,7 +6,7 @@ namespace ARMeilleure.Translation.Cache
|
|||||||
{
|
{
|
||||||
class CacheMemoryAllocator
|
class CacheMemoryAllocator
|
||||||
{
|
{
|
||||||
private struct MemoryBlock : IComparable<MemoryBlock>
|
private readonly struct MemoryBlock : IComparable<MemoryBlock>
|
||||||
{
|
{
|
||||||
public int Offset { get; }
|
public int Offset { get; }
|
||||||
public int Size { get; }
|
public int Size { get; }
|
||||||
|
@ -2,7 +2,7 @@ using ARMeilleure.IntermediateRepresentation;
|
|||||||
|
|
||||||
namespace ARMeilleure.Translation
|
namespace ARMeilleure.Translation
|
||||||
{
|
{
|
||||||
struct CompilerContext
|
readonly struct CompilerContext
|
||||||
{
|
{
|
||||||
public ControlFlowGraph Cfg { get; }
|
public ControlFlowGraph Cfg { get; }
|
||||||
|
|
||||||
|
@ -14,7 +14,7 @@ namespace ARMeilleure.Translation
|
|||||||
private const int RegsCount = 32;
|
private const int RegsCount = 32;
|
||||||
private const int RegsMask = RegsCount - 1;
|
private const int RegsMask = RegsCount - 1;
|
||||||
|
|
||||||
private struct RegisterMask : IEquatable<RegisterMask>
|
private readonly struct RegisterMask : IEquatable<RegisterMask>
|
||||||
{
|
{
|
||||||
public long IntMask => Mask.GetElement(0);
|
public long IntMask => Mask.GetElement(0);
|
||||||
public long VecMask => Mask.GetElement(1);
|
public long VecMask => Mask.GetElement(1);
|
||||||
|
@ -293,7 +293,7 @@ namespace ARMeilleure.Translation
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private struct Range
|
private readonly struct Range
|
||||||
{
|
{
|
||||||
public ulong Start { get; }
|
public ulong Start { get; }
|
||||||
public ulong End { get; }
|
public ulong End { get; }
|
||||||
|
10
README.md
10
README.md
@ -21,6 +21,10 @@
|
|||||||
<img src="https://github.com/Ryujinx/Ryujinx/actions/workflows/release.yml/badge.svg"
|
<img src="https://github.com/Ryujinx/Ryujinx/actions/workflows/release.yml/badge.svg"
|
||||||
alt="">
|
alt="">
|
||||||
</a>
|
</a>
|
||||||
|
<a href="https://crwd.in/ryujinx">
|
||||||
|
<img src="https://badges.crowdin.net/ryujinx/localized.svg"
|
||||||
|
alt="">
|
||||||
|
</a>
|
||||||
<a href="https://discord.com/invite/VkQYXAZ">
|
<a href="https://discord.com/invite/VkQYXAZ">
|
||||||
<img src="https://img.shields.io/discord/410208534861447168?color=5865F2&label=Ryujinx&logo=discord&logoColor=white"
|
<img src="https://img.shields.io/discord/410208534861447168?color=5865F2&label=Ryujinx&logo=discord&logoColor=white"
|
||||||
alt="Discord">
|
alt="Discord">
|
||||||
@ -36,7 +40,7 @@
|
|||||||
|
|
||||||
## Compatibility
|
## Compatibility
|
||||||
|
|
||||||
As of October 2022, Ryujinx has been tested on approximately 3,700 titles; over 3,500 boot past menus and into gameplay, with roughly 3,000 of those being considered playable.
|
As of November 2022, Ryujinx has been tested on approximately 3,800 titles; over 3,600 boot past menus and into gameplay, with roughly 3,200 of those being considered playable.
|
||||||
You can check out the compatibility list [here](https://github.com/Ryujinx/Ryujinx-Games-List/issues). Anyone is free to submit a new game test or update an existing game test entry; simply follow the new issue template and testing guidelines, or post as a reply to the applicable game issue. Use the search function to see if a game has been tested already!
|
You can check out the compatibility list [here](https://github.com/Ryujinx/Ryujinx-Games-List/issues). Anyone is free to submit a new game test or update an existing game test entry; simply follow the new issue template and testing guidelines, or post as a reply to the applicable game issue. Use the search function to see if a game has been tested already!
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
@ -48,6 +52,8 @@ See our [Setup & Configuration Guide](https://github.com/Ryujinx/Ryujinx/wiki/Ry
|
|||||||
For our Local Wireless and LAN builds, see our [Multiplayer: Local Play/Local Wireless Guide
|
For our Local Wireless and LAN builds, see our [Multiplayer: Local Play/Local Wireless Guide
|
||||||
](https://github.com/Ryujinx/Ryujinx/wiki/Multiplayer-(LDN-Local-Wireless)-Guide).
|
](https://github.com/Ryujinx/Ryujinx/wiki/Multiplayer-(LDN-Local-Wireless)-Guide).
|
||||||
|
|
||||||
|
Avalonia UI comes with translations for various languages. See [Crowdin](https://crwd.in/ryujinx) for more information.
|
||||||
|
|
||||||
## Latest build
|
## Latest build
|
||||||
|
|
||||||
These builds are compiled automatically for each commit on the master branch. While we strive to ensure optimal stability and performance prior to pushing an update, our automated builds **may be unstable or completely broken.**
|
These builds are compiled automatically for each commit on the master branch. While we strive to ensure optimal stability and performance prior to pushing an update, our automated builds **may be unstable or completely broken.**
|
||||||
@ -90,7 +96,7 @@ Ryujinx system files are stored in the `Ryujinx` folder. This folder is located
|
|||||||
|
|
||||||
- **GPU**
|
- **GPU**
|
||||||
|
|
||||||
The GPU emulator emulates the Switch's Maxwell GPU using either the OpenGL (version 4.5 minimum) or Vulkan APIs through a custom build of OpenTK or Silk.NET respectively. There are currently four graphics enhancements available to the end user in Ryujinx: Disk Shader Caching, Resolution Scaling, Aspect Ratio Adjustment, and Anisotropic Filtering. These enhancements can be adjusted or toggled as desired in the GUI.
|
The GPU emulator emulates the Switch's Maxwell GPU using either the OpenGL (version 4.5 minimum), Vulkan, or Metal (via MoltenVK) APIs through a custom build of OpenTK or Silk.NET respectively. There are currently four graphics enhancements available to the end user in Ryujinx: Disk Shader Caching, Resolution Scaling, Aspect Ratio Adjustment, and Anisotropic Filtering. These enhancements can be adjusted or toggled as desired in the GUI.
|
||||||
|
|
||||||
- **Input**
|
- **Input**
|
||||||
|
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="OpenTK.OpenAL" Version="4.7.2" />
|
<PackageReference Include="OpenTK.OpenAL" Version="4.7.5" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
using Ryujinx.Audio.Common;
|
using Ryujinx.Audio.Common;
|
||||||
using Ryujinx.Audio.Integration;
|
using Ryujinx.Audio.Integration;
|
||||||
|
using Ryujinx.Common.Logging;
|
||||||
using Ryujinx.Memory;
|
using Ryujinx.Memory;
|
||||||
using Ryujinx.SDL2.Common;
|
using Ryujinx.SDL2.Common;
|
||||||
using System;
|
using System;
|
||||||
@ -112,6 +113,9 @@ namespace Ryujinx.Audio.Backends.SDL2
|
|||||||
|
|
||||||
if (device == 0)
|
if (device == 0)
|
||||||
{
|
{
|
||||||
|
Logger.Error?.Print(LogClass.Application,
|
||||||
|
$"SDL2 open audio device initialization failed with error \"{SDL_GetError()}\"");
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -119,6 +123,7 @@ namespace Ryujinx.Audio.Backends.SDL2
|
|||||||
|
|
||||||
if (!isValid)
|
if (!isValid)
|
||||||
{
|
{
|
||||||
|
Logger.Error?.Print(LogClass.Application, "SDL2 open audio device is not valid");
|
||||||
SDL_CloseAudioDevice(device);
|
SDL_CloseAudioDevice(device);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -4,7 +4,7 @@ using System.Runtime.InteropServices;
|
|||||||
|
|
||||||
namespace SoundIOSharp
|
namespace SoundIOSharp
|
||||||
{
|
{
|
||||||
public struct SoundIOChannelLayout
|
public readonly struct SoundIOChannelLayout
|
||||||
{
|
{
|
||||||
public static int BuiltInCount
|
public static int BuiltInCount
|
||||||
{
|
{
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
namespace SoundIOSharp
|
namespace SoundIOSharp
|
||||||
{
|
{
|
||||||
public struct SoundIOSampleRateRange
|
public readonly struct SoundIOSampleRateRange
|
||||||
{
|
{
|
||||||
internal SoundIOSampleRateRange(int min, int max)
|
internal SoundIOSampleRateRange(int min, int max)
|
||||||
{
|
{
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
using Ryujinx.Audio.Renderer.Dsp.State;
|
using Ryujinx.Audio.Renderer.Dsp.State;
|
||||||
|
using Ryujinx.Common.Logging;
|
||||||
using System;
|
using System;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
@ -71,6 +72,19 @@ namespace Ryujinx.Audio.Renderer.Dsp
|
|||||||
return (short)value;
|
return (short)value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
private static short GetCoefficientAtIndex(ReadOnlySpan<short> coefficients, int index)
|
||||||
|
{
|
||||||
|
if ((uint)index > (uint)coefficients.Length)
|
||||||
|
{
|
||||||
|
Logger.Error?.Print(LogClass.AudioRenderer, $"Out of bound read for coefficient at index {index}");
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return coefficients[index];
|
||||||
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static int Decode(Span<short> output, ReadOnlySpan<byte> input, int startSampleOffset, int endSampleOffset, int offset, int count, ReadOnlySpan<short> coefficients, ref AdpcmLoopContext loopContext)
|
public static int Decode(Span<short> output, ReadOnlySpan<byte> input, int startSampleOffset, int endSampleOffset, int offset, int count, ReadOnlySpan<short> coefficients, ref AdpcmLoopContext loopContext)
|
||||||
{
|
{
|
||||||
@ -84,8 +98,8 @@ namespace Ryujinx.Audio.Renderer.Dsp
|
|||||||
byte coefficientIndex = (byte)((predScale >> 4) & 0xF);
|
byte coefficientIndex = (byte)((predScale >> 4) & 0xF);
|
||||||
short history0 = loopContext.History0;
|
short history0 = loopContext.History0;
|
||||||
short history1 = loopContext.History1;
|
short history1 = loopContext.History1;
|
||||||
short coefficient0 = coefficients[coefficientIndex * 2 + 0];
|
short coefficient0 = GetCoefficientAtIndex(coefficients, coefficientIndex * 2 + 0);
|
||||||
short coefficient1 = coefficients[coefficientIndex * 2 + 1];
|
short coefficient1 = GetCoefficientAtIndex(coefficients, coefficientIndex * 2 + 1);
|
||||||
|
|
||||||
int decodedCount = Math.Min(count, endSampleOffset - startSampleOffset - offset);
|
int decodedCount = Math.Min(count, endSampleOffset - startSampleOffset - offset);
|
||||||
int nibbles = GetNibblesFromSampleCount(offset + startSampleOffset);
|
int nibbles = GetNibblesFromSampleCount(offset + startSampleOffset);
|
||||||
@ -109,8 +123,8 @@ namespace Ryujinx.Audio.Renderer.Dsp
|
|||||||
|
|
||||||
coefficientIndex = (byte)((predScale >> 4) & 0xF);
|
coefficientIndex = (byte)((predScale >> 4) & 0xF);
|
||||||
|
|
||||||
coefficient0 = coefficients[coefficientIndex * 2 + 0];
|
coefficient0 = GetCoefficientAtIndex(coefficients, coefficientIndex * 2);
|
||||||
coefficient1 = coefficients[coefficientIndex * 2 + 1];
|
coefficient1 = GetCoefficientAtIndex(coefficients, coefficientIndex * 2 + 1);
|
||||||
|
|
||||||
nibbles += 2;
|
nibbles += 2;
|
||||||
|
|
||||||
|
@ -116,6 +116,11 @@ namespace Ryujinx.Audio.Renderer.Dsp
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool HasRemainingCommands(int sessionId)
|
||||||
|
{
|
||||||
|
return _sessionCommandList[sessionId] != null;
|
||||||
|
}
|
||||||
|
|
||||||
public void Signal()
|
public void Signal()
|
||||||
{
|
{
|
||||||
_mailbox.SendMessage(MailboxMessage.RenderStart);
|
_mailbox.SendMessage(MailboxMessage.RenderStart);
|
||||||
|
@ -13,7 +13,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
|||||||
|
|
||||||
public CommandType CommandType => CommandType.AdpcmDataSourceVersion1;
|
public CommandType CommandType => CommandType.AdpcmDataSourceVersion1;
|
||||||
|
|
||||||
public ulong EstimatedProcessingTime { get; set; }
|
public uint EstimatedProcessingTime { get; set; }
|
||||||
|
|
||||||
public ushort OutputBufferIndex { get; }
|
public ushort OutputBufferIndex { get; }
|
||||||
public uint SampleRate { get; }
|
public uint SampleRate { get; }
|
||||||
|
@ -16,7 +16,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
|||||||
|
|
||||||
public CommandType CommandType => CommandType.AuxiliaryBuffer;
|
public CommandType CommandType => CommandType.AuxiliaryBuffer;
|
||||||
|
|
||||||
public ulong EstimatedProcessingTime { get; set; }
|
public uint EstimatedProcessingTime { get; set; }
|
||||||
|
|
||||||
public uint InputBufferIndex { get; }
|
public uint InputBufferIndex { get; }
|
||||||
public uint OutputBufferIndex { get; }
|
public uint OutputBufferIndex { get; }
|
||||||
|
@ -12,7 +12,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
|||||||
|
|
||||||
public CommandType CommandType => CommandType.BiquadFilter;
|
public CommandType CommandType => CommandType.BiquadFilter;
|
||||||
|
|
||||||
public ulong EstimatedProcessingTime { get; set; }
|
public uint EstimatedProcessingTime { get; set; }
|
||||||
|
|
||||||
public Memory<BiquadFilterState> BiquadFilterState { get; }
|
public Memory<BiquadFilterState> BiquadFilterState { get; }
|
||||||
public int InputBufferIndex { get; }
|
public int InputBufferIndex { get; }
|
||||||
|
@ -16,7 +16,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
|||||||
|
|
||||||
public CommandType CommandType => CommandType.CaptureBuffer;
|
public CommandType CommandType => CommandType.CaptureBuffer;
|
||||||
|
|
||||||
public ulong EstimatedProcessingTime { get; set; }
|
public uint EstimatedProcessingTime { get; set; }
|
||||||
|
|
||||||
public uint InputBufferIndex { get; }
|
public uint InputBufferIndex { get; }
|
||||||
|
|
||||||
|
@ -12,7 +12,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
|||||||
|
|
||||||
public CommandType CommandType => CommandType.CircularBufferSink;
|
public CommandType CommandType => CommandType.CircularBufferSink;
|
||||||
|
|
||||||
public ulong EstimatedProcessingTime { get; set; }
|
public uint EstimatedProcessingTime { get; set; }
|
||||||
|
|
||||||
public ushort[] Input { get; }
|
public ushort[] Input { get; }
|
||||||
public uint InputCount { get; }
|
public uint InputCount { get; }
|
||||||
|
@ -8,7 +8,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
|||||||
|
|
||||||
public CommandType CommandType => CommandType.ClearMixBuffer;
|
public CommandType CommandType => CommandType.ClearMixBuffer;
|
||||||
|
|
||||||
public ulong EstimatedProcessingTime { get; set; }
|
public uint EstimatedProcessingTime { get; set; }
|
||||||
|
|
||||||
public ClearMixBufferCommand(int nodeId)
|
public ClearMixBufferCommand(int nodeId)
|
||||||
{
|
{
|
||||||
|
@ -8,7 +8,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
|||||||
|
|
||||||
public CommandType CommandType => CommandType.CopyMixBuffer;
|
public CommandType CommandType => CommandType.CopyMixBuffer;
|
||||||
|
|
||||||
public ulong EstimatedProcessingTime { get; set; }
|
public uint EstimatedProcessingTime { get; set; }
|
||||||
|
|
||||||
public ushort InputBufferIndex { get; }
|
public ushort InputBufferIndex { get; }
|
||||||
public ushort OutputBufferIndex { get; }
|
public ushort OutputBufferIndex { get; }
|
||||||
|
@ -13,7 +13,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
|||||||
|
|
||||||
public CommandType CommandType { get; }
|
public CommandType CommandType { get; }
|
||||||
|
|
||||||
public ulong EstimatedProcessingTime { get; set; }
|
public uint EstimatedProcessingTime { get; set; }
|
||||||
|
|
||||||
public ushort OutputBufferIndex { get; }
|
public ushort OutputBufferIndex { get; }
|
||||||
public uint SampleRate { get; }
|
public uint SampleRate { get; }
|
||||||
|
@ -17,7 +17,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
|||||||
|
|
||||||
public CommandType CommandType => CommandType.Delay;
|
public CommandType CommandType => CommandType.Delay;
|
||||||
|
|
||||||
public ulong EstimatedProcessingTime { get; set; }
|
public uint EstimatedProcessingTime { get; set; }
|
||||||
|
|
||||||
public DelayParameter Parameter => _parameter;
|
public DelayParameter Parameter => _parameter;
|
||||||
public Memory<DelayState> State { get; }
|
public Memory<DelayState> State { get; }
|
||||||
@ -49,15 +49,15 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
|||||||
OutputBufferIndices[i] = (ushort)(bufferOffset + Parameter.Output[i]);
|
OutputBufferIndices[i] = (ushort)(bufferOffset + Parameter.Output[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE: We do the opposite as Nintendo here for now to restore previous behaviour
|
DataSourceHelper.RemapLegacyChannelEffectMappingToChannelResourceMapping(newEffectChannelMappingSupported, InputBufferIndices);
|
||||||
// TODO: Update delay processing and remove this to use RemapLegacyChannelEffectMappingToChannelResourceMapping.
|
DataSourceHelper.RemapLegacyChannelEffectMappingToChannelResourceMapping(newEffectChannelMappingSupported, OutputBufferIndices);
|
||||||
DataSourceHelper.RemapChannelResourceMappingToLegacy(newEffectChannelMappingSupported, InputBufferIndices);
|
|
||||||
DataSourceHelper.RemapChannelResourceMappingToLegacy(newEffectChannelMappingSupported, OutputBufferIndices);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
|
||||||
private unsafe void ProcessDelayMono(ref DelayState state, float* outputBuffer, float* inputBuffer, uint sampleCount)
|
private unsafe void ProcessDelayMono(ref DelayState state, float* outputBuffer, float* inputBuffer, uint sampleCount)
|
||||||
{
|
{
|
||||||
|
const ushort channelCount = 1;
|
||||||
|
|
||||||
float feedbackGain = FixedPointHelper.ToFloat(Parameter.FeedbackGain, FixedPointPrecision);
|
float feedbackGain = FixedPointHelper.ToFloat(Parameter.FeedbackGain, FixedPointPrecision);
|
||||||
float inGain = FixedPointHelper.ToFloat(Parameter.InGain, FixedPointPrecision);
|
float inGain = FixedPointHelper.ToFloat(Parameter.InGain, FixedPointPrecision);
|
||||||
float dryGain = FixedPointHelper.ToFloat(Parameter.DryGain, FixedPointPrecision);
|
float dryGain = FixedPointHelper.ToFloat(Parameter.DryGain, FixedPointPrecision);
|
||||||
@ -70,7 +70,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
|||||||
|
|
||||||
float temp = input * inGain + delayLineValue * feedbackGain;
|
float temp = input * inGain + delayLineValue * feedbackGain;
|
||||||
|
|
||||||
state.UpdateLowPassFilter(ref temp, 1);
|
state.UpdateLowPassFilter(ref temp, channelCount);
|
||||||
|
|
||||||
outputBuffer[i] = (input * dryGain + delayLineValue * outGain) / 64;
|
outputBuffer[i] = (input * dryGain + delayLineValue * outGain) / 64;
|
||||||
}
|
}
|
||||||
@ -104,7 +104,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
|||||||
Y = state.DelayLines[1].Read(),
|
Y = state.DelayLines[1].Read(),
|
||||||
};
|
};
|
||||||
|
|
||||||
Vector2 temp = MatrixHelper.Transform(ref channelInput, ref delayFeedback) + channelInput * inGain;
|
Vector2 temp = MatrixHelper.Transform(ref delayLineValues, ref delayFeedback) + channelInput * inGain;
|
||||||
|
|
||||||
state.UpdateLowPassFilter(ref Unsafe.As<Vector2, float>(ref temp), channelCount);
|
state.UpdateLowPassFilter(ref Unsafe.As<Vector2, float>(ref temp), channelCount);
|
||||||
|
|
||||||
@ -148,7 +148,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
|||||||
W = state.DelayLines[3].Read()
|
W = state.DelayLines[3].Read()
|
||||||
};
|
};
|
||||||
|
|
||||||
Vector4 temp = MatrixHelper.Transform(ref channelInput, ref delayFeedback) + channelInput * inGain;
|
Vector4 temp = MatrixHelper.Transform(ref delayLineValues, ref delayFeedback) + channelInput * inGain;
|
||||||
|
|
||||||
state.UpdateLowPassFilter(ref Unsafe.As<Vector4, float>(ref temp), channelCount);
|
state.UpdateLowPassFilter(ref Unsafe.As<Vector4, float>(ref temp), channelCount);
|
||||||
|
|
||||||
@ -171,12 +171,12 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
|||||||
float dryGain = FixedPointHelper.ToFloat(Parameter.DryGain, FixedPointPrecision);
|
float dryGain = FixedPointHelper.ToFloat(Parameter.DryGain, FixedPointPrecision);
|
||||||
float outGain = FixedPointHelper.ToFloat(Parameter.OutGain, FixedPointPrecision);
|
float outGain = FixedPointHelper.ToFloat(Parameter.OutGain, FixedPointPrecision);
|
||||||
|
|
||||||
Matrix6x6 delayFeedback = new Matrix6x6(delayFeedbackBaseGain, 0.0f, 0.0f, 0.0f, delayFeedbackCrossGain, delayFeedbackCrossGain,
|
Matrix6x6 delayFeedback = new Matrix6x6(delayFeedbackBaseGain, 0.0f, delayFeedbackCrossGain, 0.0f, delayFeedbackCrossGain, 0.0f,
|
||||||
0.0f, delayFeedbackBaseGain, 0.0f, delayFeedbackCrossGain, delayFeedbackCrossGain, 0.0f,
|
0.0f, delayFeedbackBaseGain, delayFeedbackCrossGain, 0.0f, 0.0f, delayFeedbackCrossGain,
|
||||||
delayFeedbackCrossGain, 0.0f, delayFeedbackBaseGain, delayFeedbackCrossGain, 0.0f, 0.0f,
|
delayFeedbackCrossGain, delayFeedbackCrossGain, delayFeedbackBaseGain, 0.0f, 0.0f, 0.0f,
|
||||||
0.0f, delayFeedbackCrossGain, delayFeedbackCrossGain, delayFeedbackBaseGain, 0.0f, 0.0f,
|
0.0f, 0.0f, 0.0f, feedbackGain, 0.0f, 0.0f,
|
||||||
delayFeedbackCrossGain, delayFeedbackCrossGain, 0.0f, 0.0f, delayFeedbackBaseGain, 0.0f,
|
delayFeedbackCrossGain, 0.0f, 0.0f, 0.0f, delayFeedbackBaseGain, delayFeedbackCrossGain,
|
||||||
0.0f, 0.0f, 0.0f, 0.0f, 0.0f, feedbackGain);
|
0.0f, delayFeedbackCrossGain, 0.0f, 0.0f, delayFeedbackCrossGain, delayFeedbackBaseGain);
|
||||||
|
|
||||||
for (int i = 0; i < sampleCount; i++)
|
for (int i = 0; i < sampleCount; i++)
|
||||||
{
|
{
|
||||||
@ -200,7 +200,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
|||||||
U = state.DelayLines[5].Read()
|
U = state.DelayLines[5].Read()
|
||||||
};
|
};
|
||||||
|
|
||||||
Vector6 temp = MatrixHelper.Transform(ref channelInput, ref delayFeedback) + channelInput * inGain;
|
Vector6 temp = MatrixHelper.Transform(ref delayLineValues, ref delayFeedback) + channelInput * inGain;
|
||||||
|
|
||||||
state.UpdateLowPassFilter(ref Unsafe.As<Vector6, float>(ref temp), channelCount);
|
state.UpdateLowPassFilter(ref Unsafe.As<Vector6, float>(ref temp), channelCount);
|
||||||
|
|
||||||
|
@ -11,7 +11,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
|||||||
|
|
||||||
public CommandType CommandType => CommandType.DepopForMixBuffers;
|
public CommandType CommandType => CommandType.DepopForMixBuffers;
|
||||||
|
|
||||||
public ulong EstimatedProcessingTime { get; set; }
|
public uint EstimatedProcessingTime { get; set; }
|
||||||
|
|
||||||
public uint MixBufferOffset { get; }
|
public uint MixBufferOffset { get; }
|
||||||
|
|
||||||
|
@ -11,7 +11,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
|||||||
|
|
||||||
public CommandType CommandType => CommandType.DepopPrepare;
|
public CommandType CommandType => CommandType.DepopPrepare;
|
||||||
|
|
||||||
public ulong EstimatedProcessingTime { get; set; }
|
public uint EstimatedProcessingTime { get; set; }
|
||||||
|
|
||||||
public uint MixBufferCount { get; }
|
public uint MixBufferCount { get; }
|
||||||
|
|
||||||
|
@ -14,7 +14,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
|||||||
|
|
||||||
public CommandType CommandType => CommandType.DeviceSink;
|
public CommandType CommandType => CommandType.DeviceSink;
|
||||||
|
|
||||||
public ulong EstimatedProcessingTime { get; set; }
|
public uint EstimatedProcessingTime { get; set; }
|
||||||
|
|
||||||
public string DeviceName { get; }
|
public string DeviceName { get; }
|
||||||
|
|
||||||
|
@ -11,7 +11,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
|||||||
|
|
||||||
public CommandType CommandType => CommandType.DownMixSurroundToStereo;
|
public CommandType CommandType => CommandType.DownMixSurroundToStereo;
|
||||||
|
|
||||||
public ulong EstimatedProcessingTime { get; set; }
|
public uint EstimatedProcessingTime { get; set; }
|
||||||
|
|
||||||
public ushort[] InputBufferIndices { get; }
|
public ushort[] InputBufferIndices { get; }
|
||||||
public ushort[] OutputBufferIndices { get; }
|
public ushort[] OutputBufferIndices { get; }
|
||||||
|
@ -12,7 +12,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
|||||||
|
|
||||||
public CommandType CommandType => CommandType.GroupedBiquadFilter;
|
public CommandType CommandType => CommandType.GroupedBiquadFilter;
|
||||||
|
|
||||||
public ulong EstimatedProcessingTime { get; set; }
|
public uint EstimatedProcessingTime { get; set; }
|
||||||
|
|
||||||
private BiquadFilterParameter[] _parameters;
|
private BiquadFilterParameter[] _parameters;
|
||||||
private Memory<BiquadFilterState> _biquadFilterStates;
|
private Memory<BiquadFilterState> _biquadFilterStates;
|
||||||
@ -47,9 +47,8 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE: Nintendo also implements a hot path for double biquad filters, but no generic path when the command definition suggests it could be done.
|
// NOTE: Nintendo only implement single and double biquad filters but no generic path when the command definition suggests it could be done.
|
||||||
// As such we currently only implement a generic path for simplicity.
|
// As such we currently only implement a generic path for simplicity for double biquad.
|
||||||
// TODO: Implement double biquad filters fast path.
|
|
||||||
if (_parameters.Length == 1)
|
if (_parameters.Length == 1)
|
||||||
{
|
{
|
||||||
BiquadFilterHelper.ProcessBiquadFilter(ref _parameters[0], ref states[0], outputBuffer, inputBuffer, context.SampleCount);
|
BiquadFilterHelper.ProcessBiquadFilter(ref _parameters[0], ref states[0], outputBuffer, inputBuffer, context.SampleCount);
|
||||||
|
@ -8,7 +8,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
|||||||
|
|
||||||
public CommandType CommandType { get; }
|
public CommandType CommandType { get; }
|
||||||
|
|
||||||
public ulong EstimatedProcessingTime { get; }
|
public uint EstimatedProcessingTime { get; }
|
||||||
|
|
||||||
public void Process(CommandList context);
|
public void Process(CommandList context);
|
||||||
|
|
||||||
|
@ -13,7 +13,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
|||||||
|
|
||||||
public CommandType CommandType => CommandType.LimiterVersion1;
|
public CommandType CommandType => CommandType.LimiterVersion1;
|
||||||
|
|
||||||
public ulong EstimatedProcessingTime { get; set; }
|
public uint EstimatedProcessingTime { get; set; }
|
||||||
|
|
||||||
public LimiterParameter Parameter => _parameter;
|
public LimiterParameter Parameter => _parameter;
|
||||||
public Memory<LimiterState> State { get; }
|
public Memory<LimiterState> State { get; }
|
||||||
|
@ -15,7 +15,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
|||||||
|
|
||||||
public CommandType CommandType => CommandType.LimiterVersion2;
|
public CommandType CommandType => CommandType.LimiterVersion2;
|
||||||
|
|
||||||
public ulong EstimatedProcessingTime { get; set; }
|
public uint EstimatedProcessingTime { get; set; }
|
||||||
|
|
||||||
public LimiterParameter Parameter => _parameter;
|
public LimiterParameter Parameter => _parameter;
|
||||||
public Memory<LimiterState> State { get; }
|
public Memory<LimiterState> State { get; }
|
||||||
|
@ -15,7 +15,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
|||||||
|
|
||||||
public CommandType CommandType => CommandType.Mix;
|
public CommandType CommandType => CommandType.Mix;
|
||||||
|
|
||||||
public ulong EstimatedProcessingTime { get; set; }
|
public uint EstimatedProcessingTime { get; set; }
|
||||||
|
|
||||||
public ushort InputBufferIndex { get; }
|
public ushort InputBufferIndex { get; }
|
||||||
public ushort OutputBufferIndex { get; }
|
public ushort OutputBufferIndex { get; }
|
||||||
|
@ -12,7 +12,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
|||||||
|
|
||||||
public CommandType CommandType => CommandType.MixRamp;
|
public CommandType CommandType => CommandType.MixRamp;
|
||||||
|
|
||||||
public ulong EstimatedProcessingTime { get; set; }
|
public uint EstimatedProcessingTime { get; set; }
|
||||||
|
|
||||||
public ushort InputBufferIndex { get; }
|
public ushort InputBufferIndex { get; }
|
||||||
public ushort OutputBufferIndex { get; }
|
public ushort OutputBufferIndex { get; }
|
||||||
|
@ -12,7 +12,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
|||||||
|
|
||||||
public CommandType CommandType => CommandType.MixRampGrouped;
|
public CommandType CommandType => CommandType.MixRampGrouped;
|
||||||
|
|
||||||
public ulong EstimatedProcessingTime { get; set; }
|
public uint EstimatedProcessingTime { get; set; }
|
||||||
|
|
||||||
public uint MixBufferCount { get; }
|
public uint MixBufferCount { get; }
|
||||||
|
|
||||||
|
@ -13,7 +13,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
|||||||
|
|
||||||
public CommandType CommandType => CommandType.PcmFloatDataSourceVersion1;
|
public CommandType CommandType => CommandType.PcmFloatDataSourceVersion1;
|
||||||
|
|
||||||
public ulong EstimatedProcessingTime { get; set; }
|
public uint EstimatedProcessingTime { get; set; }
|
||||||
|
|
||||||
public ushort OutputBufferIndex { get; }
|
public ushort OutputBufferIndex { get; }
|
||||||
public uint SampleRate { get; }
|
public uint SampleRate { get; }
|
||||||
|
@ -13,7 +13,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
|||||||
|
|
||||||
public CommandType CommandType => CommandType.PcmInt16DataSourceVersion1;
|
public CommandType CommandType => CommandType.PcmInt16DataSourceVersion1;
|
||||||
|
|
||||||
public ulong EstimatedProcessingTime { get; set; }
|
public uint EstimatedProcessingTime { get; set; }
|
||||||
|
|
||||||
public ushort OutputBufferIndex { get; }
|
public ushort OutputBufferIndex { get; }
|
||||||
public uint SampleRate { get; }
|
public uint SampleRate { get; }
|
||||||
|
@ -17,7 +17,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
|||||||
|
|
||||||
public CommandType CommandType => CommandType.Performance;
|
public CommandType CommandType => CommandType.Performance;
|
||||||
|
|
||||||
public ulong EstimatedProcessingTime { get; set; }
|
public uint EstimatedProcessingTime { get; set; }
|
||||||
|
|
||||||
public PerformanceEntryAddresses PerformanceEntryAddresses { get; }
|
public PerformanceEntryAddresses PerformanceEntryAddresses { get; }
|
||||||
|
|
||||||
|
@ -31,7 +31,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
|||||||
|
|
||||||
public CommandType CommandType => CommandType.Reverb3d;
|
public CommandType CommandType => CommandType.Reverb3d;
|
||||||
|
|
||||||
public ulong EstimatedProcessingTime { get; set; }
|
public uint EstimatedProcessingTime { get; set; }
|
||||||
|
|
||||||
public ushort InputBufferIndex { get; }
|
public ushort InputBufferIndex { get; }
|
||||||
public ushort OutputBufferIndex { get; }
|
public ushort OutputBufferIndex { get; }
|
||||||
|
@ -34,7 +34,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
|||||||
|
|
||||||
public CommandType CommandType => CommandType.Reverb;
|
public CommandType CommandType => CommandType.Reverb;
|
||||||
|
|
||||||
public ulong EstimatedProcessingTime { get; set; }
|
public uint EstimatedProcessingTime { get; set; }
|
||||||
|
|
||||||
public ReverbParameter Parameter => _parameter;
|
public ReverbParameter Parameter => _parameter;
|
||||||
public Memory<ReverbState> State { get; }
|
public Memory<ReverbState> State { get; }
|
||||||
|
@ -11,7 +11,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
|||||||
|
|
||||||
public CommandType CommandType => CommandType.Upsample;
|
public CommandType CommandType => CommandType.Upsample;
|
||||||
|
|
||||||
public ulong EstimatedProcessingTime { get; set; }
|
public uint EstimatedProcessingTime { get; set; }
|
||||||
|
|
||||||
public uint BufferCount { get; }
|
public uint BufferCount { get; }
|
||||||
public uint InputBufferIndex { get; }
|
public uint InputBufferIndex { get; }
|
||||||
|
@ -15,7 +15,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
|||||||
|
|
||||||
public CommandType CommandType => CommandType.Volume;
|
public CommandType CommandType => CommandType.Volume;
|
||||||
|
|
||||||
public ulong EstimatedProcessingTime { get; set; }
|
public uint EstimatedProcessingTime { get; set; }
|
||||||
|
|
||||||
public ushort InputBufferIndex { get; }
|
public ushort InputBufferIndex { get; }
|
||||||
public ushort OutputBufferIndex { get; }
|
public ushort OutputBufferIndex { get; }
|
||||||
|
@ -11,7 +11,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
|||||||
|
|
||||||
public CommandType CommandType => CommandType.VolumeRamp;
|
public CommandType CommandType => CommandType.VolumeRamp;
|
||||||
|
|
||||||
public ulong EstimatedProcessingTime { get; set; }
|
public uint EstimatedProcessingTime { get; set; }
|
||||||
|
|
||||||
public ushort InputBufferIndex { get; }
|
public ushort InputBufferIndex { get; }
|
||||||
public ushort OutputBufferIndex { get; }
|
public ushort OutputBufferIndex { get; }
|
||||||
|
@ -28,6 +28,7 @@ namespace Ryujinx.Audio.Renderer.Server
|
|||||||
{
|
{
|
||||||
private object _lock = new object();
|
private object _lock = new object();
|
||||||
|
|
||||||
|
private AudioRendererRenderingDevice _renderingDevice;
|
||||||
private AudioRendererExecutionMode _executionMode;
|
private AudioRendererExecutionMode _executionMode;
|
||||||
private IWritableEvent _systemEvent;
|
private IWritableEvent _systemEvent;
|
||||||
private ManualResetEvent _terminationEvent;
|
private ManualResetEvent _terminationEvent;
|
||||||
@ -63,6 +64,7 @@ namespace Ryujinx.Audio.Renderer.Server
|
|||||||
private uint _renderingTimeLimitPercent;
|
private uint _renderingTimeLimitPercent;
|
||||||
private bool _voiceDropEnabled;
|
private bool _voiceDropEnabled;
|
||||||
private uint _voiceDropCount;
|
private uint _voiceDropCount;
|
||||||
|
private float _voiceDropParameter;
|
||||||
private bool _isDspRunningBehind;
|
private bool _isDspRunningBehind;
|
||||||
|
|
||||||
private ICommandProcessingTimeEstimator _commandProcessingTimeEstimator;
|
private ICommandProcessingTimeEstimator _commandProcessingTimeEstimator;
|
||||||
@ -95,6 +97,7 @@ namespace Ryujinx.Audio.Renderer.Server
|
|||||||
|
|
||||||
_totalElapsedTicksUpdating = 0;
|
_totalElapsedTicksUpdating = 0;
|
||||||
_sessionId = 0;
|
_sessionId = 0;
|
||||||
|
_voiceDropParameter = 1.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ResultCode Initialize(
|
public ResultCode Initialize(
|
||||||
@ -130,6 +133,7 @@ namespace Ryujinx.Audio.Renderer.Server
|
|||||||
_upsamplerCount = parameter.SinkCount + parameter.SubMixBufferCount;
|
_upsamplerCount = parameter.SinkCount + parameter.SubMixBufferCount;
|
||||||
_appletResourceId = appletResourceId;
|
_appletResourceId = appletResourceId;
|
||||||
_memoryPoolCount = parameter.EffectCount + parameter.VoiceCount * Constants.VoiceWaveBufferCount;
|
_memoryPoolCount = parameter.EffectCount + parameter.VoiceCount * Constants.VoiceWaveBufferCount;
|
||||||
|
_renderingDevice = parameter.RenderingDevice;
|
||||||
_executionMode = parameter.ExecutionMode;
|
_executionMode = parameter.ExecutionMode;
|
||||||
_sessionId = sessionId;
|
_sessionId = sessionId;
|
||||||
MemoryManager = memoryManager;
|
MemoryManager = memoryManager;
|
||||||
@ -337,6 +341,7 @@ namespace Ryujinx.Audio.Renderer.Server
|
|||||||
|
|
||||||
_processHandle = processHandle;
|
_processHandle = processHandle;
|
||||||
_elapsedFrameCount = 0;
|
_elapsedFrameCount = 0;
|
||||||
|
_voiceDropParameter = 1.0f;
|
||||||
|
|
||||||
switch (_behaviourContext.GetCommandProcessingTimeEstimatorVersion())
|
switch (_behaviourContext.GetCommandProcessingTimeEstimatorVersion())
|
||||||
{
|
{
|
||||||
@ -515,7 +520,7 @@ namespace Ryujinx.Audio.Renderer.Server
|
|||||||
return (ulong)(_manager.TickSource.ElapsedSeconds * Constants.TargetTimerFrequency);
|
return (ulong)(_manager.TickSource.ElapsedSeconds * Constants.TargetTimerFrequency);
|
||||||
}
|
}
|
||||||
|
|
||||||
private uint ComputeVoiceDrop(CommandBuffer commandBuffer, long voicesEstimatedTime, long deltaTimeDsp)
|
private uint ComputeVoiceDrop(CommandBuffer commandBuffer, uint voicesEstimatedTime, long deltaTimeDsp)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
@ -584,7 +589,7 @@ namespace Ryujinx.Audio.Renderer.Server
|
|||||||
{
|
{
|
||||||
command.Enabled = false;
|
command.Enabled = false;
|
||||||
|
|
||||||
voicesEstimatedTime -= (long)command.EstimatedProcessingTime;
|
voicesEstimatedTime -= (uint)(_voiceDropParameter * command.EstimatedProcessingTime);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -618,13 +623,13 @@ namespace Ryujinx.Audio.Renderer.Server
|
|||||||
_voiceContext.Sort();
|
_voiceContext.Sort();
|
||||||
commandGenerator.GenerateVoices();
|
commandGenerator.GenerateVoices();
|
||||||
|
|
||||||
long voicesEstimatedTime = (long)commandBuffer.EstimatedProcessingTime;
|
uint voicesEstimatedTime = (uint)(_voiceDropParameter * commandBuffer.EstimatedProcessingTime);
|
||||||
|
|
||||||
commandGenerator.GenerateSubMixes();
|
commandGenerator.GenerateSubMixes();
|
||||||
commandGenerator.GenerateFinalMixes();
|
commandGenerator.GenerateFinalMixes();
|
||||||
commandGenerator.GenerateSinks();
|
commandGenerator.GenerateSinks();
|
||||||
|
|
||||||
long totalEstimatedTime = (long)commandBuffer.EstimatedProcessingTime;
|
uint totalEstimatedTime = (uint)(_voiceDropParameter * commandBuffer.EstimatedProcessingTime);
|
||||||
|
|
||||||
if (_voiceDropEnabled)
|
if (_voiceDropEnabled)
|
||||||
{
|
{
|
||||||
@ -665,14 +670,21 @@ namespace Ryujinx.Audio.Renderer.Server
|
|||||||
{
|
{
|
||||||
_terminationEvent.Reset();
|
_terminationEvent.Reset();
|
||||||
|
|
||||||
GenerateCommandList(out CommandList commands);
|
if (!_manager.Processor.HasRemainingCommands(_sessionId))
|
||||||
|
{
|
||||||
|
GenerateCommandList(out CommandList commands);
|
||||||
|
|
||||||
_manager.Processor.Send(_sessionId,
|
_manager.Processor.Send(_sessionId,
|
||||||
commands,
|
commands,
|
||||||
GetMaxAllocatedTimeForDsp(),
|
GetMaxAllocatedTimeForDsp(),
|
||||||
_appletResourceId);
|
_appletResourceId);
|
||||||
|
|
||||||
_systemEvent.Signal();
|
_systemEvent.Signal();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_isDspRunningBehind = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -856,5 +868,26 @@ namespace Ryujinx.Audio.Renderer.Server
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void SetVoiceDropParameter(float voiceDropParameter)
|
||||||
|
{
|
||||||
|
_voiceDropParameter = Math.Clamp(voiceDropParameter, 0.0f, 2.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
public float GetVoiceDropParameter()
|
||||||
|
{
|
||||||
|
return _voiceDropParameter;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ResultCode ExecuteAudioRendererRendering()
|
||||||
|
{
|
||||||
|
if (_executionMode == AudioRendererExecutionMode.Manual && _renderingDevice == AudioRendererRenderingDevice.Cpu)
|
||||||
|
{
|
||||||
|
// NOTE: Here Nintendo aborts with this error code, we don't want that.
|
||||||
|
return ResultCode.InvalidExecutionContextOperation;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ResultCode.UnsupportedOperation;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -94,8 +94,9 @@ namespace Ryujinx.Audio.Renderer.Server
|
|||||||
/// REV11:
|
/// REV11:
|
||||||
/// The "legacy" effects (Delay, Reverb and Reverb 3D) were updated to match the standard channel mapping used by the audio renderer.
|
/// The "legacy" effects (Delay, Reverb and Reverb 3D) were updated to match the standard channel mapping used by the audio renderer.
|
||||||
/// A new version of the command estimator was added to address timing changes caused by the legacy effects changes.
|
/// A new version of the command estimator was added to address timing changes caused by the legacy effects changes.
|
||||||
|
/// A voice drop parameter was added in 15.0.0: This allows an application to amplify or attenuate the estimated time of DSP commands.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <remarks>This was added in system update 14.0.0</remarks>
|
/// <remarks>This was added in system update 14.0.0 but some changes were made in 15.0.0</remarks>
|
||||||
public const int Revision11 = 11 << 24;
|
public const int Revision11 = 11 << 24;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -25,7 +25,7 @@ namespace Ryujinx.Audio.Renderer.Server
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// The estimated total processing time.
|
/// The estimated total processing time.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public ulong EstimatedProcessingTime { get; set; }
|
public uint EstimatedProcessingTime { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The command list that is populated by the <see cref="CommandBuffer"/>.
|
/// The command list that is populated by the <see cref="CommandBuffer"/>.
|
||||||
|
@ -263,12 +263,12 @@ namespace Ryujinx.Audio.Renderer.Server.MemoryPool
|
|||||||
return UpdateResult.Success;
|
return UpdateResult.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (inParameter.CpuAddress == 0 || (inParameter.CpuAddress & (pageSize - 1)) != 0)
|
if (inParameter.CpuAddress == 0 || (inParameter.CpuAddress % pageSize) != 0)
|
||||||
{
|
{
|
||||||
return UpdateResult.InvalidParameter;
|
return UpdateResult.InvalidParameter;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (inParameter.Size == 0 || (inParameter.Size & (pageSize - 1)) != 0)
|
if (inParameter.Size == 0 || (inParameter.Size % pageSize) != 0)
|
||||||
{
|
{
|
||||||
return UpdateResult.InvalidParameter;
|
return UpdateResult.InvalidParameter;
|
||||||
}
|
}
|
||||||
|
@ -17,5 +17,6 @@ namespace Ryujinx.Audio
|
|||||||
InvalidAddressInfo = (42 << ErrorCodeShift) | ModuleId,
|
InvalidAddressInfo = (42 << ErrorCodeShift) | ModuleId,
|
||||||
InvalidMixSorting = (43 << ErrorCodeShift) | ModuleId,
|
InvalidMixSorting = (43 << ErrorCodeShift) | ModuleId,
|
||||||
UnsupportedOperation = (513 << ErrorCodeShift) | ModuleId,
|
UnsupportedOperation = (513 << ErrorCodeShift) | ModuleId,
|
||||||
|
InvalidExecutionContextOperation = (514 << ErrorCodeShift) | ModuleId,
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -60,7 +60,7 @@ namespace Ryujinx.Ava
|
|||||||
|
|
||||||
private const float VolumeDelta = 0.05f;
|
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;
|
||||||
private readonly Stopwatch _chrono;
|
private readonly Stopwatch _chrono;
|
||||||
@ -349,7 +349,10 @@ namespace Ryujinx.Ava
|
|||||||
|
|
||||||
_isActive = false;
|
_isActive = false;
|
||||||
|
|
||||||
_renderingThread.Join();
|
if (_renderingThread.IsAlive)
|
||||||
|
{
|
||||||
|
_renderingThread.Join();
|
||||||
|
}
|
||||||
|
|
||||||
DisplaySleep.Restore();
|
DisplaySleep.Restore();
|
||||||
|
|
||||||
@ -378,7 +381,7 @@ namespace Ryujinx.Ava
|
|||||||
|
|
||||||
_gpuCancellationTokenSource.Cancel();
|
_gpuCancellationTokenSource.Cancel();
|
||||||
_gpuCancellationTokenSource.Dispose();
|
_gpuCancellationTokenSource.Dispose();
|
||||||
|
|
||||||
_chrono.Stop();
|
_chrono.Stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -393,7 +396,7 @@ namespace Ryujinx.Ava
|
|||||||
Renderer?.MakeCurrent();
|
Renderer?.MakeCurrent();
|
||||||
|
|
||||||
Device.DisposeGpu();
|
Device.DisposeGpu();
|
||||||
|
|
||||||
Renderer?.MakeCurrent(null);
|
Renderer?.MakeCurrent(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -417,7 +420,6 @@ namespace Ryujinx.Ava
|
|||||||
public async Task<bool> LoadGuestApplication()
|
public async Task<bool> LoadGuestApplication()
|
||||||
{
|
{
|
||||||
InitializeSwitchInstance();
|
InitializeSwitchInstance();
|
||||||
|
|
||||||
MainWindow.UpdateGraphicsConfig();
|
MainWindow.UpdateGraphicsConfig();
|
||||||
|
|
||||||
SystemVersion firmwareVersion = ContentManager.GetCurrentFirmwareVersion();
|
SystemVersion firmwareVersion = ContentManager.GetCurrentFirmwareVersion();
|
||||||
@ -428,17 +430,16 @@ namespace Ryujinx.Ava
|
|||||||
{
|
{
|
||||||
if (userError == UserError.NoFirmware)
|
if (userError == UserError.NoFirmware)
|
||||||
{
|
{
|
||||||
string message = string.Format(LocaleManager.Instance["DialogFirmwareInstallEmbeddedMessage"],
|
|
||||||
firmwareVersion.VersionString);
|
|
||||||
|
|
||||||
UserResult result = await ContentDialogHelper.CreateConfirmationDialog(
|
UserResult result = await ContentDialogHelper.CreateConfirmationDialog(
|
||||||
LocaleManager.Instance["DialogFirmwareNoFirmwareInstalledMessage"], message,
|
LocaleManager.Instance["DialogFirmwareNoFirmwareInstalledMessage"],
|
||||||
LocaleManager.Instance["InputDialogYes"], LocaleManager.Instance["InputDialogNo"], "");
|
string.Format(LocaleManager.Instance["DialogFirmwareInstallEmbeddedMessage"], firmwareVersion.VersionString),
|
||||||
|
LocaleManager.Instance["InputDialogYes"],
|
||||||
|
LocaleManager.Instance["InputDialogNo"],
|
||||||
|
"");
|
||||||
|
|
||||||
if (result != UserResult.Yes)
|
if (result != UserResult.Yes)
|
||||||
{
|
{
|
||||||
Dispatcher.UIThread.Post(async () => await
|
await UserErrorDialog.ShowUserErrorDialog(userError, _parent);
|
||||||
UserErrorDialog.ShowUserErrorDialog(userError, _parent));
|
|
||||||
Device.Dispose();
|
Device.Dispose();
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
@ -447,8 +448,7 @@ namespace Ryujinx.Ava
|
|||||||
|
|
||||||
if (!SetupValidator.TryFixStartApplication(ContentManager, ApplicationPath, userError, out _))
|
if (!SetupValidator.TryFixStartApplication(ContentManager, ApplicationPath, userError, out _))
|
||||||
{
|
{
|
||||||
Dispatcher.UIThread.Post(async () => await
|
await UserErrorDialog.ShowUserErrorDialog(userError, _parent);
|
||||||
UserErrorDialog.ShowUserErrorDialog(userError, _parent));
|
|
||||||
Device.Dispose();
|
Device.Dispose();
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
@ -461,11 +461,9 @@ namespace Ryujinx.Ava
|
|||||||
|
|
||||||
_parent.RefreshFirmwareStatus();
|
_parent.RefreshFirmwareStatus();
|
||||||
|
|
||||||
string message = string.Format(LocaleManager.Instance["DialogFirmwareInstallEmbeddedSuccessMessage"], firmwareVersion.VersionString);
|
|
||||||
|
|
||||||
await ContentDialogHelper.CreateInfoDialog(
|
await ContentDialogHelper.CreateInfoDialog(
|
||||||
string.Format(LocaleManager.Instance["DialogFirmwareInstalledMessage"], firmwareVersion.VersionString),
|
string.Format(LocaleManager.Instance["DialogFirmwareInstalledMessage"], firmwareVersion.VersionString),
|
||||||
message,
|
string.Format(LocaleManager.Instance["DialogFirmwareInstallEmbeddedSuccessMessage"], firmwareVersion.VersionString),
|
||||||
LocaleManager.Instance["InputDialogOk"],
|
LocaleManager.Instance["InputDialogOk"],
|
||||||
"",
|
"",
|
||||||
LocaleManager.Instance["RyujinxInfo"]);
|
LocaleManager.Instance["RyujinxInfo"]);
|
||||||
@ -473,9 +471,7 @@ namespace Ryujinx.Ava
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Dispatcher.UIThread.Post(async () => await
|
await UserErrorDialog.ShowUserErrorDialog(userError, _parent);
|
||||||
UserErrorDialog.ShowUserErrorDialog(userError, _parent));
|
|
||||||
|
|
||||||
Device.Dispose();
|
Device.Dispose();
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
@ -514,7 +510,7 @@ namespace Ryujinx.Ava
|
|||||||
}
|
}
|
||||||
else if (File.Exists(ApplicationPath))
|
else if (File.Exists(ApplicationPath))
|
||||||
{
|
{
|
||||||
switch (System.IO.Path.GetExtension(ApplicationPath).ToLowerInvariant())
|
switch (Path.GetExtension(ApplicationPath).ToLowerInvariant())
|
||||||
{
|
{
|
||||||
case ".xci":
|
case ".xci":
|
||||||
{
|
{
|
||||||
@ -602,7 +598,7 @@ namespace Ryujinx.Ava
|
|||||||
if (Renderer.IsVulkan)
|
if (Renderer.IsVulkan)
|
||||||
{
|
{
|
||||||
string preferredGpu = ConfigurationState.Instance.Graphics.PreferredGpu.Value;
|
string preferredGpu = ConfigurationState.Instance.Graphics.PreferredGpu.Value;
|
||||||
|
|
||||||
renderer = new VulkanRenderer(Renderer.CreateVulkanSurface, VulkanHelper.GetRequiredInstanceExtensions, preferredGpu);
|
renderer = new VulkanRenderer(Renderer.CreateVulkanSurface, VulkanHelper.GetRequiredInstanceExtensions, preferredGpu);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -168,6 +168,8 @@
|
|||||||
"SettingsTabInputDirectKeyboardAccess": "Direkter Tastaturzugriff",
|
"SettingsTabInputDirectKeyboardAccess": "Direkter Tastaturzugriff",
|
||||||
"SettingsButtonSave": "Speichern",
|
"SettingsButtonSave": "Speichern",
|
||||||
"SettingsButtonClose": "Schließen",
|
"SettingsButtonClose": "Schließen",
|
||||||
|
"SettingsButtonOk": "OK",
|
||||||
|
"SettingsButtonCancel": "Abbrechen",
|
||||||
"SettingsButtonApply": "Übernehmen",
|
"SettingsButtonApply": "Übernehmen",
|
||||||
"ControllerSettingsPlayer": "Spieler",
|
"ControllerSettingsPlayer": "Spieler",
|
||||||
"ControllerSettingsPlayer1": "Spieler 1",
|
"ControllerSettingsPlayer1": "Spieler 1",
|
||||||
|
@ -168,6 +168,8 @@
|
|||||||
"SettingsTabInputDirectKeyboardAccess": "Άμεση Πρόσβαση στο Πληκτρολόγιο",
|
"SettingsTabInputDirectKeyboardAccess": "Άμεση Πρόσβαση στο Πληκτρολόγιο",
|
||||||
"SettingsButtonSave": "Αποθήκευση",
|
"SettingsButtonSave": "Αποθήκευση",
|
||||||
"SettingsButtonClose": "Κλείσιμο",
|
"SettingsButtonClose": "Κλείσιμο",
|
||||||
|
"SettingsButtonOk": "OK",
|
||||||
|
"SettingsButtonCancel": "Ακύρωση",
|
||||||
"SettingsButtonApply": "Εφαρμογή",
|
"SettingsButtonApply": "Εφαρμογή",
|
||||||
"ControllerSettingsPlayer": "Παίχτης",
|
"ControllerSettingsPlayer": "Παίχτης",
|
||||||
"ControllerSettingsPlayer1": "Παίχτης 1",
|
"ControllerSettingsPlayer1": "Παίχτης 1",
|
||||||
|
@ -168,6 +168,8 @@
|
|||||||
"SettingsTabInputDirectKeyboardAccess": "Direct Keyboard Access",
|
"SettingsTabInputDirectKeyboardAccess": "Direct Keyboard Access",
|
||||||
"SettingsButtonSave": "Save",
|
"SettingsButtonSave": "Save",
|
||||||
"SettingsButtonClose": "Close",
|
"SettingsButtonClose": "Close",
|
||||||
|
"SettingsButtonOk": "OK",
|
||||||
|
"SettingsButtonCancel": "Cancel",
|
||||||
"SettingsButtonApply": "Apply",
|
"SettingsButtonApply": "Apply",
|
||||||
"ControllerSettingsPlayer": "Player",
|
"ControllerSettingsPlayer": "Player",
|
||||||
"ControllerSettingsPlayer1": "Player 1",
|
"ControllerSettingsPlayer1": "Player 1",
|
||||||
@ -410,6 +412,8 @@
|
|||||||
"DlcManagerTableHeadingContainerPathLabel": "Container Path",
|
"DlcManagerTableHeadingContainerPathLabel": "Container Path",
|
||||||
"DlcManagerTableHeadingFullPathLabel": "Full Path",
|
"DlcManagerTableHeadingFullPathLabel": "Full Path",
|
||||||
"DlcManagerRemoveAllButton": "Remove All",
|
"DlcManagerRemoveAllButton": "Remove All",
|
||||||
|
"DlcManagerEnableAllButton": "Enable All",
|
||||||
|
"DlcManagerDisableAllButton": "Disable All",
|
||||||
"MenuBarOptionsChangeLanguage": "Change Language",
|
"MenuBarOptionsChangeLanguage": "Change Language",
|
||||||
"CommonSort": "Sort",
|
"CommonSort": "Sort",
|
||||||
"CommonShowNames": "Show Names",
|
"CommonShowNames": "Show Names",
|
||||||
@ -562,12 +566,12 @@
|
|||||||
"Writable": "Writable",
|
"Writable": "Writable",
|
||||||
"SelectDlcDialogTitle": "Select DLC files",
|
"SelectDlcDialogTitle": "Select DLC files",
|
||||||
"SelectUpdateDialogTitle": "Select update files",
|
"SelectUpdateDialogTitle": "Select update files",
|
||||||
"UserProfileWindowTitle": "Manage User Profiles",
|
"UserProfileWindowTitle": "User Profiles Manager",
|
||||||
"CheatWindowTitle": "Manage Game Cheats",
|
"CheatWindowTitle": "Cheats Manager",
|
||||||
"DlcWindowTitle": "Manage Game DLC",
|
"DlcWindowTitle": "Downloadable Content Manager",
|
||||||
"UpdateWindowTitle": "Manage Game Updates",
|
"UpdateWindowTitle": "Title Update Manager",
|
||||||
"CheatWindowHeading": "Cheats Available for {0} [{1}]",
|
"CheatWindowHeading": "Cheats Available for {0} [{1}]",
|
||||||
"DlcWindowHeading": "DLC Available for {0} [{1}]",
|
"DlcWindowHeading": "{0} Downloadable Content(s) available for {1} ({2})",
|
||||||
"UserProfilesEditProfile": "Edit Selected",
|
"UserProfilesEditProfile": "Edit Selected",
|
||||||
"Cancel": "Cancel",
|
"Cancel": "Cancel",
|
||||||
"Save": "Save",
|
"Save": "Save",
|
||||||
@ -575,7 +579,7 @@
|
|||||||
"UserProfilesSetProfileImage": "Set Profile Image",
|
"UserProfilesSetProfileImage": "Set Profile Image",
|
||||||
"UserProfileEmptyNameError": "Name is required",
|
"UserProfileEmptyNameError": "Name is required",
|
||||||
"UserProfileNoImageError": "Profile image must be set",
|
"UserProfileNoImageError": "Profile image must be set",
|
||||||
"GameUpdateWindowHeading": "Updates Available for {0} [{1}]",
|
"GameUpdateWindowHeading": "{0} Update(s) available for {1} ({2})",
|
||||||
"SettingsTabHotkeysResScaleUpHotkey": "Increase resolution:",
|
"SettingsTabHotkeysResScaleUpHotkey": "Increase resolution:",
|
||||||
"SettingsTabHotkeysResScaleDownHotkey": "Decrease resolution:",
|
"SettingsTabHotkeysResScaleDownHotkey": "Decrease resolution:",
|
||||||
"UserProfilesName": "Name:",
|
"UserProfilesName": "Name:",
|
||||||
@ -592,7 +596,18 @@
|
|||||||
"RyujinxUpdaterMessage": "Do you want to update Ryujinx to the latest version?",
|
"RyujinxUpdaterMessage": "Do you want to update Ryujinx to the latest version?",
|
||||||
"SettingsTabHotkeysVolumeUpHotkey": "Increase Volume:",
|
"SettingsTabHotkeysVolumeUpHotkey": "Increase Volume:",
|
||||||
"SettingsTabHotkeysVolumeDownHotkey": "Decrease Volume:",
|
"SettingsTabHotkeysVolumeDownHotkey": "Decrease Volume:",
|
||||||
"VolumeShort": "Vol",
|
|
||||||
"SettingsEnableMacroHLE": "Enable Macro HLE",
|
"SettingsEnableMacroHLE": "Enable Macro HLE",
|
||||||
"SettingsEnableMacroHLETooltip": "High-level emulation of GPU Macro code.\n\nImproves performance, but may cause graphical glitches in some games.\n\nLeave ON if unsure."
|
"SettingsEnableMacroHLETooltip": "High-level emulation of GPU Macro code.\n\nImproves performance, but may cause graphical glitches in some games.\n\nLeave ON if unsure.",
|
||||||
|
"VolumeShort": "Vol",
|
||||||
|
"UserProfilesManageSaves": "Manage Saves",
|
||||||
|
"DeleteUserSave": "Do you want to delete user save for this game?",
|
||||||
|
"IrreversibleActionNote": "This action is not reversible.",
|
||||||
|
"SaveManagerHeading": "Manage Saves for {0}",
|
||||||
|
"SaveManagerTitle": "Save Manager",
|
||||||
|
"Name": "Name",
|
||||||
|
"Size": "Size",
|
||||||
|
"Search": "Search",
|
||||||
|
"UserProfilesRecoverLostAccounts": "Recover Lost Accounts",
|
||||||
|
"Recover": "Recover",
|
||||||
|
"UserProfilesRecoverHeading" : "Saves were found for the following accounts"
|
||||||
}
|
}
|
||||||
|
@ -168,6 +168,8 @@
|
|||||||
"SettingsTabInputDirectKeyboardAccess": "Acceso directo al teclado",
|
"SettingsTabInputDirectKeyboardAccess": "Acceso directo al teclado",
|
||||||
"SettingsButtonSave": "Guardar",
|
"SettingsButtonSave": "Guardar",
|
||||||
"SettingsButtonClose": "Cerrar",
|
"SettingsButtonClose": "Cerrar",
|
||||||
|
"SettingsButtonOk": "OK",
|
||||||
|
"SettingsButtonCancel": "Cancelar",
|
||||||
"SettingsButtonApply": "Aplicar",
|
"SettingsButtonApply": "Aplicar",
|
||||||
"ControllerSettingsPlayer": "Jugador",
|
"ControllerSettingsPlayer": "Jugador",
|
||||||
"ControllerSettingsPlayer1": "Jugador 1",
|
"ControllerSettingsPlayer1": "Jugador 1",
|
||||||
|
@ -161,6 +161,8 @@
|
|||||||
"SettingsTabInputDirectKeyboardAccess": "Accès direct au clavier",
|
"SettingsTabInputDirectKeyboardAccess": "Accès direct au clavier",
|
||||||
"SettingsButtonSave": "Enregistrer",
|
"SettingsButtonSave": "Enregistrer",
|
||||||
"SettingsButtonClose": "Fermer",
|
"SettingsButtonClose": "Fermer",
|
||||||
|
"SettingsButtonOk": "OK",
|
||||||
|
"SettingsButtonCancel": "Annuler",
|
||||||
"SettingsButtonApply": "Appliquer",
|
"SettingsButtonApply": "Appliquer",
|
||||||
"ControllerSettingsPlayer": "Joueur",
|
"ControllerSettingsPlayer": "Joueur",
|
||||||
"ControllerSettingsPlayer1": "Joueur 1",
|
"ControllerSettingsPlayer1": "Joueur 1",
|
||||||
|
@ -168,6 +168,8 @@
|
|||||||
"SettingsTabInputDirectKeyboardAccess": "Accesso diretto alla tastiera",
|
"SettingsTabInputDirectKeyboardAccess": "Accesso diretto alla tastiera",
|
||||||
"SettingsButtonSave": "Salva",
|
"SettingsButtonSave": "Salva",
|
||||||
"SettingsButtonClose": "Chiudi",
|
"SettingsButtonClose": "Chiudi",
|
||||||
|
"SettingsButtonOk": "OK",
|
||||||
|
"SettingsButtonCancel": "Cancella",
|
||||||
"SettingsButtonApply": "Applica",
|
"SettingsButtonApply": "Applica",
|
||||||
"ControllerSettingsPlayer": "Giocatore",
|
"ControllerSettingsPlayer": "Giocatore",
|
||||||
"ControllerSettingsPlayer1": "Giocatore 1",
|
"ControllerSettingsPlayer1": "Giocatore 1",
|
||||||
|
@ -168,6 +168,8 @@
|
|||||||
"SettingsTabInputDirectKeyboardAccess": "キーボード直接アクセス",
|
"SettingsTabInputDirectKeyboardAccess": "キーボード直接アクセス",
|
||||||
"SettingsButtonSave": "セーブ",
|
"SettingsButtonSave": "セーブ",
|
||||||
"SettingsButtonClose": "閉じる",
|
"SettingsButtonClose": "閉じる",
|
||||||
|
"SettingsButtonOk": "オーケー",
|
||||||
|
"SettingsButtonCancel": "キャンセル",
|
||||||
"SettingsButtonApply": "適用",
|
"SettingsButtonApply": "適用",
|
||||||
"ControllerSettingsPlayer": "プレイヤー",
|
"ControllerSettingsPlayer": "プレイヤー",
|
||||||
"ControllerSettingsPlayer1": "プレイヤー 1",
|
"ControllerSettingsPlayer1": "プレイヤー 1",
|
||||||
|
@ -167,6 +167,8 @@
|
|||||||
"SettingsTabInputDirectKeyboardAccess": "직접 키보드 액세스",
|
"SettingsTabInputDirectKeyboardAccess": "직접 키보드 액세스",
|
||||||
"SettingsButtonSave": "구하다",
|
"SettingsButtonSave": "구하다",
|
||||||
"SettingsButtonClose": "출구",
|
"SettingsButtonClose": "출구",
|
||||||
|
"SettingsButtonOk": "좋아",
|
||||||
|
"SettingsButtonCancel": "취소",
|
||||||
"SettingsButtonApply": "적용하다",
|
"SettingsButtonApply": "적용하다",
|
||||||
"ControllerSettingsPlayer": "플레이어",
|
"ControllerSettingsPlayer": "플레이어",
|
||||||
"ControllerSettingsPlayer1": "플레이어 1",
|
"ControllerSettingsPlayer1": "플레이어 1",
|
||||||
|
@ -168,6 +168,8 @@
|
|||||||
"SettingsTabInputDirectKeyboardAccess": "Bezpośredni Dostęp do Klawiatury",
|
"SettingsTabInputDirectKeyboardAccess": "Bezpośredni Dostęp do Klawiatury",
|
||||||
"SettingsButtonSave": "Zapisz",
|
"SettingsButtonSave": "Zapisz",
|
||||||
"SettingsButtonClose": "Zamknij",
|
"SettingsButtonClose": "Zamknij",
|
||||||
|
"SettingsButtonOk": "OK",
|
||||||
|
"SettingsButtonCancel": "Anuluj",
|
||||||
"SettingsButtonApply": "Zastosuj",
|
"SettingsButtonApply": "Zastosuj",
|
||||||
"ControllerSettingsPlayer": "Gracz",
|
"ControllerSettingsPlayer": "Gracz",
|
||||||
"ControllerSettingsPlayer1": "Gracz 1",
|
"ControllerSettingsPlayer1": "Gracz 1",
|
||||||
|
@ -168,6 +168,8 @@
|
|||||||
"SettingsTabInputDirectKeyboardAccess": "Acesso direto ao teclado",
|
"SettingsTabInputDirectKeyboardAccess": "Acesso direto ao teclado",
|
||||||
"SettingsButtonSave": "Salvar",
|
"SettingsButtonSave": "Salvar",
|
||||||
"SettingsButtonClose": "Fechar",
|
"SettingsButtonClose": "Fechar",
|
||||||
|
"SettingsButtonOk": "OK",
|
||||||
|
"SettingsButtonCancel": "Cancelar",
|
||||||
"SettingsButtonApply": "Aplicar",
|
"SettingsButtonApply": "Aplicar",
|
||||||
"ControllerSettingsPlayer": "Jogador",
|
"ControllerSettingsPlayer": "Jogador",
|
||||||
"ControllerSettingsPlayer1": "Jogador 1",
|
"ControllerSettingsPlayer1": "Jogador 1",
|
||||||
|
@ -167,6 +167,8 @@
|
|||||||
"SettingsTabInputDirectKeyboardAccess": "Прямой доступ с клавиатуры",
|
"SettingsTabInputDirectKeyboardAccess": "Прямой доступ с клавиатуры",
|
||||||
"SettingsButtonSave": "Сохранить",
|
"SettingsButtonSave": "Сохранить",
|
||||||
"SettingsButtonClose": "Закрыть",
|
"SettingsButtonClose": "Закрыть",
|
||||||
|
"SettingsButtonOk": "OK",
|
||||||
|
"SettingsButtonCancel": "Отмена",
|
||||||
"SettingsButtonApply": "Применить",
|
"SettingsButtonApply": "Применить",
|
||||||
"ControllerSettingsPlayer": "Игрок",
|
"ControllerSettingsPlayer": "Игрок",
|
||||||
"ControllerSettingsPlayer1": "Игрок 1",
|
"ControllerSettingsPlayer1": "Игрок 1",
|
||||||
|
@ -168,6 +168,8 @@
|
|||||||
"SettingsTabInputDirectKeyboardAccess": "Doğrudan Klavye Erişimi",
|
"SettingsTabInputDirectKeyboardAccess": "Doğrudan Klavye Erişimi",
|
||||||
"SettingsButtonSave": "Kaydet",
|
"SettingsButtonSave": "Kaydet",
|
||||||
"SettingsButtonClose": "Kapat",
|
"SettingsButtonClose": "Kapat",
|
||||||
|
"SettingsButtonOk": "Tamam",
|
||||||
|
"SettingsButtonCancel": "İptal",
|
||||||
"SettingsButtonApply": "Uygula",
|
"SettingsButtonApply": "Uygula",
|
||||||
"ControllerSettingsPlayer": "Oyuncu",
|
"ControllerSettingsPlayer": "Oyuncu",
|
||||||
"ControllerSettingsPlayer1": "Oyuncu 1",
|
"ControllerSettingsPlayer1": "Oyuncu 1",
|
||||||
|
@ -168,6 +168,8 @@
|
|||||||
"SettingsTabInputDirectKeyboardAccess": "直通键盘控制",
|
"SettingsTabInputDirectKeyboardAccess": "直通键盘控制",
|
||||||
"SettingsButtonSave": "保存",
|
"SettingsButtonSave": "保存",
|
||||||
"SettingsButtonClose": "关闭",
|
"SettingsButtonClose": "关闭",
|
||||||
|
"SettingsButtonOk": "批准",
|
||||||
|
"SettingsButtonCancel": "取消",
|
||||||
"SettingsButtonApply": "应用",
|
"SettingsButtonApply": "应用",
|
||||||
"ControllerSettingsPlayer": "玩家",
|
"ControllerSettingsPlayer": "玩家",
|
||||||
"ControllerSettingsPlayer1": "玩家 1",
|
"ControllerSettingsPlayer1": "玩家 1",
|
||||||
|
@ -168,6 +168,8 @@
|
|||||||
"SettingsTabInputDirectKeyboardAccess": "直通鍵盤控制",
|
"SettingsTabInputDirectKeyboardAccess": "直通鍵盤控制",
|
||||||
"SettingsButtonSave": "儲存",
|
"SettingsButtonSave": "儲存",
|
||||||
"SettingsButtonClose": "關閉",
|
"SettingsButtonClose": "關閉",
|
||||||
|
"SettingsButtonOk": "嘛好",
|
||||||
|
"SettingsButtonCancel": "取消",
|
||||||
"SettingsButtonApply": "套用",
|
"SettingsButtonApply": "套用",
|
||||||
"ControllerSettingsPlayer": "玩家",
|
"ControllerSettingsPlayer": "玩家",
|
||||||
"ControllerSettingsPlayer1": "玩家 1",
|
"ControllerSettingsPlayer1": "玩家 1",
|
||||||
|
@ -41,6 +41,9 @@
|
|||||||
<SolidColorBrush x:Key="DataGridSelectionBackgroundBrush" Color="{DynamicResource DataGridSelectionColor}" />
|
<SolidColorBrush x:Key="DataGridSelectionBackgroundBrush" Color="{DynamicResource DataGridSelectionColor}" />
|
||||||
<SolidColorBrush x:Key="ThemeAccentColorBrush" Color="{DynamicResource SystemAccentColor}" />
|
<SolidColorBrush x:Key="ThemeAccentColorBrush" Color="{DynamicResource SystemAccentColor}" />
|
||||||
<SolidColorBrush x:Key="ThemeAccentBrush4" Color="{DynamicResource ThemeAccentColor4}" />
|
<SolidColorBrush x:Key="ThemeAccentBrush4" Color="{DynamicResource ThemeAccentColor4}" />
|
||||||
|
<Color x:Key="ControlFillColorSecondary">#008AA8</Color>
|
||||||
|
<SolidColorBrush x:Key="ControlFillColorSecondaryBrush" Color="{StaticResource ControlFillColorSecondary}" />
|
||||||
|
<StaticResource x:Key="ButtonBackgroundPointerOver" ResourceKey="ControlFillColorSecondaryBrush" />
|
||||||
<Color x:Key="SystemAccentColor">#FF00C3E3</Color>
|
<Color x:Key="SystemAccentColor">#FF00C3E3</Color>
|
||||||
<Color x:Key="SystemAccentColorDark1">#FF99b000</Color>
|
<Color x:Key="SystemAccentColorDark1">#FF99b000</Color>
|
||||||
<Color x:Key="SystemAccentColorDark2">#FF006d7d</Color>
|
<Color x:Key="SystemAccentColorDark2">#FF006d7d</Color>
|
||||||
@ -55,5 +58,7 @@
|
|||||||
<Color x:Key="SystemChromeWhiteColor">#FFFFFFFF</Color>
|
<Color x:Key="SystemChromeWhiteColor">#FFFFFFFF</Color>
|
||||||
<Color x:Key="ThemeForegroundColor">#FFFFFFFF</Color>
|
<Color x:Key="ThemeForegroundColor">#FFFFFFFF</Color>
|
||||||
<Color x:Key="MenuFlyoutPresenterBorderColor">#3D3D3D</Color>
|
<Color x:Key="MenuFlyoutPresenterBorderColor">#3D3D3D</Color>
|
||||||
|
<Color x:Key="AppListBackgroundColor">#0FFFFFFF</Color>
|
||||||
|
<Color x:Key="AppListHoverBackgroundColor">#1EFFFFFF</Color>
|
||||||
</Styles.Resources>
|
</Styles.Resources>
|
||||||
</Styles>
|
</Styles>
|
@ -50,5 +50,7 @@
|
|||||||
<Color x:Key="SystemChromeWhiteColor">#FFFFFFFF</Color>
|
<Color x:Key="SystemChromeWhiteColor">#FFFFFFFF</Color>
|
||||||
<Color x:Key="ThemeForegroundColor">#FF000000</Color>
|
<Color x:Key="ThemeForegroundColor">#FF000000</Color>
|
||||||
<Color x:Key="MenuFlyoutPresenterBorderColor">#C1C1C1</Color>
|
<Color x:Key="MenuFlyoutPresenterBorderColor">#C1C1C1</Color>
|
||||||
|
<Color x:Key="AppListBackgroundColor">#b3ffffff</Color>
|
||||||
|
<Color x:Key="AppListHoverBackgroundColor">#80cccccc</Color>
|
||||||
</Styles.Resources>
|
</Styles.Resources>
|
||||||
</Styles>
|
</Styles>
|
@ -1,7 +1,6 @@
|
|||||||
<Styles
|
<Styles
|
||||||
xmlns="https://github.com/avaloniaui"
|
xmlns="https://github.com/avaloniaui"
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
xmlns:sys="clr-namespace:System;assembly=netstandard"
|
|
||||||
xmlns:ui="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia">
|
xmlns:ui="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia">
|
||||||
<Design.PreviewWith>
|
<Design.PreviewWith>
|
||||||
<Border Height="2000" Padding="20">
|
<Border Height="2000" Padding="20">
|
||||||
@ -269,13 +268,15 @@
|
|||||||
<Color x:Key="DataGridSelectionColor">#FF00FABB</Color>
|
<Color x:Key="DataGridSelectionColor">#FF00FABB</Color>
|
||||||
<Color x:Key="ThemeContentBackgroundColor">#FF2D2D2D</Color>
|
<Color x:Key="ThemeContentBackgroundColor">#FF2D2D2D</Color>
|
||||||
<Color x:Key="ThemeControlBorderColor">#FF505050</Color>
|
<Color x:Key="ThemeControlBorderColor">#FF505050</Color>
|
||||||
<sys:Double x:Key="ScrollBarThickness">15</sys:Double>
|
<x:Double x:Key="ScrollBarThickness">15</x:Double>
|
||||||
<sys:Double x:Key="FontSizeSmall">8</sys:Double>
|
<x:Double x:Key="FontSizeSmall">8</x:Double>
|
||||||
<sys:Double x:Key="FontSizeNormal">10</sys:Double>
|
<x:Double x:Key="FontSizeNormal">10</x:Double>
|
||||||
<sys:Double x:Key="FontSize">12</sys:Double>
|
<x:Double x:Key="FontSize">12</x:Double>
|
||||||
<sys:Double x:Key="FontSizeLarge">15</sys:Double>
|
<x:Double x:Key="FontSizeLarge">15</x:Double>
|
||||||
<sys:Double x:Key="ControlContentThemeFontSize">13</sys:Double>
|
<x:Double x:Key="ControlContentThemeFontSize">13</x:Double>
|
||||||
<x:Double x:Key="MenuItemHeight">26</x:Double>
|
<x:Double x:Key="MenuItemHeight">26</x:Double>
|
||||||
<x:Double x:Key="TabItemMinHeight">28</x:Double>
|
<x:Double x:Key="TabItemMinHeight">28</x:Double>
|
||||||
|
<x:Double x:Key="ContentDialogMaxWidth">600</x:Double>
|
||||||
|
<x:Double x:Key="ContentDialogMaxHeight">756</x:Double>
|
||||||
</Styles.Resources>
|
</Styles.Resources>
|
||||||
</Styles>
|
</Styles>
|
@ -113,6 +113,11 @@ namespace Ryujinx.Ava.Common
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
OpenSaveDir(saveDataId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void OpenSaveDir(ulong saveDataId)
|
||||||
|
{
|
||||||
string saveRootPath = Path.Combine(_virtualFileSystem.GetNandPath(), $"user/save/{saveDataId:x16}");
|
string saveRootPath = Path.Combine(_virtualFileSystem.GetNandPath(), $"user/save/{saveDataId:x16}");
|
||||||
|
|
||||||
if (!Directory.Exists(saveRootPath))
|
if (!Directory.Exists(saveRootPath))
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
using ARMeilleure.Translation.PTC;
|
using ARMeilleure.Translation.PTC;
|
||||||
using Avalonia;
|
using Avalonia;
|
||||||
using Avalonia.Rendering;
|
|
||||||
using Avalonia.Threading;
|
using Avalonia.Threading;
|
||||||
using Ryujinx.Ava.Ui.Controls;
|
|
||||||
using Ryujinx.Ava.Ui.Windows;
|
using Ryujinx.Ava.Ui.Windows;
|
||||||
using Ryujinx.Common;
|
using Ryujinx.Common;
|
||||||
using Ryujinx.Common.Configuration;
|
using Ryujinx.Common.Configuration;
|
||||||
@ -11,6 +9,7 @@ using Ryujinx.Common.Logging;
|
|||||||
using Ryujinx.Common.System;
|
using Ryujinx.Common.System;
|
||||||
using Ryujinx.Common.SystemInfo;
|
using Ryujinx.Common.SystemInfo;
|
||||||
using Ryujinx.Modules;
|
using Ryujinx.Modules;
|
||||||
|
using Ryujinx.SDL2.Common;
|
||||||
using Ryujinx.Ui.Common;
|
using Ryujinx.Ui.Common;
|
||||||
using Ryujinx.Ui.Common.Configuration;
|
using Ryujinx.Ui.Common.Configuration;
|
||||||
using Ryujinx.Ui.Common.Helper;
|
using Ryujinx.Ui.Common.Helper;
|
||||||
@ -24,18 +23,14 @@ namespace Ryujinx.Ava
|
|||||||
internal class Program
|
internal class Program
|
||||||
{
|
{
|
||||||
public static double WindowScaleFactor { get; set; }
|
public static double WindowScaleFactor { get; set; }
|
||||||
public static double ActualScaleFactor { get; set; }
|
public static string Version { get; private set; }
|
||||||
public static string Version { get; private set; }
|
|
||||||
public static string ConfigurationPath { get; private set; }
|
public static string ConfigurationPath { get; private set; }
|
||||||
public static bool PreviewerDetached { get; private set; }
|
public static bool PreviewerDetached { get; private set; }
|
||||||
|
|
||||||
public static RenderTimer RenderTimer { get; private set; }
|
|
||||||
|
|
||||||
[DllImport("user32.dll", SetLastError = true)]
|
[DllImport("user32.dll", SetLastError = true)]
|
||||||
public static extern int MessageBoxA(IntPtr hWnd, string text, string caption, uint type);
|
public static extern int MessageBoxA(IntPtr hWnd, string text, string caption, uint type);
|
||||||
|
|
||||||
private const uint MB_ICONWARNING = 0x30;
|
private const uint MB_ICONWARNING = 0x30;
|
||||||
private const int BaseDpi = 96;
|
|
||||||
|
|
||||||
public static void Main(string[] args)
|
public static void Main(string[] args)
|
||||||
{
|
{
|
||||||
@ -43,18 +38,14 @@ namespace Ryujinx.Ava
|
|||||||
|
|
||||||
if (OperatingSystem.IsWindows() && !OperatingSystem.IsWindowsVersionAtLeast(10, 0, 17134))
|
if (OperatingSystem.IsWindows() && !OperatingSystem.IsWindowsVersionAtLeast(10, 0, 17134))
|
||||||
{
|
{
|
||||||
MessageBoxA(IntPtr.Zero, "You are running an outdated version of Windows.\n\nStarting on June 1st 2022, Ryujinx will only support Windows 10 1803 and newer.\n", $"Ryujinx {Version}", MB_ICONWARNING);
|
_ = MessageBoxA(IntPtr.Zero, "You are running an outdated version of Windows.\n\nStarting on June 1st 2022, Ryujinx will only support Windows 10 1803 and newer.\n", $"Ryujinx {Version}", MB_ICONWARNING);
|
||||||
}
|
}
|
||||||
|
|
||||||
PreviewerDetached = true;
|
PreviewerDetached = true;
|
||||||
|
|
||||||
Initialize(args);
|
Initialize(args);
|
||||||
|
|
||||||
RenderTimer = new RenderTimer();
|
|
||||||
|
|
||||||
BuildAvaloniaApp().StartWithClassicDesktopLifetime(args);
|
BuildAvaloniaApp().StartWithClassicDesktopLifetime(args);
|
||||||
|
|
||||||
RenderTimer.Dispose();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static AppBuilder BuildAvaloniaApp()
|
public static AppBuilder BuildAvaloniaApp()
|
||||||
@ -64,24 +55,18 @@ namespace Ryujinx.Ava
|
|||||||
.With(new X11PlatformOptions
|
.With(new X11PlatformOptions
|
||||||
{
|
{
|
||||||
EnableMultiTouch = true,
|
EnableMultiTouch = true,
|
||||||
EnableIme = true,
|
EnableIme = true,
|
||||||
UseEGL = false,
|
UseEGL = false,
|
||||||
UseGpu = false
|
UseGpu = true
|
||||||
})
|
})
|
||||||
.With(new Win32PlatformOptions
|
.With(new Win32PlatformOptions
|
||||||
{
|
{
|
||||||
EnableMultitouch = true,
|
EnableMultitouch = true,
|
||||||
UseWgl = false,
|
UseWgl = false,
|
||||||
AllowEglInitialization = false,
|
AllowEglInitialization = false,
|
||||||
CompositionBackdropCornerRadius = 8f,
|
CompositionBackdropCornerRadius = 8.0f,
|
||||||
})
|
})
|
||||||
.UseSkia()
|
.UseSkia()
|
||||||
.AfterSetup(_ =>
|
|
||||||
{
|
|
||||||
AvaloniaLocator.CurrentMutable
|
|
||||||
.Bind<IRenderTimer>().ToConstant(RenderTimer)
|
|
||||||
.Bind<IRenderLoop>().ToConstant(new RenderLoop(RenderTimer, Dispatcher.UIThread));
|
|
||||||
})
|
|
||||||
.LogToTrace();
|
.LogToTrace();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -111,23 +96,23 @@ namespace Ryujinx.Ava
|
|||||||
// Initialize Discord integration.
|
// Initialize Discord integration.
|
||||||
DiscordIntegrationModule.Initialize();
|
DiscordIntegrationModule.Initialize();
|
||||||
|
|
||||||
|
// Initialize SDL2 driver
|
||||||
|
SDL2Driver.MainThreadDispatcher = action => Dispatcher.UIThread.InvokeAsync(action, DispatcherPriority.Input);
|
||||||
|
|
||||||
ReloadConfig();
|
ReloadConfig();
|
||||||
|
|
||||||
ForceDpiAware.Windows();
|
ForceDpiAware.Windows();
|
||||||
|
|
||||||
WindowScaleFactor = ForceDpiAware.GetWindowScaleFactor();
|
WindowScaleFactor = ForceDpiAware.GetWindowScaleFactor();
|
||||||
ActualScaleFactor = ForceDpiAware.GetActualScaleFactor() / BaseDpi;
|
|
||||||
|
|
||||||
// Logging system information.
|
// Logging system information.
|
||||||
PrintSystemInfo();
|
PrintSystemInfo();
|
||||||
|
|
||||||
// Enable OGL multithreading on the driver, when available.
|
// Enable OGL multithreading on the driver, when available.
|
||||||
BackendThreading threadingMode = ConfigurationState.Instance.Graphics.BackendThreading;
|
DriverUtilities.ToggleOGLThreading(ConfigurationState.Instance.Graphics.BackendThreading == BackendThreading.Off);
|
||||||
DriverUtilities.ToggleOGLThreading(threadingMode == BackendThreading.Off);
|
|
||||||
|
|
||||||
// Check if keys exists.
|
// Check if keys exists.
|
||||||
bool hasSystemProdKeys = File.Exists(Path.Combine(AppDataManager.KeysDirPath, "prod.keys"));
|
if (!File.Exists(Path.Combine(AppDataManager.KeysDirPath, "prod.keys")))
|
||||||
if (!hasSystemProdKeys)
|
|
||||||
{
|
{
|
||||||
if (!(AppDataManager.Mode == AppDataManager.LaunchMode.UserProfile && File.Exists(Path.Combine(AppDataManager.KeysDirPathUser, "prod.keys"))))
|
if (!(AppDataManager.Mode == AppDataManager.LaunchMode.UserProfile && File.Exists(Path.Combine(AppDataManager.KeysDirPathUser, "prod.keys"))))
|
||||||
{
|
{
|
||||||
@ -143,7 +128,7 @@ namespace Ryujinx.Ava
|
|||||||
|
|
||||||
public static void ReloadConfig()
|
public static void ReloadConfig()
|
||||||
{
|
{
|
||||||
string localConfigurationPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Config.json");
|
string localConfigurationPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Config.json");
|
||||||
string appDataConfigurationPath = Path.Combine(AppDataManager.BaseDirPath, "Config.json");
|
string appDataConfigurationPath = Path.Combine(AppDataManager.BaseDirPath, "Config.json");
|
||||||
|
|
||||||
// Now load the configuration as the other subsystems are now registered
|
// Now load the configuration as the other subsystems are now registered
|
||||||
@ -197,8 +182,7 @@ namespace Ryujinx.Ava
|
|||||||
Logger.Notice.Print(LogClass.Application, $"Ryujinx Version: {Version}");
|
Logger.Notice.Print(LogClass.Application, $"Ryujinx Version: {Version}");
|
||||||
SystemInfo.Gather().Print();
|
SystemInfo.Gather().Print();
|
||||||
|
|
||||||
var enabledLogs = Logger.GetEnabledLevels();
|
Logger.Notice.Print(LogClass.Application, $"Logs Enabled: {(Logger.GetEnabledLevels().Count == 0 ? "<None>" : string.Join(", ", Logger.GetEnabledLevels()))}");
|
||||||
Logger.Notice.Print(LogClass.Application, $"Logs Enabled: {(enabledLogs.Count == 0 ? "<None>" : string.Join(", ", enabledLogs))}");
|
|
||||||
|
|
||||||
if (AppDataManager.Mode == AppDataManager.LaunchMode.Custom)
|
if (AppDataManager.Mode == AppDataManager.LaunchMode.Custom)
|
||||||
{
|
{
|
||||||
@ -240,4 +224,4 @@ namespace Ryujinx.Ava
|
|||||||
Logger.Shutdown();
|
Logger.Shutdown();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,25 +19,25 @@
|
|||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Avalonia" Version="0.10.18" />
|
<PackageReference Include="Avalonia" Version="0.10.18" />
|
||||||
<PackageReference Include="Avalonia.Desktop" Version="0.10.15" />
|
<PackageReference Include="Avalonia.Desktop" Version="0.10.18" />
|
||||||
<PackageReference Include="Avalonia.Diagnostics" Version="0.10.15" />
|
<PackageReference Include="Avalonia.Diagnostics" Version="0.10.18" />
|
||||||
<PackageReference Include="Avalonia.Controls.DataGrid" Version="0.10.15" />
|
<PackageReference Include="Avalonia.Controls.DataGrid" Version="0.10.18" />
|
||||||
<PackageReference Include="Avalonia.Markup.Xaml.Loader" Version="0.10.15" />
|
<PackageReference Include="Avalonia.Markup.Xaml.Loader" Version="0.10.18" />
|
||||||
<PackageReference Include="Avalonia.Svg" Version="0.10.14" />
|
<PackageReference Include="Avalonia.Svg" Version="0.10.18" />
|
||||||
<PackageReference Include="Avalonia.Svg.Skia" Version="0.10.14" />
|
<PackageReference Include="Avalonia.Svg.Skia" Version="0.10.18" />
|
||||||
<PackageReference Include="jp2masa.Avalonia.Flexbox" Version="0.2.0" />
|
<PackageReference Include="jp2masa.Avalonia.Flexbox" Version="0.2.0" />
|
||||||
<PackageReference Include="DynamicData" Version="7.9.4" />
|
<PackageReference Include="DynamicData" Version="7.12.8" />
|
||||||
<PackageReference Include="FluentAvaloniaUI" Version="1.4.1" />
|
<PackageReference Include="FluentAvaloniaUI" Version="1.4.5" />
|
||||||
<PackageReference Include="XamlNameReferenceGenerator" Version="1.3.4" />
|
<PackageReference Include="XamlNameReferenceGenerator" Version="1.4.2" />
|
||||||
|
|
||||||
<PackageReference Include="OpenTK.Core" Version="4.7.2" />
|
<PackageReference Include="OpenTK.Core" Version="4.7.5" />
|
||||||
<PackageReference Include="Ryujinx.Audio.OpenAL.Dependencies" Version="1.21.0.1" Condition="'$(RuntimeIdentifier)' != 'linux-x64' AND '$(RuntimeIdentifier)' != 'osx-x64'" />
|
<PackageReference Include="Ryujinx.Audio.OpenAL.Dependencies" Version="1.21.0.1" Condition="'$(RuntimeIdentifier)' != 'linux-x64' AND '$(RuntimeIdentifier)' != 'osx-x64'" />
|
||||||
<PackageReference Include="Ryujinx.Graphics.Nvdec.Dependencies" Version="5.0.1-build10" Condition="'$(RuntimeIdentifier)' != 'linux-x64' AND '$(RuntimeIdentifier)' != 'osx-x64'" />
|
<PackageReference Include="Ryujinx.Graphics.Nvdec.Dependencies" Version="5.0.1-build10" Condition="'$(RuntimeIdentifier)' != 'linux-x64' AND '$(RuntimeIdentifier)' != 'osx-x64'" />
|
||||||
<PackageReference Include="Silk.NET.Vulkan" Version="2.10.1" />
|
<PackageReference Include="Silk.NET.Vulkan" Version="2.16.0" />
|
||||||
<PackageReference Include="Silk.NET.Vulkan.Extensions.EXT" Version="2.10.1" />
|
<PackageReference Include="Silk.NET.Vulkan.Extensions.EXT" Version="2.16.0" />
|
||||||
<PackageReference Include="Silk.NET.Vulkan.Extensions.KHR" Version="2.10.1" />
|
<PackageReference Include="Silk.NET.Vulkan.Extensions.KHR" Version="2.16.0" />
|
||||||
<PackageReference Include="SPB" Version="0.0.4-build28" />
|
<PackageReference Include="SPB" Version="0.0.4-build28" />
|
||||||
<PackageReference Include="SharpZipLib" Version="1.3.3" />
|
<PackageReference Include="SharpZipLib" Version="1.4.1" />
|
||||||
<PackageReference Include="SixLabors.ImageSharp" Version="1.0.4" />
|
<PackageReference Include="SixLabors.ImageSharp" Version="1.0.4" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
@ -11,7 +11,8 @@
|
|||||||
Height="340"
|
Height="340"
|
||||||
CanResize="False"
|
CanResize="False"
|
||||||
SizeToContent="Height"
|
SizeToContent="Height"
|
||||||
mc:Ignorable="d">
|
mc:Ignorable="d"
|
||||||
|
Focusable="True">
|
||||||
<Grid
|
<Grid
|
||||||
Margin="20"
|
Margin="20"
|
||||||
HorizontalAlignment="Stretch"
|
HorizontalAlignment="Stretch"
|
||||||
|
@ -6,7 +6,8 @@
|
|||||||
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"
|
||||||
Width="400"
|
Width="400"
|
||||||
mc:Ignorable="d">
|
mc:Ignorable="d"
|
||||||
|
Focusable="True">
|
||||||
<Grid
|
<Grid
|
||||||
Margin="20"
|
Margin="20"
|
||||||
HorizontalAlignment="Stretch"
|
HorizontalAlignment="Stretch"
|
||||||
|
@ -127,9 +127,16 @@ namespace Ryujinx.Ava.Ui.Controls
|
|||||||
contentDialog.PrimaryButtonClick += deferCloseAction;
|
contentDialog.PrimaryButtonClick += deferCloseAction;
|
||||||
}
|
}
|
||||||
|
|
||||||
await contentDialog.ShowAsync(ContentDialogPlacement.Popup);
|
if (useOverlay)
|
||||||
|
{
|
||||||
|
await contentDialog.ShowAsync(overlay, ContentDialogPlacement.Popup);
|
||||||
|
|
||||||
overlay?.Close();
|
overlay!.Close();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
await contentDialog.ShowAsync(ContentDialogPlacement.Popup);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (useOverlay)
|
if (useOverlay)
|
||||||
@ -391,4 +398,4 @@ namespace Ryujinx.Ava.Ui.Controls
|
|||||||
return string.Empty;
|
return string.Empty;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -6,8 +6,8 @@ using SPB.Graphics;
|
|||||||
using SPB.Platform;
|
using SPB.Platform;
|
||||||
using SPB.Platform.GLX;
|
using SPB.Platform.GLX;
|
||||||
using SPB.Platform.X11;
|
using SPB.Platform.X11;
|
||||||
|
using SPB.Windowing;
|
||||||
using System;
|
using System;
|
||||||
using System.Reflection;
|
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using System.Runtime.Versioning;
|
using System.Runtime.Versioning;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
@ -15,12 +15,12 @@ using static Ryujinx.Ava.Ui.Controls.Win32NativeInterop;
|
|||||||
|
|
||||||
namespace Ryujinx.Ava.Ui.Controls
|
namespace Ryujinx.Ava.Ui.Controls
|
||||||
{
|
{
|
||||||
public unsafe class EmbeddedWindow : NativeControlHost
|
public class EmbeddedWindow : NativeControlHost
|
||||||
{
|
{
|
||||||
private WindowProc _wndProcDelegate;
|
private WindowProc _wndProcDelegate;
|
||||||
private string _className;
|
private string _className;
|
||||||
|
|
||||||
protected GLXWindow X11Window { get; private set; }
|
protected GLXWindow X11Window { get; set; }
|
||||||
protected IntPtr WindowHandle { get; set; }
|
protected IntPtr WindowHandle { get; set; }
|
||||||
protected IntPtr X11Display { get; set; }
|
protected IntPtr X11Display { get; set; }
|
||||||
|
|
||||||
@ -94,19 +94,17 @@ namespace Ryujinx.Ava.Ui.Controls
|
|||||||
}
|
}
|
||||||
|
|
||||||
[SupportedOSPlatform("linux")]
|
[SupportedOSPlatform("linux")]
|
||||||
IPlatformHandle CreateLinux(IPlatformHandle parent)
|
protected virtual IPlatformHandle CreateLinux(IPlatformHandle parent)
|
||||||
{
|
{
|
||||||
X11Window = PlatformHelper.CreateOpenGLWindow(FramebufferFormat.Default, 0, 0, 100, 100) as GLXWindow;
|
X11Window = PlatformHelper.CreateOpenGLWindow(FramebufferFormat.Default, 0, 0, 100, 100) as GLXWindow;
|
||||||
|
|
||||||
WindowHandle = X11Window.WindowHandle.RawHandle;
|
WindowHandle = X11Window.WindowHandle.RawHandle;
|
||||||
|
X11Display = X11Window.DisplayHandle.RawHandle;
|
||||||
X11Display = X11Window.DisplayHandle.RawHandle;
|
|
||||||
|
|
||||||
return new PlatformHandle(WindowHandle, "X11");
|
return new PlatformHandle(WindowHandle, "X11");
|
||||||
}
|
}
|
||||||
|
|
||||||
[SupportedOSPlatform("windows")]
|
[SupportedOSPlatform("windows")]
|
||||||
unsafe IPlatformHandle CreateWin32(IPlatformHandle parent)
|
IPlatformHandle CreateWin32(IPlatformHandle parent)
|
||||||
{
|
{
|
||||||
_className = "NativeWindow-" + Guid.NewGuid();
|
_className = "NativeWindow-" + Guid.NewGuid();
|
||||||
_wndProcDelegate = WndProc;
|
_wndProcDelegate = WndProc;
|
||||||
@ -142,7 +140,7 @@ namespace Ryujinx.Ava.Ui.Controls
|
|||||||
}
|
}
|
||||||
|
|
||||||
[SupportedOSPlatform("windows")]
|
[SupportedOSPlatform("windows")]
|
||||||
internal IntPtr WndProc(IntPtr hWnd, WindowsMessages msg, IntPtr wParam, IntPtr lParam)
|
IntPtr WndProc(IntPtr hWnd, WindowsMessages msg, IntPtr wParam, IntPtr lParam)
|
||||||
{
|
{
|
||||||
var point = new Point((long)lParam & 0xFFFF, ((long)lParam >> 16) & 0xFFFF);
|
var point = new Point((long)lParam & 0xFFFF, ((long)lParam >> 16) & 0xFFFF);
|
||||||
var root = VisualRoot as Window;
|
var root = VisualRoot as Window;
|
||||||
|
@ -10,7 +10,8 @@
|
|||||||
xmlns:ui="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia"
|
xmlns:ui="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia"
|
||||||
d:DesignHeight="450"
|
d:DesignHeight="450"
|
||||||
d:DesignWidth="800"
|
d:DesignWidth="800"
|
||||||
mc:Ignorable="d">
|
mc:Ignorable="d"
|
||||||
|
Focusable="True">
|
||||||
<UserControl.Resources>
|
<UserControl.Resources>
|
||||||
<controls:BitmapArrayValueConverter x:Key="ByteImage" />
|
<controls:BitmapArrayValueConverter x:Key="ByteImage" />
|
||||||
<MenuFlyout x:Key="GameContextMenu" Opened="MenuBase_OnMenuOpened">
|
<MenuFlyout x:Key="GameContextMenu" Opened="MenuBase_OnMenuOpened">
|
||||||
@ -113,8 +114,8 @@
|
|||||||
<Style Selector="ListBoxItem">
|
<Style Selector="ListBoxItem">
|
||||||
<Setter Property="Padding" Value="0" />
|
<Setter Property="Padding" Value="0" />
|
||||||
<Setter Property="Margin" Value="5" />
|
<Setter Property="Margin" Value="5" />
|
||||||
<Setter Property="CornerRadius" Value="5" />
|
<Setter Property="CornerRadius" Value="4" />
|
||||||
<Setter Property="Background" Value="{DynamicResource SystemAccentColorDark3}" />
|
<Setter Property="Background" Value="{DynamicResource AppListBackgroundColor}" />
|
||||||
<Style.Animations>
|
<Style.Animations>
|
||||||
<Animation Duration="0:0:0.7">
|
<Animation Duration="0:0:0.7">
|
||||||
<KeyFrame Cue="0%">
|
<KeyFrame Cue="0%">
|
||||||
@ -132,27 +133,18 @@
|
|||||||
</Animation>
|
</Animation>
|
||||||
</Style.Animations>
|
</Style.Animations>
|
||||||
</Style>
|
</Style>
|
||||||
|
<Style Selector="ListBoxItem:selected /template/ ContentPresenter">
|
||||||
|
<Setter Property="Background" Value="{DynamicResource AppListBackgroundColor}" />
|
||||||
|
</Style>
|
||||||
|
<Style Selector="ListBoxItem:pointerover /template/ ContentPresenter">
|
||||||
|
<Setter Property="Background" Value="{DynamicResource AppListHoverBackgroundColor}" />
|
||||||
|
</Style>
|
||||||
</ListBox.Styles>
|
</ListBox.Styles>
|
||||||
<ListBox.ItemTemplate>
|
<ListBox.ItemTemplate>
|
||||||
<DataTemplate>
|
<DataTemplate>
|
||||||
<Grid>
|
<Grid>
|
||||||
<Grid.Styles>
|
|
||||||
<Style Selector="ui|SymbolIcon.small.icon">
|
|
||||||
<Setter Property="FontSize" Value="15" />
|
|
||||||
</Style>
|
|
||||||
<Style Selector="ui|SymbolIcon.normal.icon">
|
|
||||||
<Setter Property="FontSize" Value="19" />
|
|
||||||
</Style>
|
|
||||||
<Style Selector="ui|SymbolIcon.large.icon">
|
|
||||||
<Setter Property="FontSize" Value="23" />
|
|
||||||
</Style>
|
|
||||||
<Style Selector="ui|SymbolIcon.huge.icon">
|
|
||||||
<Setter Property="FontSize" Value="26" />
|
|
||||||
</Style>
|
|
||||||
</Grid.Styles>
|
|
||||||
<Border
|
<Border
|
||||||
Margin="0"
|
Margin="10"
|
||||||
Padding="{Binding $parent[UserControl].DataContext.GridItemPadding}"
|
|
||||||
HorizontalAlignment="Stretch"
|
HorizontalAlignment="Stretch"
|
||||||
VerticalAlignment="Stretch"
|
VerticalAlignment="Stretch"
|
||||||
Classes.huge="{Binding $parent[UserControl].DataContext.IsGridHuge}"
|
Classes.huge="{Binding $parent[UserControl].DataContext.IsGridHuge}"
|
||||||
@ -160,57 +152,41 @@
|
|||||||
Classes.normal="{Binding $parent[UserControl].DataContext.IsGridMedium}"
|
Classes.normal="{Binding $parent[UserControl].DataContext.IsGridMedium}"
|
||||||
Classes.small="{Binding $parent[UserControl].DataContext.IsGridSmall}"
|
Classes.small="{Binding $parent[UserControl].DataContext.IsGridSmall}"
|
||||||
ClipToBounds="True"
|
ClipToBounds="True"
|
||||||
CornerRadius="5">
|
CornerRadius="4">
|
||||||
<Grid Margin="0">
|
<Grid>
|
||||||
<Grid.RowDefinitions>
|
<Grid.RowDefinitions>
|
||||||
<RowDefinition Height="Auto" />
|
<RowDefinition Height="Auto" />
|
||||||
<RowDefinition Height="Auto" />
|
<RowDefinition Height="Auto" />
|
||||||
</Grid.RowDefinitions>
|
</Grid.RowDefinitions>
|
||||||
<Image
|
<Image
|
||||||
Grid.Row="0"
|
Grid.Row="0"
|
||||||
Margin="0"
|
|
||||||
HorizontalAlignment="Stretch"
|
HorizontalAlignment="Stretch"
|
||||||
VerticalAlignment="Top"
|
VerticalAlignment="Top"
|
||||||
Source="{Binding Icon, Converter={StaticResource ByteImage}}" />
|
Source="{Binding Icon, Converter={StaticResource ByteImage}}" />
|
||||||
<StackPanel
|
<Panel
|
||||||
Grid.Row="1"
|
Grid.Row="1"
|
||||||
Height="50"
|
Height="50"
|
||||||
Margin="5"
|
Margin="0 10 0 0"
|
||||||
HorizontalAlignment="Stretch"
|
HorizontalAlignment="Stretch"
|
||||||
VerticalAlignment="Stretch"
|
VerticalAlignment="Stretch"
|
||||||
IsVisible="{Binding $parent[UserControl].DataContext.ShowNames}">
|
IsVisible="{Binding $parent[UserControl].DataContext.ShowNames}">
|
||||||
<TextBlock
|
<TextBlock
|
||||||
HorizontalAlignment="Stretch"
|
HorizontalAlignment="Stretch"
|
||||||
|
VerticalAlignment="Center"
|
||||||
Text="{Binding TitleName}"
|
Text="{Binding TitleName}"
|
||||||
TextAlignment="Center"
|
TextAlignment="Center"
|
||||||
TextWrapping="Wrap" />
|
TextWrapping="Wrap" />
|
||||||
</StackPanel>
|
</Panel>
|
||||||
</Grid>
|
</Grid>
|
||||||
</Border>
|
</Border>
|
||||||
<ui:SymbolIcon
|
<ui:SymbolIcon
|
||||||
Margin="5"
|
Margin="5,5,0,0"
|
||||||
HorizontalAlignment="Left"
|
HorizontalAlignment="Left"
|
||||||
VerticalAlignment="Top"
|
VerticalAlignment="Top"
|
||||||
Classes.huge="{Binding $parent[UserControl].DataContext.IsGridHuge}"
|
FontSize="16"
|
||||||
Classes.icon="true"
|
Foreground="{DynamicResource SystemAccentColor}"
|
||||||
Classes.large="{Binding $parent[UserControl].DataContext.IsGridLarge}"
|
|
||||||
Classes.normal="{Binding $parent[UserControl].DataContext.IsGridMedium}"
|
|
||||||
Classes.small="{Binding $parent[UserControl].DataContext.IsGridSmall}"
|
|
||||||
Foreground="Yellow"
|
|
||||||
IsVisible="{Binding Favorite}"
|
IsVisible="{Binding Favorite}"
|
||||||
Symbol="StarFilled" />
|
Symbol="StarFilled" />
|
||||||
<ui:SymbolIcon
|
|
||||||
Margin="5"
|
|
||||||
HorizontalAlignment="Left"
|
|
||||||
VerticalAlignment="Top"
|
|
||||||
Classes.huge="{Binding $parent[UserControl].DataContext.IsGridHuge}"
|
|
||||||
Classes.icon="true"
|
|
||||||
Classes.large="{Binding $parent[UserControl].DataContext.IsGridLarge}"
|
|
||||||
Classes.normal="{Binding $parent[UserControl].DataContext.IsGridMedium}"
|
|
||||||
Classes.small="{Binding $parent[UserControl].DataContext.IsGridSmall}"
|
|
||||||
Foreground="Black"
|
|
||||||
IsVisible="{Binding Favorite}"
|
|
||||||
Symbol="Star" />
|
|
||||||
</Grid>
|
</Grid>
|
||||||
</DataTemplate>
|
</DataTemplate>
|
||||||
</ListBox.ItemTemplate>
|
</ListBox.ItemTemplate>
|
||||||
|
@ -10,7 +10,8 @@
|
|||||||
xmlns:ui="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia"
|
xmlns:ui="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia"
|
||||||
d:DesignHeight="450"
|
d:DesignHeight="450"
|
||||||
d:DesignWidth="800"
|
d:DesignWidth="800"
|
||||||
mc:Ignorable="d">
|
mc:Ignorable="d"
|
||||||
|
Focusable="True">
|
||||||
<UserControl.Resources>
|
<UserControl.Resources>
|
||||||
<controls:BitmapArrayValueConverter x:Key="ByteImage" />
|
<controls:BitmapArrayValueConverter x:Key="ByteImage" />
|
||||||
<MenuFlyout x:Key="GameContextMenu" Opened="MenuBase_OnMenuOpened">
|
<MenuFlyout x:Key="GameContextMenu" Opened="MenuBase_OnMenuOpened">
|
||||||
@ -115,8 +116,8 @@
|
|||||||
<Setter Property="Padding" Value="0" />
|
<Setter Property="Padding" Value="0" />
|
||||||
<Setter Property="Margin" Value="0" />
|
<Setter Property="Margin" Value="0" />
|
||||||
<Setter Property="CornerRadius" Value="5" />
|
<Setter Property="CornerRadius" Value="5" />
|
||||||
<Setter Property="BorderBrush" Value="{DynamicResource SystemAccentColorDark3}" />
|
<Setter Property="Background" Value="{DynamicResource AppListBackgroundColor}" />
|
||||||
<Setter Property="BorderThickness" Value="2" />
|
<Setter Property="BorderThickness" Value="2"/>
|
||||||
<Style.Animations>
|
<Style.Animations>
|
||||||
<Animation Duration="0:0:0.7">
|
<Animation Duration="0:0:0.7">
|
||||||
<KeyFrame Cue="0%">
|
<KeyFrame Cue="0%">
|
||||||
@ -134,6 +135,12 @@
|
|||||||
</Animation>
|
</Animation>
|
||||||
</Style.Animations>
|
</Style.Animations>
|
||||||
</Style>
|
</Style>
|
||||||
|
<Style Selector="ListBoxItem:selected /template/ ContentPresenter">
|
||||||
|
<Setter Property="Background" Value="{DynamicResource AppListBackgroundColor}" />
|
||||||
|
</Style>
|
||||||
|
<Style Selector="ListBoxItem:pointerover /template/ ContentPresenter">
|
||||||
|
<Setter Property="Background" Value="{DynamicResource AppListHoverBackgroundColor}" />
|
||||||
|
</Style>
|
||||||
</ListBox.Styles>
|
</ListBox.Styles>
|
||||||
<ListBox.ItemTemplate>
|
<ListBox.ItemTemplate>
|
||||||
<DataTemplate>
|
<DataTemplate>
|
||||||
@ -152,9 +159,6 @@
|
|||||||
<ColumnDefinition Width="*" />
|
<ColumnDefinition Width="*" />
|
||||||
<ColumnDefinition Width="Auto" />
|
<ColumnDefinition Width="Auto" />
|
||||||
</Grid.ColumnDefinitions>
|
</Grid.ColumnDefinitions>
|
||||||
<Grid.RowDefinitions>
|
|
||||||
<RowDefinition />
|
|
||||||
</Grid.RowDefinitions>
|
|
||||||
<Image
|
<Image
|
||||||
Grid.RowSpan="3"
|
Grid.RowSpan="3"
|
||||||
Grid.Column="0"
|
Grid.Column="0"
|
||||||
@ -169,7 +173,7 @@
|
|||||||
HorizontalAlignment="Left"
|
HorizontalAlignment="Left"
|
||||||
VerticalAlignment="Top"
|
VerticalAlignment="Top"
|
||||||
Orientation="Vertical"
|
Orientation="Vertical"
|
||||||
Spacing="5">
|
Spacing="5" >
|
||||||
<TextBlock
|
<TextBlock
|
||||||
HorizontalAlignment="Stretch"
|
HorizontalAlignment="Stretch"
|
||||||
Text="{Binding TitleName}"
|
Text="{Binding TitleName}"
|
||||||
@ -214,20 +218,10 @@
|
|||||||
Margin="-5,-5,0,0"
|
Margin="-5,-5,0,0"
|
||||||
HorizontalAlignment="Left"
|
HorizontalAlignment="Left"
|
||||||
VerticalAlignment="Top"
|
VerticalAlignment="Top"
|
||||||
FontSize="20"
|
FontSize="16"
|
||||||
Foreground="Yellow"
|
Foreground="{DynamicResource SystemAccentColor}"
|
||||||
IsVisible="{Binding Favorite}"
|
IsVisible="{Binding Favorite}"
|
||||||
Symbol="StarFilled" />
|
Symbol="StarFilled" />
|
||||||
<ui:SymbolIcon
|
|
||||||
Grid.Row="0"
|
|
||||||
Grid.Column="0"
|
|
||||||
Margin="-5,-5,0,0"
|
|
||||||
HorizontalAlignment="Left"
|
|
||||||
VerticalAlignment="Top"
|
|
||||||
FontSize="20"
|
|
||||||
Foreground="Black"
|
|
||||||
IsVisible="{Binding Favorite}"
|
|
||||||
Symbol="Star" />
|
|
||||||
</Grid>
|
</Grid>
|
||||||
</Border>
|
</Border>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
@ -4,7 +4,8 @@
|
|||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
mc:Ignorable="d">
|
mc:Ignorable="d"
|
||||||
|
Focusable="True">
|
||||||
<Grid
|
<Grid
|
||||||
Margin="5,10,5,5"
|
Margin="5,10,5,5"
|
||||||
HorizontalAlignment="Stretch"
|
HorizontalAlignment="Stretch"
|
||||||
|
@ -4,7 +4,8 @@
|
|||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
xmlns:ui="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia"
|
xmlns:ui="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia"
|
||||||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||||
x:Class="Ryujinx.Ava.Ui.Controls.NavigationDialogHost">
|
x:Class="Ryujinx.Ava.Ui.Controls.NavigationDialogHost"
|
||||||
|
Focusable="True">
|
||||||
<ui:Frame HorizontalAlignment="Stretch" VerticalAlignment="Stretch"
|
<ui:Frame HorizontalAlignment="Stretch" VerticalAlignment="Stretch"
|
||||||
x:Name="ContentFrame" />
|
x:Name="ContentFrame" />
|
||||||
</UserControl>
|
</UserControl>
|
@ -1,6 +1,7 @@
|
|||||||
using Avalonia;
|
using Avalonia;
|
||||||
using Avalonia.Controls;
|
using Avalonia.Controls;
|
||||||
using FluentAvalonia.UI.Controls;
|
using FluentAvalonia.UI.Controls;
|
||||||
|
using LibHac;
|
||||||
using Ryujinx.Ava.Common.Locale;
|
using Ryujinx.Ava.Common.Locale;
|
||||||
using Ryujinx.Ava.Ui.ViewModels;
|
using Ryujinx.Ava.Ui.ViewModels;
|
||||||
using Ryujinx.HLE.FileSystem;
|
using Ryujinx.HLE.FileSystem;
|
||||||
@ -14,6 +15,8 @@ namespace Ryujinx.Ava.Ui.Controls
|
|||||||
{
|
{
|
||||||
public AccountManager AccountManager { get; }
|
public AccountManager AccountManager { get; }
|
||||||
public ContentManager ContentManager { get; }
|
public ContentManager ContentManager { get; }
|
||||||
|
public VirtualFileSystem VirtualFileSystem { get; }
|
||||||
|
public HorizonClient HorizonClient { get; }
|
||||||
public UserProfileViewModel ViewModel { get; set; }
|
public UserProfileViewModel ViewModel { get; set; }
|
||||||
|
|
||||||
public NavigationDialogHost()
|
public NavigationDialogHost()
|
||||||
@ -22,10 +25,12 @@ namespace Ryujinx.Ava.Ui.Controls
|
|||||||
}
|
}
|
||||||
|
|
||||||
public NavigationDialogHost(AccountManager accountManager, ContentManager contentManager,
|
public NavigationDialogHost(AccountManager accountManager, ContentManager contentManager,
|
||||||
VirtualFileSystem virtualFileSystem)
|
VirtualFileSystem virtualFileSystem, HorizonClient horizonClient)
|
||||||
{
|
{
|
||||||
AccountManager = accountManager;
|
AccountManager = accountManager;
|
||||||
ContentManager = contentManager;
|
ContentManager = contentManager;
|
||||||
|
VirtualFileSystem = virtualFileSystem;
|
||||||
|
HorizonClient = horizonClient;
|
||||||
ViewModel = new UserProfileViewModel(this);
|
ViewModel = new UserProfileViewModel(this);
|
||||||
|
|
||||||
|
|
||||||
@ -54,9 +59,10 @@ namespace Ryujinx.Ava.Ui.Controls
|
|||||||
ContentFrame.Navigate(sourcePageType, parameter);
|
ContentFrame.Navigate(sourcePageType, parameter);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static async Task Show(AccountManager ownerAccountManager, ContentManager ownerContentManager, VirtualFileSystem ownerVirtualFileSystem)
|
public static async Task Show(AccountManager ownerAccountManager, ContentManager ownerContentManager,
|
||||||
|
VirtualFileSystem ownerVirtualFileSystem, HorizonClient ownerHorizonClient)
|
||||||
{
|
{
|
||||||
var content = new NavigationDialogHost(ownerAccountManager, ownerContentManager, ownerVirtualFileSystem);
|
var content = new NavigationDialogHost(ownerAccountManager, ownerContentManager, ownerVirtualFileSystem, ownerHorizonClient);
|
||||||
ContentDialog contentDialog = new ContentDialog
|
ContentDialog contentDialog = new ContentDialog
|
||||||
{
|
{
|
||||||
Title = LocaleManager.Instance["UserProfileWindowTitle"],
|
Title = LocaleManager.Instance["UserProfileWindowTitle"],
|
||||||
|
@ -49,7 +49,7 @@ namespace Ryujinx.Ava.Ui.Controls
|
|||||||
{
|
{
|
||||||
throw new PlatformNotSupportedException();
|
throw new PlatformNotSupportedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
var flags = OpenGLContextFlags.Compat;
|
var flags = OpenGLContextFlags.Compat;
|
||||||
if (_graphicsDebugLevel != GraphicsDebugLevel.None)
|
if (_graphicsDebugLevel != GraphicsDebugLevel.None)
|
||||||
{
|
{
|
||||||
@ -69,12 +69,12 @@ namespace Ryujinx.Ava.Ui.Controls
|
|||||||
|
|
||||||
public void MakeCurrent()
|
public void MakeCurrent()
|
||||||
{
|
{
|
||||||
Context.MakeCurrent(_window);
|
Context?.MakeCurrent(_window);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void MakeCurrent(NativeWindowBase window)
|
public void MakeCurrent(NativeWindowBase window)
|
||||||
{
|
{
|
||||||
Context.MakeCurrent(window);
|
Context?.MakeCurrent(window);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SwapBuffers()
|
public void SwapBuffers()
|
||||||
|
@ -4,7 +4,8 @@
|
|||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
mc:Ignorable="d"
|
mc:Ignorable="d"
|
||||||
xmlns:Locale="clr-namespace:Ryujinx.Ava.Common.Locale"
|
xmlns:Locale="clr-namespace:Ryujinx.Ava.Common.Locale"
|
||||||
x:Class="Ryujinx.Ava.Ui.Controls.ProfileImageSelectionDialog">
|
x:Class="Ryujinx.Ava.Ui.Controls.ProfileImageSelectionDialog"
|
||||||
|
Focusable="True">
|
||||||
<Grid HorizontalAlignment="Stretch" VerticalAlignment="Center" Margin="5,10,5, 5">
|
<Grid HorizontalAlignment="Stretch" VerticalAlignment="Center" Margin="5,10,5, 5">
|
||||||
<Grid.RowDefinitions>
|
<Grid.RowDefinitions>
|
||||||
<RowDefinition Height="Auto" />
|
<RowDefinition Height="Auto" />
|
||||||
|
@ -1,100 +0,0 @@
|
|||||||
using Avalonia.Rendering;
|
|
||||||
using System;
|
|
||||||
using System.Threading;
|
|
||||||
using System.Timers;
|
|
||||||
|
|
||||||
namespace Ryujinx.Ava.Ui.Controls
|
|
||||||
{
|
|
||||||
internal class RenderTimer : IRenderTimer, IDisposable
|
|
||||||
{
|
|
||||||
public event Action<TimeSpan> Tick
|
|
||||||
{
|
|
||||||
add
|
|
||||||
{
|
|
||||||
_tick += value;
|
|
||||||
|
|
||||||
if (_subscriberCount++ == 0)
|
|
||||||
{
|
|
||||||
Start();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
remove
|
|
||||||
{
|
|
||||||
if (--_subscriberCount == 0)
|
|
||||||
{
|
|
||||||
Stop();
|
|
||||||
}
|
|
||||||
|
|
||||||
_tick -= value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private Thread _tickThread;
|
|
||||||
private readonly System.Timers.Timer _timer;
|
|
||||||
|
|
||||||
private Action<TimeSpan> _tick;
|
|
||||||
private int _subscriberCount;
|
|
||||||
|
|
||||||
private bool _isRunning;
|
|
||||||
|
|
||||||
private AutoResetEvent _resetEvent;
|
|
||||||
|
|
||||||
public RenderTimer()
|
|
||||||
{
|
|
||||||
_timer = new System.Timers.Timer(15);
|
|
||||||
_resetEvent = new AutoResetEvent(true);
|
|
||||||
_timer.Elapsed += Timer_Elapsed;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void Timer_Elapsed(object sender, ElapsedEventArgs e)
|
|
||||||
{
|
|
||||||
TickNow();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Start()
|
|
||||||
{
|
|
||||||
_timer.Start();
|
|
||||||
if (_tickThread == null)
|
|
||||||
{
|
|
||||||
_tickThread = new Thread(RunTick);
|
|
||||||
_tickThread.Name = "RenderTimerTickThread";
|
|
||||||
_tickThread.IsBackground = true;
|
|
||||||
_isRunning = true;
|
|
||||||
_tickThread.Start();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void RunTick()
|
|
||||||
{
|
|
||||||
while (_isRunning)
|
|
||||||
{
|
|
||||||
_resetEvent.WaitOne();
|
|
||||||
_tick?.Invoke(TimeSpan.FromMilliseconds(Environment.TickCount));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void TickNow()
|
|
||||||
{
|
|
||||||
lock (_timer)
|
|
||||||
{
|
|
||||||
_resetEvent.Set();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Stop()
|
|
||||||
{
|
|
||||||
_timer.Stop();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
_timer.Elapsed -= Timer_Elapsed;
|
|
||||||
_timer.Stop();
|
|
||||||
_isRunning = false;
|
|
||||||
_resetEvent.Set();
|
|
||||||
_tickThread.Join();
|
|
||||||
_resetEvent.Dispose();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -3,12 +3,6 @@
|
|||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||||
x:Class="Ryujinx.Ava.Ui.Controls.RendererHost">
|
x:Class="Ryujinx.Ava.Ui.Controls.RendererHost"
|
||||||
<ContentControl
|
Focusable="True">
|
||||||
HorizontalAlignment="Stretch"
|
|
||||||
HorizontalContentAlignment="Stretch"
|
|
||||||
VerticalAlignment="Stretch"
|
|
||||||
VerticalContentAlignment="Stretch"
|
|
||||||
Name="View"
|
|
||||||
/>
|
|
||||||
</UserControl>
|
</UserControl>
|
||||||
|
@ -41,7 +41,7 @@ namespace Ryujinx.Ava.Ui.Controls
|
|||||||
{
|
{
|
||||||
_currentWindow.WindowCreated += CurrentWindow_WindowCreated;
|
_currentWindow.WindowCreated += CurrentWindow_WindowCreated;
|
||||||
_currentWindow.SizeChanged += CurrentWindow_SizeChanged;
|
_currentWindow.SizeChanged += CurrentWindow_SizeChanged;
|
||||||
View.Content = _currentWindow;
|
Content = _currentWindow;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void CreateVulkan()
|
public void CreateVulkan()
|
||||||
|
103
Ryujinx.Ava/Ui/Controls/SaveManager.axaml
Normal file
103
Ryujinx.Ava/Ui/Controls/SaveManager.axaml
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
<UserControl xmlns="https://github.com/avaloniaui"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
xmlns:controls="clr-namespace:Ryujinx.Ava.Ui.Controls"
|
||||||
|
xmlns:models="clr-namespace:Ryujinx.Ava.Ui.Models"
|
||||||
|
xmlns:ui="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia"
|
||||||
|
xmlns:locale="clr-namespace:Ryujinx.Ava.Common.Locale"
|
||||||
|
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||||
|
Height="400"
|
||||||
|
Width="550"
|
||||||
|
x:Class="Ryujinx.Ava.Ui.Controls.SaveManager"
|
||||||
|
Focusable="True">
|
||||||
|
<UserControl.Resources>
|
||||||
|
<controls:BitmapArrayValueConverter x:Key="ByteImage" />
|
||||||
|
</UserControl.Resources>
|
||||||
|
<Grid>
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
<RowDefinition />
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
<Grid Grid.Row="0" HorizontalAlignment="Stretch">
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="Auto" />
|
||||||
|
<ColumnDefinition />
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
<StackPanel Spacing="10" Orientation="Horizontal" HorizontalAlignment="Left" VerticalAlignment="Center">
|
||||||
|
<Label Content="{locale:Locale CommonSort}" VerticalAlignment="Center" />
|
||||||
|
<ComboBox SelectedIndex="{Binding SortIndex}" Width="100">
|
||||||
|
<ComboBoxItem>
|
||||||
|
<Label VerticalAlignment="Center" HorizontalContentAlignment="Left"
|
||||||
|
Content="{locale:Locale Name}" />
|
||||||
|
</ComboBoxItem>
|
||||||
|
<ComboBoxItem>
|
||||||
|
<Label VerticalAlignment="Center" HorizontalContentAlignment="Left"
|
||||||
|
Content="{locale:Locale Size}" />
|
||||||
|
</ComboBoxItem>
|
||||||
|
</ComboBox>
|
||||||
|
<ComboBox SelectedIndex="{Binding OrderIndex}" Width="150">
|
||||||
|
<ComboBoxItem>
|
||||||
|
<Label VerticalAlignment="Center" HorizontalContentAlignment="Left"
|
||||||
|
Content="{locale:Locale OrderAscending}" />
|
||||||
|
</ComboBoxItem>
|
||||||
|
<ComboBoxItem>
|
||||||
|
<Label VerticalAlignment="Center" HorizontalContentAlignment="Left"
|
||||||
|
Content="{locale:Locale Descending}" />
|
||||||
|
</ComboBoxItem>
|
||||||
|
</ComboBox>
|
||||||
|
</StackPanel>
|
||||||
|
<Grid Grid.Column="1" HorizontalAlignment="Stretch" Margin="10,0, 0, 0">
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="Auto"/>
|
||||||
|
<ColumnDefinition/>
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
<Label Content="{locale:Locale Search}" VerticalAlignment="Center"/>
|
||||||
|
<TextBox Margin="5,0,0,0" Grid.Column="1" HorizontalAlignment="Stretch" Text="{Binding Search}"/>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
<Border Grid.Row="1" Margin="0,5" BorderThickness="1" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
|
||||||
|
<ListBox Name="SaveList" Items="{Binding View}" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
|
||||||
|
<ListBox.ItemTemplate>
|
||||||
|
<DataTemplate x:DataType="models:SaveModel">
|
||||||
|
<Grid HorizontalAlignment="Stretch" Margin="0,5">
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition />
|
||||||
|
<ColumnDefinition Width="Auto" />
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
<StackPanel Grid.Column="0" Orientation="Horizontal">
|
||||||
|
<Border Height="42" Margin="2" Width="42" Padding="10"
|
||||||
|
IsVisible="{Binding !InGameList}">
|
||||||
|
<ui:SymbolIcon Symbol="Help" FontSize="30" HorizontalAlignment="Center"
|
||||||
|
VerticalAlignment="Center" />
|
||||||
|
</Border>
|
||||||
|
<Image IsVisible="{Binding InGameList}"
|
||||||
|
Margin="2"
|
||||||
|
Width="42"
|
||||||
|
Height="42"
|
||||||
|
Source="{Binding Icon, Converter={StaticResource ByteImage}}" />
|
||||||
|
<TextBlock MaxLines="3" Width="320" Margin="5" TextWrapping="Wrap"
|
||||||
|
Text="{Binding Title}" VerticalAlignment="Center" />
|
||||||
|
</StackPanel>
|
||||||
|
<StackPanel Grid.Column="1" Spacing="10" HorizontalAlignment="Right"
|
||||||
|
Orientation="Horizontal">
|
||||||
|
<Label Content="{Binding SizeString}" IsVisible="{Binding SizeAvailable}"
|
||||||
|
VerticalAlignment="Center" HorizontalAlignment="Right" />
|
||||||
|
<Button VerticalAlignment="Center" HorizontalAlignment="Right" Padding="10"
|
||||||
|
MinWidth="0" MinHeight="0" Name="OpenLocation" Command="{Binding OpenLocation}">
|
||||||
|
<ui:SymbolIcon Symbol="OpenFolder" HorizontalAlignment="Center"
|
||||||
|
VerticalAlignment="Center" />
|
||||||
|
</Button>
|
||||||
|
<Button VerticalAlignment="Center" HorizontalAlignment="Right" Padding="10"
|
||||||
|
MinWidth="0" MinHeight="0" Name="Delete" Command="{Binding Delete}">
|
||||||
|
<ui:SymbolIcon Symbol="Delete" HorizontalAlignment="Center"
|
||||||
|
VerticalAlignment="Center" />
|
||||||
|
</Button>
|
||||||
|
</StackPanel>
|
||||||
|
</Grid>
|
||||||
|
</DataTemplate>
|
||||||
|
</ListBox.ItemTemplate>
|
||||||
|
</ListBox>
|
||||||
|
</Border>
|
||||||
|
</Grid>
|
||||||
|
</UserControl>
|
160
Ryujinx.Ava/Ui/Controls/SaveManager.axaml.cs
Normal file
160
Ryujinx.Ava/Ui/Controls/SaveManager.axaml.cs
Normal file
@ -0,0 +1,160 @@
|
|||||||
|
using Avalonia.Controls;
|
||||||
|
using DynamicData;
|
||||||
|
using DynamicData.Binding;
|
||||||
|
using LibHac;
|
||||||
|
using LibHac.Common;
|
||||||
|
using LibHac.Fs;
|
||||||
|
using LibHac.Fs.Shim;
|
||||||
|
using Ryujinx.Ava.Common;
|
||||||
|
using Ryujinx.Ava.Common.Locale;
|
||||||
|
using Ryujinx.Ava.Ui.Models;
|
||||||
|
using Ryujinx.HLE.FileSystem;
|
||||||
|
using Ryujinx.Ui.App.Common;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Collections.ObjectModel;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using UserProfile = Ryujinx.Ava.Ui.Models.UserProfile;
|
||||||
|
|
||||||
|
namespace Ryujinx.Ava.Ui.Controls
|
||||||
|
{
|
||||||
|
public partial class SaveManager : UserControl
|
||||||
|
{
|
||||||
|
private readonly UserProfile _userProfile;
|
||||||
|
private readonly HorizonClient _horizonClient;
|
||||||
|
private readonly VirtualFileSystem _virtualFileSystem;
|
||||||
|
private int _sortIndex;
|
||||||
|
private int _orderIndex;
|
||||||
|
private ObservableCollection<SaveModel> _view = new ObservableCollection<SaveModel>();
|
||||||
|
private string _search;
|
||||||
|
|
||||||
|
public ObservableCollection<SaveModel> Saves { get; set; } = new ObservableCollection<SaveModel>();
|
||||||
|
|
||||||
|
public ObservableCollection<SaveModel> View
|
||||||
|
{
|
||||||
|
get => _view;
|
||||||
|
set => _view = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int SortIndex
|
||||||
|
{
|
||||||
|
get => _sortIndex;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_sortIndex = value;
|
||||||
|
Sort();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int OrderIndex
|
||||||
|
{
|
||||||
|
get => _orderIndex;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_orderIndex = value;
|
||||||
|
Sort();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public string Search
|
||||||
|
{
|
||||||
|
get => _search;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_search = value;
|
||||||
|
Sort();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public SaveManager()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
}
|
||||||
|
|
||||||
|
public SaveManager(UserProfile userProfile, HorizonClient horizonClient, VirtualFileSystem virtualFileSystem)
|
||||||
|
{
|
||||||
|
_userProfile = userProfile;
|
||||||
|
_horizonClient = horizonClient;
|
||||||
|
_virtualFileSystem = virtualFileSystem;
|
||||||
|
InitializeComponent();
|
||||||
|
|
||||||
|
DataContext = this;
|
||||||
|
|
||||||
|
Task.Run(LoadSaves);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void LoadSaves()
|
||||||
|
{
|
||||||
|
Saves.Clear();
|
||||||
|
var saveDataFilter = SaveDataFilter.Make(programId: default, saveType: SaveDataType.Account,
|
||||||
|
new UserId((ulong)_userProfile.UserId.High, (ulong)_userProfile.UserId.Low), saveDataId: default, index: default);
|
||||||
|
|
||||||
|
using var saveDataIterator = new UniqueRef<SaveDataIterator>();
|
||||||
|
|
||||||
|
_horizonClient.Fs.OpenSaveDataIterator(ref saveDataIterator.Ref(), SaveDataSpaceId.User, in saveDataFilter).ThrowIfFailure();
|
||||||
|
|
||||||
|
Span<SaveDataInfo> saveDataInfo = stackalloc SaveDataInfo[10];
|
||||||
|
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
saveDataIterator.Get.ReadSaveDataInfo(out long readCount, saveDataInfo).ThrowIfFailure();
|
||||||
|
|
||||||
|
if (readCount == 0)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < readCount; i++)
|
||||||
|
{
|
||||||
|
var save = saveDataInfo[i];
|
||||||
|
if (save.ProgramId.Value != 0)
|
||||||
|
{
|
||||||
|
var saveModel = new SaveModel(save, _horizonClient, _virtualFileSystem);
|
||||||
|
Saves.Add(saveModel);
|
||||||
|
saveModel.DeleteAction = () => { Saves.Remove(saveModel); };
|
||||||
|
}
|
||||||
|
|
||||||
|
Sort();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Sort()
|
||||||
|
{
|
||||||
|
Saves.AsObservableChangeSet()
|
||||||
|
.Filter(Filter)
|
||||||
|
.Sort(GetComparer())
|
||||||
|
.Bind(out var view).AsObservableList();
|
||||||
|
|
||||||
|
_view.Clear();
|
||||||
|
_view.AddRange(view);
|
||||||
|
}
|
||||||
|
|
||||||
|
private IComparer<SaveModel> GetComparer()
|
||||||
|
{
|
||||||
|
switch (SortIndex)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
return OrderIndex == 0
|
||||||
|
? SortExpressionComparer<SaveModel>.Ascending(save => save.Title)
|
||||||
|
: SortExpressionComparer<SaveModel>.Descending(save => save.Title);
|
||||||
|
case 1:
|
||||||
|
return OrderIndex == 0
|
||||||
|
? SortExpressionComparer<SaveModel>.Ascending(save => save.Size)
|
||||||
|
: SortExpressionComparer<SaveModel>.Descending(save => save.Size);
|
||||||
|
default:
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool Filter(object arg)
|
||||||
|
{
|
||||||
|
if (arg is SaveModel save)
|
||||||
|
{
|
||||||
|
return string.IsNullOrWhiteSpace(_search) || save.Title.ToLower().Contains(_search.ToLower());
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -8,7 +8,8 @@
|
|||||||
Title="Ryujinx - Waiting"
|
Title="Ryujinx - Waiting"
|
||||||
SizeToContent="WidthAndHeight"
|
SizeToContent="WidthAndHeight"
|
||||||
WindowStartupLocation="CenterOwner"
|
WindowStartupLocation="CenterOwner"
|
||||||
mc:Ignorable="d">
|
mc:Ignorable="d"
|
||||||
|
Focusable="True">
|
||||||
<Grid
|
<Grid
|
||||||
Margin="20"
|
Margin="20"
|
||||||
HorizontalAlignment="Stretch"
|
HorizontalAlignment="Stretch"
|
||||||
|
@ -10,8 +10,10 @@
|
|||||||
xmlns:ui="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia"
|
xmlns:ui="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia"
|
||||||
xmlns:viewModels="clr-namespace:Ryujinx.Ava.Ui.ViewModels"
|
xmlns:viewModels="clr-namespace:Ryujinx.Ava.Ui.ViewModels"
|
||||||
Margin="0"
|
Margin="0"
|
||||||
|
MinWidth="500"
|
||||||
Padding="0"
|
Padding="0"
|
||||||
mc:Ignorable="d">
|
mc:Ignorable="d"
|
||||||
|
Focusable="True">
|
||||||
<UserControl.Resources>
|
<UserControl.Resources>
|
||||||
<controls:BitmapArrayValueConverter x:Key="ByteImage" />
|
<controls:BitmapArrayValueConverter x:Key="ByteImage" />
|
||||||
</UserControl.Resources>
|
</UserControl.Resources>
|
||||||
@ -63,7 +65,7 @@
|
|||||||
HorizontalAlignment="Stretch"
|
HorizontalAlignment="Stretch"
|
||||||
MaxLength="{Binding MaxProfileNameLength}"
|
MaxLength="{Binding MaxProfileNameLength}"
|
||||||
Text="{Binding Name}" />
|
Text="{Binding Name}" />
|
||||||
<TextBlock Text="{Locale:Locale UserProfilesUserId}" />
|
<TextBlock Name="IdText" Text="{Locale:Locale UserProfilesUserId}" />
|
||||||
<TextBlock Name="IdLabel" Text="{Binding UserId}" />
|
<TextBlock Name="IdLabel" Text="{Binding UserId}" />
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
<StackPanel
|
<StackPanel
|
||||||
|
@ -36,15 +36,8 @@ namespace Ryujinx.Ava.Ui.Controls
|
|||||||
case NavigationMode.New:
|
case NavigationMode.New:
|
||||||
var args = ((NavigationDialogHost parent, UserProfile profile, bool isNewUser))arg.Parameter;
|
var args = ((NavigationDialogHost parent, UserProfile profile, bool isNewUser))arg.Parameter;
|
||||||
_isNewUser = args.isNewUser;
|
_isNewUser = args.isNewUser;
|
||||||
if (!_isNewUser)
|
_profile = args.profile;
|
||||||
{
|
TempProfile = new TempProfile(_profile);
|
||||||
_profile = args.profile;
|
|
||||||
TempProfile = new TempProfile(_profile);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
TempProfile = new TempProfile();
|
|
||||||
}
|
|
||||||
|
|
||||||
_parent = args.parent;
|
_parent = args.parent;
|
||||||
break;
|
break;
|
||||||
@ -53,7 +46,8 @@ namespace Ryujinx.Ava.Ui.Controls
|
|||||||
DataContext = TempProfile;
|
DataContext = TempProfile;
|
||||||
|
|
||||||
AddPictureButton.IsVisible = _isNewUser;
|
AddPictureButton.IsVisible = _isNewUser;
|
||||||
IdLabel.IsVisible = !_isNewUser;
|
IdLabel.IsVisible = _profile != null;
|
||||||
|
IdText.IsVisible = _profile != null;
|
||||||
ChangePictureButton.IsVisible = !_isNewUser;
|
ChangePictureButton.IsVisible = !_isNewUser;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -87,7 +81,7 @@ namespace Ryujinx.Ava.Ui.Controls
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_profile != null)
|
if (_profile != null && !_isNewUser)
|
||||||
{
|
{
|
||||||
_profile.Name = TempProfile.Name;
|
_profile.Name = TempProfile.Name;
|
||||||
_profile.Image = TempProfile.Image;
|
_profile.Image = TempProfile.Image;
|
||||||
@ -97,7 +91,7 @@ namespace Ryujinx.Ava.Ui.Controls
|
|||||||
}
|
}
|
||||||
else if (_isNewUser)
|
else if (_isNewUser)
|
||||||
{
|
{
|
||||||
_parent.AccountManager.AddUser(TempProfile.Name, TempProfile.Image);
|
_parent.AccountManager.AddUser(TempProfile.Name, TempProfile.Image, TempProfile.UserId);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
71
Ryujinx.Ava/Ui/Controls/UserRecoverer.axaml
Normal file
71
Ryujinx.Ava/Ui/Controls/UserRecoverer.axaml
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
<UserControl xmlns="https://github.com/avaloniaui"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
mc:Ignorable="d"
|
||||||
|
d:DesignWidth="800"
|
||||||
|
d:DesignHeight="450"
|
||||||
|
MinWidth="500"
|
||||||
|
MinHeight="400"
|
||||||
|
xmlns:Locale="clr-namespace:Ryujinx.Ava.Common.Locale"
|
||||||
|
xmlns:ui="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia"
|
||||||
|
xmlns:viewModels="clr-namespace:Ryujinx.Ava.Ui.ViewModels"
|
||||||
|
x:Class="Ryujinx.Ava.Ui.Controls.UserRecoverer"
|
||||||
|
Focusable="True">
|
||||||
|
<Design.DataContext>
|
||||||
|
<viewModels:UserProfileViewModel />
|
||||||
|
</Design.DataContext>
|
||||||
|
<Grid HorizontalAlignment="Stretch"
|
||||||
|
VerticalAlignment="Stretch">
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="Auto"/>
|
||||||
|
<RowDefinition Height="Auto"/>
|
||||||
|
<RowDefinition/>
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
<Button Grid.Row="0"
|
||||||
|
Margin="5"
|
||||||
|
Height="30"
|
||||||
|
Width="50"
|
||||||
|
MinWidth="50"
|
||||||
|
HorizontalAlignment="Left"
|
||||||
|
Command="{Binding GoBack}">
|
||||||
|
<ui:SymbolIcon Symbol="Back"/>
|
||||||
|
</Button>
|
||||||
|
<TextBlock Grid.Row="1"
|
||||||
|
Text="{Locale:Locale UserProfilesRecoverHeading}"/>
|
||||||
|
<ListBox
|
||||||
|
Margin="5"
|
||||||
|
Grid.Row="2"
|
||||||
|
HorizontalAlignment="Stretch"
|
||||||
|
VerticalAlignment="Stretch"
|
||||||
|
Items="{Binding LostProfiles}">
|
||||||
|
<ListBox.ItemTemplate>
|
||||||
|
<DataTemplate>
|
||||||
|
<Border
|
||||||
|
Margin="2"
|
||||||
|
HorizontalAlignment="Stretch"
|
||||||
|
VerticalAlignment="Stretch"
|
||||||
|
ClipToBounds="True"
|
||||||
|
CornerRadius="5">
|
||||||
|
<Grid Margin="0">
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition/>
|
||||||
|
<ColumnDefinition Width="Auto"/>
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
<TextBlock
|
||||||
|
HorizontalAlignment="Stretch"
|
||||||
|
Text="{Binding UserId}"
|
||||||
|
TextAlignment="Left"
|
||||||
|
TextWrapping="Wrap" />
|
||||||
|
<Button Grid.Column="1"
|
||||||
|
HorizontalAlignment="Right"
|
||||||
|
Command="{Binding Recover}"
|
||||||
|
CommandParameter="{Binding}"
|
||||||
|
Content="{Locale:Locale Recover}"/>
|
||||||
|
</Grid>
|
||||||
|
</Border>
|
||||||
|
</DataTemplate>
|
||||||
|
</ListBox.ItemTemplate>
|
||||||
|
</ListBox>
|
||||||
|
</Grid>
|
||||||
|
</UserControl>
|
44
Ryujinx.Ava/Ui/Controls/UserRecoverer.axaml.cs
Normal file
44
Ryujinx.Ava/Ui/Controls/UserRecoverer.axaml.cs
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
using Avalonia;
|
||||||
|
using Avalonia.Controls;
|
||||||
|
using Avalonia.Interactivity;
|
||||||
|
using Avalonia.Markup.Xaml;
|
||||||
|
using FluentAvalonia.UI.Controls;
|
||||||
|
using FluentAvalonia.UI.Navigation;
|
||||||
|
using Ryujinx.Ava.Ui.Models;
|
||||||
|
using Ryujinx.Ava.Ui.ViewModels;
|
||||||
|
|
||||||
|
namespace Ryujinx.Ava.Ui.Controls
|
||||||
|
{
|
||||||
|
public partial class UserRecoverer : UserControl
|
||||||
|
{
|
||||||
|
private UserProfileViewModel _viewModel;
|
||||||
|
private NavigationDialogHost _parent;
|
||||||
|
|
||||||
|
public UserRecoverer()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
AddHandler(Frame.NavigatedToEvent, (s, e) =>
|
||||||
|
{
|
||||||
|
NavigatedTo(e);
|
||||||
|
}, RoutingStrategies.Direct);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void NavigatedTo(NavigationEventArgs arg)
|
||||||
|
{
|
||||||
|
if (Program.PreviewerDetached)
|
||||||
|
{
|
||||||
|
switch (arg.NavigationMode)
|
||||||
|
{
|
||||||
|
case NavigationMode.New:
|
||||||
|
var args = ((NavigationDialogHost parent, UserProfileViewModel viewModel))arg.Parameter;
|
||||||
|
|
||||||
|
_viewModel = args.viewModel;
|
||||||
|
_parent = args.parent;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
DataContext = _viewModel;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -10,8 +10,10 @@
|
|||||||
xmlns:ui="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia"
|
xmlns:ui="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia"
|
||||||
xmlns:viewModels="clr-namespace:Ryujinx.Ava.Ui.ViewModels"
|
xmlns:viewModels="clr-namespace:Ryujinx.Ava.Ui.ViewModels"
|
||||||
d:DesignHeight="450"
|
d:DesignHeight="450"
|
||||||
|
MinWidth="500"
|
||||||
d:DesignWidth="800"
|
d:DesignWidth="800"
|
||||||
mc:Ignorable="d">
|
mc:Ignorable="d"
|
||||||
|
Focusable="True">
|
||||||
<UserControl.Resources>
|
<UserControl.Resources>
|
||||||
<controls:BitmapArrayValueConverter x:Key="ByteImage" />
|
<controls:BitmapArrayValueConverter x:Key="ByteImage" />
|
||||||
</UserControl.Resources>
|
</UserControl.Resources>
|
||||||
@ -25,6 +27,7 @@
|
|||||||
</Grid.RowDefinitions>
|
</Grid.RowDefinitions>
|
||||||
<ListBox
|
<ListBox
|
||||||
Margin="5"
|
Margin="5"
|
||||||
|
MaxHeight="300"
|
||||||
HorizontalAlignment="Stretch"
|
HorizontalAlignment="Stretch"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
DoubleTapped="ProfilesList_DoubleTapped"
|
DoubleTapped="ProfilesList_DoubleTapped"
|
||||||
@ -88,21 +91,56 @@
|
|||||||
</DataTemplate>
|
</DataTemplate>
|
||||||
</ListBox.ItemTemplate>
|
</ListBox.ItemTemplate>
|
||||||
</ListBox>
|
</ListBox>
|
||||||
<StackPanel
|
<Grid
|
||||||
Grid.Row="1"
|
Grid.Row="1"
|
||||||
Margin="10,0"
|
HorizontalAlignment="Center">
|
||||||
HorizontalAlignment="Center"
|
<Grid.RowDefinitions>
|
||||||
Orientation="Horizontal"
|
<RowDefinition Height="Auto"/>
|
||||||
Spacing="10">
|
<RowDefinition Height="Auto"/>
|
||||||
<Button Command="{Binding AddUser}" Content="{Locale:Locale UserProfilesAddNewProfile}" />
|
<RowDefinition Height="Auto"/>
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="Auto"/>
|
||||||
|
<ColumnDefinition Width="Auto"/>
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
<Button
|
||||||
|
HorizontalAlignment="Stretch"
|
||||||
|
Grid.Row="0"
|
||||||
|
Grid.Column="0"
|
||||||
|
Margin="2"
|
||||||
|
Command="{Binding AddUser}"
|
||||||
|
Content="{Locale:Locale UserProfilesAddNewProfile}" />
|
||||||
<Button
|
<Button
|
||||||
|
HorizontalAlignment="Stretch"
|
||||||
|
Grid.Row="0"
|
||||||
|
Margin="2"
|
||||||
|
Grid.Column="1"
|
||||||
Command="{Binding EditUser}"
|
Command="{Binding EditUser}"
|
||||||
Content="{Locale:Locale UserProfilesEditProfile}"
|
Content="{Locale:Locale UserProfilesEditProfile}"
|
||||||
IsEnabled="{Binding IsSelectedProfiledEditable}" />
|
IsEnabled="{Binding IsSelectedProfiledEditable}" />
|
||||||
|
<Button
|
||||||
|
HorizontalAlignment="Stretch"
|
||||||
|
Grid.Row="1"
|
||||||
|
Grid.Column="0"
|
||||||
|
Margin="2"
|
||||||
|
Content="{Locale:Locale UserProfilesManageSaves}"
|
||||||
|
Command="{Binding ManageSaves}" />
|
||||||
<Button
|
<Button
|
||||||
|
HorizontalAlignment="Stretch"
|
||||||
|
Grid.Row="1"
|
||||||
|
Grid.Column="1"
|
||||||
|
Margin="2"
|
||||||
Command="{Binding DeleteUser}"
|
Command="{Binding DeleteUser}"
|
||||||
Content="{Locale:Locale UserProfilesDeleteSelectedProfile}"
|
Content="{Locale:Locale UserProfilesDeleteSelectedProfile}"
|
||||||
IsEnabled="{Binding IsSelectedProfileDeletable}" />
|
IsEnabled="{Binding IsSelectedProfileDeletable}" />
|
||||||
</StackPanel>
|
<Button
|
||||||
|
HorizontalAlignment="Stretch"
|
||||||
|
Grid.Row="2"
|
||||||
|
Grid.ColumnSpan="2"
|
||||||
|
Grid.Column="0"
|
||||||
|
Margin="2"
|
||||||
|
Command="{Binding RecoverLostAccounts}"
|
||||||
|
Content="{Locale:Locale UserProfilesRecoverLostAccounts}" />
|
||||||
|
</Grid>
|
||||||
</Grid>
|
</Grid>
|
||||||
</UserControl>
|
</UserControl>
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user