Compare commits

..

168 Commits

Author SHA1 Message Date
LotP
3c3e14c819 Update .gitattributes (ryubing/ryujinx!213)
See merge request ryubing/ryujinx!213
2025-11-09 19:03:01 -06:00
Godzilaa4
dd9ba05e36 Updated PT_BR translation (ryubing/ryujinx!208)
See merge request ryubing/ryujinx!208
2025-11-09 14:36:44 -06:00
Maki
a49822470c fix: crash when connecting a joycon (ryubing/ryujinx!211)
See merge request ryubing/ryujinx!211
2025-11-09 13:35:16 -06:00
GreemDev
58be57bf73 chore: [ci skip] rename InputElement_OnGotFocus/OnLostFocus to fit what it's listening to better 2025-11-08 03:21:54 -06:00
shinyoyo
17d5d6e65a Updated Simplified Chinese translation. (ryubing/ryujinx!209)
See merge request ryubing/ryujinx!209
2025-11-08 03:16:17 -06:00
GreemDev
1dac06e394 misc: [ci skip] remove duplicate log when setting audio backend 2025-11-08 00:18:23 -06:00
GreemDev
ed89ffd3f8 fix: add back compat functionality to the AudioBackend enum as well, and add missing migration comment from config version 70 2025-11-07 22:23:13 -06:00
GreemDev
844d7a9cfe fix: broken arrow in log 2025-11-07 22:14:35 -06:00
GreemDev
cf6acba416 chore: remove debug logging from SDL update 2025-11-07 20:44:25 -06:00
GreemDev
5a9d5ee664 chore: [ci skip] Add more misc logging similar to the "loading content archive" line for loading a base game dump, to updates and DLC. 2025-11-07 15:14:43 -06:00
GreemDev
bbad867319 add back the SDL2 enum for back compatibility so existing configs are not entirely reset upon loading the version with SDL3 2025-11-07 15:02:29 -06:00
Maki
a8ace3d23c chore: SDL3 (ryubing/ryujinx!207)
See merge request ryubing/ryujinx!207
2025-11-07 14:43:48 -06:00
GreemDev
13b69aedfe idea: Catch HorizonResultExceptions of result type ResultFsNonRealDataVerificationFailed
- log a more clear error message as to what 2002-4604 means for the user
- and return the result from the FileSystemProxy IStorage to pass the invalid data handling to the game instead of stopping emulation there and then.
  - this may be changed. i'm pretty sure this error is only thrown when you actually have integrity checking enabled in settings, so maybe it crashing with a friendler message is more desired than potentially continuing execution. we will see
2025-11-06 23:40:16 -06:00
GreemDev
234f7ca298 Fix socket closing on shutdown
Previously, sockets were only ever closed when the game specifically requested it.

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

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

(it was saved, just not loaded back)
2025-10-24 18:25:29 -05:00
Coxxs
6fd67cdcb7 Fix application list loads slowly when RyuLDN is enabled (ryubing/ryujinx!191)
See merge request ryubing/ryujinx!191
2025-10-24 10:29:33 -05:00
LotP
5ced2bf764 fix wrong bit value (ryubing/ryujinx!190)
See merge request ryubing/ryujinx!190
2025-10-24 10:10:31 -05:00
GreemDev
67e97d1a1a gdb: YACC (yet another cleanup commit) 2025-10-23 19:11:58 -05:00
Coxxs
09d8a411c8 Do not RecurseSubdirectories when finding the icon fallback (ryubing/ryujinx!189)
See merge request ryubing/ryujinx!189
2025-10-23 15:17:29 -05:00
Coxxs
93516df7e6 Skip directories when finding the icon fallback (ryubing/ryujinx!188)
See merge request ryubing/ryujinx!188
2025-10-23 14:56:39 -05:00
Coxxs
0c165c3f62 Move ProcessInfo and Minidump to HleProcessDebugger (ryubing/ryujinx!187)
See merge request ryubing/ryujinx!187
2025-10-22 16:20:13 -05:00
GreemDev
91da244c02 gdb: some more cleanups 2025-10-22 15:04:03 -05:00
GreemDev
904d4a7eb0 gdb: Make waiting for a process to start more forgiving (200ms per poll 10x -> 500ms) 2025-10-22 01:07:19 -05:00
Coxxs
1248a054de gdb: Abort if unable to start GDB server (ryubing/ryujinx!186)
See merge request ryubing/ryujinx!186
2025-10-21 23:16:18 -05:00
GreemDev
1bb2af84ce gdb: Catch SocketException from TcpListener#Start 2025-10-21 22:15:14 -05:00
GreemDev
886981004d chore: I thought I removed these months ago lol 2025-10-21 20:33:35 -05:00
Coxxs
e551dda17e gdb: fix IsProcess32Bit throws exception if called too early (ryubing/ryujinx!185)
See merge request ryubing/ryujinx!185
2025-10-20 21:35:55 -05:00
GreemDev
ed67535227 chore: [si skip] fix in-code typos 2025-10-20 21:32:23 -05:00
GreemDev
7d65611b96 gdb: [ci skip] just had a brain wave 2025-10-20 21:20:41 -05:00
GreemDev
71eb844dd8 gdb: dynamic rcmd system & more cleanups 2025-10-20 21:18:16 -05:00
Coxxs
a0e5edf8ba gdb: Support qAttached; Add missing ReplyOK when detach (ryubing/ryujinx!184)
See merge request ryubing/ryujinx!184
2025-10-20 21:12:16 -05:00
Coxxs
6541ad0726 Implement IUserServiceCreator: 1 (CreateClientProcessMonitor) (ryubing/ryujinx!181)
See merge request ryubing/ryujinx!181
2025-10-20 19:14:42 -05:00
Coxxs
1c084373c9 Update LoadIdTokenCache for 19.0.0+ (ryubing/ryujinx!182)
See merge request ryubing/ryujinx!182
2025-10-20 17:37:16 -05:00
GreemDev
5b3b907fd2 [ci skip] chore: Fix usage of var 2025-10-20 02:42:57 -05:00
Hack茶ん
f46577af58 [ci skip] Update Korean translation (ryubing/ryujinx!174)
See merge request ryubing/ryujinx!174
2025-10-19 17:43:34 -05:00
Xam
0e218754f5 Fix duplicate volume and mode change events in AppHost (ryubing/ryujinx!176)
See merge request ryubing/ryujinx!176
2025-10-19 17:41:21 -05:00
Xam
0c6d4a07b9 Input: AvaloniaMouseDriver: fix native touch inputs (ryubing/ryujinx!178)
See merge request ryubing/ryujinx!178
2025-10-19 17:33:24 -05:00
Xam
8714b010f6 Horizon: Audio: HwopusIpcServer: fix random crashes regression in Pokemon Quest (ryubing/ryujinx!175)
See merge request ryubing/ryujinx!175
2025-10-19 17:17:46 -05:00
GreemDev
d1d4a735a6 docs: use the real repo in COMPILING.md 2025-10-19 14:48:41 -05:00
GreemDev
247e2e03d6 gdb: More cleanup changes
- Move the message handler into its debugger class part,
- Move all message types into one file and collapse 3 of the ones with no data into a generic, stateless message with a single property being its type,
- Add an Fpscr helper property on IExecutionContext along with a comment about what Fpscr is (similar to the other registers in there)
- Moved the Rcmd helpers (such as GetRegisters, GetMinidump, etc) into a dedicated Debugger class part,
- Fixed the double-collection (ToArray being called twice) in GetThreadUids & GetThread in KProcess
2025-10-19 04:26:12 -05:00
GreemDev
6058af5119 chore: cleanup unused usings in Ryujinx.HLE 2025-10-19 04:17:02 -05:00
GreemDev
e11eff0f41 gdb: more cleanups
- convert GdbRegisters utilities into extensions on IExecutionContext

- add a Write/Read Register helper on Debugger that handles 32/64 bit instead of doing that for every usage of register reading/writing
2025-10-18 03:01:21 -05:00
GreemDev
2a2ab523cb gdb: Code cleanup pass #2
Moved the reply functionality into the command processor, move the main debugger thread into a dedicated class part, and more
2025-10-17 00:09:51 -05:00
Coxxs
8e941e4a8f gdb: Cleanup (ryubing/ryujinx!171)
See merge request ryubing/ryujinx!171
2025-10-16 19:53:51 -05:00
Hack茶ん
9aacf9b37b Update Korean translation (ryubing/ryujinx!168)
See merge request ryubing/ryujinx!168
2025-10-16 19:45:14 -05:00
Bluey Enjoyer
2b159dbca8 AHHHHHHHHHHHHHH (ryubing/ryujinx!170)
See merge request ryubing/ryujinx!170
2025-10-16 19:43:56 -05:00
GreemDev
c33a97f01c gdb: Cleanup Debugger.cs
by moving the GDB command handlers and command processor out of the class and into their own
2025-10-16 17:32:04 -05:00
GreemDev
fdbdb05cb5 misc: Update Ryujinx.LibHac 2025-10-16 12:23:15 -05:00
Coxxs
7268acbfb4 gdb: Do not skip CheckInterrupt when gdb stub is enabled (ryubing/ryujinx!169)
See merge request ryubing/ryujinx!169
2025-10-16 07:49:41 -05:00
GreemDev
d4107ac05f UI: Add a startup flag to ignore new Amiibo file updates, useful for testing changes you intend on committing to Ryubing/Nfc.
Flag is `--local-only-amiibo`
2025-10-15 21:51:13 -05:00
LotP
1d409f7127 12 GiB heap support (ryubing/ryujinx!166)
See merge request ryubing/ryujinx!166
2025-10-15 15:37:13 -05:00
GreemDev
2434c55266 UI: Updater: Fix "No" opening the changelog and "Show Changelog" doing nothing (aka doing what "No" should be doing) 2025-10-14 18:38:56 -05:00
GreemDev
99126603ba UI: swap the UI reset checkbox text back to a sentence instead of title cased 2025-10-14 16:12:11 -05:00
GreemDev
a62716002e chore: move HasPtcCacheFiles & HasShaderCacheFiles into ApplicationData, instead of having the weird static dependency helpers 2025-10-14 16:09:51 -05:00
GreemDev
47559cd311 Revert game list rounding
The selected highlight was bugged

