Compare commits

...

91 Commits

Author SHA1 Message Date
KeatonTheBot
81eddcadc5 Merge branch 'fix/linux-file-picker' into 'master'
Linux: Fix file picker not launching from disabling core dumps

See merge request [ryubing/ryujinx!249](https://git.ryujinx.app/ryubing/ryujinx/-/merge_requests/249)
2026-02-19 11:02:29 -06:00
KeatonTheBot
224142b9c5 Linux: Fix file picker not launching from disabling core dumps
Core dumps are disabled by default on Linux, but this prevents access to the file picker due to security hardening. To work around this, core dumps are selectively enabled and disabled around the file picker tasks.
2026-02-19 11:02:24 -06:00
BowedCascade
d1205dc95d Fix backslash key not mappable in controller settings (ryubing/ryujinx!265)
See merge request ryubing/ryujinx!265
2026-02-18 18:13:15 -06:00
Awesomeangotti
6f95172bb6 Compatability Data Update (ryubing/ryujinx!264)
See merge request ryubing/ryujinx!264
2026-02-17 19:24:01 -06:00
Princess Piplup
8208d43d9e compatiblity/2026-02-17 (ryubing/ryujinx!263)
See merge request ryubing/ryujinx!263
2026-02-17 18:57:50 -06:00
shinyoyo
1260f93aaf Updated ‌Simplified Chinese‌ translation. (ryubing/ryujinx!260)
See merge request ryubing/ryujinx!260
2026-02-09 01:07:22 -06:00
LotP
1b3bf1473d Fix Dual Joy-Con driver and InputView (ryubing/ryujinx!259)
See merge request ryubing/ryujinx!259
2026-01-31 23:12:29 -06:00
LotP
081cdcab0c remap joy-cons (ryubing/ryujinx!258)
See merge request ryubing/ryujinx!258
2026-01-31 17:58:31 -06:00
Coxxs
922775664c audio: Fix crash due to invalid Splitter size (ryubing/ryujinx!257)
See merge request ryubing/ryujinx!257
2026-01-31 11:22:14 -06:00
sh0inx
478b66fd49 HLE: Stubbed IUserLocalCommuniationService SetProtocol (106) (ryubing/ryujinx!253)
See merge request ryubing/ryujinx!253
2026-01-30 20:48:41 -06:00
Coxxs
a16a072155 HLE: Implement 10106 and 10107 in IPrepoService (ryubing/ryujinx!254)
See merge request ryubing/ryujinx!254
2026-01-29 13:45:35 -06:00
Babib3l
a4a0fcd4da General translations updates + fixes (ryubing/ryujinx!248)
See merge request ryubing/ryujinx!248
2026-01-28 07:01:39 -06:00
GreemDev
cc5b60bbca fix AppleHardwareDeviceDriver.IsSupported (no fancy check is needed; it's on any macOS version 10.5 (Leopard) and above) 2026-01-28 00:05:02 -06:00
GreemDev
5ed94c365b add a stack trace for the catch branch of AppleHardwareDeviceDriver.IsSupported 2026-01-27 17:52:45 -06:00
GreemDev
fef93a453a [ci skip] replace all usages of IntPtr with nint 2026-01-27 17:41:46 -06:00
GreemDev
82074eb191 audio backend projects code cleanup 2026-01-27 17:34:51 -06:00
GreemDev
bd388cf4f9 Expose AudioToolkit in UI 2026-01-27 17:28:59 -06:00
Stossy11
d271abe19a [ci skip] Add macOS native Audio Backend (ryubing/ryujinx!252)
See merge request ryubing/ryujinx!252

THIS IS CURRENTLY NOT EXPOSED BY THE UI OR HANDLED BY THE EMULATOR. Expect a commit later to add it to configs, UI, etc.
2026-01-27 17:03:59 -06:00
Hack茶ん
c154f66f26 Update Korean translation (ryubing/ryujinx!251)
See merge request ryubing/ryujinx!251
2026-01-21 18:23:34 -06:00
GreemDev
f556e8b8fb add offline update server catch branch 2026-01-20 13:19:44 -06:00
Babib3l
99feaafbe6 French and Spanish Translations updates on RenderDoc (ryubing/ryujinx!246)
See merge request ryubing/ryujinx!246
2026-01-03 07:23:11 -06:00
GreemDev
fa55608587 RenderDoc API support (ryubing/ryujinx!242)
See merge request ryubing/ryujinx!242
2026-01-01 00:10:21 -06:00
LotP
4c64300576 fix new locale files data loading (ryubing/ryujinx!245)
See merge request ryubing/ryujinx!245
2025-12-31 20:21:35 -06:00
LotP
0a3db19b28 fix language switching 2 (ryubing/ryujinx!244)
See merge request ryubing/ryujinx!244
2025-12-31 10:30:35 -06:00
LotP
453b246faa fix (ryubing/ryujinx!243)
See merge request ryubing/ryujinx!243
2025-12-31 09:15:40 -06:00
LotP
45193dcc8d Fractured Locales Support (ryubing/ryujinx!238)
See merge request ryubing/ryujinx!238
2025-12-27 14:07:56 -06:00
GreemDev
9ebf444644 [ci skip] Code comment 2025-12-25 23:48:10 -06:00
GreemDev
f585b36263 Use new retry flag for uploading built artifacts in CI
(I'm tired of the GitLab randomly HTTP 500ing and causing the entire CI to fail)
2025-12-23 02:16:01 -06:00
GreemDev
a96f20dca5 Removed TypedStringEnumConverter; it exists in .NET now.
As per the remark XMLdoc on the type: Get rid of this converter if dotnet supports similar functionality out of the box.
2025-12-23 01:42:28 -06:00
GreemDev
1e1bcb4a5b storing commit string in github output causes weird CI failures
so let's just not bother, it didn't show anything more than the UI already did anyways
2025-12-23 00:02:02 -06:00
Coxxs
ca76bacd22 gdb: add monitor get mapping (ryubing/ryujinx!215)
See merge request ryubing/ryujinx!215
2025-12-21 22:34:20 -06:00
GreemDev
66f339d265 CI 2.0 (ryubing/ryujinx!237)
See merge request ryubing/ryujinx!237
2025-12-18 22:56:50 -06:00
GreemDev
6cdbdfd329 [ci skip] Pin GitLabCli to 1.4.1 in CI scripts so I can test v2.0 2025-12-18 03:27:43 -06:00
GreemDev
9f817d60d5 oops 2025-12-18 03:05:42 -06:00
GreemDev
5cffc95be6 Make all OSes build on Linux (7zip has a linux version) 2025-12-18 03:01:22 -06:00
LotP
2c0977f6b3 fix pre-action crash (ryubing/ryujinx!236)
See merge request ryubing/ryujinx!236
2025-12-12 14:28:54 -06:00
LotP
3a593b6084 Fix kaddressarbiter crash (ryubing/ryujinx!235)
See merge request ryubing/ryujinx!235
2025-12-06 20:16:43 -06:00
LotP
c3155fcadb Memory Changes 3.2 (ryubing/ryujinx!234)
See merge request ryubing/ryujinx!234
2025-12-06 17:19:19 -06:00
LotP
fd7554425a Update BiquadFilterEffectParameter2.cs (ryubing/ryujinx!233)
See merge request ryubing/ryujinx!233
2025-12-05 07:53:09 -06:00
Princess Piplup
52700f71dc Fix SaveCurrentScreenshot (ryubing/ryujinx!230)
See merge request ryubing/ryujinx!230
2025-12-04 17:35:17 -06:00
Alula
b018a44ff0 Disable coredumps by default on Linux + other minor fixes (ryubing/ryujinx!204)
See merge request ryubing/ryujinx!204
2025-12-04 17:32:26 -06:00
GreemDev
d522bfef62 fix: Force the key install helper to delete key files before copying (not sure why the overwrite boolean does nothing for File.Copy) 2025-12-02 21:23:06 -06:00
KeatonTheBot
39f55b2af3 cpu: Protect against stack overflow caused by deep recursion (ryubing/ryujinx!111)
See merge request ryubing/ryujinx!111
2025-11-19 20:50:23 -06:00
Goodfeat
6126e3dc1e fix: UI: Custom setting was reset to global when changed during gameplay. (ryubing/ryujinx!164)
See merge request ryubing/ryujinx!164
2025-11-19 20:33:35 -06:00
GreemDev
e1c829f91d We no longer offer a dedicated headless build. This script could have been deleted like a year ago lol 2025-11-17 22:47:23 -06:00
Babib3l
6c7dc7646b Translation updates (ryubing/ryujinx!221)
See merge request ryubing/ryujinx!221
2025-11-17 22:34:54 -06:00
GreemDev
862a686c5e UI: Improve "Show Changelog" button in the updater
Now it no longer causes the dialog to disappear (which then promptly re-appears so you can click yes/no to accept/deny the update)
2025-11-17 00:15:58 -06:00
GreemDev
e8751e1c40 more C# 14 partial properties 2025-11-16 19:14:26 -06:00
GreemDev
09748b140a Use the new C# 14 null propagation setter 2025-11-16 19:14:26 -06:00
Coxxs
456db46065 Stub IWriterForApplication: 0 (CreateContextRegistrar) (ryubing/ryujinx!183)
See merge request ryubing/ryujinx!183
2025-11-16 18:24:41 -06:00
GreemDev
7b39ff36c0 docs: compat: ZA LDN works and has for a while 2025-11-16 00:30:37 -06:00
Maki
10476771d3 fix: detect face button layout for gamepads (ryubing/ryujinx!219)
See merge request ryubing/ryujinx!219
2025-11-14 12:51:53 -06:00
Maki
c5082ac85a fix: make controller GUIDs match old SDL2 GUIDs (ryubing/ryujinx!218)
See merge request ryubing/ryujinx!218
2025-11-14 11:52:42 -06:00
GreemDev
5e86ad83cc feature: macOS Liquid Glass dynamic icon
No more squircle jail! Thanks @transistor.exe in the Ryubing discord for dropping the asset files for this to happen.
2025-11-13 20:47:05 -06:00
Coxxs
1baaa1c365 Preserve and rename the configuration file when it is deemed invalid (ryubing/ryujinx!216)
See merge request ryubing/ryujinx!216
2025-11-12 08:23:05 -06:00
LotP
e8225ce7aa Memory changes 3.1 (ryubing/ryujinx!212)
See merge request ryubing/ryujinx!212
2025-11-11 13:24:57 -06:00
GreemDev
6b814fb973 feature: .NET 10 (ryubing/ryujinx!214)
See merge request ryubing/ryujinx!214
2025-11-11 12:55:36 -06:00
GreemDev
49c70efdd5 UI: App Library: automatically remove nonexistent autoload/game dirs from the configuration upon load. 2025-11-10 19:14:29 -06:00
Babib3l
4677b749b1 fr_FR and es_ES small translation update (ryubing/ryujinx!172)
See merge request ryubing/ryujinx!172
2025-11-10 17:35:17 -06:00
GreemDev
ed32cd6999 fix nested project error when building 2025-11-10 13:32:40 -06:00
GreemDev
d7e2d4534a [ci skip] fix new SDL projects showing up in an src folder in the IDE (idk how I didn't see that before) 2025-11-10 00:12:39 -06:00
LotP
3c3e14c819 Update .gitattributes (ryubing/ryujinx!213)
See merge request ryubing/ryujinx!213
2025-11-09 19:03:01 -06:00
Godzilaa4
dd9ba05e36 Updated PT_BR translation (ryubing/ryujinx!208)
See merge request ryubing/ryujinx!208
2025-11-09 14:36:44 -06:00
Maki
a49822470c fix: crash when connecting a joycon (ryubing/ryujinx!211)
See merge request ryubing/ryujinx!211
2025-11-09 13:35:16 -06:00
GreemDev
58be57bf73 chore: [ci skip] rename InputElement_OnGotFocus/OnLostFocus to fit what it's listening to better 2025-11-08 03:21:54 -06:00
shinyoyo
17d5d6e65a Updated Simplified Chinese translation. (ryubing/ryujinx!209)
See merge request ryubing/ryujinx!209
2025-11-08 03:16:17 -06:00
GreemDev
1dac06e394 misc: [ci skip] remove duplicate log when setting audio backend 2025-11-08 00:18:23 -06:00
GreemDev
ed89ffd3f8 fix: add back compat functionality to the AudioBackend enum as well, and add missing migration comment from config version 70 2025-11-07 22:23:13 -06:00
GreemDev
844d7a9cfe fix: broken arrow in log 2025-11-07 22:14:35 -06:00
GreemDev
cf6acba416 chore: remove debug logging from SDL update 2025-11-07 20:44:25 -06:00
GreemDev
5a9d5ee664 chore: [ci skip] Add more misc logging similar to the "loading content archive" line for loading a base game dump, to updates and DLC. 2025-11-07 15:14:43 -06:00
GreemDev
bbad867319 add back the SDL2 enum for back compatibility so existing configs are not entirely reset upon loading the version with SDL3 2025-11-07 15:02:29 -06:00
Maki
a8ace3d23c chore: SDL3 (ryubing/ryujinx!207)
See merge request ryubing/ryujinx!207
2025-11-07 14:43:48 -06:00
GreemDev
13b69aedfe idea: Catch HorizonResultExceptions of result type ResultFsNonRealDataVerificationFailed
- log a more clear error message as to what 2002-4604 means for the user
- and return the result from the FileSystemProxy IStorage to pass the invalid data handling to the game instead of stopping emulation there and then.
  - this may be changed. i'm pretty sure this error is only thrown when you actually have integrity checking enabled in settings, so maybe it crashing with a friendler message is more desired than potentially continuing execution. we will see
2025-11-06 23:40:16 -06:00
GreemDev
234f7ca298 Fix socket closing on shutdown
Previously, sockets were only ever closed when the game specifically requested it.

Thanks @comex on GitHub for the patch submitted via the issues page.

Co-Authored-By: comex <47517+comex@users.noreply.github.com>
2025-11-04 20:48:36 -06:00
LotP
2c9b193018 Fix compiler warning (ryubing/ryujinx!203)
See merge request ryubing/ryujinx!203
2025-10-30 21:09:24 -05:00
LotP
92b61f9d73 Memory changes 3 (ryubing/ryujinx!202)
See merge request ryubing/ryujinx!202
2025-10-30 20:55:58 -05:00
WilliamWsyHK
ab7aeee67b Add newly translated items for zh-TW (ryubing/ryujinx!200)
See merge request ryubing/ryujinx!200
2025-10-29 18:02:54 -05:00
Hack茶ん
b991fe05d9 Update Korean translation (ryubing/ryujinx!201)
See merge request ryubing/ryujinx!201
2025-10-29 18:01:07 -05:00
GreemDev
3140ec5f05 misc: Also show an error message box and quit if the process was launched with administrator rights. 2025-10-28 20:57:03 -05:00
GreemDev
40f709ff55 misc: Add a launch guard for program files (the emulator does not work properly when put here as it does not require admin) 2025-10-28 19:04:25 -05:00
GreemDev
53aae9b584 hle: Throw a ServiceNotImplementedException instead of ArgumentException if any number arguments provided to ILibraryAppletAccessor are nonzero 2025-10-28 15:37:59 -05:00
LotP
ff9a75f895 ILibraryAppletAccessor:90 tweak (ryubing/ryujinx!199)
See merge request ryubing/ryujinx!199
2025-10-28 13:37:20 -05:00
sh0inx
3394736b07 HLE: Stub ILibraryAppletAccessor Unknown90 (ryubing/ryujinx!197)
See merge request ryubing/ryujinx!197
2025-10-27 12:48:17 -05:00
yeager
b06846aa5e Updated Swedish translation (with updated branch) (ryubing/ryujinx!156)
See merge request ryubing/ryujinx!156
2025-10-27 02:47:59 -05:00
LotP
c94ffaa00a gpu allocation optimizations (ryubing/ryujinx!195)
See merge request ryubing/ryujinx!195
2025-10-26 14:14:51 -05:00
GreemDev
718652599d UI: Prevent null ldn game model arrays from entering the SetEntries method 2025-10-26 12:51:08 -05:00
GreemDev
c8959afa3d chore: Overall code cleanup
Update NuGet packages, fix version string in plist for macOS
2025-10-26 01:22:20 -05:00
Coxxs
7175da8621 UI: [ci skip] Show notifications for options that may cause side effects (ryubing/ryujinx!193)
See merge request ryubing/ryujinx!193
2025-10-26 00:29:38 -05:00
LotP
fd07453887 audio effects fix and audio object pooling (ryubing/ryujinx!192)
See merge request ryubing/ryujinx!192
2025-10-25 21:07:10 -05:00
KeatonTheBot
c6bc77e4bf UI: Update Avalonia to 11.3.6, FluentAvalonia to 2.4.0 (ryubing/ryujinx!118)
See merge request ryubing/ryujinx!118
2025-10-25 00:29:51 -05:00
482 changed files with 14097 additions and 10900 deletions

1
.gitattributes vendored
View File

@@ -2,3 +2,4 @@
# Set default behavior to automatically normalize line endings.
###############################################################################
* text=auto eol=lf
*.json text eol=lf

View File

@@ -1,4 +1,4 @@
name: Canary release job
name: Canary CI
on:
workflow_dispatch:
@@ -19,7 +19,6 @@ concurrency: release
env:
POWERSHELL_TELEMETRY_OPTOUT: 1
DOTNET_CLI_TELEMETRY_OPTOUT: 1
RYUJINX_BASE_VERSION: "1.3"
RYUJINX_TARGET_RELEASE_CHANNEL_NAME: "canary"
RELEASE: 1
@@ -30,8 +29,8 @@ jobs:
strategy:
matrix:
platform:
- { name: win-x64, os: windows-latest, zip_os_name: win_x64 }
#- { name: win-arm64, os: windows-latest, zip_os_name: win_arm64 }
- { name: win-x64, os: ubuntu-latest, zip_os_name: win_x64 }
#- { name: win-arm64, os: ubuntu-latest, zip_os_name: win_arm64 }
- { name: linux-x64, os: ubuntu-latest, zip_os_name: linux_x64 }
- { name: linux-arm64, os: ubuntu-latest, zip_os_name: linux_arm64 }
steps:
@@ -44,11 +43,25 @@ jobs:
- name: Overwrite csc problem matcher
run: echo "::add-matcher::.github/csc.json"
- name: Install 7zip
run: |
sudo apt install -y 7zip
- name: Install gli
run: |
mkdir -p $HOME/.bin
gh release download -R GreemDev/GLI -O gli -p 'gli-linux-x64'
chmod +x gli
mv gli $HOME/.bin/
echo "$HOME/.bin" >> $GITHUB_PATH
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Get version info
id: version_info
run: |
echo "build_version=${{ env.RYUJINX_BASE_VERSION }}.${{ github.run_number }}" >> $GITHUB_OUTPUT
echo "prev_build_version=${{ env.RYUJINX_BASE_VERSION }}.$((${{ github.run_number }} - 1))" >> $GITHUB_OUTPUT
echo "build_version=$(gli get-next-version -c Canary -R)" >> $GITHUB_OUTPUT
echo "prev_build_version=$(gli get-current-version -c Canary -R)" >> $GITHUB_OUTPUT
echo "git_short_hash=$(git rev-parse --short "${{ github.sha }}")" >> $GITHUB_OUTPUT
shell: bash
@@ -69,33 +82,20 @@ jobs:
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'
if: contains(matrix.platform.name, 'win')
run: |
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
gh release download -R GreemDev/GLI -O gli.exe -p 'GitLabCli-win_x64.exe'
./gli.exe --access-token=${{ secrets.GITLAB_TOKEN }} --project=ryubing/canary --command=UploadGenericPackage "Ryubing-Canary|${{ steps.version_info.outputs.build_version }}|release_output/ryujinx-canary-${{ steps.version_info.outputs.build_version }}-${{ matrix.platform.zip_os_name }}.zip"
gli upload-generic-package -T ${{ secrets.GITLAB_TOKEN }} -P ryubing/canary -n Ryubing-Canary -v ${{ steps.version_info.outputs.build_version }} -r 5 -p release_output/ryujinx-canary-${{ steps.version_info.outputs.build_version }}-${{ matrix.platform.zip_os_name }}.zip
shell: bash
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Install GitLabCli
if: matrix.platform.os == 'ubuntu-latest'
run: |
mkdir -p $HOME/.bin
gh release download -R GreemDev/GLI -O gli -p 'GitLabCli-linux_x64'
chmod +x gli
mv gli $HOME/.bin/
echo "$HOME/.bin" >> $GITHUB_PATH
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Packing Linux builds
if: matrix.platform.os == 'ubuntu-latest'
if: contains(matrix.platform.name, 'linux')
run: |
pushd publish
rm libarmeilleure-jitsupport.dylib
@@ -103,11 +103,11 @@ jobs:
tar -czvf ../release_output/ryujinx-canary-${{ steps.version_info.outputs.build_version }}-${{ matrix.platform.zip_os_name }}.tar.gz ../publish
popd
gli --access-token=${{ secrets.GITLAB_TOKEN }} --project=ryubing/canary --command=UploadGenericPackage "Ryubing-Canary|${{ steps.version_info.outputs.build_version }}|release_output/ryujinx-canary-${{ steps.version_info.outputs.build_version }}-${{ matrix.platform.zip_os_name }}.tar.gz"
gli upload-generic-package -T ${{ secrets.GITLAB_TOKEN }} -P ryubing/canary -n Ryubing-Canary -v ${{ steps.version_info.outputs.build_version }} -r 5 -p release_output/ryujinx-canary-${{ steps.version_info.outputs.build_version }}-${{ matrix.platform.zip_os_name }}.tar.gz
shell: bash
- name: Build AppImage (Linux)
if: matrix.platform.os == 'ubuntu-latest'
if: contains(matrix.platform.name, 'linux')
run: |
BUILD_VERSION="${{ steps.version_info.outputs.build_version }}"
PLATFORM_NAME="${{ matrix.platform.name }}"
@@ -139,8 +139,8 @@ jobs:
pushd publish_appimage
mv Ryujinx.AppImage ../release_output/ryujinx-canary-$BUILD_VERSION-$ARCH_NAME.AppImage
popd
gli --access-token=${{ secrets.GITLAB_TOKEN }} --project=ryubing/canary --command=UploadGenericPackage "Ryubing-Canary|${{ steps.version_info.outputs.build_version }}|release_output/ryujinx-canary-$BUILD_VERSION-$ARCH_NAME.AppImage"
gli upload-generic-package -T ${{ secrets.GITLAB_TOKEN }} -P ryubing/canary -n Ryubing-Canary -v ${{ steps.version_info.outputs.build_version }} -r 5 -p release_output/ryujinx-canary-$BUILD_VERSION-$ARCH_NAME.AppImage
shell: bash
macos_release:
@@ -159,10 +159,10 @@ jobs:
chmod +x llvm.sh
sudo ./llvm.sh 17
- name: Install GitLabCli
- name: Install gli
run: |
mkdir -p $HOME/.bin
gh release download -R GreemDev/GLI -O gli -p 'GitLabCli-linux_x64'
gh release download -R GreemDev/GLI -O gli -p 'gli-linux-x64'
chmod +x gli
mv gli $HOME/.bin/
echo "$HOME/.bin" >> $GITHUB_PATH
@@ -183,9 +183,10 @@ jobs:
- name: Get version info
id: version_info
run: |
echo "build_version=${{ env.RYUJINX_BASE_VERSION }}.${{ github.run_number }}" >> $GITHUB_OUTPUT
echo "prev_build_version=${{ env.RYUJINX_BASE_VERSION }}.$((${{ github.run_number }} - 1))" >> $GITHUB_OUTPUT
echo "build_version=$(gli get-next-version -c Canary -R)" >> $GITHUB_OUTPUT
echo "prev_build_version=$(gli get-current-version -c Canary -R)" >> $GITHUB_OUTPUT
echo "git_short_hash=$(git rev-parse --short "${{ github.sha }}")" >> $GITHUB_OUTPUT
shell: bash
- name: Configure for release
run: |
@@ -200,7 +201,7 @@ jobs:
- name: Publish macOS Ryujinx
run: |
./distribution/macos/create_macos_build_ava.sh . publish_tmp_ava publish_ava ./distribution/macos/entitlements.xml "${{ steps.version_info.outputs.build_version }}" "${{ steps.version_info.outputs.git_short_hash }}" Release 1
gli --access-token=${{ secrets.GITLAB_TOKEN }} --project=ryubing/canary --command=UploadGenericPackage "Ryubing-Canary|${{ steps.version_info.outputs.build_version }}|publish_ava/ryujinx-canary-${{ steps.version_info.outputs.build_version }}-macos_universal.app.tar.gz"
gli upload-generic-package -T ${{ secrets.GITLAB_TOKEN }} -P ryubing/canary -n Ryubing-Canary -v ${{ steps.version_info.outputs.build_version }} -r 5 -p publish_ava/ryujinx-canary-${{ steps.version_info.outputs.build_version }}-macos_universal.app.tar.gz
create_gitlab_release:
name: Create GitLab Release
@@ -210,37 +211,41 @@ jobs:
- release
steps:
- uses: actions/checkout@v4
- name: Get version info
id: version_info
run: |
echo "build_version=${{ env.RYUJINX_BASE_VERSION }}.${{ github.run_number }}" >> $GITHUB_OUTPUT
echo "prev_build_version=${{ env.RYUJINX_BASE_VERSION }}.$((${{ github.run_number }} - 1))" >> $GITHUB_OUTPUT
echo "git_short_hash=$(git rev-parse --short "${{ github.sha }}")" >> $GITHUB_OUTPUT
shell: bash
- name: Install GitLabCli
- name: Install gli
run: |
mkdir -p $HOME/.bin
gh release download -R GreemDev/GLI -O gli -p 'GitLabCli-linux_x64'
gh release download -R GreemDev/GLI -O gli -p 'gli-linux-x64'
chmod +x gli
mv gli $HOME/.bin/
echo "$HOME/.bin" >> $GITHUB_PATH
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Get version info
id: version_info
run: |
echo "build_version=$(gli get-next-version -c Canary -R)" >> $GITHUB_OUTPUT
echo "prev_build_version=$(gli get-current-version -c Canary -R)" >> $GITHUB_OUTPUT
echo "git_short_hash=$(git rev-parse --short "${{ github.sha }}")" >> $GITHUB_OUTPUT
shell: bash
- name: Create tag
run: |
gli --access-token=${{ secrets.GITLAB_TOKEN }} --project=ryubing/ryujinx --command=CreateTag "Canary-${{ steps.version_info.outputs.build_version }}|${{ steps.version_info.outputs.git_short_hash }}"
gli create-tag -T ${{ secrets.GITLAB_TOKEN }} -P ryubing/ryujinx -n Canary-${{ steps.version_info.outputs.build_version }} -r ${{ steps.version_info.outputs.git_short_hash }}
- name: Create release
run: |
gli --access-token=${{ secrets.GITLAB_TOKEN }} --project=ryubing/canary --command=CreateReleaseFromGenericPackageFiles "Ryubing-Canary|${{ steps.version_info.outputs.build_version }}|main|Canary ${{ steps.version_info.outputs.build_version }}|**Full Changelog:** [${{ steps.version_info.outputs.prev_build_version }}...${{ steps.version_info.outputs.build_version }}](https://git.ryujinx.app/ryubing/ryujinx/-/compare/Canary-${{ steps.version_info.outputs.prev_build_version }}...Canary-${{ steps.version_info.outputs.build_version }})"
gli create-release-from-generic-package-files -T ${{ secrets.GITLAB_TOKEN }} -P ryubing/canary -n Ryubing-Canary -v ${{ steps.version_info.outputs.build_version }} -r main -t "Canary ${{ steps.version_info.outputs.build_version }}" -b "**Full Changelog:** [${{ steps.version_info.outputs.prev_build_version }}...${{ steps.version_info.outputs.build_version }}](https://git.ryujinx.app/ryubing/ryujinx/-/compare/Canary-${{ steps.version_info.outputs.prev_build_version }}...Canary-${{ steps.version_info.outputs.build_version }})"
- name: Send notification webhook
run: |
gli --access-token=${{ secrets.GITLAB_TOKEN }} --project=ryubing/canary --command=SendUpdateMessage "${{ steps.version_info.outputs.build_version }}|FF4500|${{ secrets.CANARY_DISCORD_WEBHOOK }}|https://avatars.githubusercontent.com/u/192939710?s=200&v=4|false"
gli send-update-message -T ${{ secrets.GITLAB_TOKEN }} -P ryubing/canary -t ${{ steps.version_info.outputs.build_version }} -c FF4500 -w ${{ secrets.CANARY_DISCORD_WEBHOOK }} -i https://avatars.githubusercontent.com/u/192939710?s=200&v=4
- name: Notify update server of new builds
run: |
curl 'https://update.ryujinx.app/api/v1/admin/refresh_cache?rc=canary' -X PATCH -H 'accept: */*' -H 'Authorization: ${{ secrets.UPDATE_SERVER_ADMIN_TOKEN }}'
gli refresh-version-cache -T ${{ secrets.UPDATE_SERVER_ADMIN_TOKEN }} -c Canary
- name: Advance to the next version
run: |
gli increment-version -T ${{ secrets.UPDATE_SERVER_ADMIN_TOKEN }} -c Canary

View File

@@ -1,224 +0,0 @@
name: Release job (Debug)
on:
workflow_dispatch:
inputs: {}
concurrency: release
env:
POWERSHELL_TELEMETRY_OPTOUT: 1
DOTNET_CLI_TELEMETRY_OPTOUT: 1
RYUJINX_BASE_VERSION: "1.3"
RYUJINX_TARGET_RELEASE_CHANNEL_NAME: "release"
RELEASE: 1
jobs:
release:
name: Release for ${{ matrix.platform.name }}
runs-on: ${{ matrix.platform.os }}
strategy:
matrix:
platform:
- { name: win-x64, os: windows-latest, zip_os_name: win_x64 }
#- { name: win-arm64, os: windows-latest, zip_os_name: win_arm64 }
- { name: linux-x64, os: ubuntu-latest, zip_os_name: linux_x64 }
- { name: linux-arm64, os: ubuntu-latest, zip_os_name: linux_arm64 }
steps:
- uses: actions/checkout@v4
- uses: actions/setup-dotnet@v4
with:
global-json-file: global.json
- name: Overwrite csc problem matcher
run: echo "::add-matcher::.github/csc.json"
- name: Get version info
id: version_info
run: |
echo "build_version=${{ env.RYUJINX_BASE_VERSION }}.$((${{ github.run_number }} + 10))" >> $GITHUB_OUTPUT
echo "prev_build_version=${{ env.RYUJINX_BASE_VERSION }}.$((${{ github.run_number }} - 1))" >> $GITHUB_OUTPUT
echo "git_short_hash=$(git rev-parse --short "${{ github.sha }}")" >> $GITHUB_OUTPUT
shell: bash
- name: Configure for release
run: |
sed -r --in-place 's/\%\%RYUJINX_BUILD_VERSION\%\%/${{ steps.version_info.outputs.build_version }}/g;' src/Ryujinx.Common/ReleaseInformation.cs
sed -r --in-place 's/\%\%RYUJINX_BUILD_GIT_HASH\%\%/${{ steps.version_info.outputs.git_short_hash }}/g;' src/Ryujinx.Common/ReleaseInformation.cs
sed -r --in-place 's/\%\%RYUJINX_TARGET_RELEASE_CHANNEL_NAME\%\%/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_NAME }}/g;' src/Ryujinx.Common/ReleaseInformation.cs
sed -r --in-place 's/\%\%RYUJINX_CONFIG_FILE_NAME\%\%/Config\.json/g;' src/Ryujinx.Common/ReleaseInformation.cs
shell: bash
- name: Create output dir
run: "mkdir release_output"
- name: Publish
run: |
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
rm libarmeilleure-jitsupport.dylib
7z a ../release_output/ryujinx-${{ steps.version_info.outputs.build_version }}-${{ matrix.platform.zip_os_name }}.zip ../publish
popd
gh release download -R GreemDev/GLI -O gli.exe -p 'GitLabCli-win_x64.exe'
./gli.exe --access-token=${{ secrets.GITLAB_TOKEN }} --project=ryubing/ryujinx --command=UploadGenericPackage "Ryubing|${{ steps.version_info.outputs.build_version }}|release_output/ryujinx-${{ steps.version_info.outputs.build_version }}-${{ matrix.platform.zip_os_name }}.zip"
shell: bash
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Install GitLabCli
if: matrix.platform.os == 'ubuntu-latest'
run: |
mkdir -p $HOME/.bin
gh release download -R GreemDev/GLI -O gli -p 'GitLabCli-linux_x64'
chmod +x gli
mv gli $HOME/.bin/
echo "$HOME/.bin" >> $GITHUB_PATH
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Packing Linux builds
if: matrix.platform.os == 'ubuntu-latest'
run: |
pushd publish
rm libarmeilleure-jitsupport.dylib
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
gli --access-token=${{ secrets.GITLAB_TOKEN }} --project=ryubing/ryujinx --command=UploadGenericPackage "Ryubing|${{ steps.version_info.outputs.build_version }}|release_output/ryujinx-${{ steps.version_info.outputs.build_version }}-${{ matrix.platform.zip_os_name }}.tar.gz"
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 }}"
sudo apt install -y zsync desktop-file-utils appstream
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
# 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
export UFLAG="gh-releases-zsync|${{ github.repository_owner }}|${{ github.event.repository.name }}|latest|*-$ARCH_NAME.AppImage.zsync"
BUILDDIR=publish OUTDIR=publish_appimage distribution/linux/appimage/build-appimage.sh
pushd publish_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
gli --access-token=${{ secrets.GITLAB_TOKEN }} --project=ryubing/ryujinx --command=UploadGenericPackage "Ryubing|${{ steps.version_info.outputs.build_version }}|release_output/ryujinx-$BUILD_VERSION-$ARCH_NAME.AppImage"
gli --access-token=${{ secrets.GITLAB_TOKEN }} --project=ryubing/ryujinx --command=UploadGenericPackage "Ryubing|${{ steps.version_info.outputs.build_version }}|release_output/ryujinx-$BUILD_VERSION-$ARCH_NAME.AppImage.zsync"
shell: bash
macos_release:
name: Release MacOS universal
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v4
- uses: actions/setup-dotnet@v4
with:
global-json-file: global.json
- name: Setup LLVM 17
run: |
wget https://apt.llvm.org/llvm.sh
chmod +x llvm.sh
sudo ./llvm.sh 17
- name: Install GitLabCli
run: |
mkdir -p $HOME/.bin
gh release download -R GreemDev/GLI -O gli -p 'GitLabCli-linux_x64'
chmod +x gli
mv gli $HOME/.bin/
echo "$HOME/.bin" >> $GITHUB_PATH
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Install rcodesign
run: |
mkdir -p $HOME/.bin
gh release download -R indygreg/apple-platform-rs -O apple-codesign.tar.gz -p 'apple-codesign-*-x86_64-unknown-linux-musl.tar.gz'
tar -xzvf apple-codesign.tar.gz --wildcards '*/rcodesign' --strip-components=1
rm apple-codesign.tar.gz
mv rcodesign $HOME/.bin/
echo "$HOME/.bin" >> $GITHUB_PATH
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Get version info
id: version_info
run: |
echo "build_version=${{ env.RYUJINX_BASE_VERSION }}.$((${{ github.run_number }} + 10))" >> $GITHUB_OUTPUT
echo "prev_build_version=${{ env.RYUJINX_BASE_VERSION }}.$((${{ github.run_number }} - 1))" >> $GITHUB_OUTPUT
echo "git_short_hash=$(git rev-parse --short "${{ github.sha }}")" >> $GITHUB_OUTPUT
- name: Configure for release
run: |
sed -r --in-place 's/\%\%RYUJINX_BUILD_VERSION\%\%/${{ steps.version_info.outputs.build_version }}/g;' src/Ryujinx.Common/ReleaseInformation.cs
sed -r --in-place 's/\%\%RYUJINX_BUILD_GIT_HASH\%\%/${{ steps.version_info.outputs.git_short_hash }}/g;' src/Ryujinx.Common/ReleaseInformation.cs
sed -r --in-place 's/\%\%RYUJINX_TARGET_RELEASE_CHANNEL_NAME\%\%/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_NAME }}/g;' src/Ryujinx.Common/ReleaseInformation.cs
sed -r --in-place 's/\%\%RYUJINX_CONFIG_FILE_NAME\%\%/Config\.json/g;' src/Ryujinx.Common/ReleaseInformation.cs
shell: bash
- name: Publish macOS Ryujinx
run: |
./distribution/macos/create_macos_build_ava.sh . publish_tmp_ava publish ./distribution/macos/entitlements.xml "${{ steps.version_info.outputs.build_version }}" "${{ steps.version_info.outputs.git_short_hash }}" Release 0
gli --access-token=${{ secrets.GITLAB_TOKEN }} --project=ryubing/ryujinx --command=UploadGenericPackage "Ryubing|${{ steps.version_info.outputs.build_version }}|publish/ryujinx-${{ steps.version_info.outputs.build_version }}-macos_universal.app.tar.gz"
create_gitlab_release:
name: Create GitLab Release
runs-on: ubuntu-24.04
needs:
- macos_release
- release
steps:
- uses: actions/checkout@v4
- name: Get version info
id: version_info
run: |
echo "build_version=${{ env.RYUJINX_BASE_VERSION }}.$((${{ github.run_number }} + 10))" >> $GITHUB_OUTPUT
echo "prev_build_version=${{ env.RYUJINX_BASE_VERSION }}.$((${{ github.run_number }} - 1))" >> $GITHUB_OUTPUT
echo "git_short_hash=$(git rev-parse --short "${{ github.sha }}")" >> $GITHUB_OUTPUT
shell: bash
- name: Install GitLabCli
run: |
mkdir -p $HOME/.bin
gh release download -R GreemDev/GLI -O gli -p 'GitLabCli-linux_x64'
chmod +x gli
mv gli $HOME/.bin/
echo "$HOME/.bin" >> $GITHUB_PATH
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Create release
run: |
gli --access-token=${{ secrets.GITLAB_TOKEN }} --project=ryubing/ryujinx --command=CreateReleaseFromGenericPackageFiles "Ryubing|${{ steps.version_info.outputs.build_version }}|${{ steps.version_info.outputs.git_short_hash }}|test|THIS IS NOT INTENDED FOR END USER USAGE"

View File

@@ -1,15 +1,18 @@
name: Release job
name: Stable CI
on:
workflow_dispatch:
inputs: {}
inputs:
is_bugfix_release:
description: "Bug fix release: If checked, this will increment the third number for only Stable, and leave the Major version alone for both Stable and Canary."
required: true
type: boolean
concurrency: release
env:
POWERSHELL_TELEMETRY_OPTOUT: 1
DOTNET_CLI_TELEMETRY_OPTOUT: 1
RYUJINX_BASE_VERSION: "1.3"
RYUJINX_TARGET_RELEASE_CHANNEL_NAME: "release"
RELEASE: 1
@@ -20,8 +23,8 @@ jobs:
strategy:
matrix:
platform:
- { name: win-x64, os: windows-latest, zip_os_name: win_x64 }
#- { name: win-arm64, os: windows-latest, zip_os_name: win_arm64 }
- { name: win-x64, os: ubuntu-latest, zip_os_name: win_x64 }
#- { name: win-arm64, os: ubuntu-latest, zip_os_name: win_arm64 }
- { name: linux-x64, os: ubuntu-latest, zip_os_name: linux_x64 }
- { name: linux-arm64, os: ubuntu-latest, zip_os_name: linux_arm64 }
steps:
@@ -33,12 +36,30 @@ jobs:
- name: Overwrite csc problem matcher
run: echo "::add-matcher::.github/csc.json"
- name: Install 7zip
run: |
sudo apt install -y 7zip
- name: Install gli
run: |
mkdir -p $HOME/.bin
gh release download -R GreemDev/GLI -O gli -p 'gli-linux-x64'
chmod +x gli
mv gli $HOME/.bin/
echo "$HOME/.bin" >> $GITHUB_PATH
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Get version info
id: version_info
run: |
echo "build_version=${{ env.RYUJINX_BASE_VERSION }}.${{ github.run_number }}" >> $GITHUB_OUTPUT
echo "prev_build_version=${{ env.RYUJINX_BASE_VERSION }}.$((${{ github.run_number }} - 1))" >> $GITHUB_OUTPUT
if [ '${{ inputs.is_bugfix_release }}' == 'false' ]; then
echo "build_version=$(gli get-next-version -m -c Stable -R)" >> $GITHUB_OUTPUT
else
echo "build_version=$(gli get-next-version -c Stable -R)" >> $GITHUB_OUTPUT
fi
echo "prev_build_version=$(gli get-current-version -c Stable -R)" >> $GITHUB_OUTPUT
echo "git_short_hash=$(git rev-parse --short "${{ github.sha }}")" >> $GITHUB_OUTPUT
shell: bash
@@ -58,47 +79,34 @@ jobs:
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'
if: contains(matrix.platform.name, 'win')
run: |
pushd publish
rm libarmeilleure-jitsupport.dylib
7z a ../release_output/ryujinx-${{ steps.version_info.outputs.build_version }}-${{ matrix.platform.zip_os_name }}.zip ../publish
popd
gh release download -R GreemDev/GLI -O gli.exe -p 'GitLabCli-win_x64.exe'
./gli.exe --access-token=${{ secrets.GITLAB_TOKEN }} --project=ryubing/ryujinx --command=UploadGenericPackage "Ryubing|${{ steps.version_info.outputs.build_version }}|release_output/ryujinx-${{ steps.version_info.outputs.build_version }}-${{ matrix.platform.zip_os_name }}.zip"
gli upload-generic-package -T ${{ secrets.GITLAB_TOKEN }} -P ryubing/ryujinx -n Ryubing -v ${{ steps.version_info.outputs.build_version }} -r 5 -p release_output/ryujinx-${{ steps.version_info.outputs.build_version }}-${{ matrix.platform.zip_os_name }}.zip
shell: bash
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Install GitLabCli
if: matrix.platform.os == 'ubuntu-latest'
run: |
mkdir -p $HOME/.bin
gh release download -R GreemDev/GLI -O gli -p 'GitLabCli-linux_x64'
chmod +x gli
mv gli $HOME/.bin/
echo "$HOME/.bin" >> $GITHUB_PATH
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Packing Linux builds
if: matrix.platform.os == 'ubuntu-latest'
if: contains(matrix.platform.name, 'linux')
run: |
pushd publish
rm libarmeilleure-jitsupport.dylib
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
gli --access-token=${{ secrets.GITLAB_TOKEN }} --project=ryubing/ryujinx --command=UploadGenericPackage "Ryubing|${{ steps.version_info.outputs.build_version }}|release_output/ryujinx-${{ steps.version_info.outputs.build_version }}-${{ matrix.platform.zip_os_name }}.tar.gz"
gli upload-generic-package -T ${{ secrets.GITLAB_TOKEN }} -P ryubing/ryujinx -n Ryubing -v ${{ steps.version_info.outputs.build_version }} -r 5 -p release_output/ryujinx-${{ steps.version_info.outputs.build_version }}-${{ matrix.platform.zip_os_name }}.tar.gz
shell: bash
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Build AppImage (Linux)
if: matrix.platform.os == 'ubuntu-latest'
if: contains(matrix.platform.name, 'linux')
run: |
BUILD_VERSION="${{ steps.version_info.outputs.build_version }}"
PLATFORM_NAME="${{ matrix.platform.name }}"
@@ -131,7 +139,7 @@ jobs:
mv Ryujinx.AppImage ../release_output/ryujinx-$BUILD_VERSION-$ARCH_NAME.AppImage
popd
gli --access-token=${{ secrets.GITLAB_TOKEN }} --project=ryubing/ryujinx --command=UploadGenericPackage "Ryubing|${{ steps.version_info.outputs.build_version }}|release_output/ryujinx-$BUILD_VERSION-$ARCH_NAME.AppImage"
gli upload-generic-package -T ${{ secrets.GITLAB_TOKEN }} -P ryubing/ryujinx -n Ryubing -v ${{ steps.version_info.outputs.build_version }} -r 5 -p release_output/ryujinx-$BUILD_VERSION-$ARCH_NAME.AppImage
shell: bash
macos_release:
@@ -150,10 +158,10 @@ jobs:
chmod +x llvm.sh
sudo ./llvm.sh 17
- name: Install GitLabCli
- name: Install gli
run: |
mkdir -p $HOME/.bin
gh release download -R GreemDev/GLI -O gli -p 'GitLabCli-linux_x64'
gh release download -R GreemDev/GLI -O gli -p 'gli-linux-x64'
chmod +x gli
mv gli $HOME/.bin/
echo "$HOME/.bin" >> $GITHUB_PATH
@@ -174,9 +182,14 @@ jobs:
- name: Get version info
id: version_info
run: |
echo "build_version=${{ env.RYUJINX_BASE_VERSION }}.${{ github.run_number }}" >> $GITHUB_OUTPUT
echo "prev_build_version=${{ env.RYUJINX_BASE_VERSION }}.$((${{ github.run_number }} - 1))" >> $GITHUB_OUTPUT
if [ '${{ inputs.is_bugfix_release }}' == 'false' ]; then
echo "build_version=$(gli get-next-version -m -c Stable -R)" >> $GITHUB_OUTPUT
else
echo "build_version=$(gli get-next-version -c Stable -R)" >> $GITHUB_OUTPUT
fi
echo "prev_build_version=$(gli get-current-version -c Stable -R)" >> $GITHUB_OUTPUT
echo "git_short_hash=$(git rev-parse --short "${{ github.sha }}")" >> $GITHUB_OUTPUT
shell: bash
- name: Configure for release
run: |
@@ -189,7 +202,8 @@ jobs:
- name: Publish macOS Ryujinx
run: |
./distribution/macos/create_macos_build_ava.sh . publish_tmp_ava publish ./distribution/macos/entitlements.xml "${{ steps.version_info.outputs.build_version }}" "${{ steps.version_info.outputs.git_short_hash }}" Release 0
gli --access-token=${{ secrets.GITLAB_TOKEN }} --project=ryubing/ryujinx --command=UploadGenericPackage "Ryubing|${{ steps.version_info.outputs.build_version }}|publish/ryujinx-${{ steps.version_info.outputs.build_version }}-macos_universal.app.tar.gz"
gli upload-generic-package -T ${{ secrets.GITLAB_TOKEN }} -P ryubing/ryujinx -n Ryubing -v ${{ steps.version_info.outputs.build_version }} -r 5 -p publish/ryujinx-${{ steps.version_info.outputs.build_version }}-macos_universal.app.tar.gz
create_gitlab_release:
name: Create GitLab Release
@@ -200,32 +214,45 @@ jobs:
steps:
- uses: actions/checkout@v4
- name: Get version info
id: version_info
run: |
echo "build_version=${{ env.RYUJINX_BASE_VERSION }}.${{ github.run_number }}" >> $GITHUB_OUTPUT
echo "prev_build_version=${{ env.RYUJINX_BASE_VERSION }}.$((${{ github.run_number }} - 1))" >> $GITHUB_OUTPUT
echo "git_short_hash=$(git rev-parse --short "${{ github.sha }}")" >> $GITHUB_OUTPUT
shell: bash
- name: Install GitLabCli
- name: Install gli
run: |
mkdir -p $HOME/.bin
gh release download -R GreemDev/GLI -O gli -p 'GitLabCli-linux_x64'
gh release download -R GreemDev/GLI -O gli -p 'gli-linux-x64'
chmod +x gli
mv gli $HOME/.bin/
echo "$HOME/.bin" >> $GITHUB_PATH
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Get version info
id: version_info
run: |
if [ '${{ inputs.is_bugfix_release }}' == 'false' ]; then
echo "build_version=$(gli get-next-version -m -c Stable -R)" >> $GITHUB_OUTPUT
else
echo "build_version=$(gli get-next-version -c Stable -R)" >> $GITHUB_OUTPUT
fi
echo "prev_build_version=$(gli get-current-version -c Stable -R)" >> $GITHUB_OUTPUT
echo "git_short_hash=$(git rev-parse --short "${{ github.sha }}")" >> $GITHUB_OUTPUT
echo "commit_message=$(git log -1 --pretty=%B)" >> $GITHUB_OUTPUT
shell: bash
- name: Create release
run: |
gli --access-token=${{ secrets.GITLAB_TOKEN }} --project=ryubing/ryujinx --command=CreateReleaseFromGenericPackageFiles "Ryubing|${{ steps.version_info.outputs.build_version }}|${{ steps.version_info.outputs.git_short_hash }}|${{ steps.version_info.outputs.build_version }}|msd:${{ steps.version_info.outputs.build_version }}"
gli create-release-from-generic-package-files -T ${{ secrets.GITLAB_TOKEN }} -P ryubing/ryujinx -n Ryubing -v ${{ steps.version_info.outputs.build_version }} -r ${{ steps.version_info.outputs.git_short_hash }} -t "${{ steps.version_info.outputs.build_version }}" -b "msd:${{ steps.version_info.outputs.build_version }}"
- name: Send notification webhook
run: |
gli --access-token=${{ secrets.GITLAB_TOKEN }} --project=ryubing/ryujinx --command=SendUpdateMessage "${{ steps.version_info.outputs.build_version }}|32cd32|${{ secrets.STABLE_DISCORD_WEBHOOK }}|https://avatars.githubusercontent.com/u/192939710?s=200&v=4|false"
gli send-update-message -T ${{ secrets.GITLAB_TOKEN }} -P ryubing/ryujinx -t ${{ steps.version_info.outputs.build_version }} -c 32cd32 -w ${{ secrets.STABLE_DISCORD_WEBHOOK }} -i https://avatars.githubusercontent.com/u/192939710?s=200&v=4
- name: Notify update server of new builds
run: |
curl 'https://update.ryujinx.app/api/v1/admin/refresh_cache?rc=stable' -X PATCH -H 'accept: */*' -H 'Authorization: ${{ secrets.UPDATE_SERVER_ADMIN_TOKEN }}'
gli refresh-version-cache -T ${{ secrets.UPDATE_SERVER_ADMIN_TOKEN }} -c Stable
- name: Advance to the next version
run: |
if [ '${{ inputs.is_bugfix_release }}' == 'false' ]; then
gli advance-version -T ${{ secrets.UPDATE_SERVER_ADMIN_TOKEN }}
else
gli increment-version -T ${{ secrets.UPDATE_SERVER_ADMIN_TOKEN }} -c Stable
fi

3
.gitignore vendored
View File

@@ -18,6 +18,8 @@ build/
[Oo]bj/
AppDir/
publish_appimage/
publish_ava/
publish_tmp_ava/
# Enable "build/" folder in the NuGet Packages folder since NuGet packages use it for MSBuild targets
!packages/*/build/
@@ -98,6 +100,7 @@ DocProject/Help/html
# Click-Once directory
publish/
RyubingMaintainerTools/
# Publish Web Output
*.Publish.xml

View File

@@ -5,7 +5,7 @@ If you wish to build the emulator yourself, follow these steps:
### Step 1
Install the [.NET 9.0 (or higher) SDK](https://dotnet.microsoft.com/download/dotnet/9.0).
Install the [.NET 10.0 (or higher) SDK](https://dotnet.microsoft.com/en-us/download/dotnet/10.0).
Make sure your SDK version is higher or equal to the required version specified in [global.json](global.json).
### Step 2

View File

@@ -1,6 +1,6 @@
<Project>
<PropertyGroup>
<TargetFramework>net9.0</TargetFramework>
<LangVersion>latest</LangVersion>
<TargetFramework>net10.0</TargetFramework>
<LangVersion>preview</LangVersion>
</PropertyGroup>
</Project>

View File

@@ -3,25 +3,26 @@
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
</PropertyGroup>
<ItemGroup>
<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="Avalonia" Version="11.3.6" />
<PackageVersion Include="Avalonia.Controls.DataGrid" Version="11.3.6" />
<PackageVersion Include="Avalonia.Desktop" Version="11.3.6" />
<PackageVersion Include="Avalonia.Diagnostics" Version="11.3.6" />
<PackageVersion Include="Avalonia.Markup.Xaml.Loader" Version="11.3.6" />
<PackageVersion Include="Svg.Controls.Avalonia" Version="11.3.6.2" />
<PackageVersion Include="Svg.Controls.Skia.Avalonia" Version="11.3.6.2" />
<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" Version="9.6.2" />
<PackageVersion Include="Projektanker.Icons.Avalonia.FontAwesome" Version="9.6.2" />
<PackageVersion Include="Projektanker.Icons.Avalonia.MaterialDesign" Version="9.6.2" />
<PackageVersion Include="ppy.SDL3-CS" Version="2025.920.0" />
<PackageVersion Include="CommandLineParser" Version="2.9.1" />
<PackageVersion Include="CommunityToolkit.Mvvm" Version="8.4.0"/>
<PackageVersion Include="CommunityToolkit.Mvvm" Version="8.4.0" />
<PackageVersion Include="Concentus" Version="2.2.2" />
<PackageVersion Include="DiscordRichPresence" Version="1.6.1.70" />
<PackageVersion Include="DynamicData" Version="9.4.1" />
<PackageVersion Include="FluentAvaloniaUI" Version="2.0.5" />
<PackageVersion Include="FluentAvaloniaUI.NoAnim" Version="2.4.0-build3" />
<PackageVersion Include="Humanizer" Version="2.14.1" />
<PackageVersion Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.4" />
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp" Version="4.9.2" />
@@ -40,11 +41,10 @@
<PackageVersion Include="Ryujinx.Audio.OpenAL.Dependencies" Version="1.21.0.1" />
<PackageVersion Include="Ryujinx.Graphics.Nvdec.Dependencies.AllArch" Version="6.1.2-build3" />
<PackageVersion Include="Ryujinx.Graphics.Vulkan.Dependencies.MoltenVK" Version="1.2.0" />
<PackageVersion Include="Ryujinx.LibHac" Version="0.21.0-alpha.117" />
<PackageVersion Include="Ryujinx.SDL2-CS" Version="2.30.0-build32" />
<PackageVersion Include="Ryujinx.LibHac" Version="0.21.0-alpha.126" />
<PackageVersion Include="Ryujinx.UpdateClient" Version="1.0.44" />
<PackageVersion Include="Ryujinx.Systems.Update.Common" Version="1.0.44" />
<PackageVersion Include="Gommon" Version="2.7.2.1" />
<PackageVersion Include="Gommon" Version="2.8.0.1" />
<PackageVersion Include="securifybv.ShellLink" Version="0.1.0" />
<PackageVersion Include="Sep" Version="0.11.1" />
<PackageVersion Include="shaderc.net" Version="0.1.0" />
@@ -59,4 +59,4 @@
<PackageVersion Include="System.Management" Version="9.0.2" />
<PackageVersion Include="UnicornEngine.Unicorn" Version="2.0.2-rc1-fb78016" />
</ItemGroup>
</Project>
</Project>

View File

@@ -66,7 +66,7 @@ If you are planning to contribute or just want to learn more about this project
- **Audio**
Audio output is entirely supported, audio input (microphone) isn't supported.
We use C# wrappers for [OpenAL](https://openal-soft.org/), and [SDL2](https://www.libsdl.org/) & [libsoundio](http://libsound.io/) as fallbacks.
We use C# wrappers for [OpenAL](https://openal-soft.org/), and [SDL3](https://www.libsdl.org/) & [libsoundio](http://libsound.io/) as fallbacks.
- **CPU**

View File

@@ -21,6 +21,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Graphics.GAL", "src
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Graphics.OpenGL", "src\Ryujinx.Graphics.OpenGL\Ryujinx.Graphics.OpenGL.csproj", "{9558FB96-075D-4219-8FFF-401979DC0B69}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ryujinx.Graphics.RenderDoc", "src\Ryujinx.Graphics.RenderDocApi\Ryujinx.Graphics.RenderDocApi.csproj", "{D58FA894-27D5-4EAA-9042-AD422AD82931}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Graphics.Texture", "src\Ryujinx.Graphics.Texture\Ryujinx.Graphics.Texture.csproj", "{E1B1AD28-289D-47B7-A106-326972240207}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Graphics.Shader", "src\Ryujinx.Graphics.Shader\Ryujinx.Graphics.Shader.csproj", "{03B955CD-AD84-4B93-AAA7-BF17923BBAA5}"
@@ -45,17 +47,17 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Graphics.Vic", "src
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Graphics.Video", "src\Ryujinx.Graphics.Video\Ryujinx.Graphics.Video.csproj", "{FD4A2C14-8E3D-4957-ABBE-3C38897B3E2D}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Audio.Backends.Apple", "src\Ryujinx.Audio.Backends.Apple\Ryujinx.Audio.Backends.Apple.csproj", "{AC26EFF0-8593-4184-9A09-98E37EFFB32E}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Audio.Backends.SDL3", "src\Ryujinx.Audio.Backends.SDL3\Ryujinx.Audio.Backends.SDL3.csproj", "{988E6191-82E1-4E13-9DDB-CB9FA2FDAF29}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Audio.Backends.OpenAL", "src\Ryujinx.Audio.Backends.OpenAL\Ryujinx.Audio.Backends.OpenAL.csproj", "{0BE11899-DF2D-4BDE-B9EE-2489E8D35E7D}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Audio.Backends.SoundIo", "src\Ryujinx.Audio.Backends.SoundIo\Ryujinx.Audio.Backends.SoundIo.csproj", "{716364DE-B988-41A6-BAB4-327964266ECC}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Input", "src\Ryujinx.Input\Ryujinx.Input.csproj", "{C16F112F-38C3-40BC-9F5F-4791112063D6}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Input.SDL2", "src\Ryujinx.Input.SDL2\Ryujinx.Input.SDL2.csproj", "{DFAB6F2D-B9BF-4AFF-B22B-7684A328EBA3}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.SDL2.Common", "src\Ryujinx.SDL2.Common\Ryujinx.SDL2.Common.csproj", "{2D5D3A1D-5730-4648-B0AB-06C53CB910C0}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Audio.Backends.SDL2", "src\Ryujinx.Audio.Backends.SDL2\Ryujinx.Audio.Backends.SDL2.csproj", "{D99A395A-8569-4DB0-B336-900647890052}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Input.SDL3", "src\Ryujinx.Input.SDL3\Ryujinx.Input.SDL3.csproj", "{D728444C-3D1F-4A0E-B4C9-5C9375D47EA3}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Graphics.Nvdec.FFmpeg", "src\Ryujinx.Graphics.Nvdec.FFmpeg\Ryujinx.Graphics.Nvdec.FFmpeg.csproj", "{BEE1C184-C9A4-410B-8DFC-FB74D5C93AEB}"
EndProject
@@ -79,12 +81,15 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.HLE.Generators", "s
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ryujinx.BuildValidationTasks", "src\Ryujinx.BuildValidationTasks\Ryujinx.BuildValidationTasks.csproj", "{4A89A234-4F19-497D-A576-DDE8CDFC5B22}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.SDL3.Common", "src\Ryujinx.SDL3.Common\Ryujinx.SDL3.Common.csproj", "{F6F9826A-BC58-4D78-A700-F358A66B2B06}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{36F870C1-3E5F-485F-B426-F0645AF78751}"
ProjectSection(SolutionItems) = preProject
.editorconfig = .editorconfig
.github\workflows\build.yml = .github\workflows\build.yml
.github\workflows\canary.yml = .github\workflows\canary.yml
Directory.Packages.props = Directory.Packages.props
Directory.Build.props = Directory.Build.props
.github\workflows\release.yml = .github\workflows\release.yml
nuget.config = nuget.config
EndProjectSection
@@ -92,164 +97,482 @@ EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Debug|x64 = Debug|x64
Debug|x86 = Debug|x86
Release|Any CPU = Release|Any CPU
Release|x64 = Release|x64
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{EBB55AEA-C7D7-4DEB-BF96-FA1789E225E9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{EBB55AEA-C7D7-4DEB-BF96-FA1789E225E9}.Debug|Any CPU.Build.0 = Debug|Any CPU
{EBB55AEA-C7D7-4DEB-BF96-FA1789E225E9}.Debug|x64.ActiveCfg = Debug|Any CPU
{EBB55AEA-C7D7-4DEB-BF96-FA1789E225E9}.Debug|x64.Build.0 = Debug|Any CPU
{EBB55AEA-C7D7-4DEB-BF96-FA1789E225E9}.Debug|x86.ActiveCfg = Debug|Any CPU
{EBB55AEA-C7D7-4DEB-BF96-FA1789E225E9}.Debug|x86.Build.0 = Debug|Any CPU
{EBB55AEA-C7D7-4DEB-BF96-FA1789E225E9}.Release|Any CPU.ActiveCfg = Release|Any CPU
{EBB55AEA-C7D7-4DEB-BF96-FA1789E225E9}.Release|Any CPU.Build.0 = Release|Any CPU
{EBB55AEA-C7D7-4DEB-BF96-FA1789E225E9}.Release|x64.ActiveCfg = Release|Any CPU
{EBB55AEA-C7D7-4DEB-BF96-FA1789E225E9}.Release|x64.Build.0 = Release|Any CPU
{EBB55AEA-C7D7-4DEB-BF96-FA1789E225E9}.Release|x86.ActiveCfg = Release|Any CPU
{EBB55AEA-C7D7-4DEB-BF96-FA1789E225E9}.Release|x86.Build.0 = Release|Any CPU
{D8F72938-78EF-4E8C-BAFE-531C9C3C8F15}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D8F72938-78EF-4E8C-BAFE-531C9C3C8F15}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D8F72938-78EF-4E8C-BAFE-531C9C3C8F15}.Debug|x64.ActiveCfg = Debug|Any CPU
{D8F72938-78EF-4E8C-BAFE-531C9C3C8F15}.Debug|x64.Build.0 = Debug|Any CPU
{D8F72938-78EF-4E8C-BAFE-531C9C3C8F15}.Debug|x86.ActiveCfg = Debug|Any CPU
{D8F72938-78EF-4E8C-BAFE-531C9C3C8F15}.Debug|x86.Build.0 = Debug|Any CPU
{D8F72938-78EF-4E8C-BAFE-531C9C3C8F15}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D8F72938-78EF-4E8C-BAFE-531C9C3C8F15}.Release|Any CPU.Build.0 = Release|Any CPU
{D8F72938-78EF-4E8C-BAFE-531C9C3C8F15}.Release|x64.ActiveCfg = Release|Any CPU
{D8F72938-78EF-4E8C-BAFE-531C9C3C8F15}.Release|x64.Build.0 = Release|Any CPU
{D8F72938-78EF-4E8C-BAFE-531C9C3C8F15}.Release|x86.ActiveCfg = Release|Any CPU
{D8F72938-78EF-4E8C-BAFE-531C9C3C8F15}.Release|x86.Build.0 = Release|Any CPU
{CB92CFF9-1D62-4D4F-9E88-8130EF61E351}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{CB92CFF9-1D62-4D4F-9E88-8130EF61E351}.Debug|Any CPU.Build.0 = Debug|Any CPU
{CB92CFF9-1D62-4D4F-9E88-8130EF61E351}.Debug|x64.ActiveCfg = Debug|Any CPU
{CB92CFF9-1D62-4D4F-9E88-8130EF61E351}.Debug|x64.Build.0 = Debug|Any CPU
{CB92CFF9-1D62-4D4F-9E88-8130EF61E351}.Debug|x86.ActiveCfg = Debug|Any CPU
{CB92CFF9-1D62-4D4F-9E88-8130EF61E351}.Debug|x86.Build.0 = Debug|Any CPU
{CB92CFF9-1D62-4D4F-9E88-8130EF61E351}.Release|Any CPU.ActiveCfg = Release|Any CPU
{CB92CFF9-1D62-4D4F-9E88-8130EF61E351}.Release|Any CPU.Build.0 = Release|Any CPU
{CB92CFF9-1D62-4D4F-9E88-8130EF61E351}.Release|x64.ActiveCfg = Release|Any CPU
{CB92CFF9-1D62-4D4F-9E88-8130EF61E351}.Release|x64.Build.0 = Release|Any CPU
{CB92CFF9-1D62-4D4F-9E88-8130EF61E351}.Release|x86.ActiveCfg = Release|Any CPU
{CB92CFF9-1D62-4D4F-9E88-8130EF61E351}.Release|x86.Build.0 = Release|Any CPU
{3AB294D0-2230-468F-9EB3-BDFCAEAE99A5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{3AB294D0-2230-468F-9EB3-BDFCAEAE99A5}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3AB294D0-2230-468F-9EB3-BDFCAEAE99A5}.Debug|x64.ActiveCfg = Debug|Any CPU
{3AB294D0-2230-468F-9EB3-BDFCAEAE99A5}.Debug|x64.Build.0 = Debug|Any CPU
{3AB294D0-2230-468F-9EB3-BDFCAEAE99A5}.Debug|x86.ActiveCfg = Debug|Any CPU
{3AB294D0-2230-468F-9EB3-BDFCAEAE99A5}.Debug|x86.Build.0 = Debug|Any CPU
{3AB294D0-2230-468F-9EB3-BDFCAEAE99A5}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3AB294D0-2230-468F-9EB3-BDFCAEAE99A5}.Release|Any CPU.Build.0 = Release|Any CPU
{3AB294D0-2230-468F-9EB3-BDFCAEAE99A5}.Release|x64.ActiveCfg = Release|Any CPU
{3AB294D0-2230-468F-9EB3-BDFCAEAE99A5}.Release|x64.Build.0 = Release|Any CPU
{3AB294D0-2230-468F-9EB3-BDFCAEAE99A5}.Release|x86.ActiveCfg = Release|Any CPU
{3AB294D0-2230-468F-9EB3-BDFCAEAE99A5}.Release|x86.Build.0 = Release|Any CPU
{5FD4E4F6-8928-4B3C-BE07-28A675C17226}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{5FD4E4F6-8928-4B3C-BE07-28A675C17226}.Debug|Any CPU.Build.0 = Debug|Any CPU
{5FD4E4F6-8928-4B3C-BE07-28A675C17226}.Debug|x64.ActiveCfg = Debug|Any CPU
{5FD4E4F6-8928-4B3C-BE07-28A675C17226}.Debug|x64.Build.0 = Debug|Any CPU
{5FD4E4F6-8928-4B3C-BE07-28A675C17226}.Debug|x86.ActiveCfg = Debug|Any CPU
{5FD4E4F6-8928-4B3C-BE07-28A675C17226}.Debug|x86.Build.0 = Debug|Any CPU
{5FD4E4F6-8928-4B3C-BE07-28A675C17226}.Release|Any CPU.ActiveCfg = Release|Any CPU
{5FD4E4F6-8928-4B3C-BE07-28A675C17226}.Release|Any CPU.Build.0 = Release|Any CPU
{5FD4E4F6-8928-4B3C-BE07-28A675C17226}.Release|x64.ActiveCfg = Release|Any CPU
{5FD4E4F6-8928-4B3C-BE07-28A675C17226}.Release|x64.Build.0 = Release|Any CPU
{5FD4E4F6-8928-4B3C-BE07-28A675C17226}.Release|x86.ActiveCfg = Release|Any CPU
{5FD4E4F6-8928-4B3C-BE07-28A675C17226}.Release|x86.Build.0 = Release|Any CPU
{ABF09A5E-2D8B-4B6F-A51D-5CE414DDB15A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{ABF09A5E-2D8B-4B6F-A51D-5CE414DDB15A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{ABF09A5E-2D8B-4B6F-A51D-5CE414DDB15A}.Debug|x64.ActiveCfg = Debug|Any CPU
{ABF09A5E-2D8B-4B6F-A51D-5CE414DDB15A}.Debug|x64.Build.0 = Debug|Any CPU
{ABF09A5E-2D8B-4B6F-A51D-5CE414DDB15A}.Debug|x86.ActiveCfg = Debug|Any CPU
{ABF09A5E-2D8B-4B6F-A51D-5CE414DDB15A}.Debug|x86.Build.0 = Debug|Any CPU
{ABF09A5E-2D8B-4B6F-A51D-5CE414DDB15A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{ABF09A5E-2D8B-4B6F-A51D-5CE414DDB15A}.Release|Any CPU.Build.0 = Release|Any CPU
{ABF09A5E-2D8B-4B6F-A51D-5CE414DDB15A}.Release|x64.ActiveCfg = Release|Any CPU
{ABF09A5E-2D8B-4B6F-A51D-5CE414DDB15A}.Release|x64.Build.0 = Release|Any CPU
{ABF09A5E-2D8B-4B6F-A51D-5CE414DDB15A}.Release|x86.ActiveCfg = Release|Any CPU
{ABF09A5E-2D8B-4B6F-A51D-5CE414DDB15A}.Release|x86.Build.0 = Release|Any CPU
{ADA7EA87-0D63-4D97-9433-922A2124401F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{ADA7EA87-0D63-4D97-9433-922A2124401F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{ADA7EA87-0D63-4D97-9433-922A2124401F}.Debug|x64.ActiveCfg = Debug|Any CPU
{ADA7EA87-0D63-4D97-9433-922A2124401F}.Debug|x64.Build.0 = Debug|Any CPU
{ADA7EA87-0D63-4D97-9433-922A2124401F}.Debug|x86.ActiveCfg = Debug|Any CPU
{ADA7EA87-0D63-4D97-9433-922A2124401F}.Debug|x86.Build.0 = Debug|Any CPU
{ADA7EA87-0D63-4D97-9433-922A2124401F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{ADA7EA87-0D63-4D97-9433-922A2124401F}.Release|Any CPU.Build.0 = Release|Any CPU
{ADA7EA87-0D63-4D97-9433-922A2124401F}.Release|x64.ActiveCfg = Release|Any CPU
{ADA7EA87-0D63-4D97-9433-922A2124401F}.Release|x64.Build.0 = Release|Any CPU
{ADA7EA87-0D63-4D97-9433-922A2124401F}.Release|x86.ActiveCfg = Release|Any CPU
{ADA7EA87-0D63-4D97-9433-922A2124401F}.Release|x86.Build.0 = Release|Any CPU
{A602AE97-91A5-4608-8DF1-EBF4ED7A0B9E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A602AE97-91A5-4608-8DF1-EBF4ED7A0B9E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A602AE97-91A5-4608-8DF1-EBF4ED7A0B9E}.Debug|x64.ActiveCfg = Debug|Any CPU
{A602AE97-91A5-4608-8DF1-EBF4ED7A0B9E}.Debug|x64.Build.0 = Debug|Any CPU
{A602AE97-91A5-4608-8DF1-EBF4ED7A0B9E}.Debug|x86.ActiveCfg = Debug|Any CPU
{A602AE97-91A5-4608-8DF1-EBF4ED7A0B9E}.Debug|x86.Build.0 = Debug|Any CPU
{A602AE97-91A5-4608-8DF1-EBF4ED7A0B9E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A602AE97-91A5-4608-8DF1-EBF4ED7A0B9E}.Release|Any CPU.Build.0 = Release|Any CPU
{A602AE97-91A5-4608-8DF1-EBF4ED7A0B9E}.Release|x64.ActiveCfg = Release|Any CPU
{A602AE97-91A5-4608-8DF1-EBF4ED7A0B9E}.Release|x64.Build.0 = Release|Any CPU
{A602AE97-91A5-4608-8DF1-EBF4ED7A0B9E}.Release|x86.ActiveCfg = Release|Any CPU
{A602AE97-91A5-4608-8DF1-EBF4ED7A0B9E}.Release|x86.Build.0 = Release|Any CPU
{9558FB96-075D-4219-8FFF-401979DC0B69}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{9558FB96-075D-4219-8FFF-401979DC0B69}.Debug|Any CPU.Build.0 = Debug|Any CPU
{9558FB96-075D-4219-8FFF-401979DC0B69}.Debug|x64.ActiveCfg = Debug|Any CPU
{9558FB96-075D-4219-8FFF-401979DC0B69}.Debug|x64.Build.0 = Debug|Any CPU
{9558FB96-075D-4219-8FFF-401979DC0B69}.Debug|x86.ActiveCfg = Debug|Any CPU
{9558FB96-075D-4219-8FFF-401979DC0B69}.Debug|x86.Build.0 = Debug|Any CPU
{9558FB96-075D-4219-8FFF-401979DC0B69}.Release|Any CPU.ActiveCfg = Release|Any CPU
{9558FB96-075D-4219-8FFF-401979DC0B69}.Release|Any CPU.Build.0 = Release|Any CPU
{9558FB96-075D-4219-8FFF-401979DC0B69}.Release|x64.ActiveCfg = Release|Any CPU
{9558FB96-075D-4219-8FFF-401979DC0B69}.Release|x64.Build.0 = Release|Any CPU
{9558FB96-075D-4219-8FFF-401979DC0B69}.Release|x86.ActiveCfg = Release|Any CPU
{9558FB96-075D-4219-8FFF-401979DC0B69}.Release|x86.Build.0 = Release|Any CPU
{E1B1AD28-289D-47B7-A106-326972240207}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E1B1AD28-289D-47B7-A106-326972240207}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E1B1AD28-289D-47B7-A106-326972240207}.Debug|x64.ActiveCfg = Debug|Any CPU
{E1B1AD28-289D-47B7-A106-326972240207}.Debug|x64.Build.0 = Debug|Any CPU
{E1B1AD28-289D-47B7-A106-326972240207}.Debug|x86.ActiveCfg = Debug|Any CPU
{E1B1AD28-289D-47B7-A106-326972240207}.Debug|x86.Build.0 = Debug|Any CPU
{E1B1AD28-289D-47B7-A106-326972240207}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E1B1AD28-289D-47B7-A106-326972240207}.Release|Any CPU.Build.0 = Release|Any CPU
{E1B1AD28-289D-47B7-A106-326972240207}.Release|x64.ActiveCfg = Release|Any CPU
{E1B1AD28-289D-47B7-A106-326972240207}.Release|x64.Build.0 = Release|Any CPU
{E1B1AD28-289D-47B7-A106-326972240207}.Release|x86.ActiveCfg = Release|Any CPU
{E1B1AD28-289D-47B7-A106-326972240207}.Release|x86.Build.0 = Release|Any CPU
{03B955CD-AD84-4B93-AAA7-BF17923BBAA5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{03B955CD-AD84-4B93-AAA7-BF17923BBAA5}.Debug|Any CPU.Build.0 = Debug|Any CPU
{03B955CD-AD84-4B93-AAA7-BF17923BBAA5}.Debug|x64.ActiveCfg = Debug|Any CPU
{03B955CD-AD84-4B93-AAA7-BF17923BBAA5}.Debug|x64.Build.0 = Debug|Any CPU
{03B955CD-AD84-4B93-AAA7-BF17923BBAA5}.Debug|x86.ActiveCfg = Debug|Any CPU
{03B955CD-AD84-4B93-AAA7-BF17923BBAA5}.Debug|x86.Build.0 = Debug|Any CPU
{03B955CD-AD84-4B93-AAA7-BF17923BBAA5}.Release|Any CPU.ActiveCfg = Release|Any CPU
{03B955CD-AD84-4B93-AAA7-BF17923BBAA5}.Release|Any CPU.Build.0 = Release|Any CPU
{03B955CD-AD84-4B93-AAA7-BF17923BBAA5}.Release|x64.ActiveCfg = Release|Any CPU
{03B955CD-AD84-4B93-AAA7-BF17923BBAA5}.Release|x64.Build.0 = Release|Any CPU
{03B955CD-AD84-4B93-AAA7-BF17923BBAA5}.Release|x86.ActiveCfg = Release|Any CPU
{03B955CD-AD84-4B93-AAA7-BF17923BBAA5}.Release|x86.Build.0 = Release|Any CPU
{85A0FA56-DC01-4A42-8808-70DAC76BD66D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{85A0FA56-DC01-4A42-8808-70DAC76BD66D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{85A0FA56-DC01-4A42-8808-70DAC76BD66D}.Debug|x64.ActiveCfg = Debug|Any CPU
{85A0FA56-DC01-4A42-8808-70DAC76BD66D}.Debug|x64.Build.0 = Debug|Any CPU
{85A0FA56-DC01-4A42-8808-70DAC76BD66D}.Debug|x86.ActiveCfg = Debug|Any CPU
{85A0FA56-DC01-4A42-8808-70DAC76BD66D}.Debug|x86.Build.0 = Debug|Any CPU
{85A0FA56-DC01-4A42-8808-70DAC76BD66D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{85A0FA56-DC01-4A42-8808-70DAC76BD66D}.Release|Any CPU.Build.0 = Release|Any CPU
{85A0FA56-DC01-4A42-8808-70DAC76BD66D}.Release|x64.ActiveCfg = Release|Any CPU
{85A0FA56-DC01-4A42-8808-70DAC76BD66D}.Release|x64.Build.0 = Release|Any CPU
{85A0FA56-DC01-4A42-8808-70DAC76BD66D}.Release|x86.ActiveCfg = Release|Any CPU
{85A0FA56-DC01-4A42-8808-70DAC76BD66D}.Release|x86.Build.0 = Release|Any CPU
{806ACF6D-90B0-45D0-A1AC-5F220F3B3985}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{806ACF6D-90B0-45D0-A1AC-5F220F3B3985}.Debug|Any CPU.Build.0 = Debug|Any CPU
{806ACF6D-90B0-45D0-A1AC-5F220F3B3985}.Debug|x64.ActiveCfg = Debug|Any CPU
{806ACF6D-90B0-45D0-A1AC-5F220F3B3985}.Debug|x64.Build.0 = Debug|Any CPU
{806ACF6D-90B0-45D0-A1AC-5F220F3B3985}.Debug|x86.ActiveCfg = Debug|Any CPU
{806ACF6D-90B0-45D0-A1AC-5F220F3B3985}.Debug|x86.Build.0 = Debug|Any CPU
{806ACF6D-90B0-45D0-A1AC-5F220F3B3985}.Release|Any CPU.ActiveCfg = Release|Any CPU
{806ACF6D-90B0-45D0-A1AC-5F220F3B3985}.Release|Any CPU.Build.0 = Release|Any CPU
{806ACF6D-90B0-45D0-A1AC-5F220F3B3985}.Release|x64.ActiveCfg = Release|Any CPU
{806ACF6D-90B0-45D0-A1AC-5F220F3B3985}.Release|x64.Build.0 = Release|Any CPU
{806ACF6D-90B0-45D0-A1AC-5F220F3B3985}.Release|x86.ActiveCfg = Release|Any CPU
{806ACF6D-90B0-45D0-A1AC-5F220F3B3985}.Release|x86.Build.0 = Release|Any CPU
{A5E6C691-9E22-4263-8F40-42F002CE66BE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A5E6C691-9E22-4263-8F40-42F002CE66BE}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A5E6C691-9E22-4263-8F40-42F002CE66BE}.Debug|x64.ActiveCfg = Debug|Any CPU
{A5E6C691-9E22-4263-8F40-42F002CE66BE}.Debug|x64.Build.0 = Debug|Any CPU
{A5E6C691-9E22-4263-8F40-42F002CE66BE}.Debug|x86.ActiveCfg = Debug|Any CPU
{A5E6C691-9E22-4263-8F40-42F002CE66BE}.Debug|x86.Build.0 = Debug|Any CPU
{A5E6C691-9E22-4263-8F40-42F002CE66BE}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A5E6C691-9E22-4263-8F40-42F002CE66BE}.Release|Any CPU.Build.0 = Release|Any CPU
{A5E6C691-9E22-4263-8F40-42F002CE66BE}.Release|x64.ActiveCfg = Release|Any CPU
{A5E6C691-9E22-4263-8F40-42F002CE66BE}.Release|x64.Build.0 = Release|Any CPU
{A5E6C691-9E22-4263-8F40-42F002CE66BE}.Release|x86.ActiveCfg = Release|Any CPU
{A5E6C691-9E22-4263-8F40-42F002CE66BE}.Release|x86.Build.0 = Release|Any CPU
{D1CC5322-7325-4F6B-9625-194B30BE1296}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D1CC5322-7325-4F6B-9625-194B30BE1296}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D1CC5322-7325-4F6B-9625-194B30BE1296}.Debug|x64.ActiveCfg = Debug|Any CPU
{D1CC5322-7325-4F6B-9625-194B30BE1296}.Debug|x64.Build.0 = Debug|Any CPU
{D1CC5322-7325-4F6B-9625-194B30BE1296}.Debug|x86.ActiveCfg = Debug|Any CPU
{D1CC5322-7325-4F6B-9625-194B30BE1296}.Debug|x86.Build.0 = Debug|Any CPU
{D1CC5322-7325-4F6B-9625-194B30BE1296}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D1CC5322-7325-4F6B-9625-194B30BE1296}.Release|Any CPU.Build.0 = Release|Any CPU
{D1CC5322-7325-4F6B-9625-194B30BE1296}.Release|x64.ActiveCfg = Release|Any CPU
{D1CC5322-7325-4F6B-9625-194B30BE1296}.Release|x64.Build.0 = Release|Any CPU
{D1CC5322-7325-4F6B-9625-194B30BE1296}.Release|x86.ActiveCfg = Release|Any CPU
{D1CC5322-7325-4F6B-9625-194B30BE1296}.Release|x86.Build.0 = Release|Any CPU
{3DF35E3D-D844-4399-A9A1-A9E923264C17}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{3DF35E3D-D844-4399-A9A1-A9E923264C17}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3DF35E3D-D844-4399-A9A1-A9E923264C17}.Debug|x64.ActiveCfg = Debug|Any CPU
{3DF35E3D-D844-4399-A9A1-A9E923264C17}.Debug|x64.Build.0 = Debug|Any CPU
{3DF35E3D-D844-4399-A9A1-A9E923264C17}.Debug|x86.ActiveCfg = Debug|Any CPU
{3DF35E3D-D844-4399-A9A1-A9E923264C17}.Debug|x86.Build.0 = Debug|Any CPU
{3DF35E3D-D844-4399-A9A1-A9E923264C17}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3DF35E3D-D844-4399-A9A1-A9E923264C17}.Release|Any CPU.Build.0 = Release|Any CPU
{3DF35E3D-D844-4399-A9A1-A9E923264C17}.Release|x64.ActiveCfg = Release|Any CPU
{3DF35E3D-D844-4399-A9A1-A9E923264C17}.Release|x64.Build.0 = Release|Any CPU
{3DF35E3D-D844-4399-A9A1-A9E923264C17}.Release|x86.ActiveCfg = Release|Any CPU
{3DF35E3D-D844-4399-A9A1-A9E923264C17}.Release|x86.Build.0 = Release|Any CPU
{C3002C3C-7B09-4FE7-894A-372EDA22FC6E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C3002C3C-7B09-4FE7-894A-372EDA22FC6E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C3002C3C-7B09-4FE7-894A-372EDA22FC6E}.Debug|x64.ActiveCfg = Debug|Any CPU
{C3002C3C-7B09-4FE7-894A-372EDA22FC6E}.Debug|x64.Build.0 = Debug|Any CPU
{C3002C3C-7B09-4FE7-894A-372EDA22FC6E}.Debug|x86.ActiveCfg = Debug|Any CPU
{C3002C3C-7B09-4FE7-894A-372EDA22FC6E}.Debug|x86.Build.0 = Debug|Any CPU
{C3002C3C-7B09-4FE7-894A-372EDA22FC6E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C3002C3C-7B09-4FE7-894A-372EDA22FC6E}.Release|Any CPU.Build.0 = Release|Any CPU
{C3002C3C-7B09-4FE7-894A-372EDA22FC6E}.Release|x64.ActiveCfg = Release|Any CPU
{C3002C3C-7B09-4FE7-894A-372EDA22FC6E}.Release|x64.Build.0 = Release|Any CPU
{C3002C3C-7B09-4FE7-894A-372EDA22FC6E}.Release|x86.ActiveCfg = Release|Any CPU
{C3002C3C-7B09-4FE7-894A-372EDA22FC6E}.Release|x86.Build.0 = Release|Any CPU
{C35F1536-7DE5-4F9D-9604-B5B4E1561947}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C35F1536-7DE5-4F9D-9604-B5B4E1561947}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C35F1536-7DE5-4F9D-9604-B5B4E1561947}.Debug|x64.ActiveCfg = Debug|Any CPU
{C35F1536-7DE5-4F9D-9604-B5B4E1561947}.Debug|x64.Build.0 = Debug|Any CPU
{C35F1536-7DE5-4F9D-9604-B5B4E1561947}.Debug|x86.ActiveCfg = Debug|Any CPU
{C35F1536-7DE5-4F9D-9604-B5B4E1561947}.Debug|x86.Build.0 = Debug|Any CPU
{C35F1536-7DE5-4F9D-9604-B5B4E1561947}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C35F1536-7DE5-4F9D-9604-B5B4E1561947}.Release|Any CPU.Build.0 = Release|Any CPU
{C35F1536-7DE5-4F9D-9604-B5B4E1561947}.Release|x64.ActiveCfg = Release|Any CPU
{C35F1536-7DE5-4F9D-9604-B5B4E1561947}.Release|x64.Build.0 = Release|Any CPU
{C35F1536-7DE5-4F9D-9604-B5B4E1561947}.Release|x86.ActiveCfg = Release|Any CPU
{C35F1536-7DE5-4F9D-9604-B5B4E1561947}.Release|x86.Build.0 = Release|Any CPU
{B9AECA11-E248-4886-A10B-81B631CAAF29}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B9AECA11-E248-4886-A10B-81B631CAAF29}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B9AECA11-E248-4886-A10B-81B631CAAF29}.Debug|x64.ActiveCfg = Debug|Any CPU
{B9AECA11-E248-4886-A10B-81B631CAAF29}.Debug|x64.Build.0 = Debug|Any CPU
{B9AECA11-E248-4886-A10B-81B631CAAF29}.Debug|x86.ActiveCfg = Debug|Any CPU
{B9AECA11-E248-4886-A10B-81B631CAAF29}.Debug|x86.Build.0 = Debug|Any CPU
{B9AECA11-E248-4886-A10B-81B631CAAF29}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B9AECA11-E248-4886-A10B-81B631CAAF29}.Release|Any CPU.Build.0 = Release|Any CPU
{B9AECA11-E248-4886-A10B-81B631CAAF29}.Release|x64.ActiveCfg = Release|Any CPU
{B9AECA11-E248-4886-A10B-81B631CAAF29}.Release|x64.Build.0 = Release|Any CPU
{B9AECA11-E248-4886-A10B-81B631CAAF29}.Release|x86.ActiveCfg = Release|Any CPU
{B9AECA11-E248-4886-A10B-81B631CAAF29}.Release|x86.Build.0 = Release|Any CPU
{81BB2C11-9408-4EA3-822E-42987AF54429}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{81BB2C11-9408-4EA3-822E-42987AF54429}.Debug|Any CPU.Build.0 = Debug|Any CPU
{81BB2C11-9408-4EA3-822E-42987AF54429}.Debug|x64.ActiveCfg = Debug|Any CPU
{81BB2C11-9408-4EA3-822E-42987AF54429}.Debug|x64.Build.0 = Debug|Any CPU
{81BB2C11-9408-4EA3-822E-42987AF54429}.Debug|x86.ActiveCfg = Debug|Any CPU
{81BB2C11-9408-4EA3-822E-42987AF54429}.Debug|x86.Build.0 = Debug|Any CPU
{81BB2C11-9408-4EA3-822E-42987AF54429}.Release|Any CPU.ActiveCfg = Release|Any CPU
{81BB2C11-9408-4EA3-822E-42987AF54429}.Release|Any CPU.Build.0 = Release|Any CPU
{81BB2C11-9408-4EA3-822E-42987AF54429}.Release|x64.ActiveCfg = Release|Any CPU
{81BB2C11-9408-4EA3-822E-42987AF54429}.Release|x64.Build.0 = Release|Any CPU
{81BB2C11-9408-4EA3-822E-42987AF54429}.Release|x86.ActiveCfg = Release|Any CPU
{81BB2C11-9408-4EA3-822E-42987AF54429}.Release|x86.Build.0 = Release|Any CPU
{FD4A2C14-8E3D-4957-ABBE-3C38897B3E2D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{FD4A2C14-8E3D-4957-ABBE-3C38897B3E2D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{FD4A2C14-8E3D-4957-ABBE-3C38897B3E2D}.Debug|x64.ActiveCfg = Debug|Any CPU
{FD4A2C14-8E3D-4957-ABBE-3C38897B3E2D}.Debug|x64.Build.0 = Debug|Any CPU
{FD4A2C14-8E3D-4957-ABBE-3C38897B3E2D}.Debug|x86.ActiveCfg = Debug|Any CPU
{FD4A2C14-8E3D-4957-ABBE-3C38897B3E2D}.Debug|x86.Build.0 = Debug|Any CPU
{FD4A2C14-8E3D-4957-ABBE-3C38897B3E2D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{FD4A2C14-8E3D-4957-ABBE-3C38897B3E2D}.Release|Any CPU.Build.0 = Release|Any CPU
{FD4A2C14-8E3D-4957-ABBE-3C38897B3E2D}.Release|x64.ActiveCfg = Release|Any CPU
{FD4A2C14-8E3D-4957-ABBE-3C38897B3E2D}.Release|x64.Build.0 = Release|Any CPU
{FD4A2C14-8E3D-4957-ABBE-3C38897B3E2D}.Release|x86.ActiveCfg = Release|Any CPU
{FD4A2C14-8E3D-4957-ABBE-3C38897B3E2D}.Release|x86.Build.0 = Release|Any CPU
{0BE11899-DF2D-4BDE-B9EE-2489E8D35E7D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{0BE11899-DF2D-4BDE-B9EE-2489E8D35E7D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{0BE11899-DF2D-4BDE-B9EE-2489E8D35E7D}.Debug|x64.ActiveCfg = Debug|Any CPU
{0BE11899-DF2D-4BDE-B9EE-2489E8D35E7D}.Debug|x64.Build.0 = Debug|Any CPU
{0BE11899-DF2D-4BDE-B9EE-2489E8D35E7D}.Debug|x86.ActiveCfg = Debug|Any CPU
{0BE11899-DF2D-4BDE-B9EE-2489E8D35E7D}.Debug|x86.Build.0 = Debug|Any CPU
{0BE11899-DF2D-4BDE-B9EE-2489E8D35E7D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{0BE11899-DF2D-4BDE-B9EE-2489E8D35E7D}.Release|Any CPU.Build.0 = Release|Any CPU
{0BE11899-DF2D-4BDE-B9EE-2489E8D35E7D}.Release|x64.ActiveCfg = Release|Any CPU
{0BE11899-DF2D-4BDE-B9EE-2489E8D35E7D}.Release|x64.Build.0 = Release|Any CPU
{0BE11899-DF2D-4BDE-B9EE-2489E8D35E7D}.Release|x86.ActiveCfg = Release|Any CPU
{0BE11899-DF2D-4BDE-B9EE-2489E8D35E7D}.Release|x86.Build.0 = Release|Any CPU
{716364DE-B988-41A6-BAB4-327964266ECC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{716364DE-B988-41A6-BAB4-327964266ECC}.Debug|Any CPU.Build.0 = Debug|Any CPU
{716364DE-B988-41A6-BAB4-327964266ECC}.Debug|x64.ActiveCfg = Debug|Any CPU
{716364DE-B988-41A6-BAB4-327964266ECC}.Debug|x64.Build.0 = Debug|Any CPU
{716364DE-B988-41A6-BAB4-327964266ECC}.Debug|x86.ActiveCfg = Debug|Any CPU
{716364DE-B988-41A6-BAB4-327964266ECC}.Debug|x86.Build.0 = Debug|Any CPU
{716364DE-B988-41A6-BAB4-327964266ECC}.Release|Any CPU.ActiveCfg = Release|Any CPU
{716364DE-B988-41A6-BAB4-327964266ECC}.Release|Any CPU.Build.0 = Release|Any CPU
{716364DE-B988-41A6-BAB4-327964266ECC}.Release|x64.ActiveCfg = Release|Any CPU
{716364DE-B988-41A6-BAB4-327964266ECC}.Release|x64.Build.0 = Release|Any CPU
{716364DE-B988-41A6-BAB4-327964266ECC}.Release|x86.ActiveCfg = Release|Any CPU
{716364DE-B988-41A6-BAB4-327964266ECC}.Release|x86.Build.0 = Release|Any CPU
{C16F112F-38C3-40BC-9F5F-4791112063D6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C16F112F-38C3-40BC-9F5F-4791112063D6}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C16F112F-38C3-40BC-9F5F-4791112063D6}.Debug|x64.ActiveCfg = Debug|Any CPU
{C16F112F-38C3-40BC-9F5F-4791112063D6}.Debug|x64.Build.0 = Debug|Any CPU
{C16F112F-38C3-40BC-9F5F-4791112063D6}.Debug|x86.ActiveCfg = Debug|Any CPU
{C16F112F-38C3-40BC-9F5F-4791112063D6}.Debug|x86.Build.0 = Debug|Any CPU
{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
{C16F112F-38C3-40BC-9F5F-4791112063D6}.Release|x64.ActiveCfg = Release|Any CPU
{C16F112F-38C3-40BC-9F5F-4791112063D6}.Release|x64.Build.0 = Release|Any CPU
{C16F112F-38C3-40BC-9F5F-4791112063D6}.Release|x86.ActiveCfg = Release|Any CPU
{C16F112F-38C3-40BC-9F5F-4791112063D6}.Release|x86.Build.0 = Release|Any CPU
{BEE1C184-C9A4-410B-8DFC-FB74D5C93AEB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{BEE1C184-C9A4-410B-8DFC-FB74D5C93AEB}.Debug|Any CPU.Build.0 = Debug|Any CPU
{BEE1C184-C9A4-410B-8DFC-FB74D5C93AEB}.Debug|x64.ActiveCfg = Debug|Any CPU
{BEE1C184-C9A4-410B-8DFC-FB74D5C93AEB}.Debug|x64.Build.0 = Debug|Any CPU
{BEE1C184-C9A4-410B-8DFC-FB74D5C93AEB}.Debug|x86.ActiveCfg = Debug|Any CPU
{BEE1C184-C9A4-410B-8DFC-FB74D5C93AEB}.Debug|x86.Build.0 = Debug|Any CPU
{BEE1C184-C9A4-410B-8DFC-FB74D5C93AEB}.Release|Any CPU.ActiveCfg = Release|Any CPU
{BEE1C184-C9A4-410B-8DFC-FB74D5C93AEB}.Release|Any CPU.Build.0 = Release|Any CPU
{BEE1C184-C9A4-410B-8DFC-FB74D5C93AEB}.Release|x64.ActiveCfg = Release|Any CPU
{BEE1C184-C9A4-410B-8DFC-FB74D5C93AEB}.Release|x64.Build.0 = Release|Any CPU
{BEE1C184-C9A4-410B-8DFC-FB74D5C93AEB}.Release|x86.ActiveCfg = Release|Any CPU
{BEE1C184-C9A4-410B-8DFC-FB74D5C93AEB}.Release|x86.Build.0 = Release|Any CPU
{7C1B2721-13DA-4B62-B046-C626605ECCE6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{7C1B2721-13DA-4B62-B046-C626605ECCE6}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7C1B2721-13DA-4B62-B046-C626605ECCE6}.Debug|x64.ActiveCfg = Debug|Any CPU
{7C1B2721-13DA-4B62-B046-C626605ECCE6}.Debug|x64.Build.0 = Debug|Any CPU
{7C1B2721-13DA-4B62-B046-C626605ECCE6}.Debug|x86.ActiveCfg = Debug|Any CPU
{7C1B2721-13DA-4B62-B046-C626605ECCE6}.Debug|x86.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
{7C1B2721-13DA-4B62-B046-C626605ECCE6}.Release|x64.ActiveCfg = Release|Any CPU
{7C1B2721-13DA-4B62-B046-C626605ECCE6}.Release|x64.Build.0 = Release|Any CPU
{7C1B2721-13DA-4B62-B046-C626605ECCE6}.Release|x86.ActiveCfg = Release|Any CPU
{7C1B2721-13DA-4B62-B046-C626605ECCE6}.Release|x86.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}.Debug|x64.ActiveCfg = Debug|Any CPU
{6AE2A5E8-4C5A-48B9-997B-E1455C0355C6}.Debug|x64.Build.0 = Debug|Any CPU
{6AE2A5E8-4C5A-48B9-997B-E1455C0355C6}.Debug|x86.ActiveCfg = Debug|Any CPU
{6AE2A5E8-4C5A-48B9-997B-E1455C0355C6}.Debug|x86.Build.0 = Debug|Any CPU
{6AE2A5E8-4C5A-48B9-997B-E1455C0355C6}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6AE2A5E8-4C5A-48B9-997B-E1455C0355C6}.Release|Any CPU.Build.0 = Release|Any CPU
{6AE2A5E8-4C5A-48B9-997B-E1455C0355C6}.Release|x64.ActiveCfg = Release|Any CPU
{6AE2A5E8-4C5A-48B9-997B-E1455C0355C6}.Release|x64.Build.0 = Release|Any CPU
{6AE2A5E8-4C5A-48B9-997B-E1455C0355C6}.Release|x86.ActiveCfg = Release|Any CPU
{6AE2A5E8-4C5A-48B9-997B-E1455C0355C6}.Release|x86.Build.0 = Release|Any CPU
{D4D09B08-D580-4D69-B886-C35D2853F6C8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D4D09B08-D580-4D69-B886-C35D2853F6C8}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D4D09B08-D580-4D69-B886-C35D2853F6C8}.Debug|x64.ActiveCfg = Debug|Any CPU
{D4D09B08-D580-4D69-B886-C35D2853F6C8}.Debug|x64.Build.0 = Debug|Any CPU
{D4D09B08-D580-4D69-B886-C35D2853F6C8}.Debug|x86.ActiveCfg = Debug|Any CPU
{D4D09B08-D580-4D69-B886-C35D2853F6C8}.Debug|x86.Build.0 = Debug|Any CPU
{D4D09B08-D580-4D69-B886-C35D2853F6C8}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D4D09B08-D580-4D69-B886-C35D2853F6C8}.Release|Any CPU.Build.0 = Release|Any CPU
{D4D09B08-D580-4D69-B886-C35D2853F6C8}.Release|x64.ActiveCfg = Release|Any CPU
{D4D09B08-D580-4D69-B886-C35D2853F6C8}.Release|x64.Build.0 = Release|Any CPU
{D4D09B08-D580-4D69-B886-C35D2853F6C8}.Release|x86.ActiveCfg = Release|Any CPU
{D4D09B08-D580-4D69-B886-C35D2853F6C8}.Release|x86.Build.0 = Release|Any CPU
{2BCB3D7A-38C0-4FE7-8FDA-374C6AD56D0E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{2BCB3D7A-38C0-4FE7-8FDA-374C6AD56D0E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{2BCB3D7A-38C0-4FE7-8FDA-374C6AD56D0E}.Debug|x64.ActiveCfg = Debug|Any CPU
{2BCB3D7A-38C0-4FE7-8FDA-374C6AD56D0E}.Debug|x64.Build.0 = Debug|Any CPU
{2BCB3D7A-38C0-4FE7-8FDA-374C6AD56D0E}.Debug|x86.ActiveCfg = Debug|Any CPU
{2BCB3D7A-38C0-4FE7-8FDA-374C6AD56D0E}.Debug|x86.Build.0 = Debug|Any CPU
{2BCB3D7A-38C0-4FE7-8FDA-374C6AD56D0E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2BCB3D7A-38C0-4FE7-8FDA-374C6AD56D0E}.Release|Any CPU.Build.0 = Release|Any CPU
{2BCB3D7A-38C0-4FE7-8FDA-374C6AD56D0E}.Release|x64.ActiveCfg = Release|Any CPU
{2BCB3D7A-38C0-4FE7-8FDA-374C6AD56D0E}.Release|x64.Build.0 = Release|Any CPU
{2BCB3D7A-38C0-4FE7-8FDA-374C6AD56D0E}.Release|x86.ActiveCfg = Release|Any CPU
{2BCB3D7A-38C0-4FE7-8FDA-374C6AD56D0E}.Release|x86.Build.0 = Release|Any CPU
{77D01AD9-2C98-478E-AE1D-8F7100738FB4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{77D01AD9-2C98-478E-AE1D-8F7100738FB4}.Debug|Any CPU.Build.0 = Debug|Any CPU
{77D01AD9-2C98-478E-AE1D-8F7100738FB4}.Debug|x64.ActiveCfg = Debug|Any CPU
{77D01AD9-2C98-478E-AE1D-8F7100738FB4}.Debug|x64.Build.0 = Debug|Any CPU
{77D01AD9-2C98-478E-AE1D-8F7100738FB4}.Debug|x86.ActiveCfg = Debug|Any CPU
{77D01AD9-2C98-478E-AE1D-8F7100738FB4}.Debug|x86.Build.0 = Debug|Any CPU
{77D01AD9-2C98-478E-AE1D-8F7100738FB4}.Release|Any CPU.ActiveCfg = Release|Any CPU
{77D01AD9-2C98-478E-AE1D-8F7100738FB4}.Release|Any CPU.Build.0 = Release|Any CPU
{77D01AD9-2C98-478E-AE1D-8F7100738FB4}.Release|x64.ActiveCfg = Release|Any CPU
{77D01AD9-2C98-478E-AE1D-8F7100738FB4}.Release|x64.Build.0 = Release|Any CPU
{77D01AD9-2C98-478E-AE1D-8F7100738FB4}.Release|x86.ActiveCfg = Release|Any CPU
{77D01AD9-2C98-478E-AE1D-8F7100738FB4}.Release|x86.Build.0 = Release|Any CPU
{77F96ECE-4952-42DB-A528-DED25572A573}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{77F96ECE-4952-42DB-A528-DED25572A573}.Debug|Any CPU.Build.0 = Debug|Any CPU
{77F96ECE-4952-42DB-A528-DED25572A573}.Debug|x64.ActiveCfg = Debug|Any CPU
{77F96ECE-4952-42DB-A528-DED25572A573}.Debug|x64.Build.0 = Debug|Any CPU
{77F96ECE-4952-42DB-A528-DED25572A573}.Debug|x86.ActiveCfg = Debug|Any CPU
{77F96ECE-4952-42DB-A528-DED25572A573}.Debug|x86.Build.0 = Debug|Any CPU
{77F96ECE-4952-42DB-A528-DED25572A573}.Release|Any CPU.ActiveCfg = Release|Any CPU
{77F96ECE-4952-42DB-A528-DED25572A573}.Release|Any CPU.Build.0 = Release|Any CPU
{77F96ECE-4952-42DB-A528-DED25572A573}.Release|x64.ActiveCfg = Release|Any CPU
{77F96ECE-4952-42DB-A528-DED25572A573}.Release|x64.Build.0 = Release|Any CPU
{77F96ECE-4952-42DB-A528-DED25572A573}.Release|x86.ActiveCfg = Release|Any CPU
{77F96ECE-4952-42DB-A528-DED25572A573}.Release|x86.Build.0 = Release|Any CPU
{AF34127A-3A92-43E5-8496-14960A50B1F1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{AF34127A-3A92-43E5-8496-14960A50B1F1}.Debug|Any CPU.Build.0 = Debug|Any CPU
{AF34127A-3A92-43E5-8496-14960A50B1F1}.Debug|x64.ActiveCfg = Debug|Any CPU
{AF34127A-3A92-43E5-8496-14960A50B1F1}.Debug|x64.Build.0 = Debug|Any CPU
{AF34127A-3A92-43E5-8496-14960A50B1F1}.Debug|x86.ActiveCfg = Debug|Any CPU
{AF34127A-3A92-43E5-8496-14960A50B1F1}.Debug|x86.Build.0 = Debug|Any CPU
{AF34127A-3A92-43E5-8496-14960A50B1F1}.Release|Any CPU.ActiveCfg = Release|Any CPU
{AF34127A-3A92-43E5-8496-14960A50B1F1}.Release|Any CPU.Build.0 = Release|Any CPU
{AF34127A-3A92-43E5-8496-14960A50B1F1}.Release|x64.ActiveCfg = Release|Any CPU
{AF34127A-3A92-43E5-8496-14960A50B1F1}.Release|x64.Build.0 = Release|Any CPU
{AF34127A-3A92-43E5-8496-14960A50B1F1}.Release|x86.ActiveCfg = Release|Any CPU
{AF34127A-3A92-43E5-8496-14960A50B1F1}.Release|x86.Build.0 = Release|Any CPU
{7F55A45D-4E1D-4A36-ADD3-87F29A285AA2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{7F55A45D-4E1D-4A36-ADD3-87F29A285AA2}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7F55A45D-4E1D-4A36-ADD3-87F29A285AA2}.Debug|x64.ActiveCfg = Debug|Any CPU
{7F55A45D-4E1D-4A36-ADD3-87F29A285AA2}.Debug|x64.Build.0 = Debug|Any CPU
{7F55A45D-4E1D-4A36-ADD3-87F29A285AA2}.Debug|x86.ActiveCfg = Debug|Any CPU
{7F55A45D-4E1D-4A36-ADD3-87F29A285AA2}.Debug|x86.Build.0 = Debug|Any CPU
{7F55A45D-4E1D-4A36-ADD3-87F29A285AA2}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7F55A45D-4E1D-4A36-ADD3-87F29A285AA2}.Release|Any CPU.Build.0 = Release|Any CPU
{7F55A45D-4E1D-4A36-ADD3-87F29A285AA2}.Release|x64.ActiveCfg = Release|Any CPU
{7F55A45D-4E1D-4A36-ADD3-87F29A285AA2}.Release|x64.Build.0 = Release|Any CPU
{7F55A45D-4E1D-4A36-ADD3-87F29A285AA2}.Release|x86.ActiveCfg = Release|Any CPU
{7F55A45D-4E1D-4A36-ADD3-87F29A285AA2}.Release|x86.Build.0 = Release|Any CPU
{B575BCDE-2FD8-4A5D-8756-31CDD7FE81F0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B575BCDE-2FD8-4A5D-8756-31CDD7FE81F0}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B575BCDE-2FD8-4A5D-8756-31CDD7FE81F0}.Debug|x64.ActiveCfg = Debug|Any CPU
{B575BCDE-2FD8-4A5D-8756-31CDD7FE81F0}.Debug|x64.Build.0 = Debug|Any CPU
{B575BCDE-2FD8-4A5D-8756-31CDD7FE81F0}.Debug|x86.ActiveCfg = Debug|Any CPU
{B575BCDE-2FD8-4A5D-8756-31CDD7FE81F0}.Debug|x86.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
{B575BCDE-2FD8-4A5D-8756-31CDD7FE81F0}.Release|x64.ActiveCfg = Release|Any CPU
{B575BCDE-2FD8-4A5D-8756-31CDD7FE81F0}.Release|x64.Build.0 = Release|Any CPU
{B575BCDE-2FD8-4A5D-8756-31CDD7FE81F0}.Release|x86.ActiveCfg = Release|Any CPU
{B575BCDE-2FD8-4A5D-8756-31CDD7FE81F0}.Release|x86.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}.Debug|x64.ActiveCfg = Debug|Any CPU
{4A89A234-4F19-497D-A576-DDE8CDFC5B22}.Debug|x64.Build.0 = Debug|Any CPU
{4A89A234-4F19-497D-A576-DDE8CDFC5B22}.Debug|x86.ActiveCfg = Debug|Any CPU
{4A89A234-4F19-497D-A576-DDE8CDFC5B22}.Debug|x86.Build.0 = Debug|Any CPU
{4A89A234-4F19-497D-A576-DDE8CDFC5B22}.Release|Any CPU.ActiveCfg = Release|Any CPU
{4A89A234-4F19-497D-A576-DDE8CDFC5B22}.Release|x64.ActiveCfg = Release|Any CPU
{4A89A234-4F19-497D-A576-DDE8CDFC5B22}.Release|x64.Build.0 = Release|Any CPU
{4A89A234-4F19-497D-A576-DDE8CDFC5B22}.Release|x86.ActiveCfg = Release|Any CPU
{4A89A234-4F19-497D-A576-DDE8CDFC5B22}.Release|x86.Build.0 = Release|Any CPU
{F6F9826A-BC58-4D78-A700-F358A66B2B06}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{F6F9826A-BC58-4D78-A700-F358A66B2B06}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F6F9826A-BC58-4D78-A700-F358A66B2B06}.Debug|x64.ActiveCfg = Debug|Any CPU
{F6F9826A-BC58-4D78-A700-F358A66B2B06}.Debug|x64.Build.0 = Debug|Any CPU
{F6F9826A-BC58-4D78-A700-F358A66B2B06}.Debug|x86.ActiveCfg = Debug|Any CPU
{F6F9826A-BC58-4D78-A700-F358A66B2B06}.Debug|x86.Build.0 = Debug|Any CPU
{F6F9826A-BC58-4D78-A700-F358A66B2B06}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F6F9826A-BC58-4D78-A700-F358A66B2B06}.Release|Any CPU.Build.0 = Release|Any CPU
{F6F9826A-BC58-4D78-A700-F358A66B2B06}.Release|x64.ActiveCfg = Release|Any CPU
{F6F9826A-BC58-4D78-A700-F358A66B2B06}.Release|x64.Build.0 = Release|Any CPU
{F6F9826A-BC58-4D78-A700-F358A66B2B06}.Release|x86.ActiveCfg = Release|Any CPU
{F6F9826A-BC58-4D78-A700-F358A66B2B06}.Release|x86.Build.0 = Release|Any CPU
{D728444C-3D1F-4A0E-B4C9-5C9375D47EA3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D728444C-3D1F-4A0E-B4C9-5C9375D47EA3}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D728444C-3D1F-4A0E-B4C9-5C9375D47EA3}.Debug|x64.ActiveCfg = Debug|Any CPU
{D728444C-3D1F-4A0E-B4C9-5C9375D47EA3}.Debug|x64.Build.0 = Debug|Any CPU
{D728444C-3D1F-4A0E-B4C9-5C9375D47EA3}.Debug|x86.ActiveCfg = Debug|Any CPU
{D728444C-3D1F-4A0E-B4C9-5C9375D47EA3}.Debug|x86.Build.0 = Debug|Any CPU
{D728444C-3D1F-4A0E-B4C9-5C9375D47EA3}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D728444C-3D1F-4A0E-B4C9-5C9375D47EA3}.Release|Any CPU.Build.0 = Release|Any CPU
{D728444C-3D1F-4A0E-B4C9-5C9375D47EA3}.Release|x64.ActiveCfg = Release|Any CPU
{D728444C-3D1F-4A0E-B4C9-5C9375D47EA3}.Release|x64.Build.0 = Release|Any CPU
{D728444C-3D1F-4A0E-B4C9-5C9375D47EA3}.Release|x86.ActiveCfg = Release|Any CPU
{D728444C-3D1F-4A0E-B4C9-5C9375D47EA3}.Release|x86.Build.0 = Release|Any CPU
{988E6191-82E1-4E13-9DDB-CB9FA2FDAF29}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{988E6191-82E1-4E13-9DDB-CB9FA2FDAF29}.Debug|Any CPU.Build.0 = Debug|Any CPU
{988E6191-82E1-4E13-9DDB-CB9FA2FDAF29}.Debug|x64.ActiveCfg = Debug|Any CPU
{988E6191-82E1-4E13-9DDB-CB9FA2FDAF29}.Debug|x64.Build.0 = Debug|Any CPU
{988E6191-82E1-4E13-9DDB-CB9FA2FDAF29}.Debug|x86.ActiveCfg = Debug|Any CPU
{988E6191-82E1-4E13-9DDB-CB9FA2FDAF29}.Debug|x86.Build.0 = Debug|Any CPU
{988E6191-82E1-4E13-9DDB-CB9FA2FDAF29}.Release|Any CPU.ActiveCfg = Release|Any CPU
{988E6191-82E1-4E13-9DDB-CB9FA2FDAF29}.Release|Any CPU.Build.0 = Release|Any CPU
{988E6191-82E1-4E13-9DDB-CB9FA2FDAF29}.Release|x64.ActiveCfg = Release|Any CPU
{988E6191-82E1-4E13-9DDB-CB9FA2FDAF29}.Release|x64.Build.0 = Release|Any CPU
{988E6191-82E1-4E13-9DDB-CB9FA2FDAF29}.Release|x86.ActiveCfg = Release|Any CPU
{988E6191-82E1-4E13-9DDB-CB9FA2FDAF29}.Release|x86.Build.0 = Release|Any CPU
{D58FA894-27D5-4EAA-9042-AD422AD82931}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D58FA894-27D5-4EAA-9042-AD422AD82931}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D58FA894-27D5-4EAA-9042-AD422AD82931}.Debug|x64.ActiveCfg = Debug|Any CPU
{D58FA894-27D5-4EAA-9042-AD422AD82931}.Debug|x64.Build.0 = Debug|Any CPU
{D58FA894-27D5-4EAA-9042-AD422AD82931}.Debug|x86.ActiveCfg = Debug|Any CPU
{D58FA894-27D5-4EAA-9042-AD422AD82931}.Debug|x86.Build.0 = Debug|Any CPU
{D58FA894-27D5-4EAA-9042-AD422AD82931}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D58FA894-27D5-4EAA-9042-AD422AD82931}.Release|Any CPU.Build.0 = Release|Any CPU
{D58FA894-27D5-4EAA-9042-AD422AD82931}.Release|x64.ActiveCfg = Release|Any CPU
{D58FA894-27D5-4EAA-9042-AD422AD82931}.Release|x64.Build.0 = Release|Any CPU
{D58FA894-27D5-4EAA-9042-AD422AD82931}.Release|x86.ActiveCfg = Release|Any CPU
{D58FA894-27D5-4EAA-9042-AD422AD82931}.Release|x86.Build.0 = Release|Any CPU
{AC26EFF0-8593-4184-9A09-98E37EFFB32E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{AC26EFF0-8593-4184-9A09-98E37EFFB32E}.Debug|Any CPU.Build.0 = Debug|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE

24
assets/Languages.json Normal file
View File

@@ -0,0 +1,24 @@
{
"Languages": {
"ar_SA": "اَلْعَرَبِيَّةُ",
"de_DE": "Deutsch",
"el_GR": "Ελληνικά",
"en_US": "English (US)",
"es_ES": "Español (ES)",
"fr_FR": "Français (FR)",
"he_IL": "עִברִית",
"it_IT": "Italiano",
"ja_JP": "日本語",
"ko_KR": "한국어",
"no_NO": "Norsk",
"pl_PL": "Polski",
"pt_BR": "Português (BR)",
"ru_RU": "Русский",
"sv_SE": "Svenska",
"th_TH": "ภาษาไทย",
"tr_TR": "Türkçe",
"uk_UA": "Українська",
"zh_CN": "简体中文",
"zh_TW": "繁體中文 (台灣)"
}
}

60
assets/Locales.md Normal file
View File

@@ -0,0 +1,60 @@
# Ryubing Locales
Ryubing Locales uses a custom format, which uses a file for defining the supported languages and a folder of json files for the locales themselves.
Each json file holds the locales for a specific part of the emulator, e.g. the Setup Wizard locales are in `SetupWizard.json`, and each locale entry in the file includes all the supported languages in the same place.
## Languages
in the `/assets/` folder you will find the `Languages.json` file, which defines all the languages supported by the emulator.
The file includes a table of the langauge codes and their langauge names.
#Example of the format for Languages.json
{
"Languages": {
"ar_SA": "اَلْعَرَبِيَّةُ",
"en_US": "English (US)",
...
"zh_TW": "繁體中文 (台灣)"
}
}
## Locales
in the `/assets/Locales/` folder you will find the json files, which define all the locales supported by the emulator.
Each json file holds locales for a specific part of the emulator in a large array of locale objects.
Each locale is made up an ID used for lookup and a list of the languages and their matching translations.
Any empty string or null value will automatically use the English translation instead in the emulator.
### Format
When adding a new locale, you just need to add the ID and the en_US language translation, then the validation system will add default values for the rest of languages automatically, when rebuilding the project.
If you want to signal that a translation is supposed to match the English translation, you just have to replace the empty string with `null`.
When you want to check what translations are missing for a language just search for `"<lang_code>": ""`, e.g: `"en_US": ""` (but with any other language, as English will never be missing translations).
### Legacy file (Root.json)
Currently all older locales are stored in `Root.json`, but they are slowly being moved into newer, more descriptive json files, to make the locale system more accessible.
Do **not** add new locales to `Root.json`.
If no json file exists for the specific part of the emulator you're working on, you should instead add a new json file for that part.
#Example of the format for Root.json
{
"Locales": [
{
"ID": "MenuBarActionsOpenMiiEditor",
"Translations": {
"ar_SA": "",
"en_US": "Mii Editor",
...
"zh_TW": "Mii 編輯器"
}
},
{
"ID": "KeyNumber9",
"Translations": {
"ar_SA": "٩",
"en_US": "9",
...
"zh_TW": null
}
}
]
}

View File

@@ -0,0 +1,104 @@
{
"Locales": [
{
"ID": "MenuBarActions_StartCapture",
"Translations": {
"ar_SA": "",
"de_DE": "",
"el_GR": "",
"en_US": "Start RenderDoc Frame Capture",
"es_ES": "Iniciar una captura de fotograma de RenderDoc",
"fr_FR": "Démarrer une capture de trame RenderDoc",
"he_IL": "",
"it_IT": "",
"ja_JP": "",
"ko_KR": "RenderDoc 프레임 캡처 시작",
"no_NO": "",
"pl_PL": "",
"pt_BR": "",
"ru_RU": "",
"sv_SE": "",
"th_TH": "",
"tr_TR": "",
"uk_UA": "",
"zh_CN": "启动 RenderDoc 帧捕获",
"zh_TW": ""
}
},
{
"ID": "MenuBarActions_EndCapture",
"Translations": {
"ar_SA": "",
"de_DE": "",
"el_GR": "",
"en_US": "End RenderDoc Frame Capture",
"es_ES": "Detener la captura de fotograma de RenderDoc",
"fr_FR": "Arrêter la capture de trame RenderDoc",
"he_IL": "",
"it_IT": "",
"ja_JP": "",
"ko_KR": "RenderDoc 프레임 캡처 종료",
"no_NO": "",
"pl_PL": "",
"pt_BR": "",
"ru_RU": "",
"sv_SE": "",
"th_TH": "",
"tr_TR": "",
"uk_UA": "",
"zh_CN": "结束 RenderDoc 帧捕获",
"zh_TW": ""
}
},
{
"ID": "MenuBarActions_DiscardCapture",
"Translations": {
"ar_SA": "",
"de_DE": "",
"el_GR": "",
"en_US": "Discard RenderDoc Frame Capture",
"es_ES": "Descartar la captura de fotograma de RenderDoc",
"fr_FR": "Supprimer la capture de trame RenderDoc",
"he_IL": "",
"it_IT": "",
"ja_JP": "",
"ko_KR": "RenderDoc 프레임 캡처 폐기",
"no_NO": "",
"pl_PL": "",
"pt_BR": "",
"ru_RU": "",
"sv_SE": "",
"th_TH": "",
"tr_TR": "",
"uk_UA": "",
"zh_CN": "丢弃 RenderDoc 帧捕获",
"zh_TW": ""
}
},
{
"ID": "MenuBarActions_DiscardCapture_ToolTip",
"Translations": {
"ar_SA": "",
"de_DE": "",
"el_GR": "",
"en_US": "Ends the currently active RenderDoc Frame Capture, immediately discarding its result.",
"es_ES": "Finaliza la captura de fotograma de RenderDoc actualmente activa y descarta inmediatamente su resultado.",
"fr_FR": "Met fin à la capture de trame RenderDoc en cours, en supprimant immédiatement son résultat.",
"he_IL": "",
"it_IT": "",
"ja_JP": "",
"ko_KR": "현재 활성화된 RenderDoc 프레임 캡처를 종료하고 결과를 즉시 폐기합니다.",
"no_NO": "",
"pl_PL": "",
"pt_BR": "",
"ru_RU": "",
"sv_SE": "",
"th_TH": "",
"tr_TR": "",
"uk_UA": "",
"zh_CN": "结束当前正在进行的 RenderDoc 帧捕获,并立即丢弃其结果。",
"zh_TW": ""
}
}
]
}

File diff suppressed because it is too large Load Diff

View File

@@ -2,8 +2,8 @@
SCRIPT_DIR=$(dirname "$(realpath "$0")")
if [ -f "$SCRIPT_DIR/Ryujinx.Headless.SDL2" ]; then
RYUJINX_BIN="Ryujinx.Headless.SDL2"
if [ -f "$SCRIPT_DIR/Ryujinx.Headless.SDL3" ]; then
RYUJINX_BIN="Ryujinx.Headless.SDL3"
fi
if [ -f "$SCRIPT_DIR/Ryujinx" ]; then

Binary file not shown.

View File

@@ -10,6 +10,8 @@
<string>Ryujinx</string>
<key>CFBundleIconFile</key>
<string>Ryujinx.icns</string>
<key>CFBundleIconName</key>
<string>Ryujinx</string>
<key>CFBundleDocumentTypes</key>
<array>
<dict>
@@ -34,23 +36,23 @@
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleLongVersionString</key>
<string>%%RYUJINX_BUILD_VERSION%%-%%RYUJINX_BUILD_GIT_HASH%%"</string>
<string>%%RYUJINX_BUILD_VERSION%%-%%RYUJINX_BUILD_GIT_HASH%%</string>
<key>CFBundleName</key>
<string>Ryujinx</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>1.2</string>
<string>1.3</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1.2.0</string>
<string>%%RYUJINX_BUILD_VERSION%%</string>
<key>NSHighResolutionCapable</key>
<true/>
<key>CSResourcesFileMapped</key>
<true/>
<key>NSHumanReadableCopyright</key>
<string>Copyright © 2018 - 2023 Ryujinx Team and Contributors.</string>
<string>Copyright © 2018 - 2024 Ryujinx Team and Contributors. Copyright © 2024 - 2025 Ryubing and Contributors.</string>
<key>LSApplicationCategoryType</key>
<string>public.app-category.games</string>
<key>LSMinimumSystemVersion</key>

View File

@@ -25,6 +25,7 @@ cp "$PUBLISH_DIRECTORY"/*.dylib "$APP_BUNDLE_DIRECTORY/Contents/Frameworks"
cp Info.plist "$APP_BUNDLE_DIRECTORY/Contents"
cp Ryujinx.icns "$APP_BUNDLE_DIRECTORY/Contents/Resources/Ryujinx.icns"
cp updater.sh "$APP_BUNDLE_DIRECTORY/Contents/Resources/updater.sh"
cp Assets.car "$APP_BUNDLE_DIRECTORY/Contents/Resources/Assets.car"
cp -r "$PUBLISH_DIRECTORY/THIRDPARTY.md" "$APP_BUNDLE_DIRECTORY/Contents/Resources"
echo -n "APPL????" > "$APP_BUNDLE_DIRECTORY/Contents/PkgInfo"

View File

@@ -1,124 +0,0 @@
#!/bin/bash
set -e
if [ "$#" -lt 8 ]; then
echo "usage <BASE_DIR> <TEMP_DIRECTORY> <OUTPUT_DIRECTORY> <ENTITLEMENTS_FILE_PATH> <VERSION> <SOURCE_REVISION_ID> <CONFIGURATION> <CANARY>"
exit 1
fi
mkdir -p "$1"
mkdir -p "$2"
mkdir -p "$3"
BASE_DIR=$(readlink -f "$1")
TEMP_DIRECTORY=$(readlink -f "$2")
OUTPUT_DIRECTORY=$(readlink -f "$3")
ENTITLEMENTS_FILE_PATH=$(readlink -f "$4")
VERSION=$5
SOURCE_REVISION_ID=$6
CONFIGURATION=$7
CANARY=$8
if [[ "$(uname)" == "Darwin" ]]; then
echo "Clearing xattr on all dot undercsore files"
find "$BASE_DIR" -type f -name "._*" -exec sh -c '
for f; do
dir=$(dirname "$f")
base=$(basename "$f")
orig="$dir/${base#._}"
[ -f "$orig" ] && xattr -c "$orig" || true
done
' sh {} +
fi
if [ "$CANARY" == "1" ]; then
RELEASE_TAR_FILE_NAME=nogui-ryujinx-canary-$VERSION-macos_universal.tar
elif [ "$VERSION" == "1.1.0" ]; then
RELEASE_TAR_FILE_NAME=nogui-ryujinx-$CONFIGURATION-$VERSION+$SOURCE_REVISION_ID-macos_universal.tar
else
RELEASE_TAR_FILE_NAME=nogui-ryujinx-$VERSION-macos_universal.tar
fi
ARM64_OUTPUT="$TEMP_DIRECTORY/publish_arm64"
X64_OUTPUT="$TEMP_DIRECTORY/publish_x64"
UNIVERSAL_OUTPUT="$OUTPUT_DIRECTORY/publish"
EXECUTABLE_SUB_PATH=Ryujinx.Headless.SDL2
rm -rf "$TEMP_DIRECTORY"
mkdir -p "$TEMP_DIRECTORY"
DOTNET_COMMON_ARGS=(-p:DebugType=embedded -p:Version="$VERSION" -p:SourceRevisionId="$SOURCE_REVISION_ID" --self-contained true $EXTRA_ARGS)
dotnet restore
dotnet build -c "$CONFIGURATION" src/Ryujinx.Headless.SDL2
dotnet publish -c "$CONFIGURATION" -r osx-arm64 -o "$TEMP_DIRECTORY/publish_arm64" "${DOTNET_COMMON_ARGS[@]}" src/Ryujinx.Headless.SDL2
dotnet publish -c "$CONFIGURATION" -r osx-x64 -o "$TEMP_DIRECTORY/publish_x64" "${DOTNET_COMMON_ARGS[@]}" src/Ryujinx.Headless.SDL2
# Get rid of the support library for ARMeilleure for x64 (that's only for arm64)
rm -rf "$TEMP_DIRECTORY/publish_x64/libarmeilleure-jitsupport.dylib"
# Get rid of libsoundio from arm64 builds as we don't have a arm64 variant
# TODO: remove this once done
rm -rf "$TEMP_DIRECTORY/publish_arm64/libsoundio.dylib"
rm -rf "$OUTPUT_DIRECTORY"
mkdir -p "$OUTPUT_DIRECTORY"
# Let's copy one of the two different outputs and remove the executable
cp -R "$ARM64_OUTPUT/" "$UNIVERSAL_OUTPUT"
rm "$UNIVERSAL_OUTPUT/$EXECUTABLE_SUB_PATH"
# Make its libraries universal
python3 "$BASE_DIR/distribution/macos/construct_universal_dylib.py" "$ARM64_OUTPUT" "$X64_OUTPUT" "$UNIVERSAL_OUTPUT" "**/*.dylib"
if ! [ -x "$(command -v lipo)" ];
then
if ! [ -x "$(command -v llvm-lipo-17)" ];
then
LIPO=llvm-lipo
else
LIPO=llvm-lipo-17
fi
else
LIPO=lipo
fi
# Make the executable universal
$LIPO "$ARM64_OUTPUT/$EXECUTABLE_SUB_PATH" "$X64_OUTPUT/$EXECUTABLE_SUB_PATH" -output "$UNIVERSAL_OUTPUT/$EXECUTABLE_SUB_PATH" -create
# Now sign it
if ! [ -x "$(command -v codesign)" ];
then
if ! [ -x "$(command -v rcodesign)" ];
then
echo "Cannot find rcodesign on your system, please install rcodesign."
exit 1
fi
# NOTE: Currently require https://github.com/indygreg/apple-platform-rs/pull/44 to work on other OSes.
# cargo install --git "https://github.com/marysaka/apple-platform-rs" --branch "fix/adhoc-app-bundle" apple-codesign --bin "rcodesign"
echo "Using rcodesign for ad-hoc signing"
for FILE in "$UNIVERSAL_OUTPUT"/*; do
if [[ $(file "$FILE") == *"Mach-O"* ]]; then
rcodesign sign --entitlements-xml-path "$ENTITLEMENTS_FILE_PATH" "$FILE"
fi
done
else
echo "Using codesign for ad-hoc signing"
for FILE in "$UNIVERSAL_OUTPUT"/*; do
if [[ $(file "$FILE") == *"Mach-O"* ]]; then
codesign --entitlements "$ENTITLEMENTS_FILE_PATH" -f -s - "$FILE"
fi
done
fi
echo "Creating archive"
pushd "$OUTPUT_DIRECTORY"
tar --exclude "publish/Ryujinx.Headless.SDL2" -cvf "$RELEASE_TAR_FILE_NAME" publish 1> /dev/null
python3 "$BASE_DIR/distribution/misc/add_tar_exec.py" "$RELEASE_TAR_FILE_NAME" "publish/Ryujinx.Headless.SDL2" "publish/Ryujinx.Headless.SDL2"
gzip -9 < "$RELEASE_TAR_FILE_NAME" > "$RELEASE_TAR_FILE_NAME.gz"
rm "$RELEASE_TAR_FILE_NAME"
popd
echo "Done"

View File

@@ -8,7 +8,7 @@ Intro to Ryujinx
Ryujinx is an open-source Nintendo Switch emulator, created by gdkchan, written in C#.
* The CPU emulator, ARMeilleure, emulates an ARMv8 CPU and currently has support for most 64-bit ARMv8 and some of the ARMv7 (and older) instructions.
* The GPU emulator emulates the Switch's Maxwell GPU using either the OpenGL (version 4.5 minimum), Vulkan, or Metal (via MoltenVK) APIs through a custom build of OpenTK or Silk.NET respectively.
* Audio output is entirely supported via C# wrappers for SDL2, with OpenAL & libsoundio as fallbacks.
* Audio output is entirely supported via C# wrappers for SDL3, with OpenAL & libsoundio as fallbacks.
Getting Started
===============

View File

@@ -2050,7 +2050,9 @@
010003C00B868000,"Ninjin: Clash of Carrots",online-broken,playable,2024-07-10 05:12:26
0100746010E4C000,"NinNinDays",,playable,2022-11-20 15:17:29
0100C9A00ECE6000,"Nintendo 64™ Nintendo Switch Online",gpu;vulkan,ingame,2024-04-23 20:21:07
010057D00ECE4000,"Nintendo 64™ Nintendo Switch Online",gpu;vulkan,ingame,2024-04-23 20:21:07
0100e0601c632000,"Nintendo 64™ Nintendo Switch Online: MATURE 17+",,ingame,2025-02-03 22:27:00
010037A0170D2000,"NINTENDO 64™ Nintendo Switch Online 18+",,ingame,2025-02-03 22:27:00
0100D870045B6000,"Nintendo Entertainment System™ - Nintendo Switch Online",online,playable,2022-07-01 15:45:06
0100C4B0034B2000,"Nintendo Labo Toy-Con 01 Variety Kit",gpu,ingame,2022-08-07 12:56:07
01001E9003502000,"Nintendo Labo Toy-Con 03 Vehicle Kit",services;crash,menus,2022-08-03 17:20:11
@@ -2275,12 +2277,12 @@
010018E011D92000,"Pokémon™ Shining Pearl",gpu;ldn-works,ingame,2024-08-28 13:26:35
010015F008C54000,"Pokémon™ HOME",Needs Update;crash;services,menus,2020-12-06 06:01:51
01001F5010DFA000,"Pokémon™ Legends: Arceus",gpu;Needs Update;ldn-works,ingame,2024-09-19 10:02:02
0100F43008C44000,"Pokémon™ Legends: Z-A",gpu;crash;ldn-works,ingame,2025-11-16 00:30:00
01005D100807A000,"Pokémon™ Quest",,playable,2022-02-22 16:12:32
0100A3D008C5C000,"Pokémon™ Scarlet",gpu;nvdec;ldn-works;amd-vendor-bug,ingame,2023-12-14 13:18:29
01008F6008C5E000,"Pokémon™ Violet",gpu;nvdec;ldn-works;amd-vendor-bug;mac-bug,ingame,2024-07-30 02:51:48
0100187003A36000,"Pokémon™: Lets Go, Eevee!",crash;nvdec;online-broken;ldn-broken,ingame,2024-06-01 15:03:04
010003F003A34000,"Pokémon™: Lets Go, Pikachu!",crash;nvdec;online-broken;ldn-broken,ingame,2024-03-15 07:55:41
0100F43008C44000,"Pokémon Legends: Z-A",gpu;crash;ldn-broken,ingame,2025-10-16 19:13:00
0100B3F000BE2000,"Pokkén Tournament™ DX",nvdec;ldn-works;opengl-backend-bug;LAN;amd-vendor-bug;intel-vendor-bug,playable,2024-07-18 23:11:08
010030D005AE6000,"Pokkén Tournament™ DX Demo",demo;opengl-backend-bug,playable,2022-08-10 12:03:19
0100A3500B4EC000,"Polandball: Can Into Space",,playable,2020-06-25 15:13:26
@@ -2638,6 +2640,7 @@
0100B16009C10000,"SINNER: Sacrifice for Redemption",nvdec;UE4;vulkan-backend-bug,playable,2022-08-12 20:37:33
0100E9201410E000,"Sir Lovelot",,playable,2021-04-05 16:21:46
0100134011E32000,"Skate City",,playable,2022-11-04 11:37:39
0100a8501b66e000,"Skateboard Drifting with Maxwell Cat: The Game Simulator",,playable,2026-02-17 19:05:00
0100B2F008BD8000,"Skee-Ball",,playable,2020-11-16 04:44:07
01001A900F862000,"Skelattack",,playable,2021-06-09 15:26:26
01008E700F952000,"Skelittle: A Giant Party!",,playable,2021-06-09 19:08:34
@@ -3307,6 +3310,7 @@
0100AFA011068000,"Voxel Pirates",,playable,2022-09-28 22:55:02
0100BFB00D1F4000,"Voxel Sword",,playable,2022-08-30 14:57:27
01004E90028A2000,"Vroom in the night sky",Needs Update;vulkan-backend-bug,playable,2023-02-20 02:32:29
0100BFC01D976000,"Virtual Boy Nintendo Classics",services,nothing,2026-02-17 11:26:59
0100C7C00AE6C000,"VSR: Void Space Racing",,playable,2021-01-27 14:08:59
0100B130119D0000,"Waifu Uncovered",crash,ingame,2023-02-27 01:17:46
0100E29010A4A000,"Wanba Warriors",,playable,2020-10-04 17:56:22
1 title_id game_name labels status last_updated
2050 010003C00B868000 Ninjin: Clash of Carrots online-broken playable 2024-07-10 05:12:26
2051 0100746010E4C000 NinNinDays playable 2022-11-20 15:17:29
2052 0100C9A00ECE6000 Nintendo 64™ – Nintendo Switch Online gpu;vulkan ingame 2024-04-23 20:21:07
2053 010057D00ECE4000 Nintendo 64™ – Nintendo Switch Online gpu;vulkan ingame 2024-04-23 20:21:07
2054 0100e0601c632000 Nintendo 64™ – Nintendo Switch Online: MATURE 17+ ingame 2025-02-03 22:27:00
2055 010037A0170D2000 NINTENDO 64™ – Nintendo Switch Online 18+ ingame 2025-02-03 22:27:00
2056 0100D870045B6000 Nintendo Entertainment System™ - Nintendo Switch Online online playable 2022-07-01 15:45:06
2057 0100C4B0034B2000 Nintendo Labo Toy-Con 01 Variety Kit gpu ingame 2022-08-07 12:56:07
2058 01001E9003502000 Nintendo Labo Toy-Con 03 Vehicle Kit services;crash menus 2022-08-03 17:20:11
2277 010018E011D92000 Pokémon™ Shining Pearl gpu;ldn-works ingame 2024-08-28 13:26:35
2278 010015F008C54000 Pokémon™ HOME Needs Update;crash;services menus 2020-12-06 06:01:51
2279 01001F5010DFA000 Pokémon™ Legends: Arceus gpu;Needs Update;ldn-works ingame 2024-09-19 10:02:02
2280 0100F43008C44000 Pokémon™ Legends: Z-A gpu;crash;ldn-works ingame 2025-11-16 00:30:00
2281 01005D100807A000 Pokémon™ Quest playable 2022-02-22 16:12:32
2282 0100A3D008C5C000 Pokémon™ Scarlet gpu;nvdec;ldn-works;amd-vendor-bug ingame 2023-12-14 13:18:29
2283 01008F6008C5E000 Pokémon™ Violet gpu;nvdec;ldn-works;amd-vendor-bug;mac-bug ingame 2024-07-30 02:51:48
2284 0100187003A36000 Pokémon™: Let’s Go, Eevee! crash;nvdec;online-broken;ldn-broken ingame 2024-06-01 15:03:04
2285 010003F003A34000 Pokémon™: Let’s Go, Pikachu! crash;nvdec;online-broken;ldn-broken ingame 2024-03-15 07:55:41
0100F43008C44000 Pokémon Legends: Z-A gpu;crash;ldn-broken ingame 2025-10-16 19:13:00
2286 0100B3F000BE2000 Pokkén Tournament™ DX nvdec;ldn-works;opengl-backend-bug;LAN;amd-vendor-bug;intel-vendor-bug playable 2024-07-18 23:11:08
2287 010030D005AE6000 Pokkén Tournament™ DX Demo demo;opengl-backend-bug playable 2022-08-10 12:03:19
2288 0100A3500B4EC000 Polandball: Can Into Space playable 2020-06-25 15:13:26
2640 0100B16009C10000 SINNER: Sacrifice for Redemption nvdec;UE4;vulkan-backend-bug playable 2022-08-12 20:37:33
2641 0100E9201410E000 Sir Lovelot playable 2021-04-05 16:21:46
2642 0100134011E32000 Skate City playable 2022-11-04 11:37:39
2643 0100a8501b66e000 Skateboard Drifting with Maxwell Cat: The Game Simulator playable 2026-02-17 19:05:00
2644 0100B2F008BD8000 Skee-Ball playable 2020-11-16 04:44:07
2645 01001A900F862000 Skelattack playable 2021-06-09 15:26:26
2646 01008E700F952000 Skelittle: A Giant Party! playable 2021-06-09 19:08:34
3310 0100AFA011068000 Voxel Pirates playable 2022-09-28 22:55:02
3311 0100BFB00D1F4000 Voxel Sword playable 2022-08-30 14:57:27
3312 01004E90028A2000 Vroom in the night sky Needs Update;vulkan-backend-bug playable 2023-02-20 02:32:29
3313 0100BFC01D976000 Virtual Boy – Nintendo Classics services nothing 2026-02-17 11:26:59
3314 0100C7C00AE6C000 VSR: Void Space Racing playable 2021-01-27 14:08:59
3315 0100B130119D0000 Waifu Uncovered crash ingame 2023-02-27 01:17:46
3316 0100E29010A4A000 Wanba Warriors playable 2020-10-04 17:56:22

View File

@@ -1,6 +1,6 @@
{
"sdk": {
"version": "9.0.100",
"version": "10.0.100",
"rollForward": "latestFeature"
}
}

View File

@@ -25,9 +25,9 @@ namespace ARMeilleure.CodeGen.Arm64
static class ComparisonArm64Extensions
{
public static ArmCondition ToArmCondition(this Comparison comp)
extension(Comparison comparison)
{
return comp switch
public ArmCondition Arm => comparison switch
{
#pragma warning disable IDE0055 // Disable formatting
Comparison.Equal => ArmCondition.Eq,
@@ -42,7 +42,7 @@ namespace ARMeilleure.CodeGen.Arm64
Comparison.LessUI => ArmCondition.LtUn,
#pragma warning restore IDE0055
_ => throw new ArgumentException(null, nameof(comp)),
_ => throw new ArgumentException(null, nameof(comparison))
};
}
}

View File

@@ -181,10 +181,10 @@ namespace ARMeilleure.CodeGen.Arm64
public void Fmov(Operand rd, Operand rn, bool topHalf)
{
Debug.Assert(rd.Type.IsInteger() != rn.Type.IsInteger());
Debug.Assert(rd.Type.IsInteger != rn.Type.IsInteger);
Debug.Assert(rd.Type == OperandType.I64 || rn.Type == OperandType.I64 || !topHalf);
uint opcode = rd.Type.IsInteger() ? 0b110u : 0b111u;
uint opcode = rd.Type.IsInteger ? 0b110u : 0b111u;
uint rmode = topHalf ? 1u << 19 : 0u;
uint ftype = rd.Type == OperandType.FP64 || rn.Type == OperandType.FP64 ? 1u << 22 : 0u;
@@ -411,7 +411,7 @@ namespace ARMeilleure.CodeGen.Arm64
public void Mov(Operand rd, Operand rn)
{
if (rd.Type.IsInteger())
if (rd.Type.IsInteger)
{
Orr(rd, Factory.Register(ZrRegister, RegisterType.Integer, rd.Type), rn);
}
@@ -973,7 +973,7 @@ namespace ARMeilleure.CodeGen.Arm64
uint instruction;
int scale;
if (type.IsInteger())
if (type.IsInteger)
{
instruction = intInst;
@@ -1009,7 +1009,7 @@ namespace ARMeilleure.CodeGen.Arm64
{
uint instruction;
if (type.IsInteger())
if (type.IsInteger)
{
instruction = intInst;

View File

@@ -250,7 +250,7 @@ namespace ARMeilleure.CodeGen.Arm64
// ValidateBinOp(dest, src1, src2);
if (dest.Type.IsInteger())
if (dest.Type.IsInteger)
{
context.Assembler.Add(dest, src1, src2);
}
@@ -268,7 +268,7 @@ namespace ARMeilleure.CodeGen.Arm64
ValidateBinOp(dest, src1, src2);
Debug.Assert(dest.Type.IsInteger());
Debug.Assert(dest.Type.IsInteger);
context.Assembler.And(dest, src1, src2);
}
@@ -281,7 +281,7 @@ namespace ARMeilleure.CodeGen.Arm64
ValidateBinOp(dest, src1, src2);
if (dest.Type.IsInteger())
if (dest.Type.IsInteger)
{
context.Assembler.Eor(dest, src1, src2);
}
@@ -298,7 +298,7 @@ namespace ARMeilleure.CodeGen.Arm64
ValidateUnOp(dest, source);
Debug.Assert(dest.Type.IsInteger());
Debug.Assert(dest.Type.IsInteger);
context.Assembler.Mvn(dest, source);
}
@@ -311,7 +311,7 @@ namespace ARMeilleure.CodeGen.Arm64
ValidateBinOp(dest, src1, src2);
Debug.Assert(dest.Type.IsInteger());
Debug.Assert(dest.Type.IsInteger);
context.Assembler.Orr(dest, src1, src2);
}
@@ -322,7 +322,7 @@ namespace ARMeilleure.CodeGen.Arm64
Debug.Assert(comp.Kind == OperandKind.Constant);
ArmCondition cond = ((Comparison)comp.AsInt32()).ToArmCondition();
ArmCondition cond = ((Comparison)comp.AsInt32()).Arm;
GenerateCompareCommon(context, operation);
@@ -336,7 +336,7 @@ namespace ARMeilleure.CodeGen.Arm64
ValidateUnOp(dest, source);
Debug.Assert(dest.Type.IsInteger());
Debug.Assert(dest.Type.IsInteger);
context.Assembler.Rev(dest, source);
}
@@ -354,7 +354,7 @@ namespace ARMeilleure.CodeGen.Arm64
Debug.Assert(dest.Type == OperandType.I32);
Debug.Assert(comp.Kind == OperandKind.Constant);
ArmCondition cond = ((Comparison)comp.AsInt32()).ToArmCondition();
ArmCondition cond = ((Comparison)comp.AsInt32()).Arm;
GenerateCompareCommon(context, operation);
@@ -428,7 +428,7 @@ namespace ARMeilleure.CodeGen.Arm64
EnsureSameType(src1, src2);
Debug.Assert(src1.Type.IsInteger());
Debug.Assert(src1.Type.IsInteger);
context.Assembler.Cmp(src1, src2);
}
@@ -442,7 +442,7 @@ namespace ARMeilleure.CodeGen.Arm64
EnsureSameType(dest, src2, src3);
Debug.Assert(dest.Type.IsInteger());
Debug.Assert(dest.Type.IsInteger);
Debug.Assert(src1.Type == OperandType.I32);
context.Assembler.Cmp(src1, Const(src1.Type, 0));
@@ -468,7 +468,7 @@ namespace ARMeilleure.CodeGen.Arm64
Debug.Assert(dest.Type != source.Type);
Debug.Assert(source.Type != OperandType.V128);
if (source.Type.IsInteger())
if (source.Type.IsInteger)
{
context.Assembler.ScvtfScalar(dest, source);
}
@@ -485,7 +485,7 @@ namespace ARMeilleure.CodeGen.Arm64
Debug.Assert(dest.Type is OperandType.FP32 or OperandType.FP64);
Debug.Assert(dest.Type != source.Type);
Debug.Assert(source.Type.IsInteger());
Debug.Assert(source.Type.IsInteger);
context.Assembler.UcvtfScalar(dest, source);
}
@@ -497,7 +497,7 @@ namespace ARMeilleure.CodeGen.Arm64
EnsureSameType(dest, source);
Debug.Assert(dest.Type.IsInteger() || source.Kind != OperandKind.Constant);
Debug.Assert(dest.Type.IsInteger || source.Kind != OperandKind.Constant);
// Moves to the same register are useless.
if (dest.Kind == source.Kind && dest.Value == source.Value)
@@ -529,7 +529,7 @@ namespace ARMeilleure.CodeGen.Arm64
EnsureSameType(dest, source);
Debug.Assert(dest.Type.IsInteger());
Debug.Assert(dest.Type.IsInteger);
context.Assembler.Clz(dest, source);
}
@@ -542,7 +542,7 @@ namespace ARMeilleure.CodeGen.Arm64
ValidateBinOp(dest, dividend, divisor);
if (dest.Type.IsInteger())
if (dest.Type.IsInteger)
{
context.Assembler.Sdiv(dest, dividend, divisor);
}
@@ -576,7 +576,7 @@ namespace ARMeilleure.CodeGen.Arm64
Operand value = operation.Destination;
Operand address = operation.GetSource(0);
Debug.Assert(value.Type.IsInteger());
Debug.Assert(value.Type.IsInteger);
context.Assembler.LdrhRiUn(value, address, 0);
}
@@ -586,7 +586,7 @@ namespace ARMeilleure.CodeGen.Arm64
Operand value = operation.Destination;
Operand address = operation.GetSource(0);
Debug.Assert(value.Type.IsInteger());
Debug.Assert(value.Type.IsInteger);
context.Assembler.LdrbRiUn(value, address, 0);
}
@@ -604,7 +604,7 @@ namespace ARMeilleure.CodeGen.Arm64
EnsureSameType(dest, src1, src2);
if (dest.Type.IsInteger())
if (dest.Type.IsInteger)
{
context.Assembler.Mul(dest, src1, src2);
}
@@ -647,7 +647,7 @@ namespace ARMeilleure.CodeGen.Arm64
ValidateUnOp(dest, source);
if (dest.Type.IsInteger())
if (dest.Type.IsInteger)
{
context.Assembler.Neg(dest, source);
}
@@ -732,7 +732,7 @@ namespace ARMeilleure.CodeGen.Arm64
Operand dest = operation.Destination;
Operand source = operation.GetSource(0);
Debug.Assert(dest.Type.IsInteger() && source.Type.IsInteger());
Debug.Assert(dest.Type.IsInteger && source.Type.IsInteger);
context.Assembler.Sxth(dest, source);
}
@@ -742,7 +742,7 @@ namespace ARMeilleure.CodeGen.Arm64
Operand dest = operation.Destination;
Operand source = operation.GetSource(0);
Debug.Assert(dest.Type.IsInteger() && source.Type.IsInteger());
Debug.Assert(dest.Type.IsInteger && source.Type.IsInteger);
context.Assembler.Sxtw(dest, source);
}
@@ -752,7 +752,7 @@ namespace ARMeilleure.CodeGen.Arm64
Operand dest = operation.Destination;
Operand source = operation.GetSource(0);
Debug.Assert(dest.Type.IsInteger() && source.Type.IsInteger());
Debug.Assert(dest.Type.IsInteger && source.Type.IsInteger);
context.Assembler.Sxtb(dest, source);
}
@@ -823,7 +823,7 @@ namespace ARMeilleure.CodeGen.Arm64
Operand value = operation.GetSource(1);
Operand address = operation.GetSource(0);
Debug.Assert(value.Type.IsInteger());
Debug.Assert(value.Type.IsInteger);
context.Assembler.StrhRiUn(value, address, 0);
}
@@ -833,7 +833,7 @@ namespace ARMeilleure.CodeGen.Arm64
Operand value = operation.GetSource(1);
Operand address = operation.GetSource(0);
Debug.Assert(value.Type.IsInteger());
Debug.Assert(value.Type.IsInteger);
context.Assembler.StrbRiUn(value, address, 0);
}
@@ -858,7 +858,7 @@ namespace ARMeilleure.CodeGen.Arm64
// ValidateBinOp(dest, src1, src2);
if (dest.Type.IsInteger())
if (dest.Type.IsInteger)
{
context.Assembler.Sub(dest, src1, src2);
}
@@ -882,7 +882,7 @@ namespace ARMeilleure.CodeGen.Arm64
if (dest != default)
{
Debug.Assert(!dest.Type.IsInteger() && source.Type.IsInteger());
Debug.Assert(!dest.Type.IsInteger && source.Type.IsInteger);
OperandType destType = source.Type == OperandType.I64 ? OperandType.FP64 : OperandType.FP32;
@@ -901,9 +901,9 @@ namespace ARMeilleure.CodeGen.Arm64
byte index = src2.AsByte();
Debug.Assert(index < OperandType.V128.GetSizeInBytes() / dest.Type.GetSizeInBytes());
Debug.Assert(index < OperandType.V128.ByteSize / dest.Type.ByteSize);
if (dest.Type.IsInteger())
if (dest.Type.IsInteger)
{
context.Assembler.Umov(dest, src1, index, dest.Type == OperandType.I64 ? 3 : 2);
}
@@ -959,7 +959,7 @@ namespace ARMeilleure.CodeGen.Arm64
byte index = src3.AsByte();
if (src2.Type.IsInteger())
if (src2.Type.IsInteger)
{
context.Assembler.Ins(dest, src2, index, src2.Type == OperandType.I64 ? 3 : 2);
}
@@ -1007,7 +1007,7 @@ namespace ARMeilleure.CodeGen.Arm64
{
Operand dest = operation.Destination;
Debug.Assert(!dest.Type.IsInteger());
Debug.Assert(!dest.Type.IsInteger);
context.Assembler.CmeqVector(dest, dest, dest, 2);
}
@@ -1016,7 +1016,7 @@ namespace ARMeilleure.CodeGen.Arm64
{
Operand dest = operation.Destination;
Debug.Assert(!dest.Type.IsInteger());
Debug.Assert(!dest.Type.IsInteger);
context.Assembler.EorVector(dest, dest, dest);
}
@@ -1046,7 +1046,7 @@ namespace ARMeilleure.CodeGen.Arm64
Operand dest = operation.Destination;
Operand source = operation.GetSource(0);
Debug.Assert(dest.Type.IsInteger() && source.Type.IsInteger());
Debug.Assert(dest.Type.IsInteger && source.Type.IsInteger);
context.Assembler.Uxth(dest, source);
}
@@ -1056,7 +1056,7 @@ namespace ARMeilleure.CodeGen.Arm64
Operand dest = operation.Destination;
Operand source = operation.GetSource(0);
Debug.Assert(dest.Type.IsInteger() && source.Type.IsInteger());
Debug.Assert(dest.Type.IsInteger && source.Type.IsInteger);
// We can eliminate the move if source is already 32-bit and the registers are the same.
if (dest.Value == source.Value && source.Type == OperandType.I32)
@@ -1072,7 +1072,7 @@ namespace ARMeilleure.CodeGen.Arm64
Operand dest = operation.Destination;
Operand source = operation.GetSource(0);
Debug.Assert(dest.Type.IsInteger() && source.Type.IsInteger());
Debug.Assert(dest.Type.IsInteger && source.Type.IsInteger);
context.Assembler.Uxtb(dest, source);
}
@@ -1169,7 +1169,7 @@ namespace ARMeilleure.CodeGen.Arm64
context.Assembler.StrRiPre(Register(reg, type), Register(SpRegister), -calleeSaveRegionSize);
}
offset += type.GetSizeInBytes();
offset += type.ByteSize;
}
while (mask != 0)
@@ -1195,7 +1195,7 @@ namespace ARMeilleure.CodeGen.Arm64
context.Assembler.StpRiPre(Register(reg, type), Register(reg2, type), Register(SpRegister), -calleeSaveRegionSize);
}
offset += type.GetSizeInBytes() * 2;
offset += type.ByteSize * 2;
}
}
@@ -1273,7 +1273,7 @@ namespace ARMeilleure.CodeGen.Arm64
mask &= ~(1 << reg2);
offset -= type.GetSizeInBytes() * 2;
offset -= type.ByteSize * 2;
if (offset != 0)
{
@@ -1286,7 +1286,7 @@ namespace ARMeilleure.CodeGen.Arm64
}
else
{
offset -= type.GetSizeInBytes();
offset -= type.ByteSize;
if (offset != 0)
{
@@ -1435,12 +1435,12 @@ namespace ARMeilleure.CodeGen.Arm64
OperandType valueType = GetMemOpValueType(currentOp);
if (valueType != GetMemOpValueType(nextOp) || op1Offset + valueType.GetSizeInBytes() != op2Offset)
if (valueType != GetMemOpValueType(nextOp) || op1Offset + valueType.ByteSize != op2Offset)
{
return false;
}
if (!CodeGenCommon.ConstFitsOnSImm7(op1Offset, valueType.GetSizeInBytesLog2()))
if (!CodeGenCommon.ConstFitsOnSImm7(op1Offset, valueType.ByteSizeLog2))
{
return false;
}
@@ -1549,7 +1549,7 @@ namespace ARMeilleure.CodeGen.Arm64
// EnsureSameReg (dest, src1);
EnsureSameType(dest, src1);
Debug.Assert(dest.Type.IsInteger() && src2.Type == OperandType.I32);
Debug.Assert(dest.Type.IsInteger && src2.Type == OperandType.I32);
}
private static void EnsureSameReg(Operand op1, Operand op2)

View File

@@ -462,7 +462,7 @@ namespace ARMeilleure.CodeGen.Arm64
{
instruction |= (sz << 22);
if (rd.Type.IsInteger())
if (rd.Type.IsInteger)
{
context.Assembler.WriteInstructionAuto(instruction, rd, rn);
}
@@ -490,7 +490,7 @@ namespace ARMeilleure.CodeGen.Arm64
instruction |= (sz << 22);
instruction |= (64 - fBits) << 10;
if (rd.Type.IsInteger())
if (rd.Type.IsInteger)
{
Debug.Assert(rd.Type != OperandType.I32 || fBits <= 32);

View File

@@ -112,7 +112,7 @@ namespace ARMeilleure.CodeGen.Arm64
if (src1.Kind == OperandKind.Constant)
{
if (!src1.Type.IsInteger())
if (!src1.Type.IsInteger)
{
// Handle non-integer types (FP32, FP64 and V128).
// For instructions without an immediate operand, we do the following:
@@ -161,7 +161,7 @@ namespace ARMeilleure.CodeGen.Arm64
if (src2.Kind == OperandKind.Constant)
{
if (!src2.Type.IsInteger())
if (!src2.Type.IsInteger)
{
src2 = AddFloatConstantCopy(constants, nodes, node, src2);
@@ -191,7 +191,7 @@ namespace ARMeilleure.CodeGen.Arm64
if (src.Kind == OperandKind.Constant)
{
if (!src.Type.IsInteger())
if (!src.Type.IsInteger)
{
src = AddFloatConstantCopy(constants, nodes, node, src);
@@ -282,7 +282,7 @@ namespace ARMeilleure.CodeGen.Arm64
bool passOnReg;
if (source.Type.IsInteger())
if (source.Type.IsInteger)
{
passOnReg = intCount < intMax;
}
@@ -309,7 +309,7 @@ namespace ARMeilleure.CodeGen.Arm64
if (passOnReg)
{
Operand argReg = source.Type.IsInteger()
Operand argReg = source.Type.IsInteger
? Gpr(CallingConvention.GetIntArgumentRegister(intCount++), source.Type)
: Xmm(CallingConvention.GetVecArgumentRegister(vecCount++), source.Type);
@@ -327,7 +327,7 @@ namespace ARMeilleure.CodeGen.Arm64
InsertConstantRegCopies(constants, nodes, nodes.AddBefore(node, spillOp));
stackOffset += source.Type.GetSizeInBytes();
stackOffset += source.Type.ByteSize;
}
}
@@ -345,7 +345,7 @@ namespace ARMeilleure.CodeGen.Arm64
}
else
{
Operand retReg = dest.Type.IsInteger()
Operand retReg = dest.Type.IsInteger
? Gpr(CallingConvention.GetIntReturnRegister(), dest.Type)
: Xmm(CallingConvention.GetVecReturnRegister(), dest.Type);
@@ -385,7 +385,7 @@ namespace ARMeilleure.CodeGen.Arm64
bool passOnReg;
if (source.Type.IsInteger())
if (source.Type.IsInteger)
{
passOnReg = intCount + 1 < intMax;
}
@@ -408,7 +408,7 @@ namespace ARMeilleure.CodeGen.Arm64
if (passOnReg)
{
Operand argReg = source.Type.IsInteger()
Operand argReg = source.Type.IsInteger
? Gpr(CallingConvention.GetIntArgumentRegister(intCount++), source.Type)
: Xmm(CallingConvention.GetVecArgumentRegister(vecCount++), source.Type);
@@ -521,7 +521,7 @@ namespace ARMeilleure.CodeGen.Arm64
}
else
{
Operand retReg = source.Type.IsInteger()
Operand retReg = source.Type.IsInteger
? Gpr(CallingConvention.GetIntReturnRegister(), source.Type)
: Xmm(CallingConvention.GetVecReturnRegister(), source.Type);
@@ -551,7 +551,7 @@ namespace ARMeilleure.CodeGen.Arm64
{
OperandType argType = cctx.FuncArgTypes[cIndex];
if (argType.IsInteger())
if (argType.IsInteger)
{
intCount++;
}
@@ -567,7 +567,7 @@ namespace ARMeilleure.CodeGen.Arm64
bool passOnReg;
if (source.Type.IsInteger())
if (source.Type.IsInteger)
{
passOnReg = intCount < CallingConvention.GetArgumentsOnRegsCount();
}
@@ -606,7 +606,7 @@ namespace ARMeilleure.CodeGen.Arm64
{
Operand pArg = Local(dest.Type);
Operand argReg = dest.Type.IsInteger()
Operand argReg = dest.Type.IsInteger
? Gpr(CallingConvention.GetIntArgumentRegister(intCount), dest.Type)
: Xmm(CallingConvention.GetVecArgumentRegister(vecCount), dest.Type);

View File

@@ -51,7 +51,7 @@ namespace ARMeilleure.CodeGen.Optimizations
if (trueSucc == block.ListNext)
{
Comparison comp = (Comparison)branchOp.GetSource(2).AsInt32();
Comparison compInv = comp.Invert();
Comparison compInv = comp.Inverse;
branchOp.SetSource(2, Const((int)compInv));

View File

@@ -161,7 +161,7 @@ namespace ARMeilleure.CodeGen.Optimizations
}
else if (otherCompType == Comparison.Equal)
{
propCompType = compType.Invert();
propCompType = compType.Inverse;
}
else
{

View File

@@ -105,7 +105,7 @@ namespace ARMeilleure.CodeGen.Optimizations
Operand x = operation.GetSource(0);
Operand y = operation.GetSource(1);
if (x == y && x.Type.IsInteger())
if (x == y && x.Type.IsInteger)
{
operation.TurnIntoCopy(Const(x.Type, 0));
}
@@ -161,7 +161,7 @@ namespace ARMeilleure.CodeGen.Optimizations
private static bool IsConstEqual(Operand operand, ulong comparand)
{
if (operand.Kind != OperandKind.Constant || !operand.Type.IsInteger())
if (operand.Kind != OperandKind.Constant || !operand.Type.IsInteger)
{
return false;
}

View File

@@ -98,7 +98,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
{
OperandType type = types[copyDest];
type = type.IsInteger() ? OperandType.I64 : OperandType.V128;
type = type.IsInteger ? OperandType.I64 : OperandType.V128;
EmitXorSwap(sequence, GetRegister(copyDest, type), GetRegister(copySource, type));

View File

@@ -178,7 +178,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
}
else if (dest.Kind == OperandKind.Register)
{
if (dest.Type.IsInteger())
if (dest.Type.IsInteger)
{
intFixedRegisters |= 1 << dest.GetRegister().Index;
}
@@ -236,7 +236,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
{
Register reg = info.Register.GetRegister();
if (local.Type.IsInteger())
if (local.Type.IsInteger)
{
intLocalFreeRegisters |= 1 << reg.Index;
}
@@ -254,7 +254,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
if (temp == default || info.Sequence != sequence)
{
temp = local.Type.IsInteger()
temp = local.Type.IsInteger
? GetSpillTemp(local, intSpillTempRegisters, ref intLocalUse)
: GetSpillTemp(local, vecSpillTempRegisters, ref vecLocalUse);
@@ -335,7 +335,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
if (info.UsesAllocated == 0)
{
int mask = dest.Type.IsInteger()
int mask = dest.Type.IsInteger
? intLocalFreeRegisters
: vecLocalFreeRegisters;
@@ -343,9 +343,9 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
{
int selectedReg = BitOperations.TrailingZeroCount(mask);
info.Register = Register(selectedReg, info.Type.ToRegisterType(), info.Type);
info.Register = Register(selectedReg, info.Type.Register, info.Type);
if (dest.Type.IsInteger())
if (dest.Type.IsInteger)
{
intLocalFreeRegisters &= ~(1 << selectedReg);
intUsedRegisters |= 1 << selectedReg;
@@ -359,7 +359,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
else
{
info.Register = default;
info.SpillOffset = Const(stackAlloc.Allocate(dest.Type.GetSizeInBytes()));
info.SpillOffset = Const(stackAlloc.Allocate(dest.Type.ByteSize));
}
}
@@ -377,7 +377,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
if (temp == default || info.Sequence != sequence)
{
temp = dest.Type.IsInteger()
temp = dest.Type.IsInteger
? GetSpillTemp(dest, intSpillTempRegisters, ref intLocalAsg)
: GetSpillTemp(dest, vecSpillTempRegisters, ref vecLocalAsg);
@@ -443,7 +443,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
useMask |= 1 << selectedReg;
return Register(selectedReg, local.Type.ToRegisterType(), local.Type);
return Register(selectedReg, local.Type.Register, local.Type);
}
private static int UsesCount(Operand local)

View File

@@ -208,7 +208,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
private bool TryAllocateRegWithoutSpill(AllocationContext context, LiveInterval current, int cIndex, int registersCount)
{
RegisterType regType = current.Local.Type.ToRegisterType();
RegisterType regType = current.Local.Type.Register;
Span<int> freePositions = stackalloc int[registersCount];
@@ -318,7 +318,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
private void AllocateRegWithSpill(AllocationContext context, LiveInterval current, int cIndex, int registersCount)
{
RegisterType regType = current.Local.Type.ToRegisterType();
RegisterType regType = current.Local.Type.Register;
Span<int> usePositions = stackalloc int[registersCount];
Span<int> blockedPositions = stackalloc int[registersCount];

View File

@@ -10,7 +10,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
public int Allocate(OperandType type)
{
return Allocate(type.GetSizeInBytes());
return Allocate(type.ByteSize);
}
public int Allocate(int sizeInBytes)

View File

@@ -385,7 +385,7 @@ namespace ARMeilleure.CodeGen.X86
{
ref readonly InstructionInfo info = ref _instTable[(int)X86Instruction.Movd];
if (source.Type.IsInteger() || source.Kind == OperandKind.Memory)
if (source.Type.IsInteger || source.Kind == OperandKind.Memory)
{
WriteOpCode(dest, default, source, OperandType.None, info.Flags, info.OpRRM, rrm: true);
}
@@ -416,11 +416,11 @@ namespace ARMeilleure.CodeGen.X86
InstructionFlags flags = info.Flags | InstructionFlags.RexW;
if (source.Type.IsInteger() || source.Kind == OperandKind.Memory)
if (source.Type.IsInteger || source.Kind == OperandKind.Memory)
{
WriteOpCode(dest, default, source, OperandType.None, flags, info.OpRRM, rrm: true);
}
else if (dest.Type.IsInteger() || dest.Kind == OperandKind.Memory)
else if (dest.Type.IsInteger || dest.Kind == OperandKind.Memory)
{
WriteOpCode(dest, default, source, OperandType.None, flags, info.OpRMR);
}
@@ -1107,17 +1107,17 @@ namespace ARMeilleure.CodeGen.X86
}
else
{
if (flags.HasFlag(InstructionFlags.Prefix66))
if ((flags & InstructionFlags.Prefix66) != 0)
{
WriteByte(0x66);
}
if (flags.HasFlag(InstructionFlags.PrefixF2))
if ((flags & InstructionFlags.PrefixF2) != 0f)
{
WriteByte(0xf2);
}
if (flags.HasFlag(InstructionFlags.PrefixF3))
if ((flags & InstructionFlags.PrefixF3) != 0f)
{
WriteByte(0xf3);
}

View File

@@ -1,5 +1,4 @@
using System;
using System.Diagnostics.CodeAnalysis;
namespace ARMeilleure.CodeGen.X86
{

View File

@@ -2,7 +2,6 @@ using ARMeilleure.CodeGen.RegisterAllocators;
using ARMeilleure.IntermediateRepresentation;
using Microsoft.IO;
using Ryujinx.Common.Memory;
using System.IO;
using System.Numerics;
namespace ARMeilleure.CodeGen.X86

View File

@@ -289,7 +289,7 @@ namespace ARMeilleure.CodeGen.X86
EnsureSameType(dest, source);
Debug.Assert(dest.Type.IsInteger());
Debug.Assert(dest.Type.IsInteger);
context.Assembler.Popcnt(dest, source, dest.Type);
@@ -303,7 +303,7 @@ namespace ARMeilleure.CodeGen.X86
EnsureSameType(dest, source);
Debug.Assert(!dest.Type.IsInteger());
Debug.Assert(!dest.Type.IsInteger);
context.Assembler.WriteInstruction(info.Inst, dest, source);
@@ -315,7 +315,7 @@ namespace ARMeilleure.CodeGen.X86
Operand dest = operation.Destination;
Operand source = operation.GetSource(0);
Debug.Assert(dest.Type.IsInteger() && !source.Type.IsInteger());
Debug.Assert(dest.Type.IsInteger && !source.Type.IsInteger);
if (operation.Intrinsic == Intrinsic.X86Cvtsi2si)
{
@@ -349,8 +349,8 @@ namespace ARMeilleure.CodeGen.X86
EnsureSameReg(dest, src1);
}
Debug.Assert(!dest.Type.IsInteger());
Debug.Assert(!src2.Type.IsInteger() || src2.Kind == OperandKind.Constant);
Debug.Assert(!dest.Type.IsInteger);
Debug.Assert(!src2.Type.IsInteger || src2.Kind == OperandKind.Constant);
context.Assembler.WriteInstruction(info.Inst, dest, src1, src2);
@@ -370,7 +370,7 @@ namespace ARMeilleure.CodeGen.X86
EnsureSameReg(dest, src1);
}
Debug.Assert(!dest.Type.IsInteger() && src2.Type.IsInteger());
Debug.Assert(!dest.Type.IsInteger && src2.Type.IsInteger);
context.Assembler.WriteInstruction(info.Inst, dest, src1, src2, src2.Type);
@@ -385,7 +385,7 @@ namespace ARMeilleure.CodeGen.X86
EnsureSameReg(dest, src1);
Debug.Assert(dest.Type.IsInteger() && src1.Type.IsInteger() && src2.Type.IsInteger());
Debug.Assert(dest.Type.IsInteger && src1.Type.IsInteger && src2.Type.IsInteger);
context.Assembler.WriteInstruction(info.Inst, dest, src2, dest.Type);
@@ -405,7 +405,7 @@ namespace ARMeilleure.CodeGen.X86
EnsureSameReg(dest, src1);
}
Debug.Assert(!dest.Type.IsInteger() && src2.Kind == OperandKind.Constant);
Debug.Assert(!dest.Type.IsInteger && src2.Kind == OperandKind.Constant);
context.Assembler.WriteInstruction(info.Inst, dest, src1, src2.AsByte());
@@ -421,7 +421,7 @@ namespace ARMeilleure.CodeGen.X86
EnsureSameType(dest, src1, src2, src3);
Debug.Assert(!dest.Type.IsInteger());
Debug.Assert(!dest.Type.IsInteger);
if (info.Inst == X86Instruction.Blendvpd && HardwareCapabilities.SupportsVexEncoding)
{
@@ -461,7 +461,7 @@ namespace ARMeilleure.CodeGen.X86
EnsureSameReg(dest, src1);
}
Debug.Assert(!dest.Type.IsInteger() && src3.Kind == OperandKind.Constant);
Debug.Assert(!dest.Type.IsInteger && src3.Kind == OperandKind.Constant);
context.Assembler.WriteInstruction(info.Inst, dest, src1, src2, src3.AsByte());
@@ -512,7 +512,7 @@ namespace ARMeilleure.CodeGen.X86
Operand src1 = operation.GetSource(0);
Operand src2 = operation.GetSource(1);
if (dest.Type.IsInteger())
if (dest.Type.IsInteger)
{
// If Destination and Source 1 Operands are the same, perform a standard add as there are no benefits to using LEA.
if (dest.Kind == src1.Kind && dest.Value == src1.Value)
@@ -567,7 +567,7 @@ namespace ARMeilleure.CodeGen.X86
ValidateBinOp(dest, src1, src2);
Debug.Assert(dest.Type.IsInteger());
Debug.Assert(dest.Type.IsInteger);
// Note: GenerateCompareCommon makes the assumption that BitwiseAnd will emit only a single `and`
// instruction.
@@ -582,7 +582,7 @@ namespace ARMeilleure.CodeGen.X86
ValidateBinOp(dest, src1, src2);
if (dest.Type.IsInteger())
if (dest.Type.IsInteger)
{
context.Assembler.Xor(dest, src2, dest.Type);
}
@@ -599,7 +599,7 @@ namespace ARMeilleure.CodeGen.X86
ValidateUnOp(dest, source);
Debug.Assert(dest.Type.IsInteger());
Debug.Assert(dest.Type.IsInteger);
context.Assembler.Not(dest);
}
@@ -612,7 +612,7 @@ namespace ARMeilleure.CodeGen.X86
ValidateBinOp(dest, src1, src2);
Debug.Assert(dest.Type.IsInteger());
Debug.Assert(dest.Type.IsInteger);
context.Assembler.Or(dest, src2, dest.Type);
}
@@ -623,7 +623,7 @@ namespace ARMeilleure.CodeGen.X86
Debug.Assert(comp.Kind == OperandKind.Constant);
X86Condition cond = ((Comparison)comp.AsInt32()).ToX86Condition();
X86Condition cond = ((Comparison)comp.AsInt32()).X86;
GenerateCompareCommon(context, operation);
@@ -637,7 +637,7 @@ namespace ARMeilleure.CodeGen.X86
ValidateUnOp(dest, source);
Debug.Assert(dest.Type.IsInteger());
Debug.Assert(dest.Type.IsInteger);
context.Assembler.Bswap(dest);
}
@@ -661,7 +661,7 @@ namespace ARMeilleure.CodeGen.X86
Debug.Assert(dest.Type == OperandType.I32);
Debug.Assert(comp.Kind == OperandKind.Constant);
X86Condition cond = ((Comparison)comp.AsInt32()).ToX86Condition();
X86Condition cond = ((Comparison)comp.AsInt32()).X86;
GenerateCompareCommon(context, operation);
@@ -676,7 +676,7 @@ namespace ARMeilleure.CodeGen.X86
EnsureSameType(src1, src2);
Debug.Assert(src1.Type.IsInteger());
Debug.Assert(src1.Type.IsInteger);
if (src2.Kind == OperandKind.Constant && src2.Value == 0)
{
@@ -766,7 +766,7 @@ namespace ARMeilleure.CodeGen.X86
EnsureSameReg(dest, src3);
EnsureSameType(dest, src2, src3);
Debug.Assert(dest.Type.IsInteger());
Debug.Assert(dest.Type.IsInteger);
Debug.Assert(src1.Type == OperandType.I32);
context.Assembler.Test(src1, src1, src1.Type);
@@ -792,9 +792,9 @@ namespace ARMeilleure.CodeGen.X86
if (dest.Type == OperandType.FP32)
{
Debug.Assert(source.Type.IsInteger() || source.Type == OperandType.FP64);
Debug.Assert(source.Type.IsInteger || source.Type == OperandType.FP64);
if (source.Type.IsInteger())
if (source.Type.IsInteger)
{
context.Assembler.Xorps(dest, dest, dest);
context.Assembler.Cvtsi2ss(dest, dest, source, source.Type);
@@ -808,9 +808,9 @@ namespace ARMeilleure.CodeGen.X86
}
else /* if (dest.Type == OperandType.FP64) */
{
Debug.Assert(source.Type.IsInteger() || source.Type == OperandType.FP32);
Debug.Assert(source.Type.IsInteger || source.Type == OperandType.FP32);
if (source.Type.IsInteger())
if (source.Type.IsInteger)
{
context.Assembler.Xorps(dest, dest, dest);
context.Assembler.Cvtsi2sd(dest, dest, source, source.Type);
@@ -831,7 +831,7 @@ namespace ARMeilleure.CodeGen.X86
EnsureSameType(dest, source);
Debug.Assert(dest.Type.IsInteger() || source.Kind != OperandKind.Constant);
Debug.Assert(dest.Type.IsInteger || source.Kind != OperandKind.Constant);
// Moves to the same register are useless.
if (dest.Kind == source.Kind && dest.Value == source.Value)
@@ -845,7 +845,7 @@ namespace ARMeilleure.CodeGen.X86
// Assemble "mov reg, 0" as "xor reg, reg" as the later is more efficient.
context.Assembler.Xor(dest, dest, OperandType.I32);
}
else if (dest.Type.IsInteger())
else if (dest.Type.IsInteger)
{
context.Assembler.Mov(dest, source, dest.Type);
}
@@ -862,7 +862,7 @@ namespace ARMeilleure.CodeGen.X86
EnsureSameType(dest, source);
Debug.Assert(dest.Type.IsInteger());
Debug.Assert(dest.Type.IsInteger);
context.Assembler.Bsr(dest, source, dest.Type);
@@ -894,12 +894,12 @@ namespace ARMeilleure.CodeGen.X86
Operand dividend = operation.GetSource(0);
Operand divisor = operation.GetSource(1);
if (!dest.Type.IsInteger())
if (!dest.Type.IsInteger)
{
ValidateBinOp(dest, dividend, divisor);
}
if (dest.Type.IsInteger())
if (dest.Type.IsInteger)
{
divisor = operation.GetSource(2);
@@ -932,7 +932,7 @@ namespace ARMeilleure.CodeGen.X86
Operand rdx = Register(X86Register.Rdx);
Debug.Assert(divisor.Type.IsInteger());
Debug.Assert(divisor.Type.IsInteger);
context.Assembler.Xor(rdx, rdx, OperandType.I32);
context.Assembler.Div(divisor);
@@ -967,7 +967,7 @@ namespace ARMeilleure.CodeGen.X86
Operand value = operation.Destination;
Operand address = Memory(operation.GetSource(0), value.Type);
Debug.Assert(value.Type.IsInteger());
Debug.Assert(value.Type.IsInteger);
context.Assembler.Movzx16(value, address, value.Type);
}
@@ -977,7 +977,7 @@ namespace ARMeilleure.CodeGen.X86
Operand value = operation.Destination;
Operand address = Memory(operation.GetSource(0), value.Type);
Debug.Assert(value.Type.IsInteger());
Debug.Assert(value.Type.IsInteger);
context.Assembler.Movzx8(value, address, value.Type);
}
@@ -1000,7 +1000,7 @@ namespace ARMeilleure.CodeGen.X86
EnsureSameType(dest, src1, src2);
if (dest.Type.IsInteger())
if (dest.Type.IsInteger)
{
if (src2.Kind == OperandKind.Constant)
{
@@ -1046,7 +1046,7 @@ namespace ARMeilleure.CodeGen.X86
ValidateUnOp(dest, source);
Debug.Assert(dest.Type.IsInteger());
Debug.Assert(dest.Type.IsInteger);
context.Assembler.Neg(dest);
}
@@ -1107,7 +1107,7 @@ namespace ARMeilleure.CodeGen.X86
Operand dest = operation.Destination;
Operand source = operation.GetSource(0);
Debug.Assert(dest.Type.IsInteger() && source.Type.IsInteger());
Debug.Assert(dest.Type.IsInteger && source.Type.IsInteger);
context.Assembler.Movsx16(dest, source, dest.Type);
}
@@ -1117,7 +1117,7 @@ namespace ARMeilleure.CodeGen.X86
Operand dest = operation.Destination;
Operand source = operation.GetSource(0);
Debug.Assert(dest.Type.IsInteger() && source.Type.IsInteger());
Debug.Assert(dest.Type.IsInteger && source.Type.IsInteger);
context.Assembler.Movsx32(dest, source, dest.Type);
}
@@ -1127,7 +1127,7 @@ namespace ARMeilleure.CodeGen.X86
Operand dest = operation.Destination;
Operand source = operation.GetSource(0);
Debug.Assert(dest.Type.IsInteger() && source.Type.IsInteger());
Debug.Assert(dest.Type.IsInteger && source.Type.IsInteger);
context.Assembler.Movsx8(dest, source, dest.Type);
}
@@ -1187,7 +1187,7 @@ namespace ARMeilleure.CodeGen.X86
Operand value = operation.GetSource(1);
Operand address = Memory(operation.GetSource(0), value.Type);
Debug.Assert(value.Type.IsInteger());
Debug.Assert(value.Type.IsInteger);
context.Assembler.Mov16(address, value);
}
@@ -1197,7 +1197,7 @@ namespace ARMeilleure.CodeGen.X86
Operand value = operation.GetSource(1);
Operand address = Memory(operation.GetSource(0), value.Type);
Debug.Assert(value.Type.IsInteger());
Debug.Assert(value.Type.IsInteger);
context.Assembler.Mov8(address, value);
}
@@ -1210,7 +1210,7 @@ namespace ARMeilleure.CodeGen.X86
ValidateBinOp(dest, src1, src2);
if (dest.Type.IsInteger())
if (dest.Type.IsInteger)
{
context.Assembler.Sub(dest, src2, dest.Type);
}
@@ -1236,7 +1236,7 @@ namespace ARMeilleure.CodeGen.X86
Operand dest = operation.Destination;
Operand source = operation.GetSource(0);
Debug.Assert(!dest.Type.IsInteger() && source.Type.IsInteger());
Debug.Assert(!dest.Type.IsInteger && source.Type.IsInteger);
if (source.Type == OperandType.I32)
{
@@ -1259,7 +1259,7 @@ namespace ARMeilleure.CodeGen.X86
byte index = src2.AsByte();
Debug.Assert(index < OperandType.V128.GetSizeInBytes() / dest.Type.GetSizeInBytes());
Debug.Assert(index < OperandType.V128.ByteSize / dest.Type.ByteSize);
if (dest.Type == OperandType.I32)
{
@@ -1541,7 +1541,7 @@ namespace ARMeilleure.CodeGen.X86
{
Operand dest = operation.Destination;
Debug.Assert(!dest.Type.IsInteger());
Debug.Assert(!dest.Type.IsInteger);
context.Assembler.Pcmpeqw(dest, dest, dest);
}
@@ -1550,7 +1550,7 @@ namespace ARMeilleure.CodeGen.X86
{
Operand dest = operation.Destination;
Debug.Assert(!dest.Type.IsInteger());
Debug.Assert(!dest.Type.IsInteger);
context.Assembler.Xorps(dest, dest, dest);
}
@@ -1580,7 +1580,7 @@ namespace ARMeilleure.CodeGen.X86
Operand dest = operation.Destination;
Operand source = operation.GetSource(0);
Debug.Assert(dest.Type.IsInteger() && source.Type.IsInteger());
Debug.Assert(dest.Type.IsInteger && source.Type.IsInteger);
context.Assembler.Movzx16(dest, source, OperandType.I32);
}
@@ -1590,7 +1590,7 @@ namespace ARMeilleure.CodeGen.X86
Operand dest = operation.Destination;
Operand source = operation.GetSource(0);
Debug.Assert(dest.Type.IsInteger() && source.Type.IsInteger());
Debug.Assert(dest.Type.IsInteger && source.Type.IsInteger);
// We can eliminate the move if source is already 32-bit and the registers are the same.
if (dest.Value == source.Value && source.Type == OperandType.I32)
@@ -1606,7 +1606,7 @@ namespace ARMeilleure.CodeGen.X86
Operand dest = operation.Destination;
Operand source = operation.GetSource(0);
Debug.Assert(dest.Type.IsInteger() && source.Type.IsInteger());
Debug.Assert(dest.Type.IsInteger && source.Type.IsInteger);
context.Assembler.Movzx8(dest, source, OperandType.I32);
}
@@ -1713,12 +1713,12 @@ namespace ARMeilleure.CodeGen.X86
EnsureSameReg(dest, src1);
EnsureSameType(dest, src1);
Debug.Assert(dest.Type.IsInteger() && src2.Type == OperandType.I32);
Debug.Assert(dest.Type.IsInteger && src2.Type == OperandType.I32);
}
private static void EnsureSameReg(Operand op1, Operand op2)
{
if (!op1.Type.IsInteger() && HardwareCapabilities.SupportsVexEncoding)
if (!op1.Type.IsInteger && HardwareCapabilities.SupportsVexEncoding)
{
return;
}

View File

@@ -86,7 +86,7 @@ namespace ARMeilleure.CodeGen.X86
break;
case Instruction.Negate:
if (!node.GetSource(0).Type.IsInteger())
if (!node.GetSource(0).Type.IsInteger)
{
GenerateNegate(block.Operations, node);
}
@@ -159,7 +159,7 @@ namespace ARMeilleure.CodeGen.X86
if (src1.Kind == OperandKind.Constant)
{
if (!src1.Type.IsInteger())
if (!src1.Type.IsInteger)
{
// Handle non-integer types (FP32, FP64 and V128).
// For instructions without an immediate operand, we do the following:
@@ -208,7 +208,7 @@ namespace ARMeilleure.CodeGen.X86
if (src2.Kind == OperandKind.Constant)
{
if (!src2.Type.IsInteger())
if (!src2.Type.IsInteger)
{
src2 = AddXmmCopy(nodes, node, src2);
@@ -298,7 +298,7 @@ namespace ARMeilleure.CodeGen.X86
// - The dividend is always in RDX:RAX.
// - The result is always in RAX.
// - Additionally it also writes the remainder in RDX.
if (dest.Type.IsInteger())
if (dest.Type.IsInteger)
{
Operand src1 = node.GetSource(0);
@@ -466,7 +466,7 @@ namespace ARMeilleure.CodeGen.X86
Operand dest = node.Destination;
Operand source = node.GetSource(0);
Debug.Assert(source.Type.IsInteger(), $"Invalid source type \"{source.Type}\".");
Debug.Assert(source.Type.IsInteger, $"Invalid source type \"{source.Type}\".");
Operation currentNode = node;
@@ -654,10 +654,10 @@ namespace ARMeilleure.CodeGen.X86
switch (operation.Instruction)
{
case Instruction.Add:
return !HardwareCapabilities.SupportsVexEncoding && !operation.Destination.Type.IsInteger();
return !HardwareCapabilities.SupportsVexEncoding && !operation.Destination.Type.IsInteger;
case Instruction.Multiply:
case Instruction.Subtract:
return !HardwareCapabilities.SupportsVexEncoding || operation.Destination.Type.IsInteger();
return !HardwareCapabilities.SupportsVexEncoding || operation.Destination.Type.IsInteger;
case Instruction.BitwiseAnd:
case Instruction.BitwiseExclusiveOr:
@@ -672,7 +672,7 @@ namespace ARMeilleure.CodeGen.X86
return true;
case Instruction.Divide:
return !HardwareCapabilities.SupportsVexEncoding && !operation.Destination.Type.IsInteger();
return !HardwareCapabilities.SupportsVexEncoding && !operation.Destination.Type.IsInteger;
case Instruction.VectorInsert:
case Instruction.VectorInsert16:

View File

@@ -35,7 +35,7 @@ namespace ARMeilleure.CodeGen.X86
bool passOnReg;
if (source.Type.IsInteger())
if (source.Type.IsInteger)
{
passOnReg = intCount < intMax;
}
@@ -62,7 +62,7 @@ namespace ARMeilleure.CodeGen.X86
if (passOnReg)
{
Operand argReg = source.Type.IsInteger()
Operand argReg = source.Type.IsInteger
? Gpr(CallingConvention.GetIntArgumentRegister(intCount++), source.Type)
: Xmm(CallingConvention.GetVecArgumentRegister(vecCount++), source.Type);
@@ -80,7 +80,7 @@ namespace ARMeilleure.CodeGen.X86
InsertConstantRegCopies(nodes, nodes.AddBefore(node, spillOp));
stackOffset += source.Type.GetSizeInBytes();
stackOffset += source.Type.ByteSize;
}
}
@@ -102,7 +102,7 @@ namespace ARMeilleure.CodeGen.X86
}
else
{
Operand retReg = dest.Type.IsInteger()
Operand retReg = dest.Type.IsInteger
? Gpr(CallingConvention.GetIntReturnRegister(), dest.Type)
: Xmm(CallingConvention.GetVecReturnRegister(), dest.Type);
@@ -137,7 +137,7 @@ namespace ARMeilleure.CodeGen.X86
bool passOnReg;
if (source.Type.IsInteger())
if (source.Type.IsInteger)
{
passOnReg = intCount + 1 < intMax;
}
@@ -160,7 +160,7 @@ namespace ARMeilleure.CodeGen.X86
if (passOnReg)
{
Operand argReg = source.Type.IsInteger()
Operand argReg = source.Type.IsInteger
? Gpr(CallingConvention.GetIntArgumentRegister(intCount++), source.Type)
: Xmm(CallingConvention.GetVecArgumentRegister(vecCount++), source.Type);
@@ -210,7 +210,7 @@ namespace ARMeilleure.CodeGen.X86
{
OperandType argType = cctx.FuncArgTypes[cIndex];
if (argType.IsInteger())
if (argType.IsInteger)
{
intCount++;
}
@@ -226,7 +226,7 @@ namespace ARMeilleure.CodeGen.X86
bool passOnReg;
if (source.Type.IsInteger())
if (source.Type.IsInteger)
{
passOnReg = intCount < CallingConvention.GetIntArgumentsOnRegsCount();
}
@@ -265,7 +265,7 @@ namespace ARMeilleure.CodeGen.X86
{
Operand pArg = Local(dest.Type);
Operand argReg = dest.Type.IsInteger()
Operand argReg = dest.Type.IsInteger
? Gpr(CallingConvention.GetIntArgumentRegister(intCount), dest.Type)
: Xmm(CallingConvention.GetVecArgumentRegister(vecCount), dest.Type);
@@ -320,7 +320,7 @@ namespace ARMeilleure.CodeGen.X86
}
else
{
Operand retReg = source.Type.IsInteger()
Operand retReg = source.Type.IsInteger
? Gpr(CallingConvention.GetIntReturnRegister(), source.Type)
: Xmm(CallingConvention.GetVecReturnRegister(), source.Type);

View File

@@ -40,7 +40,7 @@ namespace ARMeilleure.CodeGen.X86
if (dest != default && dest.Type == OperandType.V128)
{
int stackOffset = AllocateOnStack(dest.Type.GetSizeInBytes());
int stackOffset = AllocateOnStack(dest.Type.ByteSize);
arg0Reg = Gpr(CallingConvention.GetIntArgumentRegister(0), OperandType.I64);
@@ -76,7 +76,7 @@ namespace ARMeilleure.CodeGen.X86
{
Operand stackAddr = Local(OperandType.I64);
int stackOffset = AllocateOnStack(source.Type.GetSizeInBytes());
int stackOffset = AllocateOnStack(source.Type.ByteSize);
nodes.AddBefore(node, Operation(Instruction.StackAlloc, stackAddr, Const(stackOffset)));
@@ -96,7 +96,7 @@ namespace ARMeilleure.CodeGen.X86
int argIndex = index + retArgs;
if (source.Type.IsInteger())
if (source.Type.IsInteger)
{
argReg = Gpr(CallingConvention.GetIntArgumentRegister(argIndex), source.Type);
}
@@ -140,7 +140,7 @@ namespace ARMeilleure.CodeGen.X86
}
else
{
Operand retReg = dest.Type.IsInteger()
Operand retReg = dest.Type.IsInteger
? Gpr(CallingConvention.GetIntReturnRegister(), dest.Type)
: Xmm(CallingConvention.GetVecReturnRegister(), dest.Type);
@@ -171,7 +171,7 @@ namespace ARMeilleure.CodeGen.X86
for (int index = 0; index < argsCount; index++)
{
Operand source = node.GetSource(1 + index);
Operand argReg = source.Type.IsInteger()
Operand argReg = source.Type.IsInteger
? Gpr(CallingConvention.GetIntArgumentRegister(index), source.Type)
: Xmm(CallingConvention.GetVecArgumentRegister(index), source.Type);
@@ -219,7 +219,7 @@ namespace ARMeilleure.CodeGen.X86
{
Operand argReg, pArg;
if (dest.Type.IsInteger())
if (dest.Type.IsInteger)
{
argReg = Gpr(CallingConvention.GetIntArgumentRegister(index), dest.Type);
pArg = Local(dest.Type);
@@ -283,7 +283,7 @@ namespace ARMeilleure.CodeGen.X86
Operand source = node.GetSource(0);
Operand retReg;
if (source.Type.IsInteger())
if (source.Type.IsInteger)
{
retReg = Gpr(CallingConvention.GetIntReturnRegister(), source.Type);
}

View File

@@ -25,9 +25,9 @@ namespace ARMeilleure.CodeGen.X86
static class ComparisonX86Extensions
{
public static X86Condition ToX86Condition(this Comparison comp)
extension(Comparison comparison)
{
return comp switch
public X86Condition X86 => comparison switch
{
#pragma warning disable IDE0055 // Disable formatting
Comparison.Equal => X86Condition.Equal,
@@ -42,7 +42,7 @@ namespace ARMeilleure.CodeGen.X86
Comparison.LessUI => X86Condition.Below,
#pragma warning restore IDE0055
_ => throw new ArgumentException(null, nameof(comp)),
_ => throw new ArgumentException(null, nameof(comparison))
};
}
}

View File

@@ -1,5 +1,3 @@
using System.Diagnostics.CodeAnalysis;
namespace ARMeilleure.CodeGen.X86
{
enum X86Register

View File

@@ -168,7 +168,7 @@ namespace ARMeilleure.Common
{
_allocated.Dispose();
foreach (IntPtr page in _pages.Values)
foreach (nint page in _pages.Values)
{
NativeAllocator.Instance.Free((void*)page);
}

View File

@@ -22,11 +22,11 @@ namespace ARMeilleure.Decoders
static class ConditionExtensions
{
public static Condition Invert(this Condition cond)
extension(Condition condition)
{
// Bit 0 of all conditions is basically a negation bit, so
// inverting this bit has the effect of inverting the condition.
return (Condition)((int)cond ^ 1);
public Condition Inverse => (Condition)((int)condition ^ 1);
}
}
}

View File

@@ -19,7 +19,7 @@ namespace ARMeilleure.Instructions
context.LoadFromContext();
context.Return(Const(op.Address));
InstEmitFlowHelper.EmitReturn(context, Const(op.Address));
}
public static void Svc(ArmEmitterContext context)
@@ -49,7 +49,7 @@ namespace ARMeilleure.Instructions
context.LoadFromContext();
context.Return(Const(op.Address));
InstEmitFlowHelper.EmitReturn(context, Const(op.Address));
}
}
}

View File

@@ -33,7 +33,7 @@ namespace ARMeilleure.Instructions
context.LoadFromContext();
context.Return(Const(context.CurrOp.Address));
InstEmitFlowHelper.EmitReturn(context, Const(context.CurrOp.Address));
}
}
}

View File

@@ -66,7 +66,7 @@ namespace ARMeilleure.Instructions
{
OpCodeBReg op = (OpCodeBReg)context.CurrOp;
context.Return(GetIntOrZR(context, op.Rn));
EmitReturn(context, GetIntOrZR(context, op.Rn));
}
public static void Tbnz(ArmEmitterContext context) => EmitTb(context, onNotZero: true);

View File

@@ -13,6 +13,10 @@ namespace ARMeilleure.Instructions
{
static class InstEmitFlowHelper
{
// How many calls we can have in our call stack before we give up and return to the dispatcher.
// This prevents stack overflows caused by deep recursive calls.
private const int MaxCallDepth = 200;
public static void EmitCondBranch(ArmEmitterContext context, Operand target, Condition cond)
{
if (cond != Condition.Al)
@@ -182,12 +186,7 @@ namespace ARMeilleure.Instructions
{
if (isReturn || context.IsSingleStep)
{
if (target.Type == OperandType.I32)
{
target = context.ZeroExtend32(OperandType.I64, target);
}
context.Return(target);
EmitReturn(context, target);
}
else
{
@@ -195,6 +194,19 @@ namespace ARMeilleure.Instructions
}
}
public static void EmitReturn(ArmEmitterContext context, Operand target)
{
Operand nativeContext = context.LoadArgument(OperandType.I64, 0);
DecreaseCallDepth(context, nativeContext);
if (target.Type == OperandType.I32)
{
target = context.ZeroExtend32(OperandType.I64, target);
}
context.Return(target);
}
private static void EmitTableBranch(ArmEmitterContext context, Operand guestAddress, bool isJump)
{
context.StoreToContext();
@@ -257,6 +269,8 @@ namespace ARMeilleure.Instructions
if (isJump)
{
DecreaseCallDepth(context, nativeContext);
context.Tailcall(hostAddress, nativeContext);
}
else
@@ -278,8 +292,42 @@ namespace ARMeilleure.Instructions
Operand lblContinue = context.GetLabel(nextAddr.Value);
context.BranchIf(lblContinue, returnAddress, nextAddr, Comparison.Equal, BasicBlockFrequency.Cold);
DecreaseCallDepth(context, nativeContext);
context.Return(returnAddress);
}
}
public static void EmitCallDepthCheckAndIncrement(EmitterContext context, Operand guestAddress)
{
if (!Optimizations.EnableDeepCallRecursionProtection)
{
return;
}
Operand nativeContext = context.LoadArgument(OperandType.I64, 0);
Operand callDepthAddr = context.Add(nativeContext, Const((ulong)NativeContext.GetCallDepthOffset()));
Operand currentCallDepth = context.Load(OperandType.I32, callDepthAddr);
Operand lblDoCall = Label();
context.BranchIf(lblDoCall, currentCallDepth, Const(MaxCallDepth), Comparison.LessUI);
context.Store(callDepthAddr, context.Subtract(currentCallDepth, Const(1)));
context.Return(guestAddress);
context.MarkLabel(lblDoCall);
context.Store(callDepthAddr, context.Add(currentCallDepth, Const(1)));
}
private static void DecreaseCallDepth(EmitterContext context, Operand nativeContext)
{
if (!Optimizations.EnableDeepCallRecursionProtection)
{
return;
}
Operand callDepthAddr = context.Add(nativeContext, Const((ulong)NativeContext.GetCallDepthOffset()));
Operand currentCallDepth = context.Load(OperandType.I32, callDepthAddr);
context.Store(callDepthAddr, context.Subtract(currentCallDepth, Const(1)));
}
}
}

View File

@@ -16,7 +16,7 @@ namespace ARMeilleure.Instructions
public static Operand EmitCrc32(ArmEmitterContext context, Operand crc, Operand value, int size, bool castagnoli)
{
Debug.Assert(crc.Type.IsInteger() && value.Type.IsInteger());
Debug.Assert(crc.Type.IsInteger && value.Type.IsInteger);
Debug.Assert(size is >= 0 and < 4);
Debug.Assert((size < 3) || (value.Type == OperandType.I64));

View File

@@ -157,7 +157,7 @@ namespace ARMeilleure.Instructions
context.Copy(temp, value);
if (!context.Memory.Type.IsHostMappedOrTracked())
if (!context.Memory.Type.IsHostMappedOrTracked)
{
context.Branch(lblEnd);
@@ -198,7 +198,7 @@ namespace ARMeilleure.Instructions
SetInt(context, rt, value);
if (!context.Memory.Type.IsHostMappedOrTracked())
if (!context.Memory.Type.IsHostMappedOrTracked)
{
context.Branch(lblEnd);
@@ -265,7 +265,7 @@ namespace ARMeilleure.Instructions
context.Copy(GetVec(rt), value);
if (!context.Memory.Type.IsHostMappedOrTracked())
if (!context.Memory.Type.IsHostMappedOrTracked)
{
context.Branch(lblEnd);
@@ -312,7 +312,7 @@ namespace ARMeilleure.Instructions
break;
}
if (!context.Memory.Type.IsHostMappedOrTracked())
if (!context.Memory.Type.IsHostMappedOrTracked)
{
context.Branch(lblEnd);
@@ -385,7 +385,7 @@ namespace ARMeilleure.Instructions
break;
}
if (!context.Memory.Type.IsHostMappedOrTracked())
if (!context.Memory.Type.IsHostMappedOrTracked)
{
context.Branch(lblEnd);
@@ -399,11 +399,11 @@ namespace ARMeilleure.Instructions
public static Operand EmitPtPointerLoad(ArmEmitterContext context, Operand address, Operand lblSlowPath, bool write, int size)
{
if (context.Memory.Type.IsHostMapped())
if (context.Memory.Type.IsHostMapped)
{
return EmitHostMappedPointer(context, address);
}
else if (context.Memory.Type.IsHostTracked())
else if (context.Memory.Type.IsHostTracked)
{
if (address.Type == OperandType.I32)
{

View File

@@ -2,7 +2,6 @@ using ARMeilleure.Decoders;
using ARMeilleure.IntermediateRepresentation;
using ARMeilleure.Translation;
using System;
using System.Diagnostics.CodeAnalysis;
using static ARMeilleure.Instructions.InstEmitHelper;
namespace ARMeilleure.Instructions

View File

@@ -1,692 +0,0 @@
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)
{
if (shift <= 63)
{
return value >> shift;
}
else /* if (shift == 64) */
{
if (value < 0L)
{
return -1L;
}
else /* if (value >= 0L) */
{
return 0L;
}
}
}
else /* if (roundConst == 1L << (shift - 1)) */
{
if (shift <= 63)
{
long add = value + roundConst;
if ((~value & (value ^ add)) < 0L)
{
return (long)((ulong)add >> shift);
}
else
{
return add >> shift;
}
}
else /* if (shift == 64) */
{
return 0L;
}
}
}
[UnmanagedCallersOnly]
public static ulong UnsignedShrImm64(ulong value, long roundConst, int shift)
{
if (roundConst == 0L)
{
if (shift <= 63)
{
return value >> shift;
}
else /* if (shift == 64) */
{
return 0UL;
}
}
else /* if (roundConst == 1L << (shift - 1)) */
{
ulong add = value + (ulong)roundConst;
if ((add < value) && (add < (ulong)roundConst))
{
if (shift <= 63)
{
return (add >> shift) | (0x8000000000000000UL >> (shift - 1));
}
else /* if (shift == 64) */
{
return 1UL;
}
}
else
{
if (shift <= 63)
{
return add >> shift;
}
else /* if (shift == 64) */
{
return 0UL;
}
}
}
}
#endregion
#region "Saturation"
[UnmanagedCallersOnly]
public static int SatF32ToS32(float value)
{
if (float.IsNaN(value))
{
return 0;
}
return value >= int.MaxValue ? int.MaxValue :
value <= int.MinValue ? int.MinValue : (int)value;
}
[UnmanagedCallersOnly]
public static long SatF32ToS64(float value)
{
if (float.IsNaN(value))
{
return 0;
}
return value >= long.MaxValue ? long.MaxValue :
value <= long.MinValue ? long.MinValue : (long)value;
}
[UnmanagedCallersOnly]
public static uint SatF32ToU32(float value)
{
if (float.IsNaN(value))
{
return 0;
}
return value >= uint.MaxValue ? uint.MaxValue :
value <= uint.MinValue ? uint.MinValue : (uint)value;
}
[UnmanagedCallersOnly]
public static ulong SatF32ToU64(float value)
{
if (float.IsNaN(value))
{
return 0;
}
return value >= ulong.MaxValue ? ulong.MaxValue :
value <= ulong.MinValue ? ulong.MinValue : (ulong)value;
}
[UnmanagedCallersOnly]
public static int SatF64ToS32(double value)
{
if (double.IsNaN(value))
{
return 0;
}
return value >= int.MaxValue ? int.MaxValue :
value <= int.MinValue ? int.MinValue : (int)value;
}
[UnmanagedCallersOnly]
public static long SatF64ToS64(double value)
{
if (double.IsNaN(value))
{
return 0;
}
return value >= long.MaxValue ? long.MaxValue :
value <= long.MinValue ? long.MinValue : (long)value;
}
[UnmanagedCallersOnly]
public static uint SatF64ToU32(double value)
{
if (double.IsNaN(value))
{
return 0;
}
return value >= uint.MaxValue ? uint.MaxValue :
value <= uint.MinValue ? uint.MinValue : (uint)value;
}
[UnmanagedCallersOnly]
public static ulong SatF64ToU64(double value)
{
if (double.IsNaN(value))
{
return 0;
}
return value >= ulong.MaxValue ? ulong.MaxValue :
value <= ulong.MinValue ? ulong.MinValue : (ulong)value;
}
#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;
int highBit = size - 2;
for (int bit = highBit; bit >= 0; bit--)
{
if (((int)(value >> bit) & 0b1) != 0)
{
return (ulong)(highBit - bit);
}
}
return (ulong)(size - 1);
}
private static ReadOnlySpan<byte> ClzNibbleTbl => [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)
{
return (ulong)size;
}
int nibbleIdx = size;
int preCount, count = 0;
do
{
nibbleIdx -= 4;
preCount = ClzNibbleTbl[(int)(value >> nibbleIdx) & 0b1111];
count += preCount;
}
while (preCount == 4);
return (ulong)count;
}
#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);
}
private static V128 TblOrTbx(V128 dest, V128 vector, int bytes, params ReadOnlySpan<V128> tb)
{
byte[] res = new byte[16];
if (dest != default)
{
Buffer.BlockCopy(dest.ToArray(), 0, res, 0, bytes);
}
byte[] table = new byte[tb.Length * 16];
for (byte index = 0; index < tb.Length; index++)
{
Buffer.BlockCopy(tb[index].ToArray(), 0, table, index * 16, 16);
}
byte[] v = vector.ToArray();
for (byte index = 0; index < bytes; index++)
{
byte tblIndex = v[index];
if (tblIndex < table.Length)
{
res[index] = table[tblIndex];
}
}
return new V128(res);
}
#endregion
#region "Crc32"
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)
{
crc = Crc32(crc, poly, (byte)(val >> 0));
crc = Crc32(crc, poly, (byte)(val >> 8));
return crc;
}
private static uint Crc32w(uint crc, uint poly, uint val)
{
crc = Crc32(crc, poly, (byte)(val >> 0));
crc = Crc32(crc, poly, (byte)(val >> 8));
crc = Crc32(crc, poly, (byte)(val >> 16));
crc = Crc32(crc, poly, (byte)(val >> 24));
return crc;
}
private static uint Crc32x(uint crc, uint poly, ulong val)
{
crc = Crc32(crc, poly, (byte)(val >> 0));
crc = Crc32(crc, poly, (byte)(val >> 8));
crc = Crc32(crc, poly, (byte)(val >> 16));
crc = Crc32(crc, poly, (byte)(val >> 24));
crc = Crc32(crc, poly, (byte)(val >> 32));
crc = Crc32(crc, poly, (byte)(val >> 40));
crc = Crc32(crc, poly, (byte)(val >> 48));
crc = Crc32(crc, poly, (byte)(val >> 56));
return crc;
}
private static uint Crc32(uint crc, uint poly, byte val)
{
crc ^= val;
for (int bit = 7; bit >= 0; bit--)
{
uint mask = (uint)(-(int)(crc & 1));
crc = (crc >> 1) ^ (poly & mask);
}
return crc;
}
#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);
}
#endregion
#region "Sha1"
[UnmanagedCallersOnly]
public static V128 HashChoose(V128 hash_abcd, uint hash_e, V128 wk)
{
for (int e = 0; e <= 3; e++)
{
uint t = ShaChoose(hash_abcd.Extract<uint>(1),
hash_abcd.Extract<uint>(2),
hash_abcd.Extract<uint>(3));
hash_e += Rol(hash_abcd.Extract<uint>(0), 5) + t + wk.Extract<uint>(e);
t = Rol(hash_abcd.Extract<uint>(1), 30);
hash_abcd.Insert(1, t);
Rol32_160(ref hash_e, ref hash_abcd);
}
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++)
{
uint t = ShaMajority(hash_abcd.Extract<uint>(1),
hash_abcd.Extract<uint>(2),
hash_abcd.Extract<uint>(3));
hash_e += Rol(hash_abcd.Extract<uint>(0), 5) + t + wk.Extract<uint>(e);
t = Rol(hash_abcd.Extract<uint>(1), 30);
hash_abcd.Insert(1, t);
Rol32_160(ref hash_e, ref hash_abcd);
}
return hash_abcd;
}
[UnmanagedCallersOnly]
public static V128 HashParity(V128 hash_abcd, uint hash_e, V128 wk)
{
for (int e = 0; e <= 3; e++)
{
uint t = ShaParity(hash_abcd.Extract<uint>(1),
hash_abcd.Extract<uint>(2),
hash_abcd.Extract<uint>(3));
hash_e += Rol(hash_abcd.Extract<uint>(0), 5) + t + wk.Extract<uint>(e);
t = Rol(hash_abcd.Extract<uint>(1), 30);
hash_abcd.Insert(1, t);
Rol32_160(ref hash_e, ref hash_abcd);
}
return hash_abcd;
}
[UnmanagedCallersOnly]
public static V128 Sha1SchedulePart1(V128 w0_3, V128 w4_7, V128 w8_11)
{
ulong t2 = w4_7.Extract<ulong>(0);
ulong t1 = w0_3.Extract<ulong>(1);
V128 result = new(t1, t2);
return result ^ (w0_3 ^ w8_11);
}
[UnmanagedCallersOnly]
public static V128 Sha1SchedulePart2(V128 tw0_3, V128 w12_15)
{
V128 t = tw0_3 ^ (w12_15 >> 32);
uint tE0 = t.Extract<uint>(0);
uint tE1 = t.Extract<uint>(1);
uint tE2 = t.Extract<uint>(2);
uint tE3 = t.Extract<uint>(3);
return new V128(tE0.Rol(1), tE1.Rol(1), tE2.Rol(1), tE3.Rol(1) ^ tE0.Rol(2));
}
private static void Rol32_160(ref uint y, ref V128 x)
{
uint xE3 = x.Extract<uint>(3);
x <<= 32;
x.Insert(0, y);
y = xE3;
}
private static uint ShaChoose(uint x, uint y, uint z)
{
return ((y ^ z) & x) ^ z;
}
private static uint ShaMajority(uint x, uint y, uint z)
{
return (x & y) | ((x | y) & z);
}
private static uint ShaParity(uint x, uint y, uint z)
{
return x ^ y ^ z;
}
private static uint Rol(this uint value, int count)
{
return (value << count) | (value >> (32 - count));
}
#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();
for (int e = 0; e <= 3; e++)
{
uint elt = (e <= 2 ? w0_3 : w4_7).Extract<uint>(e <= 2 ? e + 1 : 0);
elt = elt.Ror(7) ^ elt.Ror(18) ^ elt.Lsr(3);
elt += w0_3.Extract<uint>(e);
result.Insert(e, elt);
}
return result;
}
[UnmanagedCallersOnly]
public static V128 Sha256SchedulePart2(V128 w0_3, V128 w8_11, V128 w12_15)
{
V128 result = new();
ulong t1 = w12_15.Extract<ulong>(1);
for (int e = 0; e <= 1; e++)
{
uint elt = t1.ULongPart(e);
elt = elt.Ror(17) ^ elt.Ror(19) ^ elt.Lsr(10);
elt += w0_3.Extract<uint>(e) + w8_11.Extract<uint>(e + 1);
result.Insert(e, elt);
}
t1 = result.Extract<ulong>(0);
for (int e = 2; e <= 3; e++)
{
uint elt = t1.ULongPart(e - 2);
elt = elt.Ror(17) ^ elt.Ror(19) ^ elt.Lsr(10);
elt += w0_3.Extract<uint>(e) + (e == 2 ? w8_11 : w12_15).Extract<uint>(e == 2 ? 3 : 0);
result.Insert(e, elt);
}
return result;
}
private static V128 Sha256Hash(V128 x, V128 y, V128 w, bool part1)
{
for (int e = 0; e <= 3; e++)
{
uint chs = ShaChoose(y.Extract<uint>(0),
y.Extract<uint>(1),
y.Extract<uint>(2));
uint maj = ShaMajority(x.Extract<uint>(0),
x.Extract<uint>(1),
x.Extract<uint>(2));
uint t1 = y.Extract<uint>(3) + ShaHashSigma1(y.Extract<uint>(0)) + chs + w.Extract<uint>(e);
uint t2 = t1 + x.Extract<uint>(3);
x.Insert(3, t2);
t2 = t1 + ShaHashSigma0(x.Extract<uint>(0)) + maj;
y.Insert(3, t2);
Rol32_256(ref y, ref x);
}
return part1 ? x : y;
}
private static void Rol32_256(ref V128 y, ref V128 x)
{
uint yE3 = y.Extract<uint>(3);
uint xE3 = x.Extract<uint>(3);
y <<= 32;
x <<= 32;
y.Insert(0, xE3);
x.Insert(0, yE3);
}
private static uint ShaHashSigma0(uint x)
{
return x.Ror(2) ^ x.Ror(13) ^ x.Ror(22);
}
private static uint ShaHashSigma1(uint x)
{
return x.Ror(6) ^ x.Ror(11) ^ x.Ror(25);
}
private static uint Ror(this uint value, int count)
{
return (value >> count) | (value << (32 - count));
}
private static uint Lsr(this uint value, int count)
{
return value >> count;
}
private static uint ULongPart(this ulong value, int part)
{
return part == 0
? (uint)(value & 0xFFFFFFFFUL)
: (uint)(value >> 32);
}
#endregion
[UnmanagedCallersOnly]
public static V128 PolynomialMult64_128(ulong op1, ulong op2)
{
V128 result = V128.Zero;
V128 op2_128 = new(op2, 0);
for (int i = 0; i < 64; i++)
{
if (((op1 >> i) & 1) == 1)
{
result ^= op2_128 << i;
}
}
return result;
}
}
}

View File

@@ -0,0 +1,32 @@
using ARMeilleure.State;
using System.Runtime.InteropServices;
namespace ARMeilleure.Instructions
{
static partial class SoftFallback
{
[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);
}
}
}

View File

@@ -0,0 +1,50 @@
using System;
using System.Runtime.InteropServices;
namespace ARMeilleure.Instructions
{
static partial class SoftFallback
{
[UnmanagedCallersOnly]
public static ulong CountLeadingSigns(ulong value, int size) // size is 8, 16, 32 or 64 (SIMD&FP or Base Inst.).
{
value ^= value >> 1;
int highBit = size - 2;
for (int bit = highBit; bit >= 0; bit--)
{
if (((int)(value >> bit) & 0b1) != 0)
{
return (ulong)(highBit - bit);
}
}
return (ulong)(size - 1);
}
private static ReadOnlySpan<byte> ClzNibbleTbl => [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)
{
return (ulong)size;
}
int nibbleIdx = size;
int preCount, count = 0;
do
{
nibbleIdx -= 4;
preCount = ClzNibbleTbl[(int)(value >> nibbleIdx) & 0b1111];
count += preCount;
}
while (preCount == 4);
return (ulong)count;
}
}
}

View File

@@ -0,0 +1,74 @@
using System.Runtime.InteropServices;
namespace ARMeilleure.Instructions
{
static partial class SoftFallback
{
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)
{
crc = Crc32(crc, poly, (byte)(val >> 0));
crc = Crc32(crc, poly, (byte)(val >> 8));
return crc;
}
private static uint Crc32w(uint crc, uint poly, uint val)
{
crc = Crc32(crc, poly, (byte)(val >> 0));
crc = Crc32(crc, poly, (byte)(val >> 8));
crc = Crc32(crc, poly, (byte)(val >> 16));
crc = Crc32(crc, poly, (byte)(val >> 24));
return crc;
}
private static uint Crc32x(uint crc, uint poly, ulong val)
{
crc = Crc32(crc, poly, (byte)(val >> 0));
crc = Crc32(crc, poly, (byte)(val >> 8));
crc = Crc32(crc, poly, (byte)(val >> 16));
crc = Crc32(crc, poly, (byte)(val >> 24));
crc = Crc32(crc, poly, (byte)(val >> 32));
crc = Crc32(crc, poly, (byte)(val >> 40));
crc = Crc32(crc, poly, (byte)(val >> 48));
crc = Crc32(crc, poly, (byte)(val >> 56));
return crc;
}
private static uint Crc32(uint crc, uint poly, byte val)
{
crc ^= val;
for (int bit = 7; bit >= 0; bit--)
{
uint mask = (uint)(-(int)(crc & 1));
crc = (crc >> 1) ^ (poly & mask);
}
return crc;
}
}
}

View File

@@ -0,0 +1,103 @@
using System.Runtime.InteropServices;
namespace ARMeilleure.Instructions
{
static partial class SoftFallback
{
[UnmanagedCallersOnly]
public static int SatF32ToS32(float value)
{
if (float.IsNaN(value))
{
return 0;
}
return value >= int.MaxValue ? int.MaxValue :
value <= int.MinValue ? int.MinValue : (int)value;
}
[UnmanagedCallersOnly]
public static long SatF32ToS64(float value)
{
if (float.IsNaN(value))
{
return 0;
}
return value >= long.MaxValue ? long.MaxValue :
value <= long.MinValue ? long.MinValue : (long)value;
}
[UnmanagedCallersOnly]
public static uint SatF32ToU32(float value)
{
if (float.IsNaN(value))
{
return 0;
}
return value >= uint.MaxValue ? uint.MaxValue :
value <= uint.MinValue ? uint.MinValue : (uint)value;
}
[UnmanagedCallersOnly]
public static ulong SatF32ToU64(float value)
{
if (float.IsNaN(value))
{
return 0;
}
return value >= ulong.MaxValue ? ulong.MaxValue :
value <= ulong.MinValue ? ulong.MinValue : (ulong)value;
}
[UnmanagedCallersOnly]
public static int SatF64ToS32(double value)
{
if (double.IsNaN(value))
{
return 0;
}
return value >= int.MaxValue ? int.MaxValue :
value <= int.MinValue ? int.MinValue : (int)value;
}
[UnmanagedCallersOnly]
public static long SatF64ToS64(double value)
{
if (double.IsNaN(value))
{
return 0;
}
return value >= long.MaxValue ? long.MaxValue :
value <= long.MinValue ? long.MinValue : (long)value;
}
[UnmanagedCallersOnly]
public static uint SatF64ToU32(double value)
{
if (double.IsNaN(value))
{
return 0;
}
return value >= uint.MaxValue ? uint.MaxValue :
value <= uint.MinValue ? uint.MinValue : (uint)value;
}
[UnmanagedCallersOnly]
public static ulong SatF64ToU64(double value)
{
if (double.IsNaN(value))
{
return 0;
}
return value >= ulong.MaxValue ? ulong.MaxValue :
value <= ulong.MinValue ? ulong.MinValue : (ulong)value;
}
}
}

View File

@@ -0,0 +1,131 @@
using ARMeilleure.State;
using System.Runtime.InteropServices;
namespace ARMeilleure.Instructions
{
static partial class SoftFallback
{
[UnmanagedCallersOnly]
public static V128 HashChoose(V128 hash_abcd, uint hash_e, V128 wk)
{
for (int e = 0; e <= 3; e++)
{
uint t = ShaChoose(hash_abcd.Extract<uint>(1),
hash_abcd.Extract<uint>(2),
hash_abcd.Extract<uint>(3));
hash_e += Rol(hash_abcd.Extract<uint>(0), 5) + t + wk.Extract<uint>(e);
t = Rol(hash_abcd.Extract<uint>(1), 30);
hash_abcd.Insert(1, t);
Rol32_160(ref hash_e, ref hash_abcd);
}
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++)
{
uint t = ShaMajority(hash_abcd.Extract<uint>(1),
hash_abcd.Extract<uint>(2),
hash_abcd.Extract<uint>(3));
hash_e += Rol(hash_abcd.Extract<uint>(0), 5) + t + wk.Extract<uint>(e);
t = Rol(hash_abcd.Extract<uint>(1), 30);
hash_abcd.Insert(1, t);
Rol32_160(ref hash_e, ref hash_abcd);
}
return hash_abcd;
}
[UnmanagedCallersOnly]
public static V128 HashParity(V128 hash_abcd, uint hash_e, V128 wk)
{
for (int e = 0; e <= 3; e++)
{
uint t = ShaParity(hash_abcd.Extract<uint>(1),
hash_abcd.Extract<uint>(2),
hash_abcd.Extract<uint>(3));
hash_e += Rol(hash_abcd.Extract<uint>(0), 5) + t + wk.Extract<uint>(e);
t = Rol(hash_abcd.Extract<uint>(1), 30);
hash_abcd.Insert(1, t);
Rol32_160(ref hash_e, ref hash_abcd);
}
return hash_abcd;
}
[UnmanagedCallersOnly]
public static V128 Sha1SchedulePart1(V128 w0_3, V128 w4_7, V128 w8_11)
{
ulong t2 = w4_7.Extract<ulong>(0);
ulong t1 = w0_3.Extract<ulong>(1);
V128 result = new(t1, t2);
return result ^ (w0_3 ^ w8_11);
}
[UnmanagedCallersOnly]
public static V128 Sha1SchedulePart2(V128 tw0_3, V128 w12_15)
{
V128 t = tw0_3 ^ (w12_15 >> 32);
uint tE0 = t.Extract<uint>(0);
uint tE1 = t.Extract<uint>(1);
uint tE2 = t.Extract<uint>(2);
uint tE3 = t.Extract<uint>(3);
return new V128(tE0.Rol(1), tE1.Rol(1), tE2.Rol(1), tE3.Rol(1) ^ tE0.Rol(2));
}
private static void Rol32_160(ref uint y, ref V128 x)
{
uint xE3 = x.Extract<uint>(3);
x <<= 32;
x.Insert(0, y);
y = xE3;
}
private static uint ShaChoose(uint x, uint y, uint z)
{
return ((y ^ z) & x) ^ z;
}
private static uint ShaMajority(uint x, uint y, uint z)
{
return (x & y) | ((x | y) & z);
}
private static uint ShaParity(uint x, uint y, uint z)
{
return x ^ y ^ z;
}
private static uint Rol(this uint value, int count)
{
return (value << count) | (value >> (32 - count));
}
}
}

