Compare commits
65 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
70d65d3d8e | ||
|
0b58f46266 | ||
|
aa96dcb1be | ||
|
82a638230e | ||
|
d11fe26aa3 | ||
|
dcf10561b9 | ||
|
cdc8fed64f | ||
|
388446c255 | ||
|
29e192f241 | ||
|
5b3662b793 | ||
|
1329c47ea4 | ||
|
6bce46621c | ||
|
e6e5838916 | ||
|
51065d9129 | ||
|
6228331fd1 | ||
|
98e7c33630 | ||
|
5c3cfb84c0 | ||
|
55557525b1 | ||
|
7e6342e44d | ||
|
c3555cb5d6 | ||
|
815819767c | ||
|
623604c391 | ||
|
617c5700ca | ||
|
7b62f7475e | ||
|
841dd56f4c | ||
|
a16d582a10 | ||
|
9ef0be477b | ||
|
c14ce4d2a5 | ||
|
171b46ef49 | ||
|
56fe2ff535 | ||
|
b1f8f868f6 | ||
|
d773d5152e | ||
|
33ba170315 | ||
|
638be5f296 | ||
|
49b37550ca | ||
|
a42f0bbb87 | ||
|
b4bb22ba06 | ||
|
6fdf774845 | ||
|
76b53e018a | ||
|
28dd7d80af | ||
|
1e06b28b22 | ||
|
e768a54f17 | ||
|
4e2bb13080 | ||
|
ac4f2c1e70 | ||
|
e40470bbe1 | ||
|
f460ecc182 | ||
|
086564c3c8 | ||
|
b6ac45d36d | ||
|
7afae8c699 | ||
|
7835968214 | ||
|
0aceb534cb | ||
|
a0af6e4d07 | ||
|
f61b7818c3 | ||
|
a2a97e1b11 | ||
|
8b2625b0be | ||
|
651e24fed9 | ||
|
41b104d0fb | ||
|
bc44b85b0b | ||
|
01c2b8097c | ||
|
4bd2ca3f0d | ||
|
e63157cc33 | ||
|
7f2fb049f5 | ||
|
4744bde0e5 | ||
|
4a835bb2b9 | ||
|
ddc9ae2a83 |
@@ -233,6 +233,29 @@ dotnet_naming_style.IPascalCase.required_suffix =
|
|||||||
dotnet_naming_style.IPascalCase.word_separator =
|
dotnet_naming_style.IPascalCase.word_separator =
|
||||||
dotnet_naming_style.IPascalCase.capitalization = pascal_case
|
dotnet_naming_style.IPascalCase.capitalization = pascal_case
|
||||||
|
|
||||||
|
# TODO:
|
||||||
|
# .NET 8 migration (new warnings are caused by the NET 8 C# compiler and analyzer)
|
||||||
|
# The following info messages might need to be fixed in the source code instead of hiding the actual message
|
||||||
|
# Without the following lines, dotnet format would fail
|
||||||
|
# Disable "Collection initialization can be simplified"
|
||||||
|
dotnet_diagnostic.IDE0028.severity = none
|
||||||
|
dotnet_diagnostic.IDE0300.severity = none
|
||||||
|
dotnet_diagnostic.IDE0301.severity = none
|
||||||
|
dotnet_diagnostic.IDE0302.severity = none
|
||||||
|
dotnet_diagnostic.IDE0305.severity = none
|
||||||
|
# Disable "'new' expression can be simplified"
|
||||||
|
dotnet_diagnostic.IDE0090.severity = none
|
||||||
|
# Disable "Use primary constructor"
|
||||||
|
dotnet_diagnostic.IDE0290.severity = none
|
||||||
|
# Disable "Member '' does not access instance data and can be marked as static"
|
||||||
|
dotnet_diagnostic.CA1822.severity = none
|
||||||
|
# Disable "Change type of field '' from '' to '' for improved performance"
|
||||||
|
dotnet_diagnostic.CA1859.severity = none
|
||||||
|
# Disable "Prefer 'static readonly' fields over constant array arguments if the called method is called repeatedly and is not mutating the passed array"
|
||||||
|
dotnet_diagnostic.CA1861.severity = none
|
||||||
|
# Disable "Prefer using 'string.Equals(string, StringComparison)' to perform a case-insensitive comparison, but keep in mind that this might cause subtle changes in behavior, so make sure to conduct thorough testing after applying the suggestion, or if culturally sensitive comparison is not required, consider using 'StringComparison.OrdinalIgnoreCase'"
|
||||||
|
dotnet_diagnostic.CA1862.severity = none
|
||||||
|
|
||||||
[src/Ryujinx.HLE/HOS/Services/**.cs]
|
[src/Ryujinx.HLE/HOS/Services/**.cs]
|
||||||
# Disable "mark members as static" rule for services
|
# Disable "mark members as static" rule for services
|
||||||
dotnet_diagnostic.CA1822.severity = none
|
dotnet_diagnostic.CA1822.severity = none
|
||||||
|
2
.github/workflows/build.yml
vendored
2
.github/workflows/build.yml
vendored
@@ -30,7 +30,7 @@ jobs:
|
|||||||
|
|
||||||
- os: windows-latest
|
- os: windows-latest
|
||||||
OS_NAME: Windows x64
|
OS_NAME: Windows x64
|
||||||
DOTNET_RUNTIME_IDENTIFIER: win10-x64
|
DOTNET_RUNTIME_IDENTIFIER: win-x64
|
||||||
RELEASE_ZIP_OS_NAME: win_x64
|
RELEASE_ZIP_OS_NAME: win_x64
|
||||||
|
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
|
4
.github/workflows/flatpak.yml
vendored
4
.github/workflows/flatpak.yml
vendored
@@ -49,7 +49,9 @@ jobs:
|
|||||||
run: python -m pip install PyYAML lxml
|
run: python -m pip install PyYAML lxml
|
||||||
|
|
||||||
- name: Restore Nuget packages
|
- name: Restore Nuget packages
|
||||||
run: dotnet restore Ryujinx/${{ env.RYUJINX_PROJECT_FILE }}
|
# With .NET 8.0.100, Microsoft.NET.ILLink.Tasks isn't restored by default and only seems to appears when publishing.
|
||||||
|
# So we just publish to grab the dependencies
|
||||||
|
run: dotnet publish -c Release -r linux-x64 Ryujinx/${{ env.RYUJINX_PROJECT_FILE }} --self-contained
|
||||||
|
|
||||||
- name: Generate nuget_sources.json
|
- name: Generate nuget_sources.json
|
||||||
shell: python
|
shell: python
|
||||||
|
8
.github/workflows/release.yml
vendored
8
.github/workflows/release.yml
vendored
@@ -25,7 +25,7 @@ env:
|
|||||||
jobs:
|
jobs:
|
||||||
tag:
|
tag:
|
||||||
name: Create tag
|
name: Create tag
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-20.04
|
||||||
steps:
|
steps:
|
||||||
- name: Get version info
|
- name: Get version info
|
||||||
id: version_info
|
id: version_info
|
||||||
@@ -59,7 +59,7 @@ jobs:
|
|||||||
|
|
||||||
- os: windows-latest
|
- os: windows-latest
|
||||||
OS_NAME: Windows x64
|
OS_NAME: Windows x64
|
||||||
DOTNET_RUNTIME_IDENTIFIER: win10-x64
|
DOTNET_RUNTIME_IDENTIFIER: win-x64
|
||||||
RELEASE_ZIP_OS_NAME: win_x64
|
RELEASE_ZIP_OS_NAME: win_x64
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
@@ -156,11 +156,11 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
global-json-file: global.json
|
global-json-file: global.json
|
||||||
|
|
||||||
- name: Setup LLVM 14
|
- name: Setup LLVM 15
|
||||||
run: |
|
run: |
|
||||||
wget https://apt.llvm.org/llvm.sh
|
wget https://apt.llvm.org/llvm.sh
|
||||||
chmod +x llvm.sh
|
chmod +x llvm.sh
|
||||||
sudo ./llvm.sh 14
|
sudo ./llvm.sh 15
|
||||||
|
|
||||||
- name: Install rcodesign
|
- name: Install rcodesign
|
||||||
run: |
|
run: |
|
||||||
|
@@ -3,38 +3,40 @@
|
|||||||
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
|
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageVersion Include="Avalonia" Version="11.0.3" />
|
<PackageVersion Include="Avalonia" Version="11.0.5" />
|
||||||
<PackageVersion Include="Avalonia.Controls.DataGrid" Version="11.0.3" />
|
<PackageVersion Include="Avalonia.Controls.DataGrid" Version="11.0.5" />
|
||||||
<PackageVersion Include="Avalonia.Desktop" Version="11.0.3" />
|
<PackageVersion Include="Avalonia.Desktop" Version="11.0.5" />
|
||||||
<PackageVersion Include="Avalonia.Diagnostics" Version="11.0.3" />
|
<PackageVersion Include="Avalonia.Diagnostics" Version="11.0.5" />
|
||||||
<PackageVersion Include="Avalonia.Markup.Xaml.Loader" Version="11.0.3" />
|
<PackageVersion Include="Avalonia.Markup.Xaml.Loader" Version="11.0.5" />
|
||||||
<PackageVersion Include="Avalonia.Svg" Version="11.0.0" />
|
<PackageVersion Include="Avalonia.Svg" Version="11.0.0.3" />
|
||||||
<PackageVersion Include="Avalonia.Svg.Skia" Version="11.0.0" />
|
<PackageVersion Include="Avalonia.Svg.Skia" Version="11.0.0.3" />
|
||||||
<PackageVersion Include="CommandLineParser" Version="2.9.1" />
|
<PackageVersion Include="CommandLineParser" Version="2.9.1" />
|
||||||
<PackageVersion Include="Concentus" Version="1.1.7" />
|
<PackageVersion Include="Concentus" Version="1.1.7" />
|
||||||
<PackageVersion Include="DiscordRichPresence" Version="1.2.1.24" />
|
<PackageVersion Include="DiscordRichPresence" Version="1.2.1.24" />
|
||||||
<PackageVersion Include="DynamicData" Version="7.14.2" />
|
<PackageVersion Include="DynamicData" Version="7.14.2" />
|
||||||
<PackageVersion Include="FluentAvaloniaUI" Version="2.0.1" />
|
<PackageVersion Include="FluentAvaloniaUI" Version="2.0.4" />
|
||||||
<PackageVersion Include="GtkSharp.Dependencies" Version="1.1.1" />
|
<PackageVersion Include="GtkSharp.Dependencies" Version="1.1.1" />
|
||||||
<PackageVersion Include="GtkSharp.Dependencies.osx" Version="0.0.5" />
|
<PackageVersion Include="GtkSharp.Dependencies.osx" Version="0.0.5" />
|
||||||
<PackageVersion Include="jp2masa.Avalonia.Flexbox" Version="0.3.0-beta.4" />
|
<PackageVersion Include="jp2masa.Avalonia.Flexbox" Version="0.3.0-beta.4" />
|
||||||
<PackageVersion Include="LibHac" Version="0.18.0" />
|
<PackageVersion Include="LibHac" Version="0.19.0" />
|
||||||
<PackageVersion Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.4" />
|
<PackageVersion Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.4" />
|
||||||
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp" Version="4.6.0" />
|
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp" Version="4.7.0" />
|
||||||
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.7.2" />
|
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.8.0" />
|
||||||
<PackageVersion Include="Microsoft.IO.RecyclableMemoryStream" Version="2.3.2" />
|
<PackageVersion Include="Microsoft.IO.RecyclableMemoryStream" Version="2.3.2" />
|
||||||
<PackageVersion Include="MsgPack.Cli" Version="1.0.1" />
|
<PackageVersion Include="MsgPack.Cli" Version="1.0.1" />
|
||||||
|
<PackageVersion Include="NetCoreServer" Version="7.0.0" />
|
||||||
<PackageVersion Include="NUnit" Version="3.13.3" />
|
<PackageVersion Include="NUnit" Version="3.13.3" />
|
||||||
<PackageVersion Include="NUnit3TestAdapter" Version="4.1.0" />
|
<PackageVersion Include="NUnit3TestAdapter" Version="4.1.0" />
|
||||||
<PackageVersion Include="OpenTK.Core" Version="4.7.7" />
|
<PackageVersion Include="OpenTK.Core" Version="4.8.1" />
|
||||||
<PackageVersion Include="OpenTK.Graphics" Version="4.7.7" />
|
<PackageVersion Include="OpenTK.Graphics" Version="4.8.1" />
|
||||||
<PackageVersion Include="OpenTK.OpenAL" Version="4.7.7" />
|
<PackageVersion Include="OpenTK.Audio.OpenAL" Version="4.8.1" />
|
||||||
<PackageVersion Include="OpenTK.Windowing.GraphicsLibraryFramework" Version="4.7.7" />
|
<PackageVersion Include="OpenTK.Windowing.GraphicsLibraryFramework" Version="4.8.1" />
|
||||||
<PackageVersion Include="Ryujinx.Audio.OpenAL.Dependencies" Version="1.21.0.1" />
|
<PackageVersion Include="Ryujinx.Audio.OpenAL.Dependencies" Version="1.21.0.1" />
|
||||||
<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.28.1-build28" />
|
<PackageVersion Include="Ryujinx.SDL2-CS" Version="2.28.1-build28" />
|
||||||
|
<PackageVersion Include="securifybv.ShellLink" Version="0.1.0" />
|
||||||
<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" />
|
||||||
@@ -43,10 +45,10 @@
|
|||||||
<PackageVersion Include="SixLabors.ImageSharp" Version="1.0.4" />
|
<PackageVersion Include="SixLabors.ImageSharp" Version="1.0.4" />
|
||||||
<PackageVersion Include="SixLabors.ImageSharp.Drawing" Version="1.0.0-beta11" />
|
<PackageVersion Include="SixLabors.ImageSharp.Drawing" Version="1.0.0-beta11" />
|
||||||
<PackageVersion Include="SPB" Version="0.0.4-build28" />
|
<PackageVersion Include="SPB" Version="0.0.4-build28" />
|
||||||
<PackageVersion Include="System.Drawing.Common" Version="7.0.0" />
|
<PackageVersion Include="System.Drawing.Common" Version="8.0.0" />
|
||||||
<PackageVersion Include="System.IdentityModel.Tokens.Jwt" Version="6.31.0" />
|
<PackageVersion Include="System.IdentityModel.Tokens.Jwt" Version="7.0.3" />
|
||||||
<PackageVersion Include="System.IO.Hashing" Version="7.0.0" />
|
<PackageVersion Include="System.IO.Hashing" Version="8.0.0" />
|
||||||
<PackageVersion Include="System.Management" Version="7.0.2" />
|
<PackageVersion Include="System.Management" Version="8.0.0" />
|
||||||
<PackageVersion Include="UnicornEngine.Unicorn" Version="2.0.2-rc1-fb78016" />
|
<PackageVersion Include="UnicornEngine.Unicorn" Version="2.0.2-rc1-fb78016" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
||||||
|
@@ -68,7 +68,7 @@ The latest automatic build for Windows, macOS, and Linux can be found on the [Of
|
|||||||
If you wish to build the emulator yourself, follow these steps:
|
If you wish to build the emulator yourself, follow these steps:
|
||||||
|
|
||||||
### Step 1
|
### Step 1
|
||||||
Install the X64 version of [.NET 7.0 (or higher) SDK](https://dotnet.microsoft.com/download/dotnet/7.0).
|
Install the X64 version of [.NET 8.0 (or higher) SDK](https://dotnet.microsoft.com/download/dotnet/8.0).
|
||||||
|
|
||||||
### Step 2
|
### Step 2
|
||||||
Either use `git clone https://github.com/Ryujinx/Ryujinx` on the command line to clone the repository or use Code --> Download zip button to get the files.
|
Either use `git clone https://github.com/Ryujinx/Ryujinx` on the command line to clone the repository or use Code --> Download zip button to get the files.
|
||||||
@@ -141,3 +141,5 @@ See [LICENSE.txt](LICENSE.txt) and [THIRDPARTY.md](distribution/legal/THIRDPARTY
|
|||||||
|
|
||||||
- [LibHac](https://github.com/Thealexbarney/LibHac) is used for our file-system.
|
- [LibHac](https://github.com/Thealexbarney/LibHac) is used for our file-system.
|
||||||
- [AmiiboAPI](https://www.amiiboapi.com) is used in our Amiibo emulation.
|
- [AmiiboAPI](https://www.amiiboapi.com) is used in our Amiibo emulation.
|
||||||
|
- [ldn_mitm](https://github.com/spacemeowx2/ldn_mitm) is used for one of our available multiplayer modes.
|
||||||
|
- [ShellLink](https://github.com/securifybv/ShellLink) is used for Windows shortcut generation.
|
||||||
|
@@ -682,3 +682,32 @@
|
|||||||
END OF TERMS AND CONDITIONS
|
END OF TERMS AND CONDITIONS
|
||||||
```
|
```
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
|
# ShellLink (MIT)
|
||||||
|
<details>
|
||||||
|
<summary>See License</summary>
|
||||||
|
|
||||||
|
```
|
||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2017 Yorick Koster, Securify B.V.
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
|
```
|
||||||
|
</details>
|
||||||
|
@@ -3,8 +3,8 @@ Version=1.0
|
|||||||
Name=Ryujinx
|
Name=Ryujinx
|
||||||
Type=Application
|
Type=Application
|
||||||
Icon=Ryujinx
|
Icon=Ryujinx
|
||||||
Exec=env DOTNET_EnableAlternateStackCheck=1 Ryujinx %f
|
Exec=Ryujinx.sh %f
|
||||||
Comment=A Nintendo Switch Emulator
|
Comment=Plays Nintendo Switch applications
|
||||||
GenericName=Nintendo Switch Emulator
|
GenericName=Nintendo Switch Emulator
|
||||||
Terminal=false
|
Terminal=false
|
||||||
Categories=Game;Emulator;
|
Categories=Game;Emulator;
|
||||||
|
13
distribution/linux/shortcut-template.desktop
Normal file
13
distribution/linux/shortcut-template.desktop
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
[Desktop Entry]
|
||||||
|
Version=1.0
|
||||||
|
Name={0}
|
||||||
|
Type=Application
|
||||||
|
Icon={1}
|
||||||
|
Exec={2} %f
|
||||||
|
Comment=Nintendo Switch application
|
||||||
|
GenericName=Nintendo Switch Emulator
|
||||||
|
Terminal=false
|
||||||
|
Categories=Game;Emulator;
|
||||||
|
Keywords=Switch;Nintendo;Emulator;
|
||||||
|
StartupWMClass=Ryujinx
|
||||||
|
PrefersNonDefaultGPU=true
|
@@ -43,7 +43,7 @@
|
|||||||
<key>LSApplicationCategoryType</key>
|
<key>LSApplicationCategoryType</key>
|
||||||
<string>public.app-category.games</string>
|
<string>public.app-category.games</string>
|
||||||
<key>LSMinimumSystemVersion</key>
|
<key>LSMinimumSystemVersion</key>
|
||||||
<string>11.0</string>
|
<string>12.0</string>
|
||||||
<key>UTExportedTypeDeclarations</key>
|
<key>UTExportedTypeDeclarations</key>
|
||||||
<array>
|
<array>
|
||||||
<dict>
|
<dict>
|
||||||
|
35
distribution/macos/shortcut-template.plist
Normal file
35
distribution/macos/shortcut-template.plist
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>CFBundleDevelopmentRegion</key>
|
||||||
|
<string>English</string>
|
||||||
|
<key>CFBundleExecutable</key>
|
||||||
|
<string>{0}</string>
|
||||||
|
<key>CFBundleGetInfoString</key>
|
||||||
|
<string>{1}</string>
|
||||||
|
<key>CFBundleIconFile</key>
|
||||||
|
<string>{2}</string>
|
||||||
|
<key>CFBundleInfoDictionaryVersion</key>
|
||||||
|
<string>6.0</string>
|
||||||
|
<key>CFBundleVersion</key>
|
||||||
|
<string>1.0</string>
|
||||||
|
<key>NSHighResolutionCapable</key>
|
||||||
|
<true/>
|
||||||
|
<key>CSResourcesFileMapped</key>
|
||||||
|
<true/>
|
||||||
|
<key>NSHumanReadableCopyright</key>
|
||||||
|
<string>Copyright © 2018 - 2023 Ryujinx Team and Contributors.</string>
|
||||||
|
<key>LSApplicationCategoryType</key>
|
||||||
|
<string>public.app-category.games</string>
|
||||||
|
<key>LSMinimumSystemVersion</key>
|
||||||
|
<string>11.0</string>
|
||||||
|
<key>UIPrerenderedIcon</key>
|
||||||
|
<true/>
|
||||||
|
<key>LSEnvironment</key>
|
||||||
|
<dict>
|
||||||
|
<key>DOTNET_DefaultStackSize</key>
|
||||||
|
<string>200000</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"sdk": {
|
"sdk": {
|
||||||
"version": "7.0.200",
|
"version": "8.0.100",
|
||||||
"rollForward": "latestFeature"
|
"rollForward": "latestFeature"
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -1,7 +1,7 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net7.0</TargetFramework>
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
|
@@ -38,7 +38,9 @@ namespace ARMeilleure.Decoders
|
|||||||
{
|
{
|
||||||
block = new Block(blkAddress);
|
block = new Block(blkAddress);
|
||||||
|
|
||||||
if ((dMode != DecoderMode.MultipleBlocks && visited.Count >= 1) || opsCount > instructionLimit || !memory.IsMapped(blkAddress))
|
if ((dMode != DecoderMode.MultipleBlocks && visited.Count >= 1) ||
|
||||||
|
opsCount > instructionLimit ||
|
||||||
|
(visited.Count > 0 && !memory.IsMapped(blkAddress)))
|
||||||
{
|
{
|
||||||
block.Exit = true;
|
block.Exit = true;
|
||||||
block.EndAddress = blkAddress;
|
block.EndAddress = blkAddress;
|
||||||
|
@@ -1,6 +1,7 @@
|
|||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
namespace ARMeilleure.Diagnostics
|
namespace ARMeilleure.Diagnostics
|
||||||
{
|
{
|
||||||
@@ -33,7 +34,6 @@ namespace ARMeilleure.Diagnostics
|
|||||||
|
|
||||||
public static string Get(ulong address)
|
public static string Get(ulong address)
|
||||||
{
|
{
|
||||||
|
|
||||||
if (_symbols.TryGetValue(address, out string result))
|
if (_symbols.TryGetValue(address, out string result))
|
||||||
{
|
{
|
||||||
return result;
|
return result;
|
||||||
@@ -48,13 +48,15 @@ namespace ARMeilleure.Diagnostics
|
|||||||
ulong diff = address - symbol.Start;
|
ulong diff = address - symbol.Start;
|
||||||
ulong rem = diff % symbol.ElementSize;
|
ulong rem = diff % symbol.ElementSize;
|
||||||
|
|
||||||
result = symbol.Name + "_" + diff / symbol.ElementSize;
|
StringBuilder resultBuilder = new();
|
||||||
|
resultBuilder.Append($"{symbol.Name}_{diff / symbol.ElementSize}");
|
||||||
|
|
||||||
if (rem != 0)
|
if (rem != 0)
|
||||||
{
|
{
|
||||||
result += "+" + rem;
|
resultBuilder.Append($"+{rem}");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
result = resultBuilder.ToString();
|
||||||
_symbols.TryAdd(address, result);
|
_symbols.TryAdd(address, result);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
|
@@ -117,12 +117,11 @@ namespace ARMeilleure.Translation.Cache
|
|||||||
|
|
||||||
int funcOffset = (int)(pointer.ToInt64() - _jitRegion.Pointer.ToInt64());
|
int funcOffset = (int)(pointer.ToInt64() - _jitRegion.Pointer.ToInt64());
|
||||||
|
|
||||||
bool result = TryFind(funcOffset, out CacheEntry entry);
|
if (TryFind(funcOffset, out CacheEntry entry, out int entryIndex) && entry.Offset == funcOffset)
|
||||||
Debug.Assert(result);
|
{
|
||||||
|
|
||||||
_cacheAllocator.Free(funcOffset, AlignCodeSize(entry.Size));
|
_cacheAllocator.Free(funcOffset, AlignCodeSize(entry.Size));
|
||||||
|
_cacheEntries.RemoveAt(entryIndex);
|
||||||
Remove(funcOffset);
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -181,22 +180,7 @@ namespace ARMeilleure.Translation.Cache
|
|||||||
_cacheEntries.Insert(index, entry);
|
_cacheEntries.Insert(index, entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void Remove(int offset)
|
public static bool TryFind(int offset, out CacheEntry entry, out int entryIndex)
|
||||||
{
|
|
||||||
int index = _cacheEntries.BinarySearch(new CacheEntry(offset, 0, default));
|
|
||||||
|
|
||||||
if (index < 0)
|
|
||||||
{
|
|
||||||
index = ~index - 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (index >= 0)
|
|
||||||
{
|
|
||||||
_cacheEntries.RemoveAt(index);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static bool TryFind(int offset, out CacheEntry entry)
|
|
||||||
{
|
{
|
||||||
lock (_lock)
|
lock (_lock)
|
||||||
{
|
{
|
||||||
@@ -210,11 +194,13 @@ namespace ARMeilleure.Translation.Cache
|
|||||||
if (index >= 0)
|
if (index >= 0)
|
||||||
{
|
{
|
||||||
entry = _cacheEntries[index];
|
entry = _cacheEntries[index];
|
||||||
|
entryIndex = index;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
entry = default;
|
entry = default;
|
||||||
|
entryIndex = 0;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -95,7 +95,7 @@ namespace ARMeilleure.Translation.Cache
|
|||||||
{
|
{
|
||||||
int offset = (int)((long)controlPc - context.ToInt64());
|
int offset = (int)((long)controlPc - context.ToInt64());
|
||||||
|
|
||||||
if (!JitCache.TryFind(offset, out CacheEntry funcEntry))
|
if (!JitCache.TryFind(offset, out CacheEntry funcEntry, out _))
|
||||||
{
|
{
|
||||||
return null; // Not found.
|
return null; // Not found.
|
||||||
}
|
}
|
||||||
|
@@ -189,7 +189,7 @@ namespace ARMeilleure.Translation
|
|||||||
{
|
{
|
||||||
if (start.CompareTo(node.End) < 0)
|
if (start.CompareTo(node.End) < 0)
|
||||||
{
|
{
|
||||||
if (overlaps.Length >= overlapCount)
|
if (overlaps.Length <= overlapCount)
|
||||||
{
|
{
|
||||||
Array.Resize(ref overlaps, overlapCount + ArrayGrowthSize);
|
Array.Resize(ref overlaps, overlapCount + ArrayGrowthSize);
|
||||||
}
|
}
|
||||||
|
@@ -7,14 +7,14 @@ namespace ARMeilleure.Translation
|
|||||||
internal class TranslatorCache<T>
|
internal class TranslatorCache<T>
|
||||||
{
|
{
|
||||||
private readonly IntervalTree<ulong, T> _tree;
|
private readonly IntervalTree<ulong, T> _tree;
|
||||||
private readonly ReaderWriterLock _treeLock;
|
private readonly ReaderWriterLockSlim _treeLock;
|
||||||
|
|
||||||
public int Count => _tree.Count;
|
public int Count => _tree.Count;
|
||||||
|
|
||||||
public TranslatorCache()
|
public TranslatorCache()
|
||||||
{
|
{
|
||||||
_tree = new IntervalTree<ulong, T>();
|
_tree = new IntervalTree<ulong, T>();
|
||||||
_treeLock = new ReaderWriterLock();
|
_treeLock = new ReaderWriterLockSlim();
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool TryAdd(ulong address, ulong size, T value)
|
public bool TryAdd(ulong address, ulong size, T value)
|
||||||
@@ -24,70 +24,70 @@ namespace ARMeilleure.Translation
|
|||||||
|
|
||||||
public bool AddOrUpdate(ulong address, ulong size, T value, Func<ulong, T, T> updateFactoryCallback)
|
public bool AddOrUpdate(ulong address, ulong size, T value, Func<ulong, T, T> updateFactoryCallback)
|
||||||
{
|
{
|
||||||
_treeLock.AcquireWriterLock(Timeout.Infinite);
|
_treeLock.EnterWriteLock();
|
||||||
bool result = _tree.AddOrUpdate(address, address + size, value, updateFactoryCallback);
|
bool result = _tree.AddOrUpdate(address, address + size, value, updateFactoryCallback);
|
||||||
_treeLock.ReleaseWriterLock();
|
_treeLock.ExitWriteLock();
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public T GetOrAdd(ulong address, ulong size, T value)
|
public T GetOrAdd(ulong address, ulong size, T value)
|
||||||
{
|
{
|
||||||
_treeLock.AcquireWriterLock(Timeout.Infinite);
|
_treeLock.EnterWriteLock();
|
||||||
value = _tree.GetOrAdd(address, address + size, value);
|
value = _tree.GetOrAdd(address, address + size, value);
|
||||||
_treeLock.ReleaseWriterLock();
|
_treeLock.ExitWriteLock();
|
||||||
|
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool Remove(ulong address)
|
public bool Remove(ulong address)
|
||||||
{
|
{
|
||||||
_treeLock.AcquireWriterLock(Timeout.Infinite);
|
_treeLock.EnterWriteLock();
|
||||||
bool removed = _tree.Remove(address) != 0;
|
bool removed = _tree.Remove(address) != 0;
|
||||||
_treeLock.ReleaseWriterLock();
|
_treeLock.ExitWriteLock();
|
||||||
|
|
||||||
return removed;
|
return removed;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Clear()
|
public void Clear()
|
||||||
{
|
{
|
||||||
_treeLock.AcquireWriterLock(Timeout.Infinite);
|
_treeLock.EnterWriteLock();
|
||||||
_tree.Clear();
|
_tree.Clear();
|
||||||
_treeLock.ReleaseWriterLock();
|
_treeLock.ExitWriteLock();
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool ContainsKey(ulong address)
|
public bool ContainsKey(ulong address)
|
||||||
{
|
{
|
||||||
_treeLock.AcquireReaderLock(Timeout.Infinite);
|
_treeLock.EnterReadLock();
|
||||||
bool result = _tree.ContainsKey(address);
|
bool result = _tree.ContainsKey(address);
|
||||||
_treeLock.ReleaseReaderLock();
|
_treeLock.ExitReadLock();
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool TryGetValue(ulong address, out T value)
|
public bool TryGetValue(ulong address, out T value)
|
||||||
{
|
{
|
||||||
_treeLock.AcquireReaderLock(Timeout.Infinite);
|
_treeLock.EnterReadLock();
|
||||||
bool result = _tree.TryGet(address, out value);
|
bool result = _tree.TryGet(address, out value);
|
||||||
_treeLock.ReleaseReaderLock();
|
_treeLock.ExitReadLock();
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int GetOverlaps(ulong address, ulong size, ref ulong[] overlaps)
|
public int GetOverlaps(ulong address, ulong size, ref ulong[] overlaps)
|
||||||
{
|
{
|
||||||
_treeLock.AcquireReaderLock(Timeout.Infinite);
|
_treeLock.EnterReadLock();
|
||||||
int count = _tree.Get(address, address + size, ref overlaps);
|
int count = _tree.Get(address, address + size, ref overlaps);
|
||||||
_treeLock.ReleaseReaderLock();
|
_treeLock.ExitReadLock();
|
||||||
|
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<T> AsList()
|
public List<T> AsList()
|
||||||
{
|
{
|
||||||
_treeLock.AcquireReaderLock(Timeout.Infinite);
|
_treeLock.EnterReadLock();
|
||||||
List<T> list = _tree.AsList();
|
List<T> list = _tree.AsList();
|
||||||
_treeLock.ReleaseReaderLock();
|
_treeLock.ExitReadLock();
|
||||||
|
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
@@ -1,11 +1,11 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net7.0</TargetFramework>
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="OpenTK.OpenAL" />
|
<PackageReference Include="OpenTK.Audio.OpenAL" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net7.0</TargetFramework>
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
|
@@ -1,9 +1,9 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net7.0</TargetFramework>
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||||
<RuntimeIdentifiers>win10-x64;linux-x64;osx-x64</RuntimeIdentifiers>
|
<RuntimeIdentifiers>win-x64;osx-x64;linux-x64</RuntimeIdentifiers>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
@@ -15,11 +15,11 @@
|
|||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
<TargetPath>libsoundio.dll</TargetPath>
|
<TargetPath>libsoundio.dll</TargetPath>
|
||||||
</ContentWithTargetPath>
|
</ContentWithTargetPath>
|
||||||
<ContentWithTargetPath Include="Native\libsoundio\libs\libsoundio.dylib" Condition="'$(RuntimeIdentifier)' != 'linux-x64' AND '$(RuntimeIdentifier)' != 'win10-x64'">
|
<ContentWithTargetPath Include="Native\libsoundio\libs\libsoundio.dylib" Condition="'$(RuntimeIdentifier)' != 'linux-x64' AND '$(RuntimeIdentifier)' != 'win-x64'">
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
<TargetPath>libsoundio.dylib</TargetPath>
|
<TargetPath>libsoundio.dylib</TargetPath>
|
||||||
</ContentWithTargetPath>
|
</ContentWithTargetPath>
|
||||||
<ContentWithTargetPath Include="Native\libsoundio\libs\libsoundio.so" Condition="'$(RuntimeIdentifier)' != 'win10-x64' AND '$(RuntimeIdentifier)' != 'osx-x64'">
|
<ContentWithTargetPath Include="Native\libsoundio\libs\libsoundio.so" Condition="'$(RuntimeIdentifier)' != 'win-x64' AND '$(RuntimeIdentifier)' != 'osx-x64'">
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
<TargetPath>libsoundio.so</TargetPath>
|
<TargetPath>libsoundio.so</TargetPath>
|
||||||
</ContentWithTargetPath>
|
</ContentWithTargetPath>
|
||||||
|
@@ -31,9 +31,18 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
|||||||
|
|
||||||
public bool IsEffectEnabled { get; }
|
public bool IsEffectEnabled { get; }
|
||||||
|
|
||||||
public AuxiliaryBufferCommand(uint bufferOffset, byte inputBufferOffset, byte outputBufferOffset,
|
public AuxiliaryBufferCommand(
|
||||||
ref AuxiliaryBufferAddresses sendBufferInfo, bool isEnabled, uint countMax,
|
uint bufferOffset,
|
||||||
CpuAddress outputBuffer, CpuAddress inputBuffer, uint updateCount, uint writeOffset, int nodeId)
|
byte inputBufferOffset,
|
||||||
|
byte outputBufferOffset,
|
||||||
|
ref AuxiliaryBufferAddresses sendBufferInfo,
|
||||||
|
bool isEnabled,
|
||||||
|
uint countMax,
|
||||||
|
CpuAddress outputBuffer,
|
||||||
|
CpuAddress inputBuffer,
|
||||||
|
uint updateCount,
|
||||||
|
uint writeOffset,
|
||||||
|
int nodeId)
|
||||||
{
|
{
|
||||||
Enabled = true;
|
Enabled = true;
|
||||||
NodeId = nodeId;
|
NodeId = nodeId;
|
||||||
|
@@ -21,7 +21,14 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
|||||||
|
|
||||||
private BiquadFilterParameter _parameter;
|
private BiquadFilterParameter _parameter;
|
||||||
|
|
||||||
public BiquadFilterCommand(int baseIndex, ref BiquadFilterParameter filter, Memory<BiquadFilterState> biquadFilterStateMemory, int inputBufferOffset, int outputBufferOffset, bool needInitialization, int nodeId)
|
public BiquadFilterCommand(
|
||||||
|
int baseIndex,
|
||||||
|
ref BiquadFilterParameter filter,
|
||||||
|
Memory<BiquadFilterState> biquadFilterStateMemory,
|
||||||
|
int inputBufferOffset,
|
||||||
|
int outputBufferOffset,
|
||||||
|
bool needInitialization,
|
||||||
|
int nodeId)
|
||||||
{
|
{
|
||||||
_parameter = filter;
|
_parameter = filter;
|
||||||
BiquadFilterState = biquadFilterStateMemory;
|
BiquadFilterState = biquadFilterStateMemory;
|
||||||
|
@@ -77,7 +77,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
|||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public unsafe void ClearBuffer(int index)
|
public unsafe void ClearBuffer(int index)
|
||||||
{
|
{
|
||||||
Unsafe.InitBlock((void*)GetBufferPointer(index), 0, SampleCount);
|
Unsafe.InitBlock((void*)GetBufferPointer(index), 0, SampleCount * sizeof(float));
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
@@ -89,7 +89,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
|||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public unsafe void CopyBuffer(int outputBufferIndex, int inputBufferIndex)
|
public unsafe void CopyBuffer(int outputBufferIndex, int inputBufferIndex)
|
||||||
{
|
{
|
||||||
Unsafe.CopyBlock((void*)GetBufferPointer(outputBufferIndex), (void*)GetBufferPointer(inputBufferIndex), SampleCount);
|
Unsafe.CopyBlock((void*)GetBufferPointer(outputBufferIndex), (void*)GetBufferPointer(inputBufferIndex), SampleCount * sizeof(float));
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
@@ -94,18 +94,18 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
|||||||
|
|
||||||
float newMean = inputMovingAverage.Update(FloatingPointHelper.MeanSquare(channelInput), _parameter.InputGain);
|
float newMean = inputMovingAverage.Update(FloatingPointHelper.MeanSquare(channelInput), _parameter.InputGain);
|
||||||
float y = FloatingPointHelper.Log10(newMean) * 10.0f;
|
float y = FloatingPointHelper.Log10(newMean) * 10.0f;
|
||||||
float z = 0.0f;
|
float z = 1.0f;
|
||||||
|
|
||||||
bool unknown10OutOfRange = false;
|
bool unknown10OutOfRange = y >= state.Unknown10;
|
||||||
|
|
||||||
if (newMean < 1.0e-10f)
|
if (newMean < 1.0e-10f)
|
||||||
{
|
{
|
||||||
z = 1.0f;
|
y = -100.0f;
|
||||||
|
|
||||||
unknown10OutOfRange = state.Unknown10 < -100.0f;
|
unknown10OutOfRange = state.Unknown10 <= -100.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (y >= state.Unknown10 || unknown10OutOfRange)
|
if (unknown10OutOfRange)
|
||||||
{
|
{
|
||||||
float tmpGain;
|
float tmpGain;
|
||||||
|
|
||||||
@@ -118,7 +118,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
|||||||
tmpGain = (y - state.Unknown10) * ((y - state.Unknown10) * -state.CompressorGainReduction);
|
tmpGain = (y - state.Unknown10) * ((y - state.Unknown10) * -state.CompressorGainReduction);
|
||||||
}
|
}
|
||||||
|
|
||||||
z = FloatingPointHelper.DecibelToLinearExtended(tmpGain);
|
z = FloatingPointHelper.DecibelToLinear(tmpGain);
|
||||||
}
|
}
|
||||||
|
|
||||||
float unknown4New = z;
|
float unknown4New = z;
|
||||||
|
@@ -28,7 +28,14 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
|||||||
|
|
||||||
private LimiterParameter _parameter;
|
private LimiterParameter _parameter;
|
||||||
|
|
||||||
public LimiterCommandVersion2(uint bufferOffset, LimiterParameter parameter, Memory<LimiterState> state, Memory<EffectResultState> resultState, bool isEnabled, ulong workBuffer, int nodeId)
|
public LimiterCommandVersion2(
|
||||||
|
uint bufferOffset,
|
||||||
|
LimiterParameter parameter,
|
||||||
|
Memory<LimiterState> state,
|
||||||
|
Memory<EffectResultState> resultState,
|
||||||
|
bool isEnabled,
|
||||||
|
ulong workBuffer,
|
||||||
|
int nodeId)
|
||||||
{
|
{
|
||||||
Enabled = true;
|
Enabled = true;
|
||||||
NodeId = nodeId;
|
NodeId = nodeId;
|
||||||
|
@@ -79,7 +79,8 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
|||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
private void ProcessReverbMono(ref ReverbState state, ReadOnlySpan<IntPtr> outputBuffers, ReadOnlySpan<IntPtr> inputBuffers, uint sampleCount)
|
private void ProcessReverbMono(ref ReverbState state, ReadOnlySpan<IntPtr> outputBuffers, ReadOnlySpan<IntPtr> inputBuffers, uint sampleCount)
|
||||||
{
|
{
|
||||||
ProcessReverbGeneric(ref state,
|
ProcessReverbGeneric(
|
||||||
|
ref state,
|
||||||
outputBuffers,
|
outputBuffers,
|
||||||
inputBuffers,
|
inputBuffers,
|
||||||
sampleCount,
|
sampleCount,
|
||||||
@@ -92,7 +93,8 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
|||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
private void ProcessReverbStereo(ref ReverbState state, ReadOnlySpan<IntPtr> outputBuffers, ReadOnlySpan<IntPtr> inputBuffers, uint sampleCount)
|
private void ProcessReverbStereo(ref ReverbState state, ReadOnlySpan<IntPtr> outputBuffers, ReadOnlySpan<IntPtr> inputBuffers, uint sampleCount)
|
||||||
{
|
{
|
||||||
ProcessReverbGeneric(ref state,
|
ProcessReverbGeneric(
|
||||||
|
ref state,
|
||||||
outputBuffers,
|
outputBuffers,
|
||||||
inputBuffers,
|
inputBuffers,
|
||||||
sampleCount,
|
sampleCount,
|
||||||
@@ -105,7 +107,8 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
|||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
private void ProcessReverbQuadraphonic(ref ReverbState state, ReadOnlySpan<IntPtr> outputBuffers, ReadOnlySpan<IntPtr> inputBuffers, uint sampleCount)
|
private void ProcessReverbQuadraphonic(ref ReverbState state, ReadOnlySpan<IntPtr> outputBuffers, ReadOnlySpan<IntPtr> inputBuffers, uint sampleCount)
|
||||||
{
|
{
|
||||||
ProcessReverbGeneric(ref state,
|
ProcessReverbGeneric(
|
||||||
|
ref state,
|
||||||
outputBuffers,
|
outputBuffers,
|
||||||
inputBuffers,
|
inputBuffers,
|
||||||
sampleCount,
|
sampleCount,
|
||||||
@@ -118,7 +121,8 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
|||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
private void ProcessReverbSurround(ref ReverbState state, ReadOnlySpan<IntPtr> outputBuffers, ReadOnlySpan<IntPtr> inputBuffers, uint sampleCount)
|
private void ProcessReverbSurround(ref ReverbState state, ReadOnlySpan<IntPtr> outputBuffers, ReadOnlySpan<IntPtr> inputBuffers, uint sampleCount)
|
||||||
{
|
{
|
||||||
ProcessReverbGeneric(ref state,
|
ProcessReverbGeneric(
|
||||||
|
ref state,
|
||||||
outputBuffers,
|
outputBuffers,
|
||||||
inputBuffers,
|
inputBuffers,
|
||||||
sampleCount,
|
sampleCount,
|
||||||
|
@@ -52,7 +52,7 @@ namespace Ryujinx.Audio.Renderer.Dsp
|
|||||||
{
|
{
|
||||||
// NOTE: Nintendo uses an approximation of log10, we don't.
|
// NOTE: Nintendo uses an approximation of log10, we don't.
|
||||||
// As such, we support the same ranges as Nintendo to avoid unexpected behaviours.
|
// As such, we support the same ranges as Nintendo to avoid unexpected behaviours.
|
||||||
return MathF.Pow(10, MathF.Max(x, 1.0e-10f));
|
return MathF.Log10(MathF.Max(x, 1.0e-10f));
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
@@ -62,7 +62,8 @@ namespace Ryujinx.Audio.Renderer.Dsp
|
|||||||
|
|
||||||
foreach (float input in inputs)
|
foreach (float input in inputs)
|
||||||
{
|
{
|
||||||
res += (input * input);
|
float normInput = input * (1f / 32768f);
|
||||||
|
res += normInput * normInput;
|
||||||
}
|
}
|
||||||
|
|
||||||
res /= inputs.Length;
|
res /= inputs.Length;
|
||||||
@@ -81,19 +82,6 @@ namespace Ryujinx.Audio.Renderer.Dsp
|
|||||||
return MathF.Pow(10.0f, db / 20.0f);
|
return MathF.Pow(10.0f, db / 20.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Map decibel to linear in [0, 2] range.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="db">The decibel value to convert</param>
|
|
||||||
/// <returns>Converted linear value in [0, 2] range</returns>
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public static float DecibelToLinearExtended(float db)
|
|
||||||
{
|
|
||||||
float tmp = MathF.Log2(DecibelToLinear(db));
|
|
||||||
|
|
||||||
return MathF.Truncate(tmp) + MathF.Pow(2.0f, tmp - MathF.Truncate(tmp));
|
|
||||||
}
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static float DegreesToRadians(float degrees)
|
public static float DegreesToRadians(float degrees)
|
||||||
{
|
{
|
||||||
|
@@ -3,7 +3,7 @@ using Ryujinx.Audio.Renderer.Parameter.Effect;
|
|||||||
|
|
||||||
namespace Ryujinx.Audio.Renderer.Dsp.State
|
namespace Ryujinx.Audio.Renderer.Dsp.State
|
||||||
{
|
{
|
||||||
public class CompressorState
|
public struct CompressorState
|
||||||
{
|
{
|
||||||
public ExponentialMovingAverage InputMovingAverage;
|
public ExponentialMovingAverage InputMovingAverage;
|
||||||
public float Unknown4;
|
public float Unknown4;
|
||||||
@@ -45,7 +45,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.State
|
|||||||
CompressorGainReduction = (1.0f - ratio) / Constants.ChannelCountMax;
|
CompressorGainReduction = (1.0f - ratio) / Constants.ChannelCountMax;
|
||||||
Unknown10 = threshold - 1.5f;
|
Unknown10 = threshold - 1.5f;
|
||||||
Unknown14 = threshold + 1.5f;
|
Unknown14 = threshold + 1.5f;
|
||||||
OutputGain = FloatingPointHelper.DecibelToLinearExtended(parameter.OutputGain + makeupGain);
|
OutputGain = FloatingPointHelper.DecibelToLinear(parameter.OutputGain + makeupGain);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -4,7 +4,7 @@ using System.Runtime.CompilerServices;
|
|||||||
|
|
||||||
namespace Ryujinx.Audio.Renderer.Dsp.State
|
namespace Ryujinx.Audio.Renderer.Dsp.State
|
||||||
{
|
{
|
||||||
public class DelayState
|
public struct DelayState
|
||||||
{
|
{
|
||||||
public DelayLine[] DelayLines { get; }
|
public DelayLine[] DelayLines { get; }
|
||||||
public float[] LowPassZ { get; set; }
|
public float[] LowPassZ { get; set; }
|
||||||
@@ -53,7 +53,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.State
|
|||||||
LowPassBaseGain = 1.0f - LowPassFeedbackGain;
|
LowPassBaseGain = 1.0f - LowPassFeedbackGain;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void UpdateLowPassFilter(ref float tempRawRef, uint channelCount)
|
public readonly void UpdateLowPassFilter(ref float tempRawRef, uint channelCount)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < channelCount; i++)
|
for (int i = 0; i < channelCount; i++)
|
||||||
{
|
{
|
||||||
|
@@ -4,7 +4,7 @@ using System;
|
|||||||
|
|
||||||
namespace Ryujinx.Audio.Renderer.Dsp.State
|
namespace Ryujinx.Audio.Renderer.Dsp.State
|
||||||
{
|
{
|
||||||
public class LimiterState
|
public struct LimiterState
|
||||||
{
|
{
|
||||||
public ExponentialMovingAverage[] DetectorAverage;
|
public ExponentialMovingAverage[] DetectorAverage;
|
||||||
public ExponentialMovingAverage[] CompressionGainAverage;
|
public ExponentialMovingAverage[] CompressionGainAverage;
|
||||||
|
@@ -4,7 +4,7 @@ using System;
|
|||||||
|
|
||||||
namespace Ryujinx.Audio.Renderer.Dsp.State
|
namespace Ryujinx.Audio.Renderer.Dsp.State
|
||||||
{
|
{
|
||||||
public class Reverb3dState
|
public struct Reverb3dState
|
||||||
{
|
{
|
||||||
private readonly float[] _fdnDelayMinTimes = new float[4] { 5.0f, 6.0f, 13.0f, 14.0f };
|
private readonly float[] _fdnDelayMinTimes = new float[4] { 5.0f, 6.0f, 13.0f, 14.0f };
|
||||||
private readonly float[] _fdnDelayMaxTimes = new float[4] { 45.704f, 82.782f, 149.94f, 271.58f };
|
private readonly float[] _fdnDelayMaxTimes = new float[4] { 45.704f, 82.782f, 149.94f, 271.58f };
|
||||||
|
@@ -5,7 +5,7 @@ using System;
|
|||||||
|
|
||||||
namespace Ryujinx.Audio.Renderer.Dsp.State
|
namespace Ryujinx.Audio.Renderer.Dsp.State
|
||||||
{
|
{
|
||||||
public class ReverbState
|
public struct ReverbState
|
||||||
{
|
{
|
||||||
private static readonly float[] _fdnDelayTimes = new float[20]
|
private static readonly float[] _fdnDelayTimes = new float[20]
|
||||||
{
|
{
|
||||||
|
@@ -25,7 +25,7 @@ namespace Ryujinx.Audio.Renderer.Utils
|
|||||||
throw new ArgumentOutOfRangeException(nameof(backingMemory), backingMemory.Length, null);
|
throw new ArgumentOutOfRangeException(nameof(backingMemory), backingMemory.Length, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
MemoryMarshal.Write(backingMemory.Span[..size], ref data);
|
MemoryMarshal.Write(backingMemory.Span[..size], in data);
|
||||||
|
|
||||||
backingMemory = backingMemory[size..];
|
backingMemory = backingMemory[size..];
|
||||||
}
|
}
|
||||||
@@ -45,7 +45,7 @@ namespace Ryujinx.Audio.Renderer.Utils
|
|||||||
throw new ArgumentOutOfRangeException(nameof(backingMemory), backingMemory.Length, null);
|
throw new ArgumentOutOfRangeException(nameof(backingMemory), backingMemory.Length, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
MemoryMarshal.Write(backingMemory[..size], ref data);
|
MemoryMarshal.Write(backingMemory[..size], in data);
|
||||||
|
|
||||||
backingMemory = backingMemory[size..];
|
backingMemory = backingMemory[size..];
|
||||||
}
|
}
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net7.0</TargetFramework>
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
|
@@ -190,6 +190,7 @@ namespace Ryujinx.Ava
|
|||||||
ConfigurationState.Instance.Graphics.ScalingFilterLevel.Event += UpdateScalingFilterLevel;
|
ConfigurationState.Instance.Graphics.ScalingFilterLevel.Event += UpdateScalingFilterLevel;
|
||||||
ConfigurationState.Instance.Graphics.EnableColorSpacePassthrough.Event += UpdateColorSpacePassthrough;
|
ConfigurationState.Instance.Graphics.EnableColorSpacePassthrough.Event += UpdateColorSpacePassthrough;
|
||||||
|
|
||||||
|
ConfigurationState.Instance.System.EnableInternetAccess.Event += UpdateEnableInternetAccessState;
|
||||||
ConfigurationState.Instance.Multiplayer.LanInterfaceId.Event += UpdateLanInterfaceIdState;
|
ConfigurationState.Instance.Multiplayer.LanInterfaceId.Event += UpdateLanInterfaceIdState;
|
||||||
ConfigurationState.Instance.Multiplayer.Mode.Event += UpdateMultiplayerModeState;
|
ConfigurationState.Instance.Multiplayer.Mode.Event += UpdateMultiplayerModeState;
|
||||||
|
|
||||||
@@ -408,6 +409,11 @@ namespace Ryujinx.Ava
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void UpdateEnableInternetAccessState(object sender, ReactiveEventArgs<bool> e)
|
||||||
|
{
|
||||||
|
Device.Configuration.EnableInternetAccess = e.NewValue;
|
||||||
|
}
|
||||||
|
|
||||||
private void UpdateLanInterfaceIdState(object sender, ReactiveEventArgs<string> e)
|
private void UpdateLanInterfaceIdState(object sender, ReactiveEventArgs<string> e)
|
||||||
{
|
{
|
||||||
Device.Configuration.MultiplayerLanInterfaceId = e.NewValue;
|
Device.Configuration.MultiplayerLanInterfaceId = e.NewValue;
|
||||||
@@ -710,7 +716,7 @@ namespace Ryujinx.Ava
|
|||||||
|
|
||||||
ApplicationLibrary.LoadAndSaveMetaData(Device.Processes.ActiveApplication.ProgramIdText, appMetadata =>
|
ApplicationLibrary.LoadAndSaveMetaData(Device.Processes.ActiveApplication.ProgramIdText, appMetadata =>
|
||||||
{
|
{
|
||||||
appMetadata.LastPlayed = DateTime.UtcNow;
|
appMetadata.UpdatePreGame();
|
||||||
});
|
});
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@@ -14,7 +14,7 @@
|
|||||||
"MenuBarFileOpenEmuFolder": "Open Ryujinx Folder",
|
"MenuBarFileOpenEmuFolder": "Open Ryujinx Folder",
|
||||||
"MenuBarFileOpenLogsFolder": "Open Logs Folder",
|
"MenuBarFileOpenLogsFolder": "Open Logs Folder",
|
||||||
"MenuBarFileExit": "_Exit",
|
"MenuBarFileExit": "_Exit",
|
||||||
"MenuBarOptions": "Options",
|
"MenuBarOptions": "_Options",
|
||||||
"MenuBarOptionsToggleFullscreen": "Toggle Fullscreen",
|
"MenuBarOptionsToggleFullscreen": "Toggle Fullscreen",
|
||||||
"MenuBarOptionsStartGamesInFullscreen": "Start Games in Fullscreen Mode",
|
"MenuBarOptionsStartGamesInFullscreen": "Start Games in Fullscreen Mode",
|
||||||
"MenuBarOptionsStopEmulation": "Stop Emulation",
|
"MenuBarOptionsStopEmulation": "Stop Emulation",
|
||||||
@@ -30,7 +30,7 @@
|
|||||||
"MenuBarToolsManageFileTypes": "Manage file types",
|
"MenuBarToolsManageFileTypes": "Manage file types",
|
||||||
"MenuBarToolsInstallFileTypes": "Install file types",
|
"MenuBarToolsInstallFileTypes": "Install file types",
|
||||||
"MenuBarToolsUninstallFileTypes": "Uninstall file types",
|
"MenuBarToolsUninstallFileTypes": "Uninstall file types",
|
||||||
"MenuBarHelp": "Help",
|
"MenuBarHelp": "_Help",
|
||||||
"MenuBarHelpCheckForUpdates": "Check for Updates",
|
"MenuBarHelpCheckForUpdates": "Check for Updates",
|
||||||
"MenuBarHelpAbout": "About",
|
"MenuBarHelpAbout": "About",
|
||||||
"MenuSearch": "Search...",
|
"MenuSearch": "Search...",
|
||||||
@@ -72,6 +72,8 @@
|
|||||||
"GameListContextMenuExtractDataRomFSToolTip": "Extract the RomFS section from Application's current config (including updates)",
|
"GameListContextMenuExtractDataRomFSToolTip": "Extract the RomFS section from Application's current config (including updates)",
|
||||||
"GameListContextMenuExtractDataLogo": "Logo",
|
"GameListContextMenuExtractDataLogo": "Logo",
|
||||||
"GameListContextMenuExtractDataLogoToolTip": "Extract the Logo section from Application's current config (including updates)",
|
"GameListContextMenuExtractDataLogoToolTip": "Extract the Logo section from Application's current config (including updates)",
|
||||||
|
"GameListContextMenuCreateShortcut": "Create Application Shortcut",
|
||||||
|
"GameListContextMenuCreateShortcutToolTip": "Create a Desktop Shortcut that launches the selected Application",
|
||||||
"StatusBarGamesLoaded": "{0}/{1} Games Loaded",
|
"StatusBarGamesLoaded": "{0}/{1} Games Loaded",
|
||||||
"StatusBarSystemVersion": "System Version: {0}",
|
"StatusBarSystemVersion": "System Version: {0}",
|
||||||
"LinuxVmMaxMapCountDialogTitle": "Low limit for memory mappings detected",
|
"LinuxVmMaxMapCountDialogTitle": "Low limit for memory mappings detected",
|
||||||
@@ -648,7 +650,7 @@
|
|||||||
"UserEditorTitle": "Edit User",
|
"UserEditorTitle": "Edit User",
|
||||||
"UserEditorTitleCreate": "Create User",
|
"UserEditorTitleCreate": "Create User",
|
||||||
"SettingsTabNetworkInterface": "Network Interface:",
|
"SettingsTabNetworkInterface": "Network Interface:",
|
||||||
"NetworkInterfaceTooltip": "The network interface used for LAN features",
|
"NetworkInterfaceTooltip": "The network interface used for LAN/LDN features",
|
||||||
"NetworkInterfaceDefault": "Default",
|
"NetworkInterfaceDefault": "Default",
|
||||||
"PackagingShaders": "Packaging Shaders",
|
"PackagingShaders": "Packaging Shaders",
|
||||||
"AboutChangelogButton": "View Changelog on GitHub",
|
"AboutChangelogButton": "View Changelog on GitHub",
|
||||||
|
@@ -173,7 +173,7 @@ namespace Ryujinx.Ava.Common
|
|||||||
string extension = Path.GetExtension(titleFilePath).ToLower();
|
string extension = Path.GetExtension(titleFilePath).ToLower();
|
||||||
if (extension == ".nsp" || extension == ".pfs0" || extension == ".xci")
|
if (extension == ".nsp" || extension == ".pfs0" || extension == ".xci")
|
||||||
{
|
{
|
||||||
PartitionFileSystem pfs;
|
IFileSystem pfs;
|
||||||
|
|
||||||
if (extension == ".xci")
|
if (extension == ".xci")
|
||||||
{
|
{
|
||||||
@@ -181,7 +181,9 @@ namespace Ryujinx.Ava.Common
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
pfs = new PartitionFileSystem(file.AsStorage());
|
var pfsTemp = new PartitionFileSystem();
|
||||||
|
pfsTemp.Initialize(file.AsStorage()).ThrowIfFailure();
|
||||||
|
pfs = pfsTemp;
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (DirectoryEntryEx fileEntry in pfs.EnumerateEntries("/", "*.nca"))
|
foreach (DirectoryEntryEx fileEntry in pfs.EnumerateEntries("/", "*.nca"))
|
||||||
|
@@ -6,13 +6,13 @@ using Ryujinx.Common;
|
|||||||
using Ryujinx.Common.Configuration;
|
using Ryujinx.Common.Configuration;
|
||||||
using Ryujinx.Common.GraphicsDriver;
|
using Ryujinx.Common.GraphicsDriver;
|
||||||
using Ryujinx.Common.Logging;
|
using Ryujinx.Common.Logging;
|
||||||
using Ryujinx.Common.SystemInfo;
|
|
||||||
using Ryujinx.Common.SystemInterop;
|
using Ryujinx.Common.SystemInterop;
|
||||||
using Ryujinx.Modules;
|
using Ryujinx.Modules;
|
||||||
using Ryujinx.SDL2.Common;
|
using Ryujinx.SDL2.Common;
|
||||||
using Ryujinx.Ui.Common;
|
using Ryujinx.Ui.Common;
|
||||||
using Ryujinx.Ui.Common.Configuration;
|
using Ryujinx.Ui.Common.Configuration;
|
||||||
using Ryujinx.Ui.Common.Helper;
|
using Ryujinx.Ui.Common.Helper;
|
||||||
|
using Ryujinx.Ui.Common.SystemInfo;
|
||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net7.0</TargetFramework>
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
<RuntimeIdentifiers>win10-x64;osx-x64;linux-x64</RuntimeIdentifiers>
|
<RuntimeIdentifiers>win-x64;osx-x64;linux-x64</RuntimeIdentifiers>
|
||||||
<OutputType>Exe</OutputType>
|
<OutputType>Exe</OutputType>
|
||||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||||
<Version>1.0.0-dirty</Version>
|
<Version>1.0.0-dirty</Version>
|
||||||
@@ -25,6 +25,16 @@
|
|||||||
<TrimMode>partial</TrimMode>
|
<TrimMode>partial</TrimMode>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
FluentAvalonia, used in the Avalonia UI, requires a workaround for the json serializer used internally when using .NET 8+ System.Text.Json.
|
||||||
|
See:
|
||||||
|
https://github.com/amwx/FluentAvalonia/issues/481
|
||||||
|
https://devblogs.microsoft.com/dotnet/system-text-json-in-dotnet-8/
|
||||||
|
-->
|
||||||
|
<PropertyGroup>
|
||||||
|
<JsonSerializerIsReflectionEnabledByDefault>true</JsonSerializerIsReflectionEnabledByDefault>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Avalonia" />
|
<PackageReference Include="Avalonia" />
|
||||||
<PackageReference Include="Avalonia.Desktop" />
|
<PackageReference Include="Avalonia.Desktop" />
|
||||||
@@ -40,7 +50,7 @@
|
|||||||
<PackageReference Include="OpenTK.Core" />
|
<PackageReference Include="OpenTK.Core" />
|
||||||
<PackageReference Include="Ryujinx.Audio.OpenAL.Dependencies" Condition="'$(RuntimeIdentifier)' != 'linux-x64' AND '$(RuntimeIdentifier)' != 'osx-x64' AND '$(RuntimeIdentifier)' != 'osx-arm64'" />
|
<PackageReference Include="Ryujinx.Audio.OpenAL.Dependencies" Condition="'$(RuntimeIdentifier)' != 'linux-x64' AND '$(RuntimeIdentifier)' != 'osx-x64' AND '$(RuntimeIdentifier)' != 'osx-arm64'" />
|
||||||
<PackageReference Include="Ryujinx.Graphics.Nvdec.Dependencies" />
|
<PackageReference Include="Ryujinx.Graphics.Nvdec.Dependencies" />
|
||||||
<PackageReference Include="Ryujinx.Graphics.Vulkan.Dependencies.MoltenVK" Condition="'$(RuntimeIdentifier)' != 'linux-x64' AND '$(RuntimeIdentifier)' != 'win10-x64'" />
|
<PackageReference Include="Ryujinx.Graphics.Vulkan.Dependencies.MoltenVK" Condition="'$(RuntimeIdentifier)' != 'linux-x64' AND '$(RuntimeIdentifier)' != 'win-x64'" />
|
||||||
<PackageReference Include="Silk.NET.Vulkan" />
|
<PackageReference Include="Silk.NET.Vulkan" />
|
||||||
<PackageReference Include="Silk.NET.Vulkan.Extensions.EXT" />
|
<PackageReference Include="Silk.NET.Vulkan.Extensions.EXT" />
|
||||||
<PackageReference Include="Silk.NET.Vulkan.Extensions.KHR" />
|
<PackageReference Include="Silk.NET.Vulkan.Extensions.KHR" />
|
||||||
|
@@ -12,6 +12,11 @@
|
|||||||
Click="ToggleFavorite_Click"
|
Click="ToggleFavorite_Click"
|
||||||
Header="{locale:Locale GameListContextMenuToggleFavorite}"
|
Header="{locale:Locale GameListContextMenuToggleFavorite}"
|
||||||
ToolTip.Tip="{locale:Locale GameListContextMenuToggleFavoriteToolTip}" />
|
ToolTip.Tip="{locale:Locale GameListContextMenuToggleFavoriteToolTip}" />
|
||||||
|
<MenuItem
|
||||||
|
Click="CreateApplicationShortcut_Click"
|
||||||
|
Header="{locale:Locale GameListContextMenuCreateShortcut}"
|
||||||
|
IsEnabled="{Binding CreateShortcutEnabled}"
|
||||||
|
ToolTip.Tip="{locale:Locale GameListContextMenuCreateShortcutToolTip}" />
|
||||||
<Separator />
|
<Separator />
|
||||||
<MenuItem
|
<MenuItem
|
||||||
Click="OpenUserSaveDirectory_Click"
|
Click="OpenUserSaveDirectory_Click"
|
||||||
|
@@ -337,6 +337,17 @@ namespace Ryujinx.Ava.UI.Controls
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void CreateApplicationShortcut_Click(object sender, RoutedEventArgs args)
|
||||||
|
{
|
||||||
|
var viewModel = (sender as MenuItem)?.DataContext as MainWindowViewModel;
|
||||||
|
|
||||||
|
if (viewModel?.SelectedApplication != null)
|
||||||
|
{
|
||||||
|
ApplicationData selectedApplication = viewModel.SelectedApplication;
|
||||||
|
ShortcutHelper.CreateAppShortcut(selectedApplication.Path, selectedApplication.TitleName, selectedApplication.TitleId, selectedApplication.Icon);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public async void RunApplication_Click(object sender, RoutedEventArgs args)
|
public async void RunApplication_Click(object sender, RoutedEventArgs args)
|
||||||
{
|
{
|
||||||
var viewModel = (sender as MenuItem)?.DataContext as MainWindowViewModel;
|
var viewModel = (sender as MenuItem)?.DataContext as MainWindowViewModel;
|
||||||
|
@@ -126,17 +126,17 @@
|
|||||||
Spacing="5">
|
Spacing="5">
|
||||||
<TextBlock
|
<TextBlock
|
||||||
HorizontalAlignment="Stretch"
|
HorizontalAlignment="Stretch"
|
||||||
Text="{Binding TimePlayed}"
|
Text="{Binding TimePlayedString}"
|
||||||
TextAlignment="Right"
|
TextAlignment="Right"
|
||||||
TextWrapping="Wrap" />
|
TextWrapping="Wrap" />
|
||||||
<TextBlock
|
<TextBlock
|
||||||
HorizontalAlignment="Stretch"
|
HorizontalAlignment="Stretch"
|
||||||
Text="{Binding LastPlayed, Converter={helpers:NullableDateTimeConverter}}"
|
Text="{Binding LastPlayedString, Converter={helpers:LocalizedNeverConverter}}"
|
||||||
TextAlignment="Right"
|
TextAlignment="Right"
|
||||||
TextWrapping="Wrap" />
|
TextWrapping="Wrap" />
|
||||||
<TextBlock
|
<TextBlock
|
||||||
HorizontalAlignment="Stretch"
|
HorizontalAlignment="Stretch"
|
||||||
Text="{Binding FileSize}"
|
Text="{Binding FileSizeString}"
|
||||||
TextAlignment="Right"
|
TextAlignment="Right"
|
||||||
TextWrapping="Wrap" />
|
TextWrapping="Wrap" />
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
31
src/Ryujinx.Ava/UI/Controls/SliderScroll.axaml.cs
Normal file
31
src/Ryujinx.Ava/UI/Controls/SliderScroll.axaml.cs
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
using Avalonia.Controls;
|
||||||
|
using Avalonia.Input;
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Ryujinx.Ava.UI.Controls
|
||||||
|
{
|
||||||
|
public class SliderScroll : Slider
|
||||||
|
{
|
||||||
|
protected override Type StyleKeyOverride => typeof(Slider);
|
||||||
|
|
||||||
|
protected override void OnPointerWheelChanged(PointerWheelEventArgs e)
|
||||||
|
{
|
||||||
|
var newValue = Value + e.Delta.Y * TickFrequency;
|
||||||
|
|
||||||
|
if (newValue < Minimum)
|
||||||
|
{
|
||||||
|
Value = Minimum;
|
||||||
|
}
|
||||||
|
else if (newValue > Maximum)
|
||||||
|
{
|
||||||
|
Value = Maximum;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Value = newValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
e.Handled = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
43
src/Ryujinx.Ava/UI/Helpers/LocalizedNeverConverter.cs
Normal file
43
src/Ryujinx.Ava/UI/Helpers/LocalizedNeverConverter.cs
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
using Avalonia.Data.Converters;
|
||||||
|
using Avalonia.Markup.Xaml;
|
||||||
|
using Ryujinx.Ava.Common.Locale;
|
||||||
|
using Ryujinx.Ui.Common.Helper;
|
||||||
|
using System;
|
||||||
|
using System.Globalization;
|
||||||
|
|
||||||
|
namespace Ryujinx.Ava.UI.Helpers
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// This <see cref="IValueConverter"/> makes sure that the string "Never" that's returned by <see cref="ValueFormatUtils.FormatDateTime"/> is properly localized in the Avalonia UI.
|
||||||
|
/// After the Avalonia UI has been made the default and the GTK UI is removed, <see cref="ValueFormatUtils"/> should be updated to directly return a localized string.
|
||||||
|
/// </summary>
|
||||||
|
internal class LocalizedNeverConverter : MarkupExtension, IValueConverter
|
||||||
|
{
|
||||||
|
private static readonly LocalizedNeverConverter _instance = new();
|
||||||
|
|
||||||
|
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||||
|
{
|
||||||
|
if (value is not string valStr)
|
||||||
|
{
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (valStr == "Never")
|
||||||
|
{
|
||||||
|
return LocaleManager.Instance[LocaleKeys.Never];
|
||||||
|
}
|
||||||
|
|
||||||
|
return valStr;
|
||||||
|
}
|
||||||
|
|
||||||
|
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
||||||
|
{
|
||||||
|
throw new NotSupportedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override object ProvideValue(IServiceProvider serviceProvider)
|
||||||
|
{
|
||||||
|
return _instance;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -1,38 +0,0 @@
|
|||||||
using Avalonia.Data.Converters;
|
|
||||||
using Avalonia.Markup.Xaml;
|
|
||||||
using Ryujinx.Ava.Common.Locale;
|
|
||||||
using System;
|
|
||||||
using System.Globalization;
|
|
||||||
|
|
||||||
namespace Ryujinx.Ava.UI.Helpers
|
|
||||||
{
|
|
||||||
internal class NullableDateTimeConverter : MarkupExtension, IValueConverter
|
|
||||||
{
|
|
||||||
private static readonly NullableDateTimeConverter _instance = new();
|
|
||||||
|
|
||||||
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
|
||||||
{
|
|
||||||
if (value == null)
|
|
||||||
{
|
|
||||||
return LocaleManager.Instance[LocaleKeys.Never];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (value is DateTime dateTime)
|
|
||||||
{
|
|
||||||
return dateTime.ToLocalTime().ToString(culture);
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new NotSupportedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
|
||||||
{
|
|
||||||
throw new NotSupportedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
public override object ProvideValue(IServiceProvider serviceProvider)
|
|
||||||
{
|
|
||||||
return _instance;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@@ -86,7 +86,7 @@ namespace Ryujinx.Ava.UI.Helpers
|
|||||||
public static partial IntPtr SetCursor(IntPtr handle);
|
public static partial IntPtr SetCursor(IntPtr handle);
|
||||||
|
|
||||||
[LibraryImport("user32.dll")]
|
[LibraryImport("user32.dll")]
|
||||||
public static partial IntPtr CreateCursor(IntPtr hInst, int xHotSpot, int yHotSpot, int nWidth, int nHeight, byte[] pvAndPlane, byte[] pvXorPlane);
|
public static partial IntPtr CreateCursor(IntPtr hInst, int xHotSpot, int yHotSpot, int nWidth, int nHeight, [In] byte[] pvAndPlane, [In] byte[] pvXorPlane);
|
||||||
|
|
||||||
[LibraryImport("user32.dll", SetLastError = true, EntryPoint = "RegisterClassExW")]
|
[LibraryImport("user32.dll", SetLastError = true, EntryPoint = "RegisterClassExW")]
|
||||||
public static partial ushort RegisterClassEx(ref WndClassEx param);
|
public static partial ushort RegisterClassEx(ref WndClassEx param);
|
||||||
|
@@ -13,20 +13,19 @@ namespace Ryujinx.Ava.UI.Models.Generic
|
|||||||
|
|
||||||
public int Compare(ApplicationData x, ApplicationData y)
|
public int Compare(ApplicationData x, ApplicationData y)
|
||||||
{
|
{
|
||||||
var aValue = x.LastPlayed;
|
DateTime aValue = DateTime.UnixEpoch, bValue = DateTime.UnixEpoch;
|
||||||
var bValue = y.LastPlayed;
|
|
||||||
|
|
||||||
if (!aValue.HasValue)
|
if (x?.LastPlayed != null)
|
||||||
{
|
{
|
||||||
aValue = DateTime.UnixEpoch;
|
aValue = x.LastPlayed.Value;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!bValue.HasValue)
|
if (y?.LastPlayed != null)
|
||||||
{
|
{
|
||||||
bValue = DateTime.UnixEpoch;
|
bValue = y.LastPlayed.Value;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (IsAscending ? 1 : -1) * DateTime.Compare(bValue.Value, aValue.Value);
|
return (IsAscending ? 1 : -1) * DateTime.Compare(aValue, bValue);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
31
src/Ryujinx.Ava/UI/Models/Generic/TimePlayedSortComparer.cs
Normal file
31
src/Ryujinx.Ava/UI/Models/Generic/TimePlayedSortComparer.cs
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
using Ryujinx.Ui.App.Common;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace Ryujinx.Ava.UI.Models.Generic
|
||||||
|
{
|
||||||
|
internal class TimePlayedSortComparer : IComparer<ApplicationData>
|
||||||
|
{
|
||||||
|
public TimePlayedSortComparer() { }
|
||||||
|
public TimePlayedSortComparer(bool isAscending) { IsAscending = isAscending; }
|
||||||
|
|
||||||
|
public bool IsAscending { get; }
|
||||||
|
|
||||||
|
public int Compare(ApplicationData x, ApplicationData y)
|
||||||
|
{
|
||||||
|
TimeSpan aValue = TimeSpan.Zero, bValue = TimeSpan.Zero;
|
||||||
|
|
||||||
|
if (x?.TimePlayed != null)
|
||||||
|
{
|
||||||
|
aValue = x.TimePlayed;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (y?.TimePlayed != null)
|
||||||
|
{
|
||||||
|
bValue = y.TimePlayed;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (IsAscending ? 1 : -1) * TimeSpan.Compare(aValue, bValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -4,7 +4,7 @@ using Ryujinx.Ava.UI.ViewModels;
|
|||||||
using Ryujinx.Ava.UI.Windows;
|
using Ryujinx.Ava.UI.Windows;
|
||||||
using Ryujinx.HLE.FileSystem;
|
using Ryujinx.HLE.FileSystem;
|
||||||
using Ryujinx.Ui.App.Common;
|
using Ryujinx.Ui.App.Common;
|
||||||
using System;
|
using Ryujinx.Ui.Common.Helper;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
@@ -38,26 +38,7 @@ namespace Ryujinx.Ava.UI.Models
|
|||||||
|
|
||||||
public bool SizeAvailable { get; set; }
|
public bool SizeAvailable { get; set; }
|
||||||
|
|
||||||
public string SizeString => GetSizeString();
|
public string SizeString => ValueFormatUtils.FormatFileSize(Size);
|
||||||
|
|
||||||
private string GetSizeString()
|
|
||||||
{
|
|
||||||
const int Scale = 1024;
|
|
||||||
string[] orders = { "GiB", "MiB", "KiB" };
|
|
||||||
long max = (long)Math.Pow(Scale, orders.Length);
|
|
||||||
|
|
||||||
foreach (string order in orders)
|
|
||||||
{
|
|
||||||
if (Size > max)
|
|
||||||
{
|
|
||||||
return $"{decimal.Divide(Size, max):##.##} {order}";
|
|
||||||
}
|
|
||||||
|
|
||||||
max /= Scale;
|
|
||||||
}
|
|
||||||
|
|
||||||
return "0 KiB";
|
|
||||||
}
|
|
||||||
|
|
||||||
public SaveModel(SaveDataInfo info)
|
public SaveModel(SaveDataInfo info)
|
||||||
{
|
{
|
||||||
|
@@ -327,7 +327,7 @@ namespace Ryujinx.Ava.UI.ViewModels
|
|||||||
|
|
||||||
string imageUrl = _amiiboList.Find(amiibo => amiibo.Equals(selected)).Image;
|
string imageUrl = _amiiboList.Find(amiibo => amiibo.Equals(selected)).Image;
|
||||||
|
|
||||||
string usageString = "";
|
StringBuilder usageStringBuilder = new();
|
||||||
|
|
||||||
for (int i = 0; i < _amiiboList.Count; i++)
|
for (int i = 0; i < _amiiboList.Count; i++)
|
||||||
{
|
{
|
||||||
@@ -341,20 +341,19 @@ namespace Ryujinx.Ava.UI.ViewModels
|
|||||||
{
|
{
|
||||||
foreach (AmiiboApiUsage usageItem in item.AmiiboUsage)
|
foreach (AmiiboApiUsage usageItem in item.AmiiboUsage)
|
||||||
{
|
{
|
||||||
usageString += Environment.NewLine +
|
usageStringBuilder.Append($"{Environment.NewLine}- {usageItem.Usage.Replace("/", Environment.NewLine + "-")}");
|
||||||
$"- {usageItem.Usage.Replace("/", Environment.NewLine + "-")}";
|
|
||||||
|
|
||||||
writable = usageItem.Write;
|
writable = usageItem.Write;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (usageString.Length == 0)
|
if (usageStringBuilder.Length == 0)
|
||||||
{
|
{
|
||||||
usageString = LocaleManager.Instance[LocaleKeys.Unknown] + ".";
|
usageStringBuilder.Append($"{LocaleManager.Instance[LocaleKeys.Unknown]}.");
|
||||||
}
|
}
|
||||||
|
|
||||||
Usage = $"{LocaleManager.Instance[LocaleKeys.Usage]} {(writable ? $" ({LocaleManager.Instance[LocaleKeys.Writable]})" : "")} : {usageString}";
|
Usage = $"{LocaleManager.Instance[LocaleKeys.Usage]} {(writable ? $" ({LocaleManager.Instance[LocaleKeys.Writable]})" : "")} : {usageStringBuilder}";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -126,7 +126,8 @@ namespace Ryujinx.Ava.UI.ViewModels
|
|||||||
{
|
{
|
||||||
using FileStream containerFile = File.OpenRead(downloadableContentContainer.ContainerPath);
|
using FileStream containerFile = File.OpenRead(downloadableContentContainer.ContainerPath);
|
||||||
|
|
||||||
PartitionFileSystem partitionFileSystem = new(containerFile.AsStorage());
|
PartitionFileSystem partitionFileSystem = new();
|
||||||
|
partitionFileSystem.Initialize(containerFile.AsStorage()).ThrowIfFailure();
|
||||||
|
|
||||||
_virtualFileSystem.ImportTickets(partitionFileSystem);
|
_virtualFileSystem.ImportTickets(partitionFileSystem);
|
||||||
|
|
||||||
@@ -232,7 +233,8 @@ namespace Ryujinx.Ava.UI.ViewModels
|
|||||||
|
|
||||||
using FileStream containerFile = File.OpenRead(path);
|
using FileStream containerFile = File.OpenRead(path);
|
||||||
|
|
||||||
PartitionFileSystem partitionFileSystem = new(containerFile.AsStorage());
|
PartitionFileSystem partitionFileSystem = new();
|
||||||
|
partitionFileSystem.Initialize(containerFile.AsStorage()).ThrowIfFailure();
|
||||||
bool containsDownloadableContent = false;
|
bool containsDownloadableContent = false;
|
||||||
|
|
||||||
_virtualFileSystem.ImportTickets(partitionFileSystem);
|
_virtualFileSystem.ImportTickets(partitionFileSystem);
|
||||||
|
@@ -356,6 +356,8 @@ namespace Ryujinx.Ava.UI.ViewModels
|
|||||||
|
|
||||||
public bool OpenBcatSaveDirectoryEnabled => !SelectedApplication.ControlHolder.ByteSpan.IsZeros() && SelectedApplication.ControlHolder.Value.BcatDeliveryCacheStorageSize > 0;
|
public bool OpenBcatSaveDirectoryEnabled => !SelectedApplication.ControlHolder.ByteSpan.IsZeros() && SelectedApplication.ControlHolder.Value.BcatDeliveryCacheStorageSize > 0;
|
||||||
|
|
||||||
|
public bool CreateShortcutEnabled => !ReleaseInformation.IsFlatHubBuild();
|
||||||
|
|
||||||
public string LoadHeading
|
public string LoadHeading
|
||||||
{
|
{
|
||||||
get => _loadHeading;
|
get => _loadHeading;
|
||||||
@@ -928,21 +930,20 @@ namespace Ryujinx.Ava.UI.ViewModels
|
|||||||
return SortMode switch
|
return SortMode switch
|
||||||
{
|
{
|
||||||
#pragma warning disable IDE0055 // Disable formatting
|
#pragma warning disable IDE0055 // Disable formatting
|
||||||
ApplicationSort.LastPlayed => new LastPlayedSortComparer(IsAscending),
|
|
||||||
ApplicationSort.FileSize => IsAscending ? SortExpressionComparer<ApplicationData>.Ascending(app => app.FileSizeBytes)
|
|
||||||
: SortExpressionComparer<ApplicationData>.Descending(app => app.FileSizeBytes),
|
|
||||||
ApplicationSort.TotalTimePlayed => IsAscending ? SortExpressionComparer<ApplicationData>.Ascending(app => app.TimePlayedNum)
|
|
||||||
: SortExpressionComparer<ApplicationData>.Descending(app => app.TimePlayedNum),
|
|
||||||
ApplicationSort.Title => IsAscending ? SortExpressionComparer<ApplicationData>.Ascending(app => app.TitleName)
|
ApplicationSort.Title => IsAscending ? SortExpressionComparer<ApplicationData>.Ascending(app => app.TitleName)
|
||||||
: SortExpressionComparer<ApplicationData>.Descending(app => app.TitleName),
|
: SortExpressionComparer<ApplicationData>.Descending(app => app.TitleName),
|
||||||
ApplicationSort.Favorite => !IsAscending ? SortExpressionComparer<ApplicationData>.Ascending(app => app.Favorite)
|
|
||||||
: SortExpressionComparer<ApplicationData>.Descending(app => app.Favorite),
|
|
||||||
ApplicationSort.Developer => IsAscending ? SortExpressionComparer<ApplicationData>.Ascending(app => app.Developer)
|
ApplicationSort.Developer => IsAscending ? SortExpressionComparer<ApplicationData>.Ascending(app => app.Developer)
|
||||||
: SortExpressionComparer<ApplicationData>.Descending(app => app.Developer),
|
: SortExpressionComparer<ApplicationData>.Descending(app => app.Developer),
|
||||||
|
ApplicationSort.LastPlayed => new LastPlayedSortComparer(IsAscending),
|
||||||
|
ApplicationSort.TotalTimePlayed => new TimePlayedSortComparer(IsAscending),
|
||||||
ApplicationSort.FileType => IsAscending ? SortExpressionComparer<ApplicationData>.Ascending(app => app.FileExtension)
|
ApplicationSort.FileType => IsAscending ? SortExpressionComparer<ApplicationData>.Ascending(app => app.FileExtension)
|
||||||
: SortExpressionComparer<ApplicationData>.Descending(app => app.FileExtension),
|
: SortExpressionComparer<ApplicationData>.Descending(app => app.FileExtension),
|
||||||
|
ApplicationSort.FileSize => IsAscending ? SortExpressionComparer<ApplicationData>.Ascending(app => app.FileSize)
|
||||||
|
: SortExpressionComparer<ApplicationData>.Descending(app => app.FileSize),
|
||||||
ApplicationSort.Path => IsAscending ? SortExpressionComparer<ApplicationData>.Ascending(app => app.Path)
|
ApplicationSort.Path => IsAscending ? SortExpressionComparer<ApplicationData>.Ascending(app => app.Path)
|
||||||
: SortExpressionComparer<ApplicationData>.Descending(app => app.Path),
|
: SortExpressionComparer<ApplicationData>.Descending(app => app.Path),
|
||||||
|
ApplicationSort.Favorite => !IsAscending ? SortExpressionComparer<ApplicationData>.Ascending(app => app.Favorite)
|
||||||
|
: SortExpressionComparer<ApplicationData>.Descending(app => app.Favorite),
|
||||||
_ => null,
|
_ => null,
|
||||||
#pragma warning restore IDE0055
|
#pragma warning restore IDE0055
|
||||||
};
|
};
|
||||||
@@ -1278,6 +1279,11 @@ namespace Ryujinx.Ava.UI.ViewModels
|
|||||||
Glyph = Glyph.Grid;
|
Glyph = Glyph.Grid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void SetAspectRatio(AspectRatio aspectRatio)
|
||||||
|
{
|
||||||
|
ConfigurationState.Instance.Graphics.AspectRatio.Value = aspectRatio;
|
||||||
|
}
|
||||||
|
|
||||||
public async Task InstallFirmwareFromFile()
|
public async Task InstallFirmwareFromFile()
|
||||||
{
|
{
|
||||||
var result = await StorageProvider.OpenFilePickerAsync(new FilePickerOpenOptions
|
var result = await StorageProvider.OpenFilePickerAsync(new FilePickerOpenOptions
|
||||||
@@ -1483,7 +1489,7 @@ namespace Ryujinx.Ava.UI.ViewModels
|
|||||||
|
|
||||||
Logger.RestartTime();
|
Logger.RestartTime();
|
||||||
|
|
||||||
SelectedIcon ??= ApplicationLibrary.GetApplicationIcon(path);
|
SelectedIcon ??= ApplicationLibrary.GetApplicationIcon(path, ConfigurationState.Instance.System.Language);
|
||||||
|
|
||||||
PrepareLoadScreen();
|
PrepareLoadScreen();
|
||||||
|
|
||||||
@@ -1542,13 +1548,7 @@ namespace Ryujinx.Ava.UI.ViewModels
|
|||||||
{
|
{
|
||||||
ApplicationLibrary.LoadAndSaveMetaData(titleId, appMetadata =>
|
ApplicationLibrary.LoadAndSaveMetaData(titleId, appMetadata =>
|
||||||
{
|
{
|
||||||
if (appMetadata.LastPlayed.HasValue)
|
appMetadata.UpdatePostGame();
|
||||||
{
|
|
||||||
double sessionTimePlayed = DateTime.UtcNow.Subtract(appMetadata.LastPlayed.Value).TotalSeconds;
|
|
||||||
appMetadata.TimePlayed += Math.Round(sessionTimePlayed, MidpointRounding.AwayFromZero);
|
|
||||||
}
|
|
||||||
|
|
||||||
appMetadata.LastPlayed = DateTime.UtcNow;
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1691,7 +1691,6 @@ namespace Ryujinx.Ava.UI.ViewModels
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -147,6 +147,7 @@ namespace Ryujinx.Ava.UI.ViewModels
|
|||||||
public bool EnableTextureRecompression { get; set; }
|
public bool EnableTextureRecompression { get; set; }
|
||||||
public bool EnableMacroHLE { get; set; }
|
public bool EnableMacroHLE { get; set; }
|
||||||
public bool EnableColorSpacePassthrough { get; set; }
|
public bool EnableColorSpacePassthrough { get; set; }
|
||||||
|
public bool ColorSpacePassthroughAvailable => IsMacOS;
|
||||||
public bool EnableFileLog { get; set; }
|
public bool EnableFileLog { get; set; }
|
||||||
public bool EnableStub { get; set; }
|
public bool EnableStub { get; set; }
|
||||||
public bool EnableInfo { get; set; }
|
public bool EnableInfo { get; set; }
|
||||||
|
@@ -170,7 +170,9 @@ namespace Ryujinx.Ava.UI.ViewModels
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
(Nca patchNca, Nca controlNca) = ApplicationLibrary.GetGameUpdateDataFromPartition(VirtualFileSystem, new PartitionFileSystem(file.AsStorage()), TitleId.ToString("x16"), 0);
|
var pfs = new PartitionFileSystem();
|
||||||
|
pfs.Initialize(file.AsStorage()).ThrowIfFailure();
|
||||||
|
(Nca patchNca, Nca controlNca) = ApplicationLibrary.GetGameUpdateDataFromPartition(VirtualFileSystem, pfs, TitleId.ToString("x16"), 0);
|
||||||
|
|
||||||
if (controlNca != null && patchNca != null)
|
if (controlNca != null && patchNca != null)
|
||||||
{
|
{
|
||||||
|
@@ -5,6 +5,7 @@
|
|||||||
xmlns:locale="clr-namespace:Ryujinx.Ava.Common.Locale"
|
xmlns:locale="clr-namespace:Ryujinx.Ava.Common.Locale"
|
||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
xmlns:controls="clr-namespace:Ryujinx.Ava.UI.Controls"
|
||||||
xmlns:models="clr-namespace:Ryujinx.Ava.UI.Models"
|
xmlns:models="clr-namespace:Ryujinx.Ava.UI.Models"
|
||||||
xmlns:viewModels="clr-namespace:Ryujinx.Ava.UI.ViewModels"
|
xmlns:viewModels="clr-namespace:Ryujinx.Ava.UI.ViewModels"
|
||||||
xmlns:helpers="clr-namespace:Ryujinx.Ava.UI.Helpers"
|
xmlns:helpers="clr-namespace:Ryujinx.Ava.UI.Helpers"
|
||||||
@@ -460,7 +461,7 @@
|
|||||||
HorizontalAlignment="Center"
|
HorizontalAlignment="Center"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
Orientation="Horizontal">
|
Orientation="Horizontal">
|
||||||
<Slider
|
<controls:SliderScroll
|
||||||
Width="130"
|
Width="130"
|
||||||
Maximum="1"
|
Maximum="1"
|
||||||
TickFrequency="0.01"
|
TickFrequency="0.01"
|
||||||
@@ -480,7 +481,7 @@
|
|||||||
HorizontalAlignment="Center"
|
HorizontalAlignment="Center"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
Orientation="Horizontal">
|
Orientation="Horizontal">
|
||||||
<Slider
|
<controls:SliderScroll
|
||||||
Width="130"
|
Width="130"
|
||||||
Maximum="2"
|
Maximum="2"
|
||||||
TickFrequency="0.01"
|
TickFrequency="0.01"
|
||||||
@@ -604,7 +605,7 @@
|
|||||||
<StackPanel
|
<StackPanel
|
||||||
HorizontalAlignment="Center"
|
HorizontalAlignment="Center"
|
||||||
Orientation="Horizontal">
|
Orientation="Horizontal">
|
||||||
<Slider
|
<controls:SliderScroll
|
||||||
Width="130"
|
Width="130"
|
||||||
Maximum="1"
|
Maximum="1"
|
||||||
TickFrequency="0.01"
|
TickFrequency="0.01"
|
||||||
@@ -1083,7 +1084,7 @@
|
|||||||
HorizontalAlignment="Center"
|
HorizontalAlignment="Center"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
Orientation="Horizontal">
|
Orientation="Horizontal">
|
||||||
<Slider
|
<controls:SliderScroll
|
||||||
Width="130"
|
Width="130"
|
||||||
Maximum="1"
|
Maximum="1"
|
||||||
TickFrequency="0.01"
|
TickFrequency="0.01"
|
||||||
@@ -1105,7 +1106,7 @@
|
|||||||
HorizontalAlignment="Center"
|
HorizontalAlignment="Center"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
Orientation="Horizontal">
|
Orientation="Horizontal">
|
||||||
<Slider
|
<controls:SliderScroll
|
||||||
Width="130"
|
Width="130"
|
||||||
Maximum="2"
|
Maximum="2"
|
||||||
TickFrequency="0.01"
|
TickFrequency="0.01"
|
||||||
|
@@ -3,6 +3,7 @@
|
|||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
xmlns:controls="clr-namespace:Ryujinx.Ava.UI.Controls"
|
||||||
xmlns:ui="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia"
|
xmlns:ui="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia"
|
||||||
xmlns:locale="clr-namespace:Ryujinx.Ava.Common.Locale"
|
xmlns:locale="clr-namespace:Ryujinx.Ava.Common.Locale"
|
||||||
xmlns:viewModels="clr-namespace:Ryujinx.Ava.UI.ViewModels"
|
xmlns:viewModels="clr-namespace:Ryujinx.Ava.UI.ViewModels"
|
||||||
@@ -23,11 +24,11 @@
|
|||||||
Margin="0"
|
Margin="0"
|
||||||
HorizontalAlignment="Center"
|
HorizontalAlignment="Center"
|
||||||
Text="{locale:Locale ControllerSettingsMotionGyroSensitivity}" />
|
Text="{locale:Locale ControllerSettingsMotionGyroSensitivity}" />
|
||||||
<Slider
|
<controls:SliderScroll
|
||||||
Margin="0,-5,0,-5"
|
Margin="0,-5,0,-5"
|
||||||
Width="150"
|
Width="150"
|
||||||
MaxWidth="150"
|
MaxWidth="150"
|
||||||
TickFrequency="0.01"
|
TickFrequency="1"
|
||||||
IsSnapToTickEnabled="True"
|
IsSnapToTickEnabled="True"
|
||||||
SmallChange="0.01"
|
SmallChange="0.01"
|
||||||
Maximum="100"
|
Maximum="100"
|
||||||
@@ -45,11 +46,11 @@
|
|||||||
Margin="0"
|
Margin="0"
|
||||||
HorizontalAlignment="Center"
|
HorizontalAlignment="Center"
|
||||||
Text="{locale:Locale ControllerSettingsMotionGyroDeadzone}" />
|
Text="{locale:Locale ControllerSettingsMotionGyroDeadzone}" />
|
||||||
<Slider
|
<controls:SliderScroll
|
||||||
Margin="0,-5,0,-5"
|
Margin="0,-5,0,-5"
|
||||||
Width="150"
|
Width="150"
|
||||||
MaxWidth="150"
|
MaxWidth="150"
|
||||||
TickFrequency="0.01"
|
TickFrequency="1"
|
||||||
IsSnapToTickEnabled="True"
|
IsSnapToTickEnabled="True"
|
||||||
SmallChange="0.01"
|
SmallChange="0.01"
|
||||||
Maximum="100"
|
Maximum="100"
|
||||||
|
@@ -1,6 +1,7 @@
|
|||||||
<UserControl
|
<UserControl
|
||||||
xmlns="https://github.com/avaloniaui"
|
xmlns="https://github.com/avaloniaui"
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:controls="clr-namespace:Ryujinx.Ava.UI.Controls"
|
||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
xmlns:locale="clr-namespace:Ryujinx.Ava.Common.Locale"
|
xmlns:locale="clr-namespace:Ryujinx.Ava.Common.Locale"
|
||||||
@@ -21,7 +22,7 @@
|
|||||||
TextWrapping="WrapWithOverflow"
|
TextWrapping="WrapWithOverflow"
|
||||||
HorizontalAlignment="Center"
|
HorizontalAlignment="Center"
|
||||||
Text="{locale:Locale ControllerSettingsRumbleStrongMultiplier}" />
|
Text="{locale:Locale ControllerSettingsRumbleStrongMultiplier}" />
|
||||||
<Slider
|
<controls:SliderScroll
|
||||||
Margin="0,-5,0,-5"
|
Margin="0,-5,0,-5"
|
||||||
Width="200"
|
Width="200"
|
||||||
TickFrequency="0.01"
|
TickFrequency="0.01"
|
||||||
@@ -41,7 +42,7 @@
|
|||||||
TextWrapping="WrapWithOverflow"
|
TextWrapping="WrapWithOverflow"
|
||||||
HorizontalAlignment="Center"
|
HorizontalAlignment="Center"
|
||||||
Text="{locale:Locale ControllerSettingsRumbleWeakMultiplier}" />
|
Text="{locale:Locale ControllerSettingsRumbleWeakMultiplier}" />
|
||||||
<Slider
|
<controls:SliderScroll
|
||||||
Margin="0,-5,0,-5"
|
Margin="0,-5,0,-5"
|
||||||
Width="200"
|
Width="200"
|
||||||
MaxWidth="200"
|
MaxWidth="200"
|
||||||
|
@@ -3,9 +3,11 @@
|
|||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
xmlns:controls="clr-namespace:Ryujinx.Ava.UI.Controls"
|
||||||
xmlns:locale="clr-namespace:Ryujinx.Ava.Common.Locale"
|
xmlns:locale="clr-namespace:Ryujinx.Ava.Common.Locale"
|
||||||
xmlns:ui="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia"
|
xmlns:ui="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia"
|
||||||
xmlns:viewModels="clr-namespace:Ryujinx.Ava.UI.ViewModels"
|
xmlns:viewModels="clr-namespace:Ryujinx.Ava.UI.ViewModels"
|
||||||
|
xmlns:config="clr-namespace:Ryujinx.Common.Configuration;assembly=Ryujinx.Common"
|
||||||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||||
x:Class="Ryujinx.Ava.UI.Views.Main.MainStatusBarView"
|
x:Class="Ryujinx.Ava.UI.Views.Main.MainStatusBarView"
|
||||||
x:DataType="viewModels:MainWindowViewModel">
|
x:DataType="viewModels:MainWindowViewModel">
|
||||||
@@ -112,15 +114,52 @@
|
|||||||
Background="Gray"
|
Background="Gray"
|
||||||
BorderThickness="1"
|
BorderThickness="1"
|
||||||
IsVisible="{Binding !ShowLoadProgress}" />
|
IsVisible="{Binding !ShowLoadProgress}" />
|
||||||
<TextBlock
|
<SplitButton
|
||||||
Name="AspectRatioStatus"
|
Name="AspectRatioStatus"
|
||||||
Margin="5,0,5,0"
|
Padding="5,0,5,0"
|
||||||
HorizontalAlignment="Left"
|
HorizontalAlignment="Left"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
|
Background="Transparent"
|
||||||
|
BorderThickness="0"
|
||||||
|
CornerRadius="0"
|
||||||
IsVisible="{Binding !ShowLoadProgress}"
|
IsVisible="{Binding !ShowLoadProgress}"
|
||||||
PointerReleased="AspectRatioStatus_PointerReleased"
|
Content="{Binding AspectRatioStatusText}"
|
||||||
Text="{Binding AspectRatioStatusText}"
|
Click="AspectRatioStatus_OnClick"
|
||||||
TextAlignment="Left" />
|
ToolTip.Tip="{locale:Locale AspectRatioTooltip}">
|
||||||
|
<SplitButton.Styles>
|
||||||
|
<Style Selector="Border#SeparatorBorder">
|
||||||
|
<Setter Property="Opacity" Value="0" />
|
||||||
|
</Style>
|
||||||
|
</SplitButton.Styles>
|
||||||
|
<SplitButton.Flyout>
|
||||||
|
<MenuFlyout Placement="Bottom" ShowMode="TransientWithDismissOnPointerMoveAway">
|
||||||
|
<MenuItem
|
||||||
|
Header="{locale:Locale SettingsTabGraphicsAspectRatio4x3}"
|
||||||
|
Command="{Binding SetAspectRatio}"
|
||||||
|
CommandParameter="{x:Static config:AspectRatio.Fixed4x3}"/>
|
||||||
|
<MenuItem
|
||||||
|
Header="{locale:Locale SettingsTabGraphicsAspectRatio16x9}"
|
||||||
|
Command="{Binding SetAspectRatio}"
|
||||||
|
CommandParameter="{x:Static config:AspectRatio.Fixed16x9}"/>
|
||||||
|
<MenuItem
|
||||||
|
Header="{locale:Locale SettingsTabGraphicsAspectRatio16x10}"
|
||||||
|
Command="{Binding SetAspectRatio}"
|
||||||
|
CommandParameter="{x:Static config:AspectRatio.Fixed16x10}"/>
|
||||||
|
<MenuItem
|
||||||
|
Header="{locale:Locale SettingsTabGraphicsAspectRatio21x9}"
|
||||||
|
Command="{Binding SetAspectRatio}"
|
||||||
|
CommandParameter="{x:Static config:AspectRatio.Fixed21x9}"/>
|
||||||
|
<MenuItem
|
||||||
|
Header="{locale:Locale SettingsTabGraphicsAspectRatio32x9}"
|
||||||
|
Command="{Binding SetAspectRatio}"
|
||||||
|
CommandParameter="{x:Static config:AspectRatio.Fixed32x9}"/>
|
||||||
|
<MenuItem
|
||||||
|
Header="{locale:Locale SettingsTabGraphicsAspectRatioStretch}"
|
||||||
|
Command="{Binding SetAspectRatio}"
|
||||||
|
CommandParameter="{x:Static config:AspectRatio.Stretched}"/>
|
||||||
|
</MenuFlyout>
|
||||||
|
</SplitButton.Flyout>
|
||||||
|
</SplitButton>
|
||||||
<Border
|
<Border
|
||||||
Width="2"
|
Width="2"
|
||||||
Height="12"
|
Height="12"
|
||||||
@@ -138,6 +177,7 @@
|
|||||||
Content="{Binding VolumeStatusText}"
|
Content="{Binding VolumeStatusText}"
|
||||||
IsChecked="{Binding VolumeMuted}"
|
IsChecked="{Binding VolumeMuted}"
|
||||||
IsVisible="{Binding !ShowLoadProgress}"
|
IsVisible="{Binding !ShowLoadProgress}"
|
||||||
|
PointerWheelChanged="VolumeStatus_OnPointerWheelChanged"
|
||||||
Background="Transparent"
|
Background="Transparent"
|
||||||
BorderThickness="0"
|
BorderThickness="0"
|
||||||
CornerRadius="0">
|
CornerRadius="0">
|
||||||
@@ -154,7 +194,7 @@
|
|||||||
<ToggleSplitButton.Flyout>
|
<ToggleSplitButton.Flyout>
|
||||||
<Flyout Placement="Bottom" ShowMode="TransientWithDismissOnPointerMoveAway">
|
<Flyout Placement="Bottom" ShowMode="TransientWithDismissOnPointerMoveAway">
|
||||||
<Grid Margin="0">
|
<Grid Margin="0">
|
||||||
<Slider
|
<controls:SliderScroll
|
||||||
MaxHeight="40"
|
MaxHeight="40"
|
||||||
Width="150"
|
Width="150"
|
||||||
Margin="0"
|
Margin="0"
|
||||||
|
@@ -43,10 +43,9 @@ namespace Ryujinx.Ava.UI.Views.Main
|
|||||||
ConfigurationState.Instance.System.EnableDockedMode.Value = !ConfigurationState.Instance.System.EnableDockedMode.Value;
|
ConfigurationState.Instance.System.EnableDockedMode.Value = !ConfigurationState.Instance.System.EnableDockedMode.Value;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void AspectRatioStatus_PointerReleased(object sender, PointerReleasedEventArgs e)
|
private void AspectRatioStatus_OnClick(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
AspectRatio aspectRatio = ConfigurationState.Instance.Graphics.AspectRatio.Value;
|
AspectRatio aspectRatio = ConfigurationState.Instance.Graphics.AspectRatio.Value;
|
||||||
|
|
||||||
ConfigurationState.Instance.Graphics.AspectRatio.Value = (int)aspectRatio + 1 > Enum.GetNames(typeof(AspectRatio)).Length - 1 ? AspectRatio.Fixed4x3 : aspectRatio + 1;
|
ConfigurationState.Instance.Graphics.AspectRatio.Value = (int)aspectRatio + 1 > Enum.GetNames(typeof(AspectRatio)).Length - 1 ? AspectRatio.Fixed4x3 : aspectRatio + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -54,5 +53,20 @@ namespace Ryujinx.Ava.UI.Views.Main
|
|||||||
{
|
{
|
||||||
Window.LoadApplications();
|
Window.LoadApplications();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void VolumeStatus_OnPointerWheelChanged(object sender, PointerWheelEventArgs e)
|
||||||
|
{
|
||||||
|
// Change the volume by 5% at a time
|
||||||
|
float newValue = Window.ViewModel.Volume + (float)e.Delta.Y * 0.05f;
|
||||||
|
|
||||||
|
Window.ViewModel.Volume = newValue switch
|
||||||
|
{
|
||||||
|
< 0 => 0,
|
||||||
|
> 1 => 1,
|
||||||
|
_ => newValue,
|
||||||
|
};
|
||||||
|
|
||||||
|
e.Handled = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -3,6 +3,7 @@
|
|||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
xmlns:controls="clr-namespace:Ryujinx.Ava.UI.Controls"
|
||||||
xmlns:ui="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia"
|
xmlns:ui="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia"
|
||||||
xmlns:helpers="clr-namespace:Ryujinx.Ava.UI.Helpers"
|
xmlns:helpers="clr-namespace:Ryujinx.Ava.UI.Helpers"
|
||||||
xmlns:locale="clr-namespace:Ryujinx.Ava.Common.Locale"
|
xmlns:locale="clr-namespace:Ryujinx.Ava.Common.Locale"
|
||||||
@@ -50,7 +51,7 @@
|
|||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
Text="{locale:Locale IconSize}"
|
Text="{locale:Locale IconSize}"
|
||||||
ToolTip.Tip="{locale:Locale IconSizeTooltip}" />
|
ToolTip.Tip="{locale:Locale IconSizeTooltip}" />
|
||||||
<Slider
|
<controls:SliderScroll
|
||||||
Width="150"
|
Width="150"
|
||||||
Height="35"
|
Height="35"
|
||||||
Margin="5,-10,5,0"
|
Margin="5,-10,5,0"
|
||||||
|
@@ -4,6 +4,7 @@
|
|||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
xmlns:controls="clr-namespace:Ryujinx.Ava.UI.Controls"
|
||||||
xmlns:ui="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia"
|
xmlns:ui="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia"
|
||||||
xmlns:locale="clr-namespace:Ryujinx.Ava.Common.Locale"
|
xmlns:locale="clr-namespace:Ryujinx.Ava.Common.Locale"
|
||||||
xmlns:viewModels="clr-namespace:Ryujinx.Ava.UI.ViewModels"
|
xmlns:viewModels="clr-namespace:Ryujinx.Ava.UI.ViewModels"
|
||||||
@@ -63,13 +64,13 @@
|
|||||||
Maximum="100" />
|
Maximum="100" />
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
<StackPanel Margin="10,0,0,0" Orientation="Horizontal">
|
<StackPanel Margin="10,0,0,0" Orientation="Horizontal">
|
||||||
<Slider Value="{Binding Volume}"
|
<controls:SliderScroll Value="{Binding Volume}"
|
||||||
Margin="250,0,0,0"
|
Margin="250,0,0,0"
|
||||||
ToolTip.Tip="{locale:Locale AudioVolumeTooltip}"
|
ToolTip.Tip="{locale:Locale AudioVolumeTooltip}"
|
||||||
Minimum="0"
|
Minimum="0"
|
||||||
Maximum="100"
|
Maximum="100"
|
||||||
SmallChange="5"
|
SmallChange="1"
|
||||||
TickFrequency="5"
|
TickFrequency="1"
|
||||||
IsSnapToTickEnabled="True"
|
IsSnapToTickEnabled="True"
|
||||||
LargeChange="10"
|
LargeChange="10"
|
||||||
Width="350" />
|
Width="350" />
|
||||||
|
@@ -4,6 +4,7 @@
|
|||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
xmlns:controls="clr-namespace:Ryujinx.Ava.UI.Controls"
|
||||||
xmlns:ui="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia"
|
xmlns:ui="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia"
|
||||||
xmlns:locale="clr-namespace:Ryujinx.Ava.Common.Locale"
|
xmlns:locale="clr-namespace:Ryujinx.Ava.Common.Locale"
|
||||||
xmlns:viewModels="clr-namespace:Ryujinx.Ava.UI.ViewModels"
|
xmlns:viewModels="clr-namespace:Ryujinx.Ava.UI.ViewModels"
|
||||||
@@ -73,6 +74,7 @@
|
|||||||
<TextBlock Text="{locale:Locale SettingsEnableMacroHLE}" />
|
<TextBlock Text="{locale:Locale SettingsEnableMacroHLE}" />
|
||||||
</CheckBox>
|
</CheckBox>
|
||||||
<CheckBox IsChecked="{Binding EnableColorSpacePassthrough}"
|
<CheckBox IsChecked="{Binding EnableColorSpacePassthrough}"
|
||||||
|
IsVisible="{Binding ColorSpacePassthroughAvailable}"
|
||||||
ToolTip.Tip="{locale:Locale SettingsEnableColorSpacePassthroughTooltip}">
|
ToolTip.Tip="{locale:Locale SettingsEnableColorSpacePassthroughTooltip}">
|
||||||
<TextBlock Text="{locale:Locale SettingsEnableColorSpacePassthrough}" />
|
<TextBlock Text="{locale:Locale SettingsEnableColorSpacePassthrough}" />
|
||||||
</CheckBox>
|
</CheckBox>
|
||||||
@@ -172,7 +174,7 @@
|
|||||||
<TextBlock Text="FSR" />
|
<TextBlock Text="FSR" />
|
||||||
</ComboBoxItem>
|
</ComboBoxItem>
|
||||||
</ComboBox>
|
</ComboBox>
|
||||||
<Slider Value="{Binding ScalingFilterLevel}"
|
<controls:SliderScroll Value="{Binding ScalingFilterLevel}"
|
||||||
ToolTip.Tip="{locale:Locale GraphicsScalingFilterLevelTooltip}"
|
ToolTip.Tip="{locale:Locale GraphicsScalingFilterLevelTooltip}"
|
||||||
MinWidth="150"
|
MinWidth="150"
|
||||||
Margin="10,-3,0,0"
|
Margin="10,-3,0,0"
|
||||||
|
@@ -265,33 +265,47 @@ namespace Ryujinx.Ava.UI.Windows
|
|||||||
|
|
||||||
private void CheckLaunchState()
|
private void CheckLaunchState()
|
||||||
{
|
{
|
||||||
if (ShowKeyErrorOnLoad)
|
|
||||||
{
|
|
||||||
ShowKeyErrorOnLoad = false;
|
|
||||||
|
|
||||||
UserErrorDialog.ShowUserErrorDialog(UserError.NoKeys).Wait();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (OperatingSystem.IsLinux() && LinuxHelper.VmMaxMapCount < LinuxHelper.RecommendedVmMaxMapCount)
|
if (OperatingSystem.IsLinux() && LinuxHelper.VmMaxMapCount < LinuxHelper.RecommendedVmMaxMapCount)
|
||||||
{
|
{
|
||||||
Logger.Warning?.Print(LogClass.Application, $"The value of vm.max_map_count is lower than {LinuxHelper.RecommendedVmMaxMapCount}. ({LinuxHelper.VmMaxMapCount})");
|
Logger.Warning?.Print(LogClass.Application, $"The value of vm.max_map_count is lower than {LinuxHelper.RecommendedVmMaxMapCount}. ({LinuxHelper.VmMaxMapCount})");
|
||||||
|
|
||||||
if (LinuxHelper.PkExecPath is not null)
|
if (LinuxHelper.PkExecPath is not null)
|
||||||
{
|
{
|
||||||
ShowVmMaxMapCountDialog().Wait();
|
Dispatcher.UIThread.Post(async () =>
|
||||||
|
{
|
||||||
|
if (OperatingSystem.IsLinux())
|
||||||
|
{
|
||||||
|
await ShowVmMaxMapCountDialog();
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ShowVmMaxMapCountWarning().Wait();
|
Dispatcher.UIThread.Post(async () =>
|
||||||
|
{
|
||||||
|
if (OperatingSystem.IsLinux())
|
||||||
|
{
|
||||||
|
await ShowVmMaxMapCountWarning();
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!ShowKeyErrorOnLoad)
|
||||||
|
{
|
||||||
if (_deferLoad)
|
if (_deferLoad)
|
||||||
{
|
{
|
||||||
_deferLoad = false;
|
_deferLoad = false;
|
||||||
|
|
||||||
ViewModel.LoadApplication(_launchPath, _startFullscreen).Wait();
|
ViewModel.LoadApplication(_launchPath, _startFullscreen).Wait();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ShowKeyErrorOnLoad = false;
|
||||||
|
|
||||||
|
Dispatcher.UIThread.Post(async () => await UserErrorDialog.ShowUserErrorDialog(UserError.NoKeys));
|
||||||
|
}
|
||||||
|
|
||||||
if (ConfigurationState.Instance.CheckUpdatesOnStart.Value && Updater.CanUpdate(false))
|
if (ConfigurationState.Instance.CheckUpdatesOnStart.Value && Updater.CanUpdate(false))
|
||||||
{
|
{
|
||||||
|
@@ -192,7 +192,7 @@ namespace Ryujinx.Common.Collections
|
|||||||
{
|
{
|
||||||
if (start.CompareTo(overlap.End) < 0)
|
if (start.CompareTo(overlap.End) < 0)
|
||||||
{
|
{
|
||||||
if (overlaps.Length >= overlapCount)
|
if (overlaps.Length <= overlapCount)
|
||||||
{
|
{
|
||||||
Array.Resize(ref overlaps, overlapCount + ArrayGrowthSize);
|
Array.Resize(ref overlaps, overlapCount + ArrayGrowthSize);
|
||||||
}
|
}
|
||||||
|
@@ -48,7 +48,7 @@ namespace Ryujinx.Common.Configuration
|
|||||||
string appDataPath;
|
string appDataPath;
|
||||||
if (OperatingSystem.IsMacOS())
|
if (OperatingSystem.IsMacOS())
|
||||||
{
|
{
|
||||||
appDataPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Personal), "Library", "Application Support");
|
appDataPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), "Library", "Application Support");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@@ -3,5 +3,6 @@
|
|||||||
public enum MultiplayerMode
|
public enum MultiplayerMode
|
||||||
{
|
{
|
||||||
Disabled,
|
Disabled,
|
||||||
|
LdnMitm,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -756,6 +756,18 @@ namespace Ryujinx.Common.Memory
|
|||||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public struct Array96<T> : IArray<T> where T : unmanaged
|
||||||
|
{
|
||||||
|
T _e0;
|
||||||
|
Array64<T> _other;
|
||||||
|
Array31<T> _other2;
|
||||||
|
public readonly int Length => 96;
|
||||||
|
public ref T this[int index] => ref AsSpan()[index];
|
||||||
|
|
||||||
|
[Pure]
|
||||||
|
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||||
|
}
|
||||||
|
|
||||||
public struct Array127<T> : IArray<T> where T : unmanaged
|
public struct Array127<T> : IArray<T> where T : unmanaged
|
||||||
{
|
{
|
||||||
T _e0;
|
T _e0;
|
||||||
|
@@ -5,7 +5,7 @@ namespace Ryujinx.Common
|
|||||||
{
|
{
|
||||||
public class ReactiveObject<T>
|
public class ReactiveObject<T>
|
||||||
{
|
{
|
||||||
private readonly ReaderWriterLock _readerWriterLock = new();
|
private readonly ReaderWriterLockSlim _readerWriterLock = new();
|
||||||
private bool _isInitialized;
|
private bool _isInitialized;
|
||||||
private T _value;
|
private T _value;
|
||||||
|
|
||||||
@@ -15,15 +15,15 @@ namespace Ryujinx.Common
|
|||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
_readerWriterLock.AcquireReaderLock(Timeout.Infinite);
|
_readerWriterLock.EnterReadLock();
|
||||||
T value = _value;
|
T value = _value;
|
||||||
_readerWriterLock.ReleaseReaderLock();
|
_readerWriterLock.ExitReadLock();
|
||||||
|
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
_readerWriterLock.AcquireWriterLock(Timeout.Infinite);
|
_readerWriterLock.EnterWriteLock();
|
||||||
|
|
||||||
T oldValue = _value;
|
T oldValue = _value;
|
||||||
|
|
||||||
@@ -32,7 +32,7 @@ namespace Ryujinx.Common
|
|||||||
_isInitialized = true;
|
_isInitialized = true;
|
||||||
_value = value;
|
_value = value;
|
||||||
|
|
||||||
_readerWriterLock.ReleaseWriterLock();
|
_readerWriterLock.ExitWriteLock();
|
||||||
|
|
||||||
if (!oldIsInitialized || oldValue == null || !oldValue.Equals(_value))
|
if (!oldIsInitialized || oldValue == null || !oldValue.Equals(_value))
|
||||||
{
|
{
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net7.0</TargetFramework>
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||||
<DefineConstants Condition=" '$(ExtraDefineConstants)' != '' ">$(DefineConstants);$(ExtraDefineConstants)</DefineConstants>
|
<DefineConstants Condition=" '$(ExtraDefineConstants)' != '' ">$(DefineConstants);$(ExtraDefineConstants)</DefineConstants>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
@@ -74,5 +74,10 @@ namespace Ryujinx.Common.Utilities
|
|||||||
{
|
{
|
||||||
return ConvertIpv4Address(IPAddress.Parse(ipAddress));
|
return ConvertIpv4Address(IPAddress.Parse(ipAddress));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static IPAddress ConvertUint(uint ipAddress)
|
||||||
|
{
|
||||||
|
return new IPAddress(new byte[] { (byte)((ipAddress >> 24) & 0xFF), (byte)((ipAddress >> 16) & 0xFF), (byte)((ipAddress >> 8) & 0xFF), (byte)(ipAddress & 0xFF) });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,9 +1,11 @@
|
|||||||
using Ryujinx.Cpu.AppleHv.Arm;
|
using Ryujinx.Cpu.AppleHv.Arm;
|
||||||
using Ryujinx.Memory;
|
using Ryujinx.Memory;
|
||||||
using System;
|
using System;
|
||||||
|
using System.Runtime.Versioning;
|
||||||
|
|
||||||
namespace Ryujinx.Cpu.AppleHv
|
namespace Ryujinx.Cpu.AppleHv
|
||||||
{
|
{
|
||||||
|
[SupportedOSPlatform("macos")]
|
||||||
class HvAddressSpace : IDisposable
|
class HvAddressSpace : IDisposable
|
||||||
{
|
{
|
||||||
private const ulong KernelRegionBase = unchecked((ulong)-(1L << 39));
|
private const ulong KernelRegionBase = unchecked((ulong)-(1L << 39));
|
||||||
|
@@ -2,10 +2,12 @@ using Ryujinx.Cpu.AppleHv.Arm;
|
|||||||
using System;
|
using System;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
using System.Runtime.Versioning;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
|
|
||||||
namespace Ryujinx.Cpu.AppleHv
|
namespace Ryujinx.Cpu.AppleHv
|
||||||
{
|
{
|
||||||
|
[SupportedOSPlatform("macos")]
|
||||||
class HvAddressSpaceRange : IDisposable
|
class HvAddressSpaceRange : IDisposable
|
||||||
{
|
{
|
||||||
private const ulong AllocationGranule = 1UL << 14;
|
private const ulong AllocationGranule = 1UL << 14;
|
||||||
|
@@ -1,5 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
using System.Runtime.Versioning;
|
||||||
|
|
||||||
namespace Ryujinx.Cpu.AppleHv
|
namespace Ryujinx.Cpu.AppleHv
|
||||||
{
|
{
|
||||||
@@ -12,10 +13,18 @@ namespace Ryujinx.Cpu.AppleHv
|
|||||||
#pragma warning restore CS0649
|
#pragma warning restore CS0649
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum HvExitReason : uint
|
||||||
|
{
|
||||||
|
Canceled,
|
||||||
|
Exception,
|
||||||
|
VTimerActivated,
|
||||||
|
Unknown,
|
||||||
|
}
|
||||||
|
|
||||||
struct HvVcpuExit
|
struct HvVcpuExit
|
||||||
{
|
{
|
||||||
#pragma warning disable CS0649 // Field is never assigned to
|
#pragma warning disable CS0649 // Field is never assigned to
|
||||||
public uint Reason;
|
public HvExitReason Reason;
|
||||||
public HvVcpuExitException Exception;
|
public HvVcpuExitException Exception;
|
||||||
#pragma warning restore CS0649
|
#pragma warning restore CS0649
|
||||||
}
|
}
|
||||||
@@ -255,6 +264,7 @@ namespace Ryujinx.Cpu.AppleHv
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[SupportedOSPlatform("macos")]
|
||||||
static partial class HvApi
|
static partial class HvApi
|
||||||
{
|
{
|
||||||
public const string LibraryName = "/System/Library/Frameworks/Hypervisor.framework/Hypervisor";
|
public const string LibraryName = "/System/Library/Frameworks/Hypervisor.framework/Hypervisor";
|
||||||
|
62
src/Ryujinx.Cpu/AppleHv/HvCodePatcher.cs
Normal file
62
src/Ryujinx.Cpu/AppleHv/HvCodePatcher.cs
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
using System;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using System.Runtime.Intrinsics;
|
||||||
|
|
||||||
|
namespace Ryujinx.Cpu.AppleHv
|
||||||
|
{
|
||||||
|
static class HvCodePatcher
|
||||||
|
{
|
||||||
|
private const uint XMask = 0x3f808000u;
|
||||||
|
private const uint XValue = 0x8000000u;
|
||||||
|
|
||||||
|
private const uint ZrIndex = 31u;
|
||||||
|
|
||||||
|
public static void RewriteUnorderedExclusiveInstructions(Span<byte> code)
|
||||||
|
{
|
||||||
|
Span<uint> codeUint = MemoryMarshal.Cast<byte, uint>(code);
|
||||||
|
Span<Vector128<uint>> codeVector = MemoryMarshal.Cast<byte, Vector128<uint>>(code);
|
||||||
|
|
||||||
|
Vector128<uint> mask = Vector128.Create(XMask);
|
||||||
|
Vector128<uint> value = Vector128.Create(XValue);
|
||||||
|
|
||||||
|
for (int index = 0; index < codeVector.Length; index++)
|
||||||
|
{
|
||||||
|
Vector128<uint> v = codeVector[index];
|
||||||
|
|
||||||
|
if (Vector128.EqualsAny(Vector128.BitwiseAnd(v, mask), value))
|
||||||
|
{
|
||||||
|
int baseIndex = index * 4;
|
||||||
|
|
||||||
|
for (int instIndex = baseIndex; instIndex < baseIndex + 4; instIndex++)
|
||||||
|
{
|
||||||
|
ref uint inst = ref codeUint[instIndex];
|
||||||
|
|
||||||
|
if ((inst & XMask) != XValue)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isPair = (inst & (1u << 21)) != 0;
|
||||||
|
bool isLoad = (inst & (1u << 22)) != 0;
|
||||||
|
|
||||||
|
uint rt2 = (inst >> 10) & 0x1fu;
|
||||||
|
uint rs = (inst >> 16) & 0x1fu;
|
||||||
|
|
||||||
|
if (isLoad && rs != ZrIndex)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isPair && rt2 != ZrIndex)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the ordered flag.
|
||||||
|
inst |= 1u << 15;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -1,7 +1,9 @@
|
|||||||
using ARMeilleure.Memory;
|
using ARMeilleure.Memory;
|
||||||
|
using System.Runtime.Versioning;
|
||||||
|
|
||||||
namespace Ryujinx.Cpu.AppleHv
|
namespace Ryujinx.Cpu.AppleHv
|
||||||
{
|
{
|
||||||
|
[SupportedOSPlatform("macos")]
|
||||||
class HvCpuContext : ICpuContext
|
class HvCpuContext : ICpuContext
|
||||||
{
|
{
|
||||||
private readonly ITickSource _tickSource;
|
private readonly ITickSource _tickSource;
|
||||||
|
@@ -1,7 +1,9 @@
|
|||||||
using ARMeilleure.Memory;
|
using ARMeilleure.Memory;
|
||||||
|
using System.Runtime.Versioning;
|
||||||
|
|
||||||
namespace Ryujinx.Cpu.AppleHv
|
namespace Ryujinx.Cpu.AppleHv
|
||||||
{
|
{
|
||||||
|
[SupportedOSPlatform("macos")]
|
||||||
public class HvEngine : ICpuEngine
|
public class HvEngine : ICpuEngine
|
||||||
{
|
{
|
||||||
private readonly ITickSource _tickSource;
|
private readonly ITickSource _tickSource;
|
||||||
|
@@ -2,9 +2,12 @@ using ARMeilleure.State;
|
|||||||
using Ryujinx.Cpu.AppleHv.Arm;
|
using Ryujinx.Cpu.AppleHv.Arm;
|
||||||
using Ryujinx.Memory.Tracking;
|
using Ryujinx.Memory.Tracking;
|
||||||
using System;
|
using System;
|
||||||
|
using System.Runtime.Versioning;
|
||||||
|
using System.Threading;
|
||||||
|
|
||||||
namespace Ryujinx.Cpu.AppleHv
|
namespace Ryujinx.Cpu.AppleHv
|
||||||
{
|
{
|
||||||
|
[SupportedOSPlatform("macos")]
|
||||||
class HvExecutionContext : IExecutionContext
|
class HvExecutionContext : IExecutionContext
|
||||||
{
|
{
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
@@ -67,6 +70,8 @@ namespace Ryujinx.Cpu.AppleHv
|
|||||||
|
|
||||||
private readonly ExceptionCallbacks _exceptionCallbacks;
|
private readonly ExceptionCallbacks _exceptionCallbacks;
|
||||||
|
|
||||||
|
private int _interruptRequested;
|
||||||
|
|
||||||
public HvExecutionContext(ICounter counter, ExceptionCallbacks exceptionCallbacks)
|
public HvExecutionContext(ICounter counter, ExceptionCallbacks exceptionCallbacks)
|
||||||
{
|
{
|
||||||
_counter = counter;
|
_counter = counter;
|
||||||
@@ -111,7 +116,15 @@ namespace Ryujinx.Cpu.AppleHv
|
|||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public void RequestInterrupt()
|
public void RequestInterrupt()
|
||||||
{
|
{
|
||||||
_impl.RequestInterrupt();
|
if (Interlocked.Exchange(ref _interruptRequested, 1) == 0 && _impl is HvExecutionContextVcpu impl)
|
||||||
|
{
|
||||||
|
impl.RequestInterrupt();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool GetAndClearInterruptRequested()
|
||||||
|
{
|
||||||
|
return Interlocked.Exchange(ref _interruptRequested, 0) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
@@ -131,9 +144,9 @@ namespace Ryujinx.Cpu.AppleHv
|
|||||||
{
|
{
|
||||||
HvApi.hv_vcpu_run(vcpu.Handle).ThrowOnError();
|
HvApi.hv_vcpu_run(vcpu.Handle).ThrowOnError();
|
||||||
|
|
||||||
uint reason = vcpu.ExitInfo->Reason;
|
HvExitReason reason = vcpu.ExitInfo->Reason;
|
||||||
|
|
||||||
if (reason == 1)
|
if (reason == HvExitReason.Exception)
|
||||||
{
|
{
|
||||||
uint hvEsr = (uint)vcpu.ExitInfo->Exception.Syndrome;
|
uint hvEsr = (uint)vcpu.ExitInfo->Exception.Syndrome;
|
||||||
ExceptionClass hvEc = (ExceptionClass)(hvEsr >> 26);
|
ExceptionClass hvEc = (ExceptionClass)(hvEsr >> 26);
|
||||||
@@ -146,14 +159,22 @@ namespace Ryujinx.Cpu.AppleHv
|
|||||||
address = SynchronousException(memoryManager, ref vcpu);
|
address = SynchronousException(memoryManager, ref vcpu);
|
||||||
HvApi.hv_vcpu_set_reg(vcpu.Handle, HvReg.PC, address).ThrowOnError();
|
HvApi.hv_vcpu_set_reg(vcpu.Handle, HvReg.PC, address).ThrowOnError();
|
||||||
}
|
}
|
||||||
else if (reason == 0)
|
else if (reason == HvExitReason.Canceled || reason == HvExitReason.VTimerActivated)
|
||||||
{
|
{
|
||||||
if (_impl.GetAndClearInterruptRequested())
|
if (GetAndClearInterruptRequested())
|
||||||
{
|
{
|
||||||
ReturnToPool(vcpu);
|
ReturnToPool(vcpu);
|
||||||
InterruptHandler();
|
InterruptHandler();
|
||||||
vcpu = RentFromPool(memoryManager.AddressSpace, vcpu);
|
vcpu = RentFromPool(memoryManager.AddressSpace, vcpu);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (reason == HvExitReason.VTimerActivated)
|
||||||
|
{
|
||||||
|
vcpu.EnableAndUpdateVTimer();
|
||||||
|
|
||||||
|
// Unmask VTimer interrupts.
|
||||||
|
HvApi.hv_vcpu_set_vtimer_mask(vcpu.Handle, false).ThrowOnError();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@@ -46,14 +46,5 @@ namespace Ryujinx.Cpu.AppleHv
|
|||||||
{
|
{
|
||||||
_v[index] = value;
|
_v[index] = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void RequestInterrupt()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool GetAndClearInterruptRequested()
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -2,10 +2,11 @@ using ARMeilleure.State;
|
|||||||
using Ryujinx.Memory;
|
using Ryujinx.Memory;
|
||||||
using System;
|
using System;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using System.Threading;
|
using System.Runtime.Versioning;
|
||||||
|
|
||||||
namespace Ryujinx.Cpu.AppleHv
|
namespace Ryujinx.Cpu.AppleHv
|
||||||
{
|
{
|
||||||
|
[SupportedOSPlatform("macos")]
|
||||||
class HvExecutionContextVcpu : IHvExecutionContext
|
class HvExecutionContextVcpu : IHvExecutionContext
|
||||||
{
|
{
|
||||||
private static readonly MemoryBlock _setSimdFpRegFuncMem;
|
private static readonly MemoryBlock _setSimdFpRegFuncMem;
|
||||||
@@ -135,7 +136,6 @@ namespace Ryujinx.Cpu.AppleHv
|
|||||||
}
|
}
|
||||||
|
|
||||||
private readonly ulong _vcpu;
|
private readonly ulong _vcpu;
|
||||||
private int _interruptRequested;
|
|
||||||
|
|
||||||
public HvExecutionContextVcpu(ulong vcpu)
|
public HvExecutionContextVcpu(ulong vcpu)
|
||||||
{
|
{
|
||||||
@@ -180,17 +180,9 @@ namespace Ryujinx.Cpu.AppleHv
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void RequestInterrupt()
|
public void RequestInterrupt()
|
||||||
{
|
|
||||||
if (Interlocked.Exchange(ref _interruptRequested, 1) == 0)
|
|
||||||
{
|
{
|
||||||
ulong vcpu = _vcpu;
|
ulong vcpu = _vcpu;
|
||||||
HvApi.hv_vcpus_exit(ref vcpu, 1);
|
HvApi.hv_vcpus_exit(ref vcpu, 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool GetAndClearInterruptRequested()
|
|
||||||
{
|
|
||||||
return Interlocked.Exchange(ref _interruptRequested, 0) != 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@@ -1,8 +1,10 @@
|
|||||||
using Ryujinx.Memory;
|
using Ryujinx.Memory;
|
||||||
using System;
|
using System;
|
||||||
|
using System.Runtime.Versioning;
|
||||||
|
|
||||||
namespace Ryujinx.Cpu.AppleHv
|
namespace Ryujinx.Cpu.AppleHv
|
||||||
{
|
{
|
||||||
|
[SupportedOSPlatform("macos")]
|
||||||
readonly struct HvMemoryBlockAllocation : IDisposable
|
readonly struct HvMemoryBlockAllocation : IDisposable
|
||||||
{
|
{
|
||||||
private readonly HvMemoryBlockAllocator _owner;
|
private readonly HvMemoryBlockAllocator _owner;
|
||||||
|
@@ -1,7 +1,9 @@
|
|||||||
using Ryujinx.Memory;
|
using Ryujinx.Memory;
|
||||||
|
using System.Runtime.Versioning;
|
||||||
|
|
||||||
namespace Ryujinx.Cpu.AppleHv
|
namespace Ryujinx.Cpu.AppleHv
|
||||||
{
|
{
|
||||||
|
[SupportedOSPlatform("macos")]
|
||||||
class HvMemoryBlockAllocator : PrivateMemoryAllocatorImpl<HvMemoryBlockAllocator.Block>
|
class HvMemoryBlockAllocator : PrivateMemoryAllocatorImpl<HvMemoryBlockAllocator.Block>
|
||||||
{
|
{
|
||||||
public class Block : PrivateMemoryAllocator.Block
|
public class Block : PrivateMemoryAllocator.Block
|
||||||
|
@@ -7,6 +7,7 @@ using System.Collections.Generic;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
using System.Runtime.Versioning;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
|
|
||||||
namespace Ryujinx.Cpu.AppleHv
|
namespace Ryujinx.Cpu.AppleHv
|
||||||
@@ -14,6 +15,7 @@ namespace Ryujinx.Cpu.AppleHv
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents a CPU memory manager which maps guest virtual memory directly onto the Hypervisor page table.
|
/// Represents a CPU memory manager which maps guest virtual memory directly onto the Hypervisor page table.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
[SupportedOSPlatform("macos")]
|
||||||
public class HvMemoryManager : MemoryManagerBase, IMemoryManager, IVirtualMemoryManagerTracked, IWritableBlock
|
public class HvMemoryManager : MemoryManagerBase, IMemoryManager, IVirtualMemoryManagerTracked, IWritableBlock
|
||||||
{
|
{
|
||||||
public const int PageBits = 12;
|
public const int PageBits = 12;
|
||||||
@@ -126,21 +128,6 @@ namespace Ryujinx.Cpu.AppleHv
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma warning disable IDE0051 // Remove unused private member
|
|
||||||
/// <summary>
|
|
||||||
/// Ensures the combination of virtual address and size is part of the addressable space and fully mapped.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="va">Virtual address of the range</param>
|
|
||||||
/// <param name="size">Size of the range in bytes</param>
|
|
||||||
private void AssertMapped(ulong va, ulong size)
|
|
||||||
{
|
|
||||||
if (!ValidateAddressAndSize(va, size) || !IsRangeMappedImpl(va, size))
|
|
||||||
{
|
|
||||||
throw new InvalidMemoryRegionException($"Not mapped: va=0x{va:X16}, size=0x{size:X16}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#pragma warning restore IDE0051
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public void Map(ulong va, ulong pa, ulong size, MemoryMapFlags flags)
|
public void Map(ulong va, ulong pa, ulong size, MemoryMapFlags flags)
|
||||||
{
|
{
|
||||||
@@ -734,6 +721,24 @@ namespace Ryujinx.Cpu.AppleHv
|
|||||||
return (int)(vaSpan / PageSize);
|
return (int)(vaSpan / PageSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public void Reprotect(ulong va, ulong size, MemoryPermission protection)
|
||||||
|
{
|
||||||
|
if (protection.HasFlag(MemoryPermission.Execute))
|
||||||
|
{
|
||||||
|
// Some applications use unordered exclusive memory access instructions
|
||||||
|
// where it is not valid to do so, leading to memory re-ordering that
|
||||||
|
// makes the code behave incorrectly on some CPUs.
|
||||||
|
// To work around this, we force all such accesses to be ordered.
|
||||||
|
|
||||||
|
using WritableRegion writableRegion = GetWritableRegion(va, (int)size);
|
||||||
|
|
||||||
|
HvCodePatcher.RewriteUnorderedExclusiveInstructions(writableRegion.Memory.Span);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public void TrackingReprotect(ulong va, ulong size, MemoryPermission protection)
|
public void TrackingReprotect(ulong va, ulong size, MemoryPermission protection)
|
||||||
{
|
{
|
||||||
|
@@ -1,7 +1,15 @@
|
|||||||
|
using System.Diagnostics;
|
||||||
|
using System.Runtime.Versioning;
|
||||||
|
|
||||||
namespace Ryujinx.Cpu.AppleHv
|
namespace Ryujinx.Cpu.AppleHv
|
||||||
{
|
{
|
||||||
|
[SupportedOSPlatform("macos")]
|
||||||
unsafe class HvVcpu
|
unsafe class HvVcpu
|
||||||
{
|
{
|
||||||
|
private const ulong InterruptIntervalNs = 16 * 1000000; // 16 ms
|
||||||
|
|
||||||
|
private static ulong _interruptTimeDeltaTicks = 0;
|
||||||
|
|
||||||
public readonly ulong Handle;
|
public readonly ulong Handle;
|
||||||
public readonly HvVcpuExit* ExitInfo;
|
public readonly HvVcpuExit* ExitInfo;
|
||||||
public readonly IHvExecutionContext ShadowContext;
|
public readonly IHvExecutionContext ShadowContext;
|
||||||
@@ -21,5 +29,28 @@ namespace Ryujinx.Cpu.AppleHv
|
|||||||
NativeContext = nativeContext;
|
NativeContext = nativeContext;
|
||||||
IsEphemeral = isEphemeral;
|
IsEphemeral = isEphemeral;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void EnableAndUpdateVTimer()
|
||||||
|
{
|
||||||
|
// We need to ensure interrupts will be serviced,
|
||||||
|
// and for that we set up the VTime to trigger an interrupt at fixed intervals.
|
||||||
|
|
||||||
|
ulong deltaTicks = _interruptTimeDeltaTicks;
|
||||||
|
|
||||||
|
if (deltaTicks == 0)
|
||||||
|
{
|
||||||
|
// Calculate our time delta in ticks based on the current clock frequency.
|
||||||
|
|
||||||
|
int result = TimeApi.mach_timebase_info(out var timeBaseInfo);
|
||||||
|
|
||||||
|
Debug.Assert(result == 0);
|
||||||
|
|
||||||
|
deltaTicks = ((InterruptIntervalNs * timeBaseInfo.Denom) + (timeBaseInfo.Numer - 1)) / timeBaseInfo.Numer;
|
||||||
|
_interruptTimeDeltaTicks = deltaTicks;
|
||||||
|
}
|
||||||
|
|
||||||
|
HvApi.hv_vcpu_set_sys_reg(Handle, HvSysReg.CNTV_CTL_EL0, 1).ThrowOnError();
|
||||||
|
HvApi.hv_vcpu_set_sys_reg(Handle, HvSysReg.CNTV_CVAL_EL0, TimeApi.mach_absolute_time() + deltaTicks).ThrowOnError();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,8 +1,10 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Runtime.Versioning;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
|
|
||||||
namespace Ryujinx.Cpu.AppleHv
|
namespace Ryujinx.Cpu.AppleHv
|
||||||
{
|
{
|
||||||
|
[SupportedOSPlatform("macos")]
|
||||||
class HvVcpuPool
|
class HvVcpuPool
|
||||||
{
|
{
|
||||||
// Since there's a limit on the number of VCPUs we can create,
|
// Since there's a limit on the number of VCPUs we can create,
|
||||||
@@ -81,6 +83,8 @@ namespace Ryujinx.Cpu.AppleHv
|
|||||||
|
|
||||||
HvVcpu vcpu = new(vcpuHandle, exitInfo, shadowContext, nativeContext, isEphemeral);
|
HvVcpu vcpu = new(vcpuHandle, exitInfo, shadowContext, nativeContext, isEphemeral);
|
||||||
|
|
||||||
|
vcpu.EnableAndUpdateVTimer();
|
||||||
|
|
||||||
return vcpu;
|
return vcpu;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1,8 +1,10 @@
|
|||||||
using Ryujinx.Memory;
|
using Ryujinx.Memory;
|
||||||
using System;
|
using System;
|
||||||
|
using System.Runtime.Versioning;
|
||||||
|
|
||||||
namespace Ryujinx.Cpu.AppleHv
|
namespace Ryujinx.Cpu.AppleHv
|
||||||
{
|
{
|
||||||
|
[SupportedOSPlatform("macos")]
|
||||||
static class HvVm
|
static class HvVm
|
||||||
{
|
{
|
||||||
// This alignment allows us to use larger blocks on the page table.
|
// This alignment allows us to use larger blocks on the page table.
|
||||||
|
@@ -2,7 +2,7 @@ using ARMeilleure.State;
|
|||||||
|
|
||||||
namespace Ryujinx.Cpu.AppleHv
|
namespace Ryujinx.Cpu.AppleHv
|
||||||
{
|
{
|
||||||
public interface IHvExecutionContext
|
interface IHvExecutionContext
|
||||||
{
|
{
|
||||||
ulong Pc { get; set; }
|
ulong Pc { get; set; }
|
||||||
ulong ElrEl1 { get; set; }
|
ulong ElrEl1 { get; set; }
|
||||||
@@ -39,8 +39,5 @@ namespace Ryujinx.Cpu.AppleHv
|
|||||||
SetV(i, context.GetV(i));
|
SetV(i, context.GetV(i));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void RequestInterrupt();
|
|
||||||
bool GetAndClearInterruptRequested();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
21
src/Ryujinx.Cpu/AppleHv/TimeApi.cs
Normal file
21
src/Ryujinx.Cpu/AppleHv/TimeApi.cs
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using System.Runtime.Versioning;
|
||||||
|
|
||||||
|
namespace Ryujinx.Cpu.AppleHv
|
||||||
|
{
|
||||||
|
struct MachTimebaseInfo
|
||||||
|
{
|
||||||
|
public uint Numer;
|
||||||
|
public uint Denom;
|
||||||
|
}
|
||||||
|
|
||||||
|
[SupportedOSPlatform("macos")]
|
||||||
|
static partial class TimeApi
|
||||||
|
{
|
||||||
|
[LibraryImport("libc", SetLastError = true)]
|
||||||
|
public static partial ulong mach_absolute_time();
|
||||||
|
|
||||||
|
[LibraryImport("libc", SetLastError = true)]
|
||||||
|
public static partial int mach_timebase_info(out MachTimebaseInfo info);
|
||||||
|
}
|
||||||
|
}
|
@@ -575,24 +575,17 @@ namespace Ryujinx.Cpu.Jit
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma warning disable IDE0051 // Remove unused private member
|
|
||||||
private ulong GetPhysicalAddress(ulong va)
|
|
||||||
{
|
|
||||||
// We return -1L if the virtual address is invalid or unmapped.
|
|
||||||
if (!ValidateAddress(va) || !IsMapped(va))
|
|
||||||
{
|
|
||||||
return ulong.MaxValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
return GetPhysicalAddressInternal(va);
|
|
||||||
}
|
|
||||||
#pragma warning restore IDE0051
|
|
||||||
|
|
||||||
private ulong GetPhysicalAddressInternal(ulong va)
|
private ulong GetPhysicalAddressInternal(ulong va)
|
||||||
{
|
{
|
||||||
return PteToPa(_pageTable.Read<ulong>((va / PageSize) * PteSize) & ~(0xffffUL << 48)) + (va & PageMask);
|
return PteToPa(_pageTable.Read<ulong>((va / PageSize) * PteSize) & ~(0xffffUL << 48)) + (va & PageMask);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public void Reprotect(ulong va, ulong size, MemoryPermission protection)
|
||||||
|
{
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public void TrackingReprotect(ulong va, ulong size, MemoryPermission protection)
|
public void TrackingReprotect(ulong va, ulong size, MemoryPermission protection)
|
||||||
{
|
{
|
||||||
@@ -698,9 +691,5 @@ namespace Ryujinx.Cpu.Jit
|
|||||||
/// Disposes of resources used by the memory manager.
|
/// Disposes of resources used by the memory manager.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected override void Destroy() => _pageTable.Dispose();
|
protected override void Destroy() => _pageTable.Dispose();
|
||||||
|
|
||||||
#pragma warning disable IDE0051 // Remove unused private member
|
|
||||||
private static void ThrowInvalidMemoryRegionException(string message) => throw new InvalidMemoryRegionException(message);
|
|
||||||
#pragma warning restore IDE0051
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -615,6 +615,12 @@ namespace Ryujinx.Cpu.Jit
|
|||||||
return (int)(vaSpan / PageSize);
|
return (int)(vaSpan / PageSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public void Reprotect(ulong va, ulong size, MemoryPermission protection)
|
||||||
|
{
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public void TrackingReprotect(ulong va, ulong size, MemoryPermission protection)
|
public void TrackingReprotect(ulong va, ulong size, MemoryPermission protection)
|
||||||
{
|
{
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net7.0</TargetFramework>
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net7.0</TargetFramework>
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
@@ -38,6 +38,7 @@ namespace Ryujinx.Graphics.GAL
|
|||||||
public readonly bool SupportsShaderBallot;
|
public readonly bool SupportsShaderBallot;
|
||||||
public readonly bool SupportsShaderBarrierDivergence;
|
public readonly bool SupportsShaderBarrierDivergence;
|
||||||
public readonly bool SupportsShaderFloat64;
|
public readonly bool SupportsShaderFloat64;
|
||||||
|
public readonly bool SupportsTextureGatherOffsets;
|
||||||
public readonly bool SupportsTextureShadowLod;
|
public readonly bool SupportsTextureShadowLod;
|
||||||
public readonly bool SupportsVertexStoreAndAtomics;
|
public readonly bool SupportsVertexStoreAndAtomics;
|
||||||
public readonly bool SupportsViewportIndexVertexTessellation;
|
public readonly bool SupportsViewportIndexVertexTessellation;
|
||||||
@@ -92,6 +93,7 @@ namespace Ryujinx.Graphics.GAL
|
|||||||
bool supportsShaderBallot,
|
bool supportsShaderBallot,
|
||||||
bool supportsShaderBarrierDivergence,
|
bool supportsShaderBarrierDivergence,
|
||||||
bool supportsShaderFloat64,
|
bool supportsShaderFloat64,
|
||||||
|
bool supportsTextureGatherOffsets,
|
||||||
bool supportsTextureShadowLod,
|
bool supportsTextureShadowLod,
|
||||||
bool supportsVertexStoreAndAtomics,
|
bool supportsVertexStoreAndAtomics,
|
||||||
bool supportsViewportIndexVertexTessellation,
|
bool supportsViewportIndexVertexTessellation,
|
||||||
@@ -142,6 +144,7 @@ namespace Ryujinx.Graphics.GAL
|
|||||||
SupportsShaderBallot = supportsShaderBallot;
|
SupportsShaderBallot = supportsShaderBallot;
|
||||||
SupportsShaderBarrierDivergence = supportsShaderBarrierDivergence;
|
SupportsShaderBarrierDivergence = supportsShaderBarrierDivergence;
|
||||||
SupportsShaderFloat64 = supportsShaderFloat64;
|
SupportsShaderFloat64 = supportsShaderFloat64;
|
||||||
|
SupportsTextureGatherOffsets = supportsTextureGatherOffsets;
|
||||||
SupportsTextureShadowLod = supportsTextureShadowLod;
|
SupportsTextureShadowLod = supportsTextureShadowLod;
|
||||||
SupportsVertexStoreAndAtomics = supportsVertexStoreAndAtomics;
|
SupportsVertexStoreAndAtomics = supportsVertexStoreAndAtomics;
|
||||||
SupportsViewportIndexVertexTessellation = supportsViewportIndexVertexTessellation;
|
SupportsViewportIndexVertexTessellation = supportsViewportIndexVertexTessellation;
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net7.0</TargetFramework>
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
|
||||||
|
@@ -32,6 +32,11 @@ namespace Ryujinx.Graphics.Gpu.Engine
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public ref TState State => ref _state.State;
|
public ref TState State => ref _state.State;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Current shadow state.
|
||||||
|
/// </summary>
|
||||||
|
public ref TState ShadowState => ref _shadowState.State;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates a new instance of the device state, with shadow state.
|
/// Creates a new instance of the device state, with shadow state.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@@ -211,6 +211,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Dma
|
|||||||
int xCount = (int)_state.State.LineLengthIn;
|
int xCount = (int)_state.State.LineLengthIn;
|
||||||
int yCount = (int)_state.State.LineCount;
|
int yCount = (int)_state.State.LineCount;
|
||||||
|
|
||||||
|
_channel.TextureManager.RefreshModifiedTextures();
|
||||||
_3dEngine.CreatePendingSyncs();
|
_3dEngine.CreatePendingSyncs();
|
||||||
_3dEngine.FlushUboDirty();
|
_3dEngine.FlushUboDirty();
|
||||||
|
|
||||||
@@ -279,7 +280,11 @@ namespace Ryujinx.Graphics.Gpu.Engine.Dma
|
|||||||
bool completeSource = IsTextureCopyComplete(src, srcLinear, srcBpp, srcStride, xCount, yCount);
|
bool completeSource = IsTextureCopyComplete(src, srcLinear, srcBpp, srcStride, xCount, yCount);
|
||||||
bool completeDest = IsTextureCopyComplete(dst, dstLinear, dstBpp, dstStride, xCount, yCount);
|
bool completeDest = IsTextureCopyComplete(dst, dstLinear, dstBpp, dstStride, xCount, yCount);
|
||||||
|
|
||||||
if (completeSource && completeDest)
|
// Try to set the texture data directly,
|
||||||
|
// but only if we are doing a complete copy,
|
||||||
|
// and not for block linear to linear copies, since those are typically accessed from the CPU.
|
||||||
|
|
||||||
|
if (completeSource && completeDest && !(dstLinear && !srcLinear))
|
||||||
{
|
{
|
||||||
var target = memoryManager.Physical.TextureCache.FindTexture(
|
var target = memoryManager.Physical.TextureCache.FindTexture(
|
||||||
memoryManager,
|
memoryManager,
|
||||||
|
@@ -1,7 +1,10 @@
|
|||||||
using Ryujinx.Common.Logging;
|
using Ryujinx.Common.Logging;
|
||||||
|
using Ryujinx.Common.Memory;
|
||||||
using Ryujinx.Graphics.Device;
|
using Ryujinx.Graphics.Device;
|
||||||
using Ryujinx.Graphics.GAL;
|
using Ryujinx.Graphics.GAL;
|
||||||
using Ryujinx.Graphics.Gpu.Engine.GPFifo;
|
using Ryujinx.Graphics.Gpu.Engine.GPFifo;
|
||||||
|
using Ryujinx.Graphics.Gpu.Engine.Threed;
|
||||||
|
using Ryujinx.Graphics.Gpu.Engine.Types;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|
||||||
@@ -15,9 +18,18 @@ namespace Ryujinx.Graphics.Gpu.Engine.MME
|
|||||||
private const int ColorLayerCountOffset = 0x818;
|
private const int ColorLayerCountOffset = 0x818;
|
||||||
private const int ColorStructSize = 0x40;
|
private const int ColorStructSize = 0x40;
|
||||||
private const int ZetaLayerCountOffset = 0x1230;
|
private const int ZetaLayerCountOffset = 0x1230;
|
||||||
|
private const int UniformBufferBindVertexOffset = 0x2410;
|
||||||
|
private const int FirstVertexOffset = 0x1434;
|
||||||
|
|
||||||
private const int IndirectIndexedDataEntrySize = 0x14;
|
private const int IndirectIndexedDataEntrySize = 0x14;
|
||||||
|
|
||||||
|
private const int LogicOpOffset = 0x19c4;
|
||||||
|
private const int ShaderIdScratchOffset = 0x3470;
|
||||||
|
private const int ShaderAddressScratchOffset = 0x3488;
|
||||||
|
private const int UpdateConstantBufferAddressesBase = 0x34a8;
|
||||||
|
private const int UpdateConstantBufferSizesBase = 0x34bc;
|
||||||
|
private const int UpdateConstantBufferAddressCbu = 0x3460;
|
||||||
|
|
||||||
private readonly GPFifoProcessor _processor;
|
private readonly GPFifoProcessor _processor;
|
||||||
private readonly MacroHLEFunctionName _functionName;
|
private readonly MacroHLEFunctionName _functionName;
|
||||||
|
|
||||||
@@ -49,6 +61,9 @@ namespace Ryujinx.Graphics.Gpu.Engine.MME
|
|||||||
{
|
{
|
||||||
switch (_functionName)
|
switch (_functionName)
|
||||||
{
|
{
|
||||||
|
case MacroHLEFunctionName.BindShaderProgram:
|
||||||
|
BindShaderProgram(state, arg0);
|
||||||
|
break;
|
||||||
case MacroHLEFunctionName.ClearColor:
|
case MacroHLEFunctionName.ClearColor:
|
||||||
ClearColor(state, arg0);
|
ClearColor(state, arg0);
|
||||||
break;
|
break;
|
||||||
@@ -58,6 +73,9 @@ namespace Ryujinx.Graphics.Gpu.Engine.MME
|
|||||||
case MacroHLEFunctionName.DrawArraysInstanced:
|
case MacroHLEFunctionName.DrawArraysInstanced:
|
||||||
DrawArraysInstanced(state, arg0);
|
DrawArraysInstanced(state, arg0);
|
||||||
break;
|
break;
|
||||||
|
case MacroHLEFunctionName.DrawElements:
|
||||||
|
DrawElements(state, arg0);
|
||||||
|
break;
|
||||||
case MacroHLEFunctionName.DrawElementsInstanced:
|
case MacroHLEFunctionName.DrawElementsInstanced:
|
||||||
DrawElementsInstanced(state, arg0);
|
DrawElementsInstanced(state, arg0);
|
||||||
break;
|
break;
|
||||||
@@ -67,6 +85,21 @@ namespace Ryujinx.Graphics.Gpu.Engine.MME
|
|||||||
case MacroHLEFunctionName.MultiDrawElementsIndirectCount:
|
case MacroHLEFunctionName.MultiDrawElementsIndirectCount:
|
||||||
MultiDrawElementsIndirectCount(state, arg0);
|
MultiDrawElementsIndirectCount(state, arg0);
|
||||||
break;
|
break;
|
||||||
|
case MacroHLEFunctionName.UpdateBlendState:
|
||||||
|
UpdateBlendState(state, arg0);
|
||||||
|
break;
|
||||||
|
case MacroHLEFunctionName.UpdateColorMasks:
|
||||||
|
UpdateColorMasks(state, arg0);
|
||||||
|
break;
|
||||||
|
case MacroHLEFunctionName.UpdateUniformBufferState:
|
||||||
|
UpdateUniformBufferState(state, arg0);
|
||||||
|
break;
|
||||||
|
case MacroHLEFunctionName.UpdateUniformBufferStateCbu:
|
||||||
|
UpdateUniformBufferStateCbu(state, arg0);
|
||||||
|
break;
|
||||||
|
case MacroHLEFunctionName.UpdateUniformBufferStateCbuV2:
|
||||||
|
UpdateUniformBufferStateCbuV2(state, arg0);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
throw new NotImplementedException(_functionName.ToString());
|
throw new NotImplementedException(_functionName.ToString());
|
||||||
}
|
}
|
||||||
@@ -75,6 +108,149 @@ namespace Ryujinx.Graphics.Gpu.Engine.MME
|
|||||||
Fifo.Clear();
|
Fifo.Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Binds a shader program with the index in arg0.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="state">GPU state at the time of the call</param>
|
||||||
|
/// <param name="arg0">First argument of the call</param>
|
||||||
|
private void BindShaderProgram(IDeviceState state, int arg0)
|
||||||
|
{
|
||||||
|
int scratchOffset = ShaderIdScratchOffset + arg0 * 4;
|
||||||
|
|
||||||
|
int lastId = state.Read(scratchOffset);
|
||||||
|
int id = FetchParam().Word;
|
||||||
|
int offset = FetchParam().Word;
|
||||||
|
|
||||||
|
if (lastId == id)
|
||||||
|
{
|
||||||
|
FetchParam();
|
||||||
|
FetchParam();
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_processor.ThreedClass.SetShaderOffset(arg0, (uint)offset);
|
||||||
|
|
||||||
|
// Removes overflow on the method address into the increment portion.
|
||||||
|
// Present in the original macro.
|
||||||
|
int addrMask = unchecked((int)0xfffc0fff) << 2;
|
||||||
|
|
||||||
|
state.Write(scratchOffset & addrMask, id);
|
||||||
|
state.Write((ShaderAddressScratchOffset + arg0 * 4) & addrMask, offset);
|
||||||
|
|
||||||
|
int stage = FetchParam().Word;
|
||||||
|
uint cbAddress = (uint)FetchParam().Word;
|
||||||
|
|
||||||
|
_processor.ThreedClass.UpdateUniformBufferState(65536, cbAddress >> 24, cbAddress << 8);
|
||||||
|
|
||||||
|
int stageOffset = (stage & 0x7f) << 3;
|
||||||
|
|
||||||
|
state.Write((UniformBufferBindVertexOffset + stageOffset * 4) & addrMask, 17);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Updates uniform buffer state for update or bind.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="state">GPU state at the time of the call</param>
|
||||||
|
/// <param name="arg0">First argument of the call</param>
|
||||||
|
private void UpdateUniformBufferState(IDeviceState state, int arg0)
|
||||||
|
{
|
||||||
|
uint address = (uint)state.Read(UpdateConstantBufferAddressesBase + arg0 * 4);
|
||||||
|
int size = state.Read(UpdateConstantBufferSizesBase + arg0 * 4);
|
||||||
|
|
||||||
|
_processor.ThreedClass.UpdateUniformBufferState(size, address >> 24, address << 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Updates uniform buffer state for update.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="state">GPU state at the time of the call</param>
|
||||||
|
/// <param name="arg0">First argument of the call</param>
|
||||||
|
private void UpdateUniformBufferStateCbu(IDeviceState state, int arg0)
|
||||||
|
{
|
||||||
|
uint address = (uint)state.Read(UpdateConstantBufferAddressCbu);
|
||||||
|
|
||||||
|
UniformBufferState ubState = new()
|
||||||
|
{
|
||||||
|
Address = new()
|
||||||
|
{
|
||||||
|
High = address >> 24,
|
||||||
|
Low = address << 8
|
||||||
|
},
|
||||||
|
Size = 24320,
|
||||||
|
Offset = arg0 << 2
|
||||||
|
};
|
||||||
|
|
||||||
|
_processor.ThreedClass.UpdateUniformBufferState(ubState);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Updates uniform buffer state for update.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="state">GPU state at the time of the call</param>
|
||||||
|
/// <param name="arg0">First argument of the call</param>
|
||||||
|
private void UpdateUniformBufferStateCbuV2(IDeviceState state, int arg0)
|
||||||
|
{
|
||||||
|
uint address = (uint)state.Read(UpdateConstantBufferAddressCbu);
|
||||||
|
|
||||||
|
UniformBufferState ubState = new()
|
||||||
|
{
|
||||||
|
Address = new()
|
||||||
|
{
|
||||||
|
High = address >> 24,
|
||||||
|
Low = address << 8
|
||||||
|
},
|
||||||
|
Size = 28672,
|
||||||
|
Offset = arg0 << 2
|
||||||
|
};
|
||||||
|
|
||||||
|
_processor.ThreedClass.UpdateUniformBufferState(ubState);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Updates blend enable using the given argument.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="state">GPU state at the time of the call</param>
|
||||||
|
/// <param name="arg0">First argument of the call</param>
|
||||||
|
private void UpdateBlendState(IDeviceState state, int arg0)
|
||||||
|
{
|
||||||
|
state.Write(LogicOpOffset, 0);
|
||||||
|
|
||||||
|
Array8<Boolean32> enable = new();
|
||||||
|
|
||||||
|
for (int i = 0; i < 8; i++)
|
||||||
|
{
|
||||||
|
enable[i] = new Boolean32((uint)(arg0 >> (i + 8)) & 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
_processor.ThreedClass.UpdateBlendEnable(ref enable);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Updates color masks using the given argument and three pushed arguments.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="state">GPU state at the time of the call</param>
|
||||||
|
/// <param name="arg0">First argument of the call</param>
|
||||||
|
private void UpdateColorMasks(IDeviceState state, int arg0)
|
||||||
|
{
|
||||||
|
Array8<RtColorMask> masks = new();
|
||||||
|
|
||||||
|
int index = 0;
|
||||||
|
|
||||||
|
for (int i = 0; i < 4; i++)
|
||||||
|
{
|
||||||
|
masks[index++] = new RtColorMask((uint)arg0 & 0x1fff);
|
||||||
|
masks[index++] = new RtColorMask(((uint)arg0 >> 16) & 0x1fff);
|
||||||
|
|
||||||
|
if (i != 3)
|
||||||
|
{
|
||||||
|
arg0 = FetchParam().Word;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_processor.ThreedClass.UpdateColorMasks(ref masks);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Clears one bound color target.
|
/// Clears one bound color target.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -129,6 +305,36 @@ namespace Ryujinx.Graphics.Gpu.Engine.MME
|
|||||||
indexed: false);
|
indexed: false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Performs a indexed draw.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="state">GPU state at the time of the call</param>
|
||||||
|
/// <param name="arg0">First argument of the call</param>
|
||||||
|
private void DrawElements(IDeviceState state, int arg0)
|
||||||
|
{
|
||||||
|
var topology = (PrimitiveTopology)arg0;
|
||||||
|
|
||||||
|
var indexAddressHigh = FetchParam();
|
||||||
|
var indexAddressLow = FetchParam();
|
||||||
|
var indexType = FetchParam();
|
||||||
|
var firstIndex = 0;
|
||||||
|
var indexCount = FetchParam();
|
||||||
|
|
||||||
|
_processor.ThreedClass.UpdateIndexBuffer(
|
||||||
|
(uint)indexAddressHigh.Word,
|
||||||
|
(uint)indexAddressLow.Word,
|
||||||
|
(IndexType)indexType.Word);
|
||||||
|
|
||||||
|
_processor.ThreedClass.Draw(
|
||||||
|
topology,
|
||||||
|
indexCount.Word,
|
||||||
|
1,
|
||||||
|
firstIndex,
|
||||||
|
state.Read(FirstVertexOffset),
|
||||||
|
0,
|
||||||
|
indexed: true);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Performs a indexed draw.
|
/// Performs a indexed draw.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@@ -6,11 +6,19 @@
|
|||||||
enum MacroHLEFunctionName
|
enum MacroHLEFunctionName
|
||||||
{
|
{
|
||||||
None,
|
None,
|
||||||
|
BindShaderProgram,
|
||||||
ClearColor,
|
ClearColor,
|
||||||
ClearDepthStencil,
|
ClearDepthStencil,
|
||||||
DrawArraysInstanced,
|
DrawArraysInstanced,
|
||||||
|
DrawElements,
|
||||||
DrawElementsInstanced,
|
DrawElementsInstanced,
|
||||||
DrawElementsIndirect,
|
DrawElementsIndirect,
|
||||||
MultiDrawElementsIndirectCount,
|
MultiDrawElementsIndirectCount,
|
||||||
|
|
||||||
|
UpdateBlendState,
|
||||||
|
UpdateColorMasks,
|
||||||
|
UpdateUniformBufferState,
|
||||||
|
UpdateUniformBufferStateCbu,
|
||||||
|
UpdateUniformBufferStateCbuV2
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -46,12 +46,19 @@ namespace Ryujinx.Graphics.Gpu.Engine.MME
|
|||||||
|
|
||||||
private static readonly TableEntry[] _table = new TableEntry[]
|
private static readonly TableEntry[] _table = new TableEntry[]
|
||||||
{
|
{
|
||||||
|
new(MacroHLEFunctionName.BindShaderProgram, new Hash128(0x5d5efb912369f60b, 0x69131ed5019f08ef), 0x68),
|
||||||
new(MacroHLEFunctionName.ClearColor, new Hash128(0xA9FB28D1DC43645A, 0xB177E5D2EAE67FB0), 0x28),
|
new(MacroHLEFunctionName.ClearColor, new Hash128(0xA9FB28D1DC43645A, 0xB177E5D2EAE67FB0), 0x28),
|
||||||
new(MacroHLEFunctionName.ClearDepthStencil, new Hash128(0x1B96CB77D4879F4F, 0x8557032FE0C965FB), 0x24),
|
new(MacroHLEFunctionName.ClearDepthStencil, new Hash128(0x1B96CB77D4879F4F, 0x8557032FE0C965FB), 0x24),
|
||||||
new(MacroHLEFunctionName.DrawArraysInstanced, new Hash128(0x197FB416269DBC26, 0x34288C01DDA82202), 0x48),
|
new(MacroHLEFunctionName.DrawArraysInstanced, new Hash128(0x197FB416269DBC26, 0x34288C01DDA82202), 0x48),
|
||||||
|
new(MacroHLEFunctionName.DrawElements, new Hash128(0x3D7F32AE6C2702A7, 0x9353C9F41C1A244D), 0x20),
|
||||||
new(MacroHLEFunctionName.DrawElementsInstanced, new Hash128(0x1A501FD3D54EC8E0, 0x6CF570CF79DA74D6), 0x5c),
|
new(MacroHLEFunctionName.DrawElementsInstanced, new Hash128(0x1A501FD3D54EC8E0, 0x6CF570CF79DA74D6), 0x5c),
|
||||||
new(MacroHLEFunctionName.DrawElementsIndirect, new Hash128(0x86A3E8E903AF8F45, 0xD35BBA07C23860A4), 0x7c),
|
new(MacroHLEFunctionName.DrawElementsIndirect, new Hash128(0x86A3E8E903AF8F45, 0xD35BBA07C23860A4), 0x7c),
|
||||||
new(MacroHLEFunctionName.MultiDrawElementsIndirectCount, new Hash128(0x890AF57ED3FB1C37, 0x35D0C95C61F5386F), 0x19C),
|
new(MacroHLEFunctionName.MultiDrawElementsIndirectCount, new Hash128(0x890AF57ED3FB1C37, 0x35D0C95C61F5386F), 0x19C),
|
||||||
|
new(MacroHLEFunctionName.UpdateBlendState, new Hash128(0x40F6D4E7B08D7640, 0x82167BEEAECB959F), 0x28),
|
||||||
|
new(MacroHLEFunctionName.UpdateColorMasks, new Hash128(0x9EE32420B8441DFD, 0x6E7724759A57333E), 0x24),
|
||||||
|
new(MacroHLEFunctionName.UpdateUniformBufferState, new Hash128(0x8EE66706049CB0B0, 0x51C1CF906EC86F7C), 0x20),
|
||||||
|
new(MacroHLEFunctionName.UpdateUniformBufferStateCbu, new Hash128(0xA4592676A3E581A0, 0xA39E77FE19FE04AC), 0x18),
|
||||||
|
new(MacroHLEFunctionName.UpdateUniformBufferStateCbuV2, new Hash128(0x392FA750489983D4, 0x35BACE455155D2C3), 0x18)
|
||||||
};
|
};
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -62,18 +69,14 @@ namespace Ryujinx.Graphics.Gpu.Engine.MME
|
|||||||
/// <returns>True if the host supports the HLE macro, false otherwise</returns>
|
/// <returns>True if the host supports the HLE macro, false otherwise</returns>
|
||||||
private static bool IsMacroHLESupported(Capabilities caps, MacroHLEFunctionName name)
|
private static bool IsMacroHLESupported(Capabilities caps, MacroHLEFunctionName name)
|
||||||
{
|
{
|
||||||
if (name == MacroHLEFunctionName.ClearColor ||
|
if (name == MacroHLEFunctionName.MultiDrawElementsIndirectCount)
|
||||||
name == MacroHLEFunctionName.ClearDepthStencil ||
|
|
||||||
name == MacroHLEFunctionName.DrawArraysInstanced ||
|
|
||||||
name == MacroHLEFunctionName.DrawElementsInstanced ||
|
|
||||||
name == MacroHLEFunctionName.DrawElementsIndirect)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else if (name == MacroHLEFunctionName.MultiDrawElementsIndirectCount)
|
|
||||||
{
|
{
|
||||||
return caps.SupportsIndirectParameters;
|
return caps.SupportsIndirectParameters;
|
||||||
}
|
}
|
||||||
|
else if (name != MacroHLEFunctionName.None)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user