https://fs.ryujinx.app/40cl4Ih9RiOWLVi7e4lJsw.png
2025-10-14 15:59:02 -05:00
Coxxs
51584a083b Flush the error log before exit (ryubing/ryujinx!163)
See merge request ryubing/ryujinx!163
2025-10-13 17:40:15 -05:00
Coxxs
ceec9617ef gdb: Fix the crash that occurs when GDB is connected early (ryubing/ryujinx!159)
See merge request ryubing/ryujinx!159
2025-10-11 19:06:14 -05:00
Coxxs
1865be47cf gdb: Add monitor minidump command (ryubing/ryujinx!158)
See merge request ryubing/ryujinx!158
2025-10-11 10:01:30 -05:00
LotP
ef9810582a Sync thread name on Schedule (ryubing/ryujinx!157)
See merge request ryubing/ryujinx!157
2025-10-11 07:47:45 -05:00
KeatonTheBot
13878acdb2 Avoid lookup of invalid textures if pool did not change (ryubing/ryujinx!113)
See merge request ryubing/ryujinx!113
2025-10-11 02:56:13 -05:00
LotP
e2143d43bc SDK20 and REV15 support (ryubing/ryujinx!50)
See merge request ryubing/ryujinx!50
2025-10-11 02:11:39 -05:00
Astell
4444ecae41 fix super mario galaxy 0x25E00040 error (ryubing/ryujinx!155)
See merge request ryubing/ryujinx!155
2025-10-10 17:37:42 -05:00
Neo
4f5a236c21 UI: Settings → Interface Tab + General Settings (ryubing/ryujinx!154)
See merge request ryubing/ryujinx!154
2025-10-09 16:32:33 -05:00
Lorenzo
db31ff15c7 it_IT translation update (ryubing/ryujinx!148)
See merge request ryubing/ryujinx!148
2025-10-06 20:22:15 -05:00
Bluey Enjoyer
e70cd08c9a cleanup work for my last MR/PR (ryubing/ryujinx!153)
See merge request ryubing/ryujinx!153
2025-10-04 13:07:31 -05:00
Neo
60b9723df4 UI: Main Window + General (ryubing/ryujinx!150)
See merge request ryubing/ryujinx!150
2025-10-03 16:02:37 -05:00
KeatonTheBot
1900924a78 Fix push descriptors bugfix logic for Intel Arc on Linux 2025-10-01 21:58:22 -05:00
GreemDev
5fb0b5e7ec vulkan: Intel Arc on Linux also has the push descriptors bug. 2025-10-01 13:03:22 -05:00
Bluey Enjoyer
8d0e28ed9d New RPC images and compat updates (ryubing/ryujinx!151)
See merge request ryubing/ryujinx!151
2025-10-01 12:29:27 -05:00
Babib3l
a4eafd01f5 es_ES and fr_FR translation updates (ryubing/ryujinx!129)
See merge request ryubing/ryujinx!129
2025-09-28 14:58:32 -05:00
在中国的泰国青年_
f55aa87ab9 update thai language additional (ryubing/ryujinx!108)
See merge request ryubing/ryujinx!108
2025-09-27 23:27:56 -05:00
Mcost45
bb4f8d8749 Include SL/SR default bindings for single joycons (ryubing/ryujinx!149)
See merge request ryubing/ryujinx!149
2025-09-22 14:23:40 -05:00
Alula
a6cb681f10 feat: resolve real module names in HLE debugger (ryubing/ryujinx!147)
See merge request ryubing/ryujinx!147
2025-09-20 07:05:44 -05:00
GreemDev
00ff3e6b1b chore: CI: oops missed another zsync reference 2025-09-14 01:35:05 -05:00
GreemDev
12510a5396 chore: CI: actually remove zsync files this time
I'm blind, the previous commit failed CI since it still thought they were being generated
2025-09-14 00:37:30 -05:00
GreemDev
ea30a0ed24 chore: ci: Remove .zsync 2025-09-14 00:26:09 -05:00
Coxxs
df40a69872 Fix headless mode (ryubing/ryujinx!146)
See merge request ryubing/ryujinx!146
2025-09-10 11:43:50 -05:00
LotP
b000f91dad Memory changes 2.2.1 (ryubing/ryujinx!144)
See merge request ryubing/ryujinx!144
2025-09-06 13:51:08 -05:00
LotP
a60b2a0ba3 Memory changes 2.2 (ryubing/ryujinx!143)
See merge request ryubing/ryujinx!143
2025-09-06 11:10:55 -05:00
Hack茶ん
4c9b48b754 Update Korean translation (ryubing/ryujinx!141)
See merge request ryubing/ryujinx!141
2025-09-05 13:06:59 -05:00
Neo
3bd7d5904e Compat: New Entries + Minor Adjustments (ryubing/ryujinx!140)
See merge request ryubing/ryujinx!140
2025-09-05 03:50:49 -05:00
GreemDev
23eb9a3043 improvement: Make the updater log a special error message in some cases
specifically about potentially not being connected to the internet on a connection error or name resolution error
2025-09-05 03:12:15 -05:00
GreemDev
931ec44406 [ci skip] fix: <Reset> text in Pokemon Scarlet/Violet play report rich presence 2025-09-05 03:02:16 -05:00
GreemDev
d68efa98ba [ci skip] Update NuGet packages 2025-09-05 02:25:05 -05:00
GreemDev
ded76801d1 removal: Installing keys from a zip
Also cleaned up a bit
2025-09-04 19:04:50 -05:00
GreemDev
6084df7473 Silksong compatibility entry and RPC image 2025-09-04 16:23:38 -05:00
LotP1
f3953c6039 Fix a crash when no controller is connected 2025-09-04 16:18:07 -05:00
LotP1
91f5247e7f add missing field 2025-09-04 16:17:59 -05:00
LotP1
5658402c6b fix spelling 2025-09-04 16:17:53 -05:00
LotP1
1b2c93e188 Add version comment 2025-09-04 16:14:38 -05:00
LotP1
9e599ff325 remove stub 2025-09-04 16:14:18 -05:00
LotP1
7a5f430b59 hle: Basic event handle implementation for IApplicationFunctions 210
Lets Hollow Knight: Silksong boot.
2025-09-04 16:14:03 -05:00
shinyoyo
1e340ce2f3 Update Simplified Chinese translation. (ryubing/ryujinx!139)
See merge request ryubing/ryujinx!139
2025-09-03 15:49:14 -05:00
WilliamWsyHK
dbb4e63e1e Update zh-TW translation (ryubing/ryujinx!130)
See merge request ryubing/ryujinx!130
2025-09-03 03:28:37 -05:00
Hack茶ん
d00ab52fa2 Update Korean translation (ryubing/ryujinx!138)
See merge request ryubing/ryujinx!138
2025-09-03 03:26:33 -05:00
VewDev
959af3613d doc: update documentation for Shared property in Switch class (ryubing/ryujinx!137)
See merge request ryubing/ryujinx!137
2025-09-03 03:25:43 -05:00
GreemDev
3309fb2351 chore: Replace dead URLs in the changelog with archive.org links (that I could find) 2025-09-03 00:49:30 -05:00
GreemDev
e1e8628a6f chore: remove BuildAndPushLibraries.sh 2025-09-03 00:25:08 -05:00
Neo
3969191605 UI: Menubar & Game Context Menu Updates (ryubing/ryujinx!134)
See merge request ryubing/ryujinx!134
2025-09-02 03:32:06 -05:00
Hack茶ん
07c7b39053 Update Korean translation (ryubing/ryujinx!136)
See merge request ryubing/ryujinx!136
2025-09-01 17:57:44 -05:00
Hack茶ん
053efaa414 Update Korean translation (ryubing/ryujinx!135)
See merge request ryubing/ryujinx!135
2025-09-01 01:36:27 -05:00
GreemDev
56e6339553 hle: cheats: Prevent NullRef and throw a TamperCompilationException instead
for null base instruction byte arrays on the current block in EndConditionalBlock
2025-08-31 23:06:42 -05:00
shinyoyo
042362ee2b Update Simplified Chinese translation. (ryubing/ryujinx!133)
See merge request ryubing/ryujinx!133
2025-08-30 22:40:05 -05:00
GreemDev
7347ee2212 [ci skip] chore: UI: Add localization key for LDN Game Viewer filters dropdown button heading 2025-08-30 22:13:38 -05:00
LotP
01a9b636af Memory changes 2.1 (ryubing/ryujinx!132)
See merge request ryubing/ryujinx!132
2025-08-30 20:30:17 -05:00
GreemDev
6e47d8548c feature: UI: LDN Games Viewer
This window can be accessed via "Help" menu in the title bar.
This menu's data is synced with the in-app-list LDN game data, and that has been modified to hide unjoinable games (in-progress and/or private (needing a passphrase)). You can still see these games in the list.
2025-08-30 19:54:00 -05:00
GreemDev
da340f5615 chore: remove redundant CloseWindow helper 2025-08-30 00:40:39 -05:00
GreemDev
be249f7bdc chore: move NFC tags URL to SharedConstants.cs 2025-08-30 00:35:16 -05:00
GreemDev
462c93e1ff fix key number 5 locale 2025-08-28 20:32:48 -05:00
Babib3l
573a6f32fe nullify + update spanish and french translations (ryubing/ryujinx!125)
See merge request ryubing/ryujinx!125
2025-08-28 13:28:24 -05:00
GreemDev
7846f58cad [ci skip] chore: Change LDN server URL (it's the same server, just a more official URL) 2025-08-27 22:49:51 -05:00
GreemDev
0203065fed ui: fix: Missing "Loading" text when shader cache is disabled and PPTC doesn't trigger 2025-08-27 22:35:09 -05:00
shinyoyo
7319a2dafc Nullify & update Simplified Chinese translation. (ryubing/ryujinx!124)
See merge request ryubing/ryujinx!124
2025-08-27 00:41:47 -05:00
Hack茶ん
f992735656 Nullify & Update Korean translation (ryubing/ryujinx!122)
See merge request ryubing/ryujinx!122
2025-08-27 00:40:11 -05:00
GreemDev
48b9f2ab93 docs: compat: High on Life: Menus 2025-08-26 20:12:36 -05:00
LotP
50ab108ee1 Memory Changes part 2 (ryubing/ryujinx!123)
See merge request ryubing/ryujinx!123
2025-08-25 17:44:15 -05:00
VewDev
d499449f57 feat(ui): improve Amiibo selection UX (ryubing/ryujinx!121)
See merge request ryubing/ryujinx!121
2025-08-25 05:14:06 -05:00
GreemDev
cd3c614021 fix: part 2: Resolve AppImage CI failures in Stable and Canary
This was done by adding the -n flag when running appimagetool.
Fix suggested by `settyness` on Discord.
2025-08-24 15:44:38 -05:00
GreemDev
5fa82bb1f5 fix: attempt at resolving AppImage CI failures 2025-08-24 15:35:11 -05:00
GreemDev
234cb99325 [ci skip] chore: minor nitpick: Use passed dlc IDs array instead of the field 2025-08-23 23:50:23 -05:00
GreemDev
ab7914f235 input: ava: Rename timer interval constant
Also cut the delay after which scrolling is considered ended in half
2025-08-19 19:39:18 -05:00
MaxLastBreath
3df6b7c0f5 Fix Avalonia Native MouseWheel-Support (ryubing/ryujinx!116)
See merge request ryubing/ryujinx!116
2025-08-19 18:46:20 -05:00
ProIcons
37e81481c4 Fix nn::ec::detail::PurchasedProductInfo to return No purchase information... (ryubing/ryujinx!114)
See merge request ryubing/ryujinx!114
2025-08-17 04:52:20 -05:00
shinyoyo
4d8b799763 Updated Simplified Chinese translation. (ryubing/ryujinx!104)
See merge request ryubing/ryujinx!104
2025-08-16 19:18:39 -05:00
WilliamWsyHK
cb786b7147 Update zh-TW translation after nullify locales to signify intention of using default en-US values (ryubing/ryujinx!85)
See merge request ryubing/ryujinx!85
2025-08-16 19:17:51 -05:00
Gab
2a308f50c0 Nullify french locales + updated translation (ryubing/ryujinx!87)
See merge request ryubing/ryujinx!87
2025-08-16 16:59:20 -05:00
Neo
b51c5cead6 Nullify + Update Russian Locales (ryubing/ryujinx!103)
See merge request ryubing/ryujinx!103
2025-08-13 05:00:22 -05:00
GreemDev
461c1f5342 UI: compat list: fix squished search box 2025-08-13 04:08:28 -05:00
Neo
cfea61b3a0 QUICK FIX: Compatibility Window Checkbox Spacing (ryubing/ryujinx!112)
See merge request ryubing/ryujinx!112
2025-08-13 03:53:58 -05:00
Neo
ae2e9a73ab UI Updates Batch 2 (ryubing/ryujinx!105)
See merge request ryubing/ryujinx!105
2025-08-12 17:45:24 -05:00
GreemDev
c6f22318a7 add an ASCII header at startup in the log 2025-08-11 18:06:53 -05:00
GreemDev
dd5e1b99b1 remove localization entries for auto graphics backend 2025-08-11 18:00:10 -05:00
Hack茶ん
c863ffd353 Update Korean translation (ryubing/ryujinx!107)
See merge request ryubing/ryujinx!107
2025-08-10 16:37:14 -05:00
LotP
d6d089b81b Revert "Fix crash caused by VirtualRange mismatch (ryubing/ryujinx!109)" (ryubing/ryujinx!110)
See merge request ryubing/ryujinx!110
2025-08-09 18:41:36 -05:00
LotP
c482b7a1c0 Fix crash caused by VirtualRange mismatch (ryubing/ryujinx!109)
See merge request ryubing/ryujinx!109
2025-08-09 17:46:29 -05:00
在中国的泰国青年_
01e1cd4d5a update thai language in locales.json (ryubing/ryujinx!102)
See merge request ryubing/ryujinx!102
2025-08-08 04:34:56 -05:00
GreemDev
bb06eb751b Revert "fix: Super Mario Party Jamboree audio renderer crashing"
This reverts commit c0c021c7a966e32ed39018f8ec00f9f373173b60.

This commit was useless, and submitted by a GDKchan-obsessed chronically online lunatic who has disrespected the maintainers of this fork due to petty disagreements of how we run our Discord server. This is my parting gift to you: Stay gone. I'd prefer this code the way it was, because then you didn't touch it.

For the record, this commit is literally useless. The behavioral outcome is functionally identical to before the commit.
2025-08-06 18:43:31 -05:00
LotP
5613d3f35d Memory Changes (ryubing/ryujinx!46)
See merge request ryubing/ryujinx!46
2025-08-06 15:57:08 -05:00
Coxxs
54d4d184f4 gdb: Improve stepping (ryubing/ryujinx!106)
See merge request ryubing/ryujinx!106
2025-08-05 14:51:51 -05:00
Coxxs
d22756f1bd Add GDB Stub (ryubing/ryujinx!71)
See merge request ryubing/ryujinx!71
2025-08-04 20:45:15 -05:00
Neo
324f18aa5f Tooltip Fix Pt.4 (ryubing/ryujinx!101)
See merge request ryubing/ryujinx!101
2025-08-03 04:39:56 -05:00
Neo
31870707cf Tooltip Fix Pt.3 (ryubing/ryujinx!96)
See merge request ryubing/ryujinx!96
2025-08-02 20:30:54 -05:00
Hack茶ん
fd6648e30a Update Korean translation (ryubing/ryujinx!100)
See merge request ryubing/ryujinx!100
2025-08-02 20:29:50 -05:00
Neo
bc6be4e088 Other Tooltips Pt.2 (ryubing/ryujinx!95)
See merge request ryubing/ryujinx!95
2025-08-02 05:01:59 -05:00
Neo
64a6494d90 GameListContext Menu Tooltips (ryubing/ryujinx!94)
See merge request ryubing/ryujinx!94
2025-08-02 04:51:32 -05:00
Neo
ddb8afa6f4 Edit compatibility.csv (ryubing/ryujinx!88)
See merge request ryubing/ryujinx!88
2025-08-02 04:33:29 -05:00
Neo
c2f4118b1f Minor locales.json Adjustments (ryubing/ryujinx!91)
See merge request ryubing/ryujinx!91
2025-08-02 04:21:52 -05:00
GreemDev
47aa2c1513 Comment AppImage builds
It randomly started erroring in GitHub actions with exit code 8 but only sometimes, and I don't have the patience to debug it. I don't even use linux lol
2025-07-28 19:34:21 -05:00
LotP
f3a2f59683 Nullify Locales (ryubing/ryujinx!83)
See merge request ryubing/ryujinx!83
2025-07-28 18:24:35 -05:00
Rondo
51bcb9e128 Changes to uk_UA (ryubing/ryujinx!84)
See merge request ryubing/ryujinx!84
2025-07-28 15:55:48 -05:00
Daenorth
dce5f0eb55 Edit TileIDs.cs (ryubing/ryujinx!81)
See merge request ryubing/ryujinx!81
2025-07-24 13:04:22 -05:00
Daenorth
f2eb3749f9 Edit compatibility.csv (ryubing/ryujinx!80)
See merge request ryubing/ryujinx!80
2025-07-24 06:48:56 -05:00
470 changed files with 18614 additions and 10977 deletions

1
.gitattributes vendored
View File

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

View File

@@ -102,51 +102,46 @@ 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
# If anyone wants to look into why appimagetool randomly errors with exit code 8, that would be cool
# - name: Build AppImage (Linux)
# if: matrix.platform.os == 'ubuntu-latest'
# run: |
# BUILD_VERSION="${{ steps.version_info.outputs.build_version }}"
# PLATFORM_NAME="${{ matrix.platform.name }}"
#
# sudo apt install -y zsync desktop-file-utils appstream
#
# mkdir -p tools
# export PATH="$PATH:$(readlink -f tools)"
#
# # Setup appimagetool
# wget -q -O tools/appimagetool "https://github.com/AppImage/appimagetool/releases/download/continuous/appimagetool-x86_64.AppImage"
# chmod +x tools/appimagetool
# chmod +x distribution/linux/appimage/build-appimage.sh
#
# # Explicitly set $ARCH for appimagetool ($ARCH_NAME is for the file name)
# if [ "$PLATFORM_NAME" = "linux-x64" ]; then
# ARCH_NAME=x64
# export ARCH=x86_64
# elif [ "$PLATFORM_NAME" = "linux-arm64" ]; then
# ARCH_NAME=arm64
# export ARCH=aarch64
# else
# echo "Unexpected PLATFORM_NAME "$PLATFORM_NAME""
# exit 1
# fi
#
# export UFLAG="gh-releases-zsync|${{ 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
- name: Build AppImage (Linux)
if: matrix.platform.os == 'ubuntu-latest'
run: |
BUILD_VERSION="${{ steps.version_info.outputs.build_version }}"
PLATFORM_NAME="${{ matrix.platform.name }}"
sudo apt install -y zsync desktop-file-utils appstream
mkdir -p tools
export PATH="$PATH:$(readlink -f tools)"
# Setup appimagetool
wget -q -O tools/appimagetool "https://github.com/AppImage/appimagetool/releases/download/continuous/appimagetool-x86_64.AppImage"
chmod +x tools/appimagetool
chmod +x distribution/linux/appimage/build-appimage.sh
# Explicitly set $ARCH for appimagetool ($ARCH_NAME is for the file name)
if [ "$PLATFORM_NAME" = "linux-x64" ]; then
ARCH_NAME=x64
export ARCH=x86_64
elif [ "$PLATFORM_NAME" = "linux-arm64" ]; then
ARCH_NAME=arm64
export ARCH=aarch64
else
echo "Unexpected PLATFORM_NAME "$PLATFORM_NAME""
exit 1
fi
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
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"
shell: bash
macos_release:
name: Release MacOS universal

View File

@@ -96,48 +96,43 @@ jobs:
shell: bash
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
# If anyone wants to look into why appimagetool randomly errors with exit code 8, that would be cool
# - name: Build AppImage (Linux)
# if: matrix.platform.os == 'ubuntu-latest'
# run: |
# BUILD_VERSION="${{ steps.version_info.outputs.build_version }}"
# PLATFORM_NAME="${{ matrix.platform.name }}"
#
# sudo apt install -y zsync desktop-file-utils appstream
#
# mkdir -p tools
# export PATH="$PATH:$(readlink -f tools)"
#
# # Setup appimagetool
# wget -q -O tools/appimagetool "https://github.com/AppImage/appimagetool/releases/download/continuous/appimagetool-x86_64.AppImage"
# chmod +x tools/appimagetool
# chmod +x distribution/linux/appimage/build-appimage.sh
#
# # Explicitly set $ARCH for appimagetool ($ARCH_NAME is for the file name)
# if [ "$PLATFORM_NAME" = "linux-x64" ]; then
# ARCH_NAME=x64
# export ARCH=x86_64
# elif [ "$PLATFORM_NAME" = "linux-arm64" ]; then
# ARCH_NAME=arm64
# export ARCH=aarch64
# else
# echo "Unexpected PLATFORM_NAME "$PLATFORM_NAME""
# exit 1
# fi
#
# export UFLAG="gh-releases-zsync|${{ github.repository_owner }}|${{ github.event.repository.name }}|latest|*-$ARCH_NAME.AppImage.zsync"
# BUILDDIR=publish OUTDIR=publish_appimage distribution/linux/appimage/build-appimage.sh
#
# pushd publish_appimage
# mv Ryujinx.AppImage ../release_output/ryujinx-$BUILD_VERSION-$ARCH_NAME.AppImage
# mv Ryujinx.AppImage.zsync ../release_output/ryujinx-$BUILD_VERSION-$ARCH_NAME.AppImage.zsync
# popd
#
# gli --access-token=${{ secrets.GITLAB_TOKEN }} --project=ryubing/ryujinx --command=UploadGenericPackage "Ryubing|${{ steps.version_info.outputs.build_version }}|release_output/ryujinx-$BUILD_VERSION-$ARCH_NAME.AppImage"
# gli --access-token=${{ secrets.GITLAB_TOKEN }} --project=ryubing/ryujinx --command=UploadGenericPackage "Ryubing|${{ steps.version_info.outputs.build_version }}|release_output/ryujinx-$BUILD_VERSION-$ARCH_NAME.AppImage.zsync"
# shell: bash
- name: Build AppImage (Linux)
if: matrix.platform.os == 'ubuntu-latest'
run: |
BUILD_VERSION="${{ steps.version_info.outputs.build_version }}"
PLATFORM_NAME="${{ matrix.platform.name }}"
sudo apt install -y zsync desktop-file-utils appstream
mkdir -p tools
export PATH="$PATH:$(readlink -f tools)"
# Setup appimagetool
wget -q -O tools/appimagetool "https://github.com/AppImage/appimagetool/releases/download/continuous/appimagetool-x86_64.AppImage"
chmod +x tools/appimagetool
chmod +x distribution/linux/appimage/build-appimage.sh
# Explicitly set $ARCH for appimagetool ($ARCH_NAME is for the file name)
if [ "$PLATFORM_NAME" = "linux-x64" ]; then
ARCH_NAME=x64
export ARCH=x86_64
elif [ "$PLATFORM_NAME" = "linux-arm64" ]; then
ARCH_NAME=arm64
export ARCH=aarch64
else
echo "Unexpected PLATFORM_NAME "$PLATFORM_NAME""
exit 1
fi
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
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"
shell: bash
macos_release:
name: Release MacOS universal

View File

@@ -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

View File

@@ -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.

View File

@@ -10,7 +10,7 @@ Make sure your SDK version is higher or equal to the required version specified
### Step 2
Either use `git clone https://github.com/Ryubing/Ryujinx` on the command line to clone the repository or use Code --> Download zip button to get the files.
Either use `git clone https://git.ryujinx.app/ryubing/ryujinx.git` on the command line to clone the repository or use Code --> Download zip button to get the files.
### Step 3

View File

@@ -3,25 +3,26 @@
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
</PropertyGroup>
<ItemGroup>
<PackageVersion Include="Avalonia" Version="11.0.13" />
<PackageVersion Include="Avalonia.Controls.DataGrid" Version="11.0.13" />
<PackageVersion Include="Avalonia.Desktop" Version="11.0.13" />
<PackageVersion Include="Avalonia.Diagnostics" Version="11.0.13" />
<PackageVersion Include="Avalonia.Markup.Xaml.Loader" Version="11.0.13" />
<PackageVersion Include="Avalonia.Svg" Version="11.0.0.19" />
<PackageVersion Include="Avalonia.Svg.Skia" Version="11.0.0.19" />
<PackageVersion Include="Avalonia" Version="11.3.6" />
<PackageVersion Include="Avalonia.Controls.DataGrid" Version="11.3.6" />
<PackageVersion Include="Avalonia.Desktop" Version="11.3.6" />
<PackageVersion Include="Avalonia.Diagnostics" Version="11.3.6" />
<PackageVersion Include="Avalonia.Markup.Xaml.Loader" Version="11.3.6" />
<PackageVersion Include="Svg.Controls.Avalonia" Version="11.3.6.2" />
<PackageVersion Include="Svg.Controls.Skia.Avalonia" Version="11.3.6.2" />
<PackageVersion Include="Microsoft.Build.Framework" Version="17.11.4" />
<PackageVersion Include="Microsoft.Build.Utilities.Core" Version="17.12.6" />
<PackageVersion Include="Newtonsoft.Json" Version="13.0.3" />
<PackageVersion Include="Projektanker.Icons.Avalonia" Version="9.4.0" />
<PackageVersion Include="Projektanker.Icons.Avalonia.FontAwesome" Version="9.4.0"/>
<PackageVersion Include="Projektanker.Icons.Avalonia.MaterialDesign" Version="9.4.0"/>
<PackageVersion Include="Projektanker.Icons.Avalonia" Version="9.6.2" />
<PackageVersion Include="Projektanker.Icons.Avalonia.FontAwesome" Version="9.6.2" />
<PackageVersion Include="Projektanker.Icons.Avalonia.MaterialDesign" Version="9.6.2" />
<PackageVersion Include="ppy.SDL3-CS" Version="2025.920.0" />
<PackageVersion Include="CommandLineParser" Version="2.9.1" />
<PackageVersion Include="CommunityToolkit.Mvvm" Version="8.4.0"/>
<PackageVersion Include="CommunityToolkit.Mvvm" Version="8.4.0" />
<PackageVersion Include="Concentus" Version="2.2.2" />
<PackageVersion Include="DiscordRichPresence" Version="1.2.1.24" />
<PackageVersion Include="DynamicData" Version="9.0.4" />
<PackageVersion Include="FluentAvaloniaUI" Version="2.0.5" />
<PackageVersion Include="DiscordRichPresence" Version="1.6.1.70" />
<PackageVersion Include="DynamicData" Version="9.4.1" />
<PackageVersion Include="FluentAvaloniaUI.NoAnim" Version="2.4.0-build3" />
<PackageVersion Include="Humanizer" Version="2.14.1" />
<PackageVersion Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.4" />
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp" Version="4.9.2" />
@@ -40,13 +41,12 @@
<PackageVersion Include="Ryujinx.Audio.OpenAL.Dependencies" Version="1.21.0.1" />
<PackageVersion Include="Ryujinx.Graphics.Nvdec.Dependencies.AllArch" Version="6.1.2-build3" />
<PackageVersion Include="Ryujinx.Graphics.Vulkan.Dependencies.MoltenVK" Version="1.2.0" />
<PackageVersion Include="Ryujinx.LibHac" Version="0.21.0-alpha.116" />
<PackageVersion Include="Ryujinx.SDL2-CS" Version="2.30.0-build32" />
<PackageVersion Include="Ryujinx.UpdateClient" Version="1.0.29" />
<PackageVersion Include="Ryujinx.Systems.Update.Common" Version="1.0.29" />
<PackageVersion Include="Gommon" Version="2.7.1.1" />
<PackageVersion Include="Ryujinx.LibHac" Version="0.21.0-alpha.126" />
<PackageVersion Include="Ryujinx.UpdateClient" Version="1.0.44" />
<PackageVersion Include="Ryujinx.Systems.Update.Common" Version="1.0.44" />
<PackageVersion Include="Gommon" Version="2.8.0.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" />
@@ -55,9 +55,8 @@
<PackageVersion Include="SkiaSharp" Version="2.88.9" />
<PackageVersion Include="SkiaSharp.NativeAssets.Linux" Version="2.88.9" />
<PackageVersion Include="SPB" Version="0.0.4-build32" />
<PackageVersion Include="Starscript.Net" Version="1.0.36" />
<PackageVersion Include="System.IO.Hashing" Version="9.0.2" />
<PackageVersion Include="System.Management" Version="9.0.2" />
<PackageVersion Include="UnicornEngine.Unicorn" Version="2.0.2-rc1-fb78016" />
</ItemGroup>
</Project>
</Project>

View File

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

View File

@@ -51,12 +51,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Audio.Backends.Soun
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Input", "src\Ryujinx.Input\Ryujinx.Input.csproj", "{C16F112F-38C3-40BC-9F5F-4791112063D6}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Input.SDL2", "src\Ryujinx.Input.SDL2\Ryujinx.Input.SDL2.csproj", "{DFAB6F2D-B9BF-4AFF-B22B-7684A328EBA3}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.SDL2.Common", "src\Ryujinx.SDL2.Common\Ryujinx.SDL2.Common.csproj", "{2D5D3A1D-5730-4648-B0AB-06C53CB910C0}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Audio.Backends.SDL2", "src\Ryujinx.Audio.Backends.SDL2\Ryujinx.Audio.Backends.SDL2.csproj", "{D99A395A-8569-4DB0-B336-900647890052}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Graphics.Nvdec.FFmpeg", "src\Ryujinx.Graphics.Nvdec.FFmpeg\Ryujinx.Graphics.Nvdec.FFmpeg.csproj", "{BEE1C184-C9A4-410B-8DFC-FB74D5C93AEB}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx", "src\Ryujinx\Ryujinx.csproj", "{7C1B2721-13DA-4B62-B046-C626605ECCE6}"
@@ -89,171 +83,488 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
nuget.config = nuget.config
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{827E0CD3-B72D-47B6-A68D-7590B98EB39B}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ryujinx.SDL3.Common", "src\Ryujinx.SDL3.Common\Ryujinx.SDL3.Common.csproj", "{F6F9826A-BC58-4D78-A700-F358A66B2B06}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ryujinx.Input.SDL3", "src\Ryujinx.Input.SDL3\Ryujinx.Input.SDL3.csproj", "{D728444C-3D1F-4A0E-B4C9-5C9375D47EA3}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ryujinx.Audio.Backends.SDL3", "src\Ryujinx.Audio.Backends.SDL3\Ryujinx.Audio.Backends.SDL3.csproj", "{988E6191-82E1-4E13-9DDB-CB9FA2FDAF29}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Debug|x64 = Debug|x64
Debug|x86 = Debug|x86
Release|Any CPU = Release|Any CPU
Release|x64 = Release|x64
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{EBB55AEA-C7D7-4DEB-BF96-FA1789E225E9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{EBB55AEA-C7D7-4DEB-BF96-FA1789E225E9}.Debug|Any CPU.Build.0 = Debug|Any CPU
{EBB55AEA-C7D7-4DEB-BF96-FA1789E225E9}.Debug|x64.ActiveCfg = Debug|Any CPU
{EBB55AEA-C7D7-4DEB-BF96-FA1789E225E9}.Debug|x64.Build.0 = Debug|Any CPU
{EBB55AEA-C7D7-4DEB-BF96-FA1789E225E9}.Debug|x86.ActiveCfg = Debug|Any CPU
{EBB55AEA-C7D7-4DEB-BF96-FA1789E225E9}.Debug|x86.Build.0 = Debug|Any CPU
{EBB55AEA-C7D7-4DEB-BF96-FA1789E225E9}.Release|Any CPU.ActiveCfg = Release|Any CPU
{EBB55AEA-C7D7-4DEB-BF96-FA1789E225E9}.Release|Any CPU.Build.0 = Release|Any CPU
{EBB55AEA-C7D7-4DEB-BF96-FA1789E225E9}.Release|x64.ActiveCfg = Release|Any CPU
{EBB55AEA-C7D7-4DEB-BF96-FA1789E225E9}.Release|x64.Build.0 = Release|Any CPU
{EBB55AEA-C7D7-4DEB-BF96-FA1789E225E9}.Release|x86.ActiveCfg = Release|Any CPU
{EBB55AEA-C7D7-4DEB-BF96-FA1789E225E9}.Release|x86.Build.0 = Release|Any CPU
{D8F72938-78EF-4E8C-BAFE-531C9C3C8F15}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D8F72938-78EF-4E8C-BAFE-531C9C3C8F15}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D8F72938-78EF-4E8C-BAFE-531C9C3C8F15}.Debug|x64.ActiveCfg = Debug|Any CPU
{D8F72938-78EF-4E8C-BAFE-531C9C3C8F15}.Debug|x64.Build.0 = Debug|Any CPU
{D8F72938-78EF-4E8C-BAFE-531C9C3C8F15}.Debug|x86.ActiveCfg = Debug|Any CPU
{D8F72938-78EF-4E8C-BAFE-531C9C3C8F15}.Debug|x86.Build.0 = Debug|Any CPU
{D8F72938-78EF-4E8C-BAFE-531C9C3C8F15}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D8F72938-78EF-4E8C-BAFE-531C9C3C8F15}.Release|Any CPU.Build.0 = Release|Any CPU
{D8F72938-78EF-4E8C-BAFE-531C9C3C8F15}.Release|x64.ActiveCfg = Release|Any CPU
{D8F72938-78EF-4E8C-BAFE-531C9C3C8F15}.Release|x64.Build.0 = Release|Any CPU
{D8F72938-78EF-4E8C-BAFE-531C9C3C8F15}.Release|x86.ActiveCfg = Release|Any CPU
{D8F72938-78EF-4E8C-BAFE-531C9C3C8F15}.Release|x86.Build.0 = Release|Any CPU
{CB92CFF9-1D62-4D4F-9E88-8130EF61E351}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{CB92CFF9-1D62-4D4F-9E88-8130EF61E351}.Debug|Any CPU.Build.0 = Debug|Any CPU
{CB92CFF9-1D62-4D4F-9E88-8130EF61E351}.Debug|x64.ActiveCfg = Debug|Any CPU
{CB92CFF9-1D62-4D4F-9E88-8130EF61E351}.Debug|x64.Build.0 = Debug|Any CPU
{CB92CFF9-1D62-4D4F-9E88-8130EF61E351}.Debug|x86.ActiveCfg = Debug|Any CPU
{CB92CFF9-1D62-4D4F-9E88-8130EF61E351}.Debug|x86.Build.0 = Debug|Any CPU
{CB92CFF9-1D62-4D4F-9E88-8130EF61E351}.Release|Any CPU.ActiveCfg = Release|Any CPU
{CB92CFF9-1D62-4D4F-9E88-8130EF61E351}.Release|Any CPU.Build.0 = Release|Any CPU
{CB92CFF9-1D62-4D4F-9E88-8130EF61E351}.Release|x64.ActiveCfg = Release|Any CPU
{CB92CFF9-1D62-4D4F-9E88-8130EF61E351}.Release|x64.Build.0 = Release|Any CPU
{CB92CFF9-1D62-4D4F-9E88-8130EF61E351}.Release|x86.ActiveCfg = Release|Any CPU
{CB92CFF9-1D62-4D4F-9E88-8130EF61E351}.Release|x86.Build.0 = Release|Any CPU
{3AB294D0-2230-468F-9EB3-BDFCAEAE99A5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{3AB294D0-2230-468F-9EB3-BDFCAEAE99A5}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3AB294D0-2230-468F-9EB3-BDFCAEAE99A5}.Debug|x64.ActiveCfg = Debug|Any CPU
{3AB294D0-2230-468F-9EB3-BDFCAEAE99A5}.Debug|x64.Build.0 = Debug|Any CPU
{3AB294D0-2230-468F-9EB3-BDFCAEAE99A5}.Debug|x86.ActiveCfg = Debug|Any CPU
{3AB294D0-2230-468F-9EB3-BDFCAEAE99A5}.Debug|x86.Build.0 = Debug|Any CPU
{3AB294D0-2230-468F-9EB3-BDFCAEAE99A5}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3AB294D0-2230-468F-9EB3-BDFCAEAE99A5}.Release|Any CPU.Build.0 = Release|Any CPU
{3AB294D0-2230-468F-9EB3-BDFCAEAE99A5}.Release|x64.ActiveCfg = Release|Any CPU
{3AB294D0-2230-468F-9EB3-BDFCAEAE99A5}.Release|x64.Build.0 = Release|Any CPU
{3AB294D0-2230-468F-9EB3-BDFCAEAE99A5}.Release|x86.ActiveCfg = Release|Any CPU
{3AB294D0-2230-468F-9EB3-BDFCAEAE99A5}.Release|x86.Build.0 = Release|Any CPU
{5FD4E4F6-8928-4B3C-BE07-28A675C17226}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{5FD4E4F6-8928-4B3C-BE07-28A675C17226}.Debug|Any CPU.Build.0 = Debug|Any CPU
{5FD4E4F6-8928-4B3C-BE07-28A675C17226}.Debug|x64.ActiveCfg = Debug|Any CPU
{5FD4E4F6-8928-4B3C-BE07-28A675C17226}.Debug|x64.Build.0 = Debug|Any CPU
{5FD4E4F6-8928-4B3C-BE07-28A675C17226}.Debug|x86.ActiveCfg = Debug|Any CPU
{5FD4E4F6-8928-4B3C-BE07-28A675C17226}.Debug|x86.Build.0 = Debug|Any CPU
{5FD4E4F6-8928-4B3C-BE07-28A675C17226}.Release|Any CPU.ActiveCfg = Release|Any CPU
{5FD4E4F6-8928-4B3C-BE07-28A675C17226}.Release|Any CPU.Build.0 = Release|Any CPU
{5FD4E4F6-8928-4B3C-BE07-28A675C17226}.Release|x64.ActiveCfg = Release|Any CPU
{5FD4E4F6-8928-4B3C-BE07-28A675C17226}.Release|x64.Build.0 = Release|Any CPU
{5FD4E4F6-8928-4B3C-BE07-28A675C17226}.Release|x86.ActiveCfg = Release|Any CPU
{5FD4E4F6-8928-4B3C-BE07-28A675C17226}.Release|x86.Build.0 = Release|Any CPU
{ABF09A5E-2D8B-4B6F-A51D-5CE414DDB15A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{ABF09A5E-2D8B-4B6F-A51D-5CE414DDB15A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{ABF09A5E-2D8B-4B6F-A51D-5CE414DDB15A}.Debug|x64.ActiveCfg = Debug|Any CPU
{ABF09A5E-2D8B-4B6F-A51D-5CE414DDB15A}.Debug|x64.Build.0 = Debug|Any CPU
{ABF09A5E-2D8B-4B6F-A51D-5CE414DDB15A}.Debug|x86.ActiveCfg = Debug|Any CPU
{ABF09A5E-2D8B-4B6F-A51D-5CE414DDB15A}.Debug|x86.Build.0 = Debug|Any CPU
{ABF09A5E-2D8B-4B6F-A51D-5CE414DDB15A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{ABF09A5E-2D8B-4B6F-A51D-5CE414DDB15A}.Release|Any CPU.Build.0 = Release|Any CPU
{ABF09A5E-2D8B-4B6F-A51D-5CE414DDB15A}.Release|x64.ActiveCfg = Release|Any CPU
{ABF09A5E-2D8B-4B6F-A51D-5CE414DDB15A}.Release|x64.Build.0 = Release|Any CPU
{ABF09A5E-2D8B-4B6F-A51D-5CE414DDB15A}.Release|x86.ActiveCfg = Release|Any CPU
{ABF09A5E-2D8B-4B6F-A51D-5CE414DDB15A}.Release|x86.Build.0 = Release|Any CPU
{ADA7EA87-0D63-4D97-9433-922A2124401F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{ADA7EA87-0D63-4D97-9433-922A2124401F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{ADA7EA87-0D63-4D97-9433-922A2124401F}.Debug|x64.ActiveCfg = Debug|Any CPU
{ADA7EA87-0D63-4D97-9433-922A2124401F}.Debug|x64.Build.0 = Debug|Any CPU
{ADA7EA87-0D63-4D97-9433-922A2124401F}.Debug|x86.ActiveCfg = Debug|Any CPU
{ADA7EA87-0D63-4D97-9433-922A2124401F}.Debug|x86.Build.0 = Debug|Any CPU
{ADA7EA87-0D63-4D97-9433-922A2124401F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{ADA7EA87-0D63-4D97-9433-922A2124401F}.Release|Any CPU.Build.0 = Release|Any CPU
{ADA7EA87-0D63-4D97-9433-922A2124401F}.Release|x64.ActiveCfg = Release|Any CPU
{ADA7EA87-0D63-4D97-9433-922A2124401F}.Release|x64.Build.0 = Release|Any CPU
{ADA7EA87-0D63-4D97-9433-922A2124401F}.Release|x86.ActiveCfg = Release|Any CPU
{ADA7EA87-0D63-4D97-9433-922A2124401F}.Release|x86.Build.0 = Release|Any CPU
{A602AE97-91A5-4608-8DF1-EBF4ED7A0B9E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A602AE97-91A5-4608-8DF1-EBF4ED7A0B9E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A602AE97-91A5-4608-8DF1-EBF4ED7A0B9E}.Debug|x64.ActiveCfg = Debug|Any CPU
{A602AE97-91A5-4608-8DF1-EBF4ED7A0B9E}.Debug|x64.Build.0 = Debug|Any CPU
{A602AE97-91A5-4608-8DF1-EBF4ED7A0B9E}.Debug|x86.ActiveCfg = Debug|Any CPU
{A602AE97-91A5-4608-8DF1-EBF4ED7A0B9E}.Debug|x86.Build.0 = Debug|Any CPU
{A602AE97-91A5-4608-8DF1-EBF4ED7A0B9E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A602AE97-91A5-4608-8DF1-EBF4ED7A0B9E}.Release|Any CPU.Build.0 = Release|Any CPU
{A602AE97-91A5-4608-8DF1-EBF4ED7A0B9E}.Release|x64.ActiveCfg = Release|Any CPU
{A602AE97-91A5-4608-8DF1-EBF4ED7A0B9E}.Release|x64.Build.0 = Release|Any CPU
{A602AE97-91A5-4608-8DF1-EBF4ED7A0B9E}.Release|x86.ActiveCfg = Release|Any CPU
{A602AE97-91A5-4608-8DF1-EBF4ED7A0B9E}.Release|x86.Build.0 = Release|Any CPU
{9558FB96-075D-4219-8FFF-401979DC0B69}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{9558FB96-075D-4219-8FFF-401979DC0B69}.Debug|Any CPU.Build.0 = Debug|Any CPU
{9558FB96-075D-4219-8FFF-401979DC0B69}.Debug|x64.ActiveCfg = Debug|Any CPU
{9558FB96-075D-4219-8FFF-401979DC0B69}.Debug|x64.Build.0 = Debug|Any CPU
{9558FB96-075D-4219-8FFF-401979DC0B69}.Debug|x86.ActiveCfg = Debug|Any CPU
{9558FB96-075D-4219-8FFF-401979DC0B69}.Debug|x86.Build.0 = Debug|Any CPU
{9558FB96-075D-4219-8FFF-401979DC0B69}.Release|Any CPU.ActiveCfg = Release|Any CPU
{9558FB96-075D-4219-8FFF-401979DC0B69}.Release|Any CPU.Build.0 = Release|Any CPU
{9558FB96-075D-4219-8FFF-401979DC0B69}.Release|x64.ActiveCfg = Release|Any CPU
{9558FB96-075D-4219-8FFF-401979DC0B69}.Release|x64.Build.0 = Release|Any CPU
{9558FB96-075D-4219-8FFF-401979DC0B69}.Release|x86.ActiveCfg = Release|Any CPU
{9558FB96-075D-4219-8FFF-401979DC0B69}.Release|x86.Build.0 = Release|Any CPU
{E1B1AD28-289D-47B7-A106-326972240207}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E1B1AD28-289D-47B7-A106-326972240207}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E1B1AD28-289D-47B7-A106-326972240207}.Debug|x64.ActiveCfg = Debug|Any CPU
{E1B1AD28-289D-47B7-A106-326972240207}.Debug|x64.Build.0 = Debug|Any CPU
{E1B1AD28-289D-47B7-A106-326972240207}.Debug|x86.ActiveCfg = Debug|Any CPU
{E1B1AD28-289D-47B7-A106-326972240207}.Debug|x86.Build.0 = Debug|Any CPU
{E1B1AD28-289D-47B7-A106-326972240207}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E1B1AD28-289D-47B7-A106-326972240207}.Release|Any CPU.Build.0 = Release|Any CPU
{E1B1AD28-289D-47B7-A106-326972240207}.Release|x64.ActiveCfg = Release|Any CPU
{E1B1AD28-289D-47B7-A106-326972240207}.Release|x64.Build.0 = Release|Any CPU
{E1B1AD28-289D-47B7-A106-326972240207}.Release|x86.ActiveCfg = Release|Any CPU
{E1B1AD28-289D-47B7-A106-326972240207}.Release|x86.Build.0 = Release|Any CPU
{03B955CD-AD84-4B93-AAA7-BF17923BBAA5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{03B955CD-AD84-4B93-AAA7-BF17923BBAA5}.Debug|Any CPU.Build.0 = Debug|Any CPU
{03B955CD-AD84-4B93-AAA7-BF17923BBAA5}.Debug|x64.ActiveCfg = Debug|Any CPU
{03B955CD-AD84-4B93-AAA7-BF17923BBAA5}.Debug|x64.Build.0 = Debug|Any CPU
{03B955CD-AD84-4B93-AAA7-BF17923BBAA5}.Debug|x86.ActiveCfg = Debug|Any CPU
{03B955CD-AD84-4B93-AAA7-BF17923BBAA5}.Debug|x86.Build.0 = Debug|Any CPU
{03B955CD-AD84-4B93-AAA7-BF17923BBAA5}.Release|Any CPU.ActiveCfg = Release|Any CPU
{03B955CD-AD84-4B93-AAA7-BF17923BBAA5}.Release|Any CPU.Build.0 = Release|Any CPU
{03B955CD-AD84-4B93-AAA7-BF17923BBAA5}.Release|x64.ActiveCfg = Release|Any CPU
{03B955CD-AD84-4B93-AAA7-BF17923BBAA5}.Release|x64.Build.0 = Release|Any CPU
{03B955CD-AD84-4B93-AAA7-BF17923BBAA5}.Release|x86.ActiveCfg = Release|Any CPU
{03B955CD-AD84-4B93-AAA7-BF17923BBAA5}.Release|x86.Build.0 = Release|Any CPU
{85A0FA56-DC01-4A42-8808-70DAC76BD66D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{85A0FA56-DC01-4A42-8808-70DAC76BD66D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{85A0FA56-DC01-4A42-8808-70DAC76BD66D}.Debug|x64.ActiveCfg = Debug|Any CPU
{85A0FA56-DC01-4A42-8808-70DAC76BD66D}.Debug|x64.Build.0 = Debug|Any CPU
{85A0FA56-DC01-4A42-8808-70DAC76BD66D}.Debug|x86.ActiveCfg = Debug|Any CPU
{85A0FA56-DC01-4A42-8808-70DAC76BD66D}.Debug|x86.Build.0 = Debug|Any CPU
{85A0FA56-DC01-4A42-8808-70DAC76BD66D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{85A0FA56-DC01-4A42-8808-70DAC76BD66D}.Release|Any CPU.Build.0 = Release|Any CPU
{85A0FA56-DC01-4A42-8808-70DAC76BD66D}.Release|x64.ActiveCfg = Release|Any CPU
{85A0FA56-DC01-4A42-8808-70DAC76BD66D}.Release|x64.Build.0 = Release|Any CPU
{85A0FA56-DC01-4A42-8808-70DAC76BD66D}.Release|x86.ActiveCfg = Release|Any CPU
{85A0FA56-DC01-4A42-8808-70DAC76BD66D}.Release|x86.Build.0 = Release|Any CPU
{806ACF6D-90B0-45D0-A1AC-5F220F3B3985}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{806ACF6D-90B0-45D0-A1AC-5F220F3B3985}.Debug|Any CPU.Build.0 = Debug|Any CPU
{806ACF6D-90B0-45D0-A1AC-5F220F3B3985}.Debug|x64.ActiveCfg = Debug|Any CPU
{806ACF6D-90B0-45D0-A1AC-5F220F3B3985}.Debug|x64.Build.0 = Debug|Any CPU
{806ACF6D-90B0-45D0-A1AC-5F220F3B3985}.Debug|x86.ActiveCfg = Debug|Any CPU
{806ACF6D-90B0-45D0-A1AC-5F220F3B3985}.Debug|x86.Build.0 = Debug|Any CPU
{806ACF6D-90B0-45D0-A1AC-5F220F3B3985}.Release|Any CPU.ActiveCfg = Release|Any CPU
{806ACF6D-90B0-45D0-A1AC-5F220F3B3985}.Release|Any CPU.Build.0 = Release|Any CPU
{806ACF6D-90B0-45D0-A1AC-5F220F3B3985}.Release|x64.ActiveCfg = Release|Any CPU
{806ACF6D-90B0-45D0-A1AC-5F220F3B3985}.Release|x64.Build.0 = Release|Any CPU
{806ACF6D-90B0-45D0-A1AC-5F220F3B3985}.Release|x86.ActiveCfg = Release|Any CPU
{806ACF6D-90B0-45D0-A1AC-5F220F3B3985}.Release|x86.Build.0 = Release|Any CPU
{A5E6C691-9E22-4263-8F40-42F002CE66BE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A5E6C691-9E22-4263-8F40-42F002CE66BE}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A5E6C691-9E22-4263-8F40-42F002CE66BE}.Debug|x64.ActiveCfg = Debug|Any CPU
{A5E6C691-9E22-4263-8F40-42F002CE66BE}.Debug|x64.Build.0 = Debug|Any CPU
{A5E6C691-9E22-4263-8F40-42F002CE66BE}.Debug|x86.ActiveCfg = Debug|Any CPU
{A5E6C691-9E22-4263-8F40-42F002CE66BE}.Debug|x86.Build.0 = Debug|Any CPU
{A5E6C691-9E22-4263-8F40-42F002CE66BE}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A5E6C691-9E22-4263-8F40-42F002CE66BE}.Release|Any CPU.Build.0 = Release|Any CPU
{A5E6C691-9E22-4263-8F40-42F002CE66BE}.Release|x64.ActiveCfg = Release|Any CPU
{A5E6C691-9E22-4263-8F40-42F002CE66BE}.Release|x64.Build.0 = Release|Any CPU
{A5E6C691-9E22-4263-8F40-42F002CE66BE}.Release|x86.ActiveCfg = Release|Any CPU
{A5E6C691-9E22-4263-8F40-42F002CE66BE}.Release|x86.Build.0 = Release|Any CPU
{D1CC5322-7325-4F6B-9625-194B30BE1296}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D1CC5322-7325-4F6B-9625-194B30BE1296}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D1CC5322-7325-4F6B-9625-194B30BE1296}.Debug|x64.ActiveCfg = Debug|Any CPU
{D1CC5322-7325-4F6B-9625-194B30BE1296}.Debug|x64.Build.0 = Debug|Any CPU
{D1CC5322-7325-4F6B-9625-194B30BE1296}.Debug|x86.ActiveCfg = Debug|Any CPU
{D1CC5322-7325-4F6B-9625-194B30BE1296}.Debug|x86.Build.0 = Debug|Any CPU
{D1CC5322-7325-4F6B-9625-194B30BE1296}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D1CC5322-7325-4F6B-9625-194B30BE1296}.Release|Any CPU.Build.0 = Release|Any CPU
{D1CC5322-7325-4F6B-9625-194B30BE1296}.Release|x64.ActiveCfg = Release|Any CPU
{D1CC5322-7325-4F6B-9625-194B30BE1296}.Release|x64.Build.0 = Release|Any CPU
{D1CC5322-7325-4F6B-9625-194B30BE1296}.Release|x86.ActiveCfg = Release|Any CPU
{D1CC5322-7325-4F6B-9625-194B30BE1296}.Release|x86.Build.0 = Release|Any CPU
{3DF35E3D-D844-4399-A9A1-A9E923264C17}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{3DF35E3D-D844-4399-A9A1-A9E923264C17}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3DF35E3D-D844-4399-A9A1-A9E923264C17}.Debug|x64.ActiveCfg = Debug|Any CPU
{3DF35E3D-D844-4399-A9A1-A9E923264C17}.Debug|x64.Build.0 = Debug|Any CPU
{3DF35E3D-D844-4399-A9A1-A9E923264C17}.Debug|x86.ActiveCfg = Debug|Any CPU
{3DF35E3D-D844-4399-A9A1-A9E923264C17}.Debug|x86.Build.0 = Debug|Any CPU
{3DF35E3D-D844-4399-A9A1-A9E923264C17}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3DF35E3D-D844-4399-A9A1-A9E923264C17}.Release|Any CPU.Build.0 = Release|Any CPU
{3DF35E3D-D844-4399-A9A1-A9E923264C17}.Release|x64.ActiveCfg = Release|Any CPU
{3DF35E3D-D844-4399-A9A1-A9E923264C17}.Release|x64.Build.0 = Release|Any CPU
{3DF35E3D-D844-4399-A9A1-A9E923264C17}.Release|x86.ActiveCfg = Release|Any CPU
{3DF35E3D-D844-4399-A9A1-A9E923264C17}.Release|x86.Build.0 = Release|Any CPU
{C3002C3C-7B09-4FE7-894A-372EDA22FC6E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C3002C3C-7B09-4FE7-894A-372EDA22FC6E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C3002C3C-7B09-4FE7-894A-372EDA22FC6E}.Debug|x64.ActiveCfg = Debug|Any CPU
{C3002C3C-7B09-4FE7-894A-372EDA22FC6E}.Debug|x64.Build.0 = Debug|Any CPU
{C3002C3C-7B09-4FE7-894A-372EDA22FC6E}.Debug|x86.ActiveCfg = Debug|Any CPU
{C3002C3C-7B09-4FE7-894A-372EDA22FC6E}.Debug|x86.Build.0 = Debug|Any CPU
{C3002C3C-7B09-4FE7-894A-372EDA22FC6E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C3002C3C-7B09-4FE7-894A-372EDA22FC6E}.Release|Any CPU.Build.0 = Release|Any CPU
{C3002C3C-7B09-4FE7-894A-372EDA22FC6E}.Release|x64.ActiveCfg = Release|Any CPU
{C3002C3C-7B09-4FE7-894A-372EDA22FC6E}.Release|x64.Build.0 = Release|Any CPU
{C3002C3C-7B09-4FE7-894A-372EDA22FC6E}.Release|x86.ActiveCfg = Release|Any CPU
{C3002C3C-7B09-4FE7-894A-372EDA22FC6E}.Release|x86.Build.0 = Release|Any CPU
{C35F1536-7DE5-4F9D-9604-B5B4E1561947}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C35F1536-7DE5-4F9D-9604-B5B4E1561947}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C35F1536-7DE5-4F9D-9604-B5B4E1561947}.Debug|x64.ActiveCfg = Debug|Any CPU
{C35F1536-7DE5-4F9D-9604-B5B4E1561947}.Debug|x64.Build.0 = Debug|Any CPU
{C35F1536-7DE5-4F9D-9604-B5B4E1561947}.Debug|x86.ActiveCfg = Debug|Any CPU
{C35F1536-7DE5-4F9D-9604-B5B4E1561947}.Debug|x86.Build.0 = Debug|Any CPU
{C35F1536-7DE5-4F9D-9604-B5B4E1561947}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C35F1536-7DE5-4F9D-9604-B5B4E1561947}.Release|Any CPU.Build.0 = Release|Any CPU
{C35F1536-7DE5-4F9D-9604-B5B4E1561947}.Release|x64.ActiveCfg = Release|Any CPU
{C35F1536-7DE5-4F9D-9604-B5B4E1561947}.Release|x64.Build.0 = Release|Any CPU
{C35F1536-7DE5-4F9D-9604-B5B4E1561947}.Release|x86.ActiveCfg = Release|Any CPU
{C35F1536-7DE5-4F9D-9604-B5B4E1561947}.Release|x86.Build.0 = Release|Any CPU
{B9AECA11-E248-4886-A10B-81B631CAAF29}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B9AECA11-E248-4886-A10B-81B631CAAF29}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B9AECA11-E248-4886-A10B-81B631CAAF29}.Debug|x64.ActiveCfg = Debug|Any CPU
{B9AECA11-E248-4886-A10B-81B631CAAF29}.Debug|x64.Build.0 = Debug|Any CPU
{B9AECA11-E248-4886-A10B-81B631CAAF29}.Debug|x86.ActiveCfg = Debug|Any CPU
{B9AECA11-E248-4886-A10B-81B631CAAF29}.Debug|x86.Build.0 = Debug|Any CPU
{B9AECA11-E248-4886-A10B-81B631CAAF29}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B9AECA11-E248-4886-A10B-81B631CAAF29}.Release|Any CPU.Build.0 = Release|Any CPU
{B9AECA11-E248-4886-A10B-81B631CAAF29}.Release|x64.ActiveCfg = Release|Any CPU
{B9AECA11-E248-4886-A10B-81B631CAAF29}.Release|x64.Build.0 = Release|Any CPU
{B9AECA11-E248-4886-A10B-81B631CAAF29}.Release|x86.ActiveCfg = Release|Any CPU
{B9AECA11-E248-4886-A10B-81B631CAAF29}.Release|x86.Build.0 = Release|Any CPU
{81BB2C11-9408-4EA3-822E-42987AF54429}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{81BB2C11-9408-4EA3-822E-42987AF54429}.Debug|Any CPU.Build.0 = Debug|Any CPU
{81BB2C11-9408-4EA3-822E-42987AF54429}.Debug|x64.ActiveCfg = Debug|Any CPU
{81BB2C11-9408-4EA3-822E-42987AF54429}.Debug|x64.Build.0 = Debug|Any CPU
{81BB2C11-9408-4EA3-822E-42987AF54429}.Debug|x86.ActiveCfg = Debug|Any CPU
{81BB2C11-9408-4EA3-822E-42987AF54429}.Debug|x86.Build.0 = Debug|Any CPU
{81BB2C11-9408-4EA3-822E-42987AF54429}.Release|Any CPU.ActiveCfg = Release|Any CPU
{81BB2C11-9408-4EA3-822E-42987AF54429}.Release|Any CPU.Build.0 = Release|Any CPU
{81BB2C11-9408-4EA3-822E-42987AF54429}.Release|x64.ActiveCfg = Release|Any CPU
{81BB2C11-9408-4EA3-822E-42987AF54429}.Release|x64.Build.0 = Release|Any CPU
{81BB2C11-9408-4EA3-822E-42987AF54429}.Release|x86.ActiveCfg = Release|Any CPU
{81BB2C11-9408-4EA3-822E-42987AF54429}.Release|x86.Build.0 = Release|Any CPU
{FD4A2C14-8E3D-4957-ABBE-3C38897B3E2D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{FD4A2C14-8E3D-4957-ABBE-3C38897B3E2D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{FD4A2C14-8E3D-4957-ABBE-3C38897B3E2D}.Debug|x64.ActiveCfg = Debug|Any CPU
{FD4A2C14-8E3D-4957-ABBE-3C38897B3E2D}.Debug|x64.Build.0 = Debug|Any CPU
{FD4A2C14-8E3D-4957-ABBE-3C38897B3E2D}.Debug|x86.ActiveCfg = Debug|Any CPU
{FD4A2C14-8E3D-4957-ABBE-3C38897B3E2D}.Debug|x86.Build.0 = Debug|Any CPU
{FD4A2C14-8E3D-4957-ABBE-3C38897B3E2D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{FD4A2C14-8E3D-4957-ABBE-3C38897B3E2D}.Release|Any CPU.Build.0 = Release|Any CPU
{FD4A2C14-8E3D-4957-ABBE-3C38897B3E2D}.Release|x64.ActiveCfg = Release|Any CPU
{FD4A2C14-8E3D-4957-ABBE-3C38897B3E2D}.Release|x64.Build.0 = Release|Any CPU
{FD4A2C14-8E3D-4957-ABBE-3C38897B3E2D}.Release|x86.ActiveCfg = Release|Any CPU
{FD4A2C14-8E3D-4957-ABBE-3C38897B3E2D}.Release|x86.Build.0 = Release|Any CPU
{0BE11899-DF2D-4BDE-B9EE-2489E8D35E7D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{0BE11899-DF2D-4BDE-B9EE-2489E8D35E7D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{0BE11899-DF2D-4BDE-B9EE-2489E8D35E7D}.Debug|x64.ActiveCfg = Debug|Any CPU
{0BE11899-DF2D-4BDE-B9EE-2489E8D35E7D}.Debug|x64.Build.0 = Debug|Any CPU
{0BE11899-DF2D-4BDE-B9EE-2489E8D35E7D}.Debug|x86.ActiveCfg = Debug|Any CPU
{0BE11899-DF2D-4BDE-B9EE-2489E8D35E7D}.Debug|x86.Build.0 = Debug|Any CPU
{0BE11899-DF2D-4BDE-B9EE-2489E8D35E7D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{0BE11899-DF2D-4BDE-B9EE-2489E8D35E7D}.Release|Any CPU.Build.0 = Release|Any CPU
{0BE11899-DF2D-4BDE-B9EE-2489E8D35E7D}.Release|x64.ActiveCfg = Release|Any CPU
{0BE11899-DF2D-4BDE-B9EE-2489E8D35E7D}.Release|x64.Build.0 = Release|Any CPU
{0BE11899-DF2D-4BDE-B9EE-2489E8D35E7D}.Release|x86.ActiveCfg = Release|Any CPU
{0BE11899-DF2D-4BDE-B9EE-2489E8D35E7D}.Release|x86.Build.0 = Release|Any CPU
{716364DE-B988-41A6-BAB4-327964266ECC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{716364DE-B988-41A6-BAB4-327964266ECC}.Debug|Any CPU.Build.0 = Debug|Any CPU
{716364DE-B988-41A6-BAB4-327964266ECC}.Debug|x64.ActiveCfg = Debug|Any CPU
{716364DE-B988-41A6-BAB4-327964266ECC}.Debug|x64.Build.0 = Debug|Any CPU
{716364DE-B988-41A6-BAB4-327964266ECC}.Debug|x86.ActiveCfg = Debug|Any CPU
{716364DE-B988-41A6-BAB4-327964266ECC}.Debug|x86.Build.0 = Debug|Any CPU
{716364DE-B988-41A6-BAB4-327964266ECC}.Release|Any CPU.ActiveCfg = Release|Any CPU
{716364DE-B988-41A6-BAB4-327964266ECC}.Release|Any CPU.Build.0 = Release|Any CPU
{716364DE-B988-41A6-BAB4-327964266ECC}.Release|x64.ActiveCfg = Release|Any CPU
{716364DE-B988-41A6-BAB4-327964266ECC}.Release|x64.Build.0 = Release|Any CPU
{716364DE-B988-41A6-BAB4-327964266ECC}.Release|x86.ActiveCfg = Release|Any CPU
{716364DE-B988-41A6-BAB4-327964266ECC}.Release|x86.Build.0 = Release|Any CPU
{C16F112F-38C3-40BC-9F5F-4791112063D6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C16F112F-38C3-40BC-9F5F-4791112063D6}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C16F112F-38C3-40BC-9F5F-4791112063D6}.Debug|x64.ActiveCfg = Debug|Any CPU
{C16F112F-38C3-40BC-9F5F-4791112063D6}.Debug|x64.Build.0 = Debug|Any CPU
{C16F112F-38C3-40BC-9F5F-4791112063D6}.Debug|x86.ActiveCfg = Debug|Any CPU
{C16F112F-38C3-40BC-9F5F-4791112063D6}.Debug|x86.Build.0 = Debug|Any CPU
{C16F112F-38C3-40BC-9F5F-4791112063D6}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C16F112F-38C3-40BC-9F5F-4791112063D6}.Release|Any CPU.Build.0 = Release|Any CPU
{DFAB6F2D-B9BF-4AFF-B22B-7684A328EBA3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{DFAB6F2D-B9BF-4AFF-B22B-7684A328EBA3}.Debug|Any CPU.Build.0 = Debug|Any CPU
{DFAB6F2D-B9BF-4AFF-B22B-7684A328EBA3}.Release|Any CPU.ActiveCfg = Release|Any CPU
{DFAB6F2D-B9BF-4AFF-B22B-7684A328EBA3}.Release|Any CPU.Build.0 = Release|Any CPU
{2D5D3A1D-5730-4648-B0AB-06C53CB910C0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{2D5D3A1D-5730-4648-B0AB-06C53CB910C0}.Debug|Any CPU.Build.0 = Debug|Any CPU
{2D5D3A1D-5730-4648-B0AB-06C53CB910C0}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2D5D3A1D-5730-4648-B0AB-06C53CB910C0}.Release|Any CPU.Build.0 = Release|Any CPU
{D99A395A-8569-4DB0-B336-900647890052}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D99A395A-8569-4DB0-B336-900647890052}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D99A395A-8569-4DB0-B336-900647890052}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D99A395A-8569-4DB0-B336-900647890052}.Release|Any CPU.Build.0 = Release|Any CPU
{C16F112F-38C3-40BC-9F5F-4791112063D6}.Release|x64.ActiveCfg = Release|Any CPU
{C16F112F-38C3-40BC-9F5F-4791112063D6}.Release|x64.Build.0 = Release|Any CPU
{C16F112F-38C3-40BC-9F5F-4791112063D6}.Release|x86.ActiveCfg = Release|Any CPU
{C16F112F-38C3-40BC-9F5F-4791112063D6}.Release|x86.Build.0 = Release|Any CPU
{BEE1C184-C9A4-410B-8DFC-FB74D5C93AEB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{BEE1C184-C9A4-410B-8DFC-FB74D5C93AEB}.Debug|Any CPU.Build.0 = Debug|Any CPU
{BEE1C184-C9A4-410B-8DFC-FB74D5C93AEB}.Debug|x64.ActiveCfg = Debug|Any CPU
{BEE1C184-C9A4-410B-8DFC-FB74D5C93AEB}.Debug|x64.Build.0 = Debug|Any CPU
{BEE1C184-C9A4-410B-8DFC-FB74D5C93AEB}.Debug|x86.ActiveCfg = Debug|Any CPU
{BEE1C184-C9A4-410B-8DFC-FB74D5C93AEB}.Debug|x86.Build.0 = Debug|Any CPU
{BEE1C184-C9A4-410B-8DFC-FB74D5C93AEB}.Release|Any CPU.ActiveCfg = Release|Any CPU
{BEE1C184-C9A4-410B-8DFC-FB74D5C93AEB}.Release|Any CPU.Build.0 = Release|Any CPU
{BEE1C184-C9A4-410B-8DFC-FB74D5C93AEB}.Release|x64.ActiveCfg = Release|Any CPU
{BEE1C184-C9A4-410B-8DFC-FB74D5C93AEB}.Release|x64.Build.0 = Release|Any CPU
{BEE1C184-C9A4-410B-8DFC-FB74D5C93AEB}.Release|x86.ActiveCfg = Release|Any CPU
{BEE1C184-C9A4-410B-8DFC-FB74D5C93AEB}.Release|x86.Build.0 = Release|Any CPU
{7C1B2721-13DA-4B62-B046-C626605ECCE6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{7C1B2721-13DA-4B62-B046-C626605ECCE6}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7C1B2721-13DA-4B62-B046-C626605ECCE6}.Debug|x64.ActiveCfg = Debug|Any CPU
{7C1B2721-13DA-4B62-B046-C626605ECCE6}.Debug|x64.Build.0 = Debug|Any CPU
{7C1B2721-13DA-4B62-B046-C626605ECCE6}.Debug|x86.ActiveCfg = Debug|Any CPU
{7C1B2721-13DA-4B62-B046-C626605ECCE6}.Debug|x86.Build.0 = Debug|Any CPU
{7C1B2721-13DA-4B62-B046-C626605ECCE6}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7C1B2721-13DA-4B62-B046-C626605ECCE6}.Release|Any CPU.Build.0 = Release|Any CPU
{BA161CA0-CD65-4E6E-B644-51C8D1E542DC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{BA161CA0-CD65-4E6E-B644-51C8D1E542DC}.Debug|Any CPU.Build.0 = Debug|Any CPU
{BA161CA0-CD65-4E6E-B644-51C8D1E542DC}.Release|Any CPU.ActiveCfg = Release|Any CPU
{BA161CA0-CD65-4E6E-B644-51C8D1E542DC}.Release|Any CPU.Build.0 = Release|Any CPU
{7C1B2721-13DA-4B62-B046-C626605ECCE6}.Release|x64.ActiveCfg = Release|Any CPU
{7C1B2721-13DA-4B62-B046-C626605ECCE6}.Release|x64.Build.0 = Release|Any CPU
{7C1B2721-13DA-4B62-B046-C626605ECCE6}.Release|x86.ActiveCfg = Release|Any CPU
{7C1B2721-13DA-4B62-B046-C626605ECCE6}.Release|x86.Build.0 = Release|Any CPU
{6AE2A5E8-4C5A-48B9-997B-E1455C0355C6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{6AE2A5E8-4C5A-48B9-997B-E1455C0355C6}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6AE2A5E8-4C5A-48B9-997B-E1455C0355C6}.Debug|x64.ActiveCfg = Debug|Any CPU
{6AE2A5E8-4C5A-48B9-997B-E1455C0355C6}.Debug|x64.Build.0 = Debug|Any CPU
{6AE2A5E8-4C5A-48B9-997B-E1455C0355C6}.Debug|x86.ActiveCfg = Debug|Any CPU
{6AE2A5E8-4C5A-48B9-997B-E1455C0355C6}.Debug|x86.Build.0 = Debug|Any CPU
{6AE2A5E8-4C5A-48B9-997B-E1455C0355C6}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6AE2A5E8-4C5A-48B9-997B-E1455C0355C6}.Release|Any CPU.Build.0 = Release|Any CPU
{6AE2A5E8-4C5A-48B9-997B-E1455C0355C6}.Release|x64.ActiveCfg = Release|Any CPU
{6AE2A5E8-4C5A-48B9-997B-E1455C0355C6}.Release|x64.Build.0 = Release|Any CPU
{6AE2A5E8-4C5A-48B9-997B-E1455C0355C6}.Release|x86.ActiveCfg = Release|Any CPU
{6AE2A5E8-4C5A-48B9-997B-E1455C0355C6}.Release|x86.Build.0 = Release|Any CPU
{D4D09B08-D580-4D69-B886-C35D2853F6C8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D4D09B08-D580-4D69-B886-C35D2853F6C8}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D4D09B08-D580-4D69-B886-C35D2853F6C8}.Debug|x64.ActiveCfg = Debug|Any CPU
{D4D09B08-D580-4D69-B886-C35D2853F6C8}.Debug|x64.Build.0 = Debug|Any CPU
{D4D09B08-D580-4D69-B886-C35D2853F6C8}.Debug|x86.ActiveCfg = Debug|Any CPU
{D4D09B08-D580-4D69-B886-C35D2853F6C8}.Debug|x86.Build.0 = Debug|Any CPU
{D4D09B08-D580-4D69-B886-C35D2853F6C8}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D4D09B08-D580-4D69-B886-C35D2853F6C8}.Release|Any CPU.Build.0 = Release|Any CPU
{D4D09B08-D580-4D69-B886-C35D2853F6C8}.Release|x64.ActiveCfg = Release|Any CPU
{D4D09B08-D580-4D69-B886-C35D2853F6C8}.Release|x64.Build.0 = Release|Any CPU
{D4D09B08-D580-4D69-B886-C35D2853F6C8}.Release|x86.ActiveCfg = Release|Any CPU
{D4D09B08-D580-4D69-B886-C35D2853F6C8}.Release|x86.Build.0 = Release|Any CPU
{2BCB3D7A-38C0-4FE7-8FDA-374C6AD56D0E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{2BCB3D7A-38C0-4FE7-8FDA-374C6AD56D0E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{2BCB3D7A-38C0-4FE7-8FDA-374C6AD56D0E}.Debug|x64.ActiveCfg = Debug|Any CPU
{2BCB3D7A-38C0-4FE7-8FDA-374C6AD56D0E}.Debug|x64.Build.0 = Debug|Any CPU
{2BCB3D7A-38C0-4FE7-8FDA-374C6AD56D0E}.Debug|x86.ActiveCfg = Debug|Any CPU
{2BCB3D7A-38C0-4FE7-8FDA-374C6AD56D0E}.Debug|x86.Build.0 = Debug|Any CPU
{2BCB3D7A-38C0-4FE7-8FDA-374C6AD56D0E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2BCB3D7A-38C0-4FE7-8FDA-374C6AD56D0E}.Release|Any CPU.Build.0 = Release|Any CPU
{2BCB3D7A-38C0-4FE7-8FDA-374C6AD56D0E}.Release|x64.ActiveCfg = Release|Any CPU
{2BCB3D7A-38C0-4FE7-8FDA-374C6AD56D0E}.Release|x64.Build.0 = Release|Any CPU
{2BCB3D7A-38C0-4FE7-8FDA-374C6AD56D0E}.Release|x86.ActiveCfg = Release|Any CPU
{2BCB3D7A-38C0-4FE7-8FDA-374C6AD56D0E}.Release|x86.Build.0 = Release|Any CPU
{77D01AD9-2C98-478E-AE1D-8F7100738FB4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{77D01AD9-2C98-478E-AE1D-8F7100738FB4}.Debug|Any CPU.Build.0 = Debug|Any CPU
{77D01AD9-2C98-478E-AE1D-8F7100738FB4}.Debug|x64.ActiveCfg = Debug|Any CPU
{77D01AD9-2C98-478E-AE1D-8F7100738FB4}.Debug|x64.Build.0 = Debug|Any CPU
{77D01AD9-2C98-478E-AE1D-8F7100738FB4}.Debug|x86.ActiveCfg = Debug|Any CPU
{77D01AD9-2C98-478E-AE1D-8F7100738FB4}.Debug|x86.Build.0 = Debug|Any CPU
{77D01AD9-2C98-478E-AE1D-8F7100738FB4}.Release|Any CPU.ActiveCfg = Release|Any CPU
{77D01AD9-2C98-478E-AE1D-8F7100738FB4}.Release|Any CPU.Build.0 = Release|Any CPU
{77D01AD9-2C98-478E-AE1D-8F7100738FB4}.Release|x64.ActiveCfg = Release|Any CPU
{77D01AD9-2C98-478E-AE1D-8F7100738FB4}.Release|x64.Build.0 = Release|Any CPU
{77D01AD9-2C98-478E-AE1D-8F7100738FB4}.Release|x86.ActiveCfg = Release|Any CPU
{77D01AD9-2C98-478E-AE1D-8F7100738FB4}.Release|x86.Build.0 = Release|Any CPU
{77F96ECE-4952-42DB-A528-DED25572A573}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{77F96ECE-4952-42DB-A528-DED25572A573}.Debug|Any CPU.Build.0 = Debug|Any CPU
{77F96ECE-4952-42DB-A528-DED25572A573}.Debug|x64.ActiveCfg = Debug|Any CPU
{77F96ECE-4952-42DB-A528-DED25572A573}.Debug|x64.Build.0 = Debug|Any CPU
{77F96ECE-4952-42DB-A528-DED25572A573}.Debug|x86.ActiveCfg = Debug|Any CPU
{77F96ECE-4952-42DB-A528-DED25572A573}.Debug|x86.Build.0 = Debug|Any CPU
{77F96ECE-4952-42DB-A528-DED25572A573}.Release|Any CPU.ActiveCfg = Release|Any CPU
{77F96ECE-4952-42DB-A528-DED25572A573}.Release|Any CPU.Build.0 = Release|Any CPU
{77F96ECE-4952-42DB-A528-DED25572A573}.Release|x64.ActiveCfg = Release|Any CPU
{77F96ECE-4952-42DB-A528-DED25572A573}.Release|x64.Build.0 = Release|Any CPU
{77F96ECE-4952-42DB-A528-DED25572A573}.Release|x86.ActiveCfg = Release|Any CPU
{77F96ECE-4952-42DB-A528-DED25572A573}.Release|x86.Build.0 = Release|Any CPU
{AF34127A-3A92-43E5-8496-14960A50B1F1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{AF34127A-3A92-43E5-8496-14960A50B1F1}.Debug|Any CPU.Build.0 = Debug|Any CPU
{AF34127A-3A92-43E5-8496-14960A50B1F1}.Debug|x64.ActiveCfg = Debug|Any CPU
{AF34127A-3A92-43E5-8496-14960A50B1F1}.Debug|x64.Build.0 = Debug|Any CPU
{AF34127A-3A92-43E5-8496-14960A50B1F1}.Debug|x86.ActiveCfg = Debug|Any CPU
{AF34127A-3A92-43E5-8496-14960A50B1F1}.Debug|x86.Build.0 = Debug|Any CPU
{AF34127A-3A92-43E5-8496-14960A50B1F1}.Release|Any CPU.ActiveCfg = Release|Any CPU
{AF34127A-3A92-43E5-8496-14960A50B1F1}.Release|Any CPU.Build.0 = Release|Any CPU
{AF34127A-3A92-43E5-8496-14960A50B1F1}.Release|x64.ActiveCfg = Release|Any CPU
{AF34127A-3A92-43E5-8496-14960A50B1F1}.Release|x64.Build.0 = Release|Any CPU
{AF34127A-3A92-43E5-8496-14960A50B1F1}.Release|x86.ActiveCfg = Release|Any CPU
{AF34127A-3A92-43E5-8496-14960A50B1F1}.Release|x86.Build.0 = Release|Any CPU
{7F55A45D-4E1D-4A36-ADD3-87F29A285AA2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{7F55A45D-4E1D-4A36-ADD3-87F29A285AA2}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7F55A45D-4E1D-4A36-ADD3-87F29A285AA2}.Debug|x64.ActiveCfg = Debug|Any CPU
{7F55A45D-4E1D-4A36-ADD3-87F29A285AA2}.Debug|x64.Build.0 = Debug|Any CPU
{7F55A45D-4E1D-4A36-ADD3-87F29A285AA2}.Debug|x86.ActiveCfg = Debug|Any CPU
{7F55A45D-4E1D-4A36-ADD3-87F29A285AA2}.Debug|x86.Build.0 = Debug|Any CPU
{7F55A45D-4E1D-4A36-ADD3-87F29A285AA2}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7F55A45D-4E1D-4A36-ADD3-87F29A285AA2}.Release|Any CPU.Build.0 = Release|Any CPU
{7F55A45D-4E1D-4A36-ADD3-87F29A285AA2}.Release|x64.ActiveCfg = Release|Any CPU
{7F55A45D-4E1D-4A36-ADD3-87F29A285AA2}.Release|x64.Build.0 = Release|Any CPU
{7F55A45D-4E1D-4A36-ADD3-87F29A285AA2}.Release|x86.ActiveCfg = Release|Any CPU
{7F55A45D-4E1D-4A36-ADD3-87F29A285AA2}.Release|x86.Build.0 = Release|Any CPU
{B575BCDE-2FD8-4A5D-8756-31CDD7FE81F0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B575BCDE-2FD8-4A5D-8756-31CDD7FE81F0}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B575BCDE-2FD8-4A5D-8756-31CDD7FE81F0}.Debug|x64.ActiveCfg = Debug|Any CPU
{B575BCDE-2FD8-4A5D-8756-31CDD7FE81F0}.Debug|x64.Build.0 = Debug|Any CPU
{B575BCDE-2FD8-4A5D-8756-31CDD7FE81F0}.Debug|x86.ActiveCfg = Debug|Any CPU
{B575BCDE-2FD8-4A5D-8756-31CDD7FE81F0}.Debug|x86.Build.0 = Debug|Any CPU
{B575BCDE-2FD8-4A5D-8756-31CDD7FE81F0}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B575BCDE-2FD8-4A5D-8756-31CDD7FE81F0}.Release|Any CPU.Build.0 = Release|Any CPU
{B575BCDE-2FD8-4A5D-8756-31CDD7FE81F0}.Release|x64.ActiveCfg = Release|Any CPU
{B575BCDE-2FD8-4A5D-8756-31CDD7FE81F0}.Release|x64.Build.0 = Release|Any CPU
{B575BCDE-2FD8-4A5D-8756-31CDD7FE81F0}.Release|x86.ActiveCfg = Release|Any CPU
{B575BCDE-2FD8-4A5D-8756-31CDD7FE81F0}.Release|x86.Build.0 = Release|Any CPU
{4A89A234-4F19-497D-A576-DDE8CDFC5B22}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{4A89A234-4F19-497D-A576-DDE8CDFC5B22}.Debug|Any CPU.Build.0 = Debug|Any CPU
{4A89A234-4F19-497D-A576-DDE8CDFC5B22}.Debug|x64.ActiveCfg = Debug|Any CPU
{4A89A234-4F19-497D-A576-DDE8CDFC5B22}.Debug|x64.Build.0 = Debug|Any CPU
{4A89A234-4F19-497D-A576-DDE8CDFC5B22}.Debug|x86.ActiveCfg = Debug|Any CPU
{4A89A234-4F19-497D-A576-DDE8CDFC5B22}.Debug|x86.Build.0 = Debug|Any CPU
{4A89A234-4F19-497D-A576-DDE8CDFC5B22}.Release|Any CPU.ActiveCfg = Release|Any CPU
{4A89A234-4F19-497D-A576-DDE8CDFC5B22}.Release|x64.ActiveCfg = Release|Any CPU
{4A89A234-4F19-497D-A576-DDE8CDFC5B22}.Release|x64.Build.0 = Release|Any CPU
{4A89A234-4F19-497D-A576-DDE8CDFC5B22}.Release|x86.ActiveCfg = Release|Any CPU
{4A89A234-4F19-497D-A576-DDE8CDFC5B22}.Release|x86.Build.0 = Release|Any CPU
{F6F9826A-BC58-4D78-A700-F358A66B2B06}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{F6F9826A-BC58-4D78-A700-F358A66B2B06}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F6F9826A-BC58-4D78-A700-F358A66B2B06}.Debug|x64.ActiveCfg = Debug|Any CPU
{F6F9826A-BC58-4D78-A700-F358A66B2B06}.Debug|x64.Build.0 = Debug|Any CPU
{F6F9826A-BC58-4D78-A700-F358A66B2B06}.Debug|x86.ActiveCfg = Debug|Any CPU
{F6F9826A-BC58-4D78-A700-F358A66B2B06}.Debug|x86.Build.0 = Debug|Any CPU
{F6F9826A-BC58-4D78-A700-F358A66B2B06}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F6F9826A-BC58-4D78-A700-F358A66B2B06}.Release|Any CPU.Build.0 = Release|Any CPU
{F6F9826A-BC58-4D78-A700-F358A66B2B06}.Release|x64.ActiveCfg = Release|Any CPU
{F6F9826A-BC58-4D78-A700-F358A66B2B06}.Release|x64.Build.0 = Release|Any CPU
{F6F9826A-BC58-4D78-A700-F358A66B2B06}.Release|x86.ActiveCfg = Release|Any CPU
{F6F9826A-BC58-4D78-A700-F358A66B2B06}.Release|x86.Build.0 = Release|Any CPU
{D728444C-3D1F-4A0E-B4C9-5C9375D47EA3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D728444C-3D1F-4A0E-B4C9-5C9375D47EA3}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D728444C-3D1F-4A0E-B4C9-5C9375D47EA3}.Debug|x64.ActiveCfg = Debug|Any CPU
{D728444C-3D1F-4A0E-B4C9-5C9375D47EA3}.Debug|x64.Build.0 = Debug|Any CPU
{D728444C-3D1F-4A0E-B4C9-5C9375D47EA3}.Debug|x86.ActiveCfg = Debug|Any CPU
{D728444C-3D1F-4A0E-B4C9-5C9375D47EA3}.Debug|x86.Build.0 = Debug|Any CPU
{D728444C-3D1F-4A0E-B4C9-5C9375D47EA3}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D728444C-3D1F-4A0E-B4C9-5C9375D47EA3}.Release|Any CPU.Build.0 = Release|Any CPU
{D728444C-3D1F-4A0E-B4C9-5C9375D47EA3}.Release|x64.ActiveCfg = Release|Any CPU
{D728444C-3D1F-4A0E-B4C9-5C9375D47EA3}.Release|x64.Build.0 = Release|Any CPU
{D728444C-3D1F-4A0E-B4C9-5C9375D47EA3}.Release|x86.ActiveCfg = Release|Any CPU
{D728444C-3D1F-4A0E-B4C9-5C9375D47EA3}.Release|x86.Build.0 = Release|Any CPU
{988E6191-82E1-4E13-9DDB-CB9FA2FDAF29}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{988E6191-82E1-4E13-9DDB-CB9FA2FDAF29}.Debug|Any CPU.Build.0 = Debug|Any CPU
{988E6191-82E1-4E13-9DDB-CB9FA2FDAF29}.Debug|x64.ActiveCfg = Debug|Any CPU
{988E6191-82E1-4E13-9DDB-CB9FA2FDAF29}.Debug|x64.Build.0 = Debug|Any CPU
{988E6191-82E1-4E13-9DDB-CB9FA2FDAF29}.Debug|x86.ActiveCfg = Debug|Any CPU
{988E6191-82E1-4E13-9DDB-CB9FA2FDAF29}.Debug|x86.Build.0 = Debug|Any CPU
{988E6191-82E1-4E13-9DDB-CB9FA2FDAF29}.Release|Any CPU.ActiveCfg = Release|Any CPU
{988E6191-82E1-4E13-9DDB-CB9FA2FDAF29}.Release|Any CPU.Build.0 = Release|Any CPU
{988E6191-82E1-4E13-9DDB-CB9FA2FDAF29}.Release|x64.ActiveCfg = Release|Any CPU
{988E6191-82E1-4E13-9DDB-CB9FA2FDAF29}.Release|x64.Build.0 = Release|Any CPU
{988E6191-82E1-4E13-9DDB-CB9FA2FDAF29}.Release|x86.ActiveCfg = Release|Any CPU
{988E6191-82E1-4E13-9DDB-CB9FA2FDAF29}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{F6F9826A-BC58-4D78-A700-F358A66B2B06} = {827E0CD3-B72D-47B6-A68D-7590B98EB39B}
{D728444C-3D1F-4A0E-B4C9-5C9375D47EA3} = {827E0CD3-B72D-47B6-A68D-7590B98EB39B}
{988E6191-82E1-4E13-9DDB-CB9FA2FDAF29} = {827E0CD3-B72D-47B6-A68D-7590B98EB39B}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {110169B3-3328-4730-8AB0-BA05BEF75C1A}
EndGlobalSection

