mirror of
https://git.ryujinx.app/ryubing/ryujinx.git
synced 2026-02-22 08:41:08 +00:00
Compare commits
122 Commits
Canary-1.3
...
1.3.3
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e2143d43bc | ||
|
|
4444ecae41 | ||
|
|
4f5a236c21 | ||
|
|
db31ff15c7 | ||
|
|
e70cd08c9a | ||
|
|
60b9723df4 | ||
|
|
1900924a78 | ||
|
|
5fb0b5e7ec | ||
|
|
8d0e28ed9d | ||
|
|
a4eafd01f5 | ||
|
|
f55aa87ab9 | ||
|
|
bb4f8d8749 | ||
|
|
a6cb681f10 | ||
|
|
00ff3e6b1b | ||
|
|
12510a5396 | ||
|
|
ea30a0ed24 | ||
|
|
df40a69872 | ||
|
|
b000f91dad | ||
|
|
a60b2a0ba3 | ||
|
|
4c9b48b754 | ||
|
|
3bd7d5904e | ||
|
|
23eb9a3043 | ||
|
|
931ec44406 | ||
|
|
d68efa98ba | ||
|
|
ded76801d1 | ||
|
|
6084df7473 | ||
|
|
f3953c6039 | ||
|
|
91f5247e7f | ||
|
|
5658402c6b | ||
|
|
1b2c93e188 | ||
|
|
9e599ff325 | ||
|
|
7a5f430b59 | ||
|
|
1e340ce2f3 | ||
|
|
dbb4e63e1e | ||
|
|
d00ab52fa2 | ||
|
|
959af3613d | ||
|
|
3309fb2351 | ||
|
|
e1e8628a6f | ||
|
|
3969191605 | ||
|
|
07c7b39053 | ||
|
|
053efaa414 | ||
|
|
56e6339553 | ||
|
|
042362ee2b | ||
|
|
7347ee2212 | ||
|
|
01a9b636af | ||
|
|
6e47d8548c | ||
|
|
da340f5615 | ||
|
|
be249f7bdc | ||
|
|
462c93e1ff | ||
|
|
573a6f32fe | ||
|
|
7846f58cad | ||
|
|
0203065fed | ||
|
|
7319a2dafc | ||
|
|
f992735656 | ||
|
|
48b9f2ab93 | ||
|
|
50ab108ee1 | ||
|
|
d499449f57 | ||
|
|
cd3c614021 | ||
|
|
5fa82bb1f5 | ||
|
|
234cb99325 | ||
|
|
ab7914f235 | ||
|
|
3df6b7c0f5 | ||
|
|
37e81481c4 | ||
|
|
4d8b799763 | ||
|
|
cb786b7147 | ||
|
|
2a308f50c0 | ||
|
|
b51c5cead6 | ||
|
|
461c1f5342 | ||
|
|
cfea61b3a0 | ||
|
|
ae2e9a73ab | ||
|
|
c6f22318a7 | ||
|
|
dd5e1b99b1 | ||
|
|
c863ffd353 | ||
|
|
d6d089b81b | ||
|
|
c482b7a1c0 | ||
|
|
01e1cd4d5a | ||
|
|
bb06eb751b | ||
|
|
5613d3f35d | ||
|
|
54d4d184f4 | ||
|
|
d22756f1bd | ||
|
|
324f18aa5f | ||
|
|
31870707cf | ||
|
|
fd6648e30a | ||
|
|
bc6be4e088 | ||
|
|
64a6494d90 | ||
|
|
ddb8afa6f4 | ||
|
|
c2f4118b1f | ||
|
|
47aa2c1513 | ||
|
|
f3a2f59683 | ||
|
|
51bcb9e128 | ||
|
|
dce5f0eb55 | ||
|
|
f2eb3749f9 | ||
|
|
45b2e613cf | ||
|
|
932c480325 | ||
|
|
0e24435414 | ||
|
|
a5cf0482b4 | ||
|
|
14e794af84 | ||
|
|
29a02f4787 | ||
|
|
e2f9d84b64 | ||
|
|
0cc94fdf37 | ||
|
|
74a9b94227 | ||
|
|
d3208a4c44 | ||
|
|
5d136980a3 | ||
|
|
572ad1eac5 | ||
|
|
6bb2af0091 | ||
|
|
534a194ed9 | ||
|
|
331805791e | ||
|
|
6773406bb6 | ||
|
|
6226eadf55 | ||
|
|
b1cde5fd97 | ||
|
|
39944b2063 | ||
|
|
973c6ba5df | ||
|
|
6803c91da8 | ||
|
|
557c2a50b2 | ||
|
|
77a797f154 | ||
|
|
faf9e3cdd7 | ||
|
|
7bc80ed4fe | ||
|
|
a1d44ec496 | ||
|
|
bab3beb0ac | ||
|
|
aa9e74339b | ||
|
|
908273d848 | ||
|
|
b51ad11574 |
@@ -45,10 +45,10 @@ dotnet_separate_import_directive_groups = false
|
||||
dotnet_sort_system_directives_first = false
|
||||
|
||||
# this. and Me. preferences
|
||||
dotnet_style_qualification_for_event = false:suggestion
|
||||
dotnet_style_qualification_for_field = false:suggestion
|
||||
dotnet_style_qualification_for_method = false:suggestion
|
||||
dotnet_style_qualification_for_property = false:suggestion
|
||||
dotnet_style_qualification_for_event = false:silent
|
||||
dotnet_style_qualification_for_field = false:silent
|
||||
dotnet_style_qualification_for_method = false:silent
|
||||
dotnet_style_qualification_for_property = false:silent
|
||||
|
||||
# Language keywords vs BCL types preferences
|
||||
dotnet_style_predefined_type_for_locals_parameters_members = true:silent
|
||||
@@ -257,14 +257,12 @@ csharp_prefer_system_threading_lock = true:suggestion
|
||||
dotnet_diagnostic.CA1069.severity = none # CA1069: Enums values should not be duplicated
|
||||
# Disable Collection initialization can be simplified
|
||||
dotnet_diagnostic.IDE0028.severity = none
|
||||
dotnet_diagnostic.IDE0079.severity = none # IDE0079: Remove unnecessary suppression
|
||||
dotnet_diagnostic.IDE0130.severity = none # IDE0130: Namespace does not match folder structure
|
||||
dotnet_diagnostic.IDE0300.severity = none
|
||||
dotnet_diagnostic.IDE0301.severity = none
|
||||
dotnet_diagnostic.IDE0302.severity = none
|
||||
dotnet_diagnostic.IDE0305.severity = none
|
||||
dotnet_diagnostic.CS9113.severity = none # CS9113: Parameter 'value' is unread
|
||||
dotnet_diagnostic.CS0649.severity = none # CS0649: Field is never assigned to, and will always have its default value
|
||||
dotnet_diagnostic.IDE0130.severity = none # IDE0130: Namespace does not match folder structure
|
||||
|
||||
[src/Ryujinx/UI/ViewModels/**.cs]
|
||||
# Disable "mark members as static" rule for ViewModels
|
||||
|
||||
13
.github/workflows/canary.yml
vendored
13
.github/workflows/canary.yml
vendored
@@ -102,10 +102,10 @@ jobs:
|
||||
chmod +x Ryujinx.sh Ryujinx
|
||||
tar -czvf ../release_output/ryujinx-canary-${{ steps.version_info.outputs.build_version }}-${{ matrix.platform.zip_os_name }}.tar.gz ../publish
|
||||
popd
|
||||
|
||||
|
||||
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"
|
||||
shell: bash
|
||||
|
||||
|
||||
- name: Build AppImage (Linux)
|
||||
if: matrix.platform.os == 'ubuntu-latest'
|
||||
run: |
|
||||
@@ -134,16 +134,13 @@ jobs:
|
||||
exit 1
|
||||
fi
|
||||
|
||||
export UFLAG="gh-releases-zsync|${{ secrets.RC_OWNER }}${{ secrets.RC_CANARY_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-canary-$BUILD_VERSION-$ARCH_NAME.AppImage
|
||||
mv Ryujinx.AppImage.zsync ../release_output/ryujinx-canary-$BUILD_VERSION-$ARCH_NAME.AppImage.zsync
|
||||
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 --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.zsync"
|
||||
shell: bash
|
||||
|
||||
macos_release:
|
||||
@@ -243,3 +240,7 @@ jobs:
|
||||
- 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"
|
||||
|
||||
- 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 }}'
|
||||
|
||||
11
.github/workflows/release.yml
vendored
11
.github/workflows/release.yml
vendored
@@ -96,7 +96,7 @@ jobs:
|
||||
shell: bash
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
|
||||
- name: Build AppImage (Linux)
|
||||
if: matrix.platform.os == 'ubuntu-latest'
|
||||
run: |
|
||||
@@ -125,16 +125,13 @@ jobs:
|
||||
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:
|
||||
@@ -228,3 +225,7 @@ jobs:
|
||||
- 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"
|
||||
|
||||
- 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 }}'
|
||||
|
||||
@@ -1,18 +0,0 @@
|
||||
function pub {
|
||||
dotnet publish -c release
|
||||
}
|
||||
|
||||
function package {
|
||||
cd src/$1
|
||||
pub
|
||||
mv bin/Release/$1.1.0.0.nupkg ../../pkgs/$1.1.0.0.nupkg
|
||||
cd ../../
|
||||
}
|
||||
|
||||
rm -rf pkgs
|
||||
mkdir pkgs
|
||||
|
||||
package ARMeilleure
|
||||
package Ryujinx.Memory
|
||||
|
||||
dotnet nuget push pkgs/*.nupkg --source RyubingPkgs
|
||||
40
CHANGELOG.md
40
CHANGELOG.md
@@ -21,8 +21,8 @@ Additionally, 1.2.74 & 75 were fixes for uploading Windows build artifacts.
|
||||
|
||||
1.2.76 fixes a rare crash on startup.
|
||||
|
||||
## [1.2.72](<https://github.com/GreemDev/Ryujinx/releases/tag/1.2.72>) - 2024-11-03
|
||||
PRs [#163](<https://github.com/GreemDev/Ryujinx/pull/163>), [#164](<https://github.com/GreemDev/Ryujinx/pull/164>), [#139](<https://github.com/GreemDev/Ryujinx/pull/139>)
|
||||
## [1.2.72](<https://git.ryujinx.app/ryubing/ryujinx/-/tags/1.2.72>) - 2024-11-03
|
||||
PRs [#163](<https://web.archive.org/web/20241123015123/https://github.com/GreemDev/Ryujinx/pull/163>), [#164](<https://web.archive.org/web/20250307192526/https://github.com/Ryubing/Ryujinx/pull/164>), [#139](<https://web.archive.org/web/20250306123457/https://github.com/Ryubing/Ryujinx/pull/139>)
|
||||
### HLE:
|
||||
- Add DebugMouse HID device.
|
||||
- Fixes "Clock Tower Rewind" crashing while loading.
|
||||
@@ -32,7 +32,7 @@ PRs [#163](<https://github.com/GreemDev/Ryujinx/pull/163>), [#164](<https://gith
|
||||
### misc:
|
||||
- Update macOS distribution .icns.
|
||||
|
||||
## [1.2.69](<https://github.com/GreemDev/Ryujinx/releases/tag/1.2.69>) - 2024-11-01
|
||||
## [1.2.69](<https://git.ryujinx.app/ryubing/ryujinx/-/tags/1.2.69>) - 2024-11-01
|
||||
### Infra:
|
||||
- Compile the native libraries into the Ryujinx executable.
|
||||
- Remove `libarmeilleure-jitsupport.dylib` from Windows & Linux releases (dylibs are macOS-only)
|
||||
@@ -42,8 +42,8 @@ PRs [#163](<https://github.com/GreemDev/Ryujinx/pull/163>), [#164](<https://gith
|
||||
- Replace "" with `string.Empty`.
|
||||
- Code cleanups & simplifications.
|
||||
|
||||
## [1.2.67](<https://github.com/GreemDev/Ryujinx/releases/tag/1.2.67>) - 2024-11-01
|
||||
PRs [#36](<https://github.com/GreemDev/Ryujinx/pull/36>), [#135](<https://github.com/GreemDev/Ryujinx/pull/135>)
|
||||
## [1.2.67](<https://git.ryujinx.app/ryubing/ryujinx/-/tags/1.2.67>) - 2024-11-01
|
||||
PRs [#36](<https://web.archive.org/web/20250306215917/https://github.com/Ryubing/Ryujinx/pull/36>), [#135](<https://web.archive.org/web/20241122135125/https://github.com/GreemDev/Ryujinx/pull/135>)
|
||||
|
||||
### GUI:
|
||||
- Set UseFloatingWatermark to false when watermark is empty
|
||||
@@ -54,8 +54,8 @@ PRs [#36](<https://github.com/GreemDev/Ryujinx/pull/36>), [#135](<https://github
|
||||
- Fix homebrew loading.
|
||||
|
||||
|
||||
## [1.2.64](https://github.com/GreemDev/Ryujinx/releases/tag/1.2.64) - 2024-10-30
|
||||
PRs [#92](https://github.com/GreemDev/Ryujinx/pull/92), [#96](https://github.com/GreemDev/Ryujinx/pull/96), [#97](https://github.com/GreemDev/Ryujinx/pull/97), [#101](https://github.com/GreemDev/Ryujinx/pull/101), [#103](https://github.com/GreemDev/Ryujinx/pull/103)
|
||||
## [1.2.64](https://git.ryujinx.app/ryubing/ryujinx/-/tags/1.2.64) - 2024-10-30
|
||||
PRs [#92](https://web.archive.org/web/20241118052724/https://github.com/GreemDev/Ryujinx/pull/92), ~~[#96](https://github.com/GreemDev/Ryujinx/pull/96)~~, ~~[#97](https://github.com/GreemDev/Ryujinx/pull/97)~~, [#101](https://web.archive.org/web/20250306223605/https://github.com/Ryubing/Ryujinx/pull/101), ~~[#103](https://github.com/GreemDev/Ryujinx/pull/103)~~
|
||||
### GUI:
|
||||
- Option to show classic-style title bar. Requires restart of emulator to take effect.
|
||||
- This is only relevant on Windows. Other Operating Systems default to this being on and not being changeable, because the custom (current) title bar only works on Windows in the first place.
|
||||
@@ -71,14 +71,14 @@ PRs [#92](https://github.com/GreemDev/Ryujinx/pull/92), [#96](https://github.com
|
||||
|
||||
## 1.2.59 - 2024-10-27
|
||||
|
||||
PRs [#88](https://github.com/GreemDev/Ryujinx/pull/88), [#87](https://github.com/GreemDev/Ryujinx/pull/87)
|
||||
PRs ~~[#88](https://github.com/GreemDev/Ryujinx/pull/88), [#87](https://github.com/GreemDev/Ryujinx/pull/87)~~
|
||||
### i18n:
|
||||
- fr_FR:
|
||||
- Add missing translations for new features & fix a couple wrong ones.
|
||||
- Fix Ignore Missing Services / Ignore Applet tooltip.
|
||||
|
||||
## 1.2.57 - 2024-10-27
|
||||
PRs [#60](https://github.com/GreemDev/Ryujinx/pull/60), [#42](https://github.com/GreemDev/Ryujinx/pull/42)
|
||||
PRs ~~[#60](https://github.com/GreemDev/Ryujinx/pull/60)~~, [#42](https://web.archive.org/web/20241126203614/https://github.com/GreemDev/Ryujinx/pull/42)
|
||||
### GUI:
|
||||
- Automatically remove invalid DLC & updates as part of autoload.
|
||||
- Added Thai translation for Ignore Applet hover tooltip.
|
||||
@@ -104,7 +104,7 @@ PRs [#60](https://github.com/GreemDev/Ryujinx/pull/60), [#42](https://github.com
|
||||
- Code cleanup.
|
||||
|
||||
## 1.2.44 - 2024-10-25
|
||||
PR [#59](https://github.com/GreemDev/Ryujinx/pull/59)
|
||||
PR [#59](https://web.archive.org/web/20241125060420/https://github.com/GreemDev/Ryujinx/pull/59)
|
||||
### GUI:
|
||||
- Add descriptions for "ignoring applet" translated into other languages.
|
||||
|
||||
@@ -117,9 +117,9 @@ NOTE: The translation isn't referenced in the code yet, it will be in the next u
|
||||
## 1.2.42 - 2024-10-24
|
||||
Sources:
|
||||
|
||||
Init function: https://github.com/MutantAura/Ryujinx/commit/9cef4ceba40d66492ff775af793ff70e6e7551a9
|
||||
Init function: [archive of github.com/MutantAura/Ryujinx/commit/9cef4ceba40d66492ff775af793ff70e6e7551a9](https://web.archive.org/web/20241122193401/https://github.com/MutantAura/Ryujinx/commit/9cef4ceba40d66492ff775af793ff70e6e7551a9)
|
||||
|
||||
Shader counter: https://github.com/MutantAura/Ryujinx/commit/67b873645fd593e83d042a77bf7ab12e5ec97357
|
||||
Shader counter: ~~https://github.com/MutantAura/Ryujinx/commit/67b873645fd593e83d042a77bf7ab12e5ec97357~~ Original commit has been lost
|
||||
|
||||
Thanks MutantAura :D
|
||||
### GUI:
|
||||
@@ -127,14 +127,14 @@ Thanks MutantAura :D
|
||||
- Remove graphics backend / GPU name event logic in favor of a single init function.
|
||||
|
||||
## 1.2.41 - 2024-10-24
|
||||
PR [#54](https://github.com/GreemDev/Ryujinx/pull/54)
|
||||
PR ~~[#54](https://github.com/GreemDev/Ryujinx/pull/54)~~
|
||||
|
||||
Thanks Whitescatz!
|
||||
### i18n:
|
||||
- th_TH (Thai): Added missing translations, reduce transliterated words, fix grammar.
|
||||
|
||||
## 1.2.40 - 2024-10-23
|
||||
PR [#40](https://github.com/GreemDev/Ryujinx/pull/40)
|
||||
PR ~~[#40](https://github.com/GreemDev/Ryujinx/pull/40)~~
|
||||
|
||||
Thanks Вова С!
|
||||
### GUI:
|
||||
@@ -148,30 +148,30 @@ Thanks Вова С!
|
||||
- Should prevent crashing on config loads in some circumstances.
|
||||
|
||||
## 1.2.38 - 2024-10-23
|
||||
PR [#51](https://github.com/GreemDev/Ryujinx/pull/51)
|
||||
PR [#51](https://web.archive.org/web/20241127022413/https://github.com/GreemDev/Ryujinx/pull/51)
|
||||
### i18n:
|
||||
- zh_CH (Simplified Chinese): Add some missing translations.
|
||||
|
||||
## 1.2.37 - 2024-10-23
|
||||
PR [#37](https://github.com/GreemDev/Ryujinx/pull/37)
|
||||
PR [#37](https://web.archive.org/web/20241123010103/https://github.com/GreemDev/Ryujinx/pull/37)
|
||||
|
||||
Thanks Last Breath!
|
||||
### GUI:
|
||||
- Set the default controller to the Pro Controller.
|
||||
|
||||
## 1.2.36 - 2024-10-21
|
||||
PR [#30](https://github.com/GreemDev/Ryujinx/pull/30)
|
||||
PR ~~[#30](https://github.com/GreemDev/Ryujinx/pull/30)~~
|
||||
### GUI:
|
||||
- Fix repeated dialog popup notifying you of new updates when there aren't any, while having a bundled update inside an XCI and an external update file.
|
||||
|
||||
## 1.2.35 - 2024-10-21
|
||||
PR [#32](https://github.com/GreemDev/Ryujinx/pull/32)
|
||||
PR [#32](https://web.archive.org/web/20241127010942/https://github.com/GreemDev/Ryujinx/pull/32)
|
||||
### GUI:
|
||||
- Replace "expand DRAM" option with a DRAM size dropdown.
|
||||
- Allows for using mods which require a ridiculous amount of memory to allocate from.
|
||||
|
||||
## 1.2.34 - 2024-10-21
|
||||
PR [#29](https://github.com/GreemDev/Ryujinx/pull/29)
|
||||
PR [#29](https://web.archive.org/web/20241125093029/https://github.com/GreemDev/Ryujinx/pull/29)
|
||||
### GUI:
|
||||
- Fix duplicate controller names when 2 controllers of the same type are connected.
|
||||
### INPUT:
|
||||
@@ -248,7 +248,7 @@ Added Low-power PPTC mode strings to the translation files.
|
||||
## 1.2.1-1.2.19 - 2024-10-08 - 2024-10-11
|
||||
### GUI/INFRA/MISC:
|
||||
- Remove GTK UI.
|
||||
- Autoload DLC/Updates from dir ([#12](https://github.com/GreemDev/Ryujinx/pull/12)).
|
||||
- Autoload DLC/Updates from dir ([#12](https://web.archive.org/web/20241127004005/https://github.com/GreemDev/Ryujinx/pull/12)).
|
||||
- Changed executable icon to rainbow logo.
|
||||
- Extract Data > Logo now also extracts the square thumbnail you see for the game in the UI.
|
||||
- The "use random UUID hack" checkbox in the Amiibo screen now remembers its last state when you reopen the window in a given session.
|
||||
|
||||
@@ -19,8 +19,8 @@
|
||||
<PackageVersion Include="CommandLineParser" Version="2.9.1" />
|
||||
<PackageVersion Include="CommunityToolkit.Mvvm" Version="8.4.0"/>
|
||||
<PackageVersion Include="Concentus" Version="2.2.2" />
|
||||
<PackageVersion Include="DiscordRichPresence" Version="1.2.1.24" />
|
||||
<PackageVersion Include="DynamicData" Version="9.0.4" />
|
||||
<PackageVersion Include="DiscordRichPresence" Version="1.6.1.70" />
|
||||
<PackageVersion Include="DynamicData" Version="9.4.1" />
|
||||
<PackageVersion Include="FluentAvaloniaUI" Version="2.0.5" />
|
||||
<PackageVersion Include="Humanizer" Version="2.14.1" />
|
||||
<PackageVersion Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.4" />
|
||||
@@ -40,11 +40,13 @@
|
||||
<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.20.0" />
|
||||
<PackageVersion Include="Ryujinx.LibHac" Version="0.21.0-alpha.116" />
|
||||
<PackageVersion Include="Ryujinx.SDL2-CS" Version="2.30.0-build32" />
|
||||
<PackageVersion Include="Gommon" Version="2.7.1.1" />
|
||||
<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="securifybv.ShellLink" Version="0.1.0" />
|
||||
<PackageVersion Include="Sep" Version="0.6.0" />
|
||||
<PackageVersion Include="Sep" Version="0.11.1" />
|
||||
<PackageVersion Include="shaderc.net" Version="0.1.0" />
|
||||
<PackageVersion Include="SharpZipLib" Version="1.4.2" />
|
||||
<PackageVersion Include="Silk.NET.Vulkan" Version="2.22.0" />
|
||||
|
||||
@@ -7,8 +7,8 @@
|
||||
|
||||
# Ryujinx
|
||||
|
||||
[](https://git.ryujinx.app/ryubing/ryujinx/-/releases)
|
||||
[](https://git.ryujinx.app/ryubing/canary/-/releases)
|
||||
[](https://update.ryujinx.app/latest/stable)
|
||||
[](https://update.ryujinx.app/latest/canary)
|
||||
<br>
|
||||
<a href="https://discord.gg/PEuzjrFXUA">
|
||||
<img src="https://img.shields.io/discord/1294443224030511104?color=5865F2&label=Ryubing&logo=discord&logoColor=white" alt="Discord">
|
||||
|
||||
@@ -77,6 +77,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Horizon.Kernel.Gene
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.HLE.Generators", "src\Ryujinx.HLE.Generators\Ryujinx.HLE.Generators.csproj", "{B575BCDE-2FD8-4A5D-8756-31CDD7FE81F0}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ryujinx.BuildValidationTasks", "src\Ryujinx.BuildValidationTasks\Ryujinx.BuildValidationTasks.csproj", "{4A89A234-4F19-497D-A576-DDE8CDFC5B22}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{36F870C1-3E5F-485F-B426-F0645AF78751}"
|
||||
ProjectSection(SolutionItems) = preProject
|
||||
.editorconfig = .editorconfig
|
||||
@@ -84,10 +86,9 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
|
||||
.github\workflows\canary.yml = .github\workflows\canary.yml
|
||||
Directory.Packages.props = Directory.Packages.props
|
||||
.github\workflows\release.yml = .github\workflows\release.yml
|
||||
nuget.config = nuget.config
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ryujinx.BuildValidationTasks", "src\Ryujinx.BuildValidationTasks\Ryujinx.BuildValidationTasks.csproj", "{4A89A234-4F19-497D-A576-DDE8CDFC5B22}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
|
||||
9596
assets/locales.json
9596
assets/locales.json
File diff suppressed because it is too large
Load Diff
@@ -6,7 +6,6 @@ cd "$ROOTDIR"
|
||||
|
||||
BUILDDIR=${BUILDDIR:-publish}
|
||||
OUTDIR=${OUTDIR:-publish_appimage}
|
||||
UFLAG=${UFLAG:-"gh-releases-zsync|Ryubing|ryujinx|latest|*-x64.AppImage.zsync"}
|
||||
|
||||
rm -rf AppDir
|
||||
mkdir -p AppDir/usr/bin
|
||||
@@ -23,11 +22,5 @@ chmod +x AppDir/AppRun AppDir/usr/bin/Ryujinx*
|
||||
|
||||
mkdir -p "$OUTDIR"
|
||||
|
||||
appimagetool --comp zstd --mksquashfs-opt -Xcompression-level --mksquashfs-opt 21 \
|
||||
-u "$UFLAG" \
|
||||
appimagetool -n --comp zstd --mksquashfs-opt -Xcompression-level --mksquashfs-opt 21 \
|
||||
AppDir "$OUTDIR"/Ryujinx.AppImage
|
||||
|
||||
# Move zsync file needed for delta updates
|
||||
if [ "$RELEASE" = "1" ]; then
|
||||
mv ./*.AppImage.zsync "$OUTDIR"
|
||||
fi
|
||||
|
||||
@@ -188,6 +188,8 @@
|
||||
01003DD00BFEE000,"Airheart - Tales of broken Wings",,playable,2021-02-26 15:20:27
|
||||
01007F100DE52000,"Akane",nvdec,playable,2022-07-21 00:12:18
|
||||
01009A800F0C8000,"Akash: Path of the Five",gpu;nvdec,ingame,2020-12-14 22:33:12
|
||||
01009E8012976000,"AKIBA'S TRIP: Hellbound & Debriefed",,playable,2025-07-30 23:22:47
|
||||
0100D74019A0E000,"AKIBA'S TRIP: Undead & Undressed Director's Cut",,playable,2025-07-31 13:58:42
|
||||
010053100B0EA000,"Akihabara - Feel the Rhythm Remixed",,playable,2021-02-22 14:39:35
|
||||
0100D4C00EE0C000,"Akuarium",slow,playable,2020-12-12 23:43:36
|
||||
010026E00FEBE000,"Akuto: Showdown",,playable,2020-08-04 19:43:27
|
||||
@@ -976,7 +978,7 @@
|
||||
0100416004C00000,"DOOM",gpu;slow;nvdec;online-broken,ingame,2024-09-23 15:40:07
|
||||
010018900DD00000,"DOOM (1993)",nvdec;online-broken,menus,2022-09-06 13:32:19
|
||||
01008CB01E52E000,"DOOM + DOOM II",opengl;ldn-untested;LAN,playable,2024-09-12 07:06:01
|
||||
010029D00E740000,"DOOM 3",crash,menus,2024-08-03 05:25:47
|
||||
010029D00E740000,"DOOM 3",crash;slow,menus,2024-08-03 05:25:47
|
||||
01005D700E742000,"DOOM 64",nvdec;vulkan,playable,2020-10-13 23:47:28
|
||||
0100D4F00DD02000,"DOOM II (Classic)",nvdec;online,playable,2021-06-03 20:10:01
|
||||
0100B1A00D8CE000,"DOOM® Eternal",gpu;slow;nvdec;online-broken,ingame,2024-08-28 15:57:17
|
||||
@@ -1095,6 +1097,7 @@
|
||||
0100F9600E746000,"ESP Ra.De. Psi",audio;slow,ingame,2024-03-07 15:05:08
|
||||
010073000FE18000,"Esports powerful pro yakyuu 2020",gpu;crash;Needs More Attention,ingame,2024-04-29 05:34:14
|
||||
01004F9012FD8000,"Estranged: The Departure",nvdec;UE4,playable,2022-10-24 10:37:58
|
||||
010018F01E0A0000,"Eternights",,playable,2025-07-30 12:10:24
|
||||
0100CB900B498000,"Eternum Ex",,playable,2021-01-13 20:28:32
|
||||
010092501EB2C000,"Europa (Demo)",gpu;crash;UE4,ingame,2024-04-23 10:47:12
|
||||
01007BE0160D6000,"EVE ghost enemies",gpu,ingame,2023-01-14 03:13:30
|
||||
@@ -1172,6 +1175,7 @@
|
||||
0100EB100AB42000,"FINAL FANTASY XII THE ZODIAC AGE",opengl;vulkan-backend-bug,playable,2024-08-11 07:01:54
|
||||
010068F00AA78000,"FINAL FANTASY XV POCKET EDITION HD",,playable,2021-01-05 17:52:08
|
||||
0100CE4010AAC000,"FINAL FANTASY® CRYSTAL CHRONICLES™ Remastered Edition",,playable,2023-04-02 23:39:12
|
||||
010038B015560000,FINAL FANTASY TACTICS - The Ivalice Chronicles,gpu,boots,2024-09-30 02:59:00
|
||||
01001BA00AE4E000,"Final Light, The Prison",,playable,2020-07-31 21:48:44
|
||||
0100FF100FB68000,"Finding Teddy 2 : Definitive Edition",gpu,ingame,2024-04-19 16:51:33
|
||||
0100F4E013AAE000,"Fire & Water",,playable,2020-12-15 15:43:20
|
||||
@@ -1240,6 +1244,8 @@
|
||||
010003F00BD48000,"Friday the 13th: Killer Puzzle",,playable,2021-01-28 01:33:38
|
||||
010092A00C4B6000,"Friday the 13th: The Game Ultimate Slasher Edition",nvdec;online-broken;UE4,playable,2022-09-06 17:33:27
|
||||
0100F200178F4000,"FRONT MISSION 1st: Remake",,playable,2023-06-09 07:44:24
|
||||
0100C4E018A24000,"FRONT MISSION 2: Remake",,playable,2025-07-30 12:11:23
|
||||
01007E6019872000,"FRONT MISSION 3: Remake",,playable,2025-07-30 12:12:02
|
||||
0100861012474000,"Frontline Zed",,playable,2020-10-03 12:55:59
|
||||
0100B5300B49A000,"Frost",,playable,2022-07-27 12:00:36
|
||||
010038A007AA4000,"FruitFall Crush",,playable,2020-10-20 11:33:33
|
||||
@@ -1435,6 +1441,7 @@
|
||||
0100C2700E338000,"Heroland",,playable,2020-08-05 15:35:39
|
||||
01007AC00E012000,"HexaGravity",,playable,2021-05-28 13:47:48
|
||||
01004E800F03C000,"Hidden",slow,ingame,2022-10-05 10:56:53
|
||||
0100C1101EE5A000,"High on Life",,menus,2025-08-26 19:11:00
|
||||
0100F6A00A684000,"Higurashi no Naku Koro ni Hō",audio,ingame,2021-09-18 14:40:28
|
||||
0100F8D0129F4000,"Himehibi 1 gakki - Princess Days",crash,nothing,2021-11-03 08:34:19
|
||||
0100F3D008436000,"Hiragana Pixel Party",,playable,2021-01-14 08:36:50
|
||||
@@ -1444,6 +1451,7 @@
|
||||
0100F7300ED2C000,"Hoggy2",,playable,2022-10-10 13:53:35
|
||||
0100F7E00C70E000,"Hogwarts Legacy",UE4;slow,ingame,2024-09-03 19:53:58
|
||||
0100633007D48000,"Hollow Knight",nvdec,playable,2023-01-16 15:44:56
|
||||
010013C00E930000,"Hollow Knight: Silksong",,playable,2025-09-04 17:23:22
|
||||
0100F2100061E800,"Hollow0",UE4;gpu,ingame,2021-03-03 23:42:56
|
||||
0100342009E16000,"Holy Potatoes! What The Hell?!",,playable,2020-07-03 10:48:56
|
||||
010071B00C904000,"HoPiKo",,playable,2021-01-13 20:12:38
|
||||
@@ -1518,6 +1526,7 @@
|
||||
010095C016C14000,"Iridium",,playable,2022-08-05 23:19:53
|
||||
0100AD300B786000,"Iris School of Wizardry -Vinculum Hearts-",,playable,2022-12-05 13:11:15
|
||||
0100945012168000,"Iris.Fall",nvdec,playable,2022-10-18 13:40:22
|
||||
010059801B736000,"IronFall: Invasion",,playable,2025-07-30 11:42:30
|
||||
01005270118D6000,"Iron Wings",slow,ingame,2022-08-07 08:32:57
|
||||
01004DB003E6A000,"IRONCAST",,playable,2021-01-13 13:54:29
|
||||
0100E5700CD56000,"Irony Curtain: From Matryoshka with Love",,playable,2021-06-04 20:12:37
|
||||
@@ -1881,7 +1890,7 @@
|
||||
010097800EA20000,"Monster Energy Supercross - The Official Videogame 3",UE4;audout;nvdec;online,playable,2021-06-14 12:37:54
|
||||
0100E9900ED74000,"Monster Farm",32-bit;nvdec,playable,2021-05-05 19:29:13
|
||||
0100770008DD8000,"Monster Hunter Generations Ultimate™",32-bit;online-broken;ldn-works,playable,2024-03-18 14:35:36
|
||||
0100B04011742000,"Monster Hunter Rise",gpu;slow;crash;nvdec;online-broken;Needs Update;ldn-works,ingame,2024-08-24 11:04:59
|
||||
0100B04011742000,"MONSTER HUNTER RISE",gpu;slow;crash;nvdec;online-broken;Needs Update;ldn-works,ingame,2024-08-24 11:04:59
|
||||
010093A01305C000,"Monster Hunter Rise Demo",online-broken;ldn-works;demo,playable,2022-10-18 23:04:17
|
||||
0100E21011446000,"Monster Hunter Stories 2: Wings of Ruin",services,ingame,2022-07-10 19:27:30
|
||||
010042501329E000,"MONSTER HUNTER STORIES 2: WINGS OF RUIN Trial Version",demo,playable,2022-11-13 22:20:26
|
||||
@@ -2257,11 +2266,13 @@
|
||||
010086F0064CE000,"Poi: Explorer Edition",nvdec,playable,2021-01-21 19:32:00
|
||||
0100EB6012FD2000,"Poison Control",,playable,2021-05-16 14:01:54
|
||||
010072400E04A000,"Pokémon Café ReMix",,playable,2021-08-17 20:00:04
|
||||
010008c01e742000,"Pokémon Friends",crash;services,menus,2025-07-24 13:32:00
|
||||
01003D200BAA2000,"Pokémon Mystery Dungeon™: Rescue Team DX",mac-bug,playable,2024-01-21 00:16:32
|
||||
01008DB008C2C000,"Pokémon Shield + Pokémon Shield Expansion Pass",deadlock;crash;online-broken;ldn-works;LAN,ingame,2024-08-12 07:20:22
|
||||
0100ABF008968000,"Pokémon Sword + Pokémon Sword Expansion Pass",deadlock;crash;online-broken;ldn-works;LAN,ingame,2024-08-26 15:40:37
|
||||
01009AD008C4C000,"Pokémon: Let's Go, Pikachu! demo",slow;demo,playable,2023-11-26 11:23:20
|
||||
0100000011D90000,"Pokémon™ Brilliant Diamond",gpu;ldn-works,ingame,2024-08-28 13:26:35
|
||||
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
|
||||
01005D100807A000,"Pokémon™ Quest",,playable,2022-02-22 16:12:32
|
||||
@@ -2305,6 +2316,7 @@
|
||||
010077B00BDD8000,"Professional Farmer: Nintendo Switch™ Edition",slow,playable,2020-12-16 13:38:19
|
||||
010018300C83A000,"Professor Lupo and his Horrible Pets",,playable,2020-06-12 00:08:45
|
||||
0100D1F0132F6000,"Professor Lupo: Ocean",,playable,2021-04-14 16:33:33
|
||||
0100C3A017834000,"Prodeus",,playable,2025-07-30 12:07:52
|
||||
0100BBD00976C000,"Project Highrise: Architect's Edition",,playable,2022-08-10 17:19:12
|
||||
0100ACE00DAB6000,"Project Nimbus: Complete Edition",nvdec;UE4;vulkan-backend-bug,playable,2022-08-10 17:35:43
|
||||
01002980140F6000,"Project TRIANGLE STRATEGY™ Debut Demo",UE4;demo,playable,2022-10-24 21:40:27
|
||||
@@ -2436,6 +2448,7 @@
|
||||
0100E9C010EA8000,"Rise of Insanity",,playable,2020-08-30 15:42:14
|
||||
01006BA00E652000,"Rise: Race The Future",,playable,2021-02-27 13:29:06
|
||||
010020C012F48000,"Rising Hell",,playable,2022-10-31 13:54:02
|
||||
0100D1801A0F4000,"Risk of Rain Returns",,playable,2025-06-28 04:24:04
|
||||
010076D00E4BA000,"Risk of Rain 2",online-broken,playable,2024-03-04 17:01:05
|
||||
0100E8300A67A000,"RISK® Global Domination",nvdec;online-broken,playable,2022-08-01 18:53:28
|
||||
010042500FABA000,"Ritual: Crown of Horns",,playable,2021-01-26 16:01:47
|
||||
@@ -2569,6 +2582,7 @@
|
||||
0100C610154CA000,"Shadowrun: Hong Kong - Extended Edition",gpu;Needs Update,ingame,2022-10-04 20:53:09
|
||||
010000000EEF0000,"Shadows 2: Perfidia",,playable,2020-08-07 12:43:46
|
||||
0100AD700CBBE000,"Shadows of Adam",,playable,2021-01-11 13:35:58
|
||||
010037A01F96C000,"Shadows of the Damned: Hella Remastered",,playable,2025-09-05 11:34:32
|
||||
01002A800C064000,"Shadowverse Champions Battle",,playable,2022-10-02 22:59:29
|
||||
01003B90136DA000,"Shadowverse: Champion's Battle",crash,nothing,2023-03-06 00:31:50
|
||||
0100820013612000,"Shady Part of Me",,playable,2022-10-20 11:31:55
|
||||
@@ -2695,6 +2709,8 @@
|
||||
01008F701C074000,"SONIC SUPERSTARS",gpu;nvdec,ingame,2023-10-28 17:48:07
|
||||
010088801C150000,"Sonic Superstars Digital Art Book with Mini Digital Soundtrack",,playable,2024-08-20 13:26:56
|
||||
01005EA01C0FC000,"SONIC X SHADOW GENERATIONS",crash,ingame,2025-01-07 04:20:45
|
||||
010064B0242BE000,"Sonic Racing: CrossWorlds - Demo",gpu;vulkan-backend-bug;demo,ingame,2024-09-25 11:27:53
|
||||
01006E001823C000,"Sonic Racing: CrossWorlds",gpu;vulkan-backend-bug;ldn-broken,ingame,2024-09-30 17:23:00
|
||||
010064F00C212000,"Soul Axiom Rebooted",nvdec;slow,ingame,2020-09-04 12:41:01
|
||||
0100F2100F0B2000,"Soul Searching",,playable,2020-07-09 18:39:07
|
||||
01008F2005154000,"South Park™: The Fractured but Whole™ - Standard Edition",slow;online-broken;vulkan-backend-bug;gpu,ingame,2025-01-21 17:35:10
|
||||
@@ -2746,6 +2762,7 @@
|
||||
01005D701264A000,"SpyHack",,playable,2021-04-15 10:53:51
|
||||
010077B00E046000,"Spyro™ Reignited Trilogy",nvdec;UE4,playable,2022-09-11 18:38:33
|
||||
0100085012A0E000,"Squeakers",,playable,2020-12-13 12:13:05
|
||||
0100E1D01EB2E000,"Squeakross: Home Squeak Home",,playable,2025-06-16 02:02:00
|
||||
010009300D31C000,"Squidgies Takeover",,playable,2020-07-20 22:28:08
|
||||
0100FCD0102EC000,"Squidlit",,playable,2020-08-06 12:38:32
|
||||
0100EBF00E702000,"STAR OCEAN First Departure R",nvdec,playable,2021-07-05 19:29:16
|
||||
@@ -2765,7 +2782,7 @@
|
||||
0100E6B0115FC000,"Star99",online,menus,2021-11-26 14:18:51
|
||||
01002100137BA000,"Stardash",,playable,2021-01-21 16:31:19
|
||||
0100E65002BB8000,"Stardew Valley",online-broken;ldn-untested,playable,2024-02-14 03:11:19
|
||||
01002CC003FE6000,"Starlink: Battle for Atlas™ Digital Edition",services-horizon;crash;Needs Update,nothing,2024-05-05 17:25:11
|
||||
01002CC003FE6000,"Starlink: Battle for Atlas™ Digital Edition",,playable,2025-07-30 12:09:37
|
||||
010098E010FDA000,"Starlit Adventures Golden Stars",,playable,2020-11-21 12:14:43
|
||||
01001BB00AC26000,"STARSHIP AVENGER Operation: Take Back Earth",,playable,2021-01-12 15:52:55
|
||||
010000700A572000,"State of Anarchy: Master of Mayhem",nvdec,playable,2021-01-12 19:00:05
|
||||
@@ -2851,11 +2868,13 @@
|
||||
0100BC0018138000,"Super Mario RPG™",gpu;audio;nvdec,ingame,2024-06-19 17:43:42
|
||||
,"Super Mario World",homebrew,boots,2024-06-13 01:40:31
|
||||
010049900F546000,"Super Mario™ 3D All-Stars",services-horizon;slow;vulkan;amd-vendor-bug,ingame,2024-05-07 02:38:16
|
||||
010099C022B96000,"Super Mario Galaxy",slow;vulkan;amd-vendor-bug;vulkan-vendor-bug,ingame,2025-10-01 15:30:00
|
||||
0100FD8022DAA000,"Super Mario Galaxy 2",slow;vulkan;amd-vendor-bug;vulkan-vendor-bug;deadlock,ingame,2025-10-04 18:50:00
|
||||
010028600EBDA000,"Super Mario™ 3D World + Bowser’s Fury",ldn-works,playable,2024-07-31 10:45:37
|
||||
01004F8006A78000,"Super Meat Boy",services,playable,2020-04-02 23:10:07
|
||||
01009C200D60E000,"Super Meat Boy Forever",gpu,boots,2021-04-26 14:25:39
|
||||
0100BDD00EC5C000,"Super Mega Space Blaster Special Turbo",online,playable,2020-08-06 12:13:25
|
||||
010031F019294000,"Super Monkey Ball Banana Rumble",,playable,2024-06-28 10:39:18
|
||||
010031F019294000,"Super Monkey Ball Banana Rumble",ldn-broken,playable,2025-10-01 18:03:00
|
||||
0100B2A00E1E0000,"Super Monkey Ball: Banana Blitz HD",online-broken,playable,2022-09-16 13:16:25
|
||||
01006D000D2A0000,"Super Mutant Alien Assault",,playable,2020-06-07 23:32:45
|
||||
01004D600AC14000,"Super Neptunia RPG",nvdec,playable,2022-08-17 16:38:52
|
||||
@@ -2921,6 +2940,7 @@
|
||||
0100B76011DAA000,"Taxi Chaos",slow;online-broken;UE4,playable,2022-10-25 19:13:00
|
||||
0100F43011E5A000,"Tcheco in the Castle of Lucio",,playable,2020-06-27 13:35:43
|
||||
010092B0091D0000,"Team Sonic Racing",online-broken;ldn-works,playable,2024-02-05 15:05:27
|
||||
010084B00B36E000,"Team Sonic Racing",online-broken;ldn-works,playable,2024-02-05 15:05:27
|
||||
0100FE701475A000,"Teenage Mutant Ninja Turtles: Shredder's Revenge",deadlock;crash,boots,2024-09-28 09:31:39
|
||||
01005CF01E784000,"Teenage Mutant Ninja Turtles: Splintered Fate",,playable,2024-08-03 13:50:42
|
||||
0100FDB0154E4000,"Teenage Mutant Ninja Turtles: The Cowabunga Collection",,playable,2024-01-22 19:39:04
|
||||
@@ -2966,6 +2986,7 @@
|
||||
0100EBA01548E000,"The Cruel King and the Great Hero",gpu;services,ingame,2022-12-02 07:02:08
|
||||
010051800E922000,"The Dark Crystal: Age of Resistance Tactics",,playable,2020-08-11 13:43:41
|
||||
01003DE00918E000,"The Darkside Detective",,playable,2020-06-03 22:16:18
|
||||
010032B015D66000,"The DioField Chronicle",,playable,2025-09-05 11:35:50
|
||||
01000A10041EA000,"The Elder Scrolls V: Skyrim",gpu;crash,ingame,2024-07-14 03:21:31
|
||||
01004A9006B84000,"The End Is Nigh",,playable,2020-06-01 11:26:45
|
||||
0100CA100489C000,"The Escapists 2",nvdec,playable,2020-09-24 12:31:31
|
||||
@@ -2973,6 +2994,7 @@
|
||||
0100C2E0129A6000,"The Executioner",nvdec,playable,2021-01-23 00:31:28
|
||||
01006050114D4000,"The Experiment: Escape Room",gpu,ingame,2022-09-30 13:20:35
|
||||
0100B5900DFB2000,"The Eyes of Ara",,playable,2022-09-16 14:44:06
|
||||
0100BA5013E52000,"The Falconeer: Warrior Edition",,playable,2025-07-30 12:04:50
|
||||
01002DD00AF9E000,"The Fall",gpu,ingame,2020-05-31 23:31:16
|
||||
01003E5002320000,"The Fall Part 2: Unbound",,playable,2021-11-06 02:18:08
|
||||
0100CDC00789E000,"The Final Station",nvdec,playable,2022-08-22 15:54:39
|
||||
@@ -3016,6 +3038,7 @@
|
||||
01009B101044C000,"The Legend of Heroes: Trails of Cold Steel III Demo",demo;nvdec,playable,2021-04-23 01:07:32
|
||||
0100D3C010DE8000,"The Legend of Heroes: Trails of Cold Steel IV",nvdec,playable,2021-04-23 14:01:05
|
||||
01005E5013862000,"THE LEGEND OF HEROES: ZERO NO KISEKI KAI [英雄傳說 零之軌跡:改]",crash,nothing,2021-09-30 14:41:07
|
||||
01009C901ACEE000,"The Legend of Nayuta: Boundless Trails",,ingame,2025-06-12 15:47
|
||||
01008CF01BAAC000,"The Legend of Zelda Echoes of Wisdom",nvdec;ASTC;intel-vendor-bug,playable,2024-10-01 14:11:01
|
||||
0100509005AF2000,"The Legend of Zelda: Breath of the Wild Demo",demo,ingame,2022-12-24 05:02:58
|
||||
01007EF00011E000,"The Legend of Zelda™: Breath of the Wild",gpu;amd-vendor-bug;mac-bug,ingame,2024-09-23 19:35:46
|
||||
@@ -3194,6 +3217,7 @@
|
||||
010000400F582000,"TT Isle of Man Ride on the Edge 2",gpu;nvdec;online-broken,ingame,2022-09-30 22:13:05
|
||||
0100752011628000,"TTV2",,playable,2020-11-27 13:21:36
|
||||
0100AFE00452E000,"Tumblestone",,playable,2021-01-07 17:49:20
|
||||
0100D1A01D7BA000,"Turbo Overkill",,playable,2025-07-30 12:08:57
|
||||
010085500D5F6000,"Turok",gpu,ingame,2021-06-04 13:16:24
|
||||
0100CDC00D8D6000,"Turok 2: Seeds of Evil",gpu;vulkan,ingame,2022-09-12 17:50:05
|
||||
010004B0130C8000,"Turrican Flashback",audout,playable,2021-08-30 10:07:56
|
||||
@@ -3203,6 +3227,7 @@
|
||||
010038400C2FE000,"TY the Tasmanian Tiger™ HD",32-bit;crash;nvdec,menus,2020-12-17 21:15:00
|
||||
010073A00C4B2000,"Tyd wag vir Niemand",,playable,2021-03-02 13:39:53
|
||||
0100D5B00D6DA000,"Type:Rider",,playable,2021-01-06 13:12:55
|
||||
01008AF01AD22000,"The Patrick Star Game",,playable,2025-10-01 17:55:30
|
||||
010040D01222C000,"UBERMOSH: SANTICIDE",,playable,2020-11-27 15:05:01
|
||||
0100992010BF8000,"Ubongo",,playable,2021-02-04 21:15:01
|
||||
010079000B56C000,"UglyDolls: An Imperfect Adventure",nvdec;UE4,playable,2022-08-25 14:42:16
|
||||
@@ -3217,6 +3242,8 @@
|
||||
0100592005164000,"UNBOX: Newbie's Adventure",UE4,playable,2022-08-29 13:12:56
|
||||
01002D900C5E4000,"Uncanny Valley",nvdec,playable,2021-06-04 13:28:45
|
||||
010076F011F54000,"Undead & Beyond",nvdec,playable,2022-10-04 09:11:18
|
||||
01009B700D0B8000,"Undead Horde",,playable,2025-07-30 12:05:05
|
||||
0100FC301A878000,"Undead Horde 2: Necropolis",,playable,2025-07-30 12:06:07
|
||||
01008F3013E4E000,"Under Leaves",,playable,2021-05-22 18:13:58
|
||||
010080B00AD66000,"Undertale",,playable,2022-08-31 17:31:46
|
||||
01008F80049C6000,"Unepic",,playable,2024-01-15 17:03:00
|
||||
@@ -3447,3 +3474,6 @@
|
||||
0100F4401940A000,"超探偵事件簿 レインコード (Master Detective Archives: Rain Code)",crash,ingame,2024-02-12 20:58:31
|
||||
010064801A01C000,"超次元ゲイム ネプテューヌ GameMaker R:Evolution",crash,nothing,2023-10-30 22:37:40
|
||||
0100F3400332C000,"ゼノブレイド2",deadlock;amd-vendor-bug,ingame,2024-03-28 14:31:41
|
||||
010075000ECBE000,"超级马力欧 奥德赛",nvdec;intel-vendor-bug;mac-bug,playable,2024-08-25 01:32:34
|
||||
010075100E8EC000,"马力欧卡丁车8 豪华版",32-bit;ldn-works;LAN;amd-vendor-bug,playable,2024-09-19 11:55:17
|
||||
0100E8C00F506000,"新 超级马力欧兄弟U 豪华版",32-bit,playable,2023-10-08 02:06:37
|
||||
|
||||
|
17
nuget.config
17
nuget.config
@@ -5,6 +5,21 @@
|
||||
<clear />
|
||||
<add key="nuget.org" value="https://api.nuget.org/v3/index.json" />
|
||||
<!-- Only needed when using pre-release versions of Ryujinx.LibHac. -->
|
||||
<!--<add key="LibHacAlpha" value="https://git.ryujinx.app/api/v4/projects/17/packages/nuget/index.json" />-->
|
||||
<add key="LibHacAlpha" value="https://git.ryujinx.app/api/v4/projects/17/packages/nuget/index.json" />
|
||||
<add key="Ryujinx.UpdateClient" value="https://git.ryujinx.app/api/v4/projects/71/packages/nuget/index.json" />
|
||||
</packageSources>
|
||||
<packageSourceMapping>
|
||||
<!-- key value for <packageSource> should match key values from <packageSources> element -->
|
||||
<!-- These are defined and .NET still yells about multiple package sources with no mappings. Not sure what to do, this is in the docs lol -->
|
||||
<packageSource key="nuget.org">
|
||||
<package pattern="*" />
|
||||
</packageSource>
|
||||
<packageSource key="Ryujinx.UpdateClient">
|
||||
<package pattern="Ryujinx.UpdateClient" />
|
||||
<package pattern="Ryujinx.Systems.Update.Common" />
|
||||
</packageSource>
|
||||
<packageSource key="LibHacAlpha">
|
||||
<package pattern="Ryujinx.LibHac" />
|
||||
</packageSource>
|
||||
</packageSourceMapping>
|
||||
</configuration>
|
||||
|
||||
@@ -1129,6 +1129,7 @@ namespace ARMeilleure.CodeGen.Arm64
|
||||
};
|
||||
}
|
||||
|
||||
#pragma warning disable IDE0051 // Remove unused private member
|
||||
private void WriteInt16(short value)
|
||||
{
|
||||
WriteUInt16((ushort)value);
|
||||
@@ -1143,6 +1144,7 @@ namespace ARMeilleure.CodeGen.Arm64
|
||||
{
|
||||
_stream.WriteByte(value);
|
||||
}
|
||||
#pragma warning restore IDE0051
|
||||
|
||||
private void WriteUInt16(ushort value)
|
||||
{
|
||||
|
||||
@@ -1570,11 +1570,13 @@ namespace ARMeilleure.CodeGen.Arm64
|
||||
Debug.Assert(op1.Type == op3.Type);
|
||||
}
|
||||
|
||||
#pragma warning disable IDE0051 // Remove unused private member
|
||||
private static void EnsureSameType(Operand op1, Operand op2, Operand op3, Operand op4)
|
||||
{
|
||||
Debug.Assert(op1.Type == op2.Type);
|
||||
Debug.Assert(op1.Type == op3.Type);
|
||||
Debug.Assert(op1.Type == op4.Type);
|
||||
}
|
||||
#pragma warning restore IDE0051
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
namespace ARMeilleure.CodeGen.X86
|
||||
{
|
||||
|
||||
@@ -20,12 +20,12 @@ namespace ARMeilleure.CodeGen.X86
|
||||
{
|
||||
if (GetCurrentCallConv() == CallConvName.Windows)
|
||||
{
|
||||
|
||||
#pragma warning disable IDE0055 // Disable formatting
|
||||
return (1 << (int)X86Register.Rax) |
|
||||
(1 << (int)X86Register.Rcx) |
|
||||
(1 << (int)X86Register.Rdx) |
|
||||
(1 << (int)X86Register.R8) |
|
||||
(1 << (int)X86Register.R9) |
|
||||
(1 << (int)X86Register.R8) |
|
||||
(1 << (int)X86Register.R9) |
|
||||
(1 << (int)X86Register.R10) |
|
||||
(1 << (int)X86Register.R11);
|
||||
}
|
||||
@@ -36,11 +36,11 @@ namespace ARMeilleure.CodeGen.X86
|
||||
(1 << (int)X86Register.Rdx) |
|
||||
(1 << (int)X86Register.Rsi) |
|
||||
(1 << (int)X86Register.Rdi) |
|
||||
(1 << (int)X86Register.R8) |
|
||||
(1 << (int)X86Register.R9) |
|
||||
(1 << (int)X86Register.R8) |
|
||||
(1 << (int)X86Register.R9) |
|
||||
(1 << (int)X86Register.R10) |
|
||||
(1 << (int)X86Register.R11);
|
||||
|
||||
#pragma warning restore IDE0055
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ using ARMeilleure.CodeGen.RegisterAllocators;
|
||||
using ARMeilleure.IntermediateRepresentation;
|
||||
using Microsoft.IO;
|
||||
using Ryujinx.Common.Memory;
|
||||
using System.IO;
|
||||
using System.Numerics;
|
||||
|
||||
namespace ARMeilleure.CodeGen.X86
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
namespace ARMeilleure.CodeGen.X86
|
||||
{
|
||||
enum X86Register
|
||||
|
||||
@@ -8,8 +8,8 @@ namespace ARMeilleure.Instructions
|
||||
static class CryptoHelper
|
||||
{
|
||||
#region "LookUp Tables"
|
||||
|
||||
private static ReadOnlySpan<byte> SBox =>
|
||||
#pragma warning disable IDE1006 // Naming rule violation
|
||||
private static ReadOnlySpan<byte> _sBox =>
|
||||
[
|
||||
0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76,
|
||||
0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0,
|
||||
@@ -29,7 +29,7 @@ namespace ARMeilleure.Instructions
|
||||
0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16
|
||||
];
|
||||
|
||||
private static ReadOnlySpan<byte> InvSBox =>
|
||||
private static ReadOnlySpan<byte> _invSBox =>
|
||||
[
|
||||
0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb,
|
||||
0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb,
|
||||
@@ -49,7 +49,7 @@ namespace ARMeilleure.Instructions
|
||||
0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d
|
||||
];
|
||||
|
||||
private static ReadOnlySpan<byte> GfMul02 =>
|
||||
private static ReadOnlySpan<byte> _gfMul02 =>
|
||||
[
|
||||
0x00, 0x02, 0x04, 0x06, 0x08, 0x0a, 0x0c, 0x0e, 0x10, 0x12, 0x14, 0x16, 0x18, 0x1a, 0x1c, 0x1e,
|
||||
0x20, 0x22, 0x24, 0x26, 0x28, 0x2a, 0x2c, 0x2e, 0x30, 0x32, 0x34, 0x36, 0x38, 0x3a, 0x3c, 0x3e,
|
||||
@@ -69,7 +69,7 @@ namespace ARMeilleure.Instructions
|
||||
0xfb, 0xf9, 0xff, 0xfd, 0xf3, 0xf1, 0xf7, 0xf5, 0xeb, 0xe9, 0xef, 0xed, 0xe3, 0xe1, 0xe7, 0xe5
|
||||
];
|
||||
|
||||
private static ReadOnlySpan<byte> GfMul03 =>
|
||||
private static ReadOnlySpan<byte> _gfMul03 =>
|
||||
[
|
||||
0x00, 0x03, 0x06, 0x05, 0x0c, 0x0f, 0x0a, 0x09, 0x18, 0x1b, 0x1e, 0x1d, 0x14, 0x17, 0x12, 0x11,
|
||||
0x30, 0x33, 0x36, 0x35, 0x3c, 0x3f, 0x3a, 0x39, 0x28, 0x2b, 0x2e, 0x2d, 0x24, 0x27, 0x22, 0x21,
|
||||
@@ -89,7 +89,7 @@ namespace ARMeilleure.Instructions
|
||||
0x0b, 0x08, 0x0d, 0x0e, 0x07, 0x04, 0x01, 0x02, 0x13, 0x10, 0x15, 0x16, 0x1f, 0x1c, 0x19, 0x1a
|
||||
];
|
||||
|
||||
private static ReadOnlySpan<byte> GfMul09 =>
|
||||
private static ReadOnlySpan<byte> _gfMul09 =>
|
||||
[
|
||||
0x00, 0x09, 0x12, 0x1b, 0x24, 0x2d, 0x36, 0x3f, 0x48, 0x41, 0x5a, 0x53, 0x6c, 0x65, 0x7e, 0x77,
|
||||
0x90, 0x99, 0x82, 0x8b, 0xb4, 0xbd, 0xa6, 0xaf, 0xd8, 0xd1, 0xca, 0xc3, 0xfc, 0xf5, 0xee, 0xe7,
|
||||
@@ -109,7 +109,7 @@ namespace ARMeilleure.Instructions
|
||||
0x31, 0x38, 0x23, 0x2a, 0x15, 0x1c, 0x07, 0x0e, 0x79, 0x70, 0x6b, 0x62, 0x5d, 0x54, 0x4f, 0x46
|
||||
];
|
||||
|
||||
private static ReadOnlySpan<byte> GfMul0B =>
|
||||
private static ReadOnlySpan<byte> _gfMul0B =>
|
||||
[
|
||||
0x00, 0x0b, 0x16, 0x1d, 0x2c, 0x27, 0x3a, 0x31, 0x58, 0x53, 0x4e, 0x45, 0x74, 0x7f, 0x62, 0x69,
|
||||
0xb0, 0xbb, 0xa6, 0xad, 0x9c, 0x97, 0x8a, 0x81, 0xe8, 0xe3, 0xfe, 0xf5, 0xc4, 0xcf, 0xd2, 0xd9,
|
||||
@@ -129,7 +129,7 @@ namespace ARMeilleure.Instructions
|
||||
0xca, 0xc1, 0xdc, 0xd7, 0xe6, 0xed, 0xf0, 0xfb, 0x92, 0x99, 0x84, 0x8f, 0xbe, 0xb5, 0xa8, 0xa3
|
||||
];
|
||||
|
||||
private static ReadOnlySpan<byte> GfMul0D =>
|
||||
private static ReadOnlySpan<byte> _gfMul0D =>
|
||||
[
|
||||
0x00, 0x0d, 0x1a, 0x17, 0x34, 0x39, 0x2e, 0x23, 0x68, 0x65, 0x72, 0x7f, 0x5c, 0x51, 0x46, 0x4b,
|
||||
0xd0, 0xdd, 0xca, 0xc7, 0xe4, 0xe9, 0xfe, 0xf3, 0xb8, 0xb5, 0xa2, 0xaf, 0x8c, 0x81, 0x96, 0x9b,
|
||||
@@ -149,7 +149,7 @@ namespace ARMeilleure.Instructions
|
||||
0xdc, 0xd1, 0xc6, 0xcb, 0xe8, 0xe5, 0xf2, 0xff, 0xb4, 0xb9, 0xae, 0xa3, 0x80, 0x8d, 0x9a, 0x97
|
||||
];
|
||||
|
||||
private static ReadOnlySpan<byte> GfMul0E =>
|
||||
private static ReadOnlySpan<byte> _gfMul0E =>
|
||||
[
|
||||
0x00, 0x0e, 0x1c, 0x12, 0x38, 0x36, 0x24, 0x2a, 0x70, 0x7e, 0x6c, 0x62, 0x48, 0x46, 0x54, 0x5a,
|
||||
0xe0, 0xee, 0xfc, 0xf2, 0xd8, 0xd6, 0xc4, 0xca, 0x90, 0x9e, 0x8c, 0x82, 0xa8, 0xa6, 0xb4, 0xba,
|
||||
@@ -169,16 +169,16 @@ namespace ARMeilleure.Instructions
|
||||
0xd7, 0xd9, 0xcb, 0xc5, 0xef, 0xe1, 0xf3, 0xfd, 0xa7, 0xa9, 0xbb, 0xb5, 0x9f, 0x91, 0x83, 0x8d
|
||||
];
|
||||
|
||||
private static ReadOnlySpan<byte> SrPerm =>
|
||||
private static ReadOnlySpan<byte> _srPerm =>
|
||||
[
|
||||
0, 13, 10, 7, 4, 1, 14, 11, 8, 5, 2, 15, 12, 9, 6, 3
|
||||
];
|
||||
|
||||
private static ReadOnlySpan<byte> IsrPerm =>
|
||||
private static ReadOnlySpan<byte> _isrPerm =>
|
||||
[
|
||||
0, 5, 10, 15, 4, 9, 14, 3, 8, 13, 2, 7, 12, 1, 6, 11
|
||||
];
|
||||
|
||||
#pragma warning restore IDE1006
|
||||
#endregion
|
||||
|
||||
public static V128 AesInvMixColumns(V128 op)
|
||||
@@ -195,10 +195,10 @@ namespace ARMeilleure.Instructions
|
||||
byte row2 = inState[idx + 2]; // C, G, K, O: [row2, col0-col3]
|
||||
byte row3 = inState[idx + 3]; // D, H, L, P: [row3, col0-col3]
|
||||
|
||||
outState[idx + 0] = (byte)((uint)GfMul0E[row0] ^ GfMul0B[row1] ^ GfMul0D[row2] ^ GfMul09[row3]);
|
||||
outState[idx + 1] = (byte)((uint)GfMul09[row0] ^ GfMul0E[row1] ^ GfMul0B[row2] ^ GfMul0D[row3]);
|
||||
outState[idx + 2] = (byte)((uint)GfMul0D[row0] ^ GfMul09[row1] ^ GfMul0E[row2] ^ GfMul0B[row3]);
|
||||
outState[idx + 3] = (byte)((uint)GfMul0B[row0] ^ GfMul0D[row1] ^ GfMul09[row2] ^ GfMul0E[row3]);
|
||||
outState[idx + 0] = (byte)((uint)_gfMul0E[row0] ^ _gfMul0B[row1] ^ _gfMul0D[row2] ^ _gfMul09[row3]);
|
||||
outState[idx + 1] = (byte)((uint)_gfMul09[row0] ^ _gfMul0E[row1] ^ _gfMul0B[row2] ^ _gfMul0D[row3]);
|
||||
outState[idx + 2] = (byte)((uint)_gfMul0D[row0] ^ _gfMul09[row1] ^ _gfMul0E[row2] ^ _gfMul0B[row3]);
|
||||
outState[idx + 3] = (byte)((uint)_gfMul0B[row0] ^ _gfMul0D[row1] ^ _gfMul09[row2] ^ _gfMul0E[row3]);
|
||||
}
|
||||
|
||||
return new V128(outState);
|
||||
@@ -211,7 +211,7 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
for (int idx = 0; idx <= 15; idx++)
|
||||
{
|
||||
outState[IsrPerm[idx]] = inState[idx];
|
||||
outState[_isrPerm[idx]] = inState[idx];
|
||||
}
|
||||
|
||||
return new V128(outState);
|
||||
@@ -224,7 +224,7 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
for (int idx = 0; idx <= 15; idx++)
|
||||
{
|
||||
outState[idx] = InvSBox[inState[idx]];
|
||||
outState[idx] = _invSBox[inState[idx]];
|
||||
}
|
||||
|
||||
return new V128(outState);
|
||||
@@ -244,10 +244,10 @@ namespace ARMeilleure.Instructions
|
||||
byte row2 = inState[idx + 2]; // C, G, K, O: [row2, col0-col3]
|
||||
byte row3 = inState[idx + 3]; // D, H, L, P: [row3, col0-col3]
|
||||
|
||||
outState[idx + 0] = (byte)((uint)GfMul02[row0] ^ GfMul03[row1] ^ row2 ^ row3);
|
||||
outState[idx + 1] = (byte)((uint)row0 ^ GfMul02[row1] ^ GfMul03[row2] ^ row3);
|
||||
outState[idx + 2] = (byte)((uint)row0 ^ row1 ^ GfMul02[row2] ^ GfMul03[row3]);
|
||||
outState[idx + 3] = (byte)((uint)GfMul03[row0] ^ row1 ^ row2 ^ GfMul02[row3]);
|
||||
outState[idx + 0] = (byte)((uint)_gfMul02[row0] ^ _gfMul03[row1] ^ row2 ^ row3);
|
||||
outState[idx + 1] = (byte)((uint)row0 ^ _gfMul02[row1] ^ _gfMul03[row2] ^ row3);
|
||||
outState[idx + 2] = (byte)((uint)row0 ^ row1 ^ _gfMul02[row2] ^ _gfMul03[row3]);
|
||||
outState[idx + 3] = (byte)((uint)_gfMul03[row0] ^ row1 ^ row2 ^ _gfMul02[row3]);
|
||||
}
|
||||
|
||||
return new V128(outState);
|
||||
@@ -260,7 +260,7 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
for (int idx = 0; idx <= 15; idx++)
|
||||
{
|
||||
outState[SrPerm[idx]] = inState[idx];
|
||||
outState[_srPerm[idx]] = inState[idx];
|
||||
}
|
||||
|
||||
return new V128(outState);
|
||||
@@ -273,7 +273,7 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
for (int idx = 0; idx <= 15; idx++)
|
||||
{
|
||||
outState[idx] = SBox[inState[idx]];
|
||||
outState[idx] = _sBox[inState[idx]];
|
||||
}
|
||||
|
||||
return new V128(outState);
|
||||
|
||||
@@ -143,6 +143,12 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
public static void EmitCall(ArmEmitterContext context, ulong immediate)
|
||||
{
|
||||
if (context.IsSingleStep)
|
||||
{
|
||||
context.Return(Const(immediate));
|
||||
return;
|
||||
}
|
||||
|
||||
bool isRecursive = immediate == context.EntryAddress;
|
||||
|
||||
if (isRecursive)
|
||||
@@ -157,12 +163,24 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
public static void EmitVirtualCall(ArmEmitterContext context, Operand target)
|
||||
{
|
||||
EmitTableBranch(context, target, isJump: false);
|
||||
if (context.IsSingleStep)
|
||||
{
|
||||
if (target.Type == OperandType.I32)
|
||||
{
|
||||
target = context.ZeroExtend32(OperandType.I64, target);
|
||||
}
|
||||
|
||||
context.Return(target);
|
||||
}
|
||||
else
|
||||
{
|
||||
EmitTableBranch(context, target, isJump: false);
|
||||
}
|
||||
}
|
||||
|
||||
public static void EmitVirtualJump(ArmEmitterContext context, Operand target, bool isReturn)
|
||||
{
|
||||
if (isReturn)
|
||||
if (isReturn || context.IsSingleStep)
|
||||
{
|
||||
if (target.Type == OperandType.I32)
|
||||
{
|
||||
|
||||
@@ -2,6 +2,7 @@ using ARMeilleure.Decoders;
|
||||
using ARMeilleure.IntermediateRepresentation;
|
||||
using ARMeilleure.Translation;
|
||||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using static ARMeilleure.Instructions.InstEmitHelper;
|
||||
|
||||
namespace ARMeilleure.Instructions
|
||||
|
||||
@@ -11,10 +11,11 @@ using static ARMeilleure.Instructions.InstEmitHelper;
|
||||
using static ARMeilleure.Instructions.InstEmitSimdHelper;
|
||||
using static ARMeilleure.Instructions.InstEmitSimdHelper32;
|
||||
using static ARMeilleure.IntermediateRepresentation.Operand.Factory;
|
||||
using Func2I = System.Func<ARMeilleure.IntermediateRepresentation.Operand, ARMeilleure.IntermediateRepresentation.Operand, ARMeilleure.IntermediateRepresentation.Operand>;
|
||||
|
||||
namespace ARMeilleure.Instructions
|
||||
{
|
||||
using Func2I = Func<Operand, Operand, Operand>;
|
||||
|
||||
static partial class InstEmit
|
||||
{
|
||||
public static void Abs_S(ArmEmitterContext context)
|
||||
|
||||
@@ -2,13 +2,15 @@ using ARMeilleure.Decoders;
|
||||
using ARMeilleure.IntermediateRepresentation;
|
||||
using ARMeilleure.State;
|
||||
using ARMeilleure.Translation;
|
||||
using System;
|
||||
using static ARMeilleure.Instructions.InstEmitHelper;
|
||||
using static ARMeilleure.Instructions.InstEmitSimdHelper;
|
||||
using static ARMeilleure.IntermediateRepresentation.Operand.Factory;
|
||||
using Func2I = System.Func<ARMeilleure.IntermediateRepresentation.Operand, ARMeilleure.IntermediateRepresentation.Operand, ARMeilleure.IntermediateRepresentation.Operand>;
|
||||
|
||||
namespace ARMeilleure.Instructions
|
||||
{
|
||||
using Func2I = Func<Operand, Operand, Operand>;
|
||||
|
||||
static partial class InstEmit
|
||||
{
|
||||
public static void Cmeq_S(ArmEmitterContext context)
|
||||
|
||||
@@ -2,15 +2,17 @@ using ARMeilleure.Decoders;
|
||||
using ARMeilleure.IntermediateRepresentation;
|
||||
using ARMeilleure.State;
|
||||
using ARMeilleure.Translation;
|
||||
using System;
|
||||
|
||||
using static ARMeilleure.Instructions.InstEmitHelper;
|
||||
using static ARMeilleure.Instructions.InstEmitSimdHelper;
|
||||
using static ARMeilleure.Instructions.InstEmitSimdHelper32;
|
||||
using static ARMeilleure.IntermediateRepresentation.Operand.Factory;
|
||||
using Func2I = System.Func<ARMeilleure.IntermediateRepresentation.Operand, ARMeilleure.IntermediateRepresentation.Operand, ARMeilleure.IntermediateRepresentation.Operand>;
|
||||
|
||||
namespace ARMeilleure.Instructions
|
||||
{
|
||||
using Func2I = Func<Operand, Operand, Operand>;
|
||||
|
||||
static partial class InstEmit32
|
||||
{
|
||||
public static void Vceq_V(ArmEmitterContext context)
|
||||
|
||||
@@ -8,10 +8,11 @@ using System.Reflection;
|
||||
using static ARMeilleure.Instructions.InstEmitHelper;
|
||||
using static ARMeilleure.Instructions.InstEmitSimdHelper;
|
||||
using static ARMeilleure.IntermediateRepresentation.Operand.Factory;
|
||||
using Func1I = System.Func<ARMeilleure.IntermediateRepresentation.Operand, ARMeilleure.IntermediateRepresentation.Operand>;
|
||||
|
||||
namespace ARMeilleure.Instructions
|
||||
{
|
||||
using Func1I = Func<Operand, Operand>;
|
||||
|
||||
static partial class InstEmit
|
||||
{
|
||||
public static void Fcvt_S(ArmEmitterContext context)
|
||||
|
||||
@@ -8,12 +8,13 @@ using System.Diagnostics;
|
||||
using System.Reflection;
|
||||
using static ARMeilleure.Instructions.InstEmitHelper;
|
||||
using static ARMeilleure.IntermediateRepresentation.Operand.Factory;
|
||||
using Func1I = System.Func<ARMeilleure.IntermediateRepresentation.Operand, ARMeilleure.IntermediateRepresentation.Operand>;
|
||||
using Func2I = System.Func<ARMeilleure.IntermediateRepresentation.Operand, ARMeilleure.IntermediateRepresentation.Operand, ARMeilleure.IntermediateRepresentation.Operand>;
|
||||
using Func3I = System.Func<ARMeilleure.IntermediateRepresentation.Operand, ARMeilleure.IntermediateRepresentation.Operand, ARMeilleure.IntermediateRepresentation.Operand, ARMeilleure.IntermediateRepresentation.Operand>;
|
||||
|
||||
namespace ARMeilleure.Instructions
|
||||
{
|
||||
using Func1I = Func<Operand, Operand>;
|
||||
using Func2I = Func<Operand, Operand, Operand>;
|
||||
using Func3I = Func<Operand, Operand, Operand, Operand>;
|
||||
|
||||
static class InstEmitSimdHelper
|
||||
{
|
||||
#region "Masks"
|
||||
|
||||
@@ -7,12 +7,13 @@ using System.Reflection;
|
||||
using static ARMeilleure.Instructions.InstEmitHelper;
|
||||
using static ARMeilleure.Instructions.InstEmitSimdHelper;
|
||||
using static ARMeilleure.IntermediateRepresentation.Operand.Factory;
|
||||
using Func1I = System.Func<ARMeilleure.IntermediateRepresentation.Operand, ARMeilleure.IntermediateRepresentation.Operand>;
|
||||
using Func2I = System.Func<ARMeilleure.IntermediateRepresentation.Operand, ARMeilleure.IntermediateRepresentation.Operand, ARMeilleure.IntermediateRepresentation.Operand>;
|
||||
using Func3I = System.Func<ARMeilleure.IntermediateRepresentation.Operand, ARMeilleure.IntermediateRepresentation.Operand, ARMeilleure.IntermediateRepresentation.Operand, ARMeilleure.IntermediateRepresentation.Operand>;
|
||||
|
||||
namespace ARMeilleure.Instructions
|
||||
{
|
||||
using Func1I = Func<Operand, Operand>;
|
||||
using Func2I = Func<Operand, Operand, Operand>;
|
||||
using Func3I = Func<Operand, Operand, Operand, Operand>;
|
||||
|
||||
static class InstEmitSimdHelper32
|
||||
{
|
||||
public static (int, int) GetQuadwordAndSubindex(int index, RegisterSize size)
|
||||
|
||||
@@ -7,12 +7,13 @@ using System.Diagnostics;
|
||||
using static ARMeilleure.Instructions.InstEmitHelper;
|
||||
using static ARMeilleure.Instructions.InstEmitSimdHelper;
|
||||
using static ARMeilleure.IntermediateRepresentation.Operand.Factory;
|
||||
using Func1I = System.Func<ARMeilleure.IntermediateRepresentation.Operand, ARMeilleure.IntermediateRepresentation.Operand>;
|
||||
using Func2I = System.Func<ARMeilleure.IntermediateRepresentation.Operand, ARMeilleure.IntermediateRepresentation.Operand, ARMeilleure.IntermediateRepresentation.Operand>;
|
||||
using Func3I = System.Func<ARMeilleure.IntermediateRepresentation.Operand, ARMeilleure.IntermediateRepresentation.Operand, ARMeilleure.IntermediateRepresentation.Operand, ARMeilleure.IntermediateRepresentation.Operand>;
|
||||
|
||||
namespace ARMeilleure.Instructions
|
||||
{
|
||||
using Func1I = Func<Operand, Operand>;
|
||||
using Func2I = Func<Operand, Operand, Operand>;
|
||||
using Func3I = Func<Operand, Operand, Operand, Operand>;
|
||||
|
||||
static class InstEmitSimdHelper32Arm64
|
||||
{
|
||||
// Intrinsic Helpers
|
||||
|
||||
@@ -40,36 +40,34 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
long offset = 0;
|
||||
|
||||
for (int rep = 0; rep < op.Reps; rep++)
|
||||
#pragma warning disable IDE0055 // Disable formatting
|
||||
for (int rep = 0; rep < op.Reps; rep++)
|
||||
for (int elem = 0; elem < op.Elems; elem++)
|
||||
for (int sElem = 0; sElem < op.SElems; sElem++)
|
||||
{
|
||||
for (int elem = 0; elem < op.Elems; elem++)
|
||||
int rtt = (op.Rt + rep + sElem) & 0x1f;
|
||||
|
||||
Operand tt = GetVec(rtt);
|
||||
|
||||
Operand address = context.Add(n, Const(offset));
|
||||
|
||||
if (isLoad)
|
||||
{
|
||||
for (int sElem = 0; sElem < op.SElems; sElem++)
|
||||
EmitLoadSimd(context, address, tt, rtt, elem, op.Size);
|
||||
|
||||
if (op.RegisterSize == RegisterSize.Simd64 && elem == op.Elems - 1)
|
||||
{
|
||||
int rtt = (op.Rt + rep + sElem) & 0x1f;
|
||||
|
||||
Operand tt = GetVec(rtt);
|
||||
|
||||
Operand address = context.Add(n, Const(offset));
|
||||
|
||||
if (isLoad)
|
||||
{
|
||||
EmitLoadSimd(context, address, tt, rtt, elem, op.Size);
|
||||
|
||||
if (op.RegisterSize == RegisterSize.Simd64 && elem == op.Elems - 1)
|
||||
{
|
||||
context.Copy(tt, context.VectorZeroUpper64(tt));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
EmitStoreSimd(context, address, rtt, elem, op.Size);
|
||||
}
|
||||
|
||||
offset += 1 << op.Size;
|
||||
context.Copy(tt, context.VectorZeroUpper64(tt));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
EmitStoreSimd(context, address, rtt, elem, op.Size);
|
||||
}
|
||||
|
||||
offset += 1 << op.Size;
|
||||
}
|
||||
#pragma warning restore IDE0055
|
||||
|
||||
if (op.WBack)
|
||||
{
|
||||
|
||||
@@ -9,10 +9,11 @@ using System.Reflection;
|
||||
using static ARMeilleure.Instructions.InstEmitHelper;
|
||||
using static ARMeilleure.Instructions.InstEmitSimdHelper;
|
||||
using static ARMeilleure.IntermediateRepresentation.Operand.Factory;
|
||||
using Func2I = System.Func<ARMeilleure.IntermediateRepresentation.Operand, ARMeilleure.IntermediateRepresentation.Operand, ARMeilleure.IntermediateRepresentation.Operand>;
|
||||
|
||||
namespace ARMeilleure.Instructions
|
||||
{
|
||||
using Func2I = Func<Operand, Operand, Operand>;
|
||||
|
||||
static partial class InstEmit
|
||||
{
|
||||
#region "Masks"
|
||||
|
||||
@@ -3,6 +3,7 @@ using ARMeilleure.State;
|
||||
using ARMeilleure.Translation;
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using ExecutionContext = ARMeilleure.State.ExecutionContext;
|
||||
|
||||
namespace ARMeilleure.Instructions
|
||||
{
|
||||
@@ -200,7 +201,11 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
ExecutionContext context = GetContext();
|
||||
|
||||
context.CheckInterrupt();
|
||||
// If debugging, we'll handle interrupts outside
|
||||
if (!Optimizations.EnableDebugging)
|
||||
{
|
||||
context.CheckInterrupt();
|
||||
}
|
||||
|
||||
Statistics.ResumeTimer();
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
namespace ARMeilleure.IntermediateRepresentation
|
||||
{
|
||||
|
||||
@@ -7,9 +7,10 @@ namespace ARMeilleure.IntermediateRepresentation
|
||||
{
|
||||
private struct Data
|
||||
{
|
||||
#pragma warning disable CS0649 // Field is never assigned to
|
||||
public byte Kind;
|
||||
public byte Type;
|
||||
|
||||
#pragma warning restore CS0649
|
||||
public byte Scale;
|
||||
public Operand BaseAddress;
|
||||
public Operand Index;
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
using Arm64HardwareCapabilities = ARMeilleure.CodeGen.Arm64.HardwareCapabilities;
|
||||
using X86HardwareCapabilities = ARMeilleure.CodeGen.X86.HardwareCapabilities;
|
||||
|
||||
namespace ARMeilleure
|
||||
{
|
||||
using Arm64HardwareCapabilities = ARMeilleure.CodeGen.Arm64.HardwareCapabilities;
|
||||
using X86HardwareCapabilities = ARMeilleure.CodeGen.X86.HardwareCapabilities;
|
||||
|
||||
public static class Optimizations
|
||||
{
|
||||
// low-core count PPTC
|
||||
@@ -12,6 +12,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 UseAdvSimdIfAvailable { get; set; } = true;
|
||||
public static bool UseArm64AesIfAvailable { get; set; } = true;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using ARMeilleure.Memory;
|
||||
using System.Threading;
|
||||
|
||||
namespace ARMeilleure.State
|
||||
{
|
||||
@@ -10,7 +11,7 @@ namespace ARMeilleure.State
|
||||
|
||||
internal nint NativeContextPtr => _nativeContext.BasePtr;
|
||||
|
||||
private bool _interrupted;
|
||||
internal bool Interrupted { get; private set; }
|
||||
|
||||
private readonly ICounter _counter;
|
||||
|
||||
@@ -65,6 +66,8 @@ namespace ARMeilleure.State
|
||||
|
||||
public bool IsAarch32 { get; set; }
|
||||
|
||||
public ulong ThreadUid { get; set; }
|
||||
|
||||
internal ExecutionMode ExecutionMode
|
||||
{
|
||||
get
|
||||
@@ -90,14 +93,19 @@ namespace ARMeilleure.State
|
||||
|
||||
private readonly ExceptionCallbackNoArgs _interruptCallback;
|
||||
private readonly ExceptionCallback _breakCallback;
|
||||
private readonly ExceptionCallbackNoArgs _stepCallback;
|
||||
private readonly ExceptionCallback _supervisorCallback;
|
||||
private readonly ExceptionCallback _undefinedCallback;
|
||||
|
||||
internal int ShouldStep;
|
||||
public ulong DebugPc { get; set; }
|
||||
|
||||
public ExecutionContext(
|
||||
IJitMemoryAllocator allocator,
|
||||
ICounter counter,
|
||||
ExceptionCallbackNoArgs interruptCallback = null,
|
||||
ExceptionCallback breakCallback = null,
|
||||
ExceptionCallbackNoArgs stepCallback = null,
|
||||
ExceptionCallback supervisorCallback = null,
|
||||
ExceptionCallback undefinedCallback = null)
|
||||
{
|
||||
@@ -105,6 +113,7 @@ namespace ARMeilleure.State
|
||||
_counter = counter;
|
||||
_interruptCallback = interruptCallback;
|
||||
_breakCallback = breakCallback;
|
||||
_stepCallback = stepCallback;
|
||||
_supervisorCallback = supervisorCallback;
|
||||
_undefinedCallback = undefinedCallback;
|
||||
|
||||
@@ -127,9 +136,9 @@ namespace ARMeilleure.State
|
||||
|
||||
internal void CheckInterrupt()
|
||||
{
|
||||
if (_interrupted)
|
||||
if (Interrupted)
|
||||
{
|
||||
_interrupted = false;
|
||||
Interrupted = false;
|
||||
|
||||
_interruptCallback?.Invoke(this);
|
||||
}
|
||||
@@ -139,16 +148,37 @@ namespace ARMeilleure.State
|
||||
|
||||
public void RequestInterrupt()
|
||||
{
|
||||
_interrupted = true;
|
||||
Interrupted = true;
|
||||
}
|
||||
|
||||
public void StepHandler()
|
||||
{
|
||||
_stepCallback?.Invoke(this);
|
||||
}
|
||||
|
||||
public void RequestDebugStep()
|
||||
{
|
||||
Interlocked.Exchange(ref ShouldStep, 1);
|
||||
RequestInterrupt();
|
||||
}
|
||||
|
||||
internal void OnBreak(ulong address, int imm)
|
||||
{
|
||||
if (Optimizations.EnableDebugging)
|
||||
{
|
||||
DebugPc = Pc;
|
||||
}
|
||||
|
||||
_breakCallback?.Invoke(this, address, imm);
|
||||
}
|
||||
|
||||
internal void OnSupervisorCall(ulong address, int imm)
|
||||
{
|
||||
if (Optimizations.EnableDebugging)
|
||||
{
|
||||
DebugPc = Pc;
|
||||
}
|
||||
|
||||
_supervisorCallback?.Invoke(this, address, imm);
|
||||
}
|
||||
|
||||
|
||||
@@ -22,6 +22,12 @@ namespace ARMeilleure.State
|
||||
public ulong ExclusiveValueHigh;
|
||||
public int Running;
|
||||
public long Tpidr2El0;
|
||||
|
||||
/// <summary>
|
||||
/// Precise PC value used for debugging.
|
||||
/// This will only be set when Optimizations.EnableDebugging is true.
|
||||
/// </summary>
|
||||
public ulong DebugPrecisePc;
|
||||
}
|
||||
|
||||
private static NativeCtxStorage _dummyStorage = new();
|
||||
@@ -39,6 +45,11 @@ namespace ARMeilleure.State
|
||||
|
||||
public ulong GetPc()
|
||||
{
|
||||
if (Optimizations.EnableDebugging)
|
||||
{
|
||||
return GetStorage().DebugPrecisePc;
|
||||
}
|
||||
|
||||
// TODO: More precise tracking of PC value.
|
||||
return GetStorage().DispatchAddress;
|
||||
}
|
||||
@@ -268,6 +279,11 @@ namespace ARMeilleure.State
|
||||
return StorageOffset(ref _dummyStorage, ref _dummyStorage.Running);
|
||||
}
|
||||
|
||||
public static int GetDebugPrecisePcOffset()
|
||||
{
|
||||
return StorageOffset(ref _dummyStorage, ref _dummyStorage.DebugPrecisePc);
|
||||
}
|
||||
|
||||
private static int StorageOffset<T>(ref NativeCtxStorage storage, ref T target)
|
||||
{
|
||||
return (int)Unsafe.ByteOffset(ref Unsafe.As<NativeCtxStorage, T>(ref storage), ref target);
|
||||
|
||||
@@ -52,6 +52,7 @@ namespace ARMeilleure.Translation
|
||||
public bool HighCq { get; }
|
||||
public bool HasPtc { get; }
|
||||
public Aarch32Mode Mode { get; }
|
||||
public bool IsSingleStep { get; }
|
||||
|
||||
private int _ifThenBlockStateIndex = 0;
|
||||
private Condition[] _ifThenBlockState = [];
|
||||
@@ -66,7 +67,8 @@ namespace ARMeilleure.Translation
|
||||
ulong entryAddress,
|
||||
bool highCq,
|
||||
bool hasPtc,
|
||||
Aarch32Mode mode)
|
||||
Aarch32Mode mode,
|
||||
bool isSingleStep)
|
||||
{
|
||||
Memory = memory;
|
||||
CountTable = countTable;
|
||||
@@ -76,6 +78,7 @@ namespace ARMeilleure.Translation
|
||||
HighCq = highCq;
|
||||
HasPtc = hasPtc;
|
||||
Mode = mode;
|
||||
IsSingleStep = isSingleStep;
|
||||
|
||||
_labels = new Dictionary<ulong, Operand>();
|
||||
}
|
||||
@@ -218,28 +221,18 @@ namespace ARMeilleure.Translation
|
||||
{
|
||||
switch (condition)
|
||||
{
|
||||
|
||||
case Condition.Eq:
|
||||
return ICompareEqual(n, m);
|
||||
case Condition.Ne:
|
||||
return ICompareNotEqual(n, m);
|
||||
case Condition.GeUn:
|
||||
return ICompareGreaterOrEqualUI(n, m);
|
||||
case Condition.LtUn:
|
||||
return ICompareLessUI(n, m);
|
||||
case Condition.GtUn:
|
||||
return ICompareGreaterUI(n, m);
|
||||
case Condition.LeUn:
|
||||
return ICompareLessOrEqualUI(n, m);
|
||||
case Condition.Ge:
|
||||
return ICompareGreaterOrEqual(n, m);
|
||||
case Condition.Lt:
|
||||
return ICompareLess(n, m);
|
||||
case Condition.Gt:
|
||||
return ICompareGreater(n, m);
|
||||
case Condition.Le:
|
||||
return ICompareLessOrEqual(n, m);
|
||||
|
||||
#pragma warning disable IDE0055 // Disable formatting
|
||||
case Condition.Eq: return ICompareEqual (n, m);
|
||||
case Condition.Ne: return ICompareNotEqual (n, m);
|
||||
case Condition.GeUn: return ICompareGreaterOrEqualUI(n, m);
|
||||
case Condition.LtUn: return ICompareLessUI (n, m);
|
||||
case Condition.GtUn: return ICompareGreaterUI (n, m);
|
||||
case Condition.LeUn: return ICompareLessOrEqualUI (n, m);
|
||||
case Condition.Ge: return ICompareGreaterOrEqual (n, m);
|
||||
case Condition.Lt: return ICompareLess (n, m);
|
||||
case Condition.Gt: return ICompareGreater (n, m);
|
||||
case Condition.Le: return ICompareLessOrEqual (n, m);
|
||||
#pragma warning restore IDE0055
|
||||
}
|
||||
}
|
||||
else if (cmpName == InstName.Adds && _optOpLastCompare is IOpCodeAluImm op)
|
||||
@@ -264,20 +257,14 @@ namespace ARMeilleure.Translation
|
||||
|
||||
switch (condition)
|
||||
{
|
||||
|
||||
case Condition.Eq:
|
||||
return ICompareEqual(n, m);
|
||||
case Condition.Ne:
|
||||
return ICompareNotEqual(n, m);
|
||||
case Condition.Ge:
|
||||
return ICompareGreaterOrEqual(n, m);
|
||||
case Condition.Lt:
|
||||
return ICompareLess(n, m);
|
||||
case Condition.Gt:
|
||||
return ICompareGreater(n, m);
|
||||
case Condition.Le:
|
||||
return ICompareLessOrEqual(n, m);
|
||||
|
||||
#pragma warning disable IDE0055 // Disable formatting
|
||||
case Condition.Eq: return ICompareEqual (n, m);
|
||||
case Condition.Ne: return ICompareNotEqual (n, m);
|
||||
case Condition.Ge: return ICompareGreaterOrEqual(n, m);
|
||||
case Condition.Lt: return ICompareLess (n, m);
|
||||
case Condition.Gt: return ICompareGreater (n, m);
|
||||
case Condition.Le: return ICompareLessOrEqual (n, m);
|
||||
#pragma warning restore IDE0055
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -22,17 +22,18 @@ using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Threading;
|
||||
using static ARMeilleure.Translation.PTC.PtcFormatter;
|
||||
using Arm64HardwareCapabilities = ARMeilleure.CodeGen.Arm64.HardwareCapabilities;
|
||||
using X86HardwareCapabilities = ARMeilleure.CodeGen.X86.HardwareCapabilities;
|
||||
|
||||
namespace ARMeilleure.Translation.PTC
|
||||
{
|
||||
using Arm64HardwareCapabilities = CodeGen.Arm64.HardwareCapabilities;
|
||||
using X86HardwareCapabilities = CodeGen.X86.HardwareCapabilities;
|
||||
|
||||
class Ptc : IPtcLoadState
|
||||
{
|
||||
private const string OuterHeaderMagicString = "PTCohd\0\0";
|
||||
private const string InnerHeaderMagicString = "PTCihd\0\0";
|
||||
|
||||
private const uint InternalVersion = 7008; //! To be incremented manually for each change to the ARMeilleure project.
|
||||
private const uint InternalVersion = 7009; //! To be incremented manually for each change to the ARMeilleure project.
|
||||
|
||||
private const string ActualDir = "0";
|
||||
private const string BackupDir = "1";
|
||||
@@ -302,6 +303,13 @@ namespace ARMeilleure.Translation.PTC
|
||||
return false;
|
||||
}
|
||||
|
||||
if (outerHeader.DebuggerMode != Optimizations.EnableDebugging)
|
||||
{
|
||||
InvalidateCompressedStream(compressedStream);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
nint intPtr = nint.Zero;
|
||||
|
||||
try
|
||||
@@ -478,6 +486,7 @@ namespace ARMeilleure.Translation.PTC
|
||||
MemoryManagerMode = GetMemoryManagerMode(),
|
||||
OSPlatform = GetOSPlatform(),
|
||||
Architecture = (uint)RuntimeInformation.ProcessArchitecture,
|
||||
DebuggerMode = Optimizations.EnableDebugging,
|
||||
|
||||
UncompressedStreamSize =
|
||||
(long)Unsafe.SizeOf<InnerHeader>() +
|
||||
@@ -1067,7 +1076,7 @@ namespace ARMeilleure.Translation.PTC
|
||||
return osPlatform;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1/*, Size = 86*/)]
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1/*, Size = 87*/)]
|
||||
private struct OuterHeader
|
||||
{
|
||||
public ulong Magic;
|
||||
@@ -1079,6 +1088,7 @@ namespace ARMeilleure.Translation.PTC
|
||||
public byte MemoryManagerMode;
|
||||
public uint OSPlatform;
|
||||
public uint Architecture;
|
||||
public bool DebuggerMode;
|
||||
|
||||
public long UncompressedStreamSize;
|
||||
|
||||
|
||||
@@ -297,20 +297,12 @@ namespace ARMeilleure.Translation
|
||||
|
||||
switch (register.Type)
|
||||
{
|
||||
|
||||
case RegisterType.Flag:
|
||||
intMask = (1L << RegsCount) << register.Index;
|
||||
break;
|
||||
case RegisterType.Integer:
|
||||
intMask = 1L << register.Index;
|
||||
break;
|
||||
case RegisterType.FpFlag:
|
||||
vecMask = (1L << RegsCount) << register.Index;
|
||||
break;
|
||||
case RegisterType.Vector:
|
||||
vecMask = 1L << register.Index;
|
||||
break;
|
||||
|
||||
#pragma warning disable IDE0055 // Disable formatting
|
||||
case RegisterType.Flag: intMask = (1L << RegsCount) << register.Index; break;
|
||||
case RegisterType.Integer: intMask = 1L << register.Index; break;
|
||||
case RegisterType.FpFlag: vecMask = (1L << RegsCount) << register.Index; break;
|
||||
case RegisterType.Vector: vecMask = 1L << register.Index; break;
|
||||
#pragma warning restore IDE0055
|
||||
}
|
||||
|
||||
return new RegisterMask(intMask, vecMask);
|
||||
|
||||
@@ -119,7 +119,25 @@ namespace ARMeilleure.Translation
|
||||
|
||||
NativeInterface.RegisterThread(context, Memory, this);
|
||||
|
||||
if (Optimizations.UseUnmanagedDispatchLoop)
|
||||
if (Optimizations.EnableDebugging)
|
||||
{
|
||||
context.DebugPc = address;
|
||||
do
|
||||
{
|
||||
if (Interlocked.CompareExchange(ref context.ShouldStep, 0, 1) == 1)
|
||||
{
|
||||
context.DebugPc = Step(context, context.DebugPc);
|
||||
context.StepHandler();
|
||||
}
|
||||
else
|
||||
{
|
||||
context.DebugPc = ExecuteSingle(context, context.DebugPc);
|
||||
}
|
||||
context.CheckInterrupt();
|
||||
}
|
||||
while (context.Running && context.DebugPc != 0);
|
||||
}
|
||||
else if (Optimizations.UseUnmanagedDispatchLoop)
|
||||
{
|
||||
Stubs.DispatchLoop(context.NativeContextPtr, address);
|
||||
}
|
||||
@@ -175,7 +193,7 @@ namespace ARMeilleure.Translation
|
||||
return nextAddr;
|
||||
}
|
||||
|
||||
public ulong Step(State.ExecutionContext context, ulong address)
|
||||
private ulong Step(State.ExecutionContext context, ulong address)
|
||||
{
|
||||
TranslatedFunction func = Translate(address, context.ExecutionMode, highCq: false, singleStep: true);
|
||||
|
||||
@@ -186,6 +204,8 @@ namespace ARMeilleure.Translation
|
||||
return address;
|
||||
}
|
||||
|
||||
|
||||
|
||||
internal TranslatedFunction GetOrTranslate(ulong address, ExecutionMode mode)
|
||||
{
|
||||
if (!Functions.TryGetValue(address, out TranslatedFunction func))
|
||||
@@ -229,7 +249,8 @@ namespace ARMeilleure.Translation
|
||||
address,
|
||||
highCq,
|
||||
_ptc.State != PtcState.Disabled,
|
||||
mode: Aarch32Mode.User);
|
||||
mode: Aarch32Mode.User,
|
||||
isSingleStep: singleStep);
|
||||
|
||||
Logger.StartPass(PassName.Decoding);
|
||||
|
||||
@@ -367,9 +388,13 @@ namespace ARMeilleure.Translation
|
||||
|
||||
if (block.Exit)
|
||||
{
|
||||
// Left option here as it may be useful if we need to return to managed rather than tail call in
|
||||
// future. (eg. for debug)
|
||||
bool useReturns = false;
|
||||
// Return to managed rather than tail call.
|
||||
bool useReturns = Optimizations.EnableDebugging;
|
||||
|
||||
if (Optimizations.EnableDebugging)
|
||||
{
|
||||
EmitDebugPrecisePcUpdate(context, block.Address);
|
||||
}
|
||||
|
||||
InstEmitFlowHelper.EmitVirtualJump(context, Const(block.Address), isReturn: useReturns);
|
||||
}
|
||||
@@ -393,6 +418,11 @@ namespace ARMeilleure.Translation
|
||||
}
|
||||
}
|
||||
|
||||
if (Optimizations.EnableDebugging)
|
||||
{
|
||||
EmitDebugPrecisePcUpdate(context, opCode.Address);
|
||||
}
|
||||
|
||||
Operand lblPredicateSkip = default;
|
||||
|
||||
if (context.IsInIfThenBlock && context.CurrentIfThenBlockCond != Condition.Al)
|
||||
@@ -489,6 +519,14 @@ namespace ARMeilleure.Translation
|
||||
context.MarkLabel(lblExit);
|
||||
}
|
||||
|
||||
internal static void EmitDebugPrecisePcUpdate(EmitterContext context, ulong address)
|
||||
{
|
||||
long debugPrecisePcOffs = NativeContext.GetDebugPrecisePcOffset();
|
||||
|
||||
Operand debugPrecisePcAddr = context.Add(context.LoadArgument(OperandType.I64, 0), Const(debugPrecisePcOffs));
|
||||
context.Store(debugPrecisePcAddr, Const(address));
|
||||
}
|
||||
|
||||
public void InvalidateJitCacheRegion(ulong address, ulong size)
|
||||
{
|
||||
ulong[] overlapAddresses = [];
|
||||
|
||||
@@ -12,7 +12,7 @@ using static SDL2.SDL;
|
||||
|
||||
namespace Ryujinx.Audio.Backends.SDL2
|
||||
{
|
||||
public partial class SDL2HardwareDeviceDriver : IHardwareDeviceDriver
|
||||
public class SDL2HardwareDeviceDriver : IHardwareDeviceDriver
|
||||
{
|
||||
private readonly ManualResetEvent _updateRequiredEvent;
|
||||
private readonly ManualResetEvent _pauseEvent;
|
||||
@@ -22,36 +22,10 @@ namespace Ryujinx.Audio.Backends.SDL2
|
||||
|
||||
public float Volume { get; set; }
|
||||
|
||||
// A safe method to get default audio information.
|
||||
private static int GetDefaultAudioInfo(nint name, out SDL_AudioSpec spec, int isCapture)
|
||||
{
|
||||
int result;
|
||||
spec = new SDL_AudioSpec();
|
||||
IntPtr specPtr = IntPtr.Zero;
|
||||
|
||||
try
|
||||
{
|
||||
// Reserve memory
|
||||
specPtr = Marshal.AllocHGlobal(Marshal.SizeOf<SDL_AudioSpec>());
|
||||
// Call method
|
||||
result = SDL_GetDefaultAudioInfo(name, specPtr, isCapture);
|
||||
// Copy result to managed structure
|
||||
spec = Marshal.PtrToStructure<SDL_AudioSpec>(specPtr);
|
||||
}
|
||||
finally
|
||||
{
|
||||
// Free the unmanaged memory to prevent memory leaks
|
||||
if (specPtr != IntPtr.Zero)
|
||||
{
|
||||
Marshal.FreeHGlobal(specPtr);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
[LibraryImport("SDL2")]
|
||||
private static partial int SDL_GetDefaultAudioInfo(nint name, nint spec, int isCapture);
|
||||
// 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()
|
||||
{
|
||||
@@ -61,7 +35,7 @@ namespace Ryujinx.Audio.Backends.SDL2
|
||||
|
||||
SDL2Driver.Instance.Initialize();
|
||||
|
||||
int res = GetDefaultAudioInfo(nint.Zero, out SDL_AudioSpec spec, 0);
|
||||
int res = SDL_GetDefaultAudioInfo(nint.Zero, out SDL_AudioSpec spec, 0);
|
||||
|
||||
if (res != 0)
|
||||
{
|
||||
|
||||
@@ -23,7 +23,7 @@ namespace Ryujinx.Audio.Backends.SoundIo.Native
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
public delegate void JackCallbackDelegate(nint msg);
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct SoundIoStruct
|
||||
{
|
||||
public nint UserData;
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
using Ryujinx.Audio.Renderer.Server;
|
||||
using Ryujinx.Audio.Renderer.Server.MemoryPool;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Ryujinx.Audio.Renderer.Common
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents the input parameter for <see cref="Server.BehaviourContext"/>.
|
||||
/// Represents the input parameter for <see cref="BehaviourInfo"/>.
|
||||
/// </summary>
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
public struct BehaviourParameter
|
||||
@@ -21,7 +23,7 @@ namespace Ryujinx.Audio.Renderer.Common
|
||||
/// <summary>
|
||||
/// The flags given controlling behaviour of the audio renderer
|
||||
/// </summary>
|
||||
/// <remarks>See <see cref="Server.BehaviourContext.UpdateFlags(ulong)"/> and <see cref="Server.BehaviourContext.IsMemoryPoolForceMappingEnabled"/>.</remarks>
|
||||
/// <remarks>See <see cref="BehaviourInfo.UpdateFlags(ulong)"/> and <see cref="BehaviourInfo.IsMemoryPoolForceMappingEnabled"/>.</remarks>
|
||||
public ulong Flags;
|
||||
|
||||
/// <summary>
|
||||
@@ -43,7 +45,7 @@ namespace Ryujinx.Audio.Renderer.Common
|
||||
/// <summary>
|
||||
/// Extra information given with the <see cref="ResultCode"/>
|
||||
/// </summary>
|
||||
/// <remarks>This is usually used to report a faulting cpu address when a <see cref="Server.MemoryPool.MemoryPoolState"/> mapping fail.</remarks>
|
||||
/// <remarks>This is usually used to report a faulting cpu address when a <see cref="MemoryPoolInfo"/> mapping fail.</remarks>
|
||||
public ulong ExtraErrorInfo;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,7 +20,9 @@ namespace Ryujinx.Audio.Renderer.Common
|
||||
public uint Unknown24;
|
||||
public uint RenderInfoSize;
|
||||
|
||||
#pragma warning disable IDE0051, CS0169 // Remove unused field
|
||||
private Array4<int> _reserved;
|
||||
#pragma warning restore IDE0051, CS0169
|
||||
|
||||
public uint TotalSize;
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using Ryujinx.Audio.Renderer.Dsp.State;
|
||||
using Ryujinx.Audio.Renderer.Parameter;
|
||||
using Ryujinx.Common.Memory;
|
||||
using Ryujinx.Common.Utilities;
|
||||
using System;
|
||||
@@ -11,7 +12,7 @@ namespace Ryujinx.Audio.Renderer.Common
|
||||
/// </summary>
|
||||
/// <remarks>This is shared between the server and audio processor.</remarks>
|
||||
[StructLayout(LayoutKind.Sequential, Pack = Align)]
|
||||
public struct VoiceUpdateState
|
||||
public struct VoiceState
|
||||
{
|
||||
public const int Align = 0x10;
|
||||
public const int BiquadStateOffset = 0x0;
|
||||
@@ -25,7 +26,7 @@ namespace Ryujinx.Audio.Renderer.Common
|
||||
/// The total amount of samples that was played.
|
||||
/// </summary>
|
||||
/// <remarks>This is reset to 0 when a <see cref="WaveBuffer"/> finishes playing and <see cref="WaveBuffer.IsEndOfStream"/> is set.</remarks>
|
||||
/// <remarks>This is reset to 0 when looping while <see cref="Parameter.VoiceInParameter.DecodingBehaviour.PlayedSampleCountResetWhenLooping"/> is set.</remarks>
|
||||
/// <remarks>This is reset to 0 when looping while <see cref="VoiceInParameter1.DecodingBehaviour.PlayedSampleCountResetWhenLooping"/> is set.</remarks>
|
||||
public ulong PlayedSampleCount;
|
||||
|
||||
/// <summary>
|
||||
@@ -12,8 +12,9 @@ namespace Ryujinx.Audio.Renderer.Dsp
|
||||
private const int SamplesPerFrame = 14;
|
||||
private const int NibblesPerFrame = SamplesPerFrame + 2;
|
||||
private const int BytesPerFrame = 8;
|
||||
|
||||
#pragma warning disable IDE0051 // Remove unused private member
|
||||
private const int BitsPerFrame = BytesPerFrame * 8;
|
||||
#pragma warning restore IDE0051
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static uint GetAdpcmDataSize(int sampleCount)
|
||||
@@ -80,14 +81,14 @@ namespace Ryujinx.Audio.Renderer.Dsp
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static short GetCoefficientAtIndex(ReadOnlySpan<short> coefficients, int index)
|
||||
{
|
||||
if ((uint)index < (uint)coefficients.Length)
|
||||
if ((uint)index >= (uint)coefficients.Length)
|
||||
{
|
||||
return coefficients[index];
|
||||
Logger.Error?.Print(LogClass.AudioRenderer, $"Out of bound read for coefficient at index {index}");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
Logger.Error?.Print(LogClass.AudioRenderer, $"Out of bound read for coefficient at index {index}");
|
||||
|
||||
return 0;
|
||||
return coefficients[index];
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
using Ryujinx.Audio.Renderer.Dsp.State;
|
||||
using Ryujinx.Audio.Renderer.Parameter;
|
||||
using Ryujinx.Audio.Renderer.Parameter.Effect;
|
||||
using Ryujinx.Common.Memory;
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
@@ -9,6 +11,112 @@ namespace Ryujinx.Audio.Renderer.Dsp
|
||||
{
|
||||
private const int FixedPointPrecisionForParameter = 14;
|
||||
|
||||
public static BiquadFilterParameter1 ToBiquadFilterParameter1(BiquadFilterParameter2 parameter)
|
||||
{
|
||||
BiquadFilterParameter1 result = new()
|
||||
{
|
||||
Enable = parameter.Enable, Numerator = new Array3<short>(), Denominator = new Array2<short>()
|
||||
};
|
||||
|
||||
Span<short> resultNumeratorSpan = result.Numerator.AsSpan();
|
||||
Span<short> resultDenominatorSpan = result.Denominator.AsSpan();
|
||||
|
||||
Span<float> parameterNumeratorSpan = parameter.Numerator.AsSpan();
|
||||
Span<float> parameterDenominatorSpan = parameter.Denominator.AsSpan();
|
||||
|
||||
|
||||
resultNumeratorSpan[0] = (short)FixedPointHelper.ToFixed(parameterNumeratorSpan[0], FixedPointPrecisionForParameter);
|
||||
resultNumeratorSpan[1] = (short)FixedPointHelper.ToFixed(parameterNumeratorSpan[1], FixedPointPrecisionForParameter);
|
||||
resultNumeratorSpan[2] = (short)FixedPointHelper.ToFixed(parameterNumeratorSpan[2], FixedPointPrecisionForParameter);
|
||||
|
||||
resultDenominatorSpan[0] = (short)FixedPointHelper.ToFixed(parameterDenominatorSpan[0], FixedPointPrecisionForParameter);
|
||||
resultDenominatorSpan[1] = (short)FixedPointHelper.ToFixed(parameterDenominatorSpan[1], FixedPointPrecisionForParameter);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static BiquadFilterParameter2 ToBiquadFilterParameter2(BiquadFilterParameter1 parameter)
|
||||
{
|
||||
BiquadFilterParameter2 result = new()
|
||||
{
|
||||
Enable = parameter.Enable, Numerator = new Array3<float>(), Denominator = new Array2<float>()
|
||||
};
|
||||
|
||||
Span<float> resultNumeratorSpan = result.Numerator.AsSpan();
|
||||
Span<float> resultDenominatorSpan = result.Denominator.AsSpan();
|
||||
|
||||
Span<short> parameterNumeratorSpan = parameter.Numerator.AsSpan();
|
||||
Span<short> parameterDenominatorSpan = parameter.Denominator.AsSpan();
|
||||
|
||||
|
||||
resultNumeratorSpan[0] = FixedPointHelper.ToFloat(parameterNumeratorSpan[0], FixedPointPrecisionForParameter);
|
||||
resultNumeratorSpan[1] = FixedPointHelper.ToFloat(parameterNumeratorSpan[1], FixedPointPrecisionForParameter);
|
||||
resultNumeratorSpan[2] = FixedPointHelper.ToFloat(parameterNumeratorSpan[2], FixedPointPrecisionForParameter);
|
||||
|
||||
resultDenominatorSpan[0] = FixedPointHelper.ToFloat(parameterDenominatorSpan[0], FixedPointPrecisionForParameter);
|
||||
resultDenominatorSpan[1] = FixedPointHelper.ToFloat(parameterDenominatorSpan[1], FixedPointPrecisionForParameter);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static BiquadFilterEffectParameter1 ToBiquadFilterEffectParameter1(BiquadFilterEffectParameter2 parameter)
|
||||
{
|
||||
BiquadFilterEffectParameter1 result = new()
|
||||
{
|
||||
Input = parameter.Input,
|
||||
Output = parameter.Output,
|
||||
Numerator = new Array3<short>(),
|
||||
Denominator = new Array2<short>(),
|
||||
ChannelCount = parameter.ChannelCount,
|
||||
Status = parameter.Status,
|
||||
};
|
||||
|
||||
Span<short> resultNumeratorSpan = result.Numerator.AsSpan();
|
||||
Span<short> resultDenominatorSpan = result.Denominator.AsSpan();
|
||||
|
||||
Span<float> parameterNumeratorSpan = parameter.Numerator.AsSpan();
|
||||
Span<float> parameterDenominatorSpan = parameter.Denominator.AsSpan();
|
||||
|
||||
|
||||
resultNumeratorSpan[0] = (short)FixedPointHelper.ToFixed(parameterNumeratorSpan[0], FixedPointPrecisionForParameter);
|
||||
resultNumeratorSpan[1] = (short)FixedPointHelper.ToFixed(parameterNumeratorSpan[1], FixedPointPrecisionForParameter);
|
||||
resultNumeratorSpan[2] = (short)FixedPointHelper.ToFixed(parameterNumeratorSpan[2], FixedPointPrecisionForParameter);
|
||||
|
||||
resultDenominatorSpan[0] = (short)FixedPointHelper.ToFixed(parameterDenominatorSpan[0], FixedPointPrecisionForParameter);
|
||||
resultDenominatorSpan[1] = (short)FixedPointHelper.ToFixed(parameterDenominatorSpan[1], FixedPointPrecisionForParameter);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static BiquadFilterEffectParameter2 ToBiquadFilterEffectParameter2(BiquadFilterEffectParameter1 parameter)
|
||||
{
|
||||
BiquadFilterEffectParameter2 result = new()
|
||||
{
|
||||
Input = parameter.Input,
|
||||
Output = parameter.Output,
|
||||
Numerator = new Array3<float>(),
|
||||
Denominator = new Array2<float>(),
|
||||
ChannelCount = parameter.ChannelCount,
|
||||
Status = parameter.Status,
|
||||
};
|
||||
|
||||
Span<float> resultNumeratorSpan = result.Numerator.AsSpan();
|
||||
Span<float> resultDenominatorSpan = result.Denominator.AsSpan();
|
||||
|
||||
Span<short> parameterNumeratorSpan = parameter.Numerator.AsSpan();
|
||||
Span<short> parameterDenominatorSpan = parameter.Denominator.AsSpan();
|
||||
|
||||
|
||||
resultNumeratorSpan[0] = FixedPointHelper.ToFloat(parameterNumeratorSpan[0], FixedPointPrecisionForParameter);
|
||||
resultNumeratorSpan[1] = FixedPointHelper.ToFloat(parameterNumeratorSpan[1], FixedPointPrecisionForParameter);
|
||||
resultNumeratorSpan[2] = FixedPointHelper.ToFloat(parameterNumeratorSpan[2], FixedPointPrecisionForParameter);
|
||||
|
||||
resultDenominatorSpan[0] = FixedPointHelper.ToFloat(parameterDenominatorSpan[0], FixedPointPrecisionForParameter);
|
||||
resultDenominatorSpan[1] = FixedPointHelper.ToFloat(parameterDenominatorSpan[1], FixedPointPrecisionForParameter);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Apply a single biquad filter.
|
||||
/// </summary>
|
||||
@@ -20,18 +128,21 @@ namespace Ryujinx.Audio.Renderer.Dsp
|
||||
/// <param name="sampleCount">The count of samples to process</param>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void ProcessBiquadFilter(
|
||||
ref BiquadFilterParameter parameter,
|
||||
ref BiquadFilterParameter2 parameter,
|
||||
ref BiquadFilterState state,
|
||||
Span<float> outputBuffer,
|
||||
ReadOnlySpan<float> inputBuffer,
|
||||
uint sampleCount)
|
||||
{
|
||||
float a0 = FixedPointHelper.ToFloat(parameter.Numerator[0], FixedPointPrecisionForParameter);
|
||||
float a1 = FixedPointHelper.ToFloat(parameter.Numerator[1], FixedPointPrecisionForParameter);
|
||||
float a2 = FixedPointHelper.ToFloat(parameter.Numerator[2], FixedPointPrecisionForParameter);
|
||||
Span<float> numeratorSpan = parameter.Numerator.AsSpan();
|
||||
Span<float> denominatorSpan = parameter.Denominator.AsSpan();
|
||||
|
||||
float a0 = numeratorSpan[0];
|
||||
float a1 = numeratorSpan[1];
|
||||
float a2 = numeratorSpan[2];
|
||||
|
||||
float b1 = FixedPointHelper.ToFloat(parameter.Denominator[0], FixedPointPrecisionForParameter);
|
||||
float b2 = FixedPointHelper.ToFloat(parameter.Denominator[1], FixedPointPrecisionForParameter);
|
||||
float b1 = denominatorSpan[0];
|
||||
float b2 = denominatorSpan[1];
|
||||
|
||||
for (int i = 0; i < sampleCount; i++)
|
||||
{
|
||||
@@ -57,19 +168,22 @@ namespace Ryujinx.Audio.Renderer.Dsp
|
||||
/// <param name="volume">Mix volume</param>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void ProcessBiquadFilterAndMix(
|
||||
ref BiquadFilterParameter parameter,
|
||||
ref BiquadFilterParameter2 parameter,
|
||||
ref BiquadFilterState state,
|
||||
Span<float> outputBuffer,
|
||||
ReadOnlySpan<float> inputBuffer,
|
||||
uint sampleCount,
|
||||
float volume)
|
||||
{
|
||||
float a0 = FixedPointHelper.ToFloat(parameter.Numerator[0], FixedPointPrecisionForParameter);
|
||||
float a1 = FixedPointHelper.ToFloat(parameter.Numerator[1], FixedPointPrecisionForParameter);
|
||||
float a2 = FixedPointHelper.ToFloat(parameter.Numerator[2], FixedPointPrecisionForParameter);
|
||||
Span<float> numeratorSpan = parameter.Numerator.AsSpan();
|
||||
Span<float> denominatorSpan = parameter.Denominator.AsSpan();
|
||||
|
||||
float a0 = numeratorSpan[0];
|
||||
float a1 = numeratorSpan[1];
|
||||
float a2 = numeratorSpan[2];
|
||||
|
||||
float b1 = FixedPointHelper.ToFloat(parameter.Denominator[0], FixedPointPrecisionForParameter);
|
||||
float b2 = FixedPointHelper.ToFloat(parameter.Denominator[1], FixedPointPrecisionForParameter);
|
||||
float b1 = denominatorSpan[0];
|
||||
float b2 = denominatorSpan[1];
|
||||
|
||||
for (int i = 0; i < sampleCount; i++)
|
||||
{
|
||||
@@ -99,7 +213,7 @@ namespace Ryujinx.Audio.Renderer.Dsp
|
||||
/// <returns>Last filtered sample value</returns>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static float ProcessBiquadFilterAndMixRamp(
|
||||
ref BiquadFilterParameter parameter,
|
||||
ref BiquadFilterParameter2 parameter,
|
||||
ref BiquadFilterState state,
|
||||
Span<float> outputBuffer,
|
||||
ReadOnlySpan<float> inputBuffer,
|
||||
@@ -107,12 +221,15 @@ namespace Ryujinx.Audio.Renderer.Dsp
|
||||
float volume,
|
||||
float ramp)
|
||||
{
|
||||
float a0 = FixedPointHelper.ToFloat(parameter.Numerator[0], FixedPointPrecisionForParameter);
|
||||
float a1 = FixedPointHelper.ToFloat(parameter.Numerator[1], FixedPointPrecisionForParameter);
|
||||
float a2 = FixedPointHelper.ToFloat(parameter.Numerator[2], FixedPointPrecisionForParameter);
|
||||
Span<float> numeratorSpan = parameter.Numerator.AsSpan();
|
||||
Span<float> denominatorSpan = parameter.Denominator.AsSpan();
|
||||
|
||||
float a0 = numeratorSpan[0];
|
||||
float a1 = numeratorSpan[1];
|
||||
float a2 = numeratorSpan[2];
|
||||
|
||||
float b1 = FixedPointHelper.ToFloat(parameter.Denominator[0], FixedPointPrecisionForParameter);
|
||||
float b2 = FixedPointHelper.ToFloat(parameter.Denominator[1], FixedPointPrecisionForParameter);
|
||||
float b1 = denominatorSpan[0];
|
||||
float b2 = denominatorSpan[1];
|
||||
|
||||
float mixState = 0f;
|
||||
|
||||
@@ -146,7 +263,7 @@ namespace Ryujinx.Audio.Renderer.Dsp
|
||||
/// <param name="sampleCount">The count of samples to process</param>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void ProcessBiquadFilter(
|
||||
ReadOnlySpan<BiquadFilterParameter> parameters,
|
||||
ReadOnlySpan<BiquadFilterParameter2> parameters,
|
||||
Span<BiquadFilterState> states,
|
||||
Span<float> outputBuffer,
|
||||
ReadOnlySpan<float> inputBuffer,
|
||||
@@ -154,16 +271,19 @@ namespace Ryujinx.Audio.Renderer.Dsp
|
||||
{
|
||||
for (int stageIndex = 0; stageIndex < parameters.Length; stageIndex++)
|
||||
{
|
||||
BiquadFilterParameter parameter = parameters[stageIndex];
|
||||
BiquadFilterParameter2 parameter = parameters[stageIndex];
|
||||
|
||||
ref BiquadFilterState state = ref states[stageIndex];
|
||||
|
||||
Span<float> numeratorSpan = parameter.Numerator.AsSpan();
|
||||
Span<float> denominatorSpan = parameter.Denominator.AsSpan();
|
||||
|
||||
float a0 = FixedPointHelper.ToFloat(parameter.Numerator[0], FixedPointPrecisionForParameter);
|
||||
float a1 = FixedPointHelper.ToFloat(parameter.Numerator[1], FixedPointPrecisionForParameter);
|
||||
float a2 = FixedPointHelper.ToFloat(parameter.Numerator[2], FixedPointPrecisionForParameter);
|
||||
float a0 = numeratorSpan[0];
|
||||
float a1 = numeratorSpan[1];
|
||||
float a2 = numeratorSpan[2];
|
||||
|
||||
float b1 = FixedPointHelper.ToFloat(parameter.Denominator[0], FixedPointPrecisionForParameter);
|
||||
float b2 = FixedPointHelper.ToFloat(parameter.Denominator[1], FixedPointPrecisionForParameter);
|
||||
float b1 = denominatorSpan[0];
|
||||
float b2 = denominatorSpan[1];
|
||||
|
||||
for (int i = 0; i < sampleCount; i++)
|
||||
{
|
||||
@@ -192,8 +312,8 @@ namespace Ryujinx.Audio.Renderer.Dsp
|
||||
/// <param name="volume">Mix volume</param>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void ProcessDoubleBiquadFilterAndMix(
|
||||
ref BiquadFilterParameter parameter0,
|
||||
ref BiquadFilterParameter parameter1,
|
||||
ref BiquadFilterParameter2 parameter0,
|
||||
ref BiquadFilterParameter2 parameter1,
|
||||
ref BiquadFilterState state0,
|
||||
ref BiquadFilterState state1,
|
||||
Span<float> outputBuffer,
|
||||
@@ -201,19 +321,25 @@ namespace Ryujinx.Audio.Renderer.Dsp
|
||||
uint sampleCount,
|
||||
float volume)
|
||||
{
|
||||
float a00 = FixedPointHelper.ToFloat(parameter0.Numerator[0], FixedPointPrecisionForParameter);
|
||||
float a10 = FixedPointHelper.ToFloat(parameter0.Numerator[1], FixedPointPrecisionForParameter);
|
||||
float a20 = FixedPointHelper.ToFloat(parameter0.Numerator[2], FixedPointPrecisionForParameter);
|
||||
Span<float> numerator0Span = parameter0.Numerator.AsSpan();
|
||||
Span<float> numerator1Span = parameter1.Numerator.AsSpan();
|
||||
Span<float> denominator0Span = parameter0.Denominator.AsSpan();
|
||||
Span<float> denominator1Span = parameter1.Denominator.AsSpan();
|
||||
|
||||
|
||||
float a00 = numerator0Span[0];
|
||||
float a10 = numerator0Span[1];
|
||||
float a20 = numerator0Span[2];
|
||||
|
||||
float b10 = FixedPointHelper.ToFloat(parameter0.Denominator[0], FixedPointPrecisionForParameter);
|
||||
float b20 = FixedPointHelper.ToFloat(parameter0.Denominator[1], FixedPointPrecisionForParameter);
|
||||
float b10 = denominator0Span[0];
|
||||
float b20 = denominator0Span[1];
|
||||
|
||||
float a01 = FixedPointHelper.ToFloat(parameter1.Numerator[0], FixedPointPrecisionForParameter);
|
||||
float a11 = FixedPointHelper.ToFloat(parameter1.Numerator[1], FixedPointPrecisionForParameter);
|
||||
float a21 = FixedPointHelper.ToFloat(parameter1.Numerator[2], FixedPointPrecisionForParameter);
|
||||
float a01 = numerator1Span[0];
|
||||
float a11 = numerator1Span[1];
|
||||
float a21 = numerator1Span[2];
|
||||
|
||||
float b11 = FixedPointHelper.ToFloat(parameter1.Denominator[0], FixedPointPrecisionForParameter);
|
||||
float b21 = FixedPointHelper.ToFloat(parameter1.Denominator[1], FixedPointPrecisionForParameter);
|
||||
float b11 = denominator1Span[0];
|
||||
float b21 = denominator1Span[1];
|
||||
|
||||
for (int i = 0; i < sampleCount; i++)
|
||||
{
|
||||
@@ -251,8 +377,8 @@ namespace Ryujinx.Audio.Renderer.Dsp
|
||||
/// <returns>Last filtered sample value</returns>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static float ProcessDoubleBiquadFilterAndMixRamp(
|
||||
ref BiquadFilterParameter parameter0,
|
||||
ref BiquadFilterParameter parameter1,
|
||||
ref BiquadFilterParameter2 parameter0,
|
||||
ref BiquadFilterParameter2 parameter1,
|
||||
ref BiquadFilterState state0,
|
||||
ref BiquadFilterState state1,
|
||||
Span<float> outputBuffer,
|
||||
@@ -261,19 +387,24 @@ namespace Ryujinx.Audio.Renderer.Dsp
|
||||
float volume,
|
||||
float ramp)
|
||||
{
|
||||
float a00 = FixedPointHelper.ToFloat(parameter0.Numerator[0], FixedPointPrecisionForParameter);
|
||||
float a10 = FixedPointHelper.ToFloat(parameter0.Numerator[1], FixedPointPrecisionForParameter);
|
||||
float a20 = FixedPointHelper.ToFloat(parameter0.Numerator[2], FixedPointPrecisionForParameter);
|
||||
Span<float> numerator0Span = parameter0.Numerator.AsSpan();
|
||||
Span<float> numerator1Span = parameter1.Numerator.AsSpan();
|
||||
Span<float> denominator0Span = parameter0.Denominator.AsSpan();
|
||||
Span<float> denominator1Span = parameter1.Denominator.AsSpan();
|
||||
|
||||
float a00 = numerator0Span[0];
|
||||
float a10 = numerator0Span[1];
|
||||
float a20 = numerator0Span[2];
|
||||
|
||||
float b10 = FixedPointHelper.ToFloat(parameter0.Denominator[0], FixedPointPrecisionForParameter);
|
||||
float b20 = FixedPointHelper.ToFloat(parameter0.Denominator[1], FixedPointPrecisionForParameter);
|
||||
float b10 = denominator0Span[0];
|
||||
float b20 = denominator0Span[1];
|
||||
|
||||
float a01 = FixedPointHelper.ToFloat(parameter1.Numerator[0], FixedPointPrecisionForParameter);
|
||||
float a11 = FixedPointHelper.ToFloat(parameter1.Numerator[1], FixedPointPrecisionForParameter);
|
||||
float a21 = FixedPointHelper.ToFloat(parameter1.Numerator[2], FixedPointPrecisionForParameter);
|
||||
float a01 = numerator1Span[0];
|
||||
float a11 = numerator1Span[1];
|
||||
float a21 = numerator1Span[2];
|
||||
|
||||
float b11 = FixedPointHelper.ToFloat(parameter1.Denominator[0], FixedPointPrecisionForParameter);
|
||||
float b21 = FixedPointHelper.ToFloat(parameter1.Denominator[1], FixedPointPrecisionForParameter);
|
||||
float b11 = denominator1Span[0];
|
||||
float b21 = denominator1Span[1];
|
||||
|
||||
float mixState = 0f;
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ using Ryujinx.Audio.Common;
|
||||
using Ryujinx.Audio.Renderer.Common;
|
||||
using Ryujinx.Audio.Renderer.Server.Voice;
|
||||
using System;
|
||||
using static Ryujinx.Audio.Renderer.Parameter.VoiceInParameter;
|
||||
using Ryujinx.Audio.Renderer.Parameter;
|
||||
using WaveBuffer = Ryujinx.Audio.Renderer.Common.WaveBuffer;
|
||||
|
||||
namespace Ryujinx.Audio.Renderer.Dsp.Command
|
||||
@@ -24,35 +24,37 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
||||
|
||||
public WaveBuffer[] WaveBuffers { get; }
|
||||
|
||||
public Memory<VoiceUpdateState> State { get; }
|
||||
public Memory<VoiceState> State { get; }
|
||||
|
||||
public ulong AdpcmParameter { get; }
|
||||
public ulong AdpcmParameterSize { get; }
|
||||
|
||||
public DecodingBehaviour DecodingBehaviour { get; }
|
||||
|
||||
public AdpcmDataSourceCommandVersion1(ref VoiceState serverState, Memory<VoiceUpdateState> state, ushort outputBufferIndex, int nodeId)
|
||||
public AdpcmDataSourceCommandVersion1(ref VoiceInfo serverInfo, Memory<VoiceState> state, ushort outputBufferIndex, int nodeId)
|
||||
{
|
||||
Enabled = true;
|
||||
NodeId = nodeId;
|
||||
|
||||
OutputBufferIndex = outputBufferIndex;
|
||||
SampleRate = serverState.SampleRate;
|
||||
Pitch = serverState.Pitch;
|
||||
SampleRate = serverInfo.SampleRate;
|
||||
Pitch = serverInfo.Pitch;
|
||||
|
||||
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 serverState.WaveBuffers[i];
|
||||
ref Server.Voice.WaveBuffer voiceWaveBuffer = ref waveBufferSpan[i];
|
||||
|
||||
WaveBuffers[i] = voiceWaveBuffer.ToCommon(1);
|
||||
}
|
||||
|
||||
AdpcmParameter = serverState.DataSourceStateAddressInfo.GetReference(true);
|
||||
AdpcmParameterSize = serverState.DataSourceStateAddressInfo.Size;
|
||||
AdpcmParameter = serverInfo.DataSourceStateAddressInfo.GetReference(true);
|
||||
AdpcmParameterSize = serverInfo.DataSourceStateAddressInfo.Size;
|
||||
State = state;
|
||||
DecodingBehaviour = serverState.DecodingBehaviour;
|
||||
DecodingBehaviour = serverInfo.DecodingBehaviour;
|
||||
}
|
||||
|
||||
public void Process(CommandList context)
|
||||
|
||||
@@ -18,12 +18,12 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
||||
public ushort InputBufferIndex { get; }
|
||||
public ushort OutputBufferIndex { get; }
|
||||
|
||||
private BiquadFilterParameter _parameter;
|
||||
private BiquadFilterParameter2 _parameter;
|
||||
|
||||
public Memory<BiquadFilterState> BiquadFilterState { get; }
|
||||
public Memory<BiquadFilterState> PreviousBiquadFilterState { get; }
|
||||
|
||||
public Memory<VoiceUpdateState> State { get; }
|
||||
public Memory<VoiceState> State { get; }
|
||||
|
||||
public int LastSampleIndex { get; }
|
||||
|
||||
@@ -40,8 +40,8 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
||||
uint inputBufferIndex,
|
||||
uint outputBufferIndex,
|
||||
int lastSampleIndex,
|
||||
Memory<VoiceUpdateState> state,
|
||||
ref BiquadFilterParameter filter,
|
||||
Memory<VoiceState> state,
|
||||
ref BiquadFilterParameter2 filter,
|
||||
Memory<BiquadFilterState> biquadFilterState,
|
||||
Memory<BiquadFilterState> previousBiquadFilterState,
|
||||
bool needInitialization,
|
||||
|
||||
@@ -19,11 +19,11 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
||||
public int OutputBufferIndex { get; }
|
||||
public bool NeedInitialization { get; }
|
||||
|
||||
private BiquadFilterParameter _parameter;
|
||||
private BiquadFilterParameter2 _parameter;
|
||||
|
||||
public BiquadFilterCommand(
|
||||
int baseIndex,
|
||||
ref BiquadFilterParameter filter,
|
||||
ref BiquadFilterParameter2 filter,
|
||||
Memory<BiquadFilterState> biquadFilterStateMemory,
|
||||
int inputBufferOffset,
|
||||
int outputBufferOffset,
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using Ryujinx.Audio.Renderer.Parameter.Sink;
|
||||
using Ryujinx.Audio.Renderer.Server.MemoryPool;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace Ryujinx.Audio.Renderer.Dsp.Command
|
||||
@@ -28,10 +29,12 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
||||
|
||||
Input = new ushort[Constants.ChannelCountMax];
|
||||
InputCount = parameter.InputCount;
|
||||
|
||||
Span<byte> inputSpan = parameter.Input.AsSpan();
|
||||
|
||||
for (int i = 0; i < InputCount; i++)
|
||||
{
|
||||
Input[i] = (ushort)(bufferOffset + parameter.Input[i]);
|
||||
Input[i] = (ushort)(bufferOffset + inputSpan[i]);
|
||||
}
|
||||
|
||||
CircularBuffer = circularBufferAddressInfo.GetReference(true);
|
||||
|
||||
@@ -129,7 +129,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
||||
{
|
||||
startTime = PerformanceCounter.ElapsedNanoseconds;
|
||||
}
|
||||
|
||||
|
||||
command.Process(this);
|
||||
|
||||
if (shouldMeter)
|
||||
|
||||
@@ -12,6 +12,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
||||
Volume,
|
||||
VolumeRamp,
|
||||
BiquadFilter,
|
||||
BiquadFilterFloatCoeff, // new
|
||||
Mix,
|
||||
MixRamp,
|
||||
MixRampGrouped,
|
||||
@@ -31,9 +32,17 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
||||
LimiterVersion1,
|
||||
LimiterVersion2,
|
||||
MultiTapBiquadFilter,
|
||||
MultiTapBiquadFilterFloatCoeff, // new
|
||||
CaptureBuffer,
|
||||
Compressor,
|
||||
BiquadFilterAndMix,
|
||||
BiquadFilterAndMixFloatCoeff, // new
|
||||
MultiTapBiquadFilterAndMix,
|
||||
MultiTapBiquadFilterAndMixFloatCoef, // new
|
||||
AuxiliaryBufferGrouped, // new
|
||||
FillMixBuffer, // new
|
||||
BiquadFilterCrossFade, // new
|
||||
MultiTapBiquadFilterCrossFade, // new
|
||||
FillBuffer, // new
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,11 +42,14 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
||||
|
||||
InputBufferIndices = new ushort[Constants.VoiceChannelCountMax];
|
||||
OutputBufferIndices = new ushort[Constants.VoiceChannelCountMax];
|
||||
|
||||
Span<byte> inputSpan = _parameter.Input.AsSpan();
|
||||
Span<byte> outputSpan = _parameter.Output.AsSpan();
|
||||
|
||||
for (int i = 0; i < _parameter.ChannelCount; i++)
|
||||
{
|
||||
InputBufferIndices[i] = (ushort)(bufferOffset + _parameter.Input[i]);
|
||||
OutputBufferIndices[i] = (ushort)(bufferOffset + _parameter.Output[i]);
|
||||
InputBufferIndices[i] = (ushort)(bufferOffset + inputSpan[i]);
|
||||
OutputBufferIndices[i] = (ushort)(bufferOffset + outputSpan[i]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -171,10 +174,12 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
||||
|
||||
statistics.MinimumGain = MathF.Min(statistics.MinimumGain, compressionGain * state.OutputGain);
|
||||
statistics.MaximumMean = MathF.Max(statistics.MaximumMean, mean);
|
||||
|
||||
Span<float> lastSamplesSpan = statistics.LastSamples.AsSpan();
|
||||
|
||||
for (int channelIndex = 0; channelIndex < _parameter.ChannelCount; channelIndex++)
|
||||
{
|
||||
statistics.LastSamples[channelIndex] = MathF.Abs(channelInput[channelIndex] * (1f / 32768f));
|
||||
lastSamplesSpan[channelIndex] = MathF.Abs(channelInput[channelIndex] * (1f / 32768f));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ using Ryujinx.Audio.Common;
|
||||
using Ryujinx.Audio.Renderer.Common;
|
||||
using Ryujinx.Audio.Renderer.Server.Voice;
|
||||
using System;
|
||||
using static Ryujinx.Audio.Renderer.Parameter.VoiceInParameter;
|
||||
using Ryujinx.Audio.Renderer.Parameter;
|
||||
using WaveBuffer = Ryujinx.Audio.Renderer.Common.WaveBuffer;
|
||||
|
||||
namespace Ryujinx.Audio.Renderer.Dsp.Command
|
||||
@@ -24,7 +24,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
||||
|
||||
public WaveBuffer[] WaveBuffers { get; }
|
||||
|
||||
public Memory<VoiceUpdateState> State { get; }
|
||||
public Memory<VoiceState> State { get; }
|
||||
|
||||
public ulong ExtraParameter { get; }
|
||||
public ulong ExtraParameterSize { get; }
|
||||
@@ -39,37 +39,39 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
||||
|
||||
public SampleRateConversionQuality SrcQuality { get; }
|
||||
|
||||
public DataSourceVersion2Command(ref VoiceState serverState, Memory<VoiceUpdateState> state, ushort outputBufferIndex, ushort channelIndex, int nodeId)
|
||||
public DataSourceVersion2Command(ref VoiceInfo serverInfo, Memory<VoiceState> state, ushort outputBufferIndex, ushort channelIndex, int nodeId)
|
||||
{
|
||||
Enabled = true;
|
||||
NodeId = nodeId;
|
||||
ChannelIndex = channelIndex;
|
||||
ChannelCount = serverState.ChannelsCount;
|
||||
SampleFormat = serverState.SampleFormat;
|
||||
SrcQuality = serverState.SrcQuality;
|
||||
ChannelCount = serverInfo.ChannelsCount;
|
||||
SampleFormat = serverInfo.SampleFormat;
|
||||
SrcQuality = serverInfo.SrcQuality;
|
||||
CommandType = GetCommandTypeBySampleFormat(SampleFormat);
|
||||
|
||||
OutputBufferIndex = (ushort)(channelIndex + outputBufferIndex);
|
||||
SampleRate = serverState.SampleRate;
|
||||
Pitch = serverState.Pitch;
|
||||
SampleRate = serverInfo.SampleRate;
|
||||
Pitch = serverInfo.Pitch;
|
||||
|
||||
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 serverState.WaveBuffers[i];
|
||||
ref Server.Voice.WaveBuffer voiceWaveBuffer = ref waveBufferSpan[i];
|
||||
|
||||
WaveBuffers[i] = voiceWaveBuffer.ToCommon(2);
|
||||
}
|
||||
|
||||
if (SampleFormat == SampleFormat.Adpcm)
|
||||
{
|
||||
ExtraParameter = serverState.DataSourceStateAddressInfo.GetReference(true);
|
||||
ExtraParameterSize = serverState.DataSourceStateAddressInfo.Size;
|
||||
ExtraParameter = serverInfo.DataSourceStateAddressInfo.GetReference(true);
|
||||
ExtraParameterSize = serverInfo.DataSourceStateAddressInfo.Size;
|
||||
}
|
||||
|
||||
State = state;
|
||||
DecodingBehaviour = serverState.DecodingBehaviour;
|
||||
DecodingBehaviour = serverInfo.DecodingBehaviour;
|
||||
}
|
||||
|
||||
private static CommandType GetCommandTypeBySampleFormat(SampleFormat sampleFormat)
|
||||
|
||||
@@ -42,11 +42,14 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
||||
|
||||
InputBufferIndices = new ushort[Constants.VoiceChannelCountMax];
|
||||
OutputBufferIndices = new ushort[Constants.VoiceChannelCountMax];
|
||||
|
||||
Span<byte> inputSpan = Parameter.Input.AsSpan();
|
||||
Span<byte> outputSpan = Parameter.Output.AsSpan();
|
||||
|
||||
for (int i = 0; i < Parameter.ChannelCount; i++)
|
||||
{
|
||||
InputBufferIndices[i] = (ushort)(bufferOffset + Parameter.Input[i]);
|
||||
OutputBufferIndices[i] = (ushort)(bufferOffset + Parameter.Output[i]);
|
||||
InputBufferIndices[i] = (ushort)(bufferOffset + inputSpan[i]);
|
||||
OutputBufferIndices[i] = (ushort)(bufferOffset + outputSpan[i]);
|
||||
}
|
||||
|
||||
DataSourceHelper.RemapLegacyChannelEffectMappingToChannelResourceMapping(newEffectChannelMappingSupported, InputBufferIndices, Parameter.ChannelCount);
|
||||
|
||||
@@ -17,10 +17,10 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
||||
|
||||
public ushort[] OutputBufferIndices { get; }
|
||||
|
||||
public Memory<VoiceUpdateState> State { get; }
|
||||
public Memory<VoiceState> State { get; }
|
||||
public Memory<float> DepopBuffer { get; }
|
||||
|
||||
public DepopPrepareCommand(Memory<VoiceUpdateState> state, Memory<float> depopBuffer, uint mixBufferCount, uint bufferOffset, int nodeId, bool enabled)
|
||||
public DepopPrepareCommand(Memory<VoiceState> state, Memory<float> depopBuffer, uint mixBufferCount, uint bufferOffset, int nodeId, bool enabled)
|
||||
{
|
||||
Enabled = enabled;
|
||||
NodeId = nodeId;
|
||||
@@ -39,17 +39,18 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
||||
|
||||
public void Process(CommandList context)
|
||||
{
|
||||
ref VoiceUpdateState state = ref State.Span[0];
|
||||
ref VoiceState state = ref State.Span[0];
|
||||
|
||||
Span<float> depopBuffer = DepopBuffer.Span;
|
||||
Span<float> lastSamplesSpan = state.LastSamples.AsSpan();
|
||||
|
||||
for (int i = 0; i < MixBufferCount; i++)
|
||||
{
|
||||
if (state.LastSamples[i] != 0)
|
||||
if (lastSamplesSpan[i] != 0)
|
||||
{
|
||||
depopBuffer[OutputBufferIndices[i]] += state.LastSamples[i];
|
||||
depopBuffer[OutputBufferIndices[i]] += lastSamplesSpan[i];
|
||||
|
||||
state.LastSamples[i] = 0;
|
||||
lastSamplesSpan[i] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,15 +34,17 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
||||
SessionId = sessionId;
|
||||
InputCount = sink.Parameter.InputCount;
|
||||
InputBufferIndices = new ushort[InputCount];
|
||||
|
||||
Span<byte> inputSpan = sink.Parameter.Input.AsSpan();
|
||||
|
||||
for (int i = 0; i < Math.Min(InputCount, Constants.ChannelCountMax); i++)
|
||||
{
|
||||
InputBufferIndices[i] = (ushort)(bufferOffset + sink.Parameter.Input[i]);
|
||||
InputBufferIndices[i] = (ushort)(bufferOffset + inputSpan[i]);
|
||||
}
|
||||
|
||||
if (sink.UpsamplerState != null)
|
||||
if (sink.UpsamplerInfo != null)
|
||||
{
|
||||
Buffers = sink.UpsamplerState.OutputBuffer;
|
||||
Buffers = sink.UpsamplerInfo.OutputBuffer;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
69
src/Ryujinx.Audio/Renderer/Dsp/Command/FillBufferCommand.cs
Normal file
69
src/Ryujinx.Audio/Renderer/Dsp/Command/FillBufferCommand.cs
Normal file
@@ -0,0 +1,69 @@
|
||||
using Ryujinx.Audio.Renderer.Server.Splitter;
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace Ryujinx.Audio.Renderer.Dsp.Command
|
||||
{
|
||||
public class FillBufferCommand : ICommand
|
||||
{
|
||||
public bool Enabled { get; set; }
|
||||
|
||||
public int NodeId { get; }
|
||||
|
||||
public CommandType CommandType => CommandType.FillBuffer;
|
||||
|
||||
public uint EstimatedProcessingTime { get; set; }
|
||||
|
||||
public SplitterDestinationVersion1 Destination1 { get; }
|
||||
public SplitterDestinationVersion2 Destination2 { get; }
|
||||
public bool IsV2 { get; }
|
||||
public int Length { get; }
|
||||
public float Value { get; }
|
||||
|
||||
public FillBufferCommand(SplitterDestinationVersion1 destination, int length, float value, int nodeId)
|
||||
{
|
||||
Enabled = true;
|
||||
NodeId = nodeId;
|
||||
|
||||
Destination1 = destination;
|
||||
IsV2 = false;
|
||||
Length = length;
|
||||
Value = value;
|
||||
}
|
||||
|
||||
public FillBufferCommand(SplitterDestinationVersion2 destination, int length, float value, int nodeId)
|
||||
{
|
||||
Enabled = true;
|
||||
NodeId = nodeId;
|
||||
|
||||
Destination2 = destination;
|
||||
IsV2 = true;
|
||||
Length = length;
|
||||
Value = value;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private void ProcessFillBuffer()
|
||||
{
|
||||
if (IsV2)
|
||||
{
|
||||
for (int i = 0; i < Length; i++)
|
||||
{
|
||||
Destination2.PreviousMixBufferVolume[i] = Value;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < Length; i++)
|
||||
{
|
||||
Destination1.PreviousMixBufferVolume[i] = Value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Process(CommandList context)
|
||||
{
|
||||
ProcessFillBuffer();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -37,11 +37,14 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
||||
|
||||
InputBufferIndices = new ushort[Constants.VoiceChannelCountMax];
|
||||
OutputBufferIndices = new ushort[Constants.VoiceChannelCountMax];
|
||||
|
||||
Span<byte> inputSpan = _parameter.Input.AsSpan();
|
||||
Span<byte> outputSpan = _parameter.Output.AsSpan();
|
||||
|
||||
for (int i = 0; i < _parameter.ChannelCount; i++)
|
||||
{
|
||||
InputBufferIndices[i] = (ushort)(bufferOffset + _parameter.Input[i]);
|
||||
OutputBufferIndices[i] = (ushort)(bufferOffset + _parameter.Output[i]);
|
||||
InputBufferIndices[i] = (ushort)(bufferOffset + inputSpan[i]);
|
||||
OutputBufferIndices[i] = (ushort)(bufferOffset + outputSpan[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -48,11 +48,14 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
||||
|
||||
InputBufferIndices = new ushort[Constants.VoiceChannelCountMax];
|
||||
OutputBufferIndices = new ushort[Constants.VoiceChannelCountMax];
|
||||
|
||||
Span<byte> inputSpan = _parameter.Input.AsSpan();
|
||||
Span<byte> outputSpan = _parameter.Output.AsSpan();
|
||||
|
||||
for (int i = 0; i < _parameter.ChannelCount; i++)
|
||||
{
|
||||
InputBufferIndices[i] = (ushort)(bufferOffset + _parameter.Input[i]);
|
||||
OutputBufferIndices[i] = (ushort)(bufferOffset + _parameter.Output[i]);
|
||||
InputBufferIndices[i] = (ushort)(bufferOffset + inputSpan[i]);
|
||||
OutputBufferIndices[i] = (ushort)(bufferOffset + outputSpan[i]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -150,8 +153,11 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
||||
{
|
||||
ref LimiterStatistics statistics = ref MemoryMarshal.Cast<byte, LimiterStatistics>(ResultState.Span[0].SpecificData)[0];
|
||||
|
||||
statistics.InputMax[channelIndex] = Math.Max(statistics.InputMax[channelIndex], sampleInputMax);
|
||||
statistics.CompressionGainMin[channelIndex] = Math.Min(statistics.CompressionGainMin[channelIndex], compressionGain);
|
||||
Span<float> inputMaxSpan = statistics.InputMax.AsSpan();
|
||||
Span<float> compressionGainMinSpan = statistics.CompressionGainMin.AsSpan();
|
||||
|
||||
inputMaxSpan[channelIndex] = Math.Max(inputMaxSpan[channelIndex], sampleInputMax);
|
||||
compressionGainMinSpan[channelIndex] = Math.Min(compressionGainMinSpan[channelIndex], compressionGain);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,11 +20,11 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
||||
public float Volume0 { get; }
|
||||
public float Volume1 { get; }
|
||||
|
||||
public Memory<VoiceUpdateState> State { get; }
|
||||
public Memory<VoiceState> State { get; }
|
||||
|
||||
public int LastSampleIndex { get; }
|
||||
|
||||
public MixRampCommand(float volume0, float volume1, uint inputBufferIndex, uint outputBufferIndex, int lastSampleIndex, Memory<VoiceUpdateState> state, int nodeId)
|
||||
public MixRampCommand(float volume0, float volume1, uint inputBufferIndex, uint outputBufferIndex, int lastSampleIndex, Memory<VoiceState> state, int nodeId)
|
||||
{
|
||||
Enabled = true;
|
||||
NodeId = nodeId;
|
||||
|
||||
@@ -22,7 +22,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
||||
public float[] Volume0 { get; }
|
||||
public float[] Volume1 { get; }
|
||||
|
||||
public Memory<VoiceUpdateState> State { get; }
|
||||
public Memory<VoiceState> State { get; }
|
||||
|
||||
public MixRampGroupedCommand(
|
||||
uint mixBufferCount,
|
||||
@@ -30,7 +30,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
||||
uint outputBufferIndex,
|
||||
ReadOnlySpan<float> volume0,
|
||||
ReadOnlySpan<float> volume1,
|
||||
Memory<VoiceUpdateState> state,
|
||||
Memory<VoiceState> state,
|
||||
int nodeId)
|
||||
{
|
||||
Enabled = true;
|
||||
@@ -79,6 +79,10 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
||||
|
||||
public void Process(CommandList context)
|
||||
{
|
||||
ref VoiceState state = ref State.Span[0];
|
||||
|
||||
Span<float> lastSamplesSpan = state.LastSamples.AsSpan();
|
||||
|
||||
for (int i = 0; i < MixBufferCount; i++)
|
||||
{
|
||||
ReadOnlySpan<float> inputBuffer = context.GetBuffer(InputBufferIndices[i]);
|
||||
@@ -87,15 +91,13 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
||||
float volume0 = Volume0[i];
|
||||
float volume1 = Volume1[i];
|
||||
|
||||
ref VoiceUpdateState state = ref State.Span[0];
|
||||
|
||||
if (volume0 != 0 || volume1 != 0)
|
||||
{
|
||||
state.LastSamples[i] = ProcessMixRampGrouped(outputBuffer, inputBuffer, volume0, volume1, (int)context.SampleCount);
|
||||
lastSamplesSpan[i] = ProcessMixRampGrouped(outputBuffer, inputBuffer, volume0, volume1, (int)context.SampleCount);
|
||||
}
|
||||
else
|
||||
{
|
||||
state.LastSamples[i] = 0;
|
||||
lastSamplesSpan[i] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,15 +18,15 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
||||
public ushort InputBufferIndex { get; }
|
||||
public ushort OutputBufferIndex { get; }
|
||||
|
||||
private BiquadFilterParameter _parameter0;
|
||||
private BiquadFilterParameter _parameter1;
|
||||
private BiquadFilterParameter2 _parameter0;
|
||||
private BiquadFilterParameter2 _parameter1;
|
||||
|
||||
public Memory<BiquadFilterState> BiquadFilterState0 { get; }
|
||||
public Memory<BiquadFilterState> BiquadFilterState1 { get; }
|
||||
public Memory<BiquadFilterState> PreviousBiquadFilterState0 { get; }
|
||||
public Memory<BiquadFilterState> PreviousBiquadFilterState1 { get; }
|
||||
|
||||
public Memory<VoiceUpdateState> State { get; }
|
||||
public Memory<VoiceState> State { get; }
|
||||
|
||||
public int LastSampleIndex { get; }
|
||||
|
||||
@@ -44,9 +44,9 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
||||
uint inputBufferIndex,
|
||||
uint outputBufferIndex,
|
||||
int lastSampleIndex,
|
||||
Memory<VoiceUpdateState> state,
|
||||
ref BiquadFilterParameter filter0,
|
||||
ref BiquadFilterParameter filter1,
|
||||
Memory<VoiceState> state,
|
||||
ref BiquadFilterParameter2 filter0,
|
||||
ref BiquadFilterParameter2 filter1,
|
||||
Memory<BiquadFilterState> biquadFilterState0,
|
||||
Memory<BiquadFilterState> biquadFilterState1,
|
||||
Memory<BiquadFilterState> previousBiquadFilterState0,
|
||||
|
||||
@@ -14,13 +14,13 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
||||
|
||||
public uint EstimatedProcessingTime { get; set; }
|
||||
|
||||
private readonly BiquadFilterParameter[] _parameters;
|
||||
private readonly BiquadFilterParameter2[] _parameters;
|
||||
private readonly Memory<BiquadFilterState> _biquadFilterStates;
|
||||
private readonly int _inputBufferIndex;
|
||||
private readonly int _outputBufferIndex;
|
||||
private readonly bool[] _isInitialized;
|
||||
|
||||
public MultiTapBiquadFilterCommand(int baseIndex, ReadOnlySpan<BiquadFilterParameter> filters, Memory<BiquadFilterState> biquadFilterStateMemory, int inputBufferOffset, int outputBufferOffset, ReadOnlySpan<bool> isInitialized, int nodeId)
|
||||
public MultiTapBiquadFilterCommand(int baseIndex, ReadOnlySpan<BiquadFilterParameter2> filters, Memory<BiquadFilterState> biquadFilterStateMemory, int inputBufferOffset, int outputBufferOffset, ReadOnlySpan<bool> isInitialized, int nodeId)
|
||||
{
|
||||
_parameters = filters.ToArray();
|
||||
_biquadFilterStates = biquadFilterStateMemory;
|
||||
|
||||
@@ -2,7 +2,7 @@ using Ryujinx.Audio.Common;
|
||||
using Ryujinx.Audio.Renderer.Common;
|
||||
using Ryujinx.Audio.Renderer.Server.Voice;
|
||||
using System;
|
||||
using static Ryujinx.Audio.Renderer.Parameter.VoiceInParameter;
|
||||
using Ryujinx.Audio.Renderer.Parameter;
|
||||
using WaveBuffer = Ryujinx.Audio.Renderer.Common.WaveBuffer;
|
||||
|
||||
namespace Ryujinx.Audio.Renderer.Dsp.Command
|
||||
@@ -27,31 +27,33 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
||||
|
||||
public WaveBuffer[] WaveBuffers { get; }
|
||||
|
||||
public Memory<VoiceUpdateState> State { get; }
|
||||
public Memory<VoiceState> State { get; }
|
||||
public DecodingBehaviour DecodingBehaviour { get; }
|
||||
|
||||
public PcmFloatDataSourceCommandVersion1(ref VoiceState serverState, Memory<VoiceUpdateState> state, ushort outputBufferIndex, ushort channelIndex, int nodeId)
|
||||
public PcmFloatDataSourceCommandVersion1(ref VoiceInfo serverInfo, Memory<VoiceState> state, ushort outputBufferIndex, ushort channelIndex, int nodeId)
|
||||
{
|
||||
Enabled = true;
|
||||
NodeId = nodeId;
|
||||
|
||||
OutputBufferIndex = (ushort)(channelIndex + outputBufferIndex);
|
||||
SampleRate = serverState.SampleRate;
|
||||
SampleRate = serverInfo.SampleRate;
|
||||
ChannelIndex = channelIndex;
|
||||
ChannelCount = serverState.ChannelsCount;
|
||||
Pitch = serverState.Pitch;
|
||||
ChannelCount = serverInfo.ChannelsCount;
|
||||
Pitch = serverInfo.Pitch;
|
||||
|
||||
WaveBuffers = new WaveBuffer[Constants.VoiceWaveBufferCount];
|
||||
|
||||
Span<Server.Voice.WaveBuffer> waveBufferSpan = serverInfo.WaveBuffers.AsSpan();
|
||||
|
||||
for (int i = 0; i < WaveBuffers.Length; i++)
|
||||
{
|
||||
ref Server.Voice.WaveBuffer voiceWaveBuffer = ref serverState.WaveBuffers[i];
|
||||
ref Server.Voice.WaveBuffer voiceWaveBuffer = ref waveBufferSpan[i];
|
||||
|
||||
WaveBuffers[i] = voiceWaveBuffer.ToCommon(1);
|
||||
}
|
||||
|
||||
State = state;
|
||||
DecodingBehaviour = serverState.DecodingBehaviour;
|
||||
DecodingBehaviour = serverInfo.DecodingBehaviour;
|
||||
}
|
||||
|
||||
public void Process(CommandList context)
|
||||
|
||||
@@ -2,7 +2,7 @@ using Ryujinx.Audio.Common;
|
||||
using Ryujinx.Audio.Renderer.Common;
|
||||
using Ryujinx.Audio.Renderer.Server.Voice;
|
||||
using System;
|
||||
using static Ryujinx.Audio.Renderer.Parameter.VoiceInParameter;
|
||||
using Ryujinx.Audio.Renderer.Parameter;
|
||||
using WaveBuffer = Ryujinx.Audio.Renderer.Common.WaveBuffer;
|
||||
|
||||
namespace Ryujinx.Audio.Renderer.Dsp.Command
|
||||
@@ -27,31 +27,33 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
||||
|
||||
public WaveBuffer[] WaveBuffers { get; }
|
||||
|
||||
public Memory<VoiceUpdateState> State { get; }
|
||||
public Memory<VoiceState> State { get; }
|
||||
public DecodingBehaviour DecodingBehaviour { get; }
|
||||
|
||||
public PcmInt16DataSourceCommandVersion1(ref VoiceState serverState, Memory<VoiceUpdateState> state, ushort outputBufferIndex, ushort channelIndex, int nodeId)
|
||||
public PcmInt16DataSourceCommandVersion1(ref VoiceInfo serverInfo, Memory<VoiceState> state, ushort outputBufferIndex, ushort channelIndex, int nodeId)
|
||||
{
|
||||
Enabled = true;
|
||||
NodeId = nodeId;
|
||||
|
||||
OutputBufferIndex = (ushort)(channelIndex + outputBufferIndex);
|
||||
SampleRate = serverState.SampleRate;
|
||||
SampleRate = serverInfo.SampleRate;
|
||||
ChannelIndex = channelIndex;
|
||||
ChannelCount = serverState.ChannelsCount;
|
||||
Pitch = serverState.Pitch;
|
||||
ChannelCount = serverInfo.ChannelsCount;
|
||||
Pitch = serverInfo.Pitch;
|
||||
|
||||
WaveBuffers = new WaveBuffer[Constants.VoiceWaveBufferCount];
|
||||
|
||||
Span<Server.Voice.WaveBuffer> waveBufferSpan = serverInfo.WaveBuffers.AsSpan();
|
||||
|
||||
for (int i = 0; i < WaveBuffers.Length; i++)
|
||||
{
|
||||
ref Server.Voice.WaveBuffer voiceWaveBuffer = ref serverState.WaveBuffers[i];
|
||||
ref Server.Voice.WaveBuffer voiceWaveBuffer = ref waveBufferSpan[i];
|
||||
|
||||
WaveBuffers[i] = voiceWaveBuffer.ToCommon(1);
|
||||
}
|
||||
|
||||
State = state;
|
||||
DecodingBehaviour = serverState.DecodingBehaviour;
|
||||
DecodingBehaviour = serverInfo.DecodingBehaviour;
|
||||
}
|
||||
|
||||
public void Process(CommandList context)
|
||||
|
||||
@@ -65,11 +65,14 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
||||
|
||||
InputBufferIndices = new ushort[Constants.VoiceChannelCountMax];
|
||||
OutputBufferIndices = new ushort[Constants.VoiceChannelCountMax];
|
||||
|
||||
Span<byte> inputSpan = Parameter.Input.AsSpan();
|
||||
Span<byte> outputSpan = Parameter.Output.AsSpan();
|
||||
|
||||
for (int i = 0; i < Parameter.ChannelCount; i++)
|
||||
{
|
||||
InputBufferIndices[i] = (ushort)(bufferOffset + Parameter.Input[i]);
|
||||
OutputBufferIndices[i] = (ushort)(bufferOffset + Parameter.Output[i]);
|
||||
InputBufferIndices[i] = (ushort)(bufferOffset + inputSpan[i]);
|
||||
OutputBufferIndices[i] = (ushort)(bufferOffset + outputSpan[i]);
|
||||
}
|
||||
|
||||
// NOTE: We do the opposite as Nintendo here for now to restore previous behaviour
|
||||
|
||||
@@ -63,11 +63,14 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
||||
|
||||
InputBufferIndices = new ushort[Constants.VoiceChannelCountMax];
|
||||
OutputBufferIndices = new ushort[Constants.VoiceChannelCountMax];
|
||||
|
||||
Span<byte> inputSpan = Parameter.Input.AsSpan();
|
||||
Span<byte> outputSpan = Parameter.Output.AsSpan();
|
||||
|
||||
for (int i = 0; i < Parameter.ChannelCount; i++)
|
||||
{
|
||||
InputBufferIndices[i] = (ushort)(bufferOffset + Parameter.Input[i]);
|
||||
OutputBufferIndices[i] = (ushort)(bufferOffset + Parameter.Output[i]);
|
||||
InputBufferIndices[i] = (ushort)(bufferOffset + inputSpan[i]);
|
||||
OutputBufferIndices[i] = (ushort)(bufferOffset + outputSpan[i]);
|
||||
}
|
||||
|
||||
IsLongSizePreDelaySupported = isLongSizePreDelaySupported;
|
||||
|
||||
@@ -18,11 +18,11 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
||||
public uint InputSampleCount { get; }
|
||||
public uint InputSampleRate { get; }
|
||||
|
||||
public UpsamplerState UpsamplerInfo { get; }
|
||||
public UpsamplerInfo UpsamplerInfo { get; }
|
||||
|
||||
public Memory<float> OutBuffer { get; }
|
||||
|
||||
public UpsampleCommand(uint bufferOffset, UpsamplerState info, uint inputCount, Span<byte> inputBufferOffset, uint bufferCount, uint sampleCount, uint sampleRate, int nodeId)
|
||||
public UpsampleCommand(uint bufferOffset, UpsamplerInfo info, uint inputCount, Span<byte> inputBufferOffset, uint bufferCount, uint sampleCount, uint sampleRate, int nodeId)
|
||||
{
|
||||
Enabled = true;
|
||||
NodeId = nodeId;
|
||||
|
||||
@@ -10,7 +10,7 @@ using System.Runtime.InteropServices;
|
||||
using System.Runtime.Intrinsics;
|
||||
using System.Runtime.Intrinsics.Arm;
|
||||
using System.Runtime.Intrinsics.X86;
|
||||
using static Ryujinx.Audio.Renderer.Parameter.VoiceInParameter;
|
||||
using Ryujinx.Audio.Renderer.Parameter;
|
||||
|
||||
namespace Ryujinx.Audio.Renderer.Dsp
|
||||
{
|
||||
@@ -42,7 +42,7 @@ namespace Ryujinx.Audio.Renderer.Dsp
|
||||
};
|
||||
}
|
||||
|
||||
public static void ProcessWaveBuffers(IVirtualMemoryManager memoryManager, Span<float> outputBuffer, ref WaveBufferInformation info, Span<WaveBuffer> wavebuffers, ref VoiceUpdateState voiceState, uint targetSampleRate, int sampleCount)
|
||||
public static void ProcessWaveBuffers(IVirtualMemoryManager memoryManager, Span<float> outputBuffer, ref WaveBufferInformation info, Span<WaveBuffer> wavebuffers, ref VoiceState voiceState, uint targetSampleRate, int sampleCount)
|
||||
{
|
||||
const int TempBufferSize = 0x3F00;
|
||||
|
||||
@@ -74,7 +74,7 @@ namespace Ryujinx.Audio.Renderer.Dsp
|
||||
{
|
||||
int tempBufferIndex = 0;
|
||||
|
||||
if (!info.DecodingBehaviour.HasFlag(DecodingBehaviour.SkipPitchAndSampleRateConversion))
|
||||
if ((info.DecodingBehaviour & DecodingBehaviour.SkipPitchAndSampleRateConversion) != DecodingBehaviour.SkipPitchAndSampleRateConversion)
|
||||
{
|
||||
voiceState.Pitch.AsSpan()[..pitchMaxLength].CopyTo(tempBuffer);
|
||||
tempBufferIndex += pitchMaxLength;
|
||||
@@ -208,7 +208,7 @@ namespace Ryujinx.Audio.Renderer.Dsp
|
||||
break;
|
||||
}
|
||||
|
||||
if (info.DecodingBehaviour.HasFlag(DecodingBehaviour.PlayedSampleCountResetWhenLooping))
|
||||
if ((info.DecodingBehaviour & DecodingBehaviour.PlayedSampleCountResetWhenLooping) == DecodingBehaviour.PlayedSampleCountResetWhenLooping)
|
||||
{
|
||||
playedSampleCount = 0;
|
||||
}
|
||||
@@ -222,7 +222,7 @@ namespace Ryujinx.Audio.Renderer.Dsp
|
||||
|
||||
Span<int> outputSpanInt = MemoryMarshal.Cast<float, int>(outputBuffer[i..]);
|
||||
|
||||
if (info.DecodingBehaviour.HasFlag(DecodingBehaviour.SkipPitchAndSampleRateConversion))
|
||||
if ((info.DecodingBehaviour & DecodingBehaviour.SkipPitchAndSampleRateConversion) == DecodingBehaviour.SkipPitchAndSampleRateConversion)
|
||||
{
|
||||
for (int j = 0; j < y; j++)
|
||||
{
|
||||
|
||||
@@ -3,7 +3,7 @@ using System.Linq;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.Intrinsics;
|
||||
using System.Runtime.Intrinsics.X86;
|
||||
using static Ryujinx.Audio.Renderer.Parameter.VoiceInParameter;
|
||||
using Ryujinx.Audio.Renderer.Parameter;
|
||||
|
||||
namespace Ryujinx.Audio.Renderer.Dsp
|
||||
{
|
||||
|
||||
@@ -41,11 +41,12 @@ namespace Ryujinx.Audio.Renderer.Dsp
|
||||
}
|
||||
|
||||
Array20<float> result = new();
|
||||
Span<float> resultSpan = result.AsSpan();
|
||||
|
||||
for (int i = 0; i < FilterBankLength; i++)
|
||||
{
|
||||
float x = (Bank0CenterIndex - i) + offset;
|
||||
result[i] = Sinc(x) * BlackmanWindow(x / FilterBankLength + 0.5f);
|
||||
resultSpan[i] = Sinc(x) * BlackmanWindow(x / FilterBankLength + 0.5f);
|
||||
}
|
||||
|
||||
return result;
|
||||
@@ -78,6 +79,9 @@ namespace Ryujinx.Audio.Renderer.Dsp
|
||||
|
||||
Debug.Assert(state.History.Length == HistoryLength);
|
||||
Debug.Assert(bank.Length == FilterBankLength);
|
||||
|
||||
Span<float> bankSpan = bank.AsSpan();
|
||||
Span<float> historySpan = state.History.AsSpan();
|
||||
|
||||
int curIdx = 0;
|
||||
if (Vector.IsHardwareAccelerated)
|
||||
@@ -88,15 +92,15 @@ namespace Ryujinx.Audio.Renderer.Dsp
|
||||
while (curIdx < stopIdx)
|
||||
{
|
||||
result += Vector.Dot(
|
||||
new Vector<float>(bank.AsSpan().Slice(curIdx, Vector<float>.Count)),
|
||||
new Vector<float>(state.History.AsSpan().Slice(curIdx, Vector<float>.Count)));
|
||||
new Vector<float>(bankSpan[curIdx..(curIdx + Vector<float>.Count)]),
|
||||
new Vector<float>(historySpan[curIdx..(curIdx + Vector<float>.Count)]));
|
||||
curIdx += Vector<float>.Count;
|
||||
}
|
||||
}
|
||||
|
||||
while (curIdx < FilterBankLength)
|
||||
{
|
||||
result += bank[curIdx] * state.History[curIdx];
|
||||
result += bankSpan[curIdx] * historySpan[curIdx];
|
||||
curIdx++;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using Ryujinx.Audio.Renderer.Server;
|
||||
using Ryujinx.Audio.Renderer.Server.Types;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
@@ -93,7 +94,7 @@ namespace Ryujinx.Audio.Renderer.Parameter
|
||||
/// <summary>
|
||||
/// The user audio revision
|
||||
/// </summary>
|
||||
/// <seealso cref="Server.BehaviourContext"/>
|
||||
/// <seealso cref="BehaviourInfo"/>
|
||||
public int Revision;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ namespace Ryujinx.Audio.Renderer.Parameter
|
||||
/// Biquad filter parameters.
|
||||
/// </summary>
|
||||
[StructLayout(LayoutKind.Sequential, Size = 0xC, Pack = 1)]
|
||||
public struct BiquadFilterParameter
|
||||
public struct BiquadFilterParameter1
|
||||
{
|
||||
/// <summary>
|
||||
/// Set to true if the biquad filter is active.
|
||||
@@ -0,0 +1,36 @@
|
||||
using Ryujinx.Common.Memory;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Ryujinx.Audio.Renderer.Parameter
|
||||
{
|
||||
/// <summary>
|
||||
/// Biquad filter parameters.
|
||||
/// </summary>
|
||||
[StructLayout(LayoutKind.Sequential, Size = 0x18, Pack = 1)]
|
||||
public struct BiquadFilterParameter2
|
||||
{
|
||||
/// <summary>
|
||||
/// Set to true if the biquad filter is active.
|
||||
/// </summary>
|
||||
[MarshalAs(UnmanagedType.I1)]
|
||||
public bool Enable;
|
||||
|
||||
/// <summary>
|
||||
/// Reserved/padding.
|
||||
/// </summary>
|
||||
private readonly byte _reserved1;
|
||||
private readonly byte _reserved2;
|
||||
private readonly byte _reserved3;
|
||||
|
||||
/// <summary>
|
||||
/// Biquad filter numerator (b0, b1, b2).
|
||||
/// </summary>
|
||||
public Array3<float> Numerator;
|
||||
|
||||
/// <summary>
|
||||
/// Biquad filter denominator (a1, a2).
|
||||
/// </summary>
|
||||
/// <remarks>a0 = 1</remarks>
|
||||
public Array2<float> Denominator;
|
||||
}
|
||||
}
|
||||
@@ -8,7 +8,7 @@ namespace Ryujinx.Audio.Renderer.Parameter.Effect
|
||||
/// <see cref="IEffectInParameter.SpecificData"/> for <see cref="Common.EffectType.BiquadFilter"/>.
|
||||
/// </summary>
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
public struct BiquadFilterEffectParameter
|
||||
public struct BiquadFilterEffectParameter1
|
||||
{
|
||||
/// <summary>
|
||||
/// The input channel indices that will be used by the <see cref="Dsp.AudioProcessor"/>.
|
||||
@@ -0,0 +1,49 @@
|
||||
using Ryujinx.Audio.Renderer.Server.Effect;
|
||||
using Ryujinx.Common.Memory;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Ryujinx.Audio.Renderer.Parameter.Effect
|
||||
{
|
||||
/// <summary>
|
||||
/// <see cref="IEffectInParameter.SpecificData"/> for <see cref="Common.EffectType.BiquadFilter"/>.
|
||||
/// </summary>
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
public struct BiquadFilterEffectParameter2
|
||||
{
|
||||
/// <summary>
|
||||
/// The input channel indices that will be used by the <see cref="Dsp.AudioProcessor"/>.
|
||||
/// </summary>
|
||||
public Array6<byte> Input;
|
||||
|
||||
/// <summary>
|
||||
/// The output channel indices that will be used by the <see cref="Dsp.AudioProcessor"/>.
|
||||
/// </summary>
|
||||
public Array6<byte> Output;
|
||||
|
||||
/// <summary>
|
||||
/// Biquad filter numerator (b0, b1, b2).
|
||||
/// </summary>
|
||||
public Array3<float> Numerator;
|
||||
|
||||
/// <summary>
|
||||
/// Biquad filter denominator (a1, a2).
|
||||
/// </summary>
|
||||
/// <remarks>a0 = 1</remarks>
|
||||
public Array2<float> Denominator;
|
||||
|
||||
/// <summary>
|
||||
/// The total channel count used.
|
||||
/// </summary>
|
||||
public byte ChannelCount;
|
||||
|
||||
/// <summary>
|
||||
/// The current usage status of the effect on the client side.
|
||||
/// </summary>
|
||||
public UsageState Status;
|
||||
|
||||
/// <summary>
|
||||
/// Reserved/unused.
|
||||
/// </summary>
|
||||
private readonly ushort _reserved;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
using Ryujinx.Audio.Renderer.Common;
|
||||
using Ryujinx.Common.Utilities;
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Ryujinx.Audio.Renderer.Parameter
|
||||
{
|
||||
/// <summary>
|
||||
/// Input information for an effect version 2. (added with REV9)
|
||||
/// </summary>
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
public struct EffectInParameterVersion3 : IEffectInParameter
|
||||
{
|
||||
/// <summary>
|
||||
/// Type of the effect.
|
||||
/// </summary>
|
||||
public EffectType Type;
|
||||
|
||||
/// <summary>
|
||||
/// Set to true if the effect is new.
|
||||
/// </summary>
|
||||
[MarshalAs(UnmanagedType.I1)]
|
||||
public bool IsNew;
|
||||
|
||||
/// <summary>
|
||||
/// Set to true if the effect must be active.
|
||||
/// </summary>
|
||||
[MarshalAs(UnmanagedType.I1)]
|
||||
public bool IsEnabled;
|
||||
|
||||
/// <summary>
|
||||
/// Reserved/padding.
|
||||
/// </summary>
|
||||
private readonly byte _reserved1;
|
||||
|
||||
/// <summary>
|
||||
/// The target mix id of the effect.
|
||||
/// </summary>
|
||||
public int MixId;
|
||||
|
||||
/// <summary>
|
||||
/// Address of the processing workbuffer.
|
||||
/// </summary>
|
||||
/// <remarks>This is additional data that could be required by the effect processing.</remarks>
|
||||
public ulong BufferBase;
|
||||
|
||||
/// <summary>
|
||||
/// Size of the processing workbuffer.
|
||||
/// </summary>
|
||||
/// <remarks>This is additional data that could be required by the effect processing.</remarks>
|
||||
public ulong BufferSize;
|
||||
|
||||
/// <summary>
|
||||
/// Position of the effect while processing effects.
|
||||
/// </summary>
|
||||
public uint ProcessingOrder;
|
||||
|
||||
/// <summary>
|
||||
/// Reserved/padding.
|
||||
/// </summary>
|
||||
private readonly uint _reserved2;
|
||||
|
||||
/// <summary>
|
||||
/// Specific data storage.
|
||||
/// </summary>
|
||||
private SpecificDataStruct _specificDataStart;
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Size = 0xA0, Pack = 1)]
|
||||
private struct SpecificDataStruct { }
|
||||
|
||||
public Span<byte> SpecificData => SpanHelpers.AsSpan<SpecificDataStruct, byte>(ref _specificDataStart);
|
||||
|
||||
readonly EffectType IEffectInParameter.Type => Type;
|
||||
|
||||
readonly bool IEffectInParameter.IsNew => IsNew;
|
||||
|
||||
readonly bool IEffectInParameter.IsEnabled => IsEnabled;
|
||||
|
||||
readonly int IEffectInParameter.MixId => MixId;
|
||||
|
||||
readonly ulong IEffectInParameter.BufferBase => BufferBase;
|
||||
|
||||
readonly ulong IEffectInParameter.BufferSize => BufferSize;
|
||||
|
||||
readonly uint IEffectInParameter.ProcessingOrder => ProcessingOrder;
|
||||
|
||||
/// <summary>
|
||||
/// Check if the given channel count is valid.
|
||||
/// </summary>
|
||||
/// <param name="channelCount">The channel count to check</param>
|
||||
/// <returns>Returns true if the channel count is valid.</returns>
|
||||
public static bool IsChannelCountValid(int channelCount)
|
||||
{
|
||||
return channelCount is 1 or 2 or 4 or 6;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -17,11 +17,11 @@ namespace Ryujinx.Audio.Renderer.Parameter
|
||||
/// The mix to output the result of the splitter.
|
||||
/// </summary>
|
||||
int DestinationId { get; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Biquad filter parameters.
|
||||
/// </summary>
|
||||
Array2<BiquadFilterParameter> BiquadFilters { get; }
|
||||
Array2<BiquadFilterParameter2> BiquadFilters2 { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Set to true if in use.
|
||||
|
||||
@@ -25,7 +25,7 @@ namespace Ryujinx.Audio.Renderer.Parameter
|
||||
/// <summary>
|
||||
/// Reserved/padding.
|
||||
/// </summary>
|
||||
private readonly ushort _reserved1;
|
||||
private readonly ushort _magic; // 0xCAFE
|
||||
|
||||
/// <summary>
|
||||
/// The node id of the sink.
|
||||
|
||||
@@ -60,8 +60,8 @@ namespace Ryujinx.Audio.Renderer.Parameter
|
||||
readonly int ISplitterDestinationInParameter.Id => Id;
|
||||
|
||||
readonly int ISplitterDestinationInParameter.DestinationId => DestinationId;
|
||||
|
||||
readonly Array2<BiquadFilterParameter> ISplitterDestinationInParameter.BiquadFilters => default;
|
||||
|
||||
readonly Array2<BiquadFilterParameter2> ISplitterDestinationInParameter.BiquadFilters2 => default;
|
||||
|
||||
readonly bool ISplitterDestinationInParameter.IsUsed => IsUsed;
|
||||
readonly bool ISplitterDestinationInParameter.ResetPrevVolume => ResetPrevVolume;
|
||||
|
||||
@@ -0,0 +1,100 @@
|
||||
using Ryujinx.Audio.Renderer.Dsp;
|
||||
using Ryujinx.Common.Memory;
|
||||
using Ryujinx.Common.Utilities;
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Ryujinx.Audio.Renderer.Parameter
|
||||
{
|
||||
/// <summary>
|
||||
/// Input header for a splitter destination version 2 update.
|
||||
/// </summary>
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
public struct SplitterDestinationInParameterVersion2a : ISplitterDestinationInParameter
|
||||
{
|
||||
/// <summary>
|
||||
/// Magic of the input header.
|
||||
/// </summary>
|
||||
public uint Magic;
|
||||
|
||||
/// <summary>
|
||||
/// Target splitter destination data id.
|
||||
/// </summary>
|
||||
public int Id;
|
||||
|
||||
/// <summary>
|
||||
/// Mix buffer volumes storage.
|
||||
/// </summary>
|
||||
private MixArray _mixBufferVolume;
|
||||
|
||||
/// <summary>
|
||||
/// The mix to output the result of the splitter.
|
||||
/// </summary>
|
||||
public int DestinationId;
|
||||
|
||||
/// <summary>
|
||||
/// Biquad filter parameters.
|
||||
/// </summary>
|
||||
public Array2<BiquadFilterParameter1> BiquadFilters;
|
||||
|
||||
/// <summary>
|
||||
/// Set to true if in use.
|
||||
/// </summary>
|
||||
[MarshalAs(UnmanagedType.I1)]
|
||||
public bool IsUsed;
|
||||
|
||||
/// <summary>
|
||||
/// Set to true to force resetting the previous mix volumes.
|
||||
/// </summary>
|
||||
[MarshalAs(UnmanagedType.I1)]
|
||||
public bool ResetPrevVolume;
|
||||
|
||||
/// <summary>
|
||||
/// Reserved/padding.
|
||||
/// </summary>
|
||||
private unsafe fixed byte _reserved[10];
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Size = sizeof(float) * Constants.MixBufferCountMax, Pack = 1)]
|
||||
private struct MixArray { }
|
||||
|
||||
/// <summary>
|
||||
/// Mix buffer volumes.
|
||||
/// </summary>
|
||||
/// <remarks>Used when a splitter id is specified in the mix.</remarks>
|
||||
public Span<float> MixBufferVolume => SpanHelpers.AsSpan<MixArray, float>(ref _mixBufferVolume);
|
||||
|
||||
readonly int ISplitterDestinationInParameter.Id => Id;
|
||||
|
||||
readonly int ISplitterDestinationInParameter.DestinationId => DestinationId;
|
||||
|
||||
readonly Array2<BiquadFilterParameter2> ISplitterDestinationInParameter.BiquadFilters2
|
||||
{
|
||||
get
|
||||
{
|
||||
Array2<BiquadFilterParameter2> newFilters = new();
|
||||
Span<BiquadFilterParameter2> newFiltersSpan = newFilters.AsSpan();
|
||||
newFiltersSpan[0] = BiquadFilterHelper.ToBiquadFilterParameter2(BiquadFilters[0]);
|
||||
newFiltersSpan[1] = BiquadFilterHelper.ToBiquadFilterParameter2(BiquadFilters[1]);
|
||||
|
||||
return newFilters;
|
||||
}
|
||||
}
|
||||
|
||||
readonly bool ISplitterDestinationInParameter.IsUsed => IsUsed;
|
||||
readonly bool ISplitterDestinationInParameter.ResetPrevVolume => ResetPrevVolume;
|
||||
|
||||
/// <summary>
|
||||
/// The expected constant of any input header.
|
||||
/// </summary>
|
||||
private const uint ValidMagic = 0x44444E53;
|
||||
|
||||
/// <summary>
|
||||
/// Check if the magic is valid.
|
||||
/// </summary>
|
||||
/// <returns>Returns true if the magic is valid.</returns>
|
||||
public readonly bool IsMagicValid()
|
||||
{
|
||||
return Magic == ValidMagic;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -9,7 +9,7 @@ namespace Ryujinx.Audio.Renderer.Parameter
|
||||
/// Input header for a splitter destination version 2 update.
|
||||
/// </summary>
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
public struct SplitterDestinationInParameterVersion2 : ISplitterDestinationInParameter
|
||||
public struct SplitterDestinationInParameterVersion2b : ISplitterDestinationInParameter
|
||||
{
|
||||
/// <summary>
|
||||
/// Magic of the input header.
|
||||
@@ -34,7 +34,7 @@ namespace Ryujinx.Audio.Renderer.Parameter
|
||||
/// <summary>
|
||||
/// Biquad filter parameters.
|
||||
/// </summary>
|
||||
public Array2<BiquadFilterParameter> BiquadFilters;
|
||||
public Array2<BiquadFilterParameter2> BiquadFilters;
|
||||
|
||||
/// <summary>
|
||||
/// Set to true if in use.
|
||||
@@ -66,7 +66,7 @@ namespace Ryujinx.Audio.Renderer.Parameter
|
||||
|
||||
readonly int ISplitterDestinationInParameter.DestinationId => DestinationId;
|
||||
|
||||
readonly Array2<BiquadFilterParameter> ISplitterDestinationInParameter.BiquadFilters => BiquadFilters;
|
||||
readonly Array2<BiquadFilterParameter2> ISplitterDestinationInParameter.BiquadFilters2 => BiquadFilters;
|
||||
|
||||
readonly bool ISplitterDestinationInParameter.IsUsed => IsUsed;
|
||||
readonly bool ISplitterDestinationInParameter.ResetPrevVolume => ResetPrevVolume;
|
||||
@@ -12,7 +12,7 @@ namespace Ryujinx.Audio.Renderer.Parameter
|
||||
/// Input information for a voice.
|
||||
/// </summary>
|
||||
[StructLayout(LayoutKind.Sequential, Size = 0x170, Pack = 1)]
|
||||
public struct VoiceInParameter
|
||||
public struct VoiceInParameter1
|
||||
{
|
||||
/// <summary>
|
||||
/// Id of the voice.
|
||||
@@ -79,7 +79,7 @@ namespace Ryujinx.Audio.Renderer.Parameter
|
||||
/// <summary>
|
||||
/// Biquad filters to apply to the output of the voice.
|
||||
/// </summary>
|
||||
public Array2<BiquadFilterParameter> BiquadFilters;
|
||||
public Array2<BiquadFilterParameter1> BiquadFilters;
|
||||
|
||||
/// <summary>
|
||||
/// Total count of <see cref="WaveBufferInternal"/> of the voice.
|
||||
@@ -171,8 +171,9 @@ namespace Ryujinx.Audio.Renderer.Parameter
|
||||
/// Reserved/unused.
|
||||
/// </summary>
|
||||
private unsafe fixed uint _reserved3[2];
|
||||
|
||||
/// <summary>
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Input information for a voice wavebuffer.
|
||||
/// </summary>
|
||||
[StructLayout(LayoutKind.Sequential, Size = 0x38, Pack = 1)]
|
||||
@@ -328,5 +329,4 @@ namespace Ryujinx.Audio.Renderer.Parameter
|
||||
/// </summary>
|
||||
Low,
|
||||
}
|
||||
}
|
||||
}
|
||||
176
src/Ryujinx.Audio/Renderer/Parameter/VoiceInParameter2.cs
Normal file
176
src/Ryujinx.Audio/Renderer/Parameter/VoiceInParameter2.cs
Normal file
@@ -0,0 +1,176 @@
|
||||
using Ryujinx.Audio.Common;
|
||||
using Ryujinx.Audio.Renderer.Common;
|
||||
using Ryujinx.Audio.Renderer.Dsp;
|
||||
using Ryujinx.Common.Memory;
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Ryujinx.Audio.Renderer.Parameter
|
||||
{
|
||||
/// <summary>
|
||||
/// Input information for a voice.
|
||||
/// </summary>
|
||||
[StructLayout(LayoutKind.Sequential, Size = 0x188, Pack = 1)]
|
||||
public struct VoiceInParameter2
|
||||
{
|
||||
/// <summary>
|
||||
/// Id of the voice.
|
||||
/// </summary>
|
||||
public int Id;
|
||||
|
||||
/// <summary>
|
||||
/// Node id of the voice.
|
||||
/// </summary>
|
||||
public int NodeId;
|
||||
|
||||
/// <summary>
|
||||
/// Set to true if the voice is new.
|
||||
/// </summary>
|
||||
[MarshalAs(UnmanagedType.I1)]
|
||||
public bool IsNew;
|
||||
|
||||
/// <summary>
|
||||
/// Set to true if the voice is used.
|
||||
/// </summary>
|
||||
[MarshalAs(UnmanagedType.I1)]
|
||||
public bool InUse;
|
||||
|
||||
/// <summary>
|
||||
/// The voice <see cref="PlayState"/> wanted by the user.
|
||||
/// </summary>
|
||||
public PlayState PlayState;
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="SampleFormat"/> of the voice.
|
||||
/// </summary>
|
||||
public SampleFormat SampleFormat;
|
||||
|
||||
/// <summary>
|
||||
/// The sample rate of the voice.
|
||||
/// </summary>
|
||||
public uint SampleRate;
|
||||
|
||||
/// <summary>
|
||||
/// The priority of the voice.
|
||||
/// </summary>
|
||||
public uint Priority;
|
||||
|
||||
/// <summary>
|
||||
/// Target sorting position of the voice. (Used to sort voices with the same <see cref="Priority"/>)
|
||||
/// </summary>
|
||||
public uint SortingOrder;
|
||||
|
||||
/// <summary>
|
||||
/// The total channel count used.
|
||||
/// </summary>
|
||||
public uint ChannelCount;
|
||||
|
||||
/// <summary>
|
||||
/// The pitch used on the voice.
|
||||
/// </summary>
|
||||
public float Pitch;
|
||||
|
||||
/// <summary>
|
||||
/// The output volume of the voice.
|
||||
/// </summary>
|
||||
public float Volume;
|
||||
|
||||
/// <summary>
|
||||
/// Biquad filters to apply to the output of the voice.
|
||||
/// </summary>
|
||||
public Array2<BiquadFilterParameter2> BiquadFilters;
|
||||
|
||||
/// <summary>
|
||||
/// Total count of <see cref="WaveBufferInternal"/> of the voice.
|
||||
/// </summary>
|
||||
public uint WaveBuffersCount;
|
||||
|
||||
/// <summary>
|
||||
/// Current playing <see cref="WaveBufferInternal"/> of the voice.
|
||||
/// </summary>
|
||||
public uint WaveBuffersIndex;
|
||||
|
||||
/// <summary>
|
||||
/// Reserved/unused.
|
||||
/// </summary>
|
||||
private readonly uint
|
||||
_reserved1;
|
||||
|
||||
/// <summary>
|
||||
/// User state address required by the data source.
|
||||
/// </summary>
|
||||
/// <remarks>Only used for <see cref="SampleFormat.Adpcm"/> as the address of the GC-ADPCM coefficients.</remarks>
|
||||
public ulong DataSourceStateAddress;
|
||||
|
||||
/// <summary>
|
||||
/// User state size required by the data source.
|
||||
/// </summary>
|
||||
/// <remarks>Only used for <see cref="SampleFormat.Adpcm"/> as the size of the GC-ADPCM coefficients.</remarks>
|
||||
public ulong DataSourceStateSize;
|
||||
|
||||
/// <summary>
|
||||
/// The target mix id of the voice.
|
||||
/// </summary>
|
||||
public int MixId;
|
||||
|
||||
/// <summary>
|
||||
/// The target splitter id of the voice.
|
||||
/// </summary>
|
||||
public uint SplitterId;
|
||||
|
||||
/// <summary>
|
||||
/// The wavebuffer parameters of this voice.
|
||||
/// </summary>
|
||||
public Array4<WaveBufferInternal> WaveBuffers;
|
||||
|
||||
/// <summary>
|
||||
/// The channel resource ids associated to the voice.
|
||||
/// </summary>
|
||||
public Array6<int> ChannelResourceIds;
|
||||
|
||||
/// <summary>
|
||||
/// Reset the voice drop flag during voice server update.
|
||||
/// </summary>
|
||||
[MarshalAs(UnmanagedType.I1)]
|
||||
public bool ResetVoiceDropFlag;
|
||||
|
||||
/// <summary>
|
||||
/// Flush the amount of wavebuffer specified. This will result in the wavebuffer being skipped and marked played.
|
||||
/// </summary>
|
||||
/// <remarks>This was added on REV5.</remarks>
|
||||
public byte FlushWaveBufferCount;
|
||||
|
||||
/// <summary>
|
||||
/// Reserved/unused.
|
||||
/// </summary>
|
||||
private readonly ushort _reserved2;
|
||||
|
||||
/// <summary>
|
||||
/// Change the behaviour of the voice.
|
||||
/// </summary>
|
||||
/// <remarks>This was added on REV5.</remarks>
|
||||
public DecodingBehaviour DecodingBehaviourFlags;
|
||||
|
||||
/// <summary>
|
||||
/// Change the Sample Rate Conversion (SRC) quality of the voice.
|
||||
/// </summary>
|
||||
/// <remarks>This was added on REV8.</remarks>
|
||||
public SampleRateConversionQuality SrcQuality;
|
||||
|
||||
/// <summary>
|
||||
/// This was previously used for opus codec support on the Audio Renderer and was removed on REV3.
|
||||
/// </summary>
|
||||
public uint ExternalContext;
|
||||
|
||||
/// <summary>
|
||||
/// This was previously used for opus codec support on the Audio Renderer and was removed on REV3.
|
||||
/// </summary>
|
||||
public uint ExternalContextSize;
|
||||
|
||||
/// <summary>
|
||||
/// Reserved/unused.
|
||||
/// </summary>
|
||||
private unsafe fixed uint _reserved3[2];
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,5 @@
|
||||
using Ryujinx.Audio.Renderer.Common;
|
||||
using Ryujinx.Audio.Renderer.Server;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Ryujinx.Audio.Renderer.Parameter
|
||||
@@ -5,7 +7,7 @@ namespace Ryujinx.Audio.Renderer.Parameter
|
||||
/// <summary>
|
||||
/// Output information about a voice.
|
||||
/// </summary>
|
||||
/// <remarks>See <seealso cref="Server.StateUpdater.UpdateVoices(Server.Voice.VoiceContext, System.Memory{Server.MemoryPool.MemoryPoolState})"/></remarks>
|
||||
/// <remarks>See <seealso cref="StateUpdater.UpdateVoices1"/></remarks>
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
public struct VoiceOutStatus
|
||||
{
|
||||
@@ -13,7 +15,7 @@ namespace Ryujinx.Audio.Renderer.Parameter
|
||||
/// The total amount of samples that was played.
|
||||
/// </summary>
|
||||
/// <remarks>This is reset to 0 when a <see cref="Common.WaveBuffer"/> finishes playing and <see cref="Common.WaveBuffer.IsEndOfStream"/> is set.</remarks>
|
||||
/// <remarks>This is reset to 0 when looping while <see cref="Parameter.VoiceInParameter.DecodingBehaviour.PlayedSampleCountResetWhenLooping"/> is set.</remarks>
|
||||
/// <remarks>This is reset to 0 when looping while <see cref="DecodingBehaviour.PlayedSampleCountResetWhenLooping"/> is set.</remarks>
|
||||
public ulong PlayedSampleCount;
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -31,7 +31,7 @@ namespace Ryujinx.Audio.Renderer.Server
|
||||
private AudioRendererRenderingDevice _renderingDevice;
|
||||
private AudioRendererExecutionMode _executionMode;
|
||||
private readonly IWritableEvent _systemEvent;
|
||||
private MemoryPoolState _dspMemoryPoolState;
|
||||
private MemoryPoolInfo _dspMemoryPoolInfo;
|
||||
private readonly VoiceContext _voiceContext;
|
||||
private readonly MixContext _mixContext;
|
||||
private readonly SinkContext _sinkContext;
|
||||
@@ -40,13 +40,13 @@ namespace Ryujinx.Audio.Renderer.Server
|
||||
private PerformanceManager _performanceManager;
|
||||
private UpsamplerManager _upsamplerManager;
|
||||
private bool _isActive;
|
||||
private BehaviourContext _behaviourContext;
|
||||
|
||||
private BehaviourInfo _behaviourInfo;
|
||||
#pragma warning disable IDE0052 // Remove unread private member
|
||||
private ulong _totalElapsedTicksUpdating;
|
||||
private ulong _totalElapsedTicks;
|
||||
|
||||
#pragma warning restore IDE0052
|
||||
private int _sessionId;
|
||||
private Memory<MemoryPoolState> _memoryPools;
|
||||
private Memory<MemoryPoolInfo> _memoryPools;
|
||||
|
||||
private uint _sampleRate;
|
||||
private uint _sampleCount;
|
||||
@@ -84,7 +84,7 @@ namespace Ryujinx.Audio.Renderer.Server
|
||||
public AudioRenderSystem(AudioRendererManager manager, IWritableEvent systemEvent)
|
||||
{
|
||||
_manager = manager;
|
||||
_dspMemoryPoolState = MemoryPoolState.Create(MemoryPoolState.LocationType.Dsp);
|
||||
_dspMemoryPoolInfo = MemoryPoolInfo.Create(MemoryPoolInfo.LocationType.Dsp);
|
||||
_voiceContext = new VoiceContext();
|
||||
_mixContext = new MixContext();
|
||||
_sinkContext = new SinkContext();
|
||||
@@ -93,7 +93,7 @@ namespace Ryujinx.Audio.Renderer.Server
|
||||
|
||||
_commandProcessingTimeEstimator = null;
|
||||
_systemEvent = systemEvent;
|
||||
_behaviourContext = new BehaviourContext();
|
||||
_behaviourInfo = new BehaviourInfo();
|
||||
|
||||
_totalElapsedTicksUpdating = 0;
|
||||
_sessionId = 0;
|
||||
@@ -110,7 +110,7 @@ namespace Ryujinx.Audio.Renderer.Server
|
||||
ulong appletResourceId,
|
||||
IVirtualMemoryManager memoryManager)
|
||||
{
|
||||
if (!BehaviourContext.CheckValidRevision(parameter.Revision))
|
||||
if (!BehaviourInfo.CheckValidRevision(parameter.Revision))
|
||||
{
|
||||
return ResultCode.OperationFailed;
|
||||
}
|
||||
@@ -122,9 +122,9 @@ namespace Ryujinx.Audio.Renderer.Server
|
||||
|
||||
Debug.Assert(parameter.RenderingDevice == AudioRendererRenderingDevice.Dsp && parameter.ExecutionMode == AudioRendererExecutionMode.Auto);
|
||||
|
||||
Logger.Info?.Print(LogClass.AudioRenderer, $"Initializing with REV{BehaviourContext.GetRevisionNumber(parameter.Revision)}");
|
||||
Logger.Info?.Print(LogClass.AudioRenderer, $"Initializing with REV{BehaviourInfo.GetRevisionNumber(parameter.Revision)}");
|
||||
|
||||
_behaviourContext.SetUserRevision(parameter.Revision);
|
||||
_behaviourInfo.SetUserRevision(parameter.Revision);
|
||||
|
||||
_sampleRate = parameter.SampleRate;
|
||||
_sampleCount = parameter.SampleCount;
|
||||
@@ -151,7 +151,7 @@ namespace Ryujinx.Audio.Renderer.Server
|
||||
workBufferAllocator = new WorkBufferAllocator(workBufferMemory);
|
||||
|
||||
PoolMapper poolMapper = new(processHandle, false);
|
||||
poolMapper.InitializeSystemPool(ref _dspMemoryPoolState, workBuffer, workBufferSize);
|
||||
poolMapper.InitializeSystemPool(ref _dspMemoryPoolInfo, workBuffer, workBufferSize);
|
||||
|
||||
_mixBuffer = workBufferAllocator.Allocate<float>(_sampleCount * (_voiceChannelCountMax + _mixBufferCount), 0x10);
|
||||
|
||||
@@ -176,7 +176,7 @@ namespace Ryujinx.Audio.Renderer.Server
|
||||
|
||||
Memory<BiquadFilterState> splitterBqfStates = Memory<BiquadFilterState>.Empty;
|
||||
|
||||
if (_behaviourContext.IsBiquadFilterParameterForSplitterEnabled() &&
|
||||
if (_behaviourInfo.IsBiquadFilterParameterForSplitterEnabled() &&
|
||||
parameter.SplitterCount > 0 &&
|
||||
parameter.SplitterDestinationCount > 0)
|
||||
{
|
||||
@@ -191,23 +191,23 @@ namespace Ryujinx.Audio.Renderer.Server
|
||||
}
|
||||
|
||||
// Invalidate DSP cache on what was currently allocated with workBuffer.
|
||||
AudioProcessorMemoryManager.InvalidateDspCache(_dspMemoryPoolState.Translate(workBuffer, workBufferAllocator.Offset), workBufferAllocator.Offset);
|
||||
AudioProcessorMemoryManager.InvalidateDspCache(_dspMemoryPoolInfo.Translate(workBuffer, workBufferAllocator.Offset), workBufferAllocator.Offset);
|
||||
|
||||
Debug.Assert((workBufferAllocator.Offset % Constants.BufferAlignment) == 0);
|
||||
|
||||
Memory<VoiceState> voices = workBufferAllocator.Allocate<VoiceState>(parameter.VoiceCount, VoiceState.Alignment);
|
||||
Memory<VoiceInfo> voices = workBufferAllocator.Allocate<VoiceInfo>(parameter.VoiceCount, VoiceInfo.Alignment);
|
||||
|
||||
if (voices.IsEmpty)
|
||||
{
|
||||
return ResultCode.WorkBufferTooSmall;
|
||||
}
|
||||
|
||||
foreach (ref VoiceState voice in voices.Span)
|
||||
foreach (ref VoiceInfo voice in voices.Span)
|
||||
{
|
||||
voice.Initialize();
|
||||
}
|
||||
|
||||
// A pain to handle as we can't have VoiceState*, use indices to be a bit more safe
|
||||
// A pain to handle as we can't have VoiceInfo*, use indices to be a bit more safe
|
||||
Memory<int> sortedVoices = workBufferAllocator.Allocate<int>(parameter.VoiceCount, 0x10);
|
||||
|
||||
if (sortedVoices.IsEmpty)
|
||||
@@ -233,16 +233,16 @@ namespace Ryujinx.Audio.Renderer.Server
|
||||
voiceChannelResource.IsUsed = false;
|
||||
}
|
||||
|
||||
Memory<VoiceUpdateState> voiceUpdateStates = workBufferAllocator.Allocate<VoiceUpdateState>(parameter.VoiceCount, VoiceUpdateState.Align);
|
||||
Memory<VoiceState> voiceStates = workBufferAllocator.Allocate<VoiceState>(parameter.VoiceCount, VoiceState.Align);
|
||||
|
||||
if (voiceUpdateStates.IsEmpty)
|
||||
if (voiceStates.IsEmpty)
|
||||
{
|
||||
return ResultCode.WorkBufferTooSmall;
|
||||
}
|
||||
|
||||
uint mixesCount = parameter.SubMixBufferCount + 1;
|
||||
|
||||
Memory<MixState> mixes = workBufferAllocator.Allocate<MixState>(mixesCount, MixState.Alignment);
|
||||
Memory<MixInfo> mixes = workBufferAllocator.Allocate<MixInfo>(mixesCount, MixInfo.Alignment);
|
||||
|
||||
if (mixes.IsEmpty)
|
||||
{
|
||||
@@ -251,18 +251,18 @@ namespace Ryujinx.Audio.Renderer.Server
|
||||
|
||||
if (parameter.EffectCount == 0)
|
||||
{
|
||||
foreach (ref MixState mix in mixes.Span)
|
||||
foreach (ref MixInfo mix in mixes.Span)
|
||||
{
|
||||
mix = new MixState(Memory<int>.Empty, ref _behaviourContext);
|
||||
mix = new MixInfo(Memory<int>.Empty, ref _behaviourInfo);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Memory<int> effectProcessingOrderArray = workBufferAllocator.Allocate<int>(parameter.EffectCount * mixesCount, 0x10);
|
||||
|
||||
foreach (ref MixState mix in mixes.Span)
|
||||
foreach (ref MixInfo mix in mixes.Span)
|
||||
{
|
||||
mix = new MixState(effectProcessingOrderArray[..(int)parameter.EffectCount], ref _behaviourContext);
|
||||
mix = new MixInfo(effectProcessingOrderArray[..(int)parameter.EffectCount], ref _behaviourInfo);
|
||||
|
||||
effectProcessingOrderArray = effectProcessingOrderArray[(int)parameter.EffectCount..];
|
||||
}
|
||||
@@ -271,20 +271,20 @@ namespace Ryujinx.Audio.Renderer.Server
|
||||
// Initialize the final mix id
|
||||
mixes.Span[0].MixId = Constants.FinalMixId;
|
||||
|
||||
Memory<int> sortedMixesState = workBufferAllocator.Allocate<int>(mixesCount, 0x10);
|
||||
Memory<int> sortedMixesInfo = workBufferAllocator.Allocate<int>(mixesCount, 0x10);
|
||||
|
||||
if (sortedMixesState.IsEmpty)
|
||||
if (sortedMixesInfo.IsEmpty)
|
||||
{
|
||||
return ResultCode.WorkBufferTooSmall;
|
||||
}
|
||||
|
||||
// Clear memory (use -1 as it's an invalid index)
|
||||
sortedMixesState.Span.Fill(-1);
|
||||
sortedMixesInfo.Span.Fill(-1);
|
||||
|
||||
Memory<byte> nodeStatesWorkBuffer = Memory<byte>.Empty;
|
||||
Memory<byte> edgeMatrixWorkBuffer = Memory<byte>.Empty;
|
||||
|
||||
if (_behaviourContext.IsSplitterSupported())
|
||||
if (_behaviourInfo.IsSplitterSupported())
|
||||
{
|
||||
nodeStatesWorkBuffer = workBufferAllocator.Allocate((uint)NodeStates.GetWorkBufferSize((int)mixesCount), 1);
|
||||
edgeMatrixWorkBuffer = workBufferAllocator.Allocate((uint)EdgeMatrix.GetWorkBufferSize((int)mixesCount), 1);
|
||||
@@ -295,21 +295,21 @@ namespace Ryujinx.Audio.Renderer.Server
|
||||
}
|
||||
}
|
||||
|
||||
_mixContext.Initialize(sortedMixesState, mixes, nodeStatesWorkBuffer, edgeMatrixWorkBuffer);
|
||||
_mixContext.Initialize(sortedMixesInfo, mixes, nodeStatesWorkBuffer, edgeMatrixWorkBuffer);
|
||||
|
||||
_memoryPools = workBufferAllocator.Allocate<MemoryPoolState>(_memoryPoolCount, MemoryPoolState.Alignment);
|
||||
_memoryPools = workBufferAllocator.Allocate<MemoryPoolInfo>(_memoryPoolCount, MemoryPoolInfo.Alignment);
|
||||
|
||||
if (_memoryPools.IsEmpty)
|
||||
{
|
||||
return ResultCode.WorkBufferTooSmall;
|
||||
}
|
||||
|
||||
foreach (ref MemoryPoolState state in _memoryPools.Span)
|
||||
foreach (ref MemoryPoolInfo info in _memoryPools.Span)
|
||||
{
|
||||
state = MemoryPoolState.Create(MemoryPoolState.LocationType.Cpu);
|
||||
info = MemoryPoolInfo.Create(MemoryPoolInfo.LocationType.Cpu);
|
||||
}
|
||||
|
||||
if (!_splitterContext.Initialize(ref _behaviourContext, ref parameter, workBufferAllocator, splitterBqfStates))
|
||||
if (!_splitterContext.Initialize(ref _behaviourInfo, ref parameter, workBufferAllocator, splitterBqfStates))
|
||||
{
|
||||
return ResultCode.WorkBufferTooSmall;
|
||||
}
|
||||
@@ -318,21 +318,21 @@ namespace Ryujinx.Audio.Renderer.Server
|
||||
|
||||
_upsamplerManager = new UpsamplerManager(upSamplerWorkBuffer, _upsamplerCount);
|
||||
|
||||
_effectContext.Initialize(parameter.EffectCount, _behaviourContext.IsEffectInfoVersion2Supported() ? parameter.EffectCount : 0);
|
||||
_effectContext.Initialize(parameter.EffectCount, _behaviourInfo.IsEffectInfoVersion2Supported() ? parameter.EffectCount : 0);
|
||||
_sinkContext.Initialize(parameter.SinkCount);
|
||||
|
||||
Memory<VoiceUpdateState> voiceUpdateStatesDsp = workBufferAllocator.Allocate<VoiceUpdateState>(parameter.VoiceCount, VoiceUpdateState.Align);
|
||||
Memory<VoiceState> voiceStatesDsp = workBufferAllocator.Allocate<VoiceState>(parameter.VoiceCount, VoiceState.Align);
|
||||
|
||||
if (voiceUpdateStatesDsp.IsEmpty)
|
||||
if (voiceStatesDsp.IsEmpty)
|
||||
{
|
||||
return ResultCode.WorkBufferTooSmall;
|
||||
}
|
||||
|
||||
_voiceContext.Initialize(sortedVoices, voices, voiceChannelResources, voiceUpdateStates, voiceUpdateStatesDsp, parameter.VoiceCount);
|
||||
_voiceContext.Initialize(sortedVoices, voices, voiceChannelResources, voiceStates, voiceStatesDsp, parameter.VoiceCount);
|
||||
|
||||
if (parameter.PerformanceMetricFramesCount > 0)
|
||||
{
|
||||
ulong performanceBufferSize = PerformanceManager.GetRequiredBufferSizeForPerformanceMetricsPerFrame(ref parameter, ref _behaviourContext) * (parameter.PerformanceMetricFramesCount + 1) + 0xC;
|
||||
ulong performanceBufferSize = PerformanceManager.GetRequiredBufferSizeForPerformanceMetricsPerFrame(ref parameter, ref _behaviourInfo) * (parameter.PerformanceMetricFramesCount + 1) + 0xC;
|
||||
|
||||
_performanceBuffer = workBufferAllocator.Allocate(performanceBufferSize, Constants.BufferAlignment);
|
||||
|
||||
@@ -341,7 +341,7 @@ namespace Ryujinx.Audio.Renderer.Server
|
||||
return ResultCode.WorkBufferTooSmall;
|
||||
}
|
||||
|
||||
_performanceManager = PerformanceManager.Create(_performanceBuffer, ref parameter, _behaviourContext);
|
||||
_performanceManager = PerformanceManager.Create(_performanceBuffer, ref parameter, _behaviourInfo);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -359,14 +359,14 @@ namespace Ryujinx.Audio.Renderer.Server
|
||||
_elapsedFrameCount = 0;
|
||||
_voiceDropParameter = 1.0f;
|
||||
|
||||
_commandProcessingTimeEstimator = _behaviourContext.GetCommandProcessingTimeEstimatorVersion() switch
|
||||
_commandProcessingTimeEstimator = _behaviourInfo.GetCommandProcessingTimeEstimatorVersion() switch
|
||||
{
|
||||
1 => new CommandProcessingTimeEstimatorVersion1(_sampleCount, _mixBufferCount),
|
||||
2 => new CommandProcessingTimeEstimatorVersion2(_sampleCount, _mixBufferCount),
|
||||
3 => new CommandProcessingTimeEstimatorVersion3(_sampleCount, _mixBufferCount),
|
||||
4 => new CommandProcessingTimeEstimatorVersion4(_sampleCount, _mixBufferCount),
|
||||
5 => new CommandProcessingTimeEstimatorVersion5(_sampleCount, _mixBufferCount),
|
||||
_ => throw new NotImplementedException($"Unsupported processing time estimator version {_behaviourContext.GetCommandProcessingTimeEstimatorVersion()}."),
|
||||
_ => throw new NotImplementedException($"Unsupported processing time estimator version {_behaviourInfo.GetCommandProcessingTimeEstimatorVersion()}."),
|
||||
};
|
||||
|
||||
return ResultCode.Success;
|
||||
@@ -411,11 +411,11 @@ namespace Ryujinx.Audio.Renderer.Server
|
||||
|
||||
output.Span.Clear();
|
||||
|
||||
StateUpdater stateUpdater = new(input, output, _processHandle, _behaviourContext);
|
||||
StateUpdater stateUpdater = new(input, output, _processHandle, _behaviourInfo);
|
||||
|
||||
ResultCode result;
|
||||
|
||||
result = stateUpdater.UpdateBehaviourContext();
|
||||
result = stateUpdater.UpdateBehaviourInfo();
|
||||
|
||||
if (result != ResultCode.Success)
|
||||
{
|
||||
@@ -436,9 +436,16 @@ namespace Ryujinx.Audio.Renderer.Server
|
||||
return result;
|
||||
}
|
||||
|
||||
PoolMapper poolMapper = new(_processHandle, _memoryPools, _behaviourContext.IsMemoryPoolForceMappingEnabled());
|
||||
PoolMapper poolMapper = new(_processHandle, _memoryPools, _behaviourInfo.IsMemoryPoolForceMappingEnabled());
|
||||
|
||||
result = stateUpdater.UpdateVoices(_voiceContext, poolMapper);
|
||||
if (_behaviourInfo.IsBiquadFilterParameterFloatSupported())
|
||||
{
|
||||
result = stateUpdater.UpdateVoices2(_voiceContext, poolMapper);
|
||||
}
|
||||
else
|
||||
{
|
||||
result = stateUpdater.UpdateVoices1(_voiceContext, poolMapper);
|
||||
}
|
||||
|
||||
if (result != ResultCode.Success)
|
||||
{
|
||||
@@ -452,7 +459,7 @@ namespace Ryujinx.Audio.Renderer.Server
|
||||
return result;
|
||||
}
|
||||
|
||||
if (_behaviourContext.IsSplitterSupported())
|
||||
if (_behaviourInfo.IsSplitterSupported())
|
||||
{
|
||||
result = stateUpdater.UpdateSplitter(_splitterContext);
|
||||
|
||||
@@ -490,7 +497,7 @@ namespace Ryujinx.Audio.Renderer.Server
|
||||
return result;
|
||||
}
|
||||
|
||||
if (_behaviourContext.IsElapsedFrameCountSupported())
|
||||
if (_behaviourInfo.IsElapsedFrameCountSupported())
|
||||
{
|
||||
result = stateUpdater.UpdateRendererInfo(_elapsedFrameCount);
|
||||
|
||||
@@ -557,7 +564,7 @@ namespace Ryujinx.Audio.Renderer.Server
|
||||
break;
|
||||
}
|
||||
|
||||
ref VoiceState voice = ref _voiceContext.GetState(NodeIdHelper.GetBase(targetNodeId));
|
||||
ref VoiceInfo voice = ref _voiceContext.GetState(NodeIdHelper.GetBase(targetNodeId));
|
||||
|
||||
if (voice.Priority == Constants.VoiceHighestPriority)
|
||||
{
|
||||
@@ -646,7 +653,7 @@ namespace Ryujinx.Audio.Renderer.Server
|
||||
|
||||
_voiceContext.UpdateForCommandGeneration();
|
||||
|
||||
if (_behaviourContext.IsEffectInfoVersion2Supported())
|
||||
if (_behaviourInfo.IsEffectInfoVersion2Supported())
|
||||
{
|
||||
_effectContext.UpdateResultStateForCommandGeneration();
|
||||
}
|
||||
@@ -661,7 +668,7 @@ namespace Ryujinx.Audio.Renderer.Server
|
||||
|
||||
private int GetMaxAllocatedTimeForDsp()
|
||||
{
|
||||
return (int)(Constants.AudioProcessorMaxUpdateTimePerSessions * _behaviourContext.GetAudioRendererProcessingTimeLimit() * (GetRenderingTimeLimit() / 100.0f));
|
||||
return (int)(Constants.AudioProcessorMaxUpdateTimePerSessions * _behaviourInfo.GetAudioRendererProcessingTimeLimit() * (GetRenderingTimeLimit() / 100.0f));
|
||||
}
|
||||
|
||||
public void SendCommands()
|
||||
@@ -736,7 +743,7 @@ namespace Ryujinx.Audio.Renderer.Server
|
||||
return new RendererSystemContext
|
||||
{
|
||||
ChannelCount = _manager.Processor.OutputDevices[_sessionId].GetChannelCount(),
|
||||
BehaviourContext = _behaviourContext,
|
||||
BehaviourInfo = _behaviourInfo,
|
||||
DepopBuffer = _depopBuffer,
|
||||
MixBufferCount = GetMixBufferCount(),
|
||||
SessionId = _sessionId,
|
||||
@@ -751,9 +758,9 @@ namespace Ryujinx.Audio.Renderer.Server
|
||||
|
||||
public static ulong GetWorkBufferSize(ref AudioRendererConfiguration parameter)
|
||||
{
|
||||
BehaviourContext behaviourContext = new();
|
||||
BehaviourInfo behaviourInfo = new();
|
||||
|
||||
behaviourContext.SetUserRevision(parameter.Revision);
|
||||
behaviourInfo.SetUserRevision(parameter.Revision);
|
||||
|
||||
uint mixesCount = parameter.SubMixBufferCount + 1;
|
||||
|
||||
@@ -771,28 +778,28 @@ namespace Ryujinx.Audio.Renderer.Server
|
||||
size = WorkBufferAllocator.GetTargetSize<float>(size, BitUtils.AlignUp<ulong>(parameter.MixBufferCount, Constants.BufferAlignment), Constants.BufferAlignment);
|
||||
|
||||
// Voice
|
||||
size = WorkBufferAllocator.GetTargetSize<VoiceState>(size, parameter.VoiceCount, VoiceState.Alignment);
|
||||
size = WorkBufferAllocator.GetTargetSize<VoiceInfo>(size, parameter.VoiceCount, VoiceInfo.Alignment);
|
||||
size = WorkBufferAllocator.GetTargetSize<int>(size, parameter.VoiceCount, 0x10);
|
||||
size = WorkBufferAllocator.GetTargetSize<VoiceChannelResource>(size, parameter.VoiceCount, VoiceChannelResource.Alignment);
|
||||
size = WorkBufferAllocator.GetTargetSize<VoiceUpdateState>(size, parameter.VoiceCount, VoiceUpdateState.Align);
|
||||
size = WorkBufferAllocator.GetTargetSize<VoiceState>(size, parameter.VoiceCount, VoiceState.Align);
|
||||
|
||||
// Mix
|
||||
size = WorkBufferAllocator.GetTargetSize<MixState>(size, mixesCount, MixState.Alignment);
|
||||
size = WorkBufferAllocator.GetTargetSize<MixInfo>(size, mixesCount, MixInfo.Alignment);
|
||||
size = WorkBufferAllocator.GetTargetSize<int>(size, parameter.EffectCount * mixesCount, 0x10);
|
||||
size = WorkBufferAllocator.GetTargetSize<int>(size, mixesCount, 0x10);
|
||||
|
||||
if (behaviourContext.IsSplitterSupported())
|
||||
if (behaviourInfo.IsSplitterSupported())
|
||||
{
|
||||
size += (ulong)BitUtils.AlignUp(NodeStates.GetWorkBufferSize((int)mixesCount) + EdgeMatrix.GetWorkBufferSize((int)mixesCount), 0x10);
|
||||
}
|
||||
|
||||
// Memory Pool
|
||||
size = WorkBufferAllocator.GetTargetSize<MemoryPoolState>(size, memoryPoolCount, MemoryPoolState.Alignment);
|
||||
size = WorkBufferAllocator.GetTargetSize<MemoryPoolInfo>(size, memoryPoolCount, MemoryPoolInfo.Alignment);
|
||||
|
||||
// Splitter
|
||||
size = SplitterContext.GetWorkBufferSize(size, ref behaviourContext, ref parameter);
|
||||
size = SplitterContext.GetWorkBufferSize(size, ref behaviourInfo, ref parameter);
|
||||
|
||||
if (behaviourContext.IsBiquadFilterParameterForSplitterEnabled() &&
|
||||
if (behaviourInfo.IsBiquadFilterParameterForSplitterEnabled() &&
|
||||
parameter.SplitterCount > 0 &&
|
||||
parameter.SplitterDestinationCount > 0)
|
||||
{
|
||||
@@ -800,12 +807,12 @@ namespace Ryujinx.Audio.Renderer.Server
|
||||
}
|
||||
|
||||
// DSP Voice
|
||||
size = WorkBufferAllocator.GetTargetSize<VoiceUpdateState>(size, parameter.VoiceCount, VoiceUpdateState.Align);
|
||||
size = WorkBufferAllocator.GetTargetSize<VoiceState>(size, parameter.VoiceCount, VoiceState.Align);
|
||||
|
||||
// Performance
|
||||
if (parameter.PerformanceMetricFramesCount > 0)
|
||||
{
|
||||
ulong performanceMetricsPerFramesSize = PerformanceManager.GetRequiredBufferSizeForPerformanceMetricsPerFrame(ref parameter, ref behaviourContext) * (parameter.PerformanceMetricFramesCount + 1) + 0xC;
|
||||
ulong performanceMetricsPerFramesSize = PerformanceManager.GetRequiredBufferSizeForPerformanceMetricsPerFrame(ref parameter, ref behaviourInfo) * (parameter.PerformanceMetricFramesCount + 1) + 0xC;
|
||||
|
||||
size += BitUtils.AlignUp<ulong>(performanceMetricsPerFramesSize, Constants.PerformanceMetricsPerFramesSizeAlignment);
|
||||
}
|
||||
@@ -847,13 +854,13 @@ namespace Ryujinx.Audio.Renderer.Server
|
||||
}
|
||||
|
||||
PoolMapper mapper = new(_processHandle, false);
|
||||
mapper.Unmap(ref _dspMemoryPoolState);
|
||||
mapper.Unmap(ref _dspMemoryPoolInfo);
|
||||
|
||||
PoolMapper.ClearUsageState(_memoryPools);
|
||||
|
||||
for (int i = 0; i < _memoryPoolCount; i++)
|
||||
{
|
||||
ref MemoryPoolState memoryPool = ref _memoryPools.Span[i];
|
||||
ref MemoryPoolInfo memoryPool = ref _memoryPools.Span[i];
|
||||
|
||||
if (memoryPool.IsMapped())
|
||||
{
|
||||
@@ -875,7 +882,7 @@ namespace Ryujinx.Audio.Renderer.Server
|
||||
|
||||
public void SetVoiceDropParameter(float voiceDropParameter)
|
||||
{
|
||||
_voiceDropParameter = Math.Clamp(voiceDropParameter, 0.0f, 2.0f);
|
||||
_voiceDropParameter = Math.Clamp(voiceDropParameter, 0.0f, 4.0f);
|
||||
}
|
||||
|
||||
public float GetVoiceDropParameter()
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
using Ryujinx.Audio.Renderer.Parameter;
|
||||
using Ryujinx.Common.Memory;
|
||||
using System;
|
||||
using System.Buffers;
|
||||
using System.Diagnostics;
|
||||
@@ -9,7 +11,7 @@ namespace Ryujinx.Audio.Renderer.Server
|
||||
/// Behaviour context.
|
||||
/// </summary>
|
||||
/// <remarks>This handles features based on the audio renderer revision provided by the user.</remarks>
|
||||
public class BehaviourContext
|
||||
public class BehaviourInfo
|
||||
{
|
||||
/// <summary>
|
||||
/// The base magic of the Audio Renderer revision.
|
||||
@@ -40,7 +42,7 @@ namespace Ryujinx.Audio.Renderer.Server
|
||||
public const int Revision4 = 4 << 24;
|
||||
|
||||
/// <summary>
|
||||
/// REV5: <see cref="Parameter.VoiceInParameter.DecodingBehaviour"/>, <see cref="Parameter.VoiceInParameter.FlushWaveBufferCount"/> were added to voice.
|
||||
/// REV5: <see cref="VoiceInParameter1.DecodingBehaviour"/>, <see cref="VoiceInParameter1.FlushWaveBufferCount"/> were added to voice.
|
||||
/// A new performance frame format (version 2) was added with support for more information about DSP timing.
|
||||
/// <see cref="Parameter.RendererInfoOutStatus"/> was added to supply the count of update done sent to the DSP.
|
||||
/// A new version of the command estimator was added to address timing changes caused by the voice changes.
|
||||
@@ -64,7 +66,7 @@ namespace Ryujinx.Audio.Renderer.Server
|
||||
/// <summary>
|
||||
/// REV8:
|
||||
/// Wavebuffer was changed to support more control over loop (you can now specify where to start and end a loop, and how many times to loop).
|
||||
/// <see cref="Parameter.VoiceInParameter.SrcQuality"/> was added (see <see cref="Parameter.VoiceInParameter.SampleRateConversionQuality"/> for more info).
|
||||
/// <see cref="VoiceInParameter1.SrcQuality"/> was added (see <see cref="VoiceInParameter1.SampleRateConversionQuality"/> for more info).
|
||||
/// Final leftovers of the codec system were removed.
|
||||
/// <see cref="Common.SampleFormat.PcmFloat"/> support was added.
|
||||
/// A new version of the command estimator was added to address timing changes caused by the voice and command changes.
|
||||
@@ -115,16 +117,27 @@ namespace Ryujinx.Audio.Renderer.Server
|
||||
/// </summary>
|
||||
/// <remarks>This was added in system update 18.0.0</remarks>
|
||||
public const int Revision13 = 13 << 24;
|
||||
|
||||
/// <summary>
|
||||
/// REV14:
|
||||
/// Fixes the Depop Bug.
|
||||
///
|
||||
/// </summary>
|
||||
/// <remarks>This was added in system update 19.0.0 </remarks>
|
||||
public const int Revision14 = 14 << 24;
|
||||
|
||||
/// <summary>
|
||||
/// REV15:
|
||||
/// Support for float coefficients in biquad filters
|
||||
///
|
||||
/// </summary>
|
||||
/// <remarks>This was added in system update 19.0.0 </remarks>
|
||||
public const int Revision15 = 15 << 24;
|
||||
|
||||
/// <summary>
|
||||
/// Last revision supported by the implementation.
|
||||
/// </summary>
|
||||
public const int LastRevision = Revision13;
|
||||
|
||||
/// <summary>
|
||||
/// Target revision magic supported by the implementation.
|
||||
/// </summary>
|
||||
public const int ProcessRevision = BaseRevisionMagic + LastRevision;
|
||||
public const int LastRevision = Revision15;
|
||||
|
||||
/// <summary>
|
||||
/// Get the revision number from the revision magic.
|
||||
@@ -133,15 +146,25 @@ namespace Ryujinx.Audio.Renderer.Server
|
||||
/// <returns>The revision number.</returns>
|
||||
public static int GetRevisionNumber(int revision) => (revision - BaseRevisionMagic) >> 24;
|
||||
|
||||
/// <summary>
|
||||
/// Target revision magic supported by the implementation.
|
||||
/// </summary>
|
||||
public const int ProcessRevision = BaseRevisionMagic + LastRevision;
|
||||
|
||||
/// <summary>
|
||||
/// Current active revision.
|
||||
/// </summary>
|
||||
public int UserRevision { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Current flags of the <see cref="BehaviourInfo"/>.
|
||||
/// </summary>
|
||||
private ulong _flags;
|
||||
|
||||
/// <summary>
|
||||
/// Error storage.
|
||||
/// </summary>
|
||||
private readonly ErrorInfo[] _errorInfos;
|
||||
private readonly Array10<ErrorInfo> _errorInfos;
|
||||
|
||||
/// <summary>
|
||||
/// Current position in the <see cref="_errorInfos"/> array.
|
||||
@@ -149,17 +172,12 @@ namespace Ryujinx.Audio.Renderer.Server
|
||||
private uint _errorIndex;
|
||||
|
||||
/// <summary>
|
||||
/// Current flags of the <see cref="BehaviourContext"/>.
|
||||
/// Create a new instance of <see cref="BehaviourInfo"/>.
|
||||
/// </summary>
|
||||
private ulong _flags;
|
||||
|
||||
/// <summary>
|
||||
/// Create a new instance of <see cref="BehaviourContext"/>.
|
||||
/// </summary>
|
||||
public BehaviourContext()
|
||||
public BehaviourInfo()
|
||||
{
|
||||
UserRevision = 0;
|
||||
_errorInfos = new ErrorInfo[Constants.MaxErrorInfos];
|
||||
_errorInfos = new Array10<ErrorInfo>();
|
||||
_errorIndex = 0;
|
||||
}
|
||||
|
||||
@@ -173,7 +191,7 @@ namespace Ryujinx.Audio.Renderer.Server
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Update flags of the <see cref="BehaviourContext"/>.
|
||||
/// Update flags of the <see cref="BehaviourInfo"/>.
|
||||
/// </summary>
|
||||
/// <param name="flags">The new flags.</param>
|
||||
public void UpdateFlags(ulong flags)
|
||||
@@ -321,9 +339,9 @@ namespace Ryujinx.Audio.Renderer.Server
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check if the audio renderer should support <see cref="Parameter.VoiceInParameter.DecodingBehaviour"/>.
|
||||
/// Check if the audio renderer should support <see cref="VoiceInParameter1.DecodingBehaviour"/>.
|
||||
/// </summary>
|
||||
/// <returns>True if the audio renderer should support <see cref="Parameter.VoiceInParameter.DecodingBehaviour"/>.</returns>
|
||||
/// <returns>True if the audio renderer should support <see cref="VoiceInParameter1.DecodingBehaviour"/>.</returns>
|
||||
public bool IsDecodingBehaviourFlagSupported()
|
||||
{
|
||||
return CheckFeatureSupported(UserRevision, BaseRevisionMagic + Revision5);
|
||||
@@ -400,6 +418,24 @@ namespace Ryujinx.Audio.Renderer.Server
|
||||
{
|
||||
return CheckFeatureSupported(UserRevision, BaseRevisionMagic + Revision13);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check if the audio renderer should support the depop bug fix.
|
||||
/// </summary>
|
||||
/// <returns>True if the audio renderer supports the depop bug fix</returns>
|
||||
public bool IsSplitterDepopBugFixEnabled()
|
||||
{
|
||||
return CheckFeatureSupported(UserRevision, BaseRevisionMagic + Revision14);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check if the audio renderer should support biquad filter with float coefficients.
|
||||
/// </summary>
|
||||
/// <returns>True if the audio renderer support biquad filter with float coefficients</returns>
|
||||
public bool IsBiquadFilterParameterFloatSupported()
|
||||
{
|
||||
return CheckFeatureSupported(UserRevision, BaseRevisionMagic + Revision15);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the version of the <see cref="ICommandProcessingTimeEstimator"/>.
|
||||
@@ -440,7 +476,7 @@ namespace Ryujinx.Audio.Renderer.Server
|
||||
|
||||
if (_errorIndex <= Constants.MaxErrorInfos - 1)
|
||||
{
|
||||
_errorInfos[_errorIndex++] = errorInfo;
|
||||
_errorInfos[(int)_errorIndex++] = errorInfo;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -457,22 +493,8 @@ namespace Ryujinx.Audio.Renderer.Server
|
||||
}
|
||||
|
||||
errorCount = Math.Min(_errorIndex, Constants.MaxErrorInfos);
|
||||
|
||||
for (int i = 0; i < Constants.MaxErrorInfos; i++)
|
||||
{
|
||||
if (i < errorCount)
|
||||
{
|
||||
errorInfos[i] = _errorInfos[i];
|
||||
}
|
||||
else
|
||||
{
|
||||
errorInfos[i] = new ErrorInfo
|
||||
{
|
||||
ErrorCode = 0,
|
||||
ExtraErrorInfo = 0,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
_errorInfos.AsSpan().CopyTo(errorInfos);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -5,9 +5,11 @@ using Ryujinx.Audio.Renderer.Parameter;
|
||||
using Ryujinx.Audio.Renderer.Parameter.Effect;
|
||||
using Ryujinx.Audio.Renderer.Server.Performance;
|
||||
using Ryujinx.Audio.Renderer.Server.Sink;
|
||||
using Ryujinx.Audio.Renderer.Server.Splitter;
|
||||
using Ryujinx.Audio.Renderer.Server.Upsampler;
|
||||
using Ryujinx.Audio.Renderer.Server.Voice;
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
using CpuAddress = System.UInt64;
|
||||
|
||||
namespace Ryujinx.Audio.Renderer.Server
|
||||
@@ -77,7 +79,7 @@ namespace Ryujinx.Audio.Renderer.Server
|
||||
/// <param name="bufferOffset">The target buffer offset.</param>
|
||||
/// <param name="nodeId">The node id associated to this command.</param>
|
||||
/// <param name="wasPlaying">Set to true if the voice was playing previously.</param>
|
||||
public void GenerateDepopPrepare(Memory<VoiceUpdateState> state, Memory<float> depopBuffer, uint bufferCount, uint bufferOffset, int nodeId, bool wasPlaying)
|
||||
public void GenerateDepopPrepare(Memory<VoiceState> state, Memory<float> depopBuffer, uint bufferCount, uint bufferOffset, int nodeId, bool wasPlaying)
|
||||
{
|
||||
DepopPrepareCommand command = new(state, depopBuffer, bufferCount, bufferOffset, nodeId, wasPlaying);
|
||||
|
||||
@@ -120,14 +122,14 @@ namespace Ryujinx.Audio.Renderer.Server
|
||||
/// <summary>
|
||||
/// Create a new <see cref="DataSourceVersion2Command"/>.
|
||||
/// </summary>
|
||||
/// <param name="voiceState">The <see cref="VoiceState"/> to generate the command from.</param>
|
||||
/// <param name="state">The <see cref="VoiceUpdateState"/> to generate the command from.</param>
|
||||
/// <param name="voiceInfo">The <see cref="VoiceInfo"/> to generate the command from.</param>
|
||||
/// <param name="state">The <see cref="VoiceState"/> to generate the command from.</param>
|
||||
/// <param name="outputBufferIndex">The output buffer index to use.</param>
|
||||
/// <param name="channelIndex">The target channel index.</param>
|
||||
/// <param name="nodeId">The node id associated to this command.</param>
|
||||
public void GenerateDataSourceVersion2(ref VoiceState voiceState, Memory<VoiceUpdateState> state, ushort outputBufferIndex, ushort channelIndex, int nodeId)
|
||||
public void GenerateDataSourceVersion2(ref VoiceInfo voiceInfo, Memory<VoiceState> state, ushort outputBufferIndex, ushort channelIndex, int nodeId)
|
||||
{
|
||||
DataSourceVersion2Command command = new(ref voiceState, state, outputBufferIndex, channelIndex, nodeId);
|
||||
DataSourceVersion2Command command = new(ref voiceInfo, state, outputBufferIndex, channelIndex, nodeId);
|
||||
|
||||
command.EstimatedProcessingTime = _commandProcessingTimeEstimator.Estimate(command);
|
||||
|
||||
@@ -137,14 +139,14 @@ namespace Ryujinx.Audio.Renderer.Server
|
||||
/// <summary>
|
||||
/// Create a new <see cref="PcmInt16DataSourceCommandVersion1"/>.
|
||||
/// </summary>
|
||||
/// <param name="voiceState">The <see cref="VoiceState"/> to generate the command from.</param>
|
||||
/// <param name="state">The <see cref="VoiceUpdateState"/> to generate the command from.</param>
|
||||
/// <param name="voiceInfo">The <see cref="VoiceInfo"/> to generate the command from.</param>
|
||||
/// <param name="state">The <see cref="VoiceState"/> to generate the command from.</param>
|
||||
/// <param name="outputBufferIndex">The output buffer index to use.</param>
|
||||
/// <param name="channelIndex">The target channel index.</param>
|
||||
/// <param name="nodeId">The node id associated to this command.</param>
|
||||
public void GeneratePcmInt16DataSourceVersion1(ref VoiceState voiceState, Memory<VoiceUpdateState> state, ushort outputBufferIndex, ushort channelIndex, int nodeId)
|
||||
public void GeneratePcmInt16DataSourceVersion1(ref VoiceInfo voiceInfo, Memory<VoiceState> state, ushort outputBufferIndex, ushort channelIndex, int nodeId)
|
||||
{
|
||||
PcmInt16DataSourceCommandVersion1 command = new(ref voiceState, state, outputBufferIndex, channelIndex, nodeId);
|
||||
PcmInt16DataSourceCommandVersion1 command = new(ref voiceInfo, state, outputBufferIndex, channelIndex, nodeId);
|
||||
|
||||
command.EstimatedProcessingTime = _commandProcessingTimeEstimator.Estimate(command);
|
||||
|
||||
@@ -154,14 +156,14 @@ namespace Ryujinx.Audio.Renderer.Server
|
||||
/// <summary>
|
||||
/// Create a new <see cref="PcmFloatDataSourceCommandVersion1"/>.
|
||||
/// </summary>
|
||||
/// <param name="voiceState">The <see cref="VoiceState"/> to generate the command from.</param>
|
||||
/// <param name="state">The <see cref="VoiceUpdateState"/> to generate the command from.</param>
|
||||
/// <param name="voiceInfo">The <see cref="VoiceInfo"/> to generate the command from.</param>
|
||||
/// <param name="state">The <see cref="VoiceState"/> to generate the command from.</param>
|
||||
/// <param name="outputBufferIndex">The output buffer index to use.</param>
|
||||
/// <param name="channelIndex">The target channel index.</param>
|
||||
/// <param name="nodeId">The node id associated to this command.</param>
|
||||
public void GeneratePcmFloatDataSourceVersion1(ref VoiceState voiceState, Memory<VoiceUpdateState> state, ushort outputBufferIndex, ushort channelIndex, int nodeId)
|
||||
public void GeneratePcmFloatDataSourceVersion1(ref VoiceInfo voiceInfo, Memory<VoiceState> state, ushort outputBufferIndex, ushort channelIndex, int nodeId)
|
||||
{
|
||||
PcmFloatDataSourceCommandVersion1 command = new(ref voiceState, state, outputBufferIndex, channelIndex, nodeId);
|
||||
PcmFloatDataSourceCommandVersion1 command = new(ref voiceInfo, state, outputBufferIndex, channelIndex, nodeId);
|
||||
|
||||
command.EstimatedProcessingTime = _commandProcessingTimeEstimator.Estimate(command);
|
||||
|
||||
@@ -171,13 +173,13 @@ namespace Ryujinx.Audio.Renderer.Server
|
||||
/// <summary>
|
||||
/// Create a new <see cref="AdpcmDataSourceCommandVersion1"/>.
|
||||
/// </summary>
|
||||
/// <param name="voiceState">The <see cref="VoiceState"/> to generate the command from.</param>
|
||||
/// <param name="state">The <see cref="VoiceUpdateState"/> to generate the command from.</param>
|
||||
/// <param name="voiceInfo">The <see cref="VoiceInfo"/> to generate the command from.</param>
|
||||
/// <param name="state">The <see cref="VoiceState"/> to generate the command from.</param>
|
||||
/// <param name="outputBufferIndex">The output buffer index to use.</param>
|
||||
/// <param name="nodeId">The node id associated to this command.</param>
|
||||
public void GenerateAdpcmDataSourceVersion1(ref VoiceState voiceState, Memory<VoiceUpdateState> state, ushort outputBufferIndex, int nodeId)
|
||||
public void GenerateAdpcmDataSourceVersion1(ref VoiceInfo voiceInfo, Memory<VoiceState> state, ushort outputBufferIndex, int nodeId)
|
||||
{
|
||||
AdpcmDataSourceCommandVersion1 command = new(ref voiceState, state, outputBufferIndex, nodeId);
|
||||
AdpcmDataSourceCommandVersion1 command = new(ref voiceInfo, state, outputBufferIndex, nodeId);
|
||||
|
||||
command.EstimatedProcessingTime = _commandProcessingTimeEstimator.Estimate(command);
|
||||
|
||||
@@ -194,7 +196,7 @@ namespace Ryujinx.Audio.Renderer.Server
|
||||
/// <param name="outputBufferOffset">The output buffer offset.</param>
|
||||
/// <param name="needInitialization">Set to true if the biquad filter state needs to be initialized.</param>
|
||||
/// <param name="nodeId">The node id associated to this command.</param>
|
||||
public void GenerateBiquadFilter(int baseIndex, ref BiquadFilterParameter filter, Memory<BiquadFilterState> biquadFilterStateMemory, int inputBufferOffset, int outputBufferOffset, bool needInitialization, int nodeId)
|
||||
public void GenerateBiquadFilter(int baseIndex, ref BiquadFilterParameter2 filter, Memory<BiquadFilterState> biquadFilterStateMemory, int inputBufferOffset, int outputBufferOffset, bool needInitialization, int nodeId)
|
||||
{
|
||||
BiquadFilterCommand command = new(baseIndex, ref filter, biquadFilterStateMemory, inputBufferOffset, outputBufferOffset, needInitialization, nodeId);
|
||||
|
||||
@@ -213,7 +215,7 @@ namespace Ryujinx.Audio.Renderer.Server
|
||||
/// <param name="outputBufferOffset">The output buffer offset.</param>
|
||||
/// <param name="isInitialized">Set to true if the biquad filter state is initialized.</param>
|
||||
/// <param name="nodeId">The node id associated to this command.</param>
|
||||
public void GenerateMultiTapBiquadFilter(int baseIndex, ReadOnlySpan<BiquadFilterParameter> filters, Memory<BiquadFilterState> biquadFilterStatesMemory, int inputBufferOffset, int outputBufferOffset, ReadOnlySpan<bool> isInitialized, int nodeId)
|
||||
public void GenerateMultiTapBiquadFilter(int baseIndex, ReadOnlySpan<BiquadFilterParameter2> filters, Memory<BiquadFilterState> biquadFilterStatesMemory, int inputBufferOffset, int outputBufferOffset, ReadOnlySpan<bool> isInitialized, int nodeId)
|
||||
{
|
||||
MultiTapBiquadFilterCommand command = new(baseIndex, filters, biquadFilterStatesMemory, inputBufferOffset, outputBufferOffset, isInitialized, nodeId);
|
||||
|
||||
@@ -230,9 +232,9 @@ namespace Ryujinx.Audio.Renderer.Server
|
||||
/// <param name="outputBufferIndex">The base output index.</param>
|
||||
/// <param name="previousVolume">The previous volume.</param>
|
||||
/// <param name="volume">The new volume.</param>
|
||||
/// <param name="state">The <see cref="VoiceUpdateState"/> to generate the command from.</param>
|
||||
/// <param name="state">The <see cref="VoiceState"/> to generate the command from.</param>
|
||||
/// <param name="nodeId">The node id associated to this command.</param>
|
||||
public void GenerateMixRampGrouped(uint mixBufferCount, uint inputBufferIndex, uint outputBufferIndex, ReadOnlySpan<float> previousVolume, ReadOnlySpan<float> volume, Memory<VoiceUpdateState> state, int nodeId)
|
||||
public void GenerateMixRampGrouped(uint mixBufferCount, uint inputBufferIndex, uint outputBufferIndex, ReadOnlySpan<float> previousVolume, ReadOnlySpan<float> volume, Memory<VoiceState> state, int nodeId)
|
||||
{
|
||||
MixRampGroupedCommand command = new(mixBufferCount, inputBufferIndex, outputBufferIndex, previousVolume, volume, state, nodeId);
|
||||
|
||||
@@ -248,10 +250,10 @@ namespace Ryujinx.Audio.Renderer.Server
|
||||
/// <param name="volume">The new volume.</param>
|
||||
/// <param name="inputBufferIndex">The input buffer index.</param>
|
||||
/// <param name="outputBufferIndex">The output buffer index.</param>
|
||||
/// <param name="lastSampleIndex">The index in the <see cref="VoiceUpdateState.LastSamples"/> array to store the ramped sample.</param>
|
||||
/// <param name="state">The <see cref="VoiceUpdateState"/> to generate the command from.</param>
|
||||
/// <param name="lastSampleIndex">The index in the <see cref="VoiceState.LastSamples"/> array to store the ramped sample.</param>
|
||||
/// <param name="state">The <see cref="VoiceState"/> to generate the command from.</param>
|
||||
/// <param name="nodeId">The node id associated to this command.</param>
|
||||
public void GenerateMixRamp(float previousVolume, float volume, uint inputBufferIndex, uint outputBufferIndex, int lastSampleIndex, Memory<VoiceUpdateState> state, int nodeId)
|
||||
public void GenerateMixRamp(float previousVolume, float volume, uint inputBufferIndex, uint outputBufferIndex, int lastSampleIndex, Memory<VoiceState> state, int nodeId)
|
||||
{
|
||||
MixRampCommand command = new(previousVolume, volume, inputBufferIndex, outputBufferIndex, lastSampleIndex, state, nodeId);
|
||||
|
||||
@@ -267,8 +269,8 @@ namespace Ryujinx.Audio.Renderer.Server
|
||||
/// <param name="volume">The new volume.</param>
|
||||
/// <param name="inputBufferIndex">The input buffer index.</param>
|
||||
/// <param name="outputBufferIndex">The output buffer index.</param>
|
||||
/// <param name="lastSampleIndex">The index in the <see cref="VoiceUpdateState.LastSamples"/> array to store the ramped sample.</param>
|
||||
/// <param name="state">The <see cref="VoiceUpdateState"/> to generate the command from.</param>
|
||||
/// <param name="lastSampleIndex">The index in the <see cref="VoiceState.LastSamples"/> array to store the ramped sample.</param>
|
||||
/// <param name="state">The <see cref="VoiceState"/> to generate the command from.</param>
|
||||
/// <param name="filter">The biquad filter parameter.</param>
|
||||
/// <param name="biquadFilterState">The biquad state.</param>
|
||||
/// <param name="previousBiquadFilterState">The previous biquad state.</param>
|
||||
@@ -282,8 +284,8 @@ namespace Ryujinx.Audio.Renderer.Server
|
||||
uint inputBufferIndex,
|
||||
uint outputBufferIndex,
|
||||
int lastSampleIndex,
|
||||
Memory<VoiceUpdateState> state,
|
||||
ref BiquadFilterParameter filter,
|
||||
Memory<VoiceState> state,
|
||||
ref BiquadFilterParameter2 filter,
|
||||
Memory<BiquadFilterState> biquadFilterState,
|
||||
Memory<BiquadFilterState> previousBiquadFilterState,
|
||||
bool needInitialization,
|
||||
@@ -318,8 +320,8 @@ namespace Ryujinx.Audio.Renderer.Server
|
||||
/// <param name="volume">The new volume.</param>
|
||||
/// <param name="inputBufferIndex">The input buffer index.</param>
|
||||
/// <param name="outputBufferIndex">The output buffer index.</param>
|
||||
/// <param name="lastSampleIndex">The index in the <see cref="VoiceUpdateState.LastSamples"/> array to store the ramped sample.</param>
|
||||
/// <param name="state">The <see cref="VoiceUpdateState"/> to generate the command from.</param>
|
||||
/// <param name="lastSampleIndex">The index in the <see cref="VoiceState.LastSamples"/> array to store the ramped sample.</param>
|
||||
/// <param name="state">The <see cref="VoiceState"/> to generate the command from.</param>
|
||||
/// <param name="filter0">First biquad filter parameter.</param>
|
||||
/// <param name="filter1">Second biquad filter parameter.</param>
|
||||
/// <param name="biquadFilterState0">First biquad state.</param>
|
||||
@@ -337,9 +339,9 @@ namespace Ryujinx.Audio.Renderer.Server
|
||||
uint inputBufferIndex,
|
||||
uint outputBufferIndex,
|
||||
int lastSampleIndex,
|
||||
Memory<VoiceUpdateState> state,
|
||||
ref BiquadFilterParameter filter0,
|
||||
ref BiquadFilterParameter filter1,
|
||||
Memory<VoiceState> state,
|
||||
ref BiquadFilterParameter2 filter0,
|
||||
ref BiquadFilterParameter2 filter1,
|
||||
Memory<BiquadFilterState> biquadFilterState0,
|
||||
Memory<BiquadFilterState> biquadFilterState1,
|
||||
Memory<BiquadFilterState> previousBiquadFilterState0,
|
||||
@@ -654,14 +656,14 @@ namespace Ryujinx.Audio.Renderer.Server
|
||||
/// Create a new <see cref="UpsampleCommand"/>.
|
||||
/// </summary>
|
||||
/// <param name="bufferOffset">The offset of the mix buffer.</param>
|
||||
/// <param name="upsampler">The <see cref="UpsamplerState"/> associated.</param>
|
||||
/// <param name="upsampler">The <see cref="UpsamplerInfo"/> associated.</param>
|
||||
/// <param name="inputCount">The total input count.</param>
|
||||
/// <param name="inputBufferOffset">The input buffer mix offset.</param>
|
||||
/// <param name="bufferCountPerSample">The buffer count per sample.</param>
|
||||
/// <param name="sampleCount">The source sample count.</param>
|
||||
/// <param name="sampleRate">The source sample rate.</param>
|
||||
/// <param name="nodeId">The node id associated to this command.</param>
|
||||
public void GenerateUpsample(uint bufferOffset, UpsamplerState upsampler, uint inputCount, Span<byte> inputBufferOffset, uint bufferCountPerSample, uint sampleCount, uint sampleRate, int nodeId)
|
||||
public void GenerateUpsample(uint bufferOffset, UpsamplerInfo upsampler, uint inputCount, Span<byte> inputBufferOffset, uint bufferCountPerSample, uint sampleCount, uint sampleRate, int nodeId)
|
||||
{
|
||||
UpsampleCommand command = new(bufferOffset, upsampler, inputCount, inputBufferOffset, bufferCountPerSample, sampleCount, sampleRate, nodeId);
|
||||
|
||||
@@ -686,5 +688,23 @@ namespace Ryujinx.Audio.Renderer.Server
|
||||
|
||||
AddCommand(command);
|
||||
}
|
||||
|
||||
public void GenerateFillBuffer(SplitterDestination destination, float value, int length, int nodeId)
|
||||
{
|
||||
FillBufferCommand command;
|
||||
|
||||
if (Unsafe.IsNullRef(ref destination.GetV2RefOrNull()))
|
||||
{
|
||||
command = new(destination.GetV1RefOrNull(), length, value, nodeId);
|
||||
}
|
||||
else
|
||||
{
|
||||
command = new(destination.GetV2RefOrNull(), length, value, nodeId);
|
||||
}
|
||||
|
||||
command.EstimatedProcessingTime = _commandProcessingTimeEstimator.Estimate(command);
|
||||
|
||||
AddCommand(command);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using Ryujinx.Audio.Common;
|
||||
using Ryujinx.Audio.Renderer.Common;
|
||||
using Ryujinx.Audio.Renderer.Dsp;
|
||||
using Ryujinx.Audio.Renderer.Dsp.Command;
|
||||
using Ryujinx.Audio.Renderer.Dsp.State;
|
||||
using Ryujinx.Audio.Renderer.Parameter;
|
||||
@@ -41,27 +42,27 @@ namespace Ryujinx.Audio.Renderer.Server
|
||||
_commandBuffer.GenerateClearMixBuffer(Constants.InvalidNodeId);
|
||||
}
|
||||
|
||||
private void GenerateDataSource(ref VoiceState voiceState, Memory<VoiceUpdateState> dspState, int channelIndex)
|
||||
private void GenerateDataSource(ref VoiceInfo voiceInfo, Memory<VoiceState> dspState, int channelIndex)
|
||||
{
|
||||
if (voiceState.MixId != Constants.UnusedMixId)
|
||||
if (voiceInfo.MixId != Constants.UnusedMixId)
|
||||
{
|
||||
ref MixState mix = ref _mixContext.GetState(voiceState.MixId);
|
||||
ref MixInfo mix = ref _mixContext.GetState(voiceInfo.MixId);
|
||||
|
||||
_commandBuffer.GenerateDepopPrepare(
|
||||
dspState,
|
||||
_rendererContext.DepopBuffer,
|
||||
mix.BufferCount,
|
||||
mix.BufferOffset,
|
||||
voiceState.NodeId,
|
||||
voiceState.WasPlaying);
|
||||
voiceInfo.NodeId,
|
||||
voiceInfo.WasPlaying);
|
||||
}
|
||||
else if (voiceState.SplitterId != Constants.UnusedSplitterId)
|
||||
else if (voiceInfo.SplitterId != Constants.UnusedSplitterId)
|
||||
{
|
||||
int destinationId = 0;
|
||||
|
||||
while (true)
|
||||
{
|
||||
SplitterDestination destination = _splitterContext.GetDestination((int)voiceState.SplitterId, destinationId++);
|
||||
SplitterDestination destination = _splitterContext.GetDestination((int)voiceInfo.SplitterId, destinationId++);
|
||||
|
||||
if (destination.IsNull)
|
||||
{
|
||||
@@ -74,15 +75,17 @@ namespace Ryujinx.Audio.Renderer.Server
|
||||
|
||||
if (mixId < _mixContext.GetCount() && mixId != Constants.UnusedSplitterIdInt)
|
||||
{
|
||||
ref MixState mix = ref _mixContext.GetState(mixId);
|
||||
ref MixInfo mix = ref _mixContext.GetState(mixId);
|
||||
|
||||
// _commandBuffer.GenerateFillBuffer();
|
||||
|
||||
_commandBuffer.GenerateDepopPrepare(
|
||||
dspState,
|
||||
_rendererContext.DepopBuffer,
|
||||
mix.BufferCount,
|
||||
mix.BufferOffset,
|
||||
voiceState.NodeId,
|
||||
voiceState.WasPlaying);
|
||||
voiceInfo.NodeId,
|
||||
voiceInfo.WasPlaying);
|
||||
|
||||
destination.MarkAsNeedToUpdateInternalState();
|
||||
}
|
||||
@@ -90,69 +93,71 @@ namespace Ryujinx.Audio.Renderer.Server
|
||||
}
|
||||
}
|
||||
|
||||
if (!voiceState.WasPlaying)
|
||||
if (!voiceInfo.WasPlaying)
|
||||
{
|
||||
Debug.Assert(voiceState.SampleFormat != SampleFormat.Adpcm || channelIndex == 0);
|
||||
Debug.Assert(voiceInfo.SampleFormat != SampleFormat.Adpcm || channelIndex == 0);
|
||||
|
||||
if (_rendererContext.BehaviourContext.IsWaveBufferVersion2Supported())
|
||||
if (_rendererContext.BehaviourInfo.IsWaveBufferVersion2Supported())
|
||||
{
|
||||
_commandBuffer.GenerateDataSourceVersion2(
|
||||
ref voiceState,
|
||||
ref voiceInfo,
|
||||
dspState,
|
||||
(ushort)_rendererContext.MixBufferCount,
|
||||
(ushort)channelIndex,
|
||||
voiceState.NodeId);
|
||||
voiceInfo.NodeId);
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (voiceState.SampleFormat)
|
||||
switch (voiceInfo.SampleFormat)
|
||||
{
|
||||
case SampleFormat.PcmInt16:
|
||||
_commandBuffer.GeneratePcmInt16DataSourceVersion1(
|
||||
ref voiceState,
|
||||
ref voiceInfo,
|
||||
dspState,
|
||||
(ushort)_rendererContext.MixBufferCount,
|
||||
(ushort)channelIndex,
|
||||
voiceState.NodeId);
|
||||
voiceInfo.NodeId);
|
||||
break;
|
||||
case SampleFormat.PcmFloat:
|
||||
_commandBuffer.GeneratePcmFloatDataSourceVersion1(
|
||||
ref voiceState,
|
||||
ref voiceInfo,
|
||||
dspState,
|
||||
(ushort)_rendererContext.MixBufferCount,
|
||||
(ushort)channelIndex,
|
||||
voiceState.NodeId);
|
||||
voiceInfo.NodeId);
|
||||
break;
|
||||
case SampleFormat.Adpcm:
|
||||
_commandBuffer.GenerateAdpcmDataSourceVersion1(
|
||||
ref voiceState,
|
||||
ref voiceInfo,
|
||||
dspState,
|
||||
(ushort)_rendererContext.MixBufferCount,
|
||||
voiceState.NodeId);
|
||||
voiceInfo.NodeId);
|
||||
break;
|
||||
default:
|
||||
throw new NotImplementedException($"Unsupported data source {voiceState.SampleFormat}");
|
||||
throw new NotImplementedException($"Unsupported data source {voiceInfo.SampleFormat}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void GenerateBiquadFilterForVoice(ref VoiceState voiceState, Memory<VoiceUpdateState> state, int baseIndex, int bufferOffset, int nodeId)
|
||||
private void GenerateBiquadFilterForVoice(ref VoiceInfo voiceInfo, Memory<VoiceState> state, int baseIndex, int bufferOffset, int nodeId)
|
||||
{
|
||||
bool supportsOptimizedPath = _rendererContext.BehaviourContext.UseMultiTapBiquadFilterProcessing();
|
||||
bool supportsOptimizedPath = _rendererContext.BehaviourInfo.UseMultiTapBiquadFilterProcessing();
|
||||
|
||||
if (supportsOptimizedPath && voiceState.BiquadFilters[0].Enable && voiceState.BiquadFilters[1].Enable)
|
||||
Span<BiquadFilterParameter2> biquadFiltersSpan = voiceInfo.BiquadFilters.AsSpan();
|
||||
|
||||
if (supportsOptimizedPath && biquadFiltersSpan[0].Enable && biquadFiltersSpan[1].Enable)
|
||||
{
|
||||
Memory<byte> biquadStateRawMemory = SpanMemoryManager<byte>.Cast(state)[..(Unsafe.SizeOf<BiquadFilterState>() * Constants.VoiceBiquadFilterCount)];
|
||||
Memory<BiquadFilterState> stateMemory = SpanMemoryManager<BiquadFilterState>.Cast(biquadStateRawMemory);
|
||||
|
||||
_commandBuffer.GenerateMultiTapBiquadFilter(baseIndex, voiceState.BiquadFilters.AsSpan(), stateMemory, bufferOffset, bufferOffset, voiceState.BiquadFilterNeedInitialization, nodeId);
|
||||
_commandBuffer.GenerateMultiTapBiquadFilter(baseIndex, biquadFiltersSpan, stateMemory, bufferOffset, bufferOffset, voiceInfo.BiquadFilterNeedInitialization, nodeId);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < voiceState.BiquadFilters.Length; i++)
|
||||
for (int i = 0; i < biquadFiltersSpan.Length; i++)
|
||||
{
|
||||
ref BiquadFilterParameter filter = ref voiceState.BiquadFilters[i];
|
||||
ref BiquadFilterParameter2 filter = ref biquadFiltersSpan[i];
|
||||
|
||||
if (filter.Enable)
|
||||
{
|
||||
@@ -165,7 +170,7 @@ namespace Ryujinx.Audio.Renderer.Server
|
||||
stateMemory.Slice(i, 1),
|
||||
bufferOffset,
|
||||
bufferOffset,
|
||||
!voiceState.BiquadFilterNeedInitialization[i],
|
||||
!voiceInfo.BiquadFilterNeedInitialization[i],
|
||||
nodeId);
|
||||
}
|
||||
}
|
||||
@@ -174,7 +179,7 @@ namespace Ryujinx.Audio.Renderer.Server
|
||||
|
||||
private void GenerateVoiceMixWithSplitter(
|
||||
SplitterDestination destination,
|
||||
Memory<VoiceUpdateState> state,
|
||||
Memory<VoiceState> state,
|
||||
uint bufferOffset,
|
||||
uint bufferCount,
|
||||
uint bufferIndex,
|
||||
@@ -183,8 +188,8 @@ namespace Ryujinx.Audio.Renderer.Server
|
||||
ReadOnlySpan<float> mixVolumes = destination.MixBufferVolume;
|
||||
ReadOnlySpan<float> previousMixVolumes = destination.PreviousMixBufferVolume;
|
||||
|
||||
ref BiquadFilterParameter bqf0 = ref destination.GetBiquadFilterParameter(0);
|
||||
ref BiquadFilterParameter bqf1 = ref destination.GetBiquadFilterParameter(1);
|
||||
ref BiquadFilterParameter2 bqf0 = ref destination.GetBiquadFilterParameter(0);
|
||||
ref BiquadFilterParameter2 bqf1 = ref destination.GetBiquadFilterParameter(1);
|
||||
|
||||
Memory<BiquadFilterState> bqfState = _splitterContext.GetBiquadFilterState(destination);
|
||||
|
||||
@@ -268,7 +273,7 @@ namespace Ryujinx.Audio.Renderer.Server
|
||||
private void GenerateVoiceMix(
|
||||
ReadOnlySpan<float> mixVolumes,
|
||||
ReadOnlySpan<float> previousMixVolumes,
|
||||
Memory<VoiceUpdateState> state,
|
||||
Memory<VoiceState> state,
|
||||
uint bufferOffset,
|
||||
uint bufferCount,
|
||||
uint bufferIndex,
|
||||
@@ -307,24 +312,27 @@ namespace Ryujinx.Audio.Renderer.Server
|
||||
}
|
||||
}
|
||||
|
||||
private void GenerateVoice(ref VoiceState voiceState)
|
||||
private void GenerateVoice(ref VoiceInfo voiceInfo)
|
||||
{
|
||||
int nodeId = voiceState.NodeId;
|
||||
uint channelsCount = voiceState.ChannelsCount;
|
||||
int nodeId = voiceInfo.NodeId;
|
||||
uint channelsCount = voiceInfo.ChannelsCount;
|
||||
|
||||
Span<int> channelResourceIdsSpan = voiceInfo.ChannelResourceIds.AsSpan();
|
||||
Span<BiquadFilterParameter2> biquadFiltersSpan = voiceInfo.BiquadFilters.AsSpan();
|
||||
|
||||
for (int channelIndex = 0; channelIndex < channelsCount; channelIndex++)
|
||||
{
|
||||
Memory<VoiceUpdateState> dspStateMemory = _voiceContext.GetUpdateStateForDsp(voiceState.ChannelResourceIds[channelIndex]);
|
||||
Memory<VoiceState> dspStateMemory = _voiceContext.GetUpdateStateForDsp(channelResourceIdsSpan[channelIndex]);
|
||||
|
||||
ref VoiceChannelResource channelResource = ref _voiceContext.GetChannelResource(voiceState.ChannelResourceIds[channelIndex]);
|
||||
ref VoiceChannelResource channelResource = ref _voiceContext.GetChannelResource(channelResourceIdsSpan[channelIndex]);
|
||||
|
||||
PerformanceDetailType dataSourceDetailType = PerformanceDetailType.Adpcm;
|
||||
|
||||
if (voiceState.SampleFormat == SampleFormat.PcmInt16)
|
||||
if (voiceInfo.SampleFormat == SampleFormat.PcmInt16)
|
||||
{
|
||||
dataSourceDetailType = PerformanceDetailType.PcmInt16;
|
||||
}
|
||||
else if (voiceState.SampleFormat == SampleFormat.PcmFloat)
|
||||
else if (voiceInfo.SampleFormat == SampleFormat.PcmFloat)
|
||||
{
|
||||
dataSourceDetailType = PerformanceDetailType.PcmFloat;
|
||||
}
|
||||
@@ -340,18 +348,18 @@ namespace Ryujinx.Audio.Renderer.Server
|
||||
GeneratePerformance(ref performanceEntry, PerformanceCommand.Type.Start, nodeId);
|
||||
}
|
||||
|
||||
GenerateDataSource(ref voiceState, dspStateMemory, channelIndex);
|
||||
GenerateDataSource(ref voiceInfo, dspStateMemory, channelIndex);
|
||||
|
||||
if (performanceInitialized)
|
||||
{
|
||||
GeneratePerformance(ref performanceEntry, PerformanceCommand.Type.End, nodeId);
|
||||
}
|
||||
|
||||
if (voiceState.WasPlaying)
|
||||
if (voiceInfo.WasPlaying)
|
||||
{
|
||||
voiceState.PreviousVolume = 0.0f;
|
||||
voiceInfo.PreviousVolume = 0.0f;
|
||||
}
|
||||
else if (voiceState.HasAnyDestination())
|
||||
else if (voiceInfo.HasAnyDestination())
|
||||
{
|
||||
performanceInitialized = false;
|
||||
|
||||
@@ -362,7 +370,7 @@ namespace Ryujinx.Audio.Renderer.Server
|
||||
GeneratePerformance(ref performanceEntry, PerformanceCommand.Type.Start, nodeId);
|
||||
}
|
||||
|
||||
GenerateBiquadFilterForVoice(ref voiceState, dspStateMemory, (int)_rendererContext.MixBufferCount, channelIndex, nodeId);
|
||||
GenerateBiquadFilterForVoice(ref voiceInfo, dspStateMemory, (int)_rendererContext.MixBufferCount, channelIndex, nodeId);
|
||||
|
||||
if (performanceInitialized)
|
||||
{
|
||||
@@ -379,8 +387,8 @@ namespace Ryujinx.Audio.Renderer.Server
|
||||
}
|
||||
|
||||
_commandBuffer.GenerateVolumeRamp(
|
||||
voiceState.PreviousVolume,
|
||||
voiceState.Volume,
|
||||
voiceInfo.PreviousVolume,
|
||||
voiceInfo.Volume,
|
||||
_rendererContext.MixBufferCount + (uint)channelIndex,
|
||||
nodeId);
|
||||
|
||||
@@ -389,17 +397,17 @@ namespace Ryujinx.Audio.Renderer.Server
|
||||
GeneratePerformance(ref performanceEntry, PerformanceCommand.Type.End, nodeId);
|
||||
}
|
||||
|
||||
voiceState.PreviousVolume = voiceState.Volume;
|
||||
voiceInfo.PreviousVolume = voiceInfo.Volume;
|
||||
|
||||
if (voiceState.MixId == Constants.UnusedMixId)
|
||||
if (voiceInfo.MixId == Constants.UnusedMixId)
|
||||
{
|
||||
if (voiceState.SplitterId != Constants.UnusedSplitterId)
|
||||
if (voiceInfo.SplitterId != Constants.UnusedSplitterId)
|
||||
{
|
||||
int destinationId = channelIndex;
|
||||
|
||||
while (true)
|
||||
{
|
||||
SplitterDestination destination = _splitterContext.GetDestination((int)voiceState.SplitterId, destinationId);
|
||||
SplitterDestination destination = _splitterContext.GetDestination((int)voiceInfo.SplitterId, destinationId);
|
||||
|
||||
if (destination.IsNull)
|
||||
{
|
||||
@@ -414,7 +422,7 @@ namespace Ryujinx.Audio.Renderer.Server
|
||||
|
||||
if (mixId < _mixContext.GetCount() && mixId != Constants.UnusedSplitterIdInt)
|
||||
{
|
||||
ref MixState mix = ref _mixContext.GetState(mixId);
|
||||
ref MixInfo mix = ref _mixContext.GetState(mixId);
|
||||
|
||||
if (destination.IsBiquadFilterEnabled())
|
||||
{
|
||||
@@ -446,7 +454,7 @@ namespace Ryujinx.Audio.Renderer.Server
|
||||
}
|
||||
else
|
||||
{
|
||||
ref MixState mix = ref _mixContext.GetState(voiceState.MixId);
|
||||
ref MixInfo mix = ref _mixContext.GetState(voiceInfo.MixId);
|
||||
|
||||
performanceInitialized = false;
|
||||
|
||||
@@ -474,9 +482,9 @@ namespace Ryujinx.Audio.Renderer.Server
|
||||
channelResource.UpdateState();
|
||||
}
|
||||
|
||||
for (int i = 0; i < voiceState.BiquadFilterNeedInitialization.Length; i++)
|
||||
for (int i = 0; i < voiceInfo.BiquadFilterNeedInitialization.Length; i++)
|
||||
{
|
||||
voiceState.BiquadFilterNeedInitialization[i] = voiceState.BiquadFilters[i].Enable;
|
||||
voiceInfo.BiquadFilterNeedInitialization[i] = biquadFiltersSpan[i].Enable;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -486,11 +494,11 @@ namespace Ryujinx.Audio.Renderer.Server
|
||||
{
|
||||
for (int i = 0; i < _voiceContext.GetCount(); i++)
|
||||
{
|
||||
ref VoiceState sortedState = ref _voiceContext.GetSortedState(i);
|
||||
ref VoiceInfo sortedInfo = ref _voiceContext.GetSortedState(i);
|
||||
|
||||
if (!sortedState.ShouldSkip() && sortedState.UpdateForCommandGeneration(_voiceContext))
|
||||
if (!sortedInfo.ShouldSkip() && sortedInfo.UpdateForCommandGeneration(_voiceContext))
|
||||
{
|
||||
int nodeId = sortedState.NodeId;
|
||||
int nodeId = sortedInfo.NodeId;
|
||||
|
||||
PerformanceEntryAddresses performanceEntry = new();
|
||||
|
||||
@@ -503,7 +511,7 @@ namespace Ryujinx.Audio.Renderer.Server
|
||||
GeneratePerformance(ref performanceEntry, PerformanceCommand.Type.Start, nodeId);
|
||||
}
|
||||
|
||||
GenerateVoice(ref sortedState);
|
||||
GenerateVoice(ref sortedInfo);
|
||||
|
||||
if (performanceInitialized)
|
||||
{
|
||||
@@ -526,15 +534,19 @@ namespace Ryujinx.Audio.Renderer.Server
|
||||
|
||||
if (effect.IsEnabled)
|
||||
{
|
||||
Span<float> volumesSpan = effect.Parameter.Volumes.AsSpan();
|
||||
Span<byte> inputSpan = effect.Parameter.Input.AsSpan();
|
||||
Span<byte> outputSpan = effect.Parameter.Output.AsSpan();
|
||||
|
||||
for (int i = 0; i < effect.Parameter.MixesCount; i++)
|
||||
{
|
||||
if (effect.Parameter.Volumes[i] != 0.0f)
|
||||
if (volumesSpan[i] != 0.0f)
|
||||
{
|
||||
_commandBuffer.GenerateMix(
|
||||
(uint)bufferOffset + effect.Parameter.Input[i],
|
||||
(uint)bufferOffset + effect.Parameter.Output[i],
|
||||
(uint)bufferOffset + inputSpan[i],
|
||||
(uint)bufferOffset + outputSpan[i],
|
||||
nodeId,
|
||||
effect.Parameter.Volumes[i]);
|
||||
volumesSpan[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -554,6 +566,10 @@ namespace Ryujinx.Audio.Renderer.Server
|
||||
{
|
||||
int i = 0;
|
||||
uint writeOffset = 0;
|
||||
|
||||
Span<byte> inputSpan = effect.Parameter.Input.AsSpan();
|
||||
Span<byte> outputSpan = effect.Parameter.Output.AsSpan();
|
||||
|
||||
for (uint channelIndex = effect.Parameter.ChannelCount; channelIndex != 0; channelIndex--)
|
||||
{
|
||||
uint newUpdateCount = writeOffset + _commandBuffer.CommandList.SampleCount;
|
||||
@@ -571,8 +587,8 @@ namespace Ryujinx.Audio.Renderer.Server
|
||||
|
||||
_commandBuffer.GenerateAuxEffect(
|
||||
bufferOffset,
|
||||
effect.Parameter.Input[i],
|
||||
effect.Parameter.Output[i],
|
||||
inputSpan[i],
|
||||
outputSpan[i],
|
||||
ref effect.State,
|
||||
effect.IsEnabled,
|
||||
effect.Parameter.BufferStorageSize,
|
||||
@@ -619,13 +635,16 @@ namespace Ryujinx.Audio.Renderer.Server
|
||||
private void GenerateBiquadFilterEffect(uint bufferOffset, BiquadFilterEffect effect, int nodeId)
|
||||
{
|
||||
Debug.Assert(effect.Type == EffectType.BiquadFilter);
|
||||
|
||||
Span<byte> inputSpan = effect.Parameter.Input.AsSpan();
|
||||
Span<byte> outputSpan = effect.Parameter.Output.AsSpan();
|
||||
|
||||
if (effect.IsEnabled)
|
||||
{
|
||||
bool needInitialization = effect.Parameter.Status == UsageState.Invalid ||
|
||||
(effect.Parameter.Status == UsageState.New && !_rendererContext.BehaviourContext.IsBiquadFilterEffectStateClearBugFixed());
|
||||
(effect.Parameter.Status == UsageState.New && !_rendererContext.BehaviourInfo.IsBiquadFilterEffectStateClearBugFixed());
|
||||
|
||||
BiquadFilterParameter parameter = new()
|
||||
BiquadFilterParameter2 parameter = new()
|
||||
{
|
||||
Enable = true,
|
||||
};
|
||||
@@ -639,8 +658,8 @@ namespace Ryujinx.Audio.Renderer.Server
|
||||
(int)bufferOffset,
|
||||
ref parameter,
|
||||
effect.State.Slice(i, 1),
|
||||
effect.Parameter.Input[i],
|
||||
effect.Parameter.Output[i],
|
||||
inputSpan[i],
|
||||
outputSpan[i],
|
||||
needInitialization,
|
||||
nodeId);
|
||||
}
|
||||
@@ -649,8 +668,8 @@ namespace Ryujinx.Audio.Renderer.Server
|
||||
{
|
||||
for (int i = 0; i < effect.Parameter.ChannelCount; i++)
|
||||
{
|
||||
uint inputBufferIndex = bufferOffset + effect.Parameter.Input[i];
|
||||
uint outputBufferIndex = bufferOffset + effect.Parameter.Output[i];
|
||||
uint inputBufferIndex = bufferOffset + inputSpan[i];
|
||||
uint outputBufferIndex = bufferOffset + outputSpan[i];
|
||||
|
||||
// If the input and output isn't the same, generate a command.
|
||||
if (inputBufferIndex != outputBufferIndex)
|
||||
@@ -667,7 +686,7 @@ namespace Ryujinx.Audio.Renderer.Server
|
||||
|
||||
ulong workBuffer = effect.GetWorkBuffer(-1);
|
||||
|
||||
if (_rendererContext.BehaviourContext.IsEffectInfoVersion2Supported())
|
||||
if (_rendererContext.BehaviourInfo.IsEffectInfoVersion2Supported())
|
||||
{
|
||||
Memory<EffectResultState> dspResultState;
|
||||
|
||||
@@ -701,6 +720,8 @@ namespace Ryujinx.Audio.Renderer.Server
|
||||
{
|
||||
int i = 0;
|
||||
uint writeOffset = 0;
|
||||
|
||||
Span<byte> inputSpan = effect.Parameter.Input.AsSpan();
|
||||
|
||||
for (uint channelIndex = effect.Parameter.ChannelCount; channelIndex != 0; channelIndex--)
|
||||
{
|
||||
@@ -719,7 +740,7 @@ namespace Ryujinx.Audio.Renderer.Server
|
||||
|
||||
_commandBuffer.GenerateCaptureEffect(
|
||||
bufferOffset,
|
||||
effect.Parameter.Input[i],
|
||||
inputSpan[i],
|
||||
effect.State.SendBufferInfo,
|
||||
effect.IsEnabled,
|
||||
effect.Parameter.BufferStorageSize,
|
||||
@@ -759,7 +780,7 @@ namespace Ryujinx.Audio.Renderer.Server
|
||||
nodeId);
|
||||
}
|
||||
|
||||
private void GenerateEffect(ref MixState mix, int effectId, BaseEffect effect)
|
||||
private void GenerateEffect(ref MixInfo mix, int effectId, BaseEffect effect)
|
||||
{
|
||||
int nodeId = mix.NodeId;
|
||||
|
||||
@@ -789,13 +810,13 @@ namespace Ryujinx.Audio.Renderer.Server
|
||||
GenerateAuxEffect(mix.BufferOffset, (AuxiliaryBufferEffect)effect, nodeId);
|
||||
break;
|
||||
case EffectType.Delay:
|
||||
GenerateDelayEffect(mix.BufferOffset, (DelayEffect)effect, nodeId, _rendererContext.BehaviourContext.IsNewEffectChannelMappingSupported());
|
||||
GenerateDelayEffect(mix.BufferOffset, (DelayEffect)effect, nodeId, _rendererContext.BehaviourInfo.IsNewEffectChannelMappingSupported());
|
||||
break;
|
||||
case EffectType.Reverb:
|
||||
GenerateReverbEffect(mix.BufferOffset, (ReverbEffect)effect, nodeId, mix.IsLongSizePreDelaySupported, _rendererContext.BehaviourContext.IsNewEffectChannelMappingSupported());
|
||||
GenerateReverbEffect(mix.BufferOffset, (ReverbEffect)effect, nodeId, mix.IsLongSizePreDelaySupported, _rendererContext.BehaviourInfo.IsNewEffectChannelMappingSupported());
|
||||
break;
|
||||
case EffectType.Reverb3d:
|
||||
GenerateReverb3dEffect(mix.BufferOffset, (Reverb3dEffect)effect, nodeId, _rendererContext.BehaviourContext.IsNewEffectChannelMappingSupported());
|
||||
GenerateReverb3dEffect(mix.BufferOffset, (Reverb3dEffect)effect, nodeId, _rendererContext.BehaviourInfo.IsNewEffectChannelMappingSupported());
|
||||
break;
|
||||
case EffectType.BiquadFilter:
|
||||
GenerateBiquadFilterEffect(mix.BufferOffset, (BiquadFilterEffect)effect, nodeId);
|
||||
@@ -821,7 +842,7 @@ namespace Ryujinx.Audio.Renderer.Server
|
||||
effect.UpdateForCommandGeneration();
|
||||
}
|
||||
|
||||
private void GenerateEffects(ref MixState mix)
|
||||
private void GenerateEffects(ref MixInfo mix)
|
||||
{
|
||||
ReadOnlySpan<int> effectProcessingOrderArray = mix.EffectProcessingOrderArray;
|
||||
|
||||
@@ -857,8 +878,8 @@ namespace Ryujinx.Audio.Renderer.Server
|
||||
ref bool isFirstMixBuffer,
|
||||
int nodeId)
|
||||
{
|
||||
ref BiquadFilterParameter bqf0 = ref destination.GetBiquadFilterParameter(0);
|
||||
ref BiquadFilterParameter bqf1 = ref destination.GetBiquadFilterParameter(1);
|
||||
ref BiquadFilterParameter2 bqf0 = ref destination.GetBiquadFilterParameter(0);
|
||||
ref BiquadFilterParameter2 bqf1 = ref destination.GetBiquadFilterParameter(1);
|
||||
|
||||
Memory<BiquadFilterState> bqfState = _splitterContext.GetBiquadFilterState(destination);
|
||||
|
||||
@@ -870,7 +891,7 @@ namespace Ryujinx.Audio.Renderer.Server
|
||||
inputBufferIndex,
|
||||
outputBufferIndex,
|
||||
0,
|
||||
Memory<VoiceUpdateState>.Empty,
|
||||
Memory<VoiceState>.Empty,
|
||||
ref bqf0,
|
||||
ref bqf1,
|
||||
bqfState[..1],
|
||||
@@ -894,7 +915,7 @@ namespace Ryujinx.Audio.Renderer.Server
|
||||
inputBufferIndex,
|
||||
outputBufferIndex,
|
||||
0,
|
||||
Memory<VoiceUpdateState>.Empty,
|
||||
Memory<VoiceState>.Empty,
|
||||
ref bqf0,
|
||||
bqfState[..1],
|
||||
bqfState.Slice(1, 1),
|
||||
@@ -913,7 +934,7 @@ namespace Ryujinx.Audio.Renderer.Server
|
||||
inputBufferIndex,
|
||||
outputBufferIndex,
|
||||
0,
|
||||
Memory<VoiceUpdateState>.Empty,
|
||||
Memory<VoiceState>.Empty,
|
||||
ref bqf1,
|
||||
bqfState[..1],
|
||||
bqfState.Slice(1, 1),
|
||||
@@ -928,7 +949,7 @@ namespace Ryujinx.Audio.Renderer.Server
|
||||
isFirstMixBuffer = false;
|
||||
}
|
||||
|
||||
private void GenerateMix(ref MixState mix)
|
||||
private void GenerateMix(ref MixInfo mix)
|
||||
{
|
||||
if (mix.HasAnyDestination())
|
||||
{
|
||||
@@ -957,7 +978,7 @@ namespace Ryujinx.Audio.Renderer.Server
|
||||
|
||||
if (mixId < _mixContext.GetCount() && mixId != Constants.UnusedSplitterIdInt)
|
||||
{
|
||||
ref MixState destinationMix = ref _mixContext.GetState(mixId);
|
||||
ref MixInfo destinationMix = ref _mixContext.GetState(mixId);
|
||||
|
||||
uint inputBufferIndex = mix.BufferOffset + ((uint)destinationIndex % mix.BufferCount);
|
||||
|
||||
@@ -996,7 +1017,7 @@ namespace Ryujinx.Audio.Renderer.Server
|
||||
}
|
||||
else
|
||||
{
|
||||
ref MixState destinationMix = ref _mixContext.GetState(mix.DestinationMixId);
|
||||
ref MixInfo destinationMix = ref _mixContext.GetState(mix.DestinationMixId);
|
||||
|
||||
for (uint bufferIndex = 0; bufferIndex < mix.BufferCount; bufferIndex++)
|
||||
{
|
||||
@@ -1018,7 +1039,7 @@ namespace Ryujinx.Audio.Renderer.Server
|
||||
}
|
||||
}
|
||||
|
||||
private void GenerateSubMix(ref MixState subMix)
|
||||
private void GenerateSubMix(ref MixInfo subMix)
|
||||
{
|
||||
_commandBuffer.GenerateDepopForMixBuffers(
|
||||
_rendererContext.DepopBuffer,
|
||||
@@ -1054,11 +1075,11 @@ namespace Ryujinx.Audio.Renderer.Server
|
||||
{
|
||||
for (int id = 0; id < _mixContext.GetCount(); id++)
|
||||
{
|
||||
ref MixState sortedState = ref _mixContext.GetSortedState(id);
|
||||
ref MixInfo sortedInfo = ref _mixContext.GetSortedState(id);
|
||||
|
||||
if (sortedState.IsUsed && sortedState.MixId != Constants.FinalMixId)
|
||||
if (sortedInfo.IsUsed && sortedInfo.MixId != Constants.FinalMixId)
|
||||
{
|
||||
int nodeId = sortedState.NodeId;
|
||||
int nodeId = sortedInfo.NodeId;
|
||||
|
||||
PerformanceEntryAddresses performanceEntry = new();
|
||||
|
||||
@@ -1071,7 +1092,7 @@ namespace Ryujinx.Audio.Renderer.Server
|
||||
GeneratePerformance(ref performanceEntry, PerformanceCommand.Type.Start, nodeId);
|
||||
}
|
||||
|
||||
GenerateSubMix(ref sortedState);
|
||||
GenerateSubMix(ref sortedInfo);
|
||||
|
||||
if (performanceInitialized)
|
||||
{
|
||||
@@ -1083,7 +1104,7 @@ namespace Ryujinx.Audio.Renderer.Server
|
||||
|
||||
private void GenerateFinalMix()
|
||||
{
|
||||
ref MixState finalMix = ref _mixContext.GetFinalState();
|
||||
ref MixInfo finalMix = ref _mixContext.GetFinalState();
|
||||
|
||||
_commandBuffer.GenerateDepopForMixBuffers(
|
||||
_rendererContext.DepopBuffer,
|
||||
@@ -1162,16 +1183,16 @@ namespace Ryujinx.Audio.Renderer.Server
|
||||
}
|
||||
}
|
||||
|
||||
private void GenerateCircularBuffer(CircularBufferSink sink, ref MixState finalMix)
|
||||
private void GenerateCircularBuffer(CircularBufferSink sink, ref MixInfo finalMix)
|
||||
{
|
||||
_commandBuffer.GenerateCircularBuffer(finalMix.BufferOffset, sink, Constants.InvalidNodeId);
|
||||
}
|
||||
|
||||
private void GenerateDevice(DeviceSink sink, ref MixState finalMix)
|
||||
private void GenerateDevice(DeviceSink sink, ref MixInfo finalMix)
|
||||
{
|
||||
if (_commandBuffer.CommandList.SampleRate != 48000 && sink.UpsamplerState == null)
|
||||
if (_commandBuffer.CommandList.SampleRate != 48000 && sink.UpsamplerInfo == null)
|
||||
{
|
||||
sink.UpsamplerState = _rendererContext.UpsamplerManager.Allocate();
|
||||
sink.UpsamplerInfo = _rendererContext.UpsamplerManager.Allocate();
|
||||
}
|
||||
|
||||
bool useCustomDownMixingCommand = _rendererContext.ChannelCount == 2 && sink.Parameter.DownMixParameterEnabled;
|
||||
@@ -1198,11 +1219,11 @@ namespace Ryujinx.Audio.Renderer.Server
|
||||
|
||||
CommandList commandList = _commandBuffer.CommandList;
|
||||
|
||||
if (sink.UpsamplerState != null)
|
||||
if (sink.UpsamplerInfo != null)
|
||||
{
|
||||
_commandBuffer.GenerateUpsample(
|
||||
finalMix.BufferOffset,
|
||||
sink.UpsamplerState,
|
||||
sink.UpsamplerInfo,
|
||||
sink.Parameter.InputCount,
|
||||
sink.Parameter.Input.AsSpan(),
|
||||
commandList.BufferCount,
|
||||
@@ -1219,7 +1240,7 @@ namespace Ryujinx.Audio.Renderer.Server
|
||||
Constants.InvalidNodeId);
|
||||
}
|
||||
|
||||
private void GenerateSink(BaseSink sink, ref MixState finalMix)
|
||||
private void GenerateSink(BaseSink sink, ref MixInfo finalMix)
|
||||
{
|
||||
bool performanceInitialized = false;
|
||||
|
||||
@@ -1257,7 +1278,7 @@ namespace Ryujinx.Audio.Renderer.Server
|
||||
|
||||
public void GenerateSinks()
|
||||
{
|
||||
ref MixState finalMix = ref _mixContext.GetFinalState();
|
||||
ref MixInfo finalMix = ref _mixContext.GetFinalState();
|
||||
|
||||
for (int i = 0; i < _sinkContext.GetCount(); i++)
|
||||
{
|
||||
|
||||
@@ -194,5 +194,10 @@ namespace Ryujinx.Audio.Renderer.Server
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
public uint Estimate(FillBufferCommand command)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -486,5 +486,10 @@ namespace Ryujinx.Audio.Renderer.Server
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
public uint Estimate(FillBufferCommand command)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ using Ryujinx.Audio.Renderer.Dsp.Command;
|
||||
using Ryujinx.Audio.Renderer.Parameter.Effect;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using static Ryujinx.Audio.Renderer.Parameter.VoiceInParameter;
|
||||
using Ryujinx.Audio.Renderer.Parameter;
|
||||
|
||||
namespace Ryujinx.Audio.Renderer.Server
|
||||
{
|
||||
@@ -656,5 +656,10 @@ namespace Ryujinx.Audio.Renderer.Server
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
public virtual uint Estimate(FillBufferCommand command)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -286,5 +286,10 @@ namespace Ryujinx.Audio.Renderer.Server
|
||||
return 8683;
|
||||
}
|
||||
}
|
||||
|
||||
public override uint Estimate(FillBufferCommand command)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -174,6 +174,19 @@ namespace Ryujinx.Audio.Renderer.Server.Effect
|
||||
|
||||
updateErrorInfo = new ErrorInfo();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Update the internal state from a user version 3 parameter.
|
||||
/// </summary>
|
||||
/// <param name="updateErrorInfo">The possible <see cref="ErrorInfo"/> that was generated.</param>
|
||||
/// <param name="parameter">The user parameter.</param>
|
||||
/// <param name="mapper">The mapper to use.</param>
|
||||
public virtual void Update(out ErrorInfo updateErrorInfo, in EffectInParameterVersion3 parameter, PoolMapper mapper)
|
||||
{
|
||||
Debug.Assert(IsTypeValid(in parameter));
|
||||
|
||||
updateErrorInfo = new ErrorInfo();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the work buffer DSP address at the given index.
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using Ryujinx.Audio.Renderer.Common;
|
||||
using Ryujinx.Audio.Renderer.Dsp;
|
||||
using Ryujinx.Audio.Renderer.Dsp.State;
|
||||
using Ryujinx.Audio.Renderer.Parameter;
|
||||
using Ryujinx.Audio.Renderer.Parameter.Effect;
|
||||
@@ -17,7 +18,7 @@ namespace Ryujinx.Audio.Renderer.Server.Effect
|
||||
/// <summary>
|
||||
/// The biquad filter parameter.
|
||||
/// </summary>
|
||||
public BiquadFilterEffectParameter Parameter;
|
||||
public BiquadFilterEffectParameter2 Parameter;
|
||||
|
||||
/// <summary>
|
||||
/// The biquad filter state.
|
||||
@@ -29,7 +30,7 @@ namespace Ryujinx.Audio.Renderer.Server.Effect
|
||||
/// </summary>
|
||||
public BiquadFilterEffect()
|
||||
{
|
||||
Parameter = new BiquadFilterEffectParameter();
|
||||
Parameter = new BiquadFilterEffectParameter2();
|
||||
State = new BiquadFilterState[Constants.ChannelCountMax];
|
||||
}
|
||||
|
||||
@@ -44,6 +45,11 @@ namespace Ryujinx.Audio.Renderer.Server.Effect
|
||||
{
|
||||
Update(out updateErrorInfo, in parameter, mapper);
|
||||
}
|
||||
|
||||
public override void Update(out BehaviourParameter.ErrorInfo updateErrorInfo, in EffectInParameterVersion3 parameter, PoolMapper mapper)
|
||||
{
|
||||
Update(out updateErrorInfo, in parameter, mapper);
|
||||
}
|
||||
|
||||
public void Update<T>(out BehaviourParameter.ErrorInfo updateErrorInfo, in T parameter, PoolMapper mapper) where T : unmanaged, IEffectInParameter
|
||||
{
|
||||
@@ -51,7 +57,17 @@ namespace Ryujinx.Audio.Renderer.Server.Effect
|
||||
|
||||
UpdateParameterBase(in parameter);
|
||||
|
||||
Parameter = MemoryMarshal.Cast<byte, BiquadFilterEffectParameter>(parameter.SpecificData)[0];
|
||||
if (typeof(T) == typeof(EffectInParameterVersion3))
|
||||
{
|
||||
Parameter = MemoryMarshal.Cast<byte, BiquadFilterEffectParameter2>(parameter.SpecificData)[0];
|
||||
}
|
||||
else
|
||||
{
|
||||
BiquadFilterEffectParameter1 oldParameter =
|
||||
MemoryMarshal.Cast<byte, BiquadFilterEffectParameter1>(parameter.SpecificData)[0];
|
||||
Parameter = BiquadFilterHelper.ToBiquadFilterEffectParameter2(oldParameter);
|
||||
}
|
||||
|
||||
IsEnabled = parameter.IsEnabled;
|
||||
|
||||
updateErrorInfo = new BehaviourParameter.ErrorInfo();
|
||||
|
||||
@@ -38,5 +38,6 @@ namespace Ryujinx.Audio.Renderer.Server
|
||||
uint Estimate(CompressorCommand command);
|
||||
uint Estimate(BiquadFilterAndMixCommand command);
|
||||
uint Estimate(MultiTapBiquadFilterAndMixCommand command);
|
||||
uint Estimate(FillBufferCommand command);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,14 +20,14 @@ namespace Ryujinx.Audio.Renderer.Server.MemoryPool
|
||||
/// </summary>
|
||||
public ulong Size;
|
||||
|
||||
private unsafe MemoryPoolState* _memoryPools;
|
||||
private unsafe MemoryPoolInfo* _memoryPools;
|
||||
|
||||
/// <summary>
|
||||
/// The forced DSP address of the region.
|
||||
/// </summary>
|
||||
public DspAddress ForceMappedDspAddress;
|
||||
|
||||
private readonly unsafe ref MemoryPoolState MemoryPoolState => ref *_memoryPools;
|
||||
private readonly unsafe ref MemoryPoolInfo MemoryPoolInfo => ref *_memoryPools;
|
||||
|
||||
public readonly unsafe bool HasMemoryPoolState => (nint)_memoryPools != nint.Zero;
|
||||
|
||||
@@ -53,7 +53,7 @@ namespace Ryujinx.Audio.Renderer.Server.MemoryPool
|
||||
return new AddressInfo
|
||||
{
|
||||
CpuAddress = cpuAddress,
|
||||
_memoryPools = MemoryPoolState.Null,
|
||||
_memoryPools = MemoryPoolInfo.Null,
|
||||
Size = size,
|
||||
ForceMappedDspAddress = 0,
|
||||
};
|
||||
@@ -73,19 +73,19 @@ namespace Ryujinx.Audio.Renderer.Server.MemoryPool
|
||||
|
||||
unsafe
|
||||
{
|
||||
_memoryPools = MemoryPoolState.Null;
|
||||
_memoryPools = MemoryPoolInfo.Null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set the <see cref="MemoryPoolState"/> associated.
|
||||
/// Set the <see cref="MemoryPoolInfo"/> associated.
|
||||
/// </summary>
|
||||
/// <param name="memoryPoolState">The <see cref="MemoryPoolState"/> associated.</param>
|
||||
public void SetupMemoryPool(Span<MemoryPoolState> memoryPoolState)
|
||||
/// <param name="memoryPoolState">The <see cref="MemoryPoolInfo"/> associated.</param>
|
||||
public void SetupMemoryPool(Span<MemoryPoolInfo> memoryPoolState)
|
||||
{
|
||||
unsafe
|
||||
{
|
||||
fixed (MemoryPoolState* ptr = &MemoryMarshal.GetReference(memoryPoolState))
|
||||
fixed (MemoryPoolInfo* ptr = &MemoryMarshal.GetReference(memoryPoolState))
|
||||
{
|
||||
SetupMemoryPool(ptr);
|
||||
}
|
||||
@@ -93,27 +93,27 @@ namespace Ryujinx.Audio.Renderer.Server.MemoryPool
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set the <see cref="MemoryPoolState"/> associated.
|
||||
/// Set the <see cref="MemoryPoolInfo"/> associated.
|
||||
/// </summary>
|
||||
/// <param name="memoryPoolState">The <see cref="MemoryPoolState"/> associated.</param>
|
||||
public unsafe void SetupMemoryPool(MemoryPoolState* memoryPoolState)
|
||||
/// <param name="memoryPoolState">The <see cref="MemoryPoolInfo"/> associated.</param>
|
||||
public unsafe void SetupMemoryPool(MemoryPoolInfo* memoryPoolState)
|
||||
{
|
||||
_memoryPools = memoryPoolState;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check if the <see cref="MemoryPoolState"/> is mapped.
|
||||
/// Check if the <see cref="MemoryPoolInfo"/> is mapped.
|
||||
/// </summary>
|
||||
/// <returns>Returns true if the <see cref="MemoryPoolState"/> is mapped.</returns>
|
||||
/// <returns>Returns true if the <see cref="MemoryPoolInfo"/> is mapped.</returns>
|
||||
public readonly bool HasMappedMemoryPool()
|
||||
{
|
||||
return HasMemoryPoolState && MemoryPoolState.IsMapped();
|
||||
return HasMemoryPoolState && MemoryPoolInfo.IsMapped();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the DSP address associated to the <see cref="AddressInfo"/>.
|
||||
/// </summary>
|
||||
/// <param name="markUsed">If true, mark the <see cref="MemoryPoolState"/> as used.</param>
|
||||
/// <param name="markUsed">If true, mark the <see cref="MemoryPoolInfo"/> as used.</param>
|
||||
/// <returns>Returns the DSP address associated to the <see cref="AddressInfo"/>.</returns>
|
||||
public readonly DspAddress GetReference(bool markUsed)
|
||||
{
|
||||
@@ -124,10 +124,10 @@ namespace Ryujinx.Audio.Renderer.Server.MemoryPool
|
||||
|
||||
if (markUsed)
|
||||
{
|
||||
MemoryPoolState.IsUsed = true;
|
||||
MemoryPoolInfo.IsUsed = true;
|
||||
}
|
||||
|
||||
return MemoryPoolState.Translate(CpuAddress, Size);
|
||||
return MemoryPoolInfo.Translate(CpuAddress, Size);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,62 +8,62 @@ namespace Ryujinx.Audio.Renderer.Server.MemoryPool
|
||||
/// Server state for a memory pool.
|
||||
/// </summary>
|
||||
[StructLayout(LayoutKind.Sequential, Size = 0x20, Pack = Alignment)]
|
||||
public struct MemoryPoolState
|
||||
public struct MemoryPoolInfo
|
||||
{
|
||||
public const int Alignment = 0x10;
|
||||
|
||||
/// <summary>
|
||||
/// The location of the <see cref="MemoryPoolState"/>.
|
||||
/// The location of the <see cref="MemoryPoolInfo"/>.
|
||||
/// </summary>
|
||||
public enum LocationType : uint
|
||||
{
|
||||
/// <summary>
|
||||
/// <see cref="MemoryPoolState"/> located on the CPU side for user use.
|
||||
/// <see cref="MemoryPoolInfo"/> located on the CPU side for user use.
|
||||
/// </summary>
|
||||
Cpu,
|
||||
|
||||
/// <summary>
|
||||
/// <see cref="MemoryPoolState"/> located on the DSP side for system use.
|
||||
/// <see cref="MemoryPoolInfo"/> located on the DSP side for system use.
|
||||
/// </summary>
|
||||
Dsp,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The CPU address associated to the <see cref="MemoryPoolState"/>.
|
||||
/// The CPU address associated to the <see cref="MemoryPoolInfo"/>.
|
||||
/// </summary>
|
||||
public CpuAddress CpuAddress;
|
||||
|
||||
/// <summary>
|
||||
/// The DSP address associated to the <see cref="MemoryPoolState"/>.
|
||||
/// The DSP address associated to the <see cref="MemoryPoolInfo"/>.
|
||||
/// </summary>
|
||||
public DspAddress DspAddress;
|
||||
|
||||
/// <summary>
|
||||
/// The size associated to the <see cref="MemoryPoolState"/>.
|
||||
/// The size associated to the <see cref="MemoryPoolInfo"/>.
|
||||
/// </summary>
|
||||
public ulong Size;
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="LocationType"/> associated to the <see cref="MemoryPoolState"/>.
|
||||
/// The <see cref="LocationType"/> associated to the <see cref="MemoryPoolInfo"/>.
|
||||
/// </summary>
|
||||
public LocationType Location;
|
||||
|
||||
/// <summary>
|
||||
/// Set to true if the <see cref="MemoryPoolState"/> is used.
|
||||
/// Set to true if the <see cref="MemoryPoolInfo"/> is used.
|
||||
/// </summary>
|
||||
[MarshalAs(UnmanagedType.I1)]
|
||||
public bool IsUsed;
|
||||
|
||||
public static unsafe MemoryPoolState* Null => (MemoryPoolState*)nint.Zero.ToPointer();
|
||||
public static unsafe MemoryPoolInfo* Null => (MemoryPoolInfo*)nint.Zero.ToPointer();
|
||||
|
||||
/// <summary>
|
||||
/// Create a new <see cref="MemoryPoolState"/> with the given <see cref="LocationType"/>.
|
||||
/// Create a new <see cref="MemoryPoolInfo"/> with the given <see cref="LocationType"/>.
|
||||
/// </summary>
|
||||
/// <param name="location">The location type to use.</param>
|
||||
/// <returns>A new <see cref="MemoryPoolState"/> with the given <see cref="LocationType"/>.</returns>
|
||||
public static MemoryPoolState Create(LocationType location)
|
||||
/// <returns>A new <see cref="MemoryPoolInfo"/> with the given <see cref="LocationType"/>.</returns>
|
||||
public static MemoryPoolInfo Create(LocationType location)
|
||||
{
|
||||
return new MemoryPoolState
|
||||
return new MemoryPoolInfo
|
||||
{
|
||||
CpuAddress = 0,
|
||||
DspAddress = 0,
|
||||
@@ -73,7 +73,7 @@ namespace Ryujinx.Audio.Renderer.Server.MemoryPool
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set the <see cref="CpuAddress"/> and size of the <see cref="MemoryPoolState"/>.
|
||||
/// Set the <see cref="CpuAddress"/> and size of the <see cref="MemoryPoolInfo"/>.
|
||||
/// </summary>
|
||||
/// <param name="cpuAddress">The <see cref="CpuAddress"/>.</param>
|
||||
/// <param name="size">The size.</param>
|
||||
@@ -84,11 +84,11 @@ namespace Ryujinx.Audio.Renderer.Server.MemoryPool
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check if the given <see cref="CpuAddress"/> and size is contains in the <see cref="MemoryPoolState"/>.
|
||||
/// Check if the given <see cref="CpuAddress"/> and size is contains in the <see cref="MemoryPoolInfo"/>.
|
||||
/// </summary>
|
||||
/// <param name="targetCpuAddress">The <see cref="CpuAddress"/>.</param>
|
||||
/// <param name="size">The size.</param>
|
||||
/// <returns>True if the <see cref="CpuAddress"/> is contained inside the <see cref="MemoryPoolState"/>.</returns>
|
||||
/// <returns>True if the <see cref="CpuAddress"/> is contained inside the <see cref="MemoryPoolInfo"/>.</returns>
|
||||
public readonly bool Contains(CpuAddress targetCpuAddress, ulong size)
|
||||
{
|
||||
if (CpuAddress <= targetCpuAddress && size + targetCpuAddress <= Size + CpuAddress)
|
||||
@@ -118,9 +118,9 @@ namespace Ryujinx.Audio.Renderer.Server.MemoryPool
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Is the <see cref="MemoryPoolState"/> mapped on the DSP?
|
||||
/// Is the <see cref="MemoryPoolInfo"/> mapped on the DSP?
|
||||
/// </summary>
|
||||
/// <returns>Returns true if the <see cref="MemoryPoolState"/> is mapped on the DSP.</returns>
|
||||
/// <returns>Returns true if the <see cref="MemoryPoolInfo"/> is mapped on the DSP.</returns>
|
||||
public readonly bool IsMapped()
|
||||
{
|
||||
return DspAddress != 0;
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user