forked from MeloNX/MeloNX
Compare commits
200 Commits
XC-ios-ht
...
libryujinx
Author | SHA1 | Date | |
---|---|---|---|
|
0f1b737b07 | ||
|
29332c44ab | ||
|
e926499e32 | ||
|
96c4edb697 | ||
|
ba3438f24a | ||
|
956c5fe4fd | ||
|
15baf43a7c | ||
|
aec0b99f8a | ||
|
16f77936e0 | ||
|
5f18d19f23 | ||
|
29a0c1caed | ||
|
97e3fc60ca | ||
|
1a4f506991 | ||
|
af4f7b9ee7 | ||
|
a6a75a4208 | ||
|
d6e88e3cc9 | ||
|
66e58aa6a7 | ||
|
5d919039d9 | ||
|
cdf188a434 | ||
|
f403484276 | ||
|
7955b4f287 | ||
|
047ee4554e | ||
|
e0c5953ce0 | ||
|
b81643352e | ||
|
c12da6d650 | ||
|
c74ad70c3d | ||
|
1ea1a0ba68 | ||
|
8e25994391 | ||
|
52f5142305 | ||
|
80d1ac212e | ||
|
a8fcf22b89 | ||
|
aa87b4abd8 | ||
|
60f320bc07 | ||
|
521403b0ea | ||
|
9680ecd820 | ||
|
3bc415053e | ||
|
e7ac8bf333 | ||
|
819c7671bb | ||
|
990ad3d133 | ||
|
923d0a5bd1 | ||
|
024a6cdbb2 | ||
|
5028673968 | ||
|
d7b139a4a8 | ||
|
9765f7a388 | ||
|
bc6e5de507 | ||
|
e5d54d5374 | ||
|
038ee1a6dd | ||
|
c6e2e16e0b | ||
|
74f45c486f | ||
|
4fc253384b | ||
|
71f3d22db8 | ||
|
fdb7320031 | ||
|
f6850bcc1a | ||
|
946079f5e3 | ||
|
14d6e280f7 | ||
|
2240d87902 | ||
|
5b1a928e1b | ||
|
04850674d0 | ||
|
f560431792 | ||
|
ba745514a1 | ||
|
8e2eb5fd26 | ||
|
34e52880da | ||
|
a2b7dc5aca | ||
|
28af479e2a | ||
|
c0091c838d | ||
|
4c0d21ede4 | ||
|
e3a81cfdee | ||
|
698ac0413b | ||
|
dca4091930 | ||
|
f1814ca542 | ||
|
3e6ec4aea8 | ||
|
fdc5ceea41 | ||
|
091d9d4546 | ||
|
7a2fadb499 | ||
|
c732a9fbb6 | ||
|
6f48a6a24d | ||
|
e6ceb70114 | ||
|
83c9e4fcb2 | ||
|
8c0bd460d9 | ||
|
0bf93ef754 | ||
|
8f8f9e996a | ||
|
3f8d269719 | ||
|
6a8fce261e | ||
|
44315541c3 | ||
|
7a85dc2e76 | ||
|
fb562c8077 | ||
|
2999275ed2 | ||
|
a050e5c6c0 | ||
|
398fb78a31 | ||
|
f0b0f3b796 | ||
|
7d7e1ce639 | ||
|
f8c1e745ca | ||
|
a0c9d3b7de | ||
|
108fb2380a | ||
|
9b4d988d8c | ||
|
fae788f698 | ||
|
fa16c9c3bd | ||
|
979db1def3 | ||
|
300b23cf9b | ||
|
ee4e18ff0d | ||
|
14cf6efa60 | ||
|
35641ee3ca | ||
|
853ef9ff8f | ||
|
03ec861e03 | ||
|
9d8e02dd0e | ||
|
733f13fe0e | ||
|
5070e14317 | ||
|
c247830f78 | ||
|
853b6f29ce | ||
|
4d2add5264 | ||
|
4728c1e96c | ||
|
dd31c40f4e | ||
|
bda6617571 | ||
|
7fd44e32d0 | ||
|
fb592277a7 | ||
|
826c64ddfe | ||
|
beba6d1422 | ||
|
5708f700ec | ||
|
918b0fa302 | ||
|
ffaa4d8ac1 | ||
|
ff3099e4a1 | ||
|
61ba5e7bff | ||
|
4f1bf2d0cc | ||
|
93cf57913c | ||
|
2ad3605cdb | ||
|
7925581e72 | ||
|
2814fa60bf | ||
|
437bfdbd5a | ||
|
375691b0e0 | ||
|
517277a11f | ||
|
8e23eb88bb | ||
|
c694d5774d | ||
|
25b31b559a | ||
|
f3531394d5 | ||
|
976514fdcc | ||
|
953559c71c | ||
|
d6ba9ad8f5 | ||
|
4eb8e27517 | ||
|
6262bd1730 | ||
|
e9c7564a03 | ||
|
7b1ce437ef | ||
|
21a78f173e | ||
|
e54e18dab8 | ||
|
2d39deba26 | ||
|
28eb812018 | ||
|
9c510fec3e | ||
|
44551a0409 | ||
|
0970972f0d | ||
|
a1e34041fa | ||
|
c5bcdc06f5 | ||
|
c8d6f786c5 | ||
|
c0a2cc5f6c | ||
|
db9111b895 | ||
|
159d1f0eae | ||
|
07caf24936 | ||
|
56a6ac2a65 | ||
|
145cd0b2b1 | ||
|
333401b71d | ||
|
5b9b17ef24 | ||
|
ba8028d1d0 | ||
|
a57cad5d5e | ||
|
9bb70e5ac2 | ||
|
416f40bddc | ||
|
3af84d0715 | ||
|
d988dfa781 | ||
|
fd05b76554 | ||
|
6828fe6270 | ||
|
4d06f19fe7 | ||
|
ad0f9a7fc7 | ||
|
1835e16045 | ||
|
0a666d9c5b | ||
|
b7d08e5050 | ||
|
8a8db6244d | ||
|
0b14eb3a61 | ||
|
c27a12df2c | ||
|
24b8d7c981 | ||
|
8535b6c2f6 | ||
|
cb8837e1b8 | ||
|
0e3c224b8d | ||
|
1694303e4c | ||
|
cea50d80c9 | ||
|
c3a3adbaeb | ||
|
4df22eb867 | ||
|
f241f88558 | ||
|
90455a05e6 | ||
|
edc76883db | ||
|
427b7d06b5 | ||
|
331c07807f | ||
|
a772b073ec | ||
|
870d9599cc | ||
|
2dbbc9bc05 | ||
|
72634c80f4 | ||
|
bebd8eb822 | ||
|
f4b74e9ce1 | ||
|
4e19b36ad7 | ||
|
b16923a902 | ||
|
7e58b21f3d | ||
|
4fbc978e73 | ||
|
1a45dc8df8 | ||
|
f037fcba9a |
@ -1,21 +0,0 @@
|
||||
name: Notify API on Release
|
||||
|
||||
on:
|
||||
release:
|
||||
types: [published]
|
||||
|
||||
jobs:
|
||||
notify-api:
|
||||
runs-on: debian-trixie
|
||||
steps:
|
||||
- name: Send API Call for New Release
|
||||
run: |
|
||||
curl -X POST http://melonx.org/api/new_release \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Authorization: Bearer ${{ secrets.MELONX_GITEA_API_KEY }}" \
|
||||
-d '{
|
||||
"version_number": "${{ github.event.release.tag_name }}",
|
||||
"download_link": "${{ github.event.release.html_url }}",
|
||||
"changelog": "${{ github.event.release.body }}",
|
||||
"is_latest": true
|
||||
}'
|
18
.github/dependabot.yml
vendored
18
.github/dependabot.yml
vendored
@ -13,7 +13,7 @@ updates:
|
||||
|
||||
- package-ecosystem: nuget
|
||||
directory: /
|
||||
open-pull-requests-limit: 5
|
||||
open-pull-requests-limit: 10
|
||||
schedule:
|
||||
interval: daily
|
||||
labels:
|
||||
@ -22,3 +22,19 @@ updates:
|
||||
- marysaka
|
||||
commit-message:
|
||||
prefix: nuget
|
||||
groups:
|
||||
Avalonia:
|
||||
patterns:
|
||||
- "*Avalonia*"
|
||||
Silk.NET:
|
||||
patterns:
|
||||
- "Silk.NET*"
|
||||
OpenTK:
|
||||
patterns:
|
||||
- "OpenTK*"
|
||||
SixLabors:
|
||||
patterns:
|
||||
- "SixLabors*"
|
||||
NUnit:
|
||||
patterns:
|
||||
- "NUnit*"
|
||||
|
5
.gitignore
vendored
5
.gitignore
vendored
@ -10,8 +10,6 @@
|
||||
|
||||
# Build results
|
||||
|
||||
dotnet.xcconfig
|
||||
|
||||
[Dd]ebug/
|
||||
[Rr]elease/
|
||||
x64/
|
||||
@ -47,7 +45,6 @@ build/
|
||||
*.vssscc
|
||||
.builds
|
||||
*.pidb
|
||||
*.log
|
||||
*.scc
|
||||
|
||||
# Visual C++ cache files
|
||||
@ -175,4 +172,4 @@ PublishProfiles/
|
||||
|
||||
# Glade backup files
|
||||
*.glade~
|
||||
src/MeloNX/MeloNX/Dependencies/Dynamic Libraries/Ryujinx.Headless.SDL2.dylib
|
||||
|
||||
|
72
Compile.md
72
Compile.md
@ -1,72 +0,0 @@
|
||||
# Compiling MeloNX on macOS
|
||||
|
||||
## Prerequisites
|
||||
|
||||
Before you begin, ensure you have the following installed:
|
||||
|
||||
- [**.NET 8.0**](https://dotnet.microsoft.com/en-us/download/dotnet/8.0)
|
||||
- A Mac running **macOS**
|
||||
|
||||
## Compilation Steps
|
||||
|
||||
### 1. Clone the Repository and Build Ryujinx
|
||||
|
||||
Open a terminal and run:
|
||||
|
||||
```sh
|
||||
git clone https://git.743378673.xyz/MeloNX/MeloNX.git
|
||||
cd MeloNX
|
||||
./compile.sh
|
||||
```
|
||||
You may need to run this command if compilation fails, then run the `./compile.sh` command again (You will need to put in your user password. Your password will not be shown at all.)
|
||||
```
|
||||
sudo xcode-select --switch /Applications/Xcode.app/Contents/Developer
|
||||
```
|
||||
|
||||
|
||||
However, if you only need to update MeloNX, make sure you have cd into the directory then run this then skip to step 5
|
||||
```
|
||||
git pull
|
||||
./compile.sh
|
||||
```
|
||||
|
||||
### 2. Open the Xcode Project
|
||||
|
||||
Navigate to the **Xcode project file** located at:
|
||||
|
||||
```
|
||||
src/MeloNX/MeloNX.xcodeproj
|
||||
```
|
||||
|
||||
Double-click to open it in **Xcode**.
|
||||
|
||||
### 3. Configure the Project Settings
|
||||
|
||||
- In **Xcode**, select the **MeloNX** project.
|
||||
- Under the **General** tab, find `Ryujinx.Headless.SDL2.dylib`.
|
||||
- Set its **Embed setting** to **"Embed & Sign"**.
|
||||
|
||||
### 4. Configure Signing & Capabilities
|
||||
|
||||
- In **Xcode**, go to **Signing & Capabilities**.
|
||||
- Set the **Team** to your **Apple Developer account** (free or paid).
|
||||
- Change the **Bundle Identifier** to:
|
||||
|
||||
```
|
||||
com.<your-name>.MeloNX
|
||||
```
|
||||
|
||||
*(Replace `<your-name>` with your actual name or identifier.)*
|
||||
|
||||
### 5. Connect Your Device
|
||||
|
||||
Ensure your **iPhone/iPad** is **connected** and **recognized** in Xcode.
|
||||
|
||||
### 6. Build and Run
|
||||
|
||||
Click the **Run (▶️) button** in Xcode to compile and launch MeloNX.
|
||||
|
||||
---
|
||||
|
||||
Now you're all set! 🚀 If you encounter issues, please join the discord at https://melonx.org
|
||||
```
|
@ -3,52 +3,53 @@
|
||||
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageVersion Include="Avalonia" Version="11.0.5" />
|
||||
<PackageVersion Include="Avalonia.Controls.DataGrid" Version="11.0.5" />
|
||||
<PackageVersion Include="Avalonia.Desktop" Version="11.0.5" />
|
||||
<PackageVersion Include="Avalonia.Diagnostics" Version="11.0.5" />
|
||||
<PackageVersion Include="Avalonia.Markup.Xaml.Loader" Version="11.0.5" />
|
||||
<PackageVersion Include="Avalonia.Svg" Version="11.0.0.3" />
|
||||
<PackageVersion Include="Avalonia.Svg.Skia" Version="11.0.0.3" />
|
||||
<PackageVersion Include="Avalonia" Version="11.0.7" />
|
||||
<PackageVersion Include="Avalonia.Controls.DataGrid" Version="11.0.7" />
|
||||
<PackageVersion Include="Avalonia.Desktop" Version="11.0.7" />
|
||||
<PackageVersion Include="Avalonia.Diagnostics" Version="11.0.7" />
|
||||
<PackageVersion Include="Avalonia.Markup.Xaml.Loader" Version="11.0.7" />
|
||||
<PackageVersion Include="Avalonia.Svg" Version="11.0.0.10" />
|
||||
<PackageVersion Include="Avalonia.Svg.Skia" Version="11.0.0.10" />
|
||||
<PackageVersion Include="CommandLineParser" Version="2.9.1" />
|
||||
<PackageVersion Include="Concentus" Version="1.1.7" />
|
||||
<PackageVersion Include="DiscordRichPresence" Version="1.2.1.24" />
|
||||
<PackageVersion Include="DynamicData" Version="7.14.2" />
|
||||
<PackageVersion Include="FluentAvaloniaUI" Version="2.0.4" />
|
||||
<PackageVersion Include="FluentAvaloniaUI" Version="2.0.5" />
|
||||
<PackageVersion Include="GtkSharp.Dependencies" Version="1.1.1" />
|
||||
<PackageVersion Include="GtkSharp.Dependencies.osx" Version="0.0.5" />
|
||||
<PackageVersion Include="jp2masa.Avalonia.Flexbox" Version="0.3.0-beta.4" />
|
||||
<PackageVersion Include="LibHac" Version="0.19.0" />
|
||||
<PackageVersion Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.4" />
|
||||
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp" Version="4.7.0" />
|
||||
<PackageVersion Include="Microsoft.IdentityModel.JsonWebTokens" Version="7.2.0" />
|
||||
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.8.0" />
|
||||
<PackageVersion Include="Microsoft.IO.RecyclableMemoryStream" Version="2.3.2" />
|
||||
<PackageVersion Include="MsgPack.Cli" Version="1.0.1" />
|
||||
<PackageVersion Include="NetCoreServer" Version="7.0.0" />
|
||||
<PackageVersion Include="NUnit" Version="3.13.3" />
|
||||
<PackageVersion Include="NUnit3TestAdapter" Version="4.1.0" />
|
||||
<PackageVersion Include="OpenTK.Core" Version="4.8.1" />
|
||||
<PackageVersion Include="OpenTK.Graphics" Version="4.8.1" />
|
||||
<PackageVersion Include="OpenTK.Audio.OpenAL" Version="4.8.1" />
|
||||
<PackageVersion Include="OpenTK.Windowing.GraphicsLibraryFramework" Version="4.8.1" />
|
||||
<PackageVersion Include="OpenTK.Core" Version="4.8.2" />
|
||||
<PackageVersion Include="OpenTK.Graphics" Version="4.8.2" />
|
||||
<PackageVersion Include="OpenTK.Audio.OpenAL" Version="4.8.2" />
|
||||
<PackageVersion Include="OpenTK.Windowing.GraphicsLibraryFramework" Version="4.8.2" />
|
||||
<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.Vulkan.Dependencies.MoltenVK" Version="1.2.3" />
|
||||
<PackageVersion Include="Ryujinx.Graphics.Vulkan.Dependencies.MoltenVK" Version="1.2.0" />
|
||||
<PackageVersion Include="Ryujinx.GtkSharp" Version="3.24.24.59-ryujinx" />
|
||||
<PackageVersion Include="Ryujinx.SDL2-CS" Version="2.28.1-build28" />
|
||||
<PackageVersion Include="securifybv.ShellLink" Version="0.1.0" />
|
||||
<PackageVersion Include="shaderc.net" Version="0.1.0" />
|
||||
<PackageVersion Include="SharpZipLib" Version="1.4.2" />
|
||||
<PackageVersion Include="Silk.NET.Vulkan" Version="2.22.0" />
|
||||
<PackageVersion Include="Silk.NET.Vulkan.Extensions.EXT" Version="2.22.0" />
|
||||
<PackageVersion Include="Silk.NET.Vulkan.Extensions.KHR" Version="2.22.0" />
|
||||
<PackageVersion Include="Silk.NET.Vulkan" Version="2.17.1" />
|
||||
<PackageVersion Include="Silk.NET.Vulkan.Extensions.EXT" Version="2.17.1" />
|
||||
<PackageVersion Include="Silk.NET.Vulkan.Extensions.KHR" Version="2.17.1" />
|
||||
<PackageVersion Include="SixLabors.ImageSharp" Version="1.0.4" />
|
||||
<PackageVersion Include="SixLabors.ImageSharp.Drawing" Version="1.0.0-beta11" />
|
||||
<PackageVersion Include="SPB" Version="0.0.4-build28" />
|
||||
<PackageVersion Include="System.Drawing.Common" Version="8.0.0" />
|
||||
<PackageVersion Include="System.IdentityModel.Tokens.Jwt" Version="7.0.3" />
|
||||
<PackageVersion Include="System.IO.Hashing" Version="8.0.0" />
|
||||
<PackageVersion Include="System.Management" Version="8.0.0" />
|
||||
<PackageVersion Include="UnicornEngine.Unicorn" Version="2.0.2-rc1-fb78016" />
|
||||
<PackageVersion Include="Rxmxnx.PInvoke.Extensions" Version="1.0.1" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
</Project>
|
14
LICENSE.txt
14
LICENSE.txt
@ -1,15 +1,9 @@
|
||||
MeloNX License
|
||||
MIT License
|
||||
|
||||
Copyright (c) MeloNX Team and Contributors
|
||||
Copyright (c) Ryujinx Team and Contributors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person (except anyone who has previously attempted or is currently attempting to merge MeloNX with Pomelo) 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:
|
||||
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. Every file is under this license, and all copies must be redistributed under the same license.
|
||||
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.
|
||||
|
||||
Anyone who attempts or has attempted to merge MeloNX with Pomelo, or otherwise use this source code in conjunction with Pomelo, is prohibited from using, copying, modifying, or distributing the source code without first obtaining explicit, written permission from Stossy11.
|
||||
|
||||
Additionally, the names of the developers or contributors to this project may not be used to endorse or promote products derived from this software without specific, prior written permission from the respective developer(s).
|
||||
|
||||
Ryujinx is licensed under the MIT License. Copyright (c) Ryujinx contributors. All rights to Ryujinx are held by its respective copyright holders, and its use is subject to the terms of the MIT License.
|
@ -1,46 +0,0 @@
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>get-task-allow</key>
|
||||
<true/>
|
||||
<key>com.apple.developer.kernel.increased-memory-limit</key>
|
||||
<true/>
|
||||
<key>com.apple.developer.kernel.extended-virtual-addressing</key>
|
||||
<true/>
|
||||
<key>com.apple.private.iokit.IOServiceSetAuthorizationID</key>
|
||||
<true/>
|
||||
<key>com.apple.security.exception.iokit-user-client-class</key>
|
||||
<array>
|
||||
<string>AGXCommandQueue</string>
|
||||
<string>AGXDevice</string>
|
||||
<string>AGXDeviceUserClient</string>
|
||||
<string>AGXSharedUserClient</string>
|
||||
<string>AppleUSBHostDeviceUserClient</string>
|
||||
<string>AppleUSBHostInterfaceUserClient</string>
|
||||
<string>IOSurfaceRootUserClient</string>
|
||||
<string>IOAccelContext</string>
|
||||
<string>IOAccelContext2</string>
|
||||
<string>IOAccelDevice</string>
|
||||
<string>IOAccelDevice2</string>
|
||||
<string>IOAccelSharedUserClient</string>
|
||||
<string>IOAccelSharedUserClient2</string>
|
||||
<string>IOAccelSubmitter2</string>
|
||||
</array>
|
||||
<key>com.apple.system.diagnostics.iokit-properties</key>
|
||||
<true/>
|
||||
<key>com.apple.vm.device-access</key>
|
||||
<true/>
|
||||
<key>com.apple.private.hypervisor</key>
|
||||
<true/>
|
||||
<key>com.apple.private.memorystatus</key>
|
||||
<true/>
|
||||
<key>com.apple.private.security.no-sandbox</key>
|
||||
<true/>
|
||||
<key>com.apple.private.security.storage.AppDataContainers</key>
|
||||
<true/>
|
||||
<key>com.apple.private.security.storage.MobileDocuments</key>
|
||||
<true/>
|
||||
<key>platform-application</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
180
README.md
180
README.md
@ -1,120 +1,144 @@
|
||||
|
||||
<h1 align="center">
|
||||
<br>
|
||||
<a href="https://ryujinx.org/"><img src="https://i.imgur.com/WcCj6Rt.png" alt="Ryujinx" width="150"></a>
|
||||
<br>
|
||||
<b>Ryujinx</b>
|
||||
<br>
|
||||
<sub><sup><b>(REE-YOU-JINX)</b></sup></sub>
|
||||
<br>
|
||||
|
||||
</h1>
|
||||
|
||||
<p align="center">
|
||||
<a href="https://melonx.org">
|
||||
<img src="https://melonx.org/static/imgs/MeloNX.svg" alt="MeloNX Logo" width="120">
|
||||
Ryujinx is an open-source Nintendo Switch emulator, created by gdkchan, written in C#.
|
||||
This emulator aims at providing excellent accuracy and performance, a user-friendly interface and consistent builds.
|
||||
It was written from scratch and development on the project began in September 2017. Ryujinx is available on Github under the <a href="https://github.com/Ryujinx/Ryujinx/blob/master/LICENSE.txt" target="_blank">MIT license</a>. <br />
|
||||
|
||||
</p>
|
||||
<p align="center">
|
||||
<a href="https://github.com/Ryujinx/Ryujinx/actions/workflows/release.yml">
|
||||
<img src="https://github.com/Ryujinx/Ryujinx/actions/workflows/release.yml/badge.svg"
|
||||
alt="">
|
||||
</a>
|
||||
<a href="https://crwd.in/ryujinx">
|
||||
<img src="https://badges.crowdin.net/ryujinx/localized.svg"
|
||||
alt="">
|
||||
</a>
|
||||
<a href="https://discord.com/invite/VkQYXAZ">
|
||||
<img src="https://img.shields.io/discord/410208534861447168?color=5865F2&label=Ryujinx&logo=discord&logoColor=white"
|
||||
alt="Discord">
|
||||
</a>
|
||||
<br>
|
||||
<br>
|
||||
<img src="https://raw.githubusercontent.com/Ryujinx/Ryujinx-Website/master/public/assets/images/shell.png">
|
||||
</p>
|
||||
|
||||
<h1 align="center">MeloNX</h1>
|
||||
<h5 align="center">
|
||||
|
||||
</h5>
|
||||
|
||||
## Compatibility
|
||||
|
||||
As of April 2023, Ryujinx has been tested on approximately 4,050 titles; over 4,000 boot past menus and into gameplay, with roughly 3,400 of those being considered playable.
|
||||
You can check out the compatibility list [here](https://github.com/Ryujinx/Ryujinx-Games-List/issues). Anyone is free to submit a new game test or update an existing game test entry; simply follow the new issue template and testing guidelines, or post as a reply to the applicable game issue. Use the search function to see if a game has been tested already!
|
||||
|
||||
## Usage
|
||||
|
||||
To run this emulator, your PC must be equipped with at least 8GiB of RAM; failing to meet this requirement may result in a poor gameplay experience or unexpected crashes.
|
||||
|
||||
See our [Setup & Configuration Guide](https://github.com/Ryujinx/Ryujinx/wiki/Ryujinx-Setup-&-Configuration-Guide) on how to set up the emulator.
|
||||
|
||||
For our Local Wireless and LAN builds, see our [Multiplayer: Local Play/Local Wireless Guide
|
||||
](https://github.com/Ryujinx/Ryujinx/wiki/Multiplayer-(LDN-Local-Wireless)-Guide).
|
||||
|
||||
Avalonia UI comes with translations for various languages. See [Crowdin](https://crwd.in/ryujinx) for more information.
|
||||
|
||||
## Latest build
|
||||
|
||||
These builds are compiled automatically for each commit on the master branch. While we strive to ensure optimal stability and performance prior to pushing an update, our automated builds **may be unstable or completely broken.**
|
||||
|
||||
If you want to see details on updates to the emulator, you can visit our [Changelog](https://github.com/Ryujinx/Ryujinx/wiki/Changelog).
|
||||
|
||||
The latest automatic build for Windows, macOS, and Linux can be found on the [Official Website](https://ryujinx.org/download).
|
||||
|
||||
|
||||
## Building
|
||||
|
||||
<p align="center">
|
||||
MeloNX enables Nintendo Switch game emulation on iOS using the Ryujinx iOS code base.
|
||||
</p>
|
||||
If you wish to build the emulator yourself, follow these steps:
|
||||
|
||||
<p align="center">
|
||||
MeloNX is an iOS Nintendo Switch emulator based on Ryujinx, written primarily in C#. Designed to bring accurate performance and a user-friendly interface to iOS, MeloNX makes Switch games accessible on Apple devices.
|
||||
Developed from the ground up, MeloNX is open-source and available on Github under the <a href="https://github.com/MeloNX-Emu/MeloNX/blob/master/LICENSE.txt" target="_blank">MeloNX license (Based on MIT)</a>. <br
|
||||
</p>
|
||||
### Step 1
|
||||
Install the X64 version of [.NET 8.0 (or higher) SDK](https://dotnet.microsoft.com/download/dotnet/8.0).
|
||||
|
||||
# Compatibility
|
||||
### 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.
|
||||
|
||||
MeloNX works on iPhone X and later and iPad 7th Gen and later. Check out the Compatibility on the <a href="https://melonx.org/compatibility/" target="_blank">website</a>.
|
||||
### Step 3
|
||||
|
||||
# Usage
|
||||
To build Ryujinx, open a command prompt inside the project directory. You can quickly access it on Windows by holding shift in File Explorer, then right clicking and selecting `Open command window here`. Then type the following command:
|
||||
`dotnet build -c Release -o build`
|
||||
the built files will be found in the newly created build directory.
|
||||
|
||||
## FAQ
|
||||
- MeloNX is made for iOS 17+, iOS 15 - 16 is supported but will have issues.
|
||||
- MeloNX needs Xcode or a Paid Apple Developer Account. SideStore support may come soon (SideStore Side Issue)
|
||||
- MeloNX needs JIT
|
||||
- Recommended Device: iPhone 15 Pro or newer.
|
||||
- Low-End Recommended Device**: iPhone 13 Pro.
|
||||
- Lowest Supported Device: iPhone XR
|
||||
Ryujinx system files are stored in the `Ryujinx` folder. This folder is located in the user folder, which can be accessed by clicking `Open Ryujinx Folder` under the File menu in the GUI.
|
||||
|
||||
|
||||
## How to install
|
||||
|
||||
### Paid Developer Account
|
||||
|
||||
1. **Sideload the App**
|
||||
- Use any sideloading tool that supports Apple IDs.
|
||||
|
||||
2. **Enable Entitlements**
|
||||
- Visit [Apple Developer Identifiers](https://developer.apple.com/account/resources/identifiers).
|
||||
- Locate **MeloNX** and enable the following entitlements:
|
||||
- `Increased Memory Limit`
|
||||
- `Increased Debugging Memory Limit`
|
||||
|
||||
3. **Reinstall the App**
|
||||
- Delete the existing installation.
|
||||
- Sideload the app again with the updated entitlements.
|
||||
|
||||
4. **Enable JIT**
|
||||
- Use your preferred method to enable Just-In-Time (JIT) compilation.
|
||||
|
||||
5. **Add Necessary Files**
|
||||
|
||||
If having Issues installing firmware (Make sure your Keys are installed first)
|
||||
- If needed, install firmware and keys from **Ryujinx Desktop**.
|
||||
- Copy the **bis** and **system** folders
|
||||
|
||||
### Xcode
|
||||
|
||||
1. **Compile Guide**
|
||||
- Visit the [guide here](https://git.743378673.xyz/MeloNX/MeloNX/src/branch/XC-ios-ht/Compile.md).
|
||||
|
||||
2. **Add Necessary Files**
|
||||
|
||||
If having Issues installing firmware (Make sure your Keys are installed first)
|
||||
- If needed, install firmware and keys from **Ryujinx Desktop**.
|
||||
- Copy the **bis** and **system** folders
|
||||
|
||||
## Features
|
||||
|
||||
- **Audio**
|
||||
- **Audio**
|
||||
|
||||
Audio output is entirely supported, audio input (microphone) isn't supported.
|
||||
We use C# wrappers for [OpenAL](https://openal-soft.org/), and [SDL2](https://www.libsdl.org/) & [libsoundio](http://libsound.io/) as fallbacks.
|
||||
Audio output is entirely supported, audio input (microphone) isn't supported. We use C# wrappers for [OpenAL](https://openal-soft.org/), and [SDL2](https://www.libsdl.org/) & [libsoundio](http://libsound.io/) as fallbacks.
|
||||
|
||||
- **CPU**
|
||||
|
||||
The CPU emulator, ARMeilleure, emulates an ARMv8 CPU and currently has support for most 64-bit ARMv8 and some of the ARMv7 (and older) instructions, including partial 32-bit support.
|
||||
It translates the ARM code to a custom IR, performs a few optimizations, and turns that into x86 code.
|
||||
There are three memory manager options available depending on the user's preference, leveraging both software-based (slower) and host-mapped modes (much faster).
|
||||
The fastest option (host, unchecked) is set by default.
|
||||
Ryujinx also features an optional Profiled Persistent Translation Cache, which essentially caches translated functions so that they do not need to be translated every time the game loads.
|
||||
The net result is a significant reduction in load times (the amount of time between launching a game and arriving at the title screen) for nearly every game.
|
||||
NOTE: This feature is enabled by default, You must launch the game at least twice to the title screen or beyond before performance improvements are unlocked on the third launch!
|
||||
These improvements are permanent and do not require any extra launches going forward.
|
||||
The CPU emulator, ARMeilleure, emulates an ARMv8 CPU and currently has support for most 64-bit ARMv8 and some of the ARMv7 (and older) instructions, including partial 32-bit support. It translates the ARM code to a custom IR, performs a few optimizations, and turns that into x86 code.
|
||||
There are three memory manager options available depending on the user's preference, leveraging both software-based (slower) and host-mapped modes (much faster). The fastest option (host, unchecked) is set by default.
|
||||
Ryujinx also features an optional Profiled Persistent Translation Cache, which essentially caches translated functions so that they do not need to be translated every time the game loads. The net result is a significant reduction in load times (the amount of time between launching a game and arriving at the title screen) for nearly every game. NOTE: this feature is enabled by default in the Options menu > System tab. You must launch the game at least twice to the title screen or beyond before performance improvements are unlocked on the third launch! These improvements are permanent and do not require any extra launches going forward.
|
||||
|
||||
- **GPU**
|
||||
|
||||
The GPU emulator emulates the Switch's Maxwell GPU using Metal (via MoltenVK) APIs through a custom build of OpenTK or Silk.NET respectively.
|
||||
The GPU emulator emulates the Switch's Maxwell GPU using either the OpenGL (version 4.5 minimum), Vulkan, or Metal (via MoltenVK) APIs through a custom build of OpenTK or Silk.NET respectively. There are currently six graphics enhancements available to the end user in Ryujinx: Disk Shader Caching, Resolution Scaling, Anti-Aliasing, Scaling Filters (including FSR), Anisotropic Filtering and Aspect Ratio Adjustment. These enhancements can be adjusted or toggled as desired in the GUI.
|
||||
|
||||
- **Input**
|
||||
|
||||
We currently have support for keyboard, touch input, JoyCon input support, and nearly all controllers.
|
||||
Motion controls are natively supported in most cases; for dual-JoyCon motion support, DS4Windows or BetterJoy are currently required.
|
||||
In all scenarios, you can set up everything inside the input configuration menu.
|
||||
We currently have support for keyboard, mouse, touch input, JoyCon input support, and nearly all controllers. Motion controls are natively supported in most cases; for dual-JoyCon motion support, DS4Windows or BetterJoy are currently required.
|
||||
In all scenarios, you can set up everything inside the input configuration menu.
|
||||
|
||||
- **DLC & Modifications**
|
||||
|
||||
MeloNX does not support add-on content/downloadable content.
|
||||
Mods (romfs, exefs, and runtime mods such as cheats) are supported;
|
||||
Ryujinx is able to manage add-on content/downloadable content through the GUI. Mods (romfs, exefs, and runtime mods such as cheats) are also supported; the GUI contains a shortcut to open the respective mods folder for a particular game.
|
||||
|
||||
- **Configuration**
|
||||
|
||||
The emulator has settings for enabling or disabling some logging, remapping controllers, and more.
|
||||
The emulator has settings for enabling or disabling some logging, remapping controllers, and more. You can configure all of them through the graphical interface or manually through the config file, `Config.json`, found in the user folder which can be accessed by clicking `Open Ryujinx Folder` under the File menu in the GUI.
|
||||
|
||||
|
||||
## Contact
|
||||
|
||||
If you have contributions, suggestions, need emulator support or just want to get in touch with the team, join our [Discord server](https://discord.com/invite/Ryujinx). You may also review our [FAQ](https://github.com/Ryujinx/Ryujinx/wiki/Frequently-Asked-Questions).
|
||||
|
||||
## Donations
|
||||
|
||||
If you'd like to support the project financially, Ryujinx has an active Patreon campaign.
|
||||
|
||||
<a href="https://www.patreon.com/ryujinx">
|
||||
<img src="https://images.squarespace-cdn.com/content/v1/560c1d39e4b0b4fae0c9cf2a/1567548955044-WVD994WZP76EWF15T0L3/Patreon+Button.png?format=500w" width="150">
|
||||
</a>
|
||||
|
||||
All developers working on the project do so in their free time, but the project has several expenses:
|
||||
* Hackable Nintendo Switch consoles to reverse-engineer the hardware
|
||||
* Additional computer hardware for testing purposes (e.g. GPUs to diagnose graphical bugs, etc.)
|
||||
* Licenses for various software development tools (e.g. Jetbrains, IDA)
|
||||
* Web hosting and infrastructure maintenance (e.g. LDN servers)
|
||||
|
||||
All funds received through Patreon are considered a donation to support the project. Patrons receive early access to progress reports and exclusive access to developer interviews.
|
||||
|
||||
## License
|
||||
|
||||
This software is licensed under the terms of the [MeloNX license (Based on MIT License)](LICENSE.txt).
|
||||
This software is licensed under the terms of the <a href="https://github.com/Ryujinx/Ryujinx/blob/master/LICENSE.txt" target="_blank">MIT license.</a></i><br />
|
||||
This project makes use of code authored by the libvpx project, licensed under BSD and the ffmpeg project, licensed under LGPLv3.
|
||||
See [LICENSE.txt](LICENSE.txt) and [THIRDPARTY.md](distribution/legal/THIRDPARTY.md) for more details.
|
||||
|
||||
## Credits
|
||||
|
||||
- [Ryujinx](https://github.com/ryujinx-mirror/ryujinx) is used for the base of this emulator. (link is to ryujinx-mirror since they were supportive)
|
||||
- [LibHac](https://github.com/Thealexbarney/LibHac) is used for our file-system.
|
||||
- [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.
|
||||
|
18
Ryujinx.sln
18
Ryujinx.sln
@ -87,6 +87,12 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Horizon", "src\Ryuj
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Horizon.Kernel.Generators", "src\Ryujinx.Horizon.Kernel.Generators\Ryujinx.Horizon.Kernel.Generators.csproj", "{7F55A45D-4E1D-4A36-ADD3-87F29A285AA2}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LibRyujinx.Shared", "src\LibRyujinx\LibRyujinx.csproj", "{5BBF478C-A520-41E7-9B88-890AD26766B8}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.HLE.Generators", "src\Ryujinx.HLE.Generators\Ryujinx.HLE.Generators.csproj", "{C75176EB-C44E-449A-8077-A48AD94534EE}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LibRyujinx.NativeSample", "src\LibRyujinx.NativeSample\LibRyujinx.NativeSample.csproj", "{63D2C96B-5194-4592-BC91-30BEB11C06BD}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
@ -249,6 +255,18 @@ Global
|
||||
{7F55A45D-4E1D-4A36-ADD3-87F29A285AA2}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{7F55A45D-4E1D-4A36-ADD3-87F29A285AA2}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{7F55A45D-4E1D-4A36-ADD3-87F29A285AA2}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{5BBF478C-A520-41E7-9B88-890AD26766B8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{5BBF478C-A520-41E7-9B88-890AD26766B8}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{5BBF478C-A520-41E7-9B88-890AD26766B8}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{5BBF478C-A520-41E7-9B88-890AD26766B8}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{C75176EB-C44E-449A-8077-A48AD94534EE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{C75176EB-C44E-449A-8077-A48AD94534EE}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{C75176EB-C44E-449A-8077-A48AD94534EE}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{C75176EB-C44E-449A-8077-A48AD94534EE}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{63D2C96B-5194-4592-BC91-30BEB11C06BD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{63D2C96B-5194-4592-BC91-30BEB11C06BD}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{63D2C96B-5194-4592-BC91-30BEB11C06BD}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{63D2C96B-5194-4592-BC91-30BEB11C06BD}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
18
compile.sh
18
compile.sh
@ -1,18 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
|
||||
# Define the destination directory (hardcoded)
|
||||
DESTINATION_DIR="src/MeloNX/Dependencies/Dynamic\ Libraries/Ryujinx.Headless.SDL2.dylib"
|
||||
|
||||
# Restore the project
|
||||
dotnet restore
|
||||
|
||||
# Build the project with the specified version
|
||||
dotnet build -c Release
|
||||
|
||||
# Publish the project with the specified runtime and settings
|
||||
dotnet publish -c Release -r ios-arm64 -p:ExtraDefineConstants=DISABLE_UPDATER src/Ryujinx.Headless.SDL2 --self-contained true
|
||||
|
||||
# Move the published .dylib to the specified location
|
||||
mv src/Ryujinx.Headless.SDL2/bin/Release/net8.0/ios-arm64/native/Ryujinx.Headless.SDL2.dylib src/MeloNX/MeloNX/Dependencies/Dynamic\ Libraries/Ryujinx.Headless.SDL2.dylib
|
||||
|
@ -2,6 +2,7 @@
|
||||
<configuration>
|
||||
<packageSources>
|
||||
<clear />
|
||||
<add key="nuget.org" value="https://api.nuget.org/v3/index.json" />
|
||||
<add key="nuget"
|
||||
value="https://api.nuget.org/v3/index.json" />
|
||||
</packageSources>
|
||||
</configuration>
|
||||
|
@ -124,7 +124,7 @@ namespace ARMeilleure.CodeGen.Arm64
|
||||
|
||||
#endregion
|
||||
|
||||
#region macOS
|
||||
#region Darwin
|
||||
|
||||
[LibraryImport("libSystem.dylib", SetLastError = true)]
|
||||
private static unsafe partial int sysctlbyname([MarshalAs(UnmanagedType.LPStr)] string name, out int oldValue, ref ulong oldSize, IntPtr newValue, ulong newValueSize);
|
||||
|
@ -58,9 +58,9 @@ namespace ARMeilleure.CodeGen
|
||||
/// <typeparam name="T">Type of delegate</typeparam>
|
||||
/// <param name="codePointer">Pointer to the function code in memory</param>
|
||||
/// <returns>A delegate of type <typeparamref name="T"/> pointing to the mapped function</returns>
|
||||
public T MapWithPointer<T>(out IntPtr codePointer, bool deferProtect = false)
|
||||
public T MapWithPointer<T>(out IntPtr codePointer)
|
||||
{
|
||||
codePointer = JitCache.Map(this, deferProtect);
|
||||
codePointer = JitCache.Map(this);
|
||||
|
||||
return Marshal.GetDelegateForFunctionPointer<T>(codePointer);
|
||||
}
|
||||
|
@ -157,7 +157,7 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
context.Copy(temp, value);
|
||||
|
||||
if (!context.Memory.Type.IsHostMappedOrTracked())
|
||||
if (!context.Memory.Type.IsHostMapped())
|
||||
{
|
||||
context.Branch(lblEnd);
|
||||
|
||||
@ -198,7 +198,7 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
SetInt(context, rt, value);
|
||||
|
||||
if (!context.Memory.Type.IsHostMappedOrTracked())
|
||||
if (!context.Memory.Type.IsHostMapped())
|
||||
{
|
||||
context.Branch(lblEnd);
|
||||
|
||||
@ -265,7 +265,7 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
context.Copy(GetVec(rt), value);
|
||||
|
||||
if (!context.Memory.Type.IsHostMappedOrTracked())
|
||||
if (!context.Memory.Type.IsHostMapped())
|
||||
{
|
||||
context.Branch(lblEnd);
|
||||
|
||||
@ -312,7 +312,7 @@ namespace ARMeilleure.Instructions
|
||||
break;
|
||||
}
|
||||
|
||||
if (!context.Memory.Type.IsHostMappedOrTracked())
|
||||
if (!context.Memory.Type.IsHostMapped())
|
||||
{
|
||||
context.Branch(lblEnd);
|
||||
|
||||
@ -385,7 +385,7 @@ namespace ARMeilleure.Instructions
|
||||
break;
|
||||
}
|
||||
|
||||
if (!context.Memory.Type.IsHostMappedOrTracked())
|
||||
if (!context.Memory.Type.IsHostMapped())
|
||||
{
|
||||
context.Branch(lblEnd);
|
||||
|
||||
@ -403,21 +403,6 @@ namespace ARMeilleure.Instructions
|
||||
{
|
||||
return EmitHostMappedPointer(context, address);
|
||||
}
|
||||
else if (context.Memory.Type == MemoryManagerType.HostTracked)
|
||||
{
|
||||
Operand ptBase = !context.HasPtc
|
||||
? Const(context.Memory.PageTablePointer.ToInt64())
|
||||
: Const(context.Memory.PageTablePointer.ToInt64(), Ptc.PageTableSymbol);
|
||||
|
||||
Operand ptOffset = context.ShiftRightUI(address, Const(PageBits));
|
||||
|
||||
if (ptOffset.Type == OperandType.I32)
|
||||
{
|
||||
ptOffset = context.ZeroExtend32(OperandType.I64, ptOffset);
|
||||
}
|
||||
|
||||
return context.Add(address, context.Load(OperandType.I64, context.Add(ptBase, context.ShiftLeft(ptOffset, Const(3)))));
|
||||
}
|
||||
|
||||
int ptLevelBits = context.Memory.AddressSpaceBits - PageBits;
|
||||
int ptLevelSize = 1 << ptLevelBits;
|
||||
|
@ -4,7 +4,5 @@ namespace ARMeilleure.Memory
|
||||
{
|
||||
IJitMemoryBlock Allocate(ulong size);
|
||||
IJitMemoryBlock Reserve(ulong size);
|
||||
|
||||
ulong GetPageSize();
|
||||
}
|
||||
}
|
||||
|
@ -18,12 +18,6 @@ namespace ARMeilleure.Memory
|
||||
/// </summary>
|
||||
SoftwarePageTable,
|
||||
|
||||
/// <summary>
|
||||
/// High level implementation using a software flat page table for address translation,
|
||||
/// no support for handling invalid or non-contiguous memory access.
|
||||
/// </summary>
|
||||
HostTracked,
|
||||
|
||||
/// <summary>
|
||||
/// High level implementation with mappings managed by the host OS, effectively using hardware
|
||||
/// page tables. No address translation is performed in software and the memory is just accessed directly.
|
||||
@ -37,16 +31,11 @@ namespace ARMeilleure.Memory
|
||||
HostMappedUnsafe,
|
||||
}
|
||||
|
||||
static class MemoryManagerTypeExtensions
|
||||
public static class MemoryManagerTypeExtensions
|
||||
{
|
||||
public static bool IsHostMapped(this MemoryManagerType type)
|
||||
{
|
||||
return type == MemoryManagerType.HostMapped || type == MemoryManagerType.HostMappedUnsafe;
|
||||
}
|
||||
|
||||
public static bool IsHostMappedOrTracked(this MemoryManagerType type)
|
||||
{
|
||||
return type == MemoryManagerType.HostTracked || type == MemoryManagerType.HostMapped || type == MemoryManagerType.HostMappedUnsafe;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -11,35 +11,4 @@ namespace ARMeilleure.Native
|
||||
[LibraryImport("libarmeilleure-jitsupport", EntryPoint = "armeilleure_jit_memcpy")]
|
||||
public static partial void Copy(IntPtr dst, IntPtr src, ulong n);
|
||||
}
|
||||
|
||||
[SupportedOSPlatform("ios")]
|
||||
internal static partial class JitSupportDarwinAot
|
||||
{
|
||||
[LibraryImport("pthread", EntryPoint = "pthread_jit_write_protect_np")]
|
||||
private static partial void pthread_jit_write_protect_np(int enabled);
|
||||
|
||||
[LibraryImport("libc", EntryPoint = "sys_icache_invalidate")]
|
||||
private static partial void sys_icache_invalidate(IntPtr start, IntPtr length);
|
||||
|
||||
public static unsafe void Copy(IntPtr dst, IntPtr src, ulong n) {
|
||||
// When NativeAOT is in use, we can toggle per-thread write protection without worrying about breaking .NET code.
|
||||
|
||||
// pthread_jit_write_protect_np(0);
|
||||
|
||||
var srcSpan = new Span<byte>(src.ToPointer(), (int)n);
|
||||
var dstSpan = new Span<byte>(dst.ToPointer(), (int)n);
|
||||
srcSpan.CopyTo(dstSpan);
|
||||
|
||||
// pthread_jit_write_protect_np(1);
|
||||
|
||||
// Ensure that the instruction cache for this range is invalidated.
|
||||
sys_icache_invalidate(dst, (IntPtr)n);
|
||||
}
|
||||
|
||||
public static unsafe void Invalidate(IntPtr dst, ulong n)
|
||||
{
|
||||
// Ensure that the instruction cache for this range is invalidated.
|
||||
sys_icache_invalidate(dst, (IntPtr)n);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,63 +1,14 @@
|
||||
using ARMeilleure.IntermediateRepresentation;
|
||||
using ARMeilleure.Memory;
|
||||
using ARMeilleure.IntermediateRepresentation;
|
||||
using ARMeilleure.Translation;
|
||||
using ARMeilleure.Translation.Cache;
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using static ARMeilleure.IntermediateRepresentation.Operand.Factory;
|
||||
|
||||
namespace ARMeilleure.Signal
|
||||
{
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct SignalHandlerRange
|
||||
public static class NativeSignalHandlerGenerator
|
||||
{
|
||||
public int IsActive;
|
||||
public nuint RangeAddress;
|
||||
public nuint RangeEndAddress;
|
||||
public IntPtr ActionPointer;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct SignalHandlerConfig
|
||||
{
|
||||
/// <summary>
|
||||
/// The byte offset of the faulting address in the SigInfo or ExceptionRecord struct.
|
||||
/// </summary>
|
||||
public int StructAddressOffset;
|
||||
|
||||
/// <summary>
|
||||
/// The byte offset of the write flag in the SigInfo or ExceptionRecord struct.
|
||||
/// </summary>
|
||||
public int StructWriteOffset;
|
||||
|
||||
/// <summary>
|
||||
/// The sigaction handler that was registered before this one. (unix only)
|
||||
/// </summary>
|
||||
public nuint UnixOldSigaction;
|
||||
|
||||
/// <summary>
|
||||
/// The type of the previous sigaction. True for the 3 argument variant. (unix only)
|
||||
/// </summary>
|
||||
public int UnixOldSigaction3Arg;
|
||||
|
||||
public SignalHandlerRange Range0;
|
||||
public SignalHandlerRange Range1;
|
||||
public SignalHandlerRange Range2;
|
||||
public SignalHandlerRange Range3;
|
||||
public SignalHandlerRange Range4;
|
||||
public SignalHandlerRange Range5;
|
||||
public SignalHandlerRange Range6;
|
||||
public SignalHandlerRange Range7;
|
||||
}
|
||||
|
||||
public static class NativeSignalHandler
|
||||
{
|
||||
private delegate void UnixExceptionHandler(int sig, IntPtr info, IntPtr ucontext);
|
||||
[UnmanagedFunctionPointer(CallingConvention.Winapi)]
|
||||
private delegate int VectoredExceptionHandler(IntPtr exceptionInfo);
|
||||
|
||||
private const int MaxTrackedRanges = 8;
|
||||
public const int MaxTrackedRanges = 8;
|
||||
|
||||
private const int StructAddressOffset = 0;
|
||||
private const int StructWriteOffset = 4;
|
||||
@ -70,125 +21,10 @@ namespace ARMeilleure.Signal
|
||||
|
||||
private const uint EXCEPTION_ACCESS_VIOLATION = 0xc0000005;
|
||||
|
||||
private static ulong _pageSize;
|
||||
private static ulong _pageMask;
|
||||
|
||||
private static readonly IntPtr _handlerConfig;
|
||||
private static IntPtr _signalHandlerPtr;
|
||||
private static IntPtr _signalHandlerHandle;
|
||||
|
||||
private static readonly object _lock = new();
|
||||
private static bool _initialized;
|
||||
|
||||
static NativeSignalHandler()
|
||||
private static Operand EmitGenericRegionCheck(EmitterContext context, IntPtr signalStructPtr, Operand faultAddress, Operand isWrite, int rangeStructSize, ulong pageSize)
|
||||
{
|
||||
_handlerConfig = Marshal.AllocHGlobal(Unsafe.SizeOf<SignalHandlerConfig>());
|
||||
ref SignalHandlerConfig config = ref GetConfigRef();
|
||||
ulong pageMask = pageSize - 1;
|
||||
|
||||
config = new SignalHandlerConfig();
|
||||
}
|
||||
|
||||
public static void Initialize(IJitMemoryAllocator allocator)
|
||||
{
|
||||
JitCache.Initialize(allocator);
|
||||
}
|
||||
|
||||
public static void InitializeSignalHandler(ulong pageSize, Func<IntPtr, IntPtr, IntPtr> customSignalHandlerFactory = null)
|
||||
{
|
||||
if (_initialized)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
lock (_lock)
|
||||
{
|
||||
if (_initialized)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_pageSize = pageSize;
|
||||
_pageMask = pageSize - 1;
|
||||
|
||||
ref SignalHandlerConfig config = ref GetConfigRef();
|
||||
|
||||
if (OperatingSystem.IsLinux() || OperatingSystem.IsMacOS() || OperatingSystem.IsIOS())
|
||||
{
|
||||
_signalHandlerPtr = Marshal.GetFunctionPointerForDelegate(GenerateUnixSignalHandler(_handlerConfig));
|
||||
|
||||
if (customSignalHandlerFactory != null)
|
||||
{
|
||||
_signalHandlerPtr = customSignalHandlerFactory(UnixSignalHandlerRegistration.GetSegfaultExceptionHandler().sa_handler, _signalHandlerPtr);
|
||||
}
|
||||
|
||||
var old = UnixSignalHandlerRegistration.RegisterExceptionHandler(_signalHandlerPtr);
|
||||
|
||||
config.UnixOldSigaction = (nuint)(ulong)old.sa_handler;
|
||||
config.UnixOldSigaction3Arg = old.sa_flags & 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
config.StructAddressOffset = 40; // ExceptionInformation1
|
||||
config.StructWriteOffset = 32; // ExceptionInformation0
|
||||
|
||||
_signalHandlerPtr = Marshal.GetFunctionPointerForDelegate(GenerateWindowsSignalHandler(_handlerConfig));
|
||||
|
||||
if (customSignalHandlerFactory != null)
|
||||
{
|
||||
_signalHandlerPtr = customSignalHandlerFactory(IntPtr.Zero, _signalHandlerPtr);
|
||||
}
|
||||
|
||||
_signalHandlerHandle = WindowsSignalHandlerRegistration.RegisterExceptionHandler(_signalHandlerPtr);
|
||||
}
|
||||
|
||||
_initialized = true;
|
||||
}
|
||||
}
|
||||
|
||||
private static unsafe ref SignalHandlerConfig GetConfigRef()
|
||||
{
|
||||
return ref Unsafe.AsRef<SignalHandlerConfig>((void*)_handlerConfig);
|
||||
}
|
||||
|
||||
public static unsafe bool AddTrackedRegion(nuint address, nuint endAddress, IntPtr action)
|
||||
{
|
||||
var ranges = &((SignalHandlerConfig*)_handlerConfig)->Range0;
|
||||
|
||||
for (int i = 0; i < MaxTrackedRanges; i++)
|
||||
{
|
||||
if (ranges[i].IsActive == 0)
|
||||
{
|
||||
ranges[i].RangeAddress = address;
|
||||
ranges[i].RangeEndAddress = endAddress;
|
||||
ranges[i].ActionPointer = action;
|
||||
ranges[i].IsActive = 1;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static unsafe bool RemoveTrackedRegion(nuint address)
|
||||
{
|
||||
var ranges = &((SignalHandlerConfig*)_handlerConfig)->Range0;
|
||||
|
||||
for (int i = 0; i < MaxTrackedRanges; i++)
|
||||
{
|
||||
if (ranges[i].IsActive == 1 && ranges[i].RangeAddress == address)
|
||||
{
|
||||
ranges[i].IsActive = 0;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static Operand EmitGenericRegionCheck(EmitterContext context, IntPtr signalStructPtr, Operand faultAddress, Operand isWrite)
|
||||
{
|
||||
Operand inRegionLocal = context.AllocateLocal(OperandType.I32);
|
||||
context.Copy(inRegionLocal, Const(0));
|
||||
|
||||
@ -196,7 +32,7 @@ namespace ARMeilleure.Signal
|
||||
|
||||
for (int i = 0; i < MaxTrackedRanges; i++)
|
||||
{
|
||||
ulong rangeBaseOffset = (ulong)(RangeOffset + i * Unsafe.SizeOf<SignalHandlerRange>());
|
||||
ulong rangeBaseOffset = (ulong)(RangeOffset + i * rangeStructSize);
|
||||
|
||||
Operand nextLabel = Label();
|
||||
|
||||
@ -210,13 +46,12 @@ namespace ARMeilleure.Signal
|
||||
// Is the fault address within this tracked region?
|
||||
Operand inRange = context.BitwiseAnd(
|
||||
context.ICompare(faultAddress, rangeAddress, Comparison.GreaterOrEqualUI),
|
||||
context.ICompare(faultAddress, rangeEndAddress, Comparison.LessUI)
|
||||
);
|
||||
context.ICompare(faultAddress, rangeEndAddress, Comparison.LessUI));
|
||||
|
||||
// Only call tracking if in range.
|
||||
context.BranchIfFalse(nextLabel, inRange, BasicBlockFrequency.Cold);
|
||||
|
||||
Operand offset = context.BitwiseAnd(context.Subtract(faultAddress, rangeAddress), Const(~_pageMask));
|
||||
Operand offset = context.BitwiseAnd(context.Subtract(faultAddress, rangeAddress), Const(~pageMask));
|
||||
|
||||
// Call the tracking action, with the pointer's relative offset to the base address.
|
||||
Operand trackingActionPtr = context.Load(OperandType.I64, Const((ulong)signalStructPtr + rangeBaseOffset + 20));
|
||||
@ -227,7 +62,7 @@ namespace ARMeilleure.Signal
|
||||
|
||||
// Tracking action should be non-null to call it, otherwise assume false return.
|
||||
context.BranchIfFalse(skipActionLabel, trackingActionPtr);
|
||||
Operand result = context.Call(trackingActionPtr, OperandType.I32, offset, Const(_pageSize), isWrite);
|
||||
Operand result = context.Call(trackingActionPtr, OperandType.I32, offset, Const(pageSize), isWrite);
|
||||
context.Copy(inRegionLocal, result);
|
||||
|
||||
context.MarkLabel(skipActionLabel);
|
||||
@ -269,8 +104,7 @@ namespace ARMeilleure.Signal
|
||||
Operand esr = context.Load(OperandType.I64, context.Add(ctxPtr, Const(EsrOffset)));
|
||||
return context.BitwiseAnd(esr, Const(0x40ul));
|
||||
}
|
||||
|
||||
if (RuntimeInformation.ProcessArchitecture == Architecture.X64)
|
||||
else if (RuntimeInformation.ProcessArchitecture == Architecture.X64)
|
||||
{
|
||||
const ulong ErrOffset = 4; // __es.__err
|
||||
Operand err = context.Load(OperandType.I64, context.Add(ctxPtr, Const(ErrOffset)));
|
||||
@ -310,8 +144,7 @@ namespace ARMeilleure.Signal
|
||||
Operand esr = context.Load(OperandType.I64, context.Add(auxPtr, Const(8ul)));
|
||||
return context.BitwiseAnd(esr, Const(0x40ul));
|
||||
}
|
||||
|
||||
if (RuntimeInformation.ProcessArchitecture == Architecture.X64)
|
||||
else if (RuntimeInformation.ProcessArchitecture == Architecture.X64)
|
||||
{
|
||||
const int ErrOffset = 192; // uc_mcontext.gregs[REG_ERR]
|
||||
Operand err = context.Load(OperandType.I64, context.Add(ucontextPtr, Const(ErrOffset)));
|
||||
@ -322,7 +155,7 @@ namespace ARMeilleure.Signal
|
||||
throw new PlatformNotSupportedException();
|
||||
}
|
||||
|
||||
private static UnixExceptionHandler GenerateUnixSignalHandler(IntPtr signalStructPtr)
|
||||
public static byte[] GenerateUnixSignalHandler(IntPtr signalStructPtr, int rangeStructSize, ulong pageSize)
|
||||
{
|
||||
EmitterContext context = new();
|
||||
|
||||
@ -335,7 +168,7 @@ namespace ARMeilleure.Signal
|
||||
|
||||
Operand isWrite = context.ICompareNotEqual(writeFlag, Const(0L)); // Normalize to 0/1.
|
||||
|
||||
Operand isInRegion = EmitGenericRegionCheck(context, signalStructPtr, faultAddress, isWrite);
|
||||
Operand isInRegion = EmitGenericRegionCheck(context, signalStructPtr, faultAddress, isWrite, rangeStructSize, pageSize);
|
||||
|
||||
Operand endLabel = Label();
|
||||
|
||||
@ -367,10 +200,10 @@ namespace ARMeilleure.Signal
|
||||
|
||||
OperandType[] argTypes = new OperandType[] { OperandType.I32, OperandType.I64, OperandType.I64 };
|
||||
|
||||
return Compiler.Compile(cfg, argTypes, OperandType.None, CompilerOptions.HighCq, RuntimeInformation.ProcessArchitecture).Map<UnixExceptionHandler>();
|
||||
return Compiler.Compile(cfg, argTypes, OperandType.None, CompilerOptions.HighCq, RuntimeInformation.ProcessArchitecture).Code;
|
||||
}
|
||||
|
||||
private static VectoredExceptionHandler GenerateWindowsSignalHandler(IntPtr signalStructPtr)
|
||||
public static byte[] GenerateWindowsSignalHandler(IntPtr signalStructPtr, int rangeStructSize, ulong pageSize)
|
||||
{
|
||||
EmitterContext context = new();
|
||||
|
||||
@ -399,7 +232,7 @@ namespace ARMeilleure.Signal
|
||||
|
||||
Operand isWrite = context.ICompareNotEqual(writeFlag, Const(0L)); // Normalize to 0/1.
|
||||
|
||||
Operand isInRegion = EmitGenericRegionCheck(context, signalStructPtr, faultAddress, isWrite);
|
||||
Operand isInRegion = EmitGenericRegionCheck(context, signalStructPtr, faultAddress, isWrite, rangeStructSize, pageSize);
|
||||
|
||||
Operand endLabel = Label();
|
||||
|
||||
@ -421,7 +254,7 @@ namespace ARMeilleure.Signal
|
||||
|
||||
OperandType[] argTypes = new OperandType[] { OperandType.I64 };
|
||||
|
||||
return Compiler.Compile(cfg, argTypes, OperandType.I32, CompilerOptions.HighCq, RuntimeInformation.ProcessArchitecture).Map<VectoredExceptionHandler>();
|
||||
return Compiler.Compile(cfg, argTypes, OperandType.I32, CompilerOptions.HighCq, RuntimeInformation.ProcessArchitecture).Code;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,83 +0,0 @@
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace ARMeilleure.Signal
|
||||
{
|
||||
static partial class UnixSignalHandlerRegistration
|
||||
{
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
public unsafe struct SigSet
|
||||
{
|
||||
fixed long sa_mask[16];
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
public struct SigAction
|
||||
{
|
||||
public IntPtr sa_handler;
|
||||
public SigSet sa_mask;
|
||||
public int sa_flags;
|
||||
public IntPtr sa_restorer;
|
||||
}
|
||||
|
||||
private const int SIGSEGV = 11;
|
||||
private const int SIGBUS = 10;
|
||||
private const int SA_SIGINFO = 0x00000004;
|
||||
|
||||
[LibraryImport("libc", SetLastError = true)]
|
||||
private static partial int sigaction(int signum, ref SigAction sigAction, out SigAction oldAction);
|
||||
|
||||
[LibraryImport("libc", SetLastError = true)]
|
||||
private static partial int sigaction(int signum, IntPtr sigAction, out SigAction oldAction);
|
||||
|
||||
[LibraryImport("libc", SetLastError = true)]
|
||||
private static partial int sigemptyset(ref SigSet set);
|
||||
|
||||
public static SigAction GetSegfaultExceptionHandler()
|
||||
{
|
||||
int result = sigaction(SIGSEGV, IntPtr.Zero, out SigAction old);
|
||||
|
||||
if (result != 0)
|
||||
{
|
||||
throw new InvalidOperationException($"Could not get SIGSEGV sigaction. Error: {result}");
|
||||
}
|
||||
|
||||
return old;
|
||||
}
|
||||
|
||||
public static SigAction RegisterExceptionHandler(IntPtr action)
|
||||
{
|
||||
SigAction sig = new()
|
||||
{
|
||||
sa_handler = action,
|
||||
sa_flags = SA_SIGINFO,
|
||||
};
|
||||
|
||||
sigemptyset(ref sig.sa_mask);
|
||||
|
||||
int result = sigaction(SIGSEGV, ref sig, out SigAction old);
|
||||
|
||||
if (result != 0)
|
||||
{
|
||||
throw new InvalidOperationException($"Could not register SIGSEGV sigaction. Error: {result}");
|
||||
}
|
||||
|
||||
if (OperatingSystem.IsMacOS() || OperatingSystem.IsIOS())
|
||||
{
|
||||
result = sigaction(SIGBUS, ref sig, out _);
|
||||
|
||||
if (result != 0)
|
||||
{
|
||||
throw new InvalidOperationException($"Could not register SIGBUS sigaction. Error: {result}");
|
||||
}
|
||||
}
|
||||
|
||||
return old;
|
||||
}
|
||||
|
||||
public static bool RestoreExceptionHandler(SigAction oldAction)
|
||||
{
|
||||
return sigaction(SIGSEGV, ref oldAction, out SigAction _) == 0 && (!OperatingSystem.IsMacOS() || OperatingSystem.IsIOS() || sigaction(SIGBUS, ref oldAction, out SigAction _) == 0);
|
||||
}
|
||||
}
|
||||
}
|
@ -2,7 +2,7 @@ using ARMeilleure.IntermediateRepresentation;
|
||||
using ARMeilleure.Translation;
|
||||
using Ryujinx.Common.Memory.PartialUnmaps;
|
||||
using System;
|
||||
|
||||
using System.Runtime.InteropServices;
|
||||
using static ARMeilleure.IntermediateRepresentation.Operand.Factory;
|
||||
|
||||
namespace ARMeilleure.Signal
|
||||
@ -10,8 +10,28 @@ namespace ARMeilleure.Signal
|
||||
/// <summary>
|
||||
/// Methods to handle signals caused by partial unmaps. See the structs for C# implementations of the methods.
|
||||
/// </summary>
|
||||
internal static class WindowsPartialUnmapHandler
|
||||
internal static partial class WindowsPartialUnmapHandler
|
||||
{
|
||||
[LibraryImport("kernel32.dll", SetLastError = true, EntryPoint = "LoadLibraryA")]
|
||||
private static partial IntPtr LoadLibrary([MarshalAs(UnmanagedType.LPStr)] string lpFileName);
|
||||
|
||||
[LibraryImport("kernel32.dll", SetLastError = true)]
|
||||
private static partial IntPtr GetProcAddress(IntPtr hModule, [MarshalAs(UnmanagedType.LPStr)] string procName);
|
||||
|
||||
private static IntPtr _getCurrentThreadIdPtr;
|
||||
|
||||
public static IntPtr GetCurrentThreadIdFunc()
|
||||
{
|
||||
if (_getCurrentThreadIdPtr == IntPtr.Zero)
|
||||
{
|
||||
IntPtr handle = LoadLibrary("kernel32.dll");
|
||||
|
||||
_getCurrentThreadIdPtr = GetProcAddress(handle, "GetCurrentThreadId");
|
||||
}
|
||||
|
||||
return _getCurrentThreadIdPtr;
|
||||
}
|
||||
|
||||
public static Operand EmitRetryFromAccessViolation(EmitterContext context)
|
||||
{
|
||||
IntPtr partialRemapStatePtr = PartialUnmapState.GlobalState;
|
||||
@ -20,7 +40,7 @@ namespace ARMeilleure.Signal
|
||||
// Get the lock first.
|
||||
EmitNativeReaderLockAcquire(context, IntPtr.Add(partialRemapStatePtr, PartialUnmapState.PartialUnmapLockOffset));
|
||||
|
||||
IntPtr getCurrentThreadId = WindowsSignalHandlerRegistration.GetCurrentThreadIdFunc();
|
||||
IntPtr getCurrentThreadId = GetCurrentThreadIdFunc();
|
||||
Operand threadId = context.Call(Const((ulong)getCurrentThreadId), OperandType.I32);
|
||||
Operand threadIndex = EmitThreadLocalMapIntGetOrReserve(context, localCountsPtr, threadId, Const(0));
|
||||
|
||||
@ -137,17 +157,6 @@ namespace ARMeilleure.Signal
|
||||
return context.Add(structsPtr, context.SignExtend32(OperandType.I64, offset));
|
||||
}
|
||||
|
||||
#pragma warning disable IDE0051 // Remove unused private member
|
||||
private static void EmitThreadLocalMapIntRelease(EmitterContext context, IntPtr threadLocalMapPtr, Operand threadId, Operand index)
|
||||
{
|
||||
Operand offset = context.Multiply(index, Const(sizeof(int)));
|
||||
Operand idsPtr = Const((ulong)IntPtr.Add(threadLocalMapPtr, ThreadLocalMap<int>.ThreadIdsOffset));
|
||||
Operand idPtr = context.Add(idsPtr, context.SignExtend32(OperandType.I64, offset));
|
||||
|
||||
context.CompareAndSwap(idPtr, threadId, Const(0));
|
||||
}
|
||||
#pragma warning restore IDE0051
|
||||
|
||||
private static void EmitAtomicAddI32(EmitterContext context, Operand ptr, Operand additive)
|
||||
{
|
||||
Operand loop = Label();
|
||||
|
@ -1,44 +0,0 @@
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace ARMeilleure.Signal
|
||||
{
|
||||
unsafe partial class WindowsSignalHandlerRegistration
|
||||
{
|
||||
[LibraryImport("kernel32.dll")]
|
||||
private static partial IntPtr AddVectoredExceptionHandler(uint first, IntPtr handler);
|
||||
|
||||
[LibraryImport("kernel32.dll")]
|
||||
private static partial ulong RemoveVectoredExceptionHandler(IntPtr handle);
|
||||
|
||||
[LibraryImport("kernel32.dll", SetLastError = true, EntryPoint = "LoadLibraryA")]
|
||||
private static partial IntPtr LoadLibrary([MarshalAs(UnmanagedType.LPStr)] string lpFileName);
|
||||
|
||||
[LibraryImport("kernel32.dll", SetLastError = true)]
|
||||
private static partial IntPtr GetProcAddress(IntPtr hModule, [MarshalAs(UnmanagedType.LPStr)] string procName);
|
||||
|
||||
private static IntPtr _getCurrentThreadIdPtr;
|
||||
|
||||
public static IntPtr RegisterExceptionHandler(IntPtr action)
|
||||
{
|
||||
return AddVectoredExceptionHandler(1, action);
|
||||
}
|
||||
|
||||
public static bool RemoveExceptionHandler(IntPtr handle)
|
||||
{
|
||||
return RemoveVectoredExceptionHandler(handle) != 0;
|
||||
}
|
||||
|
||||
public static IntPtr GetCurrentThreadIdFunc()
|
||||
{
|
||||
if (_getCurrentThreadIdPtr == IntPtr.Zero)
|
||||
{
|
||||
IntPtr handle = LoadLibrary("kernel32.dll");
|
||||
|
||||
_getCurrentThreadIdPtr = GetProcAddress(handle, "GetCurrentThreadId");
|
||||
}
|
||||
|
||||
return _getCurrentThreadIdPtr;
|
||||
}
|
||||
}
|
||||
}
|
@ -30,26 +30,21 @@ namespace ARMeilleure.Translation.Cache
|
||||
_blocks.Add(new MemoryBlock(0, capacity));
|
||||
}
|
||||
|
||||
public int Allocate(ref int size, int alignment)
|
||||
public int Allocate(int size)
|
||||
{
|
||||
int alignM1 = alignment - 1;
|
||||
for (int i = 0; i < _blocks.Count; i++)
|
||||
{
|
||||
MemoryBlock block = _blocks[i];
|
||||
int misAlignment = ((block.Offset + alignM1) & (~alignM1)) - block.Offset;
|
||||
int alignedSize = size + misAlignment;
|
||||
|
||||
if (block.Size > alignedSize)
|
||||
if (block.Size > size)
|
||||
{
|
||||
size = alignedSize;
|
||||
_blocks[i] = new MemoryBlock(block.Offset + alignedSize, block.Size - alignedSize);
|
||||
return block.Offset + misAlignment;
|
||||
_blocks[i] = new MemoryBlock(block.Offset + size, block.Size - size);
|
||||
return block.Offset;
|
||||
}
|
||||
else if (block.Size == alignedSize)
|
||||
else if (block.Size == size)
|
||||
{
|
||||
size = alignedSize;
|
||||
_blocks.RemoveAt(i);
|
||||
return block.Offset + misAlignment;
|
||||
return block.Offset;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4,7 +4,6 @@ using ARMeilleure.Memory;
|
||||
using ARMeilleure.Native;
|
||||
using Ryujinx.Memory;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Runtime.InteropServices;
|
||||
@ -15,11 +14,10 @@ namespace ARMeilleure.Translation.Cache
|
||||
static partial class JitCache
|
||||
{
|
||||
private static readonly int _pageSize = (int)MemoryBlock.GetPageSize();
|
||||
private static readonly int _pageMask = _pageSize - 4;
|
||||
private static readonly int _pageMask = _pageSize - 1;
|
||||
|
||||
private const int CodeAlignment = 4; // Bytes.
|
||||
private const int CacheSize = 1024 * 1024 * 1024;
|
||||
private const int CacheSizeIOS = 128 * 1024 * 1024;
|
||||
private const int CacheSize = 2047 * 1024 * 1024;
|
||||
|
||||
private static ReservedRegion _jitRegion;
|
||||
private static JitCacheInvalidation _jitCacheInvalidator;
|
||||
@ -49,9 +47,9 @@ namespace ARMeilleure.Translation.Cache
|
||||
return;
|
||||
}
|
||||
|
||||
_jitRegion = new ReservedRegion(allocator, (ulong)(OperatingSystem.IsIOS() ? CacheSizeIOS : CacheSize));
|
||||
_jitRegion = new ReservedRegion(allocator, CacheSize);
|
||||
|
||||
if (!OperatingSystem.IsWindows() && !OperatingSystem.IsMacOS() && !OperatingSystem.IsIOS())
|
||||
if (!OperatingSystem.IsWindows() && !OperatingSystem.IsMacOS())
|
||||
{
|
||||
_jitCacheInvalidator = new JitCacheInvalidation(allocator);
|
||||
}
|
||||
@ -67,17 +65,7 @@ namespace ARMeilleure.Translation.Cache
|
||||
}
|
||||
}
|
||||
|
||||
static ConcurrentQueue<(int funcOffset, int length)> _deferredRxProtect = new();
|
||||
|
||||
public static void RunDeferredRxProtects()
|
||||
{
|
||||
while (_deferredRxProtect.TryDequeue(out var result))
|
||||
{
|
||||
ReprotectAsExecutable(result.funcOffset, result.length);
|
||||
}
|
||||
}
|
||||
|
||||
public static IntPtr Map(CompiledFunction func, bool deferProtect)
|
||||
public static IntPtr Map(CompiledFunction func)
|
||||
{
|
||||
byte[] code = func.Code;
|
||||
|
||||
@ -85,25 +73,11 @@ namespace ARMeilleure.Translation.Cache
|
||||
{
|
||||
Debug.Assert(_initialized);
|
||||
|
||||
int funcOffset = Allocate(code.Length, deferProtect);
|
||||
int funcOffset = Allocate(code.Length);
|
||||
|
||||
IntPtr funcPtr = _jitRegion.Pointer + funcOffset;
|
||||
|
||||
if (OperatingSystem.IsIOS())
|
||||
{
|
||||
Marshal.Copy(code, 0, funcPtr, code.Length);
|
||||
if (deferProtect)
|
||||
{
|
||||
_deferredRxProtect.Enqueue((funcOffset, code.Length));
|
||||
}
|
||||
else
|
||||
{
|
||||
ReprotectAsExecutable(funcOffset, code.Length);
|
||||
|
||||
JitSupportDarwinAot.Invalidate(funcPtr, (ulong)code.Length);
|
||||
}
|
||||
}
|
||||
else if (OperatingSystem.IsMacOS()&& RuntimeInformation.ProcessArchitecture == Architecture.Arm64)
|
||||
if (OperatingSystem.IsMacOS() && RuntimeInformation.ProcessArchitecture == Architecture.Arm64)
|
||||
{
|
||||
unsafe
|
||||
{
|
||||
@ -137,11 +111,6 @@ namespace ARMeilleure.Translation.Cache
|
||||
|
||||
public static void Unmap(IntPtr pointer)
|
||||
{
|
||||
if (OperatingSystem.IsIOS())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
lock (_lock)
|
||||
{
|
||||
Debug.Assert(_initialized);
|
||||
@ -176,22 +145,11 @@ namespace ARMeilleure.Translation.Cache
|
||||
_jitRegion.Block.MapAsRx((ulong)regionStart, (ulong)(regionEnd - regionStart));
|
||||
}
|
||||
|
||||
private static int Allocate(int codeSize, bool deferProtect = false)
|
||||
private static int Allocate(int codeSize)
|
||||
{
|
||||
codeSize = AlignCodeSize(codeSize, deferProtect);
|
||||
codeSize = AlignCodeSize(codeSize);
|
||||
|
||||
int alignment = CodeAlignment;
|
||||
|
||||
if (OperatingSystem.IsIOS() && !deferProtect)
|
||||
{
|
||||
alignment = 0x4000;
|
||||
}
|
||||
|
||||
int allocOffset = _cacheAllocator.Allocate(ref codeSize, alignment);
|
||||
|
||||
//DEBUG: Show JIT Memory Allocation
|
||||
|
||||
//Console.WriteLine($"{allocOffset:x8}: {codeSize:x8} {alignment:x8}");
|
||||
int allocOffset = _cacheAllocator.Allocate(codeSize);
|
||||
|
||||
if (allocOffset < 0)
|
||||
{
|
||||
@ -203,16 +161,9 @@ namespace ARMeilleure.Translation.Cache
|
||||
return allocOffset;
|
||||
}
|
||||
|
||||
private static int AlignCodeSize(int codeSize, bool deferProtect = false)
|
||||
private static int AlignCodeSize(int codeSize)
|
||||
{
|
||||
int alignment = CodeAlignment;
|
||||
|
||||
if (OperatingSystem.IsIOS() && !deferProtect)
|
||||
{
|
||||
alignment = 0x4000;
|
||||
}
|
||||
|
||||
return checked(codeSize + (alignment - 1)) & ~(alignment - 1);
|
||||
return checked(codeSize + (CodeAlignment - 1)) & ~(CodeAlignment - 1);
|
||||
}
|
||||
|
||||
private static void Add(int offset, int size, UnwindInfo unwindInfo)
|
||||
|
@ -114,7 +114,7 @@ namespace ARMeilleure.Translation.Cache
|
||||
{
|
||||
int stackOffset = entry.StackOffsetOrAllocSize;
|
||||
|
||||
// Debug.Assert(stackOffset % 16 == 0);
|
||||
Debug.Assert(stackOffset % 16 == 0);
|
||||
|
||||
if (stackOffset <= 0xFFFF0)
|
||||
{
|
||||
@ -135,7 +135,7 @@ namespace ARMeilleure.Translation.Cache
|
||||
{
|
||||
int allocSize = entry.StackOffsetOrAllocSize;
|
||||
|
||||
// Debug.Assert(allocSize % 8 == 0);
|
||||
Debug.Assert(allocSize % 8 == 0);
|
||||
|
||||
if (allocSize <= 128)
|
||||
{
|
||||
|
@ -3,7 +3,6 @@ using ARMeilleure.CodeGen.Linking;
|
||||
using ARMeilleure.CodeGen.Unwinding;
|
||||
using ARMeilleure.Common;
|
||||
using ARMeilleure.Memory;
|
||||
using ARMeilleure.Translation.Cache;
|
||||
using Ryujinx.Common;
|
||||
using Ryujinx.Common.Configuration;
|
||||
using Ryujinx.Common.Logging;
|
||||
@ -414,8 +413,6 @@ namespace ARMeilleure.Translation.PTC
|
||||
finally
|
||||
{
|
||||
ResetCarriersIfNeeded();
|
||||
|
||||
GCSettings.LargeObjectHeapCompactionMode = GCLargeObjectHeapCompactionMode.CompactOnce;
|
||||
}
|
||||
|
||||
_waitEvent.Set();
|
||||
@ -745,7 +742,7 @@ namespace ARMeilleure.Translation.PTC
|
||||
bool highCq)
|
||||
{
|
||||
var cFunc = new CompiledFunction(code, unwindInfo, RelocInfo.Empty);
|
||||
var gFunc = cFunc.MapWithPointer<GuestFunction>(out IntPtr gFuncPointer, true);
|
||||
var gFunc = cFunc.MapWithPointer<GuestFunction>(out IntPtr gFuncPointer);
|
||||
|
||||
return new TranslatedFunction(gFunc, gFuncPointer, callCounter, guestSize, highCq);
|
||||
}
|
||||
@ -791,8 +788,6 @@ namespace ARMeilleure.Translation.PTC
|
||||
{
|
||||
ResetCarriersIfNeeded();
|
||||
|
||||
GCSettings.LargeObjectHeapCompactionMode = GCLargeObjectHeapCompactionMode.CompactOnce;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@ -827,7 +822,7 @@ namespace ARMeilleure.Translation.PTC
|
||||
|
||||
Debug.Assert(Profiler.IsAddressInStaticCodeRange(address));
|
||||
|
||||
TranslatedFunction func = translator.Translate(address, item.funcProfile.Mode, item.funcProfile.HighCq, deferProtect: true);
|
||||
TranslatedFunction func = translator.Translate(address, item.funcProfile.Mode, item.funcProfile.HighCq);
|
||||
|
||||
bool isAddressUnique = translator.Functions.TryAdd(address, func.GuestSize, func);
|
||||
|
||||
@ -1005,7 +1000,7 @@ namespace ARMeilleure.Translation.PTC
|
||||
osPlatform |= (OperatingSystem.IsLinux() ? 1u : 0u) << 1;
|
||||
osPlatform |= (OperatingSystem.IsMacOS() ? 1u : 0u) << 2;
|
||||
osPlatform |= (OperatingSystem.IsWindows() ? 1u : 0u) << 3;
|
||||
osPlatform |= (OperatingSystem.IsIOS() ? 1u : 0u) << 4;
|
||||
osPlatform |= (Ryujinx.Common.PlatformInfo.IsBionic ? 1u : 0u) << 4;
|
||||
#pragma warning restore IDE0055
|
||||
|
||||
return osPlatform;
|
||||
|
@ -57,9 +57,6 @@ namespace ARMeilleure.Translation
|
||||
private Thread[] _backgroundTranslationThreads;
|
||||
private volatile int _threadCount;
|
||||
|
||||
// FIXME: Remove this once the init logic of the emulator will be redone.
|
||||
public static readonly ManualResetEvent IsReadyForTranslation = new(false);
|
||||
|
||||
public Translator(IJitMemoryAllocator allocator, IMemoryManager memory, bool for64Bits)
|
||||
{
|
||||
_allocator = allocator;
|
||||
@ -79,11 +76,6 @@ namespace ARMeilleure.Translation
|
||||
Stubs = new TranslatorStubs(FunctionTable);
|
||||
|
||||
FunctionTable.Fill = (ulong)Stubs.SlowDispatchStub;
|
||||
|
||||
if (memory.Type.IsHostMappedOrTracked())
|
||||
{
|
||||
NativeSignalHandler.InitializeSignalHandler(allocator.GetPageSize());
|
||||
}
|
||||
}
|
||||
|
||||
public IPtcLoadState LoadDiskCache(string titleIdText, string displayVersion, bool enabled)
|
||||
@ -105,15 +97,11 @@ namespace ARMeilleure.Translation
|
||||
{
|
||||
if (Interlocked.Increment(ref _threadCount) == 1)
|
||||
{
|
||||
IsReadyForTranslation.WaitOne();
|
||||
|
||||
if (_ptc.State == PtcState.Enabled)
|
||||
{
|
||||
Debug.Assert(Functions.Count == 0);
|
||||
_ptc.LoadTranslations(this);
|
||||
_ptc.MakeAndSaveTranslations(this);
|
||||
|
||||
JitCache.RunDeferredRxProtects();
|
||||
}
|
||||
|
||||
_ptc.Profiler.Start();
|
||||
@ -252,7 +240,7 @@ namespace ARMeilleure.Translation
|
||||
}
|
||||
}
|
||||
|
||||
internal TranslatedFunction Translate(ulong address, ExecutionMode mode, bool highCq, bool singleStep = false, bool deferProtect = false)
|
||||
internal TranslatedFunction Translate(ulong address, ExecutionMode mode, bool highCq, bool singleStep = false)
|
||||
{
|
||||
var context = new ArmEmitterContext(
|
||||
Memory,
|
||||
@ -310,7 +298,7 @@ namespace ARMeilleure.Translation
|
||||
_ptc.WriteCompiledFunction(address, funcSize, hash, highCq, compiledFunc);
|
||||
}
|
||||
|
||||
GuestFunction func = compiledFunc.MapWithPointer<GuestFunction>(out IntPtr funcPointer, deferProtect);
|
||||
GuestFunction func = compiledFunc.MapWithPointer<GuestFunction>(out IntPtr funcPointer);
|
||||
|
||||
Allocators.ResetAll();
|
||||
|
||||
|
15
src/LibRyujinx.NativeSample/LibRyujinx.NativeSample.csproj
Normal file
15
src/LibRyujinx.NativeSample/LibRyujinx.NativeSample.csproj
Normal file
@ -0,0 +1,15 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net7.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="OpenTK" />
|
||||
<PackageReference Include="Ryujinx.SDL2-CS" />
|
||||
</ItemGroup>
|
||||
</Project>
|
183
src/LibRyujinx.NativeSample/LibRyujinxInterop.cs
Normal file
183
src/LibRyujinx.NativeSample/LibRyujinxInterop.cs
Normal file
@ -0,0 +1,183 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Numerics;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace LibRyujinx.Sample
|
||||
{
|
||||
internal static class LibRyujinxInterop
|
||||
{
|
||||
private const string dll = "LibRyujinx.dll";
|
||||
|
||||
[DllImport(dll, EntryPoint = "initialize")]
|
||||
public extern static bool Initialize(IntPtr path);
|
||||
|
||||
|
||||
[DllImport(dll, EntryPoint = "graphics_initialize")]
|
||||
public extern static bool InitializeGraphics(GraphicsConfiguration graphicsConfiguration);
|
||||
|
||||
[DllImport(dll, EntryPoint = "device_initialize")]
|
||||
internal extern static bool InitializeDevice();
|
||||
|
||||
[DllImport(dll, EntryPoint = "graphics_initialize_renderer")]
|
||||
internal extern static bool InitializeGraphicsRenderer(GraphicsBackend backend, NativeGraphicsInterop nativeGraphicsInterop);
|
||||
|
||||
[DllImport(dll, EntryPoint = "device_load")]
|
||||
internal extern static bool LoadApplication(IntPtr pathPtr);
|
||||
|
||||
[DllImport(dll, EntryPoint = "graphics_renderer_run_loop")]
|
||||
internal extern static void RunLoop();
|
||||
|
||||
[DllImport(dll, EntryPoint = "graphics_renderer_set_size")]
|
||||
internal extern static void SetRendererSize(int width, int height);
|
||||
|
||||
[DllImport(dll, EntryPoint = "graphics_renderer_set_swap_buffer_callback")]
|
||||
internal extern static void SetSwapBuffersCallback(IntPtr swapBuffers);
|
||||
|
||||
[DllImport(dll, EntryPoint = "graphics_renderer_set_vsync")]
|
||||
internal extern static void SetVsyncState(bool enabled);
|
||||
|
||||
[DllImport(dll, EntryPoint = "input_initialize")]
|
||||
internal extern static void InitializeInput(int width, int height);
|
||||
|
||||
[DllImport(dll, EntryPoint = "input_set_client_size")]
|
||||
internal extern static void SetClientSize(int width, int height);
|
||||
|
||||
[DllImport(dll, EntryPoint = "input_set_touch_point")]
|
||||
internal extern static void SetTouchPoint(int x, int y);
|
||||
|
||||
[DllImport(dll, EntryPoint = "input_release_touch_point")]
|
||||
internal extern static void ReleaseTouchPoint();
|
||||
|
||||
[DllImport(dll, EntryPoint = "input_update")]
|
||||
internal extern static void UpdateInput();
|
||||
|
||||
[DllImport(dll, EntryPoint = "input_set_button_pressed")]
|
||||
public extern static void SetButtonPressed(GamepadButtonInputId button, IntPtr idPtr);
|
||||
|
||||
[DllImport(dll, EntryPoint = "input_set_button_released")]
|
||||
public extern static void SetButtonReleased(GamepadButtonInputId button, IntPtr idPtr);
|
||||
|
||||
[DllImport(dll, EntryPoint = "input_set_stick_axis")]
|
||||
public extern static void SetStickAxis(StickInputId stick, Vector2 axes, IntPtr idPtr);
|
||||
|
||||
[DllImport(dll, EntryPoint = "input_connect_gamepad")]
|
||||
public extern static IntPtr ConnectGamepad(int index);
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct GraphicsConfiguration
|
||||
{
|
||||
public float ResScale = 1f;
|
||||
public float MaxAnisotropy = -1;
|
||||
public bool FastGpuTime = true;
|
||||
public bool Fast2DCopy = true;
|
||||
public bool EnableMacroJit = false;
|
||||
public bool EnableMacroHLE = true;
|
||||
public bool EnableShaderCache = true;
|
||||
public bool EnableTextureRecompression = false;
|
||||
public BackendThreading BackendThreading = BackendThreading.Auto;
|
||||
public AspectRatio AspectRatio = AspectRatio.Fixed16x9;
|
||||
|
||||
public GraphicsConfiguration()
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public enum GraphicsBackend
|
||||
{
|
||||
Vulkan,
|
||||
OpenGl
|
||||
}
|
||||
public enum BackendThreading
|
||||
{
|
||||
Auto,
|
||||
Off,
|
||||
On
|
||||
}
|
||||
|
||||
public struct NativeGraphicsInterop
|
||||
{
|
||||
public IntPtr GlGetProcAddress;
|
||||
public IntPtr VkNativeContextLoader;
|
||||
public IntPtr VkCreateSurface;
|
||||
public IntPtr VkRequiredExtensions;
|
||||
public int VkRequiredExtensionsCount;
|
||||
}
|
||||
public enum AspectRatio
|
||||
{
|
||||
Fixed4x3,
|
||||
Fixed16x9,
|
||||
Fixed16x10,
|
||||
Fixed21x9,
|
||||
Fixed32x9,
|
||||
Stretched
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Represent a button from a gamepad.
|
||||
/// </summary>
|
||||
public enum GamepadButtonInputId : byte
|
||||
{
|
||||
Unbound,
|
||||
A,
|
||||
B,
|
||||
X,
|
||||
Y,
|
||||
LeftStick,
|
||||
RightStick,
|
||||
LeftShoulder,
|
||||
RightShoulder,
|
||||
|
||||
// Likely axis
|
||||
LeftTrigger,
|
||||
// Likely axis
|
||||
RightTrigger,
|
||||
|
||||
DpadUp,
|
||||
DpadDown,
|
||||
DpadLeft,
|
||||
DpadRight,
|
||||
|
||||
// Special buttons
|
||||
|
||||
Minus,
|
||||
Plus,
|
||||
|
||||
Back = Minus,
|
||||
Start = Plus,
|
||||
|
||||
Guide,
|
||||
Misc1,
|
||||
|
||||
// Xbox Elite paddle
|
||||
Paddle1,
|
||||
Paddle2,
|
||||
Paddle3,
|
||||
Paddle4,
|
||||
|
||||
// PS5 touchpad button
|
||||
Touchpad,
|
||||
|
||||
// Virtual buttons for single joycon
|
||||
SingleLeftTrigger0,
|
||||
SingleRightTrigger0,
|
||||
|
||||
SingleLeftTrigger1,
|
||||
SingleRightTrigger1,
|
||||
|
||||
Count
|
||||
}
|
||||
|
||||
public enum StickInputId : byte
|
||||
{
|
||||
Unbound,
|
||||
Left,
|
||||
Right,
|
||||
|
||||
Count
|
||||
}
|
||||
}
|
249
src/LibRyujinx.NativeSample/NativeWindow.cs
Normal file
249
src/LibRyujinx.NativeSample/NativeWindow.cs
Normal file
@ -0,0 +1,249 @@
|
||||
using LibRyujinx.Sample;
|
||||
using OpenTK.Graphics.OpenGL;
|
||||
using OpenTK.Mathematics;
|
||||
using OpenTK.Windowing.Common;
|
||||
using OpenTK.Windowing.Desktop;
|
||||
using OpenTK.Windowing.GraphicsLibraryFramework;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace LibRyujinx.NativeSample
|
||||
{
|
||||
internal class NativeWindow : OpenTK.Windowing.Desktop.NativeWindow
|
||||
{
|
||||
private nint del;
|
||||
public delegate void SwapBuffersCallback();
|
||||
public delegate IntPtr GetProcAddress(string name);
|
||||
public delegate IntPtr CreateSurface(IntPtr instance);
|
||||
|
||||
private bool _run;
|
||||
private bool _isVulkan;
|
||||
private Vector2 _lastPosition;
|
||||
private bool _mousePressed;
|
||||
private nint _gamepadIdPtr;
|
||||
private string? _gamepadId;
|
||||
|
||||
public NativeWindow(NativeWindowSettings nativeWindowSettings) : base(nativeWindowSettings)
|
||||
{
|
||||
_isVulkan = true;
|
||||
}
|
||||
|
||||
internal unsafe void Start(string gamePath)
|
||||
{
|
||||
if (!_isVulkan)
|
||||
{
|
||||
MakeCurrent();
|
||||
}
|
||||
|
||||
var getProcAddress = Marshal.GetFunctionPointerForDelegate<GetProcAddress>(x => GLFW.GetProcAddress(x));
|
||||
var createSurface = Marshal.GetFunctionPointerForDelegate<CreateSurface>( x =>
|
||||
{
|
||||
VkHandle surface;
|
||||
GLFW.CreateWindowSurface(new VkHandle(x) ,this.WindowPtr, null, out surface);
|
||||
|
||||
return surface.Handle;
|
||||
});
|
||||
var vkExtensions = GLFW.GetRequiredInstanceExtensions();
|
||||
|
||||
|
||||
var pointers = new IntPtr[vkExtensions.Length];
|
||||
for (int i = 0; i < vkExtensions.Length; i++)
|
||||
{
|
||||
pointers[i] = Marshal.StringToHGlobalAnsi(vkExtensions[i]);
|
||||
}
|
||||
|
||||
fixed (IntPtr* ptr = pointers)
|
||||
{
|
||||
var nativeGraphicsInterop = new NativeGraphicsInterop()
|
||||
{
|
||||
GlGetProcAddress = getProcAddress,
|
||||
VkRequiredExtensions = (nint)ptr,
|
||||
VkRequiredExtensionsCount = pointers.Length,
|
||||
VkCreateSurface = createSurface
|
||||
};
|
||||
var success = LibRyujinxInterop.InitializeGraphicsRenderer(_isVulkan ? GraphicsBackend.Vulkan : GraphicsBackend.OpenGl, nativeGraphicsInterop);
|
||||
success = LibRyujinxInterop.InitializeDevice();
|
||||
LibRyujinxInterop.InitializeInput(ClientSize.X, ClientSize.Y);
|
||||
|
||||
var path = Marshal.StringToHGlobalAnsi(gamePath);
|
||||
var loaded = LibRyujinxInterop.LoadApplication(path);
|
||||
LibRyujinxInterop.SetRendererSize(Size.X, Size.Y);
|
||||
Marshal.FreeHGlobal(path);
|
||||
}
|
||||
|
||||
_gamepadIdPtr = LibRyujinxInterop.ConnectGamepad(0);
|
||||
_gamepadId = Marshal.PtrToStringAnsi(_gamepadIdPtr);
|
||||
|
||||
if (!_isVulkan)
|
||||
{
|
||||
Context.MakeNoneCurrent();
|
||||
}
|
||||
|
||||
_run = true;
|
||||
var thread = new Thread(new ThreadStart(RunLoop));
|
||||
thread.Start();
|
||||
|
||||
UpdateLoop();
|
||||
|
||||
thread.Join();
|
||||
|
||||
foreach(var ptr in pointers)
|
||||
{
|
||||
Marshal.FreeHGlobal(ptr);
|
||||
}
|
||||
|
||||
Marshal.FreeHGlobal(_gamepadIdPtr);
|
||||
}
|
||||
|
||||
public void RunLoop()
|
||||
{
|
||||
del = Marshal.GetFunctionPointerForDelegate<SwapBuffersCallback>(SwapBuffers);
|
||||
LibRyujinxInterop.SetSwapBuffersCallback(del);
|
||||
|
||||
if (!_isVulkan)
|
||||
{
|
||||
MakeCurrent();
|
||||
|
||||
Context.SwapInterval = 0;
|
||||
}
|
||||
|
||||
/* Task.Run(async () =>
|
||||
{
|
||||
await Task.Delay(1000);
|
||||
|
||||
LibRyujinxInterop.SetVsyncState(true);
|
||||
});*/
|
||||
|
||||
LibRyujinxInterop.RunLoop();
|
||||
|
||||
_run = false;
|
||||
|
||||
if (!_isVulkan)
|
||||
{
|
||||
Context.MakeNoneCurrent();
|
||||
}
|
||||
}
|
||||
|
||||
private void SwapBuffers()
|
||||
{
|
||||
if (!_isVulkan)
|
||||
{
|
||||
this.Context.SwapBuffers();
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnMouseMove(MouseMoveEventArgs e)
|
||||
{
|
||||
base.OnMouseMove(e);
|
||||
_lastPosition = e.Position;
|
||||
}
|
||||
|
||||
protected override void OnMouseDown(MouseButtonEventArgs e)
|
||||
{
|
||||
base.OnMouseDown(e);
|
||||
if(e.Button == MouseButton.Left)
|
||||
{
|
||||
_mousePressed = true;
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnResize(ResizeEventArgs e)
|
||||
{
|
||||
base.OnResize(e);
|
||||
|
||||
if (_run)
|
||||
{
|
||||
LibRyujinxInterop.SetRendererSize(e.Width, e.Height);
|
||||
LibRyujinxInterop.SetClientSize(e.Width, e.Height);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnMouseUp(MouseButtonEventArgs e)
|
||||
{
|
||||
base.OnMouseUp(e);
|
||||
if (e.Button == MouseButton.Left)
|
||||
{
|
||||
_mousePressed = false;
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnKeyUp(KeyboardKeyEventArgs e)
|
||||
{
|
||||
base.OnKeyUp(e);
|
||||
|
||||
if (_gamepadIdPtr != IntPtr.Zero)
|
||||
{
|
||||
var key = GetKeyMapping(e.Key);
|
||||
|
||||
LibRyujinxInterop.SetButtonReleased(key, _gamepadIdPtr);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnKeyDown(KeyboardKeyEventArgs e)
|
||||
{
|
||||
base.OnKeyDown(e);
|
||||
|
||||
if (_gamepadIdPtr != IntPtr.Zero)
|
||||
{
|
||||
var key = GetKeyMapping(e.Key);
|
||||
|
||||
LibRyujinxInterop.SetButtonPressed(key, _gamepadIdPtr);
|
||||
}
|
||||
}
|
||||
|
||||
public void UpdateLoop()
|
||||
{
|
||||
while(_run)
|
||||
{
|
||||
ProcessWindowEvents(true);
|
||||
ProcessInputEvents();
|
||||
ProcessWindowEvents(IsEventDriven);
|
||||
if (_mousePressed)
|
||||
{
|
||||
LibRyujinxInterop.SetTouchPoint((int)_lastPosition.X, (int)_lastPosition.Y);
|
||||
}
|
||||
else
|
||||
{
|
||||
LibRyujinxInterop.ReleaseTouchPoint();
|
||||
}
|
||||
|
||||
LibRyujinxInterop.UpdateInput();
|
||||
|
||||
Thread.Sleep(1);
|
||||
}
|
||||
}
|
||||
|
||||
public GamepadButtonInputId GetKeyMapping(Keys key)
|
||||
{
|
||||
if(_keyMapping.TryGetValue(key, out var mapping))
|
||||
{
|
||||
return mapping;
|
||||
}
|
||||
|
||||
return GamepadButtonInputId.Unbound;
|
||||
}
|
||||
|
||||
private Dictionary<Keys, GamepadButtonInputId> _keyMapping = new Dictionary<Keys, GamepadButtonInputId>()
|
||||
{
|
||||
{Keys.A, GamepadButtonInputId.A },
|
||||
{Keys.S, GamepadButtonInputId.B },
|
||||
{Keys.Z, GamepadButtonInputId.X },
|
||||
{Keys.X, GamepadButtonInputId.Y },
|
||||
{Keys.Equal, GamepadButtonInputId.Plus },
|
||||
{Keys.Minus, GamepadButtonInputId.Minus },
|
||||
{Keys.Q, GamepadButtonInputId.LeftShoulder },
|
||||
{Keys.D1, GamepadButtonInputId.LeftTrigger },
|
||||
{Keys.W, GamepadButtonInputId.RightShoulder },
|
||||
{Keys.D2, GamepadButtonInputId.RightTrigger },
|
||||
{Keys.E, GamepadButtonInputId.LeftStick },
|
||||
{Keys.R, GamepadButtonInputId.RightStick },
|
||||
{Keys.Up, GamepadButtonInputId.DpadUp },
|
||||
{Keys.Down, GamepadButtonInputId.DpadDown },
|
||||
{Keys.Left, GamepadButtonInputId.DpadLeft },
|
||||
{Keys.Right, GamepadButtonInputId.DpadRight },
|
||||
{Keys.U, GamepadButtonInputId.SingleLeftTrigger0 },
|
||||
{Keys.D7, GamepadButtonInputId.SingleLeftTrigger1 },
|
||||
{Keys.O, GamepadButtonInputId.SingleRightTrigger0 },
|
||||
{Keys.D9, GamepadButtonInputId.SingleRightTrigger1 }
|
||||
};
|
||||
}
|
||||
}
|
33
src/LibRyujinx.NativeSample/Program.cs
Normal file
33
src/LibRyujinx.NativeSample/Program.cs
Normal file
@ -0,0 +1,33 @@
|
||||
using LibRyujinx.Sample;
|
||||
using OpenTK.Mathematics;
|
||||
using OpenTK.Windowing.Common;
|
||||
using OpenTK.Windowing.Desktop;
|
||||
|
||||
namespace LibRyujinx.NativeSample
|
||||
{
|
||||
internal class Program
|
||||
{
|
||||
static void Main(string[] args)
|
||||
{
|
||||
if (args.Length > 0)
|
||||
{
|
||||
var success = LibRyujinxInterop.Initialize(IntPtr.Zero);
|
||||
success = LibRyujinxInterop.InitializeGraphics(new GraphicsConfiguration());
|
||||
var nativeWindowSettings = new NativeWindowSettings()
|
||||
{
|
||||
Size = new Vector2i(800, 600),
|
||||
Title = "Ryujinx",
|
||||
API = ContextAPI.NoAPI,
|
||||
IsEventDriven = false,
|
||||
// This is needed to run on macos
|
||||
Flags = ContextFlags.ForwardCompatible,
|
||||
};
|
||||
|
||||
using var window = new NativeWindow(nativeWindowSettings);
|
||||
|
||||
window.IsVisible = true;
|
||||
window.Start(args[0]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
49
src/LibRyujinx/Android/AndroidLogTarget.cs
Normal file
49
src/LibRyujinx/Android/AndroidLogTarget.cs
Normal file
@ -0,0 +1,49 @@
|
||||
using Ryujinx.Common.Logging;
|
||||
using Ryujinx.Common.Logging.Formatters;
|
||||
using Ryujinx.Common.Logging.Targets;
|
||||
using System;
|
||||
|
||||
namespace LibRyujinx
|
||||
{
|
||||
public class AndroidLogTarget : ILogTarget
|
||||
{
|
||||
private readonly string _name;
|
||||
private readonly DefaultLogFormatter _formatter;
|
||||
|
||||
string ILogTarget.Name { get => _name; }
|
||||
|
||||
public AndroidLogTarget(string name)
|
||||
{
|
||||
_name = name;
|
||||
_formatter = new DefaultLogFormatter();
|
||||
}
|
||||
|
||||
public void Log(object sender, LogEventArgs args)
|
||||
{
|
||||
Logcat.AndroidLogPrint(GetLogLevel(args.Level), _name, _formatter.Format(args));
|
||||
}
|
||||
|
||||
private static Logcat.LogLevel GetLogLevel(LogLevel logLevel)
|
||||
{
|
||||
return logLevel switch
|
||||
{
|
||||
LogLevel.Debug => Logcat.LogLevel.Debug,
|
||||
LogLevel.Stub => Logcat.LogLevel.Info,
|
||||
LogLevel.Info => Logcat.LogLevel.Info,
|
||||
LogLevel.Warning => Logcat.LogLevel.Warn,
|
||||
LogLevel.Error => Logcat.LogLevel.Error,
|
||||
LogLevel.Guest => Logcat.LogLevel.Info,
|
||||
LogLevel.AccessLog => Logcat.LogLevel.Info,
|
||||
LogLevel.Notice => Logcat.LogLevel.Info,
|
||||
LogLevel.Trace => Logcat.LogLevel.Verbose,
|
||||
_ => throw new NotImplementedException(),
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
}
|
||||
}
|
136
src/LibRyujinx/Android/AndroidUiHandler.cs
Normal file
136
src/LibRyujinx/Android/AndroidUiHandler.cs
Normal file
@ -0,0 +1,136 @@
|
||||
using LibHac.Tools.Fs;
|
||||
using Ryujinx.Common.Logging;
|
||||
using Ryujinx.HLE;
|
||||
using Ryujinx.HLE.HOS.Applets;
|
||||
using Ryujinx.HLE.HOS.Services.Am.AppletOE.ApplicationProxyService.ApplicationProxy.Types;
|
||||
using Ryujinx.HLE.Ui;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace LibRyujinx.Android
|
||||
{
|
||||
internal class AndroidUiHandler : IHostUiHandler, IDisposable
|
||||
{
|
||||
public IHostUiTheme HostUiTheme => throw new NotImplementedException();
|
||||
|
||||
public ManualResetEvent _waitEvent;
|
||||
public ManualResetEvent _responseEvent;
|
||||
private bool _isDisposed;
|
||||
private bool _isOkPressed;
|
||||
private long _input;
|
||||
|
||||
public AndroidUiHandler()
|
||||
{
|
||||
_waitEvent = new ManualResetEvent(false);
|
||||
_responseEvent = new ManualResetEvent(false);
|
||||
}
|
||||
|
||||
public IDynamicTextInputHandler CreateDynamicTextInputHandler()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public bool DisplayErrorAppletDialog(string title, string message, string[] buttonsText)
|
||||
{
|
||||
LibRyujinx.setUiHandlerTitle(LibRyujinx.storeString(title ?? ""));
|
||||
LibRyujinx.setUiHandlerMessage(LibRyujinx.storeString(message ?? ""));
|
||||
LibRyujinx.setUiHandlerType(1);
|
||||
|
||||
_responseEvent.Reset();
|
||||
Set();
|
||||
_responseEvent.WaitOne();
|
||||
|
||||
return _isOkPressed;
|
||||
}
|
||||
|
||||
public bool DisplayInputDialog(SoftwareKeyboardUiArgs args, out string userText)
|
||||
{
|
||||
LibRyujinx.setUiHandlerTitle(LibRyujinx.storeString("Software Keyboard"));
|
||||
LibRyujinx.setUiHandlerMessage(LibRyujinx.storeString(args.HeaderText ?? ""));
|
||||
LibRyujinx.setUiHandlerWatermark(LibRyujinx.storeString(args.GuideText ?? ""));
|
||||
LibRyujinx.setUiHandlerSubtitle(LibRyujinx.storeString(args.SubtitleText ?? ""));
|
||||
LibRyujinx.setUiHandlerInitialText(LibRyujinx.storeString(args.InitialText ?? ""));
|
||||
LibRyujinx.setUiHandlerMinLength(args.StringLengthMin);
|
||||
LibRyujinx.setUiHandlerMaxLength(args.StringLengthMax);
|
||||
LibRyujinx.setUiHandlerType(2);
|
||||
LibRyujinx.setUiHandlerKeyboardMode((int)args.KeyboardMode);
|
||||
|
||||
_responseEvent.Reset();
|
||||
Set();
|
||||
_responseEvent.WaitOne();
|
||||
|
||||
userText = _input != -1 ? LibRyujinx.GetStoredString(_input) : "";
|
||||
|
||||
return _isOkPressed;
|
||||
}
|
||||
|
||||
public bool DisplayMessageDialog(string title, string message)
|
||||
{
|
||||
LibRyujinx.setUiHandlerTitle(LibRyujinx.storeString(title ?? ""));
|
||||
LibRyujinx.setUiHandlerMessage(LibRyujinx.storeString(message ?? ""));
|
||||
LibRyujinx.setUiHandlerType(1);
|
||||
|
||||
_responseEvent.Reset();
|
||||
Set();
|
||||
_responseEvent.WaitOne();
|
||||
|
||||
return _isOkPressed;
|
||||
}
|
||||
|
||||
public bool DisplayMessageDialog(ControllerAppletUiArgs args)
|
||||
{
|
||||
string playerCount = args.PlayerCountMin == args.PlayerCountMax ? $"exactly {args.PlayerCountMin}" : $"{args.PlayerCountMin}-{args.PlayerCountMax}";
|
||||
|
||||
string message = $"Application requests **{playerCount}** player(s) with:\n\n"
|
||||
+ $"**TYPES:** {args.SupportedStyles}\n\n"
|
||||
+ $"**PLAYERS:** {string.Join(", ", args.SupportedPlayers)}\n\n"
|
||||
+ (args.IsDocked ? "Docked mode set. `Handheld` is also invalid.\n\n" : "")
|
||||
+ "_Please reconfigure Input now and then press OK._";
|
||||
|
||||
return DisplayMessageDialog("Controller Applet", message);
|
||||
}
|
||||
|
||||
public void ExecuteProgram(Switch device, ProgramSpecifyKind kind, ulong value)
|
||||
{
|
||||
// throw new NotImplementedException();
|
||||
}
|
||||
|
||||
internal void Wait()
|
||||
{
|
||||
if (_isDisposed)
|
||||
return;
|
||||
_waitEvent.Reset();
|
||||
_waitEvent.WaitOne();
|
||||
_waitEvent.Reset();
|
||||
}
|
||||
|
||||
internal void Set()
|
||||
{
|
||||
if (_isDisposed)
|
||||
return;
|
||||
_waitEvent.Set();
|
||||
}
|
||||
|
||||
internal void SetResponse(bool isOkPressed, long input)
|
||||
{
|
||||
if (_isDisposed)
|
||||
return;
|
||||
_isOkPressed = isOkPressed;
|
||||
_input = input;
|
||||
_responseEvent.Set();
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_isDisposed = true;
|
||||
_waitEvent.Set();
|
||||
_waitEvent.Set();
|
||||
_responseEvent.Dispose();
|
||||
_waitEvent.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
18
src/LibRyujinx/Android/Audio/Oboe/OboeAudioBuffer.cs
Normal file
18
src/LibRyujinx/Android/Audio/Oboe/OboeAudioBuffer.cs
Normal file
@ -0,0 +1,18 @@
|
||||
namespace LibRyujinx.Shared.Audio.Oboe
|
||||
{
|
||||
internal class OboeAudioBuffer
|
||||
{
|
||||
public readonly ulong DriverIdentifier;
|
||||
public readonly ulong SampleCount;
|
||||
public readonly byte[] Data;
|
||||
public ulong SamplePlayed;
|
||||
|
||||
public OboeAudioBuffer(ulong driverIdentifier, byte[] data, ulong sampleCount)
|
||||
{
|
||||
DriverIdentifier = driverIdentifier;
|
||||
Data = data;
|
||||
SampleCount = sampleCount;
|
||||
SamplePlayed = 0;
|
||||
}
|
||||
}
|
||||
}
|
105
src/LibRyujinx/Android/Audio/Oboe/OboeHardwareDeviceDriver.cs
Normal file
105
src/LibRyujinx/Android/Audio/Oboe/OboeHardwareDeviceDriver.cs
Normal file
@ -0,0 +1,105 @@
|
||||
using Ryujinx.Audio;
|
||||
using Ryujinx.Audio.Common;
|
||||
using Ryujinx.Audio.Integration;
|
||||
using Ryujinx.Memory;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using static Ryujinx.Audio.Integration.IHardwareDeviceDriver;
|
||||
|
||||
namespace LibRyujinx.Shared.Audio.Oboe
|
||||
{
|
||||
internal class OboeHardwareDeviceDriver : IHardwareDeviceDriver
|
||||
{
|
||||
private readonly ManualResetEvent _updateRequiredEvent;
|
||||
private readonly ManualResetEvent _pauseEvent;
|
||||
private readonly ConcurrentDictionary<OboeHardwareDeviceSession, byte> _sessions;
|
||||
|
||||
public OboeHardwareDeviceDriver()
|
||||
{
|
||||
_updateRequiredEvent = new ManualResetEvent(false);
|
||||
_pauseEvent = new ManualResetEvent(true);
|
||||
_sessions = new ConcurrentDictionary<OboeHardwareDeviceSession, byte>();
|
||||
}
|
||||
|
||||
public static bool IsSupported => true;
|
||||
|
||||
public ManualResetEvent GetUpdateRequiredEvent()
|
||||
{
|
||||
return _updateRequiredEvent;
|
||||
}
|
||||
|
||||
public ManualResetEvent GetPauseEvent()
|
||||
{
|
||||
return _pauseEvent;
|
||||
}
|
||||
|
||||
public IHardwareDeviceSession OpenDeviceSession(Direction direction, IVirtualMemoryManager memoryManager, SampleFormat sampleFormat, uint sampleRate, uint channelCount, float volume)
|
||||
{
|
||||
if (channelCount == 0)
|
||||
{
|
||||
channelCount = 2;
|
||||
}
|
||||
|
||||
if (sampleRate == 0)
|
||||
{
|
||||
sampleRate = Constants.TargetSampleRate;
|
||||
}
|
||||
|
||||
if (direction != Direction.Output)
|
||||
{
|
||||
throw new NotImplementedException("Input direction is currently not implemented on Oboe backend!");
|
||||
}
|
||||
|
||||
OboeHardwareDeviceSession session = new OboeHardwareDeviceSession(this, memoryManager, sampleFormat, sampleRate, channelCount, volume);
|
||||
|
||||
_sessions.TryAdd(session, 0);
|
||||
|
||||
return session;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(true);
|
||||
}
|
||||
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
foreach (OboeHardwareDeviceSession session in _sessions.Keys)
|
||||
{
|
||||
session.Dispose();
|
||||
}
|
||||
|
||||
_pauseEvent.Dispose();
|
||||
|
||||
_sessions.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
public bool SupportsSampleRate(uint sampleRate)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool SupportsSampleFormat(SampleFormat sampleFormat)
|
||||
{
|
||||
return sampleFormat != SampleFormat.Adpcm;
|
||||
}
|
||||
|
||||
public bool SupportsChannelCount(uint channelCount)
|
||||
{
|
||||
return channelCount == 1 || channelCount == 2 || channelCount == 4 || channelCount == 6;
|
||||
}
|
||||
|
||||
public bool SupportsDirection(Direction direction)
|
||||
{
|
||||
return direction == Direction.Output;
|
||||
}
|
||||
}
|
||||
}
|
189
src/LibRyujinx/Android/Audio/Oboe/OboeHardwareDeviceSession.cs
Normal file
189
src/LibRyujinx/Android/Audio/Oboe/OboeHardwareDeviceSession.cs
Normal file
@ -0,0 +1,189 @@
|
||||
using Ryujinx.Audio.Backends.Common;
|
||||
using Ryujinx.Audio.Common;
|
||||
using Ryujinx.Memory;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
|
||||
namespace LibRyujinx.Shared.Audio.Oboe
|
||||
{
|
||||
internal class OboeHardwareDeviceSession : HardwareDeviceSessionOutputBase
|
||||
{
|
||||
private OboeHardwareDeviceDriver _driver;
|
||||
private bool _isClosed;
|
||||
private bool _isWorkerActive;
|
||||
private Queue<OboeAudioBuffer> _queuedBuffers;
|
||||
private bool _isActive;
|
||||
private ulong _playedSampleCount;
|
||||
private Thread _workerThread;
|
||||
private ManualResetEvent _updateRequiredEvent;
|
||||
private IntPtr _session;
|
||||
private object _queueLock = new object();
|
||||
private object _trackLock = new object();
|
||||
|
||||
public OboeHardwareDeviceSession(OboeHardwareDeviceDriver driver, IVirtualMemoryManager memoryManager, SampleFormat requestedSampleFormat, uint requestedSampleRate, uint requestedChannelCount, float requestedVolume) : base(memoryManager, requestedSampleFormat, requestedSampleRate, requestedChannelCount)
|
||||
{
|
||||
_driver = driver;
|
||||
_isActive = false;
|
||||
_playedSampleCount = 0;
|
||||
_isWorkerActive = true;
|
||||
_queuedBuffers = new Queue<OboeAudioBuffer>();
|
||||
_updateRequiredEvent = driver.GetUpdateRequiredEvent();
|
||||
|
||||
_session = OboeInterop.CreateSession((int)requestedSampleFormat, requestedSampleRate, requestedChannelCount);
|
||||
|
||||
_workerThread = new Thread(Update);
|
||||
_workerThread.Name = $"HardwareDeviceSession.Android.Track";
|
||||
_workerThread.Start();
|
||||
|
||||
SetVolume(requestedVolume);
|
||||
}
|
||||
|
||||
public override void UnregisterBuffer(AudioBuffer buffer) { }
|
||||
|
||||
public unsafe void Update(object ignored)
|
||||
{
|
||||
while (_isWorkerActive)
|
||||
{
|
||||
bool needUpdate = false;
|
||||
|
||||
bool hasBuffer;
|
||||
|
||||
OboeAudioBuffer buffer;
|
||||
|
||||
lock (_queueLock)
|
||||
{
|
||||
hasBuffer = _queuedBuffers.TryPeek(out buffer);
|
||||
}
|
||||
|
||||
while (hasBuffer)
|
||||
{
|
||||
StartIfNotPlaying();
|
||||
|
||||
if (_isClosed)
|
||||
break;
|
||||
|
||||
fixed(byte* ptr = buffer.Data)
|
||||
OboeInterop.WriteToSession(_session, (ulong)ptr, buffer.SampleCount);
|
||||
|
||||
lock (_queueLock)
|
||||
{
|
||||
_playedSampleCount += buffer.SampleCount;
|
||||
|
||||
_queuedBuffers.TryDequeue(out _);
|
||||
}
|
||||
|
||||
needUpdate = true;
|
||||
|
||||
lock (_queueLock)
|
||||
{
|
||||
hasBuffer = _queuedBuffers.TryPeek(out buffer);
|
||||
}
|
||||
}
|
||||
|
||||
if (needUpdate)
|
||||
{
|
||||
_updateRequiredEvent.Set();
|
||||
}
|
||||
|
||||
// No work
|
||||
Thread.Sleep(5);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public override void Dispose()
|
||||
{
|
||||
if (_session == 0)
|
||||
return;
|
||||
|
||||
PrepareToClose();
|
||||
|
||||
OboeInterop.CloseSession(_session);
|
||||
|
||||
_session = 0;
|
||||
}
|
||||
|
||||
public override void PrepareToClose()
|
||||
{
|
||||
_isClosed = true;
|
||||
_isWorkerActive = false;
|
||||
_workerThread?.Join();
|
||||
Stop();
|
||||
}
|
||||
|
||||
private void StartIfNotPlaying()
|
||||
{
|
||||
lock (_trackLock)
|
||||
{
|
||||
if (_isClosed)
|
||||
return;
|
||||
|
||||
if (OboeInterop.IsPlaying(_session) == 0)
|
||||
{
|
||||
Start();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void QueueBuffer(AudioBuffer buffer)
|
||||
{
|
||||
lock (_queueLock)
|
||||
{
|
||||
OboeAudioBuffer driverBuffer = new OboeAudioBuffer(buffer.DataPointer, buffer.Data, GetSampleCount(buffer));
|
||||
|
||||
_queuedBuffers.Enqueue(driverBuffer);
|
||||
|
||||
if (_isActive)
|
||||
{
|
||||
StartIfNotPlaying();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override float GetVolume()
|
||||
{
|
||||
return OboeInterop.GetSessionVolume(_session);
|
||||
}
|
||||
|
||||
public override ulong GetPlayedSampleCount()
|
||||
{
|
||||
lock (_queueLock)
|
||||
{
|
||||
return _playedSampleCount;
|
||||
}
|
||||
}
|
||||
|
||||
public override void SetVolume(float volume)
|
||||
{
|
||||
volume = 1;
|
||||
OboeInterop.SetSessionVolume(_session, volume);
|
||||
}
|
||||
|
||||
public override void Start()
|
||||
{
|
||||
if (_isClosed)
|
||||
return;
|
||||
|
||||
OboeInterop.StartSession(_session);
|
||||
}
|
||||
|
||||
public override void Stop()
|
||||
{
|
||||
OboeInterop.StopSession(_session);
|
||||
}
|
||||
|
||||
public override bool WasBufferFullyConsumed(AudioBuffer buffer)
|
||||
{
|
||||
lock (_queueLock)
|
||||
{
|
||||
if (!_queuedBuffers.TryPeek(out OboeAudioBuffer driverBuffer))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return driverBuffer.DriverIdentifier != buffer.DataPointer;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
41
src/LibRyujinx/Android/Audio/Oboe/OboeInterop.cs
Normal file
41
src/LibRyujinx/Android/Audio/Oboe/OboeInterop.cs
Normal file
@ -0,0 +1,41 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace LibRyujinx.Shared.Audio.Oboe
|
||||
{
|
||||
internal static partial class OboeInterop
|
||||
{
|
||||
private const string InteropLib = "libryujinxjni";
|
||||
|
||||
[LibraryImport(InteropLib, EntryPoint = "create_session")]
|
||||
public static partial IntPtr CreateSession(int sample_format,
|
||||
uint sample_rate,
|
||||
uint channel_count);
|
||||
|
||||
|
||||
[LibraryImport(InteropLib, EntryPoint = "start_session")]
|
||||
public static partial void StartSession(IntPtr session);
|
||||
|
||||
[LibraryImport(InteropLib, EntryPoint = "stop_session")]
|
||||
public static partial void StopSession(IntPtr session);
|
||||
|
||||
[LibraryImport(InteropLib, EntryPoint = "close_session")]
|
||||
public static partial void CloseSession(IntPtr session);
|
||||
|
||||
[LibraryImport(InteropLib, EntryPoint = "set_session_volume")]
|
||||
public static partial void SetSessionVolume(IntPtr session, float volume);
|
||||
|
||||
[LibraryImport(InteropLib, EntryPoint = "get_session_volume")]
|
||||
public static partial float GetSessionVolume(IntPtr session);
|
||||
|
||||
[LibraryImport(InteropLib, EntryPoint = "is_playing")]
|
||||
public static partial int IsPlaying(IntPtr session);
|
||||
|
||||
[LibraryImport(InteropLib, EntryPoint = "write_to_session")]
|
||||
public static partial void WriteToSession(IntPtr session, ulong data, ulong samples);
|
||||
}
|
||||
}
|
799
src/LibRyujinx/Android/JniExportedMethods.cs
Normal file
799
src/LibRyujinx/Android/JniExportedMethods.cs
Normal file
@ -0,0 +1,799 @@
|
||||
using LibRyujinx.Jni;
|
||||
using LibRyujinx.Jni.Pointers;
|
||||
using LibRyujinx.Jni.Primitives;
|
||||
using LibRyujinx.Jni.References;
|
||||
using LibRyujinx.Jni.Values;
|
||||
using LibRyujinx.Shared.Audio.Oboe;
|
||||
using Rxmxnx.PInvoke;
|
||||
using Ryujinx.Audio.Backends.OpenAL;
|
||||
using Ryujinx.Common;
|
||||
using Ryujinx.Common.Configuration;
|
||||
using Ryujinx.Common.Logging;
|
||||
using Ryujinx.Common.Logging.Targets;
|
||||
using Ryujinx.HLE.HOS.SystemState;
|
||||
using Ryujinx.Input;
|
||||
using Silk.NET.Core.Loader;
|
||||
using Silk.NET.Vulkan;
|
||||
using Silk.NET.Vulkan.Extensions.KHR;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Numerics;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
|
||||
namespace LibRyujinx
|
||||
{
|
||||
public static partial class LibRyujinx
|
||||
{
|
||||
private static ManualResetEvent _surfaceEvent;
|
||||
private static long _surfacePtr;
|
||||
private static long _window = 0;
|
||||
|
||||
public static VulkanLoader? VulkanLoader { get; private set; }
|
||||
|
||||
[DllImport("libryujinxjni")]
|
||||
private extern static IntPtr getStringPointer(JEnvRef jEnv, JStringLocalRef s);
|
||||
|
||||
[DllImport("libryujinxjni")]
|
||||
private extern static JStringLocalRef createString(JEnvRef jEnv, IntPtr ch);
|
||||
|
||||
[DllImport("libryujinxjni")]
|
||||
internal extern static long storeString(string ch);
|
||||
|
||||
[DllImport("libryujinxjni")]
|
||||
internal extern static IntPtr getString(long id);
|
||||
|
||||
[DllImport("libryujinxjni")]
|
||||
internal extern static long setUiHandlerTitle(long title);
|
||||
|
||||
[DllImport("libryujinxjni")]
|
||||
internal extern static long setUiHandlerMessage(long message);
|
||||
[DllImport("libryujinxjni")]
|
||||
internal extern static long setUiHandlerWatermark(long watermark);
|
||||
[DllImport("libryujinxjni")]
|
||||
internal extern static long setUiHandlerInitialText(long text);
|
||||
[DllImport("libryujinxjni")]
|
||||
internal extern static long setUiHandlerSubtitle(long text);
|
||||
|
||||
[DllImport("libryujinxjni")]
|
||||
internal extern static long setUiHandlerType(int type);
|
||||
|
||||
[DllImport("libryujinxjni")]
|
||||
internal extern static long setUiHandlerKeyboardMode(int mode);
|
||||
|
||||
[DllImport("libryujinxjni")]
|
||||
internal extern static long setUiHandlerMinLength(int lenght);
|
||||
|
||||
[DllImport("libryujinxjni")]
|
||||
internal extern static long setUiHandlerMaxLength(int lenght);
|
||||
|
||||
internal static string GetStoredString(long id)
|
||||
{
|
||||
var pointer = getString(id);
|
||||
if (pointer != IntPtr.Zero)
|
||||
{
|
||||
var str = Marshal.PtrToStringAnsi(pointer) ?? "";
|
||||
|
||||
Marshal.FreeHGlobal(pointer);
|
||||
return str;
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
[DllImport("libryujinxjni")]
|
||||
internal extern static void setRenderingThread();
|
||||
|
||||
[DllImport("libryujinxjni")]
|
||||
internal extern static void debug_break(int code);
|
||||
|
||||
[DllImport("libryujinxjni")]
|
||||
internal extern static void onFrameEnd(double time);
|
||||
|
||||
[DllImport("libryujinxjni")]
|
||||
internal extern static void setProgressInfo(IntPtr info, float progress);
|
||||
|
||||
[DllImport("libryujinxjni")]
|
||||
internal extern static void setCurrentTransform(long native_window, int transform);
|
||||
|
||||
public delegate IntPtr JniCreateSurface(IntPtr native_surface, IntPtr instance);
|
||||
|
||||
[UnmanagedCallersOnly(EntryPoint = "JNI_OnLoad")]
|
||||
internal static int LoadLibrary(JavaVMRef vm, IntPtr unknown)
|
||||
{
|
||||
return 0x00010006; //JNI_VERSION_1_6
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly(EntryPoint = "Java_org_ryujinx_android_RyujinxNative_initialize")]
|
||||
public static JBoolean JniInitialize(JEnvRef jEnv, JObjectLocalRef jObj, JLong jpathId)
|
||||
{
|
||||
Logger.Trace?.Print(LogClass.Application, "Jni Function Call");
|
||||
PlatformInfo.IsBionic = true;
|
||||
|
||||
Logger.AddTarget(
|
||||
new AsyncLogTargetWrapper(
|
||||
new AndroidLogTarget("RyujinxLog"),
|
||||
1000,
|
||||
AsyncLogTargetOverflowAction.Block
|
||||
));
|
||||
|
||||
var path = GetStoredString(jpathId);
|
||||
|
||||
var init = Initialize(path);
|
||||
|
||||
_surfaceEvent?.Set();
|
||||
|
||||
_surfaceEvent = new ManualResetEvent(false);
|
||||
|
||||
return init;
|
||||
}
|
||||
|
||||
private static string? GetString(JEnvRef jEnv, JStringLocalRef jString)
|
||||
{
|
||||
var stringPtr = getStringPointer(jEnv, jString);
|
||||
|
||||
var s = Marshal.PtrToStringAnsi(stringPtr);
|
||||
Marshal.FreeHGlobal(stringPtr);
|
||||
return s;
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly(EntryPoint = "Java_org_ryujinx_android_RyujinxNative_deviceReloadFilesystem")]
|
||||
public static void JniReloadFileSystem()
|
||||
{
|
||||
Logger.Trace?.Print(LogClass.Application, "Jni Function Call");
|
||||
SwitchDevice?.ReloadFileSystem();
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly(EntryPoint = "Java_org_ryujinx_android_RyujinxNative_deviceInitialize")]
|
||||
public static JBoolean JniInitializeDeviceNative(JEnvRef jEnv,
|
||||
JObjectLocalRef jObj,
|
||||
JBoolean isHostMapped,
|
||||
JBoolean useNce,
|
||||
JInt systemLanguage,
|
||||
JInt regionCode,
|
||||
JBoolean enableVsync,
|
||||
JBoolean enableDockedMode,
|
||||
JBoolean enablePtc,
|
||||
JBoolean enableInternetAccess,
|
||||
JLong timeZoneId,
|
||||
JBoolean ignoreMissingServices)
|
||||
{
|
||||
Logger.Trace?.Print(LogClass.Application, "Jni Function Call");
|
||||
AudioDriver = new OpenALHardwareDeviceDriver();//new OboeHardwareDeviceDriver();
|
||||
return InitializeDevice(isHostMapped,
|
||||
useNce,
|
||||
(SystemLanguage)(int)systemLanguage,
|
||||
(RegionCode)(int)regionCode,
|
||||
enableVsync,
|
||||
enableDockedMode,
|
||||
enablePtc,
|
||||
enableInternetAccess,
|
||||
GetStoredString(timeZoneId),
|
||||
ignoreMissingServices);
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly(EntryPoint = "Java_org_ryujinx_android_RyujinxNative_deviceGetGameFifo")]
|
||||
public static JDouble JniGetGameFifo(JEnvRef jEnv, JObjectLocalRef jObj)
|
||||
{
|
||||
Logger.Trace?.Print(LogClass.Application, "Jni Function Call");
|
||||
var stats = SwitchDevice.EmulationContext?.Statistics.GetFifoPercent() ?? 0;
|
||||
|
||||
return stats;
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly(EntryPoint = "Java_org_ryujinx_android_RyujinxNative_deviceGetGameFrameTime")]
|
||||
public static JDouble JniGetGameFrameTime(JEnvRef jEnv, JObjectLocalRef jObj)
|
||||
{
|
||||
Logger.Trace?.Print(LogClass.Application, "Jni Function Call");
|
||||
var stats = SwitchDevice.EmulationContext?.Statistics.GetGameFrameTime() ?? 0;
|
||||
|
||||
return stats;
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly(EntryPoint = "Java_org_ryujinx_android_RyujinxNative_deviceGetGameFrameRate")]
|
||||
public static JDouble JniGetGameFrameRate(JEnvRef jEnv, JObjectLocalRef jObj)
|
||||
{
|
||||
Logger.Trace?.Print(LogClass.Application, "Jni Function Call");
|
||||
var stats = SwitchDevice.EmulationContext?.Statistics.GetGameFrameRate() ?? 0;
|
||||
|
||||
return stats;
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly(EntryPoint = "Java_org_ryujinx_android_RyujinxNative_deviceLoad")]
|
||||
public static JBoolean JniLoadApplicationNative(JEnvRef jEnv, JObjectLocalRef jObj, JStringLocalRef pathPtr)
|
||||
{
|
||||
Logger.Trace?.Print(LogClass.Application, "Jni Function Call");
|
||||
if (SwitchDevice?.EmulationContext == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var path = GetString(jEnv, pathPtr);
|
||||
|
||||
return LoadApplication(path);
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly(EntryPoint = "Java_org_ryujinx_android_RyujinxNative_deviceLaunchMiiEditor")]
|
||||
public static JBoolean JniLaunchMiiEditApplet(JEnvRef jEnv, JObjectLocalRef jObj)
|
||||
{
|
||||
Logger.Trace?.Print(LogClass.Application, "Jni Function Call");
|
||||
if (SwitchDevice?.EmulationContext == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return LaunchMiiEditApplet();
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly(EntryPoint = "Java_org_ryujinx_android_RyujinxNative_deviceGetDlcContentList")]
|
||||
public static JArrayLocalRef JniGetDlcContentListNative(JEnvRef jEnv, JObjectLocalRef jObj, JLong pathPtr, JLong titleId)
|
||||
{
|
||||
Logger.Trace?.Print(LogClass.Application, "Jni Function Call");
|
||||
var list = GetDlcContentList(GetStoredString(pathPtr), (ulong)(long)titleId);
|
||||
|
||||
debug_break(4);
|
||||
|
||||
return CreateStringArray(jEnv, list);
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly(EntryPoint = "Java_org_ryujinx_android_RyujinxNative_deviceGetDlcTitleId")]
|
||||
public static JLong JniGetDlcTitleIdNative(JEnvRef jEnv, JObjectLocalRef jObj, JLong pathPtr, JLong ncaPath)
|
||||
{
|
||||
Logger.Trace?.Print(LogClass.Application, "Jni Function Call");
|
||||
return storeString(GetDlcTitleId(GetStoredString(pathPtr), GetStoredString(ncaPath)));
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly(EntryPoint = "Java_org_ryujinx_android_RyujinxNative_deviceSignalEmulationClose")]
|
||||
public static void JniSignalEmulationCloseNative(JEnvRef jEnv, JObjectLocalRef jObj)
|
||||
{
|
||||
Logger.Trace?.Print(LogClass.Application, "Jni Function Call");
|
||||
SignalEmulationClose();
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly(EntryPoint = "Java_org_ryujinx_android_RyujinxNative_deviceCloseEmulation")]
|
||||
public static void JniCloseEmulationNative(JEnvRef jEnv, JObjectLocalRef jObj)
|
||||
{
|
||||
Logger.Trace?.Print(LogClass.Application, "Jni Function Call");
|
||||
CloseEmulation();
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly(EntryPoint = "Java_org_ryujinx_android_RyujinxNative_deviceLoadDescriptor")]
|
||||
public static JBoolean JniLoadApplicationNative(JEnvRef jEnv, JObjectLocalRef jObj, JInt descriptor, JInt type, JInt updateDescriptor)
|
||||
{
|
||||
Logger.Trace?.Print(LogClass.Application, "Jni Function Call");
|
||||
if (SwitchDevice?.EmulationContext == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var stream = OpenFile(descriptor);
|
||||
var update = updateDescriptor == -1 ? null : OpenFile(updateDescriptor);
|
||||
|
||||
return LoadApplication(stream, (FileType)(int)type, update);
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly(EntryPoint = "Java_org_ryujinx_android_RyujinxNative_deviceVerifyFirmware")]
|
||||
public static JLong JniVerifyFirmware(JEnvRef jEnv, JObjectLocalRef jObj, JInt descriptor, JBoolean isXci)
|
||||
{
|
||||
Logger.Trace?.Print(LogClass.Application, "Jni Function Call");
|
||||
|
||||
var stream = OpenFile(descriptor);
|
||||
|
||||
long stringHandle = -1;
|
||||
|
||||
try
|
||||
{
|
||||
var version = VerifyFirmware(stream, isXci);
|
||||
|
||||
if (version != null)
|
||||
{
|
||||
stringHandle = storeString(version.VersionString);
|
||||
}
|
||||
}
|
||||
catch(Exception _)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
return stringHandle;
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly(EntryPoint = "Java_org_ryujinx_android_RyujinxNative_deviceInstallFirmware")]
|
||||
public static void JniInstallFirmware(JEnvRef jEnv, JObjectLocalRef jObj, JInt descriptor, JBoolean isXci)
|
||||
{
|
||||
Logger.Trace?.Print(LogClass.Application, "Jni Function Call");
|
||||
|
||||
var stream = OpenFile(descriptor);
|
||||
|
||||
InstallFirmware(stream, isXci);
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly(EntryPoint = "Java_org_ryujinx_android_RyujinxNative_deviceGetInstalledFirmwareVersion")]
|
||||
public static JLong JniGetInstalledFirmwareVersion(JEnvRef jEnv, JObjectLocalRef jObj)
|
||||
{
|
||||
Logger.Trace?.Print(LogClass.Application, "Jni Function Call");
|
||||
|
||||
var version = GetInstalledFirmwareVersion();
|
||||
long stringHandle = -1;
|
||||
|
||||
if (version != String.Empty)
|
||||
{
|
||||
stringHandle = storeString(version);
|
||||
}
|
||||
|
||||
return stringHandle;
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly(EntryPoint = "Java_org_ryujinx_android_RyujinxNative_graphicsInitialize")]
|
||||
public static JBoolean JniInitializeGraphicsNative(JEnvRef jEnv, JObjectLocalRef jObj, JObjectLocalRef graphicObject)
|
||||
{
|
||||
Logger.Trace?.Print(LogClass.Application, "Jni Function Call");
|
||||
JEnvValue value = jEnv.Environment;
|
||||
ref JNativeInterface jInterface = ref value.Functions;
|
||||
IntPtr getObjectClassPtr = jInterface.GetObjectClassPointer;
|
||||
IntPtr getFieldIdPtr = jInterface.GetFieldIdPointer;
|
||||
IntPtr getIntFieldPtr = jInterface.GetIntFieldPointer;
|
||||
IntPtr getLongFieldPtr = jInterface.GetLongFieldPointer;
|
||||
IntPtr getFloatFieldPtr = jInterface.GetFloatFieldPointer;
|
||||
IntPtr getBooleanFieldPtr = jInterface.GetBooleanFieldPointer;
|
||||
|
||||
var getObjectClass = getObjectClassPtr.GetUnsafeDelegate<GetObjectClassDelegate>();
|
||||
var getFieldId = getFieldIdPtr.GetUnsafeDelegate<GetFieldIdDelegate>();
|
||||
var getLongField = getLongFieldPtr.GetUnsafeDelegate<GetLongFieldDelegate>();
|
||||
var getIntField = getIntFieldPtr.GetUnsafeDelegate<GetIntFieldDelegate>();
|
||||
var getBooleanField = getBooleanFieldPtr.GetUnsafeDelegate<GetBooleanFieldDelegate>();
|
||||
var getFloatField = getFloatFieldPtr.GetUnsafeDelegate<GetFloatFieldDelegate>();
|
||||
|
||||
var jobject = getObjectClass(jEnv, graphicObject);
|
||||
|
||||
GraphicsConfiguration graphicsConfiguration = new()
|
||||
{
|
||||
EnableShaderCache = getBooleanField(jEnv, graphicObject, getFieldId(jEnv, jobject, GetCCharSequence("EnableShaderCache"), GetCCharSequence("Z"))),
|
||||
EnableMacroHLE = getBooleanField(jEnv, graphicObject, getFieldId(jEnv, jobject, GetCCharSequence("EnableMacroHLE"), GetCCharSequence("Z"))),
|
||||
EnableMacroJit = getBooleanField(jEnv, graphicObject, getFieldId(jEnv, jobject, GetCCharSequence("EnableMacroJit"), GetCCharSequence("Z"))),
|
||||
EnableTextureRecompression = getBooleanField(jEnv, graphicObject, getFieldId(jEnv, jobject, GetCCharSequence("EnableTextureRecompression"), GetCCharSequence("Z"))),
|
||||
Fast2DCopy = getBooleanField(jEnv, graphicObject, getFieldId(jEnv, jobject, GetCCharSequence("Fast2DCopy"), GetCCharSequence("Z"))),
|
||||
FastGpuTime = getBooleanField(jEnv, graphicObject, getFieldId(jEnv, jobject, GetCCharSequence("FastGpuTime"), GetCCharSequence("Z"))),
|
||||
ResScale = getFloatField(jEnv, graphicObject, getFieldId(jEnv, jobject, GetCCharSequence("ResScale"), GetCCharSequence("F"))),
|
||||
MaxAnisotropy = getFloatField(jEnv, graphicObject, getFieldId(jEnv, jobject, GetCCharSequence("MaxAnisotropy"), GetCCharSequence("F"))),
|
||||
BackendThreading = (BackendThreading)(int)getIntField(jEnv, graphicObject, getFieldId(jEnv, jobject, GetCCharSequence("BackendThreading"), GetCCharSequence("I")))
|
||||
};
|
||||
SearchPathContainer.Platform = UnderlyingPlatform.Android;
|
||||
return InitializeGraphics(graphicsConfiguration);
|
||||
}
|
||||
|
||||
private static CCharSequence GetCCharSequence(string s)
|
||||
{
|
||||
return Encoding.UTF8.GetBytes(s).AsSpan();
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly(EntryPoint = "Java_org_ryujinx_android_RyujinxNative_graphicsSetSurface")]
|
||||
public static void JniSetSurface(JEnvRef jEnv, JObjectLocalRef jObj, JLong surfacePtr, JLong window)
|
||||
{
|
||||
Logger.Trace?.Print(LogClass.Application, "Jni Function Call");
|
||||
_surfacePtr = surfacePtr;
|
||||
_window = window;
|
||||
|
||||
_surfaceEvent.Set();
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly(EntryPoint = "Java_org_ryujinx_android_RyujinxNative_graphicsInitializeRenderer")]
|
||||
public unsafe static JBoolean JniInitializeGraphicsRendererNative(JEnvRef jEnv,
|
||||
JObjectLocalRef jObj,
|
||||
JArrayLocalRef extensionsArray,
|
||||
JLong driverHandle)
|
||||
{
|
||||
Logger.Trace?.Print(LogClass.Application, "Jni Function Call");
|
||||
if (Renderer != null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
JEnvValue value = jEnv.Environment;
|
||||
ref JNativeInterface jInterface = ref value.Functions;
|
||||
IntPtr getObjectClassPtr = jInterface.GetObjectClassPointer;
|
||||
IntPtr getFieldIdPtr = jInterface.GetFieldIdPointer;
|
||||
IntPtr getLongFieldPtr = jInterface.GetLongFieldPointer;
|
||||
IntPtr getArrayLengthPtr = jInterface.GetArrayLengthPointer;
|
||||
IntPtr getObjectArrayElementPtr = jInterface.GetObjectArrayElementPointer;
|
||||
IntPtr getObjectFieldPtr = jInterface.GetObjectFieldPointer;
|
||||
|
||||
var getObjectClass = getObjectClassPtr.GetUnsafeDelegate<GetObjectClassDelegate>();
|
||||
var getFieldId = getFieldIdPtr.GetUnsafeDelegate<GetFieldIdDelegate>();
|
||||
var getArrayLength = getArrayLengthPtr.GetUnsafeDelegate<GetArrayLengthDelegate>();
|
||||
var getObjectArrayElement = getObjectArrayElementPtr.GetUnsafeDelegate<GetObjectArrayElementDelegate>();
|
||||
var getLongField = getLongFieldPtr.GetUnsafeDelegate<GetLongFieldDelegate>();
|
||||
var getObjectField = getObjectFieldPtr.GetUnsafeDelegate<GetObjectFieldDelegate>();
|
||||
|
||||
List<string?> extensions = new();
|
||||
|
||||
var count = getArrayLength(jEnv, extensionsArray);
|
||||
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
var obj = getObjectArrayElement(jEnv, extensionsArray, i);
|
||||
var ext = obj.Transform<JObjectLocalRef, JStringLocalRef>();
|
||||
|
||||
extensions.Add(GetString(jEnv, ext));
|
||||
}
|
||||
|
||||
if ((long)driverHandle != 0)
|
||||
{
|
||||
VulkanLoader = new VulkanLoader((IntPtr)(long)driverHandle);
|
||||
}
|
||||
|
||||
CreateSurface createSurfaceFunc = instance =>
|
||||
{
|
||||
_surfaceEvent.WaitOne();
|
||||
_surfaceEvent.Reset();
|
||||
|
||||
var api = VulkanLoader?.GetApi() ?? Vk.GetApi();
|
||||
if (api.TryGetInstanceExtension(new Instance(instance), out KhrAndroidSurface surfaceExtension))
|
||||
{
|
||||
var createInfo = new AndroidSurfaceCreateInfoKHR
|
||||
{
|
||||
SType = StructureType.AndroidSurfaceCreateInfoKhr,
|
||||
Window = (nint*)_surfacePtr,
|
||||
};
|
||||
|
||||
var result = surfaceExtension.CreateAndroidSurface(new Instance(instance), createInfo, null, out var surface);
|
||||
|
||||
return (nint)surface.Handle;
|
||||
}
|
||||
|
||||
return IntPtr.Zero;
|
||||
};
|
||||
|
||||
return InitializeGraphicsRenderer(GraphicsBackend.Vulkan, createSurfaceFunc, extensions.ToArray());
|
||||
}
|
||||
|
||||
private static JArrayLocalRef CreateStringArray(JEnvRef jEnv, List<string> strings)
|
||||
{
|
||||
JEnvValue value = jEnv.Environment;
|
||||
ref JNativeInterface jInterface = ref value.Functions;
|
||||
IntPtr newObjectArrayPtr = jInterface.NewObjectArrayPointer;
|
||||
IntPtr findClassPtr = jInterface.FindClassPointer;
|
||||
IntPtr setObjectArrayElementPtr = jInterface.SetObjectArrayElementPointer;
|
||||
|
||||
var newObjectArray = newObjectArrayPtr.GetUnsafeDelegate<NewObjectArrayDelegate>();
|
||||
var findClass = findClassPtr.GetUnsafeDelegate<FindClassDelegate>();
|
||||
var setObjectArrayElement = setObjectArrayElementPtr.GetUnsafeDelegate<SetObjectArrayElementDelegate>();
|
||||
var array = newObjectArray(jEnv, strings.Count, findClass(jEnv, GetCCharSequence("java/lang/String")), CreateString(jEnv, "")._value);
|
||||
|
||||
for (int i = 0; i < strings.Count; i++)
|
||||
{
|
||||
setObjectArrayElement(jEnv, array, i, CreateString(jEnv, strings[i])._value);
|
||||
}
|
||||
|
||||
return array;
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly(EntryPoint = "Java_org_ryujinx_android_RyujinxNative_graphicsRendererSetSize")]
|
||||
public static void JniSetRendererSizeNative(JEnvRef jEnv, JObjectLocalRef jObj, JInt width, JInt height)
|
||||
{
|
||||
Logger.Trace?.Print(LogClass.Application, "Jni Function Call");
|
||||
Renderer?.Window?.SetSize(width, height);
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly(EntryPoint = "Java_org_ryujinx_android_RyujinxNative_graphicsRendererRunLoop")]
|
||||
public static void JniRunLoopNative(JEnvRef jEnv, JObjectLocalRef jObj)
|
||||
{
|
||||
Logger.Trace?.Print(LogClass.Application, "Jni Function Call");
|
||||
SetSwapBuffersCallback(() =>
|
||||
{
|
||||
var time = SwitchDevice.EmulationContext.Statistics.GetGameFrameTime();
|
||||
onFrameEnd(time);
|
||||
});
|
||||
RunLoop();
|
||||
}
|
||||
|
||||
|
||||
[UnmanagedCallersOnly(EntryPoint = "Java_org_ryujinx_android_RyujinxNative_loggingSetEnabled")]
|
||||
public static void JniSetLoggingEnabledNative(JEnvRef jEnv, JObjectLocalRef jObj, JInt logLevel, JBoolean enabled)
|
||||
{
|
||||
Logger.SetEnable((LogLevel)(int)logLevel, enabled);
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly(EntryPoint = "Java_org_ryujinx_android_RyujinxNative_deviceGetGameInfoFromPath")]
|
||||
public static JObjectLocalRef JniGetGameInfo(JEnvRef jEnv, JObjectLocalRef jObj, JStringLocalRef path)
|
||||
{
|
||||
Logger.Trace?.Print(LogClass.Application, "Jni Function Call");
|
||||
var info = GetGameInfo(GetString(jEnv, path));
|
||||
return GetInfo(jEnv, info);
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly(EntryPoint = "Java_org_ryujinx_android_RyujinxNative_deviceGetGameInfo")]
|
||||
public static JObjectLocalRef JniGetGameInfo(JEnvRef jEnv, JObjectLocalRef jObj, JInt fileDescriptor, JLong extension)
|
||||
{
|
||||
Logger.Trace?.Print(LogClass.Application, "Jni Function Call");
|
||||
using var stream = OpenFile(fileDescriptor);
|
||||
var ext = GetStoredString(extension);
|
||||
var info = GetGameInfo(stream, ext.ToLower());
|
||||
return GetInfo(jEnv, info);
|
||||
}
|
||||
|
||||
private static JObjectLocalRef GetInfo(JEnvRef jEnv, GameInfo? info)
|
||||
{
|
||||
Logger.Trace?.Print(LogClass.Application, "Jni Function Call");
|
||||
var javaClassName = GetCCharSequence("org/ryujinx/android/viewmodels/GameInfo");
|
||||
|
||||
JEnvValue value = jEnv.Environment;
|
||||
ref JNativeInterface jInterface = ref value.Functions;
|
||||
IntPtr findClassPtr = jInterface.FindClassPointer;
|
||||
IntPtr newGlobalRefPtr = jInterface.NewGlobalRefPointer;
|
||||
IntPtr getFieldIdPtr = jInterface.GetFieldIdPointer;
|
||||
IntPtr getMethodPtr = jInterface.GetMethodIdPointer;
|
||||
IntPtr newObjectPtr = jInterface.NewObjectPointer;
|
||||
IntPtr setObjectFieldPtr = jInterface.SetObjectFieldPointer;
|
||||
IntPtr setDoubleFieldPtr = jInterface.SetDoubleFieldPointer;
|
||||
|
||||
|
||||
var findClass = findClassPtr.GetUnsafeDelegate<FindClassDelegate>();
|
||||
var newGlobalRef = newGlobalRefPtr.GetUnsafeDelegate<NewGlobalRefDelegate>();
|
||||
var getFieldId = getFieldIdPtr.GetUnsafeDelegate<GetFieldIdDelegate>();
|
||||
var getMethod = getMethodPtr.GetUnsafeDelegate<GetMethodIdDelegate>();
|
||||
var newObject = newObjectPtr.GetUnsafeDelegate<NewObjectDelegate>();
|
||||
var setObjectField = setObjectFieldPtr.GetUnsafeDelegate<SetObjectFieldDelegate>();
|
||||
var setDoubleField = setDoubleFieldPtr.GetUnsafeDelegate<SetDoubleFieldDelegate>();
|
||||
|
||||
var javaClass = findClass(jEnv, javaClassName);
|
||||
var newGlobal = newGlobalRef(jEnv, javaClass._value);
|
||||
var constructor = getMethod(jEnv, javaClass, GetCCharSequence("<init>"), GetCCharSequence("()V"));
|
||||
var newObj = newObject(jEnv, javaClass, constructor, 0);
|
||||
|
||||
setObjectField(jEnv, newObj, getFieldId(jEnv, javaClass, GetCCharSequence("TitleName"), GetCCharSequence("Ljava/lang/String;")), CreateString(jEnv, info?.TitleName)._value);
|
||||
setObjectField(jEnv, newObj, getFieldId(jEnv, javaClass, GetCCharSequence("TitleId"), GetCCharSequence("Ljava/lang/String;")), CreateString(jEnv, info?.TitleId)._value);
|
||||
setObjectField(jEnv, newObj, getFieldId(jEnv, javaClass, GetCCharSequence("Developer"), GetCCharSequence("Ljava/lang/String;")), CreateString(jEnv, info?.Developer)._value);
|
||||
setObjectField(jEnv, newObj, getFieldId(jEnv, javaClass, GetCCharSequence("Version"), GetCCharSequence("Ljava/lang/String;")), CreateString(jEnv, info?.Version)._value);
|
||||
setObjectField(jEnv, newObj, getFieldId(jEnv, javaClass, GetCCharSequence("Icon"), GetCCharSequence("Ljava/lang/String;")), CreateString(jEnv, Convert.ToBase64String(info?.Icon ?? Array.Empty<byte>()))._value);
|
||||
setDoubleField(jEnv, newObj, getFieldId(jEnv, javaClass, GetCCharSequence("FileSize"), GetCCharSequence("D")), info?.FileSize ?? 0d);
|
||||
|
||||
return newObj;
|
||||
}
|
||||
|
||||
private static JStringLocalRef CreateString(JEnvRef jEnv, string? s)
|
||||
{
|
||||
s ??= string.Empty;
|
||||
|
||||
var ptr = Marshal.StringToHGlobalAnsi(s);
|
||||
|
||||
var str = createString(jEnv, ptr);
|
||||
|
||||
Marshal.FreeHGlobal(ptr);
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly(EntryPoint = "Java_org_ryujinx_android_RyujinxNative_graphicsRendererSetVsync")]
|
||||
public static void JniSetVsyncStateNative(JEnvRef jEnv, JObjectLocalRef jObj, JBoolean enabled)
|
||||
{
|
||||
Logger.Trace?.Print(LogClass.Application, "Jni Function Call");
|
||||
SetVsyncState(enabled);
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly(EntryPoint = "Java_org_ryujinx_android_RyujinxNative_graphicsRendererSetSwapBufferCallback")]
|
||||
public static void JniSetSwapBuffersCallbackNative(JEnvRef jEnv, JObjectLocalRef jObj, IntPtr swapBuffersCallback)
|
||||
{
|
||||
Logger.Trace?.Print(LogClass.Application, "Jni Function Call");
|
||||
_swapBuffersCallback = Marshal.GetDelegateForFunctionPointer<SwapBuffersCallback>(swapBuffersCallback);
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly(EntryPoint = "Java_org_ryujinx_android_RyujinxNative_inputInitialize")]
|
||||
public static void JniInitializeInput(JEnvRef jEnv, JObjectLocalRef jObj, JInt width, JInt height)
|
||||
{
|
||||
Logger.Trace?.Print(LogClass.Application, "Jni Function Call");
|
||||
InitializeInput(width, height);
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly(EntryPoint = "Java_org_ryujinx_android_RyujinxNative_inputSetClientSize")]
|
||||
public static void JniSetClientSize(JEnvRef jEnv, JObjectLocalRef jObj, JInt width, JInt height)
|
||||
{
|
||||
Logger.Trace?.Print(LogClass.Application, "Jni Function Call");
|
||||
SetClientSize(width, height);
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly(EntryPoint = "Java_org_ryujinx_android_RyujinxNative_inputSetTouchPoint")]
|
||||
public static void JniSetTouchPoint(JEnvRef jEnv, JObjectLocalRef jObj, JInt x, JInt y)
|
||||
{
|
||||
Logger.Trace?.Print(LogClass.Application, "Jni Function Call");
|
||||
SetTouchPoint(x, y);
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly(EntryPoint = "Java_org_ryujinx_android_RyujinxNative_inputReleaseTouchPoint")]
|
||||
public static void JniReleaseTouchPoint(JEnvRef jEnv, JObjectLocalRef jObj)
|
||||
{
|
||||
Logger.Trace?.Print(LogClass.Application, "Jni Function Call");
|
||||
ReleaseTouchPoint();
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly(EntryPoint = "Java_org_ryujinx_android_RyujinxNative_inputUpdate")]
|
||||
public static void JniUpdateInput(JEnvRef jEnv, JObjectLocalRef jObj)
|
||||
{
|
||||
Logger.Trace?.Print(LogClass.Application, "Jni Function Call");
|
||||
UpdateInput();
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly(EntryPoint = "Java_org_ryujinx_android_RyujinxNative_inputSetButtonPressed")]
|
||||
public static void JniSetButtonPressed(JEnvRef jEnv, JObjectLocalRef jObj, JInt button, JInt id)
|
||||
{
|
||||
Logger.Trace?.Print(LogClass.Application, "Jni Function Call");
|
||||
SetButtonPressed((GamepadButtonInputId)(int)button, id);
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly(EntryPoint = "Java_org_ryujinx_android_RyujinxNative_inputSetButtonReleased")]
|
||||
public static void JniSetButtonReleased(JEnvRef jEnv, JObjectLocalRef jObj, JInt button, JInt id)
|
||||
{
|
||||
Logger.Trace?.Print(LogClass.Application, "Jni Function Call");
|
||||
SetButtonReleased((GamepadButtonInputId)(int)button, id);
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly(EntryPoint = "Java_org_ryujinx_android_RyujinxNative_inputSetAccelerometerData")]
|
||||
public static void JniSetAccelerometerData(JEnvRef jEnv, JObjectLocalRef jObj, JFloat x, JFloat y, JFloat z, JInt id)
|
||||
{
|
||||
var accel = new Vector3(x, y, z);
|
||||
SetAccelerometerData(accel, id);
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly(EntryPoint = "Java_org_ryujinx_android_RyujinxNative_inputSetGyroData")]
|
||||
public static void JniSetGyroData(JEnvRef jEnv, JObjectLocalRef jObj, JFloat x, JFloat y, JFloat z, JInt id)
|
||||
{
|
||||
var gryo = new Vector3(x, y, z);
|
||||
SetGryoData(gryo, id);
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly(EntryPoint = "Java_org_ryujinx_android_RyujinxNative_inputSetStickAxis")]
|
||||
public static void JniSetStickAxis(JEnvRef jEnv, JObjectLocalRef jObj, JInt stick, JFloat x, JFloat y, JInt id)
|
||||
{
|
||||
Logger.Trace?.Print(LogClass.Application, "Jni Function Call");
|
||||
SetStickAxis((StickInputId)(int)stick, new Vector2(float.IsNaN(x) ? 0 : x, float.IsNaN(y) ? 0 : y), id);
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly(EntryPoint = "Java_org_ryujinx_android_RyujinxNative_inputConnectGamepad")]
|
||||
public static JInt JniConnectGamepad(JEnvRef jEnv, JObjectLocalRef jObj, JInt index)
|
||||
{
|
||||
Logger.Trace?.Print(LogClass.Application, "Jni Function Call");
|
||||
return ConnectGamepad(index);
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly(EntryPoint = "Java_org_ryujinx_android_RyujinxNative_userGetOpenedUser")]
|
||||
public static JLong JniGetOpenedUser(JEnvRef jEnv, JObjectLocalRef jObj)
|
||||
{
|
||||
Logger.Trace?.Print(LogClass.Application, "Jni Function Call");
|
||||
var userId = GetOpenedUser();
|
||||
|
||||
return storeString(userId);
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly(EntryPoint = "Java_org_ryujinx_android_RyujinxNative_userGetUserPicture")]
|
||||
public static JLong JniGetUserPicture(JEnvRef jEnv, JObjectLocalRef jObj, JLong userIdPtr)
|
||||
{
|
||||
Logger.Trace?.Print(LogClass.Application, "Jni Function Call");
|
||||
var userId = GetStoredString(userIdPtr) ?? "";
|
||||
|
||||
return storeString(GetUserPicture(userId));
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly(EntryPoint = "Java_org_ryujinx_android_RyujinxNative_userSetUserPicture")]
|
||||
public static void JniGetUserPicture(JEnvRef jEnv, JObjectLocalRef jObj, JStringLocalRef userIdPtr, JStringLocalRef picturePtr)
|
||||
{
|
||||
Logger.Trace?.Print(LogClass.Application, "Jni Function Call");
|
||||
var userId = GetString(jEnv, userIdPtr) ?? "";
|
||||
var picture = GetString(jEnv, picturePtr) ?? "";
|
||||
|
||||
SetUserPicture(userId, picture);
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly(EntryPoint = "Java_org_ryujinx_android_RyujinxNative_userGetUserName")]
|
||||
public static JLong JniGetUserName(JEnvRef jEnv, JObjectLocalRef jObj, JLong userIdPtr)
|
||||
{
|
||||
Logger.Trace?.Print(LogClass.Application, "Jni Function Call");
|
||||
var userId = GetStoredString(userIdPtr) ?? "";
|
||||
|
||||
return storeString(GetUserName(userId));
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly(EntryPoint = "Java_org_ryujinx_android_RyujinxNative_userSetUserName")]
|
||||
public static void JniSetUserName(JEnvRef jEnv, JObjectLocalRef jObj, JStringLocalRef userIdPtr, JStringLocalRef userNamePtr)
|
||||
{
|
||||
Logger.Trace?.Print(LogClass.Application, "Jni Function Call");
|
||||
var userId = GetString(jEnv, userIdPtr) ?? "";
|
||||
var userName = GetString(jEnv, userNamePtr) ?? "";
|
||||
|
||||
SetUserName(userId, userName);
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly(EntryPoint = "Java_org_ryujinx_android_RyujinxNative_userGetAllUsers")]
|
||||
public static JArrayLocalRef JniGetAllUsers(JEnvRef jEnv, JObjectLocalRef jObj)
|
||||
{
|
||||
Logger.Trace?.Print(LogClass.Application, "Jni Function Call");
|
||||
var users = GetAllUsers();
|
||||
|
||||
return CreateStringArray(jEnv, users.ToList());
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly(EntryPoint = "Java_org_ryujinx_android_RyujinxNative_userAddUser")]
|
||||
public static void JniAddUser(JEnvRef jEnv, JObjectLocalRef jObj, JStringLocalRef userNamePtr, JStringLocalRef picturePtr)
|
||||
{
|
||||
Logger.Trace?.Print(LogClass.Application, "Jni Function Call");
|
||||
var userName = GetString(jEnv, userNamePtr) ?? "";
|
||||
var picture = GetString(jEnv, picturePtr) ?? "";
|
||||
|
||||
AddUser(userName, picture);
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly(EntryPoint = "Java_org_ryujinx_android_RyujinxNative_userDeleteUser")]
|
||||
public static void JniDeleteUser(JEnvRef jEnv, JObjectLocalRef jObj, JStringLocalRef userIdPtr)
|
||||
{
|
||||
Logger.Trace?.Print(LogClass.Application, "Jni Function Call");
|
||||
var userId = GetString(jEnv, userIdPtr) ?? "";
|
||||
|
||||
DeleteUser(userId);
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly(EntryPoint = "Java_org_ryujinx_android_RyujinxNative_uiHandlerSetup")]
|
||||
public static void JniSetupUiHandler(JEnvRef jEnv, JObjectLocalRef jObj)
|
||||
{
|
||||
SetupUiHandler();
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly(EntryPoint = "Java_org_ryujinx_android_RyujinxNative_uiHandlerWait")]
|
||||
public static void JniWaitUiHandler(JEnvRef jEnv, JObjectLocalRef jObj)
|
||||
{
|
||||
WaitUiHandler();
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly(EntryPoint = "Java_org_ryujinx_android_RyujinxNative_uiHandlerStopWait")]
|
||||
public static void JniStopUiHandlerWait(JEnvRef jEnv, JObjectLocalRef jObj)
|
||||
{
|
||||
StopUiHandlerWait();
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly(EntryPoint = "Java_org_ryujinx_android_RyujinxNative_uiHandlerSetResponse")]
|
||||
public static void JniSetUiHandlerResponse(JEnvRef jEnv, JObjectLocalRef jObj, JBoolean isOkPressed, JLong input)
|
||||
{
|
||||
SetUiHandlerResponse(isOkPressed, input);
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly(EntryPoint = "Java_org_ryujinx_android_RyujinxNative_userOpenUser")]
|
||||
public static void JniOpenUser(JEnvRef jEnv, JObjectLocalRef jObj, JLong userIdPtr)
|
||||
{
|
||||
Logger.Trace?.Print(LogClass.Application, "Jni Function Call");
|
||||
var userId = GetStoredString(userIdPtr) ?? "";
|
||||
|
||||
OpenUser(userId);
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly(EntryPoint = "Java_org_ryujinx_android_RyujinxNative_userCloseUser")]
|
||||
public static void JniCloseUser(JEnvRef jEnv, JObjectLocalRef jObj, JStringLocalRef userIdPtr)
|
||||
{
|
||||
Logger.Trace?.Print(LogClass.Application, "Jni Function Call");
|
||||
var userId = GetString(jEnv, userIdPtr) ?? "";
|
||||
|
||||
CloseUser(userId);
|
||||
}
|
||||
}
|
||||
|
||||
internal static partial class Logcat
|
||||
{
|
||||
[LibraryImport("liblog", StringMarshalling = StringMarshalling.Utf8)]
|
||||
private static partial void __android_log_print(LogLevel level, string? tag, string format, string args, IntPtr ptr);
|
||||
|
||||
internal static void AndroidLogPrint(LogLevel level, string? tag, string message) =>
|
||||
__android_log_print(level, tag, "%s", message, IntPtr.Zero);
|
||||
|
||||
internal enum LogLevel
|
||||
{
|
||||
Unknown = 0x00,
|
||||
Default = 0x01,
|
||||
Verbose = 0x02,
|
||||
Debug = 0x03,
|
||||
Info = 0x04,
|
||||
Warn = 0x05,
|
||||
Error = 0x06,
|
||||
Fatal = 0x07,
|
||||
Silent = 0x08,
|
||||
}
|
||||
}
|
||||
}
|
286
src/LibRyujinx/Jni/Delegates.cs
Normal file
286
src/LibRyujinx/Jni/Delegates.cs
Normal file
@ -0,0 +1,286 @@
|
||||
using LibRyujinx.Jni.Identifiers;
|
||||
using LibRyujinx.Jni.Internal.Pointers;
|
||||
using LibRyujinx.Jni.Pointers;
|
||||
using LibRyujinx.Jni.Primitives;
|
||||
using LibRyujinx.Jni.References;
|
||||
using LibRyujinx.Jni.Values;
|
||||
using System;
|
||||
|
||||
namespace LibRyujinx.Jni
|
||||
{
|
||||
internal delegate Int32 GetVersionDelegate(JEnvRef env);
|
||||
|
||||
internal delegate JClassLocalRef DefineClassDelegate(JEnvRef env, CCharSequence name, JObjectLocalRef loader, IntPtr binaryData, Int32 len);
|
||||
internal delegate JClassLocalRef FindClassDelegate(JEnvRef env, CCharSequence name);
|
||||
|
||||
internal delegate JMethodId FromReflectedMethodDelegate(JEnvRef env, JObjectLocalRef method);
|
||||
internal delegate JFieldId FromReflectedFieldIdDelegate(JEnvRef env, JObjectLocalRef field);
|
||||
|
||||
internal delegate JObjectLocalRef ToReflectedMethodDelegate(JEnvRef env, JClassLocalRef jClass, JMethodId methodId, Boolean isStatic);
|
||||
|
||||
internal delegate JClassLocalRef GetSuperclassDelegate(JEnvRef env, JClassLocalRef sub);
|
||||
internal delegate Boolean IsAssignableFromDelegate(JEnvRef env, JClassLocalRef sub, JClassLocalRef sup);
|
||||
|
||||
internal delegate JObjectLocalRef ToReflectedFieldIdDelegate(JEnvRef env, JClassLocalRef jClass, JFieldId fieldId, Boolean isStatic);
|
||||
|
||||
internal delegate JResult ThrowDelegate(JEnvRef env, JThrowableLocalRef obj);
|
||||
internal delegate JResult ThrowNewDelegate(JEnvRef env, JClassLocalRef jClass, CCharSequence msg);
|
||||
internal delegate JThrowableLocalRef ExceptionOccurredDelegate(JEnvRef env);
|
||||
internal delegate void ExceptionDescribeDelegate(JEnvRef env);
|
||||
internal delegate void ExceptionClearDelegate(JEnvRef env);
|
||||
internal delegate void FatalErrorDelegate(JEnvRef env, CCharSequence msg);
|
||||
|
||||
internal delegate JResult PushLocalFrameDelegate(JEnvRef env, Int32 capacity);
|
||||
internal delegate JObjectLocalRef PopLocalFrameDelegate(JEnvRef env, JObjectLocalRef result);
|
||||
|
||||
internal delegate JGlobalRef NewGlobalRefDelegate(JEnvRef env, JObjectLocalRef lref);
|
||||
internal delegate void DeleteGlobalRefDelegate(JEnvRef env, JGlobalRef gref);
|
||||
internal delegate void DeleteLocalRefDelegate(JEnvRef env, JObjectLocalRef lref);
|
||||
internal delegate Boolean IsSameObjectDelegate(JEnvRef env, JObjectLocalRef obj1, JObjectLocalRef obj2);
|
||||
internal delegate JObjectLocalRef NewLocalRefDelegate(JEnvRef env, JObjectLocalRef objRef);
|
||||
internal delegate JResult EnsureLocalCapacityDelegate(JEnvRef env, Int32 capacity);
|
||||
|
||||
internal delegate JObjectLocalRef AllocObjectDelegate(JEnvRef env, JClassLocalRef jClass);
|
||||
internal delegate JObjectLocalRef NewObjectDelegate(JEnvRef env, JClassLocalRef jClass, JMethodId jMethod, IntPtr args);
|
||||
internal delegate JObjectLocalRef NewObjectVDelegate(JEnvRef env, JClassLocalRef jClass, JMethodId jMethod, ArgIterator args);
|
||||
internal delegate JObjectLocalRef NewObjectADelegate(JEnvRef env, JClassLocalRef jClass, JMethodId jMethod, JValueSequence args);
|
||||
|
||||
internal delegate JClassLocalRef GetObjectClassDelegate(JEnvRef env, JObjectLocalRef obj);
|
||||
internal delegate Boolean IsInstanceOfDelegate(JEnvRef env, JObjectLocalRef obj, JClassLocalRef jclass);
|
||||
|
||||
internal delegate JMethodId GetMethodIdDelegate(JEnvRef env, JClassLocalRef jClass, CCharSequence name, CCharSequence signature);
|
||||
|
||||
internal delegate JObjectLocalRef CallObjectMethodDelegate(JEnvRef env, JObjectLocalRef obj, JMethodId jMethod, IntPtr args);
|
||||
internal delegate JObjectLocalRef CallObjectMethodVDelegate(JEnvRef env, JObjectLocalRef obj, JMethodId jMethod, ArgIterator args);
|
||||
internal delegate JObjectLocalRef CallObjectMethodADelegate(JEnvRef env, JObjectLocalRef obj, JMethodId jMethod, JValueSequence args);
|
||||
internal delegate JBoolean CallBooleanMethodDelegate(JEnvRef env, JObjectLocalRef obj, JMethodId jMethod, IntPtr args);
|
||||
internal delegate JBoolean CallBooleanMethodVDelegate(JEnvRef env, JObjectLocalRef obj, JMethodId jMethod, ArgIterator args);
|
||||
internal delegate JBoolean CallBooleanMethodADelegate(JEnvRef env, JObjectLocalRef obj, JMethodId jMethod, JValueSequence args);
|
||||
internal delegate JByte CallByteMethodDelegate(JEnvRef env, JObjectLocalRef obj, JMethodId jMethod, IntPtr args);
|
||||
internal delegate JByte CallByteMethodVDelegate(JEnvRef env, JObjectLocalRef obj, JMethodId jMethod, ArgIterator args);
|
||||
internal delegate JByte CallByteMethodADelegate(JEnvRef env, JObjectLocalRef obj, JMethodId jMethod, JValueSequence args);
|
||||
internal delegate JChar CallCharMethodDelegate(JEnvRef env, JObjectLocalRef obj, JMethodId jMethod, IntPtr args);
|
||||
internal delegate JChar CallCharMethodVDelegate(JEnvRef env, JObjectLocalRef obj, JMethodId jMethod, ArgIterator args);
|
||||
internal delegate JChar CallCharMethodADelegate(JEnvRef env, JObjectLocalRef obj, JMethodId jMethod, JValueSequence args);
|
||||
internal delegate JShort CallShortMethodDelegate(JEnvRef env, JObjectLocalRef obj, JMethodId jMethod, IntPtr args);
|
||||
internal delegate JShort CallShortMethodVDelegate(JEnvRef env, JObjectLocalRef obj, JMethodId jMethod, ArgIterator args);
|
||||
internal delegate JShort CallShortMethodADelegate(JEnvRef env, JObjectLocalRef obj, JMethodId jMethod, JValueSequence args);
|
||||
internal delegate JInt CallIntMethodDelegate(JEnvRef env, JObjectLocalRef obj, JMethodId jMethod, IntPtr args);
|
||||
internal delegate JInt CallIntMethodVDelegate(JEnvRef env, JObjectLocalRef obj, JMethodId jMethod, ArgIterator args);
|
||||
internal delegate JInt CallIntMethodADelegate(JEnvRef env, JObjectLocalRef obj, JMethodId jMethod, JValueSequence args);
|
||||
internal delegate JLong CallLongMethodDelegate(JEnvRef env, JObjectLocalRef obj, JMethodId jMethod, IntPtr args);
|
||||
internal delegate JLong CallLongMethodVDelegate(JEnvRef env, JObjectLocalRef obj, JMethodId jMethod, ArgIterator args);
|
||||
internal delegate JLong CallLongMethodADelegate(JEnvRef env, JObjectLocalRef obj, JMethodId jMethod, JValueSequence args);
|
||||
internal delegate JFloat CallFloatMethodDelegate(JEnvRef env, JObjectLocalRef obj, JMethodId jMethod, IntPtr args);
|
||||
internal delegate JFloat CallFloatMethodVDelegate(JEnvRef env, JObjectLocalRef obj, JMethodId jMethod, ArgIterator args);
|
||||
internal delegate JFloat CallFloatMethodADelegate(JEnvRef env, JObjectLocalRef obj, JMethodId jMethod, JValueSequence args);
|
||||
internal delegate JDouble CallDoubleMethodDelegate(JEnvRef env, JObjectLocalRef obj, JMethodId jMethod, IntPtr args);
|
||||
internal delegate JDouble CallDoubleMethodVDelegate(JEnvRef env, JObjectLocalRef obj, JMethodId jMethod, ArgIterator args);
|
||||
internal delegate JDouble CallDoubleMethodADelegate(JEnvRef env, JObjectLocalRef obj, JMethodId jMethod, JValueSequence args);
|
||||
internal delegate void CallVoidMethodDelegate(JEnvRef env, JObjectLocalRef obj, JMethodId jMethod, IntPtr args);
|
||||
internal delegate void CallVoidMethodVDelegate(JEnvRef env, JObjectLocalRef obj, JMethodId jMethod, ArgIterator args);
|
||||
internal delegate void CallVoidMethodADelegate(JEnvRef env, JObjectLocalRef obj, JMethodId jMethod, JValueSequence args);
|
||||
|
||||
internal delegate JObjectLocalRef CallNonVirtualObjectMethodDelegate(JEnvRef env, JObjectLocalRef obj, JClassLocalRef jclass, JMethodId jMethod, IntPtr args);
|
||||
internal delegate JObjectLocalRef CallNonVirtualObjectMethodVDelegate(JEnvRef env, JObjectLocalRef obj, JClassLocalRef jclass, JMethodId jMethod, ArgIterator args);
|
||||
internal delegate JObjectLocalRef CallNonVirtualObjectMethodADelegate(JEnvRef env, JObjectLocalRef obj, JClassLocalRef jclass, JMethodId jMethod, JValueSequence args);
|
||||
internal delegate JBoolean CallNonVirtualBooleanMethodDelegate(JEnvRef env, JObjectLocalRef obj, JClassLocalRef jclass, JMethodId jMethod, IntPtr args);
|
||||
internal delegate JBoolean CallNonVirtualBooleanMethodVDelegate(JEnvRef env, JObjectLocalRef obj, JClassLocalRef jclass, JMethodId jMethod, ArgIterator args);
|
||||
internal delegate JBoolean CallNonVirtualBooleanMethodADelegate(JEnvRef env, JObjectLocalRef obj, JClassLocalRef jclass, JMethodId jMethod, JValueSequence args);
|
||||
internal delegate JByte CallNonVirtualByteMethodDelegate(JEnvRef env, JObjectLocalRef obj, JClassLocalRef jclass, JMethodId jMethod, IntPtr args);
|
||||
internal delegate JByte CallNonVirtualByteMethodVDelegate(JEnvRef env, JObjectLocalRef obj, JClassLocalRef jclass, JMethodId jMethod, ArgIterator args);
|
||||
internal delegate JByte CallNonVirtualByteMethodADelegate(JEnvRef env, JObjectLocalRef obj, JClassLocalRef jclass, JMethodId jMethod, JValueSequence args);
|
||||
internal delegate JChar CallNonVirtualCharMethodDelegate(JEnvRef env, JObjectLocalRef obj, JClassLocalRef jclass, JMethodId jMethod, IntPtr args);
|
||||
internal delegate JChar CallNonVirtualCharMethodVDelegate(JEnvRef env, JObjectLocalRef obj, JClassLocalRef jclass, JMethodId jMethod, ArgIterator args);
|
||||
internal delegate JChar CallNonVirtualCharMethodADelegate(JEnvRef env, JObjectLocalRef obj, JClassLocalRef jclass, JMethodId jMethod, JValueSequence args);
|
||||
internal delegate JShort CallNonVirtualShortMethodDelegate(JEnvRef env, JObjectLocalRef obj, JClassLocalRef jclass, JMethodId jMethod, IntPtr args);
|
||||
internal delegate JShort CallNonVirtualShortMethodVDelegate(JEnvRef env, JObjectLocalRef obj, JClassLocalRef jclass, JMethodId jMethod, ArgIterator args);
|
||||
internal delegate JShort CallNonVirtualShortMethodADelegate(JEnvRef env, JObjectLocalRef obj, JClassLocalRef jclass, JMethodId jMethod, JValueSequence args);
|
||||
internal delegate JInt CallNonVirtualIntMethodDelegate(JEnvRef env, JObjectLocalRef obj, JClassLocalRef jclass, JMethodId jMethod, IntPtr args);
|
||||
internal delegate JInt CallNonVirtualIntMethodVDelegate(JEnvRef env, JObjectLocalRef obj, JClassLocalRef jclass, JMethodId jMethod, ArgIterator args);
|
||||
internal delegate JInt CallNonVirtualIntMethodADelegate(JEnvRef env, JObjectLocalRef obj, JClassLocalRef jclass, JMethodId jMethod, JValueSequence args);
|
||||
internal delegate JLong CallNonVirtualLongMethodDelegate(JEnvRef env, JObjectLocalRef obj, JClassLocalRef jclass, JMethodId jMethod, IntPtr args);
|
||||
internal delegate JLong CallNonVirtualLongMethodVDelegate(JEnvRef env, JObjectLocalRef obj, JClassLocalRef jclass, JMethodId jMethod, ArgIterator args);
|
||||
internal delegate JLong CallNonVirtualLongMethodADelegate(JEnvRef env, JObjectLocalRef obj, JClassLocalRef jclass, JMethodId jMethod, JValueSequence args);
|
||||
internal delegate JFloat CallNonVirtualFloatMethodDelegate(JEnvRef env, JObjectLocalRef obj, JClassLocalRef jclass, JMethodId jMethod, IntPtr args);
|
||||
internal delegate JFloat CallNonVirtualFloatMethodVDelegate(JEnvRef env, JObjectLocalRef obj, JClassLocalRef jclass, JMethodId jMethod, ArgIterator args);
|
||||
internal delegate JFloat CallNonVirtualFloatMethodADelegate(JEnvRef env, JObjectLocalRef obj, JClassLocalRef jclass, JMethodId jMethod, JValueSequence args);
|
||||
internal delegate JDouble CallNonVirtualDoubleMethodDelegate(JEnvRef env, JObjectLocalRef obj, JClassLocalRef jclass, JMethodId jMethod, IntPtr args);
|
||||
internal delegate JDouble CallNonVirtualDoubleMethodVDelegate(JEnvRef env, JObjectLocalRef obj, JClassLocalRef jclass, JMethodId jMethod, ArgIterator args);
|
||||
internal delegate JDouble CallNonVirtualDoubleMethodADelegate(JEnvRef env, JObjectLocalRef obj, JClassLocalRef jclass, JMethodId jMethod, JValueSequence args);
|
||||
internal delegate void CallNonVirtualVoidMethodDelegate(JEnvRef env, JObjectLocalRef obj, JClassLocalRef jclass, JMethodId jMethod, IntPtr args);
|
||||
internal delegate void CallNonVirtualVoidMethodVDelegate(JEnvRef env, JObjectLocalRef obj, JClassLocalRef jclass, JMethodId jMethod, ArgIterator args);
|
||||
internal delegate void CallNonVirtualVoidMethodADelegate(JEnvRef env, JObjectLocalRef obj, JClassLocalRef jclass, JMethodId jMethod, JValueSequence args);
|
||||
|
||||
internal delegate JFieldId GetFieldIdDelegate(JEnvRef env, JClassLocalRef jclass, CCharSequence name, CCharSequence signature);
|
||||
|
||||
internal delegate JObjectLocalRef GetObjectFieldDelegate(JEnvRef env, JObjectLocalRef obj, JFieldId jField);
|
||||
internal delegate JBoolean GetBooleanFieldDelegate(JEnvRef env, JObjectLocalRef obj, JFieldId jField);
|
||||
internal delegate JByte GetByteFieldDelegate(JEnvRef env, JObjectLocalRef obj, JFieldId jField);
|
||||
internal delegate JChar GetCharFieldDelegate(JEnvRef env, JObjectLocalRef obj, JFieldId jField);
|
||||
internal delegate JShort GetShortFieldDelegate(JEnvRef env, JObjectLocalRef obj, JFieldId jField);
|
||||
internal delegate JInt GetIntFieldDelegate(JEnvRef env, JObjectLocalRef obj, JFieldId jField);
|
||||
internal delegate JLong GetLongFieldDelegate(JEnvRef env, JObjectLocalRef obj, JFieldId jField);
|
||||
internal delegate JFloat GetFloatFieldDelegate(JEnvRef env, JObjectLocalRef obj, JFieldId jField);
|
||||
internal delegate JDouble GetDoubleFieldDelegate(JEnvRef env, JObjectLocalRef obj, JFieldId jField);
|
||||
internal delegate void SetObjectFieldDelegate(JEnvRef env, JObjectLocalRef obj, JFieldId jField, JObjectLocalRef value);
|
||||
internal delegate void SetBooleanFieldDelegate(JEnvRef env, JObjectLocalRef obj, JFieldId jField, JBoolean value);
|
||||
internal delegate void SetByteFieldDelegate(JEnvRef env, JObjectLocalRef obj, JFieldId jField, JByte value);
|
||||
internal delegate void SetCharFieldDelegate(JEnvRef env, JObjectLocalRef obj, JFieldId jField, JChar value);
|
||||
internal delegate void SetShortFieldDelegate(JEnvRef env, JObjectLocalRef obj, JFieldId jField, JShort value);
|
||||
internal delegate void SetIntFieldDelegate(JEnvRef env, JObjectLocalRef obj, JFieldId jField, JInt value);
|
||||
internal delegate void SetLongFieldDelegate(JEnvRef env, JObjectLocalRef obj, JFieldId jField, JLong value);
|
||||
internal delegate void SetFloatFieldDelegate(JEnvRef env, JObjectLocalRef obj, JFieldId jField, JFloat value);
|
||||
internal delegate void SetDoubleFieldDelegate(JEnvRef env, JObjectLocalRef obj, JFieldId jField, JDouble value);
|
||||
|
||||
internal delegate JMethodId GetStaticMethodIdDelegate(JEnvRef env, JClassLocalRef jClass, CCharSequence name, CCharSequence signature);
|
||||
|
||||
internal delegate JObjectLocalRef CallStaticObjectMethodDelegate(JEnvRef env, JClassLocalRef jclass, JMethodId jMethod, IntPtr args);
|
||||
internal delegate JObjectLocalRef CallStaticObjectMethodVDelegate(JEnvRef env, JClassLocalRef jclass, JMethodId jMethod, ArgIterator args);
|
||||
internal delegate JObjectLocalRef CallStaticObjectMethodADelegate(JEnvRef env, JClassLocalRef jclass, JMethodId jMethod, JValueSequence args);
|
||||
internal delegate JBoolean CallStaticBooleanMethodDelegate(JEnvRef env, JClassLocalRef jclass, JMethodId jMethod, IntPtr args);
|
||||
internal delegate JBoolean CallStaticBooleanMethodVDelegate(JEnvRef env, JClassLocalRef jclass, JMethodId jMethod, ArgIterator args);
|
||||
internal delegate JBoolean CallStaticBooleanMethodADelegate(JEnvRef env, JClassLocalRef jclass, JMethodId jMethod, JValueSequence args);
|
||||
internal delegate JByte CallStaticByteMethodDelegate(JEnvRef env, JClassLocalRef jclass, JMethodId jMethod, IntPtr args);
|
||||
internal delegate JByte CallStaticByteMethodVDelegate(JEnvRef env, JClassLocalRef jclass, JMethodId jMethod, ArgIterator args);
|
||||
internal delegate JByte CallStaticByteMethodADelegate(JEnvRef env, JClassLocalRef jclass, JMethodId jMethod, JValueSequence args);
|
||||
internal delegate JChar CallStaticCharMethodDelegate(JEnvRef env, JClassLocalRef jclass, JMethodId jMethod, IntPtr args);
|
||||
internal delegate JChar CallStaticCharMethodVDelegate(JEnvRef env, JClassLocalRef jclass, JMethodId jMethod, ArgIterator args);
|
||||
internal delegate JChar CallStaticCharMethodADelegate(JEnvRef env, JClassLocalRef jclass, JMethodId jMethod, JValueSequence args);
|
||||
internal delegate JShort CallStaticShortMethodDelegate(JEnvRef env, JClassLocalRef jclass, JMethodId jMethod, IntPtr args);
|
||||
internal delegate JShort CallStaticShortMethodVDelegate(JEnvRef env, JClassLocalRef jclass, JMethodId jMethod, ArgIterator args);
|
||||
internal delegate JShort CallStaticShortMethodADelegate(JEnvRef env, JClassLocalRef jclass, JMethodId jMethod, JValueSequence args);
|
||||
internal delegate JInt CallStaticIntMethodDelegate(JEnvRef env, JClassLocalRef jclass, JMethodId jMethod, IntPtr args);
|
||||
internal delegate JInt CallStaticIntMethodVDelegate(JEnvRef env, JClassLocalRef jclass, JMethodId jMethod, ArgIterator args);
|
||||
internal delegate JInt CallStaticIntMethodADelegate(JEnvRef env, JClassLocalRef jclass, JMethodId jMethod, JValueSequence args);
|
||||
internal delegate JLong CallStaticLongMethodDelegate(JEnvRef env, JClassLocalRef jclass, JMethodId jMethod, IntPtr args);
|
||||
internal delegate JLong CallStaticLongMethodVDelegate(JEnvRef env, JClassLocalRef jclass, JMethodId jMethod, ArgIterator args);
|
||||
internal delegate JLong CallStaticLongMethodADelegate(JEnvRef env, JClassLocalRef jclass, JMethodId jMethod, JValueSequence args);
|
||||
internal delegate JFloat CallStaticFloatMethodDelegate(JEnvRef env, JClassLocalRef jclass, JMethodId jMethod, IntPtr args);
|
||||
internal delegate JFloat CallStaticFloatMethodVDelegate(JEnvRef env, JClassLocalRef jclass, JMethodId jMethod, ArgIterator args);
|
||||
internal delegate JFloat CallStaticFloatMethodADelegate(JEnvRef env, JClassLocalRef jclass, JMethodId jMethod, JValueSequence args);
|
||||
internal delegate JDouble CallStaticDoubleMethodDelegate(JEnvRef env, JClassLocalRef jclass, JMethodId jMethod, IntPtr args);
|
||||
internal delegate JDouble CallStaticDoubleMethodVDelegate(JEnvRef env, JClassLocalRef jclass, JMethodId jMethod, ArgIterator args);
|
||||
internal delegate JDouble CallStaticDoubleMethodADelegate(JEnvRef env, JClassLocalRef jclass, JMethodId jMethod, JValueSequence args);
|
||||
internal delegate void CallStaticVoidMethodDelegate(JEnvRef env, JClassLocalRef jclass, JMethodId jMethod, IntPtr args);
|
||||
internal delegate void CallStaticVoidMethodVDelegate(JEnvRef env, JClassLocalRef jclass, JMethodId jMethod, ArgIterator args);
|
||||
internal delegate void CallStaticVoidMethodADelegate(JEnvRef env, JClassLocalRef jclass, JMethodId jMethod, JValueSequence args);
|
||||
|
||||
internal delegate JFieldId GetStaticFieldIdDelegate(JEnvRef env, JClassLocalRef jclass, CCharSequence name, CCharSequence signature);
|
||||
|
||||
internal delegate JObjectLocalRef GetStaticObjectFieldDelegate(JEnvRef env, JClassLocalRef jclass, JFieldId jField);
|
||||
internal delegate JBoolean GetStaticBooleanFieldDelegate(JEnvRef env, JClassLocalRef jclass, JFieldId jField);
|
||||
internal delegate JByte GetStaticByteFieldDelegate(JEnvRef env, JClassLocalRef jclass, JFieldId jField);
|
||||
internal delegate JChar GetStaticCharFieldDelegate(JEnvRef env, JClassLocalRef jclass, JFieldId jField);
|
||||
internal delegate JShort GetStaticShortFieldDelegate(JEnvRef env, JClassLocalRef jclass, JFieldId jField);
|
||||
internal delegate JInt GetStaticIntFieldDelegate(JEnvRef env, JClassLocalRef jclass, JFieldId jField);
|
||||
internal delegate JLong GetStaticLongFieldDelegate(JEnvRef env, JClassLocalRef jclass, JFieldId jField);
|
||||
internal delegate JFloat GetStaticFloatFieldDelegate(JEnvRef env, JClassLocalRef jclass, JFieldId jField);
|
||||
internal delegate JDouble GetStaticDoubleFieldDelegate(JEnvRef env, JClassLocalRef jclass, JFieldId jField);
|
||||
internal delegate void SetStaticObjectFieldDelegate(JEnvRef env, JClassLocalRef jclass, JFieldId jField, JObjectLocalRef value);
|
||||
internal delegate void SetStaticBooleanFieldDelegate(JEnvRef env, JClassLocalRef jclass, JFieldId jField, JBoolean value);
|
||||
internal delegate void SetStaticByteFieldDelegate(JEnvRef env, JClassLocalRef jclass, JFieldId jField, JByte value);
|
||||
internal delegate void SetStaticCharFieldDelegate(JEnvRef env, JClassLocalRef jclass, JFieldId jField, JChar value);
|
||||
internal delegate void SetStaticShortFieldDelegate(JEnvRef env, JClassLocalRef jclass, JFieldId jField, JShort value);
|
||||
internal delegate void SetStaticIntFieldDelegate(JEnvRef env, JClassLocalRef jclass, JFieldId jField, JInt value);
|
||||
internal delegate void SetStaticLongFieldDelegate(JEnvRef env, JClassLocalRef jclass, JFieldId jField, JLong value);
|
||||
internal delegate void SetStaticFloatFieldDelegate(JEnvRef env, JClassLocalRef jclass, JFieldId jField, JFloat value);
|
||||
internal delegate void SetStaticDoubleFieldDelegate(JEnvRef env, JClassLocalRef jclass, JFieldId jField, JDouble value);
|
||||
|
||||
internal delegate JStringLocalRef NewStringDelegate(JEnvRef env, JCharSequence unicode, Int32 length);
|
||||
|
||||
internal delegate Int32 GetStringLengthDelegate(JEnvRef env, JStringLocalRef jString);
|
||||
internal delegate JCharSequence GetStringCharsDelegate(JEnvRef env, JStringLocalRef jString, JBooleanRef isCopy);
|
||||
internal delegate void ReleaseStringCharsDelegate(JEnvRef env, JStringLocalRef jString, JCharSequence chars);
|
||||
|
||||
internal delegate JStringLocalRef NewStringUtfDelegate(JEnvRef env, CCharSequence unicode);
|
||||
internal delegate Int32 GetStringUtfLengthDelegate(JEnvRef env, JStringLocalRef jString);
|
||||
internal delegate CCharSequence GetStringUtfCharsDelegate(JEnvRef env, JStringLocalRef jString, JBooleanRef isCopy);
|
||||
internal delegate void ReleaseStringUtfCharsDelegate(JEnvRef env, JStringLocalRef jString, CCharSequence chars);
|
||||
|
||||
internal delegate Int32 GetArrayLengthDelegate(JEnvRef env, JArrayLocalRef array);
|
||||
|
||||
internal delegate JArrayLocalRef NewObjectArrayDelegate(JEnvRef env, Int32 length, JClassLocalRef jClass, JObjectLocalRef init);
|
||||
internal delegate JObjectLocalRef GetObjectArrayElementDelegate(JEnvRef env, JArrayLocalRef jArray, Int32 index);
|
||||
internal delegate void SetObjectArrayElementDelegate(JEnvRef env, JArrayLocalRef jArray, Int32 index, JObjectLocalRef obj);
|
||||
|
||||
internal delegate JArrayLocalRef NewBooleanArrayDelegate(JEnvRef env, Int32 length);
|
||||
internal delegate JArrayLocalRef NewByteArrayDelegate(JEnvRef env, Int32 length);
|
||||
internal delegate JArrayLocalRef NewCharArrayDelegate(JEnvRef env, Int32 length);
|
||||
internal delegate JArrayLocalRef NewShortArrayDelegate(JEnvRef env, Int32 length);
|
||||
internal delegate JArrayLocalRef NewIntArrayDelegate(JEnvRef env, Int32 length);
|
||||
internal delegate JArrayLocalRef NewLongArrayDelegate(JEnvRef env, Int32 length);
|
||||
internal delegate JArrayLocalRef NewFloatArrayDelegate(JEnvRef env, Int32 length);
|
||||
internal delegate JArrayLocalRef NewDoubleArrayDelegate(JEnvRef env, Int32 length);
|
||||
|
||||
internal delegate IntPtr GetBooleanArrayElementsDelegate(JEnvRef env, JArrayLocalRef jArray, JBooleanRef isCopy);
|
||||
internal delegate IntPtr GetByteArrayElementsDelegate(JEnvRef env, JArrayLocalRef jArray, JBooleanRef isCopy);
|
||||
internal delegate IntPtr GetCharArrayElementsDelegate(JEnvRef env, JArrayLocalRef jArray, JBooleanRef isCopy);
|
||||
internal delegate IntPtr GetShortArrayElementsDelegate(JEnvRef env, JArrayLocalRef jArray, JBooleanRef isCopy);
|
||||
internal delegate IntPtr GetIntArrayElementsDelegate(JEnvRef env, JArrayLocalRef jArray, JBooleanRef isCopy);
|
||||
internal delegate IntPtr GetLongArrayElementsDelegate(JEnvRef env, JArrayLocalRef jArray, JBooleanRef isCopy);
|
||||
internal delegate IntPtr GetFloatArrayElementsDelegate(JEnvRef env, JArrayLocalRef jArray, JBooleanRef isCopy);
|
||||
internal delegate IntPtr GetDoubleArrayElementsDelegate(JEnvRef env, JArrayLocalRef jArray, JBooleanRef isCopy);
|
||||
|
||||
internal delegate void ReleaseBooleanArrayElementsDelegate(JEnvRef env, JArrayLocalRef jArray, IntPtr elements, JReleaseMode mode);
|
||||
internal delegate void ReleaseByteArrayElementsDelegate(JEnvRef env, JArrayLocalRef jArray, IntPtr elements, JReleaseMode mode);
|
||||
internal delegate void ReleaseCharArrayElementsDelegate(JEnvRef env, JArrayLocalRef jArray, IntPtr elements, JReleaseMode mode);
|
||||
internal delegate void ReleaseShortArrayElementsDelegate(JEnvRef env, JArrayLocalRef jArray, IntPtr elements, JReleaseMode mode);
|
||||
internal delegate void ReleaseIntArrayElementsDelegate(JEnvRef env, JArrayLocalRef jArray, IntPtr elements, JReleaseMode mode);
|
||||
internal delegate void ReleaseLongArrayElementsDelegate(JEnvRef env, JArrayLocalRef jArray, IntPtr elements, JReleaseMode mode);
|
||||
internal delegate void ReleaseFloatArrayElementsDelegate(JEnvRef env, JArrayLocalRef jArray, IntPtr elements, JReleaseMode mode);
|
||||
internal delegate void ReleaseDoubleArrayElementsDelegate(JEnvRef env, JArrayLocalRef jArray, IntPtr elements, JReleaseMode mode);
|
||||
|
||||
internal delegate void GetBooleanArrayRegionDelegate(JEnvRef env, JArrayLocalRef jArray, Int32 startIndex, Int32 length, IntPtr buffer);
|
||||
internal delegate void GetByteArrayRegionDelegate(JEnvRef env, JArrayLocalRef jArray, Int32 startIndex, Int32 length, IntPtr buffer);
|
||||
internal delegate void GetCharArrayRegionDelegate(JEnvRef env, JArrayLocalRef jArray, Int32 startIndex, Int32 length, IntPtr buffer);
|
||||
internal delegate void GetShortArrayRegionDelegate(JEnvRef env, JArrayLocalRef jArray, Int32 startIndex, Int32 length, IntPtr buffer);
|
||||
internal delegate void GetIntArrayRegionDelegate(JEnvRef env, JArrayLocalRef jArray, Int32 startIndex, Int32 length, IntPtr buffer);
|
||||
internal delegate void GetLongArrayRegionDelegate(JEnvRef env, JArrayLocalRef jArray, Int32 startIndex, Int32 length, IntPtr buffer);
|
||||
internal delegate void GetFloatArrayRegionDelegate(JEnvRef env, JArrayLocalRef jArray, Int32 startIndex, Int32 length, IntPtr buffer);
|
||||
internal delegate void GetDoubleArrayRegionDelegate(JEnvRef env, JArrayLocalRef jArray, Int32 startIndex, Int32 length, IntPtr buffer);
|
||||
internal delegate void SetBooleanArrayRegionDelegate(JEnvRef env, JArrayLocalRef jArray, Int32 startIndex, Int32 length, IntPtr buffer);
|
||||
internal delegate void SetByteArrayRegionDelegate(JEnvRef env, JArrayLocalRef jArray, Int32 startIndex, Int32 length, IntPtr buffer);
|
||||
internal delegate void SetCharArrayRegionDelegate(JEnvRef env, JArrayLocalRef jArray, Int32 startIndex, Int32 length, IntPtr buffer);
|
||||
internal delegate void SetShortArrayRegionDelegate(JEnvRef env, JArrayLocalRef jArray, Int32 startIndex, Int32 length, IntPtr buffer);
|
||||
internal delegate void SetIntArrayRegionDelegate(JEnvRef env, JArrayLocalRef jArray, Int32 startIndex, Int32 length, IntPtr buffer);
|
||||
internal delegate void SetLongArrayRegionDelegate(JEnvRef env, JArrayLocalRef jArray, Int32 startIndex, Int32 length, IntPtr buffer);
|
||||
internal delegate void SetFloatArrayRegionDelegate(JEnvRef env, JArrayLocalRef jArray, Int32 startIndex, Int32 length, IntPtr buffer);
|
||||
internal delegate void SetDoubleArrayRegionDelegate(JEnvRef env, JArrayLocalRef jArray, Int32 startIndex, Int32 length, IntPtr buffer);
|
||||
|
||||
internal delegate JResult RegisterNativesDelegate(JEnvRef env, JClassLocalRef jClass, JNativeMethodSequence methods);
|
||||
internal delegate JResult UnregisterNativesDelegate(JEnvRef env, JClassLocalRef jClass);
|
||||
|
||||
internal delegate JResult MonitorEnterDelegate(JEnvRef env, JObjectLocalRef jClass);
|
||||
internal delegate JResult MonitorExitDelegate(JEnvRef env, JObjectLocalRef jClass);
|
||||
|
||||
internal delegate JResult GetJavaVMDelegate(JEnvRef env, ref JavaVMRef jvm);
|
||||
|
||||
internal delegate void GetStringRegionDelegate(JEnvRef env, JStringLocalRef jString, Int32 startIndex, Int32 length, JCharSequence buffer);
|
||||
internal delegate void GetStringUtfRegionDelegate(JEnvRef env, JStringLocalRef jString, Int32 startIndex, Int32 length, CCharSequence buffer);
|
||||
|
||||
internal delegate IntPtr GetPrimitiveArrayCriticalDelegate(JEnvRef env, JArrayLocalRef jArray, JBooleanRef isCopy);
|
||||
internal delegate void ReleasePrimitiveArrayCriticalDelegate(JEnvRef env, JArrayLocalRef jArray, IntPtr elements, JReleaseMode mode);
|
||||
|
||||
internal delegate JCharSequence GetStringCriticalDelegate(JEnvRef env, JStringLocalRef jString, JBooleanRef isCopy);
|
||||
internal delegate void ReleaseStringCriticalDelegate(JEnvRef env, JStringLocalRef jString, JCharSequence chars);
|
||||
|
||||
internal delegate JWeakRef NewWeakGlobalRefDelegate(JEnvRef env, JObjectLocalRef obj);
|
||||
internal delegate void DeleteWeakGlobalRefDelegate(JEnvRef env, JWeakRef jWeak);
|
||||
|
||||
internal delegate Boolean ExceptionCheckDelegate(JEnvRef env);
|
||||
|
||||
internal delegate JObjectLocalRef NewDirectByteBufferDelegate(JEnvRef env, IntPtr address, Int64 capacity);
|
||||
internal delegate IntPtr GetDirectBufferAddressDelegate(JEnvRef env, JObjectLocalRef buffObj);
|
||||
internal delegate Int64 GetDirectBufferCapacityDelegate(JEnvRef env, JObjectLocalRef buffObj);
|
||||
|
||||
internal delegate JReferenceType GetObjectRefTypeDelegate(JEnvRef env, JObjectLocalRef obj);
|
||||
|
||||
internal delegate JResult DestroyJavaVMDelegate(JavaVMRef vm);
|
||||
internal delegate JResult AttachCurrentThreadDelegate(JavaVMRef vm, ref JEnvRef env, in JavaVMAttachArgs args);
|
||||
internal delegate JResult DetachCurrentThreadDelegate(JavaVMRef vm);
|
||||
|
||||
internal delegate JResult GetEnvDelegate(JavaVMRef vm, ref JEnvRef env, JInt version);
|
||||
|
||||
internal delegate JResult AttachCurrentThreadAsDaemonDelegate(JavaVMRef vm, ref JEnvRef env, in JavaVMAttachArgs args);
|
||||
}
|
28
src/LibRyujinx/Jni/Identifiers/JFieldId.cs
Normal file
28
src/LibRyujinx/Jni/Identifiers/JFieldId.cs
Normal file
@ -0,0 +1,28 @@
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System;
|
||||
|
||||
namespace LibRyujinx.Jni.Identifiers
|
||||
{
|
||||
public readonly struct JFieldId : IEquatable<JFieldId>
|
||||
{
|
||||
#pragma warning disable 0649
|
||||
private readonly IntPtr _value;
|
||||
#pragma warning restore 0649
|
||||
|
||||
#region Public Methods
|
||||
public Boolean Equals(JFieldId other)
|
||||
=> this._value.Equals(other._value);
|
||||
#endregion
|
||||
|
||||
#region Override Methods
|
||||
public override Boolean Equals([NotNullWhen(true)] Object obj)
|
||||
=> obj is JFieldId other && this.Equals(other);
|
||||
public override Int32 GetHashCode() => this._value.GetHashCode();
|
||||
#endregion
|
||||
|
||||
#region Operators
|
||||
public static Boolean operator ==(JFieldId a, JFieldId b) => a.Equals(b);
|
||||
public static Boolean operator !=(JFieldId a, JFieldId b) => !a.Equals(b);
|
||||
#endregion
|
||||
}
|
||||
}
|
28
src/LibRyujinx/Jni/Identifiers/JMethodId.cs
Normal file
28
src/LibRyujinx/Jni/Identifiers/JMethodId.cs
Normal file
@ -0,0 +1,28 @@
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System;
|
||||
|
||||
namespace LibRyujinx.Jni.Identifiers
|
||||
{
|
||||
public readonly struct JMethodId : IEquatable<JMethodId>
|
||||
{
|
||||
#pragma warning disable 0649
|
||||
private readonly IntPtr _value;
|
||||
#pragma warning restore 0649
|
||||
|
||||
#region Public Methods
|
||||
public Boolean Equals(JMethodId other)
|
||||
=> this._value.Equals(other._value);
|
||||
#endregion
|
||||
|
||||
#region Override Methods
|
||||
public override Boolean Equals([NotNullWhen(true)] Object obj)
|
||||
=> obj is JMethodId other && this.Equals(other);
|
||||
public override Int32 GetHashCode() => this._value.GetHashCode();
|
||||
#endregion
|
||||
|
||||
#region Operators
|
||||
public static Boolean operator ==(JMethodId a, JMethodId b) => a.Equals(b);
|
||||
public static Boolean operator !=(JMethodId a, JMethodId b) => !a.Equals(b);
|
||||
#endregion
|
||||
}
|
||||
}
|
12
src/LibRyujinx/Jni/JReferenceType.cs
Normal file
12
src/LibRyujinx/Jni/JReferenceType.cs
Normal file
@ -0,0 +1,12 @@
|
||||
using System;
|
||||
|
||||
namespace LibRyujinx.Jni
|
||||
{
|
||||
public enum JReferenceType : Int32
|
||||
{
|
||||
InvalidRefType = 0,
|
||||
LocalRefType = 1,
|
||||
GlobalRefType = 2,
|
||||
WeakGlobalRefType = 3
|
||||
}
|
||||
}
|
10
src/LibRyujinx/Jni/JReleaseMode.cs
Normal file
10
src/LibRyujinx/Jni/JReleaseMode.cs
Normal file
@ -0,0 +1,10 @@
|
||||
using System;
|
||||
namespace LibRyujinx.Jni
|
||||
{
|
||||
public enum JReleaseMode : Int32
|
||||
{
|
||||
Free = 0,
|
||||
Commit = 1,
|
||||
Abort = 2,
|
||||
}
|
||||
}
|
14
src/LibRyujinx/Jni/JResult.cs
Normal file
14
src/LibRyujinx/Jni/JResult.cs
Normal file
@ -0,0 +1,14 @@
|
||||
using System;
|
||||
namespace LibRyujinx.Jni
|
||||
{
|
||||
public enum JResult : Int32
|
||||
{
|
||||
Ok = 0,
|
||||
Error = -1,
|
||||
DetachedThreadError = -2,
|
||||
VersionError = -3,
|
||||
MemoryError = -4,
|
||||
ExitingVMError = -5,
|
||||
InvalidArgumentsError = -6,
|
||||
}
|
||||
}
|
36
src/LibRyujinx/Jni/Pointers/CCharSequence.cs
Normal file
36
src/LibRyujinx/Jni/Pointers/CCharSequence.cs
Normal file
@ -0,0 +1,36 @@
|
||||
using System.Runtime.InteropServices;
|
||||
using System;
|
||||
|
||||
using Rxmxnx.PInvoke;
|
||||
|
||||
namespace LibRyujinx.Jni.Pointers
|
||||
{
|
||||
public readonly struct CCharSequence : IEquatable<CCharSequence>
|
||||
{
|
||||
private readonly IntPtr _value;
|
||||
|
||||
private CCharSequence(IntPtr value) => this._value = value;
|
||||
|
||||
#region Operators
|
||||
public static implicit operator CCharSequence(IntPtr value) => new(value);
|
||||
public static implicit operator CCharSequence(Span<Byte> span) => new(span.GetUnsafeIntPtr());
|
||||
public static implicit operator CCharSequence(ReadOnlySpan<Byte> readonlySpan) => new(readonlySpan.GetUnsafeIntPtr());
|
||||
|
||||
public static CCharSequence operator ++(CCharSequence a) => new(a._value + sizeof(Byte));
|
||||
public static CCharSequence operator --(CCharSequence a) => new(a._value - sizeof(Byte));
|
||||
public static Boolean operator ==(CCharSequence a, CCharSequence b) => a._value.Equals(b._value);
|
||||
public static Boolean operator !=(CCharSequence a, CCharSequence b) => !a._value.Equals(b._value);
|
||||
#endregion
|
||||
|
||||
#region Public Methods
|
||||
public Boolean Equals(CCharSequence other) => this._value.Equals(other._value);
|
||||
public String AsString(Int32 length = 0)
|
||||
=> length == 0 ? Marshal.PtrToStringUTF8(_value) : Marshal.PtrToStringUTF8(_value, length);
|
||||
#endregion
|
||||
|
||||
#region Overrided Methods
|
||||
public override Boolean Equals(Object obj) => obj is CCharSequence other && this.Equals(other);
|
||||
public override Int32 GetHashCode() => this._value.GetHashCode();
|
||||
#endregion
|
||||
}
|
||||
}
|
30
src/LibRyujinx/Jni/Pointers/JBooleanRef.cs
Normal file
30
src/LibRyujinx/Jni/Pointers/JBooleanRef.cs
Normal file
@ -0,0 +1,30 @@
|
||||
using System.Runtime.CompilerServices;
|
||||
using System;
|
||||
|
||||
using LibRyujinx.Jni.Primitives;
|
||||
|
||||
using Rxmxnx.PInvoke;
|
||||
|
||||
namespace LibRyujinx.Jni.Pointers
|
||||
{
|
||||
public readonly struct JBooleanRef
|
||||
{
|
||||
private static readonly Int32 JBooleanResultFalse = 0;
|
||||
private static readonly Int32 JBooleanResultTrue = 1;
|
||||
|
||||
#pragma warning disable IDE0052
|
||||
private readonly IntPtr _value;
|
||||
#pragma warning restore IDE0052
|
||||
|
||||
public JBooleanRef(JBoolean? jBoolean)
|
||||
=> this._value = jBoolean.HasValue ? GetJBooleanRef(jBoolean.Value) : IntPtr.Zero;
|
||||
|
||||
private static IntPtr GetJBooleanRef(Boolean value)
|
||||
{
|
||||
// Probably gonna break stuff
|
||||
var t = JBooleanResultTrue;
|
||||
var f = JBooleanResultFalse;
|
||||
return value ? Unsafe.AsRef(ref f).GetUnsafeIntPtr() : Unsafe.AsRef(ref t).GetUnsafeIntPtr();
|
||||
}
|
||||
}
|
||||
}
|
33
src/LibRyujinx/Jni/Pointers/JCharSequence.cs
Normal file
33
src/LibRyujinx/Jni/Pointers/JCharSequence.cs
Normal file
@ -0,0 +1,33 @@
|
||||
using Rxmxnx.PInvoke;
|
||||
using System;
|
||||
|
||||
namespace LibRyujinx.Jni.Pointers
|
||||
{
|
||||
public readonly struct JCharSequence : IEquatable<JCharSequence>
|
||||
{
|
||||
private readonly IntPtr _value;
|
||||
|
||||
private JCharSequence(IntPtr value) => this._value = value;
|
||||
|
||||
#region Operators
|
||||
public static implicit operator JCharSequence(IntPtr value) => new(value);
|
||||
public static implicit operator JCharSequence(Span<Char> span) => new(span.GetUnsafeIntPtr());
|
||||
public static implicit operator JCharSequence(ReadOnlySpan<Char> readonlySpan) => new(readonlySpan.GetUnsafeIntPtr());
|
||||
|
||||
public static JCharSequence operator ++(JCharSequence a) => new(a._value + sizeof(Char));
|
||||
public static JCharSequence operator --(JCharSequence a) => new(a._value - sizeof(Char));
|
||||
public static Boolean operator ==(JCharSequence a, JCharSequence b) => a._value.Equals(b._value);
|
||||
public static Boolean operator !=(JCharSequence a, JCharSequence b) => !a._value.Equals(b._value);
|
||||
#endregion
|
||||
|
||||
#region Public Methods
|
||||
public Boolean Equals(JCharSequence other) => this._value.Equals(other._value);
|
||||
public String AsString(Int32 length = 0) => this._value.GetUnsafeString(length);
|
||||
#endregion
|
||||
|
||||
#region Overrided Methods
|
||||
public override Boolean Equals(Object obj) => obj is JCharSequence other && this.Equals(other);
|
||||
public override Int32 GetHashCode() => this._value.GetHashCode();
|
||||
#endregion
|
||||
}
|
||||
}
|
32
src/LibRyujinx/Jni/Pointers/JEnvRef.cs
Normal file
32
src/LibRyujinx/Jni/Pointers/JEnvRef.cs
Normal file
@ -0,0 +1,32 @@
|
||||
using LibRyujinx.Jni.Values;
|
||||
|
||||
using Rxmxnx.PInvoke;
|
||||
using System;
|
||||
|
||||
namespace LibRyujinx.Jni.Pointers
|
||||
{
|
||||
public readonly struct JEnvRef : IEquatable<JEnvRef>
|
||||
{
|
||||
#pragma warning disable 0649
|
||||
private readonly IntPtr _value;
|
||||
#pragma warning restore 0649
|
||||
|
||||
#region Operators
|
||||
public static Boolean operator ==(JEnvRef a, JEnvRef b) => a._value.Equals(b._value);
|
||||
public static Boolean operator !=(JEnvRef a, JEnvRef b) => !a._value.Equals(b._value);
|
||||
#endregion
|
||||
|
||||
#region Public Properties
|
||||
internal readonly ref JEnvValue Environment => ref this._value.GetUnsafeReference<JEnvValue>();
|
||||
#endregion
|
||||
|
||||
#region Public Methods
|
||||
public Boolean Equals(JEnvRef other) => this._value.Equals(other._value);
|
||||
#endregion
|
||||
|
||||
#region Overrided Methods
|
||||
public override Boolean Equals(Object obj) => obj is JEnvRef other && this.Equals(other);
|
||||
public override Int32 GetHashCode() => this._value.GetHashCode();
|
||||
#endregion
|
||||
}
|
||||
}
|
33
src/LibRyujinx/Jni/Pointers/JNativeMethodSequence.cs
Normal file
33
src/LibRyujinx/Jni/Pointers/JNativeMethodSequence.cs
Normal file
@ -0,0 +1,33 @@
|
||||
using LibRyujinx.Jni.Values;
|
||||
|
||||
using Rxmxnx.PInvoke;
|
||||
using System;
|
||||
|
||||
namespace LibRyujinx.Jni.Pointers
|
||||
{
|
||||
public readonly struct JNativeMethodSequence : IEquatable<JNativeMethodSequence>
|
||||
{
|
||||
private readonly IntPtr _value;
|
||||
|
||||
private JNativeMethodSequence(IntPtr value) => this._value = value;
|
||||
|
||||
#region Operators
|
||||
public static implicit operator JNativeMethodSequence(IntPtr value) => new(value);
|
||||
public static implicit operator JNativeMethodSequence(ReadOnlySpan<JNativeMethod> readonlySpan) => new(readonlySpan.GetUnsafeIntPtr());
|
||||
|
||||
public static JNativeMethodSequence operator ++(JNativeMethodSequence a) => new(a._value + JValue.Size);
|
||||
public static JNativeMethodSequence operator --(JNativeMethodSequence a) => new(a._value - JValue.Size);
|
||||
public static Boolean operator ==(JNativeMethodSequence a, JNativeMethodSequence b) => a._value.Equals(b._value);
|
||||
public static Boolean operator !=(JNativeMethodSequence a, JNativeMethodSequence b) => !a._value.Equals(b._value);
|
||||
#endregion
|
||||
|
||||
#region Public Methods
|
||||
public Boolean Equals(JNativeMethodSequence other) => this._value.Equals(other._value);
|
||||
#endregion
|
||||
|
||||
#region Overrided Methods
|
||||
public override Boolean Equals(Object obj) => obj is JNativeMethodSequence other && this.Equals(other);
|
||||
public override Int32 GetHashCode() => this._value.GetHashCode();
|
||||
#endregion
|
||||
}
|
||||
}
|
33
src/LibRyujinx/Jni/Pointers/JValueSequence.cs
Normal file
33
src/LibRyujinx/Jni/Pointers/JValueSequence.cs
Normal file
@ -0,0 +1,33 @@
|
||||
using LibRyujinx.Jni.Values;
|
||||
|
||||
using Rxmxnx.PInvoke;
|
||||
using System;
|
||||
|
||||
namespace LibRyujinx.Jni.Internal.Pointers
|
||||
{
|
||||
internal readonly struct JValueSequence : IEquatable<JValueSequence>
|
||||
{
|
||||
private readonly IntPtr _value;
|
||||
|
||||
private JValueSequence(IntPtr value) => this._value = value;
|
||||
internal JValueSequence(ReadOnlySpan<JValue> readonlySpan) : this(readonlySpan.GetUnsafeIntPtr()) { }
|
||||
|
||||
#region Operators
|
||||
public static implicit operator JValueSequence(IntPtr value) => new(value);
|
||||
|
||||
public static JValueSequence operator ++(JValueSequence a) => new(a._value + JValue.Size);
|
||||
public static JValueSequence operator --(JValueSequence a) => new(a._value - JValue.Size);
|
||||
public static Boolean operator ==(JValueSequence a, JValueSequence b) => a._value.Equals(b._value);
|
||||
public static Boolean operator !=(JValueSequence a, JValueSequence b) => !a._value.Equals(b._value);
|
||||
#endregion
|
||||
|
||||
#region Public Methods
|
||||
public Boolean Equals(JValueSequence other) => this._value.Equals(other._value);
|
||||
#endregion
|
||||
|
||||
#region Overrided Methods
|
||||
public override Boolean Equals(Object obj) => obj is JValueSequence other && this.Equals(other);
|
||||
public override Int32 GetHashCode() => this._value.GetHashCode();
|
||||
#endregion
|
||||
}
|
||||
}
|
25
src/LibRyujinx/Jni/Pointers/JavaVMRef.cs
Normal file
25
src/LibRyujinx/Jni/Pointers/JavaVMRef.cs
Normal file
@ -0,0 +1,25 @@
|
||||
using System;
|
||||
|
||||
namespace LibRyujinx.Jni.Pointers
|
||||
{
|
||||
public readonly struct JavaVMRef : IEquatable<JavaVMRef>
|
||||
{
|
||||
#pragma warning disable 0649
|
||||
private readonly IntPtr _value;
|
||||
#pragma warning restore 0649
|
||||
|
||||
#region Operators
|
||||
public static Boolean operator ==(JavaVMRef a, JavaVMRef b) => a._value.Equals(b._value);
|
||||
public static Boolean operator !=(JavaVMRef a, JavaVMRef b) => !a._value.Equals(b._value);
|
||||
#endregion
|
||||
|
||||
#region Public Methods
|
||||
public Boolean Equals(JavaVMRef other) => this._value.Equals(other._value);
|
||||
#endregion
|
||||
|
||||
#region Overrided Methods
|
||||
public override Boolean Equals(Object obj) => obj is JavaVMRef other && this.Equals(other);
|
||||
public override Int32 GetHashCode() => this._value.GetHashCode();
|
||||
#endregion
|
||||
}
|
||||
}
|
67
src/LibRyujinx/Jni/Primitives/JBoolean.cs
Normal file
67
src/LibRyujinx/Jni/Primitives/JBoolean.cs
Normal file
@ -0,0 +1,67 @@
|
||||
using LibRyujinx.Jni.Pointers;
|
||||
|
||||
using Rxmxnx.PInvoke;
|
||||
using System;
|
||||
|
||||
namespace LibRyujinx.Jni.Primitives
|
||||
{
|
||||
public readonly struct JBoolean : IComparable<Boolean>, IEquatable<Boolean>
|
||||
{
|
||||
internal static readonly Type Type = typeof(JBoolean);
|
||||
private static readonly Byte trueByte = 1;
|
||||
private static readonly Byte falseByte = 2;
|
||||
|
||||
public static readonly CString Signature = (CString)"Z";
|
||||
|
||||
private readonly Byte _value;
|
||||
private Boolean Value => this._value == trueByte;
|
||||
|
||||
private JBoolean(Boolean value) => this._value = value ? trueByte : falseByte;
|
||||
|
||||
#region Operators
|
||||
public static implicit operator JBoolean(Boolean value) => new(value);
|
||||
public static implicit operator Boolean(JBoolean jValue) => jValue._value == 1;
|
||||
public static implicit operator JBooleanRef(JBoolean? jValue) => new(jValue);
|
||||
public static JBoolean operator !(JBoolean a) => new(!a.Value);
|
||||
public static JBoolean operator |(JBoolean a, JBoolean b) => new(a.Value || b.Value);
|
||||
public static JBoolean operator |(Boolean a, JBoolean b) => new(a || b.Value);
|
||||
public static JBoolean operator |(JBoolean a, Boolean b) => new(a.Value || b);
|
||||
public static JBoolean operator &(JBoolean a, JBoolean b) => new(a.Value && b.Value);
|
||||
public static JBoolean operator &(Boolean a, JBoolean b) => new(a && b.Value);
|
||||
public static JBoolean operator &(JBoolean a, Boolean b) => new(a.Value && b);
|
||||
public static Boolean operator ==(JBoolean a, JBoolean b) => a._value.Equals(b._value);
|
||||
public static Boolean operator ==(Boolean a, JBoolean b) => a.Equals(b._value);
|
||||
public static Boolean operator ==(JBoolean a, Boolean b) => a._value.Equals(b);
|
||||
public static Boolean operator !=(JBoolean a, JBoolean b) => !a._value.Equals(b._value);
|
||||
public static Boolean operator !=(Boolean a, JBoolean b) => !a.Equals(b._value);
|
||||
public static Boolean operator !=(JBoolean a, Boolean b) => !a._value.Equals(b);
|
||||
public static Boolean operator >(JBoolean a, JBoolean b) => a._value.CompareTo(b._value) > 0;
|
||||
public static Boolean operator >(Boolean a, JBoolean b) => a.CompareTo(b._value) > 0;
|
||||
public static Boolean operator >(JBoolean a, Boolean b) => a._value.CompareTo(b) > 0;
|
||||
public static Boolean operator <(JBoolean a, JBoolean b) => a._value.CompareTo(b._value) < 0;
|
||||
public static Boolean operator <(Boolean a, JBoolean b) => a.CompareTo(b._value) < 0;
|
||||
public static Boolean operator <(JBoolean a, Boolean b) => a._value.CompareTo(b) < 0;
|
||||
public static Boolean operator >=(JBoolean a, JBoolean b) => a._value.CompareTo(b._value) > 0 || a.Equals(b._value);
|
||||
public static Boolean operator >=(Boolean a, JBoolean b) => a.CompareTo(b._value) > 0 || a.Equals(b._value);
|
||||
public static Boolean operator >=(JBoolean a, Boolean b) => a._value.CompareTo(b) > 0 || a._value.Equals(b);
|
||||
public static Boolean operator <=(JBoolean a, JBoolean b) => a._value.CompareTo(b._value) < 0 || a.Equals(b._value);
|
||||
public static Boolean operator <=(Boolean a, JBoolean b) => a.CompareTo(b._value) < 0 || a.Equals(b._value);
|
||||
public static Boolean operator <=(JBoolean a, Boolean b) => a._value.CompareTo(b) < 0 || a._value.Equals(b);
|
||||
#endregion
|
||||
|
||||
#region Public Methods
|
||||
public Int32 CompareTo(Boolean other) => this._value.CompareTo(other);
|
||||
public Int32 CompareTo(JBoolean other) => this._value.CompareTo(other._value);
|
||||
public Int32 CompareTo(Object obj) => obj is JBoolean jvalue ? this.CompareTo(jvalue) : obj is Boolean value ? this.CompareTo(value) : this._value.CompareTo(obj);
|
||||
public Boolean Equals(Boolean other) => this._value.Equals(other);
|
||||
public Boolean Equals(JBoolean other) => this._value.Equals(other._value);
|
||||
public String ToString(IFormatProvider formatProvider) => this._value.ToString(formatProvider);
|
||||
#endregion
|
||||
|
||||
#region Overrided Methods
|
||||
public override String ToString() => this._value.ToString();
|
||||
public override Boolean Equals(Object obj) => obj is JBoolean jvalue ? this.Equals(jvalue) : obj is Boolean value ? this.Equals(value) : this._value.Equals(obj);
|
||||
public override Int32 GetHashCode() => this._value.GetHashCode();
|
||||
#endregion
|
||||
}
|
||||
}
|
74
src/LibRyujinx/Jni/Primitives/JByte.cs
Normal file
74
src/LibRyujinx/Jni/Primitives/JByte.cs
Normal file
@ -0,0 +1,74 @@
|
||||
using Rxmxnx.PInvoke;
|
||||
using System;
|
||||
|
||||
namespace LibRyujinx.Jni.Primitives
|
||||
{
|
||||
public readonly struct JByte : IComparable<SByte>, IEquatable<SByte>, IFormattable
|
||||
{
|
||||
internal static readonly Type Type = typeof(JByte);
|
||||
|
||||
public static readonly CString Signature = (CString)"B";
|
||||
|
||||
private readonly SByte _value;
|
||||
|
||||
private JByte(SByte value) => this._value = value;
|
||||
private JByte(Int32 value) => this._value = Convert.ToSByte(value);
|
||||
|
||||
#region Operators
|
||||
public static implicit operator JByte(SByte value) => new(value);
|
||||
public static implicit operator SByte(JByte jValue) => jValue._value;
|
||||
public static JByte operator +(JByte a) => a;
|
||||
public static JByte operator ++(JByte a) => new(a._value + 1);
|
||||
public static JByte operator -(JByte a) => new(-a._value);
|
||||
public static JByte operator --(JByte a) => new(a._value - 1);
|
||||
public static JByte operator +(JByte a, JByte b) => new(a._value + b._value);
|
||||
public static JByte operator +(SByte a, JByte b) => new(a + b._value);
|
||||
public static JByte operator +(JByte a, SByte b) => new(a._value + b);
|
||||
public static JByte operator -(JByte a, JByte b) => new(a._value - b._value);
|
||||
public static JByte operator -(SByte a, JByte b) => new(a - b._value);
|
||||
public static JByte operator -(JByte a, SByte b) => new(a._value - b);
|
||||
public static JByte operator *(JByte a, JByte b) => new(a._value * b._value);
|
||||
public static JByte operator *(SByte a, JByte b) => new(a * b._value);
|
||||
public static JByte operator *(JByte a, SByte b) => new(a._value * b);
|
||||
public static JByte operator /(JByte a, JByte b) => new(a._value / b._value);
|
||||
public static JByte operator /(SByte a, JByte b) => new(a / b._value);
|
||||
public static JByte operator /(JByte a, SByte b) => new(a._value / b);
|
||||
public static JByte operator %(JByte a, JByte b) => new(a._value % b._value);
|
||||
public static JByte operator %(SByte a, JByte b) => new(a % b._value);
|
||||
public static JByte operator %(JByte a, SByte b) => new(a._value % b);
|
||||
public static Boolean operator ==(JByte a, JByte b) => a._value.Equals(b._value);
|
||||
public static Boolean operator ==(SByte a, JByte b) => a.Equals(b._value);
|
||||
public static Boolean operator ==(JByte a, SByte b) => a._value.Equals(b);
|
||||
public static Boolean operator !=(JByte a, JByte b) => !a._value.Equals(b._value);
|
||||
public static Boolean operator !=(SByte a, JByte b) => !a.Equals(b._value);
|
||||
public static Boolean operator !=(JByte a, SByte b) => !a._value.Equals(b);
|
||||
public static Boolean operator >(JByte a, JByte b) => a._value.CompareTo(b._value) > 0;
|
||||
public static Boolean operator >(SByte a, JByte b) => a.CompareTo(b._value) > 0;
|
||||
public static Boolean operator >(JByte a, SByte b) => a._value.CompareTo(b) > 0;
|
||||
public static Boolean operator <(JByte a, JByte b) => a._value.CompareTo(b._value) < 0;
|
||||
public static Boolean operator <(SByte a, JByte b) => a.CompareTo(b._value) < 0;
|
||||
public static Boolean operator <(JByte a, SByte b) => a._value.CompareTo(b) < 0;
|
||||
public static Boolean operator >=(JByte a, JByte b) => a._value.CompareTo(b._value) > 0 || a.Equals(b._value);
|
||||
public static Boolean operator >=(SByte a, JByte b) => a.CompareTo(b._value) > 0 || a.Equals(b._value);
|
||||
public static Boolean operator >=(JByte a, SByte b) => a._value.CompareTo(b) > 0 || a._value.Equals(b);
|
||||
public static Boolean operator <=(JByte a, JByte b) => a._value.CompareTo(b._value) < 0 || a.Equals(b._value);
|
||||
public static Boolean operator <=(SByte a, JByte b) => a.CompareTo(b._value) < 0 || a.Equals(b._value);
|
||||
public static Boolean operator <=(JByte a, SByte b) => a._value.CompareTo(b) < 0 || a._value.Equals(b);
|
||||
#endregion
|
||||
|
||||
#region Public Methods
|
||||
public Int32 CompareTo(SByte other) => this._value.CompareTo(other);
|
||||
public Int32 CompareTo(JByte other) => this._value.CompareTo(other._value);
|
||||
public Int32 CompareTo(Object obj) => obj is JByte jValue ? this.CompareTo(jValue) : obj is SByte value ? this.CompareTo(value) : this._value.CompareTo(obj);
|
||||
public Boolean Equals(SByte other) => this._value.Equals(other);
|
||||
public Boolean Equals(JByte other) => this._value.Equals(other._value);
|
||||
public String ToString(String format, IFormatProvider formatProvider) => this._value.ToString(format, formatProvider);
|
||||
#endregion
|
||||
|
||||
#region Overrided Methods
|
||||
public override String ToString() => this._value.ToString();
|
||||
public override Boolean Equals(Object obj) => obj is JByte jvalue ? this.Equals(jvalue) : obj is SByte value ? this.Equals(value) : this._value.Equals(obj);
|
||||
public override Int32 GetHashCode() => this._value.GetHashCode();
|
||||
#endregion
|
||||
}
|
||||
}
|
56
src/LibRyujinx/Jni/Primitives/JChar.cs
Normal file
56
src/LibRyujinx/Jni/Primitives/JChar.cs
Normal file
@ -0,0 +1,56 @@
|
||||
using Rxmxnx.PInvoke;
|
||||
using System;
|
||||
|
||||
namespace LibRyujinx.Jni.Primitives
|
||||
{
|
||||
public readonly struct JChar : IComparable<Char>, IEquatable<Char>
|
||||
{
|
||||
internal static readonly Type Type = typeof(JChar);
|
||||
|
||||
public static readonly CString Signature = (CString)"C";
|
||||
|
||||
private readonly Char _value;
|
||||
|
||||
private JChar(Char value) => this._value = value;
|
||||
|
||||
#region Operators
|
||||
public static implicit operator JChar(Char value) => new(value);
|
||||
public static explicit operator JChar(Int16 value) => new((Char)value);
|
||||
public static implicit operator Char(JChar jValue) => jValue._value;
|
||||
public static explicit operator Int16(JChar jValue) => (Int16)jValue._value;
|
||||
public static Boolean operator ==(JChar a, JChar b) => a._value.Equals(b._value);
|
||||
public static Boolean operator ==(Char a, JChar b) => a.Equals(b._value);
|
||||
public static Boolean operator ==(JChar a, Char b) => a._value.Equals(b);
|
||||
public static Boolean operator !=(JChar a, JChar b) => !a._value.Equals(b._value);
|
||||
public static Boolean operator !=(Char a, JChar b) => !a.Equals(b._value);
|
||||
public static Boolean operator !=(JChar a, Char b) => !a._value.Equals(b);
|
||||
public static Boolean operator >(JChar a, JChar b) => a._value.CompareTo(b._value) > 0;
|
||||
public static Boolean operator >(Char a, JChar b) => a.CompareTo(b._value) > 0;
|
||||
public static Boolean operator >(JChar a, Char b) => a._value.CompareTo(b) > 0;
|
||||
public static Boolean operator <(JChar a, JChar b) => a._value.CompareTo(b._value) < 0;
|
||||
public static Boolean operator <(Char a, JChar b) => a.CompareTo(b._value) < 0;
|
||||
public static Boolean operator <(JChar a, Char b) => a._value.CompareTo(b) < 0;
|
||||
public static Boolean operator >=(JChar a, JChar b) => a._value.CompareTo(b._value) > 0 || a.Equals(b._value);
|
||||
public static Boolean operator >=(Char a, JChar b) => a.CompareTo(b._value) > 0 || a.Equals(b._value);
|
||||
public static Boolean operator >=(JChar a, Char b) => a._value.CompareTo(b) > 0 || a._value.Equals(b);
|
||||
public static Boolean operator <=(JChar a, JChar b) => a._value.CompareTo(b._value) < 0 || a.Equals(b._value);
|
||||
public static Boolean operator <=(Char a, JChar b) => a.CompareTo(b._value) < 0 || a.Equals(b._value);
|
||||
public static Boolean operator <=(JChar a, Char b) => a._value.CompareTo(b) < 0 || a._value.Equals(b);
|
||||
#endregion
|
||||
|
||||
#region Public Methods
|
||||
public Int32 CompareTo(Char other) => this._value.CompareTo(other);
|
||||
public Int32 CompareTo(JChar other) => this._value.CompareTo(other._value);
|
||||
public Int32 CompareTo(Object obj) => obj is JChar jvalue ? this.CompareTo(jvalue) : obj is Char value ? this.CompareTo(value) : this._value.CompareTo(obj);
|
||||
public Boolean Equals(Char other) => this._value.Equals(other);
|
||||
public Boolean Equals(JChar other) => this._value.Equals(other._value);
|
||||
public String ToString(IFormatProvider formatProvider) => this._value.ToString(formatProvider);
|
||||
#endregion
|
||||
|
||||
#region Overrided Methods
|
||||
public override String ToString() => this._value.ToString();
|
||||
public override Boolean Equals(Object obj) => obj is JChar jvalue ? this.Equals(jvalue) : obj is Char value ? this.Equals(value) : this._value.Equals(obj);
|
||||
public override Int32 GetHashCode() => this._value.GetHashCode();
|
||||
#endregion
|
||||
}
|
||||
}
|
70
src/LibRyujinx/Jni/Primitives/JDouble.cs
Normal file
70
src/LibRyujinx/Jni/Primitives/JDouble.cs
Normal file
@ -0,0 +1,70 @@
|
||||
using Rxmxnx.PInvoke;
|
||||
using System;
|
||||
|
||||
namespace LibRyujinx.Jni.Primitives
|
||||
{
|
||||
public readonly struct JDouble : IComparable<Double>, IEquatable<Double>, IFormattable
|
||||
{
|
||||
internal static readonly Type Type = typeof(JDouble);
|
||||
|
||||
public static readonly CString Signature = (CString)"D";
|
||||
|
||||
private readonly Double _value;
|
||||
|
||||
private JDouble(Double value) => this._value = value;
|
||||
|
||||
#region Operators
|
||||
public static implicit operator JDouble(Double value) => new(value);
|
||||
public static implicit operator Double(JDouble jValue) => jValue._value;
|
||||
public static JDouble operator +(JDouble a) => a;
|
||||
public static JDouble operator ++(JDouble a) => new(a._value + 1);
|
||||
public static JDouble operator -(JDouble a) => new(-a._value);
|
||||
public static JDouble operator --(JDouble a) => new(a._value - 1);
|
||||
public static JDouble operator +(JDouble a, JDouble b) => new(a._value + b._value);
|
||||
public static JDouble operator +(Double a, JDouble b) => new(a + b._value);
|
||||
public static JDouble operator +(JDouble a, Double b) => new(a._value + b);
|
||||
public static JDouble operator -(JDouble a, JDouble b) => new(a._value - b._value);
|
||||
public static JDouble operator -(Double a, JDouble b) => new(a - b._value);
|
||||
public static JDouble operator -(JDouble a, Double b) => new(a._value - b);
|
||||
public static JDouble operator *(JDouble a, JDouble b) => new(a._value * b._value);
|
||||
public static JDouble operator *(Double a, JDouble b) => new(a * b._value);
|
||||
public static JDouble operator *(JDouble a, Double b) => new(a._value * b);
|
||||
public static JDouble operator /(JDouble a, JDouble b) => new(a._value / b._value);
|
||||
public static JDouble operator /(Double a, JDouble b) => new(a / b._value);
|
||||
public static JDouble operator /(JDouble a, Double b) => new(a._value / b);
|
||||
public static Boolean operator ==(JDouble a, JDouble b) => a._value.Equals(b._value);
|
||||
public static Boolean operator ==(Double a, JDouble b) => a.Equals(b._value);
|
||||
public static Boolean operator ==(JDouble a, Double b) => a._value.Equals(b);
|
||||
public static Boolean operator !=(JDouble a, JDouble b) => !a._value.Equals(b._value);
|
||||
public static Boolean operator !=(Double a, JDouble b) => !a.Equals(b._value);
|
||||
public static Boolean operator !=(JDouble a, Double b) => !a._value.Equals(b);
|
||||
public static Boolean operator >(JDouble a, JDouble b) => a._value.CompareTo(b._value) > 0;
|
||||
public static Boolean operator >(Double a, JDouble b) => a.CompareTo(b._value) > 0;
|
||||
public static Boolean operator >(JDouble a, Double b) => a._value.CompareTo(b) > 0;
|
||||
public static Boolean operator <(JDouble a, JDouble b) => a._value.CompareTo(b._value) < 0;
|
||||
public static Boolean operator <(Double a, JDouble b) => a.CompareTo(b._value) < 0;
|
||||
public static Boolean operator <(JDouble a, Double b) => a._value.CompareTo(b) < 0;
|
||||
public static Boolean operator >=(JDouble a, JDouble b) => a._value.CompareTo(b._value) > 0 || a.Equals(b._value);
|
||||
public static Boolean operator >=(Double a, JDouble b) => a.CompareTo(b._value) > 0 || a.Equals(b._value);
|
||||
public static Boolean operator >=(JDouble a, Double b) => a._value.CompareTo(b) > 0 || a._value.Equals(b);
|
||||
public static Boolean operator <=(JDouble a, JDouble b) => a._value.CompareTo(b._value) < 0 || a.Equals(b._value);
|
||||
public static Boolean operator <=(Double a, JDouble b) => a.CompareTo(b._value) < 0 || a.Equals(b._value);
|
||||
public static Boolean operator <=(JDouble a, Double b) => a._value.CompareTo(b) < 0 || a._value.Equals(b);
|
||||
#endregion
|
||||
|
||||
#region Public Methods
|
||||
public Int32 CompareTo(Double other) => this._value.CompareTo(other);
|
||||
public Int32 CompareTo(JDouble other) => this._value.CompareTo(other._value);
|
||||
public Int32 CompareTo(Object obj) => obj is JDouble jvalue ? this.CompareTo(jvalue) : obj is Double value ? this.CompareTo(value) : this._value.CompareTo(obj);
|
||||
public Boolean Equals(Double other) => this._value.Equals(other);
|
||||
public Boolean Equals(JDouble other) => this._value.Equals(other._value);
|
||||
public String ToString(String format, IFormatProvider formatProvider) => this._value.ToString(format, formatProvider);
|
||||
#endregion
|
||||
|
||||
#region Overrided Methods
|
||||
public override String ToString() => this._value.ToString();
|
||||
public override Boolean Equals(Object obj) => obj is JDouble jvalue ? this.Equals(jvalue) : obj is Double value ? this.Equals(value) : this._value.Equals(obj);
|
||||
public override Int32 GetHashCode() => this._value.GetHashCode();
|
||||
#endregion
|
||||
}
|
||||
}
|
70
src/LibRyujinx/Jni/Primitives/JFloat.cs
Normal file
70
src/LibRyujinx/Jni/Primitives/JFloat.cs
Normal file
@ -0,0 +1,70 @@
|
||||
using Rxmxnx.PInvoke;
|
||||
using System;
|
||||
|
||||
namespace LibRyujinx.Jni.Primitives
|
||||
{
|
||||
public readonly struct JFloat : IComparable<Single>, IEquatable<Single>, IFormattable
|
||||
{
|
||||
internal static readonly Type Type = typeof(JFloat);
|
||||
|
||||
public static readonly CString Signature = (CString)"F";
|
||||
|
||||
private readonly Single _value;
|
||||
|
||||
private JFloat(Single value) => this._value = value;
|
||||
|
||||
#region Operators
|
||||
public static implicit operator JFloat(Single value) => new(value);
|
||||
public static implicit operator Single(JFloat jValue) => jValue._value;
|
||||
public static JFloat operator +(JFloat a) => a;
|
||||
public static JFloat operator ++(JFloat a) => new(a._value + 1);
|
||||
public static JFloat operator -(JFloat a) => new(-a._value);
|
||||
public static JFloat operator --(JFloat a) => new(a._value - 1);
|
||||
public static JFloat operator +(JFloat a, JFloat b) => new(a._value + b._value);
|
||||
public static JFloat operator +(Single a, JFloat b) => new(a + b._value);
|
||||
public static JFloat operator +(JFloat a, Single b) => new(a._value + b);
|
||||
public static JFloat operator -(JFloat a, JFloat b) => new(a._value - b._value);
|
||||
public static JFloat operator -(Single a, JFloat b) => new(a - b._value);
|
||||
public static JFloat operator -(JFloat a, Single b) => new(a._value - b);
|
||||
public static JFloat operator *(JFloat a, JFloat b) => new(a._value * b._value);
|
||||
public static JFloat operator *(Single a, JFloat b) => new(a * b._value);
|
||||
public static JFloat operator *(JFloat a, Single b) => new(a._value * b);
|
||||
public static JFloat operator /(JFloat a, JFloat b) => new(a._value / b._value);
|
||||
public static JFloat operator /(Single a, JFloat b) => new(a / b._value);
|
||||
public static JFloat operator /(JFloat a, Single b) => new(a._value / b);
|
||||
public static Boolean operator ==(JFloat a, JFloat b) => a._value.Equals(b._value);
|
||||
public static Boolean operator ==(Single a, JFloat b) => a.Equals(b._value);
|
||||
public static Boolean operator ==(JFloat a, Single b) => a._value.Equals(b);
|
||||
public static Boolean operator !=(JFloat a, JFloat b) => !a._value.Equals(b._value);
|
||||
public static Boolean operator !=(Single a, JFloat b) => !a.Equals(b._value);
|
||||
public static Boolean operator !=(JFloat a, Single b) => !a._value.Equals(b);
|
||||
public static Boolean operator >(JFloat a, JFloat b) => a._value.CompareTo(b._value) > 0;
|
||||
public static Boolean operator >(Single a, JFloat b) => a.CompareTo(b._value) > 0;
|
||||
public static Boolean operator >(JFloat a, Single b) => a._value.CompareTo(b) > 0;
|
||||
public static Boolean operator <(JFloat a, JFloat b) => a._value.CompareTo(b._value) < 0;
|
||||
public static Boolean operator <(Single a, JFloat b) => a.CompareTo(b._value) < 0;
|
||||
public static Boolean operator <(JFloat a, Single b) => a._value.CompareTo(b) < 0;
|
||||
public static Boolean operator >=(JFloat a, JFloat b) => a._value.CompareTo(b._value) > 0 || a.Equals(b._value);
|
||||
public static Boolean operator >=(Single a, JFloat b) => a.CompareTo(b._value) > 0 || a.Equals(b._value);
|
||||
public static Boolean operator >=(JFloat a, Single b) => a._value.CompareTo(b) > 0 || a._value.Equals(b);
|
||||
public static Boolean operator <=(JFloat a, JFloat b) => a._value.CompareTo(b._value) < 0 || a.Equals(b._value);
|
||||
public static Boolean operator <=(Single a, JFloat b) => a.CompareTo(b._value) < 0 || a.Equals(b._value);
|
||||
public static Boolean operator <=(JFloat a, Single b) => a._value.CompareTo(b) < 0 || a._value.Equals(b);
|
||||
#endregion
|
||||
|
||||
#region Public Methods
|
||||
public Int32 CompareTo(Single other) => this._value.CompareTo(other);
|
||||
public Int32 CompareTo(JFloat other) => this._value.CompareTo(other._value);
|
||||
public Int32 CompareTo(Object obj) => obj is JFloat jvalue ? this.CompareTo(jvalue) : obj is Single value ? this.CompareTo(value) : this._value.CompareTo(obj);
|
||||
public Boolean Equals(Single other) => this._value.Equals(other);
|
||||
public Boolean Equals(JFloat other) => this._value.Equals(other._value);
|
||||
public String ToString(String format, IFormatProvider formatProvider) => this._value.ToString(format, formatProvider);
|
||||
#endregion
|
||||
|
||||
#region Overrided Methods
|
||||
public override String ToString() => this._value.ToString();
|
||||
public override Boolean Equals(Object obj) => obj is JFloat jvalue ? this.Equals(jvalue) : obj is Single value ? this.Equals(value) : this._value.Equals(obj);
|
||||
public override Int32 GetHashCode() => this._value.GetHashCode();
|
||||
#endregion
|
||||
}
|
||||
}
|
73
src/LibRyujinx/Jni/Primitives/JInt.cs
Normal file
73
src/LibRyujinx/Jni/Primitives/JInt.cs
Normal file
@ -0,0 +1,73 @@
|
||||
using Rxmxnx.PInvoke;
|
||||
using System;
|
||||
|
||||
namespace LibRyujinx.Jni.Primitives
|
||||
{
|
||||
public readonly struct JInt : IComparable<Int32>, IEquatable<Int32>, IFormattable
|
||||
{
|
||||
internal static readonly Type Type = typeof(JInt);
|
||||
|
||||
public static readonly CString Signature = (CString)"I";
|
||||
|
||||
private readonly Int32 _value;
|
||||
|
||||
private JInt(Int32 value) => this._value = value;
|
||||
|
||||
#region Operators
|
||||
public static implicit operator JInt(Int32 value) => new(value);
|
||||
public static implicit operator Int32(JInt jValue) => jValue._value;
|
||||
public static JInt operator +(JInt a) => a;
|
||||
public static JInt operator ++(JInt a) => new(a._value + 1);
|
||||
public static JInt operator -(JInt a) => new(-a._value);
|
||||
public static JInt operator --(JInt a) => new(a._value - 1);
|
||||
public static JInt operator +(JInt a, JInt b) => new(a._value + b._value);
|
||||
public static JInt operator +(Int32 a, JInt b) => new(a + b._value);
|
||||
public static JInt operator +(JInt a, Int32 b) => new(a._value + b);
|
||||
public static JInt operator -(JInt a, JInt b) => new(a._value - b._value);
|
||||
public static JInt operator -(Int32 a, JInt b) => new(a - b._value);
|
||||
public static JInt operator -(JInt a, Int32 b) => new(a._value - b);
|
||||
public static JInt operator *(JInt a, JInt b) => new(a._value * b._value);
|
||||
public static JInt operator *(Int32 a, JInt b) => new(a * b._value);
|
||||
public static JInt operator *(JInt a, Int32 b) => new(a._value * b);
|
||||
public static JInt operator /(JInt a, JInt b) => new(a._value / b._value);
|
||||
public static JInt operator /(Int32 a, JInt b) => new(a / b._value);
|
||||
public static JInt operator /(JInt a, Int32 b) => new(a._value / b);
|
||||
public static JInt operator %(JInt a, JInt b) => new(a._value % b._value);
|
||||
public static JInt operator %(Int32 a, JInt b) => new(a % b._value);
|
||||
public static JInt operator %(JInt a, Int32 b) => new(a._value % b);
|
||||
public static Boolean operator ==(JInt a, JInt b) => a._value.Equals(b._value);
|
||||
public static Boolean operator ==(Int32 a, JInt b) => a.Equals(b._value);
|
||||
public static Boolean operator ==(JInt a, Int32 b) => a._value.Equals(b);
|
||||
public static Boolean operator !=(JInt a, JInt b) => !a._value.Equals(b._value);
|
||||
public static Boolean operator !=(Int32 a, JInt b) => !a.Equals(b._value);
|
||||
public static Boolean operator !=(JInt a, Int32 b) => !a._value.Equals(b);
|
||||
public static Boolean operator >(JInt a, JInt b) => a._value.CompareTo(b._value) > 0;
|
||||
public static Boolean operator >(Int32 a, JInt b) => a.CompareTo(b._value) > 0;
|
||||
public static Boolean operator >(JInt a, Int32 b) => a._value.CompareTo(b) > 0;
|
||||
public static Boolean operator <(JInt a, JInt b) => a._value.CompareTo(b._value) < 0;
|
||||
public static Boolean operator <(Int32 a, JInt b) => a.CompareTo(b._value) < 0;
|
||||
public static Boolean operator <(JInt a, Int32 b) => a._value.CompareTo(b) < 0;
|
||||
public static Boolean operator >=(JInt a, JInt b) => a._value.CompareTo(b._value) > 0 || a.Equals(b._value);
|
||||
public static Boolean operator >=(Int32 a, JInt b) => a.CompareTo(b._value) > 0 || a.Equals(b._value);
|
||||
public static Boolean operator >=(JInt a, Int32 b) => a._value.CompareTo(b) > 0 || a._value.Equals(b);
|
||||
public static Boolean operator <=(JInt a, JInt b) => a._value.CompareTo(b._value) < 0 || a.Equals(b._value);
|
||||
public static Boolean operator <=(Int32 a, JInt b) => a.CompareTo(b._value) < 0 || a.Equals(b._value);
|
||||
public static Boolean operator <=(JInt a, Int32 b) => a._value.CompareTo(b) < 0 || a._value.Equals(b);
|
||||
#endregion
|
||||
|
||||
#region Public Methods
|
||||
public Int32 CompareTo(Int32 other) => this._value.CompareTo(other);
|
||||
public Int32 CompareTo(JInt other) => this._value.CompareTo(other._value);
|
||||
public Int32 CompareTo(Object obj) => obj is JInt jValue ? this.CompareTo(jValue) : obj is Int32 value ? this.CompareTo(value) : this._value.CompareTo(obj);
|
||||
public Boolean Equals(Int32 other) => this._value.Equals(other);
|
||||
public Boolean Equals(JInt other) => this._value.Equals(other._value);
|
||||
public String ToString(String format, IFormatProvider formatProvider) => this._value.ToString(format, formatProvider);
|
||||
#endregion
|
||||
|
||||
#region Overrided Methods
|
||||
public override String ToString() => this._value.ToString();
|
||||
public override Boolean Equals(Object obj) => obj is JInt jvalue ? this.Equals(jvalue) : obj is Int32 value ? this.Equals(value) : this._value.Equals(obj);
|
||||
public override Int32 GetHashCode() => this._value.GetHashCode();
|
||||
#endregion
|
||||
}
|
||||
}
|
73
src/LibRyujinx/Jni/Primitives/JLong.cs
Normal file
73
src/LibRyujinx/Jni/Primitives/JLong.cs
Normal file
@ -0,0 +1,73 @@
|
||||
using Rxmxnx.PInvoke;
|
||||
using System;
|
||||
|
||||
namespace LibRyujinx.Jni.Primitives
|
||||
{
|
||||
public readonly struct JLong : IComparable<Int64>, IEquatable<Int64>, IFormattable
|
||||
{
|
||||
internal static readonly Type Type = typeof(JLong);
|
||||
|
||||
public static readonly CString Signature = (CString)"J";
|
||||
|
||||
private readonly Int64 _value;
|
||||
|
||||
private JLong(Int64 value) => this._value = value;
|
||||
|
||||
#region Operators
|
||||
public static implicit operator JLong(Int64 value) => new(value);
|
||||
public static implicit operator Int64(JLong jValue) => jValue._value;
|
||||
public static JLong operator +(JLong a) => a;
|
||||
public static JLong operator ++(JLong a) => new(a._value + 1);
|
||||
public static JLong operator -(JLong a) => new(-a._value);
|
||||
public static JLong operator --(JLong a) => new(a._value - 1);
|
||||
public static JLong operator +(JLong a, JLong b) => new(a._value + b._value);
|
||||
public static JLong operator +(Int64 a, JLong b) => new(a + b._value);
|
||||
public static JLong operator +(JLong a, Int64 b) => new(a._value + b);
|
||||
public static JLong operator -(JLong a, JLong b) => new(a._value - b._value);
|
||||
public static JLong operator -(Int64 a, JLong b) => new(a - b._value);
|
||||
public static JLong operator -(JLong a, Int64 b) => new(a._value - b);
|
||||
public static JLong operator *(JLong a, JLong b) => new(a._value * b._value);
|
||||
public static JLong operator *(Int64 a, JLong b) => new(a * b._value);
|
||||
public static JLong operator *(JLong a, Int64 b) => new(a._value * b);
|
||||
public static JLong operator /(JLong a, JLong b) => new(a._value / b._value);
|
||||
public static JLong operator /(Int64 a, JLong b) => new(a / b._value);
|
||||
public static JLong operator /(JLong a, Int64 b) => new(a._value / b);
|
||||
public static JLong operator %(JLong a, JLong b) => new(a._value % b._value);
|
||||
public static JLong operator %(Int64 a, JLong b) => new(a % b._value);
|
||||
public static JLong operator %(JLong a, Int64 b) => new(a._value % b);
|
||||
public static Boolean operator ==(JLong a, JLong b) => a._value.Equals(b._value);
|
||||
public static Boolean operator ==(Int64 a, JLong b) => a.Equals(b._value);
|
||||
public static Boolean operator ==(JLong a, Int64 b) => a._value.Equals(b);
|
||||
public static Boolean operator !=(JLong a, JLong b) => !a._value.Equals(b._value);
|
||||
public static Boolean operator !=(Int64 a, JLong b) => !a.Equals(b._value);
|
||||
public static Boolean operator !=(JLong a, Int64 b) => !a._value.Equals(b);
|
||||
public static Boolean operator >(JLong a, JLong b) => a._value.CompareTo(b._value) > 0;
|
||||
public static Boolean operator >(Int64 a, JLong b) => a.CompareTo(b._value) > 0;
|
||||
public static Boolean operator >(JLong a, Int64 b) => a._value.CompareTo(b) > 0;
|
||||
public static Boolean operator <(JLong a, JLong b) => a._value.CompareTo(b._value) < 0;
|
||||
public static Boolean operator <(Int64 a, JLong b) => a.CompareTo(b._value) < 0;
|
||||
public static Boolean operator <(JLong a, Int64 b) => a._value.CompareTo(b) < 0;
|
||||
public static Boolean operator >=(JLong a, JLong b) => a._value.CompareTo(b._value) > 0 || a.Equals(b._value);
|
||||
public static Boolean operator >=(Int64 a, JLong b) => a.CompareTo(b._value) > 0 || a.Equals(b._value);
|
||||
public static Boolean operator >=(JLong a, Int64 b) => a._value.CompareTo(b) > 0 || a._value.Equals(b);
|
||||
public static Boolean operator <=(JLong a, JLong b) => a._value.CompareTo(b._value) < 0 || a.Equals(b._value);
|
||||
public static Boolean operator <=(Int64 a, JLong b) => a.CompareTo(b._value) < 0 || a.Equals(b._value);
|
||||
public static Boolean operator <=(JLong a, Int64 b) => a._value.CompareTo(b) < 0 || a._value.Equals(b);
|
||||
#endregion
|
||||
|
||||
#region Public Methods
|
||||
public Int32 CompareTo(Int64 other) => this._value.CompareTo(other);
|
||||
public Int32 CompareTo(JLong other) => this._value.CompareTo(other._value);
|
||||
public Int32 CompareTo(Object obj) => obj is JLong jvalue ? this.CompareTo(jvalue) : obj is Int64 value ? this.CompareTo(value) : this._value.CompareTo(obj);
|
||||
public Boolean Equals(Int64 other) => this._value.Equals(other);
|
||||
public Boolean Equals(JLong other) => this._value.Equals(other._value);
|
||||
public String ToString(String format, IFormatProvider formatProvider) => this._value.ToString(format, formatProvider);
|
||||
#endregion
|
||||
|
||||
#region Overrided Methods
|
||||
public override String ToString() => this._value.ToString();
|
||||
public override Boolean Equals(Object obj) => obj is JLong jvalue ? this.Equals(jvalue) : obj is Int64 value ? this.Equals(value) : this._value.Equals(obj);
|
||||
public override Int32 GetHashCode() => this._value.GetHashCode();
|
||||
#endregion
|
||||
}
|
||||
}
|
74
src/LibRyujinx/Jni/Primitives/JShort.cs
Normal file
74
src/LibRyujinx/Jni/Primitives/JShort.cs
Normal file
@ -0,0 +1,74 @@
|
||||
using Rxmxnx.PInvoke;
|
||||
using System;
|
||||
|
||||
namespace LibRyujinx.Jni.Primitives
|
||||
{
|
||||
public readonly struct JShort : IComparable<Int16>, IEquatable<Int16>, IFormattable
|
||||
{
|
||||
internal static readonly Type Type = typeof(JShort);
|
||||
|
||||
public static readonly CString Signature = (CString)"S";
|
||||
|
||||
private readonly Int16 _value;
|
||||
|
||||
private JShort(Int16 value) => this._value = value;
|
||||
private JShort(Int32 value) => this._value = Convert.ToInt16(value);
|
||||
|
||||
#region Operators
|
||||
public static implicit operator JShort(Int16 value) => new(value);
|
||||
public static implicit operator Int16(JShort jValue) => jValue._value;
|
||||
public static JShort operator +(JShort a) => a;
|
||||
public static JShort operator ++(JShort a) => new(a._value + 1);
|
||||
public static JShort operator -(JShort a) => new(-a._value);
|
||||
public static JShort operator --(JShort a) => new(a._value - 1);
|
||||
public static JShort operator +(JShort a, JShort b) => new(a._value + b._value);
|
||||
public static JShort operator +(Int16 a, JShort b) => new(a + b._value);
|
||||
public static JShort operator +(JShort a, Int16 b) => new(a._value + b);
|
||||
public static JShort operator -(JShort a, JShort b) => new(a._value - b._value);
|
||||
public static JShort operator -(Int16 a, JShort b) => new(a - b._value);
|
||||
public static JShort operator -(JShort a, Int16 b) => new(a._value - b);
|
||||
public static JShort operator *(JShort a, JShort b) => new(a._value * b._value);
|
||||
public static JShort operator *(Int16 a, JShort b) => new(a * b._value);
|
||||
public static JShort operator *(JShort a, Int16 b) => new(a._value * b);
|
||||
public static JShort operator /(JShort a, JShort b) => new(a._value / b._value);
|
||||
public static JShort operator /(Int16 a, JShort b) => new(a / b._value);
|
||||
public static JShort operator /(JShort a, Int16 b) => new(a._value / b);
|
||||
public static JShort operator %(JShort a, JShort b) => new(a._value % b._value);
|
||||
public static JShort operator %(Int16 a, JShort b) => new(a % b._value);
|
||||
public static JShort operator %(JShort a, Int16 b) => new(a._value % b);
|
||||
public static Boolean operator ==(JShort a, JShort b) => a._value.Equals(b._value);
|
||||
public static Boolean operator ==(Int16 a, JShort b) => a.Equals(b._value);
|
||||
public static Boolean operator ==(JShort a, Int16 b) => a._value.Equals(b);
|
||||
public static Boolean operator !=(JShort a, JShort b) => !a._value.Equals(b._value);
|
||||
public static Boolean operator !=(Int16 a, JShort b) => !a.Equals(b._value);
|
||||
public static Boolean operator !=(JShort a, Int16 b) => !a._value.Equals(b);
|
||||
public static Boolean operator >(JShort a, JShort b) => a._value.CompareTo(b._value) > 0;
|
||||
public static Boolean operator >(Int16 a, JShort b) => a.CompareTo(b._value) > 0;
|
||||
public static Boolean operator >(JShort a, Int16 b) => a._value.CompareTo(b) > 0;
|
||||
public static Boolean operator <(JShort a, JShort b) => a._value.CompareTo(b._value) < 0;
|
||||
public static Boolean operator <(Int16 a, JShort b) => a.CompareTo(b._value) < 0;
|
||||
public static Boolean operator <(JShort a, Int16 b) => a._value.CompareTo(b) < 0;
|
||||
public static Boolean operator >=(JShort a, JShort b) => a._value.CompareTo(b._value) > 0 || a.Equals(b._value);
|
||||
public static Boolean operator >=(Int16 a, JShort b) => a.CompareTo(b._value) > 0 || a.Equals(b._value);
|
||||
public static Boolean operator >=(JShort a, Int16 b) => a._value.CompareTo(b) > 0 || a._value.Equals(b);
|
||||
public static Boolean operator <=(JShort a, JShort b) => a._value.CompareTo(b._value) < 0 || a.Equals(b._value);
|
||||
public static Boolean operator <=(Int16 a, JShort b) => a.CompareTo(b._value) < 0 || a.Equals(b._value);
|
||||
public static Boolean operator <=(JShort a, Int16 b) => a._value.CompareTo(b) < 0 || a._value.Equals(b);
|
||||
#endregion
|
||||
|
||||
#region Public Methods
|
||||
public Int32 CompareTo(Int16 other) => this._value.CompareTo(other);
|
||||
public Int32 CompareTo(JShort other) => this._value.CompareTo(other._value);
|
||||
public Int32 CompareTo(Object obj) => obj is JShort jvalue ? this.CompareTo(jvalue) : obj is Int16 value ? this.CompareTo(value) : this._value.CompareTo(obj);
|
||||
public Boolean Equals(Int16 other) => this._value.Equals(other);
|
||||
public Boolean Equals(JShort other) => this._value.Equals(other._value);
|
||||
public String ToString(String format, IFormatProvider formatProvider) => this._value.ToString(format, formatProvider);
|
||||
#endregion
|
||||
|
||||
#region Overrided Methods
|
||||
public override String ToString() => this._value.ToString();
|
||||
public override Boolean Equals(Object obj) => obj is JShort jvalue ? this.Equals(jvalue) : obj is Int16 value ? this.Equals(value) : this._value.Equals(obj);
|
||||
public override Int32 GetHashCode() => this._value.GetHashCode();
|
||||
#endregion
|
||||
}
|
||||
}
|
28
src/LibRyujinx/Jni/References/JArrayLocalRef.cs
Normal file
28
src/LibRyujinx/Jni/References/JArrayLocalRef.cs
Normal file
@ -0,0 +1,28 @@
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System;
|
||||
|
||||
namespace LibRyujinx.Jni.References
|
||||
{
|
||||
public readonly struct JArrayLocalRef : IEquatable<JArrayLocalRef>
|
||||
{
|
||||
#pragma warning disable 0649
|
||||
private readonly JObjectLocalRef _value;
|
||||
#pragma warning restore 0649
|
||||
|
||||
#region Public Methods
|
||||
public Boolean Equals(JArrayLocalRef other)
|
||||
=> this._value.Equals(other._value);
|
||||
#endregion
|
||||
|
||||
#region Override Methods
|
||||
public override Boolean Equals([NotNullWhen(true)] Object obj)
|
||||
=> obj is JArrayLocalRef other && this.Equals(other);
|
||||
public override Int32 GetHashCode() => this._value.GetHashCode();
|
||||
#endregion
|
||||
|
||||
#region Operators
|
||||
public static Boolean operator ==(JArrayLocalRef a, JArrayLocalRef b) => a.Equals(b);
|
||||
public static Boolean operator !=(JArrayLocalRef a, JArrayLocalRef b) => !a.Equals(b);
|
||||
#endregion
|
||||
}
|
||||
}
|
28
src/LibRyujinx/Jni/References/JClassLocalRef.cs
Normal file
28
src/LibRyujinx/Jni/References/JClassLocalRef.cs
Normal file
@ -0,0 +1,28 @@
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System;
|
||||
|
||||
namespace LibRyujinx.Jni.References
|
||||
{
|
||||
public readonly struct JClassLocalRef : IEquatable<JClassLocalRef>
|
||||
{
|
||||
#pragma warning disable 0649
|
||||
public readonly JObjectLocalRef _value;
|
||||
#pragma warning restore 0649
|
||||
|
||||
#region Public Methods
|
||||
public Boolean Equals(JClassLocalRef other)
|
||||
=> this._value.Equals(other._value);
|
||||
#endregion
|
||||
|
||||
#region Override Methods
|
||||
public override Boolean Equals([NotNullWhen(true)] Object obj)
|
||||
=> obj is JClassLocalRef other && this.Equals(other);
|
||||
public override Int32 GetHashCode() => this._value.GetHashCode();
|
||||
#endregion
|
||||
|
||||
#region Operators
|
||||
public static Boolean operator ==(JClassLocalRef a, JClassLocalRef b) => a.Equals(b);
|
||||
public static Boolean operator !=(JClassLocalRef a, JClassLocalRef b) => !a.Equals(b);
|
||||
#endregion
|
||||
}
|
||||
}
|
28
src/LibRyujinx/Jni/References/JGlobalRef.cs
Normal file
28
src/LibRyujinx/Jni/References/JGlobalRef.cs
Normal file
@ -0,0 +1,28 @@
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System;
|
||||
|
||||
namespace LibRyujinx.Jni.References
|
||||
{
|
||||
public readonly struct JGlobalRef : IEquatable<JGlobalRef>
|
||||
{
|
||||
#pragma warning disable 0649
|
||||
private readonly IntPtr _value;
|
||||
#pragma warning restore 0649
|
||||
|
||||
#region Public Methods
|
||||
public Boolean Equals(JGlobalRef other)
|
||||
=> this._value.Equals(other._value);
|
||||
#endregion
|
||||
|
||||
#region Override Methods
|
||||
public override Boolean Equals([NotNullWhen(true)] Object obj)
|
||||
=> obj is JGlobalRef other && this.Equals(other);
|
||||
public override Int32 GetHashCode() => this._value.GetHashCode();
|
||||
#endregion
|
||||
|
||||
#region Operators
|
||||
public static Boolean operator ==(JGlobalRef a, JGlobalRef b) => a.Equals(b);
|
||||
public static Boolean operator !=(JGlobalRef a, JGlobalRef b) => !a.Equals(b);
|
||||
#endregion
|
||||
}
|
||||
}
|
28
src/LibRyujinx/Jni/References/JObjectLocalRef.cs
Normal file
28
src/LibRyujinx/Jni/References/JObjectLocalRef.cs
Normal file
@ -0,0 +1,28 @@
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System;
|
||||
|
||||
namespace LibRyujinx.Jni.References
|
||||
{
|
||||
public readonly struct JObjectLocalRef : IEquatable<JObjectLocalRef>
|
||||
{
|
||||
#pragma warning disable 0649
|
||||
private readonly IntPtr _value;
|
||||
#pragma warning restore 0649
|
||||
|
||||
#region Public Methods
|
||||
public Boolean Equals(JObjectLocalRef other)
|
||||
=> this._value.Equals(other._value);
|
||||
#endregion
|
||||
|
||||
#region Override Methods
|
||||
public override Boolean Equals([NotNullWhen(true)] Object obj)
|
||||
=> obj is JObjectLocalRef other && this.Equals(other);
|
||||
public override Int32 GetHashCode() => this._value.GetHashCode();
|
||||
#endregion
|
||||
|
||||
#region Operators
|
||||
public static Boolean operator ==(JObjectLocalRef a, JObjectLocalRef b) => a.Equals(b);
|
||||
public static Boolean operator !=(JObjectLocalRef a, JObjectLocalRef b) => !a.Equals(b);
|
||||
#endregion
|
||||
}
|
||||
}
|
28
src/LibRyujinx/Jni/References/JStringLocalRef.cs
Normal file
28
src/LibRyujinx/Jni/References/JStringLocalRef.cs
Normal file
@ -0,0 +1,28 @@
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System;
|
||||
|
||||
namespace LibRyujinx.Jni.References
|
||||
{
|
||||
public readonly struct JStringLocalRef : IEquatable<JStringLocalRef>
|
||||
{
|
||||
#pragma warning disable 0649
|
||||
public readonly JObjectLocalRef _value;
|
||||
#pragma warning restore 0649
|
||||
|
||||
#region Public Methods
|
||||
public Boolean Equals(JStringLocalRef other)
|
||||
=> this._value.Equals(other._value);
|
||||
#endregion
|
||||
|
||||
#region Override Methods
|
||||
public override Boolean Equals([NotNullWhen(true)] Object obj)
|
||||
=> obj is JStringLocalRef other && this.Equals(other);
|
||||
public override Int32 GetHashCode() => this._value.GetHashCode();
|
||||
#endregion
|
||||
|
||||
#region Operators
|
||||
public static Boolean operator ==(JStringLocalRef a, JStringLocalRef b) => a.Equals(b);
|
||||
public static Boolean operator !=(JStringLocalRef a, JStringLocalRef b) => !a.Equals(b);
|
||||
#endregion
|
||||
}
|
||||
}
|
28
src/LibRyujinx/Jni/References/JThrowableLocalRef.cs
Normal file
28
src/LibRyujinx/Jni/References/JThrowableLocalRef.cs
Normal file
@ -0,0 +1,28 @@
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System;
|
||||
|
||||
namespace LibRyujinx.Jni.References
|
||||
{
|
||||
public readonly struct JThrowableLocalRef : IEquatable<JThrowableLocalRef>
|
||||
{
|
||||
#pragma warning disable 0649
|
||||
private readonly IntPtr _value;
|
||||
#pragma warning restore 0649
|
||||
|
||||
#region Public Methods
|
||||
public Boolean Equals(JThrowableLocalRef other)
|
||||
=> this._value.Equals(other._value);
|
||||
#endregion
|
||||
|
||||
#region Override Methods
|
||||
public override Boolean Equals([NotNullWhen(true)] Object obj)
|
||||
=> obj is JThrowableLocalRef other && this.Equals(other);
|
||||
public override Int32 GetHashCode() => this._value.GetHashCode();
|
||||
#endregion
|
||||
|
||||
#region Operators
|
||||
public static Boolean operator ==(JThrowableLocalRef a, JThrowableLocalRef b) => a.Equals(b);
|
||||
public static Boolean operator !=(JThrowableLocalRef a, JThrowableLocalRef b) => !a.Equals(b);
|
||||
#endregion
|
||||
}
|
||||
}
|
28
src/LibRyujinx/Jni/References/JWeakRef.cs
Normal file
28
src/LibRyujinx/Jni/References/JWeakRef.cs
Normal file
@ -0,0 +1,28 @@
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System;
|
||||
|
||||
namespace LibRyujinx.Jni.References
|
||||
{
|
||||
public readonly struct JWeakRef : IEquatable<JWeakRef>
|
||||
{
|
||||
#pragma warning disable 0649
|
||||
private readonly IntPtr _value;
|
||||
#pragma warning restore 0649
|
||||
|
||||
#region Public Methods
|
||||
public Boolean Equals(JWeakRef other)
|
||||
=> this._value.Equals(other._value);
|
||||
#endregion
|
||||
|
||||
#region Override Methods
|
||||
public override Boolean Equals([NotNullWhen(true)] Object obj)
|
||||
=> obj is JWeakRef other && this.Equals(other);
|
||||
public override Int32 GetHashCode() => this._value.GetHashCode();
|
||||
#endregion
|
||||
|
||||
#region Operators
|
||||
public static Boolean operator ==(JWeakRef a, JWeakRef b) => a.Equals(b);
|
||||
public static Boolean operator !=(JWeakRef a, JWeakRef b) => !a.Equals(b);
|
||||
#endregion
|
||||
}
|
||||
}
|
30
src/LibRyujinx/Jni/Values/JEnvValue.cs
Normal file
30
src/LibRyujinx/Jni/Values/JEnvValue.cs
Normal file
@ -0,0 +1,30 @@
|
||||
using Rxmxnx.PInvoke;
|
||||
using System;
|
||||
|
||||
namespace LibRyujinx.Jni.Values
|
||||
{
|
||||
internal readonly struct JEnvValue : IEquatable<JEnvValue>
|
||||
{
|
||||
#pragma warning disable 0649
|
||||
private readonly IntPtr _value;
|
||||
#pragma warning restore 0649
|
||||
|
||||
#region Operators
|
||||
public static Boolean operator ==(JEnvValue a, JEnvValue b) => a._value.Equals(b._value);
|
||||
public static Boolean operator !=(JEnvValue a, JEnvValue b) => !a._value.Equals(b._value);
|
||||
#endregion
|
||||
|
||||
#region Public Properties
|
||||
internal readonly ref JNativeInterface Functions => ref this._value.GetUnsafeReference<JNativeInterface>();
|
||||
#endregion
|
||||
|
||||
#region Public Methods
|
||||
public Boolean Equals(JEnvValue other) => this._value.Equals(other._value);
|
||||
#endregion
|
||||
|
||||
#region Overrided Methods
|
||||
public override Boolean Equals(Object obj) => obj is JEnvValue other && this.Equals(other);
|
||||
public override Int32 GetHashCode() => this._value.GetHashCode();
|
||||
#endregion
|
||||
}
|
||||
}
|
20
src/LibRyujinx/Jni/Values/JInvokeInterface.cs
Normal file
20
src/LibRyujinx/Jni/Values/JInvokeInterface.cs
Normal file
@ -0,0 +1,20 @@
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System;
|
||||
|
||||
namespace LibRyujinx.Jni.Values
|
||||
{
|
||||
[SuppressMessage("CodeQuality", "IDE0051:Remove unused private members", Justification = "This struct is created only by binary operations.")]
|
||||
public readonly struct JInvokeInterface
|
||||
{
|
||||
#pragma warning disable 0169
|
||||
private readonly IntPtr _reserved0;
|
||||
private readonly IntPtr _reserved1;
|
||||
private readonly IntPtr _reserved2;
|
||||
#pragma warning restore 0169
|
||||
internal IntPtr DestroyJavaVMPointer { get; init; }
|
||||
internal IntPtr AttachCurrentThreadPointer { get; init; }
|
||||
internal IntPtr DetachCurrentThreadPointer { get; init; }
|
||||
internal IntPtr GetEnvPointer { get; init; }
|
||||
internal IntPtr AttachCurrentThreadAsDaemonPointer { get; init; }
|
||||
}
|
||||
}
|
245
src/LibRyujinx/Jni/Values/JNativeInterface.cs
Normal file
245
src/LibRyujinx/Jni/Values/JNativeInterface.cs
Normal file
@ -0,0 +1,245 @@
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System;
|
||||
|
||||
namespace LibRyujinx.Jni.Values
|
||||
{
|
||||
[SuppressMessage("CodeQuality", "IDE0051:Remove unused private members", Justification = "This struct is created only by binary operations.")]
|
||||
public readonly struct JNativeInterface
|
||||
{
|
||||
#pragma warning disable 0169
|
||||
private readonly IntPtr _reserved0;
|
||||
private readonly IntPtr _reserved1;
|
||||
private readonly IntPtr _reserved2;
|
||||
private readonly IntPtr _reserved3;
|
||||
#pragma warning restore 0169
|
||||
internal readonly IntPtr GetVersionPointer { get; init; }
|
||||
internal readonly IntPtr DefineClassPointer { get; init; }
|
||||
internal readonly IntPtr FindClassPointer { get; init; }
|
||||
internal readonly IntPtr FromReflectedMethodPointer { get; init; }
|
||||
internal readonly IntPtr FromReflectedFieldPointer { get; init; }
|
||||
internal readonly IntPtr ToReflectedMethodPointer { get; init; }
|
||||
internal readonly IntPtr GetSuperclassPointer { get; init; }
|
||||
internal readonly IntPtr IsAssignableFromPointer { get; init; }
|
||||
internal readonly IntPtr ToReflectedFieldPointer { get; init; }
|
||||
internal readonly IntPtr ThrowPointer { get; init; }
|
||||
internal readonly IntPtr ThrowNewPointer { get; init; }
|
||||
internal readonly IntPtr ExceptionOccurredPointer { get; init; }
|
||||
internal readonly IntPtr ExceptionDescribePointer { get; init; }
|
||||
internal readonly IntPtr ExceptionClearPointer { get; init; }
|
||||
internal readonly IntPtr FatalErrorPointer { get; init; }
|
||||
internal readonly IntPtr PushLocalFramePointer { get; init; }
|
||||
internal readonly IntPtr PopLocalFramePointer { get; init; }
|
||||
internal readonly IntPtr NewGlobalRefPointer { get; init; }
|
||||
internal readonly IntPtr DeleteGlobalRefPointer { get; init; }
|
||||
internal readonly IntPtr DeleteLocalRefPointer { get; init; }
|
||||
internal readonly IntPtr IsSameObjectPointer { get; init; }
|
||||
internal readonly IntPtr NewLocalRefPointer { get; init; }
|
||||
internal readonly IntPtr EnsureLocalCapacityPointer { get; init; }
|
||||
internal readonly IntPtr AllocObjectPointer { get; init; }
|
||||
internal readonly IntPtr NewObjectPointer { get; init; }
|
||||
internal readonly IntPtr NewObjectVPointer { get; init; }
|
||||
internal readonly IntPtr NewObjectAPointer { get; init; }
|
||||
internal readonly IntPtr GetObjectClassPointer { get; init; }
|
||||
internal readonly IntPtr IsInstanceOfPointer { get; init; }
|
||||
internal readonly IntPtr GetMethodIdPointer { get; init; }
|
||||
internal readonly IntPtr CallObjectMethodPointer { get; init; }
|
||||
internal readonly IntPtr CallObjectMethodVPointer { get; init; }
|
||||
internal readonly IntPtr CallObjectMethodAPointer { get; init; }
|
||||
internal readonly IntPtr CallBooleanMethodPointer { get; init; }
|
||||
internal readonly IntPtr CallBooleanMethodVPointer { get; init; }
|
||||
internal readonly IntPtr CallBooleanMethodAPointer { get; init; }
|
||||
internal readonly IntPtr CallByteMethodPointer { get; init; }
|
||||
internal readonly IntPtr CallByteMethodVPointer { get; init; }
|
||||
internal readonly IntPtr CallByteMethodAPointer { get; init; }
|
||||
internal readonly IntPtr CallCharMethodPointer { get; init; }
|
||||
internal readonly IntPtr CallCharMethodVPointer { get; init; }
|
||||
internal readonly IntPtr CallCharMethodAPointer { get; init; }
|
||||
internal readonly IntPtr CallShortMethodPointer { get; init; }
|
||||
internal readonly IntPtr CallShortMethodVPointer { get; init; }
|
||||
internal readonly IntPtr CallShortMethodAPointer { get; init; }
|
||||
internal readonly IntPtr CallIntMethodPointer { get; init; }
|
||||
internal readonly IntPtr CallIntMethodVPointer { get; init; }
|
||||
internal readonly IntPtr CallIntMethodAPointer { get; init; }
|
||||
internal readonly IntPtr CallLongMethodPointer { get; init; }
|
||||
internal readonly IntPtr CallLongMethodVPointer { get; init; }
|
||||
internal readonly IntPtr CallLongMethodAPointer { get; init; }
|
||||
internal readonly IntPtr CallFloatMethodPointer { get; init; }
|
||||
internal readonly IntPtr CallFloatMethodVPointer { get; init; }
|
||||
internal readonly IntPtr CallFloatMethodAPointer { get; init; }
|
||||
internal readonly IntPtr CallDoubleMethodPointer { get; init; }
|
||||
internal readonly IntPtr CallDoubleMethodVPointer { get; init; }
|
||||
internal readonly IntPtr CallDoubleMethodAPointer { get; init; }
|
||||
internal readonly IntPtr CallVoidMethodPointer { get; init; }
|
||||
internal readonly IntPtr CallVoidMethodVPointer { get; init; }
|
||||
internal readonly IntPtr CallVoidMethodAPointer { get; init; }
|
||||
internal readonly IntPtr CallNonVirtualObjectMethodPointer { get; init; }
|
||||
internal readonly IntPtr CallNonVirtualObjectMethodVPointer { get; init; }
|
||||
internal readonly IntPtr CallNonVirtualObjectMethodAPointer { get; init; }
|
||||
internal readonly IntPtr CallNonVirtualBooleanMethodPointer { get; init; }
|
||||
internal readonly IntPtr CallNonVirtualBooleanMethodVPointer { get; init; }
|
||||
internal readonly IntPtr CallNonVirtualBooleanMethodAPointer { get; init; }
|
||||
internal readonly IntPtr CallNonVirtualByteMethodPointer { get; init; }
|
||||
internal readonly IntPtr CallNonVirtualByteMethodVPointer { get; init; }
|
||||
internal readonly IntPtr CallNonVirtualByteMethodAPointer { get; init; }
|
||||
internal readonly IntPtr CallNonVirtualCharMethodPointer { get; init; }
|
||||
internal readonly IntPtr CallNonVirtualCharMethodVPointer { get; init; }
|
||||
internal readonly IntPtr CallNonVirtualCharMethodAPointer { get; init; }
|
||||
internal readonly IntPtr CallNonVirtualShortMethodPointer { get; init; }
|
||||
internal readonly IntPtr CallNonVirtualShortMethodVPointer { get; init; }
|
||||
internal readonly IntPtr CallNonVirtualShortMethodAPointer { get; init; }
|
||||
internal readonly IntPtr CallNonVirtualIntMethodPointer { get; init; }
|
||||
internal readonly IntPtr CallNonVirtualIntMethodVPointer { get; init; }
|
||||
internal readonly IntPtr CallNonVirtualIntMethodAPointer { get; init; }
|
||||
internal readonly IntPtr CallNonVirtualLongMethodPointer { get; init; }
|
||||
internal readonly IntPtr CallNonVirtualLongMethodVPointer { get; init; }
|
||||
internal readonly IntPtr CallNonVirtualLongMethodAPointer { get; init; }
|
||||
internal readonly IntPtr CallNonVirtualFloatMethodPointer { get; init; }
|
||||
internal readonly IntPtr CallNonVirtualFloatMethodVPointer { get; init; }
|
||||
internal readonly IntPtr CallNonVirtualFloatMethodAPointer { get; init; }
|
||||
internal readonly IntPtr CallNonVirtualDoubleMethodPointer { get; init; }
|
||||
internal readonly IntPtr CallNonVirtualDoubleMethodVPointer { get; init; }
|
||||
internal readonly IntPtr CallNonVirtualDoubleMethodAPointer { get; init; }
|
||||
internal readonly IntPtr CallNonVirtualVoidMethodPointer { get; init; }
|
||||
internal readonly IntPtr CallNonVirtualVoidMethodVPointer { get; init; }
|
||||
internal readonly IntPtr CallNonVirtualVoidMethodAPointer { get; init; }
|
||||
internal readonly IntPtr GetFieldIdPointer { get; init; }
|
||||
internal readonly IntPtr GetObjectFieldPointer { get; init; }
|
||||
internal readonly IntPtr GetBooleanFieldPointer { get; init; }
|
||||
internal readonly IntPtr GetByteFieldPointer { get; init; }
|
||||
internal readonly IntPtr GetCharFieldPointer { get; init; }
|
||||
internal readonly IntPtr GetShortFieldPointer { get; init; }
|
||||
internal readonly IntPtr GetIntFieldPointer { get; init; }
|
||||
internal readonly IntPtr GetLongFieldPointer { get; init; }
|
||||
internal readonly IntPtr GetFloatFieldPointer { get; init; }
|
||||
internal readonly IntPtr GetDoubleFieldPointer { get; init; }
|
||||
internal readonly IntPtr SetObjectFieldPointer { get; init; }
|
||||
internal readonly IntPtr SetBooleanFieldPointer { get; init; }
|
||||
internal readonly IntPtr SetByteFieldPointer { get; init; }
|
||||
internal readonly IntPtr SetCharFieldPointer { get; init; }
|
||||
internal readonly IntPtr SetShortFieldPointer { get; init; }
|
||||
internal readonly IntPtr SetIntFieldPointer { get; init; }
|
||||
internal readonly IntPtr SetLongFieldPointer { get; init; }
|
||||
internal readonly IntPtr SetFloatFieldPointer { get; init; }
|
||||
internal readonly IntPtr SetDoubleFieldPointer { get; init; }
|
||||
internal readonly IntPtr GetStaticMethodIdPointer { get; init; }
|
||||
internal readonly IntPtr CallStaticObjectMethodPointer { get; init; }
|
||||
internal readonly IntPtr CallStaticObjectMethodVPointer { get; init; }
|
||||
internal readonly IntPtr CallStaticObjectMethodAPointer { get; init; }
|
||||
internal readonly IntPtr CallStaticBooleanMethodPointer { get; init; }
|
||||
internal readonly IntPtr CallStaticBooleanMethodVPointer { get; init; }
|
||||
internal readonly IntPtr CallStaticBooleanMethodAPointer { get; init; }
|
||||
internal readonly IntPtr CallStaticByteMethodPointer { get; init; }
|
||||
internal readonly IntPtr CallStaticByteMethodVPointer { get; init; }
|
||||
internal readonly IntPtr CallStaticByteMethodAPointer { get; init; }
|
||||
internal readonly IntPtr CallStaticCharMethodPointer { get; init; }
|
||||
internal readonly IntPtr CallStaticCharMethodVPointer { get; init; }
|
||||
internal readonly IntPtr CallStaticCharMethodAPointer { get; init; }
|
||||
internal readonly IntPtr CallStaticShortMethodPointer { get; init; }
|
||||
internal readonly IntPtr CallStaticShortMethodVPointer { get; init; }
|
||||
internal readonly IntPtr CallStaticShortMethodAPointer { get; init; }
|
||||
internal readonly IntPtr CallStaticIntMethodPointer { get; init; }
|
||||
internal readonly IntPtr CallStaticIntMethodVPointer { get; init; }
|
||||
internal readonly IntPtr CallStaticIntMethodAPointer { get; init; }
|
||||
internal readonly IntPtr CallStaticLongMethodPointer { get; init; }
|
||||
internal readonly IntPtr CallStaticLongMethodVPointer { get; init; }
|
||||
internal readonly IntPtr CallStaticLongMethodAPointer { get; init; }
|
||||
internal readonly IntPtr CallStaticFloatMethodPointer { get; init; }
|
||||
internal readonly IntPtr CallStaticFloatMethodVPointer { get; init; }
|
||||
internal readonly IntPtr CallStaticFloatMethodAPointer { get; init; }
|
||||
internal readonly IntPtr CallStaticDoubleMethodPointer { get; init; }
|
||||
internal readonly IntPtr CallStaticDoubleMethodVPointer { get; init; }
|
||||
internal readonly IntPtr CallStaticDoubleMethodAPointer { get; init; }
|
||||
internal readonly IntPtr CallStaticVoidMethodPointer { get; init; }
|
||||
internal readonly IntPtr CallStaticVoidMethodVPointer { get; init; }
|
||||
internal readonly IntPtr CallStaticVoidMethodAPointer { get; init; }
|
||||
internal readonly IntPtr GetStaticFieldIdPointer { get; init; }
|
||||
internal readonly IntPtr GetStaticObjectFieldPointer { get; init; }
|
||||
internal readonly IntPtr GetStaticBooleanFieldPointer { get; init; }
|
||||
internal readonly IntPtr GetStaticByteFieldPointer { get; init; }
|
||||
internal readonly IntPtr GetStaticCharFieldPointer { get; init; }
|
||||
internal readonly IntPtr GetStaticShortFieldPointer { get; init; }
|
||||
internal readonly IntPtr GetStaticIntFieldPointer { get; init; }
|
||||
internal readonly IntPtr GetStaticLongFieldPointer { get; init; }
|
||||
internal readonly IntPtr GetStaticFloatFieldPointer { get; init; }
|
||||
internal readonly IntPtr GetStaticDoubleFieldPointer { get; init; }
|
||||
internal readonly IntPtr SetStaticObjectFieldPointer { get; init; }
|
||||
internal readonly IntPtr SetStaticBooleanFieldPointer { get; init; }
|
||||
internal readonly IntPtr SetStaticByteFieldPointer { get; init; }
|
||||
internal readonly IntPtr SetStaticCharFieldPointer { get; init; }
|
||||
internal readonly IntPtr SetStaticShortFieldPointer { get; init; }
|
||||
internal readonly IntPtr SetStaticIntFieldPointer { get; init; }
|
||||
internal readonly IntPtr SetStaticLongFieldPointer { get; init; }
|
||||
internal readonly IntPtr SetStaticFloatFieldPointer { get; init; }
|
||||
internal readonly IntPtr SetStaticDoubleFieldPointer { get; init; }
|
||||
internal readonly IntPtr NewStringPointer { get; init; }
|
||||
internal readonly IntPtr GetStringLengthPointer { get; init; }
|
||||
internal readonly IntPtr GetStringCharsPointer { get; init; }
|
||||
internal readonly IntPtr ReleaseStringCharsPointer { get; init; }
|
||||
internal readonly IntPtr NewStringUtfPointer { get; init; }
|
||||
internal readonly IntPtr GetStringUtfLengthPointer { get; init; }
|
||||
internal readonly IntPtr GetStringUtfCharsPointer { get; init; }
|
||||
internal readonly IntPtr ReleaseStringUtfCharsPointer { get; init; }
|
||||
internal readonly IntPtr GetArrayLengthPointer { get; init; }
|
||||
internal readonly IntPtr NewObjectArrayPointer { get; init; }
|
||||
internal readonly IntPtr GetObjectArrayElementPointer { get; init; }
|
||||
internal readonly IntPtr SetObjectArrayElementPointer { get; init; }
|
||||
internal readonly IntPtr NewBooleanArrayPointer { get; init; }
|
||||
internal readonly IntPtr NewByteArrayPointer { get; init; }
|
||||
internal readonly IntPtr NewCharArrayPointer { get; init; }
|
||||
internal readonly IntPtr NewShortArrayPointer { get; init; }
|
||||
internal readonly IntPtr NewIntArrayPointer { get; init; }
|
||||
internal readonly IntPtr NewLongArrayPointer { get; init; }
|
||||
internal readonly IntPtr NewFloatArrayPointer { get; init; }
|
||||
internal readonly IntPtr NewDoubleArrayPointer { get; init; }
|
||||
internal readonly IntPtr GetBooleanArrayElementsPointer { get; init; }
|
||||
internal readonly IntPtr GetByteArrayElementsPointer { get; init; }
|
||||
internal readonly IntPtr GetCharArrayElementsPointer { get; init; }
|
||||
internal readonly IntPtr GetShortArrayElementsPointer { get; init; }
|
||||
internal readonly IntPtr GetIntArrayElementsPointer { get; init; }
|
||||
internal readonly IntPtr GetLongArrayElementsPointer { get; init; }
|
||||
internal readonly IntPtr GetFloatArrayElementsPointer { get; init; }
|
||||
internal readonly IntPtr GetDoubleArrayElementsPointer { get; init; }
|
||||
internal readonly IntPtr ReleaseBooleanArrayElementsPointer { get; init; }
|
||||
internal readonly IntPtr ReleaseByteArrayElementsPointer { get; init; }
|
||||
internal readonly IntPtr ReleaseCharArrayElementsPointer { get; init; }
|
||||
internal readonly IntPtr ReleaseShortArrayElementsPointer { get; init; }
|
||||
internal readonly IntPtr ReleaseIntArrayElementsPointer { get; init; }
|
||||
internal readonly IntPtr ReleaseLongArrayElementsPointer { get; init; }
|
||||
internal readonly IntPtr ReleaseFloatArrayElementsPointer { get; init; }
|
||||
internal readonly IntPtr ReleaseDoubleArrayElementsPointer { get; init; }
|
||||
internal readonly IntPtr GetBooleanArrayRegionPointer { get; init; }
|
||||
internal readonly IntPtr GetByteArrayRegionPointer { get; init; }
|
||||
internal readonly IntPtr GetCharArrayRegionPointer { get; init; }
|
||||
internal readonly IntPtr GetShortArrayRegionPointer { get; init; }
|
||||
internal readonly IntPtr GetIntArrayRegionPointer { get; init; }
|
||||
internal readonly IntPtr GetLongArrayRegionPointer { get; init; }
|
||||
internal readonly IntPtr GetFloatArrayRegionPointer { get; init; }
|
||||
internal readonly IntPtr GetDoubleArrayRegionPointer { get; init; }
|
||||
internal readonly IntPtr SetBooleanArrayRegionPointer { get; init; }
|
||||
internal readonly IntPtr SetByteArrayRegionPointer { get; init; }
|
||||
internal readonly IntPtr SetCharArrayRegionPointer { get; init; }
|
||||
internal readonly IntPtr SetShortArrayRegionPointer { get; init; }
|
||||
internal readonly IntPtr SetIntArrayRegionPointer { get; init; }
|
||||
internal readonly IntPtr SetLongArrayRegionPointer { get; init; }
|
||||
internal readonly IntPtr SetFloatArrayRegionPointer { get; init; }
|
||||
internal readonly IntPtr SetDoubleArrayRegionPointer { get; init; }
|
||||
internal readonly IntPtr RegisterNativesPointer { get; init; }
|
||||
internal readonly IntPtr UnregisterNativesPointer { get; init; }
|
||||
internal readonly IntPtr MonitorEnterPointer { get; init; }
|
||||
internal readonly IntPtr MonitorExitPointer { get; init; }
|
||||
internal readonly IntPtr GetJavaVMPointer { get; init; }
|
||||
internal readonly IntPtr GetStringRegionPointer { get; init; }
|
||||
internal readonly IntPtr GetStringUtfRegionPointer { get; init; }
|
||||
internal readonly IntPtr GetPrimitiveArrayCriticalPointer { get; init; }
|
||||
internal readonly IntPtr ReleasePrimitiveArrayCriticalPointer { get; init; }
|
||||
internal readonly IntPtr GetStringCriticalPointer { get; init; }
|
||||
internal readonly IntPtr ReleaseStringCriticalPointer { get; init; }
|
||||
internal readonly IntPtr NewWeakGlobalRefPointer { get; init; }
|
||||
internal readonly IntPtr DeleteWeakGlobalRefPointer { get; init; }
|
||||
internal readonly IntPtr ExceptionCheckPointer { get; init; }
|
||||
internal readonly IntPtr NewDirectByteBufferPointer { get; init; }
|
||||
internal readonly IntPtr GetDirectBufferAddressPointer { get; init; }
|
||||
internal readonly IntPtr GetDirectBufferCapacityPointer { get; init; }
|
||||
internal readonly IntPtr GetObjectRefTypePointer { get; init; }
|
||||
}
|
||||
}
|
12
src/LibRyujinx/Jni/Values/JNativeMethod.cs
Normal file
12
src/LibRyujinx/Jni/Values/JNativeMethod.cs
Normal file
@ -0,0 +1,12 @@
|
||||
using LibRyujinx.Jni.Pointers;
|
||||
using System;
|
||||
|
||||
namespace LibRyujinx.Jni.Values
|
||||
{
|
||||
public readonly struct JNativeMethod
|
||||
{
|
||||
internal CCharSequence Name { get; init; }
|
||||
internal CCharSequence Signature { get; init; }
|
||||
internal IntPtr Pointer { get; init; }
|
||||
}
|
||||
}
|
47
src/LibRyujinx/Jni/Values/JValue.cs
Normal file
47
src/LibRyujinx/Jni/Values/JValue.cs
Normal file
@ -0,0 +1,47 @@
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
using Rxmxnx.PInvoke;
|
||||
using System;
|
||||
|
||||
namespace LibRyujinx.Jni.Values
|
||||
{
|
||||
internal readonly struct JValue
|
||||
{
|
||||
private delegate Boolean IsDefaultDelegate(in JValue value);
|
||||
|
||||
public static readonly Int32 Size = NativeUtilities.SizeOf<JValue>();
|
||||
|
||||
private static readonly IsDefaultDelegate isDefault = GetIsDefault();
|
||||
|
||||
#pragma warning disable 0649
|
||||
#pragma warning disable 0169
|
||||
private readonly Byte _value1;
|
||||
private readonly Byte _value2;
|
||||
private readonly Int16 _value3;
|
||||
private readonly Int32 _value4;
|
||||
#pragma warning restore 0169
|
||||
#pragma warning restore 0649
|
||||
|
||||
public Boolean IsDefault => isDefault(this);
|
||||
|
||||
public static JValue Create(in ReadOnlySpan<Byte> source)
|
||||
{
|
||||
Byte[] result = new Byte[Size];
|
||||
for (Int32 i = 0; i < source.Length; i++)
|
||||
result[i] = source[i];
|
||||
return result.ToValue<JValue>();
|
||||
}
|
||||
|
||||
private static IsDefaultDelegate GetIsDefault() => Environment.Is64BitProcess ? DefaultLong : Default;
|
||||
|
||||
private static Boolean Default(in JValue jValue)
|
||||
=> (jValue._value1 + jValue._value2 + jValue._value3) == default
|
||||
&& jValue._value4 == default;
|
||||
|
||||
private static Boolean DefaultLong(in JValue jValue)
|
||||
{
|
||||
var jv = jValue;
|
||||
return Unsafe.AsRef(ref jv).Transform<JValue, Int64>() == default;
|
||||
}
|
||||
}
|
||||
}
|
13
src/LibRyujinx/Jni/Values/JavaVMAttachArgs.cs
Normal file
13
src/LibRyujinx/Jni/Values/JavaVMAttachArgs.cs
Normal file
@ -0,0 +1,13 @@
|
||||
using LibRyujinx.Jni.Pointers;
|
||||
using LibRyujinx.Jni.References;
|
||||
using System;
|
||||
|
||||
namespace LibRyujinx.Jni.Values
|
||||
{
|
||||
public readonly struct JavaVMAttachArgs
|
||||
{
|
||||
internal Int32 Version { get; init; }
|
||||
internal CCharSequence Name { get; init; }
|
||||
internal JObjectLocalRef Group { get; init; }
|
||||
}
|
||||
}
|
12
src/LibRyujinx/Jni/Values/JavaVMInitArgs.cs
Normal file
12
src/LibRyujinx/Jni/Values/JavaVMInitArgs.cs
Normal file
@ -0,0 +1,12 @@
|
||||
using System;
|
||||
|
||||
namespace LibRyujinx.Jni.Values
|
||||
{
|
||||
public readonly struct JavaVMInitArgs
|
||||
{
|
||||
internal Int32 Version { get; init; }
|
||||
internal Int32 OptionsLenght { get; init; }
|
||||
internal IntPtr Options { get; init; }
|
||||
internal Boolean IgnoreUnrecognized { get; init; }
|
||||
}
|
||||
}
|
11
src/LibRyujinx/Jni/Values/JavaVMOption.cs
Normal file
11
src/LibRyujinx/Jni/Values/JavaVMOption.cs
Normal file
@ -0,0 +1,11 @@
|
||||
using LibRyujinx.Jni.Pointers;
|
||||
using System;
|
||||
|
||||
namespace LibRyujinx.Jni.Values
|
||||
{
|
||||
public readonly struct JavaVMOption
|
||||
{
|
||||
internal CCharSequence Name { get; init; }
|
||||
internal IntPtr ExtraInfo { get; init; }
|
||||
}
|
||||
}
|
301
src/LibRyujinx/LibRyujinx.Device.cs
Normal file
301
src/LibRyujinx/LibRyujinx.Device.cs
Normal file
@ -0,0 +1,301 @@
|
||||
using ARMeilleure.Translation;
|
||||
using LibHac.Ncm;
|
||||
using LibHac.Tools.FsSystem.NcaUtils;
|
||||
using Microsoft.Win32.SafeHandles;
|
||||
using Ryujinx.Common.Logging;
|
||||
using Ryujinx.HLE.FileSystem;
|
||||
using Ryujinx.HLE.HOS.SystemState;
|
||||
using Ryujinx.Input.HLE;
|
||||
using Silk.NET.Vulkan;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace LibRyujinx
|
||||
{
|
||||
public static partial class LibRyujinx
|
||||
{
|
||||
[UnmanagedCallersOnly(EntryPoint = "device_initialize")]
|
||||
public static bool InitializeDeviceNative(bool isHostMapped,
|
||||
bool useNce,
|
||||
SystemLanguage systemLanguage,
|
||||
RegionCode regionCode,
|
||||
bool enableVsync,
|
||||
bool enableDockedMode,
|
||||
bool enablePtc,
|
||||
bool enableInternetAccess,
|
||||
IntPtr timeZone,
|
||||
bool ignoreMissingServices)
|
||||
{
|
||||
return InitializeDevice(isHostMapped,
|
||||
useNce,
|
||||
systemLanguage,
|
||||
regionCode,
|
||||
enableVsync,
|
||||
enableDockedMode,
|
||||
enablePtc,
|
||||
enableInternetAccess,
|
||||
Marshal.PtrToStringAnsi(timeZone),
|
||||
ignoreMissingServices);
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly(EntryPoint = "device_reloadFilesystem")]
|
||||
public static void ReloadFileSystem()
|
||||
{
|
||||
SwitchDevice?.ReloadFileSystem();
|
||||
}
|
||||
|
||||
public static bool InitializeDevice(bool isHostMapped,
|
||||
bool useNce,
|
||||
SystemLanguage systemLanguage,
|
||||
RegionCode regionCode,
|
||||
bool enableVsync,
|
||||
bool enableDockedMode,
|
||||
bool enablePtc,
|
||||
bool enableInternetAccess,
|
||||
string? timeZone,
|
||||
bool ignoreMissingServices)
|
||||
{
|
||||
if (SwitchDevice == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return SwitchDevice.InitializeContext(isHostMapped,
|
||||
useNce,
|
||||
systemLanguage,
|
||||
regionCode,
|
||||
enableVsync,
|
||||
enableDockedMode,
|
||||
enablePtc,
|
||||
enableInternetAccess,
|
||||
timeZone,
|
||||
ignoreMissingServices);
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly(EntryPoint = "device_load")]
|
||||
public static bool LoadApplicationNative(IntPtr pathPtr)
|
||||
{
|
||||
if(SwitchDevice?.EmulationContext == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var path = Marshal.PtrToStringAnsi(pathPtr);
|
||||
|
||||
return LoadApplication(path);
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly(EntryPoint = "device_install_firmware")]
|
||||
public static void InstallFirmwareNative(int descriptor, bool isXci)
|
||||
{
|
||||
var stream = OpenFile(descriptor);
|
||||
|
||||
InstallFirmware(stream, isXci);
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly(EntryPoint = "device_get_installed_firmware_version")]
|
||||
public static IntPtr GetInstalledFirmwareVersionNative()
|
||||
{
|
||||
var result = GetInstalledFirmwareVersion();
|
||||
return Marshal.StringToHGlobalAnsi(result);
|
||||
}
|
||||
|
||||
public static void InstallFirmware(Stream stream, bool isXci)
|
||||
{
|
||||
SwitchDevice?.ContentManager.InstallFirmware(stream, isXci);
|
||||
}
|
||||
|
||||
public static string GetInstalledFirmwareVersion()
|
||||
{
|
||||
var version = SwitchDevice?.ContentManager.GetCurrentFirmwareVersion();
|
||||
|
||||
if (version != null)
|
||||
{
|
||||
return version.VersionString;
|
||||
}
|
||||
|
||||
return String.Empty;
|
||||
}
|
||||
|
||||
public static SystemVersion? VerifyFirmware(Stream stream, bool isXci)
|
||||
{
|
||||
return SwitchDevice?.ContentManager?.VerifyFirmwarePackage(stream, isXci) ?? null;
|
||||
}
|
||||
|
||||
public static bool LoadApplication(Stream stream, FileType type, Stream? updateStream = null)
|
||||
{
|
||||
var emulationContext = SwitchDevice.EmulationContext;
|
||||
return type switch
|
||||
{
|
||||
FileType.None => false,
|
||||
FileType.Nsp => emulationContext?.LoadNsp(stream, updateStream) ?? false,
|
||||
FileType.Xci => emulationContext?.LoadXci(stream, updateStream) ?? false,
|
||||
FileType.Nro => emulationContext?.LoadProgram(stream, true, "") ?? false,
|
||||
};
|
||||
}
|
||||
|
||||
public static bool LaunchMiiEditApplet()
|
||||
{
|
||||
string contentPath = SwitchDevice.ContentManager.GetInstalledContentPath(0x0100000000001009, StorageId.BuiltInSystem, NcaContentType.Program);
|
||||
|
||||
return LoadApplication(contentPath);
|
||||
}
|
||||
|
||||
public static bool LoadApplication(string? path)
|
||||
{
|
||||
var emulationContext = SwitchDevice.EmulationContext;
|
||||
|
||||
if (Directory.Exists(path))
|
||||
{
|
||||
string[] romFsFiles = Directory.GetFiles(path, "*.istorage");
|
||||
|
||||
if (romFsFiles.Length == 0)
|
||||
{
|
||||
romFsFiles = Directory.GetFiles(path, "*.romfs");
|
||||
}
|
||||
|
||||
if (romFsFiles.Length > 0)
|
||||
{
|
||||
Logger.Info?.Print(LogClass.Application, "Loading as cart with RomFS.");
|
||||
|
||||
if (!emulationContext.LoadCart(path, romFsFiles[0]))
|
||||
{
|
||||
SwitchDevice.DisposeContext();
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger.Info?.Print(LogClass.Application, "Loading as cart WITHOUT RomFS.");
|
||||
|
||||
if (!emulationContext.LoadCart(path))
|
||||
{
|
||||
SwitchDevice.DisposeContext();
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (File.Exists(path))
|
||||
{
|
||||
switch (Path.GetExtension(path).ToLowerInvariant())
|
||||
{
|
||||
case ".xci":
|
||||
Logger.Info?.Print(LogClass.Application, "Loading as XCI.");
|
||||
|
||||
if (!emulationContext.LoadXci(path))
|
||||
{
|
||||
SwitchDevice.DisposeContext();
|
||||
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case ".nca":
|
||||
Logger.Info?.Print(LogClass.Application, "Loading as NCA.");
|
||||
|
||||
if (!emulationContext.LoadNca(path))
|
||||
{
|
||||
SwitchDevice.DisposeContext();
|
||||
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case ".nsp":
|
||||
case ".pfs0":
|
||||
Logger.Info?.Print(LogClass.Application, "Loading as NSP.");
|
||||
|
||||
if (!emulationContext.LoadNsp(path))
|
||||
{
|
||||
SwitchDevice.DisposeContext();
|
||||
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
Logger.Info?.Print(LogClass.Application, "Loading as Homebrew.");
|
||||
try
|
||||
{
|
||||
if (!emulationContext.LoadProgram(path))
|
||||
{
|
||||
SwitchDevice.DisposeContext();
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
catch (ArgumentOutOfRangeException)
|
||||
{
|
||||
Logger.Error?.Print(LogClass.Application, "The specified file is not supported by Ryujinx.");
|
||||
|
||||
SwitchDevice.DisposeContext();
|
||||
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger.Warning?.Print(LogClass.Application, $"Couldn't load '{path}'. Please specify a valid XCI/NCA/NSP/PFS0/NRO file.");
|
||||
|
||||
SwitchDevice.DisposeContext();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static void SignalEmulationClose()
|
||||
{
|
||||
_isStopped = true;
|
||||
_isActive = false;
|
||||
|
||||
debug_break(2);
|
||||
}
|
||||
|
||||
public static void CloseEmulation()
|
||||
{
|
||||
if (SwitchDevice == null)
|
||||
return;
|
||||
|
||||
_npadManager?.Dispose();
|
||||
_npadManager = null;
|
||||
|
||||
_touchScreenManager?.Dispose();
|
||||
_touchScreenManager = null;
|
||||
|
||||
SwitchDevice?.InputManager?.Dispose();
|
||||
SwitchDevice.InputManager = null;
|
||||
_inputManager = null;
|
||||
|
||||
|
||||
_surfaceEvent?.Set();
|
||||
|
||||
if (Renderer != null)
|
||||
{
|
||||
_gpuDoneEvent.WaitOne();
|
||||
_gpuDoneEvent.Dispose();
|
||||
_gpuDoneEvent = null;
|
||||
SwitchDevice?.DisposeContext();
|
||||
Renderer = null;
|
||||
}
|
||||
}
|
||||
|
||||
private static FileStream OpenFile(int descriptor)
|
||||
{
|
||||
var safeHandle = new SafeFileHandle(descriptor, false);
|
||||
|
||||
return new FileStream(safeHandle, FileAccess.ReadWrite);
|
||||
}
|
||||
|
||||
public enum FileType
|
||||
{
|
||||
None,
|
||||
Nsp,
|
||||
Xci,
|
||||
Nro
|
||||
}
|
||||
}
|
||||
}
|
324
src/LibRyujinx/LibRyujinx.Graphics.cs
Normal file
324
src/LibRyujinx/LibRyujinx.Graphics.cs
Normal file
@ -0,0 +1,324 @@
|
||||
using ARMeilleure.Translation;
|
||||
using LibHac.Bcat;
|
||||
using LibRyujinx.Shared;
|
||||
using OpenTK.Graphics.OpenGL;
|
||||
using Ryujinx.Common.Configuration;
|
||||
using Ryujinx.Cpu;
|
||||
using Ryujinx.Graphics.GAL;
|
||||
using Ryujinx.Graphics.GAL.Multithreading;
|
||||
using Ryujinx.Graphics.Gpu;
|
||||
using Ryujinx.Graphics.Gpu.Shader;
|
||||
using Ryujinx.Graphics.OpenGL;
|
||||
using Ryujinx.Graphics.Vulkan;
|
||||
using Silk.NET.Vulkan;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Threading;
|
||||
|
||||
namespace LibRyujinx
|
||||
{
|
||||
public static partial class LibRyujinx
|
||||
{
|
||||
private static bool _isActive;
|
||||
private static bool _isStopped;
|
||||
private static CancellationTokenSource _gpuCancellationTokenSource;
|
||||
private static SwapBuffersCallback? _swapBuffersCallback;
|
||||
private static NativeGraphicsInterop _nativeGraphicsInterop;
|
||||
private static ManualResetEvent _gpuDoneEvent;
|
||||
|
||||
public delegate void SwapBuffersCallback();
|
||||
public delegate IntPtr GetProcAddress(string name);
|
||||
public delegate IntPtr CreateSurface(IntPtr instance);
|
||||
|
||||
public static IRenderer? Renderer { get; set; }
|
||||
public static GraphicsConfiguration GraphicsConfiguration { get; private set; }
|
||||
|
||||
[UnmanagedCallersOnly(EntryPoint = "graphics_initialize")]
|
||||
public static bool InitializeGraphicsNative(GraphicsConfiguration graphicsConfiguration)
|
||||
{
|
||||
if (Ryujinx.Common.PlatformInfo.IsBionic)
|
||||
{
|
||||
Silk.NET.Core.Loader.SearchPathContainer.Platform = Silk.NET.Core.Loader.UnderlyingPlatform.Android;
|
||||
}
|
||||
else if (OperatingSystem.IsIOS())
|
||||
{
|
||||
// Yes, macOS not iOS
|
||||
Silk.NET.Core.Loader.SearchPathContainer.Platform = Silk.NET.Core.Loader.UnderlyingPlatform.MacOS;
|
||||
}
|
||||
return InitializeGraphics(graphicsConfiguration);
|
||||
}
|
||||
|
||||
public static bool InitializeGraphics(GraphicsConfiguration graphicsConfiguration)
|
||||
{
|
||||
GraphicsConfig.ResScale = graphicsConfiguration.ResScale;
|
||||
GraphicsConfig.MaxAnisotropy = graphicsConfiguration.MaxAnisotropy;
|
||||
GraphicsConfig.FastGpuTime = graphicsConfiguration.FastGpuTime;
|
||||
GraphicsConfig.Fast2DCopy = graphicsConfiguration.Fast2DCopy;
|
||||
GraphicsConfig.EnableMacroJit = graphicsConfiguration.EnableMacroJit;
|
||||
GraphicsConfig.EnableMacroHLE = graphicsConfiguration.EnableMacroHLE;
|
||||
GraphicsConfig.EnableShaderCache = graphicsConfiguration.EnableShaderCache;
|
||||
GraphicsConfig.EnableTextureRecompression = graphicsConfiguration.EnableTextureRecompression;
|
||||
|
||||
GraphicsConfiguration = graphicsConfiguration;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly(EntryPoint = "graphics_initialize_renderer")]
|
||||
public unsafe static bool InitializeGraphicsRendererNative(GraphicsBackend graphicsBackend, NativeGraphicsInterop nativeGraphicsInterop)
|
||||
{
|
||||
_nativeGraphicsInterop = nativeGraphicsInterop;
|
||||
if (Renderer != null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
List<string> extensions = new List<string>();
|
||||
var size = Marshal.SizeOf<IntPtr>();
|
||||
var extPtr = (IntPtr*)nativeGraphicsInterop.VkRequiredExtensions;
|
||||
for (int i = 0; i < nativeGraphicsInterop.VkRequiredExtensionsCount; i++)
|
||||
{
|
||||
var ptr = extPtr[i];
|
||||
extensions.Add(Marshal.PtrToStringAnsi(ptr) ?? string.Empty);
|
||||
}
|
||||
|
||||
CreateSurface createSurfaceFunc = nativeGraphicsInterop.VkCreateSurface == IntPtr.Zero ? default : Marshal.GetDelegateForFunctionPointer<CreateSurface>(nativeGraphicsInterop.VkCreateSurface);
|
||||
|
||||
return InitializeGraphicsRenderer(graphicsBackend, createSurfaceFunc, extensions.ToArray());
|
||||
}
|
||||
|
||||
public static bool InitializeGraphicsRenderer(GraphicsBackend graphicsBackend, CreateSurface createSurfaceFunc, string?[] requiredExtensions)
|
||||
{
|
||||
if (Renderer != null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (graphicsBackend == GraphicsBackend.OpenGl)
|
||||
{
|
||||
Renderer = new OpenGLRenderer();
|
||||
}
|
||||
else if (graphicsBackend == GraphicsBackend.Vulkan)
|
||||
{
|
||||
Renderer = new VulkanRenderer(VulkanLoader?.GetApi() ?? Vk.GetApi(), (instance, vk) => new SurfaceKHR((ulong?)createSurfaceFunc(instance.Handle)),
|
||||
() => requiredExtensions,
|
||||
null);
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
[UnmanagedCallersOnly(EntryPoint = "graphics_renderer_set_size")]
|
||||
public static void SetRendererSizeNative(int width, int height)
|
||||
{
|
||||
SetRendererSize(width, height);
|
||||
}
|
||||
|
||||
public static void SetRendererSize(int width, int height)
|
||||
{
|
||||
Renderer?.Window?.SetSize(width, height);
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly(EntryPoint = "graphics_renderer_run_loop")]
|
||||
public static void RunLoopNative()
|
||||
{
|
||||
if (Renderer is OpenGLRenderer)
|
||||
{
|
||||
var proc = Marshal.GetDelegateForFunctionPointer<GetProcAddress>(_nativeGraphicsInterop.GlGetProcAddress);
|
||||
GL.LoadBindings(new OpenTKBindingsContext(x => proc!.Invoke(x)));
|
||||
}
|
||||
RunLoop();
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly(EntryPoint = "graphics_renderer_set_vsync")]
|
||||
public static void SetVsyncStateNative(bool enabled)
|
||||
{
|
||||
SetVsyncState(enabled);
|
||||
}
|
||||
|
||||
public static void SetVsyncState(bool enabled)
|
||||
{
|
||||
var device = SwitchDevice!.EmulationContext!;
|
||||
device.EnableDeviceVsync = enabled;
|
||||
device.Gpu.Renderer.Window.ChangeVSyncMode(enabled);
|
||||
}
|
||||
|
||||
public static void RunLoop()
|
||||
{
|
||||
if (Renderer == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
var device = SwitchDevice!.EmulationContext!;
|
||||
_gpuDoneEvent = new ManualResetEvent(true);
|
||||
|
||||
device.Gpu.Renderer.Initialize(GraphicsDebugLevel.None);
|
||||
_gpuCancellationTokenSource = new CancellationTokenSource();
|
||||
|
||||
device.Gpu.ShaderCacheStateChanged += LoadProgressStateChangedHandler;
|
||||
device.Processes.ActiveApplication.DiskCacheLoadState.StateChanged += LoadProgressStateChangedHandler;
|
||||
|
||||
try
|
||||
{
|
||||
device.Gpu.Renderer.RunLoop(() =>
|
||||
{
|
||||
_gpuDoneEvent.Reset();
|
||||
device.Gpu.SetGpuThread();
|
||||
device.Gpu.InitializeShaderCache(_gpuCancellationTokenSource.Token);
|
||||
|
||||
_isActive = true;
|
||||
|
||||
while (_isActive)
|
||||
{
|
||||
if (_isStopped)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
debug_break(1);
|
||||
|
||||
if (Ryujinx.Common.PlatformInfo.IsBionic)
|
||||
{
|
||||
setRenderingThread();
|
||||
}
|
||||
|
||||
if (device.WaitFifo())
|
||||
{
|
||||
device.Statistics.RecordFifoStart();
|
||||
device.ProcessFrame();
|
||||
device.Statistics.RecordFifoEnd();
|
||||
}
|
||||
|
||||
while (device.ConsumeFrameAvailable())
|
||||
{
|
||||
device.PresentFrame(() =>
|
||||
{
|
||||
VulkanRenderer? vk = device.Gpu.Renderer as VulkanRenderer;
|
||||
if (vk == null)
|
||||
{
|
||||
vk = (device.Gpu.Renderer as ThreadedRenderer)?.BaseRenderer as VulkanRenderer;
|
||||
}
|
||||
|
||||
if (vk != null)
|
||||
{
|
||||
var transform = vk.CurrentTransform;
|
||||
|
||||
setCurrentTransform(_window, (int)transform);
|
||||
}
|
||||
_swapBuffersCallback?.Invoke();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (device.Gpu.Renderer is ThreadedRenderer threaded)
|
||||
{
|
||||
threaded.FlushThreadedCommands();
|
||||
}
|
||||
|
||||
_gpuDoneEvent.Set();
|
||||
});
|
||||
}
|
||||
finally
|
||||
{
|
||||
device.Gpu.ShaderCacheStateChanged -= LoadProgressStateChangedHandler;
|
||||
device.Processes.ActiveApplication.DiskCacheLoadState.StateChanged -= LoadProgressStateChangedHandler;
|
||||
}
|
||||
}
|
||||
|
||||
private static void LoadProgressStateChangedHandler<T>(T state, int current, int total) where T : Enum
|
||||
{
|
||||
void SetInfo(string status, float value)
|
||||
{
|
||||
var ptr = Marshal.StringToHGlobalAnsi(status);
|
||||
|
||||
setProgressInfo(ptr, value);
|
||||
|
||||
Marshal.FreeHGlobal(ptr);
|
||||
}
|
||||
var status = $"{current} / {total}";
|
||||
var progress = current / (float)total;
|
||||
|
||||
switch (state)
|
||||
{
|
||||
case LoadState ptcState:
|
||||
if (float.IsNaN((progress)))
|
||||
progress = 0;
|
||||
|
||||
switch (ptcState)
|
||||
{
|
||||
case LoadState.Unloaded:
|
||||
case LoadState.Loading:
|
||||
SetInfo($"Loading PTC {status}", progress);
|
||||
break;
|
||||
case LoadState.Loaded:
|
||||
SetInfo($"PTC Loaded", -1);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case ShaderCacheState shaderCacheState:
|
||||
switch (shaderCacheState)
|
||||
{
|
||||
case ShaderCacheState.Start:
|
||||
case ShaderCacheState.Loading:
|
||||
SetInfo($"Compiling Shaders {status}", progress);
|
||||
break;
|
||||
case ShaderCacheState.Packaging:
|
||||
SetInfo($"Packaging Shaders {status}", progress);
|
||||
break;
|
||||
case ShaderCacheState.Loaded:
|
||||
SetInfo($"Shaders Loaded", -1);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentException($"Unknown Progress Handler type {typeof(T)}");
|
||||
}
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly(EntryPoint = "graphics_renderer_set_swap_buffer_callback")]
|
||||
public static void SetSwapBuffersCallbackNative(IntPtr swapBuffersCallback)
|
||||
{
|
||||
_swapBuffersCallback = Marshal.GetDelegateForFunctionPointer<SwapBuffersCallback>(swapBuffersCallback);
|
||||
}
|
||||
|
||||
public static void SetSwapBuffersCallback(SwapBuffersCallback swapBuffersCallback)
|
||||
{
|
||||
_swapBuffersCallback = swapBuffersCallback;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct GraphicsConfiguration
|
||||
{
|
||||
public float ResScale = 1f;
|
||||
public float MaxAnisotropy = -1;
|
||||
public bool FastGpuTime = true;
|
||||
public bool Fast2DCopy = true;
|
||||
public bool EnableMacroJit = false;
|
||||
public bool EnableMacroHLE = true;
|
||||
public bool EnableShaderCache = true;
|
||||
public bool EnableTextureRecompression = false;
|
||||
public BackendThreading BackendThreading = BackendThreading.Auto;
|
||||
public AspectRatio AspectRatio = AspectRatio.Fixed16x9;
|
||||
|
||||
public GraphicsConfiguration()
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public struct NativeGraphicsInterop
|
||||
{
|
||||
public IntPtr GlGetProcAddress;
|
||||
public IntPtr VkNativeContextLoader;
|
||||
public IntPtr VkCreateSurface;
|
||||
public IntPtr VkRequiredExtensions;
|
||||
public int VkRequiredExtensionsCount;
|
||||
}
|
||||
}
|
602
src/LibRyujinx/LibRyujinx.Input.cs
Normal file
602
src/LibRyujinx/LibRyujinx.Input.cs
Normal file
@ -0,0 +1,602 @@
|
||||
using DiscordRPC;
|
||||
using Ryujinx.Common.Configuration;
|
||||
using Ryujinx.Common.Configuration.Hid;
|
||||
using Ryujinx.Common.Configuration.Hid.Controller;
|
||||
using Ryujinx.Common.Configuration.Hid.Controller.Motion;
|
||||
using Ryujinx.Common.Logging;
|
||||
using Ryujinx.Common.Memory;
|
||||
using Ryujinx.Input;
|
||||
using Ryujinx.Input.HLE;
|
||||
using Ryujinx.Ui.Common.Configuration;
|
||||
using Silk.NET.Vulkan;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using System.Numerics;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using ConfigGamepadInputId = Ryujinx.Common.Configuration.Hid.Controller.GamepadInputId;
|
||||
using ConfigStickInputId = Ryujinx.Common.Configuration.Hid.Controller.StickInputId;
|
||||
using StickInputId = Ryujinx.Input.StickInputId;
|
||||
|
||||
namespace LibRyujinx
|
||||
{
|
||||
public static partial class LibRyujinx
|
||||
{
|
||||
private static VirtualGamepadDriver? _gamepadDriver;
|
||||
private static VirtualTouchScreen? _virtualTouchScreen;
|
||||
private static VirtualTouchScreenDriver? _touchScreenDriver;
|
||||
private static TouchScreenManager? _touchScreenManager;
|
||||
private static InputManager? _inputManager;
|
||||
private static NpadManager? _npadManager;
|
||||
private static InputConfig[] _configs;
|
||||
|
||||
public static void InitializeInput(int width, int height)
|
||||
{
|
||||
if(SwitchDevice!.InputManager != null)
|
||||
{
|
||||
throw new InvalidOperationException("Input is already initialized");
|
||||
}
|
||||
|
||||
_gamepadDriver = new VirtualGamepadDriver(4);
|
||||
_configs = new InputConfig[4];
|
||||
_virtualTouchScreen = new VirtualTouchScreen();
|
||||
_touchScreenDriver = new VirtualTouchScreenDriver(_virtualTouchScreen);
|
||||
_inputManager = new InputManager(null, _gamepadDriver);
|
||||
_inputManager.SetMouseDriver(_touchScreenDriver);
|
||||
_npadManager = _inputManager.CreateNpadManager();
|
||||
|
||||
SwitchDevice!.InputManager = _inputManager;
|
||||
|
||||
_touchScreenManager = _inputManager.CreateTouchScreenManager();
|
||||
_touchScreenManager.Initialize(SwitchDevice!.EmulationContext);
|
||||
|
||||
_npadManager.Initialize(SwitchDevice.EmulationContext, new List<InputConfig>(), false, false);
|
||||
|
||||
_virtualTouchScreen.ClientSize = new Size(width, height);
|
||||
}
|
||||
|
||||
public static void SetClientSize(int width, int height)
|
||||
{
|
||||
_virtualTouchScreen!.ClientSize = new Size(width, height);
|
||||
}
|
||||
|
||||
public static void SetTouchPoint(int x, int y)
|
||||
{
|
||||
_virtualTouchScreen?.SetPosition(x, y);
|
||||
}
|
||||
|
||||
public static void ReleaseTouchPoint()
|
||||
{
|
||||
_virtualTouchScreen?.ReleaseTouch();
|
||||
}
|
||||
|
||||
public static void SetButtonPressed(GamepadButtonInputId button, int id)
|
||||
{
|
||||
_gamepadDriver?.SetButtonPressed(button, id);
|
||||
}
|
||||
|
||||
public static void SetButtonReleased(GamepadButtonInputId button, int id)
|
||||
{
|
||||
_gamepadDriver?.SetButtonReleased(button, id);
|
||||
}
|
||||
|
||||
public static void SetAccelerometerData(Vector3 accel, int id)
|
||||
{
|
||||
_gamepadDriver?.SetAccelerometerData(accel, id);
|
||||
}
|
||||
|
||||
public static void SetGryoData(Vector3 gyro, int id)
|
||||
{
|
||||
_gamepadDriver?.SetGryoData(gyro, id);
|
||||
}
|
||||
|
||||
public static void SetStickAxis(StickInputId stick, Vector2 axes, int deviceId)
|
||||
{
|
||||
_gamepadDriver?.SetStickAxis(stick, axes, deviceId);
|
||||
}
|
||||
|
||||
public static int ConnectGamepad(int index)
|
||||
{
|
||||
var gamepad = _gamepadDriver?.GetGamepad(index);
|
||||
if (gamepad != null)
|
||||
{
|
||||
var config = CreateDefaultInputConfig();
|
||||
|
||||
config.Id = gamepad.Id;
|
||||
config.PlayerIndex = (PlayerIndex)index;
|
||||
|
||||
_configs[index] = config;
|
||||
}
|
||||
|
||||
_npadManager?.ReloadConfiguration(_configs.Where(x => x != null).ToList(), false, false);
|
||||
|
||||
return int.TryParse(gamepad?.Id, out var idInt) ? idInt : -1;
|
||||
}
|
||||
|
||||
private static InputConfig CreateDefaultInputConfig()
|
||||
{
|
||||
return new StandardControllerInputConfig
|
||||
{
|
||||
Version = InputConfig.CurrentVersion,
|
||||
Backend = InputBackendType.GamepadSDL2,
|
||||
Id = null,
|
||||
ControllerType = ControllerType.ProController,
|
||||
DeadzoneLeft = 0.1f,
|
||||
DeadzoneRight = 0.1f,
|
||||
RangeLeft = 1.0f,
|
||||
RangeRight = 1.0f,
|
||||
TriggerThreshold = 0.5f,
|
||||
LeftJoycon = new LeftJoyconCommonConfig<ConfigGamepadInputId>
|
||||
{
|
||||
DpadUp = ConfigGamepadInputId.DpadUp,
|
||||
DpadDown = ConfigGamepadInputId.DpadDown,
|
||||
DpadLeft = ConfigGamepadInputId.DpadLeft,
|
||||
DpadRight = ConfigGamepadInputId.DpadRight,
|
||||
ButtonMinus = ConfigGamepadInputId.Minus,
|
||||
ButtonL = ConfigGamepadInputId.LeftShoulder,
|
||||
ButtonZl = ConfigGamepadInputId.LeftTrigger,
|
||||
ButtonSl = ConfigGamepadInputId.Unbound,
|
||||
ButtonSr = ConfigGamepadInputId.Unbound,
|
||||
},
|
||||
|
||||
LeftJoyconStick = new JoyconConfigControllerStick<ConfigGamepadInputId, ConfigStickInputId>
|
||||
{
|
||||
Joystick = ConfigStickInputId.Left,
|
||||
StickButton = ConfigGamepadInputId.LeftStick,
|
||||
InvertStickX = false,
|
||||
InvertStickY = false,
|
||||
Rotate90CW = false,
|
||||
},
|
||||
|
||||
RightJoycon = new RightJoyconCommonConfig<ConfigGamepadInputId>
|
||||
{
|
||||
ButtonA = ConfigGamepadInputId.A,
|
||||
ButtonB = ConfigGamepadInputId.B,
|
||||
ButtonX = ConfigGamepadInputId.X,
|
||||
ButtonY = ConfigGamepadInputId.Y,
|
||||
ButtonPlus = ConfigGamepadInputId.Plus,
|
||||
ButtonR = ConfigGamepadInputId.RightShoulder,
|
||||
ButtonZr = ConfigGamepadInputId.RightTrigger,
|
||||
ButtonSl = ConfigGamepadInputId.Unbound,
|
||||
ButtonSr = ConfigGamepadInputId.Unbound,
|
||||
},
|
||||
|
||||
RightJoyconStick = new JoyconConfigControllerStick<ConfigGamepadInputId, ConfigStickInputId>
|
||||
{
|
||||
Joystick = ConfigStickInputId.Right,
|
||||
StickButton = ConfigGamepadInputId.RightStick,
|
||||
InvertStickX = false,
|
||||
InvertStickY = false,
|
||||
Rotate90CW = false,
|
||||
},
|
||||
|
||||
Motion = new StandardMotionConfigController
|
||||
{
|
||||
MotionBackend = MotionInputBackendType.GamepadDriver,
|
||||
EnableMotion = true,
|
||||
Sensitivity = 100,
|
||||
GyroDeadzone = 1,
|
||||
},
|
||||
Rumble = new RumbleConfigController
|
||||
{
|
||||
StrongRumble = 1f,
|
||||
WeakRumble = 1f,
|
||||
EnableRumble = false
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public static void UpdateInput()
|
||||
{
|
||||
_npadManager?.Update(GraphicsConfiguration.AspectRatio.ToFloat());
|
||||
|
||||
if(!_touchScreenManager!.Update(true, _virtualTouchScreen!.IsButtonPressed(MouseButton.Button1), GraphicsConfiguration.AspectRatio.ToFloat()))
|
||||
{
|
||||
SwitchDevice!.EmulationContext?.Hid.Touchscreen.Update();
|
||||
}
|
||||
}
|
||||
|
||||
// Native Methods
|
||||
|
||||
[UnmanagedCallersOnly(EntryPoint = "input_initialize")]
|
||||
public static void InitializeInputNative(int width, int height)
|
||||
{
|
||||
InitializeInput(width, height);
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly(EntryPoint = "input_set_client_size")]
|
||||
public static void SetClientSizeNative(int width, int height)
|
||||
{
|
||||
SetClientSize(width, height);
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly(EntryPoint = "input_set_touch_point")]
|
||||
public static void SetTouchPointNative(int x, int y)
|
||||
{
|
||||
SetTouchPoint(x, y);
|
||||
}
|
||||
|
||||
|
||||
[UnmanagedCallersOnly(EntryPoint = "input_release_touch_point")]
|
||||
public static void ReleaseTouchPointNative()
|
||||
{
|
||||
ReleaseTouchPoint();
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly(EntryPoint = "input_update")]
|
||||
public static void UpdateInputNative()
|
||||
{
|
||||
UpdateInput();
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly(EntryPoint = "input_set_button_pressed")]
|
||||
public static void SetButtonPressedNative(GamepadButtonInputId button, int id)
|
||||
{
|
||||
SetButtonPressed(button, id);
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly(EntryPoint = "input_set_button_released")]
|
||||
public static void SetButtonReleasedNative(GamepadButtonInputId button, int id)
|
||||
{
|
||||
SetButtonReleased(button, id);
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly(EntryPoint = "input_set_accelerometer_data")]
|
||||
public static void SetAccelerometerDataNative(Vector3 accel, int id)
|
||||
{
|
||||
SetAccelerometerData(accel, id);
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly(EntryPoint = "input_set_gyro_data")]
|
||||
public static void SetGryoDataNatuve(Vector3 gyro, int id)
|
||||
{
|
||||
SetGryoData(gyro, id);
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly(EntryPoint = "input_set_stick_axis")]
|
||||
public static void SetStickAxisNative(StickInputId stick, Vector2 axes, int id)
|
||||
{
|
||||
SetStickAxis(stick, axes, id);
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly(EntryPoint = "input_connect_gamepad")]
|
||||
public static IntPtr ConnectGamepadNative(int index)
|
||||
{
|
||||
return ConnectGamepad(index);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public class VirtualTouchScreen : IMouse
|
||||
{
|
||||
public Size ClientSize { get; set; }
|
||||
|
||||
public bool[] Buttons { get; }
|
||||
|
||||
public VirtualTouchScreen()
|
||||
{
|
||||
Buttons = new bool[2];
|
||||
}
|
||||
|
||||
public Vector2 CurrentPosition { get; private set; }
|
||||
public Vector2 Scroll { get; private set; }
|
||||
public string Id => "0";
|
||||
public string Name => "AvaloniaMouse";
|
||||
|
||||
public bool IsConnected => true;
|
||||
public GamepadFeaturesFlag Features => throw new NotImplementedException();
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public GamepadStateSnapshot GetMappedStateSnapshot()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public void SetPosition(int x, int y)
|
||||
{
|
||||
CurrentPosition = new Vector2(x, y);
|
||||
|
||||
Buttons[0] = true;
|
||||
}
|
||||
|
||||
public void ReleaseTouch()
|
||||
{
|
||||
Buttons[0] = false;
|
||||
}
|
||||
|
||||
public Vector3 GetMotionData(MotionInputId inputId)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Vector2 GetPosition()
|
||||
{
|
||||
return CurrentPosition;
|
||||
}
|
||||
|
||||
public Vector2 GetScroll()
|
||||
{
|
||||
return Scroll;
|
||||
}
|
||||
|
||||
public GamepadStateSnapshot GetStateSnapshot()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public (float, float) GetStick(Ryujinx.Input.StickInputId inputId)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public bool IsButtonPressed(MouseButton button)
|
||||
{
|
||||
return Buttons[0];
|
||||
}
|
||||
|
||||
public bool IsPressed(GamepadButtonInputId inputId)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public void Rumble(float lowFrequency, float highFrequency, uint durationMs)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public void SetConfiguration(InputConfig configuration)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public void SetTriggerThreshold(float triggerThreshold)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
||||
public class VirtualTouchScreenDriver : IGamepadDriver
|
||||
{
|
||||
private readonly VirtualTouchScreen _virtualTouchScreen;
|
||||
|
||||
public VirtualTouchScreenDriver(VirtualTouchScreen virtualTouchScreen)
|
||||
{
|
||||
_virtualTouchScreen = virtualTouchScreen;
|
||||
}
|
||||
|
||||
public string DriverName => "VirtualTouchDriver";
|
||||
|
||||
public ReadOnlySpan<string> GamepadsIds => new[] { "0" };
|
||||
|
||||
|
||||
public event Action<string> OnGamepadConnected
|
||||
{
|
||||
add { }
|
||||
remove { }
|
||||
}
|
||||
|
||||
public event Action<string> OnGamepadDisconnected
|
||||
{
|
||||
add { }
|
||||
remove { }
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public IGamepad GetGamepad(string id)
|
||||
{
|
||||
return _virtualTouchScreen;
|
||||
}
|
||||
}
|
||||
|
||||
public class VirtualGamepadDriver : IGamepadDriver
|
||||
{
|
||||
private readonly int _controllerCount;
|
||||
|
||||
public ReadOnlySpan<string> GamepadsIds => _gamePads.Keys.Select(x => x.ToString()).ToArray();
|
||||
|
||||
public string DriverName => "Virtual";
|
||||
|
||||
public event Action<string> OnGamepadConnected;
|
||||
public event Action<string> OnGamepadDisconnected;
|
||||
|
||||
private Dictionary<int, VirtualGamepad> _gamePads;
|
||||
|
||||
public VirtualGamepadDriver(int controllerCount)
|
||||
{
|
||||
_gamePads = new Dictionary<int, VirtualGamepad>();
|
||||
for (int joystickIndex = 0; joystickIndex < controllerCount; joystickIndex++)
|
||||
{
|
||||
HandleJoyStickConnected(joystickIndex);
|
||||
}
|
||||
|
||||
_controllerCount = controllerCount;
|
||||
}
|
||||
|
||||
private void HandleJoyStickConnected(int joystickDeviceId)
|
||||
{
|
||||
_gamePads[joystickDeviceId] = new VirtualGamepad(this, joystickDeviceId);
|
||||
OnGamepadConnected?.Invoke(joystickDeviceId.ToString());
|
||||
}
|
||||
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
// Simulate a full disconnect when disposing
|
||||
var ids = GamepadsIds;
|
||||
foreach (string id in ids)
|
||||
{
|
||||
OnGamepadDisconnected?.Invoke(id);
|
||||
}
|
||||
|
||||
_gamePads.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(true);
|
||||
}
|
||||
|
||||
public IGamepad GetGamepad(string id)
|
||||
{
|
||||
return _gamePads[int.Parse(id)];
|
||||
}
|
||||
|
||||
public IGamepad GetGamepad(int index)
|
||||
{
|
||||
return _gamePads[index];
|
||||
}
|
||||
|
||||
public void SetStickAxis(StickInputId stick, Vector2 axes, int deviceId)
|
||||
{
|
||||
if(_gamePads.TryGetValue(deviceId, out var gamePad))
|
||||
{
|
||||
gamePad.StickInputs[(int)stick] = axes;
|
||||
}
|
||||
}
|
||||
|
||||
public void SetButtonPressed(GamepadButtonInputId button, int deviceId)
|
||||
{
|
||||
if (_gamePads.TryGetValue(deviceId, out var gamePad))
|
||||
{
|
||||
gamePad.ButtonInputs[(int)button] = true;
|
||||
}
|
||||
}
|
||||
|
||||
public void SetButtonReleased(GamepadButtonInputId button, int deviceId)
|
||||
{
|
||||
if (_gamePads.TryGetValue(deviceId, out var gamePad))
|
||||
{
|
||||
gamePad.ButtonInputs[(int)button] = false;
|
||||
}
|
||||
}
|
||||
|
||||
public void SetAccelerometerData(Vector3 accel, int deviceId)
|
||||
{
|
||||
if (_gamePads.TryGetValue(deviceId, out var gamePad))
|
||||
{
|
||||
gamePad.Accelerometer = accel;
|
||||
}
|
||||
}
|
||||
|
||||
public void SetGryoData(Vector3 gyro, int deviceId)
|
||||
{
|
||||
if (_gamePads.TryGetValue(deviceId, out var gamePad))
|
||||
{
|
||||
gamePad.Gyro = gyro;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class VirtualGamepad : IGamepad
|
||||
{
|
||||
private readonly VirtualGamepadDriver _driver;
|
||||
|
||||
private bool[] _buttonInputs;
|
||||
|
||||
private Vector2[] _stickInputs;
|
||||
|
||||
public VirtualGamepad(VirtualGamepadDriver driver, int id)
|
||||
{
|
||||
_buttonInputs = new bool[(int)GamepadButtonInputId.Count];
|
||||
_stickInputs = new Vector2[(int)StickInputId.Count];
|
||||
_driver = driver;
|
||||
Id = id.ToString();
|
||||
IdInt = id;
|
||||
}
|
||||
|
||||
public void Dispose() { }
|
||||
|
||||
public GamepadFeaturesFlag Features { get; } = GamepadFeaturesFlag.Motion;
|
||||
public string Id { get; }
|
||||
|
||||
internal readonly int IdInt;
|
||||
|
||||
public string Name => Id;
|
||||
public bool IsConnected { get; }
|
||||
public Vector2[] StickInputs { get => _stickInputs; set => _stickInputs = value; }
|
||||
public bool[] ButtonInputs { get => _buttonInputs; set => _buttonInputs = value; }
|
||||
public Vector3 Accelerometer { get; internal set; }
|
||||
public Vector3 Gyro { get; internal set; }
|
||||
|
||||
public bool IsPressed(GamepadButtonInputId inputId)
|
||||
{
|
||||
return _buttonInputs[(int)inputId];
|
||||
}
|
||||
|
||||
public (float, float) GetStick(StickInputId inputId)
|
||||
{
|
||||
var v = _stickInputs[(int)inputId];
|
||||
|
||||
return (v.X, v.Y);
|
||||
}
|
||||
|
||||
public Vector3 GetMotionData(MotionInputId inputId)
|
||||
{
|
||||
if (inputId == MotionInputId.Accelerometer)
|
||||
return Accelerometer;
|
||||
else if (inputId == MotionInputId.Gyroscope)
|
||||
return RadToDegree(Gyro);
|
||||
return new Vector3();
|
||||
}
|
||||
|
||||
private static Vector3 RadToDegree(Vector3 rad)
|
||||
{
|
||||
return rad * (180 / MathF.PI);
|
||||
}
|
||||
|
||||
public void SetTriggerThreshold(float triggerThreshold)
|
||||
{
|
||||
//throw new System.NotImplementedException();
|
||||
}
|
||||
|
||||
public void SetConfiguration(InputConfig configuration)
|
||||
{
|
||||
//throw new System.NotImplementedException();
|
||||
}
|
||||
|
||||
public void Rumble(float lowFrequency, float highFrequency, uint durationMs)
|
||||
{
|
||||
//throw new System.NotImplementedException();
|
||||
}
|
||||
|
||||
public GamepadStateSnapshot GetMappedStateSnapshot()
|
||||
{
|
||||
GamepadStateSnapshot result = default;
|
||||
|
||||
foreach (var button in Enum.GetValues<GamepadButtonInputId>())
|
||||
{
|
||||
// Do not touch state of button already pressed
|
||||
if (button != GamepadButtonInputId.Count && !result.IsPressed(button))
|
||||
{
|
||||
result.SetPressed(button, IsPressed(button));
|
||||
}
|
||||
}
|
||||
|
||||
(float leftStickX, float leftStickY) = GetStick(StickInputId.Left);
|
||||
(float rightStickX, float rightStickY) = GetStick(StickInputId.Right);
|
||||
|
||||
result.SetStick(StickInputId.Left, leftStickX, leftStickY);
|
||||
result.SetStick(StickInputId.Right, rightStickX, rightStickY);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public GamepadStateSnapshot GetStateSnapshot()
|
||||
{
|
||||
return new GamepadStateSnapshot();
|
||||
}
|
||||
}
|
||||
}
|
82
src/LibRyujinx/LibRyujinx.User.cs
Normal file
82
src/LibRyujinx/LibRyujinx.User.cs
Normal file
@ -0,0 +1,82 @@
|
||||
using Ryujinx.HLE.HOS.Services.Account.Acc;
|
||||
using System;
|
||||
using System.Linq;
|
||||
|
||||
namespace LibRyujinx
|
||||
{
|
||||
public static partial class LibRyujinx
|
||||
{
|
||||
public static string GetOpenedUser()
|
||||
{
|
||||
var lastProfile = SwitchDevice?.AccountManager.LastOpenedUser;
|
||||
|
||||
return lastProfile?.UserId.ToString() ?? "";
|
||||
}
|
||||
|
||||
public static string GetUserPicture(string userId)
|
||||
{
|
||||
var uid = new UserId(userId);
|
||||
|
||||
var user = SwitchDevice?.AccountManager.GetAllUsers().FirstOrDefault(x => x.UserId == uid);
|
||||
|
||||
if (user == null)
|
||||
return "";
|
||||
|
||||
var pic = user.Image;
|
||||
|
||||
return pic != null ? Convert.ToBase64String(pic) : "";
|
||||
}
|
||||
|
||||
public static void SetUserPicture(string userId, string picture)
|
||||
{
|
||||
var uid = new UserId(userId);
|
||||
|
||||
SwitchDevice?.AccountManager.SetUserImage(uid, Convert.FromBase64String(picture));
|
||||
}
|
||||
|
||||
public static string GetUserName(string userId)
|
||||
{
|
||||
var uid = new UserId(userId);
|
||||
|
||||
var user = SwitchDevice?.AccountManager.GetAllUsers().FirstOrDefault(x => x.UserId == uid);
|
||||
|
||||
return user?.Name ?? "";
|
||||
}
|
||||
|
||||
public static void SetUserName(string userId, string name)
|
||||
{
|
||||
var uid = new UserId(userId);
|
||||
|
||||
SwitchDevice?.AccountManager.SetUserName(uid, name);
|
||||
}
|
||||
|
||||
public static string[] GetAllUsers()
|
||||
{
|
||||
return SwitchDevice?.AccountManager.GetAllUsers().Select(x => x.UserId.ToString()).ToArray() ??
|
||||
Array.Empty<string>();
|
||||
}
|
||||
|
||||
public static void AddUser(string userName, string picture)
|
||||
{
|
||||
SwitchDevice?.AccountManager.AddUser(userName, Convert.FromBase64String(picture));
|
||||
}
|
||||
|
||||
public static void DeleteUser(string userId)
|
||||
{
|
||||
var uid = new UserId(userId);
|
||||
SwitchDevice?.AccountManager.DeleteUser(uid);
|
||||
}
|
||||
|
||||
public static void OpenUser(string userId)
|
||||
{
|
||||
var uid = new UserId(userId);
|
||||
SwitchDevice?.AccountManager.OpenUser(uid);
|
||||
}
|
||||
|
||||
public static void CloseUser(string userId)
|
||||
{
|
||||
var uid = new UserId(userId);
|
||||
SwitchDevice?.AccountManager.CloseUser(uid);
|
||||
}
|
||||
}
|
||||
}
|
883
src/LibRyujinx/LibRyujinx.cs
Normal file
883
src/LibRyujinx/LibRyujinx.cs
Normal file
@ -0,0 +1,883 @@
|
||||
// State class for the library
|
||||
using Ryujinx.HLE.FileSystem;
|
||||
using Ryujinx.HLE.HOS.Services.Account.Acc;
|
||||
using Ryujinx.HLE.HOS;
|
||||
using Ryujinx.Input.HLE;
|
||||
using Ryujinx.HLE;
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using Ryujinx.Common.Configuration;
|
||||
using LibHac.Tools.FsSystem;
|
||||
using Ryujinx.Graphics.GAL.Multithreading;
|
||||
using Ryujinx.Audio.Backends.Dummy;
|
||||
using Ryujinx.HLE.HOS.SystemState;
|
||||
using Ryujinx.Ui.Common.Configuration;
|
||||
using Ryujinx.Common.Logging;
|
||||
using Ryujinx.Audio.Integration;
|
||||
using Ryujinx.Audio.Backends.SDL2;
|
||||
using System.IO;
|
||||
using LibHac.Common.Keys;
|
||||
using LibHac.Common;
|
||||
using LibHac.Ns;
|
||||
using LibHac.Tools.Fs;
|
||||
using LibHac.Tools.FsSystem.NcaUtils;
|
||||
using LibHac.Fs.Fsa;
|
||||
using LibHac.FsSystem;
|
||||
using LibHac.Fs;
|
||||
using Path = System.IO.Path;
|
||||
using LibHac;
|
||||
using OpenTK.Audio.OpenAL;
|
||||
using Ryujinx.Common.Configuration.Multiplayer;
|
||||
using Ryujinx.HLE.Loaders.Npdm;
|
||||
using Ryujinx.Common.Utilities;
|
||||
using System.Globalization;
|
||||
using Ryujinx.Ui.Common.Configuration.System;
|
||||
using Ryujinx.Common.Logging.Targets;
|
||||
using System.Collections.Generic;
|
||||
using LibHac.Bcat;
|
||||
using Ryujinx.Ui.App.Common;
|
||||
using System.Text;
|
||||
using Ryujinx.HLE.Ui;
|
||||
using LibRyujinx.Android;
|
||||
|
||||
namespace LibRyujinx
|
||||
{
|
||||
public static partial class LibRyujinx
|
||||
{
|
||||
internal static IHardwareDeviceDriver AudioDriver { get; set; } = new DummyHardwareDeviceDriver();
|
||||
|
||||
private static readonly TitleUpdateMetadataJsonSerializerContext _titleSerializerContext = new(JsonHelper.GetDefaultSerializerOptions());
|
||||
public static SwitchDevice? SwitchDevice { get; set; }
|
||||
|
||||
[UnmanagedCallersOnly(EntryPoint = "initialize")]
|
||||
public static bool Initialize(IntPtr basePathPtr)
|
||||
{
|
||||
var path = Marshal.PtrToStringAnsi(basePathPtr);
|
||||
|
||||
var res = Initialize(path);
|
||||
|
||||
InitializeAudio();
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
public static bool Initialize(string? basePath)
|
||||
{
|
||||
if (SwitchDevice != null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
AppDataManager.Initialize(basePath);
|
||||
|
||||
ConfigurationState.Initialize();
|
||||
LoggerModule.Initialize();
|
||||
|
||||
Logger.AddTarget(new AsyncLogTargetWrapper(
|
||||
new FileLogTarget(AppDataManager.BaseDirPath, "file"),
|
||||
1000,
|
||||
AsyncLogTargetOverflowAction.Block
|
||||
));
|
||||
|
||||
Logger.Notice.Print(LogClass.Application, "Initializing...");
|
||||
Logger.Notice.Print(LogClass.Application, $"Using base path: {AppDataManager.BaseDirPath}");
|
||||
|
||||
SwitchDevice = new SwitchDevice();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine(ex);
|
||||
return false;
|
||||
}
|
||||
|
||||
OpenALLibraryNameContainer.OverridePath = "libopenal.so";
|
||||
|
||||
Logger.Notice.Print(LogClass.Application, "RyujinxAndroid is ready!");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static void InitializeAudio()
|
||||
{
|
||||
AudioDriver = new SDL2HardwareDeviceDriver();
|
||||
}
|
||||
|
||||
public static GameStats GetGameStats()
|
||||
{
|
||||
if (SwitchDevice?.EmulationContext == null)
|
||||
return new GameStats();
|
||||
|
||||
var context = SwitchDevice.EmulationContext;
|
||||
|
||||
return new GameStats
|
||||
{
|
||||
Fifo = context.Statistics.GetFifoPercent(),
|
||||
GameFps = context.Statistics.GetGameFrameRate(),
|
||||
GameTime = context.Statistics.GetGameFrameTime()
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
public static GameInfo? GetGameInfo(string? file)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(file))
|
||||
{
|
||||
return new GameInfo();
|
||||
}
|
||||
|
||||
Logger.Info?.Print(LogClass.Application, $"Getting game info for file: {file}");
|
||||
|
||||
using var stream = File.Open(file, FileMode.Open);
|
||||
|
||||
return GetGameInfo(stream, new FileInfo(file).Extension.Remove('.'));
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly(EntryPoint = "get_game_info")]
|
||||
public static GameInfoNative GetGameInfoNative(int descriptor, IntPtr extensionPtr)
|
||||
{
|
||||
var extension = Marshal.PtrToStringAnsi(extensionPtr);
|
||||
var stream = OpenFile(descriptor);
|
||||
|
||||
var gameInfo = GetGameInfo(stream, extension);
|
||||
|
||||
return new GameInfoNative(0, gameInfo.TitleName, 0, gameInfo.Developer, 0);
|
||||
}
|
||||
|
||||
public static GameInfo? GetGameInfo(Stream gameStream, string extension)
|
||||
{
|
||||
if (SwitchDevice == null)
|
||||
{
|
||||
Logger.Error?.Print(LogClass.Application, "SwitchDevice is not initialized.");
|
||||
return null;
|
||||
}
|
||||
|
||||
var gameInfo = new GameInfo
|
||||
{
|
||||
FileSize = gameStream.Length * 0.000000000931,
|
||||
TitleName = "Unknown",
|
||||
TitleId = "0000000000000000",
|
||||
Developer = "Unknown",
|
||||
Version = "0",
|
||||
Icon = null
|
||||
};
|
||||
|
||||
const Language TitleLanguage = Language.AmericanEnglish;
|
||||
|
||||
BlitStruct<ApplicationControlProperty> controlHolder = new(1);
|
||||
|
||||
try
|
||||
{
|
||||
try
|
||||
{
|
||||
if (extension == "nsp" || extension == "pfs0" || extension == "xci")
|
||||
{
|
||||
IFileSystem pfs;
|
||||
|
||||
bool isExeFs = false;
|
||||
|
||||
if (extension == "xci")
|
||||
{
|
||||
Xci xci = new(SwitchDevice.VirtualFileSystem.KeySet, gameStream.AsStorage());
|
||||
|
||||
pfs = xci.OpenPartition(XciPartitionType.Secure);
|
||||
}
|
||||
else
|
||||
{
|
||||
var pfsTemp = new PartitionFileSystem();
|
||||
pfsTemp.Initialize(gameStream.AsStorage()).ThrowIfFailure();
|
||||
pfs = pfsTemp;
|
||||
|
||||
// If the NSP doesn't have a main NCA, decrement the number of applications found and then continue to the next application.
|
||||
bool hasMainNca = false;
|
||||
|
||||
foreach (DirectoryEntryEx fileEntry in pfs.EnumerateEntries("/", "*"))
|
||||
{
|
||||
if (Path.GetExtension(fileEntry.FullPath).ToLower() == ".nca")
|
||||
{
|
||||
using UniqueRef<IFile> ncaFile = new();
|
||||
|
||||
pfs.OpenFile(ref ncaFile.Ref, fileEntry.FullPath.ToU8Span(), OpenMode.Read).ThrowIfFailure();
|
||||
|
||||
Nca nca = new(SwitchDevice.VirtualFileSystem.KeySet, ncaFile.Get.AsStorage());
|
||||
int dataIndex = Nca.GetSectionIndexFromType(NcaSectionType.Data, NcaContentType.Program);
|
||||
|
||||
// Some main NCAs don't have a data partition, so check if the partition exists before opening it
|
||||
if (nca.Header.ContentType == NcaContentType.Program && !(nca.SectionExists(NcaSectionType.Data) && nca.Header.GetFsHeader(dataIndex).IsPatchSection()))
|
||||
{
|
||||
hasMainNca = true;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (Path.GetFileNameWithoutExtension(fileEntry.FullPath) == "main")
|
||||
{
|
||||
isExeFs = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!hasMainNca && !isExeFs)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
if (isExeFs)
|
||||
{
|
||||
using UniqueRef<IFile> npdmFile = new();
|
||||
|
||||
Result result = pfs.OpenFile(ref npdmFile.Ref, "/main.npdm".ToU8Span(), OpenMode.Read);
|
||||
|
||||
if (ResultFs.PathNotFound.Includes(result))
|
||||
{
|
||||
Npdm npdm = new(npdmFile.Get.AsStream());
|
||||
|
||||
gameInfo.TitleName = npdm.TitleName;
|
||||
gameInfo.TitleId = npdm.Aci0.TitleId.ToString("x16");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
GetControlFsAndTitleId(pfs, out IFileSystem? controlFs, out string? id);
|
||||
|
||||
gameInfo.TitleId = id;
|
||||
|
||||
if (controlFs == null)
|
||||
{
|
||||
Logger.Error?.Print(LogClass.Application, $"No control FS was returned. Unable to process game any further: {gameInfo.TitleName}");
|
||||
return null;
|
||||
}
|
||||
|
||||
// Check if there is an update available.
|
||||
if (IsUpdateApplied(gameInfo.TitleId, out IFileSystem? updatedControlFs))
|
||||
{
|
||||
// Replace the original ControlFs by the updated one.
|
||||
controlFs = updatedControlFs;
|
||||
}
|
||||
|
||||
ReadControlData(controlFs, controlHolder.ByteSpan);
|
||||
|
||||
GetGameInformation(ref controlHolder.Value, out gameInfo.TitleName, out _, out gameInfo.Developer, out gameInfo.Version);
|
||||
|
||||
// Read the icon from the ControlFS and store it as a byte array
|
||||
try
|
||||
{
|
||||
using UniqueRef<IFile> icon = new();
|
||||
|
||||
controlFs?.OpenFile(ref icon.Ref, $"/icon_{TitleLanguage}.dat".ToU8Span(), OpenMode.Read).ThrowIfFailure();
|
||||
|
||||
using MemoryStream stream = new();
|
||||
|
||||
icon.Get.AsStream().CopyTo(stream);
|
||||
gameInfo.Icon = stream.ToArray();
|
||||
}
|
||||
catch (HorizonResultException)
|
||||
{
|
||||
foreach (DirectoryEntryEx entry in controlFs.EnumerateEntries("/", "*"))
|
||||
{
|
||||
if (entry.Name == "control.nacp")
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
using var icon = new UniqueRef<IFile>();
|
||||
|
||||
controlFs?.OpenFile(ref icon.Ref, entry.FullPath.ToU8Span(), OpenMode.Read).ThrowIfFailure();
|
||||
|
||||
using MemoryStream stream = new();
|
||||
|
||||
icon.Get.AsStream().CopyTo(stream);
|
||||
gameInfo.Icon = stream.ToArray();
|
||||
|
||||
if (gameInfo.Icon != null)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (extension == "nro")
|
||||
{
|
||||
BinaryReader reader = new(gameStream);
|
||||
|
||||
byte[] Read(long position, int size)
|
||||
{
|
||||
gameStream.Seek(position, SeekOrigin.Begin);
|
||||
|
||||
return reader.ReadBytes(size);
|
||||
}
|
||||
|
||||
gameStream.Seek(24, SeekOrigin.Begin);
|
||||
|
||||
int assetOffset = reader.ReadInt32();
|
||||
|
||||
if (Encoding.ASCII.GetString(Read(assetOffset, 4)) == "ASET")
|
||||
{
|
||||
byte[] iconSectionInfo = Read(assetOffset + 8, 0x10);
|
||||
|
||||
long iconOffset = BitConverter.ToInt64(iconSectionInfo, 0);
|
||||
long iconSize = BitConverter.ToInt64(iconSectionInfo, 8);
|
||||
|
||||
ulong nacpOffset = reader.ReadUInt64();
|
||||
ulong nacpSize = reader.ReadUInt64();
|
||||
|
||||
// Reads and stores game icon as byte array
|
||||
if (iconSize > 0)
|
||||
{
|
||||
gameInfo.Icon = Read(assetOffset + iconOffset, (int)iconSize);
|
||||
}
|
||||
|
||||
// Read the NACP data
|
||||
Read(assetOffset + (int)nacpOffset, (int)nacpSize).AsSpan().CopyTo(controlHolder.ByteSpan);
|
||||
|
||||
GetGameInformation(ref controlHolder.Value, out gameInfo.TitleName, out _, out gameInfo.Developer, out gameInfo.Version);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (MissingKeyException exception)
|
||||
{
|
||||
Logger.Warning?.Print(LogClass.Application, $"Your key set is missing a key with the name: {exception.Name}");
|
||||
}
|
||||
catch (InvalidDataException exception)
|
||||
{
|
||||
Logger.Warning?.Print(LogClass.Application, $"The header key is incorrect or missing and therefore the NCA header content type check has failed. {exception}");
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
Logger.Warning?.Print(LogClass.Application, $"The gameStream encountered was not of a valid type. Error: {exception}");
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
catch (IOException exception)
|
||||
{
|
||||
Logger.Warning?.Print(LogClass.Application, exception.Message);
|
||||
}
|
||||
|
||||
void ReadControlData(IFileSystem? controlFs, Span<byte> outProperty)
|
||||
{
|
||||
using UniqueRef<IFile> controlFile = new();
|
||||
|
||||
controlFs?.OpenFile(ref controlFile.Ref, "/control.nacp".ToU8Span(), OpenMode.Read).ThrowIfFailure();
|
||||
controlFile.Get.Read(out _, 0, outProperty, ReadOption.None).ThrowIfFailure();
|
||||
}
|
||||
|
||||
void GetGameInformation(ref ApplicationControlProperty controlData, out string? titleName, out string titleId, out string? publisher, out string? version)
|
||||
{
|
||||
_ = Enum.TryParse(TitleLanguage.ToString(), out TitleLanguage desiredTitleLanguage);
|
||||
|
||||
if (controlData.Title.ItemsRo.Length > (int)desiredTitleLanguage)
|
||||
{
|
||||
titleName = controlData.Title[(int)desiredTitleLanguage].NameString.ToString();
|
||||
publisher = controlData.Title[(int)desiredTitleLanguage].PublisherString.ToString();
|
||||
}
|
||||
else
|
||||
{
|
||||
titleName = null;
|
||||
publisher = null;
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(titleName))
|
||||
{
|
||||
foreach (ref readonly var controlTitle in controlData.Title.ItemsRo)
|
||||
{
|
||||
if (!controlTitle.NameString.IsEmpty())
|
||||
{
|
||||
titleName = controlTitle.NameString.ToString();
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(publisher))
|
||||
{
|
||||
foreach (ref readonly var controlTitle in controlData.Title.ItemsRo)
|
||||
{
|
||||
if (!controlTitle.PublisherString.IsEmpty())
|
||||
{
|
||||
publisher = controlTitle.PublisherString.ToString();
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (controlData.PresenceGroupId != 0)
|
||||
{
|
||||
titleId = controlData.PresenceGroupId.ToString("x16");
|
||||
}
|
||||
else if (controlData.SaveDataOwnerId != 0)
|
||||
{
|
||||
titleId = controlData.SaveDataOwnerId.ToString();
|
||||
}
|
||||
else if (controlData.AddOnContentBaseId != 0)
|
||||
{
|
||||
titleId = (controlData.AddOnContentBaseId - 0x1000).ToString("x16");
|
||||
}
|
||||
else
|
||||
{
|
||||
titleId = "0000000000000000";
|
||||
}
|
||||
|
||||
version = controlData.DisplayVersionString.ToString();
|
||||
}
|
||||
|
||||
void GetControlFsAndTitleId(IFileSystem pfs, out IFileSystem? controlFs, out string? titleId)
|
||||
{
|
||||
if (SwitchDevice == null)
|
||||
{
|
||||
Logger.Error?.Print(LogClass.Application, "SwitchDevice is not initialized.");
|
||||
|
||||
controlFs = null;
|
||||
titleId = null;
|
||||
return;
|
||||
}
|
||||
(_, _, Nca? controlNca) = GetGameData(SwitchDevice.VirtualFileSystem, pfs, 0);
|
||||
|
||||
if (controlNca == null)
|
||||
{
|
||||
Logger.Warning?.Print(LogClass.Application, "Control NCA is null. Unable to load control FS.");
|
||||
}
|
||||
|
||||
// Return the ControlFS
|
||||
controlFs = controlNca?.OpenFileSystem(NcaSectionType.Data, IntegrityCheckLevel.None);
|
||||
titleId = controlNca?.Header.TitleId.ToString("x16");
|
||||
}
|
||||
|
||||
(Nca? mainNca, Nca? patchNca, Nca? controlNca) GetGameData(VirtualFileSystem fileSystem, IFileSystem pfs, int programIndex)
|
||||
{
|
||||
Nca? mainNca = null;
|
||||
Nca? patchNca = null;
|
||||
Nca? controlNca = null;
|
||||
|
||||
fileSystem.ImportTickets(pfs);
|
||||
|
||||
foreach (DirectoryEntryEx fileEntry in pfs.EnumerateEntries("/", "*.nca"))
|
||||
{
|
||||
using var ncaFile = new UniqueRef<IFile>();
|
||||
|
||||
Logger.Info?.Print(LogClass.Application, $"Loading file from PFS: {fileEntry.FullPath}");
|
||||
|
||||
pfs.OpenFile(ref ncaFile.Ref, fileEntry.FullPath.ToU8Span(), OpenMode.Read).ThrowIfFailure();
|
||||
|
||||
Nca nca = new(fileSystem.KeySet, ncaFile.Release().AsStorage());
|
||||
|
||||
int ncaProgramIndex = (int)(nca.Header.TitleId & 0xF);
|
||||
|
||||
if (ncaProgramIndex != programIndex)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (nca.Header.ContentType == NcaContentType.Program)
|
||||
{
|
||||
int dataIndex = Nca.GetSectionIndexFromType(NcaSectionType.Data, NcaContentType.Program);
|
||||
|
||||
if (nca.SectionExists(NcaSectionType.Data) && nca.Header.GetFsHeader(dataIndex).IsPatchSection())
|
||||
{
|
||||
patchNca = nca;
|
||||
}
|
||||
else
|
||||
{
|
||||
mainNca = nca;
|
||||
}
|
||||
}
|
||||
else if (nca.Header.ContentType == NcaContentType.Control)
|
||||
{
|
||||
controlNca = nca;
|
||||
}
|
||||
}
|
||||
|
||||
return (mainNca, patchNca, controlNca);
|
||||
}
|
||||
|
||||
bool IsUpdateApplied(string? titleId, out IFileSystem? updatedControlFs)
|
||||
{
|
||||
updatedControlFs = null;
|
||||
|
||||
string? updatePath = "(unknown)";
|
||||
|
||||
if (SwitchDevice?.VirtualFileSystem == null)
|
||||
{
|
||||
Logger.Error?.Print(LogClass.Application, "SwitchDevice was not initialized.");
|
||||
return false;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
(Nca? patchNca, Nca? controlNca) = GetGameUpdateData(SwitchDevice.VirtualFileSystem, titleId, 0, out updatePath);
|
||||
|
||||
if (patchNca != null && controlNca != null)
|
||||
{
|
||||
updatedControlFs = controlNca.OpenFileSystem(NcaSectionType.Data, IntegrityCheckLevel.None);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
catch (InvalidDataException)
|
||||
{
|
||||
Logger.Warning?.Print(LogClass.Application, $"The header key is incorrect or missing and therefore the NCA header content type check has failed. Errored File: {updatePath}");
|
||||
}
|
||||
catch (MissingKeyException exception)
|
||||
{
|
||||
Logger.Warning?.Print(LogClass.Application, $"Your key set is missing a key with the name: {exception.Name}. Errored File: {updatePath}");
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
(Nca? patch, Nca? control) GetGameUpdateData(VirtualFileSystem fileSystem, string? titleId, int programIndex, out string? updatePath)
|
||||
{
|
||||
updatePath = null;
|
||||
|
||||
if (ulong.TryParse(titleId, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out ulong titleIdBase))
|
||||
{
|
||||
// Clear the program index part.
|
||||
titleIdBase &= ~0xFUL;
|
||||
|
||||
// Load update information if exists.
|
||||
string titleUpdateMetadataPath = Path.Combine(AppDataManager.GamesDirPath, titleIdBase.ToString("x16"), "updates.json");
|
||||
|
||||
if (File.Exists(titleUpdateMetadataPath))
|
||||
{
|
||||
updatePath = JsonHelper.DeserializeFromFile(titleUpdateMetadataPath, _titleSerializerContext.TitleUpdateMetadata).Selected;
|
||||
|
||||
if (File.Exists(updatePath))
|
||||
{
|
||||
FileStream file = new(updatePath, FileMode.Open, FileAccess.Read);
|
||||
PartitionFileSystem nsp = new();
|
||||
nsp.Initialize(file.AsStorage()).ThrowIfFailure();
|
||||
|
||||
return GetGameUpdateDataFromPartition(fileSystem, nsp, titleIdBase.ToString("x16"), programIndex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (null, null);
|
||||
}
|
||||
|
||||
(Nca? patchNca, Nca? controlNca) GetGameUpdateDataFromPartition(VirtualFileSystem fileSystem, PartitionFileSystem pfs, string titleId, int programIndex)
|
||||
{
|
||||
Nca? patchNca = null;
|
||||
Nca? controlNca = null;
|
||||
|
||||
fileSystem.ImportTickets(pfs);
|
||||
|
||||
foreach (DirectoryEntryEx fileEntry in pfs.EnumerateEntries("/", "*.nca"))
|
||||
{
|
||||
using var ncaFile = new UniqueRef<IFile>();
|
||||
|
||||
pfs.OpenFile(ref ncaFile.Ref, fileEntry.FullPath.ToU8Span(), OpenMode.Read).ThrowIfFailure();
|
||||
|
||||
Nca nca = new(fileSystem.KeySet, ncaFile.Release().AsStorage());
|
||||
|
||||
int ncaProgramIndex = (int)(nca.Header.TitleId & 0xF);
|
||||
|
||||
if (ncaProgramIndex != programIndex)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($"{nca.Header.TitleId.ToString("x16")[..^3]}000" != titleId)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (nca.Header.ContentType == NcaContentType.Program)
|
||||
{
|
||||
patchNca = nca;
|
||||
}
|
||||
else if (nca.Header.ContentType == NcaContentType.Control)
|
||||
{
|
||||
controlNca = nca;
|
||||
}
|
||||
}
|
||||
|
||||
return (patchNca, controlNca);
|
||||
}
|
||||
|
||||
return gameInfo;
|
||||
}
|
||||
|
||||
public static string GetDlcTitleId(string path, string ncaPath)
|
||||
{
|
||||
if (File.Exists(path))
|
||||
{
|
||||
using FileStream containerFile = File.OpenRead(path);
|
||||
|
||||
PartitionFileSystem partitionFileSystem = new();
|
||||
partitionFileSystem.Initialize(containerFile.AsStorage()).ThrowIfFailure();
|
||||
|
||||
SwitchDevice.VirtualFileSystem.ImportTickets(partitionFileSystem);
|
||||
|
||||
using UniqueRef<IFile> ncaFile = new();
|
||||
|
||||
partitionFileSystem.OpenFile(ref ncaFile.Ref, ncaPath.ToU8Span(), OpenMode.Read).ThrowIfFailure();
|
||||
|
||||
Nca nca = TryOpenNca(ncaFile.Get.AsStorage(), ncaPath);
|
||||
if (nca != null)
|
||||
{
|
||||
return nca.Header.TitleId.ToString("X16");
|
||||
}
|
||||
}
|
||||
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
|
||||
private static Nca TryOpenNca(IStorage ncaStorage, string containerPath)
|
||||
{
|
||||
try
|
||||
{
|
||||
return new Nca(SwitchDevice.VirtualFileSystem.KeySet, ncaStorage);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static List<string> GetDlcContentList(string path, ulong titleId)
|
||||
{
|
||||
if (!File.Exists(path))
|
||||
return new List<string>();
|
||||
|
||||
using FileStream containerFile = File.OpenRead(path);
|
||||
|
||||
PartitionFileSystem partitionFileSystem = new();
|
||||
partitionFileSystem.Initialize(containerFile.AsStorage()).ThrowIfFailure();
|
||||
|
||||
SwitchDevice.VirtualFileSystem.ImportTickets(partitionFileSystem);
|
||||
List<string> paths = new List<string>();
|
||||
|
||||
foreach (DirectoryEntryEx fileEntry in partitionFileSystem.EnumerateEntries("/", "*.nca"))
|
||||
{
|
||||
using var ncaFile = new UniqueRef<IFile>();
|
||||
|
||||
partitionFileSystem.OpenFile(ref ncaFile.Ref, fileEntry.FullPath.ToU8Span(), OpenMode.Read).ThrowIfFailure();
|
||||
|
||||
Nca nca = TryOpenNca(ncaFile.Get.AsStorage(), path);
|
||||
if (nca == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (nca.Header.ContentType == NcaContentType.PublicData)
|
||||
{
|
||||
if ((nca.Header.TitleId & 0xFFFFFFFFFFFFE000) != titleId)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
paths.Add(fileEntry.FullPath);
|
||||
}
|
||||
}
|
||||
|
||||
return paths;
|
||||
}
|
||||
|
||||
public static void SetupUiHandler()
|
||||
{
|
||||
if (SwitchDevice is { } switchDevice)
|
||||
{
|
||||
switchDevice.HostUiHandler = new AndroidUiHandler();
|
||||
}
|
||||
}
|
||||
|
||||
public static void WaitUiHandler()
|
||||
{
|
||||
if (SwitchDevice?.HostUiHandler is AndroidUiHandler uiHandler)
|
||||
{
|
||||
uiHandler.Wait();
|
||||
}
|
||||
}
|
||||
|
||||
public static void StopUiHandlerWait()
|
||||
{
|
||||
if (SwitchDevice?.HostUiHandler is AndroidUiHandler uiHandler)
|
||||
{
|
||||
uiHandler.Set();
|
||||
}
|
||||
}
|
||||
|
||||
public static void SetUiHandlerResponse(bool isOkPressed, long input)
|
||||
{
|
||||
if (SwitchDevice?.HostUiHandler is AndroidUiHandler uiHandler)
|
||||
{
|
||||
uiHandler.SetResponse(isOkPressed, input);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class SwitchDevice : IDisposable
|
||||
{
|
||||
private readonly SystemVersion _firmwareVersion;
|
||||
public VirtualFileSystem VirtualFileSystem { get; set; }
|
||||
public ContentManager ContentManager { get; set; }
|
||||
public AccountManager AccountManager { get; set; }
|
||||
public LibHacHorizonManager LibHacHorizonManager { get; set; }
|
||||
public UserChannelPersistence UserChannelPersistence { get; set; }
|
||||
public InputManager? InputManager { get; set; }
|
||||
public Switch? EmulationContext { get; set; }
|
||||
public IHostUiHandler? HostUiHandler { get; set; }
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
GC.SuppressFinalize(this);
|
||||
|
||||
VirtualFileSystem.Dispose();
|
||||
InputManager?.Dispose();
|
||||
EmulationContext?.Dispose();
|
||||
}
|
||||
|
||||
public SwitchDevice()
|
||||
{
|
||||
VirtualFileSystem = VirtualFileSystem.CreateInstance();
|
||||
LibHacHorizonManager = new LibHacHorizonManager();
|
||||
|
||||
LibHacHorizonManager.InitializeFsServer(VirtualFileSystem);
|
||||
LibHacHorizonManager.InitializeArpServer();
|
||||
LibHacHorizonManager.InitializeBcatServer();
|
||||
LibHacHorizonManager.InitializeSystemClients();
|
||||
|
||||
ContentManager = new ContentManager(VirtualFileSystem);
|
||||
AccountManager = new AccountManager(LibHacHorizonManager.RyujinxClient);
|
||||
UserChannelPersistence = new UserChannelPersistence();
|
||||
|
||||
_firmwareVersion = ContentManager.GetCurrentFirmwareVersion();
|
||||
|
||||
if (_firmwareVersion != null)
|
||||
{
|
||||
Logger.Notice.Print(LogClass.Application, $"System Firmware Version: {_firmwareVersion.VersionString}");
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger.Notice.Print(LogClass.Application, $"System Firmware not installed");
|
||||
}
|
||||
}
|
||||
|
||||
public bool InitializeContext(bool isHostMapped,
|
||||
bool useNce,
|
||||
SystemLanguage systemLanguage,
|
||||
RegionCode regionCode,
|
||||
bool enableVsync,
|
||||
bool enableDockedMode,
|
||||
bool enablePtc,
|
||||
bool enableInternetAccess,
|
||||
string? timeZone,
|
||||
bool ignoreMissingServices)
|
||||
{
|
||||
if (LibRyujinx.Renderer == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var renderer = LibRyujinx.Renderer;
|
||||
BackendThreading threadingMode = LibRyujinx.GraphicsConfiguration.BackendThreading;
|
||||
|
||||
bool threadedGAL = threadingMode == BackendThreading.On || (threadingMode == BackendThreading.Auto && renderer.PreferThreading);
|
||||
|
||||
if (threadedGAL)
|
||||
{
|
||||
renderer = new ThreadedRenderer(renderer);
|
||||
}
|
||||
|
||||
HLEConfiguration configuration = new HLEConfiguration(VirtualFileSystem,
|
||||
LibHacHorizonManager,
|
||||
ContentManager,
|
||||
AccountManager,
|
||||
UserChannelPersistence,
|
||||
renderer,
|
||||
LibRyujinx.AudioDriver, //Audio
|
||||
MemoryConfiguration.MemoryConfiguration4GiB,
|
||||
HostUiHandler,
|
||||
systemLanguage,
|
||||
regionCode,
|
||||
enableVsync,
|
||||
enableDockedMode,
|
||||
enablePtc,
|
||||
enableInternetAccess,
|
||||
IntegrityCheckLevel.None,
|
||||
0,
|
||||
0,
|
||||
timeZone,
|
||||
isHostMapped ? MemoryManagerMode.HostMappedUnsafe : MemoryManagerMode.SoftwarePageTable,
|
||||
ignoreMissingServices,
|
||||
LibRyujinx.GraphicsConfiguration.AspectRatio,
|
||||
100,
|
||||
useNce,
|
||||
"",
|
||||
MultiplayerMode.Disabled);
|
||||
|
||||
EmulationContext = new Switch(configuration);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
internal void ReloadFileSystem()
|
||||
{
|
||||
VirtualFileSystem.ReloadKeySet();
|
||||
ContentManager = new ContentManager(VirtualFileSystem);
|
||||
AccountManager = new AccountManager(LibHacHorizonManager.RyujinxClient);
|
||||
}
|
||||
|
||||
internal void DisposeContext()
|
||||
{
|
||||
EmulationContext?.Dispose();
|
||||
EmulationContext?.DisposeGpu();
|
||||
EmulationContext = null;
|
||||
LibRyujinx.Renderer = null;
|
||||
}
|
||||
}
|
||||
|
||||
public class GameInfo
|
||||
{
|
||||
public double FileSize;
|
||||
public string? TitleName;
|
||||
public string? TitleId;
|
||||
public string? Developer;
|
||||
public string? Version;
|
||||
public byte[]? Icon;
|
||||
}
|
||||
|
||||
public unsafe struct GameInfoNative
|
||||
{
|
||||
public ulong FileSize;
|
||||
public fixed byte TitleName[512];
|
||||
public ulong TitleId;
|
||||
public fixed byte Developer[256];
|
||||
public uint Version;
|
||||
|
||||
public GameInfoNative(ulong fileSize, string titleName, ulong titleId, string developer, uint version)
|
||||
{
|
||||
FileSize = fileSize;
|
||||
TitleId = titleId;
|
||||
Version = version;
|
||||
|
||||
fixed (byte* developerPtr = Developer)
|
||||
fixed (byte* titleNamePtr = TitleName)
|
||||
{
|
||||
CopyStringToFixedArray(titleName, titleNamePtr, 512);
|
||||
CopyStringToFixedArray(developer, developerPtr, 256);
|
||||
}
|
||||
}
|
||||
|
||||
private void CopyStringToFixedArray(string source, byte* destination, int length)
|
||||
{
|
||||
var span = new Span<byte>(destination, length);
|
||||
Encoding.UTF8.GetBytes(source, span);
|
||||
}
|
||||
}
|
||||
|
||||
public class GameStats
|
||||
{
|
||||
public double Fifo;
|
||||
public double GameFps;
|
||||
public double GameTime;
|
||||
}
|
||||
}
|
81
src/LibRyujinx/LibRyujinx.csproj
Normal file
81
src/LibRyujinx/LibRyujinx.csproj
Normal file
@ -0,0 +1,81 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<RuntimeIdentifiers>linux-bionic-arm64;ios-arm64</RuntimeIdentifiers>
|
||||
<Nullable>enable</Nullable>
|
||||
<LinkerFlavor Condition="'$(RuntimeIdentifier)'=='linux-bionic-arm64'">lld</LinkerFlavor>
|
||||
<DefineConstants>$(DefineConstants);FORCE_EXTERNAL_BASE_DIR</DefineConstants>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<PublishAot>true</PublishAot>
|
||||
<PublishAotUsingRuntimePack>true</PublishAotUsingRuntimePack>
|
||||
<!-- Not sure why, but on iOS this results in an error. Result is still a .dylib. -->
|
||||
<NativeLib Condition="'$(RuntimeIdentifier)'=='linux-bionic-arm64'">Shared</NativeLib>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<EnableTrimAnalyzer>true</EnableTrimAnalyzer>
|
||||
<InvariantGlobalization>true</InvariantGlobalization>
|
||||
<IlcInstructionSet>armv8.2-a</IlcInstructionSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)'=='Release'">
|
||||
<Optimize>true</Optimize>
|
||||
<OptimizationPreference>Speed</OptimizationPreference>
|
||||
</PropertyGroup>
|
||||
|
||||
<!-- iOS Linking Fixes -->
|
||||
<Target Condition="'$(RuntimeIdentifier)'=='ios-arm64'" Name="PrepareBeforeIlcCompile" BeforeTargets="IlcCompile">
|
||||
<Exec Command="xcrun xcode-select -p" ConsoleToMSBuild="true">
|
||||
<Output TaskParameter="ConsoleOutput" PropertyName="XcodeSelect" />
|
||||
</Exec>
|
||||
<PropertyGroup>
|
||||
<XcodePath>$(XcodeSelect)</XcodePath>
|
||||
<XcodePath>$([MSBuild]::EnsureTrailingSlash('$(XCodePath)'))</XcodePath>
|
||||
</PropertyGroup>
|
||||
<Message Importance="normal" Text="Found Xcode at $(XcodeSelect)" />
|
||||
<ItemGroup>
|
||||
<LinkerArg Include="-Wl,-ld_classic" />
|
||||
<LinkerArg Include="-isysroot %22$(XcodePath)Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk%22"
|
||||
Condition=" $(RuntimeIdentifier.Contains('simulator')) "/>
|
||||
<LinkerArg Include="-isysroot %22$(XcodePath)Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk%22"
|
||||
Condition=" !$(RuntimeIdentifier.Contains('simulator')) "/>
|
||||
</ItemGroup>
|
||||
</Target>
|
||||
<Target Condition="'$(RuntimeIdentifier)'=='ios-arm64'" Name="FixDylib" AfterTargets="Publish">
|
||||
<Exec Command="install_name_tool -id @rpath/$(TargetName).dylib $(NativeBinary)" ConsoleToMSBuild="true" />
|
||||
</Target>
|
||||
<Target Condition="'$(RuntimeIdentifier)'=='ios-arm64'" Name="FixSymbols" AfterTargets="Publish">
|
||||
<RemoveDir Directories="$(PublishDir)$(TargetName).framework.dSYM"/>
|
||||
<!-- create-xcframework (called from the export plugin wants the symbol files in a directory
|
||||
with a slightly different name from the one created by dotnet publish, so we copy them over
|
||||
to the correctly-named directory -->
|
||||
<ItemGroup>
|
||||
<SymbolFiles Include="$(NativeBinary).dsym\**\*.*"/>
|
||||
</ItemGroup>
|
||||
<Copy SourceFiles="@(SymbolFiles)" DestinationFolder="$(PublishDir)$(TargetName).framework.dSYM"/>
|
||||
</Target>
|
||||
<!-- End iOS Linking Fixes -->
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Ryujinx.Audio.Backends.OpenAL\Ryujinx.Audio.Backends.OpenAL.csproj" />
|
||||
<ProjectReference Include="..\Ryujinx.Audio.Backends.SDL2\Ryujinx.Audio.Backends.SDL2.csproj" />
|
||||
<ProjectReference Include="..\Ryujinx.Input\Ryujinx.Input.csproj" />
|
||||
<ProjectReference Include="..\Ryujinx.Common\Ryujinx.Common.csproj" />
|
||||
<ProjectReference Include="..\Ryujinx.HLE\Ryujinx.HLE.csproj" />
|
||||
<ProjectReference Include="..\ARMeilleure\ARMeilleure.csproj" />
|
||||
<ProjectReference Include="..\Ryujinx.Graphics.OpenGL\Ryujinx.Graphics.OpenGL.csproj" />
|
||||
<ProjectReference Include="..\Ryujinx.Graphics.Vulkan\Ryujinx.Graphics.Vulkan.csproj" />
|
||||
<ProjectReference Include="..\Ryujinx.Graphics.Gpu\Ryujinx.Graphics.Gpu.csproj" />
|
||||
<ProjectReference Include="..\Ryujinx.Ui.Common\Ryujinx.Ui.Common.csproj" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<RdXmlFile Include="rd.xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Rxmxnx.PInvoke.Extensions" />
|
||||
<PackageReference Include="Silk.NET.Vulkan" />
|
||||
<PackageReference Include="Silk.NET.Vulkan.Extensions.KHR" />
|
||||
<LinkerArg Condition="'$(RuntimeIdentifier)'=='linux-bionic-arm64'" Include="-llog" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Folder Include="Jni\" />
|
||||
</ItemGroup>
|
||||
</Project>
|
20
src/LibRyujinx/OpenTKBindingsContext.cs
Normal file
20
src/LibRyujinx/OpenTKBindingsContext.cs
Normal file
@ -0,0 +1,20 @@
|
||||
using OpenTK;
|
||||
using System;
|
||||
|
||||
namespace LibRyujinx.Shared
|
||||
{
|
||||
public class OpenTKBindingsContext : IBindingsContext
|
||||
{
|
||||
private readonly Func<string, IntPtr> _getProcAddress;
|
||||
|
||||
public OpenTKBindingsContext(Func<string, IntPtr> getProcAddress)
|
||||
{
|
||||
_getProcAddress = getProcAddress;
|
||||
}
|
||||
|
||||
public IntPtr GetProcAddress(string procName)
|
||||
{
|
||||
return _getProcAddress(procName);
|
||||
}
|
||||
}
|
||||
}
|
99
src/LibRyujinx/VulkanLoader.cs
Normal file
99
src/LibRyujinx/VulkanLoader.cs
Normal file
@ -0,0 +1,99 @@
|
||||
using Ryujinx.Common.Logging;
|
||||
using Silk.NET.Core.Contexts;
|
||||
using Silk.NET.Vulkan;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace LibRyujinx
|
||||
{
|
||||
public class VulkanLoader : IDisposable
|
||||
{
|
||||
private delegate IntPtr GetInstanceProcAddress(IntPtr instance, IntPtr name);
|
||||
private delegate IntPtr GetDeviceProcAddress(IntPtr device, IntPtr name);
|
||||
|
||||
private IntPtr _loadedLibrary = IntPtr.Zero;
|
||||
private GetInstanceProcAddress _getInstanceProcAddr;
|
||||
private GetDeviceProcAddress _getDeviceProcAddr;
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (_loadedLibrary != IntPtr.Zero)
|
||||
{
|
||||
NativeLibrary.Free(_loadedLibrary);
|
||||
_loadedLibrary = IntPtr.Zero;
|
||||
}
|
||||
}
|
||||
|
||||
public VulkanLoader(IntPtr driver)
|
||||
{
|
||||
_loadedLibrary = driver;
|
||||
|
||||
if (_loadedLibrary != IntPtr.Zero)
|
||||
{
|
||||
var instanceGetProc = NativeLibrary.GetExport(_loadedLibrary, "vkGetInstanceProcAddr");
|
||||
var deviceProc = NativeLibrary.GetExport(_loadedLibrary, "vkGetDeviceProcAddr");
|
||||
|
||||
_getInstanceProcAddr = Marshal.GetDelegateForFunctionPointer<GetInstanceProcAddress>(instanceGetProc);
|
||||
_getDeviceProcAddr = Marshal.GetDelegateForFunctionPointer<GetDeviceProcAddress>(deviceProc);
|
||||
}
|
||||
}
|
||||
|
||||
public unsafe Vk GetApi()
|
||||
{
|
||||
|
||||
if (_loadedLibrary == IntPtr.Zero)
|
||||
{
|
||||
return Vk.GetApi();
|
||||
}
|
||||
var ctx = new MultiNativeContext(new INativeContext[1]);
|
||||
var ret = new Vk(ctx);
|
||||
ctx.Contexts[0] = new LamdaNativeContext
|
||||
(
|
||||
x =>
|
||||
{
|
||||
var xPtr = Marshal.StringToHGlobalAnsi(x);
|
||||
byte* xp = (byte*)xPtr;
|
||||
LibRyujinx.debug_break(0);
|
||||
try
|
||||
{
|
||||
nint ptr = default;
|
||||
ptr = _getInstanceProcAddr(ret.CurrentInstance.GetValueOrDefault().Handle, xPtr);
|
||||
|
||||
if (ptr == default)
|
||||
{
|
||||
ptr = _getInstanceProcAddr(IntPtr.Zero, xPtr);
|
||||
|
||||
if (ptr == default)
|
||||
{
|
||||
var currentDevice = ret.CurrentDevice.GetValueOrDefault().Handle;
|
||||
if (currentDevice != IntPtr.Zero)
|
||||
{
|
||||
ptr = _getDeviceProcAddr(currentDevice, xPtr);
|
||||
}
|
||||
|
||||
if (ptr == default)
|
||||
{
|
||||
Logger.Warning?.Print(LogClass.Gpu, $"Failed to get function pointer: {x}");
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return ptr;
|
||||
}
|
||||
finally
|
||||
{
|
||||
Marshal.FreeHGlobal(xPtr);
|
||||
}
|
||||
}
|
||||
);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
@ -24,20 +24,6 @@
|
||||
<Type Name="Silk.NET.Vulkan.Extensions.KHR.KhrSwapchain"
|
||||
Dynamic="Required All"/>
|
||||
</Assembly>
|
||||
<Assembly Name="Ryujinx.Ava">
|
||||
<Type Name="Ryujinx.Ava.UI.Views.User.UserSelectorViews"
|
||||
Dynamic="Required All"/>
|
||||
<Type Name="Ryujinx.Ava.UI.Views.User.UserSaveManagerView"
|
||||
Dynamic="Required All"/>
|
||||
<Type Name="Ryujinx.Ava.UI.Views.User.UserRecovererView"
|
||||
Dynamic="Required All"/>
|
||||
<Type Name="Ryujinx.Ava.UI.Views.User.UserProfileImageSelectorView"
|
||||
Dynamic="Required All"/>
|
||||
<Type Name="Ryujinx.Ava.UI.Views.User.UserFirmwareAvatarSelectorView"
|
||||
Dynamic="Required All"/>
|
||||
<Type Name="Ryujinx.Ava.UI.Views.User.UserEditorView"
|
||||
Dynamic="Required All"/>
|
||||
</Assembly>
|
||||
<Assembly Name="Ryujinx.HLE">
|
||||
<Type Name="Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostChannel.NvHostGpuDeviceFile"
|
||||
Dynamic="Required All" />
|
File diff suppressed because it is too large
Load Diff
@ -1,7 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Workspace
|
||||
version = "1.0">
|
||||
<FileRef
|
||||
location = "self:">
|
||||
</FileRef>
|
||||
</Workspace>
|
@ -1,24 +0,0 @@
|
||||
{
|
||||
"originHash" : "d611b071fbe94fdc9900a07a218340eab4ce2c3c7168bf6542f2830c0400a72b",
|
||||
"pins" : [
|
||||
{
|
||||
"identity" : "swiftsvg",
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/mchoe/SwiftSVG",
|
||||
"state" : {
|
||||
"branch" : "master",
|
||||
"revision" : "88b9ee086b29019e35f6f49c8e30e5552eb8fa9d"
|
||||
}
|
||||
},
|
||||
{
|
||||
"identity" : "swiftuijoystick",
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/michael94ellis/SwiftUIJoystick",
|
||||
"state" : {
|
||||
"revision" : "5bd303cdafb369a70a45c902538b42dd3c5f4d65",
|
||||
"version" : "1.5.0"
|
||||
}
|
||||
}
|
||||
],
|
||||
"version" : 3
|
||||
}
|
Binary file not shown.
@ -1,5 +0,0 @@
|
||||
<?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">
|
||||
<array/>
|
||||
</plist>
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -1,104 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "1610"
|
||||
version = "1.7">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
buildImplicitDependencies = "YES"
|
||||
buildArchitectures = "Automatic">
|
||||
<BuildActionEntries>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "YES"
|
||||
buildForProfiling = "YES"
|
||||
buildForArchiving = "YES"
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "4E80A98C2CD6F54500029585"
|
||||
BuildableName = "MeloNX.app"
|
||||
BlueprintName = "MeloNX"
|
||||
ReferencedContainer = "container:MeloNX.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
</BuildActionEntries>
|
||||
</BuildAction>
|
||||
<TestAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
shouldAutocreateTestPlan = "YES">
|
||||
<Testables>
|
||||
<TestableReference
|
||||
skipped = "NO"
|
||||
parallelizable = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "4E80A99C2CD6F54700029585"
|
||||
BuildableName = "MeloNXTests.xctest"
|
||||
BlueprintName = "MeloNXTests"
|
||||
ReferencedContainer = "container:MeloNX.xcodeproj">
|
||||
</BuildableReference>
|
||||
</TestableReference>
|
||||
<TestableReference
|
||||
skipped = "NO"
|
||||
parallelizable = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "4E80A9A62CD6F54700029585"
|
||||
BuildableName = "MeloNXUITests.xctest"
|
||||
BlueprintName = "MeloNXUITests"
|
||||
ReferencedContainer = "container:MeloNX.xcodeproj">
|
||||
</BuildableReference>
|
||||
</TestableReference>
|
||||
</Testables>
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
buildConfiguration = "Release"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
launchStyle = "0"
|
||||
useCustomWorkingDirectory = "NO"
|
||||
ignoresPersistentStateOnLaunch = "NO"
|
||||
debugDocumentVersioning = "YES"
|
||||
debugServiceExtension = "internal"
|
||||
enableGPUValidationMode = "1"
|
||||
showGraphicsOverview = "Yes"
|
||||
allowLocationSimulation = "YES">
|
||||
<BuildableProductRunnable
|
||||
runnableDebuggingMode = "0">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "4E80A98C2CD6F54500029585"
|
||||
BuildableName = "MeloNX.app"
|
||||
BlueprintName = "MeloNX"
|
||||
ReferencedContainer = "container:MeloNX.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildableProductRunnable>
|
||||
</LaunchAction>
|
||||
<ProfileAction
|
||||
buildConfiguration = "Release"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
savedToolIdentifier = ""
|
||||
useCustomWorkingDirectory = "NO"
|
||||
debugDocumentVersioning = "YES">
|
||||
<BuildableProductRunnable
|
||||
runnableDebuggingMode = "0">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "4E80A98C2CD6F54500029585"
|
||||
BuildableName = "MeloNX.app"
|
||||
BlueprintName = "MeloNX"
|
||||
ReferencedContainer = "container:MeloNX.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildableProductRunnable>
|
||||
</ProfileAction>
|
||||
<AnalyzeAction
|
||||
buildConfiguration = "Debug">
|
||||
</AnalyzeAction>
|
||||
<ArchiveAction
|
||||
buildConfiguration = "Release"
|
||||
revealArchiveInOrganizer = "YES">
|
||||
</ArchiveAction>
|
||||
</Scheme>
|
@ -1,24 +0,0 @@
|
||||
<?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>SchemeUserState</key>
|
||||
<dict>
|
||||
<key>MeloNX.xcscheme_^#shared#^_</key>
|
||||
<dict>
|
||||
<key>orderHint</key>
|
||||
<integer>0</integer>
|
||||
</dict>
|
||||
<key>Ryujinx.xcscheme_^#shared#^_</key>
|
||||
<dict>
|
||||
<key>orderHint</key>
|
||||
<integer>1</integer>
|
||||
</dict>
|
||||
<key>com.Stossy11.MeloNX.RyujinxAg.xcscheme_^#shared#^_</key>
|
||||
<dict>
|
||||
<key>orderHint</key>
|
||||
<integer>2</integer>
|
||||
</dict>
|
||||
</dict>
|
||||
</dict>
|
||||
</plist>
|
@ -1,24 +0,0 @@
|
||||
<?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>SchemeUserState</key>
|
||||
<dict>
|
||||
<key>MeloNX.xcscheme_^#shared#^_</key>
|
||||
<dict>
|
||||
<key>orderHint</key>
|
||||
<integer>0</integer>
|
||||
</dict>
|
||||
<key>Ryujinx.xcscheme_^#shared#^_</key>
|
||||
<dict>
|
||||
<key>orderHint</key>
|
||||
<integer>1</integer>
|
||||
</dict>
|
||||
<key>com.Stossy11.MeloNX.RyujinxAg.xcscheme_^#shared#^_</key>
|
||||
<dict>
|
||||
<key>orderHint</key>
|
||||
<integer>2</integer>
|
||||
</dict>
|
||||
</dict>
|
||||
</dict>
|
||||
</plist>
|
@ -1,24 +0,0 @@
|
||||
<?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>SchemeUserState</key>
|
||||
<dict>
|
||||
<key>MeloNX.xcscheme_^#shared#^_</key>
|
||||
<dict>
|
||||
<key>orderHint</key>
|
||||
<integer>0</integer>
|
||||
</dict>
|
||||
<key>Ryujinx.xcscheme_^#shared#^_</key>
|
||||
<dict>
|
||||
<key>orderHint</key>
|
||||
<integer>3</integer>
|
||||
</dict>
|
||||
<key>com.Stossy11.MeloNX.RyujinxAg.xcscheme_^#shared#^_</key>
|
||||
<dict>
|
||||
<key>orderHint</key>
|
||||
<integer>4</integer>
|
||||
</dict>
|
||||
</dict>
|
||||
</dict>
|
||||
</plist>
|
@ -1,40 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Bucket
|
||||
uuid = "271EB822-2830-4016-A3D7-CA2DEBEDCD27"
|
||||
type = "1"
|
||||
version = "2.0">
|
||||
<Breakpoints>
|
||||
<BreakpointProxy
|
||||
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
|
||||
<BreakpointContent
|
||||
uuid = "499F5405-B63B-4623-9332-1E44FC449FD0"
|
||||
shouldBeEnabled = "No"
|
||||
ignoreCount = "0"
|
||||
continueAfterRunningActions = "No"
|
||||
filePath = "MeloNX/Views/GamesList/GameListView.swift"
|
||||
startingColumnNumber = "9223372036854775807"
|
||||
endingColumnNumber = "9223372036854775807"
|
||||
startingLineNumber = "309"
|
||||
endingLineNumber = "309"
|
||||
landmarkName = "loadGames()"
|
||||
landmarkType = "7">
|
||||
</BreakpointContent>
|
||||
</BreakpointProxy>
|
||||
<BreakpointProxy
|
||||
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
|
||||
<BreakpointContent
|
||||
uuid = "0BB7C122-8933-48E8-ABA3-1ABB39594258"
|
||||
shouldBeEnabled = "No"
|
||||
ignoreCount = "0"
|
||||
continueAfterRunningActions = "No"
|
||||
filePath = "MeloNX/Models/Game.swift"
|
||||
startingColumnNumber = "9223372036854775807"
|
||||
endingColumnNumber = "9223372036854775807"
|
||||
startingLineNumber = "37"
|
||||
endingLineNumber = "37"
|
||||
landmarkName = "createImage(from:)"
|
||||
landmarkType = "7">
|
||||
</BreakpointContent>
|
||||
</BreakpointProxy>
|
||||
</Breakpoints>
|
||||
</Bucket>
|
@ -1,42 +0,0 @@
|
||||
<?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>SchemeUserState</key>
|
||||
<dict>
|
||||
<key>MeloNX.xcscheme_^#shared#^_</key>
|
||||
<dict>
|
||||
<key>orderHint</key>
|
||||
<integer>0</integer>
|
||||
</dict>
|
||||
<key>Ryujinx.xcscheme_^#shared#^_</key>
|
||||
<dict>
|
||||
<key>orderHint</key>
|
||||
<integer>3</integer>
|
||||
</dict>
|
||||
<key>com.Stossy11.MeloNX.RyujinxAg.xcscheme_^#shared#^_</key>
|
||||
<dict>
|
||||
<key>orderHint</key>
|
||||
<integer>4</integer>
|
||||
</dict>
|
||||
</dict>
|
||||
<key>SuppressBuildableAutocreation</key>
|
||||
<dict>
|
||||
<key>4E80A98C2CD6F54500029585</key>
|
||||
<dict>
|
||||
<key>primary</key>
|
||||
<true/>
|
||||
</dict>
|
||||
<key>4E80A99C2CD6F54700029585</key>
|
||||
<dict>
|
||||
<key>primary</key>
|
||||
<true/>
|
||||
</dict>
|
||||
<key>4E80A9A62CD6F54700029585</key>
|
||||
<dict>
|
||||
<key>primary</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</dict>
|
||||
</dict>
|
||||
</plist>
|
@ -1,24 +0,0 @@
|
||||
<?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>SchemeUserState</key>
|
||||
<dict>
|
||||
<key>MeloNX.xcscheme_^#shared#^_</key>
|
||||
<dict>
|
||||
<key>orderHint</key>
|
||||
<integer>0</integer>
|
||||
</dict>
|
||||
<key>Ryujinx.xcscheme_^#shared#^_</key>
|
||||
<dict>
|
||||
<key>orderHint</key>
|
||||
<integer>2</integer>
|
||||
</dict>
|
||||
<key>com.Stossy11.MeloNX.RyujinxAg.xcscheme_^#shared#^_</key>
|
||||
<dict>
|
||||
<key>orderHint</key>
|
||||
<integer>1</integer>
|
||||
</dict>
|
||||
</dict>
|
||||
</dict>
|
||||
</plist>
|
@ -1,53 +0,0 @@
|
||||
//
|
||||
// Ryujinx-Header.h
|
||||
// MeloNX
|
||||
//
|
||||
// Created by Stossy11 on 3/11/2024.
|
||||
//
|
||||
|
||||
#define DRM 0
|
||||
#define CS_DEBUGGED 0x10000000
|
||||
|
||||
#ifndef RyujinxHeader
|
||||
#define RyujinxHeader
|
||||
|
||||
|
||||
#include <SDL2/SDL.h>
|
||||
#include <SDL2/SDL_syswm.h>
|
||||
#import "utils.h"
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct GameInfo {
|
||||
long FileSize;
|
||||
char TitleName[512];
|
||||
char TitleId[32];
|
||||
char Developer[256];
|
||||
char Version[16];
|
||||
unsigned char* ImageData;
|
||||
unsigned int ImageSize;
|
||||
};
|
||||
|
||||
extern struct GameInfo get_game_info(int, char*);
|
||||
|
||||
void install_firmware(const char* inputPtr);
|
||||
|
||||
char* installed_firmware_version();
|
||||
|
||||
void stop_emulation();
|
||||
|
||||
int main_ryujinx_sdl(int argc, char **argv);
|
||||
|
||||
int get_current_fps();
|
||||
|
||||
void initialize();
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* RyujinxSDL_h */
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user