File diff suppressed because it is too large Load Diff

View File

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

View File

@@ -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

View File

@@ -34,7 +34,7 @@
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleLongVersionString</key>
<string>%%RYUJINX_BUILD_VERSION%%-%%RYUJINX_BUILD_GIT_HASH%%"</string>
<string>%%RYUJINX_BUILD_VERSION%%-%%RYUJINX_BUILD_GIT_HASH%%</string>
<key>CFBundleName</key>
<string>Ryujinx</string>
<key>CFBundlePackageType</key>
@@ -44,13 +44,13 @@
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1.2.0</string>
<string>%%RYUJINX_BUILD_VERSION%%</string>
<key>NSHighResolutionCapable</key>
<true/>
<key>CSResourcesFileMapped</key>
<true/>
<key>NSHumanReadableCopyright</key>
<string>Copyright © 2018 - 2023 Ryujinx Team and Contributors.</string>
<string>Copyright © 2018 - 2024 Ryujinx Team and Contributors. Copyright © 2024 - 2025 Ryubing and Contributors.</string>
<key>LSApplicationCategoryType</key>
<string>public.app-category.games</string>
<key>LSMinimumSystemVersion</key>

View File

@@ -43,7 +43,7 @@ fi
ARM64_OUTPUT="$TEMP_DIRECTORY/publish_arm64"
X64_OUTPUT="$TEMP_DIRECTORY/publish_x64"
UNIVERSAL_OUTPUT="$OUTPUT_DIRECTORY/publish"
EXECUTABLE_SUB_PATH=Ryujinx.Headless.SDL2
EXECUTABLE_SUB_PATH=Ryujinx.Headless.SDL3
rm -rf "$TEMP_DIRECTORY"
mkdir -p "$TEMP_DIRECTORY"
@@ -51,9 +51,9 @@ mkdir -p "$TEMP_DIRECTORY"
DOTNET_COMMON_ARGS=(-p:DebugType=embedded -p:Version="$VERSION" -p:SourceRevisionId="$SOURCE_REVISION_ID" --self-contained true $EXTRA_ARGS)
dotnet restore
dotnet build -c "$CONFIGURATION" src/Ryujinx.Headless.SDL2
dotnet publish -c "$CONFIGURATION" -r osx-arm64 -o "$TEMP_DIRECTORY/publish_arm64" "${DOTNET_COMMON_ARGS[@]}" src/Ryujinx.Headless.SDL2
dotnet publish -c "$CONFIGURATION" -r osx-x64 -o "$TEMP_DIRECTORY/publish_x64" "${DOTNET_COMMON_ARGS[@]}" src/Ryujinx.Headless.SDL2
dotnet build -c "$CONFIGURATION" src/Ryujinx.Headless.SDL3
dotnet publish -c "$CONFIGURATION" -r osx-arm64 -o "$TEMP_DIRECTORY/publish_arm64" "${DOTNET_COMMON_ARGS[@]}" src/Ryujinx.Headless.SDL3
dotnet publish -c "$CONFIGURATION" -r osx-x64 -o "$TEMP_DIRECTORY/publish_x64" "${DOTNET_COMMON_ARGS[@]}" src/Ryujinx.Headless.SDL3
# Get rid of the support library for ARMeilleure for x64 (that's only for arm64)
rm -rf "$TEMP_DIRECTORY/publish_x64/libarmeilleure-jitsupport.dylib"
@@ -115,8 +115,8 @@ fi
echo "Creating archive"
pushd "$OUTPUT_DIRECTORY"
tar --exclude "publish/Ryujinx.Headless.SDL2" -cvf "$RELEASE_TAR_FILE_NAME" publish 1> /dev/null
python3 "$BASE_DIR/distribution/misc/add_tar_exec.py" "$RELEASE_TAR_FILE_NAME" "publish/Ryujinx.Headless.SDL2" "publish/Ryujinx.Headless.SDL2"
tar --exclude "publish/Ryujinx.Headless.SDL3" -cvf "$RELEASE_TAR_FILE_NAME" publish 1> /dev/null
python3 "$BASE_DIR/distribution/misc/add_tar_exec.py" "$RELEASE_TAR_FILE_NAME" "publish/Ryujinx.Headless.SDL3" "publish/Ryujinx.Headless.SDL3"
gzip -9 < "$RELEASE_TAR_FILE_NAME" > "$RELEASE_TAR_FILE_NAME.gz"
rm "$RELEASE_TAR_FILE_NAME"
popd

