Compare commits
10 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
4cf2419e6c | ||
|
440abac9f8 | ||
|
732714349e | ||
|
016262514d | ||
|
326749498b | ||
|
fec8291c17 | ||
|
c5d9e67cb2 | ||
|
e5261228d7 | ||
|
e61c09bc85 | ||
|
ac2444f908 |
8
.github/assign/audio.yml
vendored
8
.github/assign/audio.yml
vendored
@@ -1,8 +0,0 @@
|
||||
addReviewers: true
|
||||
|
||||
reviewers:
|
||||
- marysaka
|
||||
|
||||
filterLabels:
|
||||
include:
|
||||
- audio
|
11
.github/assign/cpu.yml
vendored
11
.github/assign/cpu.yml
vendored
@@ -1,11 +0,0 @@
|
||||
addReviewers: true
|
||||
|
||||
reviewers:
|
||||
- gdkchan
|
||||
- riperiperi
|
||||
- marysaka
|
||||
- LDj3SNuD
|
||||
|
||||
filterLabels:
|
||||
include:
|
||||
- cpu
|
4
.github/assign/global.yml
vendored
4
.github/assign/global.yml
vendored
@@ -1,4 +0,0 @@
|
||||
addReviewers: true
|
||||
|
||||
reviewers:
|
||||
- Ryujinx/developers
|
10
.github/assign/gpu.yml
vendored
10
.github/assign/gpu.yml
vendored
@@ -1,10 +0,0 @@
|
||||
addReviewers: true
|
||||
|
||||
reviewers:
|
||||
- gdkchan
|
||||
- riperiperi
|
||||
- marysaka
|
||||
|
||||
filterLabels:
|
||||
include:
|
||||
- gpu
|
11
.github/assign/gui.yml
vendored
11
.github/assign/gui.yml
vendored
@@ -1,11 +0,0 @@
|
||||
addReviewers: true
|
||||
|
||||
reviewers:
|
||||
- Ack77
|
||||
- emmauss
|
||||
- TSRBerry
|
||||
- marysaka
|
||||
|
||||
filterLabels:
|
||||
include:
|
||||
- gui
|
11
.github/assign/horizon.yml
vendored
11
.github/assign/horizon.yml
vendored
@@ -1,11 +0,0 @@
|
||||
addReviewers: true
|
||||
|
||||
reviewers:
|
||||
- gdkchan
|
||||
- Ack77
|
||||
- marysaka
|
||||
- TSRBerry
|
||||
|
||||
filterLabels:
|
||||
include:
|
||||
- horizon
|
9
.github/assign/infra.yml
vendored
9
.github/assign/infra.yml
vendored
@@ -1,9 +0,0 @@
|
||||
addReviewers: true
|
||||
|
||||
reviewers:
|
||||
- marysaka
|
||||
- TSRBerry
|
||||
|
||||
filterLabels:
|
||||
include:
|
||||
- infra
|
32
.github/reviewers.yml
vendored
Normal file
32
.github/reviewers.yml
vendored
Normal 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
79
.github/update_reviewers.py
vendored
Normal 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))
|
48
.github/workflows/pr_triage.yml
vendored
48
.github/workflows/pr_triage.yml
vendored
@@ -12,43 +12,23 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
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
|
||||
uses: actions/labeler@v4
|
||||
with:
|
||||
sync-labels: true
|
||||
dot: true
|
||||
|
||||
- name: Auto Assign [Audio]
|
||||
uses: kentaro-m/auto-assign-action@v1.2.5
|
||||
with:
|
||||
configuration-path: '.github/assign/audio.yml'
|
||||
|
||||
- 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'
|
||||
- name: Assign reviewers
|
||||
run: |
|
||||
pip3 install PyGithub
|
||||
python3 .github/update_reviewers.py ${{ secrets.GITHUB_TOKEN }} ${{ github.repository }} ${{ github.event.pull_request.number }} .github/reviewers.yml
|
||||
shell: bash
|
||||
|
@@ -34,7 +34,7 @@
|
||||
<PackageVersion Include="Ryujinx.Graphics.Nvdec.Dependencies" Version="5.0.1-build13" />
|
||||
<PackageVersion Include="Ryujinx.Graphics.Vulkan.Dependencies.MoltenVK" Version="1.2.0" />
|
||||
<PackageVersion Include="Ryujinx.GtkSharp" Version="3.24.24.59-ryujinx" />
|
||||
<PackageVersion Include="Ryujinx.SDL2-CS" Version="2.26.3-build25" />
|
||||
<PackageVersion Include="Ryujinx.SDL2-CS" Version="2.28.1-build28" />
|
||||
<PackageVersion Include="shaderc.net" Version="0.1.0" />
|
||||
<PackageVersion Include="SharpZipLib" Version="1.4.2" />
|
||||
<PackageVersion Include="Silk.NET.Vulkan" Version="2.16.0" />
|
||||
|
@@ -1448,6 +1448,7 @@ namespace ARMeilleure.Instructions
|
||||
{
|
||||
var overflowToInf = fpcr.GetRoundingMode() switch
|
||||
{
|
||||
FPRoundingMode.ToNearest => true,
|
||||
FPRoundingMode.TowardsPlusInfinity => !sign,
|
||||
FPRoundingMode.TowardsMinusInfinity => sign,
|
||||
FPRoundingMode.TowardsZero => false,
|
||||
@@ -2879,6 +2880,7 @@ namespace ARMeilleure.Instructions
|
||||
{
|
||||
var overflowToInf = fpcr.GetRoundingMode() switch
|
||||
{
|
||||
FPRoundingMode.ToNearest => true,
|
||||
FPRoundingMode.TowardsPlusInfinity => !sign,
|
||||
FPRoundingMode.TowardsMinusInfinity => sign,
|
||||
FPRoundingMode.TowardsZero => false,
|
||||
|
@@ -114,7 +114,7 @@ namespace Ryujinx.Ava.Common
|
||||
|
||||
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))
|
||||
{
|
||||
|
@@ -2,6 +2,7 @@ using LibHac.Fs;
|
||||
using LibHac.Ncm;
|
||||
using Ryujinx.Ava.UI.ViewModels;
|
||||
using Ryujinx.Ava.UI.Windows;
|
||||
using Ryujinx.HLE.FileSystem;
|
||||
using Ryujinx.Ui.App.Common;
|
||||
using System;
|
||||
using System.IO;
|
||||
@@ -81,7 +82,7 @@ namespace Ryujinx.Ava.UI.Models
|
||||
|
||||
Task.Run(() =>
|
||||
{
|
||||
var saveRoot = Path.Combine(MainWindow.MainWindowViewModel.VirtualFileSystem.GetNandPath(), $"user/save/{info.SaveDataId:x16}");
|
||||
var saveRoot = Path.Combine(VirtualFileSystem.GetNandPath(), $"user/save/{info.SaveDataId:x16}");
|
||||
|
||||
long totalSize = GetDirectorySize(saveRoot);
|
||||
|
||||
|
@@ -105,7 +105,7 @@ namespace Ryujinx.Ava.UI.ViewModels
|
||||
}
|
||||
|
||||
string contentPath = contentManager.GetInstalledContentPath(0x010000000000080A, StorageId.BuiltInSystem, NcaContentType.Data);
|
||||
string avatarPath = virtualFileSystem.SwitchPathToSystemPath(contentPath);
|
||||
string avatarPath = VirtualFileSystem.SwitchPathToSystemPath(contentPath);
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(avatarPath))
|
||||
{
|
||||
|
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.Diagnostics.Contracts;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
#pragma warning disable CS0169, IDE0051 // Remove unused private member
|
||||
@@ -9,6 +10,8 @@ namespace Ryujinx.Common.Memory
|
||||
T _e0;
|
||||
public readonly int Length => 1;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
|
||||
[Pure]
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
@@ -18,6 +21,8 @@ namespace Ryujinx.Common.Memory
|
||||
Array1<T> _other;
|
||||
public readonly int Length => 2;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
|
||||
[Pure]
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
@@ -27,6 +32,8 @@ namespace Ryujinx.Common.Memory
|
||||
Array2<T> _other;
|
||||
public readonly int Length => 3;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
|
||||
[Pure]
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
@@ -36,6 +43,8 @@ namespace Ryujinx.Common.Memory
|
||||
Array3<T> _other;
|
||||
public readonly int Length => 4;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
|
||||
[Pure]
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
@@ -45,6 +54,8 @@ namespace Ryujinx.Common.Memory
|
||||
Array4<T> _other;
|
||||
public readonly int Length => 5;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
|
||||
[Pure]
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
@@ -54,6 +65,8 @@ namespace Ryujinx.Common.Memory
|
||||
Array5<T> _other;
|
||||
public readonly int Length => 6;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
|
||||
[Pure]
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
@@ -63,6 +76,8 @@ namespace Ryujinx.Common.Memory
|
||||
Array6<T> _other;
|
||||
public readonly int Length => 7;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
|
||||
[Pure]
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
@@ -72,6 +87,8 @@ namespace Ryujinx.Common.Memory
|
||||
Array7<T> _other;
|
||||
public readonly int Length => 8;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
|
||||
[Pure]
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
@@ -81,6 +98,8 @@ namespace Ryujinx.Common.Memory
|
||||
Array8<T> _other;
|
||||
public readonly int Length => 9;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
|
||||
[Pure]
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
@@ -90,6 +109,8 @@ namespace Ryujinx.Common.Memory
|
||||
Array9<T> _other;
|
||||
public readonly int Length => 10;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
|
||||
[Pure]
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
@@ -99,6 +120,8 @@ namespace Ryujinx.Common.Memory
|
||||
Array10<T> _other;
|
||||
public readonly int Length => 11;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
|
||||
[Pure]
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
@@ -108,6 +131,8 @@ namespace Ryujinx.Common.Memory
|
||||
Array11<T> _other;
|
||||
public readonly int Length => 12;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
|
||||
[Pure]
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
@@ -117,6 +142,8 @@ namespace Ryujinx.Common.Memory
|
||||
Array12<T> _other;
|
||||
public readonly int Length => 13;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
|
||||
[Pure]
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
@@ -126,6 +153,8 @@ namespace Ryujinx.Common.Memory
|
||||
Array13<T> _other;
|
||||
public readonly int Length => 14;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
|
||||
[Pure]
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
@@ -135,6 +164,8 @@ namespace Ryujinx.Common.Memory
|
||||
Array14<T> _other;
|
||||
public readonly int Length => 15;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
|
||||
[Pure]
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
@@ -144,6 +175,8 @@ namespace Ryujinx.Common.Memory
|
||||
Array15<T> _other;
|
||||
public readonly int Length => 16;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
|
||||
[Pure]
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
@@ -153,6 +186,8 @@ namespace Ryujinx.Common.Memory
|
||||
Array16<T> _other;
|
||||
public readonly int Length => 17;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
|
||||
[Pure]
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
@@ -162,6 +197,8 @@ namespace Ryujinx.Common.Memory
|
||||
Array17<T> _other;
|
||||
public readonly int Length => 18;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
|
||||
[Pure]
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
@@ -171,6 +208,8 @@ namespace Ryujinx.Common.Memory
|
||||
Array18<T> _other;
|
||||
public readonly int Length => 19;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
|
||||
[Pure]
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
@@ -180,6 +219,8 @@ namespace Ryujinx.Common.Memory
|
||||
Array19<T> _other;
|
||||
public readonly int Length => 20;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
|
||||
[Pure]
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
@@ -189,6 +230,8 @@ namespace Ryujinx.Common.Memory
|
||||
Array20<T> _other;
|
||||
public readonly int Length => 21;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
|
||||
[Pure]
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
@@ -198,6 +241,8 @@ namespace Ryujinx.Common.Memory
|
||||
Array21<T> _other;
|
||||
public readonly int Length => 22;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
|
||||
[Pure]
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
@@ -207,6 +252,8 @@ namespace Ryujinx.Common.Memory
|
||||
Array22<T> _other;
|
||||
public readonly int Length => 23;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
|
||||
[Pure]
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
@@ -217,6 +264,8 @@ namespace Ryujinx.Common.Memory
|
||||
|
||||
public readonly int Length => 24;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
|
||||
[Pure]
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
@@ -227,6 +276,8 @@ namespace Ryujinx.Common.Memory
|
||||
|
||||
public readonly int Length => 25;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
|
||||
[Pure]
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
@@ -237,6 +288,8 @@ namespace Ryujinx.Common.Memory
|
||||
|
||||
public readonly int Length => 26;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
|
||||
[Pure]
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
@@ -247,6 +300,8 @@ namespace Ryujinx.Common.Memory
|
||||
|
||||
public readonly int Length => 27;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
|
||||
[Pure]
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
@@ -257,6 +312,8 @@ namespace Ryujinx.Common.Memory
|
||||
|
||||
public readonly int Length => 28;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
|
||||
[Pure]
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
@@ -267,6 +324,8 @@ namespace Ryujinx.Common.Memory
|
||||
|
||||
public readonly int Length => 29;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
|
||||
[Pure]
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
@@ -277,6 +336,8 @@ namespace Ryujinx.Common.Memory
|
||||
|
||||
public readonly int Length => 30;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
|
||||
[Pure]
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
@@ -287,6 +348,8 @@ namespace Ryujinx.Common.Memory
|
||||
|
||||
public readonly int Length => 31;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
|
||||
[Pure]
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
@@ -297,6 +360,8 @@ namespace Ryujinx.Common.Memory
|
||||
|
||||
public readonly int Length => 32;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
|
||||
[Pure]
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
@@ -307,6 +372,8 @@ namespace Ryujinx.Common.Memory
|
||||
|
||||
public readonly int Length => 33;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
|
||||
[Pure]
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
@@ -317,6 +384,8 @@ namespace Ryujinx.Common.Memory
|
||||
|
||||
public readonly int Length => 34;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
|
||||
[Pure]
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
@@ -327,6 +396,8 @@ namespace Ryujinx.Common.Memory
|
||||
|
||||
public readonly int Length => 35;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
|
||||
[Pure]
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
@@ -337,6 +408,8 @@ namespace Ryujinx.Common.Memory
|
||||
|
||||
public readonly int Length => 36;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
|
||||
[Pure]
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
@@ -347,6 +420,8 @@ namespace Ryujinx.Common.Memory
|
||||
|
||||
public readonly int Length => 37;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
|
||||
[Pure]
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
@@ -357,6 +432,8 @@ namespace Ryujinx.Common.Memory
|
||||
|
||||
public readonly int Length => 38;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
|
||||
[Pure]
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
@@ -367,6 +444,8 @@ namespace Ryujinx.Common.Memory
|
||||
|
||||
public readonly int Length => 39;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
|
||||
[Pure]
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
@@ -377,6 +456,8 @@ namespace Ryujinx.Common.Memory
|
||||
|
||||
public readonly int Length => 40;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
|
||||
[Pure]
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
@@ -387,6 +468,8 @@ namespace Ryujinx.Common.Memory
|
||||
|
||||
public readonly int Length => 41;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
|
||||
[Pure]
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
@@ -397,6 +480,8 @@ namespace Ryujinx.Common.Memory
|
||||
|
||||
public readonly int Length => 42;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
|
||||
[Pure]
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
@@ -407,6 +492,8 @@ namespace Ryujinx.Common.Memory
|
||||
|
||||
public readonly int Length => 43;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
|
||||
[Pure]
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
@@ -417,6 +504,8 @@ namespace Ryujinx.Common.Memory
|
||||
|
||||
public readonly int Length => 44;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
|
||||
[Pure]
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
@@ -427,6 +516,8 @@ namespace Ryujinx.Common.Memory
|
||||
|
||||
public readonly int Length => 45;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
|
||||
[Pure]
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
@@ -437,6 +528,8 @@ namespace Ryujinx.Common.Memory
|
||||
|
||||
public readonly int Length => 46;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
|
||||
[Pure]
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
@@ -447,6 +540,8 @@ namespace Ryujinx.Common.Memory
|
||||
|
||||
public readonly int Length => 47;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
|
||||
[Pure]
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
@@ -457,6 +552,8 @@ namespace Ryujinx.Common.Memory
|
||||
|
||||
public readonly int Length => 48;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
|
||||
[Pure]
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
@@ -467,6 +564,8 @@ namespace Ryujinx.Common.Memory
|
||||
|
||||
public readonly int Length => 49;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
|
||||
[Pure]
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
@@ -477,6 +576,8 @@ namespace Ryujinx.Common.Memory
|
||||
|
||||
public readonly int Length => 50;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
|
||||
[Pure]
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
@@ -487,6 +588,8 @@ namespace Ryujinx.Common.Memory
|
||||
|
||||
public readonly int Length => 51;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
|
||||
[Pure]
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
@@ -497,6 +600,8 @@ namespace Ryujinx.Common.Memory
|
||||
|
||||
public readonly int Length => 52;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
|
||||
[Pure]
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
@@ -507,6 +612,8 @@ namespace Ryujinx.Common.Memory
|
||||
|
||||
public readonly int Length => 53;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
|
||||
[Pure]
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
@@ -517,6 +624,8 @@ namespace Ryujinx.Common.Memory
|
||||
|
||||
public readonly int Length => 54;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
|
||||
[Pure]
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
@@ -527,6 +636,8 @@ namespace Ryujinx.Common.Memory
|
||||
|
||||
public readonly int Length => 55;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
|
||||
[Pure]
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
@@ -537,6 +648,8 @@ namespace Ryujinx.Common.Memory
|
||||
|
||||
public readonly int Length => 56;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
|
||||
[Pure]
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
@@ -547,6 +660,8 @@ namespace Ryujinx.Common.Memory
|
||||
|
||||
public readonly int Length => 57;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
|
||||
[Pure]
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
@@ -557,6 +672,8 @@ namespace Ryujinx.Common.Memory
|
||||
|
||||
public readonly int Length => 58;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
|
||||
[Pure]
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
@@ -567,6 +684,8 @@ namespace Ryujinx.Common.Memory
|
||||
|
||||
public readonly int Length => 59;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
|
||||
[Pure]
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
@@ -576,6 +695,8 @@ namespace Ryujinx.Common.Memory
|
||||
Array59<T> _other;
|
||||
public readonly int Length => 60;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
|
||||
[Pure]
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
@@ -585,6 +706,8 @@ namespace Ryujinx.Common.Memory
|
||||
Array60<T> _other;
|
||||
public readonly int Length => 61;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
|
||||
[Pure]
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
@@ -594,6 +717,8 @@ namespace Ryujinx.Common.Memory
|
||||
Array61<T> _other;
|
||||
public readonly int Length => 62;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
|
||||
[Pure]
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
@@ -603,6 +728,8 @@ namespace Ryujinx.Common.Memory
|
||||
Array62<T> _other;
|
||||
public readonly int Length => 63;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
|
||||
[Pure]
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
@@ -612,6 +739,8 @@ namespace Ryujinx.Common.Memory
|
||||
Array63<T> _other;
|
||||
public readonly int Length => 64;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
|
||||
[Pure]
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
@@ -622,6 +751,8 @@ namespace Ryujinx.Common.Memory
|
||||
Array8<T> _other2;
|
||||
public readonly int Length => 73;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
|
||||
[Pure]
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
@@ -632,6 +763,8 @@ namespace Ryujinx.Common.Memory
|
||||
Array62<T> _other2;
|
||||
public readonly int Length => 127;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
|
||||
[Pure]
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
@@ -642,6 +775,8 @@ namespace Ryujinx.Common.Memory
|
||||
Array63<T> _other2;
|
||||
public readonly int Length => 128;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
|
||||
[Pure]
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
@@ -652,6 +787,8 @@ namespace Ryujinx.Common.Memory
|
||||
Array127<T> _other2;
|
||||
public readonly int Length => 256;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
|
||||
[Pure]
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
}
|
||||
|
@@ -168,6 +168,16 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
return ComponentType.Float;
|
||||
}
|
||||
|
||||
public ImageAspectFlags GetDepthStencilAspectFlags()
|
||||
{
|
||||
if (_depthStencil == null)
|
||||
{
|
||||
return ImageAspectFlags.None;
|
||||
}
|
||||
|
||||
return _depthStencil.Info.Format.ConvertAspectFlags();
|
||||
}
|
||||
|
||||
public bool IsValidColorAttachment(int bindIndex)
|
||||
{
|
||||
return (uint)bindIndex < Constants.MaxRenderTargets && (_validColorAttachments & (1u << bindIndex)) != 0;
|
||||
@@ -226,7 +236,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
|
||||
_depthStencil?.Storage.SetModification(
|
||||
AccessFlags.DepthStencilAttachmentWriteBit,
|
||||
PipelineStageFlags.ColorAttachmentOutputBit);
|
||||
PipelineStageFlags.LateFragmentTestsBit);
|
||||
}
|
||||
|
||||
public void InsertClearBarrier(CommandBufferScoped cbs, int index)
|
||||
|
@@ -1,10 +1,11 @@
|
||||
using Ryujinx.Graphics.GAL;
|
||||
using Ryujinx.Common;
|
||||
using Ryujinx.Graphics.GAL;
|
||||
using Ryujinx.Graphics.Shader;
|
||||
using Ryujinx.Graphics.Shader.Translation;
|
||||
using Ryujinx.Graphics.Vulkan.Shaders;
|
||||
using Silk.NET.Vulkan;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Numerics;
|
||||
using CompareOp = Ryujinx.Graphics.GAL.CompareOp;
|
||||
using Format = Ryujinx.Graphics.GAL.Format;
|
||||
@@ -26,6 +27,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
class HelperShader : IDisposable
|
||||
{
|
||||
private const int UniformBufferAlignment = 256;
|
||||
private const string ShaderBinariesPath = "Ryujinx.Graphics.Vulkan/Shaders/SpirvBinaries";
|
||||
|
||||
private readonly PipelineHelperShader _pipeline;
|
||||
private readonly ISampler _samplerLinear;
|
||||
@@ -67,40 +69,40 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
|
||||
_programColorBlit = gd.CreateProgramWithMinimalLayout(new[]
|
||||
{
|
||||
new ShaderSource(ShaderBinaries.ColorBlitVertexShaderSource, ShaderStage.Vertex, TargetLanguage.Spirv),
|
||||
new ShaderSource(ShaderBinaries.ColorBlitFragmentShaderSource, ShaderStage.Fragment, TargetLanguage.Spirv),
|
||||
new ShaderSource(ReadSpirv("ColorBlitVertex.spv"), ShaderStage.Vertex, TargetLanguage.Spirv),
|
||||
new ShaderSource(ReadSpirv("ColorBlitFragment.spv"), ShaderStage.Fragment, TargetLanguage.Spirv),
|
||||
}, blitResourceLayout);
|
||||
|
||||
_programColorBlitMs = gd.CreateProgramWithMinimalLayout(new[]
|
||||
{
|
||||
new ShaderSource(ShaderBinaries.ColorBlitVertexShaderSource, ShaderStage.Vertex, TargetLanguage.Spirv),
|
||||
new ShaderSource(ShaderBinaries.ColorBlitMsFragmentShaderSource, ShaderStage.Fragment, TargetLanguage.Spirv),
|
||||
new ShaderSource(ReadSpirv("ColorBlitVertex.spv"), ShaderStage.Vertex, TargetLanguage.Spirv),
|
||||
new ShaderSource(ReadSpirv("ColorBlitMsFragment.spv"), ShaderStage.Fragment, TargetLanguage.Spirv),
|
||||
}, blitResourceLayout);
|
||||
|
||||
_programColorBlitClearAlpha = gd.CreateProgramWithMinimalLayout(new[]
|
||||
{
|
||||
new ShaderSource(ShaderBinaries.ColorBlitVertexShaderSource, ShaderStage.Vertex, TargetLanguage.Spirv),
|
||||
new ShaderSource(ShaderBinaries.ColorBlitClearAlphaFragmentShaderSource, ShaderStage.Fragment, TargetLanguage.Spirv),
|
||||
new ShaderSource(ReadSpirv("ColorBlitVertex.spv"), ShaderStage.Vertex, TargetLanguage.Spirv),
|
||||
new ShaderSource(ReadSpirv("ColorBlitClearAlphaFragment.spv"), ShaderStage.Fragment, TargetLanguage.Spirv),
|
||||
}, blitResourceLayout);
|
||||
|
||||
var colorClearResourceLayout = new ResourceLayoutBuilder().Add(ResourceStages.Vertex, ResourceType.UniformBuffer, 1).Build();
|
||||
|
||||
_programColorClearF = gd.CreateProgramWithMinimalLayout(new[]
|
||||
{
|
||||
new ShaderSource(ShaderBinaries.ColorClearVertexShaderSource, ShaderStage.Vertex, TargetLanguage.Spirv),
|
||||
new ShaderSource(ShaderBinaries.ColorClearFFragmentShaderSource, ShaderStage.Fragment, TargetLanguage.Spirv),
|
||||
new ShaderSource(ReadSpirv("ColorClearVertex.spv"), ShaderStage.Vertex, TargetLanguage.Spirv),
|
||||
new ShaderSource(ReadSpirv("ColorClearFFragment.spv"), ShaderStage.Fragment, TargetLanguage.Spirv),
|
||||
}, colorClearResourceLayout);
|
||||
|
||||
_programColorClearSI = gd.CreateProgramWithMinimalLayout(new[]
|
||||
{
|
||||
new ShaderSource(ShaderBinaries.ColorClearVertexShaderSource, ShaderStage.Vertex, TargetLanguage.Spirv),
|
||||
new ShaderSource(ShaderBinaries.ColorClearSIFragmentShaderSource, ShaderStage.Fragment, TargetLanguage.Spirv),
|
||||
new ShaderSource(ReadSpirv("ColorClearVertex.spv"), ShaderStage.Vertex, TargetLanguage.Spirv),
|
||||
new ShaderSource(ReadSpirv("ColorClearSIFragment.spv"), ShaderStage.Fragment, TargetLanguage.Spirv),
|
||||
}, colorClearResourceLayout);
|
||||
|
||||
_programColorClearUI = gd.CreateProgramWithMinimalLayout(new[]
|
||||
{
|
||||
new ShaderSource(ShaderBinaries.ColorClearVertexShaderSource, ShaderStage.Vertex, TargetLanguage.Spirv),
|
||||
new ShaderSource(ShaderBinaries.ColorClearUIFragmentShaderSource, ShaderStage.Fragment, TargetLanguage.Spirv),
|
||||
new ShaderSource(ReadSpirv("ColorClearVertex.spv"), ShaderStage.Vertex, TargetLanguage.Spirv),
|
||||
new ShaderSource(ReadSpirv("ColorClearUIFragment.spv"), ShaderStage.Fragment, TargetLanguage.Spirv),
|
||||
}, colorClearResourceLayout);
|
||||
|
||||
var strideChangeResourceLayout = new ResourceLayoutBuilder()
|
||||
@@ -110,7 +112,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
|
||||
_programStrideChange = gd.CreateProgramWithMinimalLayout(new[]
|
||||
{
|
||||
new ShaderSource(ShaderBinaries.ChangeBufferStrideShaderSource, ShaderStage.Compute, TargetLanguage.Spirv),
|
||||
new ShaderSource(ReadSpirv("ChangeBufferStride.spv"), ShaderStage.Compute, TargetLanguage.Spirv),
|
||||
}, strideChangeResourceLayout);
|
||||
|
||||
var colorCopyResourceLayout = new ResourceLayoutBuilder()
|
||||
@@ -120,17 +122,17 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
|
||||
_programColorCopyShortening = gd.CreateProgramWithMinimalLayout(new[]
|
||||
{
|
||||
new ShaderSource(ShaderBinaries.ColorCopyShorteningComputeShaderSource, ShaderStage.Compute, TargetLanguage.Spirv),
|
||||
new ShaderSource(ReadSpirv("ColorCopyShorteningCompute.spv"), ShaderStage.Compute, TargetLanguage.Spirv),
|
||||
}, colorCopyResourceLayout);
|
||||
|
||||
_programColorCopyToNonMs = gd.CreateProgramWithMinimalLayout(new[]
|
||||
{
|
||||
new ShaderSource(ShaderBinaries.ColorCopyToNonMsComputeShaderSource, ShaderStage.Compute, TargetLanguage.Spirv),
|
||||
new ShaderSource(ReadSpirv("ColorCopyToNonMsCompute.spv"), ShaderStage.Compute, TargetLanguage.Spirv),
|
||||
}, colorCopyResourceLayout);
|
||||
|
||||
_programColorCopyWidening = gd.CreateProgramWithMinimalLayout(new[]
|
||||
{
|
||||
new ShaderSource(ShaderBinaries.ColorCopyWideningComputeShaderSource, ShaderStage.Compute, TargetLanguage.Spirv),
|
||||
new ShaderSource(ReadSpirv("ColorCopyWideningCompute.spv"), ShaderStage.Compute, TargetLanguage.Spirv),
|
||||
}, colorCopyResourceLayout);
|
||||
|
||||
var colorDrawToMsResourceLayout = new ResourceLayoutBuilder()
|
||||
@@ -139,8 +141,8 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
|
||||
_programColorDrawToMs = gd.CreateProgramWithMinimalLayout(new[]
|
||||
{
|
||||
new ShaderSource(ShaderBinaries.ColorDrawToMsVertexShaderSource, ShaderStage.Vertex, TargetLanguage.Spirv),
|
||||
new ShaderSource(ShaderBinaries.ColorDrawToMsFragmentShaderSource, ShaderStage.Fragment, TargetLanguage.Spirv),
|
||||
new ShaderSource(ReadSpirv("ColorDrawToMsVertex.spv"), ShaderStage.Vertex, TargetLanguage.Spirv),
|
||||
new ShaderSource(ReadSpirv("ColorDrawToMsFragment.spv"), ShaderStage.Fragment, TargetLanguage.Spirv),
|
||||
}, colorDrawToMsResourceLayout);
|
||||
|
||||
var convertD32S8ToD24S8ResourceLayout = new ResourceLayoutBuilder()
|
||||
@@ -150,7 +152,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
|
||||
_programConvertD32S8ToD24S8 = gd.CreateProgramWithMinimalLayout(new[]
|
||||
{
|
||||
new ShaderSource(ShaderBinaries.ConvertD32S8ToD24S8ShaderSource, ShaderStage.Compute, TargetLanguage.Spirv),
|
||||
new ShaderSource(ReadSpirv("ConvertD32S8ToD24S8.spv"), ShaderStage.Compute, TargetLanguage.Spirv),
|
||||
}, convertD32S8ToD24S8ResourceLayout);
|
||||
|
||||
var convertIndexBufferResourceLayout = new ResourceLayoutBuilder()
|
||||
@@ -160,7 +162,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
|
||||
_programConvertIndexBuffer = gd.CreateProgramWithMinimalLayout(new[]
|
||||
{
|
||||
new ShaderSource(ShaderBinaries.ConvertIndexBufferShaderSource, ShaderStage.Compute, TargetLanguage.Spirv),
|
||||
new ShaderSource(ReadSpirv("ConvertIndexBuffer.spv"), ShaderStage.Compute, TargetLanguage.Spirv),
|
||||
}, convertIndexBufferResourceLayout);
|
||||
|
||||
var convertIndirectDataResourceLayout = new ResourceLayoutBuilder()
|
||||
@@ -171,61 +173,66 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
|
||||
_programConvertIndirectData = gd.CreateProgramWithMinimalLayout(new[]
|
||||
{
|
||||
new ShaderSource(ShaderBinaries.ConvertIndirectDataShaderSource, ShaderStage.Compute, TargetLanguage.Spirv),
|
||||
new ShaderSource(ReadSpirv("ConvertIndirectData.spv"), ShaderStage.Compute, TargetLanguage.Spirv),
|
||||
}, convertIndirectDataResourceLayout);
|
||||
|
||||
_programDepthBlit = gd.CreateProgramWithMinimalLayout(new[]
|
||||
{
|
||||
new ShaderSource(ShaderBinaries.ColorBlitVertexShaderSource, ShaderStage.Vertex, TargetLanguage.Spirv),
|
||||
new ShaderSource(ShaderBinaries.DepthBlitFragmentShaderSource, ShaderStage.Fragment, TargetLanguage.Spirv),
|
||||
new ShaderSource(ReadSpirv("ColorBlitVertex.spv"), ShaderStage.Vertex, TargetLanguage.Spirv),
|
||||
new ShaderSource(ReadSpirv("DepthBlitFragment.spv"), ShaderStage.Fragment, TargetLanguage.Spirv),
|
||||
}, blitResourceLayout);
|
||||
|
||||
_programDepthBlitMs = gd.CreateProgramWithMinimalLayout(new[]
|
||||
{
|
||||
new ShaderSource(ShaderBinaries.ColorBlitVertexShaderSource, ShaderStage.Vertex, TargetLanguage.Spirv),
|
||||
new ShaderSource(ShaderBinaries.DepthBlitMsFragmentShaderSource, ShaderStage.Fragment, TargetLanguage.Spirv),
|
||||
new ShaderSource(ReadSpirv("ColorBlitVertex.spv"), ShaderStage.Vertex, TargetLanguage.Spirv),
|
||||
new ShaderSource(ReadSpirv("DepthBlitMsFragment.spv"), ShaderStage.Fragment, TargetLanguage.Spirv),
|
||||
}, blitResourceLayout);
|
||||
|
||||
_programDepthDrawToMs = gd.CreateProgramWithMinimalLayout(new[]
|
||||
{
|
||||
new ShaderSource(ShaderBinaries.ColorDrawToMsVertexShaderSource, ShaderStage.Vertex, TargetLanguage.Spirv),
|
||||
new ShaderSource(ShaderBinaries.DepthDrawToMsFragmentShaderSource, ShaderStage.Fragment, TargetLanguage.Spirv),
|
||||
new ShaderSource(ReadSpirv("ColorDrawToMsVertex.spv"), ShaderStage.Vertex, TargetLanguage.Spirv),
|
||||
new ShaderSource(ReadSpirv("DepthDrawToMsFragment.spv"), ShaderStage.Fragment, TargetLanguage.Spirv),
|
||||
}, colorDrawToMsResourceLayout);
|
||||
|
||||
_programDepthDrawToNonMs = gd.CreateProgramWithMinimalLayout(new[]
|
||||
{
|
||||
new ShaderSource(ShaderBinaries.ColorDrawToMsVertexShaderSource, ShaderStage.Vertex, TargetLanguage.Spirv),
|
||||
new ShaderSource(ShaderBinaries.DepthDrawToNonMsFragmentShaderSource, ShaderStage.Fragment, TargetLanguage.Spirv),
|
||||
new ShaderSource(ReadSpirv("ColorDrawToMsVertex.spv"), ShaderStage.Vertex, TargetLanguage.Spirv),
|
||||
new ShaderSource(ReadSpirv("DepthDrawToNonMsFragment.spv"), ShaderStage.Fragment, TargetLanguage.Spirv),
|
||||
}, colorDrawToMsResourceLayout);
|
||||
|
||||
if (gd.Capabilities.SupportsShaderStencilExport)
|
||||
{
|
||||
_programStencilBlit = gd.CreateProgramWithMinimalLayout(new[]
|
||||
{
|
||||
new ShaderSource(ShaderBinaries.ColorBlitVertexShaderSource, ShaderStage.Vertex, TargetLanguage.Spirv),
|
||||
new ShaderSource(ShaderBinaries.StencilBlitFragmentShaderSource, ShaderStage.Fragment, TargetLanguage.Spirv),
|
||||
new ShaderSource(ReadSpirv("ColorBlitVertex.spv"), ShaderStage.Vertex, TargetLanguage.Spirv),
|
||||
new ShaderSource(ReadSpirv("StencilBlitFragment.spv"), ShaderStage.Fragment, TargetLanguage.Spirv),
|
||||
}, blitResourceLayout);
|
||||
|
||||
_programStencilBlitMs = gd.CreateProgramWithMinimalLayout(new[]
|
||||
{
|
||||
new ShaderSource(ShaderBinaries.ColorBlitVertexShaderSource, ShaderStage.Vertex, TargetLanguage.Spirv),
|
||||
new ShaderSource(ShaderBinaries.StencilBlitMsFragmentShaderSource, ShaderStage.Fragment, TargetLanguage.Spirv),
|
||||
new ShaderSource(ReadSpirv("ColorBlitVertex.spv"), ShaderStage.Vertex, TargetLanguage.Spirv),
|
||||
new ShaderSource(ReadSpirv("StencilBlitMsFragment.spv"), ShaderStage.Fragment, TargetLanguage.Spirv),
|
||||
}, blitResourceLayout);
|
||||
|
||||
_programStencilDrawToMs = gd.CreateProgramWithMinimalLayout(new[]
|
||||
{
|
||||
new ShaderSource(ShaderBinaries.ColorDrawToMsVertexShaderSource, ShaderStage.Vertex, TargetLanguage.Spirv),
|
||||
new ShaderSource(ShaderBinaries.StencilDrawToMsFragmentShaderSource, ShaderStage.Fragment, TargetLanguage.Spirv),
|
||||
new ShaderSource(ReadSpirv("ColorDrawToMsVertex.spv"), ShaderStage.Vertex, TargetLanguage.Spirv),
|
||||
new ShaderSource(ReadSpirv("StencilDrawToMsFragment.spv"), ShaderStage.Fragment, TargetLanguage.Spirv),
|
||||
}, colorDrawToMsResourceLayout);
|
||||
|
||||
_programStencilDrawToNonMs = gd.CreateProgramWithMinimalLayout(new[]
|
||||
{
|
||||
new ShaderSource(ShaderBinaries.ColorDrawToMsVertexShaderSource, ShaderStage.Vertex, TargetLanguage.Spirv),
|
||||
new ShaderSource(ShaderBinaries.StencilDrawToNonMsFragmentShaderSource, ShaderStage.Fragment, TargetLanguage.Spirv),
|
||||
new ShaderSource(ReadSpirv("ColorDrawToMsVertex.spv"), ShaderStage.Vertex, TargetLanguage.Spirv),
|
||||
new ShaderSource(ReadSpirv("StencilDrawToNonMsFragment.spv"), ShaderStage.Fragment, TargetLanguage.Spirv),
|
||||
}, colorDrawToMsResourceLayout);
|
||||
}
|
||||
}
|
||||
|
||||
private static byte[] ReadSpirv(string fileName)
|
||||
{
|
||||
return EmbeddedResources.Read(string.Join('/', ShaderBinariesPath, fileName));
|
||||
}
|
||||
|
||||
public void Blit(
|
||||
VulkanRenderer gd,
|
||||
TextureView src,
|
||||
|
@@ -152,9 +152,6 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
{
|
||||
if (_buffer == from)
|
||||
{
|
||||
_buffer.DecrementReferenceCount();
|
||||
to.IncrementReferenceCount();
|
||||
|
||||
_buffer = to;
|
||||
}
|
||||
}
|
||||
|
@@ -245,13 +245,28 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
|
||||
public unsafe void ClearRenderTargetDepthStencil(int layer, int layerCount, float depthValue, bool depthMask, int stencilValue, int stencilMask)
|
||||
{
|
||||
// TODO: Use stencilMask (fully)
|
||||
// TODO: Use stencilMask (fully).
|
||||
|
||||
if (FramebufferParams == null || !FramebufferParams.HasDepthStencil)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var clearValue = new ClearValue(null, new ClearDepthStencilValue(depthValue, (uint)stencilValue));
|
||||
var flags = depthMask ? ImageAspectFlags.DepthBit : 0;
|
||||
|
||||
if (stencilMask != 0)
|
||||
{
|
||||
flags |= ImageAspectFlags.StencilBit;
|
||||
}
|
||||
|
||||
flags &= FramebufferParams.GetDepthStencilAspectFlags();
|
||||
|
||||
if (flags == ImageAspectFlags.None)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (_renderPass == null)
|
||||
{
|
||||
CreateRenderPass();
|
||||
@@ -259,14 +274,6 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
|
||||
BeginRenderPass();
|
||||
|
||||
var clearValue = new ClearValue(null, new ClearDepthStencilValue(depthValue, (uint)stencilValue));
|
||||
var flags = depthMask ? ImageAspectFlags.DepthBit : 0;
|
||||
|
||||
if (stencilMask != 0)
|
||||
{
|
||||
flags |= ImageAspectFlags.StencilBit;
|
||||
}
|
||||
|
||||
var attachment = new ClearAttachment(flags, 0, clearValue);
|
||||
var clearRect = FramebufferParams.GetClearRect(ClearScissor, layer, layerCount);
|
||||
|
||||
@@ -935,7 +942,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
|
||||
SignalStateChange();
|
||||
|
||||
if (_program.IsCompute)
|
||||
if (internalProgram.IsCompute)
|
||||
{
|
||||
EndRenderPass();
|
||||
}
|
||||
|
@@ -21,6 +21,31 @@
|
||||
<EmbeddedResource Include="Effects\Shaders\SmaaBlend.spv" />
|
||||
<EmbeddedResource Include="Effects\Shaders\SmaaEdge.spv" />
|
||||
<EmbeddedResource Include="Effects\Shaders\SmaaNeighbour.spv" />
|
||||
<EmbeddedResource Include="Shaders\SpirvBinaries\ChangeBufferStride.spv" />
|
||||
<EmbeddedResource Include="Shaders\SpirvBinaries\ColorBlitClearAlphaFragment.spv" />
|
||||
<EmbeddedResource Include="Shaders\SpirvBinaries\ColorBlitFragment.spv" />
|
||||
<EmbeddedResource Include="Shaders\SpirvBinaries\ColorBlitMsFragment.spv" />
|
||||
<EmbeddedResource Include="Shaders\SpirvBinaries\ColorBlitVertex.spv" />
|
||||
<EmbeddedResource Include="Shaders\SpirvBinaries\ColorClearFFragment.spv" />
|
||||
<EmbeddedResource Include="Shaders\SpirvBinaries\ColorClearSIFragment.spv" />
|
||||
<EmbeddedResource Include="Shaders\SpirvBinaries\ColorClearUIFragment.spv" />
|
||||
<EmbeddedResource Include="Shaders\SpirvBinaries\ColorClearVertex.spv" />
|
||||
<EmbeddedResource Include="Shaders\SpirvBinaries\ColorCopyShorteningCompute.spv" />
|
||||
<EmbeddedResource Include="Shaders\SpirvBinaries\ColorCopyToNonMsCompute.spv" />
|
||||
<EmbeddedResource Include="Shaders\SpirvBinaries\ColorCopyWideningCompute.spv" />
|
||||
<EmbeddedResource Include="Shaders\SpirvBinaries\ColorDrawToMsFragment.spv" />
|
||||
<EmbeddedResource Include="Shaders\SpirvBinaries\ColorDrawToMsVertex.spv" />
|
||||
<EmbeddedResource Include="Shaders\SpirvBinaries\ConvertD32S8ToD24S8.spv" />
|
||||
<EmbeddedResource Include="Shaders\SpirvBinaries\ConvertIndexBuffer.spv" />
|
||||
<EmbeddedResource Include="Shaders\SpirvBinaries\ConvertIndirectData.spv" />
|
||||
<EmbeddedResource Include="Shaders\SpirvBinaries\DepthBlitFragment.spv" />
|
||||
<EmbeddedResource Include="Shaders\SpirvBinaries\DepthBlitMsFragment.spv" />
|
||||
<EmbeddedResource Include="Shaders\SpirvBinaries\DepthDrawToMsFragment.spv" />
|
||||
<EmbeddedResource Include="Shaders\SpirvBinaries\DepthDrawToNonMsFragment.spv" />
|
||||
<EmbeddedResource Include="Shaders\SpirvBinaries\StencilBlitFragment.spv" />
|
||||
<EmbeddedResource Include="Shaders\SpirvBinaries\StencilBlitMsFragment.spv" />
|
||||
<EmbeddedResource Include="Shaders\SpirvBinaries\StencilDrawToMsFragment.spv" />
|
||||
<EmbeddedResource Include="Shaders\SpirvBinaries\StencilDrawToNonMsFragment.spv" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
File diff suppressed because it is too large
Load Diff
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -78,7 +78,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
|
||||
var sampleCountFlags = ConvertToSampleCountFlags(gd.Capabilities.SupportedSampleCounts, (uint)info.Samples);
|
||||
|
||||
var usage = GetImageUsage(info.Format, info.Target, gd.Capabilities.SupportsShaderStorageImageMultisample);
|
||||
var usage = GetImageUsage(info.Format, info.Target, gd.Capabilities.SupportsShaderStorageImageMultisample, forceStorage: true);
|
||||
|
||||
var flags = ImageCreateFlags.CreateMutableFormatBit;
|
||||
|
||||
@@ -291,7 +291,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
}
|
||||
}
|
||||
|
||||
public static ImageUsageFlags GetImageUsage(Format format, Target target, bool supportsMsStorage)
|
||||
public static ImageUsageFlags GetImageUsage(Format format, Target target, bool supportsMsStorage, bool forceStorage = false)
|
||||
{
|
||||
var usage = DefaultUsageFlags;
|
||||
|
||||
@@ -304,7 +304,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
usage |= ImageUsageFlags.ColorAttachmentBit;
|
||||
}
|
||||
|
||||
if (format.IsImageCompatible() && (supportsMsStorage || !target.IsMultisample()))
|
||||
if (((forceStorage && !format.IsDepthOrStencil()) || format.IsImageCompatible()) && (supportsMsStorage || !target.IsMultisample()))
|
||||
{
|
||||
usage |= ImageUsageFlags.StorageBit;
|
||||
}
|
||||
|
@@ -116,7 +116,14 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
return new Auto<DisposableImageView>(new DisposableImageView(gd.Api, device, imageView), null, storage.GetImage());
|
||||
}
|
||||
|
||||
_imageView = CreateImageView(componentMapping, subresourceRange, type, ImageUsageFlags.SampledBit);
|
||||
ImageUsageFlags shaderUsage = ImageUsageFlags.SampledBit;
|
||||
|
||||
if (info.Format.IsImageCompatible())
|
||||
{
|
||||
shaderUsage |= ImageUsageFlags.StorageBit;
|
||||
}
|
||||
|
||||
_imageView = CreateImageView(componentMapping, subresourceRange, type, shaderUsage);
|
||||
|
||||
// Framebuffer attachments and storage images requires a identity component mapping.
|
||||
var identityComponentMapping = new ComponentMapping(
|
||||
@@ -378,7 +385,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
|
||||
bool isDepthOrStencil = dst.Info.Format.IsDepthOrStencil();
|
||||
|
||||
if (VulkanConfiguration.UseSlowSafeBlitOnAmd && (_gd.Vendor == Vendor.Amd || _gd.IsMoltenVk))
|
||||
if (!VulkanConfiguration.UseUnsafeBlit || (_gd.Vendor != Vendor.Nvidia && _gd.Vendor != Vendor.Intel))
|
||||
{
|
||||
_gd.HelperShader.Blit(
|
||||
_gd,
|
||||
|
@@ -3,7 +3,7 @@
|
||||
static class VulkanConfiguration
|
||||
{
|
||||
public const bool UseFastBufferUpdates = true;
|
||||
public const bool UseSlowSafeBlitOnAmd = true;
|
||||
public const bool UseUnsafeBlit = true;
|
||||
public const bool UsePushDescriptors = false;
|
||||
|
||||
public const bool ForceD24S8Unsupported = false;
|
||||
|
@@ -10,17 +10,6 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
{
|
||||
class VulkanDebugMessenger : IDisposable
|
||||
{
|
||||
private static readonly string[] _excludedMessages = {
|
||||
// NOTE: Done on purpose right now.
|
||||
"UNASSIGNED-CoreValidation-Shader-OutputNotConsumed",
|
||||
// TODO: Figure out if fixable
|
||||
"VUID-vkCmdDrawIndexed-None-04584",
|
||||
// TODO: Might be worth looking into making this happy to possibly optimize copies.
|
||||
"UNASSIGNED-CoreValidation-DrawState-InvalidImageLayout",
|
||||
// TODO: Fix this, it's causing too much noise right now.
|
||||
"VUID-VkSubpassDependency-srcSubpass-00867",
|
||||
};
|
||||
|
||||
private readonly Vk _api;
|
||||
private readonly Instance _instance;
|
||||
private readonly GraphicsDebugLevel _logLevel;
|
||||
@@ -108,14 +97,6 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
{
|
||||
var msg = Marshal.PtrToStringAnsi((IntPtr)pCallbackData->PMessage);
|
||||
|
||||
foreach (string excludedMessagePart in _excludedMessages)
|
||||
{
|
||||
if (msg.Contains(excludedMessagePart))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (messageSeverity.HasFlag(DebugUtilsMessageSeverityFlagsEXT.ErrorBitExt))
|
||||
{
|
||||
Logger.Error?.Print(LogClass.Gpu, msg);
|
||||
|
@@ -377,8 +377,8 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
ShaderFloat64 = supportedFeatures.ShaderFloat64,
|
||||
ShaderImageGatherExtended = supportedFeatures.ShaderImageGatherExtended,
|
||||
ShaderStorageImageMultisample = supportedFeatures.ShaderStorageImageMultisample,
|
||||
// ShaderStorageImageReadWithoutFormat = true,
|
||||
// ShaderStorageImageWriteWithoutFormat = true,
|
||||
ShaderStorageImageReadWithoutFormat = supportedFeatures.ShaderStorageImageReadWithoutFormat,
|
||||
ShaderStorageImageWriteWithoutFormat = supportedFeatures.ShaderStorageImageWriteWithoutFormat,
|
||||
TessellationShader = supportedFeatures.TessellationShader,
|
||||
VertexPipelineStoresAndAtomics = supportedFeatures.VertexPipelineStoresAndAtomics,
|
||||
RobustBufferAccess = useRobustBufferAccess,
|
||||
|
@@ -47,7 +47,7 @@ namespace Ryujinx.HLE.Exceptions
|
||||
|
||||
private string BuildMessage()
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
StringBuilder sb = new();
|
||||
|
||||
// Print the IPC command details (service name, command ID, and handler)
|
||||
(Type callingType, MethodBase callingMethod) = WalkStackTrace(new StackTrace(this));
|
||||
|
@@ -30,13 +30,13 @@ namespace Ryujinx.HLE.FileSystem
|
||||
|
||||
private Dictionary<StorageId, LinkedList<LocationEntry>> _locationEntries;
|
||||
|
||||
private Dictionary<string, ulong> _sharedFontTitleDictionary;
|
||||
private Dictionary<ulong, string> _systemTitlesNameDictionary;
|
||||
private Dictionary<string, string> _sharedFontFilenameDictionary;
|
||||
private readonly Dictionary<string, ulong> _sharedFontTitleDictionary;
|
||||
private readonly Dictionary<ulong, string> _systemTitlesNameDictionary;
|
||||
private readonly Dictionary<string, string> _sharedFontFilenameDictionary;
|
||||
|
||||
private SortedDictionary<(ulong titleId, NcaContentType type), string> _contentDictionary;
|
||||
|
||||
private struct AocItem
|
||||
private readonly struct AocItem
|
||||
{
|
||||
public readonly string ContainerPath;
|
||||
public readonly string NcaPath;
|
||||
@@ -48,9 +48,9 @@ namespace Ryujinx.HLE.FileSystem
|
||||
}
|
||||
}
|
||||
|
||||
private SortedList<ulong, AocItem> _aocData { get; }
|
||||
private SortedList<ulong, AocItem> AocData { get; }
|
||||
|
||||
private VirtualFileSystem _virtualFileSystem;
|
||||
private readonly VirtualFileSystem _virtualFileSystem;
|
||||
|
||||
private readonly object _lock = new();
|
||||
|
||||
@@ -66,7 +66,7 @@ namespace Ryujinx.HLE.FileSystem
|
||||
{ "FontExtendedChineseSimplified", 0x0100000000000814 },
|
||||
{ "FontKorean", 0x0100000000000812 },
|
||||
{ "FontChineseTraditional", 0x0100000000000813 },
|
||||
{ "FontNintendoExtended", 0x0100000000000810 }
|
||||
{ "FontNintendoExtended", 0x0100000000000810 },
|
||||
};
|
||||
|
||||
_systemTitlesNameDictionary = new Dictionary<ulong, string>()
|
||||
@@ -86,12 +86,12 @@ namespace Ryujinx.HLE.FileSystem
|
||||
{ "FontExtendedChineseSimplified", "nintendo_udsg-r_ext_zh-cn_003.bfttf" },
|
||||
{ "FontKorean", "nintendo_udsg-r_ko_003.bfttf" },
|
||||
{ "FontChineseTraditional", "nintendo_udjxh-db_zh-tw_003.bfttf" },
|
||||
{ "FontNintendoExtended", "nintendo_ext_003.bfttf" }
|
||||
{ "FontNintendoExtended", "nintendo_ext_003.bfttf" },
|
||||
};
|
||||
|
||||
_virtualFileSystem = virtualFileSystem;
|
||||
|
||||
_aocData = new SortedList<ulong, AocItem>();
|
||||
AocData = new SortedList<ulong, AocItem>();
|
||||
}
|
||||
|
||||
public void LoadEntries(Switch device = null)
|
||||
@@ -110,7 +110,7 @@ namespace Ryujinx.HLE.FileSystem
|
||||
try
|
||||
{
|
||||
contentPathString = ContentPath.GetContentPath(storageId);
|
||||
contentDirectory = ContentPath.GetRealPath(_virtualFileSystem, contentPathString);
|
||||
contentDirectory = ContentPath.GetRealPath(contentPathString);
|
||||
registeredDirectory = Path.Combine(contentDirectory, "registered");
|
||||
}
|
||||
catch (NotSupportedException)
|
||||
@@ -120,7 +120,7 @@ namespace Ryujinx.HLE.FileSystem
|
||||
|
||||
Directory.CreateDirectory(registeredDirectory);
|
||||
|
||||
LinkedList<LocationEntry> locationList = new LinkedList<LocationEntry>();
|
||||
LinkedList<LocationEntry> locationList = new();
|
||||
|
||||
void AddEntry(LocationEntry entry)
|
||||
{
|
||||
@@ -133,26 +133,21 @@ namespace Ryujinx.HLE.FileSystem
|
||||
{
|
||||
string ncaName = new DirectoryInfo(directoryPath).Name.Replace(".nca", string.Empty);
|
||||
|
||||
using (FileStream ncaFile = File.OpenRead(Directory.GetFiles(directoryPath)[0]))
|
||||
{
|
||||
Nca nca = new Nca(_virtualFileSystem.KeySet, ncaFile.AsStorage());
|
||||
using FileStream ncaFile = File.OpenRead(Directory.GetFiles(directoryPath)[0]);
|
||||
Nca nca = new(_virtualFileSystem.KeySet, ncaFile.AsStorage());
|
||||
|
||||
string switchPath = contentPathString + ":/" + ncaFile.Name.Replace(contentDirectory, string.Empty).TrimStart(Path.DirectorySeparatorChar);
|
||||
|
||||
// Change path format to switch's
|
||||
switchPath = switchPath.Replace('\\', '/');
|
||||
|
||||
LocationEntry entry = new LocationEntry(switchPath,
|
||||
0,
|
||||
nca.Header.TitleId,
|
||||
nca.Header.ContentType);
|
||||
LocationEntry entry = new(switchPath, 0, nca.Header.TitleId, nca.Header.ContentType);
|
||||
|
||||
AddEntry(entry);
|
||||
|
||||
_contentDictionary.Add((nca.Header.TitleId, nca.Header.ContentType), ncaName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach (string filePath in Directory.EnumerateFiles(contentDirectory))
|
||||
{
|
||||
@@ -160,36 +155,28 @@ namespace Ryujinx.HLE.FileSystem
|
||||
{
|
||||
string ncaName = Path.GetFileNameWithoutExtension(filePath);
|
||||
|
||||
using (FileStream ncaFile = new FileStream(filePath, FileMode.Open, FileAccess.Read))
|
||||
{
|
||||
Nca nca = new Nca(_virtualFileSystem.KeySet, ncaFile.AsStorage());
|
||||
using FileStream ncaFile = new(filePath, FileMode.Open, FileAccess.Read);
|
||||
Nca nca = new(_virtualFileSystem.KeySet, ncaFile.AsStorage());
|
||||
|
||||
string switchPath = contentPathString + ":/" + filePath.Replace(contentDirectory, string.Empty).TrimStart(Path.DirectorySeparatorChar);
|
||||
|
||||
// Change path format to switch's
|
||||
switchPath = switchPath.Replace('\\', '/');
|
||||
|
||||
LocationEntry entry = new LocationEntry(switchPath,
|
||||
0,
|
||||
nca.Header.TitleId,
|
||||
nca.Header.ContentType);
|
||||
LocationEntry entry = new(switchPath, 0, nca.Header.TitleId, nca.Header.ContentType);
|
||||
|
||||
AddEntry(entry);
|
||||
|
||||
_contentDictionary.Add((nca.Header.TitleId, nca.Header.ContentType), ncaName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (_locationEntries.TryGetValue(storageId, out var locationEntriesItem) && locationEntriesItem?.Count == 0)
|
||||
{
|
||||
_locationEntries.Remove(storageId);
|
||||
}
|
||||
|
||||
if (!_locationEntries.ContainsKey(storageId))
|
||||
{
|
||||
_locationEntries.Add(storageId, locationList);
|
||||
}
|
||||
_locationEntries.TryAdd(storageId, locationList);
|
||||
}
|
||||
|
||||
if (device != null)
|
||||
@@ -239,7 +226,7 @@ namespace Ryujinx.HLE.FileSystem
|
||||
public void AddAocItem(ulong titleId, string containerPath, string ncaPath, bool mergedToContainer = false)
|
||||
{
|
||||
// TODO: Check Aoc version.
|
||||
if (!_aocData.TryAdd(titleId, new AocItem(containerPath, ncaPath)))
|
||||
if (!AocData.TryAdd(titleId, new AocItem(containerPath, ncaPath)))
|
||||
{
|
||||
Logger.Warning?.Print(LogClass.Application, $"Duplicate AddOnContent detected. TitleId {titleId:X16}");
|
||||
}
|
||||
@@ -257,17 +244,17 @@ namespace Ryujinx.HLE.FileSystem
|
||||
}
|
||||
}
|
||||
|
||||
public void ClearAocData() => _aocData.Clear();
|
||||
public void ClearAocData() => AocData.Clear();
|
||||
|
||||
public int GetAocCount() => _aocData.Count;
|
||||
public int GetAocCount() => AocData.Count;
|
||||
|
||||
public IList<ulong> GetAocTitleIds() => _aocData.Select(e => e.Key).ToList();
|
||||
public IList<ulong> GetAocTitleIds() => AocData.Select(e => e.Key).ToList();
|
||||
|
||||
public bool GetAocDataStorage(ulong aocTitleId, out IStorage aocStorage, IntegrityCheckLevel integrityCheckLevel)
|
||||
{
|
||||
aocStorage = null;
|
||||
|
||||
if (_aocData.TryGetValue(aocTitleId, out AocItem aoc))
|
||||
if (AocData.TryGetValue(aocTitleId, out AocItem aoc))
|
||||
{
|
||||
var file = new FileStream(aoc.ContainerPath, FileMode.Open, FileAccess.Read);
|
||||
using var ncaFile = new UniqueRef<IFile>();
|
||||
@@ -331,7 +318,7 @@ namespace Ryujinx.HLE.FileSystem
|
||||
if (_contentDictionary.ContainsValue(ncaId))
|
||||
{
|
||||
var content = _contentDictionary.FirstOrDefault(x => x.Value == ncaId);
|
||||
ulong titleId = content.Key.Item1;
|
||||
ulong titleId = content.Key.titleId;
|
||||
|
||||
NcaContentType contentType = content.Key.type;
|
||||
StorageId storage = GetInstalledStorage(titleId, contentType, storageId);
|
||||
@@ -403,21 +390,19 @@ namespace Ryujinx.HLE.FileSystem
|
||||
return false;
|
||||
}
|
||||
|
||||
string installedPath = _virtualFileSystem.SwitchPathToSystemPath(locationEntry.ContentPath);
|
||||
string installedPath = VirtualFileSystem.SwitchPathToSystemPath(locationEntry.ContentPath);
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(installedPath))
|
||||
{
|
||||
if (File.Exists(installedPath))
|
||||
{
|
||||
using (FileStream file = new FileStream(installedPath, FileMode.Open, FileAccess.Read))
|
||||
{
|
||||
Nca nca = new Nca(_virtualFileSystem.KeySet, file.AsStorage());
|
||||
using FileStream file = new(installedPath, FileMode.Open, FileAccess.Read);
|
||||
Nca nca = new(_virtualFileSystem.KeySet, file.AsStorage());
|
||||
bool contentCheck = nca.Header.ContentType == contentType;
|
||||
|
||||
return contentCheck;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -426,9 +411,9 @@ namespace Ryujinx.HLE.FileSystem
|
||||
{
|
||||
LinkedList<LocationEntry> locationList = null;
|
||||
|
||||
if (_locationEntries.ContainsKey(storageId))
|
||||
if (_locationEntries.TryGetValue(storageId, out LinkedList<LocationEntry> locationEntry))
|
||||
{
|
||||
locationList = _locationEntries[storageId];
|
||||
locationList = locationEntry;
|
||||
}
|
||||
|
||||
if (locationList != null)
|
||||
@@ -446,9 +431,9 @@ namespace Ryujinx.HLE.FileSystem
|
||||
{
|
||||
LinkedList<LocationEntry> locationList = null;
|
||||
|
||||
if (_locationEntries.ContainsKey(storageId))
|
||||
if (_locationEntries.TryGetValue(storageId, out LinkedList<LocationEntry> locationEntry))
|
||||
{
|
||||
locationList = _locationEntries[storageId];
|
||||
locationList = locationEntry;
|
||||
}
|
||||
|
||||
if (locationList != null)
|
||||
@@ -488,7 +473,7 @@ namespace Ryujinx.HLE.FileSystem
|
||||
public void InstallFirmware(string firmwareSource)
|
||||
{
|
||||
string contentPathString = ContentPath.GetContentPath(StorageId.BuiltInSystem);
|
||||
string contentDirectory = ContentPath.GetRealPath(_virtualFileSystem, contentPathString);
|
||||
string contentDirectory = ContentPath.GetRealPath(contentPathString);
|
||||
string registeredDirectory = Path.Combine(contentDirectory, "registered");
|
||||
string temporaryDirectory = Path.Combine(contentDirectory, "temp");
|
||||
|
||||
@@ -510,10 +495,10 @@ namespace Ryujinx.HLE.FileSystem
|
||||
throw new FileNotFoundException("Firmware file does not exist.");
|
||||
}
|
||||
|
||||
FileInfo info = new FileInfo(firmwareSource);
|
||||
FileInfo info = new(firmwareSource);
|
||||
|
||||
using FileStream file = File.OpenRead(firmwareSource);
|
||||
|
||||
using (FileStream file = File.OpenRead(firmwareSource))
|
||||
{
|
||||
switch (info.Extension)
|
||||
{
|
||||
case ".zip":
|
||||
@@ -523,7 +508,7 @@ namespace Ryujinx.HLE.FileSystem
|
||||
}
|
||||
break;
|
||||
case ".xci":
|
||||
Xci xci = new Xci(_virtualFileSystem.KeySet, file.AsStorage());
|
||||
Xci xci = new(_virtualFileSystem.KeySet, file.AsStorage());
|
||||
InstallFromCart(xci, temporaryDirectory);
|
||||
break;
|
||||
default:
|
||||
@@ -532,7 +517,6 @@ namespace Ryujinx.HLE.FileSystem
|
||||
|
||||
FinishInstallation(temporaryDirectory, registeredDirectory);
|
||||
}
|
||||
}
|
||||
|
||||
private void FinishInstallation(string temporaryDirectory, string registeredDirectory)
|
||||
{
|
||||
@@ -555,7 +539,7 @@ namespace Ryujinx.HLE.FileSystem
|
||||
{
|
||||
foreach (var entry in filesystem.EnumerateEntries("/", "*.nca"))
|
||||
{
|
||||
Nca nca = new Nca(_virtualFileSystem.KeySet, OpenPossibleFragmentedFile(filesystem, entry.FullPath, OpenMode.Read).AsStorage());
|
||||
Nca nca = new(_virtualFileSystem.KeySet, OpenPossibleFragmentedFile(filesystem, entry.FullPath, OpenMode.Read).AsStorage());
|
||||
|
||||
SaveNca(nca, entry.Name.Remove(entry.Name.IndexOf('.')), temporaryDirectory);
|
||||
}
|
||||
@@ -575,9 +559,7 @@ namespace Ryujinx.HLE.FileSystem
|
||||
}
|
||||
}
|
||||
|
||||
private void InstallFromZip(ZipArchive archive, string temporaryDirectory)
|
||||
{
|
||||
using (archive)
|
||||
private static void InstallFromZip(ZipArchive archive, string temporaryDirectory)
|
||||
{
|
||||
foreach (var entry in archive.Entries)
|
||||
{
|
||||
@@ -587,12 +569,12 @@ namespace Ryujinx.HLE.FileSystem
|
||||
|
||||
string[] pathComponents = entry.FullName.Replace(".cnmt", "").Split('/');
|
||||
|
||||
string ncaId = pathComponents[pathComponents.Length - 1];
|
||||
string ncaId = pathComponents[^1];
|
||||
|
||||
// If this is a fragmented nca, we need to get the previous element.GetZip
|
||||
if (ncaId.Equals("00"))
|
||||
{
|
||||
ncaId = pathComponents[pathComponents.Length - 2];
|
||||
ncaId = pathComponents[^2];
|
||||
}
|
||||
|
||||
if (ncaId.Contains(".nca"))
|
||||
@@ -606,21 +588,18 @@ namespace Ryujinx.HLE.FileSystem
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void SaveNca(Nca nca, string ncaId, string temporaryDirectory)
|
||||
public static void SaveNca(Nca nca, string ncaId, string temporaryDirectory)
|
||||
{
|
||||
string newPath = Path.Combine(temporaryDirectory, ncaId + ".nca");
|
||||
|
||||
Directory.CreateDirectory(newPath);
|
||||
|
||||
using (FileStream file = File.Create(Path.Combine(newPath, "00")))
|
||||
{
|
||||
using FileStream file = File.Create(Path.Combine(newPath, "00"));
|
||||
nca.BaseStorage.AsStream().CopyTo(file);
|
||||
}
|
||||
}
|
||||
|
||||
private IFile OpenPossibleFragmentedFile(IFileSystem filesystem, string path, OpenMode mode)
|
||||
private static IFile OpenPossibleFragmentedFile(IFileSystem filesystem, string path, OpenMode mode)
|
||||
{
|
||||
using var file = new UniqueRef<IFile>();
|
||||
|
||||
@@ -636,14 +615,12 @@ namespace Ryujinx.HLE.FileSystem
|
||||
return file.Release();
|
||||
}
|
||||
|
||||
private Stream GetZipStream(ZipArchiveEntry entry)
|
||||
private static Stream GetZipStream(ZipArchiveEntry entry)
|
||||
{
|
||||
MemoryStream dest = MemoryStreamManager.Shared.GetStream();
|
||||
|
||||
using (Stream src = entry.Open())
|
||||
{
|
||||
using Stream src = entry.Open();
|
||||
src.CopyTo(dest);
|
||||
}
|
||||
|
||||
return dest;
|
||||
}
|
||||
@@ -659,7 +636,7 @@ namespace Ryujinx.HLE.FileSystem
|
||||
throw new MissingKeyException("HeaderKey is empty. Cannot decrypt NCA headers.");
|
||||
}
|
||||
|
||||
Dictionary<ulong, List<(NcaContentType type, string path)>> updateNcas = new Dictionary<ulong, List<(NcaContentType, string)>>();
|
||||
Dictionary<ulong, List<(NcaContentType type, string path)>> updateNcas = new();
|
||||
|
||||
if (Directory.Exists(firmwarePackage))
|
||||
{
|
||||
@@ -671,10 +648,10 @@ namespace Ryujinx.HLE.FileSystem
|
||||
throw new FileNotFoundException("Firmware file does not exist.");
|
||||
}
|
||||
|
||||
FileInfo info = new FileInfo(firmwarePackage);
|
||||
FileInfo info = new(firmwarePackage);
|
||||
|
||||
using FileStream file = File.OpenRead(firmwarePackage);
|
||||
|
||||
using (FileStream file = File.OpenRead(firmwarePackage))
|
||||
{
|
||||
switch (info.Extension)
|
||||
{
|
||||
case ".zip":
|
||||
@@ -683,7 +660,7 @@ namespace Ryujinx.HLE.FileSystem
|
||||
return VerifyAndGetVersionZip(archive);
|
||||
}
|
||||
case ".xci":
|
||||
Xci xci = new Xci(_virtualFileSystem.KeySet, file.AsStorage());
|
||||
Xci xci = new(_virtualFileSystem.KeySet, file.AsStorage());
|
||||
|
||||
if (xci.HasPartition(XciPartitionType.Update))
|
||||
{
|
||||
@@ -698,7 +675,6 @@ namespace Ryujinx.HLE.FileSystem
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
SystemVersion VerifyAndGetVersionDirectory(string firmwareDirectory)
|
||||
{
|
||||
@@ -713,11 +689,10 @@ namespace Ryujinx.HLE.FileSystem
|
||||
{
|
||||
if (entry.FullName.EndsWith(".nca") || entry.FullName.EndsWith(".nca/00"))
|
||||
{
|
||||
using (Stream ncaStream = GetZipStream(entry))
|
||||
{
|
||||
using Stream ncaStream = GetZipStream(entry);
|
||||
IStorage storage = ncaStream.AsStorage();
|
||||
|
||||
Nca nca = new Nca(_virtualFileSystem.KeySet, storage);
|
||||
Nca nca = new(_virtualFileSystem.KeySet, storage);
|
||||
|
||||
if (updateNcas.TryGetValue(nca.Header.TitleId, out var updateNcasItem))
|
||||
{
|
||||
@@ -730,7 +705,6 @@ namespace Ryujinx.HLE.FileSystem
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (updateNcas.TryGetValue(SystemUpdateTitleId, out var ncaEntry))
|
||||
{
|
||||
@@ -742,7 +716,7 @@ namespace Ryujinx.HLE.FileSystem
|
||||
|
||||
using (Stream ncaStream = GetZipStream(fileEntry))
|
||||
{
|
||||
Nca metaNca = new Nca(_virtualFileSystem.KeySet, ncaStream.AsStorage());
|
||||
Nca metaNca = new(_virtualFileSystem.KeySet, ncaStream.AsStorage());
|
||||
|
||||
IFileSystem fs = metaNca.OpenFileSystem(NcaSectionType.Data, IntegrityCheckLevel.ErrorOnInvalid);
|
||||
|
||||
@@ -772,9 +746,8 @@ namespace Ryujinx.HLE.FileSystem
|
||||
{
|
||||
string versionEntry = updateNcasItem.Find(x => x.type != NcaContentType.Meta).path;
|
||||
|
||||
using (Stream ncaStream = GetZipStream(archive.GetEntry(versionEntry)))
|
||||
{
|
||||
Nca nca = new Nca(_virtualFileSystem.KeySet, ncaStream.AsStorage());
|
||||
using Stream ncaStream = GetZipStream(archive.GetEntry(versionEntry));
|
||||
Nca nca = new(_virtualFileSystem.KeySet, ncaStream.AsStorage());
|
||||
|
||||
var romfs = nca.OpenFileSystem(NcaSectionType.Data, IntegrityCheckLevel.ErrorOnInvalid);
|
||||
|
||||
@@ -785,7 +758,6 @@ namespace Ryujinx.HLE.FileSystem
|
||||
systemVersion = new SystemVersion(systemVersionFile.Get.AsStream());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach (CnmtContentMetaEntry metaEntry in metaEntries)
|
||||
{
|
||||
@@ -807,11 +779,9 @@ namespace Ryujinx.HLE.FileSystem
|
||||
ZipArchiveEntry metaZipEntry = archive.GetEntry(metaPath);
|
||||
ZipArchiveEntry contentZipEntry = archive.GetEntry(contentPath);
|
||||
|
||||
using (Stream metaNcaStream = GetZipStream(metaZipEntry))
|
||||
{
|
||||
using (Stream contentNcaStream = GetZipStream(contentZipEntry))
|
||||
{
|
||||
Nca metaNca = new Nca(_virtualFileSystem.KeySet, metaNcaStream.AsStorage());
|
||||
using Stream metaNcaStream = GetZipStream(metaZipEntry);
|
||||
using Stream contentNcaStream = GetZipStream(contentZipEntry);
|
||||
Nca metaNca = new(_virtualFileSystem.KeySet, metaNcaStream.AsStorage());
|
||||
|
||||
IFileSystem fs = metaNca.OpenFileSystem(NcaSectionType.Data, IntegrityCheckLevel.ErrorOnInvalid);
|
||||
|
||||
@@ -828,11 +798,11 @@ namespace Ryujinx.HLE.FileSystem
|
||||
{
|
||||
byte[] contentData = new byte[size];
|
||||
|
||||
Span<byte> content = new Span<byte>(contentData);
|
||||
Span<byte> content = new(contentData);
|
||||
|
||||
contentStorage.Read(0, content);
|
||||
|
||||
Span<byte> hash = new Span<byte>(new byte[32]);
|
||||
Span<byte> hash = new(new byte[32]);
|
||||
|
||||
LibHac.Crypto.Sha256.GenerateSha256Hash(content, hash);
|
||||
|
||||
@@ -844,8 +814,6 @@ namespace Ryujinx.HLE.FileSystem
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (updateNcas.Count > 0)
|
||||
{
|
||||
@@ -853,9 +821,9 @@ namespace Ryujinx.HLE.FileSystem
|
||||
|
||||
foreach (var entry in updateNcas)
|
||||
{
|
||||
foreach (var nca in entry.Value)
|
||||
foreach (var (type, path) in entry.Value)
|
||||
{
|
||||
extraNcas += nca.path + Environment.NewLine;
|
||||
extraNcas += path + Environment.NewLine;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -880,7 +848,7 @@ namespace Ryujinx.HLE.FileSystem
|
||||
{
|
||||
IStorage ncaStorage = OpenPossibleFragmentedFile(filesystem, entry.FullPath, OpenMode.Read).AsStorage();
|
||||
|
||||
Nca nca = new Nca(_virtualFileSystem.KeySet, ncaStorage);
|
||||
Nca nca = new(_virtualFileSystem.KeySet, ncaStorage);
|
||||
|
||||
if (nca.Header.TitleId == SystemUpdateTitleId && nca.Header.ContentType == NcaContentType.Meta)
|
||||
{
|
||||
@@ -936,7 +904,7 @@ namespace Ryujinx.HLE.FileSystem
|
||||
{
|
||||
if (updateNcas.TryGetValue(metaEntry.TitleId, out var ncaEntry))
|
||||
{
|
||||
var metaNcaEntry = ncaEntry.Find(x => x.type == NcaContentType.Meta);
|
||||
string metaNcaPath = ncaEntry.Find(x => x.type == NcaContentType.Meta).path;
|
||||
string contentPath = ncaEntry.Find(x => x.type != NcaContentType.Meta).path;
|
||||
|
||||
// Nintendo in 9.0.0, removed PPC and only kept the meta nca of it.
|
||||
@@ -948,10 +916,10 @@ namespace Ryujinx.HLE.FileSystem
|
||||
continue;
|
||||
}
|
||||
|
||||
IStorage metaStorage = OpenPossibleFragmentedFile(filesystem, metaNcaEntry.path, OpenMode.Read).AsStorage();
|
||||
IStorage metaStorage = OpenPossibleFragmentedFile(filesystem, metaNcaPath, OpenMode.Read).AsStorage();
|
||||
IStorage contentStorage = OpenPossibleFragmentedFile(filesystem, contentPath, OpenMode.Read).AsStorage();
|
||||
|
||||
Nca metaNca = new Nca(_virtualFileSystem.KeySet, metaStorage);
|
||||
Nca metaNca = new(_virtualFileSystem.KeySet, metaStorage);
|
||||
|
||||
IFileSystem fs = metaNca.OpenFileSystem(NcaSectionType.Data, IntegrityCheckLevel.ErrorOnInvalid);
|
||||
|
||||
@@ -967,11 +935,11 @@ namespace Ryujinx.HLE.FileSystem
|
||||
{
|
||||
byte[] contentData = new byte[size];
|
||||
|
||||
Span<byte> content = new Span<byte>(contentData);
|
||||
Span<byte> content = new(contentData);
|
||||
|
||||
contentStorage.Read(0, content);
|
||||
|
||||
Span<byte> hash = new Span<byte>(new byte[32]);
|
||||
Span<byte> hash = new(new byte[32]);
|
||||
|
||||
LibHac.Crypto.Sha256.GenerateSha256Hash(content, hash);
|
||||
|
||||
@@ -1017,11 +985,10 @@ namespace Ryujinx.HLE.FileSystem
|
||||
{
|
||||
if (entry.ContentType == NcaContentType.Data)
|
||||
{
|
||||
var path = _virtualFileSystem.SwitchPathToSystemPath(entry.ContentPath);
|
||||
var path = VirtualFileSystem.SwitchPathToSystemPath(entry.ContentPath);
|
||||
|
||||
using (FileStream fileStream = File.OpenRead(path))
|
||||
{
|
||||
Nca nca = new Nca(_virtualFileSystem.KeySet, fileStream.AsStorage());
|
||||
using FileStream fileStream = File.OpenRead(path);
|
||||
Nca nca = new(_virtualFileSystem.KeySet, fileStream.AsStorage());
|
||||
|
||||
if (nca.Header.TitleId == SystemVersionTitleId && nca.Header.ContentType == NcaContentType.Data)
|
||||
{
|
||||
@@ -1034,8 +1001,6 @@ namespace Ryujinx.HLE.FileSystem
|
||||
return new SystemVersion(systemVersionFile.Get.AsStream());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -2,7 +2,6 @@
|
||||
using LibHac.Ncm;
|
||||
using Ryujinx.Common.Configuration;
|
||||
using System;
|
||||
|
||||
using static Ryujinx.HLE.FileSystem.VirtualFileSystem;
|
||||
using Path = System.IO.Path;
|
||||
|
||||
@@ -27,16 +26,16 @@ namespace Ryujinx.HLE.FileSystem
|
||||
public const string Nintendo = "Nintendo";
|
||||
public const string Contents = "Contents";
|
||||
|
||||
public static string GetRealPath(VirtualFileSystem fileSystem, string switchContentPath)
|
||||
public static string GetRealPath(string switchContentPath)
|
||||
{
|
||||
return switchContentPath switch
|
||||
{
|
||||
SystemContent => Path.Combine(AppDataManager.BaseDirPath, SystemNandPath, Contents),
|
||||
UserContent => Path.Combine(AppDataManager.BaseDirPath, UserNandPath, Contents),
|
||||
SdCardContent => Path.Combine(fileSystem.GetSdCardPath(), Nintendo, Contents),
|
||||
SdCardContent => Path.Combine(GetSdCardPath(), Nintendo, Contents),
|
||||
System => Path.Combine(AppDataManager.BaseDirPath, SystemNandPath),
|
||||
User => Path.Combine(AppDataManager.BaseDirPath, UserNandPath),
|
||||
_ => throw new NotSupportedException($"Content Path \"`{switchContentPath}`\" is not supported.")
|
||||
_ => throw new NotSupportedException($"Content Path \"`{switchContentPath}`\" is not supported."),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -47,7 +46,7 @@ namespace Ryujinx.HLE.FileSystem
|
||||
ContentStorageId.System => SystemContent,
|
||||
ContentStorageId.User => UserContent,
|
||||
ContentStorageId.SdCard => SdCardContent,
|
||||
_ => throw new NotSupportedException($"Content Storage Id \"`{contentStorageId}`\" is not supported.")
|
||||
_ => throw new NotSupportedException($"Content Storage Id \"`{contentStorageId}`\" is not supported."),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -58,7 +57,7 @@ namespace Ryujinx.HLE.FileSystem
|
||||
StorageId.BuiltInSystem => SystemContent,
|
||||
StorageId.BuiltInUser => UserContent,
|
||||
StorageId.SdCard => SdCardContent,
|
||||
_ => throw new NotSupportedException($"Storage Id \"`{storageId}`\" is not supported.")
|
||||
_ => throw new NotSupportedException($"Storage Id \"`{storageId}`\" is not supported."),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -75,7 +74,7 @@ namespace Ryujinx.HLE.FileSystem
|
||||
GamecardApp or
|
||||
GamecardContents or
|
||||
GamecardUpdate => StorageId.GameCard,
|
||||
_ => StorageId.None
|
||||
_ => StorageId.None,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@@ -17,8 +17,7 @@ namespace Ryujinx.HLE.FileSystem
|
||||
|
||||
public SystemVersion(Stream systemVersionFile)
|
||||
{
|
||||
using (BinaryReader reader = new BinaryReader(systemVersionFile))
|
||||
{
|
||||
using BinaryReader reader = new(systemVersionFile);
|
||||
Major = reader.ReadByte();
|
||||
Minor = reader.ReadByte();
|
||||
Micro = reader.ReadByte();
|
||||
@@ -37,4 +36,3 @@ namespace Ryujinx.HLE.FileSystem
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -26,9 +26,9 @@ namespace Ryujinx.HLE.FileSystem
|
||||
{
|
||||
public class VirtualFileSystem : IDisposable
|
||||
{
|
||||
public static string SafeNandPath = Path.Combine(AppDataManager.DefaultNandDir, "safe");
|
||||
public static string SystemNandPath = Path.Combine(AppDataManager.DefaultNandDir, "system");
|
||||
public static string UserNandPath = Path.Combine(AppDataManager.DefaultNandDir, "user");
|
||||
public static readonly string SafeNandPath = Path.Combine(AppDataManager.DefaultNandDir, "safe");
|
||||
public static readonly string SystemNandPath = Path.Combine(AppDataManager.DefaultNandDir, "system");
|
||||
public static readonly string UserNandPath = Path.Combine(AppDataManager.DefaultNandDir, "user");
|
||||
|
||||
public KeySet KeySet { get; private set; }
|
||||
public EmulatedGameCard GameCard { get; private set; }
|
||||
@@ -85,15 +85,15 @@ namespace Ryujinx.HLE.FileSystem
|
||||
return _romFsByPid[pid];
|
||||
}
|
||||
|
||||
public string GetFullPath(string basePath, string fileName)
|
||||
public static string GetFullPath(string basePath, string fileName)
|
||||
{
|
||||
if (fileName.StartsWith("//"))
|
||||
{
|
||||
fileName = fileName.Substring(2);
|
||||
fileName = fileName[2..];
|
||||
}
|
||||
else if (fileName.StartsWith('/'))
|
||||
{
|
||||
fileName = fileName.Substring(1);
|
||||
fileName = fileName[1..];
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -110,10 +110,10 @@ namespace Ryujinx.HLE.FileSystem
|
||||
return fullPath;
|
||||
}
|
||||
|
||||
internal string GetSdCardPath() => MakeFullPath(AppDataManager.DefaultSdcardDir);
|
||||
public string GetNandPath() => MakeFullPath(AppDataManager.DefaultNandDir);
|
||||
internal static string GetSdCardPath() => MakeFullPath(AppDataManager.DefaultSdcardDir);
|
||||
public static string GetNandPath() => MakeFullPath(AppDataManager.DefaultNandDir);
|
||||
|
||||
public string SwitchPathToSystemPath(string switchPath)
|
||||
public static string SwitchPathToSystemPath(string switchPath)
|
||||
{
|
||||
string[] parts = switchPath.Split(":");
|
||||
|
||||
@@ -125,7 +125,7 @@ namespace Ryujinx.HLE.FileSystem
|
||||
return GetFullPath(MakeFullPath(parts[0]), parts[1]);
|
||||
}
|
||||
|
||||
public string SystemPathToSwitchPath(string systemPath)
|
||||
public static string SystemPathToSwitchPath(string systemPath)
|
||||
{
|
||||
string baseSystemPath = AppDataManager.BaseDirPath + Path.DirectorySeparatorChar;
|
||||
|
||||
@@ -148,7 +148,7 @@ namespace Ryujinx.HLE.FileSystem
|
||||
return null;
|
||||
}
|
||||
|
||||
private string MakeFullPath(string path, bool isDirectory = true)
|
||||
private static string MakeFullPath(string path, bool isDirectory = true)
|
||||
{
|
||||
// Handles Common Switch Content Paths
|
||||
switch (path)
|
||||
@@ -185,7 +185,7 @@ namespace Ryujinx.HLE.FileSystem
|
||||
|
||||
public void InitializeFsServer(LibHac.Horizon horizon, out HorizonClient fsServerClient)
|
||||
{
|
||||
LocalFileSystem serverBaseFs = new LocalFileSystem(AppDataManager.BaseDirPath);
|
||||
LocalFileSystem serverBaseFs = new(AppDataManager.BaseDirPath);
|
||||
|
||||
fsServerClient = horizon.CreatePrivilegedHorizonClient();
|
||||
var fsServer = new FileSystemServer(fsServerClient);
|
||||
@@ -207,7 +207,7 @@ namespace Ryujinx.HLE.FileSystem
|
||||
DeviceOperator = fsServerObjects.DeviceOperator,
|
||||
ExternalKeySet = KeySet.ExternalKeySet,
|
||||
FsCreators = fsServerObjects.FsCreators,
|
||||
RandomGenerator = randomGenerator
|
||||
RandomGenerator = randomGenerator,
|
||||
};
|
||||
|
||||
FileSystemServerInitializer.InitializeWithConfig(fsServerClient, fsServer, fsServerConfig);
|
||||
@@ -282,16 +282,28 @@ namespace Ryujinx.HLE.FileSystem
|
||||
public static Result FixExtraData(HorizonClient hos)
|
||||
{
|
||||
Result rc = GetSystemSaveList(hos, out List<ulong> systemSaveIds);
|
||||
if (rc.IsFailure()) return rc;
|
||||
if (rc.IsFailure())
|
||||
{
|
||||
return rc;
|
||||
}
|
||||
|
||||
rc = FixUnindexedSystemSaves(hos, systemSaveIds);
|
||||
if (rc.IsFailure()) return rc;
|
||||
if (rc.IsFailure())
|
||||
{
|
||||
return rc;
|
||||
}
|
||||
|
||||
rc = FixExtraDataInSpaceId(hos, SaveDataSpaceId.System);
|
||||
if (rc.IsFailure()) return rc;
|
||||
if (rc.IsFailure())
|
||||
{
|
||||
return rc;
|
||||
}
|
||||
|
||||
rc = FixExtraDataInSpaceId(hos, SaveDataSpaceId.User);
|
||||
if (rc.IsFailure()) return rc;
|
||||
if (rc.IsFailure())
|
||||
{
|
||||
return rc;
|
||||
}
|
||||
|
||||
return Result.Success;
|
||||
}
|
||||
@@ -303,15 +315,23 @@ namespace Ryujinx.HLE.FileSystem
|
||||
using var iterator = new UniqueRef<SaveDataIterator>();
|
||||
|
||||
Result rc = hos.Fs.OpenSaveDataIterator(ref iterator.Ref, spaceId);
|
||||
if (rc.IsFailure()) return rc;
|
||||
if (rc.IsFailure())
|
||||
{
|
||||
return rc;
|
||||
}
|
||||
|
||||
while (true)
|
||||
{
|
||||
rc = iterator.Get.ReadSaveDataInfo(out long count, info);
|
||||
if (rc.IsFailure()) return rc;
|
||||
if (rc.IsFailure())
|
||||
{
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (count == 0)
|
||||
{
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
@@ -351,7 +371,9 @@ namespace Ryujinx.HLE.FileSystem
|
||||
private static Result CreateSaveDataDirectory(HorizonClient hos, in SaveDataInfo info)
|
||||
{
|
||||
if (info.SpaceId != SaveDataSpaceId.User && info.SpaceId != SaveDataSpaceId.System)
|
||||
{
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
const string MountName = "SaveDir";
|
||||
var mountNameU8 = MountName.ToU8Span();
|
||||
@@ -360,11 +382,15 @@ namespace Ryujinx.HLE.FileSystem
|
||||
{
|
||||
SaveDataSpaceId.System => BisPartitionId.System,
|
||||
SaveDataSpaceId.User => BisPartitionId.User,
|
||||
_ => throw new ArgumentOutOfRangeException()
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(info), info.SpaceId, null),
|
||||
};
|
||||
|
||||
Result rc = hos.Fs.MountBis(mountNameU8, partitionId);
|
||||
if (rc.IsFailure()) return rc;
|
||||
if (rc.IsFailure())
|
||||
{
|
||||
return rc;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var path = $"{MountName}:/save/{info.SaveDataId:x16}".ToU8Span();
|
||||
@@ -391,28 +417,38 @@ namespace Ryujinx.HLE.FileSystem
|
||||
|
||||
var mountName = "system".ToU8Span();
|
||||
DirectoryHandle handle = default;
|
||||
List<ulong> localList = new List<ulong>();
|
||||
List<ulong> localList = new();
|
||||
|
||||
try
|
||||
{
|
||||
Result rc = hos.Fs.MountBis(mountName, BisPartitionId.System);
|
||||
if (rc.IsFailure()) return rc;
|
||||
if (rc.IsFailure())
|
||||
{
|
||||
return rc;
|
||||
}
|
||||
|
||||
rc = hos.Fs.OpenDirectory(out handle, "system:/save".ToU8Span(), OpenDirectoryMode.All);
|
||||
if (rc.IsFailure()) return rc;
|
||||
if (rc.IsFailure())
|
||||
{
|
||||
return rc;
|
||||
}
|
||||
|
||||
DirectoryEntry entry = new DirectoryEntry();
|
||||
DirectoryEntry entry = new();
|
||||
|
||||
while (true)
|
||||
{
|
||||
rc = hos.Fs.ReadDirectory(out long readCount, SpanHelpers.AsSpan(ref entry), handle);
|
||||
if (rc.IsFailure()) return rc;
|
||||
if (rc.IsFailure())
|
||||
{
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (readCount == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (Utf8Parser.TryParse(entry.Name, out ulong saveDataId, out int bytesRead, 'x') &&
|
||||
bytesRead == 16 && (long)saveDataId < 0)
|
||||
if (Utf8Parser.TryParse(entry.Name, out ulong saveDataId, out int bytesRead, 'x') && bytesRead == 16 && (long)saveDataId < 0)
|
||||
{
|
||||
localList.Add(saveDataId);
|
||||
}
|
||||
@@ -440,7 +476,7 @@ namespace Ryujinx.HLE.FileSystem
|
||||
// Only save data IDs added to SystemExtraDataFixInfo will be fixed.
|
||||
private static Result FixUnindexedSystemSaves(HorizonClient hos, List<ulong> existingSaveIds)
|
||||
{
|
||||
foreach (var fixInfo in SystemExtraDataFixInfo)
|
||||
foreach (var fixInfo in _systemExtraDataFixInfo)
|
||||
{
|
||||
if (!existingSaveIds.Contains(fixInfo.StaticSaveDataId))
|
||||
{
|
||||
@@ -472,7 +508,9 @@ namespace Ryujinx.HLE.FileSystem
|
||||
if (!rc.IsSuccess())
|
||||
{
|
||||
if (!ResultFs.TargetNotFound.Includes(rc))
|
||||
{
|
||||
return rc;
|
||||
}
|
||||
|
||||
// We'll reach this point only if the save data directory exists but it's not in the save data indexer.
|
||||
// Creating the save will add it to the indexer while leaving its existing contents intact.
|
||||
@@ -492,7 +530,7 @@ namespace Ryujinx.HLE.FileSystem
|
||||
OwnerId = info.OwnerId,
|
||||
Flags = info.Flags,
|
||||
DataSize = info.DataSize,
|
||||
JournalSize = info.JournalSize
|
||||
JournalSize = info.JournalSize,
|
||||
};
|
||||
|
||||
// Make a mask for writing the entire extra data
|
||||
@@ -507,9 +545,11 @@ namespace Ryujinx.HLE.FileSystem
|
||||
{
|
||||
wasFixNeeded = true;
|
||||
|
||||
Result rc = hos.Fs.Impl.ReadSaveDataFileSystemExtraData(out SaveDataExtraData extraData, info.SpaceId,
|
||||
info.SaveDataId);
|
||||
if (rc.IsFailure()) return rc;
|
||||
Result rc = hos.Fs.Impl.ReadSaveDataFileSystemExtraData(out SaveDataExtraData extraData, info.SpaceId, info.SaveDataId);
|
||||
if (rc.IsFailure())
|
||||
{
|
||||
return rc;
|
||||
}
|
||||
|
||||
// The extra data should have program ID or static save data ID set if it's valid.
|
||||
// We only try to fix the extra data if the info from the save data indexer has a program ID or static save data ID.
|
||||
@@ -543,7 +583,7 @@ namespace Ryujinx.HLE.FileSystem
|
||||
else
|
||||
{
|
||||
// Try to match the system save with one of the known saves
|
||||
foreach (ExtraDataFixInfo fixInfo in SystemExtraDataFixInfo)
|
||||
foreach (ExtraDataFixInfo fixInfo in _systemExtraDataFixInfo)
|
||||
{
|
||||
if (extraData.Attribute.StaticSaveDataId == fixInfo.StaticSaveDataId)
|
||||
{
|
||||
@@ -573,7 +613,7 @@ namespace Ryujinx.HLE.FileSystem
|
||||
public long JournalSize;
|
||||
}
|
||||
|
||||
private static readonly ExtraDataFixInfo[] SystemExtraDataFixInfo =
|
||||
private static readonly ExtraDataFixInfo[] _systemExtraDataFixInfo =
|
||||
{
|
||||
new ExtraDataFixInfo()
|
||||
{
|
||||
@@ -581,7 +621,7 @@ namespace Ryujinx.HLE.FileSystem
|
||||
OwnerId = 0x010000000000001F,
|
||||
Flags = SaveDataFlags.KeepAfterResettingSystemSaveDataWithoutUserSaveData,
|
||||
DataSize = 0x10000,
|
||||
JournalSize = 0x10000
|
||||
JournalSize = 0x10000,
|
||||
},
|
||||
new ExtraDataFixInfo()
|
||||
{
|
||||
@@ -589,12 +629,13 @@ namespace Ryujinx.HLE.FileSystem
|
||||
OwnerId = 0x0100000000001009,
|
||||
Flags = SaveDataFlags.None,
|
||||
DataSize = 0xC000,
|
||||
JournalSize = 0xC000
|
||||
}
|
||||
JournalSize = 0xC000,
|
||||
},
|
||||
};
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
GC.SuppressFinalize(this);
|
||||
Dispose(true);
|
||||
}
|
||||
|
||||
|
@@ -8,7 +8,7 @@ namespace Ryujinx.HLE.HOS.Applets
|
||||
{
|
||||
static class AppletManager
|
||||
{
|
||||
private static Dictionary<AppletId, Type> _appletMapping;
|
||||
private static readonly Dictionary<AppletId, Type> _appletMapping;
|
||||
|
||||
static AppletManager()
|
||||
{
|
||||
@@ -20,7 +20,7 @@ namespace Ryujinx.HLE.HOS.Applets
|
||||
{ AppletId.SoftwareKeyboard, typeof(SoftwareKeyboardApplet) },
|
||||
{ AppletId.LibAppletWeb, typeof(BrowserApplet) },
|
||||
{ AppletId.LibAppletShop, typeof(BrowserApplet) },
|
||||
{ AppletId.LibAppletOff, typeof(BrowserApplet) }
|
||||
{ AppletId.LibAppletOff, typeof(BrowserApplet) },
|
||||
};
|
||||
}
|
||||
|
||||
|
@@ -6,6 +6,6 @@
|
||||
Offline,
|
||||
Black,
|
||||
Share,
|
||||
Lobby
|
||||
Lobby,
|
||||
}
|
||||
}
|
||||
|
@@ -13,7 +13,6 @@ namespace Ryujinx.HLE.HOS.Applets.Browser
|
||||
public event EventHandler AppletStateChanged;
|
||||
|
||||
private AppletSession _normalSession;
|
||||
private AppletSession _interactiveSession;
|
||||
|
||||
private CommonArguments _commonArguments;
|
||||
private List<BrowserArgument> _arguments;
|
||||
@@ -29,7 +28,6 @@ namespace Ryujinx.HLE.HOS.Applets.Browser
|
||||
public ResultCode Start(AppletSession normalSession, AppletSession interactiveSession)
|
||||
{
|
||||
_normalSession = normalSession;
|
||||
_interactiveSession = interactiveSession;
|
||||
|
||||
_commonArguments = IApplet.ReadStruct<CommonArguments>(_normalSession.Pop());
|
||||
|
||||
@@ -48,15 +46,16 @@ namespace Ryujinx.HLE.HOS.Applets.Browser
|
||||
|
||||
if ((_commonArguments.AppletVersion >= 0x80000 && _shimKind == ShimKind.Web) || (_commonArguments.AppletVersion >= 0x30000 && _shimKind == ShimKind.Share))
|
||||
{
|
||||
List<BrowserOutput> result = new List<BrowserOutput>();
|
||||
|
||||
result.Add(new BrowserOutput(BrowserOutputType.ExitReason, (uint)WebExitReason.ExitButton));
|
||||
List<BrowserOutput> result = new()
|
||||
{
|
||||
new BrowserOutput(BrowserOutputType.ExitReason, (uint)WebExitReason.ExitButton),
|
||||
};
|
||||
|
||||
_normalSession.Push(BuildResponseNew(result));
|
||||
}
|
||||
else
|
||||
{
|
||||
WebCommonReturnValue result = new WebCommonReturnValue()
|
||||
WebCommonReturnValue result = new()
|
||||
{
|
||||
ExitReason = WebExitReason.ExitButton,
|
||||
};
|
||||
@@ -69,25 +68,22 @@ namespace Ryujinx.HLE.HOS.Applets.Browser
|
||||
return ResultCode.Success;
|
||||
}
|
||||
|
||||
private byte[] BuildResponseOld(WebCommonReturnValue result)
|
||||
{
|
||||
using (MemoryStream stream = MemoryStreamManager.Shared.GetStream())
|
||||
using (BinaryWriter writer = new BinaryWriter(stream))
|
||||
private static byte[] BuildResponseOld(WebCommonReturnValue result)
|
||||
{
|
||||
using MemoryStream stream = MemoryStreamManager.Shared.GetStream();
|
||||
using BinaryWriter writer = new(stream);
|
||||
writer.WriteStruct(result);
|
||||
|
||||
return stream.ToArray();
|
||||
}
|
||||
}
|
||||
private byte[] BuildResponseNew(List<BrowserOutput> outputArguments)
|
||||
{
|
||||
using (MemoryStream stream = MemoryStreamManager.Shared.GetStream())
|
||||
using (BinaryWriter writer = new BinaryWriter(stream))
|
||||
{
|
||||
using MemoryStream stream = MemoryStreamManager.Shared.GetStream();
|
||||
using BinaryWriter writer = new(stream);
|
||||
writer.WriteStruct(new WebArgHeader
|
||||
{
|
||||
Count = (ushort)outputArguments.Count,
|
||||
ShimKind = _shimKind
|
||||
ShimKind = _shimKind,
|
||||
});
|
||||
|
||||
foreach (BrowserOutput output in outputArguments)
|
||||
@@ -101,4 +97,3 @@ namespace Ryujinx.HLE.HOS.Applets.Browser
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -17,7 +17,7 @@ namespace Ryujinx.HLE.HOS.Applets.Browser
|
||||
Value = value;
|
||||
}
|
||||
|
||||
private static readonly Dictionary<WebArgTLVType, Type> _typeRegistry = new Dictionary<WebArgTLVType, Type>
|
||||
private static readonly Dictionary<WebArgTLVType, Type> _typeRegistry = new()
|
||||
{
|
||||
{ WebArgTLVType.InitialURL, typeof(string) },
|
||||
{ WebArgTLVType.CallbackUrl, typeof(string) },
|
||||
@@ -64,11 +64,11 @@ namespace Ryujinx.HLE.HOS.Applets.Browser
|
||||
|
||||
public static (ShimKind, List<BrowserArgument>) ParseArguments(ReadOnlySpan<byte> data)
|
||||
{
|
||||
List<BrowserArgument> browserArguments = new List<BrowserArgument>();
|
||||
List<BrowserArgument> browserArguments = new();
|
||||
|
||||
WebArgHeader header = IApplet.ReadStruct<WebArgHeader>(data.Slice(0, 8));
|
||||
WebArgHeader header = IApplet.ReadStruct<WebArgHeader>(data[..8]);
|
||||
|
||||
ReadOnlySpan<byte> rawTLVs = data.Slice(8);
|
||||
ReadOnlySpan<byte> rawTLVs = data[8..];
|
||||
|
||||
for (int i = 0; i < header.Count; i++)
|
||||
{
|
||||
@@ -77,7 +77,7 @@ namespace Ryujinx.HLE.HOS.Applets.Browser
|
||||
|
||||
browserArguments.Add(new BrowserArgument((WebArgTLVType)tlv.Type, tlvData.ToArray()));
|
||||
|
||||
rawTLVs = rawTLVs.Slice(Unsafe.SizeOf<WebArgTLV>() + tlv.Size);
|
||||
rawTLVs = rawTLVs[(Unsafe.SizeOf<WebArgTLV>() + tlv.Size)..];
|
||||
}
|
||||
|
||||
return (header.ShimKind, browserArguments);
|
||||
|
@@ -38,7 +38,7 @@ namespace Ryujinx.HLE.HOS.Applets.Browser
|
||||
writer.WriteStruct(new WebArgTLV
|
||||
{
|
||||
Type = (ushort)Type,
|
||||
Size = (ushort)Value.Length
|
||||
Size = (ushort)Value.Length,
|
||||
});
|
||||
|
||||
writer.Write(Value);
|
||||
|
@@ -9,6 +9,6 @@
|
||||
PostServiceName = 0x5,
|
||||
PostServiceNameSize = 0x6,
|
||||
PostId = 0x7,
|
||||
MediaPlayerAutoClosedByCompletion = 0x8
|
||||
MediaPlayerAutoClosedByCompletion = 0x8,
|
||||
}
|
||||
}
|
||||
|
@@ -4,6 +4,6 @@
|
||||
{
|
||||
OfflineHtmlPage = 1,
|
||||
ApplicationLegalInformation,
|
||||
SystemDataPage
|
||||
SystemDataPage,
|
||||
}
|
||||
}
|
||||
|
@@ -3,6 +3,6 @@
|
||||
enum LeftStickMode
|
||||
{
|
||||
Pointer = 0,
|
||||
Cursor
|
||||
Cursor,
|
||||
}
|
||||
}
|
||||
|
@@ -8,6 +8,6 @@
|
||||
Share,
|
||||
Web,
|
||||
Wifi,
|
||||
Lobby
|
||||
Lobby,
|
||||
}
|
||||
}
|
||||
|
@@ -57,6 +57,6 @@
|
||||
OverrideWebAudioVolume = 0x3F,
|
||||
OverrideMediaAudioVolume = 0x40,
|
||||
BootMode = 0x41,
|
||||
MediaPlayerUiEnabled = 0x43
|
||||
MediaPlayerUiEnabled = 0x43,
|
||||
}
|
||||
}
|
||||
|
@@ -6,6 +6,6 @@
|
||||
BackButton,
|
||||
Requested,
|
||||
LastUrl,
|
||||
ErrorDialog = 7
|
||||
ErrorDialog = 7,
|
||||
}
|
||||
}
|
||||
|
@@ -13,7 +13,7 @@ namespace Ryujinx.HLE.HOS.Applets
|
||||
{
|
||||
internal class ControllerApplet : IApplet
|
||||
{
|
||||
private Horizon _system;
|
||||
private readonly Horizon _system;
|
||||
|
||||
private AppletSession _normalSession;
|
||||
|
||||
@@ -65,7 +65,7 @@ namespace Ryujinx.HLE.HOS.Applets
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger.Stub?.PrintStub(LogClass.ServiceHid, $"ControllerSupportArg Version Unknown");
|
||||
Logger.Stub?.PrintStub(LogClass.ServiceHid, "ControllerSupportArg Version Unknown");
|
||||
|
||||
argHeader = IApplet.ReadStruct<ControllerSupportArgHeader>(controllerSupportArg); // Read just the header
|
||||
}
|
||||
@@ -82,17 +82,17 @@ namespace Ryujinx.HLE.HOS.Applets
|
||||
playerMin = playerMax = 1;
|
||||
}
|
||||
|
||||
int configuredCount = 0;
|
||||
PlayerIndex primaryIndex = PlayerIndex.Unknown;
|
||||
int configuredCount;
|
||||
PlayerIndex primaryIndex;
|
||||
while (!_system.Device.Hid.Npads.Validate(playerMin, playerMax, (ControllerType)privateArg.NpadStyleSet, out configuredCount, out primaryIndex))
|
||||
{
|
||||
ControllerAppletUiArgs uiArgs = new ControllerAppletUiArgs
|
||||
ControllerAppletUiArgs uiArgs = new()
|
||||
{
|
||||
PlayerCountMin = playerMin,
|
||||
PlayerCountMax = playerMax,
|
||||
SupportedStyles = (ControllerType)privateArg.NpadStyleSet,
|
||||
SupportedPlayers = _system.Device.Hid.Npads.GetSupportedPlayers(),
|
||||
IsDocked = _system.State.DockedMode
|
||||
IsDocked = _system.State.DockedMode,
|
||||
};
|
||||
|
||||
if (!_system.Device.UiHandler.DisplayMessageDialog(uiArgs))
|
||||
@@ -101,10 +101,10 @@ namespace Ryujinx.HLE.HOS.Applets
|
||||
}
|
||||
}
|
||||
|
||||
ControllerSupportResultInfo result = new ControllerSupportResultInfo
|
||||
ControllerSupportResultInfo result = new()
|
||||
{
|
||||
PlayerCount = (sbyte)configuredCount,
|
||||
SelectedId = (uint)GetNpadIdTypeFromIndex(primaryIndex)
|
||||
SelectedId = (uint)GetNpadIdTypeFromIndex(primaryIndex),
|
||||
};
|
||||
|
||||
Logger.Stub?.PrintStub(LogClass.ServiceHid, $"ControllerApplet ReturnResult {result.PlayerCount} {result.SelectedId}");
|
||||
@@ -122,26 +122,24 @@ namespace Ryujinx.HLE.HOS.Applets
|
||||
return ResultCode.Success;
|
||||
}
|
||||
|
||||
private byte[] BuildResponse(ControllerSupportResultInfo result)
|
||||
{
|
||||
using (MemoryStream stream = MemoryStreamManager.Shared.GetStream())
|
||||
using (BinaryWriter writer = new BinaryWriter(stream))
|
||||
private static byte[] BuildResponse(ControllerSupportResultInfo result)
|
||||
{
|
||||
using MemoryStream stream = MemoryStreamManager.Shared.GetStream();
|
||||
using BinaryWriter writer = new(stream);
|
||||
|
||||
writer.Write(MemoryMarshal.AsBytes(MemoryMarshal.CreateReadOnlySpan(ref result, Unsafe.SizeOf<ControllerSupportResultInfo>())));
|
||||
|
||||
return stream.ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
private byte[] BuildResponse()
|
||||
{
|
||||
using (MemoryStream stream = MemoryStreamManager.Shared.GetStream())
|
||||
using (BinaryWriter writer = new BinaryWriter(stream))
|
||||
private static byte[] BuildResponse()
|
||||
{
|
||||
using MemoryStream stream = MemoryStreamManager.Shared.GetStream();
|
||||
using BinaryWriter writer = new(stream);
|
||||
|
||||
writer.Write((ulong)ResultCode.Success);
|
||||
|
||||
return stream.ToArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -2,7 +2,7 @@ using System.Runtime.InteropServices;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Applets
|
||||
{
|
||||
#pragma warning disable CS0649
|
||||
#pragma warning disable CS0649 // Field is never assigned to
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct ControllerSupportArgHeader
|
||||
{
|
||||
|
@@ -1,6 +1,6 @@
|
||||
namespace Ryujinx.HLE.HOS.Applets
|
||||
{
|
||||
#pragma warning disable CS0649
|
||||
#pragma warning disable CS0649 // Field is never assigned to
|
||||
struct ControllerSupportArgPrivate
|
||||
{
|
||||
public uint PrivateSize;
|
||||
|
@@ -4,7 +4,7 @@ using System.Runtime.InteropServices;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Applets
|
||||
{
|
||||
#pragma warning disable CS0649
|
||||
#pragma warning disable CS0649 // Field is never assigned to
|
||||
// (8.0.0+ version)
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct ControllerSupportArgV7
|
||||
|
@@ -4,7 +4,7 @@ using System.Runtime.InteropServices;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Applets
|
||||
{
|
||||
#pragma warning disable CS0649
|
||||
#pragma warning disable CS0649 // Field is never assigned to
|
||||
// (1.0.0+ version)
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct ControllerSupportArgVPre7
|
||||
|
@@ -4,6 +4,6 @@ namespace Ryujinx.HLE.HOS.Applets
|
||||
{
|
||||
ShowControllerSupport = 0,
|
||||
ShowControllerStrapGuide = 1,
|
||||
ShowControllerFirmwareUpdate = 2
|
||||
ShowControllerFirmwareUpdate = 2,
|
||||
}
|
||||
}
|
@@ -3,7 +3,7 @@ using System.Runtime.InteropServices;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Applets
|
||||
{
|
||||
#pragma warning disable CS0649
|
||||
#pragma warning disable CS0649 // Field is never assigned to
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct ControllerSupportResultInfo
|
||||
{
|
||||
|
@@ -22,7 +22,7 @@ namespace Ryujinx.HLE.HOS.Applets.Error
|
||||
{
|
||||
private const long ErrorMessageBinaryTitleId = 0x0100000000000801;
|
||||
|
||||
private Horizon _horizon;
|
||||
private readonly Horizon _horizon;
|
||||
private AppletSession _normalSession;
|
||||
private CommonArguments _commonArguments;
|
||||
private ErrorCommonHeader _errorCommonHeader;
|
||||
@@ -63,7 +63,8 @@ namespace Ryujinx.HLE.HOS.Applets.Error
|
||||
|
||||
break;
|
||||
}
|
||||
default: throw new NotImplementedException($"ErrorApplet type {_errorCommonHeader.Type} is not implemented.");
|
||||
default:
|
||||
throw new NotImplementedException($"ErrorApplet type {_errorCommonHeader.Type} is not implemented.");
|
||||
}
|
||||
|
||||
AppletStateChanged?.Invoke(this, null);
|
||||
@@ -71,15 +72,16 @@ namespace Ryujinx.HLE.HOS.Applets.Error
|
||||
return ResultCode.Success;
|
||||
}
|
||||
|
||||
private (uint module, uint description) HexToResultCode(uint resultCode)
|
||||
private static (uint module, uint description) HexToResultCode(uint resultCode)
|
||||
{
|
||||
return ((resultCode & 0x1FF) + 2000, (resultCode >> 9) & 0x3FFF);
|
||||
}
|
||||
|
||||
private string SystemLanguageToLanguageKey(SystemLanguage systemLanguage)
|
||||
private static string SystemLanguageToLanguageKey(SystemLanguage systemLanguage)
|
||||
{
|
||||
return systemLanguage switch
|
||||
{
|
||||
#pragma warning disable IDE0055 // Disable formatting
|
||||
SystemLanguage.Japanese => "ja",
|
||||
SystemLanguage.AmericanEnglish => "en-US",
|
||||
SystemLanguage.French => "fr",
|
||||
@@ -98,7 +100,8 @@ namespace Ryujinx.HLE.HOS.Applets.Error
|
||||
SystemLanguage.SimplifiedChinese => "zh-Hans",
|
||||
SystemLanguage.TraditionalChinese => "zh-Hant",
|
||||
SystemLanguage.BrazilianPortuguese => "pt-BR",
|
||||
_ => "en-US"
|
||||
_ => "en-US",
|
||||
#pragma warning restore IDE0055
|
||||
};
|
||||
}
|
||||
|
||||
@@ -111,9 +114,8 @@ namespace Ryujinx.HLE.HOS.Applets.Error
|
||||
{
|
||||
string binaryTitleContentPath = _horizon.ContentManager.GetInstalledContentPath(ErrorMessageBinaryTitleId, StorageId.BuiltInSystem, NcaContentType.Data);
|
||||
|
||||
using (LibHac.Fs.IStorage ncaFileStream = new LocalStorage(_horizon.Device.FileSystem.SwitchPathToSystemPath(binaryTitleContentPath), FileAccess.Read, FileMode.Open))
|
||||
{
|
||||
Nca nca = new Nca(_horizon.Device.FileSystem.KeySet, ncaFileStream);
|
||||
using LibHac.Fs.IStorage ncaFileStream = new LocalStorage(FileSystem.VirtualFileSystem.SwitchPathToSystemPath(binaryTitleContentPath), FileAccess.Read, FileMode.Open);
|
||||
Nca nca = new(_horizon.Device.FileSystem.KeySet, ncaFileStream);
|
||||
IFileSystem romfs = nca.OpenFileSystem(NcaSectionType.Data, _horizon.FsIntegrityCheckLevel);
|
||||
string languageCode = SystemLanguageToLanguageKey(_horizon.State.DesiredSystemLanguage);
|
||||
string filePath = $"/{module}/{description:0000}/{languageCode}_{key}";
|
||||
@@ -123,7 +125,7 @@ namespace Ryujinx.HLE.HOS.Applets.Error
|
||||
using var binaryFile = new UniqueRef<IFile>();
|
||||
|
||||
romfs.OpenFile(ref binaryFile.Ref, filePath.ToU8Span(), OpenMode.Read).ThrowIfFailure();
|
||||
StreamReader reader = new StreamReader(binaryFile.Get.AsStream(), Encoding.Unicode);
|
||||
StreamReader reader = new(binaryFile.Get.AsStream(), Encoding.Unicode);
|
||||
|
||||
return CleanText(reader.ReadToEnd());
|
||||
}
|
||||
@@ -132,7 +134,6 @@ namespace Ryujinx.HLE.HOS.Applets.Error
|
||||
return "";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private string[] GetButtonsText(uint module, uint description, string key)
|
||||
{
|
||||
@@ -188,7 +189,7 @@ namespace Ryujinx.HLE.HOS.Applets.Error
|
||||
string messageText = Encoding.ASCII.GetString(messageTextBuffer.TakeWhile(b => !b.Equals(0)).ToArray());
|
||||
string detailsText = Encoding.ASCII.GetString(detailsTextBuffer.TakeWhile(b => !b.Equals(0)).ToArray());
|
||||
|
||||
List<string> buttons = new List<string>();
|
||||
List<string> buttons = new();
|
||||
|
||||
// TODO: Handle the LanguageCode to return the translated "OK" and "Details".
|
||||
|
||||
|
@@ -8,6 +8,6 @@
|
||||
ErrorEulaArg,
|
||||
ErrorPctlArg,
|
||||
ErrorRecordArg,
|
||||
SystemUpdateEulaArg = 8
|
||||
SystemUpdateEulaArg = 8,
|
||||
}
|
||||
}
|
@@ -8,10 +8,12 @@ namespace Ryujinx.HLE.HOS.Applets
|
||||
{
|
||||
internal class PlayerSelectApplet : IApplet
|
||||
{
|
||||
private Horizon _system;
|
||||
private readonly Horizon _system;
|
||||
|
||||
private AppletSession _normalSession;
|
||||
#pragma warning disable IDE0052 // Remove unread private member
|
||||
private AppletSession _interactiveSession;
|
||||
#pragma warning restore IDE0052
|
||||
|
||||
public event EventHandler AppletStateChanged;
|
||||
|
||||
@@ -44,9 +46,9 @@ namespace Ryujinx.HLE.HOS.Applets
|
||||
{
|
||||
UserProfile currentUser = _system.AccountManager.LastOpenedUser;
|
||||
|
||||
using (MemoryStream stream = MemoryStreamManager.Shared.GetStream())
|
||||
using (BinaryWriter writer = new BinaryWriter(stream))
|
||||
{
|
||||
using MemoryStream stream = MemoryStreamManager.Shared.GetStream();
|
||||
using BinaryWriter writer = new(stream);
|
||||
|
||||
writer.Write((ulong)PlayerSelectResult.Success);
|
||||
|
||||
currentUser.UserId.Write(writer);
|
||||
@@ -55,4 +57,3 @@ namespace Ryujinx.HLE.HOS.Applets
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -3,6 +3,6 @@
|
||||
enum PlayerSelectResult : ulong
|
||||
{
|
||||
Success = 0,
|
||||
Failure = 2
|
||||
Failure = 2,
|
||||
}
|
||||
}
|
||||
|
@@ -13,6 +13,6 @@
|
||||
/// <summary>
|
||||
/// Position the cursor at the end of the text
|
||||
/// </summary>
|
||||
End
|
||||
End,
|
||||
}
|
||||
}
|
||||
|
@@ -43,6 +43,6 @@
|
||||
/// <summary>
|
||||
/// [8.0.0+] Request the keyboard applet to use the MovedCursorV2 response when notifying changes in cursor position.
|
||||
/// </summary>
|
||||
UseMovedCursorV2 = 0xE
|
||||
UseMovedCursorV2 = 0xE,
|
||||
}
|
||||
}
|
||||
|
@@ -88,6 +88,6 @@
|
||||
/// <summary>
|
||||
/// Same as MovedCursorUtf8, but with additional fields.
|
||||
/// </summary>
|
||||
MovedCursorUtf8V2 = 0x10
|
||||
MovedCursorUtf8V2 = 0x10,
|
||||
}
|
||||
}
|
||||
|
@@ -28,6 +28,6 @@
|
||||
/// <summary>
|
||||
/// software keyboard is transitioning to a hidden state because the user pressed either OK or Cancel.
|
||||
/// </summary>
|
||||
Disappearing = 0x4
|
||||
Disappearing = 0x4,
|
||||
}
|
||||
}
|
||||
|
@@ -60,56 +60,52 @@ namespace Ryujinx.HLE.HOS.Applets.SoftwareKeyboard
|
||||
{
|
||||
uint resSize = 2 * sizeof(uint) + 0x1;
|
||||
|
||||
using (MemoryStream stream = new MemoryStream(new byte[resSize]))
|
||||
using (BinaryWriter writer = new BinaryWriter(stream))
|
||||
{
|
||||
using MemoryStream stream = new(new byte[resSize]);
|
||||
using BinaryWriter writer = new(stream);
|
||||
|
||||
BeginResponse(state, InlineKeyboardResponse.FinishedInitialize, writer);
|
||||
writer.Write((byte)1); // Data (ignored by the program)
|
||||
|
||||
return stream.ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
public static byte[] Default(InlineKeyboardState state)
|
||||
{
|
||||
uint resSize = 2 * sizeof(uint);
|
||||
|
||||
using (MemoryStream stream = new MemoryStream(new byte[resSize]))
|
||||
using (BinaryWriter writer = new BinaryWriter(stream))
|
||||
{
|
||||
using MemoryStream stream = new(new byte[resSize]);
|
||||
using BinaryWriter writer = new(stream);
|
||||
|
||||
BeginResponse(state, InlineKeyboardResponse.Default, writer);
|
||||
|
||||
return stream.ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
public static byte[] ChangedString(string text, uint cursor, InlineKeyboardState state)
|
||||
{
|
||||
uint resSize = 6 * sizeof(uint) + MaxStrLenUTF16;
|
||||
|
||||
using (MemoryStream stream = new MemoryStream(new byte[resSize]))
|
||||
using (BinaryWriter writer = new BinaryWriter(stream))
|
||||
{
|
||||
using MemoryStream stream = new(new byte[resSize]);
|
||||
using BinaryWriter writer = new(stream);
|
||||
|
||||
BeginResponse(state, InlineKeyboardResponse.ChangedString, writer);
|
||||
WriteStringWithCursor(text, cursor, writer, MaxStrLenUTF16, Encoding.Unicode, true);
|
||||
|
||||
return stream.ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
public static byte[] MovedCursor(string text, uint cursor, InlineKeyboardState state)
|
||||
{
|
||||
uint resSize = 4 * sizeof(uint) + MaxStrLenUTF16;
|
||||
|
||||
using (MemoryStream stream = new MemoryStream(new byte[resSize]))
|
||||
using (BinaryWriter writer = new BinaryWriter(stream))
|
||||
{
|
||||
using MemoryStream stream = new(new byte[resSize]);
|
||||
using BinaryWriter writer = new(stream);
|
||||
|
||||
BeginResponse(state, InlineKeyboardResponse.MovedCursor, writer);
|
||||
WriteStringWithCursor(text, cursor, writer, MaxStrLenUTF16, Encoding.Unicode, false);
|
||||
|
||||
return stream.ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
public static byte[] MovedTab(string text, uint cursor, InlineKeyboardState state)
|
||||
{
|
||||
@@ -117,176 +113,164 @@ namespace Ryujinx.HLE.HOS.Applets.SoftwareKeyboard
|
||||
|
||||
uint resSize = 4 * sizeof(uint) + MaxStrLenUTF16;
|
||||
|
||||
using (MemoryStream stream = new MemoryStream(new byte[resSize]))
|
||||
using (BinaryWriter writer = new BinaryWriter(stream))
|
||||
{
|
||||
using MemoryStream stream = new(new byte[resSize]);
|
||||
using BinaryWriter writer = new(stream);
|
||||
|
||||
BeginResponse(state, InlineKeyboardResponse.MovedTab, writer);
|
||||
WriteStringWithCursor(text, cursor, writer, MaxStrLenUTF16, Encoding.Unicode, false);
|
||||
|
||||
return stream.ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
public static byte[] DecidedEnter(string text, InlineKeyboardState state)
|
||||
{
|
||||
uint resSize = 3 * sizeof(uint) + MaxStrLenUTF16;
|
||||
|
||||
using (MemoryStream stream = new MemoryStream(new byte[resSize]))
|
||||
using (BinaryWriter writer = new BinaryWriter(stream))
|
||||
{
|
||||
using MemoryStream stream = new(new byte[resSize]);
|
||||
using BinaryWriter writer = new(stream);
|
||||
|
||||
BeginResponse(state, InlineKeyboardResponse.DecidedEnter, writer);
|
||||
WriteString(text, writer, MaxStrLenUTF16, Encoding.Unicode);
|
||||
|
||||
return stream.ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
public static byte[] DecidedCancel(InlineKeyboardState state)
|
||||
{
|
||||
uint resSize = 2 * sizeof(uint);
|
||||
|
||||
using (MemoryStream stream = new MemoryStream(new byte[resSize]))
|
||||
using (BinaryWriter writer = new BinaryWriter(stream))
|
||||
{
|
||||
using MemoryStream stream = new(new byte[resSize]);
|
||||
using BinaryWriter writer = new(stream);
|
||||
|
||||
BeginResponse(state, InlineKeyboardResponse.DecidedCancel, writer);
|
||||
|
||||
return stream.ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
public static byte[] ChangedStringUtf8(string text, uint cursor, InlineKeyboardState state)
|
||||
{
|
||||
uint resSize = 6 * sizeof(uint) + MaxStrLenUTF8;
|
||||
|
||||
using (MemoryStream stream = new MemoryStream(new byte[resSize]))
|
||||
using (BinaryWriter writer = new BinaryWriter(stream))
|
||||
{
|
||||
using MemoryStream stream = new(new byte[resSize]);
|
||||
using BinaryWriter writer = new(stream);
|
||||
|
||||
BeginResponse(state, InlineKeyboardResponse.ChangedStringUtf8, writer);
|
||||
WriteStringWithCursor(text, cursor, writer, MaxStrLenUTF8, Encoding.UTF8, true);
|
||||
|
||||
return stream.ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
public static byte[] MovedCursorUtf8(string text, uint cursor, InlineKeyboardState state)
|
||||
{
|
||||
uint resSize = 4 * sizeof(uint) + MaxStrLenUTF8;
|
||||
|
||||
using (MemoryStream stream = new MemoryStream(new byte[resSize]))
|
||||
using (BinaryWriter writer = new BinaryWriter(stream))
|
||||
{
|
||||
using MemoryStream stream = new(new byte[resSize]);
|
||||
using BinaryWriter writer = new(stream);
|
||||
|
||||
BeginResponse(state, InlineKeyboardResponse.MovedCursorUtf8, writer);
|
||||
WriteStringWithCursor(text, cursor, writer, MaxStrLenUTF8, Encoding.UTF8, false);
|
||||
|
||||
return stream.ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
public static byte[] DecidedEnterUtf8(string text, InlineKeyboardState state)
|
||||
{
|
||||
uint resSize = 3 * sizeof(uint) + MaxStrLenUTF8;
|
||||
|
||||
using (MemoryStream stream = new MemoryStream(new byte[resSize]))
|
||||
using (BinaryWriter writer = new BinaryWriter(stream))
|
||||
{
|
||||
using MemoryStream stream = new(new byte[resSize]);
|
||||
using BinaryWriter writer = new(stream);
|
||||
|
||||
BeginResponse(state, InlineKeyboardResponse.DecidedEnterUtf8, writer);
|
||||
WriteString(text, writer, MaxStrLenUTF8, Encoding.UTF8);
|
||||
|
||||
return stream.ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
public static byte[] UnsetCustomizeDic(InlineKeyboardState state)
|
||||
{
|
||||
uint resSize = 2 * sizeof(uint);
|
||||
|
||||
using (MemoryStream stream = new MemoryStream(new byte[resSize]))
|
||||
using (BinaryWriter writer = new BinaryWriter(stream))
|
||||
{
|
||||
using MemoryStream stream = new(new byte[resSize]);
|
||||
using BinaryWriter writer = new(stream);
|
||||
|
||||
BeginResponse(state, InlineKeyboardResponse.UnsetCustomizeDic, writer);
|
||||
|
||||
return stream.ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
public static byte[] ReleasedUserWordInfo(InlineKeyboardState state)
|
||||
{
|
||||
uint resSize = 2 * sizeof(uint);
|
||||
|
||||
using (MemoryStream stream = new MemoryStream(new byte[resSize]))
|
||||
using (BinaryWriter writer = new BinaryWriter(stream))
|
||||
{
|
||||
using MemoryStream stream = new(new byte[resSize]);
|
||||
using BinaryWriter writer = new(stream);
|
||||
|
||||
BeginResponse(state, InlineKeyboardResponse.ReleasedUserWordInfo, writer);
|
||||
|
||||
return stream.ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
public static byte[] UnsetCustomizedDictionaries(InlineKeyboardState state)
|
||||
{
|
||||
uint resSize = 2 * sizeof(uint);
|
||||
|
||||
using (MemoryStream stream = new MemoryStream(new byte[resSize]))
|
||||
using (BinaryWriter writer = new BinaryWriter(stream))
|
||||
{
|
||||
using MemoryStream stream = new(new byte[resSize]);
|
||||
using BinaryWriter writer = new(stream);
|
||||
|
||||
BeginResponse(state, InlineKeyboardResponse.UnsetCustomizedDictionaries, writer);
|
||||
|
||||
return stream.ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
public static byte[] ChangedStringV2(string text, uint cursor, InlineKeyboardState state)
|
||||
{
|
||||
uint resSize = 6 * sizeof(uint) + MaxStrLenUTF16 + 0x1;
|
||||
|
||||
using (MemoryStream stream = new MemoryStream(new byte[resSize]))
|
||||
using (BinaryWriter writer = new BinaryWriter(stream))
|
||||
{
|
||||
using MemoryStream stream = new(new byte[resSize]);
|
||||
using BinaryWriter writer = new(stream);
|
||||
|
||||
BeginResponse(state, InlineKeyboardResponse.ChangedStringV2, writer);
|
||||
WriteStringWithCursor(text, cursor, writer, MaxStrLenUTF16, Encoding.Unicode, true);
|
||||
writer.Write((byte)0); // Flag == 0
|
||||
|
||||
return stream.ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
public static byte[] MovedCursorV2(string text, uint cursor, InlineKeyboardState state)
|
||||
{
|
||||
uint resSize = 4 * sizeof(uint) + MaxStrLenUTF16 + 0x1;
|
||||
|
||||
using (MemoryStream stream = new MemoryStream(new byte[resSize]))
|
||||
using (BinaryWriter writer = new BinaryWriter(stream))
|
||||
{
|
||||
using MemoryStream stream = new(new byte[resSize]);
|
||||
using BinaryWriter writer = new(stream);
|
||||
|
||||
BeginResponse(state, InlineKeyboardResponse.MovedCursorV2, writer);
|
||||
WriteStringWithCursor(text, cursor, writer, MaxStrLenUTF16, Encoding.Unicode, false);
|
||||
writer.Write((byte)0); // Flag == 0
|
||||
|
||||
return stream.ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
public static byte[] ChangedStringUtf8V2(string text, uint cursor, InlineKeyboardState state)
|
||||
{
|
||||
uint resSize = 6 * sizeof(uint) + MaxStrLenUTF8 + 0x1;
|
||||
|
||||
using (MemoryStream stream = new MemoryStream(new byte[resSize]))
|
||||
using (BinaryWriter writer = new BinaryWriter(stream))
|
||||
{
|
||||
using MemoryStream stream = new(new byte[resSize]);
|
||||
using BinaryWriter writer = new(stream);
|
||||
|
||||
BeginResponse(state, InlineKeyboardResponse.ChangedStringUtf8V2, writer);
|
||||
WriteStringWithCursor(text, cursor, writer, MaxStrLenUTF8, Encoding.UTF8, true);
|
||||
writer.Write((byte)0); // Flag == 0
|
||||
|
||||
return stream.ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
public static byte[] MovedCursorUtf8V2(string text, uint cursor, InlineKeyboardState state)
|
||||
{
|
||||
uint resSize = 4 * sizeof(uint) + MaxStrLenUTF8 + 0x1;
|
||||
|
||||
using (MemoryStream stream = new MemoryStream(new byte[resSize]))
|
||||
using (BinaryWriter writer = new BinaryWriter(stream))
|
||||
{
|
||||
using MemoryStream stream = new(new byte[resSize]);
|
||||
using BinaryWriter writer = new(stream);
|
||||
|
||||
BeginResponse(state, InlineKeyboardResponse.MovedCursorUtf8V2, writer);
|
||||
WriteStringWithCursor(text, cursor, writer, MaxStrLenUTF8, Encoding.UTF8, false);
|
||||
writer.Write((byte)0); // Flag == 0
|
||||
@@ -295,4 +279,3 @@ namespace Ryujinx.HLE.HOS.Applets.SoftwareKeyboard
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -13,6 +13,6 @@
|
||||
/// <summary>
|
||||
/// Displays the text entry area as a multi-line field.
|
||||
/// </summary>
|
||||
MultiLine
|
||||
MultiLine,
|
||||
}
|
||||
}
|
||||
|
@@ -51,6 +51,6 @@ namespace Ryujinx.HLE.HOS.Applets.SoftwareKeyboard
|
||||
/// <summary>
|
||||
/// Prohibits characters outside of those allowed in Mii Nicknames.
|
||||
/// </summary>
|
||||
Username = 1 << 8
|
||||
Username = 1 << 8,
|
||||
}
|
||||
}
|
||||
|
@@ -21,6 +21,6 @@ namespace Ryujinx.HLE.HOS.Applets.SoftwareKeyboard
|
||||
DisableSeGroup = 0x4000,
|
||||
SetBackspaceEnabled = 0x8000,
|
||||
AppearTrigger = 0x10000,
|
||||
MustShow = Appear | SetInputText | AppearTrigger
|
||||
MustShow = Appear | SetInputText | AppearTrigger,
|
||||
}
|
||||
}
|
||||
|
@@ -7,6 +7,6 @@
|
||||
{
|
||||
None = 0,
|
||||
Auto = 1,
|
||||
Forced = 2
|
||||
Forced = 2,
|
||||
}
|
||||
}
|
||||
|
@@ -13,6 +13,6 @@
|
||||
/// <summary>
|
||||
/// Hide input characters.
|
||||
/// </summary>
|
||||
Enabled
|
||||
Enabled,
|
||||
}
|
||||
}
|
||||
|
@@ -85,33 +85,34 @@ namespace Ryujinx.HLE.HOS.Applets.SoftwareKeyboard
|
||||
|
||||
public SoftwareKeyboardAppearEx ToExtended()
|
||||
{
|
||||
SoftwareKeyboardAppearEx appear = new SoftwareKeyboardAppearEx();
|
||||
|
||||
appear.KeyboardMode = KeyboardMode;
|
||||
appear.OkText = OkText;
|
||||
appear.LeftOptionalSymbolKey = LeftOptionalSymbolKey;
|
||||
appear.RightOptionalSymbolKey = RightOptionalSymbolKey;
|
||||
appear.PredictionEnabled = PredictionEnabled;
|
||||
appear.CancelButtonDisabled = CancelButtonDisabled;
|
||||
appear.InvalidChars = InvalidChars;
|
||||
appear.TextMaxLength = TextMaxLength;
|
||||
appear.TextMinLength = TextMinLength;
|
||||
appear.UseNewLine = UseNewLine;
|
||||
appear.MiniaturizationMode = MiniaturizationMode;
|
||||
appear.Reserved1 = Reserved1;
|
||||
appear.Reserved2 = Reserved2;
|
||||
appear.InvalidButtons = InvalidButtons;
|
||||
appear.UseSaveData = UseSaveData;
|
||||
appear.Reserved3 = Reserved3;
|
||||
appear.Reserved4 = Reserved4;
|
||||
appear.Reserved5 = Reserved5;
|
||||
appear.Uid0 = Reserved6;
|
||||
appear.Uid1 = Reserved7;
|
||||
appear.SamplingNumber = 0;
|
||||
appear.Reserved6 = 0;
|
||||
appear.Reserved7 = 0;
|
||||
appear.Reserved8 = 0;
|
||||
appear.Reserved9 = 0;
|
||||
SoftwareKeyboardAppearEx appear = new()
|
||||
{
|
||||
KeyboardMode = KeyboardMode,
|
||||
OkText = OkText,
|
||||
LeftOptionalSymbolKey = LeftOptionalSymbolKey,
|
||||
RightOptionalSymbolKey = RightOptionalSymbolKey,
|
||||
PredictionEnabled = PredictionEnabled,
|
||||
CancelButtonDisabled = CancelButtonDisabled,
|
||||
InvalidChars = InvalidChars,
|
||||
TextMaxLength = TextMaxLength,
|
||||
TextMinLength = TextMinLength,
|
||||
UseNewLine = UseNewLine,
|
||||
MiniaturizationMode = MiniaturizationMode,
|
||||
Reserved1 = Reserved1,
|
||||
Reserved2 = Reserved2,
|
||||
InvalidButtons = InvalidButtons,
|
||||
UseSaveData = UseSaveData,
|
||||
Reserved3 = Reserved3,
|
||||
Reserved4 = Reserved4,
|
||||
Reserved5 = Reserved5,
|
||||
Uid0 = Reserved6,
|
||||
Uid1 = Reserved7,
|
||||
SamplingNumber = 0,
|
||||
Reserved6 = 0,
|
||||
Reserved7 = 0,
|
||||
Reserved8 = 0,
|
||||
Reserved9 = 0,
|
||||
};
|
||||
|
||||
return appear;
|
||||
}
|
||||
|
@@ -42,9 +42,11 @@ namespace Ryujinx.HLE.HOS.Applets
|
||||
private SoftwareKeyboardConfig _keyboardForegroundConfig;
|
||||
|
||||
// Configuration for background (inline) mode.
|
||||
#pragma warning disable IDE0052 // Remove unread private member
|
||||
private SoftwareKeyboardInitialize _keyboardBackgroundInitialize;
|
||||
private SoftwareKeyboardCustomizeDic _keyboardBackgroundDic;
|
||||
private SoftwareKeyboardDictSet _keyboardBackgroundDictSet;
|
||||
#pragma warning restore IDE0052
|
||||
private SoftwareKeyboardUserWord[] _keyboardBackgroundUserWords;
|
||||
|
||||
private byte[] _transferMemory;
|
||||
@@ -217,7 +219,7 @@ namespace Ryujinx.HLE.HOS.Applets
|
||||
_keyboardForegroundConfig.SubmitText : "OK"),
|
||||
StringLengthMin = _keyboardForegroundConfig.StringLengthMin,
|
||||
StringLengthMax = _keyboardForegroundConfig.StringLengthMax,
|
||||
InitialText = initialText
|
||||
InitialText = initialText,
|
||||
};
|
||||
|
||||
_lastResult = _device.UiHandler.DisplayInputDialog(args, out _textValue) ? KeyboardResult.Accept : KeyboardResult.Cancel;
|
||||
@@ -237,7 +239,7 @@ namespace Ryujinx.HLE.HOS.Applets
|
||||
// we truncate it.
|
||||
if (_textValue.Length > _keyboardForegroundConfig.StringLengthMax)
|
||||
{
|
||||
_textValue = _textValue.Substring(0, _keyboardForegroundConfig.StringLengthMax);
|
||||
_textValue = _textValue[.._keyboardForegroundConfig.StringLengthMax];
|
||||
}
|
||||
|
||||
// Does the application want to validate the text itself?
|
||||
@@ -319,9 +321,9 @@ namespace Ryujinx.HLE.HOS.Applets
|
||||
// request from the game, this is because the inline keyboard is expected to
|
||||
// keep running in the background sending data by itself.
|
||||
|
||||
using (MemoryStream stream = new MemoryStream(data))
|
||||
using (BinaryReader reader = new BinaryReader(stream))
|
||||
{
|
||||
using MemoryStream stream = new(data);
|
||||
using BinaryReader reader = new(stream);
|
||||
|
||||
var request = (InlineKeyboardRequest)reader.ReadUInt32();
|
||||
|
||||
long remaining;
|
||||
@@ -486,11 +488,10 @@ namespace Ryujinx.HLE.HOS.Applets
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void ActivateFrontend()
|
||||
{
|
||||
Logger.Debug?.Print(LogClass.ServiceAm, $"Activating software keyboard frontend");
|
||||
Logger.Debug?.Print(LogClass.ServiceAm, "Activating software keyboard frontend");
|
||||
|
||||
_inputMode = KeyboardInputMode.ControllerAndKeyboard;
|
||||
|
||||
@@ -509,7 +510,7 @@ namespace Ryujinx.HLE.HOS.Applets
|
||||
|
||||
private void DeactivateFrontend()
|
||||
{
|
||||
Logger.Debug?.Print(LogClass.ServiceAm, $"Deactivating software keyboard frontend");
|
||||
Logger.Debug?.Print(LogClass.ServiceAm, "Deactivating software keyboard frontend");
|
||||
|
||||
_inputMode = KeyboardInputMode.ControllerAndKeyboard;
|
||||
_canAcceptController = false;
|
||||
@@ -520,7 +521,7 @@ namespace Ryujinx.HLE.HOS.Applets
|
||||
|
||||
private void DestroyFrontend()
|
||||
{
|
||||
Logger.Debug?.Print(LogClass.ServiceAm, $"Destroying software keyboard frontend");
|
||||
Logger.Debug?.Print(LogClass.ServiceAm, "Destroying software keyboard frontend");
|
||||
|
||||
_keyboardRenderer?.Dispose();
|
||||
_keyboardRenderer = null;
|
||||
@@ -575,7 +576,7 @@ namespace Ryujinx.HLE.HOS.Applets
|
||||
if (text.Length > MaxUiTextSize)
|
||||
{
|
||||
// Limit the text size and change it back.
|
||||
text = text.Substring(0, MaxUiTextSize);
|
||||
text = text[..MaxUiTextSize];
|
||||
cursorBegin = Math.Min(cursorBegin, MaxUiTextSize);
|
||||
cursorEnd = Math.Min(cursorEnd, MaxUiTextSize);
|
||||
|
||||
@@ -734,9 +735,8 @@ namespace Ryujinx.HLE.HOS.Applets
|
||||
{
|
||||
int bufferSize = interactive ? InteractiveBufferSize : StandardBufferSize;
|
||||
|
||||
using (MemoryStream stream = new MemoryStream(new byte[bufferSize]))
|
||||
using (BinaryWriter writer = new BinaryWriter(stream))
|
||||
{
|
||||
using MemoryStream stream = new(new byte[bufferSize]);
|
||||
using BinaryWriter writer = new(stream);
|
||||
byte[] output = _encoding.GetBytes(_textValue);
|
||||
|
||||
if (!interactive)
|
||||
@@ -762,7 +762,6 @@ namespace Ryujinx.HLE.HOS.Applets
|
||||
_interactiveSession.Push(stream.ToArray());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes all Unicode control code characters from the input string.
|
||||
@@ -787,7 +786,7 @@ namespace Ryujinx.HLE.HOS.Applets
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
StringBuilder sb = new StringBuilder(capacity: input.Length);
|
||||
StringBuilder sb = new(capacity: input.Length);
|
||||
foreach (char c in input)
|
||||
{
|
||||
if (!char.IsControl(c))
|
||||
|
@@ -174,45 +174,46 @@ namespace Ryujinx.HLE.HOS.Applets.SoftwareKeyboard
|
||||
|
||||
public SoftwareKeyboardCalcEx ToExtended()
|
||||
{
|
||||
SoftwareKeyboardCalcEx calc = new SoftwareKeyboardCalcEx();
|
||||
|
||||
calc.Unknown = Unknown;
|
||||
calc.Size = Size;
|
||||
calc.Unknown1 = Unknown1;
|
||||
calc.Unknown2 = Unknown2;
|
||||
calc.Flags = Flags;
|
||||
calc.Initialize = Initialize;
|
||||
calc.Volume = Volume;
|
||||
calc.CursorPos = CursorPos;
|
||||
calc.Appear = Appear.ToExtended();
|
||||
calc.InputText = InputText;
|
||||
calc.UseUtf8 = UseUtf8;
|
||||
calc.Unknown3 = Unknown3;
|
||||
calc.BackspaceEnabled = BackspaceEnabled;
|
||||
calc.Unknown4 = Unknown4;
|
||||
calc.Unknown5 = Unknown5;
|
||||
calc.KeytopAsFloating = KeytopAsFloating;
|
||||
calc.FooterScalable = FooterScalable;
|
||||
calc.AlphaEnabledInInputMode = AlphaEnabledInInputMode;
|
||||
calc.InputModeFadeType = InputModeFadeType;
|
||||
calc.TouchDisabled = TouchDisabled;
|
||||
calc.HardwareKeyboardDisabled = HardwareKeyboardDisabled;
|
||||
calc.Unknown6 = Unknown6;
|
||||
calc.Unknown7 = Unknown7;
|
||||
calc.KeytopScale0 = KeytopScale0;
|
||||
calc.KeytopScale1 = KeytopScale1;
|
||||
calc.KeytopTranslate0 = KeytopTranslate0;
|
||||
calc.KeytopTranslate1 = KeytopTranslate1;
|
||||
calc.KeytopBgAlpha = KeytopBgAlpha;
|
||||
calc.FooterBgAlpha = FooterBgAlpha;
|
||||
calc.BalloonScale = BalloonScale;
|
||||
calc.Unknown8 = Unknown8;
|
||||
calc.Unknown9 = Unknown9;
|
||||
calc.Unknown10 = Unknown10;
|
||||
calc.Unknown11 = Unknown11;
|
||||
calc.SeGroup = SeGroup;
|
||||
calc.TriggerFlag = TriggerFlag;
|
||||
calc.Trigger = Trigger;
|
||||
SoftwareKeyboardCalcEx calc = new()
|
||||
{
|
||||
Unknown = Unknown,
|
||||
Size = Size,
|
||||
Unknown1 = Unknown1,
|
||||
Unknown2 = Unknown2,
|
||||
Flags = Flags,
|
||||
Initialize = Initialize,
|
||||
Volume = Volume,
|
||||
CursorPos = CursorPos,
|
||||
Appear = Appear.ToExtended(),
|
||||
InputText = InputText,
|
||||
UseUtf8 = UseUtf8,
|
||||
Unknown3 = Unknown3,
|
||||
BackspaceEnabled = BackspaceEnabled,
|
||||
Unknown4 = Unknown4,
|
||||
Unknown5 = Unknown5,
|
||||
KeytopAsFloating = KeytopAsFloating,
|
||||
FooterScalable = FooterScalable,
|
||||
AlphaEnabledInInputMode = AlphaEnabledInInputMode,
|
||||
InputModeFadeType = InputModeFadeType,
|
||||
TouchDisabled = TouchDisabled,
|
||||
HardwareKeyboardDisabled = HardwareKeyboardDisabled,
|
||||
Unknown6 = Unknown6,
|
||||
Unknown7 = Unknown7,
|
||||
KeytopScale0 = KeytopScale0,
|
||||
KeytopScale1 = KeytopScale1,
|
||||
KeytopTranslate0 = KeytopTranslate0,
|
||||
KeytopTranslate1 = KeytopTranslate1,
|
||||
KeytopBgAlpha = KeytopBgAlpha,
|
||||
FooterBgAlpha = FooterBgAlpha,
|
||||
BalloonScale = BalloonScale,
|
||||
Unknown8 = Unknown8,
|
||||
Unknown9 = Unknown9,
|
||||
Unknown10 = Unknown10,
|
||||
Unknown11 = Unknown11,
|
||||
SeGroup = SeGroup,
|
||||
TriggerFlag = TriggerFlag,
|
||||
Trigger = Trigger,
|
||||
};
|
||||
|
||||
return calc;
|
||||
}
|
||||
|
@@ -15,11 +15,11 @@ namespace Ryujinx.HLE.HOS.Applets.SoftwareKeyboard
|
||||
|
||||
private readonly object _stateLock = new();
|
||||
|
||||
private SoftwareKeyboardUiState _state = new SoftwareKeyboardUiState();
|
||||
private SoftwareKeyboardRendererBase _renderer;
|
||||
private readonly SoftwareKeyboardUiState _state = new();
|
||||
private readonly SoftwareKeyboardRendererBase _renderer;
|
||||
|
||||
private TimedAction _textBoxBlinkTimedAction = new TimedAction();
|
||||
private TimedAction _renderAction = new TimedAction();
|
||||
private readonly TimedAction _textBoxBlinkTimedAction = new();
|
||||
private readonly TimedAction _renderAction = new();
|
||||
|
||||
public SoftwareKeyboardRenderer(IHostUiTheme uiTheme)
|
||||
{
|
||||
@@ -47,7 +47,7 @@ namespace Ryujinx.HLE.HOS.Applets.SoftwareKeyboard
|
||||
|
||||
private static void StartRenderer(TimedAction timedAction, SoftwareKeyboardRendererBase renderer, SoftwareKeyboardUiState state, object stateLock)
|
||||
{
|
||||
SoftwareKeyboardUiState internalState = new SoftwareKeyboardUiState();
|
||||
SoftwareKeyboardUiState internalState = new();
|
||||
|
||||
bool canCreateSurface = false;
|
||||
bool needsUpdate = true;
|
||||
@@ -61,6 +61,7 @@ namespace Ryujinx.HLE.HOS.Applets.SoftwareKeyboard
|
||||
return;
|
||||
}
|
||||
|
||||
#pragma warning disable IDE0055 // Disable formatting
|
||||
needsUpdate = UpdateStateField(ref state.InputText, ref internalState.InputText);
|
||||
needsUpdate |= UpdateStateField(ref state.CursorBegin, ref internalState.CursorBegin);
|
||||
needsUpdate |= UpdateStateField(ref state.CursorEnd, ref internalState.CursorEnd);
|
||||
@@ -70,6 +71,7 @@ namespace Ryujinx.HLE.HOS.Applets.SoftwareKeyboard
|
||||
needsUpdate |= UpdateStateField(ref state.TypingEnabled, ref internalState.TypingEnabled);
|
||||
needsUpdate |= UpdateStateField(ref state.ControllerEnabled, ref internalState.ControllerEnabled);
|
||||
needsUpdate |= UpdateStateField(ref state.TextBoxBlinkCounter, ref internalState.TextBoxBlinkCounter);
|
||||
#pragma warning restore IDE0055
|
||||
|
||||
canCreateSurface = state.SurfaceInfo != null && internalState.SurfaceInfo == null;
|
||||
|
||||
@@ -104,14 +106,12 @@ namespace Ryujinx.HLE.HOS.Applets.SoftwareKeyboard
|
||||
return false;
|
||||
}
|
||||
|
||||
#pragma warning disable CS8632
|
||||
public void UpdateTextState(string? inputText, int? cursorBegin, int? cursorEnd, bool? overwriteMode, bool? typingEnabled)
|
||||
#pragma warning restore CS8632
|
||||
public void UpdateTextState(string inputText, int? cursorBegin, int? cursorEnd, bool? overwriteMode, bool? typingEnabled)
|
||||
{
|
||||
lock (_stateLock)
|
||||
{
|
||||
// Update the parameters that were provided.
|
||||
_state.InputText = inputText != null ? inputText : _state.InputText;
|
||||
_state.InputText = inputText ?? _state.InputText;
|
||||
_state.CursorBegin = cursorBegin.GetValueOrDefault(_state.CursorBegin);
|
||||
_state.CursorEnd = cursorEnd.GetValueOrDefault(_state.CursorEnd);
|
||||
_state.OverwriteMode = overwriteMode.GetValueOrDefault(_state.OverwriteMode);
|
||||
|
@@ -32,29 +32,29 @@ namespace Ryujinx.HLE.HOS.Applets.SoftwareKeyboard
|
||||
private Image<Argb32> _surface = null;
|
||||
private byte[] _bufferData = null;
|
||||
|
||||
private Image _ryujinxLogo = null;
|
||||
private Image _padAcceptIcon = null;
|
||||
private Image _padCancelIcon = null;
|
||||
private Image _keyModeIcon = null;
|
||||
private readonly Image _ryujinxLogo = null;
|
||||
private readonly Image _padAcceptIcon = null;
|
||||
private readonly Image _padCancelIcon = null;
|
||||
private readonly Image _keyModeIcon = null;
|
||||
|
||||
private float _textBoxOutlineWidth;
|
||||
private float _padPressedPenWidth;
|
||||
private readonly float _textBoxOutlineWidth;
|
||||
private readonly float _padPressedPenWidth;
|
||||
|
||||
private Color _textNormalColor;
|
||||
private Color _textSelectedColor;
|
||||
private Color _textOverCursorColor;
|
||||
private readonly Color _textNormalColor;
|
||||
private readonly Color _textSelectedColor;
|
||||
private readonly Color _textOverCursorColor;
|
||||
|
||||
private IBrush _panelBrush;
|
||||
private IBrush _disabledBrush;
|
||||
private IBrush _cursorBrush;
|
||||
private IBrush _selectionBoxBrush;
|
||||
private readonly IBrush _panelBrush;
|
||||
private readonly IBrush _disabledBrush;
|
||||
private readonly IBrush _cursorBrush;
|
||||
private readonly IBrush _selectionBoxBrush;
|
||||
|
||||
private Pen _textBoxOutlinePen;
|
||||
private Pen _cursorPen;
|
||||
private Pen _selectionBoxPen;
|
||||
private Pen _padPressedPen;
|
||||
private readonly Pen _textBoxOutlinePen;
|
||||
private readonly Pen _cursorPen;
|
||||
private readonly Pen _selectionBoxPen;
|
||||
private readonly Pen _padPressedPen;
|
||||
|
||||
private int _inputTextFontSize;
|
||||
private readonly int _inputTextFontSize;
|
||||
private Font _messageFont;
|
||||
private Font _inputTextFont;
|
||||
private Font _labelsTextFont;
|
||||
@@ -111,13 +111,12 @@ namespace Ryujinx.HLE.HOS.Applets.SoftwareKeyboard
|
||||
{
|
||||
// Try a list of fonts in case any of them is not available in the system.
|
||||
|
||||
string[] availableFonts = new string[]
|
||||
{
|
||||
string[] availableFonts = {
|
||||
uiThemeFontFamily,
|
||||
"Liberation Sans",
|
||||
"FreeSans",
|
||||
"DejaVu Sans",
|
||||
"Lucida Grande"
|
||||
"Lucida Grande",
|
||||
};
|
||||
|
||||
foreach (string fontFamily in availableFonts)
|
||||
@@ -138,7 +137,7 @@ namespace Ryujinx.HLE.HOS.Applets.SoftwareKeyboard
|
||||
throw new Exception($"None of these fonts were found in the system: {String.Join(", ", availableFonts)}!");
|
||||
}
|
||||
|
||||
private Color ToColor(ThemeColor color, byte? overrideAlpha = null, bool flipRgb = false)
|
||||
private static Color ToColor(ThemeColor color, byte? overrideAlpha = null, bool flipRgb = false)
|
||||
{
|
||||
var a = (byte)(color.A * 255);
|
||||
var r = (byte)(color.R * 255);
|
||||
@@ -155,14 +154,14 @@ namespace Ryujinx.HLE.HOS.Applets.SoftwareKeyboard
|
||||
return Color.FromRgba(r, g, b, overrideAlpha.GetValueOrDefault(a));
|
||||
}
|
||||
|
||||
private Image LoadResource(Assembly assembly, string resourcePath, int newWidth, int newHeight)
|
||||
private static Image LoadResource(Assembly assembly, string resourcePath, int newWidth, int newHeight)
|
||||
{
|
||||
Stream resourceStream = assembly.GetManifestResourceStream(resourcePath);
|
||||
|
||||
return LoadResource(resourceStream, newWidth, newHeight);
|
||||
}
|
||||
|
||||
private Image LoadResource(Stream resourceStream, int newWidth, int newHeight)
|
||||
private static Image LoadResource(Stream resourceStream, int newWidth, int newHeight)
|
||||
{
|
||||
Debug.Assert(resourceStream != null);
|
||||
|
||||
@@ -176,7 +175,7 @@ namespace Ryujinx.HLE.HOS.Applets.SoftwareKeyboard
|
||||
return image;
|
||||
}
|
||||
|
||||
private void SetGraphicsOptions(IImageProcessingContext context)
|
||||
private static void SetGraphicsOptions(IImageProcessingContext context)
|
||||
{
|
||||
context.GetGraphicsOptions().Antialias = true;
|
||||
context.GetShapeGraphicsOptions().GraphicsOptions.Antialias = true;
|
||||
@@ -200,7 +199,7 @@ namespace Ryujinx.HLE.HOS.Applets.SoftwareKeyboard
|
||||
float halfWidth = _panelRectangle.Width / 2;
|
||||
float buttonsY = _panelRectangle.Y + 185;
|
||||
|
||||
PointF disableButtonPosition = new PointF(halfWidth + 180, buttonsY);
|
||||
PointF disableButtonPosition = new(halfWidth + 180, buttonsY);
|
||||
|
||||
DrawControllerToggle(context, disableButtonPosition);
|
||||
});
|
||||
@@ -240,9 +239,9 @@ namespace Ryujinx.HLE.HOS.Applets.SoftwareKeyboard
|
||||
float halfWidth = _panelRectangle.Width / 2;
|
||||
float buttonsY = _panelRectangle.Y + 185;
|
||||
|
||||
PointF acceptButtonPosition = new PointF(halfWidth - 180, buttonsY);
|
||||
PointF cancelButtonPosition = new PointF(halfWidth , buttonsY);
|
||||
PointF disableButtonPosition = new PointF(halfWidth + 180, buttonsY);
|
||||
PointF acceptButtonPosition = new(halfWidth - 180, buttonsY);
|
||||
PointF cancelButtonPosition = new(halfWidth, buttonsY);
|
||||
PointF disableButtonPosition = new(halfWidth + 180, buttonsY);
|
||||
|
||||
DrawPadButton(context, acceptButtonPosition, _padAcceptIcon, AcceptText, state.AcceptPressed, state.ControllerEnabled);
|
||||
DrawPadButton(context, cancelButtonPosition, _padCancelIcon, CancelText, state.CancelPressed, state.ControllerEnabled);
|
||||
@@ -294,7 +293,7 @@ namespace Ryujinx.HLE.HOS.Applets.SoftwareKeyboard
|
||||
}
|
||||
private static RectangleF MeasureString(string text, Font font)
|
||||
{
|
||||
RendererOptions options = new RendererOptions(font);
|
||||
RendererOptions options = new(font);
|
||||
|
||||
if (text == "")
|
||||
{
|
||||
@@ -310,7 +309,7 @@ namespace Ryujinx.HLE.HOS.Applets.SoftwareKeyboard
|
||||
|
||||
private static RectangleF MeasureString(ReadOnlySpan<char> text, Font font)
|
||||
{
|
||||
RendererOptions options = new RendererOptions(font);
|
||||
RendererOptions options = new(font);
|
||||
|
||||
if (text == "")
|
||||
{
|
||||
@@ -332,9 +331,9 @@ namespace Ryujinx.HLE.HOS.Applets.SoftwareKeyboard
|
||||
float boxY = _panelRectangle.Y + 110;
|
||||
float boxX = (int)((_panelRectangle.Width - boxWidth) / 2);
|
||||
|
||||
RectangleF boxRectangle = new RectangleF(boxX, boxY, boxWidth, boxHeight);
|
||||
RectangleF boxRectangle = new(boxX, boxY, boxWidth, boxHeight);
|
||||
|
||||
RectangleF boundRectangle = new RectangleF(_panelRectangle.X, boxY - _textBoxOutlineWidth,
|
||||
RectangleF boundRectangle = new(_panelRectangle.X, boxY - _textBoxOutlineWidth,
|
||||
_panelRectangle.Width, boxHeight + 2 * _textBoxOutlineWidth);
|
||||
|
||||
context.Fill(_panelBrush, boundRectangle);
|
||||
@@ -431,8 +430,7 @@ namespace Ryujinx.HLE.HOS.Applets.SoftwareKeyboard
|
||||
|
||||
if (cursorWidth == 0)
|
||||
{
|
||||
PointF[] points = new PointF[]
|
||||
{
|
||||
PointF[] points = {
|
||||
new PointF(cursorPositionXLeft, cursorPositionYTop),
|
||||
new PointF(cursorPositionXLeft, cursorPositionYBottom),
|
||||
};
|
||||
@@ -446,7 +444,7 @@ namespace Ryujinx.HLE.HOS.Applets.SoftwareKeyboard
|
||||
context.Draw(cursorPen, cursorRectangle);
|
||||
context.Fill(cursorBrush, cursorRectangle);
|
||||
|
||||
Image<Argb32> textOverCursor = new Image<Argb32>((int)cursorRectangle.Width, (int)cursorRectangle.Height);
|
||||
Image<Argb32> textOverCursor = new((int)cursorRectangle.Width, (int)cursorRectangle.Height);
|
||||
textOverCursor.Mutate(context =>
|
||||
{
|
||||
var textRelativePosition = new PointF(inputTextPosition.X - cursorRectangle.X, inputTextPosition.Y - cursorRectangle.Y);
|
||||
|
@@ -23,6 +23,6 @@
|
||||
/// <summary>
|
||||
/// swkbd has completed.
|
||||
/// </summary>
|
||||
Complete
|
||||
Complete,
|
||||
}
|
||||
}
|
@@ -96,7 +96,7 @@ namespace Ryujinx.HLE.HOS
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException();
|
||||
throw new InvalidOperationException($"{nameof(mode)} contains an invalid value: {mode}");
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -4,8 +4,8 @@ namespace Ryujinx.HLE.HOS.Diagnostics.Demangler.Ast
|
||||
{
|
||||
public class ArraySubscriptingExpression : BaseNode
|
||||
{
|
||||
private BaseNode _leftNode;
|
||||
private BaseNode _subscript;
|
||||
private readonly BaseNode _leftNode;
|
||||
private readonly BaseNode _subscript;
|
||||
|
||||
public ArraySubscriptingExpression(BaseNode leftNode, BaseNode subscript) : base(NodeType.ArraySubscriptingExpression)
|
||||
{
|
||||
|
@@ -4,9 +4,9 @@ namespace Ryujinx.HLE.HOS.Diagnostics.Demangler.Ast
|
||||
{
|
||||
public class ArrayType : BaseNode
|
||||
{
|
||||
private BaseNode _base;
|
||||
private BaseNode _dimensionExpression;
|
||||
private string _dimensionString;
|
||||
private readonly BaseNode _base;
|
||||
private readonly BaseNode _dimensionExpression;
|
||||
private readonly string _dimensionString;
|
||||
|
||||
public ArrayType(BaseNode Base, BaseNode dimensionExpression = null) : base(NodeType.ArrayType)
|
||||
{
|
||||
@@ -46,9 +46,9 @@ namespace Ryujinx.HLE.HOS.Diagnostics.Demangler.Ast
|
||||
{
|
||||
writer.Write(_dimensionString);
|
||||
}
|
||||
else if (_dimensionExpression != null)
|
||||
else
|
||||
{
|
||||
_dimensionExpression.Print(writer);
|
||||
_dimensionExpression?.Print(writer);
|
||||
}
|
||||
|
||||
writer.Write("]");
|
||||
|
@@ -55,7 +55,7 @@ namespace Ryujinx.HLE.HOS.Diagnostics.Demangler.Ast
|
||||
ConversionOperatorType,
|
||||
LocalName,
|
||||
CtorVtableSpecialName,
|
||||
ArrayType
|
||||
ArrayType,
|
||||
}
|
||||
|
||||
public abstract class BaseNode
|
||||
@@ -103,7 +103,7 @@ namespace Ryujinx.HLE.HOS.Diagnostics.Demangler.Ast
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
StringWriter writer = new StringWriter();
|
||||
StringWriter writer = new();
|
||||
|
||||
Print(writer);
|
||||
|
||||
|
@@ -4,9 +4,9 @@ namespace Ryujinx.HLE.HOS.Diagnostics.Demangler.Ast
|
||||
{
|
||||
public class BinaryExpression : BaseNode
|
||||
{
|
||||
private BaseNode _leftPart;
|
||||
private string _name;
|
||||
private BaseNode _rightPart;
|
||||
private readonly BaseNode _leftPart;
|
||||
private readonly string _name;
|
||||
private readonly BaseNode _rightPart;
|
||||
|
||||
public BinaryExpression(BaseNode leftPart, string name, BaseNode rightPart) : base(NodeType.BinaryExpression)
|
||||
{
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user