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
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
|
# Grab sources to get update_reviewers.py and reviewers.yml
|
||||||
|
- name: Fetch sources
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
# Ensure we pin the source origin as pull_request_target run under forks.
|
||||||
|
fetch-depth: 0
|
||||||
|
repository: Ryujinx/Ryujinx
|
||||||
|
ref: master
|
||||||
|
|
||||||
- name: Update labels based on changes
|
- name: Update labels based on changes
|
||||||
uses: actions/labeler@v4
|
uses: actions/labeler@v4
|
||||||
with:
|
with:
|
||||||
sync-labels: true
|
sync-labels: true
|
||||||
dot: true
|
dot: true
|
||||||
|
|
||||||
- name: Auto Assign [Audio]
|
- name: Assign reviewers
|
||||||
uses: kentaro-m/auto-assign-action@v1.2.5
|
run: |
|
||||||
with:
|
pip3 install PyGithub
|
||||||
configuration-path: '.github/assign/audio.yml'
|
python3 .github/update_reviewers.py ${{ secrets.GITHUB_TOKEN }} ${{ github.repository }} ${{ github.event.pull_request.number }} .github/reviewers.yml
|
||||||
|
shell: bash
|
||||||
- name: Auto Assign [CPU]
|
|
||||||
uses: kentaro-m/auto-assign-action@v1.2.5
|
|
||||||
with:
|
|
||||||
configuration-path: '.github/assign/cpu.yml'
|
|
||||||
|
|
||||||
- name: Auto Assign [GPU]
|
|
||||||
uses: kentaro-m/auto-assign-action@v1.2.5
|
|
||||||
with:
|
|
||||||
configuration-path: '.github/assign/gpu.yml'
|
|
||||||
|
|
||||||
- name: Auto Assign [GUI]
|
|
||||||
uses: kentaro-m/auto-assign-action@v1.2.5
|
|
||||||
with:
|
|
||||||
configuration-path: '.github/assign/gui.yml'
|
|
||||||
|
|
||||||
- name: Auto Assign [Horizon]
|
|
||||||
uses: kentaro-m/auto-assign-action@v1.2.5
|
|
||||||
with:
|
|
||||||
configuration-path: '.github/assign/horizon.yml'
|
|
||||||
|
|
||||||
- name: Auto Assign [Infra]
|
|
||||||
uses: kentaro-m/auto-assign-action@v1.2.5
|
|
||||||
with:
|
|
||||||
configuration-path: '.github/assign/infra.yml'
|
|
||||||
|
|
||||||
- name: Auto Assign [Global]
|
|
||||||
uses: kentaro-m/auto-assign-action@v1.2.5
|
|
||||||
with:
|
|
||||||
configuration-path: '.github/assign/global.yml'
|
|
||||||
|
@@ -34,7 +34,7 @@
|
|||||||
<PackageVersion Include="Ryujinx.Graphics.Nvdec.Dependencies" Version="5.0.1-build13" />
|
<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.Graphics.Vulkan.Dependencies.MoltenVK" Version="1.2.0" />
|
||||||
<PackageVersion Include="Ryujinx.GtkSharp" Version="3.24.24.59-ryujinx" />
|
<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="shaderc.net" Version="0.1.0" />
|
||||||
<PackageVersion Include="SharpZipLib" Version="1.4.2" />
|
<PackageVersion Include="SharpZipLib" Version="1.4.2" />
|
||||||
<PackageVersion Include="Silk.NET.Vulkan" Version="2.16.0" />
|
<PackageVersion Include="Silk.NET.Vulkan" Version="2.16.0" />
|
||||||
|
@@ -1448,6 +1448,7 @@ namespace ARMeilleure.Instructions
|
|||||||
{
|
{
|
||||||
var overflowToInf = fpcr.GetRoundingMode() switch
|
var overflowToInf = fpcr.GetRoundingMode() switch
|
||||||
{
|
{
|
||||||
|
FPRoundingMode.ToNearest => true,
|
||||||
FPRoundingMode.TowardsPlusInfinity => !sign,
|
FPRoundingMode.TowardsPlusInfinity => !sign,
|
||||||
FPRoundingMode.TowardsMinusInfinity => sign,
|
FPRoundingMode.TowardsMinusInfinity => sign,
|
||||||
FPRoundingMode.TowardsZero => false,
|
FPRoundingMode.TowardsZero => false,
|
||||||
@@ -2879,6 +2880,7 @@ namespace ARMeilleure.Instructions
|
|||||||
{
|
{
|
||||||
var overflowToInf = fpcr.GetRoundingMode() switch
|
var overflowToInf = fpcr.GetRoundingMode() switch
|
||||||
{
|
{
|
||||||
|
FPRoundingMode.ToNearest => true,
|
||||||
FPRoundingMode.TowardsPlusInfinity => !sign,
|
FPRoundingMode.TowardsPlusInfinity => !sign,
|
||||||
FPRoundingMode.TowardsMinusInfinity => sign,
|
FPRoundingMode.TowardsMinusInfinity => sign,
|
||||||
FPRoundingMode.TowardsZero => false,
|
FPRoundingMode.TowardsZero => false,
|
||||||
|
@@ -114,7 +114,7 @@ namespace Ryujinx.Ava.Common
|
|||||||
|
|
||||||
public static void OpenSaveDir(ulong saveDataId)
|
public static void OpenSaveDir(ulong saveDataId)
|
||||||
{
|
{
|
||||||
string saveRootPath = Path.Combine(_virtualFileSystem.GetNandPath(), $"user/save/{saveDataId:x16}");
|
string saveRootPath = Path.Combine(VirtualFileSystem.GetNandPath(), $"user/save/{saveDataId:x16}");
|
||||||
|
|
||||||
if (!Directory.Exists(saveRootPath))
|
if (!Directory.Exists(saveRootPath))
|
||||||
{
|
{
|
||||||
|
@@ -2,6 +2,7 @@ using LibHac.Fs;
|
|||||||
using LibHac.Ncm;
|
using LibHac.Ncm;
|
||||||
using Ryujinx.Ava.UI.ViewModels;
|
using Ryujinx.Ava.UI.ViewModels;
|
||||||
using Ryujinx.Ava.UI.Windows;
|
using Ryujinx.Ava.UI.Windows;
|
||||||
|
using Ryujinx.HLE.FileSystem;
|
||||||
using Ryujinx.Ui.App.Common;
|
using Ryujinx.Ui.App.Common;
|
||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
@@ -81,7 +82,7 @@ namespace Ryujinx.Ava.UI.Models
|
|||||||
|
|
||||||
Task.Run(() =>
|
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);
|
long totalSize = GetDirectorySize(saveRoot);
|
||||||
|
|
||||||
|
@@ -105,7 +105,7 @@ namespace Ryujinx.Ava.UI.ViewModels
|
|||||||
}
|
}
|
||||||
|
|
||||||
string contentPath = contentManager.GetInstalledContentPath(0x010000000000080A, StorageId.BuiltInSystem, NcaContentType.Data);
|
string contentPath = contentManager.GetInstalledContentPath(0x010000000000080A, StorageId.BuiltInSystem, NcaContentType.Data);
|
||||||
string avatarPath = virtualFileSystem.SwitchPathToSystemPath(contentPath);
|
string avatarPath = VirtualFileSystem.SwitchPathToSystemPath(contentPath);
|
||||||
|
|
||||||
if (!string.IsNullOrWhiteSpace(avatarPath))
|
if (!string.IsNullOrWhiteSpace(avatarPath))
|
||||||
{
|
{
|
||||||
|
@@ -1,4 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Diagnostics.Contracts;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
#pragma warning disable CS0169, IDE0051 // Remove unused private member
|
#pragma warning disable CS0169, IDE0051 // Remove unused private member
|
||||||
@@ -9,6 +10,8 @@ namespace Ryujinx.Common.Memory
|
|||||||
T _e0;
|
T _e0;
|
||||||
public readonly int Length => 1;
|
public readonly int Length => 1;
|
||||||
public ref T this[int index] => ref AsSpan()[index];
|
public ref T this[int index] => ref AsSpan()[index];
|
||||||
|
|
||||||
|
[Pure]
|
||||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -18,6 +21,8 @@ namespace Ryujinx.Common.Memory
|
|||||||
Array1<T> _other;
|
Array1<T> _other;
|
||||||
public readonly int Length => 2;
|
public readonly int Length => 2;
|
||||||
public ref T this[int index] => ref AsSpan()[index];
|
public ref T this[int index] => ref AsSpan()[index];
|
||||||
|
|
||||||
|
[Pure]
|
||||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -27,6 +32,8 @@ namespace Ryujinx.Common.Memory
|
|||||||
Array2<T> _other;
|
Array2<T> _other;
|
||||||
public readonly int Length => 3;
|
public readonly int Length => 3;
|
||||||
public ref T this[int index] => ref AsSpan()[index];
|
public ref T this[int index] => ref AsSpan()[index];
|
||||||
|
|
||||||
|
[Pure]
|
||||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -36,6 +43,8 @@ namespace Ryujinx.Common.Memory
|
|||||||
Array3<T> _other;
|
Array3<T> _other;
|
||||||
public readonly int Length => 4;
|
public readonly int Length => 4;
|
||||||
public ref T this[int index] => ref AsSpan()[index];
|
public ref T this[int index] => ref AsSpan()[index];
|
||||||
|
|
||||||
|
[Pure]
|
||||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -45,6 +54,8 @@ namespace Ryujinx.Common.Memory
|
|||||||
Array4<T> _other;
|
Array4<T> _other;
|
||||||
public readonly int Length => 5;
|
public readonly int Length => 5;
|
||||||
public ref T this[int index] => ref AsSpan()[index];
|
public ref T this[int index] => ref AsSpan()[index];
|
||||||
|
|
||||||
|
[Pure]
|
||||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -54,6 +65,8 @@ namespace Ryujinx.Common.Memory
|
|||||||
Array5<T> _other;
|
Array5<T> _other;
|
||||||
public readonly int Length => 6;
|
public readonly int Length => 6;
|
||||||
public ref T this[int index] => ref AsSpan()[index];
|
public ref T this[int index] => ref AsSpan()[index];
|
||||||
|
|
||||||
|
[Pure]
|
||||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -63,6 +76,8 @@ namespace Ryujinx.Common.Memory
|
|||||||
Array6<T> _other;
|
Array6<T> _other;
|
||||||
public readonly int Length => 7;
|
public readonly int Length => 7;
|
||||||
public ref T this[int index] => ref AsSpan()[index];
|
public ref T this[int index] => ref AsSpan()[index];
|
||||||
|
|
||||||
|
[Pure]
|
||||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -72,6 +87,8 @@ namespace Ryujinx.Common.Memory
|
|||||||
Array7<T> _other;
|
Array7<T> _other;
|
||||||
public readonly int Length => 8;
|
public readonly int Length => 8;
|
||||||
public ref T this[int index] => ref AsSpan()[index];
|
public ref T this[int index] => ref AsSpan()[index];
|
||||||
|
|
||||||
|
[Pure]
|
||||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -81,6 +98,8 @@ namespace Ryujinx.Common.Memory
|
|||||||
Array8<T> _other;
|
Array8<T> _other;
|
||||||
public readonly int Length => 9;
|
public readonly int Length => 9;
|
||||||
public ref T this[int index] => ref AsSpan()[index];
|
public ref T this[int index] => ref AsSpan()[index];
|
||||||
|
|
||||||
|
[Pure]
|
||||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -90,6 +109,8 @@ namespace Ryujinx.Common.Memory
|
|||||||
Array9<T> _other;
|
Array9<T> _other;
|
||||||
public readonly int Length => 10;
|
public readonly int Length => 10;
|
||||||
public ref T this[int index] => ref AsSpan()[index];
|
public ref T this[int index] => ref AsSpan()[index];
|
||||||
|
|
||||||
|
[Pure]
|
||||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -99,6 +120,8 @@ namespace Ryujinx.Common.Memory
|
|||||||
Array10<T> _other;
|
Array10<T> _other;
|
||||||
public readonly int Length => 11;
|
public readonly int Length => 11;
|
||||||
public ref T this[int index] => ref AsSpan()[index];
|
public ref T this[int index] => ref AsSpan()[index];
|
||||||
|
|
||||||
|
[Pure]
|
||||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -108,6 +131,8 @@ namespace Ryujinx.Common.Memory
|
|||||||
Array11<T> _other;
|
Array11<T> _other;
|
||||||
public readonly int Length => 12;
|
public readonly int Length => 12;
|
||||||
public ref T this[int index] => ref AsSpan()[index];
|
public ref T this[int index] => ref AsSpan()[index];
|
||||||
|
|
||||||
|
[Pure]
|
||||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -117,6 +142,8 @@ namespace Ryujinx.Common.Memory
|
|||||||
Array12<T> _other;
|
Array12<T> _other;
|
||||||
public readonly int Length => 13;
|
public readonly int Length => 13;
|
||||||
public ref T this[int index] => ref AsSpan()[index];
|
public ref T this[int index] => ref AsSpan()[index];
|
||||||
|
|
||||||
|
[Pure]
|
||||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -126,6 +153,8 @@ namespace Ryujinx.Common.Memory
|
|||||||
Array13<T> _other;
|
Array13<T> _other;
|
||||||
public readonly int Length => 14;
|
public readonly int Length => 14;
|
||||||
public ref T this[int index] => ref AsSpan()[index];
|
public ref T this[int index] => ref AsSpan()[index];
|
||||||
|
|
||||||
|
[Pure]
|
||||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -135,6 +164,8 @@ namespace Ryujinx.Common.Memory
|
|||||||
Array14<T> _other;
|
Array14<T> _other;
|
||||||
public readonly int Length => 15;
|
public readonly int Length => 15;
|
||||||
public ref T this[int index] => ref AsSpan()[index];
|
public ref T this[int index] => ref AsSpan()[index];
|
||||||
|
|
||||||
|
[Pure]
|
||||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -144,6 +175,8 @@ namespace Ryujinx.Common.Memory
|
|||||||
Array15<T> _other;
|
Array15<T> _other;
|
||||||
public readonly int Length => 16;
|
public readonly int Length => 16;
|
||||||
public ref T this[int index] => ref AsSpan()[index];
|
public ref T this[int index] => ref AsSpan()[index];
|
||||||
|
|
||||||
|
[Pure]
|
||||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -153,6 +186,8 @@ namespace Ryujinx.Common.Memory
|
|||||||
Array16<T> _other;
|
Array16<T> _other;
|
||||||
public readonly int Length => 17;
|
public readonly int Length => 17;
|
||||||
public ref T this[int index] => ref AsSpan()[index];
|
public ref T this[int index] => ref AsSpan()[index];
|
||||||
|
|
||||||
|
[Pure]
|
||||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -162,6 +197,8 @@ namespace Ryujinx.Common.Memory
|
|||||||
Array17<T> _other;
|
Array17<T> _other;
|
||||||
public readonly int Length => 18;
|
public readonly int Length => 18;
|
||||||
public ref T this[int index] => ref AsSpan()[index];
|
public ref T this[int index] => ref AsSpan()[index];
|
||||||
|
|
||||||
|
[Pure]
|
||||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -171,6 +208,8 @@ namespace Ryujinx.Common.Memory
|
|||||||
Array18<T> _other;
|
Array18<T> _other;
|
||||||
public readonly int Length => 19;
|
public readonly int Length => 19;
|
||||||
public ref T this[int index] => ref AsSpan()[index];
|
public ref T this[int index] => ref AsSpan()[index];
|
||||||
|
|
||||||
|
[Pure]
|
||||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -180,6 +219,8 @@ namespace Ryujinx.Common.Memory
|
|||||||
Array19<T> _other;
|
Array19<T> _other;
|
||||||
public readonly int Length => 20;
|
public readonly int Length => 20;
|
||||||
public ref T this[int index] => ref AsSpan()[index];
|
public ref T this[int index] => ref AsSpan()[index];
|
||||||
|
|
||||||
|
[Pure]
|
||||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -189,6 +230,8 @@ namespace Ryujinx.Common.Memory
|
|||||||
Array20<T> _other;
|
Array20<T> _other;
|
||||||
public readonly int Length => 21;
|
public readonly int Length => 21;
|
||||||
public ref T this[int index] => ref AsSpan()[index];
|
public ref T this[int index] => ref AsSpan()[index];
|
||||||
|
|
||||||
|
[Pure]
|
||||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -198,6 +241,8 @@ namespace Ryujinx.Common.Memory
|
|||||||
Array21<T> _other;
|
Array21<T> _other;
|
||||||
public readonly int Length => 22;
|
public readonly int Length => 22;
|
||||||
public ref T this[int index] => ref AsSpan()[index];
|
public ref T this[int index] => ref AsSpan()[index];
|
||||||
|
|
||||||
|
[Pure]
|
||||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -207,6 +252,8 @@ namespace Ryujinx.Common.Memory
|
|||||||
Array22<T> _other;
|
Array22<T> _other;
|
||||||
public readonly int Length => 23;
|
public readonly int Length => 23;
|
||||||
public ref T this[int index] => ref AsSpan()[index];
|
public ref T this[int index] => ref AsSpan()[index];
|
||||||
|
|
||||||
|
[Pure]
|
||||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -217,6 +264,8 @@ namespace Ryujinx.Common.Memory
|
|||||||
|
|
||||||
public readonly int Length => 24;
|
public readonly int Length => 24;
|
||||||
public ref T this[int index] => ref AsSpan()[index];
|
public ref T this[int index] => ref AsSpan()[index];
|
||||||
|
|
||||||
|
[Pure]
|
||||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -227,6 +276,8 @@ namespace Ryujinx.Common.Memory
|
|||||||
|
|
||||||
public readonly int Length => 25;
|
public readonly int Length => 25;
|
||||||
public ref T this[int index] => ref AsSpan()[index];
|
public ref T this[int index] => ref AsSpan()[index];
|
||||||
|
|
||||||
|
[Pure]
|
||||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -237,6 +288,8 @@ namespace Ryujinx.Common.Memory
|
|||||||
|
|
||||||
public readonly int Length => 26;
|
public readonly int Length => 26;
|
||||||
public ref T this[int index] => ref AsSpan()[index];
|
public ref T this[int index] => ref AsSpan()[index];
|
||||||
|
|
||||||
|
[Pure]
|
||||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -247,6 +300,8 @@ namespace Ryujinx.Common.Memory
|
|||||||
|
|
||||||
public readonly int Length => 27;
|
public readonly int Length => 27;
|
||||||
public ref T this[int index] => ref AsSpan()[index];
|
public ref T this[int index] => ref AsSpan()[index];
|
||||||
|
|
||||||
|
[Pure]
|
||||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -257,6 +312,8 @@ namespace Ryujinx.Common.Memory
|
|||||||
|
|
||||||
public readonly int Length => 28;
|
public readonly int Length => 28;
|
||||||
public ref T this[int index] => ref AsSpan()[index];
|
public ref T this[int index] => ref AsSpan()[index];
|
||||||
|
|
||||||
|
[Pure]
|
||||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -267,6 +324,8 @@ namespace Ryujinx.Common.Memory
|
|||||||
|
|
||||||
public readonly int Length => 29;
|
public readonly int Length => 29;
|
||||||
public ref T this[int index] => ref AsSpan()[index];
|
public ref T this[int index] => ref AsSpan()[index];
|
||||||
|
|
||||||
|
[Pure]
|
||||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -277,6 +336,8 @@ namespace Ryujinx.Common.Memory
|
|||||||
|
|
||||||
public readonly int Length => 30;
|
public readonly int Length => 30;
|
||||||
public ref T this[int index] => ref AsSpan()[index];
|
public ref T this[int index] => ref AsSpan()[index];
|
||||||
|
|
||||||
|
[Pure]
|
||||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -287,6 +348,8 @@ namespace Ryujinx.Common.Memory
|
|||||||
|
|
||||||
public readonly int Length => 31;
|
public readonly int Length => 31;
|
||||||
public ref T this[int index] => ref AsSpan()[index];
|
public ref T this[int index] => ref AsSpan()[index];
|
||||||
|
|
||||||
|
[Pure]
|
||||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -297,6 +360,8 @@ namespace Ryujinx.Common.Memory
|
|||||||
|
|
||||||
public readonly int Length => 32;
|
public readonly int Length => 32;
|
||||||
public ref T this[int index] => ref AsSpan()[index];
|
public ref T this[int index] => ref AsSpan()[index];
|
||||||
|
|
||||||
|
[Pure]
|
||||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -307,6 +372,8 @@ namespace Ryujinx.Common.Memory
|
|||||||
|
|
||||||
public readonly int Length => 33;
|
public readonly int Length => 33;
|
||||||
public ref T this[int index] => ref AsSpan()[index];
|
public ref T this[int index] => ref AsSpan()[index];
|
||||||
|
|
||||||
|
[Pure]
|
||||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -317,6 +384,8 @@ namespace Ryujinx.Common.Memory
|
|||||||
|
|
||||||
public readonly int Length => 34;
|
public readonly int Length => 34;
|
||||||
public ref T this[int index] => ref AsSpan()[index];
|
public ref T this[int index] => ref AsSpan()[index];
|
||||||
|
|
||||||
|
[Pure]
|
||||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -327,6 +396,8 @@ namespace Ryujinx.Common.Memory
|
|||||||
|
|
||||||
public readonly int Length => 35;
|
public readonly int Length => 35;
|
||||||
public ref T this[int index] => ref AsSpan()[index];
|
public ref T this[int index] => ref AsSpan()[index];
|
||||||
|
|
||||||
|
[Pure]
|
||||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -337,6 +408,8 @@ namespace Ryujinx.Common.Memory
|
|||||||
|
|
||||||
public readonly int Length => 36;
|
public readonly int Length => 36;
|
||||||
public ref T this[int index] => ref AsSpan()[index];
|
public ref T this[int index] => ref AsSpan()[index];
|
||||||
|
|
||||||
|
[Pure]
|
||||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -347,6 +420,8 @@ namespace Ryujinx.Common.Memory
|
|||||||
|
|
||||||
public readonly int Length => 37;
|
public readonly int Length => 37;
|
||||||
public ref T this[int index] => ref AsSpan()[index];
|
public ref T this[int index] => ref AsSpan()[index];
|
||||||
|
|
||||||
|
[Pure]
|
||||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -357,6 +432,8 @@ namespace Ryujinx.Common.Memory
|
|||||||
|
|
||||||
public readonly int Length => 38;
|
public readonly int Length => 38;
|
||||||
public ref T this[int index] => ref AsSpan()[index];
|
public ref T this[int index] => ref AsSpan()[index];
|
||||||
|
|
||||||
|
[Pure]
|
||||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -367,6 +444,8 @@ namespace Ryujinx.Common.Memory
|
|||||||
|
|
||||||
public readonly int Length => 39;
|
public readonly int Length => 39;
|
||||||
public ref T this[int index] => ref AsSpan()[index];
|
public ref T this[int index] => ref AsSpan()[index];
|
||||||
|
|
||||||
|
[Pure]
|
||||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -377,6 +456,8 @@ namespace Ryujinx.Common.Memory
|
|||||||
|
|
||||||
public readonly int Length => 40;
|
public readonly int Length => 40;
|
||||||
public ref T this[int index] => ref AsSpan()[index];
|
public ref T this[int index] => ref AsSpan()[index];
|
||||||
|
|
||||||
|
[Pure]
|
||||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -387,6 +468,8 @@ namespace Ryujinx.Common.Memory
|
|||||||
|
|
||||||
public readonly int Length => 41;
|
public readonly int Length => 41;
|
||||||
public ref T this[int index] => ref AsSpan()[index];
|
public ref T this[int index] => ref AsSpan()[index];
|
||||||
|
|
||||||
|
[Pure]
|
||||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -397,6 +480,8 @@ namespace Ryujinx.Common.Memory
|
|||||||
|
|
||||||
public readonly int Length => 42;
|
public readonly int Length => 42;
|
||||||
public ref T this[int index] => ref AsSpan()[index];
|
public ref T this[int index] => ref AsSpan()[index];
|
||||||
|
|
||||||
|
[Pure]
|
||||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -407,6 +492,8 @@ namespace Ryujinx.Common.Memory
|
|||||||
|
|
||||||
public readonly int Length => 43;
|
public readonly int Length => 43;
|
||||||
public ref T this[int index] => ref AsSpan()[index];
|
public ref T this[int index] => ref AsSpan()[index];
|
||||||
|
|
||||||
|
[Pure]
|
||||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -417,6 +504,8 @@ namespace Ryujinx.Common.Memory
|
|||||||
|
|
||||||
public readonly int Length => 44;
|
public readonly int Length => 44;
|
||||||
public ref T this[int index] => ref AsSpan()[index];
|
public ref T this[int index] => ref AsSpan()[index];
|
||||||
|
|
||||||
|
[Pure]
|
||||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -427,6 +516,8 @@ namespace Ryujinx.Common.Memory
|
|||||||
|
|
||||||
public readonly int Length => 45;
|
public readonly int Length => 45;
|
||||||
public ref T this[int index] => ref AsSpan()[index];
|
public ref T this[int index] => ref AsSpan()[index];
|
||||||
|
|
||||||
|
[Pure]
|
||||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -437,6 +528,8 @@ namespace Ryujinx.Common.Memory
|
|||||||
|
|
||||||
public readonly int Length => 46;
|
public readonly int Length => 46;
|
||||||
public ref T this[int index] => ref AsSpan()[index];
|
public ref T this[int index] => ref AsSpan()[index];
|
||||||
|
|
||||||
|
[Pure]
|
||||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -447,6 +540,8 @@ namespace Ryujinx.Common.Memory
|
|||||||
|
|
||||||
public readonly int Length => 47;
|
public readonly int Length => 47;
|
||||||
public ref T this[int index] => ref AsSpan()[index];
|
public ref T this[int index] => ref AsSpan()[index];
|
||||||
|
|
||||||
|
[Pure]
|
||||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -457,6 +552,8 @@ namespace Ryujinx.Common.Memory
|
|||||||
|
|
||||||
public readonly int Length => 48;
|
public readonly int Length => 48;
|
||||||
public ref T this[int index] => ref AsSpan()[index];
|
public ref T this[int index] => ref AsSpan()[index];
|
||||||
|
|
||||||
|
[Pure]
|
||||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -467,6 +564,8 @@ namespace Ryujinx.Common.Memory
|
|||||||
|
|
||||||
public readonly int Length => 49;
|
public readonly int Length => 49;
|
||||||
public ref T this[int index] => ref AsSpan()[index];
|
public ref T this[int index] => ref AsSpan()[index];
|
||||||
|
|
||||||
|
[Pure]
|
||||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -477,6 +576,8 @@ namespace Ryujinx.Common.Memory
|
|||||||
|
|
||||||
public readonly int Length => 50;
|
public readonly int Length => 50;
|
||||||
public ref T this[int index] => ref AsSpan()[index];
|
public ref T this[int index] => ref AsSpan()[index];
|
||||||
|
|
||||||
|
[Pure]
|
||||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -487,6 +588,8 @@ namespace Ryujinx.Common.Memory
|
|||||||
|
|
||||||
public readonly int Length => 51;
|
public readonly int Length => 51;
|
||||||
public ref T this[int index] => ref AsSpan()[index];
|
public ref T this[int index] => ref AsSpan()[index];
|
||||||
|
|
||||||
|
[Pure]
|
||||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -497,6 +600,8 @@ namespace Ryujinx.Common.Memory
|
|||||||
|
|
||||||
public readonly int Length => 52;
|
public readonly int Length => 52;
|
||||||
public ref T this[int index] => ref AsSpan()[index];
|
public ref T this[int index] => ref AsSpan()[index];
|
||||||
|
|
||||||
|
[Pure]
|
||||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -507,6 +612,8 @@ namespace Ryujinx.Common.Memory
|
|||||||
|
|
||||||
public readonly int Length => 53;
|
public readonly int Length => 53;
|
||||||
public ref T this[int index] => ref AsSpan()[index];
|
public ref T this[int index] => ref AsSpan()[index];
|
||||||
|
|
||||||
|
[Pure]
|
||||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -517,6 +624,8 @@ namespace Ryujinx.Common.Memory
|
|||||||
|
|
||||||
public readonly int Length => 54;
|
public readonly int Length => 54;
|
||||||
public ref T this[int index] => ref AsSpan()[index];
|
public ref T this[int index] => ref AsSpan()[index];
|
||||||
|
|
||||||
|
[Pure]
|
||||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -527,6 +636,8 @@ namespace Ryujinx.Common.Memory
|
|||||||
|
|
||||||
public readonly int Length => 55;
|
public readonly int Length => 55;
|
||||||
public ref T this[int index] => ref AsSpan()[index];
|
public ref T this[int index] => ref AsSpan()[index];
|
||||||
|
|
||||||
|
[Pure]
|
||||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -537,6 +648,8 @@ namespace Ryujinx.Common.Memory
|
|||||||
|
|
||||||
public readonly int Length => 56;
|
public readonly int Length => 56;
|
||||||
public ref T this[int index] => ref AsSpan()[index];
|
public ref T this[int index] => ref AsSpan()[index];
|
||||||
|
|
||||||
|
[Pure]
|
||||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -547,6 +660,8 @@ namespace Ryujinx.Common.Memory
|
|||||||
|
|
||||||
public readonly int Length => 57;
|
public readonly int Length => 57;
|
||||||
public ref T this[int index] => ref AsSpan()[index];
|
public ref T this[int index] => ref AsSpan()[index];
|
||||||
|
|
||||||
|
[Pure]
|
||||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -557,6 +672,8 @@ namespace Ryujinx.Common.Memory
|
|||||||
|
|
||||||
public readonly int Length => 58;
|
public readonly int Length => 58;
|
||||||
public ref T this[int index] => ref AsSpan()[index];
|
public ref T this[int index] => ref AsSpan()[index];
|
||||||
|
|
||||||
|
[Pure]
|
||||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -567,6 +684,8 @@ namespace Ryujinx.Common.Memory
|
|||||||
|
|
||||||
public readonly int Length => 59;
|
public readonly int Length => 59;
|
||||||
public ref T this[int index] => ref AsSpan()[index];
|
public ref T this[int index] => ref AsSpan()[index];
|
||||||
|
|
||||||
|
[Pure]
|
||||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -576,6 +695,8 @@ namespace Ryujinx.Common.Memory
|
|||||||
Array59<T> _other;
|
Array59<T> _other;
|
||||||
public readonly int Length => 60;
|
public readonly int Length => 60;
|
||||||
public ref T this[int index] => ref AsSpan()[index];
|
public ref T this[int index] => ref AsSpan()[index];
|
||||||
|
|
||||||
|
[Pure]
|
||||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -585,6 +706,8 @@ namespace Ryujinx.Common.Memory
|
|||||||
Array60<T> _other;
|
Array60<T> _other;
|
||||||
public readonly int Length => 61;
|
public readonly int Length => 61;
|
||||||
public ref T this[int index] => ref AsSpan()[index];
|
public ref T this[int index] => ref AsSpan()[index];
|
||||||
|
|
||||||
|
[Pure]
|
||||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -594,6 +717,8 @@ namespace Ryujinx.Common.Memory
|
|||||||
Array61<T> _other;
|
Array61<T> _other;
|
||||||
public readonly int Length => 62;
|
public readonly int Length => 62;
|
||||||
public ref T this[int index] => ref AsSpan()[index];
|
public ref T this[int index] => ref AsSpan()[index];
|
||||||
|
|
||||||
|
[Pure]
|
||||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -603,6 +728,8 @@ namespace Ryujinx.Common.Memory
|
|||||||
Array62<T> _other;
|
Array62<T> _other;
|
||||||
public readonly int Length => 63;
|
public readonly int Length => 63;
|
||||||
public ref T this[int index] => ref AsSpan()[index];
|
public ref T this[int index] => ref AsSpan()[index];
|
||||||
|
|
||||||
|
[Pure]
|
||||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -612,6 +739,8 @@ namespace Ryujinx.Common.Memory
|
|||||||
Array63<T> _other;
|
Array63<T> _other;
|
||||||
public readonly int Length => 64;
|
public readonly int Length => 64;
|
||||||
public ref T this[int index] => ref AsSpan()[index];
|
public ref T this[int index] => ref AsSpan()[index];
|
||||||
|
|
||||||
|
[Pure]
|
||||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -622,6 +751,8 @@ namespace Ryujinx.Common.Memory
|
|||||||
Array8<T> _other2;
|
Array8<T> _other2;
|
||||||
public readonly int Length => 73;
|
public readonly int Length => 73;
|
||||||
public ref T this[int index] => ref AsSpan()[index];
|
public ref T this[int index] => ref AsSpan()[index];
|
||||||
|
|
||||||
|
[Pure]
|
||||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -632,6 +763,8 @@ namespace Ryujinx.Common.Memory
|
|||||||
Array62<T> _other2;
|
Array62<T> _other2;
|
||||||
public readonly int Length => 127;
|
public readonly int Length => 127;
|
||||||
public ref T this[int index] => ref AsSpan()[index];
|
public ref T this[int index] => ref AsSpan()[index];
|
||||||
|
|
||||||
|
[Pure]
|
||||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -642,6 +775,8 @@ namespace Ryujinx.Common.Memory
|
|||||||
Array63<T> _other2;
|
Array63<T> _other2;
|
||||||
public readonly int Length => 128;
|
public readonly int Length => 128;
|
||||||
public ref T this[int index] => ref AsSpan()[index];
|
public ref T this[int index] => ref AsSpan()[index];
|
||||||
|
|
||||||
|
[Pure]
|
||||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -652,6 +787,8 @@ namespace Ryujinx.Common.Memory
|
|||||||
Array127<T> _other2;
|
Array127<T> _other2;
|
||||||
public readonly int Length => 256;
|
public readonly int Length => 256;
|
||||||
public ref T this[int index] => ref AsSpan()[index];
|
public ref T this[int index] => ref AsSpan()[index];
|
||||||
|
|
||||||
|
[Pure]
|
||||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -168,6 +168,16 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
return ComponentType.Float;
|
return ComponentType.Float;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ImageAspectFlags GetDepthStencilAspectFlags()
|
||||||
|
{
|
||||||
|
if (_depthStencil == null)
|
||||||
|
{
|
||||||
|
return ImageAspectFlags.None;
|
||||||
|
}
|
||||||
|
|
||||||
|
return _depthStencil.Info.Format.ConvertAspectFlags();
|
||||||
|
}
|
||||||
|
|
||||||
public bool IsValidColorAttachment(int bindIndex)
|
public bool IsValidColorAttachment(int bindIndex)
|
||||||
{
|
{
|
||||||
return (uint)bindIndex < Constants.MaxRenderTargets && (_validColorAttachments & (1u << bindIndex)) != 0;
|
return (uint)bindIndex < Constants.MaxRenderTargets && (_validColorAttachments & (1u << bindIndex)) != 0;
|
||||||
@@ -226,7 +236,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
|
|
||||||
_depthStencil?.Storage.SetModification(
|
_depthStencil?.Storage.SetModification(
|
||||||
AccessFlags.DepthStencilAttachmentWriteBit,
|
AccessFlags.DepthStencilAttachmentWriteBit,
|
||||||
PipelineStageFlags.ColorAttachmentOutputBit);
|
PipelineStageFlags.LateFragmentTestsBit);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void InsertClearBarrier(CommandBufferScoped cbs, int index)
|
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;
|
||||||
using Ryujinx.Graphics.Shader.Translation;
|
using Ryujinx.Graphics.Shader.Translation;
|
||||||
using Ryujinx.Graphics.Vulkan.Shaders;
|
|
||||||
using Silk.NET.Vulkan;
|
using Silk.NET.Vulkan;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
using System.Numerics;
|
using System.Numerics;
|
||||||
using CompareOp = Ryujinx.Graphics.GAL.CompareOp;
|
using CompareOp = Ryujinx.Graphics.GAL.CompareOp;
|
||||||
using Format = Ryujinx.Graphics.GAL.Format;
|
using Format = Ryujinx.Graphics.GAL.Format;
|
||||||
@@ -26,6 +27,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
class HelperShader : IDisposable
|
class HelperShader : IDisposable
|
||||||
{
|
{
|
||||||
private const int UniformBufferAlignment = 256;
|
private const int UniformBufferAlignment = 256;
|
||||||
|
private const string ShaderBinariesPath = "Ryujinx.Graphics.Vulkan/Shaders/SpirvBinaries";
|
||||||
|
|
||||||
private readonly PipelineHelperShader _pipeline;
|
private readonly PipelineHelperShader _pipeline;
|
||||||
private readonly ISampler _samplerLinear;
|
private readonly ISampler _samplerLinear;
|
||||||
@@ -67,40 +69,40 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
|
|
||||||
_programColorBlit = gd.CreateProgramWithMinimalLayout(new[]
|
_programColorBlit = gd.CreateProgramWithMinimalLayout(new[]
|
||||||
{
|
{
|
||||||
new ShaderSource(ShaderBinaries.ColorBlitVertexShaderSource, ShaderStage.Vertex, TargetLanguage.Spirv),
|
new ShaderSource(ReadSpirv("ColorBlitVertex.spv"), ShaderStage.Vertex, TargetLanguage.Spirv),
|
||||||
new ShaderSource(ShaderBinaries.ColorBlitFragmentShaderSource, ShaderStage.Fragment, TargetLanguage.Spirv),
|
new ShaderSource(ReadSpirv("ColorBlitFragment.spv"), ShaderStage.Fragment, TargetLanguage.Spirv),
|
||||||
}, blitResourceLayout);
|
}, blitResourceLayout);
|
||||||
|
|
||||||
_programColorBlitMs = gd.CreateProgramWithMinimalLayout(new[]
|
_programColorBlitMs = gd.CreateProgramWithMinimalLayout(new[]
|
||||||
{
|
{
|
||||||
new ShaderSource(ShaderBinaries.ColorBlitVertexShaderSource, ShaderStage.Vertex, TargetLanguage.Spirv),
|
new ShaderSource(ReadSpirv("ColorBlitVertex.spv"), ShaderStage.Vertex, TargetLanguage.Spirv),
|
||||||
new ShaderSource(ShaderBinaries.ColorBlitMsFragmentShaderSource, ShaderStage.Fragment, TargetLanguage.Spirv),
|
new ShaderSource(ReadSpirv("ColorBlitMsFragment.spv"), ShaderStage.Fragment, TargetLanguage.Spirv),
|
||||||
}, blitResourceLayout);
|
}, blitResourceLayout);
|
||||||
|
|
||||||
_programColorBlitClearAlpha = gd.CreateProgramWithMinimalLayout(new[]
|
_programColorBlitClearAlpha = gd.CreateProgramWithMinimalLayout(new[]
|
||||||
{
|
{
|
||||||
new ShaderSource(ShaderBinaries.ColorBlitVertexShaderSource, ShaderStage.Vertex, TargetLanguage.Spirv),
|
new ShaderSource(ReadSpirv("ColorBlitVertex.spv"), ShaderStage.Vertex, TargetLanguage.Spirv),
|
||||||
new ShaderSource(ShaderBinaries.ColorBlitClearAlphaFragmentShaderSource, ShaderStage.Fragment, TargetLanguage.Spirv),
|
new ShaderSource(ReadSpirv("ColorBlitClearAlphaFragment.spv"), ShaderStage.Fragment, TargetLanguage.Spirv),
|
||||||
}, blitResourceLayout);
|
}, blitResourceLayout);
|
||||||
|
|
||||||
var colorClearResourceLayout = new ResourceLayoutBuilder().Add(ResourceStages.Vertex, ResourceType.UniformBuffer, 1).Build();
|
var colorClearResourceLayout = new ResourceLayoutBuilder().Add(ResourceStages.Vertex, ResourceType.UniformBuffer, 1).Build();
|
||||||
|
|
||||||
_programColorClearF = gd.CreateProgramWithMinimalLayout(new[]
|
_programColorClearF = gd.CreateProgramWithMinimalLayout(new[]
|
||||||
{
|
{
|
||||||
new ShaderSource(ShaderBinaries.ColorClearVertexShaderSource, ShaderStage.Vertex, TargetLanguage.Spirv),
|
new ShaderSource(ReadSpirv("ColorClearVertex.spv"), ShaderStage.Vertex, TargetLanguage.Spirv),
|
||||||
new ShaderSource(ShaderBinaries.ColorClearFFragmentShaderSource, ShaderStage.Fragment, TargetLanguage.Spirv),
|
new ShaderSource(ReadSpirv("ColorClearFFragment.spv"), ShaderStage.Fragment, TargetLanguage.Spirv),
|
||||||
}, colorClearResourceLayout);
|
}, colorClearResourceLayout);
|
||||||
|
|
||||||
_programColorClearSI = gd.CreateProgramWithMinimalLayout(new[]
|
_programColorClearSI = gd.CreateProgramWithMinimalLayout(new[]
|
||||||
{
|
{
|
||||||
new ShaderSource(ShaderBinaries.ColorClearVertexShaderSource, ShaderStage.Vertex, TargetLanguage.Spirv),
|
new ShaderSource(ReadSpirv("ColorClearVertex.spv"), ShaderStage.Vertex, TargetLanguage.Spirv),
|
||||||
new ShaderSource(ShaderBinaries.ColorClearSIFragmentShaderSource, ShaderStage.Fragment, TargetLanguage.Spirv),
|
new ShaderSource(ReadSpirv("ColorClearSIFragment.spv"), ShaderStage.Fragment, TargetLanguage.Spirv),
|
||||||
}, colorClearResourceLayout);
|
}, colorClearResourceLayout);
|
||||||
|
|
||||||
_programColorClearUI = gd.CreateProgramWithMinimalLayout(new[]
|
_programColorClearUI = gd.CreateProgramWithMinimalLayout(new[]
|
||||||
{
|
{
|
||||||
new ShaderSource(ShaderBinaries.ColorClearVertexShaderSource, ShaderStage.Vertex, TargetLanguage.Spirv),
|
new ShaderSource(ReadSpirv("ColorClearVertex.spv"), ShaderStage.Vertex, TargetLanguage.Spirv),
|
||||||
new ShaderSource(ShaderBinaries.ColorClearUIFragmentShaderSource, ShaderStage.Fragment, TargetLanguage.Spirv),
|
new ShaderSource(ReadSpirv("ColorClearUIFragment.spv"), ShaderStage.Fragment, TargetLanguage.Spirv),
|
||||||
}, colorClearResourceLayout);
|
}, colorClearResourceLayout);
|
||||||
|
|
||||||
var strideChangeResourceLayout = new ResourceLayoutBuilder()
|
var strideChangeResourceLayout = new ResourceLayoutBuilder()
|
||||||
@@ -110,7 +112,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
|
|
||||||
_programStrideChange = gd.CreateProgramWithMinimalLayout(new[]
|
_programStrideChange = gd.CreateProgramWithMinimalLayout(new[]
|
||||||
{
|
{
|
||||||
new ShaderSource(ShaderBinaries.ChangeBufferStrideShaderSource, ShaderStage.Compute, TargetLanguage.Spirv),
|
new ShaderSource(ReadSpirv("ChangeBufferStride.spv"), ShaderStage.Compute, TargetLanguage.Spirv),
|
||||||
}, strideChangeResourceLayout);
|
}, strideChangeResourceLayout);
|
||||||
|
|
||||||
var colorCopyResourceLayout = new ResourceLayoutBuilder()
|
var colorCopyResourceLayout = new ResourceLayoutBuilder()
|
||||||
@@ -120,17 +122,17 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
|
|
||||||
_programColorCopyShortening = gd.CreateProgramWithMinimalLayout(new[]
|
_programColorCopyShortening = gd.CreateProgramWithMinimalLayout(new[]
|
||||||
{
|
{
|
||||||
new ShaderSource(ShaderBinaries.ColorCopyShorteningComputeShaderSource, ShaderStage.Compute, TargetLanguage.Spirv),
|
new ShaderSource(ReadSpirv("ColorCopyShorteningCompute.spv"), ShaderStage.Compute, TargetLanguage.Spirv),
|
||||||
}, colorCopyResourceLayout);
|
}, colorCopyResourceLayout);
|
||||||
|
|
||||||
_programColorCopyToNonMs = gd.CreateProgramWithMinimalLayout(new[]
|
_programColorCopyToNonMs = gd.CreateProgramWithMinimalLayout(new[]
|
||||||
{
|
{
|
||||||
new ShaderSource(ShaderBinaries.ColorCopyToNonMsComputeShaderSource, ShaderStage.Compute, TargetLanguage.Spirv),
|
new ShaderSource(ReadSpirv("ColorCopyToNonMsCompute.spv"), ShaderStage.Compute, TargetLanguage.Spirv),
|
||||||
}, colorCopyResourceLayout);
|
}, colorCopyResourceLayout);
|
||||||
|
|
||||||
_programColorCopyWidening = gd.CreateProgramWithMinimalLayout(new[]
|
_programColorCopyWidening = gd.CreateProgramWithMinimalLayout(new[]
|
||||||
{
|
{
|
||||||
new ShaderSource(ShaderBinaries.ColorCopyWideningComputeShaderSource, ShaderStage.Compute, TargetLanguage.Spirv),
|
new ShaderSource(ReadSpirv("ColorCopyWideningCompute.spv"), ShaderStage.Compute, TargetLanguage.Spirv),
|
||||||
}, colorCopyResourceLayout);
|
}, colorCopyResourceLayout);
|
||||||
|
|
||||||
var colorDrawToMsResourceLayout = new ResourceLayoutBuilder()
|
var colorDrawToMsResourceLayout = new ResourceLayoutBuilder()
|
||||||
@@ -139,8 +141,8 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
|
|
||||||
_programColorDrawToMs = gd.CreateProgramWithMinimalLayout(new[]
|
_programColorDrawToMs = gd.CreateProgramWithMinimalLayout(new[]
|
||||||
{
|
{
|
||||||
new ShaderSource(ShaderBinaries.ColorDrawToMsVertexShaderSource, ShaderStage.Vertex, TargetLanguage.Spirv),
|
new ShaderSource(ReadSpirv("ColorDrawToMsVertex.spv"), ShaderStage.Vertex, TargetLanguage.Spirv),
|
||||||
new ShaderSource(ShaderBinaries.ColorDrawToMsFragmentShaderSource, ShaderStage.Fragment, TargetLanguage.Spirv),
|
new ShaderSource(ReadSpirv("ColorDrawToMsFragment.spv"), ShaderStage.Fragment, TargetLanguage.Spirv),
|
||||||
}, colorDrawToMsResourceLayout);
|
}, colorDrawToMsResourceLayout);
|
||||||
|
|
||||||
var convertD32S8ToD24S8ResourceLayout = new ResourceLayoutBuilder()
|
var convertD32S8ToD24S8ResourceLayout = new ResourceLayoutBuilder()
|
||||||
@@ -150,7 +152,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
|
|
||||||
_programConvertD32S8ToD24S8 = gd.CreateProgramWithMinimalLayout(new[]
|
_programConvertD32S8ToD24S8 = gd.CreateProgramWithMinimalLayout(new[]
|
||||||
{
|
{
|
||||||
new ShaderSource(ShaderBinaries.ConvertD32S8ToD24S8ShaderSource, ShaderStage.Compute, TargetLanguage.Spirv),
|
new ShaderSource(ReadSpirv("ConvertD32S8ToD24S8.spv"), ShaderStage.Compute, TargetLanguage.Spirv),
|
||||||
}, convertD32S8ToD24S8ResourceLayout);
|
}, convertD32S8ToD24S8ResourceLayout);
|
||||||
|
|
||||||
var convertIndexBufferResourceLayout = new ResourceLayoutBuilder()
|
var convertIndexBufferResourceLayout = new ResourceLayoutBuilder()
|
||||||
@@ -160,7 +162,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
|
|
||||||
_programConvertIndexBuffer = gd.CreateProgramWithMinimalLayout(new[]
|
_programConvertIndexBuffer = gd.CreateProgramWithMinimalLayout(new[]
|
||||||
{
|
{
|
||||||
new ShaderSource(ShaderBinaries.ConvertIndexBufferShaderSource, ShaderStage.Compute, TargetLanguage.Spirv),
|
new ShaderSource(ReadSpirv("ConvertIndexBuffer.spv"), ShaderStage.Compute, TargetLanguage.Spirv),
|
||||||
}, convertIndexBufferResourceLayout);
|
}, convertIndexBufferResourceLayout);
|
||||||
|
|
||||||
var convertIndirectDataResourceLayout = new ResourceLayoutBuilder()
|
var convertIndirectDataResourceLayout = new ResourceLayoutBuilder()
|
||||||
@@ -171,61 +173,66 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
|
|
||||||
_programConvertIndirectData = gd.CreateProgramWithMinimalLayout(new[]
|
_programConvertIndirectData = gd.CreateProgramWithMinimalLayout(new[]
|
||||||
{
|
{
|
||||||
new ShaderSource(ShaderBinaries.ConvertIndirectDataShaderSource, ShaderStage.Compute, TargetLanguage.Spirv),
|
new ShaderSource(ReadSpirv("ConvertIndirectData.spv"), ShaderStage.Compute, TargetLanguage.Spirv),
|
||||||
}, convertIndirectDataResourceLayout);
|
}, convertIndirectDataResourceLayout);
|
||||||
|
|
||||||
_programDepthBlit = gd.CreateProgramWithMinimalLayout(new[]
|
_programDepthBlit = gd.CreateProgramWithMinimalLayout(new[]
|
||||||
{
|
{
|
||||||
new ShaderSource(ShaderBinaries.ColorBlitVertexShaderSource, ShaderStage.Vertex, TargetLanguage.Spirv),
|
new ShaderSource(ReadSpirv("ColorBlitVertex.spv"), ShaderStage.Vertex, TargetLanguage.Spirv),
|
||||||
new ShaderSource(ShaderBinaries.DepthBlitFragmentShaderSource, ShaderStage.Fragment, TargetLanguage.Spirv),
|
new ShaderSource(ReadSpirv("DepthBlitFragment.spv"), ShaderStage.Fragment, TargetLanguage.Spirv),
|
||||||
}, blitResourceLayout);
|
}, blitResourceLayout);
|
||||||
|
|
||||||
_programDepthBlitMs = gd.CreateProgramWithMinimalLayout(new[]
|
_programDepthBlitMs = gd.CreateProgramWithMinimalLayout(new[]
|
||||||
{
|
{
|
||||||
new ShaderSource(ShaderBinaries.ColorBlitVertexShaderSource, ShaderStage.Vertex, TargetLanguage.Spirv),
|
new ShaderSource(ReadSpirv("ColorBlitVertex.spv"), ShaderStage.Vertex, TargetLanguage.Spirv),
|
||||||
new ShaderSource(ShaderBinaries.DepthBlitMsFragmentShaderSource, ShaderStage.Fragment, TargetLanguage.Spirv),
|
new ShaderSource(ReadSpirv("DepthBlitMsFragment.spv"), ShaderStage.Fragment, TargetLanguage.Spirv),
|
||||||
}, blitResourceLayout);
|
}, blitResourceLayout);
|
||||||
|
|
||||||
_programDepthDrawToMs = gd.CreateProgramWithMinimalLayout(new[]
|
_programDepthDrawToMs = gd.CreateProgramWithMinimalLayout(new[]
|
||||||
{
|
{
|
||||||
new ShaderSource(ShaderBinaries.ColorDrawToMsVertexShaderSource, ShaderStage.Vertex, TargetLanguage.Spirv),
|
new ShaderSource(ReadSpirv("ColorDrawToMsVertex.spv"), ShaderStage.Vertex, TargetLanguage.Spirv),
|
||||||
new ShaderSource(ShaderBinaries.DepthDrawToMsFragmentShaderSource, ShaderStage.Fragment, TargetLanguage.Spirv),
|
new ShaderSource(ReadSpirv("DepthDrawToMsFragment.spv"), ShaderStage.Fragment, TargetLanguage.Spirv),
|
||||||
}, colorDrawToMsResourceLayout);
|
}, colorDrawToMsResourceLayout);
|
||||||
|
|
||||||
_programDepthDrawToNonMs = gd.CreateProgramWithMinimalLayout(new[]
|
_programDepthDrawToNonMs = gd.CreateProgramWithMinimalLayout(new[]
|
||||||
{
|
{
|
||||||
new ShaderSource(ShaderBinaries.ColorDrawToMsVertexShaderSource, ShaderStage.Vertex, TargetLanguage.Spirv),
|
new ShaderSource(ReadSpirv("ColorDrawToMsVertex.spv"), ShaderStage.Vertex, TargetLanguage.Spirv),
|
||||||
new ShaderSource(ShaderBinaries.DepthDrawToNonMsFragmentShaderSource, ShaderStage.Fragment, TargetLanguage.Spirv),
|
new ShaderSource(ReadSpirv("DepthDrawToNonMsFragment.spv"), ShaderStage.Fragment, TargetLanguage.Spirv),
|
||||||
}, colorDrawToMsResourceLayout);
|
}, colorDrawToMsResourceLayout);
|
||||||
|
|
||||||
if (gd.Capabilities.SupportsShaderStencilExport)
|
if (gd.Capabilities.SupportsShaderStencilExport)
|
||||||
{
|
{
|
||||||
_programStencilBlit = gd.CreateProgramWithMinimalLayout(new[]
|
_programStencilBlit = gd.CreateProgramWithMinimalLayout(new[]
|
||||||
{
|
{
|
||||||
new ShaderSource(ShaderBinaries.ColorBlitVertexShaderSource, ShaderStage.Vertex, TargetLanguage.Spirv),
|
new ShaderSource(ReadSpirv("ColorBlitVertex.spv"), ShaderStage.Vertex, TargetLanguage.Spirv),
|
||||||
new ShaderSource(ShaderBinaries.StencilBlitFragmentShaderSource, ShaderStage.Fragment, TargetLanguage.Spirv),
|
new ShaderSource(ReadSpirv("StencilBlitFragment.spv"), ShaderStage.Fragment, TargetLanguage.Spirv),
|
||||||
}, blitResourceLayout);
|
}, blitResourceLayout);
|
||||||
|
|
||||||
_programStencilBlitMs = gd.CreateProgramWithMinimalLayout(new[]
|
_programStencilBlitMs = gd.CreateProgramWithMinimalLayout(new[]
|
||||||
{
|
{
|
||||||
new ShaderSource(ShaderBinaries.ColorBlitVertexShaderSource, ShaderStage.Vertex, TargetLanguage.Spirv),
|
new ShaderSource(ReadSpirv("ColorBlitVertex.spv"), ShaderStage.Vertex, TargetLanguage.Spirv),
|
||||||
new ShaderSource(ShaderBinaries.StencilBlitMsFragmentShaderSource, ShaderStage.Fragment, TargetLanguage.Spirv),
|
new ShaderSource(ReadSpirv("StencilBlitMsFragment.spv"), ShaderStage.Fragment, TargetLanguage.Spirv),
|
||||||
}, blitResourceLayout);
|
}, blitResourceLayout);
|
||||||
|
|
||||||
_programStencilDrawToMs = gd.CreateProgramWithMinimalLayout(new[]
|
_programStencilDrawToMs = gd.CreateProgramWithMinimalLayout(new[]
|
||||||
{
|
{
|
||||||
new ShaderSource(ShaderBinaries.ColorDrawToMsVertexShaderSource, ShaderStage.Vertex, TargetLanguage.Spirv),
|
new ShaderSource(ReadSpirv("ColorDrawToMsVertex.spv"), ShaderStage.Vertex, TargetLanguage.Spirv),
|
||||||
new ShaderSource(ShaderBinaries.StencilDrawToMsFragmentShaderSource, ShaderStage.Fragment, TargetLanguage.Spirv),
|
new ShaderSource(ReadSpirv("StencilDrawToMsFragment.spv"), ShaderStage.Fragment, TargetLanguage.Spirv),
|
||||||
}, colorDrawToMsResourceLayout);
|
}, colorDrawToMsResourceLayout);
|
||||||
|
|
||||||
_programStencilDrawToNonMs = gd.CreateProgramWithMinimalLayout(new[]
|
_programStencilDrawToNonMs = gd.CreateProgramWithMinimalLayout(new[]
|
||||||
{
|
{
|
||||||
new ShaderSource(ShaderBinaries.ColorDrawToMsVertexShaderSource, ShaderStage.Vertex, TargetLanguage.Spirv),
|
new ShaderSource(ReadSpirv("ColorDrawToMsVertex.spv"), ShaderStage.Vertex, TargetLanguage.Spirv),
|
||||||
new ShaderSource(ShaderBinaries.StencilDrawToNonMsFragmentShaderSource, ShaderStage.Fragment, TargetLanguage.Spirv),
|
new ShaderSource(ReadSpirv("StencilDrawToNonMsFragment.spv"), ShaderStage.Fragment, TargetLanguage.Spirv),
|
||||||
}, colorDrawToMsResourceLayout);
|
}, colorDrawToMsResourceLayout);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static byte[] ReadSpirv(string fileName)
|
||||||
|
{
|
||||||
|
return EmbeddedResources.Read(string.Join('/', ShaderBinariesPath, fileName));
|
||||||
|
}
|
||||||
|
|
||||||
public void Blit(
|
public void Blit(
|
||||||
VulkanRenderer gd,
|
VulkanRenderer gd,
|
||||||
TextureView src,
|
TextureView src,
|
||||||
|
@@ -152,9 +152,6 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
{
|
{
|
||||||
if (_buffer == from)
|
if (_buffer == from)
|
||||||
{
|
{
|
||||||
_buffer.DecrementReferenceCount();
|
|
||||||
to.IncrementReferenceCount();
|
|
||||||
|
|
||||||
_buffer = to;
|
_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)
|
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)
|
if (FramebufferParams == null || !FramebufferParams.HasDepthStencil)
|
||||||
{
|
{
|
||||||
return;
|
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)
|
if (_renderPass == null)
|
||||||
{
|
{
|
||||||
CreateRenderPass();
|
CreateRenderPass();
|
||||||
@@ -259,14 +274,6 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
|
|
||||||
BeginRenderPass();
|
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 attachment = new ClearAttachment(flags, 0, clearValue);
|
||||||
var clearRect = FramebufferParams.GetClearRect(ClearScissor, layer, layerCount);
|
var clearRect = FramebufferParams.GetClearRect(ClearScissor, layer, layerCount);
|
||||||
|
|
||||||
@@ -935,7 +942,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
|
|
||||||
SignalStateChange();
|
SignalStateChange();
|
||||||
|
|
||||||
if (_program.IsCompute)
|
if (internalProgram.IsCompute)
|
||||||
{
|
{
|
||||||
EndRenderPass();
|
EndRenderPass();
|
||||||
}
|
}
|
||||||
|
@@ -21,6 +21,31 @@
|
|||||||
<EmbeddedResource Include="Effects\Shaders\SmaaBlend.spv" />
|
<EmbeddedResource Include="Effects\Shaders\SmaaBlend.spv" />
|
||||||
<EmbeddedResource Include="Effects\Shaders\SmaaEdge.spv" />
|
<EmbeddedResource Include="Effects\Shaders\SmaaEdge.spv" />
|
||||||
<EmbeddedResource Include="Effects\Shaders\SmaaNeighbour.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>
|
||||||
|
|
||||||
<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 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;
|
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;
|
var usage = DefaultUsageFlags;
|
||||||
|
|
||||||
@@ -304,7 +304,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
usage |= ImageUsageFlags.ColorAttachmentBit;
|
usage |= ImageUsageFlags.ColorAttachmentBit;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (format.IsImageCompatible() && (supportsMsStorage || !target.IsMultisample()))
|
if (((forceStorage && !format.IsDepthOrStencil()) || format.IsImageCompatible()) && (supportsMsStorage || !target.IsMultisample()))
|
||||||
{
|
{
|
||||||
usage |= ImageUsageFlags.StorageBit;
|
usage |= ImageUsageFlags.StorageBit;
|
||||||
}
|
}
|
||||||
|
@@ -116,7 +116,14 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
return new Auto<DisposableImageView>(new DisposableImageView(gd.Api, device, imageView), null, storage.GetImage());
|
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.
|
// Framebuffer attachments and storage images requires a identity component mapping.
|
||||||
var identityComponentMapping = new ComponentMapping(
|
var identityComponentMapping = new ComponentMapping(
|
||||||
@@ -378,7 +385,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
|
|
||||||
bool isDepthOrStencil = dst.Info.Format.IsDepthOrStencil();
|
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.HelperShader.Blit(
|
||||||
_gd,
|
_gd,
|
||||||
|
@@ -3,7 +3,7 @@
|
|||||||
static class VulkanConfiguration
|
static class VulkanConfiguration
|
||||||
{
|
{
|
||||||
public const bool UseFastBufferUpdates = true;
|
public const bool UseFastBufferUpdates = true;
|
||||||
public const bool UseSlowSafeBlitOnAmd = true;
|
public const bool UseUnsafeBlit = true;
|
||||||
public const bool UsePushDescriptors = false;
|
public const bool UsePushDescriptors = false;
|
||||||
|
|
||||||
public const bool ForceD24S8Unsupported = false;
|
public const bool ForceD24S8Unsupported = false;
|
||||||
|
@@ -10,17 +10,6 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
{
|
{
|
||||||
class VulkanDebugMessenger : IDisposable
|
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 Vk _api;
|
||||||
private readonly Instance _instance;
|
private readonly Instance _instance;
|
||||||
private readonly GraphicsDebugLevel _logLevel;
|
private readonly GraphicsDebugLevel _logLevel;
|
||||||
@@ -108,14 +97,6 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
{
|
{
|
||||||
var msg = Marshal.PtrToStringAnsi((IntPtr)pCallbackData->PMessage);
|
var msg = Marshal.PtrToStringAnsi((IntPtr)pCallbackData->PMessage);
|
||||||
|
|
||||||
foreach (string excludedMessagePart in _excludedMessages)
|
|
||||||
{
|
|
||||||
if (msg.Contains(excludedMessagePart))
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (messageSeverity.HasFlag(DebugUtilsMessageSeverityFlagsEXT.ErrorBitExt))
|
if (messageSeverity.HasFlag(DebugUtilsMessageSeverityFlagsEXT.ErrorBitExt))
|
||||||
{
|
{
|
||||||
Logger.Error?.Print(LogClass.Gpu, msg);
|
Logger.Error?.Print(LogClass.Gpu, msg);
|
||||||
|
@@ -377,8 +377,8 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
ShaderFloat64 = supportedFeatures.ShaderFloat64,
|
ShaderFloat64 = supportedFeatures.ShaderFloat64,
|
||||||
ShaderImageGatherExtended = supportedFeatures.ShaderImageGatherExtended,
|
ShaderImageGatherExtended = supportedFeatures.ShaderImageGatherExtended,
|
||||||
ShaderStorageImageMultisample = supportedFeatures.ShaderStorageImageMultisample,
|
ShaderStorageImageMultisample = supportedFeatures.ShaderStorageImageMultisample,
|
||||||
// ShaderStorageImageReadWithoutFormat = true,
|
ShaderStorageImageReadWithoutFormat = supportedFeatures.ShaderStorageImageReadWithoutFormat,
|
||||||
// ShaderStorageImageWriteWithoutFormat = true,
|
ShaderStorageImageWriteWithoutFormat = supportedFeatures.ShaderStorageImageWriteWithoutFormat,
|
||||||
TessellationShader = supportedFeatures.TessellationShader,
|
TessellationShader = supportedFeatures.TessellationShader,
|
||||||
VertexPipelineStoresAndAtomics = supportedFeatures.VertexPipelineStoresAndAtomics,
|
VertexPipelineStoresAndAtomics = supportedFeatures.VertexPipelineStoresAndAtomics,
|
||||||
RobustBufferAccess = useRobustBufferAccess,
|
RobustBufferAccess = useRobustBufferAccess,
|
||||||
|
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
namespace Ryujinx.HLE.Exceptions
|
namespace Ryujinx.HLE.Exceptions
|
||||||
{
|
{
|
||||||
class InternalServiceException: Exception
|
class InternalServiceException : Exception
|
||||||
{
|
{
|
||||||
public InternalServiceException(string message) : base(message) { }
|
public InternalServiceException(string message) : base(message) { }
|
||||||
}
|
}
|
||||||
|
@@ -47,7 +47,7 @@ namespace Ryujinx.HLE.Exceptions
|
|||||||
|
|
||||||
private string BuildMessage()
|
private string BuildMessage()
|
||||||
{
|
{
|
||||||
StringBuilder sb = new StringBuilder();
|
StringBuilder sb = new();
|
||||||
|
|
||||||
// Print the IPC command details (service name, command ID, and handler)
|
// Print the IPC command details (service name, command ID, and handler)
|
||||||
(Type callingType, MethodBase callingMethod) = WalkStackTrace(new StackTrace(this));
|
(Type callingType, MethodBase callingMethod) = WalkStackTrace(new StackTrace(this));
|
||||||
@@ -58,9 +58,9 @@ namespace Ryujinx.HLE.Exceptions
|
|||||||
var ipcCommands = Request.Type > IpcMessageType.TipcCloseSession ? Service.TipcCommands : Service.CmifCommands;
|
var ipcCommands = Request.Type > IpcMessageType.TipcCloseSession ? Service.TipcCommands : Service.CmifCommands;
|
||||||
|
|
||||||
// Find the handler for the method called
|
// Find the handler for the method called
|
||||||
var ipcHandler = ipcCommands.FirstOrDefault(x => x.Value == callingMethod);
|
var ipcHandler = ipcCommands.FirstOrDefault(x => x.Value == callingMethod);
|
||||||
var ipcCommandId = ipcHandler.Key;
|
var ipcCommandId = ipcHandler.Key;
|
||||||
var ipcMethod = ipcHandler.Value;
|
var ipcMethod = ipcHandler.Value;
|
||||||
|
|
||||||
if (ipcMethod != null)
|
if (ipcMethod != null)
|
||||||
{
|
{
|
||||||
@@ -73,9 +73,9 @@ namespace Ryujinx.HLE.Exceptions
|
|||||||
sb.AppendLine(Context.Thread.GetGuestStackTrace());
|
sb.AppendLine(Context.Thread.GetGuestStackTrace());
|
||||||
|
|
||||||
// Print buffer information
|
// Print buffer information
|
||||||
if (Request.PtrBuff.Count > 0 ||
|
if (Request.PtrBuff.Count > 0 ||
|
||||||
Request.SendBuff.Count > 0 ||
|
Request.SendBuff.Count > 0 ||
|
||||||
Request.ReceiveBuff.Count > 0 ||
|
Request.ReceiveBuff.Count > 0 ||
|
||||||
Request.ExchangeBuff.Count > 0 ||
|
Request.ExchangeBuff.Count > 0 ||
|
||||||
Request.RecvListBuff.Count > 0)
|
Request.RecvListBuff.Count > 0)
|
||||||
{
|
{
|
||||||
@@ -149,7 +149,7 @@ namespace Ryujinx.HLE.Exceptions
|
|||||||
// Find the IIpcService method that threw this exception
|
// Find the IIpcService method that threw this exception
|
||||||
while ((frame = trace.GetFrame(i++)) != null)
|
while ((frame = trace.GetFrame(i++)) != null)
|
||||||
{
|
{
|
||||||
var method = frame.GetMethod();
|
var method = frame.GetMethod();
|
||||||
var declType = method.DeclaringType;
|
var declType = method.DeclaringType;
|
||||||
|
|
||||||
if (typeof(IpcService).IsAssignableFrom(declType))
|
if (typeof(IpcService).IsAssignableFrom(declType))
|
||||||
|
@@ -26,17 +26,17 @@ namespace Ryujinx.HLE.FileSystem
|
|||||||
public class ContentManager
|
public class ContentManager
|
||||||
{
|
{
|
||||||
private const ulong SystemVersionTitleId = 0x0100000000000809;
|
private const ulong SystemVersionTitleId = 0x0100000000000809;
|
||||||
private const ulong SystemUpdateTitleId = 0x0100000000000816;
|
private const ulong SystemUpdateTitleId = 0x0100000000000816;
|
||||||
|
|
||||||
private Dictionary<StorageId, LinkedList<LocationEntry>> _locationEntries;
|
private Dictionary<StorageId, LinkedList<LocationEntry>> _locationEntries;
|
||||||
|
|
||||||
private Dictionary<string, ulong> _sharedFontTitleDictionary;
|
private readonly Dictionary<string, ulong> _sharedFontTitleDictionary;
|
||||||
private Dictionary<ulong, string> _systemTitlesNameDictionary;
|
private readonly Dictionary<ulong, string> _systemTitlesNameDictionary;
|
||||||
private Dictionary<string, string> _sharedFontFilenameDictionary;
|
private readonly Dictionary<string, string> _sharedFontFilenameDictionary;
|
||||||
|
|
||||||
private SortedDictionary<(ulong titleId, NcaContentType type), string> _contentDictionary;
|
private SortedDictionary<(ulong titleId, NcaContentType type), string> _contentDictionary;
|
||||||
|
|
||||||
private struct AocItem
|
private readonly struct AocItem
|
||||||
{
|
{
|
||||||
public readonly string ContainerPath;
|
public readonly string ContainerPath;
|
||||||
public readonly string NcaPath;
|
public readonly string NcaPath;
|
||||||
@@ -48,16 +48,16 @@ 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();
|
private readonly object _lock = new();
|
||||||
|
|
||||||
public ContentManager(VirtualFileSystem virtualFileSystem)
|
public ContentManager(VirtualFileSystem virtualFileSystem)
|
||||||
{
|
{
|
||||||
_contentDictionary = new SortedDictionary<(ulong, NcaContentType), string>();
|
_contentDictionary = new SortedDictionary<(ulong, NcaContentType), string>();
|
||||||
_locationEntries = new Dictionary<StorageId, LinkedList<LocationEntry>>();
|
_locationEntries = new Dictionary<StorageId, LinkedList<LocationEntry>>();
|
||||||
|
|
||||||
_sharedFontTitleDictionary = new Dictionary<string, ulong>
|
_sharedFontTitleDictionary = new Dictionary<string, ulong>
|
||||||
{
|
{
|
||||||
@@ -66,7 +66,7 @@ namespace Ryujinx.HLE.FileSystem
|
|||||||
{ "FontExtendedChineseSimplified", 0x0100000000000814 },
|
{ "FontExtendedChineseSimplified", 0x0100000000000814 },
|
||||||
{ "FontKorean", 0x0100000000000812 },
|
{ "FontKorean", 0x0100000000000812 },
|
||||||
{ "FontChineseTraditional", 0x0100000000000813 },
|
{ "FontChineseTraditional", 0x0100000000000813 },
|
||||||
{ "FontNintendoExtended", 0x0100000000000810 }
|
{ "FontNintendoExtended", 0x0100000000000810 },
|
||||||
};
|
};
|
||||||
|
|
||||||
_systemTitlesNameDictionary = new Dictionary<ulong, string>()
|
_systemTitlesNameDictionary = new Dictionary<ulong, string>()
|
||||||
@@ -86,12 +86,12 @@ namespace Ryujinx.HLE.FileSystem
|
|||||||
{ "FontExtendedChineseSimplified", "nintendo_udsg-r_ext_zh-cn_003.bfttf" },
|
{ "FontExtendedChineseSimplified", "nintendo_udsg-r_ext_zh-cn_003.bfttf" },
|
||||||
{ "FontKorean", "nintendo_udsg-r_ko_003.bfttf" },
|
{ "FontKorean", "nintendo_udsg-r_ko_003.bfttf" },
|
||||||
{ "FontChineseTraditional", "nintendo_udjxh-db_zh-tw_003.bfttf" },
|
{ "FontChineseTraditional", "nintendo_udjxh-db_zh-tw_003.bfttf" },
|
||||||
{ "FontNintendoExtended", "nintendo_ext_003.bfttf" }
|
{ "FontNintendoExtended", "nintendo_ext_003.bfttf" },
|
||||||
};
|
};
|
||||||
|
|
||||||
_virtualFileSystem = virtualFileSystem;
|
_virtualFileSystem = virtualFileSystem;
|
||||||
|
|
||||||
_aocData = new SortedList<ulong, AocItem>();
|
AocData = new SortedList<ulong, AocItem>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void LoadEntries(Switch device = null)
|
public void LoadEntries(Switch device = null)
|
||||||
@@ -99,18 +99,18 @@ namespace Ryujinx.HLE.FileSystem
|
|||||||
lock (_lock)
|
lock (_lock)
|
||||||
{
|
{
|
||||||
_contentDictionary = new SortedDictionary<(ulong, NcaContentType), string>();
|
_contentDictionary = new SortedDictionary<(ulong, NcaContentType), string>();
|
||||||
_locationEntries = new Dictionary<StorageId, LinkedList<LocationEntry>>();
|
_locationEntries = new Dictionary<StorageId, LinkedList<LocationEntry>>();
|
||||||
|
|
||||||
foreach (StorageId storageId in Enum.GetValues<StorageId>())
|
foreach (StorageId storageId in Enum.GetValues<StorageId>())
|
||||||
{
|
{
|
||||||
string contentDirectory = null;
|
string contentDirectory = null;
|
||||||
string contentPathString = null;
|
string contentPathString = null;
|
||||||
string registeredDirectory = null;
|
string registeredDirectory = null;
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
contentPathString = ContentPath.GetContentPath(storageId);
|
contentPathString = ContentPath.GetContentPath(storageId);
|
||||||
contentDirectory = ContentPath.GetRealPath(_virtualFileSystem, contentPathString);
|
contentDirectory = ContentPath.GetRealPath(contentPathString);
|
||||||
registeredDirectory = Path.Combine(contentDirectory, "registered");
|
registeredDirectory = Path.Combine(contentDirectory, "registered");
|
||||||
}
|
}
|
||||||
catch (NotSupportedException)
|
catch (NotSupportedException)
|
||||||
@@ -120,7 +120,7 @@ namespace Ryujinx.HLE.FileSystem
|
|||||||
|
|
||||||
Directory.CreateDirectory(registeredDirectory);
|
Directory.CreateDirectory(registeredDirectory);
|
||||||
|
|
||||||
LinkedList<LocationEntry> locationList = new LinkedList<LocationEntry>();
|
LinkedList<LocationEntry> locationList = new();
|
||||||
|
|
||||||
void AddEntry(LocationEntry entry)
|
void AddEntry(LocationEntry entry)
|
||||||
{
|
{
|
||||||
@@ -133,24 +133,19 @@ namespace Ryujinx.HLE.FileSystem
|
|||||||
{
|
{
|
||||||
string ncaName = new DirectoryInfo(directoryPath).Name.Replace(".nca", string.Empty);
|
string ncaName = new DirectoryInfo(directoryPath).Name.Replace(".nca", string.Empty);
|
||||||
|
|
||||||
using (FileStream ncaFile = File.OpenRead(Directory.GetFiles(directoryPath)[0]))
|
using FileStream ncaFile = File.OpenRead(Directory.GetFiles(directoryPath)[0]);
|
||||||
{
|
Nca nca = new(_virtualFileSystem.KeySet, ncaFile.AsStorage());
|
||||||
Nca nca = new Nca(_virtualFileSystem.KeySet, ncaFile.AsStorage());
|
|
||||||
|
|
||||||
string switchPath = contentPathString + ":/" + ncaFile.Name.Replace(contentDirectory, string.Empty).TrimStart(Path.DirectorySeparatorChar);
|
string switchPath = contentPathString + ":/" + ncaFile.Name.Replace(contentDirectory, string.Empty).TrimStart(Path.DirectorySeparatorChar);
|
||||||
|
|
||||||
// Change path format to switch's
|
// Change path format to switch's
|
||||||
switchPath = switchPath.Replace('\\', '/');
|
switchPath = switchPath.Replace('\\', '/');
|
||||||
|
|
||||||
LocationEntry entry = new LocationEntry(switchPath,
|
LocationEntry entry = new(switchPath, 0, nca.Header.TitleId, nca.Header.ContentType);
|
||||||
0,
|
|
||||||
nca.Header.TitleId,
|
|
||||||
nca.Header.ContentType);
|
|
||||||
|
|
||||||
AddEntry(entry);
|
AddEntry(entry);
|
||||||
|
|
||||||
_contentDictionary.Add((nca.Header.TitleId, nca.Header.ContentType), ncaName);
|
_contentDictionary.Add((nca.Header.TitleId, nca.Header.ContentType), ncaName);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -160,24 +155,19 @@ namespace Ryujinx.HLE.FileSystem
|
|||||||
{
|
{
|
||||||
string ncaName = Path.GetFileNameWithoutExtension(filePath);
|
string ncaName = Path.GetFileNameWithoutExtension(filePath);
|
||||||
|
|
||||||
using (FileStream ncaFile = new FileStream(filePath, FileMode.Open, FileAccess.Read))
|
using FileStream ncaFile = new(filePath, FileMode.Open, FileAccess.Read);
|
||||||
{
|
Nca nca = new(_virtualFileSystem.KeySet, ncaFile.AsStorage());
|
||||||
Nca nca = new Nca(_virtualFileSystem.KeySet, ncaFile.AsStorage());
|
|
||||||
|
|
||||||
string switchPath = contentPathString + ":/" + filePath.Replace(contentDirectory, string.Empty).TrimStart(Path.DirectorySeparatorChar);
|
string switchPath = contentPathString + ":/" + filePath.Replace(contentDirectory, string.Empty).TrimStart(Path.DirectorySeparatorChar);
|
||||||
|
|
||||||
// Change path format to switch's
|
// Change path format to switch's
|
||||||
switchPath = switchPath.Replace('\\', '/');
|
switchPath = switchPath.Replace('\\', '/');
|
||||||
|
|
||||||
LocationEntry entry = new LocationEntry(switchPath,
|
LocationEntry entry = new(switchPath, 0, nca.Header.TitleId, nca.Header.ContentType);
|
||||||
0,
|
|
||||||
nca.Header.TitleId,
|
|
||||||
nca.Header.ContentType);
|
|
||||||
|
|
||||||
AddEntry(entry);
|
AddEntry(entry);
|
||||||
|
|
||||||
_contentDictionary.Add((nca.Header.TitleId, nca.Header.ContentType), ncaName);
|
_contentDictionary.Add((nca.Header.TitleId, nca.Header.ContentType), ncaName);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -186,10 +176,7 @@ namespace Ryujinx.HLE.FileSystem
|
|||||||
_locationEntries.Remove(storageId);
|
_locationEntries.Remove(storageId);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!_locationEntries.ContainsKey(storageId))
|
_locationEntries.TryAdd(storageId, locationList);
|
||||||
{
|
|
||||||
_locationEntries.Add(storageId, locationList);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (device != null)
|
if (device != null)
|
||||||
@@ -239,7 +226,7 @@ namespace Ryujinx.HLE.FileSystem
|
|||||||
public void AddAocItem(ulong titleId, string containerPath, string ncaPath, bool mergedToContainer = false)
|
public void AddAocItem(ulong titleId, string containerPath, string ncaPath, bool mergedToContainer = false)
|
||||||
{
|
{
|
||||||
// TODO: Check Aoc version.
|
// 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}");
|
Logger.Warning?.Print(LogClass.Application, $"Duplicate AddOnContent detected. TitleId {titleId:X16}");
|
||||||
}
|
}
|
||||||
@@ -249,7 +236,7 @@ namespace Ryujinx.HLE.FileSystem
|
|||||||
|
|
||||||
if (!mergedToContainer)
|
if (!mergedToContainer)
|
||||||
{
|
{
|
||||||
using FileStream fileStream = File.OpenRead(containerPath);
|
using FileStream fileStream = File.OpenRead(containerPath);
|
||||||
using PartitionFileSystem partitionFileSystem = new(fileStream.AsStorage());
|
using PartitionFileSystem partitionFileSystem = new(fileStream.AsStorage());
|
||||||
|
|
||||||
_virtualFileSystem.ImportTickets(partitionFileSystem);
|
_virtualFileSystem.ImportTickets(partitionFileSystem);
|
||||||
@@ -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)
|
public bool GetAocDataStorage(ulong aocTitleId, out IStorage aocStorage, IntegrityCheckLevel integrityCheckLevel)
|
||||||
{
|
{
|
||||||
aocStorage = null;
|
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);
|
var file = new FileStream(aoc.ContainerPath, FileMode.Open, FileAccess.Read);
|
||||||
using var ncaFile = new UniqueRef<IFile>();
|
using var ncaFile = new UniqueRef<IFile>();
|
||||||
@@ -307,7 +294,7 @@ namespace Ryujinx.HLE.FileSystem
|
|||||||
{
|
{
|
||||||
lock (_lock)
|
lock (_lock)
|
||||||
{
|
{
|
||||||
LinkedList<LocationEntry> locationList = _locationEntries[storageId];
|
LinkedList<LocationEntry> locationList = _locationEntries[storageId];
|
||||||
LinkedListNode<LocationEntry> locationEntry = locationList.First;
|
LinkedListNode<LocationEntry> locationEntry = locationList.First;
|
||||||
|
|
||||||
while (locationEntry != null)
|
while (locationEntry != null)
|
||||||
@@ -331,7 +318,7 @@ namespace Ryujinx.HLE.FileSystem
|
|||||||
if (_contentDictionary.ContainsValue(ncaId))
|
if (_contentDictionary.ContainsValue(ncaId))
|
||||||
{
|
{
|
||||||
var content = _contentDictionary.FirstOrDefault(x => x.Value == ncaId);
|
var content = _contentDictionary.FirstOrDefault(x => x.Value == ncaId);
|
||||||
ulong titleId = content.Key.Item1;
|
ulong titleId = content.Key.titleId;
|
||||||
|
|
||||||
NcaContentType contentType = content.Key.type;
|
NcaContentType contentType = content.Key.type;
|
||||||
StorageId storage = GetInstalledStorage(titleId, contentType, storageId);
|
StorageId storage = GetInstalledStorage(titleId, contentType, storageId);
|
||||||
@@ -403,19 +390,17 @@ namespace Ryujinx.HLE.FileSystem
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
string installedPath = _virtualFileSystem.SwitchPathToSystemPath(locationEntry.ContentPath);
|
string installedPath = VirtualFileSystem.SwitchPathToSystemPath(locationEntry.ContentPath);
|
||||||
|
|
||||||
if (!string.IsNullOrWhiteSpace(installedPath))
|
if (!string.IsNullOrWhiteSpace(installedPath))
|
||||||
{
|
{
|
||||||
if (File.Exists(installedPath))
|
if (File.Exists(installedPath))
|
||||||
{
|
{
|
||||||
using (FileStream file = new FileStream(installedPath, FileMode.Open, FileAccess.Read))
|
using FileStream file = new(installedPath, FileMode.Open, FileAccess.Read);
|
||||||
{
|
Nca nca = new(_virtualFileSystem.KeySet, file.AsStorage());
|
||||||
Nca nca = new Nca(_virtualFileSystem.KeySet, file.AsStorage());
|
bool contentCheck = nca.Header.ContentType == contentType;
|
||||||
bool contentCheck = nca.Header.ContentType == contentType;
|
|
||||||
|
|
||||||
return contentCheck;
|
return contentCheck;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -426,9 +411,9 @@ namespace Ryujinx.HLE.FileSystem
|
|||||||
{
|
{
|
||||||
LinkedList<LocationEntry> locationList = null;
|
LinkedList<LocationEntry> locationList = null;
|
||||||
|
|
||||||
if (_locationEntries.ContainsKey(storageId))
|
if (_locationEntries.TryGetValue(storageId, out LinkedList<LocationEntry> locationEntry))
|
||||||
{
|
{
|
||||||
locationList = _locationEntries[storageId];
|
locationList = locationEntry;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (locationList != null)
|
if (locationList != null)
|
||||||
@@ -446,9 +431,9 @@ namespace Ryujinx.HLE.FileSystem
|
|||||||
{
|
{
|
||||||
LinkedList<LocationEntry> locationList = null;
|
LinkedList<LocationEntry> locationList = null;
|
||||||
|
|
||||||
if (_locationEntries.ContainsKey(storageId))
|
if (_locationEntries.TryGetValue(storageId, out LinkedList<LocationEntry> locationEntry))
|
||||||
{
|
{
|
||||||
locationList = _locationEntries[storageId];
|
locationList = locationEntry;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (locationList != null)
|
if (locationList != null)
|
||||||
@@ -487,10 +472,10 @@ namespace Ryujinx.HLE.FileSystem
|
|||||||
|
|
||||||
public void InstallFirmware(string firmwareSource)
|
public void InstallFirmware(string firmwareSource)
|
||||||
{
|
{
|
||||||
string contentPathString = ContentPath.GetContentPath(StorageId.BuiltInSystem);
|
string contentPathString = ContentPath.GetContentPath(StorageId.BuiltInSystem);
|
||||||
string contentDirectory = ContentPath.GetRealPath(_virtualFileSystem, contentPathString);
|
string contentDirectory = ContentPath.GetRealPath(contentPathString);
|
||||||
string registeredDirectory = Path.Combine(contentDirectory, "registered");
|
string registeredDirectory = Path.Combine(contentDirectory, "registered");
|
||||||
string temporaryDirectory = Path.Combine(contentDirectory, "temp");
|
string temporaryDirectory = Path.Combine(contentDirectory, "temp");
|
||||||
|
|
||||||
if (Directory.Exists(temporaryDirectory))
|
if (Directory.Exists(temporaryDirectory))
|
||||||
{
|
{
|
||||||
@@ -510,28 +495,27 @@ namespace Ryujinx.HLE.FileSystem
|
|||||||
throw new FileNotFoundException("Firmware file does not exist.");
|
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)
|
||||||
{
|
{
|
||||||
switch (info.Extension)
|
case ".zip":
|
||||||
{
|
using (ZipArchive archive = ZipFile.OpenRead(firmwareSource))
|
||||||
case ".zip":
|
{
|
||||||
using (ZipArchive archive = ZipFile.OpenRead(firmwareSource))
|
InstallFromZip(archive, temporaryDirectory);
|
||||||
{
|
}
|
||||||
InstallFromZip(archive, temporaryDirectory);
|
break;
|
||||||
}
|
case ".xci":
|
||||||
break;
|
Xci xci = new(_virtualFileSystem.KeySet, file.AsStorage());
|
||||||
case ".xci":
|
InstallFromCart(xci, temporaryDirectory);
|
||||||
Xci xci = new Xci(_virtualFileSystem.KeySet, file.AsStorage());
|
break;
|
||||||
InstallFromCart(xci, temporaryDirectory);
|
default:
|
||||||
break;
|
throw new InvalidFirmwarePackageException("Input file is not a valid firmware package");
|
||||||
default:
|
|
||||||
throw new InvalidFirmwarePackageException("Input file is not a valid firmware package");
|
|
||||||
}
|
|
||||||
|
|
||||||
FinishInstallation(temporaryDirectory, registeredDirectory);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FinishInstallation(temporaryDirectory, registeredDirectory);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void FinishInstallation(string temporaryDirectory, string registeredDirectory)
|
private void FinishInstallation(string temporaryDirectory, string registeredDirectory)
|
||||||
@@ -555,7 +539,7 @@ namespace Ryujinx.HLE.FileSystem
|
|||||||
{
|
{
|
||||||
foreach (var entry in filesystem.EnumerateEntries("/", "*.nca"))
|
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);
|
SaveNca(nca, entry.Name.Remove(entry.Name.IndexOf('.')), temporaryDirectory);
|
||||||
}
|
}
|
||||||
@@ -575,52 +559,47 @@ namespace Ryujinx.HLE.FileSystem
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void InstallFromZip(ZipArchive archive, string temporaryDirectory)
|
private static void InstallFromZip(ZipArchive archive, string temporaryDirectory)
|
||||||
{
|
{
|
||||||
using (archive)
|
foreach (var entry in archive.Entries)
|
||||||
{
|
{
|
||||||
foreach (var entry in archive.Entries)
|
if (entry.FullName.EndsWith(".nca") || entry.FullName.EndsWith(".nca/00"))
|
||||||
{
|
{
|
||||||
if (entry.FullName.EndsWith(".nca") || entry.FullName.EndsWith(".nca/00"))
|
// Clean up the name and get the NcaId
|
||||||
|
|
||||||
|
string[] pathComponents = entry.FullName.Replace(".cnmt", "").Split('/');
|
||||||
|
|
||||||
|
string ncaId = pathComponents[^1];
|
||||||
|
|
||||||
|
// If this is a fragmented nca, we need to get the previous element.GetZip
|
||||||
|
if (ncaId.Equals("00"))
|
||||||
{
|
{
|
||||||
// Clean up the name and get the NcaId
|
ncaId = pathComponents[^2];
|
||||||
|
}
|
||||||
|
|
||||||
string[] pathComponents = entry.FullName.Replace(".cnmt", "").Split('/');
|
if (ncaId.Contains(".nca"))
|
||||||
|
{
|
||||||
|
string newPath = Path.Combine(temporaryDirectory, ncaId);
|
||||||
|
|
||||||
string ncaId = pathComponents[pathComponents.Length - 1];
|
Directory.CreateDirectory(newPath);
|
||||||
|
|
||||||
// If this is a fragmented nca, we need to get the previous element.GetZip
|
entry.ExtractToFile(Path.Combine(newPath, "00"));
|
||||||
if (ncaId.Equals("00"))
|
|
||||||
{
|
|
||||||
ncaId = pathComponents[pathComponents.Length - 2];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ncaId.Contains(".nca"))
|
|
||||||
{
|
|
||||||
string newPath = Path.Combine(temporaryDirectory, ncaId);
|
|
||||||
|
|
||||||
Directory.CreateDirectory(newPath);
|
|
||||||
|
|
||||||
entry.ExtractToFile(Path.Combine(newPath, "00"));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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");
|
string newPath = Path.Combine(temporaryDirectory, ncaId + ".nca");
|
||||||
|
|
||||||
Directory.CreateDirectory(newPath);
|
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);
|
||||||
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>();
|
using var file = new UniqueRef<IFile>();
|
||||||
|
|
||||||
@@ -636,14 +615,12 @@ namespace Ryujinx.HLE.FileSystem
|
|||||||
return file.Release();
|
return file.Release();
|
||||||
}
|
}
|
||||||
|
|
||||||
private Stream GetZipStream(ZipArchiveEntry entry)
|
private static Stream GetZipStream(ZipArchiveEntry entry)
|
||||||
{
|
{
|
||||||
MemoryStream dest = MemoryStreamManager.Shared.GetStream();
|
MemoryStream dest = MemoryStreamManager.Shared.GetStream();
|
||||||
|
|
||||||
using (Stream src = entry.Open())
|
using Stream src = entry.Open();
|
||||||
{
|
src.CopyTo(dest);
|
||||||
src.CopyTo(dest);
|
|
||||||
}
|
|
||||||
|
|
||||||
return dest;
|
return dest;
|
||||||
}
|
}
|
||||||
@@ -659,7 +636,7 @@ namespace Ryujinx.HLE.FileSystem
|
|||||||
throw new MissingKeyException("HeaderKey is empty. Cannot decrypt NCA headers.");
|
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))
|
if (Directory.Exists(firmwarePackage))
|
||||||
{
|
{
|
||||||
@@ -671,33 +648,32 @@ namespace Ryujinx.HLE.FileSystem
|
|||||||
throw new FileNotFoundException("Firmware file does not exist.");
|
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)
|
||||||
{
|
{
|
||||||
switch (info.Extension)
|
case ".zip":
|
||||||
{
|
using (ZipArchive archive = ZipFile.OpenRead(firmwarePackage))
|
||||||
case ".zip":
|
{
|
||||||
using (ZipArchive archive = ZipFile.OpenRead(firmwarePackage))
|
return VerifyAndGetVersionZip(archive);
|
||||||
{
|
}
|
||||||
return VerifyAndGetVersionZip(archive);
|
case ".xci":
|
||||||
}
|
Xci xci = new(_virtualFileSystem.KeySet, file.AsStorage());
|
||||||
case ".xci":
|
|
||||||
Xci xci = new Xci(_virtualFileSystem.KeySet, file.AsStorage());
|
|
||||||
|
|
||||||
if (xci.HasPartition(XciPartitionType.Update))
|
if (xci.HasPartition(XciPartitionType.Update))
|
||||||
{
|
{
|
||||||
XciPartition partition = xci.OpenPartition(XciPartitionType.Update);
|
XciPartition partition = xci.OpenPartition(XciPartitionType.Update);
|
||||||
|
|
||||||
return VerifyAndGetVersion(partition);
|
return VerifyAndGetVersion(partition);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
throw new InvalidFirmwarePackageException("Update not found in xci file.");
|
throw new InvalidFirmwarePackageException("Update not found in xci file.");
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SystemVersion VerifyAndGetVersionDirectory(string firmwareDirectory)
|
SystemVersion VerifyAndGetVersionDirectory(string firmwareDirectory)
|
||||||
@@ -713,21 +689,19 @@ namespace Ryujinx.HLE.FileSystem
|
|||||||
{
|
{
|
||||||
if (entry.FullName.EndsWith(".nca") || entry.FullName.EndsWith(".nca/00"))
|
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(_virtualFileSystem.KeySet, storage);
|
||||||
|
|
||||||
|
if (updateNcas.TryGetValue(nca.Header.TitleId, out var updateNcasItem))
|
||||||
{
|
{
|
||||||
IStorage storage = ncaStream.AsStorage();
|
updateNcasItem.Add((nca.Header.ContentType, entry.FullName));
|
||||||
|
}
|
||||||
Nca nca = new Nca(_virtualFileSystem.KeySet, storage);
|
else
|
||||||
|
{
|
||||||
if (updateNcas.TryGetValue(nca.Header.TitleId, out var updateNcasItem))
|
updateNcas.Add(nca.Header.TitleId, new List<(NcaContentType, string)>());
|
||||||
{
|
updateNcas[nca.Header.TitleId].Add((nca.Header.ContentType, entry.FullName));
|
||||||
updateNcasItem.Add((nca.Header.ContentType, entry.FullName));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
updateNcas.Add(nca.Header.TitleId, new List<(NcaContentType, string)>());
|
|
||||||
updateNcas[nca.Header.TitleId].Add((nca.Header.ContentType, entry.FullName));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -742,7 +716,7 @@ namespace Ryujinx.HLE.FileSystem
|
|||||||
|
|
||||||
using (Stream ncaStream = GetZipStream(fileEntry))
|
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);
|
IFileSystem fs = metaNca.OpenFileSystem(NcaSectionType.Data, IntegrityCheckLevel.ErrorOnInvalid);
|
||||||
|
|
||||||
@@ -772,18 +746,16 @@ namespace Ryujinx.HLE.FileSystem
|
|||||||
{
|
{
|
||||||
string versionEntry = updateNcasItem.Find(x => x.type != NcaContentType.Meta).path;
|
string versionEntry = updateNcasItem.Find(x => x.type != NcaContentType.Meta).path;
|
||||||
|
|
||||||
using (Stream ncaStream = GetZipStream(archive.GetEntry(versionEntry)))
|
using Stream ncaStream = GetZipStream(archive.GetEntry(versionEntry));
|
||||||
|
Nca nca = new(_virtualFileSystem.KeySet, ncaStream.AsStorage());
|
||||||
|
|
||||||
|
var romfs = nca.OpenFileSystem(NcaSectionType.Data, IntegrityCheckLevel.ErrorOnInvalid);
|
||||||
|
|
||||||
|
using var systemVersionFile = new UniqueRef<IFile>();
|
||||||
|
|
||||||
|
if (romfs.OpenFile(ref systemVersionFile.Ref, "/file".ToU8Span(), OpenMode.Read).IsSuccess())
|
||||||
{
|
{
|
||||||
Nca nca = new Nca(_virtualFileSystem.KeySet, ncaStream.AsStorage());
|
systemVersion = new SystemVersion(systemVersionFile.Get.AsStream());
|
||||||
|
|
||||||
var romfs = nca.OpenFileSystem(NcaSectionType.Data, IntegrityCheckLevel.ErrorOnInvalid);
|
|
||||||
|
|
||||||
using var systemVersionFile = new UniqueRef<IFile>();
|
|
||||||
|
|
||||||
if (romfs.OpenFile(ref systemVersionFile.Ref, "/file".ToU8Span(), OpenMode.Read).IsSuccess())
|
|
||||||
{
|
|
||||||
systemVersion = new SystemVersion(systemVersionFile.Get.AsStream());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -804,43 +776,39 @@ namespace Ryujinx.HLE.FileSystem
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
ZipArchiveEntry metaZipEntry = archive.GetEntry(metaPath);
|
ZipArchiveEntry metaZipEntry = archive.GetEntry(metaPath);
|
||||||
ZipArchiveEntry contentZipEntry = archive.GetEntry(contentPath);
|
ZipArchiveEntry contentZipEntry = archive.GetEntry(contentPath);
|
||||||
|
|
||||||
using (Stream metaNcaStream = GetZipStream(metaZipEntry))
|
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);
|
||||||
|
|
||||||
|
string cnmtPath = fs.EnumerateEntries("/", "*.cnmt").Single().FullPath;
|
||||||
|
|
||||||
|
using var metaFile = new UniqueRef<IFile>();
|
||||||
|
|
||||||
|
if (fs.OpenFile(ref metaFile.Ref, cnmtPath.ToU8Span(), OpenMode.Read).IsSuccess())
|
||||||
{
|
{
|
||||||
using (Stream contentNcaStream = GetZipStream(contentZipEntry))
|
var meta = new Cnmt(metaFile.Get.AsStream());
|
||||||
|
|
||||||
|
IStorage contentStorage = contentNcaStream.AsStorage();
|
||||||
|
if (contentStorage.GetSize(out long size).IsSuccess())
|
||||||
{
|
{
|
||||||
Nca metaNca = new Nca(_virtualFileSystem.KeySet, metaNcaStream.AsStorage());
|
byte[] contentData = new byte[size];
|
||||||
|
|
||||||
IFileSystem fs = metaNca.OpenFileSystem(NcaSectionType.Data, IntegrityCheckLevel.ErrorOnInvalid);
|
Span<byte> content = new(contentData);
|
||||||
|
|
||||||
string cnmtPath = fs.EnumerateEntries("/", "*.cnmt").Single().FullPath;
|
contentStorage.Read(0, content);
|
||||||
|
|
||||||
using var metaFile = new UniqueRef<IFile>();
|
Span<byte> hash = new(new byte[32]);
|
||||||
|
|
||||||
if (fs.OpenFile(ref metaFile.Ref, cnmtPath.ToU8Span(), OpenMode.Read).IsSuccess())
|
LibHac.Crypto.Sha256.GenerateSha256Hash(content, hash);
|
||||||
|
|
||||||
|
if (LibHac.Common.Utilities.ArraysEqual(hash.ToArray(), meta.ContentEntries[0].Hash))
|
||||||
{
|
{
|
||||||
var meta = new Cnmt(metaFile.Get.AsStream());
|
updateNcas.Remove(metaEntry.TitleId);
|
||||||
|
|
||||||
IStorage contentStorage = contentNcaStream.AsStorage();
|
|
||||||
if (contentStorage.GetSize(out long size).IsSuccess())
|
|
||||||
{
|
|
||||||
byte[] contentData = new byte[size];
|
|
||||||
|
|
||||||
Span<byte> content = new Span<byte>(contentData);
|
|
||||||
|
|
||||||
contentStorage.Read(0, content);
|
|
||||||
|
|
||||||
Span<byte> hash = new Span<byte>(new byte[32]);
|
|
||||||
|
|
||||||
LibHac.Crypto.Sha256.GenerateSha256Hash(content, hash);
|
|
||||||
|
|
||||||
if (LibHac.Common.Utilities.ArraysEqual(hash.ToArray(), meta.ContentEntries[0].Hash))
|
|
||||||
{
|
|
||||||
updateNcas.Remove(metaEntry.TitleId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -853,9 +821,9 @@ namespace Ryujinx.HLE.FileSystem
|
|||||||
|
|
||||||
foreach (var entry in updateNcas)
|
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();
|
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)
|
if (nca.Header.TitleId == SystemUpdateTitleId && nca.Header.ContentType == NcaContentType.Meta)
|
||||||
{
|
{
|
||||||
@@ -936,8 +904,8 @@ namespace Ryujinx.HLE.FileSystem
|
|||||||
{
|
{
|
||||||
if (updateNcas.TryGetValue(metaEntry.TitleId, out var ncaEntry))
|
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;
|
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.
|
// Nintendo in 9.0.0, removed PPC and only kept the meta nca of it.
|
||||||
// This is a perfect valid case, so we should just ignore the missing content nca and continue.
|
// This is a perfect valid case, so we should just ignore the missing content nca and continue.
|
||||||
@@ -948,10 +916,10 @@ namespace Ryujinx.HLE.FileSystem
|
|||||||
continue;
|
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();
|
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);
|
IFileSystem fs = metaNca.OpenFileSystem(NcaSectionType.Data, IntegrityCheckLevel.ErrorOnInvalid);
|
||||||
|
|
||||||
@@ -967,11 +935,11 @@ namespace Ryujinx.HLE.FileSystem
|
|||||||
{
|
{
|
||||||
byte[] contentData = new byte[size];
|
byte[] contentData = new byte[size];
|
||||||
|
|
||||||
Span<byte> content = new Span<byte>(contentData);
|
Span<byte> content = new(contentData);
|
||||||
|
|
||||||
contentStorage.Read(0, content);
|
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);
|
LibHac.Crypto.Sha256.GenerateSha256Hash(content, hash);
|
||||||
|
|
||||||
@@ -1017,24 +985,21 @@ namespace Ryujinx.HLE.FileSystem
|
|||||||
{
|
{
|
||||||
if (entry.ContentType == NcaContentType.Data)
|
if (entry.ContentType == NcaContentType.Data)
|
||||||
{
|
{
|
||||||
var path = _virtualFileSystem.SwitchPathToSystemPath(entry.ContentPath);
|
var path = VirtualFileSystem.SwitchPathToSystemPath(entry.ContentPath);
|
||||||
|
|
||||||
using (FileStream fileStream = File.OpenRead(path))
|
using FileStream fileStream = File.OpenRead(path);
|
||||||
|
Nca nca = new(_virtualFileSystem.KeySet, fileStream.AsStorage());
|
||||||
|
|
||||||
|
if (nca.Header.TitleId == SystemVersionTitleId && nca.Header.ContentType == NcaContentType.Data)
|
||||||
{
|
{
|
||||||
Nca nca = new Nca(_virtualFileSystem.KeySet, fileStream.AsStorage());
|
var romfs = nca.OpenFileSystem(NcaSectionType.Data, IntegrityCheckLevel.ErrorOnInvalid);
|
||||||
|
|
||||||
if (nca.Header.TitleId == SystemVersionTitleId && nca.Header.ContentType == NcaContentType.Data)
|
using var systemVersionFile = new UniqueRef<IFile>();
|
||||||
|
|
||||||
|
if (romfs.OpenFile(ref systemVersionFile.Ref, "/file".ToU8Span(), OpenMode.Read).IsSuccess())
|
||||||
{
|
{
|
||||||
var romfs = nca.OpenFileSystem(NcaSectionType.Data, IntegrityCheckLevel.ErrorOnInvalid);
|
return new SystemVersion(systemVersionFile.Get.AsStream());
|
||||||
|
|
||||||
using var systemVersionFile = new UniqueRef<IFile>();
|
|
||||||
|
|
||||||
if (romfs.OpenFile(ref systemVersionFile.Ref, "/file".ToU8Span(), OpenMode.Read).IsSuccess())
|
|
||||||
{
|
|
||||||
return new SystemVersion(systemVersionFile.Get.AsStream());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -2,7 +2,6 @@
|
|||||||
using LibHac.Ncm;
|
using LibHac.Ncm;
|
||||||
using Ryujinx.Common.Configuration;
|
using Ryujinx.Common.Configuration;
|
||||||
using System;
|
using System;
|
||||||
|
|
||||||
using static Ryujinx.HLE.FileSystem.VirtualFileSystem;
|
using static Ryujinx.HLE.FileSystem.VirtualFileSystem;
|
||||||
using Path = System.IO.Path;
|
using Path = System.IO.Path;
|
||||||
|
|
||||||
@@ -10,33 +9,33 @@ namespace Ryujinx.HLE.FileSystem
|
|||||||
{
|
{
|
||||||
internal static class ContentPath
|
internal static class ContentPath
|
||||||
{
|
{
|
||||||
public const string SystemContent = "@SystemContent";
|
public const string SystemContent = "@SystemContent";
|
||||||
public const string UserContent = "@UserContent";
|
public const string UserContent = "@UserContent";
|
||||||
public const string SdCardContent = "@SdCardContent";
|
public const string SdCardContent = "@SdCardContent";
|
||||||
public const string SdCard = "@Sdcard";
|
public const string SdCard = "@Sdcard";
|
||||||
public const string CalibFile = "@CalibFile";
|
public const string CalibFile = "@CalibFile";
|
||||||
public const string Safe = "@Safe";
|
public const string Safe = "@Safe";
|
||||||
public const string User = "@User";
|
public const string User = "@User";
|
||||||
public const string System = "@System";
|
public const string System = "@System";
|
||||||
public const string Host = "@Host";
|
public const string Host = "@Host";
|
||||||
public const string GamecardApp = "@GcApp";
|
public const string GamecardApp = "@GcApp";
|
||||||
public const string GamecardContents = "@GcS00000001";
|
public const string GamecardContents = "@GcS00000001";
|
||||||
public const string GamecardUpdate = "@upp";
|
public const string GamecardUpdate = "@upp";
|
||||||
public const string RegisteredUpdate = "@RegUpdate";
|
public const string RegisteredUpdate = "@RegUpdate";
|
||||||
|
|
||||||
public const string Nintendo = "Nintendo";
|
public const string Nintendo = "Nintendo";
|
||||||
public const string Contents = "Contents";
|
public const string Contents = "Contents";
|
||||||
|
|
||||||
public static string GetRealPath(VirtualFileSystem fileSystem, string switchContentPath)
|
public static string GetRealPath(string switchContentPath)
|
||||||
{
|
{
|
||||||
return switchContentPath switch
|
return switchContentPath switch
|
||||||
{
|
{
|
||||||
SystemContent => Path.Combine(AppDataManager.BaseDirPath, SystemNandPath, Contents),
|
SystemContent => Path.Combine(AppDataManager.BaseDirPath, SystemNandPath, Contents),
|
||||||
UserContent => Path.Combine(AppDataManager.BaseDirPath, UserNandPath, 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),
|
System => Path.Combine(AppDataManager.BaseDirPath, SystemNandPath),
|
||||||
User => Path.Combine(AppDataManager.BaseDirPath, UserNandPath),
|
User => Path.Combine(AppDataManager.BaseDirPath, UserNandPath),
|
||||||
_ => throw new NotSupportedException($"Content Path \"`{switchContentPath}`\" is not supported.")
|
_ => throw new NotSupportedException($"Content Path \"`{switchContentPath}`\" is not supported."),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -45,9 +44,9 @@ namespace Ryujinx.HLE.FileSystem
|
|||||||
return contentStorageId switch
|
return contentStorageId switch
|
||||||
{
|
{
|
||||||
ContentStorageId.System => SystemContent,
|
ContentStorageId.System => SystemContent,
|
||||||
ContentStorageId.User => UserContent,
|
ContentStorageId.User => UserContent,
|
||||||
ContentStorageId.SdCard => SdCardContent,
|
ContentStorageId.SdCard => SdCardContent,
|
||||||
_ => throw new NotSupportedException($"Content Storage Id \"`{contentStorageId}`\" is not supported.")
|
_ => throw new NotSupportedException($"Content Storage Id \"`{contentStorageId}`\" is not supported."),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -56,9 +55,9 @@ namespace Ryujinx.HLE.FileSystem
|
|||||||
return storageId switch
|
return storageId switch
|
||||||
{
|
{
|
||||||
StorageId.BuiltInSystem => SystemContent,
|
StorageId.BuiltInSystem => SystemContent,
|
||||||
StorageId.BuiltInUser => UserContent,
|
StorageId.BuiltInUser => UserContent,
|
||||||
StorageId.SdCard => SdCardContent,
|
StorageId.SdCard => SdCardContent,
|
||||||
_ => throw new NotSupportedException($"Storage Id \"`{storageId}`\" is not supported.")
|
_ => throw new NotSupportedException($"Storage Id \"`{storageId}`\" is not supported."),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -67,15 +66,15 @@ namespace Ryujinx.HLE.FileSystem
|
|||||||
return contentPathString.Split(':')[0] switch
|
return contentPathString.Split(':')[0] switch
|
||||||
{
|
{
|
||||||
SystemContent or
|
SystemContent or
|
||||||
System => StorageId.BuiltInSystem,
|
System => StorageId.BuiltInSystem,
|
||||||
UserContent or
|
UserContent or
|
||||||
User => StorageId.BuiltInUser,
|
User => StorageId.BuiltInUser,
|
||||||
SdCardContent => StorageId.SdCard,
|
SdCardContent => StorageId.SdCard,
|
||||||
Host => StorageId.Host,
|
Host => StorageId.Host,
|
||||||
GamecardApp or
|
GamecardApp or
|
||||||
GamecardContents or
|
GamecardContents or
|
||||||
GamecardUpdate => StorageId.GameCard,
|
GamecardUpdate => StorageId.GameCard,
|
||||||
_ => StorageId.None
|
_ => StorageId.None,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -4,16 +4,16 @@ namespace Ryujinx.HLE.FileSystem
|
|||||||
{
|
{
|
||||||
public struct LocationEntry
|
public struct LocationEntry
|
||||||
{
|
{
|
||||||
public string ContentPath { get; private set; }
|
public string ContentPath { get; private set; }
|
||||||
public int Flag { get; private set; }
|
public int Flag { get; private set; }
|
||||||
public ulong TitleId { get; private set; }
|
public ulong TitleId { get; private set; }
|
||||||
public NcaContentType ContentType { get; private set; }
|
public NcaContentType ContentType { get; private set; }
|
||||||
|
|
||||||
public LocationEntry(string contentPath, int flag, ulong titleId, NcaContentType contentType)
|
public LocationEntry(string contentPath, int flag, ulong titleId, NcaContentType contentType)
|
||||||
{
|
{
|
||||||
ContentPath = contentPath;
|
ContentPath = contentPath;
|
||||||
Flag = flag;
|
Flag = flag;
|
||||||
TitleId = titleId;
|
TitleId = titleId;
|
||||||
ContentType = contentType;
|
ContentType = contentType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -5,36 +5,34 @@ namespace Ryujinx.HLE.FileSystem
|
|||||||
{
|
{
|
||||||
public class SystemVersion
|
public class SystemVersion
|
||||||
{
|
{
|
||||||
public byte Major { get; }
|
public byte Major { get; }
|
||||||
public byte Minor { get; }
|
public byte Minor { get; }
|
||||||
public byte Micro { get; }
|
public byte Micro { get; }
|
||||||
public byte RevisionMajor { get; }
|
public byte RevisionMajor { get; }
|
||||||
public byte RevisionMinor { get; }
|
public byte RevisionMinor { get; }
|
||||||
public string PlatformString { get; }
|
public string PlatformString { get; }
|
||||||
public string Hex { get; }
|
public string Hex { get; }
|
||||||
public string VersionString { get; }
|
public string VersionString { get; }
|
||||||
public string VersionTitle { get; }
|
public string VersionTitle { get; }
|
||||||
|
|
||||||
public SystemVersion(Stream systemVersionFile)
|
public SystemVersion(Stream systemVersionFile)
|
||||||
{
|
{
|
||||||
using (BinaryReader reader = new BinaryReader(systemVersionFile))
|
using BinaryReader reader = new(systemVersionFile);
|
||||||
{
|
Major = reader.ReadByte();
|
||||||
Major = reader.ReadByte();
|
Minor = reader.ReadByte();
|
||||||
Minor = reader.ReadByte();
|
Micro = reader.ReadByte();
|
||||||
Micro = reader.ReadByte();
|
|
||||||
|
|
||||||
reader.ReadByte(); // Padding
|
reader.ReadByte(); // Padding
|
||||||
|
|
||||||
RevisionMajor = reader.ReadByte();
|
RevisionMajor = reader.ReadByte();
|
||||||
RevisionMinor = reader.ReadByte();
|
RevisionMinor = reader.ReadByte();
|
||||||
|
|
||||||
reader.ReadBytes(2); // Padding
|
reader.ReadBytes(2); // Padding
|
||||||
|
|
||||||
PlatformString = StringUtils.ReadInlinedAsciiString(reader, 0x20);
|
PlatformString = StringUtils.ReadInlinedAsciiString(reader, 0x20);
|
||||||
Hex = StringUtils.ReadInlinedAsciiString(reader, 0x40);
|
Hex = StringUtils.ReadInlinedAsciiString(reader, 0x40);
|
||||||
VersionString = StringUtils.ReadInlinedAsciiString(reader, 0x18);
|
VersionString = StringUtils.ReadInlinedAsciiString(reader, 0x18);
|
||||||
VersionTitle = StringUtils.ReadInlinedAsciiString(reader, 0x80);
|
VersionTitle = StringUtils.ReadInlinedAsciiString(reader, 0x80);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -26,14 +26,14 @@ namespace Ryujinx.HLE.FileSystem
|
|||||||
{
|
{
|
||||||
public class VirtualFileSystem : IDisposable
|
public class VirtualFileSystem : IDisposable
|
||||||
{
|
{
|
||||||
public static string SafeNandPath = Path.Combine(AppDataManager.DefaultNandDir, "safe");
|
public static readonly string SafeNandPath = Path.Combine(AppDataManager.DefaultNandDir, "safe");
|
||||||
public static string SystemNandPath = Path.Combine(AppDataManager.DefaultNandDir, "system");
|
public static readonly string SystemNandPath = Path.Combine(AppDataManager.DefaultNandDir, "system");
|
||||||
public static string UserNandPath = Path.Combine(AppDataManager.DefaultNandDir, "user");
|
public static readonly string UserNandPath = Path.Combine(AppDataManager.DefaultNandDir, "user");
|
||||||
|
|
||||||
public KeySet KeySet { get; private set; }
|
public KeySet KeySet { get; private set; }
|
||||||
public EmulatedGameCard GameCard { get; private set; }
|
public EmulatedGameCard GameCard { get; private set; }
|
||||||
public EmulatedSdCard SdCard { get; private set; }
|
public EmulatedSdCard SdCard { get; private set; }
|
||||||
public ModLoader ModLoader { get; private set; }
|
public ModLoader ModLoader { get; private set; }
|
||||||
|
|
||||||
private readonly ConcurrentDictionary<ulong, Stream> _romFsByPid;
|
private readonly ConcurrentDictionary<ulong, Stream> _romFsByPid;
|
||||||
|
|
||||||
@@ -85,15 +85,15 @@ namespace Ryujinx.HLE.FileSystem
|
|||||||
return _romFsByPid[pid];
|
return _romFsByPid[pid];
|
||||||
}
|
}
|
||||||
|
|
||||||
public string GetFullPath(string basePath, string fileName)
|
public static string GetFullPath(string basePath, string fileName)
|
||||||
{
|
{
|
||||||
if (fileName.StartsWith("//"))
|
if (fileName.StartsWith("//"))
|
||||||
{
|
{
|
||||||
fileName = fileName.Substring(2);
|
fileName = fileName[2..];
|
||||||
}
|
}
|
||||||
else if (fileName.StartsWith('/'))
|
else if (fileName.StartsWith('/'))
|
||||||
{
|
{
|
||||||
fileName = fileName.Substring(1);
|
fileName = fileName[1..];
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -110,10 +110,10 @@ namespace Ryujinx.HLE.FileSystem
|
|||||||
return fullPath;
|
return fullPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal string GetSdCardPath() => MakeFullPath(AppDataManager.DefaultSdcardDir);
|
internal static string GetSdCardPath() => MakeFullPath(AppDataManager.DefaultSdcardDir);
|
||||||
public string GetNandPath() => MakeFullPath(AppDataManager.DefaultNandDir);
|
public static string GetNandPath() => MakeFullPath(AppDataManager.DefaultNandDir);
|
||||||
|
|
||||||
public string SwitchPathToSystemPath(string switchPath)
|
public static string SwitchPathToSystemPath(string switchPath)
|
||||||
{
|
{
|
||||||
string[] parts = switchPath.Split(":");
|
string[] parts = switchPath.Split(":");
|
||||||
|
|
||||||
@@ -125,7 +125,7 @@ namespace Ryujinx.HLE.FileSystem
|
|||||||
return GetFullPath(MakeFullPath(parts[0]), parts[1]);
|
return GetFullPath(MakeFullPath(parts[0]), parts[1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
public string SystemPathToSwitchPath(string systemPath)
|
public static string SystemPathToSwitchPath(string systemPath)
|
||||||
{
|
{
|
||||||
string baseSystemPath = AppDataManager.BaseDirPath + Path.DirectorySeparatorChar;
|
string baseSystemPath = AppDataManager.BaseDirPath + Path.DirectorySeparatorChar;
|
||||||
|
|
||||||
@@ -148,7 +148,7 @@ namespace Ryujinx.HLE.FileSystem
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private string MakeFullPath(string path, bool isDirectory = true)
|
private static string MakeFullPath(string path, bool isDirectory = true)
|
||||||
{
|
{
|
||||||
// Handles Common Switch Content Paths
|
// Handles Common Switch Content Paths
|
||||||
switch (path)
|
switch (path)
|
||||||
@@ -185,7 +185,7 @@ namespace Ryujinx.HLE.FileSystem
|
|||||||
|
|
||||||
public void InitializeFsServer(LibHac.Horizon horizon, out HorizonClient fsServerClient)
|
public void InitializeFsServer(LibHac.Horizon horizon, out HorizonClient fsServerClient)
|
||||||
{
|
{
|
||||||
LocalFileSystem serverBaseFs = new LocalFileSystem(AppDataManager.BaseDirPath);
|
LocalFileSystem serverBaseFs = new(AppDataManager.BaseDirPath);
|
||||||
|
|
||||||
fsServerClient = horizon.CreatePrivilegedHorizonClient();
|
fsServerClient = horizon.CreatePrivilegedHorizonClient();
|
||||||
var fsServer = new FileSystemServer(fsServerClient);
|
var fsServer = new FileSystemServer(fsServerClient);
|
||||||
@@ -207,7 +207,7 @@ namespace Ryujinx.HLE.FileSystem
|
|||||||
DeviceOperator = fsServerObjects.DeviceOperator,
|
DeviceOperator = fsServerObjects.DeviceOperator,
|
||||||
ExternalKeySet = KeySet.ExternalKeySet,
|
ExternalKeySet = KeySet.ExternalKeySet,
|
||||||
FsCreators = fsServerObjects.FsCreators,
|
FsCreators = fsServerObjects.FsCreators,
|
||||||
RandomGenerator = randomGenerator
|
RandomGenerator = randomGenerator,
|
||||||
};
|
};
|
||||||
|
|
||||||
FileSystemServerInitializer.InitializeWithConfig(fsServerClient, fsServer, fsServerConfig);
|
FileSystemServerInitializer.InitializeWithConfig(fsServerClient, fsServer, fsServerConfig);
|
||||||
@@ -282,16 +282,28 @@ namespace Ryujinx.HLE.FileSystem
|
|||||||
public static Result FixExtraData(HorizonClient hos)
|
public static Result FixExtraData(HorizonClient hos)
|
||||||
{
|
{
|
||||||
Result rc = GetSystemSaveList(hos, out List<ulong> systemSaveIds);
|
Result rc = GetSystemSaveList(hos, out List<ulong> systemSaveIds);
|
||||||
if (rc.IsFailure()) return rc;
|
if (rc.IsFailure())
|
||||||
|
{
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
rc = FixUnindexedSystemSaves(hos, systemSaveIds);
|
rc = FixUnindexedSystemSaves(hos, systemSaveIds);
|
||||||
if (rc.IsFailure()) return rc;
|
if (rc.IsFailure())
|
||||||
|
{
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
rc = FixExtraDataInSpaceId(hos, SaveDataSpaceId.System);
|
rc = FixExtraDataInSpaceId(hos, SaveDataSpaceId.System);
|
||||||
if (rc.IsFailure()) return rc;
|
if (rc.IsFailure())
|
||||||
|
{
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
rc = FixExtraDataInSpaceId(hos, SaveDataSpaceId.User);
|
rc = FixExtraDataInSpaceId(hos, SaveDataSpaceId.User);
|
||||||
if (rc.IsFailure()) return rc;
|
if (rc.IsFailure())
|
||||||
|
{
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
return Result.Success;
|
return Result.Success;
|
||||||
}
|
}
|
||||||
@@ -303,15 +315,23 @@ namespace Ryujinx.HLE.FileSystem
|
|||||||
using var iterator = new UniqueRef<SaveDataIterator>();
|
using var iterator = new UniqueRef<SaveDataIterator>();
|
||||||
|
|
||||||
Result rc = hos.Fs.OpenSaveDataIterator(ref iterator.Ref, spaceId);
|
Result rc = hos.Fs.OpenSaveDataIterator(ref iterator.Ref, spaceId);
|
||||||
if (rc.IsFailure()) return rc;
|
if (rc.IsFailure())
|
||||||
|
{
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
rc = iterator.Get.ReadSaveDataInfo(out long count, info);
|
rc = iterator.Get.ReadSaveDataInfo(out long count, info);
|
||||||
if (rc.IsFailure()) return rc;
|
if (rc.IsFailure())
|
||||||
|
{
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
if (count == 0)
|
if (count == 0)
|
||||||
|
{
|
||||||
return Result.Success;
|
return Result.Success;
|
||||||
|
}
|
||||||
|
|
||||||
for (int i = 0; i < count; i++)
|
for (int i = 0; i < count; i++)
|
||||||
{
|
{
|
||||||
@@ -351,7 +371,9 @@ namespace Ryujinx.HLE.FileSystem
|
|||||||
private static Result CreateSaveDataDirectory(HorizonClient hos, in SaveDataInfo info)
|
private static Result CreateSaveDataDirectory(HorizonClient hos, in SaveDataInfo info)
|
||||||
{
|
{
|
||||||
if (info.SpaceId != SaveDataSpaceId.User && info.SpaceId != SaveDataSpaceId.System)
|
if (info.SpaceId != SaveDataSpaceId.User && info.SpaceId != SaveDataSpaceId.System)
|
||||||
|
{
|
||||||
return Result.Success;
|
return Result.Success;
|
||||||
|
}
|
||||||
|
|
||||||
const string MountName = "SaveDir";
|
const string MountName = "SaveDir";
|
||||||
var mountNameU8 = MountName.ToU8Span();
|
var mountNameU8 = MountName.ToU8Span();
|
||||||
@@ -360,11 +382,15 @@ namespace Ryujinx.HLE.FileSystem
|
|||||||
{
|
{
|
||||||
SaveDataSpaceId.System => BisPartitionId.System,
|
SaveDataSpaceId.System => BisPartitionId.System,
|
||||||
SaveDataSpaceId.User => BisPartitionId.User,
|
SaveDataSpaceId.User => BisPartitionId.User,
|
||||||
_ => throw new ArgumentOutOfRangeException()
|
_ => throw new ArgumentOutOfRangeException(nameof(info), info.SpaceId, null),
|
||||||
};
|
};
|
||||||
|
|
||||||
Result rc = hos.Fs.MountBis(mountNameU8, partitionId);
|
Result rc = hos.Fs.MountBis(mountNameU8, partitionId);
|
||||||
if (rc.IsFailure()) return rc;
|
if (rc.IsFailure())
|
||||||
|
{
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var path = $"{MountName}:/save/{info.SaveDataId:x16}".ToU8Span();
|
var path = $"{MountName}:/save/{info.SaveDataId:x16}".ToU8Span();
|
||||||
@@ -391,28 +417,38 @@ namespace Ryujinx.HLE.FileSystem
|
|||||||
|
|
||||||
var mountName = "system".ToU8Span();
|
var mountName = "system".ToU8Span();
|
||||||
DirectoryHandle handle = default;
|
DirectoryHandle handle = default;
|
||||||
List<ulong> localList = new List<ulong>();
|
List<ulong> localList = new();
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
Result rc = hos.Fs.MountBis(mountName, BisPartitionId.System);
|
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);
|
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)
|
while (true)
|
||||||
{
|
{
|
||||||
rc = hos.Fs.ReadDirectory(out long readCount, SpanHelpers.AsSpan(ref entry), handle);
|
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)
|
if (readCount == 0)
|
||||||
|
{
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
if (Utf8Parser.TryParse(entry.Name, out ulong saveDataId, out int bytesRead, 'x') &&
|
if (Utf8Parser.TryParse(entry.Name, out ulong saveDataId, out int bytesRead, 'x') && bytesRead == 16 && (long)saveDataId < 0)
|
||||||
bytesRead == 16 && (long)saveDataId < 0)
|
|
||||||
{
|
{
|
||||||
localList.Add(saveDataId);
|
localList.Add(saveDataId);
|
||||||
}
|
}
|
||||||
@@ -440,7 +476,7 @@ namespace Ryujinx.HLE.FileSystem
|
|||||||
// Only save data IDs added to SystemExtraDataFixInfo will be fixed.
|
// Only save data IDs added to SystemExtraDataFixInfo will be fixed.
|
||||||
private static Result FixUnindexedSystemSaves(HorizonClient hos, List<ulong> existingSaveIds)
|
private static Result FixUnindexedSystemSaves(HorizonClient hos, List<ulong> existingSaveIds)
|
||||||
{
|
{
|
||||||
foreach (var fixInfo in SystemExtraDataFixInfo)
|
foreach (var fixInfo in _systemExtraDataFixInfo)
|
||||||
{
|
{
|
||||||
if (!existingSaveIds.Contains(fixInfo.StaticSaveDataId))
|
if (!existingSaveIds.Contains(fixInfo.StaticSaveDataId))
|
||||||
{
|
{
|
||||||
@@ -472,7 +508,9 @@ namespace Ryujinx.HLE.FileSystem
|
|||||||
if (!rc.IsSuccess())
|
if (!rc.IsSuccess())
|
||||||
{
|
{
|
||||||
if (!ResultFs.TargetNotFound.Includes(rc))
|
if (!ResultFs.TargetNotFound.Includes(rc))
|
||||||
|
{
|
||||||
return rc;
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
// We'll reach this point only if the save data directory exists but it's not in the save data indexer.
|
// 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.
|
// 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,
|
OwnerId = info.OwnerId,
|
||||||
Flags = info.Flags,
|
Flags = info.Flags,
|
||||||
DataSize = info.DataSize,
|
DataSize = info.DataSize,
|
||||||
JournalSize = info.JournalSize
|
JournalSize = info.JournalSize,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Make a mask for writing the entire extra data
|
// Make a mask for writing the entire extra data
|
||||||
@@ -507,9 +545,11 @@ namespace Ryujinx.HLE.FileSystem
|
|||||||
{
|
{
|
||||||
wasFixNeeded = true;
|
wasFixNeeded = true;
|
||||||
|
|
||||||
Result rc = hos.Fs.Impl.ReadSaveDataFileSystemExtraData(out SaveDataExtraData extraData, info.SpaceId,
|
Result rc = hos.Fs.Impl.ReadSaveDataFileSystemExtraData(out SaveDataExtraData extraData, info.SpaceId, info.SaveDataId);
|
||||||
info.SaveDataId);
|
if (rc.IsFailure())
|
||||||
if (rc.IsFailure()) return rc;
|
{
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
// The extra data should have program ID or static save data ID set if it's valid.
|
// 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.
|
// 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
|
else
|
||||||
{
|
{
|
||||||
// Try to match the system save with one of the known saves
|
// 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)
|
if (extraData.Attribute.StaticSaveDataId == fixInfo.StaticSaveDataId)
|
||||||
{
|
{
|
||||||
@@ -573,7 +613,7 @@ namespace Ryujinx.HLE.FileSystem
|
|||||||
public long JournalSize;
|
public long JournalSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static readonly ExtraDataFixInfo[] SystemExtraDataFixInfo =
|
private static readonly ExtraDataFixInfo[] _systemExtraDataFixInfo =
|
||||||
{
|
{
|
||||||
new ExtraDataFixInfo()
|
new ExtraDataFixInfo()
|
||||||
{
|
{
|
||||||
@@ -581,7 +621,7 @@ namespace Ryujinx.HLE.FileSystem
|
|||||||
OwnerId = 0x010000000000001F,
|
OwnerId = 0x010000000000001F,
|
||||||
Flags = SaveDataFlags.KeepAfterResettingSystemSaveDataWithoutUserSaveData,
|
Flags = SaveDataFlags.KeepAfterResettingSystemSaveDataWithoutUserSaveData,
|
||||||
DataSize = 0x10000,
|
DataSize = 0x10000,
|
||||||
JournalSize = 0x10000
|
JournalSize = 0x10000,
|
||||||
},
|
},
|
||||||
new ExtraDataFixInfo()
|
new ExtraDataFixInfo()
|
||||||
{
|
{
|
||||||
@@ -589,12 +629,13 @@ namespace Ryujinx.HLE.FileSystem
|
|||||||
OwnerId = 0x0100000000001009,
|
OwnerId = 0x0100000000001009,
|
||||||
Flags = SaveDataFlags.None,
|
Flags = SaveDataFlags.None,
|
||||||
DataSize = 0xC000,
|
DataSize = 0xC000,
|
||||||
JournalSize = 0xC000
|
JournalSize = 0xC000,
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
|
GC.SuppressFinalize(this);
|
||||||
Dispose(true);
|
Dispose(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -163,56 +163,56 @@ namespace Ryujinx.HLE
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public Action RefreshInputConfig { internal get; set; }
|
public Action RefreshInputConfig { internal get; set; }
|
||||||
|
|
||||||
public HLEConfiguration(VirtualFileSystem virtualFileSystem,
|
public HLEConfiguration(VirtualFileSystem virtualFileSystem,
|
||||||
LibHacHorizonManager libHacHorizonManager,
|
LibHacHorizonManager libHacHorizonManager,
|
||||||
ContentManager contentManager,
|
ContentManager contentManager,
|
||||||
AccountManager accountManager,
|
AccountManager accountManager,
|
||||||
UserChannelPersistence userChannelPersistence,
|
UserChannelPersistence userChannelPersistence,
|
||||||
IRenderer gpuRenderer,
|
IRenderer gpuRenderer,
|
||||||
IHardwareDeviceDriver audioDeviceDriver,
|
IHardwareDeviceDriver audioDeviceDriver,
|
||||||
MemoryConfiguration memoryConfiguration,
|
MemoryConfiguration memoryConfiguration,
|
||||||
IHostUiHandler hostUiHandler,
|
IHostUiHandler hostUiHandler,
|
||||||
SystemLanguage systemLanguage,
|
SystemLanguage systemLanguage,
|
||||||
RegionCode region,
|
RegionCode region,
|
||||||
bool enableVsync,
|
bool enableVsync,
|
||||||
bool enableDockedMode,
|
bool enableDockedMode,
|
||||||
bool enablePtc,
|
bool enablePtc,
|
||||||
bool enableInternetAccess,
|
bool enableInternetAccess,
|
||||||
IntegrityCheckLevel fsIntegrityCheckLevel,
|
IntegrityCheckLevel fsIntegrityCheckLevel,
|
||||||
int fsGlobalAccessLogMode,
|
int fsGlobalAccessLogMode,
|
||||||
long systemTimeOffset,
|
long systemTimeOffset,
|
||||||
string timeZone,
|
string timeZone,
|
||||||
MemoryManagerMode memoryManagerMode,
|
MemoryManagerMode memoryManagerMode,
|
||||||
bool ignoreMissingServices,
|
bool ignoreMissingServices,
|
||||||
AspectRatio aspectRatio,
|
AspectRatio aspectRatio,
|
||||||
float audioVolume,
|
float audioVolume,
|
||||||
bool useHypervisor,
|
bool useHypervisor,
|
||||||
string multiplayerLanInterfaceId)
|
string multiplayerLanInterfaceId)
|
||||||
{
|
{
|
||||||
VirtualFileSystem = virtualFileSystem;
|
VirtualFileSystem = virtualFileSystem;
|
||||||
LibHacHorizonManager = libHacHorizonManager;
|
LibHacHorizonManager = libHacHorizonManager;
|
||||||
AccountManager = accountManager;
|
AccountManager = accountManager;
|
||||||
ContentManager = contentManager;
|
ContentManager = contentManager;
|
||||||
UserChannelPersistence = userChannelPersistence;
|
UserChannelPersistence = userChannelPersistence;
|
||||||
GpuRenderer = gpuRenderer;
|
GpuRenderer = gpuRenderer;
|
||||||
AudioDeviceDriver = audioDeviceDriver;
|
AudioDeviceDriver = audioDeviceDriver;
|
||||||
MemoryConfiguration = memoryConfiguration;
|
MemoryConfiguration = memoryConfiguration;
|
||||||
HostUiHandler = hostUiHandler;
|
HostUiHandler = hostUiHandler;
|
||||||
SystemLanguage = systemLanguage;
|
SystemLanguage = systemLanguage;
|
||||||
Region = region;
|
Region = region;
|
||||||
EnableVsync = enableVsync;
|
EnableVsync = enableVsync;
|
||||||
EnableDockedMode = enableDockedMode;
|
EnableDockedMode = enableDockedMode;
|
||||||
EnablePtc = enablePtc;
|
EnablePtc = enablePtc;
|
||||||
EnableInternetAccess = enableInternetAccess;
|
EnableInternetAccess = enableInternetAccess;
|
||||||
FsIntegrityCheckLevel = fsIntegrityCheckLevel;
|
FsIntegrityCheckLevel = fsIntegrityCheckLevel;
|
||||||
FsGlobalAccessLogMode = fsGlobalAccessLogMode;
|
FsGlobalAccessLogMode = fsGlobalAccessLogMode;
|
||||||
SystemTimeOffset = systemTimeOffset;
|
SystemTimeOffset = systemTimeOffset;
|
||||||
TimeZone = timeZone;
|
TimeZone = timeZone;
|
||||||
MemoryManagerMode = memoryManagerMode;
|
MemoryManagerMode = memoryManagerMode;
|
||||||
IgnoreMissingServices = ignoreMissingServices;
|
IgnoreMissingServices = ignoreMissingServices;
|
||||||
AspectRatio = aspectRatio;
|
AspectRatio = aspectRatio;
|
||||||
AudioVolume = audioVolume;
|
AudioVolume = audioVolume;
|
||||||
UseHypervisor = useHypervisor;
|
UseHypervisor = useHypervisor;
|
||||||
MultiplayerLanInterfaceId = multiplayerLanInterfaceId;
|
MultiplayerLanInterfaceId = multiplayerLanInterfaceId;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -8,7 +8,7 @@ namespace Ryujinx.HLE.HOS.Applets
|
|||||||
{
|
{
|
||||||
static class AppletManager
|
static class AppletManager
|
||||||
{
|
{
|
||||||
private static Dictionary<AppletId, Type> _appletMapping;
|
private static readonly Dictionary<AppletId, Type> _appletMapping;
|
||||||
|
|
||||||
static AppletManager()
|
static AppletManager()
|
||||||
{
|
{
|
||||||
@@ -20,7 +20,7 @@ namespace Ryujinx.HLE.HOS.Applets
|
|||||||
{ AppletId.SoftwareKeyboard, typeof(SoftwareKeyboardApplet) },
|
{ AppletId.SoftwareKeyboard, typeof(SoftwareKeyboardApplet) },
|
||||||
{ AppletId.LibAppletWeb, typeof(BrowserApplet) },
|
{ AppletId.LibAppletWeb, typeof(BrowserApplet) },
|
||||||
{ AppletId.LibAppletShop, typeof(BrowserApplet) },
|
{ AppletId.LibAppletShop, typeof(BrowserApplet) },
|
||||||
{ AppletId.LibAppletOff, typeof(BrowserApplet) }
|
{ AppletId.LibAppletOff, typeof(BrowserApplet) },
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -6,6 +6,6 @@
|
|||||||
Offline,
|
Offline,
|
||||||
Black,
|
Black,
|
||||||
Share,
|
Share,
|
||||||
Lobby
|
Lobby,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -13,13 +13,12 @@ namespace Ryujinx.HLE.HOS.Applets.Browser
|
|||||||
public event EventHandler AppletStateChanged;
|
public event EventHandler AppletStateChanged;
|
||||||
|
|
||||||
private AppletSession _normalSession;
|
private AppletSession _normalSession;
|
||||||
private AppletSession _interactiveSession;
|
|
||||||
|
|
||||||
private CommonArguments _commonArguments;
|
private CommonArguments _commonArguments;
|
||||||
private List<BrowserArgument> _arguments;
|
private List<BrowserArgument> _arguments;
|
||||||
private ShimKind _shimKind;
|
private ShimKind _shimKind;
|
||||||
|
|
||||||
public BrowserApplet(Horizon system) {}
|
public BrowserApplet(Horizon system) { }
|
||||||
|
|
||||||
public ResultCode GetResult()
|
public ResultCode GetResult()
|
||||||
{
|
{
|
||||||
@@ -29,7 +28,6 @@ namespace Ryujinx.HLE.HOS.Applets.Browser
|
|||||||
public ResultCode Start(AppletSession normalSession, AppletSession interactiveSession)
|
public ResultCode Start(AppletSession normalSession, AppletSession interactiveSession)
|
||||||
{
|
{
|
||||||
_normalSession = normalSession;
|
_normalSession = normalSession;
|
||||||
_interactiveSession = interactiveSession;
|
|
||||||
|
|
||||||
_commonArguments = IApplet.ReadStruct<CommonArguments>(_normalSession.Pop());
|
_commonArguments = IApplet.ReadStruct<CommonArguments>(_normalSession.Pop());
|
||||||
|
|
||||||
@@ -48,17 +46,18 @@ namespace Ryujinx.HLE.HOS.Applets.Browser
|
|||||||
|
|
||||||
if ((_commonArguments.AppletVersion >= 0x80000 && _shimKind == ShimKind.Web) || (_commonArguments.AppletVersion >= 0x30000 && _shimKind == ShimKind.Share))
|
if ((_commonArguments.AppletVersion >= 0x80000 && _shimKind == ShimKind.Web) || (_commonArguments.AppletVersion >= 0x30000 && _shimKind == ShimKind.Share))
|
||||||
{
|
{
|
||||||
List<BrowserOutput> result = new List<BrowserOutput>();
|
List<BrowserOutput> result = new()
|
||||||
|
{
|
||||||
result.Add(new BrowserOutput(BrowserOutputType.ExitReason, (uint)WebExitReason.ExitButton));
|
new BrowserOutput(BrowserOutputType.ExitReason, (uint)WebExitReason.ExitButton),
|
||||||
|
};
|
||||||
|
|
||||||
_normalSession.Push(BuildResponseNew(result));
|
_normalSession.Push(BuildResponseNew(result));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
WebCommonReturnValue result = new WebCommonReturnValue()
|
WebCommonReturnValue result = new()
|
||||||
{
|
{
|
||||||
ExitReason = WebExitReason.ExitButton,
|
ExitReason = WebExitReason.ExitButton,
|
||||||
};
|
};
|
||||||
|
|
||||||
_normalSession.Push(BuildResponseOld(result));
|
_normalSession.Push(BuildResponseOld(result));
|
||||||
@@ -69,36 +68,32 @@ namespace Ryujinx.HLE.HOS.Applets.Browser
|
|||||||
return ResultCode.Success;
|
return ResultCode.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
private byte[] BuildResponseOld(WebCommonReturnValue result)
|
private static byte[] BuildResponseOld(WebCommonReturnValue result)
|
||||||
{
|
{
|
||||||
using (MemoryStream stream = MemoryStreamManager.Shared.GetStream())
|
using MemoryStream stream = MemoryStreamManager.Shared.GetStream();
|
||||||
using (BinaryWriter writer = new BinaryWriter(stream))
|
using BinaryWriter writer = new(stream);
|
||||||
{
|
writer.WriteStruct(result);
|
||||||
writer.WriteStruct(result);
|
|
||||||
|
|
||||||
return stream.ToArray();
|
return stream.ToArray();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
private byte[] BuildResponseNew(List<BrowserOutput> outputArguments)
|
private byte[] BuildResponseNew(List<BrowserOutput> outputArguments)
|
||||||
{
|
{
|
||||||
using (MemoryStream stream = MemoryStreamManager.Shared.GetStream())
|
using MemoryStream stream = MemoryStreamManager.Shared.GetStream();
|
||||||
using (BinaryWriter writer = new BinaryWriter(stream))
|
using BinaryWriter writer = new(stream);
|
||||||
|
writer.WriteStruct(new WebArgHeader
|
||||||
{
|
{
|
||||||
writer.WriteStruct(new WebArgHeader
|
Count = (ushort)outputArguments.Count,
|
||||||
{
|
ShimKind = _shimKind,
|
||||||
Count = (ushort)outputArguments.Count,
|
});
|
||||||
ShimKind = _shimKind
|
|
||||||
});
|
|
||||||
|
|
||||||
foreach (BrowserOutput output in outputArguments)
|
foreach (BrowserOutput output in outputArguments)
|
||||||
{
|
{
|
||||||
output.Write(writer);
|
output.Write(writer);
|
||||||
}
|
|
||||||
|
|
||||||
writer.Write(new byte[0x2000 - writer.BaseStream.Position]);
|
|
||||||
|
|
||||||
return stream.ToArray();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
writer.Write(new byte[0x2000 - writer.BaseStream.Position]);
|
||||||
|
|
||||||
|
return stream.ToArray();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -8,16 +8,16 @@ namespace Ryujinx.HLE.HOS.Applets.Browser
|
|||||||
{
|
{
|
||||||
class BrowserArgument
|
class BrowserArgument
|
||||||
{
|
{
|
||||||
public WebArgTLVType Type { get; }
|
public WebArgTLVType Type { get; }
|
||||||
public byte[] Value { get; }
|
public byte[] Value { get; }
|
||||||
|
|
||||||
public BrowserArgument(WebArgTLVType type, byte[] value)
|
public BrowserArgument(WebArgTLVType type, byte[] value)
|
||||||
{
|
{
|
||||||
Type = type;
|
Type = type;
|
||||||
Value = value;
|
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.InitialURL, typeof(string) },
|
||||||
{ WebArgTLVType.CallbackUrl, 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)
|
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++)
|
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()));
|
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);
|
return (header.ShimKind, browserArguments);
|
||||||
|
@@ -11,25 +11,25 @@ namespace Ryujinx.HLE.HOS.Applets.Browser
|
|||||||
|
|
||||||
public BrowserOutput(BrowserOutputType type, byte[] value)
|
public BrowserOutput(BrowserOutputType type, byte[] value)
|
||||||
{
|
{
|
||||||
Type = type;
|
Type = type;
|
||||||
Value = value;
|
Value = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
public BrowserOutput(BrowserOutputType type, uint value)
|
public BrowserOutput(BrowserOutputType type, uint value)
|
||||||
{
|
{
|
||||||
Type = type;
|
Type = type;
|
||||||
Value = BitConverter.GetBytes(value);
|
Value = BitConverter.GetBytes(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public BrowserOutput(BrowserOutputType type, ulong value)
|
public BrowserOutput(BrowserOutputType type, ulong value)
|
||||||
{
|
{
|
||||||
Type = type;
|
Type = type;
|
||||||
Value = BitConverter.GetBytes(value);
|
Value = BitConverter.GetBytes(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public BrowserOutput(BrowserOutputType type, bool value)
|
public BrowserOutput(BrowserOutputType type, bool value)
|
||||||
{
|
{
|
||||||
Type = type;
|
Type = type;
|
||||||
Value = BitConverter.GetBytes(value);
|
Value = BitConverter.GetBytes(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -38,7 +38,7 @@ namespace Ryujinx.HLE.HOS.Applets.Browser
|
|||||||
writer.WriteStruct(new WebArgTLV
|
writer.WriteStruct(new WebArgTLV
|
||||||
{
|
{
|
||||||
Type = (ushort)Type,
|
Type = (ushort)Type,
|
||||||
Size = (ushort)Value.Length
|
Size = (ushort)Value.Length,
|
||||||
});
|
});
|
||||||
|
|
||||||
writer.Write(Value);
|
writer.Write(Value);
|
||||||
|
@@ -2,13 +2,13 @@
|
|||||||
{
|
{
|
||||||
enum BrowserOutputType : ushort
|
enum BrowserOutputType : ushort
|
||||||
{
|
{
|
||||||
ExitReason = 0x1,
|
ExitReason = 0x1,
|
||||||
LastUrl = 0x2,
|
LastUrl = 0x2,
|
||||||
LastUrlSize = 0x3,
|
LastUrlSize = 0x3,
|
||||||
SharePostResult = 0x4,
|
SharePostResult = 0x4,
|
||||||
PostServiceName = 0x5,
|
PostServiceName = 0x5,
|
||||||
PostServiceNameSize = 0x6,
|
PostServiceNameSize = 0x6,
|
||||||
PostId = 0x7,
|
PostId = 0x7,
|
||||||
MediaPlayerAutoClosedByCompletion = 0x8
|
MediaPlayerAutoClosedByCompletion = 0x8,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -4,6 +4,6 @@
|
|||||||
{
|
{
|
||||||
OfflineHtmlPage = 1,
|
OfflineHtmlPage = 1,
|
||||||
ApplicationLegalInformation,
|
ApplicationLegalInformation,
|
||||||
SystemDataPage
|
SystemDataPage,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -3,6 +3,6 @@
|
|||||||
enum LeftStickMode
|
enum LeftStickMode
|
||||||
{
|
{
|
||||||
Pointer = 0,
|
Pointer = 0,
|
||||||
Cursor
|
Cursor,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -8,6 +8,6 @@
|
|||||||
Share,
|
Share,
|
||||||
Web,
|
Web,
|
||||||
Wifi,
|
Wifi,
|
||||||
Lobby
|
Lobby,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -2,8 +2,8 @@
|
|||||||
{
|
{
|
||||||
public struct WebArgHeader
|
public struct WebArgHeader
|
||||||
{
|
{
|
||||||
public ushort Count;
|
public ushort Count;
|
||||||
public ushort Padding;
|
public ushort Padding;
|
||||||
public ShimKind ShimKind;
|
public ShimKind ShimKind;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -4,6 +4,6 @@
|
|||||||
{
|
{
|
||||||
public ushort Type;
|
public ushort Type;
|
||||||
public ushort Size;
|
public ushort Size;
|
||||||
public uint Padding;
|
public uint Padding;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -2,61 +2,61 @@
|
|||||||
{
|
{
|
||||||
enum WebArgTLVType : ushort
|
enum WebArgTLVType : ushort
|
||||||
{
|
{
|
||||||
InitialURL = 0x1,
|
InitialURL = 0x1,
|
||||||
CallbackUrl = 0x3,
|
CallbackUrl = 0x3,
|
||||||
CallbackableUrl = 0x4,
|
CallbackableUrl = 0x4,
|
||||||
ApplicationId = 0x5,
|
ApplicationId = 0x5,
|
||||||
DocumentPath = 0x6,
|
DocumentPath = 0x6,
|
||||||
DocumentKind = 0x7,
|
DocumentKind = 0x7,
|
||||||
SystemDataId = 0x8,
|
SystemDataId = 0x8,
|
||||||
ShareStartPage = 0x9,
|
ShareStartPage = 0x9,
|
||||||
Whitelist = 0xA,
|
Whitelist = 0xA,
|
||||||
NewsFlag = 0xB,
|
NewsFlag = 0xB,
|
||||||
UserID = 0xE,
|
UserID = 0xE,
|
||||||
AlbumEntry0 = 0xF,
|
AlbumEntry0 = 0xF,
|
||||||
ScreenShotEnabled = 0x10,
|
ScreenShotEnabled = 0x10,
|
||||||
EcClientCertEnabled = 0x11,
|
EcClientCertEnabled = 0x11,
|
||||||
PlayReportEnabled = 0x13,
|
PlayReportEnabled = 0x13,
|
||||||
UnknownFlag0x14 = 0x14,
|
UnknownFlag0x14 = 0x14,
|
||||||
UnknownFlag0x15 = 0x15,
|
UnknownFlag0x15 = 0x15,
|
||||||
BootDisplayKind = 0x17,
|
BootDisplayKind = 0x17,
|
||||||
BackgroundKind = 0x18,
|
BackgroundKind = 0x18,
|
||||||
FooterEnabled = 0x19,
|
FooterEnabled = 0x19,
|
||||||
PointerEnabled = 0x1A,
|
PointerEnabled = 0x1A,
|
||||||
LeftStickMode = 0x1B,
|
LeftStickMode = 0x1B,
|
||||||
KeyRepeatFrame1 = 0x1C,
|
KeyRepeatFrame1 = 0x1C,
|
||||||
KeyRepeatFrame2 = 0x1D,
|
KeyRepeatFrame2 = 0x1D,
|
||||||
BootAsMediaPlayerInverted = 0x1E,
|
BootAsMediaPlayerInverted = 0x1E,
|
||||||
DisplayUrlKind = 0x1F,
|
DisplayUrlKind = 0x1F,
|
||||||
BootAsMediaPlayer = 0x21,
|
BootAsMediaPlayer = 0x21,
|
||||||
ShopJumpEnabled = 0x22,
|
ShopJumpEnabled = 0x22,
|
||||||
MediaAutoPlayEnabled = 0x23,
|
MediaAutoPlayEnabled = 0x23,
|
||||||
LobbyParameter = 0x24,
|
LobbyParameter = 0x24,
|
||||||
ApplicationAlbumEntry = 0x26,
|
ApplicationAlbumEntry = 0x26,
|
||||||
JsExtensionEnabled = 0x27,
|
JsExtensionEnabled = 0x27,
|
||||||
AdditionalCommentText = 0x28,
|
AdditionalCommentText = 0x28,
|
||||||
TouchEnabledOnContents = 0x29,
|
TouchEnabledOnContents = 0x29,
|
||||||
UserAgentAdditionalString = 0x2A,
|
UserAgentAdditionalString = 0x2A,
|
||||||
AdditionalMediaData0 = 0x2B,
|
AdditionalMediaData0 = 0x2B,
|
||||||
MediaPlayerAutoCloseEnabled = 0x2C,
|
MediaPlayerAutoCloseEnabled = 0x2C,
|
||||||
PageCacheEnabled = 0x2D,
|
PageCacheEnabled = 0x2D,
|
||||||
WebAudioEnabled = 0x2E,
|
WebAudioEnabled = 0x2E,
|
||||||
FooterFixedKind = 0x32,
|
FooterFixedKind = 0x32,
|
||||||
PageFadeEnabled = 0x33,
|
PageFadeEnabled = 0x33,
|
||||||
MediaCreatorApplicationRatingAge = 0x34,
|
MediaCreatorApplicationRatingAge = 0x34,
|
||||||
BootLoadingIconEnabled = 0x35,
|
BootLoadingIconEnabled = 0x35,
|
||||||
PageScrollIndicatorEnabled = 0x36,
|
PageScrollIndicatorEnabled = 0x36,
|
||||||
MediaPlayerSpeedControlEnabled = 0x37,
|
MediaPlayerSpeedControlEnabled = 0x37,
|
||||||
AlbumEntry1 = 0x38,
|
AlbumEntry1 = 0x38,
|
||||||
AlbumEntry2 = 0x39,
|
AlbumEntry2 = 0x39,
|
||||||
AlbumEntry3 = 0x3A,
|
AlbumEntry3 = 0x3A,
|
||||||
AdditionalMediaData1 = 0x3B,
|
AdditionalMediaData1 = 0x3B,
|
||||||
AdditionalMediaData2 = 0x3C,
|
AdditionalMediaData2 = 0x3C,
|
||||||
AdditionalMediaData3 = 0x3D,
|
AdditionalMediaData3 = 0x3D,
|
||||||
BootFooterButton = 0x3E,
|
BootFooterButton = 0x3E,
|
||||||
OverrideWebAudioVolume = 0x3F,
|
OverrideWebAudioVolume = 0x3F,
|
||||||
OverrideMediaAudioVolume = 0x40,
|
OverrideMediaAudioVolume = 0x40,
|
||||||
BootMode = 0x41,
|
BootMode = 0x41,
|
||||||
MediaPlayerUiEnabled = 0x43
|
MediaPlayerUiEnabled = 0x43,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -5,8 +5,8 @@ namespace Ryujinx.HLE.HOS.Applets.Browser
|
|||||||
public struct WebCommonReturnValue
|
public struct WebCommonReturnValue
|
||||||
{
|
{
|
||||||
public WebExitReason ExitReason;
|
public WebExitReason ExitReason;
|
||||||
public uint Padding;
|
public uint Padding;
|
||||||
public ByteArray4096 LastUrl;
|
public ByteArray4096 LastUrl;
|
||||||
public ulong LastUrlSize;
|
public ulong LastUrlSize;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -6,6 +6,6 @@
|
|||||||
BackButton,
|
BackButton,
|
||||||
Requested,
|
Requested,
|
||||||
LastUrl,
|
LastUrl,
|
||||||
ErrorDialog = 7
|
ErrorDialog = 7,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -5,12 +5,12 @@ namespace Ryujinx.HLE.HOS.Applets
|
|||||||
[StructLayout(LayoutKind.Sequential, Pack = 8)]
|
[StructLayout(LayoutKind.Sequential, Pack = 8)]
|
||||||
struct CommonArguments
|
struct CommonArguments
|
||||||
{
|
{
|
||||||
public uint Version;
|
public uint Version;
|
||||||
public uint StructureSize;
|
public uint StructureSize;
|
||||||
public uint AppletVersion;
|
public uint AppletVersion;
|
||||||
public uint ThemeColor;
|
public uint ThemeColor;
|
||||||
[MarshalAs(UnmanagedType.I1)]
|
[MarshalAs(UnmanagedType.I1)]
|
||||||
public bool PlayStartupSound;
|
public bool PlayStartupSound;
|
||||||
public ulong SystemTicks;
|
public ulong SystemTicks;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -13,7 +13,7 @@ namespace Ryujinx.HLE.HOS.Applets
|
|||||||
{
|
{
|
||||||
internal class ControllerApplet : IApplet
|
internal class ControllerApplet : IApplet
|
||||||
{
|
{
|
||||||
private Horizon _system;
|
private readonly Horizon _system;
|
||||||
|
|
||||||
private AppletSession _normalSession;
|
private AppletSession _normalSession;
|
||||||
|
|
||||||
@@ -65,7 +65,7 @@ namespace Ryujinx.HLE.HOS.Applets
|
|||||||
}
|
}
|
||||||
else
|
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
|
argHeader = IApplet.ReadStruct<ControllerSupportArgHeader>(controllerSupportArg); // Read just the header
|
||||||
}
|
}
|
||||||
@@ -82,17 +82,17 @@ namespace Ryujinx.HLE.HOS.Applets
|
|||||||
playerMin = playerMax = 1;
|
playerMin = playerMax = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int configuredCount = 0;
|
int configuredCount;
|
||||||
PlayerIndex primaryIndex = PlayerIndex.Unknown;
|
PlayerIndex primaryIndex;
|
||||||
while (!_system.Device.Hid.Npads.Validate(playerMin, playerMax, (ControllerType)privateArg.NpadStyleSet, out configuredCount, out 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,
|
PlayerCountMin = playerMin,
|
||||||
PlayerCountMax = playerMax,
|
PlayerCountMax = playerMax,
|
||||||
SupportedStyles = (ControllerType)privateArg.NpadStyleSet,
|
SupportedStyles = (ControllerType)privateArg.NpadStyleSet,
|
||||||
SupportedPlayers = _system.Device.Hid.Npads.GetSupportedPlayers(),
|
SupportedPlayers = _system.Device.Hid.Npads.GetSupportedPlayers(),
|
||||||
IsDocked = _system.State.DockedMode
|
IsDocked = _system.State.DockedMode,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!_system.Device.UiHandler.DisplayMessageDialog(uiArgs))
|
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,
|
PlayerCount = (sbyte)configuredCount,
|
||||||
SelectedId = (uint)GetNpadIdTypeFromIndex(primaryIndex)
|
SelectedId = (uint)GetNpadIdTypeFromIndex(primaryIndex),
|
||||||
};
|
};
|
||||||
|
|
||||||
Logger.Stub?.PrintStub(LogClass.ServiceHid, $"ControllerApplet ReturnResult {result.PlayerCount} {result.SelectedId}");
|
Logger.Stub?.PrintStub(LogClass.ServiceHid, $"ControllerApplet ReturnResult {result.PlayerCount} {result.SelectedId}");
|
||||||
@@ -122,26 +122,24 @@ namespace Ryujinx.HLE.HOS.Applets
|
|||||||
return ResultCode.Success;
|
return ResultCode.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
private byte[] BuildResponse(ControllerSupportResultInfo result)
|
private static byte[] BuildResponse(ControllerSupportResultInfo result)
|
||||||
{
|
{
|
||||||
using (MemoryStream stream = MemoryStreamManager.Shared.GetStream())
|
using MemoryStream stream = MemoryStreamManager.Shared.GetStream();
|
||||||
using (BinaryWriter writer = new BinaryWriter(stream))
|
using BinaryWriter writer = new(stream);
|
||||||
{
|
|
||||||
writer.Write(MemoryMarshal.AsBytes(MemoryMarshal.CreateReadOnlySpan(ref result, Unsafe.SizeOf<ControllerSupportResultInfo>())));
|
|
||||||
|
|
||||||
return stream.ToArray();
|
writer.Write(MemoryMarshal.AsBytes(MemoryMarshal.CreateReadOnlySpan(ref result, Unsafe.SizeOf<ControllerSupportResultInfo>())));
|
||||||
}
|
|
||||||
|
return stream.ToArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
private byte[] BuildResponse()
|
private static byte[] BuildResponse()
|
||||||
{
|
{
|
||||||
using (MemoryStream stream = MemoryStreamManager.Shared.GetStream())
|
using MemoryStream stream = MemoryStreamManager.Shared.GetStream();
|
||||||
using (BinaryWriter writer = new BinaryWriter(stream))
|
using BinaryWriter writer = new(stream);
|
||||||
{
|
|
||||||
writer.Write((ulong)ResultCode.Success);
|
|
||||||
|
|
||||||
return stream.ToArray();
|
writer.Write((ulong)ResultCode.Success);
|
||||||
}
|
|
||||||
|
return stream.ToArray();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -2,7 +2,7 @@ using System.Runtime.InteropServices;
|
|||||||
|
|
||||||
namespace Ryujinx.HLE.HOS.Applets
|
namespace Ryujinx.HLE.HOS.Applets
|
||||||
{
|
{
|
||||||
#pragma warning disable CS0649
|
#pragma warning disable CS0649 // Field is never assigned to
|
||||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||||
struct ControllerSupportArgHeader
|
struct ControllerSupportArgHeader
|
||||||
{
|
{
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
namespace Ryujinx.HLE.HOS.Applets
|
namespace Ryujinx.HLE.HOS.Applets
|
||||||
{
|
{
|
||||||
#pragma warning disable CS0649
|
#pragma warning disable CS0649 // Field is never assigned to
|
||||||
struct ControllerSupportArgPrivate
|
struct ControllerSupportArgPrivate
|
||||||
{
|
{
|
||||||
public uint PrivateSize;
|
public uint PrivateSize;
|
||||||
|
@@ -4,7 +4,7 @@ using System.Runtime.InteropServices;
|
|||||||
|
|
||||||
namespace Ryujinx.HLE.HOS.Applets
|
namespace Ryujinx.HLE.HOS.Applets
|
||||||
{
|
{
|
||||||
#pragma warning disable CS0649
|
#pragma warning disable CS0649 // Field is never assigned to
|
||||||
// (8.0.0+ version)
|
// (8.0.0+ version)
|
||||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||||
struct ControllerSupportArgV7
|
struct ControllerSupportArgV7
|
||||||
|
@@ -4,7 +4,7 @@ using System.Runtime.InteropServices;
|
|||||||
|
|
||||||
namespace Ryujinx.HLE.HOS.Applets
|
namespace Ryujinx.HLE.HOS.Applets
|
||||||
{
|
{
|
||||||
#pragma warning disable CS0649
|
#pragma warning disable CS0649 // Field is never assigned to
|
||||||
// (1.0.0+ version)
|
// (1.0.0+ version)
|
||||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||||
struct ControllerSupportArgVPre7
|
struct ControllerSupportArgVPre7
|
||||||
|
@@ -4,6 +4,6 @@ namespace Ryujinx.HLE.HOS.Applets
|
|||||||
{
|
{
|
||||||
ShowControllerSupport = 0,
|
ShowControllerSupport = 0,
|
||||||
ShowControllerStrapGuide = 1,
|
ShowControllerStrapGuide = 1,
|
||||||
ShowControllerFirmwareUpdate = 2
|
ShowControllerFirmwareUpdate = 2,
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -3,7 +3,7 @@ using System.Runtime.InteropServices;
|
|||||||
|
|
||||||
namespace Ryujinx.HLE.HOS.Applets
|
namespace Ryujinx.HLE.HOS.Applets
|
||||||
{
|
{
|
||||||
#pragma warning disable CS0649
|
#pragma warning disable CS0649 // Field is never assigned to
|
||||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||||
struct ControllerSupportResultInfo
|
struct ControllerSupportResultInfo
|
||||||
{
|
{
|
||||||
|
@@ -6,8 +6,8 @@ namespace Ryujinx.HLE.HOS.Applets.Error
|
|||||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||||
struct ApplicationErrorArg
|
struct ApplicationErrorArg
|
||||||
{
|
{
|
||||||
public uint ErrorNumber;
|
public uint ErrorNumber;
|
||||||
public ulong LanguageCode;
|
public ulong LanguageCode;
|
||||||
public ByteArray2048 MessageText;
|
public ByteArray2048 MessageText;
|
||||||
public ByteArray2048 DetailsText;
|
public ByteArray2048 DetailsText;
|
||||||
}
|
}
|
||||||
|
@@ -22,11 +22,11 @@ namespace Ryujinx.HLE.HOS.Applets.Error
|
|||||||
{
|
{
|
||||||
private const long ErrorMessageBinaryTitleId = 0x0100000000000801;
|
private const long ErrorMessageBinaryTitleId = 0x0100000000000801;
|
||||||
|
|
||||||
private Horizon _horizon;
|
private readonly Horizon _horizon;
|
||||||
private AppletSession _normalSession;
|
private AppletSession _normalSession;
|
||||||
private CommonArguments _commonArguments;
|
private CommonArguments _commonArguments;
|
||||||
private ErrorCommonHeader _errorCommonHeader;
|
private ErrorCommonHeader _errorCommonHeader;
|
||||||
private byte[] _errorStorage;
|
private byte[] _errorStorage;
|
||||||
|
|
||||||
public event EventHandler AppletStateChanged;
|
public event EventHandler AppletStateChanged;
|
||||||
|
|
||||||
@@ -40,14 +40,14 @@ namespace Ryujinx.HLE.HOS.Applets.Error
|
|||||||
|
|
||||||
public ResultCode Start(AppletSession normalSession, AppletSession interactiveSession)
|
public ResultCode Start(AppletSession normalSession, AppletSession interactiveSession)
|
||||||
{
|
{
|
||||||
_normalSession = normalSession;
|
_normalSession = normalSession;
|
||||||
_commonArguments = IApplet.ReadStruct<CommonArguments>(_normalSession.Pop());
|
_commonArguments = IApplet.ReadStruct<CommonArguments>(_normalSession.Pop());
|
||||||
|
|
||||||
Logger.Info?.PrintMsg(LogClass.ServiceAm, $"ErrorApplet version: 0x{_commonArguments.AppletVersion:x8}");
|
Logger.Info?.PrintMsg(LogClass.ServiceAm, $"ErrorApplet version: 0x{_commonArguments.AppletVersion:x8}");
|
||||||
|
|
||||||
_errorStorage = _normalSession.Pop();
|
_errorStorage = _normalSession.Pop();
|
||||||
_errorCommonHeader = IApplet.ReadStruct<ErrorCommonHeader>(_errorStorage);
|
_errorCommonHeader = IApplet.ReadStruct<ErrorCommonHeader>(_errorStorage);
|
||||||
_errorStorage = _errorStorage.Skip(Marshal.SizeOf<ErrorCommonHeader>()).ToArray();
|
_errorStorage = _errorStorage.Skip(Marshal.SizeOf<ErrorCommonHeader>()).ToArray();
|
||||||
|
|
||||||
switch (_errorCommonHeader.Type)
|
switch (_errorCommonHeader.Type)
|
||||||
{
|
{
|
||||||
@@ -63,7 +63,8 @@ namespace Ryujinx.HLE.HOS.Applets.Error
|
|||||||
|
|
||||||
break;
|
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);
|
AppletStateChanged?.Invoke(this, null);
|
||||||
@@ -71,15 +72,16 @@ namespace Ryujinx.HLE.HOS.Applets.Error
|
|||||||
return ResultCode.Success;
|
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);
|
return ((resultCode & 0x1FF) + 2000, (resultCode >> 9) & 0x3FFF);
|
||||||
}
|
}
|
||||||
|
|
||||||
private string SystemLanguageToLanguageKey(SystemLanguage systemLanguage)
|
private static string SystemLanguageToLanguageKey(SystemLanguage systemLanguage)
|
||||||
{
|
{
|
||||||
return systemLanguage switch
|
return systemLanguage switch
|
||||||
{
|
{
|
||||||
|
#pragma warning disable IDE0055 // Disable formatting
|
||||||
SystemLanguage.Japanese => "ja",
|
SystemLanguage.Japanese => "ja",
|
||||||
SystemLanguage.AmericanEnglish => "en-US",
|
SystemLanguage.AmericanEnglish => "en-US",
|
||||||
SystemLanguage.French => "fr",
|
SystemLanguage.French => "fr",
|
||||||
@@ -98,7 +100,8 @@ namespace Ryujinx.HLE.HOS.Applets.Error
|
|||||||
SystemLanguage.SimplifiedChinese => "zh-Hans",
|
SystemLanguage.SimplifiedChinese => "zh-Hans",
|
||||||
SystemLanguage.TraditionalChinese => "zh-Hant",
|
SystemLanguage.TraditionalChinese => "zh-Hant",
|
||||||
SystemLanguage.BrazilianPortuguese => "pt-BR",
|
SystemLanguage.BrazilianPortuguese => "pt-BR",
|
||||||
_ => "en-US"
|
_ => "en-US",
|
||||||
|
#pragma warning restore IDE0055
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -111,26 +114,24 @@ namespace Ryujinx.HLE.HOS.Applets.Error
|
|||||||
{
|
{
|
||||||
string binaryTitleContentPath = _horizon.ContentManager.GetInstalledContentPath(ErrorMessageBinaryTitleId, StorageId.BuiltInSystem, NcaContentType.Data);
|
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))
|
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}";
|
||||||
|
|
||||||
|
if (romfs.FileExists(filePath))
|
||||||
{
|
{
|
||||||
Nca nca = new Nca(_horizon.Device.FileSystem.KeySet, ncaFileStream);
|
using var binaryFile = new UniqueRef<IFile>();
|
||||||
IFileSystem romfs = nca.OpenFileSystem(NcaSectionType.Data, _horizon.FsIntegrityCheckLevel);
|
|
||||||
string languageCode = SystemLanguageToLanguageKey(_horizon.State.DesiredSystemLanguage);
|
|
||||||
string filePath = $"/{module}/{description:0000}/{languageCode}_{key}";
|
|
||||||
|
|
||||||
if (romfs.FileExists(filePath))
|
romfs.OpenFile(ref binaryFile.Ref, filePath.ToU8Span(), OpenMode.Read).ThrowIfFailure();
|
||||||
{
|
StreamReader reader = new(binaryFile.Get.AsStream(), Encoding.Unicode);
|
||||||
using var binaryFile = new UniqueRef<IFile>();
|
|
||||||
|
|
||||||
romfs.OpenFile(ref binaryFile.Ref, filePath.ToU8Span(), OpenMode.Read).ThrowIfFailure();
|
return CleanText(reader.ReadToEnd());
|
||||||
StreamReader reader = new StreamReader(binaryFile.Get.AsStream(), Encoding.Unicode);
|
}
|
||||||
|
else
|
||||||
return CleanText(reader.ReadToEnd());
|
{
|
||||||
}
|
return "";
|
||||||
else
|
|
||||||
{
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -145,7 +146,7 @@ namespace Ryujinx.HLE.HOS.Applets.Error
|
|||||||
{
|
{
|
||||||
ErrorCommonArg errorCommonArg = IApplet.ReadStruct<ErrorCommonArg>(_errorStorage);
|
ErrorCommonArg errorCommonArg = IApplet.ReadStruct<ErrorCommonArg>(_errorStorage);
|
||||||
|
|
||||||
uint module = errorCommonArg.Module;
|
uint module = errorCommonArg.Module;
|
||||||
uint description = errorCommonArg.Description;
|
uint description = errorCommonArg.Description;
|
||||||
|
|
||||||
if (_errorCommonHeader.MessageFlag == 0)
|
if (_errorCommonHeader.MessageFlag == 0)
|
||||||
@@ -188,7 +189,7 @@ namespace Ryujinx.HLE.HOS.Applets.Error
|
|||||||
string messageText = Encoding.ASCII.GetString(messageTextBuffer.TakeWhile(b => !b.Equals(0)).ToArray());
|
string messageText = Encoding.ASCII.GetString(messageTextBuffer.TakeWhile(b => !b.Equals(0)).ToArray());
|
||||||
string detailsText = Encoding.ASCII.GetString(detailsTextBuffer.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".
|
// TODO: Handle the LanguageCode to return the translated "OK" and "Details".
|
||||||
|
|
||||||
|
@@ -6,12 +6,12 @@ namespace Ryujinx.HLE.HOS.Applets.Error
|
|||||||
struct ErrorCommonHeader
|
struct ErrorCommonHeader
|
||||||
{
|
{
|
||||||
public ErrorType Type;
|
public ErrorType Type;
|
||||||
public byte JumpFlag;
|
public byte JumpFlag;
|
||||||
public byte ReservedFlag1;
|
public byte ReservedFlag1;
|
||||||
public byte ReservedFlag2;
|
public byte ReservedFlag2;
|
||||||
public byte ReservedFlag3;
|
public byte ReservedFlag3;
|
||||||
public byte ContextFlag;
|
public byte ContextFlag;
|
||||||
public byte MessageFlag;
|
public byte MessageFlag;
|
||||||
public byte ContextFlag2;
|
public byte ContextFlag2;
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -8,6 +8,6 @@
|
|||||||
ErrorEulaArg,
|
ErrorEulaArg,
|
||||||
ErrorPctlArg,
|
ErrorPctlArg,
|
||||||
ErrorRecordArg,
|
ErrorRecordArg,
|
||||||
SystemUpdateEulaArg = 8
|
SystemUpdateEulaArg = 8,
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -8,10 +8,12 @@ namespace Ryujinx.HLE.HOS.Applets
|
|||||||
{
|
{
|
||||||
internal class PlayerSelectApplet : IApplet
|
internal class PlayerSelectApplet : IApplet
|
||||||
{
|
{
|
||||||
private Horizon _system;
|
private readonly Horizon _system;
|
||||||
|
|
||||||
private AppletSession _normalSession;
|
private AppletSession _normalSession;
|
||||||
|
#pragma warning disable IDE0052 // Remove unread private member
|
||||||
private AppletSession _interactiveSession;
|
private AppletSession _interactiveSession;
|
||||||
|
#pragma warning restore IDE0052
|
||||||
|
|
||||||
public event EventHandler AppletStateChanged;
|
public event EventHandler AppletStateChanged;
|
||||||
|
|
||||||
@@ -22,7 +24,7 @@ namespace Ryujinx.HLE.HOS.Applets
|
|||||||
|
|
||||||
public ResultCode Start(AppletSession normalSession, AppletSession interactiveSession)
|
public ResultCode Start(AppletSession normalSession, AppletSession interactiveSession)
|
||||||
{
|
{
|
||||||
_normalSession = normalSession;
|
_normalSession = normalSession;
|
||||||
_interactiveSession = interactiveSession;
|
_interactiveSession = interactiveSession;
|
||||||
|
|
||||||
// TODO(jduncanator): Parse PlayerSelectConfig from input data
|
// TODO(jduncanator): Parse PlayerSelectConfig from input data
|
||||||
@@ -44,15 +46,14 @@ namespace Ryujinx.HLE.HOS.Applets
|
|||||||
{
|
{
|
||||||
UserProfile currentUser = _system.AccountManager.LastOpenedUser;
|
UserProfile currentUser = _system.AccountManager.LastOpenedUser;
|
||||||
|
|
||||||
using (MemoryStream stream = MemoryStreamManager.Shared.GetStream())
|
using MemoryStream stream = MemoryStreamManager.Shared.GetStream();
|
||||||
using (BinaryWriter writer = new BinaryWriter(stream))
|
using BinaryWriter writer = new(stream);
|
||||||
{
|
|
||||||
writer.Write((ulong)PlayerSelectResult.Success);
|
|
||||||
|
|
||||||
currentUser.UserId.Write(writer);
|
writer.Write((ulong)PlayerSelectResult.Success);
|
||||||
|
|
||||||
return stream.ToArray();
|
currentUser.UserId.Write(writer);
|
||||||
}
|
|
||||||
|
return stream.ToArray();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -3,6 +3,6 @@
|
|||||||
enum PlayerSelectResult : ulong
|
enum PlayerSelectResult : ulong
|
||||||
{
|
{
|
||||||
Success = 0,
|
Success = 0,
|
||||||
Failure = 2
|
Failure = 2,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -13,6 +13,6 @@
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Position the cursor at the end of the text
|
/// Position the cursor at the end of the text
|
||||||
/// </summary>
|
/// </summary>
|
||||||
End
|
End,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -43,6 +43,6 @@
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// [8.0.0+] Request the keyboard applet to use the MovedCursorV2 response when notifying changes in cursor position.
|
/// [8.0.0+] Request the keyboard applet to use the MovedCursorV2 response when notifying changes in cursor position.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
UseMovedCursorV2 = 0xE
|
UseMovedCursorV2 = 0xE,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -88,6 +88,6 @@
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Same as MovedCursorUtf8, but with additional fields.
|
/// Same as MovedCursorUtf8, but with additional fields.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
MovedCursorUtf8V2 = 0x10
|
MovedCursorUtf8V2 = 0x10,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -28,6 +28,6 @@
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// software keyboard is transitioning to a hidden state because the user pressed either OK or Cancel.
|
/// software keyboard is transitioning to a hidden state because the user pressed either OK or Cancel.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
Disappearing = 0x4
|
Disappearing = 0x4,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -60,55 +60,51 @@ namespace Ryujinx.HLE.HOS.Applets.SoftwareKeyboard
|
|||||||
{
|
{
|
||||||
uint resSize = 2 * sizeof(uint) + 0x1;
|
uint resSize = 2 * sizeof(uint) + 0x1;
|
||||||
|
|
||||||
using (MemoryStream stream = new MemoryStream(new byte[resSize]))
|
using MemoryStream stream = new(new byte[resSize]);
|
||||||
using (BinaryWriter writer = new BinaryWriter(stream))
|
using BinaryWriter writer = new(stream);
|
||||||
{
|
|
||||||
BeginResponse(state, InlineKeyboardResponse.FinishedInitialize, writer);
|
|
||||||
writer.Write((byte)1); // Data (ignored by the program)
|
|
||||||
|
|
||||||
return stream.ToArray();
|
BeginResponse(state, InlineKeyboardResponse.FinishedInitialize, writer);
|
||||||
}
|
writer.Write((byte)1); // Data (ignored by the program)
|
||||||
|
|
||||||
|
return stream.ToArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static byte[] Default(InlineKeyboardState state)
|
public static byte[] Default(InlineKeyboardState state)
|
||||||
{
|
{
|
||||||
uint resSize = 2 * sizeof(uint);
|
uint resSize = 2 * sizeof(uint);
|
||||||
|
|
||||||
using (MemoryStream stream = new MemoryStream(new byte[resSize]))
|
using MemoryStream stream = new(new byte[resSize]);
|
||||||
using (BinaryWriter writer = new BinaryWriter(stream))
|
using BinaryWriter writer = new(stream);
|
||||||
{
|
|
||||||
BeginResponse(state, InlineKeyboardResponse.Default, writer);
|
|
||||||
|
|
||||||
return stream.ToArray();
|
BeginResponse(state, InlineKeyboardResponse.Default, writer);
|
||||||
}
|
|
||||||
|
return stream.ToArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static byte[] ChangedString(string text, uint cursor, InlineKeyboardState state)
|
public static byte[] ChangedString(string text, uint cursor, InlineKeyboardState state)
|
||||||
{
|
{
|
||||||
uint resSize = 6 * sizeof(uint) + MaxStrLenUTF16;
|
uint resSize = 6 * sizeof(uint) + MaxStrLenUTF16;
|
||||||
|
|
||||||
using (MemoryStream stream = new MemoryStream(new byte[resSize]))
|
using MemoryStream stream = new(new byte[resSize]);
|
||||||
using (BinaryWriter writer = new BinaryWriter(stream))
|
using BinaryWriter writer = new(stream);
|
||||||
{
|
|
||||||
BeginResponse(state, InlineKeyboardResponse.ChangedString, writer);
|
|
||||||
WriteStringWithCursor(text, cursor, writer, MaxStrLenUTF16, Encoding.Unicode, true);
|
|
||||||
|
|
||||||
return stream.ToArray();
|
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)
|
public static byte[] MovedCursor(string text, uint cursor, InlineKeyboardState state)
|
||||||
{
|
{
|
||||||
uint resSize = 4 * sizeof(uint) + MaxStrLenUTF16;
|
uint resSize = 4 * sizeof(uint) + MaxStrLenUTF16;
|
||||||
|
|
||||||
using (MemoryStream stream = new MemoryStream(new byte[resSize]))
|
using MemoryStream stream = new(new byte[resSize]);
|
||||||
using (BinaryWriter writer = new BinaryWriter(stream))
|
using BinaryWriter writer = new(stream);
|
||||||
{
|
|
||||||
BeginResponse(state, InlineKeyboardResponse.MovedCursor, writer);
|
|
||||||
WriteStringWithCursor(text, cursor, writer, MaxStrLenUTF16, Encoding.Unicode, false);
|
|
||||||
|
|
||||||
return stream.ToArray();
|
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)
|
public static byte[] MovedTab(string text, uint cursor, InlineKeyboardState state)
|
||||||
@@ -117,182 +113,169 @@ namespace Ryujinx.HLE.HOS.Applets.SoftwareKeyboard
|
|||||||
|
|
||||||
uint resSize = 4 * sizeof(uint) + MaxStrLenUTF16;
|
uint resSize = 4 * sizeof(uint) + MaxStrLenUTF16;
|
||||||
|
|
||||||
using (MemoryStream stream = new MemoryStream(new byte[resSize]))
|
using MemoryStream stream = new(new byte[resSize]);
|
||||||
using (BinaryWriter writer = new BinaryWriter(stream))
|
using BinaryWriter writer = new(stream);
|
||||||
{
|
|
||||||
BeginResponse(state, InlineKeyboardResponse.MovedTab, writer);
|
|
||||||
WriteStringWithCursor(text, cursor, writer, MaxStrLenUTF16, Encoding.Unicode, false);
|
|
||||||
|
|
||||||
return stream.ToArray();
|
BeginResponse(state, InlineKeyboardResponse.MovedTab, writer);
|
||||||
}
|
WriteStringWithCursor(text, cursor, writer, MaxStrLenUTF16, Encoding.Unicode, false);
|
||||||
|
|
||||||
|
return stream.ToArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static byte[] DecidedEnter(string text, InlineKeyboardState state)
|
public static byte[] DecidedEnter(string text, InlineKeyboardState state)
|
||||||
{
|
{
|
||||||
uint resSize = 3 * sizeof(uint) + MaxStrLenUTF16;
|
uint resSize = 3 * sizeof(uint) + MaxStrLenUTF16;
|
||||||
|
|
||||||
using (MemoryStream stream = new MemoryStream(new byte[resSize]))
|
using MemoryStream stream = new(new byte[resSize]);
|
||||||
using (BinaryWriter writer = new BinaryWriter(stream))
|
using BinaryWriter writer = new(stream);
|
||||||
{
|
|
||||||
BeginResponse(state, InlineKeyboardResponse.DecidedEnter, writer);
|
|
||||||
WriteString(text, writer, MaxStrLenUTF16, Encoding.Unicode);
|
|
||||||
|
|
||||||
return stream.ToArray();
|
BeginResponse(state, InlineKeyboardResponse.DecidedEnter, writer);
|
||||||
}
|
WriteString(text, writer, MaxStrLenUTF16, Encoding.Unicode);
|
||||||
|
|
||||||
|
return stream.ToArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static byte[] DecidedCancel(InlineKeyboardState state)
|
public static byte[] DecidedCancel(InlineKeyboardState state)
|
||||||
{
|
{
|
||||||
uint resSize = 2 * sizeof(uint);
|
uint resSize = 2 * sizeof(uint);
|
||||||
|
|
||||||
using (MemoryStream stream = new MemoryStream(new byte[resSize]))
|
using MemoryStream stream = new(new byte[resSize]);
|
||||||
using (BinaryWriter writer = new BinaryWriter(stream))
|
using BinaryWriter writer = new(stream);
|
||||||
{
|
|
||||||
BeginResponse(state, InlineKeyboardResponse.DecidedCancel, writer);
|
|
||||||
|
|
||||||
return stream.ToArray();
|
BeginResponse(state, InlineKeyboardResponse.DecidedCancel, writer);
|
||||||
}
|
|
||||||
|
return stream.ToArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static byte[] ChangedStringUtf8(string text, uint cursor, InlineKeyboardState state)
|
public static byte[] ChangedStringUtf8(string text, uint cursor, InlineKeyboardState state)
|
||||||
{
|
{
|
||||||
uint resSize = 6 * sizeof(uint) + MaxStrLenUTF8;
|
uint resSize = 6 * sizeof(uint) + MaxStrLenUTF8;
|
||||||
|
|
||||||
using (MemoryStream stream = new MemoryStream(new byte[resSize]))
|
using MemoryStream stream = new(new byte[resSize]);
|
||||||
using (BinaryWriter writer = new BinaryWriter(stream))
|
using BinaryWriter writer = new(stream);
|
||||||
{
|
|
||||||
BeginResponse(state, InlineKeyboardResponse.ChangedStringUtf8, writer);
|
|
||||||
WriteStringWithCursor(text, cursor, writer, MaxStrLenUTF8, Encoding.UTF8, true);
|
|
||||||
|
|
||||||
return stream.ToArray();
|
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)
|
public static byte[] MovedCursorUtf8(string text, uint cursor, InlineKeyboardState state)
|
||||||
{
|
{
|
||||||
uint resSize = 4 * sizeof(uint) + MaxStrLenUTF8;
|
uint resSize = 4 * sizeof(uint) + MaxStrLenUTF8;
|
||||||
|
|
||||||
using (MemoryStream stream = new MemoryStream(new byte[resSize]))
|
using MemoryStream stream = new(new byte[resSize]);
|
||||||
using (BinaryWriter writer = new BinaryWriter(stream))
|
using BinaryWriter writer = new(stream);
|
||||||
{
|
|
||||||
BeginResponse(state, InlineKeyboardResponse.MovedCursorUtf8, writer);
|
|
||||||
WriteStringWithCursor(text, cursor, writer, MaxStrLenUTF8, Encoding.UTF8, false);
|
|
||||||
|
|
||||||
return stream.ToArray();
|
BeginResponse(state, InlineKeyboardResponse.MovedCursorUtf8, writer);
|
||||||
}
|
WriteStringWithCursor(text, cursor, writer, MaxStrLenUTF8, Encoding.UTF8, false);
|
||||||
|
|
||||||
|
return stream.ToArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static byte[] DecidedEnterUtf8(string text, InlineKeyboardState state)
|
public static byte[] DecidedEnterUtf8(string text, InlineKeyboardState state)
|
||||||
{
|
{
|
||||||
uint resSize = 3 * sizeof(uint) + MaxStrLenUTF8;
|
uint resSize = 3 * sizeof(uint) + MaxStrLenUTF8;
|
||||||
|
|
||||||
using (MemoryStream stream = new MemoryStream(new byte[resSize]))
|
using MemoryStream stream = new(new byte[resSize]);
|
||||||
using (BinaryWriter writer = new BinaryWriter(stream))
|
using BinaryWriter writer = new(stream);
|
||||||
{
|
|
||||||
BeginResponse(state, InlineKeyboardResponse.DecidedEnterUtf8, writer);
|
|
||||||
WriteString(text, writer, MaxStrLenUTF8, Encoding.UTF8);
|
|
||||||
|
|
||||||
return stream.ToArray();
|
BeginResponse(state, InlineKeyboardResponse.DecidedEnterUtf8, writer);
|
||||||
}
|
WriteString(text, writer, MaxStrLenUTF8, Encoding.UTF8);
|
||||||
|
|
||||||
|
return stream.ToArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static byte[] UnsetCustomizeDic(InlineKeyboardState state)
|
public static byte[] UnsetCustomizeDic(InlineKeyboardState state)
|
||||||
{
|
{
|
||||||
uint resSize = 2 * sizeof(uint);
|
uint resSize = 2 * sizeof(uint);
|
||||||
|
|
||||||
using (MemoryStream stream = new MemoryStream(new byte[resSize]))
|
using MemoryStream stream = new(new byte[resSize]);
|
||||||
using (BinaryWriter writer = new BinaryWriter(stream))
|
using BinaryWriter writer = new(stream);
|
||||||
{
|
|
||||||
BeginResponse(state, InlineKeyboardResponse.UnsetCustomizeDic, writer);
|
|
||||||
|
|
||||||
return stream.ToArray();
|
BeginResponse(state, InlineKeyboardResponse.UnsetCustomizeDic, writer);
|
||||||
}
|
|
||||||
|
return stream.ToArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static byte[] ReleasedUserWordInfo(InlineKeyboardState state)
|
public static byte[] ReleasedUserWordInfo(InlineKeyboardState state)
|
||||||
{
|
{
|
||||||
uint resSize = 2 * sizeof(uint);
|
uint resSize = 2 * sizeof(uint);
|
||||||
|
|
||||||
using (MemoryStream stream = new MemoryStream(new byte[resSize]))
|
using MemoryStream stream = new(new byte[resSize]);
|
||||||
using (BinaryWriter writer = new BinaryWriter(stream))
|
using BinaryWriter writer = new(stream);
|
||||||
{
|
|
||||||
BeginResponse(state, InlineKeyboardResponse.ReleasedUserWordInfo, writer);
|
|
||||||
|
|
||||||
return stream.ToArray();
|
BeginResponse(state, InlineKeyboardResponse.ReleasedUserWordInfo, writer);
|
||||||
}
|
|
||||||
|
return stream.ToArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static byte[] UnsetCustomizedDictionaries(InlineKeyboardState state)
|
public static byte[] UnsetCustomizedDictionaries(InlineKeyboardState state)
|
||||||
{
|
{
|
||||||
uint resSize = 2 * sizeof(uint);
|
uint resSize = 2 * sizeof(uint);
|
||||||
|
|
||||||
using (MemoryStream stream = new MemoryStream(new byte[resSize]))
|
using MemoryStream stream = new(new byte[resSize]);
|
||||||
using (BinaryWriter writer = new BinaryWriter(stream))
|
using BinaryWriter writer = new(stream);
|
||||||
{
|
|
||||||
BeginResponse(state, InlineKeyboardResponse.UnsetCustomizedDictionaries, writer);
|
|
||||||
|
|
||||||
return stream.ToArray();
|
BeginResponse(state, InlineKeyboardResponse.UnsetCustomizedDictionaries, writer);
|
||||||
}
|
|
||||||
|
return stream.ToArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static byte[] ChangedStringV2(string text, uint cursor, InlineKeyboardState state)
|
public static byte[] ChangedStringV2(string text, uint cursor, InlineKeyboardState state)
|
||||||
{
|
{
|
||||||
uint resSize = 6 * sizeof(uint) + MaxStrLenUTF16 + 0x1;
|
uint resSize = 6 * sizeof(uint) + MaxStrLenUTF16 + 0x1;
|
||||||
|
|
||||||
using (MemoryStream stream = new MemoryStream(new byte[resSize]))
|
using MemoryStream stream = new(new byte[resSize]);
|
||||||
using (BinaryWriter writer = new BinaryWriter(stream))
|
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();
|
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)
|
public static byte[] MovedCursorV2(string text, uint cursor, InlineKeyboardState state)
|
||||||
{
|
{
|
||||||
uint resSize = 4 * sizeof(uint) + MaxStrLenUTF16 + 0x1;
|
uint resSize = 4 * sizeof(uint) + MaxStrLenUTF16 + 0x1;
|
||||||
|
|
||||||
using (MemoryStream stream = new MemoryStream(new byte[resSize]))
|
using MemoryStream stream = new(new byte[resSize]);
|
||||||
using (BinaryWriter writer = new BinaryWriter(stream))
|
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();
|
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)
|
public static byte[] ChangedStringUtf8V2(string text, uint cursor, InlineKeyboardState state)
|
||||||
{
|
{
|
||||||
uint resSize = 6 * sizeof(uint) + MaxStrLenUTF8 + 0x1;
|
uint resSize = 6 * sizeof(uint) + MaxStrLenUTF8 + 0x1;
|
||||||
|
|
||||||
using (MemoryStream stream = new MemoryStream(new byte[resSize]))
|
using MemoryStream stream = new(new byte[resSize]);
|
||||||
using (BinaryWriter writer = new BinaryWriter(stream))
|
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();
|
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)
|
public static byte[] MovedCursorUtf8V2(string text, uint cursor, InlineKeyboardState state)
|
||||||
{
|
{
|
||||||
uint resSize = 4 * sizeof(uint) + MaxStrLenUTF8 + 0x1;
|
uint resSize = 4 * sizeof(uint) + MaxStrLenUTF8 + 0x1;
|
||||||
|
|
||||||
using (MemoryStream stream = new MemoryStream(new byte[resSize]))
|
using MemoryStream stream = new(new byte[resSize]);
|
||||||
using (BinaryWriter writer = new BinaryWriter(stream))
|
using BinaryWriter writer = new(stream);
|
||||||
{
|
|
||||||
BeginResponse(state, InlineKeyboardResponse.MovedCursorUtf8V2, writer);
|
|
||||||
WriteStringWithCursor(text, cursor, writer, MaxStrLenUTF8, Encoding.UTF8, false);
|
|
||||||
writer.Write((byte)0); // Flag == 0
|
|
||||||
|
|
||||||
return stream.ToArray();
|
BeginResponse(state, InlineKeyboardResponse.MovedCursorUtf8V2, writer);
|
||||||
}
|
WriteStringWithCursor(text, cursor, writer, MaxStrLenUTF8, Encoding.UTF8, false);
|
||||||
|
writer.Write((byte)0); // Flag == 0
|
||||||
|
|
||||||
|
return stream.ToArray();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -13,6 +13,6 @@
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Displays the text entry area as a multi-line field.
|
/// Displays the text entry area as a multi-line field.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
MultiLine
|
MultiLine,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -8,10 +8,10 @@ namespace Ryujinx.HLE.HOS.Applets.SoftwareKeyboard
|
|||||||
[Flags]
|
[Flags]
|
||||||
enum InvalidButtonFlags : uint
|
enum InvalidButtonFlags : uint
|
||||||
{
|
{
|
||||||
None = 0,
|
None = 0,
|
||||||
AnalogStickL = 1 << 1,
|
AnalogStickL = 1 << 1,
|
||||||
AnalogStickR = 1 << 2,
|
AnalogStickR = 1 << 2,
|
||||||
ZL = 1 << 3,
|
ZL = 1 << 3,
|
||||||
ZR = 1 << 4,
|
ZR = 1 << 4,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -51,6 +51,6 @@ namespace Ryujinx.HLE.HOS.Applets.SoftwareKeyboard
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Prohibits characters outside of those allowed in Mii Nicknames.
|
/// Prohibits characters outside of those allowed in Mii Nicknames.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
Username = 1 << 8
|
Username = 1 << 8,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -8,19 +8,19 @@ namespace Ryujinx.HLE.HOS.Applets.SoftwareKeyboard
|
|||||||
[Flags]
|
[Flags]
|
||||||
enum KeyboardCalcFlags : ulong
|
enum KeyboardCalcFlags : ulong
|
||||||
{
|
{
|
||||||
Initialize = 0x1,
|
Initialize = 0x1,
|
||||||
SetVolume = 0x2,
|
SetVolume = 0x2,
|
||||||
Appear = 0x4,
|
Appear = 0x4,
|
||||||
SetInputText = 0x8,
|
SetInputText = 0x8,
|
||||||
SetCursorPos = 0x10,
|
SetCursorPos = 0x10,
|
||||||
SetUtf8Mode = 0x20,
|
SetUtf8Mode = 0x20,
|
||||||
SetKeyboardBackground = 0x100,
|
SetKeyboardBackground = 0x100,
|
||||||
SetKeyboardOptions1 = 0x200,
|
SetKeyboardOptions1 = 0x200,
|
||||||
SetKeyboardOptions2 = 0x800,
|
SetKeyboardOptions2 = 0x800,
|
||||||
EnableSeGroup = 0x2000,
|
EnableSeGroup = 0x2000,
|
||||||
DisableSeGroup = 0x4000,
|
DisableSeGroup = 0x4000,
|
||||||
SetBackspaceEnabled = 0x8000,
|
SetBackspaceEnabled = 0x8000,
|
||||||
AppearTrigger = 0x10000,
|
AppearTrigger = 0x10000,
|
||||||
MustShow = Appear | SetInputText | AppearTrigger
|
MustShow = Appear | SetInputText | AppearTrigger,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -5,8 +5,8 @@
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
enum KeyboardMiniaturizationMode : byte
|
enum KeyboardMiniaturizationMode : byte
|
||||||
{
|
{
|
||||||
None = 0,
|
None = 0,
|
||||||
Auto = 1,
|
Auto = 1,
|
||||||
Forced = 2
|
Forced = 2,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -30,10 +30,10 @@
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
Alphabet = 4,
|
Alphabet = 4,
|
||||||
|
|
||||||
SimplifiedChinese = 5,
|
SimplifiedChinese = 5,
|
||||||
TraditionalChinese = 6,
|
TraditionalChinese = 6,
|
||||||
Korean = 7,
|
Korean = 7,
|
||||||
LanguageSet2 = 8,
|
LanguageSet2 = 8,
|
||||||
LanguageSet2Latin = 9,
|
LanguageSet2Latin = 9,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -13,6 +13,6 @@
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Hide input characters.
|
/// Hide input characters.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
Enabled
|
Enabled,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user