View File

@@ -0,0 +1,140 @@
using ARMeilleure.State;
using System.Runtime.InteropServices;
namespace ARMeilleure.Instructions
{
static partial class SoftFallback
{
[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();
for (int e = 0; e <= 3; e++)
{
uint elt = (e <= 2 ? w0_3 : w4_7).Extract<uint>(e <= 2 ? e + 1 : 0);
elt = elt.Ror(7) ^ elt.Ror(18) ^ elt.Lsr(3);
elt += w0_3.Extract<uint>(e);
result.Insert(e, elt);
}
return result;
}
[UnmanagedCallersOnly]
public static V128 Sha256SchedulePart2(V128 w0_3, V128 w8_11, V128 w12_15)
{
V128 result = new();
ulong t1 = w12_15.Extract<ulong>(1);
for (int e = 0; e <= 1; e++)
{
uint elt = t1.ULongPart(e);
elt = elt.Ror(17) ^ elt.Ror(19) ^ elt.Lsr(10);
elt += w0_3.Extract<uint>(e) + w8_11.Extract<uint>(e + 1);
result.Insert(e, elt);
}
t1 = result.Extract<ulong>(0);
for (int e = 2; e <= 3; e++)
{
uint elt = t1.ULongPart(e - 2);
elt = elt.Ror(17) ^ elt.Ror(19) ^ elt.Lsr(10);
elt += w0_3.Extract<uint>(e) + (e == 2 ? w8_11 : w12_15).Extract<uint>(e == 2 ? 3 : 0);
result.Insert(e, elt);
}
return result;
}
private static V128 Sha256Hash(V128 x, V128 y, V128 w, bool part1)
{
for (int e = 0; e <= 3; e++)
{
uint chs = ShaChoose(y.Extract<uint>(0),
y.Extract<uint>(1),
y.Extract<uint>(2));
uint maj = ShaMajority(x.Extract<uint>(0),
x.Extract<uint>(1),
x.Extract<uint>(2));
uint t1 = y.Extract<uint>(3) + ShaHashSigma1(y.Extract<uint>(0)) + chs + w.Extract<uint>(e);
uint t2 = t1 + x.Extract<uint>(3);
x.Insert(3, t2);
t2 = t1 + ShaHashSigma0(x.Extract<uint>(0)) + maj;
y.Insert(3, t2);
Rol32_256(ref y, ref x);
}
return part1 ? x : y;
}
private static void Rol32_256(ref V128 y, ref V128 x)
{
uint yE3 = y.Extract<uint>(3);
uint xE3 = x.Extract<uint>(3);
y <<= 32;
x <<= 32;
y.Insert(0, xE3);
x.Insert(0, yE3);
}
private static uint ShaHashSigma0(uint x)
{
return x.Ror(2) ^ x.Ror(13) ^ x.Ror(22);
}
private static uint ShaHashSigma1(uint x)
{
return x.Ror(6) ^ x.Ror(11) ^ x.Ror(25);
}
private static uint Ror(this uint value, int count)
{
return (value >> count) | (value << (32 - count));
}
private static uint Lsr(this uint value, int count)
{
return value >> count;
}
private static uint ULongPart(this ulong value, int part)
{
return part == 0
? (uint)(value & 0xFFFFFFFFUL)
: (uint)(value >> 32);
}
}
}