View File

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

View File

@@ -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
@@ -2263,6 +2272,7 @@
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
@@ -2270,6 +2280,7 @@
01008F6008C5E000,"Pokémon™ Violet",gpu;nvdec;ldn-works;amd-vendor-bug;mac-bug,ingame,2024-07-30 02:51:48
0100187003A36000,"Pokémon™: Lets Go, Eevee!",crash;nvdec;online-broken;ldn-broken,ingame,2024-06-01 15:03:04
010003F003A34000,"Pokémon™: Lets Go, Pikachu!",crash;nvdec;online-broken;ldn-broken,ingame,2024-03-15 07:55:41
0100F43008C44000,"Pokémon Legends: Z-A",gpu;crash;ldn-broken,ingame,2025-10-16 19:13:00
0100B3F000BE2000,"Pokkén Tournament™ DX",nvdec;ldn-works;opengl-backend-bug;LAN;amd-vendor-bug;intel-vendor-bug,playable,2024-07-18 23:11:08
010030D005AE6000,"Pokkén Tournament™ DX Demo",demo;opengl-backend-bug,playable,2022-08-10 12:03:19
0100A3500B4EC000,"Polandball: Can Into Space",,playable,2020-06-25 15:13:26
@@ -2306,6 +2317,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
@@ -2571,6 +2583,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
@@ -2697,6 +2710,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
@@ -2768,7 +2783,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
@@ -2854,11 +2869,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 + Bowsers 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
@@ -2924,6 +2941,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
@@ -2969,6 +2987,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
@@ -2976,6 +2995,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
@@ -3198,6 +3218,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
@@ -3207,6 +3228,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
@@ -3221,6 +3243,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
@@ -3451,3 +3475,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
1 title_id game_name labels status last_updated
188 01003DD00BFEE000 Airheart - Tales of broken Wings playable 2021-02-26 15:20:27
189 01007F100DE52000 Akane nvdec playable 2022-07-21 00:12:18
190 01009A800F0C8000 Akash: Path of the Five gpu;nvdec ingame 2020-12-14 22:33:12
191 01009E8012976000 AKIBA'S TRIP: Hellbound & Debriefed playable 2025-07-30 23:22:47
192 0100D74019A0E000 AKIBA'S TRIP: Undead & Undressed Director's Cut playable 2025-07-31 13:58:42
193 010053100B0EA000 Akihabara - Feel the Rhythm Remixed playable 2021-02-22 14:39:35
194 0100D4C00EE0C000 Akuarium slow playable 2020-12-12 23:43:36
195 010026E00FEBE000 Akuto: Showdown playable 2020-08-04 19:43:27
978 0100416004C00000 DOOM gpu;slow;nvdec;online-broken ingame 2024-09-23 15:40:07
979 010018900DD00000 DOOM (1993) nvdec;online-broken menus 2022-09-06 13:32:19
980 01008CB01E52E000 DOOM + DOOM II opengl;ldn-untested;LAN playable 2024-09-12 07:06:01
981 010029D00E740000 DOOM 3 crash crash;slow menus 2024-08-03 05:25:47
982 01005D700E742000 DOOM 64 nvdec;vulkan playable 2020-10-13 23:47:28
983 0100D4F00DD02000 DOOM II (Classic) nvdec;online playable 2021-06-03 20:10:01
984 0100B1A00D8CE000 DOOM® Eternal gpu;slow;nvdec;online-broken ingame 2024-08-28 15:57:17
1097 0100F9600E746000 ESP Ra.De. Psi audio;slow ingame 2024-03-07 15:05:08
1098 010073000FE18000 Esports powerful pro yakyuu 2020 gpu;crash;Needs More Attention ingame 2024-04-29 05:34:14
1099 01004F9012FD8000 Estranged: The Departure nvdec;UE4 playable 2022-10-24 10:37:58
1100 010018F01E0A0000 Eternights playable 2025-07-30 12:10:24
1101 0100CB900B498000 Eternum Ex playable 2021-01-13 20:28:32
1102 010092501EB2C000 Europa (Demo) gpu;crash;UE4 ingame 2024-04-23 10:47:12
1103 01007BE0160D6000 EVE ghost enemies gpu ingame 2023-01-14 03:13:30
1175 0100EB100AB42000 FINAL FANTASY XII THE ZODIAC AGE opengl;vulkan-backend-bug playable 2024-08-11 07:01:54
1176 010068F00AA78000 FINAL FANTASY XV POCKET EDITION HD playable 2021-01-05 17:52:08
1177 0100CE4010AAC000 FINAL FANTASY® CRYSTAL CHRONICLES™ Remastered Edition playable 2023-04-02 23:39:12
1178 010038B015560000 FINAL FANTASY TACTICS - The Ivalice Chronicles gpu boots 2024-09-30 02:59:00
1179 01001BA00AE4E000 Final Light, The Prison playable 2020-07-31 21:48:44
1180 0100FF100FB68000 Finding Teddy 2 : Definitive Edition gpu ingame 2024-04-19 16:51:33
1181 0100F4E013AAE000 Fire & Water playable 2020-12-15 15:43:20
1244 010003F00BD48000 Friday the 13th: Killer Puzzle playable 2021-01-28 01:33:38
1245 010092A00C4B6000 Friday the 13th: The Game Ultimate Slasher Edition nvdec;online-broken;UE4 playable 2022-09-06 17:33:27
1246 0100F200178F4000 FRONT MISSION 1st: Remake playable 2023-06-09 07:44:24
1247 0100C4E018A24000 FRONT MISSION 2: Remake playable 2025-07-30 12:11:23
1248 01007E6019872000 FRONT MISSION 3: Remake playable 2025-07-30 12:12:02
1249 0100861012474000 Frontline Zed playable 2020-10-03 12:55:59
1250 0100B5300B49A000 Frost playable 2022-07-27 12:00:36
1251 010038A007AA4000 FruitFall Crush playable 2020-10-20 11:33:33
1441 0100C2700E338000 Heroland playable 2020-08-05 15:35:39
1442 01007AC00E012000 HexaGravity playable 2021-05-28 13:47:48
1443 01004E800F03C000 Hidden slow ingame 2022-10-05 10:56:53
1444 0100C1101EE5A000 High on Life menus 2025-08-26 19:11:00
1445 0100F6A00A684000 Higurashi no Naku Koro ni Hō audio ingame 2021-09-18 14:40:28
1446 0100F8D0129F4000 Himehibi 1 gakki - Princess Days crash nothing 2021-11-03 08:34:19
1447 0100F3D008436000 Hiragana Pixel Party playable 2021-01-14 08:36:50
1451 0100F7300ED2C000 Hoggy2 playable 2022-10-10 13:53:35
1452 0100F7E00C70E000 Hogwarts Legacy UE4;slow ingame 2024-09-03 19:53:58
1453 0100633007D48000 Hollow Knight nvdec playable 2023-01-16 15:44:56
1454 010013C00E930000 Hollow Knight: Silksong playable 2025-09-04 17:23:22
1455 0100F2100061E800 Hollow0 UE4;gpu ingame 2021-03-03 23:42:56
1456 0100342009E16000 Holy Potatoes! What The Hell?! playable 2020-07-03 10:48:56
1457 010071B00C904000 HoPiKo playable 2021-01-13 20:12:38
1526 010095C016C14000 Iridium playable 2022-08-05 23:19:53
1527 0100AD300B786000 Iris School of Wizardry -Vinculum Hearts- playable 2022-12-05 13:11:15
1528 0100945012168000 Iris.Fall nvdec playable 2022-10-18 13:40:22
1529 010059801B736000 IronFall: Invasion playable 2025-07-30 11:42:30
1530 01005270118D6000 Iron Wings slow ingame 2022-08-07 08:32:57
1531 01004DB003E6A000 IRONCAST playable 2021-01-13 13:54:29
1532 0100E5700CD56000 Irony Curtain: From Matryoshka with Love playable 2021-06-04 20:12:37
1890 010097800EA20000 Monster Energy Supercross - The Official Videogame 3 UE4;audout;nvdec;online playable 2021-06-14 12:37:54
1891 0100E9900ED74000 Monster Farm 32-bit;nvdec playable 2021-05-05 19:29:13
1892 0100770008DD8000 Monster Hunter Generations Ultimate™ 32-bit;online-broken;ldn-works playable 2024-03-18 14:35:36
1893 0100B04011742000 Monster Hunter Rise MONSTER HUNTER RISE gpu;slow;crash;nvdec;online-broken;Needs Update;ldn-works ingame 2024-08-24 11:04:59
1894 010093A01305C000 Monster Hunter Rise Demo online-broken;ldn-works;demo playable 2022-10-18 23:04:17
1895 0100E21011446000 Monster Hunter Stories 2: Wings of Ruin services ingame 2022-07-10 19:27:30
1896 010042501329E000 MONSTER HUNTER STORIES 2: WINGS OF RUIN Trial Version demo playable 2022-11-13 22:20:26
2272 0100ABF008968000 Pokémon Sword + Pokémon Sword Expansion Pass deadlock;crash;online-broken;ldn-works;LAN ingame 2024-08-26 15:40:37
2273 01009AD008C4C000 Pokémon: Let's Go, Pikachu! demo slow;demo playable 2023-11-26 11:23:20
2274 0100000011D90000 Pokémon™ Brilliant Diamond gpu;ldn-works ingame 2024-08-28 13:26:35
2275 010018E011D92000 Pokémon™ Shining Pearl gpu;ldn-works ingame 2024-08-28 13:26:35
2276 010015F008C54000 Pokémon™ HOME Needs Update;crash;services menus 2020-12-06 06:01:51
2277 01001F5010DFA000 Pokémon™ Legends: Arceus gpu;Needs Update;ldn-works ingame 2024-09-19 10:02:02
2278 01005D100807A000 Pokémon™ Quest playable 2022-02-22 16:12:32
2280 01008F6008C5E000 Pokémon™ Violet gpu;nvdec;ldn-works;amd-vendor-bug;mac-bug ingame 2024-07-30 02:51:48
2281 0100187003A36000 Pokémon™: Let’s Go, Eevee! crash;nvdec;online-broken;ldn-broken ingame 2024-06-01 15:03:04
2282 010003F003A34000 Pokémon™: Let’s Go, Pikachu! crash;nvdec;online-broken;ldn-broken ingame 2024-03-15 07:55:41
2283 0100F43008C44000 Pokémon Legends: Z-A gpu;crash;ldn-broken ingame 2025-10-16 19:13:00
2284 0100B3F000BE2000 Pokkén Tournament™ DX nvdec;ldn-works;opengl-backend-bug;LAN;amd-vendor-bug;intel-vendor-bug playable 2024-07-18 23:11:08
2285 010030D005AE6000 Pokkén Tournament™ DX Demo demo;opengl-backend-bug playable 2022-08-10 12:03:19
2286 0100A3500B4EC000 Polandball: Can Into Space playable 2020-06-25 15:13:26
2317 010077B00BDD8000 Professional Farmer: Nintendo Switch™ Edition slow playable 2020-12-16 13:38:19
2318 010018300C83A000 Professor Lupo and his Horrible Pets playable 2020-06-12 00:08:45
2319 0100D1F0132F6000 Professor Lupo: Ocean playable 2021-04-14 16:33:33
2320 0100C3A017834000 Prodeus playable 2025-07-30 12:07:52
2321 0100BBD00976C000 Project Highrise: Architect's Edition playable 2022-08-10 17:19:12
2322 0100ACE00DAB6000 Project Nimbus: Complete Edition nvdec;UE4;vulkan-backend-bug playable 2022-08-10 17:35:43
2323 01002980140F6000 Project TRIANGLE STRATEGY™ Debut Demo UE4;demo playable 2022-10-24 21:40:27
2583 0100C610154CA000 Shadowrun: Hong Kong - Extended Edition gpu;Needs Update ingame 2022-10-04 20:53:09
2584 010000000EEF0000 Shadows 2: Perfidia playable 2020-08-07 12:43:46
2585 0100AD700CBBE000 Shadows of Adam playable 2021-01-11 13:35:58
2586 010037A01F96C000 Shadows of the Damned: Hella Remastered playable 2025-09-05 11:34:32
2587 01002A800C064000 Shadowverse Champions Battle playable 2022-10-02 22:59:29
2588 01003B90136DA000 Shadowverse: Champion's Battle crash nothing 2023-03-06 00:31:50
2589 0100820013612000 Shady Part of Me playable 2022-10-20 11:31:55
2710 01008F701C074000 SONIC SUPERSTARS gpu;nvdec ingame 2023-10-28 17:48:07
2711 010088801C150000 Sonic Superstars Digital Art Book with Mini Digital Soundtrack playable 2024-08-20 13:26:56
2712 01005EA01C0FC000 SONIC X SHADOW GENERATIONS crash ingame 2025-01-07 04:20:45
2713 010064B0242BE000 Sonic Racing: CrossWorlds - Demo gpu;vulkan-backend-bug;demo ingame 2024-09-25 11:27:53
2714 01006E001823C000 Sonic Racing: CrossWorlds gpu;vulkan-backend-bug;ldn-broken ingame 2024-09-30 17:23:00
2715 010064F00C212000 Soul Axiom Rebooted nvdec;slow ingame 2020-09-04 12:41:01
2716 0100F2100F0B2000 Soul Searching playable 2020-07-09 18:39:07
2717 01008F2005154000 South Park™: The Fractured but Whole™ - Standard Edition slow;online-broken;vulkan-backend-bug;gpu ingame 2025-01-21 17:35:10
2783 0100E6B0115FC000 Star99 online menus 2021-11-26 14:18:51
2784 01002100137BA000 Stardash playable 2021-01-21 16:31:19
2785 0100E65002BB8000 Stardew Valley online-broken;ldn-untested playable 2024-02-14 03:11:19
2786 01002CC003FE6000 Starlink: Battle for Atlas™ Digital Edition services-horizon;crash;Needs Update nothing playable 2024-05-05 17:25:11 2025-07-30 12:09:37
2787 010098E010FDA000 Starlit Adventures Golden Stars playable 2020-11-21 12:14:43
2788 01001BB00AC26000 STARSHIP AVENGER Operation: Take Back Earth playable 2021-01-12 15:52:55
2789 010000700A572000 State of Anarchy: Master of Mayhem nvdec playable 2021-01-12 19:00:05
2869 0100BC0018138000 Super Mario RPG™ gpu;audio;nvdec ingame 2024-06-19 17:43:42
2870 Super Mario World homebrew boots 2024-06-13 01:40:31
2871 010049900F546000 Super Mario™ 3D All-Stars services-horizon;slow;vulkan;amd-vendor-bug ingame 2024-05-07 02:38:16
2872 010099C022B96000 Super Mario Galaxy slow;vulkan;amd-vendor-bug;vulkan-vendor-bug ingame 2025-10-01 15:30:00
2873 0100FD8022DAA000 Super Mario Galaxy 2 slow;vulkan;amd-vendor-bug;vulkan-vendor-bug;deadlock ingame 2025-10-04 18:50:00
2874 010028600EBDA000 Super Mario™ 3D World + Bowser’s Fury ldn-works playable 2024-07-31 10:45:37
2875 01004F8006A78000 Super Meat Boy services playable 2020-04-02 23:10:07
2876 01009C200D60E000 Super Meat Boy Forever gpu boots 2021-04-26 14:25:39
2877 0100BDD00EC5C000 Super Mega Space Blaster Special Turbo online playable 2020-08-06 12:13:25
2878 010031F019294000 Super Monkey Ball Banana Rumble ldn-broken playable 2024-06-28 10:39:18 2025-10-01 18:03:00
2879 0100B2A00E1E0000 Super Monkey Ball: Banana Blitz HD online-broken playable 2022-09-16 13:16:25
2880 01006D000D2A0000 Super Mutant Alien Assault playable 2020-06-07 23:32:45
2881 01004D600AC14000 Super Neptunia RPG nvdec playable 2022-08-17 16:38:52
2941 0100B76011DAA000 Taxi Chaos slow;online-broken;UE4 playable 2022-10-25 19:13:00
2942 0100F43011E5A000 Tcheco in the Castle of Lucio playable 2020-06-27 13:35:43
2943 010092B0091D0000 Team Sonic Racing online-broken;ldn-works playable 2024-02-05 15:05:27
2944 010084B00B36E000 Team Sonic Racing online-broken;ldn-works playable 2024-02-05 15:05:27
2945 0100FE701475A000 Teenage Mutant Ninja Turtles: Shredder's Revenge deadlock;crash boots 2024-09-28 09:31:39
2946 01005CF01E784000 Teenage Mutant Ninja Turtles: Splintered Fate playable 2024-08-03 13:50:42
2947 0100FDB0154E4000 Teenage Mutant Ninja Turtles: The Cowabunga Collection playable 2024-01-22 19:39:04
2987 0100EBA01548E000 The Cruel King and the Great Hero gpu;services ingame 2022-12-02 07:02:08
2988 010051800E922000 The Dark Crystal: Age of Resistance Tactics playable 2020-08-11 13:43:41
2989 01003DE00918E000 The Darkside Detective playable 2020-06-03 22:16:18
2990 010032B015D66000 The DioField Chronicle playable 2025-09-05 11:35:50
2991 01000A10041EA000 The Elder Scrolls V: Skyrim gpu;crash ingame 2024-07-14 03:21:31
2992 01004A9006B84000 The End Is Nigh playable 2020-06-01 11:26:45
2993 0100CA100489C000 The Escapists 2 nvdec playable 2020-09-24 12:31:31
2995 0100C2E0129A6000 The Executioner nvdec playable 2021-01-23 00:31:28
2996 01006050114D4000 The Experiment: Escape Room gpu ingame 2022-09-30 13:20:35
2997 0100B5900DFB2000 The Eyes of Ara playable 2022-09-16 14:44:06
2998 0100BA5013E52000 The Falconeer: Warrior Edition playable 2025-07-30 12:04:50
2999 01002DD00AF9E000 The Fall gpu ingame 2020-05-31 23:31:16
3000 01003E5002320000 The Fall Part 2: Unbound playable 2021-11-06 02:18:08
3001 0100CDC00789E000 The Final Station nvdec playable 2022-08-22 15:54:39
3218 010000400F582000 TT Isle of Man Ride on the Edge 2 gpu;nvdec;online-broken ingame 2022-09-30 22:13:05
3219 0100752011628000 TTV2 playable 2020-11-27 13:21:36
3220 0100AFE00452E000 Tumblestone playable 2021-01-07 17:49:20
3221 0100D1A01D7BA000 Turbo Overkill playable 2025-07-30 12:08:57
3222 010085500D5F6000 Turok gpu ingame 2021-06-04 13:16:24
3223 0100CDC00D8D6000 Turok 2: Seeds of Evil gpu;vulkan ingame 2022-09-12 17:50:05
3224 010004B0130C8000 Turrican Flashback audout playable 2021-08-30 10:07:56
3228 010038400C2FE000 TY the Tasmanian Tiger™ HD 32-bit;crash;nvdec menus 2020-12-17 21:15:00
3229 010073A00C4B2000 Tyd wag vir Niemand playable 2021-03-02 13:39:53
3230 0100D5B00D6DA000 Type:Rider playable 2021-01-06 13:12:55
3231 01008AF01AD22000 The Patrick Star Game playable 2025-10-01 17:55:30
3232 010040D01222C000 UBERMOSH: SANTICIDE playable 2020-11-27 15:05:01
3233 0100992010BF8000 Ubongo playable 2021-02-04 21:15:01
3234 010079000B56C000 UglyDolls: An Imperfect Adventure nvdec;UE4 playable 2022-08-25 14:42:16
3243 0100592005164000 UNBOX: Newbie's Adventure UE4 playable 2022-08-29 13:12:56
3244 01002D900C5E4000 Uncanny Valley nvdec playable 2021-06-04 13:28:45
3245 010076F011F54000 Undead & Beyond nvdec playable 2022-10-04 09:11:18
3246 01009B700D0B8000 Undead Horde playable 2025-07-30 12:05:05
3247 0100FC301A878000 Undead Horde 2: Necropolis playable 2025-07-30 12:06:07
3248 01008F3013E4E000 Under Leaves playable 2021-05-22 18:13:58
3249 010080B00AD66000 Undertale playable 2022-08-31 17:31:46
3250 01008F80049C6000 Unepic playable 2024-01-15 17:03:00
3475 0100F4401940A000 超探偵事件簿 レインコード (Master Detective Archives: Rain Code) crash ingame 2024-02-12 20:58:31
3476 010064801A01C000 超次元ゲイム ネプテューヌ GameMaker R:Evolution crash nothing 2023-10-30 22:37:40
3477 0100F3400332C000 ゼノブレイド2 deadlock;amd-vendor-bug ingame 2024-03-28 14:31:41
3478 010075000ECBE000 超级马力欧 奥德赛 nvdec;intel-vendor-bug;mac-bug playable 2024-08-25 01:32:34
3479 010075100E8EC000 马力欧卡丁车8 豪华版 32-bit;ldn-works;LAN;amd-vendor-bug playable 2024-09-19 11:55:17
3480 0100E8C00F506000 新 超级马力欧兄弟U 豪华版 32-bit playable 2023-10-08 02:06:37

