Compare commits
231 Commits
Canary-1.2
...
9f25816eeb
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9f25816eeb | ||
|
|
e676fd8b17 | ||
|
|
dd16e3cee1 | ||
|
|
31e5f74e05 | ||
|
|
f2f099bddb | ||
|
|
2616dc57fb | ||
|
|
0cdf7cfe21 | ||
|
|
2ecf999569 | ||
|
|
b612fc5155 | ||
|
|
4f8bb06d8e | ||
|
|
8fd97963e9 | ||
|
|
25eb545409 | ||
|
|
52269964b6 | ||
|
|
ccdddac8fc | ||
|
|
1bc30bf3ba | ||
|
|
4868fface8 | ||
|
|
6fca4492d0 | ||
|
|
ade2f256e0 | ||
|
|
580b150c9a | ||
|
|
e6bad52945 | ||
|
|
beda3206e0 | ||
|
|
2f93a0f706 | ||
|
|
80f44d9547 | ||
|
|
b08e5db6d8 | ||
|
|
6a291d4116 | ||
|
|
6fc827fe67 | ||
|
|
6cd4866d76 | ||
|
|
4d7ca5c0f0 | ||
|
|
a375faecc1 | ||
|
|
1728b0f20c | ||
|
|
f7c70def34 | ||
|
|
846f8940e5 | ||
|
|
5aa071c59b | ||
|
|
c05aa45f30 | ||
|
|
8f09f4cec8 | ||
|
|
55d7584d0f | ||
|
|
1018c9db8b | ||
|
|
01ccd18726 | ||
|
|
abfbc6f4bc | ||
|
|
0c25cc1a81 | ||
|
|
6e7c787cb4 | ||
|
|
6a4bc02d7a | ||
|
|
cfbe22e9b8 | ||
|
|
868e5199c2 | ||
|
|
814c0526d2 | ||
|
|
48968f1195 | ||
|
|
f56cd968e2 | ||
|
|
82664ef69b | ||
|
|
a5a4ef38e6 | ||
|
|
e1cb957d7b | ||
|
|
dfbcdfa83a | ||
|
|
37f4c1ea1a | ||
|
|
fbc5ccfa2c | ||
|
|
c17e3bfcdf | ||
|
|
017f46f318 | ||
|
|
0bd62888a0 | ||
|
|
b01dcd1963 | ||
|
|
992fe0e64f | ||
|
|
b8b3767613 | ||
|
|
fd4d801bfd | ||
|
|
c4b9aedc0f | ||
|
|
106b37f91f | ||
|
|
9356b68f26 | ||
|
|
14aafebaa6 | ||
|
|
f1dee50275 | ||
|
|
c2ae49eb47 | ||
|
|
47c71966d0 | ||
|
|
f4e7482312 | ||
|
|
f9e8f4bc29 | ||
|
|
7694c8c046 | ||
|
|
0dd789e8a5 | ||
|
|
4e0aafd005 | ||
|
|
c5091f499e | ||
|
|
41c8fd8194 | ||
|
|
d4a7ee25ea | ||
|
|
3141c560fb | ||
|
|
de341b285b | ||
|
|
4518666a04 | ||
|
|
cc95e80ee9 | ||
|
|
d75ce52bd4 | ||
|
|
241b0152ad | ||
|
|
4a4ea557de | ||
|
|
33f42adb11 | ||
|
|
918ec1bde3 | ||
|
|
cca429d46a | ||
|
|
845c86f545 | ||
|
|
27993b789f | ||
|
|
bdd890cf6f | ||
|
|
c5574b41a1 | ||
|
|
292e27f0da | ||
|
|
606e149bd3 | ||
|
|
a8c3407d11 | ||
|
|
daa8168985 | ||
|
|
f580521e99 | ||
|
|
91f70584ec | ||
|
|
2c26388dde | ||
|
|
7df576b5d4 | ||
|
|
2226521f6c | ||
|
|
384416953d | ||
|
|
1343fabe41 | ||
|
|
1e52af5e29 | ||
|
|
7532ba06ad | ||
|
|
6d5dd49550 | ||
|
|
1e3718343c | ||
|
|
39e99ce271 | ||
|
|
672f5df0f9 | ||
|
|
804d9c1efe | ||
|
|
9270b35648 | ||
|
|
5a6d01db3c | ||
|
|
ef9c1416ec | ||
|
|
5efa7d5dfa | ||
|
|
a82569d615 | ||
|
|
ed5832ca73 | ||
|
|
574aa9ff9c | ||
|
|
8a29428de2 | ||
|
|
f4272b05fa | ||
|
|
d8265f7772 | ||
|
|
259526430c | ||
|
|
b5fafb6394 | ||
|
|
323c356d9c | ||
|
|
30b22ce6ba | ||
|
|
9acecc9eb2 | ||
|
|
4193a37a91 | ||
|
|
c4cc657b89 | ||
|
|
9726b0feb0 | ||
|
|
159ff828a1 | ||
|
|
6fa2bfc736 | ||
|
|
2c24df0247 | ||
|
|
13efc3e544 | ||
|
|
845dd9a8db | ||
|
|
b661bdd997 | ||
|
|
cc84041270 | ||
|
|
987ab9be41 | ||
|
|
8a2bc3957a | ||
|
|
850df38f1e | ||
|
|
c8d598d5ac | ||
|
|
3e5b2bda38 | ||
|
|
9bb50fc6dd | ||
|
|
e956864697 | ||
|
|
270c5bd815 | ||
|
|
6945a05e45 | ||
|
|
4399edaa9f | ||
|
|
4e77bcb55a | ||
|
|
f43442f774 | ||
|
|
88d11d3d8d | ||
|
|
391f57bdd2 | ||
|
|
fd2b5a7fc1 | ||
|
|
37c165e9fc | ||
|
|
003a6d322b | ||
|
|
978d2c132b | ||
|
|
5d63706cea | ||
|
|
732aafd3bb | ||
|
|
3fa714bb72 | ||
|
|
7c01633f13 | ||
|
|
27c5cba10b | ||
|
|
3525d5ecd4 | ||
|
|
6286501550 | ||
|
|
3cbd7dc1a1 | ||
|
|
61ae427a4d | ||
|
|
19d2883a35 | ||
|
|
617c03119f | ||
|
|
e43d899e1d | ||
|
|
0cd09ea0c5 | ||
|
|
4135d74e4d | ||
|
|
bd29f658b1 | ||
|
|
df150f0788 | ||
|
|
e50198b37d | ||
|
|
f426945fec | ||
|
|
172869bfba | ||
|
|
b6f88514f9 | ||
|
|
e92f52e56c | ||
|
|
de9e93606a | ||
|
|
318498eab0 | ||
|
|
a5cde8e006 | ||
|
|
d0a344d632 | ||
|
|
ca66298817 | ||
|
|
536f792558 | ||
|
|
7a451ab160 | ||
|
|
9ae1c4380d | ||
|
|
c88518bce2 | ||
|
|
a3888ed7cf | ||
|
|
7cbbd02973 | ||
|
|
b2e1e553e4 | ||
|
|
699e1962b1 | ||
|
|
e486b902b1 | ||
|
|
0ab5b41c4b | ||
|
|
d10a478cce | ||
|
|
ec1020b165 | ||
|
|
4082ebad1a | ||
|
|
da8ea06074 | ||
|
|
7f9dccb293 | ||
|
|
8e4a77aba0 | ||
|
|
8fd8a776c9 | ||
|
|
eec92c242c | ||
|
|
42a739d34c | ||
|
|
f362bef43d | ||
|
|
f5ce539de9 | ||
|
|
4f699afe7a | ||
|
|
6caab1aa37 | ||
|
|
9baaa2b8f8 | ||
|
|
7f376b4f45 | ||
|
|
32cdccde12 | ||
|
|
99c7c3fb14 | ||
|
|
cbd851d00e | ||
|
|
09e7b660f4 | ||
|
|
f463ea1c5d | ||
|
|
1dd69912b1 | ||
|
|
1fbb0d8e7d | ||
|
|
9ee3f1ff36 | ||
|
|
d052d74ac4 | ||
|
|
df91c4c57a | ||
|
|
2aaaa7872f | ||
|
|
b5999583d6 | ||
|
|
69dfd8c60e | ||
|
|
8e50dd9fa6 | ||
|
|
68c03051ad | ||
|
|
a837294b11 | ||
|
|
f1c0cc8076 | ||
|
|
6dec7ff8ba | ||
|
|
20fdbff964 | ||
|
|
e426680cb0 | ||
|
|
7863e97cb0 | ||
|
|
c4dea0ee28 | ||
|
|
e0b6a01e9d | ||
|
|
e509ffa716 | ||
|
|
714c68b548 | ||
|
|
fec197d9ec | ||
|
|
a4b2feef79 | ||
|
|
ad7d9d1ce0 | ||
|
|
86f9544910 | ||
|
|
e9ecbd44fc |
2
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
2
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
@@ -22,7 +22,7 @@ body:
|
||||
id: log
|
||||
attributes:
|
||||
label: Log file
|
||||
description: A log file will help our developers to better diagnose and fix the issue.
|
||||
description: "A log file will help our developers to better diagnose and fix the issue. UPLOAD THE FILE. DO NOT COPY AND PASTE THE FILE'S CONTENT."
|
||||
placeholder: Logs files can be found under "Logs" folder in Ryujinx program folder. They can also be accessed by opening Ryujinx, then going to File > Open Logs Folder. You can drag and drop the log on to the text area (do not copy paste).
|
||||
validations:
|
||||
required: true
|
||||
|
||||
4
.github/workflows/build.yml
vendored
4
.github/workflows/build.yml
vendored
@@ -129,11 +129,11 @@ jobs:
|
||||
with:
|
||||
global-json-file: global.json
|
||||
|
||||
- name: Setup LLVM 14
|
||||
- name: Setup LLVM 17
|
||||
run: |
|
||||
wget https://apt.llvm.org/llvm.sh
|
||||
chmod +x llvm.sh
|
||||
sudo ./llvm.sh 14
|
||||
sudo ./llvm.sh 17
|
||||
|
||||
- name: Install rcodesign
|
||||
run: |
|
||||
|
||||
81
.github/workflows/canary.yml
vendored
81
.github/workflows/canary.yml
vendored
@@ -108,6 +108,7 @@ jobs:
|
||||
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_TARGET_RELEASE_CHANNEL_SOURCE_REPO\%\%/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_SOURCE_REPO }}/g;' src/Ryujinx.Common/ReleaseInformation.cs
|
||||
sed -r --in-place 's/\%\%RYUJINX_CONFIG_FILE_NAME\%\%/Config\.json/g;' src/Ryujinx.Common/ReleaseInformation.cs
|
||||
sed -r --in-place '/^Name=Ryujinx$/s/Name=Ryujinx/Name=Ryujinx-Canary/' distribution/linux/Ryujinx.desktop
|
||||
shell: bash
|
||||
|
||||
- name: Create output dir
|
||||
@@ -115,71 +116,69 @@ jobs:
|
||||
|
||||
- name: Publish
|
||||
run: |
|
||||
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
|
||||
dotnet publish -c Release -r "${{ matrix.platform.name }}" -o ./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
|
||||
|
||||
- name: Packing Windows builds
|
||||
if: matrix.platform.os == 'windows-latest'
|
||||
run: |
|
||||
pushd publish_ava
|
||||
rm publish/libarmeilleure-jitsupport.dylib
|
||||
7z a ../release_output/ryujinx-canary-${{ steps.version_info.outputs.build_version }}-${{ matrix.platform.zip_os_name }}.zip publish
|
||||
pushd publish
|
||||
rm libarmeilleure-jitsupport.dylib
|
||||
7z a ../release_output/ryujinx-canary-${{ steps.version_info.outputs.build_version }}-${{ matrix.platform.zip_os_name }}.zip ../publish
|
||||
popd
|
||||
shell: bash
|
||||
|
||||
- name: Packing Linux builds
|
||||
if: matrix.platform.os == 'ubuntu-latest'
|
||||
run: |
|
||||
pushd publish_ava
|
||||
rm publish/libarmeilleure-jitsupport.dylib
|
||||
chmod +x publish/Ryujinx.sh publish/Ryujinx
|
||||
tar -czvf ../release_output/ryujinx-canary-${{ steps.version_info.outputs.build_version }}-${{ matrix.platform.zip_os_name }}.tar.gz publish
|
||||
pushd publish
|
||||
rm libarmeilleure-jitsupport.dylib
|
||||
chmod +x Ryujinx.sh Ryujinx
|
||||
tar -czvf ../release_output/ryujinx-canary-${{ steps.version_info.outputs.build_version }}-${{ matrix.platform.zip_os_name }}.tar.gz ../publish
|
||||
popd
|
||||
shell: bash
|
||||
|
||||
#- name: Build AppImage (Linux)
|
||||
# if: matrix.platform.os == 'ubuntu-latest'
|
||||
# run: |
|
||||
# BUILD_VERSION="${{ steps.version_info.outputs.build_version }}"
|
||||
# PLATFORM_NAME="${{ matrix.platform.name }}"
|
||||
- name: Build AppImage (Linux)
|
||||
if: matrix.platform.os == 'ubuntu-latest'
|
||||
run: |
|
||||
BUILD_VERSION="${{ steps.version_info.outputs.build_version }}"
|
||||
PLATFORM_NAME="${{ matrix.platform.name }}"
|
||||
|
||||
# sudo apt install -y zsync desktop-file-utils appstream
|
||||
sudo apt install -y zsync desktop-file-utils appstream
|
||||
|
||||
# mkdir -p tools
|
||||
# export PATH="$PATH:$(readlink -f tools)"
|
||||
mkdir -p tools
|
||||
export PATH="$PATH:$(readlink -f tools)"
|
||||
|
||||
# Setup appimagetool
|
||||
# wget -q -O tools/appimagetool "https://github.com/AppImage/appimagetool/releases/download/continuous/appimagetool-x86_64.AppImage"
|
||||
# chmod +x tools/appimagetool
|
||||
# chmod +x distribution/linux/appimage/build-appimage.sh
|
||||
wget -q -O tools/appimagetool "https://github.com/AppImage/appimagetool/releases/download/continuous/appimagetool-x86_64.AppImage"
|
||||
chmod +x tools/appimagetool
|
||||
chmod +x distribution/linux/appimage/build-appimage.sh
|
||||
|
||||
# Explicitly set $ARCH for appimagetool ($ARCH_NAME is for the file name)
|
||||
# if [ "$PLATFORM_NAME" = "linux-x64" ]; then
|
||||
# ARCH_NAME=x64
|
||||
# export ARCH=x86_64
|
||||
# elif [ "$PLATFORM_NAME" = "linux-arm64" ]; then
|
||||
# ARCH_NAME=arm64
|
||||
# export ARCH=aarch64
|
||||
# else
|
||||
# echo "Unexpected PLATFORM_NAME "$PLATFORM_NAME""
|
||||
# exit 1
|
||||
# fi
|
||||
if [ "$PLATFORM_NAME" = "linux-x64" ]; then
|
||||
ARCH_NAME=x64
|
||||
export ARCH=x86_64
|
||||
elif [ "$PLATFORM_NAME" = "linux-arm64" ]; then
|
||||
ARCH_NAME=arm64
|
||||
export ARCH=aarch64
|
||||
else
|
||||
echo "Unexpected PLATFORM_NAME "$PLATFORM_NAME""
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# export UFLAG="gh-releases-zsync|${{ github.repository_owner }}|${{ github.event.repository.name }}|latest|*-$ARCH_NAME.AppImage.zsync"
|
||||
# BUILDDIR=publish_ava OUTDIR=publish_ava_appimage distribution/linux/appimage/build-appimage.sh
|
||||
export UFLAG="gh-releases-zsync|${{ github.repository_owner }}|Canary-Releases|latest|*-$ARCH_NAME.AppImage.zsync"
|
||||
BUILDDIR=publish OUTDIR=publish_appimage distribution/linux/appimage/build-appimage.sh
|
||||
|
||||
# Add to release output
|
||||
# pushd publish_ava_appimage
|
||||
# mv Ryujinx.AppImage ../release_output/ryujinx-$BUILD_VERSION-$ARCH_NAME.AppImage
|
||||
# mv Ryujinx.AppImage.zsync ../release_output/ryujinx-$BUILD_VERSION-$ARCH_NAME.AppImage.zsync
|
||||
# popd
|
||||
# shell: bash
|
||||
pushd publish_appimage
|
||||
mv Ryujinx.AppImage ../release_output/ryujinx-canary-$BUILD_VERSION-$ARCH_NAME.AppImage
|
||||
mv Ryujinx.AppImage.zsync ../release_output/ryujinx-canary-$BUILD_VERSION-$ARCH_NAME.AppImage.zsync
|
||||
popd
|
||||
shell: bash
|
||||
|
||||
- name: Pushing new release
|
||||
uses: ncipollo/release-action@v1
|
||||
with:
|
||||
name: ${{ steps.version_info.outputs.build_version }}
|
||||
artifacts: "release_output/*.tar.gz,release_output/*.zip"
|
||||
#artifacts: "release_output/*.tar.gz,release_output/*.zip,release_output/*AppImage*"
|
||||
artifacts: "release_output/*.tar.gz,release_output/*.zip,release_output/*AppImage*"
|
||||
tag: ${{ steps.version_info.outputs.build_version }}
|
||||
body: |
|
||||
# Canary builds:
|
||||
@@ -211,11 +210,11 @@ jobs:
|
||||
with:
|
||||
global-json-file: global.json
|
||||
|
||||
- name: Setup LLVM 15
|
||||
- name: Setup LLVM 17
|
||||
run: |
|
||||
wget https://apt.llvm.org/llvm.sh
|
||||
chmod +x llvm.sh
|
||||
sudo ./llvm.sh 15
|
||||
sudo ./llvm.sh 17
|
||||
|
||||
- name: Install rcodesign
|
||||
run: |
|
||||
|
||||
4
.github/workflows/nightly_pr_comment.yml
vendored
4
.github/workflows/nightly_pr_comment.yml
vendored
@@ -40,8 +40,8 @@ jobs:
|
||||
let body = `Download the artifacts for this pull request:\n`;
|
||||
let hidden_debug_artifacts = `\n\n <details><summary>Only for Developers</summary>\n`;
|
||||
for (const art of artifacts) {
|
||||
const url = `https://github.com/Ryubing/Ryujinx/actions/runs/${run_id}/artifacts/${art.id}`;
|
||||
if(art.name.includes('Debug')) {
|
||||
const url = `https://nightly.link/${owner}/${repo}/actions/artifacts/${art.id}.zip`;
|
||||
if (art.name.includes('Debug')) {
|
||||
hidden_debug_artifacts += `\n* [${art.name}](${url})`;
|
||||
} else {
|
||||
body += `\n* [${art.name}](${url})`;
|
||||
|
||||
32
.github/workflows/release.yml
vendored
32
.github/workflows/release.yml
vendored
@@ -3,16 +3,6 @@ name: Release job
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs: {}
|
||||
push:
|
||||
branches: [ release ]
|
||||
paths-ignore:
|
||||
- '.github/**'
|
||||
- 'docs/**'
|
||||
- 'assets/**'
|
||||
- '*.yml'
|
||||
- '*.json'
|
||||
- '*.config'
|
||||
- '*.md'
|
||||
|
||||
concurrency: release
|
||||
|
||||
@@ -121,6 +111,15 @@ jobs:
|
||||
7z a ../release_output/ryujinx-${{ steps.version_info.outputs.build_version }}-${{ matrix.platform.zip_os_name }}.zip ../publish
|
||||
popd
|
||||
shell: bash
|
||||
|
||||
- name: Packing Linux builds
|
||||
if: matrix.platform.os == 'ubuntu-latest'
|
||||
run: |
|
||||
pushd publish
|
||||
chmod +x Ryujinx.sh Ryujinx
|
||||
tar -czvf ../release_output/ryujinx-${{ steps.version_info.outputs.build_version }}-${{ matrix.platform.zip_os_name }}.tar.gz ../publish
|
||||
popd
|
||||
shell: bash
|
||||
|
||||
- name: Build AppImage (Linux)
|
||||
if: matrix.platform.os == 'ubuntu-latest'
|
||||
@@ -157,15 +156,6 @@ jobs:
|
||||
mv Ryujinx.AppImage ../release_output/ryujinx-$BUILD_VERSION-$ARCH_NAME.AppImage
|
||||
mv Ryujinx.AppImage.zsync ../release_output/ryujinx-$BUILD_VERSION-$ARCH_NAME.AppImage.zsync
|
||||
popd
|
||||
shell: bash
|
||||
|
||||
- name: Packing Linux builds
|
||||
if: matrix.platform.os == 'ubuntu-latest'
|
||||
run: |
|
||||
pushd publish
|
||||
chmod +x Ryujinx.sh Ryujinx
|
||||
tar -czvf ../release_output/ryujinx-${{ steps.version_info.outputs.build_version }}-${{ matrix.platform.zip_os_name }}.tar.gz ../publish
|
||||
popd
|
||||
shell: bash
|
||||
|
||||
- name: Pushing new release
|
||||
@@ -201,11 +191,11 @@ jobs:
|
||||
with:
|
||||
global-json-file: global.json
|
||||
|
||||
- name: Setup LLVM 15
|
||||
- name: Setup LLVM 17
|
||||
run: |
|
||||
wget https://apt.llvm.org/llvm.sh
|
||||
chmod +x llvm.sh
|
||||
sudo ./llvm.sh 15
|
||||
sudo ./llvm.sh 17
|
||||
|
||||
- name: Install rcodesign
|
||||
run: |
|
||||
|
||||
@@ -3,21 +3,22 @@
|
||||
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<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="Avalonia" Version="11.0.13" />
|
||||
<PackageVersion Include="Avalonia.Controls.DataGrid" Version="11.0.13" />
|
||||
<PackageVersion Include="Avalonia.Desktop" Version="11.0.13" />
|
||||
<PackageVersion Include="Avalonia.Diagnostics" Version="11.0.13" />
|
||||
<PackageVersion Include="Avalonia.Markup.Xaml.Loader" Version="11.0.13" />
|
||||
<PackageVersion Include="Avalonia.Svg" Version="11.0.0.19" />
|
||||
<PackageVersion Include="Avalonia.Svg.Skia" Version="11.0.0.19" />
|
||||
<PackageVersion Include="Microsoft.Build.Framework" Version="17.11.4" />
|
||||
<PackageVersion Include="Microsoft.Build.Utilities.Core" Version="17.12.6" />
|
||||
<PackageVersion Include="Newtonsoft.Json" Version="13.0.3" />
|
||||
<PackageVersion Include="Projektanker.Icons.Avalonia" Version="9.4.0" />
|
||||
<PackageVersion Include="Projektanker.Icons.Avalonia.FontAwesome" Version="9.4.0"/>
|
||||
<PackageVersion Include="Projektanker.Icons.Avalonia.MaterialDesign" Version="9.4.0"/>
|
||||
<PackageVersion Include="Projektanker.Icons.Avalonia.FontAwesome" Version="9.4.0" />
|
||||
<PackageVersion Include="Projektanker.Icons.Avalonia.MaterialDesign" Version="9.4.0" />
|
||||
<PackageVersion Include="CommandLineParser" Version="2.9.1" />
|
||||
<PackageVersion Include="Concentus" Version="2.2.0" />
|
||||
<PackageVersion Include="CommunityToolkit.Mvvm" Version="8.4.0" />
|
||||
<PackageVersion Include="Concentus" Version="2.2.2" />
|
||||
<PackageVersion Include="DiscordRichPresence" Version="1.2.1.24" />
|
||||
<PackageVersion Include="DynamicData" Version="9.0.4" />
|
||||
<PackageVersion Include="FluentAvaloniaUI" Version="2.0.5" />
|
||||
@@ -25,7 +26,7 @@
|
||||
<PackageVersion Include="LibHac" Version="0.19.0" />
|
||||
<PackageVersion Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.4" />
|
||||
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp" Version="4.9.2" />
|
||||
<PackageVersion Include="Microsoft.IdentityModel.JsonWebTokens" Version="8.1.2" />
|
||||
<PackageVersion Include="Microsoft.IdentityModel.JsonWebTokens" Version="8.3.0" />
|
||||
<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" />
|
||||
@@ -40,20 +41,20 @@
|
||||
<PackageVersion Include="Ryujinx.Audio.OpenAL.Dependencies" Version="1.21.0.1" />
|
||||
<PackageVersion Include="Ryujinx.Graphics.Nvdec.Dependencies" Version="5.0.3-build14" />
|
||||
<PackageVersion Include="Ryujinx.Graphics.Vulkan.Dependencies.MoltenVK" Version="1.2.0" />
|
||||
<PackageVersion Include="Ryujinx.SDL2-CS" Version="2.30.0-build32" />
|
||||
<PackageVersion Include="Gommon" Version="2.6.8" />
|
||||
<PackageVersion Include="Gommon" Version="2.7.0.2" />
|
||||
<PackageVersion Include="securifybv.ShellLink" Version="0.1.0" />
|
||||
<PackageVersion Include="Sep" Version="0.6.0" />
|
||||
<PackageVersion Include="shaderc.net" Version="0.1.0" />
|
||||
<PackageVersion Include="SharpMetal" Version="1.0.0-preview21" />
|
||||
<PackageVersion Include="SharpZipLib" Version="1.4.2" />
|
||||
<PackageVersion Include="Silk.NET.Vulkan" Version="2.21.0" />
|
||||
<PackageVersion Include="Silk.NET.Vulkan.Extensions.EXT" Version="2.21.0" />
|
||||
<PackageVersion Include="Silk.NET.Vulkan.Extensions.KHR" Version="2.21.0" />
|
||||
<PackageVersion Include="SkiaSharp" Version="2.88.7" />
|
||||
<PackageVersion Include="SkiaSharp.NativeAssets.Linux" Version="2.88.7" />
|
||||
<PackageVersion Include="Silk.NET.Vulkan" Version="2.22.0" />
|
||||
<PackageVersion Include="Silk.NET.Vulkan.Extensions.EXT" Version="2.22.0" />
|
||||
<PackageVersion Include="Silk.NET.Vulkan.Extensions.KHR" Version="2.22.0" />
|
||||
<PackageVersion Include="SkiaSharp" Version="2.88.9" />
|
||||
<PackageVersion Include="SkiaSharp.NativeAssets.Linux" Version="2.88.9" />
|
||||
<PackageVersion Include="SPB" Version="0.0.4-build32" />
|
||||
<PackageVersion Include="System.IO.Hashing" Version="9.0.0" />
|
||||
<PackageVersion Include="System.Management" Version="9.0.0" />
|
||||
<PackageVersion Include="UnicornEngine.Unicorn" Version="2.0.2-rc1-fb78016" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
</Project>
|
||||
38
Ryujinx.sln
38
Ryujinx.sln
@@ -61,8 +61,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Graphics.Nvdec.FFmp
|
||||
EndProject
|
||||
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}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Horizon.Generators", "src\Ryujinx.Horizon.Generators\Ryujinx.Horizon.Generators.csproj", "{6AE2A5E8-4C5A-48B9-997B-E1455C0355C6}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Graphics.Vulkan", "src\Ryujinx.Graphics.Vulkan\Ryujinx.Graphics.Vulkan.csproj", "{D4D09B08-D580-4D69-B886-C35D2853F6C8}"
|
||||
@@ -97,6 +95,14 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
|
||||
.github\workflows\release.yml = .github\workflows\release.yml
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ryujinx.SDL3.Common", "src\Ryujinx.SDL3.Common\Ryujinx.SDL3.Common.csproj", "{7C70B441-F3D1-41FE-A648-19014BFB88D9}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ryujinx.Input.SDL3", "src\Ryujinx.Input.SDL3\Ryujinx.Input.SDL3.csproj", "{7420A718-7E3C-42B5-82EA-74F6BEE0F1FB}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ryujinx.SDL3-CS", "src\Ryujinx.SDL3-CS\Ryujinx.SDL3-CS.csproj", "{ED2A7EA4-4098-47ED-BA87-EDB3537CFC10}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ryujinx.Audio.Backends.SDL3", "src\Ryujinx.Audio.Backends.SDL3\Ryujinx.Audio.Backends.SDL3.csproj", "{027A38DC-774D-4CF7-A1C0-C510BFC4BD29}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
@@ -200,15 +206,12 @@ Global
|
||||
{C16F112F-38C3-40BC-9F5F-4791112063D6}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{C16F112F-38C3-40BC-9F5F-4791112063D6}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{DFAB6F2D-B9BF-4AFF-B22B-7684A328EBA3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{DFAB6F2D-B9BF-4AFF-B22B-7684A328EBA3}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{DFAB6F2D-B9BF-4AFF-B22B-7684A328EBA3}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{DFAB6F2D-B9BF-4AFF-B22B-7684A328EBA3}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{2D5D3A1D-5730-4648-B0AB-06C53CB910C0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{2D5D3A1D-5730-4648-B0AB-06C53CB910C0}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{2D5D3A1D-5730-4648-B0AB-06C53CB910C0}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{2D5D3A1D-5730-4648-B0AB-06C53CB910C0}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{D99A395A-8569-4DB0-B336-900647890052}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{D99A395A-8569-4DB0-B336-900647890052}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{D99A395A-8569-4DB0-B336-900647890052}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{D99A395A-8569-4DB0-B336-900647890052}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{BEE1C184-C9A4-410B-8DFC-FB74D5C93AEB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
@@ -219,10 +222,6 @@ Global
|
||||
{7C1B2721-13DA-4B62-B046-C626605ECCE6}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{7C1B2721-13DA-4B62-B046-C626605ECCE6}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{7C1B2721-13DA-4B62-B046-C626605ECCE6}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{BA161CA0-CD65-4E6E-B644-51C8D1E542DC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{BA161CA0-CD65-4E6E-B644-51C8D1E542DC}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{BA161CA0-CD65-4E6E-B644-51C8D1E542DC}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{BA161CA0-CD65-4E6E-B644-51C8D1E542DC}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{6AE2A5E8-4C5A-48B9-997B-E1455C0355C6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{6AE2A5E8-4C5A-48B9-997B-E1455C0355C6}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{6AE2A5E8-4C5A-48B9-997B-E1455C0355C6}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
@@ -255,17 +254,32 @@ Global
|
||||
{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
|
||||
{4A89A234-4F19-497D-A576-DDE8CDFC5B22}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{4A89A234-4F19-497D-A576-DDE8CDFC5B22}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{4A89A234-4F19-497D-A576-DDE8CDFC5B22}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{C08931FA-1191-417A-864F-3882D93E683B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{C08931FA-1191-417A-864F-3882D93E683B}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{C08931FA-1191-417A-864F-3882D93E683B}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{C08931FA-1191-417A-864F-3882D93E683B}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{4A89A234-4F19-497D-A576-DDE8CDFC5B22}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{4A89A234-4F19-497D-A576-DDE8CDFC5B22}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{81EA598C-DBA1-40B0-8DA4-4796B78F2037}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{81EA598C-DBA1-40B0-8DA4-4796B78F2037}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{81EA598C-DBA1-40B0-8DA4-4796B78F2037}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{81EA598C-DBA1-40B0-8DA4-4796B78F2037}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{7C70B441-F3D1-41FE-A648-19014BFB88D9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{7C70B441-F3D1-41FE-A648-19014BFB88D9}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{7C70B441-F3D1-41FE-A648-19014BFB88D9}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{7C70B441-F3D1-41FE-A648-19014BFB88D9}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{7420A718-7E3C-42B5-82EA-74F6BEE0F1FB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{7420A718-7E3C-42B5-82EA-74F6BEE0F1FB}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{7420A718-7E3C-42B5-82EA-74F6BEE0F1FB}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{7420A718-7E3C-42B5-82EA-74F6BEE0F1FB}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{ED2A7EA4-4098-47ED-BA87-EDB3537CFC10}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{ED2A7EA4-4098-47ED-BA87-EDB3537CFC10}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{ED2A7EA4-4098-47ED-BA87-EDB3537CFC10}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{ED2A7EA4-4098-47ED-BA87-EDB3537CFC10}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{027A38DC-774D-4CF7-A1C0-C510BFC4BD29}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{027A38DC-774D-4CF7-A1C0-C510BFC4BD29}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{027A38DC-774D-4CF7-A1C0-C510BFC4BD29}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{027A38DC-774D-4CF7-A1C0-C510BFC4BD29}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
||||
@@ -6,14 +6,14 @@ cd "$ROOTDIR"
|
||||
|
||||
BUILDDIR=${BUILDDIR:-publish}
|
||||
OUTDIR=${OUTDIR:-publish_appimage}
|
||||
UFLAG=${UFLAG:-"gh-releases-zsync|GreemDev|ryujinx|latest|*-x64.AppImage.zsync"}
|
||||
UFLAG=${UFLAG:-"gh-releases-zsync|Ryubing|ryujinx|latest|*-x64.AppImage.zsync"}
|
||||
|
||||
rm -rf AppDir
|
||||
mkdir -p AppDir/usr/bin
|
||||
|
||||
cp distribution/linux/Ryujinx.desktop AppDir/Ryujinx.desktop
|
||||
cp distribution/linux/appimage/AppRun AppDir/AppRun
|
||||
cp src/Ryujinx.UI.Common/Resources/Logo_Ryujinx.png AppDir/Ryujinx.svg
|
||||
cp distribution/misc/Logo.svg AppDir/Ryujinx.svg
|
||||
|
||||
|
||||
cp -r "$BUILDDIR"/* AppDir/usr/bin/
|
||||
|
||||
@@ -19,7 +19,7 @@ if platform.system() == "Darwin":
|
||||
else:
|
||||
OTOOL = shutil.which("llvm-otool")
|
||||
if OTOOL is None:
|
||||
for llvm_ver in [15, 14, 13]:
|
||||
for llvm_ver in [17, 16, 15, 14, 13]:
|
||||
otool_path = shutil.which(f"llvm-otool-{llvm_ver}")
|
||||
if otool_path is not None:
|
||||
OTOOL = otool_path
|
||||
|
||||
@@ -26,7 +26,7 @@ else:
|
||||
LIPO = shutil.which("llvm-lipo")
|
||||
|
||||
if LIPO is None:
|
||||
for llvm_ver in [15, 14, 13]:
|
||||
for llvm_ver in [17, 16, 15, 14, 13]:
|
||||
lipo_path = shutil.which(f"llvm-lipo-{llvm_ver}")
|
||||
if lipo_path is not None:
|
||||
LIPO = lipo_path
|
||||
|
||||
@@ -67,11 +67,11 @@ python3 "$BASE_DIR/distribution/macos/construct_universal_dylib.py" "$ARM64_APP_
|
||||
|
||||
if ! [ -x "$(command -v lipo)" ];
|
||||
then
|
||||
if ! [ -x "$(command -v llvm-lipo-14)" ];
|
||||
if ! [ -x "$(command -v llvm-lipo-17)" ];
|
||||
then
|
||||
LIPO=llvm-lipo
|
||||
else
|
||||
LIPO=llvm-lipo-14
|
||||
LIPO=llvm-lipo-17
|
||||
fi
|
||||
else
|
||||
LIPO=lipo
|
||||
|
||||
@@ -62,11 +62,11 @@ python3 "$BASE_DIR/distribution/macos/construct_universal_dylib.py" "$ARM64_OUTP
|
||||
|
||||
if ! [ -x "$(command -v lipo)" ];
|
||||
then
|
||||
if ! [ -x "$(command -v llvm-lipo-14)" ];
|
||||
if ! [ -x "$(command -v llvm-lipo-17)" ];
|
||||
then
|
||||
LIPO=llvm-lipo
|
||||
else
|
||||
LIPO=llvm-lipo-14
|
||||
LIPO=llvm-lipo-17
|
||||
fi
|
||||
else
|
||||
LIPO=lipo
|
||||
|
||||
3424
docs/compatibility.csv
Normal file
3424
docs/compatibility.csv
Normal file
File diff suppressed because it is too large
Load Diff
@@ -406,7 +406,7 @@ namespace ARMeilleure.Instructions
|
||||
{
|
||||
Operand res = EmitSoftFloatCall(context, nameof(SoftFloat32.FPSub), op1, op2);
|
||||
|
||||
return EmitUnaryMathCall(context, nameof(Math.Abs), res);
|
||||
return EmitUnaryMathCall(context, nameof(MathHelper.Abs), res);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -451,7 +451,7 @@ namespace ARMeilleure.Instructions
|
||||
{
|
||||
Operand res = EmitSoftFloatCall(context, nameof(SoftFloat32.FPSub), op1, op2);
|
||||
|
||||
return EmitUnaryMathCall(context, nameof(Math.Abs), res);
|
||||
return EmitUnaryMathCall(context, nameof(MathHelper.Abs), res);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -483,7 +483,7 @@ namespace ARMeilleure.Instructions
|
||||
{
|
||||
EmitScalarUnaryOpF(context, (op1) =>
|
||||
{
|
||||
return EmitUnaryMathCall(context, nameof(Math.Abs), op1);
|
||||
return EmitUnaryMathCall(context, nameof(MathHelper.Abs), op1);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -522,7 +522,7 @@ namespace ARMeilleure.Instructions
|
||||
{
|
||||
EmitVectorUnaryOpF(context, (op1) =>
|
||||
{
|
||||
return EmitUnaryMathCall(context, nameof(Math.Abs), op1);
|
||||
return EmitUnaryMathCall(context, nameof(MathHelper.Abs), op1);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -2246,7 +2246,7 @@ namespace ARMeilleure.Instructions
|
||||
{
|
||||
EmitScalarUnaryOpF(context, (op1) =>
|
||||
{
|
||||
return EmitUnaryMathCall(context, nameof(Math.Floor), op1);
|
||||
return EmitUnaryMathCall(context, nameof(MathHelper.Floor), op1);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -2265,7 +2265,7 @@ namespace ARMeilleure.Instructions
|
||||
{
|
||||
EmitVectorUnaryOpF(context, (op1) =>
|
||||
{
|
||||
return EmitUnaryMathCall(context, nameof(Math.Floor), op1);
|
||||
return EmitUnaryMathCall(context, nameof(MathHelper.Floor), op1);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -2322,7 +2322,7 @@ namespace ARMeilleure.Instructions
|
||||
{
|
||||
EmitScalarUnaryOpF(context, (op1) =>
|
||||
{
|
||||
return EmitUnaryMathCall(context, nameof(Math.Ceiling), op1);
|
||||
return EmitUnaryMathCall(context, nameof(MathHelper.Ceiling), op1);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -2341,7 +2341,7 @@ namespace ARMeilleure.Instructions
|
||||
{
|
||||
EmitVectorUnaryOpF(context, (op1) =>
|
||||
{
|
||||
return EmitUnaryMathCall(context, nameof(Math.Ceiling), op1);
|
||||
return EmitUnaryMathCall(context, nameof(MathHelper.Ceiling), op1);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -2390,7 +2390,7 @@ namespace ARMeilleure.Instructions
|
||||
{
|
||||
EmitScalarUnaryOpF(context, (op1) =>
|
||||
{
|
||||
return EmitUnaryMathCall(context, nameof(Math.Truncate), op1);
|
||||
return EmitUnaryMathCall(context, nameof(MathHelper.Truncate), op1);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -2409,7 +2409,7 @@ namespace ARMeilleure.Instructions
|
||||
{
|
||||
EmitVectorUnaryOpF(context, (op1) =>
|
||||
{
|
||||
return EmitUnaryMathCall(context, nameof(Math.Truncate), op1);
|
||||
return EmitUnaryMathCall(context, nameof(MathHelper.Truncate), op1);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,7 +43,7 @@ namespace ARMeilleure.Instructions
|
||||
}
|
||||
else
|
||||
{
|
||||
EmitScalarUnaryOpF32(context, (op1) => EmitUnaryMathCall(context, nameof(Math.Abs), op1));
|
||||
EmitScalarUnaryOpF32(context, (op1) => EmitUnaryMathCall(context, nameof(MathHelper.Abs), op1));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -66,7 +66,7 @@ namespace ARMeilleure.Instructions
|
||||
}
|
||||
else
|
||||
{
|
||||
EmitVectorUnaryOpF32(context, (op1) => EmitUnaryMathCall(context, nameof(Math.Abs), op1));
|
||||
EmitVectorUnaryOpF32(context, (op1) => EmitUnaryMathCall(context, nameof(MathHelper.Abs), op1));
|
||||
}
|
||||
}
|
||||
else
|
||||
|
||||
@@ -726,8 +726,8 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
if (absolute)
|
||||
{
|
||||
ne = EmitUnaryMathCall(context, nameof(Math.Abs), ne);
|
||||
me = EmitUnaryMathCall(context, nameof(Math.Abs), me);
|
||||
ne = EmitUnaryMathCall(context, nameof(MathHelper.Abs), ne);
|
||||
me = EmitUnaryMathCall(context, nameof(MathHelper.Abs), me);
|
||||
}
|
||||
|
||||
Operand e = EmitSoftFloatCall(context, name, ne, me);
|
||||
|
||||
@@ -333,7 +333,7 @@ namespace ARMeilleure.Instructions
|
||||
}
|
||||
else
|
||||
{
|
||||
EmitFcvt_s_Gp(context, (op1) => EmitUnaryMathCall(context, nameof(Math.Floor), op1));
|
||||
EmitFcvt_s_Gp(context, (op1) => EmitUnaryMathCall(context, nameof(MathHelper.Floor), op1));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -349,7 +349,7 @@ namespace ARMeilleure.Instructions
|
||||
}
|
||||
else
|
||||
{
|
||||
EmitFcvt(context, (op1) => EmitUnaryMathCall(context, nameof(Math.Floor), op1), signed: true, scalar: false);
|
||||
EmitFcvt(context, (op1) => EmitUnaryMathCall(context, nameof(MathHelper.Floor), op1), signed: true, scalar: false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -365,7 +365,7 @@ namespace ARMeilleure.Instructions
|
||||
}
|
||||
else
|
||||
{
|
||||
EmitFcvt_u_Gp(context, (op1) => EmitUnaryMathCall(context, nameof(Math.Floor), op1));
|
||||
EmitFcvt_u_Gp(context, (op1) => EmitUnaryMathCall(context, nameof(MathHelper.Floor), op1));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -538,7 +538,7 @@ namespace ARMeilleure.Instructions
|
||||
}
|
||||
else
|
||||
{
|
||||
EmitFcvt_s_Gp(context, (op1) => EmitUnaryMathCall(context, nameof(Math.Ceiling), op1));
|
||||
EmitFcvt_s_Gp(context, (op1) => EmitUnaryMathCall(context, nameof(MathHelper.Ceiling), op1));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -554,7 +554,7 @@ namespace ARMeilleure.Instructions
|
||||
}
|
||||
else
|
||||
{
|
||||
EmitFcvt_u_Gp(context, (op1) => EmitUnaryMathCall(context, nameof(Math.Ceiling), op1));
|
||||
EmitFcvt_u_Gp(context, (op1) => EmitUnaryMathCall(context, nameof(MathHelper.Ceiling), op1));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -357,10 +357,10 @@ namespace ARMeilleure.Instructions
|
||||
toConvert = EmitRoundMathCall(context, MidpointRounding.ToEven, toConvert);
|
||||
break;
|
||||
case 0b10: // Towards positive infinity
|
||||
toConvert = EmitUnaryMathCall(context, nameof(Math.Ceiling), toConvert);
|
||||
toConvert = EmitUnaryMathCall(context, nameof(MathHelper.Ceiling), toConvert);
|
||||
break;
|
||||
case 0b11: // Towards negative infinity
|
||||
toConvert = EmitUnaryMathCall(context, nameof(Math.Floor), toConvert);
|
||||
toConvert = EmitUnaryMathCall(context, nameof(MathHelper.Floor), toConvert);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -494,10 +494,10 @@ namespace ARMeilleure.Instructions
|
||||
toConvert = EmitRoundMathCall(context, MidpointRounding.ToEven, toConvert);
|
||||
break;
|
||||
case 0b10: // Towards positive infinity
|
||||
toConvert = EmitUnaryMathCall(context, nameof(Math.Ceiling), toConvert);
|
||||
toConvert = EmitUnaryMathCall(context, nameof(MathHelper.Ceiling), toConvert);
|
||||
break;
|
||||
case 0b11: // Towards negative infinity
|
||||
toConvert = EmitUnaryMathCall(context, nameof(Math.Floor), toConvert);
|
||||
toConvert = EmitUnaryMathCall(context, nameof(MathHelper.Floor), toConvert);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -534,7 +534,7 @@ namespace ARMeilleure.Instructions
|
||||
}
|
||||
else
|
||||
{
|
||||
EmitVectorUnaryOpF32(context, (m) => EmitUnaryMathCall(context, nameof(Math.Floor), m));
|
||||
EmitVectorUnaryOpF32(context, (m) => EmitUnaryMathCall(context, nameof(MathHelper.Floor), m));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -574,7 +574,7 @@ namespace ARMeilleure.Instructions
|
||||
}
|
||||
else
|
||||
{
|
||||
EmitVectorUnaryOpF32(context, (m) => EmitUnaryMathCall(context, nameof(Math.Ceiling), m));
|
||||
EmitVectorUnaryOpF32(context, (m) => EmitUnaryMathCall(context, nameof(MathHelper.Ceiling), m));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -613,7 +613,7 @@ namespace ARMeilleure.Instructions
|
||||
}
|
||||
else
|
||||
{
|
||||
EmitScalarUnaryOpF32(context, (op1) => EmitUnaryMathCall(context, nameof(Math.Truncate), op1));
|
||||
EmitScalarUnaryOpF32(context, (op1) => EmitUnaryMathCall(context, nameof(MathHelper.Truncate), op1));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -460,8 +460,8 @@ namespace ARMeilleure.Instructions
|
||||
IOpCodeSimd op = (IOpCodeSimd)context.CurrOp;
|
||||
|
||||
MethodInfo info = (op.Size & 1) == 0
|
||||
? typeof(MathF).GetMethod(name, new Type[] { typeof(float) })
|
||||
: typeof(Math).GetMethod(name, new Type[] { typeof(double) });
|
||||
? typeof(MathHelperF).GetMethod(name, new Type[] { typeof(float) })
|
||||
: typeof(MathHelper).GetMethod(name, new Type[] { typeof(double) });
|
||||
|
||||
return context.Call(info, n);
|
||||
}
|
||||
@@ -470,11 +470,11 @@ namespace ARMeilleure.Instructions
|
||||
{
|
||||
IOpCodeSimd op = (IOpCodeSimd)context.CurrOp;
|
||||
|
||||
string name = nameof(Math.Round);
|
||||
string name = nameof(MathHelper.Round);
|
||||
|
||||
MethodInfo info = (op.Size & 1) == 0
|
||||
? typeof(MathF).GetMethod(name, new Type[] { typeof(float), typeof(MidpointRounding) })
|
||||
: typeof(Math).GetMethod(name, new Type[] { typeof(double), typeof(MidpointRounding) });
|
||||
? typeof(MathHelperF).GetMethod(name, new Type[] { typeof(float), typeof(int) })
|
||||
: typeof(MathHelper).GetMethod(name, new Type[] { typeof(double), typeof(int) });
|
||||
|
||||
return context.Call(info, n, Const((int)roundMode));
|
||||
}
|
||||
@@ -510,16 +510,16 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
context.MarkLabel(lbl1);
|
||||
context.BranchIf(lbl2, rMode, rP, Comparison.NotEqual);
|
||||
context.Copy(res, EmitUnaryMathCall(context, nameof(Math.Ceiling), op));
|
||||
context.Copy(res, EmitUnaryMathCall(context, nameof(MathHelper.Ceiling), op));
|
||||
context.Branch(lblEnd);
|
||||
|
||||
context.MarkLabel(lbl2);
|
||||
context.BranchIf(lbl3, rMode, rM, Comparison.NotEqual);
|
||||
context.Copy(res, EmitUnaryMathCall(context, nameof(Math.Floor), op));
|
||||
context.Copy(res, EmitUnaryMathCall(context, nameof(MathHelper.Floor), op));
|
||||
context.Branch(lblEnd);
|
||||
|
||||
context.MarkLabel(lbl3);
|
||||
context.Copy(res, EmitUnaryMathCall(context, nameof(Math.Truncate), op));
|
||||
context.Copy(res, EmitUnaryMathCall(context, nameof(MathHelper.Truncate), op));
|
||||
context.Branch(lblEnd);
|
||||
|
||||
context.MarkLabel(lblEnd);
|
||||
|
||||
71
src/ARMeilleure/Instructions/MathHelper.cs
Normal file
71
src/ARMeilleure/Instructions/MathHelper.cs
Normal file
@@ -0,0 +1,71 @@
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace ARMeilleure.Instructions
|
||||
{
|
||||
static class MathHelper
|
||||
{
|
||||
[UnmanagedCallersOnly]
|
||||
public static double Abs(double value)
|
||||
{
|
||||
return Math.Abs(value);
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
public static double Ceiling(double value)
|
||||
{
|
||||
return Math.Ceiling(value);
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
public static double Floor(double value)
|
||||
{
|
||||
return Math.Floor(value);
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
public static double Round(double value, int mode)
|
||||
{
|
||||
return Math.Round(value, (MidpointRounding)mode);
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
public static double Truncate(double value)
|
||||
{
|
||||
return Math.Truncate(value);
|
||||
}
|
||||
}
|
||||
|
||||
static class MathHelperF
|
||||
{
|
||||
[UnmanagedCallersOnly]
|
||||
public static float Abs(float value)
|
||||
{
|
||||
return MathF.Abs(value);
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
public static float Ceiling(float value)
|
||||
{
|
||||
return MathF.Ceiling(value);
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
public static float Floor(float value)
|
||||
{
|
||||
return MathF.Floor(value);
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
public static float Round(float value, int mode)
|
||||
{
|
||||
return MathF.Round(value, (MidpointRounding)mode);
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
public static float Truncate(float value)
|
||||
{
|
||||
return MathF.Truncate(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@ using ARMeilleure.Memory;
|
||||
using ARMeilleure.State;
|
||||
using ARMeilleure.Translation;
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace ARMeilleure.Instructions
|
||||
{
|
||||
@@ -34,6 +35,7 @@ namespace ARMeilleure.Instructions
|
||||
Context = null;
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
public static void Break(ulong address, int imm)
|
||||
{
|
||||
Statistics.PauseTimer();
|
||||
@@ -43,6 +45,7 @@ namespace ARMeilleure.Instructions
|
||||
Statistics.ResumeTimer();
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
public static void SupervisorCall(ulong address, int imm)
|
||||
{
|
||||
Statistics.PauseTimer();
|
||||
@@ -52,6 +55,7 @@ namespace ARMeilleure.Instructions
|
||||
Statistics.ResumeTimer();
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
public static void Undefined(ulong address, int opCode)
|
||||
{
|
||||
Statistics.PauseTimer();
|
||||
@@ -62,26 +66,31 @@ namespace ARMeilleure.Instructions
|
||||
}
|
||||
|
||||
#region "System registers"
|
||||
[UnmanagedCallersOnly]
|
||||
public static ulong GetCtrEl0()
|
||||
{
|
||||
return GetContext().CtrEl0;
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
public static ulong GetDczidEl0()
|
||||
{
|
||||
return GetContext().DczidEl0;
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
public static ulong GetCntfrqEl0()
|
||||
{
|
||||
return GetContext().CntfrqEl0;
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
public static ulong GetCntpctEl0()
|
||||
{
|
||||
return GetContext().CntpctEl0;
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
public static ulong GetCntvctEl0()
|
||||
{
|
||||
return GetContext().CntvctEl0;
|
||||
@@ -89,26 +98,31 @@ namespace ARMeilleure.Instructions
|
||||
#endregion
|
||||
|
||||
#region "Read"
|
||||
[UnmanagedCallersOnly]
|
||||
public static byte ReadByte(ulong address)
|
||||
{
|
||||
return GetMemoryManager().ReadGuest<byte>(address);
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
public static ushort ReadUInt16(ulong address)
|
||||
{
|
||||
return GetMemoryManager().ReadGuest<ushort>(address);
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
public static uint ReadUInt32(ulong address)
|
||||
{
|
||||
return GetMemoryManager().ReadGuest<uint>(address);
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
public static ulong ReadUInt64(ulong address)
|
||||
{
|
||||
return GetMemoryManager().ReadGuest<ulong>(address);
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
public static V128 ReadVector128(ulong address)
|
||||
{
|
||||
return GetMemoryManager().ReadGuest<V128>(address);
|
||||
@@ -116,47 +130,56 @@ namespace ARMeilleure.Instructions
|
||||
#endregion
|
||||
|
||||
#region "Write"
|
||||
[UnmanagedCallersOnly]
|
||||
public static void WriteByte(ulong address, byte value)
|
||||
{
|
||||
GetMemoryManager().WriteGuest(address, value);
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
public static void WriteUInt16(ulong address, ushort value)
|
||||
{
|
||||
GetMemoryManager().WriteGuest(address, value);
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
public static void WriteUInt32(ulong address, uint value)
|
||||
{
|
||||
GetMemoryManager().WriteGuest(address, value);
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
public static void WriteUInt64(ulong address, ulong value)
|
||||
{
|
||||
GetMemoryManager().WriteGuest(address, value);
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
public static void WriteVector128(ulong address, V128 value)
|
||||
{
|
||||
GetMemoryManager().WriteGuest(address, value);
|
||||
}
|
||||
#endregion
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
public static void EnqueueForRejit(ulong address)
|
||||
{
|
||||
Context.Translator.EnqueueForRejit(address, GetContext().ExecutionMode);
|
||||
}
|
||||
|
||||
public static void SignalMemoryTracking(ulong address, ulong size, bool write)
|
||||
[UnmanagedCallersOnly]
|
||||
public static void SignalMemoryTracking(ulong address, ulong size, byte write)
|
||||
{
|
||||
GetMemoryManager().SignalMemoryTracking(address, size, write);
|
||||
GetMemoryManager().SignalMemoryTracking(address, size, write == 1);
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
public static void ThrowInvalidMemoryAccess(ulong address)
|
||||
{
|
||||
throw new InvalidAccessException(address);
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
public static ulong GetFunctionAddress(ulong address)
|
||||
{
|
||||
TranslatedFunction function = Context.Translator.GetOrTranslate(address, GetContext().ExecutionMode);
|
||||
@@ -164,12 +187,14 @@ namespace ARMeilleure.Instructions
|
||||
return (ulong)function.FuncPointer.ToInt64();
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
public static void InvalidateCacheLine(ulong address)
|
||||
{
|
||||
Context.Translator.InvalidateJitCacheRegion(address, InstEmit.DczSizeInBytes);
|
||||
}
|
||||
|
||||
public static bool CheckSynchronization()
|
||||
[UnmanagedCallersOnly]
|
||||
public static byte CheckSynchronization()
|
||||
{
|
||||
Statistics.PauseTimer();
|
||||
|
||||
@@ -179,7 +204,7 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
Statistics.ResumeTimer();
|
||||
|
||||
return context.Running;
|
||||
return (byte)(context.Running ? 1 : 0);
|
||||
}
|
||||
|
||||
public static ExecutionContext GetContext()
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
using ARMeilleure.State;
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace ARMeilleure.Instructions
|
||||
{
|
||||
static class SoftFallback
|
||||
{
|
||||
#region "ShrImm64"
|
||||
[UnmanagedCallersOnly]
|
||||
public static long SignedShrImm64(long value, long roundConst, int shift)
|
||||
{
|
||||
if (roundConst == 0L)
|
||||
@@ -48,6 +50,7 @@ namespace ARMeilleure.Instructions
|
||||
}
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
public static ulong UnsignedShrImm64(ulong value, long roundConst, int shift)
|
||||
{
|
||||
if (roundConst == 0L)
|
||||
@@ -92,6 +95,7 @@ namespace ARMeilleure.Instructions
|
||||
#endregion
|
||||
|
||||
#region "Saturation"
|
||||
[UnmanagedCallersOnly]
|
||||
public static int SatF32ToS32(float value)
|
||||
{
|
||||
if (float.IsNaN(value))
|
||||
@@ -103,6 +107,7 @@ namespace ARMeilleure.Instructions
|
||||
value <= int.MinValue ? int.MinValue : (int)value;
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
public static long SatF32ToS64(float value)
|
||||
{
|
||||
if (float.IsNaN(value))
|
||||
@@ -114,6 +119,7 @@ namespace ARMeilleure.Instructions
|
||||
value <= long.MinValue ? long.MinValue : (long)value;
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
public static uint SatF32ToU32(float value)
|
||||
{
|
||||
if (float.IsNaN(value))
|
||||
@@ -125,6 +131,7 @@ namespace ARMeilleure.Instructions
|
||||
value <= uint.MinValue ? uint.MinValue : (uint)value;
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
public static ulong SatF32ToU64(float value)
|
||||
{
|
||||
if (float.IsNaN(value))
|
||||
@@ -136,6 +143,7 @@ namespace ARMeilleure.Instructions
|
||||
value <= ulong.MinValue ? ulong.MinValue : (ulong)value;
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
public static int SatF64ToS32(double value)
|
||||
{
|
||||
if (double.IsNaN(value))
|
||||
@@ -147,6 +155,7 @@ namespace ARMeilleure.Instructions
|
||||
value <= int.MinValue ? int.MinValue : (int)value;
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
public static long SatF64ToS64(double value)
|
||||
{
|
||||
if (double.IsNaN(value))
|
||||
@@ -158,6 +167,7 @@ namespace ARMeilleure.Instructions
|
||||
value <= long.MinValue ? long.MinValue : (long)value;
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
public static uint SatF64ToU32(double value)
|
||||
{
|
||||
if (double.IsNaN(value))
|
||||
@@ -169,6 +179,7 @@ namespace ARMeilleure.Instructions
|
||||
value <= uint.MinValue ? uint.MinValue : (uint)value;
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
public static ulong SatF64ToU64(double value)
|
||||
{
|
||||
if (double.IsNaN(value))
|
||||
@@ -182,6 +193,7 @@ namespace ARMeilleure.Instructions
|
||||
#endregion
|
||||
|
||||
#region "Count"
|
||||
[UnmanagedCallersOnly]
|
||||
public static ulong CountLeadingSigns(ulong value, int size) // size is 8, 16, 32 or 64 (SIMD&FP or Base Inst.).
|
||||
{
|
||||
value ^= value >> 1;
|
||||
@@ -201,6 +213,7 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
private static ReadOnlySpan<byte> ClzNibbleTbl => new byte[] { 4, 3, 2, 2, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0 };
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
public static ulong CountLeadingZeros(ulong value, int size) // size is 8, 16, 32 or 64 (SIMD&FP or Base Inst.).
|
||||
{
|
||||
if (value == 0ul)
|
||||
@@ -224,41 +237,49 @@ namespace ARMeilleure.Instructions
|
||||
#endregion
|
||||
|
||||
#region "Table"
|
||||
[UnmanagedCallersOnly]
|
||||
public static V128 Tbl1(V128 vector, int bytes, V128 tb0)
|
||||
{
|
||||
return TblOrTbx(default, vector, bytes, tb0);
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
public static V128 Tbl2(V128 vector, int bytes, V128 tb0, V128 tb1)
|
||||
{
|
||||
return TblOrTbx(default, vector, bytes, tb0, tb1);
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
public static V128 Tbl3(V128 vector, int bytes, V128 tb0, V128 tb1, V128 tb2)
|
||||
{
|
||||
return TblOrTbx(default, vector, bytes, tb0, tb1, tb2);
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
public static V128 Tbl4(V128 vector, int bytes, V128 tb0, V128 tb1, V128 tb2, V128 tb3)
|
||||
{
|
||||
return TblOrTbx(default, vector, bytes, tb0, tb1, tb2, tb3);
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
public static V128 Tbx1(V128 dest, V128 vector, int bytes, V128 tb0)
|
||||
{
|
||||
return TblOrTbx(dest, vector, bytes, tb0);
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
public static V128 Tbx2(V128 dest, V128 vector, int bytes, V128 tb0, V128 tb1)
|
||||
{
|
||||
return TblOrTbx(dest, vector, bytes, tb0, tb1);
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
public static V128 Tbx3(V128 dest, V128 vector, int bytes, V128 tb0, V128 tb1, V128 tb2)
|
||||
{
|
||||
return TblOrTbx(dest, vector, bytes, tb0, tb1, tb2);
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
public static V128 Tbx4(V128 dest, V128 vector, int bytes, V128 tb0, V128 tb1, V128 tb2, V128 tb3)
|
||||
{
|
||||
return TblOrTbx(dest, vector, bytes, tb0, tb1, tb2, tb3);
|
||||
@@ -300,14 +321,22 @@ namespace ARMeilleure.Instructions
|
||||
private const uint Crc32RevPoly = 0xedb88320;
|
||||
private const uint Crc32cRevPoly = 0x82f63b78;
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
public static uint Crc32b(uint crc, byte value) => Crc32(crc, Crc32RevPoly, value);
|
||||
[UnmanagedCallersOnly]
|
||||
public static uint Crc32h(uint crc, ushort value) => Crc32h(crc, Crc32RevPoly, value);
|
||||
[UnmanagedCallersOnly]
|
||||
public static uint Crc32w(uint crc, uint value) => Crc32w(crc, Crc32RevPoly, value);
|
||||
[UnmanagedCallersOnly]
|
||||
public static uint Crc32x(uint crc, ulong value) => Crc32x(crc, Crc32RevPoly, value);
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
public static uint Crc32cb(uint crc, byte value) => Crc32(crc, Crc32cRevPoly, value);
|
||||
[UnmanagedCallersOnly]
|
||||
public static uint Crc32ch(uint crc, ushort value) => Crc32h(crc, Crc32cRevPoly, value);
|
||||
[UnmanagedCallersOnly]
|
||||
public static uint Crc32cw(uint crc, uint value) => Crc32w(crc, Crc32cRevPoly, value);
|
||||
[UnmanagedCallersOnly]
|
||||
public static uint Crc32cx(uint crc, ulong value) => Crc32x(crc, Crc32cRevPoly, value);
|
||||
|
||||
private static uint Crc32h(uint crc, uint poly, ushort val)
|
||||
@@ -358,21 +387,25 @@ namespace ARMeilleure.Instructions
|
||||
#endregion
|
||||
|
||||
#region "Aes"
|
||||
[UnmanagedCallersOnly]
|
||||
public static V128 Decrypt(V128 value, V128 roundKey)
|
||||
{
|
||||
return CryptoHelper.AesInvSubBytes(CryptoHelper.AesInvShiftRows(value ^ roundKey));
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
public static V128 Encrypt(V128 value, V128 roundKey)
|
||||
{
|
||||
return CryptoHelper.AesSubBytes(CryptoHelper.AesShiftRows(value ^ roundKey));
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
public static V128 InverseMixColumns(V128 value)
|
||||
{
|
||||
return CryptoHelper.AesInvMixColumns(value);
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
public static V128 MixColumns(V128 value)
|
||||
{
|
||||
return CryptoHelper.AesMixColumns(value);
|
||||
@@ -380,6 +413,7 @@ namespace ARMeilleure.Instructions
|
||||
#endregion
|
||||
|
||||
#region "Sha1"
|
||||
[UnmanagedCallersOnly]
|
||||
public static V128 HashChoose(V128 hash_abcd, uint hash_e, V128 wk)
|
||||
{
|
||||
for (int e = 0; e <= 3; e++)
|
||||
@@ -400,11 +434,13 @@ namespace ARMeilleure.Instructions
|
||||
return hash_abcd;
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
public static uint FixedRotate(uint hash_e)
|
||||
{
|
||||
return hash_e.Rol(30);
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
public static V128 HashMajority(V128 hash_abcd, uint hash_e, V128 wk)
|
||||
{
|
||||
for (int e = 0; e <= 3; e++)
|
||||
@@ -425,6 +461,7 @@ namespace ARMeilleure.Instructions
|
||||
return hash_abcd;
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
public static V128 HashParity(V128 hash_abcd, uint hash_e, V128 wk)
|
||||
{
|
||||
for (int e = 0; e <= 3; e++)
|
||||
@@ -445,6 +482,7 @@ namespace ARMeilleure.Instructions
|
||||
return hash_abcd;
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
public static V128 Sha1SchedulePart1(V128 w0_3, V128 w4_7, V128 w8_11)
|
||||
{
|
||||
ulong t2 = w4_7.Extract<ulong>(0);
|
||||
@@ -455,6 +493,7 @@ namespace ARMeilleure.Instructions
|
||||
return result ^ (w0_3 ^ w8_11);
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
public static V128 Sha1SchedulePart2(V128 tw0_3, V128 w12_15)
|
||||
{
|
||||
V128 t = tw0_3 ^ (w12_15 >> 32);
|
||||
@@ -499,16 +538,19 @@ namespace ARMeilleure.Instructions
|
||||
#endregion
|
||||
|
||||
#region "Sha256"
|
||||
[UnmanagedCallersOnly]
|
||||
public static V128 HashLower(V128 hash_abcd, V128 hash_efgh, V128 wk)
|
||||
{
|
||||
return Sha256Hash(hash_abcd, hash_efgh, wk, part1: true);
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
public static V128 HashUpper(V128 hash_abcd, V128 hash_efgh, V128 wk)
|
||||
{
|
||||
return Sha256Hash(hash_abcd, hash_efgh, wk, part1: false);
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
public static V128 Sha256SchedulePart1(V128 w0_3, V128 w4_7)
|
||||
{
|
||||
V128 result = new();
|
||||
@@ -527,6 +569,7 @@ namespace ARMeilleure.Instructions
|
||||
return result;
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
public static V128 Sha256SchedulePart2(V128 w0_3, V128 w8_11, V128 w12_15)
|
||||
{
|
||||
V128 result = new();
|
||||
@@ -628,6 +671,7 @@ namespace ARMeilleure.Instructions
|
||||
}
|
||||
#endregion
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
public static V128 PolynomialMult64_128(ulong op1, ulong op2)
|
||||
{
|
||||
V128 result = V128.Zero;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using ARMeilleure.State;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace ARMeilleure.Instructions
|
||||
{
|
||||
@@ -312,6 +313,7 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
static class SoftFloat16_32
|
||||
{
|
||||
[UnmanagedCallersOnly]
|
||||
public static float FPConvert(ushort valueBits)
|
||||
{
|
||||
ExecutionContext context = NativeInterface.GetContext();
|
||||
@@ -487,6 +489,7 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
static class SoftFloat16_64
|
||||
{
|
||||
[UnmanagedCallersOnly]
|
||||
public static double FPConvert(ushort valueBits)
|
||||
{
|
||||
ExecutionContext context = NativeInterface.GetContext();
|
||||
@@ -662,6 +665,7 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
static class SoftFloat32_16
|
||||
{
|
||||
[UnmanagedCallersOnly]
|
||||
public static ushort FPConvert(float value)
|
||||
{
|
||||
ExecutionContext context = NativeInterface.GetContext();
|
||||
@@ -781,12 +785,19 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
static class SoftFloat32
|
||||
{
|
||||
[UnmanagedCallersOnly]
|
||||
public static float FPAdd(float value1, float value2)
|
||||
{
|
||||
return FPAddFpscr(value1, value2, false);
|
||||
return FPAddFpscrImpl(value1, value2, false);
|
||||
}
|
||||
|
||||
public static float FPAddFpscr(float value1, float value2, bool standardFpscr)
|
||||
[UnmanagedCallersOnly]
|
||||
public static float FPAddFpscr(float value1, float value2, byte standardFpscr)
|
||||
{
|
||||
return FPAddFpscrImpl(value1, value2, standardFpscr == 1);
|
||||
}
|
||||
|
||||
private static float FPAddFpscrImpl(float value1, float value2, bool standardFpscr)
|
||||
{
|
||||
ExecutionContext context = NativeInterface.GetContext();
|
||||
FPCR fpcr = standardFpscr ? context.StandardFpcrValue : context.Fpcr;
|
||||
@@ -837,7 +848,8 @@ namespace ARMeilleure.Instructions
|
||||
return result;
|
||||
}
|
||||
|
||||
public static int FPCompare(float value1, float value2, bool signalNaNs)
|
||||
[UnmanagedCallersOnly]
|
||||
public static int FPCompare(float value1, float value2, byte signalNaNs)
|
||||
{
|
||||
ExecutionContext context = NativeInterface.GetContext();
|
||||
FPCR fpcr = context.Fpcr;
|
||||
@@ -851,7 +863,7 @@ namespace ARMeilleure.Instructions
|
||||
{
|
||||
result = 0b0011;
|
||||
|
||||
if (type1 == FPType.SNaN || type2 == FPType.SNaN || signalNaNs)
|
||||
if (type1 == FPType.SNaN || type2 == FPType.SNaN || signalNaNs == 1)
|
||||
{
|
||||
SoftFloat.FPProcessException(FPException.InvalidOp, context, fpcr);
|
||||
}
|
||||
@@ -875,12 +887,13 @@ namespace ARMeilleure.Instructions
|
||||
return result;
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
public static float FPCompareEQ(float value1, float value2)
|
||||
{
|
||||
return FPCompareEQFpscr(value1, value2, false);
|
||||
return FPCompareEQFpscrImpl(value1, value2, false);
|
||||
}
|
||||
|
||||
public static float FPCompareEQFpscr(float value1, float value2, bool standardFpscr)
|
||||
private static float FPCompareEQFpscrImpl(float value1, float value2, bool standardFpscr)
|
||||
{
|
||||
ExecutionContext context = NativeInterface.GetContext();
|
||||
FPCR fpcr = standardFpscr ? context.StandardFpcrValue : context.Fpcr;
|
||||
@@ -907,12 +920,25 @@ namespace ARMeilleure.Instructions
|
||||
return result;
|
||||
}
|
||||
|
||||
public static float FPCompareGE(float value1, float value2)
|
||||
[UnmanagedCallersOnly]
|
||||
public static float FPCompareEQFpscr(float value1, float value2, byte standardFpscr)
|
||||
{
|
||||
return FPCompareGEFpscr(value1, value2, false);
|
||||
return FPCompareEQFpscrImpl(value1, value2, standardFpscr == 1);
|
||||
}
|
||||
|
||||
public static float FPCompareGEFpscr(float value1, float value2, bool standardFpscr)
|
||||
[UnmanagedCallersOnly]
|
||||
public static float FPCompareGE(float value1, float value2)
|
||||
{
|
||||
return FPCompareGEFpscrImpl(value1, value2, false);
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
public static float FPCompareGEFpscr(float value1, float value2, byte standardFpscr)
|
||||
{
|
||||
return FPCompareGEFpscrImpl(value1, value2, standardFpscr == 1);
|
||||
}
|
||||
|
||||
private static float FPCompareGEFpscrImpl(float value1, float value2, bool standardFpscr)
|
||||
{
|
||||
ExecutionContext context = NativeInterface.GetContext();
|
||||
FPCR fpcr = standardFpscr ? context.StandardFpcrValue : context.Fpcr;
|
||||
@@ -936,12 +962,19 @@ namespace ARMeilleure.Instructions
|
||||
return result;
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
public static float FPCompareGT(float value1, float value2)
|
||||
{
|
||||
return FPCompareGTFpscr(value1, value2, false);
|
||||
return FPCompareGTFpscrImpl(value1, value2, false);
|
||||
}
|
||||
|
||||
public static float FPCompareGTFpscr(float value1, float value2, bool standardFpscr)
|
||||
[UnmanagedCallersOnly]
|
||||
public static float FPCompareGTFpscr(float value1, float value2, byte standardFpscr)
|
||||
{
|
||||
return FPCompareGTFpscrImpl(value1, value2, standardFpscr == 1);
|
||||
}
|
||||
|
||||
private static float FPCompareGTFpscrImpl(float value1, float value2, bool standardFpscr)
|
||||
{
|
||||
ExecutionContext context = NativeInterface.GetContext();
|
||||
FPCR fpcr = standardFpscr ? context.StandardFpcrValue : context.Fpcr;
|
||||
@@ -965,26 +998,31 @@ namespace ARMeilleure.Instructions
|
||||
return result;
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
public static float FPCompareLE(float value1, float value2)
|
||||
{
|
||||
return FPCompareGE(value2, value1);
|
||||
return FPCompareGEFpscrImpl(value2, value1, false);
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
public static float FPCompareLT(float value1, float value2)
|
||||
{
|
||||
return FPCompareGT(value2, value1);
|
||||
return FPCompareGTFpscrImpl(value2, value1, false);
|
||||
}
|
||||
|
||||
public static float FPCompareLEFpscr(float value1, float value2, bool standardFpscr)
|
||||
[UnmanagedCallersOnly]
|
||||
public static float FPCompareLEFpscr(float value1, float value2, byte standardFpscr)
|
||||
{
|
||||
return FPCompareGEFpscr(value2, value1, standardFpscr);
|
||||
return FPCompareGEFpscrImpl(value2, value1, standardFpscr == 1);
|
||||
}
|
||||
|
||||
public static float FPCompareLTFpscr(float value1, float value2, bool standardFpscr)
|
||||
[UnmanagedCallersOnly]
|
||||
public static float FPCompareLTFpscr(float value1, float value2, byte standardFpscr)
|
||||
{
|
||||
return FPCompareGTFpscr(value2, value1, standardFpscr);
|
||||
return FPCompareGEFpscrImpl(value2, value1, standardFpscr == 1);
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
public static float FPDiv(float value1, float value2)
|
||||
{
|
||||
ExecutionContext context = NativeInterface.GetContext();
|
||||
@@ -1037,12 +1075,19 @@ namespace ARMeilleure.Instructions
|
||||
return result;
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
public static float FPMax(float value1, float value2)
|
||||
{
|
||||
return FPMaxFpscr(value1, value2, false);
|
||||
return FPMaxFpscrImpl(value1, value2, false);
|
||||
}
|
||||
|
||||
public static float FPMaxFpscr(float value1, float value2, bool standardFpscr)
|
||||
[UnmanagedCallersOnly]
|
||||
public static float FPMaxFpscr(float value1, float value2, byte standardFpscr)
|
||||
{
|
||||
return FPMaxFpscrImpl(value1, value2, standardFpscr == 1);
|
||||
}
|
||||
|
||||
private static float FPMaxFpscrImpl(float value1, float value2, bool standardFpscr)
|
||||
{
|
||||
ExecutionContext context = NativeInterface.GetContext();
|
||||
FPCR fpcr = standardFpscr ? context.StandardFpcrValue : context.Fpcr;
|
||||
@@ -1103,12 +1148,13 @@ namespace ARMeilleure.Instructions
|
||||
return result;
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
public static float FPMaxNum(float value1, float value2)
|
||||
{
|
||||
return FPMaxNumFpscr(value1, value2, false);
|
||||
return FPMaxNumFpscrImpl(value1, value2, false);
|
||||
}
|
||||
|
||||
public static float FPMaxNumFpscr(float value1, float value2, bool standardFpscr)
|
||||
private static float FPMaxNumFpscrImpl(float value1, float value2, bool standardFpscr)
|
||||
{
|
||||
ExecutionContext context = NativeInterface.GetContext();
|
||||
FPCR fpcr = standardFpscr ? context.StandardFpcrValue : context.Fpcr;
|
||||
@@ -1125,15 +1171,28 @@ namespace ARMeilleure.Instructions
|
||||
value2 = FPInfinity(true);
|
||||
}
|
||||
|
||||
return FPMaxFpscr(value1, value2, standardFpscr);
|
||||
return FPMaxFpscrImpl(value1, value2, standardFpscr);
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
public static float FPMaxNumFpscr(float value1, float value2, byte standardFpscr)
|
||||
{
|
||||
return FPMaxNumFpscrImpl(value1, value2, standardFpscr == 1);
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
public static float FPMin(float value1, float value2)
|
||||
{
|
||||
return FPMinFpscr(value1, value2, false);
|
||||
return FPMinFpscrImpl(value1, value2, false);
|
||||
}
|
||||
|
||||
public static float FPMinFpscr(float value1, float value2, bool standardFpscr)
|
||||
[UnmanagedCallersOnly]
|
||||
public static float FPMinFpscr(float value1, float value2, byte standardFpscr)
|
||||
{
|
||||
return FPMinFpscrImpl(value1, value2, standardFpscr == 1);
|
||||
}
|
||||
|
||||
private static float FPMinFpscrImpl(float value1, float value2, bool standardFpscr)
|
||||
{
|
||||
ExecutionContext context = NativeInterface.GetContext();
|
||||
FPCR fpcr = standardFpscr ? context.StandardFpcrValue : context.Fpcr;
|
||||
@@ -1194,12 +1253,19 @@ namespace ARMeilleure.Instructions
|
||||
return result;
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
public static float FPMinNum(float value1, float value2)
|
||||
{
|
||||
return FPMinNumFpscr(value1, value2, false);
|
||||
return FPMinNumFpscrImpl(value1, value2, false);
|
||||
}
|
||||
|
||||
public static float FPMinNumFpscr(float value1, float value2, bool standardFpscr)
|
||||
[UnmanagedCallersOnly]
|
||||
public static float FPMinNumFpscr(float value1, float value2, byte standardFpscr)
|
||||
{
|
||||
return FPMinNumFpscrImpl(value1, value2, standardFpscr == 1);
|
||||
}
|
||||
|
||||
private static float FPMinNumFpscrImpl(float value1, float value2, bool standardFpscr)
|
||||
{
|
||||
ExecutionContext context = NativeInterface.GetContext();
|
||||
FPCR fpcr = standardFpscr ? context.StandardFpcrValue : context.Fpcr;
|
||||
@@ -1216,15 +1282,22 @@ namespace ARMeilleure.Instructions
|
||||
value2 = FPInfinity(false);
|
||||
}
|
||||
|
||||
return FPMinFpscr(value1, value2, standardFpscr);
|
||||
return FPMinFpscrImpl(value1, value2, standardFpscr);
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
public static float FPMul(float value1, float value2)
|
||||
{
|
||||
return FPMulFpscr(value1, value2, false);
|
||||
return FPMulFpscrImpl(value1, value2, false);
|
||||
}
|
||||
|
||||
public static float FPMulFpscr(float value1, float value2, bool standardFpscr)
|
||||
[UnmanagedCallersOnly]
|
||||
public static float FPMulFpscr(float value1, float value2, byte standardFpscr)
|
||||
{
|
||||
return FPMulFpscrImpl(value1, value2, standardFpscr == 1);
|
||||
}
|
||||
|
||||
private static float FPMulFpscrImpl(float value1, float value2, bool standardFpscr)
|
||||
{
|
||||
ExecutionContext context = NativeInterface.GetContext();
|
||||
FPCR fpcr = standardFpscr ? context.StandardFpcrValue : context.Fpcr;
|
||||
@@ -1271,12 +1344,19 @@ namespace ARMeilleure.Instructions
|
||||
return result;
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
public static float FPMulAdd(float valueA, float value1, float value2)
|
||||
{
|
||||
return FPMulAddFpscr(valueA, value1, value2, false);
|
||||
return FPMulAddFpscrImpl(valueA, value1, value2, false);
|
||||
}
|
||||
|
||||
public static float FPMulAddFpscr(float valueA, float value1, float value2, bool standardFpscr)
|
||||
[UnmanagedCallersOnly]
|
||||
public static float FPMulAddFpscr(float valueA, float value1, float value2, byte standardFpscr)
|
||||
{
|
||||
return FPMulAddFpscrImpl(valueA, value1, value2, standardFpscr == 1);
|
||||
}
|
||||
|
||||
private static float FPMulAddFpscrImpl(float valueA, float value1, float value2, bool standardFpscr)
|
||||
{
|
||||
ExecutionContext context = NativeInterface.GetContext();
|
||||
FPCR fpcr = standardFpscr ? context.StandardFpcrValue : context.Fpcr;
|
||||
@@ -1342,20 +1422,23 @@ namespace ARMeilleure.Instructions
|
||||
return result;
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
public static float FPMulSub(float valueA, float value1, float value2)
|
||||
{
|
||||
value1 = value1.FPNeg();
|
||||
|
||||
return FPMulAdd(valueA, value1, value2);
|
||||
return FPMulAddFpscrImpl(valueA, value1, value2, false);
|
||||
}
|
||||
|
||||
public static float FPMulSubFpscr(float valueA, float value1, float value2, bool standardFpscr)
|
||||
[UnmanagedCallersOnly]
|
||||
public static float FPMulSubFpscr(float valueA, float value1, float value2, byte standardFpscr)
|
||||
{
|
||||
value1 = value1.FPNeg();
|
||||
|
||||
return FPMulAddFpscr(valueA, value1, value2, standardFpscr);
|
||||
return FPMulAddFpscrImpl(valueA, value1, value2, standardFpscr == 1);
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
public static float FPMulX(float value1, float value2)
|
||||
{
|
||||
ExecutionContext context = NativeInterface.GetContext();
|
||||
@@ -1401,27 +1484,36 @@ namespace ARMeilleure.Instructions
|
||||
return result;
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
public static float FPNegMulAdd(float valueA, float value1, float value2)
|
||||
{
|
||||
valueA = valueA.FPNeg();
|
||||
value1 = value1.FPNeg();
|
||||
|
||||
return FPMulAdd(valueA, value1, value2);
|
||||
return FPMulAddFpscrImpl(valueA, value1, value2, false);
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
public static float FPNegMulSub(float valueA, float value1, float value2)
|
||||
{
|
||||
valueA = valueA.FPNeg();
|
||||
|
||||
return FPMulAdd(valueA, value1, value2);
|
||||
return FPMulAddFpscrImpl(valueA, value1, value2, false);
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
public static float FPRecipEstimate(float value)
|
||||
{
|
||||
return FPRecipEstimateFpscr(value, false);
|
||||
return FPRecipEstimateFpscrImpl(value, false);
|
||||
}
|
||||
|
||||
public static float FPRecipEstimateFpscr(float value, bool standardFpscr)
|
||||
[UnmanagedCallersOnly]
|
||||
public static float FPRecipEstimateFpscr(float value, byte standardFpscr)
|
||||
{
|
||||
return FPRecipEstimateFpscrImpl(value, standardFpscr == 1);
|
||||
}
|
||||
|
||||
private static float FPRecipEstimateFpscrImpl(float value, bool standardFpscr)
|
||||
{
|
||||
ExecutionContext context = NativeInterface.GetContext();
|
||||
FPCR fpcr = standardFpscr ? context.StandardFpcrValue : context.Fpcr;
|
||||
@@ -1508,6 +1600,7 @@ namespace ARMeilleure.Instructions
|
||||
return result;
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
public static float FPRecipStep(float value1, float value2)
|
||||
{
|
||||
ExecutionContext context = NativeInterface.GetContext();
|
||||
@@ -1533,15 +1626,16 @@ namespace ARMeilleure.Instructions
|
||||
}
|
||||
else
|
||||
{
|
||||
product = FPMulFpscr(value1, value2, true);
|
||||
product = FPMulFpscrImpl(value1, value2, true);
|
||||
}
|
||||
|
||||
result = FPSubFpscr(FPTwo(false), product, true);
|
||||
result = FPSubFpscrImpl(FPTwo(false), product, true);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
public static float FPRecipStepFused(float value1, float value2)
|
||||
{
|
||||
ExecutionContext context = NativeInterface.GetContext();
|
||||
@@ -1585,6 +1679,7 @@ namespace ARMeilleure.Instructions
|
||||
return result;
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
public static float FPRecpX(float value)
|
||||
{
|
||||
ExecutionContext context = NativeInterface.GetContext();
|
||||
@@ -1610,12 +1705,19 @@ namespace ARMeilleure.Instructions
|
||||
return result;
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
public static float FPRSqrtEstimate(float value)
|
||||
{
|
||||
return FPRSqrtEstimateFpscr(value, false);
|
||||
return FPRSqrtEstimateFpscrImpl(value, false);
|
||||
}
|
||||
|
||||
public static float FPRSqrtEstimateFpscr(float value, bool standardFpscr)
|
||||
[UnmanagedCallersOnly]
|
||||
public static float FPRSqrtEstimateFpscr(float value, byte standardFpscr)
|
||||
{
|
||||
return FPRSqrtEstimateFpscrImpl(value, standardFpscr == 1);
|
||||
}
|
||||
|
||||
private static float FPRSqrtEstimateFpscrImpl(float value, bool standardFpscr)
|
||||
{
|
||||
ExecutionContext context = NativeInterface.GetContext();
|
||||
FPCR fpcr = standardFpscr ? context.StandardFpcrValue : context.Fpcr;
|
||||
@@ -1729,6 +1831,7 @@ namespace ARMeilleure.Instructions
|
||||
return result;
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
public static float FPRSqrtStep(float value1, float value2)
|
||||
{
|
||||
ExecutionContext context = NativeInterface.GetContext();
|
||||
@@ -1754,7 +1857,7 @@ namespace ARMeilleure.Instructions
|
||||
}
|
||||
else
|
||||
{
|
||||
product = FPMulFpscr(value1, value2, true);
|
||||
product = FPMulFpscrImpl(value1, value2, true);
|
||||
}
|
||||
|
||||
result = FPHalvedSub(FPThree(false), product, context, fpcr);
|
||||
@@ -1763,6 +1866,7 @@ namespace ARMeilleure.Instructions
|
||||
return result;
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
public static float FPRSqrtStepFused(float value1, float value2)
|
||||
{
|
||||
ExecutionContext context = NativeInterface.GetContext();
|
||||
@@ -1806,6 +1910,7 @@ namespace ARMeilleure.Instructions
|
||||
return result;
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
public static float FPSqrt(float value)
|
||||
{
|
||||
ExecutionContext context = NativeInterface.GetContext();
|
||||
@@ -1848,12 +1953,13 @@ namespace ARMeilleure.Instructions
|
||||
return result;
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
public static float FPSub(float value1, float value2)
|
||||
{
|
||||
return FPSubFpscr(value1, value2, false);
|
||||
return FPSubFpscrImpl(value1, value2, false);
|
||||
}
|
||||
|
||||
public static float FPSubFpscr(float value1, float value2, bool standardFpscr)
|
||||
private static float FPSubFpscrImpl(float value1, float value2, bool standardFpscr)
|
||||
{
|
||||
ExecutionContext context = NativeInterface.GetContext();
|
||||
FPCR fpcr = standardFpscr ? context.StandardFpcrValue : context.Fpcr;
|
||||
@@ -2094,6 +2200,7 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
static class SoftFloat64_16
|
||||
{
|
||||
[UnmanagedCallersOnly]
|
||||
public static ushort FPConvert(double value)
|
||||
{
|
||||
ExecutionContext context = NativeInterface.GetContext();
|
||||
@@ -2213,12 +2320,19 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
static class SoftFloat64
|
||||
{
|
||||
[UnmanagedCallersOnly]
|
||||
public static double FPAdd(double value1, double value2)
|
||||
{
|
||||
return FPAddFpscr(value1, value2, false);
|
||||
return FPAddFpscrImpl(value1, value2, false);
|
||||
}
|
||||
|
||||
public static double FPAddFpscr(double value1, double value2, bool standardFpscr)
|
||||
[UnmanagedCallersOnly]
|
||||
public static double FPAddFpscr(double value1, double value2, byte standardFpscr)
|
||||
{
|
||||
return FPAddFpscrImpl(value1, value2, standardFpscr == 1);
|
||||
}
|
||||
|
||||
private static double FPAddFpscrImpl(double value1, double value2, bool standardFpscr)
|
||||
{
|
||||
ExecutionContext context = NativeInterface.GetContext();
|
||||
FPCR fpcr = standardFpscr ? context.StandardFpcrValue : context.Fpcr;
|
||||
@@ -2269,7 +2383,8 @@ namespace ARMeilleure.Instructions
|
||||
return result;
|
||||
}
|
||||
|
||||
public static int FPCompare(double value1, double value2, bool signalNaNs)
|
||||
[UnmanagedCallersOnly]
|
||||
public static int FPCompare(double value1, double value2, byte signalNaNs)
|
||||
{
|
||||
ExecutionContext context = NativeInterface.GetContext();
|
||||
FPCR fpcr = context.Fpcr;
|
||||
@@ -2283,7 +2398,7 @@ namespace ARMeilleure.Instructions
|
||||
{
|
||||
result = 0b0011;
|
||||
|
||||
if (type1 == FPType.SNaN || type2 == FPType.SNaN || signalNaNs)
|
||||
if (type1 == FPType.SNaN || type2 == FPType.SNaN || signalNaNs == 1)
|
||||
{
|
||||
SoftFloat.FPProcessException(FPException.InvalidOp, context, fpcr);
|
||||
}
|
||||
@@ -2307,12 +2422,19 @@ namespace ARMeilleure.Instructions
|
||||
return result;
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
public static double FPCompareEQ(double value1, double value2)
|
||||
{
|
||||
return FPCompareEQFpscr(value1, value2, false);
|
||||
return FPCompareEQFpscrImpl(value1, value2, false);
|
||||
}
|
||||
|
||||
public static double FPCompareEQFpscr(double value1, double value2, bool standardFpscr)
|
||||
[UnmanagedCallersOnly]
|
||||
public static double FPCompareEQFpscr(double value1, double value2, byte standardFpscr)
|
||||
{
|
||||
return FPCompareEQFpscrImpl(value1, value2, standardFpscr == 1);
|
||||
}
|
||||
|
||||
private static double FPCompareEQFpscrImpl(double value1, double value2, bool standardFpscr)
|
||||
{
|
||||
ExecutionContext context = NativeInterface.GetContext();
|
||||
FPCR fpcr = standardFpscr ? context.StandardFpcrValue : context.Fpcr;
|
||||
@@ -2339,12 +2461,19 @@ namespace ARMeilleure.Instructions
|
||||
return result;
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
public static double FPCompareGE(double value1, double value2)
|
||||
{
|
||||
return FPCompareGEFpscr(value1, value2, false);
|
||||
return FPCompareGEFpscrImpl(value1, value2, false);
|
||||
}
|
||||
|
||||
public static double FPCompareGEFpscr(double value1, double value2, bool standardFpscr)
|
||||
[UnmanagedCallersOnly]
|
||||
public static double FPCompareGEFpscr(double value1, double value2, byte standardFpscr)
|
||||
{
|
||||
return FPCompareGEFpscrImpl(value1, value2, standardFpscr == 1);
|
||||
}
|
||||
|
||||
private static double FPCompareGEFpscrImpl(double value1, double value2, bool standardFpscr)
|
||||
{
|
||||
ExecutionContext context = NativeInterface.GetContext();
|
||||
FPCR fpcr = standardFpscr ? context.StandardFpcrValue : context.Fpcr;
|
||||
@@ -2368,12 +2497,19 @@ namespace ARMeilleure.Instructions
|
||||
return result;
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
public static double FPCompareGT(double value1, double value2)
|
||||
{
|
||||
return FPCompareGTFpscr(value1, value2, false);
|
||||
return FPCompareGTFpscrImpl(value1, value2, false);
|
||||
}
|
||||
|
||||
public static double FPCompareGTFpscr(double value1, double value2, bool standardFpscr)
|
||||
[UnmanagedCallersOnly]
|
||||
public static double FPCompareGTFpscr(double value1, double value2, byte standardFpscr)
|
||||
{
|
||||
return FPCompareGTFpscrImpl(value1, value2, standardFpscr == 1);
|
||||
}
|
||||
|
||||
private static double FPCompareGTFpscrImpl(double value1, double value2, bool standardFpscr)
|
||||
{
|
||||
ExecutionContext context = NativeInterface.GetContext();
|
||||
FPCR fpcr = standardFpscr ? context.StandardFpcrValue : context.Fpcr;
|
||||
@@ -2397,26 +2533,31 @@ namespace ARMeilleure.Instructions
|
||||
return result;
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
public static double FPCompareLE(double value1, double value2)
|
||||
{
|
||||
return FPCompareGE(value2, value1);
|
||||
return FPCompareGEFpscrImpl(value2, value1, false);
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
public static double FPCompareLT(double value1, double value2)
|
||||
{
|
||||
return FPCompareGT(value2, value1);
|
||||
return FPCompareGTFpscrImpl(value2, value1, false);
|
||||
}
|
||||
|
||||
public static double FPCompareLEFpscr(double value1, double value2, bool standardFpscr)
|
||||
[UnmanagedCallersOnly]
|
||||
public static double FPCompareLEFpscr(double value1, double value2, byte standardFpscr)
|
||||
{
|
||||
return FPCompareGEFpscr(value2, value1, standardFpscr);
|
||||
return FPCompareGEFpscrImpl(value2, value1, standardFpscr == 1);
|
||||
}
|
||||
|
||||
public static double FPCompareLTFpscr(double value1, double value2, bool standardFpscr)
|
||||
[UnmanagedCallersOnly]
|
||||
public static double FPCompareLTFpscr(double value1, double value2, byte standardFpscr)
|
||||
{
|
||||
return FPCompareGTFpscr(value2, value1, standardFpscr);
|
||||
return FPCompareGTFpscrImpl(value2, value1, standardFpscr == 1);
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
public static double FPDiv(double value1, double value2)
|
||||
{
|
||||
ExecutionContext context = NativeInterface.GetContext();
|
||||
@@ -2469,12 +2610,19 @@ namespace ARMeilleure.Instructions
|
||||
return result;
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
public static double FPMax(double value1, double value2)
|
||||
{
|
||||
return FPMaxFpscr(value1, value2, false);
|
||||
return FPMaxFpscrImpl(value1, value2, false);
|
||||
}
|
||||
|
||||
public static double FPMaxFpscr(double value1, double value2, bool standardFpscr)
|
||||
[UnmanagedCallersOnly]
|
||||
public static double FPMaxFpscr(double value1, double value2, byte standardFpscr)
|
||||
{
|
||||
return FPMaxFpscrImpl(value1, value2, standardFpscr == 1);
|
||||
}
|
||||
|
||||
private static double FPMaxFpscrImpl(double value1, double value2, bool standardFpscr)
|
||||
{
|
||||
ExecutionContext context = NativeInterface.GetContext();
|
||||
FPCR fpcr = standardFpscr ? context.StandardFpcrValue : context.Fpcr;
|
||||
@@ -2535,12 +2683,19 @@ namespace ARMeilleure.Instructions
|
||||
return result;
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
public static double FPMaxNum(double value1, double value2)
|
||||
{
|
||||
return FPMaxNumFpscr(value1, value2, false);
|
||||
return FPMaxNumFpscrImpl(value1, value2, false);
|
||||
}
|
||||
|
||||
public static double FPMaxNumFpscr(double value1, double value2, bool standardFpscr)
|
||||
[UnmanagedCallersOnly]
|
||||
public static double FPMaxNumFpscr(double value1, double value2, byte standardFpscr)
|
||||
{
|
||||
return FPMaxNumFpscrImpl(value1, value2, standardFpscr == 1);
|
||||
}
|
||||
|
||||
private static double FPMaxNumFpscrImpl(double value1, double value2, bool standardFpscr)
|
||||
{
|
||||
ExecutionContext context = NativeInterface.GetContext();
|
||||
FPCR fpcr = standardFpscr ? context.StandardFpcrValue : context.Fpcr;
|
||||
@@ -2557,15 +2712,22 @@ namespace ARMeilleure.Instructions
|
||||
value2 = FPInfinity(true);
|
||||
}
|
||||
|
||||
return FPMaxFpscr(value1, value2, standardFpscr);
|
||||
return FPMaxFpscrImpl(value1, value2, standardFpscr);
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
public static double FPMin(double value1, double value2)
|
||||
{
|
||||
return FPMinFpscr(value1, value2, false);
|
||||
return FPMinFpscrImpl(value1, value2, false);
|
||||
}
|
||||
|
||||
public static double FPMinFpscr(double value1, double value2, bool standardFpscr)
|
||||
[UnmanagedCallersOnly]
|
||||
public static double FPMinFpscr(double value1, double value2, byte standardFpscr)
|
||||
{
|
||||
return FPMinFpscrImpl(value1, value2, standardFpscr == 1);
|
||||
}
|
||||
|
||||
private static double FPMinFpscrImpl(double value1, double value2, bool standardFpscr)
|
||||
{
|
||||
ExecutionContext context = NativeInterface.GetContext();
|
||||
FPCR fpcr = standardFpscr ? context.StandardFpcrValue : context.Fpcr;
|
||||
@@ -2626,12 +2788,19 @@ namespace ARMeilleure.Instructions
|
||||
return result;
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
public static double FPMinNum(double value1, double value2)
|
||||
{
|
||||
return FPMinNumFpscr(value1, value2, false);
|
||||
return FPMinNumFpscrImpl(value1, value2, false);
|
||||
}
|
||||
|
||||
public static double FPMinNumFpscr(double value1, double value2, bool standardFpscr)
|
||||
[UnmanagedCallersOnly]
|
||||
public static double FPMinNumFpscr(double value1, double value2, byte standardFpscr)
|
||||
{
|
||||
return FPMinNumFpscrImpl(value1, value2, standardFpscr == 1);
|
||||
}
|
||||
|
||||
private static double FPMinNumFpscrImpl(double value1, double value2, bool standardFpscr)
|
||||
{
|
||||
ExecutionContext context = NativeInterface.GetContext();
|
||||
FPCR fpcr = standardFpscr ? context.StandardFpcrValue : context.Fpcr;
|
||||
@@ -2648,15 +2817,22 @@ namespace ARMeilleure.Instructions
|
||||
value2 = FPInfinity(false);
|
||||
}
|
||||
|
||||
return FPMinFpscr(value1, value2, standardFpscr);
|
||||
return FPMinFpscrImpl(value1, value2, standardFpscr);
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
public static double FPMul(double value1, double value2)
|
||||
{
|
||||
return FPMulFpscr(value1, value2, false);
|
||||
return FPMulFpscrImpl(value1, value2, false);
|
||||
}
|
||||
|
||||
public static double FPMulFpscr(double value1, double value2, bool standardFpscr)
|
||||
[UnmanagedCallersOnly]
|
||||
public static double FPMulFpscr(double value1, double value2, byte standardFpscr)
|
||||
{
|
||||
return FPMulFpscrImpl(value1, value2, standardFpscr == 1);
|
||||
}
|
||||
|
||||
private static double FPMulFpscrImpl(double value1, double value2, bool standardFpscr)
|
||||
{
|
||||
ExecutionContext context = NativeInterface.GetContext();
|
||||
FPCR fpcr = standardFpscr ? context.StandardFpcrValue : context.Fpcr;
|
||||
@@ -2703,12 +2879,19 @@ namespace ARMeilleure.Instructions
|
||||
return result;
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
public static double FPMulAdd(double valueA, double value1, double value2)
|
||||
{
|
||||
return FPMulAddFpscr(valueA, value1, value2, false);
|
||||
return FPMulAddFpscrImpl(valueA, value1, value2, false);
|
||||
}
|
||||
|
||||
public static double FPMulAddFpscr(double valueA, double value1, double value2, bool standardFpscr)
|
||||
[UnmanagedCallersOnly]
|
||||
public static double FPMulAddFpscr(double valueA, double value1, double value2, byte standardFpscr)
|
||||
{
|
||||
return FPMulAddFpscrImpl(valueA, value1, value2, standardFpscr == 1);
|
||||
}
|
||||
|
||||
private static double FPMulAddFpscrImpl(double valueA, double value1, double value2, bool standardFpscr)
|
||||
{
|
||||
ExecutionContext context = NativeInterface.GetContext();
|
||||
FPCR fpcr = standardFpscr ? context.StandardFpcrValue : context.Fpcr;
|
||||
@@ -2774,20 +2957,23 @@ namespace ARMeilleure.Instructions
|
||||
return result;
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
public static double FPMulSub(double valueA, double value1, double value2)
|
||||
{
|
||||
value1 = value1.FPNeg();
|
||||
|
||||
return FPMulAdd(valueA, value1, value2);
|
||||
return FPMulAddFpscrImpl(valueA, value1, value2, false);
|
||||
}
|
||||
|
||||
public static double FPMulSubFpscr(double valueA, double value1, double value2, bool standardFpscr)
|
||||
[UnmanagedCallersOnly]
|
||||
public static double FPMulSubFpscr(double valueA, double value1, double value2, byte standardFpscr)
|
||||
{
|
||||
value1 = value1.FPNeg();
|
||||
|
||||
return FPMulAddFpscr(valueA, value1, value2, standardFpscr);
|
||||
return FPMulAddFpscrImpl(valueA, value1, value2, standardFpscr == 1);
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
public static double FPMulX(double value1, double value2)
|
||||
{
|
||||
ExecutionContext context = NativeInterface.GetContext();
|
||||
@@ -2833,27 +3019,36 @@ namespace ARMeilleure.Instructions
|
||||
return result;
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
public static double FPNegMulAdd(double valueA, double value1, double value2)
|
||||
{
|
||||
valueA = valueA.FPNeg();
|
||||
value1 = value1.FPNeg();
|
||||
|
||||
return FPMulAdd(valueA, value1, value2);
|
||||
return FPMulAddFpscrImpl(valueA, value1, value2, false);
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
public static double FPNegMulSub(double valueA, double value1, double value2)
|
||||
{
|
||||
valueA = valueA.FPNeg();
|
||||
|
||||
return FPMulAdd(valueA, value1, value2);
|
||||
return FPMulAddFpscrImpl(valueA, value1, value2, false);
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
public static double FPRecipEstimate(double value)
|
||||
{
|
||||
return FPRecipEstimateFpscr(value, false);
|
||||
return FPRecipEstimateFpscrImpl(value, false);
|
||||
}
|
||||
|
||||
public static double FPRecipEstimateFpscr(double value, bool standardFpscr)
|
||||
[UnmanagedCallersOnly]
|
||||
public static double FPRecipEstimateFpscr(double value, byte standardFpscr)
|
||||
{
|
||||
return FPRecipEstimateFpscrImpl(value, standardFpscr == 1);
|
||||
}
|
||||
|
||||
private static double FPRecipEstimateFpscrImpl(double value, bool standardFpscr)
|
||||
{
|
||||
ExecutionContext context = NativeInterface.GetContext();
|
||||
FPCR fpcr = standardFpscr ? context.StandardFpcrValue : context.Fpcr;
|
||||
@@ -2940,6 +3135,7 @@ namespace ARMeilleure.Instructions
|
||||
return result;
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
public static double FPRecipStep(double value1, double value2)
|
||||
{
|
||||
ExecutionContext context = NativeInterface.GetContext();
|
||||
@@ -2965,7 +3161,7 @@ namespace ARMeilleure.Instructions
|
||||
}
|
||||
else
|
||||
{
|
||||
product = FPMulFpscr(value1, value2, true);
|
||||
product = FPMulFpscrImpl(value1, value2, true);
|
||||
}
|
||||
|
||||
result = FPSubFpscr(FPTwo(false), product, true);
|
||||
@@ -2974,6 +3170,7 @@ namespace ARMeilleure.Instructions
|
||||
return result;
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
public static double FPRecipStepFused(double value1, double value2)
|
||||
{
|
||||
ExecutionContext context = NativeInterface.GetContext();
|
||||
@@ -3017,6 +3214,7 @@ namespace ARMeilleure.Instructions
|
||||
return result;
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
public static double FPRecpX(double value)
|
||||
{
|
||||
ExecutionContext context = NativeInterface.GetContext();
|
||||
@@ -3042,12 +3240,19 @@ namespace ARMeilleure.Instructions
|
||||
return result;
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
public static double FPRSqrtEstimate(double value)
|
||||
{
|
||||
return FPRSqrtEstimateFpscr(value, false);
|
||||
return FPRSqrtEstimateFpscrImpl(value, false);
|
||||
}
|
||||
|
||||
public static double FPRSqrtEstimateFpscr(double value, bool standardFpscr)
|
||||
[UnmanagedCallersOnly]
|
||||
public static double FPRSqrtEstimateFpscr(double value, byte standardFpscr)
|
||||
{
|
||||
return FPRSqrtEstimateFpscrImpl(value, standardFpscr == 1);
|
||||
}
|
||||
|
||||
private static double FPRSqrtEstimateFpscrImpl(double value, bool standardFpscr)
|
||||
{
|
||||
ExecutionContext context = NativeInterface.GetContext();
|
||||
FPCR fpcr = standardFpscr ? context.StandardFpcrValue : context.Fpcr;
|
||||
@@ -3161,6 +3366,7 @@ namespace ARMeilleure.Instructions
|
||||
return result;
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
public static double FPRSqrtStep(double value1, double value2)
|
||||
{
|
||||
ExecutionContext context = NativeInterface.GetContext();
|
||||
@@ -3186,7 +3392,7 @@ namespace ARMeilleure.Instructions
|
||||
}
|
||||
else
|
||||
{
|
||||
product = FPMulFpscr(value1, value2, true);
|
||||
product = FPMulFpscrImpl(value1, value2, true);
|
||||
}
|
||||
|
||||
result = FPHalvedSub(FPThree(false), product, context, fpcr);
|
||||
@@ -3195,6 +3401,7 @@ namespace ARMeilleure.Instructions
|
||||
return result;
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
public static double FPRSqrtStepFused(double value1, double value2)
|
||||
{
|
||||
ExecutionContext context = NativeInterface.GetContext();
|
||||
@@ -3238,6 +3445,7 @@ namespace ARMeilleure.Instructions
|
||||
return result;
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
public static double FPSqrt(double value)
|
||||
{
|
||||
ExecutionContext context = NativeInterface.GetContext();
|
||||
@@ -3280,6 +3488,7 @@ namespace ARMeilleure.Instructions
|
||||
return result;
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
public static double FPSub(double value1, double value2)
|
||||
{
|
||||
return FPSubFpscr(value1, value2, false);
|
||||
|
||||
@@ -4,15 +4,9 @@ namespace ARMeilleure.Translation
|
||||
{
|
||||
class DelegateInfo
|
||||
{
|
||||
#pragma warning disable IDE0052 // Remove unread private member
|
||||
private readonly Delegate _dlg; // Ensure that this delegate will not be garbage collected.
|
||||
#pragma warning restore IDE0052
|
||||
|
||||
public nint FuncPtr { get; }
|
||||
|
||||
public DelegateInfo(Delegate dlg, nint funcPtr)
|
||||
public nint FuncPtr { get; private set; }
|
||||
public DelegateInfo(nint funcPtr)
|
||||
{
|
||||
_dlg = dlg;
|
||||
FuncPtr = funcPtr;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
using ARMeilleure.Instructions;
|
||||
using ARMeilleure.State;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace ARMeilleure.Translation
|
||||
{
|
||||
@@ -34,21 +32,7 @@ namespace ARMeilleure.Translation
|
||||
|
||||
return _delegates.Values[index].FuncPtr; // O(1).
|
||||
}
|
||||
|
||||
public static nint GetDelegateFuncPtr(MethodInfo info)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(info);
|
||||
|
||||
string key = GetKey(info);
|
||||
|
||||
if (!_delegates.TryGetValue(key, out DelegateInfo dlgInfo)) // O(log(n)).
|
||||
{
|
||||
throw new KeyNotFoundException($"({nameof(key)} = {key})");
|
||||
}
|
||||
|
||||
return dlgInfo.FuncPtr;
|
||||
}
|
||||
|
||||
|
||||
public static int GetDelegateIndex(MethodInfo info)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(info);
|
||||
@@ -64,12 +48,12 @@ namespace ARMeilleure.Translation
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
private static void SetDelegateInfo(Delegate dlg, nint funcPtr)
|
||||
|
||||
private static void SetDelegateInfo(MethodInfo method)
|
||||
{
|
||||
string key = GetKey(dlg.Method);
|
||||
string key = GetKey(method);
|
||||
|
||||
_delegates.Add(key, new DelegateInfo(dlg, funcPtr)); // ArgumentException (key).
|
||||
_delegates.Add(key, new DelegateInfo(method.MethodHandle.GetFunctionPointer())); // ArgumentException (key).
|
||||
}
|
||||
|
||||
private static string GetKey(MethodInfo info)
|
||||
@@ -83,528 +67,179 @@ namespace ARMeilleure.Translation
|
||||
{
|
||||
_delegates = new SortedList<string, DelegateInfo>();
|
||||
|
||||
var dlgMathAbs = new MathAbs(Math.Abs);
|
||||
var dlgMathCeiling = new MathCeiling(Math.Ceiling);
|
||||
var dlgMathFloor = new MathFloor(Math.Floor);
|
||||
var dlgMathRound = new MathRound(Math.Round);
|
||||
var dlgMathTruncate = new MathTruncate(Math.Truncate);
|
||||
SetDelegateInfo(typeof(MathHelper).GetMethod(nameof(MathHelper.Abs)));
|
||||
SetDelegateInfo(typeof(MathHelper).GetMethod(nameof(MathHelper.Ceiling)));
|
||||
SetDelegateInfo(typeof(MathHelper).GetMethod(nameof(MathHelper.Floor)));
|
||||
SetDelegateInfo(typeof(MathHelper).GetMethod(nameof(MathHelper.Round)));
|
||||
SetDelegateInfo(typeof(MathHelper).GetMethod(nameof(MathHelper.Truncate)));
|
||||
|
||||
var dlgMathFAbs = new MathFAbs(MathF.Abs);
|
||||
var dlgMathFCeiling = new MathFCeiling(MathF.Ceiling);
|
||||
var dlgMathFFloor = new MathFFloor(MathF.Floor);
|
||||
var dlgMathFRound = new MathFRound(MathF.Round);
|
||||
var dlgMathFTruncate = new MathFTruncate(MathF.Truncate);
|
||||
SetDelegateInfo(typeof(MathHelperF).GetMethod(nameof(MathHelperF.Abs)));
|
||||
SetDelegateInfo(typeof(MathHelperF).GetMethod(nameof(MathHelperF.Ceiling)));
|
||||
SetDelegateInfo(typeof(MathHelperF).GetMethod(nameof(MathHelperF.Floor)));
|
||||
SetDelegateInfo(typeof(MathHelperF).GetMethod(nameof(MathHelperF.Round)));
|
||||
SetDelegateInfo(typeof(MathHelperF).GetMethod(nameof(MathHelperF.Truncate)));
|
||||
|
||||
var dlgNativeInterfaceBreak = new NativeInterfaceBreak(NativeInterface.Break);
|
||||
var dlgNativeInterfaceCheckSynchronization = new NativeInterfaceCheckSynchronization(NativeInterface.CheckSynchronization);
|
||||
var dlgNativeInterfaceEnqueueForRejit = new NativeInterfaceEnqueueForRejit(NativeInterface.EnqueueForRejit);
|
||||
var dlgNativeInterfaceGetCntfrqEl0 = new NativeInterfaceGetCntfrqEl0(NativeInterface.GetCntfrqEl0);
|
||||
var dlgNativeInterfaceGetCntpctEl0 = new NativeInterfaceGetCntpctEl0(NativeInterface.GetCntpctEl0);
|
||||
var dlgNativeInterfaceGetCntvctEl0 = new NativeInterfaceGetCntvctEl0(NativeInterface.GetCntvctEl0);
|
||||
var dlgNativeInterfaceGetCtrEl0 = new NativeInterfaceGetCtrEl0(NativeInterface.GetCtrEl0);
|
||||
var dlgNativeInterfaceGetDczidEl0 = new NativeInterfaceGetDczidEl0(NativeInterface.GetDczidEl0);
|
||||
var dlgNativeInterfaceGetFunctionAddress = new NativeInterfaceGetFunctionAddress(NativeInterface.GetFunctionAddress);
|
||||
var dlgNativeInterfaceInvalidateCacheLine = new NativeInterfaceInvalidateCacheLine(NativeInterface.InvalidateCacheLine);
|
||||
var dlgNativeInterfaceReadByte = new NativeInterfaceReadByte(NativeInterface.ReadByte);
|
||||
var dlgNativeInterfaceReadUInt16 = new NativeInterfaceReadUInt16(NativeInterface.ReadUInt16);
|
||||
var dlgNativeInterfaceReadUInt32 = new NativeInterfaceReadUInt32(NativeInterface.ReadUInt32);
|
||||
var dlgNativeInterfaceReadUInt64 = new NativeInterfaceReadUInt64(NativeInterface.ReadUInt64);
|
||||
var dlgNativeInterfaceReadVector128 = new NativeInterfaceReadVector128(NativeInterface.ReadVector128);
|
||||
var dlgNativeInterfaceSignalMemoryTracking = new NativeInterfaceSignalMemoryTracking(NativeInterface.SignalMemoryTracking);
|
||||
var dlgNativeInterfaceSupervisorCall = new NativeInterfaceSupervisorCall(NativeInterface.SupervisorCall);
|
||||
var dlgNativeInterfaceThrowInvalidMemoryAccess = new NativeInterfaceThrowInvalidMemoryAccess(NativeInterface.ThrowInvalidMemoryAccess);
|
||||
var dlgNativeInterfaceUndefined = new NativeInterfaceUndefined(NativeInterface.Undefined);
|
||||
var dlgNativeInterfaceWriteByte = new NativeInterfaceWriteByte(NativeInterface.WriteByte);
|
||||
var dlgNativeInterfaceWriteUInt16 = new NativeInterfaceWriteUInt16(NativeInterface.WriteUInt16);
|
||||
var dlgNativeInterfaceWriteUInt32 = new NativeInterfaceWriteUInt32(NativeInterface.WriteUInt32);
|
||||
var dlgNativeInterfaceWriteUInt64 = new NativeInterfaceWriteUInt64(NativeInterface.WriteUInt64);
|
||||
var dlgNativeInterfaceWriteVector128 = new NativeInterfaceWriteVector128(NativeInterface.WriteVector128);
|
||||
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.Break)));
|
||||
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.CheckSynchronization)));
|
||||
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.EnqueueForRejit)));
|
||||
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetCntfrqEl0)));
|
||||
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetCntpctEl0)));
|
||||
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetCntvctEl0)));
|
||||
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetCtrEl0)));
|
||||
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetDczidEl0)));
|
||||
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetFunctionAddress)));
|
||||
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.InvalidateCacheLine)));
|
||||
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.ReadByte)));
|
||||
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.ReadUInt16)));
|
||||
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.ReadUInt32)));
|
||||
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.ReadUInt64)));
|
||||
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.ReadVector128)));
|
||||
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SignalMemoryTracking)));
|
||||
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SupervisorCall)));
|
||||
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.ThrowInvalidMemoryAccess)));
|
||||
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.Undefined)));
|
||||
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.WriteByte)));
|
||||
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.WriteUInt16)));
|
||||
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.WriteUInt32)));
|
||||
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.WriteUInt64)));
|
||||
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.WriteVector128)));
|
||||
|
||||
var dlgSoftFallbackCountLeadingSigns = new SoftFallbackCountLeadingSigns(SoftFallback.CountLeadingSigns);
|
||||
var dlgSoftFallbackCountLeadingZeros = new SoftFallbackCountLeadingZeros(SoftFallback.CountLeadingZeros);
|
||||
var dlgSoftFallbackCrc32b = new SoftFallbackCrc32b(SoftFallback.Crc32b);
|
||||
var dlgSoftFallbackCrc32cb = new SoftFallbackCrc32cb(SoftFallback.Crc32cb);
|
||||
var dlgSoftFallbackCrc32ch = new SoftFallbackCrc32ch(SoftFallback.Crc32ch);
|
||||
var dlgSoftFallbackCrc32cw = new SoftFallbackCrc32cw(SoftFallback.Crc32cw);
|
||||
var dlgSoftFallbackCrc32cx = new SoftFallbackCrc32cx(SoftFallback.Crc32cx);
|
||||
var dlgSoftFallbackCrc32h = new SoftFallbackCrc32h(SoftFallback.Crc32h);
|
||||
var dlgSoftFallbackCrc32w = new SoftFallbackCrc32w(SoftFallback.Crc32w);
|
||||
var dlgSoftFallbackCrc32x = new SoftFallbackCrc32x(SoftFallback.Crc32x);
|
||||
var dlgSoftFallbackDecrypt = new SoftFallbackDecrypt(SoftFallback.Decrypt);
|
||||
var dlgSoftFallbackEncrypt = new SoftFallbackEncrypt(SoftFallback.Encrypt);
|
||||
var dlgSoftFallbackFixedRotate = new SoftFallbackFixedRotate(SoftFallback.FixedRotate);
|
||||
var dlgSoftFallbackHashChoose = new SoftFallbackHashChoose(SoftFallback.HashChoose);
|
||||
var dlgSoftFallbackHashLower = new SoftFallbackHashLower(SoftFallback.HashLower);
|
||||
var dlgSoftFallbackHashMajority = new SoftFallbackHashMajority(SoftFallback.HashMajority);
|
||||
var dlgSoftFallbackHashParity = new SoftFallbackHashParity(SoftFallback.HashParity);
|
||||
var dlgSoftFallbackHashUpper = new SoftFallbackHashUpper(SoftFallback.HashUpper);
|
||||
var dlgSoftFallbackInverseMixColumns = new SoftFallbackInverseMixColumns(SoftFallback.InverseMixColumns);
|
||||
var dlgSoftFallbackMixColumns = new SoftFallbackMixColumns(SoftFallback.MixColumns);
|
||||
var dlgSoftFallbackPolynomialMult64_128 = new SoftFallbackPolynomialMult64_128(SoftFallback.PolynomialMult64_128);
|
||||
var dlgSoftFallbackSatF32ToS32 = new SoftFallbackSatF32ToS32(SoftFallback.SatF32ToS32);
|
||||
var dlgSoftFallbackSatF32ToS64 = new SoftFallbackSatF32ToS64(SoftFallback.SatF32ToS64);
|
||||
var dlgSoftFallbackSatF32ToU32 = new SoftFallbackSatF32ToU32(SoftFallback.SatF32ToU32);
|
||||
var dlgSoftFallbackSatF32ToU64 = new SoftFallbackSatF32ToU64(SoftFallback.SatF32ToU64);
|
||||
var dlgSoftFallbackSatF64ToS32 = new SoftFallbackSatF64ToS32(SoftFallback.SatF64ToS32);
|
||||
var dlgSoftFallbackSatF64ToS64 = new SoftFallbackSatF64ToS64(SoftFallback.SatF64ToS64);
|
||||
var dlgSoftFallbackSatF64ToU32 = new SoftFallbackSatF64ToU32(SoftFallback.SatF64ToU32);
|
||||
var dlgSoftFallbackSatF64ToU64 = new SoftFallbackSatF64ToU64(SoftFallback.SatF64ToU64);
|
||||
var dlgSoftFallbackSha1SchedulePart1 = new SoftFallbackSha1SchedulePart1(SoftFallback.Sha1SchedulePart1);
|
||||
var dlgSoftFallbackSha1SchedulePart2 = new SoftFallbackSha1SchedulePart2(SoftFallback.Sha1SchedulePart2);
|
||||
var dlgSoftFallbackSha256SchedulePart1 = new SoftFallbackSha256SchedulePart1(SoftFallback.Sha256SchedulePart1);
|
||||
var dlgSoftFallbackSha256SchedulePart2 = new SoftFallbackSha256SchedulePart2(SoftFallback.Sha256SchedulePart2);
|
||||
var dlgSoftFallbackSignedShrImm64 = new SoftFallbackSignedShrImm64(SoftFallback.SignedShrImm64);
|
||||
var dlgSoftFallbackTbl1 = new SoftFallbackTbl1(SoftFallback.Tbl1);
|
||||
var dlgSoftFallbackTbl2 = new SoftFallbackTbl2(SoftFallback.Tbl2);
|
||||
var dlgSoftFallbackTbl3 = new SoftFallbackTbl3(SoftFallback.Tbl3);
|
||||
var dlgSoftFallbackTbl4 = new SoftFallbackTbl4(SoftFallback.Tbl4);
|
||||
var dlgSoftFallbackTbx1 = new SoftFallbackTbx1(SoftFallback.Tbx1);
|
||||
var dlgSoftFallbackTbx2 = new SoftFallbackTbx2(SoftFallback.Tbx2);
|
||||
var dlgSoftFallbackTbx3 = new SoftFallbackTbx3(SoftFallback.Tbx3);
|
||||
var dlgSoftFallbackTbx4 = new SoftFallbackTbx4(SoftFallback.Tbx4);
|
||||
var dlgSoftFallbackUnsignedShrImm64 = new SoftFallbackUnsignedShrImm64(SoftFallback.UnsignedShrImm64);
|
||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.CountLeadingSigns)));
|
||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.CountLeadingZeros)));
|
||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Crc32b)));
|
||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Crc32cb)));
|
||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Crc32ch)));
|
||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Crc32cw)));
|
||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Crc32cx)));
|
||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Crc32h)));
|
||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Crc32w)));
|
||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Crc32x)));
|
||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Decrypt)));
|
||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Encrypt)));
|
||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.FixedRotate)));
|
||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.HashChoose)));
|
||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.HashLower)));
|
||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.HashMajority)));
|
||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.HashParity)));
|
||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.HashUpper)));
|
||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.InverseMixColumns)));
|
||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.MixColumns)));
|
||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.PolynomialMult64_128)));
|
||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.SatF32ToS32)));
|
||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.SatF32ToS64)));
|
||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.SatF32ToU32)));
|
||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.SatF32ToU64)));
|
||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.SatF64ToS32)));
|
||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.SatF64ToS64)));
|
||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.SatF64ToU32)));
|
||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.SatF64ToU64)));
|
||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Sha1SchedulePart1)));
|
||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Sha1SchedulePart2)));
|
||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Sha256SchedulePart1)));
|
||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Sha256SchedulePart2)));
|
||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.SignedShrImm64)));
|
||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Tbl1)));
|
||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Tbl2)));
|
||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Tbl3)));
|
||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Tbl4)));
|
||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Tbx1)));
|
||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Tbx2)));
|
||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Tbx3)));
|
||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Tbx4)));
|
||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.UnsignedShrImm64)));
|
||||
|
||||
var dlgSoftFloat16_32FPConvert = new SoftFloat16_32FPConvert(SoftFloat16_32.FPConvert);
|
||||
var dlgSoftFloat16_64FPConvert = new SoftFloat16_64FPConvert(SoftFloat16_64.FPConvert);
|
||||
SetDelegateInfo(typeof(SoftFloat16_32).GetMethod(nameof(SoftFloat16_32.FPConvert)));
|
||||
SetDelegateInfo(typeof(SoftFloat16_64).GetMethod(nameof(SoftFloat16_64.FPConvert)));
|
||||
|
||||
var dlgSoftFloat32FPAdd = new SoftFloat32FPAdd(SoftFloat32.FPAdd);
|
||||
var dlgSoftFloat32FPAddFpscr = new SoftFloat32FPAddFpscr(SoftFloat32.FPAddFpscr); // A32 only.
|
||||
var dlgSoftFloat32FPCompare = new SoftFloat32FPCompare(SoftFloat32.FPCompare);
|
||||
var dlgSoftFloat32FPCompareEQ = new SoftFloat32FPCompareEQ(SoftFloat32.FPCompareEQ);
|
||||
var dlgSoftFloat32FPCompareEQFpscr = new SoftFloat32FPCompareEQFpscr(SoftFloat32.FPCompareEQFpscr); // A32 only.
|
||||
var dlgSoftFloat32FPCompareGE = new SoftFloat32FPCompareGE(SoftFloat32.FPCompareGE);
|
||||
var dlgSoftFloat32FPCompareGEFpscr = new SoftFloat32FPCompareGEFpscr(SoftFloat32.FPCompareGEFpscr); // A32 only.
|
||||
var dlgSoftFloat32FPCompareGT = new SoftFloat32FPCompareGT(SoftFloat32.FPCompareGT);
|
||||
var dlgSoftFloat32FPCompareGTFpscr = new SoftFloat32FPCompareGTFpscr(SoftFloat32.FPCompareGTFpscr); // A32 only.
|
||||
var dlgSoftFloat32FPCompareLE = new SoftFloat32FPCompareLE(SoftFloat32.FPCompareLE);
|
||||
var dlgSoftFloat32FPCompareLEFpscr = new SoftFloat32FPCompareLEFpscr(SoftFloat32.FPCompareLEFpscr); // A32 only.
|
||||
var dlgSoftFloat32FPCompareLT = new SoftFloat32FPCompareLT(SoftFloat32.FPCompareLT);
|
||||
var dlgSoftFloat32FPCompareLTFpscr = new SoftFloat32FPCompareLTFpscr(SoftFloat32.FPCompareLTFpscr); // A32 only.
|
||||
var dlgSoftFloat32FPDiv = new SoftFloat32FPDiv(SoftFloat32.FPDiv);
|
||||
var dlgSoftFloat32FPMax = new SoftFloat32FPMax(SoftFloat32.FPMax);
|
||||
var dlgSoftFloat32FPMaxFpscr = new SoftFloat32FPMaxFpscr(SoftFloat32.FPMaxFpscr); // A32 only.
|
||||
var dlgSoftFloat32FPMaxNum = new SoftFloat32FPMaxNum(SoftFloat32.FPMaxNum);
|
||||
var dlgSoftFloat32FPMaxNumFpscr = new SoftFloat32FPMaxNumFpscr(SoftFloat32.FPMaxNumFpscr); // A32 only.
|
||||
var dlgSoftFloat32FPMin = new SoftFloat32FPMin(SoftFloat32.FPMin);
|
||||
var dlgSoftFloat32FPMinFpscr = new SoftFloat32FPMinFpscr(SoftFloat32.FPMinFpscr); // A32 only.
|
||||
var dlgSoftFloat32FPMinNum = new SoftFloat32FPMinNum(SoftFloat32.FPMinNum);
|
||||
var dlgSoftFloat32FPMinNumFpscr = new SoftFloat32FPMinNumFpscr(SoftFloat32.FPMinNumFpscr); // A32 only.
|
||||
var dlgSoftFloat32FPMul = new SoftFloat32FPMul(SoftFloat32.FPMul);
|
||||
var dlgSoftFloat32FPMulFpscr = new SoftFloat32FPMulFpscr(SoftFloat32.FPMulFpscr); // A32 only.
|
||||
var dlgSoftFloat32FPMulAdd = new SoftFloat32FPMulAdd(SoftFloat32.FPMulAdd);
|
||||
var dlgSoftFloat32FPMulAddFpscr = new SoftFloat32FPMulAddFpscr(SoftFloat32.FPMulAddFpscr); // A32 only.
|
||||
var dlgSoftFloat32FPMulSub = new SoftFloat32FPMulSub(SoftFloat32.FPMulSub);
|
||||
var dlgSoftFloat32FPMulSubFpscr = new SoftFloat32FPMulSubFpscr(SoftFloat32.FPMulSubFpscr); // A32 only.
|
||||
var dlgSoftFloat32FPMulX = new SoftFloat32FPMulX(SoftFloat32.FPMulX);
|
||||
var dlgSoftFloat32FPNegMulAdd = new SoftFloat32FPNegMulAdd(SoftFloat32.FPNegMulAdd);
|
||||
var dlgSoftFloat32FPNegMulSub = new SoftFloat32FPNegMulSub(SoftFloat32.FPNegMulSub);
|
||||
var dlgSoftFloat32FPRecipEstimate = new SoftFloat32FPRecipEstimate(SoftFloat32.FPRecipEstimate);
|
||||
var dlgSoftFloat32FPRecipEstimateFpscr = new SoftFloat32FPRecipEstimateFpscr(SoftFloat32.FPRecipEstimateFpscr); // A32 only.
|
||||
var dlgSoftFloat32FPRecipStep = new SoftFloat32FPRecipStep(SoftFloat32.FPRecipStep); // A32 only.
|
||||
var dlgSoftFloat32FPRecipStepFused = new SoftFloat32FPRecipStepFused(SoftFloat32.FPRecipStepFused);
|
||||
var dlgSoftFloat32FPRecpX = new SoftFloat32FPRecpX(SoftFloat32.FPRecpX);
|
||||
var dlgSoftFloat32FPRSqrtEstimate = new SoftFloat32FPRSqrtEstimate(SoftFloat32.FPRSqrtEstimate);
|
||||
var dlgSoftFloat32FPRSqrtEstimateFpscr = new SoftFloat32FPRSqrtEstimateFpscr(SoftFloat32.FPRSqrtEstimateFpscr); // A32 only.
|
||||
var dlgSoftFloat32FPRSqrtStep = new SoftFloat32FPRSqrtStep(SoftFloat32.FPRSqrtStep); // A32 only.
|
||||
var dlgSoftFloat32FPRSqrtStepFused = new SoftFloat32FPRSqrtStepFused(SoftFloat32.FPRSqrtStepFused);
|
||||
var dlgSoftFloat32FPSqrt = new SoftFloat32FPSqrt(SoftFloat32.FPSqrt);
|
||||
var dlgSoftFloat32FPSub = new SoftFloat32FPSub(SoftFloat32.FPSub);
|
||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPAdd)));
|
||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPAddFpscr))); // A32 only.
|
||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPCompare)));
|
||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPCompareEQ)));
|
||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPCompareEQFpscr))); // A32 only.
|
||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPCompareGE)));
|
||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPCompareGEFpscr))); // A32 only.
|
||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPCompareGT)));
|
||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPCompareGTFpscr))); // A32 only.
|
||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPCompareLE)));
|
||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPCompareLEFpscr))); // A32 only.
|
||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPCompareLT)));
|
||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPCompareLTFpscr))); // A32 only.
|
||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPDiv)));
|
||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMax)));
|
||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMaxFpscr))); // A32 only.
|
||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMaxNum)));
|
||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMaxNumFpscr))); // A32 only.
|
||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMin)));
|
||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMinFpscr))); // A32 only.
|
||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMinNum)));
|
||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMinNumFpscr))); // A32 only.
|
||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMul)));
|
||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMulFpscr))); // A32 only.
|
||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMulAdd)));
|
||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMulAddFpscr))); // A32 only.
|
||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMulSub)));
|
||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMulSubFpscr))); // A32 only.
|
||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMulX)));
|
||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPNegMulAdd)));
|
||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPNegMulSub)));
|
||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPRecipEstimate)));
|
||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPRecipEstimateFpscr))); // A32 only.
|
||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPRecipStep))); // A32 only.
|
||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPRecipStepFused)));
|
||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPRecpX)));
|
||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPRSqrtEstimate)));
|
||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPRSqrtEstimateFpscr))); // A32 only.
|
||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPRSqrtStep))); // A32 only.
|
||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPRSqrtStepFused)));
|
||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPSqrt)));
|
||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPSub)));
|
||||
|
||||
var dlgSoftFloat32_16FPConvert = new SoftFloat32_16FPConvert(SoftFloat32_16.FPConvert);
|
||||
SetDelegateInfo(typeof(SoftFloat32_16).GetMethod(nameof(SoftFloat32_16.FPConvert)));
|
||||
|
||||
var dlgSoftFloat64FPAdd = new SoftFloat64FPAdd(SoftFloat64.FPAdd);
|
||||
var dlgSoftFloat64FPAddFpscr = new SoftFloat64FPAddFpscr(SoftFloat64.FPAddFpscr); // A32 only.
|
||||
var dlgSoftFloat64FPCompare = new SoftFloat64FPCompare(SoftFloat64.FPCompare);
|
||||
var dlgSoftFloat64FPCompareEQ = new SoftFloat64FPCompareEQ(SoftFloat64.FPCompareEQ);
|
||||
var dlgSoftFloat64FPCompareEQFpscr = new SoftFloat64FPCompareEQFpscr(SoftFloat64.FPCompareEQFpscr); // A32 only.
|
||||
var dlgSoftFloat64FPCompareGE = new SoftFloat64FPCompareGE(SoftFloat64.FPCompareGE);
|
||||
var dlgSoftFloat64FPCompareGEFpscr = new SoftFloat64FPCompareGEFpscr(SoftFloat64.FPCompareGEFpscr); // A32 only.
|
||||
var dlgSoftFloat64FPCompareGT = new SoftFloat64FPCompareGT(SoftFloat64.FPCompareGT);
|
||||
var dlgSoftFloat64FPCompareGTFpscr = new SoftFloat64FPCompareGTFpscr(SoftFloat64.FPCompareGTFpscr); // A32 only.
|
||||
var dlgSoftFloat64FPCompareLE = new SoftFloat64FPCompareLE(SoftFloat64.FPCompareLE);
|
||||
var dlgSoftFloat64FPCompareLEFpscr = new SoftFloat64FPCompareLEFpscr(SoftFloat64.FPCompareLEFpscr); // A32 only.
|
||||
var dlgSoftFloat64FPCompareLT = new SoftFloat64FPCompareLT(SoftFloat64.FPCompareLT);
|
||||
var dlgSoftFloat64FPCompareLTFpscr = new SoftFloat64FPCompareLTFpscr(SoftFloat64.FPCompareLTFpscr); // A32 only.
|
||||
var dlgSoftFloat64FPDiv = new SoftFloat64FPDiv(SoftFloat64.FPDiv);
|
||||
var dlgSoftFloat64FPMax = new SoftFloat64FPMax(SoftFloat64.FPMax);
|
||||
var dlgSoftFloat64FPMaxFpscr = new SoftFloat64FPMaxFpscr(SoftFloat64.FPMaxFpscr); // A32 only.
|
||||
var dlgSoftFloat64FPMaxNum = new SoftFloat64FPMaxNum(SoftFloat64.FPMaxNum);
|
||||
var dlgSoftFloat64FPMaxNumFpscr = new SoftFloat64FPMaxNumFpscr(SoftFloat64.FPMaxNumFpscr); // A32 only.
|
||||
var dlgSoftFloat64FPMin = new SoftFloat64FPMin(SoftFloat64.FPMin);
|
||||
var dlgSoftFloat64FPMinFpscr = new SoftFloat64FPMinFpscr(SoftFloat64.FPMinFpscr); // A32 only.
|
||||
var dlgSoftFloat64FPMinNum = new SoftFloat64FPMinNum(SoftFloat64.FPMinNum);
|
||||
var dlgSoftFloat64FPMinNumFpscr = new SoftFloat64FPMinNumFpscr(SoftFloat64.FPMinNumFpscr); // A32 only.
|
||||
var dlgSoftFloat64FPMul = new SoftFloat64FPMul(SoftFloat64.FPMul);
|
||||
var dlgSoftFloat64FPMulFpscr = new SoftFloat64FPMulFpscr(SoftFloat64.FPMulFpscr); // A32 only.
|
||||
var dlgSoftFloat64FPMulAdd = new SoftFloat64FPMulAdd(SoftFloat64.FPMulAdd);
|
||||
var dlgSoftFloat64FPMulAddFpscr = new SoftFloat64FPMulAddFpscr(SoftFloat64.FPMulAddFpscr); // A32 only.
|
||||
var dlgSoftFloat64FPMulSub = new SoftFloat64FPMulSub(SoftFloat64.FPMulSub);
|
||||
var dlgSoftFloat64FPMulSubFpscr = new SoftFloat64FPMulSubFpscr(SoftFloat64.FPMulSubFpscr); // A32 only.
|
||||
var dlgSoftFloat64FPMulX = new SoftFloat64FPMulX(SoftFloat64.FPMulX);
|
||||
var dlgSoftFloat64FPNegMulAdd = new SoftFloat64FPNegMulAdd(SoftFloat64.FPNegMulAdd);
|
||||
var dlgSoftFloat64FPNegMulSub = new SoftFloat64FPNegMulSub(SoftFloat64.FPNegMulSub);
|
||||
var dlgSoftFloat64FPRecipEstimate = new SoftFloat64FPRecipEstimate(SoftFloat64.FPRecipEstimate);
|
||||
var dlgSoftFloat64FPRecipEstimateFpscr = new SoftFloat64FPRecipEstimateFpscr(SoftFloat64.FPRecipEstimateFpscr); // A32 only.
|
||||
var dlgSoftFloat64FPRecipStep = new SoftFloat64FPRecipStep(SoftFloat64.FPRecipStep); // A32 only.
|
||||
var dlgSoftFloat64FPRecipStepFused = new SoftFloat64FPRecipStepFused(SoftFloat64.FPRecipStepFused);
|
||||
var dlgSoftFloat64FPRecpX = new SoftFloat64FPRecpX(SoftFloat64.FPRecpX);
|
||||
var dlgSoftFloat64FPRSqrtEstimate = new SoftFloat64FPRSqrtEstimate(SoftFloat64.FPRSqrtEstimate);
|
||||
var dlgSoftFloat64FPRSqrtEstimateFpscr = new SoftFloat64FPRSqrtEstimateFpscr(SoftFloat64.FPRSqrtEstimateFpscr); // A32 only.
|
||||
var dlgSoftFloat64FPRSqrtStep = new SoftFloat64FPRSqrtStep(SoftFloat64.FPRSqrtStep); // A32 only.
|
||||
var dlgSoftFloat64FPRSqrtStepFused = new SoftFloat64FPRSqrtStepFused(SoftFloat64.FPRSqrtStepFused);
|
||||
var dlgSoftFloat64FPSqrt = new SoftFloat64FPSqrt(SoftFloat64.FPSqrt);
|
||||
var dlgSoftFloat64FPSub = new SoftFloat64FPSub(SoftFloat64.FPSub);
|
||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPAdd)));
|
||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPAddFpscr))); // A32 only.
|
||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPCompare)));
|
||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPCompareEQ)));
|
||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPCompareEQFpscr))); // A32 only.
|
||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPCompareGE)));
|
||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPCompareGEFpscr))); // A32 only.
|
||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPCompareGT)));
|
||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPCompareGTFpscr))); // A32 only.
|
||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPCompareLE)));
|
||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPCompareLEFpscr))); // A32 only.
|
||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPCompareLT)));
|
||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPCompareLTFpscr))); // A32 only.
|
||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPDiv)));
|
||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMax)));
|
||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMaxFpscr))); // A32 only.
|
||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMaxNum)));
|
||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMaxNumFpscr))); // A32 only.
|
||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMin)));
|
||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMinFpscr))); // A32 only.
|
||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMinNum)));
|
||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMinNumFpscr))); // A32 only.
|
||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMul)));
|
||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMulFpscr))); // A32 only.
|
||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMulAdd)));
|
||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMulAddFpscr))); // A32 only.
|
||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMulSub)));
|
||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMulSubFpscr))); // A32 only.
|
||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMulX)));
|
||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPNegMulAdd)));
|
||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPNegMulSub)));
|
||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPRecipEstimate)));
|
||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPRecipEstimateFpscr))); // A32 only.
|
||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPRecipStep))); // A32 only.
|
||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPRecipStepFused)));
|
||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPRecpX)));
|
||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPRSqrtEstimate)));
|
||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPRSqrtEstimateFpscr))); // A32 only.
|
||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPRSqrtStep))); // A32 only.
|
||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPRSqrtStepFused)));
|
||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPSqrt)));
|
||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPSub)));
|
||||
|
||||
var dlgSoftFloat64_16FPConvert = new SoftFloat64_16FPConvert(SoftFloat64_16.FPConvert);
|
||||
|
||||
SetDelegateInfo(dlgMathAbs, Marshal.GetFunctionPointerForDelegate<MathAbs>(dlgMathAbs));
|
||||
SetDelegateInfo(dlgMathCeiling, Marshal.GetFunctionPointerForDelegate<MathCeiling>(dlgMathCeiling));
|
||||
SetDelegateInfo(dlgMathFloor, Marshal.GetFunctionPointerForDelegate<MathFloor>(dlgMathFloor));
|
||||
SetDelegateInfo(dlgMathRound, Marshal.GetFunctionPointerForDelegate<MathRound>(dlgMathRound));
|
||||
SetDelegateInfo(dlgMathTruncate, Marshal.GetFunctionPointerForDelegate<MathTruncate>(dlgMathTruncate));
|
||||
|
||||
SetDelegateInfo(dlgMathFAbs, Marshal.GetFunctionPointerForDelegate<MathFAbs>(dlgMathFAbs));
|
||||
SetDelegateInfo(dlgMathFCeiling, Marshal.GetFunctionPointerForDelegate<MathFCeiling>(dlgMathFCeiling));
|
||||
SetDelegateInfo(dlgMathFFloor, Marshal.GetFunctionPointerForDelegate<MathFFloor>(dlgMathFFloor));
|
||||
SetDelegateInfo(dlgMathFRound, Marshal.GetFunctionPointerForDelegate<MathFRound>(dlgMathFRound));
|
||||
SetDelegateInfo(dlgMathFTruncate, Marshal.GetFunctionPointerForDelegate<MathFTruncate>(dlgMathFTruncate));
|
||||
|
||||
SetDelegateInfo(dlgNativeInterfaceBreak, Marshal.GetFunctionPointerForDelegate<NativeInterfaceBreak>(dlgNativeInterfaceBreak));
|
||||
SetDelegateInfo(dlgNativeInterfaceCheckSynchronization, Marshal.GetFunctionPointerForDelegate<NativeInterfaceCheckSynchronization>(dlgNativeInterfaceCheckSynchronization));
|
||||
SetDelegateInfo(dlgNativeInterfaceEnqueueForRejit, Marshal.GetFunctionPointerForDelegate<NativeInterfaceEnqueueForRejit>(dlgNativeInterfaceEnqueueForRejit));
|
||||
SetDelegateInfo(dlgNativeInterfaceGetCntfrqEl0, Marshal.GetFunctionPointerForDelegate<NativeInterfaceGetCntfrqEl0>(dlgNativeInterfaceGetCntfrqEl0));
|
||||
SetDelegateInfo(dlgNativeInterfaceGetCntpctEl0, Marshal.GetFunctionPointerForDelegate<NativeInterfaceGetCntpctEl0>(dlgNativeInterfaceGetCntpctEl0));
|
||||
SetDelegateInfo(dlgNativeInterfaceGetCntvctEl0, Marshal.GetFunctionPointerForDelegate<NativeInterfaceGetCntvctEl0>(dlgNativeInterfaceGetCntvctEl0));
|
||||
SetDelegateInfo(dlgNativeInterfaceGetCtrEl0, Marshal.GetFunctionPointerForDelegate<NativeInterfaceGetCtrEl0>(dlgNativeInterfaceGetCtrEl0));
|
||||
SetDelegateInfo(dlgNativeInterfaceGetDczidEl0, Marshal.GetFunctionPointerForDelegate<NativeInterfaceGetDczidEl0>(dlgNativeInterfaceGetDczidEl0));
|
||||
SetDelegateInfo(dlgNativeInterfaceGetFunctionAddress, Marshal.GetFunctionPointerForDelegate<NativeInterfaceGetFunctionAddress>(dlgNativeInterfaceGetFunctionAddress));
|
||||
SetDelegateInfo(dlgNativeInterfaceInvalidateCacheLine, Marshal.GetFunctionPointerForDelegate<NativeInterfaceInvalidateCacheLine>(dlgNativeInterfaceInvalidateCacheLine));
|
||||
SetDelegateInfo(dlgNativeInterfaceReadByte, Marshal.GetFunctionPointerForDelegate<NativeInterfaceReadByte>(dlgNativeInterfaceReadByte));
|
||||
SetDelegateInfo(dlgNativeInterfaceReadUInt16, Marshal.GetFunctionPointerForDelegate<NativeInterfaceReadUInt16>(dlgNativeInterfaceReadUInt16));
|
||||
SetDelegateInfo(dlgNativeInterfaceReadUInt32, Marshal.GetFunctionPointerForDelegate<NativeInterfaceReadUInt32>(dlgNativeInterfaceReadUInt32));
|
||||
SetDelegateInfo(dlgNativeInterfaceReadUInt64, Marshal.GetFunctionPointerForDelegate<NativeInterfaceReadUInt64>(dlgNativeInterfaceReadUInt64));
|
||||
SetDelegateInfo(dlgNativeInterfaceReadVector128, Marshal.GetFunctionPointerForDelegate<NativeInterfaceReadVector128>(dlgNativeInterfaceReadVector128));
|
||||
SetDelegateInfo(dlgNativeInterfaceSignalMemoryTracking, Marshal.GetFunctionPointerForDelegate<NativeInterfaceSignalMemoryTracking>(dlgNativeInterfaceSignalMemoryTracking));
|
||||
SetDelegateInfo(dlgNativeInterfaceSupervisorCall, Marshal.GetFunctionPointerForDelegate<NativeInterfaceSupervisorCall>(dlgNativeInterfaceSupervisorCall));
|
||||
SetDelegateInfo(dlgNativeInterfaceThrowInvalidMemoryAccess, Marshal.GetFunctionPointerForDelegate<NativeInterfaceThrowInvalidMemoryAccess>(dlgNativeInterfaceThrowInvalidMemoryAccess));
|
||||
SetDelegateInfo(dlgNativeInterfaceUndefined, Marshal.GetFunctionPointerForDelegate<NativeInterfaceUndefined>(dlgNativeInterfaceUndefined));
|
||||
SetDelegateInfo(dlgNativeInterfaceWriteByte, Marshal.GetFunctionPointerForDelegate<NativeInterfaceWriteByte>(dlgNativeInterfaceWriteByte));
|
||||
SetDelegateInfo(dlgNativeInterfaceWriteUInt16, Marshal.GetFunctionPointerForDelegate<NativeInterfaceWriteUInt16>(dlgNativeInterfaceWriteUInt16));
|
||||
SetDelegateInfo(dlgNativeInterfaceWriteUInt32, Marshal.GetFunctionPointerForDelegate<NativeInterfaceWriteUInt32>(dlgNativeInterfaceWriteUInt32));
|
||||
SetDelegateInfo(dlgNativeInterfaceWriteUInt64, Marshal.GetFunctionPointerForDelegate<NativeInterfaceWriteUInt64>(dlgNativeInterfaceWriteUInt64));
|
||||
SetDelegateInfo(dlgNativeInterfaceWriteVector128, Marshal.GetFunctionPointerForDelegate<NativeInterfaceWriteVector128>(dlgNativeInterfaceWriteVector128));
|
||||
|
||||
SetDelegateInfo(dlgSoftFallbackCountLeadingSigns, Marshal.GetFunctionPointerForDelegate<SoftFallbackCountLeadingSigns>(dlgSoftFallbackCountLeadingSigns));
|
||||
SetDelegateInfo(dlgSoftFallbackCountLeadingZeros, Marshal.GetFunctionPointerForDelegate<SoftFallbackCountLeadingZeros>(dlgSoftFallbackCountLeadingZeros));
|
||||
SetDelegateInfo(dlgSoftFallbackCrc32b, Marshal.GetFunctionPointerForDelegate<SoftFallbackCrc32b>(dlgSoftFallbackCrc32b));
|
||||
SetDelegateInfo(dlgSoftFallbackCrc32cb, Marshal.GetFunctionPointerForDelegate<SoftFallbackCrc32cb>(dlgSoftFallbackCrc32cb));
|
||||
SetDelegateInfo(dlgSoftFallbackCrc32ch, Marshal.GetFunctionPointerForDelegate<SoftFallbackCrc32ch>(dlgSoftFallbackCrc32ch));
|
||||
SetDelegateInfo(dlgSoftFallbackCrc32cw, Marshal.GetFunctionPointerForDelegate<SoftFallbackCrc32cw>(dlgSoftFallbackCrc32cw));
|
||||
SetDelegateInfo(dlgSoftFallbackCrc32cx, Marshal.GetFunctionPointerForDelegate<SoftFallbackCrc32cx>(dlgSoftFallbackCrc32cx));
|
||||
SetDelegateInfo(dlgSoftFallbackCrc32h, Marshal.GetFunctionPointerForDelegate<SoftFallbackCrc32h>(dlgSoftFallbackCrc32h));
|
||||
SetDelegateInfo(dlgSoftFallbackCrc32w, Marshal.GetFunctionPointerForDelegate<SoftFallbackCrc32w>(dlgSoftFallbackCrc32w));
|
||||
SetDelegateInfo(dlgSoftFallbackCrc32x, Marshal.GetFunctionPointerForDelegate<SoftFallbackCrc32x>(dlgSoftFallbackCrc32x));
|
||||
SetDelegateInfo(dlgSoftFallbackDecrypt, Marshal.GetFunctionPointerForDelegate<SoftFallbackDecrypt>(dlgSoftFallbackDecrypt));
|
||||
SetDelegateInfo(dlgSoftFallbackEncrypt, Marshal.GetFunctionPointerForDelegate<SoftFallbackEncrypt>(dlgSoftFallbackEncrypt));
|
||||
SetDelegateInfo(dlgSoftFallbackFixedRotate, Marshal.GetFunctionPointerForDelegate<SoftFallbackFixedRotate>(dlgSoftFallbackFixedRotate));
|
||||
SetDelegateInfo(dlgSoftFallbackHashChoose, Marshal.GetFunctionPointerForDelegate<SoftFallbackHashChoose>(dlgSoftFallbackHashChoose));
|
||||
SetDelegateInfo(dlgSoftFallbackHashLower, Marshal.GetFunctionPointerForDelegate<SoftFallbackHashLower>(dlgSoftFallbackHashLower));
|
||||
SetDelegateInfo(dlgSoftFallbackHashMajority, Marshal.GetFunctionPointerForDelegate<SoftFallbackHashMajority>(dlgSoftFallbackHashMajority));
|
||||
SetDelegateInfo(dlgSoftFallbackHashParity, Marshal.GetFunctionPointerForDelegate<SoftFallbackHashParity>(dlgSoftFallbackHashParity));
|
||||
SetDelegateInfo(dlgSoftFallbackHashUpper, Marshal.GetFunctionPointerForDelegate<SoftFallbackHashUpper>(dlgSoftFallbackHashUpper));
|
||||
SetDelegateInfo(dlgSoftFallbackInverseMixColumns, Marshal.GetFunctionPointerForDelegate<SoftFallbackInverseMixColumns>(dlgSoftFallbackInverseMixColumns));
|
||||
SetDelegateInfo(dlgSoftFallbackMixColumns, Marshal.GetFunctionPointerForDelegate<SoftFallbackMixColumns>(dlgSoftFallbackMixColumns));
|
||||
SetDelegateInfo(dlgSoftFallbackPolynomialMult64_128, Marshal.GetFunctionPointerForDelegate<SoftFallbackPolynomialMult64_128>(dlgSoftFallbackPolynomialMult64_128));
|
||||
SetDelegateInfo(dlgSoftFallbackSatF32ToS32, Marshal.GetFunctionPointerForDelegate<SoftFallbackSatF32ToS32>(dlgSoftFallbackSatF32ToS32));
|
||||
SetDelegateInfo(dlgSoftFallbackSatF32ToS64, Marshal.GetFunctionPointerForDelegate<SoftFallbackSatF32ToS64>(dlgSoftFallbackSatF32ToS64));
|
||||
SetDelegateInfo(dlgSoftFallbackSatF32ToU32, Marshal.GetFunctionPointerForDelegate<SoftFallbackSatF32ToU32>(dlgSoftFallbackSatF32ToU32));
|
||||
SetDelegateInfo(dlgSoftFallbackSatF32ToU64, Marshal.GetFunctionPointerForDelegate<SoftFallbackSatF32ToU64>(dlgSoftFallbackSatF32ToU64));
|
||||
SetDelegateInfo(dlgSoftFallbackSatF64ToS32, Marshal.GetFunctionPointerForDelegate<SoftFallbackSatF64ToS32>(dlgSoftFallbackSatF64ToS32));
|
||||
SetDelegateInfo(dlgSoftFallbackSatF64ToS64, Marshal.GetFunctionPointerForDelegate<SoftFallbackSatF64ToS64>(dlgSoftFallbackSatF64ToS64));
|
||||
SetDelegateInfo(dlgSoftFallbackSatF64ToU32, Marshal.GetFunctionPointerForDelegate<SoftFallbackSatF64ToU32>(dlgSoftFallbackSatF64ToU32));
|
||||
SetDelegateInfo(dlgSoftFallbackSatF64ToU64, Marshal.GetFunctionPointerForDelegate<SoftFallbackSatF64ToU64>(dlgSoftFallbackSatF64ToU64));
|
||||
SetDelegateInfo(dlgSoftFallbackSha1SchedulePart1, Marshal.GetFunctionPointerForDelegate<SoftFallbackSha1SchedulePart1>(dlgSoftFallbackSha1SchedulePart1));
|
||||
SetDelegateInfo(dlgSoftFallbackSha1SchedulePart2, Marshal.GetFunctionPointerForDelegate<SoftFallbackSha1SchedulePart2>(dlgSoftFallbackSha1SchedulePart2));
|
||||
SetDelegateInfo(dlgSoftFallbackSha256SchedulePart1, Marshal.GetFunctionPointerForDelegate<SoftFallbackSha256SchedulePart1>(dlgSoftFallbackSha256SchedulePart1));
|
||||
SetDelegateInfo(dlgSoftFallbackSha256SchedulePart2, Marshal.GetFunctionPointerForDelegate<SoftFallbackSha256SchedulePart2>(dlgSoftFallbackSha256SchedulePart2));
|
||||
SetDelegateInfo(dlgSoftFallbackSignedShrImm64, Marshal.GetFunctionPointerForDelegate<SoftFallbackSignedShrImm64>(dlgSoftFallbackSignedShrImm64));
|
||||
SetDelegateInfo(dlgSoftFallbackTbl1, Marshal.GetFunctionPointerForDelegate<SoftFallbackTbl1>(dlgSoftFallbackTbl1));
|
||||
SetDelegateInfo(dlgSoftFallbackTbl2, Marshal.GetFunctionPointerForDelegate<SoftFallbackTbl2>(dlgSoftFallbackTbl2));
|
||||
SetDelegateInfo(dlgSoftFallbackTbl3, Marshal.GetFunctionPointerForDelegate<SoftFallbackTbl3>(dlgSoftFallbackTbl3));
|
||||
SetDelegateInfo(dlgSoftFallbackTbl4, Marshal.GetFunctionPointerForDelegate<SoftFallbackTbl4>(dlgSoftFallbackTbl4));
|
||||
SetDelegateInfo(dlgSoftFallbackTbx1, Marshal.GetFunctionPointerForDelegate<SoftFallbackTbx1>(dlgSoftFallbackTbx1));
|
||||
SetDelegateInfo(dlgSoftFallbackTbx2, Marshal.GetFunctionPointerForDelegate<SoftFallbackTbx2>(dlgSoftFallbackTbx2));
|
||||
SetDelegateInfo(dlgSoftFallbackTbx3, Marshal.GetFunctionPointerForDelegate<SoftFallbackTbx3>(dlgSoftFallbackTbx3));
|
||||
SetDelegateInfo(dlgSoftFallbackTbx4, Marshal.GetFunctionPointerForDelegate<SoftFallbackTbx4>(dlgSoftFallbackTbx4));
|
||||
SetDelegateInfo(dlgSoftFallbackUnsignedShrImm64, Marshal.GetFunctionPointerForDelegate<SoftFallbackUnsignedShrImm64>(dlgSoftFallbackUnsignedShrImm64));
|
||||
|
||||
SetDelegateInfo(dlgSoftFloat16_32FPConvert, Marshal.GetFunctionPointerForDelegate<SoftFloat16_32FPConvert>(dlgSoftFloat16_32FPConvert));
|
||||
SetDelegateInfo(dlgSoftFloat16_64FPConvert, Marshal.GetFunctionPointerForDelegate<SoftFloat16_64FPConvert>(dlgSoftFloat16_64FPConvert));
|
||||
|
||||
SetDelegateInfo(dlgSoftFloat32FPAdd, Marshal.GetFunctionPointerForDelegate<SoftFloat32FPAdd>(dlgSoftFloat32FPAdd));
|
||||
SetDelegateInfo(dlgSoftFloat32FPAddFpscr, Marshal.GetFunctionPointerForDelegate<SoftFloat32FPAddFpscr>(dlgSoftFloat32FPAddFpscr)); // A32 only.
|
||||
SetDelegateInfo(dlgSoftFloat32FPCompare, Marshal.GetFunctionPointerForDelegate<SoftFloat32FPCompare>(dlgSoftFloat32FPCompare));
|
||||
SetDelegateInfo(dlgSoftFloat32FPCompareEQ, Marshal.GetFunctionPointerForDelegate<SoftFloat32FPCompareEQ>(dlgSoftFloat32FPCompareEQ));
|
||||
SetDelegateInfo(dlgSoftFloat32FPCompareEQFpscr, Marshal.GetFunctionPointerForDelegate<SoftFloat32FPCompareEQFpscr>(dlgSoftFloat32FPCompareEQFpscr)); // A32 only.
|
||||
SetDelegateInfo(dlgSoftFloat32FPCompareGE, Marshal.GetFunctionPointerForDelegate<SoftFloat32FPCompareGE>(dlgSoftFloat32FPCompareGE));
|
||||
SetDelegateInfo(dlgSoftFloat32FPCompareGEFpscr, Marshal.GetFunctionPointerForDelegate<SoftFloat32FPCompareGEFpscr>(dlgSoftFloat32FPCompareGEFpscr)); // A32 only.
|
||||
SetDelegateInfo(dlgSoftFloat32FPCompareGT, Marshal.GetFunctionPointerForDelegate<SoftFloat32FPCompareGT>(dlgSoftFloat32FPCompareGT));
|
||||
SetDelegateInfo(dlgSoftFloat32FPCompareGTFpscr, Marshal.GetFunctionPointerForDelegate<SoftFloat32FPCompareGTFpscr>(dlgSoftFloat32FPCompareGTFpscr)); // A32 only.
|
||||
SetDelegateInfo(dlgSoftFloat32FPCompareLE, Marshal.GetFunctionPointerForDelegate<SoftFloat32FPCompareLE>(dlgSoftFloat32FPCompareLE));
|
||||
SetDelegateInfo(dlgSoftFloat32FPCompareLEFpscr, Marshal.GetFunctionPointerForDelegate<SoftFloat32FPCompareLEFpscr>(dlgSoftFloat32FPCompareLEFpscr)); // A32 only.
|
||||
SetDelegateInfo(dlgSoftFloat32FPCompareLT, Marshal.GetFunctionPointerForDelegate<SoftFloat32FPCompareLT>(dlgSoftFloat32FPCompareLT));
|
||||
SetDelegateInfo(dlgSoftFloat32FPCompareLTFpscr, Marshal.GetFunctionPointerForDelegate<SoftFloat32FPCompareLTFpscr>(dlgSoftFloat32FPCompareLTFpscr)); // A32 only.
|
||||
SetDelegateInfo(dlgSoftFloat32FPDiv, Marshal.GetFunctionPointerForDelegate<SoftFloat32FPDiv>(dlgSoftFloat32FPDiv));
|
||||
SetDelegateInfo(dlgSoftFloat32FPMax, Marshal.GetFunctionPointerForDelegate<SoftFloat32FPMax>(dlgSoftFloat32FPMax));
|
||||
SetDelegateInfo(dlgSoftFloat32FPMaxFpscr, Marshal.GetFunctionPointerForDelegate<SoftFloat32FPMaxFpscr>(dlgSoftFloat32FPMaxFpscr)); // A32 only.
|
||||
SetDelegateInfo(dlgSoftFloat32FPMaxNum, Marshal.GetFunctionPointerForDelegate<SoftFloat32FPMaxNum>(dlgSoftFloat32FPMaxNum));
|
||||
SetDelegateInfo(dlgSoftFloat32FPMaxNumFpscr, Marshal.GetFunctionPointerForDelegate<SoftFloat32FPMaxNumFpscr>(dlgSoftFloat32FPMaxNumFpscr)); // A32 only.
|
||||
SetDelegateInfo(dlgSoftFloat32FPMin, Marshal.GetFunctionPointerForDelegate<SoftFloat32FPMin>(dlgSoftFloat32FPMin));
|
||||
SetDelegateInfo(dlgSoftFloat32FPMinFpscr, Marshal.GetFunctionPointerForDelegate<SoftFloat32FPMinFpscr>(dlgSoftFloat32FPMinFpscr)); // A32 only.
|
||||
SetDelegateInfo(dlgSoftFloat32FPMinNum, Marshal.GetFunctionPointerForDelegate<SoftFloat32FPMinNum>(dlgSoftFloat32FPMinNum));
|
||||
SetDelegateInfo(dlgSoftFloat32FPMinNumFpscr, Marshal.GetFunctionPointerForDelegate<SoftFloat32FPMinNumFpscr>(dlgSoftFloat32FPMinNumFpscr)); // A32 only.
|
||||
SetDelegateInfo(dlgSoftFloat32FPMul, Marshal.GetFunctionPointerForDelegate<SoftFloat32FPMul>(dlgSoftFloat32FPMul));
|
||||
SetDelegateInfo(dlgSoftFloat32FPMulFpscr, Marshal.GetFunctionPointerForDelegate<SoftFloat32FPMulFpscr>(dlgSoftFloat32FPMulFpscr)); // A32 only.
|
||||
SetDelegateInfo(dlgSoftFloat32FPMulAdd, Marshal.GetFunctionPointerForDelegate<SoftFloat32FPMulAdd>(dlgSoftFloat32FPMulAdd));
|
||||
SetDelegateInfo(dlgSoftFloat32FPMulAddFpscr, Marshal.GetFunctionPointerForDelegate<SoftFloat32FPMulAddFpscr>(dlgSoftFloat32FPMulAddFpscr)); // A32 only.
|
||||
SetDelegateInfo(dlgSoftFloat32FPMulSub, Marshal.GetFunctionPointerForDelegate<SoftFloat32FPMulSub>(dlgSoftFloat32FPMulSub));
|
||||
SetDelegateInfo(dlgSoftFloat32FPMulSubFpscr, Marshal.GetFunctionPointerForDelegate<SoftFloat32FPMulSubFpscr>(dlgSoftFloat32FPMulSubFpscr)); // A32 only.
|
||||
SetDelegateInfo(dlgSoftFloat32FPMulX, Marshal.GetFunctionPointerForDelegate<SoftFloat32FPMulX>(dlgSoftFloat32FPMulX));
|
||||
SetDelegateInfo(dlgSoftFloat32FPNegMulAdd, Marshal.GetFunctionPointerForDelegate<SoftFloat32FPNegMulAdd>(dlgSoftFloat32FPNegMulAdd));
|
||||
SetDelegateInfo(dlgSoftFloat32FPNegMulSub, Marshal.GetFunctionPointerForDelegate<SoftFloat32FPNegMulSub>(dlgSoftFloat32FPNegMulSub));
|
||||
SetDelegateInfo(dlgSoftFloat32FPRecipEstimate, Marshal.GetFunctionPointerForDelegate<SoftFloat32FPRecipEstimate>(dlgSoftFloat32FPRecipEstimate));
|
||||
SetDelegateInfo(dlgSoftFloat32FPRecipEstimateFpscr, Marshal.GetFunctionPointerForDelegate<SoftFloat32FPRecipEstimateFpscr>(dlgSoftFloat32FPRecipEstimateFpscr)); // A32 only.
|
||||
SetDelegateInfo(dlgSoftFloat32FPRecipStep, Marshal.GetFunctionPointerForDelegate<SoftFloat32FPRecipStep>(dlgSoftFloat32FPRecipStep)); // A32 only.
|
||||
SetDelegateInfo(dlgSoftFloat32FPRecipStepFused, Marshal.GetFunctionPointerForDelegate<SoftFloat32FPRecipStepFused>(dlgSoftFloat32FPRecipStepFused));
|
||||
SetDelegateInfo(dlgSoftFloat32FPRecpX, Marshal.GetFunctionPointerForDelegate<SoftFloat32FPRecpX>(dlgSoftFloat32FPRecpX));
|
||||
SetDelegateInfo(dlgSoftFloat32FPRSqrtEstimate, Marshal.GetFunctionPointerForDelegate<SoftFloat32FPRSqrtEstimate>(dlgSoftFloat32FPRSqrtEstimate));
|
||||
SetDelegateInfo(dlgSoftFloat32FPRSqrtEstimateFpscr, Marshal.GetFunctionPointerForDelegate<SoftFloat32FPRSqrtEstimateFpscr>(dlgSoftFloat32FPRSqrtEstimateFpscr)); // A32 only.
|
||||
SetDelegateInfo(dlgSoftFloat32FPRSqrtStep, Marshal.GetFunctionPointerForDelegate<SoftFloat32FPRSqrtStep>(dlgSoftFloat32FPRSqrtStep)); // A32 only.
|
||||
SetDelegateInfo(dlgSoftFloat32FPRSqrtStepFused, Marshal.GetFunctionPointerForDelegate<SoftFloat32FPRSqrtStepFused>(dlgSoftFloat32FPRSqrtStepFused));
|
||||
SetDelegateInfo(dlgSoftFloat32FPSqrt, Marshal.GetFunctionPointerForDelegate<SoftFloat32FPSqrt>(dlgSoftFloat32FPSqrt));
|
||||
SetDelegateInfo(dlgSoftFloat32FPSub, Marshal.GetFunctionPointerForDelegate<SoftFloat32FPSub>(dlgSoftFloat32FPSub));
|
||||
|
||||
SetDelegateInfo(dlgSoftFloat32_16FPConvert, Marshal.GetFunctionPointerForDelegate<SoftFloat32_16FPConvert>(dlgSoftFloat32_16FPConvert));
|
||||
|
||||
SetDelegateInfo(dlgSoftFloat64FPAdd, Marshal.GetFunctionPointerForDelegate<SoftFloat64FPAdd>(dlgSoftFloat64FPAdd));
|
||||
SetDelegateInfo(dlgSoftFloat64FPAddFpscr, Marshal.GetFunctionPointerForDelegate<SoftFloat64FPAddFpscr>(dlgSoftFloat64FPAddFpscr)); // A32 only.
|
||||
SetDelegateInfo(dlgSoftFloat64FPCompare, Marshal.GetFunctionPointerForDelegate<SoftFloat64FPCompare>(dlgSoftFloat64FPCompare));
|
||||
SetDelegateInfo(dlgSoftFloat64FPCompareEQ, Marshal.GetFunctionPointerForDelegate<SoftFloat64FPCompareEQ>(dlgSoftFloat64FPCompareEQ));
|
||||
SetDelegateInfo(dlgSoftFloat64FPCompareEQFpscr, Marshal.GetFunctionPointerForDelegate<SoftFloat64FPCompareEQFpscr>(dlgSoftFloat64FPCompareEQFpscr)); // A32 only.
|
||||
SetDelegateInfo(dlgSoftFloat64FPCompareGE, Marshal.GetFunctionPointerForDelegate<SoftFloat64FPCompareGE>(dlgSoftFloat64FPCompareGE));
|
||||
SetDelegateInfo(dlgSoftFloat64FPCompareGEFpscr, Marshal.GetFunctionPointerForDelegate<SoftFloat64FPCompareGEFpscr>(dlgSoftFloat64FPCompareGEFpscr)); // A32 only.
|
||||
SetDelegateInfo(dlgSoftFloat64FPCompareGT, Marshal.GetFunctionPointerForDelegate<SoftFloat64FPCompareGT>(dlgSoftFloat64FPCompareGT));
|
||||
SetDelegateInfo(dlgSoftFloat64FPCompareGTFpscr, Marshal.GetFunctionPointerForDelegate<SoftFloat64FPCompareGTFpscr>(dlgSoftFloat64FPCompareGTFpscr)); // A32 only.
|
||||
SetDelegateInfo(dlgSoftFloat64FPCompareLE, Marshal.GetFunctionPointerForDelegate<SoftFloat64FPCompareLE>(dlgSoftFloat64FPCompareLE));
|
||||
SetDelegateInfo(dlgSoftFloat64FPCompareLEFpscr, Marshal.GetFunctionPointerForDelegate<SoftFloat64FPCompareLEFpscr>(dlgSoftFloat64FPCompareLEFpscr)); // A32 only.
|
||||
SetDelegateInfo(dlgSoftFloat64FPCompareLT, Marshal.GetFunctionPointerForDelegate<SoftFloat64FPCompareLT>(dlgSoftFloat64FPCompareLT));
|
||||
SetDelegateInfo(dlgSoftFloat64FPCompareLTFpscr, Marshal.GetFunctionPointerForDelegate<SoftFloat64FPCompareLTFpscr>(dlgSoftFloat64FPCompareLTFpscr)); // A32 only.
|
||||
SetDelegateInfo(dlgSoftFloat64FPDiv, Marshal.GetFunctionPointerForDelegate<SoftFloat64FPDiv>(dlgSoftFloat64FPDiv));
|
||||
SetDelegateInfo(dlgSoftFloat64FPMax, Marshal.GetFunctionPointerForDelegate<SoftFloat64FPMax>(dlgSoftFloat64FPMax));
|
||||
SetDelegateInfo(dlgSoftFloat64FPMaxFpscr, Marshal.GetFunctionPointerForDelegate<SoftFloat64FPMaxFpscr>(dlgSoftFloat64FPMaxFpscr)); // A32 only.
|
||||
SetDelegateInfo(dlgSoftFloat64FPMaxNum, Marshal.GetFunctionPointerForDelegate<SoftFloat64FPMaxNum>(dlgSoftFloat64FPMaxNum));
|
||||
SetDelegateInfo(dlgSoftFloat64FPMaxNumFpscr, Marshal.GetFunctionPointerForDelegate<SoftFloat64FPMaxNumFpscr>(dlgSoftFloat64FPMaxNumFpscr)); // A32 only.
|
||||
SetDelegateInfo(dlgSoftFloat64FPMin, Marshal.GetFunctionPointerForDelegate<SoftFloat64FPMin>(dlgSoftFloat64FPMin));
|
||||
SetDelegateInfo(dlgSoftFloat64FPMinFpscr, Marshal.GetFunctionPointerForDelegate<SoftFloat64FPMinFpscr>(dlgSoftFloat64FPMinFpscr)); // A32 only.
|
||||
SetDelegateInfo(dlgSoftFloat64FPMinNum, Marshal.GetFunctionPointerForDelegate<SoftFloat64FPMinNum>(dlgSoftFloat64FPMinNum));
|
||||
SetDelegateInfo(dlgSoftFloat64FPMinNumFpscr, Marshal.GetFunctionPointerForDelegate<SoftFloat64FPMinNumFpscr>(dlgSoftFloat64FPMinNumFpscr)); // A32 only.
|
||||
SetDelegateInfo(dlgSoftFloat64FPMul, Marshal.GetFunctionPointerForDelegate<SoftFloat64FPMul>(dlgSoftFloat64FPMul));
|
||||
SetDelegateInfo(dlgSoftFloat64FPMulFpscr, Marshal.GetFunctionPointerForDelegate<SoftFloat64FPMulFpscr>(dlgSoftFloat64FPMulFpscr)); // A32 only.
|
||||
SetDelegateInfo(dlgSoftFloat64FPMulAdd, Marshal.GetFunctionPointerForDelegate<SoftFloat64FPMulAdd>(dlgSoftFloat64FPMulAdd));
|
||||
SetDelegateInfo(dlgSoftFloat64FPMulAddFpscr, Marshal.GetFunctionPointerForDelegate<SoftFloat64FPMulAddFpscr>(dlgSoftFloat64FPMulAddFpscr)); // A32 only.
|
||||
SetDelegateInfo(dlgSoftFloat64FPMulSub, Marshal.GetFunctionPointerForDelegate<SoftFloat64FPMulSub>(dlgSoftFloat64FPMulSub));
|
||||
SetDelegateInfo(dlgSoftFloat64FPMulSubFpscr, Marshal.GetFunctionPointerForDelegate<SoftFloat64FPMulSubFpscr>(dlgSoftFloat64FPMulSubFpscr)); // A32 only.
|
||||
SetDelegateInfo(dlgSoftFloat64FPMulX, Marshal.GetFunctionPointerForDelegate<SoftFloat64FPMulX>(dlgSoftFloat64FPMulX));
|
||||
SetDelegateInfo(dlgSoftFloat64FPNegMulAdd, Marshal.GetFunctionPointerForDelegate<SoftFloat64FPNegMulAdd>(dlgSoftFloat64FPNegMulAdd));
|
||||
SetDelegateInfo(dlgSoftFloat64FPNegMulSub, Marshal.GetFunctionPointerForDelegate<SoftFloat64FPNegMulSub>(dlgSoftFloat64FPNegMulSub));
|
||||
SetDelegateInfo(dlgSoftFloat64FPRecipEstimate, Marshal.GetFunctionPointerForDelegate<SoftFloat64FPRecipEstimate>(dlgSoftFloat64FPRecipEstimate));
|
||||
SetDelegateInfo(dlgSoftFloat64FPRecipEstimateFpscr, Marshal.GetFunctionPointerForDelegate<SoftFloat64FPRecipEstimateFpscr>(dlgSoftFloat64FPRecipEstimateFpscr)); // A32 only.
|
||||
SetDelegateInfo(dlgSoftFloat64FPRecipStep, Marshal.GetFunctionPointerForDelegate<SoftFloat64FPRecipStep>(dlgSoftFloat64FPRecipStep)); // A32 only.
|
||||
SetDelegateInfo(dlgSoftFloat64FPRecipStepFused, Marshal.GetFunctionPointerForDelegate<SoftFloat64FPRecipStepFused>(dlgSoftFloat64FPRecipStepFused));
|
||||
SetDelegateInfo(dlgSoftFloat64FPRecpX, Marshal.GetFunctionPointerForDelegate<SoftFloat64FPRecpX>(dlgSoftFloat64FPRecpX));
|
||||
SetDelegateInfo(dlgSoftFloat64FPRSqrtEstimate, Marshal.GetFunctionPointerForDelegate<SoftFloat64FPRSqrtEstimate>(dlgSoftFloat64FPRSqrtEstimate));
|
||||
SetDelegateInfo(dlgSoftFloat64FPRSqrtEstimateFpscr, Marshal.GetFunctionPointerForDelegate<SoftFloat64FPRSqrtEstimateFpscr>(dlgSoftFloat64FPRSqrtEstimateFpscr)); // A32 only.
|
||||
SetDelegateInfo(dlgSoftFloat64FPRSqrtStep, Marshal.GetFunctionPointerForDelegate<SoftFloat64FPRSqrtStep>(dlgSoftFloat64FPRSqrtStep)); // A32 only.
|
||||
SetDelegateInfo(dlgSoftFloat64FPRSqrtStepFused, Marshal.GetFunctionPointerForDelegate<SoftFloat64FPRSqrtStepFused>(dlgSoftFloat64FPRSqrtStepFused));
|
||||
SetDelegateInfo(dlgSoftFloat64FPSqrt, Marshal.GetFunctionPointerForDelegate<SoftFloat64FPSqrt>(dlgSoftFloat64FPSqrt));
|
||||
SetDelegateInfo(dlgSoftFloat64FPSub, Marshal.GetFunctionPointerForDelegate<SoftFloat64FPSub>(dlgSoftFloat64FPSub));
|
||||
|
||||
SetDelegateInfo(dlgSoftFloat64_16FPConvert, Marshal.GetFunctionPointerForDelegate<SoftFloat64_16FPConvert>(dlgSoftFloat64_16FPConvert));
|
||||
SetDelegateInfo(typeof(SoftFloat64_16).GetMethod(nameof(SoftFloat64_16.FPConvert)));
|
||||
}
|
||||
|
||||
private delegate double MathAbs(double value);
|
||||
private delegate double MathCeiling(double a);
|
||||
private delegate double MathFloor(double d);
|
||||
private delegate double MathRound(double value, MidpointRounding mode);
|
||||
private delegate double MathTruncate(double d);
|
||||
|
||||
private delegate float MathFAbs(float x);
|
||||
private delegate float MathFCeiling(float x);
|
||||
private delegate float MathFFloor(float x);
|
||||
private delegate float MathFRound(float x, MidpointRounding mode);
|
||||
private delegate float MathFTruncate(float x);
|
||||
|
||||
private delegate void NativeInterfaceBreak(ulong address, int imm);
|
||||
private delegate bool NativeInterfaceCheckSynchronization();
|
||||
private delegate void NativeInterfaceEnqueueForRejit(ulong address);
|
||||
private delegate ulong NativeInterfaceGetCntfrqEl0();
|
||||
private delegate ulong NativeInterfaceGetCntpctEl0();
|
||||
private delegate ulong NativeInterfaceGetCntvctEl0();
|
||||
private delegate ulong NativeInterfaceGetCtrEl0();
|
||||
private delegate ulong NativeInterfaceGetDczidEl0();
|
||||
private delegate ulong NativeInterfaceGetFunctionAddress(ulong address);
|
||||
private delegate void NativeInterfaceInvalidateCacheLine(ulong address);
|
||||
private delegate byte NativeInterfaceReadByte(ulong address);
|
||||
private delegate ushort NativeInterfaceReadUInt16(ulong address);
|
||||
private delegate uint NativeInterfaceReadUInt32(ulong address);
|
||||
private delegate ulong NativeInterfaceReadUInt64(ulong address);
|
||||
private delegate V128 NativeInterfaceReadVector128(ulong address);
|
||||
private delegate void NativeInterfaceSignalMemoryTracking(ulong address, ulong size, bool write);
|
||||
private delegate void NativeInterfaceSupervisorCall(ulong address, int imm);
|
||||
private delegate void NativeInterfaceThrowInvalidMemoryAccess(ulong address);
|
||||
private delegate void NativeInterfaceUndefined(ulong address, int opCode);
|
||||
private delegate void NativeInterfaceWriteByte(ulong address, byte value);
|
||||
private delegate void NativeInterfaceWriteUInt16(ulong address, ushort value);
|
||||
private delegate void NativeInterfaceWriteUInt32(ulong address, uint value);
|
||||
private delegate void NativeInterfaceWriteUInt64(ulong address, ulong value);
|
||||
private delegate void NativeInterfaceWriteVector128(ulong address, V128 value);
|
||||
|
||||
private delegate ulong SoftFallbackCountLeadingSigns(ulong value, int size);
|
||||
private delegate ulong SoftFallbackCountLeadingZeros(ulong value, int size);
|
||||
private delegate uint SoftFallbackCrc32b(uint crc, byte value);
|
||||
private delegate uint SoftFallbackCrc32cb(uint crc, byte value);
|
||||
private delegate uint SoftFallbackCrc32ch(uint crc, ushort value);
|
||||
private delegate uint SoftFallbackCrc32cw(uint crc, uint value);
|
||||
private delegate uint SoftFallbackCrc32cx(uint crc, ulong value);
|
||||
private delegate uint SoftFallbackCrc32h(uint crc, ushort value);
|
||||
private delegate uint SoftFallbackCrc32w(uint crc, uint value);
|
||||
private delegate uint SoftFallbackCrc32x(uint crc, ulong value);
|
||||
private delegate V128 SoftFallbackDecrypt(V128 value, V128 roundKey);
|
||||
private delegate V128 SoftFallbackEncrypt(V128 value, V128 roundKey);
|
||||
private delegate uint SoftFallbackFixedRotate(uint hash_e);
|
||||
private delegate V128 SoftFallbackHashChoose(V128 hash_abcd, uint hash_e, V128 wk);
|
||||
private delegate V128 SoftFallbackHashLower(V128 hash_abcd, V128 hash_efgh, V128 wk);
|
||||
private delegate V128 SoftFallbackHashMajority(V128 hash_abcd, uint hash_e, V128 wk);
|
||||
private delegate V128 SoftFallbackHashParity(V128 hash_abcd, uint hash_e, V128 wk);
|
||||
private delegate V128 SoftFallbackHashUpper(V128 hash_abcd, V128 hash_efgh, V128 wk);
|
||||
private delegate V128 SoftFallbackInverseMixColumns(V128 value);
|
||||
private delegate V128 SoftFallbackMixColumns(V128 value);
|
||||
private delegate V128 SoftFallbackPolynomialMult64_128(ulong op1, ulong op2);
|
||||
private delegate int SoftFallbackSatF32ToS32(float value);
|
||||
private delegate long SoftFallbackSatF32ToS64(float value);
|
||||
private delegate uint SoftFallbackSatF32ToU32(float value);
|
||||
private delegate ulong SoftFallbackSatF32ToU64(float value);
|
||||
private delegate int SoftFallbackSatF64ToS32(double value);
|
||||
private delegate long SoftFallbackSatF64ToS64(double value);
|
||||
private delegate uint SoftFallbackSatF64ToU32(double value);
|
||||
private delegate ulong SoftFallbackSatF64ToU64(double value);
|
||||
private delegate V128 SoftFallbackSha1SchedulePart1(V128 w0_3, V128 w4_7, V128 w8_11);
|
||||
private delegate V128 SoftFallbackSha1SchedulePart2(V128 tw0_3, V128 w12_15);
|
||||
private delegate V128 SoftFallbackSha256SchedulePart1(V128 w0_3, V128 w4_7);
|
||||
private delegate V128 SoftFallbackSha256SchedulePart2(V128 w0_3, V128 w8_11, V128 w12_15);
|
||||
private delegate long SoftFallbackSignedShrImm64(long value, long roundConst, int shift);
|
||||
private delegate V128 SoftFallbackTbl1(V128 vector, int bytes, V128 tb0);
|
||||
private delegate V128 SoftFallbackTbl2(V128 vector, int bytes, V128 tb0, V128 tb1);
|
||||
private delegate V128 SoftFallbackTbl3(V128 vector, int bytes, V128 tb0, V128 tb1, V128 tb2);
|
||||
private delegate V128 SoftFallbackTbl4(V128 vector, int bytes, V128 tb0, V128 tb1, V128 tb2, V128 tb3);
|
||||
private delegate V128 SoftFallbackTbx1(V128 dest, V128 vector, int bytes, V128 tb0);
|
||||
private delegate V128 SoftFallbackTbx2(V128 dest, V128 vector, int bytes, V128 tb0, V128 tb1);
|
||||
private delegate V128 SoftFallbackTbx3(V128 dest, V128 vector, int bytes, V128 tb0, V128 tb1, V128 tb2);
|
||||
private delegate V128 SoftFallbackTbx4(V128 dest, V128 vector, int bytes, V128 tb0, V128 tb1, V128 tb2, V128 tb3);
|
||||
private delegate ulong SoftFallbackUnsignedShrImm64(ulong value, long roundConst, int shift);
|
||||
|
||||
private delegate float SoftFloat16_32FPConvert(ushort valueBits);
|
||||
|
||||
private delegate double SoftFloat16_64FPConvert(ushort valueBits);
|
||||
|
||||
private delegate float SoftFloat32FPAdd(float value1, float value2);
|
||||
private delegate float SoftFloat32FPAddFpscr(float value1, float value2, bool standardFpscr);
|
||||
private delegate int SoftFloat32FPCompare(float value1, float value2, bool signalNaNs);
|
||||
private delegate float SoftFloat32FPCompareEQ(float value1, float value2);
|
||||
private delegate float SoftFloat32FPCompareEQFpscr(float value1, float value2, bool standardFpscr);
|
||||
private delegate float SoftFloat32FPCompareGE(float value1, float value2);
|
||||
private delegate float SoftFloat32FPCompareGEFpscr(float value1, float value2, bool standardFpscr);
|
||||
private delegate float SoftFloat32FPCompareGT(float value1, float value2);
|
||||
private delegate float SoftFloat32FPCompareGTFpscr(float value1, float value2, bool standardFpscr);
|
||||
private delegate float SoftFloat32FPCompareLE(float value1, float value2);
|
||||
private delegate float SoftFloat32FPCompareLEFpscr(float value1, float value2, bool standardFpscr);
|
||||
private delegate float SoftFloat32FPCompareLT(float value1, float value2);
|
||||
private delegate float SoftFloat32FPCompareLTFpscr(float value1, float value2, bool standardFpscr);
|
||||
private delegate float SoftFloat32FPDiv(float value1, float value2);
|
||||
private delegate float SoftFloat32FPMax(float value1, float value2);
|
||||
private delegate float SoftFloat32FPMaxFpscr(float value1, float value2, bool standardFpscr);
|
||||
private delegate float SoftFloat32FPMaxNum(float value1, float value2);
|
||||
private delegate float SoftFloat32FPMaxNumFpscr(float value1, float value2, bool standardFpscr);
|
||||
private delegate float SoftFloat32FPMin(float value1, float value2);
|
||||
private delegate float SoftFloat32FPMinFpscr(float value1, float value2, bool standardFpscr);
|
||||
private delegate float SoftFloat32FPMinNum(float value1, float value2);
|
||||
private delegate float SoftFloat32FPMinNumFpscr(float value1, float value2, bool standardFpscr);
|
||||
private delegate float SoftFloat32FPMul(float value1, float value2);
|
||||
private delegate float SoftFloat32FPMulFpscr(float value1, float value2, bool standardFpscr);
|
||||
private delegate float SoftFloat32FPMulAdd(float valueA, float value1, float value2);
|
||||
private delegate float SoftFloat32FPMulAddFpscr(float valueA, float value1, float value2, bool standardFpscr);
|
||||
private delegate float SoftFloat32FPMulSub(float valueA, float value1, float value2);
|
||||
private delegate float SoftFloat32FPMulSubFpscr(float valueA, float value1, float value2, bool standardFpscr);
|
||||
private delegate float SoftFloat32FPMulX(float value1, float value2);
|
||||
private delegate float SoftFloat32FPNegMulAdd(float valueA, float value1, float value2);
|
||||
private delegate float SoftFloat32FPNegMulSub(float valueA, float value1, float value2);
|
||||
private delegate float SoftFloat32FPRecipEstimate(float value);
|
||||
private delegate float SoftFloat32FPRecipEstimateFpscr(float value, bool standardFpscr);
|
||||
private delegate float SoftFloat32FPRecipStep(float value1, float value2);
|
||||
private delegate float SoftFloat32FPRecipStepFused(float value1, float value2);
|
||||
private delegate float SoftFloat32FPRecpX(float value);
|
||||
private delegate float SoftFloat32FPRSqrtEstimate(float value);
|
||||
private delegate float SoftFloat32FPRSqrtEstimateFpscr(float value, bool standardFpscr);
|
||||
private delegate float SoftFloat32FPRSqrtStep(float value1, float value2);
|
||||
private delegate float SoftFloat32FPRSqrtStepFused(float value1, float value2);
|
||||
private delegate float SoftFloat32FPSqrt(float value);
|
||||
private delegate float SoftFloat32FPSub(float value1, float value2);
|
||||
|
||||
private delegate ushort SoftFloat32_16FPConvert(float value);
|
||||
|
||||
private delegate double SoftFloat64FPAdd(double value1, double value2);
|
||||
private delegate double SoftFloat64FPAddFpscr(double value1, double value2, bool standardFpscr);
|
||||
private delegate int SoftFloat64FPCompare(double value1, double value2, bool signalNaNs);
|
||||
private delegate double SoftFloat64FPCompareEQ(double value1, double value2);
|
||||
private delegate double SoftFloat64FPCompareEQFpscr(double value1, double value2, bool standardFpscr);
|
||||
private delegate double SoftFloat64FPCompareGE(double value1, double value2);
|
||||
private delegate double SoftFloat64FPCompareGEFpscr(double value1, double value2, bool standardFpscr);
|
||||
private delegate double SoftFloat64FPCompareGT(double value1, double value2);
|
||||
private delegate double SoftFloat64FPCompareGTFpscr(double value1, double value2, bool standardFpscr);
|
||||
private delegate double SoftFloat64FPCompareLE(double value1, double value2);
|
||||
private delegate double SoftFloat64FPCompareLEFpscr(double value1, double value2, bool standardFpscr);
|
||||
private delegate double SoftFloat64FPCompareLT(double value1, double value2);
|
||||
private delegate double SoftFloat64FPCompareLTFpscr(double value1, double value2, bool standardFpscr);
|
||||
private delegate double SoftFloat64FPDiv(double value1, double value2);
|
||||
private delegate double SoftFloat64FPMax(double value1, double value2);
|
||||
private delegate double SoftFloat64FPMaxFpscr(double value1, double value2, bool standardFpscr);
|
||||
private delegate double SoftFloat64FPMaxNum(double value1, double value2);
|
||||
private delegate double SoftFloat64FPMaxNumFpscr(double value1, double value2, bool standardFpscr);
|
||||
private delegate double SoftFloat64FPMin(double value1, double value2);
|
||||
private delegate double SoftFloat64FPMinFpscr(double value1, double value2, bool standardFpscr);
|
||||
private delegate double SoftFloat64FPMinNum(double value1, double value2);
|
||||
private delegate double SoftFloat64FPMinNumFpscr(double value1, double value2, bool standardFpscr);
|
||||
private delegate double SoftFloat64FPMul(double value1, double value2);
|
||||
private delegate double SoftFloat64FPMulFpscr(double value1, double value2, bool standardFpscr);
|
||||
private delegate double SoftFloat64FPMulAdd(double valueA, double value1, double value2);
|
||||
private delegate double SoftFloat64FPMulAddFpscr(double valueA, double value1, double value2, bool standardFpscr);
|
||||
private delegate double SoftFloat64FPMulSub(double valueA, double value1, double value2);
|
||||
private delegate double SoftFloat64FPMulSubFpscr(double valueA, double value1, double value2, bool standardFpscr);
|
||||
private delegate double SoftFloat64FPMulX(double value1, double value2);
|
||||
private delegate double SoftFloat64FPNegMulAdd(double valueA, double value1, double value2);
|
||||
private delegate double SoftFloat64FPNegMulSub(double valueA, double value1, double value2);
|
||||
private delegate double SoftFloat64FPRecipEstimate(double value);
|
||||
private delegate double SoftFloat64FPRecipEstimateFpscr(double value, bool standardFpscr);
|
||||
private delegate double SoftFloat64FPRecipStep(double value1, double value2);
|
||||
private delegate double SoftFloat64FPRecipStepFused(double value1, double value2);
|
||||
private delegate double SoftFloat64FPRecpX(double value);
|
||||
private delegate double SoftFloat64FPRSqrtEstimate(double value);
|
||||
private delegate double SoftFloat64FPRSqrtEstimateFpscr(double value, bool standardFpscr);
|
||||
private delegate double SoftFloat64FPRSqrtStep(double value1, double value2);
|
||||
private delegate double SoftFloat64FPRSqrtStepFused(double value1, double value2);
|
||||
private delegate double SoftFloat64FPSqrt(double value);
|
||||
private delegate double SoftFloat64FPSub(double value1, double value2);
|
||||
|
||||
private delegate ushort SoftFloat64_16FPConvert(double value);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -97,7 +97,7 @@ namespace ARMeilleure.Translation
|
||||
|
||||
public virtual Operand Call(MethodInfo info, params Operand[] callArgs)
|
||||
{
|
||||
nint funcPtr = Delegates.GetDelegateFuncPtr(info);
|
||||
nint funcPtr = info.MethodHandle.GetFunctionPointer();
|
||||
|
||||
OperandType returnType = GetOperandType(info.ReturnType);
|
||||
|
||||
|
||||
@@ -29,8 +29,8 @@ namespace ARMeilleure.Translation.PTC
|
||||
{
|
||||
private const string OuterHeaderMagicString = "PTCohd\0\0";
|
||||
private const string InnerHeaderMagicString = "PTCihd\0\0";
|
||||
|
||||
private const uint InternalVersion = 6997; //! To be incremented manually for each change to the ARMeilleure project.
|
||||
|
||||
private const uint InternalVersion = 6998; //! To be incremented manually for each change to the ARMeilleure project.
|
||||
|
||||
private const string ActualDir = "0";
|
||||
private const string BackupDir = "1";
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<DefaultItemExcludes>$(DefaultItemExcludes);._*</DefaultItemExcludes>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Ryujinx.Audio\Ryujinx.Audio.csproj" />
|
||||
<ProjectReference Include="..\Ryujinx.SDL3.Common\Ryujinx.SDL3.Common.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
16
src/Ryujinx.Audio.Backends.SDL3/SDL3AudioBuffer.cs
Normal file
16
src/Ryujinx.Audio.Backends.SDL3/SDL3AudioBuffer.cs
Normal file
@@ -0,0 +1,16 @@
|
||||
namespace Ryujinx.Audio.Backends.SDL3
|
||||
{
|
||||
class SDL3AudioBuffer
|
||||
{
|
||||
public readonly ulong DriverIdentifier;
|
||||
public readonly ulong SampleCount;
|
||||
public ulong SamplePlayed;
|
||||
|
||||
public SDL3AudioBuffer(ulong driverIdentifier, ulong sampleCount)
|
||||
{
|
||||
DriverIdentifier = driverIdentifier;
|
||||
SampleCount = sampleCount;
|
||||
SamplePlayed = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
190
src/Ryujinx.Audio.Backends.SDL3/SDL3HardwareDeviceDriver.cs
Normal file
190
src/Ryujinx.Audio.Backends.SDL3/SDL3HardwareDeviceDriver.cs
Normal file
@@ -0,0 +1,190 @@
|
||||
using Ryujinx.Audio.Common;
|
||||
using Ryujinx.Audio.Integration;
|
||||
using Ryujinx.Common.Logging;
|
||||
using Ryujinx.Memory;
|
||||
using Ryujinx.SDL3.Common;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Threading;
|
||||
using static Ryujinx.Audio.Integration.IHardwareDeviceDriver;
|
||||
using static SDL3.SDL;
|
||||
|
||||
namespace Ryujinx.Audio.Backends.SDL3
|
||||
{
|
||||
public class SDL3HardwareDeviceDriver : IHardwareDeviceDriver
|
||||
{
|
||||
private readonly ManualResetEvent _updateRequiredEvent;
|
||||
private readonly ManualResetEvent _pauseEvent;
|
||||
private readonly ConcurrentDictionary<SDL3HardwareDeviceSession, byte> _sessions;
|
||||
|
||||
private readonly bool _supportSurroundConfiguration;
|
||||
|
||||
public float Volume { get; set; }
|
||||
|
||||
public SDL3HardwareDeviceDriver()
|
||||
{
|
||||
_updateRequiredEvent = new ManualResetEvent(false);
|
||||
_pauseEvent = new ManualResetEvent(true);
|
||||
_sessions = new ConcurrentDictionary<SDL3HardwareDeviceSession, byte>();
|
||||
|
||||
SDL3Driver.Instance.Initialize();
|
||||
|
||||
if (!SDL_GetAudioDeviceFormat(SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK, out var spec, out int _))
|
||||
{
|
||||
Logger.Error?.Print(LogClass.Application,
|
||||
$"SDL_GetDefaultAudioInfo failed with error \"{SDL_GetError()}\"");
|
||||
|
||||
_supportSurroundConfiguration = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
_supportSurroundConfiguration = spec.channels >= 6;
|
||||
}
|
||||
|
||||
Volume = 1f;
|
||||
}
|
||||
|
||||
public static bool IsSupported => IsSupportedInternal();
|
||||
|
||||
private static bool IsSupportedInternal()
|
||||
{
|
||||
nint device = OpenStream(SampleFormat.PcmInt16, Constants.TargetSampleRate, Constants.ChannelCountMax, null);
|
||||
|
||||
if (device != 0)
|
||||
{
|
||||
SDL_DestroyAudioStream(device);
|
||||
}
|
||||
|
||||
return device != 0;
|
||||
}
|
||||
|
||||
public ManualResetEvent GetUpdateRequiredEvent()
|
||||
{
|
||||
return _updateRequiredEvent;
|
||||
}
|
||||
|
||||
public ManualResetEvent GetPauseEvent()
|
||||
{
|
||||
return _pauseEvent;
|
||||
}
|
||||
|
||||
public IHardwareDeviceSession OpenDeviceSession(Direction direction, IVirtualMemoryManager memoryManager,
|
||||
SampleFormat sampleFormat, uint sampleRate, uint channelCount)
|
||||
{
|
||||
if (channelCount == 0)
|
||||
{
|
||||
channelCount = 2;
|
||||
}
|
||||
|
||||
if (sampleRate == 0)
|
||||
{
|
||||
sampleRate = Constants.TargetSampleRate;
|
||||
}
|
||||
|
||||
if (direction != Direction.Output)
|
||||
{
|
||||
throw new NotImplementedException("Input direction is currently not implemented on SDL3 backend!");
|
||||
}
|
||||
|
||||
SDL3HardwareDeviceSession session = new(this, memoryManager, sampleFormat, sampleRate, channelCount);
|
||||
|
||||
_sessions.TryAdd(session, 0);
|
||||
|
||||
return session;
|
||||
}
|
||||
|
||||
internal bool Unregister(SDL3HardwareDeviceSession session)
|
||||
{
|
||||
return _sessions.TryRemove(session, out _);
|
||||
}
|
||||
|
||||
private static SDL_AudioSpec GetSDL3Spec(SampleFormat requestedSampleFormat, uint requestedSampleRate,
|
||||
uint requestedChannelCount)
|
||||
{
|
||||
return new SDL_AudioSpec
|
||||
{
|
||||
channels = (byte)requestedChannelCount,
|
||||
format = GetSDL3Format(requestedSampleFormat),
|
||||
freq = (int)requestedSampleRate,
|
||||
};
|
||||
}
|
||||
|
||||
internal static SDL_AudioFormat GetSDL3Format(SampleFormat format)
|
||||
{
|
||||
return format switch
|
||||
{
|
||||
SampleFormat.PcmInt8 => SDL_AudioFormat.SDL_AUDIO_S8,
|
||||
SampleFormat.PcmInt16 => SDL_AudioFormat.SDL_AUDIO_S16,
|
||||
SampleFormat.PcmInt32 => SDL_AudioFormat.SDL_AUDIO_S32,
|
||||
SampleFormat.PcmFloat => SDL_AudioFormat.SDL_AUDIO_F32,
|
||||
_ => throw new ArgumentException($"Unsupported sample format {format}"),
|
||||
};
|
||||
}
|
||||
|
||||
internal static nint OpenStream(SampleFormat requestedSampleFormat, uint requestedSampleRate,
|
||||
uint requestedChannelCount, SDL_AudioStreamCallback callback)
|
||||
{
|
||||
SDL_AudioSpec desired = GetSDL3Spec(requestedSampleFormat, requestedSampleRate, requestedChannelCount);
|
||||
|
||||
nint stream =
|
||||
SDL_OpenAudioDeviceStream(SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK, ref desired, callback, nint.Zero);
|
||||
|
||||
if (stream == 0)
|
||||
{
|
||||
Logger.Error?.Print(LogClass.Application,
|
||||
$"SDL3 open audio device initialization failed with error \"{SDL_GetError()}\"");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
return stream;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
GC.SuppressFinalize(this);
|
||||
Dispose(true);
|
||||
}
|
||||
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
foreach (SDL3HardwareDeviceSession session in _sessions.Keys)
|
||||
{
|
||||
session.Dispose();
|
||||
}
|
||||
|
||||
SDL3Driver.Instance.Dispose();
|
||||
|
||||
_pauseEvent.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
public bool SupportsSampleRate(uint sampleRate)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool SupportsSampleFormat(SampleFormat sampleFormat)
|
||||
{
|
||||
return sampleFormat != SampleFormat.PcmInt24;
|
||||
}
|
||||
|
||||
public bool SupportsChannelCount(uint channelCount)
|
||||
{
|
||||
if (channelCount == 6)
|
||||
{
|
||||
return _supportSurroundConfiguration;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool SupportsDirection(Direction direction)
|
||||
{
|
||||
// TODO: add direction input when supported.
|
||||
return direction == Direction.Output;
|
||||
}
|
||||
}
|
||||
}
|
||||
231
src/Ryujinx.Audio.Backends.SDL3/SDL3HardwareDeviceSession.cs
Normal file
231
src/Ryujinx.Audio.Backends.SDL3/SDL3HardwareDeviceSession.cs
Normal file
@@ -0,0 +1,231 @@
|
||||
using Ryujinx.Audio.Backends.Common;
|
||||
using Ryujinx.Audio.Common;
|
||||
using Ryujinx.Common.Logging;
|
||||
using Ryujinx.Common.Memory;
|
||||
using Ryujinx.Memory;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Threading;
|
||||
using static SDL3.SDL;
|
||||
|
||||
namespace Ryujinx.Audio.Backends.SDL3
|
||||
{
|
||||
class SDL3HardwareDeviceSession : HardwareDeviceSessionOutputBase
|
||||
{
|
||||
private readonly SDL3HardwareDeviceDriver _driver;
|
||||
private readonly ConcurrentQueue<SDL3AudioBuffer> _queuedBuffers;
|
||||
private readonly DynamicRingBuffer _ringBuffer;
|
||||
private ulong _playedSampleCount;
|
||||
private readonly ManualResetEvent _updateRequiredEvent;
|
||||
private nint _outputStream;
|
||||
private bool _hasSetupError;
|
||||
private readonly SDL_AudioStreamCallback _callbackDelegate;
|
||||
private readonly int _bytesPerFrame;
|
||||
private bool _started;
|
||||
private float _volume;
|
||||
private readonly SDL_AudioFormat _nativeSampleFormat;
|
||||
|
||||
public SDL3HardwareDeviceSession(SDL3HardwareDeviceDriver driver, IVirtualMemoryManager memoryManager,
|
||||
SampleFormat requestedSampleFormat, uint requestedSampleRate, uint requestedChannelCount) : base(
|
||||
memoryManager, requestedSampleFormat, requestedSampleRate, requestedChannelCount)
|
||||
{
|
||||
_driver = driver;
|
||||
_updateRequiredEvent = _driver.GetUpdateRequiredEvent();
|
||||
_queuedBuffers = new ConcurrentQueue<SDL3AudioBuffer>();
|
||||
_ringBuffer = new DynamicRingBuffer();
|
||||
_callbackDelegate = Update;
|
||||
_bytesPerFrame = BackendHelper.GetSampleSize(RequestedSampleFormat) * (int)RequestedChannelCount;
|
||||
_nativeSampleFormat = SDL3HardwareDeviceDriver.GetSDL3Format(RequestedSampleFormat);
|
||||
_started = false;
|
||||
_volume = 1f;
|
||||
}
|
||||
|
||||
private void EnsureAudioStreamSetup(AudioBuffer buffer)
|
||||
{
|
||||
uint bufferSampleCount = (uint)GetSampleCount(buffer);
|
||||
bool needAudioSetup = (_outputStream == 0 && !_hasSetupError) ||
|
||||
(bufferSampleCount >= Constants.TargetSampleCount);
|
||||
|
||||
if (needAudioSetup)
|
||||
{
|
||||
nint newOutputStream = SDL3HardwareDeviceDriver.OpenStream(RequestedSampleFormat, RequestedSampleRate,
|
||||
RequestedChannelCount, _callbackDelegate);
|
||||
|
||||
_hasSetupError = newOutputStream == 0;
|
||||
|
||||
if (!_hasSetupError)
|
||||
{
|
||||
if (_outputStream != 0)
|
||||
{
|
||||
SDL_DestroyAudioStream(_outputStream);
|
||||
}
|
||||
|
||||
_outputStream = newOutputStream;
|
||||
|
||||
if (_started)
|
||||
{
|
||||
SDL_ResumeAudioStreamDevice(_outputStream);
|
||||
}
|
||||
else
|
||||
{
|
||||
SDL_PauseAudioStreamDevice(_outputStream);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private unsafe void Update(nint userdata, nint stream, int additionalAmount, int totalAmount)
|
||||
{
|
||||
int maxFrameCount = (int)GetSampleCount(additionalAmount);
|
||||
int bufferedFrames = _ringBuffer.Length / _bytesPerFrame;
|
||||
|
||||
int frameCount = Math.Min(bufferedFrames, maxFrameCount);
|
||||
|
||||
if (frameCount == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
using SpanOwner<byte> samplesOwner = SpanOwner<byte>.Rent(frameCount * _bytesPerFrame);
|
||||
|
||||
Span<byte> samples = samplesOwner.Span;
|
||||
int samplesLength = samples.Length;
|
||||
_ringBuffer.Read(samples, 0, samplesLength);
|
||||
|
||||
fixed (byte* p = samples)
|
||||
{
|
||||
nint pStreamSrc = (nint)p;
|
||||
nint pStreamDst = SDL_calloc(1,samplesLength);
|
||||
// Apply volume to written data
|
||||
SDL_MixAudio(pStreamDst, pStreamSrc, _nativeSampleFormat, (uint)samplesLength, _driver.Volume);
|
||||
SDL_PutAudioStreamData(stream, pStreamDst, samplesLength);
|
||||
SDL_free(pStreamDst);
|
||||
}
|
||||
|
||||
ulong sampleCount = GetSampleCount(samplesLength);
|
||||
|
||||
ulong availaibleSampleCount = sampleCount;
|
||||
|
||||
bool needUpdate = false;
|
||||
|
||||
while (availaibleSampleCount > 0 && _queuedBuffers.TryPeek(out SDL3AudioBuffer driverBuffer))
|
||||
{
|
||||
ulong sampleStillNeeded = driverBuffer.SampleCount - Interlocked.Read(ref driverBuffer.SamplePlayed);
|
||||
ulong playedAudioBufferSampleCount = Math.Min(sampleStillNeeded, availaibleSampleCount);
|
||||
|
||||
ulong currentSamplePlayed =
|
||||
Interlocked.Add(ref driverBuffer.SamplePlayed, playedAudioBufferSampleCount);
|
||||
availaibleSampleCount -= playedAudioBufferSampleCount;
|
||||
|
||||
if (currentSamplePlayed == driverBuffer.SampleCount)
|
||||
{
|
||||
_queuedBuffers.TryDequeue(out _);
|
||||
|
||||
needUpdate = true;
|
||||
}
|
||||
|
||||
Interlocked.Add(ref _playedSampleCount, playedAudioBufferSampleCount);
|
||||
}
|
||||
|
||||
// Notify the output if needed.
|
||||
if (needUpdate)
|
||||
{
|
||||
_updateRequiredEvent.Set();
|
||||
}
|
||||
}
|
||||
|
||||
public override ulong GetPlayedSampleCount()
|
||||
{
|
||||
return Interlocked.Read(ref _playedSampleCount);
|
||||
}
|
||||
|
||||
public override float GetVolume()
|
||||
{
|
||||
return _volume;
|
||||
}
|
||||
|
||||
public override void PrepareToClose() { }
|
||||
|
||||
public override void QueueBuffer(AudioBuffer buffer)
|
||||
{
|
||||
EnsureAudioStreamSetup(buffer);
|
||||
|
||||
if (_outputStream != 0)
|
||||
{
|
||||
SDL3AudioBuffer driverBuffer = new(buffer.DataPointer, GetSampleCount(buffer));
|
||||
|
||||
_ringBuffer.Write(buffer.Data, 0, buffer.Data.Length);
|
||||
|
||||
_queuedBuffers.Enqueue(driverBuffer);
|
||||
}
|
||||
else
|
||||
{
|
||||
Interlocked.Add(ref _playedSampleCount, GetSampleCount(buffer));
|
||||
|
||||
_updateRequiredEvent.Set();
|
||||
}
|
||||
}
|
||||
|
||||
public override void SetVolume(float volume)
|
||||
{
|
||||
_volume = volume;
|
||||
}
|
||||
|
||||
public override void Start()
|
||||
{
|
||||
if (!_started)
|
||||
{
|
||||
if (_outputStream != 0)
|
||||
{
|
||||
SDL_ResumeAudioStreamDevice(_outputStream);
|
||||
}
|
||||
|
||||
_started = true;
|
||||
}
|
||||
}
|
||||
|
||||
public override void Stop()
|
||||
{
|
||||
if (_started)
|
||||
{
|
||||
if (_outputStream != 0)
|
||||
{
|
||||
SDL_PauseAudioStreamDevice(_outputStream);
|
||||
}
|
||||
|
||||
_started = false;
|
||||
}
|
||||
}
|
||||
|
||||
public override void UnregisterBuffer(AudioBuffer buffer) { }
|
||||
|
||||
public override bool WasBufferFullyConsumed(AudioBuffer buffer)
|
||||
{
|
||||
if (!_queuedBuffers.TryPeek(out SDL3AudioBuffer driverBuffer))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return driverBuffer.DriverIdentifier != buffer.DataPointer;
|
||||
}
|
||||
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing && _driver.Unregister(this))
|
||||
{
|
||||
PrepareToClose();
|
||||
Stop();
|
||||
|
||||
if (_outputStream != 0)
|
||||
{
|
||||
SDL_DestroyAudioStream(_outputStream);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void Dispose()
|
||||
{
|
||||
Dispose(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -9,20 +9,12 @@ namespace Ryujinx.Audio.Backends.Dummy
|
||||
{
|
||||
public class DummyHardwareDeviceDriver : IHardwareDeviceDriver
|
||||
{
|
||||
private readonly ManualResetEvent _updateRequiredEvent;
|
||||
private readonly ManualResetEvent _pauseEvent;
|
||||
private readonly ManualResetEvent _updateRequiredEvent = new(false);
|
||||
private readonly ManualResetEvent _pauseEvent = new(true);
|
||||
|
||||
public static bool IsSupported => true;
|
||||
|
||||
public float Volume { get; set; }
|
||||
|
||||
public DummyHardwareDeviceDriver()
|
||||
{
|
||||
_updateRequiredEvent = new ManualResetEvent(false);
|
||||
_pauseEvent = new ManualResetEvent(true);
|
||||
|
||||
Volume = 1f;
|
||||
}
|
||||
public float Volume { get; set; } = 1f;
|
||||
|
||||
public IHardwareDeviceSession OpenDeviceSession(Direction direction, IVirtualMemoryManager memoryManager, SampleFormat sampleFormat, uint sampleRate, uint channelCount)
|
||||
{
|
||||
@@ -60,7 +52,7 @@ namespace Ryujinx.Audio.Backends.Dummy
|
||||
Dispose(true);
|
||||
}
|
||||
|
||||
protected virtual void Dispose(bool disposing)
|
||||
private void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
|
||||
7
src/Ryujinx.BuildValidationTasks/IValidationTask.cs
Normal file
7
src/Ryujinx.BuildValidationTasks/IValidationTask.cs
Normal file
@@ -0,0 +1,7 @@
|
||||
namespace Ryujinx.BuildValidationTasks
|
||||
{
|
||||
public interface IValidationTask
|
||||
{
|
||||
public bool Execute(string projectPath, bool isGitRunner);
|
||||
}
|
||||
}
|
||||
@@ -1,73 +0,0 @@
|
||||
using System;
|
||||
using Microsoft.Build.Utilities;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.IO;
|
||||
using Newtonsoft.Json;
|
||||
using Microsoft.Build.Framework;
|
||||
|
||||
namespace Ryujinx.BuildValidationTasks
|
||||
{
|
||||
public class LocaleValidationTask : Task
|
||||
{
|
||||
public override bool Execute()
|
||||
{
|
||||
string path = System.Reflection.Assembly.GetExecutingAssembly().Location;
|
||||
|
||||
if (path.Split(["src"], StringSplitOptions.None).Length == 1)
|
||||
{
|
||||
//i assume that we are in a build directory in the solution dir
|
||||
path = new FileInfo(path).Directory!.Parent!.GetDirectories("src")[0].GetDirectories("Ryujinx")[0].GetDirectories("Assets")[0].GetFiles("locales.json")[0].FullName;
|
||||
}
|
||||
else
|
||||
{
|
||||
path = path.Split(["src"], StringSplitOptions.None)[0];
|
||||
path = new FileInfo(path).Directory!.GetDirectories("src")[0].GetDirectories("Ryujinx")[0].GetDirectories("Assets")[0].GetFiles("locales.json")[0].FullName;
|
||||
}
|
||||
|
||||
string data;
|
||||
|
||||
using (StreamReader sr = new(path))
|
||||
{
|
||||
data = sr.ReadToEnd();
|
||||
}
|
||||
|
||||
LocalesJson json = JsonConvert.DeserializeObject<LocalesJson>(data);
|
||||
|
||||
for (int i = 0; i < json.Locales.Count; i++)
|
||||
{
|
||||
LocalesEntry locale = json.Locales[i];
|
||||
|
||||
foreach (string langCode in json.Languages.Where(it => !locale.Translations.ContainsKey(it)))
|
||||
{
|
||||
locale.Translations.Add(langCode, string.Empty);
|
||||
Log.LogMessage(MessageImportance.High, $"Added '{langCode}' to Locale '{locale.ID}'");
|
||||
}
|
||||
|
||||
locale.Translations = locale.Translations.OrderBy(pair => pair.Key).ToDictionary(pair => pair.Key, pair => pair.Value);
|
||||
json.Locales[i] = locale;
|
||||
}
|
||||
|
||||
string jsonString = JsonConvert.SerializeObject(json, Formatting.Indented);
|
||||
|
||||
using (StreamWriter sw = new(path))
|
||||
{
|
||||
sw.Write(jsonString);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
struct LocalesJson
|
||||
{
|
||||
public List<string> Languages { get; set; }
|
||||
public List<LocalesEntry> Locales { get; set; }
|
||||
}
|
||||
|
||||
struct LocalesEntry
|
||||
{
|
||||
public string ID { get; set; }
|
||||
public Dictionary<string, string> Translations { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
||||
117
src/Ryujinx.BuildValidationTasks/LocalesValidationTask.cs
Normal file
117
src/Ryujinx.BuildValidationTasks/LocalesValidationTask.cs
Normal file
@@ -0,0 +1,117 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.IO;
|
||||
using System.Text.Json;
|
||||
using System.Text.Encodings.Web;
|
||||
|
||||
namespace Ryujinx.BuildValidationTasks
|
||||
{
|
||||
public class LocalesValidationTask : IValidationTask
|
||||
{
|
||||
public LocalesValidationTask() { }
|
||||
|
||||
public bool Execute(string projectPath, bool isGitRunner)
|
||||
{
|
||||
Console.WriteLine("Running Locale Validation Task...");
|
||||
|
||||
string path = projectPath + "src/Ryujinx/Assets/locales.json";
|
||||
string data;
|
||||
|
||||
using (StreamReader sr = new(path))
|
||||
{
|
||||
data = sr.ReadToEnd();
|
||||
}
|
||||
|
||||
LocalesJson json;
|
||||
|
||||
if (isGitRunner && data.Contains("\r\n"))
|
||||
throw new FormatException("locales.json is using CRLF line endings! It should be using LF line endings, build locally to fix...");
|
||||
|
||||
try
|
||||
{
|
||||
json = JsonSerializer.Deserialize<LocalesJson>(data);
|
||||
|
||||
}
|
||||
catch (JsonException e)
|
||||
{
|
||||
throw new JsonException(e.Message); //shorter and easier stacktrace
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool encounteredIssue = false;
|
||||
|
||||
for (int i = 0; i < json.Locales.Count; i++)
|
||||
{
|
||||
LocalesEntry locale = json.Locales[i];
|
||||
|
||||
foreach (string langCode in json.Languages.Where(lang => !locale.Translations.ContainsKey(lang)))
|
||||
{
|
||||
encounteredIssue = true;
|
||||
|
||||
if (!isGitRunner)
|
||||
{
|
||||
locale.Translations.Add(langCode, string.Empty);
|
||||
Console.WriteLine($"Added '{langCode}' to Locale '{locale.ID}'");
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine($"Missing '{langCode}' in Locale '{locale.ID}'!");
|
||||
}
|
||||
}
|
||||
|
||||
foreach (string langCode in json.Languages.Where(lang => locale.Translations.ContainsKey(lang) && lang != "en_US" && locale.Translations[lang] == locale.Translations["en_US"]))
|
||||
{
|
||||
encounteredIssue = true;
|
||||
|
||||
if (!isGitRunner)
|
||||
{
|
||||
locale.Translations[langCode] = string.Empty;
|
||||
Console.WriteLine($"Lanugage '{langCode}' is a duplicate of en_US in Locale '{locale.ID}'! Resetting it...");
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine($"Lanugage '{langCode}' is a duplicate of en_US in Locale '{locale.ID}'!");
|
||||
}
|
||||
}
|
||||
|
||||
locale.Translations = locale.Translations.OrderBy(pair => pair.Key).ToDictionary(pair => pair.Key, pair => pair.Value);
|
||||
json.Locales[i] = locale;
|
||||
}
|
||||
|
||||
if (isGitRunner && encounteredIssue)
|
||||
throw new JsonException("1 or more locales are invalid!");
|
||||
|
||||
JsonSerializerOptions jsonOptions = new JsonSerializerOptions()
|
||||
{
|
||||
WriteIndented = true,
|
||||
NewLine = "\n",
|
||||
Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping
|
||||
};
|
||||
|
||||
string jsonString = JsonSerializer.Serialize(json, jsonOptions);
|
||||
|
||||
using (StreamWriter sw = new(path))
|
||||
{
|
||||
sw.Write(jsonString);
|
||||
}
|
||||
|
||||
Console.WriteLine("Finished Locale Validation Task!");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
struct LocalesJson
|
||||
{
|
||||
public List<string> Languages { get; set; }
|
||||
public List<LocalesEntry> Locales { get; set; }
|
||||
}
|
||||
|
||||
struct LocalesEntry
|
||||
{
|
||||
public string ID { get; set; }
|
||||
public Dictionary<string, string> Translations { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
||||
37
src/Ryujinx.BuildValidationTasks/Program.cs
Normal file
37
src/Ryujinx.BuildValidationTasks/Program.cs
Normal file
@@ -0,0 +1,37 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
namespace Ryujinx.BuildValidationTasks
|
||||
{
|
||||
public class Program
|
||||
{
|
||||
static void Main(string[] args)
|
||||
{
|
||||
// Display the number of command line arguments.
|
||||
if (args.Length == 0)
|
||||
throw new ArgumentException("Error: too few arguments!");
|
||||
|
||||
string path = args[0];
|
||||
|
||||
if (string.IsNullOrEmpty(path))
|
||||
throw new ArgumentException("Error: path is null or empty!");
|
||||
|
||||
if (!Path.Exists(path))
|
||||
throw new FileLoadException($"path {{{path}}} does not exist!");
|
||||
|
||||
path = Path.GetFullPath(path);
|
||||
|
||||
if (!Directory.GetDirectories(path).Contains($"{path}src"))
|
||||
throw new FileLoadException($"path {{{path}}} is not a valid ryujinx project!");
|
||||
|
||||
bool isGitRunner = path.Contains("runner") || path.Contains("D:\\a\\Ryujinx\\Ryujinx");
|
||||
if (isGitRunner)
|
||||
Console.WriteLine("Is Git Runner!");
|
||||
|
||||
// Run tasks
|
||||
// Pass extra info needed in the task constructors
|
||||
new LocalesValidationTask().Execute(path, isGitRunner);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,19 +1,17 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard2.0</TargetFramework>
|
||||
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
|
||||
<OutputType>Exe</OutputType>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Build.Utilities.Core" />
|
||||
<PackageReference Include="Newtonsoft.Json" />
|
||||
</ItemGroup>
|
||||
<Target Name="PostBuildTarget" AfterTargets="AfterBuild">
|
||||
<Message Text="Running Validation Project" Importance="high" />
|
||||
|
||||
<UsingTask TaskName="Ryujinx.BuildValidationTasks.LocaleValidationTask" TaskFactory="TaskHostFactory" AssemblyFile="$(OutDir)Ryujinx.BuildValidationTasks.dll" />
|
||||
|
||||
<Target Name="LocalesJsonValidation" AfterTargets="AfterRebuild">
|
||||
<LocaleValidationTask />
|
||||
<Exec WorkingDirectory="$(ProjectDir)bin\Debug\$(TargetFramework)\"
|
||||
Command="dotnet Ryujinx.BuildValidationTasks.dll "$(ProjectDir)..\..\\""
|
||||
ConsoleToMsBuild="true"
|
||||
Condition="'$(RuntimeIdentifier)' == ''"
|
||||
/>
|
||||
</Target>
|
||||
|
||||
</Project>
|
||||
</Project>
|
||||
60
src/Ryujinx.Common/Configuration/DirtyHack.cs
Normal file
60
src/Ryujinx.Common/Configuration/DirtyHack.cs
Normal file
@@ -0,0 +1,60 @@
|
||||
using Gommon;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Ryujinx.Common.Configuration
|
||||
{
|
||||
[Flags]
|
||||
public enum DirtyHack : byte
|
||||
{
|
||||
Xc2MenuSoftlockFix = 1,
|
||||
ShaderTranslationDelay = 2
|
||||
}
|
||||
|
||||
public readonly struct EnabledDirtyHack(DirtyHack hack, int value)
|
||||
{
|
||||
public DirtyHack Hack => hack;
|
||||
public int Value => value;
|
||||
|
||||
|
||||
|
||||
public ulong Pack() => Raw.PackBitFields(PackedFormat);
|
||||
|
||||
public static EnabledDirtyHack Unpack(ulong packedHack)
|
||||
{
|
||||
var unpackedFields = packedHack.UnpackBitFields(PackedFormat);
|
||||
if (unpackedFields is not [var hack, var value])
|
||||
throw new Exception("The unpack operation on the integer resulted in an invalid unpacked result.");
|
||||
|
||||
return new EnabledDirtyHack((DirtyHack)hack, (int)value);
|
||||
}
|
||||
|
||||
private uint[] Raw => [(uint)Hack, (uint)Value.CoerceAtLeast(0)];
|
||||
|
||||
public static readonly byte[] PackedFormat = [8, 32];
|
||||
}
|
||||
|
||||
public class DirtyHacks : Dictionary<DirtyHack, int>
|
||||
{
|
||||
public DirtyHacks(IEnumerable<EnabledDirtyHack> hacks)
|
||||
=> hacks.ForEach(edh => Add(edh.Hack, edh.Value));
|
||||
|
||||
public DirtyHacks(ulong[] packedHacks) : this(packedHacks.Select(EnabledDirtyHack.Unpack)) {}
|
||||
|
||||
public ulong[] PackEntries()
|
||||
=> Entries.Select(it => it.Pack()).ToArray();
|
||||
|
||||
public EnabledDirtyHack[] Entries
|
||||
=> this
|
||||
.Select(it => new EnabledDirtyHack(it.Key, it.Value))
|
||||
.ToArray();
|
||||
|
||||
public static implicit operator DirtyHacks(EnabledDirtyHack[] hacks) => new(hacks);
|
||||
public static implicit operator DirtyHacks(ulong[] packedHacks) => new(packedHacks);
|
||||
|
||||
public new int this[DirtyHack hack] => TryGetValue(hack, out var value) ? value : -1;
|
||||
|
||||
public bool IsEnabled(DirtyHack hack) => ContainsKey(hack);
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
using System;
|
||||
|
||||
namespace Ryujinx.Common.Configuration
|
||||
{
|
||||
[Flags]
|
||||
public enum DirtyHacks
|
||||
{
|
||||
None = 0,
|
||||
Xc2MenuSoftlockFix = 1 << 10
|
||||
}
|
||||
}
|
||||
@@ -8,6 +8,6 @@ namespace Ryujinx.Common.Configuration.Hid
|
||||
{
|
||||
Invalid,
|
||||
WindowKeyboard,
|
||||
GamepadSDL2,
|
||||
GamepadSDL3
|
||||
}
|
||||
}
|
||||
|
||||
@@ -58,7 +58,7 @@ namespace Ryujinx.Common.Configuration.Hid
|
||||
return backendType switch
|
||||
{
|
||||
InputBackendType.WindowKeyboard => JsonSerializer.Deserialize(ref reader, _serializerContext.StandardKeyboardInputConfig),
|
||||
InputBackendType.GamepadSDL2 => JsonSerializer.Deserialize(ref reader, _serializerContext.StandardControllerInputConfig),
|
||||
InputBackendType.GamepadSDL3 => JsonSerializer.Deserialize(ref reader, _serializerContext.StandardControllerInputConfig),
|
||||
_ => throw new InvalidOperationException($"Unknown backend type {backendType}"),
|
||||
};
|
||||
}
|
||||
@@ -70,7 +70,7 @@ namespace Ryujinx.Common.Configuration.Hid
|
||||
case InputBackendType.WindowKeyboard:
|
||||
JsonSerializer.Serialize(writer, value as StandardKeyboardInputConfig, _serializerContext.StandardKeyboardInputConfig);
|
||||
break;
|
||||
case InputBackendType.GamepadSDL2:
|
||||
case InputBackendType.GamepadSDL3:
|
||||
JsonSerializer.Serialize(writer, value as StandardControllerInputConfig, _serializerContext.StandardControllerInputConfig);
|
||||
break;
|
||||
default:
|
||||
|
||||
@@ -8,10 +8,10 @@ namespace Ryujinx.Common
|
||||
public static class StreamExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Writes a <see cref="ReadOnlySpan{int}" /> to this stream.
|
||||
/// Writes an int span to this stream.
|
||||
///
|
||||
/// This default implementation converts each buffer value to a stack-allocated
|
||||
/// byte array, then writes it to the Stream using <cref="System.Stream.Write(byte[])" />.
|
||||
/// byte array, then writes it to the Stream using <see cref="Stream.Write(ReadOnlySpan{byte})" />.
|
||||
/// </summary>
|
||||
/// <param name="stream">The stream to be written to</param>
|
||||
/// <param name="buffer">The buffer of values to be written</param>
|
||||
|
||||
@@ -3,7 +3,7 @@ using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Runtime.Versioning;
|
||||
|
||||
namespace Ryujinx.UI.Common.Helper
|
||||
namespace Ryujinx.Common.Helper
|
||||
{
|
||||
public static partial class ConsoleHelper
|
||||
{
|
||||
@@ -8,7 +8,7 @@ using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Runtime.Versioning;
|
||||
|
||||
namespace Ryujinx.UI.Common.Helper
|
||||
namespace Ryujinx.Common.Helper
|
||||
{
|
||||
public static partial class FileAssociationHelper
|
||||
{
|
||||
@@ -3,7 +3,7 @@ using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Runtime.Versioning;
|
||||
|
||||
namespace Ryujinx.UI.Common.Helper
|
||||
namespace Ryujinx.Common.Helper
|
||||
{
|
||||
[SupportedOSPlatform("linux")]
|
||||
public static class LinuxHelper
|
||||
@@ -2,7 +2,7 @@ using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Runtime.Versioning;
|
||||
|
||||
namespace Ryujinx.UI.Common.Helper
|
||||
namespace Ryujinx.Common.Helper
|
||||
{
|
||||
[SupportedOSPlatform("macos")]
|
||||
public static partial class ObjectiveC
|
||||
@@ -5,7 +5,7 @@ using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Ryujinx.UI.Common.Helper
|
||||
namespace Ryujinx.Common.Helper
|
||||
{
|
||||
public static partial class OpenHelper
|
||||
{
|
||||
@@ -53,6 +53,9 @@ namespace Ryujinx.Common
|
||||
{
|
||||
public static void LogValueChange<T>(LogClass logClass, ReactiveEventArgs<T> eventArgs, string valueName)
|
||||
{
|
||||
if (eventArgs.AreValuesEqual)
|
||||
return;
|
||||
|
||||
string message = string.Create(CultureInfo.InvariantCulture, $"{valueName} set to: {eventArgs.NewValue}");
|
||||
|
||||
Logger.Info?.Print(logClass, message);
|
||||
@@ -65,5 +68,22 @@ namespace Ryujinx.Common
|
||||
{
|
||||
public T OldValue { get; } = oldValue;
|
||||
public T NewValue { get; } = newValue;
|
||||
|
||||
public bool AreValuesEqual
|
||||
{
|
||||
get
|
||||
{
|
||||
if (OldValue == null && NewValue == null)
|
||||
return true;
|
||||
|
||||
if (OldValue == null && NewValue != null)
|
||||
return false;
|
||||
|
||||
if (OldValue != null && NewValue == null)
|
||||
return false;
|
||||
|
||||
return OldValue!.Equals(NewValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
10
src/Ryujinx.Common/RyujinxException.cs
Normal file
10
src/Ryujinx.Common/RyujinxException.cs
Normal file
@@ -0,0 +1,10 @@
|
||||
using System;
|
||||
|
||||
namespace Ryujinx.Common
|
||||
{
|
||||
public class RyujinxException : Exception
|
||||
{
|
||||
public RyujinxException(string message) : base(message)
|
||||
{ }
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
using Gommon;
|
||||
using Gommon;
|
||||
using Ryujinx.Common.Configuration;
|
||||
using System;
|
||||
using System.Linq;
|
||||
@@ -8,7 +8,7 @@ namespace Ryujinx.Common
|
||||
{
|
||||
public static class TitleIDs
|
||||
{
|
||||
public static Optional<string> CurrentApplication;
|
||||
public static ReactiveObject<Optional<string>> CurrentApplication { get; set; } = new();
|
||||
|
||||
public static GraphicsBackend SelectGraphicsBackend(string titleId, GraphicsBackend currentBackend)
|
||||
{
|
||||
@@ -35,6 +35,8 @@ namespace Ryujinx.Common
|
||||
"010028600EBDA000", // Mario 3D World
|
||||
"0100152000022000", // Mario Kart 8 Deluxe
|
||||
"01005CA01580E000", // Persona 5
|
||||
"0100187003A36000", // Pokémon: Let's Go, Evoli!
|
||||
"010003f003a34000", // Pokémon: Let's Go, Pikachu!
|
||||
"01008C0016544000", // Sea of Stars
|
||||
"01006A800016E000", // Smash Ultimate
|
||||
"0100000000010000", // Super Mario Odyessy
|
||||
@@ -45,6 +47,9 @@ namespace Ryujinx.Common
|
||||
|
||||
public static readonly string[] DiscordGameAssetKeys =
|
||||
[
|
||||
"010008900705c000", // Dragon Quest Builders
|
||||
"010042000a986000", // Dragon Quest Builders 2
|
||||
|
||||
"010055d009f78000", // Fire Emblem: Three Houses
|
||||
"0100a12011cc8000", // Fire Emblem: Shadow Dragon
|
||||
"0100a6301214e000", // Fire Emblem Engage
|
||||
@@ -103,17 +108,18 @@ namespace Ryujinx.Common
|
||||
"0100f4c009322000", // Pikmin 3 Deluxe
|
||||
"0100b7c00933a000", // Pikmin 4
|
||||
|
||||
"0100f4300bf2c000", // New Pokémon Snap
|
||||
"0100000011d90000", // Pokémon Brilliant Diamond
|
||||
"01001f5010dfa000", // Pokémon Legends: Arceus
|
||||
"010003f003a34000", // Pokémon: Let's Go Pikachu!
|
||||
"0100187003a36000", // Pokémon: Let's Go Eevee!
|
||||
"0100abf008968000", // Pokémon Sword
|
||||
"01008db008c2c000", // Pokémon Shield
|
||||
"0100000011d90000", // Pokémon Brilliant Diamond
|
||||
"010018e011d92000", // Pokémon Shining Pearl
|
||||
"01001f5010dfa000", // Pokémon Legends: Arceus
|
||||
"01003d200baa2000", // Pokémon Mystery Dungeon - Rescue Team DX
|
||||
"0100a3d008c5c000", // Pokémon Scarlet
|
||||
"01008db008c2c000", // Pokémon Shield
|
||||
"010018e011d92000", // Pokémon Shining Pearl
|
||||
"0100abf008968000", // Pokémon Sword
|
||||
"01008f6008c5e000", // Pokémon Violet
|
||||
"0100b3f000be2000", // Pokkén Tournament DX
|
||||
"0100f4300bf2c000", // New Pokémon Snap
|
||||
|
||||
"01003bc0000a0000", // Splatoon 2 (US)
|
||||
"0100f8f0000a2000", // Splatoon 2 (EU)
|
||||
@@ -163,12 +169,21 @@ namespace Ryujinx.Common
|
||||
"01005ea01c0fc000", // SONIC X SHADOW GENERATIONS
|
||||
"01005ea01c0fc001", // ^
|
||||
|
||||
"0100ff500e34a000", // Xenoblade Chronicles - Definitive Edition
|
||||
"0100e95004038000", // Xenoblade Chronicles 2
|
||||
"010074f013262000", // Xenoblade Chronicles 3
|
||||
|
||||
"010056e00853a000", // A Hat in Time
|
||||
"0100fd1014726000", // Baldurs Gate: Dark Alliance
|
||||
"0100dbf01000a000", // Burnout Paradise Remastered
|
||||
"0100744001588000", // Cars 3: Driven to Win
|
||||
"0100b41013c82000", // Cruis'n Blast
|
||||
"010085900337e000", // Death Squared
|
||||
"01001b300b9be000", // Diablo III: Eternal Collection
|
||||
"01008c8012920000", // Dying Light Platinum Edition
|
||||
"01001cc01b2d4000", // Goat Simulator 3
|
||||
"01003620068ea000", // Hand of Fate 2
|
||||
"010085500130a000", // Lego City: Undercover
|
||||
"010073c01af34000", // LEGO Horizon Adventures
|
||||
"0100770008dd8000", // Monster Hunter Generations Ultimate
|
||||
"0100b04011742000", // Monster Hunter Rise
|
||||
@@ -187,6 +202,8 @@ namespace Ryujinx.Common
|
||||
"01000a10041ea000", // The Elder Scrolls V: Skyrim
|
||||
"010057a01e4d4000", // TSUKIHIME -A piece of blue glass moon-
|
||||
"010080b00ad66000", // Undertale
|
||||
"010069401adb8000", // Unicorn Overlord
|
||||
"0100534009ff2000", // Yonder - The cloud catcher chronicles
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
namespace Ryujinx.UI.Common
|
||||
namespace Ryujinx.Common.UI
|
||||
{
|
||||
/// <summary>
|
||||
/// Represent a common error that could be reported to the user by the emulator.
|
||||
@@ -40,5 +40,35 @@ namespace Ryujinx.Common
|
||||
|
||||
return (value >> 32) | (value << 32);
|
||||
}
|
||||
|
||||
// Never actually written bit packing logic before, so I looked it up.
|
||||
// This code is from https://gist.github.com/Alan-FGR/04938e93e2bffdf5802ceb218a37c195
|
||||
|
||||
public static ulong PackBitFields(this uint[] values, byte[] bitFields)
|
||||
{
|
||||
ulong retVal = values[0]; //we set the first value right away
|
||||
for (int f = 1; f < values.Length; f++)
|
||||
{
|
||||
retVal <<= bitFields[f]; // we shift the previous value
|
||||
retVal += values[f];// and add our current value
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
|
||||
public static uint[] UnpackBitFields(this ulong packed, byte[] bitFields)
|
||||
{
|
||||
int fields = bitFields.Length - 1; // number of fields to unpack
|
||||
uint[] retArr = new uint[fields + 1]; // init return array
|
||||
int curPos = 0; // current field bit position (start)
|
||||
int lastEnd; // position where last field ended
|
||||
for (int f = fields; f >= 0; f--) // loop from last
|
||||
{
|
||||
lastEnd = curPos; // we store where the last value ended
|
||||
curPos += bitFields[f]; // we get where the current value starts
|
||||
int leftShift = 64 - curPos; // we figure how much left shift we gotta apply for the other numbers to overflow into oblivion
|
||||
retArr[f] = (uint)((packed << leftShift) >> leftShift + lastEnd); // we do magic
|
||||
}
|
||||
return retArr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using Ryujinx.Common;
|
||||
using Ryujinx.Common.Configuration;
|
||||
using Ryujinx.Graphics.Device;
|
||||
using Ryujinx.Graphics.GAL;
|
||||
using Ryujinx.Graphics.Gpu.Engine.GPFifo;
|
||||
@@ -90,6 +91,13 @@ namespace Ryujinx.Graphics.Gpu
|
||||
/// Support buffer updater.
|
||||
/// </summary>
|
||||
internal SupportBufferUpdater SupportBufferUpdater { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Enabled dirty hacks.
|
||||
/// Used for workarounds to emulator bugs we can't fix/don't know how to fix yet.
|
||||
/// </summary>
|
||||
internal DirtyHacks DirtyHacks { get; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Host hardware capabilities.
|
||||
@@ -113,7 +121,7 @@ namespace Ryujinx.Graphics.Gpu
|
||||
/// Creates a new instance of the GPU emulation context.
|
||||
/// </summary>
|
||||
/// <param name="renderer">Host renderer</param>
|
||||
public GpuContext(IRenderer renderer)
|
||||
public GpuContext(IRenderer renderer, DirtyHacks hacks)
|
||||
{
|
||||
Renderer = renderer;
|
||||
|
||||
@@ -136,6 +144,8 @@ namespace Ryujinx.Graphics.Gpu
|
||||
|
||||
SupportBufferUpdater = new SupportBufferUpdater(renderer);
|
||||
|
||||
DirtyHacks = hacks;
|
||||
|
||||
_firstTimestamp = ConvertNanosecondsToTicks((ulong)PerformanceCounter.ElapsedNanoseconds);
|
||||
}
|
||||
|
||||
|
||||
@@ -46,6 +46,12 @@ namespace Ryujinx.Graphics.Gpu
|
||||
/// Enables or disables high-level emulation of common GPU Macro code.
|
||||
/// </summary>
|
||||
public static bool EnableMacroHLE = true;
|
||||
|
||||
/// <summary>
|
||||
/// Title id of the current running game.
|
||||
/// Used by the shader cache.
|
||||
/// </summary>
|
||||
public static string TitleId;
|
||||
|
||||
/// <summary>
|
||||
/// Enables or disables the shader cache.
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using Ryujinx.Common.Configuration;
|
||||
using Ryujinx.Common.Logging;
|
||||
using Ryujinx.Graphics.GAL;
|
||||
using Ryujinx.Graphics.Shader;
|
||||
@@ -366,6 +367,9 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache
|
||||
{
|
||||
try
|
||||
{
|
||||
if (_context.Capabilities.Api == TargetApi.Metal && _context.DirtyHacks.IsEnabled(DirtyHack.ShaderTranslationDelay))
|
||||
Thread.Sleep(_context.DirtyHacks[DirtyHack.ShaderTranslationDelay]);
|
||||
|
||||
AsyncProgramTranslation asyncTranslation = new(guestShaders, specState, programIndex, isCompute);
|
||||
_asyncTranslationQueue.Add(asyncTranslation, _cancellationToken);
|
||||
}
|
||||
|
||||
@@ -117,8 +117,8 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||
/// </summary>
|
||||
private static string GetDiskCachePath()
|
||||
{
|
||||
return GraphicsConfig.EnableShaderCache && TitleIDs.CurrentApplication.HasValue
|
||||
? Path.Combine(AppDataManager.GamesDirPath, TitleIDs.CurrentApplication, "cache", "shader")
|
||||
return GraphicsConfig.EnableShaderCache && GraphicsConfig.TitleId != null
|
||||
? Path.Combine(AppDataManager.GamesDirPath, GraphicsConfig.TitleId, "cache", "shader")
|
||||
: null;
|
||||
}
|
||||
|
||||
|
||||
@@ -22,13 +22,15 @@ namespace Ryujinx.Graphics.Metal
|
||||
|
||||
private int _requestedWidth;
|
||||
private int _requestedHeight;
|
||||
|
||||
// private bool _vsyncEnabled;
|
||||
|
||||
private AntiAliasing _currentAntiAliasing;
|
||||
private bool _updateEffect;
|
||||
private IPostProcessingEffect _effect;
|
||||
private IScalingFilter _scalingFilter;
|
||||
private bool _isLinear;
|
||||
|
||||
public bool IsVSyncEnabled => _metalLayer.DisplaySyncEnabled;
|
||||
|
||||
// private float _scalingFilterLevel;
|
||||
private bool _updateScalingFilter;
|
||||
private ScalingFilter _currentScalingFilter;
|
||||
@@ -40,7 +42,7 @@ namespace Ryujinx.Graphics.Metal
|
||||
_metalLayer = metalLayer;
|
||||
}
|
||||
|
||||
private unsafe void ResizeIfNeeded()
|
||||
private void ResizeIfNeeded()
|
||||
{
|
||||
if (_requestedWidth != 0 && _requestedHeight != 0)
|
||||
{
|
||||
@@ -54,7 +56,7 @@ namespace Ryujinx.Graphics.Metal
|
||||
}
|
||||
}
|
||||
|
||||
public unsafe void Present(ITexture texture, ImageCrop crop, Action swapBuffersCallback)
|
||||
public void Present(ITexture texture, ImageCrop crop, Action swapBuffersCallback)
|
||||
{
|
||||
if (_renderer.Pipeline is Pipeline pipeline && texture is Texture tex)
|
||||
{
|
||||
@@ -141,15 +143,7 @@ namespace Ryujinx.Graphics.Metal
|
||||
|
||||
public void ChangeVSyncMode(VSyncMode vSyncMode)
|
||||
{
|
||||
switch (vSyncMode)
|
||||
{
|
||||
case VSyncMode.Unbounded:
|
||||
_metalLayer.DisplaySyncEnabled = false;
|
||||
break;
|
||||
case VSyncMode.Switch:
|
||||
_metalLayer.DisplaySyncEnabled = true;
|
||||
break;
|
||||
}
|
||||
_metalLayer.DisplaySyncEnabled = vSyncMode is VSyncMode.Switch;
|
||||
}
|
||||
|
||||
public void SetAntiAliasing(AntiAliasing effect)
|
||||
|
||||
@@ -2,8 +2,8 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
{
|
||||
internal enum BitDepth
|
||||
{
|
||||
Bits8 = 8, /**< 8 bits */
|
||||
Bits10 = 10, /**< 10 bits */
|
||||
Bits12 = 12, /**< 12 bits */
|
||||
Bits8 = 8, // < 8 bits
|
||||
Bits10 = 10, // < 10 bits
|
||||
Bits12 = 12, // < 12 bits
|
||||
}
|
||||
}
|
||||
|
||||
@@ -168,13 +168,15 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
return BinarySearch(list, offset, size) >= 0;
|
||||
}
|
||||
|
||||
public readonly IEnumerable<Range> FindOverlaps(int offset, int size)
|
||||
public readonly List<Range> FindOverlaps(int offset, int size)
|
||||
{
|
||||
var list = _ranges;
|
||||
if (list == null)
|
||||
{
|
||||
yield break;
|
||||
return null;
|
||||
}
|
||||
|
||||
List<Range> result = null;
|
||||
|
||||
int index = BinarySearch(list, offset, size);
|
||||
|
||||
@@ -187,10 +189,12 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
|
||||
do
|
||||
{
|
||||
yield return list[index++];
|
||||
(result ??= []).Add(list[index++]);
|
||||
}
|
||||
while (index < list.Count && list[index].OverlapsWith(offset, size));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private static int BinarySearch(List<Range> list, int offset, int size)
|
||||
|
||||
@@ -92,7 +92,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
DriverId.MesaDozen => "Dozen",
|
||||
DriverId.MesaNvk => "NVK",
|
||||
DriverId.ImaginationOpenSourceMesa => "Imagination (Open)",
|
||||
DriverId.MesaAgxv => "Honeykrisp",
|
||||
DriverId.MesaHoneykrisp => "Honeykrisp",
|
||||
_ => id.ToString(),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using Gommon;
|
||||
using Ryujinx.Common.Configuration;
|
||||
using Ryujinx.Common.Logging;
|
||||
using Ryujinx.Graphics.GAL;
|
||||
@@ -890,7 +891,12 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
|
||||
private void PrintGpuInformation()
|
||||
{
|
||||
Logger.Notice.Print(LogClass.Gpu, $"{GpuVendor} {GpuRenderer} ({GpuVersion})");
|
||||
string gpuInfoMessage = $"{GpuRenderer} ({GpuVersion})";
|
||||
if (!GpuRenderer.StartsWithIgnoreCase(GpuVendor))
|
||||
gpuInfoMessage = gpuInfoMessage.Prepend(GpuVendor);
|
||||
|
||||
Logger.Notice.Print(LogClass.Gpu, gpuInfoMessage);
|
||||
|
||||
Logger.Notice.Print(LogClass.Gpu, $"GPU Memory: {GetTotalGPUMemory() / (1024 * 1024)} MiB");
|
||||
}
|
||||
|
||||
|
||||
@@ -189,10 +189,10 @@ namespace Ryujinx.HLE
|
||||
/// </summary>
|
||||
public Action RefreshInputConfig { internal get; set; }
|
||||
|
||||
/**
|
||||
* The desired hacky workarounds.
|
||||
*/
|
||||
public DirtyHacks Hacks { internal get; set; }
|
||||
/// <summary>
|
||||
/// The desired hacky workarounds.
|
||||
/// </summary>
|
||||
public EnabledDirtyHack[] Hacks { internal get; set; }
|
||||
|
||||
public HLEConfiguration(VirtualFileSystem virtualFileSystem,
|
||||
LibHacHorizonManager libHacHorizonManager,
|
||||
@@ -224,7 +224,7 @@ namespace Ryujinx.HLE
|
||||
string multiplayerLdnPassphrase,
|
||||
string multiplayerLdnServer,
|
||||
int customVSyncInterval,
|
||||
DirtyHacks dirtyHacks = DirtyHacks.None)
|
||||
EnabledDirtyHack[] dirtyHacks = null)
|
||||
{
|
||||
VirtualFileSystem = virtualFileSystem;
|
||||
LibHacHorizonManager = libHacHorizonManager;
|
||||
@@ -256,7 +256,7 @@ namespace Ryujinx.HLE
|
||||
MultiplayerDisableP2p = multiplayerDisableP2p;
|
||||
MultiplayerLdnPassphrase = multiplayerLdnPassphrase;
|
||||
MultiplayerLdnServer = multiplayerLdnServer;
|
||||
Hacks = dirtyHacks;
|
||||
Hacks = dirtyHacks ?? [];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,10 +26,20 @@ namespace Ryujinx.HLE.HOS.Applets
|
||||
{
|
||||
_normalSession = normalSession;
|
||||
_interactiveSession = interactiveSession;
|
||||
|
||||
// TODO(jduncanator): Parse PlayerSelectConfig from input data
|
||||
_normalSession.Push(BuildResponse());
|
||||
|
||||
|
||||
UserProfile selected = _system.Device.UIHandler.ShowPlayerSelectDialog();
|
||||
if (selected == null)
|
||||
{
|
||||
_normalSession.Push(BuildResponse());
|
||||
}
|
||||
else if (selected.UserId == new UserId("00000000000000000000000000000080"))
|
||||
{
|
||||
_normalSession.Push(BuildGuestResponse());
|
||||
}
|
||||
else
|
||||
{
|
||||
_normalSession.Push(BuildResponse(selected));
|
||||
}
|
||||
AppletStateChanged?.Invoke(this, null);
|
||||
|
||||
_system.ReturnFocus();
|
||||
@@ -37,16 +47,34 @@ namespace Ryujinx.HLE.HOS.Applets
|
||||
return ResultCode.Success;
|
||||
}
|
||||
|
||||
private byte[] BuildResponse()
|
||||
private byte[] BuildResponse(UserProfile selectedUser)
|
||||
{
|
||||
UserProfile currentUser = _system.AccountManager.LastOpenedUser;
|
||||
|
||||
using MemoryStream stream = MemoryStreamManager.Shared.GetStream();
|
||||
using BinaryWriter writer = new(stream);
|
||||
|
||||
writer.Write((ulong)PlayerSelectResult.Success);
|
||||
|
||||
currentUser.UserId.Write(writer);
|
||||
selectedUser.UserId.Write(writer);
|
||||
|
||||
return stream.ToArray();
|
||||
}
|
||||
|
||||
private byte[] BuildGuestResponse()
|
||||
{
|
||||
using MemoryStream stream = MemoryStreamManager.Shared.GetStream();
|
||||
using BinaryWriter writer = new(stream);
|
||||
|
||||
writer.Write(new byte());
|
||||
|
||||
return stream.ToArray();
|
||||
}
|
||||
|
||||
private byte[] BuildResponse()
|
||||
{
|
||||
using MemoryStream stream = MemoryStreamManager.Shared.GetStream();
|
||||
using BinaryWriter writer = new(stream);
|
||||
|
||||
writer.Write((ulong)PlayerSelectResult.Failure);
|
||||
|
||||
return stream.ToArray();
|
||||
}
|
||||
|
||||
@@ -284,7 +284,7 @@ namespace Ryujinx.HLE.HOS
|
||||
ProcessCreationInfo creationInfo = new("Service", 1, 0, 0x8000000, 1, Flags, 0, 0);
|
||||
|
||||
uint[] defaultCapabilities = {
|
||||
0x030363F7,
|
||||
(((uint)KScheduler.CpuCoresCount - 1) << 24) + (((uint)KScheduler.CpuCoresCount - 1) << 16) + 0x63F7u,
|
||||
0x1FFFFFCF,
|
||||
0x207FFFEF,
|
||||
0x47E0060F,
|
||||
|
||||
@@ -63,6 +63,7 @@ namespace Ryujinx.HLE.HOS.Kernel
|
||||
TickSource = tickSource;
|
||||
Device = device;
|
||||
Memory = memory;
|
||||
KScheduler.CpuCoresCount = device.CpuCoresCount;
|
||||
|
||||
Running = true;
|
||||
|
||||
|
||||
@@ -37,7 +37,7 @@ namespace Ryujinx.HLE.HOS.Kernel
|
||||
return result;
|
||||
}
|
||||
|
||||
process.DefaultCpuCore = 3;
|
||||
process.DefaultCpuCore = KScheduler.CpuCoresCount - 1;
|
||||
|
||||
context.Processes.TryAdd(process.Pid, process);
|
||||
|
||||
|
||||
@@ -277,7 +277,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
|
||||
return result;
|
||||
}
|
||||
|
||||
result = Capabilities.InitializeForUser(capabilities, MemoryManager);
|
||||
result = Capabilities.InitializeForUser(capabilities, MemoryManager, IsApplication);
|
||||
|
||||
if (result != Result.Success)
|
||||
{
|
||||
|
||||
@@ -35,15 +35,15 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
|
||||
DebuggingFlags &= ~3u;
|
||||
KernelReleaseVersion = KProcess.KernelVersionPacked;
|
||||
|
||||
return Parse(capabilities, memoryManager);
|
||||
return Parse(capabilities, memoryManager, false);
|
||||
}
|
||||
|
||||
public Result InitializeForUser(ReadOnlySpan<uint> capabilities, KPageTableBase memoryManager)
|
||||
public Result InitializeForUser(ReadOnlySpan<uint> capabilities, KPageTableBase memoryManager, bool isApplication)
|
||||
{
|
||||
return Parse(capabilities, memoryManager);
|
||||
return Parse(capabilities, memoryManager, isApplication);
|
||||
}
|
||||
|
||||
private Result Parse(ReadOnlySpan<uint> capabilities, KPageTableBase memoryManager)
|
||||
private Result Parse(ReadOnlySpan<uint> capabilities, KPageTableBase memoryManager, bool isApplication)
|
||||
{
|
||||
int mask0 = 0;
|
||||
int mask1 = 0;
|
||||
@@ -54,7 +54,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
|
||||
|
||||
if (cap.GetCapabilityType() != CapabilityType.MapRange)
|
||||
{
|
||||
Result result = ParseCapability(cap, ref mask0, ref mask1, memoryManager);
|
||||
Result result = ParseCapability(cap, ref mask0, ref mask1, memoryManager, isApplication);
|
||||
|
||||
if (result != Result.Success)
|
||||
{
|
||||
@@ -120,7 +120,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
private Result ParseCapability(uint cap, ref int mask0, ref int mask1, KPageTableBase memoryManager)
|
||||
private Result ParseCapability(uint cap, ref int mask0, ref int mask1, KPageTableBase memoryManager, bool isApplication)
|
||||
{
|
||||
CapabilityType code = cap.GetCapabilityType();
|
||||
|
||||
@@ -176,6 +176,9 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
|
||||
AllowedCpuCoresMask = GetMaskFromMinMax(lowestCpuCore, highestCpuCore);
|
||||
AllowedThreadPriosMask = GetMaskFromMinMax(lowestThreadPrio, highestThreadPrio);
|
||||
|
||||
if (isApplication)
|
||||
Ryujinx.Common.Logging.Logger.Info?.Print(Ryujinx.Common.Logging.LogClass.Application, $"Application requested cores with index range {lowestCpuCore} to {highestCpuCore}");
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
@@ -2683,7 +2683,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
||||
return KernelResult.InvalidCombination;
|
||||
}
|
||||
|
||||
if ((uint)preferredCore > 3)
|
||||
if ((uint)preferredCore > KScheduler.CpuCoresCount - 1)
|
||||
{
|
||||
if ((preferredCore | 2) != -1)
|
||||
{
|
||||
|
||||
@@ -9,13 +9,11 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
|
||||
partial class KScheduler : IDisposable
|
||||
{
|
||||
public const int PrioritiesCount = 64;
|
||||
public const int CpuCoresCount = 4;
|
||||
public static int CpuCoresCount;
|
||||
|
||||
private const int RoundRobinTimeQuantumMs = 10;
|
||||
|
||||
private static readonly int[] _preemptionPriorities = { 59, 59, 59, 63 };
|
||||
|
||||
private static readonly int[] _srcCoresHighestPrioThreads = new int[CpuCoresCount];
|
||||
private static int[] _srcCoresHighestPrioThreads;
|
||||
|
||||
private readonly KernelContext _context;
|
||||
private readonly int _coreId;
|
||||
@@ -47,6 +45,16 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
|
||||
_coreId = coreId;
|
||||
|
||||
_currentThread = null;
|
||||
|
||||
if (_srcCoresHighestPrioThreads == null)
|
||||
{
|
||||
_srcCoresHighestPrioThreads = new int[CpuCoresCount];
|
||||
}
|
||||
}
|
||||
|
||||
private static int PreemptionPriorities(int index)
|
||||
{
|
||||
return index == CpuCoresCount - 1 ? 63 : 59;
|
||||
}
|
||||
|
||||
public static ulong SelectThreads(KernelContext context)
|
||||
@@ -437,7 +445,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
|
||||
|
||||
for (int core = 0; core < CpuCoresCount; core++)
|
||||
{
|
||||
RotateScheduledQueue(context, core, _preemptionPriorities[core]);
|
||||
RotateScheduledQueue(context, core, PreemptionPriorities(core));
|
||||
}
|
||||
|
||||
context.CriticalSection.Leave();
|
||||
|
||||
BIN
src/Ryujinx.HLE/HOS/Services/Account/Acc/GuestUserImage.jpg
Normal file
BIN
src/Ryujinx.HLE/HOS/Services/Account/Acc/GuestUserImage.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 7.8 KiB |
@@ -15,8 +15,10 @@ namespace Ryujinx.HLE.HOS.Services.Fs.FileSystemProxy
|
||||
{
|
||||
_baseStorage = SharedRef<LibHac.FsSrv.Sf.IStorage>.CreateMove(ref baseStorage);
|
||||
}
|
||||
|
||||
private const string Xc2TitleId = "0100e95004038000";
|
||||
|
||||
private const string Xc2JpTitleId = "0100f3400332c000";
|
||||
private const string Xc2GlobalTitleId = "0100e95004038000";
|
||||
private static bool IsXc2 => TitleIDs.CurrentApplication.Value.OrDefault() is Xc2GlobalTitleId or Xc2JpTitleId;
|
||||
|
||||
[CommandCmif(0)]
|
||||
// Read(u64 offset, u64 length) -> buffer<u8, 0x46, 0> buffer
|
||||
@@ -39,7 +41,7 @@ namespace Ryujinx.HLE.HOS.Services.Fs.FileSystemProxy
|
||||
using var region = context.Memory.GetWritableRegion(bufferAddress, (int)bufferLen, true);
|
||||
Result result = _baseStorage.Get.Read((long)offset, new OutBuffer(region.Memory.Span), (long)size);
|
||||
|
||||
if (context.Device.DirtyHacks.HasFlag(DirtyHacks.Xc2MenuSoftlockFix) && TitleIDs.CurrentApplication == Xc2TitleId)
|
||||
if (context.Device.DirtyHacks.IsEnabled(DirtyHack.Xc2MenuSoftlockFix) && IsXc2)
|
||||
{
|
||||
// Add a load-bearing sleep to avoid XC2 softlock
|
||||
// https://web.archive.org/web/20240728045136/https://github.com/Ryujinx/Ryujinx/issues/2357
|
||||
|
||||
@@ -702,6 +702,18 @@ namespace Ryujinx.HLE.HOS.Services.Hid
|
||||
|
||||
return ResultCode.Success;
|
||||
}
|
||||
|
||||
[CommandCmif(92)]
|
||||
// SetGestureOutputRanges(pid, ushort Unknown0)
|
||||
public ResultCode SetGestureOutputRanges(ServiceCtx context)
|
||||
{
|
||||
ulong pid = context.Request.HandleDesc.PId;
|
||||
ushort unknown0 = context.RequestData.ReadUInt16();
|
||||
|
||||
Logger.Stub?.PrintStub(LogClass.ServiceHid, new { pid, unknown0 });
|
||||
|
||||
return ResultCode.Success;
|
||||
}
|
||||
|
||||
[CommandCmif(100)]
|
||||
// SetSupportedNpadStyleSet(pid, nn::applet::AppletResourceUserId, nn::hid::NpadStyleTag)
|
||||
|
||||
@@ -114,10 +114,10 @@ namespace Ryujinx.HLE.HOS.Services.Nfc.AmiiboDecryption
|
||||
}
|
||||
}
|
||||
|
||||
string usedCharacterStr = BitConverter.ToString(usedCharacter).Replace("-", "");
|
||||
string variationStr = BitConverter.ToString(variation).Replace("-", "");
|
||||
string amiiboIDStr = BitConverter.ToString(amiiboID).Replace("-", "");
|
||||
string setIDStr = BitConverter.ToString(setID).Replace("-", "");
|
||||
string usedCharacterStr = Convert.ToHexString(usedCharacter);
|
||||
string variationStr = Convert.ToHexString(variation);
|
||||
string amiiboIDStr = Convert.ToHexString(amiiboID);
|
||||
string setIDStr = Convert.ToHexString(setID);
|
||||
string head = usedCharacterStr + variationStr;
|
||||
string tail = amiiboIDStr + setIDStr + "02";
|
||||
string finalID = head + tail;
|
||||
@@ -289,8 +289,8 @@ namespace Ryujinx.HLE.HOS.Services.Nfc.AmiiboDecryption
|
||||
|
||||
private static void LogFinalData(byte[] titleId, byte[] appId, string head, string tail, string finalID, string nickName, DateTime initDateTime, DateTime writeDateTime, ushort settingsValue, ushort writeCounterValue, byte[] applicationAreas)
|
||||
{
|
||||
Logger.Debug?.Print(LogClass.ServiceNfp, $"Title ID: 0x{BitConverter.ToString(titleId).Replace("-", "")}");
|
||||
Logger.Debug?.Print(LogClass.ServiceNfp, $"Application Program ID: 0x{BitConverter.ToString(appId).Replace("-", "")}");
|
||||
Logger.Debug?.Print(LogClass.ServiceNfp, $"Title ID: 0x{Convert.ToHexString(titleId)}");
|
||||
Logger.Debug?.Print(LogClass.ServiceNfp, $"Application Program ID: 0x{Convert.ToHexString(appId)}");
|
||||
Logger.Debug?.Print(LogClass.ServiceNfp, $"Head: {head}");
|
||||
Logger.Debug?.Print(LogClass.ServiceNfp, $"Tail: {tail}");
|
||||
Logger.Debug?.Print(LogClass.ServiceNfp, $"Final ID: {finalID}");
|
||||
|
||||
@@ -24,14 +24,14 @@ namespace Ryujinx.HLE.HOS.Services
|
||||
// not large enough.
|
||||
private const int PointerBufferSize = 0x8000;
|
||||
|
||||
private readonly static uint[] _defaultCapabilities = {
|
||||
0x030363F7,
|
||||
private static uint[] _defaultCapabilities => [
|
||||
(((uint)KScheduler.CpuCoresCount - 1) << 24) + (((uint)KScheduler.CpuCoresCount - 1) << 16) + 0x63F7u,
|
||||
0x1FFFFFCF,
|
||||
0x207FFFEF,
|
||||
0x47E0060F,
|
||||
0x0048BFFF,
|
||||
0x01007FFF,
|
||||
};
|
||||
];
|
||||
|
||||
// The amount of time Dispose() will wait to Join() the thread executing the ServerLoop()
|
||||
private static readonly TimeSpan _threadJoinTimeout = TimeSpan.FromSeconds(3);
|
||||
|
||||
@@ -7,6 +7,7 @@ using LibHac.Tools.FsSystem;
|
||||
using Ryujinx.Common;
|
||||
using Ryujinx.Common.Configuration;
|
||||
using Ryujinx.Common.Logging;
|
||||
using Ryujinx.Graphics.Gpu;
|
||||
using Ryujinx.HLE.Loaders.Executables;
|
||||
using Ryujinx.Memory;
|
||||
using System;
|
||||
@@ -103,7 +104,7 @@ namespace Ryujinx.HLE.Loaders.Processes.Extensions
|
||||
}
|
||||
|
||||
// Initialize GPU.
|
||||
TitleIDs.CurrentApplication = programId.ToString("X16");
|
||||
GraphicsConfig.TitleId = programId.ToString("X16");
|
||||
device.Gpu.HostInitalized.Set();
|
||||
|
||||
if (!MemoryBlock.SupportsFlags(MemoryAllocationFlags.ViewCompatible))
|
||||
|
||||
@@ -8,6 +8,7 @@ using LibHac.Tools.FsSystem;
|
||||
using LibHac.Tools.FsSystem.NcaUtils;
|
||||
using Ryujinx.Common;
|
||||
using Ryujinx.Common.Logging;
|
||||
using Ryujinx.Graphics.Gpu;
|
||||
using Ryujinx.HLE.Loaders.Executables;
|
||||
using Ryujinx.HLE.Loaders.Processes.Extensions;
|
||||
using System;
|
||||
@@ -25,7 +26,17 @@ namespace Ryujinx.HLE.Loaders.Processes
|
||||
|
||||
private ulong _latestPid;
|
||||
|
||||
public ProcessResult ActiveApplication => _processesByPid[_latestPid];
|
||||
public ProcessResult ActiveApplication
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!_processesByPid.TryGetValue(_latestPid, out ProcessResult value))
|
||||
throw new RyujinxException(
|
||||
$"The HLE Process map did not have a process with ID {_latestPid}. Are you missing firmware?");
|
||||
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
public ProcessLoader(Switch device)
|
||||
{
|
||||
@@ -60,6 +71,8 @@ namespace Ryujinx.HLE.Loaders.Processes
|
||||
{
|
||||
_latestPid = processResult.ProcessId;
|
||||
|
||||
TitleIDs.CurrentApplication.Value = processResult.ProgramIdText;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -87,6 +100,8 @@ namespace Ryujinx.HLE.Loaders.Processes
|
||||
{
|
||||
_latestPid = processResult.ProcessId;
|
||||
|
||||
TitleIDs.CurrentApplication.Value = processResult.ProgramIdText;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -114,6 +129,8 @@ namespace Ryujinx.HLE.Loaders.Processes
|
||||
if (processResult.ProgramId > 0x01000000000007FF)
|
||||
{
|
||||
_latestPid = processResult.ProcessId;
|
||||
|
||||
TitleIDs.CurrentApplication.Value = processResult.ProgramIdText;
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -133,6 +150,8 @@ namespace Ryujinx.HLE.Loaders.Processes
|
||||
{
|
||||
_latestPid = processResult.ProcessId;
|
||||
|
||||
TitleIDs.CurrentApplication.Value = processResult.ProgramIdText;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -184,14 +203,17 @@ namespace Ryujinx.HLE.Loaders.Processes
|
||||
if (nacpData.Value.PresenceGroupId != 0)
|
||||
{
|
||||
programId = nacpData.Value.PresenceGroupId;
|
||||
TitleIDs.CurrentApplication.Value = programId.ToString("X16");
|
||||
}
|
||||
else if (nacpData.Value.SaveDataOwnerId != 0)
|
||||
{
|
||||
programId = nacpData.Value.SaveDataOwnerId;
|
||||
TitleIDs.CurrentApplication.Value = programId.ToString("X16");
|
||||
}
|
||||
else if (nacpData.Value.AddOnContentBaseId != 0)
|
||||
{
|
||||
programId = nacpData.Value.AddOnContentBaseId - 0x1000;
|
||||
TitleIDs.CurrentApplication.Value = programId.ToString("X16");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -205,7 +227,7 @@ namespace Ryujinx.HLE.Loaders.Processes
|
||||
}
|
||||
|
||||
// Explicitly null TitleId to disable the shader cache.
|
||||
TitleIDs.CurrentApplication = default;
|
||||
GraphicsConfig.TitleId = null;
|
||||
_device.Gpu.HostInitalized.Set();
|
||||
|
||||
ProcessResult processResult = ProcessLoaderHelper.LoadNsos(_device,
|
||||
|
||||
@@ -48,6 +48,7 @@
|
||||
<EmbeddedResource Include="HOS\Applets\SoftwareKeyboard\Resources\Icon_BtnB.png" />
|
||||
<EmbeddedResource Include="HOS\Applets\SoftwareKeyboard\Resources\Icon_KeyF6.png" />
|
||||
<EmbeddedResource Include="HOS\Services\Account\Acc\DefaultUserImage.jpg" />
|
||||
<EmbeddedResource Include="HOS\Services\Account\Acc\GuestUserImage.jpg" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -2,6 +2,7 @@ using LibHac.Common;
|
||||
using LibHac.Ns;
|
||||
using Ryujinx.Audio.Backends.CompatLayer;
|
||||
using Ryujinx.Audio.Integration;
|
||||
using Ryujinx.Common;
|
||||
using Ryujinx.Common.Configuration;
|
||||
using Ryujinx.Graphics.Gpu;
|
||||
using Ryujinx.HLE.FileSystem;
|
||||
@@ -17,6 +18,8 @@ namespace Ryujinx.HLE
|
||||
{
|
||||
public class Switch : IDisposable
|
||||
{
|
||||
public static Switch Shared { get; private set; }
|
||||
|
||||
public HLEConfiguration Configuration { get; }
|
||||
public IHardwareDeviceDriver AudioDeviceDriver { get; }
|
||||
public MemoryBlock Memory { get; }
|
||||
@@ -29,6 +32,8 @@ namespace Ryujinx.HLE
|
||||
public TamperMachine TamperMachine { get; }
|
||||
public IHostUIHandler UIHandler { get; }
|
||||
|
||||
public int CpuCoresCount = 4; //Switch 1 has 4 cores
|
||||
|
||||
public VSyncMode VSyncMode { get; set; } = VSyncMode.Switch;
|
||||
public bool CustomVSyncIntervalEnabled { get; set; } = false;
|
||||
public int CustomVSyncInterval { get; set; }
|
||||
@@ -54,9 +59,10 @@ namespace Ryujinx.HLE
|
||||
: MemoryAllocationFlags.Reserve | MemoryAllocationFlags.Mirrorable;
|
||||
|
||||
#pragma warning disable IDE0055 // Disable formatting
|
||||
DirtyHacks = new DirtyHacks(Configuration.Hacks);
|
||||
AudioDeviceDriver = new CompatLayerHardwareDeviceDriver(Configuration.AudioDeviceDriver);
|
||||
Memory = new MemoryBlock(Configuration.MemoryConfiguration.ToDramSize(), memoryAllocationFlags);
|
||||
Gpu = new GpuContext(Configuration.GpuRenderer);
|
||||
Gpu = new GpuContext(Configuration.GpuRenderer, DirtyHacks);
|
||||
System = new HOS.Horizon(this);
|
||||
Statistics = new PerformanceStatistics();
|
||||
Hid = new Hid(this, System.HidStorage);
|
||||
@@ -74,9 +80,11 @@ namespace Ryujinx.HLE
|
||||
System.EnablePtc = Configuration.EnablePtc;
|
||||
System.FsIntegrityCheckLevel = Configuration.FsIntegrityCheckLevel;
|
||||
System.GlobalAccessLogMode = Configuration.FsGlobalAccessLogMode;
|
||||
DirtyHacks = Configuration.Hacks;
|
||||
|
||||
UpdateVSyncInterval();
|
||||
#pragma warning restore IDE0055
|
||||
|
||||
Shared = this;
|
||||
}
|
||||
|
||||
public void ProcessFrame()
|
||||
@@ -145,6 +153,9 @@ namespace Ryujinx.HLE
|
||||
AudioDeviceDriver.Dispose();
|
||||
FileSystem.Dispose();
|
||||
Memory.Dispose();
|
||||
|
||||
TitleIDs.CurrentApplication.Value = null;
|
||||
Shared = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using Ryujinx.HLE.HOS.Applets;
|
||||
using Ryujinx.HLE.HOS.Services.Account.Acc;
|
||||
using Ryujinx.HLE.HOS.Services.Am.AppletOE.ApplicationProxyService.ApplicationProxy.Types;
|
||||
|
||||
namespace Ryujinx.HLE.UI
|
||||
@@ -59,5 +60,11 @@ namespace Ryujinx.HLE.UI
|
||||
/// Gets fonts and colors used by the host.
|
||||
/// </summary>
|
||||
IHostUITheme HostUITheme { get; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Displays the player select dialog and returns the selected profile.
|
||||
/// </summary>
|
||||
UserProfile ShowPlayerSelectDialog();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using Ryujinx.Common.Logging;
|
||||
using Ryujinx.SDL2.Common;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
@@ -36,6 +37,7 @@ namespace Ryujinx.Input.SDL2
|
||||
SDL2Driver.Instance.Initialize();
|
||||
SDL2Driver.Instance.OnJoyStickConnected += HandleJoyStickConnected;
|
||||
SDL2Driver.Instance.OnJoystickDisconnected += HandleJoyStickDisconnected;
|
||||
SDL2Driver.Instance.OnJoyBatteryUpdated += HandleJoyBatteryUpdated;
|
||||
|
||||
// Add already connected gamepads
|
||||
int numJoysticks = SDL_NumJoysticks();
|
||||
@@ -83,19 +85,30 @@ namespace Ryujinx.Input.SDL2
|
||||
|
||||
private void HandleJoyStickDisconnected(int joystickInstanceId)
|
||||
{
|
||||
bool joyConPairDisconnected = false;
|
||||
if (!_gamepadsInstanceIdsMapping.Remove(joystickInstanceId, out string id))
|
||||
return;
|
||||
|
||||
lock (_lock)
|
||||
{
|
||||
_gamepadsIds.Remove(id);
|
||||
if (!SDL2JoyConPair.IsCombinable(_gamepadsIds))
|
||||
{
|
||||
_gamepadsIds.Remove(SDL2JoyConPair.Id);
|
||||
joyConPairDisconnected = true;
|
||||
}
|
||||
}
|
||||
|
||||
OnGamepadDisconnected?.Invoke(id);
|
||||
if (joyConPairDisconnected)
|
||||
{
|
||||
OnGamepadDisconnected?.Invoke(SDL2JoyConPair.Id);
|
||||
}
|
||||
}
|
||||
|
||||
private void HandleJoyStickConnected(int joystickDeviceId, int joystickInstanceId)
|
||||
{
|
||||
bool joyConPairConnected = false;
|
||||
if (SDL_IsGameController(joystickDeviceId) == SDL_bool.SDL_TRUE)
|
||||
{
|
||||
if (_gamepadsInstanceIdsMapping.ContainsKey(joystickInstanceId))
|
||||
@@ -120,13 +133,29 @@ namespace Ryujinx.Input.SDL2
|
||||
_gamepadsIds.Insert(joystickDeviceId, id);
|
||||
else
|
||||
_gamepadsIds.Add(id);
|
||||
if (SDL2JoyConPair.IsCombinable(_gamepadsIds))
|
||||
{
|
||||
_gamepadsIds.Remove(SDL2JoyConPair.Id);
|
||||
_gamepadsIds.Add(SDL2JoyConPair.Id);
|
||||
joyConPairConnected = true;
|
||||
}
|
||||
}
|
||||
|
||||
OnGamepadConnected?.Invoke(id);
|
||||
if (joyConPairConnected)
|
||||
{
|
||||
OnGamepadConnected?.Invoke(SDL2JoyConPair.Id);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void HandleJoyBatteryUpdated(int joystickDeviceId, SDL_JoystickPowerLevel powerLevel)
|
||||
{
|
||||
Logger.Info?.Print(LogClass.Hid,
|
||||
$"{SDL_GameControllerNameForIndex(joystickDeviceId)} power level: {powerLevel}");
|
||||
}
|
||||
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing)
|
||||
@@ -157,6 +186,14 @@ namespace Ryujinx.Input.SDL2
|
||||
|
||||
public IGamepad GetGamepad(string id)
|
||||
{
|
||||
if (id == SDL2JoyConPair.Id)
|
||||
{
|
||||
lock (_lock)
|
||||
{
|
||||
return SDL2JoyConPair.GetGamepad(_gamepadsIds);
|
||||
}
|
||||
}
|
||||
|
||||
int joystickIndex = GetJoystickIndexByGamepadId(id);
|
||||
|
||||
if (joystickIndex == -1)
|
||||
@@ -165,12 +202,16 @@ namespace Ryujinx.Input.SDL2
|
||||
}
|
||||
|
||||
nint gamepadHandle = SDL_GameControllerOpen(joystickIndex);
|
||||
|
||||
if (gamepadHandle == nint.Zero)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if (SDL_GameControllerName(gamepadHandle).StartsWith(SDL2JoyCon.Prefix))
|
||||
{
|
||||
return new SDL2JoyCon(gamepadHandle, id);
|
||||
}
|
||||
|
||||
return new SDL2Gamepad(gamepadHandle, id);
|
||||
}
|
||||
}
|
||||
|
||||
409
src/Ryujinx.Input.SDL2/SDL2JoyCon.cs
Normal file
409
src/Ryujinx.Input.SDL2/SDL2JoyCon.cs
Normal file
@@ -0,0 +1,409 @@
|
||||
using Ryujinx.Common.Configuration.Hid;
|
||||
using Ryujinx.Common.Configuration.Hid.Controller;
|
||||
using Ryujinx.Common.Logging;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Numerics;
|
||||
using System.Threading;
|
||||
using static SDL2.SDL;
|
||||
|
||||
namespace Ryujinx.Input.SDL2
|
||||
{
|
||||
internal class SDL2JoyCon : IGamepad
|
||||
{
|
||||
private bool HasConfiguration => _configuration != null;
|
||||
|
||||
private readonly record struct ButtonMappingEntry(GamepadButtonInputId To, GamepadButtonInputId From)
|
||||
{
|
||||
public bool IsValid => To is not GamepadButtonInputId.Unbound && From is not GamepadButtonInputId.Unbound;
|
||||
}
|
||||
|
||||
private StandardControllerInputConfig _configuration;
|
||||
|
||||
private readonly Dictionary<GamepadButtonInputId,SDL_GameControllerButton> _leftButtonsDriverMapping = new()
|
||||
{
|
||||
{ GamepadButtonInputId.LeftStick , SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_LEFTSTICK },
|
||||
{GamepadButtonInputId.DpadUp ,SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_Y},
|
||||
{GamepadButtonInputId.DpadDown ,SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_A},
|
||||
{GamepadButtonInputId.DpadLeft ,SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_B},
|
||||
{GamepadButtonInputId.DpadRight ,SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_X},
|
||||
{GamepadButtonInputId.Minus ,SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_START},
|
||||
{GamepadButtonInputId.LeftShoulder,SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_PADDLE2},
|
||||
{GamepadButtonInputId.LeftTrigger,SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_PADDLE4},
|
||||
{GamepadButtonInputId.SingleRightTrigger0,SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_RIGHTSHOULDER},
|
||||
{GamepadButtonInputId.SingleLeftTrigger0,SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_LEFTSHOULDER},
|
||||
};
|
||||
private readonly Dictionary<GamepadButtonInputId,SDL_GameControllerButton> _rightButtonsDriverMapping = new()
|
||||
{
|
||||
{GamepadButtonInputId.RightStick,SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_LEFTSTICK},
|
||||
{GamepadButtonInputId.A,SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_B},
|
||||
{GamepadButtonInputId.B,SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_Y},
|
||||
{GamepadButtonInputId.X,SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_A},
|
||||
{GamepadButtonInputId.Y,SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_X},
|
||||
{GamepadButtonInputId.Plus,SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_START},
|
||||
{GamepadButtonInputId.RightShoulder,SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_PADDLE1},
|
||||
{GamepadButtonInputId.RightTrigger,SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_PADDLE3},
|
||||
{GamepadButtonInputId.SingleRightTrigger1,SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_RIGHTSHOULDER},
|
||||
{GamepadButtonInputId.SingleLeftTrigger1,SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_LEFTSHOULDER}
|
||||
};
|
||||
|
||||
private readonly Dictionary<GamepadButtonInputId, SDL_GameControllerButton> _buttonsDriverMapping;
|
||||
private readonly Lock _userMappingLock = new();
|
||||
|
||||
private readonly List<ButtonMappingEntry> _buttonsUserMapping;
|
||||
|
||||
private readonly StickInputId[] _stickUserMapping = new StickInputId[(int)StickInputId.Count]
|
||||
{
|
||||
StickInputId.Unbound, StickInputId.Left, StickInputId.Right,
|
||||
};
|
||||
|
||||
public GamepadFeaturesFlag Features { get; }
|
||||
|
||||
private nint _gamepadHandle;
|
||||
|
||||
private enum JoyConType
|
||||
{
|
||||
Left, Right
|
||||
}
|
||||
|
||||
public const string Prefix = "Nintendo Switch Joy-Con";
|
||||
public const string LeftName = "Nintendo Switch Joy-Con (L)";
|
||||
public const string RightName = "Nintendo Switch Joy-Con (R)";
|
||||
|
||||
private readonly JoyConType _joyConType;
|
||||
|
||||
public SDL2JoyCon(nint gamepadHandle, string driverId)
|
||||
{
|
||||
_gamepadHandle = gamepadHandle;
|
||||
_buttonsUserMapping = new List<ButtonMappingEntry>(10);
|
||||
|
||||
Name = SDL_GameControllerName(_gamepadHandle);
|
||||
Id = driverId;
|
||||
Features = GetFeaturesFlag();
|
||||
|
||||
// Enable motion tracking
|
||||
if (Features.HasFlag(GamepadFeaturesFlag.Motion))
|
||||
{
|
||||
if (SDL_GameControllerSetSensorEnabled(_gamepadHandle, SDL_SensorType.SDL_SENSOR_ACCEL,
|
||||
SDL_bool.SDL_TRUE) != 0)
|
||||
{
|
||||
Logger.Error?.Print(LogClass.Hid,
|
||||
$"Could not enable data reporting for SensorType {SDL_SensorType.SDL_SENSOR_ACCEL}.");
|
||||
}
|
||||
|
||||
if (SDL_GameControllerSetSensorEnabled(_gamepadHandle, SDL_SensorType.SDL_SENSOR_GYRO,
|
||||
SDL_bool.SDL_TRUE) != 0)
|
||||
{
|
||||
Logger.Error?.Print(LogClass.Hid,
|
||||
$"Could not enable data reporting for SensorType {SDL_SensorType.SDL_SENSOR_GYRO}.");
|
||||
}
|
||||
}
|
||||
|
||||
switch (Name)
|
||||
{
|
||||
case LeftName:
|
||||
{
|
||||
_buttonsDriverMapping = _leftButtonsDriverMapping;
|
||||
_joyConType = JoyConType.Left;
|
||||
break;
|
||||
}
|
||||
case RightName:
|
||||
{
|
||||
_buttonsDriverMapping = _rightButtonsDriverMapping;
|
||||
_joyConType = JoyConType.Right;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private GamepadFeaturesFlag GetFeaturesFlag()
|
||||
{
|
||||
GamepadFeaturesFlag result = GamepadFeaturesFlag.None;
|
||||
|
||||
if (SDL_GameControllerHasSensor(_gamepadHandle, SDL_SensorType.SDL_SENSOR_ACCEL) == SDL_bool.SDL_TRUE &&
|
||||
SDL_GameControllerHasSensor(_gamepadHandle, SDL_SensorType.SDL_SENSOR_GYRO) == SDL_bool.SDL_TRUE)
|
||||
{
|
||||
result |= GamepadFeaturesFlag.Motion;
|
||||
}
|
||||
|
||||
int error = SDL_GameControllerRumble(_gamepadHandle, 0, 0, 100);
|
||||
|
||||
if (error == 0)
|
||||
{
|
||||
result |= GamepadFeaturesFlag.Rumble;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public string Id { get; }
|
||||
public string Name { get; }
|
||||
public bool IsConnected => SDL_GameControllerGetAttached(_gamepadHandle) == SDL_bool.SDL_TRUE;
|
||||
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing && _gamepadHandle != nint.Zero)
|
||||
{
|
||||
SDL_GameControllerClose(_gamepadHandle);
|
||||
|
||||
_gamepadHandle = nint.Zero;
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(true);
|
||||
}
|
||||
|
||||
|
||||
public void SetTriggerThreshold(float triggerThreshold)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public void Rumble(float lowFrequency, float highFrequency, uint durationMs)
|
||||
{
|
||||
if (!Features.HasFlag(GamepadFeaturesFlag.Rumble))
|
||||
return;
|
||||
|
||||
ushort lowFrequencyRaw = (ushort)(lowFrequency * ushort.MaxValue);
|
||||
ushort highFrequencyRaw = (ushort)(highFrequency * ushort.MaxValue);
|
||||
|
||||
if (durationMs == uint.MaxValue)
|
||||
{
|
||||
if (SDL_GameControllerRumble(_gamepadHandle, lowFrequencyRaw, highFrequencyRaw, SDL_HAPTIC_INFINITY) !=
|
||||
0)
|
||||
Logger.Error?.Print(LogClass.Hid, "Rumble is not supported on this game controller.");
|
||||
}
|
||||
else if (durationMs > SDL_HAPTIC_INFINITY)
|
||||
{
|
||||
Logger.Error?.Print(LogClass.Hid, $"Unsupported rumble duration {durationMs}");
|
||||
}
|
||||
else
|
||||
{
|
||||
if (SDL_GameControllerRumble(_gamepadHandle, lowFrequencyRaw, highFrequencyRaw, durationMs) != 0)
|
||||
Logger.Error?.Print(LogClass.Hid, "Rumble is not supported on this game controller.");
|
||||
}
|
||||
}
|
||||
|
||||
public Vector3 GetMotionData(MotionInputId inputId)
|
||||
{
|
||||
SDL_SensorType sensorType = inputId switch
|
||||
{
|
||||
MotionInputId.Accelerometer => SDL_SensorType.SDL_SENSOR_ACCEL,
|
||||
MotionInputId.Gyroscope => SDL_SensorType.SDL_SENSOR_GYRO,
|
||||
_ => SDL_SensorType.SDL_SENSOR_INVALID
|
||||
};
|
||||
|
||||
if (!Features.HasFlag(GamepadFeaturesFlag.Motion) || sensorType is SDL_SensorType.SDL_SENSOR_INVALID)
|
||||
return Vector3.Zero;
|
||||
|
||||
const int ElementCount = 3;
|
||||
|
||||
unsafe
|
||||
{
|
||||
float* values = stackalloc float[ElementCount];
|
||||
|
||||
int result = SDL_GameControllerGetSensorData(_gamepadHandle, sensorType, (nint)values, ElementCount);
|
||||
|
||||
if (result != 0)
|
||||
return Vector3.Zero;
|
||||
|
||||
Vector3 value = _joyConType switch
|
||||
{
|
||||
JoyConType.Left => new Vector3(-values[2], values[1], values[0]),
|
||||
JoyConType.Right => new Vector3(values[2], values[1], -values[0])
|
||||
};
|
||||
|
||||
return inputId switch
|
||||
{
|
||||
MotionInputId.Gyroscope => RadToDegree(value),
|
||||
MotionInputId.Accelerometer => GsToMs2(value),
|
||||
_ => value
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
private static Vector3 RadToDegree(Vector3 rad) => rad * (180 / MathF.PI);
|
||||
|
||||
private static Vector3 GsToMs2(Vector3 gs) => gs / SDL_STANDARD_GRAVITY;
|
||||
|
||||
public void SetConfiguration(InputConfig configuration)
|
||||
{
|
||||
lock (_userMappingLock)
|
||||
{
|
||||
_configuration = (StandardControllerInputConfig)configuration;
|
||||
|
||||
_buttonsUserMapping.Clear();
|
||||
|
||||
// First update sticks
|
||||
_stickUserMapping[(int)StickInputId.Left] = (StickInputId)_configuration.LeftJoyconStick.Joystick;
|
||||
_stickUserMapping[(int)StickInputId.Right] = (StickInputId)_configuration.RightJoyconStick.Joystick;
|
||||
|
||||
|
||||
switch (_joyConType)
|
||||
{
|
||||
case JoyConType.Left:
|
||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.LeftStick, (GamepadButtonInputId)_configuration.LeftJoyconStick.StickButton));
|
||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.DpadUp, (GamepadButtonInputId)_configuration.LeftJoycon.DpadUp));
|
||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.DpadDown, (GamepadButtonInputId)_configuration.LeftJoycon.DpadDown));
|
||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.DpadLeft, (GamepadButtonInputId)_configuration.LeftJoycon.DpadLeft));
|
||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.DpadRight, (GamepadButtonInputId)_configuration.LeftJoycon.DpadRight));
|
||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.Minus, (GamepadButtonInputId)_configuration.LeftJoycon.ButtonMinus));
|
||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.LeftShoulder, (GamepadButtonInputId)_configuration.LeftJoycon.ButtonL));
|
||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.LeftTrigger, (GamepadButtonInputId)_configuration.LeftJoycon.ButtonZl));
|
||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.SingleRightTrigger0, (GamepadButtonInputId)_configuration.LeftJoycon.ButtonSr));
|
||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.SingleLeftTrigger0, (GamepadButtonInputId)_configuration.LeftJoycon.ButtonSl));
|
||||
break;
|
||||
case JoyConType.Right:
|
||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.RightStick, (GamepadButtonInputId)_configuration.RightJoyconStick.StickButton));
|
||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.A, (GamepadButtonInputId)_configuration.RightJoycon.ButtonA));
|
||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.B, (GamepadButtonInputId)_configuration.RightJoycon.ButtonB));
|
||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.X, (GamepadButtonInputId)_configuration.RightJoycon.ButtonX));
|
||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.Y, (GamepadButtonInputId)_configuration.RightJoycon.ButtonY));
|
||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.Plus, (GamepadButtonInputId)_configuration.RightJoycon.ButtonPlus));
|
||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.RightShoulder, (GamepadButtonInputId)_configuration.RightJoycon.ButtonR));
|
||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.RightTrigger, (GamepadButtonInputId)_configuration.RightJoycon.ButtonZr));
|
||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.SingleRightTrigger1, (GamepadButtonInputId)_configuration.RightJoycon.ButtonSr));
|
||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.SingleLeftTrigger1, (GamepadButtonInputId)_configuration.RightJoycon.ButtonSl));
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
|
||||
SetTriggerThreshold(_configuration.TriggerThreshold);
|
||||
}
|
||||
}
|
||||
|
||||
public GamepadStateSnapshot GetStateSnapshot()
|
||||
{
|
||||
return IGamepad.GetStateSnapshot(this);
|
||||
}
|
||||
|
||||
public GamepadStateSnapshot GetMappedStateSnapshot()
|
||||
{
|
||||
GamepadStateSnapshot rawState = GetStateSnapshot();
|
||||
GamepadStateSnapshot result = default;
|
||||
|
||||
lock (_userMappingLock)
|
||||
{
|
||||
if (_buttonsUserMapping.Count == 0)
|
||||
return rawState;
|
||||
|
||||
|
||||
// ReSharper disable once ForeachCanBePartlyConvertedToQueryUsingAnotherGetEnumerator
|
||||
foreach (ButtonMappingEntry entry in _buttonsUserMapping)
|
||||
{
|
||||
if (!entry.IsValid)
|
||||
continue;
|
||||
|
||||
// Do not touch state of button already pressed
|
||||
if (!result.IsPressed(entry.To))
|
||||
{
|
||||
result.SetPressed(entry.To, rawState.IsPressed(entry.From));
|
||||
}
|
||||
}
|
||||
|
||||
(float leftStickX, float leftStickY) = rawState.GetStick(_stickUserMapping[(int)StickInputId.Left]);
|
||||
(float rightStickX, float rightStickY) = rawState.GetStick(_stickUserMapping[(int)StickInputId.Right]);
|
||||
|
||||
result.SetStick(StickInputId.Left, leftStickX, leftStickY);
|
||||
result.SetStick(StickInputId.Right, rightStickX, rightStickY);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
private static float ConvertRawStickValue(short value)
|
||||
{
|
||||
const float ConvertRate = 1.0f / (short.MaxValue + 0.5f);
|
||||
|
||||
return value * ConvertRate;
|
||||
}
|
||||
|
||||
private JoyconConfigControllerStick<GamepadInputId, Common.Configuration.Hid.Controller.StickInputId>
|
||||
GetLogicalJoyStickConfig(StickInputId inputId)
|
||||
{
|
||||
switch (inputId)
|
||||
{
|
||||
case StickInputId.Left:
|
||||
if (_configuration.RightJoyconStick.Joystick ==
|
||||
Common.Configuration.Hid.Controller.StickInputId.Left)
|
||||
return _configuration.RightJoyconStick;
|
||||
else
|
||||
return _configuration.LeftJoyconStick;
|
||||
case StickInputId.Right:
|
||||
if (_configuration.LeftJoyconStick.Joystick ==
|
||||
Common.Configuration.Hid.Controller.StickInputId.Right)
|
||||
return _configuration.LeftJoyconStick;
|
||||
else
|
||||
return _configuration.RightJoyconStick;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
public (float, float) GetStick(StickInputId inputId)
|
||||
{
|
||||
if (inputId == StickInputId.Unbound)
|
||||
return (0.0f, 0.0f);
|
||||
|
||||
if (inputId == StickInputId.Left && _joyConType == JoyConType.Right || inputId == StickInputId.Right && _joyConType == JoyConType.Left)
|
||||
{
|
||||
return (0.0f, 0.0f);
|
||||
}
|
||||
|
||||
(short stickX, short stickY) = GetStickXY();
|
||||
|
||||
float resultX = ConvertRawStickValue(stickX);
|
||||
float resultY = -ConvertRawStickValue(stickY);
|
||||
|
||||
if (HasConfiguration)
|
||||
{
|
||||
var joyconStickConfig = GetLogicalJoyStickConfig(inputId);
|
||||
|
||||
if (joyconStickConfig != null)
|
||||
{
|
||||
if (joyconStickConfig.InvertStickX)
|
||||
resultX = -resultX;
|
||||
|
||||
if (joyconStickConfig.InvertStickY)
|
||||
resultY = -resultY;
|
||||
|
||||
if (joyconStickConfig.Rotate90CW)
|
||||
{
|
||||
float temp = resultX;
|
||||
resultX = resultY;
|
||||
resultY = -temp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return inputId switch
|
||||
{
|
||||
StickInputId.Left when _joyConType == JoyConType.Left => (resultY, -resultX),
|
||||
StickInputId.Right when _joyConType == JoyConType.Right => (-resultY, resultX),
|
||||
_ => (0.0f, 0.0f)
|
||||
};
|
||||
}
|
||||
|
||||
private (short, short) GetStickXY()
|
||||
{
|
||||
return (
|
||||
SDL_GameControllerGetAxis(_gamepadHandle, SDL_GameControllerAxis.SDL_CONTROLLER_AXIS_LEFTX),
|
||||
SDL_GameControllerGetAxis(_gamepadHandle, SDL_GameControllerAxis.SDL_CONTROLLER_AXIS_LEFTY));
|
||||
}
|
||||
|
||||
public bool IsPressed(GamepadButtonInputId inputId)
|
||||
{
|
||||
if (!_buttonsDriverMapping.TryGetValue(inputId, out var button))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return SDL_GameControllerGetButton(_gamepadHandle, button) == 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
142
src/Ryujinx.Input.SDL2/SDL2JoyConPair.cs
Normal file
142
src/Ryujinx.Input.SDL2/SDL2JoyConPair.cs
Normal file
@@ -0,0 +1,142 @@
|
||||
using Ryujinx.Common.Configuration.Hid;
|
||||
using Ryujinx.Common.Configuration.Hid.Controller;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Numerics;
|
||||
using static SDL2.SDL;
|
||||
|
||||
namespace Ryujinx.Input.SDL2
|
||||
{
|
||||
internal class SDL2JoyConPair(IGamepad left, IGamepad right) : IGamepad
|
||||
{
|
||||
private StandardControllerInputConfig _configuration;
|
||||
|
||||
private readonly StickInputId[] _stickUserMapping =
|
||||
[
|
||||
StickInputId.Unbound,
|
||||
StickInputId.Left,
|
||||
StickInputId.Right
|
||||
];
|
||||
|
||||
public GamepadFeaturesFlag Features => (left?.Features ?? GamepadFeaturesFlag.None) |
|
||||
(right?.Features ?? GamepadFeaturesFlag.None);
|
||||
|
||||
public const string Id = "JoyConPair";
|
||||
string IGamepad.Id => Id;
|
||||
|
||||
public string Name => "* Nintendo Switch Joy-Con (L/R)";
|
||||
public bool IsConnected => left is { IsConnected: true } && right is { IsConnected: true };
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
left?.Dispose();
|
||||
right?.Dispose();
|
||||
}
|
||||
|
||||
public GamepadStateSnapshot GetMappedStateSnapshot()
|
||||
{
|
||||
return GetStateSnapshot();
|
||||
}
|
||||
|
||||
public Vector3 GetMotionData(MotionInputId inputId)
|
||||
{
|
||||
return inputId switch
|
||||
{
|
||||
MotionInputId.Accelerometer or
|
||||
MotionInputId.Gyroscope => left.GetMotionData(inputId),
|
||||
MotionInputId.SecondAccelerometer => right.GetMotionData(MotionInputId.Accelerometer),
|
||||
MotionInputId.SecondGyroscope => right.GetMotionData(MotionInputId.Gyroscope),
|
||||
_ => Vector3.Zero
|
||||
};
|
||||
}
|
||||
|
||||
public GamepadStateSnapshot GetStateSnapshot()
|
||||
{
|
||||
return IGamepad.GetStateSnapshot(this);
|
||||
}
|
||||
|
||||
public (float, float) GetStick(StickInputId inputId)
|
||||
{
|
||||
return inputId switch
|
||||
{
|
||||
StickInputId.Left => left.GetStick(StickInputId.Left),
|
||||
StickInputId.Right => right.GetStick(StickInputId.Right),
|
||||
_ => (0, 0)
|
||||
};
|
||||
}
|
||||
|
||||
public bool IsPressed(GamepadButtonInputId inputId)
|
||||
{
|
||||
return left.IsPressed(inputId) || right.IsPressed(inputId);
|
||||
}
|
||||
|
||||
public void Rumble(float lowFrequency, float highFrequency, uint durationMs)
|
||||
{
|
||||
if (lowFrequency != 0)
|
||||
{
|
||||
right.Rumble(lowFrequency, lowFrequency, durationMs);
|
||||
}
|
||||
|
||||
if (highFrequency != 0)
|
||||
{
|
||||
left.Rumble(highFrequency, highFrequency, durationMs);
|
||||
}
|
||||
|
||||
if (lowFrequency == 0 && highFrequency == 0)
|
||||
{
|
||||
left.Rumble(0, 0, durationMs);
|
||||
right.Rumble(0, 0, durationMs);
|
||||
}
|
||||
}
|
||||
|
||||
public void SetConfiguration(InputConfig configuration)
|
||||
{
|
||||
left.SetConfiguration(configuration);
|
||||
right.SetConfiguration(configuration);
|
||||
}
|
||||
|
||||
public void SetTriggerThreshold(float triggerThreshold)
|
||||
{
|
||||
left.SetTriggerThreshold(triggerThreshold);
|
||||
right.SetTriggerThreshold(triggerThreshold);
|
||||
}
|
||||
|
||||
public static bool IsCombinable(List<string> gamepadsIds)
|
||||
{
|
||||
(int leftIndex, int rightIndex) = DetectJoyConPair(gamepadsIds);
|
||||
return leftIndex >= 0 && rightIndex >= 0;
|
||||
}
|
||||
|
||||
private static (int leftIndex, int rightIndex) DetectJoyConPair(List<string> gamepadsIds)
|
||||
{
|
||||
var gamepadNames = gamepadsIds.Where(gamepadId => gamepadId != Id)
|
||||
.Select((_, index) => SDL_GameControllerNameForIndex(index)).ToList();
|
||||
int leftIndex = gamepadNames.IndexOf(SDL2JoyCon.LeftName);
|
||||
int rightIndex = gamepadNames.IndexOf(SDL2JoyCon.RightName);
|
||||
|
||||
return (leftIndex, rightIndex);
|
||||
}
|
||||
|
||||
public static IGamepad GetGamepad(List<string> gamepadsIds)
|
||||
{
|
||||
(int leftIndex, int rightIndex) = DetectJoyConPair(gamepadsIds);
|
||||
if (leftIndex == -1 || rightIndex == -1)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
nint leftGamepadHandle = SDL_GameControllerOpen(leftIndex);
|
||||
nint rightGamepadHandle = SDL_GameControllerOpen(rightIndex);
|
||||
|
||||
if (leftGamepadHandle == nint.Zero || rightGamepadHandle == nint.Zero)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
return new SDL2JoyConPair(new SDL2JoyCon(leftGamepadHandle, gamepadsIds[leftIndex]),
|
||||
new SDL2JoyCon(rightGamepadHandle, gamepadsIds[rightIndex]));
|
||||
}
|
||||
}
|
||||
}
|
||||
13
src/Ryujinx.Input.SDL3/Ryujinx.Input.SDL3.csproj
Normal file
13
src/Ryujinx.Input.SDL3/Ryujinx.Input.SDL3.csproj
Normal file
@@ -0,0 +1,13 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<DefaultItemExcludes>$(DefaultItemExcludes);._*</DefaultItemExcludes>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Ryujinx.Input\Ryujinx.Input.csproj" />
|
||||
<ProjectReference Include="..\Ryujinx.SDL3.Common\Ryujinx.SDL3.Common.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
388
src/Ryujinx.Input.SDL3/SDL3Gamepad.cs
Normal file
388
src/Ryujinx.Input.SDL3/SDL3Gamepad.cs
Normal file
@@ -0,0 +1,388 @@
|
||||
using Humanizer;
|
||||
using Ryujinx.Common.Configuration.Hid;
|
||||
using Ryujinx.Common.Configuration.Hid.Controller;
|
||||
using Ryujinx.Common.Logging;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Numerics;
|
||||
using System.Threading;
|
||||
using static SDL3.SDL;
|
||||
|
||||
namespace Ryujinx.Input.SDL3
|
||||
{
|
||||
class SDL3Gamepad : IGamepad
|
||||
{
|
||||
private bool HasConfiguration => _configuration != null;
|
||||
|
||||
private readonly record struct ButtonMappingEntry(GamepadButtonInputId To, GamepadButtonInputId From)
|
||||
{
|
||||
public bool IsValid => To is not GamepadButtonInputId.Unbound && From is not GamepadButtonInputId.Unbound;
|
||||
}
|
||||
private static readonly Dictionary<GamepadButtonInputId, SDL_GamepadButton> _buttonsDriverDict = new()
|
||||
{
|
||||
{ GamepadButtonInputId.LeftStick, SDL_GamepadButton.SDL_GAMEPAD_BUTTON_LEFT_STICK },
|
||||
{ GamepadButtonInputId.DpadUp, SDL_GamepadButton.SDL_GAMEPAD_BUTTON_DPAD_UP },
|
||||
{ GamepadButtonInputId.DpadDown, SDL_GamepadButton.SDL_GAMEPAD_BUTTON_DPAD_DOWN },
|
||||
{ GamepadButtonInputId.DpadLeft, SDL_GamepadButton.SDL_GAMEPAD_BUTTON_DPAD_LEFT },
|
||||
{ GamepadButtonInputId.DpadRight, SDL_GamepadButton.SDL_GAMEPAD_BUTTON_DPAD_RIGHT },
|
||||
{ GamepadButtonInputId.Minus, SDL_GamepadButton.SDL_GAMEPAD_BUTTON_BACK },
|
||||
{ GamepadButtonInputId.LeftShoulder, SDL_GamepadButton.SDL_GAMEPAD_BUTTON_LEFT_SHOULDER },
|
||||
{ GamepadButtonInputId.LeftTrigger, SDL_GamepadButton.SDL_GAMEPAD_BUTTON_LEFT_PADDLE2 },
|
||||
{ GamepadButtonInputId.RightStick, SDL_GamepadButton.SDL_GAMEPAD_BUTTON_RIGHT_STICK },
|
||||
{ GamepadButtonInputId.A, SDL_GamepadButton.SDL_GAMEPAD_BUTTON_EAST },
|
||||
{ GamepadButtonInputId.B, SDL_GamepadButton.SDL_GAMEPAD_BUTTON_SOUTH },
|
||||
{ GamepadButtonInputId.X, SDL_GamepadButton.SDL_GAMEPAD_BUTTON_NORTH },
|
||||
{ GamepadButtonInputId.Y, SDL_GamepadButton.SDL_GAMEPAD_BUTTON_WEST },
|
||||
{ GamepadButtonInputId.Plus, SDL_GamepadButton.SDL_GAMEPAD_BUTTON_START },
|
||||
{ GamepadButtonInputId.RightShoulder, SDL_GamepadButton.SDL_GAMEPAD_BUTTON_RIGHT_SHOULDER },
|
||||
{ GamepadButtonInputId.RightTrigger, SDL_GamepadButton.SDL_GAMEPAD_BUTTON_RIGHT_PADDLE2 },
|
||||
};
|
||||
|
||||
private StandardControllerInputConfig _configuration;
|
||||
|
||||
private static readonly SDL_GamepadButton[] _buttonsDriverMapping = ToSDLButtonMapping(_buttonsDriverDict);
|
||||
|
||||
private readonly Lock _userMappingLock = new();
|
||||
|
||||
private readonly List<ButtonMappingEntry> _buttonsUserMapping;
|
||||
|
||||
private readonly StickInputId[] _stickUserMapping = new StickInputId[(int)StickInputId.Count]
|
||||
{
|
||||
StickInputId.Unbound, StickInputId.Left, StickInputId.Right,
|
||||
};
|
||||
|
||||
public GamepadFeaturesFlag Features { get; }
|
||||
|
||||
private nint _gamepadHandle;
|
||||
|
||||
private float _triggerThreshold;
|
||||
|
||||
public SDL3Gamepad(uint joystickId, string driverId)
|
||||
{
|
||||
_gamepadHandle = SDL_OpenGamepad(joystickId);
|
||||
_buttonsUserMapping = new List<ButtonMappingEntry>(20);
|
||||
|
||||
Name = SDL_GetGamepadName(_gamepadHandle);
|
||||
Id = driverId;
|
||||
Features = GetFeaturesFlag();
|
||||
_triggerThreshold = 0.0f;
|
||||
|
||||
// Enable motion tracking
|
||||
if (Features.HasFlag(GamepadFeaturesFlag.Motion))
|
||||
{
|
||||
if (!SDL_SetGamepadSensorEnabled(_gamepadHandle, SDL_SensorType.SDL_SENSOR_ACCEL, true))
|
||||
{
|
||||
Logger.Error?.Print(LogClass.Hid,
|
||||
$"Could not enable data reporting for SensorType {SDL_SensorType.SDL_SENSOR_ACCEL}.");
|
||||
}
|
||||
|
||||
if (!SDL_SetGamepadSensorEnabled(_gamepadHandle, SDL_SensorType.SDL_SENSOR_GYRO, true))
|
||||
{
|
||||
Logger.Error?.Print(LogClass.Hid,
|
||||
$"Could not enable data reporting for SensorType {SDL_SensorType.SDL_SENSOR_GYRO}.");
|
||||
}
|
||||
}
|
||||
}
|
||||
private static SDL_GamepadButton[] ToSDLButtonMapping(
|
||||
Dictionary<GamepadButtonInputId, SDL_GamepadButton> buttonsDriverMapping)
|
||||
{
|
||||
return Enumerable.Range(0, (int)GamepadButtonInputId.Count)
|
||||
.Select(i =>
|
||||
buttonsDriverMapping.GetValueOrDefault((GamepadButtonInputId)i,
|
||||
SDL_GamepadButton.SDL_GAMEPAD_BUTTON_INVALID))
|
||||
.ToArray();
|
||||
}
|
||||
private GamepadFeaturesFlag GetFeaturesFlag()
|
||||
{
|
||||
GamepadFeaturesFlag result = GamepadFeaturesFlag.None;
|
||||
|
||||
if (SDL_GamepadHasSensor(_gamepadHandle, SDL_SensorType.SDL_SENSOR_ACCEL) &&
|
||||
SDL_GamepadHasSensor(_gamepadHandle, SDL_SensorType.SDL_SENSOR_GYRO))
|
||||
{
|
||||
result |= GamepadFeaturesFlag.Motion;
|
||||
}
|
||||
|
||||
if (SDL_RumbleGamepad(_gamepadHandle, 0, 0, 100))
|
||||
{
|
||||
result |= GamepadFeaturesFlag.Rumble;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public string Id { get; }
|
||||
public string Name { get; }
|
||||
|
||||
public bool IsConnected => SDL_GamepadConnected(_gamepadHandle);
|
||||
|
||||
private void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing && _gamepadHandle != nint.Zero)
|
||||
{
|
||||
SDL_CloseGamepad(_gamepadHandle);
|
||||
|
||||
_gamepadHandle = nint.Zero;
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(true);
|
||||
}
|
||||
|
||||
public void SetTriggerThreshold(float triggerThreshold)
|
||||
{
|
||||
_triggerThreshold = triggerThreshold;
|
||||
}
|
||||
|
||||
public void Rumble(float lowFrequency, float highFrequency, uint durationMs)
|
||||
{
|
||||
if (!Features.HasFlag(GamepadFeaturesFlag.Rumble))
|
||||
return;
|
||||
|
||||
ushort lowFrequencyRaw = (ushort)(lowFrequency * ushort.MaxValue);
|
||||
ushort highFrequencyRaw = (ushort)(highFrequency * ushort.MaxValue);
|
||||
|
||||
|
||||
if (!SDL_RumbleGamepad(_gamepadHandle, lowFrequencyRaw, highFrequencyRaw, durationMs))
|
||||
{
|
||||
Logger.Error?.Print(LogClass.Hid, "Rumble is not supported on this game controller.");
|
||||
}
|
||||
}
|
||||
|
||||
public Vector3 GetMotionData(MotionInputId inputId)
|
||||
{
|
||||
SDL_SensorType sensorType = inputId switch
|
||||
{
|
||||
MotionInputId.Accelerometer => SDL_SensorType.SDL_SENSOR_ACCEL,
|
||||
MotionInputId.Gyroscope => SDL_SensorType.SDL_SENSOR_GYRO,
|
||||
_ => SDL_SensorType.SDL_SENSOR_INVALID
|
||||
};
|
||||
|
||||
if (!Features.HasFlag(GamepadFeaturesFlag.Motion) || sensorType is SDL_SensorType.SDL_SENSOR_INVALID)
|
||||
return Vector3.Zero;
|
||||
|
||||
const int ElementCount = 3;
|
||||
|
||||
|
||||
unsafe
|
||||
{
|
||||
float* values = stackalloc float[ElementCount];
|
||||
if (!SDL_GetGamepadSensorData(_gamepadHandle, sensorType, values, ElementCount))
|
||||
{
|
||||
return Vector3.Zero;
|
||||
}
|
||||
|
||||
Vector3 value = new(values[0], values[1], values[2]);
|
||||
|
||||
return inputId switch
|
||||
{
|
||||
MotionInputId.Gyroscope => RadToDegree(value),
|
||||
MotionInputId.Accelerometer => GsToMs2(value),
|
||||
_ => value
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
private static Vector3 RadToDegree(Vector3 rad) => rad * (180 / MathF.PI);
|
||||
|
||||
private static Vector3 GsToMs2(Vector3 gs) => gs / SDL_STANDARD_GRAVITY;
|
||||
|
||||
public void SetConfiguration(InputConfig configuration)
|
||||
{
|
||||
lock (_userMappingLock)
|
||||
{
|
||||
_configuration = (StandardControllerInputConfig)configuration;
|
||||
|
||||
_buttonsUserMapping.Clear();
|
||||
|
||||
// First update sticks
|
||||
_stickUserMapping[(int)StickInputId.Left] = (StickInputId)_configuration.LeftJoyconStick.Joystick;
|
||||
_stickUserMapping[(int)StickInputId.Right] = (StickInputId)_configuration.RightJoyconStick.Joystick;
|
||||
|
||||
// Then left joycon
|
||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.LeftStick,
|
||||
(GamepadButtonInputId)_configuration.LeftJoyconStick.StickButton));
|
||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.DpadUp,
|
||||
(GamepadButtonInputId)_configuration.LeftJoycon.DpadUp));
|
||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.DpadDown,
|
||||
(GamepadButtonInputId)_configuration.LeftJoycon.DpadDown));
|
||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.DpadLeft,
|
||||
(GamepadButtonInputId)_configuration.LeftJoycon.DpadLeft));
|
||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.DpadRight,
|
||||
(GamepadButtonInputId)_configuration.LeftJoycon.DpadRight));
|
||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.Minus,
|
||||
(GamepadButtonInputId)_configuration.LeftJoycon.ButtonMinus));
|
||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.LeftShoulder,
|
||||
(GamepadButtonInputId)_configuration.LeftJoycon.ButtonL));
|
||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.LeftTrigger,
|
||||
(GamepadButtonInputId)_configuration.LeftJoycon.ButtonZl));
|
||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.SingleRightTrigger0,
|
||||
(GamepadButtonInputId)_configuration.LeftJoycon.ButtonSr));
|
||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.SingleLeftTrigger0,
|
||||
(GamepadButtonInputId)_configuration.LeftJoycon.ButtonSl));
|
||||
|
||||
// Finally right joycon
|
||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.RightStick,
|
||||
(GamepadButtonInputId)_configuration.RightJoyconStick.StickButton));
|
||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.A,
|
||||
(GamepadButtonInputId)_configuration.RightJoycon.ButtonA));
|
||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.B,
|
||||
(GamepadButtonInputId)_configuration.RightJoycon.ButtonB));
|
||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.X,
|
||||
(GamepadButtonInputId)_configuration.RightJoycon.ButtonX));
|
||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.Y,
|
||||
(GamepadButtonInputId)_configuration.RightJoycon.ButtonY));
|
||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.Plus,
|
||||
(GamepadButtonInputId)_configuration.RightJoycon.ButtonPlus));
|
||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.RightShoulder,
|
||||
(GamepadButtonInputId)_configuration.RightJoycon.ButtonR));
|
||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.RightTrigger,
|
||||
(GamepadButtonInputId)_configuration.RightJoycon.ButtonZr));
|
||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.SingleRightTrigger1,
|
||||
(GamepadButtonInputId)_configuration.RightJoycon.ButtonSr));
|
||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.SingleLeftTrigger1,
|
||||
(GamepadButtonInputId)_configuration.RightJoycon.ButtonSl));
|
||||
|
||||
SetTriggerThreshold(_configuration.TriggerThreshold);
|
||||
}
|
||||
}
|
||||
|
||||
public GamepadStateSnapshot GetStateSnapshot()
|
||||
{
|
||||
return IGamepad.GetStateSnapshot(this);
|
||||
}
|
||||
|
||||
public GamepadStateSnapshot GetMappedStateSnapshot()
|
||||
{
|
||||
GamepadStateSnapshot rawState = GetStateSnapshot();
|
||||
GamepadStateSnapshot result = default;
|
||||
|
||||
lock (_userMappingLock)
|
||||
{
|
||||
if (_buttonsUserMapping.Count == 0)
|
||||
return rawState;
|
||||
|
||||
|
||||
// ReSharper disable once ForeachCanBePartlyConvertedToQueryUsingAnotherGetEnumerator
|
||||
foreach (ButtonMappingEntry entry in _buttonsUserMapping)
|
||||
{
|
||||
if (!entry.IsValid)
|
||||
continue;
|
||||
|
||||
// Do not touch state of button already pressed
|
||||
if (!result.IsPressed(entry.To))
|
||||
{
|
||||
result.SetPressed(entry.To, rawState.IsPressed(entry.From));
|
||||
}
|
||||
}
|
||||
|
||||
(float leftStickX, float leftStickY) = rawState.GetStick(_stickUserMapping[(int)StickInputId.Left]);
|
||||
(float rightStickX, float rightStickY) = rawState.GetStick(_stickUserMapping[(int)StickInputId.Right]);
|
||||
|
||||
result.SetStick(StickInputId.Left, leftStickX, leftStickY);
|
||||
result.SetStick(StickInputId.Right, rightStickX, rightStickY);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private static float ConvertRawStickValue(short value)
|
||||
{
|
||||
const float ConvertRate = 1.0f / (short.MaxValue + 0.5f);
|
||||
|
||||
return value * ConvertRate;
|
||||
}
|
||||
|
||||
private JoyconConfigControllerStick<GamepadInputId, Common.Configuration.Hid.Controller.StickInputId>
|
||||
GetLogicalJoyStickConfig(StickInputId inputId)
|
||||
{
|
||||
switch (inputId)
|
||||
{
|
||||
case StickInputId.Left:
|
||||
if (_configuration.RightJoyconStick.Joystick ==
|
||||
Common.Configuration.Hid.Controller.StickInputId.Left)
|
||||
return _configuration.RightJoyconStick;
|
||||
else
|
||||
return _configuration.LeftJoyconStick;
|
||||
case StickInputId.Right:
|
||||
if (_configuration.LeftJoyconStick.Joystick ==
|
||||
Common.Configuration.Hid.Controller.StickInputId.Right)
|
||||
return _configuration.LeftJoyconStick;
|
||||
else
|
||||
return _configuration.RightJoyconStick;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public (float, float) GetStick(StickInputId inputId)
|
||||
{
|
||||
if (inputId == StickInputId.Unbound)
|
||||
return (0.0f, 0.0f);
|
||||
|
||||
(short stickX, short stickY) = GetStickXY(inputId);
|
||||
|
||||
float resultX = ConvertRawStickValue(stickX);
|
||||
float resultY = -ConvertRawStickValue(stickY);
|
||||
|
||||
if (HasConfiguration)
|
||||
{
|
||||
var joyconStickConfig = GetLogicalJoyStickConfig(inputId);
|
||||
|
||||
if (joyconStickConfig != null)
|
||||
{
|
||||
if (joyconStickConfig.InvertStickX)
|
||||
resultX = -resultX;
|
||||
|
||||
if (joyconStickConfig.InvertStickY)
|
||||
resultY = -resultY;
|
||||
|
||||
if (joyconStickConfig.Rotate90CW)
|
||||
{
|
||||
float temp = resultX;
|
||||
resultX = resultY;
|
||||
resultY = -temp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (resultX, resultY);
|
||||
}
|
||||
|
||||
// ReSharper disable once InconsistentNaming
|
||||
private (short, short) GetStickXY(StickInputId inputId) =>
|
||||
inputId switch
|
||||
{
|
||||
StickInputId.Left => (
|
||||
SDL_GetGamepadAxis(_gamepadHandle, SDL_GamepadAxis.SDL_GAMEPAD_AXIS_LEFTX),
|
||||
SDL_GetGamepadAxis(_gamepadHandle, SDL_GamepadAxis.SDL_GAMEPAD_AXIS_LEFTY)),
|
||||
StickInputId.Right => (
|
||||
SDL_GetGamepadAxis(_gamepadHandle, SDL_GamepadAxis.SDL_GAMEPAD_AXIS_RIGHTX),
|
||||
SDL_GetGamepadAxis(_gamepadHandle, SDL_GamepadAxis.SDL_GAMEPAD_AXIS_RIGHTY)),
|
||||
_ => throw new NotSupportedException($"Unsupported stick {inputId}")
|
||||
};
|
||||
|
||||
public bool IsPressed(GamepadButtonInputId inputId)
|
||||
{
|
||||
switch (inputId)
|
||||
{
|
||||
case GamepadButtonInputId.LeftTrigger:
|
||||
return ConvertRawStickValue(SDL_GetGamepadAxis(_gamepadHandle,
|
||||
SDL_GamepadAxis.SDL_GAMEPAD_AXIS_LEFT_TRIGGER)) > _triggerThreshold;
|
||||
case GamepadButtonInputId.RightTrigger:
|
||||
return ConvertRawStickValue(SDL_GetGamepadAxis(_gamepadHandle,
|
||||
SDL_GamepadAxis.SDL_GAMEPAD_AXIS_RIGHT_TRIGGER)) > _triggerThreshold;
|
||||
}
|
||||
|
||||
var button = _buttonsDriverMapping[(int)inputId];
|
||||
if (button == SDL_GamepadButton.SDL_GAMEPAD_BUTTON_INVALID)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return SDL_GetGamepadButton(_gamepadHandle, button);
|
||||
}
|
||||
}
|
||||
}
|
||||
192
src/Ryujinx.Input.SDL3/SDL3GamepadDriver.cs
Normal file
192
src/Ryujinx.Input.SDL3/SDL3GamepadDriver.cs
Normal file
@@ -0,0 +1,192 @@
|
||||
using Ryujinx.Common.Logging;
|
||||
using Ryujinx.Input.SDL3;
|
||||
using Ryujinx.SDL3.Common;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using static SDL3.SDL;
|
||||
|
||||
namespace Ryujinx.Input.SDL3
|
||||
{
|
||||
public class SDL3GamepadDriver : IGamepadDriver
|
||||
{
|
||||
private readonly Dictionary<uint, string> _gamepadsInstanceIdsMapping;
|
||||
private readonly List<string> _gamepadsIds;
|
||||
private readonly Lock _lock = new();
|
||||
|
||||
public ReadOnlySpan<string> GamepadsIds
|
||||
{
|
||||
get
|
||||
{
|
||||
lock (_lock)
|
||||
{
|
||||
return _gamepadsIds.ToArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public string DriverName => "SDL3";
|
||||
|
||||
public event Action<string> OnGamepadConnected;
|
||||
public event Action<string> OnGamepadDisconnected;
|
||||
|
||||
public SDL3GamepadDriver()
|
||||
{
|
||||
_gamepadsInstanceIdsMapping = new Dictionary<uint, string>();
|
||||
_gamepadsIds = new List<string>();
|
||||
|
||||
SDL3Driver.Instance.Initialize();
|
||||
SDL3Driver.Instance.OnJoyStickConnected += HandleJoyStickConnected;
|
||||
SDL3Driver.Instance.OnJoystickDisconnected += HandleJoyStickDisconnected;
|
||||
SDL3Driver.Instance.OnJoyBatteryUpdated += HandleJoyBatteryUpdated;
|
||||
}
|
||||
|
||||
private string GenerateGamepadId(uint joystickId)
|
||||
{
|
||||
int bufferSize = 33;
|
||||
Span<byte> pszGuid = stackalloc byte[bufferSize];
|
||||
SDL_GUIDToString(SDL_GetJoystickGUIDForID(joystickId), pszGuid, bufferSize);
|
||||
var guid = Encoding.UTF8.GetString(pszGuid);
|
||||
|
||||
string id;
|
||||
lock (_lock)
|
||||
{
|
||||
int guidIndex = 0;
|
||||
id = guidIndex + guid;
|
||||
|
||||
while (_gamepadsIds.Contains(id))
|
||||
{
|
||||
id = (++guidIndex) + "-" + guid;
|
||||
}
|
||||
}
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
private KeyValuePair<uint,string> GetGamepadInfoByGamepadId(string id)
|
||||
{
|
||||
lock (_lock)
|
||||
{
|
||||
return _gamepadsInstanceIdsMapping.FirstOrDefault(gamepadId => gamepadId.Value == id);
|
||||
}
|
||||
}
|
||||
|
||||
private void HandleJoyStickDisconnected(uint joystickId)
|
||||
{
|
||||
bool joyConPairDisconnected = false;
|
||||
if (!_gamepadsInstanceIdsMapping.Remove(joystickId, out string id))
|
||||
return;
|
||||
|
||||
lock (_lock)
|
||||
{
|
||||
_gamepadsIds.Remove(id);
|
||||
if (!SDL3JoyConPair.IsCombinable(_gamepadsInstanceIdsMapping))
|
||||
{
|
||||
_gamepadsIds.Remove(SDL3JoyConPair.Id);
|
||||
joyConPairDisconnected = true;
|
||||
}
|
||||
}
|
||||
|
||||
OnGamepadDisconnected?.Invoke(id);
|
||||
if (joyConPairDisconnected)
|
||||
{
|
||||
OnGamepadDisconnected?.Invoke(SDL3JoyConPair.Id);
|
||||
}
|
||||
}
|
||||
|
||||
private void HandleJoyStickConnected(uint joystickId)
|
||||
{
|
||||
bool joyConPairConnected = false;
|
||||
|
||||
if (_gamepadsInstanceIdsMapping.ContainsKey(joystickId))
|
||||
{
|
||||
// Sometimes a JoyStick connected event fires after the app starts even though it was connected before
|
||||
// so it is rejected to avoid doubling the entries.
|
||||
return;
|
||||
}
|
||||
|
||||
string id = GenerateGamepadId(joystickId);
|
||||
if (id == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (_gamepadsInstanceIdsMapping.TryAdd(joystickId, id))
|
||||
{
|
||||
lock (_lock)
|
||||
{
|
||||
_gamepadsIds.Add(id);
|
||||
|
||||
if (SDL3JoyConPair.IsCombinable(_gamepadsInstanceIdsMapping))
|
||||
{
|
||||
_gamepadsIds.Remove(SDL3JoyConPair.Id);
|
||||
_gamepadsIds.Add(SDL3JoyConPair.Id);
|
||||
joyConPairConnected = true;
|
||||
}
|
||||
}
|
||||
|
||||
OnGamepadConnected?.Invoke(id);
|
||||
if (joyConPairConnected)
|
||||
{
|
||||
OnGamepadConnected?.Invoke(SDL3JoyConPair.Id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void HandleJoyBatteryUpdated(uint joystickId, SDL_JoyBatteryEvent joyBatteryEvent)
|
||||
{
|
||||
Logger.Info?.Print(LogClass.Hid,
|
||||
$"{SDL_GetGamepadNameForID(joystickId)}, Battery percent: {joyBatteryEvent.percent}");
|
||||
}
|
||||
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
SDL3Driver.Instance.OnJoyStickConnected -= HandleJoyStickConnected;
|
||||
SDL3Driver.Instance.OnJoystickDisconnected -= HandleJoyStickDisconnected;
|
||||
|
||||
// Simulate a full disconnect when disposing
|
||||
foreach (string id in _gamepadsIds)
|
||||
{
|
||||
OnGamepadDisconnected?.Invoke(id);
|
||||
}
|
||||
|
||||
lock (_lock)
|
||||
{
|
||||
_gamepadsIds.Clear();
|
||||
}
|
||||
|
||||
SDL3Driver.Instance.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
GC.SuppressFinalize(this);
|
||||
Dispose(true);
|
||||
}
|
||||
|
||||
public IGamepad GetGamepad(string id)
|
||||
{
|
||||
if (id == SDL3JoyConPair.Id)
|
||||
{
|
||||
lock (_lock)
|
||||
{
|
||||
return SDL3JoyConPair.GetGamepad(_gamepadsInstanceIdsMapping);
|
||||
}
|
||||
}
|
||||
|
||||
var gamepadInfo = GetGamepadInfoByGamepadId(id);
|
||||
|
||||
if (SDL3JoyCon.IsJoyCon(gamepadInfo.Key))
|
||||
{
|
||||
return new SDL3JoyCon(gamepadInfo.Key, gamepadInfo.Value);
|
||||
}
|
||||
|
||||
return new SDL3Gamepad(gamepadInfo.Key, gamepadInfo.Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
418
src/Ryujinx.Input.SDL3/SDL3JoyCon.cs
Normal file
418
src/Ryujinx.Input.SDL3/SDL3JoyCon.cs
Normal file
@@ -0,0 +1,418 @@
|
||||
using Ryujinx.Common.Configuration.Hid;
|
||||
using Ryujinx.Common.Configuration.Hid.Controller;
|
||||
using Ryujinx.Common.Logging;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Numerics;
|
||||
using System.Threading;
|
||||
using static SDL3.SDL;
|
||||
|
||||
namespace Ryujinx.Input.SDL3
|
||||
{
|
||||
class SDL3JoyCon : IGamepad
|
||||
{
|
||||
private bool HasConfiguration => _configuration != null;
|
||||
|
||||
private readonly record struct ButtonMappingEntry(GamepadButtonInputId To, GamepadButtonInputId From)
|
||||
{
|
||||
public bool IsValid => To is not GamepadButtonInputId.Unbound && From is not GamepadButtonInputId.Unbound;
|
||||
}
|
||||
|
||||
private StandardControllerInputConfig _configuration;
|
||||
|
||||
private static readonly Dictionary<GamepadButtonInputId, SDL_GamepadButton> _leftButtonsDriverDict = new()
|
||||
{
|
||||
{ GamepadButtonInputId.LeftStick, SDL_GamepadButton.SDL_GAMEPAD_BUTTON_LEFT_STICK },
|
||||
{ GamepadButtonInputId.DpadUp, SDL_GamepadButton.SDL_GAMEPAD_BUTTON_WEST },
|
||||
{ GamepadButtonInputId.DpadDown, SDL_GamepadButton.SDL_GAMEPAD_BUTTON_EAST },
|
||||
{ GamepadButtonInputId.DpadLeft, SDL_GamepadButton.SDL_GAMEPAD_BUTTON_SOUTH },
|
||||
{ GamepadButtonInputId.DpadRight, SDL_GamepadButton.SDL_GAMEPAD_BUTTON_NORTH },
|
||||
{ GamepadButtonInputId.Minus, SDL_GamepadButton.SDL_GAMEPAD_BUTTON_START },
|
||||
{ GamepadButtonInputId.LeftShoulder, SDL_GamepadButton.SDL_GAMEPAD_BUTTON_LEFT_PADDLE1 },
|
||||
{ GamepadButtonInputId.LeftTrigger, SDL_GamepadButton.SDL_GAMEPAD_BUTTON_LEFT_PADDLE2 },
|
||||
{ GamepadButtonInputId.SingleRightTrigger0, SDL_GamepadButton.SDL_GAMEPAD_BUTTON_RIGHT_SHOULDER },
|
||||
{ GamepadButtonInputId.SingleLeftTrigger0, SDL_GamepadButton.SDL_GAMEPAD_BUTTON_LEFT_SHOULDER },
|
||||
};
|
||||
|
||||
private static readonly Dictionary<GamepadButtonInputId, SDL_GamepadButton> _rightButtonsDriverDict = new()
|
||||
{
|
||||
{ GamepadButtonInputId.RightStick, SDL_GamepadButton.SDL_GAMEPAD_BUTTON_LEFT_STICK },
|
||||
{ GamepadButtonInputId.A, SDL_GamepadButton.SDL_GAMEPAD_BUTTON_SOUTH },
|
||||
{ GamepadButtonInputId.B, SDL_GamepadButton.SDL_GAMEPAD_BUTTON_WEST },
|
||||
{ GamepadButtonInputId.X, SDL_GamepadButton.SDL_GAMEPAD_BUTTON_EAST },
|
||||
{ GamepadButtonInputId.Y, SDL_GamepadButton.SDL_GAMEPAD_BUTTON_NORTH },
|
||||
{ GamepadButtonInputId.Plus, SDL_GamepadButton.SDL_GAMEPAD_BUTTON_START },
|
||||
{ GamepadButtonInputId.RightShoulder, SDL_GamepadButton.SDL_GAMEPAD_BUTTON_RIGHT_PADDLE1 },
|
||||
{ GamepadButtonInputId.RightTrigger, SDL_GamepadButton.SDL_GAMEPAD_BUTTON_RIGHT_PADDLE2 },
|
||||
{ GamepadButtonInputId.SingleRightTrigger1, SDL_GamepadButton.SDL_GAMEPAD_BUTTON_RIGHT_SHOULDER },
|
||||
{ GamepadButtonInputId.SingleLeftTrigger1, SDL_GamepadButton.SDL_GAMEPAD_BUTTON_LEFT_SHOULDER }
|
||||
};
|
||||
|
||||
private readonly SDL_GamepadButton[] _buttonsDriverMapping;
|
||||
private readonly Lock _userMappingLock = new();
|
||||
|
||||
private readonly List<ButtonMappingEntry> _buttonsUserMapping;
|
||||
|
||||
private readonly StickInputId[] _stickUserMapping = new StickInputId[(int)StickInputId.Count]
|
||||
{
|
||||
StickInputId.Unbound, StickInputId.Left, StickInputId.Right,
|
||||
};
|
||||
|
||||
public GamepadFeaturesFlag Features { get; }
|
||||
|
||||
private nint _gamepadHandle;
|
||||
|
||||
private readonly SDL_GamepadType _gamepadType;
|
||||
|
||||
public SDL3JoyCon(uint joystickId, string driverId)
|
||||
{
|
||||
_gamepadHandle = SDL_OpenGamepad(joystickId);
|
||||
_buttonsUserMapping = new List<ButtonMappingEntry>(10);
|
||||
|
||||
Name = SDL_GetGamepadName(_gamepadHandle);
|
||||
Id = driverId;
|
||||
Features = GetFeaturesFlag();
|
||||
|
||||
// Enable motion tracking
|
||||
if (Features.HasFlag(GamepadFeaturesFlag.Motion))
|
||||
{
|
||||
if (!SDL_SetGamepadSensorEnabled(_gamepadHandle, SDL_SensorType.SDL_SENSOR_ACCEL, true))
|
||||
{
|
||||
Logger.Error?.Print(LogClass.Hid,
|
||||
$"Could not enable data reporting for SensorType {SDL_SensorType.SDL_SENSOR_ACCEL}.");
|
||||
}
|
||||
|
||||
if (!SDL_SetGamepadSensorEnabled(_gamepadHandle, SDL_SensorType.SDL_SENSOR_GYRO, true))
|
||||
{
|
||||
Logger.Error?.Print(LogClass.Hid,
|
||||
$"Could not enable data reporting for SensorType {SDL_SensorType.SDL_SENSOR_GYRO}.");
|
||||
}
|
||||
}
|
||||
|
||||
_gamepadType = SDL_GetGamepadType(_gamepadHandle);
|
||||
|
||||
_buttonsDriverMapping = _gamepadType switch
|
||||
{
|
||||
SDL_GamepadType.SDL_GAMEPAD_TYPE_NINTENDO_SWITCH_JOYCON_LEFT => ToSDLButtonMapping(
|
||||
_leftButtonsDriverDict),
|
||||
SDL_GamepadType.SDL_GAMEPAD_TYPE_NINTENDO_SWITCH_JOYCON_RIGHT => ToSDLButtonMapping(
|
||||
_rightButtonsDriverDict),
|
||||
_ => throw new InvalidOperationException($"Unexpected JoyConType value: {_gamepadType}")
|
||||
};
|
||||
}
|
||||
|
||||
private static SDL_GamepadButton[] ToSDLButtonMapping(
|
||||
Dictionary<GamepadButtonInputId, SDL_GamepadButton> buttonsDriverDict)
|
||||
{
|
||||
return Enumerable.Range(0, (int)GamepadButtonInputId.Count)
|
||||
.Select(i =>
|
||||
buttonsDriverDict.GetValueOrDefault((GamepadButtonInputId)i,
|
||||
SDL_GamepadButton.SDL_GAMEPAD_BUTTON_INVALID))
|
||||
.ToArray();
|
||||
}
|
||||
|
||||
private GamepadFeaturesFlag GetFeaturesFlag()
|
||||
{
|
||||
GamepadFeaturesFlag result = GamepadFeaturesFlag.None;
|
||||
if (SDL_GamepadHasSensor(_gamepadHandle, SDL_SensorType.SDL_SENSOR_ACCEL) &&
|
||||
SDL_GamepadHasSensor(_gamepadHandle, SDL_SensorType.SDL_SENSOR_GYRO))
|
||||
{
|
||||
result |= GamepadFeaturesFlag.Motion;
|
||||
}
|
||||
|
||||
if (SDL_RumbleGamepad(_gamepadHandle, 0, 0, 100))
|
||||
{
|
||||
result |= GamepadFeaturesFlag.Rumble;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public string Id { get; }
|
||||
public string Name { get; }
|
||||
public bool IsConnected => SDL_GamepadConnected(_gamepadHandle);
|
||||
|
||||
private void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing && _gamepadHandle != nint.Zero)
|
||||
{
|
||||
SDL_CloseGamepad(_gamepadHandle);
|
||||
_gamepadHandle = nint.Zero;
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(true);
|
||||
}
|
||||
|
||||
|
||||
public void SetTriggerThreshold(float triggerThreshold)
|
||||
{
|
||||
}
|
||||
|
||||
public void Rumble(float lowFrequency, float highFrequency, uint durationMs)
|
||||
{
|
||||
if (!Features.HasFlag(GamepadFeaturesFlag.Rumble))
|
||||
return;
|
||||
|
||||
ushort lowFrequencyRaw = (ushort)(lowFrequency * ushort.MaxValue);
|
||||
ushort highFrequencyRaw = (ushort)(highFrequency * ushort.MaxValue);
|
||||
|
||||
if (!SDL_RumbleGamepad(_gamepadHandle, lowFrequencyRaw, highFrequencyRaw, durationMs))
|
||||
{
|
||||
Logger.Error?.Print(LogClass.Hid, "Rumble is not supported on this game controller.");
|
||||
}
|
||||
}
|
||||
|
||||
public Vector3 GetMotionData(MotionInputId inputId)
|
||||
{
|
||||
SDL_SensorType sensorType = inputId switch
|
||||
{
|
||||
MotionInputId.Accelerometer => SDL_SensorType.SDL_SENSOR_ACCEL,
|
||||
MotionInputId.Gyroscope => SDL_SensorType.SDL_SENSOR_GYRO,
|
||||
_ => SDL_SensorType.SDL_SENSOR_INVALID
|
||||
};
|
||||
|
||||
if (!Features.HasFlag(GamepadFeaturesFlag.Motion) || sensorType is SDL_SensorType.SDL_SENSOR_INVALID)
|
||||
return Vector3.Zero;
|
||||
|
||||
const int ElementCount = 3;
|
||||
|
||||
unsafe
|
||||
{
|
||||
float* values = stackalloc float[ElementCount];
|
||||
|
||||
if (!SDL_GetGamepadSensorData(_gamepadHandle, sensorType, values, ElementCount))
|
||||
{
|
||||
return Vector3.Zero;
|
||||
}
|
||||
|
||||
Vector3 value = _gamepadType switch
|
||||
{
|
||||
SDL_GamepadType.SDL_GAMEPAD_TYPE_NINTENDO_SWITCH_JOYCON_LEFT => new Vector3(-values[2], values[1], values[0]),
|
||||
SDL_GamepadType.SDL_GAMEPAD_TYPE_NINTENDO_SWITCH_JOYCON_RIGHT => new Vector3(values[2], values[1], -values[0]),
|
||||
_ => throw new ArgumentOutOfRangeException($"Unexpected JoyConType value: {_gamepadType}")
|
||||
};
|
||||
|
||||
return inputId switch
|
||||
{
|
||||
MotionInputId.Gyroscope => RadToDegree(value),
|
||||
MotionInputId.Accelerometer => GsToMs2(value),
|
||||
_ => value
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
private static Vector3 RadToDegree(Vector3 rad) => rad * (180 / MathF.PI);
|
||||
private static Vector3 GsToMs2(Vector3 gs) => gs / SDL_STANDARD_GRAVITY;
|
||||
|
||||
public void SetConfiguration(InputConfig configuration)
|
||||
{
|
||||
lock (_userMappingLock)
|
||||
{
|
||||
_configuration = (StandardControllerInputConfig)configuration;
|
||||
|
||||
_buttonsUserMapping.Clear();
|
||||
|
||||
// First update sticks
|
||||
_stickUserMapping[(int)StickInputId.Left] = (StickInputId)_configuration.LeftJoyconStick.Joystick;
|
||||
_stickUserMapping[(int)StickInputId.Right] = (StickInputId)_configuration.RightJoyconStick.Joystick;
|
||||
|
||||
|
||||
switch (_gamepadType)
|
||||
{
|
||||
case SDL_GamepadType.SDL_GAMEPAD_TYPE_NINTENDO_SWITCH_JOYCON_LEFT:
|
||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.LeftStick,
|
||||
(GamepadButtonInputId)_configuration.LeftJoyconStick.StickButton));
|
||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.DpadUp,
|
||||
(GamepadButtonInputId)_configuration.LeftJoycon.DpadUp));
|
||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.DpadDown,
|
||||
(GamepadButtonInputId)_configuration.LeftJoycon.DpadDown));
|
||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.DpadLeft,
|
||||
(GamepadButtonInputId)_configuration.LeftJoycon.DpadLeft));
|
||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.DpadRight,
|
||||
(GamepadButtonInputId)_configuration.LeftJoycon.DpadRight));
|
||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.Minus,
|
||||
(GamepadButtonInputId)_configuration.LeftJoycon.ButtonMinus));
|
||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.LeftShoulder,
|
||||
(GamepadButtonInputId)_configuration.LeftJoycon.ButtonL));
|
||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.LeftTrigger,
|
||||
(GamepadButtonInputId)_configuration.LeftJoycon.ButtonZl));
|
||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.SingleRightTrigger0,
|
||||
(GamepadButtonInputId)_configuration.LeftJoycon.ButtonSr));
|
||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.SingleLeftTrigger0,
|
||||
(GamepadButtonInputId)_configuration.LeftJoycon.ButtonSl));
|
||||
break;
|
||||
case SDL_GamepadType.SDL_GAMEPAD_TYPE_NINTENDO_SWITCH_JOYCON_RIGHT:
|
||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.RightStick,
|
||||
(GamepadButtonInputId)_configuration.RightJoyconStick.StickButton));
|
||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.A,
|
||||
(GamepadButtonInputId)_configuration.RightJoycon.ButtonA));
|
||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.B,
|
||||
(GamepadButtonInputId)_configuration.RightJoycon.ButtonB));
|
||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.X,
|
||||
(GamepadButtonInputId)_configuration.RightJoycon.ButtonX));
|
||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.Y,
|
||||
(GamepadButtonInputId)_configuration.RightJoycon.ButtonY));
|
||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.Plus,
|
||||
(GamepadButtonInputId)_configuration.RightJoycon.ButtonPlus));
|
||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.RightShoulder,
|
||||
(GamepadButtonInputId)_configuration.RightJoycon.ButtonR));
|
||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.RightTrigger,
|
||||
(GamepadButtonInputId)_configuration.RightJoycon.ButtonZr));
|
||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.SingleRightTrigger1,
|
||||
(GamepadButtonInputId)_configuration.RightJoycon.ButtonSr));
|
||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.SingleLeftTrigger1,
|
||||
(GamepadButtonInputId)_configuration.RightJoycon.ButtonSl));
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
|
||||
SetTriggerThreshold(_configuration.TriggerThreshold);
|
||||
}
|
||||
}
|
||||
|
||||
public GamepadStateSnapshot GetStateSnapshot()
|
||||
{
|
||||
return IGamepad.GetStateSnapshot(this);
|
||||
}
|
||||
|
||||
public GamepadStateSnapshot GetMappedStateSnapshot()
|
||||
{
|
||||
GamepadStateSnapshot rawState = GetStateSnapshot();
|
||||
GamepadStateSnapshot result = default;
|
||||
|
||||
lock (_userMappingLock)
|
||||
{
|
||||
if (_buttonsUserMapping.Count == 0)
|
||||
return rawState;
|
||||
|
||||
|
||||
// ReSharper disable once ForeachCanBePartlyConvertedToQueryUsingAnotherGetEnumerator
|
||||
foreach (ButtonMappingEntry entry in _buttonsUserMapping)
|
||||
{
|
||||
if (!entry.IsValid)
|
||||
continue;
|
||||
|
||||
// Do not touch state of button already pressed
|
||||
if (!result.IsPressed(entry.To))
|
||||
{
|
||||
result.SetPressed(entry.To, rawState.IsPressed(entry.From));
|
||||
}
|
||||
}
|
||||
|
||||
(float leftStickX, float leftStickY) = rawState.GetStick(_stickUserMapping[(int)StickInputId.Left]);
|
||||
(float rightStickX, float rightStickY) = rawState.GetStick(_stickUserMapping[(int)StickInputId.Right]);
|
||||
|
||||
result.SetStick(StickInputId.Left, leftStickX, leftStickY);
|
||||
result.SetStick(StickInputId.Right, rightStickX, rightStickY);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
private static float ConvertRawStickValue(short value)
|
||||
{
|
||||
const float ConvertRate = 1.0f / (short.MaxValue + 0.5f);
|
||||
|
||||
return value * ConvertRate;
|
||||
}
|
||||
|
||||
private JoyconConfigControllerStick<GamepadInputId, Common.Configuration.Hid.Controller.StickInputId>
|
||||
GetLogicalJoyStickConfig(StickInputId inputId)
|
||||
{
|
||||
switch (inputId)
|
||||
{
|
||||
case StickInputId.Left:
|
||||
if (_configuration.RightJoyconStick.Joystick ==
|
||||
Common.Configuration.Hid.Controller.StickInputId.Left)
|
||||
return _configuration.RightJoyconStick;
|
||||
else
|
||||
return _configuration.LeftJoyconStick;
|
||||
case StickInputId.Right:
|
||||
if (_configuration.LeftJoyconStick.Joystick ==
|
||||
Common.Configuration.Hid.Controller.StickInputId.Right)
|
||||
return _configuration.LeftJoyconStick;
|
||||
else
|
||||
return _configuration.RightJoyconStick;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
public (float, float) GetStick(StickInputId inputId)
|
||||
{
|
||||
if (inputId == StickInputId.Unbound)
|
||||
return (0.0f, 0.0f);
|
||||
|
||||
if (inputId == StickInputId.Left && _gamepadType == SDL_GamepadType.SDL_GAMEPAD_TYPE_NINTENDO_SWITCH_JOYCON_RIGHT ||
|
||||
inputId == StickInputId.Right && _gamepadType == SDL_GamepadType.SDL_GAMEPAD_TYPE_NINTENDO_SWITCH_JOYCON_LEFT)
|
||||
{
|
||||
return (0.0f, 0.0f);
|
||||
}
|
||||
|
||||
(short stickX, short stickY) = GetStickXY();
|
||||
|
||||
float resultX = ConvertRawStickValue(stickX);
|
||||
float resultY = -ConvertRawStickValue(stickY);
|
||||
|
||||
if (HasConfiguration)
|
||||
{
|
||||
var joyconStickConfig = GetLogicalJoyStickConfig(inputId);
|
||||
|
||||
if (joyconStickConfig != null)
|
||||
{
|
||||
if (joyconStickConfig.InvertStickX)
|
||||
resultX = -resultX;
|
||||
|
||||
if (joyconStickConfig.InvertStickY)
|
||||
resultY = -resultY;
|
||||
|
||||
if (joyconStickConfig.Rotate90CW)
|
||||
{
|
||||
float temp = resultX;
|
||||
resultX = resultY;
|
||||
resultY = -temp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return inputId switch
|
||||
{
|
||||
StickInputId.Left when _gamepadType == SDL_GamepadType.SDL_GAMEPAD_TYPE_NINTENDO_SWITCH_JOYCON_LEFT => (resultY, -resultX),
|
||||
StickInputId.Right when _gamepadType == SDL_GamepadType.SDL_GAMEPAD_TYPE_NINTENDO_SWITCH_JOYCON_RIGHT => (-resultY, resultX),
|
||||
_ => (0.0f, 0.0f)
|
||||
};
|
||||
}
|
||||
|
||||
private (short, short) GetStickXY()
|
||||
{
|
||||
return (
|
||||
SDL_GetGamepadAxis(_gamepadHandle, SDL_GamepadAxis.SDL_GAMEPAD_AXIS_LEFTX),
|
||||
SDL_GetGamepadAxis(_gamepadHandle, SDL_GamepadAxis.SDL_GAMEPAD_AXIS_LEFTY));
|
||||
}
|
||||
|
||||
public bool IsPressed(GamepadButtonInputId inputId)
|
||||
{
|
||||
var button = _buttonsDriverMapping[(int)inputId];
|
||||
if (button == SDL_GamepadButton.SDL_GAMEPAD_BUTTON_INVALID)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return SDL_GetGamepadButton(_gamepadHandle, button);
|
||||
}
|
||||
|
||||
public static bool IsJoyCon(uint joystickId)
|
||||
{
|
||||
var gamepadName = SDL_GetGamepadTypeForID(joystickId);
|
||||
return gamepadName is SDL_GamepadType.SDL_GAMEPAD_TYPE_NINTENDO_SWITCH_JOYCON_LEFT
|
||||
or SDL_GamepadType.SDL_GAMEPAD_TYPE_NINTENDO_SWITCH_JOYCON_RIGHT;
|
||||
}
|
||||
}
|
||||
}
|
||||
215
src/Ryujinx.Input.SDL3/SDL3JoyConPair.cs
Normal file
215
src/Ryujinx.Input.SDL3/SDL3JoyConPair.cs
Normal file
@@ -0,0 +1,215 @@
|
||||
using Ryujinx.Common.Configuration.Hid;
|
||||
using Ryujinx.Common.Configuration.Hid.Controller;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Numerics;
|
||||
using System.Threading;
|
||||
using static SDL3.SDL;
|
||||
|
||||
namespace Ryujinx.Input.SDL3
|
||||
{
|
||||
class SDL3JoyConPair(SDL3JoyCon left, SDL3JoyCon right) : IGamepad
|
||||
{
|
||||
private StandardControllerInputConfig _configuration;
|
||||
|
||||
private readonly record struct ButtonMappingEntry(GamepadButtonInputId To, GamepadButtonInputId From)
|
||||
{
|
||||
public bool IsValid => To is not GamepadButtonInputId.Unbound && From is not GamepadButtonInputId.Unbound;
|
||||
}
|
||||
|
||||
private readonly StickInputId[] _stickUserMapping = new StickInputId[(int)StickInputId.Count]
|
||||
{
|
||||
StickInputId.Unbound, StickInputId.Left, StickInputId.Right,
|
||||
};
|
||||
|
||||
public GamepadFeaturesFlag Features => (left?.Features ?? GamepadFeaturesFlag.None) |
|
||||
(right?.Features ?? GamepadFeaturesFlag.None);
|
||||
|
||||
public const string Id = "JoyConPair";
|
||||
private readonly Lock _userMappingLock = new();
|
||||
|
||||
private readonly List<ButtonMappingEntry> _buttonsUserMapping = new List<ButtonMappingEntry>(20);
|
||||
string IGamepad.Id => Id;
|
||||
|
||||
public string Name => "* Nintendo Switch Joy-Con (L/R)";
|
||||
public bool IsConnected => left is { IsConnected: true } && right is { IsConnected: true };
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
left?.Dispose();
|
||||
right?.Dispose();
|
||||
}
|
||||
|
||||
public GamepadStateSnapshot GetMappedStateSnapshot()
|
||||
{
|
||||
GamepadStateSnapshot rawState = GetStateSnapshot();
|
||||
GamepadStateSnapshot result = default;
|
||||
|
||||
lock (_userMappingLock)
|
||||
{
|
||||
if (_buttonsUserMapping.Count == 0)
|
||||
return rawState;
|
||||
|
||||
|
||||
// ReSharper disable once ForeachCanBePartlyConvertedToQueryUsingAnotherGetEnumerator
|
||||
foreach (ButtonMappingEntry entry in _buttonsUserMapping)
|
||||
{
|
||||
if (!entry.IsValid)
|
||||
continue;
|
||||
|
||||
// Do not touch state of button already pressed
|
||||
if (!result.IsPressed(entry.To))
|
||||
{
|
||||
result.SetPressed(entry.To, rawState.IsPressed(entry.From));
|
||||
}
|
||||
}
|
||||
|
||||
(float leftStickX, float leftStickY) = rawState.GetStick(_stickUserMapping[(int)StickInputId.Left]);
|
||||
(float rightStickX, float rightStickY) = rawState.GetStick(_stickUserMapping[(int)StickInputId.Right]);
|
||||
|
||||
result.SetStick(StickInputId.Left, leftStickX, leftStickY);
|
||||
result.SetStick(StickInputId.Right, rightStickX, rightStickY);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public Vector3 GetMotionData(MotionInputId inputId)
|
||||
{
|
||||
return inputId switch
|
||||
{
|
||||
MotionInputId.Accelerometer or
|
||||
MotionInputId.Gyroscope => left.GetMotionData(inputId),
|
||||
MotionInputId.SecondAccelerometer => right.GetMotionData(MotionInputId.Accelerometer),
|
||||
MotionInputId.SecondGyroscope => right.GetMotionData(MotionInputId.Gyroscope),
|
||||
_ => Vector3.Zero
|
||||
};
|
||||
}
|
||||
|
||||
public GamepadStateSnapshot GetStateSnapshot()
|
||||
{
|
||||
return IGamepad.GetStateSnapshot(this);
|
||||
}
|
||||
|
||||
public (float, float) GetStick(StickInputId inputId)
|
||||
{
|
||||
return inputId switch
|
||||
{
|
||||
StickInputId.Left => left.GetStick(StickInputId.Left),
|
||||
StickInputId.Right => right.GetStick(StickInputId.Right),
|
||||
_ => (0, 0)
|
||||
};
|
||||
}
|
||||
|
||||
public bool IsPressed(GamepadButtonInputId inputId)
|
||||
{
|
||||
return left.IsPressed(inputId) || right.IsPressed(inputId);
|
||||
}
|
||||
|
||||
public void Rumble(float lowFrequency, float highFrequency, uint durationMs)
|
||||
{
|
||||
if (lowFrequency != 0)
|
||||
{
|
||||
right.Rumble(lowFrequency, lowFrequency, durationMs);
|
||||
}
|
||||
|
||||
if (highFrequency != 0)
|
||||
{
|
||||
left.Rumble(highFrequency, highFrequency, durationMs);
|
||||
}
|
||||
|
||||
if (lowFrequency == 0 && highFrequency == 0)
|
||||
{
|
||||
left.Rumble(0, 0, durationMs);
|
||||
right.Rumble(0, 0, durationMs);
|
||||
}
|
||||
}
|
||||
|
||||
public void SetConfiguration(InputConfig configuration)
|
||||
{
|
||||
lock (_userMappingLock)
|
||||
{
|
||||
_configuration = (StandardControllerInputConfig)configuration;
|
||||
_buttonsUserMapping.Clear();
|
||||
|
||||
// First update sticks
|
||||
_stickUserMapping[(int)StickInputId.Left] = (StickInputId)_configuration.LeftJoyconStick.Joystick;
|
||||
_stickUserMapping[(int)StickInputId.Right] = (StickInputId)_configuration.RightJoyconStick.Joystick;
|
||||
|
||||
// Then left joycon
|
||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.LeftStick,
|
||||
(GamepadButtonInputId)_configuration.LeftJoyconStick.StickButton));
|
||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.DpadUp,
|
||||
(GamepadButtonInputId)_configuration.LeftJoycon.DpadUp));
|
||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.DpadDown,
|
||||
(GamepadButtonInputId)_configuration.LeftJoycon.DpadDown));
|
||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.DpadLeft,
|
||||
(GamepadButtonInputId)_configuration.LeftJoycon.DpadLeft));
|
||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.DpadRight,
|
||||
(GamepadButtonInputId)_configuration.LeftJoycon.DpadRight));
|
||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.Minus,
|
||||
(GamepadButtonInputId)_configuration.LeftJoycon.ButtonMinus));
|
||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.LeftShoulder,
|
||||
(GamepadButtonInputId)_configuration.LeftJoycon.ButtonL));
|
||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.LeftTrigger,
|
||||
(GamepadButtonInputId)_configuration.LeftJoycon.ButtonZl));
|
||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.SingleRightTrigger0,
|
||||
(GamepadButtonInputId)_configuration.LeftJoycon.ButtonSr));
|
||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.SingleLeftTrigger0,
|
||||
(GamepadButtonInputId)_configuration.LeftJoycon.ButtonSl));
|
||||
|
||||
// Finally right joycon
|
||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.RightStick,
|
||||
(GamepadButtonInputId)_configuration.RightJoyconStick.StickButton));
|
||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.A,
|
||||
(GamepadButtonInputId)_configuration.RightJoycon.ButtonA));
|
||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.B,
|
||||
(GamepadButtonInputId)_configuration.RightJoycon.ButtonB));
|
||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.X,
|
||||
(GamepadButtonInputId)_configuration.RightJoycon.ButtonX));
|
||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.Y,
|
||||
(GamepadButtonInputId)_configuration.RightJoycon.ButtonY));
|
||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.Plus,
|
||||
(GamepadButtonInputId)_configuration.RightJoycon.ButtonPlus));
|
||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.RightShoulder,
|
||||
(GamepadButtonInputId)_configuration.RightJoycon.ButtonR));
|
||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.RightTrigger,
|
||||
(GamepadButtonInputId)_configuration.RightJoycon.ButtonZr));
|
||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.SingleRightTrigger1,
|
||||
(GamepadButtonInputId)_configuration.RightJoycon.ButtonSr));
|
||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.SingleLeftTrigger1,
|
||||
(GamepadButtonInputId)_configuration.RightJoycon.ButtonSl));
|
||||
left.SetConfiguration(configuration);
|
||||
right.SetConfiguration(configuration);
|
||||
}
|
||||
}
|
||||
|
||||
public void SetTriggerThreshold(float triggerThreshold)
|
||||
{
|
||||
}
|
||||
|
||||
public static bool IsCombinable(Dictionary<uint, string> gamepadsInstanceIdsMapping)
|
||||
{
|
||||
var gamepadTypes = gamepadsInstanceIdsMapping.Keys.Select(SDL_GetGamepadTypeForID).ToArray();
|
||||
return gamepadTypes.Contains(SDL_GamepadType.SDL_GAMEPAD_TYPE_NINTENDO_SWITCH_JOYCON_LEFT) &&
|
||||
gamepadTypes.Contains(SDL_GamepadType.SDL_GAMEPAD_TYPE_NINTENDO_SWITCH_JOYCON_RIGHT);
|
||||
}
|
||||
|
||||
public static IGamepad GetGamepad(Dictionary<uint, string> gamepadsInstanceIdsMapping)
|
||||
{
|
||||
var leftPair =
|
||||
gamepadsInstanceIdsMapping.FirstOrDefault(pair =>
|
||||
SDL_GetGamepadTypeForID(pair.Key) == SDL_GamepadType.SDL_GAMEPAD_TYPE_NINTENDO_SWITCH_JOYCON_LEFT);
|
||||
var rightPair =
|
||||
gamepadsInstanceIdsMapping.FirstOrDefault(pair =>
|
||||
SDL_GetGamepadTypeForID(pair.Key) == SDL_GamepadType.SDL_GAMEPAD_TYPE_NINTENDO_SWITCH_JOYCON_RIGHT);
|
||||
if (leftPair.Key == 0 || rightPair.Key == 0)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return new SDL3JoyConPair(new SDL3JoyCon(leftPair.Key, leftPair.Value),
|
||||
new SDL3JoyCon(rightPair.Key, rightPair.Value));
|
||||
}
|
||||
}
|
||||
}
|
||||
405
src/Ryujinx.Input.SDL3/SDL3Keyboard.cs
Normal file
405
src/Ryujinx.Input.SDL3/SDL3Keyboard.cs
Normal file
@@ -0,0 +1,405 @@
|
||||
using Ryujinx.Common.Configuration.Hid;
|
||||
using Ryujinx.Common.Configuration.Hid.Keyboard;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Numerics;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Threading;
|
||||
using static SDL3.SDL;
|
||||
|
||||
using ConfigKey = Ryujinx.Common.Configuration.Hid.Key;
|
||||
|
||||
namespace Ryujinx.Input.SDL3
|
||||
{
|
||||
class SDL3Keyboard : IKeyboard
|
||||
{
|
||||
private readonly record struct ButtonMappingEntry(GamepadButtonInputId To, Key From)
|
||||
{
|
||||
public bool IsValid => To is not GamepadButtonInputId.Unbound && From is not Key.Unbound;
|
||||
}
|
||||
|
||||
private readonly Lock _userMappingLock = new();
|
||||
|
||||
#pragma warning disable IDE0052 // Remove unread private member
|
||||
private readonly SDL3KeyboardDriver _driver;
|
||||
#pragma warning restore IDE0052
|
||||
private StandardKeyboardInputConfig _configuration;
|
||||
private readonly List<ButtonMappingEntry> _buttonsUserMapping;
|
||||
|
||||
private static readonly SDL_Keycode[] _keysDriverMapping = new SDL_Keycode[(int)Key.Count]
|
||||
{
|
||||
// INVALID
|
||||
SDL_Keycode.SDLK_0,
|
||||
// Presented as modifiers, so invalid here.
|
||||
SDL_Keycode.SDLK_0,
|
||||
SDL_Keycode.SDLK_0,
|
||||
SDL_Keycode.SDLK_0,
|
||||
SDL_Keycode.SDLK_0,
|
||||
SDL_Keycode.SDLK_0,
|
||||
SDL_Keycode.SDLK_0,
|
||||
SDL_Keycode.SDLK_0,
|
||||
SDL_Keycode.SDLK_0,
|
||||
SDL_Keycode.SDLK_0,
|
||||
|
||||
SDL_Keycode.SDLK_F1,
|
||||
SDL_Keycode.SDLK_F2,
|
||||
SDL_Keycode.SDLK_F3,
|
||||
SDL_Keycode.SDLK_F4,
|
||||
SDL_Keycode.SDLK_F5,
|
||||
SDL_Keycode.SDLK_F6,
|
||||
SDL_Keycode.SDLK_F7,
|
||||
SDL_Keycode.SDLK_F8,
|
||||
SDL_Keycode.SDLK_F9,
|
||||
SDL_Keycode.SDLK_F10,
|
||||
SDL_Keycode.SDLK_F11,
|
||||
SDL_Keycode.SDLK_F12,
|
||||
SDL_Keycode.SDLK_F13,
|
||||
SDL_Keycode.SDLK_F14,
|
||||
SDL_Keycode.SDLK_F15,
|
||||
SDL_Keycode.SDLK_F16,
|
||||
SDL_Keycode.SDLK_F17,
|
||||
SDL_Keycode.SDLK_F18,
|
||||
SDL_Keycode.SDLK_F19,
|
||||
SDL_Keycode.SDLK_F20,
|
||||
SDL_Keycode.SDLK_F21,
|
||||
SDL_Keycode.SDLK_F22,
|
||||
SDL_Keycode.SDLK_F23,
|
||||
SDL_Keycode.SDLK_F24,
|
||||
|
||||
SDL_Keycode.SDLK_0,
|
||||
SDL_Keycode.SDLK_0,
|
||||
SDL_Keycode.SDLK_0,
|
||||
SDL_Keycode.SDLK_0,
|
||||
SDL_Keycode.SDLK_0,
|
||||
SDL_Keycode.SDLK_0,
|
||||
SDL_Keycode.SDLK_0,
|
||||
SDL_Keycode.SDLK_0,
|
||||
SDL_Keycode.SDLK_0,
|
||||
SDL_Keycode.SDLK_0,
|
||||
SDL_Keycode.SDLK_0,
|
||||
|
||||
SDL_Keycode.SDLK_UP,
|
||||
SDL_Keycode.SDLK_DOWN,
|
||||
SDL_Keycode.SDLK_LEFT,
|
||||
SDL_Keycode.SDLK_RIGHT,
|
||||
SDL_Keycode.SDLK_RETURN,
|
||||
SDL_Keycode.SDLK_ESCAPE,
|
||||
SDL_Keycode.SDLK_SPACE,
|
||||
SDL_Keycode.SDLK_TAB,
|
||||
SDL_Keycode.SDLK_BACKSPACE,
|
||||
SDL_Keycode.SDLK_INSERT,
|
||||
SDL_Keycode.SDLK_DELETE,
|
||||
SDL_Keycode.SDLK_PAGEUP,
|
||||
SDL_Keycode.SDLK_PAGEDOWN,
|
||||
SDL_Keycode.SDLK_HOME,
|
||||
SDL_Keycode.SDLK_END,
|
||||
SDL_Keycode.SDLK_CAPSLOCK,
|
||||
SDL_Keycode.SDLK_SCROLLLOCK,
|
||||
SDL_Keycode.SDLK_PRINTSCREEN,
|
||||
SDL_Keycode.SDLK_PAUSE,
|
||||
SDL_Keycode.SDLK_NUMLOCKCLEAR,
|
||||
SDL_Keycode.SDLK_CLEAR,
|
||||
SDL_Keycode.SDLK_KP_0,
|
||||
SDL_Keycode.SDLK_KP_1,
|
||||
SDL_Keycode.SDLK_KP_2,
|
||||
SDL_Keycode.SDLK_KP_3,
|
||||
SDL_Keycode.SDLK_KP_4,
|
||||
SDL_Keycode.SDLK_KP_5,
|
||||
SDL_Keycode.SDLK_KP_6,
|
||||
SDL_Keycode.SDLK_KP_7,
|
||||
SDL_Keycode.SDLK_KP_8,
|
||||
SDL_Keycode.SDLK_KP_9,
|
||||
SDL_Keycode.SDLK_KP_DIVIDE,
|
||||
SDL_Keycode.SDLK_KP_MULTIPLY,
|
||||
SDL_Keycode.SDLK_KP_MINUS,
|
||||
SDL_Keycode.SDLK_KP_PLUS,
|
||||
SDL_Keycode.SDLK_KP_DECIMAL,
|
||||
SDL_Keycode.SDLK_KP_ENTER,
|
||||
SDL_Keycode.SDLK_A,
|
||||
SDL_Keycode.SDLK_B,
|
||||
SDL_Keycode.SDLK_C,
|
||||
SDL_Keycode.SDLK_D,
|
||||
SDL_Keycode.SDLK_E,
|
||||
SDL_Keycode.SDLK_F,
|
||||
SDL_Keycode.SDLK_G,
|
||||
SDL_Keycode.SDLK_H,
|
||||
SDL_Keycode.SDLK_I,
|
||||
SDL_Keycode.SDLK_J,
|
||||
SDL_Keycode.SDLK_K,
|
||||
SDL_Keycode.SDLK_L,
|
||||
SDL_Keycode.SDLK_M,
|
||||
SDL_Keycode.SDLK_N,
|
||||
SDL_Keycode.SDLK_O,
|
||||
SDL_Keycode.SDLK_P,
|
||||
SDL_Keycode.SDLK_Q,
|
||||
SDL_Keycode.SDLK_R,
|
||||
SDL_Keycode.SDLK_S,
|
||||
SDL_Keycode.SDLK_T,
|
||||
SDL_Keycode.SDLK_U,
|
||||
SDL_Keycode.SDLK_V,
|
||||
SDL_Keycode.SDLK_W,
|
||||
SDL_Keycode.SDLK_X,
|
||||
SDL_Keycode.SDLK_Y,
|
||||
SDL_Keycode.SDLK_Z,
|
||||
SDL_Keycode.SDLK_0,
|
||||
SDL_Keycode.SDLK_1,
|
||||
SDL_Keycode.SDLK_2,
|
||||
SDL_Keycode.SDLK_3,
|
||||
SDL_Keycode.SDLK_4,
|
||||
SDL_Keycode.SDLK_5,
|
||||
SDL_Keycode.SDLK_6,
|
||||
SDL_Keycode.SDLK_7,
|
||||
SDL_Keycode.SDLK_8,
|
||||
SDL_Keycode.SDLK_9,
|
||||
SDL_Keycode.SDLK_GRAVE,
|
||||
SDL_Keycode.SDLK_GRAVE,
|
||||
SDL_Keycode.SDLK_MINUS,
|
||||
SDL_Keycode.SDLK_PLUS,
|
||||
SDL_Keycode.SDLK_LEFTBRACKET,
|
||||
SDL_Keycode.SDLK_RIGHTBRACKET,
|
||||
SDL_Keycode.SDLK_SEMICOLON,
|
||||
SDL_Keycode.SDLK_APOSTROPHE,
|
||||
SDL_Keycode.SDLK_COMMA,
|
||||
SDL_Keycode.SDLK_PERIOD,
|
||||
SDL_Keycode.SDLK_SLASH,
|
||||
SDL_Keycode.SDLK_BACKSLASH,
|
||||
|
||||
// Invalids
|
||||
SDL_Keycode.SDLK_0,
|
||||
};
|
||||
|
||||
public SDL3Keyboard(SDL3KeyboardDriver driver, string id, string name)
|
||||
{
|
||||
_driver = driver;
|
||||
Id = id;
|
||||
Name = name;
|
||||
_buttonsUserMapping = new List<ButtonMappingEntry>();
|
||||
}
|
||||
|
||||
private bool HasConfiguration => _configuration != null;
|
||||
|
||||
public string Id { get; }
|
||||
|
||||
public string Name { get; }
|
||||
|
||||
public bool IsConnected => true;
|
||||
|
||||
public GamepadFeaturesFlag Features => GamepadFeaturesFlag.None;
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
// No operations
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static int ToSDL3Scancode(Key key)
|
||||
{
|
||||
if (key >= Key.Unknown && key <= Key.Menu)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
IntPtr modstate = (int)SDL_Keymod.SDL_KMOD_NONE;
|
||||
return (int)SDL_GetScancodeFromKey((uint)_keysDriverMapping[(int)key], modstate);
|
||||
}
|
||||
|
||||
private static SDL_Keymod GetKeyboardModifierMask(Key key)
|
||||
{
|
||||
return key switch
|
||||
{
|
||||
Key.ShiftLeft => SDL_Keymod.SDL_KMOD_LSHIFT,
|
||||
Key.ShiftRight => SDL_Keymod.SDL_KMOD_RSHIFT,
|
||||
Key.ControlLeft => SDL_Keymod.SDL_KMOD_LCTRL,
|
||||
Key.ControlRight => SDL_Keymod.SDL_KMOD_RCTRL,
|
||||
Key.AltLeft => SDL_Keymod.SDL_KMOD_LALT,
|
||||
Key.AltRight => SDL_Keymod.SDL_KMOD_RALT,
|
||||
Key.WinLeft => SDL_Keymod.SDL_KMOD_LGUI,
|
||||
Key.WinRight => SDL_Keymod.SDL_KMOD_RGUI,
|
||||
// NOTE: Menu key isn't supported by SDL3.
|
||||
_ => SDL_Keymod.SDL_KMOD_NONE,
|
||||
};
|
||||
}
|
||||
|
||||
public KeyboardStateSnapshot GetKeyboardStateSnapshot()
|
||||
{
|
||||
Span<SDLBool> rawKeyboardState;
|
||||
SDL_Keymod rawKeyboardModifierState = SDL_GetModState();
|
||||
|
||||
unsafe
|
||||
{
|
||||
rawKeyboardState = SDL_GetKeyboardState(out int numKeys);
|
||||
}
|
||||
|
||||
bool[] keysState = new bool[(int)Key.Count];
|
||||
|
||||
for (Key key = 0; key < Key.Count; key++)
|
||||
{
|
||||
int index = ToSDL3Scancode(key);
|
||||
if (index == -1)
|
||||
{
|
||||
SDL_Keymod modifierMask = GetKeyboardModifierMask(key);
|
||||
|
||||
if (modifierMask == SDL_Keymod.SDL_KMOD_NONE)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
keysState[(int)key] = (rawKeyboardModifierState & modifierMask) == modifierMask;
|
||||
}
|
||||
else
|
||||
{
|
||||
keysState[(int)key] = rawKeyboardState[index];
|
||||
}
|
||||
}
|
||||
|
||||
return new KeyboardStateSnapshot(keysState);
|
||||
}
|
||||
|
||||
private static float ConvertRawStickValue(short value)
|
||||
{
|
||||
const float ConvertRate = 1.0f / (short.MaxValue + 0.5f);
|
||||
|
||||
return value * ConvertRate;
|
||||
}
|
||||
|
||||
private static (short, short) GetStickValues(ref KeyboardStateSnapshot snapshot, JoyconConfigKeyboardStick<ConfigKey> stickConfig)
|
||||
{
|
||||
short stickX = 0;
|
||||
short stickY = 0;
|
||||
|
||||
if (snapshot.IsPressed((Key)stickConfig.StickUp))
|
||||
{
|
||||
stickY += 1;
|
||||
}
|
||||
|
||||
if (snapshot.IsPressed((Key)stickConfig.StickDown))
|
||||
{
|
||||
stickY -= 1;
|
||||
}
|
||||
|
||||
if (snapshot.IsPressed((Key)stickConfig.StickRight))
|
||||
{
|
||||
stickX += 1;
|
||||
}
|
||||
|
||||
if (snapshot.IsPressed((Key)stickConfig.StickLeft))
|
||||
{
|
||||
stickX -= 1;
|
||||
}
|
||||
|
||||
Vector2 stick = Vector2.Normalize(new Vector2(stickX, stickY));
|
||||
|
||||
return ((short)(stick.X * short.MaxValue), (short)(stick.Y * short.MaxValue));
|
||||
}
|
||||
|
||||
public GamepadStateSnapshot GetMappedStateSnapshot()
|
||||
{
|
||||
KeyboardStateSnapshot rawState = GetKeyboardStateSnapshot();
|
||||
GamepadStateSnapshot result = default;
|
||||
|
||||
lock (_userMappingLock)
|
||||
{
|
||||
if (!HasConfiguration)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
foreach (ButtonMappingEntry entry in _buttonsUserMapping)
|
||||
{
|
||||
if (entry.From == Key.Unknown || entry.From == Key.Unbound || entry.To == GamepadButtonInputId.Unbound)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Do not touch state of button already pressed
|
||||
if (!result.IsPressed(entry.To))
|
||||
{
|
||||
result.SetPressed(entry.To, rawState.IsPressed(entry.From));
|
||||
}
|
||||
}
|
||||
|
||||
(short leftStickX, short leftStickY) = GetStickValues(ref rawState, _configuration.LeftJoyconStick);
|
||||
(short rightStickX, short rightStickY) = GetStickValues(ref rawState, _configuration.RightJoyconStick);
|
||||
|
||||
result.SetStick(StickInputId.Left, ConvertRawStickValue(leftStickX), ConvertRawStickValue(leftStickY));
|
||||
result.SetStick(StickInputId.Right, ConvertRawStickValue(rightStickX), ConvertRawStickValue(rightStickY));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public GamepadStateSnapshot GetStateSnapshot()
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public (float, float) GetStick(StickInputId inputId)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public bool IsPressed(GamepadButtonInputId inputId)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public bool IsPressed(Key key)
|
||||
{
|
||||
// We only implement GetKeyboardStateSnapshot.
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public void SetConfiguration(InputConfig configuration)
|
||||
{
|
||||
lock (_userMappingLock)
|
||||
{
|
||||
_configuration = (StandardKeyboardInputConfig)configuration;
|
||||
|
||||
// First clear the buttons mapping
|
||||
_buttonsUserMapping.Clear();
|
||||
|
||||
// Then configure left joycon
|
||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.LeftStick, (Key)_configuration.LeftJoyconStick.StickButton));
|
||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.DpadUp, (Key)_configuration.LeftJoycon.DpadUp));
|
||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.DpadDown, (Key)_configuration.LeftJoycon.DpadDown));
|
||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.DpadLeft, (Key)_configuration.LeftJoycon.DpadLeft));
|
||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.DpadRight, (Key)_configuration.LeftJoycon.DpadRight));
|
||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.Minus, (Key)_configuration.LeftJoycon.ButtonMinus));
|
||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.LeftShoulder, (Key)_configuration.LeftJoycon.ButtonL));
|
||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.LeftTrigger, (Key)_configuration.LeftJoycon.ButtonZl));
|
||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.SingleRightTrigger0, (Key)_configuration.LeftJoycon.ButtonSr));
|
||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.SingleLeftTrigger0, (Key)_configuration.LeftJoycon.ButtonSl));
|
||||
|
||||
// Finally configure right joycon
|
||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.RightStick, (Key)_configuration.RightJoyconStick.StickButton));
|
||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.A, (Key)_configuration.RightJoycon.ButtonA));
|
||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.B, (Key)_configuration.RightJoycon.ButtonB));
|
||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.X, (Key)_configuration.RightJoycon.ButtonX));
|
||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.Y, (Key)_configuration.RightJoycon.ButtonY));
|
||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.Plus, (Key)_configuration.RightJoycon.ButtonPlus));
|
||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.RightShoulder, (Key)_configuration.RightJoycon.ButtonR));
|
||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.RightTrigger, (Key)_configuration.RightJoycon.ButtonZr));
|
||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.SingleRightTrigger1, (Key)_configuration.RightJoycon.ButtonSr));
|
||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.SingleLeftTrigger1, (Key)_configuration.RightJoycon.ButtonSl));
|
||||
}
|
||||
}
|
||||
|
||||
public void SetTriggerThreshold(float triggerThreshold)
|
||||
{
|
||||
// No operations
|
||||
}
|
||||
|
||||
public void Rumble(float lowFrequency, float highFrequency, uint durationMs)
|
||||
{
|
||||
// No operations
|
||||
}
|
||||
|
||||
public Vector3 GetMotionData(MotionInputId inputId)
|
||||
{
|
||||
// No operations
|
||||
|
||||
return Vector3.Zero;
|
||||
}
|
||||
}
|
||||
}
|
||||
55
src/Ryujinx.Input.SDL3/SDL3KeyboardDriver.cs
Normal file
55
src/Ryujinx.Input.SDL3/SDL3KeyboardDriver.cs
Normal file
@@ -0,0 +1,55 @@
|
||||
using Ryujinx.SDL3.Common;
|
||||
using System;
|
||||
|
||||
namespace Ryujinx.Input.SDL3
|
||||
{
|
||||
public class SDL3KeyboardDriver : IGamepadDriver
|
||||
{
|
||||
public SDL3KeyboardDriver()
|
||||
{
|
||||
SDL3Driver.Instance.Initialize();
|
||||
}
|
||||
|
||||
public string DriverName => "SDL3";
|
||||
|
||||
private static readonly string[] _keyboardIdentifers = new string[1] { "0" };
|
||||
|
||||
public ReadOnlySpan<string> GamepadsIds => _keyboardIdentifers;
|
||||
|
||||
public event Action<string> OnGamepadConnected
|
||||
{
|
||||
add { }
|
||||
remove { }
|
||||
}
|
||||
|
||||
public event Action<string> OnGamepadDisconnected
|
||||
{
|
||||
add { }
|
||||
remove { }
|
||||
}
|
||||
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
SDL3Driver.Instance.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
GC.SuppressFinalize(this);
|
||||
Dispose(true);
|
||||
}
|
||||
|
||||
public IGamepad GetGamepad(string id)
|
||||
{
|
||||
if (!_keyboardIdentifers[0].Equals(id))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return new SDL3Keyboard(this, _keyboardIdentifers[0], "All keyboards");
|
||||
}
|
||||
}
|
||||
}
|
||||
90
src/Ryujinx.Input.SDL3/SDL3Mouse.cs
Normal file
90
src/Ryujinx.Input.SDL3/SDL3Mouse.cs
Normal file
@@ -0,0 +1,90 @@
|
||||
using Ryujinx.Common.Configuration.Hid;
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using System.Numerics;
|
||||
|
||||
namespace Ryujinx.Input.SDL3
|
||||
{
|
||||
public class SDL3Mouse : IMouse
|
||||
{
|
||||
private SDL3MouseDriver _driver;
|
||||
|
||||
public GamepadFeaturesFlag Features => throw new NotImplementedException();
|
||||
|
||||
public string Id => "0";
|
||||
|
||||
public string Name => "SDL3Mouse";
|
||||
|
||||
public bool IsConnected => true;
|
||||
|
||||
public bool[] Buttons => _driver.PressedButtons;
|
||||
|
||||
Size IMouse.ClientSize => _driver.GetClientSize();
|
||||
|
||||
public SDL3Mouse(SDL3MouseDriver driver)
|
||||
{
|
||||
_driver = driver;
|
||||
}
|
||||
|
||||
public Vector2 GetPosition()
|
||||
{
|
||||
return _driver.CurrentPosition;
|
||||
}
|
||||
|
||||
public Vector2 GetScroll()
|
||||
{
|
||||
return _driver.Scroll;
|
||||
}
|
||||
|
||||
public GamepadStateSnapshot GetMappedStateSnapshot()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Vector3 GetMotionData(MotionInputId inputId)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public GamepadStateSnapshot GetStateSnapshot()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public (float, float) GetStick(StickInputId inputId)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public bool IsButtonPressed(MouseButton button)
|
||||
{
|
||||
return _driver.IsButtonPressed(button);
|
||||
}
|
||||
|
||||
public bool IsPressed(GamepadButtonInputId inputId)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public void Rumble(float lowFrequency, float highFrequency, uint durationMs)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public void SetConfiguration(InputConfig configuration)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public void SetTriggerThreshold(float triggerThreshold)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
GC.SuppressFinalize(this);
|
||||
_driver = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
179
src/Ryujinx.Input.SDL3/SDL3MouseDriver.cs
Normal file
179
src/Ryujinx.Input.SDL3/SDL3MouseDriver.cs
Normal file
@@ -0,0 +1,179 @@
|
||||
using Ryujinx.Common.Configuration;
|
||||
using Ryujinx.Common.Logging;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Drawing;
|
||||
using System.Numerics;
|
||||
using System.Runtime.CompilerServices;
|
||||
using static SDL3.SDL;
|
||||
|
||||
namespace Ryujinx.Input.SDL3
|
||||
{
|
||||
public class SDL3MouseDriver : IGamepadDriver
|
||||
{
|
||||
private const int CursorHideIdleTime = 5; // seconds
|
||||
|
||||
private bool _isDisposed;
|
||||
private readonly HideCursorMode _hideCursorMode;
|
||||
private bool _isHidden;
|
||||
private long _lastCursorMoveTime;
|
||||
|
||||
public bool[] PressedButtons { get; }
|
||||
|
||||
public Vector2 CurrentPosition { get; private set; }
|
||||
public Vector2 Scroll { get; private set; }
|
||||
public Size ClientSize;
|
||||
|
||||
public SDL3MouseDriver(HideCursorMode hideCursorMode)
|
||||
{
|
||||
PressedButtons = new bool[(int)MouseButton.Count];
|
||||
_hideCursorMode = hideCursorMode;
|
||||
|
||||
if (_hideCursorMode == HideCursorMode.Always)
|
||||
{
|
||||
if (!SDL_HideCursor())
|
||||
{
|
||||
Logger.Error?.PrintMsg(LogClass.Application, "Failed to disable the cursor.");
|
||||
}
|
||||
|
||||
_isHidden = true;
|
||||
}
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static MouseButton DriverButtonToMouseButton(uint rawButton)
|
||||
{
|
||||
Debug.Assert(rawButton is > 0 and <= (int)MouseButton.Count);
|
||||
|
||||
return (MouseButton)(rawButton - 1);
|
||||
}
|
||||
|
||||
public void UpdatePosition()
|
||||
{
|
||||
_ = SDL_GetMouseState(out float posX, out float posY);
|
||||
Vector2 position = new(posX, posY);
|
||||
|
||||
if (CurrentPosition != position)
|
||||
{
|
||||
CurrentPosition = position;
|
||||
_lastCursorMoveTime = Stopwatch.GetTimestamp();
|
||||
}
|
||||
|
||||
CheckIdle();
|
||||
}
|
||||
|
||||
private void CheckIdle()
|
||||
{
|
||||
if (_hideCursorMode != HideCursorMode.OnIdle)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
long cursorMoveDelta = Stopwatch.GetTimestamp() - _lastCursorMoveTime;
|
||||
|
||||
if (cursorMoveDelta >= CursorHideIdleTime * Stopwatch.Frequency)
|
||||
{
|
||||
if (!_isHidden)
|
||||
{
|
||||
if (!SDL_HideCursor())
|
||||
{
|
||||
Logger.Error?.PrintMsg(LogClass.Application, "Failed to disable the cursor.");
|
||||
}
|
||||
|
||||
_isHidden = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_isHidden)
|
||||
{
|
||||
if (!SDL_HideCursor())
|
||||
{
|
||||
Logger.Error?.PrintMsg(LogClass.Application, "Failed to enable the cursor.");
|
||||
}
|
||||
|
||||
_isHidden = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Update(SDL_Event evnt)
|
||||
{
|
||||
var type = (SDL_EventType)evnt.type;
|
||||
switch (type)
|
||||
{
|
||||
case SDL_EventType.SDL_EVENT_MOUSE_BUTTON_DOWN:
|
||||
case SDL_EventType.SDL_EVENT_MOUSE_BUTTON_UP:
|
||||
uint rawButton = evnt.button.button;
|
||||
|
||||
if (rawButton > 0 && rawButton <= (int)MouseButton.Count)
|
||||
{
|
||||
PressedButtons[(int)DriverButtonToMouseButton(rawButton)] = type == SDL_EventType.SDL_EVENT_MOUSE_BUTTON_DOWN;
|
||||
|
||||
CurrentPosition = new Vector2(evnt.button.x, evnt.button.y);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
// NOTE: On Linux using Wayland mouse motion events won't be received at all.
|
||||
case SDL_EventType.SDL_EVENT_MOUSE_MOTION:
|
||||
CurrentPosition = new Vector2(evnt.motion.x, evnt.motion.y);
|
||||
_lastCursorMoveTime = Stopwatch.GetTimestamp();
|
||||
|
||||
break;
|
||||
|
||||
case SDL_EventType.SDL_EVENT_MOUSE_WHEEL:
|
||||
Scroll = new Vector2(evnt.wheel.x, evnt.wheel.y);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public void SetClientSize(int width, int height)
|
||||
{
|
||||
ClientSize = new Size(width, height);
|
||||
}
|
||||
|
||||
public bool IsButtonPressed(MouseButton button)
|
||||
{
|
||||
return PressedButtons[(int)button];
|
||||
}
|
||||
|
||||
public Size GetClientSize()
|
||||
{
|
||||
return ClientSize;
|
||||
}
|
||||
|
||||
public string DriverName => "SDL3";
|
||||
|
||||
public event Action<string> OnGamepadConnected
|
||||
{
|
||||
add { }
|
||||
remove { }
|
||||
}
|
||||
|
||||
public event Action<string> OnGamepadDisconnected
|
||||
{
|
||||
add { }
|
||||
remove { }
|
||||
}
|
||||
|
||||
public ReadOnlySpan<string> GamepadsIds => new[] { "0" };
|
||||
|
||||
public IGamepad GetGamepad(string id)
|
||||
{
|
||||
return new SDL3Mouse(this);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (_isDisposed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
GC.SuppressFinalize(this);
|
||||
_isDisposed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -266,6 +266,7 @@ namespace Ryujinx.Input.HLE
|
||||
if (motionConfig.MotionBackend != MotionInputBackendType.CemuHook)
|
||||
{
|
||||
_leftMotionInput = new MotionInput();
|
||||
_rightMotionInput = new MotionInput();
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -298,7 +299,20 @@ namespace Ryujinx.Input.HLE
|
||||
|
||||
if (controllerConfig.ControllerType == ConfigControllerType.JoyconPair)
|
||||
{
|
||||
_rightMotionInput = _leftMotionInput;
|
||||
if (gamepad.Id== "JoyConPair")
|
||||
{
|
||||
Vector3 rightAccelerometer = gamepad.GetMotionData(MotionInputId.SecondAccelerometer);
|
||||
Vector3 rightGyroscope = gamepad.GetMotionData(MotionInputId.SecondGyroscope);
|
||||
|
||||
rightAccelerometer = new Vector3(rightAccelerometer.X, -rightAccelerometer.Z, rightAccelerometer.Y);
|
||||
rightGyroscope = new Vector3(rightGyroscope.X, -rightGyroscope.Z, rightGyroscope.Y);
|
||||
|
||||
_rightMotionInput.Update(rightAccelerometer, rightGyroscope, (ulong)PerformanceCounter.ElapsedNanoseconds / 1000, controllerConfig.Motion.Sensitivity, (float)controllerConfig.Motion.GyroDeadzone);
|
||||
}
|
||||
else
|
||||
{
|
||||
_rightMotionInput = _leftMotionInput;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -333,6 +347,7 @@ namespace Ryujinx.Input.HLE
|
||||
// Reset states
|
||||
State = default;
|
||||
_leftMotionInput = null;
|
||||
_rightMotionInput = null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -377,6 +392,11 @@ namespace Ryujinx.Input.HLE
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
public static JoystickPosition GetJoystickPosition(float x, float y, float deadzone, float range)
|
||||
{
|
||||
return ClampToCircle(ApplyDeadzone(x, y,deadzone), range);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static JoystickPosition ApplyDeadzone(float x, float y, float deadzone)
|
||||
|
||||
@@ -21,5 +21,17 @@ namespace Ryujinx.Input
|
||||
/// </summary>
|
||||
/// <remarks>Values are in degrees</remarks>
|
||||
Gyroscope,
|
||||
|
||||
/// <summary>
|
||||
/// Second accelerometer.
|
||||
/// </summary>
|
||||
/// <remarks>Values are in m/s^2</remarks>
|
||||
SecondAccelerometer,
|
||||
|
||||
/// <summary>
|
||||
/// Second gyroscope.
|
||||
/// </summary>
|
||||
/// <remarks>Values are in degrees</remarks>
|
||||
SecondGyroscope
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,14 +25,17 @@ namespace Ryujinx.SDL2.Common
|
||||
|
||||
public static Action<Action> MainThreadDispatcher { get; set; }
|
||||
|
||||
private const uint SdlInitFlags = SDL_INIT_EVENTS | SDL_INIT_GAMECONTROLLER | SDL_INIT_JOYSTICK | SDL_INIT_AUDIO | SDL_INIT_VIDEO;
|
||||
private const uint SdlInitFlags = SDL_INIT_EVENTS | SDL_INIT_GAMECONTROLLER | SDL_INIT_JOYSTICK |
|
||||
SDL_INIT_AUDIO | SDL_INIT_VIDEO;
|
||||
|
||||
private bool _isRunning;
|
||||
private uint _refereceCount;
|
||||
private Thread _worker;
|
||||
|
||||
private const uint SDL_JOYBATTERYUPDATED = 1543;
|
||||
public event Action<int, int> OnJoyStickConnected;
|
||||
public event Action<int> OnJoystickDisconnected;
|
||||
public event Action<int, SDL_JoystickPowerLevel> OnJoyBatteryUpdated;
|
||||
|
||||
private ConcurrentDictionary<uint, Action<SDL_Event>> _registeredWindowHandlers;
|
||||
|
||||
@@ -78,12 +81,14 @@ namespace Ryujinx.SDL2.Common
|
||||
// First ensure that we only enable joystick events (for connected/disconnected).
|
||||
if (SDL_GameControllerEventState(SDL_IGNORE) != SDL_IGNORE)
|
||||
{
|
||||
Logger.Error?.PrintMsg(LogClass.Application, "Couldn't change the state of game controller events.");
|
||||
Logger.Error?.PrintMsg(LogClass.Application,
|
||||
"Couldn't change the state of game controller events.");
|
||||
}
|
||||
|
||||
if (SDL_JoystickEventState(SDL_ENABLE) < 0)
|
||||
{
|
||||
Logger.Error?.PrintMsg(LogClass.Application, $"Failed to enable joystick event polling: {SDL_GetError()}");
|
||||
Logger.Error?.PrintMsg(LogClass.Application,
|
||||
$"Failed to enable joystick event polling: {SDL_GetError()}");
|
||||
}
|
||||
|
||||
// Disable all joysticks information, we don't need them no need to flood the event queue for that.
|
||||
@@ -143,7 +148,12 @@ namespace Ryujinx.SDL2.Common
|
||||
|
||||
OnJoystickDisconnected?.Invoke(evnt.cbutton.which);
|
||||
}
|
||||
else if (evnt.type is SDL_EventType.SDL_WINDOWEVENT or SDL_EventType.SDL_MOUSEBUTTONDOWN or SDL_EventType.SDL_MOUSEBUTTONUP)
|
||||
else if ((uint)evnt.type == SDL_JOYBATTERYUPDATED)
|
||||
{
|
||||
OnJoyBatteryUpdated?.Invoke(evnt.cbutton.which, (SDL_JoystickPowerLevel)evnt.user.code);
|
||||
}
|
||||
else if (evnt.type is SDL_EventType.SDL_WINDOWEVENT or SDL_EventType.SDL_MOUSEBUTTONDOWN
|
||||
or SDL_EventType.SDL_MOUSEBUTTONUP)
|
||||
{
|
||||
if (_registeredWindowHandlers.TryGetValue(evnt.window.windowID, out Action<SDL_Event> handler))
|
||||
{
|
||||
|
||||
31
src/Ryujinx.SDL3-CS/Ryujinx.SDL3-CS.csproj
Normal file
31
src/Ryujinx.SDL3-CS/Ryujinx.SDL3-CS.csproj
Normal file
@@ -0,0 +1,31 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
<RootNamespace>Ryujinx.SDL3_CS</RootNamespace>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup Condition="'$(OS)' == 'Windows_NT'">
|
||||
<None Include="runtimes\win-x64\native\SDL3.dll">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
<Link>SDL3.dll</Link>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
|
||||
<!-- <ItemGroup Condition="'$(OS)' == 'Linux'">-->
|
||||
<!-- <None Include="runtimes\linux-x64\native\SDL3.dll">-->
|
||||
<!-- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>-->
|
||||
<!-- <DestinationFolder>$(ProjectDir)</DestinationFolder>-->
|
||||
<!-- </None>-->
|
||||
<!-- </ItemGroup>-->
|
||||
|
||||
<!-- <ItemGroup Condition="'$(OS)' == 'Darwin'">-->
|
||||
<!-- <None Include="runtimes\osx-x64\native\SDL3.dll">-->
|
||||
<!-- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>-->
|
||||
<!-- <DestinationFolder>$(ProjectDir)</DestinationFolder>-->
|
||||
<!-- </None>-->
|
||||
<!-- </ItemGroup>-->
|
||||
|
||||
</Project>
|
||||
8079
src/Ryujinx.SDL3-CS/SDL3.cs
Normal file
8079
src/Ryujinx.SDL3-CS/SDL3.cs
Normal file
File diff suppressed because it is too large
Load Diff
BIN
src/Ryujinx.SDL3-CS/runtimes/win-x64/native/SDL3.dll
Normal file
BIN
src/Ryujinx.SDL3-CS/runtimes/win-x64/native/SDL3.dll
Normal file
Binary file not shown.
12
src/Ryujinx.SDL3.Common/Ryujinx.SDL3.Common.csproj
Normal file
12
src/Ryujinx.SDL3.Common/Ryujinx.SDL3.Common.csproj
Normal file
@@ -0,0 +1,12 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<DefaultItemExcludes>$(DefaultItemExcludes);._*</DefaultItemExcludes>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Ryujinx.Common\Ryujinx.Common.csproj" />
|
||||
<ProjectReference Include="..\Ryujinx.SDL3-CS\Ryujinx.SDL3-CS.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
210
src/Ryujinx.SDL3.Common/SDL3Driver.cs
Normal file
210
src/Ryujinx.SDL3.Common/SDL3Driver.cs
Normal file
@@ -0,0 +1,210 @@
|
||||
using Ryujinx.Common.Configuration;
|
||||
using Ryujinx.Common.Logging;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using static SDL3.SDL;
|
||||
|
||||
|
||||
namespace Ryujinx.SDL3.Common
|
||||
{
|
||||
public class SDL3Driver : IDisposable
|
||||
{
|
||||
private static SDL3Driver _instance;
|
||||
|
||||
public static SDL3Driver Instance
|
||||
{
|
||||
get
|
||||
{
|
||||
_instance ??= new SDL3Driver();
|
||||
|
||||
return _instance;
|
||||
}
|
||||
}
|
||||
|
||||
public static Action<Action> MainThreadDispatcher { get; set; }
|
||||
|
||||
private const SDL_InitFlags SdlInitFlags = SDL_InitFlags.SDL_INIT_GAMEPAD | SDL_InitFlags.SDL_INIT_AUDIO |
|
||||
SDL_InitFlags.SDL_INIT_VIDEO;
|
||||
|
||||
private bool _isRunning;
|
||||
private uint _refereceCount;
|
||||
private Thread _worker;
|
||||
|
||||
public event Action<uint> OnJoyStickConnected;
|
||||
public event Action<uint> OnJoystickDisconnected;
|
||||
public event Action<uint, SDL_JoyBatteryEvent> OnJoyBatteryUpdated;
|
||||
|
||||
private ConcurrentDictionary<uint, Action<SDL_Event>> _registeredWindowHandlers;
|
||||
|
||||
private readonly Lock _lock = new();
|
||||
|
||||
private SDL3Driver() { }
|
||||
|
||||
public void Initialize()
|
||||
{
|
||||
lock (_lock)
|
||||
{
|
||||
_refereceCount++;
|
||||
|
||||
if (_isRunning)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
SDL_SetHint(SDL_HINT_APP_NAME, "Ryujinx");
|
||||
// SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_PS4_RUMBLE, "1");
|
||||
// SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_PS5_RUMBLE, "1");
|
||||
SDL_SetHint(SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS, "1");
|
||||
SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_SWITCH_HOME_LED, "0");
|
||||
SDL_SetHint(SDL_HINT_VIDEO_ALLOW_SCREENSAVER, "1");
|
||||
//
|
||||
//
|
||||
// // NOTE: As of SDL2 2.24.0, joycons are combined by default but the motion source only come from one of them.
|
||||
// // We disable this behavior for now.
|
||||
SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_COMBINE_JOY_CONS, "0");
|
||||
|
||||
if (!SDL_Init(SdlInitFlags))
|
||||
{
|
||||
string errorMessage = $"SDL3 initialization failed with error \"{SDL_GetError()}\"";
|
||||
|
||||
Logger.Error?.Print(LogClass.Application, errorMessage);
|
||||
|
||||
throw new Exception(errorMessage);
|
||||
}
|
||||
|
||||
// First ensure that we only enable joystick events (for connected/disconnected).
|
||||
if (!SDL_GamepadEventsEnabled())
|
||||
{
|
||||
Logger.Error?.PrintMsg(LogClass.Application,
|
||||
"Couldn't change the state of game controller events.");
|
||||
}
|
||||
|
||||
if (!SDL_JoystickEventsEnabled())
|
||||
{
|
||||
Logger.Error?.PrintMsg(LogClass.Application,
|
||||
$"Failed to enable joystick event polling: {SDL_GetError()}");
|
||||
}
|
||||
|
||||
// Disable all joysticks information, we don't need them no need to flood the event queue for that.
|
||||
SDL_SetEventEnabled((uint)SDL_EventType.SDL_EVENT_JOYSTICK_AXIS_MOTION, false);
|
||||
SDL_SetEventEnabled((uint)SDL_EventType.SDL_EVENT_JOYSTICK_BALL_MOTION, false);
|
||||
SDL_SetEventEnabled((uint)SDL_EventType.SDL_EVENT_JOYSTICK_HAT_MOTION, false);
|
||||
SDL_SetEventEnabled((uint)SDL_EventType.SDL_EVENT_JOYSTICK_BUTTON_DOWN, false);
|
||||
SDL_SetEventEnabled((uint)SDL_EventType.SDL_EVENT_JOYSTICK_BUTTON_UP, false);
|
||||
|
||||
SDL_SetEventEnabled((uint)SDL_EventType.SDL_EVENT_GAMEPAD_SENSOR_UPDATE, false);
|
||||
|
||||
string gamepadDbPath = Path.Combine(AppDataManager.BaseDirPath, "SDL_GameControllerDB.txt");
|
||||
|
||||
if (File.Exists(gamepadDbPath))
|
||||
{
|
||||
SDL_AddGamepadMappingsFromFile(gamepadDbPath);
|
||||
}
|
||||
|
||||
_registeredWindowHandlers = new ConcurrentDictionary<uint, Action<SDL_Event>>();
|
||||
_worker = new Thread(EventWorker);
|
||||
_isRunning = true;
|
||||
_worker.Start();
|
||||
}
|
||||
}
|
||||
|
||||
public bool RegisterWindow(uint windowId, Action<SDL_Event> windowEventHandler)
|
||||
{
|
||||
return _registeredWindowHandlers.TryAdd(windowId, windowEventHandler);
|
||||
}
|
||||
|
||||
public void UnregisterWindow(uint windowId)
|
||||
{
|
||||
_registeredWindowHandlers.Remove(windowId, out _);
|
||||
}
|
||||
|
||||
private void HandleSDLEvent(ref SDL_Event evnt)
|
||||
{
|
||||
if (evnt.type == (uint)SDL_EventType.SDL_EVENT_GAMEPAD_ADDED)
|
||||
{
|
||||
var instanceId = evnt.jdevice.which;
|
||||
|
||||
Logger.Debug?.Print(LogClass.Application, $"Added joystick instance id {instanceId}");
|
||||
|
||||
OnJoyStickConnected?.Invoke(instanceId);
|
||||
}
|
||||
else if (evnt.type == (uint)SDL_EventType.SDL_EVENT_GAMEPAD_REMOVED)
|
||||
{
|
||||
var instanceId = evnt.jdevice.which;
|
||||
|
||||
Logger.Debug?.Print(LogClass.Application, $"Removed joystick instance id {instanceId}");
|
||||
|
||||
OnJoystickDisconnected?.Invoke(instanceId);
|
||||
}
|
||||
else if (evnt.type == (uint)SDL_EventType.SDL_EVENT_JOYSTICK_BATTERY_UPDATED)
|
||||
{
|
||||
OnJoyBatteryUpdated?.Invoke(evnt.jbattery.which, evnt.jbattery);
|
||||
}
|
||||
else if (evnt.type is >= (uint)SDL_EventType.SDL_EVENT_WINDOW_FIRST and <= (uint)SDL_EventType.SDL_EVENT_WINDOW_LAST
|
||||
or (uint)SDL_EventType.SDL_EVENT_MOUSE_BUTTON_DOWN
|
||||
or (uint)SDL_EventType.SDL_EVENT_MOUSE_BUTTON_UP)
|
||||
{
|
||||
if (_registeredWindowHandlers.TryGetValue(evnt.window.windowID, out Action<SDL_Event> handler))
|
||||
{
|
||||
handler(evnt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void EventWorker()
|
||||
{
|
||||
const int WaitTimeMs = 10;
|
||||
|
||||
using ManualResetEventSlim waitHandle = new(false);
|
||||
while (_isRunning)
|
||||
{
|
||||
MainThreadDispatcher?.Invoke(() =>
|
||||
{
|
||||
while (SDL_PollEvent(out SDL_Event evnt))
|
||||
{
|
||||
HandleSDLEvent(ref evnt);
|
||||
}
|
||||
});
|
||||
|
||||
waitHandle.Wait(WaitTimeMs);
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (!disposing)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
lock (_lock)
|
||||
{
|
||||
if (_isRunning)
|
||||
{
|
||||
_refereceCount--;
|
||||
|
||||
if (_refereceCount == 0)
|
||||
{
|
||||
_isRunning = false;
|
||||
|
||||
_worker?.Join();
|
||||
|
||||
SDL_Quit();
|
||||
|
||||
OnJoyStickConnected = null;
|
||||
OnJoystickDisconnected = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
GC.SuppressFinalize(this);
|
||||
Dispose(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user