Compare commits

..

525 Commits

Author SHA1 Message Date
Ani a00f9e4211 rpcs3_version: Bump to 0.0.25 2022-11-01 21:50:08 +00:00
brian218 3cb9cd7724 sys_fs: Minor fixup (#12913)
Stubbed sys_fs_newfs
2022-11-01 19:49:50 +03:00
Eladash 9632d0ab8a Emu: fixup message when the application has crashed 2022-11-01 19:08:55 +03:00
brian218 68b68e676b sys_fs.cpp: Satisfy Clang 2022-10-31 18:53:09 +03:00
brian218 c7ced46707 Add support for mounting and unmounting CELL_FS_SIMPLEFS 2022-10-31 18:53:09 +03:00
brian218 ecc194cb62 Use DECR's Product Code when Debug Console Mode is enabled 2022-10-31 18:53:09 +03:00
Nekotekina a1b4ffcf52 VFS.cpp: fixup for mounting files 2022-10-31 14:20:02 +03:00
Nekotekina ae809ad320 Unexpected bugfixes
Mostly unaligned memory access.
Also includes workarounds for ubsan execution.
2022-10-31 14:20:02 +03:00
kd-11 7d1c18a569 Fix LOD bias widget title. 2022-10-31 13:39:37 +03:00
kd-11 71f034c4ea Move 'LOD bias addend' to debug tab 2022-10-31 13:39:37 +03:00
kd-11 b156b40f8f rsx: Fix clear color for formats with less than 32-bit width 2022-10-31 13:39:37 +03:00
Darkhost1999 8d5a9dc722 Add Texture lod bias to UI (#12905) 2022-10-30 21:06:53 +01:00
RipleyTom 06dc6909c4 implement sceNpManagerGetMyLanguages 2022-10-30 18:00:54 +01:00
capriots c639b7d5f4 cellAudioAdd6chData(): fix channel order 2022-10-30 04:50:02 +01:00
Megamouse a38e144320 overlays: use the system keyboard layout for osk 2022-10-29 22:56:08 +02:00
Megamouse 059c45f202 overlays: implement osk keyboard cursor actions 2022-10-29 22:56:08 +02:00
Megamouse eccceea7fb overlays: implement osk delete action 2022-10-29 22:56:08 +02:00
Megamouse ad340c3007 overlays/osk: Implement fallback for unknown keys
Note that those keys won't be passed to the cellOsk event hook callback
2022-10-29 22:56:08 +02:00
Elad Ashkenazi c214f45e14 Savestates/rsx/IO: Resume emulation on long START press, enable "Start Paused" by defaut (#12881)
* Savestates: Enable "Start Paused" by default
* Emu/rsx/IO: Resume emulation on long START press
* rsx: fix missing graphics with savestates' "Start Paused" setting
* rsx/overlays: Add simple reference counting for messages to hide them manually
* Move some code in Emulator::Pause() so thread pausing is the first thing done by this function
2022-10-29 19:53:00 +02:00
Elad Ashkenazi c8620070b9 Savestates/System.cpp: Realized fix for suspend mode (#12883) 2022-10-28 09:51:46 +02:00
brian218 61a371b106 Implemented sys_fs_mount() and sys_fs_unmount() 2022-10-28 08:51:41 +02:00
shinra-electric 5210df6882 [3rdParty] Update MoltenVK to 1.2.231 2022-10-25 07:22:44 +02:00
shinra-electric edb7991979 Remove MVK Semaphore Support Style options
This line is no longer needed as MVK will select the appropriate support style automatically. 

See https://github.com/KhronosGroup/MoltenVK/pull/1738
2022-10-25 07:22:44 +02:00
Elad Ashkenazi 90d6069a16 Update System.cpp 2022-10-24 18:54:53 +03:00
RipleyTom 880a4e3ca6 SceNpScore: improvements 2022-10-24 00:49:44 +02:00
Eladash 18e30c7e44 rsx: Implement custom fractional frame limit 2022-10-24 00:10:37 +02:00
Eladash 0113224cb6 cfg: Implement float config entry
Add missing string empty checks
2022-10-24 00:10:37 +02:00
Eladash d1bd936765 rsx: Unlimit texture LOD bias addend
It's a relative setting and actual bias ranges from -16 to +16, so the maximum difference an addend would make is 32.
2022-10-24 00:10:37 +02:00
kd-11 2c41eecdb1 rsx: Force position invariance on GPUs where it matters 2022-10-24 00:49:44 +03:00
Elad Ashkenazi 1a9e38a1dd System.cpp: Minor regression fix (#12874)
Do not move savestate if the actual boot is unsuccessful.
2022-10-23 18:07:44 +03:00
Eladash 9f3f619774 Minor cleanup 2022-10-23 13:06:57 +02:00
Eladash 795e234c6f game list: Silence some warning 2022-10-23 13:06:57 +02:00
Eladash 23fdcbfeb8 Add one missing line, fix savestate restart 2022-10-23 13:06:57 +02:00
Eladash ee3e36672c Savestates: Rename savestate when booting the game regularly (suspend mode) 2022-10-23 10:49:58 +02:00
Eladash 119b4e4529 Savestates/Menu: Add "Create Savestate" Button 2022-10-23 10:49:58 +02:00
Eladash cc6112cbc4 Savestates: Auto-relaunch savestate when suspen mode is off 2022-10-23 10:49:58 +02:00
Eladash f16c9cd3c6 Savestates: Disable HDD1 saving optimization
HDD1 is very volatile, it was a bad idea not to save it.
2022-10-23 10:49:58 +02:00
Eladash 9e4c24baa3 qt: Add "suspend Emulation Mode Savestates" to advanced tab 2022-10-23 10:49:58 +02:00
Elad Ashkenazi 801609fb78 Make RPCS3 not delete savestate on boot by default 2022-10-23 10:49:58 +02:00
Megamouse 4c8630d29f sceNpTrophyRegisterContext: log tls error 2022-10-22 22:30:23 +02:00
Megamouse 4e426af114 Qt: replace nul character with 0 in the log viewer
Fixes cropped content
2022-10-22 22:30:23 +02:00
Megamouse 5b66fe47db sceNpTrophyCreateContext: do not log nul characters 2022-10-22 22:30:23 +02:00
RipleyTom 7ae9b15b5c sys_net: return appropriate packet size for P2P 2022-10-22 20:14:32 +03:00
RipleyTom 67323994fc Implement sceNpScoreSanitizeComment 2022-10-22 18:43:13 +02:00
kd-11 fcc7a7452a vk: Fix scratch buf size calculation when uploading DSVs 2022-10-22 15:11:40 +03:00
kd-11 1bb0caed6f gl: Add missing memory barrier after texture decode 2022-10-22 15:11:40 +03:00
Elad Ashkenazi 23a445619b Savestates: +1 Bug 2022-10-22 13:37:33 +02:00
RipleyTom 837d9ca688 Disable AlignConsecutiveAssignments 2022-10-22 11:32:04 +02:00
RipleyTom 9b121a6414 sys_net: improvements
sys_net: implement reusable addr for p2p sockets
sys_net: implement getpeername for P2PS
sys_net: sockets inherit NBIO from their parent
2022-10-22 11:32:04 +02:00
Megamouse 5f1aafb961 Dualsense: Enable improved rumble emulation (or so)
Also disable audio haptics to save power
2022-10-22 10:26:26 +02:00
Megamouse 615ff08d1a Dualsense: Release LEDs on when the handler is destroyed 2022-10-22 10:26:26 +02:00
Megamouse 3320d1e1c7 Dualsense: Read firmware version as seen in firmware installer 2022-10-22 10:26:26 +02:00
Megamouse 3deb177ab7 Dualsense: name some report members based on SDL2 2022-10-22 10:26:26 +02:00
Megamouse 41dad58489 Loader/Input: Process Qt events instead of yielding during init 2022-10-21 23:42:01 +02:00
Megamouse cb8a240f1a Qt/Input: Properly clear pad selection in pad settings
Fixes a rare issue that causes a newly selected pad handler with no pads to try to connect a previously selected pad from another handler.
2022-10-21 23:42:01 +02:00
Megamouse 871ef2cdfe Input: return pad connection in get_next_button_press
This fix some minor race condition in the UI that had no real consequences just by chance.
2022-10-21 23:42:01 +02:00
Megamouse 6c0bc43776 Input: change brightness data type in hid to u32 2022-10-21 23:42:01 +02:00
Megamouse a16d18d83c Input: rename misleading ThreadProc to process 2022-10-21 23:42:01 +02:00
Megamouse e499c3c6e3 Input: move m_is_init to base class 2022-10-21 23:42:01 +02:00
Megamouse ddd261c943 Input: refactor vibration
There's no need to deal with vibration levels outside of the handlers.
All we need to know is the 0-255 DS3 range which is given by the u8 type.
2022-10-21 23:42:01 +02:00
Vestral a1f9ff0aaa Cubeb: rewrite locking 2022-10-21 22:15:49 +02:00
Megamouse d636ea9338 Update dependencies
zlib  1.2.12 -> 1.2.13
libpng 1.6.37 -> 1.6.38
glslang sdk-1.3.216.0 -> sdk-1.3.224.1
SPIRV-Headers sdk-1.3.211.0 -> sdk-1.3.224.1
SPIRV-Tools sdk-1.3.211.0 -> sdk-1.3.224.1
2022-10-21 20:44:46 +02:00
Megamouse 1747e68d1d Fix warning 2022-10-21 20:44:46 +02:00
Elad Ashkenazi c4c710d39d GUI TTY: fix a regression (#12855) 2022-10-21 19:05:21 +02:00
brian218 9a5dbda063 Changed the log level of LV2 Watchdog's being triggered 2022-10-21 17:38:59 +02:00
kd-11 bd9c876e36 gl: Handle clip plane switching using API calls and the state tracker 2022-10-21 13:45:45 +03:00
Eladash 903d847058 cellAudio: Implement setting to disable sampling skip 2022-10-21 09:32:49 +02:00
brian218 789e42e26f sys_sm_shutdown() log minor fixup 2022-10-21 02:09:08 +02:00
brian218 85e11ca341 USIO Input Enhancement 2022-10-20 21:00:38 +02:00
Eladash 0da81d22d3 SPU Profiler: fix CPU usage when emulation is paused
Avoid collecting samples when the thread paused.
2022-10-20 11:22:33 +03:00
Eladash 52b993095d SPU Profiler: nearly always print on Emu.Pause() 2022-10-20 11:22:33 +03:00
Megamouse 363e0a40e5 Input: Allow to toggle player LED (Dualsense and DS3) 2022-10-19 22:55:50 +02:00
Eladash 7ea0a6d642 sys_game_watchdog minor fixups 2022-10-18 13:08:48 +02:00
Megamouse 035d410a89 evdev: change default axis for gyro 2022-10-18 00:19:01 +02:00
Megamouse b0b42071f2 Input: Fix Dualsense gyro axis and adjust DS4 resolution 2022-10-18 00:19:01 +02:00
brian218 5c24009eb5 Implemented sys_game_watchdog syscalls 2022-10-17 20:32:01 +03:00
Eladash 00340f33c3 GUI/TTY: fix UI deadlock when TTY is being spammed 2022-10-17 19:12:51 +03:00
RipleyTom 01c285fc4a RPCN v0.7
Bump protocol version
Improve signaling RTT calculation for client
Implement score game data functions
Various sceNpScore fixes
Verify flatbuffer buffers
Use std::variant for transaction specific data
2022-10-17 09:57:10 +02:00
Eladash 87797e117e sys_spu: Some more fixes of wait flag misuse 2022-10-16 20:55:36 +03:00
Eladash a5cc9a5517 Update cellFsGetDirectoryEntries to use wait flag correctly 2022-10-16 20:55:36 +03:00
Eladash 806acf8cd0 sys_fs: Fixed placement of check_state() and add some bugfixes 2022-10-16 20:55:36 +03:00
kd-11 04f6302ecc Fix decode shader compilation 2022-10-16 19:58:30 +03:00
kd-11 1df977fae2 gl: Avoid including unnecessary headers 2022-10-16 19:58:30 +03:00
kd-11 9105c2cf4a gl: Refactor capabilities and add GLSL version detection support. 2022-10-16 19:58:30 +03:00
kd-11 6d43fcf8fb gl: Fall back to renderpass decoder on ATI drivers 2022-10-16 19:58:30 +03:00
Megamouse fafae1cbb5 cellRtc: Fix some param checks 2022-10-15 19:56:53 +02:00
brian218 419e673d5b Fix USIO Backup behavior 2022-10-15 14:38:43 +02:00
brian218 48f47de95c Added USB passthrough for H050 USJ PCB 2022-10-15 14:38:43 +02:00
brian218 44a1df4353 usb_device: Updated control_transfer in order to prevent some games from being frozen 2022-10-15 14:38:43 +02:00
Megamouse 13b3c78c7f Input: fix MMJOY axis identification 2022-10-15 13:17:16 +02:00
Megamouse e362c2c078 Input: fix some type warnings 2022-10-15 13:17:16 +02:00
Megamouse 814adbb8c4 Input: simplify InitPadConfig 2022-10-15 13:17:16 +02:00
Megamouse cf86b6c107 Input: keep old port status when reconnecting ldd pads
The port status might not change currently, but it should be more correct this way.
2022-10-12 22:30:09 +02:00
Megamouse 12a83e5a1c Input: simplify unnecessarily complex ldd reload 2022-10-12 22:30:09 +02:00
Megamouse 0f769eec81 Input: log more pad information 2022-10-12 21:01:02 +02:00
kd-11 0737c788fc rsx: Fix parsing of broken command streams with hanging begin/end commands without a pair.
- While these are game bugs, the parser shouldn't break on encountering them.
2022-10-12 11:19:52 +03:00
kd-11 3fe9aea5b5 rsx/overlays: Allow some basic communication from the UI components to the backend renderers 2022-10-11 23:13:12 +02:00
Megamouse ab6ba848b8 overlays: simplify overlay_media_list_dialog 2022-10-11 23:13:12 +02:00
Elad Ashkenazi 0a38800e44 Savestates: fix endless renaming of used savestates (#12780) 2022-10-11 17:02:25 +03:00
kd-11 6be5618d22 config: Add missing option 2022-10-11 14:00:34 +03:00
kd-11 95d9462a71 settings: Remove misleading comment 2022-10-11 14:00:34 +03:00
kd-11 e05cd9f47b qt: Add translation for shader precision 2022-10-11 14:00:34 +03:00
kd-11 aa09302ca0 Clean up some unnecessary changes
- Hopefully nothing breaks 🤞
2022-10-11 14:00:34 +03:00
kd-11 6d6b9fd269 Qt: Apply tooltip hover to parent groupbox.
Co-authored-by: Megamouse <studienricky89@googlemail.com>
2022-10-11 14:00:34 +03:00
kd-11 6d265452cf rsxqt: Fix shader precision tooltip 2022-10-11 14:00:34 +03:00
kd-11 65d20f2d08 gl: Add mesa support for polygon offset 2022-10-11 14:00:34 +03:00
kd-11 a229e30b08 rsx: Implement RSX-compliant polygon offset 2022-10-11 14:00:34 +03:00
kd-11 d246a37b11 rsx: Move fp16 toggle to a global shader precision option 2022-10-11 14:00:34 +03:00
brian218 e839595053 Implemented sys_game_get_system_sw_version() 2022-10-11 08:32:49 +02:00
brian218 a711eb31f4 Corrected the implementation of sys_game_board_storage_read() 2022-10-11 08:32:49 +02:00
brian218 b117a6d4cd Improved the compatibility of USIO for old versions of games 2022-10-11 07:51:21 +02:00
Megamouse 36b1004e26 cubeb: ignore callbacks for unknown streams or contexts 2022-10-11 00:09:28 +02:00
Megamouse c75c47fdd2 cubeb: add some more logging and error checks 2022-10-11 00:09:28 +02:00
Megamouse 0f626c8d30 Qt: delay first log frame update
This fixes the log not scrolling automatically when we first open RPCS3 with a low log level.
2022-10-10 23:21:49 +02:00
Megamouse 021783dcc1 Qt: throw if a translation is expected in GetLocalizedSetting 2022-10-10 22:46:42 +02:00
Megamouse 1f339862db Qt: add missing translation comment 2022-10-10 22:46:42 +02:00
Megamouse 4446d9ce4b cellSubDisplay: add error checks 2022-10-10 21:26:27 +02:00
Elad Ashkenazi 92b08a4faf rsx: Fixup a bug after mfc list optimization (#12782) 2022-10-10 04:04:41 +03:00
brian218 d311b4bd53 Update sys_game_board_storage_read() 2022-10-09 21:05:10 +03:00
Eladash a6dfc3be2f SPU: Enable the MFC list optimization for Atomic RSX FIFO 2022-10-09 19:27:46 +03:00
Eladash 750e7b73e3 Optimize vm::range_lock a bit
Bad conditions led to optimization misses and long-generated code.
2022-10-09 19:27:46 +03:00
Eladash 6a36967e6f SPU: Inline and batch MFC list transfers 2022-10-09 19:27:46 +03:00
kd-11 d6d7ade6e3 vk: Reload state on dynamic state changed 2022-10-09 03:00:39 +03:00
shinra-electric 151d98df51 Update based on feedback by GovanifY 2022-10-09 02:16:08 +03:00
shinra-electric fa744e53d3 Replace sprintf with snprintf to silence compiler warning
This fixes the following compiler deprecation warning

`warning: 'sprintf' is deprecated: This function is provided for compatibility reasons only.  Due to security concerns inherent in the design of sprintf(3), it is highly recommended that you use snprintf(3) instead.`
2022-10-09 02:16:08 +03:00
Elad Ashkenazi e0df2c584f rsx: Attempt to fix frame limiter 2022-10-09 01:33:40 +03:00
kd-11 3c88477270 Fixup for scissor/viewport invalidation rules 2022-10-07 15:27:54 +03:00
kd-11 df46e5137c gl: Fix texture reconstruction logic
- Use correct target types
- Fix key generation to apply differently for each target type
2022-10-07 11:53:34 +03:00
kd-11 ffe8133865 vk: Avoid unnecessary dynamic state updates 2022-10-07 11:53:34 +03:00
kd-11 7140e82189 rsx: Fix program invalidation rules 2022-10-07 11:53:34 +03:00
Elad Ashkenazi cb743da215 sys_spu: fixup raw spu destroy regression
Caused a missed cpu_thread::state notification which is required now.
2022-10-06 12:23:51 +03:00
Elad Ashkenazi 4d24ba1f35 PPU Precompilation: Abort compilation as soon as possible on Emu.Stop() 2022-10-06 12:23:51 +03:00
kd-11 87411da95f gl: Explicitly declare gl_Position as invariant when using MESA 2022-10-06 06:41:24 +03:00
Eladash d25d1ecb3a LV2: Avoid using multi-variable atomic waiting on cpu_thread::state wait 2022-10-04 16:28:34 +03:00
Eladash 2a00a88e2a SPU LLVM: don't force-enter process_mfc_cmd() because it's slower 2022-10-04 16:28:34 +03:00
Eladash b01220d2c5 debugger: Don't refresh no-thread window at a high rate 2022-10-04 16:28:34 +03:00
Eladash 58dd2bff41 Savestates: Fix unintentional pause when saving with HLE VDEC contexts 2022-10-04 14:14:38 +03:00
Eladash f34773ed73 Savestates: Make Ctrl+R work when not ingame
Restore old behavior of Ctrl+R making it restart emulation when stoppped.
2022-10-04 14:14:38 +03:00
Eladash 9b5cc7cda7 System.cpp: Fix RSX thread abort 2022-10-04 14:14:38 +03:00
Elad Ashkenazi 77db8f04b9 Savestates: fix saving in HLE functions 2022-10-04 14:14:38 +03:00
Eladash 9319bc579c cellAudio: Always send periodic sampling events 2022-10-04 13:41:57 +03:00
kd-11 73784b9e12 Fix GCC build 2022-10-03 12:57:16 +03:00
kd-11 533f960854 rsx: Handle some more corner cases 2022-10-03 12:57:16 +03:00
kd-11 765208a181 rsx: Avoid clobbering CELL memory when splitting fbos 2022-10-03 12:57:16 +03:00
kd-11 4417701ea7 rsx: Track orphaned surfaces' parent addresses 2022-10-03 12:57:16 +03:00
kd-11 f66eaf8f44 rsx: Add some handy util functions to simple_array 2022-10-03 12:57:16 +03:00
kd-11 0dd9c386ee Fix running the emulator with AUDIT enabled 2022-10-03 12:57:16 +03:00
Eladash af8c871411 Add origin PRX names for log messages 2022-10-02 20:03:27 +03:00
brian218 50e1e6596e USIO Backup Minor Optimization 2022-10-01 17:32:22 +03:00
Malcolm Jestadt d8897c585d PPU/SPU LLVM: Allow Zen4 cpus to use VPERMI2B/VPERMT2B instead of the vperm2b256to128 path
- Zen4 based cpus can process VPERM2B in a single uop, unlike intel where it is 3 uops.
2022-10-01 15:38:29 +03:00
Megamouse 7d32dc312f Qt: pad settings: clear input data on thread pause
Fixes incorrectly disabled buttons when changing from a handler with a disconnected pad to any other handler
2022-10-01 13:49:58 +02:00
RipleyTom eff1e4bd7e CELL_NET_CTL_INFO_IP_ADDRESS returns external address 2022-10-01 11:56:41 +02:00
nastys ac50b46608 Mac CI fixes 2022-10-01 11:01:21 +02:00
kd-11 a0e2a3db1d Fix underflow in ZCULL sync 2022-09-30 23:44:37 +03:00
Elad Ashkenazi 0cc981ec18 SPU: fix atomicity of inaccurate GETLLAR 2022-09-30 15:26:08 +03:00
RipleyTom 8170b91f76 sceNpScore: return error on 0 scores returned 2022-09-28 21:58:11 +02:00
RipleyTom d1a7bb0136 Fix faulty GetScoreFriendsRequest 2022-09-28 21:58:11 +02:00
RipleyTom 56caa10e56 Fix blocking raw socket recvfrom 2022-09-28 21:58:11 +02:00
brian218 926496b59d USIO: Save Game Settings - Full Implementation 2022-09-28 16:54:55 +03:00
kd-11 102d30db2d vk: Update support for framebuffer loops to comply with current spec 2022-09-28 12:55:31 +03:00
kd-11 5281a85b67 rsx: Fix compiler warnings 2022-09-28 12:55:31 +03:00
kd-11 de28c812e8 rsx: Re-evaluate color MRT setup when the surface target type changes 2022-09-28 12:55:31 +03:00
RipleyTom eea73deab3 RPCN v0.6 2022-09-27 23:39:54 +03:00
kd-11 67c02e3522 vk: Bump compute descriptor pool size to 8k
- TODO: This should be dynamic.
2022-09-27 14:58:47 +03:00
kd-11 19dd2a693b gl: Fix transform job assert 2022-09-27 14:58:47 +03:00
Ani 3df133652a gui: Rename full width AVX-512 (#12709)
Some people think that this is a toggle to enable and disable AVX-512 support, let's make it more clear
2022-09-26 23:40:04 +01:00
xddxd 80d2034083 Update LLVM commit (Zen Detection) 2022-09-26 20:40:26 +01:00
shinra-electric db9389d24c [macOS] Ask CMake to look in the right place for include & link directories (#12516)
* Ask CMake to look in the right place for include_directories and link_directories on macOS (arm64 and x86_64)

Homebrew installs to a different location on Arm Macs compared to Intel Macs. 

This change prevents this error when compiling on Arm:   
`ld: warning: directory not found for option '-L/opt/local/lib'`

Use STREQUAL instead of MATCHES, since MATCHES is supposed to be used with regular expressions. 

Also update the homebrew directories for Intel, since they were wrong.

Remove the conditional check for x86 Apple, as usr/local is part of the default search path.
Tested on Intel and the warning does not appear.
2022-09-26 18:07:05 +01:00
brian218 c996be321c sys_game_board_storage_read(): Add more known code & Improve byte casting 2022-09-26 17:17:49 +01:00
Nekotekina 6ff6a4989a Implement at32() util
Works like .at() but uses source location for "exception".
2022-09-26 18:04:15 +03:00
cohaereo 2655255d4d sys_net: Implement sys_net_bnet_sendmsg for native sockets 2022-09-25 18:24:47 +03:00
Eladash 8485afa3a5 PPU debugger: report ppu_thread::ack_suspend state 2022-09-25 14:31:39 +03:00
Eladash 2759091ede Debugger: Rewind SPU captures
Very basic implementation, can be improved.
2022-09-25 14:31:39 +03:00
Eladash ae02b71a85 Savestates/Debugger: fix mfc debug option with savestates 2022-09-25 14:31:39 +03:00
Eladash 4445569bb0 Savestates: Don't actually delete savestates 2022-09-25 14:31:39 +03:00
Nekotekina a604394b20 BufferUtils: fix regression on AVX path
primitive_restart_impl::upload_untouched was broken.
Bug in vec_broadcast_gpr on AVX path.
2022-09-24 17:23:12 +03:00
kd-11 dd8a337b14 rsx: Fix some more warnings 2022-09-22 23:46:48 +03:00
kd-11 0572d44996 gl: Fix enum collision 2022-09-22 23:46:48 +03:00
kd-11 38aa116c59 Fix build 2022-09-22 23:46:48 +03:00
kd-11 61666bae69 rsx: Fix hardware deswizzle not getting used when hardware deswizzle flag is not set 2022-09-22 23:46:48 +03:00
kd-11 362a26a404 gl: Fix D24X8 accelerated encode/decode
- PS3 D24X8 is swapped as a full word, unlike PC.
- Add missing paths to handle custom swap behavior.
2022-09-22 23:46:48 +03:00
kd-11 81fa3da101 gl: Minor optimization around test..set patterns in the state tracker 2022-09-22 23:46:48 +03:00
RipleyTom bd1fb86492 Fix pkg batch install dlg on linux 2022-09-22 19:41:09 +02:00
Elad Ashkenazi 238298f695 sys_ppu_thread: Fix surmixer hack (#12689)
* sys_ppu_thread: Fix surmixer hack

* Hotfix after #12678
2022-09-21 21:10:59 +03:00
Eladash 194f7375da SPU/LV2: Fix tiny race conditions 2022-09-21 20:35:34 +03:00
brian218 3581c5b078 USIO: Save Game Settings 2022-09-21 14:43:24 +03:00
Marc Riera c5572acd38 Allow USB passthrough for Densha de GO! controller 2022-09-21 12:04:16 +03:00
nastys acc2fea7e3 Update MoltenVK to 250e1f9 and single queue (#12620) 2022-09-20 11:12:27 +03:00
kd-11 3dc7b64fa1 rsx: Fix initialization of null cubemap resources 2022-09-19 19:13:46 +03:00
kd-11 79f2c21dfb gl: Restrict compute image bindings to [0-8]
NVIDIA only supports 8 compute image slots even on modern GPUs.
2022-09-19 01:37:10 +03:00
kd-11 df36c44bc2 gl: Avoid UBO/SSBO binding index collisions
- Some drivers don't like this. Actually only RADV.
- Almost all GPUs going back 15 years have a large number of UBO slots but limited SSBO slots.
  Move UBO slots up as we have tons more headroom there.
2022-09-19 01:37:10 +03:00
Nekotekina c4db65cc08 Fix one more warning 2022-09-18 18:35:17 +03:00
Nekotekina c86ddb3b7d cellImeJp: fix regression 2022-09-18 18:35:17 +03:00
Florin9doi a1aebdc5d6 Request macOS 10.14.+ permissions (#12600) 2022-09-17 18:26:22 +01:00
Nekotekina b49a1f27eb Warning fixes 2022-09-17 16:35:02 +03:00
brian218 e7fd84e031 USIO: Keep LastGameStatus Memory 2022-09-17 10:59:28 +03:00
Eladash 9d9e18f614 CPU preemption control: don't yield if we can't stop 2022-09-16 18:57:55 +03:00
Eladash c8199de188 CPU preemption control: Improve stutter elimination 2022-09-16 18:57:55 +03:00
Eladash fc331da883 CPU preemption control: remove yield before thread stop 2022-09-16 18:57:55 +03:00
Eladash b6d3fa8c66 CPU preemption control: avoidance in reservation operations 2022-09-16 18:57:55 +03:00
Eladash 3cebea1801 CPU preemption control: extend range to 400 2022-09-16 18:57:55 +03:00
Eladash 2e9ee81dcd CPU preemption control: Improve analysis 2022-09-16 18:57:55 +03:00
Eladash cf4da5c4d1 CPU preemption control: bugfixes 2022-09-16 18:57:55 +03:00
Eladash 9d1ec0b319 CPU preemption control: try to minimize sleep time gaps between setups 2022-09-16 18:57:55 +03:00
Eladash 9c5108c1ca CPU preemption control: Add one more debug variable 2022-09-16 18:57:55 +03:00
Eladash 2807be7080 SPU: Regression fix after #12648 2022-09-13 20:11:30 +03:00
Eladash ec7b18dab5 Implement independent CPU preemptions 2022-09-13 19:28:20 +03:00
brian218 b9e20dc5c9 sys_game_board_storage_read(): Fix regression after #12637 2022-09-13 12:57:43 +03:00
Eladash cfdc852f03 SPU: Power consumption reduction when using SPU inaccurate reservations 2022-09-13 11:21:01 +03:00
Eladash 92514e33bb Avoid reservation notifications in liblv2.sprx 2022-09-13 11:21:01 +03:00
kd-11 572a2a06d1 rsx: Properly reset occlusion counters even when the register is not in use. 2022-09-12 17:15:06 +03:00
Eladash f076fcd539 cellMusic: Implement some error checking 2022-09-12 15:04:23 +03:00
Eladash 4ac59875af ppu: add some debug information 2022-09-12 15:04:23 +03:00
Eladash 780ca38f2f SPU: Extend Inaccurate SPU reservations 2022-09-12 14:16:39 +03:00
Ethan Rushbrook 97ea5e9dba readme: improvements
Fixed platform availability
Fixed discord link (discord.me is not valid)
2022-09-12 13:34:58 +03:00
Yui 9e83bc6544 Add the ability to set the PSID from the configuration (#12637) 2022-09-12 13:23:13 +03:00
Eladash 37aefe5811 sys_ppu_thread: Fix max thread name size 2022-09-12 12:57:39 +03:00
kd-11 d686b48f65 rsx: Simplify FIFO concurrent access. 2022-09-09 23:17:27 +03:00
kd-11 f319362e35 vk: Fix queue concurrency behavior for images 2022-09-09 23:17:27 +03:00
kd-11 0d9b1654ec asm: Avoid ALU instructions on busy wait cycles 2022-09-09 23:17:27 +03:00
kd-11 940e726754 rsx: Minor FIFO cleanup 2022-09-09 23:17:27 +03:00
kd-11 f43824762a rsx: Get rid of an allocation in analyse_vertex_data that adds about 5% overhead.
This method is called many thousands of times per frame and that single allocation introduces a small perf hit.
Just get rid of it, it doesn't improve anything to have it there.
2022-09-09 23:17:27 +03:00
kd-11 cd53bb7eff rsx: Avoid on-the-fly ZCULL allocations with unordered_map 2022-09-09 23:17:27 +03:00
Eladash 60fc90bb8e System.cpp: Fix Create Firmware Cache 2022-09-08 19:38:11 +03:00
Nekotekina a9437d69ab simd_builder: fixups
Fix resetting vmask in reduce() step.
Fix AVX-512 loads in vec_load_unaligned().
Fix bzhi reg size in build_look().
2022-09-08 18:12:15 +03:00
Nekotekina 5d91caebe9 Linux: delete /tmp/perf.map on exit 2022-09-08 16:56:06 +03:00
Eladash eb4131e1c7 cellGame: Minor revert
I think there are many more bugs here..
2022-09-07 20:42:23 +03:00
Eladash 07f0ba213e SPU: Allow special channel storage in channel busy waiting period
Move code to SPUThread.cpp.
2022-09-07 20:42:23 +03:00
Eladash 48382564d1 SPU: Implement "quintuple" Inbound MBOX storage 2022-09-07 20:42:23 +03:00
Eladash 274386a078 rsx: Add some debugging information 2022-09-07 18:39:32 +03:00
Eladash 557d015662 System.cpp: Fix Create PPU Cache regression 2022-09-07 18:39:32 +03:00
Nekotekina 5985f0eefa BufferUtils: cleanup regarding ARM64 2022-09-07 17:59:07 +03:00
Nekotekina 82258915da BufferUtils: rewrite remaining intrinsic code with simd_builder 2022-09-07 17:59:07 +03:00
Nekotekina 11a1f090d3 BufferUtils: simd_builder refactoring
Some simplifications implemented.
2022-09-07 17:59:07 +03:00
sguo35 a0d48c588a spu/arm64: clean up assembly code generation
Clean up asmjit usage so we don't unnecessarily allocate memory
anymore for SPURecompiler functions.
2022-09-07 17:33:01 +03:00
Eladash 5e2424da58 IdManager.cpp: Fix cellFs IDs 2022-09-07 17:05:51 +03:00
Eladash 72a6696f5c cellGame Fix PS3 disc insert 2022-09-07 17:05:51 +03:00
brian218 9087116ee5 Fix USIO fault when it received unsupported FW commands 2022-09-07 16:42:37 +03:00
Eladash 89e0dcba5e cellVdec: Adjust for reservations 2022-09-07 16:05:56 +03:00
Eladash 7698064f5a SPU: Untangle VM lock to avoid deadlocks 2022-09-07 16:05:56 +03:00
Megamouse ab31e96385 Qt: batch stack suffix updates
No need to patch the suffix every single time. We can just do it when we exit the stack loop.
2022-09-05 21:20:14 +02:00
Megamouse a9dcad629b Qt: fix weird missing space in stack log 2022-09-05 21:20:14 +02:00
Megamouse e49679484a Qt: simplify log logic. We can in fact only flush once.
Also invert a negation
2022-09-05 21:20:14 +02:00
Elad Ashkenazi 290226539f Fix ARM build (#12606) 2022-09-04 21:11:04 +03:00
brian218 75efc79930 Implemented sys_game_board_storage_read() 2022-09-04 13:28:05 +03:00
Nick Renieris 905496e926 PPU: Fix STVLX
Fixes Sly 2 and Sly 3 crash on boot (RSX desync).
2022-09-04 12:27:29 +03:00
srive 64579eef7e Update tooltips.h 2022-09-02 08:59:08 +02:00
Elad Ashkenazi e0a648240f Unlog sceNpUtilCmpNpId 2022-09-02 08:29:09 +02:00
Eladash 7bad8f3348 Savestates/SPU: Minor fixup after fb01ed55 2022-09-01 20:09:28 +03:00
Eladash 11a197a387 Savestates/RSX: fix unintentional vblank thread spin after abort 2022-09-01 20:09:28 +03:00
Eladash ee1384341e rsx: Implement atomic vertex upload (with Strict Rendering Mode) 2022-09-01 20:09:28 +03:00
Eladash fb01ed55e5 SPU: Fix potential deadlock in event queue syscalls 2022-09-01 19:03:38 +03:00
Elad Ashkenazi 5a0a5d9ff1 vm.cpp: Fix emulation stopping on SPU access violation (#12586) 2022-09-01 18:23:18 +03:00
Nekotekina 58e3232710 BufferUtils: Fix regression in upload_untouched 2022-09-01 17:39:04 +03:00
Ani 2cd7238e76 rpcs3_version: Bump to 0.0.24 2022-08-31 23:24:42 +01:00
Ani 21f0043b27 gui/themes: YoRHa by Ani (r3) (#11585) 2022-08-31 22:47:42 +01:00
Elad Ashkenazi b7599c0f30 Update Thread.cpp 2022-08-31 22:19:05 +03:00
Elad Ashkenazi d8494ef1ae Update Thread.cpp 2022-08-31 22:19:05 +03:00
Elad Ashkenazi 727b32e886 RawSPU: Do not assume GPU memory fault on SPU MMIO 2022-08-31 22:19:05 +03:00
Ani 8124efa505 cubeb: Update from 2022.04.13 to 2022.07.21 2022-08-31 17:59:35 +01:00
Ani a5cff4d797 glext: Update from 2021.04.20 to 2022.05.30 2022-08-31 17:59:35 +01:00
Ani d1e5828644 XAudio2: Update from 1.2.8 to 1.2.9 2022-08-31 17:59:35 +01:00
Ani 18d73d6d76 FAudio: Update from 22.07 to 22.08 2022-08-31 17:59:35 +01:00
Ani 4a3a24dcc1 7z: Update from 21.07 to 22.01 2022-08-31 17:59:35 +01:00
Eladash 591159c4a9 Debugger: Prevent possible "current instruction" duplication when the thread is running 2022-08-30 08:57:33 +02:00
Eladash 7baf959975 Avoid empty resume output when using PPU debug option 2022-08-30 08:57:33 +02:00
Eladash 3f02935844 Add some debugging information 2022-08-30 08:57:33 +02:00
RipleyTom f98251a05a Fixes -w leaking 2022-08-30 07:46:42 +02:00
Nekotekina 80f0741103 simd_builder: fix constant locations 2022-08-29 14:32:56 +03:00
Nekotekina e28707055b Implement simd_builder for x86
ASMJIT-based tool for building vectorized loops (such as ones in BufferUtils.cpp)
2022-08-28 18:38:52 +03:00
brian218 698c3415ea Fixed SIG: Thread terminated due to fatal error: Failed to read hex string: invalid argument
Fixed the error which occurred when a game attempted to read the VID/PID of an undefined VFS USB device:

SIG: Thread terminated due to fatal error: Failed to read hex string: invalid argument
(in file C:\Users\ContainerAdministrator\AppData\Local\Temp\cirrus-ci-build\rpcs3\Emu\Cell\lv2\sys_fs.cpp:1942[:25], in function sys_fs_fcntl)
2022-08-26 08:45:14 +02:00
Eladash daf43989fc Thread.h: Improve thread abort performance 2022-08-25 23:54:56 +03:00
Eladash c7586de280 Savestates/sys_fs: Fix saving encrypted and split-files file descriptors 2022-08-25 23:54:56 +03:00
Eladash 506b9deec5 Savestates/SPU LLVM: Improve saving performance 2022-08-25 23:54:56 +03:00
kd-11 1fc0191311 Fix build 2022-08-23 23:49:46 +03:00
kd-11 1f9e04f72d rsx/vk: Implement flushing surface cache blocks to linear mem 2022-08-23 23:49:46 +03:00
Eladash a71bdc761e SPU/Debugger: Improve debugging reservations
Simplify and make the debugging results more consistent.
2022-08-22 18:24:26 +03:00
Eladash 9d8f4d5cfa Bugfix after #12523 2022-08-22 18:24:26 +03:00
Eladash ee87fdc869 Fix GETLLAR spin detection 2022-08-22 08:33:22 +03:00
Eladash bf63a18c5f SPU Add ability to specify percentage of busy waiting 2022-08-21 15:02:01 +03:00
Eladash ddba30988b vm: Attempt to not remove cpu_flag::wait flag during access violation 2022-08-21 15:02:01 +03:00
Eladash b0e2c959eb SPU: Disable notification if no changes were made in PUTLLC 2022-08-21 15:02:01 +03:00
Eladash 28bec8e1bf SPU: Implement custom reservation condition in atomic wait 2022-08-21 15:02:01 +03:00
Eladash 86702186f2 PPU: Detect lwmutex reservation pattern and optimize it 2022-08-21 15:02:01 +03:00
Eladash 82b1a2bd7a SPU: add the concept of inaccurate reservations
Implement cellSpursRequestIdleSpu
2022-08-21 15:02:01 +03:00
Eladash d36cf71a2d Savestates: Fix PPU analysis when patches are applied 2022-08-21 15:02:01 +03:00
Eladash 1dd1062be1 PPU LLVM: Fix HLE function injection 2022-08-21 15:02:01 +03:00
Eladash c0e3b86064 SPU: Optimize spu_thread::get_events() 2022-08-21 15:02:01 +03:00
Eladash 6210a8491f SPU: Optimize and enable SPU GETLLAR Polling detection by default
* Make this setting guard all reservation waitings. (renamed)
* Revert atomic list usage: it's more expensive and not needed because it has a timeout and is not optimized for the rest of the waitables.
2022-08-21 15:02:01 +03:00
Eladash 33a4f05ffa SPU: Interleave loads/stores in reservation access utilities 2022-08-21 15:02:01 +03:00
Ani a74d3005f8 vk: Update FSR from 1.0 to 1.0.2 (#12538) 2022-08-20 17:37:42 +01:00
kd-11 bca833dad7 Fix surface reuse 2022-08-20 01:23:15 +03:00
kd-11 f981e05908 rsx: Do not lie about surface details 2022-08-20 01:23:15 +03:00
kd-11 b5abd777b0 rsx: Allow longer dispatch queues to accomodate games with high draw call count 2022-08-19 20:29:32 +03:00
Elad Ashkenazi b2c9add47e rsx: Fix semaphore timeout on boot
Allow semaphore timeout to be disabled again.
2022-08-19 15:40:20 +03:00
kd-11 a401a192b8 Fixup for dst_stage 2022-08-19 14:29:20 +03:00
kd-11 ad1b007dd1 Fix whitespace 2022-08-19 14:29:20 +03:00
kd-11 71e35c8b4d vk: Implement support for VK_EXT_attachment_feedback_loop_layout 2022-08-19 14:29:20 +03:00
kd-11 2e504b2dac rsx: Silence some warnings 2022-08-19 14:29:20 +03:00
Jan Beich 6e9df9e452 CI: upgrade FreeBSD to 13.1
FreeBSD doesn't support /latest and /quarterly package repos on EOL
versions. 13.0 reaches EOL on 2022-08-31, so avoid CI breakage.
2022-08-19 13:46:01 +03:00
Trevor Mack 8aa5899196 Update BUILDING.md
Updating the 'Configuring the Qt plugin' section with more details and for the new versions of the plugin.
2022-08-18 08:41:46 +02:00
Nekotekina b6608ad31d vm_native: rewrite win7 workaround 2022-08-15 12:26:17 +03:00
kd-11 edb39039dd Fix linux build 2022-08-14 23:53:50 +03:00
kd-11 bacf518189 rsx: Fix 2D intersection tests 2022-08-14 23:53:50 +03:00
kd-11 1244044647 util: Provide stack-trace utilities 2022-08-14 23:53:50 +03:00
kd-11 b960ce1426 vk: Align write length when pre-filling buffers with constant patterns 2022-08-14 23:53:50 +03:00
kd-11 c55a889c23 vk: Initialize buffer info blocks to avoid null descriptors 2022-08-14 23:53:50 +03:00
Megamouse 829af30568 evdev: add motion device 2022-08-14 11:04:57 +02:00
Eladash a3007e11ca SPU: Fix minor race in sys_spu_thread_receive_event
Check final cpu_state::state value for suspend state because that's the variable the thread waits on.
2022-08-12 15:20:48 +03:00
Eladash 9a981b5292 rsx_debugger: Fix memory leak 2022-08-12 15:20:48 +03:00
Eladash 4464a6c3f6 CG-Disasm: Name input/output vetex arrays 2022-08-12 15:20:48 +03:00
Eladash d30ac20fad Debugger: Fix and use centered PC by default
* Fix instruction-selection dependent functionality.
* Remove odd instruction position jumps in add/remove breakpoint.
* Make PC fixate at 1/3 of the frame because knowing future instructions is more important than knowing the previous.
2022-08-12 15:20:48 +03:00
Nekotekina 7bb2d94e53 vm: use sparse files to emulate overcommit memory
Fix shm::map_critical page flags.
2022-08-12 13:59:03 +03:00
Eladash 7ff4509858 sys_lwcond: Fix a loose notification in cond wait 2022-08-11 12:44:40 +03:00
Eladash f2997e4c00 LV2: Fix the most annoying race ever
Timeline of the race:
1. The PPU is in SLEEP state. state = suspend.
2. lv2_obj::awake is called on the traced thread and is now in ONPROC state, state = signal.
3. lv2_obj::awake is called by another thread externally with a priority higher than our traced thread and appends it to g_pending. state = suspend + signal.
4. lv2_obj::sleep/set_priority (higering priority) is called on any thread which is in ONPROC. Causing it to enter SLEEP or RUNNING state, while the traced thread is back in queue in ONPROC. state = suspend + signal.
5. The traced thread finally calls lv2_obj::awake on itself, g_pending decrements to 0 and we a have a rescheduling event, after XOR state = 0!!! (no signal)
6. In check_state: cpu_sleep_called is now true and remains this way.
7. Another thread with a higher prioty kicks in and appends the traced thread into g_pending. state = suspend.
8. The traced thread is at cpu_thread::cpu_wait(), and that's where it's gonna spend the rest of its life.
2022-08-11 12:44:40 +03:00
Eladash 133e9d4705 CPUThread.cpp: Fix cpu_flag::pending reset 2022-08-11 11:42:16 +03:00
Eladash 501ca4bcf5 logs: Prevent potential deadlock of the main thread in stack mode
If a thread logs faster than the GUI thread can print on screen.
2022-08-11 11:42:16 +03:00
Eladash 9212942724 kernel_explorer: Add info about ppu_thread::ack_suspend
The wording is bad but unless the emulation went downhill it shouldn't print on screen repeatedly.
2022-08-11 11:42:16 +03:00
Eladash 683c1a6512 LV2: Optimize sys_ppu_thread a bit 2022-08-11 11:42:16 +03:00
Eladash 9b0d33048c Savestates/LV2: Fix race on _sys_lwcond_queue_wait saving
cpu_flag::again modification requires exclusive access.
2022-08-11 11:42:16 +03:00
Eladash bc8bf2c329 sys_cond/lwcond: Fix waiting time in the debugger for mutex lock 2022-08-11 11:42:16 +03:00
Elad Ashkenazi f0002501f7 sys_mutex/lwmutex: Regression fixes after #12378 2022-08-11 11:42:16 +03:00
Elad Ashkenazi c4cc0154be LV2: Optimizations and fixes
Fix and optimize sys_ppu_thread_yield

Fix LV2 syscalls with timeout bug. (use ppu_thread::cancel_sleep instead)

Move timeout notification out of mutex scope

Allow g_waiting timeouts to be awaked in scope
2022-08-11 11:42:16 +03:00
shinra-electric cba4c3cdc4 [macOS] Update hid_pad_handler.cpp to prevent DS4 from disconnecting (#12493)
Prevents DS4 (and possibly DS3) from disconnecting from bluetooth after 15 minutes by using hidapi's non-exclusive mode. 
The most recent version of hidapi, 0.12 from two months ago, added "macOS-specific function(s) to open device(s) in non-exclusive mode".
2022-08-11 07:14:37 +02:00
kd-11 c51d3b5465 Workaround for msvc weirdness 2022-08-09 18:32:54 +03:00
kd-11 e179adc4a0 rsx: Refactor surface cache storage 2022-08-09 18:32:54 +03:00
Elad Ashkenazi 47f3740a70 System.cpp: Replace std::filesystem usage (#12474) 2022-08-08 05:46:32 +03:00
nastys 2880370047 Update MoltenVK (#12456) 2022-08-07 20:54:31 +01:00
kd-11 61a055a1c6 Tuning 2022-08-07 22:14:49 +03:00
kd-11 64b4cfa59f rsx: Erase surface background when reloading after a pitch mismatch 2022-08-07 22:14:49 +03:00
kd-11 c799ffd223 rsx: Stubs for pitch conversion 2022-08-07 22:14:49 +03:00
Eladash 2ec039365f shared_mutex: Optimize busy-waiting by detecting waiters and try to steal the notifying bit
Add an unused has_waiters() method.
2022-08-07 20:23:54 +03:00
Eladash 26e731b487 LV2: Re-add dropped optimization by previous commit
Currently only for lock-free syscalls.
2022-08-07 20:23:54 +03:00
Eladash 34bae90820 LV2: Move nearly all notifications out of all mutex scopes including IDM 2022-08-07 20:23:54 +03:00
Eladash b55a052a22 IdManager.h: Do not lock IDM mutex if the preliminary ID check failed
Optimizes common ESRCH failures. (lambda variants only atm)
2022-08-07 20:23:54 +03:00
Eladash 011aabe9ed LV2: Make sys_mutex and sys_lwmutex lock-free, add some busy waiting in sys_mutex_lock 2022-08-07 20:23:54 +03:00
Eladash a17a6527f6 LV2: Move memory unlocking outside of mutex ownership and make it conditional 2022-08-07 20:23:54 +03:00
Eladash 122c6256ca A fix of _spurs::add_workload 2022-08-07 20:23:54 +03:00
Eladash 73aaff1b29 LV2: allocation-free synchronization syscalls
* Show waiters' ID in kernel explorer.
* Remove deque dependency from sys_sync.h
2022-08-07 20:23:54 +03:00
Eladash c7fbc16357 SPU: Postpone notifications to afterward group mutex ownership 2022-08-07 20:23:54 +03:00
Eladash bc728db15b LV2: Add busy waiting before entering atomic wait 2022-08-07 20:23:54 +03:00
Eladash 2eebbd307d LV2: Minor optimization regarding signal flag 2022-08-07 20:23:54 +03:00
Eladash dc851a729e LV2: Postpone thread notifications to afterward mutex ownership(s) 2022-08-07 20:23:54 +03:00
Eladash 6007fd630f Do not use lv2_obj::g_waiting when not needed in sys_timer_usleep 2022-08-07 20:23:54 +03:00
Megamouse cb0ecb2afb cellPngEnc 2022-08-06 10:35:10 +02:00
sguo35 84a785ea67 arm64: implement pshufb intrinsic 2022-08-05 22:53:11 +02:00
sguo35 cc1e4d2194 ppu/arm64: don't restore rsp on ppu_gateway return
Don't restore rsp on ppu_gateway return, since it can be reentrant. Also
change some registers to align with the x86 version's 32bit/64bit
usages.
2022-08-05 22:53:11 +02:00
Megamouse b2d84dcebd Qt: Add save filtered log to menu of log viewer 2022-08-05 20:50:51 +02:00
Megamouse 958d77ba52 Qt: filter log viewer when opening a file 2022-08-05 20:50:51 +02:00
Megamouse c4b38869ab Input: fix pad initialization 2022-08-05 20:16:21 +02:00
Eladash fd1968dd22 Savestates: Save SFO directory path for PSN games 2022-08-05 19:19:16 +03:00
Elad Ashkenazi 88b80ebdf5 sys_net: Fix missing locks in some syscalls (#12459) 2022-08-04 21:31:34 +03:00
kd-11 2445ab8d8e Fix RSX capture playback 2022-08-04 19:01:45 +03:00
Elad Ashkenazi 0e1931f178 sys_lwcond: Fix rare race on mode 3 signal (#12413) 2022-08-04 14:13:51 +03:00
kd-11 3e923b4993 rsx: Optimize VTX_FMT_SNORM16 decoding
- Cuts down SNORM16 overhead by ~65%
2022-08-03 23:33:31 +03:00
kd-11 8181498d86 gl: Alias UBO/SSBO slots to avoid exceeding the available number of binding slots.
- The sets are different anyway and should not overwrite each other in a proper driver.
2022-08-03 23:33:31 +03:00
kd-11 57dd611111 gl: Fix incomplete stencil view of depth-stencil texture
- Samplers must use point sampling for stencil views
2022-08-03 23:33:31 +03:00
Eladash b3162bd41c rsx/vp: Fix SNORM16 vertex decoding 2022-08-03 18:11:46 +03:00
Elad Ashkenazi cd2adbad9a Update rsx_methods.cpp 2022-08-03 17:15:59 +03:00
Elad Ashkenazi 99730ac4f9 Update rsx_methods.cpp 2022-08-03 17:15:59 +03:00
Elad Ashkenazi d2ab3383ad Update rsx_methods.cpp 2022-08-03 17:15:59 +03:00
Elad Ashkenazi 3b15a6b39e Update rsx_methods.cpp 2022-08-03 17:15:59 +03:00
Elad Ashkenazi 651e58f443 rsx: Trivial optimization 2022-08-03 17:15:59 +03:00
Eladash 769f9e33e9 Savestates/RSX: Fix fifo_control::restore_state 2022-08-03 15:35:41 +03:00
Eladash cf77bb7cfc Savestates/MSVC: Replace bugged std::unique (compiler bug) 2022-08-03 15:35:41 +03:00
Megamouse c75b76ddf5 cellPhotoImport: fallback to extension if sub_type is unknown 2022-08-02 01:43:23 +02:00
Megamouse 4dec8d7925 cellPhotoImport: allow dev_hdd1 2022-08-02 01:43:23 +02:00
Megamouse 934e7b614c cellPhotoExport/cellVideoExport: fix filenames 2022-08-02 01:43:23 +02:00
Megamouse 416b14de72 cellPhotoExport: first implementation 2022-08-01 19:11:14 +02:00
Megamouse b87099c790 cellVideoExport: fix some copy pasta errors and prevent file overwrite 2022-08-01 19:11:14 +02:00
kd-11 052725fdc7 rsx: Do not require ZCULL buffer binding to enable ZPASS counting
- ZPASS data is still accessible in unbuffered mode.
  The only thing that buffered ZCULL enables is something closer to early-Z where large blocks of pixels can be dicarded earlier.
  It is strictly a performance optimization and not required for ZPASS to work.
- Update ZCULL stat calculations to take into account unbuffered Z
2022-08-01 00:23:54 +03:00
Megamouse f90b79791f HLE: fix file not found errors in media functions 2022-07-31 16:45:05 +02:00
RipleyTom 4c32c95b33 Enable wolfssl fast-math option (#12427) 2022-07-30 18:19:19 +01:00
Megamouse c00d47cc99 Update wolfssl to v5.4.0-stable 2022-07-30 14:33:14 +02:00
Megamouse ea53c7dc85 Update curl to curl-7_84_0 2022-07-30 14:33:14 +02:00
Megamouse 2b923c681e Update FAudio to 22.07 2022-07-30 14:33:14 +02:00
Elad Ashkenazi 7a8e918519 Update System.cpp 2022-07-30 08:33:09 +02:00
Elad Ashkenazi d99ae3809d Update keyboard_pad_handler.cpp 2022-07-29 13:45:19 +02:00
Malcolm Jestadt 51e6d0a336 SPU LLVM: Add integer compare optimization for FCMGT 2022-07-29 11:59:59 +03:00
Megamouse 228844c017 overlays: fix line wrapping and position of lines
- Fix off by one issue when we wrapping a line caused by unnecessary zeroed whitespaces.
- Fix centering of lines that end with carriage return caused by overzealous reset of counters.
- Remove fabs where there shouldn't be any
2022-07-29 09:26:45 +02:00
Megamouse 87e628a9e9 cellPhotoDecode: optimize get_scaled_image 2022-07-29 08:05:35 +02:00
Megamouse e6885e25b5 Qt: fix image ratio in screenshot_manager_dialog 2022-07-29 03:14:29 +02:00
Megamouse f31ffc4596 Implement cellPhotoDecode 2022-07-28 09:06:48 +02:00
Megamouse 4114f00c05 cellPhotoImport: fix vfs path and add some logging 2022-07-28 09:06:48 +02:00
Megamouse 8f7209f886 cellMusicSelectionContext: fix log message facepalm 2022-07-27 07:39:55 +02:00
Megamouse d80146c704 cellMusic: Fix resume, fast forward and rewind
- Sadly rewind does not work with the QMediaPlayer on windows
2022-07-27 07:39:55 +02:00
Megamouse 577f379a12 implement cellPhotoImport 2022-07-26 17:27:35 +02:00
Megamouse 3d73915358 cellSearch: improve populate_photo_info, read image headers 2022-07-26 17:27:35 +02:00
Megamouse a5317d50a5 cellMusicSelectionContext: log playlist 2022-07-26 17:27:35 +02:00
MSuih 143bd6cc80 Fix typo in tooltips.h 2022-07-25 21:28:24 +02:00
MSuih 5cc8f970c0 Fix minor issues with issue templates 2022-07-25 21:28:24 +02:00
kd-11 c9058280e0 vk: Fix a potential deadlock 2022-07-25 21:05:31 +03:00
kd-11 5af50cfd55 vk: Handle corner cases
- Fix up flush sequence in DMA handling (WCB)
- Do not request resource sharing if queue family is not different!
2022-07-25 21:05:31 +03:00
kd-11 d846142f0c vk: Reimplement compliant async texture streaming
- Use CONCURRENT queue access instead of fighting with queue acquire/release via submit chains.
  The minor benefits of forcing EXCLUSIVE mode are buried under the huge penalty of multiple vkQueueSubmit.
  Batching submits does not help alleviate this situation. We simply must avoid interrupting execution.
2022-07-25 21:05:31 +03:00
Elad Ashkenazi 0ba0f9d2b9 Disable Disc update redirection for manual ELF loader (#12381) 2022-07-22 20:35:15 +02:00
Elad Ashkenazi f4f9c1865e Savestates: Implement compatibility with disc Demon's Souls (#12379)
* Savestates: Implement compatibility with virtual /dev_bdvd/PS3_GAME
2022-07-22 19:23:23 +03:00
Megamouse c40439ae6b cellMusic/Decode: implement playlist shuffle and repeat 2022-07-22 08:42:43 +02:00
Megamouse 683fa2a392 Mount custom dev_bdvd if a disc game was mounted from dev_hdd0 2022-07-22 07:36:49 +02:00
kd-11 246bf1df64 Use C++17 ctor for string_view 2022-07-21 22:29:40 +03:00
kd-11 9a868e9239 gl: Silence compiler warning 2022-07-21 22:29:40 +03:00
kd-11 ab3cde1939 gl: Do some macro patching for intel driver 2022-07-21 22:29:40 +03:00
kd-11 bec3e156fb vk: Disable robust buffer access for ANV
- Robust access is nice, but we don't actually need it
2022-07-21 22:29:40 +03:00
Megamouse 086afbbaa5 overlays: implement back and focus in media_list_dialog 2022-07-21 01:36:33 +02:00
Megamouse cd4d73114c overlays: fix media_list_dialog title 2022-07-21 01:36:33 +02:00
Megamouse 14ca506774 Qt/savedata: use rsx overlays selection_code 2022-07-21 01:36:33 +02:00
MSuih 984bf67d84 Replace issue templates with issue forms (#12373) 2022-07-20 20:22:12 +01:00
Eladash 2b3ae8b638 Revert another change 2022-07-20 18:11:52 +03:00
Eladash bb9ae18c71 Savestates: Fix sys_rwlock_wunlock saving 2022-07-20 18:11:52 +03:00
Eladash ce01457510 Fix futile wait regression in sys_lwcond_signal 2022-07-20 18:11:52 +03:00
Megamouse d1a46b491e cellMusic: add some error checks and copy context to callback 2022-07-20 07:09:38 +02:00
Elad Ashkenazi 31df99f7d6 Logs: Flush unreported errors when turning off Stack Cell errors (#12366) 2022-07-19 17:05:51 +02:00
Eladash 5e11b2b056 log_frame: Minor fix for stack mode 2022-07-19 10:43:51 +03:00
Eladash d106934336 Savestates: Fix saving sys_mutex_unlock 2022-07-19 10:43:51 +03:00
Eladash 68718361a7 Allow non-existing paths in vfs::retrieve 2022-07-19 10:43:51 +03:00
Eladash c887865d54 Perform cleanup after Emulator::Load failures 2022-07-19 10:43:51 +03:00
Eladash dc48944979 Prefer BDVD over HDD0 in vfs::retrieve 2022-07-19 10:43:51 +03:00
Eladash d22b8b1d3a Savestates: Do not restart after Ctrl+S for now 2022-07-19 10:43:51 +03:00
Eladash 56619b20cf Savestates: savestate reload fix 2022-07-19 10:43:51 +03:00
Eladash 12ebf77e22 Savestates: save sys_spu_initialize settings 2022-07-19 10:43:51 +03:00
Megamouse 845af8bd96 cellGifDec: random stuff because I was bored 2022-07-18 22:23:25 +02:00
kd-11 680f08c2b8 gl: Destroy barrier signals correctly 2022-07-18 18:58:22 +03:00
kd-11 82bac4173e gl: Reuse scratch images 2022-07-18 18:58:22 +03:00
kd-11 8a8fda3e02 gl: Combine RGBA8/D24S8 readback and byteswap into one operation 2022-07-18 18:58:22 +03:00
kd-11 1c5b685398 gl: Only toggle state settings that are relevant to the current RSX state 2022-07-18 18:58:22 +03:00
kd-11 e95084f138 gl: Use DSA for imageview configuration and avoid needless bind operations 2022-07-18 18:58:22 +03:00
kd-11 e12d268662 gl: Implement support for texture1D decode 2022-07-18 18:58:22 +03:00
kd-11 6a3f17cd36 gl: Fix compute invocation counts for format handling code 2022-07-18 18:58:22 +03:00
Erik S. V. Jansson db0774a81b Fix spirv/glslang.vcxproj build to support spaces.
e.g. cloning into D:\Source Code\C++\rpcs3 will cause spirv and glslang
to error during MSBuild. All other parts of rpcs3 compile fine so these
are probably the only places which fail when the project is placed in a
path with spaces in it. I've at least been able to compile + run rpcs3.
2022-07-18 01:27:56 +03:00
Megamouse 34615d3a74 cellMic: slow down if no mics are configured 2022-07-17 19:31:05 +02:00
Zion Nimchuk 189499c10b Fix shellcheck errors 2022-07-17 15:14:02 +03:00
Zion Nimchuk de613a8a98 Docker version bump 2022-07-17 15:14:02 +03:00
Eladash c0369b2e10 sys_net: Implement sys_net_abort 2022-07-17 14:53:03 +03:00
Megamouse 07ebbb6c84 cellSysutilAvc2SetStreamingTarget: remove ensure 2022-07-16 20:09:13 +02:00
sguo35 73ed657e00 spu/arm64: fix 16 byte branch patch alignment 2022-07-15 12:37:33 +03:00
sguo35 b37217b181 windows: fix build for asmjit update 2022-07-15 12:37:33 +03:00
sguo35 b02e6e222f arm64: enable fma and "avx" on Apple and Cortex CPUs 2022-07-15 12:37:33 +03:00
sguo35 c52abed4d3 spu: implement ubertrampoline generator for arm64
Implement the ubertrampoline generator for arm64. It generally follows
the x86 version, but uses asmjit to generate code instead of writing raw
opcodes to memory, trading memory usage for readability. Currently the
trampoline implementation is fairly inefficient in terms of instruction
size and is substantially larger than the x86 version.
2022-07-15 12:37:33 +03:00
sguo35 9e57efe82c spu: implement assembly functions for arm64 2022-07-15 12:37:33 +03:00
sguo35 77ab872bec spu: remove rotqby C++ impl
rotqby C++ implementation is broken, since replacing it with the
intrinsic version reliably fixes spurs test. A conditional branch
immediately after a rotqby instruction will fail using the C++ version
but succeed using the intrinsic.
2022-07-15 12:37:33 +03:00
sguo35 27acebc5f5 spu: use portable llvm recompiler on arm64
Since there is not yet an arm64 version of the assembly (fast) version.
2022-07-15 12:37:33 +03:00
sguo35 2755d9941c ppu: fix a bug where arm64 sp wasn't being saved
ASMJIT can silently fail and drop instructions when invalid operations
are performed (e.g. loading/storing sp). Explicitly move sp to a gp
register before doing loads/stores to fix this.
2022-07-15 12:37:33 +03:00
sguo35 488982f424 spu: external function calls should be marked non-tail
Mark external function calls as non-tail, since they aren't tail calls
and assuming they are will cause returns to fail in Arm64 GHC CC.
2022-07-15 12:37:33 +03:00
sguo35 086e12c6ca mac: mmap calls should initialize with r/w page perms
Mac/Arm64 pages should be R/W by default due to 16k page
incompatibility. Without this there will be segfaults due to invalid
permissions.
2022-07-15 12:37:33 +03:00
sguo35 9b19f16698 arm64: add optimized 16byte ld/st for armv8.4a+
16B ldp/stp are atomic on v8.4a+. See Arm Architecture Reference Manual,
"Changes to single-copy atomicity in Armv8.4". Add load/release atomic
impls for this instruction and add detection for 8.4a+ capability.
2022-07-15 12:37:33 +03:00
sguo35 b13fd68848 [3rdparty] update asmjit dependency 2022-07-15 12:37:33 +03:00
Eladash 3e51426379 Savestates/SPU: Kill emulation when its safe to save SPU state 2022-07-15 09:30:53 +03:00
Megamouse 105781fa76 overlays: properly align lines with leading or trailing whitespace 2022-07-14 23:32:20 +02:00
Megamouse d2be12bb07 overlays: find missing characters lost during wrapped rendering 2022-07-14 23:32:20 +02:00
Megamouse fdc15e12c4 overlays: properly calculate offsets for wrapped text 2022-07-14 23:32:20 +02:00
Eladash e548743cbf Fixup rsx cpatures 2022-07-14 18:50:31 +03:00
Megamouse 7499f875a6 cellCrossControllerInitialize: add dialog 2022-07-13 19:12:46 +02:00
kd-11 cdef752a9c gl: Fix 2D->3D splat in CopyBufferToImage 2022-07-13 02:09:58 +03:00
kd-11 1483941bea gl: Implement row alignment in CopyBufferToImage routines 2022-07-13 02:09:58 +03:00
kd-11 9cc15be7f2 Fix linux build 2022-07-13 02:09:58 +03:00
kd-11 453e1bfaec gl: Silence compiler warning 2022-07-13 02:09:58 +03:00
kd-11 82439327fa gl: Support loading data from SSBO using compute shaders
- Gives better performance than using raw draw calls.
- Does not work with all formats. The draw call version is still used when needed.
2022-07-13 02:09:58 +03:00
kd-11 f60002e87d gl: Optimize memory barriers a bit
- Move waits to server side
- Increase the scratch buffer size to avoid waiting on barriers
2022-07-13 02:09:58 +03:00
kd-11 9fc6382909 gl: Finalize BGRA storage format internals
- Performance is terrible but it works properly now
2022-07-13 02:09:58 +03:00
kd-11 ebad08aa97 gl: Fix image creation for virtual formats 2022-07-13 02:09:58 +03:00
kd-11 599f1dd157 gl: Properly match BGRA RTT formats 2022-07-13 02:09:58 +03:00
kd-11 bb5ce67d57 gl: Handle corner cases for CopyBufferToImage
- Handle 3D textures and cubemaps
- Handle writing to mip > 0
2022-07-13 02:09:58 +03:00
kd-11 f948ce399e gl: Implement CopyBufferToImage in software
- Overrides the drivers CopyBufferToImage handling where possible
2022-07-13 02:09:58 +03:00
kd-11 954c60947d gl: Avoid calling gl functions without a context even if the object is GL_NONE
- While calling glDestroyXXXX with GL_NONE is a no-op, calling it without a context will crash some drivers.
2022-07-13 02:09:58 +03:00
kd-11 98b6783c05 gl: Fix image views broken after refactor 2022-07-13 02:09:58 +03:00
kd-11 0894d2886a Fix build 2022-07-13 02:09:58 +03:00
kd-11 4995b4abe3 gl: Do not use raw GL image copy command for RSX data 2022-07-13 02:09:58 +03:00
kd-11 35ef19cfc8 gl: Refactor the rest of GLHelpers 2022-07-13 02:09:58 +03:00
kd-11 09824a718f gl: Separate BGRA8 storage from RGBA8 2022-07-13 02:09:58 +03:00
Megamouse f4e85af53c sceNpUtil: implement skeleton bandwidth test 2022-07-12 22:45:40 +02:00
Eladash 74a909cfbc logs: Batch log messages (optimization) 2022-07-12 21:37:06 +02:00
Eladash 0bfdfd8433 Savestates: Implement Ctrl+R to reload the most recent savestate
Ctrl+R no longer means Resume emulation, this functionality has been transferred to Ctrl+P which is also capable of pausing the emulation. (so it's now a toggle)
2022-07-12 15:15:42 +03:00
Eladash 1f5cf776b2 Savestates: Fix "Suspend Emulation Savestate Mode" setting 2022-07-12 15:15:42 +03:00
Eladash cdd6840826 Savestates/SPU: Complete fix for saving sys_spu_thread_receive_event 2022-07-12 15:15:42 +03:00
Eladash ab27ee4cf4 Savestates/RSX: Save NV406E semaphore waiting 2022-07-12 15:15:42 +03:00
Eladash 6211295155 atomic.hpp: Truncation warning fix 2022-07-12 15:15:42 +03:00
Eladash befd7ceb89 Savestates/sys_spu: Minor fix in saving sys_spu_thread_receive_event 2022-07-10 14:19:59 +03:00
Eladash 2cead6f328 Savestates/SPU: Fix saving sys_spu_thread_send_event 2022-07-10 14:19:59 +03:00
Eladash 4e3d58f75a Savestates: Fix crash when savestating before PPU/SPU compilation finishes
Unintentional concurrent access to m_ar ptr itself.
2022-07-10 14:19:59 +03:00
Eladash 24fddf1ded rsx: Fix emu stopping crash when using multi-threaded rsx
FXO signaled abort before it completed its work, leading to unsignalled vk::fence and deadlock. Fix it by deregistering it from FXO.
2022-07-10 14:19:59 +03:00
Eladash 87cd65ff03 Savestates: support game collections 2022-07-10 14:19:59 +03:00
Eladash 219e3d61f8 Minor fix in shm::map_critical 2022-07-10 14:19:59 +03:00
Eladash 4ade06f36f Savestates/RSX: Restore the ZCULL control state
And fix the ZCULL control state at the initial state of RSX.
2022-07-10 14:19:59 +03:00
Nekotekina 786510a937 Use gettid() on Linux, don't use std::thread::id
pthread_self() returns a large opaque pointer which is harder to use.
2022-07-10 12:22:28 +03:00
Megamouse 0c6df39a45 cellSearch: more error checks and shuffle 2022-07-09 16:39:10 +02:00
Vestrel 648ad0cd90 cellAudio: fix downmix if device doesn't support multichannel (#12328)
* cellAudio: fix downmix if device doesn't support multichannel
* Downmix in 2 stages
2022-07-09 15:25:28 +02:00
Megamouse cd0d43382f Qt: fix custom settings audio device corruption 2022-07-08 23:56:10 +02:00
Vestrel 98b730c806 Audio: device switching and channel count detection (#12246) 2022-07-08 17:13:38 +02:00
Nekotekina 4b787b22c8 Implement FN (lambda shortener)
Useful for some higher order functions.
Allows to make short lambdas even shorter.
2022-07-08 14:47:41 +03:00
Nekotekina 5c6f5a1610 Cleanse LOG_CONSTINIT macro
Should be unnecessary.
2022-07-08 14:47:41 +03:00
Eladash 0b8d5f7b98 Savestates: Fix argv 2022-07-08 12:57:43 +03:00
Eladash 314d481dcd Savestates: Fix typo in page size setting 2022-07-08 12:57:43 +03:00
Eladash 0980c68e6f Savestates: Increase timeout for emulation stopping 2022-07-08 12:57:43 +03:00
Eladash 983bfa2088 Savestates: Decryption of executable fix 2022-07-08 12:57:43 +03:00
Eladash 3a9928de65 Savestates: Log file descriptor information 2022-07-08 12:57:43 +03:00
Eladash 1fd5fb2f7e Savestates: Fix minor race with LV2 timers 2022-07-08 12:57:43 +03:00
Eladash 4ac88fa8d3 Savestates/RSX: Save drawing context 2022-07-08 12:57:43 +03:00
Eladash 5f8f9e33f1 RSX/Savestates: Replace GCM hack with a proper fix 2022-07-08 12:57:43 +03:00
Eladash f0c71ae2ae Savestates: Fix saving sys_event_queue_destroy 2022-07-08 12:57:43 +03:00
Megamouse 0c7ecdc954 cellMusicDecode: add more error checks and silence some log messages 2022-07-08 07:55:46 +02:00
Elad Ashkenazi 73a687df7d Savestates/Not Savestates: Fix exitspawn to HDD0 executable with mounted BDVD 2022-07-07 21:59:39 +02:00
Megamouse b683110e72 cellGem/overlays: show cursor if necessary 2022-07-07 12:40:23 +02:00
Megamouse 3840015e7d cellGem: implement basic ds3 cursor movement 2022-07-06 21:49:31 +02:00
Megamouse 639b8112b6 Input: make move handler dynamic 2022-07-06 21:49:31 +02:00
Megamouse 2bf17f5d3c input: fix horrible pad hacks 2022-07-06 21:49:31 +02:00
Megamouse 4823d4c32a input: add background input option
Adds an option to disable background input to the IO tab in the settings dialog.
This will disable pad input as well as ps move and overlays input when the window is unfocused.
2022-07-06 21:49:31 +02:00
Eladash c8c035eeef Regression fix 2022-07-06 20:07:09 +02:00
Eladash 155bd09fd0 Savestates: Cleanup v128 usage
It's compatible with bitwise serialization so it is faster to load/save it this way.
2022-07-06 19:43:25 +03:00
Eladash f546e5a8ef VM/Savestates: Replace bugged read-only block optimization 2022-07-06 19:43:25 +03:00
Eladash 2ccb0c8f42 SPU LLVM/Savestates: Remove unneeded store insurance and add related fix 2022-07-06 19:43:25 +03:00
Eladash 05303ce6c6 GUI: regression fix
Improperly resolved git conflict when rebasing savestates.
2022-07-06 19:43:25 +03:00
Eladash d8f3029952 Log LV2 periodic timers 2022-07-06 19:43:25 +03:00
Eladash 09c28f75b3 Savestates: Fix LV2 timers (fixes audio in some games) 2022-07-06 19:43:25 +03:00
Eladash 57671e267d Savestates: save cellAudioOut 2022-07-06 19:43:25 +03:00
Eladash b692108f1e Savestates: HLE state saving POC in sys_lwmutex 2022-07-06 19:43:25 +03:00
Eladash 2815aecd0c Savestates: Save SPU decrementer state 2022-07-06 19:43:25 +03:00
Megamouse b9f2b1e7c6 Qt: add UUID reset button 2022-07-05 09:09:00 +02:00
Eladash bd9ba7ef1f Remove incorrect Emu.IsStopped() checks 2022-07-05 08:25:36 +02:00
Eladash a015bd1ebd Savestates: Add missing position placement 2022-07-05 08:25:36 +02:00
Eladash d6cf167d52 Savestates: Minor optimization of size 2022-07-05 08:25:36 +02:00
Eladash 3fc2194fd5 Savestates: Fix zombie PPU threads saving 2022-07-05 08:25:36 +02:00
Eladash 72c14994f0 Savestates: Fix memory containers initialization (invalidates old savestates) 2022-07-05 08:25:36 +02:00
kd-11 fddb6a31a7 Use utils::c_page_size 2022-07-04 22:35:05 +03:00
kd-11 278ae7763a Use better macro notation 2022-07-04 22:35:05 +03:00
kd-11 5cafaef0a9 Aarch64 fixes for RSX 2022-07-04 22:35:05 +03:00
Elad Ashkenazi fcd297ffb2 Savestates Support For PS3 Emulation (#10478) 2022-07-04 16:02:17 +03:00
566 changed files with 34326 additions and 12611 deletions
+11 -11
View File
@@ -1,9 +1,9 @@
#!/bin/sh -ex
# Setup Qt variables
export QT_BASE_DIR=/opt/qt${QTVERMIN}
export PATH=$QT_BASE_DIR/bin:$PATH
export LD_LIBRARY_PATH=$QT_BASE_DIR/lib/x86_64-linux-gnu:$QT_BASE_DIR/lib
export QT_BASE_DIR=/opt/qt"${QTVERMIN}"
export PATH="$QT_BASE_DIR"/bin:"$PATH"
export LD_LIBRARY_PATH="$QT_BASE_DIR"/lib/x86_64-linux-gnu:"$QT_BASE_DIR"/lib
if [ -z "$CIRRUS_CI" ]; then
cd rpcs3 || exit 1
@@ -23,19 +23,19 @@ mkdir build && cd build || exit 1
if [ "$COMPILER" = "gcc" ]; then
# These are set in the dockerfile
export CC=${GCC_BINARY}
export CXX=${GXX_BINARY}
export CC="${GCC_BINARY}"
export CXX="${GXX_BINARY}"
export LINKER=gold
# We need to set the following variables for LTO to link properly
export AR=/usr/bin/gcc-ar-$GCCVER
export RANLIB=/usr/bin/gcc-ranlib-$GCCVER
export AR=/usr/bin/gcc-ar-"$GCCVER"
export RANLIB=/usr/bin/gcc-ranlib-"$GCCVER"
export CFLAGS="-fuse-linker-plugin"
else
export CC=${CLANG_BINARY}
export CXX=${CLANGXX_BINARY}
export CC="${CLANG_BINARY}"
export CXX="${CLANGXX_BINARY}"
export LINKER=lld
export AR=/usr/bin/llvm-ar-$LLVMVER
export RANLIB=/usr/bin/llvm-ranlib-$LLVMVER
export AR=/usr/bin/llvm-ar-"$LLVMVER"
export RANLIB=/usr/bin/llvm-ranlib-"$LLVMVER"
fi
export CFLAGS="$CFLAGS -fuse-ld=${LINKER}"
+1 -1
View File
@@ -13,7 +13,7 @@ if [ "$DEPLOY_APPIMAGE" = "true" ]; then
ls ./appdir/usr/lib/
rm -r ./appdir/usr/share/doc
cp "$(readlink -f /lib/x86_64-linux-gnu/libnsl.so.1)" ./appdir/usr/lib/libnsl.so.1
export PATH=/rpcs3/build/squashfs-root/usr/bin/:${PATH}
export PATH=/rpcs3/build/squashfs-root/usr/bin/:"${PATH}"
# Embed newer libstdc++ for distros that don't come with it (ubuntu 16.04)
mkdir -p appdir/usr/optional/ ; mkdir -p appdir/usr/optional/libstdc++/
+1 -1
View File
@@ -14,7 +14,7 @@ echo "AVVER=$AVVER" >> ../.ci/ci-vars.env
cd bin
mkdir "rpcs3.app/Contents/lib/"
cp "/usr/local/opt/llvm@13/lib/libc++abi.1.0.dylib" "rpcs3.app/Contents/lib/libc++abi.1.dylib"
cp "/usr/local/opt/llvm@13/lib/c++/libc++abi.1.0.dylib" "rpcs3.app/Contents/lib/libc++abi.1.dylib"
rm -rf "rpcs3.app/Contents/Frameworks/QtPdf.framework" \
"rpcs3.app/Contents/Frameworks/QtQml.framework" \
"rpcs3.app/Contents/Frameworks/QtQmlModels.framework" \
+2 -2
View File
@@ -61,7 +61,7 @@ windows_task:
linux_task:
container:
image: rpcs3/rpcs3-ci-bionic:1.3
image: rpcs3/rpcs3-ci-bionic:1.5
cpu: 4
memory: 16G
env:
@@ -108,7 +108,7 @@ freebsd_task:
matrix:
- name: Cirrus FreeBSD
freebsd_instance:
image_family: freebsd-13-0
image_family: freebsd-13-1
cpu: 8
memory: 8G
env:
+1 -1
View File
@@ -21,7 +21,7 @@ Cpp11BracedListStyle: true
IndentCaseLabels: false
SortIncludes: false
ReflowComments: true
AlignConsecutiveAssignments: true
AlignConsecutiveAssignments: false
AlignTrailingComments: true
AlignAfterOpenBracket: DontAlign
ConstructorInitializerAllOnOneLineOrOnePerLine: false
@@ -1,66 +0,0 @@
---
name: Regression report
about: If something used to work before, but now it doesn't
title: ''
labels: ''
assignees: ''
---
## Please do not ask for help or report compatibility regressions here, use [RPCS3 Discord server](https://discord.me/RPCS3) or [forums](https://forums.rpcs3.net/) instead.
## Quick summary
Please briefly describe what has stopped working correctly.
## Details
Please describe the regression as accurately as possible.
#### 0. Make sure you're running with settings as close to default as possible
* **Do NOT enable any emulator game patches when reporting issues**
* Only change settings that are required for the game to work
#### 1. Please provide _exact_ build (or commit) information that introduced the regression you're reporting.
* Please see [How to find the build that caused a regression](https://wiki.rpcs3.net/index.php?title=Help:Using_different_versions_of_RPCS3#How_to_find_the_build_that_caused_a_regression.3F) in our wiki.
* You can find [History of RPCS3 builds](https://rpcs3.net/compatibility?b) here.
#### 2. Please attach TWO logs:
* One for the build with regression.
* One for the build that works as expected.
##### How to obtain RPCS3's log:
* Run the game until you find the regression.
* Completely close RPCS3, or move to the next step in case it has crashed.
* Locate RPCS3's log file:
+ ```RPCS3.log``` (It can show up as just RPCS3 and have a notepad icon)
or
+ ```RPCS3.log.gz``` (It can show up as RPCS3.log and have a zip or rar icon)
![image](https://user-images.githubusercontent.com/44116740/84433247-aa15fa80-ac36-11ea-913e-6fe25a1d040e.png)
On Linux it will be in ```~/.cache/rpcs3/```.
On Windows it will be near the executable.
* Attach the log:
+ Drag and drop your log file into the issue.
+ Or upload it to the cloud, such as Dropbox, Mega etc.
#### 3. If you describe graphical regression, please provide an RSX capture and a RenderDoc capture that demonstrate it.
* To create an RSX capture, use _Create_ _RSX_ _Capture_ under _Utilities_.
Captures will be stored in RPCS3 folder → captures.
+ Compress your capture with 7z, Rar etc.
And drag and drop it into the issue.
+ Or upload it to the cloud, such as Dropbox, Mega etc.
* To create a RenderDoc capture, please refer to [RenderDoc's documentation](https://renderdoc.org/docs/how/how_capture_frame.html).
#### 4. Please attach screenshots of your problem.
* Enable performance overlay with at least medium level of detail.
You can find it in _Emulator_ tab in _Settings_.
#### 5. Please provide comparison with real PS3.
#### 6. Please provide your system configuration:
* OS
* CPU
* GPU
* Driver version
* etc.
#### Please include.
* Anything else you deem to be important
@@ -0,0 +1,93 @@
name: Regression report
description: If something used to work before, but now it doesn't
title: "[Regression] Enter a title here"
labels: []
body:
- type: markdown
attributes:
value: |
# Summary
Please do not ask for help or report compatibility regressions here, use [RPCS3 Discord server](https://discord.me/RPCS3) or [forums](https://forums.rpcs3.net/) instead.
- type: textarea
id: quick-summary
attributes:
label: Quick summary
description: Please briefly describe what has stopped working correctly.
validations:
required: true
- type: textarea
id: details
attributes:
label: Details
description: Please describe the regression as accurately as possible. Include screenshots if neccessary.
validations:
required: false
- type: markdown
attributes:
value: |
# Identify the regressed build
Please provide the _exact_ build (or commit) information that introduced the regression you're reporting.
* Please see [How to find the build that caused a regression](https://wiki.rpcs3.net/index.php?title=Help:Using_different_versions_of_RPCS3#How_to_find_the_build_that_caused_a_regression.3F) in our wiki.
* You can find [History of RPCS3 builds](https://rpcs3.net/compatibility?b) here.
Make sure you're running with settings as close to default as possible
* **Do NOT enable any emulator game patches when reporting issues**
* Only change settings that are required for the game to work
- type: input
id: regressed-build
attributes:
label: Build with regression
description: Provide _exact_ build (or commit) information that introduced the regression you're reporting.
placeholder: v0.0.23-13948-31df99f7
validations:
required: true
- type: markdown
attributes:
value: |
# Log files
Obtaining the log file:
* Run the game until you find the regression.
* Completely close RPCS3 and locate the log file.
RPCS3's Log file will be ```RPCS3.log.gz``` (sometimes shows as RPCS3.log with zip icon) or ```RPCS3.log``` (sometimes shows as RPCS3 wtih notepad icon).
* On Windows it will be in the RPCS3 directory near the executable
* On Linux it will be in ```~/.cache/rpcs3/```
* On MacOS it will be in ```~/Library/Caches/rpcs3```. If you're unable to locate it copy paste the path in Spotlight and hit enter.
- type: textarea
id: logs
attributes:
label: Attach two log files
description: |
Attach one file for the build with regression and another for a build that works.
Drag & drop the files into this input field, or upload them to another service (f.ex. Dropbox, Mega) and provide a link.
validations:
required: true
- type: markdown
attributes:
value: |
# Other details
If you describe a graphical regression, please provide an RSX capture and/or a RenderDoc capture that demonstrate it.
* To create an RSX capture, use _Create_ _RSX_ _Capture_ under _Utilities_.
* Captures will be stored in RPCS3 folder → captures.
* To create a RenderDoc capture, please refer to [RenderDoc's documentation](https://renderdoc.org/docs/how/how_capture_frame.html).
- type: textarea
id: captures
attributes:
label: Attach capture files for visual issues
description: Compress your capture with 7z, Rar etc. and attach it here, or upload it to the cloud (Dropbox, Mega etc) and add a link to it.
validations:
required: false
- type: textarea
id: system-info
attributes:
label: System configuration
description: Provide information about your system, such as operating system, CPU and GPU model, GPU driver version and other information that describes your system configuration.
validations:
required: false
- type: textarea
id: other-details
attributes:
label: Other details
description: Include anything else you deem to be important.
validations:
required: false
-59
View File
@@ -1,59 +0,0 @@
---
name: Bug report
about: If something doesn't work correctly in RPCS3
title: ''
labels: ''
assignees: ''
---
## Please do not ask for help or report compatibility regressions here, use [RPCS3 Discord server](https://discord.me/RPCS3) or [forums](https://forums.rpcs3.net/) instead.
## Quick summary
Please briefly describe what is not working correctly.
## Details
Please describe the problem as accurately as possible.
#### 0. Make sure you're running with settings as close to default as possible
* **Do NOT enable any emulator game patches when reporting issues**
* Only change settings that are required for the game to work
#### 1. Please attach RPCS3's log.
* Run the game until you find the issue.
* Completely close RPCS3, or move to the next step in case it has crashed.
* Locate RPCS3's log file:
+ ```RPCS3.log``` (It can show up as just RPCS3 and have a notepad icon)
or
+ ```RPCS3.log.gz``` (It can show up as RPCS3.log and have a zip or rar icon)
![image](https://user-images.githubusercontent.com/44116740/84433247-aa15fa80-ac36-11ea-913e-6fe25a1d040e.png)
On Linux it will be in ```~/.cache/rpcs3/```.
On Windows it will be near the executable.
* Attach the log:
+ Drag and drop your log file into the issue.
+ Or upload it to the cloud, such as Dropbox, Mega etc.
#### 2. If you describe graphical issue, please provide an RSX capture and a RenderDoc capture that demonstrate it.
* To create an RSX capture, use _Create_ _RSX_ _Capture_ under _Utilities_.
Captures will be stored in RPCS3 folder → captures.
+ Compress your capture with 7z, Rar etc.
And drag and drop it into the issue.
+ Or upload it to the cloud, such as Dropbox, Mega etc.
* To create a RenderDoc capture, please refer to [RenderDoc's documentation](https://renderdoc.org/docs/how/how_capture_frame.html).
#### 3. Please attach screenshots of your problem.
* Enable performance overlay with at least medium level of detail.
You can find it in _Emulator_ tab in _Settings_.
#### 4. Please provide comparison with real PS3.
#### 5. Please provide your system configuration:
* OS
* CPU
* GPU
* Driver version
* etc.
#### Please include.
* Anything else you deem to be important
+78
View File
@@ -0,0 +1,78 @@
name: Bug report
description: If something doesn't work correctly in RPCS3
title: "Enter a title here"
labels: []
body:
- type: markdown
attributes:
value: |
# Summary
Please do not ask for help or report compatibility regressions here, use [RPCS3 Discord server](https://discord.me/RPCS3) or [forums](https://forums.rpcs3.net/) instead.
- type: textarea
id: quick-summary
attributes:
label: Quick summary
description: Please briefly describe what is not working correctly.
validations:
required: true
- type: textarea
id: details
attributes:
label: Details
description: |
Please describe the problem as accurately as possible.
Provide a comparison with a real PS3, if possible.
validations:
required: false
- type: markdown
attributes:
value: |
# Log files
Provide a log file that includes the bug you're reporting.
Obtaining the log file:
* Run the game until you find the regression.
* Completely close RPCS3 and locate the log file.
RPCS3's Log file will be ```RPCS3.log.gz``` (sometimes shows as RPCS3.log with zip icon) or ```RPCS3.log``` (sometimes shows as RPCS3 wtih notepad icon).
* On Windows it will be in the RPCS3 directory near the executable
* On Linux it will be in ```~/.cache/rpcs3/```
* On MacOS it will be in ```~/Library/Caches/rpcs3```. If you're unable to locate it copy paste the path in Spotlight and hit enter.
- type: textarea
id: logs
attributes:
label: Attach a log file
description: |
Drag & drop the files into this input field, or upload them to another service (f.ex. Dropbox, Mega) and provide a link.
validations:
required: true
- type: markdown
attributes:
value: |
# Other details
If you describe a graphical issue, please provide an RSX capture and/or a RenderDoc capture that demonstrate it.
* To create an RSX capture, use _Create_ _RSX_ _Capture_ under _Utilities_.
* Captures will be stored in RPCS3 folder → captures.
* To create a RenderDoc capture, please refer to [RenderDoc's documentation](https://renderdoc.org/docs/how/how_capture_frame.html).
- type: textarea
id: captures
attributes:
label: Attach capture files for visual issues
description: Compress your capture with 7z, Rar etc. and attach it here, or upload it to the cloud (Dropbox, Mega etc) and add a link to it.
validations:
required: false
- type: textarea
id: system-info
attributes:
label: System configuration
description: Provide information about your system, such as operating system, CPU and GPU model, GPU driver version and other information that describes your system configuration.
validations:
required: false
- type: textarea
id: other-details
attributes:
label: Other details
description: Include anything else you deem to be important.
validations:
required: false
@@ -1,41 +0,0 @@
---
name: Feature Request
about: If RPCS3 lacks a feature you would like to see
title: '[Feature Request] Enter Feature Title Here'
labels: ''
assignees: ''
---
## Please do not ask for help or report compatibility regressions here, use [RPCS3 Discord server](https://discord.me/RPCS3) or [forums](https://forums.rpcs3.net/) instead.
## Quick summary
Please briefly describe what feature you would like RPCS3 to have.
## Details
Please describe the feature as accurately as possible.
#### 1. Please describe, what part of RPCS3 would be affected by your feature:
* Gameplay
* Debugging
* UI
* Patches
* Installation
* Github
* CI
* etc.
#### 2. Please tell us, why your feature is important to RPCS3.
#### 3. Please attach screenshots of the feature implemented in other projects.
#### 4. Please provide your system configuration:
* OS
* CPU
* GPU
* Driver version
* etc.
#### Please include.
* Anything else you deem to be important
@@ -0,0 +1,36 @@
name: Feature request
description: If RPCS3 lacks a feature you would like to see
title: "[Feature request] Enter a title here"
labels: []
body:
- type: markdown
attributes:
value: |
Please do not ask for help or report compatibility regressions here, use [RPCS3 Discord server](https://discord.me/RPCS3) or [forums](https://forums.rpcs3.net/) instead.
- type: textarea
id: quick-summary
attributes:
label: Quick summary
description: Please briefly describe what feature you would like RPCS3 to have.
validations:
required: true
- type: textarea
id: details
attributes:
label: Details
description: Please describe the feature as accurately as possible.
validations:
required: false
- type: markdown
attributes:
value: |
Please include the following information:
* What part of RPCS3 would be affected by your feature? (Gameplay, Debugging, UI, Patches, Installation, CI etc.)
* Why your feature is important to RPCS3.
* If the feature is implemented in other projects, attach screenshots.
* If this feature is something that a game is trying to use, upload a log file for it.
RPCS3's Log file will be ```RPCS3.log.gz``` (sometimes shows as RPCS3.log with zip icon) or ```RPCS3.log``` (sometimes shows as RPCS3 wtih notepad icon).
* On Windows it will be in the RPCS3 directory near the executable
* On Linux it will be in ```~/.cache/rpcs3/```
* On MacOS it will be in ```~/Library/Caches/rpcs3```. If you're unable to locate it copy paste the path in Spotlight and hit enter.
+14
View File
@@ -0,0 +1,14 @@
---
name: Advanced
about: For developers and experienced users only
title: ''
labels: ''
assignees: ''
---
## Please do not ask for help or report compatibility regressions here, use [RPCS3 Discord server](https://discord.me/RPCS3) or [forums](https://forums.rpcs3.net/) instead.
You're using the advanced template. You're expected to know what to write in order to fill in all the required information for proper report.
If you're unsure on what to do, please return back to the issue type selection and choose different category.
+9 -5
View File
@@ -1,5 +1,5 @@
/* 7zTypes.h -- Basic types
2021-12-25 : Igor Pavlov : Public domain */
2022-04-01 : Igor Pavlov : Public domain */
#ifndef __7Z_TYPES_H
#define __7Z_TYPES_H
@@ -133,10 +133,6 @@ typedef int WRes;
#define MY__E_ERROR_NEGATIVE_SEEK MY_HRESULT_FROM_errno_CONST_ERROR(EINVAL)
*/
// gcc / clang : (sizeof(long) == sizeof(void*)) in 32/64 bits
typedef long INT_PTR;
typedef unsigned long UINT_PTR;
#define TEXT(quote) quote
#define FILE_ATTRIBUTE_READONLY 0x0001
@@ -520,6 +516,14 @@ struct ISzAlloc
#endif
#define k_PropVar_TimePrec_0 0
#define k_PropVar_TimePrec_Unix 1
#define k_PropVar_TimePrec_DOS 2
#define k_PropVar_TimePrec_HighPrec 3
#define k_PropVar_TimePrec_Base 16
#define k_PropVar_TimePrec_100ns (k_PropVar_TimePrec_Base + 7)
#define k_PropVar_TimePrec_1ns (k_PropVar_TimePrec_Base + 9)
EXTERN_C_END
#endif
+5 -5
View File
@@ -1,7 +1,7 @@
#define MY_VER_MAJOR 21
#define MY_VER_MINOR 07
#define MY_VER_MAJOR 22
#define MY_VER_MINOR 01
#define MY_VER_BUILD 0
#define MY_VERSION_NUMBERS "21.07"
#define MY_VERSION_NUMBERS "22.01"
#define MY_VERSION MY_VERSION_NUMBERS
#ifdef MY_CPU_NAME
@@ -10,12 +10,12 @@
#define MY_VERSION_CPU MY_VERSION
#endif
#define MY_DATE "2021-12-26"
#define MY_DATE "2022-07-15"
#undef MY_COPYRIGHT
#undef MY_VERSION_COPYRIGHT_DATE
#define MY_AUTHOR_NAME "Igor Pavlov"
#define MY_COPYRIGHT_PD "Igor Pavlov : Public domain"
#define MY_COPYRIGHT_CR "Copyright (c) 1999-2021 Igor Pavlov"
#define MY_COPYRIGHT_CR "Copyright (c) 1999-2022 Igor Pavlov"
#ifdef USE_COPYRIGHT_CR
#define MY_COPYRIGHT MY_COPYRIGHT_CR
+10 -7
View File
@@ -1,5 +1,5 @@
/* CpuArch.h -- CPU specific code
2021-07-13 : Igor Pavlov : Public domain */
2022-07-15 : Igor Pavlov : Public domain */
#ifndef __CPU_ARCH_H
#define __CPU_ARCH_H
@@ -123,12 +123,15 @@ MY_CPU_64BIT means that processor can work with 64-bit registers.
#endif
#if defined(__sparc64__)
#define MY_CPU_NAME "sparc64"
#define MY_CPU_64BIT
#elif defined(__sparc__)
#define MY_CPU_NAME "sparc"
/* #define MY_CPU_32BIT */
#if defined(__riscv) \
|| defined(__riscv__)
#if __riscv_xlen == 32
#define MY_CPU_NAME "riscv32"
#elif __riscv_xlen == 64
#define MY_CPU_NAME "riscv64"
#else
#define MY_CPU_NAME "riscv"
#endif
#endif
+6 -2
View File
@@ -1,5 +1,5 @@
/* DllSecur.c -- DLL loading security
2021-12-25 : Igor Pavlov : Public domain */
2022-07-15 : Igor Pavlov : Public domain */
#include "Precomp.h"
@@ -11,6 +11,10 @@
#ifndef UNDER_CE
#if defined(__GNUC__) && (__GNUC__ >= 8)
#pragma GCC diagnostic ignored "-Wcast-function-type"
#endif
typedef BOOL (WINAPI *Func_SetDefaultDllDirectories)(DWORD DirectoryFlags);
#define MY_LOAD_LIBRARY_SEARCH_USER_DIRS 0x400
@@ -34,7 +38,7 @@ static const char * const g_Dlls =
#endif
// #define MY_CAST_FUNC (void(*)())
#define MY_CAST_FUNC
#define MY_CAST_FUNC
void My_SetDefaultDllDirectories()
{
+4 -7
View File
@@ -1,5 +1,5 @@
/* LzmaEnc.c -- LZMA Encoder
2021-11-18: Igor Pavlov : Public domain */
2022-07-15: Igor Pavlov : Public domain */
#include "Precomp.h"
@@ -2970,6 +2970,7 @@ const Byte *LzmaEnc_GetCurBuf(CLzmaEncHandle pp)
}
// (desiredPackSize == 0) is not allowed
SRes LzmaEnc_CodeOneMemBlock(CLzmaEncHandle pp, BoolInt reInit,
Byte *dest, size_t *destLen, UInt32 desiredPackSize, UInt32 *unpackSize)
{
@@ -2990,14 +2991,10 @@ SRes LzmaEnc_CodeOneMemBlock(CLzmaEncHandle pp, BoolInt reInit,
if (reInit)
LzmaEnc_Init(p);
LzmaEnc_InitPrices(p);
nowPos64 = p->nowPos64;
RangeEnc_Init(&p->rc);
p->rc.outStream = &outStream.vt;
if (desiredPackSize == 0)
return SZ_ERROR_OUTPUT_EOF;
nowPos64 = p->nowPos64;
res = LzmaEnc_CodeOneBlock(p, desiredPackSize, *unpackSize);
*unpackSize = (UInt32)(p->nowPos64 - nowPos64);
+24 -3
View File
@@ -153,6 +153,20 @@ typedef int64_t khronos_int64_t;
typedef uint64_t khronos_uint64_t;
#define KHRONOS_SUPPORT_INT64 1
#define KHRONOS_SUPPORT_FLOAT 1
/*
* To support platform where unsigned long cannot be used interchangeably with
* inptr_t (e.g. CHERI-extended ISAs), we can use the stdint.h intptr_t.
* Ideally, we could just use (u)intptr_t everywhere, but this could result in
* ABI breakage if khronos_uintptr_t is changed from unsigned long to
* unsigned long long or similar (this results in different C++ name mangling).
* To avoid changes for existing platforms, we restrict usage of intptr_t to
* platforms where the size of a pointer is larger than the size of long.
*/
#if defined(__SIZEOF_LONG__) && defined(__SIZEOF_POINTER__)
#if __SIZEOF_POINTER__ > __SIZEOF_LONG__
#define KHRONOS_USE_INTPTR_T
#endif
#endif
#elif defined(__VMS ) || defined(__sgi)
@@ -235,14 +249,21 @@ typedef unsigned short int khronos_uint16_t;
* pointers are 64 bits, but 'long' is still 32 bits. Win64 appears
* to be the only LLP64 architecture in current use.
*/
#ifdef _WIN64
#ifdef KHRONOS_USE_INTPTR_T
typedef intptr_t khronos_intptr_t;
typedef uintptr_t khronos_uintptr_t;
#elif defined(_WIN64)
typedef signed long long int khronos_intptr_t;
typedef unsigned long long int khronos_uintptr_t;
typedef signed long long int khronos_ssize_t;
typedef unsigned long long int khronos_usize_t;
#else
typedef signed long int khronos_intptr_t;
typedef unsigned long int khronos_uintptr_t;
#endif
#if defined(_WIN64)
typedef signed long long int khronos_ssize_t;
typedef unsigned long long int khronos_usize_t;
#else
typedef signed long int khronos_ssize_t;
typedef unsigned long int khronos_usize_t;
#endif
+36 -2
View File
@@ -32,9 +32,9 @@ extern "C" {
#define GLAPI extern
#endif
#define GL_GLEXT_VERSION 20210420
#define GL_GLEXT_VERSION 20220530
#include "khrplatform.h"
#include <KHR/khrplatform.h>
/* Generated C header for:
* API: gl
@@ -8214,6 +8214,10 @@ GLAPI void APIENTRY glMemoryBarrierEXT (GLbitfield barriers);
#define GL_EXT_shader_integer_mix 1
#endif /* GL_EXT_shader_integer_mix */
#ifndef GL_EXT_shader_samples_identical
#define GL_EXT_shader_samples_identical 1
#endif /* GL_EXT_shader_samples_identical */
#ifndef GL_EXT_shadow_funcs
#define GL_EXT_shadow_funcs 1
#endif /* GL_EXT_shadow_funcs */
@@ -8625,6 +8629,36 @@ GLAPI void APIENTRY glTextureNormalEXT (GLenum mode);
#define GL_RGBA_SNORM 0x8F93
#endif /* GL_EXT_texture_snorm */
#ifndef GL_EXT_texture_storage
#define GL_EXT_texture_storage 1
#define GL_TEXTURE_IMMUTABLE_FORMAT_EXT 0x912F
#define GL_RGBA32F_EXT 0x8814
#define GL_RGB32F_EXT 0x8815
#define GL_ALPHA32F_EXT 0x8816
#define GL_LUMINANCE32F_EXT 0x8818
#define GL_LUMINANCE_ALPHA32F_EXT 0x8819
#define GL_RGBA16F_EXT 0x881A
#define GL_RGB16F_EXT 0x881B
#define GL_ALPHA16F_EXT 0x881C
#define GL_LUMINANCE16F_EXT 0x881E
#define GL_LUMINANCE_ALPHA16F_EXT 0x881F
#define GL_BGRA8_EXT 0x93A1
#define GL_R8_EXT 0x8229
#define GL_RG8_EXT 0x822B
#define GL_R32F_EXT 0x822E
#define GL_RG32F_EXT 0x8230
#define GL_R16F_EXT 0x822D
#define GL_RG16F_EXT 0x822F
typedef void (APIENTRYP PFNGLTEXSTORAGE1DEXTPROC) (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width);
typedef void (APIENTRYP PFNGLTEXSTORAGE2DEXTPROC) (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height);
typedef void (APIENTRYP PFNGLTEXSTORAGE3DEXTPROC) (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth);
#ifdef GL_GLEXT_PROTOTYPES
GLAPI void APIENTRY glTexStorage1DEXT (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width);
GLAPI void APIENTRY glTexStorage2DEXT (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height);
GLAPI void APIENTRY glTexStorage3DEXT (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth);
#endif
#endif /* GL_EXT_texture_storage */
#ifndef GL_EXT_texture_swizzle
#define GL_EXT_texture_swizzle 1
#define GL_TEXTURE_SWIZZLE_R_EXT 0x8E42
+18 -18
View File
@@ -747,12 +747,12 @@ AF1 sharpness){
// Immediate constants for peak range.
AF2 peakC=AF2(1.0,-1.0*4.0);
// Limiters, these need to be high precision RCPs.
AF1 hitMinR=mn4R*ARcpF1(AF1_(4.0)*mx4R);
AF1 hitMinG=mn4G*ARcpF1(AF1_(4.0)*mx4G);
AF1 hitMinB=mn4B*ARcpF1(AF1_(4.0)*mx4B);
AF1 hitMaxR=(peakC.x-mx4R)*ARcpF1(AF1_(4.0)*mn4R+peakC.y);
AF1 hitMaxG=(peakC.x-mx4G)*ARcpF1(AF1_(4.0)*mn4G+peakC.y);
AF1 hitMaxB=(peakC.x-mx4B)*ARcpF1(AF1_(4.0)*mn4B+peakC.y);
AF1 hitMinR=min(mn4R,eR)*ARcpF1(AF1_(4.0)*mx4R);
AF1 hitMinG=min(mn4G,eG)*ARcpF1(AF1_(4.0)*mx4G);
AF1 hitMinB=min(mn4B,eB)*ARcpF1(AF1_(4.0)*mx4B);
AF1 hitMaxR=(peakC.x-max(mx4R,eR))*ARcpF1(AF1_(4.0)*mn4R+peakC.y);
AF1 hitMaxG=(peakC.x-max(mx4G,eG))*ARcpF1(AF1_(4.0)*mn4G+peakC.y);
AF1 hitMaxB=(peakC.x-max(mx4B,eB))*ARcpF1(AF1_(4.0)*mn4B+peakC.y);
AF1 lobeR=max(-hitMinR,hitMaxR);
AF1 lobeG=max(-hitMinG,hitMaxG);
AF1 lobeB=max(-hitMinB,hitMaxB);
@@ -845,12 +845,12 @@ AF1 sharpness){
// Immediate constants for peak range.
AH2 peakC=AH2(1.0,-1.0*4.0);
// Limiters, these need to be high precision RCPs.
AH1 hitMinR=mn4R*ARcpH1(AH1_(4.0)*mx4R);
AH1 hitMinG=mn4G*ARcpH1(AH1_(4.0)*mx4G);
AH1 hitMinB=mn4B*ARcpH1(AH1_(4.0)*mx4B);
AH1 hitMaxR=(peakC.x-mx4R)*ARcpH1(AH1_(4.0)*mn4R+peakC.y);
AH1 hitMaxG=(peakC.x-mx4G)*ARcpH1(AH1_(4.0)*mn4G+peakC.y);
AH1 hitMaxB=(peakC.x-mx4B)*ARcpH1(AH1_(4.0)*mn4B+peakC.y);
AH1 hitMinR=min(mn4R,eR)*ARcpH1(AH1_(4.0)*mx4R);
AH1 hitMinG=min(mn4G,eG)*ARcpH1(AH1_(4.0)*mx4G);
AH1 hitMinB=min(mn4B,eB)*ARcpH1(AH1_(4.0)*mx4B);
AH1 hitMaxR=(peakC.x-max(mx4R,eR))*ARcpH1(AH1_(4.0)*mn4R+peakC.y);
AH1 hitMaxG=(peakC.x-max(mx4G,eG))*ARcpH1(AH1_(4.0)*mn4G+peakC.y);
AH1 hitMaxB=(peakC.x-max(mx4B,eB))*ARcpH1(AH1_(4.0)*mn4B+peakC.y);
AH1 lobeR=max(-hitMinR,hitMaxR);
AH1 lobeG=max(-hitMinG,hitMaxG);
AH1 lobeB=max(-hitMinB,hitMaxB);
@@ -963,12 +963,12 @@ AF1 sharpness){
// Immediate constants for peak range.
AH2 peakC=AH2(1.0,-1.0*4.0);
// Limiters, these need to be high precision RCPs.
AH2 hitMinR=mn4R*ARcpH2(AH2_(4.0)*mx4R);
AH2 hitMinG=mn4G*ARcpH2(AH2_(4.0)*mx4G);
AH2 hitMinB=mn4B*ARcpH2(AH2_(4.0)*mx4B);
AH2 hitMaxR=(peakC.x-mx4R)*ARcpH2(AH2_(4.0)*mn4R+peakC.y);
AH2 hitMaxG=(peakC.x-mx4G)*ARcpH2(AH2_(4.0)*mn4G+peakC.y);
AH2 hitMaxB=(peakC.x-mx4B)*ARcpH2(AH2_(4.0)*mn4B+peakC.y);
AH2 hitMinR=min(mn4R,eR)*ARcpH2(AH2_(4.0)*mx4R);
AH2 hitMinG=min(mn4G,eG)*ARcpH2(AH2_(4.0)*mx4G);
AH2 hitMinB=min(mn4B,eB)*ARcpH2(AH2_(4.0)*mx4B);
AH2 hitMaxR=(peakC.x-max(mx4R,eR))*ARcpH2(AH2_(4.0)*mn4R+peakC.y);
AH2 hitMaxG=(peakC.x-max(mx4G,eG))*ARcpH2(AH2_(4.0)*mn4G+peakC.y);
AH2 hitMaxB=(peakC.x-max(mx4B,eB))*ARcpH2(AH2_(4.0)*mn4B+peakC.y);
AH2 lobeR=max(-hitMinR,hitMaxR);
AH2 lobeG=max(-hitMinG,hitMaxG);
AH2 lobeB=max(-hitMinB,hitMaxB);
+1 -1
View File
@@ -4,7 +4,7 @@ include(ExternalProject)
ExternalProject_Add(moltenvk
GIT_REPOSITORY https://github.com/KhronosGroup/MoltenVK.git
GIT_TAG 1236d2f
GIT_TAG 260bad4
BUILD_IN_SOURCE 1
SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/MoltenVK
CONFIGURE_COMMAND "${CMAKE_CURRENT_SOURCE_DIR}/MoltenVK/fetchDependencies" --macos
-7
View File
@@ -1,7 +0,0 @@
diff --git a/ExternalRevisions/SPIRV-Cross_repo_revision b/ExternalRevisions/SPIRV-Cross_repo_revision
index 777346a0..c1971b45 100644
--- a/ExternalRevisions/SPIRV-Cross_repo_revision
+++ b/ExternalRevisions/SPIRV-Cross_repo_revision
@@ -1 +1 @@
-0d4ce028bf8b8a94d325dc1e1c20446153ba19c4
+44c3333a1c315ead00c24f7aef5fa8a7ccf49299
+9 -9
View File
@@ -39,28 +39,28 @@
<PropertyGroup Label="UserMacros">
<CmakeGenerator>"Visual Studio $(VisualStudioVersion.Substring(0,2))"</CmakeGenerator>
<CmakeReleaseCLI>call vsdevcmd.bat -arch=amd64
cmake -G $(CmakeGenerator) -A x64 -DCMAKE_BUILD_TYPE="Release" -DSPIRV_WERROR=OFF -DSPIRV-Headers_SOURCE_DIR=$([System.IO.Path]::GetFullPath('$(MSBuildThisFileDirectory)/SPIRV-Headers').Replace('\', '/')) SPIRV-Tools -B build</CmakeReleaseCLI>
cmake -G $(CmakeGenerator) -A x64 -DCMAKE_BUILD_TYPE="Release" -DSPIRV_WERROR=OFF -DSPIRV-Headers_SOURCE_DIR="$([System.IO.Path]::GetFullPath('$(MSBuildThisFileDirectory)/SPIRV-Headers').Replace('\', '/'))" SPIRV-Tools -B build</CmakeReleaseCLI>
<CmakeDebugCLI>call vsdevcmd.bat -arch=amd64
cmake -G $(CmakeGenerator) -A x64 -DCMAKE_BUILD_TYPE="Debug" -DSPIRV_WERROR=OFF -DSPIRV-Headers_SOURCE_DIR=$([System.IO.Path]::GetFullPath('$(MSBuildThisFileDirectory)/SPIRV-Headers').Replace('\', '/')) -S SPIRV-Tools -B build</CmakeDebugCLI>
cmake -G $(CmakeGenerator) -A x64 -DCMAKE_BUILD_TYPE="Debug" -DSPIRV_WERROR=OFF -DSPIRV-Headers_SOURCE_DIR="$([System.IO.Path]::GetFullPath('$(MSBuildThisFileDirectory)/SPIRV-Headers').Replace('\', '/'))" -S SPIRV-Tools -B build</CmakeDebugCLI>
<PropsAbsPath>$([System.IO.Path]::GetFullPath('$(MSBuildThisFileDirectory)..\..\buildfiles\msvc\common_default.props'))</PropsAbsPath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<NMakeBuildCommandLine>$(CmakeReleaseCLI)
msbuild.exe build\ALL_BUILD.vcxproj /t:build /p:Configuration=Release /p:ForceImportBeforeCppTargets=$(PropsAbsPath) /m</NMakeBuildCommandLine>
msbuild.exe build\ALL_BUILD.vcxproj /t:build /p:Configuration=Release /p:ForceImportBeforeCppTargets="$(PropsAbsPath)" /m</NMakeBuildCommandLine>
<NMakeReBuildCommandLine>$(CmakeReleaseCLI)
msbuild.exe build\ALL_BUILD.vcxproj /t:rebuild /p:Configuration=Release /p:ForceImportBeforeCppTargets=$(PropsAbsPath) /m</NMakeReBuildCommandLine>
msbuild.exe build\ALL_BUILD.vcxproj /t:rebuild /p:Configuration=Release /p:ForceImportBeforeCppTargets="$(PropsAbsPath)" /m</NMakeReBuildCommandLine>
<NMakeCleanCommandLine>$(CmakeReleaseCLI)
msbuild.exe build\ALL_BUILD.vcxproj /t:clean /p:Configuration=Release /p:ForceImportBeforeCppTargets=$(PropsAbsPath) /m</NMakeCleanCommandLine>
msbuild.exe build\ALL_BUILD.vcxproj /t:clean /p:Configuration=Release /p:ForceImportBeforeCppTargets="$(PropsAbsPath)" /m</NMakeCleanCommandLine>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<NMakeBuildCommandLine>$(CmakeDebugCLI)
msbuild.exe build\ALL_BUILD.vcxproj /t:build /p:Configuration=Debug /p:ForceImportBeforeCppTargets=$(PropsAbsPath) /m
msbuild.exe build\ALL_BUILD.vcxproj /t:build /p:Configuration=Debug /p:ForceImportBeforeCppTargets="$(PropsAbsPath)" /m
</NMakeBuildCommandLine>
<NMakeReBuildCommandLine>$(CmakeDebugCLI)
msbuild.exe build\ALL_BUILD.vcxproj /t:rebuild /p:Configuration=Debug /p:ForceImportBeforeCppTargets=$(PropsAbsPath) /m
msbuild.exe build\ALL_BUILD.vcxproj /t:rebuild /p:Configuration=Debug /p:ForceImportBeforeCppTargets="$(PropsAbsPath)" /m
</NMakeReBuildCommandLine>
<NMakeCleanCommandLine>$(CmakeDebugCLI)
msbuild.exe build\ALL_BUILD.vcxproj /t:clean /p:Configuration=Debug /p:ForceImportBeforeCppTargets=$(PropsAbsPath) /m
msbuild.exe build\ALL_BUILD.vcxproj /t:clean /p:Configuration=Debug /p:ForceImportBeforeCppTargets="$(PropsAbsPath)" /m
</NMakeCleanCommandLine>
</PropertyGroup>
<ItemDefinitionGroup>
@@ -68,4 +68,4 @@
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
</Project>
+1 -1
View File
@@ -27,7 +27,7 @@ target_compile_definitions(soundtouch PUBLIC
SOUNDTOUCH_FLOAT_SAMPLES;
)
target_compile_options(soundtouch PUBLIC "-w")
target_compile_options(soundtouch PRIVATE "-w")
if (CMAKE_SYSTEM_PROCESSOR MATCHES "^(x86|X86|amd64|AMD64|em64t|EM64T)")
target_compile_definitions(soundtouch PUBLIC
File diff suppressed because it is too large Load Diff
Binary file not shown.
+5 -3
View File
@@ -62,12 +62,13 @@
<ClCompile Include="asmjit\src\asmjit\arm\a64builder.cpp" />
<ClCompile Include="asmjit\src\asmjit\arm\a64compiler.cpp" />
<ClCompile Include="asmjit\src\asmjit\arm\a64emithelper.cpp" />
<ClCompile Include="asmjit\src\asmjit\arm\a64formatter.cpp" />
<ClCompile Include="asmjit\src\asmjit\arm\a64func.cpp" />
<ClCompile Include="asmjit\src\asmjit\arm\a64instapi.cpp" />
<ClCompile Include="asmjit\src\asmjit\arm\a64instdb.cpp" />
<ClCompile Include="asmjit\src\asmjit\arm\a64operand.cpp" />
<ClCompile Include="asmjit\src\asmjit\arm\a64rapass.cpp" />
<ClCompile Include="asmjit\src\asmjit\arm\armformatter.cpp" />
<ClCompile Include="asmjit\src\asmjit\arm\armfunc.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="asmjit\src\asmjit\core\api-build_p.h" />
@@ -134,11 +135,14 @@
<ClInclude Include="asmjit\src\asmjit\x86\x86opcode_p.h" />
<ClInclude Include="asmjit\src\asmjit\x86\x86operand.h" />
<ClInclude Include="asmjit\src\asmjit\x86\x86rapass_p.h" />
<ClInclude Include="asmjit\src\asmjit\arm\a64archtraits_p.h" />
<ClInclude Include="asmjit\src\asmjit\arm\a64assembler.h" />
<ClInclude Include="asmjit\src\asmjit\arm\a64builder.h" />
<ClInclude Include="asmjit\src\asmjit\arm\a64compiler.h" />
<ClInclude Include="asmjit\src\asmjit\arm\a64emithelper_p.h" />
<ClInclude Include="asmjit\src\asmjit\arm\a64emitter.h" />
<ClInclude Include="asmjit\src\asmjit\arm\a64formatter_p.h" />
<ClInclude Include="asmjit\src\asmjit\arm\a64func_p.h" />
<ClInclude Include="asmjit\src\asmjit\arm\a64globals.h" />
<ClInclude Include="asmjit\src\asmjit\arm\a64instapi_p.h" />
<ClInclude Include="asmjit\src\asmjit\arm\a64instdb.h" />
@@ -146,9 +150,7 @@
<ClInclude Include="asmjit\src\asmjit\arm\a64operand.h" />
<ClInclude Include="asmjit\src\asmjit\arm\a64rapass_p.h" />
<ClInclude Include="asmjit\src\asmjit\arm\a64utils.h" />
<ClInclude Include="asmjit\src\asmjit\arm\armarchtraits_p.h" />
<ClInclude Include="asmjit\src\asmjit\arm\armformatter_p.h" />
<ClInclude Include="asmjit\src\asmjit\arm\armfunc_p.h" />
<ClInclude Include="asmjit\src\asmjit\arm\armglobals.h" />
<ClInclude Include="asmjit\src\asmjit\arm\armoperand.h" />
</ItemGroup>
+5 -3
View File
@@ -52,12 +52,13 @@
<ClCompile Include="asmjit\src\asmjit\arm\a64builder.cpp" />
<ClCompile Include="asmjit\src\asmjit\arm\a64compiler.cpp" />
<ClCompile Include="asmjit\src\asmjit\arm\a64emithelper.cpp" />
<ClCompile Include="asmjit\src\asmjit\arm\a64formatter.cpp" />
<ClCompile Include="asmjit\src\asmjit\arm\a64func.cpp" />
<ClCompile Include="asmjit\src\asmjit\arm\a64instapi.cpp" />
<ClCompile Include="asmjit\src\asmjit\arm\a64instdb.cpp" />
<ClCompile Include="asmjit\src\asmjit\arm\a64operand.cpp" />
<ClCompile Include="asmjit\src\asmjit\arm\a64rapass.cpp" />
<ClCompile Include="asmjit\src\asmjit\arm\armformatter.cpp" />
<ClCompile Include="asmjit\src\asmjit\arm\armfunc.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="asmjit\src\asmjit\core\api-build_p.h" />
@@ -124,11 +125,14 @@
<ClInclude Include="asmjit\src\asmjit\x86\x86opcode_p.h" />
<ClInclude Include="asmjit\src\asmjit\x86\x86operand.h" />
<ClInclude Include="asmjit\src\asmjit\x86\x86rapass_p.h" />
<ClInclude Include="asmjit\src\asmjit\arm\a64archtraits_p.h" />
<ClInclude Include="asmjit\src\asmjit\arm\a64assembler.h" />
<ClInclude Include="asmjit\src\asmjit\arm\a64builder.h" />
<ClInclude Include="asmjit\src\asmjit\arm\a64compiler.h" />
<ClInclude Include="asmjit\src\asmjit\arm\a64emithelper_p.h" />
<ClInclude Include="asmjit\src\asmjit\arm\a64emitter.h" />
<ClInclude Include="asmjit\src\asmjit\arm\a64formatter_p.h" />
<ClInclude Include="asmjit\src\asmjit\arm\a64func_p.h" />
<ClInclude Include="asmjit\src\asmjit\arm\a64globals.h" />
<ClInclude Include="asmjit\src\asmjit\arm\a64instapi_p.h" />
<ClInclude Include="asmjit\src\asmjit\arm\a64instdb.h" />
@@ -136,9 +140,7 @@
<ClInclude Include="asmjit\src\asmjit\arm\a64operand.h" />
<ClInclude Include="asmjit\src\asmjit\arm\a64rapass_p.h" />
<ClInclude Include="asmjit\src\asmjit\arm\a64utils.h" />
<ClInclude Include="asmjit\src\asmjit\arm\armarchtraits_p.h" />
<ClInclude Include="asmjit\src\asmjit\arm\armformatter_p.h" />
<ClInclude Include="asmjit\src\asmjit\arm\armfunc_p.h" />
<ClInclude Include="asmjit\src\asmjit\arm\armglobals.h" />
<ClInclude Include="asmjit\src\asmjit\arm\armoperand.h" />
</ItemGroup>
+1
View File
@@ -12,6 +12,7 @@ else()
option(CURL_USE_WOLFSSL "enable wolfSSL for SSL/TLS" ON)
option(HTTP_ONLY "disables all protocols except HTTP (This overrides all CURL_DISABLE_* options)" ON)
option(CURL_ZLIB "Set to ON to enable building curl with zlib support." OFF)
option(USE_LIBIDN2 "Use libidn2 for IDN support" OFF) # Disabled because MacOs CI doesn't work otherwise
set(CURL_CA_PATH "none" CACHE STRING "Location of default CA path. Set 'none' to disable or 'auto' for auto-detection. Defaults to 'auto'.")
if(USE_MSVC_STATIC_CRT)
set(CURL_STATIC_CRT ON CACHE BOOL "Use static crt to build curl" FORCE)
+3
View File
@@ -98,6 +98,7 @@
<ClCompile Include="curl\lib\escape.c" />
<ClCompile Include="curl\lib\file.c" />
<ClCompile Include="curl\lib\fileinfo.c" />
<ClCompile Include="curl\lib\fopen.c" />
<ClCompile Include="curl\lib\formdata.c" />
<ClCompile Include="curl\lib\ftp.c" />
<ClCompile Include="curl\lib\ftplistparser.c" />
@@ -279,9 +280,11 @@
<ClInclude Include="curl\lib\dynbuf.h" />
<ClInclude Include="curl\lib\easyif.h" />
<ClInclude Include="curl\lib\easyoptions.h" />
<ClInclude Include="curl\lib\easy_lock.h" />
<ClInclude Include="curl\lib\escape.h" />
<ClInclude Include="curl\lib\file.h" />
<ClInclude Include="curl\lib\fileinfo.h" />
<ClInclude Include="curl\lib\fopen.h" />
<ClInclude Include="curl\lib\formdata.h" />
<ClInclude Include="curl\lib\ftp.h" />
<ClInclude Include="curl\lib\ftplistparser.h" />
+9
View File
@@ -480,6 +480,9 @@
<ClCompile Include="curl\lib\timediff.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="curl\lib\fopen.c">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="curl\include\curl\curl.h">
@@ -965,6 +968,12 @@
<ClInclude Include="curl\lib\timediff.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="curl\lib\easy_lock.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="curl\lib\fopen.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="curl\lib\libcurl.rc">
+7 -7
View File
@@ -46,21 +46,21 @@
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<NMakeBuildCommandLine>$(CmakeReleaseCLI)
msbuild.exe build\ALL_BUILD.vcxproj /t:build /p:Configuration=Release /p:ForceImportBeforeCppTargets=$(PropsAbsPath) /m</NMakeBuildCommandLine>
msbuild.exe build\ALL_BUILD.vcxproj /t:build /p:Configuration=Release /p:ForceImportBeforeCppTargets="$(PropsAbsPath)" /m</NMakeBuildCommandLine>
<NMakeReBuildCommandLine>$(CmakeReleaseCLI)
msbuild.exe build\ALL_BUILD.vcxproj /t:rebuild /p:Configuration=Release /p:ForceImportBeforeCppTargets=$(PropsAbsPath) /m</NMakeReBuildCommandLine>
msbuild.exe build\ALL_BUILD.vcxproj /t:rebuild /p:Configuration=Release /p:ForceImportBeforeCppTargets="$(PropsAbsPath)" /m</NMakeReBuildCommandLine>
<NMakeCleanCommandLine>$(CmakeReleaseCLI)
msbuild.exe build\ALL_BUILD.vcxproj /t:clean /p:Configuration=Release /p:ForceImportBeforeCppTargets=$(PropsAbsPath) /m</NMakeCleanCommandLine>
msbuild.exe build\ALL_BUILD.vcxproj /t:clean /p:Configuration=Release /p:ForceImportBeforeCppTargets="$(PropsAbsPath)" /m</NMakeCleanCommandLine>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<NMakeBuildCommandLine>$(CmakeDebugCLI)
msbuild.exe build\ALL_BUILD.vcxproj /t:build /p:Configuration=Debug /p:ForceImportBeforeCppTargets=$(PropsAbsPath) /m
msbuild.exe build\ALL_BUILD.vcxproj /t:build /p:Configuration=Debug /p:ForceImportBeforeCppTargets="$(PropsAbsPath)" /m
</NMakeBuildCommandLine>
<NMakeReBuildCommandLine>$(CmakeDebugCLI)
msbuild.exe build\ALL_BUILD.vcxproj /t:rebuild /p:Configuration=Debug /p:ForceImportBeforeCppTargets=$(PropsAbsPath) /m
msbuild.exe build\ALL_BUILD.vcxproj /t:rebuild /p:Configuration=Debug /p:ForceImportBeforeCppTargets="$(PropsAbsPath)" /m
</NMakeReBuildCommandLine>
<NMakeCleanCommandLine>$(CmakeDebugCLI)
msbuild.exe build\ALL_BUILD.vcxproj /t:clean /p:Configuration=Debug /p:ForceImportBeforeCppTargets=$(PropsAbsPath) /m
msbuild.exe build\ALL_BUILD.vcxproj /t:clean /p:Configuration=Debug /p:ForceImportBeforeCppTargets="$(PropsAbsPath)" /m
</NMakeCleanCommandLine>
</PropertyGroup>
<ItemDefinitionGroup>
@@ -68,4 +68,4 @@
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
</Project>
+5 -10
View File
@@ -265,9 +265,8 @@ namespace pine
case MsgVersion:
{
char version[256] = {};
sprintf(version, "RPCS3 %s", Impl::get_version_and_branch().c_str());
snprintf(version, sizeof(version), "RPCS3 %s", Impl::get_version_and_branch().c_str());
const u32 size = strlen(version) + 1;
version[size] = 0x00;
if (!SafetyChecks(buf_cnt, 0, ret_cnt, size + 4, buf_size))
goto error;
ToArray(ret_buffer, size, ret_cnt);
@@ -291,8 +290,7 @@ namespace pine
const auto title_string = Impl::get_title();
const auto size = title_string.size() + 1;
char* title = new char[size];
sprintf(title, "%s", title_string.c_str());
title[size] = 0x00;
snprintf(title, size, "%s", title_string.c_str());
if (!SafetyChecks(buf_cnt, 0, ret_cnt, size + 4, buf_size))
goto error;
ToArray(ret_buffer, size, ret_cnt);
@@ -307,8 +305,7 @@ namespace pine
const auto title_id_string = Impl::get_title_ID();
const auto size = title_id_string.size() + 1;
char* title_id = new char[size];
sprintf(title_id, "%s", title_id_string.c_str());
title_id[size] = 0x00;
snprintf(title_id, size, "%s", title_id_string.c_str());
if (!SafetyChecks(buf_cnt, 0, ret_cnt, size + 4, buf_size))
goto error;
ToArray(ret_buffer, size, ret_cnt);
@@ -323,8 +320,7 @@ namespace pine
const auto hash_string = Impl::get_executable_hash();
const auto size = hash_string.size() + 1;
char* hash = new char[size];
sprintf(hash, "%s", hash_string.c_str());
hash[size] = 0x00;
snprintf(hash, size, "%s", hash_string.c_str());
if (!SafetyChecks(buf_cnt, 0, ret_cnt, size + 4, buf_size))
goto error;
ToArray(ret_buffer, size, ret_cnt);
@@ -339,8 +335,7 @@ namespace pine
const auto game_version_string = Impl::get_app_version();
const auto size = game_version_string.size() + 1;
char* game_version = new char[size];
sprintf(game_version, "%s", game_version_string.c_str());
game_version[size] = 0x00;
snprintf(game_version, size, "%s", game_version_string.c_str());
if (!SafetyChecks(buf_cnt, 0, ret_cnt, size, buf_size))
goto error;
ToArray(ret_buffer, size, ret_cnt);
+3 -2
View File
@@ -5,9 +5,10 @@ if(USE_SYSTEM_WOLFSSL)
target_link_libraries(wolfssl INTERFACE PkgConfig::WolfSSL)
else()
# TODO(cjj19970505@live.cn)
# OPENSSL_EXTRA, WOLFSSL_DES_ECB and HAVE_SNI are unconfigurable from CMake cache.
# OPENSSL_EXTRA, and HAVE_SNI are unconfigurable from CMake cache.
# but they do have it in a TODO list (wolfssl/CMakeList, 1021)
add_compile_definitions(OPENSSL_EXTRA WOLFSSL_DES_ECB HAVE_SNI HAVE_WRITE_DUP)
add_compile_definitions(FP_MAX_BITS=8192)
set(WOLFSSL_TLS13 "no" CACHE INTERNAL "")
set(WOLFSSL_SHA224 "yes" CACHE INTERNAL "")
@@ -19,7 +20,7 @@ else()
set(WOLFSSL_CHACHA "yes" CACHE INTERNAL "")
set(WOLFSSL_FILESYSTEM "yes" CACHE INTERNAL "")
set(WOLFSSL_PWDBASED "yes" CACHE INTERNAL "")
set(WOLFSSL_FAST_MATH "no" CACHE INTERNAL "")
set(WOLFSSL_FAST_MATH "yes" CACHE INTERNAL "")
set(WOLFSSL_EXAMPLES "no" CACHE INTERNAL "")
set(WOLFSSL_CRYPT_TESTS "no" CACHE INTERNAL "")
set(WOLFSSL_ASYNC_THREADS "no" CACHE INTERNAL "")
+2
View File
@@ -43,6 +43,8 @@
#define HAVE_ECC
#define ECC_SHAMIR
#define ECC_TIMING_RESISTANT
#define USE_FAST_MATH
#define FP_MAX_BITS 8192
/* UTF-8 aware filesystem functions for Windows */
#define WOLFSSL_USER_FILESYSTEM
+4 -3
View File
@@ -102,9 +102,10 @@ git submodule update --init
#### Configuring the Qt plugin (if used)
1) Go to the Qt5 menu and edit Qt5 options.
2) Add the path to your Qt installation with compiler e.g. `<QtInstallFolder>\5.15.2\msvc2019_64`.
3) While selecting the rpcs3qt project, go to Qt5->Project Setting and select the version you added.
1) Go to `Extensions->Qt VS Tools->Qt Versions`.
2) Add the path to your Qt installation with compiler e.g. `<QtInstallFolder>\5.15.2\msvc2019_64`, version will fill in automatically.
3) Go to `Extensions->Qt VS Tools->Options->Legacy Project Format`.
4) Set `Build: Run pre-build setup` to `true`.
#### Building the projects
+3 -3
View File
@@ -104,9 +104,9 @@ if(WIN32)
add_definitions(-D_WIN32_WINNT=0x0602)
endif()
if(APPLE)
include_directories(/opt/local/include)
link_directories(/opt/local/lib)
if(APPLE AND CMAKE_OSX_ARCHITECTURES STREQUAL "arm64")
include_directories(/opt/homebrew/include)
link_directories(/opt/homebrew/lib)
endif()
# Warnings are silenced for 3rdparty code
+2 -2
View File
@@ -5,10 +5,10 @@ RPCS3
[![Cirrus CI - Base Branch Build Status](https://img.shields.io/cirrus/github/RPCS3/rpcs3?label=Cirrus%20CI%20(FreeBSD)&logo=cirrus-ci)](https://cirrus-ci.com/github/RPCS3/rpcs3)
[![RPCS3 discord server](https://img.shields.io/discord/272035812277878785?color=5865F2&label=RPCS3%20Discord&logo=discord&logoColor=white)](https://discord.me/rpcs3)
The world's first free and open-source PlayStation 3 emulator/debugger, written in C++ for Windows and Linux.
The world's first free and open-source PlayStation 3 emulator/debugger, written in C++ for Windows, Linux, macOS and FreeBSD.
You can find some basic information on our [**website**](https://rpcs3.net/). Game info is being populated on the [**Wiki**](https://wiki.rpcs3.net/).
For discussion about this emulator, PS3 emulation, and game compatibility reports, please visit our [**forums**](https://forums.rpcs3.net) and our [**Discord server**](https://discord.me/RPCS3).
For discussion about this emulator, PS3 emulation, and game compatibility reports, please visit our [**forums**](https://forums.rpcs3.net) and our [**Discord server**](https://discord.gg/RPCS3).
[**Support Lead Developers Nekotekina and kd-11 on Patreon**](https://www.patreon.com/Nekotekina)
+56 -8
View File
@@ -60,9 +60,15 @@ std::vector<std::string> cfg::make_int_range(s64 min, s64 max)
bool try_to_int64(s64* out, std::string_view value, s64 min, s64 max)
{
if (value.empty())
{
if (out) cfg_log.error("cfg::try_to_uint64(): called with an empty string");
return false;
}
s64 result;
const char* start = &value.front();
const char* end = &value.back() + 1;
const char* start = value.data();
const char* end = start + value.size();
int base = 10;
int sign = +1;
@@ -72,7 +78,7 @@ bool try_to_int64(s64* out, std::string_view value, s64 min, s64 max)
start += 1;
}
if (start[0] == '0' && (start[1] == 'x' || start[1] == 'X'))
if (start[0] == '0' && value.size() >= 2 && (start[1] == 'x' || start[1] == 'X'))
{
// Limited hex support
base = 16;
@@ -106,12 +112,18 @@ std::vector<std::string> cfg::make_uint_range(u64 min, u64 max)
bool try_to_uint64(u64* out, std::string_view value, u64 min, u64 max)
{
if (value.empty())
{
if (out) cfg_log.error("cfg::try_to_uint64(): called with an empty string");
return false;
}
u64 result;
const char* start = &value.front();
const char* end = &value.back() + 1;
const char* start = value.data();
const char* end = start + value.size();
int base = 10;
if (start[0] == '0' && (start[1] == 'x' || start[1] == 'X'))
if (start[0] == '0' && value.size() >= 2 && (start[1] == 'x' || start[1] == 'X'))
{
// Limited hex support
base = 16;
@@ -136,6 +148,42 @@ bool try_to_uint64(u64* out, std::string_view value, u64 min, u64 max)
return true;
}
std::vector<std::string> cfg::make_float_range(f64 min, f64 max)
{
return {std::to_string(min), std::to_string(max)};
}
bool try_to_float(f64* out, std::string_view value, f64 min, f64 max)
{
if (value.empty())
{
if (out) cfg_log.error("cfg::try_to_float(): called with an empty string");
return false;
}
// std::from_chars float is yet to be implemented on Xcode it seems
// And strtod doesn't support ranged view so we need to ensure it meets a null terminator
const std::string str = std::string{value};
char* end_check{};
const double result = std::strtod(str.data(), &end_check);
if (end_check != str.data() + str.size())
{
if (out) cfg_log.error("cfg::try_to_float('%s'): invalid float", value);
return false;
}
if (result < min || result > max)
{
if (out) cfg_log.error("cfg::try_to_float('%s'): out of bounds (%f..%f)", value, min, max);
return false;
}
if (out) *out = result;
return true;
}
bool cfg::try_to_enum_value(u64* out, decltype(&fmt_class_string<int>::format) func, std::string_view value)
{
u64 max = umax;
@@ -162,8 +210,8 @@ bool cfg::try_to_enum_value(u64* out, decltype(&fmt_class_string<int>::format) f
}
u64 result;
const char* start = &value.front();
const char* end = &value.back() + 1;
const char* start = value.data();
const char* end = start + value.size();
int base = 10;
if (start[0] == '0' && (start[1] == 'x' || start[1] == 'X'))
+69
View File
@@ -20,6 +20,9 @@ namespace cfg
// Format min and max unsigned values
std::vector<std::string> make_uint_range(u64 min, u64 max);
// Format min and max float values
std::vector<std::string> make_float_range(f64 min, f64 max);
// Internal hack
bool try_to_enum_value(u64* out, decltype(&fmt_class_string<int>::format) func, std::string_view);
@@ -309,6 +312,72 @@ namespace cfg
}
};
// Float entry with custom Min/Max range.
template <s32 Min, s32 Max>
class _float final : public _base
{
static_assert(Min < Max, "Invalid cfg::_float range");
using float_type = f64;
atomic_t<float_type> m_value;
public:
float_type def;
// Expose range
static constexpr float_type max = Max;
static constexpr float_type min = Min;
_float(node* owner, const std::string& name, float_type def = std::min<float_type>(Max, std::max<float_type>(Min, 0)), bool dynamic = false)
: _base(type::_int, owner, name, dynamic)
, m_value(def)
, def(def)
{
}
operator float_type() const
{
return m_value;
}
float_type get() const
{
return m_value;
}
void from_default() override
{
m_value = def;
}
std::string to_string() const override
{
return std::to_string(m_value);
}
bool from_string(std::string_view value, bool /*dynamic*/ = false) override
{
f64 result;
if (try_to_float(&result, value, Min, Max))
{
m_value = static_cast<float_type>(result);
return true;
}
return false;
}
void set(const f64& value)
{
m_value = static_cast<float_type>(value);
}
std::vector<std::string> to_list() const override
{
return make_float_range(Min, Max);
}
};
// Alias for 32 bit int
using int32 = _int<s32{smin}, s32{smax}>;
+34 -3
View File
@@ -71,6 +71,10 @@ namespace fs
s64 atime;
s64 mtime;
s64 ctime;
using enable_bitcopy = std::true_type;
constexpr bool operator==(const stat_t&) const = default;
};
// Helper, layout is equal to iovec struct
@@ -105,6 +109,8 @@ namespace fs
: stat_t{}
{
}
using enable_bitcopy = std::false_type;
};
// Directory handle base
@@ -681,9 +687,10 @@ namespace fs
T obj;
u64 pos;
container_stream(T&& obj)
container_stream(T&& obj, const stat_t& init_stat = {})
: obj(std::forward<T>(obj))
, pos(0)
, m_stat(init_stat)
{
}
@@ -694,6 +701,7 @@ namespace fs
bool trunc(u64 length) override
{
obj.resize(length);
update_time(true);
return true;
}
@@ -708,6 +716,7 @@ namespace fs
{
std::copy(obj.cbegin() + pos, obj.cbegin() + pos + max, static_cast<value_type*>(buffer));
pos = pos + max;
update_time();
return max;
}
}
@@ -743,6 +752,7 @@ namespace fs
obj.insert(obj.end(), src + overlap, src + size);
pos += size;
if (size) update_time(true);
return size;
}
@@ -767,13 +777,34 @@ namespace fs
{
return obj.size();
}
stat_t stat() override
{
return m_stat;
}
private:
stat_t m_stat{};
void update_time(bool write = false)
{
// TODO: Accurate timestamps
m_stat.atime++;
if (write)
{
m_stat.mtime++;
m_stat.mtime = std::max(m_stat.atime, m_stat.mtime);
m_stat.ctime = m_stat.mtime;
}
}
};
template <typename T>
file make_stream(T&& container = T{})
file make_stream(T&& container = T{}, const stat_t& stat = stat_t{})
{
file result;
result.reset(std::make_unique<container_stream<T>>(std::forward<T>(container)));
result.reset(std::make_unique<container_stream<T>>(std::forward<T>(container), stat));
return result;
}
+502 -6
View File
@@ -7,6 +7,8 @@
#include "mutex.h"
#include "util/vm.hpp"
#include "util/asm.hpp"
#include "util/v128.hpp"
#include "util/simd.hpp"
#include <charconv>
#include <zlib.h>
@@ -18,6 +20,34 @@ LOG_CHANNEL(jit_log, "JIT");
void jit_announce(uptr func, usz size, std::string_view name)
{
#ifdef __linux__
static const struct tmp_perf_map
{
std::string name{fmt::format("/tmp/perf-%d.map", getpid())};
fs::file data{name, fs::rewrite + fs::append};
tmp_perf_map() = default;
tmp_perf_map(const tmp_perf_map&) = delete;
tmp_perf_map& operator=(const tmp_perf_map&) = delete;
~tmp_perf_map()
{
fs::remove_file(name);
}
} s_map;
if (size && name.size())
{
s_map.data.write(fmt::format("%x %x %s\n", func, size, name));
}
if (!func && !size && !name.size())
{
fs::remove_file(s_map.name);
return;
}
#endif
if (!size)
{
jit_log.error("Empty function announced: %s (%p)", name, func);
@@ -81,12 +111,6 @@ void jit_announce(uptr func, usz size, std::string_view name)
dump.write(reinterpret_cast<uchar*>(func), size);
}
}
#ifdef __linux__
static const fs::file s_map(fmt::format("/tmp/perf-%d.map", getpid()), fs::rewrite + fs::append);
s_map.write(fmt::format("%x %x %s\n", func, size, name));
#endif
}
static u8* get_jit_memory()
@@ -351,6 +375,473 @@ asmjit::inline_runtime::~inline_runtime()
utils::memory_protect(m_data, m_size, utils::protection::rx);
}
#if defined(ARCH_X64)
asmjit::simd_builder::simd_builder(CodeHolder* ch) noexcept
: native_asm(ch)
{
_init(0);
consts[~v128()] = this->newLabel();
}
asmjit::simd_builder::~simd_builder()
{
}
void asmjit::simd_builder::_init(uint new_vsize)
{
if ((!new_vsize && utils::has_avx512_icl()) || new_vsize == 64)
{
v0 = x86::zmm0;
v1 = x86::zmm1;
v2 = x86::zmm2;
v3 = x86::zmm3;
v4 = x86::zmm4;
v5 = x86::zmm5;
vsize = 64;
}
else if ((!new_vsize && utils::has_avx2()) || new_vsize == 32)
{
v0 = x86::ymm0;
v1 = x86::ymm1;
v2 = x86::ymm2;
v3 = x86::ymm3;
v4 = x86::ymm4;
v5 = x86::ymm5;
vsize = 32;
}
else
{
v0 = x86::xmm0;
v1 = x86::xmm1;
v2 = x86::xmm2;
v3 = x86::xmm3;
v4 = x86::xmm4;
v5 = x86::xmm5;
vsize = new_vsize ? new_vsize : 16;
}
if (utils::has_avx512())
{
if (!new_vsize)
vmask = -1;
}
else
{
vmask = 0;
}
}
void asmjit::simd_builder::operator()() noexcept
{
for (auto&& [x, y] : consts)
{
this->align(AlignMode::kData, 16);
this->bind(y);
this->embed(&x, 16);
}
}
void asmjit::simd_builder::vec_cleanup_ret()
{
if (utils::has_avx() && vsize > 16)
this->vzeroupper();
this->ret();
}
void asmjit::simd_builder::vec_set_all_zeros(const Operand& v)
{
x86::Xmm reg(v.id());
if (utils::has_avx())
this->vpxor(reg, reg, reg);
else
this->xorps(reg, reg);
}
void asmjit::simd_builder::vec_set_all_ones(const Operand& v)
{
x86::Xmm reg(v.id());
if (x86::Zmm zr(v.id()); zr == v)
this->vpternlogd(zr, zr, zr, 0xff);
else if (x86::Ymm yr(v.id()); yr == v)
this->vpcmpeqd(yr, yr, yr);
else if (utils::has_avx())
this->vpcmpeqd(reg, reg, reg);
else
this->pcmpeqd(reg, reg);
}
void asmjit::simd_builder::vec_set_const(const Operand& v, const v128& val)
{
if (!val._u)
return vec_set_all_zeros(v);
if (!~val._u)
return vec_set_all_ones(v);
else
{
Label co = consts[val];
if (!co.isValid())
co = consts[val] = this->newLabel();
if (x86::Zmm zr(v.id()); zr == v)
this->vbroadcasti32x4(zr, x86::oword_ptr(co));
else if (x86::Ymm yr(v.id()); yr == v)
this->vbroadcasti128(yr, x86::oword_ptr(co));
else if (utils::has_avx())
this->vmovaps(x86::Xmm(v.id()), x86::oword_ptr(co));
else
this->movaps(x86::Xmm(v.id()), x86::oword_ptr(co));
}
}
void asmjit::simd_builder::vec_clobbering_test(u32 esize, const Operand& v, const Operand& rhs)
{
if (esize == 64)
{
this->emit(x86::Inst::kIdVptestmd, x86::k0, v, rhs);
this->ktestw(x86::k0, x86::k0);
}
else if (esize == 32)
{
this->emit(x86::Inst::kIdVptest, v, rhs);
}
else if (esize == 16 && utils::has_avx())
{
this->emit(x86::Inst::kIdVptest, v, rhs);
}
else if (esize == 16 && utils::has_sse41())
{
this->emit(x86::Inst::kIdPtest, v, rhs);
}
else
{
if (v != rhs)
this->emit(x86::Inst::kIdPand, v, rhs);
if (esize == 16)
this->emit(x86::Inst::kIdPacksswb, v, v);
this->emit(x86::Inst::kIdMovq, x86::rax, v);
if (esize == 16 || esize == 8)
this->test(x86::rax, x86::rax);
else if (esize == 4)
this->test(x86::eax, x86::eax);
else if (esize == 2)
this->test(x86::ax, x86::ax);
else if (esize == 1)
this->test(x86::al, x86::al);
else
fmt::throw_exception("Unimplemented");
}
}
void asmjit::simd_builder::vec_broadcast_gpr(u32 esize, const Operand& v, const x86::Gp& r)
{
if (esize == 2)
{
if (utils::has_avx512())
this->emit(x86::Inst::kIdVpbroadcastw, v, r.r32());
else if (utils::has_avx())
{
this->emit(x86::Inst::kIdVmovd, v, r.r32());
if (utils::has_avx2())
this->emit(x86::Inst::kIdVpbroadcastw, v, v);
else
{
this->emit(x86::Inst::kIdVpunpcklwd, v, v, v);
this->emit(x86::Inst::kIdVpshufd, v, v, Imm(0));
}
}
else
{
this->emit(x86::Inst::kIdMovd, v, r.r32());
this->emit(x86::Inst::kIdPunpcklwd, v, v);
this->emit(x86::Inst::kIdPshufd, v, v, Imm(0));
}
}
else if (esize == 4)
{
if (utils::has_avx512())
this->emit(x86::Inst::kIdVpbroadcastd, v, r.r32());
else if (utils::has_avx())
{
this->emit(x86::Inst::kIdVmovd, v, r.r32());
if (utils::has_avx2())
this->emit(x86::Inst::kIdVpbroadcastd, v, v);
else
this->emit(x86::Inst::kIdVpshufd, v, v, Imm(0));
}
else
{
this->emit(x86::Inst::kIdMovd, v, r.r32());
this->emit(x86::Inst::kIdPshufd, v, v, Imm(0));
}
}
else
{
fmt::throw_exception("Unimplemented");
}
}
asmjit::x86::Mem asmjit::simd_builder::ptr_scale_for_vec(u32 esize, const x86::Gp& base, const x86::Gp& index)
{
switch (ensure(esize))
{
case 1: return x86::ptr(base, index, 0, 0);
case 2: return x86::ptr(base, index, 1, 0);
case 4: return x86::ptr(base, index, 2, 0);
case 8: return x86::ptr(base, index, 3, 0);
default: fmt::throw_exception("Bad esize");
}
}
void asmjit::simd_builder::vec_load_unaligned(u32 esize, const Operand& v, const x86::Mem& src)
{
ensure(std::has_single_bit(esize));
ensure(std::has_single_bit(vsize));
if (esize == 2)
{
ensure(vsize >= 2);
if (vsize == 2)
vec_set_all_zeros(v);
if (vsize == 2 && utils::has_avx())
this->emit(x86::Inst::kIdVpinsrw, x86::Xmm(v.id()), x86::Xmm(v.id()), src, Imm(0));
else if (vsize == 2)
this->emit(x86::Inst::kIdPinsrw, v, src, Imm(0));
else if ((vmask && vmask < 8) || vsize >= 64)
this->emit(x86::Inst::kIdVmovdqu16, v, src);
else
return vec_load_unaligned(vsize, v, src);
}
else if (esize == 4)
{
ensure(vsize >= 4);
if (vsize == 4 && utils::has_avx())
this->emit(x86::Inst::kIdVmovd, x86::Xmm(v.id()), src);
else if (vsize == 4)
this->emit(x86::Inst::kIdMovd, v, src);
else if ((vmask && vmask < 8) || vsize >= 64)
this->emit(x86::Inst::kIdVmovdqu32, v, src);
else
return vec_load_unaligned(vsize, v, src);
}
else if (esize == 8)
{
ensure(vsize >= 8);
if (vsize == 8 && utils::has_avx())
this->emit(x86::Inst::kIdVmovq, x86::Xmm(v.id()), src);
else if (vsize == 8)
this->emit(x86::Inst::kIdMovq, v, src);
else if ((vmask && vmask < 8) || vsize >= 64)
this->emit(x86::Inst::kIdVmovdqu64, v, src);
else
return vec_load_unaligned(vsize, v, src);
}
else if (esize >= 16)
{
ensure(vsize >= 16);
if ((vmask && vmask < 8) || vsize >= 64)
this->emit(x86::Inst::kIdVmovdqu64, v, src); // Not really needed
else if (utils::has_avx())
this->emit(x86::Inst::kIdVmovdqu, v, src);
else
this->emit(x86::Inst::kIdMovups, v, src);
}
else
{
fmt::throw_exception("Unimplemented");
}
}
void asmjit::simd_builder::vec_store_unaligned(u32 esize, const Operand& v, const x86::Mem& dst)
{
ensure(std::has_single_bit(esize));
ensure(std::has_single_bit(vsize));
if (esize == 2)
{
ensure(vsize >= 2);
if (vsize == 2 && utils::has_avx())
this->emit(x86::Inst::kIdVpextrw, dst, x86::Xmm(v.id()), Imm(0));
else if (vsize == 2 && utils::has_sse41())
this->emit(x86::Inst::kIdPextrw, dst, v, Imm(0));
else if (vsize == 2)
this->push(x86::rax), this->pextrw(x86::eax, x86::Xmm(v.id()), 0), this->mov(dst, x86::ax), this->pop(x86::rax);
else if ((vmask && vmask < 8) || vsize >= 64)
this->emit(x86::Inst::kIdVmovdqu16, dst, v);
else
return vec_store_unaligned(vsize, v, dst);
}
else if (esize == 4)
{
ensure(vsize >= 4);
if (vsize == 4 && utils::has_avx())
this->emit(x86::Inst::kIdVmovd, dst, x86::Xmm(v.id()));
else if (vsize == 4)
this->emit(x86::Inst::kIdMovd, dst, v);
else if ((vmask && vmask < 8) || vsize >= 64)
this->emit(x86::Inst::kIdVmovdqu32, dst, v);
else
return vec_store_unaligned(vsize, v, dst);
}
else if (esize == 8)
{
ensure(vsize >= 8);
if (vsize == 8 && utils::has_avx())
this->emit(x86::Inst::kIdVmovq, dst, x86::Xmm(v.id()));
else if (vsize == 8)
this->emit(x86::Inst::kIdMovq, dst, v);
else if ((vmask && vmask < 8) || vsize >= 64)
this->emit(x86::Inst::kIdVmovdqu64, dst, v);
else
return vec_store_unaligned(vsize, v, dst);
}
else if (esize >= 16)
{
ensure(vsize >= 16);
if ((vmask && vmask < 8) || vsize >= 64)
this->emit(x86::Inst::kIdVmovdqu64, dst, v); // Not really needed
else if (utils::has_avx())
this->emit(x86::Inst::kIdVmovdqu, dst, v);
else
this->emit(x86::Inst::kIdMovups, dst, v);
}
else
{
fmt::throw_exception("Unimplemented");
}
}
void asmjit::simd_builder::_vec_binary_op(x86::Inst::Id sse_op, x86::Inst::Id vex_op, x86::Inst::Id evex_op, const Operand& dst, const Operand& lhs, const Operand& rhs)
{
if (utils::has_avx())
{
if (evex_op != x86::Inst::kIdNone && (vex_op == x86::Inst::kIdNone || this->_extraReg.isReg() || vsize >= 64))
{
this->evex().emit(evex_op, dst, lhs, rhs);
}
else
{
this->emit(vex_op, dst, lhs, rhs);
}
}
else if (dst == lhs)
{
this->emit(sse_op, dst, rhs);
}
else if (dst == rhs)
{
fmt::throw_exception("Unimplemented");
}
else
{
this->emit(x86::Inst::kIdMovaps, dst, lhs);
this->emit(sse_op, dst, rhs);
}
}
void asmjit::simd_builder::vec_umin(u32 esize, const Operand& dst, const Operand& lhs, const Operand& rhs)
{
using enum x86::Inst::Id;
if (esize == 2)
{
if (utils::has_sse41())
return _vec_binary_op(kIdPminuw, kIdVpminuw, kIdVpminuw, dst, lhs, rhs);
}
else if (esize == 4)
{
if (utils::has_sse41())
return _vec_binary_op(kIdPminud, kIdVpminud, kIdVpminud, dst, lhs, rhs);
}
fmt::throw_exception("Unimplemented");
}
void asmjit::simd_builder::vec_umax(u32 esize, const Operand& dst, const Operand& lhs, const Operand& rhs)
{
using enum x86::Inst::Id;
if (esize == 2)
{
if (utils::has_sse41())
return _vec_binary_op(kIdPmaxuw, kIdVpmaxuw, kIdVpmaxuw, dst, lhs, rhs);
}
else if (esize == 4)
{
if (utils::has_sse41())
return _vec_binary_op(kIdPmaxud, kIdVpmaxud, kIdVpmaxud, dst, lhs, rhs);
}
fmt::throw_exception("Unimplemented");
}
void asmjit::simd_builder::vec_cmp_eq(u32 esize, const Operand& dst, const Operand& lhs, const Operand& rhs)
{
using enum x86::Inst::Id;
if (esize == 2)
{
if (vsize == 64)
{
this->evex().emit(kIdVpcmpeqw, x86::k0, lhs, rhs);
this->evex().emit(kIdVpmovm2w, dst, x86::k0);
}
else
{
_vec_binary_op(kIdPcmpeqw, kIdVpcmpeqw, kIdNone, dst, lhs, rhs);
}
}
else if (esize == 4)
{
if (vsize == 64)
{
this->evex().emit(kIdVpcmpeqd, x86::k0, lhs, rhs);
this->evex().emit(kIdVpmovm2d, dst, x86::k0);
}
else
{
_vec_binary_op(kIdPcmpeqw, kIdVpcmpeqw, kIdNone, dst, lhs, rhs);
}
}
else
{
fmt::throw_exception("Unimplemented");
}
}
void asmjit::simd_builder::vec_extract_high(u32, const Operand& dst, const Operand& src)
{
if (vsize == 32)
this->vextracti32x8(x86::Ymm(dst.id()), x86::Zmm(src.id()), 1);
else if (vsize == 16)
this->vextracti128(x86::Xmm(dst.id()), x86::Ymm(src.id()), 1);
else
{
if (utils::has_avx())
this->vpsrldq(x86::Xmm(dst.id()), x86::Xmm(src.id()), vsize);
else
{
this->movdqa(x86::Xmm(dst.id()), x86::Xmm(src.id()));
this->psrldq(x86::Xmm(dst.id()), vsize);
}
}
}
void asmjit::simd_builder::vec_extract_gpr(u32 esize, const x86::Gp& dst, const Operand& src)
{
if (esize == 8 && utils::has_avx())
this->vmovq(dst.r64(), x86::Xmm(src.id()));
else if (esize == 8)
this->movq(dst.r64(), x86::Xmm(src.id()));
else if (esize == 4 && utils::has_avx())
this->vmovd(dst.r32(), x86::Xmm(src.id()));
else if (esize == 4)
this->movd(dst.r32(), x86::Xmm(src.id()));
else if (esize == 2 && utils::has_avx())
this->vpextrw(dst.r32(), x86::Xmm(src.id()), 0);
else if (esize == 2)
this->pextrw(dst.r32(), x86::Xmm(src.id()), 0);
else
fmt::throw_exception("Unimplemented");
}
#endif /* X86 */
#ifdef LLVM_AVAILABLE
#include <unordered_map>
@@ -996,6 +1487,11 @@ bool jit_compiler::check(const std::string& path)
return false;
}
void jit_compiler::update_global_mapping(const std::string& name, u64 addr)
{
m_engine->updateGlobalMapping(name, addr);
}
void jit_compiler::fin()
{
m_engine->finalizeObject();
+207 -34
View File
@@ -42,6 +42,7 @@
#include <string>
#include <string_view>
#include <unordered_map>
#include <util/v128.hpp>
#if defined(ARCH_X64)
using native_asm = asmjit::x86::Assembler;
@@ -211,40 +212,182 @@ namespace asmjit
}
#if defined(ARCH_X64)
template <uint Size>
struct native_vec;
template <>
struct native_vec<16> { using type = x86::Xmm; };
template <>
struct native_vec<32> { using type = x86::Ymm; };
template <>
struct native_vec<64> { using type = x86::Zmm; };
template <uint Size>
using native_vec_t = typename native_vec<Size>::type;
// if (count > step) { for (; ctr < (count - step); ctr += step) {...} count -= ctr; }
inline void build_incomplete_loop(native_asm& c, auto ctr, auto count, u32 step, auto&& build)
struct simd_builder : native_asm
{
asmjit::Label body = c.newLabel();
asmjit::Label exit = c.newLabel();
std::unordered_map<v128, Label> consts;
ensure((step & (step - 1)) == 0);
c.cmp(count, step);
c.jbe(exit);
c.sub(count, step);
c.align(asmjit::AlignMode::kCode, 16);
c.bind(body);
build();
c.add(ctr, step);
c.sub(count, step);
c.ja(body);
c.add(count, step);
c.bind(exit);
}
Operand v0, v1, v2, v3, v4, v5;
uint vsize = 16;
uint vmask = 0;
simd_builder(CodeHolder* ch) noexcept;
~simd_builder();
void operator()() noexcept;
void _init(uint new_vsize = 0);
void vec_cleanup_ret();
void vec_set_all_zeros(const Operand& v);
void vec_set_all_ones(const Operand& v);
void vec_set_const(const Operand& v, const v128& value);
void vec_clobbering_test(u32 esize, const Operand& v, const Operand& rhs);
void vec_broadcast_gpr(u32 esize, const Operand& v, const x86::Gp& r);
// return x86::ptr(base, ctr, X, 0) where X is set for esize accordingly
x86::Mem ptr_scale_for_vec(u32 esize, const x86::Gp& base, const x86::Gp& index);
void vec_load_unaligned(u32 esize, const Operand& v, const x86::Mem& src);
void vec_store_unaligned(u32 esize, const Operand& v, const x86::Mem& dst);
void vec_partial_move(u32 esize, const Operand& dst, const Operand& src);
void _vec_binary_op(x86::Inst::Id sse_op, x86::Inst::Id vex_op, x86::Inst::Id evex_op, const Operand& dst, const Operand& lhs, const Operand& rhs);
void vec_shuffle_xi8(const Operand& dst, const Operand& lhs, const Operand& rhs)
{
using enum x86::Inst::Id;
_vec_binary_op(kIdPshufb, kIdVpshufb, kIdVpshufb, dst, lhs, rhs);
}
void vec_xor(u32, const Operand& dst, const Operand& lhs, const Operand& rhs)
{
using enum x86::Inst::Id;
_vec_binary_op(kIdPxor, kIdVpxor, kIdVpxord, dst, lhs, rhs);
}
void vec_or(u32, const Operand& dst, const Operand& lhs, const Operand& rhs)
{
using enum x86::Inst::Id;
_vec_binary_op(kIdPor, kIdVpor, kIdVpord, dst, lhs, rhs);
}
void vec_andn(u32, const Operand& dst, const Operand& lhs, const Operand& rhs)
{
using enum x86::Inst::Id;
_vec_binary_op(kIdPandn, kIdVpandn, kIdVpandnd, dst, lhs, rhs);
}
void vec_umin(u32 esize, const Operand& dst, const Operand& lhs, const Operand& rhs);
void vec_umax(u32 esize, const Operand& dst, const Operand& lhs, const Operand& rhs);
void vec_cmp_eq(u32 esize, const Operand& dst, const Operand& lhs, const Operand& rhs);
void vec_extract_high(u32 esize, const Operand& dst, const Operand& src);
void vec_extract_gpr(u32 esize, const x86::Gp& dst, const Operand& src);
simd_builder& keep_if_not_masked()
{
if (vmask && vmask < 8)
{
this->k(x86::KReg(vmask));
}
return *this;
}
simd_builder& zero_if_not_masked()
{
if (vmask && vmask < 8)
{
this->k(x86::KReg(vmask));
this->z();
}
return *this;
}
void build_loop(u32 esize, const x86::Gp& reg_ctr, const x86::Gp& reg_cnt, auto&& build, auto&& reduce)
{
ensure((esize & (esize - 1)) == 0);
ensure(esize <= vsize);
Label body = this->newLabel();
Label next = this->newLabel();
Label exit = this->newLabel();
const u32 step = vsize / esize;
this->xor_(reg_ctr.r32(), reg_ctr.r32()); // Reset counter reg
this->cmp(reg_cnt, step);
this->jb(next); // If count < step, skip main loop body
this->align(AlignMode::kCode, 16);
this->bind(body);
this->sub(reg_cnt, step);
build();
this->add(reg_ctr, step);
this->cmp(reg_cnt, step);
this->jae(body);
this->bind(next);
if (vmask)
{
// Build single last iteration (masked)
this->test(reg_cnt, reg_cnt);
this->jz(exit);
if (esize == 1 && vsize == 64)
{
this->bzhi(reg_cnt.r64(), x86::Mem(consts[~u128()], 0), reg_cnt.r64());
this->kmovq(x86::k7, reg_cnt.r64());
}
else
{
this->bzhi(reg_cnt.r32(), x86::Mem(consts[~u128()], 0), reg_cnt.r32());
this->kmovd(x86::k7, reg_cnt.r32());
}
vmask = 7;
build();
// Rollout reduction step
this->bind(exit);
while (true)
{
vsize /= 2;
if (vsize < esize)
break;
this->_init(vsize);
reduce();
}
}
else
{
// Build unrolled loop tail (reduced vector width)
while (true)
{
vsize /= 2;
if (vsize < esize)
break;
// Shall not clobber flags
this->_init(vsize);
reduce();
if (vsize == esize)
{
// Last "iteration"
this->test(reg_cnt, reg_cnt);
this->jz(exit);
build();
}
else
{
const u32 step = vsize / esize;
Label next = this->newLabel();
this->cmp(reg_cnt, step);
this->jb(next);
build();
this->add(reg_ctr, step);
this->sub(reg_cnt, step);
this->bind(next);
}
}
this->bind(exit);
}
this->_init(0);
}
};
// for (; count > 0; ctr++, count--)
inline void build_loop(native_asm& c, auto ctr, auto count, auto&& build)
@@ -262,19 +405,40 @@ namespace asmjit
c.ja(body);
c.bind(exit);
}
inline void maybe_flush_lbr(native_asm& c, uint count = 2)
{
// Workaround for bad LBR callstacks which happen in some situations (mainly TSX) - execute additional RETs
Label next = c.newLabel();
c.lea(x86::rcx, x86::qword_ptr(next));
for (u32 i = 0; i < count; i++)
{
c.push(x86::rcx);
c.sub(x86::rcx, 16);
}
for (u32 i = 0; i < count; i++)
{
c.ret();
c.align(asmjit::AlignMode::kCode, 16);
}
c.bind(next);
}
#endif
}
// Build runtime function with asmjit::X86Assembler
template <typename FT, typename Asm = native_asm, typename F>
inline FT build_function_asm(std::string_view name, F&& builder)
inline FT build_function_asm(std::string_view name, F&& builder, ::jit_runtime* custom_runtime = nullptr)
{
#ifdef __APPLE__
pthread_jit_write_protect_np(false);
#endif
using namespace asmjit;
auto& rt = get_global_runtime();
auto& rt = custom_runtime ? *custom_runtime : get_global_runtime();
CodeHolder code;
code.init(rt.environment());
@@ -312,6 +476,12 @@ inline FT build_function_asm(std::string_view name, F&& builder)
builder(compiler, args);
}
if constexpr (std::is_invocable_r_v<void, Asm>)
{
// Finalization
compiler();
}
const auto result = rt._add(&code);
jit_announce(result, code.codeSize(), name);
return reinterpret_cast<FT>(uptr(result));
@@ -362,6 +532,9 @@ public:
// Add object (path to obj file)
void add(const std::string& path);
// Update global mapping for a single value
void update_global_mapping(const std::string& name, u64 addr);
// Check object file
static bool check(const std::string& path);
+19 -3
View File
@@ -5,6 +5,8 @@
#include "util/logs.hpp"
#include "util/v128.hpp"
#include <locale>
#include <codecvt>
#include <algorithm>
#include <string_view>
#include "Thread.h"
@@ -13,8 +15,6 @@
#include <Windows.h>
#else
#include <errno.h>
#include <locale>
#include <codecvt>
#endif
std::string wchar_to_utf8(std::wstring_view src)
@@ -26,11 +26,17 @@ std::string wchar_to_utf8(std::wstring_view src)
WideCharToMultiByte(CP_UTF8, 0, src.data(), src.size(), utf8_string.data(), tmp_size, nullptr, nullptr);
return utf8_string;
#else
std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>, wchar_t> converter{};
std::wstring_convert<std::codecvt_utf8<wchar_t>, wchar_t> converter{};
return converter.to_bytes(src.data());
#endif
}
std::string utf16_to_utf8(std::u16string_view src)
{
std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t> converter{};
return converter.to_bytes(src.data());
}
std::wstring utf8_to_wchar(std::string_view src)
{
#ifdef _WIN32
@@ -609,3 +615,13 @@ bool fmt::match(const std::string& source, const std::string& mask)
return true;
}
std::string get_file_extension(const std::string& file_path)
{
if (usz dotpos = file_path.find_last_of('.'); dotpos != std::string::npos && dotpos + 1 < file_path.size())
{
return file_path.substr(dotpos + 1);
}
return {};
}
+7
View File
@@ -10,6 +10,7 @@
std::wstring utf8_to_wchar(std::string_view src);
std::string wchar_to_utf8(std::wstring_view src);
std::string utf16_to_utf8(std::u16string_view src);
// Copy null-terminated string from a std::string or a char array to a char array with truncation
template <typename D, typename T>
@@ -26,6 +27,12 @@ bool try_to_int64(s64* out, std::string_view value, s64 min, s64 max);
// Convert string to unsigned integer
bool try_to_uint64(u64* out, std::string_view value, u64 min, u64 max);
// Convert string to float
bool try_to_float(f64* out, std::string_view value, f64 min, f64 max);
// Get the file extension of a file path ("png", "jpg", etc.)
std::string get_file_extension(const std::string& file_path);
namespace fmt
{
std::string replace_all(std::string_view src, std::string_view from, std::string_view to, usz count = -1);
+14 -16
View File
@@ -8,7 +8,6 @@
#include "Thread.h"
#include "Utilities/JIT.h"
#include <thread>
#include <sstream>
#include <cfenv>
#ifdef _WIN32
@@ -17,6 +16,9 @@
#include <process.h>
#include <sysinfoapi.h>
#else
#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif
#ifdef __APPLE__
#define _XOPEN_SOURCE
#define __USE_GNU
@@ -96,14 +98,6 @@ extern thread_local std::string(*g_tls_log_prefix)();
// Report error and call std::abort(), defined in main.cpp
[[noreturn]] void report_fatal_error(std::string_view);
template <>
void fmt_class_string<std::thread::id>::format(std::string& out, u64 arg)
{
std::ostringstream ss;
ss << get_object(arg);
out += ss.str();
}
std::string dump_useful_thread_info()
{
thread_local volatile bool guard = false;
@@ -1248,16 +1242,18 @@ bool handle_access_violation(u32 addr, bool is_writing, ucontext_t* context) noe
const auto cpu = get_current_cpu_thread();
if (rsx::g_access_violation_handler)
if (addr < RAW_SPU_BASE_ADDR && vm::check_addr(addr) && rsx::g_access_violation_handler)
{
bool state_changed = false;
if (cpu)
{
vm::temporary_unlock(*cpu);
state_changed = vm::temporary_unlock(*cpu);
}
bool handled = rsx::g_access_violation_handler(addr, is_writing);
if (cpu && (cpu->state += cpu_flag::temp, cpu->test_stopped()))
if (state_changed && (cpu->state += cpu_flag::temp, cpu->test_stopped()))
{
//
}
@@ -1536,14 +1532,14 @@ bool handle_access_violation(u32 addr, bool is_writing, ucontext_t* context) noe
// If we fail due to being busy, wait a bit and try again.
while (static_cast<u32>(sending_error) == CELL_EBUSY)
{
thread_ctrl::wait_for(1000);
sending_error = sys_event_port_send(pf_port_id, data1, data2, data3);
if (cpu->is_stopped())
{
sending_error = {};
break;
}
thread_ctrl::wait_for(1000);
sending_error = sys_event_port_send(pf_port_id, data1, data2, data3);
}
if (sending_error)
@@ -1644,7 +1640,7 @@ static void append_thread_name(std::string& msg)
}
else
{
fmt::append(msg, "Thread id = %s.\n", std::this_thread::get_id());
fmt::append(msg, "Thread id = %u.\n", thread_ctrl::get_tid());
}
}
@@ -3139,6 +3135,8 @@ u64 thread_ctrl::get_tid()
{
#ifdef _WIN32
return GetCurrentThreadId();
#elif defined(__linux__)
return syscall(SYS_gettid);
#else
return reinterpret_cast<u64>(pthread_self());
#endif
+9 -1
View File
@@ -635,13 +635,21 @@ public:
// Join thread by thread_state::finished
named_thread& operator=(thread_state s)
{
bool notify_sync = false;
if (s >= thread_state::aborting && thread::m_sync.fetch_op([](u64& v){ return !(v & 3) && (v |= 1); }).second)
{
notify_sync = true;
}
if constexpr (std::is_assignable_v<Context&, thread_state>)
{
static_cast<Context&>(*this) = s;
}
if (s >= thread_state::aborting && thread::m_sync.fetch_op([](u64& v){ return !(v & 3) && (v |= 1); }).second)
if (notify_sync)
{
// Notify after context abortion has been made so all conditions for wake-up be satisfied by the time of notification
thread::m_sync.notify_one(1);
}
+10 -11
View File
@@ -1,37 +1,36 @@
#pragma once
#include "util/types.hpp"
#include "util/vm.hpp"
#include "StrFmt.h"
#include <vector>
#include <algorithm>
namespace utils
{
class address_range_vector;
/**
* Constexprs
* Helpers
*/
constexpr inline u32 page_start(u32 addr)
static inline u32 page_start(u32 addr)
{
return addr & ~4095u;
return addr & ~(c_page_size - 1);
}
constexpr inline u32 next_page(u32 addr)
static inline u32 next_page(u32 addr)
{
return page_start(addr + 4096u);
return page_start(addr) + c_page_size;
}
constexpr inline u32 page_end(u32 addr)
static inline u32 page_end(u32 addr)
{
return next_page(addr) - 1;
}
constexpr inline u32 is_page_aligned(u32 addr)
static inline u32 is_page_aligned(u32 val)
{
return page_start(addr) == addr;
return (val & (c_page_size - 1)) == 0;
}
@@ -186,7 +185,7 @@ namespace utils
bool is_page_range() const
{
return (valid() && start % 4096u == 0 && length() % 4096u == 0);
return (valid() && is_page_aligned(start) && is_page_aligned(length()));
}
address_range to_page_range() const
+4 -4
View File
@@ -939,7 +939,7 @@ std::basic_string<u32> patch_engine::apply(const std::string& name, u8* dst, u32
}
std::basic_string<u32> applied_total;
const auto& container = m_map.at(name);
const auto& container = ::at32(m_map, name);
const auto& serial = Emu.GetTitleID();
const auto& app_version = Emu.GetAppVersion();
@@ -975,7 +975,7 @@ std::basic_string<u32> patch_engine::apply(const std::string& name, u8* dst, u32
continue;
}
const auto& app_versions = serials.at(found_serial);
const auto& app_versions = ::at32(serials, found_serial);
std::string found_app_version;
if (app_versions.find(app_version) != app_versions.end())
@@ -988,7 +988,7 @@ std::basic_string<u32> patch_engine::apply(const std::string& name, u8* dst, u32
is_all_versions = true;
}
if (!found_app_version.empty() && app_versions.at(found_app_version))
if (!found_app_version.empty() && ::at32(app_versions, found_app_version))
{
// This patch is enabled
if (is_all_serials)
@@ -1073,7 +1073,7 @@ void patch_engine::unload(const std::string& name)
return;
}
const auto& container = m_map.at(name);
const auto& container = ::at32(m_map, name);
for (const auto& [description, patch] : container.patch_info_map)
{
+2 -2
View File
@@ -371,12 +371,12 @@ public:
bool bit_test_reset(uint bit) = delete;
bool bit_test_invert(uint bit) = delete;
bool all_of(bs_t arg)
bool all_of(bs_t arg) const
{
return base::load().all_of(arg);
}
bool none_of(bs_t arg)
bool none_of(bs_t arg) const
{
return base::load().none_of(arg);
}
+6
View File
@@ -700,6 +700,12 @@ template<typename T>
struct size3_base
{
T width, height, depth;
template<typename NT>
explicit constexpr operator size3_base<NT>() const
{
return{ static_cast<NT>(width), static_cast<NT>(height), static_cast<NT>(depth) };
}
};
template<typename T>
+29 -3
View File
@@ -6,14 +6,27 @@ void shared_mutex::imp_lock_shared(u32 val)
{
ensure(val < c_err); // "shared_mutex underflow"
// Try to steal the notification bit
if (val & c_sig && m_value.compare_exchange(val, val - c_sig + 1))
{
return;
}
for (int i = 0; i < 10; i++)
{
busy_wait();
if (try_lock_shared())
{
return;
}
const u32 old = m_value;
if (old & c_sig && m_value.compare_and_swap_test(old, old - c_sig + 1))
{
return;
}
busy_wait();
}
// Acquire writer lock and downgrade
@@ -75,11 +88,24 @@ void shared_mutex::imp_lock(u32 val)
{
ensure(val < c_err); // "shared_mutex underflow"
// Try to steal the notification bit
if (val & c_sig && m_value.compare_exchange(val, val - c_sig + c_one))
{
return;
}
for (int i = 0; i < 10; i++)
{
busy_wait();
if (!m_value && try_lock())
const u32 old = m_value;
if (!old && try_lock())
{
return;
}
if (old & c_sig && m_value.compare_and_swap_test(old, old - c_sig + c_one))
{
return;
}
+5
View File
@@ -171,6 +171,11 @@ public:
{
return m_value.load() < c_one - 1;
}
bool has_waiters() const
{
return m_value.load() > c_one;
}
};
// Simplified shared (reader) lock implementation.
+144
View File
@@ -0,0 +1,144 @@
#include "stdafx.h"
#include "stack_trace.h"
#ifdef _WIN32
#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
#define DBGHELP_TRANSLATE_TCHAR
#include <DbgHelp.h>
#include <codecvt>
#else
#include <execinfo.h>
#endif
namespace utils
{
#ifdef _WIN32
std::string wstr_to_utf8(LPWSTR data, int str_len)
{
if (!str_len)
{
return {};
}
// Calculate size
const auto length = WideCharToMultiByte(CP_UTF8, 0, data, str_len, NULL, 0, NULL, NULL);
// Convert
std::vector<char> out(length + 1, 0);
WideCharToMultiByte(CP_UTF8, 0, data, str_len, out.data(), length, NULL, NULL);
return out.data();
}
std::vector<void*> get_backtrace(int max_depth)
{
std::vector<void*> result = {};
const auto hProcess = ::GetCurrentProcess();
const auto hThread = ::GetCurrentThread();
CONTEXT context{};
RtlCaptureContext(&context);
STACKFRAME64 stack = {};
stack.AddrPC.Offset = context.Rip;
stack.AddrPC.Mode = AddrModeFlat;
stack.AddrStack.Offset = context.Rsp;
stack.AddrStack.Mode = AddrModeFlat;
stack.AddrFrame.Offset = context.Rbp;
stack.AddrFrame.Mode = AddrModeFlat;
while (max_depth--)
{
if (!StackWalk64(
IMAGE_FILE_MACHINE_AMD64,
hProcess,
hThread,
&stack,
&context,
NULL,
SymFunctionTableAccess64,
SymGetModuleBase64,
NULL))
{
break;
}
result.push_back(reinterpret_cast<void*>(stack.AddrPC.Offset));
}
return result;
}
std::vector<std::string> get_backtrace_symbols(const std::vector<void*>& stack)
{
std::vector<std::string> result = {};
std::vector<u8> symbol_buf(sizeof(SYMBOL_INFO) + sizeof(TCHAR) * 256);
const auto hProcess = ::GetCurrentProcess();
auto sym = reinterpret_cast<SYMBOL_INFO*>(symbol_buf.data());
sym->SizeOfStruct = sizeof(SYMBOL_INFO);
sym->MaxNameLen = 256;
IMAGEHLP_LINEW64 line_info{};
line_info.SizeOfStruct = sizeof(IMAGEHLP_LINEW64);
SymInitialize(hProcess, NULL, TRUE);
SymSetOptions(SYMOPT_LOAD_LINES);
for (const auto& pointer : stack)
{
DWORD64 unused;
SymFromAddr(hProcess, reinterpret_cast<DWORD64>(pointer), &unused, sym);
if (sym->NameLen)
{
const auto function_name = wstr_to_utf8(sym->Name, static_cast<int>(sym->NameLen));
// Attempt to get file and line information if available
DWORD unused2;
if (SymGetLineFromAddrW(hProcess, reinterpret_cast<DWORD64>(pointer), &unused2, &line_info))
{
const auto full_path = fmt::format("%s:%u %s", wstr_to_utf8(line_info.FileName, -1), line_info.LineNumber, function_name);
result.push_back(full_path);
}
else
{
result.push_back(function_name);
}
}
else
{
result.push_back(fmt::format("rpcs3@0xp", pointer));
}
}
return result;
}
#else
std::vector<void*> get_backtrace(int max_depth)
{
std::vector<void*> result(max_depth);
int depth = backtrace(result.data(), max_depth);
result.resize(depth);
return result;
}
std::vector<std::string> get_backtrace_symbols(const std::vector<void*>& stack)
{
std::vector<std::string> result;
result.reserve(stack.size());
const auto symbols = backtrace_symbols(stack.data(), static_cast<int>(stack.size()));
for (usz i = 0; i < stack.size(); ++i)
{
result.push_back(symbols[i]);
}
free(symbols);
return result;
}
#endif
}
+20
View File
@@ -0,0 +1,20 @@
#pragma once
#include <util/types.hpp>
#include <util/logs.hpp>
namespace utils
{
std::vector<void*> get_backtrace(int max_depth = 255);
std::vector<std::string> get_backtrace_symbols(const std::vector<void*>& stack);
FORCE_INLINE void print_trace(logs::channel& logger, int max_depth = 255)
{
const auto trace = get_backtrace(max_depth);
const auto lines = get_backtrace_symbols(trace);
for (const auto& line : lines)
{
logger.error("%s", line);
}
}
}
+2 -2
View File
@@ -99,13 +99,13 @@ inline int futex(volatile void* uaddr, int futex_op, uint val, const timespec* t
if (!timeout)
{
rec.cv.wait(lock, [&] { return !rec.mask; });
rec.cv.wait(lock, FN(!rec.mask));
}
else if (futex_op == FUTEX_WAIT)
{
const auto nsec = std::chrono::nanoseconds(timeout->tv_nsec + timeout->tv_sec * 1000000000ull);
if (!rec.cv.wait_for(lock, nsec, [&] { return !rec.mask; }))
if (!rec.cv.wait_for(lock, nsec, FN(!rec.mask)))
{
res = -1;
errno = ETIMEDOUT;
+4 -2
View File
@@ -30,7 +30,8 @@ namespace utils
if (lo())
{
version += "." + std::to_string(lo());
version += '.';
version += std::to_string(lo());
}
if (type() != version_type::release)
@@ -40,7 +41,8 @@ namespace utils
version += "-" + postfix();
}
version += " " + utils::to_string(type());
version += ' ';
version += utils::to_string(type());
if (type_index() > 1)
{
+64 -41
View File
@@ -3,6 +3,7 @@ YoRHa Theme for RPCS3
by Ani @ https://github.com/AniLeo
r1 (2018.02.27)
r2 (2021.08.28)
r3 (2022.08.20)
*/
/*
@@ -26,7 +27,7 @@ aea993
/* Every widget */
QWidget {
font-family: SCE-PS3 Rodin LATIN;
font-family: "SCE-PS3 Rodin LATIN";
font-size: 9.00pt;
color: #292929;
@@ -98,6 +99,9 @@ QToolTip {
}
/* Table headers */
QHeaderView {
color: #b3ac98;
}
QHeaderView::section {
text-transform: uppercase;
background: #4d4940;
@@ -109,22 +113,32 @@ QHeaderView::section {
border: none;
}
/* All other Tabs */
/* All Tabs */
QTabBar {
border-bottom: 0.05em solid #4d4940;
text-transform: uppercase;
}
QTabBar::tab {
background: transparent;
width: 4.80em;
padding-left: 0.50em;
padding-right: 0.50em;
padding-top: 0.25em;
padding-bottom: 0.25em;
padding-top: 0.65em;
padding-bottom: 0.65em;
margin-right: 0.25em;
font-size: 10.5pt;
font-weight: 550;
}
QTabBar::tab:last {
margin-right: 0em;
}
QTabBar::tab:!selected:hover {
background: transparent;
color: #4d4940;
}
QTabBar::tab::selected {
background: #4d4940;
color: #aea993;
border-bottom-style: solid;
}
/* Checkboxes */
@@ -153,29 +167,35 @@ QCheckBox::indicator::disabled, QRadioButton::indicator::disabled {
background-color: #828790; /* Gray */
}
/* Combo Boxes */
QComboBox {
/* Combo Boxes, Datetime dropdown */
QComboBox, QDateTimeEdit, QLineEdit {
background: transparent;
color: #4d4940;
border: 0.05em solid #1e1e1e;
border-radius: 0.15em;
padding-bottom: 0.2em;
padding-left: 0.4em;
padding-top: 0.1em;
padding-bottom: 0.1em;
}
QComboBox QAbstractItemView {
background: #b3ac98;
}
QComboBox::disabled {
QComboBox::disabled, QDateTimeEdit::disabled, QLineEdit::disabled {
background: #828790;
color: #4d4940;
}
/* Text boxes need less left padding than combo boxes */
QComboBox {
padding-left: 0.4em;
}
QLineEdit {
padding-left: 0.2em;
}
/* Group Boxes (Settings Dialog) */
QGroupBox {
margin-top: 1em;
border: 0.05em solid #4d4940;
text-transform: uppercase;
font-size: 9.00pt;
}
QGroupBox::title {
subcontrol-origin: margin;
@@ -236,6 +256,10 @@ QDockWidget::close-button, QDockWidget::float-button {
QTabWidget::pane {
border: 0em solid #4d4940;
}
/* Center tabs */
QTabWidget::tab-bar {
alignment: center;
}
/* Top menu bar */
QMenuBar {
@@ -284,6 +308,12 @@ QToolButton::hover {
background-color: #b3ac98;
}
/* Calendar widget */
QCalendarWidget QWidget{
background: #b3ac98;
color: #4d4940;
}
/*** RPCS3 Specifics ***/
@@ -303,40 +333,24 @@ QWidget#trophy_manager, QWidget#cg_disasm, QWidget#log_viewer, QMainWindow#main_
border: 0.05em solid #4d4940;
color: #292929;
font-family: none;
font-size: 9.50pt;
font-size: 9.5pt;
}
/* Pad Settings, Emulator Settings Dialogs: Tabs */
#pad_settings_dialog QTabWidget::tab-bar {
alignment: center;
/* Align the log widget tabs to the left */
QTabWidget#tab_widget_log::tab-bar {
alignment: left;
}
QTabBar#tab_bar_settings, #pad_settings_dialog QTabBar {
border-bottom: 0.05em solid #4d4940;
text-transform: uppercase;
/* Restore log section QTabBar to small sizes */
QTabBar#tab_bar_log {
border-bottom: 0;
}
QTabBar::tab#tab_bar_settings, #pad_settings_dialog QTabBar::tab {
background: transparent;
width: 5.20em;
padding-left: 0.50em;
padding-right: 0.50em;
padding-top: 0.65em;
padding-bottom: 0.65em;
margin-right: 0.25em;
font-size: 10.5pt;
font-weight: 550;
}
QTabBar::tab:last#tab_bar_settings, #pad_settings_dialog QTabBar::tab:last {
margin-right: 0em;
}
QTabBar::tab:!selected:hover#tab_bar_settings, #pad_settings_dialog QTabBar::tab:!selected:hover {
background: transparent;
color: #4d4940;
}
QTabBar::tab::selected#tab_bar_settings, #pad_settings_dialog QTabBar::tab::selected {
background: #4d4940;
color: #aea993;
border-bottom-style: solid;
margin-top: 0.15em;
QTabBar#tab_bar_log::tab {
width: 2.00em;
padding: 0.25em;
font-size: 9.0pt;
font-weight: 400;
margin-right: 0;
}
/* Pad Settings: Controller Image */
@@ -362,6 +376,7 @@ QLineEdit#mw_searchbar {
margin-left: 0.7em;
color: #4d4940;
font-size: 10.25pt;
border: 0em;
}
/* Set Theme UI colors */
@@ -440,3 +455,11 @@ QWidget#trophy_notification_frame {
QSlider#sizeSlider::groove:horizontal {
height: 1.5em;
}
/*
On Patch Creator, it's the patch validation label
since we can't avoid repainting color, let's bold it instead
*/
QLabel#validLabel {
font-weight: 600;
}
Binary file not shown.
+1 -1
Submodule llvm updated: 5521155be5...9b52b6c39a
+8 -2
View File
@@ -26,11 +26,17 @@ struct loaded_npdrm_keys
}
// TODO: Check if correct for ELF files usage
u128 last_key() const
u128 last_key(usz backwards = 0) const
{
backwards++;
const usz pos = dec_keys_pos;
return pos ? dec_keys[(pos - 1) % std::size(dec_keys)].load() : u128{};
return pos >= backwards ? dec_keys[(pos - backwards) % std::size(dec_keys)].load() : u128{};
}
SAVESTATE_INIT_POS(2);
loaded_npdrm_keys() = default;
loaded_npdrm_keys(utils::serial& ar);
void save(utils::serial& ar);
};
struct NPD_HEADER
+3 -1
View File
@@ -53,11 +53,13 @@
</ItemGroup>
<ItemGroup>
<ClInclude Include="Emu\Audio\Cubeb\CubebBackend.h" />
<ClInclude Include="Emu\Audio\Cubeb\cubeb_enumerator.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="Emu\Audio\Cubeb\CubebBackend.cpp" />
<ClCompile Include="Emu\Audio\Cubeb\cubeb_enumerator.cpp" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
</Project>
+6
View File
@@ -10,10 +10,16 @@
<ClCompile Include="Emu\Audio\Cubeb\CubebBackend.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="Emu\Audio\Cubeb\cubeb_enumerator.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="Emu\Audio\Cubeb\CubebBackend.h">
<Filter>Source Files</Filter>
</ClInclude>
<ClInclude Include="Emu\Audio\Cubeb\cubeb_enumerator.h">
<Filter>Source Files</Filter>
</ClInclude>
</ItemGroup>
</Project>
+32 -5
View File
@@ -6,10 +6,16 @@
AudioBackend::AudioBackend() {}
void AudioBackend::SetErrorCallback(std::function<void()> cb)
void AudioBackend::SetWriteCallback(std::function<u32(u32 /* byte_cnt */, void* /* buffer */)> cb)
{
std::lock_guard lock(m_error_cb_mutex);
m_error_callback = cb;
std::lock_guard lock(m_cb_mutex);
m_write_callback = cb;
}
void AudioBackend::SetStateCallback(std::function<void(AudioStateEvent)> cb)
{
std::lock_guard lock(m_state_cb_mutex);
m_state_callback = cb;
}
/*
@@ -105,7 +111,7 @@ std::pair<AudioChannelCnt, AudioChannelCnt> AudioBackend::get_channel_count_and_
audio_out_configuration& audio_out_cfg = g_fxo->get<audio_out_configuration>();
std::lock_guard lock(audio_out_cfg.mtx);
ensure(device_index < audio_out_cfg.out.size());
const audio_out_configuration::audio_out& out = audio_out_cfg.out.at(device_index);
const audio_out_configuration::audio_out& out = ::at32(audio_out_cfg.out, device_index);
return out.get_channel_count_and_downmixer();
}
@@ -114,7 +120,7 @@ AudioChannelCnt AudioBackend::get_max_channel_count(u32 device_index)
audio_out_configuration& audio_out_cfg = g_fxo->get<audio_out_configuration>();
std::lock_guard lock(audio_out_cfg.mtx);
ensure(device_index < audio_out_cfg.out.size());
const audio_out_configuration::audio_out& out = audio_out_cfg.out.at(device_index);
const audio_out_configuration::audio_out& out = ::at32(audio_out_cfg.out, device_index);
AudioChannelCnt count = AudioChannelCnt::STEREO;
@@ -134,3 +140,24 @@ AudioChannelCnt AudioBackend::get_max_channel_count(u32 device_index)
return count;
}
AudioChannelCnt AudioBackend::convert_channel_count(u64 raw)
{
switch (raw)
{
default:
case 8:
return AudioChannelCnt::SURROUND_7_1;
case 7:
case 6:
return AudioChannelCnt::SURROUND_5_1;
case 5:
case 4:
case 3:
case 2:
case 1:
return AudioChannelCnt::STEREO;
case 0:
fmt::throw_exception("Usupported channel count");
}
}
+27 -6
View File
@@ -37,6 +37,12 @@ enum class AudioChannelCnt : u32
SURROUND_7_1 = 8,
};
enum class AudioStateEvent : u32
{
UNSPECIFIED_ERROR,
DEFAULT_DEVICE_MAYBE_CHANGED,
};
class AudioBackend
{
public:
@@ -60,19 +66,21 @@ public:
virtual std::string_view GetName() const = 0;
// (Re)create output stream with new parameters. Blocks until data callback returns.
// If dev_id is empty, then default device will be selected.
// May override channel count if device has smaller number of channels.
// Should return 'true' on success.
virtual bool Open(AudioFreq freq, AudioSampleSize sample_size, AudioChannelCnt ch_cnt) = 0;
virtual bool Open(std::string_view dev_id, AudioFreq freq, AudioSampleSize sample_size, AudioChannelCnt ch_cnt) = 0;
// Reset backend state. Blocks until data callback returns.
virtual void Close() = 0;
// Sets write callback. It's called when backend requests new data to be sent.
// Callback should return number of submitted bytes. Calling other backend functions from callback is unsafe.
virtual void SetWriteCallback(std::function<u32(u32 /* byte_cnt */, void* /* buffer */)> cb) = 0;
virtual void SetWriteCallback(std::function<u32(u32 /* byte_cnt */, void* /* buffer */)> cb);
// Sets error callback. It's called when backend detects uncorrectable error condition in audio chain.
// Sets error callback. It's called when backend detects event in audio chain that needs immediate attention.
// Calling other backend functions from callback is unsafe.
virtual void SetErrorCallback(std::function<void()> cb);
virtual void SetStateCallback(std::function<void(AudioStateEvent)> cb);
/*
* All functions below require that Open() was called prior.
@@ -101,6 +109,11 @@ public:
*/
virtual bool Operational() { return true; }
/*
* This virtual method should be reimplemented if backend can report device changes
*/
virtual bool DefaultDeviceChanged() { return false; }
/*
* Helper methods
*/
@@ -145,6 +158,11 @@ public:
*/
static AudioChannelCnt get_max_channel_count(u32 device_index);
/*
* Converts raw channel count to value usable by backends
*/
static AudioChannelCnt convert_channel_count(u64 raw);
/*
* Downmix audio stream.
*/
@@ -208,8 +226,11 @@ protected:
AudioFreq m_sampling_rate = AudioFreq::FREQ_48K;
AudioChannelCnt m_channels = AudioChannelCnt::STEREO;
shared_mutex m_error_cb_mutex{};
std::function<void()> m_error_callback{};
std::timed_mutex m_cb_mutex{};
std::function<u32(u32, void *)> m_write_callback{};
shared_mutex m_state_cb_mutex{};
std::function<void(AudioStateEvent)> m_state_callback{};
bool m_playing = false;
+366 -57
View File
@@ -2,6 +2,7 @@
#include <algorithm>
#include "util/logs.hpp"
#include "Emu/Audio/audio_device_enumerator.h"
#ifdef _WIN32
#include <Windows.h>
@@ -15,27 +16,46 @@ CubebBackend::CubebBackend()
{
#ifdef _WIN32
// Cubeb requires COM to be initialized on the thread calling cubeb_init on Windows
HRESULT hr = CoInitializeEx(nullptr, COINIT_MULTITHREADED);
if (SUCCEEDED(hr))
if (HRESULT hr = CoInitializeEx(nullptr, COINIT_MULTITHREADED); SUCCEEDED(hr))
{
m_com_init_success = true;
}
#endif
if (int err = cubeb_init(&m_ctx, "RPCS3", nullptr))
cubeb *ctx{};
if (int err = cubeb_init(&ctx, "RPCS3", nullptr))
{
Cubeb.error("cubeb_init() failed: 0x%08x", err);
m_ctx = nullptr;
Cubeb.error("cubeb_init() failed: %i", err);
return;
}
Cubeb.notice("Using backend %s", cubeb_get_backend_id(m_ctx));
if (int err = cubeb_register_device_collection_changed(ctx, CUBEB_DEVICE_TYPE_OUTPUT, device_collection_changed_cb, this))
{
Cubeb.error("cubeb_register_device_collection_changed() failed: %i", err);
}
else
{
m_dev_collection_cb_enabled = true;
}
Cubeb.notice("Using backend %s", cubeb_get_backend_id(ctx));
std::lock_guard cb_lock{m_state_cb_mutex};
m_ctx = ctx;
}
CubebBackend::~CubebBackend()
{
Close();
if (m_dev_collection_cb_enabled)
{
if (int err = cubeb_register_device_collection_changed(m_ctx, CUBEB_DEVICE_TYPE_OUTPUT, nullptr, nullptr))
{
Cubeb.error("cubeb_register_device_collection_changed() failed: %i", err);
}
}
if (m_ctx)
{
cubeb_destroy(m_ctx);
@@ -56,11 +76,27 @@ bool CubebBackend::Initialized()
bool CubebBackend::Operational()
{
std::lock_guard lock(m_error_cb_mutex);
return m_stream != nullptr && !m_reset_req;
return m_stream != nullptr && !m_reset_req.observe();
}
bool CubebBackend::Open(AudioFreq freq, AudioSampleSize sample_size, AudioChannelCnt ch_cnt)
bool CubebBackend::DefaultDeviceChanged()
{
if (m_default_device.empty() || m_reset_req.observe())
{
return false;
}
device_handle device = GetDevice();
if (!device.handle)
{
Cubeb.error("Selected device not found. Trying alternative approach...");
device = GetDefaultDeviceAlt(m_sampling_rate, m_sample_size, m_channels);
}
return !device.handle || device.id != m_default_device;
}
bool CubebBackend::Open(std::string_view dev_id, AudioFreq freq, AudioSampleSize sample_size, AudioChannelCnt ch_cnt)
{
if (!Initialized())
{
@@ -68,12 +104,49 @@ bool CubebBackend::Open(AudioFreq freq, AudioSampleSize sample_size, AudioChanne
return false;
}
std::lock_guard lock(m_cb_mutex);
CloseUnlocked();
Close();
std::lock_guard lock{m_cb_mutex};
const bool use_default_device = dev_id.empty() || dev_id == audio_device_enumerator::DEFAULT_DEV_ID;
if (use_default_device) Cubeb.notice("Trying to open default device");
else Cubeb.notice("Trying to open device with dev_id='%s'", dev_id);
device_handle device = GetDevice(use_default_device ? "" : dev_id);
if (!device.handle)
{
if (use_default_device)
{
device = GetDefaultDeviceAlt(freq, sample_size, ch_cnt);
if (!device.handle)
{
Cubeb.error("Cannot detect default device. Channel count detection unavailable.");
}
}
else
{
Cubeb.error("Device with id=%s not found", dev_id);
return false;
}
}
if (device.ch_cnt == 0)
{
Cubeb.error("Device reported invalid channel count, using stereo instead");
device.ch_cnt = 2;
}
if (use_default_device)
{
std::lock_guard lock{m_state_cb_mutex};
m_default_device = device.id;
}
m_sampling_rate = freq;
m_sample_size = sample_size;
m_channels = ch_cnt;
m_channels = static_cast<AudioChannelCnt>(std::min(static_cast<u32>(convert_channel_count(device.ch_cnt)), static_cast<u32>(ch_cnt)));
full_sample_size = get_channels() * get_sample_size();
cubeb_stream_params stream_param{};
@@ -82,70 +155,69 @@ bool CubebBackend::Open(AudioFreq freq, AudioSampleSize sample_size, AudioChanne
stream_param.channels = get_channels();
stream_param.layout = [&]()
{
switch (ch_cnt)
switch (m_channels)
{
case AudioChannelCnt::STEREO: return CUBEB_LAYOUT_STEREO;
case AudioChannelCnt::SURROUND_5_1: return CUBEB_LAYOUT_3F2_LFE;
case AudioChannelCnt::SURROUND_7_1: return CUBEB_LAYOUT_3F4_LFE;
default:
ensure(false);
return CUBEB_LAYOUT_UNDEFINED;
fmt::throw_exception("Invalid audio channel count");
}
}();
stream_param.prefs = m_dev_collection_cb_enabled && device.handle ? CUBEB_STREAM_PREF_DISABLE_DEVICE_SWITCHING : CUBEB_STREAM_PREF_NONE;
u32 min_latency{};
if (int err = cubeb_get_min_latency(m_ctx, &stream_param, &min_latency))
{
Cubeb.error("cubeb_get_min_latency() failed: 0x%08x", err);
Cubeb.error("cubeb_get_min_latency() failed: %i", err);
min_latency = 0;
}
const u32 stream_latency = std::max(static_cast<u32>(AUDIO_MIN_LATENCY * get_sampling_rate()), min_latency);
if (int err = cubeb_stream_init(m_ctx, &m_stream, "Main stream", nullptr, nullptr, nullptr, &stream_param, stream_latency, data_cb, state_cb, this))
if (int err = cubeb_stream_init(m_ctx, &m_stream, "Main stream", nullptr, nullptr, device.handle, &stream_param, stream_latency, data_cb, state_cb, this))
{
Cubeb.error("cubeb_stream_init() failed: 0x%08x", err);
Cubeb.error("cubeb_stream_init() failed: %i", err);
m_stream = nullptr;
}
else if (int err = cubeb_stream_start(m_stream))
{
Cubeb.error("cubeb_stream_start() failed: 0x%08x", err);
CloseUnlocked();
}
else if (int err = cubeb_stream_set_volume(m_stream, 1.0))
{
Cubeb.error("cubeb_stream_set_volume() failed: 0x%08x", err);
return false;
}
if (m_stream == nullptr)
if (int err = cubeb_stream_start(m_stream))
{
Cubeb.error("Failed to open audio backend. Make sure that no other application is running that might block audio access (e.g. Netflix).");
Cubeb.error("cubeb_stream_start() failed: %i", err);
Close();
return false;
}
if (int err = cubeb_stream_set_volume(m_stream, 1.0))
{
Cubeb.error("cubeb_stream_set_volume() failed: %i", err);
}
return true;
}
void CubebBackend::CloseUnlocked()
void CubebBackend::Close()
{
if (m_stream != nullptr)
{
if (int err = cubeb_stream_stop(m_stream))
{
Cubeb.error("cubeb_stream_stop() failed: 0x%08x", err);
Cubeb.error("cubeb_stream_stop() failed: %i", err);
}
cubeb_stream_destroy(m_stream);
m_stream = nullptr;
}
m_playing = false;
m_last_sample.fill(0);
}
{
std::lock_guard lock{m_cb_mutex};
m_stream = nullptr;
m_playing = false;
m_last_sample.fill(0);
}
void CubebBackend::Close()
{
std::lock_guard lock(m_cb_mutex);
CloseUnlocked();
std::lock_guard lock{m_state_cb_mutex};
m_default_device.clear();
}
void CubebBackend::Play()
@@ -177,12 +249,6 @@ void CubebBackend::Pause()
m_last_sample.fill(0);
}
void CubebBackend::SetWriteCallback(std::function<u32(u32, void *)> cb)
{
std::lock_guard lock(m_cb_mutex);
m_write_callback = cb;
}
f64 CubebBackend::GetCallbackFrameLen()
{
if (m_stream == nullptr)
@@ -194,20 +260,187 @@ f64 CubebBackend::GetCallbackFrameLen()
u32 stream_latency{};
if (int err = cubeb_stream_get_latency(m_stream, &stream_latency))
{
Cubeb.error("cubeb_stream_get_latency() failed: 0x%08x", err);
Cubeb.error("cubeb_stream_get_latency() failed: %i", err);
stream_latency = 0;
}
return std::max<f64>(AUDIO_MIN_LATENCY, static_cast<f64>(stream_latency) / get_sampling_rate());
}
long CubebBackend::data_cb(cubeb_stream* /* stream */, void* user_ptr, void const* /* input_buffer */, void* output_buffer, long nframes)
CubebBackend::device_handle CubebBackend::GetDevice(std::string_view dev_id)
{
const bool default_dev = dev_id.empty();
if (default_dev) Cubeb.notice("Searching for default device");
else Cubeb.notice("Searching for device with dev_id='%s'", dev_id);
cubeb_device_collection dev_collection{};
if (int err = cubeb_enumerate_devices(m_ctx, CUBEB_DEVICE_TYPE_OUTPUT, &dev_collection))
{
Cubeb.error("cubeb_enumerate_devices() failed: %i", err);
return {};
}
if (dev_collection.count == 0)
{
Cubeb.error("No output devices available");
if (int err = cubeb_device_collection_destroy(m_ctx, &dev_collection))
{
Cubeb.error("cubeb_device_collection_destroy() failed: %i", err);
}
return {};
}
Cubeb.notice("Found %d possible output devices", dev_collection.count);
device_handle result{};
for (u64 dev_idx = 0; dev_idx < dev_collection.count; dev_idx++)
{
const cubeb_device_info& dev_info = dev_collection.device[dev_idx];
device_handle device{};
device.handle = dev_info.devid;
device.ch_cnt = dev_info.max_channels;
if (dev_info.device_id)
{
device.id = dev_info.device_id;
}
if (device.id.empty())
{
Cubeb.error("device_id is missing from device");
continue;
}
if (default_dev)
{
if (dev_info.preferred & CUBEB_DEVICE_PREF_MULTIMEDIA)
{
result = std::move(device);
break;
}
}
else if (device.id == dev_id)
{
result = std::move(device);
break;
}
}
if (result.handle)
{
Cubeb.notice("Found device '%s' with %d channels", result.id, result.ch_cnt);
}
else
{
Cubeb.notice("No device found for dev_id='%s'", dev_id);
}
if (int err = cubeb_device_collection_destroy(m_ctx, &dev_collection))
{
Cubeb.error("cubeb_device_collection_destroy() failed: %i", err);
}
return result;
};
CubebBackend::device_handle CubebBackend::GetDefaultDeviceAlt(AudioFreq freq, AudioSampleSize sample_size, AudioChannelCnt ch_cnt)
{
Cubeb.notice("Starting alternative search for default device with freq=%d, sample_size=%d and ch_cnt=%d", static_cast<u32>(freq), static_cast<u32>(sample_size), static_cast<u32>(ch_cnt));
cubeb_stream_params param =
{
.format = sample_size == AudioSampleSize::S16 ? CUBEB_SAMPLE_S16NE : CUBEB_SAMPLE_FLOAT32NE,
.rate = static_cast<u32>(freq),
.channels = static_cast<u32>(ch_cnt),
.layout = CUBEB_LAYOUT_UNDEFINED,
.prefs = CUBEB_STREAM_PREF_DISABLE_DEVICE_SWITCHING
};
u32 min_latency{};
if (int err = cubeb_get_min_latency(m_ctx, &param, &min_latency))
{
Cubeb.error("cubeb_get_min_latency() failed: %i", err);
min_latency = 100;
}
cubeb_stream* tmp_stream{};
static auto dummy_data_cb = [](cubeb_stream*, void*, void const*, void*, long) -> long { return 0; };
static auto dummy_state_cb = [](cubeb_stream*, void*, cubeb_state) {};
if (int err = cubeb_stream_init(m_ctx, &tmp_stream, "Default device detector", nullptr, nullptr, nullptr, &param, min_latency, dummy_data_cb, dummy_state_cb, nullptr))
{
Cubeb.error("cubeb_stream_init() failed: %i", err);
return {};
}
cubeb_device* crnt_dev{};
if (int err = cubeb_stream_get_current_device(tmp_stream, &crnt_dev); err != CUBEB_OK || !crnt_dev)
{
Cubeb.error("cubeb_stream_get_current_device() failed: err=%i, crnt_dev=%d", err, !!crnt_dev);
cubeb_stream_destroy(tmp_stream);
return {};
}
std::string out_dev_name;
if (crnt_dev->output_name)
{
out_dev_name = crnt_dev->output_name;
}
if (int err = cubeb_stream_device_destroy(tmp_stream, crnt_dev))
{
Cubeb.error("cubeb_stream_device_destroy() failed: %i", err);
}
cubeb_stream_destroy(tmp_stream);
if (out_dev_name.empty())
{
Cubeb.notice("No default device available");
return {};
}
return GetDevice(out_dev_name);
}
long CubebBackend::data_cb(cubeb_stream* stream, void* user_ptr, void const* /* input_buffer */, void* output_buffer, long nframes)
{
if (nframes <= 0)
{
Cubeb.error("data_cb called with nframes=%d", nframes);
return 0;
}
if (!output_buffer)
{
Cubeb.error("data_cb called with invalid output_buffer");
return CUBEB_ERROR;
}
if (!stream)
{
Cubeb.error("data_cb called with invalid stream");
return CUBEB_ERROR;
}
CubebBackend* const cubeb = static_cast<CubebBackend*>(user_ptr);
ensure(cubeb);
std::unique_lock lock(cubeb->m_cb_mutex, std::defer_lock);
if (nframes && lock.try_lock() && cubeb->m_write_callback && cubeb->m_playing)
if (!cubeb->m_reset_req.observe() && lock.try_lock_for(std::chrono::microseconds{50}) && cubeb->m_write_callback && cubeb->m_playing)
{
if (stream != cubeb->m_stream)
{
// Cubeb.error("data_cb called with unknown stream");
return CUBEB_ERROR;
}
const u32 sample_size = cubeb->full_sample_size.observe();
const u32 bytes_req = nframes * sample_size;
u32 written = std::min(cubeb->m_write_callback(bytes_req, output_buffer), bytes_req);
@@ -227,26 +460,102 @@ long CubebBackend::data_cb(cubeb_stream* /* stream */, void* user_ptr, void cons
{
// Stream parameters are modified only after stream_destroy. stream_destroy will return
// only after this callback returns, so it's safe to access full_sample_size here.
memset(output_buffer, 0, nframes * cubeb->full_sample_size.observe());
memset(output_buffer, 0, nframes * cubeb->full_sample_size);
}
return nframes;
}
void CubebBackend::state_cb(cubeb_stream* /* stream */, void* user_ptr, cubeb_state state)
void CubebBackend::state_cb(cubeb_stream* stream, void* user_ptr, cubeb_state state)
{
CubebBackend* const cubeb = static_cast<CubebBackend*>(user_ptr);
if (!stream)
{
Cubeb.error("state_cb called with invalid stream");
return;
}
if (state == CUBEB_STATE_ERROR)
CubebBackend* const cubeb = static_cast<CubebBackend*>(user_ptr);
ensure(cubeb);
std::lock_guard lock(cubeb->m_state_cb_mutex);
if (stream != cubeb->m_stream)
{
Cubeb.error("state_cb called with unknown stream");
return;
}
switch (state)
{
case CUBEB_STATE_ERROR:
{
Cubeb.error("Stream entered error state");
std::lock_guard lock(cubeb->m_error_cb_mutex);
cubeb->m_reset_req = true;
if (cubeb->m_error_callback)
if (!cubeb->m_reset_req.test_and_set() && cubeb->m_state_callback)
{
cubeb->m_error_callback();
cubeb->m_state_callback(AudioStateEvent::UNSPECIFIED_ERROR);
}
break;
}
case CUBEB_STATE_STARTED:
{
Cubeb.notice("Stream started");
break;
}
case CUBEB_STATE_STOPPED:
{
Cubeb.notice("Stream stopped");
break;
}
case CUBEB_STATE_DRAINED:
{
Cubeb.notice("Stream drained");
break;
}
default:
{
Cubeb.notice("Stream entered unknown state %d", static_cast<u32>(state));
break;
}
}
}
void CubebBackend::device_collection_changed_cb(cubeb* context, void* user_ptr)
{
Cubeb.notice("Device collection changed");
if (!context)
{
Cubeb.error("device_collection_changed_cb called with invalid stream");
return;
}
CubebBackend* const cubeb = static_cast<CubebBackend*>(user_ptr);
ensure(cubeb);
if (cubeb->m_reset_req.observe())
{
return;
}
std::lock_guard cb_lock{cubeb->m_state_cb_mutex};
if (context != cubeb->m_ctx)
{
Cubeb.error("device_collection_changed_cb called with unkown context");
return;
}
// Non default device is used (or default device cannot be detected)
if (cubeb->m_default_device.empty())
{
Cubeb.notice("Skipping default device notification");
return;
}
if (cubeb->m_state_callback)
{
cubeb->m_state_callback(AudioStateEvent::DEFAULT_DEVICE_MAYBE_CHANGED);
}
}
+18 -6
View File
@@ -20,11 +20,11 @@ public:
bool Initialized() override;
bool Operational() override;
bool DefaultDeviceChanged() override;
bool Open(AudioFreq freq, AudioSampleSize sample_size, AudioChannelCnt ch_cnt) override;
bool Open(std::string_view dev_id, AudioFreq freq, AudioSampleSize sample_size, AudioChannelCnt ch_cnt) override;
void Close() override;
void SetWriteCallback(std::function<u32(u32, void *)> cb) override;
f64 GetCallbackFrameLen() override;
void Play() override;
@@ -39,16 +39,28 @@ private:
bool m_com_init_success = false;
#endif
shared_mutex m_cb_mutex{};
std::function<u32(u32, void *)> m_write_callback{};
std::array<u8, sizeof(float) * static_cast<u32>(AudioChannelCnt::SURROUND_7_1)> m_last_sample{};
atomic_t<u8> full_sample_size = 0;
bool m_reset_req = false;
atomic_t<bool> m_reset_req = false;
// Protected by callback mutex
std::string m_default_device{};
bool m_dev_collection_cb_enabled = false;
// Cubeb callbacks
static long data_cb(cubeb_stream* stream, void* user_ptr, void const* input_buffer, void* output_buffer, long nframes);
static void state_cb(cubeb_stream* stream, void* user_ptr, cubeb_state state);
static void device_collection_changed_cb(cubeb* context, void* user_ptr);
void CloseUnlocked();
struct device_handle
{
cubeb_devid handle{};
std::string id;
u32 ch_cnt{};
};
device_handle GetDevice(std::string_view dev_id = "");
device_handle GetDefaultDeviceAlt(AudioFreq freq, AudioSampleSize sample_size, AudioChannelCnt ch_cnt);
};
+113
View File
@@ -0,0 +1,113 @@
#include "Emu/Audio/Cubeb/cubeb_enumerator.h"
#include "util/logs.hpp"
#include <algorithm>
#ifdef _WIN32
#include <Windows.h>
#include <system_error>
#endif
LOG_CHANNEL(cubeb_dev_enum);
cubeb_enumerator::cubeb_enumerator() : audio_device_enumerator()
{
#ifdef _WIN32
// Cubeb requires COM to be initialized on the thread calling cubeb_init on Windows
HRESULT hr = CoInitializeEx(nullptr, COINIT_MULTITHREADED);
if (SUCCEEDED(hr))
{
com_init_success = true;
}
#endif
if (int err = cubeb_init(&ctx, "RPCS3 device enumeration", nullptr))
{
cubeb_dev_enum.error("cubeb_init() failed: %i", err);
ctx = nullptr;
}
}
cubeb_enumerator::~cubeb_enumerator()
{
if (ctx)
{
cubeb_destroy(ctx);
}
#ifdef _WIN32
if (com_init_success)
{
CoUninitialize();
}
#endif
}
std::vector<audio_device_enumerator::audio_device> cubeb_enumerator::get_output_devices()
{
if (ctx == nullptr)
{
return {};
}
cubeb_device_collection dev_collection{};
if (int err = cubeb_enumerate_devices(ctx, CUBEB_DEVICE_TYPE_OUTPUT, &dev_collection))
{
cubeb_dev_enum.error("cubeb_enumerate_devices() failed: %i", err);
return {};
}
if (dev_collection.count == 0)
{
cubeb_dev_enum.error("No output devices available");
if (int err = cubeb_device_collection_destroy(ctx, &dev_collection))
{
cubeb_dev_enum.error("cubeb_device_collection_destroy() failed: %i", err);
}
return {};
}
std::vector<audio_device> device_list{};
for (u64 dev_idx = 0; dev_idx < dev_collection.count; dev_idx++)
{
const cubeb_device_info& dev_info = dev_collection.device[dev_idx];
if (dev_info.state == CUBEB_DEVICE_STATE_UNPLUGGED)
{
continue;
}
audio_device dev =
{
.id = std::string{dev_info.device_id},
.name = std::string{dev_info.friendly_name},
.max_ch = dev_info.max_channels
};
if (dev.id.empty())
{
cubeb_dev_enum.warning("Empty device id - skipping");
continue;
}
if (dev.name.empty())
{
dev.name = dev.id;
}
cubeb_dev_enum.notice("Found device: id=%s, name=%s, max_ch=%d", dev.id, dev.name, dev.max_ch);
device_list.emplace_back(dev);
}
if (int err = cubeb_device_collection_destroy(ctx, &dev_collection))
{
cubeb_dev_enum.error("cubeb_device_collection_destroy() failed: %i", err);
}
std::sort(device_list.begin(), device_list.end(), [](audio_device_enumerator::audio_device a, audio_device_enumerator::audio_device b)
{
return a.name < b.name;
});
return device_list;
}
+22
View File
@@ -0,0 +1,22 @@
#pragma once
#include "Emu/Audio/audio_device_enumerator.h"
#include "cubeb/cubeb.h"
class cubeb_enumerator final : public audio_device_enumerator
{
public:
cubeb_enumerator();
~cubeb_enumerator() override;
std::vector<audio_device> get_output_devices() override;
private:
cubeb* ctx{};
#ifdef _WIN32
bool com_init_success = false;
#endif
};
+45 -30
View File
@@ -6,6 +6,8 @@
#include "FAudioBackend.h"
#include "Emu/system_config.h"
#include "Emu/System.h"
#include "Emu/Audio/audio_device_enumerator.h"
#include "Utilities/StrUtil.h"
LOG_CHANNEL(FAudio_, "FAudio");
@@ -117,11 +119,10 @@ bool FAudioBackend::Initialized()
bool FAudioBackend::Operational()
{
std::lock_guard lock(m_error_cb_mutex);
return m_source_voice != nullptr && !m_reset_req;
return m_source_voice != nullptr && !m_reset_req.observe();
}
bool FAudioBackend::Open(AudioFreq freq, AudioSampleSize sample_size, AudioChannelCnt ch_cnt)
bool FAudioBackend::Open(std::string_view dev_id, AudioFreq freq, AudioSampleSize sample_size, AudioChannelCnt ch_cnt)
{
if (!Initialized())
{
@@ -132,9 +133,37 @@ bool FAudioBackend::Open(AudioFreq freq, AudioSampleSize sample_size, AudioChann
std::lock_guard lock(m_cb_mutex);
CloseUnlocked();
const bool use_default_dev = dev_id.empty() || dev_id == audio_device_enumerator::DEFAULT_DEV_ID;
u64 devid{};
if (!use_default_dev)
{
if (!try_to_uint64(&devid, dev_id, 0, UINT32_MAX))
{
FAudio_.error("Invalid device id - %s", dev_id);
return false;
}
}
if (u32 res = FAudio_CreateMasteringVoice(m_instance, &m_master_voice, FAUDIO_DEFAULT_CHANNELS, FAUDIO_DEFAULT_SAMPLERATE, 0, static_cast<u32>(devid), nullptr))
{
FAudio_.error("FAudio_CreateMasteringVoice() failed(0x%08x)", res);
m_master_voice = nullptr;
return false;
}
FAudioVoiceDetails vd{};
FAudioVoice_GetVoiceDetails(m_master_voice, &vd);
if (vd.InputChannels == 0)
{
FAudio_.error("Channel count of 0 is invalid");
CloseUnlocked();
return false;
}
m_sampling_rate = freq;
m_sample_size = sample_size;
m_channels = ch_cnt;
m_channels = static_cast<AudioChannelCnt>(std::min(static_cast<u32>(convert_channel_count(vd.InputChannels)), static_cast<u32>(ch_cnt)));;
FAudioWaveFormatEx waveformatex;
waveformatex.wFormatTag = get_convert_to_s16() ? FAUDIO_FORMAT_PCM : FAUDIO_FORMAT_IEEE_FLOAT;
@@ -153,43 +182,30 @@ bool FAudioBackend::Open(AudioFreq freq, AudioSampleSize sample_size, AudioChann
OnLoopEnd = nullptr;
OnVoiceError = nullptr;
if (u32 res = FAudio_CreateMasteringVoice(m_instance, &m_master_voice, FAUDIO_DEFAULT_CHANNELS, FAUDIO_DEFAULT_SAMPLERATE, 0, 0, nullptr))
{
FAudio_.error("FAudio_CreateMasteringVoice() failed(0x%08x)", res);
m_master_voice = nullptr;
}
else if (u32 res = FAudio_CreateSourceVoice(m_instance, &m_source_voice, &waveformatex, 0, FAUDIO_DEFAULT_FREQ_RATIO, this, nullptr, nullptr))
if (u32 res = FAudio_CreateSourceVoice(m_instance, &m_source_voice, &waveformatex, 0, FAUDIO_DEFAULT_FREQ_RATIO, this, nullptr, nullptr))
{
FAudio_.error("FAudio_CreateSourceVoice() failed(0x%08x)", res);
CloseUnlocked();
return false;
}
else if (u32 res = FAudioSourceVoice_Start(m_source_voice, 0, FAUDIO_COMMIT_NOW))
if (u32 res = FAudioSourceVoice_Start(m_source_voice, 0, FAUDIO_COMMIT_NOW))
{
FAudio_.error("FAudioSourceVoice_Start() failed(0x%08x)", res);
CloseUnlocked();
return false;
}
else if (u32 res = FAudioVoice_SetVolume(m_source_voice, 1.0f, FAUDIO_COMMIT_NOW))
if (u32 res = FAudioVoice_SetVolume(m_source_voice, 1.0f, FAUDIO_COMMIT_NOW))
{
FAudio_.error("FAudioVoice_SetVolume() failed(0x%08x)", res);
}
if (m_source_voice == nullptr)
{
FAudio_.error("Failed to open audio backend. Make sure that no other application is running that might block audio access (e.g. Netflix).");
return false;
}
m_data_buf.resize(get_sampling_rate() * get_sample_size() * get_channels() * INTERNAL_BUF_SIZE_MS * static_cast<u32>(FAUDIO_DEFAULT_FREQ_RATIO) / 1000);
m_data_buf.resize(get_sampling_rate() * get_sample_size() * get_channels() * INTERNAL_BUF_SIZE_MS / 1000);
return true;
}
void FAudioBackend::SetWriteCallback(std::function<u32(u32, void *)> cb)
{
std::lock_guard lock(m_cb_mutex);
m_write_callback = cb;
}
f64 FAudioBackend::GetCallbackFrameLen()
{
constexpr f64 _10ms = 0.01;
@@ -218,7 +234,7 @@ void FAudioBackend::OnVoiceProcessingPassStart_func(FAudioVoiceCallback *cb_obj,
FAudioBackend *faudio = static_cast<FAudioBackend *>(cb_obj);
std::unique_lock lock(faudio->m_cb_mutex, std::defer_lock);
if (BytesRequired && lock.try_lock() && faudio->m_write_callback && faudio->m_playing)
if (BytesRequired && !faudio->m_reset_req.observe() && lock.try_lock_for(std::chrono::microseconds{50}) && faudio->m_write_callback && faudio->m_playing)
{
ensure(BytesRequired <= faudio->m_data_buf.size(), "FAudio internal buffer is too small. Report to developers!");
@@ -250,11 +266,10 @@ void FAudioBackend::OnCriticalError_func(FAudioEngineCallback *cb_obj, u32 Error
FAudioBackend *faudio = static_cast<FAudioBackend *>(cb_obj);
std::lock_guard lock(faudio->m_error_cb_mutex);
faudio->m_reset_req = true;
std::lock_guard lock(faudio->m_state_cb_mutex);
if (faudio->m_error_callback)
if (!faudio->m_reset_req.test_and_set() && faudio->m_state_callback)
{
faudio->m_error_callback();
faudio->m_state_callback(AudioStateEvent::UNSPECIFIED_ERROR);
}
}
+2 -5
View File
@@ -24,10 +24,9 @@ public:
bool Initialized() override;
bool Operational() override;
bool Open(AudioFreq freq, AudioSampleSize sample_size, AudioChannelCnt ch_cnt) override;
bool Open(std::string_view dev_id, AudioFreq freq, AudioSampleSize sample_size, AudioChannelCnt ch_cnt) override;
void Close() override;
void SetWriteCallback(std::function<u32(u32, void *)> cb) override;
f64 GetCallbackFrameLen() override;
void Play() override;
@@ -40,12 +39,10 @@ private:
FAudioMasteringVoice* m_master_voice{};
FAudioSourceVoice* m_source_voice{};
shared_mutex m_cb_mutex{};
std::function<u32(u32, void *)> m_write_callback{};
std::vector<u8> m_data_buf{};
std::array<u8, sizeof(float) * static_cast<u32>(AudioChannelCnt::SURROUND_7_1)> m_last_sample{};
bool m_reset_req = false;
atomic_t<bool> m_reset_req = false;
// FAudio voice callbacks
static void OnVoiceProcessingPassStart_func(FAudioVoiceCallback *cb_obj, u32 BytesRequired);
@@ -0,0 +1,90 @@
#ifndef HAVE_FAUDIO
#error "FAudio support disabled but still being built."
#endif
#include "Emu/Audio/FAudio/faudio_enumerator.h"
#include <array>
#include <algorithm>
#include "Utilities/StrUtil.h"
#include "util/logs.hpp"
LOG_CHANNEL(faudio_dev_enum);
faudio_enumerator::faudio_enumerator() : audio_device_enumerator()
{
FAudio *tmp{};
if (u32 res = FAudioCreate(&tmp, 0, FAUDIO_DEFAULT_PROCESSOR))
{
faudio_dev_enum.error("FAudioCreate() failed(0x%08x)", res);
return;
}
// All succeeded, "commit"
instance = tmp;
}
faudio_enumerator::~faudio_enumerator()
{
if (instance != nullptr)
{
FAudio_StopEngine(instance);
FAudio_Release(instance);
}
}
std::vector<audio_device_enumerator::audio_device> faudio_enumerator::get_output_devices()
{
if (!instance)
{
return {};
}
u32 dev_cnt{};
if (u32 res = FAudio_GetDeviceCount(instance, &dev_cnt))
{
faudio_dev_enum.error("FAudio_GetDeviceCount() failed(0x%08x)", res);
return {};
}
if (dev_cnt == 0)
{
faudio_dev_enum.warning("No devices available");
return {};
}
std::vector<audio_device> device_list{};
for (u32 dev_idx = 0; dev_idx < dev_cnt; dev_idx++)
{
FAudioDeviceDetails dev_info{};
if (u32 res = FAudio_GetDeviceDetails(instance, dev_idx, &dev_info))
{
faudio_dev_enum.error("FAudio_GetDeviceDetails() failed(0x%08x)", res);
continue;
}
audio_device dev =
{
.id = std::to_string(dev_idx),
.name = utf16_to_utf8(std::bit_cast<char16_t*>(&dev_info.DisplayName[0])),
.max_ch = dev_info.OutputFormat.Format.nChannels
};
if (dev.name.empty())
{
dev.name = "Device " + dev.id;
}
faudio_dev_enum.notice("Found device: id=%s, name=%s, max_ch=%d", dev.id, dev.name, dev.max_ch);
device_list.emplace_back(dev);
}
std::sort(device_list.begin(), device_list.end(), [](audio_device_enumerator::audio_device a, audio_device_enumerator::audio_device b)
{
return a.name < b.name;
});
return device_list;
}
@@ -0,0 +1,22 @@
#pragma once
#ifndef HAVE_FAUDIO
#error "FAudio support disabled but still being built."
#endif
#include "Emu/Audio/audio_device_enumerator.h"
#include "FAudio.h"
class faudio_enumerator final : public audio_device_enumerator
{
public:
faudio_enumerator();
~faudio_enumerator() override;
std::vector<audio_device> get_output_devices() override;
private:
FAudio* instance{};
};
+1 -4
View File
@@ -10,18 +10,15 @@ public:
std::string_view GetName() const override { return "Null"sv; }
bool Open(AudioFreq /* freq */, AudioSampleSize /* sample_size */, AudioChannelCnt /* ch_cnt */) override
bool Open(std::string_view /* dev_id */, AudioFreq /* freq */, AudioSampleSize /* sample_size */, AudioChannelCnt /* ch_cnt */) override
{
Close();
return true;
}
void Close() override { m_playing = false; }
void SetWriteCallback(std::function<u32(u32, void *)> /* cb */) override {};
f64 GetCallbackFrameLen() override { return 0.01; };
void SetErrorCallback(std::function<void()> /* cb */) override {};
void Play() override { m_playing = true; }
void Pause() override { m_playing = false; }
bool IsPlaying() override { return m_playing; }
+13
View File
@@ -0,0 +1,13 @@
#pragma once
#include "Emu/Audio/audio_device_enumerator.h"
class null_enumerator final : public audio_device_enumerator
{
public:
null_enumerator() {};
~null_enumerator() override {};
std::vector<audio_device> get_output_devices() override { return {}; }
};
+181 -46
View File
@@ -5,6 +5,8 @@
#include <algorithm>
#include "util/logs.hpp"
#include "Emu/System.h"
#include "Emu/Audio/audio_device_enumerator.h"
#include "Utilities/StrUtil.h"
#include "XAudio2Backend.h"
#include <Windows.h>
@@ -14,42 +16,85 @@
LOG_CHANNEL(XAudio);
template <>
void fmt_class_string<ERole>::format(std::string& out, u64 arg)
{
format_enum(out, arg, [](auto value)
{
switch (value)
{
case eConsole: return "eConsole";
case eMultimedia: return "eMultimedia";
case eCommunications: return "eCommunications";
}
return unknown;
});
}
template <>
void fmt_class_string<EDataFlow>::format(std::string& out, u64 arg)
{
format_enum(out, arg, [](auto value)
{
switch (value)
{
case eRender: return "eRender";
case eCapture: return "eCapture";
case eAll: return "eAll";
}
return unknown;
});
}
XAudio2Backend::XAudio2Backend()
: AudioBackend()
{
Microsoft::WRL::ComPtr<IXAudio2> instance;
Microsoft::WRL::ComPtr<IXAudio2> instance{};
Microsoft::WRL::ComPtr<IMMDeviceEnumerator> enumerator{};
// In order to prevent errors on CreateMasteringVoice, apparently we need CoInitializeEx according to:
// https://docs.microsoft.com/en-us/windows/win32/api/xaudio2fx/nf-xaudio2fx-xaudio2createvolumemeter
HRESULT hr = CoInitializeEx(nullptr, COINIT_MULTITHREADED);
if (SUCCEEDED(hr))
if (HRESULT hr = CoInitializeEx(nullptr, COINIT_MULTITHREADED); SUCCEEDED(hr))
{
m_com_init_success = true;
}
hr = XAudio2Create(instance.GetAddressOf(), 0, XAUDIO2_USE_DEFAULT_PROCESSOR);
if (FAILED(hr))
if (HRESULT hr = XAudio2Create(instance.GetAddressOf(), 0, XAUDIO2_USE_DEFAULT_PROCESSOR); FAILED(hr))
{
XAudio.error("XAudio2Create() failed: %s (0x%08x)", std::system_category().message(hr), static_cast<u32>(hr));
return;
}
hr = instance->RegisterForCallbacks(this);
if (FAILED(hr))
if (HRESULT hr = instance->RegisterForCallbacks(this); FAILED(hr))
{
// Some error recovery functionality will be lost, but otherwise backend is operational
XAudio.error("RegisterForCallbacks() failed: %s (0x%08x)", std::system_category().message(hr), static_cast<u32>(hr));
}
// Try to register a listener for device changes
if (HRESULT hr = CoCreateInstance(__uuidof(MMDeviceEnumerator), nullptr, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(enumerator.GetAddressOf())); FAILED(hr))
{
XAudio.error("CoCreateInstance() failed: %s (0x%08x)", std::system_category().message(hr), static_cast<u32>(hr));
return;
}
// All succeeded, "commit"
m_xaudio2_instance = std::move(instance);
m_device_enumerator = std::move(enumerator);
}
XAudio2Backend::~XAudio2Backend()
{
Close();
if (m_device_enumerator != nullptr)
{
m_device_enumerator->UnregisterEndpointNotificationCallback(this);
m_device_enumerator = nullptr;
}
if (m_xaudio2_instance != nullptr)
{
m_xaudio2_instance->StopEngine();
@@ -69,14 +114,13 @@ bool XAudio2Backend::Initialized()
bool XAudio2Backend::Operational()
{
std::lock_guard lock(m_error_cb_mutex);
return m_source_voice != nullptr && !m_reset_req.observe();
}
if (m_dev_listener.output_device_changed())
{
m_reset_req = true;
}
return m_source_voice != nullptr && !m_reset_req;
bool XAudio2Backend::DefaultDeviceChanged()
{
std::lock_guard lock{m_state_cb_mutex};
return !m_reset_req.observe() && m_default_dev_changed;
}
void XAudio2Backend::Play()
@@ -112,8 +156,14 @@ void XAudio2Backend::CloseUnlocked()
m_master_voice = nullptr;
}
m_device_enumerator->UnregisterEndpointNotificationCallback(this);
m_playing = false;
m_last_sample.fill(0);
std::lock_guard lock(m_state_cb_mutex);
m_default_dev_changed = false;
m_current_device.clear();
}
void XAudio2Backend::Close()
@@ -144,7 +194,7 @@ void XAudio2Backend::Pause()
}
}
bool XAudio2Backend::Open(AudioFreq freq, AudioSampleSize sample_size, AudioChannelCnt ch_cnt)
bool XAudio2Backend::Open(std::string_view dev_id, AudioFreq freq, AudioSampleSize sample_size, AudioChannelCnt ch_cnt)
{
if (!Initialized())
{
@@ -155,9 +205,54 @@ bool XAudio2Backend::Open(AudioFreq freq, AudioSampleSize sample_size, AudioChan
std::lock_guard lock(m_cb_mutex);
CloseUnlocked();
const bool use_default_device = dev_id.empty() || dev_id == audio_device_enumerator::DEFAULT_DEV_ID;
std::string selected_dev_id{};
if (use_default_device)
{
Microsoft::WRL::ComPtr<IMMDevice> default_dev{};
if (HRESULT hr = m_device_enumerator->GetDefaultAudioEndpoint(eRender, eConsole, default_dev.GetAddressOf()); FAILED(hr))
{
XAudio.error("GetDefaultAudioEndpoint() failed: %s (0x%08x)", std::system_category().message(hr), static_cast<u32>(hr));
return false;
}
LPWSTR default_id{};
if (HRESULT hr = default_dev->GetId(&default_id); FAILED(hr))
{
XAudio.error("GetId() failed: %s (0x%08x)", std::system_category().message(hr), static_cast<u32>(hr));
return false;
}
selected_dev_id = wchar_to_utf8(std::wstring_view{default_id});
CoTaskMemFree(default_id);
if (selected_dev_id.empty())
{
XAudio.error("Default device id is empty");
return false;
}
}
if (HRESULT hr = m_xaudio2_instance->CreateMasteringVoice(&m_master_voice, 0, 0, 0, utf8_to_wchar(use_default_device ? selected_dev_id : dev_id).c_str()); FAILED(hr))
{
XAudio.error("CreateMasteringVoice() failed: %s (0x%08x)", std::system_category().message(hr), static_cast<u32>(hr));
m_master_voice = nullptr;
return false;
}
XAUDIO2_VOICE_DETAILS vd{};
m_master_voice->GetVoiceDetails(&vd);
if (vd.InputChannels == 0)
{
XAudio.error("Channel count 0 is invalid");
CloseUnlocked();
return false;
}
m_sampling_rate = freq;
m_sample_size = sample_size;
m_channels = ch_cnt;
m_channels = static_cast<AudioChannelCnt>(std::min(static_cast<u32>(convert_channel_count(vd.InputChannels)), static_cast<u32>(ch_cnt)));
WAVEFORMATEX waveformatex{};
waveformatex.wFormatTag = get_convert_to_s16() ? WAVE_FORMAT_PCM : WAVE_FORMAT_IEEE_FLOAT;
@@ -168,65 +263,63 @@ bool XAudio2Backend::Open(AudioFreq freq, AudioSampleSize sample_size, AudioChan
waveformatex.wBitsPerSample = get_sample_size() * 8;
waveformatex.cbSize = 0;
if (HRESULT hr = m_xaudio2_instance->CreateMasteringVoice(&m_master_voice); FAILED(hr))
{
XAudio.error("CreateMasteringVoice() failed: %s (0x%08x)", std::system_category().message(hr), static_cast<u32>(hr));
m_master_voice = nullptr;
}
else if (HRESULT hr = m_xaudio2_instance->CreateSourceVoice(&m_source_voice, &waveformatex, 0, XAUDIO2_DEFAULT_FREQ_RATIO, this); FAILED(hr))
if (HRESULT hr = m_xaudio2_instance->CreateSourceVoice(&m_source_voice, &waveformatex, 0, XAUDIO2_DEFAULT_FREQ_RATIO, this); FAILED(hr))
{
XAudio.error("CreateSourceVoice() failed: %s (0x%08x)", std::system_category().message(hr), static_cast<u32>(hr));
CloseUnlocked();
return false;
}
else if (HRESULT hr = m_source_voice->Start(); FAILED(hr))
if (HRESULT hr = m_source_voice->Start(); FAILED(hr))
{
XAudio.error("Start() failed: %s (0x%08x)", std::system_category().message(hr), static_cast<u32>(hr));
CloseUnlocked();
return false;
}
else if (HRESULT hr = m_source_voice->SetVolume(1.0f); FAILED(hr))
if (HRESULT hr = m_device_enumerator->RegisterEndpointNotificationCallback(this); FAILED(hr))
{
XAudio.error("RegisterEndpointNotificationCallback() failed: %s (0x%08x)", std::system_category().message(hr), static_cast<u32>(hr));
CloseUnlocked();
return false;
}
if (HRESULT hr = m_source_voice->SetVolume(1.0f); FAILED(hr))
{
XAudio.error("SetVolume() failed: %s (0x%08x)", std::system_category().message(hr), static_cast<u32>(hr));
}
if (m_source_voice == nullptr)
m_data_buf.resize(get_sampling_rate() * get_sample_size() * get_channels() * INTERNAL_BUF_SIZE_MS / 1000);
if (use_default_device)
{
XAudio.error("Failed to open audio backend. Make sure that no other application is running that might block audio access (e.g. Netflix).");
return false;
m_current_device = selected_dev_id;
}
m_data_buf.resize(get_sampling_rate() * get_sample_size() * get_channels() * INTERNAL_BUF_SIZE_MS * static_cast<u32>(XAUDIO2_DEFAULT_FREQ_RATIO) / 1000);
return true;
}
void XAudio2Backend::SetWriteCallback(std::function<u32(u32, void *)> cb)
{
std::lock_guard lock(m_cb_mutex);
m_write_callback = cb;
}
f64 XAudio2Backend::GetCallbackFrameLen()
{
constexpr f64 _10ms = 0.01;
if (m_source_voice == nullptr)
if (m_xaudio2_instance == nullptr)
{
XAudio.error("GetCallbackFrameLen() called uninitialized");
return _10ms;
}
void *ext;
Microsoft::WRL::ComPtr<IXAudio2Extension> xaudio_ext{};
f64 min_latency{};
const HRESULT hr = m_xaudio2_instance->QueryInterface(IID_IXAudio2Extension, &ext);
if (FAILED(hr))
if (HRESULT hr = m_xaudio2_instance->QueryInterface(IID_IXAudio2Extension, std::bit_cast<void**>(xaudio_ext.GetAddressOf())); FAILED(hr))
{
XAudio.error("QueryInterface() failed: %s (0x%08x)", std::system_category().message(hr), static_cast<u32>(hr));
}
else
{
u32 samples_per_q = 0, freq = 0;
static_cast<IXAudio2Extension *>(ext)->GetProcessingQuantum(&samples_per_q, &freq);
xaudio_ext->GetProcessingQuantum(&samples_per_q, &freq);
if (freq)
{
@@ -240,7 +333,7 @@ f64 XAudio2Backend::GetCallbackFrameLen()
void XAudio2Backend::OnVoiceProcessingPassStart(UINT32 BytesRequired)
{
std::unique_lock lock(m_cb_mutex, std::defer_lock);
if (BytesRequired && lock.try_lock() && m_write_callback && m_playing)
if (BytesRequired && !m_reset_req.observe() && lock.try_lock_for(std::chrono::microseconds{50}) && m_write_callback && m_playing)
{
ensure(BytesRequired <= m_data_buf.size(), "XAudio internal buffer is too small. Report to developers!");
@@ -270,11 +363,53 @@ void XAudio2Backend::OnCriticalError(HRESULT Error)
{
XAudio.error("OnCriticalError() called: %s (0x%08x)", std::system_category().message(Error), static_cast<u32>(Error));
std::lock_guard lock(m_error_cb_mutex);
m_reset_req = true;
std::lock_guard lock(m_state_cb_mutex);
if (m_error_callback)
if (!m_reset_req.test_and_set() && m_state_callback)
{
m_error_callback();
m_state_callback(AudioStateEvent::UNSPECIFIED_ERROR);
}
}
HRESULT XAudio2Backend::OnDefaultDeviceChanged(EDataFlow flow, ERole role, LPCWSTR new_default_device_id)
{
XAudio.notice("OnDefaultDeviceChanged(flow=%s, role=%s, new_default_device_id=0x%x)", flow, role, new_default_device_id);
if (!new_default_device_id)
{
XAudio.notice("OnDefaultDeviceChanged(): new_default_device_id empty");
return S_OK;
}
// Listen only for one device role, otherwise we're going to receive more than one notification for flow type
if (role != eConsole)
{
XAudio.notice("OnDefaultDeviceChanged(): we don't care about this device");
return S_OK;
}
std::lock_guard lock(m_state_cb_mutex);
// Non default device is used
if (m_current_device.empty())
{
return S_OK;
}
const std::string new_device_id = wchar_to_utf8(std::wstring_view{new_default_device_id});
if (flow == eRender || flow == eAll)
{
if (!m_reset_req.observe() && new_device_id != m_current_device)
{
m_default_dev_changed = true;
if (m_state_callback)
{
m_state_callback(AudioStateEvent::DEFAULT_DEVICE_MAYBE_CHANGED);
}
}
}
return S_OK;
}
+21 -9
View File
@@ -7,12 +7,12 @@
#include <memory>
#include "Utilities/mutex.h"
#include "Emu/Audio/AudioBackend.h"
#include "Emu/Audio/audio_device_listener.h"
#include <xaudio2redist.h>
#include <wrl/client.h>
#include <MMDeviceAPI.h>
class XAudio2Backend final : public AudioBackend, public IXAudio2VoiceCallback, public IXAudio2EngineCallback
class XAudio2Backend final : public AudioBackend, public IXAudio2VoiceCallback, public IXAudio2EngineCallback, public IMMNotificationClient
{
public:
XAudio2Backend();
@@ -25,11 +25,11 @@ public:
bool Initialized() override;
bool Operational() override;
bool DefaultDeviceChanged() override;
bool Open(AudioFreq freq, AudioSampleSize sample_size, AudioChannelCnt ch_cnt) override;
bool Open(std::string_view dev_id, AudioFreq freq, AudioSampleSize sample_size, AudioChannelCnt ch_cnt) override;
void Close() override;
void SetWriteCallback(std::function<u32(u32, void *)> cb) override;
f64 GetCallbackFrameLen() override;
void Play() override;
@@ -43,14 +43,16 @@ private:
IXAudio2SourceVoice* m_source_voice{};
bool m_com_init_success = false;
shared_mutex m_cb_mutex{};
std::function<u32(u32, void *)> m_write_callback{};
Microsoft::WRL::ComPtr<IMMDeviceEnumerator> m_device_enumerator{};
// Protected by state callback mutex
std::string m_current_device{};
bool m_default_dev_changed = false;
std::vector<u8> m_data_buf{};
std::array<u8, sizeof(float) * static_cast<u32>(AudioChannelCnt::SURROUND_7_1)> m_last_sample{};
bool m_reset_req = false;
audio_device_listener m_dev_listener{};
atomic_t<bool> m_reset_req = false;
// XAudio voice callbacks
void OnVoiceProcessingPassStart(UINT32 BytesRequired) override;
@@ -66,5 +68,15 @@ private:
void OnProcessingPassEnd() override {};
void OnCriticalError(HRESULT Error) override;
// IMMNotificationClient callbacks
IFACEMETHODIMP_(ULONG) AddRef() override { return 1; };
IFACEMETHODIMP_(ULONG) Release() override { return 1; };
IFACEMETHODIMP QueryInterface(REFIID /*iid*/, void** /*object*/) override { return E_NOINTERFACE; };
IFACEMETHODIMP OnPropertyValueChanged(LPCWSTR /*device_id*/, const PROPERTYKEY /*key*/) override { return S_OK; };
IFACEMETHODIMP OnDeviceAdded(LPCWSTR /*device_id*/) override { return S_OK; };
IFACEMETHODIMP OnDeviceRemoved(LPCWSTR /*device_id*/) override { return S_OK; };
IFACEMETHODIMP OnDeviceStateChanged(LPCWSTR /*device_id*/, DWORD /*new_state*/) override { return S_OK; };
IFACEMETHODIMP OnDefaultDeviceChanged(EDataFlow flow, ERole role, LPCWSTR new_default_device_id) override;
void CloseUnlocked();
};
@@ -0,0 +1,153 @@
#ifndef _WIN32
#error "XAudio2 can only be built on Windows."
#endif
#include "Emu/Audio/XAudio2/xaudio2_enumerator.h"
#include "util/logs.hpp"
#include "Utilities/StrUtil.h"
#include <algorithm>
#include <wrl/client.h>
#include <Windows.h>
#include <system_error>
#include <mmdeviceapi.h>
#include <Functiondiscoverykeys_devpkey.h>
LOG_CHANNEL(xaudio_dev_enum);
xaudio2_enumerator::xaudio2_enumerator() : audio_device_enumerator()
{
}
xaudio2_enumerator::~xaudio2_enumerator()
{
}
std::vector<audio_device_enumerator::audio_device> xaudio2_enumerator::get_output_devices()
{
Microsoft::WRL::ComPtr<IMMDeviceEnumerator> devEnum{};
if (HRESULT hr = CoCreateInstance(__uuidof(MMDeviceEnumerator), nullptr, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(devEnum.GetAddressOf())); FAILED(hr))
{
xaudio_dev_enum.error("CoCreateInstance() failed: %s (0x%08x)", std::system_category().message(hr), static_cast<u32>(hr));
return {};
}
Microsoft::WRL::ComPtr<IMMDeviceCollection> devices{};
if (HRESULT hr = devEnum->EnumAudioEndpoints(eRender, DEVICE_STATE_ACTIVE | DEVICE_STATE_DISABLED, &devices); FAILED(hr))
{
xaudio_dev_enum.error("EnumAudioEndpoints() failed: %s (0x%08x)", std::system_category().message(hr), static_cast<u32>(hr));
return {};
}
UINT count = 0;
if (HRESULT hr = devices->GetCount(&count); FAILED(hr))
{
xaudio_dev_enum.error("devices->GetCount() failed: %s (0x%08x)", std::system_category().message(hr), static_cast<u32>(hr));
return {};
}
if (count == 0)
{
xaudio_dev_enum.warning("No devices available");
return {};
}
std::vector<audio_device> device_list{};
for (UINT dev_idx = 0; dev_idx < count; dev_idx++)
{
Microsoft::WRL::ComPtr<IMMDevice> endpoint{};
if (HRESULT hr = devices->Item(dev_idx, endpoint.GetAddressOf()); FAILED(hr))
{
xaudio_dev_enum.error("devices->Item() failed: %s (0x%08x)", std::system_category().message(hr), static_cast<u32>(hr));
continue;
}
LPWSTR id = nullptr;
if (HRESULT hr = endpoint->GetId(&id); FAILED(hr))
{
xaudio_dev_enum.error("endpoint->GetId() failed: %s (0x%08x)", std::system_category().message(hr), static_cast<u32>(hr));
continue;
}
if (std::wstring_view{id}.empty())
{
xaudio_dev_enum.error("Empty device id - skipping");
CoTaskMemFree(id);
continue;
}
audio_device dev{};
dev.id = wchar_to_utf8(id);
CoTaskMemFree(id);
Microsoft::WRL::ComPtr<IPropertyStore> props{};
if (HRESULT hr = endpoint->OpenPropertyStore(STGM_READ, props.GetAddressOf()); FAILED(hr))
{
xaudio_dev_enum.error("endpoint->OpenPropertyStore() failed: %s (0x%08x)", std::system_category().message(hr), static_cast<u32>(hr));
continue;
}
PROPVARIANT var;
PropVariantInit(&var);
if (HRESULT hr = props->GetValue(PKEY_Device_FriendlyName, &var); FAILED(hr))
{
xaudio_dev_enum.error("props->GetValue() failed: %s (0x%08x)", std::system_category().message(hr), static_cast<u32>(hr));
PropVariantClear(&var);
continue;
}
if (var.vt != VT_LPWSTR)
{
PropVariantClear(&var);
continue;
}
dev.name = wchar_to_utf8(var.pwszVal);
if (dev.name.empty())
{
dev.name = dev.id;
}
PropVariantClear(&var);
dev.max_ch = 2;
if (HRESULT hr = props->GetValue(PKEY_AudioEngine_DeviceFormat, &var); SUCCEEDED(hr))
{
if (var.vt == VT_BLOB)
{
if (var.blob.cbSize == sizeof(PCMWAVEFORMAT))
{
const PCMWAVEFORMAT* pcm = std::bit_cast<const PCMWAVEFORMAT*>(var.blob.pBlobData);
dev.max_ch = pcm->wf.nChannels;
}
else if (var.blob.cbSize >= sizeof(WAVEFORMATEX))
{
const WAVEFORMATEX* wfx = std::bit_cast<const WAVEFORMATEX*>(var.blob.pBlobData);
if (var.blob.cbSize >= sizeof(WAVEFORMATEX) + wfx->cbSize || wfx->wFormatTag == WAVE_FORMAT_PCM)
{
dev.max_ch = wfx->nChannels;
}
}
}
}
else
{
xaudio_dev_enum.error("props->GetValue() failed: %s (0x%08x)", std::system_category().message(hr), static_cast<u32>(hr));
}
PropVariantClear(&var);
xaudio_dev_enum.notice("Found device: id=%s, name=%s, max_ch=%d", dev.id, dev.name, dev.max_ch);
device_list.emplace_back(dev);
}
std::sort(device_list.begin(), device_list.end(), [](audio_device_enumerator::audio_device a, audio_device_enumerator::audio_device b)
{
return a.name < b.name;
});
return device_list;
}
@@ -0,0 +1,17 @@
#pragma once
#ifndef _WIN32
#error "XAudio2 can only be built on Windows."
#endif
#include "Emu/Audio/audio_device_enumerator.h"
class xaudio2_enumerator final : public audio_device_enumerator
{
public:
xaudio2_enumerator();
~xaudio2_enumerator() override;
std::vector<audio_device> get_output_devices() override;
};
+26
View File
@@ -0,0 +1,26 @@
#pragma once
#include "util/types.hpp"
#include <vector>
#include <string>
class audio_device_enumerator
{
public:
static constexpr std::string_view DEFAULT_DEV_ID = "@@@default@@@";
struct audio_device
{
std::string id{};
std::string name{};
usz max_ch{};
};
audio_device_enumerator() {};
virtual ~audio_device_enumerator() = default;
// Enumerate available output devices.
virtual std::vector<audio_device> get_output_devices() = 0;
};
-147
View File
@@ -1,147 +0,0 @@
#include "stdafx.h"
#include "audio_device_listener.h"
#include "util/logs.hpp"
#include "Utilities/StrUtil.h"
#include "Emu/Cell/Modules/cellAudio.h"
#include "Emu/IdManager.h"
LOG_CHANNEL(IO);
audio_device_listener::audio_device_listener()
{
#ifdef _WIN32
HRESULT hr = CoInitializeEx(nullptr, COINIT_MULTITHREADED);
if (SUCCEEDED(hr))
{
m_com_init_success = true;
}
// Try to register a listener for device changes
hr = CoCreateInstance(__uuidof(MMDeviceEnumerator), nullptr, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&m_device_enumerator));
if (hr != S_OK)
{
IO.error("CoCreateInstance() failed: %s (0x%08x)", std::system_category().message(hr), static_cast<u32>(hr));
}
else if (m_device_enumerator)
{
hr = m_device_enumerator->RegisterEndpointNotificationCallback(this);
if (FAILED(hr))
{
IO.error("RegisterEndpointNotificationCallback() failed: %s (0x%08x)", std::system_category().message(hr), static_cast<u32>(hr));
m_device_enumerator->Release();
}
}
else
{
IO.error("Device enumerator invalid");
}
#endif
}
audio_device_listener::~audio_device_listener()
{
#ifdef _WIN32
if (m_device_enumerator != nullptr)
{
m_device_enumerator->UnregisterEndpointNotificationCallback(this);
m_device_enumerator->Release();
}
if (m_com_init_success)
{
CoUninitialize();
}
#endif
}
bool audio_device_listener::input_device_changed()
{
return m_input_device_changed.test_and_reset();
}
bool audio_device_listener::output_device_changed()
{
return m_output_device_changed.test_and_reset();
}
#ifdef _WIN32
template <>
void fmt_class_string<ERole>::format(std::string& out, u64 arg)
{
format_enum(out, arg, [](auto value)
{
switch (value)
{
case eConsole: return "eConsole";
case eMultimedia: return "eMultimedia";
case eCommunications: return "eCommunications";
}
return unknown;
});
}
template <>
void fmt_class_string<EDataFlow>::format(std::string& out, u64 arg)
{
format_enum(out, arg, [](auto value)
{
switch (value)
{
case eRender: return "eRender";
case eCapture: return "eCapture";
case eAll: return "eAll";
}
return unknown;
});
}
HRESULT audio_device_listener::OnDefaultDeviceChanged(EDataFlow flow, ERole role, LPCWSTR new_default_device_id)
{
IO.notice("OnDefaultDeviceChanged(flow=%s, role=%s, new_default_device_id=0x%x)", flow, role, new_default_device_id);
if (!new_default_device_id)
{
IO.notice("OnDefaultDeviceChanged(): new_default_device_id empty");
return S_OK;
}
// Listen only for one device role, otherwise we're going to receive more than one
// notification for flow type
if (role != eConsole)
{
IO.notice("OnDefaultDeviceChanged(): we don't care about this device");
return S_OK;
}
const std::wstring tmp(new_default_device_id);
const std::string new_device_id = wchar_to_utf8(tmp.c_str());
if (flow == eRender || flow == eAll)
{
if (output_device_id != new_device_id)
{
output_device_id = new_device_id;
IO.warning("Default output device changed: new device = '%s'", output_device_id);
m_output_device_changed = true;
}
}
if (flow == eCapture || flow == eAll)
{
if (input_device_id != new_device_id)
{
input_device_id = new_device_id;
IO.warning("Default input device changed: new device = '%s'", input_device_id);
m_input_device_changed = true;
}
}
return S_OK;
}
#endif
-42
View File
@@ -1,42 +0,0 @@
#pragma once
#ifdef _WIN32
#include <MMDeviceAPI.h>
#endif
#include "util/atomic.hpp"
#ifdef _WIN32
class audio_device_listener : public IMMNotificationClient
#else
class audio_device_listener
#endif
{
public:
audio_device_listener();
~audio_device_listener();
bool input_device_changed();
bool output_device_changed();
private:
#ifdef _WIN32
std::string input_device_id;
std::string output_device_id;
IFACEMETHODIMP_(ULONG) AddRef() override { return 1; };
IFACEMETHODIMP_(ULONG) Release() override { return 1; };
IFACEMETHODIMP QueryInterface(REFIID /*iid*/, void** /*object*/) override { return S_OK; };
IFACEMETHODIMP OnPropertyValueChanged(LPCWSTR /*device_id*/, const PROPERTYKEY /*key*/) override { return S_OK; };
IFACEMETHODIMP OnDeviceAdded(LPCWSTR /*device_id*/) override { return S_OK; };
IFACEMETHODIMP OnDeviceRemoved(LPCWSTR /*device_id*/) override { return S_OK; };
IFACEMETHODIMP OnDeviceStateChanged(LPCWSTR /*device_id*/, DWORD /*new_state*/) override { return S_OK; };
IFACEMETHODIMP OnDefaultDeviceChanged(EDataFlow flow, ERole role, LPCWSTR new_default_device_id) override;
IMMDeviceEnumerator* m_device_enumerator = nullptr;
bool m_com_init_success = false;
#endif
atomic_t<bool> m_input_device_changed = false;
atomic_t<bool> m_output_device_changed = false;
};
+18 -7
View File
@@ -2,6 +2,7 @@ add_library(rpcs3_emu
cache_utils.cpp
IdManager.cpp
localized_string.cpp
savestate_utils.cpp
System.cpp
system_config.cpp
system_config_types.cpp
@@ -36,7 +37,6 @@ target_include_directories(rpcs3_emu
PUBLIC
${RPCS3_SRC_DIR})
# Utilities
target_sources(rpcs3_emu PRIVATE
../util/atomic.cpp
@@ -58,6 +58,7 @@ target_sources(rpcs3_emu PRIVATE
../../Utilities/rXml.cpp
../../Utilities/sema.cpp
../../Utilities/simple_ringbuf.cpp
../../Utilities/stack_trace.cpp
../../Utilities/StrFmt.cpp
../../Utilities/Thread.cpp
../../Utilities/version.cpp
@@ -115,20 +116,22 @@ target_sources(rpcs3_emu PRIVATE
../Loader/TRP.cpp
)
# Audio
target_sources(rpcs3_emu PRIVATE
Audio/audio_device_listener.cpp
Audio/audio_resampler.cpp
Audio/AudioDumper.cpp
Audio/AudioBackend.cpp
Audio/Cubeb/CubebBackend.cpp
Audio/Cubeb/cubeb_enumerator.cpp
)
if(USE_FAUDIO)
find_package(SDL2)
if(SDL2_FOUND AND NOT SDL2_VERSION VERSION_LESS 2.0.9)
target_sources(rpcs3_emu PRIVATE Audio/FAudio/FAudioBackend.cpp)
target_sources(rpcs3_emu PRIVATE
Audio/FAudio/FAudioBackend.cpp
Audio/FAudio/faudio_enumerator.cpp
)
target_link_libraries(rpcs3_emu PUBLIC 3rdparty::faudio)
endif()
endif()
@@ -139,6 +142,7 @@ if(WIN32)
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /DELAYLOAD:xaudio2_9redist.dll")
target_sources(rpcs3_emu PRIVATE
Audio/XAudio2/XAudio2Backend.cpp
Audio/XAudio2/xaudio2_enumerator.cpp
)
endif()
@@ -182,6 +186,7 @@ target_sources(rpcs3_emu PRIVATE
Cell/lv2/sys_event.cpp
Cell/lv2/sys_event_flag.cpp
Cell/lv2/sys_fs.cpp
Cell/lv2/sys_game.cpp
Cell/lv2/sys_gamepad.cpp
Cell/lv2/sys_gpio.cpp
Cell/lv2/sys_hid.cpp
@@ -259,6 +264,7 @@ target_sources(rpcs3_emu PRIVATE
Cell/Modules/cellMsgDialog.cpp
Cell/Modules/cellMusic.cpp
Cell/Modules/cellMusicDecode.cpp
Cell/Modules/cellMusicSelectionContext.cpp
Cell/Modules/cellMusicExport.cpp
Cell/Modules/cellNetAoi.cpp
Cell/Modules/cellNetCtl.cpp
@@ -332,7 +338,7 @@ target_sources(rpcs3_emu PRIVATE
Cell/Modules/sceNpUtil.cpp
Cell/Modules/StaticHLE.cpp
Cell/Modules/sys_crashdump.cpp
Cell/Modules/sys_game.cpp
Cell/Modules/sys_game_.cpp
Cell/Modules/sys_heap.cpp
Cell/Modules/sys_io_.cpp
Cell/Modules/sys_libc_.cpp
@@ -408,7 +414,6 @@ target_sources(rpcs3_emu PRIVATE
Memory/vm.cpp
)
# RSX
target_sources(rpcs3_emu PRIVATE
RSX/gcm_enums.cpp
@@ -430,6 +435,7 @@ target_sources(rpcs3_emu PRIVATE
RSX/Null/NullGSRender.cpp
RSX/Overlays/overlay_animation.cpp
RSX/Overlays/overlay_controls.cpp
RSX/Overlays/overlay_cursor.cpp
RSX/Overlays/overlay_edit_text.cpp
RSX/Overlays/overlay_fonts.cpp
RSX/Overlays/overlay_list_view.cpp
@@ -457,10 +463,15 @@ target_sources(rpcs3_emu PRIVATE
RSX/Program/VertexProgramDecompiler.cpp
RSX/Capture/rsx_capture.cpp
RSX/Capture/rsx_replay.cpp
RSX/GL/glutils/blitter.cpp
RSX/GL/glutils/buffer_object.cpp
RSX/GL/glutils/capabilities.cpp
RSX/GL/glutils/common.cpp
RSX/GL/glutils/fbo.cpp
RSX/GL/glutils/image.cpp
RSX/GL/glutils/program.cpp
RSX/GL/glutils/ring_buffer.cpp
RSX/GL/glutils/sampler.cpp
RSX/GL/GLCommonDecompiler.cpp
RSX/GL/GLCompute.cpp
RSX/GL/GLDraw.cpp
@@ -538,7 +549,7 @@ target_link_libraries(rpcs3_emu
if(APPLE)
check_function_exists(clock_gettime HAVE_CLOCK_GETTIME)
if (${HAVE_CLOCK_GETTIME})
target_compile_definitions(rpcs3_emu PUBLIC -DHAVE_CLOCK_GETTIME)
target_compile_definitions(rpcs3_emu PUBLIC -DHAVE_CLOCK_GETTIME)
endif()
endif()
+253 -41
View File
@@ -5,6 +5,7 @@
#include "Emu/System.h"
#include "Emu/system_config.h"
#include "Emu/Memory/vm_locking.h"
#include "Emu/Memory/vm_reservation.h"
#include "Emu/IdManager.h"
#include "Emu/GDB.h"
#include "Emu/Cell/PPUThread.h"
@@ -49,10 +50,14 @@ void fmt_class_string<cpu_flag>::format(std::string& out, u64 arg)
case cpu_flag::pause: return "p";
case cpu_flag::suspend: return "s";
case cpu_flag::ret: return "ret";
case cpu_flag::again: return "a";
case cpu_flag::signal: return "sig";
case cpu_flag::memory: return "mem";
case cpu_flag::pending: return "pend";
case cpu_flag::pending_recheck: return "pend-re";
case cpu_flag::notify: return "ntf";
case cpu_flag::yield: return "y";
case cpu_flag::preempt: return "PREEMPT";
case cpu_flag::dbg_global_pause: return "G-PAUSE";
case cpu_flag::dbg_pause: return "PAUSE";
case cpu_flag::dbg_step: return "STEP";
@@ -83,15 +88,18 @@ struct cpu_prof
// Total number of samples
u64 samples = 0, idle = 0;
// Avoid printing replicas
bool printed = false;
// Avoid printing replicas or when not much changed
u64 new_samples = 0;
static constexpr u64 min_print_samples = 500;
static constexpr u64 min_print_all_samples = min_print_samples * 20;
void reset()
{
freq.clear();
samples = 0;
idle = 0;
printed = false;
new_samples = 0;
}
static std::string format(const std::multimap<u64, u64, std::greater<u64>>& chart, u64 samples, u64 idle, bool extended_print = false)
@@ -127,8 +135,13 @@ struct cpu_prof
// Print info
void print(const std::shared_ptr<cpu_thread>& ptr)
{
if (printed || samples == idle)
if (new_samples < min_print_samples || samples == idle)
{
if (cpu_flag::exit - ptr->state)
{
profiler.notice("Thread \"%s\" [0x%08x]: %u samples, %u new (%.4f%% idle): Not enough new samples have been collected since the last print.", ptr->get_name(), ptr->id, samples, new_samples, 100. * idle / samples);
}
return;
}
@@ -142,13 +155,22 @@ struct cpu_prof
// Print results
const std::string results = format(chart, samples, idle);
profiler.notice("Thread \"%s\" [0x%08x]: %u samples (%.4f%% idle):%s", ptr->get_name(), ptr->id, samples, 100. * idle / samples, results);
profiler.notice("Thread \"%s\" [0x%08x]: %u samples, %u new (%.4f%% idle):%s", ptr->get_name(), ptr->id, samples, new_samples, 100. * idle / samples, results);
printed = true;
new_samples = 0;
}
static void print_all(const std::unordered_map<std::shared_ptr<cpu_thread>, sample_info>& threads)
static void print_all(std::unordered_map<std::shared_ptr<cpu_thread>, sample_info>& threads)
{
u64 new_samples = 0;
// Print all results and cleanup
for (auto& [ptr, info] : threads)
{
new_samples += info.new_samples;
info.print(ptr);
}
std::multimap<u64, u64, std::greater<u64>> chart;
std::unordered_map<u64, u64, value_hash<u64>> freq;
@@ -157,7 +179,7 @@ struct cpu_prof
for (auto& [_, info] : threads)
{
// This function collects thread information regardless of 'printed' member state
// This function collects thread information regardless of 'new_samples' member state
for (auto& [name, count] : info.freq)
{
freq[name] += count;
@@ -167,18 +189,24 @@ struct cpu_prof
idle += info.idle;
}
for (auto& [name, count] : freq)
{
chart.emplace(count, name);
}
if (samples == idle)
{
return;
}
if (new_samples < min_print_all_samples && thread_ctrl::state() != thread_state::aborting)
{
profiler.notice("All Threads: %u samples, %u new (%.4f%% idle): Not enough new samples have been collected since the last print.", samples, new_samples, 100. * idle / samples);
return;
}
for (auto& [name, count] : freq)
{
chart.emplace(count, name);
}
const std::string results = format(chart, samples, idle, true);
profiler.notice("All Threads: %u samples (%.4f%% idle):%s", samples, 100. * idle / samples, results);
profiler.notice("All Threads: %u samples, %u new (%.4f%% idle):%s", samples, new_samples, 100. * idle / samples, results);
}
};
@@ -239,7 +267,7 @@ struct cpu_prof
// Sample active threads
for (auto& [ptr, info] : threads)
{
if (cpu_flag::exit - ptr->state)
if (auto state = +ptr->state; cpu_flag::exit - state)
{
// Get short function hash
const u64 name = atomic_storage<u64>::load(ptr->block_hash);
@@ -247,9 +275,10 @@ struct cpu_prof
// Append occurrence
info.samples++;
if (auto state = +ptr->state; !::is_paused(state) && !::is_stopped(state) && cpu_flag::wait - state)
if (cpu_flag::wait - state)
{
info.freq[name]++;
info.new_samples++;
// Append verification time to fixed common name 0000000...chunk-0x3fffc
if (name >> 16 && (name & 0xffff) == 0)
@@ -257,6 +286,12 @@ struct cpu_prof
}
else
{
if (state & (cpu_flag::dbg_pause + cpu_flag::dbg_global_pause))
{
// Idle state caused by emulation pause is not accounted for
continue;
}
info.idle++;
}
}
@@ -270,11 +305,13 @@ struct cpu_prof
{
profiler.success("Flushing profiling results...");
// Print all results and cleanup
for (auto& [ptr, info] : threads)
{
info.print(ptr);
}
sample_info::print_all(threads);
}
if (Emu.IsPaused())
{
thread_ctrl::wait_for(5000);
continue;
}
// Wait, roughly for 20µs
@@ -282,11 +319,6 @@ struct cpu_prof
}
// Print all remaining results
for (auto& [ptr, info] : threads)
{
info.print(ptr);
}
sample_info::print_all(threads);
}
@@ -573,6 +605,7 @@ void cpu_thread::operator()()
if (!(state0 & cpu_flag::stop))
{
cpu_task();
state += cpu_flag::wait;
if (state & cpu_flag::ret && state.test_and_reset(cpu_flag::ret))
{
@@ -582,7 +615,7 @@ void cpu_thread::operator()()
continue;
}
thread_ctrl::wait_on(state, state0);
state.wait(state0);
if (state & cpu_flag::ret && state.test_and_reset(cpu_flag::ret))
{
@@ -634,20 +667,22 @@ cpu_thread::cpu_thread(u32 id)
void cpu_thread::cpu_wait(bs_t<cpu_flag> old)
{
thread_ctrl::wait_on(state, old);
state.wait(old);
}
static atomic_t<u32> s_dummy_atomic = 0;
bool cpu_thread::check_state() noexcept
{
bool cpu_sleep_called = false;
bool cpu_can_stop = true;
bool escape, retval;
bool escape{}, retval{};
while (true)
{
// Process all flags in a single atomic op
bs_t<cpu_flag> state1;
const auto state0 = state.fetch_op([&](bs_t<cpu_flag>& flags)
auto state0 = state.fetch_op([&](bs_t<cpu_flag>& flags)
{
bool store = false;
@@ -687,7 +722,6 @@ bool cpu_thread::check_state() noexcept
{
// Sticky flag, indicates check_state() is not allowed to return true
flags -= cpu_flag::temp;
flags -= cpu_flag::wait;
cpu_can_stop = false;
store = true;
}
@@ -699,6 +733,12 @@ bool cpu_thread::check_state() noexcept
store = true;
}
if (flags & cpu_flag::notify)
{
flags -= cpu_flag::notify;
store = true;
}
// Can't process dbg_step if we only paused temporarily
if (cpu_can_stop && flags & cpu_flag::dbg_step)
{
@@ -720,10 +760,10 @@ bool cpu_thread::check_state() noexcept
}
// Atomically clean wait flag and escape
if (!(flags & (cpu_flag::exit + cpu_flag::ret + cpu_flag::stop)))
if (!is_stopped(flags) && flags.none_of(cpu_flag::ret))
{
// Check pause flags which hold thread inside check_state (ignore suspend/debug flags on cpu_flag::temp)
if (flags & (cpu_flag::pause + cpu_flag::memory) || (cpu_can_stop && flags & (cpu_flag::dbg_global_pause + cpu_flag::dbg_pause + cpu_flag::suspend)))
if (flags & (cpu_flag::pause + cpu_flag::memory) || (cpu_can_stop && flags & (cpu_flag::dbg_global_pause + cpu_flag::dbg_pause + cpu_flag::suspend + cpu_flag::yield + cpu_flag::preempt)))
{
if (!(flags & cpu_flag::wait))
{
@@ -731,6 +771,12 @@ bool cpu_thread::check_state() noexcept
store = true;
}
if (flags & (cpu_flag::yield + cpu_flag::preempt) && cpu_can_stop)
{
flags -= (cpu_flag::yield + cpu_flag::preempt);
store = true;
}
escape = false;
state1 = flags;
return store;
@@ -746,9 +792,9 @@ bool cpu_thread::check_state() noexcept
}
else
{
if (cpu_can_stop && !(flags & cpu_flag::wait))
if (flags & cpu_flag::wait)
{
flags += cpu_flag::wait;
flags -= cpu_flag::wait;
store = true;
}
@@ -760,6 +806,34 @@ bool cpu_thread::check_state() noexcept
return store;
}).first;
if (state0 & cpu_flag::preempt && cpu_can_stop)
{
if (cpu_flag::wait - state0)
{
if (!escape || !retval)
{
// Yield itself
state0 += cpu_flag::yield;
escape = false;
}
}
if (const u128 bits = s_cpu_bits)
{
reader_lock lock(s_cpu_lock);
cpu_counter::for_all_cpu(bits & s_cpu_bits, [](cpu_thread* cpu)
{
if (cpu->state.none_of(cpu_flag::wait + cpu_flag::yield))
{
cpu->state += cpu_flag::yield;
}
return true;
});
}
}
if (escape)
{
if (s_tls_thread_slot == umax && !retval)
@@ -768,16 +842,16 @@ bool cpu_thread::check_state() noexcept
cpu_counter::add(this);
}
constexpr auto pending_and_temp = (cpu_flag::pending + cpu_flag::temp);
if ((state0 & pending_and_temp) == cpu_flag::pending)
if (cpu_can_stop && state0 & cpu_flag::pending)
{
// Execute pending work
cpu_work();
if ((state1 ^ state) - pending_and_temp)
if ((state1 ^ state) - cpu_flag::pending)
{
// Work could have changed flags
// Reset internal flags as if check_state() has just been called
cpu_sleep_called = false;
continue;
}
}
@@ -848,6 +922,32 @@ bool cpu_thread::check_state() noexcept
break;
}
}
continue;
}
if (state0 & cpu_flag::yield && cpu_flag::wait - state0 && cpu_can_stop)
{
if (auto spu = try_get<spu_thread>())
{
if (spu->raddr && spu->rtime == vm::reservation_acquire(spu->raddr) && spu->getllar_spin_count < 10)
{
// Reservation operation is a critical section (but this may result in false positives)
continue;
}
}
else if (auto ppu = try_get<ppu_thread>())
{
if (ppu->raddr && ppu->rtime == vm::reservation_acquire(ppu->raddr))
{
// Same
continue;
}
}
// Short sleep when yield flag is present alone (makes no sense when other methods which can stop thread execution have been done)
// Pass a mask of a single bit which is often unused to avoid notifications
s_dummy_atomic.wait(0, 1u << 30, atomic_wait_timeout{80'000});
}
}
}
@@ -874,8 +974,27 @@ void cpu_thread::notify()
cpu_thread& cpu_thread::operator=(thread_state)
{
state += cpu_flag::exit;
state.notify_one(cpu_flag::exit);
if (state & cpu_flag::exit)
{
// Must be notified elsewhere or self-raised
return *this;
}
const auto old = state.fetch_add(cpu_flag::exit);
if (old & cpu_flag::wait && old.none_of(cpu_flag::again + cpu_flag::exit))
{
state.notify_one(cpu_flag::exit);
if (auto thread = try_get<spu_thread>())
{
if (u32 resv = atomic_storage<u32>::load(thread->raddr))
{
vm::reservation_notifier(resv).notify_one();
}
}
}
return *this;
}
@@ -945,6 +1064,24 @@ u32* cpu_thread::get_pc2()
return nullptr;
}
cpu_thread* cpu_thread::get_next_cpu()
{
switch (id_type())
{
case 1:
{
return static_cast<ppu_thread*>(this)->next_cpu;
}
case 2:
{
return static_cast<spu_thread*>(this)->next_cpu;
}
default: break;
}
return nullptr;
}
std::shared_ptr<CPUDisAsm> make_disasm(const cpu_thread* cpu);
void cpu_thread::dump_all(std::string& ret) const
@@ -1195,3 +1332,78 @@ u32 CPUDisAsm::DisAsmBranchTarget(s32 /*imm*/)
// Unused
return 0;
}
extern bool try_lock_spu_threads_in_a_state_compatible_with_savestates(bool revert_lock)
{
const u64 start = get_system_time();
// Attempt to lock for half a second, if somehow takes longer abort it
do
{
if (revert_lock)
{
// Revert the operation of this function
break;
}
if (cpu_thread::suspend_all(nullptr, {}, []()
{
return idm::select<named_thread<spu_thread>>([](u32, spu_thread& spu)
{
if (!spu.unsavable)
{
if (Emu.IsPaused())
{
// If emulation is paused, we can only hope it's already in a state compatible with savestates
return !!(spu.state & (cpu_flag::dbg_global_pause + cpu_flag::dbg_pause));
}
else
{
ensure(!spu.state.test_and_set(cpu_flag::dbg_global_pause));
}
return false;
}
return true;
}).ret;
}))
{
if (Emu.IsPaused())
{
return false;
}
// It's faster to lock once
reader_lock lock(id_manager::g_mutex);
idm::select<named_thread<spu_thread>>([](u32, spu_thread& spu)
{
spu.state -= cpu_flag::dbg_global_pause;
}, idm::unlocked);
// For faster signalling, first remove state flags then batch notifications
idm::select<named_thread<spu_thread>>([](u32, spu_thread& spu)
{
if (spu.state & cpu_flag::wait)
{
spu.state.notify_one();
}
}, idm::unlocked);
continue;
}
return true;
} while (std::this_thread::yield(), get_system_time() - start <= 500'000);
idm::select<named_thread<spu_thread>>([&](u32, named_thread<spu_thread>& spu)
{
if (spu.state.test_and_reset(cpu_flag::dbg_global_pause))
{
spu.state.notify_one();
}
});
return false;
}
+7 -2
View File
@@ -19,10 +19,14 @@ enum class cpu_flag : u32
pause, // Thread suspended by suspend_all technique
suspend, // Thread suspended
ret, // Callback return requested
again, // Thread must complete the syscall after deserialization
signal, // Thread received a signal (HLE)
memory, // Thread must unlock memory mutex
pending, // Thread has postponed work
pending_recheck, // Thread needs to recheck if there is pending work before ::pending removal
notify, // Flag meant solely to allow atomic notification on state without changing other flags
yield, // Thread is being requested to yield its execution time if it's running
preempt, // Thread is being requested to preempt the execution of all CPU threads
dbg_global_pause, // Emulation paused
dbg_pause, // Thread paused
@@ -34,7 +38,7 @@ enum class cpu_flag : u32
// Test stopped state
constexpr bool is_stopped(bs_t<cpu_flag> state)
{
return !!(state & (cpu_flag::stop + cpu_flag::exit));
return !!(state & (cpu_flag::stop + cpu_flag::exit + cpu_flag::again));
}
// Test paused state
@@ -139,6 +143,7 @@ public:
u32 get_pc() const;
u32* get_pc2(); // Last PC before stepping for the debugger (may be null)
cpu_thread* get_next_cpu(); // Access next_cpu member if the is one
void notify();
cpu_thread& operator=(thread_state);
@@ -172,7 +177,7 @@ public:
virtual void cpu_sleep() {}
// Callback for cpu_flag::pending
virtual void cpu_work() {}
virtual void cpu_work() { state -= cpu_flag::pending + cpu_flag::pending_recheck; }
// Callback for cpu_flag::ret
virtual void cpu_return() {}
+22
View File
@@ -32,7 +32,21 @@ cpu_translator::cpu_translator(llvm::Module* _module, bool is_be)
if (m_use_ssse3)
{
#if defined(ARCH_X64)
return m_ir->CreateCall(get_intrinsic(llvm::Intrinsic::x86_ssse3_pshuf_b_128), {data0, index});
#elif defined(ARCH_ARM64)
// Modified from sse2neon
// movi v2.16b, #143
// and v1.16b, v1.16b, v2.16b
// tbl v0.16b, { v0.16b }, v1.16b
auto mask = llvm::ConstantInt::get(get_type<u8[16]>(), 0x8F);
auto and_mask = llvm::ConstantInt::get(get_type<bool[16]>(), true);
auto vec_len = llvm::ConstantInt::get(get_type<u32>(), 16);
auto index_masked = m_ir->CreateCall(get_intrinsic<u8[16]>(llvm::Intrinsic::vp_and), {index, mask, and_mask, vec_len});
return m_ir->CreateCall(get_intrinsic<u8[16]>(llvm::Intrinsic::aarch64_neon_tbl1), {data0, index_masked});
#else
#error "Unimplemented"
#endif
}
else
{
@@ -140,6 +154,14 @@ void cpu_translator::initialize(llvm::LLVMContext& context, llvm::ExecutionEngin
m_use_avx512_icl = true;
m_use_vnni = true;
}
// Aarch64 CPUs
if (cpu == "cyclone" || cpu.contains("cortex"))
{
m_use_fma = true;
// AVX does not use intrinsics so far
m_use_avx = true;
}
}
llvm::Value* cpu_translator::bitcast(llvm::Value* val, llvm::Type* type) const
+8 -5
View File
@@ -30,6 +30,7 @@
#endif
#include "util/types.hpp"
#include "util/sysinfo.hpp"
#include "Utilities/StrFmt.h"
#include "Utilities/BitField.h"
#include "Utilities/JIT.h"
@@ -2896,12 +2897,8 @@ protected:
bool m_is_be;
// Allow PSHUFB intrinsic
#ifdef ARCH_X64
bool m_use_ssse3 = true;
#else
// TODO: fix the pshufb arm64 native impl using TBL instruction
bool m_use_ssse3 = false;
#endif
// Allow FMA
bool m_use_fma = false;
@@ -2979,6 +2976,7 @@ public:
m_engine->updateGlobalMapping({lame.data(), lame.size()}, reinterpret_cast<uptr>(_func));
const auto inst = m_ir->CreateCall(func, {args...});
inst->setTailCallKind(llvm::CallInst::TCK_NoTail);
#ifdef _WIN32
inst->setCallingConv(llvm::CallingConv::Win64);
#endif
@@ -3445,6 +3443,11 @@ public:
template <typename T1, typename T2, typename T3>
value_t<u8[16]> vperm2b(T1 a, T2 b, T3 c)
{
if (!utils::has_fast_vperm2b())
{
return vperm2b256to128(a, b, c);
}
value_t<u8[16]> result;
const auto data0 = a.eval(m_ir);
+2
View File
@@ -39,6 +39,8 @@ public:
{
return value;
}
ENABLE_BITWISE_SERIALIZATION;
};
enum CellNotAnError : s32
+2
View File
@@ -88,6 +88,8 @@ enum : u32
struct alignas(16) spu_mfc_cmd
{
ENABLE_BITWISE_SERIALIZATION;
MFC cmd;
u8 tag;
u16 size;

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