forked from MeloNX/MeloNX
Compare commits
402 Commits
Author | SHA1 | Date | |
---|---|---|---|
ee179cacc4 | |||
|
e924da52ec | ||
|
ea2eff15c6 | ||
|
c6ff0b60bf | ||
|
edc56316cc | ||
|
8df465a959 | ||
527ac3fb23 | |||
8e60f6dc50 | |||
|
3b99631dfb | ||
cb33b04f2b | |||
500f3d5b9e | |||
ac4e5d394e | |||
f2d078f80b | |||
004a81fa60 | |||
ddf634ecb6 | |||
|
cce876c6f5 | ||
ebfb39c132 | |||
b3bb9cefcf | |||
8c54134699 | |||
e8537df246 | |||
8c6dd455f2 | |||
2a7cfa5650 | |||
df2b17ddd6 | |||
757fb1f6d1 | |||
|
e741039304 | ||
|
fd0ce75f67 | ||
|
0e80bd3d51 | ||
|
f95281899c | ||
802a8d7bae | |||
7277e1fa9b | |||
27312d4f31 | |||
|
932a4a24d3 | ||
|
7137063277 | ||
|
c825ab4d6f | ||
|
59c34f10aa | ||
|
5053ead4b3 | ||
|
e2f584a7ff | ||
|
b7deaefff7 | ||
|
4a47481e7a | ||
|
cca7cd02cf | ||
|
f38093a1f7 | ||
|
7e426c4377 | ||
|
ba5b26c5cf | ||
|
85c4450eb2 | ||
|
ab0845d732 | ||
|
08853515af | ||
|
1a94e37816 | ||
|
d19582b055 | ||
|
330dfdc131 | ||
|
3ff7b1d32d | ||
|
affefc35a8 | ||
|
a00c8c909f | ||
|
8888edde5c | ||
|
d19b391ca6 | ||
|
9bcc48646a | ||
|
a18bb5f31a | ||
|
ce2f577f1b | ||
|
d5aff40a2e | ||
|
fa0a9ca889 | ||
|
5ef97ca444 | ||
|
407c67a512 | ||
|
06a7c0217f | ||
|
d40dc00769 | ||
|
896851e909 | ||
|
5fa2f30ac6 | ||
|
e4a3187aac | ||
|
d2d8e3f208 | ||
|
31af1e194f | ||
|
6884a14b32 | ||
|
d589a18c08 | ||
|
9a40df6cf9 | ||
|
28df6f1c4e | ||
|
eac63c756e | ||
|
4d7356efe0 | ||
|
adda73f061 | ||
|
a583d6bf46 | ||
|
898f88350c | ||
|
9eaa683ae4 | ||
|
7cfd5dc902 | ||
|
dedecebc6b | ||
|
aa34233634 | ||
|
eb8cdde8dd | ||
|
8ac307166a | ||
|
b28f9a6331 | ||
|
f28f2dfeeb | ||
|
8b7beb6f22 | ||
|
fcb511bbca | ||
|
c57f6a7fe3 | ||
|
bbe460cecd | ||
|
0ffb074d9a | ||
|
51aec9a2ed | ||
|
282ba31810 | ||
|
498bb95cf1 | ||
|
88c45e1e86 | ||
|
32064ccba5 | ||
|
115f366609 | ||
|
b5a82ac607 | ||
|
7a2869ab6e | ||
|
1dd2d68be8 | ||
|
8af1066a55 | ||
|
ae5fd72e5c | ||
|
839d192635 | ||
|
b8125859ed | ||
|
bab815ab6f | ||
|
909558859d | ||
|
3042cabb02 | ||
|
3a7a9e4456 | ||
|
463411546a | ||
|
0a54501974 | ||
|
0394a39342 | ||
|
c90b78499b | ||
|
235a90aed8 | ||
|
0dbca88e08 | ||
|
45c4f56c1d | ||
|
8226f77ddd | ||
|
7de794cf81 | ||
|
6919b123b7 | ||
|
ca59c3f499 | ||
|
fdd7ee791c | ||
|
398fa1c238 | ||
|
2c5c0392f9 | ||
|
e0acde04bb | ||
|
3c61d560c3 | ||
|
b45a81458a | ||
|
460f9faf4e | ||
|
552c15739c | ||
|
0137c9e635 | ||
|
23fa5f4c9c | ||
|
4f75e26ec7 | ||
|
8d8983049e | ||
|
7969fb6bba | ||
|
4a4b11871e | ||
|
e85ee673b1 | ||
|
42f22fe5d7 | ||
|
263eb97f79 | ||
|
3004902257 | ||
|
59ddb26628 | ||
|
83fda10f6e | ||
|
d97e995e59 | ||
|
56b2f84702 | ||
|
698e36bbd2 | ||
|
6ce49a2dc7 | ||
|
ccd330ba0f | ||
|
95d252b7b8 | ||
|
add681144b | ||
|
c6dc00815a | ||
|
99f04ac1a6 | ||
|
ce09450743 | ||
|
2cb80f37d4 | ||
|
827069e784 | ||
|
1a919e99b2 | ||
|
f77bebac80 | ||
|
6fbf279fac | ||
|
344f4f52c1 | ||
|
eb212aa91b | ||
|
a6dbb2ad2b | ||
|
595e514f18 | ||
|
07435ad844 | ||
|
1668ba913f | ||
|
a830eb666b | ||
|
cfc75d7e78 | ||
|
c525d7d9a9 | ||
|
1a0a351a15 | ||
|
bd3335c143 | ||
|
a94445b23e | ||
|
0c3421973c | ||
|
0afa8f2c14 | ||
|
d25a084858 | ||
|
311ca3c3f1 | ||
|
3193ef1083 | ||
|
5a878ae9af | ||
|
1828bc949e | ||
|
c0f2491eae | ||
|
d7c6474729 | ||
|
1ecc8fbc3b | ||
|
888402ecaf | ||
|
971d24aef0 | ||
|
c41fddd25e | ||
|
2ebe929fa5 | ||
|
53d096e392 | ||
|
4cc00bb4b1 | ||
|
c98b7fc702 | ||
|
e65effcb05 | ||
|
c1ed150949 | ||
|
c634eb4054 | ||
|
eb1ce41b00 | ||
|
2f427deb67 | ||
|
8f51938e2b | ||
|
4d84df9487 | ||
|
9ec8b2c01a | ||
|
091230af22 | ||
|
3aea194606 | ||
|
cdccf89e10 | ||
|
2ca0b17339 | ||
|
47639e6eeb | ||
|
cd78adf07f | ||
|
a3dc295c5f | ||
|
2ef4f92b07 | ||
|
2b6cc4b353 | ||
|
075575200d | ||
|
3a3b51893e | ||
|
44dbab3848 | ||
|
cada4d04ef | ||
|
e9edf0ab7f | ||
|
6e40b64554 | ||
|
1a676ee913 | ||
|
a23d8cb92f | ||
|
ab12fbe963 | ||
|
d0cc13ce0b | ||
|
65c035cdf8 | ||
|
56c5dbe557 | ||
|
5976a5161b | ||
|
3d4dea624d | ||
|
89a274c6a6 | ||
|
c6f8bfed90 | ||
|
9b94662b4b | ||
|
216026c096 | ||
|
7070cf6ae5 | ||
|
9839cd56fb | ||
|
99f46e22e2 | ||
|
22fb8c9d4f | ||
|
2f93ae9a19 | ||
|
3224ddeeb4 | ||
|
446f2854a5 | ||
|
8884d1fd73 | ||
|
268c9aecf8 | ||
|
e916662b0f | ||
|
2ddd3dd4a7 | ||
|
a8f7ababb5 | ||
|
22e3ff06b5 | ||
|
9480e5c5ce | ||
|
0652813b0f | ||
|
e7f2342eba | ||
|
543d75a587 | ||
|
338ff79e1e | ||
|
80201466ae | ||
|
7a971edb57 | ||
|
c1b0ab805a | ||
|
3e6e0e4afa | ||
|
808803d97a | ||
|
ead9a25141 | ||
|
3e0d67533f | ||
|
0b55914864 | ||
|
451a28afb8 | ||
|
12b235700c | ||
|
3be616207d | ||
|
791bf22109 | ||
|
66b1d59c66 | ||
|
c8bb05633e | ||
|
fb1171a21e | ||
|
22c0aa9c90 | ||
|
6d28b64312 | ||
|
05c041feeb | ||
|
8c2da1aa04 | ||
|
5def0429f8 | ||
|
8e74fa3456 | ||
|
6208c3e6f0 | ||
|
7124d679fd | ||
|
b323a01738 | ||
|
f6d24449b6 | ||
|
72bdc24db8 | ||
|
43514771bf | ||
|
dbfe859ed7 | ||
|
c94a73ec60 | ||
|
20a280525f | ||
|
75a4ea3370 | ||
|
d26ef2eec3 | ||
|
a0552fd78b | ||
|
bb8c5ebae1 | ||
|
50bdda5baa | ||
|
18df25f66f | ||
|
e19e7622a3 | ||
|
26026d1357 | ||
|
24068b023c | ||
|
1217a8e69b | ||
|
732db7581f | ||
|
fdd3263e31 | ||
|
ce607db944 | ||
|
6b4ee82e5d | ||
|
e2a655f1a4 | ||
|
d9a18919b0 | ||
|
8354434a37 | ||
|
5a900f38c5 | ||
|
a3a63d4394 | ||
|
3924bd1a43 | ||
|
50458b2472 | ||
|
dda0f26067 | ||
|
4e1a60328e | ||
|
2505a1abcd | ||
|
bc4d99a078 | ||
|
ec6cb0abb4 | ||
|
53b5985da6 | ||
|
87f238be60 | ||
|
4d0dbbfae2 | ||
|
08384ee5a8 | ||
|
d4d0a48bfe | ||
|
57d8afd0c9 | ||
|
c43fb92bbf | ||
|
167f50bbcd | ||
|
ba91f5d401 | ||
|
79f6c18a9b | ||
|
4f63782bac | ||
|
6f5fcb7970 | ||
|
6ef8946169 | ||
|
42340fc743 | ||
|
103e7cb021 | ||
|
31ed061bea | ||
|
4218311e6a | ||
|
e37735ed26 | ||
|
74a18b7c18 | ||
|
74fe814329 | ||
|
d1a093e5ca | ||
|
dfb14a5607 | ||
|
904a5ffcb4 | ||
|
946633276b | ||
|
baf94e0e3e | ||
|
cf6201a4a6 | ||
|
18909195d1 | ||
|
f06d22d6f0 | ||
|
84d6e8d121 | ||
|
95c4912d58 | ||
|
356a75af0b | ||
|
4ae9921063 | ||
|
6a8ac389e5 | ||
|
8dd1eb333c | ||
|
7dc3a62c14 | ||
|
e59dba42ef | ||
|
bd6937ae5c | ||
|
b82e789d4f | ||
|
4a6724622e | ||
|
0c73eba3db | ||
|
a082e14ede | ||
|
d29da11d5f | ||
|
ea07328aea | ||
|
a0b3d82ee0 | ||
|
609de33b0b | ||
|
dfc0819e72 | ||
|
d4803356bb | ||
|
459efd0db7 | ||
|
8bb7a3fc97 | ||
|
628d092fc6 | ||
|
6c90d50c8e | ||
|
d56bab1e24 | ||
|
a37e2d6e44 | ||
|
25123232bd | ||
|
8927e0669f | ||
|
bbed3b9926 | ||
|
24c8b0edc0 | ||
|
e5066449a5 | ||
|
d704bcd93b | ||
|
c94f0fbb83 | ||
|
d1b30fbe08 | ||
|
4505a7f162 | ||
|
ccbbaddbcb | ||
|
8bf102d2cd | ||
|
2adf031830 | ||
|
bb4a28b525 | ||
|
a8fbcdae9f | ||
|
4e81ab4229 | ||
|
4117c13377 | ||
|
20a392ad55 | ||
|
70fcba39de | ||
|
7795b662a9 | ||
|
30bdc4544e | ||
|
f6475cca17 | ||
|
0335c52254 | ||
|
b8d992e5a7 | ||
|
a620cbcc90 | ||
|
cea204d48e | ||
|
35fb409e85 | ||
|
d7ec4308b4 | ||
|
fbdd390f90 | ||
|
f33fea3287 | ||
|
5d3eea40be | ||
|
cd37c75b82 | ||
|
43705c2320 | ||
|
371e6fa24c | ||
|
1d9b63cc6a | ||
|
795539bc82 | ||
|
dd2e851e95 | ||
|
2ca70eb9a0 | ||
|
6575952432 | ||
|
9a28ba72b1 | ||
|
34a9922b57 | ||
|
4df22eb867 | ||
|
f241f88558 | ||
|
90455a05e6 | ||
|
edc76883db | ||
|
427b7d06b5 | ||
|
331c07807f | ||
|
a772b073ec | ||
|
870d9599cc | ||
|
2dbbc9bc05 | ||
|
72634c80f4 | ||
|
bebd8eb822 | ||
|
f4b74e9ce1 | ||
|
4e19b36ad7 | ||
|
b16923a902 | ||
|
7e58b21f3d | ||
|
4fbc978e73 | ||
|
1a45dc8df8 | ||
|
f037fcba9a |
@ -17,8 +17,8 @@ tab_width = 4
|
||||
end_of_line = lf
|
||||
insert_final_newline = true
|
||||
|
||||
# JSON files
|
||||
[*.json]
|
||||
# Markdown, JSON, YAML, props and csproj files
|
||||
[*.{md,json,yml,props,csproj}]
|
||||
|
||||
# Indentation and spacing
|
||||
indent_size = 2
|
||||
@ -259,12 +259,12 @@ dotnet_diagnostic.CA1861.severity = none
|
||||
# Disable "Prefer using 'string.Equals(string, StringComparison)' to perform a case-insensitive comparison, but keep in mind that this might cause subtle changes in behavior, so make sure to conduct thorough testing after applying the suggestion, or if culturally sensitive comparison is not required, consider using 'StringComparison.OrdinalIgnoreCase'"
|
||||
dotnet_diagnostic.CA1862.severity = none
|
||||
|
||||
[src/Ryujinx.HLE/HOS/Services/**.cs]
|
||||
# Disable "mark members as static" rule for services
|
||||
[src/Ryujinx/UI/ViewModels/**.cs]
|
||||
# Disable "mark members as static" rule for ViewModels
|
||||
dotnet_diagnostic.CA1822.severity = none
|
||||
|
||||
[src/Ryujinx.Ava/UI/ViewModels/**.cs]
|
||||
# Disable "mark members as static" rule for ViewModels
|
||||
[src/Ryujinx.HLE/HOS/Services/**.cs]
|
||||
# Disable "mark members as static" rule for services
|
||||
dotnet_diagnostic.CA1822.severity = none
|
||||
|
||||
[src/Ryujinx.Tests/Cpu/*.cs]
|
||||
|
1
.github/ISSUE_TEMPLATE/feature_request.yml
vendored
1
.github/ISSUE_TEMPLATE/feature_request.yml
vendored
@ -1,6 +1,7 @@
|
||||
name: Feature Request
|
||||
description: Suggest a new feature for Ryujinx.
|
||||
title: "[Feature Request]"
|
||||
labels: enhancement
|
||||
body:
|
||||
- type: textarea
|
||||
id: overview
|
||||
|
22
.github/dependabot.yml
vendored
22
.github/dependabot.yml
vendored
@ -7,18 +7,34 @@ updates:
|
||||
labels:
|
||||
- "infra"
|
||||
reviewers:
|
||||
- marysaka
|
||||
- TSRBerry
|
||||
commit-message:
|
||||
prefix: "ci"
|
||||
|
||||
- package-ecosystem: nuget
|
||||
directory: /
|
||||
open-pull-requests-limit: 5
|
||||
open-pull-requests-limit: 10
|
||||
schedule:
|
||||
interval: daily
|
||||
labels:
|
||||
- "infra"
|
||||
reviewers:
|
||||
- marysaka
|
||||
- TSRBerry
|
||||
commit-message:
|
||||
prefix: nuget
|
||||
groups:
|
||||
Avalonia:
|
||||
patterns:
|
||||
- "*Avalonia*"
|
||||
Silk.NET:
|
||||
patterns:
|
||||
- "Silk.NET*"
|
||||
OpenTK:
|
||||
patterns:
|
||||
- "OpenTK*"
|
||||
SixLabors:
|
||||
patterns:
|
||||
- "SixLabors*"
|
||||
NUnit:
|
||||
patterns:
|
||||
- "NUnit*"
|
||||
|
2
.github/labeler.yml
vendored
2
.github/labeler.yml
vendored
@ -20,7 +20,7 @@ gpu:
|
||||
|
||||
gui:
|
||||
- changed-files:
|
||||
- any-glob-to-any-file: ['src/Ryujinx/**', 'src/Ryujinx.Ui.Common/**', 'src/Ryujinx.Ui.LocaleGenerator/**', 'src/Ryujinx.Ava/**']
|
||||
- any-glob-to-any-file: ['src/Ryujinx/**', 'src/Ryujinx.UI.Common/**', 'src/Ryujinx.UI.LocaleGenerator/**', 'src/Ryujinx.Gtk3/**']
|
||||
|
||||
horizon:
|
||||
- changed-files:
|
||||
|
7
.github/reviewers.yml
vendored
7
.github/reviewers.yml
vendored
@ -1,31 +1,24 @@
|
||||
audio:
|
||||
- marysaka
|
||||
|
||||
cpu:
|
||||
- gdkchan
|
||||
- riperiperi
|
||||
- marysaka
|
||||
- LDj3SNuD
|
||||
|
||||
gpu:
|
||||
- gdkchan
|
||||
- riperiperi
|
||||
- marysaka
|
||||
|
||||
gui:
|
||||
- Ack77
|
||||
- emmauss
|
||||
- TSRBerry
|
||||
- marysaka
|
||||
|
||||
horizon:
|
||||
- gdkchan
|
||||
- Ack77
|
||||
- marysaka
|
||||
- TSRBerry
|
||||
|
||||
infra:
|
||||
- marysaka
|
||||
- TSRBerry
|
||||
|
||||
default:
|
||||
|
87
.github/workflows/build.yml
vendored
87
.github/workflows/build.yml
vendored
@ -10,28 +10,17 @@ env:
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: ${{ matrix.OS_NAME }} (${{ matrix.configuration }})
|
||||
runs-on: ${{ matrix.os }}
|
||||
name: ${{ matrix.platform.name }} (${{ matrix.configuration }})
|
||||
runs-on: ${{ matrix.platform.os }}
|
||||
timeout-minutes: 45
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu-latest, macOS-latest, windows-latest]
|
||||
configuration: [Debug, Release]
|
||||
include:
|
||||
- os: ubuntu-latest
|
||||
OS_NAME: Linux x64
|
||||
DOTNET_RUNTIME_IDENTIFIER: linux-x64
|
||||
RELEASE_ZIP_OS_NAME: linux_x64
|
||||
|
||||
- os: macOS-latest
|
||||
OS_NAME: macOS x64
|
||||
DOTNET_RUNTIME_IDENTIFIER: osx-x64
|
||||
RELEASE_ZIP_OS_NAME: osx_x64
|
||||
|
||||
- os: windows-latest
|
||||
OS_NAME: Windows x64
|
||||
DOTNET_RUNTIME_IDENTIFIER: win-x64
|
||||
RELEASE_ZIP_OS_NAME: win_x64
|
||||
platform:
|
||||
- { name: win-x64, os: windows-latest, zip_os_name: win_x64 }
|
||||
- { name: linux-x64, os: ubuntu-latest, zip_os_name: linux_x64 }
|
||||
- { name: linux-arm64, os: ubuntu-latest, zip_os_name: linux_arm64 }
|
||||
- { name: osx-x64, os: macos-13, zip_os_name: osx_x64 }
|
||||
|
||||
fail-fast: false
|
||||
steps:
|
||||
@ -40,7 +29,7 @@ jobs:
|
||||
- uses: actions/setup-dotnet@v4
|
||||
with:
|
||||
global-json-file: global.json
|
||||
|
||||
|
||||
- name: Overwrite csc problem matcher
|
||||
run: echo "::add-matcher::.github/csc.json"
|
||||
|
||||
@ -49,6 +38,16 @@ jobs:
|
||||
run: echo "result=$(git rev-parse --short "${{ github.sha }}")" >> $GITHUB_OUTPUT
|
||||
shell: bash
|
||||
|
||||
- name: Change config filename
|
||||
run: sed -r --in-place 's/\%\%RYUJINX_CONFIG_FILE_NAME\%\%/PRConfig\.json/g;' src/Ryujinx.Common/ReleaseInformation.cs
|
||||
shell: bash
|
||||
if: github.event_name == 'pull_request' && matrix.platform.os != 'macos-13'
|
||||
|
||||
- name: Change config filename for macOS
|
||||
run: sed -r -i '' 's/\%\%RYUJINX_CONFIG_FILE_NAME\%\%/PRConfig\.json/g;' src/Ryujinx.Common/ReleaseInformation.cs
|
||||
shell: bash
|
||||
if: github.event_name == 'pull_request' && matrix.platform.os == 'macos-13'
|
||||
|
||||
- name: Build
|
||||
run: dotnet build -c "${{ matrix.configuration }}" -p:Version="${{ env.RYUJINX_BASE_VERSION }}" -p:SourceRevisionId="${{ steps.git_short_hash.outputs.result }}" -p:ExtraDefineConstants=DISABLE_UPDATER
|
||||
|
||||
@ -58,46 +57,47 @@ jobs:
|
||||
commands: dotnet test --no-build -c "${{ matrix.configuration }}"
|
||||
timeout-minutes: 10
|
||||
retry-codes: 139
|
||||
if: matrix.platform.name != 'linux-arm64'
|
||||
|
||||
- name: Publish Ryujinx
|
||||
run: dotnet publish -c "${{ matrix.configuration }}" -r "${{ matrix.DOTNET_RUNTIME_IDENTIFIER }}" -o ./publish -p:Version="${{ env.RYUJINX_BASE_VERSION }}" -p:DebugType=embedded -p:SourceRevisionId="${{ steps.git_short_hash.outputs.result }}" -p:ExtraDefineConstants=DISABLE_UPDATER src/Ryujinx --self-contained true
|
||||
if: github.event_name == 'pull_request' && matrix.os != 'macOS-latest'
|
||||
run: dotnet publish -c "${{ matrix.configuration }}" -r "${{ matrix.platform.name }}" -o ./publish -p:Version="${{ env.RYUJINX_BASE_VERSION }}" -p:DebugType=embedded -p:SourceRevisionId="${{ steps.git_short_hash.outputs.result }}" -p:ExtraDefineConstants=DISABLE_UPDATER src/Ryujinx --self-contained true
|
||||
if: github.event_name == 'pull_request' && matrix.platform.os != 'macos-13'
|
||||
|
||||
- name: Publish Ryujinx.Headless.SDL2
|
||||
run: dotnet publish -c "${{ matrix.configuration }}" -r "${{ matrix.DOTNET_RUNTIME_IDENTIFIER }}" -o ./publish_sdl2_headless -p:Version="${{ env.RYUJINX_BASE_VERSION }}" -p:DebugType=embedded -p:SourceRevisionId="${{ steps.git_short_hash.outputs.result }}" -p:ExtraDefineConstants=DISABLE_UPDATER src/Ryujinx.Headless.SDL2 --self-contained true
|
||||
if: github.event_name == 'pull_request' && matrix.os != 'macOS-latest'
|
||||
run: dotnet publish -c "${{ matrix.configuration }}" -r "${{ matrix.platform.name }}" -o ./publish_sdl2_headless -p:Version="${{ env.RYUJINX_BASE_VERSION }}" -p:DebugType=embedded -p:SourceRevisionId="${{ steps.git_short_hash.outputs.result }}" -p:ExtraDefineConstants=DISABLE_UPDATER src/Ryujinx.Headless.SDL2 --self-contained true
|
||||
if: github.event_name == 'pull_request' && matrix.platform.os != 'macos-13'
|
||||
|
||||
- name: Publish Ryujinx.Ava
|
||||
run: dotnet publish -c "${{ matrix.configuration }}" -r "${{ matrix.DOTNET_RUNTIME_IDENTIFIER }}" -o ./publish_ava -p:Version="${{ env.RYUJINX_BASE_VERSION }}" -p:DebugType=embedded -p:SourceRevisionId="${{ steps.git_short_hash.outputs.result }}" -p:ExtraDefineConstants=DISABLE_UPDATER src/Ryujinx.Ava --self-contained true
|
||||
if: github.event_name == 'pull_request' && matrix.os != 'macOS-latest'
|
||||
- name: Publish Ryujinx.Gtk3
|
||||
run: dotnet publish -c "${{ matrix.configuration }}" -r "${{ matrix.platform.name }}" -o ./publish_gtk -p:Version="${{ env.RYUJINX_BASE_VERSION }}" -p:DebugType=embedded -p:SourceRevisionId="${{ steps.git_short_hash.outputs.result }}" -p:ExtraDefineConstants=DISABLE_UPDATER src/Ryujinx.Gtk3 --self-contained true
|
||||
if: github.event_name == 'pull_request' && matrix.platform.os != 'macos-13'
|
||||
|
||||
- name: Set executable bit
|
||||
run: |
|
||||
chmod +x ./publish/Ryujinx ./publish/Ryujinx.sh
|
||||
chmod +x ./publish_sdl2_headless/Ryujinx.Headless.SDL2 ./publish_sdl2_headless/Ryujinx.sh
|
||||
chmod +x ./publish_ava/Ryujinx.Ava ./publish_ava/Ryujinx.sh
|
||||
if: github.event_name == 'pull_request' && matrix.os == 'ubuntu-latest'
|
||||
chmod +x ./publish_gtk/Ryujinx.Gtk3 ./publish_gtk/Ryujinx.sh
|
||||
if: github.event_name == 'pull_request' && matrix.platform.os == 'ubuntu-latest'
|
||||
|
||||
- name: Upload Ryujinx artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: ryujinx-${{ matrix.configuration }}-${{ env.RYUJINX_BASE_VERSION }}+${{ steps.git_short_hash.outputs.result }}-${{ matrix.RELEASE_ZIP_OS_NAME }}
|
||||
name: ryujinx-${{ matrix.configuration }}-${{ env.RYUJINX_BASE_VERSION }}+${{ steps.git_short_hash.outputs.result }}-${{ matrix.platform.zip_os_name }}
|
||||
path: publish
|
||||
if: github.event_name == 'pull_request' && matrix.os != 'macOS-latest'
|
||||
if: github.event_name == 'pull_request' && matrix.platform.os != 'macos-13'
|
||||
|
||||
- name: Upload Ryujinx.Headless.SDL2 artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: sdl2-ryujinx-headless-${{ matrix.configuration }}-${{ env.RYUJINX_BASE_VERSION }}+${{ steps.git_short_hash.outputs.result }}-${{ matrix.RELEASE_ZIP_OS_NAME }}
|
||||
name: sdl2-ryujinx-headless-${{ matrix.configuration }}-${{ env.RYUJINX_BASE_VERSION }}+${{ steps.git_short_hash.outputs.result }}-${{ matrix.platform.zip_os_name }}
|
||||
path: publish_sdl2_headless
|
||||
if: github.event_name == 'pull_request' && matrix.os != 'macOS-latest'
|
||||
if: github.event_name == 'pull_request' && matrix.platform.os != 'macos-13'
|
||||
|
||||
- name: Upload Ryujinx.Ava artifact
|
||||
- name: Upload Ryujinx.Gtk3 artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: ava-ryujinx-${{ matrix.configuration }}-${{ env.RYUJINX_BASE_VERSION }}+${{ steps.git_short_hash.outputs.result }}-${{ matrix.RELEASE_ZIP_OS_NAME }}
|
||||
path: publish_ava
|
||||
if: github.event_name == 'pull_request' && matrix.os != 'macOS-latest'
|
||||
name: gtk-ryujinx-${{ matrix.configuration }}-${{ env.RYUJINX_BASE_VERSION }}+${{ steps.git_short_hash.outputs.result }}-${{ matrix.platform.zip_os_name }}
|
||||
path: publish_gtk
|
||||
if: github.event_name == 'pull_request' && matrix.platform.os != 'macos-13'
|
||||
|
||||
build_macos:
|
||||
name: macOS Universal (${{ matrix.configuration }})
|
||||
@ -135,19 +135,24 @@ jobs:
|
||||
id: git_short_hash
|
||||
run: echo "result=$(git rev-parse --short "${{ github.sha }}")" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Publish macOS Ryujinx.Ava
|
||||
- name: Change config filename
|
||||
run: sed -r --in-place 's/\%\%RYUJINX_CONFIG_FILE_NAME\%\%/PRConfig\.json/g;' src/Ryujinx.Common/ReleaseInformation.cs
|
||||
shell: bash
|
||||
if: github.event_name == 'pull_request'
|
||||
|
||||
- name: Publish macOS Ryujinx
|
||||
run: |
|
||||
./distribution/macos/create_macos_build_ava.sh . publish_tmp_ava publish_ava ./distribution/macos/entitlements.xml "${{ env.RYUJINX_BASE_VERSION }}" "${{ steps.git_short_hash.outputs.result }}" "${{ matrix.configuration }}" "-p:ExtraDefineConstants=DISABLE_UPDATER"
|
||||
./distribution/macos/create_macos_build_ava.sh . publish_tmp publish ./distribution/macos/entitlements.xml "${{ env.RYUJINX_BASE_VERSION }}" "${{ steps.git_short_hash.outputs.result }}" "${{ matrix.configuration }}" "-p:ExtraDefineConstants=DISABLE_UPDATER"
|
||||
|
||||
- name: Publish macOS Ryujinx.Headless.SDL2
|
||||
run: |
|
||||
./distribution/macos/create_macos_build_headless.sh . publish_tmp_headless publish_headless ./distribution/macos/entitlements.xml "${{ env.RYUJINX_BASE_VERSION }}" "${{ steps.git_short_hash.outputs.result }}" "${{ matrix.configuration }}" "-p:ExtraDefineConstants=DISABLE_UPDATER"
|
||||
|
||||
- name: Upload Ryujinx.Ava artifact
|
||||
- name: Upload Ryujinx artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: ava-ryujinx-${{ matrix.configuration }}-${{ env.RYUJINX_BASE_VERSION }}+${{ steps.git_short_hash.outputs.result }}-macos_universal
|
||||
path: "publish_ava/*.tar.gz"
|
||||
name: ryujinx-${{ matrix.configuration }}-${{ env.RYUJINX_BASE_VERSION }}+${{ steps.git_short_hash.outputs.result }}-macos_universal
|
||||
path: "publish/*.tar.gz"
|
||||
if: github.event_name == 'pull_request'
|
||||
|
||||
- name: Upload Ryujinx.Headless.SDL2 artifact
|
||||
|
2
.github/workflows/checks.yml
vendored
2
.github/workflows/checks.yml
vendored
@ -8,7 +8,7 @@ on:
|
||||
- '!.github/**'
|
||||
- '!*.yml'
|
||||
- '!*.config'
|
||||
- '!README.md'
|
||||
- '!*.md'
|
||||
- '.github/workflows/*.yml'
|
||||
|
||||
permissions:
|
||||
|
28
.github/workflows/dotnet.yml
vendored
Normal file
28
.github/workflows/dotnet.yml
vendored
Normal file
@ -0,0 +1,28 @@
|
||||
# This workflow will build a .NET project
|
||||
# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-net
|
||||
|
||||
name: .NET
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ "libryujinx_bionic" ]
|
||||
pull_request:
|
||||
branches: [ "libryujinx_bionic" ]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Setup .NET
|
||||
uses: actions/setup-dotnet@v4
|
||||
with:
|
||||
dotnet-version: 9.0.x
|
||||
- name: Restore dependencies
|
||||
run: dotnet restore
|
||||
- name: Build
|
||||
run: dotnet build -c Release -o build
|
||||
- name: Test
|
||||
run: dotnet test --no-build --verbosity normal
|
72
.github/workflows/flatpak.yml
vendored
72
.github/workflows/flatpak.yml
vendored
@ -51,38 +51,76 @@ jobs:
|
||||
- name: Restore Nuget packages
|
||||
# With .NET 8.0.100, Microsoft.NET.ILLink.Tasks isn't restored by default and only seems to appears when publishing.
|
||||
# So we just publish to grab the dependencies
|
||||
run: dotnet publish -c Release -r linux-x64 Ryujinx/${{ env.RYUJINX_PROJECT_FILE }} --self-contained
|
||||
run: |
|
||||
dotnet publish -c Release -r linux-x64 Ryujinx/${{ env.RYUJINX_PROJECT_FILE }} --self-contained
|
||||
dotnet publish -c Release -r linux-arm64 Ryujinx/${{ env.RYUJINX_PROJECT_FILE }} --self-contained
|
||||
|
||||
- name: Generate nuget_sources.json
|
||||
shell: python
|
||||
run: |
|
||||
import hashlib
|
||||
from pathlib import Path
|
||||
import base64
|
||||
import binascii
|
||||
import json
|
||||
import os
|
||||
import urllib.request
|
||||
|
||||
sources = []
|
||||
|
||||
for path in Path(os.environ['NUGET_PACKAGES']).glob('**/*.nupkg.sha512'):
|
||||
name = path.parent.parent.name
|
||||
version = path.parent.name
|
||||
filename = '{}.{}.nupkg'.format(name, version)
|
||||
url = 'https://api.nuget.org/v3-flatcontainer/{}/{}/{}'.format(name, version, filename)
|
||||
|
||||
with path.open() as fp:
|
||||
sha512 = binascii.hexlify(base64.b64decode(fp.read())).decode('ascii')
|
||||
def create_source_from_external(name, version):
|
||||
full_dir_path = Path(os.environ["NUGET_PACKAGES"]).joinpath(name).joinpath(version)
|
||||
os.makedirs(full_dir_path, exist_ok=True)
|
||||
|
||||
sources.append({
|
||||
'type': 'file',
|
||||
'url': url,
|
||||
'sha512': sha512,
|
||||
'dest': os.environ['NUGET_SOURCES_DESTDIR'],
|
||||
'dest-filename': filename,
|
||||
})
|
||||
filename = "{}.{}.nupkg".format(name, version)
|
||||
url = "https://api.nuget.org/v3-flatcontainer/{}/{}/{}".format(
|
||||
name, version, filename
|
||||
)
|
||||
|
||||
with open('flathub/nuget_sources.json', 'w') as fp:
|
||||
json.dump(sources, fp, indent=4)
|
||||
print(f"Processing {url}...")
|
||||
response = urllib.request.urlopen(url)
|
||||
sha512 = hashlib.sha512(response.read()).hexdigest()
|
||||
|
||||
return {
|
||||
"type": "file",
|
||||
"url": url,
|
||||
"sha512": sha512,
|
||||
"dest": os.environ["NUGET_SOURCES_DESTDIR"],
|
||||
"dest-filename": filename,
|
||||
}
|
||||
|
||||
|
||||
has_added_x64_apphost = False
|
||||
|
||||
for path in Path(os.environ["NUGET_PACKAGES"]).glob("**/*.nupkg.sha512"):
|
||||
name = path.parent.parent.name
|
||||
version = path.parent.name
|
||||
filename = "{}.{}.nupkg".format(name, version)
|
||||
url = "https://api.nuget.org/v3-flatcontainer/{}/{}/{}".format(
|
||||
name, version, filename
|
||||
)
|
||||
|
||||
with path.open() as fp:
|
||||
sha512 = binascii.hexlify(base64.b64decode(fp.read())).decode("ascii")
|
||||
|
||||
sources.append(
|
||||
{
|
||||
"type": "file",
|
||||
"url": url,
|
||||
"sha512": sha512,
|
||||
"dest": os.environ["NUGET_SOURCES_DESTDIR"],
|
||||
"dest-filename": filename,
|
||||
}
|
||||
)
|
||||
|
||||
# .NET will not add current installed application host to the list, force inject it here.
|
||||
if not has_added_x64_apphost and name.startswith('microsoft.netcore.app.host'):
|
||||
sources.append(create_source_from_external("microsoft.netcore.app.host.linux-x64", version))
|
||||
has_added_x64_apphost = True
|
||||
|
||||
with open("flathub/nuget_sources.json", "w") as fp:
|
||||
json.dump(sources, fp, indent=4)
|
||||
|
||||
- name: Update flatpak metadata
|
||||
id: metadata
|
||||
|
41
.github/workflows/mako.yml
vendored
Normal file
41
.github/workflows/mako.yml
vendored
Normal file
@ -0,0 +1,41 @@
|
||||
name: Mako
|
||||
on:
|
||||
discussion:
|
||||
types: [created, edited, answered, unanswered, category_changed]
|
||||
discussion_comment:
|
||||
types: [created, edited]
|
||||
gollum:
|
||||
issue_comment:
|
||||
types: [created, edited]
|
||||
issues:
|
||||
types: [opened, edited, reopened, pinned, milestoned, demilestoned, assigned, unassigned, labeled, unlabeled]
|
||||
pull_request_target:
|
||||
types: [opened, edited, reopened, synchronize, ready_for_review, assigned, unassigned]
|
||||
|
||||
jobs:
|
||||
tasks:
|
||||
name: Run Ryujinx tasks
|
||||
permissions:
|
||||
actions: read
|
||||
contents: read
|
||||
discussions: write
|
||||
issues: write
|
||||
pull-requests: write
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
if: github.event_name == 'pull_request_target'
|
||||
with:
|
||||
# Ensure we pin the source origin as pull_request_target run under forks.
|
||||
fetch-depth: 0
|
||||
repository: Ryujinx/Ryujinx
|
||||
ref: master
|
||||
|
||||
- name: Run Mako command
|
||||
uses: Ryujinx/Ryujinx-Mako@master
|
||||
with:
|
||||
command: exec-ryujinx-tasks
|
||||
args: --event-name "${{ github.event_name }}" --event-path "${{ github.event_path }}" -w "${{ github.workspace }}" "${{ github.repository }}" "${{ github.run_id }}"
|
||||
app_id: ${{ secrets.MAKO_APP_ID }}
|
||||
private_key: ${{ secrets.MAKO_PRIVATE_KEY }}
|
||||
installation_id: ${{ secrets.MAKO_INSTALLATION_ID }}
|
10
.github/workflows/nightly_pr_comment.yml
vendored
10
.github/workflows/nightly_pr_comment.yml
vendored
@ -39,24 +39,24 @@ jobs:
|
||||
return core.error(`No artifacts found`);
|
||||
}
|
||||
let body = `Download the artifacts for this pull request:\n`;
|
||||
let hidden_avalonia_artifacts = `\n\n <details><summary>Experimental GUI (Avalonia)</summary>\n`;
|
||||
let hidden_gtk_artifacts = `\n\n <details><summary>Old GUI (GTK3)</summary>\n`;
|
||||
let hidden_headless_artifacts = `\n\n <details><summary>GUI-less (SDL2)</summary>\n`;
|
||||
let hidden_debug_artifacts = `\n\n <details><summary>Only for Developers</summary>\n`;
|
||||
for (const art of artifacts) {
|
||||
if(art.name.includes('Debug')) {
|
||||
hidden_debug_artifacts += `\n* [${art.name}](https://nightly.link/${owner}/${repo}/actions/artifacts/${art.id}.zip)`;
|
||||
} else if(art.name.includes('ava-ryujinx')) {
|
||||
hidden_avalonia_artifacts += `\n* [${art.name}](https://nightly.link/${owner}/${repo}/actions/artifacts/${art.id}.zip)`;
|
||||
} else if(art.name.includes('gtk-ryujinx')) {
|
||||
hidden_gtk_artifacts += `\n* [${art.name}](https://nightly.link/${owner}/${repo}/actions/artifacts/${art.id}.zip)`;
|
||||
} else if(art.name.includes('sdl2-ryujinx-headless')) {
|
||||
hidden_headless_artifacts += `\n* [${art.name}](https://nightly.link/${owner}/${repo}/actions/artifacts/${art.id}.zip)`;
|
||||
} else {
|
||||
body += `\n* [${art.name}](https://nightly.link/${owner}/${repo}/actions/artifacts/${art.id}.zip)`;
|
||||
}
|
||||
}
|
||||
hidden_avalonia_artifacts += `\n</details>`;
|
||||
hidden_gtk_artifacts += `\n</details>`;
|
||||
hidden_headless_artifacts += `\n</details>`;
|
||||
hidden_debug_artifacts += `\n</details>`;
|
||||
body += hidden_avalonia_artifacts;
|
||||
body += hidden_gtk_artifacts;
|
||||
body += hidden_headless_artifacts;
|
||||
body += hidden_debug_artifacts;
|
||||
|
||||
|
19
.github/workflows/pr_triage.yml
vendored
19
.github/workflows/pr_triage.yml
vendored
@ -21,27 +21,8 @@ jobs:
|
||||
repository: Ryujinx/Ryujinx
|
||||
ref: master
|
||||
|
||||
- name: Checkout Ryujinx-Mako
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
repository: Ryujinx/Ryujinx-Mako
|
||||
ref: master
|
||||
path: '.ryujinx-mako'
|
||||
|
||||
- name: Setup Ryujinx-Mako
|
||||
uses: ./.ryujinx-mako/.github/actions/setup-mako
|
||||
|
||||
- name: Update labels based on changes
|
||||
uses: actions/labeler@v5
|
||||
with:
|
||||
sync-labels: true
|
||||
dot: true
|
||||
|
||||
- name: Assign reviewers
|
||||
run: |
|
||||
poetry -n -C .ryujinx-mako run ryujinx-mako update-reviewers ${{ github.repository }} ${{ github.event.pull_request.number }} .github/reviewers.yml
|
||||
shell: bash
|
||||
env:
|
||||
MAKO_APP_ID: ${{ secrets.MAKO_APP_ID }}
|
||||
MAKO_PRIVATE_KEY: ${{ secrets.MAKO_PRIVATE_KEY }}
|
||||
MAKO_INSTALLATION_ID: ${{ secrets.MAKO_INSTALLATION_ID }}
|
||||
|
76
.github/workflows/release.yml
vendored
76
.github/workflows/release.yml
vendored
@ -10,7 +10,7 @@ on:
|
||||
- '*.yml'
|
||||
- '*.json'
|
||||
- '*.config'
|
||||
- 'README.md'
|
||||
- '*.md'
|
||||
|
||||
concurrency: release
|
||||
|
||||
@ -44,30 +44,34 @@ jobs:
|
||||
sha: context.sha
|
||||
})
|
||||
|
||||
- name: Create release
|
||||
uses: ncipollo/release-action@v1
|
||||
with:
|
||||
name: ${{ steps.version_info.outputs.build_version }}
|
||||
tag: ${{ steps.version_info.outputs.build_version }}
|
||||
body: "For more information about this release please check out the official [Changelog](https://github.com/Ryujinx/Ryujinx/wiki/Changelog)."
|
||||
omitBodyDuringUpdate: true
|
||||
owner: ${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_OWNER }}
|
||||
repo: ${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_REPO }}
|
||||
token: ${{ secrets.RELEASE_TOKEN }}
|
||||
|
||||
release:
|
||||
name: Release ${{ matrix.OS_NAME }}
|
||||
runs-on: ${{ matrix.os }}
|
||||
name: Release for ${{ matrix.platform.name }}
|
||||
runs-on: ${{ matrix.platform.os }}
|
||||
timeout-minutes: ${{ fromJSON(vars.JOB_TIMEOUT) }}
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ ubuntu-latest, windows-latest ]
|
||||
include:
|
||||
- os: ubuntu-latest
|
||||
OS_NAME: Linux x64
|
||||
DOTNET_RUNTIME_IDENTIFIER: linux-x64
|
||||
RELEASE_ZIP_OS_NAME: linux_x64
|
||||
|
||||
- os: windows-latest
|
||||
OS_NAME: Windows x64
|
||||
DOTNET_RUNTIME_IDENTIFIER: win-x64
|
||||
RELEASE_ZIP_OS_NAME: win_x64
|
||||
platform:
|
||||
- { name: win-x64, os: windows-latest, zip_os_name: win_x64 }
|
||||
- { name: linux-x64, os: ubuntu-latest, zip_os_name: linux_x64 }
|
||||
- { name: linux-arm64, os: ubuntu-latest, zip_os_name: linux_arm64 }
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- uses: actions/setup-dotnet@v4
|
||||
with:
|
||||
global-json-file: global.json
|
||||
|
||||
|
||||
- name: Overwrite csc problem matcher
|
||||
run: echo "::add-matcher::.github/csc.json"
|
||||
|
||||
@ -85,6 +89,7 @@ jobs:
|
||||
sed -r --in-place 's/\%\%RYUJINX_TARGET_RELEASE_CHANNEL_NAME\%\%/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_NAME }}/g;' src/Ryujinx.Common/ReleaseInformation.cs
|
||||
sed -r --in-place 's/\%\%RYUJINX_TARGET_RELEASE_CHANNEL_OWNER\%\%/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_OWNER }}/g;' src/Ryujinx.Common/ReleaseInformation.cs
|
||||
sed -r --in-place 's/\%\%RYUJINX_TARGET_RELEASE_CHANNEL_REPO\%\%/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_REPO }}/g;' src/Ryujinx.Common/ReleaseInformation.cs
|
||||
sed -r --in-place 's/\%\%RYUJINX_CONFIG_FILE_NAME\%\%/Config\.json/g;' src/Ryujinx.Common/ReleaseInformation.cs
|
||||
shell: bash
|
||||
|
||||
- name: Create output dir
|
||||
@ -92,42 +97,36 @@ jobs:
|
||||
|
||||
- name: Publish
|
||||
run: |
|
||||
dotnet publish -c Release -r "${{ matrix.DOTNET_RUNTIME_IDENTIFIER }}" -o ./publish_gtk/publish -p:Version="${{ steps.version_info.outputs.build_version }}" -p:SourceRevisionId="${{ steps.version_info.outputs.git_short_hash }}" -p:DebugType=embedded src/Ryujinx --self-contained true
|
||||
dotnet publish -c Release -r "${{ matrix.DOTNET_RUNTIME_IDENTIFIER }}" -o ./publish_sdl2_headless/publish -p:Version="${{ steps.version_info.outputs.build_version }}" -p:SourceRevisionId="${{ steps.version_info.outputs.git_short_hash }}" -p:DebugType=embedded src/Ryujinx.Headless.SDL2 --self-contained true
|
||||
dotnet publish -c Release -r "${{ matrix.DOTNET_RUNTIME_IDENTIFIER }}" -o ./publish_ava/publish -p:Version="${{ steps.version_info.outputs.build_version }}" -p:SourceRevisionId="${{ steps.version_info.outputs.git_short_hash }}" -p:DebugType=embedded src/Ryujinx.Ava --self-contained true
|
||||
dotnet publish -c Release -r "${{ matrix.platform.name }}" -o ./publish_ava/publish -p:Version="${{ steps.version_info.outputs.build_version }}" -p:SourceRevisionId="${{ steps.version_info.outputs.git_short_hash }}" -p:DebugType=embedded src/Ryujinx --self-contained true
|
||||
dotnet publish -c Release -r "${{ matrix.platform.name }}" -o ./publish_sdl2_headless/publish -p:Version="${{ steps.version_info.outputs.build_version }}" -p:SourceRevisionId="${{ steps.version_info.outputs.git_short_hash }}" -p:DebugType=embedded src/Ryujinx.Headless.SDL2 --self-contained true
|
||||
|
||||
- name: Packing Windows builds
|
||||
if: matrix.os == 'windows-latest'
|
||||
if: matrix.platform.os == 'windows-latest'
|
||||
run: |
|
||||
pushd publish_gtk
|
||||
7z a ../release_output/ryujinx-${{ steps.version_info.outputs.build_version }}-win_x64.zip publish
|
||||
pushd publish_ava
|
||||
cp publish/Ryujinx.exe publish/Ryujinx.Ava.exe
|
||||
7z a ../release_output/ryujinx-${{ steps.version_info.outputs.build_version }}-${{ matrix.platform.zip_os_name }}.zip publish
|
||||
7z a ../release_output/test-ava-ryujinx-${{ steps.version_info.outputs.build_version }}-${{ matrix.platform.zip_os_name }}.zip publish
|
||||
popd
|
||||
|
||||
pushd publish_sdl2_headless
|
||||
7z a ../release_output/sdl2-ryujinx-headless-${{ steps.version_info.outputs.build_version }}-win_x64.zip publish
|
||||
popd
|
||||
|
||||
pushd publish_ava
|
||||
7z a ../release_output/test-ava-ryujinx-${{ steps.version_info.outputs.build_version }}-win_x64.zip publish
|
||||
7z a ../release_output/sdl2-ryujinx-headless-${{ steps.version_info.outputs.build_version }}-${{ matrix.platform.zip_os_name }}.zip publish
|
||||
popd
|
||||
shell: bash
|
||||
|
||||
- name: Packing Linux builds
|
||||
if: matrix.os == 'ubuntu-latest'
|
||||
if: matrix.platform.os == 'ubuntu-latest'
|
||||
run: |
|
||||
pushd publish_gtk
|
||||
chmod +x publish/Ryujinx.sh publish/Ryujinx
|
||||
tar -czvf ../release_output/ryujinx-${{ steps.version_info.outputs.build_version }}-linux_x64.tar.gz publish
|
||||
pushd publish_ava
|
||||
cp publish/Ryujinx publish/Ryujinx.Ava
|
||||
chmod +x publish/Ryujinx.sh publish/Ryujinx.Ava publish/Ryujinx
|
||||
tar -czvf ../release_output/ryujinx-${{ steps.version_info.outputs.build_version }}-${{ matrix.platform.zip_os_name }}.tar.gz publish
|
||||
tar -czvf ../release_output/test-ava-ryujinx-${{ steps.version_info.outputs.build_version }}-${{ matrix.platform.zip_os_name }}.tar.gz publish
|
||||
popd
|
||||
|
||||
pushd publish_sdl2_headless
|
||||
chmod +x publish/Ryujinx.sh publish/Ryujinx.Headless.SDL2
|
||||
tar -czvf ../release_output/sdl2-ryujinx-headless-${{ steps.version_info.outputs.build_version }}-linux_x64.tar.gz publish
|
||||
popd
|
||||
|
||||
pushd publish_ava
|
||||
chmod +x publish/Ryujinx.sh publish/Ryujinx.Ava
|
||||
tar -czvf ../release_output/test-ava-ryujinx-${{ steps.version_info.outputs.build_version }}-linux_x64.tar.gz publish
|
||||
tar -czvf ../release_output/sdl2-ryujinx-headless-${{ steps.version_info.outputs.build_version }}-${{ matrix.platform.zip_os_name }}.tar.gz publish
|
||||
popd
|
||||
shell: bash
|
||||
|
||||
@ -186,12 +185,13 @@ jobs:
|
||||
sed -r --in-place 's/\%\%RYUJINX_TARGET_RELEASE_CHANNEL_NAME\%\%/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_NAME }}/g;' src/Ryujinx.Common/ReleaseInformation.cs
|
||||
sed -r --in-place 's/\%\%RYUJINX_TARGET_RELEASE_CHANNEL_OWNER\%\%/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_OWNER }}/g;' src/Ryujinx.Common/ReleaseInformation.cs
|
||||
sed -r --in-place 's/\%\%RYUJINX_TARGET_RELEASE_CHANNEL_REPO\%\%/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_REPO }}/g;' src/Ryujinx.Common/ReleaseInformation.cs
|
||||
sed -r --in-place 's/\%\%RYUJINX_CONFIG_FILE_NAME\%\%/Config\.json/g;' src/Ryujinx.Common/ReleaseInformation.cs
|
||||
shell: bash
|
||||
|
||||
- name: Publish macOS Ryujinx.Ava
|
||||
- name: Publish macOS Ryujinx
|
||||
run: |
|
||||
./distribution/macos/create_macos_build_ava.sh . publish_tmp_ava publish_ava ./distribution/macos/entitlements.xml "${{ steps.version_info.outputs.build_version }}" "${{ steps.version_info.outputs.git_short_hash }}" Release
|
||||
|
||||
|
||||
- name: Publish macOS Ryujinx.Headless.SDL2
|
||||
run: |
|
||||
./distribution/macos/create_macos_build_headless.sh . publish_tmp_headless publish_headless ./distribution/macos/entitlements.xml "${{ steps.version_info.outputs.build_version }}" "${{ steps.version_info.outputs.git_short_hash }}" Release
|
||||
|
67
.gitignore
vendored
67
.gitignore
vendored
@ -47,7 +47,6 @@ build/
|
||||
*.vssscc
|
||||
.builds
|
||||
*.pidb
|
||||
*.log
|
||||
*.scc
|
||||
|
||||
# Visual C++ cache files
|
||||
@ -176,3 +175,69 @@ PublishProfiles/
|
||||
# Glade backup files
|
||||
*.glade~
|
||||
src/MeloNX/MeloNX/Dependencies/Dynamic Libraries/Ryujinx.Headless.SDL2.dylib
|
||||
|
||||
# SWIFT GITIGNORE
|
||||
# Xcode
|
||||
#
|
||||
# gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore
|
||||
|
||||
## User settings
|
||||
xcuserdata/
|
||||
|
||||
## Obj-C/Swift specific
|
||||
*.hmap
|
||||
|
||||
## App packaging
|
||||
*.ipa
|
||||
*.dSYM.zip
|
||||
*.dSYM
|
||||
|
||||
## Playgrounds
|
||||
timeline.xctimeline
|
||||
playground.xcworkspace
|
||||
|
||||
# Swift Package Manager
|
||||
#
|
||||
# Add this line if you want to avoid checking in source code from Swift Package Manager dependencies.
|
||||
# Packages/
|
||||
# Package.pins
|
||||
# Package.resolved
|
||||
# *.xcodeproj
|
||||
#
|
||||
# Xcode automatically generates this directory with a .xcworkspacedata file and xcuserdata
|
||||
# hence it is not needed unless you have added a package configuration file to your project
|
||||
# .swiftpm
|
||||
|
||||
.build/
|
||||
|
||||
# CocoaPods
|
||||
#
|
||||
# We recommend against adding the Pods directory to your .gitignore. However
|
||||
# you should judge for yourself, the pros and cons are mentioned at:
|
||||
# https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
|
||||
#
|
||||
# Pods/
|
||||
#
|
||||
# Add this line if you want to avoid checking in source code from the Xcode workspace
|
||||
# *.xcworkspace
|
||||
|
||||
# Carthage
|
||||
#
|
||||
# Add this line if you want to avoid checking in source code from Carthage dependencies.
|
||||
# Carthage/Checkouts
|
||||
|
||||
Carthage/Build/
|
||||
|
||||
# fastlane
|
||||
#
|
||||
# It is recommended to not store the screenshots in the git repo.
|
||||
# Instead, use fastlane to re-generate the screenshots whenever they are needed.
|
||||
# For more information about the recommended setup visit:
|
||||
# https://docs.fastlane.tools/best-practices/source-control/#source-control
|
||||
|
||||
fastlane/report.xml
|
||||
fastlane/Preview.html
|
||||
fastlane/screenshots/**/*.png
|
||||
fastlane/test_output
|
||||
/src/RyujinxAndroid/.idea
|
||||
/src/RyujinxAndroid/app/src/main/jniLibs/arm64-v8a
|
||||
|
@ -5,6 +5,7 @@
|
||||
Before you begin, ensure you have the following installed:
|
||||
|
||||
- [**.NET 8.0**](https://dotnet.microsoft.com/en-us/download/dotnet/8.0)
|
||||
- [**Xcode**](https://apps.apple.com/de/app/xcode/id497799835?l=en-GB&mt=12$0)
|
||||
- A Mac running **macOS**
|
||||
|
||||
## Compilation Steps
|
||||
|
@ -3,39 +3,40 @@
|
||||
<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.10" />
|
||||
<PackageVersion Include="Avalonia.Controls.DataGrid" Version="11.0.10" />
|
||||
<PackageVersion Include="Avalonia.Desktop" Version="11.0.10" />
|
||||
<PackageVersion Include="Avalonia.Diagnostics" Version="11.0.10" />
|
||||
<PackageVersion Include="Avalonia.Markup.Xaml.Loader" Version="11.0.10" />
|
||||
<PackageVersion Include="Avalonia.Svg" Version="11.0.0.18" />
|
||||
<PackageVersion Include="Avalonia.Svg.Skia" Version="11.0.0.18" />
|
||||
<PackageVersion Include="CommandLineParser" Version="2.9.1" />
|
||||
<PackageVersion Include="Concentus" Version="1.1.7" />
|
||||
<PackageVersion Include="Concentus" Version="2.2.0" />
|
||||
<PackageVersion Include="DiscordRichPresence" Version="1.2.1.24" />
|
||||
<PackageVersion Include="DynamicData" Version="7.14.2" />
|
||||
<PackageVersion Include="FluentAvaloniaUI" Version="2.0.4" />
|
||||
<PackageVersion Include="DynamicData" Version="9.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.NET.Test.Sdk" Version="17.8.0" />
|
||||
<PackageVersion Include="Microsoft.IO.RecyclableMemoryStream" Version="2.3.2" />
|
||||
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp" Version="4.9.2" />
|
||||
<PackageVersion Include="Microsoft.IdentityModel.JsonWebTokens" Version="8.0.1" />
|
||||
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.9.0" />
|
||||
<PackageVersion Include="Microsoft.IO.RecyclableMemoryStream" Version="3.0.1" />
|
||||
<PackageVersion Include="MsgPack.Cli" Version="1.0.1" />
|
||||
<PackageVersion Include="NetCoreServer" Version="7.0.0" />
|
||||
<PackageVersion Include="NetCoreServer" Version="8.0.7" />
|
||||
<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" Version="4.8.2" />
|
||||
<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.Nvdec.Dependencies" Version="5.0.3-build14" />
|
||||
<PackageVersion Include="Ryujinx.Graphics.Vulkan.Dependencies.MoltenVK" Version="1.2.3" />
|
||||
<PackageVersion Include="Ryujinx.GtkSharp" Version="3.24.24.59-ryujinx" />
|
||||
<PackageVersion Include="Ryujinx.SDL2-CS" Version="2.28.1-build28" />
|
||||
<PackageVersion Include="Ryujinx.SDL2-CS" Version="2.30.0-build32" />
|
||||
<PackageVersion Include="securifybv.ShellLink" Version="0.1.0" />
|
||||
<PackageVersion Include="shaderc.net" Version="0.1.0" />
|
||||
<PackageVersion Include="SharpZipLib" Version="1.4.2" />
|
||||
@ -50,5 +51,6 @@
|
||||
<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.5.0" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
10
README.md
10
README.md
@ -6,6 +6,9 @@
|
||||
|
||||
<h1 align="center">MeloNX</h1>
|
||||
|
||||
## Documentation
|
||||
|
||||
If you are planning to contribute or just want to learn more about this project please read through our [documentation](docs/README.md).
|
||||
|
||||
|
||||
<p align="center">
|
||||
@ -17,14 +20,15 @@
|
||||
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 3
|
||||
# Compatibility
|
||||
|
||||
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>.
|
||||
MeloNX works on iPhone XS/XR and later and iPad 8th Gen and later. Check out the Compatibility on the <a href="https://melonx.org/compatibility/" target="_blank">website</a>.
|
||||
|
||||
# Usage
|
||||
|
||||
## FAQ
|
||||
- MeloNX is made for iOS 17+, iOS 15 - 16 is supported but will have issues.
|
||||
- MeloNX is made for iOS 17+, on iOS 15 - 16 MeloNX can be installed but will have issues or may not work at all.
|
||||
- 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.
|
||||
@ -60,6 +64,8 @@ If having Issues installing firmware (Make sure your Keys are installed first)
|
||||
|
||||
### Xcode
|
||||
|
||||
**NOTE: These Xcode builds are nightly and may have unfinished features.**
|
||||
|
||||
1. **Compile Guide**
|
||||
- Visit the [guide here](https://git.743378673.xyz/MeloNX/MeloNX/src/branch/XC-ios-ht/Compile.md).
|
||||
|
||||
|
25
Ryujinx.sln
25
Ryujinx.sln
@ -3,7 +3,7 @@ Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 17
|
||||
VisualStudioVersion = 17.1.32228.430
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx", "src\Ryujinx\Ryujinx.csproj", "{074045D4-3ED2-4711-9169-E385F2BFB5A0}"
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Gtk3", "src\Ryujinx.Gtk3\Ryujinx.Gtk3.csproj", "{074045D4-3ED2-4711-9169-E385F2BFB5A0}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Tests", "src\Ryujinx.Tests\Ryujinx.Tests.csproj", "{EBB55AEA-C7D7-4DEB-BF96-FA1789E225E9}"
|
||||
EndProject
|
||||
@ -69,9 +69,9 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Headless.SDL2", "sr
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Graphics.Nvdec.FFmpeg", "src\Ryujinx.Graphics.Nvdec.FFmpeg\Ryujinx.Graphics.Nvdec.FFmpeg.csproj", "{BEE1C184-C9A4-410B-8DFC-FB74D5C93AEB}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Ava", "src\Ryujinx.Ava\Ryujinx.Ava.csproj", "{7C1B2721-13DA-4B62-B046-C626605ECCE6}"
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx", "src\Ryujinx\Ryujinx.csproj", "{7C1B2721-13DA-4B62-B046-C626605ECCE6}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Ui.Common", "src\Ryujinx.Ui.Common\Ryujinx.Ui.Common.csproj", "{BA161CA0-CD65-4E6E-B644-51C8D1E542DC}"
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.UI.Common", "src\Ryujinx.UI.Common\Ryujinx.UI.Common.csproj", "{BA161CA0-CD65-4E6E-B644-51C8D1E542DC}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Horizon.Generators", "src\Ryujinx.Horizon.Generators\Ryujinx.Horizon.Generators.csproj", "{6AE2A5E8-4C5A-48B9-997B-E1455C0355C6}"
|
||||
EndProject
|
||||
@ -79,7 +79,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Graphics.Vulkan", "
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Spv.Generator", "src\Spv.Generator\Spv.Generator.csproj", "{2BCB3D7A-38C0-4FE7-8FDA-374C6AD56D0E}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Ui.LocaleGenerator", "src\Ryujinx.Ui.LocaleGenerator\Ryujinx.Ui.LocaleGenerator.csproj", "{77D01AD9-2C98-478E-AE1D-8F7100738FB4}"
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.UI.LocaleGenerator", "src\Ryujinx.UI.LocaleGenerator\Ryujinx.UI.LocaleGenerator.csproj", "{77D01AD9-2C98-478E-AE1D-8F7100738FB4}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Horizon.Common", "src\Ryujinx.Horizon.Common\Ryujinx.Horizon.Common.csproj", "{77F96ECE-4952-42DB-A528-DED25572A573}"
|
||||
EndProject
|
||||
@ -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}") = "Ryujinx.HLE.Generators", "src\Ryujinx.HLE.Generators\Ryujinx.HLE.Generators.csproj", "{B575BCDE-2FD8-4A5D-8756-31CDD7FE81F0}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LibRyujinx", "src\LibRyujinx\LibRyujinx.csproj", "{5BBF478C-A520-41E7-9B88-890AD26766B8}"
|
||||
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,17 @@ 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
|
||||
{B575BCDE-2FD8-4A5D-8756-31CDD7FE81F0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{B575BCDE-2FD8-4A5D-8756-31CDD7FE81F0}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{B575BCDE-2FD8-4A5D-8756-31CDD7FE81F0}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{B575BCDE-2FD8-4A5D-8756-31CDD7FE81F0}.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
|
||||
{63D2C96B-5194-4592-BC91-30BEB11C06BD}.Debug|Any CPU.ActiveCfg = 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
|
||||
|
@ -4,6 +4,8 @@
|
||||
<s:String x:Key="/Default/CodeStyle/CSharpVarKeywordUsage/ForOtherTypes/@EntryValue">UseExplicitType</s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/CSharpVarKeywordUsage/ForSimpleTypes/@EntryValue">UseExplicitType</s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=TypesAndNamespaces/@EntryIndexedValue"><Policy Inspect="True" Prefix="" Suffix="" Style="AaBb"><ExtraRule Prefix="I" Suffix="" Style="AaBb" /></Policy></s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/UserRules/=a0b4bc4d_002Dd13b_002D4a37_002Db37e_002Dc9c6864e4302/@EntryIndexedValue"><Policy><Descriptor Staticness="Any" AccessRightKinds="Any" Description="Types and namespaces"><ElementKinds><Kind Name="NAMESPACE" /><Kind Name="CLASS" /><Kind Name="STRUCT" /><Kind Name="ENUM" /><Kind Name="DELEGATE" /></ElementKinds></Descriptor><Policy Inspect="True" Prefix="" Suffix="" Style="AaBb"><ExtraRule Prefix="I" Suffix="" Style="AaBb" /></Policy></Policy></s:String>
|
||||
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EPredefinedNamingRulesToUserRulesUpgrade/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=ASET/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=Astc/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=Luma/@EntryIndexedValue">True</s:Boolean>
|
||||
|
@ -4,7 +4,7 @@ Name=Ryujinx
|
||||
Type=Application
|
||||
Icon=Ryujinx
|
||||
Exec=Ryujinx.sh %f
|
||||
Comment=Plays Nintendo Switch applications
|
||||
Comment=A Nintendo Switch Emulator
|
||||
GenericName=Nintendo Switch Emulator
|
||||
Terminal=false
|
||||
Categories=Game;Emulator;
|
||||
|
15
distribution/linux/Ryujinx.sh
Normal file → Executable file
15
distribution/linux/Ryujinx.sh
Normal file → Executable file
@ -1,20 +1,23 @@
|
||||
#!/bin/sh
|
||||
|
||||
SCRIPT_DIR=$(dirname "$(realpath "$0")")
|
||||
RYUJINX_BIN="Ryujinx"
|
||||
|
||||
if [ -f "$SCRIPT_DIR/Ryujinx.Ava" ]; then
|
||||
RYUJINX_BIN="Ryujinx.Ava"
|
||||
fi
|
||||
|
||||
if [ -f "$SCRIPT_DIR/Ryujinx.Headless.SDL2" ]; then
|
||||
RYUJINX_BIN="Ryujinx.Headless.SDL2"
|
||||
fi
|
||||
|
||||
if [ -f "$SCRIPT_DIR/Ryujinx" ]; then
|
||||
RYUJINX_BIN="Ryujinx"
|
||||
fi
|
||||
|
||||
if [ -z "$RYUJINX_BIN" ]; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
COMMAND="env DOTNET_EnableAlternateStackCheck=1"
|
||||
|
||||
if command -v gamemoderun > /dev/null 2>&1; then
|
||||
COMMAND="$COMMAND gamemoderun"
|
||||
fi
|
||||
|
||||
$COMMAND "$SCRIPT_DIR/$RYUJINX_BIN" "$@"
|
||||
exec $COMMAND "$SCRIPT_DIR/$RYUJINX_BIN" "$@"
|
||||
|
@ -14,8 +14,8 @@ mkdir "$APP_BUNDLE_DIRECTORY/Contents/Frameworks"
|
||||
mkdir "$APP_BUNDLE_DIRECTORY/Contents/MacOS"
|
||||
mkdir "$APP_BUNDLE_DIRECTORY/Contents/Resources"
|
||||
|
||||
# Copy executables first
|
||||
cp "$PUBLISH_DIRECTORY/Ryujinx.Ava" "$APP_BUNDLE_DIRECTORY/Contents/MacOS/Ryujinx"
|
||||
# Copy executable and nsure executable can be executed
|
||||
cp "$PUBLISH_DIRECTORY/Ryujinx" "$APP_BUNDLE_DIRECTORY/Contents/MacOS/Ryujinx"
|
||||
chmod u+x "$APP_BUNDLE_DIRECTORY/Contents/MacOS/Ryujinx"
|
||||
|
||||
# Then all libraries
|
||||
|
@ -22,9 +22,9 @@ EXTRA_ARGS=$8
|
||||
|
||||
if [ "$VERSION" == "1.1.0" ];
|
||||
then
|
||||
RELEASE_TAR_FILE_NAME=test-ava-ryujinx-$CONFIGURATION-$VERSION+$SOURCE_REVISION_ID-macos_universal.app.tar
|
||||
RELEASE_TAR_FILE_NAME=ryujinx-$CONFIGURATION-$VERSION+$SOURCE_REVISION_ID-macos_universal.app.tar
|
||||
else
|
||||
RELEASE_TAR_FILE_NAME=test-ava-ryujinx-$VERSION-macos_universal.app.tar
|
||||
RELEASE_TAR_FILE_NAME=ryujinx-$VERSION-macos_universal.app.tar
|
||||
fi
|
||||
|
||||
ARM64_APP_BUNDLE="$TEMP_DIRECTORY/output_arm64/Ryujinx.app"
|
||||
@ -38,9 +38,9 @@ mkdir -p "$TEMP_DIRECTORY"
|
||||
DOTNET_COMMON_ARGS=(-p:DebugType=embedded -p:Version="$VERSION" -p:SourceRevisionId="$SOURCE_REVISION_ID" --self-contained true $EXTRA_ARGS)
|
||||
|
||||
dotnet restore
|
||||
dotnet build -c "$CONFIGURATION" src/Ryujinx.Ava
|
||||
dotnet publish -c "$CONFIGURATION" -r osx-arm64 -o "$TEMP_DIRECTORY/publish_arm64" "${DOTNET_COMMON_ARGS[@]}" src/Ryujinx.Ava
|
||||
dotnet publish -c "$CONFIGURATION" -r osx-x64 -o "$TEMP_DIRECTORY/publish_x64" "${DOTNET_COMMON_ARGS[@]}" src/Ryujinx.Ava
|
||||
dotnet build -c "$CONFIGURATION" src/Ryujinx
|
||||
dotnet publish -c "$CONFIGURATION" -r osx-arm64 -o "$TEMP_DIRECTORY/publish_arm64" "${DOTNET_COMMON_ARGS[@]}" src/Ryujinx
|
||||
dotnet publish -c "$CONFIGURATION" -r osx-x64 -o "$TEMP_DIRECTORY/publish_x64" "${DOTNET_COMMON_ARGS[@]}" src/Ryujinx
|
||||
|
||||
# Get rid of the support library for ARMeilleure for x64 (that's only for arm64)
|
||||
rm -rf "$TEMP_DIRECTORY/publish_x64/libarmeilleure-jitsupport.dylib"
|
||||
@ -108,6 +108,13 @@ tar --exclude "Ryujinx.app/Contents/MacOS/Ryujinx" -cvf "$RELEASE_TAR_FILE_NAME"
|
||||
python3 "$BASE_DIR/distribution/misc/add_tar_exec.py" "$RELEASE_TAR_FILE_NAME" "Ryujinx.app/Contents/MacOS/Ryujinx" "Ryujinx.app/Contents/MacOS/Ryujinx"
|
||||
gzip -9 < "$RELEASE_TAR_FILE_NAME" > "$RELEASE_TAR_FILE_NAME.gz"
|
||||
rm "$RELEASE_TAR_FILE_NAME"
|
||||
|
||||
# Create legacy update package for Avalonia to not left behind old testers.
|
||||
if [ "$VERSION" != "1.1.0" ];
|
||||
then
|
||||
cp $RELEASE_TAR_FILE_NAME.gz test-ava-ryujinx-$VERSION-macos_universal.app.tar.gz
|
||||
fi
|
||||
|
||||
popd
|
||||
|
||||
echo "Done"
|
8
distribution/macos/shortcut-launch-script.sh
Normal file
8
distribution/macos/shortcut-launch-script.sh
Normal file
@ -0,0 +1,8 @@
|
||||
#!/bin/sh
|
||||
launch_arch="$(uname -m)"
|
||||
if [ "$(sysctl -in sysctl.proc_translated)" = "1" ]
|
||||
then
|
||||
launch_arch="arm64"
|
||||
fi
|
||||
|
||||
arch -$launch_arch {0} {1}
|
@ -33,8 +33,3 @@ Project Docs
|
||||
=================
|
||||
|
||||
To be added. Many project files will contain basic XML docs for key functions and classes in the meantime.
|
||||
|
||||
Other Information
|
||||
=================
|
||||
|
||||
- N/A
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"sdk": {
|
||||
"version": "8.0.100",
|
||||
"version": "9.0.100-preview.6.24328.19",
|
||||
"rollForward": "latestFeature"
|
||||
}
|
||||
}
|
||||
|
@ -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>
|
||||
|
@ -237,7 +237,7 @@ namespace ARMeilleure.CodeGen.Arm64
|
||||
long originalPosition = _stream.Position;
|
||||
|
||||
_stream.Seek(0, SeekOrigin.Begin);
|
||||
_stream.Read(code, 0, code.Length);
|
||||
_stream.ReadExactly(code, 0, code.Length);
|
||||
_stream.Seek(originalPosition, SeekOrigin.Begin);
|
||||
|
||||
RelocInfo relocInfo;
|
||||
|
@ -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);
|
||||
|
@ -251,7 +251,20 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
|
||||
}
|
||||
}
|
||||
|
||||
int selectedReg = GetHighestValueIndex(freePositions);
|
||||
// If this is a copy destination variable, we prefer the register used for the copy source.
|
||||
// If the register is available, then the copy can be eliminated later as both source
|
||||
// and destination will use the same register.
|
||||
int selectedReg;
|
||||
|
||||
if (current.TryGetCopySourceRegister(out int preferredReg) && freePositions[preferredReg] >= current.GetEnd())
|
||||
{
|
||||
selectedReg = preferredReg;
|
||||
}
|
||||
else
|
||||
{
|
||||
selectedReg = GetHighestValueIndex(freePositions);
|
||||
}
|
||||
|
||||
int selectedNextUse = freePositions[selectedReg];
|
||||
|
||||
// Intervals starts and ends at odd positions, unless they span an entire
|
||||
@ -431,7 +444,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
|
||||
}
|
||||
}
|
||||
|
||||
private static int GetHighestValueIndex(Span<int> span)
|
||||
private static int GetHighestValueIndex(ReadOnlySpan<int> span)
|
||||
{
|
||||
int highest = int.MinValue;
|
||||
|
||||
@ -798,12 +811,12 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
|
||||
// The "visited" state is stored in the MSB of the local's value.
|
||||
const ulong VisitedMask = 1ul << 63;
|
||||
|
||||
bool IsVisited(Operand local)
|
||||
static bool IsVisited(Operand local)
|
||||
{
|
||||
return (local.GetValueUnsafe() & VisitedMask) != 0;
|
||||
}
|
||||
|
||||
void SetVisited(Operand local)
|
||||
static void SetVisited(Operand local)
|
||||
{
|
||||
local.GetValueUnsafe() |= VisitedMask;
|
||||
}
|
||||
@ -826,9 +839,25 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
|
||||
{
|
||||
dest.NumberLocal(_intervals.Count);
|
||||
|
||||
_intervals.Add(new LiveInterval(dest));
|
||||
LiveInterval interval = new LiveInterval(dest);
|
||||
_intervals.Add(interval);
|
||||
|
||||
SetVisited(dest);
|
||||
|
||||
// If this is a copy (or copy-like operation), set the copy source interval as well.
|
||||
// This is used for register preferencing later on, which allows the copy to be eliminated
|
||||
// in some cases.
|
||||
if (node.Instruction == Instruction.Copy || node.Instruction == Instruction.ZeroExtend32)
|
||||
{
|
||||
Operand source = node.GetSource(0);
|
||||
|
||||
if (source.Kind == OperandKind.LocalVariable &&
|
||||
source.GetLocalNumber() > 0 &&
|
||||
(node.Instruction == Instruction.Copy || source.Type == OperandType.I32))
|
||||
{
|
||||
interval.SetCopySource(_intervals[source.GetLocalNumber()]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -19,6 +19,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
|
||||
public LiveRange CurrRange;
|
||||
|
||||
public LiveInterval Parent;
|
||||
public LiveInterval CopySource;
|
||||
|
||||
public UseList Uses;
|
||||
public LiveIntervalList Children;
|
||||
@ -37,6 +38,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
|
||||
private ref LiveRange CurrRange => ref _data->CurrRange;
|
||||
private ref LiveRange PrevRange => ref _data->PrevRange;
|
||||
private ref LiveInterval Parent => ref _data->Parent;
|
||||
private ref LiveInterval CopySource => ref _data->CopySource;
|
||||
private ref UseList Uses => ref _data->Uses;
|
||||
private ref LiveIntervalList Children => ref _data->Children;
|
||||
|
||||
@ -78,6 +80,25 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
|
||||
Register = register;
|
||||
}
|
||||
|
||||
public void SetCopySource(LiveInterval copySource)
|
||||
{
|
||||
CopySource = copySource;
|
||||
}
|
||||
|
||||
public bool TryGetCopySourceRegister(out int copySourceRegIndex)
|
||||
{
|
||||
if (CopySource._data != null)
|
||||
{
|
||||
copySourceRegIndex = CopySource.Register.Index;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
copySourceRegIndex = 0;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
PrevRange = default;
|
||||
|
@ -1444,7 +1444,7 @@ namespace ARMeilleure.CodeGen.X86
|
||||
|
||||
Span<byte> buffer = new byte[jump.JumpPosition - _stream.Position];
|
||||
|
||||
_stream.Read(buffer);
|
||||
_stream.ReadExactly(buffer);
|
||||
_stream.Seek(ReservedBytesForJump, SeekOrigin.Current);
|
||||
|
||||
codeStream.Write(buffer);
|
||||
|
@ -517,7 +517,10 @@ namespace ARMeilleure.Decoders
|
||||
SetA64("0x00111100>>>xxx100111xxxxxxxxxx", InstName.Sqrshrn_V, InstEmit.Sqrshrn_V, OpCodeSimdShImm.Create);
|
||||
SetA64("0111111100>>>xxx100011xxxxxxxxxx", InstName.Sqrshrun_S, InstEmit.Sqrshrun_S, OpCodeSimdShImm.Create);
|
||||
SetA64("0x10111100>>>xxx100011xxxxxxxxxx", InstName.Sqrshrun_V, InstEmit.Sqrshrun_V, OpCodeSimdShImm.Create);
|
||||
SetA64("010111110>>>>xxx011101xxxxxxxxxx", InstName.Sqshl_Si, InstEmit.Sqshl_Si, OpCodeSimdShImm.Create);
|
||||
SetA64("0>001110<<1xxxxx010011xxxxxxxxxx", InstName.Sqshl_V, InstEmit.Sqshl_V, OpCodeSimdReg.Create);
|
||||
SetA64("0000111100>>>xxx011101xxxxxxxxxx", InstName.Sqshl_Vi, InstEmit.Sqshl_Vi, OpCodeSimdShImm.Create);
|
||||
SetA64("010011110>>>>xxx011101xxxxxxxxxx", InstName.Sqshl_Vi, InstEmit.Sqshl_Vi, OpCodeSimdShImm.Create);
|
||||
SetA64("0101111100>>>xxx100101xxxxxxxxxx", InstName.Sqshrn_S, InstEmit.Sqshrn_S, OpCodeSimdShImm.Create);
|
||||
SetA64("0x00111100>>>xxx100101xxxxxxxxxx", InstName.Sqshrn_V, InstEmit.Sqshrn_V, OpCodeSimdShImm.Create);
|
||||
SetA64("0111111100>>>xxx100001xxxxxxxxxx", InstName.Sqshrun_S, InstEmit.Sqshrun_S, OpCodeSimdShImm.Create);
|
||||
@ -819,6 +822,10 @@ namespace ARMeilleure.Decoders
|
||||
SetA32("<<<<00000100xxxxxxxxxxxx1001xxxx", InstName.Umaal, InstEmit32.Umaal, OpCode32AluUmull.Create);
|
||||
SetA32("<<<<0000101xxxxxxxxxxxxx1001xxxx", InstName.Umlal, InstEmit32.Umlal, OpCode32AluUmull.Create);
|
||||
SetA32("<<<<0000100xxxxxxxxxxxxx1001xxxx", InstName.Umull, InstEmit32.Umull, OpCode32AluUmull.Create);
|
||||
SetA32("<<<<01100110xxxxxxxx11110001xxxx", InstName.Uqadd16, InstEmit32.Uqadd16, OpCode32AluReg.Create);
|
||||
SetA32("<<<<01100110xxxxxxxx11111001xxxx", InstName.Uqadd8, InstEmit32.Uqadd8, OpCode32AluReg.Create);
|
||||
SetA32("<<<<01100110xxxxxxxx11110111xxxx", InstName.Uqsub16, InstEmit32.Uqsub16, OpCode32AluReg.Create);
|
||||
SetA32("<<<<01100110xxxxxxxx11111111xxxx", InstName.Uqsub8, InstEmit32.Uqsub8, OpCode32AluReg.Create);
|
||||
SetA32("<<<<0110111xxxxxxxxxxxxxxx01xxxx", InstName.Usat, InstEmit32.Usat, OpCode32Sat.Create);
|
||||
SetA32("<<<<01101110xxxxxxxx11110011xxxx", InstName.Usat16, InstEmit32.Usat16, OpCode32Sat16.Create);
|
||||
SetA32("<<<<01100101xxxxxxxx11111111xxxx", InstName.Usub8, InstEmit32.Usub8, OpCode32AluReg.Create);
|
||||
@ -872,6 +879,7 @@ namespace ARMeilleure.Decoders
|
||||
SetVfp("<<<<11100x10xxxxxxxx101xx1x0xxxx", InstName.Vnmul, InstEmit32.Vnmul_S, OpCode32SimdRegS.Create, OpCode32SimdRegS.CreateT32);
|
||||
SetVfp("111111101x1110xxxxxx101x01x0xxxx", InstName.Vrint, InstEmit32.Vrint_RM, OpCode32SimdS.Create, OpCode32SimdS.CreateT32);
|
||||
SetVfp("<<<<11101x110110xxxx101x11x0xxxx", InstName.Vrint, InstEmit32.Vrint_Z, OpCode32SimdS.Create, OpCode32SimdS.CreateT32);
|
||||
SetVfp("<<<<11101x110110xxxx101x01x0xxxx", InstName.Vrintr, InstEmit32.Vrintr_S, OpCode32SimdS.Create, OpCode32SimdS.CreateT32);
|
||||
SetVfp("<<<<11101x110111xxxx101x01x0xxxx", InstName.Vrintx, InstEmit32.Vrintx_S, OpCode32SimdS.Create, OpCode32SimdS.CreateT32);
|
||||
SetVfp("<<<<11101x110001xxxx101x11x0xxxx", InstName.Vsqrt, InstEmit32.Vsqrt_S, OpCode32SimdS.Create, OpCode32SimdS.CreateT32);
|
||||
SetVfp("111111100xxxxxxxxxxx101xx0x0xxxx", InstName.Vsel, InstEmit32.Vsel, OpCode32SimdSel.Create, OpCode32SimdSel.CreateT32);
|
||||
@ -992,6 +1000,7 @@ namespace ARMeilleure.Decoders
|
||||
SetAsimd("1111001x1x000xxxxxxx<<x10x01xxxx", InstName.Vorr, InstEmit32.Vorr_II, OpCode32SimdImm.Create, OpCode32SimdImm.CreateT32);
|
||||
SetAsimd("111100100x<<xxxxxxxx1011x0x1xxxx", InstName.Vpadd, InstEmit32.Vpadd_I, OpCode32SimdReg.Create, OpCode32SimdReg.CreateT32);
|
||||
SetAsimd("111100110x00xxxxxxxx1101x0x0xxxx", InstName.Vpadd, InstEmit32.Vpadd_V, OpCode32SimdReg.Create, OpCode32SimdReg.CreateT32);
|
||||
SetAsimd("111100111x11<<00xxxx0110xxx0xxxx", InstName.Vpadal, InstEmit32.Vpadal, OpCode32SimdCmpZ.Create, OpCode32SimdCmpZ.CreateT32);
|
||||
SetAsimd("111100111x11<<00xxxx0010xxx0xxxx", InstName.Vpaddl, InstEmit32.Vpaddl, OpCode32SimdCmpZ.Create, OpCode32SimdCmpZ.CreateT32);
|
||||
SetAsimd("1111001x0x<<xxxxxxxx1010x0x0xxxx", InstName.Vpmax, InstEmit32.Vpmax_I, OpCode32SimdReg.Create, OpCode32SimdReg.CreateT32);
|
||||
SetAsimd("111100110x00xxxxxxxx1111x0x0xxxx", InstName.Vpmax, InstEmit32.Vpmax_V, OpCode32SimdReg.Create, OpCode32SimdReg.CreateT32);
|
||||
@ -1002,6 +1011,8 @@ namespace ARMeilleure.Decoders
|
||||
SetAsimd("111100100x10xxxxxxxx1011xxx0xxxx", InstName.Vqdmulh, InstEmit32.Vqdmulh, OpCode32SimdReg.Create, OpCode32SimdReg.CreateT32);
|
||||
SetAsimd("111100111x11<<10xxxx00101xx0xxx0", InstName.Vqmovn, InstEmit32.Vqmovn, OpCode32SimdMovn.Create, OpCode32SimdMovn.CreateT32);
|
||||
SetAsimd("111100111x11<<10xxxx001001x0xxx0", InstName.Vqmovun, InstEmit32.Vqmovun, OpCode32SimdMovn.Create, OpCode32SimdMovn.CreateT32);
|
||||
SetAsimd("111100110x01xxxxxxxx1011xxx0xxxx", InstName.Vqrdmulh, InstEmit32.Vqrdmulh, OpCode32SimdReg.Create, OpCode32SimdReg.CreateT32);
|
||||
SetAsimd("111100110x10xxxxxxxx1011xxx0xxxx", InstName.Vqrdmulh, InstEmit32.Vqrdmulh, OpCode32SimdReg.Create, OpCode32SimdReg.CreateT32);
|
||||
SetAsimd("1111001x1x>>>xxxxxxx100101x1xxx0", InstName.Vqrshrn, InstEmit32.Vqrshrn, OpCode32SimdShImmNarrow.Create, OpCode32SimdShImmNarrow.CreateT32);
|
||||
SetAsimd("111100111x>>>xxxxxxx100001x1xxx0", InstName.Vqrshrun, InstEmit32.Vqrshrun, OpCode32SimdShImmNarrow.Create, OpCode32SimdShImmNarrow.CreateT32);
|
||||
SetAsimd("1111001x1x>>>xxxxxxx100100x1xxx0", InstName.Vqshrn, InstEmit32.Vqshrn, OpCode32SimdShImmNarrow.Create, OpCode32SimdShImmNarrow.CreateT32);
|
||||
@ -1025,6 +1036,7 @@ namespace ARMeilleure.Decoders
|
||||
SetAsimd("1111001x1x>>>xxxxxxx101000x1xxxx", InstName.Vshll, InstEmit32.Vshll, OpCode32SimdShImmLong.Create, OpCode32SimdShImmLong.CreateT32); // A1 encoding.
|
||||
SetAsimd("1111001x1x>>>xxxxxxx0000>xx1xxxx", InstName.Vshr, InstEmit32.Vshr, OpCode32SimdShImm.Create, OpCode32SimdShImm.CreateT32);
|
||||
SetAsimd("111100101x>>>xxxxxxx100000x1xxx0", InstName.Vshrn, InstEmit32.Vshrn, OpCode32SimdShImmNarrow.Create, OpCode32SimdShImmNarrow.CreateT32);
|
||||
SetAsimd("111100111x>>>xxxxxxx0101>xx1xxxx", InstName.Vsli, InstEmit32.Vsli_I, OpCode32SimdShImm.Create, OpCode32SimdShImm.CreateT32);
|
||||
SetAsimd("1111001x1x>>>xxxxxxx0001>xx1xxxx", InstName.Vsra, InstEmit32.Vsra, OpCode32SimdShImm.Create, OpCode32SimdShImm.CreateT32);
|
||||
SetAsimd("111101001x00xxxxxxxx0000xxx0xxxx", InstName.Vst1, InstEmit32.Vst1, OpCode32SimdMemSingle.Create, OpCode32SimdMemSingle.CreateT32);
|
||||
SetAsimd("111101001x00xxxxxxxx0100xx0xxxxx", InstName.Vst1, InstEmit32.Vst1, OpCode32SimdMemSingle.Create, OpCode32SimdMemSingle.CreateT32);
|
||||
@ -1049,6 +1061,7 @@ namespace ARMeilleure.Decoders
|
||||
SetAsimd("111100100x10xxxxxxxx1101xxx0xxxx", InstName.Vsub, InstEmit32.Vsub_V, OpCode32SimdReg.Create, OpCode32SimdReg.CreateT32);
|
||||
SetAsimd("1111001x1x<<xxxxxxx00010x0x0xxxx", InstName.Vsubl, InstEmit32.Vsubl_I, OpCode32SimdRegLong.Create, OpCode32SimdRegLong.CreateT32);
|
||||
SetAsimd("1111001x1x<<xxxxxxx00011x0x0xxxx", InstName.Vsubw, InstEmit32.Vsubw_I, OpCode32SimdRegWide.Create, OpCode32SimdRegWide.CreateT32);
|
||||
SetAsimd("111100111x110010xxxx00000xx0xxxx", InstName.Vswp, InstEmit32.Vswp, OpCode32Simd.Create, OpCode32Simd.CreateT32);
|
||||
SetAsimd("111100111x11xxxxxxxx10xxxxx0xxxx", InstName.Vtbl, InstEmit32.Vtbl, OpCode32SimdTbl.Create, OpCode32SimdTbl.CreateT32);
|
||||
SetAsimd("111100111x11<<10xxxx00001xx0xxxx", InstName.Vtrn, InstEmit32.Vtrn, OpCode32SimdCmpZ.Create, OpCode32SimdCmpZ.CreateT32);
|
||||
SetAsimd("111100100x<<xxxxxxxx1000xxx1xxxx", InstName.Vtst, InstEmit32.Vtst, OpCode32SimdReg.Create, OpCode32SimdReg.CreateT32);
|
||||
|
@ -2,6 +2,8 @@ using ARMeilleure.Decoders;
|
||||
using ARMeilleure.IntermediateRepresentation;
|
||||
using ARMeilleure.State;
|
||||
using ARMeilleure.Translation;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using static ARMeilleure.Instructions.InstEmitAluHelper;
|
||||
using static ARMeilleure.Instructions.InstEmitHelper;
|
||||
@ -19,6 +21,12 @@ namespace ARMeilleure.Instructions
|
||||
Operand n = GetAluN(context);
|
||||
Operand m = GetAluM(context, setCarry: false);
|
||||
|
||||
if (op.Rn == RegisterAlias.Aarch32Pc && op is OpCodeT32AluImm12)
|
||||
{
|
||||
// For ADR, PC is always 4 bytes aligned, even in Thumb mode.
|
||||
n = context.BitwiseAnd(n, Const(~3u));
|
||||
}
|
||||
|
||||
Operand res = context.Add(n, m);
|
||||
|
||||
if (ShouldSetFlags(context))
|
||||
@ -467,6 +475,12 @@ namespace ARMeilleure.Instructions
|
||||
Operand n = GetAluN(context);
|
||||
Operand m = GetAluM(context, setCarry: false);
|
||||
|
||||
if (op.Rn == RegisterAlias.Aarch32Pc && op is OpCodeT32AluImm12)
|
||||
{
|
||||
// For ADR, PC is always 4 bytes aligned, even in Thumb mode.
|
||||
n = context.BitwiseAnd(n, Const(~3u));
|
||||
}
|
||||
|
||||
Operand res = context.Subtract(n, m);
|
||||
|
||||
if (ShouldSetFlags(context))
|
||||
@ -546,6 +560,46 @@ namespace ARMeilleure.Instructions
|
||||
EmitHsub8(context, unsigned: true);
|
||||
}
|
||||
|
||||
public static void Uqadd16(ArmEmitterContext context)
|
||||
{
|
||||
OpCode32AluReg op = (OpCode32AluReg)context.CurrOp;
|
||||
|
||||
SetIntA32(context, op.Rd, EmitUnsigned16BitPair(context, GetIntA32(context, op.Rn), GetIntA32(context, op.Rm), (d, n, m) =>
|
||||
{
|
||||
EmitSaturateUqadd(context, d, context.Add(n, m), 16);
|
||||
}));
|
||||
}
|
||||
|
||||
public static void Uqadd8(ArmEmitterContext context)
|
||||
{
|
||||
OpCode32AluReg op = (OpCode32AluReg)context.CurrOp;
|
||||
|
||||
SetIntA32(context, op.Rd, EmitUnsigned8BitPair(context, GetIntA32(context, op.Rn), GetIntA32(context, op.Rm), (d, n, m) =>
|
||||
{
|
||||
EmitSaturateUqadd(context, d, context.Add(n, m), 8);
|
||||
}));
|
||||
}
|
||||
|
||||
public static void Uqsub16(ArmEmitterContext context)
|
||||
{
|
||||
OpCode32AluReg op = (OpCode32AluReg)context.CurrOp;
|
||||
|
||||
SetIntA32(context, op.Rd, EmitUnsigned16BitPair(context, GetIntA32(context, op.Rn), GetIntA32(context, op.Rm), (d, n, m) =>
|
||||
{
|
||||
EmitSaturateUqsub(context, d, context.Subtract(n, m), 16);
|
||||
}));
|
||||
}
|
||||
|
||||
public static void Uqsub8(ArmEmitterContext context)
|
||||
{
|
||||
OpCode32AluReg op = (OpCode32AluReg)context.CurrOp;
|
||||
|
||||
SetIntA32(context, op.Rd, EmitUnsigned8BitPair(context, GetIntA32(context, op.Rn), GetIntA32(context, op.Rm), (d, n, m) =>
|
||||
{
|
||||
EmitSaturateUqsub(context, d, context.Subtract(n, m), 8);
|
||||
}));
|
||||
}
|
||||
|
||||
public static void Usat(ArmEmitterContext context)
|
||||
{
|
||||
OpCode32Sat op = (OpCode32Sat)context.CurrOp;
|
||||
@ -922,6 +976,148 @@ namespace ARMeilleure.Instructions
|
||||
}
|
||||
}
|
||||
|
||||
private static void EmitSaturateUqadd(ArmEmitterContext context, Operand result, Operand value, uint saturateTo)
|
||||
{
|
||||
Debug.Assert(saturateTo <= 32);
|
||||
|
||||
if (saturateTo == 32)
|
||||
{
|
||||
// No saturation possible for this case.
|
||||
|
||||
context.Copy(result, value);
|
||||
|
||||
return;
|
||||
}
|
||||
else if (saturateTo == 0)
|
||||
{
|
||||
// Result is always zero if we saturate 0 bits.
|
||||
|
||||
context.Copy(result, Const(0));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// If the result is 0, the values are equal and we don't need saturation.
|
||||
Operand lblNoSat = Label();
|
||||
context.BranchIfFalse(lblNoSat, context.ShiftRightUI(value, Const((int)saturateTo)));
|
||||
|
||||
// Saturate.
|
||||
context.Copy(result, Const(uint.MaxValue >> (32 - (int)saturateTo)));
|
||||
|
||||
Operand lblExit = Label();
|
||||
context.Branch(lblExit);
|
||||
|
||||
context.MarkLabel(lblNoSat);
|
||||
|
||||
context.Copy(result, value);
|
||||
|
||||
context.MarkLabel(lblExit);
|
||||
}
|
||||
|
||||
private static void EmitSaturateUqsub(ArmEmitterContext context, Operand result, Operand value, uint saturateTo)
|
||||
{
|
||||
Debug.Assert(saturateTo <= 32);
|
||||
|
||||
if (saturateTo == 32)
|
||||
{
|
||||
// No saturation possible for this case.
|
||||
|
||||
context.Copy(result, value);
|
||||
|
||||
return;
|
||||
}
|
||||
else if (saturateTo == 0)
|
||||
{
|
||||
// Result is always zero if we saturate 0 bits.
|
||||
|
||||
context.Copy(result, Const(0));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// If the result is 0, the values are equal and we don't need saturation.
|
||||
Operand lblNoSat = Label();
|
||||
context.BranchIf(lblNoSat, value, Const(0), Comparison.GreaterOrEqual);
|
||||
|
||||
// Saturate.
|
||||
// Assumes that the value can only underflow, since this is only used for unsigned subtraction.
|
||||
context.Copy(result, Const(0));
|
||||
|
||||
Operand lblExit = Label();
|
||||
context.Branch(lblExit);
|
||||
|
||||
context.MarkLabel(lblNoSat);
|
||||
|
||||
context.Copy(result, value);
|
||||
|
||||
context.MarkLabel(lblExit);
|
||||
}
|
||||
|
||||
private static Operand EmitUnsigned16BitPair(ArmEmitterContext context, Operand rn, Operand rm, Action<Operand, Operand, Operand> elementAction)
|
||||
{
|
||||
Operand tempD = context.AllocateLocal(OperandType.I32);
|
||||
|
||||
Operand tempN = context.ZeroExtend16(OperandType.I32, rn);
|
||||
Operand tempM = context.ZeroExtend16(OperandType.I32, rm);
|
||||
elementAction(tempD, tempN, tempM);
|
||||
Operand tempD2 = context.ZeroExtend16(OperandType.I32, tempD);
|
||||
|
||||
tempN = context.ShiftRightUI(rn, Const(16));
|
||||
tempM = context.ShiftRightUI(rm, Const(16));
|
||||
elementAction(tempD, tempN, tempM);
|
||||
return context.BitwiseOr(tempD2, context.ShiftLeft(tempD, Const(16)));
|
||||
}
|
||||
|
||||
private static Operand EmitSigned8BitPair(ArmEmitterContext context, Operand rn, Operand rm, Action<Operand, Operand, Operand> elementAction)
|
||||
{
|
||||
return Emit8BitPair(context, rn, rm, elementAction, unsigned: false);
|
||||
}
|
||||
|
||||
private static Operand EmitUnsigned8BitPair(ArmEmitterContext context, Operand rn, Operand rm, Action<Operand, Operand, Operand> elementAction)
|
||||
{
|
||||
return Emit8BitPair(context, rn, rm, elementAction, unsigned: true);
|
||||
}
|
||||
|
||||
private static Operand Emit8BitPair(ArmEmitterContext context, Operand rn, Operand rm, Action<Operand, Operand, Operand> elementAction, bool unsigned)
|
||||
{
|
||||
Operand tempD = context.AllocateLocal(OperandType.I32);
|
||||
Operand result = default;
|
||||
|
||||
for (int b = 0; b < 4; b++)
|
||||
{
|
||||
Operand nByte = b != 0 ? context.ShiftRightUI(rn, Const(b * 8)) : rn;
|
||||
Operand mByte = b != 0 ? context.ShiftRightUI(rm, Const(b * 8)) : rm;
|
||||
|
||||
if (unsigned)
|
||||
{
|
||||
nByte = context.ZeroExtend8(OperandType.I32, nByte);
|
||||
mByte = context.ZeroExtend8(OperandType.I32, mByte);
|
||||
}
|
||||
else
|
||||
{
|
||||
nByte = context.SignExtend8(OperandType.I32, nByte);
|
||||
mByte = context.SignExtend8(OperandType.I32, mByte);
|
||||
}
|
||||
|
||||
elementAction(tempD, nByte, mByte);
|
||||
|
||||
if (b == 0)
|
||||
{
|
||||
result = context.ZeroExtend8(OperandType.I32, tempD);
|
||||
}
|
||||
else if (b < 3)
|
||||
{
|
||||
result = context.BitwiseOr(result, context.ShiftLeft(context.ZeroExtend8(OperandType.I32, tempD), Const(b * 8)));
|
||||
}
|
||||
else
|
||||
{
|
||||
result = context.BitwiseOr(result, context.ShiftLeft(tempD, Const(24)));
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private static void EmitAluStore(ArmEmitterContext context, Operand value)
|
||||
{
|
||||
IOpCode32Alu op = (IOpCode32Alu)context.CurrOp;
|
||||
|
@ -403,19 +403,25 @@ namespace ARMeilleure.Instructions
|
||||
{
|
||||
return EmitHostMappedPointer(context, address);
|
||||
}
|
||||
else if (context.Memory.Type == MemoryManagerType.HostTracked)
|
||||
else if (context.Memory.Type.IsHostTracked())
|
||||
{
|
||||
if (address.Type == OperandType.I32)
|
||||
{
|
||||
address = context.ZeroExtend32(OperandType.I64, address);
|
||||
}
|
||||
|
||||
if (context.Memory.Type == MemoryManagerType.HostTracked)
|
||||
{
|
||||
Operand mask = Const(ulong.MaxValue >> (64 - context.Memory.AddressSpaceBits));
|
||||
address = context.BitwiseAnd(address, mask);
|
||||
}
|
||||
|
||||
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)))));
|
||||
}
|
||||
|
||||
|
@ -2426,7 +2426,11 @@ namespace ARMeilleure.Instructions
|
||||
}
|
||||
else if (Optimizations.FastFP && Optimizations.UseSse41 && sizeF == 0)
|
||||
{
|
||||
Operand res = EmitSse41Round32Exp8OpF(context, context.AddIntrinsic(Intrinsic.X86Rsqrtss, GetVec(op.Rn)), scalar: true);
|
||||
// RSQRTSS handles subnormals as zero, which differs from Arm, so we can't use it here.
|
||||
|
||||
Operand res = context.AddIntrinsic(Intrinsic.X86Sqrtss, GetVec(op.Rn));
|
||||
res = context.AddIntrinsic(Intrinsic.X86Rcpss, res);
|
||||
res = EmitSse41Round32Exp8OpF(context, res, scalar: true);
|
||||
|
||||
context.Copy(GetVec(op.Rd), context.VectorZeroUpper96(res));
|
||||
}
|
||||
@ -2451,7 +2455,11 @@ namespace ARMeilleure.Instructions
|
||||
}
|
||||
else if (Optimizations.FastFP && Optimizations.UseSse41 && sizeF == 0)
|
||||
{
|
||||
Operand res = EmitSse41Round32Exp8OpF(context, context.AddIntrinsic(Intrinsic.X86Rsqrtps, GetVec(op.Rn)), scalar: false);
|
||||
// RSQRTPS handles subnormals as zero, which differs from Arm, so we can't use it here.
|
||||
|
||||
Operand res = context.AddIntrinsic(Intrinsic.X86Sqrtps, GetVec(op.Rn));
|
||||
res = context.AddIntrinsic(Intrinsic.X86Rcpps, res);
|
||||
res = EmitSse41Round32Exp8OpF(context, res, scalar: false);
|
||||
|
||||
if (op.RegisterSize == RegisterSize.Simd64)
|
||||
{
|
||||
|
@ -1115,6 +1115,13 @@ namespace ARMeilleure.Instructions
|
||||
}
|
||||
}
|
||||
|
||||
public static void Vpadal(ArmEmitterContext context)
|
||||
{
|
||||
OpCode32Simd op = (OpCode32Simd)context.CurrOp;
|
||||
|
||||
EmitVectorPairwiseTernaryLongOpI32(context, (op1, op2, op3) => context.Add(context.Add(op1, op2), op3), op.Opc != 1);
|
||||
}
|
||||
|
||||
public static void Vpaddl(ArmEmitterContext context)
|
||||
{
|
||||
OpCode32Simd op = (OpCode32Simd)context.CurrOp;
|
||||
@ -1239,6 +1246,33 @@ namespace ARMeilleure.Instructions
|
||||
EmitVectorUnaryNarrowOp32(context, (op1) => EmitSatQ(context, op1, 8 << op.Size, signedSrc: true, signedDst: false), signed: true);
|
||||
}
|
||||
|
||||
public static void Vqrdmulh(ArmEmitterContext context)
|
||||
{
|
||||
OpCode32SimdReg op = (OpCode32SimdReg)context.CurrOp;
|
||||
int eSize = 8 << op.Size;
|
||||
|
||||
EmitVectorBinaryOpI32(context, (op1, op2) =>
|
||||
{
|
||||
if (op.Size == 2)
|
||||
{
|
||||
op1 = context.SignExtend32(OperandType.I64, op1);
|
||||
op2 = context.SignExtend32(OperandType.I64, op2);
|
||||
}
|
||||
|
||||
Operand res = context.Multiply(op1, op2);
|
||||
res = context.Add(res, Const(res.Type, 1L << (eSize - 2)));
|
||||
res = context.ShiftRightSI(res, Const(eSize - 1));
|
||||
res = EmitSatQ(context, res, eSize, signedSrc: true, signedDst: true);
|
||||
|
||||
if (op.Size == 2)
|
||||
{
|
||||
res = context.ConvertI64ToI32(res);
|
||||
}
|
||||
|
||||
return res;
|
||||
}, signed: true);
|
||||
}
|
||||
|
||||
public static void Vqsub(ArmEmitterContext context)
|
||||
{
|
||||
OpCode32SimdReg op = (OpCode32SimdReg)context.CurrOp;
|
||||
|
@ -578,6 +578,22 @@ namespace ARMeilleure.Instructions
|
||||
}
|
||||
}
|
||||
|
||||
// VRINTR (floating-point).
|
||||
public static void Vrintr_S(ArmEmitterContext context)
|
||||
{
|
||||
if (Optimizations.UseAdvSimd)
|
||||
{
|
||||
InstEmitSimdHelper32Arm64.EmitScalarUnaryOpF32(context, Intrinsic.Arm64FrintiS);
|
||||
}
|
||||
else
|
||||
{
|
||||
EmitScalarUnaryOpF32(context, (op1) =>
|
||||
{
|
||||
return EmitRoundByRMode(context, op1);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// VRINTZ (floating-point).
|
||||
public static void Vrint_Z(ArmEmitterContext context)
|
||||
{
|
||||
|
@ -673,6 +673,35 @@ namespace ARMeilleure.Instructions
|
||||
context.Copy(GetVecA32(op.Qd), res);
|
||||
}
|
||||
|
||||
public static void EmitVectorPairwiseTernaryLongOpI32(ArmEmitterContext context, Func3I emit, bool signed)
|
||||
{
|
||||
OpCode32Simd op = (OpCode32Simd)context.CurrOp;
|
||||
|
||||
int elems = op.GetBytesCount() >> op.Size;
|
||||
int pairs = elems >> 1;
|
||||
|
||||
Operand res = GetVecA32(op.Qd);
|
||||
|
||||
for (int index = 0; index < pairs; index++)
|
||||
{
|
||||
int pairIndex = index * 2;
|
||||
Operand m1 = EmitVectorExtract32(context, op.Qm, op.Im + pairIndex, op.Size, signed);
|
||||
Operand m2 = EmitVectorExtract32(context, op.Qm, op.Im + pairIndex + 1, op.Size, signed);
|
||||
|
||||
if (op.Size == 2)
|
||||
{
|
||||
m1 = signed ? context.SignExtend32(OperandType.I64, m1) : context.ZeroExtend32(OperandType.I64, m1);
|
||||
m2 = signed ? context.SignExtend32(OperandType.I64, m2) : context.ZeroExtend32(OperandType.I64, m2);
|
||||
}
|
||||
|
||||
Operand d1 = EmitVectorExtract32(context, op.Qd, op.Id + index, op.Size + 1, signed);
|
||||
|
||||
res = EmitVectorInsert(context, res, emit(m1, m2, d1), op.Id + index, op.Size + 1);
|
||||
}
|
||||
|
||||
context.Copy(GetVecA32(op.Qd), res);
|
||||
}
|
||||
|
||||
// Narrow
|
||||
|
||||
public static void EmitVectorUnaryNarrowOp32(ArmEmitterContext context, Func1I emit, bool signed = false)
|
||||
|
@ -191,6 +191,26 @@ namespace ARMeilleure.Instructions
|
||||
context.Copy(GetVecA32(op.Qd), res);
|
||||
}
|
||||
|
||||
public static void Vswp(ArmEmitterContext context)
|
||||
{
|
||||
OpCode32Simd op = (OpCode32Simd)context.CurrOp;
|
||||
|
||||
if (op.Q)
|
||||
{
|
||||
Operand temp = context.Copy(GetVecA32(op.Qd));
|
||||
|
||||
context.Copy(GetVecA32(op.Qd), GetVecA32(op.Qm));
|
||||
context.Copy(GetVecA32(op.Qm), temp);
|
||||
}
|
||||
else
|
||||
{
|
||||
Operand temp = ExtractScalar(context, OperandType.I64, op.Vd);
|
||||
|
||||
InsertScalar(context, op.Vd, ExtractScalar(context, OperandType.I64, op.Vm));
|
||||
InsertScalar(context, op.Vm, temp);
|
||||
}
|
||||
}
|
||||
|
||||
public static void Vtbl(ArmEmitterContext context)
|
||||
{
|
||||
OpCode32SimdTbl op = (OpCode32SimdTbl)context.CurrOp;
|
||||
|
@ -116,7 +116,7 @@ namespace ARMeilleure.Instructions
|
||||
}
|
||||
else if (shift >= eSize)
|
||||
{
|
||||
if ((op.RegisterSize == RegisterSize.Simd64))
|
||||
if (op.RegisterSize == RegisterSize.Simd64)
|
||||
{
|
||||
Operand res = context.VectorZeroUpper64(GetVec(op.Rd));
|
||||
|
||||
@ -359,6 +359,16 @@ namespace ARMeilleure.Instructions
|
||||
}
|
||||
}
|
||||
|
||||
public static void Sqshl_Si(ArmEmitterContext context)
|
||||
{
|
||||
EmitShlImmOp(context, signedDst: true, ShlRegFlags.Signed | ShlRegFlags.Scalar | ShlRegFlags.Saturating);
|
||||
}
|
||||
|
||||
public static void Sqshl_Vi(ArmEmitterContext context)
|
||||
{
|
||||
EmitShlImmOp(context, signedDst: true, ShlRegFlags.Signed | ShlRegFlags.Saturating);
|
||||
}
|
||||
|
||||
public static void Sqshrn_S(ArmEmitterContext context)
|
||||
{
|
||||
if (Optimizations.UseAdvSimd)
|
||||
@ -1593,6 +1603,99 @@ namespace ARMeilleure.Instructions
|
||||
Saturating = 1 << 3,
|
||||
}
|
||||
|
||||
private static void EmitShlImmOp(ArmEmitterContext context, bool signedDst, ShlRegFlags flags = ShlRegFlags.None)
|
||||
{
|
||||
bool scalar = flags.HasFlag(ShlRegFlags.Scalar);
|
||||
bool signed = flags.HasFlag(ShlRegFlags.Signed);
|
||||
bool saturating = flags.HasFlag(ShlRegFlags.Saturating);
|
||||
|
||||
OpCodeSimdShImm op = (OpCodeSimdShImm)context.CurrOp;
|
||||
|
||||
Operand res = context.VectorZero();
|
||||
|
||||
int elems = !scalar ? op.GetBytesCount() >> op.Size : 1;
|
||||
|
||||
for (int index = 0; index < elems; index++)
|
||||
{
|
||||
Operand ne = EmitVectorExtract(context, op.Rn, index, op.Size, signed);
|
||||
|
||||
Operand e = !saturating
|
||||
? EmitShlImm(context, ne, GetImmShl(op), op.Size)
|
||||
: EmitShlImmSatQ(context, ne, GetImmShl(op), op.Size, signed, signedDst);
|
||||
|
||||
res = EmitVectorInsert(context, res, e, index, op.Size);
|
||||
}
|
||||
|
||||
context.Copy(GetVec(op.Rd), res);
|
||||
}
|
||||
|
||||
private static Operand EmitShlImm(ArmEmitterContext context, Operand op, int shiftLsB, int size)
|
||||
{
|
||||
int eSize = 8 << size;
|
||||
|
||||
Debug.Assert(op.Type == OperandType.I64);
|
||||
Debug.Assert(eSize == 8 || eSize == 16 || eSize == 32 || eSize == 64);
|
||||
|
||||
Operand res = context.AllocateLocal(OperandType.I64);
|
||||
|
||||
if (shiftLsB >= eSize)
|
||||
{
|
||||
Operand shl = context.ShiftLeft(op, Const(shiftLsB));
|
||||
context.Copy(res, shl);
|
||||
}
|
||||
else
|
||||
{
|
||||
Operand zeroL = Const(0L);
|
||||
context.Copy(res, zeroL);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
private static Operand EmitShlImmSatQ(ArmEmitterContext context, Operand op, int shiftLsB, int size, bool signedSrc, bool signedDst)
|
||||
{
|
||||
int eSize = 8 << size;
|
||||
|
||||
Debug.Assert(op.Type == OperandType.I64);
|
||||
Debug.Assert(eSize == 8 || eSize == 16 || eSize == 32 || eSize == 64);
|
||||
|
||||
Operand lblEnd = Label();
|
||||
|
||||
Operand res = context.Copy(context.AllocateLocal(OperandType.I64), op);
|
||||
|
||||
if (shiftLsB >= eSize)
|
||||
{
|
||||
context.Copy(res, signedSrc
|
||||
? EmitSignedSignSatQ(context, op, size)
|
||||
: EmitUnsignedSignSatQ(context, op, size));
|
||||
}
|
||||
else
|
||||
{
|
||||
Operand shl = context.ShiftLeft(op, Const(shiftLsB));
|
||||
if (eSize == 64)
|
||||
{
|
||||
Operand sarOrShr = signedSrc
|
||||
? context.ShiftRightSI(shl, Const(shiftLsB))
|
||||
: context.ShiftRightUI(shl, Const(shiftLsB));
|
||||
context.Copy(res, shl);
|
||||
context.BranchIf(lblEnd, sarOrShr, op, Comparison.Equal);
|
||||
context.Copy(res, signedSrc
|
||||
? EmitSignedSignSatQ(context, op, size)
|
||||
: EmitUnsignedSignSatQ(context, op, size));
|
||||
}
|
||||
else
|
||||
{
|
||||
context.Copy(res, signedSrc
|
||||
? EmitSignedSrcSatQ(context, shl, size, signedDst)
|
||||
: EmitUnsignedSrcSatQ(context, shl, size, signedDst));
|
||||
}
|
||||
}
|
||||
|
||||
context.MarkLabel(lblEnd);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
private static void EmitShlRegOp(ArmEmitterContext context, ShlRegFlags flags = ShlRegFlags.None)
|
||||
{
|
||||
bool scalar = flags.HasFlag(ShlRegFlags.Scalar);
|
||||
|
@ -130,6 +130,36 @@ namespace ARMeilleure.Instructions
|
||||
EmitVectorUnaryNarrowOp32(context, (op1) => context.ShiftRightUI(op1, Const(shift)));
|
||||
}
|
||||
|
||||
public static void Vsli_I(ArmEmitterContext context)
|
||||
{
|
||||
OpCode32SimdShImm op = (OpCode32SimdShImm)context.CurrOp;
|
||||
int shift = op.Shift;
|
||||
int eSize = 8 << op.Size;
|
||||
|
||||
ulong mask = shift != 0 ? ulong.MaxValue >> (64 - shift) : 0UL;
|
||||
|
||||
Operand res = GetVec(op.Qd);
|
||||
|
||||
int elems = op.GetBytesCount() >> op.Size;
|
||||
|
||||
for (int index = 0; index < elems; index++)
|
||||
{
|
||||
Operand me = EmitVectorExtractZx(context, op.Qm, op.Im + index, op.Size);
|
||||
|
||||
Operand neShifted = context.ShiftLeft(me, Const(shift));
|
||||
|
||||
Operand de = EmitVectorExtractZx(context, op.Qd, op.Id + index, op.Size);
|
||||
|
||||
Operand deMasked = context.BitwiseAnd(de, Const(mask));
|
||||
|
||||
Operand e = context.BitwiseOr(neShifted, deMasked);
|
||||
|
||||
res = EmitVectorInsert(context, res, e, op.Id + index, op.Size);
|
||||
}
|
||||
|
||||
context.Copy(GetVec(op.Qd), res);
|
||||
}
|
||||
|
||||
public static void Vsra(ArmEmitterContext context)
|
||||
{
|
||||
OpCode32SimdShImm op = (OpCode32SimdShImm)context.CurrOp;
|
||||
|
@ -384,7 +384,9 @@ namespace ARMeilleure.Instructions
|
||||
Sqrshrn_V,
|
||||
Sqrshrun_S,
|
||||
Sqrshrun_V,
|
||||
Sqshl_Si,
|
||||
Sqshl_V,
|
||||
Sqshl_Vi,
|
||||
Sqshrn_S,
|
||||
Sqshrn_V,
|
||||
Sqshrun_S,
|
||||
@ -569,6 +571,10 @@ namespace ARMeilleure.Instructions
|
||||
Umaal,
|
||||
Umlal,
|
||||
Umull,
|
||||
Uqadd16,
|
||||
Uqadd8,
|
||||
Uqsub16,
|
||||
Uqsub8,
|
||||
Usat,
|
||||
Usat16,
|
||||
Usub8,
|
||||
@ -635,6 +641,7 @@ namespace ARMeilleure.Instructions
|
||||
Vorn,
|
||||
Vorr,
|
||||
Vpadd,
|
||||
Vpadal,
|
||||
Vpaddl,
|
||||
Vpmax,
|
||||
Vpmin,
|
||||
@ -642,6 +649,7 @@ namespace ARMeilleure.Instructions
|
||||
Vqdmulh,
|
||||
Vqmovn,
|
||||
Vqmovun,
|
||||
Vqrdmulh,
|
||||
Vqrshrn,
|
||||
Vqrshrun,
|
||||
Vqshrn,
|
||||
@ -654,6 +662,7 @@ namespace ARMeilleure.Instructions
|
||||
Vrintm,
|
||||
Vrintn,
|
||||
Vrintp,
|
||||
Vrintr,
|
||||
Vrintx,
|
||||
Vrshr,
|
||||
Vrshrn,
|
||||
@ -662,6 +671,7 @@ namespace ARMeilleure.Instructions
|
||||
Vshll,
|
||||
Vshr,
|
||||
Vshrn,
|
||||
Vsli,
|
||||
Vst1,
|
||||
Vst2,
|
||||
Vst3,
|
||||
@ -678,6 +688,7 @@ namespace ARMeilleure.Instructions
|
||||
Vsub,
|
||||
Vsubl,
|
||||
Vsubw,
|
||||
Vswp,
|
||||
Vtbl,
|
||||
Vtrn,
|
||||
Vtst,
|
||||
|
@ -91,54 +91,54 @@ namespace ARMeilleure.Instructions
|
||||
#region "Read"
|
||||
public static byte ReadByte(ulong address)
|
||||
{
|
||||
return GetMemoryManager().ReadTracked<byte>(address);
|
||||
return GetMemoryManager().ReadGuest<byte>(address);
|
||||
}
|
||||
|
||||
public static ushort ReadUInt16(ulong address)
|
||||
{
|
||||
return GetMemoryManager().ReadTracked<ushort>(address);
|
||||
return GetMemoryManager().ReadGuest<ushort>(address);
|
||||
}
|
||||
|
||||
public static uint ReadUInt32(ulong address)
|
||||
{
|
||||
return GetMemoryManager().ReadTracked<uint>(address);
|
||||
return GetMemoryManager().ReadGuest<uint>(address);
|
||||
}
|
||||
|
||||
public static ulong ReadUInt64(ulong address)
|
||||
{
|
||||
return GetMemoryManager().ReadTracked<ulong>(address);
|
||||
return GetMemoryManager().ReadGuest<ulong>(address);
|
||||
}
|
||||
|
||||
public static V128 ReadVector128(ulong address)
|
||||
{
|
||||
return GetMemoryManager().ReadTracked<V128>(address);
|
||||
return GetMemoryManager().ReadGuest<V128>(address);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region "Write"
|
||||
public static void WriteByte(ulong address, byte value)
|
||||
{
|
||||
GetMemoryManager().Write(address, value);
|
||||
GetMemoryManager().WriteGuest(address, value);
|
||||
}
|
||||
|
||||
public static void WriteUInt16(ulong address, ushort value)
|
||||
{
|
||||
GetMemoryManager().Write(address, value);
|
||||
GetMemoryManager().WriteGuest(address, value);
|
||||
}
|
||||
|
||||
public static void WriteUInt32(ulong address, uint value)
|
||||
{
|
||||
GetMemoryManager().Write(address, value);
|
||||
GetMemoryManager().WriteGuest(address, value);
|
||||
}
|
||||
|
||||
public static void WriteUInt64(ulong address, ulong value)
|
||||
{
|
||||
GetMemoryManager().Write(address, value);
|
||||
GetMemoryManager().WriteGuest(address, value);
|
||||
}
|
||||
|
||||
public static void WriteVector128(ulong address, V128 value)
|
||||
{
|
||||
GetMemoryManager().Write(address, value);
|
||||
GetMemoryManager().WriteGuest(address, value);
|
||||
}
|
||||
#endregion
|
||||
|
||||
|
@ -4,7 +4,5 @@ namespace ARMeilleure.Memory
|
||||
{
|
||||
IJitMemoryBlock Allocate(ulong size);
|
||||
IJitMemoryBlock Reserve(ulong size);
|
||||
|
||||
ulong GetPageSize();
|
||||
}
|
||||
}
|
||||
|
@ -28,6 +28,17 @@ namespace ARMeilleure.Memory
|
||||
/// <returns>The data</returns>
|
||||
T ReadTracked<T>(ulong va) where T : unmanaged;
|
||||
|
||||
/// <summary>
|
||||
/// Reads data from CPU mapped memory, from guest code. (with read tracking)
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Type of the data being read</typeparam>
|
||||
/// <param name="va">Virtual address of the data in memory</param>
|
||||
/// <returns>The data</returns>
|
||||
T ReadGuest<T>(ulong va) where T : unmanaged
|
||||
{
|
||||
return ReadTracked<T>(va);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes data to CPU mapped memory.
|
||||
/// </summary>
|
||||
@ -36,6 +47,17 @@ namespace ARMeilleure.Memory
|
||||
/// <param name="value">Data to be written</param>
|
||||
void Write<T>(ulong va, T value) where T : unmanaged;
|
||||
|
||||
/// <summary>
|
||||
/// Writes data to CPU mapped memory, from guest code.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Type of the data being written</typeparam>
|
||||
/// <param name="va">Virtual address to write the data into</param>
|
||||
/// <param name="value">Data to be written</param>
|
||||
void WriteGuest<T>(ulong va, T value) where T : unmanaged
|
||||
{
|
||||
Write(va, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a read-only span of data from CPU mapped memory.
|
||||
/// </summary>
|
||||
|
@ -35,18 +35,35 @@ namespace ARMeilleure.Memory
|
||||
/// Allows invalid access from JIT code to the rest of the program, but is faster.
|
||||
/// </summary>
|
||||
HostMappedUnsafe,
|
||||
|
||||
/// <summary>
|
||||
/// High level implementation using a software flat page table for address translation
|
||||
/// with no support for handling invalid or non-contiguous memory access.
|
||||
/// </summary>
|
||||
HostTracked,
|
||||
|
||||
/// <summary>
|
||||
/// High level implementation using a software flat page table for address translation
|
||||
/// without masking the address and no support for handling invalid or non-contiguous memory access.
|
||||
/// </summary>
|
||||
HostTrackedUnsafe,
|
||||
}
|
||||
|
||||
static class MemoryManagerTypeExtensions
|
||||
public static class MemoryManagerTypeExtensions
|
||||
{
|
||||
public static bool IsHostMapped(this MemoryManagerType type)
|
||||
{
|
||||
return type == MemoryManagerType.HostMapped || type == MemoryManagerType.HostMappedUnsafe;
|
||||
}
|
||||
|
||||
public static bool IsHostTracked(this MemoryManagerType type)
|
||||
{
|
||||
return type == MemoryManagerType.HostTracked || type == MemoryManagerType.HostTrackedUnsafe;
|
||||
}
|
||||
|
||||
public static bool IsHostMappedOrTracked(this MemoryManagerType type)
|
||||
{
|
||||
return type == MemoryManagerType.HostTracked || type == MemoryManagerType.HostMapped || type == MemoryManagerType.HostMappedUnsafe;
|
||||
return type.IsHostMapped() || type.IsHostTracked();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -7,6 +7,7 @@ namespace ARMeilleure.Memory
|
||||
public const int DefaultGranularity = 65536; // Mapping granularity in Windows.
|
||||
|
||||
public IJitMemoryBlock Block { get; }
|
||||
public IJitMemoryAllocator Allocator { get; }
|
||||
|
||||
public IntPtr Pointer => Block.Pointer;
|
||||
|
||||
@ -21,6 +22,7 @@ namespace ARMeilleure.Memory
|
||||
granularity = DefaultGranularity;
|
||||
}
|
||||
|
||||
Allocator = allocator;
|
||||
Block = allocator.Reserve(maxSize);
|
||||
_maxSize = maxSize;
|
||||
_sizeGranularity = granularity;
|
||||
|
@ -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,124 +21,7 @@ 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()
|
||||
{
|
||||
_handlerConfig = Marshal.AllocHGlobal(Unsafe.SizeOf<SignalHandlerConfig>());
|
||||
ref SignalHandlerConfig config = ref GetConfigRef();
|
||||
|
||||
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)
|
||||
private static Operand EmitGenericRegionCheck(EmitterContext context, IntPtr signalStructPtr, Operand faultAddress, Operand isWrite, int rangeStructSize)
|
||||
{
|
||||
Operand inRegionLocal = context.AllocateLocal(OperandType.I32);
|
||||
context.Copy(inRegionLocal, Const(0));
|
||||
@ -196,7 +30,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 +44,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.Subtract(faultAddress, rangeAddress);
|
||||
|
||||
// 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,8 +60,10 @@ 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);
|
||||
context.Copy(inRegionLocal, result);
|
||||
Operand result = context.Call(trackingActionPtr, OperandType.I64, offset, Const(1UL), isWrite);
|
||||
context.Copy(inRegionLocal, context.ICompareNotEqual(result, Const(0UL)));
|
||||
|
||||
GenerateFaultAddressPatchCode(context, faultAddress, 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)
|
||||
{
|
||||
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);
|
||||
|
||||
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)
|
||||
{
|
||||
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);
|
||||
|
||||
Operand endLabel = Label();
|
||||
|
||||
@ -421,7 +254,88 @@ 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;
|
||||
}
|
||||
|
||||
private static void GenerateFaultAddressPatchCode(EmitterContext context, Operand faultAddress, Operand newAddress)
|
||||
{
|
||||
if (RuntimeInformation.ProcessArchitecture == Architecture.Arm64)
|
||||
{
|
||||
if (SupportsFaultAddressPatchingForHostOs())
|
||||
{
|
||||
Operand lblSkip = Label();
|
||||
|
||||
context.BranchIf(lblSkip, faultAddress, newAddress, Comparison.Equal);
|
||||
|
||||
Operand ucontextPtr = context.LoadArgument(OperandType.I64, 2);
|
||||
Operand pcCtxAddress = default;
|
||||
ulong baseRegsOffset = 0;
|
||||
|
||||
if (OperatingSystem.IsLinux())
|
||||
{
|
||||
pcCtxAddress = context.Add(ucontextPtr, Const(440UL));
|
||||
baseRegsOffset = 184UL;
|
||||
}
|
||||
else if (OperatingSystem.IsMacOS() || OperatingSystem.IsIOS())
|
||||
{
|
||||
ucontextPtr = context.Load(OperandType.I64, context.Add(ucontextPtr, Const(48UL)));
|
||||
|
||||
pcCtxAddress = context.Add(ucontextPtr, Const(272UL));
|
||||
baseRegsOffset = 16UL;
|
||||
}
|
||||
|
||||
Operand pc = context.Load(OperandType.I64, pcCtxAddress);
|
||||
|
||||
Operand reg = GetAddressRegisterFromArm64Instruction(context, pc);
|
||||
Operand reg64 = context.ZeroExtend32(OperandType.I64, reg);
|
||||
Operand regCtxAddress = context.Add(ucontextPtr, context.Add(context.ShiftLeft(reg64, Const(3)), Const(baseRegsOffset)));
|
||||
Operand regAddress = context.Load(OperandType.I64, regCtxAddress);
|
||||
|
||||
Operand addressDelta = context.Subtract(regAddress, faultAddress);
|
||||
|
||||
context.Store(regCtxAddress, context.Add(newAddress, addressDelta));
|
||||
|
||||
context.MarkLabel(lblSkip);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static Operand GetAddressRegisterFromArm64Instruction(EmitterContext context, Operand pc)
|
||||
{
|
||||
Operand inst = context.Load(OperandType.I32, pc);
|
||||
Operand reg = context.AllocateLocal(OperandType.I32);
|
||||
|
||||
Operand isSysInst = context.ICompareEqual(context.BitwiseAnd(inst, Const(0xFFF80000)), Const(0xD5080000));
|
||||
|
||||
Operand lblSys = Label();
|
||||
Operand lblEnd = Label();
|
||||
|
||||
context.BranchIfTrue(lblSys, isSysInst, BasicBlockFrequency.Cold);
|
||||
|
||||
context.Copy(reg, context.BitwiseAnd(context.ShiftRightUI(inst, Const(5)), Const(0x1F)));
|
||||
context.Branch(lblEnd);
|
||||
|
||||
context.MarkLabel(lblSys);
|
||||
context.Copy(reg, context.BitwiseAnd(inst, Const(0x1F)));
|
||||
|
||||
context.MarkLabel(lblEnd);
|
||||
|
||||
return reg;
|
||||
}
|
||||
|
||||
public static bool SupportsFaultAddressPatchingForHost()
|
||||
{
|
||||
return SupportsFaultAddressPatchingForHostArch() && SupportsFaultAddressPatchingForHostOs();
|
||||
}
|
||||
|
||||
private static bool SupportsFaultAddressPatchingForHostArch()
|
||||
{
|
||||
return RuntimeInformation.ProcessArchitecture == Architecture.Arm64;
|
||||
}
|
||||
|
||||
private static bool SupportsFaultAddressPatchingForHostOs()
|
||||
{
|
||||
return OperatingSystem.IsLinux() || OperatingSystem.IsMacOS() || OperatingSystem.IsIOS();
|
||||
}
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
@ -3,6 +3,7 @@ using ARMeilleure.CodeGen.Unwinding;
|
||||
using ARMeilleure.Memory;
|
||||
using ARMeilleure.Native;
|
||||
using Ryujinx.Memory;
|
||||
using Ryujinx.Common.Logging;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
@ -18,7 +19,7 @@ namespace ARMeilleure.Translation.Cache
|
||||
private static readonly int _pageMask = _pageSize - 4;
|
||||
|
||||
private const int CodeAlignment = 4; // Bytes.
|
||||
private const int CacheSize = 1024 * 1024 * 1024;
|
||||
private const int CacheSize = 128 * 1024 * 1024;
|
||||
private const int CacheSizeIOS = 128 * 1024 * 1024;
|
||||
|
||||
private static ReservedRegion _jitRegion;
|
||||
@ -31,6 +32,10 @@ namespace ARMeilleure.Translation.Cache
|
||||
private static readonly object _lock = new();
|
||||
private static bool _initialized;
|
||||
|
||||
private static readonly List<ReservedRegion> _jitRegions = new();
|
||||
|
||||
private static int _activeRegionIndex = 0;
|
||||
|
||||
[SupportedOSPlatform("windows")]
|
||||
[LibraryImport("kernel32.dll", SetLastError = true)]
|
||||
public static partial IntPtr FlushInstructionCache(IntPtr hProcess, IntPtr lpAddress, UIntPtr dwSize);
|
||||
@ -49,7 +54,11 @@ namespace ARMeilleure.Translation.Cache
|
||||
return;
|
||||
}
|
||||
|
||||
_jitRegion = new ReservedRegion(allocator, (ulong)(OperatingSystem.IsIOS() ? CacheSizeIOS : CacheSize));
|
||||
var firstRegion = new ReservedRegion(allocator, CacheSize);
|
||||
|
||||
|
||||
_jitRegions.Add(firstRegion);
|
||||
_activeRegionIndex = 0;
|
||||
|
||||
if (!OperatingSystem.IsWindows() && !OperatingSystem.IsMacOS() && !OperatingSystem.IsIOS())
|
||||
{
|
||||
@ -60,7 +69,9 @@ namespace ARMeilleure.Translation.Cache
|
||||
|
||||
if (OperatingSystem.IsWindows())
|
||||
{
|
||||
JitUnwindWindows.InstallFunctionTableHandler(_jitRegion.Pointer, CacheSize, _jitRegion.Pointer + Allocate(_pageSize));
|
||||
JitUnwindWindows.InstallFunctionTableHandler(
|
||||
firstRegion.Pointer, CacheSize, firstRegion.Pointer + Allocate(_pageSize)
|
||||
);
|
||||
}
|
||||
|
||||
_initialized = true;
|
||||
@ -73,7 +84,9 @@ namespace ARMeilleure.Translation.Cache
|
||||
{
|
||||
while (_deferredRxProtect.TryDequeue(out var result))
|
||||
{
|
||||
ReprotectAsExecutable(result.funcOffset, result.length);
|
||||
ReservedRegion targetRegion = _jitRegions[_activeRegionIndex];
|
||||
|
||||
ReprotectAsExecutable(targetRegion, result.funcOffset, result.length);
|
||||
}
|
||||
}
|
||||
|
||||
@ -87,21 +100,14 @@ namespace ARMeilleure.Translation.Cache
|
||||
|
||||
int funcOffset = Allocate(code.Length, deferProtect);
|
||||
|
||||
IntPtr funcPtr = _jitRegion.Pointer + funcOffset;
|
||||
ReservedRegion targetRegion = _jitRegions[_activeRegionIndex];
|
||||
IntPtr funcPtr = targetRegion.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);
|
||||
}
|
||||
ReprotectAsExecutable(targetRegion, funcOffset, code.Length);
|
||||
JitSupportDarwinAot.Invalidate(funcPtr, (ulong)code.Length);
|
||||
}
|
||||
else if (OperatingSystem.IsMacOS()&& RuntimeInformation.ProcessArchitecture == Architecture.Arm64)
|
||||
{
|
||||
@ -115,9 +121,9 @@ namespace ARMeilleure.Translation.Cache
|
||||
}
|
||||
else
|
||||
{
|
||||
ReprotectAsWritable(funcOffset, code.Length);
|
||||
ReprotectAsWritable(targetRegion, funcOffset, code.Length);
|
||||
Marshal.Copy(code, 0, funcPtr, code.Length);
|
||||
ReprotectAsExecutable(funcOffset, code.Length);
|
||||
ReprotectAsExecutable(targetRegion, funcOffset, code.Length);
|
||||
|
||||
if (OperatingSystem.IsWindows() && RuntimeInformation.ProcessArchitecture == Architecture.Arm64)
|
||||
{
|
||||
@ -139,41 +145,50 @@ namespace ARMeilleure.Translation.Cache
|
||||
{
|
||||
if (OperatingSystem.IsIOS())
|
||||
{
|
||||
return;
|
||||
// return;
|
||||
}
|
||||
|
||||
lock (_lock)
|
||||
{
|
||||
Debug.Assert(_initialized);
|
||||
|
||||
int funcOffset = (int)(pointer.ToInt64() - _jitRegion.Pointer.ToInt64());
|
||||
|
||||
if (TryFind(funcOffset, out CacheEntry entry, out int entryIndex) && entry.Offset == funcOffset)
|
||||
foreach (var region in _jitRegions)
|
||||
{
|
||||
_cacheAllocator.Free(funcOffset, AlignCodeSize(entry.Size));
|
||||
_cacheEntries.RemoveAt(entryIndex);
|
||||
if (pointer.ToInt64() < region.Pointer.ToInt64() ||
|
||||
pointer.ToInt64() >= (region.Pointer + CacheSize).ToInt64())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
int funcOffset = (int)(pointer.ToInt64() - region.Pointer.ToInt64());
|
||||
|
||||
if (TryFind(funcOffset, out CacheEntry entry, out int entryIndex) && entry.Offset == funcOffset)
|
||||
{
|
||||
_cacheAllocator.Free(funcOffset, AlignCodeSize(entry.Size));
|
||||
_cacheEntries.RemoveAt(entryIndex);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void ReprotectAsWritable(int offset, int size)
|
||||
private static void ReprotectAsWritable(ReservedRegion region, int offset, int size)
|
||||
{
|
||||
int endOffs = offset + size;
|
||||
|
||||
int regionStart = offset & ~_pageMask;
|
||||
int regionEnd = (endOffs + _pageMask) & ~_pageMask;
|
||||
|
||||
_jitRegion.Block.MapAsRwx((ulong)regionStart, (ulong)(regionEnd - regionStart));
|
||||
region.Block.MapAsRwx((ulong)regionStart, (ulong)(regionEnd - regionStart));
|
||||
}
|
||||
|
||||
private static void ReprotectAsExecutable(int offset, int size)
|
||||
private static void ReprotectAsExecutable(ReservedRegion region, int offset, int size)
|
||||
{
|
||||
int endOffs = offset + size;
|
||||
|
||||
int regionStart = offset & ~_pageMask;
|
||||
int regionEnd = (endOffs + _pageMask) & ~_pageMask;
|
||||
|
||||
_jitRegion.Block.MapAsRx((ulong)regionStart, (ulong)(regionEnd - regionStart));
|
||||
region.Block.MapAsRx((ulong)regionStart, (ulong)(regionEnd - regionStart));
|
||||
}
|
||||
|
||||
private static int Allocate(int codeSize, bool deferProtect = false)
|
||||
@ -187,20 +202,35 @@ namespace ARMeilleure.Translation.Cache
|
||||
alignment = 0x4000;
|
||||
}
|
||||
|
||||
int allocOffset = _cacheAllocator.Allocate(ref codeSize, alignment);
|
||||
|
||||
//DEBUG: Show JIT Memory Allocation
|
||||
|
||||
//Console.WriteLine($"{allocOffset:x8}: {codeSize:x8} {alignment:x8}");
|
||||
|
||||
if (allocOffset < 0)
|
||||
for (int i = _activeRegionIndex; i < _jitRegions.Count; i++)
|
||||
{
|
||||
throw new OutOfMemoryException("JIT Cache exhausted.");
|
||||
int allocOffset = _cacheAllocator.Allocate(ref codeSize, alignment);
|
||||
|
||||
if (allocOffset >= 0)
|
||||
{
|
||||
_jitRegions[i].ExpandIfNeeded((ulong)allocOffset + (ulong)codeSize);
|
||||
_activeRegionIndex = i;
|
||||
return allocOffset;
|
||||
}
|
||||
}
|
||||
|
||||
_jitRegion.ExpandIfNeeded((ulong)allocOffset + (ulong)codeSize);
|
||||
int exhaustedRegion = _activeRegionIndex;
|
||||
var newRegion = new ReservedRegion(_jitRegions[0].Allocator, CacheSize);
|
||||
_jitRegions.Add(newRegion);
|
||||
_activeRegionIndex = _jitRegions.Count - 1;
|
||||
|
||||
return allocOffset;
|
||||
int newRegionNumber = _activeRegionIndex;
|
||||
|
||||
_cacheAllocator = new CacheMemoryAllocator(CacheSize);
|
||||
|
||||
int allocOffsetNew = _cacheAllocator.Allocate(ref codeSize, alignment);
|
||||
if (allocOffsetNew < 0)
|
||||
{
|
||||
throw new OutOfMemoryException("Failed to allocate in new Cache Region!");
|
||||
}
|
||||
|
||||
newRegion.ExpandIfNeeded((ulong)allocOffsetNew + (ulong)codeSize);
|
||||
return allocOffsetNew;
|
||||
}
|
||||
|
||||
private static int AlignCodeSize(int codeSize, bool deferProtect = false)
|
||||
|
@ -11,7 +11,7 @@ namespace ARMeilleure.Translation
|
||||
private int[] _postOrderMap;
|
||||
|
||||
public int LocalsCount { get; private set; }
|
||||
public BasicBlock Entry { get; }
|
||||
public BasicBlock Entry { get; private set; }
|
||||
public IntrusiveList<BasicBlock> Blocks { get; }
|
||||
public BasicBlock[] PostOrderBlocks => _postOrderBlocks;
|
||||
public int[] PostOrderMap => _postOrderMap;
|
||||
@ -34,6 +34,15 @@ namespace ARMeilleure.Translation
|
||||
return result;
|
||||
}
|
||||
|
||||
public void UpdateEntry(BasicBlock newEntry)
|
||||
{
|
||||
newEntry.AddSuccessor(Entry);
|
||||
|
||||
Entry = newEntry;
|
||||
Blocks.AddFirst(newEntry);
|
||||
Update();
|
||||
}
|
||||
|
||||
public void Update()
|
||||
{
|
||||
RemoveUnreachableBlocks(Blocks);
|
||||
|
@ -30,7 +30,7 @@ namespace ARMeilleure.Translation.PTC
|
||||
private const string OuterHeaderMagicString = "PTCohd\0\0";
|
||||
private const string InnerHeaderMagicString = "PTCihd\0\0";
|
||||
|
||||
private const uint InternalVersion = 5518; //! To be incremented manually for each change to the ARMeilleure project.
|
||||
private const uint InternalVersion = 6950; //! To be incremented manually for each change to the ARMeilleure project.
|
||||
|
||||
private const string ActualDir = "0";
|
||||
private const string BackupDir = "1";
|
||||
@ -414,8 +414,6 @@ namespace ARMeilleure.Translation.PTC
|
||||
finally
|
||||
{
|
||||
ResetCarriersIfNeeded();
|
||||
|
||||
GCSettings.LargeObjectHeapCompactionMode = GCLargeObjectHeapCompactionMode.CompactOnce;
|
||||
}
|
||||
|
||||
_waitEvent.Set();
|
||||
@ -791,8 +789,6 @@ namespace ARMeilleure.Translation.PTC
|
||||
{
|
||||
ResetCarriersIfNeeded();
|
||||
|
||||
GCSettings.LargeObjectHeapCompactionMode = GCLargeObjectHeapCompactionMode.CompactOnce;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@ -858,8 +854,14 @@ namespace ARMeilleure.Translation.PTC
|
||||
|
||||
Stopwatch sw = Stopwatch.StartNew();
|
||||
|
||||
threads.ForEach((thread) => thread.Start());
|
||||
threads.ForEach((thread) => thread.Join());
|
||||
foreach (var thread in threads)
|
||||
{
|
||||
thread.Start();
|
||||
}
|
||||
foreach (var thread in threads)
|
||||
{
|
||||
thread.Join();
|
||||
}
|
||||
|
||||
threads.Clear();
|
||||
|
||||
@ -1005,7 +1007,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 |= (OperatingSystem.IsIOS() || Ryujinx.Common.PlatformInfo.IsBionic ? 1u : 0u) << 4;
|
||||
#pragma warning restore IDE0055
|
||||
|
||||
return osPlatform;
|
||||
|
@ -89,6 +89,17 @@ namespace ARMeilleure.Translation
|
||||
|
||||
public static void RunPass(ControlFlowGraph cfg, ExecutionMode mode)
|
||||
{
|
||||
if (cfg.Entry.Predecessors.Count != 0)
|
||||
{
|
||||
// We expect the entry block to have no predecessors.
|
||||
// This is required because we have a implicit context load at the start of the function,
|
||||
// but if there is a jump to the start of the function, the context load would trash the modified values.
|
||||
// Here we insert a new entry block that will jump to the existing entry block.
|
||||
BasicBlock newEntry = new BasicBlock(cfg.Blocks.Count);
|
||||
|
||||
cfg.UpdateEntry(newEntry);
|
||||
}
|
||||
|
||||
// Compute local register inputs and outputs used inside blocks.
|
||||
RegisterMask[] localInputs = new RegisterMask[cfg.Blocks.Count];
|
||||
RegisterMask[] localOutputs = new RegisterMask[cfg.Blocks.Count];
|
||||
@ -201,7 +212,7 @@ namespace ARMeilleure.Translation
|
||||
|
||||
// The only block without any predecessor should be the entry block.
|
||||
// It always needs a context load as it is the first block to run.
|
||||
if (block.Predecessors.Count == 0 || hasContextLoad)
|
||||
if (block == cfg.Entry || hasContextLoad)
|
||||
{
|
||||
long vecMask = globalInputs[block.Index].VecMask;
|
||||
long intMask = globalInputs[block.Index].IntMask;
|
||||
|
@ -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;
|
||||
@ -105,8 +102,6 @@ namespace ARMeilleure.Translation
|
||||
{
|
||||
if (Interlocked.Increment(ref _threadCount) == 1)
|
||||
{
|
||||
IsReadyForTranslation.WaitOne();
|
||||
|
||||
if (_ptc.State == PtcState.Enabled)
|
||||
{
|
||||
Debug.Assert(Functions.Count == 0);
|
||||
|
@ -80,7 +80,10 @@ namespace ARMeilleure.Translation
|
||||
return true;
|
||||
}
|
||||
|
||||
Monitor.Wait(Sync);
|
||||
if (!_disposed)
|
||||
{
|
||||
Monitor.Wait(Sync);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
16
src/LibRyujinx.NativeSample/LibRyujinx.NativeSample.csproj
Normal file
16
src/LibRyujinx.NativeSample/LibRyujinx.NativeSample.csproj
Normal file
@ -0,0 +1,16 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<Platforms>AnyCPU</Platforms>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="OpenTK" />
|
||||
<PackageReference Include="Ryujinx.SDL2-CS" />
|
||||
</ItemGroup>
|
||||
</Project>
|
228
src/LibRyujinx.NativeSample/LibRyujinxInterop.cs
Normal file
228
src/LibRyujinx.NativeSample/LibRyujinxInterop.cs
Normal file
@ -0,0 +1,228 @@
|
||||
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(bool isHostMapped,
|
||||
bool useHypervisor,
|
||||
SystemLanguage systemLanguage,
|
||||
RegionCode regionCode,
|
||||
bool enableVsync,
|
||||
bool enableDockedMode,
|
||||
bool enablePtc,
|
||||
bool enableInternetAccess,
|
||||
IntPtr timeZone,
|
||||
bool ignoreMissingServices);
|
||||
|
||||
[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);
|
||||
}
|
||||
|
||||
public enum GraphicsBackend
|
||||
{
|
||||
Vulkan,
|
||||
OpenGl
|
||||
}
|
||||
|
||||
public enum BackendThreading
|
||||
{
|
||||
Auto,
|
||||
Off,
|
||||
On
|
||||
}
|
||||
|
||||
[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 SystemLanguage
|
||||
{
|
||||
Japanese,
|
||||
AmericanEnglish,
|
||||
French,
|
||||
German,
|
||||
Italian,
|
||||
Spanish,
|
||||
Chinese,
|
||||
Korean,
|
||||
Dutch,
|
||||
Portuguese,
|
||||
Russian,
|
||||
Taiwanese,
|
||||
BritishEnglish,
|
||||
CanadianFrench,
|
||||
LatinAmericanSpanish,
|
||||
SimplifiedChinese,
|
||||
TraditionalChinese,
|
||||
BrazilianPortuguese,
|
||||
}
|
||||
public enum RegionCode
|
||||
{
|
||||
Japan,
|
||||
USA,
|
||||
Europe,
|
||||
Australia,
|
||||
China,
|
||||
Korea,
|
||||
Taiwan,
|
||||
|
||||
Min = Japan,
|
||||
Max = Taiwan,
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
}
|
260
src/LibRyujinx.NativeSample/NativeWindow.cs
Normal file
260
src/LibRyujinx.NativeSample/NativeWindow.cs
Normal file
@ -0,0 +1,260 @@
|
||||
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);
|
||||
var timeZone = Marshal.StringToHGlobalAnsi("UTC");
|
||||
success = LibRyujinxInterop.InitializeDevice(true,
|
||||
false,
|
||||
SystemLanguage.AmericanEnglish,
|
||||
RegionCode.USA,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
false,
|
||||
timeZone,
|
||||
false);
|
||||
LibRyujinxInterop.InitializeInput(ClientSize.X, ClientSize.Y);
|
||||
Marshal.FreeHGlobal(timeZone);
|
||||
|
||||
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);
|
||||
NewInputFrame();
|
||||
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()
|
||||
{
|
||||
ClientSize = new Vector2i(800, 600),
|
||||
Title = "Ryujinx Native",
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
114
src/LibRyujinx/Android/AndroidUiHandler.cs
Normal file
114
src/LibRyujinx/Android/AndroidUiHandler.cs
Normal file
@ -0,0 +1,114 @@
|
||||
using LibHac.Tools.Fs;
|
||||
using Ryujinx.Common.Logging;
|
||||
using Ryujinx.HLE;
|
||||
using Ryujinx.HLE.HOS.Applets;
|
||||
using Ryujinx.HLE.HOS.Applets.SoftwareKeyboard;
|
||||
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
|
||||
{
|
||||
private bool _isDisposed;
|
||||
private bool _isOkPressed;
|
||||
private string? _input;
|
||||
private ManualResetEvent _resetEvent = new ManualResetEvent(false);
|
||||
|
||||
public IHostUITheme HostUITheme => throw new NotImplementedException();
|
||||
|
||||
public IDynamicTextInputHandler CreateDynamicTextInputHandler()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public bool DisplayErrorAppletDialog(string title, string message, string[] buttonsText)
|
||||
{
|
||||
Interop.UpdateUiHandler(title ?? "",
|
||||
message ?? "",
|
||||
"",
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
KeyboardMode.Default,
|
||||
"",
|
||||
"");
|
||||
|
||||
return _isOkPressed;
|
||||
}
|
||||
|
||||
public bool DisplayInputDialog(SoftwareKeyboardUIArgs args, out string userText)
|
||||
{
|
||||
_input = null;
|
||||
_resetEvent.Reset();
|
||||
Interop.UpdateUiHandler("Software Keyboard",
|
||||
args.HeaderText ?? "",
|
||||
args.GuideText ?? "",
|
||||
2,
|
||||
args.StringLengthMin,
|
||||
args.StringLengthMax,
|
||||
args.KeyboardMode,
|
||||
args.SubtitleText ?? "",
|
||||
args.InitialText ?? "");
|
||||
|
||||
_resetEvent.WaitOne();
|
||||
|
||||
userText = _input ?? "";
|
||||
|
||||
return _isOkPressed;
|
||||
}
|
||||
|
||||
public bool DisplayMessageDialog(string title, string message)
|
||||
{
|
||||
Interop.UpdateUiHandler(title ?? "",
|
||||
message ?? "",
|
||||
"",
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
KeyboardMode.Default,
|
||||
"",
|
||||
"");
|
||||
|
||||
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 SetResponse(bool isOkPressed, string input)
|
||||
{
|
||||
if (_isDisposed)
|
||||
return;
|
||||
_isOkPressed = isOkPressed;
|
||||
_input = input;
|
||||
_resetEvent.Set();
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_isDisposed = true;
|
||||
}
|
||||
}
|
||||
}
|
232
src/LibRyujinx/Android/Interop.cs
Normal file
232
src/LibRyujinx/Android/Interop.cs
Normal file
@ -0,0 +1,232 @@
|
||||
using LibRyujinx.Jni;
|
||||
using LibRyujinx.Jni.Identifiers;
|
||||
using LibRyujinx.Jni.Pointers;
|
||||
using LibRyujinx.Jni.Primitives;
|
||||
using LibRyujinx.Jni.References;
|
||||
using LibRyujinx.Jni.Values;
|
||||
using Rxmxnx.PInvoke;
|
||||
using Ryujinx.Common.Logging;
|
||||
using Ryujinx.Common.Memory;
|
||||
using Ryujinx.HLE.HOS.Applets.SoftwareKeyboard;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace LibRyujinx.Android
|
||||
{
|
||||
internal unsafe static class Interop
|
||||
{
|
||||
internal const string BaseClassName = "org/ryujinx/android/RyujinxNative";
|
||||
|
||||
private static JGlobalRef? _classId;
|
||||
private static ConcurrentDictionary<(string method, string descriptor), JMethodId> _methodCache = new ConcurrentDictionary<(string method, string descriptor), JMethodId>();
|
||||
private static (string name, string descriptor)[] _methods = new[]
|
||||
{
|
||||
("test", "()V"),
|
||||
("updateUiHandler", "(JJJIIIIJJ)V"),
|
||||
("frameEnded", "()V"),
|
||||
("updateProgress", "(JF)V"),
|
||||
("getSurfacePtr", "()J"),
|
||||
("getWindowHandle", "()J")
|
||||
};
|
||||
|
||||
internal static void Initialize(JEnvRef jniEnv)
|
||||
{
|
||||
var vm = JniHelper.GetVirtualMachine(jniEnv);
|
||||
if (_classId == null)
|
||||
{
|
||||
var className = new ReadOnlySpan<Byte>(Encoding.UTF8.GetBytes(BaseClassName));
|
||||
using (IReadOnlyFixedMemory<Byte>.IDisposable cName = className.GetUnsafeValPtr()
|
||||
.GetUnsafeFixedContext(className.Length))
|
||||
{
|
||||
_classId = JniHelper.GetGlobalClass(jniEnv, cName);
|
||||
if (_classId == null)
|
||||
{
|
||||
Logger.Info?.Print(LogClass.Application, $"Class Id {BaseClassName} not found");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var x in _methods)
|
||||
{
|
||||
CacheMethod(jniEnv, x.name, x.descriptor);
|
||||
}
|
||||
|
||||
JniEnv._jvm = vm;
|
||||
}
|
||||
|
||||
private static void CacheMethod(JEnvRef jEnv, string name, string descriptor)
|
||||
{
|
||||
if (!_methodCache.TryGetValue((name, descriptor), out var method))
|
||||
{
|
||||
var methodName = new ReadOnlySpan<Byte>(Encoding.UTF8.GetBytes(name));
|
||||
var descriptorId = new ReadOnlySpan<Byte>(Encoding.UTF8.GetBytes(descriptor));
|
||||
using (IReadOnlyFixedMemory<Byte>.IDisposable mName = methodName.GetUnsafeValPtr()
|
||||
.GetUnsafeFixedContext(methodName.Length))
|
||||
using (IReadOnlyFixedMemory<Byte>.IDisposable dName = descriptorId.GetUnsafeValPtr()
|
||||
.GetUnsafeFixedContext(descriptorId.Length))
|
||||
{
|
||||
var methodId = JniHelper.GetStaticMethodId(jEnv, (JClassLocalRef)(_classId.Value.Value), mName, dName);
|
||||
if (methodId == null)
|
||||
{
|
||||
Logger.Warning?.Print(LogClass.Application, $"Java Method Id {name} not found");
|
||||
return;
|
||||
}
|
||||
|
||||
method = methodId.Value;
|
||||
_methodCache[(name, descriptor)] = method;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void CallVoidMethod(string name, string descriptor, params JValue[] values)
|
||||
{
|
||||
using var env = JniEnv.Create();
|
||||
if (_methodCache.TryGetValue((name, descriptor), out var method))
|
||||
{
|
||||
if (descriptor.EndsWith("V"))
|
||||
{
|
||||
JniHelper.CallStaticVoidMethod(env.Env, (JClassLocalRef)(_classId.Value.Value), method, values);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static JLong CallLongMethod(string name, string descriptor, params JValue[] values)
|
||||
{
|
||||
using var env = JniEnv.Create();
|
||||
if (_methodCache.TryGetValue((name, descriptor), out var method))
|
||||
{
|
||||
if (descriptor.EndsWith("J"))
|
||||
return JniHelper.CallStaticLongMethod(env.Env, (JClassLocalRef)(_classId.Value.Value), method, values) ?? (JLong)(-1);
|
||||
}
|
||||
|
||||
return (JLong)(-1);
|
||||
}
|
||||
|
||||
public static void Test()
|
||||
{
|
||||
CallVoidMethod("test", "()V");
|
||||
}
|
||||
|
||||
public static void FrameEnded(double time)
|
||||
{
|
||||
CallVoidMethod("frameEnded", "()V");
|
||||
}
|
||||
|
||||
public static void UpdateProgress(string info, float progress)
|
||||
{
|
||||
using var infoPtr = new TempNativeString(info);
|
||||
CallVoidMethod("updateProgress", "(JF)V", new JValue[]
|
||||
{
|
||||
JValue.Create(infoPtr.AsBytes()),
|
||||
JValue.Create(progress.AsBytes())
|
||||
});
|
||||
}
|
||||
|
||||
public static JLong GetSurfacePtr()
|
||||
{
|
||||
return CallLongMethod("getSurfacePtr", "()J");
|
||||
}
|
||||
|
||||
public static JLong GetWindowsHandle()
|
||||
{
|
||||
return CallLongMethod("getWindowHandle", "()J");
|
||||
}
|
||||
|
||||
public static void UpdateUiHandler(string newTitle,
|
||||
string newMessage,
|
||||
string newWatermark,
|
||||
int newType,
|
||||
int min,
|
||||
int max,
|
||||
KeyboardMode nMode,
|
||||
string newSubtitle,
|
||||
string newInitialText)
|
||||
{
|
||||
using var titlePointer = new TempNativeString(newTitle);
|
||||
using var messagePointer = new TempNativeString(newMessage);
|
||||
using var watermarkPointer = new TempNativeString(newWatermark);
|
||||
using var subtitlePointer = new TempNativeString(newSubtitle);
|
||||
using var newInitialPointer = new TempNativeString(newInitialText);
|
||||
CallVoidMethod("updateUiHandler", "(JJJIIIIJJ)V", new JValue[]
|
||||
{
|
||||
JValue.Create(titlePointer.AsBytes()),
|
||||
JValue.Create(messagePointer.AsBytes()),
|
||||
JValue.Create(watermarkPointer.AsBytes()),
|
||||
JValue.Create(newType.AsBytes()),
|
||||
JValue.Create(min.AsBytes()),
|
||||
JValue.Create(max.AsBytes()),
|
||||
JValue.Create(nMode.AsBytes()),
|
||||
JValue.Create(subtitlePointer.AsBytes()),
|
||||
JValue.Create(newInitialPointer.AsBytes())
|
||||
});
|
||||
}
|
||||
|
||||
private class TempNativeString : IDisposable
|
||||
{
|
||||
private JLong _jPointer;
|
||||
|
||||
public TempNativeString(string value)
|
||||
{
|
||||
Pointer = Marshal.StringToHGlobalAuto(value);
|
||||
JPointer = (JLong)Pointer;
|
||||
}
|
||||
|
||||
public nint Pointer { get; private set; }
|
||||
public JLong JPointer { get => _jPointer; private set => _jPointer = value; }
|
||||
|
||||
public Span<byte> AsBytes()
|
||||
{
|
||||
return _jPointer.AsBytes();
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (Pointer != IntPtr.Zero)
|
||||
{
|
||||
Marshal.FreeHGlobal(Pointer);
|
||||
}
|
||||
Pointer = IntPtr.Zero;
|
||||
}
|
||||
}
|
||||
|
||||
private class JniEnv : IDisposable
|
||||
{
|
||||
internal static JavaVMRef? _jvm;
|
||||
private readonly JEnvRef _env;
|
||||
private readonly bool _newAttach;
|
||||
|
||||
public JEnvRef Env => _env;
|
||||
|
||||
private JniEnv(JEnvRef env, bool newAttach)
|
||||
{
|
||||
_env = env;
|
||||
_newAttach = newAttach;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if(_newAttach)
|
||||
{
|
||||
JniHelper.Detach(_jvm!.Value);
|
||||
}
|
||||
}
|
||||
|
||||
public static JniEnv? Create()
|
||||
{
|
||||
bool newAttach = false;
|
||||
ReadOnlySpan<Byte> threadName = "JvmCall"u8;
|
||||
var env = _jvm == null ? default : JniHelper.Attach(_jvm.Value, threadName.GetUnsafeValPtr().GetUnsafeFixedContext(threadName.Length),
|
||||
out newAttach);
|
||||
|
||||
return env != null ? new JniEnv(env.Value, newAttach) : null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
357
src/LibRyujinx/Android/Jni/Delegates.cs
Normal file
357
src/LibRyujinx/Android/Jni/Delegates.cs
Normal file
@ -0,0 +1,357 @@
|
||||
using LibRyujinx.Jni.Identifiers;
|
||||
using LibRyujinx.Jni.Pointers;
|
||||
using LibRyujinx.Jni.Primitives;
|
||||
using LibRyujinx.Jni.References;
|
||||
using LibRyujinx.Jni.Values;
|
||||
using System;
|
||||
|
||||
using Rxmxnx.PInvoke;
|
||||
|
||||
namespace LibRyujinx.Jni;
|
||||
|
||||
internal delegate Int32 GetVersionDelegate(JEnvRef env);
|
||||
|
||||
internal delegate JResult RegisterNativesDelegate(JEnvRef env, JClassLocalRef jClass,
|
||||
ReadOnlyValPtr<JNativeMethod> methods0, Int32 nMethods);
|
||||
|
||||
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 GetVirtualMachineDelegate(JEnvRef env, out JavaVMRef jvm);
|
||||
internal delegate JResult DestroyVirtualMachineDelegate(JavaVMRef vm);
|
||||
internal delegate JResult AttachCurrentThreadDelegate(JavaVMRef vm, out JEnvRef env, in JavaVMAttachArgs args);
|
||||
internal delegate JResult DetachCurrentThreadDelegate(JavaVMRef vm);
|
||||
internal delegate JResult GetEnvDelegate(JavaVMRef vm, out JEnvRef env, Int32 version);
|
||||
internal delegate JResult AttachCurrentThreadAsDaemonDelegate(JavaVMRef vm, out JEnvRef env, in JavaVMAttachArgs args);
|
||||
|
||||
internal delegate JResult GetCreatedVirtualMachinesDelegate(ValPtr<JavaVMRef> buffer0, Int32 bufferLength,
|
||||
out Int32 totalVms);
|
||||
|
||||
internal delegate JStringLocalRef NewStringDelegate(JEnvRef env, ReadOnlyValPtr<Char> chars0, Int32 length);
|
||||
internal delegate Int32 GetStringLengthDelegate(JEnvRef env, JStringLocalRef jString);
|
||||
|
||||
internal delegate ReadOnlyValPtr<Char>
|
||||
GetStringCharsDelegate(JEnvRef env, JStringLocalRef jString, out JBoolean isCopy);
|
||||
|
||||
internal delegate void ReleaseStringCharsDelegate(JEnvRef env, JStringLocalRef jString, ReadOnlyValPtr<Char> chars0);
|
||||
internal delegate JStringLocalRef NewStringUtfDelegate(JEnvRef env, ReadOnlyValPtr<Byte> utf8Chars0);
|
||||
internal delegate Int32 GetStringUtfLengthDelegate(JEnvRef env, JStringLocalRef jString);
|
||||
|
||||
internal delegate ReadOnlyValPtr<Byte> GetStringUtfCharsDelegate(JEnvRef env, JStringLocalRef jString,
|
||||
out JBoolean isCopy);
|
||||
|
||||
internal delegate void ReleaseStringUtfCharsDelegate(JEnvRef env, JStringLocalRef jString,
|
||||
ReadOnlyValPtr<Byte> utf8Chars0);
|
||||
|
||||
internal delegate void GetStringRegionDelegate(JEnvRef env, JStringLocalRef jString, Int32 startIndex, Int32 length,
|
||||
ValPtr<Char> buffer0);
|
||||
|
||||
internal delegate void GetStringUtfRegionDelegate(JEnvRef env, JStringLocalRef jString, Int32 startIndex, Int32 length,
|
||||
ValPtr<Byte> buffer0);
|
||||
|
||||
internal delegate ReadOnlyValPtr<Char> GetStringCriticalDelegate(JEnvRef env, JStringLocalRef jString,
|
||||
out JBoolean isCopy);
|
||||
|
||||
internal delegate void ReleaseStringCriticalDelegate(JEnvRef env, JStringLocalRef jString, ReadOnlyValPtr<Char> chars0);
|
||||
|
||||
internal delegate JObjectLocalRef CallStaticObjectMethodADelegate(JEnvRef env, JClassLocalRef jClass, JMethodId jMethod,
|
||||
ReadOnlyValPtr<JValue> args0);
|
||||
|
||||
internal delegate JBoolean CallStaticBooleanMethodADelegate(JEnvRef env, JClassLocalRef jClass, JMethodId jMethod,
|
||||
ReadOnlyValPtr<JValue> args0);
|
||||
|
||||
internal delegate JByte CallStaticByteMethodADelegate(JEnvRef env, JClassLocalRef jClass, JMethodId jMethod,
|
||||
ReadOnlyValPtr<JValue> args0);
|
||||
|
||||
internal delegate JChar CallStaticCharMethodADelegate(JEnvRef env, JClassLocalRef jClass, JMethodId jMethod,
|
||||
ReadOnlyValPtr<JValue> args0);
|
||||
|
||||
internal delegate JShort CallStaticShortMethodADelegate(JEnvRef env, JClassLocalRef jClass, JMethodId jMethod,
|
||||
ReadOnlyValPtr<JValue> args0);
|
||||
|
||||
internal delegate JInt CallStaticIntMethodADelegate(JEnvRef env, JClassLocalRef jClass, JMethodId jMethod,
|
||||
ReadOnlyValPtr<JValue> args0);
|
||||
|
||||
internal delegate JLong CallStaticLongMethodADelegate(JEnvRef env, JClassLocalRef jClass, JMethodId jMethod,
|
||||
ReadOnlyValPtr<JValue> args0);
|
||||
|
||||
internal delegate JFloat CallStaticFloatMethodADelegate(JEnvRef env, JClassLocalRef jClass, JMethodId jMethod,
|
||||
ReadOnlyValPtr<JValue> args0);
|
||||
|
||||
internal delegate JDouble CallStaticDoubleMethodADelegate(JEnvRef env, JClassLocalRef jClass, JMethodId jMethod,
|
||||
ReadOnlyValPtr<JValue> args0);
|
||||
|
||||
internal delegate void CallStaticVoidMethodADelegate(JEnvRef env, JClassLocalRef jClass, JMethodId jMethod,
|
||||
ReadOnlyValPtr<JValue> args0);
|
||||
|
||||
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 JMethodId FromReflectedMethodDelegate(JEnvRef env, JObjectLocalRef method);
|
||||
internal delegate JFieldId FromReflectedFieldDelegate(JEnvRef env, JObjectLocalRef field);
|
||||
internal delegate JResult PushLocalFrameDelegate(JEnvRef env, Int32 capacity);
|
||||
internal delegate JObjectLocalRef PopLocalFrameDelegate(JEnvRef env, JObjectLocalRef result);
|
||||
internal delegate JGlobalRef NewGlobalRefDelegate(JEnvRef env, JObjectLocalRef localRef);
|
||||
internal delegate void DeleteGlobalRefDelegate(JEnvRef env, JGlobalRef globalRef);
|
||||
internal delegate void DeleteLocalRefDelegate(JEnvRef env, JObjectLocalRef localRef);
|
||||
internal delegate JBoolean 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 JWeakRef NewWeakGlobalRefDelegate(JEnvRef env, JObjectLocalRef obj);
|
||||
internal delegate void DeleteWeakGlobalRefDelegate(JEnvRef env, JWeakRef jWeak);
|
||||
internal delegate JReferenceType GetObjectRefTypeDelegate(JEnvRef env, JObjectLocalRef obj);
|
||||
|
||||
internal delegate JObjectLocalRef CallNonVirtualObjectMethodADelegate(JEnvRef env, JObjectLocalRef obj,
|
||||
JClassLocalRef jClass, JMethodId jMethod, ReadOnlyValPtr<JValue> args0);
|
||||
|
||||
internal delegate JBoolean CallNonVirtualBooleanMethodADelegate(JEnvRef env, JObjectLocalRef obj, JClassLocalRef jClass,
|
||||
JMethodId jMethod, ReadOnlyValPtr<JValue> args0);
|
||||
|
||||
internal delegate JByte CallNonVirtualByteMethodADelegate(JEnvRef env, JObjectLocalRef obj, JClassLocalRef jClass,
|
||||
JMethodId jMethod, ReadOnlyValPtr<JValue> args0);
|
||||
|
||||
internal delegate JChar CallNonVirtualCharMethodADelegate(JEnvRef env, JObjectLocalRef obj, JClassLocalRef jClass,
|
||||
JMethodId jMethod, ReadOnlyValPtr<JValue> args0);
|
||||
|
||||
internal delegate JShort CallNonVirtualShortMethodADelegate(JEnvRef env, JObjectLocalRef obj, JClassLocalRef jClass,
|
||||
JMethodId jMethod, ReadOnlyValPtr<JValue> args0);
|
||||
|
||||
internal delegate JInt CallNonVirtualIntMethodADelegate(JEnvRef env, JObjectLocalRef obj, JClassLocalRef jClass,
|
||||
JMethodId jMethod, ReadOnlyValPtr<JValue> args0);
|
||||
|
||||
internal delegate JLong CallNonVirtualLongMethodADelegate(JEnvRef env, JObjectLocalRef obj, JClassLocalRef jClass,
|
||||
JMethodId jMethod, ReadOnlyValPtr<JValue> args0);
|
||||
|
||||
internal delegate JFloat CallNonVirtualFloatMethodADelegate(JEnvRef env, JObjectLocalRef obj, JClassLocalRef jClass,
|
||||
JMethodId jMethod, ReadOnlyValPtr<JValue> args0);
|
||||
|
||||
internal delegate JDouble CallNonVirtualDoubleMethodADelegate(JEnvRef env, JObjectLocalRef obj, JClassLocalRef jClass,
|
||||
JMethodId jMethod, ReadOnlyValPtr<JValue> args0);
|
||||
|
||||
internal delegate void CallNonVirtualVoidMethodADelegate(JEnvRef env, JObjectLocalRef obj, JClassLocalRef jClass,
|
||||
JMethodId jMethod, ReadOnlyValPtr<JValue> args0);
|
||||
|
||||
internal delegate JObjectLocalRef CallObjectMethodADelegate(JEnvRef env, JObjectLocalRef obj, JMethodId jMethod,
|
||||
ReadOnlyValPtr<JValue> args0);
|
||||
|
||||
internal delegate JBoolean CallBooleanMethodADelegate(JEnvRef env, JObjectLocalRef obj, JMethodId jMethod,
|
||||
ReadOnlyValPtr<JValue> args0);
|
||||
|
||||
internal delegate JByte CallByteMethodADelegate(JEnvRef env, JObjectLocalRef obj, JMethodId jMethod,
|
||||
ReadOnlyValPtr<JValue> args0);
|
||||
|
||||
internal delegate JChar CallCharMethodADelegate(JEnvRef env, JObjectLocalRef obj, JMethodId jMethod,
|
||||
ReadOnlyValPtr<JValue> args0);
|
||||
|
||||
internal delegate JShort CallShortMethodADelegate(JEnvRef env, JObjectLocalRef obj, JMethodId jMethod,
|
||||
ReadOnlyValPtr<JValue> args0);
|
||||
|
||||
internal delegate JInt CallIntMethodADelegate(JEnvRef env, JObjectLocalRef obj, JMethodId jMethod,
|
||||
ReadOnlyValPtr<JValue> args0);
|
||||
|
||||
internal delegate JLong CallLongMethodADelegate(JEnvRef env, JObjectLocalRef obj, JMethodId jMethod,
|
||||
ReadOnlyValPtr<JValue> args0);
|
||||
|
||||
internal delegate JFloat CallFloatMethodADelegate(JEnvRef env, JObjectLocalRef obj, JMethodId jMethod,
|
||||
ReadOnlyValPtr<JValue> args0);
|
||||
|
||||
internal delegate JDouble CallDoubleMethodADelegate(JEnvRef env, JObjectLocalRef obj, JMethodId jMethod,
|
||||
ReadOnlyValPtr<JValue> args0);
|
||||
|
||||
internal delegate void CallVoidMethodADelegate(JEnvRef env, JObjectLocalRef obj, JMethodId jMethod,
|
||||
ReadOnlyValPtr<JValue> args0);
|
||||
|
||||
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 JResult ThrowDelegate(JEnvRef env, JThrowableLocalRef obj);
|
||||
internal delegate JResult ThrowNewDelegate(JEnvRef env, JClassLocalRef jClass, ReadOnlyValPtr<Byte> messageChars0);
|
||||
internal delegate JThrowableLocalRef ExceptionOccurredDelegate(JEnvRef env);
|
||||
internal delegate void ExceptionDescribeDelegate(JEnvRef env);
|
||||
internal delegate void ExceptionClearDelegate(JEnvRef env);
|
||||
internal delegate void FatalErrorDelegate(JEnvRef env, ReadOnlyValPtr<Byte> messageChars0);
|
||||
internal delegate JBoolean 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 JClassLocalRef DefineClassDelegate(JEnvRef env, ReadOnlyValPtr<Byte> nameChars0,
|
||||
JObjectLocalRef loader, IntPtr binaryData, Int32 len);
|
||||
|
||||
internal delegate JClassLocalRef FindClassDelegate(JEnvRef env, ReadOnlyValPtr<Byte> nameChars0);
|
||||
|
||||
internal delegate JObjectLocalRef ToReflectedMethodDelegate(JEnvRef env, JClassLocalRef jClass, JMethodId methodId,
|
||||
JBoolean isStatic);
|
||||
|
||||
internal delegate JClassLocalRef GetSuperclassDelegate(JEnvRef env, JClassLocalRef sub);
|
||||
internal delegate JBoolean IsAssignableFromDelegate(JEnvRef env, JClassLocalRef sub, JClassLocalRef sup);
|
||||
internal delegate JClassLocalRef GetObjectClassDelegate(JEnvRef env, JObjectLocalRef obj);
|
||||
internal delegate JBoolean IsInstanceOfDelegate(JEnvRef env, JObjectLocalRef obj, JClassLocalRef jClass);
|
||||
|
||||
internal delegate JObjectLocalRef ToReflectedFieldDelegate(JEnvRef env, JClassLocalRef jClass, JFieldId fieldId,
|
||||
JBoolean isStatic);
|
||||
|
||||
internal delegate JMethodId GetMethodIdDelegate(JEnvRef env, JClassLocalRef jClass, ReadOnlyValPtr<Byte> nameChars0,
|
||||
ReadOnlyValPtr<Byte> signatureChars0);
|
||||
|
||||
internal delegate JFieldId GetFieldIdDelegate(JEnvRef env, JClassLocalRef jClass, ReadOnlyValPtr<Byte> nameChars0,
|
||||
ReadOnlyValPtr<Byte> signatureChars0);
|
||||
|
||||
internal delegate JMethodId GetStaticMethodIdDelegate(JEnvRef env, JClassLocalRef jClass,
|
||||
ReadOnlyValPtr<Byte> nameChars0, ReadOnlyValPtr<Byte> signatureChars0);
|
||||
|
||||
internal delegate JFieldId GetStaticFieldIdDelegate(JEnvRef env, JClassLocalRef jClass, ReadOnlyValPtr<Byte> nameChars0,
|
||||
ReadOnlyValPtr<Byte> signatureChars0);
|
||||
|
||||
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 arrayRef, Int32 index);
|
||||
|
||||
internal delegate void SetObjectArrayElementDelegate(JEnvRef env, JArrayLocalRef arrayRef, 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 ValPtr<JBoolean> GetBooleanArrayElementsDelegate(JEnvRef env, JArrayLocalRef arrayRef,
|
||||
out JBoolean isCopy);
|
||||
|
||||
internal delegate ValPtr<JByte> GetByteArrayElementsDelegate(JEnvRef env, JArrayLocalRef arrayRef, out JBoolean isCopy);
|
||||
internal delegate ValPtr<JChar> GetCharArrayElementsDelegate(JEnvRef env, JArrayLocalRef arrayRef, out JBoolean isCopy);
|
||||
|
||||
internal delegate ValPtr<JShort> GetShortArrayElementsDelegate(JEnvRef env, JArrayLocalRef arrayRef,
|
||||
out JBoolean isCopy);
|
||||
|
||||
internal delegate ValPtr<JInt> GetIntArrayElementsDelegate(JEnvRef env, JArrayLocalRef arrayRef, out JBoolean isCopy);
|
||||
internal delegate ValPtr<JLong> GetLongArrayElementsDelegate(JEnvRef env, JArrayLocalRef arrayRef, out JBoolean isCopy);
|
||||
|
||||
internal delegate ValPtr<JFloat> GetFloatArrayElementsDelegate(JEnvRef env, JArrayLocalRef arrayRef,
|
||||
out JBoolean isCopy);
|
||||
|
||||
internal delegate ValPtr<JDouble> GetDoubleArrayElementsDelegate(JEnvRef env, JArrayLocalRef arrayRef,
|
||||
out JBoolean isCopy);
|
||||
|
||||
internal delegate void ReleaseBooleanArrayElementsDelegate(JEnvRef env, JArrayLocalRef arrayRef,
|
||||
ReadOnlyValPtr<JBoolean> elements0, JReleaseMode mode);
|
||||
|
||||
internal delegate void ReleaseByteArrayElementsDelegate(JEnvRef env, JArrayLocalRef arrayRef,
|
||||
ReadOnlyValPtr<JByte> elements0, JReleaseMode mode);
|
||||
|
||||
internal delegate void ReleaseCharArrayElementsDelegate(JEnvRef env, JArrayLocalRef arrayRef,
|
||||
ReadOnlyValPtr<JChar> elements0, JReleaseMode mode);
|
||||
|
||||
internal delegate void ReleaseShortArrayElementsDelegate(JEnvRef env, JArrayLocalRef arrayRef,
|
||||
ReadOnlyValPtr<JShort> elements0, JReleaseMode mode);
|
||||
|
||||
internal delegate void ReleaseIntArrayElementsDelegate(JEnvRef env, JArrayLocalRef arrayRef,
|
||||
ReadOnlyValPtr<JInt> elements0, JReleaseMode mode);
|
||||
|
||||
internal delegate void ReleaseLongArrayElementsDelegate(JEnvRef env, JArrayLocalRef arrayRef,
|
||||
ReadOnlyValPtr<JLong> elements0, JReleaseMode mode);
|
||||
|
||||
internal delegate void ReleaseFloatArrayElementsDelegate(JEnvRef env, JArrayLocalRef arrayRef,
|
||||
ReadOnlyValPtr<JFloat> elements0, JReleaseMode mode);
|
||||
|
||||
internal delegate void ReleaseDoubleArrayElementsDelegate(JEnvRef env, JArrayLocalRef arrayRef,
|
||||
ReadOnlyValPtr<JDouble> elements0, JReleaseMode mode);
|
||||
|
||||
internal delegate void GetBooleanArrayRegionDelegate(JEnvRef env, JArrayLocalRef arrayRef, Int32 startIndex,
|
||||
Int32 length, ValPtr<JBoolean> buffer0);
|
||||
|
||||
internal delegate void GetByteArrayRegionDelegate(JEnvRef env, JArrayLocalRef arrayRef, Int32 startIndex, Int32 length,
|
||||
ValPtr<JByte> buffer0);
|
||||
|
||||
internal delegate void GetCharArrayRegionDelegate(JEnvRef env, JArrayLocalRef arrayRef, Int32 startIndex, Int32 length,
|
||||
ValPtr<JChar> buffer0);
|
||||
|
||||
internal delegate void GetShortArrayRegionDelegate(JEnvRef env, JArrayLocalRef arrayRef, Int32 startIndex, Int32 length,
|
||||
ValPtr<JShort> buffer0);
|
||||
|
||||
internal delegate void GetIntArrayRegionDelegate(JEnvRef env, JArrayLocalRef arrayRef, Int32 startIndex, Int32 length,
|
||||
ValPtr<JInt> buffer0);
|
||||
|
||||
internal delegate void GetLongArrayRegionDelegate(JEnvRef env, JArrayLocalRef arrayRef, Int32 startIndex, Int32 length,
|
||||
ValPtr<JLong> buffer0);
|
||||
|
||||
internal delegate void GetFloatArrayRegionDelegate(JEnvRef env, JArrayLocalRef arrayRef, Int32 startIndex, Int32 length,
|
||||
ValPtr<JFloat> buffer0);
|
||||
|
||||
internal delegate void GetDoubleArrayRegionDelegate(JEnvRef env, JArrayLocalRef arrayRef, Int32 startIndex,
|
||||
Int32 length, ValPtr<JDouble> buffer0);
|
||||
|
||||
internal delegate void SetBooleanArrayRegionDelegate(JEnvRef env, JArrayLocalRef arrayRef, Int32 startIndex,
|
||||
Int32 length, ReadOnlyValPtr<JBoolean> buffer0);
|
||||
|
||||
internal delegate void SetByteArrayRegionDelegate(JEnvRef env, JArrayLocalRef arrayRef, Int32 startIndex, Int32 length,
|
||||
ReadOnlyValPtr<JByte> buffer0);
|
||||
|
||||
internal delegate void SetCharArrayRegionDelegate(JEnvRef env, JArrayLocalRef arrayRef, Int32 startIndex, Int32 length,
|
||||
ReadOnlyValPtr<JChar> buffer0);
|
||||
|
||||
internal delegate void SetShortArrayRegionDelegate(JEnvRef env, JArrayLocalRef arrayRef, Int32 startIndex, Int32 length,
|
||||
ReadOnlyValPtr<JShort> buffer0);
|
||||
|
||||
internal delegate void SetIntArrayRegionDelegate(JEnvRef env, JArrayLocalRef arrayRef, Int32 startIndex, Int32 length,
|
||||
ReadOnlyValPtr<JInt> buffer0);
|
||||
|
||||
internal delegate void SetLongArrayRegionDelegate(JEnvRef env, JArrayLocalRef arrayRef, Int32 startIndex, Int32 length,
|
||||
ReadOnlyValPtr<JLong> buffer0);
|
||||
|
||||
internal delegate void SetFloatArrayRegionDelegate(JEnvRef env, JArrayLocalRef arrayRef, Int32 startIndex, Int32 length,
|
||||
ReadOnlyValPtr<JFloat> buffer0);
|
||||
|
||||
internal delegate void SetDoubleArrayRegionDelegate(JEnvRef env, JArrayLocalRef arrayRef, Int32 startIndex,
|
||||
Int32 length, ReadOnlyValPtr<JDouble> buffer0);
|
||||
|
||||
internal delegate ValPtr<Byte> GetPrimitiveArrayCriticalDelegate(JEnvRef env, JArrayLocalRef arrayRef,
|
||||
out JBoolean isCopy);
|
||||
|
||||
internal delegate void ReleasePrimitiveArrayCriticalDelegate(JEnvRef env, JArrayLocalRef arrayRef,
|
||||
ValPtr<Byte> elements, JReleaseMode mode);
|
||||
|
||||
internal delegate JObjectLocalRef NewObjectADelegate(JEnvRef env, JClassLocalRef jClass, JMethodId jMethod,
|
||||
ReadOnlyValPtr<JValue> arg0);
|
28
src/LibRyujinx/Android/Jni/Identifiers/JFieldId.cs
Normal file
28
src/LibRyujinx/Android/Jni/Identifiers/JFieldId.cs
Normal file
@ -0,0 +1,28 @@
|
||||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
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/Android/Jni/Identifiers/JMethodId.cs
Normal file
28
src/LibRyujinx/Android/Jni/Identifiers/JMethodId.cs
Normal file
@ -0,0 +1,28 @@
|
||||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
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/Android/Jni/JReferenceType.cs
Normal file
12
src/LibRyujinx/Android/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
|
||||
}
|
||||
}
|
11
src/LibRyujinx/Android/Jni/JReleaseMode.cs
Normal file
11
src/LibRyujinx/Android/Jni/JReleaseMode.cs
Normal file
@ -0,0 +1,11 @@
|
||||
using System;
|
||||
|
||||
namespace LibRyujinx.Jni
|
||||
{
|
||||
public enum JReleaseMode : Int32
|
||||
{
|
||||
Free = 0,
|
||||
Commit = 1,
|
||||
Abort = 2,
|
||||
}
|
||||
}
|
15
src/LibRyujinx/Android/Jni/JResult.cs
Normal file
15
src/LibRyujinx/Android/Jni/JResult.cs
Normal file
@ -0,0 +1,15 @@
|
||||
using System;
|
||||
|
||||
namespace LibRyujinx.Jni
|
||||
{
|
||||
public enum JResult : Int32
|
||||
{
|
||||
Ok = 0,
|
||||
Error = -1,
|
||||
DetachedThreadError = -2,
|
||||
VersionError = -3,
|
||||
MemoryError = -4,
|
||||
ExitingVMError = -5,
|
||||
InvalidArgumentsError = -6,
|
||||
}
|
||||
}
|
251
src/LibRyujinx/Android/Jni/JniHelper.cs
Normal file
251
src/LibRyujinx/Android/Jni/JniHelper.cs
Normal file
@ -0,0 +1,251 @@
|
||||
using LibRyujinx.Jni.Identifiers;
|
||||
using LibRyujinx.Jni.Pointers;
|
||||
using LibRyujinx.Jni.Primitives;
|
||||
using LibRyujinx.Jni.References;
|
||||
using LibRyujinx.Jni.Values;
|
||||
using System;
|
||||
|
||||
using Rxmxnx.PInvoke;
|
||||
|
||||
namespace LibRyujinx.Jni
|
||||
{
|
||||
internal static class JniHelper
|
||||
{
|
||||
public const Int32 JniVersion = 0x00010006; //JNI_VERSION_1_6;
|
||||
|
||||
public static JEnvRef? Attach(JavaVMRef javaVm, IReadOnlyFixedMemory<Byte> threadName, out Boolean newAttach)
|
||||
{
|
||||
ref JavaVMValue value = ref javaVm.VirtualMachine;
|
||||
ref JInvokeInterface jInvoke = ref value.Functions;
|
||||
|
||||
IntPtr getEnvPtr = jInvoke.GetEnvPointer;
|
||||
GetEnvDelegate getEnv = getEnvPtr.GetUnsafeDelegate<GetEnvDelegate>()!;
|
||||
|
||||
if (getEnv(javaVm, out JEnvRef jEnv, JniHelper.JniVersion) == JResult.Ok)
|
||||
{
|
||||
newAttach = false;
|
||||
return jEnv;
|
||||
}
|
||||
|
||||
JavaVMAttachArgs args = new() { Version = JniHelper.JniVersion, Name = threadName.ValuePointer, };
|
||||
IntPtr attachCurrentThreadPtr = jInvoke.AttachCurrentThreadPointer;
|
||||
AttachCurrentThreadDelegate attachCurrentThread =
|
||||
attachCurrentThreadPtr.GetUnsafeDelegate<AttachCurrentThreadDelegate>()!;
|
||||
|
||||
newAttach = true;
|
||||
return attachCurrentThread(javaVm, out jEnv, in args) == JResult.Ok ? jEnv : null;
|
||||
}
|
||||
public static JEnvRef? AttachDaemon(JavaVMRef javaVm, IReadOnlyFixedMemory<Byte> daemonName)
|
||||
{
|
||||
ref JavaVMValue value = ref javaVm.VirtualMachine;
|
||||
ref JInvokeInterface jInvoke = ref value.Functions;
|
||||
|
||||
JavaVMAttachArgs args = new() { Version = JniHelper.JniVersion, Name = daemonName.ValuePointer, };
|
||||
IntPtr attachCurrentThreadAsDaemonPtr = jInvoke.AttachCurrentThreadAsDaemonPointer;
|
||||
AttachCurrentThreadAsDaemonDelegate attachCurrentThreadAsDaemon =
|
||||
attachCurrentThreadAsDaemonPtr.GetUnsafeDelegate<AttachCurrentThreadAsDaemonDelegate>()!;
|
||||
|
||||
return attachCurrentThreadAsDaemon(javaVm, out JEnvRef jEnv, in args) == JResult.Ok ? jEnv : null;
|
||||
}
|
||||
public static void Detach(JavaVMRef javaVm)
|
||||
{
|
||||
ref JavaVMValue value = ref javaVm.VirtualMachine;
|
||||
ref JInvokeInterface jInvoke = ref value.Functions;
|
||||
|
||||
IntPtr detachCurrentThreadPtr = jInvoke.DetachCurrentThreadPointer;
|
||||
DetachCurrentThreadDelegate detachCurrentThread =
|
||||
detachCurrentThreadPtr.GetUnsafeDelegate<DetachCurrentThreadDelegate>()!;
|
||||
|
||||
detachCurrentThread(javaVm);
|
||||
}
|
||||
public static JGlobalRef? GetGlobalClass(JEnvRef jEnv, IReadOnlyFixedMemory<Byte> className)
|
||||
{
|
||||
ref readonly JEnvValue value = ref jEnv.Environment;
|
||||
ref JNativeInterface jInterface = ref value.Functions;
|
||||
|
||||
IntPtr findClassPtr = jInterface.FindClassPointer;
|
||||
FindClassDelegate findClass = findClassPtr.GetUnsafeDelegate<FindClassDelegate>()!;
|
||||
JClassLocalRef jClass = findClass(jEnv, className.ValuePointer);
|
||||
|
||||
if (JniHelper.ExceptionCheck(jEnv))
|
||||
return default;
|
||||
|
||||
IntPtr newGlobalRefPtr = jInterface.NewGlobalRefPointer;
|
||||
NewGlobalRefDelegate newGlobalRef = newGlobalRefPtr.GetUnsafeDelegate<NewGlobalRefDelegate>()!;
|
||||
|
||||
JGlobalRef jGlobal = newGlobalRef(jEnv, (JObjectLocalRef)jClass);
|
||||
JniHelper.RemoveLocal(jEnv, (JObjectLocalRef)jClass);
|
||||
|
||||
return !JniHelper.ExceptionCheck(jEnv) ? jGlobal : null;
|
||||
}
|
||||
public static void RemoveLocal(JEnvRef jEnv, JObjectLocalRef jObject)
|
||||
{
|
||||
ref readonly JEnvValue value = ref jEnv.Environment;
|
||||
ref JNativeInterface jInterface = ref value.Functions;
|
||||
|
||||
IntPtr deleteLocalRefPtr = jInterface.DeleteLocalRefPointer;
|
||||
DeleteLocalRefDelegate deleteLocalRef = deleteLocalRefPtr.GetUnsafeDelegate<DeleteLocalRefDelegate>()!;
|
||||
|
||||
deleteLocalRef(jEnv, jObject);
|
||||
}
|
||||
public static void RemoveGlobal(JEnvRef jEnv, JGlobalRef jObject)
|
||||
{
|
||||
ref readonly JEnvValue value = ref jEnv.Environment;
|
||||
ref JNativeInterface jInterface = ref value.Functions;
|
||||
|
||||
IntPtr deleteGlobalRefPtr = jInterface.DeleteGlobalRefPointer;
|
||||
DeleteGlobalRefDelegate deleteGlobalRef = deleteGlobalRefPtr.GetUnsafeDelegate<DeleteGlobalRefDelegate>()!;
|
||||
|
||||
deleteGlobalRef(jEnv, jObject);
|
||||
}
|
||||
public static void RemoveWeakGlobal(JEnvRef jEnv, JWeakRef jObject)
|
||||
{
|
||||
ref readonly JEnvValue value = ref jEnv.Environment;
|
||||
ref JNativeInterface jInterface = ref value.Functions;
|
||||
|
||||
IntPtr deleteWeakGlobalRefPtr = jInterface.DeleteWeakGlobalRefPointer;
|
||||
DeleteWeakGlobalRefDelegate deleteWeakGlobalRef =
|
||||
deleteWeakGlobalRefPtr.GetUnsafeDelegate<DeleteWeakGlobalRefDelegate>()!;
|
||||
|
||||
deleteWeakGlobalRef(jEnv, jObject);
|
||||
}
|
||||
public static JStringLocalRef? CreateString(JEnvRef jEnv, String textValue)
|
||||
{
|
||||
ref readonly JEnvValue value = ref jEnv.Environment;
|
||||
ref JNativeInterface jInterface = ref value.Functions;
|
||||
|
||||
IntPtr newStringPtr = jInterface.NewStringPointer;
|
||||
NewStringDelegate newString = newStringPtr.GetUnsafeDelegate<NewStringDelegate>()!;
|
||||
using IReadOnlyFixedMemory<Char>.IDisposable ctx = textValue.AsMemory().GetFixedContext();
|
||||
JStringLocalRef jString = newString(jEnv, ctx.ValuePointer, ctx.Values.Length);
|
||||
|
||||
return !JniHelper.ExceptionCheck(jEnv) ? jString : null;
|
||||
}
|
||||
public static JWeakRef? CreateWeakGlobal(JEnvRef jEnv, JObjectLocalRef jObject)
|
||||
{
|
||||
ref readonly JEnvValue value = ref jEnv.Environment;
|
||||
ref JNativeInterface jInterface = ref value.Functions;
|
||||
|
||||
IntPtr newWeakGlobalRefPtr = jInterface.NewWeakGlobalRefPointer;
|
||||
NewWeakGlobalRefDelegate newWeakGlobalRef = newWeakGlobalRefPtr.GetUnsafeDelegate<NewWeakGlobalRefDelegate>()!;
|
||||
JWeakRef jWeak = newWeakGlobalRef(jEnv, jObject);
|
||||
|
||||
return !JniHelper.ExceptionCheck(jEnv) ? jWeak : null;
|
||||
}
|
||||
private static Boolean ExceptionCheck(JEnvRef jEnv)
|
||||
{
|
||||
ref readonly JEnvValue value = ref jEnv.Environment;
|
||||
ref JNativeInterface jInterface = ref value.Functions;
|
||||
|
||||
IntPtr exceptionCheckPtr = jInterface.ExceptionCheckPointer;
|
||||
ExceptionCheckDelegate exceptionCheck = exceptionCheckPtr.GetUnsafeDelegate<ExceptionCheckDelegate>()!;
|
||||
|
||||
if (!exceptionCheck(jEnv))
|
||||
return false;
|
||||
IntPtr exceptionDescribePtr = jInterface.ExceptionDescribePointer;
|
||||
IntPtr exceptionClearPtr = jInterface.ExceptionClearPointer;
|
||||
|
||||
ExceptionDescribeDelegate exceptionDescribe =
|
||||
exceptionDescribePtr.GetUnsafeDelegate<ExceptionDescribeDelegate>()!;
|
||||
ExceptionClearDelegate exceptionClear = exceptionClearPtr.GetUnsafeDelegate<ExceptionClearDelegate>()!;
|
||||
|
||||
exceptionDescribe(jEnv);
|
||||
exceptionClear(jEnv);
|
||||
return true;
|
||||
}
|
||||
public static JavaVMRef? GetVirtualMachine(JEnvRef jEnv)
|
||||
{
|
||||
ref readonly JEnvValue value = ref jEnv.Environment;
|
||||
ref JNativeInterface jInterface = ref value.Functions;
|
||||
|
||||
IntPtr getJavaVmPtr = jInterface.GetJavaVMPointer;
|
||||
GetVirtualMachineDelegate getJavaVm = getJavaVmPtr.GetUnsafeDelegate<GetVirtualMachineDelegate>()!;
|
||||
return getJavaVm(jEnv, out JavaVMRef javaVm) == JResult.Ok ? javaVm : null;
|
||||
}
|
||||
public static Boolean? IsValidGlobalWeak(JEnvRef jEnv, JWeakRef jWeak)
|
||||
{
|
||||
ref readonly JEnvValue value = ref jEnv.Environment;
|
||||
ref JNativeInterface jInterface = ref value.Functions;
|
||||
|
||||
IntPtr isSameObjectPtr = jInterface.IsSameObjectPointer;
|
||||
IsSameObjectDelegate isSameObject = isSameObjectPtr.GetUnsafeDelegate<IsSameObjectDelegate>()!;
|
||||
JBoolean result = isSameObject(jEnv, (JObjectLocalRef)jWeak, default);
|
||||
return !JniHelper.ExceptionCheck(jEnv) ? !result : null;
|
||||
}
|
||||
public static JMethodId? GetMethodId(JEnvRef jEnv, JClassLocalRef jClass, IReadOnlyFixedMemory<Byte> methodName,
|
||||
IReadOnlyFixedMemory<Byte> descriptor)
|
||||
{
|
||||
ref readonly JEnvValue value = ref jEnv.Environment;
|
||||
ref JNativeInterface jInterface = ref value.Functions;
|
||||
|
||||
IntPtr getMethodIdPtr = jInterface.GetMethodIdPointer;
|
||||
GetMethodIdDelegate getMethodId = getMethodIdPtr.GetUnsafeDelegate<GetMethodIdDelegate>()!;
|
||||
JMethodId methodId = getMethodId(jEnv, jClass, methodName.ValuePointer, descriptor.ValuePointer);
|
||||
return !JniHelper.ExceptionCheck(jEnv) ? methodId : null;
|
||||
}
|
||||
public static JMethodId? GetStaticMethodId(JEnvRef jEnv, JClassLocalRef jClass,
|
||||
IReadOnlyFixedMemory<Byte> methodName, IReadOnlyFixedMemory<Byte> descriptor)
|
||||
{
|
||||
ref readonly JEnvValue value = ref jEnv.Environment;
|
||||
ref JNativeInterface jInterface = ref value.Functions;
|
||||
|
||||
IntPtr getStaticMethodIdPtr = jInterface.GetStaticMethodIdPointer;
|
||||
GetStaticMethodIdDelegate getStaticMethodId =
|
||||
getStaticMethodIdPtr.GetUnsafeDelegate<GetStaticMethodIdDelegate>()!;
|
||||
JMethodId jMethodId = getStaticMethodId(jEnv, jClass, methodName.ValuePointer, descriptor.ValuePointer);
|
||||
return !JniHelper.ExceptionCheck(jEnv) ? jMethodId : null;
|
||||
}
|
||||
public static void CallStaticVoidMethod(JEnvRef jEnv, JClassLocalRef jClass, JMethodId jMethodId,
|
||||
params JValue[] args)
|
||||
{
|
||||
ref readonly JEnvValue value = ref jEnv.Environment;
|
||||
ref JNativeInterface jInterface = ref value.Functions;
|
||||
|
||||
IntPtr callStaticVoidMethodPtr = jInterface.CallStaticVoidMethodAPointer;
|
||||
CallStaticVoidMethodADelegate callStaticVoidMethod =
|
||||
callStaticVoidMethodPtr.GetUnsafeDelegate<CallStaticVoidMethodADelegate>()!;
|
||||
|
||||
using IReadOnlyFixedMemory<JValue>.IDisposable fArgs = args.AsMemory().GetFixedContext();
|
||||
callStaticVoidMethod(jEnv, jClass, jMethodId, fArgs.ValuePointer);
|
||||
}
|
||||
public static JObjectLocalRef? CallStaticObjectMethod(JEnvRef jEnv, JClassLocalRef jClass, JMethodId jMethodId,
|
||||
params JValue[] args)
|
||||
{
|
||||
ref readonly JEnvValue value = ref jEnv.Environment;
|
||||
ref JNativeInterface jInterface = ref value.Functions;
|
||||
|
||||
IntPtr callStaticObjectMethodPtr = jInterface.CallStaticObjectMethodAPointer;
|
||||
CallStaticObjectMethodADelegate callStaticObjectMethod =
|
||||
callStaticObjectMethodPtr.GetUnsafeDelegate<CallStaticObjectMethodADelegate>()!;
|
||||
|
||||
using IReadOnlyFixedMemory<JValue>.IDisposable fArgs = args.AsMemory().GetFixedContext();
|
||||
JObjectLocalRef jObject = callStaticObjectMethod(jEnv, jClass, jMethodId, fArgs.ValuePointer);
|
||||
return !JniHelper.ExceptionCheck(jEnv) ? jObject : null;
|
||||
}
|
||||
public static JLong? CallStaticLongMethod(JEnvRef jEnv, JClassLocalRef jClass, JMethodId jMethodId,
|
||||
params JValue[] args)
|
||||
{
|
||||
ref readonly JEnvValue value = ref jEnv.Environment;
|
||||
ref JNativeInterface jInterface = ref value.Functions;
|
||||
|
||||
IntPtr callStaticLongMethodPtr = jInterface.CallStaticLongMethodAPointer;
|
||||
CallStaticLongMethodADelegate callStaticLongMethod =
|
||||
callStaticLongMethodPtr.GetUnsafeDelegate<CallStaticLongMethodADelegate>()!;
|
||||
|
||||
using IReadOnlyFixedMemory<JValue>.IDisposable fArgs = args.AsMemory().GetFixedContext();
|
||||
JLong jLong = callStaticLongMethod(jEnv, jClass, jMethodId, fArgs.ValuePointer);
|
||||
return !JniHelper.ExceptionCheck(jEnv) ? jLong : null;
|
||||
}
|
||||
public static void CallVoidMethod(JEnvRef jEnv, JObjectLocalRef jObject, JMethodId jMethodId, params JValue[] args)
|
||||
{
|
||||
ref readonly JEnvValue value = ref jEnv.Environment;
|
||||
ref JNativeInterface jInterface = ref value.Functions;
|
||||
|
||||
IntPtr callVoidMethodPtr = jInterface.CallVoidMethodAPointer;
|
||||
CallVoidMethodADelegate callVoidMethod = callVoidMethodPtr.GetUnsafeDelegate<CallVoidMethodADelegate>()!;
|
||||
|
||||
using IReadOnlyFixedMemory<JValue>.IDisposable fArgs = args.AsMemory().GetFixedContext();
|
||||
callVoidMethod(jEnv, jObject, jMethodId, fArgs.ValuePointer);
|
||||
}
|
||||
}
|
||||
}
|
37
src/LibRyujinx/Android/Jni/Pointers/JEnvRef.cs
Normal file
37
src/LibRyujinx/Android/Jni/Pointers/JEnvRef.cs
Normal file
@ -0,0 +1,37 @@
|
||||
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
|
||||
|
||||
public JEnvRef(IntPtr val)
|
||||
{
|
||||
_value = val;
|
||||
}
|
||||
|
||||
#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
|
||||
}
|
||||
}
|
31
src/LibRyujinx/Android/Jni/Pointers/JavaVMRef.cs
Normal file
31
src/LibRyujinx/Android/Jni/Pointers/JavaVMRef.cs
Normal file
@ -0,0 +1,31 @@
|
||||
using LibRyujinx.Jni.Values;
|
||||
|
||||
using Rxmxnx.PInvoke;
|
||||
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 Properties
|
||||
internal readonly ref JavaVMValue VirtualMachine => ref this._value.GetUnsafeReference<JavaVMValue>();
|
||||
#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/Android/Jni/Primitives/JBoolean.cs
Normal file
67
src/LibRyujinx/Android/Jni/Primitives/JBoolean.cs
Normal file
@ -0,0 +1,67 @@
|
||||
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 const Byte trueByte = 1;
|
||||
private const Byte falseByte = 0;
|
||||
|
||||
public static readonly CString Signature = (CString)"Z";
|
||||
|
||||
private readonly Byte _value;
|
||||
private Boolean Value => this._value == JBoolean.trueByte;
|
||||
|
||||
private JBoolean(Boolean value) => this._value = value ? JBoolean.trueByte : JBoolean.falseByte;
|
||||
|
||||
#region Operators
|
||||
public static implicit operator JBoolean(Boolean value) => new(value);
|
||||
public static implicit operator Boolean(JBoolean jValue) => jValue._value == 1;
|
||||
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/Android/Jni/Primitives/JByte.cs
Normal file
74
src/LibRyujinx/Android/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/Android/Jni/Primitives/JChar.cs
Normal file
56
src/LibRyujinx/Android/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/Android/Jni/Primitives/JDouble.cs
Normal file
70
src/LibRyujinx/Android/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/Android/Jni/Primitives/JFloat.cs
Normal file
70
src/LibRyujinx/Android/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/Android/Jni/Primitives/JInt.cs
Normal file
73
src/LibRyujinx/Android/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/Android/Jni/Primitives/JLong.cs
Normal file
73
src/LibRyujinx/Android/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/Android/Jni/Primitives/JShort.cs
Normal file
74
src/LibRyujinx/Android/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
|
||||
}
|
||||
}
|
26
src/LibRyujinx/Android/Jni/References/JArrayLocalRef.cs
Normal file
26
src/LibRyujinx/Android/Jni/References/JArrayLocalRef.cs
Normal file
@ -0,0 +1,26 @@
|
||||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
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 explicit operator JObjectLocalRef(JArrayLocalRef a) => a._value;
|
||||
public static Boolean operator ==(JArrayLocalRef a, JArrayLocalRef b) => a.Equals(b);
|
||||
public static Boolean operator !=(JArrayLocalRef a, JArrayLocalRef b) => !a.Equals(b);
|
||||
#endregion
|
||||
}
|
29
src/LibRyujinx/Android/Jni/References/JClassLocalRef.cs
Normal file
29
src/LibRyujinx/Android/Jni/References/JClassLocalRef.cs
Normal file
@ -0,0 +1,29 @@
|
||||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
namespace LibRyujinx.Jni.References;
|
||||
|
||||
public readonly struct JClassLocalRef : IEquatable<JClassLocalRef>
|
||||
{
|
||||
#pragma warning disable 0649
|
||||
private readonly JObjectLocalRef _value;
|
||||
#pragma warning restore 0649
|
||||
|
||||
private JClassLocalRef(JObjectLocalRef value) => this._value = value;
|
||||
|
||||
#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 explicit operator JObjectLocalRef(JClassLocalRef a) => a._value;
|
||||
public static explicit operator JClassLocalRef(JObjectLocalRef a) => new(a);
|
||||
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/Android/Jni/References/JGlobalRef.cs
Normal file
28
src/LibRyujinx/Android/Jni/References/JGlobalRef.cs
Normal file
@ -0,0 +1,28 @@
|
||||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
namespace LibRyujinx.Jni.References;
|
||||
|
||||
public readonly struct JGlobalRef : IEquatable<JGlobalRef>
|
||||
{
|
||||
#pragma warning disable 0649
|
||||
private readonly JObjectLocalRef _value;
|
||||
|
||||
public JObjectLocalRef Value => _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 explicit operator JObjectLocalRef(JGlobalRef a) => a._value;
|
||||
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/Android/Jni/References/JObjectLocalRef.cs
Normal file
28
src/LibRyujinx/Android/Jni/References/JObjectLocalRef.cs
Normal file
@ -0,0 +1,28 @@
|
||||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
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
|
||||
}
|
||||
}
|
27
src/LibRyujinx/Android/Jni/References/JStringLocalRef.cs
Normal file
27
src/LibRyujinx/Android/Jni/References/JStringLocalRef.cs
Normal file
@ -0,0 +1,27 @@
|
||||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
namespace LibRyujinx.Jni.References;
|
||||
|
||||
public readonly struct JStringLocalRef : IEquatable<JStringLocalRef>
|
||||
{
|
||||
#pragma warning disable 0649
|
||||
private 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 explicit operator JObjectLocalRef(JStringLocalRef a) => a._value;
|
||||
public static Boolean operator ==(JStringLocalRef a, JStringLocalRef b) => a.Equals(b);
|
||||
public static Boolean operator !=(JStringLocalRef a, JStringLocalRef b) => !a.Equals(b);
|
||||
#endregion
|
||||
}
|
27
src/LibRyujinx/Android/Jni/References/JThrowableLocalRef.cs
Normal file
27
src/LibRyujinx/Android/Jni/References/JThrowableLocalRef.cs
Normal file
@ -0,0 +1,27 @@
|
||||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
namespace LibRyujinx.Jni.References;
|
||||
|
||||
public readonly struct JThrowableLocalRef : IEquatable<JThrowableLocalRef>
|
||||
{
|
||||
#pragma warning disable 0649
|
||||
private readonly JObjectLocalRef _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 explicit operator JObjectLocalRef(JThrowableLocalRef a) => a._value;
|
||||
public static Boolean operator ==(JThrowableLocalRef a, JThrowableLocalRef b) => a.Equals(b);
|
||||
public static Boolean operator !=(JThrowableLocalRef a, JThrowableLocalRef b) => !a.Equals(b);
|
||||
#endregion
|
||||
}
|
26
src/LibRyujinx/Android/Jni/References/JWeakRef.cs
Normal file
26
src/LibRyujinx/Android/Jni/References/JWeakRef.cs
Normal file
@ -0,0 +1,26 @@
|
||||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
namespace LibRyujinx.Jni.References;
|
||||
|
||||
public readonly struct JWeakRef : IEquatable<JWeakRef>
|
||||
{
|
||||
#pragma warning disable 0649
|
||||
private readonly JObjectLocalRef _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 explicit operator JObjectLocalRef(JWeakRef a) => a._value;
|
||||
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/Android/Jni/Values/JEnvValue.cs
Normal file
30
src/LibRyujinx/Android/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/Android/Jni/Values/JInvokeInterface.cs
Normal file
20
src/LibRyujinx/Android/Jni/Values/JInvokeInterface.cs
Normal file
@ -0,0 +1,20 @@
|
||||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
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; }
|
||||
}
|
||||
}
|
247
src/LibRyujinx/Android/Jni/Values/JNativeInterface.cs
Normal file
247
src/LibRyujinx/Android/Jni/Values/JNativeInterface.cs
Normal file
@ -0,0 +1,247 @@
|
||||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace LibRyujinx.Jni.Values;
|
||||
|
||||
[SuppressMessage("CodeQuality", "IDE0051:Remove unused private members",
|
||||
Justification = "This struct is created only by binary operations.")]
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
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; }
|
||||
private readonly IntPtr CallObjectMethodPointer { get; init; }
|
||||
private readonly IntPtr CallObjectMethodVPointer { get; init; }
|
||||
internal readonly IntPtr CallObjectMethodAPointer { get; init; }
|
||||
private readonly IntPtr CallBooleanMethodPointer { get; init; }
|
||||
private readonly IntPtr CallBooleanMethodVPointer { get; init; }
|
||||
internal readonly IntPtr CallBooleanMethodAPointer { get; init; }
|
||||
private readonly IntPtr CallByteMethodPointer { get; init; }
|
||||
private readonly IntPtr CallByteMethodVPointer { get; init; }
|
||||
internal readonly IntPtr CallByteMethodAPointer { get; init; }
|
||||
private readonly IntPtr CallCharMethodPointer { get; init; }
|
||||
private readonly IntPtr CallCharMethodVPointer { get; init; }
|
||||
internal readonly IntPtr CallCharMethodAPointer { get; init; }
|
||||
private readonly IntPtr CallShortMethodPointer { get; init; }
|
||||
private readonly IntPtr CallShortMethodVPointer { get; init; }
|
||||
internal readonly IntPtr CallShortMethodAPointer { get; init; }
|
||||
private readonly IntPtr CallIntMethodPointer { get; init; }
|
||||
private readonly IntPtr CallIntMethodVPointer { get; init; }
|
||||
internal readonly IntPtr CallIntMethodAPointer { get; init; }
|
||||
private readonly IntPtr CallLongMethodPointer { get; init; }
|
||||
private readonly IntPtr CallLongMethodVPointer { get; init; }
|
||||
internal readonly IntPtr CallLongMethodAPointer { get; init; }
|
||||
private readonly IntPtr CallFloatMethodPointer { get; init; }
|
||||
private readonly IntPtr CallFloatMethodVPointer { get; init; }
|
||||
internal readonly IntPtr CallFloatMethodAPointer { get; init; }
|
||||
private readonly IntPtr CallDoubleMethodPointer { get; init; }
|
||||
private readonly IntPtr CallDoubleMethodVPointer { get; init; }
|
||||
internal readonly IntPtr CallDoubleMethodAPointer { get; init; }
|
||||
private readonly IntPtr CallVoidMethodPointer { get; init; }
|
||||
private readonly IntPtr CallVoidMethodVPointer { get; init; }
|
||||
internal readonly IntPtr CallVoidMethodAPointer { get; init; }
|
||||
private readonly IntPtr CallNonVirtualObjectMethodPointer { get; init; }
|
||||
private readonly IntPtr CallNonVirtualObjectMethodVPointer { get; init; }
|
||||
internal readonly IntPtr CallNonVirtualObjectMethodAPointer { get; init; }
|
||||
private readonly IntPtr CallNonVirtualBooleanMethodPointer { get; init; }
|
||||
private readonly IntPtr CallNonVirtualBooleanMethodVPointer { get; init; }
|
||||
internal readonly IntPtr CallNonVirtualBooleanMethodAPointer { get; init; }
|
||||
private readonly IntPtr CallNonVirtualByteMethodPointer { get; init; }
|
||||
private readonly IntPtr CallNonVirtualByteMethodVPointer { get; init; }
|
||||
internal readonly IntPtr CallNonVirtualByteMethodAPointer { get; init; }
|
||||
private readonly IntPtr CallNonVirtualCharMethodPointer { get; init; }
|
||||
private readonly IntPtr CallNonVirtualCharMethodVPointer { get; init; }
|
||||
internal readonly IntPtr CallNonVirtualCharMethodAPointer { get; init; }
|
||||
private readonly IntPtr CallNonVirtualShortMethodPointer { get; init; }
|
||||
private readonly IntPtr CallNonVirtualShortMethodVPointer { get; init; }
|
||||
internal readonly IntPtr CallNonVirtualShortMethodAPointer { get; init; }
|
||||
private readonly IntPtr CallNonVirtualIntMethodPointer { get; init; }
|
||||
private readonly IntPtr CallNonVirtualIntMethodVPointer { get; init; }
|
||||
internal readonly IntPtr CallNonVirtualIntMethodAPointer { get; init; }
|
||||
private readonly IntPtr CallNonVirtualLongMethodPointer { get; init; }
|
||||
private readonly IntPtr CallNonVirtualLongMethodVPointer { get; init; }
|
||||
internal readonly IntPtr CallNonVirtualLongMethodAPointer { get; init; }
|
||||
private readonly IntPtr CallNonVirtualFloatMethodPointer { get; init; }
|
||||
private readonly IntPtr CallNonVirtualFloatMethodVPointer { get; init; }
|
||||
internal readonly IntPtr CallNonVirtualFloatMethodAPointer { get; init; }
|
||||
private readonly IntPtr CallNonVirtualDoubleMethodPointer { get; init; }
|
||||
private readonly IntPtr CallNonVirtualDoubleMethodVPointer { get; init; }
|
||||
internal readonly IntPtr CallNonVirtualDoubleMethodAPointer { get; init; }
|
||||
private readonly IntPtr CallNonVirtualVoidMethodPointer { get; init; }
|
||||
private 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; }
|
||||
private readonly IntPtr CallStaticObjectMethodPointer { get; init; }
|
||||
private readonly IntPtr CallStaticObjectMethodVPointer { get; init; }
|
||||
internal readonly IntPtr CallStaticObjectMethodAPointer { get; init; }
|
||||
private readonly IntPtr CallStaticBooleanMethodPointer { get; init; }
|
||||
private readonly IntPtr CallStaticBooleanMethodVPointer { get; init; }
|
||||
internal readonly IntPtr CallStaticBooleanMethodAPointer { get; init; }
|
||||
private readonly IntPtr CallStaticByteMethodPointer { get; init; }
|
||||
private readonly IntPtr CallStaticByteMethodVPointer { get; init; }
|
||||
internal readonly IntPtr CallStaticByteMethodAPointer { get; init; }
|
||||
private readonly IntPtr CallStaticCharMethodPointer { get; init; }
|
||||
private readonly IntPtr CallStaticCharMethodVPointer { get; init; }
|
||||
internal readonly IntPtr CallStaticCharMethodAPointer { get; init; }
|
||||
private readonly IntPtr CallStaticShortMethodPointer { get; init; }
|
||||
private readonly IntPtr CallStaticShortMethodVPointer { get; init; }
|
||||
internal readonly IntPtr CallStaticShortMethodAPointer { get; init; }
|
||||
private readonly IntPtr CallStaticIntMethodPointer { get; init; }
|
||||
private readonly IntPtr CallStaticIntMethodVPointer { get; init; }
|
||||
internal readonly IntPtr CallStaticIntMethodAPointer { get; init; }
|
||||
private readonly IntPtr CallStaticLongMethodPointer { get; init; }
|
||||
private readonly IntPtr CallStaticLongMethodVPointer { get; init; }
|
||||
internal readonly IntPtr CallStaticLongMethodAPointer { get; init; }
|
||||
private readonly IntPtr CallStaticFloatMethodPointer { get; init; }
|
||||
private readonly IntPtr CallStaticFloatMethodVPointer { get; init; }
|
||||
internal readonly IntPtr CallStaticFloatMethodAPointer { get; init; }
|
||||
private readonly IntPtr CallStaticDoubleMethodPointer { get; init; }
|
||||
private readonly IntPtr CallStaticDoubleMethodVPointer { get; init; }
|
||||
internal readonly IntPtr CallStaticDoubleMethodAPointer { get; init; }
|
||||
private readonly IntPtr CallStaticVoidMethodPointer { get; init; }
|
||||
private 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; }
|
||||
}
|
11
src/LibRyujinx/Android/Jni/Values/JNativeMethod.cs
Normal file
11
src/LibRyujinx/Android/Jni/Values/JNativeMethod.cs
Normal file
@ -0,0 +1,11 @@
|
||||
using Rxmxnx.PInvoke;
|
||||
using System;
|
||||
|
||||
namespace LibRyujinx.Jni.Values;
|
||||
|
||||
public readonly struct JNativeMethod
|
||||
{
|
||||
internal ReadOnlyValPtr<Byte> Name { get; init; }
|
||||
internal ReadOnlyValPtr<Byte> Signature { get; init; }
|
||||
internal IntPtr Pointer { get; init; }
|
||||
}
|
46
src/LibRyujinx/Android/Jni/Values/JValue.cs
Normal file
46
src/LibRyujinx/Android/Jni/Values/JValue.cs
Normal file
@ -0,0 +1,46 @@
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
using LibRyujinx.Jni.References;
|
||||
|
||||
using Rxmxnx.PInvoke;
|
||||
|
||||
namespace LibRyujinx.Jni.Values;
|
||||
|
||||
internal readonly struct JValue
|
||||
{
|
||||
private delegate Boolean IsDefaultDelegate(in JValue value);
|
||||
|
||||
private static readonly Int32 size = NativeUtilities.SizeOf<JValue>();
|
||||
|
||||
private static readonly IsDefaultDelegate isDefault = JValue.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 => JValue.isDefault(this);
|
||||
|
||||
public static JValue Create(in ReadOnlySpan<Byte> source)
|
||||
{
|
||||
Byte[] result = new Byte[JValue.size];
|
||||
for (Int32 i = 0; i < source.Length; i++)
|
||||
result[i] = source[i];
|
||||
return result.ToValue<JValue>();
|
||||
}
|
||||
|
||||
private static IsDefaultDelegate GetIsDefault() => Environment.Is64BitProcess ? JValue.DefaultLong : JValue.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)
|
||||
=> Unsafe.AsRef(in jValue).Transform<JValue, Int64>() == default;
|
||||
|
||||
public static explicit operator JValue(JObjectLocalRef a) => JValue.Create(NativeUtilities.AsBytes(in a));
|
||||
}
|
13
src/LibRyujinx/Android/Jni/Values/JavaVMAttachArgs.cs
Normal file
13
src/LibRyujinx/Android/Jni/Values/JavaVMAttachArgs.cs
Normal file
@ -0,0 +1,13 @@
|
||||
using LibRyujinx.Jni.References;
|
||||
|
||||
using Rxmxnx.PInvoke;
|
||||
using System;
|
||||
|
||||
namespace LibRyujinx.Jni.Values;
|
||||
|
||||
public readonly struct JavaVMAttachArgs
|
||||
{
|
||||
internal Int32 Version { get; init; }
|
||||
internal ReadOnlyValPtr<Byte> Name { get; init; }
|
||||
internal JObjectLocalRef Group { get; init; }
|
||||
}
|
12
src/LibRyujinx/Android/Jni/Values/JavaVMInitArgs.cs
Normal file
12
src/LibRyujinx/Android/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; }
|
||||
}
|
||||
}
|
10
src/LibRyujinx/Android/Jni/Values/JavaVMOption.cs
Normal file
10
src/LibRyujinx/Android/Jni/Values/JavaVMOption.cs
Normal file
@ -0,0 +1,10 @@
|
||||
using Rxmxnx.PInvoke;
|
||||
using System;
|
||||
|
||||
namespace LibRyujinx.Jni.Values;
|
||||
|
||||
public readonly struct JavaVMOption
|
||||
{
|
||||
internal ReadOnlyValPtr<Byte> Name { get; init; }
|
||||
internal IntPtr ExtraInfo { get; init; }
|
||||
}
|
29
src/LibRyujinx/Android/Jni/Values/JavaVMValue.cs
Normal file
29
src/LibRyujinx/Android/Jni/Values/JavaVMValue.cs
Normal file
@ -0,0 +1,29 @@
|
||||
using Rxmxnx.PInvoke;
|
||||
using System;
|
||||
|
||||
namespace LibRyujinx.Jni.Values;
|
||||
|
||||
internal readonly struct JavaVMValue : IEquatable<JavaVMValue>
|
||||
{
|
||||
#pragma warning disable 0649
|
||||
private readonly IntPtr _value;
|
||||
#pragma warning restore 0649
|
||||
|
||||
#region Operators
|
||||
public static Boolean operator ==(JavaVMValue a, JavaVMValue b) => a._value.Equals(b._value);
|
||||
public static Boolean operator !=(JavaVMValue a, JavaVMValue b) => !a._value.Equals(b._value);
|
||||
#endregion
|
||||
|
||||
#region Public Properties
|
||||
internal readonly ref JInvokeInterface Functions => ref this._value.GetUnsafeReference<JInvokeInterface>();
|
||||
#endregion
|
||||
|
||||
#region Public Methods
|
||||
public Boolean Equals(JavaVMValue other) => this._value.Equals(other._value);
|
||||
#endregion
|
||||
|
||||
#region Overrided Methods
|
||||
public override Boolean Equals(Object obj) => obj is JavaVMValue other && this.Equals(other);
|
||||
public override Int32 GetHashCode() => this._value.GetHashCode();
|
||||
#endregion
|
||||
}
|
566
src/LibRyujinx/Android/JniExportedMethods.cs
Normal file
566
src/LibRyujinx/Android/JniExportedMethods.cs
Normal file
@ -0,0 +1,566 @@
|
||||
using LibRyujinx.Android;
|
||||
using LibRyujinx.Jni.Pointers;
|
||||
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.Threading;
|
||||
|
||||
namespace LibRyujinx
|
||||
{
|
||||
public static partial class LibRyujinx
|
||||
{
|
||||
private static long _surfacePtr;
|
||||
private static long _window = 0;
|
||||
|
||||
public static VulkanLoader? VulkanLoader { get; private set; }
|
||||
|
||||
[DllImport("libryujinxjni")]
|
||||
internal extern static void setRenderingThread();
|
||||
|
||||
[DllImport("libryujinxjni")]
|
||||
internal extern static void debug_break(int code);
|
||||
|
||||
[DllImport("libryujinxjni")]
|
||||
internal extern static void setCurrentTransform(long native_window, int transform);
|
||||
|
||||
public delegate IntPtr JniCreateSurface(IntPtr native_surface, IntPtr instance);
|
||||
|
||||
[UnmanagedCallersOnly(EntryPoint = "javaInitialize")]
|
||||
public unsafe static bool JniInitialize(IntPtr jpathId, IntPtr jniEnv)
|
||||
{
|
||||
Logger.Trace?.Print(LogClass.Application, "Jni Function Call");
|
||||
PlatformInfo.IsBionic = true;
|
||||
|
||||
Logger.AddTarget(
|
||||
new AsyncLogTargetWrapper(
|
||||
new AndroidLogTarget("RyujinxLog"),
|
||||
1000,
|
||||
AsyncLogTargetOverflowAction.Block
|
||||
));
|
||||
|
||||
var path = Marshal.PtrToStringAnsi(jpathId);
|
||||
|
||||
var init = Initialize(path);
|
||||
|
||||
Interop.Initialize(new JEnvRef(jniEnv));
|
||||
|
||||
Interop.Test();
|
||||
|
||||
return init;
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly(EntryPoint = "deviceReloadFilesystem")]
|
||||
public static void JnaReloadFileSystem()
|
||||
{
|
||||
Logger.Trace?.Print(LogClass.Application, "Jni Function Call");
|
||||
SwitchDevice?.ReloadFileSystem();
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly(EntryPoint = "deviceInitialize")]
|
||||
public static bool JnaDeviceInitialize(bool isHostMapped,
|
||||
bool useNce,
|
||||
int systemLanguage,
|
||||
int regionCode,
|
||||
bool enableVsync,
|
||||
bool enableDockedMode,
|
||||
bool enablePtc,
|
||||
bool enableInternetAccess,
|
||||
IntPtr timeZonePtr,
|
||||
bool ignoreMissingServices)
|
||||
{
|
||||
debug_break(4);
|
||||
Logger.Trace?.Print(LogClass.Application, "Jni Function Call");
|
||||
AudioDriver = new OpenALHardwareDeviceDriver();
|
||||
|
||||
var timezone = Marshal.PtrToStringAnsi(timeZonePtr);
|
||||
return InitializeDevice(isHostMapped,
|
||||
useNce,
|
||||
(SystemLanguage)systemLanguage,
|
||||
(RegionCode)regionCode,
|
||||
enableVsync,
|
||||
enableDockedMode,
|
||||
enablePtc,
|
||||
enableInternetAccess,
|
||||
timezone,
|
||||
ignoreMissingServices);
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly(EntryPoint = "deviceGetGameFifo")]
|
||||
public static double JnaGetGameFifo()
|
||||
{
|
||||
Logger.Trace?.Print(LogClass.Application, "Jni Function Call");
|
||||
var stats = SwitchDevice?.EmulationContext?.Statistics.GetFifoPercent() ?? 0;
|
||||
|
||||
return stats;
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly(EntryPoint = "deviceGetGameFrameTime")]
|
||||
public static double JnaGetGameFrameTime()
|
||||
{
|
||||
Logger.Trace?.Print(LogClass.Application, "Jni Function Call");
|
||||
var stats = SwitchDevice?.EmulationContext?.Statistics.GetGameFrameTime() ?? 0;
|
||||
|
||||
return stats;
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly(EntryPoint = "deviceGetGameFrameRate")]
|
||||
public static double JnaGetGameFrameRate()
|
||||
{
|
||||
Logger.Trace?.Print(LogClass.Application, "Jni Function Call");
|
||||
var stats = SwitchDevice?.EmulationContext?.Statistics.GetGameFrameRate() ?? 0;
|
||||
|
||||
return stats;
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly(EntryPoint = "deviceLaunchMiiEditor")]
|
||||
public static bool JNALaunchMiiEditApplet()
|
||||
{
|
||||
Logger.Trace?.Print(LogClass.Application, "Jni Function Call");
|
||||
if (SwitchDevice?.EmulationContext == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return LaunchMiiEditApplet();
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly(EntryPoint = "deviceGetDlcContentList")]
|
||||
public static IntPtr JniGetDlcContentListNative(IntPtr pathPtr, long titleId)
|
||||
{
|
||||
Logger.Trace?.Print(LogClass.Application, "Jni Function Call");
|
||||
var list = GetDlcContentList(Marshal.PtrToStringAnsi(pathPtr) ?? "", (ulong)titleId);
|
||||
|
||||
return CreateStringArray(list);
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly(EntryPoint = "deviceGetDlcTitleId")]
|
||||
public static long JniGetDlcTitleIdNative(IntPtr pathPtr, IntPtr ncaPath)
|
||||
{
|
||||
Logger.Trace?.Print(LogClass.Application, "Jni Function Call");
|
||||
return Marshal.StringToHGlobalAnsi(GetDlcTitleId(Marshal.PtrToStringAnsi(pathPtr) ?? "", Marshal.PtrToStringAnsi(ncaPath) ?? ""));
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly(EntryPoint = "deviceSignalEmulationClose")]
|
||||
public static void JniSignalEmulationCloseNative()
|
||||
{
|
||||
Logger.Trace?.Print(LogClass.Application, "Jni Function Call");
|
||||
SignalEmulationClose();
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly(EntryPoint = "deviceCloseEmulation")]
|
||||
public static void JniCloseEmulationNative()
|
||||
{
|
||||
Logger.Trace?.Print(LogClass.Application, "Jni Function Call");
|
||||
CloseEmulation();
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly(EntryPoint = "deviceLoadDescriptor")]
|
||||
public static bool JnaLoadApplicationNative(int descriptor, int type, int 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)type, update);
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly(EntryPoint = "deviceVerifyFirmware")]
|
||||
public static IntPtr JniVerifyFirmware(int descriptor, bool isXci)
|
||||
{
|
||||
Logger.Trace?.Print(LogClass.Application, "Jni Function Call");
|
||||
|
||||
var stream = OpenFile(descriptor);
|
||||
|
||||
IntPtr stringHandle = 0;
|
||||
string? version = "0.0";
|
||||
|
||||
try
|
||||
{
|
||||
version = VerifyFirmware(stream, isXci)?.VersionString;
|
||||
}
|
||||
catch (Exception _)
|
||||
{
|
||||
Logger.Error?.Print(LogClass.Service, $"Unable to verify firmware. Exception: {_}");
|
||||
}
|
||||
|
||||
if (version != null)
|
||||
{
|
||||
stringHandle = Marshal.StringToHGlobalAnsi(version);
|
||||
}
|
||||
|
||||
return stringHandle;
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly(EntryPoint = "deviceInstallFirmware")]
|
||||
public static void JniInstallFirmware(int descriptor, bool isXci)
|
||||
{
|
||||
Logger.Trace?.Print(LogClass.Application, "Jni Function Call");
|
||||
|
||||
var stream = OpenFile(descriptor);
|
||||
|
||||
InstallFirmware(stream, isXci);
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly(EntryPoint = "deviceGetInstalledFirmwareVersion")]
|
||||
public static IntPtr JniGetInstalledFirmwareVersion()
|
||||
{
|
||||
Logger.Trace?.Print(LogClass.Application, "Jni Function Call");
|
||||
|
||||
var version = GetInstalledFirmwareVersion() ?? "0.0";
|
||||
return Marshal.StringToHGlobalAnsi(version);
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly(EntryPoint = "graphicsInitialize")]
|
||||
public static bool JnaGraphicsInitialize(float resScale,
|
||||
float maxAnisotropy,
|
||||
bool fastGpuTime,
|
||||
bool fast2DCopy,
|
||||
bool enableMacroJit,
|
||||
bool enableMacroHLE,
|
||||
bool enableShaderCache,
|
||||
bool enableTextureRecompression,
|
||||
int backendThreading)
|
||||
{
|
||||
Logger.Trace?.Print(LogClass.Application, "Jni Function Call");
|
||||
SearchPathContainer.Platform = UnderlyingPlatform.Android;
|
||||
return InitializeGraphics(new GraphicsConfiguration()
|
||||
{
|
||||
ResScale = resScale,
|
||||
MaxAnisotropy = maxAnisotropy,
|
||||
FastGpuTime = fastGpuTime,
|
||||
Fast2DCopy = fast2DCopy,
|
||||
EnableMacroJit = enableMacroJit,
|
||||
EnableMacroHLE = enableMacroHLE,
|
||||
EnableShaderCache = enableShaderCache,
|
||||
EnableTextureRecompression = enableTextureRecompression,
|
||||
BackendThreading = (BackendThreading)backendThreading
|
||||
});
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly(EntryPoint = "graphicsInitializeRenderer")]
|
||||
public unsafe static bool JnaGraphicsInitializeRenderer(char** extensionsArray,
|
||||
int extensionsLength,
|
||||
long driverHandle)
|
||||
{
|
||||
Logger.Trace?.Print(LogClass.Application, "Jni Function Call");
|
||||
if (Renderer != null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
List<string?> extensions = new();
|
||||
|
||||
for (int i = 0; i < extensionsLength; i++)
|
||||
{
|
||||
extensions.Add(Marshal.PtrToStringAnsi((IntPtr)extensionsArray[i]));
|
||||
}
|
||||
|
||||
if (driverHandle != 0)
|
||||
{
|
||||
VulkanLoader = new VulkanLoader((IntPtr)driverHandle);
|
||||
}
|
||||
|
||||
CreateSurface createSurfaceFunc = instance =>
|
||||
{
|
||||
_surfacePtr = Interop.GetSurfacePtr();
|
||||
_window = Interop.GetWindowsHandle();
|
||||
|
||||
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());
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly(EntryPoint = "graphicsRendererSetSize")]
|
||||
public static void JnaSetRendererSizeNative(int width, int height)
|
||||
{
|
||||
Logger.Trace?.Print(LogClass.Application, "Jni Function Call");
|
||||
Renderer?.Window?.SetSize(width, height);
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly(EntryPoint = "graphicsRendererRunLoop")]
|
||||
public static void JniRunLoopNative()
|
||||
{
|
||||
Logger.Trace?.Print(LogClass.Application, "Jni Function Call");
|
||||
SetSwapBuffersCallback(() =>
|
||||
{
|
||||
var time = SwitchDevice.EmulationContext.Statistics.GetGameFrameTime();
|
||||
Interop.FrameEnded(time);
|
||||
});
|
||||
RunLoop();
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly(EntryPoint = "loggingSetEnabled")]
|
||||
public static void JniSetLoggingEnabledNative(int logLevel, bool enabled)
|
||||
{
|
||||
Logger.SetEnable((LogLevel)logLevel, enabled);
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly(EntryPoint = "loggingEnabledGraphicsLog")]
|
||||
public static void JniSetLoggingEnabledGraphicsLog(bool enabled)
|
||||
{
|
||||
_enableGraphicsLogging = enabled;
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly(EntryPoint = "deviceGetGameInfo")]
|
||||
public unsafe static void JniGetGameInfo(int fileDescriptor, IntPtr extension, IntPtr infoPtr)
|
||||
{
|
||||
Logger.Trace?.Print(LogClass.Application, "Jni Function Call");
|
||||
using var stream = OpenFile(fileDescriptor);
|
||||
var ext = Marshal.PtrToStringAnsi(extension);
|
||||
var info = GetGameInfo(stream, ext.ToLower()) ?? GetDefaultInfo(stream);
|
||||
var i = (GameInfoNative*)infoPtr;
|
||||
var n = new GameInfoNative(info);
|
||||
i->TitleId = n.TitleId;
|
||||
i->TitleName = n.TitleName;
|
||||
i->Version = n.Version;
|
||||
i->FileSize = n.FileSize;
|
||||
i->Icon = n.Icon;
|
||||
i->Version = n.Version;
|
||||
i->Developer = n.Developer;
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly(EntryPoint = "graphicsRendererSetVsync")]
|
||||
public static void JnaSetVsyncStateNative(bool enabled)
|
||||
{
|
||||
Logger.Trace?.Print(LogClass.Application, "Jni Function Call");
|
||||
SetVsyncState(enabled);
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly(EntryPoint = "inputInitialize")]
|
||||
public static void JnaInitializeInput(int width, int height)
|
||||
{
|
||||
Logger.Trace?.Print(LogClass.Application, "Jni Function Call");
|
||||
InitializeInput(width, height);
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly(EntryPoint = "inputSetClientSize")]
|
||||
public static void JnaSetClientSize(int width, int height)
|
||||
{
|
||||
Logger.Trace?.Print(LogClass.Application, "Jni Function Call");
|
||||
SetClientSize(width, height);
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly(EntryPoint = "inputSetTouchPoint")]
|
||||
public static void JnaSetTouchPoint(int x, int y)
|
||||
{
|
||||
Logger.Trace?.Print(LogClass.Application, "Jni Function Call");
|
||||
SetTouchPoint(x, y);
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly(EntryPoint = "inputReleaseTouchPoint")]
|
||||
public static void JnaReleaseTouchPoint()
|
||||
{
|
||||
Logger.Trace?.Print(LogClass.Application, "Jni Function Call");
|
||||
ReleaseTouchPoint();
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly(EntryPoint = "inputUpdate")]
|
||||
public static void JniUpdateInput()
|
||||
{
|
||||
Logger.Trace?.Print(LogClass.Application, "Jni Function Call");
|
||||
UpdateInput();
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly(EntryPoint = "inputSetButtonPressed")]
|
||||
public static void JnaSetButtonPressed(int button, int id)
|
||||
{
|
||||
Logger.Trace?.Print(LogClass.Application, "Jni Function Call");
|
||||
SetButtonPressed((GamepadButtonInputId)button, id);
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly(EntryPoint = "inputSetButtonReleased")]
|
||||
public static void JnaSetButtonReleased(int button, int id)
|
||||
{
|
||||
Logger.Trace?.Print(LogClass.Application, "Jni Function Call");
|
||||
SetButtonReleased((GamepadButtonInputId)button, id);
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly(EntryPoint = "inputSetAccelerometerData")]
|
||||
public static void JniSetAccelerometerData(float x, float y, float z, int id)
|
||||
{
|
||||
var accel = new Vector3(x, y, z);
|
||||
SetAccelerometerData(accel, id);
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly(EntryPoint = "inputSetGyroData")]
|
||||
public static void JniSetGyroData(float x, float y, float z, int id)
|
||||
{
|
||||
var gryo = new Vector3(x, y, z);
|
||||
SetGryoData(gryo, id);
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly(EntryPoint = "inputSetStickAxis")]
|
||||
public static void JnaSetStickAxis(int stick, float x, float y, int id)
|
||||
{
|
||||
Logger.Trace?.Print(LogClass.Application, "Jni Function Call");
|
||||
SetStickAxis((StickInputId)stick, new Vector2(float.IsNaN(x) ? 0 : x, float.IsNaN(y) ? 0 : y), id);
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly(EntryPoint = "inputConnectGamepad")]
|
||||
public static int JnaConnectGamepad(int index)
|
||||
{
|
||||
Logger.Trace?.Print(LogClass.Application, "Jni Function Call");
|
||||
return ConnectGamepad(index);
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly(EntryPoint = "userGetOpenedUser")]
|
||||
public static IntPtr JniGetOpenedUser()
|
||||
{
|
||||
Logger.Trace?.Print(LogClass.Application, "Jni Function Call");
|
||||
var userId = GetOpenedUser();
|
||||
var ptr = Marshal.StringToHGlobalAnsi(userId);
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly(EntryPoint = "userGetUserPicture")]
|
||||
public static IntPtr JniGetUserPicture(IntPtr userIdPtr)
|
||||
{
|
||||
Logger.Trace?.Print(LogClass.Application, "Jni Function Call");
|
||||
var userId = Marshal.PtrToStringAnsi(userIdPtr) ?? "";
|
||||
|
||||
return Marshal.StringToHGlobalAnsi(GetUserPicture(userId));
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly(EntryPoint = "userSetUserPicture")]
|
||||
public static void JniGetUserPicture(IntPtr userIdPtr, IntPtr picturePtr)
|
||||
{
|
||||
Logger.Trace?.Print(LogClass.Application, "Jni Function Call");
|
||||
var userId = Marshal.PtrToStringAnsi(userIdPtr) ?? "";
|
||||
var picture = Marshal.PtrToStringAnsi(picturePtr) ?? "";
|
||||
|
||||
SetUserPicture(userId, picture);
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly(EntryPoint = "userGetUserName")]
|
||||
public static IntPtr JniGetUserName(IntPtr userIdPtr)
|
||||
{
|
||||
Logger.Trace?.Print(LogClass.Application, "Jni Function Call");
|
||||
var userId = Marshal.PtrToStringAnsi(userIdPtr) ?? "";
|
||||
|
||||
return Marshal.StringToHGlobalAnsi(GetUserName(userId));
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly(EntryPoint = "userSetUserName")]
|
||||
public static void JniSetUserName(IntPtr userIdPtr, IntPtr userNamePtr)
|
||||
{
|
||||
Logger.Trace?.Print(LogClass.Application, "Jni Function Call");
|
||||
var userId = Marshal.PtrToStringAnsi(userIdPtr) ?? "";
|
||||
var userName = Marshal.PtrToStringAnsi(userNamePtr) ?? "";
|
||||
|
||||
SetUserName(userId, userName);
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly(EntryPoint = "userGetAllUsers")]
|
||||
public static IntPtr JniGetAllUsers()
|
||||
{
|
||||
Logger.Trace?.Print(LogClass.Application, "Jni Function Call");
|
||||
var users = GetAllUsers();
|
||||
|
||||
return CreateStringArray(users.ToList());
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly(EntryPoint = "userAddUser")]
|
||||
public static void JniAddUser(IntPtr userNamePtr, IntPtr picturePtr)
|
||||
{
|
||||
Logger.Trace?.Print(LogClass.Application, "Jni Function Call");
|
||||
var userName = Marshal.PtrToStringAnsi(userNamePtr) ?? "";
|
||||
var picture = Marshal.PtrToStringAnsi(picturePtr) ?? "";
|
||||
|
||||
AddUser(userName, picture);
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly(EntryPoint = "userDeleteUser")]
|
||||
public static void JniDeleteUser(IntPtr userIdPtr)
|
||||
{
|
||||
Logger.Trace?.Print(LogClass.Application, "Jni Function Call");
|
||||
var userId = Marshal.PtrToStringAnsi(userIdPtr) ?? "";
|
||||
|
||||
DeleteUser(userId);
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly(EntryPoint = "uiHandlerSetup")]
|
||||
public static void JniSetupUiHandler()
|
||||
{
|
||||
SetupUiHandler();
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly(EntryPoint = "uiHandlerSetResponse")]
|
||||
public static void JniSetUiHandlerResponse(bool isOkPressed, IntPtr input)
|
||||
{
|
||||
SetUiHandlerResponse(isOkPressed, Marshal.PtrToStringAnsi(input) ?? "");
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly(EntryPoint = "userOpenUser")]
|
||||
public static void JniOpenUser(IntPtr userIdPtr)
|
||||
{
|
||||
Logger.Trace?.Print(LogClass.Application, "Jni Function Call");
|
||||
var userId = Marshal.PtrToStringAnsi(userIdPtr) ?? "";
|
||||
|
||||
OpenUser(userId);
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly(EntryPoint = "userCloseUser")]
|
||||
public static void JniCloseUser(IntPtr userIdPtr)
|
||||
{
|
||||
Logger.Trace?.Print(LogClass.Application, "Jni Function Call");
|
||||
var userId = Marshal.PtrToStringAnsi(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,
|
||||
}
|
||||
}
|
||||
}
|
235
src/LibRyujinx/LibRyujinx.Device.cs
Normal file
235
src/LibRyujinx/LibRyujinx.Device.cs
Normal file
@ -0,0 +1,235 @@
|
||||
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 System;
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace LibRyujinx
|
||||
{
|
||||
public static partial class LibRyujinx
|
||||
{
|
||||
public static bool InitializeDevice(bool isHostMapped,
|
||||
bool useHypervisor,
|
||||
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,
|
||||
useHypervisor,
|
||||
systemLanguage,
|
||||
regionCode,
|
||||
enableVsync,
|
||||
enableDockedMode,
|
||||
enablePtc,
|
||||
enableInternetAccess,
|
||||
timeZone,
|
||||
ignoreMissingServices);
|
||||
}
|
||||
|
||||
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, 0, updateStream) ?? false,
|
||||
FileType.Xci => emulationContext?.LoadXci(stream, 0, 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;
|
||||
}
|
||||
|
||||
public static void CloseEmulation()
|
||||
{
|
||||
if (SwitchDevice == null)
|
||||
return;
|
||||
|
||||
_npadManager?.Dispose();
|
||||
_npadManager = null;
|
||||
|
||||
_touchScreenManager?.Dispose();
|
||||
_touchScreenManager = null;
|
||||
|
||||
SwitchDevice!.InputManager?.Dispose();
|
||||
SwitchDevice!.InputManager = null;
|
||||
_inputManager = null;
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
248
src/LibRyujinx/LibRyujinx.Graphics.cs
Normal file
248
src/LibRyujinx/LibRyujinx.Graphics.cs
Normal file
@ -0,0 +1,248 @@
|
||||
using LibRyujinx.Android;
|
||||
using LibRyujinx.Shared;
|
||||
using OpenTK.Graphics.OpenGL;
|
||||
using Ryujinx.Common.Configuration;
|
||||
using Ryujinx.Common.Logging;
|
||||
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;
|
||||
private static bool _enableGraphicsLogging;
|
||||
|
||||
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; }
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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(Vk.GetApi(), (instance, vk) => new SurfaceKHR(createSurfaceFunc == null ? null : (ulong?)createSurfaceFunc(instance.Handle)),
|
||||
() => requiredExtensions,
|
||||
null);
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static void SetRendererSize(int width, int height)
|
||||
{
|
||||
Renderer?.Window?.SetSize(width, height);
|
||||
}
|
||||
|
||||
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(_enableGraphicsLogging ? GraphicsDebugLevel.All : 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;
|
||||
|
||||
if (Ryujinx.Common.PlatformInfo.IsBionic)
|
||||
{
|
||||
setRenderingThread();
|
||||
}
|
||||
|
||||
while (_isActive)
|
||||
{
|
||||
if (_isStopped)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (device.WaitFifo())
|
||||
{
|
||||
device.Statistics.RecordFifoStart();
|
||||
device.ProcessFrame();
|
||||
device.Statistics.RecordFifoEnd();
|
||||
}
|
||||
|
||||
while (device.ConsumeFrameAvailable())
|
||||
{
|
||||
device.PresentFrame(() =>
|
||||
{
|
||||
if (device.Gpu.Renderer is ThreadedRenderer threaded && threaded.BaseRenderer is VulkanRenderer vulkanRenderer)
|
||||
{
|
||||
setCurrentTransform(_window, (int)vulkanRenderer.CurrentTransform);
|
||||
}
|
||||
_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)
|
||||
{
|
||||
if(Ryujinx.Common.PlatformInfo.IsBionic)
|
||||
{
|
||||
Interop.UpdateProgress(status, value);
|
||||
}
|
||||
}
|
||||
var status = $"{current} / {total}";
|
||||
var progress = current / (float)total;
|
||||
if (float.IsNaN(progress))
|
||||
progress = 0;
|
||||
|
||||
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)}");
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user