View File

@@ -0,0 +1,93 @@
using System.Runtime.InteropServices;
namespace ARMeilleure.Instructions
{
static partial class SoftFallback
{
[UnmanagedCallersOnly]
public static long SignedShrImm64(long value, long roundConst, int shift)
{
if (roundConst == 0L)
{
if (shift <= 63)
{
return value >> shift;
}
else /* if (shift == 64) */
{
if (value < 0L)
{
return -1L;
}
else /* if (value >= 0L) */
{
return 0L;
}
}
}
else /* if (roundConst == 1L << (shift - 1)) */
{
if (shift <= 63)
{
long add = value + roundConst;
if ((~value & (value ^ add)) < 0L)
{
return (long)((ulong)add >> shift);
}
else
{
return add >> shift;
}
}
else /* if (shift == 64) */
{
return 0L;
}
}
}
[UnmanagedCallersOnly]
public static ulong UnsignedShrImm64(ulong value, long roundConst, int shift)
{
if (roundConst == 0L)
{
if (shift <= 63)
{
return value >> shift;
}
else /* if (shift == 64) */
{
return 0UL;
}
}
else /* if (roundConst == 1L << (shift - 1)) */
{
ulong add = value + (ulong)roundConst;
if ((add < value) && (add < (ulong)roundConst))
{
if (shift <= 63)
{
return (add >> shift) | (0x8000000000000000UL >> (shift - 1));
}
else /* if (shift == 64) */
{
return 1UL;
}
}
else
{
if (shift <= 63)
{
return add >> shift;
}
else /* if (shift == 64) */
{
return 0UL;
}
}
}
}
}
}