View File

@@ -1107,17 +1107,17 @@ namespace ARMeilleure.CodeGen.X86
}
else
{
if (flags.HasFlag(InstructionFlags.Prefix66))
if ((flags & InstructionFlags.Prefix66) != 0)
{
WriteByte(0x66);
}
if (flags.HasFlag(InstructionFlags.PrefixF2))
if ((flags & InstructionFlags.PrefixF2) != 0f)
{
WriteByte(0xf2);
}
if (flags.HasFlag(InstructionFlags.PrefixF3))
if ((flags & InstructionFlags.PrefixF3) != 0f)
{
WriteByte(0xf3);
}

View File

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

View File

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

View File

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

View File

@@ -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)
{

View File

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

View File

@@ -3,6 +3,7 @@ using ARMeilleure.State;
using ARMeilleure.Translation;
using System;
using System.Runtime.InteropServices;
using ExecutionContext = ARMeilleure.State.ExecutionContext;
namespace ARMeilleure.Instructions
{

View File

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

View File

@@ -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;

View File

@@ -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);
}

View File

@@ -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);

View File

@@ -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>();
}

View File

@@ -33,7 +33,7 @@ namespace ARMeilleure.Translation.PTC
private const string OuterHeaderMagicString = "PTCohd\0\0";
private const string InnerHeaderMagicString = "PTCihd\0\0";
private const uint InternalVersion = 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";
@@ -303,6 +303,13 @@ namespace ARMeilleure.Translation.PTC
return false;
}
if (outerHeader.DebuggerMode != Optimizations.EnableDebugging)
{
InvalidateCompressedStream(compressedStream);
return false;
}
nint intPtr = nint.Zero;
try
@@ -479,6 +486,7 @@ namespace ARMeilleure.Translation.PTC
MemoryManagerMode = GetMemoryManagerMode(),
OSPlatform = GetOSPlatform(),
Architecture = (uint)RuntimeInformation.ProcessArchitecture,
DebuggerMode = Optimizations.EnableDebugging,
UncompressedStreamSize =
(long)Unsafe.SizeOf<InnerHeader>() +
@@ -1068,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;
@@ -1080,6 +1088,7 @@ namespace ARMeilleure.Translation.PTC
public byte MemoryManagerMode;
public uint OSPlatform;
public uint Architecture;
public bool DebuggerMode;
public long UncompressedStreamSize;

View File

@@ -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 = [];

View File

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

View File

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

View File

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

View File

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

View File

@@ -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;
}
}

View File

@@ -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>

View File

@@ -81,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)]

View File

@@ -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;

View File

@@ -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
@@ -11,48 +11,55 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
{
public bool Enabled { get; set; }
public int NodeId { get; }
public int NodeId { get; private set; }
public CommandType CommandType => CommandType.AdpcmDataSourceVersion1;
public uint EstimatedProcessingTime { get; set; }
public ushort OutputBufferIndex { get; }
public uint SampleRate { get; }
public ushort OutputBufferIndex { get; private set; }
public uint SampleRate { get; private set; }
public float Pitch { get; }
public float Pitch { get; private set; }
public WaveBuffer[] WaveBuffers { get; }
public Memory<VoiceUpdateState> State { get; }
public Memory<VoiceState> State { get; private set; }
public ulong AdpcmParameter { get; }
public ulong AdpcmParameterSize { get; }
public ulong AdpcmParameter { get; private set; }
public ulong AdpcmParameterSize { get; private set; }
public DecodingBehaviour DecodingBehaviour { get; }
public DecodingBehaviour DecodingBehaviour { get; private set; }
public AdpcmDataSourceCommandVersion1(ref VoiceState serverState, Memory<VoiceUpdateState> state, ushort outputBufferIndex, int nodeId)
public AdpcmDataSourceCommandVersion1()
{
WaveBuffers = new WaveBuffer[Constants.VoiceWaveBufferCount];
}
public AdpcmDataSourceCommandVersion1 Initialize(ref VoiceInfo serverInfo, Memory<VoiceState> state, ushort outputBufferIndex, int nodeId)
{
Enabled = true;
NodeId = nodeId;
OutputBufferIndex = outputBufferIndex;
SampleRate = serverState.SampleRate;
Pitch = serverState.Pitch;
WaveBuffers = new WaveBuffer[Constants.VoiceWaveBufferCount];
SampleRate = serverInfo.SampleRate;
Pitch = serverInfo.Pitch;
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);
}
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;
return this;
}
public void Process(CommandList context)

View File

@@ -12,26 +12,31 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
{
public bool Enabled { get; set; }
public int NodeId { get; }
public int NodeId { get; private set; }
public CommandType CommandType => CommandType.AuxiliaryBuffer;
public uint EstimatedProcessingTime { get; set; }
public uint InputBufferIndex { get; }
public uint OutputBufferIndex { get; }
public uint InputBufferIndex { get; private set; }
public uint OutputBufferIndex { get; private set; }
public AuxiliaryBufferAddresses BufferInfo { get; }
public AuxiliaryBufferAddresses BufferInfo { get; private set; }
public CpuAddress InputBuffer { get; }
public CpuAddress OutputBuffer { get; }
public uint CountMax { get; }
public uint UpdateCount { get; }
public uint WriteOffset { get; }
public CpuAddress InputBuffer { get; private set; }
public CpuAddress OutputBuffer { get; private set; }
public uint CountMax { get; private set; }
public uint UpdateCount { get; private set; }
public uint WriteOffset { get; private set; }
public bool IsEffectEnabled { get; }
public bool IsEffectEnabled { get; private set; }
public AuxiliaryBufferCommand(
public AuxiliaryBufferCommand()
{
}
public AuxiliaryBufferCommand Initialize(
uint bufferOffset,
byte inputBufferOffset,
byte outputBufferOffset,
@@ -55,6 +60,8 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
UpdateCount = updateCount;
WriteOffset = writeOffset;
IsEffectEnabled = isEnabled;
return this;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]

View File

@@ -9,39 +9,44 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
{
public bool Enabled { get; set; }
public int NodeId { get; }
public int NodeId { get; private set; }
public CommandType CommandType => CommandType.BiquadFilterAndMix;
public uint EstimatedProcessingTime { get; set; }
public ushort InputBufferIndex { get; }
public ushort OutputBufferIndex { get; }
public ushort InputBufferIndex { get; private set; }
public ushort OutputBufferIndex { get; private set; }
private BiquadFilterParameter _parameter;
private BiquadFilterParameter2 _parameter;
public Memory<BiquadFilterState> BiquadFilterState { get; }
public Memory<BiquadFilterState> PreviousBiquadFilterState { get; }
public Memory<BiquadFilterState> BiquadFilterState { get; private set; }
public Memory<BiquadFilterState> PreviousBiquadFilterState { get; private set; }
public Memory<VoiceUpdateState> State { get; }
public Memory<VoiceState> State { get; private set; }
public int LastSampleIndex { get; }
public int LastSampleIndex { get; private set; }
public float Volume0 { get; }
public float Volume1 { get; }
public float Volume0 { get; private set; }
public float Volume1 { get; private set; }
public bool NeedInitialization { get; }
public bool HasVolumeRamp { get; }
public bool IsFirstMixBuffer { get; }
public bool NeedInitialization { get; private set; }
public bool HasVolumeRamp { get; private set; }
public bool IsFirstMixBuffer { get; private set; }
public BiquadFilterAndMixCommand(
public BiquadFilterAndMixCommand()
{
}
public BiquadFilterAndMixCommand Initialize(
float volume0,
float volume1,
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,
@@ -68,6 +73,8 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
NeedInitialization = needInitialization;
HasVolumeRamp = hasVolumeRamp;
IsFirstMixBuffer = isFirstMixBuffer;
return this;
}
public void Process(CommandList context)

View File

@@ -8,22 +8,27 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
{
public bool Enabled { get; set; }
public int NodeId { get; }
public int NodeId { get; private set; }
public CommandType CommandType => CommandType.BiquadFilter;
public uint EstimatedProcessingTime { get; set; }
public Memory<BiquadFilterState> BiquadFilterState { get; }
public int InputBufferIndex { get; }
public int OutputBufferIndex { get; }
public bool NeedInitialization { get; }
public Memory<BiquadFilterState> BiquadFilterState { get; private set; }
public int InputBufferIndex { get; private set; }
public int OutputBufferIndex { get; private set; }
public bool NeedInitialization { get; private set; }
private BiquadFilterParameter _parameter;
private BiquadFilterParameter2 _parameter;
public BiquadFilterCommand(
public BiquadFilterCommand()
{
}
public BiquadFilterCommand Initialize(
int baseIndex,
ref BiquadFilterParameter filter,
ref BiquadFilterParameter2 filter,
Memory<BiquadFilterState> biquadFilterStateMemory,
int inputBufferOffset,
int outputBufferOffset,
@@ -38,6 +43,8 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
Enabled = true;
NodeId = nodeId;
return this;
}
public void Process(CommandList context)

View File

@@ -12,25 +12,30 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
{
public bool Enabled { get; set; }
public int NodeId { get; }
public int NodeId { get; private set; }
public CommandType CommandType => CommandType.CaptureBuffer;
public uint EstimatedProcessingTime { get; set; }
public uint InputBufferIndex { get; }
public uint InputBufferIndex { get; private set; }
public ulong CpuBufferInfoAddress { get; }
public ulong DspBufferInfoAddress { get; }
public ulong CpuBufferInfoAddress { get; private set; }
public ulong DspBufferInfoAddress { get; private set; }
public CpuAddress OutputBuffer { get; }
public uint CountMax { get; }
public uint UpdateCount { get; }
public uint WriteOffset { get; }
public CpuAddress OutputBuffer { get; private set; }
public uint CountMax { get; private set; }
public uint UpdateCount { get; private set; }
public uint WriteOffset { get; private set; }
public bool IsEffectEnabled { get; }
public bool IsEffectEnabled { get; private set; }
public CaptureBufferCommand(uint bufferOffset, byte inputBufferOffset, ulong sendBufferInfo, bool isEnabled,
public CaptureBufferCommand()
{
}
public CaptureBufferCommand Initialize(uint bufferOffset, byte inputBufferOffset, ulong sendBufferInfo, bool isEnabled,
uint countMax, CpuAddress outputBuffer, uint updateCount, uint writeOffset, int nodeId)
{
Enabled = true;
@@ -43,6 +48,8 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
UpdateCount = updateCount;
WriteOffset = writeOffset;
IsEffectEnabled = isEnabled;
return this;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]

View File

@@ -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
@@ -8,30 +9,36 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
{
public bool Enabled { get; set; }
public int NodeId { get; }
public int NodeId { get; private set; }
public CommandType CommandType => CommandType.CircularBufferSink;
public uint EstimatedProcessingTime { get; set; }
public ushort[] Input { get; }
public uint InputCount { get; }
public uint InputCount { get; private set; }
public ulong CircularBuffer { get; }
public ulong CircularBufferSize { get; }
public ulong CurrentOffset { get; }
public ulong CircularBuffer { get; private set; }
public ulong CircularBufferSize { get; private set; }
public ulong CurrentOffset { get; private set; }
public CircularBufferSinkCommand(uint bufferOffset, ref CircularBufferParameter parameter, ref AddressInfo circularBufferAddressInfo, uint currentOffset, int nodeId)
public CircularBufferSinkCommand()
{
Input = new ushort[Constants.ChannelCountMax];
}
public CircularBufferSinkCommand Initialize(uint bufferOffset, ref CircularBufferParameter parameter, ref AddressInfo circularBufferAddressInfo, uint currentOffset, int nodeId)
{
Enabled = true;
NodeId = nodeId;
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);
@@ -39,6 +46,8 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
CurrentOffset = currentOffset;
Debug.Assert(CircularBuffer != 0);
return this;
}
public void Process(CommandList context)

View File

@@ -4,16 +4,23 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
{
public bool Enabled { get; set; }
public int NodeId { get; }
public int NodeId { get; private set; }
public CommandType CommandType => CommandType.ClearMixBuffer;
public uint EstimatedProcessingTime { get; set; }
public ClearMixBufferCommand(int nodeId)
public ClearMixBufferCommand()
{
}
public ClearMixBufferCommand Initialize(int nodeId)
{
Enabled = true;
NodeId = nodeId;
return this;
}
public void Process(CommandList context)

View File

@@ -20,6 +20,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
public Memory<float> Buffers { get; }
public uint BufferCount { get; }
private readonly static ObjectPool<List<ICommand>> CommandsListPool = new(() => new List<ICommand>(256));
public List<ICommand> Commands { get; }
public IVirtualMemoryManager MemoryManager { get; }
@@ -46,7 +47,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
SampleRate = sampleRate;
BufferCount = mixBufferCount + voiceChannelCountMax;
Buffers = mixBuffer;
Commands = [];
Commands = CommandsListPool.Allocate();
MemoryManager = memoryManager;
_buffersEntryCount = Buffers.Length;
@@ -129,7 +130,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
{
startTime = PerformanceCounter.ElapsedNanoseconds;
}
command.Process(this);
if (shouldMeter)
@@ -142,6 +143,8 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
}
}
}
CommandBuffer.ReleaseCommand(command);
}
EndTime = (ulong)PerformanceCounter.ElapsedNanoseconds;
@@ -149,6 +152,8 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
public void Dispose()
{
Commands.Clear();
CommandsListPool.Release(Commands);
GC.SuppressFinalize(this);
_buffersMemoryHandle.Dispose();
}

View File

@@ -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
}
}

View File

@@ -15,22 +15,28 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
public bool Enabled { get; set; }
public int NodeId { get; }
public int NodeId { get; private set; }
public CommandType CommandType => CommandType.Compressor;
public uint EstimatedProcessingTime { get; set; }
public CompressorParameter Parameter => _parameter;
public Memory<CompressorState> State { get; }
public Memory<EffectResultState> ResultState { get; }
public Memory<CompressorState> State { get; private set; }
public Memory<EffectResultState> ResultState { get; private set; }
public ushort[] OutputBufferIndices { get; }
public ushort[] InputBufferIndices { get; }
public bool IsEffectEnabled { get; }
public bool IsEffectEnabled { get; private set; }
private CompressorParameter _parameter;
public CompressorCommand(uint bufferOffset, CompressorParameter parameter, Memory<CompressorState> state, Memory<EffectResultState> resultState, bool isEnabled, int nodeId)
public CompressorCommand()
{
InputBufferIndices = new ushort[Constants.VoiceChannelCountMax];
OutputBufferIndices = new ushort[Constants.VoiceChannelCountMax];
}
public CompressorCommand Initialize(uint bufferOffset, CompressorParameter parameter, Memory<CompressorState> state, Memory<EffectResultState> resultState, bool isEnabled, int nodeId)
{
Enabled = true;
NodeId = nodeId;
@@ -39,15 +45,17 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
ResultState = resultState;
IsEffectEnabled = isEnabled;
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]);
}
return this;
}
public void Process(CommandList context)
@@ -171,10 +179,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));
}
}
}

