Compare commits

..

17 Commits

Author SHA1 Message Date
TSRBerry
016262514d cpu: Hotfix missing ToNearest rounding mode cases 2023-07-16 20:39:08 +01:00
TSRBerry
326749498b [Ryujinx.HLE] Address dotnet-format issues (#5380)
* dotnet format style --severity info

Some changes were manually reverted.

* dotnet format analyzers --serverity info

Some changes have been minimally adapted.

* Restore a few unused methods and variables

* Silence dotnet format IDE0060 warnings

* Silence dotnet format IDE0052 warnings

* Address or silence dotnet format IDE1006 warnings

* Address dotnet format CA1816 warnings

* Address or silence dotnet format CA2208 warnings

* Address or silence dotnet format CA1806 and a few CA1854 warnings

* Address dotnet format CA2211 warnings

* Address dotnet format CA1822 warnings

* Address or silence dotnet format CA1069 warnings

* Make dotnet format succeed in style mode

* Address or silence dotnet format CA2211 warnings

* Address review comments

* Address dotnet format CA2208 warnings properly

* Make ProcessResult readonly

* Address most dotnet format whitespace warnings

* Apply dotnet format whitespace formatting

A few of them have been manually reverted and the corresponding warning was silenced

* Add previously silenced warnings back

I have no clue how these disappeared

* Revert formatting changes for while and for-loops

* Format if-blocks correctly

* Run dotnet format style after rebase

* Run dotnet format whitespace after rebase

* Run dotnet format style after rebase

* Run dotnet format analyzers after rebase

* Run dotnet format after rebase and remove unused usings

- analyzers
- style
- whitespace

* Disable 'prefer switch expression' rule

* Add comments to disabled warnings

* Fix a few disabled warnings

* Fix naming rule violation, Convert shader properties to auto-property and convert values to const

* Simplify properties and array initialization, Use const when possible, Remove trailing commas

* Start working on disabled warnings

* Fix and silence a few dotnet-format warnings again

* Run dotnet format after rebase

* Use using declaration instead of block syntax

* Address IDE0251 warnings

* Address a few disabled IDE0060 warnings

* Silence IDE0060 in .editorconfig

* Revert "Simplify properties and array initialization, Use const when possible, Remove trailing commas"

This reverts commit 9462e4136c0a2100dc28b20cf9542e06790aa67e.

* dotnet format whitespace after rebase

* First dotnet format pass

* Fix naming rule violations

* Fix typo

* Add trailing commas, use targeted new and use array initializer

* Fix build issues

* Fix remaining build issues

* Remove SuppressMessage for CA1069 where possible

* Address dotnet format issues

* Address formatting issues

Co-authored-by: Ac_K <acoustik666@gmail.com>

* Add GetHashCode implementation for RenderingSurfaceInfo

* Explicitly silence CA1822 for every affected method in Syscall

* Address formatting issues in Demangler.cs

* Address review feedback

Co-authored-by: Ac_K <acoustik666@gmail.com>

* Revert marking service methods as static

* Next dotnet format pass

* Address review feedback

---------

Co-authored-by: Ac_K <acoustik666@gmail.com>
2023-07-16 19:31:14 +02:00
Mary
fec8291c17 infra: do not assign developers team for now
Hopefully fix PR triage for real...
2023-07-14 11:32:14 +02:00
gdkchan
c5d9e67cb2 Fix some Vulkan validation errors (#5452)
* Fix some validation errors and silence the annoying pipeline barrier error

* Remove bogus decref/incref on index buffer state

* Make unsafe blit opt-in rather than opt-out

* Remove Vulkan debugger messages blacklist

* Adjust GetImageUsage to not set the storage bit for multisample textures if not supported
2023-07-14 09:08:52 +02:00
Mary
e5261228d7 infra: Fix team name in reviewer.yml 2023-07-12 19:22:09 +02:00
Mary
e61c09bc85 infra: Fix PR triage once and for all (#5442)
Switch to a custom made python script that query GitHub API to grab latest state of the PR after label assign.
2023-07-12 18:31:08 +02:00
ealekseychik
ac2444f908 Move ShaderBinaries into individual .spv files (#5280)
* Move ShaderBinaries into individual spv files

* Rename binaries directory, remove variables and add helper method instead

* Update .csproj file

* Move ShaderBinaries into individual spv files

* Rename binaries directory, remove variables and add helper method instead

* Split shader binaries into folders, use string.Join to create filepath

* Move files back to general binaries folder

* Remove ShaderSource suffix from file names

---------

Co-authored-by: Egor Alekseychik <e.alekseychik@syberry.com>
Co-authored-by: Gabriel A <gab.dark.100@gmail.com>
2023-07-11 14:41:18 -03:00
gdkchan
9c6071a645 Move support buffer update out of the backends (#5411)
* Move support buffer update out of the backends

* Fix render scale init and remove redundant state from SupportBufferUpdater

* Stop passing texture scale to the backends

* XML docs for SupportBufferUpdater
2023-07-11 14:07:41 -03:00
gleng
fa32ef9275 MacOS: Allow barriers inside a render pass for non-Apple GPUs and don't treat as TBDR (#5440)
* MoltenVK: Allow barriers inside a render pass on non-Apple GPUs

* Don't treat all non-Apple GPUs using MoltenVK as TBDR
2023-07-11 03:10:23 +02:00
gleng
7805d27e67 MacOS: Fix rendering on AMD GPUs (#5446)
* MacOS: Fix rendering on AMD GPUs

* Only disable MultiViewPort on MoltenVK for AMD GPUs
2023-07-11 03:00:19 +02:00
TSRBerry
6c515e1822 [Ryujinx.Ava] Address dotnet-format issues (#5361)
* dotnet format style --severity info

Some changes were manually reverted.

* dotnet format analyzers --serverity info

Some changes have been minimally adapted.

* Restore a few unused methods and variables

* Silence dotnet format IDE0060 warnings

* Silence dotnet format IDE0052 warnings

* Silence dotnet format IDE0059 warnings

* Address or silence dotnet format IDE1006 warnings

* Address dotnet format CA1816 warnings

* Address dotnet format CA1822 warnings

* Address or silence dotnet format CA1069 warnings

* Make dotnet format succeed in style mode

* Address dotnet format CA1401 warnings

* Address remaining dotnet format analyzer warnings

* Address review comments

* dotnet-format fixes after rebase

* Address most dotnet format whitespace warnings

* Apply dotnet format whitespace formatting

A few of them have been manually reverted and the corresponding warning was silenced

* Format if-blocks correctly

* Another rebase, another dotnet format run

* Run dotnet format whitespace after rebase

* Run dotnet format style after rebase

* Run dotnet format after rebase and remove unused usings

- analyzers
- style
- whitespace

* Add comments to disabled warnings

* Remove a few unused parameters

* Simplify properties and array initialization, Use const when possible, Remove trailing commas

* Start working on disabled warnings

* Fix and silence a few dotnet-format warnings again

* Address IDE0260 warnings

* Address a few disabled IDE0060 warnings

* Silence IDE0060 in .editorconfig

* Revert "Simplify properties and array initialization, Use const when possible, Remove trailing commas"

This reverts commit 9462e4136c0a2100dc28b20cf9542e06790aa67e.

* dotnet format whitespace after rebase

* dotnet format pass with new editorconfig

* Fix naming style issues

* Apply suggestions from code review

Co-authored-by: Ac_K <Acoustik666@gmail.com>

* Revert one suggestion

* Second dotnet format pass and fix build issues

* Final pass of dotnet format

* Add trailing commas

* Fix formatting issues

* Keep unnecessary assignment in IconColorPicker.cs

* Use using declarations and extend resource lifetimes

* Fix rebase issues

* Adjust comment spacing

* Fix typo

* Fix naming issues

* Apply suggestions from code review

Co-authored-by: Ac_K <Acoustik666@gmail.com>

* Revert unintentional change

* Remove unused file

* Remove static keyword from ViewModels

Binding of static members doesn't work and is silently ignored.

---------

Co-authored-by: Ac_K <Acoustik666@gmail.com>
2023-07-07 23:03:27 +02:00
Mary
8a363b5df2 Revert "sdl: set SDL_HINT_GAMECONTROLLER_USE_BUTTON_LABELS to 0 (#5433)" (#5439)
This reverts commit 2b5abac809.
2023-07-06 18:08:14 +02:00
SuperSamus
2b5abac809 sdl: set SDL_HINT_GAMECONTROLLER_USE_BUTTON_LABELS to 0 (#5433)
Nintendo controllers notoriously have the A/B and X/Y buttons swapped, compared to the standard.
In order to combat this, when setting the default controller layout, Ryujinx checks whether the controller name contains "Nintendo", and swaps the mapping accordingly.
However, the reason the mapping is inverted in the first place is because SDL has `SDL_HINT_GAMECONTROLLER_USE_BUTTON_LABELS` set to 1 by default. By setting it to 0, the mapping will be based on the buttons' position instead.
So, by doing it (and removing the `isNintendoStyle` variable), we get the following advantages:
- The mapping will be the same on all controllers, removing the need to adjust custom mappings depending on what controller is used
- Users who already set `SDL_HINT_GAMECONTROLLER_USE_BUTTON_LABELS` to 0 globally for other games/applications (like me) won't have a wrong default mapping
- Checking whether the controller name contains "Nintendo" is ugly

Disadvantages:
- Breaks the controller configuration for existing users who are using a Nintendo controller
2023-07-06 17:11:26 +02:00
Theun de Bruijn
c19c8bbade Headless: Add support for fullscreen option (#5339)
* Headless: Added support for fullscreen option

* Headless: cleanup of fullscreen support

* Headless: fullscreen support : implemented proposed changes

* Headless: fullscreen support: cleanup

* Headless: fullscreen support: fix for OpenGL scaling

* Headless: fullscreen support: cleanup

* Headless: fullscreen support: cleanup

* Headless: fullscreen support: add. macOS fullscreen fix

* Headless: fullscreen support: cleanup

* Headless: fullscreen support: cleanup

* Headless: fullscreen support: cleanup
2023-07-06 12:10:15 +02:00
gdkchan
1c7a90ef35 Stop identifying shader textures with handle and cbuf, use binding instead (#5266)
* Stop identifying shader textures with handle and cbuf, use binding instead

* Remove now unused code

* Consider image operations as having accurate type information too

I don't know why that was not the case before

* Fix missing unscale on InsertCoordNormalization, stop calling SetUsageFlagsForTextureQuery when not needed

* Shader cache version bump

* Change get texture methods to return descriptors created from ResourceManager state

 This is required to ensure that reserved textures and images will not be bound as a guest texture/image

* Fix BindlessElimination.SetHandle inserting coords at the wrong place
2023-07-03 14:29:27 -03:00
TSRBerry
3b46bb73f7 [Ryujinx.Graphics.Gpu] Address dotnet-format issues (#5367)
* dotnet format style --severity info

Some changes were manually reverted.

* dotnet format analyzers --serverity info

Some changes have been minimally adapted.

* Restore a few unused methods and variables

* Silence dotnet format IDE0060 warnings

* Silence dotnet format IDE0052 warnings

* Address dotnet format CA1816 warnings

* Address or silence dotnet format CA1069 warnings

* Address or silence dotnet format CA2211 warnings

* Address remaining dotnet format analyzer warnings

* Address review comments

* Address most dotnet format whitespace warnings

* Apply dotnet format whitespace formatting

A few of them have been manually reverted and the corresponding warning was silenced

* Format if-blocks correctly

* Run dotnet format whitespace after rebase

* Run dotnet format style after rebase

* Another rebase, another dotnet format run

* Run dotnet format style after rebase

* Run dotnet format after rebase and remove unused usings

- analyzers
- style
- whitespace

* Disable 'prefer switch expression' rule

* Add comments to disabled warnings

* Remove a few unused parameters

* Replace MmeShadowScratch with Array256<uint>

* Simplify properties and array initialization, Use const when possible, Remove trailing commas

* Start working on disabled warnings

* Fix and silence a few dotnet-format warnings again

* Run dotnet format after rebase

* Address IDE0251 warnings

* Silence IDE0060 in .editorconfig

* Revert "Simplify properties and array initialization, Use const when possible, Remove trailing commas"

This reverts commit 9462e4136c0a2100dc28b20cf9542e06790aa67e.

* dotnet format whitespace after rebase

* First pass of dotnet format

* Add unsafe dotnet format changes

* Fix typos

* Add trailing commas

* Disable formatting for FormatTable

* Address review feedback
2023-07-02 02:47:54 +02:00
TSRBerry
2457cfc911 Fix naming issue in ControllerWindow (#5424) 2023-07-02 02:26:32 +02:00
1379 changed files with 12063 additions and 14485 deletions

View File

@@ -1,8 +0,0 @@
addReviewers: true
reviewers:
- marysaka
filterLabels:
include:
- audio

View File

@@ -1,11 +0,0 @@
addReviewers: true
reviewers:
- gdkchan
- riperiperi
- marysaka
- LDj3SNuD
filterLabels:
include:
- cpu

View File

@@ -1,4 +0,0 @@
addReviewers: true
reviewers:
- Ryujinx/developers

View File

@@ -1,10 +0,0 @@
addReviewers: true
reviewers:
- gdkchan
- riperiperi
- marysaka
filterLabels:
include:
- gpu

View File

@@ -1,11 +0,0 @@
addReviewers: true
reviewers:
- Ack77
- emmauss
- TSRBerry
- marysaka
filterLabels:
include:
- gui

View File

@@ -1,11 +0,0 @@
addReviewers: true
reviewers:
- gdkchan
- Ack77
- marysaka
- TSRBerry
filterLabels:
include:
- horizon

View File

@@ -1,9 +0,0 @@
addReviewers: true
reviewers:
- marysaka
- TSRBerry
filterLabels:
include:
- infra

32
.github/reviewers.yml vendored Normal file
View File

@@ -0,0 +1,32 @@
audio:
- marysaka
cpu:
- gdkchan
- riperiperi
- marysaka
- LDj3SNuD
gpu:
- gdkchan
- riperiperi
- marysaka
gui:
- Ack77
- emmauss
- TSRBerry
- marysaka
horizon:
- gdkchan
- Ack77
- marysaka
- TSRBerry
infra:
- marysaka
- TSRBerry
default:
- marysaka

79
.github/update_reviewers.py vendored Normal file
View File

@@ -0,0 +1,79 @@
from pathlib import Path
from typing import List, Set
from github import Github
from github.Repository import Repository
from github.GithubException import GithubException
import sys
import yaml
def add_reviewers(
reviewers: Set[str], team_reviewers: Set[str], new_entries: List[str]
):
for reviewer in new_entries:
if reviewer.startswith("@"):
team_reviewers.add(reviewer[1:])
else:
reviewers.add(reviewer)
def update_reviewers(config, repo: Repository, pr_id: int) -> int:
pull_request = repo.get_pull(pr_id)
if not pull_request:
sys.stderr.writable(f"Unknown PR #{pr_id}\n")
return 1
pull_request_author = pull_request.user.login
reviewers = set()
team_reviewers = set()
for label in pull_request.labels:
if label.name in config:
add_reviewers(reviewers, team_reviewers, config[label.name])
if "default" in config:
add_reviewers(reviewers, team_reviewers, config["default"])
if pull_request_author in reviewers:
reviewers.remove(pull_request_author)
try:
reviewers = list(reviewers)
team_reviewers = list(team_reviewers)
print(
f"Attempting to assign reviewers ({reviewers}) and team_reviewers ({team_reviewers})"
)
pull_request.create_review_request(reviewers, team_reviewers)
return 0
except GithubException as e:
sys.stderr.write(f"Cannot assign review request for PR #{pr_id}: {e}\n")
return 1
if __name__ == "__main__":
if len(sys.argv) != 5:
sys.stderr.write("usage: <token> <repo_path> <pr_id> <config_path>\n")
sys.exit(1)
token = sys.argv[1]
repo_path = sys.argv[2]
pr_id = int(sys.argv[3])
config_path = Path(sys.argv[4])
g = Github(token)
repo = g.get_repo(repo_path)
if not repo:
sys.stderr.write("Repository not found!\n")
sys.exit(1)
if not config_path.exists():
sys.stderr.write(f'Config "{config_path}" not found!\n')
sys.exit(1)
with open(config_path, "r") as f:
config = yaml.safe_load(f)
sys.exit(update_reviewers(config, repo, pr_id))

View File

@@ -12,43 +12,23 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
# Grab sources to get update_reviewers.py and reviewers.yml
- name: Fetch sources
uses: actions/checkout@v3
with:
# Ensure we pin the source origin as pull_request_target run under forks.
fetch-depth: 0
repository: Ryujinx/Ryujinx
ref: master
- name: Update labels based on changes - name: Update labels based on changes
uses: actions/labeler@v4 uses: actions/labeler@v4
with: with:
sync-labels: true sync-labels: true
dot: true dot: true
- name: Auto Assign [Audio] - name: Assign reviewers
uses: kentaro-m/auto-assign-action@v1.2.5 run: |
with: pip3 install PyGithub
configuration-path: '.github/assign/audio.yml' python3 .github/update_reviewers.py ${{ secrets.GITHUB_TOKEN }} ${{ github.repository }} ${{ github.event.pull_request.number }} .github/reviewers.yml
shell: bash
- name: Auto Assign [CPU]
uses: kentaro-m/auto-assign-action@v1.2.5
with:
configuration-path: '.github/assign/cpu.yml'
- name: Auto Assign [GPU]
uses: kentaro-m/auto-assign-action@v1.2.5
with:
configuration-path: '.github/assign/gpu.yml'
- name: Auto Assign [GUI]
uses: kentaro-m/auto-assign-action@v1.2.5
with:
configuration-path: '.github/assign/gui.yml'
- name: Auto Assign [Horizon]
uses: kentaro-m/auto-assign-action@v1.2.5
with:
configuration-path: '.github/assign/horizon.yml'
- name: Auto Assign [Infra]
uses: kentaro-m/auto-assign-action@v1.2.5
with:
configuration-path: '.github/assign/infra.yml'
- name: Auto Assign [Global]
uses: kentaro-m/auto-assign-action@v1.2.5
with:
configuration-path: '.github/assign/global.yml'

View File

@@ -1448,6 +1448,7 @@ namespace ARMeilleure.Instructions
{ {
var overflowToInf = fpcr.GetRoundingMode() switch var overflowToInf = fpcr.GetRoundingMode() switch
{ {
FPRoundingMode.ToNearest => true,
FPRoundingMode.TowardsPlusInfinity => !sign, FPRoundingMode.TowardsPlusInfinity => !sign,
FPRoundingMode.TowardsMinusInfinity => sign, FPRoundingMode.TowardsMinusInfinity => sign,
FPRoundingMode.TowardsZero => false, FPRoundingMode.TowardsZero => false,
@@ -2879,6 +2880,7 @@ namespace ARMeilleure.Instructions
{ {
var overflowToInf = fpcr.GetRoundingMode() switch var overflowToInf = fpcr.GetRoundingMode() switch
{ {
FPRoundingMode.ToNearest => true,
FPRoundingMode.TowardsPlusInfinity => !sign, FPRoundingMode.TowardsPlusInfinity => !sign,
FPRoundingMode.TowardsMinusInfinity => sign, FPRoundingMode.TowardsMinusInfinity => sign,
FPRoundingMode.TowardsZero => false, FPRoundingMode.TowardsZero => false,

View File

@@ -5,7 +5,6 @@ using Avalonia.Styling;
using Avalonia.Threading; using Avalonia.Threading;
using FluentAvalonia.Styling; using FluentAvalonia.Styling;
using Ryujinx.Ava.Common.Locale; using Ryujinx.Ava.Common.Locale;
using Ryujinx.Ava.UI.Controls;
using Ryujinx.Ava.UI.Helpers; using Ryujinx.Ava.UI.Helpers;
using Ryujinx.Ava.UI.Windows; using Ryujinx.Ava.UI.Windows;
using Ryujinx.Common; using Ryujinx.Common;
@@ -67,7 +66,7 @@ namespace Ryujinx.Ava
if (result == UserResult.Yes) if (result == UserResult.Yes)
{ {
var path = Process.GetCurrentProcess().MainModule.FileName; var path = Environment.ProcessPath;
var proc = Process.Start(path, CommandLineState.Arguments); var proc = Process.Start(path, CommandLineState.Arguments);
desktop.Shutdown(); desktop.Shutdown();
Environment.Exit(0); Environment.Exit(0);

View File

@@ -1,4 +1,5 @@
using ARMeilleure.Translation; using ARMeilleure.Translation;
using Avalonia;
using Avalonia.Controls; using Avalonia.Controls;
using Avalonia.Controls.ApplicationLifetimes; using Avalonia.Controls.ApplicationLifetimes;
using Avalonia.Input; using Avalonia.Input;
@@ -26,6 +27,7 @@ using Ryujinx.Graphics.GAL.Multithreading;
using Ryujinx.Graphics.Gpu; using Ryujinx.Graphics.Gpu;
using Ryujinx.Graphics.OpenGL; using Ryujinx.Graphics.OpenGL;
using Ryujinx.Graphics.Vulkan; using Ryujinx.Graphics.Vulkan;
using Ryujinx.HLE;
using Ryujinx.HLE.FileSystem; using Ryujinx.HLE.FileSystem;
using Ryujinx.HLE.HOS; using Ryujinx.HLE.HOS;
using Ryujinx.HLE.HOS.Services.Account.Acc; using Ryujinx.HLE.HOS.Services.Account.Acc;
@@ -41,7 +43,6 @@ using SixLabors.ImageSharp;
using SixLabors.ImageSharp.Formats.Png; using SixLabors.ImageSharp.Formats.Png;
using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing; using SixLabors.ImageSharp.Processing;
using SPB.Graphics.Exceptions;
using SPB.Graphics.Vulkan; using SPB.Graphics.Vulkan;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
@@ -50,10 +51,12 @@ using System.IO;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using static Ryujinx.Ava.UI.Helpers.Win32NativeInterop; using static Ryujinx.Ava.UI.Helpers.Win32NativeInterop;
using AntiAliasing = Ryujinx.Common.Configuration.AntiAliasing;
using Image = SixLabors.ImageSharp.Image; using Image = SixLabors.ImageSharp.Image;
using InputManager = Ryujinx.Input.HLE.InputManager; using InputManager = Ryujinx.Input.HLE.InputManager;
using Key = Ryujinx.Input.Key; using Key = Ryujinx.Input.Key;
using MouseButton = Ryujinx.Input.MouseButton; using MouseButton = Ryujinx.Input.MouseButton;
using ScalingFilter = Ryujinx.Common.Configuration.ScalingFilter;
using Size = Avalonia.Size; using Size = Avalonia.Size;
using Switch = Ryujinx.HLE.Switch; using Switch = Ryujinx.HLE.Switch;
@@ -66,9 +69,9 @@ namespace Ryujinx.Ava
private const int TargetFps = 60; private const int TargetFps = 60;
private const float VolumeDelta = 0.05f; private const float VolumeDelta = 0.05f;
private static readonly Cursor InvisibleCursor = new(StandardCursorType.None); private static readonly Cursor _invisibleCursor = new(StandardCursorType.None);
private readonly IntPtr InvisibleCursorWin; private readonly IntPtr _invisibleCursorWin;
private readonly IntPtr DefaultCursorWin; private readonly IntPtr _defaultCursorWin;
private readonly long _ticksPerFrame; private readonly long _ticksPerFrame;
private readonly Stopwatch _chrono; private readonly Stopwatch _chrono;
@@ -81,7 +84,7 @@ namespace Ryujinx.Ava
private readonly MainWindowViewModel _viewModel; private readonly MainWindowViewModel _viewModel;
private readonly IKeyboard _keyboardInterface; private readonly IKeyboard _keyboardInterface;
private readonly TopLevel _topLevel; private readonly TopLevel _topLevel;
public RendererHost _rendererHost; public RendererHost RendererHost;
private readonly GraphicsDebugLevel _glLogLevel; private readonly GraphicsDebugLevel _glLogLevel;
private float _newVolume; private float _newVolume;
@@ -94,7 +97,7 @@ namespace Ryujinx.Ava
private bool _isActive; private bool _isActive;
private bool _renderingStarted; private bool _renderingStarted;
private ManualResetEvent _gpuDoneEvent; private readonly ManualResetEvent _gpuDoneEvent;
private IRenderer _renderer; private IRenderer _renderer;
private readonly Thread _renderingThread; private readonly Thread _renderingThread;
@@ -150,14 +153,14 @@ namespace Ryujinx.Ava
VirtualFileSystem = virtualFileSystem; VirtualFileSystem = virtualFileSystem;
ContentManager = contentManager; ContentManager = contentManager;
_rendererHost = renderer; RendererHost = renderer;
_chrono = new Stopwatch(); _chrono = new Stopwatch();
_ticksPerFrame = Stopwatch.Frequency / TargetFps; _ticksPerFrame = Stopwatch.Frequency / TargetFps;
if (ApplicationPath.StartsWith("@SystemContent")) if (ApplicationPath.StartsWith("@SystemContent"))
{ {
ApplicationPath = _viewModel.VirtualFileSystem.SwitchPathToSystemPath(ApplicationPath); ApplicationPath = VirtualFileSystem.SwitchPathToSystemPath(ApplicationPath);
_isFirmwareTitle = true; _isFirmwareTitle = true;
} }
@@ -170,8 +173,8 @@ namespace Ryujinx.Ava
if (OperatingSystem.IsWindows()) if (OperatingSystem.IsWindows())
{ {
InvisibleCursorWin = CreateEmptyCursor(); _invisibleCursorWin = CreateEmptyCursor();
DefaultCursorWin = CreateArrowCursor(); _defaultCursorWin = CreateArrowCursor();
} }
ConfigurationState.Instance.System.IgnoreMissingServices.Event += UpdateIgnoreMissingServicesState; ConfigurationState.Instance.System.IgnoreMissingServices.Event += UpdateIgnoreMissingServicesState;
@@ -196,10 +199,10 @@ namespace Ryujinx.Ava
{ {
_lastCursorMoveTime = Stopwatch.GetTimestamp(); _lastCursorMoveTime = Stopwatch.GetTimestamp();
if (_rendererHost.EmbeddedWindow.TransformedBounds != null) if (RendererHost.EmbeddedWindow.TransformedBounds != null)
{ {
var point = e.GetCurrentPoint(window).Position; var point = e.GetCurrentPoint(window).Position;
var bounds = _rendererHost.EmbeddedWindow.TransformedBounds.Value.Clip; var bounds = RendererHost.EmbeddedWindow.TransformedBounds.Value.Clip;
_isCursorInRenderer = point.X >= bounds.X && _isCursorInRenderer = point.X >= bounds.X &&
point.X <= bounds.Width + bounds.X && point.X <= bounds.Width + bounds.X &&
@@ -220,7 +223,7 @@ namespace Ryujinx.Ava
_renderer.Window?.SetScalingFilterLevel(ConfigurationState.Instance.Graphics.ScalingFilterLevel.Value); _renderer.Window?.SetScalingFilterLevel(ConfigurationState.Instance.Graphics.ScalingFilterLevel.Value);
} }
private void UpdateScalingFilter(object sender, ReactiveEventArgs<Ryujinx.Common.Configuration.ScalingFilter> e) private void UpdateScalingFilter(object sender, ReactiveEventArgs<ScalingFilter> e)
{ {
_renderer.Window?.SetScalingFilter((Graphics.GAL.ScalingFilter)ConfigurationState.Instance.Graphics.ScalingFilter.Value); _renderer.Window?.SetScalingFilter((Graphics.GAL.ScalingFilter)ConfigurationState.Instance.Graphics.ScalingFilter.Value);
_renderer.Window?.SetScalingFilterLevel(ConfigurationState.Instance.Graphics.ScalingFilterLevel.Value); _renderer.Window?.SetScalingFilterLevel(ConfigurationState.Instance.Graphics.ScalingFilterLevel.Value);
@@ -234,7 +237,7 @@ namespace Ryujinx.Ava
if (OperatingSystem.IsWindows()) if (OperatingSystem.IsWindows())
{ {
SetCursor(DefaultCursorWin); SetCursor(_defaultCursorWin);
} }
}); });
} }
@@ -243,11 +246,11 @@ namespace Ryujinx.Ava
{ {
Dispatcher.UIThread.Post(() => Dispatcher.UIThread.Post(() =>
{ {
_viewModel.Cursor = InvisibleCursor; _viewModel.Cursor = _invisibleCursor;
if (OperatingSystem.IsWindows()) if (OperatingSystem.IsWindows())
{ {
SetCursor(InvisibleCursorWin); SetCursor(_invisibleCursorWin);
} }
}); });
} }
@@ -276,7 +279,7 @@ namespace Ryujinx.Ava
string directory = AppDataManager.Mode switch string directory = AppDataManager.Mode switch
{ {
AppDataManager.LaunchMode.Portable or AppDataManager.LaunchMode.Custom => Path.Combine(AppDataManager.BaseDirPath, "screenshots"), AppDataManager.LaunchMode.Portable or AppDataManager.LaunchMode.Custom => Path.Combine(AppDataManager.BaseDirPath, "screenshots"),
_ => Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyPictures), "Ryujinx") _ => Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyPictures), "Ryujinx"),
}; };
string path = Path.Combine(directory, filename); string path = Path.Combine(directory, filename);
@@ -305,9 +308,9 @@ namespace Ryujinx.Ava
image.Mutate(x => x.Flip(FlipMode.Vertical)); image.Mutate(x => x.Flip(FlipMode.Vertical));
} }
image.SaveAsPng(path, new PngEncoder() image.SaveAsPng(path, new PngEncoder
{ {
ColorType = PngColorType.Rgb ColorType = PngColorType.Rgb,
}); });
image.Dispose(); image.Dispose();
@@ -348,9 +351,9 @@ namespace Ryujinx.Ava
_viewModel.Title = $"Ryujinx {Program.Version} -{titleNameSection}{titleVersionSection}{titleIdSection}{titleArchSection}"; _viewModel.Title = $"Ryujinx {Program.Version} -{titleNameSection}{titleVersionSection}{titleIdSection}{titleArchSection}";
}); });
_viewModel.SetUIProgressHandlers(Device); _viewModel.SetUiProgressHandlers(Device);
_rendererHost.SizeChanged += Window_SizeChanged; RendererHost.SizeChanged += Window_SizeChanged;
_isActive = true; _isActive = true;
@@ -379,7 +382,7 @@ namespace Ryujinx.Ava
} }
} }
private void UpdateAntiAliasing(object sender, ReactiveEventArgs<Ryujinx.Common.Configuration.AntiAliasing> e) private void UpdateAntiAliasing(object sender, ReactiveEventArgs<AntiAliasing> e)
{ {
_renderer?.Window?.SetAntiAliasing((Graphics.GAL.AntiAliasing)e.NewValue); _renderer?.Window?.SetAntiAliasing((Graphics.GAL.AntiAliasing)e.NewValue);
} }
@@ -448,7 +451,7 @@ namespace Ryujinx.Ava
{ {
if (Device.Processes != null) if (Device.Processes != null)
{ {
_viewModel.UpdateGameMetadata(Device.Processes.ActiveApplication.ProgramIdText); MainWindowViewModel.UpdateGameMetadata(Device.Processes.ActiveApplication.ProgramIdText);
} }
ConfigurationState.Instance.System.IgnoreMissingServices.Event -= UpdateIgnoreMissingServicesState; ConfigurationState.Instance.System.IgnoreMissingServices.Event -= UpdateIgnoreMissingServicesState;
@@ -477,7 +480,7 @@ namespace Ryujinx.Ava
_windowsMultimediaTimerResolution = null; _windowsMultimediaTimerResolution = null;
} }
if (_rendererHost.EmbeddedWindow is EmbeddedWindowOpenGL openGlWindow) if (RendererHost.EmbeddedWindow is EmbeddedWindowOpenGL openGlWindow)
{ {
// Try to bind the OpenGL context before calling the shutdown event. // Try to bind the OpenGL context before calling the shutdown event.
openGlWindow.MakeCurrent(false, false); openGlWindow.MakeCurrent(false, false);
@@ -508,7 +511,7 @@ namespace Ryujinx.Ava
SystemVersion firmwareVersion = ContentManager.GetCurrentFirmwareVersion(); SystemVersion firmwareVersion = ContentManager.GetCurrentFirmwareVersion();
if (Avalonia.Application.Current.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) if (Application.Current.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
{ {
if (!SetupValidator.CanStartApplication(ContentManager, ApplicationPath, out UserError userError)) if (!SetupValidator.CanStartApplication(ContentManager, ApplicationPath, out UserError userError))
{ {
@@ -526,7 +529,7 @@ namespace Ryujinx.Ava
if (result != UserResult.Yes) if (result != UserResult.Yes)
{ {
await UserErrorDialog.ShowUserErrorDialog(userError, (desktop.MainWindow as MainWindow)); await UserErrorDialog.ShowUserErrorDialog(userError);
Device.Dispose(); Device.Dispose();
return false; return false;
@@ -535,7 +538,7 @@ namespace Ryujinx.Ava
if (!SetupValidator.TryFixStartApplication(ContentManager, ApplicationPath, userError, out _)) if (!SetupValidator.TryFixStartApplication(ContentManager, ApplicationPath, userError, out _))
{ {
await UserErrorDialog.ShowUserErrorDialog(userError, (desktop.MainWindow as MainWindow)); await UserErrorDialog.ShowUserErrorDialog(userError);
Device.Dispose(); Device.Dispose();
return false; return false;
@@ -558,7 +561,7 @@ namespace Ryujinx.Ava
} }
else else
{ {
await UserErrorDialog.ShowUserErrorDialog(userError, (desktop.MainWindow as MainWindow)); await UserErrorDialog.ShowUserErrorDialog(userError);
Device.Dispose(); Device.Dispose();
return false; return false;
@@ -727,7 +730,7 @@ namespace Ryujinx.Ava
{ {
renderer = new VulkanRenderer( renderer = new VulkanRenderer(
Vk.GetApi(), Vk.GetApi(),
(_rendererHost.EmbeddedWindow as EmbeddedWindowVulkan).CreateSurface, (RendererHost.EmbeddedWindow as EmbeddedWindowVulkan).CreateSurface,
VulkanHelper.GetRequiredInstanceExtensions, VulkanHelper.GetRequiredInstanceExtensions,
ConfigurationState.Instance.Graphics.PreferredGpu.Value); ConfigurationState.Instance.Graphics.PreferredGpu.Value);
} }
@@ -738,18 +741,18 @@ namespace Ryujinx.Ava
BackendThreading threadingMode = ConfigurationState.Instance.Graphics.BackendThreading; BackendThreading threadingMode = ConfigurationState.Instance.Graphics.BackendThreading;
var isGALthreaded = threadingMode == BackendThreading.On || (threadingMode == BackendThreading.Auto && renderer.PreferThreading); var isGALThreaded = threadingMode == BackendThreading.On || (threadingMode == BackendThreading.Auto && renderer.PreferThreading);
if (isGALthreaded) if (isGALThreaded)
{ {
renderer = new ThreadedRenderer(renderer); renderer = new ThreadedRenderer(renderer);
} }
Logger.Info?.PrintMsg(LogClass.Gpu, $"Backend Threading ({threadingMode}): {isGALthreaded}"); Logger.Info?.PrintMsg(LogClass.Gpu, $"Backend Threading ({threadingMode}): {isGALThreaded}");
// Initialize Configuration. // Initialize Configuration.
var memoryConfiguration = ConfigurationState.Instance.System.ExpandRam.Value ? HLE.MemoryConfiguration.MemoryConfiguration6GiB : HLE.MemoryConfiguration.MemoryConfiguration4GiB; var memoryConfiguration = ConfigurationState.Instance.System.ExpandRam.Value ? MemoryConfiguration.MemoryConfiguration6GiB : MemoryConfiguration.MemoryConfiguration4GiB;
HLE.HLEConfiguration configuration = new(VirtualFileSystem, HLEConfiguration configuration = new(VirtualFileSystem,
_viewModel.LibHacHorizonManager, _viewModel.LibHacHorizonManager,
ContentManager, ContentManager,
_accountManager, _accountManager,
@@ -780,12 +783,12 @@ namespace Ryujinx.Ava
private static IHardwareDeviceDriver InitializeAudio() private static IHardwareDeviceDriver InitializeAudio()
{ {
var availableBackends = new List<AudioBackend>() var availableBackends = new List<AudioBackend>
{ {
AudioBackend.SDL2, AudioBackend.SDL2,
AudioBackend.SoundIo, AudioBackend.SoundIo,
AudioBackend.OpenAl, AudioBackend.OpenAl,
AudioBackend.Dummy AudioBackend.Dummy,
}; };
AudioBackend preferredBackend = ConfigurationState.Instance.System.AudioBackend.Value; AudioBackend preferredBackend = ConfigurationState.Instance.System.AudioBackend.Value;
@@ -806,13 +809,11 @@ namespace Ryujinx.Ava
{ {
return new T(); return new T();
} }
else
{
Logger.Warning?.Print(LogClass.Audio, $"{backend} is not supported, falling back to {nextBackend}."); Logger.Warning?.Print(LogClass.Audio, $"{backend} is not supported, falling back to {nextBackend}.");
return null; return null;
} }
}
IHardwareDeviceDriver deviceDriver = null; IHardwareDeviceDriver deviceDriver = null;
@@ -826,7 +827,7 @@ namespace Ryujinx.Ava
AudioBackend.SDL2 => InitializeAudioBackend<SDL2HardwareDeviceDriver>(AudioBackend.SDL2, nextBackend), AudioBackend.SDL2 => InitializeAudioBackend<SDL2HardwareDeviceDriver>(AudioBackend.SDL2, nextBackend),
AudioBackend.SoundIo => InitializeAudioBackend<SoundIoHardwareDeviceDriver>(AudioBackend.SoundIo, nextBackend), AudioBackend.SoundIo => InitializeAudioBackend<SoundIoHardwareDeviceDriver>(AudioBackend.SoundIo, nextBackend),
AudioBackend.OpenAl => InitializeAudioBackend<OpenALHardwareDeviceDriver>(AudioBackend.OpenAl, nextBackend), AudioBackend.OpenAl => InitializeAudioBackend<OpenALHardwareDeviceDriver>(AudioBackend.OpenAl, nextBackend),
_ => new DummyHardwareDeviceDriver() _ => new DummyHardwareDeviceDriver(),
}; };
if (deviceDriver != null) if (deviceDriver != null)
@@ -879,7 +880,7 @@ namespace Ryujinx.Ava
_renderer.ScreenCaptured += Renderer_ScreenCaptured; _renderer.ScreenCaptured += Renderer_ScreenCaptured;
(_rendererHost.EmbeddedWindow as EmbeddedWindowOpenGL)?.InitializeBackgroundContext(_renderer); (RendererHost.EmbeddedWindow as EmbeddedWindowOpenGL)?.InitializeBackgroundContext(_renderer);
Device.Gpu.Renderer.Initialize(_glLogLevel); Device.Gpu.Renderer.Initialize(_glLogLevel);
@@ -887,8 +888,8 @@ namespace Ryujinx.Ava
_renderer?.Window?.SetScalingFilter((Graphics.GAL.ScalingFilter)ConfigurationState.Instance.Graphics.ScalingFilter.Value); _renderer?.Window?.SetScalingFilter((Graphics.GAL.ScalingFilter)ConfigurationState.Instance.Graphics.ScalingFilter.Value);
_renderer?.Window?.SetScalingFilterLevel(ConfigurationState.Instance.Graphics.ScalingFilterLevel.Value); _renderer?.Window?.SetScalingFilterLevel(ConfigurationState.Instance.Graphics.ScalingFilterLevel.Value);
Width = (int)_rendererHost.Bounds.Width; Width = (int)RendererHost.Bounds.Width;
Height = (int)_rendererHost.Bounds.Height; Height = (int)RendererHost.Bounds.Height;
_renderer.Window.SetSize((int)(Width * _topLevel.PlatformImpl.RenderScaling), (int)(Height * _topLevel.PlatformImpl.RenderScaling)); _renderer.Window.SetSize((int)(Width * _topLevel.PlatformImpl.RenderScaling), (int)(Height * _topLevel.PlatformImpl.RenderScaling));
@@ -923,7 +924,7 @@ namespace Ryujinx.Ava
_viewModel.SwitchToRenderer(false); _viewModel.SwitchToRenderer(false);
} }
Device.PresentFrame(() => (_rendererHost.EmbeddedWindow as EmbeddedWindowOpenGL)?.SwapBuffers()); Device.PresentFrame(() => (RendererHost.EmbeddedWindow as EmbeddedWindowOpenGL)?.SwapBuffers());
} }
if (_ticks >= _ticksPerFrame) if (_ticks >= _ticksPerFrame)
@@ -941,7 +942,7 @@ namespace Ryujinx.Ava
_gpuDoneEvent.Set(); _gpuDoneEvent.Set();
}); });
(_rendererHost.EmbeddedWindow as EmbeddedWindowOpenGL)?.MakeCurrent(true); (RendererHost.EmbeddedWindow as EmbeddedWindowOpenGL)?.MakeCurrent(true);
} }
public void UpdateStatus() public void UpdateStatus()

View File

@@ -18,7 +18,6 @@ using Ryujinx.Ava.UI.Helpers;
using Ryujinx.Ava.UI.Windows; using Ryujinx.Ava.UI.Windows;
using Ryujinx.Common.Logging; using Ryujinx.Common.Logging;
using Ryujinx.HLE.FileSystem; using Ryujinx.HLE.FileSystem;
using Ryujinx.HLE.HOS;
using Ryujinx.HLE.HOS.Services.Account.Acc; using Ryujinx.HLE.HOS.Services.Account.Acc;
using Ryujinx.Ui.App.Common; using Ryujinx.Ui.App.Common;
using Ryujinx.Ui.Common.Helper; using Ryujinx.Ui.Common.Helper;
@@ -27,6 +26,7 @@ using System.Buffers;
using System.IO; using System.IO;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using ApplicationId = LibHac.Ncm.ApplicationId;
using Path = System.IO.Path; using Path = System.IO.Path;
namespace Ryujinx.Ava.Common namespace Ryujinx.Ava.Common
@@ -57,7 +57,7 @@ namespace Ryujinx.Ava.Common
Logger.Info?.Print(LogClass.Application, $"Creating save directory for Title: {titleName} [{titleId:x16}]"); Logger.Info?.Print(LogClass.Application, $"Creating save directory for Title: {titleName} [{titleId:x16}]");
if (Utilities.IsZeros(controlHolder.ByteSpan)) if (controlHolder.ByteSpan.IsZeros())
{ {
// If the current application doesn't have a loaded control property, create a dummy one // If the current application doesn't have a loaded control property, create a dummy one
// and set the savedata sizes so a user savedata will be created. // and set the savedata sizes so a user savedata will be created.
@@ -72,7 +72,7 @@ namespace Ryujinx.Ava.Common
Uid user = new((ulong)_accountManager.LastOpenedUser.UserId.High, (ulong)_accountManager.LastOpenedUser.UserId.Low); Uid user = new((ulong)_accountManager.LastOpenedUser.UserId.High, (ulong)_accountManager.LastOpenedUser.UserId.Low);
result = _horizonClient.Fs.EnsureApplicationSaveData(out _, new LibHac.Ncm.ApplicationId(titleId), in control, in user); result = _horizonClient.Fs.EnsureApplicationSaveData(out _, new ApplicationId(titleId), in control, in user);
if (result.IsFailure()) if (result.IsFailure())
{ {
Dispatcher.UIThread.InvokeAsync(async () => Dispatcher.UIThread.InvokeAsync(async () =>
@@ -114,7 +114,7 @@ namespace Ryujinx.Ava.Common
public static void OpenSaveDir(ulong 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))
{ {
@@ -147,7 +147,7 @@ namespace Ryujinx.Ava.Common
{ {
OpenFolderDialog folderDialog = new() OpenFolderDialog folderDialog = new()
{ {
Title = LocaleManager.Instance[LocaleKeys.FolderDialogExtractTitle] Title = LocaleManager.Instance[LocaleKeys.FolderDialogExtractTitle],
}; };
string destination = await folderDialog.ShowAsync(_owner); string destination = await folderDialog.ShowAsync(_owner);
@@ -293,10 +293,11 @@ namespace Ryujinx.Ava.Common
await ContentDialogHelper.CreateErrorDialog(ex.Message); await ContentDialogHelper.CreateErrorDialog(ex.Message);
}); });
} }
}); })
{
extractorThread.Name = "GUI.NcaSectionExtractorThread"; Name = "GUI.NcaSectionExtractorThread",
extractorThread.IsBackground = true; IsBackground = true,
};
extractorThread.Start(); extractorThread.Start();
} }
} }

View File

@@ -10,6 +10,6 @@ namespace Ryujinx.Ava.Common
FileType, FileType,
FileSize, FileSize,
Path, Path,
Favorite Favorite,
} }
} }

View File

@@ -11,6 +11,6 @@
ResScaleUp, ResScaleUp,
ResScaleDown, ResScaleDown,
VolumeUp, VolumeUp,
VolumeDown VolumeDown,
} }
} }

View File

@@ -21,7 +21,7 @@ namespace Ryujinx.Ava.Common.Locale
ReflectionBindingExtension binding = new($"[{keyToUse}]") ReflectionBindingExtension binding = new($"[{keyToUse}]")
{ {
Mode = BindingMode.OneWay, Mode = BindingMode.OneWay,
Source = LocaleManager.Instance Source = LocaleManager.Instance,
}; };
return binding.ProvideValue(serviceProvider); return binding.ProvideValue(serviceProvider);

View File

@@ -13,11 +13,11 @@ namespace Ryujinx.Ava.Common.Locale
{ {
private const string DefaultLanguageCode = "en_US"; private const string DefaultLanguageCode = "en_US";
private Dictionary<LocaleKeys, string> _localeStrings; private readonly Dictionary<LocaleKeys, string> _localeStrings;
private Dictionary<LocaleKeys, string> _localeDefaultStrings; private Dictionary<LocaleKeys, string> _localeDefaultStrings;
private readonly ConcurrentDictionary<LocaleKeys, object[]> _dynamicValues; private readonly ConcurrentDictionary<LocaleKeys, object[]> _dynamicValues;
public static LocaleManager Instance { get; } = new LocaleManager(); public static LocaleManager Instance { get; } = new();
public LocaleManager() public LocaleManager()
{ {
@@ -126,7 +126,7 @@ namespace Ryujinx.Ava.Common.Locale
} }
} }
private Dictionary<LocaleKeys, string> LoadJsonLanguage(string languageCode = DefaultLanguageCode) private static Dictionary<LocaleKeys, string> LoadJsonLanguage(string languageCode = DefaultLanguageCode)
{ {
var localeStrings = new Dictionary<LocaleKeys, string>(); var localeStrings = new Dictionary<LocaleKeys, string>();
string languageJson = EmbeddedResources.ReadAllText($"Ryujinx.Ava/Assets/Locales/{languageCode}.json"); string languageJson = EmbeddedResources.ReadAllText($"Ryujinx.Ava/Assets/Locales/{languageCode}.json");

View File

@@ -120,6 +120,7 @@ namespace Ryujinx.Ava.Input
_buttonsUserMapping.Clear(); _buttonsUserMapping.Clear();
#pragma warning disable IDE0055 // Disable formatting
// Left JoyCon // Left JoyCon
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.LeftStick, (Key)_configuration.LeftJoyconStick.StickButton)); _buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.LeftStick, (Key)_configuration.LeftJoyconStick.StickButton));
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.DpadUp, (Key)_configuration.LeftJoycon.DpadUp)); _buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.DpadUp, (Key)_configuration.LeftJoycon.DpadUp));
@@ -143,6 +144,7 @@ namespace Ryujinx.Ava.Input
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.RightTrigger, (Key)_configuration.RightJoycon.ButtonZr)); _buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.RightTrigger, (Key)_configuration.RightJoycon.ButtonZr));
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.SingleRightTrigger1, (Key)_configuration.RightJoycon.ButtonSr)); _buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.SingleRightTrigger1, (Key)_configuration.RightJoycon.ButtonSr));
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.SingleLeftTrigger1, (Key)_configuration.RightJoycon.ButtonSl)); _buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.SingleLeftTrigger1, (Key)_configuration.RightJoycon.ButtonSl));
#pragma warning restore IDE0055
} }
} }

View File

@@ -143,7 +143,7 @@ namespace Ryujinx.Ava.Input
AvaKey.OemBackslash, AvaKey.OemBackslash,
// NOTE: invalid // NOTE: invalid
AvaKey.None AvaKey.None,
}; };
private static readonly Dictionary<AvaKey, Key> _avaKeyMapping; private static readonly Dictionary<AvaKey, Key> _avaKeyMapping;

View File

@@ -31,13 +31,13 @@ namespace Ryujinx.Modules
{ {
internal static class Updater internal static class Updater
{ {
private const string GitHubApiURL = "https://api.github.com"; private const string GitHubApiUrl = "https://api.github.com";
private static readonly GithubReleasesJsonSerializerContext SerializerContext = new(JsonHelper.GetDefaultSerializerOptions()); private static readonly GithubReleasesJsonSerializerContext _serializerContext = new(JsonHelper.GetDefaultSerializerOptions());
private static readonly string HomeDir = AppDomain.CurrentDomain.BaseDirectory; private static readonly string _homeDir = AppDomain.CurrentDomain.BaseDirectory;
private static readonly string UpdateDir = Path.Combine(Path.GetTempPath(), "Ryujinx", "update"); private static readonly string _updateDir = Path.Combine(Path.GetTempPath(), "Ryujinx", "update");
private static readonly string UpdatePublishDir = Path.Combine(UpdateDir, "publish"); private static readonly string _updatePublishDir = Path.Combine(_updateDir, "publish");
private static readonly int ConnectionCount = 4; private static readonly int _connectionCount = 4;
private static string _buildVer; private static string _buildVer;
private static string _platformExt; private static string _platformExt;
@@ -46,7 +46,7 @@ namespace Ryujinx.Modules
private static bool _updateSuccessful; private static bool _updateSuccessful;
private static bool _running; private static bool _running;
private static readonly string[] WindowsDependencyDirs = Array.Empty<string>(); private static readonly string[] _windowsDependencyDirs = Array.Empty<string>();
public static async Task BeginParse(Window mainWindow, bool showVersionUpToDate) public static async Task BeginParse(Window mainWindow, bool showVersionUpToDate)
{ {
@@ -99,9 +99,9 @@ namespace Ryujinx.Modules
{ {
using HttpClient jsonClient = ConstructHttpClient(); using HttpClient jsonClient = ConstructHttpClient();
string buildInfoURL = $"{GitHubApiURL}/repos/{ReleaseInformation.ReleaseChannelOwner}/{ReleaseInformation.ReleaseChannelRepo}/releases/latest"; string buildInfoUrl = $"{GitHubApiUrl}/repos/{ReleaseInformation.ReleaseChannelOwner}/{ReleaseInformation.ReleaseChannelRepo}/releases/latest";
string fetchedJson = await jsonClient.GetStringAsync(buildInfoURL); string fetchedJson = await jsonClient.GetStringAsync(buildInfoUrl);
var fetched = JsonHelper.Deserialize(fetchedJson, SerializerContext.GithubReleasesJsonResponse); var fetched = JsonHelper.Deserialize(fetchedJson, _serializerContext.GithubReleasesJsonResponse);
_buildVer = fetched.Name; _buildVer = fetched.Name;
foreach (var asset in fetched.Assets) foreach (var asset in fetched.Assets)
@@ -195,8 +195,7 @@ namespace Ryujinx.Modules
} }
// Fetch build size information to learn chunk sizes. // Fetch build size information to learn chunk sizes.
using (HttpClient buildSizeClient = ConstructHttpClient()) using HttpClient buildSizeClient = ConstructHttpClient();
{
try try
{ {
buildSizeClient.DefaultRequestHeaders.Add("Range", "bytes=0-0"); buildSizeClient.DefaultRequestHeaders.Add("Range", "bytes=0-0");
@@ -212,7 +211,6 @@ namespace Ryujinx.Modules
_buildSize = -1; _buildSize = -1;
} }
}
Dispatcher.UIThread.Post(async () => Dispatcher.UIThread.Post(async () =>
{ {
@@ -248,23 +246,22 @@ namespace Ryujinx.Modules
_updateSuccessful = false; _updateSuccessful = false;
// Empty update dir, although it shouldn't ever have anything inside it // Empty update dir, although it shouldn't ever have anything inside it
if (Directory.Exists(UpdateDir)) if (Directory.Exists(_updateDir))
{ {
Directory.Delete(UpdateDir, true); Directory.Delete(_updateDir, true);
} }
Directory.CreateDirectory(UpdateDir); Directory.CreateDirectory(_updateDir);
string updateFile = Path.Combine(UpdateDir, "update.bin"); string updateFile = Path.Combine(_updateDir, "update.bin");
TaskDialog taskDialog = new() TaskDialog taskDialog = new()
{ {
Header = LocaleManager.Instance[LocaleKeys.RyujinxUpdater], Header = LocaleManager.Instance[LocaleKeys.RyujinxUpdater],
SubHeader = LocaleManager.Instance[LocaleKeys.UpdaterDownloading], SubHeader = LocaleManager.Instance[LocaleKeys.UpdaterDownloading],
IconSource = new SymbolIconSource { Symbol = Symbol.Download }, IconSource = new SymbolIconSource { Symbol = Symbol.Download },
Buttons = { },
ShowProgressBar = true, ShowProgressBar = true,
XamlRoot = parent XamlRoot = parent,
}; };
taskDialog.Opened += (s, e) => taskDialog.Opened += (s, e) =>
@@ -301,7 +298,7 @@ namespace Ryujinx.Modules
if (OperatingSystem.IsMacOS()) if (OperatingSystem.IsMacOS())
{ {
string baseBundlePath = Path.GetFullPath(Path.Combine(executableDirectory, "..", "..")); string baseBundlePath = Path.GetFullPath(Path.Combine(executableDirectory, "..", ".."));
string newBundlePath = Path.Combine(UpdateDir, "Ryujinx.app"); string newBundlePath = Path.Combine(_updateDir, "Ryujinx.app");
string updaterScriptPath = Path.Combine(newBundlePath, "Contents", "Resources", "updater.sh"); string updaterScriptPath = Path.Combine(newBundlePath, "Contents", "Resources", "updater.sh");
string currentPid = Environment.ProcessId.ToString(); string currentPid = Environment.ProcessId.ToString();
@@ -328,7 +325,7 @@ namespace Ryujinx.Modules
ProcessStartInfo processStart = new(ryuName) ProcessStartInfo processStart = new(ryuName)
{ {
UseShellExecute = true, UseShellExecute = true,
WorkingDirectory = executableDirectory WorkingDirectory = executableDirectory,
}; };
foreach (string argument in CommandLineState.Arguments) foreach (string argument in CommandLineState.Arguments)
@@ -347,22 +344,22 @@ namespace Ryujinx.Modules
private static void DoUpdateWithMultipleThreads(TaskDialog taskDialog, string downloadUrl, string updateFile) private static void DoUpdateWithMultipleThreads(TaskDialog taskDialog, string downloadUrl, string updateFile)
{ {
// Multi-Threaded Updater // Multi-Threaded Updater
long chunkSize = _buildSize / ConnectionCount; long chunkSize = _buildSize / _connectionCount;
long remainderChunk = _buildSize % ConnectionCount; long remainderChunk = _buildSize % _connectionCount;
int completedRequests = 0; int completedRequests = 0;
int totalProgressPercentage = 0; int totalProgressPercentage = 0;
int[] progressPercentage = new int[ConnectionCount]; int[] progressPercentage = new int[_connectionCount];
List<byte[]> list = new(ConnectionCount); List<byte[]> list = new(_connectionCount);
List<WebClient> webClients = new(ConnectionCount); List<WebClient> webClients = new(_connectionCount);
for (int i = 0; i < ConnectionCount; i++) for (int i = 0; i < _connectionCount; i++)
{ {
list.Add(Array.Empty<byte>()); list.Add(Array.Empty<byte>());
} }
for (int i = 0; i < ConnectionCount; i++) for (int i = 0; i < _connectionCount; i++)
{ {
#pragma warning disable SYSLIB0014 #pragma warning disable SYSLIB0014
// TODO: WebClient is obsolete and need to be replaced with a more complex logic using HttpClient. // TODO: WebClient is obsolete and need to be replaced with a more complex logic using HttpClient.
@@ -371,7 +368,7 @@ namespace Ryujinx.Modules
webClients.Add(client); webClients.Add(client);
if (i == ConnectionCount - 1) if (i == _connectionCount - 1)
{ {
client.Headers.Add("Range", $"bytes={chunkSize * i}-{(chunkSize * (i + 1) - 1) + remainderChunk}"); client.Headers.Add("Range", $"bytes={chunkSize * i}-{(chunkSize * (i + 1) - 1) + remainderChunk}");
} }
@@ -388,7 +385,7 @@ namespace Ryujinx.Modules
Interlocked.Exchange(ref progressPercentage[index], args.ProgressPercentage); Interlocked.Exchange(ref progressPercentage[index], args.ProgressPercentage);
Interlocked.Add(ref totalProgressPercentage, args.ProgressPercentage); Interlocked.Add(ref totalProgressPercentage, args.ProgressPercentage);
taskDialog.SetProgressBarState(totalProgressPercentage / ConnectionCount, TaskDialogProgressState.Normal); taskDialog.SetProgressBarState(totalProgressPercentage / _connectionCount, TaskDialogProgressState.Normal);
}; };
client.DownloadDataCompleted += (_, args) => client.DownloadDataCompleted += (_, args) =>
@@ -407,10 +404,10 @@ namespace Ryujinx.Modules
list[index] = args.Result; list[index] = args.Result;
Interlocked.Increment(ref completedRequests); Interlocked.Increment(ref completedRequests);
if (Equals(completedRequests, ConnectionCount)) if (Equals(completedRequests, _connectionCount))
{ {
byte[] mergedFileBytes = new byte[_buildSize]; byte[] mergedFileBytes = new byte[_buildSize];
for (int connectionIndex = 0, destinationOffset = 0; connectionIndex < ConnectionCount; connectionIndex++) for (int connectionIndex = 0, destinationOffset = 0; connectionIndex < _connectionCount; connectionIndex++)
{ {
Array.Copy(list[connectionIndex], 0, mergedFileBytes, destinationOffset, list[connectionIndex].Length); Array.Copy(list[connectionIndex], 0, mergedFileBytes, destinationOffset, list[connectionIndex].Length);
destinationOffset += list[connectionIndex].Length; destinationOffset += list[connectionIndex].Length;
@@ -421,11 +418,10 @@ namespace Ryujinx.Modules
// On macOS, ensure that we remove the quarantine bit to prevent Gatekeeper from blocking execution. // On macOS, ensure that we remove the quarantine bit to prevent Gatekeeper from blocking execution.
if (OperatingSystem.IsMacOS()) if (OperatingSystem.IsMacOS())
{ {
using (Process xattrProcess = Process.Start("xattr", new List<string> { "-d", "com.apple.quarantine", updateFile })) using Process xattrProcess = Process.Start("xattr", new List<string> { "-d", "com.apple.quarantine", updateFile });
{
xattrProcess.WaitForExit(); xattrProcess.WaitForExit();
} }
}
try try
{ {
@@ -437,8 +433,6 @@ namespace Ryujinx.Modules
Logger.Warning?.Print(LogClass.Application, "Multi-Threaded update failed, falling back to single-threaded updater."); Logger.Warning?.Print(LogClass.Application, "Multi-Threaded update failed, falling back to single-threaded updater.");
DoUpdateWithSingleThread(taskDialog, downloadUrl, updateFile); DoUpdateWithSingleThread(taskDialog, downloadUrl, updateFile);
return;
} }
} }
}; };
@@ -470,9 +464,8 @@ namespace Ryujinx.Modules
// We do not want to timeout while downloading // We do not want to timeout while downloading
client.Timeout = TimeSpan.FromDays(1); client.Timeout = TimeSpan.FromDays(1);
using (HttpResponseMessage response = client.GetAsync(downloadUrl, HttpCompletionOption.ResponseHeadersRead).Result) using HttpResponseMessage response = client.GetAsync(downloadUrl, HttpCompletionOption.ResponseHeadersRead).Result;
using (Stream remoteFileStream = response.Content.ReadAsStreamAsync().Result) using Stream remoteFileStream = response.Content.ReadAsStreamAsync().Result;
{
using Stream updateFileStream = File.Open(updateFile, FileMode.Create); using Stream updateFileStream = File.Open(updateFile, FileMode.Create);
long totalBytes = response.Content.Headers.ContentLength.Value; long totalBytes = response.Content.Headers.ContentLength.Value;
@@ -495,7 +488,6 @@ namespace Ryujinx.Modules
updateFileStream.Write(buffer, 0, readSize); updateFileStream.Write(buffer, 0, readSize);
} }
}
InstallUpdate(taskDialog, updateFile); InstallUpdate(taskDialog, updateFile);
} }
@@ -510,7 +502,7 @@ namespace Ryujinx.Modules
{ {
Thread worker = new(() => DoUpdateWithSingleThreadWorker(taskDialog, downloadUrl, updateFile)) Thread worker = new(() => DoUpdateWithSingleThreadWorker(taskDialog, downloadUrl, updateFile))
{ {
Name = "Updater.SingleThreadWorker" Name = "Updater.SingleThreadWorker",
}; };
worker.Start(); worker.Start();
@@ -537,10 +529,8 @@ namespace Ryujinx.Modules
Directory.CreateDirectory(Path.GetDirectoryName(outPath)); Directory.CreateDirectory(Path.GetDirectoryName(outPath));
using (FileStream outStream = File.OpenWrite(outPath)) using FileStream outStream = File.OpenWrite(outPath);
{
tarStream.CopyEntryContents(outStream); tarStream.CopyEntryContents(outStream);
}
File.SetUnixFileMode(outPath, (UnixFileMode)tarEntry.TarHeader.Mode); File.SetUnixFileMode(outPath, (UnixFileMode)tarEntry.TarHeader.Mode);
File.SetLastWriteTime(outPath, DateTime.SpecifyKind(tarEntry.ModTime, DateTimeKind.Utc)); File.SetLastWriteTime(outPath, DateTime.SpecifyKind(tarEntry.ModTime, DateTimeKind.Utc));
@@ -566,17 +556,19 @@ namespace Ryujinx.Modules
foreach (ZipEntry zipEntry in zipFile) foreach (ZipEntry zipEntry in zipFile)
{ {
count++; count++;
if (zipEntry.IsDirectory) continue; if (zipEntry.IsDirectory)
{
continue;
}
string outPath = Path.Combine(outputDirectoryPath, zipEntry.Name); string outPath = Path.Combine(outputDirectoryPath, zipEntry.Name);
Directory.CreateDirectory(Path.GetDirectoryName(outPath)); Directory.CreateDirectory(Path.GetDirectoryName(outPath));
using (Stream zipStream = zipFile.GetInputStream(zipEntry)) using Stream zipStream = zipFile.GetInputStream(zipEntry);
using (FileStream outStream = File.OpenWrite(outPath)) using FileStream outStream = File.OpenWrite(outPath);
{
zipStream.CopyTo(outStream); zipStream.CopyTo(outStream);
}
File.SetLastWriteTime(outPath, DateTime.SpecifyKind(zipEntry.DateTime, DateTimeKind.Utc)); File.SetLastWriteTime(outPath, DateTime.SpecifyKind(zipEntry.DateTime, DateTimeKind.Utc));
@@ -597,11 +589,11 @@ namespace Ryujinx.Modules
{ {
if (OperatingSystem.IsLinux() || OperatingSystem.IsMacOS()) if (OperatingSystem.IsLinux() || OperatingSystem.IsMacOS())
{ {
ExtractTarGzipFile(taskDialog, updateFile, UpdateDir); ExtractTarGzipFile(taskDialog, updateFile, _updateDir);
} }
else if (OperatingSystem.IsWindows()) else if (OperatingSystem.IsWindows())
{ {
ExtractZipFile(taskDialog, updateFile, UpdateDir); ExtractZipFile(taskDialog, updateFile, _updateDir);
} }
else else
{ {
@@ -648,10 +640,10 @@ namespace Ryujinx.Modules
taskDialog.SetProgressBarState(0, TaskDialogProgressState.Normal); taskDialog.SetProgressBarState(0, TaskDialogProgressState.Normal);
}); });
MoveAllFilesOver(UpdatePublishDir, HomeDir, taskDialog); MoveAllFilesOver(_updatePublishDir, _homeDir, taskDialog);
}); });
Directory.Delete(UpdateDir, true); Directory.Delete(_updateDir, true);
} }
_updateSuccessful = true; _updateSuccessful = true;
@@ -738,15 +730,15 @@ namespace Ryujinx.Modules
// NOTE: This method should always reflect the latest build layout. // NOTE: This method should always reflect the latest build layout.
private static IEnumerable<string> EnumerateFilesToDelete() private static IEnumerable<string> EnumerateFilesToDelete()
{ {
var files = Directory.EnumerateFiles(HomeDir); // All files directly in base dir. var files = Directory.EnumerateFiles(_homeDir); // All files directly in base dir.
// Determine and exclude user files only when the updater is running, not when cleaning old files // Determine and exclude user files only when the updater is running, not when cleaning old files
if (_running && !OperatingSystem.IsMacOS()) if (_running && !OperatingSystem.IsMacOS())
{ {
// Compare the loose files in base directory against the loose files from the incoming update, and store foreign ones in a user list. // Compare the loose files in base directory against the loose files from the incoming update, and store foreign ones in a user list.
var oldFiles = Directory.EnumerateFiles(HomeDir, "*", SearchOption.TopDirectoryOnly).Select(Path.GetFileName); var oldFiles = Directory.EnumerateFiles(_homeDir, "*", SearchOption.TopDirectoryOnly).Select(Path.GetFileName);
var newFiles = Directory.EnumerateFiles(UpdatePublishDir, "*", SearchOption.TopDirectoryOnly).Select(Path.GetFileName); var newFiles = Directory.EnumerateFiles(_updatePublishDir, "*", SearchOption.TopDirectoryOnly).Select(Path.GetFileName);
var userFiles = oldFiles.Except(newFiles).Select(filename => Path.Combine(HomeDir, filename)); var userFiles = oldFiles.Except(newFiles).Select(filename => Path.Combine(_homeDir, filename));
// Remove user files from the paths in files. // Remove user files from the paths in files.
files = files.Except(userFiles); files = files.Except(userFiles);
@@ -754,9 +746,9 @@ namespace Ryujinx.Modules
if (OperatingSystem.IsWindows()) if (OperatingSystem.IsWindows())
{ {
foreach (string dir in WindowsDependencyDirs) foreach (string dir in _windowsDependencyDirs)
{ {
string dirPath = Path.Combine(HomeDir, dir); string dirPath = Path.Combine(_homeDir, dir);
if (Directory.Exists(dirPath)) if (Directory.Exists(dirPath))
{ {
files = files.Concat(Directory.EnumerateFiles(dirPath, "*", SearchOption.AllDirectories)); files = files.Concat(Directory.EnumerateFiles(dirPath, "*", SearchOption.AllDirectories));
@@ -798,7 +790,7 @@ namespace Ryujinx.Modules
public static void CleanupUpdate() public static void CleanupUpdate()
{ {
foreach (string file in Directory.GetFiles(HomeDir, "*.ryuold", SearchOption.AllDirectories)) foreach (string file in Directory.GetFiles(_homeDir, "*.ryuold", SearchOption.AllDirectories))
{ {
File.Delete(file); File.Delete(file);
} }

View File

@@ -31,7 +31,7 @@ namespace Ryujinx.Ava
[LibraryImport("user32.dll", SetLastError = true)] [LibraryImport("user32.dll", SetLastError = true)]
public static partial int MessageBoxA(IntPtr hWnd, [MarshalAs(UnmanagedType.LPStr)] string text, [MarshalAs(UnmanagedType.LPStr)] string caption, uint type); public static partial int MessageBoxA(IntPtr hWnd, [MarshalAs(UnmanagedType.LPStr)] string text, [MarshalAs(UnmanagedType.LPStr)] string caption, uint type);
private const uint MB_ICONWARNING = 0x30; private const uint MbIconwarning = 0x30;
public static void Main(string[] args) public static void Main(string[] args)
{ {
@@ -39,7 +39,7 @@ 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}", MbIconwarning);
} }
PreviewerDetached = true; PreviewerDetached = true;
@@ -60,7 +60,7 @@ namespace Ryujinx.Ava
EnableMultiTouch = true, EnableMultiTouch = true,
EnableIme = true, EnableIme = true,
UseEGL = false, UseEGL = false,
UseGpu = true UseGpu = true,
}) })
.With(new Win32PlatformOptions .With(new Win32PlatformOptions
{ {
@@ -192,7 +192,7 @@ namespace Ryujinx.Ava
"never" => HideCursorMode.Never, "never" => HideCursorMode.Never,
"onidle" => HideCursorMode.OnIdle, "onidle" => HideCursorMode.OnIdle,
"always" => HideCursorMode.Always, "always" => HideCursorMode.Always,
_ => ConfigurationState.Instance.HideCursor.Value _ => ConfigurationState.Instance.HideCursor.Value,
}; };
} }
} }

View File

@@ -64,7 +64,7 @@ namespace Ryujinx.Ava.UI.Applet
LocaleManager.Instance[LocaleKeys.SettingsButtonClose], LocaleManager.Instance[LocaleKeys.SettingsButtonClose],
(int)Symbol.Important, (int)Symbol.Important,
deferEvent, deferEvent,
async (window) => async window =>
{ {
if (opened) if (opened)
{ {
@@ -112,7 +112,7 @@ namespace Ryujinx.Ava.UI.Applet
{ {
try try
{ {
var response = await SwkbdAppletDialog.ShowInputDialog(_parent, LocaleManager.Instance[LocaleKeys.SoftwareKeyboard], args); var response = await SwkbdAppletDialog.ShowInputDialog(LocaleManager.Instance[LocaleKeys.SoftwareKeyboard], args);
if (response.Result == UserResult.Ok) if (response.Result == UserResult.Ok)
{ {
@@ -142,10 +142,7 @@ namespace Ryujinx.Ava.UI.Applet
public void ExecuteProgram(Switch device, ProgramSpecifyKind kind, ulong value) public void ExecuteProgram(Switch device, ProgramSpecifyKind kind, ulong value)
{ {
device.Configuration.UserChannelPersistence.ExecuteProgram(kind, value); device.Configuration.UserChannelPersistence.ExecuteProgram(kind, value);
if (_parent.ViewModel.AppHost != null) _parent.ViewModel.AppHost?.Stop();
{
_parent.ViewModel.AppHost.Stop();
}
} }
public bool DisplayErrorAppletDialog(string title, string message, string[] buttons) public bool DisplayErrorAppletDialog(string title, string message, string[] buttons)
@@ -162,7 +159,7 @@ namespace Ryujinx.Ava.UI.Applet
{ {
Title = title, Title = title,
WindowStartupLocation = WindowStartupLocation.CenterScreen, WindowStartupLocation = WindowStartupLocation.CenterScreen,
Width = 400 Width = 400,
}; };
object response = await msgDialog.Run(); object response = await msgDialog.Run();

View File

@@ -3,13 +3,11 @@ using Avalonia.Controls;
using Avalonia.Input; using Avalonia.Input;
using Avalonia.Threading; using Avalonia.Threading;
using Ryujinx.Ava.Input; using Ryujinx.Ava.Input;
using Ryujinx.Ava.UI.Controls;
using Ryujinx.Ava.UI.Helpers; using Ryujinx.Ava.UI.Helpers;
using Ryujinx.Ava.UI.Windows; using Ryujinx.Ava.UI.Windows;
using Ryujinx.HLE.Ui; using Ryujinx.HLE.Ui;
using System; using System;
using System.Threading; using System.Threading;
using HidKey = Ryujinx.Common.Configuration.Hid.Key; using HidKey = Ryujinx.Common.Configuration.Hid.Key;
namespace Ryujinx.Ava.UI.Applet namespace Ryujinx.Ava.UI.Applet
@@ -17,7 +15,7 @@ namespace Ryujinx.Ava.UI.Applet
class AvaloniaDynamicTextInputHandler : IDynamicTextInputHandler class AvaloniaDynamicTextInputHandler : IDynamicTextInputHandler
{ {
private MainWindow _parent; private MainWindow _parent;
private OffscreenTextBox _hiddenTextBox; private readonly OffscreenTextBox _hiddenTextBox;
private bool _canProcessInput; private bool _canProcessInput;
private IDisposable _textChangedSubscription; private IDisposable _textChangedSubscription;
private IDisposable _selectionStartChangedSubscription; private IDisposable _selectionStartChangedSubscription;
@@ -76,7 +74,7 @@ namespace Ryujinx.Ava.UI.Applet
return; return;
} }
e.RoutedEvent = _hiddenTextBox.GetKeyUpRoutedEvent(); e.RoutedEvent = OffscreenTextBox.GetKeyUpRoutedEvent();
Dispatcher.UIThread.InvokeAsync(() => Dispatcher.UIThread.InvokeAsync(() =>
{ {
@@ -96,7 +94,7 @@ namespace Ryujinx.Ava.UI.Applet
return; return;
} }
e.RoutedEvent = _hiddenTextBox.GetKeyUpRoutedEvent(); e.RoutedEvent = OffscreenTextBox.GetKeyUpRoutedEvent();
Dispatcher.UIThread.InvokeAsync(() => Dispatcher.UIThread.InvokeAsync(() =>
{ {

View File

@@ -9,7 +9,7 @@ namespace Ryujinx.Ava.UI.Applet
{ {
public AvaloniaHostUiTheme(MainWindow parent) public AvaloniaHostUiTheme(MainWindow parent)
{ {
FontFamily = OperatingSystem.IsWindows() && OperatingSystem.IsWindowsVersionAtLeast(10, 0, 22000, 0) ? "Segoe UI Variable" : parent.FontFamily.Name; FontFamily = OperatingSystem.IsWindows() && OperatingSystem.IsWindowsVersionAtLeast(10, 0, 22000) ? "Segoe UI Variable" : parent.FontFamily.Name;
DefaultBackgroundColor = BrushToThemeColor(parent.Background); DefaultBackgroundColor = BrushToThemeColor(parent.Background);
DefaultForegroundColor = BrushToThemeColor(parent.Foreground); DefaultForegroundColor = BrushToThemeColor(parent.Foreground);
DefaultBorderColor = BrushToThemeColor(parent.BorderBrush); DefaultBorderColor = BrushToThemeColor(parent.BorderBrush);
@@ -25,7 +25,7 @@ namespace Ryujinx.Ava.UI.Applet
public ThemeColor SelectionBackgroundColor { get; } public ThemeColor SelectionBackgroundColor { get; }
public ThemeColor SelectionForegroundColor { get; } public ThemeColor SelectionForegroundColor { get; }
private ThemeColor BrushToThemeColor(IBrush brush) private static ThemeColor BrushToThemeColor(IBrush brush)
{ {
if (brush is SolidColorBrush solidColor) if (brush is SolidColorBrush solidColor)
{ {
@@ -34,10 +34,8 @@ namespace Ryujinx.Ava.UI.Applet
(float)solidColor.Color.G / 255, (float)solidColor.Color.G / 255,
(float)solidColor.Color.B / 255); (float)solidColor.Color.B / 255);
} }
else
{
return new ThemeColor(); return new ThemeColor();
} }
} }
}
} }

View File

@@ -1,10 +1,12 @@
using Avalonia;
using Avalonia.Controls; using Avalonia.Controls;
using Avalonia.Interactivity; using Avalonia.Interactivity;
using Avalonia.Threading; using Avalonia.Threading;
using Ryujinx.Ava.Common.Locale; using Ryujinx.Ava.Common.Locale;
using Ryujinx.Ava.UI.Windows; using Ryujinx.Ava.UI.Windows;
using System.Threading.Tasks; using System.Threading.Tasks;
#if DEBUG
using Avalonia;
#endif
namespace Ryujinx.Ava.UI.Applet namespace Ryujinx.Ava.UI.Applet
{ {

View File

@@ -1,13 +1,10 @@
using Avalonia;
using Avalonia.Controls; using Avalonia.Controls;
using Avalonia.Input; using Avalonia.Input;
using Avalonia.Interactivity; using Avalonia.Interactivity;
using Avalonia.Media; using Avalonia.Media;
using FluentAvalonia.Core;
using FluentAvalonia.UI.Controls; using FluentAvalonia.UI.Controls;
using Ryujinx.Ava.Common.Locale; using Ryujinx.Ava.Common.Locale;
using Ryujinx.Ava.UI.Helpers; using Ryujinx.Ava.UI.Helpers;
using Ryujinx.Ava.UI.Windows;
using Ryujinx.HLE.HOS.Applets; using Ryujinx.HLE.HOS.Applets;
using Ryujinx.HLE.HOS.Applets.SoftwareKeyboard; using Ryujinx.HLE.HOS.Applets.SoftwareKeyboard;
using System; using System;
@@ -22,7 +19,7 @@ namespace Ryujinx.Ava.UI.Controls
private Predicate<string> _checkInput = _ => true; private Predicate<string> _checkInput = _ => true;
private int _inputMax; private int _inputMax;
private int _inputMin; private int _inputMin;
private string _placeholder; private readonly string _placeholder;
private ContentDialog _host; private ContentDialog _host;
@@ -57,13 +54,13 @@ namespace Ryujinx.Ava.UI.Controls
public string MainText { get; set; } = ""; public string MainText { get; set; } = "";
public string SecondaryText { get; set; } = ""; public string SecondaryText { get; set; } = "";
public static async Task<(UserResult Result, string Input)> ShowInputDialog(StyleableWindow window, string title, SoftwareKeyboardUiArgs args) public static async Task<(UserResult Result, string Input)> ShowInputDialog(string title, SoftwareKeyboardUiArgs args)
{ {
ContentDialog contentDialog = new ContentDialog(); ContentDialog contentDialog = new();
UserResult result = UserResult.Cancel; UserResult result = UserResult.Cancel;
SwkbdAppletDialog content = new SwkbdAppletDialog(args.HeaderText, args.SubtitleText, args.GuideText, args.InitialText); SwkbdAppletDialog content = new(args.HeaderText, args.SubtitleText, args.GuideText, args.InitialText);
string input = string.Empty; string input = string.Empty;
@@ -78,15 +75,16 @@ namespace Ryujinx.Ava.UI.Controls
contentDialog.CloseButtonText = LocaleManager.Instance[LocaleKeys.InputDialogCancel]; contentDialog.CloseButtonText = LocaleManager.Instance[LocaleKeys.InputDialogCancel];
contentDialog.Content = content; contentDialog.Content = content;
TypedEventHandler<ContentDialog, ContentDialogClosedEventArgs> handler = (sender, eventArgs) => void Handler(ContentDialog sender, ContentDialogClosedEventArgs eventArgs)
{ {
if (eventArgs.Result == ContentDialogResult.Primary) if (eventArgs.Result == ContentDialogResult.Primary)
{ {
result = UserResult.Ok; result = UserResult.Ok;
input = content.Input.Text; input = content.Input.Text;
} }
}; }
contentDialog.Closed += handler;
contentDialog.Closed += Handler;
await ContentDialogHelper.ShowAsync(contentDialog); await ContentDialogHelper.ShowAsync(contentDialog);

View File

@@ -18,7 +18,6 @@ using System.Collections.Generic;
using System.Globalization; using System.Globalization;
using System.IO; using System.IO;
using Path = System.IO.Path; using Path = System.IO.Path;
using UserId = LibHac.Fs.UserId;
namespace Ryujinx.Ava.UI.Controls namespace Ryujinx.Ava.UI.Controls
{ {
@@ -53,7 +52,7 @@ namespace Ryujinx.Ava.UI.Controls
public void OpenUserSaveDirectory_Click(object sender, RoutedEventArgs args) public void OpenUserSaveDirectory_Click(object sender, RoutedEventArgs args)
{ {
if ((sender as MenuItem)?.DataContext is MainWindowViewModel viewModel) if (sender is MenuItem { DataContext: MainWindowViewModel viewModel })
{ {
OpenSaveDirectory(viewModel, SaveDataType.Account, userId: new UserId((ulong)viewModel.AccountManager.LastOpenedUser.UserId.High, (ulong)viewModel.AccountManager.LastOpenedUser.UserId.Low)); OpenSaveDirectory(viewModel, SaveDataType.Account, userId: new UserId((ulong)viewModel.AccountManager.LastOpenedUser.UserId.High, (ulong)viewModel.AccountManager.LastOpenedUser.UserId.Low));
} }

View File

@@ -2,7 +2,6 @@ using Avalonia;
using Avalonia.Controls; using Avalonia.Controls;
using Avalonia.Styling; using Avalonia.Styling;
using Avalonia.Threading; using Avalonia.Threading;
using FluentAvalonia.Core;
using FluentAvalonia.UI.Controls; using FluentAvalonia.UI.Controls;
using LibHac; using LibHac;
using LibHac.Common; using LibHac.Common;
@@ -10,7 +9,6 @@ using LibHac.Fs;
using LibHac.Fs.Shim; using LibHac.Fs.Shim;
using Ryujinx.Ava.Common.Locale; using Ryujinx.Ava.Common.Locale;
using Ryujinx.Ava.UI.Helpers; using Ryujinx.Ava.UI.Helpers;
using Ryujinx.Ava.UI.Models;
using Ryujinx.Ava.UI.ViewModels; using Ryujinx.Ava.UI.ViewModels;
using Ryujinx.Ava.UI.Views.User; using Ryujinx.Ava.UI.Views.User;
using Ryujinx.HLE.FileSystem; using Ryujinx.HLE.FileSystem;
@@ -19,6 +17,7 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using UserId = Ryujinx.HLE.HOS.Services.Account.Acc.UserId;
using UserProfile = Ryujinx.Ava.UI.Models.UserProfile; using UserProfile = Ryujinx.Ava.UI.Models.UserProfile;
namespace Ryujinx.Ava.UI.Controls namespace Ryujinx.Ava.UI.Controls
@@ -56,7 +55,7 @@ namespace Ryujinx.Ava.UI.Controls
InitializeComponent(); InitializeComponent();
} }
public void GoBack(object parameter = null) public void GoBack()
{ {
if (ContentFrame.BackStack.Count > 0) if (ContentFrame.BackStack.Count > 0)
{ {
@@ -75,14 +74,14 @@ namespace Ryujinx.Ava.UI.Controls
VirtualFileSystem ownerVirtualFileSystem, HorizonClient ownerHorizonClient) VirtualFileSystem ownerVirtualFileSystem, HorizonClient ownerHorizonClient)
{ {
var content = new NavigationDialogHost(ownerAccountManager, ownerContentManager, ownerVirtualFileSystem, ownerHorizonClient); var content = new NavigationDialogHost(ownerAccountManager, ownerContentManager, ownerVirtualFileSystem, ownerHorizonClient);
ContentDialog contentDialog = new ContentDialog ContentDialog contentDialog = new()
{ {
Title = LocaleManager.Instance[LocaleKeys.UserProfileWindowTitle], Title = LocaleManager.Instance[LocaleKeys.UserProfileWindowTitle],
PrimaryButtonText = "", PrimaryButtonText = "",
SecondaryButtonText = "", SecondaryButtonText = "",
CloseButtonText = "", CloseButtonText = "",
Content = content, Content = content,
Padding = new Thickness(0) Padding = new Thickness(0),
}; };
contentDialog.Closed += (sender, args) => contentDialog.Closed += (sender, args) =>
@@ -125,7 +124,7 @@ namespace Ryujinx.Ava.UI.Controls
Span<SaveDataInfo> saveDataInfo = stackalloc SaveDataInfo[10]; Span<SaveDataInfo> saveDataInfo = stackalloc SaveDataInfo[10];
HashSet<HLE.HOS.Services.Account.Acc.UserId> lostAccounts = new(); HashSet<UserId> lostAccounts = new();
while (true) while (true)
{ {
@@ -139,15 +138,15 @@ namespace Ryujinx.Ava.UI.Controls
for (int i = 0; i < readCount; i++) for (int i = 0; i < readCount; i++)
{ {
var save = saveDataInfo[i]; var save = saveDataInfo[i];
var id = new HLE.HOS.Services.Account.Acc.UserId((long)save.UserId.Id.Low, (long)save.UserId.Id.High); var id = new UserId((long)save.UserId.Id.Low, (long)save.UserId.Id.High);
if (ViewModel.Profiles.Cast<UserProfile>().FirstOrDefault( x=> x.UserId == id) == null) if (ViewModel.Profiles.Cast<UserProfile>().FirstOrDefault(x => x.UserId == id) == null)
{ {
lostAccounts.Add(id); lostAccounts.Add(id);
} }
} }
} }
foreach(var account in lostAccounts) foreach (var account in lostAccounts)
{ {
ViewModel.LostProfiles.Add(new UserProfile(new HLE.HOS.Services.Account.Acc.UserProfile(account, "", null), this)); ViewModel.LostProfiles.Add(new UserProfile(new HLE.HOS.Services.Account.Acc.UserProfile(account, "", null), this));
} }
@@ -166,7 +165,7 @@ namespace Ryujinx.Ava.UI.Controls
if (profile == null) if (profile == null)
{ {
async void Action() static async void Action()
{ {
await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance[LocaleKeys.DialogUserProfileDeletionWarningMessage]); await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance[LocaleKeys.DialogUserProfileDeletionWarningMessage]);
} }

View File

@@ -1,6 +1,7 @@
using Avalonia; using Avalonia;
using Avalonia.Controls; using Avalonia.Controls;
using Avalonia.Controls.ApplicationLifetimes; using Avalonia.Controls.ApplicationLifetimes;
using Avalonia.Layout;
using Avalonia.Media; using Avalonia.Media;
using Avalonia.Threading; using Avalonia.Threading;
using FluentAvalonia.Core; using FluentAvalonia.Core;
@@ -36,13 +37,12 @@ namespace Ryujinx.Ava.UI.Helpers
PrimaryButtonText = primaryButton, PrimaryButtonText = primaryButton,
SecondaryButtonText = secondaryButton, SecondaryButtonText = secondaryButton,
CloseButtonText = closeButton, CloseButtonText = closeButton,
Content = content Content = content,
}; PrimaryButtonCommand = MiniCommand.Create(() =>
contentDialog.PrimaryButtonCommand = MiniCommand.Create(() =>
{ {
result = primaryButtonResult; result = primaryButtonResult;
}); }),
};
contentDialog.SecondaryButtonCommand = MiniCommand.Create(() => contentDialog.SecondaryButtonCommand = MiniCommand.Create(() =>
{ {
@@ -96,7 +96,6 @@ namespace Ryujinx.Ava.UI.Helpers
Func<Window, Task> doWhileDeferred = null) Func<Window, Task> doWhileDeferred = null)
{ {
bool startedDeferring = false; bool startedDeferring = false;
UserResult result = UserResult.None;
return await ShowTextDialog( return await ShowTextDialog(
title, title,
@@ -123,8 +122,6 @@ namespace Ryujinx.Ava.UI.Helpers
var deferral = args.GetDeferral(); var deferral = args.GetDeferral();
result = primaryButton == LocaleManager.Instance[LocaleKeys.InputDialogYes] ? UserResult.Yes : UserResult.Ok;
sender.PrimaryButtonClick -= DeferClose; sender.PrimaryButtonClick -= DeferClose;
_ = Task.Run(() => _ = Task.Run(() =>
@@ -150,10 +147,10 @@ namespace Ryujinx.Ava.UI.Helpers
{ {
Grid content = new() Grid content = new()
{ {
RowDefinitions = new RowDefinitions() { new RowDefinition(), new RowDefinition() }, RowDefinitions = new RowDefinitions { new(), new() },
ColumnDefinitions = new ColumnDefinitions() { new ColumnDefinition(GridLength.Auto), new ColumnDefinition() }, ColumnDefinitions = new ColumnDefinitions { new(GridLength.Auto), new() },
MinHeight = 80 MinHeight = 80,
}; };
SymbolIcon icon = new() SymbolIcon icon = new()
@@ -161,7 +158,7 @@ namespace Ryujinx.Ava.UI.Helpers
Symbol = (Symbol)symbol, Symbol = (Symbol)symbol,
Margin = new Thickness(10), Margin = new Thickness(10),
FontSize = 40, FontSize = 40,
VerticalAlignment = Avalonia.Layout.VerticalAlignment.Center VerticalAlignment = VerticalAlignment.Center,
}; };
Grid.SetColumn(icon, 0); Grid.SetColumn(icon, 0);
@@ -173,7 +170,7 @@ namespace Ryujinx.Ava.UI.Helpers
Text = primaryText, Text = primaryText,
Margin = new Thickness(5), Margin = new Thickness(5),
TextWrapping = TextWrapping.Wrap, TextWrapping = TextWrapping.Wrap,
MaxWidth = 450 MaxWidth = 450,
}; };
TextBlock secondaryLabel = new() TextBlock secondaryLabel = new()
@@ -181,7 +178,7 @@ namespace Ryujinx.Ava.UI.Helpers
Text = secondaryText, Text = secondaryText,
Margin = new Thickness(5), Margin = new Thickness(5),
TextWrapping = TextWrapping.Wrap, TextWrapping = TextWrapping.Wrap,
MaxWidth = 450 MaxWidth = 450,
}; };
Grid.SetColumn(primaryLabel, 1); Grid.SetColumn(primaryLabel, 1);
@@ -318,14 +315,14 @@ namespace Ryujinx.Ava.UI.Helpers
Window parent = GetMainWindow(); Window parent = GetMainWindow();
if (parent != null && parent.IsActive && (parent as MainWindow).ViewModel.IsGameRunning) if (parent is { IsActive: true } and MainWindow window && window.ViewModel.IsGameRunning)
{ {
contentDialogOverlayWindow = new() contentDialogOverlayWindow = new()
{ {
Height = parent.Bounds.Height, Height = parent.Bounds.Height,
Width = parent.Bounds.Width, Width = parent.Bounds.Width,
Position = parent.PointToScreen(new Point()), Position = parent.PointToScreen(new Point()),
ShowInTaskbar = false ShowInTaskbar = false,
}; };
parent.PositionChanged += OverlayOnPositionChanged; parent.PositionChanged += OverlayOnPositionChanged;
@@ -389,7 +386,7 @@ namespace Ryujinx.Ava.UI.Helpers
private static Window GetMainWindow() private static Window GetMainWindow()
{ {
if (Application.Current.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime al) if (Application.Current?.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime al)
{ {
foreach (Window item in al.Windows) foreach (Window item in al.Windows)
{ {

View File

@@ -1,5 +1,6 @@
using Avalonia.Data; using Avalonia.Data;
using Avalonia.Markup.Xaml; using Avalonia.Markup.Xaml;
using Avalonia.Markup.Xaml.MarkupExtensions;
using FluentAvalonia.UI.Controls; using FluentAvalonia.UI.Controls;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
@@ -8,13 +9,13 @@ namespace Ryujinx.Ava.UI.Helpers
{ {
public class GlyphValueConverter : MarkupExtension public class GlyphValueConverter : MarkupExtension
{ {
private string _key; private readonly string _key;
private static Dictionary<Glyph, string> _glyphs = new Dictionary<Glyph, string> private static readonly Dictionary<Glyph, string> _glyphs = new()
{ {
{ Glyph.List, char.ConvertFromUtf32((int)Symbol.List).ToString() }, { Glyph.List, char.ConvertFromUtf32((int)Symbol.List) },
{ Glyph.Grid, char.ConvertFromUtf32((int)Symbol.ViewAll).ToString() }, { Glyph.Grid, char.ConvertFromUtf32((int)Symbol.ViewAll) },
{ Glyph.Chip, char.ConvertFromUtf32(59748).ToString() } { Glyph.Chip, char.ConvertFromUtf32(59748) },
}; };
public GlyphValueConverter(string key) public GlyphValueConverter(string key)
@@ -37,10 +38,10 @@ namespace Ryujinx.Ava.UI.Helpers
public override object ProvideValue(IServiceProvider serviceProvider) public override object ProvideValue(IServiceProvider serviceProvider)
{ {
Avalonia.Markup.Xaml.MarkupExtensions.ReflectionBindingExtension binding = new($"[{_key}]") ReflectionBindingExtension binding = new($"[{_key}]")
{ {
Mode = BindingMode.OneWay, Mode = BindingMode.OneWay,
Source = this Source = this,
}; };
return binding.ProvideValue(serviceProvider); return binding.ProvideValue(serviceProvider);

View File

@@ -1,15 +1,17 @@
using Avalonia.Logging;
using Avalonia.Utilities; using Avalonia.Utilities;
using Ryujinx.Common.Logging;
using System; using System;
using System.Text; using System.Text;
namespace Ryujinx.Ava.UI.Helpers namespace Ryujinx.Ava.UI.Helpers
{ {
using AvaLogger = Avalonia.Logging.Logger; using AvaLogger = Avalonia.Logging.Logger;
using AvaLogLevel = Avalonia.Logging.LogEventLevel; using AvaLogLevel = LogEventLevel;
using RyuLogClass = Ryujinx.Common.Logging.LogClass; using RyuLogClass = LogClass;
using RyuLogger = Ryujinx.Common.Logging.Logger; using RyuLogger = Ryujinx.Common.Logging.Logger;
internal class LoggerAdapter : Avalonia.Logging.ILogSink internal class LoggerAdapter : ILogSink
{ {
public static void Register() public static void Register()
{ {
@@ -26,7 +28,7 @@ namespace Ryujinx.Ava.UI.Helpers
AvaLogLevel.Warning => RyuLogger.Debug, AvaLogLevel.Warning => RyuLogger.Debug,
AvaLogLevel.Error => RyuLogger.Error, AvaLogLevel.Error => RyuLogger.Error,
AvaLogLevel.Fatal => RyuLogger.Error, AvaLogLevel.Fatal => RyuLogger.Error,
_ => throw new ArgumentOutOfRangeException(nameof(level), level, null) _ => throw new ArgumentOutOfRangeException(nameof(level), level, null),
}; };
} }

View File

@@ -8,7 +8,7 @@ namespace Ryujinx.Ava.UI.Helpers
{ {
private readonly Action<T> _callback; private readonly Action<T> _callback;
private bool _busy; private bool _busy;
private Func<T, Task> _asyncCallback; private readonly Func<T, Task> _asyncCallback;
public MiniCommand(Action<T> callback) public MiniCommand(Action<T> callback)
{ {

View File

@@ -25,7 +25,7 @@ namespace Ryujinx.Ava.UI.Helpers
{ {
Position = NotificationPosition.BottomRight, Position = NotificationPosition.BottomRight,
MaxItems = MaxNotifications, MaxItems = MaxNotifications,
Margin = new Thickness(0, 0, 15, 40) Margin = new Thickness(0, 0, 15, 40),
}; };
var maybeAsyncWorkQueue = new Lazy<AsyncWorkQueue<Notification>>( var maybeAsyncWorkQueue = new Lazy<AsyncWorkQueue<Notification>>(

View File

@@ -6,12 +6,12 @@ namespace Ryujinx.Ava.UI.Helpers
{ {
public class OffscreenTextBox : TextBox public class OffscreenTextBox : TextBox
{ {
public RoutedEvent<KeyEventArgs> GetKeyDownRoutedEvent() public static RoutedEvent<KeyEventArgs> GetKeyDownRoutedEvent()
{ {
return KeyDownEvent; return KeyDownEvent;
} }
public RoutedEvent<KeyEventArgs> GetKeyUpRoutedEvent() public static RoutedEvent<KeyEventArgs> GetKeyUpRoutedEvent()
{ {
return KeyUpEvent; return KeyUpEvent;
} }
@@ -28,12 +28,12 @@ namespace Ryujinx.Ava.UI.Helpers
public void SendText(string text) public void SendText(string text)
{ {
OnTextInput(new TextInputEventArgs() OnTextInput(new TextInputEventArgs
{ {
Text = text, Text = text,
Device = KeyboardDevice.Instance, Device = KeyboardDevice.Instance,
Source = this, Source = this,
RoutedEvent = TextInputEvent RoutedEvent = TextInputEvent,
}); });
} }
} }

View File

@@ -1,5 +1,4 @@
using Ryujinx.Ava.Common.Locale; using Ryujinx.Ava.Common.Locale;
using Ryujinx.Ava.UI.Windows;
using Ryujinx.Ui.Common; using Ryujinx.Ui.Common;
using Ryujinx.Ui.Common.Helper; using Ryujinx.Ui.Common.Helper;
using System.Threading.Tasks; using System.Threading.Tasks;
@@ -24,7 +23,7 @@ namespace Ryujinx.Ava.UI.Helpers
UserError.FirmwareParsingFailed => LocaleManager.Instance[LocaleKeys.UserErrorFirmwareParsingFailed], UserError.FirmwareParsingFailed => LocaleManager.Instance[LocaleKeys.UserErrorFirmwareParsingFailed],
UserError.ApplicationNotFound => LocaleManager.Instance[LocaleKeys.UserErrorApplicationNotFound], UserError.ApplicationNotFound => LocaleManager.Instance[LocaleKeys.UserErrorApplicationNotFound],
UserError.Unknown => LocaleManager.Instance[LocaleKeys.UserErrorUnknown], UserError.Unknown => LocaleManager.Instance[LocaleKeys.UserErrorUnknown],
_ => LocaleManager.Instance[LocaleKeys.UserErrorUndefined] _ => LocaleManager.Instance[LocaleKeys.UserErrorUndefined],
}; };
} }
@@ -37,7 +36,7 @@ namespace Ryujinx.Ava.UI.Helpers
UserError.FirmwareParsingFailed => LocaleManager.Instance[LocaleKeys.UserErrorFirmwareParsingFailedDescription], UserError.FirmwareParsingFailed => LocaleManager.Instance[LocaleKeys.UserErrorFirmwareParsingFailedDescription],
UserError.ApplicationNotFound => LocaleManager.Instance[LocaleKeys.UserErrorApplicationNotFoundDescription], UserError.ApplicationNotFound => LocaleManager.Instance[LocaleKeys.UserErrorApplicationNotFoundDescription],
UserError.Unknown => LocaleManager.Instance[LocaleKeys.UserErrorUnknownDescription], UserError.Unknown => LocaleManager.Instance[LocaleKeys.UserErrorUnknownDescription],
_ => LocaleManager.Instance[LocaleKeys.UserErrorUndefinedDescription] _ => LocaleManager.Instance[LocaleKeys.UserErrorUndefinedDescription],
}; };
} }
@@ -48,7 +47,7 @@ namespace Ryujinx.Ava.UI.Helpers
UserError.NoKeys or UserError.NoKeys or
UserError.NoFirmware or UserError.NoFirmware or
UserError.FirmwareParsingFailed => true, UserError.FirmwareParsingFailed => true,
_ => false _ => false,
}; };
} }
@@ -63,11 +62,11 @@ namespace Ryujinx.Ava.UI.Helpers
{ {
UserError.NoKeys => SetupGuideUrl + "#initial-setup---placement-of-prodkeys", UserError.NoKeys => SetupGuideUrl + "#initial-setup---placement-of-prodkeys",
UserError.NoFirmware => SetupGuideUrl + "#initial-setup-continued---installation-of-firmware", UserError.NoFirmware => SetupGuideUrl + "#initial-setup-continued---installation-of-firmware",
_ => SetupGuideUrl _ => SetupGuideUrl,
}; };
} }
public static async Task ShowUserErrorDialog(UserError error, StyleableWindow owner) public static async Task ShowUserErrorDialog(UserError error)
{ {
string errorCode = GetErrorCode(error); string errorCode = GetErrorCode(error);

View File

@@ -1,4 +1,5 @@
using System; using System;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Runtime.Versioning; using System.Runtime.Versioning;
@@ -10,46 +11,47 @@ namespace Ryujinx.Ava.UI.Helpers
[Flags] [Flags]
public enum ClassStyles : uint public enum ClassStyles : uint
{ {
CS_CLASSDC = 0x40, CsClassdc = 0x40,
CS_OWNDC = 0x20, CsOwndc = 0x20,
} }
[Flags] [Flags]
public enum WindowStyles : uint public enum WindowStyles : uint
{ {
WS_CHILD = 0x40000000 WsChild = 0x40000000,
} }
public enum Cursors : uint public enum Cursors : uint
{ {
IDC_ARROW = 32512 IdcArrow = 32512,
} }
[SuppressMessage("Design", "CA1069: Enums values should not be duplicated")]
public enum WindowsMessages : uint public enum WindowsMessages : uint
{ {
MOUSEMOVE = 0x0200, Mousemove = 0x0200,
LBUTTONDOWN = 0x0201, Lbuttondown = 0x0201,
LBUTTONUP = 0x0202, Lbuttonup = 0x0202,
LBUTTONDBLCLK = 0x0203, Lbuttondblclk = 0x0203,
RBUTTONDOWN = 0x0204, Rbuttondown = 0x0204,
RBUTTONUP = 0x0205, Rbuttonup = 0x0205,
RBUTTONDBLCLK = 0x0206, Rbuttondblclk = 0x0206,
MBUTTONDOWN = 0x0207, Mbuttondown = 0x0207,
MBUTTONUP = 0x0208, Mbuttonup = 0x0208,
MBUTTONDBLCLK = 0x0209, Mbuttondblclk = 0x0209,
MOUSEWHEEL = 0x020A, Mousewheel = 0x020A,
XBUTTONDOWN = 0x020B, Xbuttondown = 0x020B,
XBUTTONUP = 0x020C, Xbuttonup = 0x020C,
XBUTTONDBLCLK = 0x020D, Xbuttondblclk = 0x020D,
MOUSEHWHEEL = 0x020E, Mousehwheel = 0x020E,
MOUSELAST = 0x020E Mouselast = 0x020E,
} }
[UnmanagedFunctionPointer(CallingConvention.Winapi)] [UnmanagedFunctionPointer(CallingConvention.Winapi)]
internal delegate IntPtr WindowProc(IntPtr hWnd, WindowsMessages msg, IntPtr wParam, IntPtr lParam); internal delegate IntPtr WindowProc(IntPtr hWnd, WindowsMessages msg, IntPtr wParam, IntPtr lParam);
[StructLayout(LayoutKind.Sequential)] [StructLayout(LayoutKind.Sequential)]
public struct WNDCLASSEX public struct WndClassEx
{ {
public int cbSize; public int cbSize;
public ClassStyles style; public ClassStyles style;
@@ -64,9 +66,9 @@ namespace Ryujinx.Ava.UI.Helpers
public IntPtr lpszClassName; public IntPtr lpszClassName;
public IntPtr hIconSm; public IntPtr hIconSm;
public WNDCLASSEX() public WndClassEx()
{ {
cbSize = Marshal.SizeOf<WNDCLASSEX>(); cbSize = Marshal.SizeOf<WndClassEx>();
} }
} }
@@ -77,17 +79,17 @@ namespace Ryujinx.Ava.UI.Helpers
public static IntPtr CreateArrowCursor() public static IntPtr CreateArrowCursor()
{ {
return LoadCursor(IntPtr.Zero, (IntPtr)Cursors.IDC_ARROW); return LoadCursor(IntPtr.Zero, (IntPtr)Cursors.IdcArrow);
} }
[LibraryImport("user32.dll")] [LibraryImport("user32.dll")]
public static partial IntPtr SetCursor(IntPtr handle); public static partial IntPtr SetCursor(IntPtr handle);
[LibraryImport("user32.dll")] [LibraryImport("user32.dll")]
public static partial IntPtr CreateCursor(IntPtr hInst, int xHotSpot, int yHotSpot, int nWidth, int nHeight, byte[] pvANDPlane, byte[] pvXORPlane); public static partial IntPtr CreateCursor(IntPtr hInst, int xHotSpot, int yHotSpot, int nWidth, int nHeight, byte[] pvAndPlane, byte[] pvXorPlane);
[LibraryImport("user32.dll", SetLastError = true, EntryPoint = "RegisterClassExW")] [LibraryImport("user32.dll", SetLastError = true, EntryPoint = "RegisterClassExW")]
public static partial ushort RegisterClassEx(ref WNDCLASSEX param); public static partial ushort RegisterClassEx(ref WndClassEx param);
[LibraryImport("user32.dll", SetLastError = true, EntryPoint = "UnregisterClassW")] [LibraryImport("user32.dll", SetLastError = true, EntryPoint = "UnregisterClassW")]
public static partial short UnregisterClass([MarshalAs(UnmanagedType.LPWStr)] string lpClassName, IntPtr instance); public static partial short UnregisterClass([MarshalAs(UnmanagedType.LPWStr)] string lpClassName, IntPtr instance);

View File

@@ -35,6 +35,6 @@ namespace Ryujinx.Ava.UI.Models
public string Name { get; } public string Name { get; }
public string CleanName => Name.Substring(1, Name.Length - 8); public string CleanName => Name[1..^7];
} }
} }

View File

@@ -4,6 +4,6 @@ namespace Ryujinx.Ava.UI.Models
{ {
None, None,
Keyboard, Keyboard,
Controller Controller,
} }
} }

View File

@@ -7,16 +7,16 @@ using System;
namespace Ryujinx.Ava.UI.Models namespace Ryujinx.Ava.UI.Models
{ {
internal class InputConfiguration<Key, Stick> : BaseModel internal class InputConfiguration<TKey, TStick> : BaseModel
{ {
private float _deadzoneRight; private float _deadzoneRight;
private float _triggerThreshold; private float _triggerThreshold;
private float _deadzoneLeft; private float _deadzoneLeft;
private double _gyroDeadzone; private double _gyroDeadzone;
private int _sensitivity; private int _sensitivity;
private bool enableMotion; private bool _enableMotion;
private float weakRumble; private float _weakRumble;
private float strongRumble; private float _strongRumble;
private float _rangeLeft; private float _rangeLeft;
private float _rangeRight; private float _rangeRight;
@@ -37,17 +37,17 @@ namespace Ryujinx.Ava.UI.Models
/// </summary> /// </summary>
public PlayerIndex PlayerIndex { get; set; } public PlayerIndex PlayerIndex { get; set; }
public Stick LeftJoystick { get; set; } public TStick LeftJoystick { get; set; }
public bool LeftInvertStickX { get; set; } public bool LeftInvertStickX { get; set; }
public bool LeftInvertStickY { get; set; } public bool LeftInvertStickY { get; set; }
public bool RightRotate90 { get; set; } public bool RightRotate90 { get; set; }
public Key LeftControllerStickButton { get; set; } public TKey LeftControllerStickButton { get; set; }
public Stick RightJoystick { get; set; } public TStick RightJoystick { get; set; }
public bool RightInvertStickX { get; set; } public bool RightInvertStickX { get; set; }
public bool RightInvertStickY { get; set; } public bool RightInvertStickY { get; set; }
public bool LeftRotate90 { get; set; } public bool LeftRotate90 { get; set; }
public Key RightControllerStickButton { get; set; } public TKey RightControllerStickButton { get; set; }
public float DeadzoneLeft public float DeadzoneLeft
{ {
@@ -106,38 +106,37 @@ namespace Ryujinx.Ava.UI.Models
public MotionInputBackendType MotionBackend { get; set; } public MotionInputBackendType MotionBackend { get; set; }
public Key ButtonMinus { get; set; } public TKey ButtonMinus { get; set; }
public Key ButtonL { get; set; } public TKey ButtonL { get; set; }
public Key ButtonZl { get; set; } public TKey ButtonZl { get; set; }
public Key LeftButtonSl { get; set; } public TKey LeftButtonSl { get; set; }
public Key LeftButtonSr { get; set; } public TKey LeftButtonSr { get; set; }
public Key DpadUp { get; set; } public TKey DpadUp { get; set; }
public Key DpadDown { get; set; } public TKey DpadDown { get; set; }
public Key DpadLeft { get; set; } public TKey DpadLeft { get; set; }
public Key DpadRight { get; set; } public TKey DpadRight { get; set; }
public Key ButtonPlus { get; set; } public TKey ButtonPlus { get; set; }
public Key ButtonR { get; set; } public TKey ButtonR { get; set; }
public Key ButtonZr { get; set; } public TKey ButtonZr { get; set; }
public Key RightButtonSl { get; set; } public TKey RightButtonSl { get; set; }
public Key RightButtonSr { get; set; } public TKey RightButtonSr { get; set; }
public Key ButtonX { get; set; } public TKey ButtonX { get; set; }
public Key ButtonB { get; set; } public TKey ButtonB { get; set; }
public Key ButtonY { get; set; } public TKey ButtonY { get; set; }
public Key ButtonA { get; set; } public TKey ButtonA { get; set; }
public TKey LeftStickUp { get; set; }
public TKey LeftStickDown { get; set; }
public TKey LeftStickLeft { get; set; }
public TKey LeftStickRight { get; set; }
public TKey LeftKeyboardStickButton { get; set; }
public Key LeftStickUp { get; set; } public TKey RightStickUp { get; set; }
public Key LeftStickDown { get; set; } public TKey RightStickDown { get; set; }
public Key LeftStickLeft { get; set; } public TKey RightStickLeft { get; set; }
public Key LeftStickRight { get; set; } public TKey RightStickRight { get; set; }
public Key LeftKeyboardStickButton { get; set; } public TKey RightKeyboardStickButton { get; set; }
public Key RightStickUp { get; set; }
public Key RightStickDown { get; set; }
public Key RightStickLeft { get; set; }
public Key RightStickRight { get; set; }
public Key RightKeyboardStickButton { get; set; }
public int Sensitivity public int Sensitivity
{ {
@@ -163,9 +162,9 @@ namespace Ryujinx.Ava.UI.Models
public bool EnableMotion public bool EnableMotion
{ {
get => enableMotion; set get => _enableMotion; set
{ {
enableMotion = value; _enableMotion = value;
OnPropertyChanged(); OnPropertyChanged();
} }
@@ -181,18 +180,18 @@ namespace Ryujinx.Ava.UI.Models
public bool EnableRumble { get; set; } public bool EnableRumble { get; set; }
public float WeakRumble public float WeakRumble
{ {
get => weakRumble; set get => _weakRumble; set
{ {
weakRumble = value; _weakRumble = value;
OnPropertyChanged(); OnPropertyChanged();
} }
} }
public float StrongRumble public float StrongRumble
{ {
get => strongRumble; set get => _strongRumble; set
{ {
strongRumble = value; _strongRumble = value;
OnPropertyChanged(); OnPropertyChanged();
} }
@@ -209,71 +208,71 @@ namespace Ryujinx.Ava.UI.Models
if (config is StandardKeyboardInputConfig keyboardConfig) if (config is StandardKeyboardInputConfig keyboardConfig)
{ {
LeftStickUp = (Key)(object)keyboardConfig.LeftJoyconStick.StickUp; LeftStickUp = (TKey)(object)keyboardConfig.LeftJoyconStick.StickUp;
LeftStickDown = (Key)(object)keyboardConfig.LeftJoyconStick.StickDown; LeftStickDown = (TKey)(object)keyboardConfig.LeftJoyconStick.StickDown;
LeftStickLeft = (Key)(object)keyboardConfig.LeftJoyconStick.StickLeft; LeftStickLeft = (TKey)(object)keyboardConfig.LeftJoyconStick.StickLeft;
LeftStickRight = (Key)(object)keyboardConfig.LeftJoyconStick.StickRight; LeftStickRight = (TKey)(object)keyboardConfig.LeftJoyconStick.StickRight;
LeftKeyboardStickButton = (Key)(object)keyboardConfig.LeftJoyconStick.StickButton; LeftKeyboardStickButton = (TKey)(object)keyboardConfig.LeftJoyconStick.StickButton;
RightStickUp = (Key)(object)keyboardConfig.RightJoyconStick.StickUp; RightStickUp = (TKey)(object)keyboardConfig.RightJoyconStick.StickUp;
RightStickDown = (Key)(object)keyboardConfig.RightJoyconStick.StickDown; RightStickDown = (TKey)(object)keyboardConfig.RightJoyconStick.StickDown;
RightStickLeft = (Key)(object)keyboardConfig.RightJoyconStick.StickLeft; RightStickLeft = (TKey)(object)keyboardConfig.RightJoyconStick.StickLeft;
RightStickRight = (Key)(object)keyboardConfig.RightJoyconStick.StickRight; RightStickRight = (TKey)(object)keyboardConfig.RightJoyconStick.StickRight;
RightKeyboardStickButton = (Key)(object)keyboardConfig.RightJoyconStick.StickButton; RightKeyboardStickButton = (TKey)(object)keyboardConfig.RightJoyconStick.StickButton;
ButtonA = (Key)(object)keyboardConfig.RightJoycon.ButtonA; ButtonA = (TKey)(object)keyboardConfig.RightJoycon.ButtonA;
ButtonB = (Key)(object)keyboardConfig.RightJoycon.ButtonB; ButtonB = (TKey)(object)keyboardConfig.RightJoycon.ButtonB;
ButtonX = (Key)(object)keyboardConfig.RightJoycon.ButtonX; ButtonX = (TKey)(object)keyboardConfig.RightJoycon.ButtonX;
ButtonY = (Key)(object)keyboardConfig.RightJoycon.ButtonY; ButtonY = (TKey)(object)keyboardConfig.RightJoycon.ButtonY;
ButtonR = (Key)(object)keyboardConfig.RightJoycon.ButtonR; ButtonR = (TKey)(object)keyboardConfig.RightJoycon.ButtonR;
RightButtonSl = (Key)(object)keyboardConfig.RightJoycon.ButtonSl; RightButtonSl = (TKey)(object)keyboardConfig.RightJoycon.ButtonSl;
RightButtonSr = (Key)(object)keyboardConfig.RightJoycon.ButtonSr; RightButtonSr = (TKey)(object)keyboardConfig.RightJoycon.ButtonSr;
ButtonZr = (Key)(object)keyboardConfig.RightJoycon.ButtonZr; ButtonZr = (TKey)(object)keyboardConfig.RightJoycon.ButtonZr;
ButtonPlus = (Key)(object)keyboardConfig.RightJoycon.ButtonPlus; ButtonPlus = (TKey)(object)keyboardConfig.RightJoycon.ButtonPlus;
DpadUp = (Key)(object)keyboardConfig.LeftJoycon.DpadUp; DpadUp = (TKey)(object)keyboardConfig.LeftJoycon.DpadUp;
DpadDown = (Key)(object)keyboardConfig.LeftJoycon.DpadDown; DpadDown = (TKey)(object)keyboardConfig.LeftJoycon.DpadDown;
DpadLeft = (Key)(object)keyboardConfig.LeftJoycon.DpadLeft; DpadLeft = (TKey)(object)keyboardConfig.LeftJoycon.DpadLeft;
DpadRight = (Key)(object)keyboardConfig.LeftJoycon.DpadRight; DpadRight = (TKey)(object)keyboardConfig.LeftJoycon.DpadRight;
ButtonMinus = (Key)(object)keyboardConfig.LeftJoycon.ButtonMinus; ButtonMinus = (TKey)(object)keyboardConfig.LeftJoycon.ButtonMinus;
LeftButtonSl = (Key)(object)keyboardConfig.LeftJoycon.ButtonSl; LeftButtonSl = (TKey)(object)keyboardConfig.LeftJoycon.ButtonSl;
LeftButtonSr = (Key)(object)keyboardConfig.LeftJoycon.ButtonSr; LeftButtonSr = (TKey)(object)keyboardConfig.LeftJoycon.ButtonSr;
ButtonZl = (Key)(object)keyboardConfig.LeftJoycon.ButtonZl; ButtonZl = (TKey)(object)keyboardConfig.LeftJoycon.ButtonZl;
ButtonL = (Key)(object)keyboardConfig.LeftJoycon.ButtonL; ButtonL = (TKey)(object)keyboardConfig.LeftJoycon.ButtonL;
} }
else if (config is StandardControllerInputConfig controllerConfig) else if (config is StandardControllerInputConfig controllerConfig)
{ {
LeftJoystick = (Stick)(object)controllerConfig.LeftJoyconStick.Joystick; LeftJoystick = (TStick)(object)controllerConfig.LeftJoyconStick.Joystick;
LeftInvertStickX = controllerConfig.LeftJoyconStick.InvertStickX; LeftInvertStickX = controllerConfig.LeftJoyconStick.InvertStickX;
LeftInvertStickY = controllerConfig.LeftJoyconStick.InvertStickY; LeftInvertStickY = controllerConfig.LeftJoyconStick.InvertStickY;
LeftRotate90 = controllerConfig.LeftJoyconStick.Rotate90CW; LeftRotate90 = controllerConfig.LeftJoyconStick.Rotate90CW;
LeftControllerStickButton = (Key)(object)controllerConfig.LeftJoyconStick.StickButton; LeftControllerStickButton = (TKey)(object)controllerConfig.LeftJoyconStick.StickButton;
RightJoystick = (Stick)(object)controllerConfig.RightJoyconStick.Joystick; RightJoystick = (TStick)(object)controllerConfig.RightJoyconStick.Joystick;
RightInvertStickX = controllerConfig.RightJoyconStick.InvertStickX; RightInvertStickX = controllerConfig.RightJoyconStick.InvertStickX;
RightInvertStickY = controllerConfig.RightJoyconStick.InvertStickY; RightInvertStickY = controllerConfig.RightJoyconStick.InvertStickY;
RightRotate90 = controllerConfig.RightJoyconStick.Rotate90CW; RightRotate90 = controllerConfig.RightJoyconStick.Rotate90CW;
RightControllerStickButton = (Key)(object)controllerConfig.RightJoyconStick.StickButton; RightControllerStickButton = (TKey)(object)controllerConfig.RightJoyconStick.StickButton;
ButtonA = (Key)(object)controllerConfig.RightJoycon.ButtonA; ButtonA = (TKey)(object)controllerConfig.RightJoycon.ButtonA;
ButtonB = (Key)(object)controllerConfig.RightJoycon.ButtonB; ButtonB = (TKey)(object)controllerConfig.RightJoycon.ButtonB;
ButtonX = (Key)(object)controllerConfig.RightJoycon.ButtonX; ButtonX = (TKey)(object)controllerConfig.RightJoycon.ButtonX;
ButtonY = (Key)(object)controllerConfig.RightJoycon.ButtonY; ButtonY = (TKey)(object)controllerConfig.RightJoycon.ButtonY;
ButtonR = (Key)(object)controllerConfig.RightJoycon.ButtonR; ButtonR = (TKey)(object)controllerConfig.RightJoycon.ButtonR;
RightButtonSl = (Key)(object)controllerConfig.RightJoycon.ButtonSl; RightButtonSl = (TKey)(object)controllerConfig.RightJoycon.ButtonSl;
RightButtonSr = (Key)(object)controllerConfig.RightJoycon.ButtonSr; RightButtonSr = (TKey)(object)controllerConfig.RightJoycon.ButtonSr;
ButtonZr = (Key)(object)controllerConfig.RightJoycon.ButtonZr; ButtonZr = (TKey)(object)controllerConfig.RightJoycon.ButtonZr;
ButtonPlus = (Key)(object)controllerConfig.RightJoycon.ButtonPlus; ButtonPlus = (TKey)(object)controllerConfig.RightJoycon.ButtonPlus;
DpadUp = (Key)(object)controllerConfig.LeftJoycon.DpadUp; DpadUp = (TKey)(object)controllerConfig.LeftJoycon.DpadUp;
DpadDown = (Key)(object)controllerConfig.LeftJoycon.DpadDown; DpadDown = (TKey)(object)controllerConfig.LeftJoycon.DpadDown;
DpadLeft = (Key)(object)controllerConfig.LeftJoycon.DpadLeft; DpadLeft = (TKey)(object)controllerConfig.LeftJoycon.DpadLeft;
DpadRight = (Key)(object)controllerConfig.LeftJoycon.DpadRight; DpadRight = (TKey)(object)controllerConfig.LeftJoycon.DpadRight;
ButtonMinus = (Key)(object)controllerConfig.LeftJoycon.ButtonMinus; ButtonMinus = (TKey)(object)controllerConfig.LeftJoycon.ButtonMinus;
LeftButtonSl = (Key)(object)controllerConfig.LeftJoycon.ButtonSl; LeftButtonSl = (TKey)(object)controllerConfig.LeftJoycon.ButtonSl;
LeftButtonSr = (Key)(object)controllerConfig.LeftJoycon.ButtonSr; LeftButtonSr = (TKey)(object)controllerConfig.LeftJoycon.ButtonSr;
ButtonZl = (Key)(object)controllerConfig.LeftJoycon.ButtonZl; ButtonZl = (TKey)(object)controllerConfig.LeftJoycon.ButtonZl;
ButtonL = (Key)(object)controllerConfig.LeftJoycon.ButtonL; ButtonL = (TKey)(object)controllerConfig.LeftJoycon.ButtonL;
DeadzoneLeft = controllerConfig.DeadzoneLeft; DeadzoneLeft = controllerConfig.DeadzoneLeft;
DeadzoneRight = controllerConfig.DeadzoneRight; DeadzoneRight = controllerConfig.DeadzoneRight;
@@ -317,65 +316,66 @@ namespace Ryujinx.Ava.UI.Models
{ {
if (Backend == InputBackendType.WindowKeyboard) if (Backend == InputBackendType.WindowKeyboard)
{ {
return new StandardKeyboardInputConfig() return new StandardKeyboardInputConfig
{ {
Id = Id, Id = Id,
Backend = Backend, Backend = Backend,
PlayerIndex = PlayerIndex, PlayerIndex = PlayerIndex,
ControllerType = ControllerType, ControllerType = ControllerType,
LeftJoycon = new LeftJoyconCommonConfig<Ryujinx.Common.Configuration.Hid.Key>() LeftJoycon = new LeftJoyconCommonConfig<Key>
{ {
DpadUp = (Ryujinx.Common.Configuration.Hid.Key)(object)DpadUp, DpadUp = (Key)(object)DpadUp,
DpadDown = (Ryujinx.Common.Configuration.Hid.Key)(object)DpadDown, DpadDown = (Key)(object)DpadDown,
DpadLeft = (Ryujinx.Common.Configuration.Hid.Key)(object)DpadLeft, DpadLeft = (Key)(object)DpadLeft,
DpadRight = (Ryujinx.Common.Configuration.Hid.Key)(object)DpadRight, DpadRight = (Key)(object)DpadRight,
ButtonL = (Ryujinx.Common.Configuration.Hid.Key)(object)ButtonL, ButtonL = (Key)(object)ButtonL,
ButtonZl = (Ryujinx.Common.Configuration.Hid.Key)(object)ButtonZl, ButtonZl = (Key)(object)ButtonZl,
ButtonSl = (Ryujinx.Common.Configuration.Hid.Key)(object)LeftButtonSl, ButtonSl = (Key)(object)LeftButtonSl,
ButtonSr = (Ryujinx.Common.Configuration.Hid.Key)(object)LeftButtonSr, ButtonSr = (Key)(object)LeftButtonSr,
ButtonMinus = (Ryujinx.Common.Configuration.Hid.Key)(object)ButtonMinus ButtonMinus = (Key)(object)ButtonMinus,
}, },
RightJoycon = new RightJoyconCommonConfig<Ryujinx.Common.Configuration.Hid.Key>() RightJoycon = new RightJoyconCommonConfig<Key>
{ {
ButtonA = (Ryujinx.Common.Configuration.Hid.Key)(object)ButtonA, ButtonA = (Key)(object)ButtonA,
ButtonB = (Ryujinx.Common.Configuration.Hid.Key)(object)ButtonB, ButtonB = (Key)(object)ButtonB,
ButtonX = (Ryujinx.Common.Configuration.Hid.Key)(object)ButtonX, ButtonX = (Key)(object)ButtonX,
ButtonY = (Ryujinx.Common.Configuration.Hid.Key)(object)ButtonY, ButtonY = (Key)(object)ButtonY,
ButtonPlus = (Ryujinx.Common.Configuration.Hid.Key)(object)ButtonPlus, ButtonPlus = (Key)(object)ButtonPlus,
ButtonSl = (Ryujinx.Common.Configuration.Hid.Key)(object)RightButtonSl, ButtonSl = (Key)(object)RightButtonSl,
ButtonSr = (Ryujinx.Common.Configuration.Hid.Key)(object)RightButtonSr, ButtonSr = (Key)(object)RightButtonSr,
ButtonR = (Ryujinx.Common.Configuration.Hid.Key)(object)ButtonR, ButtonR = (Key)(object)ButtonR,
ButtonZr = (Ryujinx.Common.Configuration.Hid.Key)(object)ButtonZr ButtonZr = (Key)(object)ButtonZr,
}, },
LeftJoyconStick = new JoyconConfigKeyboardStick<Ryujinx.Common.Configuration.Hid.Key>() LeftJoyconStick = new JoyconConfigKeyboardStick<Key>
{ {
StickUp = (Ryujinx.Common.Configuration.Hid.Key)(object)LeftStickUp, StickUp = (Key)(object)LeftStickUp,
StickDown = (Ryujinx.Common.Configuration.Hid.Key)(object)LeftStickDown, StickDown = (Key)(object)LeftStickDown,
StickRight = (Ryujinx.Common.Configuration.Hid.Key)(object)LeftStickRight, StickRight = (Key)(object)LeftStickRight,
StickLeft = (Ryujinx.Common.Configuration.Hid.Key)(object)LeftStickLeft, StickLeft = (Key)(object)LeftStickLeft,
StickButton = (Ryujinx.Common.Configuration.Hid.Key)(object)LeftKeyboardStickButton StickButton = (Key)(object)LeftKeyboardStickButton,
}, },
RightJoyconStick = new JoyconConfigKeyboardStick<Ryujinx.Common.Configuration.Hid.Key>() RightJoyconStick = new JoyconConfigKeyboardStick<Key>
{ {
StickUp = (Ryujinx.Common.Configuration.Hid.Key)(object)RightStickUp, StickUp = (Key)(object)RightStickUp,
StickDown = (Ryujinx.Common.Configuration.Hid.Key)(object)RightStickDown, StickDown = (Key)(object)RightStickDown,
StickLeft = (Ryujinx.Common.Configuration.Hid.Key)(object)RightStickLeft, StickLeft = (Key)(object)RightStickLeft,
StickRight = (Ryujinx.Common.Configuration.Hid.Key)(object)RightStickRight, StickRight = (Key)(object)RightStickRight,
StickButton = (Ryujinx.Common.Configuration.Hid.Key)(object)RightKeyboardStickButton StickButton = (Key)(object)RightKeyboardStickButton,
}, },
Version = InputConfig.CurrentVersion Version = InputConfig.CurrentVersion,
}; };
} }
else if (Backend == InputBackendType.GamepadSDL2)
if (Backend == InputBackendType.GamepadSDL2)
{ {
var config = new StandardControllerInputConfig() var config = new StandardControllerInputConfig
{ {
Id = Id, Id = Id,
Backend = Backend, Backend = Backend,
PlayerIndex = PlayerIndex, PlayerIndex = PlayerIndex,
ControllerType = ControllerType, ControllerType = ControllerType,
LeftJoycon = new LeftJoyconCommonConfig<GamepadInputId>() LeftJoycon = new LeftJoyconCommonConfig<GamepadInputId>
{ {
DpadUp = (GamepadInputId)(object)DpadUp, DpadUp = (GamepadInputId)(object)DpadUp,
DpadDown = (GamepadInputId)(object)DpadDown, DpadDown = (GamepadInputId)(object)DpadDown,
@@ -387,7 +387,7 @@ namespace Ryujinx.Ava.UI.Models
ButtonSr = (GamepadInputId)(object)LeftButtonSr, ButtonSr = (GamepadInputId)(object)LeftButtonSr,
ButtonMinus = (GamepadInputId)(object)ButtonMinus, ButtonMinus = (GamepadInputId)(object)ButtonMinus,
}, },
RightJoycon = new RightJoyconCommonConfig<GamepadInputId>() RightJoycon = new RightJoyconCommonConfig<GamepadInputId>
{ {
ButtonA = (GamepadInputId)(object)ButtonA, ButtonA = (GamepadInputId)(object)ButtonA,
ButtonB = (GamepadInputId)(object)ButtonB, ButtonB = (GamepadInputId)(object)ButtonB,
@@ -399,7 +399,7 @@ namespace Ryujinx.Ava.UI.Models
ButtonR = (GamepadInputId)(object)ButtonR, ButtonR = (GamepadInputId)(object)ButtonR,
ButtonZr = (GamepadInputId)(object)ButtonZr, ButtonZr = (GamepadInputId)(object)ButtonZr,
}, },
LeftJoyconStick = new JoyconConfigControllerStick<GamepadInputId, StickInputId>() LeftJoyconStick = new JoyconConfigControllerStick<GamepadInputId, StickInputId>
{ {
Joystick = (StickInputId)(object)LeftJoystick, Joystick = (StickInputId)(object)LeftJoystick,
InvertStickX = LeftInvertStickX, InvertStickX = LeftInvertStickX,
@@ -407,7 +407,7 @@ namespace Ryujinx.Ava.UI.Models
Rotate90CW = LeftRotate90, Rotate90CW = LeftRotate90,
StickButton = (GamepadInputId)(object)LeftControllerStickButton, StickButton = (GamepadInputId)(object)LeftControllerStickButton,
}, },
RightJoyconStick = new JoyconConfigControllerStick<GamepadInputId, StickInputId>() RightJoyconStick = new JoyconConfigControllerStick<GamepadInputId, StickInputId>
{ {
Joystick = (StickInputId)(object)RightJoystick, Joystick = (StickInputId)(object)RightJoystick,
InvertStickX = RightInvertStickX, InvertStickX = RightInvertStickX,
@@ -415,11 +415,11 @@ namespace Ryujinx.Ava.UI.Models
Rotate90CW = RightRotate90, Rotate90CW = RightRotate90,
StickButton = (GamepadInputId)(object)RightControllerStickButton, StickButton = (GamepadInputId)(object)RightControllerStickButton,
}, },
Rumble = new RumbleConfigController() Rumble = new RumbleConfigController
{ {
EnableRumble = EnableRumble, EnableRumble = EnableRumble,
WeakRumble = WeakRumble, WeakRumble = WeakRumble,
StrongRumble = StrongRumble StrongRumble = StrongRumble,
}, },
Version = InputConfig.CurrentVersion, Version = InputConfig.CurrentVersion,
DeadzoneLeft = DeadzoneLeft, DeadzoneLeft = DeadzoneLeft,
@@ -428,19 +428,19 @@ namespace Ryujinx.Ava.UI.Models
RangeRight = RangeRight, RangeRight = RangeRight,
TriggerThreshold = TriggerThreshold, TriggerThreshold = TriggerThreshold,
Motion = EnableCemuHookMotion Motion = EnableCemuHookMotion
? new CemuHookMotionConfigController() ? new CemuHookMotionConfigController
{ {
DsuServerHost = DsuServerHost, DsuServerHost = DsuServerHost,
DsuServerPort = DsuServerPort, DsuServerPort = DsuServerPort,
Slot = Slot, Slot = Slot,
AltSlot = AltSlot, AltSlot = AltSlot,
MirrorInput = MirrorInput, MirrorInput = MirrorInput,
MotionBackend = MotionInputBackendType.CemuHook MotionBackend = MotionInputBackendType.CemuHook,
} }
: new StandardMotionConfigController() : new StandardMotionConfigController
{ {
MotionBackend = MotionInputBackendType.GamepadDriver MotionBackend = MotionInputBackendType.GamepadDriver,
} },
}; };
config.Motion.Sensitivity = Sensitivity; config.Motion.Sensitivity = Sensitivity;

View File

@@ -8,6 +8,7 @@ using System;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using Path = System.IO.Path;
namespace Ryujinx.Ava.UI.Models namespace Ryujinx.Ava.UI.Models
{ {
@@ -58,7 +59,7 @@ namespace Ryujinx.Ava.UI.Models
return "0 KiB"; return "0 KiB";
} }
public SaveModel(SaveDataInfo info, VirtualFileSystem virtualFileSystem) public SaveModel(SaveDataInfo info)
{ {
SaveId = info.SaveDataId; SaveId = info.SaveDataId;
TitleId = info.ProgramId; TitleId = info.ProgramId;
@@ -81,10 +82,11 @@ namespace Ryujinx.Ava.UI.Models
Task.Run(() => Task.Run(() =>
{ {
var saveRoot = System.IO.Path.Combine(virtualFileSystem.GetNandPath(), $"user/save/{info.SaveDataId:x16}"); var saveRoot = Path.Combine(VirtualFileSystem.GetNandPath(), $"user/save/{info.SaveDataId:x16}");
long total_size = GetDirectorySize(saveRoot); long totalSize = GetDirectorySize(saveRoot);
long GetDirectorySize(string path)
static long GetDirectorySize(string path)
{ {
long size = 0; long size = 0;
if (Directory.Exists(path)) if (Directory.Exists(path))
@@ -105,7 +107,7 @@ namespace Ryujinx.Ava.UI.Models
return size; return size;
} }
Size = total_size; Size = totalSize;
}); });
} }

View File

@@ -11,7 +11,7 @@ namespace Ryujinx.Ava.UI.Models
private string _name = String.Empty; private string _name = String.Empty;
private UserId _userId; private UserId _userId;
public uint MaxProfileNameLength => 0x20; public static uint MaxProfileNameLength => 0x20;
public byte[] Image public byte[] Image
{ {

View File

@@ -1,3 +1,4 @@
using Avalonia;
using Avalonia.Media; using Avalonia.Media;
using Ryujinx.Ava.UI.Controls; using Ryujinx.Ava.UI.Controls;
using Ryujinx.Ava.UI.ViewModels; using Ryujinx.Ava.UI.ViewModels;
@@ -87,7 +88,7 @@ namespace Ryujinx.Ava.UI.Models
private void UpdateBackground() private void UpdateBackground()
{ {
Avalonia.Application.Current.Styles.TryGetResource("ControlFillColorSecondary", out object color); Application.Current.Styles.TryGetResource("ControlFillColorSecondary", out object color);
if (color is not null) if (color is not null)
{ {

View File

@@ -77,11 +77,13 @@ namespace Ryujinx.Ava.UI.Renderer
{ {
return CreateLinux(control); return CreateLinux(control);
} }
else if (OperatingSystem.IsWindows())
if (OperatingSystem.IsWindows())
{ {
return CreateWin32(control); return CreateWin32(control);
} }
else if (OperatingSystem.IsMacOS())
if (OperatingSystem.IsMacOS())
{ {
return CreateMacOS(); return CreateMacOS();
} }
@@ -141,21 +143,21 @@ namespace Ryujinx.Ava.UI.Renderer
{ {
if (VisualRoot != null) if (VisualRoot != null)
{ {
if (msg == WindowsMessages.LBUTTONDOWN || if (msg == WindowsMessages.Lbuttondown ||
msg == WindowsMessages.RBUTTONDOWN || msg == WindowsMessages.Rbuttondown ||
msg == WindowsMessages.LBUTTONUP || msg == WindowsMessages.Lbuttonup ||
msg == WindowsMessages.RBUTTONUP || msg == WindowsMessages.Rbuttonup ||
msg == WindowsMessages.MOUSEMOVE) msg == WindowsMessages.Mousemove)
{ {
Point rootVisualPosition = this.TranslatePoint(new Point((long)lParam & 0xFFFF, (long)lParam >> 16 & 0xFFFF), VisualRoot).Value; Point rootVisualPosition = this.TranslatePoint(new Point((long)lParam & 0xFFFF, (long)lParam >> 16 & 0xFFFF), VisualRoot).Value;
Pointer pointer = new(0, PointerType.Mouse, true); Pointer pointer = new(0, PointerType.Mouse, true);
switch (msg) switch (msg)
{ {
case WindowsMessages.LBUTTONDOWN: case WindowsMessages.Lbuttondown:
case WindowsMessages.RBUTTONDOWN: case WindowsMessages.Rbuttondown:
{ {
bool isLeft = msg == WindowsMessages.LBUTTONDOWN; bool isLeft = msg == WindowsMessages.Lbuttondown;
RawInputModifiers pointerPointModifier = isLeft ? RawInputModifiers.LeftMouseButton : RawInputModifiers.RightMouseButton; RawInputModifiers pointerPointModifier = isLeft ? RawInputModifiers.LeftMouseButton : RawInputModifiers.RightMouseButton;
PointerPointProperties properties = new(pointerPointModifier, isLeft ? PointerUpdateKind.LeftButtonPressed : PointerUpdateKind.RightButtonPressed); PointerPointProperties properties = new(pointerPointModifier, isLeft ? PointerUpdateKind.LeftButtonPressed : PointerUpdateKind.RightButtonPressed);
@@ -172,10 +174,10 @@ namespace Ryujinx.Ava.UI.Renderer
break; break;
} }
case WindowsMessages.LBUTTONUP: case WindowsMessages.Lbuttonup:
case WindowsMessages.RBUTTONUP: case WindowsMessages.Rbuttonup:
{ {
bool isLeft = msg == WindowsMessages.LBUTTONUP; bool isLeft = msg == WindowsMessages.Lbuttonup;
RawInputModifiers pointerPointModifier = isLeft ? RawInputModifiers.LeftMouseButton : RawInputModifiers.RightMouseButton; RawInputModifiers pointerPointModifier = isLeft ? RawInputModifiers.LeftMouseButton : RawInputModifiers.RightMouseButton;
PointerPointProperties properties = new(pointerPointModifier, isLeft ? PointerUpdateKind.LeftButtonReleased : PointerUpdateKind.RightButtonReleased); PointerPointProperties properties = new(pointerPointModifier, isLeft ? PointerUpdateKind.LeftButtonReleased : PointerUpdateKind.RightButtonReleased);
@@ -193,7 +195,7 @@ namespace Ryujinx.Ava.UI.Renderer
break; break;
} }
case WindowsMessages.MOUSEMOVE: case WindowsMessages.Mousemove:
{ {
var evnt = new PointerEventArgs( var evnt = new PointerEventArgs(
PointerMovedEvent, PointerMovedEvent,
@@ -216,19 +218,19 @@ namespace Ryujinx.Ava.UI.Renderer
return DefWindowProc(hWnd, msg, wParam, lParam); return DefWindowProc(hWnd, msg, wParam, lParam);
}; };
WNDCLASSEX wndClassEx = new() WndClassEx wndClassEx = new()
{ {
cbSize = Marshal.SizeOf<WNDCLASSEX>(), cbSize = Marshal.SizeOf<WndClassEx>(),
hInstance = GetModuleHandle(null), hInstance = GetModuleHandle(null),
lpfnWndProc = Marshal.GetFunctionPointerForDelegate(_wndProcDelegate), lpfnWndProc = Marshal.GetFunctionPointerForDelegate(_wndProcDelegate),
style = ClassStyles.CS_OWNDC, style = ClassStyles.CsOwndc,
lpszClassName = Marshal.StringToHGlobalUni(_className), lpszClassName = Marshal.StringToHGlobalUni(_className),
hCursor = CreateArrowCursor() hCursor = CreateArrowCursor(),
}; };
RegisterClassEx(ref wndClassEx); RegisterClassEx(ref wndClassEx);
WindowHandle = CreateWindowEx(0, _className, "NativeWindow", WindowStyles.WS_CHILD, 0, 0, 640, 480, control.Handle, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero); WindowHandle = CreateWindowEx(0, _className, "NativeWindow", WindowStyles.WsChild, 0, 0, 640, 480, control.Handle, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero);
Marshal.FreeHGlobal(wndClassEx.lpszClassName); Marshal.FreeHGlobal(wndClassEx.lpszClassName);
@@ -280,9 +282,11 @@ namespace Ryujinx.Ava.UI.Renderer
} }
[SupportedOSPlatform("macos")] [SupportedOSPlatform("macos")]
#pragma warning disable CA1822 // Mark member as static
void DestroyMacOS() void DestroyMacOS()
{ {
// TODO // TODO
} }
#pragma warning restore CA1822
} }
} }

View File

@@ -34,7 +34,7 @@ namespace Ryujinx.Ava.UI.Renderer
return new SurfaceKHR((ulong?)VulkanHelper.CreateWindowSurface(instance.Handle, nativeWindowBase)); return new SurfaceKHR((ulong?)VulkanHelper.CreateWindowSurface(instance.Handle, nativeWindowBase));
} }
public SurfaceKHR CreateSurface(Instance instance, Vk api) public SurfaceKHR CreateSurface(Instance instance, Vk _)
{ {
return CreateSurface(instance); return CreateSurface(instance);
} }

View File

@@ -1,5 +1,6 @@
using Avalonia; using Avalonia;
using Avalonia.Media.Imaging; using Avalonia.Media.Imaging;
using Avalonia.Platform;
using Avalonia.Threading; using Avalonia.Threading;
using Ryujinx.Ava.Common.Locale; using Ryujinx.Ava.Common.Locale;
using Ryujinx.Common.Utilities; using Ryujinx.Common.Utilities;
@@ -87,7 +88,7 @@ namespace Ryujinx.Ava.UI.ViewModels
{ {
Version = Program.Version; Version = Program.Version;
var assets = AvaloniaLocator.Current.GetService<Avalonia.Platform.IAssetLoader>(); var assets = AvaloniaLocator.Current.GetService<IAssetLoader>();
if (ConfigurationState.Instance.Ui.BaseStyle.Value == "Light") if (ConfigurationState.Instance.Ui.BaseStyle.Value == "Light")
{ {

View File

@@ -18,7 +18,6 @@ using System.Linq;
using System.Net.Http; using System.Net.Http;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using AmiiboJsonSerializerContext = Ryujinx.Ui.Common.Models.Amiibo.AmiiboJsonSerializerContext;
namespace Ryujinx.Ava.UI.ViewModels namespace Ryujinx.Ava.UI.ViewModels
{ {
@@ -44,7 +43,7 @@ namespace Ryujinx.Ava.UI.ViewModels
private bool _useRandomUuid; private bool _useRandomUuid;
private string _usage; private string _usage;
private static readonly AmiiboJsonSerializerContext SerializerContext = new(JsonHelper.GetDefaultSerializerOptions()); private static readonly AmiiboJsonSerializerContext _serializerContext = new(JsonHelper.GetDefaultSerializerOptions());
public AmiiboWindowViewModel(StyleableWindow owner, string lastScannedAmiiboId, string titleId) public AmiiboWindowViewModel(StyleableWindow owner, string lastScannedAmiiboId, string titleId)
{ {
@@ -52,7 +51,7 @@ namespace Ryujinx.Ava.UI.ViewModels
_httpClient = new HttpClient _httpClient = new HttpClient
{ {
Timeout = TimeSpan.FromSeconds(30) Timeout = TimeSpan.FromSeconds(30),
}; };
LastScannedAmiiboId = lastScannedAmiiboId; LastScannedAmiiboId = lastScannedAmiiboId;
@@ -185,6 +184,7 @@ namespace Ryujinx.Ava.UI.ViewModels
public void Dispose() public void Dispose()
{ {
GC.SuppressFinalize(this);
_httpClient.Dispose(); _httpClient.Dispose();
} }
@@ -196,7 +196,7 @@ namespace Ryujinx.Ava.UI.ViewModels
{ {
amiiboJsonString = await File.ReadAllTextAsync(_amiiboJsonPath); amiiboJsonString = await File.ReadAllTextAsync(_amiiboJsonPath);
if (await NeedsUpdate(JsonHelper.Deserialize(amiiboJsonString, SerializerContext.AmiiboJson).LastUpdated)) if (await NeedsUpdate(JsonHelper.Deserialize(amiiboJsonString, _serializerContext.AmiiboJson).LastUpdated))
{ {
amiiboJsonString = await DownloadAmiiboJson(); amiiboJsonString = await DownloadAmiiboJson();
} }
@@ -215,7 +215,7 @@ namespace Ryujinx.Ava.UI.ViewModels
} }
} }
_amiiboList = JsonHelper.Deserialize(amiiboJsonString, SerializerContext.AmiiboJson).Amiibo; _amiiboList = JsonHelper.Deserialize(amiiboJsonString, _serializerContext.AmiiboJson).Amiibo;
_amiiboList = _amiiboList.OrderBy(amiibo => amiibo.AmiiboSeries).ToList(); _amiiboList = _amiiboList.OrderBy(amiibo => amiibo.AmiiboSeries).ToList();
ParseAmiiboData(); ParseAmiiboData();
@@ -426,8 +426,8 @@ namespace Ryujinx.Ava.UI.ViewModels
if (response.IsSuccessStatusCode) if (response.IsSuccessStatusCode)
{ {
byte[] amiiboPreviewBytes = await response.Content.ReadAsByteArrayAsync(); byte[] amiiboPreviewBytes = await response.Content.ReadAsByteArrayAsync();
using (MemoryStream memoryStream = new(amiiboPreviewBytes)) using MemoryStream memoryStream = new(amiiboPreviewBytes);
{
Bitmap bitmap = new(memoryStream); Bitmap bitmap = new(memoryStream);
double ratio = Math.Min(AmiiboImageSize / bitmap.Size.Width, double ratio = Math.Min(AmiiboImageSize / bitmap.Size.Width,
@@ -438,7 +438,6 @@ namespace Ryujinx.Ava.UI.ViewModels
AmiiboImage = bitmap.CreateScaledBitmap(new PixelSize(resizeWidth, resizeHeight)); AmiiboImage = bitmap.CreateScaledBitmap(new PixelSize(resizeWidth, resizeHeight));
} }
}
else else
{ {
Logger.Error?.Print(LogClass.Application, $"Failed to get amiibo preview. Response status code: {response.StatusCode}"); Logger.Error?.Print(LogClass.Application, $"Failed to get amiibo preview. Response status code: {response.StatusCode}");
@@ -447,15 +446,14 @@ namespace Ryujinx.Ava.UI.ViewModels
private void ResetAmiiboPreview() private void ResetAmiiboPreview()
{ {
using (MemoryStream memoryStream = new(_amiiboLogoBytes)) using MemoryStream memoryStream = new(_amiiboLogoBytes);
{
Bitmap bitmap = new(memoryStream); Bitmap bitmap = new(memoryStream);
AmiiboImage = bitmap; AmiiboImage = bitmap;
} }
}
private async void ShowInfoDialog() private static async void ShowInfoDialog()
{ {
await ContentDialogHelper.CreateInfoDialog(LocaleManager.Instance[LocaleKeys.DialogAmiiboApiTitle], await ContentDialogHelper.CreateInfoDialog(LocaleManager.Instance[LocaleKeys.DialogAmiiboApiTitle],
LocaleManager.Instance[LocaleKeys.DialogAmiiboApiConnectErrorMessage], LocaleManager.Instance[LocaleKeys.DialogAmiiboApiConnectErrorMessage],

View File

@@ -1,363 +0,0 @@
using Avalonia.Media;
using DynamicData;
using LibHac.Common;
using LibHac.Fs;
using LibHac.Fs.Fsa;
using LibHac.FsSystem;
using LibHac.Ncm;
using LibHac.Tools.Fs;
using LibHac.Tools.FsSystem;
using LibHac.Tools.FsSystem.NcaUtils;
using Ryujinx.Ava.UI.Models;
using Ryujinx.HLE.FileSystem;
using SixLabors.ImageSharp;
using SixLabors.ImageSharp.Formats.Png;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing;
using System;
using System.Buffers.Binary;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Color = Avalonia.Media.Color;
namespace Ryujinx.Ava.UI.ViewModels
{
internal class AvatarProfileViewModel : BaseModel, IDisposable
{
private const int MaxImageTasks = 4;
private static readonly Dictionary<string, byte[]> _avatarStore = new();
private static bool _isPreloading;
private static Action _loadCompleteAction;
private ObservableCollection<ProfileImageModel> _images;
private Color _backgroundColor = Colors.White;
private int _selectedIndex;
private int _imagesLoaded;
private bool _isActive;
private byte[] _selectedImage;
private bool _isIndeterminate = true;
public bool IsActive
{
get => _isActive;
set => _isActive = value;
}
public AvatarProfileViewModel()
{
_images = new ObservableCollection<ProfileImageModel>();
}
public AvatarProfileViewModel(Action loadCompleteAction)
{
_images = new ObservableCollection<ProfileImageModel>();
if (_isPreloading)
{
_loadCompleteAction = loadCompleteAction;
}
else
{
ReloadImages();
}
}
public Color BackgroundColor
{
get => _backgroundColor;
set
{
_backgroundColor = value;
IsActive = false;
ReloadImages();
}
}
public ObservableCollection<ProfileImageModel> Images
{
get => _images;
set
{
_images = value;
OnPropertyChanged();
}
}
public bool IsIndeterminate
{
get => _isIndeterminate;
set
{
_isIndeterminate = value;
OnPropertyChanged();
}
}
public int ImageCount => _avatarStore.Count;
public int ImagesLoaded
{
get => _imagesLoaded;
set
{
_imagesLoaded = value;
OnPropertyChanged();
}
}
public int SelectedIndex
{
get => _selectedIndex;
set
{
_selectedIndex = value;
if (_selectedIndex == -1)
{
SelectedImage = null;
}
else
{
SelectedImage = _images[_selectedIndex].Data;
}
OnPropertyChanged();
}
}
public byte[] SelectedImage
{
get => _selectedImage;
private set => _selectedImage = value;
}
public void ReloadImages()
{
if (_isPreloading)
{
IsIndeterminate = false;
return;
}
Task.Run(() =>
{
IsActive = true;
Images.Clear();
int selectedIndex = _selectedIndex;
int index = 0;
ImagesLoaded = 0;
IsIndeterminate = false;
var keys = _avatarStore.Keys.ToList();
var newImages = new List<ProfileImageModel>();
var tasks = new List<Task>();
for (int i = 0; i < MaxImageTasks; i++)
{
var start = i;
tasks.Add(Task.Run(() => ImageTask(start)));
}
Task.WaitAll(tasks.ToArray());
Images.AddRange(newImages);
void ImageTask(int start)
{
for (int i = start; i < keys.Count; i += MaxImageTasks)
{
if (!IsActive)
{
return;
}
var key = keys[i];
var image = _avatarStore[keys[i]];
var data = ProcessImage(image);
newImages.Add(new ProfileImageModel(key, data));
if (index++ == selectedIndex)
{
SelectedImage = data;
}
Interlocked.Increment(ref _imagesLoaded);
OnPropertyChanged(nameof(ImagesLoaded));
}
}
});
}
private byte[] ProcessImage(byte[] data)
{
using (MemoryStream streamJpg = new())
{
Image avatarImage = Image.Load(data, new PngDecoder());
avatarImage.Mutate(x => x.BackgroundColor(new Rgba32(BackgroundColor.R,
BackgroundColor.G,
BackgroundColor.B,
BackgroundColor.A)));
avatarImage.SaveAsJpeg(streamJpg);
return streamJpg.ToArray();
}
}
public static void PreloadAvatars(ContentManager contentManager, VirtualFileSystem virtualFileSystem)
{
try
{
if (_avatarStore.Count > 0)
{
return;
}
_isPreloading = true;
string contentPath =
contentManager.GetInstalledContentPath(0x010000000000080A, StorageId.BuiltInSystem,
NcaContentType.Data);
string avatarPath = virtualFileSystem.SwitchPathToSystemPath(contentPath);
if (!string.IsNullOrWhiteSpace(avatarPath))
{
using (IStorage ncaFileStream = new LocalStorage(avatarPath, FileAccess.Read, FileMode.Open))
{
Nca nca = new(virtualFileSystem.KeySet, ncaFileStream);
IFileSystem romfs = nca.OpenFileSystem(NcaSectionType.Data, IntegrityCheckLevel.ErrorOnInvalid);
foreach (DirectoryEntryEx item in romfs.EnumerateEntries())
{
// TODO: Parse DatabaseInfo.bin and table.bin files for more accuracy.
if (item.Type == DirectoryEntryType.File && item.FullPath.Contains("chara") &&
item.FullPath.Contains("szs"))
{
using var file = new UniqueRef<IFile>();
romfs.OpenFile(ref file.Ref, ("/" + item.FullPath).ToU8Span(), OpenMode.Read)
.ThrowIfFailure();
using (MemoryStream stream = new())
using (MemoryStream streamPng = new())
{
file.Get.AsStream().CopyTo(stream);
stream.Position = 0;
Image avatarImage = Image.LoadPixelData<Rgba32>(DecompressYaz0(stream), 256, 256);
avatarImage.SaveAsPng(streamPng);
_avatarStore.Add(item.FullPath, streamPng.ToArray());
}
}
}
}
}
}
finally
{
_isPreloading = false;
_loadCompleteAction?.Invoke();
}
}
private static byte[] DecompressYaz0(Stream stream)
{
using (BinaryReader reader = new(stream))
{
reader.ReadInt32(); // Magic
uint decodedLength = BinaryPrimitives.ReverseEndianness(reader.ReadUInt32());
reader.ReadInt64(); // Padding
byte[] input = new byte[stream.Length - stream.Position];
stream.Read(input, 0, input.Length);
uint inputOffset = 0;
byte[] output = new byte[decodedLength];
uint outputOffset = 0;
ushort mask = 0;
byte header = 0;
while (outputOffset < decodedLength)
{
if ((mask >>= 1) == 0)
{
header = input[inputOffset++];
mask = 0x80;
}
if ((header & mask) != 0)
{
if (outputOffset == output.Length)
{
break;
}
output[outputOffset++] = input[inputOffset++];
}
else
{
byte byte1 = input[inputOffset++];
byte byte2 = input[inputOffset++];
uint dist = (uint)((byte1 & 0xF) << 8) | byte2;
uint position = outputOffset - (dist + 1);
uint length = (uint)byte1 >> 4;
if (length == 0)
{
length = (uint)input[inputOffset++] + 0x12;
}
else
{
length += 2;
}
uint gap = outputOffset - position;
uint nonOverlappingLength = length;
if (nonOverlappingLength > gap)
{
nonOverlappingLength = gap;
}
Buffer.BlockCopy(output, (int)position, output, (int)outputOffset, (int)nonOverlappingLength);
outputOffset += nonOverlappingLength;
position += nonOverlappingLength;
length -= nonOverlappingLength;
while (length-- > 0)
{
output[outputOffset++] = output[position++];
}
}
}
return output;
}
}
public void Dispose()
{
_loadCompleteAction = null;
IsActive = false;
}
}
}

View File

@@ -1,3 +1,4 @@
using Avalonia;
using Avalonia.Collections; using Avalonia.Collections;
using Avalonia.Controls; using Avalonia.Controls;
using Avalonia.Controls.ApplicationLifetimes; using Avalonia.Controls.ApplicationLifetimes;
@@ -44,15 +45,14 @@ namespace Ryujinx.Ava.UI.ViewModels
private PlayerIndex _playerId; private PlayerIndex _playerId;
private int _controller; private int _controller;
private int _controllerNumber = 0; private int _controllerNumber;
private string _controllerImage; private string _controllerImage;
private int _device; private int _device;
private object _configuration; private object _configuration;
private string _profileName; private string _profileName;
private bool _isLoaded; private bool _isLoaded;
private readonly UserControl _owner;
private static readonly InputConfigJsonSerializerContext SerializerContext = new(JsonHelper.GetDefaultSerializerOptions()); private static readonly InputConfigJsonSerializerContext _serializerContext = new(JsonHelper.GetDefaultSerializerOptions());
public IGamepadDriver AvaloniaKeyboardDriver { get; } public IGamepadDriver AvaloniaKeyboardDriver { get; }
public IGamepad SelectedGamepad { get; private set; } public IGamepad SelectedGamepad { get; private set; }
@@ -176,11 +176,11 @@ namespace Ryujinx.Ava.UI.ViewModels
{ {
get get
{ {
SvgImage image = new SvgImage(); SvgImage image = new();
if (!string.IsNullOrWhiteSpace(_controllerImage)) if (!string.IsNullOrWhiteSpace(_controllerImage))
{ {
SvgSource source = new SvgSource(); SvgSource source = new();
source.Load(EmbeddedResources.GetStream(_controllerImage)); source.Load(EmbeddedResources.GetStream(_controllerImage));
@@ -234,22 +234,18 @@ namespace Ryujinx.Ava.UI.ViewModels
public ControllerInputViewModel(UserControl owner) : this() public ControllerInputViewModel(UserControl owner) : this()
{ {
_owner = owner;
if (Program.PreviewerDetached) if (Program.PreviewerDetached)
{ {
_mainWindow = _mainWindow =
(MainWindow)((IClassicDesktopStyleApplicationLifetime)Avalonia.Application.Current (MainWindow)((IClassicDesktopStyleApplicationLifetime)Application.Current
.ApplicationLifetime).MainWindow; .ApplicationLifetime).MainWindow;
AvaloniaKeyboardDriver = new AvaloniaKeyboardDriver(owner); AvaloniaKeyboardDriver = new AvaloniaKeyboardDriver(owner);
_mainWindow.InputManager.GamepadDriver.OnGamepadConnected += HandleOnGamepadConnected; _mainWindow.InputManager.GamepadDriver.OnGamepadConnected += HandleOnGamepadConnected;
_mainWindow.InputManager.GamepadDriver.OnGamepadDisconnected += HandleOnGamepadDisconnected; _mainWindow.InputManager.GamepadDriver.OnGamepadDisconnected += HandleOnGamepadDisconnected;
if (_mainWindow.ViewModel.AppHost != null)
{ _mainWindow.ViewModel.AppHost?.NpadManager.BlockInputUpdates();
_mainWindow.ViewModel.AppHost.NpadManager.BlockInputUpdates();
}
_isLoaded = false; _isLoaded = false;
@@ -351,7 +347,8 @@ namespace Ryujinx.Ava.UI.ViewModels
{ {
return; return;
} }
else if (type == DeviceType.Keyboard)
if (type == DeviceType.Keyboard)
{ {
if (_mainWindow.InputManager.KeyboardDriver is AvaloniaKeyboardDriver) if (_mainWindow.InputManager.KeyboardDriver is AvaloniaKeyboardDriver)
{ {
@@ -448,7 +445,7 @@ namespace Ryujinx.Ava.UI.ViewModels
const string Hyphen = "-"; const string Hyphen = "-";
const int Offset = 1; const int Offset = 1;
return str.Substring(str.IndexOf(Hyphen) + Offset); return str[(str.IndexOf(Hyphen) + Offset)..];
} }
public void LoadDevices() public void LoadDevices()
@@ -562,7 +559,7 @@ namespace Ryujinx.Ava.UI.ViewModels
ButtonL = Key.E, ButtonL = Key.E,
ButtonZl = Key.Q, ButtonZl = Key.Q,
ButtonSl = Key.Unbound, ButtonSl = Key.Unbound,
ButtonSr = Key.Unbound ButtonSr = Key.Unbound,
}, },
LeftJoyconStick = LeftJoyconStick =
new JoyconConfigKeyboardStick<Key> new JoyconConfigKeyboardStick<Key>
@@ -571,7 +568,7 @@ namespace Ryujinx.Ava.UI.ViewModels
StickDown = Key.S, StickDown = Key.S,
StickLeft = Key.A, StickLeft = Key.A,
StickRight = Key.D, StickRight = Key.D,
StickButton = Key.F StickButton = Key.F,
}, },
RightJoycon = new RightJoyconCommonConfig<Key> RightJoycon = new RightJoyconCommonConfig<Key>
{ {
@@ -583,7 +580,7 @@ namespace Ryujinx.Ava.UI.ViewModels
ButtonR = Key.U, ButtonR = Key.U,
ButtonZr = Key.O, ButtonZr = Key.O,
ButtonSl = Key.Unbound, ButtonSl = Key.Unbound,
ButtonSr = Key.Unbound ButtonSr = Key.Unbound,
}, },
RightJoyconStick = new JoyconConfigKeyboardStick<Key> RightJoyconStick = new JoyconConfigKeyboardStick<Key>
{ {
@@ -591,8 +588,8 @@ namespace Ryujinx.Ava.UI.ViewModels
StickDown = Key.K, StickDown = Key.K,
StickLeft = Key.J, StickLeft = Key.J,
StickRight = Key.L, StickRight = Key.L,
StickButton = Key.H StickButton = Key.H,
} },
}; };
} }
else if (activeDevice.Type == DeviceType.Controller) else if (activeDevice.Type == DeviceType.Controller)
@@ -622,14 +619,14 @@ namespace Ryujinx.Ava.UI.ViewModels
ButtonL = ConfigGamepadInputId.LeftShoulder, ButtonL = ConfigGamepadInputId.LeftShoulder,
ButtonZl = ConfigGamepadInputId.LeftTrigger, ButtonZl = ConfigGamepadInputId.LeftTrigger,
ButtonSl = ConfigGamepadInputId.Unbound, ButtonSl = ConfigGamepadInputId.Unbound,
ButtonSr = ConfigGamepadInputId.Unbound ButtonSr = ConfigGamepadInputId.Unbound,
}, },
LeftJoyconStick = new JoyconConfigControllerStick<ConfigGamepadInputId, ConfigStickInputId> LeftJoyconStick = new JoyconConfigControllerStick<ConfigGamepadInputId, ConfigStickInputId>
{ {
Joystick = ConfigStickInputId.Left, Joystick = ConfigStickInputId.Left,
StickButton = ConfigGamepadInputId.LeftStick, StickButton = ConfigGamepadInputId.LeftStick,
InvertStickX = false, InvertStickX = false,
InvertStickY = false InvertStickY = false,
}, },
RightJoycon = new RightJoyconCommonConfig<ConfigGamepadInputId> RightJoycon = new RightJoyconCommonConfig<ConfigGamepadInputId>
{ {
@@ -641,28 +638,28 @@ namespace Ryujinx.Ava.UI.ViewModels
ButtonR = ConfigGamepadInputId.RightShoulder, ButtonR = ConfigGamepadInputId.RightShoulder,
ButtonZr = ConfigGamepadInputId.RightTrigger, ButtonZr = ConfigGamepadInputId.RightTrigger,
ButtonSl = ConfigGamepadInputId.Unbound, ButtonSl = ConfigGamepadInputId.Unbound,
ButtonSr = ConfigGamepadInputId.Unbound ButtonSr = ConfigGamepadInputId.Unbound,
}, },
RightJoyconStick = new JoyconConfigControllerStick<ConfigGamepadInputId, ConfigStickInputId> RightJoyconStick = new JoyconConfigControllerStick<ConfigGamepadInputId, ConfigStickInputId>
{ {
Joystick = ConfigStickInputId.Right, Joystick = ConfigStickInputId.Right,
StickButton = ConfigGamepadInputId.RightStick, StickButton = ConfigGamepadInputId.RightStick,
InvertStickX = false, InvertStickX = false,
InvertStickY = false InvertStickY = false,
}, },
Motion = new StandardMotionConfigController Motion = new StandardMotionConfigController
{ {
MotionBackend = MotionInputBackendType.GamepadDriver, MotionBackend = MotionInputBackendType.GamepadDriver,
EnableMotion = true, EnableMotion = true,
Sensitivity = 100, Sensitivity = 100,
GyroDeadzone = 1 GyroDeadzone = 1,
}, },
Rumble = new RumbleConfigController Rumble = new RumbleConfigController
{ {
StrongRumble = 1f, StrongRumble = 1f,
WeakRumble = 1f, WeakRumble = 1f,
EnableRumble = false EnableRumble = false,
} },
}; };
} }
else else
@@ -709,7 +706,7 @@ namespace Ryujinx.Ava.UI.ViewModels
try try
{ {
config = JsonHelper.DeserializeFromFile(path, SerializerContext.InputConfig); config = JsonHelper.DeserializeFromFile(path, _serializerContext.InputConfig);
} }
catch (JsonException) { } catch (JsonException) { }
catch (InvalidOperationException) catch (InvalidOperationException)
@@ -754,8 +751,7 @@ namespace Ryujinx.Ava.UI.ViewModels
return; return;
} }
else
{
bool validFileName = ProfileName.IndexOfAny(Path.GetInvalidFileNameChars()) == -1; bool validFileName = ProfileName.IndexOfAny(Path.GetInvalidFileNameChars()) == -1;
if (validFileName) if (validFileName)
@@ -775,7 +771,7 @@ namespace Ryujinx.Ava.UI.ViewModels
config.ControllerType = Controllers[_controller].Type; config.ControllerType = Controllers[_controller].Type;
string jsonString = JsonHelper.Serialize(config, SerializerContext.InputConfig); string jsonString = JsonHelper.Serialize(config, _serializerContext.InputConfig);
await File.WriteAllTextAsync(path, jsonString); await File.WriteAllTextAsync(path, jsonString);
@@ -786,7 +782,6 @@ namespace Ryujinx.Ava.UI.ViewModels
await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance[LocaleKeys.DialogProfileInvalidProfileNameErrorMessage]); await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance[LocaleKeys.DialogProfileInvalidProfileNameErrorMessage]);
} }
} }
}
public async void RemoveProfile() public async void RemoveProfile()
{ {
@@ -887,6 +882,8 @@ namespace Ryujinx.Ava.UI.ViewModels
public void Dispose() public void Dispose()
{ {
GC.SuppressFinalize(this);
_mainWindow.InputManager.GamepadDriver.OnGamepadConnected -= HandleOnGamepadConnected; _mainWindow.InputManager.GamepadDriver.OnGamepadConnected -= HandleOnGamepadConnected;
_mainWindow.InputManager.GamepadDriver.OnGamepadDisconnected -= HandleOnGamepadDisconnected; _mainWindow.InputManager.GamepadDriver.OnGamepadDisconnected -= HandleOnGamepadDisconnected;

View File

@@ -22,6 +22,7 @@ using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using Application = Avalonia.Application;
using Path = System.IO.Path; using Path = System.IO.Path;
namespace Ryujinx.Ava.UI.ViewModels namespace Ryujinx.Ava.UI.ViewModels
@@ -31,16 +32,15 @@ namespace Ryujinx.Ava.UI.ViewModels
private readonly List<DownloadableContentContainer> _downloadableContentContainerList; private readonly List<DownloadableContentContainer> _downloadableContentContainerList;
private readonly string _downloadableContentJsonPath; private readonly string _downloadableContentJsonPath;
private VirtualFileSystem _virtualFileSystem; private readonly VirtualFileSystem _virtualFileSystem;
private AvaloniaList<DownloadableContentModel> _downloadableContents = new(); private AvaloniaList<DownloadableContentModel> _downloadableContents = new();
private AvaloniaList<DownloadableContentModel> _views = new(); private AvaloniaList<DownloadableContentModel> _views = new();
private AvaloniaList<DownloadableContentModel> _selectedDownloadableContents = new(); private AvaloniaList<DownloadableContentModel> _selectedDownloadableContents = new();
private string _search; private string _search;
private ulong _titleId; private readonly ulong _titleId;
private string _titleName;
private static readonly DownloadableContentJsonSerializerContext SerializerContext = new(JsonHelper.GetDefaultSerializerOptions()); private static readonly DownloadableContentJsonSerializerContext _serializerContext = new(JsonHelper.GetDefaultSerializerOptions());
public AvaloniaList<DownloadableContentModel> DownloadableContents public AvaloniaList<DownloadableContentModel> DownloadableContents
{ {
@@ -90,18 +90,17 @@ namespace Ryujinx.Ava.UI.ViewModels
get => string.Format(LocaleManager.Instance[LocaleKeys.DlcWindowHeading], DownloadableContents.Count); get => string.Format(LocaleManager.Instance[LocaleKeys.DlcWindowHeading], DownloadableContents.Count);
} }
public DownloadableContentManagerViewModel(VirtualFileSystem virtualFileSystem, ulong titleId, string titleName) public DownloadableContentManagerViewModel(VirtualFileSystem virtualFileSystem, ulong titleId)
{ {
_virtualFileSystem = virtualFileSystem; _virtualFileSystem = virtualFileSystem;
_titleId = titleId; _titleId = titleId;
_titleName = titleName;
_downloadableContentJsonPath = Path.Combine(AppDataManager.GamesDirPath, titleId.ToString("x16"), "dlc.json"); _downloadableContentJsonPath = Path.Combine(AppDataManager.GamesDirPath, titleId.ToString("x16"), "dlc.json");
try try
{ {
_downloadableContentContainerList = JsonHelper.DeserializeFromFile(_downloadableContentJsonPath, SerializerContext.ListDownloadableContentContainer); _downloadableContentContainerList = JsonHelper.DeserializeFromFile(_downloadableContentJsonPath, _serializerContext.ListDownloadableContentContainer);
} }
catch catch
{ {
@@ -196,19 +195,19 @@ namespace Ryujinx.Ava.UI.ViewModels
public async void Add() public async void Add()
{ {
OpenFileDialog dialog = new OpenFileDialog() OpenFileDialog dialog = new()
{ {
Title = LocaleManager.Instance[LocaleKeys.SelectDlcDialogTitle], Title = LocaleManager.Instance[LocaleKeys.SelectDlcDialogTitle],
AllowMultiple = true AllowMultiple = true,
}; };
dialog.Filters.Add(new FileDialogFilter dialog.Filters.Add(new FileDialogFilter
{ {
Name = "NSP", Name = "NSP",
Extensions = { "nsp" } Extensions = { "nsp" },
}); });
if (Avalonia.Application.Current.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) if (Application.Current.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
{ {
string[] files = await dialog.ShowAsync(desktop.MainWindow); string[] files = await dialog.ShowAsync(desktop.MainWindow);
@@ -314,7 +313,7 @@ namespace Ryujinx.Ava.UI.ViewModels
container = new DownloadableContentContainer container = new DownloadableContentContainer
{ {
ContainerPath = downloadableContent.ContainerPath, ContainerPath = downloadableContent.ContainerPath,
DownloadableContentNcaList = new List<DownloadableContentNca>() DownloadableContentNcaList = new List<DownloadableContentNca>(),
}; };
} }
@@ -322,7 +321,7 @@ namespace Ryujinx.Ava.UI.ViewModels
{ {
Enabled = downloadableContent.Enabled, Enabled = downloadableContent.Enabled,
TitleId = Convert.ToUInt64(downloadableContent.TitleId, 16), TitleId = Convert.ToUInt64(downloadableContent.TitleId, 16),
FullPath = downloadableContent.FullPath FullPath = downloadableContent.FullPath,
}); });
} }
@@ -331,7 +330,7 @@ namespace Ryujinx.Ava.UI.ViewModels
_downloadableContentContainerList.Add(container); _downloadableContentContainerList.Add(container);
} }
JsonHelper.SerializeToFile(_downloadableContentJsonPath, _downloadableContentContainerList, SerializerContext.ListDownloadableContentContainer); JsonHelper.SerializeToFile(_downloadableContentJsonPath, _downloadableContentContainerList, _serializerContext.ListDownloadableContentContainer);
} }
} }

View File

@@ -1,3 +1,4 @@
using Avalonia;
using Avalonia.Controls; using Avalonia.Controls;
using Avalonia.Controls.ApplicationLifetimes; using Avalonia.Controls.ApplicationLifetimes;
using Avalonia.Input; using Avalonia.Input;
@@ -12,6 +13,7 @@ using Ryujinx.Ava.Input;
using Ryujinx.Ava.UI.Controls; using Ryujinx.Ava.UI.Controls;
using Ryujinx.Ava.UI.Helpers; using Ryujinx.Ava.UI.Helpers;
using Ryujinx.Ava.UI.Models; using Ryujinx.Ava.UI.Models;
using Ryujinx.Ava.UI.Models.Generic;
using Ryujinx.Ava.UI.Renderer; using Ryujinx.Ava.UI.Renderer;
using Ryujinx.Ava.UI.Windows; using Ryujinx.Ava.UI.Windows;
using Ryujinx.Common; using Ryujinx.Common;
@@ -23,6 +25,7 @@ using Ryujinx.HLE.FileSystem;
using Ryujinx.HLE.HOS; using Ryujinx.HLE.HOS;
using Ryujinx.HLE.HOS.Services.Account.Acc; using Ryujinx.HLE.HOS.Services.Account.Acc;
using Ryujinx.HLE.Ui; using Ryujinx.HLE.Ui;
using Ryujinx.Modules;
using Ryujinx.Ui.App.Common; using Ryujinx.Ui.App.Common;
using Ryujinx.Ui.Common; using Ryujinx.Ui.Common;
using Ryujinx.Ui.Common.Configuration; using Ryujinx.Ui.Common.Configuration;
@@ -34,7 +37,10 @@ using System.Collections.ObjectModel;
using System.IO; using System.IO;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Path = System.IO.Path; using Image = SixLabors.ImageSharp.Image;
using InputManager = Ryujinx.Input.HLE.InputManager;
using Key = Ryujinx.Input.Key;
using MissingKeyException = LibHac.Common.Keys.MissingKeyException;
using ShaderCacheLoadingState = Ryujinx.Graphics.Gpu.Shader.ShaderCacheState; using ShaderCacheLoadingState = Ryujinx.Graphics.Gpu.Shader.ShaderCacheState;
namespace Ryujinx.Ava.UI.ViewModels namespace Ryujinx.Ava.UI.ViewModels
@@ -89,7 +95,7 @@ namespace Ryujinx.Ava.UI.ViewModels
private Cursor _cursor; private Cursor _cursor;
private string _title; private string _title;
private string _currentEmulatedGamePath; private string _currentEmulatedGamePath;
private AutoResetEvent _rendererWaitEvent; private readonly AutoResetEvent _rendererWaitEvent;
private WindowState _windowState; private WindowState _windowState;
private double _windowWidth; private double _windowWidth;
private double _windowHeight; private double _windowHeight;
@@ -128,7 +134,7 @@ namespace Ryujinx.Ava.UI.ViewModels
ApplicationLibrary applicationLibrary, ApplicationLibrary applicationLibrary,
VirtualFileSystem virtualFileSystem, VirtualFileSystem virtualFileSystem,
AccountManager accountManager, AccountManager accountManager,
Ryujinx.Input.HLE.InputManager inputManager, InputManager inputManager,
UserChannelPersistence userChannelPersistence, UserChannelPersistence userChannelPersistence,
LibHacHorizonManager libHacHorizonManager, LibHacHorizonManager libHacHorizonManager,
IHostUiHandler uiHandler, IHostUiHandler uiHandler,
@@ -152,7 +158,7 @@ namespace Ryujinx.Ava.UI.ViewModels
TopLevel = topLevel; TopLevel = topLevel;
} }
#region Properties #region Properties
public string SearchText public string SearchText
{ {
@@ -177,7 +183,7 @@ namespace Ryujinx.Ava.UI.ViewModels
public bool CanUpdate public bool CanUpdate
{ {
get => _canUpdate && EnableNonGameRunningControls && Modules.Updater.CanUpdate(false); get => _canUpdate && EnableNonGameRunningControls && Updater.CanUpdate(false);
set set
{ {
_canUpdate = value; _canUpdate = value;
@@ -343,11 +349,11 @@ namespace Ryujinx.Ava.UI.ViewModels
} }
} }
public bool OpenUserSaveDirectoryEnabled => !Utilities.IsZeros(SelectedApplication.ControlHolder.ByteSpan) && SelectedApplication.ControlHolder.Value.UserAccountSaveDataSize > 0; public bool OpenUserSaveDirectoryEnabled => !SelectedApplication.ControlHolder.ByteSpan.IsZeros() && SelectedApplication.ControlHolder.Value.UserAccountSaveDataSize > 0;
public bool OpenDeviceSaveDirectoryEnabled => !Utilities.IsZeros(SelectedApplication.ControlHolder.ByteSpan) && SelectedApplication.ControlHolder.Value.DeviceSaveDataSize > 0; public bool OpenDeviceSaveDirectoryEnabled => !SelectedApplication.ControlHolder.ByteSpan.IsZeros() && SelectedApplication.ControlHolder.Value.DeviceSaveDataSize > 0;
public bool OpenBcatSaveDirectoryEnabled => !Utilities.IsZeros(SelectedApplication.ControlHolder.ByteSpan) && SelectedApplication.ControlHolder.Value.BcatDeliveryCacheStorageSize > 0; public bool OpenBcatSaveDirectoryEnabled => !SelectedApplication.ControlHolder.ByteSpan.IsZeros() && SelectedApplication.ControlHolder.Value.BcatDeliveryCacheStorageSize > 0;
public string LoadHeading public string LoadHeading
{ {
@@ -888,7 +894,7 @@ namespace Ryujinx.Ava.UI.ViewModels
public ApplicationLibrary ApplicationLibrary { get; private set; } public ApplicationLibrary ApplicationLibrary { get; private set; }
public VirtualFileSystem VirtualFileSystem { get; private set; } public VirtualFileSystem VirtualFileSystem { get; private set; }
public AccountManager AccountManager { get; private set; } public AccountManager AccountManager { get; private set; }
public Ryujinx.Input.HLE.InputManager InputManager { get; private set; } public InputManager InputManager { get; private set; }
public UserChannelPersistence UserChannelPersistence { get; private set; } public UserChannelPersistence UserChannelPersistence { get; private set; }
public Action<bool> ShowLoading { get; private set; } public Action<bool> ShowLoading { get; private set; }
public Action<bool> SwitchToGameControl { get; private set; } public Action<bool> SwitchToGameControl { get; private set; }
@@ -911,15 +917,16 @@ namespace Ryujinx.Ava.UI.ViewModels
public bool IsGridLarge => ConfigurationState.Instance.Ui.GridSize == 3; public bool IsGridLarge => ConfigurationState.Instance.Ui.GridSize == 3;
public bool IsGridHuge => ConfigurationState.Instance.Ui.GridSize == 4; public bool IsGridHuge => ConfigurationState.Instance.Ui.GridSize == 4;
#endregion #endregion
#region PrivateMethods #region PrivateMethods
private IComparer<ApplicationData> GetComparer() private IComparer<ApplicationData> GetComparer()
{ {
return SortMode switch return SortMode switch
{ {
ApplicationSort.LastPlayed => new Models.Generic.LastPlayedSortComparer(IsAscending), #pragma warning disable IDE0055 // Disable formatting
ApplicationSort.LastPlayed => new LastPlayedSortComparer(IsAscending),
ApplicationSort.FileSize => IsAscending ? SortExpressionComparer<ApplicationData>.Ascending(app => app.FileSizeBytes) ApplicationSort.FileSize => IsAscending ? SortExpressionComparer<ApplicationData>.Ascending(app => app.FileSizeBytes)
: SortExpressionComparer<ApplicationData>.Descending(app => app.FileSizeBytes), : SortExpressionComparer<ApplicationData>.Descending(app => app.FileSizeBytes),
ApplicationSort.TotalTimePlayed => IsAscending ? SortExpressionComparer<ApplicationData>.Ascending(app => app.TimePlayedNum) ApplicationSort.TotalTimePlayed => IsAscending ? SortExpressionComparer<ApplicationData>.Ascending(app => app.TimePlayedNum)
@@ -935,6 +942,7 @@ namespace Ryujinx.Ava.UI.ViewModels
ApplicationSort.Path => IsAscending ? SortExpressionComparer<ApplicationData>.Ascending(app => app.Path) ApplicationSort.Path => IsAscending ? SortExpressionComparer<ApplicationData>.Ascending(app => app.Path)
: SortExpressionComparer<ApplicationData>.Descending(app => app.Path), : SortExpressionComparer<ApplicationData>.Descending(app => app.Path),
_ => null, _ => null,
#pragma warning restore IDE0055
}; };
} }
@@ -1023,7 +1031,7 @@ namespace Ryujinx.Ava.UI.ViewModels
// Purge Applet Cache. // Purge Applet Cache.
DirectoryInfo miiEditorCacheFolder = new DirectoryInfo(Path.Combine(AppDataManager.GamesDirPath, "0100000000001009", "cache")); DirectoryInfo miiEditorCacheFolder = new(Path.Combine(AppDataManager.GamesDirPath, "0100000000001009", "cache"));
if (miiEditorCacheFolder.Exists) if (miiEditorCacheFolder.Exists)
{ {
@@ -1044,18 +1052,21 @@ namespace Ryujinx.Ava.UI.ViewModels
{ {
RefreshFirmwareStatus(); RefreshFirmwareStatus();
} }
}) { Name = "GUI.FirmwareInstallerThread" }; })
{
Name = "GUI.FirmwareInstallerThread",
};
thread.Start(); thread.Start();
} }
} }
catch (LibHac.Common.Keys.MissingKeyException ex) catch (MissingKeyException ex)
{ {
if (Avalonia.Application.Current.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) if (Application.Current.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
{ {
Logger.Error?.Print(LogClass.Application, ex.ToString()); Logger.Error?.Print(LogClass.Application, ex.ToString());
async void Action() => await UserErrorDialog.ShowUserErrorDialog(UserError.NoKeys, (desktop.MainWindow as MainWindow)); static async void Action() => await UserErrorDialog.ShowUserErrorDialog(UserError.NoKeys);
Dispatcher.UIThread.Post(Action); Dispatcher.UIThread.Post(Action);
} }
@@ -1120,7 +1131,7 @@ namespace Ryujinx.Ava.UI.ViewModels
private void PrepareLoadScreen() private void PrepareLoadScreen()
{ {
using MemoryStream stream = new(SelectedIcon); using MemoryStream stream = new(SelectedIcon);
using var gameIconBmp = SixLabors.ImageSharp.Image.Load<Bgra32>(stream); using var gameIconBmp = Image.Load<Bgra32>(stream);
var dominantColor = IconColorPicker.GetFilteredColor(gameIconBmp).ToPixel<Bgra32>(); var dominantColor = IconColorPicker.GetFilteredColor(gameIconBmp).ToPixel<Bgra32>();
@@ -1175,7 +1186,7 @@ namespace Ryujinx.Ava.UI.ViewModels
{ {
Dispatcher.UIThread.InvokeAsync(() => Dispatcher.UIThread.InvokeAsync(() =>
{ {
Avalonia.Application.Current.Styles.TryGetResource(args.VSyncEnabled Application.Current.Styles.TryGetResource(args.VSyncEnabled
? "VsyncEnabled" ? "VsyncEnabled"
: "VsyncDisabled", out object color); : "VsyncDisabled", out object color);
@@ -1204,11 +1215,11 @@ namespace Ryujinx.Ava.UI.ViewModels
_rendererWaitEvent.Set(); _rendererWaitEvent.Set();
} }
#endregion #endregion
#region PublicMethods #region PublicMethods
public void SetUIProgressHandlers(Switch emulationContext) public void SetUiProgressHandlers(Switch emulationContext)
{ {
if (emulationContext.Processes.ActiveApplication.DiskCacheLoadState != null) if (emulationContext.Processes.ActiveApplication.DiskCacheLoadState != null)
{ {
@@ -1222,17 +1233,17 @@ namespace Ryujinx.Ava.UI.ViewModels
public void LoadConfigurableHotKeys() public void LoadConfigurableHotKeys()
{ {
if (AvaloniaKeyboardMappingHelper.TryGetAvaKey((Ryujinx.Input.Key)ConfigurationState.Instance.Hid.Hotkeys.Value.ShowUi, out var showUiKey)) if (AvaloniaKeyboardMappingHelper.TryGetAvaKey((Key)ConfigurationState.Instance.Hid.Hotkeys.Value.ShowUi, out var showUiKey))
{ {
ShowUiKey = new KeyGesture(showUiKey); ShowUiKey = new KeyGesture(showUiKey);
} }
if (AvaloniaKeyboardMappingHelper.TryGetAvaKey((Ryujinx.Input.Key)ConfigurationState.Instance.Hid.Hotkeys.Value.Screenshot, out var screenshotKey)) if (AvaloniaKeyboardMappingHelper.TryGetAvaKey((Key)ConfigurationState.Instance.Hid.Hotkeys.Value.Screenshot, out var screenshotKey))
{ {
ScreenshotKey = new KeyGesture(screenshotKey); ScreenshotKey = new KeyGesture(screenshotKey);
} }
if (AvaloniaKeyboardMappingHelper.TryGetAvaKey((Ryujinx.Input.Key)ConfigurationState.Instance.Hid.Hotkeys.Value.Pause, out var pauseKey)) if (AvaloniaKeyboardMappingHelper.TryGetAvaKey((Key)ConfigurationState.Instance.Hid.Hotkeys.Value.Pause, out var pauseKey))
{ {
PauseKey = new KeyGesture(pauseKey); PauseKey = new KeyGesture(pauseKey);
} }
@@ -1260,7 +1271,7 @@ namespace Ryujinx.Ava.UI.ViewModels
public async void InstallFirmwareFromFile() public async void InstallFirmwareFromFile()
{ {
if (Avalonia.Application.Current.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) if (Application.Current.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
{ {
OpenFileDialog dialog = new() { AllowMultiple = false }; OpenFileDialog dialog = new() { AllowMultiple = false };
dialog.Filters.Add(new FileDialogFilter { Name = LocaleManager.Instance[LocaleKeys.FileDialogAllTypes], Extensions = { "xci", "zip" } }); dialog.Filters.Add(new FileDialogFilter { Name = LocaleManager.Instance[LocaleKeys.FileDialogAllTypes], Extensions = { "xci", "zip" } });
@@ -1278,7 +1289,7 @@ namespace Ryujinx.Ava.UI.ViewModels
public async void InstallFirmwareFromFolder() public async void InstallFirmwareFromFolder()
{ {
if (Avalonia.Application.Current.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) if (Application.Current.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
{ {
OpenFolderDialog dialog = new(); OpenFolderDialog dialog = new();
@@ -1327,7 +1338,7 @@ namespace Ryujinx.Ava.UI.ViewModels
} }
} }
public void ChangeLanguage(object languageCode) public static void ChangeLanguage(object languageCode)
{ {
LocaleManager.Instance.LoadLanguage((string)languageCode); LocaleManager.Instance.LoadLanguage((string)languageCode);
@@ -1342,6 +1353,7 @@ namespace Ryujinx.Ava.UI.ViewModels
{ {
_ = fileType switch _ = fileType switch
{ {
#pragma warning disable IDE0055 // Disable formatting
"NSP" => ConfigurationState.Instance.Ui.ShownFileTypes.NSP.Value = !ConfigurationState.Instance.Ui.ShownFileTypes.NSP, "NSP" => ConfigurationState.Instance.Ui.ShownFileTypes.NSP.Value = !ConfigurationState.Instance.Ui.ShownFileTypes.NSP,
"PFS0" => ConfigurationState.Instance.Ui.ShownFileTypes.PFS0.Value = !ConfigurationState.Instance.Ui.ShownFileTypes.PFS0, "PFS0" => ConfigurationState.Instance.Ui.ShownFileTypes.PFS0.Value = !ConfigurationState.Instance.Ui.ShownFileTypes.PFS0,
"XCI" => ConfigurationState.Instance.Ui.ShownFileTypes.XCI.Value = !ConfigurationState.Instance.Ui.ShownFileTypes.XCI, "XCI" => ConfigurationState.Instance.Ui.ShownFileTypes.XCI.Value = !ConfigurationState.Instance.Ui.ShownFileTypes.XCI,
@@ -1349,6 +1361,7 @@ namespace Ryujinx.Ava.UI.ViewModels
"NRO" => ConfigurationState.Instance.Ui.ShownFileTypes.NRO.Value = !ConfigurationState.Instance.Ui.ShownFileTypes.NRO, "NRO" => ConfigurationState.Instance.Ui.ShownFileTypes.NRO.Value = !ConfigurationState.Instance.Ui.ShownFileTypes.NRO,
"NSO" => ConfigurationState.Instance.Ui.ShownFileTypes.NSO.Value = !ConfigurationState.Instance.Ui.ShownFileTypes.NSO, "NSO" => ConfigurationState.Instance.Ui.ShownFileTypes.NSO.Value = !ConfigurationState.Instance.Ui.ShownFileTypes.NSO,
_ => throw new ArgumentOutOfRangeException(fileType), _ => throw new ArgumentOutOfRangeException(fileType),
#pragma warning restore IDE0055
}; };
ConfigurationState.Instance.ToFileFormat().SaveConfig(Program.ConfigurationPath); ConfigurationState.Instance.ToFileFormat().SaveConfig(Program.ConfigurationPath);
@@ -1383,11 +1396,11 @@ namespace Ryujinx.Ava.UI.ViewModels
public async void OpenFile() public async void OpenFile()
{ {
if (Avalonia.Application.Current.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) if (Application.Current.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
{ {
OpenFileDialog dialog = new() OpenFileDialog dialog = new()
{ {
Title = LocaleManager.Instance[LocaleKeys.OpenFileDialogTitle] Title = LocaleManager.Instance[LocaleKeys.OpenFileDialogTitle],
}; };
dialog.Filters.Add(new FileDialogFilter dialog.Filters.Add(new FileDialogFilter
@@ -1400,16 +1413,18 @@ namespace Ryujinx.Ava.UI.ViewModels
"xci", "xci",
"nca", "nca",
"nro", "nro",
"nso" "nso",
} },
}); });
#pragma warning disable IDE0055 // Disable formatting
dialog.Filters.Add(new FileDialogFilter { Name = "NSP", Extensions = { "nsp" } }); dialog.Filters.Add(new FileDialogFilter { Name = "NSP", Extensions = { "nsp" } });
dialog.Filters.Add(new FileDialogFilter { Name = "PFS0", Extensions = { "pfs0" } }); dialog.Filters.Add(new FileDialogFilter { Name = "PFS0", Extensions = { "pfs0" } });
dialog.Filters.Add(new FileDialogFilter { Name = "XCI", Extensions = { "xci" } }); dialog.Filters.Add(new FileDialogFilter { Name = "XCI", Extensions = { "xci" } });
dialog.Filters.Add(new FileDialogFilter { Name = "NCA", Extensions = { "nca" } }); dialog.Filters.Add(new FileDialogFilter { Name = "NCA", Extensions = { "nca" } });
dialog.Filters.Add(new FileDialogFilter { Name = "NRO", Extensions = { "nro" } }); dialog.Filters.Add(new FileDialogFilter { Name = "NRO", Extensions = { "nro" } });
dialog.Filters.Add(new FileDialogFilter { Name = "NSO", Extensions = { "nso" } }); dialog.Filters.Add(new FileDialogFilter { Name = "NSO", Extensions = { "nso" } });
#pragma warning restore IDE0055
string[] files = await dialog.ShowAsync(desktop.MainWindow); string[] files = await dialog.ShowAsync(desktop.MainWindow);
@@ -1422,11 +1437,11 @@ namespace Ryujinx.Ava.UI.ViewModels
public async void OpenFolder() public async void OpenFolder()
{ {
if (Avalonia.Application.Current.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) if (Application.Current.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
{ {
OpenFolderDialog dialog = new() OpenFolderDialog dialog = new()
{ {
Title = LocaleManager.Instance[LocaleKeys.OpenFolderDialogTitle] Title = LocaleManager.Instance[LocaleKeys.OpenFolderDialogTitle],
}; };
string folder = await dialog.ShowAsync(desktop.MainWindow); string folder = await dialog.ShowAsync(desktop.MainWindow);
@@ -1458,10 +1473,7 @@ namespace Ryujinx.Ava.UI.ViewModels
Logger.RestartTime(); Logger.RestartTime();
if (SelectedIcon == null) SelectedIcon ??= ApplicationLibrary.GetApplicationIcon(path);
{
SelectedIcon = ApplicationLibrary.GetApplicationIcon(path);
}
PrepareLoadScreen(); PrepareLoadScreen();
@@ -1521,7 +1533,7 @@ namespace Ryujinx.Ava.UI.ViewModels
}); });
} }
public void UpdateGameMetadata(string titleId) public static void UpdateGameMetadata(string titleId)
{ {
ApplicationLibrary.LoadAndSaveMetaData(titleId, appMetadata => ApplicationLibrary.LoadAndSaveMetaData(titleId, appMetadata =>
{ {
@@ -1675,6 +1687,6 @@ namespace Ryujinx.Ava.UI.ViewModels
} }
} }
#endregion #endregion
} }
} }

View File

@@ -18,7 +18,6 @@ using Ryujinx.HLE.FileSystem;
using Ryujinx.HLE.HOS.Services.Time.TimeZone; using Ryujinx.HLE.HOS.Services.Time.TimeZone;
using Ryujinx.Ui.Common.Configuration; using Ryujinx.Ui.Common.Configuration;
using Ryujinx.Ui.Common.Configuration.System; using Ryujinx.Ui.Common.Configuration.System;
using Silk.NET.Vulkan;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.ObjectModel; using System.Collections.ObjectModel;
@@ -248,7 +247,7 @@ namespace Ryujinx.Ava.UI.ViewModels
public AvaloniaList<string> NetworkInterfaceList public AvaloniaList<string> NetworkInterfaceList
{ {
get => new AvaloniaList<string>(_networkInterfaces.Keys); get => new(_networkInterfaces.Keys);
} }
public KeyboardHotkeys KeyboardHotkeys public KeyboardHotkeys KeyboardHotkeys
@@ -561,7 +560,7 @@ namespace Ryujinx.Ava.UI.ViewModels
_directoryChanged = false; _directoryChanged = false;
} }
public void RevertIfNotSaved() private static void RevertIfNotSaved()
{ {
Program.ReloadConfig(); Program.ReloadConfig();
} }

View File

@@ -1,3 +1,4 @@
using Avalonia;
using Avalonia.Collections; using Avalonia.Collections;
using Avalonia.Controls; using Avalonia.Controls;
using Avalonia.Controls.ApplicationLifetimes; using Avalonia.Controls.ApplicationLifetimes;
@@ -16,7 +17,6 @@ using Ryujinx.Common.Configuration;
using Ryujinx.Common.Logging; using Ryujinx.Common.Logging;
using Ryujinx.Common.Utilities; using Ryujinx.Common.Utilities;
using Ryujinx.HLE.FileSystem; using Ryujinx.HLE.FileSystem;
using Ryujinx.HLE.HOS;
using Ryujinx.Ui.App.Common; using Ryujinx.Ui.App.Common;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
@@ -29,17 +29,16 @@ namespace Ryujinx.Ava.UI.ViewModels
{ {
public class TitleUpdateViewModel : BaseModel public class TitleUpdateViewModel : BaseModel
{ {
public TitleUpdateMetadata _titleUpdateWindowData; public TitleUpdateMetadata TitleUpdateWindowData;
public readonly string _titleUpdateJsonPath; public readonly string TitleUpdateJsonPath;
private VirtualFileSystem _virtualFileSystem { get; } private VirtualFileSystem VirtualFileSystem { get; }
private ulong _titleId { get; } private ulong TitleId { get; }
private string _titleName { get; }
private AvaloniaList<TitleUpdateModel> _titleUpdates = new(); private AvaloniaList<TitleUpdateModel> _titleUpdates = new();
private AvaloniaList<object> _views = new(); private AvaloniaList<object> _views = new();
private object _selectedUpdate; private object _selectedUpdate;
private static readonly TitleUpdateMetadataJsonSerializerContext SerializerContext = new(JsonHelper.GetDefaultSerializerOptions()); private static readonly TitleUpdateMetadataJsonSerializerContext _serializerContext = new(JsonHelper.GetDefaultSerializerOptions());
public AvaloniaList<TitleUpdateModel> TitleUpdates public AvaloniaList<TitleUpdateModel> TitleUpdates
{ {
@@ -71,27 +70,26 @@ namespace Ryujinx.Ava.UI.ViewModels
} }
} }
public TitleUpdateViewModel(VirtualFileSystem virtualFileSystem, ulong titleId, string titleName) public TitleUpdateViewModel(VirtualFileSystem virtualFileSystem, ulong titleId)
{ {
_virtualFileSystem = virtualFileSystem; VirtualFileSystem = virtualFileSystem;
_titleId = titleId; TitleId = titleId;
_titleName = titleName;
_titleUpdateJsonPath = Path.Combine(AppDataManager.GamesDirPath, titleId.ToString("x16"), "updates.json"); TitleUpdateJsonPath = Path.Combine(AppDataManager.GamesDirPath, titleId.ToString("x16"), "updates.json");
try try
{ {
_titleUpdateWindowData = JsonHelper.DeserializeFromFile(_titleUpdateJsonPath, SerializerContext.TitleUpdateMetadata); TitleUpdateWindowData = JsonHelper.DeserializeFromFile(TitleUpdateJsonPath, _serializerContext.TitleUpdateMetadata);
} }
catch catch
{ {
Logger.Warning?.Print(LogClass.Application, $"Failed to deserialize title update data for {_titleId} at {_titleUpdateJsonPath}"); Logger.Warning?.Print(LogClass.Application, $"Failed to deserialize title update data for {TitleId} at {TitleUpdateJsonPath}");
_titleUpdateWindowData = new TitleUpdateMetadata TitleUpdateWindowData = new TitleUpdateMetadata
{ {
Selected = "", Selected = "",
Paths = new List<string>() Paths = new List<string>(),
}; };
Save(); Save();
@@ -102,12 +100,12 @@ namespace Ryujinx.Ava.UI.ViewModels
private void LoadUpdates() private void LoadUpdates()
{ {
foreach (string path in _titleUpdateWindowData.Paths) foreach (string path in TitleUpdateWindowData.Paths)
{ {
AddUpdate(path); AddUpdate(path);
} }
TitleUpdateModel selected = TitleUpdates.FirstOrDefault(x => x.Path == _titleUpdateWindowData.Selected, null); TitleUpdateModel selected = TitleUpdates.FirstOrDefault(x => x.Path == TitleUpdateWindowData.Selected, null);
SelectedUpdate = selected; SelectedUpdate = selected;
@@ -126,7 +124,8 @@ namespace Ryujinx.Ava.UI.ViewModels
{ {
return -1; return -1;
} }
else if (string.IsNullOrEmpty(second.Control.DisplayVersionString.ToString()))
if (string.IsNullOrEmpty(second.Control.DisplayVersionString.ToString()))
{ {
return 1; return 1;
} }
@@ -163,7 +162,7 @@ namespace Ryujinx.Ava.UI.ViewModels
try try
{ {
(Nca patchNca, Nca controlNca) = ApplicationLibrary.GetGameUpdateDataFromPartition(_virtualFileSystem, new PartitionFileSystem(file.AsStorage()), _titleId.ToString("x16"), 0); (Nca patchNca, Nca controlNca) = ApplicationLibrary.GetGameUpdateDataFromPartition(VirtualFileSystem, new PartitionFileSystem(file.AsStorage()), TitleId.ToString("x16"), 0);
if (controlNca != null && patchNca != null) if (controlNca != null && patchNca != null)
{ {
@@ -206,16 +205,16 @@ namespace Ryujinx.Ava.UI.ViewModels
OpenFileDialog dialog = new() OpenFileDialog dialog = new()
{ {
Title = LocaleManager.Instance[LocaleKeys.SelectUpdateDialogTitle], Title = LocaleManager.Instance[LocaleKeys.SelectUpdateDialogTitle],
AllowMultiple = true AllowMultiple = true,
}; };
dialog.Filters.Add(new FileDialogFilter dialog.Filters.Add(new FileDialogFilter
{ {
Name = "NSP", Name = "NSP",
Extensions = { "nsp" } Extensions = { "nsp" },
}); });
if (Avalonia.Application.Current.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) if (Application.Current.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
{ {
string[] files = await dialog.ShowAsync(desktop.MainWindow); string[] files = await dialog.ShowAsync(desktop.MainWindow);
@@ -233,20 +232,20 @@ namespace Ryujinx.Ava.UI.ViewModels
public void Save() public void Save()
{ {
_titleUpdateWindowData.Paths.Clear(); TitleUpdateWindowData.Paths.Clear();
_titleUpdateWindowData.Selected = ""; TitleUpdateWindowData.Selected = "";
foreach (TitleUpdateModel update in TitleUpdates) foreach (TitleUpdateModel update in TitleUpdates)
{ {
_titleUpdateWindowData.Paths.Add(update.Path); TitleUpdateWindowData.Paths.Add(update.Path);
if (update == SelectedUpdate) if (update == SelectedUpdate)
{ {
_titleUpdateWindowData.Selected = update.Path; TitleUpdateWindowData.Selected = update.Path;
} }
} }
JsonHelper.SerializeToFile(_titleUpdateJsonPath, _titleUpdateWindowData, SerializerContext.TitleUpdateMetadata); JsonHelper.SerializeToFile(TitleUpdateJsonPath, TitleUpdateWindowData, _serializerContext.TitleUpdateMetadata);
} }
} }
} }

View File

@@ -28,7 +28,6 @@ namespace Ryujinx.Ava.UI.ViewModels
private Color _backgroundColor = Colors.White; private Color _backgroundColor = Colors.White;
private int _selectedIndex; private int _selectedIndex;
private byte[] _selectedImage;
public UserFirmwareAvatarSelectorViewModel() public UserFirmwareAvatarSelectorViewModel()
{ {
@@ -78,11 +77,7 @@ namespace Ryujinx.Ava.UI.ViewModels
} }
} }
public byte[] SelectedImage public byte[] SelectedImage { get; private set; }
{
get => _selectedImage;
private set => _selectedImage = value;
}
private void LoadImagesFromStore() private void LoadImagesFromStore()
{ {
@@ -110,12 +105,12 @@ namespace Ryujinx.Ava.UI.ViewModels
} }
string contentPath = contentManager.GetInstalledContentPath(0x010000000000080A, StorageId.BuiltInSystem, NcaContentType.Data); string contentPath = contentManager.GetInstalledContentPath(0x010000000000080A, StorageId.BuiltInSystem, NcaContentType.Data);
string avatarPath = virtualFileSystem.SwitchPathToSystemPath(contentPath); string avatarPath = VirtualFileSystem.SwitchPathToSystemPath(contentPath);
if (!string.IsNullOrWhiteSpace(avatarPath)) if (!string.IsNullOrWhiteSpace(avatarPath))
{ {
using (IStorage ncaFileStream = new LocalStorage(avatarPath, FileAccess.Read, FileMode.Open)) using IStorage ncaFileStream = new LocalStorage(avatarPath, FileAccess.Read, FileMode.Open);
{
Nca nca = new(virtualFileSystem.KeySet, ncaFileStream); Nca nca = new(virtualFileSystem.KeySet, ncaFileStream);
IFileSystem romfs = nca.OpenFileSystem(NcaSectionType.Data, IntegrityCheckLevel.ErrorOnInvalid); IFileSystem romfs = nca.OpenFileSystem(NcaSectionType.Data, IntegrityCheckLevel.ErrorOnInvalid);
@@ -128,9 +123,9 @@ namespace Ryujinx.Ava.UI.ViewModels
romfs.OpenFile(ref file.Ref, ("/" + item.FullPath).ToU8Span(), OpenMode.Read).ThrowIfFailure(); romfs.OpenFile(ref file.Ref, ("/" + item.FullPath).ToU8Span(), OpenMode.Read).ThrowIfFailure();
using (MemoryStream stream = new()) using MemoryStream stream = new();
using (MemoryStream streamPng = new()) using MemoryStream streamPng = new();
{
file.Get.AsStream().CopyTo(stream); file.Get.AsStream().CopyTo(stream);
stream.Position = 0; stream.Position = 0;
@@ -144,13 +139,11 @@ namespace Ryujinx.Ava.UI.ViewModels
} }
} }
} }
}
}
private static byte[] DecompressYaz0(Stream stream) private static byte[] DecompressYaz0(Stream stream)
{ {
using (BinaryReader reader = new(stream)) using BinaryReader reader = new(stream);
{
reader.ReadInt32(); // Magic reader.ReadInt32(); // Magic
uint decodedLength = BinaryPrimitives.ReverseEndianness(reader.ReadUInt32()); uint decodedLength = BinaryPrimitives.ReverseEndianness(reader.ReadUInt32());
@@ -226,5 +219,4 @@ namespace Ryujinx.Ava.UI.ViewModels
return output; return output;
} }
} }
}
} }

View File

@@ -1,7 +1,7 @@
using Microsoft.IdentityModel.Tokens; using Microsoft.IdentityModel.Tokens;
using Ryujinx.Ava.UI.Models;
using System; using System;
using System.Collections.ObjectModel; using System.Collections.ObjectModel;
using UserProfile = Ryujinx.Ava.UI.Models.UserProfile;
namespace Ryujinx.Ava.UI.ViewModels namespace Ryujinx.Ava.UI.ViewModels
{ {
@@ -20,6 +20,9 @@ namespace Ryujinx.Ava.UI.ViewModels
public bool IsEmpty { get; set; } public bool IsEmpty { get; set; }
public void Dispose() { } public void Dispose()
{
GC.SuppressFinalize(this);
}
} }
} }

View File

@@ -15,7 +15,7 @@ namespace Ryujinx.Ava.UI.ViewModels
private string _search; private string _search;
private ObservableCollection<SaveModel> _saves = new(); private ObservableCollection<SaveModel> _saves = new();
private ObservableCollection<SaveModel> _views = new(); private ObservableCollection<SaveModel> _views = new();
private AccountManager _accountManager; private readonly AccountManager _accountManager;
public string SaveManagerHeading => LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.SaveManagerHeading, _accountManager.LastOpenedUser.Name, _accountManager.LastOpenedUser.UserId); public string SaveManagerHeading => LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.SaveManagerHeading, _accountManager.LastOpenedUser.Name, _accountManager.LastOpenedUser.UserId);
@@ -102,19 +102,16 @@ namespace Ryujinx.Ava.UI.ViewModels
private IComparer<SaveModel> GetComparer() private IComparer<SaveModel> GetComparer()
{ {
switch (SortIndex) return SortIndex switch
{ {
case 0: 0 => OrderIndex == 0
return OrderIndex == 0
? SortExpressionComparer<SaveModel>.Ascending(save => save.Title) ? SortExpressionComparer<SaveModel>.Ascending(save => save.Title)
: SortExpressionComparer<SaveModel>.Descending(save => save.Title); : SortExpressionComparer<SaveModel>.Descending(save => save.Title),
case 1: 1 => OrderIndex == 0
return OrderIndex == 0
? SortExpressionComparer<SaveModel>.Ascending(save => save.Size) ? SortExpressionComparer<SaveModel>.Ascending(save => save.Size)
: SortExpressionComparer<SaveModel>.Descending(save => save.Size); : SortExpressionComparer<SaveModel>.Descending(save => save.Size),
default: _ => null,
return null; };
}
} }
} }
} }

View File

@@ -29,7 +29,7 @@ namespace Ryujinx.Ava.UI.Views.Input
foreach (ILogical visual in SettingButtons.GetLogicalDescendants()) foreach (ILogical visual in SettingButtons.GetLogicalDescendants())
{ {
if (visual is ToggleButton button && !(visual is CheckBox)) if (visual is ToggleButton button && visual is not CheckBox)
{ {
button.Checked += Button_Checked; button.Checked += Button_Checked;
button.Unchecked += Button_Unchecked; button.Unchecked += Button_Unchecked;

View File

@@ -10,7 +10,7 @@ namespace Ryujinx.Ava.UI.Views.Input
{ {
public partial class MotionInputView : UserControl public partial class MotionInputView : UserControl
{ {
private MotionInputViewModel _viewModel; private readonly MotionInputViewModel _viewModel;
public MotionInputView() public MotionInputView()
{ {
@@ -30,7 +30,7 @@ namespace Ryujinx.Ava.UI.Views.Input
MirrorInput = config.MirrorInput, MirrorInput = config.MirrorInput,
Sensitivity = config.Sensitivity, Sensitivity = config.Sensitivity,
GyroDeadzone = config.GyroDeadzone, GyroDeadzone = config.GyroDeadzone,
EnableCemuHookMotion = config.EnableCemuHookMotion EnableCemuHookMotion = config.EnableCemuHookMotion,
}; };
InitializeComponent(); InitializeComponent();
@@ -47,7 +47,7 @@ namespace Ryujinx.Ava.UI.Views.Input
PrimaryButtonText = LocaleManager.Instance[LocaleKeys.ControllerSettingsSave], PrimaryButtonText = LocaleManager.Instance[LocaleKeys.ControllerSettingsSave],
SecondaryButtonText = "", SecondaryButtonText = "",
CloseButtonText = LocaleManager.Instance[LocaleKeys.ControllerSettingsClose], CloseButtonText = LocaleManager.Instance[LocaleKeys.ControllerSettingsClose],
Content = content Content = content,
}; };
contentDialog.PrimaryButtonClick += (sender, args) => contentDialog.PrimaryButtonClick += (sender, args) =>
{ {

View File

@@ -10,7 +10,7 @@ namespace Ryujinx.Ava.UI.Views.Input
{ {
public partial class RumbleInputView : UserControl public partial class RumbleInputView : UserControl
{ {
private RumbleInputViewModel _viewModel; private readonly RumbleInputViewModel _viewModel;
public RumbleInputView() public RumbleInputView()
{ {
@@ -24,7 +24,7 @@ namespace Ryujinx.Ava.UI.Views.Input
_viewModel = new RumbleInputViewModel _viewModel = new RumbleInputViewModel
{ {
StrongRumble = config.StrongRumble, StrongRumble = config.StrongRumble,
WeakRumble = config.WeakRumble WeakRumble = config.WeakRumble,
}; };
InitializeComponent(); InitializeComponent();

View File

@@ -38,21 +38,21 @@ namespace Ryujinx.Ava.UI.Views.Main
{ {
List<CheckBox> checkBoxes = new(); List<CheckBox> checkBoxes = new();
foreach (var item in Enum.GetValues(typeof (FileTypes))) foreach (var item in Enum.GetValues(typeof(FileTypes)))
{ {
string fileName = Enum.GetName(typeof (FileTypes), item); string fileName = Enum.GetName(typeof(FileTypes), item);
checkBoxes.Add(new CheckBox() checkBoxes.Add(new CheckBox
{ {
Content = $".{fileName}", Content = $".{fileName}",
IsChecked = ((FileTypes)item).GetConfigValue(ConfigurationState.Instance.Ui.ShownFileTypes), IsChecked = ((FileTypes)item).GetConfigValue(ConfigurationState.Instance.Ui.ShownFileTypes),
Command = MiniCommand.Create(() => ViewModel.ToggleFileType(fileName)) Command = MiniCommand.Create(() => ViewModel.ToggleFileType(fileName)),
}); });
} }
return checkBoxes.ToArray(); return checkBoxes.ToArray();
} }
private MenuItem[] GenerateLanguageMenuItems() private static MenuItem[] GenerateLanguageMenuItems()
{ {
List<MenuItem> menuItems = new(); List<MenuItem> menuItems = new();
@@ -79,8 +79,8 @@ namespace Ryujinx.Ava.UI.Views.Main
Header = languageName, Header = languageName,
Command = MiniCommand.Create(() => Command = MiniCommand.Create(() =>
{ {
ViewModel.ChangeLanguage(languageCode); MainWindowViewModel.ChangeLanguage(languageCode);
}) }),
}; };
menuItems.Add(menuItem); menuItems.Add(menuItem);

View File

@@ -12,12 +12,12 @@ namespace Ryujinx.Ava.UI.Views.Settings
public partial class SettingsHotkeysView : UserControl public partial class SettingsHotkeysView : UserControl
{ {
private ButtonKeyAssigner _currentAssigner; private ButtonKeyAssigner _currentAssigner;
private IGamepadDriver AvaloniaKeyboardDriver; private readonly IGamepadDriver _avaloniaKeyboardDriver;
public SettingsHotkeysView() public SettingsHotkeysView()
{ {
InitializeComponent(); InitializeComponent();
AvaloniaKeyboardDriver = new AvaloniaKeyboardDriver(this); _avaloniaKeyboardDriver = new AvaloniaKeyboardDriver(this);
} }
private void MouseClick(object sender, PointerPressedEventArgs e) private void MouseClick(object sender, PointerPressedEventArgs e)
@@ -46,7 +46,7 @@ namespace Ryujinx.Ava.UI.Views.Settings
PointerPressed += MouseClick; PointerPressed += MouseClick;
var keyboard = (IKeyboard)AvaloniaKeyboardDriver.GetGamepad(AvaloniaKeyboardDriver.GamepadsIds[0]); var keyboard = (IKeyboard)_avaloniaKeyboardDriver.GetGamepad(_avaloniaKeyboardDriver.GamepadsIds[0]);
IButtonAssigner assigner = new KeyboardKeyAssigner(keyboard); IButtonAssigner assigner = new KeyboardKeyAssigner(keyboard);
_currentAssigner.GetInputAndAssign(assigner); _currentAssigner.GetInputAndAssign(assigner);

View File

@@ -1,5 +1,5 @@
<UserControl <UserControl
x:Class="Ryujinx.Ava.UI.Views.Settings.SettingsUIView" x:Class="Ryujinx.Ava.UI.Views.Settings.SettingsUiView"
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:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:d="http://schemas.microsoft.com/expression/blend/2008"

View File

@@ -1,4 +1,5 @@
using Avalonia.Controls; using Avalonia;
using Avalonia.Controls;
using Avalonia.Controls.ApplicationLifetimes; using Avalonia.Controls.ApplicationLifetimes;
using Avalonia.Interactivity; using Avalonia.Interactivity;
using Ryujinx.Ava.Common.Locale; using Ryujinx.Ava.Common.Locale;
@@ -9,11 +10,11 @@ using System.Linq;
namespace Ryujinx.Ava.UI.Views.Settings namespace Ryujinx.Ava.UI.Views.Settings
{ {
public partial class SettingsUIView : UserControl public partial class SettingsUiView : UserControl
{ {
public SettingsViewModel ViewModel; public SettingsViewModel ViewModel;
public SettingsUIView() public SettingsUiView()
{ {
InitializeComponent(); InitializeComponent();
} }
@@ -29,7 +30,7 @@ namespace Ryujinx.Ava.UI.Views.Settings
} }
else else
{ {
if (Avalonia.Application.Current.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) if (Application.Current.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
{ {
path = await new OpenFolderDialog().ShowAsync(desktop.MainWindow); path = await new OpenFolderDialog().ShowAsync(desktop.MainWindow);
@@ -60,15 +61,15 @@ namespace Ryujinx.Ava.UI.Views.Settings
public async void BrowseTheme(object sender, RoutedEventArgs e) public async void BrowseTheme(object sender, RoutedEventArgs e)
{ {
var dialog = new OpenFileDialog() var dialog = new OpenFileDialog
{ {
Title = LocaleManager.Instance[LocaleKeys.SettingsSelectThemeFileDialogTitle], Title = LocaleManager.Instance[LocaleKeys.SettingsSelectThemeFileDialogTitle],
AllowMultiple = false AllowMultiple = false,
}; };
dialog.Filters.Add(new FileDialogFilter() { Extensions = { "xaml" }, Name = LocaleManager.Instance[LocaleKeys.SettingsXamlThemeFile] }); dialog.Filters.Add(new FileDialogFilter { Extensions = { "xaml" }, Name = LocaleManager.Instance[LocaleKeys.SettingsXamlThemeFile] });
if (Avalonia.Application.Current.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) if (Application.Current.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
{ {
var file = await dialog.ShowAsync(desktop.MainWindow); var file = await dialog.ShowAsync(desktop.MainWindow);

View File

@@ -20,7 +20,7 @@ namespace Ryujinx.Ava.UI.Views.User
private bool _isNewUser; private bool _isNewUser;
public TempProfile TempProfile { get; set; } public TempProfile TempProfile { get; set; }
public uint MaxProfileNameLength => 0x20; public static uint MaxProfileNameLength => 0x20;
public bool IsDeletable => _profile.UserId != AccountManager.DefaultUserId; public bool IsDeletable => _profile.UserId != AccountManager.DefaultUserId;
public UserEditorView() public UserEditorView()
@@ -39,17 +39,17 @@ namespace Ryujinx.Ava.UI.Views.User
switch (arg.NavigationMode) switch (arg.NavigationMode)
{ {
case NavigationMode.New: case NavigationMode.New:
var args = ((NavigationDialogHost parent, UserProfile profile, bool isNewUser))arg.Parameter; var (parent, profile, isNewUser) = ((NavigationDialogHost parent, UserProfile profile, bool isNewUser))arg.Parameter;
_isNewUser = args.isNewUser; _isNewUser = isNewUser;
_profile = args.profile; _profile = profile;
TempProfile = new TempProfile(_profile); TempProfile = new TempProfile(_profile);
_parent = args.parent; _parent = parent;
break; break;
} }
((ContentDialog)_parent.Parent).Title = $"{LocaleManager.Instance[LocaleKeys.UserProfileWindowTitle]} - " + ((ContentDialog)_parent.Parent).Title = $"{LocaleManager.Instance[LocaleKeys.UserProfileWindowTitle]} - " +
$"{ (_isNewUser ? LocaleManager.Instance[LocaleKeys.UserEditorTitleCreate] : LocaleManager.Instance[LocaleKeys.UserEditorTitle])}"; $"{(_isNewUser ? LocaleManager.Instance[LocaleKeys.UserEditorTitleCreate] : LocaleManager.Instance[LocaleKeys.UserEditorTitle])}";
DataContext = TempProfile; DataContext = TempProfile;

View File

@@ -11,6 +11,7 @@ using SixLabors.ImageSharp.Formats.Png;
using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing; using SixLabors.ImageSharp.Processing;
using System.IO; using System.IO;
using Image = SixLabors.ImageSharp.Image;
namespace Ryujinx.Ava.UI.Views.User namespace Ryujinx.Ava.UI.Views.User
{ {
@@ -70,7 +71,7 @@ namespace Ryujinx.Ava.UI.Views.User
if (ViewModel.SelectedImage != null) if (ViewModel.SelectedImage != null)
{ {
MemoryStream streamJpg = new(); MemoryStream streamJpg = new();
SixLabors.ImageSharp.Image avatarImage = SixLabors.ImageSharp.Image.Load(ViewModel.SelectedImage, new PngDecoder()); Image avatarImage = Image.Load(ViewModel.SelectedImage, new PngDecoder());
avatarImage.Mutate(x => x.BackgroundColor(new Rgba32( avatarImage.Mutate(x => x.BackgroundColor(new Rgba32(
ViewModel.BackgroundColor.R, ViewModel.BackgroundColor.R,

View File

@@ -67,7 +67,7 @@ namespace Ryujinx.Ava.UI.Views.User
dialog.Filters.Add(new FileDialogFilter dialog.Filters.Add(new FileDialogFilter
{ {
Name = LocaleManager.Instance[LocaleKeys.AllSupportedFormats], Name = LocaleManager.Instance[LocaleKeys.AllSupportedFormats],
Extensions = { "jpg", "jpeg", "png", "bmp" } Extensions = { "jpg", "jpeg", "png", "bmp" },
}); });
dialog.Filters.Add(new FileDialogFilter { Name = "JPEG", Extensions = { "jpg", "jpeg" } }); dialog.Filters.Add(new FileDialogFilter { Name = "JPEG", Extensions = { "jpg", "jpeg" } });
dialog.Filters.Add(new FileDialogFilter { Name = "PNG", Extensions = { "png" } }); dialog.Filters.Add(new FileDialogFilter { Name = "PNG", Extensions = { "png" } });
@@ -108,17 +108,15 @@ namespace Ryujinx.Ava.UI.Views.User
private static byte[] ProcessProfileImage(byte[] buffer) private static byte[] ProcessProfileImage(byte[] buffer)
{ {
using (Image image = Image.Load(buffer)) using Image image = Image.Load(buffer);
{
image.Mutate(x => x.Resize(256, 256)); image.Mutate(x => x.Resize(256, 256));
using (MemoryStream streamJpg = new()) using MemoryStream streamJpg = new();
{
image.SaveAsJpeg(streamJpg); image.SaveAsJpeg(streamJpg);
return streamJpg.ToArray(); return streamJpg.ToArray();
} }
} }
}
}
} }

View File

@@ -18,6 +18,7 @@ using Ryujinx.HLE.HOS.Services.Account.Acc;
using System; using System;
using System.Collections.ObjectModel; using System.Collections.ObjectModel;
using System.Threading.Tasks; using System.Threading.Tasks;
using Button = Avalonia.Controls.Button;
using UserId = LibHac.Fs.UserId; using UserId = LibHac.Fs.UserId;
namespace Ryujinx.Ava.UI.Views.User namespace Ryujinx.Ava.UI.Views.User
@@ -47,12 +48,12 @@ namespace Ryujinx.Ava.UI.Views.User
switch (arg.NavigationMode) switch (arg.NavigationMode)
{ {
case NavigationMode.New: case NavigationMode.New:
var args = ((NavigationDialogHost parent, AccountManager accountManager, HorizonClient client, VirtualFileSystem virtualFileSystem))arg.Parameter; var (parent, accountManager, client, virtualFileSystem) = ((NavigationDialogHost parent, AccountManager accountManager, HorizonClient client, VirtualFileSystem virtualFileSystem))arg.Parameter;
_accountManager = args.accountManager; _accountManager = accountManager;
_horizonClient = args.client; _horizonClient = client;
_virtualFileSystem = args.virtualFileSystem; _virtualFileSystem = virtualFileSystem;
_parent = args.parent; _parent = parent;
break; break;
} }
@@ -94,7 +95,7 @@ namespace Ryujinx.Ava.UI.Views.User
var save = saveDataInfo[i]; var save = saveDataInfo[i];
if (save.ProgramId.Value != 0) if (save.ProgramId.Value != 0)
{ {
var saveModel = new SaveModel(save, _virtualFileSystem); var saveModel = new SaveModel(save);
saves.Add(saveModel); saves.Add(saveModel);
} }
} }
@@ -114,7 +115,7 @@ namespace Ryujinx.Ava.UI.Views.User
private void OpenLocation(object sender, RoutedEventArgs e) private void OpenLocation(object sender, RoutedEventArgs e)
{ {
if (sender is Avalonia.Controls.Button button) if (sender is Button button)
{ {
if (button.DataContext is SaveModel saveModel) if (button.DataContext is SaveModel saveModel)
{ {
@@ -125,7 +126,7 @@ namespace Ryujinx.Ava.UI.Views.User
private async void Delete(object sender, RoutedEventArgs e) private async void Delete(object sender, RoutedEventArgs e)
{ {
if (sender is Avalonia.Controls.Button button) if (sender is Button button)
{ {
if (button.DataContext is SaveModel saveModel) if (button.DataContext is SaveModel saveModel)
{ {

View File

@@ -5,8 +5,9 @@ using FluentAvalonia.UI.Controls;
using FluentAvalonia.UI.Navigation; using FluentAvalonia.UI.Navigation;
using Ryujinx.Ava.Common.Locale; using Ryujinx.Ava.Common.Locale;
using Ryujinx.Ava.UI.Controls; using Ryujinx.Ava.UI.Controls;
using Ryujinx.Ava.UI.Models;
using Ryujinx.Ava.UI.ViewModels; using Ryujinx.Ava.UI.ViewModels;
using UserProfile = Ryujinx.Ava.UI.Models.UserProfile; using Button = Avalonia.Controls.Button;
namespace Ryujinx.Ava.UI.Views.User namespace Ryujinx.Ava.UI.Views.User
{ {
@@ -101,7 +102,7 @@ namespace Ryujinx.Ava.UI.Views.User
private void EditUser(object sender, RoutedEventArgs e) private void EditUser(object sender, RoutedEventArgs e)
{ {
if (sender is Avalonia.Controls.Button button) if (sender is Button button)
{ {
if (button.DataContext is UserProfile userProfile) if (button.DataContext is UserProfile userProfile)
{ {

View File

@@ -1,6 +1,7 @@
using Avalonia.Controls; using Avalonia.Controls;
using Avalonia.Input; using Avalonia.Input;
using Avalonia.Interactivity; using Avalonia.Interactivity;
using Avalonia.Layout;
using Avalonia.Styling; using Avalonia.Styling;
using FluentAvalonia.UI.Controls; using FluentAvalonia.UI.Controls;
using Ryujinx.Ava.Common.Locale; using Ryujinx.Ava.Common.Locale;
@@ -28,14 +29,14 @@ namespace Ryujinx.Ava.UI.Windows
PrimaryButtonText = "", PrimaryButtonText = "",
SecondaryButtonText = "", SecondaryButtonText = "",
CloseButtonText = LocaleManager.Instance[LocaleKeys.UserProfilesClose], CloseButtonText = LocaleManager.Instance[LocaleKeys.UserProfilesClose],
Content = new AboutWindow() Content = new AboutWindow(),
}; };
Style closeButton = new(x => x.Name("CloseButton")); Style closeButton = new(x => x.Name("CloseButton"));
closeButton.Setters.Add(new Setter(WidthProperty, 80d)); closeButton.Setters.Add(new Setter(WidthProperty, 80d));
Style closeButtonParent = new(x => x.Name("CommandSpace")); Style closeButtonParent = new(x => x.Name("CommandSpace"));
closeButtonParent.Setters.Add(new Setter(HorizontalAlignmentProperty, Avalonia.Layout.HorizontalAlignment.Right)); closeButtonParent.Setters.Add(new Setter(HorizontalAlignmentProperty, HorizontalAlignment.Right));
contentDialog.Styles.Add(closeButton); contentDialog.Styles.Add(closeButton);
contentDialog.Styles.Add(closeButtonParent); contentDialog.Styles.Add(closeButtonParent);

View File

@@ -9,9 +9,10 @@ namespace Ryujinx.Ava.UI.Windows
{ {
public AmiiboWindow(bool showAll, string lastScannedAmiiboId, string titleId) public AmiiboWindow(bool showAll, string lastScannedAmiiboId, string titleId)
{ {
ViewModel = new AmiiboWindowViewModel(this, lastScannedAmiiboId, titleId); ViewModel = new AmiiboWindowViewModel(this, lastScannedAmiiboId, titleId)
{
ViewModel.ShowAllAmiibo = showAll; ShowAllAmiibo = showAll,
};
DataContext = ViewModel; DataContext = ViewModel;

View File

@@ -1,11 +1,12 @@
using Avalonia; using Avalonia.Collections;
using Avalonia.Collections;
using Ryujinx.Ava.Common.Locale; using Ryujinx.Ava.Common.Locale;
using Ryujinx.Ava.UI.Models; using Ryujinx.Ava.UI.Models;
using Ryujinx.HLE.FileSystem; using Ryujinx.HLE.FileSystem;
using Ryujinx.HLE.HOS; using Ryujinx.HLE.HOS;
using Ryujinx.Ui.App.Common; using Ryujinx.Ui.App.Common;
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Globalization;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
@@ -41,11 +42,11 @@ namespace Ryujinx.Ava.UI.Windows
string modsBasePath = ModLoader.GetModsBasePath(); string modsBasePath = ModLoader.GetModsBasePath();
string titleModsPath = ModLoader.GetTitleDir(modsBasePath, titleId); string titleModsPath = ModLoader.GetTitleDir(modsBasePath, titleId);
ulong titleIdValue = ulong.Parse(titleId, System.Globalization.NumberStyles.HexNumber); ulong titleIdValue = ulong.Parse(titleId, NumberStyles.HexNumber);
_enabledCheatsPath = Path.Combine(titleModsPath, "cheats", "enabled.txt"); _enabledCheatsPath = Path.Combine(titleModsPath, "cheats", "enabled.txt");
string[] enabled = { }; string[] enabled = Array.Empty<string>();
if (File.Exists(_enabledCheatsPath)) if (File.Exists(_enabledCheatsPath))
{ {
@@ -60,7 +61,6 @@ namespace Ryujinx.Ava.UI.Windows
string currentCheatFile = string.Empty; string currentCheatFile = string.Empty;
string buildId = string.Empty; string buildId = string.Empty;
string parentPath = string.Empty;
CheatsList currentGroup = null; CheatsList currentGroup = null;
@@ -69,7 +69,7 @@ namespace Ryujinx.Ava.UI.Windows
if (cheat.Path.FullName != currentCheatFile) if (cheat.Path.FullName != currentCheatFile)
{ {
currentCheatFile = cheat.Path.FullName; currentCheatFile = cheat.Path.FullName;
parentPath = currentCheatFile.Replace(titleModsPath, ""); string parentPath = currentCheatFile.Replace(titleModsPath, "");
buildId = Path.GetFileNameWithoutExtension(currentCheatFile).ToUpper(); buildId = Path.GetFileNameWithoutExtension(currentCheatFile).ToUpper();
currentGroup = new CheatsList(buildId, parentPath); currentGroup = new CheatsList(buildId, parentPath);
@@ -100,7 +100,7 @@ namespace Ryujinx.Ava.UI.Windows
return; return;
} }
List<string> enabledCheats = new List<string>(); List<string> enabledCheats = new();
foreach (var cheats in LoadedCheats) foreach (var cheats in LoadedCheats)
{ {

View File

@@ -1,7 +1,8 @@
using Avalonia;
using Avalonia.Controls; using Avalonia.Controls;
using Avalonia.Markup.Xaml;
using Avalonia.Media; using Avalonia.Media;
#if DEBUG
using Avalonia;
#endif
namespace Ryujinx.Ava.UI.Windows namespace Ryujinx.Ava.UI.Windows
{ {

View File

@@ -89,8 +89,8 @@
<Grid <Grid
Grid.Column="0"> Grid.Column="0">
<Grid.ColumnDefinitions> <Grid.ColumnDefinitions>
<ColumnDefinition Width="*"></ColumnDefinition> <ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto"></ColumnDefinition> <ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
<TextBlock <TextBlock
Grid.Column="0" Grid.Column="0"

View File

@@ -24,9 +24,9 @@ namespace Ryujinx.Ava.UI.Windows
InitializeComponent(); InitializeComponent();
} }
public DownloadableContentManagerWindow(VirtualFileSystem virtualFileSystem, ulong titleId, string titleName) public DownloadableContentManagerWindow(VirtualFileSystem virtualFileSystem, ulong titleId)
{ {
DataContext = ViewModel = new DownloadableContentManagerViewModel(virtualFileSystem, titleId, titleName); DataContext = ViewModel = new DownloadableContentManagerViewModel(virtualFileSystem, titleId);
InitializeComponent(); InitializeComponent();
} }
@@ -38,8 +38,8 @@ namespace Ryujinx.Ava.UI.Windows
PrimaryButtonText = "", PrimaryButtonText = "",
SecondaryButtonText = "", SecondaryButtonText = "",
CloseButtonText = "", CloseButtonText = "",
Content = new DownloadableContentManagerWindow(virtualFileSystem, titleId, titleName), Content = new DownloadableContentManagerWindow(virtualFileSystem, titleId),
Title = string.Format(LocaleManager.Instance[LocaleKeys.DlcWindowTitle], titleName, titleId.ToString("X16")) Title = string.Format(LocaleManager.Instance[LocaleKeys.DlcWindowTitle], titleName, titleId.ToString("X16")),
}; };
Style bottomBorder = new(x => x.OfType<Grid>().Name("DialogSpace").Child().OfType<Border>()); Style bottomBorder = new(x => x.OfType<Grid>().Name("DialogSpace").Child().OfType<Border>());

View File

@@ -68,8 +68,10 @@ namespace Ryujinx.Ava.UI.Windows
int w8 = w << 8; int w8 = w << 8;
int h8 = image.Height << 8; int h8 = image.Height << 8;
#pragma warning disable IDE0059 // Unnecessary assignment
int xStep = w8 / ColorsPerLine; int xStep = w8 / ColorsPerLine;
int yStep = h8 / ColorsPerLine; int yStep = h8 / ColorsPerLine;
#pragma warning restore IDE0059
int i = 0; int i = 0;
int maxHitCount = 0; int maxHitCount = 0;

View File

@@ -323,7 +323,7 @@ namespace Ryujinx.Ava.UI.Windows
ShowKeyErrorOnLoad = false; ShowKeyErrorOnLoad = false;
Dispatcher.UIThread.Post(async () => await Dispatcher.UIThread.Post(async () => await
UserErrorDialog.ShowUserErrorDialog(UserError.NoKeys, this)); UserErrorDialog.ShowUserErrorDialog(UserError.NoKeys));
} }
if (OperatingSystem.IsLinux() && LinuxHelper.VmMaxMapCount < LinuxHelper.RecommendedVmMaxMapCount) if (OperatingSystem.IsLinux() && LinuxHelper.VmMaxMapCount < LinuxHelper.RecommendedVmMaxMapCount)
@@ -373,7 +373,7 @@ namespace Ryujinx.Ava.UI.Windows
private void SetWindowSizePosition() private void SetWindowSizePosition()
{ {
PixelPoint SavedPoint = new PixelPoint(ConfigurationState.Instance.Ui.WindowStartup.WindowPositionX, PixelPoint savedPoint = new(ConfigurationState.Instance.Ui.WindowStartup.WindowPositionX,
ConfigurationState.Instance.Ui.WindowStartup.WindowPositionY); ConfigurationState.Instance.Ui.WindowStartup.WindowPositionY);
ViewModel.WindowHeight = ConfigurationState.Instance.Ui.WindowStartup.WindowSizeHeight * Program.WindowScaleFactor; ViewModel.WindowHeight = ConfigurationState.Instance.Ui.WindowStartup.WindowSizeHeight * Program.WindowScaleFactor;
@@ -381,12 +381,14 @@ namespace Ryujinx.Ava.UI.Windows
ViewModel.WindowState = ConfigurationState.Instance.Ui.WindowStartup.WindowMaximized.Value is true ? WindowState.Maximized : WindowState.Normal; ViewModel.WindowState = ConfigurationState.Instance.Ui.WindowStartup.WindowMaximized.Value is true ? WindowState.Maximized : WindowState.Normal;
if (CheckScreenBounds(SavedPoint)) if (CheckScreenBounds(savedPoint))
{ {
Position = SavedPoint; Position = savedPoint;
}
else
{
WindowStartupLocation = WindowStartupLocation.CenterScreen;
} }
else WindowStartupLocation = WindowStartupLocation.CenterScreen;
} }
private bool CheckScreenBounds(PixelPoint configPoint) private bool CheckScreenBounds(PixelPoint configPoint)
@@ -399,7 +401,7 @@ namespace Ryujinx.Ava.UI.Windows
} }
} }
Logger.Warning?.Print(LogClass.Application, $"Failed to find valid start-up coordinates. Defaulting to primary monitor center."); Logger.Warning?.Print(LogClass.Application, "Failed to find valid start-up coordinates. Defaulting to primary monitor center.");
return false; return false;
} }
@@ -425,10 +427,7 @@ namespace Ryujinx.Ava.UI.Windows
private void SetMainContent(Control content = null) private void SetMainContent(Control content = null)
{ {
if (content == null) content ??= GameLibrary;
{
content = GameLibrary;
}
if (MainContent.Content != content) if (MainContent.Content != content)
{ {
@@ -438,21 +437,25 @@ namespace Ryujinx.Ava.UI.Windows
public static void UpdateGraphicsConfig() public static void UpdateGraphicsConfig()
{ {
#pragma warning disable IDE0055 // Disable formatting
GraphicsConfig.ResScale = ConfigurationState.Instance.Graphics.ResScale == -1 ? ConfigurationState.Instance.Graphics.ResScaleCustom : ConfigurationState.Instance.Graphics.ResScale; GraphicsConfig.ResScale = ConfigurationState.Instance.Graphics.ResScale == -1 ? ConfigurationState.Instance.Graphics.ResScaleCustom : ConfigurationState.Instance.Graphics.ResScale;
GraphicsConfig.MaxAnisotropy = ConfigurationState.Instance.Graphics.MaxAnisotropy; GraphicsConfig.MaxAnisotropy = ConfigurationState.Instance.Graphics.MaxAnisotropy;
GraphicsConfig.ShadersDumpPath = ConfigurationState.Instance.Graphics.ShadersDumpPath; GraphicsConfig.ShadersDumpPath = ConfigurationState.Instance.Graphics.ShadersDumpPath;
GraphicsConfig.EnableShaderCache = ConfigurationState.Instance.Graphics.EnableShaderCache; GraphicsConfig.EnableShaderCache = ConfigurationState.Instance.Graphics.EnableShaderCache;
GraphicsConfig.EnableTextureRecompression = ConfigurationState.Instance.Graphics.EnableTextureRecompression; GraphicsConfig.EnableTextureRecompression = ConfigurationState.Instance.Graphics.EnableTextureRecompression;
GraphicsConfig.EnableMacroHLE = ConfigurationState.Instance.Graphics.EnableMacroHLE; GraphicsConfig.EnableMacroHLE = ConfigurationState.Instance.Graphics.EnableMacroHLE;
#pragma warning restore IDE0055
} }
public void LoadHotKeys() public void LoadHotKeys()
{ {
#pragma warning disable IDE0055 // Disable formatting
HotKeyManager.SetHotKey(FullscreenHotKey, new KeyGesture(Key.Enter, KeyModifiers.Alt)); HotKeyManager.SetHotKey(FullscreenHotKey, new KeyGesture(Key.Enter, KeyModifiers.Alt));
HotKeyManager.SetHotKey(FullscreenHotKey2, new KeyGesture(Key.F11)); HotKeyManager.SetHotKey(FullscreenHotKey2, new KeyGesture(Key.F11));
HotKeyManager.SetHotKey(FullscreenHotKeyMacOS, new KeyGesture(Key.F, KeyModifiers.Control | KeyModifiers.Meta)); HotKeyManager.SetHotKey(FullscreenHotKeyMacOS, new KeyGesture(Key.F, KeyModifiers.Control | KeyModifiers.Meta));
HotKeyManager.SetHotKey(DockToggleHotKey, new KeyGesture(Key.F9)); HotKeyManager.SetHotKey(DockToggleHotKey, new KeyGesture(Key.F9));
HotKeyManager.SetHotKey(ExitHotKey, new KeyGesture(Key.Escape)); HotKeyManager.SetHotKey(ExitHotKey, new KeyGesture(Key.Escape));
#pragma warning restore IDE0055
} }
private void VolumeStatus_CheckedChanged(object sender, SplitButtonClickEventArgs e) private void VolumeStatus_CheckedChanged(object sender, SplitButtonClickEventArgs e)

View File

@@ -34,7 +34,7 @@
IsVisible="False" IsVisible="False"
KeyboardNavigation.IsTabStop="False"/> KeyboardNavigation.IsTabStop="False"/>
<Grid Name="Pages" IsVisible="False" Grid.Row="2"> <Grid Name="Pages" IsVisible="False" Grid.Row="2">
<settings:SettingsUIView Name="UiPage" /> <settings:SettingsUiView Name="UiPage" />
<settings:SettingsInputView Name="InputPage" /> <settings:SettingsInputView Name="InputPage" />
<settings:SettingsHotkeysView Name="HotkeysPage" /> <settings:SettingsHotkeysView Name="HotkeysPage" />
<settings:SettingsSystemView Name="SystemPage" /> <settings:SettingsSystemView Name="SystemPage" />

View File

@@ -2,6 +2,7 @@
using Avalonia.Controls.Primitives; using Avalonia.Controls.Primitives;
using Avalonia.Media.Imaging; using Avalonia.Media.Imaging;
using Avalonia.Platform; using Avalonia.Platform;
using Ryujinx.Ui.Common.Configuration;
using System; using System;
using System.IO; using System.IO;
using System.Reflection; using System.Reflection;
@@ -17,7 +18,7 @@ namespace Ryujinx.Ava.UI.Windows
WindowStartupLocation = WindowStartupLocation.CenterOwner; WindowStartupLocation = WindowStartupLocation.CenterOwner;
TransparencyLevelHint = WindowTransparencyLevel.None; TransparencyLevelHint = WindowTransparencyLevel.None;
using Stream stream = Assembly.GetAssembly(typeof(Ryujinx.Ui.Common.Configuration.ConfigurationState)).GetManifestResourceStream("Ryujinx.Ui.Common.Resources.Logo_Ryujinx.png"); using Stream stream = Assembly.GetAssembly(typeof(ConfigurationState)).GetManifestResourceStream("Ryujinx.Ui.Common.Resources.Logo_Ryujinx.png");
Icon = new WindowIcon(stream); Icon = new WindowIcon(stream);
stream.Position = 0; stream.Position = 0;

View File

@@ -24,9 +24,9 @@ namespace Ryujinx.Ava.UI.Windows
InitializeComponent(); InitializeComponent();
} }
public TitleUpdateWindow(VirtualFileSystem virtualFileSystem, ulong titleId, string titleName) public TitleUpdateWindow(VirtualFileSystem virtualFileSystem, ulong titleId)
{ {
DataContext = ViewModel = new TitleUpdateViewModel(virtualFileSystem, titleId, titleName); DataContext = ViewModel = new TitleUpdateViewModel(virtualFileSystem, titleId);
InitializeComponent(); InitializeComponent();
} }
@@ -38,8 +38,8 @@ namespace Ryujinx.Ava.UI.Windows
PrimaryButtonText = "", PrimaryButtonText = "",
SecondaryButtonText = "", SecondaryButtonText = "",
CloseButtonText = "", CloseButtonText = "",
Content = new TitleUpdateWindow(virtualFileSystem, titleId, titleName), Content = new TitleUpdateWindow(virtualFileSystem, titleId),
Title = LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.GameUpdateWindowHeading, titleName, titleId.ToString("X16")) Title = LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.GameUpdateWindowHeading, titleName, titleId.ToString("X16")),
}; };
Style bottomBorder = new(x => x.OfType<Grid>().Name("DialogSpace").Child().OfType<Border>()); Style bottomBorder = new(x => x.OfType<Grid>().Name("DialogSpace").Child().OfType<Border>());

View File

@@ -79,7 +79,6 @@ namespace Ryujinx.Graphics.GAL
void SetRasterizerDiscard(bool discard); void SetRasterizerDiscard(bool discard);
void SetRenderTargetScale(float scale);
void SetRenderTargetColorMasks(ReadOnlySpan<uint> componentMask); void SetRenderTargetColorMasks(ReadOnlySpan<uint> componentMask);
void SetRenderTargets(ITexture[] colors, ITexture depthStencil); void SetRenderTargets(ITexture[] colors, ITexture depthStencil);
@@ -99,7 +98,7 @@ namespace Ryujinx.Graphics.GAL
void SetVertexAttribs(ReadOnlySpan<VertexAttribDescriptor> vertexAttribs); void SetVertexAttribs(ReadOnlySpan<VertexAttribDescriptor> vertexAttribs);
void SetVertexBuffers(ReadOnlySpan<VertexBufferDescriptor> vertexBuffers); void SetVertexBuffers(ReadOnlySpan<VertexBufferDescriptor> vertexBuffers);
void SetViewports(ReadOnlySpan<Viewport> viewports, bool disableTransform); void SetViewports(ReadOnlySpan<Viewport> viewports);
void TextureBarrier(); void TextureBarrier();
void TextureBarrierTiled(); void TextureBarrierTiled();
@@ -107,7 +106,5 @@ namespace Ryujinx.Graphics.GAL
bool TryHostConditionalRendering(ICounterEvent value, ulong compare, bool isEqual); bool TryHostConditionalRendering(ICounterEvent value, ulong compare, bool isEqual);
bool TryHostConditionalRendering(ICounterEvent value, ICounterEvent compare, bool isEqual); bool TryHostConditionalRendering(ICounterEvent value, ICounterEvent compare, bool isEqual);
void EndHostConditionalRendering(); void EndHostConditionalRendering();
void UpdateRenderScale(ReadOnlySpan<float> scales, int totalCount, int fragmentCount);
} }
} }

View File

@@ -17,7 +17,6 @@ namespace Ryujinx.Graphics.GAL
void BackgroundContextAction(Action action, bool alwaysBackground = false); void BackgroundContextAction(Action action, bool alwaysBackground = false);
BufferHandle CreateBuffer(int size, BufferHandle storageHint); BufferHandle CreateBuffer(int size, BufferHandle storageHint);
BufferHandle CreateBuffer(int size) BufferHandle CreateBuffer(int size)
{ {
return CreateBuffer(size, BufferHandle.Null); return CreateBuffer(size, BufferHandle.Null);
@@ -28,7 +27,7 @@ namespace Ryujinx.Graphics.GAL
IProgram CreateProgram(ShaderSource[] shaders, ShaderInfo info); IProgram CreateProgram(ShaderSource[] shaders, ShaderInfo info);
ISampler CreateSampler(SamplerCreateInfo info); ISampler CreateSampler(SamplerCreateInfo info);
ITexture CreateTexture(TextureCreateInfo info, float scale); ITexture CreateTexture(TextureCreateInfo info);
bool PrepareHostMapping(nint address, ulong size); bool PrepareHostMapping(nint address, ulong size);
void CreateSync(ulong id, bool strict); void CreateSync(ulong id, bool strict);
@@ -49,7 +48,7 @@ namespace Ryujinx.Graphics.GAL
void PreFrame(); void PreFrame();
ICounterEvent ReportCounter(CounterType type, EventHandler<ulong> resultHandler, bool hostReserved); ICounterEvent ReportCounter(CounterType type, EventHandler<ulong> resultHandler, float divisor, bool hostReserved);
void ResetCounter(CounterType type); void ResetCounter(CounterType type);

View File

@@ -6,7 +6,6 @@ namespace Ryujinx.Graphics.GAL
{ {
int Width { get; } int Width { get; }
int Height { get; } int Height { get; }
float ScaleFactor { get; }
void CopyTo(ITexture destination, int firstLayer, int firstLevel); void CopyTo(ITexture destination, int firstLayer, int firstLevel);
void CopyTo(ITexture destination, int srcLayer, int dstLayer, int srcLevel, int dstLevel); void CopyTo(ITexture destination, int srcLayer, int dstLayer, int srcLevel, int dstLevel);

View File

@@ -125,7 +125,6 @@ namespace Ryujinx.Graphics.GAL.Multithreading
Register<SetProgramCommand>(CommandType.SetProgram); Register<SetProgramCommand>(CommandType.SetProgram);
Register<SetRasterizerDiscardCommand>(CommandType.SetRasterizerDiscard); Register<SetRasterizerDiscardCommand>(CommandType.SetRasterizerDiscard);
Register<SetRenderTargetColorMasksCommand>(CommandType.SetRenderTargetColorMasks); Register<SetRenderTargetColorMasksCommand>(CommandType.SetRenderTargetColorMasks);
Register<SetRenderTargetScaleCommand>(CommandType.SetRenderTargetScale);
Register<SetRenderTargetsCommand>(CommandType.SetRenderTargets); Register<SetRenderTargetsCommand>(CommandType.SetRenderTargets);
Register<SetScissorsCommand>(CommandType.SetScissor); Register<SetScissorsCommand>(CommandType.SetScissor);
Register<SetStencilTestCommand>(CommandType.SetStencilTest); Register<SetStencilTestCommand>(CommandType.SetStencilTest);
@@ -138,7 +137,6 @@ namespace Ryujinx.Graphics.GAL.Multithreading
Register<TextureBarrierTiledCommand>(CommandType.TextureBarrierTiled); Register<TextureBarrierTiledCommand>(CommandType.TextureBarrierTiled);
Register<TryHostConditionalRenderingCommand>(CommandType.TryHostConditionalRendering); Register<TryHostConditionalRenderingCommand>(CommandType.TryHostConditionalRendering);
Register<TryHostConditionalRenderingFlushCommand>(CommandType.TryHostConditionalRenderingFlush); Register<TryHostConditionalRenderingFlushCommand>(CommandType.TryHostConditionalRenderingFlush);
Register<UpdateRenderScaleCommand>(CommandType.UpdateRenderScale);
return maxCommandSize; return maxCommandSize;
} }

View File

@@ -87,7 +87,6 @@
SetProgram, SetProgram,
SetRasterizerDiscard, SetRasterizerDiscard,
SetRenderTargetColorMasks, SetRenderTargetColorMasks,
SetRenderTargetScale,
SetRenderTargets, SetRenderTargets,
SetScissor, SetScissor,
SetStencilTest, SetStencilTest,
@@ -100,6 +99,5 @@
TextureBarrierTiled, TextureBarrierTiled,
TryHostConditionalRendering, TryHostConditionalRendering,
TryHostConditionalRenderingFlush, TryHostConditionalRenderingFlush,
UpdateRenderScale,
} }
} }

View File

@@ -8,18 +8,16 @@ namespace Ryujinx.Graphics.GAL.Multithreading.Commands.Renderer
public readonly CommandType CommandType => CommandType.CreateTexture; public readonly CommandType CommandType => CommandType.CreateTexture;
private TableRef<ThreadedTexture> _texture; private TableRef<ThreadedTexture> _texture;
private TextureCreateInfo _info; private TextureCreateInfo _info;
private float _scale;
public void Set(TableRef<ThreadedTexture> texture, TextureCreateInfo info, float scale) public void Set(TableRef<ThreadedTexture> texture, TextureCreateInfo info)
{ {
_texture = texture; _texture = texture;
_info = info; _info = info;
_scale = scale;
} }
public static void Run(ref CreateTextureCommand command, ThreadedRenderer threaded, IRenderer renderer) public static void Run(ref CreateTextureCommand command, ThreadedRenderer threaded, IRenderer renderer)
{ {
command._texture.Get(threaded).Base = renderer.CreateTexture(command._info, command._scale); command._texture.Get(threaded).Base = renderer.CreateTexture(command._info);
} }
} }
} }

View File

@@ -10,13 +10,15 @@ namespace Ryujinx.Graphics.GAL.Multithreading.Commands.Renderer
private TableRef<ThreadedCounterEvent> _event; private TableRef<ThreadedCounterEvent> _event;
private CounterType _type; private CounterType _type;
private TableRef<EventHandler<ulong>> _resultHandler; private TableRef<EventHandler<ulong>> _resultHandler;
private float _divisor;
private bool _hostReserved; private bool _hostReserved;
public void Set(TableRef<ThreadedCounterEvent> evt, CounterType type, TableRef<EventHandler<ulong>> resultHandler, bool hostReserved) public void Set(TableRef<ThreadedCounterEvent> evt, CounterType type, TableRef<EventHandler<ulong>> resultHandler, float divisor, bool hostReserved)
{ {
_event = evt; _event = evt;
_type = type; _type = type;
_resultHandler = resultHandler; _resultHandler = resultHandler;
_divisor = divisor;
_hostReserved = hostReserved; _hostReserved = hostReserved;
} }
@@ -24,7 +26,7 @@ namespace Ryujinx.Graphics.GAL.Multithreading.Commands.Renderer
{ {
ThreadedCounterEvent evt = command._event.Get(threaded); ThreadedCounterEvent evt = command._event.Get(threaded);
evt.Create(renderer, command._type, command._resultHandler.Get(threaded), command._hostReserved); evt.Create(renderer, command._type, command._resultHandler.Get(threaded), command._divisor, command._hostReserved);
} }
} }
} }

View File

@@ -1,18 +0,0 @@
namespace Ryujinx.Graphics.GAL.Multithreading.Commands
{
struct SetRenderTargetScaleCommand : IGALCommand, IGALCommand<SetRenderTargetScaleCommand>
{
public readonly CommandType CommandType => CommandType.SetRenderTargetScale;
private float _scale;
public void Set(float scale)
{
_scale = scale;
}
public static void Run(ref SetRenderTargetScaleCommand command, ThreadedRenderer threaded, IRenderer renderer)
{
renderer.Pipeline.SetRenderTargetScale(command._scale);
}
}
}

View File

@@ -7,18 +7,16 @@ namespace Ryujinx.Graphics.GAL.Multithreading.Commands
{ {
public readonly CommandType CommandType => CommandType.SetViewports; public readonly CommandType CommandType => CommandType.SetViewports;
private SpanRef<Viewport> _viewports; private SpanRef<Viewport> _viewports;
private bool _disableTransform;
public void Set(SpanRef<Viewport> viewports, bool disableTransform) public void Set(SpanRef<Viewport> viewports)
{ {
_viewports = viewports; _viewports = viewports;
_disableTransform = disableTransform;
} }
public static void Run(ref SetViewportsCommand command, ThreadedRenderer threaded, IRenderer renderer) public static void Run(ref SetViewportsCommand command, ThreadedRenderer threaded, IRenderer renderer)
{ {
ReadOnlySpan<Viewport> viewports = command._viewports.Get(threaded); ReadOnlySpan<Viewport> viewports = command._viewports.Get(threaded);
renderer.Pipeline.SetViewports(viewports, command._disableTransform); renderer.Pipeline.SetViewports(viewports);
command._viewports.Dispose(threaded); command._viewports.Dispose(threaded);
} }
} }

View File

@@ -1,25 +0,0 @@
using Ryujinx.Graphics.GAL.Multithreading.Model;
namespace Ryujinx.Graphics.GAL.Multithreading.Commands
{
struct UpdateRenderScaleCommand : IGALCommand, IGALCommand<UpdateRenderScaleCommand>
{
public readonly CommandType CommandType => CommandType.UpdateRenderScale;
private SpanRef<float> _scales;
private int _totalCount;
private int _fragmentCount;
public void Set(SpanRef<float> scales, int totalCount, int fragmentCount)
{
_scales = scales;
_totalCount = totalCount;
_fragmentCount = fragmentCount;
}
public static void Run(ref UpdateRenderScaleCommand command, ThreadedRenderer threaded, IRenderer renderer)
{
renderer.Pipeline.UpdateRenderScale(command._scales.Get(threaded), command._totalCount, command._fragmentCount);
command._scales.Dispose(threaded);
}
}
}

View File

@@ -70,10 +70,10 @@ namespace Ryujinx.Graphics.GAL.Multithreading.Resources
} }
} }
public void Create(IRenderer renderer, CounterType type, System.EventHandler<ulong> eventHandler, bool hostReserved) public void Create(IRenderer renderer, CounterType type, System.EventHandler<ulong> eventHandler, float divisor, bool hostReserved)
{ {
ThreadedHelpers.SpinUntilExchange(ref _createLock, 1, 0); ThreadedHelpers.SpinUntilExchange(ref _createLock, 1, 0);
Base = renderer.ReportCounter(type, eventHandler, hostReserved || _reserved); Base = renderer.ReportCounter(type, eventHandler, divisor, hostReserved || _reserved);
Volatile.Write(ref _createLock, 0); Volatile.Write(ref _createLock, 0);
} }
} }

View File

@@ -17,13 +17,10 @@ namespace Ryujinx.Graphics.GAL.Multithreading.Resources
public int Height => _info.Height; public int Height => _info.Height;
public float ScaleFactor { get; } public ThreadedTexture(ThreadedRenderer renderer, TextureCreateInfo info)
public ThreadedTexture(ThreadedRenderer renderer, TextureCreateInfo info, float scale)
{ {
_renderer = renderer; _renderer = renderer;
_info = info; _info = info;
ScaleFactor = scale;
} }
private TableRef<T> Ref<T>(T reference) private TableRef<T> Ref<T>(T reference)
@@ -64,7 +61,7 @@ namespace Ryujinx.Graphics.GAL.Multithreading.Resources
public ITexture CreateView(TextureCreateInfo info, int firstLayer, int firstLevel) public ITexture CreateView(TextureCreateInfo info, int firstLayer, int firstLevel)
{ {
ThreadedTexture newTex = new(_renderer, info, ScaleFactor); ThreadedTexture newTex = new(_renderer, info);
_renderer.New<TextureCreateViewCommand>().Set(Ref(this), Ref(newTex), info, firstLayer, firstLevel); _renderer.New<TextureCreateViewCommand>().Set(Ref(this), Ref(newTex), info, firstLayer, firstLevel);
_renderer.QueueCommand(); _renderer.QueueCommand();

View File

@@ -261,12 +261,6 @@ namespace Ryujinx.Graphics.GAL.Multithreading
_renderer.QueueCommand(); _renderer.QueueCommand();
} }
public void SetRenderTargetScale(float scale)
{
_renderer.New<SetRenderTargetScaleCommand>().Set(scale);
_renderer.QueueCommand();
}
public void SetScissors(ReadOnlySpan<Rectangle<int>> scissors) public void SetScissors(ReadOnlySpan<Rectangle<int>> scissors)
{ {
_renderer.New<SetScissorsCommand>().Set(_renderer.CopySpan(scissors)); _renderer.New<SetScissorsCommand>().Set(_renderer.CopySpan(scissors));
@@ -321,9 +315,9 @@ namespace Ryujinx.Graphics.GAL.Multithreading
_renderer.QueueCommand(); _renderer.QueueCommand();
} }
public void SetViewports(ReadOnlySpan<Viewport> viewports, bool disableTransform) public void SetViewports(ReadOnlySpan<Viewport> viewports)
{ {
_renderer.New<SetViewportsCommand>().Set(_renderer.CopySpan(viewports), disableTransform); _renderer.New<SetViewportsCommand>().Set(_renderer.CopySpan(viewports));
_renderer.QueueCommand(); _renderer.QueueCommand();
} }
@@ -368,11 +362,5 @@ namespace Ryujinx.Graphics.GAL.Multithreading
_renderer.QueueCommand(); _renderer.QueueCommand();
return false; return false;
} }
public void UpdateRenderScale(ReadOnlySpan<float> scales, int totalCount, int fragmentCount)
{
_renderer.New<UpdateRenderScaleCommand>().Set(_renderer.CopySpan(scales[..totalCount]), totalCount, fragmentCount);
_renderer.QueueCommand();
}
} }
} }

View File

@@ -320,21 +320,21 @@ namespace Ryujinx.Graphics.GAL.Multithreading
QueueCommand(); QueueCommand();
} }
public ITexture CreateTexture(TextureCreateInfo info, float scale) public ITexture CreateTexture(TextureCreateInfo info)
{ {
if (IsGpuThread()) if (IsGpuThread())
{ {
var texture = new ThreadedTexture(this, info, scale); var texture = new ThreadedTexture(this, info);
New<CreateTextureCommand>().Set(Ref(texture), info, scale); New<CreateTextureCommand>().Set(Ref(texture), info);
QueueCommand(); QueueCommand();
return texture; return texture;
} }
else else
{ {
var texture = new ThreadedTexture(this, info, scale) var texture = new ThreadedTexture(this, info)
{ {
Base = _baseRenderer.CreateTexture(info, scale), Base = _baseRenderer.CreateTexture(info),
}; };
return texture; return texture;
@@ -410,10 +410,10 @@ namespace Ryujinx.Graphics.GAL.Multithreading
QueueCommand(); QueueCommand();
} }
public ICounterEvent ReportCounter(CounterType type, EventHandler<ulong> resultHandler, bool hostReserved) public ICounterEvent ReportCounter(CounterType type, EventHandler<ulong> resultHandler, float divisor, bool hostReserved)
{ {
ThreadedCounterEvent evt = new(this, type, _lastSampleCounterClear); ThreadedCounterEvent evt = new ThreadedCounterEvent(this, type, _lastSampleCounterClear);
New<ReportCounterCommand>().Set(Ref(evt), type, Ref(resultHandler), hostReserved); New<ReportCounterCommand>().Set(Ref(evt), type, Ref(resultHandler), divisor, hostReserved);
QueueCommand(); QueueCommand();
if (type == CounterType.SamplesPassed) if (type == CounterType.SamplesPassed)

View File

@@ -1,102 +0,0 @@
using Ryujinx.Graphics.Shader;
using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace Ryujinx.Graphics.GAL
{
public class SupportBufferUpdater : IDisposable
{
public SupportBuffer Data;
public BufferHandle Handle;
private readonly IRenderer _renderer;
private int _startOffset = -1;
private int _endOffset = -1;
public SupportBufferUpdater(IRenderer renderer)
{
_renderer = renderer;
Handle = renderer.CreateBuffer(SupportBuffer.RequiredSize);
renderer.Pipeline.ClearBuffer(Handle, 0, SupportBuffer.RequiredSize, 0);
}
private void MarkDirty(int startOffset, int byteSize)
{
int endOffset = startOffset + byteSize;
if (_startOffset == -1)
{
_startOffset = startOffset;
_endOffset = endOffset;
}
else
{
if (startOffset < _startOffset)
{
_startOffset = startOffset;
}
if (endOffset > _endOffset)
{
_endOffset = endOffset;
}
}
}
public void UpdateFragmentRenderScaleCount(int count)
{
if (Data.FragmentRenderScaleCount.X != count)
{
Data.FragmentRenderScaleCount.X = count;
MarkDirty(SupportBuffer.FragmentRenderScaleCountOffset, sizeof(int));
}
}
private void UpdateGenericField<T>(int baseOffset, ReadOnlySpan<T> data, Span<T> target, int offset, int count) where T : unmanaged
{
data[..count].CopyTo(target[offset..]);
int elemSize = Unsafe.SizeOf<T>();
MarkDirty(baseOffset + offset * elemSize, count * elemSize);
}
public void UpdateRenderScale(ReadOnlySpan<Vector4<float>> data, int offset, int count)
{
UpdateGenericField(SupportBuffer.GraphicsRenderScaleOffset, data, Data.RenderScale.AsSpan(), offset, count);
}
public void UpdateFragmentIsBgra(ReadOnlySpan<Vector4<int>> data, int offset, int count)
{
UpdateGenericField(SupportBuffer.FragmentIsBgraOffset, data, Data.FragmentIsBgra.AsSpan(), offset, count);
}
public void UpdateViewportInverse(Vector4<float> data)
{
Data.ViewportInverse = data;
MarkDirty(SupportBuffer.ViewportInverseOffset, SupportBuffer.FieldSize);
}
public void Commit()
{
if (_startOffset != -1)
{
ReadOnlySpan<byte> data = MemoryMarshal.Cast<SupportBuffer, byte>(MemoryMarshal.CreateSpan(ref Data, 1));
_renderer.SetBufferData(Handle, _startOffset, data[_startOffset.._endOffset]);
_startOffset = -1;
_endOffset = -1;
}
}
public void Dispose()
{
GC.SuppressFinalize(this);
_renderer.DeleteBuffer(Handle);
}
}
}

View File

@@ -10,6 +10,6 @@ namespace Ryujinx.Graphics.Gpu
Compute = 0xb1c0, Compute = 0xb1c0,
InlineToMemory = 0xa140, InlineToMemory = 0xa140,
Dma = 0xb0b5, Dma = 0xb0b5,
GPFifo = 0xb06f GPFifo = 0xb06f,
} }
} }

View File

@@ -1,9 +1,7 @@
using Ryujinx.Graphics.Device; using Ryujinx.Graphics.Device;
using Ryujinx.Graphics.GAL;
using Ryujinx.Graphics.Gpu.Engine.InlineToMemory; using Ryujinx.Graphics.Gpu.Engine.InlineToMemory;
using Ryujinx.Graphics.Gpu.Engine.Threed; using Ryujinx.Graphics.Gpu.Engine.Threed;
using Ryujinx.Graphics.Gpu.Engine.Types; using Ryujinx.Graphics.Gpu.Engine.Types;
using Ryujinx.Graphics.Gpu.Image;
using Ryujinx.Graphics.Gpu.Shader; using Ryujinx.Graphics.Gpu.Shader;
using Ryujinx.Graphics.Shader; using Ryujinx.Graphics.Shader;
using System; using System;
@@ -39,7 +37,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Compute
{ {
{ nameof(ComputeClassState.LaunchDma), new RwCallback(LaunchDma, null) }, { nameof(ComputeClassState.LaunchDma), new RwCallback(LaunchDma, null) },
{ nameof(ComputeClassState.LoadInlineData), new RwCallback(LoadInlineData, null) }, { nameof(ComputeClassState.LoadInlineData), new RwCallback(LoadInlineData, null) },
{ nameof(ComputeClassState.SendSignalingPcasB), new RwCallback(SendSignalingPcasB, null) } { nameof(ComputeClassState.SendSignalingPcasB), new RwCallback(SendSignalingPcasB, null) },
}); });
_i2mClass = new InlineToMemoryClass(context, channel, initializeState: false); _i2mClass = new InlineToMemoryClass(context, channel, initializeState: false);
@@ -128,12 +126,12 @@ namespace Ryujinx.Graphics.Gpu.Engine.Compute
ulong samplerPoolGpuVa = ((ulong)_state.State.SetTexSamplerPoolAOffsetUpper << 32) | _state.State.SetTexSamplerPoolB; ulong samplerPoolGpuVa = ((ulong)_state.State.SetTexSamplerPoolAOffsetUpper << 32) | _state.State.SetTexSamplerPoolB;
ulong texturePoolGpuVa = ((ulong)_state.State.SetTexHeaderPoolAOffsetUpper << 32) | _state.State.SetTexHeaderPoolB; ulong texturePoolGpuVa = ((ulong)_state.State.SetTexHeaderPoolAOffsetUpper << 32) | _state.State.SetTexHeaderPoolB;
GpuChannelPoolState poolState = new GpuChannelPoolState( GpuChannelPoolState poolState = new(
texturePoolGpuVa, texturePoolGpuVa,
_state.State.SetTexHeaderPoolCMaximumIndex, _state.State.SetTexHeaderPoolCMaximumIndex,
_state.State.SetBindlessTextureConstantBufferSlotSelect); _state.State.SetBindlessTextureConstantBufferSlotSelect);
GpuChannelComputeState computeState = new GpuChannelComputeState( GpuChannelComputeState computeState = new(
qmd.CtaThreadDimension0, qmd.CtaThreadDimension0,
qmd.CtaThreadDimension1, qmd.CtaThreadDimension1,
qmd.CtaThreadDimension2, qmd.CtaThreadDimension2,
@@ -189,8 +187,6 @@ namespace Ryujinx.Graphics.Gpu.Engine.Compute
cs = memoryManager.Physical.ShaderCache.GetComputeShader(_channel, poolState, computeState, shaderGpuVa); cs = memoryManager.Physical.ShaderCache.GetComputeShader(_channel, poolState, computeState, shaderGpuVa);
_context.Renderer.Pipeline.SetProgram(cs.HostProgram); _context.Renderer.Pipeline.SetProgram(cs.HostProgram);
info = cs.Shaders[0].Info;
} }
_channel.BufferManager.SetComputeBufferBindings(cs.Bindings); _channel.BufferManager.SetComputeBufferBindings(cs.Bindings);

View File

@@ -98,24 +98,24 @@ namespace Ryujinx.Graphics.Gpu.Engine.Compute
/// </summary> /// </summary>
unsafe struct ComputeClassState unsafe struct ComputeClassState
{ {
#pragma warning disable CS0649 #pragma warning disable CS0649 // Field is never assigned to
public uint SetObject; public uint SetObject;
public int SetObjectClassId => (int)(SetObject & 0xFFFF); public readonly int SetObjectClassId => (int)(SetObject & 0xFFFF);
public int SetObjectEngineId => (int)((SetObject >> 16) & 0x1F); public readonly int SetObjectEngineId => (int)((SetObject >> 16) & 0x1F);
public fixed uint Reserved04[63]; public fixed uint Reserved04[63];
public uint NoOperation; public uint NoOperation;
public uint SetNotifyA; public uint SetNotifyA;
public int SetNotifyAAddressUpper => (int)(SetNotifyA & 0xFF); public readonly int SetNotifyAAddressUpper => (int)(SetNotifyA & 0xFF);
public uint SetNotifyB; public uint SetNotifyB;
public uint Notify; public uint Notify;
public NotifyType NotifyType => (NotifyType)(Notify); public readonly NotifyType NotifyType => (NotifyType)(Notify);
public uint WaitForIdle; public uint WaitForIdle;
public fixed uint Reserved114[7]; public fixed uint Reserved114[7];
public uint SetGlobalRenderEnableA; public uint SetGlobalRenderEnableA;
public int SetGlobalRenderEnableAOffsetUpper => (int)(SetGlobalRenderEnableA & 0xFF); public readonly int SetGlobalRenderEnableAOffsetUpper => (int)(SetGlobalRenderEnableA & 0xFF);
public uint SetGlobalRenderEnableB; public uint SetGlobalRenderEnableB;
public uint SetGlobalRenderEnableC; public uint SetGlobalRenderEnableC;
public int SetGlobalRenderEnableCMode => (int)(SetGlobalRenderEnableC & 0x7); public readonly int SetGlobalRenderEnableCMode => (int)(SetGlobalRenderEnableC & 0x7);
public uint SendGoIdle; public uint SendGoIdle;
public uint PmTrigger; public uint PmTrigger;
public uint PmTriggerWfi; public uint PmTriggerWfi;
@@ -126,34 +126,34 @@ namespace Ryujinx.Graphics.Gpu.Engine.Compute
public uint LineLengthIn; public uint LineLengthIn;
public uint LineCount; public uint LineCount;
public uint OffsetOutUpper; public uint OffsetOutUpper;
public int OffsetOutUpperValue => (int)(OffsetOutUpper & 0xFF); public readonly int OffsetOutUpperValue => (int)(OffsetOutUpper & 0xFF);
public uint OffsetOut; public uint OffsetOut;
public uint PitchOut; public uint PitchOut;
public uint SetDstBlockSize; public uint SetDstBlockSize;
public SetDstBlockSizeWidth SetDstBlockSizeWidth => (SetDstBlockSizeWidth)(SetDstBlockSize & 0xF); public readonly SetDstBlockSizeWidth SetDstBlockSizeWidth => (SetDstBlockSizeWidth)(SetDstBlockSize & 0xF);
public SetDstBlockSizeHeight SetDstBlockSizeHeight => (SetDstBlockSizeHeight)((SetDstBlockSize >> 4) & 0xF); public readonly SetDstBlockSizeHeight SetDstBlockSizeHeight => (SetDstBlockSizeHeight)((SetDstBlockSize >> 4) & 0xF);
public SetDstBlockSizeDepth SetDstBlockSizeDepth => (SetDstBlockSizeDepth)((SetDstBlockSize >> 8) & 0xF); public readonly SetDstBlockSizeDepth SetDstBlockSizeDepth => (SetDstBlockSizeDepth)((SetDstBlockSize >> 8) & 0xF);
public uint SetDstWidth; public uint SetDstWidth;
public uint SetDstHeight; public uint SetDstHeight;
public uint SetDstDepth; public uint SetDstDepth;
public uint SetDstLayer; public uint SetDstLayer;
public uint SetDstOriginBytesX; public uint SetDstOriginBytesX;
public int SetDstOriginBytesXV => (int)(SetDstOriginBytesX & 0xFFFFF); public readonly int SetDstOriginBytesXV => (int)(SetDstOriginBytesX & 0xFFFFF);
public uint SetDstOriginSamplesY; public uint SetDstOriginSamplesY;
public int SetDstOriginSamplesYV => (int)(SetDstOriginSamplesY & 0xFFFF); public readonly int SetDstOriginSamplesYV => (int)(SetDstOriginSamplesY & 0xFFFF);
public uint LaunchDma; public uint LaunchDma;
public LaunchDmaDstMemoryLayout LaunchDmaDstMemoryLayout => (LaunchDmaDstMemoryLayout)(LaunchDma & 0x1); public readonly LaunchDmaDstMemoryLayout LaunchDmaDstMemoryLayout => (LaunchDmaDstMemoryLayout)(LaunchDma & 0x1);
public LaunchDmaCompletionType LaunchDmaCompletionType => (LaunchDmaCompletionType)((LaunchDma >> 4) & 0x3); public readonly LaunchDmaCompletionType LaunchDmaCompletionType => (LaunchDmaCompletionType)((LaunchDma >> 4) & 0x3);
public LaunchDmaInterruptType LaunchDmaInterruptType => (LaunchDmaInterruptType)((LaunchDma >> 8) & 0x3); public readonly LaunchDmaInterruptType LaunchDmaInterruptType => (LaunchDmaInterruptType)((LaunchDma >> 8) & 0x3);
public LaunchDmaSemaphoreStructSize LaunchDmaSemaphoreStructSize => (LaunchDmaSemaphoreStructSize)((LaunchDma >> 12) & 0x1); public readonly LaunchDmaSemaphoreStructSize LaunchDmaSemaphoreStructSize => (LaunchDmaSemaphoreStructSize)((LaunchDma >> 12) & 0x1);
public bool LaunchDmaReductionEnable => (LaunchDma & 0x2) != 0; public readonly bool LaunchDmaReductionEnable => (LaunchDma & 0x2) != 0;
public LaunchDmaReductionOp LaunchDmaReductionOp => (LaunchDmaReductionOp)((LaunchDma >> 13) & 0x7); public readonly LaunchDmaReductionOp LaunchDmaReductionOp => (LaunchDmaReductionOp)((LaunchDma >> 13) & 0x7);
public LaunchDmaReductionFormat LaunchDmaReductionFormat => (LaunchDmaReductionFormat)((LaunchDma >> 2) & 0x3); public readonly LaunchDmaReductionFormat LaunchDmaReductionFormat => (LaunchDmaReductionFormat)((LaunchDma >> 2) & 0x3);
public bool LaunchDmaSysmembarDisable => (LaunchDma & 0x40) != 0; public readonly bool LaunchDmaSysmembarDisable => (LaunchDma & 0x40) != 0;
public uint LoadInlineData; public uint LoadInlineData;
public fixed uint Reserved1B8[9]; public fixed uint Reserved1B8[9];
public uint SetI2mSemaphoreA; public uint SetI2mSemaphoreA;
public int SetI2mSemaphoreAOffsetUpper => (int)(SetI2mSemaphoreA & 0xFF); public readonly int SetI2mSemaphoreAOffsetUpper => (int)(SetI2mSemaphoreA & 0xFF);
public uint SetI2mSemaphoreB; public uint SetI2mSemaphoreB;
public uint SetI2mSemaphoreC; public uint SetI2mSemaphoreC;
public fixed uint Reserved1E8[2]; public fixed uint Reserved1E8[2];
@@ -162,20 +162,20 @@ namespace Ryujinx.Graphics.Gpu.Engine.Compute
public uint SetI2mSpareNoop02; public uint SetI2mSpareNoop02;
public uint SetI2mSpareNoop03; public uint SetI2mSpareNoop03;
public uint SetValidSpanOverflowAreaA; public uint SetValidSpanOverflowAreaA;
public int SetValidSpanOverflowAreaAAddressUpper => (int)(SetValidSpanOverflowAreaA & 0xFF); public readonly int SetValidSpanOverflowAreaAAddressUpper => (int)(SetValidSpanOverflowAreaA & 0xFF);
public uint SetValidSpanOverflowAreaB; public uint SetValidSpanOverflowAreaB;
public uint SetValidSpanOverflowAreaC; public uint SetValidSpanOverflowAreaC;
public uint SetCoalesceWaitingPeriodUnit; public uint SetCoalesceWaitingPeriodUnit;
public uint PerfmonTransfer; public uint PerfmonTransfer;
public uint SetShaderSharedMemoryWindow; public uint SetShaderSharedMemoryWindow;
public uint SetSelectMaxwellTextureHeaders; public uint SetSelectMaxwellTextureHeaders;
public bool SetSelectMaxwellTextureHeadersV => (SetSelectMaxwellTextureHeaders & 0x1) != 0; public readonly bool SetSelectMaxwellTextureHeadersV => (SetSelectMaxwellTextureHeaders & 0x1) != 0;
public uint InvalidateShaderCaches; public uint InvalidateShaderCaches;
public bool InvalidateShaderCachesInstruction => (InvalidateShaderCaches & 0x1) != 0; public readonly bool InvalidateShaderCachesInstruction => (InvalidateShaderCaches & 0x1) != 0;
public bool InvalidateShaderCachesData => (InvalidateShaderCaches & 0x10) != 0; public readonly bool InvalidateShaderCachesData => (InvalidateShaderCaches & 0x10) != 0;
public bool InvalidateShaderCachesConstant => (InvalidateShaderCaches & 0x1000) != 0; public readonly bool InvalidateShaderCachesConstant => (InvalidateShaderCaches & 0x1000) != 0;
public bool InvalidateShaderCachesLocks => (InvalidateShaderCaches & 0x2) != 0; public readonly bool InvalidateShaderCachesLocks => (InvalidateShaderCaches & 0x2) != 0;
public bool InvalidateShaderCachesFlushData => (InvalidateShaderCaches & 0x4) != 0; public readonly bool InvalidateShaderCachesFlushData => (InvalidateShaderCaches & 0x4) != 0;
public uint SetReservedSwMethod00; public uint SetReservedSwMethod00;
public uint SetReservedSwMethod01; public uint SetReservedSwMethod01;
public uint SetReservedSwMethod02; public uint SetReservedSwMethod02;
@@ -185,13 +185,13 @@ namespace Ryujinx.Graphics.Gpu.Engine.Compute
public uint SetReservedSwMethod06; public uint SetReservedSwMethod06;
public uint SetReservedSwMethod07; public uint SetReservedSwMethod07;
public uint SetCwdControl; public uint SetCwdControl;
public SetCwdControlSmSelection SetCwdControlSmSelection => (SetCwdControlSmSelection)(SetCwdControl & 0x1); public readonly SetCwdControlSmSelection SetCwdControlSmSelection => (SetCwdControlSmSelection)(SetCwdControl & 0x1);
public uint InvalidateTextureHeaderCacheNoWfi; public uint InvalidateTextureHeaderCacheNoWfi;
public InvalidateCacheLines InvalidateTextureHeaderCacheNoWfiLines => (InvalidateCacheLines)(InvalidateTextureHeaderCacheNoWfi & 0x1); public readonly InvalidateCacheLines InvalidateTextureHeaderCacheNoWfiLines => (InvalidateCacheLines)(InvalidateTextureHeaderCacheNoWfi & 0x1);
public int InvalidateTextureHeaderCacheNoWfiTag => (int)((InvalidateTextureHeaderCacheNoWfi >> 4) & 0x3FFFFF); public readonly int InvalidateTextureHeaderCacheNoWfiTag => (int)((InvalidateTextureHeaderCacheNoWfi >> 4) & 0x3FFFFF);
public uint SetCwdRefCounter; public uint SetCwdRefCounter;
public int SetCwdRefCounterSelect => (int)(SetCwdRefCounter & 0x3F); public readonly int SetCwdRefCounterSelect => (int)(SetCwdRefCounter & 0x3F);
public int SetCwdRefCounterValue => (int)((SetCwdRefCounter >> 8) & 0xFFFF); public readonly int SetCwdRefCounterValue => (int)((SetCwdRefCounter >> 8) & 0xFFFF);
public uint SetReservedSwMethod08; public uint SetReservedSwMethod08;
public uint SetReservedSwMethod09; public uint SetReservedSwMethod09;
public uint SetReservedSwMethod10; public uint SetReservedSwMethod10;
@@ -201,59 +201,59 @@ namespace Ryujinx.Graphics.Gpu.Engine.Compute
public uint SetReservedSwMethod14; public uint SetReservedSwMethod14;
public uint SetReservedSwMethod15; public uint SetReservedSwMethod15;
public uint SetGwcScgType; public uint SetGwcScgType;
public SetGwcScgTypeScgType SetGwcScgTypeScgType => (SetGwcScgTypeScgType)(SetGwcScgType & 0x1); public readonly SetGwcScgTypeScgType SetGwcScgTypeScgType => (SetGwcScgTypeScgType)(SetGwcScgType & 0x1);
public uint SetScgControl; public uint SetScgControl;
public int SetScgControlCompute1MaxSmCount => (int)(SetScgControl & 0x1FF); public readonly int SetScgControlCompute1MaxSmCount => (int)(SetScgControl & 0x1FF);
public uint InvalidateConstantBufferCacheA; public uint InvalidateConstantBufferCacheA;
public int InvalidateConstantBufferCacheAAddressUpper => (int)(InvalidateConstantBufferCacheA & 0xFF); public readonly int InvalidateConstantBufferCacheAAddressUpper => (int)(InvalidateConstantBufferCacheA & 0xFF);
public uint InvalidateConstantBufferCacheB; public uint InvalidateConstantBufferCacheB;
public uint InvalidateConstantBufferCacheC; public uint InvalidateConstantBufferCacheC;
public int InvalidateConstantBufferCacheCByteCount => (int)(InvalidateConstantBufferCacheC & 0x1FFFF); public readonly int InvalidateConstantBufferCacheCByteCount => (int)(InvalidateConstantBufferCacheC & 0x1FFFF);
public bool InvalidateConstantBufferCacheCThruL2 => (InvalidateConstantBufferCacheC & 0x80000000) != 0; public readonly bool InvalidateConstantBufferCacheCThruL2 => (InvalidateConstantBufferCacheC & 0x80000000) != 0;
public uint SetComputeClassVersion; public uint SetComputeClassVersion;
public int SetComputeClassVersionCurrent => (int)(SetComputeClassVersion & 0xFFFF); public readonly int SetComputeClassVersionCurrent => (int)(SetComputeClassVersion & 0xFFFF);
public int SetComputeClassVersionOldestSupported => (int)((SetComputeClassVersion >> 16) & 0xFFFF); public readonly int SetComputeClassVersionOldestSupported => (int)((SetComputeClassVersion >> 16) & 0xFFFF);
public uint CheckComputeClassVersion; public uint CheckComputeClassVersion;
public int CheckComputeClassVersionCurrent => (int)(CheckComputeClassVersion & 0xFFFF); public readonly int CheckComputeClassVersionCurrent => (int)(CheckComputeClassVersion & 0xFFFF);
public int CheckComputeClassVersionOldestSupported => (int)((CheckComputeClassVersion >> 16) & 0xFFFF); public readonly int CheckComputeClassVersionOldestSupported => (int)((CheckComputeClassVersion >> 16) & 0xFFFF);
public uint SetQmdVersion; public uint SetQmdVersion;
public int SetQmdVersionCurrent => (int)(SetQmdVersion & 0xFFFF); public readonly int SetQmdVersionCurrent => (int)(SetQmdVersion & 0xFFFF);
public int SetQmdVersionOldestSupported => (int)((SetQmdVersion >> 16) & 0xFFFF); public readonly int SetQmdVersionOldestSupported => (int)((SetQmdVersion >> 16) & 0xFFFF);
public uint SetWfiConfig; public uint SetWfiConfig;
public bool SetWfiConfigEnableScgTypeWfi => (SetWfiConfig & 0x1) != 0; public readonly bool SetWfiConfigEnableScgTypeWfi => (SetWfiConfig & 0x1) != 0;
public uint CheckQmdVersion; public uint CheckQmdVersion;
public int CheckQmdVersionCurrent => (int)(CheckQmdVersion & 0xFFFF); public readonly int CheckQmdVersionCurrent => (int)(CheckQmdVersion & 0xFFFF);
public int CheckQmdVersionOldestSupported => (int)((CheckQmdVersion >> 16) & 0xFFFF); public readonly int CheckQmdVersionOldestSupported => (int)((CheckQmdVersion >> 16) & 0xFFFF);
public uint WaitForIdleScgType; public uint WaitForIdleScgType;
public uint InvalidateSkedCaches; public uint InvalidateSkedCaches;
public bool InvalidateSkedCachesV => (InvalidateSkedCaches & 0x1) != 0; public readonly bool InvalidateSkedCachesV => (InvalidateSkedCaches & 0x1) != 0;
public uint SetScgRenderEnableControl; public uint SetScgRenderEnableControl;
public bool SetScgRenderEnableControlCompute1UsesRenderEnable => (SetScgRenderEnableControl & 0x1) != 0; public readonly bool SetScgRenderEnableControlCompute1UsesRenderEnable => (SetScgRenderEnableControl & 0x1) != 0;
public fixed uint Reserved2A0[4]; public fixed uint Reserved2A0[4];
public uint SetCwdSlotCount; public uint SetCwdSlotCount;
public int SetCwdSlotCountV => (int)(SetCwdSlotCount & 0xFF); public readonly int SetCwdSlotCountV => (int)(SetCwdSlotCount & 0xFF);
public uint SendPcasA; public uint SendPcasA;
public uint SendPcasB; public uint SendPcasB;
public int SendPcasBFrom => (int)(SendPcasB & 0xFFFFFF); public readonly int SendPcasBFrom => (int)(SendPcasB & 0xFFFFFF);
public int SendPcasBDelta => (int)((SendPcasB >> 24) & 0xFF); public readonly int SendPcasBDelta => (int)((SendPcasB >> 24) & 0xFF);
public uint SendSignalingPcasB; public uint SendSignalingPcasB;
public bool SendSignalingPcasBInvalidate => (SendSignalingPcasB & 0x1) != 0; public readonly bool SendSignalingPcasBInvalidate => (SendSignalingPcasB & 0x1) != 0;
public bool SendSignalingPcasBSchedule => (SendSignalingPcasB & 0x2) != 0; public readonly bool SendSignalingPcasBSchedule => (SendSignalingPcasB & 0x2) != 0;
public fixed uint Reserved2C0[9]; public fixed uint Reserved2C0[9];
public uint SetShaderLocalMemoryNonThrottledA; public uint SetShaderLocalMemoryNonThrottledA;
public int SetShaderLocalMemoryNonThrottledASizeUpper => (int)(SetShaderLocalMemoryNonThrottledA & 0xFF); public readonly int SetShaderLocalMemoryNonThrottledASizeUpper => (int)(SetShaderLocalMemoryNonThrottledA & 0xFF);
public uint SetShaderLocalMemoryNonThrottledB; public uint SetShaderLocalMemoryNonThrottledB;
public uint SetShaderLocalMemoryNonThrottledC; public uint SetShaderLocalMemoryNonThrottledC;
public int SetShaderLocalMemoryNonThrottledCMaxSmCount => (int)(SetShaderLocalMemoryNonThrottledC & 0x1FF); public readonly int SetShaderLocalMemoryNonThrottledCMaxSmCount => (int)(SetShaderLocalMemoryNonThrottledC & 0x1FF);
public uint SetShaderLocalMemoryThrottledA; public uint SetShaderLocalMemoryThrottledA;
public int SetShaderLocalMemoryThrottledASizeUpper => (int)(SetShaderLocalMemoryThrottledA & 0xFF); public readonly int SetShaderLocalMemoryThrottledASizeUpper => (int)(SetShaderLocalMemoryThrottledA & 0xFF);
public uint SetShaderLocalMemoryThrottledB; public uint SetShaderLocalMemoryThrottledB;
public uint SetShaderLocalMemoryThrottledC; public uint SetShaderLocalMemoryThrottledC;
public int SetShaderLocalMemoryThrottledCMaxSmCount => (int)(SetShaderLocalMemoryThrottledC & 0x1FF); public readonly int SetShaderLocalMemoryThrottledCMaxSmCount => (int)(SetShaderLocalMemoryThrottledC & 0x1FF);
public fixed uint Reserved2FC[5]; public fixed uint Reserved2FC[5];
public uint SetSpaVersion; public uint SetSpaVersion;
public int SetSpaVersionMinor => (int)(SetSpaVersion & 0xFF); public readonly int SetSpaVersionMinor => (int)(SetSpaVersion & 0xFF);
public int SetSpaVersionMajor => (int)((SetSpaVersion >> 8) & 0xFF); public readonly int SetSpaVersionMajor => (int)((SetSpaVersion >> 8) & 0xFF);
public fixed uint Reserved314[123]; public fixed uint Reserved314[123];
public uint SetFalcon00; public uint SetFalcon00;
public uint SetFalcon01; public uint SetFalcon01;
@@ -291,14 +291,14 @@ namespace Ryujinx.Graphics.Gpu.Engine.Compute
public uint SetShaderLocalMemoryWindow; public uint SetShaderLocalMemoryWindow;
public fixed uint Reserved780[4]; public fixed uint Reserved780[4];
public uint SetShaderLocalMemoryA; public uint SetShaderLocalMemoryA;
public int SetShaderLocalMemoryAAddressUpper => (int)(SetShaderLocalMemoryA & 0xFF); public readonly int SetShaderLocalMemoryAAddressUpper => (int)(SetShaderLocalMemoryA & 0xFF);
public uint SetShaderLocalMemoryB; public uint SetShaderLocalMemoryB;
public fixed uint Reserved798[383]; public fixed uint Reserved798[383];
public uint SetShaderCacheControl; public uint SetShaderCacheControl;
public bool SetShaderCacheControlIcachePrefetchEnable => (SetShaderCacheControl & 0x1) != 0; public readonly bool SetShaderCacheControlIcachePrefetchEnable => (SetShaderCacheControl & 0x1) != 0;
public fixed uint ReservedD98[19]; public fixed uint ReservedD98[19];
public uint SetSmTimeoutInterval; public uint SetSmTimeoutInterval;
public int SetSmTimeoutIntervalCounterBit => (int)(SetSmTimeoutInterval & 0x3F); public readonly int SetSmTimeoutIntervalCounterBit => (int)(SetSmTimeoutInterval & 0x3F);
public fixed uint ReservedDE8[87]; public fixed uint ReservedDE8[87];
public uint SetSpareNoop12; public uint SetSpareNoop12;
public uint SetSpareNoop13; public uint SetSpareNoop13;
@@ -319,62 +319,62 @@ namespace Ryujinx.Graphics.Gpu.Engine.Compute
public uint SetSpareNoop11; public uint SetSpareNoop11;
public fixed uint Reserved1070[103]; public fixed uint Reserved1070[103];
public uint InvalidateSamplerCacheAll; public uint InvalidateSamplerCacheAll;
public bool InvalidateSamplerCacheAllV => (InvalidateSamplerCacheAll & 0x1) != 0; public readonly bool InvalidateSamplerCacheAllV => (InvalidateSamplerCacheAll & 0x1) != 0;
public uint InvalidateTextureHeaderCacheAll; public uint InvalidateTextureHeaderCacheAll;
public bool InvalidateTextureHeaderCacheAllV => (InvalidateTextureHeaderCacheAll & 0x1) != 0; public readonly bool InvalidateTextureHeaderCacheAllV => (InvalidateTextureHeaderCacheAll & 0x1) != 0;
public fixed uint Reserved1214[29]; public fixed uint Reserved1214[29];
public uint InvalidateTextureDataCacheNoWfi; public uint InvalidateTextureDataCacheNoWfi;
public InvalidateCacheLines InvalidateTextureDataCacheNoWfiLines => (InvalidateCacheLines)(InvalidateTextureDataCacheNoWfi & 0x1); public readonly InvalidateCacheLines InvalidateTextureDataCacheNoWfiLines => (InvalidateCacheLines)(InvalidateTextureDataCacheNoWfi & 0x1);
public int InvalidateTextureDataCacheNoWfiTag => (int)((InvalidateTextureDataCacheNoWfi >> 4) & 0x3FFFFF); public readonly int InvalidateTextureDataCacheNoWfiTag => (int)((InvalidateTextureDataCacheNoWfi >> 4) & 0x3FFFFF);
public fixed uint Reserved128C[7]; public fixed uint Reserved128C[7];
public uint ActivatePerfSettingsForComputeContext; public uint ActivatePerfSettingsForComputeContext;
public bool ActivatePerfSettingsForComputeContextAll => (ActivatePerfSettingsForComputeContext & 0x1) != 0; public readonly bool ActivatePerfSettingsForComputeContextAll => (ActivatePerfSettingsForComputeContext & 0x1) != 0;
public fixed uint Reserved12AC[33]; public fixed uint Reserved12AC[33];
public uint InvalidateSamplerCache; public uint InvalidateSamplerCache;
public InvalidateCacheLines InvalidateSamplerCacheLines => (InvalidateCacheLines)(InvalidateSamplerCache & 0x1); public readonly InvalidateCacheLines InvalidateSamplerCacheLines => (InvalidateCacheLines)(InvalidateSamplerCache & 0x1);
public int InvalidateSamplerCacheTag => (int)((InvalidateSamplerCache >> 4) & 0x3FFFFF); public readonly int InvalidateSamplerCacheTag => (int)((InvalidateSamplerCache >> 4) & 0x3FFFFF);
public uint InvalidateTextureHeaderCache; public uint InvalidateTextureHeaderCache;
public InvalidateCacheLines InvalidateTextureHeaderCacheLines => (InvalidateCacheLines)(InvalidateTextureHeaderCache & 0x1); public readonly InvalidateCacheLines InvalidateTextureHeaderCacheLines => (InvalidateCacheLines)(InvalidateTextureHeaderCache & 0x1);
public int InvalidateTextureHeaderCacheTag => (int)((InvalidateTextureHeaderCache >> 4) & 0x3FFFFF); public readonly int InvalidateTextureHeaderCacheTag => (int)((InvalidateTextureHeaderCache >> 4) & 0x3FFFFF);
public uint InvalidateTextureDataCache; public uint InvalidateTextureDataCache;
public InvalidateCacheLines InvalidateTextureDataCacheLines => (InvalidateCacheLines)(InvalidateTextureDataCache & 0x1); public readonly InvalidateCacheLines InvalidateTextureDataCacheLines => (InvalidateCacheLines)(InvalidateTextureDataCache & 0x1);
public int InvalidateTextureDataCacheTag => (int)((InvalidateTextureDataCache >> 4) & 0x3FFFFF); public readonly int InvalidateTextureDataCacheTag => (int)((InvalidateTextureDataCache >> 4) & 0x3FFFFF);
public fixed uint Reserved133C[58]; public fixed uint Reserved133C[58];
public uint InvalidateSamplerCacheNoWfi; public uint InvalidateSamplerCacheNoWfi;
public InvalidateCacheLines InvalidateSamplerCacheNoWfiLines => (InvalidateCacheLines)(InvalidateSamplerCacheNoWfi & 0x1); public readonly InvalidateCacheLines InvalidateSamplerCacheNoWfiLines => (InvalidateCacheLines)(InvalidateSamplerCacheNoWfi & 0x1);
public int InvalidateSamplerCacheNoWfiTag => (int)((InvalidateSamplerCacheNoWfi >> 4) & 0x3FFFFF); public readonly int InvalidateSamplerCacheNoWfiTag => (int)((InvalidateSamplerCacheNoWfi >> 4) & 0x3FFFFF);
public fixed uint Reserved1428[64]; public fixed uint Reserved1428[64];
public uint SetShaderExceptions; public uint SetShaderExceptions;
public bool SetShaderExceptionsEnable => (SetShaderExceptions & 0x1) != 0; public readonly bool SetShaderExceptionsEnable => (SetShaderExceptions & 0x1) != 0;
public fixed uint Reserved152C[9]; public fixed uint Reserved152C[9];
public uint SetRenderEnableA; public uint SetRenderEnableA;
public int SetRenderEnableAOffsetUpper => (int)(SetRenderEnableA & 0xFF); public readonly int SetRenderEnableAOffsetUpper => (int)(SetRenderEnableA & 0xFF);
public uint SetRenderEnableB; public uint SetRenderEnableB;
public uint SetRenderEnableC; public uint SetRenderEnableC;
public int SetRenderEnableCMode => (int)(SetRenderEnableC & 0x7); public readonly int SetRenderEnableCMode => (int)(SetRenderEnableC & 0x7);
public uint SetTexSamplerPoolA; public uint SetTexSamplerPoolA;
public int SetTexSamplerPoolAOffsetUpper => (int)(SetTexSamplerPoolA & 0xFF); public readonly int SetTexSamplerPoolAOffsetUpper => (int)(SetTexSamplerPoolA & 0xFF);
public uint SetTexSamplerPoolB; public uint SetTexSamplerPoolB;
public uint SetTexSamplerPoolC; public uint SetTexSamplerPoolC;
public int SetTexSamplerPoolCMaximumIndex => (int)(SetTexSamplerPoolC & 0xFFFFF); public readonly int SetTexSamplerPoolCMaximumIndex => (int)(SetTexSamplerPoolC & 0xFFFFF);
public fixed uint Reserved1568[3]; public fixed uint Reserved1568[3];
public uint SetTexHeaderPoolA; public uint SetTexHeaderPoolA;
public int SetTexHeaderPoolAOffsetUpper => (int)(SetTexHeaderPoolA & 0xFF); public readonly int SetTexHeaderPoolAOffsetUpper => (int)(SetTexHeaderPoolA & 0xFF);
public uint SetTexHeaderPoolB; public uint SetTexHeaderPoolB;
public uint SetTexHeaderPoolC; public uint SetTexHeaderPoolC;
public int SetTexHeaderPoolCMaximumIndex => (int)(SetTexHeaderPoolC & 0x3FFFFF); public readonly int SetTexHeaderPoolCMaximumIndex => (int)(SetTexHeaderPoolC & 0x3FFFFF);
public fixed uint Reserved1580[34]; public fixed uint Reserved1580[34];
public uint SetProgramRegionA; public uint SetProgramRegionA;
public int SetProgramRegionAAddressUpper => (int)(SetProgramRegionA & 0xFF); public readonly int SetProgramRegionAAddressUpper => (int)(SetProgramRegionA & 0xFF);
public uint SetProgramRegionB; public uint SetProgramRegionB;
public fixed uint Reserved1610[34]; public fixed uint Reserved1610[34];
public uint InvalidateShaderCachesNoWfi; public uint InvalidateShaderCachesNoWfi;
public bool InvalidateShaderCachesNoWfiInstruction => (InvalidateShaderCachesNoWfi & 0x1) != 0; public readonly bool InvalidateShaderCachesNoWfiInstruction => (InvalidateShaderCachesNoWfi & 0x1) != 0;
public bool InvalidateShaderCachesNoWfiGlobalData => (InvalidateShaderCachesNoWfi & 0x10) != 0; public readonly bool InvalidateShaderCachesNoWfiGlobalData => (InvalidateShaderCachesNoWfi & 0x10) != 0;
public bool InvalidateShaderCachesNoWfiConstant => (InvalidateShaderCachesNoWfi & 0x1000) != 0; public readonly bool InvalidateShaderCachesNoWfiConstant => (InvalidateShaderCachesNoWfi & 0x1000) != 0;
public fixed uint Reserved169C[170]; public fixed uint Reserved169C[170];
public uint SetRenderEnableOverride; public uint SetRenderEnableOverride;
public SetRenderEnableOverrideMode SetRenderEnableOverrideMode => (SetRenderEnableOverrideMode)(SetRenderEnableOverride & 0x3); public readonly SetRenderEnableOverrideMode SetRenderEnableOverrideMode => (SetRenderEnableOverrideMode)(SetRenderEnableOverride & 0x3);
public fixed uint Reserved1948[57]; public fixed uint Reserved1948[57];
public uint PipeNop; public uint PipeNop;
public uint SetSpare00; public uint SetSpare00;
@@ -383,20 +383,20 @@ namespace Ryujinx.Graphics.Gpu.Engine.Compute
public uint SetSpare03; public uint SetSpare03;
public fixed uint Reserved1A40[48]; public fixed uint Reserved1A40[48];
public uint SetReportSemaphoreA; public uint SetReportSemaphoreA;
public int SetReportSemaphoreAOffsetUpper => (int)(SetReportSemaphoreA & 0xFF); public readonly int SetReportSemaphoreAOffsetUpper => (int)(SetReportSemaphoreA & 0xFF);
public uint SetReportSemaphoreB; public uint SetReportSemaphoreB;
public uint SetReportSemaphoreC; public uint SetReportSemaphoreC;
public uint SetReportSemaphoreD; public uint SetReportSemaphoreD;
public SetReportSemaphoreDOperation SetReportSemaphoreDOperation => (SetReportSemaphoreDOperation)(SetReportSemaphoreD & 0x3); public readonly SetReportSemaphoreDOperation SetReportSemaphoreDOperation => (SetReportSemaphoreDOperation)(SetReportSemaphoreD & 0x3);
public bool SetReportSemaphoreDAwakenEnable => (SetReportSemaphoreD & 0x100000) != 0; public readonly bool SetReportSemaphoreDAwakenEnable => (SetReportSemaphoreD & 0x100000) != 0;
public SetReportSemaphoreDStructureSize SetReportSemaphoreDStructureSize => (SetReportSemaphoreDStructureSize)((SetReportSemaphoreD >> 28) & 0x1); public readonly SetReportSemaphoreDStructureSize SetReportSemaphoreDStructureSize => (SetReportSemaphoreDStructureSize)((SetReportSemaphoreD >> 28) & 0x1);
public bool SetReportSemaphoreDFlushDisable => (SetReportSemaphoreD & 0x4) != 0; public readonly bool SetReportSemaphoreDFlushDisable => (SetReportSemaphoreD & 0x4) != 0;
public bool SetReportSemaphoreDReductionEnable => (SetReportSemaphoreD & 0x8) != 0; public readonly bool SetReportSemaphoreDReductionEnable => (SetReportSemaphoreD & 0x8) != 0;
public SetReportSemaphoreDReductionOp SetReportSemaphoreDReductionOp => (SetReportSemaphoreDReductionOp)((SetReportSemaphoreD >> 9) & 0x7); public readonly SetReportSemaphoreDReductionOp SetReportSemaphoreDReductionOp => (SetReportSemaphoreDReductionOp)((SetReportSemaphoreD >> 9) & 0x7);
public SetReportSemaphoreDReductionFormat SetReportSemaphoreDReductionFormat => (SetReportSemaphoreDReductionFormat)((SetReportSemaphoreD >> 17) & 0x3); public readonly SetReportSemaphoreDReductionFormat SetReportSemaphoreDReductionFormat => (SetReportSemaphoreDReductionFormat)((SetReportSemaphoreD >> 17) & 0x3);
public fixed uint Reserved1B10[702]; public fixed uint Reserved1B10[702];
public uint SetBindlessTexture; public uint SetBindlessTexture;
public int SetBindlessTextureConstantBufferSlotSelect => (int)(SetBindlessTexture & 0x7); public readonly int SetBindlessTextureConstantBufferSlotSelect => (int)(SetBindlessTexture & 0x7);
public uint SetTrapHandler; public uint SetTrapHandler;
public fixed uint Reserved2610[843]; public fixed uint Reserved2610[843];
public Array8<uint> SetShaderPerformanceCounterValueUpper; public Array8<uint> SetShaderPerformanceCounterValueUpper;
@@ -423,13 +423,13 @@ namespace Ryujinx.Graphics.Gpu.Engine.Compute
public bool SetShaderPerformanceCounterControlBWindowed(int i) => (SetShaderPerformanceCounterControlB[i] & 0x8) != 0; public bool SetShaderPerformanceCounterControlBWindowed(int i) => (SetShaderPerformanceCounterControlB[i] & 0x8) != 0;
public int SetShaderPerformanceCounterControlBFunc(int i) => (int)((SetShaderPerformanceCounterControlB[i] >> 4) & 0xFFFF); public int SetShaderPerformanceCounterControlBFunc(int i) => (int)((SetShaderPerformanceCounterControlB[i] >> 4) & 0xFFFF);
public uint SetShaderPerformanceCounterTrapControl; public uint SetShaderPerformanceCounterTrapControl;
public int SetShaderPerformanceCounterTrapControlMask => (int)(SetShaderPerformanceCounterTrapControl & 0xFF); public readonly int SetShaderPerformanceCounterTrapControlMask => (int)(SetShaderPerformanceCounterTrapControl & 0xFF);
public uint StartShaderPerformanceCounter; public uint StartShaderPerformanceCounter;
public int StartShaderPerformanceCounterCounterMask => (int)(StartShaderPerformanceCounter & 0xFF); public readonly int StartShaderPerformanceCounterCounterMask => (int)(StartShaderPerformanceCounter & 0xFF);
public uint StopShaderPerformanceCounter; public uint StopShaderPerformanceCounter;
public int StopShaderPerformanceCounterCounterMask => (int)(StopShaderPerformanceCounter & 0xFF); public readonly int StopShaderPerformanceCounterCounterMask => (int)(StopShaderPerformanceCounter & 0xFF);
public fixed uint Reserved33E8[6]; public fixed uint Reserved33E8[6];
public MmeShadowScratch SetMmeShadowScratch; public Array256<uint> SetMmeShadowScratch;
#pragma warning restore CS0649 #pragma warning restore CS0649
} }
} }

View File

@@ -10,7 +10,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Compute
enum DependentQmdType enum DependentQmdType
{ {
Queue, Queue,
Grid Grid,
} }
/// <summary> /// <summary>
@@ -19,7 +19,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Compute
enum ReleaseMembarType enum ReleaseMembarType
{ {
FeNone, FeNone,
FeSysmembar FeSysmembar,
} }
/// <summary> /// <summary>
@@ -29,7 +29,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Compute
{ {
L1None, L1None,
L1Sysmembar, L1Sysmembar,
L1Membar L1Membar,
} }
/// <summary> /// <summary>
@@ -38,7 +38,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Compute
enum Fp32NanBehavior enum Fp32NanBehavior
{ {
Legacy, Legacy,
Fp64Compatible Fp64Compatible,
} }
/// <summary> /// <summary>
@@ -47,7 +47,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Compute
enum Fp32F2iNanBehavior enum Fp32F2iNanBehavior
{ {
PassZero, PassZero,
PassIndefinite PassIndefinite,
} }
/// <summary> /// <summary>
@@ -56,7 +56,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Compute
enum ApiVisibleCallLimit enum ApiVisibleCallLimit
{ {
_32, _32,
NoCheck NoCheck,
} }
/// <summary> /// <summary>
@@ -65,7 +65,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Compute
enum SharedMemoryBankMapping enum SharedMemoryBankMapping
{ {
FourBytesPerBank, FourBytesPerBank,
EightBytesPerBank EightBytesPerBank,
} }
/// <summary> /// <summary>
@@ -74,7 +74,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Compute
enum Fp32NarrowInstruction enum Fp32NarrowInstruction
{ {
KeepDenorms, KeepDenorms,
FlushDenorms FlushDenorms,
} }
/// <summary> /// <summary>
@@ -84,7 +84,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Compute
{ {
DirectlyAddressableMemorySize16kb, DirectlyAddressableMemorySize16kb,
DirectlyAddressableMemorySize32kb, DirectlyAddressableMemorySize32kb,
DirectlyAddressableMemorySize48kb DirectlyAddressableMemorySize48kb,
} }
/// <summary> /// <summary>
@@ -99,7 +99,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Compute
RedDec, RedDec,
RedAnd, RedAnd,
RedOr, RedOr,
RedXor RedXor,
} }
/// <summary> /// <summary>
@@ -108,7 +108,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Compute
enum ReductionFormat enum ReductionFormat
{ {
Unsigned32, Unsigned32,
Signed32 Signed32,
} }
/// <summary> /// <summary>
@@ -117,7 +117,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Compute
enum StructureSize enum StructureSize
{ {
FourWords, FourWords,
OneWord OneWord,
} }
/// <summary> /// <summary>
@@ -127,129 +127,129 @@ namespace Ryujinx.Graphics.Gpu.Engine.Compute
{ {
private fixed int _words[64]; private fixed int _words[64];
public int OuterPut => BitRange(30, 0); public readonly int OuterPut => BitRange(30, 0);
public bool OuterOverflow => Bit(31); public readonly bool OuterOverflow => Bit(31);
public int OuterGet => BitRange(62, 32); public readonly int OuterGet => BitRange(62, 32);
public bool OuterStickyOverflow => Bit(63); public readonly bool OuterStickyOverflow => Bit(63);
public int InnerGet => BitRange(94, 64); public readonly int InnerGet => BitRange(94, 64);
public bool InnerOverflow => Bit(95); public readonly bool InnerOverflow => Bit(95);
public int InnerPut => BitRange(126, 96); public readonly int InnerPut => BitRange(126, 96);
public bool InnerStickyOverflow => Bit(127); public readonly bool InnerStickyOverflow => Bit(127);
public int QmdReservedAA => BitRange(159, 128); public readonly int QmdReservedAA => BitRange(159, 128);
public int DependentQmdPointer => BitRange(191, 160); public readonly int DependentQmdPointer => BitRange(191, 160);
public int QmdGroupId => BitRange(197, 192); public readonly int QmdGroupId => BitRange(197, 192);
public bool SmGlobalCachingEnable => Bit(198); public readonly bool SmGlobalCachingEnable => Bit(198);
public bool RunCtaInOneSmPartition => Bit(199); public readonly bool RunCtaInOneSmPartition => Bit(199);
public bool IsQueue => Bit(200); public readonly bool IsQueue => Bit(200);
public bool AddToHeadOfQmdGroupLinkedList => Bit(201); public readonly bool AddToHeadOfQmdGroupLinkedList => Bit(201);
public bool SemaphoreReleaseEnable0 => Bit(202); public readonly bool SemaphoreReleaseEnable0 => Bit(202);
public bool SemaphoreReleaseEnable1 => Bit(203); public readonly bool SemaphoreReleaseEnable1 => Bit(203);
public bool RequireSchedulingPcas => Bit(204); public readonly bool RequireSchedulingPcas => Bit(204);
public bool DependentQmdScheduleEnable => Bit(205); public readonly bool DependentQmdScheduleEnable => Bit(205);
public DependentQmdType DependentQmdType => (DependentQmdType)BitRange(206, 206); public readonly DependentQmdType DependentQmdType => (DependentQmdType)BitRange(206, 206);
public bool DependentQmdFieldCopy => Bit(207); public readonly bool DependentQmdFieldCopy => Bit(207);
public int QmdReservedB => BitRange(223, 208); public readonly int QmdReservedB => BitRange(223, 208);
public int CircularQueueSize => BitRange(248, 224); public readonly int CircularQueueSize => BitRange(248, 224);
public bool QmdReservedC => Bit(249); public readonly bool QmdReservedC => Bit(249);
public bool InvalidateTextureHeaderCache => Bit(250); public readonly bool InvalidateTextureHeaderCache => Bit(250);
public bool InvalidateTextureSamplerCache => Bit(251); public readonly bool InvalidateTextureSamplerCache => Bit(251);
public bool InvalidateTextureDataCache => Bit(252); public readonly bool InvalidateTextureDataCache => Bit(252);
public bool InvalidateShaderDataCache => Bit(253); public readonly bool InvalidateShaderDataCache => Bit(253);
public bool InvalidateInstructionCache => Bit(254); public readonly bool InvalidateInstructionCache => Bit(254);
public bool InvalidateShaderConstantCache => Bit(255); public readonly bool InvalidateShaderConstantCache => Bit(255);
public int ProgramOffset => BitRange(287, 256); public readonly int ProgramOffset => BitRange(287, 256);
public int CircularQueueAddrLower => BitRange(319, 288); public readonly int CircularQueueAddrLower => BitRange(319, 288);
public int CircularQueueAddrUpper => BitRange(327, 320); public readonly int CircularQueueAddrUpper => BitRange(327, 320);
public int QmdReservedD => BitRange(335, 328); public readonly int QmdReservedD => BitRange(335, 328);
public int CircularQueueEntrySize => BitRange(351, 336); public readonly int CircularQueueEntrySize => BitRange(351, 336);
public int CwdReferenceCountId => BitRange(357, 352); public readonly int CwdReferenceCountId => BitRange(357, 352);
public int CwdReferenceCountDeltaMinusOne => BitRange(365, 358); public readonly int CwdReferenceCountDeltaMinusOne => BitRange(365, 358);
public ReleaseMembarType ReleaseMembarType => (ReleaseMembarType)BitRange(366, 366); public readonly ReleaseMembarType ReleaseMembarType => (ReleaseMembarType)BitRange(366, 366);
public bool CwdReferenceCountIncrEnable => Bit(367); public readonly bool CwdReferenceCountIncrEnable => Bit(367);
public CwdMembarType CwdMembarType => (CwdMembarType)BitRange(369, 368); public readonly CwdMembarType CwdMembarType => (CwdMembarType)BitRange(369, 368);
public bool SequentiallyRunCtas => Bit(370); public readonly bool SequentiallyRunCtas => Bit(370);
public bool CwdReferenceCountDecrEnable => Bit(371); public readonly bool CwdReferenceCountDecrEnable => Bit(371);
public bool Throttled => Bit(372); public readonly bool Throttled => Bit(372);
public Fp32NanBehavior Fp32NanBehavior => (Fp32NanBehavior)BitRange(376, 376); public readonly Fp32NanBehavior Fp32NanBehavior => (Fp32NanBehavior)BitRange(376, 376);
public Fp32F2iNanBehavior Fp32F2iNanBehavior => (Fp32F2iNanBehavior)BitRange(377, 377); public readonly Fp32F2iNanBehavior Fp32F2iNanBehavior => (Fp32F2iNanBehavior)BitRange(377, 377);
public ApiVisibleCallLimit ApiVisibleCallLimit => (ApiVisibleCallLimit)BitRange(378, 378); public readonly ApiVisibleCallLimit ApiVisibleCallLimit => (ApiVisibleCallLimit)BitRange(378, 378);
public SharedMemoryBankMapping SharedMemoryBankMapping => (SharedMemoryBankMapping)BitRange(379, 379); public readonly SharedMemoryBankMapping SharedMemoryBankMapping => (SharedMemoryBankMapping)BitRange(379, 379);
public SamplerIndex SamplerIndex => (SamplerIndex)BitRange(382, 382); public readonly SamplerIndex SamplerIndex => (SamplerIndex)BitRange(382, 382);
public Fp32NarrowInstruction Fp32NarrowInstruction => (Fp32NarrowInstruction)BitRange(383, 383); public readonly Fp32NarrowInstruction Fp32NarrowInstruction => (Fp32NarrowInstruction)BitRange(383, 383);
public int CtaRasterWidth => BitRange(415, 384); public readonly int CtaRasterWidth => BitRange(415, 384);
public int CtaRasterHeight => BitRange(431, 416); public readonly int CtaRasterHeight => BitRange(431, 416);
public int CtaRasterDepth => BitRange(447, 432); public readonly int CtaRasterDepth => BitRange(447, 432);
public int CtaRasterWidthResume => BitRange(479, 448); public readonly int CtaRasterWidthResume => BitRange(479, 448);
public int CtaRasterHeightResume => BitRange(495, 480); public readonly int CtaRasterHeightResume => BitRange(495, 480);
public int CtaRasterDepthResume => BitRange(511, 496); public readonly int CtaRasterDepthResume => BitRange(511, 496);
public int QueueEntriesPerCtaMinusOne => BitRange(518, 512); public readonly int QueueEntriesPerCtaMinusOne => BitRange(518, 512);
public int CoalesceWaitingPeriod => BitRange(529, 522); public readonly int CoalesceWaitingPeriod => BitRange(529, 522);
public int SharedMemorySize => BitRange(561, 544); public readonly int SharedMemorySize => BitRange(561, 544);
public int QmdReservedG => BitRange(575, 562); public readonly int QmdReservedG => BitRange(575, 562);
public int QmdVersion => BitRange(579, 576); public readonly int QmdVersion => BitRange(579, 576);
public int QmdMajorVersion => BitRange(583, 580); public readonly int QmdMajorVersion => BitRange(583, 580);
public int QmdReservedH => BitRange(591, 584); public readonly int QmdReservedH => BitRange(591, 584);
public int CtaThreadDimension0 => BitRange(607, 592); public readonly int CtaThreadDimension0 => BitRange(607, 592);
public int CtaThreadDimension1 => BitRange(623, 608); public readonly int CtaThreadDimension1 => BitRange(623, 608);
public int CtaThreadDimension2 => BitRange(639, 624); public readonly int CtaThreadDimension2 => BitRange(639, 624);
public bool ConstantBufferValid(int i) => Bit(640 + i * 1); public readonly bool ConstantBufferValid(int i) => Bit(640 + i * 1);
public int QmdReservedI => BitRange(668, 648); public readonly int QmdReservedI => BitRange(668, 648);
public L1Configuration L1Configuration => (L1Configuration)BitRange(671, 669); public readonly L1Configuration L1Configuration => (L1Configuration)BitRange(671, 669);
public int SmDisableMaskLower => BitRange(703, 672); public readonly int SmDisableMaskLower => BitRange(703, 672);
public int SmDisableMaskUpper => BitRange(735, 704); public readonly int SmDisableMaskUpper => BitRange(735, 704);
public int Release0AddressLower => BitRange(767, 736); public readonly int Release0AddressLower => BitRange(767, 736);
public int Release0AddressUpper => BitRange(775, 768); public readonly int Release0AddressUpper => BitRange(775, 768);
public int QmdReservedJ => BitRange(783, 776); public readonly int QmdReservedJ => BitRange(783, 776);
public ReductionOp Release0ReductionOp => (ReductionOp)BitRange(790, 788); public readonly ReductionOp Release0ReductionOp => (ReductionOp)BitRange(790, 788);
public bool QmdReservedK => Bit(791); public readonly bool QmdReservedK => Bit(791);
public ReductionFormat Release0ReductionFormat => (ReductionFormat)BitRange(793, 792); public readonly ReductionFormat Release0ReductionFormat => (ReductionFormat)BitRange(793, 792);
public bool Release0ReductionEnable => Bit(794); public readonly bool Release0ReductionEnable => Bit(794);
public StructureSize Release0StructureSize => (StructureSize)BitRange(799, 799); public readonly StructureSize Release0StructureSize => (StructureSize)BitRange(799, 799);
public int Release0Payload => BitRange(831, 800); public readonly int Release0Payload => BitRange(831, 800);
public int Release1AddressLower => BitRange(863, 832); public readonly int Release1AddressLower => BitRange(863, 832);
public int Release1AddressUpper => BitRange(871, 864); public readonly int Release1AddressUpper => BitRange(871, 864);
public int QmdReservedL => BitRange(879, 872); public readonly int QmdReservedL => BitRange(879, 872);
public ReductionOp Release1ReductionOp => (ReductionOp)BitRange(886, 884); public readonly ReductionOp Release1ReductionOp => (ReductionOp)BitRange(886, 884);
public bool QmdReservedM => Bit(887); public readonly bool QmdReservedM => Bit(887);
public ReductionFormat Release1ReductionFormat => (ReductionFormat)BitRange(889, 888); public readonly ReductionFormat Release1ReductionFormat => (ReductionFormat)BitRange(889, 888);
public bool Release1ReductionEnable => Bit(890); public readonly bool Release1ReductionEnable => Bit(890);
public StructureSize Release1StructureSize => (StructureSize)BitRange(895, 895); public readonly StructureSize Release1StructureSize => (StructureSize)BitRange(895, 895);
public int Release1Payload => BitRange(927, 896); public readonly int Release1Payload => BitRange(927, 896);
public int ConstantBufferAddrLower(int i) => BitRange(959 + i * 64, 928 + i * 64); public readonly int ConstantBufferAddrLower(int i) => BitRange(959 + i * 64, 928 + i * 64);
public int ConstantBufferAddrUpper(int i) => BitRange(967 + i * 64, 960 + i * 64); public readonly int ConstantBufferAddrUpper(int i) => BitRange(967 + i * 64, 960 + i * 64);
public int ConstantBufferReservedAddr(int i) => BitRange(973 + i * 64, 968 + i * 64); public readonly int ConstantBufferReservedAddr(int i) => BitRange(973 + i * 64, 968 + i * 64);
public bool ConstantBufferInvalidate(int i) => Bit(974 + i * 64); public readonly bool ConstantBufferInvalidate(int i) => Bit(974 + i * 64);
public int ConstantBufferSize(int i) => BitRange(991 + i * 64, 975 + i * 64); public readonly int ConstantBufferSize(int i) => BitRange(991 + i * 64, 975 + i * 64);
public int ShaderLocalMemoryLowSize => BitRange(1463, 1440); public readonly int ShaderLocalMemoryLowSize => BitRange(1463, 1440);
public int QmdReservedN => BitRange(1466, 1464); public readonly int QmdReservedN => BitRange(1466, 1464);
public int BarrierCount => BitRange(1471, 1467); public readonly int BarrierCount => BitRange(1471, 1467);
public int ShaderLocalMemoryHighSize => BitRange(1495, 1472); public readonly int ShaderLocalMemoryHighSize => BitRange(1495, 1472);
public int RegisterCount => BitRange(1503, 1496); public readonly int RegisterCount => BitRange(1503, 1496);
public int ShaderLocalMemoryCrsSize => BitRange(1527, 1504); public readonly int ShaderLocalMemoryCrsSize => BitRange(1527, 1504);
public int SassVersion => BitRange(1535, 1528); public readonly int SassVersion => BitRange(1535, 1528);
public int HwOnlyInnerGet => BitRange(1566, 1536); public readonly int HwOnlyInnerGet => BitRange(1566, 1536);
public bool HwOnlyRequireSchedulingPcas => Bit(1567); public readonly bool HwOnlyRequireSchedulingPcas => Bit(1567);
public int HwOnlyInnerPut => BitRange(1598, 1568); public readonly int HwOnlyInnerPut => BitRange(1598, 1568);
public bool HwOnlyScgType => Bit(1599); public readonly bool HwOnlyScgType => Bit(1599);
public int HwOnlySpanListHeadIndex => BitRange(1629, 1600); public readonly int HwOnlySpanListHeadIndex => BitRange(1629, 1600);
public bool QmdReservedQ => Bit(1630); public readonly bool QmdReservedQ => Bit(1630);
public bool HwOnlySpanListHeadIndexValid => Bit(1631); public readonly bool HwOnlySpanListHeadIndexValid => Bit(1631);
public int HwOnlySkedNextQmdPointer => BitRange(1663, 1632); public readonly int HwOnlySkedNextQmdPointer => BitRange(1663, 1632);
public int QmdSpareE => BitRange(1695, 1664); public readonly int QmdSpareE => BitRange(1695, 1664);
public int QmdSpareF => BitRange(1727, 1696); public readonly int QmdSpareF => BitRange(1727, 1696);
public int QmdSpareG => BitRange(1759, 1728); public readonly int QmdSpareG => BitRange(1759, 1728);
public int QmdSpareH => BitRange(1791, 1760); public readonly int QmdSpareH => BitRange(1791, 1760);
public int QmdSpareI => BitRange(1823, 1792); public readonly int QmdSpareI => BitRange(1823, 1792);
public int QmdSpareJ => BitRange(1855, 1824); public readonly int QmdSpareJ => BitRange(1855, 1824);
public int QmdSpareK => BitRange(1887, 1856); public readonly int QmdSpareK => BitRange(1887, 1856);
public int QmdSpareL => BitRange(1919, 1888); public readonly int QmdSpareL => BitRange(1919, 1888);
public int QmdSpareM => BitRange(1951, 1920); public readonly int QmdSpareM => BitRange(1951, 1920);
public int QmdSpareN => BitRange(1983, 1952); public readonly int QmdSpareN => BitRange(1983, 1952);
public int DebugIdUpper => BitRange(2015, 1984); public readonly int DebugIdUpper => BitRange(2015, 1984);
public int DebugIdLower => BitRange(2047, 2016); public readonly int DebugIdLower => BitRange(2047, 2016);
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
private bool Bit(int bit) private readonly bool Bit(int bit)
{ {
if ((uint)bit >= 64 * 32) if ((uint)bit >= 64 * 32)
{ {
@@ -260,7 +260,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Compute
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
private int BitRange(int upper, int lower) private readonly int BitRange(int upper, int lower)
{ {
if ((uint)lower >= 64 * 32) if ((uint)lower >= 64 * 32)
{ {

View File

@@ -7,6 +7,6 @@
{ {
False, False,
True, True,
Host Host,
} }
} }

View File

@@ -30,13 +30,13 @@ namespace Ryujinx.Graphics.Gpu.Engine.Dma
SrcLinear = 1 << 7, SrcLinear = 1 << 7,
DstLinear = 1 << 8, DstLinear = 1 << 8,
MultiLineEnable = 1 << 9, MultiLineEnable = 1 << 9,
RemapEnable = 1 << 10 RemapEnable = 1 << 10,
} }
/// <summary> /// <summary>
/// Texture parameters for copy. /// Texture parameters for copy.
/// </summary> /// </summary>
private struct TextureParams private readonly struct TextureParams
{ {
/// <summary> /// <summary>
/// Copy region X coordinate. /// Copy region X coordinate.
@@ -109,7 +109,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Dma
_3dEngine = threedEngine; _3dEngine = threedEngine;
_state = new DeviceState<DmaClassState>(new Dictionary<string, RwCallback> _state = new DeviceState<DmaClassState>(new Dictionary<string, RwCallback>
{ {
{ nameof(DmaClassState.LaunchDma), new RwCallback(LaunchDma, null) } { nameof(DmaClassState.LaunchDma), new RwCallback(LaunchDma, null) },
}); });
} }
@@ -345,8 +345,8 @@ namespace Ryujinx.Graphics.Gpu.Engine.Dma
// all be rewritten to use pooled arrays, but that gets complicated with packed data and strides // all be rewritten to use pooled arrays, but that gets complicated with packed data and strides
Span<byte> dstSpan = memoryManager.GetSpan(dstGpuVa + (ulong)dstBaseOffset, dstSize).ToArray(); Span<byte> dstSpan = memoryManager.GetSpan(dstGpuVa + (ulong)dstBaseOffset, dstSize).ToArray();
TextureParams srcParams = new TextureParams(srcRegionX, srcRegionY, srcBaseOffset, srcBpp, srcLinear, srcCalculator); TextureParams srcParams = new(srcRegionX, srcRegionY, srcBaseOffset, srcBpp, srcLinear, srcCalculator);
TextureParams dstParams = new TextureParams(dstRegionX, dstRegionY, dstBaseOffset, dstBpp, dstLinear, dstCalculator); TextureParams dstParams = new(dstRegionX, dstRegionY, dstBaseOffset, dstBpp, dstLinear, dstCalculator);
// If remapping is enabled, we always copy the components directly, in order. // If remapping is enabled, we always copy the components directly, in order.
// If it's enabled, but the mapping is just XYZW, we also copy them in order. // If it's enabled, but the mapping is just XYZW, we also copy them in order.
@@ -363,13 +363,26 @@ namespace Ryujinx.Graphics.Gpu.Engine.Dma
switch (srcBpp) switch (srcBpp)
{ {
case 1: Copy<byte>(dstSpan, srcSpan, dstParams, srcParams); break; case 1:
case 2: Copy<ushort>(dstSpan, srcSpan, dstParams, srcParams); break; Copy<byte>(dstSpan, srcSpan, dstParams, srcParams);
case 4: Copy<uint>(dstSpan, srcSpan, dstParams, srcParams); break; break;
case 8: Copy<ulong>(dstSpan, srcSpan, dstParams, srcParams); break; case 2:
case 12: Copy<Bpp12Pixel>(dstSpan, srcSpan, dstParams, srcParams); break; Copy<ushort>(dstSpan, srcSpan, dstParams, srcParams);
case 16: Copy<Vector128<byte>>(dstSpan, srcSpan, dstParams, srcParams); break; break;
default: throw new NotSupportedException($"Unable to copy ${srcBpp} bpp pixel format."); case 4:
Copy<uint>(dstSpan, srcSpan, dstParams, srcParams);
break;
case 8:
Copy<ulong>(dstSpan, srcSpan, dstParams, srcParams);
break;
case 12:
Copy<Bpp12Pixel>(dstSpan, srcSpan, dstParams, srcParams);
break;
case 16:
Copy<Vector128<byte>>(dstSpan, srcSpan, dstParams, srcParams);
break;
default:
throw new NotSupportedException($"Unable to copy ${srcBpp} bpp pixel format.");
} }
} }
else else
@@ -378,11 +391,20 @@ namespace Ryujinx.Graphics.Gpu.Engine.Dma
switch (componentSize) switch (componentSize)
{ {
case 1: CopyShuffle<byte>(dstSpan, srcSpan, dstParams, srcParams); break; case 1:
case 2: CopyShuffle<ushort>(dstSpan, srcSpan, dstParams, srcParams); break; CopyShuffle<byte>(dstSpan, srcSpan, dstParams, srcParams);
case 3: CopyShuffle<UInt24>(dstSpan, srcSpan, dstParams, srcParams); break; break;
case 4: CopyShuffle<uint>(dstSpan, srcSpan, dstParams, srcParams); break; case 2:
default: throw new NotSupportedException($"Unable to copy ${componentSize} component size."); CopyShuffle<ushort>(dstSpan, srcSpan, dstParams, srcParams);
break;
case 3:
CopyShuffle<UInt24>(dstSpan, srcSpan, dstParams, srcParams);
break;
case 4:
CopyShuffle<uint>(dstSpan, srcSpan, dstParams, srcParams);
break;
default:
throw new NotSupportedException($"Unable to copy ${componentSize} component size.");
} }
} }
@@ -526,28 +548,28 @@ namespace Ryujinx.Graphics.Gpu.Engine.Dma
0 => _state.State.SetRemapComponentsDstX, 0 => _state.State.SetRemapComponentsDstX,
1 => _state.State.SetRemapComponentsDstY, 1 => _state.State.SetRemapComponentsDstY,
2 => _state.State.SetRemapComponentsDstZ, 2 => _state.State.SetRemapComponentsDstZ,
_ => _state.State.SetRemapComponentsDstW _ => _state.State.SetRemapComponentsDstW,
}; };
switch (componentsDst) switch (componentsDst)
{ {
case SetRemapComponentsDst.SrcX: case SetRemapComponentsDst.SrcX:
Copy<T>(dstSpan.Slice(Unsafe.SizeOf<T>() * i), srcSpan, dst, src); Copy<T>(dstSpan[(Unsafe.SizeOf<T>() * i)..], srcSpan, dst, src);
break; break;
case SetRemapComponentsDst.SrcY: case SetRemapComponentsDst.SrcY:
Copy<T>(dstSpan.Slice(Unsafe.SizeOf<T>() * i), srcSpan.Slice(Unsafe.SizeOf<T>()), dst, src); Copy<T>(dstSpan[(Unsafe.SizeOf<T>() * i)..], srcSpan[Unsafe.SizeOf<T>()..], dst, src);
break; break;
case SetRemapComponentsDst.SrcZ: case SetRemapComponentsDst.SrcZ:
Copy<T>(dstSpan.Slice(Unsafe.SizeOf<T>() * i), srcSpan.Slice(Unsafe.SizeOf<T>() * 2), dst, src); Copy<T>(dstSpan[(Unsafe.SizeOf<T>() * i)..], srcSpan[(Unsafe.SizeOf<T>() * 2)..], dst, src);
break; break;
case SetRemapComponentsDst.SrcW: case SetRemapComponentsDst.SrcW:
Copy<T>(dstSpan.Slice(Unsafe.SizeOf<T>() * i), srcSpan.Slice(Unsafe.SizeOf<T>() * 3), dst, src); Copy<T>(dstSpan[(Unsafe.SizeOf<T>() * i)..], srcSpan[(Unsafe.SizeOf<T>() * 3)..], dst, src);
break; break;
case SetRemapComponentsDst.ConstA: case SetRemapComponentsDst.ConstA:
Fill<T>(dstSpan.Slice(Unsafe.SizeOf<T>() * i), dst, Unsafe.As<uint, T>(ref _state.State.SetRemapConstA)); Fill<T>(dstSpan[(Unsafe.SizeOf<T>() * i)..], dst, Unsafe.As<uint, T>(ref _state.State.SetRemapConstA));
break; break;
case SetRemapComponentsDst.ConstB: case SetRemapComponentsDst.ConstB:
Fill<T>(dstSpan.Slice(Unsafe.SizeOf<T>() * i), dst, Unsafe.As<uint, T>(ref _state.State.SetRemapConstB)); Fill<T>(dstSpan[(Unsafe.SizeOf<T>() * i)..], dst, Unsafe.As<uint, T>(ref _state.State.SetRemapConstB));
break; break;
} }
} }

Some files were not shown because too many files have changed in this diff Show More