View File

@@ -0,0 +1,88 @@
using ARMeilleure.State;
using System;
using System.Runtime.InteropServices;
namespace ARMeilleure.Instructions
{
static partial class SoftFallback
{
[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);
}
private static V128 TblOrTbx(V128 dest, V128 vector, int bytes, params ReadOnlySpan<V128> tb)
{
byte[] res = new byte[16];
if (dest != default)
{
Buffer.BlockCopy(dest.ToArray(), 0, res, 0, bytes);
}
byte[] table = new byte[tb.Length * 16];
for (byte index = 0; index < tb.Length; index++)
{
Buffer.BlockCopy(tb[index].ToArray(), 0, table, index * 16, 16);
}
byte[] v = vector.ToArray();
for (byte index = 0; index < bytes; index++)
{
byte tblIndex = v[index];
if (tblIndex < table.Length)
{
res[index] = table[tblIndex];
}
}
return new V128(res);
}
}
}

View File

@@ -0,0 +1,26 @@
using ARMeilleure.State;
using System.Runtime.InteropServices;
namespace ARMeilleure.Instructions
{
static partial class SoftFallback
{
[UnmanagedCallersOnly]
public static V128 PolynomialMult64_128(ulong op1, ulong op2)
{
V128 result = V128.Zero;
V128 op2_128 = new(op2, 0);
for (int i = 0; i < 64; i++)
{
if (((op1 >> i) & 1) == 1)
{
result ^= op2_128 << i;
}
}
return result;
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,111 @@
using ARMeilleure.State;
using System;
using System.Diagnostics;
namespace ARMeilleure.Instructions
{
static class SoftFloat
{
static SoftFloat()
{
RecipEstimateTable = BuildRecipEstimateTable();
RecipSqrtEstimateTable = BuildRecipSqrtEstimateTable();
}
public static readonly byte[] RecipEstimateTable;
public static readonly byte[] RecipSqrtEstimateTable;
private static byte[] BuildRecipEstimateTable()
{
byte[] tbl = new byte[256];
for (int idx = 0; idx < 256; idx++)
{
uint src = (uint)idx + 256u;
Debug.Assert(src is >= 256u and < 512u);
src = (src << 1) + 1u;
uint aux = (1u << 19) / src;
uint dst = (aux + 1u) >> 1;
Debug.Assert(dst is >= 256u and < 512u);
tbl[idx] = (byte)(dst - 256u);
}
return tbl;
}
private static byte[] BuildRecipSqrtEstimateTable()
{
byte[] tbl = new byte[384];
for (int idx = 0; idx < 384; idx++)
{
uint src = (uint)idx + 128u;
Debug.Assert(src is >= 128u and < 512u);
if (src < 256u)
{
src = (src << 1) + 1u;
}
else
{
src = (src >> 1) << 1;
src = (src + 1u) << 1;
}
uint aux = 512u;
while (src * (aux + 1u) * (aux + 1u) < (1u << 28))
{
aux++;
}
uint dst = (aux + 1u) >> 1;
Debug.Assert(dst is >= 256u and < 512u);
tbl[idx] = (byte)(dst - 256u);
}
return tbl;
}
public static void FPProcessException(FPException exc, ExecutionContext context)
{
FPProcessException(exc, context, context.Fpcr);
}
public static void FPProcessException(FPException exc, ExecutionContext context, FPCR fpcr)
{
int enable = (int)exc + 8;
if ((fpcr & (FPCR)(1 << enable)) != 0)
{
throw new NotImplementedException("Floating-point trap handling.");
}
else
{
context.Fpsr |= (FPSR)(1 << (int)exc);
}
}
extension(FPCR fpcr)
{
public FPRoundingMode RoundingMode
{
get
{
const int RModeShift = 22;
return (FPRoundingMode)(((uint)fpcr >> RModeShift) & 3u);
}
}
}
}
}

View File

@@ -0,0 +1,212 @@
using ARMeilleure.State;
using System;
namespace ARMeilleure.Instructions
{
static class SoftFloat16
{
public static ushort FPDefaultNaN()
{
return (ushort)0x7E00u;
}
public static ushort FPInfinity(bool sign)
{
return sign ? (ushort)0xFC00u : (ushort)0x7C00u;
}
public static ushort FPZero(bool sign)
{
return sign ? (ushort)0x8000u : (ushort)0x0000u;
}
public static ushort FPMaxNormal(bool sign)
{
return sign ? (ushort)0xFBFFu : (ushort)0x7BFFu;
}
public static double FPUnpackCv(
this ushort valueBits,
out FPType type,
out bool sign,
ExecutionContext context)
{
sign = (~(uint)valueBits & 0x8000u) == 0u;
uint exp16 = ((uint)valueBits & 0x7C00u) >> 10;
uint frac16 = (uint)valueBits & 0x03FFu;
double real;
if (exp16 == 0u)
{
if (frac16 == 0u)
{
type = FPType.Zero;
real = 0d;
}
else
{
type = FPType.Nonzero; // Subnormal.
real = Math.Pow(2d, -14) * ((double)frac16 * Math.Pow(2d, -10));
}
}
else if (exp16 == 0x1Fu && (context.Fpcr & FPCR.Ahp) == 0)
{
if (frac16 == 0u)
{
type = FPType.Infinity;
real = Math.Pow(2d, 1000);
}
else
{
type = (~frac16 & 0x0200u) == 0u ? FPType.QNaN : FPType.SNaN;
real = 0d;
}
}
else
{
type = FPType.Nonzero; // Normal.
real = Math.Pow(2d, (int)exp16 - 15) * (1d + (double)frac16 * Math.Pow(2d, -10));
}
return sign ? -real : real;
}
public static ushort FPRoundCv(double real, ExecutionContext context)
{
const int MinimumExp = -14;
const int E = 5;
const int F = 10;
bool sign;
double mantissa;
if (real < 0d)
{
sign = true;
mantissa = -real;
}
else
{
sign = false;
mantissa = real;
}
int exponent = 0;
while (mantissa < 1d)
{
mantissa *= 2d;
exponent--;
}
while (mantissa >= 2d)
{
mantissa /= 2d;
exponent++;
}
uint biasedExp = (uint)Math.Max(exponent - MinimumExp + 1, 0);
if (biasedExp == 0u)
{
mantissa /= Math.Pow(2d, MinimumExp - exponent);
}
uint intMant = (uint)Math.Floor(mantissa * Math.Pow(2d, F));
double error = mantissa * Math.Pow(2d, F) - (double)intMant;
if (biasedExp == 0u && (error != 0d || (context.Fpcr & FPCR.Ufe) != 0))
{
SoftFloat.FPProcessException(FPException.Underflow, context);
}
bool overflowToInf;
bool roundUp;
switch (context.Fpcr.RoundingMode)
{
case FPRoundingMode.ToNearest:
roundUp = (error > 0.5d || (error == 0.5d && (intMant & 1u) == 1u));
overflowToInf = true;
break;
case FPRoundingMode.TowardsPlusInfinity:
roundUp = (error != 0d && !sign);
overflowToInf = !sign;
break;
case FPRoundingMode.TowardsMinusInfinity:
roundUp = (error != 0d && sign);
overflowToInf = sign;
break;
case FPRoundingMode.TowardsZero:
roundUp = false;
overflowToInf = false;
break;
default:
throw new ArgumentException($"Invalid rounding mode \"{context.Fpcr.RoundingMode}\".");
}
if (roundUp)
{
intMant++;
if (intMant == 1u << F)
{
biasedExp = 1u;
}
if (intMant == 1u << (F + 1))
{
biasedExp++;
intMant >>= 1;
}
}
ushort resultBits;
if ((context.Fpcr & FPCR.Ahp) == 0)
{
if (biasedExp >= (1u << E) - 1u)
{
resultBits = overflowToInf ? FPInfinity(sign) : FPMaxNormal(sign);
SoftFloat.FPProcessException(FPException.Overflow, context);
error = 1d;
}
else
{
resultBits = (ushort)((sign ? 1u : 0u) << 15 | (biasedExp & 0x1Fu) << 10 | (intMant & 0x03FFu));
}
}
else
{
if (biasedExp >= 1u << E)
{
resultBits = (ushort)((sign ? 1u : 0u) << 15 | 0x7FFFu);
SoftFloat.FPProcessException(FPException.InvalidOp, context);
error = 0d;
}
else
{
resultBits = (ushort)((sign ? 1u : 0u) << 15 | (biasedExp & 0x1Fu) << 10 | (intMant & 0x03FFu));
}
}
if (error != 0d)
{
SoftFloat.FPProcessException(FPException.Inexact, context);
}
return resultBits;
}
}
}

View File

@@ -0,0 +1,182 @@
using ARMeilleure.State;
using System;
using System.Runtime.InteropServices;
namespace ARMeilleure.Instructions
{
static class SoftFloat16_32
{
[UnmanagedCallersOnly]
public static float FPConvert(ushort valueBits)
{
ExecutionContext context = NativeInterface.GetContext();
double real = valueBits.FPUnpackCv(out FPType type, out bool sign, context);
float result;
if (type is FPType.SNaN or FPType.QNaN)
{
if ((context.Fpcr & FPCR.Dn) != 0)
{
result = SoftFloat32.FPDefaultNaN();
}
else
{
result = FPConvertNaN(valueBits);
}
if (type == FPType.SNaN)
{
SoftFloat.FPProcessException(FPException.InvalidOp, context);
}
}
else if (type == FPType.Infinity)
{
result = SoftFloat32.FPInfinity(sign);
}
else if (type == FPType.Zero)
{
result = SoftFloat32.FPZero(sign);
}
else
{
result = FPRoundCv(real, context);
}
return result;
}
private static float FPRoundCv(double real, ExecutionContext context)
{
const int MinimumExp = -126;
const int E = 8;
const int F = 23;
bool sign;
double mantissa;
if (real < 0d)
{
sign = true;
mantissa = -real;
}
else
{
sign = false;
mantissa = real;
}
int exponent = 0;
while (mantissa < 1d)
{
mantissa *= 2d;
exponent--;
}
while (mantissa >= 2d)
{
mantissa /= 2d;
exponent++;
}
if ((context.Fpcr & FPCR.Fz) != 0 && exponent < MinimumExp)
{
context.Fpsr |= FPSR.Ufc;
return SoftFloat32.FPZero(sign);
}
uint biasedExp = (uint)Math.Max(exponent - MinimumExp + 1, 0);
if (biasedExp == 0u)
{
mantissa /= Math.Pow(2d, MinimumExp - exponent);
}
uint intMant = (uint)Math.Floor(mantissa * Math.Pow(2d, F));
double error = mantissa * Math.Pow(2d, F) - (double)intMant;
if (biasedExp == 0u && (error != 0d || (context.Fpcr & FPCR.Ufe) != 0))
{
SoftFloat.FPProcessException(FPException.Underflow, context);
}
bool overflowToInf;
bool roundUp;
switch (context.Fpcr.RoundingMode)
{
case FPRoundingMode.ToNearest:
roundUp = (error > 0.5d || (error == 0.5d && (intMant & 1u) == 1u));
overflowToInf = true;
break;
case FPRoundingMode.TowardsPlusInfinity:
roundUp = (error != 0d && !sign);
overflowToInf = !sign;
break;
case FPRoundingMode.TowardsMinusInfinity:
roundUp = (error != 0d && sign);
overflowToInf = sign;
break;
case FPRoundingMode.TowardsZero:
roundUp = false;
overflowToInf = false;
break;
default:
throw new ArgumentException($"Invalid rounding mode \"{context.Fpcr.RoundingMode}\".");
}
if (roundUp)
{
intMant++;
if (intMant == 1u << F)
{
biasedExp = 1u;
}
if (intMant == 1u << (F + 1))
{
biasedExp++;
intMant >>= 1;
}
}
float result;
if (biasedExp >= (1u << E) - 1u)
{
result = overflowToInf ? SoftFloat32.FPInfinity(sign) : SoftFloat32.FPMaxNormal(sign);
SoftFloat.FPProcessException(FPException.Overflow, context);
error = 1d;
}
else
{
result = BitConverter.Int32BitsToSingle(
(int)((sign ? 1u : 0u) << 31 | (biasedExp & 0xFFu) << 23 | (intMant & 0x007FFFFFu)));
}
if (error != 0d)
{
SoftFloat.FPProcessException(FPException.Inexact, context);
}
return result;
}
private static float FPConvertNaN(ushort valueBits)
{
return BitConverter.Int32BitsToSingle(
(int)(((uint)valueBits & 0x8000u) << 16 | 0x7FC00000u | ((uint)valueBits & 0x01FFu) << 13));
}
}
}

View File

@@ -0,0 +1,182 @@
using ARMeilleure.State;
using System;
using System.Runtime.InteropServices;
namespace ARMeilleure.Instructions
{
static class SoftFloat16_64
{
[UnmanagedCallersOnly]
public static double FPConvert(ushort valueBits)
{
ExecutionContext context = NativeInterface.GetContext();
double real = valueBits.FPUnpackCv(out FPType type, out bool sign, context);
double result;
if (type is FPType.SNaN or FPType.QNaN)
{
if ((context.Fpcr & FPCR.Dn) != 0)
{
result = SoftFloat64.FPDefaultNaN();
}
else
{
result = FPConvertNaN(valueBits);
}
if (type == FPType.SNaN)
{
SoftFloat.FPProcessException(FPException.InvalidOp, context);
}
}
else if (type == FPType.Infinity)
{
result = SoftFloat64.FPInfinity(sign);
}
else if (type == FPType.Zero)
{
result = SoftFloat64.FPZero(sign);
}
else
{
result = FPRoundCv(real, context);
}
return result;
}
private static double FPRoundCv(double real, ExecutionContext context)
{
const int MinimumExp = -1022;
const int E = 11;
const int F = 52;
bool sign;
double mantissa;
if (real < 0d)
{
sign = true;
mantissa = -real;
}
else
{
sign = false;
mantissa = real;
}
int exponent = 0;
while (mantissa < 1d)
{
mantissa *= 2d;
exponent--;
}
while (mantissa >= 2d)
{
mantissa /= 2d;
exponent++;
}
if ((context.Fpcr & FPCR.Fz) != 0 && exponent < MinimumExp)
{
context.Fpsr |= FPSR.Ufc;
return SoftFloat64.FPZero(sign);
}
uint biasedExp = (uint)Math.Max(exponent - MinimumExp + 1, 0);
if (biasedExp == 0u)
{
mantissa /= Math.Pow(2d, MinimumExp - exponent);
}
ulong intMant = (ulong)Math.Floor(mantissa * Math.Pow(2d, F));
double error = mantissa * Math.Pow(2d, F) - (double)intMant;
if (biasedExp == 0u && (error != 0d || (context.Fpcr & FPCR.Ufe) != 0))
{
SoftFloat.FPProcessException(FPException.Underflow, context);
}
bool overflowToInf;
bool roundUp;
switch (context.Fpcr.RoundingMode)
{
case FPRoundingMode.ToNearest:
roundUp = (error > 0.5d || (error == 0.5d && (intMant & 1u) == 1u));
overflowToInf = true;
break;
case FPRoundingMode.TowardsPlusInfinity:
roundUp = (error != 0d && !sign);
overflowToInf = !sign;
break;
case FPRoundingMode.TowardsMinusInfinity:
roundUp = (error != 0d && sign);
overflowToInf = sign;
break;
case FPRoundingMode.TowardsZero:
roundUp = false;
overflowToInf = false;
break;
default:
throw new ArgumentException($"Invalid rounding mode \"{context.Fpcr.RoundingMode}\".");
}
if (roundUp)
{
intMant++;
if (intMant == 1ul << F)
{
biasedExp = 1u;
}
if (intMant == 1ul << (F + 1))
{
biasedExp++;
intMant >>= 1;
}
}
double result;
if (biasedExp >= (1u << E) - 1u)
{
result = overflowToInf ? SoftFloat64.FPInfinity(sign) : SoftFloat64.FPMaxNormal(sign);
SoftFloat.FPProcessException(FPException.Overflow, context);
error = 1d;
}
else
{
result = BitConverter.Int64BitsToDouble(
(long)((sign ? 1ul : 0ul) << 63 | (biasedExp & 0x7FFul) << 52 | (intMant & 0x000FFFFFFFFFFFFFul)));
}
if (error != 0d)
{
SoftFloat.FPProcessException(FPException.Inexact, context);
}
return result;
}
private static double FPConvertNaN(ushort valueBits)
{
return BitConverter.Int64BitsToDouble(
(long)(((ulong)valueBits & 0x8000ul) << 48 | 0x7FF8000000000000ul | ((ulong)valueBits & 0x01FFul) << 42));
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,126 @@
using ARMeilleure.State;
using System;
using System.Runtime.InteropServices;
namespace ARMeilleure.Instructions
{
static class SoftFloat32_16
{
[UnmanagedCallersOnly]
public static ushort FPConvert(float value)
{
ExecutionContext context = NativeInterface.GetContext();
double real = value.FPUnpackCv(out FPType type, out bool sign, out uint valueBits, context);
bool altHp = (context.Fpcr & FPCR.Ahp) != 0;
ushort resultBits;
if (type is FPType.SNaN or FPType.QNaN)
{
if (altHp)
{
resultBits = SoftFloat16.FPZero(sign);
}
else if ((context.Fpcr & FPCR.Dn) != 0)
{
resultBits = SoftFloat16.FPDefaultNaN();
}
else
{
resultBits = FPConvertNaN(valueBits);
}
if (type == FPType.SNaN || altHp)
{
SoftFloat.FPProcessException(FPException.InvalidOp, context);
}
}
else if (type == FPType.Infinity)
{
if (altHp)
{
resultBits = (ushort)((sign ? 1u : 0u) << 15 | 0x7FFFu);
SoftFloat.FPProcessException(FPException.InvalidOp, context);
}
else
{
resultBits = SoftFloat16.FPInfinity(sign);
}
}
else if (type == FPType.Zero)
{
resultBits = SoftFloat16.FPZero(sign);
}
else
{
resultBits = SoftFloat16.FPRoundCv(real, context);
}
return resultBits;
}
private static double FPUnpackCv(
this float value,
out FPType type,
out bool sign,
out uint valueBits,
ExecutionContext context)
{
valueBits = (uint)BitConverter.SingleToInt32Bits(value);
sign = (~valueBits & 0x80000000u) == 0u;
uint exp32 = (valueBits & 0x7F800000u) >> 23;
uint frac32 = valueBits & 0x007FFFFFu;
double real;
if (exp32 == 0u)
{
if (frac32 == 0u || (context.Fpcr & FPCR.Fz) != 0)
{
type = FPType.Zero;
real = 0d;
if (frac32 != 0u)
{
SoftFloat.FPProcessException(FPException.InputDenorm, context);
}
}
else
{
type = FPType.Nonzero; // Subnormal.
real = Math.Pow(2d, -126) * ((double)frac32 * Math.Pow(2d, -23));
}
}
else if (exp32 == 0xFFu)
{
if (frac32 == 0u)
{
type = FPType.Infinity;
real = Math.Pow(2d, 1000);
}
else
{
type = (~frac32 & 0x00400000u) == 0u ? FPType.QNaN : FPType.SNaN;
real = 0d;
}
}
else
{
type = FPType.Nonzero; // Normal.
real = Math.Pow(2d, (int)exp32 - 127) * (1d + (double)frac32 * Math.Pow(2d, -23));
}
return sign ? -real : real;
}
private static ushort FPConvertNaN(uint valueBits)
{
return (ushort)((valueBits & 0x80000000u) >> 16 | 0x7E00u | (valueBits & 0x003FE000u) >> 13);
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,127 @@
using ARMeilleure.State;
using System;
using System.Runtime.InteropServices;
namespace ARMeilleure.Instructions
{
static class SoftFloat64_16
{
[UnmanagedCallersOnly]
public static ushort FPConvert(double value)
{
ExecutionContext context = NativeInterface.GetContext();
double real = value.FPUnpackCv(out FPType type, out bool sign, out ulong valueBits, context);
bool altHp = (context.Fpcr & FPCR.Ahp) != 0;
ushort resultBits;
if (type is FPType.SNaN or FPType.QNaN)
{
if (altHp)
{
resultBits = SoftFloat16.FPZero(sign);
}
else if ((context.Fpcr & FPCR.Dn) != 0)
{
resultBits = SoftFloat16.FPDefaultNaN();
}
else
{
resultBits = FPConvertNaN(valueBits);
}
if (type == FPType.SNaN || altHp)
{
SoftFloat.FPProcessException(FPException.InvalidOp, context);
}
}
else if (type == FPType.Infinity)
{
if (altHp)
{
resultBits = (ushort)((sign ? 1u : 0u) << 15 | 0x7FFFu);
SoftFloat.FPProcessException(FPException.InvalidOp, context);
}
else
{
resultBits = SoftFloat16.FPInfinity(sign);
}
}
else if (type == FPType.Zero)
{
resultBits = SoftFloat16.FPZero(sign);
}
else
{
resultBits = SoftFloat16.FPRoundCv(real, context);
}
return resultBits;
}
private static double FPUnpackCv(
this double value,
out FPType type,
out bool sign,
out ulong valueBits,
ExecutionContext context)
{
valueBits = (ulong)BitConverter.DoubleToInt64Bits(value);
sign = (~valueBits & 0x8000000000000000ul) == 0u;
ulong exp64 = (valueBits & 0x7FF0000000000000ul) >> 52;
ulong frac64 = valueBits & 0x000FFFFFFFFFFFFFul;
double real;
if (exp64 == 0u)
{
if (frac64 == 0u || (context.Fpcr & FPCR.Fz) != 0)
{
type = FPType.Zero;
real = 0d;
if (frac64 != 0u)
{
SoftFloat.FPProcessException(FPException.InputDenorm, context);
}
}
else
{
type = FPType.Nonzero; // Subnormal.
real = Math.Pow(2d, -1022) * ((double)frac64 * Math.Pow(2d, -52));
}
}
else if (exp64 == 0x7FFul)
{
if (frac64 == 0u)
{
type = FPType.Infinity;
real = Math.Pow(2d, 1000000);
}
else
{
type = (~frac64 & 0x0008000000000000ul) == 0u ? FPType.QNaN : FPType.SNaN;
real = 0d;
}
}
else
{
type = FPType.Nonzero; // Normal.
real = Math.Pow(2d, (int)exp64 - 1023) * (1d + (double)frac64 * Math.Pow(2d, -52));
}
return sign ? -real : real;
}
private static ushort FPConvertNaN(ulong valueBits)
{
return (ushort)((valueBits & 0x8000000000000000ul) >> 48 | 0x7E00u |
(valueBits & 0x0007FC0000000000ul) >> 42);
}
}
}

View File

@@ -16,9 +16,9 @@ namespace ARMeilleure.IntermediateRepresentation
static class ComparisonExtensions
{
public static Comparison Invert(this Comparison comp)
extension(Comparison comparison)
{
return (Comparison)((int)comp ^ 1);
public Comparison Inverse => (Comparison)((int)comparison ^ 1);
}
}
}

View File

@@ -1,5 +1,4 @@
using System;
using System.Diagnostics.CodeAnalysis;
namespace ARMeilleure.IntermediateRepresentation
{

View File

@@ -14,48 +14,38 @@ namespace ARMeilleure.IntermediateRepresentation
static class OperandTypeExtensions
{
public static bool IsInteger(this OperandType type)
extension(OperandType type)
{
return type is OperandType.I32 or
OperandType.I64;
}
public static RegisterType ToRegisterType(this OperandType type)
{
return type switch
public bool IsInteger => type is OperandType.I32 or OperandType.I64;
public RegisterType Register => type switch
{
OperandType.FP32 => RegisterType.Vector,
OperandType.FP64 => RegisterType.Vector,
OperandType.I32 => RegisterType.Integer,
OperandType.I64 => RegisterType.Integer,
OperandType.V128 => RegisterType.Vector,
_ => throw new InvalidOperationException($"Invalid operand type \"{type}\"."),
_ => throw new InvalidOperationException($"Invalid operand type \"{type}\".")
};
}
public static int GetSizeInBytes(this OperandType type)
{
return type switch
public int ByteSize => type switch
{
OperandType.FP32 => 4,
OperandType.FP64 => 8,
OperandType.I32 => 4,
OperandType.I64 => 8,
OperandType.V128 => 16,
_ => throw new InvalidOperationException($"Invalid operand type \"{type}\"."),
_ => throw new InvalidOperationException($"Invalid operand type \"{type}\".")
};
}
public static int GetSizeInBytesLog2(this OperandType type)
{
return type switch
public int ByteSizeLog2 => type switch
{
OperandType.FP32 => 2,
OperandType.FP64 => 3,
OperandType.I32 => 2,
OperandType.I64 => 3,
OperandType.V128 => 4,
_ => throw new InvalidOperationException($"Invalid operand type \"{type}\"."),
_ => throw new InvalidOperationException($"Invalid operand type \"{type}\".")
};
}
}

View File

@@ -45,19 +45,12 @@ namespace ARMeilleure.Memory
public static class MemoryManagerTypeExtensions
{
public static bool IsHostMapped(this MemoryManagerType type)
extension(MemoryManagerType type)
{
return type is MemoryManagerType.HostMapped or MemoryManagerType.HostMappedUnsafe;
}
public static bool IsHostTracked(this MemoryManagerType type)
{
return type is MemoryManagerType.HostTracked or MemoryManagerType.HostTrackedUnsafe;
}
public static bool IsHostMappedOrTracked(this MemoryManagerType type)
{
return type.IsHostMapped() || type.IsHostTracked();
public bool IsHostMapped => type is MemoryManagerType.HostMapped or MemoryManagerType.HostMappedUnsafe;
public bool IsHostTracked => type is MemoryManagerType.HostTracked or MemoryManagerType.HostTrackedUnsafe;
public bool IsHostMappedOrTracked => type.IsHostMapped || type.IsHostTracked;
}
}
}

View File

@@ -13,6 +13,7 @@ namespace ARMeilleure
public static bool AllowLcqInFunctionTable { get; set; } = true;
public static bool UseUnmanagedDispatchLoop { get; set; } = true;
public static bool EnableDebugging { get; set; } = false;
public static bool EnableDeepCallRecursionProtection { get; set; } = true;
public static bool UseAdvSimdIfAvailable { get; set; } = true;
public static bool UseArm64AesIfAvailable { get; set; } = true;

View File

@@ -134,6 +134,11 @@ namespace ARMeilleure.State
public bool GetFPstateFlag(FPState flag) => _nativeContext.GetFPStateFlag(flag);
public void SetFPstateFlag(FPState flag, bool value) => _nativeContext.SetFPStateFlag(flag, value);
internal void ResetCallDepth()
{
_nativeContext.ResetCallDepth();
}
internal void CheckInterrupt()
{
if (Interrupted)

View File

@@ -22,6 +22,7 @@ namespace ARMeilleure.State
public ulong ExclusiveValueHigh;
public int Running;
public long Tpidr2El0;
public int CallDepth;
/// <summary>
/// Precise PC value used for debugging.
@@ -199,6 +200,8 @@ namespace ARMeilleure.State
public bool GetRunning() => GetStorage().Running != 0;
public void SetRunning(bool value) => GetStorage().Running = value ? 1 : 0;
public void ResetCallDepth() => GetStorage().CallDepth = 0;
public unsafe static int GetRegisterOffset(Register reg)
{
if (reg.Type == RegisterType.Integer)
@@ -284,6 +287,11 @@ namespace ARMeilleure.State
return StorageOffset(ref _dummyStorage, ref _dummyStorage.DebugPrecisePc);
}
public static int GetCallDepthOffset()
{
return StorageOffset(ref _dummyStorage, ref _dummyStorage.CallDepth);
}
private static int StorageOffset<T>(ref NativeCtxStorage storage, ref T target)
{
return (int)Unsafe.ByteOffset(ref Unsafe.As<NativeCtxStorage, T>(ref storage), ref target);

View File

@@ -361,10 +361,7 @@ namespace ARMeilleure.Translation
IntervalTreeNode<TK, TV> tmp = LeftOf(replacementNode) ?? RightOf(replacementNode);
if (tmp != null)
{
tmp.Parent = ParentOf(replacementNode);
}
tmp?.Parent = ParentOf(replacementNode);
if (ParentOf(replacementNode) == null)
{
@@ -582,10 +579,7 @@ namespace ARMeilleure.Translation
{
IntervalTreeNode<TK, TV> right = RightOf(node);
node.Right = LeftOf(right);
if (node.Right != null)
{
node.Right.Parent = node;
}
node.Right?.Parent = node;
IntervalTreeNode<TK, TV> nodeParent = ParentOf(node);
right.Parent = nodeParent;
@@ -615,10 +609,7 @@ namespace ARMeilleure.Translation
{
IntervalTreeNode<TK, TV> left = LeftOf(node);
node.Left = RightOf(left);
if (node.Left != null)
{
node.Left.Parent = node;
}
node.Left?.Parent = node;
IntervalTreeNode<TK, TV> nodeParent = ParentOf(node);
left.Parent = nodeParent;
@@ -667,10 +658,7 @@ namespace ARMeilleure.Translation
/// <param name="color">Color (Boolean)</param>
private static void SetColor(IntervalTreeNode<TK, TV> node, bool color)
{
if (node != null)
{
node.Color = color;
}
node?.Color = color;
}
/// <summary>

View File

@@ -33,7 +33,7 @@ namespace ARMeilleure.Translation.PTC
private const string OuterHeaderMagicString = "PTCohd\0\0";
private const string InnerHeaderMagicString = "PTCihd\0\0";
private const uint InternalVersion = 7009; //! To be incremented manually for each change to the ARMeilleure project.
private const uint InternalVersion = 7010; //! To be incremented manually for each change to the ARMeilleure project.
private const string ActualDir = "0";
private const string BackupDir = "1";

View File

@@ -186,6 +186,7 @@ namespace ARMeilleure.Translation
Statistics.StartTimer();
context.ResetCallDepth();
ulong nextAddr = func.Execute(Stubs.ContextWrapper, context);
Statistics.StopTimer(address);
@@ -260,6 +261,7 @@ namespace ARMeilleure.Translation
Logger.StartPass(PassName.Translation);
InstEmitFlowHelper.EmitCallDepthCheckAndIncrement(context, Const(address));
EmitSynchronization(context);
if (blocks[0].Address != address)
@@ -412,7 +414,7 @@ namespace ARMeilleure.Translation
{
context.SyncQcFlag();
if (block.Branch != null && !block.Branch.Exit && block.Branch.Address <= block.Address)
if (block.Branch is { Exit: false } && block.Branch.Address <= block.Address)
{
EmitSynchronization(context);
}
@@ -429,14 +431,14 @@ namespace ARMeilleure.Translation
{
lblPredicateSkip = Label();
InstEmitFlowHelper.EmitCondBranch(context, lblPredicateSkip, context.CurrentIfThenBlockCond.Invert());
InstEmitFlowHelper.EmitCondBranch(context, lblPredicateSkip, context.CurrentIfThenBlockCond.Inverse);
}
if (opCode is OpCode32 op && op.Cond < Condition.Al)
if (opCode is OpCode32 { Cond: < Condition.Al } op)
{
lblPredicateSkip = Label();
InstEmitFlowHelper.EmitCondBranch(context, lblPredicateSkip, op.Cond.Invert());
InstEmitFlowHelper.EmitCondBranch(context, lblPredicateSkip, op.Cond.Inverse);
}
if (opCode.Instruction.Emitter != null)

View File

@@ -262,10 +262,18 @@ namespace ARMeilleure.Translation
Operand runningAddress = context.Add(nativeContext, Const((ulong)NativeContext.GetRunningOffset()));
Operand dispatchAddress = context.Add(nativeContext, Const((ulong)NativeContext.GetDispatchAddressOffset()));
Operand callDepthAddress = context.Add(nativeContext, Const((ulong)NativeContext.GetCallDepthOffset()));
EmitSyncFpContext(context, nativeContext, true);
context.MarkLabel(beginLbl);
if (Optimizations.EnableDeepCallRecursionProtection)
{
// Reset the call depth counter, since this is our first guest function call.
context.Store(callDepthAddress, Const(0));
}
context.Store(dispatchAddress, guestAddress);
context.Copy(guestAddress, context.Call(Const((ulong)DispatchStub), OperandType.I64, nativeContext));
context.BranchIfFalse(endLbl, guestAddress);

View File

@@ -0,0 +1,16 @@
namespace Ryujinx.Audio.Backends.Apple
{
class AppleAudioBuffer
{
public readonly ulong DriverIdentifier;
public readonly ulong SampleCount;
public ulong SamplePlayed;
public AppleAudioBuffer(ulong driverIdentifier, ulong sampleCount)
{
DriverIdentifier = driverIdentifier;
SampleCount = sampleCount;
SamplePlayed = 0;
}
}
}

View File

@@ -0,0 +1,196 @@
using Ryujinx.Audio.Common;
using Ryujinx.Audio.Integration;
using Ryujinx.Common.Logging;
using Ryujinx.Memory;
using System;
using System.Collections.Concurrent;
using System.Runtime.InteropServices;
using System.Threading;
using System.Runtime.Versioning;
using Ryujinx.Audio.Backends.Apple.Native;
using static Ryujinx.Audio.Backends.Apple.Native.AudioToolbox;
using static Ryujinx.Audio.Integration.IHardwareDeviceDriver;
namespace Ryujinx.Audio.Backends.Apple
{
[SupportedOSPlatform("macos")]
[SupportedOSPlatform("ios")]
public sealed class AppleHardwareDeviceDriver : IHardwareDeviceDriver
{
private readonly ManualResetEvent _updateRequiredEvent;
private readonly ManualResetEvent _pauseEvent;
private readonly ConcurrentDictionary<AppleHardwareDeviceSession, byte> _sessions;
private readonly bool _supportSurroundConfiguration;
public float Volume { get; set; }
public AppleHardwareDeviceDriver()
{
_updateRequiredEvent = new ManualResetEvent(false);
_pauseEvent = new ManualResetEvent(true);
_sessions = new ConcurrentDictionary<AppleHardwareDeviceSession, byte>();
_supportSurroundConfiguration = TestSurroundSupport();
Volume = 1f;
}
private bool TestSurroundSupport()
{
try
{
AudioStreamBasicDescription format =
GetAudioFormat(SampleFormat.PcmFloat, Constants.TargetSampleRate, 6);
int result = AudioQueueNewOutput(
ref format,
nint.Zero,
nint.Zero,
nint.Zero,
nint.Zero,
0,
out nint testQueue);
if (result == 0)
{
AudioChannelLayout layout = new AudioChannelLayout
{
AudioChannelLayoutTag = kAudioChannelLayoutTag_MPEG_5_1_A,
AudioChannelBitmap = 0,
NumberChannelDescriptions = 0
};
int layoutResult = AudioQueueSetProperty(
testQueue,
kAudioQueueProperty_ChannelLayout,
ref layout,
(uint)Marshal.SizeOf<AudioChannelLayout>());
if (layoutResult == 0)
{
AudioQueueDispose(testQueue, true);
return true;
}
AudioQueueDispose(testQueue, true);
}
return false;
}
catch
{
return false;
}
}
public static bool IsSupported => OperatingSystem.IsMacOSVersionAtLeast(10, 5);
public ManualResetEvent GetUpdateRequiredEvent()
=> _updateRequiredEvent;
public ManualResetEvent GetPauseEvent()
=> _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 Apple backend!");
}
AppleHardwareDeviceSession session = new(this, memoryManager, sampleFormat, sampleRate, channelCount);
_sessions.TryAdd(session, 0);
return session;
}
internal bool Unregister(AppleHardwareDeviceSession session)
=> _sessions.TryRemove(session, out _);
internal static AudioStreamBasicDescription GetAudioFormat(SampleFormat sampleFormat, uint sampleRate,
uint channelCount)
{
uint formatFlags;
uint bitsPerChannel;
switch (sampleFormat)
{
case SampleFormat.PcmInt8:
formatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked;
bitsPerChannel = 8;
break;
case SampleFormat.PcmInt16:
formatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked;
bitsPerChannel = 16;
break;
case SampleFormat.PcmInt32:
formatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked;
bitsPerChannel = 32;
break;
case SampleFormat.PcmFloat:
formatFlags = kAudioFormatFlagIsFloat | kAudioFormatFlagIsPacked;
bitsPerChannel = 32;
break;
default:
throw new ArgumentException($"Unsupported sample format {sampleFormat}");
}
uint bytesPerFrame = (bitsPerChannel / 8) * channelCount;
return new AudioStreamBasicDescription
{
SampleRate = sampleRate,
FormatID = kAudioFormatLinearPCM,
FormatFlags = formatFlags,
BytesPerPacket = bytesPerFrame,
FramesPerPacket = 1,
BytesPerFrame = bytesPerFrame,
ChannelsPerFrame = channelCount,
BitsPerChannel = bitsPerChannel,
Reserved = 0
};
}
public void Dispose()
{
GC.SuppressFinalize(this);
Dispose(true);
}
private void Dispose(bool disposing)
{
if (disposing)
{
foreach (AppleHardwareDeviceSession session in _sessions.Keys)
{
session.Dispose();
}
_pauseEvent.Dispose();
}
}
public bool SupportsDirection(Direction direction)
=> direction != Direction.Input;
public bool SupportsSampleRate(uint sampleRate) => true;
public bool SupportsSampleFormat(SampleFormat sampleFormat)
=> sampleFormat != SampleFormat.PcmInt24;
public bool SupportsChannelCount(uint channelCount)
=> channelCount != 6 || _supportSurroundConfiguration;
}
}

View File

@@ -0,0 +1,285 @@
using Ryujinx.Audio.Backends.Common;
using Ryujinx.Audio.Common;
using Ryujinx.Memory;
using System;
using System.Collections.Concurrent;
using System.Runtime.InteropServices;
using System.Threading;
using System.Runtime.Versioning;
using static Ryujinx.Audio.Backends.Apple.Native.AudioToolbox;
namespace Ryujinx.Audio.Backends.Apple
{
[SupportedOSPlatform("macos")]
[SupportedOSPlatform("ios")]
class AppleHardwareDeviceSession : HardwareDeviceSessionOutputBase
{
private const int NumBuffers = 3;
private readonly AppleHardwareDeviceDriver _driver;
private readonly ConcurrentQueue<AppleAudioBuffer> _queuedBuffers = new();
private readonly DynamicRingBuffer _ringBuffer = new();
private readonly ManualResetEvent _updateRequiredEvent;
private readonly AudioQueueOutputCallback _callbackDelegate;
private readonly GCHandle _gcHandle;
private nint _audioQueue;
private readonly nint[] _audioQueueBuffers = new nint[NumBuffers];
private readonly int[] _bufferBytesFilled = new int[NumBuffers];
private readonly int _bytesPerFrame;
private ulong _playedSampleCount;
private bool _started;
private float _volume = 1f;
private readonly object _lock = new();
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate void AudioQueueOutputCallback(
nint userData,
nint audioQueue,
nint buffer);
public AppleHardwareDeviceSession(
AppleHardwareDeviceDriver driver,
IVirtualMemoryManager memoryManager,
SampleFormat requestedSampleFormat,
uint requestedSampleRate,
uint requestedChannelCount)
: base(memoryManager, requestedSampleFormat, requestedSampleRate, requestedChannelCount)
{
_driver = driver;
_updateRequiredEvent = driver.GetUpdateRequiredEvent();
_callbackDelegate = OutputCallback;
_bytesPerFrame = BackendHelper.GetSampleSize(requestedSampleFormat) * (int)requestedChannelCount;
_gcHandle = GCHandle.Alloc(this, GCHandleType.Normal);
SetupAudioQueue();
}
private void SetupAudioQueue()
{
lock (_lock)
{
AudioStreamBasicDescription format = AppleHardwareDeviceDriver.GetAudioFormat(
RequestedSampleFormat,
RequestedSampleRate,
RequestedChannelCount);
nint callbackPtr = Marshal.GetFunctionPointerForDelegate(_callbackDelegate);
nint userData = GCHandle.ToIntPtr(_gcHandle);
int result = AudioQueueNewOutput(
ref format,
callbackPtr,
userData,
nint.Zero,
nint.Zero,
0,
out _audioQueue);
if (result != 0)
{
throw new InvalidOperationException($"AudioQueueNewOutput failed: {result}");
}
uint framesPerBuffer = RequestedSampleRate / 100;
uint bufferSize = framesPerBuffer * (uint)_bytesPerFrame;
for (int i = 0; i < NumBuffers; i++)
{
AudioQueueAllocateBuffer(_audioQueue, bufferSize, out _audioQueueBuffers[i]);
_bufferBytesFilled[i] = 0;
PrimeBuffer(_audioQueueBuffers[i], i);
}
}
}
private unsafe void PrimeBuffer(nint bufferPtr, int bufferIndex)
{
AudioQueueBuffer* buffer = (AudioQueueBuffer*)bufferPtr;
int capacityBytes = (int)buffer->AudioDataBytesCapacity;
int framesPerBuffer = capacityBytes / _bytesPerFrame;
int availableFrames = _ringBuffer.Length / _bytesPerFrame;
int framesToRead = Math.Min(availableFrames, framesPerBuffer);
int bytesToRead = framesToRead * _bytesPerFrame;
Span<byte> dst = new((void*)buffer->AudioData, capacityBytes);
dst.Clear();
if (bytesToRead > 0)
{
Span<byte> audio = dst.Slice(0, bytesToRead);
_ringBuffer.Read(audio, 0, bytesToRead);
ApplyVolume(buffer->AudioData, bytesToRead);
}
buffer->AudioDataByteSize = (uint)capacityBytes;
_bufferBytesFilled[bufferIndex] = bytesToRead;
AudioQueueEnqueueBuffer(_audioQueue, bufferPtr, 0, nint.Zero);
}
private void OutputCallback(nint userData, nint audioQueue, nint bufferPtr)
{
if (!_started || bufferPtr == nint.Zero)
return;
int bufferIndex = Array.IndexOf(_audioQueueBuffers, bufferPtr);
if (bufferIndex < 0)
return;
int bytesPlayed = _bufferBytesFilled[bufferIndex];
if (bytesPlayed > 0)
{
ProcessPlayedSamples(bytesPlayed);
}
PrimeBuffer(bufferPtr, bufferIndex);
}
private void ProcessPlayedSamples(int bytesPlayed)
{
ulong samplesPlayed = GetSampleCount(bytesPlayed);
ulong remaining = samplesPlayed;
bool needUpdate = false;
while (remaining > 0 && _queuedBuffers.TryPeek(out AppleAudioBuffer buffer))
{
ulong needed = buffer.SampleCount - Interlocked.Read(ref buffer.SamplePlayed);
ulong take = Math.Min(needed, remaining);
ulong played = Interlocked.Add(ref buffer.SamplePlayed, take);
remaining -= take;
if (played == buffer.SampleCount)
{
_queuedBuffers.TryDequeue(out _);
needUpdate = true;
}
Interlocked.Add(ref _playedSampleCount, take);
}
if (needUpdate)
{
_updateRequiredEvent.Set();
}
}
private unsafe void ApplyVolume(nint dataPtr, int byteSize)
{
float volume = Math.Clamp(_volume * _driver.Volume, 0f, 1f);
if (volume >= 0.999f)
return;
int sampleCount = byteSize / BackendHelper.GetSampleSize(RequestedSampleFormat);
switch (RequestedSampleFormat)
{
case SampleFormat.PcmInt16:
short* s16 = (short*)dataPtr;
for (int i = 0; i < sampleCount; i++)
s16[i] = (short)(s16[i] * volume);
break;
case SampleFormat.PcmFloat:
float* f32 = (float*)dataPtr;
for (int i = 0; i < sampleCount; i++)
f32[i] *= volume;
break;
case SampleFormat.PcmInt32:
int* s32 = (int*)dataPtr;
for (int i = 0; i < sampleCount; i++)
s32[i] = (int)(s32[i] * volume);
break;
case SampleFormat.PcmInt8:
sbyte* s8 = (sbyte*)dataPtr;
for (int i = 0; i < sampleCount; i++)
s8[i] = (sbyte)(s8[i] * volume);
break;
}
}
public override void QueueBuffer(AudioBuffer buffer)
{
_ringBuffer.Write(buffer.Data, 0, buffer.Data.Length);
_queuedBuffers.Enqueue(new AppleAudioBuffer(buffer.DataPointer, GetSampleCount(buffer)));
}
public override void Start()
{
lock (_lock)
{
if (_started)
return;
_started = true;
AudioQueueStart(_audioQueue, nint.Zero);
}
}
public override void Stop()
{
lock (_lock)
{
if (!_started)
return;
_started = false;
AudioQueuePause(_audioQueue);
}
}
public override ulong GetPlayedSampleCount()
=> Interlocked.Read(ref _playedSampleCount);
public override float GetVolume() => _volume;
public override void SetVolume(float volume) => _volume = volume;
public override bool WasBufferFullyConsumed(AudioBuffer buffer)
{
if (!_queuedBuffers.TryPeek(out AppleAudioBuffer driverBuffer))
return true;
return driverBuffer.DriverIdentifier != buffer.DataPointer;
}
public override void PrepareToClose() { }
public override void UnregisterBuffer(AudioBuffer buffer) { }
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
Stop();
if (_audioQueue != nint.Zero)
{
AudioQueueStop(_audioQueue, true);
AudioQueueDispose(_audioQueue, true);
_audioQueue = nint.Zero;
}
if (_gcHandle.IsAllocated)
{
_gcHandle.Free();
}
}
}
public override void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
}
}

View File

@@ -0,0 +1,102 @@
using System.Runtime.InteropServices;
// ReSharper disable InconsistentNaming
namespace Ryujinx.Audio.Backends.Apple.Native
{
public static partial class AudioToolbox
{
[StructLayout(LayoutKind.Sequential)]
internal struct AudioStreamBasicDescription
{
public double SampleRate;
public uint FormatID;
public uint FormatFlags;
public uint BytesPerPacket;
public uint FramesPerPacket;
public uint BytesPerFrame;
public uint ChannelsPerFrame;
public uint BitsPerChannel;
public uint Reserved;
}
[StructLayout(LayoutKind.Sequential)]
internal struct AudioChannelLayout
{
public uint AudioChannelLayoutTag;
public uint AudioChannelBitmap;
public uint NumberChannelDescriptions;
}
internal const uint kAudioFormatLinearPCM = 0x6C70636D;
internal const uint kAudioQueueProperty_ChannelLayout = 0x6171636c;
internal const uint kAudioChannelLayoutTag_MPEG_5_1_A = 0x650006;
internal const uint kAudioFormatFlagIsFloat = (1 << 0);
internal const uint kAudioFormatFlagIsSignedInteger = (1 << 2);
internal const uint kAudioFormatFlagIsPacked = (1 << 3);
internal const uint kAudioFormatFlagIsBigEndian = (1 << 1);
internal const uint kAudioFormatFlagIsAlignedHigh = (1 << 4);
internal const uint kAudioFormatFlagIsNonInterleaved = (1 << 5);
[LibraryImport("/System/Library/Frameworks/AudioToolbox.framework/AudioToolbox")]
internal static partial int AudioQueueNewOutput(
ref AudioStreamBasicDescription format,
nint callback,
nint userData,
nint callbackRunLoop,
nint callbackRunLoopMode,
uint flags,
out nint audioQueue);
[LibraryImport("/System/Library/Frameworks/AudioToolbox.framework/AudioToolbox")]
internal static partial int AudioQueueSetProperty(
nint audioQueue,
uint propertyID,
ref AudioChannelLayout layout,
uint layoutSize);
[LibraryImport("/System/Library/Frameworks/AudioToolbox.framework/AudioToolbox")]
internal static partial int AudioQueueDispose(nint audioQueue, [MarshalAs(UnmanagedType.I1)] bool immediate);
[LibraryImport("/System/Library/Frameworks/AudioToolbox.framework/AudioToolbox")]
internal static partial int AudioQueueAllocateBuffer(
nint audioQueue,
uint bufferByteSize,
out nint buffer);
[LibraryImport("/System/Library/Frameworks/AudioToolbox.framework/AudioToolbox")]
internal static partial int AudioQueueStart(nint audioQueue, nint startTime);
[LibraryImport("/System/Library/Frameworks/AudioToolbox.framework/AudioToolbox")]
internal static partial int AudioQueuePause(nint audioQueue);
[LibraryImport("/System/Library/Frameworks/AudioToolbox.framework/AudioToolbox")]
internal static partial int AudioQueueStop(nint audioQueue, [MarshalAs(UnmanagedType.I1)] bool immediate);
[LibraryImport("/System/Library/Frameworks/AudioToolbox.framework/AudioToolbox")]
internal static partial int AudioQueueSetParameter(
nint audioQueue,
uint parameterID,
float value);
[LibraryImport("/System/Library/Frameworks/AudioToolbox.framework/AudioToolbox")]
internal static partial int AudioQueueEnqueueBuffer(
nint audioQueue,
nint buffer,
uint numPacketDescs,
nint packetDescs);
[StructLayout(LayoutKind.Sequential)]
internal struct AudioQueueBuffer
{
public uint AudioDataBytesCapacity;
public nint AudioData;
public uint AudioDataByteSize;
public nint UserData;
public uint PacketDescriptionCapacity;
public nint PacketDescriptions;
public uint PacketDescriptionCount;
}
internal const uint kAudioQueueParam_Volume = 1;
}
}

View File

@@ -0,0 +1,13 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\Ryujinx.Audio\Ryujinx.Audio.csproj" />
<ProjectReference Include="..\Ryujinx.Common\Ryujinx.Common.csproj" />
</ItemGroup>
</Project>

View File

@@ -10,7 +10,8 @@ using static Ryujinx.Audio.Integration.IHardwareDeviceDriver;
namespace Ryujinx.Audio.Backends.OpenAL
{
public class OpenALHardwareDeviceDriver : IHardwareDeviceDriver
// ReSharper disable once InconsistentNaming
public sealed class OpenALHardwareDeviceDriver : IHardwareDeviceDriver
{
private readonly ALDevice _device;
private readonly ALContext _context;
@@ -148,7 +149,7 @@ namespace Ryujinx.Audio.Backends.OpenAL
Dispose(true);
}
protected virtual void Dispose(bool disposing)
private void Dispose(bool disposing)
{
if (disposing)
{

View File

@@ -9,7 +9,8 @@ using System.Threading;
namespace Ryujinx.Audio.Backends.OpenAL
{
class OpenALHardwareDeviceSession : HardwareDeviceSessionOutputBase
// ReSharper disable once InconsistentNaming
sealed class OpenALHardwareDeviceSession : HardwareDeviceSessionOutputBase
{
private readonly OpenALHardwareDeviceDriver _driver;
private readonly int _sourceId;
@@ -190,7 +191,7 @@ namespace Ryujinx.Audio.Backends.OpenAL
}
}
protected virtual void Dispose(bool disposing)
private void Dispose(bool disposing)
{
if (disposing && _driver.Unregister(this))
{

View File

@@ -7,7 +7,7 @@
<ItemGroup>
<ProjectReference Include="..\Ryujinx.Audio\Ryujinx.Audio.csproj" />
<ProjectReference Include="..\Ryujinx.SDL2.Common\Ryujinx.SDL2.Common.csproj" />
<ProjectReference Include="..\Ryujinx.SDL3.Common\Ryujinx.SDL3.Common.csproj" />
</ItemGroup>
</Project>

View File

@@ -1,12 +1,12 @@
namespace Ryujinx.Audio.Backends.SDL2
namespace Ryujinx.Audio.Backends.SDL3
{
class SDL2AudioBuffer
class SDL3AudioBuffer
{
public readonly ulong DriverIdentifier;
public readonly ulong SampleCount;
public ulong SamplePlayed;
public SDL2AudioBuffer(ulong driverIdentifier, ulong sampleCount)
public SDL3AudioBuffer(ulong driverIdentifier, ulong sampleCount)
{
DriverIdentifier = driverIdentifier;
SampleCount = sampleCount;

View File

@@ -2,42 +2,41 @@ using Ryujinx.Audio.Common;
using Ryujinx.Audio.Integration;
using Ryujinx.Common.Logging;
using Ryujinx.Memory;
using Ryujinx.SDL2.Common;
using Ryujinx.SDL3.Common;
using System;
using System.Collections.Concurrent;
using System.Runtime.InteropServices;
using System.Threading;
using static Ryujinx.Audio.Integration.IHardwareDeviceDriver;
using static SDL2.SDL;
using SDL;
using static SDL.SDL3;
using System.Runtime.InteropServices;
namespace Ryujinx.Audio.Backends.SDL2
namespace Ryujinx.Audio.Backends.SDL3
{
public class SDL2HardwareDeviceDriver : IHardwareDeviceDriver
using unsafe SDL_AudioStreamCallbackPointer = delegate* unmanaged[Cdecl]<nint, SDL_AudioStream*, int, int, void>;
public sealed class SDL3HardwareDeviceDriver : IHardwareDeviceDriver
{
private readonly ManualResetEvent _updateRequiredEvent;
private readonly ManualResetEvent _pauseEvent;
private readonly ConcurrentDictionary<SDL2HardwareDeviceSession, byte> _sessions;
private readonly ConcurrentDictionary<SDL3HardwareDeviceSession, byte> _sessions;
private readonly bool _supportSurroundConfiguration;
public float Volume { get; set; }
// TODO: Add this to SDL2-CS
// NOTE: We use a DllImport here because of marshaling issue for spec.
[DllImport("SDL2")]
private static extern int SDL_GetDefaultAudioInfo(nint name, out SDL_AudioSpec spec, int isCapture);
public SDL2HardwareDeviceDriver()
public unsafe SDL3HardwareDeviceDriver()
{
_updateRequiredEvent = new ManualResetEvent(false);
_pauseEvent = new ManualResetEvent(true);
_sessions = new ConcurrentDictionary<SDL2HardwareDeviceSession, byte>();
_sessions = new ConcurrentDictionary<SDL3HardwareDeviceSession, byte>();
SDL2Driver.Instance.Initialize();
SDL3Driver.Instance.Initialize();
int res = SDL_GetDefaultAudioInfo(nint.Zero, out SDL_AudioSpec spec, 0);
if (res != 0)
SDL_AudioSpec spec;
if (!SDL_GetAudioDeviceFormat(SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK, &spec, null))
{
Logger.Error?.Print(LogClass.Application,
$"SDL_GetDefaultAudioInfo failed with error \"{SDL_GetError()}\"");
@@ -54,16 +53,16 @@ namespace Ryujinx.Audio.Backends.SDL2
public static bool IsSupported => IsSupportedInternal();
private static bool IsSupportedInternal()
private unsafe static bool IsSupportedInternal()
{
uint device = OpenStream(SampleFormat.PcmInt16, Constants.TargetSampleRate, Constants.ChannelCountMax, Constants.TargetSampleCount, null);
SDL_AudioStream* device = OpenStream(SampleFormat.PcmInt16, Constants.TargetSampleRate, Constants.ChannelCountMax, Constants.TargetSampleCount, null);
if (device != 0)
if (device != null)
{
SDL_CloseAudioDevice(device);
SDL_DestroyAudioStream(device);
}
return device != 0;
return device != null;
}
public ManualResetEvent GetUpdateRequiredEvent()
@@ -90,67 +89,68 @@ namespace Ryujinx.Audio.Backends.SDL2
if (direction != Direction.Output)
{
throw new NotImplementedException("Input direction is currently not implemented on SDL2 backend!");
throw new NotImplementedException("Input direction is currently not implemented on SDL3 backend!");
}
SDL2HardwareDeviceSession session = new(this, memoryManager, sampleFormat, sampleRate, channelCount);
SDL3HardwareDeviceSession session = new(this, memoryManager, sampleFormat, sampleRate, channelCount);
_sessions.TryAdd(session, 0);
return session;
}
internal bool Unregister(SDL2HardwareDeviceSession session)
internal bool Unregister(SDL3HardwareDeviceSession session)
{
return _sessions.TryRemove(session, out _);
}
private static SDL_AudioSpec GetSDL2Spec(SampleFormat requestedSampleFormat, uint requestedSampleRate, uint requestedChannelCount, uint sampleCount)
private static SDL_AudioSpec GetSDL3Spec(SampleFormat requestedSampleFormat, uint requestedSampleRate, uint requestedChannelCount)
{
return new SDL_AudioSpec
{
channels = (byte)requestedChannelCount,
format = GetSDL2Format(requestedSampleFormat),
format = GetSDL3Format(requestedSampleFormat),
freq = (int)requestedSampleRate,
samples = (ushort)sampleCount,
};
}
internal static ushort GetSDL2Format(SampleFormat format)
internal static SDL_AudioFormat GetSDL3Format(SampleFormat format)
{
return format switch
{
SampleFormat.PcmInt8 => AUDIO_S8,
SampleFormat.PcmInt16 => AUDIO_S16,
SampleFormat.PcmInt32 => AUDIO_S32,
SampleFormat.PcmFloat => AUDIO_F32,
SampleFormat.PcmInt8 => SDL_AudioFormat.SDL_AUDIO_S8,
SampleFormat.PcmInt16 => SDL_AudioFormat.SDL_AUDIO_S16LE,
SampleFormat.PcmInt32 => SDL_AudioFormat.SDL_AUDIO_S32LE,
SampleFormat.PcmFloat => SDL_AudioFormat.SDL_AUDIO_F32LE,
_ => throw new ArgumentException($"Unsupported sample format {format}"),
};
}
internal static uint OpenStream(SampleFormat requestedSampleFormat, uint requestedSampleRate, uint requestedChannelCount, uint sampleCount, SDL_AudioCallback callback)
internal unsafe static SDL_AudioStream* OpenStream(SampleFormat requestedSampleFormat, uint requestedSampleRate, uint requestedChannelCount, uint sampleCount, SDL3HardwareDeviceSession.SDL_AudioStreamCallback callback)
{
SDL_AudioSpec desired = GetSDL2Spec(requestedSampleFormat, requestedSampleRate, requestedChannelCount, sampleCount);
SDL_AudioSpec desired = GetSDL3Spec(requestedSampleFormat, requestedSampleRate, requestedChannelCount);
SDL_AudioSpec got = desired;
var pCallback = callback != null ? (SDL_AudioStreamCallbackPointer)Marshal.GetFunctionPointerForDelegate(callback) : null;
desired.callback = callback;
// From SDL 3 and on, SDL requires us to set this as a hint
SDL_SetHint(SDL_HINT_AUDIO_DEVICE_SAMPLE_FRAMES, $"{sampleCount}");
SDL_AudioStream* device = SDL_OpenAudioDeviceStream(SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK, &got, pCallback, 0);
uint device = SDL_OpenAudioDevice(nint.Zero, 0, ref desired, out SDL_AudioSpec got, 0);
if (device == 0)
if (device == null)
{
Logger.Error?.Print(LogClass.Application, $"SDL2 open audio device initialization failed with error \"{SDL_GetError()}\"");
Logger.Error?.Print(LogClass.Application, $"SDL3 open audio device initialization failed with error \"{SDL_GetError()}\"");
return 0;
return null;
}
bool isValid = got.format == desired.format && got.freq == desired.freq && got.channels == desired.channels;
if (!isValid)
{
Logger.Error?.Print(LogClass.Application, "SDL2 open audio device is not valid");
SDL_CloseAudioDevice(device);
Logger.Error?.Print(LogClass.Application, "SDL3 open audio device is not valid");
SDL_DestroyAudioStream(device);
return 0;
return null;
}
return device;
@@ -162,16 +162,16 @@ namespace Ryujinx.Audio.Backends.SDL2
Dispose(true);
}
protected virtual void Dispose(bool disposing)
private void Dispose(bool disposing)
{
if (disposing)
{
foreach (SDL2HardwareDeviceSession session in _sessions.Keys)
foreach (SDL3HardwareDeviceSession session in _sessions.Keys)
{
session.Dispose();
}
SDL2Driver.Instance.Dispose();
SDL3Driver.Instance.Dispose();
_pauseEvent.Dispose();
}

View File

@@ -6,36 +6,40 @@ using Ryujinx.Memory;
using System;
using System.Collections.Concurrent;
using System.Threading;
using SDL;
using static SDL.SDL3;
using System.Runtime.InteropServices;
using static SDL2.SDL;
namespace Ryujinx.Audio.Backends.SDL2
namespace Ryujinx.Audio.Backends.SDL3
{
class SDL2HardwareDeviceSession : HardwareDeviceSessionOutputBase
sealed unsafe class SDL3HardwareDeviceSession : HardwareDeviceSessionOutputBase
{
private readonly SDL2HardwareDeviceDriver _driver;
private readonly ConcurrentQueue<SDL2AudioBuffer> _queuedBuffers;
private readonly SDL3HardwareDeviceDriver _driver;
private readonly ConcurrentQueue<SDL3AudioBuffer> _queuedBuffers;
private readonly DynamicRingBuffer _ringBuffer;
private ulong _playedSampleCount;
private readonly ManualResetEvent _updateRequiredEvent;
private uint _outputStream;
private SDL_AudioStream* _outputStream;
private bool _hasSetupError;
private readonly SDL_AudioCallback _callbackDelegate;
private readonly SDL_AudioStreamCallback _callbackDelegate;
private readonly int _bytesPerFrame;
private uint _sampleCount;
private bool _started;
private float _volume;
private readonly ushort _nativeSampleFormat;
private readonly SDL_AudioFormat _nativeSampleFormat;
public SDL2HardwareDeviceSession(SDL2HardwareDeviceDriver driver, IVirtualMemoryManager memoryManager, SampleFormat requestedSampleFormat, uint requestedSampleRate, uint requestedChannelCount) : base(memoryManager, requestedSampleFormat, requestedSampleRate, requestedChannelCount)
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
internal delegate void SDL_AudioStreamCallback(nint session, SDL_AudioStream* stream, int stream_count, int device_count);
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<SDL2AudioBuffer>();
_queuedBuffers = new ConcurrentQueue<SDL3AudioBuffer>();
_ringBuffer = new DynamicRingBuffer();
_callbackDelegate = Update;
_bytesPerFrame = BackendHelper.GetSampleSize(RequestedSampleFormat) * (int)RequestedChannelCount;
_nativeSampleFormat = SDL2HardwareDeviceDriver.GetSDL2Format(RequestedSampleFormat);
_nativeSampleFormat = SDL3HardwareDeviceDriver.GetSDL3Format(RequestedSampleFormat);
_sampleCount = uint.MaxValue;
_started = false;
_volume = 1f;
@@ -44,45 +48,51 @@ namespace Ryujinx.Audio.Backends.SDL2
private void EnsureAudioStreamSetup(AudioBuffer buffer)
{
uint bufferSampleCount = (uint)GetSampleCount(buffer);
bool needAudioSetup = (_outputStream == 0 && !_hasSetupError) ||
bool needAudioSetup = (_outputStream == null && !_hasSetupError) ||
(bufferSampleCount >= Constants.TargetSampleCount && bufferSampleCount < _sampleCount);
if (needAudioSetup)
{
_sampleCount = Math.Max(Constants.TargetSampleCount, bufferSampleCount);
uint newOutputStream = SDL2HardwareDeviceDriver.OpenStream(RequestedSampleFormat, RequestedSampleRate, RequestedChannelCount, _sampleCount, _callbackDelegate);
SDL_AudioStream* newOutputStream = SDL3HardwareDeviceDriver.OpenStream(RequestedSampleFormat, RequestedSampleRate, RequestedChannelCount, _sampleCount, _callbackDelegate);
_hasSetupError = newOutputStream == 0;
_hasSetupError = newOutputStream == null;
if (!_hasSetupError)
{
if (_outputStream != 0)
if (_outputStream != null)
{
SDL_CloseAudioDevice(_outputStream);
SDL_DestroyAudioStream(_outputStream);
}
_outputStream = newOutputStream;
SDL_PauseAudioDevice(_outputStream, _started ? 0 : 1);
if (_started) {
SDL_ResumeAudioStreamDevice(_outputStream);
} else {
SDL_PauseAudioStreamDevice(_outputStream);
}
Logger.Info?.Print(LogClass.Audio, $"New audio stream setup with a target sample count of {_sampleCount}");
}
}
}
private unsafe void Update(nint userdata, nint stream, int streamLength)
private unsafe void Update(nint userdata, SDL_AudioStream* streamDevice, int additionalAmount, int totalAmmount)
{
Span<byte> streamSpan = new((void*)stream, streamLength);
using SpanOwner<byte> stream = SpanOwner<byte>.Rent(additionalAmount);
Span<byte> streamSpan = stream.Span;
int maxFrameCount = (int)GetSampleCount(streamLength);
int maxFrameCount = (int)GetSampleCount(additionalAmount);
int bufferedFrames = _ringBuffer.Length / _bytesPerFrame;
int frameCount = Math.Min(bufferedFrames, maxFrameCount);
if (frameCount == 0)
{
// SDL2 left the responsibility to the user to clear the buffer.
// SDL3 left the responsibility to the user to clear the buffer.
streamSpan.Clear();
return;
@@ -94,15 +104,17 @@ namespace Ryujinx.Audio.Backends.SDL2
_ringBuffer.Read(samples, 0, samples.Length);
fixed (byte* p = samples)
{
nint pStreamSrc = (nint)p;
// Zero the dest buffer
streamSpan.Clear();
// Zero the dest buffer
streamSpan.Clear();
fixed (byte* pStreamDst = streamSpan) {
fixed (byte* pStreamSrc = samples)
{
// Apply volume to written data
SDL_MixAudioFormat(stream, pStreamSrc, _nativeSampleFormat, (uint)samples.Length, (int)(_driver.Volume * _volume * SDL_MIX_MAXVOLUME));
// Apply volume to written data
SDL_MixAudio(pStreamDst, pStreamSrc, _nativeSampleFormat, (uint)samples.Length, _driver.Volume * _volume);
SDL_PutAudioStreamData(streamDevice, (nint)pStreamDst, additionalAmount);
}
}
ulong sampleCount = GetSampleCount(samples.Length);
@@ -111,7 +123,7 @@ namespace Ryujinx.Audio.Backends.SDL2
bool needUpdate = false;
while (availaibleSampleCount > 0 && _queuedBuffers.TryPeek(out SDL2AudioBuffer driverBuffer))
while (availaibleSampleCount > 0 && _queuedBuffers.TryPeek(out SDL3AudioBuffer driverBuffer))
{
ulong sampleStillNeeded = driverBuffer.SampleCount - Interlocked.Read(ref driverBuffer.SamplePlayed);
ulong playedAudioBufferSampleCount = Math.Min(sampleStillNeeded, availaibleSampleCount);
@@ -152,9 +164,9 @@ namespace Ryujinx.Audio.Backends.SDL2
{
EnsureAudioStreamSetup(buffer);
if (_outputStream != 0)
if (_outputStream != null)
{
SDL2AudioBuffer driverBuffer = new(buffer.DataPointer, GetSampleCount(buffer));
SDL3AudioBuffer driverBuffer = new(buffer.DataPointer, GetSampleCount(buffer));
_ringBuffer.Write(buffer.Data, 0, buffer.Data.Length);
@@ -177,9 +189,9 @@ namespace Ryujinx.Audio.Backends.SDL2
{
if (!_started)
{
if (_outputStream != 0)
if (_outputStream != null)
{
SDL_PauseAudioDevice(_outputStream, 0);
SDL_ResumeAudioStreamDevice(_outputStream);
}
_started = true;
@@ -190,9 +202,9 @@ namespace Ryujinx.Audio.Backends.SDL2
{
if (_started)
{
if (_outputStream != 0)
if (_outputStream != null)
{
SDL_PauseAudioDevice(_outputStream, 1);
SDL_PauseAudioStreamDevice(_outputStream);
}
_started = false;
@@ -203,7 +215,7 @@ namespace Ryujinx.Audio.Backends.SDL2
public override bool WasBufferFullyConsumed(AudioBuffer buffer)
{
if (!_queuedBuffers.TryPeek(out SDL2AudioBuffer driverBuffer))
if (!_queuedBuffers.TryPeek(out SDL3AudioBuffer driverBuffer))
{
return true;
}
@@ -211,16 +223,16 @@ namespace Ryujinx.Audio.Backends.SDL2
return driverBuffer.DriverIdentifier != buffer.DataPointer;
}
protected virtual void Dispose(bool disposing)
private void Dispose(bool disposing)
{
if (disposing && _driver.Unregister(this))
{
PrepareToClose();
Stop();
if (_outputStream != 0)
if (_outputStream != null)
{
SDL_CloseAudioDevice(_outputStream);
SDL_DestroyAudioStream(_outputStream);
}
}
}

View File

@@ -130,7 +130,7 @@ namespace Ryujinx.Audio.Backends.SoundIo.Native
unsafe
{
int* frameCountPtr = &nativeFrameCount;
IntPtr* arenasPtr = &arenas;
nint* arenasPtr = &arenas;
CheckError(soundio_outstream_begin_write(_context, (nint)arenasPtr, (nint)frameCountPtr));
frameCount = *frameCountPtr;

View File

@@ -10,7 +10,7 @@ using static Ryujinx.Audio.Integration.IHardwareDeviceDriver;
namespace Ryujinx.Audio.Backends.SoundIo
{
public class SoundIoHardwareDeviceDriver : IHardwareDeviceDriver
public sealed class SoundIoHardwareDeviceDriver : IHardwareDeviceDriver
{
private readonly SoundIoContext _audioContext;
private readonly SoundIoDeviceContext _audioDevice;
@@ -227,7 +227,7 @@ namespace Ryujinx.Audio.Backends.SoundIo
}
}
protected virtual void Dispose(bool disposing)
private void Dispose(bool disposing)
{
if (disposing)
{

View File

@@ -11,7 +11,7 @@ using static Ryujinx.Audio.Backends.SoundIo.Native.SoundIo;
namespace Ryujinx.Audio.Backends.SoundIo
{
class SoundIoHardwareDeviceSession : HardwareDeviceSessionOutputBase
sealed class SoundIoHardwareDeviceSession : HardwareDeviceSessionOutputBase
{
private readonly SoundIoHardwareDeviceDriver _driver;
private readonly ConcurrentQueue<SoundIoAudioBuffer> _queuedBuffers;
@@ -428,7 +428,7 @@ namespace Ryujinx.Audio.Backends.SoundIo
}
}
protected virtual void Dispose(bool disposing)
private void Dispose(bool disposing)
{
if (disposing && _driver.Unregister(this))
{

View File

@@ -58,16 +58,16 @@ namespace Ryujinx.Audio.Backends.CompatLayer
switch (realSampleFormat)
{
case SampleFormat.PcmInt8:
PcmHelper.ConvertSampleToPcm8(MemoryMarshal.Cast<byte, sbyte>(convertedSamples), samples);
PcmHelper.ConvertSampleToPcm8(MemoryMarshal.Cast<byte, sbyte>(new Span<byte>(convertedSamples)), samples);
break;
case SampleFormat.PcmInt24:
PcmHelper.ConvertSampleToPcm24(convertedSamples, samples);
break;
case SampleFormat.PcmInt32:
PcmHelper.ConvertSampleToPcm32(MemoryMarshal.Cast<byte, int>(convertedSamples), samples);
PcmHelper.ConvertSampleToPcm32(MemoryMarshal.Cast<byte, int>(new Span<byte>(convertedSamples)), samples);
break;
case SampleFormat.PcmFloat:
PcmHelper.ConvertSampleToPcmFloat(MemoryMarshal.Cast<byte, float>(convertedSamples), samples);
PcmHelper.ConvertSampleToPcmFloat(MemoryMarshal.Cast<byte, float>(new Span<byte>(convertedSamples)), samples);
break;
default:
throw new NotImplementedException($"Sample format conversion from {_userSampleFormat} to {realSampleFormat} not implemented.");

View File

@@ -27,7 +27,7 @@ namespace Ryujinx.Audio.Integration
public void AppendBuffer(ReadOnlySpan<short> data, uint channelCount)
{
data.CopyTo(MemoryMarshal.Cast<byte, short>(_buffer));
data.CopyTo(MemoryMarshal.Cast<byte, short>(new Span<byte>(_buffer)));
_session.QueueBuffer(new AudioBuffer
{

View File

@@ -17,7 +17,7 @@ namespace Ryujinx.Audio.Renderer.Common
public uint MixesSize;
public uint SinksSize;
public uint PerformanceBufferSize;
public uint Unknown24;
public uint SplitterSize;
public uint RenderInfoSize;
#pragma warning disable IDE0051, CS0169 // Remove unused field

View File

@@ -11,27 +11,32 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
{
public bool Enabled { get; set; }
public int NodeId { get; }
public int NodeId { get; private set; }
public CommandType CommandType => CommandType.AdpcmDataSourceVersion1;
public uint EstimatedProcessingTime { get; set; }
public ushort OutputBufferIndex { get; }
public uint SampleRate { get; }
public ushort OutputBufferIndex { get; private set; }
public uint SampleRate { get; private set; }
public float Pitch { get; }
public float Pitch { get; private set; }
public WaveBuffer[] WaveBuffers { get; }
public Memory<VoiceState> State { get; }
public Memory<VoiceState> State { get; private set; }
public ulong AdpcmParameter { get; }
public ulong AdpcmParameterSize { get; }
public ulong AdpcmParameter { get; private set; }
public ulong AdpcmParameterSize { get; private set; }
public DecodingBehaviour DecodingBehaviour { get; }
public DecodingBehaviour DecodingBehaviour { get; private set; }
public AdpcmDataSourceCommandVersion1(ref VoiceInfo serverInfo, Memory<VoiceState> state, ushort outputBufferIndex, int nodeId)
public AdpcmDataSourceCommandVersion1()
{
WaveBuffers = new WaveBuffer[Constants.VoiceWaveBufferCount];
}
public AdpcmDataSourceCommandVersion1 Initialize(ref VoiceInfo serverInfo, Memory<VoiceState> state, ushort outputBufferIndex, int nodeId)
{
Enabled = true;
NodeId = nodeId;
@@ -42,8 +47,6 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
Span<Server.Voice.WaveBuffer> waveBufferSpan = serverInfo.WaveBuffers.AsSpan();
WaveBuffers = new WaveBuffer[Constants.VoiceWaveBufferCount];
for (int i = 0; i < WaveBuffers.Length; i++)
{
ref Server.Voice.WaveBuffer voiceWaveBuffer = ref waveBufferSpan[i];
@@ -55,6 +58,8 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
AdpcmParameterSize = serverInfo.DataSourceStateAddressInfo.Size;
State = state;
DecodingBehaviour = serverInfo.DecodingBehaviour;
return this;
}
public void Process(CommandList context)

Some files were not shown because too many files have changed in this diff Show More