View File

@@ -4,22 +4,29 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
{
public bool Enabled { get; set; }
public int NodeId { get; }
public int NodeId { get; private set; }
public CommandType CommandType => CommandType.CopyMixBuffer;
public uint EstimatedProcessingTime { get; set; }
public ushort InputBufferIndex { get; }
public ushort OutputBufferIndex { get; }
public ushort InputBufferIndex { get; private set; }
public ushort OutputBufferIndex { get; private set; }
public CopyMixBufferCommand(uint inputBufferIndex, uint outputBufferIndex, int nodeId)
public CopyMixBufferCommand()
{
}
public CopyMixBufferCommand Initialize(uint inputBufferIndex, uint outputBufferIndex, int nodeId)
{
Enabled = true;
NodeId = nodeId;
InputBufferIndex = (ushort)inputBufferIndex;
OutputBufferIndex = (ushort)outputBufferIndex;
return this;
}
public void Process(CommandList context)

View File

@@ -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
@@ -11,65 +11,72 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
{
public bool Enabled { get; set; }
public int NodeId { get; }
public int NodeId { get; private set; }
public CommandType CommandType { get; }
public CommandType CommandType { get; private set; }
public uint EstimatedProcessingTime { get; set; }
public ushort OutputBufferIndex { get; }
public uint SampleRate { get; }
public ushort OutputBufferIndex { get; private set; }
public uint SampleRate { get; private set; }
public float Pitch { get; }
public float Pitch { get; private set; }
public WaveBuffer[] WaveBuffers { get; }
public Memory<VoiceUpdateState> State { get; }
public Memory<VoiceState> State { get; private set; }
public ulong ExtraParameter { get; }
public ulong ExtraParameterSize { get; }
public ulong ExtraParameter { get; private set; }
public ulong ExtraParameterSize { get; private set; }
public uint ChannelIndex { get; }
public uint ChannelIndex { get; private set; }
public uint ChannelCount { get; }
public uint ChannelCount { get; private set; }
public DecodingBehaviour DecodingBehaviour { get; }
public DecodingBehaviour DecodingBehaviour { get; private set; }
public SampleFormat SampleFormat { get; }
public SampleFormat SampleFormat { get; private set; }
public SampleRateConversionQuality SrcQuality { get; }
public SampleRateConversionQuality SrcQuality { get; private set; }
public DataSourceVersion2Command(ref VoiceState serverState, Memory<VoiceUpdateState> state, ushort outputBufferIndex, ushort channelIndex, int nodeId)
public DataSourceVersion2Command()
{
WaveBuffers = new WaveBuffer[Constants.VoiceWaveBufferCount];
}
public DataSourceVersion2Command Initialize(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;
WaveBuffers = new WaveBuffer[Constants.VoiceWaveBufferCount];
SampleRate = serverInfo.SampleRate;
Pitch = serverInfo.Pitch;
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(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;
return this;
}
private static CommandType GetCommandTypeBySampleFormat(SampleFormat sampleFormat)

View File

@@ -13,24 +13,30 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
{
public bool Enabled { get; set; }
public int NodeId { get; }
public int NodeId { get; private set; }
public CommandType CommandType => CommandType.Delay;
public uint EstimatedProcessingTime { get; set; }
public DelayParameter Parameter => _parameter;
public Memory<DelayState> State { get; }
public ulong WorkBuffer { get; }
public Memory<DelayState> State { get; private set; }
public ulong WorkBuffer { get; private set; }
public ushort[] OutputBufferIndices { get; }
public ushort[] InputBufferIndices { get; }
public bool IsEffectEnabled { get; }
public bool IsEffectEnabled { get; private set; }
private DelayParameter _parameter;
private const int FixedPointPrecision = 14;
public DelayCommand(uint bufferOffset, DelayParameter parameter, Memory<DelayState> state, bool isEnabled, ulong workBuffer, int nodeId, bool newEffectChannelMappingSupported)
public DelayCommand()
{
InputBufferIndices = new ushort[Constants.VoiceChannelCountMax];
OutputBufferIndices = new ushort[Constants.VoiceChannelCountMax];
}
public DelayCommand Initialize(uint bufferOffset, DelayParameter parameter, Memory<DelayState> state, bool isEnabled, ulong workBuffer, int nodeId, bool newEffectChannelMappingSupported)
{
Enabled = true;
NodeId = nodeId;
@@ -39,18 +45,20 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
WorkBuffer = workBuffer;
IsEffectEnabled = isEnabled;
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);
DataSourceHelper.RemapLegacyChannelEffectMappingToChannelResourceMapping(newEffectChannelMappingSupported, OutputBufferIndices, Parameter.ChannelCount);
return this;
}
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]

View File

@@ -7,21 +7,26 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
{
public bool Enabled { get; set; }
public int NodeId { get; }
public int NodeId { get; private set; }
public CommandType CommandType => CommandType.DepopForMixBuffers;
public uint EstimatedProcessingTime { get; set; }
public uint MixBufferOffset { get; }
public uint MixBufferOffset { get; private set; }
public uint MixBufferCount { get; }
public uint MixBufferCount { get; private set; }
public float Decay { get; }
public float Decay { get; private set; }
public Memory<float> DepopBuffer { get; }
public Memory<float> DepopBuffer { get; private set; }
public DepopForMixBuffersCommand(Memory<float> depopBuffer, uint bufferOffset, uint mixBufferCount, int nodeId, uint sampleRate)
public DepopForMixBuffersCommand()
{
}
public DepopForMixBuffersCommand Initialize(Memory<float> depopBuffer, uint bufferOffset, uint mixBufferCount, int nodeId, uint sampleRate)
{
Enabled = true;
NodeId = nodeId;
@@ -37,6 +42,8 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
{
Decay = 0.943695f;
}
return this;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]

View File

@@ -7,27 +7,30 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
{
public bool Enabled { get; set; }
public int NodeId { get; }
public int NodeId { get; private set; }
public CommandType CommandType => CommandType.DepopPrepare;
public uint EstimatedProcessingTime { get; set; }
public uint MixBufferCount { get; }
public uint MixBufferCount { get; private set; }
public ushort[] OutputBufferIndices { get; }
public Memory<VoiceUpdateState> State { get; }
public Memory<float> DepopBuffer { get; }
public Memory<VoiceState> State { get; private set; }
public Memory<float> DepopBuffer { get; private set; }
public DepopPrepareCommand(Memory<VoiceUpdateState> state, Memory<float> depopBuffer, uint mixBufferCount, uint bufferOffset, int nodeId, bool enabled)
public DepopPrepareCommand()
{
OutputBufferIndices = new ushort[Constants.MixBufferCountMax];
}
public DepopPrepareCommand Initialize(Memory<VoiceState> state, Memory<float> depopBuffer, uint mixBufferCount, uint bufferOffset, int nodeId, bool enabled)
{
Enabled = enabled;
NodeId = nodeId;
MixBufferCount = mixBufferCount;
OutputBufferIndices = new ushort[Constants.MixBufferCountMax];
for (int i = 0; i < Constants.MixBufferCountMax; i++)
{
OutputBufferIndices[i] = (ushort)(bufferOffset + i);
@@ -35,21 +38,24 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
State = state;
DepopBuffer = depopBuffer;
return this;
}
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;
}
}
}

View File

@@ -1,6 +1,7 @@
using Ryujinx.Audio.Integration;
using Ryujinx.Audio.Renderer.Server.Sink;
using System;
using System.Buffers;
using System.Runtime.CompilerServices;
using System.Text;
@@ -10,44 +11,55 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
{
public bool Enabled { get; set; }
public int NodeId { get; }
public int NodeId { get; private set; }
public CommandType CommandType => CommandType.DeviceSink;
public uint EstimatedProcessingTime { get; set; }
public string DeviceName { get; }
public string DeviceName { get; private set; }
public int SessionId { get; }
public int SessionId { get; private set; }
public uint InputCount { get; }
public ushort[] InputBufferIndices { get; }
public uint InputCount { get; private set; }
public ushort[] InputBufferIndices { get; private set; }
public Memory<float> Buffers { get; }
public Memory<float> Buffers { get; private set; }
public DeviceSinkCommand(uint bufferOffset, DeviceSink sink, int sessionId, Memory<float> buffers, int nodeId)
public DeviceSinkCommand()
{
}
public DeviceSinkCommand Initialize(uint bufferOffset, DeviceSink sink, int sessionId, Memory<float> buffers, int nodeId)
{
Enabled = true;
NodeId = nodeId;
DeviceName = Encoding.ASCII.GetString(sink.Parameter.DeviceName).TrimEnd('\0');
// Unused and wasting time and memory, re-add if needed
// DeviceName = Encoding.ASCII.GetString(sink.Parameter.DeviceName).TrimEnd('\0');
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
{
Buffers = buffers;
}
return this;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
@@ -79,7 +91,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
inputCount = bufferCount;
}
short[] outputBuffer = new short[inputCount * SampleCount];
short[] outputBuffer = ArrayPool<short>.Shared.Rent((int)inputCount * SampleCount);
for (int i = 0; i < bufferCount; i++)
{
@@ -91,7 +103,9 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
}
}
device.AppendBuffer(outputBuffer, inputCount);
device.AppendBuffer(outputBuffer.AsSpan(..((int)inputCount * SampleCount)), inputCount);
ArrayPool<short>.Shared.Return(outputBuffer);
}
else
{

View File

@@ -7,7 +7,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
{
public bool Enabled { get; set; }
public int NodeId { get; }
public int NodeId { get; private set; }
public CommandType CommandType => CommandType.DownMixSurroundToStereo;
@@ -16,16 +16,19 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
public ushort[] InputBufferIndices { get; }
public ushort[] OutputBufferIndices { get; }
public float[] Coefficients { get; }
public float[] Coefficients { get; private set; }
public DownMixSurroundToStereoCommand(uint bufferOffset, Span<byte> inputBufferOffset, Span<byte> outputBufferOffset, float[] downMixParameter, int nodeId)
public DownMixSurroundToStereoCommand()
{
InputBufferIndices = new ushort[Constants.VoiceChannelCountMax];
OutputBufferIndices = new ushort[Constants.VoiceChannelCountMax];
}
public DownMixSurroundToStereoCommand Initialize(uint bufferOffset, Span<byte> inputBufferOffset, Span<byte> outputBufferOffset, float[] downMixParameter, int nodeId)
{
Enabled = true;
NodeId = nodeId;
InputBufferIndices = new ushort[Constants.VoiceChannelCountMax];
OutputBufferIndices = new ushort[Constants.VoiceChannelCountMax];
for (int i = 0; i < Constants.VoiceChannelCountMax; i++)
{
InputBufferIndices[i] = (ushort)(bufferOffset + inputBufferOffset[i]);
@@ -33,6 +36,8 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
}
Coefficients = downMixParameter;
return this;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]

View File

@@ -0,0 +1,73 @@
using Ryujinx.Audio.Renderer.Server.Splitter;
using System.Runtime.CompilerServices;
namespace Ryujinx.Audio.Renderer.Dsp.Command
{
public class FillBufferCommand : ICommand
{
public bool Enabled { get; set; }
public int NodeId { get; private set; }
public CommandType CommandType => CommandType.FillBuffer;
public uint EstimatedProcessingTime { get; set; }
public SplitterDestinationVersion1 Destination1 { get; private set; }
public SplitterDestinationVersion2 Destination2 { get; private set; }
public bool IsV2 { get; private set; }
public int Length { get; private set; }
public float Value { get; private set; }
public FillBufferCommand()
{
}
public FillBufferCommand Initialize(SplitterDestination destination, int length, float value, int nodeId)
{
Enabled = true;
NodeId = nodeId;
if (Unsafe.IsNullRef(ref destination.GetV2RefOrNull()))
{
Destination1 = destination.GetV1RefOrNull();
IsV2 = false;
}
else
{
Destination2 = destination.GetV2RefOrNull();
IsV2 = true;
}
Length = length;
Value = value;
return this;
}
[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();
}
}
}

View File

@@ -10,22 +10,28 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
{
public bool Enabled { get; set; }
public int NodeId { get; }
public int NodeId { get; private set; }
public CommandType CommandType => CommandType.LimiterVersion1;
public uint EstimatedProcessingTime { get; set; }
public LimiterParameter Parameter => _parameter;
public Memory<LimiterState> State { get; }
public ulong WorkBuffer { get; }
public Memory<LimiterState> State { get; private set; }
public ulong WorkBuffer { get; private set; }
public ushort[] OutputBufferIndices { get; }
public ushort[] InputBufferIndices { get; }
public bool IsEffectEnabled { get; }
public bool IsEffectEnabled { get; private set; }
private LimiterParameter _parameter;
public LimiterCommandVersion1(uint bufferOffset, LimiterParameter parameter, Memory<LimiterState> state, bool isEnabled, ulong workBuffer, int nodeId)
public LimiterCommandVersion1()
{
InputBufferIndices = new ushort[Constants.VoiceChannelCountMax];
OutputBufferIndices = new ushort[Constants.VoiceChannelCountMax];
}
public LimiterCommandVersion1 Initialize(uint bufferOffset, LimiterParameter parameter, Memory<LimiterState> state, bool isEnabled, ulong workBuffer, int nodeId)
{
Enabled = true;
NodeId = nodeId;
@@ -35,14 +41,16 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
IsEffectEnabled = isEnabled;
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]);
}
return this;
}
public void Process(CommandList context)

View File

@@ -12,23 +12,29 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
{
public bool Enabled { get; set; }
public int NodeId { get; }
public int NodeId { get; private set; }
public CommandType CommandType => CommandType.LimiterVersion2;
public uint EstimatedProcessingTime { get; set; }
public LimiterParameter Parameter => _parameter;
public Memory<LimiterState> State { get; }
public Memory<EffectResultState> ResultState { get; }
public ulong WorkBuffer { get; }
public Memory<LimiterState> State { get; private set; }
public Memory<EffectResultState> ResultState { get; private set; }
public ulong WorkBuffer { get; private set; }
public ushort[] OutputBufferIndices { get; }
public ushort[] InputBufferIndices { get; }
public bool IsEffectEnabled { get; }
public bool IsEffectEnabled { get; private set; }
private LimiterParameter _parameter;
public LimiterCommandVersion2(
public LimiterCommandVersion2()
{
InputBufferIndices = new ushort[Constants.VoiceChannelCountMax];
OutputBufferIndices = new ushort[Constants.VoiceChannelCountMax];
}
public LimiterCommandVersion2 Initialize(
uint bufferOffset,
LimiterParameter parameter,
Memory<LimiterState> state,
@@ -45,15 +51,17 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
WorkBuffer = workBuffer;
IsEffectEnabled = isEnabled;
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]);
}
return this;
}
public void Process(CommandList context)
@@ -150,8 +158,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);
}
}
}

View File

@@ -11,18 +11,23 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
{
public bool Enabled { get; set; }
public int NodeId { get; }
public int NodeId { get; private set; }
public CommandType CommandType => CommandType.Mix;
public uint EstimatedProcessingTime { get; set; }
public ushort InputBufferIndex { get; }
public ushort OutputBufferIndex { get; }
public ushort InputBufferIndex { get; private set; }
public ushort OutputBufferIndex { get; private set; }
public float Volume { get; }
public float Volume { get; private set; }
public MixCommand(uint inputBufferIndex, uint outputBufferIndex, int nodeId, float volume)
public MixCommand()
{
}
public MixCommand Initialize(uint inputBufferIndex, uint outputBufferIndex, int nodeId, float volume)
{
Enabled = true;
NodeId = nodeId;
@@ -31,6 +36,8 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
OutputBufferIndex = (ushort)outputBufferIndex;
Volume = volume;
return this;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]

View File

@@ -8,23 +8,28 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
{
public bool Enabled { get; set; }
public int NodeId { get; }
public int NodeId { get; private set; }
public CommandType CommandType => CommandType.MixRamp;
public uint EstimatedProcessingTime { get; set; }
public ushort InputBufferIndex { get; }
public ushort OutputBufferIndex { get; }
public ushort InputBufferIndex { get; private set; }
public ushort OutputBufferIndex { get; private set; }
public float Volume0 { get; }
public float Volume1 { get; }
public float Volume0 { get; private set; }
public float Volume1 { get; private set; }
public Memory<VoiceUpdateState> State { get; }
public Memory<VoiceState> State { get; private set; }
public int LastSampleIndex { get; }
public int LastSampleIndex { get; private set; }
public MixRampCommand(float volume0, float volume1, uint inputBufferIndex, uint outputBufferIndex, int lastSampleIndex, Memory<VoiceUpdateState> state, int nodeId)
public MixRampCommand()
{
}
public MixRampCommand Initialize(float volume0, float volume1, uint inputBufferIndex, uint outputBufferIndex, int lastSampleIndex, Memory<VoiceState> state, int nodeId)
{
Enabled = true;
NodeId = nodeId;
@@ -37,6 +42,8 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
State = state;
LastSampleIndex = lastSampleIndex;
return this;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]

View File

@@ -8,29 +8,34 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
{
public bool Enabled { get; set; }
public int NodeId { get; }
public int NodeId { get; private set; }
public CommandType CommandType => CommandType.MixRampGrouped;
public uint EstimatedProcessingTime { get; set; }
public uint MixBufferCount { get; }
public uint MixBufferCount { get; private set; }
public ushort[] InputBufferIndices { get; }
public ushort[] OutputBufferIndices { get; }
public ushort[] InputBufferIndices { get; private set; }
public ushort[] OutputBufferIndices { get; private set; }
public float[] Volume0 { get; }
public float[] Volume1 { get; }
public float[] Volume0 { get; private set; }
public float[] Volume1 { get; private set; }
public Memory<VoiceUpdateState> State { get; }
public Memory<VoiceState> State { get; private set; }
public MixRampGroupedCommand(
public MixRampGroupedCommand()
{
}
public MixRampGroupedCommand Initialize(
uint mixBufferCount,
uint inputBufferIndex,
uint outputBufferIndex,
ReadOnlySpan<float> volume0,
ReadOnlySpan<float> volume1,
Memory<VoiceUpdateState> state,
Memory<VoiceState> state,
int nodeId)
{
Enabled = true;
@@ -52,6 +57,8 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
}
State = state;
return this;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
@@ -79,6 +86,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 +98,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;
}
}
}

View File

@@ -9,44 +9,49 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
{
public bool Enabled { get; set; }
public int NodeId { get; }
public int NodeId { get; private set; }
public CommandType CommandType => CommandType.MultiTapBiquadFilterAndMix;
public uint EstimatedProcessingTime { get; set; }
public ushort InputBufferIndex { get; }
public ushort OutputBufferIndex { get; }
public ushort InputBufferIndex { get; private set; }
public ushort OutputBufferIndex { get; private set; }
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<BiquadFilterState> BiquadFilterState0 { get; private set; }
public Memory<BiquadFilterState> BiquadFilterState1 { get; private set; }
public Memory<BiquadFilterState> PreviousBiquadFilterState0 { get; private set; }
public Memory<BiquadFilterState> PreviousBiquadFilterState1 { get; private set; }
public Memory<VoiceUpdateState> State { get; }
public Memory<VoiceState> State { get; private set; }
public int LastSampleIndex { get; }
public int LastSampleIndex { get; private set; }
public float Volume0 { get; }
public float Volume1 { get; }
public float Volume0 { get; private set; }
public float Volume1 { get; private set; }
public bool NeedInitialization0 { get; }
public bool NeedInitialization1 { get; }
public bool HasVolumeRamp { get; }
public bool IsFirstMixBuffer { get; }
public bool NeedInitialization0 { get; private set; }
public bool NeedInitialization1 { get; private set; }
public bool HasVolumeRamp { get; private set; }
public bool IsFirstMixBuffer { get; private set; }
public MultiTapBiquadFilterAndMixCommand(
public MultiTapBiquadFilterAndMixCommand()
{
}
public MultiTapBiquadFilterAndMixCommand Initialize(
float volume0,
float volume1,
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,
@@ -80,6 +85,8 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
NeedInitialization1 = needInitialization1;
HasVolumeRamp = hasVolumeRamp;
IsFirstMixBuffer = isFirstMixBuffer;
return this;
}
private void UpdateState(Memory<BiquadFilterState> state, Memory<BiquadFilterState> previousState, bool needInitialization)

View File

@@ -8,40 +8,47 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
{
public bool Enabled { get; set; }
public int NodeId { get; }
public int NodeId { get; private set; }
public CommandType CommandType => CommandType.MultiTapBiquadFilter;
public uint EstimatedProcessingTime { get; set; }
private readonly BiquadFilterParameter[] _parameters;
private readonly Memory<BiquadFilterState> _biquadFilterStates;
private readonly int _inputBufferIndex;
private readonly int _outputBufferIndex;
private readonly bool[] _isInitialized;
public BiquadFilterParameter2[] Parameters { get; private set; }
public Memory<BiquadFilterState> BiquadFilterStates { get; private set; }
public int InputBufferIndex { get; private set; }
public int OutputBufferIndex { get; private set; }
public bool[] IsInitialized { get; private set; }
public MultiTapBiquadFilterCommand(int baseIndex, ReadOnlySpan<BiquadFilterParameter> filters, Memory<BiquadFilterState> biquadFilterStateMemory, int inputBufferOffset, int outputBufferOffset, ReadOnlySpan<bool> isInitialized, int nodeId)
public MultiTapBiquadFilterCommand()
{
_parameters = filters.ToArray();
_biquadFilterStates = biquadFilterStateMemory;
_inputBufferIndex = baseIndex + inputBufferOffset;
_outputBufferIndex = baseIndex + outputBufferOffset;
_isInitialized = isInitialized.ToArray();
}
public MultiTapBiquadFilterCommand Initialize(int baseIndex, ReadOnlySpan<BiquadFilterParameter2> filters, Memory<BiquadFilterState> biquadFilterStateMemory, int inputBufferOffset, int outputBufferOffset, ReadOnlySpan<bool> isInitialized, int nodeId)
{
Parameters = filters.ToArray();
BiquadFilterStates = biquadFilterStateMemory;
InputBufferIndex = baseIndex + inputBufferOffset;
OutputBufferIndex = baseIndex + outputBufferOffset;
IsInitialized = isInitialized.ToArray();
Enabled = true;
NodeId = nodeId;
return this;
}
public void Process(CommandList context)
{
Span<BiquadFilterState> states = _biquadFilterStates.Span;
Span<BiquadFilterState> states = BiquadFilterStates.Span;
ReadOnlySpan<float> inputBuffer = context.GetBuffer(_inputBufferIndex);
Span<float> outputBuffer = context.GetBuffer(_outputBufferIndex);
ReadOnlySpan<float> inputBuffer = context.GetBuffer(InputBufferIndex);
Span<float> outputBuffer = context.GetBuffer(OutputBufferIndex);
for (int i = 0; i < _parameters.Length; i++)
for (int i = 0; i < Parameters.Length; i++)
{
if (!_isInitialized[i])
if (!IsInitialized[i])
{
states[i] = new BiquadFilterState();
}
@@ -49,13 +56,13 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
// NOTE: Nintendo only implement single and double biquad filters but no generic path when the command definition suggests it could be done.
// As such we currently only implement a generic path for simplicity for double biquad.
if (_parameters.Length == 1)
if (Parameters.Length == 1)
{
BiquadFilterHelper.ProcessBiquadFilter(ref _parameters[0], ref states[0], outputBuffer, inputBuffer, context.SampleCount);
BiquadFilterHelper.ProcessBiquadFilter(ref Parameters[0], ref states[0], outputBuffer, inputBuffer, context.SampleCount);
}
else
{
BiquadFilterHelper.ProcessBiquadFilter(_parameters, states, outputBuffer, inputBuffer, context.SampleCount);
BiquadFilterHelper.ProcessBiquadFilter(Parameters, states, outputBuffer, inputBuffer, context.SampleCount);
}
}
}

View File

@@ -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
@@ -11,47 +11,54 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
{
public bool Enabled { get; set; }
public int NodeId { get; }
public int NodeId { get; private set; }
public CommandType CommandType => CommandType.PcmFloatDataSourceVersion1;
public uint EstimatedProcessingTime { get; set; }
public ushort OutputBufferIndex { get; }
public uint SampleRate { get; }
public uint ChannelIndex { get; }
public ushort OutputBufferIndex { get; private set; }
public uint SampleRate { get; private set; }
public uint ChannelIndex { get; private set; }
public uint ChannelCount { get; }
public uint ChannelCount { get; private set; }
public float Pitch { get; }
public float Pitch { get; private set; }
public WaveBuffer[] WaveBuffers { get; }
public Memory<VoiceUpdateState> State { get; }
public DecodingBehaviour DecodingBehaviour { get; }
public Memory<VoiceState> State { get; private set; }
public DecodingBehaviour DecodingBehaviour { get; private set; }
public PcmFloatDataSourceCommandVersion1(ref VoiceState serverState, Memory<VoiceUpdateState> state, ushort outputBufferIndex, ushort channelIndex, int nodeId)
public PcmFloatDataSourceCommandVersion1()
{
WaveBuffers = new WaveBuffer[Constants.VoiceWaveBufferCount];
}
public PcmFloatDataSourceCommandVersion1 Initialize(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;
WaveBuffers = new WaveBuffer[Constants.VoiceWaveBufferCount];
ChannelCount = serverInfo.ChannelsCount;
Pitch = serverInfo.Pitch;
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;
return this;
}
public void Process(CommandList context)

View File

@@ -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
@@ -11,47 +11,54 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
{
public bool Enabled { get; set; }
public int NodeId { get; }
public int NodeId { get; private set; }
public CommandType CommandType => CommandType.PcmInt16DataSourceVersion1;
public uint EstimatedProcessingTime { get; set; }
public ushort OutputBufferIndex { get; }
public uint SampleRate { get; }
public uint ChannelIndex { get; }
public ushort OutputBufferIndex { get; private set; }
public uint SampleRate { get; private set; }
public uint ChannelIndex { get; private set; }
public uint ChannelCount { get; }
public uint ChannelCount { get; private set; }
public float Pitch { get; }
public float Pitch { get; private set; }
public WaveBuffer[] WaveBuffers { get; }
public Memory<VoiceUpdateState> State { get; }
public DecodingBehaviour DecodingBehaviour { get; }
public Memory<VoiceState> State { get; private set; }
public DecodingBehaviour DecodingBehaviour { get; private set; }
public PcmInt16DataSourceCommandVersion1(ref VoiceState serverState, Memory<VoiceUpdateState> state, ushort outputBufferIndex, ushort channelIndex, int nodeId)
public PcmInt16DataSourceCommandVersion1()
{
WaveBuffers = new WaveBuffer[Constants.VoiceWaveBufferCount];
}
public PcmInt16DataSourceCommandVersion1 Initialize(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;
WaveBuffers = new WaveBuffer[Constants.VoiceWaveBufferCount];
ChannelCount = serverInfo.ChannelsCount;
Pitch = serverInfo.Pitch;
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;
return this;
}
public void Process(CommandList context)

View File

@@ -13,22 +13,34 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
public bool Enabled { get; set; }
public int NodeId { get; }
public int NodeId { get; private set; }
public CommandType CommandType => CommandType.Performance;
public uint EstimatedProcessingTime { get; set; }
public PerformanceEntryAddresses PerformanceEntryAddresses { get; }
public PerformanceEntryAddresses PerformanceEntryAddresses { get; private set; }
public Type PerformanceType { get; set; }
public PerformanceCommand(ref PerformanceEntryAddresses performanceEntryAddresses, Type performanceType, int nodeId)
public PerformanceCommand()
{
}
public PerformanceCommand Initialize(ref PerformanceEntryAddresses performanceEntryAddresses, Type performanceType, int nodeId)
{
if (PerformanceEntryAddresses is not null)
{
PerformanceEntryAddresses.PerformanceEntryAddressesPool.Release(PerformanceEntryAddresses);
}
Enabled = true;
PerformanceEntryAddresses = performanceEntryAddresses;
PerformanceType = performanceType;
NodeId = nodeId;
return this;
}
public void Process(CommandList context)

View File

@@ -35,26 +35,32 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
public bool Enabled { get; set; }
public int NodeId { get; }
public int NodeId { get; private set; }
public CommandType CommandType => CommandType.Reverb3d;
public uint EstimatedProcessingTime { get; set; }
public ushort InputBufferIndex { get; }
public ushort OutputBufferIndex { get; }
public ushort InputBufferIndex { get; private set; }
public ushort OutputBufferIndex { get; private set; }
public Reverb3dParameter Parameter => _parameter;
public Memory<Reverb3dState> State { get; }
public ulong WorkBuffer { get; }
public Memory<Reverb3dState> State { get; private set; }
public ulong WorkBuffer { get; private set; }
public ushort[] OutputBufferIndices { get; }
public ushort[] InputBufferIndices { get; }
public bool IsEffectEnabled { get; }
public bool IsEffectEnabled { get; private set; }
private Reverb3dParameter _parameter;
public Reverb3dCommand(uint bufferOffset, Reverb3dParameter parameter, Memory<Reverb3dState> state, bool isEnabled, ulong workBuffer, int nodeId, bool newEffectChannelMappingSupported)
public Reverb3dCommand()
{
InputBufferIndices = new ushort[Constants.VoiceChannelCountMax];
OutputBufferIndices = new ushort[Constants.VoiceChannelCountMax];
}
public Reverb3dCommand Initialize(uint bufferOffset, Reverb3dParameter parameter, Memory<Reverb3dState> state, bool isEnabled, ulong workBuffer, int nodeId, bool newEffectChannelMappingSupported)
{
Enabled = true;
IsEffectEnabled = isEnabled;
@@ -62,20 +68,22 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
_parameter = parameter;
State = state;
WorkBuffer = workBuffer;
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
// TODO: Update reverb 3d processing and remove this to use RemapLegacyChannelEffectMappingToChannelResourceMapping.
DataSourceHelper.RemapChannelResourceMappingToLegacy(newEffectChannelMappingSupported, InputBufferIndices, Parameter.ChannelCount);
DataSourceHelper.RemapChannelResourceMappingToLegacy(newEffectChannelMappingSupported, OutputBufferIndices, Parameter.ChannelCount);
return this;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]

View File

@@ -33,26 +33,32 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
public bool Enabled { get; set; }
public int NodeId { get; }
public int NodeId { get; private set; }
public CommandType CommandType => CommandType.Reverb;
public uint EstimatedProcessingTime { get; set; }
public ReverbParameter Parameter => _parameter;
public Memory<ReverbState> State { get; }
public ulong WorkBuffer { get; }
public Memory<ReverbState> State { get; private set; }
public ulong WorkBuffer { get; private set; }
public ushort[] OutputBufferIndices { get; }
public ushort[] InputBufferIndices { get; }
public bool IsLongSizePreDelaySupported { get; }
public bool IsLongSizePreDelaySupported { get; private set; }
public bool IsEffectEnabled { get; }
public bool IsEffectEnabled { get; private set; }
private ReverbParameter _parameter;
private const int FixedPointPrecision = 14;
public ReverbCommand(uint bufferOffset, ReverbParameter parameter, Memory<ReverbState> state, bool isEnabled, ulong workBuffer, int nodeId, bool isLongSizePreDelaySupported, bool newEffectChannelMappingSupported)
public ReverbCommand()
{
InputBufferIndices = new ushort[Constants.VoiceChannelCountMax];
OutputBufferIndices = new ushort[Constants.VoiceChannelCountMax];
}
public ReverbCommand Initialize(uint bufferOffset, ReverbParameter parameter, Memory<ReverbState> state, bool isEnabled, ulong workBuffer, int nodeId, bool isLongSizePreDelaySupported, bool newEffectChannelMappingSupported)
{
Enabled = true;
IsEffectEnabled = isEnabled;
@@ -60,14 +66,14 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
_parameter = parameter;
State = state;
WorkBuffer = workBuffer;
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;
@@ -76,6 +82,8 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
// TODO: Update reverb processing and remove this to use RemapLegacyChannelEffectMappingToChannelResourceMapping.
DataSourceHelper.RemapChannelResourceMappingToLegacy(newEffectChannelMappingSupported, InputBufferIndices, Parameter.ChannelCount);
DataSourceHelper.RemapChannelResourceMappingToLegacy(newEffectChannelMappingSupported, OutputBufferIndices, Parameter.ChannelCount);
return this;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]

View File

@@ -7,22 +7,27 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
{
public bool Enabled { get; set; }
public int NodeId { get; }
public int NodeId { get; private set; }
public CommandType CommandType => CommandType.Upsample;
public uint EstimatedProcessingTime { get; set; }
public uint BufferCount { get; }
public uint InputBufferIndex { get; }
public uint InputSampleCount { get; }
public uint InputSampleRate { get; }
public uint BufferCount { get; private set; }
public uint InputBufferIndex { get; private set; }
public uint InputSampleCount { get; private set; }
public uint InputSampleRate { get; private set; }
public UpsamplerState UpsamplerInfo { get; }
public UpsamplerInfo UpsamplerInfo { get; private set; }
public Memory<float> OutBuffer { get; }
public Memory<float> OutBuffer { get; private set; }
public UpsampleCommand(uint bufferOffset, UpsamplerState info, uint inputCount, Span<byte> inputBufferOffset, uint bufferCount, uint sampleCount, uint sampleRate, int nodeId)
public UpsampleCommand()
{
}
public UpsampleCommand Initialize(uint bufferOffset, UpsamplerInfo info, uint inputCount, Span<byte> inputBufferOffset, uint bufferCount, uint sampleCount, uint sampleRate, int nodeId)
{
Enabled = true;
NodeId = nodeId;
@@ -47,6 +52,8 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
}
UpsamplerInfo = info;
return this;
}
private Span<float> GetBuffer(int index, int sampleCount)

View File

@@ -11,18 +11,23 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
{
public bool Enabled { get; set; }
public int NodeId { get; }
public int NodeId { get; private set; }
public CommandType CommandType => CommandType.Volume;
public uint EstimatedProcessingTime { get; set; }
public ushort InputBufferIndex { get; }
public ushort OutputBufferIndex { get; }
public ushort InputBufferIndex { get; private set; }
public ushort OutputBufferIndex { get; private set; }
public float Volume { get; }
public float Volume { get; private set; }
public VolumeCommand(float volume, uint bufferIndex, int nodeId)
public VolumeCommand()
{
}
public VolumeCommand Initialize(float volume, uint bufferIndex, int nodeId)
{
Enabled = true;
NodeId = nodeId;
@@ -31,6 +36,8 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
OutputBufferIndex = (ushort)bufferIndex;
Volume = volume;
return this;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]

View File

@@ -7,19 +7,24 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
{
public bool Enabled { get; set; }
public int NodeId { get; }
public int NodeId { get; private set; }
public CommandType CommandType => CommandType.VolumeRamp;
public uint EstimatedProcessingTime { get; set; }
public ushort InputBufferIndex { get; }
public ushort OutputBufferIndex { get; }
public ushort InputBufferIndex { get; private set; }
public ushort OutputBufferIndex { get; private set; }
public float Volume0 { get; }
public float Volume1 { get; }
public float Volume0 { get; private set; }
public float Volume1 { get; private set; }
public VolumeRampCommand(float volume0, float volume1, uint bufferIndex, int nodeId)
public VolumeRampCommand()
{
}
public VolumeRampCommand Initialize(float volume0, float volume1, uint bufferIndex, int nodeId)
{
Enabled = true;
NodeId = nodeId;
@@ -29,6 +34,8 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
Volume0 = volume0;
Volume1 = volume1;
return this;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]

View File

@@ -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++)
{

View File

@@ -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
{

View File

@@ -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++;
}

View File

@@ -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;
}
}

View File

@@ -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.

View File

@@ -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;
}
}

View File

@@ -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"/>.

View File

@@ -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;
}
}

View File

@@ -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.

View File

@@ -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.

View File

@@ -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;

View File

@@ -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;
}
}
}

View File

@@ -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;

View File

@@ -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,
}
}
}

View File

@@ -0,0 +1,173 @@
using Ryujinx.Audio.Common;
using Ryujinx.Audio.Renderer.Common;
using Ryujinx.Common.Memory;
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];
}
}

View File

@@ -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>

View File

@@ -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()

View File

@@ -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>

View File

@@ -5,8 +5,10 @@ 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 Ryujinx.Common;
using System;
using CpuAddress = System.UInt64;
@@ -32,6 +34,162 @@ namespace Ryujinx.Audio.Renderer.Server
/// </summary>
public CommandList CommandList { get; }
private readonly static ObjectPool<PcmInt16DataSourceCommandVersion1> _pcmInt16DataSourceCommandVersion1Pool = new(() => new PcmInt16DataSourceCommandVersion1());
private readonly static ObjectPool<PcmFloatDataSourceCommandVersion1> _pcmFloatDataSourceCommandVersion1Pool = new(() => new PcmFloatDataSourceCommandVersion1());
private readonly static ObjectPool<AdpcmDataSourceCommandVersion1> _adpcmDataSourceCommandVersion1Pool = new(() => new AdpcmDataSourceCommandVersion1());
private readonly static ObjectPool<DataSourceVersion2Command> _dataSourceVersion2CommandPool = new(() => new DataSourceVersion2Command());
private readonly static ObjectPool<VolumeCommand> _volumeCommandPool = new(() => new VolumeCommand());
private readonly static ObjectPool<VolumeRampCommand> _volumeRampCommandPool = new(() => new VolumeRampCommand());
private readonly static ObjectPool<BiquadFilterCommand> _biquadFilterCommandPool = new(() => new BiquadFilterCommand());
private readonly static ObjectPool<MixCommand> _mixCommandPool = new(() => new MixCommand());
private readonly static ObjectPool<MixRampCommand> _mixRampCommandPool = new(() => new MixRampCommand());
private readonly static ObjectPool<MixRampGroupedCommand> _mixRampGroupedCommandPool = new(() => new MixRampGroupedCommand());
private readonly static ObjectPool<DepopPrepareCommand> _depopPrepareCommandPool = new(() => new DepopPrepareCommand());
private readonly static ObjectPool<DepopForMixBuffersCommand> _depopForMixBuffersCommandPool = new(() => new DepopForMixBuffersCommand());
private readonly static ObjectPool<DelayCommand> _delayCommandPool = new(() => new DelayCommand());
private readonly static ObjectPool<UpsampleCommand> _upsampleCommandPool = new(() => new UpsampleCommand());
private readonly static ObjectPool<DownMixSurroundToStereoCommand> _downMixSurroundToStereoCommandPool = new(() => new DownMixSurroundToStereoCommand());
private readonly static ObjectPool<AuxiliaryBufferCommand> _auxiliaryBufferCommandPool = new(() => new AuxiliaryBufferCommand());
private readonly static ObjectPool<DeviceSinkCommand> _deviceSinkCommandPool = new(() => new DeviceSinkCommand());
private readonly static ObjectPool<CircularBufferSinkCommand> _circularBufferSinkCommandPool = new(() => new CircularBufferSinkCommand());
private readonly static ObjectPool<ReverbCommand> _reverbCommandPool = new(() => new ReverbCommand());
private readonly static ObjectPool<Reverb3dCommand> _reverb3dCommandPool = new(() => new Reverb3dCommand());
private readonly static ObjectPool<PerformanceCommand> _performanceCommandPool = new(() => new PerformanceCommand());
private readonly static ObjectPool<ClearMixBufferCommand> _clearMixBufferCommandPool = new(() => new ClearMixBufferCommand());
private readonly static ObjectPool<CopyMixBufferCommand> _copyMixBufferCommandPool = new(() => new CopyMixBufferCommand());
private readonly static ObjectPool<LimiterCommandVersion1> _limiterCommandVersion1Pool = new(() => new LimiterCommandVersion1());
private readonly static ObjectPool<LimiterCommandVersion2> _limiterCommandVersion2Pool = new(() => new LimiterCommandVersion2());
private readonly static ObjectPool<MultiTapBiquadFilterCommand> _multiTapBiquadFilterCommandPool = new(() => new MultiTapBiquadFilterCommand());
private readonly static ObjectPool<CaptureBufferCommand> _captureBufferCommandPool = new(() => new CaptureBufferCommand());
private readonly static ObjectPool<CompressorCommand> _compressorCommandPool = new(() => new CompressorCommand());
private readonly static ObjectPool<BiquadFilterAndMixCommand> _biquadFilterAndMixCommandPool = new(() => new BiquadFilterAndMixCommand());
private readonly static ObjectPool<MultiTapBiquadFilterAndMixCommand> _multiTapBiquadFilterAndMixCommandPool = new(() => new MultiTapBiquadFilterAndMixCommand());
private readonly static ObjectPool<FillBufferCommand> _fillBufferCommandPool = new(() => new FillBufferCommand());
public static void ReleaseCommand(ICommand command)
{
switch (command.CommandType)
{
case CommandType.PcmInt16DataSourceVersion1:
_pcmInt16DataSourceCommandVersion1Pool.Release((PcmInt16DataSourceCommandVersion1)command);
break;
case CommandType.PcmInt16DataSourceVersion2:
_dataSourceVersion2CommandPool.Release((DataSourceVersion2Command)command);
break;
case CommandType.PcmFloatDataSourceVersion1:
_pcmFloatDataSourceCommandVersion1Pool.Release((PcmFloatDataSourceCommandVersion1)command);
break;
case CommandType.PcmFloatDataSourceVersion2:
_dataSourceVersion2CommandPool.Release((DataSourceVersion2Command)command);
break;
case CommandType.AdpcmDataSourceVersion1:
_adpcmDataSourceCommandVersion1Pool.Release((AdpcmDataSourceCommandVersion1)command);
break;
case CommandType.AdpcmDataSourceVersion2:
_dataSourceVersion2CommandPool.Release((DataSourceVersion2Command)command);
break;
case CommandType.Volume:
_volumeCommandPool.Release((VolumeCommand)command);
break;
case CommandType.VolumeRamp:
_volumeRampCommandPool.Release((VolumeRampCommand)command);
break;
case CommandType.BiquadFilter:
_biquadFilterCommandPool.Release((BiquadFilterCommand)command);
break;
case CommandType.BiquadFilterFloatCoeff:
throw new NotImplementedException();
case CommandType.Mix:
_mixCommandPool.Release((MixCommand)command);
break;
case CommandType.MixRamp:
_mixRampCommandPool.Release((MixRampCommand)command);
break;
case CommandType.MixRampGrouped:
_mixRampGroupedCommandPool.Release((MixRampGroupedCommand)command);
break;
case CommandType.DepopPrepare:
_depopPrepareCommandPool.Release((DepopPrepareCommand)command);
break;
case CommandType.DepopForMixBuffers:
_depopForMixBuffersCommandPool.Release((DepopForMixBuffersCommand)command);
break;
case CommandType.Delay:
_delayCommandPool.Release((DelayCommand)command);
break;
case CommandType.Upsample:
_upsampleCommandPool.Release((UpsampleCommand)command);
break;
case CommandType.DownMixSurroundToStereo:
_downMixSurroundToStereoCommandPool.Release((DownMixSurroundToStereoCommand)command);
break;
case CommandType.AuxiliaryBuffer:
_auxiliaryBufferCommandPool.Release((AuxiliaryBufferCommand)command);
break;
case CommandType.DeviceSink:
_deviceSinkCommandPool.Release((DeviceSinkCommand)command);
break;
case CommandType.CircularBufferSink:
_circularBufferSinkCommandPool.Release((CircularBufferSinkCommand)command);
break;
case CommandType.Reverb:
_reverbCommandPool.Release((ReverbCommand)command);
break;
case CommandType.Reverb3d:
_reverb3dCommandPool.Release((Reverb3dCommand)command);
break;
case CommandType.Performance:
_performanceCommandPool.Release((PerformanceCommand)command);
break;
case CommandType.ClearMixBuffer:
_clearMixBufferCommandPool.Release((ClearMixBufferCommand)command);
break;
case CommandType.CopyMixBuffer:
_copyMixBufferCommandPool.Release((CopyMixBufferCommand)command);
break;
case CommandType.LimiterVersion1:
_limiterCommandVersion1Pool.Release((LimiterCommandVersion1)command);
break;
case CommandType.LimiterVersion2:
_limiterCommandVersion2Pool.Release((LimiterCommandVersion2)command);
break;
case CommandType.MultiTapBiquadFilter:
_multiTapBiquadFilterCommandPool.Release((MultiTapBiquadFilterCommand)command);
break;
case CommandType.MultiTapBiquadFilterFloatCoeff:
throw new NotImplementedException();
case CommandType.CaptureBuffer:
_captureBufferCommandPool.Release((CaptureBufferCommand)command);
break;
case CommandType.Compressor:
_compressorCommandPool.Release((CompressorCommand)command);
break;
case CommandType.BiquadFilterAndMix:
_biquadFilterAndMixCommandPool.Release((BiquadFilterAndMixCommand)command);
break;
case CommandType.BiquadFilterAndMixFloatCoeff:
throw new NotImplementedException();
case CommandType.MultiTapBiquadFilterAndMix:
_multiTapBiquadFilterAndMixCommandPool.Release((MultiTapBiquadFilterAndMixCommand)command);
break;
case CommandType.MultiTapBiquadFilterAndMixFloatCoef:
throw new NotImplementedException();
case CommandType.AuxiliaryBufferGrouped:
throw new NotImplementedException();
case CommandType.FillMixBuffer:
throw new NotImplementedException();
case CommandType.BiquadFilterCrossFade:
throw new NotImplementedException();
case CommandType.MultiTapBiquadFilterCrossFade:
throw new NotImplementedException();
case CommandType.FillBuffer:
_fillBufferCommandPool.Release((FillBufferCommand)command);
break;
default:
throw new NotImplementedException();
}
}
/// <summary>
/// Create a new <see cref="CommandBuffer"/>.
/// </summary>
@@ -61,7 +219,7 @@ namespace Ryujinx.Audio.Renderer.Server
/// <param name="nodeId">The node id associated to this command.</param>
public void GenerateClearMixBuffer(int nodeId)
{
ClearMixBufferCommand command = new(nodeId);
ClearMixBufferCommand command = _clearMixBufferCommandPool.Allocate().Initialize(nodeId);
command.EstimatedProcessingTime = _commandProcessingTimeEstimator.Estimate(command);
@@ -77,9 +235,9 @@ 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);
DepopPrepareCommand command = _depopPrepareCommandPool.Allocate().Initialize(state, depopBuffer, bufferCount, bufferOffset, nodeId, wasPlaying);
command.EstimatedProcessingTime = _commandProcessingTimeEstimator.Estimate(command);
@@ -94,7 +252,7 @@ namespace Ryujinx.Audio.Renderer.Server
/// <param name="nodeId">The node id associated to this command.</param>
public void GeneratePerformance(ref PerformanceEntryAddresses performanceEntryAddresses, PerformanceCommand.Type type, int nodeId)
{
PerformanceCommand command = new(ref performanceEntryAddresses, type, nodeId);
PerformanceCommand command = _performanceCommandPool.Allocate().Initialize(ref performanceEntryAddresses, type, nodeId);
command.EstimatedProcessingTime = _commandProcessingTimeEstimator.Estimate(command);
@@ -110,7 +268,7 @@ namespace Ryujinx.Audio.Renderer.Server
/// <param name="nodeId">The node id associated to this command.</param>
public void GenerateVolumeRamp(float previousVolume, float volume, uint bufferIndex, int nodeId)
{
VolumeRampCommand command = new(previousVolume, volume, bufferIndex, nodeId);
VolumeRampCommand command = _volumeRampCommandPool.Allocate().Initialize(previousVolume, volume, bufferIndex, nodeId);
command.EstimatedProcessingTime = _commandProcessingTimeEstimator.Estimate(command);
@@ -120,14 +278,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 = _dataSourceVersion2CommandPool.Allocate().Initialize(ref voiceInfo, state, outputBufferIndex, channelIndex, nodeId);
command.EstimatedProcessingTime = _commandProcessingTimeEstimator.Estimate(command);
@@ -137,14 +295,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 = _pcmInt16DataSourceCommandVersion1Pool.Allocate().Initialize(ref voiceInfo, state, outputBufferIndex, channelIndex, nodeId);
command.EstimatedProcessingTime = _commandProcessingTimeEstimator.Estimate(command);
@@ -154,14 +312,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 = _pcmFloatDataSourceCommandVersion1Pool.Allocate().Initialize(ref voiceInfo, state, outputBufferIndex, channelIndex, nodeId);
command.EstimatedProcessingTime = _commandProcessingTimeEstimator.Estimate(command);
@@ -171,13 +329,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 = _adpcmDataSourceCommandVersion1Pool.Allocate().Initialize(ref voiceInfo, state, outputBufferIndex, nodeId);
command.EstimatedProcessingTime = _commandProcessingTimeEstimator.Estimate(command);
@@ -194,9 +352,9 @@ 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);
BiquadFilterCommand command = _biquadFilterCommandPool.Allocate().Initialize(baseIndex, ref filter, biquadFilterStateMemory, inputBufferOffset, outputBufferOffset, needInitialization, nodeId);
command.EstimatedProcessingTime = _commandProcessingTimeEstimator.Estimate(command);
@@ -213,9 +371,9 @@ 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);
MultiTapBiquadFilterCommand command = _multiTapBiquadFilterCommandPool.Allocate().Initialize(baseIndex, filters, biquadFilterStatesMemory, inputBufferOffset, outputBufferOffset, isInitialized, nodeId);
command.EstimatedProcessingTime = _commandProcessingTimeEstimator.Estimate(command);
@@ -230,11 +388,11 @@ 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);
MixRampGroupedCommand command = _mixRampGroupedCommandPool.Allocate().Initialize(mixBufferCount, inputBufferIndex, outputBufferIndex, previousVolume, volume, state, nodeId);
command.EstimatedProcessingTime = _commandProcessingTimeEstimator.Estimate(command);
@@ -248,12 +406,12 @@ 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);
MixRampCommand command = _mixRampCommandPool.Allocate().Initialize(previousVolume, volume, inputBufferIndex, outputBufferIndex, lastSampleIndex, state, nodeId);
command.EstimatedProcessingTime = _commandProcessingTimeEstimator.Estimate(command);
@@ -267,8 +425,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 +440,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,
@@ -291,7 +449,7 @@ namespace Ryujinx.Audio.Renderer.Server
bool isFirstMixBuffer,
int nodeId)
{
BiquadFilterAndMixCommand command = new(
BiquadFilterAndMixCommand command = _biquadFilterAndMixCommandPool.Allocate().Initialize(
previousVolume,
volume,
inputBufferIndex,
@@ -318,8 +476,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 +495,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,
@@ -350,7 +508,7 @@ namespace Ryujinx.Audio.Renderer.Server
bool isFirstMixBuffer,
int nodeId)
{
MultiTapBiquadFilterAndMixCommand command = new(
MultiTapBiquadFilterAndMixCommand command = _multiTapBiquadFilterAndMixCommandPool.Allocate().Initialize(
previousVolume,
volume,
inputBufferIndex,
@@ -384,7 +542,7 @@ namespace Ryujinx.Audio.Renderer.Server
/// <param name="sampleRate">The target sample rate in use.</param>
public void GenerateDepopForMixBuffers(Memory<float> depopBuffer, uint bufferOffset, uint bufferCount, int nodeId, uint sampleRate)
{
DepopForMixBuffersCommand command = new(depopBuffer, bufferOffset, bufferCount, nodeId, sampleRate);
DepopForMixBuffersCommand command = _depopForMixBuffersCommandPool.Allocate().Initialize(depopBuffer, bufferOffset, bufferCount, nodeId, sampleRate);
command.EstimatedProcessingTime = _commandProcessingTimeEstimator.Estimate(command);
@@ -399,7 +557,7 @@ namespace Ryujinx.Audio.Renderer.Server
/// <param name="nodeId">The node id associated to this command.</param>
public void GenerateCopyMixBuffer(uint inputBufferIndex, uint outputBufferIndex, int nodeId)
{
CopyMixBufferCommand command = new(inputBufferIndex, outputBufferIndex, nodeId);
CopyMixBufferCommand command = _copyMixBufferCommandPool.Allocate().Initialize(inputBufferIndex, outputBufferIndex, nodeId);
command.EstimatedProcessingTime = _commandProcessingTimeEstimator.Estimate(command);
@@ -415,7 +573,7 @@ namespace Ryujinx.Audio.Renderer.Server
/// <param name="volume">The mix volume.</param>
public void GenerateMix(uint inputBufferIndex, uint outputBufferIndex, int nodeId, float volume)
{
MixCommand command = new(inputBufferIndex, outputBufferIndex, nodeId, volume);
MixCommand command = _mixCommandPool.Allocate().Initialize(inputBufferIndex, outputBufferIndex, nodeId, volume);
command.EstimatedProcessingTime = _commandProcessingTimeEstimator.Estimate(command);
@@ -437,7 +595,7 @@ namespace Ryujinx.Audio.Renderer.Server
{
if (parameter.IsChannelCountValid())
{
ReverbCommand command = new(bufferOffset, parameter, state, isEnabled, workBuffer, nodeId, isLongSizePreDelaySupported, newEffectChannelMappingSupported);
ReverbCommand command = _reverbCommandPool.Allocate().Initialize(bufferOffset, parameter, state, isEnabled, workBuffer, nodeId, isLongSizePreDelaySupported, newEffectChannelMappingSupported);
command.EstimatedProcessingTime = _commandProcessingTimeEstimator.Estimate(command);
@@ -459,7 +617,7 @@ namespace Ryujinx.Audio.Renderer.Server
{
if (parameter.IsChannelCountValid())
{
Reverb3dCommand command = new(bufferOffset, parameter, state, isEnabled, workBuffer, nodeId, newEffectChannelMappingSupported);
Reverb3dCommand command = _reverb3dCommandPool.Allocate().Initialize(bufferOffset, parameter, state, isEnabled, workBuffer, nodeId, newEffectChannelMappingSupported);
command.EstimatedProcessingTime = _commandProcessingTimeEstimator.Estimate(command);
@@ -481,7 +639,7 @@ namespace Ryujinx.Audio.Renderer.Server
{
if (parameter.IsChannelCountValid())
{
DelayCommand command = new(bufferOffset, parameter, state, isEnabled, workBuffer, nodeId, newEffectChannelMappingSupported);
DelayCommand command = _delayCommandPool.Allocate().Initialize(bufferOffset, parameter, state, isEnabled, workBuffer, nodeId, newEffectChannelMappingSupported);
command.EstimatedProcessingTime = _commandProcessingTimeEstimator.Estimate(command);
@@ -502,7 +660,7 @@ namespace Ryujinx.Audio.Renderer.Server
{
if (parameter.IsChannelCountValid())
{
LimiterCommandVersion1 command = new(bufferOffset, parameter, state, isEnabled, workBuffer, nodeId);
LimiterCommandVersion1 command = _limiterCommandVersion1Pool.Allocate().Initialize(bufferOffset, parameter, state, isEnabled, workBuffer, nodeId);
command.EstimatedProcessingTime = _commandProcessingTimeEstimator.Estimate(command);
@@ -524,7 +682,7 @@ namespace Ryujinx.Audio.Renderer.Server
{
if (parameter.IsChannelCountValid())
{
LimiterCommandVersion2 command = new(bufferOffset, parameter, state, effectResultState, isEnabled, workBuffer, nodeId);
LimiterCommandVersion2 command = _limiterCommandVersion2Pool.Allocate().Initialize(bufferOffset, parameter, state, effectResultState, isEnabled, workBuffer, nodeId);
command.EstimatedProcessingTime = _commandProcessingTimeEstimator.Estimate(command);
@@ -550,7 +708,7 @@ namespace Ryujinx.Audio.Renderer.Server
{
if (state.SendBufferInfoBase != 0 && state.ReturnBufferInfoBase != 0)
{
AuxiliaryBufferCommand command = new(bufferOffset, inputBufferOffset, outputBufferOffset, ref state, isEnabled, countMax, outputBuffer, inputBuffer, updateCount, writeOffset, nodeId);
AuxiliaryBufferCommand command = _auxiliaryBufferCommandPool.Allocate().Initialize(bufferOffset, inputBufferOffset, outputBufferOffset, ref state, isEnabled, countMax, outputBuffer, inputBuffer, updateCount, writeOffset, nodeId);
command.EstimatedProcessingTime = _commandProcessingTimeEstimator.Estimate(command);
@@ -574,7 +732,7 @@ namespace Ryujinx.Audio.Renderer.Server
{
if (sendBufferInfo != 0)
{
CaptureBufferCommand command = new(bufferOffset, inputBufferOffset, sendBufferInfo, isEnabled, countMax, outputBuffer, updateCount, writeOffset, nodeId);
CaptureBufferCommand command = _captureBufferCommandPool.Allocate().Initialize(bufferOffset, inputBufferOffset, sendBufferInfo, isEnabled, countMax, outputBuffer, updateCount, writeOffset, nodeId);
command.EstimatedProcessingTime = _commandProcessingTimeEstimator.Estimate(command);
@@ -595,7 +753,7 @@ namespace Ryujinx.Audio.Renderer.Server
{
if (parameter.IsChannelCountValid())
{
CompressorCommand command = new(bufferOffset, parameter, state, effectResultState, isEnabled, nodeId);
CompressorCommand command = _compressorCommandPool.Allocate().Initialize(bufferOffset, parameter, state, effectResultState, isEnabled, nodeId);
command.EstimatedProcessingTime = _commandProcessingTimeEstimator.Estimate(command);
@@ -611,7 +769,7 @@ namespace Ryujinx.Audio.Renderer.Server
/// <param name="nodeId">The node id associated to this command.</param>
public void GenerateVolume(float volume, uint bufferOffset, int nodeId)
{
VolumeCommand command = new(volume, bufferOffset, nodeId);
VolumeCommand command = _volumeCommandPool.Allocate().Initialize(volume, bufferOffset, nodeId);
command.EstimatedProcessingTime = _commandProcessingTimeEstimator.Estimate(command);
@@ -626,7 +784,7 @@ namespace Ryujinx.Audio.Renderer.Server
/// <param name="nodeId">The node id associated to this command.</param>
public void GenerateCircularBuffer(uint bufferOffset, CircularBufferSink sink, int nodeId)
{
CircularBufferSinkCommand command = new(bufferOffset, ref sink.Parameter, ref sink.CircularBufferAddressInfo, sink.CurrentWriteOffset, nodeId);
CircularBufferSinkCommand command = _circularBufferSinkCommandPool.Allocate().Initialize(bufferOffset, ref sink.Parameter, ref sink.CircularBufferAddressInfo, sink.CurrentWriteOffset, nodeId);
command.EstimatedProcessingTime = _commandProcessingTimeEstimator.Estimate(command);
@@ -643,7 +801,7 @@ namespace Ryujinx.Audio.Renderer.Server
/// <param name="nodeId">The node id associated to this command.</param>
public void GenerateDownMixSurroundToStereo(uint bufferOffset, Span<byte> inputBufferOffset, Span<byte> outputBufferOffset, float[] downMixParameter, int nodeId)
{
DownMixSurroundToStereoCommand command = new(bufferOffset, inputBufferOffset, outputBufferOffset, downMixParameter, nodeId);
DownMixSurroundToStereoCommand command = _downMixSurroundToStereoCommandPool.Allocate().Initialize(bufferOffset, inputBufferOffset, outputBufferOffset, downMixParameter, nodeId);
command.EstimatedProcessingTime = _commandProcessingTimeEstimator.Estimate(command);
@@ -654,16 +812,16 @@ 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);
UpsampleCommand command = _upsampleCommandPool.Allocate().Initialize(bufferOffset, upsampler, inputCount, inputBufferOffset, bufferCountPerSample, sampleCount, sampleRate, nodeId);
command.EstimatedProcessingTime = _commandProcessingTimeEstimator.Estimate(command);
@@ -680,11 +838,20 @@ namespace Ryujinx.Audio.Renderer.Server
/// <param name="nodeId">The node id associated to this command.</param>
public void GenerateDeviceSink(uint bufferOffset, DeviceSink sink, int sessionId, Memory<float> buffer, int nodeId)
{
DeviceSinkCommand command = new(bufferOffset, sink, sessionId, buffer, nodeId);
DeviceSinkCommand command = _deviceSinkCommandPool.Allocate().Initialize(bufferOffset, sink, sessionId, buffer, nodeId);
command.EstimatedProcessingTime = _commandProcessingTimeEstimator.Estimate(command);
AddCommand(command);
}
public void GenerateFillBuffer(SplitterDestination destination, float value, int length, int nodeId)
{
FillBufferCommand command = _fillBufferCommandPool.Allocate().Initialize(destination, length, value, nodeId);
command.EstimatedProcessingTime = _commandProcessingTimeEstimator.Estimate(command);
AddCommand(command);
}
}
}

View File

@@ -41,27 +41,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 +74,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 +92,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 +169,7 @@ namespace Ryujinx.Audio.Renderer.Server
stateMemory.Slice(i, 1),
bufferOffset,
bufferOffset,
!voiceState.BiquadFilterNeedInitialization[i],
!voiceInfo.BiquadFilterNeedInitialization[i],
nodeId);
}
}
@@ -174,7 +178,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 +187,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 +272,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,31 +311,34 @@ 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;
}
bool performanceInitialized = false;
PerformanceEntryAddresses performanceEntry = new();
PerformanceEntryAddresses performanceEntry = null;
if (_performanceManager != null && _performanceManager.IsTargetNodeId(nodeId) && _performanceManager.GetNextEntry(out performanceEntry, dataSourceDetailType, PerformanceEntryType.Voice, nodeId))
{
@@ -340,18 +347,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 +369,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 +386,8 @@ namespace Ryujinx.Audio.Renderer.Server
}
_commandBuffer.GenerateVolumeRamp(
voiceState.PreviousVolume,
voiceState.Volume,
voiceInfo.PreviousVolume,
voiceInfo.Volume,
_rendererContext.MixBufferCount + (uint)channelIndex,
nodeId);
@@ -389,17 +396,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 +421,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 +453,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 +481,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,13 +493,13 @@ 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();
PerformanceEntryAddresses performanceEntry = null;
bool performanceInitialized = false;
@@ -503,7 +510,7 @@ namespace Ryujinx.Audio.Renderer.Server
GeneratePerformance(ref performanceEntry, PerformanceCommand.Type.Start, nodeId);
}
GenerateVoice(ref sortedState);
GenerateVoice(ref sortedInfo);
if (performanceInitialized)
{
@@ -526,15 +533,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 +565,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 +586,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 +634,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 +657,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 +667,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 +685,7 @@ namespace Ryujinx.Audio.Renderer.Server
ulong workBuffer = effect.GetWorkBuffer(-1);
if (_rendererContext.BehaviourContext.IsEffectInfoVersion2Supported())
if (_rendererContext.BehaviourInfo.IsEffectInfoVersion2Supported())
{
Memory<EffectResultState> dspResultState;
@@ -701,6 +719,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 +739,7 @@ namespace Ryujinx.Audio.Renderer.Server
_commandBuffer.GenerateCaptureEffect(
bufferOffset,
effect.Parameter.Input[i],
inputSpan[i],
effect.State.SendBufferInfo,
effect.IsEnabled,
effect.Parameter.BufferStorageSize,
@@ -759,13 +779,13 @@ 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;
bool isFinalMix = mix.MixId == Constants.FinalMixId;
PerformanceEntryAddresses performanceEntry = new();
PerformanceEntryAddresses performanceEntry = null;
bool performanceInitialized = false;
@@ -789,13 +809,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 +841,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 +877,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 +890,7 @@ namespace Ryujinx.Audio.Renderer.Server
inputBufferIndex,
outputBufferIndex,
0,
Memory<VoiceUpdateState>.Empty,
Memory<VoiceState>.Empty,
ref bqf0,
ref bqf1,
bqfState[..1],
@@ -894,7 +914,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 +933,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 +948,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 +977,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 +1016,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 +1038,7 @@ namespace Ryujinx.Audio.Renderer.Server
}
}
private void GenerateSubMix(ref MixState subMix)
private void GenerateSubMix(ref MixInfo subMix)
{
_commandBuffer.GenerateDepopForMixBuffers(
_rendererContext.DepopBuffer,
@@ -1029,7 +1049,7 @@ namespace Ryujinx.Audio.Renderer.Server
GenerateEffects(ref subMix);
PerformanceEntryAddresses performanceEntry = new();
PerformanceEntryAddresses performanceEntry = null;
int nodeId = subMix.NodeId;
@@ -1054,13 +1074,13 @@ 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();
PerformanceEntryAddresses performanceEntry = null;
bool performanceInitialized = false;
@@ -1071,7 +1091,7 @@ namespace Ryujinx.Audio.Renderer.Server
GeneratePerformance(ref performanceEntry, PerformanceCommand.Type.Start, nodeId);
}
GenerateSubMix(ref sortedState);
GenerateSubMix(ref sortedInfo);
if (performanceInitialized)
{
@@ -1083,7 +1103,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,
@@ -1094,7 +1114,7 @@ namespace Ryujinx.Audio.Renderer.Server
GenerateEffects(ref finalMix);
PerformanceEntryAddresses performanceEntry = new();
PerformanceEntryAddresses performanceEntry = null;
int nodeId = finalMix.NodeId;
@@ -1143,7 +1163,7 @@ namespace Ryujinx.Audio.Renderer.Server
{
int nodeId = _mixContext.GetFinalState().NodeId;
PerformanceEntryAddresses performanceEntry = new();
PerformanceEntryAddresses performanceEntry = null;
bool performanceInitialized = false;
@@ -1162,16 +1182,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 +1218,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,11 +1239,11 @@ 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;
PerformanceEntryAddresses performanceEntry = new();
PerformanceEntryAddresses performanceEntry = null;
if (_performanceManager != null && _performanceManager.GetNextEntry(out performanceEntry, PerformanceEntryType.Sink, sink.NodeId))
{
@@ -1257,7 +1277,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++)
{

View File

@@ -194,5 +194,10 @@ namespace Ryujinx.Audio.Renderer.Server
{
return 0;
}
public uint Estimate(FillBufferCommand command)
{
return 0;
}
}
}

View File

@@ -486,5 +486,10 @@ namespace Ryujinx.Audio.Renderer.Server
{
return 0;
}
public uint Estimate(FillBufferCommand command)
{
return 0;
}
}
}

View File

@@ -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;
}
}
}

View File

@@ -286,5 +286,10 @@ namespace Ryujinx.Audio.Renderer.Server
return 8683;
}
}
public override uint Estimate(FillBufferCommand command)
{
return 0;
}
}
}

View File

@@ -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,20 +18,26 @@ namespace Ryujinx.Audio.Renderer.Server.Effect
/// <summary>
/// The biquad filter parameter.
/// </summary>
public BiquadFilterEffectParameter Parameter;
public BiquadFilterEffectParameter2 Parameter;
/// <summary>
/// The biquad filter state.
/// </summary>
public Memory<BiquadFilterState> State { get; }
/// <summary>
/// The biquad filter effect version.
/// </summary>
public int BiquadFilterEffectVersion;
/// <summary>
/// Create a new <see cref="BiquadFilterEffect"/>.
/// </summary>
public BiquadFilterEffect()
public BiquadFilterEffect(int version)
{
Parameter = new BiquadFilterEffectParameter();
Parameter = new BiquadFilterEffectParameter2();
State = new BiquadFilterState[Constants.ChannelCountMax];
BiquadFilterEffectVersion = version;
}
public override EffectType TargetEffectType => EffectType.BiquadFilter;
@@ -51,7 +58,17 @@ namespace Ryujinx.Audio.Renderer.Server.Effect
UpdateParameterBase(in parameter);
Parameter = MemoryMarshal.Cast<byte, BiquadFilterEffectParameter>(parameter.SpecificData)[0];
if (BiquadFilterEffectVersion == 2)
{
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();

View File

@@ -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);
}
}

View File

@@ -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);
}
}
}

View File

@@ -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;

View File

@@ -18,7 +18,7 @@ namespace Ryujinx.Audio.Renderer.Server.MemoryPool
const uint CurrentProcessPseudoHandle = 0xFFFF8001;
/// <summary>
/// The result of <see cref="Update(ref MemoryPoolState, ref MemoryPoolInParameter, ref MemoryPoolOutStatus)"/>.
/// The result of <see cref="Update(ref MemoryPoolInfo, ref MemoryPoolInParameter, ref MemoryPoolOutStatus)"/>.
/// </summary>
public enum UpdateResult : uint
{
@@ -49,9 +49,9 @@ namespace Ryujinx.Audio.Renderer.Server.MemoryPool
private readonly uint _processHandle;
/// <summary>
/// The <see cref="Memory{MemoryPoolState}"/> that will be manipulated.
/// The <see cref="Memory{MemoryPoolInfo}"/> that will be manipulated.
/// </summary>
private readonly Memory<MemoryPoolState> _memoryPools;
private readonly Memory<MemoryPoolInfo> _memoryPools;
/// <summary>
/// If set to true, this will try to force map memory pool even if their state are considered invalid.
@@ -67,7 +67,7 @@ namespace Ryujinx.Audio.Renderer.Server.MemoryPool
{
_processHandle = processHandle;
_isForceMapEnabled = isForceMapEnabled;
_memoryPools = Memory<MemoryPoolState>.Empty;
_memoryPools = Memory<MemoryPoolInfo>.Empty;
}
/// <summary>
@@ -76,7 +76,7 @@ namespace Ryujinx.Audio.Renderer.Server.MemoryPool
/// <param name="processHandle">The handle of the process owning the CPU memory manipulated.</param>
/// <param name="memoryPool">The user memory pools.</param>
/// <param name="isForceMapEnabled">If set to true, this will try to force map memory pool even if their state are considered invalid.</param>
public PoolMapper(uint processHandle, Memory<MemoryPoolState> memoryPool, bool isForceMapEnabled)
public PoolMapper(uint processHandle, Memory<MemoryPoolInfo> memoryPool, bool isForceMapEnabled)
{
_processHandle = processHandle;
_memoryPools = memoryPool;
@@ -84,15 +84,15 @@ namespace Ryujinx.Audio.Renderer.Server.MemoryPool
}
/// <summary>
/// Initialize the <see cref="MemoryPoolState"/> for system use.
/// Initialize the <see cref="MemoryPoolInfo"/> for system use.
/// </summary>
/// <param name="memoryPool">The <see cref="MemoryPoolState"/> for system use.</param>
/// <param name="memoryPool">The <see cref="MemoryPoolInfo"/> for system use.</param>
/// <param name="cpuAddress">The <see cref="CpuAddress"/> to assign.</param>
/// <param name="size">The size to assign.</param>
/// <returns>Returns true if mapping on the <see cref="Dsp.AudioProcessor"/> succeeded.</returns>
public bool InitializeSystemPool(ref MemoryPoolState memoryPool, CpuAddress cpuAddress, ulong size)
public bool InitializeSystemPool(ref MemoryPoolInfo memoryPool, CpuAddress cpuAddress, ulong size)
{
if (memoryPool.Location != MemoryPoolState.LocationType.Dsp)
if (memoryPool.Location != MemoryPoolInfo.LocationType.Dsp)
{
return false;
}
@@ -101,13 +101,13 @@ namespace Ryujinx.Audio.Renderer.Server.MemoryPool
}
/// <summary>
/// Initialize the <see cref="MemoryPoolState"/>.
/// Initialize the <see cref="MemoryPoolInfo"/>.
/// </summary>
/// <param name="memoryPool">The <see cref="MemoryPoolState"/>.</param>
/// <param name="memoryPool">The <see cref="MemoryPoolInfo"/>.</param>
/// <param name="cpuAddress">The <see cref="CpuAddress"/> to assign.</param>
/// <param name="size">The size to assign.</param>
/// <returns>Returns true if mapping on the <see cref="Dsp.AudioProcessor"/> succeeded.</returns>
public bool InitializePool(ref MemoryPoolState memoryPool, CpuAddress cpuAddress, ulong size)
public bool InitializePool(ref MemoryPoolInfo memoryPool, CpuAddress cpuAddress, ulong size)
{
memoryPool.SetCpuAddress(cpuAddress, size);
@@ -115,18 +115,18 @@ namespace Ryujinx.Audio.Renderer.Server.MemoryPool
}
/// <summary>
/// Get the process handle associated to the <see cref="MemoryPoolState"/>.
/// Get the process handle associated to the <see cref="MemoryPoolInfo"/>.
/// </summary>
/// <param name="memoryPool">The <see cref="MemoryPoolState"/>.</param>
/// <returns>Returns the process handle associated to the <see cref="MemoryPoolState"/>.</returns>
public uint GetProcessHandle(ref MemoryPoolState memoryPool)
/// <param name="memoryPool">The <see cref="MemoryPoolInfo"/>.</param>
/// <returns>Returns the process handle associated to the <see cref="MemoryPoolInfo"/>.</returns>
public uint GetProcessHandle(ref MemoryPoolInfo memoryPool)
{
if (memoryPool.Location == MemoryPoolState.LocationType.Cpu)
if (memoryPool.Location == MemoryPoolInfo.LocationType.Cpu)
{
return CurrentProcessPseudoHandle;
}
if (memoryPool.Location == MemoryPoolState.LocationType.Dsp)
if (memoryPool.Location == MemoryPoolInfo.LocationType.Dsp)
{
return _processHandle;
}
@@ -135,11 +135,11 @@ namespace Ryujinx.Audio.Renderer.Server.MemoryPool
}
/// <summary>
/// Map the <see cref="MemoryPoolState"/> on the <see cref="Dsp.AudioProcessor"/>.
/// Map the <see cref="MemoryPoolInfo"/> on the <see cref="Dsp.AudioProcessor"/>.
/// </summary>
/// <param name="memoryPool">The <see cref="MemoryPoolState"/> to map.</param>
/// <param name="memoryPool">The <see cref="MemoryPoolInfo"/> to map.</param>
/// <returns>Returns the DSP address mapped.</returns>
public DspAddress Map(ref MemoryPoolState memoryPool)
public DspAddress Map(ref MemoryPoolInfo memoryPool)
{
DspAddress result = AudioProcessorMemoryManager.Map(GetProcessHandle(ref memoryPool), memoryPool.CpuAddress, memoryPool.Size);
@@ -152,11 +152,11 @@ namespace Ryujinx.Audio.Renderer.Server.MemoryPool
}
/// <summary>
/// Unmap the <see cref="MemoryPoolState"/> from the <see cref="Dsp.AudioProcessor"/>.
/// Unmap the <see cref="MemoryPoolInfo"/> from the <see cref="Dsp.AudioProcessor"/>.
/// </summary>
/// <param name="memoryPool">The <see cref="MemoryPoolState"/> to unmap.</param>
/// <param name="memoryPool">The <see cref="MemoryPoolInfo"/> to unmap.</param>
/// <returns>Returns true if unmapped.</returns>
public bool Unmap(ref MemoryPoolState memoryPool)
public bool Unmap(ref MemoryPoolInfo memoryPool)
{
if (memoryPool.IsUsed)
{
@@ -172,12 +172,12 @@ namespace Ryujinx.Audio.Renderer.Server.MemoryPool
}
/// <summary>
/// Find a <see cref="MemoryPoolState"/> associated to the region given.
/// Find a <see cref="MemoryPoolInfo"/> associated to the region given.
/// </summary>
/// <param name="cpuAddress">The region <see cref="CpuAddress"/>.</param>
/// <param name="size">The region size.</param>
/// <returns>Returns the <see cref="MemoryPoolState"/> found or <see cref="Memory{MemoryPoolState}.Empty"/> if not found.</returns>
private Span<MemoryPoolState> FindMemoryPool(CpuAddress cpuAddress, ulong size)
/// <returns>Returns the <see cref="MemoryPoolInfo"/> found or <see cref="Memory{MemoryPoolInfo}.Empty"/> if not found.</returns>
private Span<MemoryPoolInfo> FindMemoryPool(CpuAddress cpuAddress, ulong size)
{
if (!_memoryPools.IsEmpty && _memoryPools.Length > 0)
{
@@ -190,7 +190,7 @@ namespace Ryujinx.Audio.Renderer.Server.MemoryPool
}
}
return Span<MemoryPoolState>.Empty;
return Span<MemoryPoolInfo>.Empty;
}
/// <summary>
@@ -201,7 +201,7 @@ namespace Ryujinx.Audio.Renderer.Server.MemoryPool
{
if (_isForceMapEnabled)
{
Span<MemoryPoolState> memoryPool = FindMemoryPool(addressInfo.CpuAddress, addressInfo.Size);
Span<MemoryPoolInfo> memoryPool = FindMemoryPool(addressInfo.CpuAddress, addressInfo.Size);
if (!memoryPool.IsEmpty)
{
@@ -243,13 +243,13 @@ namespace Ryujinx.Audio.Renderer.Server.MemoryPool
}
/// <summary>
/// Update a <see cref="MemoryPoolState"/> using user parameters.
/// Update a <see cref="MemoryPoolInfo"/> using user parameters.
/// </summary>
/// <param name="memoryPool">The <see cref="MemoryPoolState"/> to update.</param>
/// <param name="memoryPool">The <see cref="MemoryPoolInfo"/> to update.</param>
/// <param name="inParameter">Input user parameter.</param>
/// <param name="outStatus">Output user parameter.</param>
/// <returns>Returns the <see cref="UpdateResult"/> of the operations performed.</returns>
public UpdateResult Update(ref MemoryPoolState memoryPool, in MemoryPoolInParameter inParameter, ref MemoryPoolOutStatus outStatus)
public UpdateResult Update(ref MemoryPoolInfo memoryPool, in MemoryPoolInParameter inParameter, ref MemoryPoolOutStatus outStatus)
{
MemoryPoolUserState inputState = inParameter.State;
@@ -321,7 +321,7 @@ namespace Ryujinx.Audio.Renderer.Server.MemoryPool
if (_memoryPools.Length > 0)
{
Span<MemoryPoolState> memoryPool = FindMemoryPool(addressInfo.CpuAddress, addressInfo.Size);
Span<MemoryPoolInfo> memoryPool = FindMemoryPool(addressInfo.CpuAddress, addressInfo.Size);
if (!memoryPool.IsEmpty)
{
@@ -343,7 +343,7 @@ namespace Ryujinx.Audio.Renderer.Server.MemoryPool
{
unsafe
{
addressInfo.SetupMemoryPool(MemoryPoolState.Null);
addressInfo.SetupMemoryPool(MemoryPoolInfo.Null);
}
}
@@ -351,12 +351,12 @@ namespace Ryujinx.Audio.Renderer.Server.MemoryPool
}
/// <summary>
/// Remove the usage flag from all the <see cref="MemoryPoolState"/>.
/// Remove the usage flag from all the <see cref="MemoryPoolInfo"/>.
/// </summary>
/// <param name="memoryPool">The <see cref="Memory{MemoryPoolState}"/> to reset.</param>
public static void ClearUsageState(Memory<MemoryPoolState> memoryPool)
/// <param name="memoryPool">The <see cref="Memory{MemoryPoolInfo}"/> to reset.</param>
public static void ClearUsageState(Memory<MemoryPoolInfo> memoryPool)
{
foreach (ref MemoryPoolState info in memoryPool.Span)
foreach (ref MemoryPoolInfo info in memoryPool.Span)
{
info.IsUsed = false;
}

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