Compare commits

..

254 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
341 changed files with 12146 additions and 4660 deletions
+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" \
+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 -1
View File
@@ -4,7 +4,7 @@ include(ExternalProject)
ExternalProject_Add(moltenvk
GIT_REPOSITORY https://github.com/KhronosGroup/MoltenVK.git
GIT_TAG 1112005
GIT_TAG 260bad4
BUILD_IN_SOURCE 1
SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/MoltenVK
CONFIGURE_COMMAND "${CMAKE_CURRENT_SOURCE_DIR}/MoltenVK/fetchDependencies" --macos
+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);
+2 -1
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 "")
+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}>;
+3 -2
View File
@@ -74,7 +74,7 @@ namespace fs
using enable_bitcopy = std::true_type;
constexpr bool operator==(const stat_t&) const = default;
constexpr bool operator==(const stat_t&) const = default;
};
// Helper, layout is equal to iovec struct
@@ -793,7 +793,8 @@ namespace fs
if (write)
{
m_stat.mtime = std::max(m_stat.atime, ++m_stat.mtime);
m_stat.mtime++;
m_stat.mtime = std::max(m_stat.atime, m_stat.mtime);
m_stat.ctime = m_stat.mtime;
}
}
+143 -83
View File
@@ -20,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);
@@ -83,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()
@@ -357,7 +379,7 @@ asmjit::inline_runtime::~inline_runtime()
asmjit::simd_builder::simd_builder(CodeHolder* ch) noexcept
: native_asm(ch)
{
_init(true);
_init(0);
consts[~v128()] = this->newLabel();
}
@@ -365,9 +387,9 @@ asmjit::simd_builder::~simd_builder()
{
}
void asmjit::simd_builder::_init(bool full)
void asmjit::simd_builder::_init(uint new_vsize)
{
if (full && utils::has_avx512_icl())
if ((!new_vsize && utils::has_avx512_icl()) || new_vsize == 64)
{
v0 = x86::zmm0;
v1 = x86::zmm1;
@@ -377,7 +399,7 @@ void asmjit::simd_builder::_init(bool full)
v5 = x86::zmm5;
vsize = 64;
}
else if (full && utils::has_avx2())
else if ((!new_vsize && utils::has_avx2()) || new_vsize == 32)
{
v0 = x86::ymm0;
v1 = x86::ymm1;
@@ -395,12 +417,13 @@ void asmjit::simd_builder::_init(bool full)
v3 = x86::xmm3;
v4 = x86::xmm4;
v5 = x86::xmm5;
vsize = 16;
vsize = new_vsize ? new_vsize : 16;
}
if (full && utils::has_avx512())
if (utils::has_avx512())
{
vmask = -1;
if (!new_vsize)
vmask = -1;
}
else
{
@@ -480,6 +503,10 @@ void asmjit::simd_builder::vec_clobbering_test(u32 esize, const Operand& v, cons
{
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);
@@ -504,6 +531,54 @@ void asmjit::simd_builder::vec_clobbering_test(u32 esize, const Operand& v, cons
}
}
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))
@@ -530,7 +605,7 @@ void asmjit::simd_builder::vec_load_unaligned(u32 esize, const Operand& v, const
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)
else if ((vmask && vmask < 8) || vsize >= 64)
this->emit(x86::Inst::kIdVmovdqu16, v, src);
else
return vec_load_unaligned(vsize, v, src);
@@ -542,7 +617,7 @@ void asmjit::simd_builder::vec_load_unaligned(u32 esize, const Operand& v, const
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)
else if ((vmask && vmask < 8) || vsize >= 64)
this->emit(x86::Inst::kIdVmovdqu32, v, src);
else
return vec_load_unaligned(vsize, v, src);
@@ -554,7 +629,7 @@ void asmjit::simd_builder::vec_load_unaligned(u32 esize, const Operand& v, const
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)
else if ((vmask && vmask < 8) || vsize >= 64)
this->emit(x86::Inst::kIdVmovdqu64, v, src);
else
return vec_load_unaligned(vsize, v, src);
@@ -562,7 +637,9 @@ void asmjit::simd_builder::vec_load_unaligned(u32 esize, const Operand& v, const
else if (esize >= 16)
{
ensure(vsize >= 16);
if (utils::has_avx())
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);
@@ -636,7 +713,7 @@ void asmjit::simd_builder::_vec_binary_op(x86::Inst::Id sse_op, x86::Inst::Id ve
{
if (utils::has_avx())
{
if (vex_op == x86::Inst::kIdNone || this->_extraReg.isReg())
if (evex_op != x86::Inst::kIdNone && (vex_op == x86::Inst::kIdNone || this->_extraReg.isReg() || vsize >= 64))
{
this->evex().emit(evex_op, dst, lhs, rhs);
}
@@ -694,40 +771,31 @@ void asmjit::simd_builder::vec_umax(u32 esize, const Operand& dst, const Operand
fmt::throw_exception("Unimplemented");
}
void asmjit::simd_builder::vec_umin_horizontal_i128(u32 esize, const x86::Gp& dst, const Operand& src, const Operand& tmp)
void asmjit::simd_builder::vec_cmp_eq(u32 esize, const Operand& dst, const Operand& lhs, const Operand& rhs)
{
using enum x86::Inst::Id;
if (!utils::has_sse41())
{
fmt::throw_exception("Unimplemented");
}
ensure(src != tmp);
if (esize == 2)
{
this->emit(utils::has_avx() ? kIdVphminposuw : kIdPhminposuw, x86::Xmm(tmp.id()), x86::Xmm(src.id()));
this->emit(utils::has_avx() ? kIdVpextrw : kIdPextrw, dst, x86::Xmm(tmp.id()), Imm(0));
}
else if (esize == 4)
{
if (utils::has_avx())
if (vsize == 64)
{
this->vpsrldq(x86::Xmm(tmp.id()), x86::Xmm(src.id()), 8);
this->vpminud(x86::Xmm(tmp.id()), x86::Xmm(tmp.id()), x86::Xmm(src.id()));
this->vpsrldq(x86::Xmm(src.id()), x86::Xmm(tmp.id()), 4);
this->vpminud(x86::Xmm(src.id()), x86::Xmm(src.id()), x86::Xmm(tmp.id()));
this->vmovd(dst.r32(), x86::Xmm(src.id()));
this->evex().emit(kIdVpcmpeqw, x86::k0, lhs, rhs);
this->evex().emit(kIdVpmovm2w, dst, x86::k0);
}
else
{
this->movdqa(x86::Xmm(tmp.id()), x86::Xmm(src.id()));
this->psrldq(x86::Xmm(tmp.id()), 8);
this->pminud(x86::Xmm(tmp.id()), x86::Xmm(src.id()));
this->movdqa(x86::Xmm(src.id()), x86::Xmm(tmp.id()));
this->psrldq(x86::Xmm(src.id()), 4);
this->pminud(x86::Xmm(src.id()), x86::Xmm(tmp.id()));
this->movd(dst.r32(), x86::Xmm(src.id()));
_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
@@ -736,50 +804,42 @@ void asmjit::simd_builder::vec_umin_horizontal_i128(u32 esize, const x86::Gp& ds
}
}
void asmjit::simd_builder::vec_umax_horizontal_i128(u32 esize, const x86::Gp& dst, const Operand& src, const Operand& tmp)
void asmjit::simd_builder::vec_extract_high(u32, const Operand& dst, const Operand& src)
{
using enum x86::Inst::Id;
if (!utils::has_sse41())
{
fmt::throw_exception("Unimplemented");
}
ensure(src != tmp);
if (esize == 2)
{
vec_set_all_ones(x86::Xmm(tmp.id()));
vec_xor(esize, x86::Xmm(tmp.id()), x86::Xmm(tmp.id()), x86::Xmm(src.id()));
this->emit(utils::has_avx() ? kIdVphminposuw : kIdPhminposuw, x86::Xmm(tmp.id()), x86::Xmm(tmp.id()));
this->emit(utils::has_avx() ? kIdVpextrw : kIdPextrw, dst, x86::Xmm(tmp.id()), Imm(0));
this->not_(dst.r16());
}
else if (esize == 4)
{
if (utils::has_avx())
{
this->vpsrldq(x86::Xmm(tmp.id()), x86::Xmm(src.id()), 8);
this->vpmaxud(x86::Xmm(tmp.id()), x86::Xmm(tmp.id()), x86::Xmm(src.id()));
this->vpsrldq(x86::Xmm(src.id()), x86::Xmm(tmp.id()), 4);
this->vpmaxud(x86::Xmm(src.id()), x86::Xmm(src.id()), x86::Xmm(tmp.id()));
this->vmovd(dst.r32(), x86::Xmm(src.id()));
}
else
{
this->movdqa(x86::Xmm(tmp.id()), x86::Xmm(src.id()));
this->psrldq(x86::Xmm(tmp.id()), 8);
this->pmaxud(x86::Xmm(tmp.id()), x86::Xmm(src.id()));
this->movdqa(x86::Xmm(src.id()), x86::Xmm(tmp.id()));
this->psrldq(x86::Xmm(src.id()), 4);
this->pmaxud(x86::Xmm(src.id()), x86::Xmm(tmp.id()));
this->movd(dst.r32(), x86::Xmm(src.id()));
}
}
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
{
fmt::throw_exception("Unimplemented");
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
+74 -28
View File
@@ -226,12 +226,13 @@ namespace asmjit
void operator()() noexcept;
void _init(bool full);
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);
@@ -260,11 +261,18 @@ namespace asmjit
_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_umin_horizontal_i128(u32 esize, const x86::Gp& dst, const Operand& src, const Operand& tmp);
void vec_umax_horizontal_i128(u32 esize, const x86::Gp& dst, const Operand& src, const Operand& tmp);
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()
{
@@ -287,7 +295,7 @@ namespace asmjit
return *this;
}
void build_loop(u32 esize, auto reg_ctr, auto reg_cnt, auto&& build, auto&& reduce)
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);
@@ -299,47 +307,85 @@ namespace asmjit
const u32 step = vsize / esize;
this->xor_(reg_ctr.r32(), reg_ctr.r32()); // Reset counter reg
this->sub(reg_cnt, step);
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->sub(reg_cnt, step);
this->ja(body);
this->cmp(reg_cnt, step);
this->jae(body);
this->bind(next);
if (!vmask)
reduce();
this->add(reg_cnt, step);
this->jz(exit);
if (vmask)
{
// Build single last iteration (masked)
this->bzhi(reg_cnt, x86::Mem(consts[~u128()], 0), reg_cnt);
this->kmovq(x86::k7, reg_cnt);
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();
vmask = -1;
reduce();
// Rollout reduction step
this->bind(exit);
while (true)
{
vsize /= 2;
if (vsize < esize)
break;
this->_init(vsize);
reduce();
}
}
else
{
// Build tail loop (reduced vector width)
Label body = this->newLabel();
this->align(AlignMode::kCode, 16);
this->bind(body);
const uint vsz = vsize / step;
this->_init(false);
vsize = vsz;
build();
this->_init(true);
this->inc(reg_ctr);
this->sub(reg_cnt, 1);
this->ja(body);
// 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->bind(exit);
this->_init(0);
}
};
+3
View File
@@ -27,6 +27,9 @@ 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);
+2
View File
@@ -16,7 +16,9 @@
#include <process.h>
#include <sysinfoapi.h>
#else
#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif
#ifdef __APPLE__
#define _XOPEN_SOURCE
#define __USE_GNU
+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)
{
+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)
{
+1 -1
Submodule llvm updated: 5521155be5...9b52b6c39a
+2 -2
View File
@@ -111,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();
}
@@ -120,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;
+2 -2
View File
@@ -40,7 +40,7 @@ enum class AudioChannelCnt : u32
enum class AudioStateEvent : u32
{
UNSPECIFIED_ERROR,
DEFAULT_DEVICE_CHANGED,
DEFAULT_DEVICE_MAYBE_CHANGED,
};
class AudioBackend
@@ -226,7 +226,7 @@ protected:
AudioFreq m_sampling_rate = AudioFreq::FREQ_48K;
AudioChannelCnt m_channels = AudioChannelCnt::STEREO;
shared_mutex m_cb_mutex{};
std::timed_mutex m_cb_mutex{};
std::function<u32(u32, void *)> m_write_callback{};
shared_mutex m_state_cb_mutex{};
+188 -81
View File
@@ -22,14 +22,14 @@ CubebBackend::CubebBackend()
}
#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: %i", err);
m_ctx = nullptr;
return;
}
if (int err = cubeb_register_device_collection_changed(m_ctx, CUBEB_DEVICE_TYPE_OUTPUT, device_collection_changed_cb, this))
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);
}
@@ -38,7 +38,10 @@ CubebBackend::CubebBackend()
m_dev_collection_cb_enabled = true;
}
Cubeb.notice("Using backend %s", cubeb_get_backend_id(m_ctx));
Cubeb.notice("Using backend %s", cubeb_get_backend_id(ctx));
std::lock_guard cb_lock{m_state_cb_mutex};
m_ctx = ctx;
}
CubebBackend::~CubebBackend()
@@ -78,8 +81,19 @@ bool CubebBackend::Operational()
bool CubebBackend::DefaultDeviceChanged()
{
std::lock_guard lock{m_dev_sw_mutex};
return !m_reset_req.observe() && m_default_dev_changed;
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)
@@ -90,20 +104,23 @@ bool CubebBackend::Open(std::string_view dev_id, AudioFreq freq, AudioSampleSize
return false;
}
std::lock_guard lock(m_cb_mutex);
std::lock_guard dev_sw_lock{m_dev_sw_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;
auto [dev_handle, dev_ident, dev_ch_cnt] = GetDevice(use_default_device ? "" : dev_id);
if (!dev_handle)
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)
{
std::tie(dev_handle, dev_ident, dev_ch_cnt) = GetDefaultDeviceAlt(freq, sample_size, ch_cnt);
device = GetDefaultDeviceAlt(freq, sample_size, ch_cnt);
if (!dev_handle)
if (!device.handle)
{
Cubeb.error("Cannot detect default device. Channel count detection unavailable.");
}
@@ -115,15 +132,21 @@ bool CubebBackend::Open(std::string_view dev_id, AudioFreq freq, AudioSampleSize
}
}
if (dev_ch_cnt == 0)
if (device.ch_cnt == 0)
{
Cubeb.error("Device reported invalid channel count, using stereo instead");
dev_ch_cnt = 2;
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 = static_cast<AudioChannelCnt>(std::min(static_cast<u32>(convert_channel_count(dev_ch_cnt)), static_cast<u32>(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{};
@@ -141,7 +164,7 @@ bool CubebBackend::Open(std::string_view dev_id, AudioFreq freq, AudioSampleSize
fmt::throw_exception("Invalid audio channel count");
}
}();
stream_param.prefs = m_dev_collection_cb_enabled && dev_handle ? CUBEB_STREAM_PREF_DISABLE_DEVICE_SWITCHING : CUBEB_STREAM_PREF_NONE;
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))
@@ -152,7 +175,7 @@ bool CubebBackend::Open(std::string_view dev_id, AudioFreq freq, AudioSampleSize
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, dev_handle, &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: %i", err);
m_stream = nullptr;
@@ -162,7 +185,7 @@ bool CubebBackend::Open(std::string_view dev_id, AudioFreq freq, AudioSampleSize
if (int err = cubeb_stream_start(m_stream))
{
Cubeb.error("cubeb_stream_start() failed: %i", err);
CloseUnlocked();
Close();
return false;
}
@@ -171,15 +194,10 @@ bool CubebBackend::Open(std::string_view dev_id, AudioFreq freq, AudioSampleSize
Cubeb.error("cubeb_stream_set_volume() failed: %i", err);
}
if (use_default_device)
{
m_current_device = dev_ident;
}
return true;
}
void CubebBackend::CloseUnlocked()
void CubebBackend::Close()
{
if (m_stream != nullptr)
{
@@ -189,21 +207,17 @@ void CubebBackend::CloseUnlocked()
}
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);
}
m_default_dev_changed = false;
m_current_device.clear();
}
void CubebBackend::Close()
{
std::lock_guard lock(m_cb_mutex);
std::lock_guard dev_sw_lock{m_dev_sw_mutex};
CloseUnlocked();
std::lock_guard lock{m_state_cb_mutex};
m_default_device.clear();
}
void CubebBackend::Play()
@@ -253,10 +267,13 @@ f64 CubebBackend::GetCallbackFrameLen()
return std::max<f64>(AUDIO_MIN_LATENCY, static_cast<f64>(stream_latency) / get_sampling_rate());
}
std::tuple<cubeb_devid, std::string, u32> CubebBackend::GetDevice(std::string_view dev_id)
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))
{
@@ -274,14 +291,24 @@ std::tuple<cubeb_devid, std::string, u32> CubebBackend::GetDevice(std::string_vi
return {};
}
std::tuple<cubeb_devid, std::string, u32> result{};
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];
const std::string dev_ident{dev_info.device_id};
if (dev_ident.empty())
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;
@@ -291,17 +318,26 @@ std::tuple<cubeb_devid, std::string, u32> CubebBackend::GetDevice(std::string_vi
{
if (dev_info.preferred & CUBEB_DEVICE_PREF_MULTIMEDIA)
{
result = {dev_info.devid, dev_ident, dev_info.max_channels};
result = std::move(device);
break;
}
}
else if (dev_ident == dev_id)
else if (device.id == dev_id)
{
result = {dev_info.devid, dev_ident, dev_info.max_channels};
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);
@@ -310,8 +346,10 @@ std::tuple<cubeb_devid, std::string, u32> CubebBackend::GetDevice(std::string_vi
return result;
};
std::tuple<cubeb_devid, std::string, u32> CubebBackend::GetDefaultDeviceAlt(AudioFreq freq, AudioSampleSize sample_size, AudioChannelCnt ch_cnt)
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,
@@ -340,14 +378,19 @@ std::tuple<cubeb_devid, std::string, u32> CubebBackend::GetDefaultDeviceAlt(Audi
cubeb_device* crnt_dev{};
if (int err = cubeb_stream_get_current_device(tmp_stream, &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: %i", err);
Cubeb.error("cubeb_stream_get_current_device() failed: err=%i, crnt_dev=%d", err, !!crnt_dev);
cubeb_stream_destroy(tmp_stream);
return {};
}
const std::string out_dev_name{crnt_dev->output_name};
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))
{
@@ -358,19 +401,46 @@ std::tuple<cubeb_devid, std::string, u32> CubebBackend::GetDefaultDeviceAlt(Audi
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)
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 && !cubeb->m_reset_req.observe() && 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);
@@ -390,65 +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_state_cb_mutex);
if (!cubeb->m_reset_req.test_and_set() && cubeb->m_state_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)
void CubebBackend::device_collection_changed_cb(cubeb* context, void* user_ptr)
{
CubebBackend* const cubeb = static_cast<CubebBackend*>(user_ptr);
Cubeb.notice("Device collection changed");
std::lock_guard lock{cubeb->m_dev_sw_mutex};
// Non default device is used (or default device cannot be detected)
if (cubeb->m_current_device.empty())
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;
}
auto [handle, dev_id, ch_cnt] = cubeb->GetDevice();
if (!handle)
{
std::tie(handle, dev_id, ch_cnt) = cubeb->GetDefaultDeviceAlt(cubeb->m_sampling_rate, cubeb->m_sample_size, cubeb->m_channels);
}
std::lock_guard cb_lock{cubeb->m_state_cb_mutex};
if (!handle)
if (context != cubeb->m_ctx)
{
// No devices available
if (!cubeb->m_reset_req.test_and_set() && cubeb->m_state_callback)
{
cubeb->m_state_callback(AudioStateEvent::UNSPECIFIED_ERROR);
}
Cubeb.error("device_collection_changed_cb called with unkown context");
return;
}
else if (!cubeb->m_reset_req.observe() && dev_id != cubeb->m_current_device)
{
cubeb->m_default_dev_changed = true;
if (cubeb->m_state_callback)
{
cubeb->m_state_callback(AudioStateEvent::DEFAULT_DEVICE_CHANGED);
}
// 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);
}
}
+10 -6
View File
@@ -44,9 +44,8 @@ private:
atomic_t<bool> m_reset_req = false;
shared_mutex m_dev_sw_mutex{};
std::string m_current_device{};
bool m_default_dev_changed = false;
// Protected by callback mutex
std::string m_default_device{};
bool m_dev_collection_cb_enabled = false;
@@ -55,8 +54,13 @@ private:
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{};
};
std::tuple<cubeb_devid, std::string /* dev_ident */, u32 /* ch_cnt */> GetDevice(std::string_view dev_id = "");
std::tuple<cubeb_devid, std::string /* dev_ident */, u32 /* ch_cnt */> GetDefaultDeviceAlt(AudioFreq freq, AudioSampleSize sample_size, AudioChannelCnt ch_cnt);
device_handle GetDevice(std::string_view dev_id = "");
device_handle GetDefaultDeviceAlt(AudioFreq freq, AudioSampleSize sample_size, AudioChannelCnt ch_cnt);
};
+1 -1
View File
@@ -234,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 && !faudio->m_reset_req.observe() && 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!");
+14 -12
View File
@@ -80,12 +80,6 @@ XAudio2Backend::XAudio2Backend()
return;
}
if (HRESULT hr = enumerator->RegisterEndpointNotificationCallback(this); FAILED(hr))
{
XAudio.error("RegisterEndpointNotificationCallback() 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);
@@ -125,7 +119,7 @@ bool XAudio2Backend::Operational()
bool XAudio2Backend::DefaultDeviceChanged()
{
std::lock_guard lock{m_dev_sw_mutex};
std::lock_guard lock{m_state_cb_mutex};
return !m_reset_req.observe() && m_default_dev_changed;
}
@@ -162,9 +156,12 @@ 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();
}
@@ -172,7 +169,6 @@ void XAudio2Backend::CloseUnlocked()
void XAudio2Backend::Close()
{
std::lock_guard lock(m_cb_mutex);
std::lock_guard dev_sw_lock{m_dev_sw_mutex};
CloseUnlocked();
}
@@ -207,7 +203,6 @@ bool XAudio2Backend::Open(std::string_view dev_id, AudioFreq freq, AudioSampleSi
}
std::lock_guard lock(m_cb_mutex);
std::lock_guard dev_sw_lock{m_dev_sw_mutex};
CloseUnlocked();
const bool use_default_device = dev_id.empty() || dev_id == audio_device_enumerator::DEFAULT_DEV_ID;
@@ -282,6 +277,13 @@ bool XAudio2Backend::Open(std::string_view dev_id, AudioFreq freq, AudioSampleSi
return false;
}
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));
@@ -331,7 +333,7 @@ f64 XAudio2Backend::GetCallbackFrameLen()
void XAudio2Backend::OnVoiceProcessingPassStart(UINT32 BytesRequired)
{
std::unique_lock lock(m_cb_mutex, std::defer_lock);
if (BytesRequired && !m_reset_req.observe() && 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!");
@@ -386,7 +388,7 @@ HRESULT XAudio2Backend::OnDefaultDeviceChanged(EDataFlow flow, ERole role, LPCWS
return S_OK;
}
std::lock_guard lock{m_dev_sw_mutex};
std::lock_guard lock(m_state_cb_mutex);
// Non default device is used
if (m_current_device.empty())
@@ -404,7 +406,7 @@ HRESULT XAudio2Backend::OnDefaultDeviceChanged(EDataFlow flow, ERole role, LPCWS
if (m_state_callback)
{
m_state_callback(AudioStateEvent::DEFAULT_DEVICE_CHANGED);
m_state_callback(AudioStateEvent::DEFAULT_DEVICE_MAYBE_CHANGED);
}
}
}
+1 -1
View File
@@ -45,7 +45,7 @@ private:
Microsoft::WRL::ComPtr<IMMDeviceEnumerator> m_device_enumerator{};
shared_mutex m_dev_sw_mutex{};
// Protected by state callback mutex
std::string m_current_device{};
bool m_default_dev_changed = false;
+4 -5
View File
@@ -37,7 +37,6 @@ target_include_directories(rpcs3_emu
PUBLIC
${RPCS3_SRC_DIR})
# Utilities
target_sources(rpcs3_emu PRIVATE
../util/atomic.cpp
@@ -117,7 +116,6 @@ target_sources(rpcs3_emu PRIVATE
../Loader/TRP.cpp
)
# Audio
target_sources(rpcs3_emu PRIVATE
Audio/audio_resampler.cpp
@@ -188,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
@@ -339,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
@@ -415,7 +414,6 @@ target_sources(rpcs3_emu PRIVATE
Memory/vm.cpp
)
# RSX
target_sources(rpcs3_emu PRIVATE
RSX/gcm_enums.cpp
@@ -467,6 +465,7 @@ target_sources(rpcs3_emu PRIVATE
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
@@ -550,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()
+142 -35
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"
@@ -54,6 +55,9 @@ void fmt_class_string<cpu_flag>::format(std::string& out, u64 arg)
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";
@@ -84,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)
@@ -128,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;
}
@@ -143,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;
@@ -158,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;
@@ -168,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);
}
};
@@ -240,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);
@@ -248,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)
@@ -258,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++;
}
}
@@ -271,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
@@ -283,11 +319,6 @@ struct cpu_prof
}
// Print all remaining results
for (auto& [ptr, info] : threads)
{
info.print(ptr);
}
sample_info::print_all(threads);
}
@@ -574,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))
{
@@ -583,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))
{
@@ -635,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;
@@ -688,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;
}
@@ -730,7 +763,7 @@ bool cpu_thread::check_state() noexcept
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))
{
@@ -738,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;
@@ -753,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;
}
@@ -767,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)
@@ -855,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});
}
}
}
@@ -892,6 +985,14 @@ cpu_thread& cpu_thread::operator=(thread_state)
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;
@@ -1232,13 +1333,19 @@ u32 CPUDisAsm::DisAsmBranchTarget(s32 /*imm*/)
return 0;
}
extern bool try_lock_spu_threads_in_a_state_compatible_with_savestates()
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)
+2
View File
@@ -25,6 +25,8 @@ enum class cpu_flag : u32
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
+6
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"
@@ -3442,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);
+1 -1
View File
@@ -162,7 +162,7 @@ bool statichle_handler::check_against_patterns(vm::cptr<u8>& data, u32 size, u32
return false;
}
const auto sfunc = &smodule->functions.at(pat.fnid);
const auto sfunc = &::at32(smodule->functions, pat.fnid);
const u32 target = g_fxo->get<ppu_function_manager>().func_addr(sfunc->index) + 4;
// write stub
+3 -34
View File
@@ -454,30 +454,8 @@ public:
if (adecIsAtracX(type)) last_pts -= 0x10000; // hack
}
struct AVPacketHolder : AVPacket
{
AVPacketHolder(u32 data_size)
{
av_init_packet(this);
if (data_size)
{
this->data = static_cast<u8*>(av_calloc(1, data_size + AV_INPUT_BUFFER_PADDING_SIZE));
this->size = data_size + AV_INPUT_BUFFER_PADDING_SIZE;
}
else
{
this->data = nullptr;
this->size = 0;
}
}
~AVPacketHolder()
{
av_free(data);
}
} au(0);
AVPacket* packet = av_packet_alloc();
std::unique_ptr<AVPacket, decltype([](AVPacket* p){av_packet_unref(p);})> packet_(packet);
if (just_started && just_finished)
{
@@ -544,8 +522,6 @@ public:
just_started = false;
}
bool last_frame = false;
while (true)
{
if (Emu.IsStopped() || is_closed)
@@ -554,14 +530,7 @@ public:
break;
}
last_frame = av_read_frame(fmt, &au) < 0;
if (last_frame)
{
//break;
av_free(au.data);
au.data = NULL;
au.size = 0;
}
av_read_frame(fmt, packet);
struct AdecFrameHolder : AdecFrame
{
+51 -37
View File
@@ -158,6 +158,7 @@ audio_ringbuffer::audio_ringbuffer(cell_audio_config& _cfg)
cb_ringbuf.set_buf_size(static_cast<u32>(static_cast<u32>(cfg.backend_ch_cnt) * cfg.audio_sampling_rate * cfg.audio_sample_size * buffer_dur_mult));
backend->SetWriteCallback(std::bind(&audio_ringbuffer::backend_write_callback, this, std::placeholders::_1, std::placeholders::_2));
backend->SetStateCallback(std::bind(&audio_ringbuffer::backend_state_callback, this, std::placeholders::_1));
}
audio_ringbuffer::~audio_ringbuffer()
@@ -191,6 +192,14 @@ u32 audio_ringbuffer::backend_write_callback(u32 size, void *buf)
return static_cast<u32>(cb_ringbuf.pop(buf, size, true));
}
void audio_ringbuffer::backend_state_callback(AudioStateEvent event)
{
if (event == AudioStateEvent::DEFAULT_DEVICE_MAYBE_CHANGED)
{
backend_device_changed = true;
}
}
u64 audio_ringbuffer::get_timestamp()
{
return get_system_time();
@@ -683,7 +692,6 @@ void cell_audio_thread::reset_counters()
m_start_time = ringbuffer->get_timestamp();
m_last_period_end = m_start_time;
m_dynamic_period = 0;
m_backend_failed = false;
m_audio_should_restart = true;
}
@@ -720,9 +728,13 @@ void cell_audio_thread::operator()()
u32 untouched_expected = 0;
u32 loop_count = 0;
// Main cellAudio loop
while (thread_ctrl::state() != thread_state::aborting)
{
loop_count++;
const auto update_req = m_update_configuration.observe();
if (update_req != audio_backend_update::NONE)
{
@@ -735,37 +747,8 @@ void cell_audio_thread::operator()()
update_config(update_req == audio_backend_update::ALL);
}
if (!ringbuffer->get_operational_status())
{
if (m_backend_failed)
{
thread_ctrl::wait_for(500 * 1000);
}
else
{
cellAudio.warning("Backend stopped unexpectedly (likely device change). Attempting to recover...");
}
update_config(true);
m_backend_failed = true;
continue;
}
if (ringbuffer->device_changed())
{
cellAudio.warning("Default device changed, attempting to switch...");
update_config(false);
continue;
}
if (m_backend_failed)
{
cellAudio.warning("Backend recovered");
m_backend_failed = false;
}
const bool emu_paused = Emu.IsPaused();
const u64 timestamp = ringbuffer->update(emu_paused);
const u64 timestamp = ringbuffer->update(emu_paused || m_backend_failed);
if (emu_paused)
{
@@ -803,6 +786,36 @@ void cell_audio_thread::operator()()
continue;
}
bool operational = ringbuffer->get_operational_status();
if (!operational && loop_count % 128 == 0)
{
update_config(true);
operational = ringbuffer->get_operational_status();
}
if (ringbuffer->device_changed())
{
cellAudio.warning("Default device changed, attempting to switch...");
update_config(false);
if (operational != ringbuffer->get_operational_status())
{
continue;
}
}
if (!m_backend_failed && !operational)
{
cellAudio.error("Backend stopped unexpectedly (likely device change). Attempting to recover...");
m_backend_failed = true;
}
else if (m_backend_failed && operational)
{
cellAudio.success("Backend recovered");
m_backend_failed = false;
}
if (!cfg.buffering_enabled)
{
const u64 period_end = (m_counter * cfg.audio_block_period) + m_start_time;
@@ -906,7 +919,7 @@ void cell_audio_thread::operator()()
// As such, if the game doesn't touch buffers for too long we advance time hoping the game recovers
if (
(untouched == active_ports && time_since_last_period > cfg.fully_untouched_timeout) ||
(time_since_last_period > cfg.partially_untouched_timeout)
(time_since_last_period > cfg.partially_untouched_timeout) || g_cfg.audio.disable_sampling_skip
)
{
// There's no audio in the buffers, simply advance time and hope the game recovers
@@ -1859,12 +1872,13 @@ error_code cellAudioAdd6chData(u32 portNum, vm::ptr<float> src, float volume)
{
for (u32 i = 0; i < CELL_AUDIO_BLOCK_SAMPLES; i++)
{
// Channel order in src is Front Left, Center, Front Right, Surround Left, Surround Right, LFE
dst[i * 8 + 0] += src[i * 6 + 0] * volume; // mix L ch
dst[i * 8 + 1] += src[i * 6 + 1] * volume; // mix R ch
dst[i * 8 + 2] += src[i * 6 + 2] * volume; // mix center
dst[i * 8 + 3] += src[i * 6 + 3] * volume; // mix LFE
dst[i * 8 + 4] += src[i * 6 + 4] * volume; // mix rear L
dst[i * 8 + 5] += src[i * 6 + 5] * volume; // mix rear R
dst[i * 8 + 1] += src[i * 6 + 2] * volume; // mix R ch
dst[i * 8 + 2] += src[i * 6 + 1] * volume; // mix center
dst[i * 8 + 3] += src[i * 6 + 5] * volume; // mix LFE
dst[i * 8 + 4] += src[i * 6 + 3] * volume; // mix rear L
dst[i * 8 + 5] += src[i * 6 + 4] * volume; // mix rear R
//dst[i * 8 + 6] += 0.0f; // side L
//dst[i * 8 + 7] += 0.0f; // side R
}
+4 -2
View File
@@ -292,6 +292,7 @@ private:
audio_resampler resampler{};
atomic_t<bool> backend_active = false;
atomic_t<bool> backend_device_changed = false;
bool playing = false;
u64 update_timestamp = 0;
@@ -310,6 +311,7 @@ private:
void commit_data(f32* buf, u32 sample_cnt);
u32 backend_write_callback(u32 size, void *buf);
void backend_state_callback(AudioStateEvent event);
public:
audio_ringbuffer(cell_audio_config &cfg);
@@ -345,9 +347,9 @@ public:
return backend->Operational();
}
bool device_changed() const
bool device_changed()
{
return backend->DefaultDeviceChanged();
return backend_device_changed.test_and_reset() && backend->DefaultDeviceChanged();
}
std::string_view get_backend_name() const
+17 -17
View File
@@ -33,8 +33,8 @@ void fmt_class_string<CellAudioOutError>::format(std::string& out, u64 arg)
audio_out_configuration::audio_out_configuration()
{
audio_out& primary_output = out.at(CELL_AUDIO_OUT_PRIMARY);
audio_out& secondary_output = out.at(CELL_AUDIO_OUT_SECONDARY);
audio_out& primary_output = ::at32(out, CELL_AUDIO_OUT_PRIMARY);
audio_out& secondary_output = ::at32(out, CELL_AUDIO_OUT_SECONDARY);
std::vector<CellAudioOutSoundMode>& primary_modes = primary_output.sound_modes;
std::vector<CellAudioOutSoundMode>& secondary_modes = secondary_output.sound_modes;
@@ -58,8 +58,8 @@ audio_out_configuration::audio_out_configuration()
const auto add_sound_mode = [&](u32 index, u8 type, u8 channel, u8 fs, u32 layout, bool supported)
{
audio_out& output = out.at(index);
bool& selected = initial_mode_selected.at(index);
audio_out& output = ::at32(out, index);
bool& selected = ::at32(initial_mode_selected, index);
CellAudioOutSoundMode mode{};
mode.type = type;
@@ -103,7 +103,7 @@ audio_out_configuration::audio_out_configuration()
{
// Linear PCM 5.1 Ch. 48 kHz
add_sound_mode(CELL_AUDIO_OUT_PRIMARY, CELL_AUDIO_OUT_CODING_TYPE_LPCM, CELL_AUDIO_OUT_CHNUM_6, CELL_AUDIO_OUT_FS_48KHZ, CELL_AUDIO_OUT_SPEAKER_LAYOUT_6CH_LREClr, supports_lpcm_5_1);
// Dolby Digital 5.1 Ch.
add_sound_mode(CELL_AUDIO_OUT_PRIMARY, CELL_AUDIO_OUT_CODING_TYPE_AC3, CELL_AUDIO_OUT_CHNUM_6, CELL_AUDIO_OUT_FS_48KHZ, CELL_AUDIO_OUT_SPEAKER_LAYOUT_6CH_LREClr, supports_ac3);
@@ -161,8 +161,8 @@ audio_out_configuration::audio_out_configuration()
// The secondary output only supports Linear PCM 2 Ch.
add_sound_mode(CELL_AUDIO_OUT_SECONDARY, CELL_AUDIO_OUT_CODING_TYPE_LPCM, CELL_AUDIO_OUT_CHNUM_2, CELL_AUDIO_OUT_FS_48KHZ, CELL_AUDIO_OUT_SPEAKER_LAYOUT_2CH, true);
ensure(!primary_modes.empty() && initial_mode_selected.at(CELL_AUDIO_OUT_PRIMARY));
ensure(!secondary_modes.empty() && initial_mode_selected.at(CELL_AUDIO_OUT_SECONDARY));
ensure(!primary_modes.empty() && ::at32(initial_mode_selected, CELL_AUDIO_OUT_PRIMARY));
ensure(!secondary_modes.empty() && ::at32(initial_mode_selected, CELL_AUDIO_OUT_SECONDARY));
for (const CellAudioOutSoundMode& mode : primary_modes)
{
@@ -238,7 +238,7 @@ error_code cellAudioOutGetSoundAvailability(u32 audioOut, u32 type, u32 fs, u32
// Check if the requested audio parameters are available and find the max supported channel count
audio_out_configuration& cfg = g_fxo->get<audio_out_configuration>();
std::lock_guard lock(cfg.mtx);
const audio_out_configuration::audio_out& out = cfg.out.at(audioOut);
const audio_out_configuration::audio_out& out = ::at32(cfg.out, audioOut);
for (const CellAudioOutSoundMode& mode : out.sound_modes)
{
@@ -265,7 +265,7 @@ error_code cellAudioOutGetSoundAvailability2(u32 audioOut, u32 type, u32 fs, u32
// Check if the requested audio parameters are available
audio_out_configuration& cfg = g_fxo->get<audio_out_configuration>();
std::lock_guard lock(cfg.mtx);
const audio_out_configuration::audio_out& out = cfg.out.at(audioOut);
const audio_out_configuration::audio_out& out = ::at32(cfg.out, audioOut);
for (const CellAudioOutSoundMode& mode : out.sound_modes)
{
@@ -319,7 +319,7 @@ error_code cellAudioOutGetState(u32 audioOut, u32 deviceIndex, vm::ptr<CellAudio
{
audio_out_configuration& cfg = g_fxo->get<audio_out_configuration>();
std::lock_guard lock(cfg.mtx);
const audio_out_configuration::audio_out& out = cfg.out.at(audioOut);
const audio_out_configuration::audio_out& out = ::at32(cfg.out, audioOut);
_state.state = out.state;
_state.encoder = out.encoder;
@@ -360,7 +360,7 @@ error_code cellAudioOutConfigure(u32 audioOut, vm::ptr<CellAudioOutConfiguration
{
std::lock_guard lock(cfg.mtx);
audio_out_configuration::audio_out& out = cfg.out.at(audioOut);
audio_out_configuration::audio_out& out = ::at32(cfg.out, audioOut);
// Apparently the set config does not necessarily have to exist in the list of sound modes.
@@ -406,7 +406,7 @@ error_code cellAudioOutConfigure(u32 audioOut, vm::ptr<CellAudioOutConfiguration
audio_out_configuration& cfg = g_fxo->get<audio_out_configuration>();
{
std::lock_guard lock(cfg.mtx);
cfg.out.at(audioOut).state = CELL_AUDIO_OUT_OUTPUT_STATE_DISABLED;
::at32(cfg.out, audioOut).state = CELL_AUDIO_OUT_OUTPUT_STATE_DISABLED;
}
audio::configure_audio(true);
@@ -414,7 +414,7 @@ error_code cellAudioOutConfigure(u32 audioOut, vm::ptr<CellAudioOutConfiguration
{
std::lock_guard lock(cfg.mtx);
cfg.out.at(audioOut).state = CELL_AUDIO_OUT_OUTPUT_STATE_ENABLED;
::at32(cfg.out, audioOut).state = CELL_AUDIO_OUT_OUTPUT_STATE_ENABLED;
}
};
@@ -455,7 +455,7 @@ error_code cellAudioOutGetConfiguration(u32 audioOut, vm::ptr<CellAudioOutConfig
audio_out_configuration& cfg = g_fxo->get<audio_out_configuration>();
std::lock_guard lock(cfg.mtx);
const audio_out_configuration::audio_out& out = cfg.out.at(audioOut);
const audio_out_configuration::audio_out& out = ::at32(cfg.out, audioOut);
// Return the active config.
CellAudioOutConfiguration _config{};
@@ -516,7 +516,7 @@ error_code cellAudioOutGetDeviceInfo(u32 audioOut, u32 deviceIndex, vm::ptr<Cell
audio_out_configuration& cfg = g_fxo->get<audio_out_configuration>();
std::lock_guard lock(cfg.mtx);
ensure(audioOut < cfg.out.size());
const audio_out_configuration::audio_out& out = cfg.out.at(audioOut);
const audio_out_configuration::audio_out& out = ::at32(cfg.out, audioOut);
ensure(out.sound_modes.size() <= 16);
CellAudioOutDeviceInfo _info{};
@@ -528,7 +528,7 @@ error_code cellAudioOutGetDeviceInfo(u32 audioOut, u32 deviceIndex, vm::ptr<Cell
for (usz i = 0; i < out.sound_modes.size(); i++)
{
_info.availableModes[i] = out.sound_modes.at(i);
_info.availableModes[i] = ::at32(out.sound_modes, i);
}
*info = _info;
@@ -557,7 +557,7 @@ error_code cellAudioOutSetCopyControl(u32 audioOut, u32 control)
audio_out_configuration& cfg = g_fxo->get<audio_out_configuration>();
std::lock_guard lock(cfg.mtx);
cfg.out.at(audioOut).copy_control = control;
::at32(cfg.out, audioOut).copy_control = control;
return CELL_OK;
}
+1 -1
View File
@@ -175,7 +175,7 @@ static error_code check_camera_info(const VariantOfCellCameraInfo& info)
return CELL_CAMERA_ERROR_BAD_FRAMERATE;
}
auto check_fps = [fps = info.framerate](const std::vector<s32>& range)
auto check_fps = [fps = info.framerate](std::initializer_list<s32> range)
{
return std::find(range.begin(), range.end(), fps) != range.end();
};
-2
View File
@@ -477,5 +477,3 @@ struct gem_camera_shared
atomic_t<s32> size{0};
atomic_t<CellCameraFormat> format{CELL_CAMERA_RAW8};
};
static inline s32 get_video_buffer_size(s32 width, s32 height);
@@ -52,7 +52,7 @@ struct cross_controller
close_msg_dialog();
sysutil_register_cb([=](ppu_thread& ppu) -> s32
sysutil_register_cb([this, status](ppu_thread& ppu) -> s32
{
callback(ppu, CELL_CROSS_CONTROLLER_STATUS_FINALIZED, status, vm::null, userdata);
return CELL_OK;
@@ -74,9 +74,9 @@ struct cross_controller
// TODO: Show icons from comboplay_plugin.rco in dialog. Maybe use a new dialog or add an optional icon to this one.
error_code res = open_msg_dialog(false, CELL_MSGDIALOG_TYPE_DISABLE_CANCEL_OFF, vm::make_str(msg), msg_dialog_callback, userdata);
sysutil_register_cb([=](ppu_thread& ppu) -> s32
sysutil_register_cb([this, res](ppu_thread& ppu) -> s32
{
callback(ppu, CELL_CROSS_CONTROLLER_STATUS_INITIALIZED, res == CELL_OK ? CELL_OK : CELL_CROSS_CONTROLLER_ERROR_INTERNAL, vm::null, userdata);
callback(ppu, CELL_CROSS_CONTROLLER_STATUS_INITIALIZED, res == CELL_OK ? +CELL_OK : +CELL_CROSS_CONTROLLER_ERROR_INTERNAL, vm::null, userdata);
return CELL_OK;
});
+12 -16
View File
@@ -230,17 +230,12 @@ disc_change_manager::~disc_change_manager()
error_code disc_change_manager::register_callbacks(vm::ptr<CellGameDiscEjectCallback> func_eject, vm::ptr<CellGameDiscInsertCallback> func_insert)
{
if (!func_eject || !func_insert)
{
return CELL_GAME_ERROR_PARAM;
}
std::lock_guard lock(mtx);
eject_callback = func_eject;
insert_callback = func_insert;
Emu.GetCallbacks().enable_disc_eject(true);
Emu.GetCallbacks().enable_disc_eject(!!func_eject);
Emu.GetCallbacks().enable_disc_insert(false);
return CELL_OK;
@@ -423,13 +418,13 @@ error_code cellHddGameCheck(ppu_thread& ppu, u32 version, vm::cptr<char> dirName
const psf::registry psf = psf::load_object(fs::file(local_dir +"/PARAM.SFO"));
// Some following fields may be zero in old FW 1.00 version PARAM.SFO
if (psf.contains("PARENTAL_LEVEL")) get->getParam.parentalLevel = psf.at("PARENTAL_LEVEL").as_integer();
if (psf.contains("ATTRIBUTE")) get->getParam.attribute = psf.at("ATTRIBUTE").as_integer();
if (psf.contains("RESOLUTION")) get->getParam.resolution = psf.at("RESOLUTION").as_integer();
if (psf.contains("SOUND_FORMAT")) get->getParam.soundFormat = psf.at("SOUND_FORMAT").as_integer();
if (psf.contains("TITLE")) strcpy_trunc(get->getParam.title, psf.at("TITLE").as_string());
if (psf.contains("APP_VER")) strcpy_trunc(get->getParam.dataVersion, psf.at("APP_VER").as_string());
if (psf.contains("TITLE_ID")) strcpy_trunc(get->getParam.titleId, psf.at("TITLE_ID").as_string());
if (psf.contains("PARENTAL_LEVEL")) get->getParam.parentalLevel = ::at32(psf, "PARENTAL_LEVEL").as_integer();
if (psf.contains("ATTRIBUTE")) get->getParam.attribute = ::at32(psf, "ATTRIBUTE").as_integer();
if (psf.contains("RESOLUTION")) get->getParam.resolution = ::at32(psf, "RESOLUTION").as_integer();
if (psf.contains("SOUND_FORMAT")) get->getParam.soundFormat = ::at32(psf, "SOUND_FORMAT").as_integer();
if (psf.contains("TITLE")) strcpy_trunc(get->getParam.title, ::at32(psf, "TITLE").as_string());
if (psf.contains("APP_VER")) strcpy_trunc(get->getParam.dataVersion, ::at32(psf, "APP_VER").as_string());
if (psf.contains("TITLE_ID")) strcpy_trunc(get->getParam.titleId, ::at32(psf, "TITLE_ID").as_string());
for (u32 i = 0; i < CELL_HDDGAME_SYSP_LANGUAGE_NUM; i++)
{
@@ -1536,7 +1531,8 @@ error_code cellGameContentErrorDialog(s32 type, s32 errNeedSizeKB, vm::cptr<char
return CELL_GAME_ERROR_PARAM;
}
error_msg += "\n" + get_localized_string(localized_string_id::CELL_GAME_ERROR_DIR_NAME, fmt::format("%s", dirName).c_str());
error_msg += '\n';
error_msg += get_localized_string(localized_string_id::CELL_GAME_ERROR_DIR_NAME, fmt::format("%s", dirName).c_str());
}
return open_exit_dialog(error_msg, type > CELL_GAME_ERRDIALOG_NOSPACE);
@@ -1714,8 +1710,8 @@ error_code cellDiscGameGetBootDiscInfo(vm::ptr<CellDiscGameSystemFileParam> getP
const psf::registry psf = psf::load_object(fs::file(vfs::get(dir + "/PARAM.SFO")));
if (psf.contains("PARENTAL_LEVEL")) getParam->parentalLevel = psf.at("PARENTAL_LEVEL").as_integer();
if (psf.contains("TITLE_ID")) strcpy_trunc(getParam->titleId, psf.at("TITLE_ID").as_string());
if (psf.contains("PARENTAL_LEVEL")) getParam->parentalLevel = ::at32(psf, "PARENTAL_LEVEL").as_integer();
if (psf.contains("TITLE_ID")) strcpy_trunc(getParam->titleId, ::at32(psf, "TITLE_ID").as_string());
return CELL_OK;
}
+1 -3
View File
@@ -322,7 +322,7 @@ error_code cellGcmBindZcull(u8 index, u32 offset, u32 width, u32 height, u32 cul
{
return err;
}
vm::_ptr<CellGcmZcullInfo>(gcm_cfg.zculls_addr)[index] = gcm_zcull;
return CELL_OK;
}
@@ -1314,8 +1314,6 @@ void _cellGcmSetFlipCommandWithWaitLabel(ppu_thread& ppu, vm::ptr<CellGcmContext
{
cellGcmSys.warning("cellGcmSetFlipCommandWithWaitLabel(ctx=*0x%x, id=0x%x, label_index=0x%x, label_value=0x%x)", ctx, id, label_index, label_value);
auto& gcm_cfg = g_fxo->get<gcm_config>();
rsx::make_command(ctx->current, NV406E_SEMAPHORE_OFFSET, { label_index * 0x10, label_value });
if (auto error = gcmSetPrepareFlip<true>(ppu, ctx, id); error < 0)
+9 -9
View File
@@ -219,7 +219,7 @@ public:
break;
}
gem_controller& controller = controllers.at(gem_num);
gem_controller& controller = ::at32(controllers, gem_num);
controller = {};
controller.sphere_rgb = gem_color::get_default_color(gem_num);
@@ -446,7 +446,7 @@ static bool check_gem_num(const u32 gem_num)
return gem_num < CELL_GEM_MAX_NUM;
}
static inline void draw_overlay_cursor(u32 gem_num, const gem_config::gem_controller& controller, s32 x_pos, s32 y_pos, s32 x_max, s32 y_max)
static inline void draw_overlay_cursor(u32 gem_num, const gem_config::gem_controller&, s32 x_pos, s32 y_pos, s32 x_max, s32 y_max)
{
const u16 x = static_cast<u16>(x_pos / (x_max / static_cast<f32>(rsx::overlays::overlay::virtual_width)));
const u16 y = static_cast<u16>(y_pos / (y_max / static_cast<f32>(rsx::overlays::overlay::virtual_height)));
@@ -563,7 +563,7 @@ static void ds3_input_to_pad(const u32 port_no, be_t<u16>& digital_buttons, be_t
std::lock_guard lock(pad::g_pad_mutex);
const auto handler = pad::get_current_handler();
const auto& pad = handler->GetPads().at(port_no);
const auto& pad = ::at32(handler->GetPads(), port_no);
if (!(pad->m_port_status & CELL_PAD_STATUS_CONNECTED))
{
@@ -656,7 +656,7 @@ static void ds3_pos_to_gem_image_state(const u32 port_no, const gem_config::gem_
std::lock_guard lock(pad::g_pad_mutex);
const auto handler = pad::get_current_handler();
const auto& pad = handler->GetPads().at(port_no);
const auto& pad = ::at32(handler->GetPads(), port_no);
if (!(pad->m_port_status & CELL_PAD_STATUS_CONNECTED))
{
@@ -679,7 +679,7 @@ static void ds3_pos_to_gem_state(const u32 port_no, const gem_config::gem_contro
std::lock_guard lock(pad::g_pad_mutex);
const auto handler = pad::get_current_handler();
const auto& pad = handler->GetPads().at(port_no);
const auto& pad = ::at32(handler->GetPads(), port_no);
if (!(pad->m_port_status & CELL_PAD_STATUS_CONNECTED))
{
@@ -712,7 +712,7 @@ static void ds3_input_to_ext(const u32 port_no, const gem_config::gem_controller
std::lock_guard lock(pad::g_pad_mutex);
const auto handler = pad::get_current_handler();
const auto& pad = handler->GetPads().at(port_no);
const auto& pad = ::at32(handler->GetPads(), port_no);
if (!(pad->m_port_status & CELL_PAD_STATUS_CONNECTED))
{
@@ -769,7 +769,7 @@ static bool mouse_input_to_pad(const u32 mouse_no, be_t<u16>& digital_buttons, b
return false;
}
const auto& mouse_data = handler.GetMice().at(mouse_no);
const auto& mouse_data = ::at32(handler.GetMice(), mouse_no);
const auto is_pressed = [&mouse_data](MouseButtonCodes button) -> bool { return !!(mouse_data.buttons & button); };
digital_buttons = 0;
@@ -822,7 +822,7 @@ static void mouse_pos_to_gem_image_state(const u32 mouse_no, const gem_config::g
return;
}
const auto& mouse = handler.GetMice().at(mouse_no);
const auto& mouse = ::at32(handler.GetMice(), mouse_no);
pos_to_gem_image_state(mouse_no, controller, gem_image_state, mouse.x_pos, mouse.y_pos, mouse.x_max, mouse.y_max);
}
@@ -846,7 +846,7 @@ static void mouse_pos_to_gem_state(const u32 mouse_no, const gem_config::gem_con
return;
}
const auto& mouse = handler.GetMice().at(mouse_no);
const auto& mouse = ::at32(handler.GetMice(), mouse_no);
pos_to_gem_state(mouse_no, controller, gem_state, mouse.x_pos, mouse.y_pos, mouse.x_max, mouse.y_max);
}
+3 -3
View File
@@ -1120,7 +1120,7 @@ error_code cellHttpAuthCacheExport(vm::ptr<u32> buf, u32 len, vm::ptr<u32> outsi
// TODO
}
u32 size = 0;
[[maybe_unused]] u32 size = 0;
// TODO
@@ -2786,7 +2786,7 @@ error_code cellHttpClientAddHeader(CellHttpClientId clientId, vm::cptr<CellHttpH
error_code cellHttpClientDeleteHeader(CellHttpClientId clientId, vm::cptr<char> name)
{
cellHttp.todo("cellHttpClientDeleteHeader(clientId=0x%x, name=%s)", clientId, name);
auto& man = g_fxo->get<http_manager>();
std::lock_guard lock(man.mtx);
@@ -2806,7 +2806,7 @@ error_code cellHttpClientDeleteHeader(CellHttpClientId clientId, vm::cptr<char>
error_code cellHttpClientSetSslCallback(CellHttpClientId clientId, vm::ptr<CellHttpsSslCallback> cbfunc, vm::ptr<void> userArg)
{
cellHttp.todo("cellHttpClientSetSslCallback(clientId=0x%x, cbfunc=*0x%x, userArg=*0x%x)", clientId, cbfunc, userArg);
auto& man = g_fxo->get<http_manager>();
std::lock_guard lock(man.mtx);
+2 -2
View File
@@ -230,7 +230,7 @@ error_code cellHttpUtilBuildRequestLine(vm::cptr<CellHttpRequestLine> req, vm::p
std::string path = fmt::format("%s", req->path);
if (path.empty())
{
path = "/";
path += '/';
}
// TODO: are the numbers properly formatted ?
@@ -805,7 +805,7 @@ error_code cellHttpUtilBase64Encoder(vm::ptr<char> out, vm::cptr<void> input, u3
error_code cellHttpUtilBase64Decoder(vm::ptr<char> output, vm::cptr<void> in, u32 len)
{
cellHttpUtil.todo("cellHttpUtilBase64Decoder(output=*0x%x, in=*0x%x, len=%d)", output, in, len);
cellHttpUtil.todo("cellHttpUtilBase64Decoder(output=*0x%x, in=*0x%x, len=%d)", output, in, len);
if (!in)
{
+7
View File
@@ -45,7 +45,14 @@ bool ime_jp_manager::addChar(u16 c)
std::u16string tmp;
tmp += c;
#if defined(__GNUG__) && !defined(__clang__)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wrestrict"
#endif
input_string.insert(cursor++, tmp);
#if defined(__GNUG__) && !defined(__clang__)
#pragma GCC diagnostic pop
#endif
cursor_end = cursor;
input_state = CELL_IMEJP_BEFORE_CONVERT;
return true;
+1 -1
View File
@@ -49,7 +49,7 @@ KeyboardHandlerBase::KeyboardHandlerBase(utils::serial* ar)
Emu.DeferDeserialization([this]()
{
Init(m_info.max_connect);
init.init();
auto lk = init.init();
});
}
}
-2
View File
@@ -56,5 +56,3 @@ struct CellKbConfig
be_t<u32> read_mode;
be_t<u32> code_type;
};
u16 cellKbCnvRawCode(u32 arrange, u32 mkey, u32 led, u16 rawcode);
+17 -17
View File
@@ -151,23 +151,23 @@ void mic_context::load_config_and_init()
for (s32 index = 0; index < static_cast<s32>(device_list.size()); index++)
{
mic_list.emplace(std::piecewise_construct, std::forward_as_tuple(index), std::forward_as_tuple(microphone_handler::standard));
mic_list.at(index).add_device(device_list[index]);
::at32(mic_list, index).add_device(device_list[index]);
}
break;
}
case microphone_handler::singstar:
{
mic_list.emplace(std::piecewise_construct, std::forward_as_tuple(0), std::forward_as_tuple(microphone_handler::singstar));
mic_list.at(0).add_device(device_list[0]);
::at32(mic_list, 0).add_device(device_list[0]);
if (device_list.size() >= 2)
mic_list.at(0).add_device(device_list[1]);
::at32(mic_list, 0).add_device(device_list[1]);
break;
}
case microphone_handler::real_singstar:
case microphone_handler::rocksmith:
{
mic_list.emplace(std::piecewise_construct, std::forward_as_tuple(0), std::forward_as_tuple(g_cfg.audio.microphone_type));
mic_list.at(0).add_device(device_list[0]);
::at32(mic_list, 0).add_device(device_list[0]);
break;
}
case microphone_handler::null:
@@ -563,7 +563,7 @@ error_code cellMicOpen(s32 dev_num, s32 sampleRate)
if (!mic_thr.mic_list.count(dev_num))
return CELL_MICIN_ERROR_DEVICE_NOT_FOUND;
auto& device = mic_thr.mic_list.at(dev_num);
auto& device = ::at32(mic_thr.mic_list, dev_num);
if (device.is_opened())
return CELL_MICIN_ERROR_ALREADY_OPEN;
@@ -583,7 +583,7 @@ error_code cellMicOpenRaw(s32 dev_num, s32 sampleRate, s32 maxChannels)
if (!mic_thr.mic_list.count(dev_num))
return CELL_MICIN_ERROR_DEVICE_NOT_FOUND;
auto& device = mic_thr.mic_list.at(dev_num);
auto& device = ::at32(mic_thr.mic_list, dev_num);
if (device.is_opened())
return CELL_MICIN_ERROR_ALREADY_OPEN;
@@ -604,7 +604,7 @@ error_code cellMicOpenEx(s32 dev_num, s32 rawSampleRate, s32 rawChannel, s32 DSP
if (!mic_thr.mic_list.count(dev_num))
return CELL_MICIN_ERROR_DEVICE_NOT_FOUND;
auto& device = mic_thr.mic_list.at(dev_num);
auto& device = ::at32(mic_thr.mic_list, dev_num);
if (device.is_opened())
return CELL_MICIN_ERROR_ALREADY_OPEN;
@@ -626,7 +626,7 @@ u8 cellMicIsOpen(s32 dev_num)
if (!mic_thr.mic_list.count(dev_num))
return false;
return mic_thr.mic_list.at(dev_num).is_opened();
return ::at32(mic_thr.mic_list, dev_num).is_opened();
}
s32 cellMicIsAttached(s32 dev_num)
@@ -647,7 +647,7 @@ error_code cellMicClose(s32 dev_num)
if (!mic_thr.mic_list.count(dev_num))
return CELL_MICIN_ERROR_DEVICE_NOT_FOUND;
auto& device = mic_thr.mic_list.at(dev_num);
auto& device = ::at32(mic_thr.mic_list, dev_num);
if (!device.is_opened())
return CELL_MICIN_ERROR_NOT_OPEN;
@@ -669,7 +669,7 @@ error_code cellMicStart(s32 dev_num)
if (!mic_thr.mic_list.count(dev_num))
return CELL_MICIN_ERROR_DEVICE_NOT_FOUND;
auto& device = mic_thr.mic_list.at(dev_num);
auto& device = ::at32(mic_thr.mic_list, dev_num);
if (!device.is_opened())
return CELL_MICIN_ERROR_NOT_OPEN;
@@ -691,7 +691,7 @@ error_code cellMicStartEx(s32 dev_num, u32 iflags)
if (!mic_thr.mic_list.count(dev_num))
return CELL_MICIN_ERROR_DEVICE_NOT_FOUND;
auto& device = mic_thr.mic_list.at(dev_num);
auto& device = ::at32(mic_thr.mic_list, dev_num);
if (!device.is_opened())
return CELL_MICIN_ERROR_NOT_OPEN;
@@ -713,7 +713,7 @@ error_code cellMicStop(s32 dev_num)
if (!mic_thr.mic_list.count(dev_num))
return CELL_MICIN_ERROR_DEVICE_NOT_FOUND;
auto& device = mic_thr.mic_list.at(dev_num);
auto& device = ::at32(mic_thr.mic_list, dev_num);
if (!device.is_opened())
return CELL_MICIN_ERROR_NOT_OPEN;
@@ -743,7 +743,7 @@ error_code cellMicGetDeviceAttr(s32 dev_num, CellMicDeviceAttr deviceAttributes,
if (!mic_thr.mic_list.count(dev_num))
return CELL_MICIN_ERROR_DEVICE_NOT_FOUND;
auto& device = mic_thr.mic_list.at(dev_num);
auto& device = ::at32(mic_thr.mic_list, dev_num);
switch (deviceAttributes)
{
@@ -771,7 +771,7 @@ error_code cellMicSetDeviceAttr(s32 dev_num, CellMicDeviceAttr deviceAttributes,
if (!mic_thr.mic_list.count(dev_num))
return CELL_MICIN_ERROR_DEVICE_NOT_FOUND;
auto& device = mic_thr.mic_list.at(dev_num);
auto& device = ::at32(mic_thr.mic_list, dev_num);
switch (deviceAttributes)
{
@@ -854,7 +854,7 @@ error_code cellMicGetFormatRaw(s32 dev_num, vm::ptr<CellMicInputFormatI> format)
if (!mic_thr.mic_list.count(dev_num))
return CELL_MICIN_ERROR_DEVICE_NOT_FOUND;
auto& device = mic_thr.mic_list.at(dev_num);
auto& device = ::at32(mic_thr.mic_list, dev_num);
format->subframeSize = device.get_bit_resolution() / 8; // Probably?
format->bitResolution = device.get_bit_resolution();
@@ -956,7 +956,7 @@ error_code cellMicReadRaw(s32 dev_num, vm::ptr<void> data, s32 max_bytes)
if (!mic_thr.mic_list.count(dev_num))
return CELL_MICIN_ERROR_DEVICE_NOT_FOUND;
auto& mic = mic_thr.mic_list.at(dev_num);
auto& mic = ::at32(mic_thr.mic_list, dev_num);
if (!mic.is_opened() || !(mic.get_signal_types() & CELLMIC_SIGTYPE_RAW))
return CELL_MICIN_ERROR_NOT_OPEN;
@@ -978,7 +978,7 @@ error_code cellMicRead(s32 dev_num, vm::ptr<void> data, u32 max_bytes)
if (!mic_thr.mic_list.count(dev_num))
return CELL_MICIN_ERROR_DEVICE_NOT_FOUND;
auto& mic = mic_thr.mic_list.at(dev_num);
auto& mic = ::at32(mic_thr.mic_list, dev_num);
if (!mic.is_opened() || !(mic.get_signal_types() & CELLMIC_SIGTYPE_DSP))
return CELL_MICIN_ERROR_NOT_OPEN;
+1 -1
View File
@@ -49,7 +49,7 @@ MouseHandlerBase::MouseHandlerBase(utils::serial* ar)
Emu.DeferDeserialization([this]()
{
Init(m_info.max_connect);
init.init();
auto lk = init.init();
});
}
}
+1 -1
View File
@@ -245,7 +245,7 @@ error_code open_msg_dialog(bool is_blocking, u32 type, vm::cptr<char> msgString,
break;
}
thread_ctrl::wait_on(ppu.state, state);
ppu.state.wait(state);
}
if (is_blocking)
+43 -9
View File
@@ -161,8 +161,8 @@ struct music_state
if (next_track < playlist.size())
{
path = vfs::get(playlist.at(next_track));
cellMusic.notice("set_playback_command: current vfs path: '%s' (unresolved='%s')", path, playlist.at(next_track));
path = vfs::get(::at32(playlist, next_track));
cellMusic.notice("set_playback_command: current vfs path: '%s' (unresolved='%s')", path, ::at32(playlist, next_track));
}
else
{
@@ -244,10 +244,15 @@ error_code cellMusicGetSelectionContext(vm::ptr<CellMusicSelectionContext> conte
if (!context)
return CELL_MUSIC_ERROR_PARAM;
auto& music = g_fxo->get<music_state>();
std::lock_guard lock(music.mtx);
if (!music.current_selection_context)
{
return CELL_MUSIC2_ERROR_NO_ACTIVE_CONTENT;
}
*context = music.current_selection_context.get();
cellMusic.success("cellMusicGetSelectionContext: selection context = %s", music.current_selection_context.to_string());
@@ -317,6 +322,12 @@ error_code cellMusicGetContentsId(vm::ptr<CellSearchContentId> contents_id)
// HACKY
auto& music = g_fxo->get<music_state>();
std::lock_guard lock(music.mtx);
if (!music.current_selection_context)
{
return CELL_MUSIC2_ERROR_NO_ACTIVE_CONTENT;
}
return music.current_selection_context.find_content_id(contents_id);
}
@@ -363,6 +374,7 @@ error_code cellMusicInitialize2SystemWorkload(s32 mode, vm::ptr<CellMusic2Callba
auto& music = g_fxo->get<music_state>();
music.func = func;
music.userData = userData;
music.current_selection_context = {};
sysutil_register_cb([=, &music](ppu_thread& ppu) -> s32
{
@@ -429,6 +441,7 @@ error_code cellMusicInitializeSystemWorkload(s32 mode, u32 container, vm::ptr<Ce
auto& music = g_fxo->get<music_state>();
music.func = func;
music.userData = userData;
music.current_selection_context = {};
sysutil_register_cb([=, &music](ppu_thread& ppu) -> s32
{
@@ -451,6 +464,7 @@ error_code cellMusicInitialize(s32 mode, u32 container, s32 spuPriority, vm::ptr
auto& music = g_fxo->get<music_state>();
music.func = func;
music.userData = userData;
music.current_selection_context = {};
sysutil_register_cb([=, &music](ppu_thread& ppu) -> s32
{
@@ -489,6 +503,11 @@ error_code cellMusicGetSelectionContext2(vm::ptr<CellMusicSelectionContext> cont
auto& music = g_fxo->get<music_state>();
std::lock_guard lock(music.mtx);
if (!music.current_selection_context)
{
return CELL_MUSIC2_ERROR_NO_ACTIVE_CONTENT;
}
*context = music.current_selection_context.get();
cellMusic.success("cellMusicGetSelectionContext2: selection context = %s", music.current_selection_context.to_string());
@@ -533,14 +552,21 @@ error_code cellMusicSetPlaybackCommand2(s32 command, vm::ptr<void> param)
if (!music.func)
return CELL_MUSIC2_ERROR_GENERIC;
sysutil_register_cb([=, &music](ppu_thread& ppu) -> s32
error_code result = CELL_OK;
if (!music.current_selection_context)
{
const error_code result = music.set_playback_command(command);
result = CELL_MUSIC_ERROR_GENERIC;
}
sysutil_register_cb([=, &music, prev_res = result](ppu_thread& ppu) -> s32
{
const error_code result = prev_res ? prev_res : music.set_playback_command(command);
music.func(ppu, CELL_MUSIC2_EVENT_SET_PLAYBACK_COMMAND_RESULT, vm::addr_t(+result), music.userData);
return CELL_OK;
});
return CELL_OK;
return result;
}
error_code cellMusicSetPlaybackCommand(s32 command, vm::ptr<void> param)
@@ -555,14 +581,21 @@ error_code cellMusicSetPlaybackCommand(s32 command, vm::ptr<void> param)
if (!music.func)
return CELL_MUSIC_ERROR_GENERIC;
sysutil_register_cb([=, &music](ppu_thread& ppu) -> s32
error_code result = CELL_OK;
if (!music.current_selection_context)
{
const error_code result = music.set_playback_command(command);
result = CELL_MUSIC2_ERROR_GENERIC;
}
sysutil_register_cb([=, &music, prev_res = result](ppu_thread& ppu) -> s32
{
const error_code result = prev_res ? prev_res : music.set_playback_command(command);
music.func(ppu, CELL_MUSIC_EVENT_SET_PLAYBACK_COMMAND_RESULT, vm::addr_t(+result), music.userData);
return CELL_OK;
});
return CELL_OK;
return result;
}
error_code cellMusicSelectContents2()
@@ -591,6 +624,7 @@ error_code cellMusicInitialize2(s32 mode, s32 spuPriority, vm::ptr<CellMusic2Cal
auto& music = g_fxo->get<music_state>();
music.func = func;
music.userData = userData;
music.current_selection_context = {};
sysutil_register_cb([=, &music](ppu_thread& ppu) -> s32
{
+6
View File
@@ -141,6 +141,7 @@ struct CellMusicSelectionContext
struct music_selection_context
{
bool valid = false;
char magic[4] = "SUS";
std::string hash;
CellSearchContentType content_type = CELL_SEARCH_CONTENTTYPE_MUSIC;
@@ -167,6 +168,11 @@ struct music_selection_context
bool load_playlist();
u32 step_track(bool next);
operator bool() const
{
return atomic_storage<bool>::load(valid);
}
// Helper
error_code find_content_id(vm::ptr<CellSearchContentId> contents_id);
};
+2 -2
View File
@@ -235,7 +235,7 @@ error_code cell_music_decode_read(vm::ptr<void> buf, vm::ptr<u32> startTime, u64
{
start_time_ms = dec.decoder.timestamps_ms.front().second;
while (dec.decoder.timestamps_ms.size() > 1 && dec.read_pos >= dec.decoder.timestamps_ms.at(1).first)
while (dec.decoder.timestamps_ms.size() > 1 && dec.read_pos >= ::at32(dec.decoder.timestamps_ms, 1).first)
{
dec.decoder.timestamps_ms.pop_front();
}
@@ -274,7 +274,7 @@ error_code cell_music_decode_read(vm::ptr<void> buf, vm::ptr<u32> startTime, u64
error_code cellMusicDecodeInitialize(s32 mode, u32 container, s32 spuPriority, vm::ptr<CellMusicDecodeCallback> func, vm::ptr<void> userData)
{
cellMusicDecode.warning("cellMusicDecodeInitialize(mode=0x%x, container=0x%x, spuPriority=0x%x, func=*0x%x, userData=*0x%x)", mode, container, spuPriority, func, userData);
if (mode != CELL_MUSIC_DECODE2_MODE_NORMAL || (spuPriority - 0x10U > 0xef) || !func)
{
return CELL_MUSIC_DECODE_ERROR_PARAM;
@@ -47,7 +47,7 @@ std::string music_selection_context::to_string() const
for (usz i = 0; i < playlist.size(); i++)
{
fmt::append(str, "\n - Track %d: %s", i, playlist.at(i));
fmt::append(str, "\n - Track %d: %s", i, ::at32(playlist, i));
}
return str;
@@ -242,6 +242,7 @@ bool music_selection_context::load_playlist()
playlist.push_back(track_node[i].Scalar());
}
valid = true;
return true;
}
+2 -2
View File
@@ -212,7 +212,7 @@ error_code cellNetCtlGetInfo(s32 code, vm::ptr<CellNetCtlInfo> info)
case CELL_NET_CTL_INFO_DEFAULT_ROUTE: strcpy_trunc(info->default_route, "192.168.1.1"); break;
case CELL_NET_CTL_INFO_PRIMARY_DNS: strcpy_trunc(info->primary_dns, np::ip_to_string(nph.get_dns_ip())); break;
case CELL_NET_CTL_INFO_SECONDARY_DNS: strcpy_trunc(info->secondary_dns, np::ip_to_string(nph.get_dns_ip())); break;
case CELL_NET_CTL_INFO_IP_ADDRESS: strcpy_trunc(info->ip_address, np::ip_to_string(nph.get_local_ip_addr())); break;
case CELL_NET_CTL_INFO_IP_ADDRESS: strcpy_trunc(info->ip_address, np::ip_to_string(nph.get_public_ip_addr())); break;
case CELL_NET_CTL_INFO_NETMASK: strcpy_trunc(info->netmask, "255.255.255.255"); break;
case CELL_NET_CTL_INFO_HTTP_PROXY_CONFIG: info->http_proxy_config = 0; break;
case CELL_NET_CTL_INFO_DHCP_HOSTNAME: strcpy_trunc(info->dhcp_hostname, nph.get_hostname()); break;
@@ -237,7 +237,7 @@ struct netstart_hack
error_code cellNetCtlNetStartDialogLoadAsync(vm::cptr<CellNetCtlNetStartDialogParam> param)
{
cellNetCtl.error("cellNetCtlNetStartDialogLoadAsync(param=*0x%x)", param);
cellNetCtl.warning("cellNetCtlNetStartDialogLoadAsync(param=*0x%x)", param);
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
+1 -1
View File
@@ -42,7 +42,7 @@ bool check_config(vm::cptr<CellPngEncConfig> config)
if (!config ||
config->maxWidth == 0u || config->maxWidth > 1000000u ||
config->maxHeight == 0u || config->maxHeight > 1000000u ||
config->maxBitDepth != 8u && config->maxBitDepth != 16u ||
(config->maxBitDepth != 8u && config->maxBitDepth != 16u) ||
static_cast<s32>(config->addMemSize) < 0 ||
config->exParamNum != 0u)
{
+19 -15
View File
@@ -7,9 +7,6 @@
#include "Emu/Cell/lv2/sys_memory.h"
#include "Emu/Cell/lv2/sys_ss.h"
//#include <iomanip>
//#include <sstream>
LOG_CHANNEL(cellRtc);
// clang-format off
@@ -43,16 +40,16 @@ void fmt_class_string<CellRtcError>::format(std::string& out, u64 arg)
// Grabbed from JPCSP
// This is the # of microseconds between January 1, 0001 and January 1, 1970.
const u64 RTC_MAGIC_OFFSET = 62135596800000000ULL;
constexpr u64 RTC_MAGIC_OFFSET = 62135596800000000ULL;
// This is the # of microseconds between January 1, 0001 and January 1, 1601 (for Win32 FILETIME.)
const u64 RTC_FILETIME_OFFSET = 50491123200000000ULL;
constexpr u64 RTC_FILETIME_OFFSET = 50491123200000000ULL;
const u64 EPOCH_AS_FILETIME = 116444736000000000ULL;
constexpr u64 EPOCH_AS_FILETIME = 116444736000000000ULL;
// Also stores leap year
const u8 DAYS_IN_MONTH[24] = {0x1F, 0x1C, 0x1F, 0x1E, 0x1F, 0x1E, 0x1F, 0x1F, 0x1E, 0x1F, 0x1E, 0x1F, 0x1F, 0x1D, 0x1F, 0x1E, 0x1F, 0x1E, 0x1F, 0x1F, 0x1E, 0x1F, 0x1E, 0x1F};
const char WEEKDAY_NAMES[7][4] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"}; // 4 as terminator
const char MONTH_NAMES[12][4] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}; // 4 as terminator
constexpr u8 DAYS_IN_MONTH[24] = {0x1F, 0x1C, 0x1F, 0x1E, 0x1F, 0x1E, 0x1F, 0x1F, 0x1E, 0x1F, 0x1E, 0x1F, 0x1F, 0x1D, 0x1F, 0x1E, 0x1F, 0x1E, 0x1F, 0x1F, 0x1E, 0x1F, 0x1E, 0x1F};
constexpr char WEEKDAY_NAMES[7][4] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"}; // 4 as terminator
constexpr char MONTH_NAMES[12][4] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}; // 4 as terminator
s64 convertToUNIXTime(u16 seconds, u16 minutes, u16 hours, u16 days, s32 years)
{
@@ -122,7 +119,7 @@ error_code cellRtcGetCurrentTick(vm::ptr<CellRtcTick> pTick)
error_code cellRtcGetCurrentClock(vm::ptr<CellRtcDateTime> pClock, s32 iTimeZone)
{
cellRtc.todo("cellRtcGetCurrentClock(pClock=*0x%x, time_zone=%d)", pClock, iTimeZone);
cellRtc.todo("cellRtcGetCurrentClock(pClock=*0x%x, iTimeZone=%d)", pClock, iTimeZone);
if (!vm::check_addr(pClock.addr()))
{
@@ -1131,6 +1128,13 @@ error_code cellRtcGetCurrentSecureTick(vm::ptr<CellRtcTick> tick)
{
cellRtc.todo("cellRtcGetCurrentSecureTick(*0x%x)", tick);
if (!vm::check_addr(tick.addr()))
{
return CELL_RTC_ERROR_INVALID_POINTER;
}
// TODO
return CELL_OK;
}
@@ -1445,7 +1449,7 @@ error_code cellRtcIsLeapYear(s32 year)
{
cellRtc.todo("cellRtcIsLeapYear(year=%d)", year);
if (year < 0)
if (year < 1)
{
return CELL_RTC_ERROR_INVALID_ARG;
}
@@ -1457,7 +1461,7 @@ error_code cellRtcGetDaysInMonth(s32 year, s32 month)
{
cellRtc.todo("cellRtcGetDaysInMonth(year=%d, month=%d)", year, month);
if ((year < 0) || (month <= 0) || (month > 12))
if ((year <= 0) || (month <= 0) || (month > 12))
{
return CELL_RTC_ERROR_INVALID_ARG;
}
@@ -1474,10 +1478,10 @@ error_code cellRtcGetDayOfWeek(s32 year, s32 month, s32 day)
{
cellRtc.trace("cellRtcGetDayOfWeek(year=%d, month=%d, day=%d)", year, month, day);
if (month - 1 < 2)
if (month == 1 || month == 2)
{
year -= 1;
month += 0xc;
year--;
month += 12;
}
return not_an_error(((month * 0xd + 8) / 5 + ((year + (year >> 2) + (year < 0 && (year & 3U) != 0)) - year / 100) + year / 400 + day) % 7);
+7 -7
View File
@@ -29,13 +29,13 @@ struct CellRtcTick
struct CellRtcDateTime
{
be_t<u16> year;
be_t<u16> month;
be_t<u16> day;
be_t<u16> hour;
be_t<u16> minute;
be_t<u16> second;
be_t<u32> microsecond;
be_t<u16> year; // 1 to 9999
be_t<u16> month; // 1 to 12
be_t<u16> day; // 1 to 31
be_t<u16> hour; // 0 to 23
be_t<u16> minute; // 0 to 59
be_t<u16> second; // 0 to 59
be_t<u32> microsecond; // 0 to 999999
};
error_code cellRtcTickAddYears(vm::ptr<CellRtcTick> pTick0, vm::cptr<CellRtcTick> pTick1, s32 iAdd);
+1 -1
View File
@@ -148,7 +148,7 @@ int check_filename(std::string_view file_path, bool disallow_system_files, bool
return 70;
}
char name[CELL_SAVEDATA_FILENAME_SIZE - 3];
char name[CELL_SAVEDATA_FILENAME_SIZE + 3];
if (dotpos)
{
+2 -2
View File
@@ -1297,7 +1297,7 @@ error_code cellSearchStartSceneSearch(CellSearchSceneSearchType searchType, vm::
return CELL_SEARCH_ERROR_PARAM;
}
if (tagNum) // TODO: find out if this is the correct location for these checks
if (tagNum) // TODO: find out if this is the correct location for these checks
{
if (tagNum > CELL_SEARCH_TAG_NUM_MAX || !tags)
{
@@ -1580,7 +1580,7 @@ error_code cellSearchGetContentIdByOffset(CellSearchId searchId, s32 offset, vm:
if (offset >= 0 && offset + 0u < searchObject->content_ids.size())
{
auto& content_id = searchObject->content_ids.at(offset);
auto& content_id = ::at32(searchObject->content_ids, offset);
const u128 content_id_128 = content_id.first;
*outContentType = content_id.second->type;
std::memcpy(outContentId->data, &content_id_128, CELL_SEARCH_CONTENT_ID_SIZE);
+276 -2
View File
@@ -1,5 +1,6 @@
#include "stdafx.h"
#include "Emu/Cell/PPUModule.h"
#include "Emu/IdManager.h"
#include "cellSubDisplay.h"
@@ -27,15 +28,147 @@ void fmt_class_string<CellSubDisplayError>::format(std::string& out, u64 arg)
});
}
enum class sub_display_status : u32
{
uninitialized = 0,
stopped = 1,
started = 2
};
struct sub_display_manager
{
shared_mutex mutex;
sub_display_status status = sub_display_status::uninitialized;
CellSubDisplayParam param{};
vm::ptr<CellSubDisplayHandler> func = vm::null;
vm::ptr<void> userdata = vm::null;
// Video data
vm::ptr<void> video_buffer = vm::null;
u32 buf_size = 0;
// Audio data
bool audio_is_busy = false;
// Touch data
std::array<CellSubDisplayTouchInfo, CELL_SUBDISPLAY_TOUCH_MAX_TOUCH_INFO> touch_info{};
};
error_code check_param(CellSubDisplayParam* param)
{
if (!param ||
param->version < CELL_SUBDISPLAY_VERSION_0001 ||
param->version > CELL_SUBDISPLAY_VERSION_0003 ||
param->mode != CELL_SUBDISPLAY_MODE_REMOTEPLAY ||
param->nGroup != 1 ||
param->nPeer != 1 ||
param->audioParam.ch != 2 ||
param->audioParam.audioMode < CELL_SUBDISPLAY_AUDIO_MODE_SETDATA ||
param->audioParam.audioMode > CELL_SUBDISPLAY_AUDIO_MODE_CAPTURE)
{
return CELL_SUBDISPLAY_ERROR_INVALID_VALUE;
}
switch (param->videoParam.format)
{
case CELL_SUBDISPLAY_VIDEO_FORMAT_A8R8G8B8:
case CELL_SUBDISPLAY_VIDEO_FORMAT_R8G8B8A8:
{
if (param->version == CELL_SUBDISPLAY_VERSION_0003 ||
param->videoParam.width != 480 ||
param->videoParam.height != 272 ||
(param->videoParam.pitch != 1920 && param->videoParam.pitch != 2048) ||
param->videoParam.aspectRatio < CELL_SUBDISPLAY_VIDEO_ASPECT_RATIO_16_9 ||
param->videoParam.aspectRatio > CELL_SUBDISPLAY_VIDEO_ASPECT_RATIO_4_3 ||
param->videoParam.videoMode < CELL_SUBDISPLAY_VIDEO_MODE_SETDATA ||
param->videoParam.videoMode > CELL_SUBDISPLAY_VIDEO_MODE_CAPTURE)
{
return CELL_SUBDISPLAY_ERROR_INVALID_VALUE;
}
break;
}
case CELL_SUBDISPLAY_VIDEO_FORMAT_YUV420:
{
if (param->version != CELL_SUBDISPLAY_VERSION_0003 ||
param->videoParam.width != CELL_SUBDISPLAY_0003_WIDTH ||
param->videoParam.height != CELL_SUBDISPLAY_0003_HEIGHT ||
param->videoParam.pitch != CELL_SUBDISPLAY_0003_PITCH ||
param->videoParam.aspectRatio != CELL_SUBDISPLAY_VIDEO_ASPECT_RATIO_16_9 ||
param->videoParam.videoMode != CELL_SUBDISPLAY_VIDEO_MODE_SETDATA)
{
return CELL_SUBDISPLAY_ERROR_INVALID_VALUE;
}
break;
}
default:
{
return CELL_SUBDISPLAY_ERROR_INVALID_VALUE;
}
}
return CELL_OK;
}
error_code cellSubDisplayInit(vm::ptr<CellSubDisplayParam> pParam, vm::ptr<CellSubDisplayHandler> func, vm::ptr<void> userdata, u32 container)
{
cellSubDisplay.todo("cellSubDisplayInit(pParam=*0x%x, func=*0x%x, userdata=*0x%x, container=0x%x)", pParam, func, userdata, container);
return CELL_SUBDISPLAY_ERROR_ZERO_REGISTERED;
auto& manager = g_fxo->get<sub_display_manager>();
std::lock_guard lock(manager.mutex);
if (manager.func)
{
return CELL_SUBDISPLAY_ERROR_NOT_INITIALIZED;
}
if (error_code error = check_param(pParam.get_ptr()))
{
return error;
}
if (!func)
{
return CELL_SUBDISPLAY_ERROR_INVALID_VALUE;
}
manager.param = *pParam;
manager.func = func;
manager.userdata = userdata;
if (true) // TODO
{
return CELL_SUBDISPLAY_ERROR_ZERO_REGISTERED;
}
return CELL_OK;
}
error_code cellSubDisplayEnd()
{
cellSubDisplay.todo("cellSubDisplayEnd()");
auto& manager = g_fxo->get<sub_display_manager>();
std::lock_guard lock(manager.mutex);
if (!manager.func)
{
return CELL_SUBDISPLAY_ERROR_NOT_INITIALIZED;
}
if (manager.status == sub_display_status::started)
{
// TODO:
// cellSubDisplayStop();
}
manager.param = {};
manager.func = vm::null;
manager.userdata = vm::null;
manager.status = sub_display_status::uninitialized;
return CELL_OK;
}
@@ -43,6 +176,11 @@ error_code cellSubDisplayGetRequiredMemory(vm::ptr<CellSubDisplayParam> pParam)
{
cellSubDisplay.warning("cellSubDisplayGetRequiredMemory(pParam=*0x%x)", pParam);
if (error_code error = check_param(pParam.get_ptr()))
{
return error;
}
switch (pParam->version)
{
case CELL_SUBDISPLAY_VERSION_0001: return not_an_error(CELL_SUBDISPLAY_0001_MEMORY_CONTAINER_SIZE);
@@ -57,18 +195,61 @@ error_code cellSubDisplayGetRequiredMemory(vm::ptr<CellSubDisplayParam> pParam)
error_code cellSubDisplayStart()
{
cellSubDisplay.todo("cellSubDisplayStart()");
auto& manager = g_fxo->get<sub_display_manager>();
std::lock_guard lock(manager.mutex);
if (manager.status == sub_display_status::uninitialized)
{
return CELL_SUBDISPLAY_ERROR_NOT_INITIALIZED;
}
manager.status = sub_display_status::started;
// TODO
return CELL_OK;
}
error_code cellSubDisplayStop()
{
cellSubDisplay.todo("cellSubDisplayStop()");
auto& manager = g_fxo->get<sub_display_manager>();
std::lock_guard lock(manager.mutex);
if (manager.status == sub_display_status::uninitialized)
{
return CELL_SUBDISPLAY_ERROR_NOT_INITIALIZED;
}
manager.status = sub_display_status::stopped;
// TODO
return CELL_OK;
}
error_code cellSubDisplayGetVideoBuffer(s32 groupId, vm::pptr<void> ppVideoBuf, vm::ptr<u32> pSize)
{
cellSubDisplay.todo("cellSubDisplayGetVideoBuffer(groupId=%d, ppVideoBuf=**0x%x, pSize=*0x%x)", groupId, ppVideoBuf, pSize);
auto& manager = g_fxo->get<sub_display_manager>();
std::lock_guard lock(manager.mutex);
if (manager.status == sub_display_status::uninitialized)
{
return CELL_SUBDISPLAY_ERROR_NOT_INITIALIZED;
}
if (groupId != 0 || !ppVideoBuf || !pSize)
{
return CELL_SUBDISPLAY_ERROR_INVALID_VALUE;
}
*pSize = manager.buf_size;
*ppVideoBuf = manager.video_buffer;
return CELL_OK;
}
@@ -76,11 +257,26 @@ error_code cellSubDisplayAudioOutBlocking(s32 groupId, vm::ptr<void> pvData, s32
{
cellSubDisplay.todo("cellSubDisplayAudioOutBlocking(groupId=%d, pvData=*0x%x, samples=%d)", groupId, pvData, samples);
auto& manager = g_fxo->get<sub_display_manager>();
std::lock_guard lock(manager.mutex);
if (manager.status == sub_display_status::uninitialized)
{
return CELL_SUBDISPLAY_ERROR_NOT_INITIALIZED;
}
if (groupId != 0 || samples < 0)
{
return CELL_SUBDISPLAY_ERROR_INVALID_VALUE;
}
if (samples % 1024)
{
return CELL_SUBDISPLAY_ERROR_SET_SAMPLE;
}
// TODO
return CELL_OK;
}
@@ -88,32 +284,110 @@ error_code cellSubDisplayAudioOutNonBlocking(s32 groupId, vm::ptr<void> pvData,
{
cellSubDisplay.todo("cellSubDisplayAudioOutNonBlocking(groupId=%d, pvData=*0x%x, samples=%d)", groupId, pvData, samples);
auto& manager = g_fxo->get<sub_display_manager>();
std::lock_guard lock(manager.mutex);
if (manager.status == sub_display_status::uninitialized)
{
return CELL_SUBDISPLAY_ERROR_NOT_INITIALIZED;
}
if (groupId != 0 || samples < 0)
{
return CELL_SUBDISPLAY_ERROR_INVALID_VALUE;
}
if (samples % 1024)
{
return CELL_SUBDISPLAY_ERROR_SET_SAMPLE;
}
if (manager.audio_is_busy)
{
return CELL_SUBDISPLAY_ERROR_AUDIOOUT_IS_BUSY;
}
// TODO: fetch audio async
// manager.audio_is_busy = true;
return CELL_OK;
}
error_code cellSubDisplayGetPeerNum(s32 groupId)
{
cellSubDisplay.todo("cellSubDisplayGetPeerNum(groupId=%d)", groupId);
return CELL_OK;
auto& manager = g_fxo->get<sub_display_manager>();
std::lock_guard lock(manager.mutex);
if (manager.status == sub_display_status::uninitialized)
{
return CELL_SUBDISPLAY_ERROR_NOT_INITIALIZED;
}
if (groupId != 0)
{
return CELL_SUBDISPLAY_ERROR_INVALID_VALUE;
}
s32 peer_num = 0; // TODO
return not_an_error(peer_num);
}
error_code cellSubDisplayGetPeerList(s32 groupId, vm::ptr<CellSubDisplayPeerInfo> pInfo, vm::ptr<s32> pNum)
{
cellSubDisplay.todo("cellSubDisplayGetPeerList(groupId=%d, pInfo=*0x%x, pNum=*0x%x)", groupId, pInfo, pNum);
auto& manager = g_fxo->get<sub_display_manager>();
std::lock_guard lock(manager.mutex);
if (manager.status == sub_display_status::uninitialized)
{
return CELL_SUBDISPLAY_ERROR_NOT_INITIALIZED;
}
if (groupId != 0)
{
return CELL_OK;
}
if (!pInfo || !pNum || *pNum < 1)
{
return CELL_SUBDISPLAY_ERROR_INVALID_VALUE;
}
*pNum = 0;
// TODO
return CELL_OK;
}
error_code cellSubDisplayGetTouchInfo(s32 groupId, vm::ptr<CellSubDisplayTouchInfo> pTouchInfo, vm::ptr<s32> pNumTouchInfo)
{
cellSubDisplay.todo("cellSubDisplayGetTouchInfo(groupId=%d, pTouchInfo=*0x%x, pNumTouchInfo=*0x%x)", groupId, pTouchInfo, pNumTouchInfo);
if (groupId != 0 || !pNumTouchInfo || !pTouchInfo)
{
return CELL_SUBDISPLAY_ERROR_INVALID_VALUE;
}
auto& manager = g_fxo->get<sub_display_manager>();
std::lock_guard lock(manager.mutex);
if (manager.param.version != CELL_SUBDISPLAY_VERSION_0003)
{
return CELL_SUBDISPLAY_ERROR_NOT_SUPPORTED;
}
if (*pNumTouchInfo > CELL_SUBDISPLAY_TOUCH_MAX_TOUCH_INFO)
{
*pNumTouchInfo = CELL_SUBDISPLAY_TOUCH_MAX_TOUCH_INFO;
}
std::memcpy(pTouchInfo.get_ptr(), manager.touch_info.data(), *pNumTouchInfo * sizeof(CellSubDisplayTouchInfo));
return CELL_OK;
}
+9
View File
@@ -20,25 +20,34 @@ enum
CELL_SUBDISPLAY_STATUS_JOIN = 1,
CELL_SUBDISPLAY_STATUS_LEAVE = 2,
CELL_SUBDISPLAY_STATUS_FATALERROR = 3,
CELL_SUBDISPLAY_VERSION_0001 = 1,
CELL_SUBDISPLAY_VERSION_0002 = 2,
CELL_SUBDISPLAY_VERSION_0003 = 3,
CELL_SUBDISPLAY_MODE_REMOTEPLAY = 1,
CELL_SUBDISPLAY_VIDEO_FORMAT_A8R8G8B8 = 1,
CELL_SUBDISPLAY_VIDEO_FORMAT_R8G8B8A8 = 2,
CELL_SUBDISPLAY_VIDEO_FORMAT_YUV420 = 3,
CELL_SUBDISPLAY_VIDEO_ASPECT_RATIO_16_9 = 0,
CELL_SUBDISPLAY_VIDEO_ASPECT_RATIO_4_3 = 1,
CELL_SUBDISPLAY_VIDEO_MODE_SETDATA = 0,
CELL_SUBDISPLAY_VIDEO_MODE_CAPTURE = 1,
CELL_SUBDISPLAY_AUDIO_MODE_SETDATA = 0,
CELL_SUBDISPLAY_AUDIO_MODE_CAPTURE = 1,
CELL_SUBDISPLAY_0001_MEMORY_CONTAINER_SIZE = 8 * 1024 * 1024,
CELL_SUBDISPLAY_0002_MEMORY_CONTAINER_SIZE = 10 * 1024 * 1024,
CELL_SUBDISPLAY_0003_MEMORY_CONTAINER_SIZE = 10 * 1024 * 1024,
CELL_SUBDISPLAY_0003_WIDTH = 864,
CELL_SUBDISPLAY_0003_PITCH = 864,
CELL_SUBDISPLAY_0003_HEIGHT = 480,
CELL_SUBDISPLAY_NICKNAME_LEN = 256,
CELL_SUBDISPLAY_PSPID_LEN = 16,
};
+1 -1
View File
@@ -315,7 +315,7 @@ error_code cellSysutilAvc2EstimateMemoryContainerSize(vm::cptr<CellSysutilAvc2In
val += static_cast<s32>(static_cast<f64>(window_count) * 1258291.2) + 0x1ed846;
}
estimated_size = (estimated_size + ((static_cast<int>(val) >> 7) + static_cast<u32>(static_cast<int>(val) < 0 && (val & 0x7f) != 0)) * 0x80 + 0x80080 & 0xfff00000) + 0x100000;
estimated_size = ((estimated_size + ((static_cast<int>(val) >> 7) + static_cast<u32>(static_cast<int>(val) < 0 && (val & 0x7f) != 0)) * 0x80 + 0x80080) & 0xfff00000) + 0x100000;
*size = estimated_size;
}
+26 -13
View File
@@ -563,9 +563,10 @@ struct vdec_context final
break;
}
}
thread_ctrl::wait_for(1000);
if (elapsed++ >= 5000) // 5 seconds
thread_ctrl::wait_for(10000);
if (elapsed++ >= 500) // 5 seconds
{
cellVdec.error("Video au decode has been waiting for a consumer for 5 seconds. (handle=0x%x, seq_id=%d, cmd_id=%d, queue_size=%d)", handle, cmd->seq_id, cmd->id, out_queue.size());
elapsed = 0;
@@ -635,14 +636,12 @@ struct vdec_creation_lock
vdec_creation_lock()
{
locked.init();
auto lk = locked.init();
}
};
extern bool try_lock_vdec_context_creation()
{
bool exist = false;
auto& lock = g_fxo->get<vdec_creation_lock>();
auto reset = lock.locked.reset();
@@ -997,8 +996,10 @@ error_code cellVdecClose(ppu_thread& ppu, u32 handle)
return CELL_OK;
}
error_code cellVdecStartSeq(u32 handle)
error_code cellVdecStartSeq(ppu_thread& ppu, u32 handle)
{
ppu.state += cpu_flag::wait;
cellVdec.warning("cellVdecStartSeq(handle=0x%x)", handle);
const auto vdec = idm::get<vdec_context>(handle);
@@ -1047,8 +1048,10 @@ error_code cellVdecStartSeq(u32 handle)
return CELL_OK;
}
error_code cellVdecEndSeq(u32 handle)
error_code cellVdecEndSeq(ppu_thread& ppu, u32 handle)
{
ppu.state += cpu_flag::wait;
cellVdec.warning("cellVdecEndSeq(handle=0x%x)", handle);
const auto vdec = idm::get<vdec_context>(handle);
@@ -1078,8 +1081,10 @@ error_code cellVdecEndSeq(u32 handle)
return CELL_OK;
}
error_code cellVdecDecodeAu(u32 handle, CellVdecDecodeMode mode, vm::cptr<CellVdecAuInfo> auInfo)
error_code cellVdecDecodeAu(ppu_thread& ppu, u32 handle, CellVdecDecodeMode mode, vm::cptr<CellVdecAuInfo> auInfo)
{
ppu.state += cpu_flag::wait;
cellVdec.trace("cellVdecDecodeAu(handle=0x%x, mode=%d, auInfo=*0x%x)", handle, +mode, auInfo);
const auto vdec = idm::get<vdec_context>(handle);
@@ -1124,8 +1129,10 @@ error_code cellVdecDecodeAu(u32 handle, CellVdecDecodeMode mode, vm::cptr<CellVd
return CELL_OK;
}
error_code cellVdecDecodeAuEx2(u32 handle, CellVdecDecodeMode mode, vm::cptr<CellVdecAuInfoEx2> auInfo)
error_code cellVdecDecodeAuEx2(ppu_thread& ppu, u32 handle, CellVdecDecodeMode mode, vm::cptr<CellVdecAuInfoEx2> auInfo)
{
ppu.state += cpu_flag::wait;
cellVdec.todo("cellVdecDecodeAuEx2(handle=0x%x, mode=%d, auInfo=*0x%x)", handle, +mode, auInfo);
const auto vdec = idm::get<vdec_context>(handle);
@@ -1178,8 +1185,10 @@ error_code cellVdecDecodeAuEx2(u32 handle, CellVdecDecodeMode mode, vm::cptr<Cel
return CELL_OK;
}
error_code cellVdecGetPictureExt(u32 handle, vm::cptr<CellVdecPicFormat2> format, vm::ptr<u8> outBuff, u32 arg4)
error_code cellVdecGetPictureExt(ppu_thread& ppu, u32 handle, vm::cptr<CellVdecPicFormat2> format, vm::ptr<u8> outBuff, u32 arg4)
{
ppu.state += cpu_flag::wait;
cellVdec.trace("cellVdecGetPictureExt(handle=0x%x, format=*0x%x, outBuff=*0x%x, arg4=*0x%x)", handle, format, outBuff, arg4);
const auto vdec = idm::get<vdec_context>(handle);
@@ -1323,8 +1332,10 @@ error_code cellVdecGetPictureExt(u32 handle, vm::cptr<CellVdecPicFormat2> format
return CELL_OK;
}
error_code cellVdecGetPicture(u32 handle, vm::cptr<CellVdecPicFormat> format, vm::ptr<u8> outBuff)
error_code cellVdecGetPicture(ppu_thread& ppu, u32 handle, vm::cptr<CellVdecPicFormat> format, vm::ptr<u8> outBuff)
{
ppu.state += cpu_flag::wait;
cellVdec.trace("cellVdecGetPicture(handle=0x%x, format=*0x%x, outBuff=*0x%x)", handle, format, outBuff);
if (!format)
@@ -1339,11 +1350,13 @@ error_code cellVdecGetPicture(u32 handle, vm::cptr<CellVdecPicFormat> format, vm
format2->unk0 = 0;
format2->unk1 = 0;
return cellVdecGetPictureExt(handle, format2, outBuff, 0);
return cellVdecGetPictureExt(ppu, handle, format2, outBuff, 0);
}
error_code cellVdecGetPicItem(u32 handle, vm::pptr<CellVdecPicItem> picItem)
error_code cellVdecGetPicItem(ppu_thread& ppu, u32 handle, vm::pptr<CellVdecPicItem> picItem)
{
ppu.state += cpu_flag::wait;
cellVdec.trace("cellVdecGetPicItem(handle=0x%x, picItem=**0x%x)", handle, picItem);
const auto vdec = idm::get<vdec_context>(handle);
+9 -9
View File
@@ -123,10 +123,10 @@ error_code cellVideoOutGetState(u32 videoOut, u32 deviceIndex, vm::ptr<CellVideo
const auto& conf = g_fxo->get<rsx::avconf>();
state->state = CELL_VIDEO_OUT_OUTPUT_STATE_ENABLED;
state->colorSpace = CELL_VIDEO_OUT_COLOR_SPACE_RGB;
state->displayMode.resolutionId = conf.state ? conf.resolution_id : g_video_out_resolution_id.at(g_cfg.video.resolution);
state->displayMode.resolutionId = conf.state ? conf.resolution_id : ::at32(g_video_out_resolution_id, g_cfg.video.resolution);
state->displayMode.scanMode = CELL_VIDEO_OUT_SCAN_MODE_PROGRESSIVE;
state->displayMode.conversion = CELL_VIDEO_OUT_DISPLAY_CONVERSION_NONE;
state->displayMode.aspect = conf.state ? conf.aspect : g_video_out_aspect_id.at(g_cfg.video.aspect_ratio);
state->displayMode.aspect = conf.state ? conf.aspect : ::at32(g_video_out_aspect_id, g_cfg.video.aspect_ratio);
state->displayMode.refreshRates = CELL_VIDEO_OUT_REFRESH_RATE_59_94HZ;
return CELL_OK;
@@ -207,7 +207,7 @@ error_code cellVideoOutConfigure(u32 videoOut, vm::ptr<CellVideoOutConfiguration
}
// Resolve 'auto' or unknown options to actual aspect ratio
conf.aspect = g_video_out_aspect_id.at(g_cfg.video.aspect_ratio);
conf.aspect = ::at32(g_video_out_aspect_id, g_cfg.video.aspect_ratio);
}
cellSysutil.notice("Selected video configuration: resolutionId=0x%x, aspect=0x%x=>0x%x, format=0x%x", config->resolutionId, config->aspect, conf.aspect, config->format);
@@ -242,9 +242,9 @@ error_code cellVideoOutGetConfiguration(u32 videoOut, vm::ptr<CellVideoOutConfig
}
else
{
config->resolutionId = g_video_out_resolution_id.at(g_cfg.video.resolution);
config->resolutionId = ::at32(g_video_out_resolution_id, g_cfg.video.resolution);
config->format = CELL_VIDEO_OUT_BUFFER_COLOR_FORMAT_X8R8G8B8;
config->aspect = g_video_out_aspect_id.at(g_cfg.video.aspect_ratio);
config->aspect = ::at32(g_video_out_aspect_id, g_cfg.video.aspect_ratio);
CellVideoOutResolution res;
ensure(_IntGetResolutionInfo(config->resolutionId, &res) == CELL_OK); // "Invalid video configuration"
@@ -295,10 +295,10 @@ error_code cellVideoOutGetDeviceInfo(u32 videoOut, u32 deviceIndex, vm::ptr<Cell
info->colorInfo.whiteX = 0xFFFF;
info->colorInfo.whiteY = 0xFFFF;
info->colorInfo.gamma = 100;
info->availableModes[0].aspect = g_video_out_aspect_id.at(g_cfg.video.aspect_ratio);
info->availableModes[0].aspect = ::at32(g_video_out_aspect_id, g_cfg.video.aspect_ratio);
info->availableModes[0].conversion = CELL_VIDEO_OUT_DISPLAY_CONVERSION_NONE;
info->availableModes[0].refreshRates = CELL_VIDEO_OUT_REFRESH_RATE_60HZ | CELL_VIDEO_OUT_REFRESH_RATE_59_94HZ;
info->availableModes[0].resolutionId = g_video_out_resolution_id.at(g_cfg.video.resolution);
info->availableModes[0].resolutionId = ::at32(g_video_out_resolution_id, g_cfg.video.resolution);
info->availableModes[0].scanMode = CELL_VIDEO_OUT_SCAN_MODE_PROGRESSIVE;
if (g_cfg.video.enable_3d && g_cfg.video.resolution == video_resolution::_720)
@@ -335,12 +335,12 @@ error_code cellVideoOutGetResolutionAvailability(u32 videoOut, u32 resolutionId,
case CELL_VIDEO_OUT_PRIMARY:
{
// NOTE: Result is boolean
if (aspect != CELL_VIDEO_OUT_ASPECT_AUTO && aspect != static_cast<u32>(g_video_out_aspect_id.at(g_cfg.video.aspect_ratio)))
if (aspect != CELL_VIDEO_OUT_ASPECT_AUTO && aspect != static_cast<u32>(::at32(g_video_out_aspect_id, g_cfg.video.aspect_ratio)))
{
return not_an_error(0);
}
if (resolutionId == static_cast<u32>(g_video_out_resolution_id.at(g_cfg.video.resolution)))
if (resolutionId == static_cast<u32>(::at32(g_video_out_resolution_id, g_cfg.video.resolution)))
{
// Perfect match
return not_an_error(1);
File diff suppressed because it is too large Load Diff
+3 -3
View File
@@ -1157,9 +1157,9 @@ struct SceNpScoreRankData
be_t<u32> serialRank;
be_t<u32> rank;
be_t<u32> highestRank;
be_t<s64> scoreValue;
be_t<s32> hasGameData;
u8 pad0[4];
be_t<s64> scoreValue;
CellRtcTick recordDate;
};
@@ -1393,14 +1393,14 @@ struct SceNpMatchingReqRange
struct SceNpScoreVariableSizeGameInfo
{
be_t<u64> infoSize;
be_t<u32> infoSize;
u8 data[SCE_NP_SCORE_VARIABLE_SIZE_GAMEINFO_MAXSIZE];
u8 pad[3];
};
struct SceNpScoreRecordOptParam
{
be_t<u64> size;
be_t<u32> size;
vm::bptr<SceNpScoreVariableSizeGameInfo> vsInfo;
vm::bptr<CellRtcTick> reserved;
};
+26 -13
View File
@@ -237,7 +237,7 @@ error_code sceNpMatching2Init(u32 stackSize, s32 priority)
error_code sceNpMatching2Init2(u64 stackSize, s32 priority, vm::ptr<SceNpMatching2UtilityInitParam> param)
{
sceNp2.todo("sceNpMatching2Init2(stackSize=0x%x, priority=%d, param=*0x%x)", stackSize, priority, param);
sceNp2.warning("sceNpMatching2Init2(stackSize=0x%x, priority=%d, param=*0x%x)", stackSize, priority, param);
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
@@ -319,7 +319,7 @@ error_code sceNpMatching2Term2()
error_code sceNpMatching2DestroyContext(SceNpMatching2ContextId ctxId)
{
sceNp2.todo("sceNpMatching2DestroyContext(ctxId=%d)", ctxId);
sceNp2.warning("sceNpMatching2DestroyContext(ctxId=%d)", ctxId);
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
@@ -611,11 +611,20 @@ error_code sceNpMatching2SignalingGetConnectionInfo(
return SCE_NP_MATCHING2_ERROR_NOT_INITIALIZED;
}
if (!connInfo)
{
return SCE_NP_MATCHING2_ERROR_INVALID_ARGUMENT;
}
auto& sigh = g_fxo->get<named_thread<signaling_handler>>();
const auto si = sigh.get_sig2_infos(roomId, memberId);
switch (code)
{
case SCE_NP_SIGNALING_CONN_INFO_RTT:
{
connInfo->rtt = 20000; // HACK
connInfo->rtt = si.rtt;
sceNp2.warning("Returning a RTT of %d microseconds", connInfo->rtt);
break;
}
case SCE_NP_SIGNALING_CONN_INFO_BANDWIDTH:
@@ -625,22 +634,17 @@ error_code sceNpMatching2SignalingGetConnectionInfo(
}
case SCE_NP_SIGNALING_CONN_INFO_PEER_NPID:
{
// TODO: need an update to whole signaling as matching2 signaling ignores npids atm
sceNp2.fatal("sceNpMatching2SignalingGetConnectionInfo Unimplemented SCE_NP_SIGNALING_CONN_INFO_PEER_NPID");
connInfo->npId = si.npid;
break;
}
case SCE_NP_SIGNALING_CONN_INFO_PEER_ADDRESS:
{
auto& sigh = g_fxo->get<named_thread<signaling_handler>>();
const auto si = sigh.get_sig2_infos(roomId, memberId);
connInfo->address.port = std::bit_cast<u16, be_t<u16>>(si.port);
connInfo->address.addr.np_s_addr = si.addr;
break;
}
case SCE_NP_SIGNALING_CONN_INFO_MAPPED_ADDRESS:
{
auto& sigh = g_fxo->get<named_thread<signaling_handler>>();
const auto si = sigh.get_sig2_infos(roomId, memberId);
connInfo->address.port = std::bit_cast<u16, be_t<u16>>(si.mapped_port);
connInfo->address.addr.np_s_addr = si.mapped_addr;
break;
@@ -652,8 +656,7 @@ error_code sceNpMatching2SignalingGetConnectionInfo(
}
default:
{
sceNp2.fatal("sceNpMatching2SignalingGetConnectionInfo Unimplemented code: %d", code);
return CELL_OK;
return SCE_NP_MATCHING2_ERROR_INVALID_ARGUMENT;
}
}
@@ -715,6 +718,16 @@ error_code sceNpMatching2AbortRequest(SceNpMatching2ContextId ctxId, SceNpMatchi
return SCE_NP_MATCHING2_ERROR_NOT_INITIALIZED;
}
if (!ctxId)
{
return SCE_NP_MATCHING2_ERROR_INVALID_CONTEXT_ID;
}
if (!check_match2_context(ctxId))
{
return SCE_NP_MATCHING2_ERROR_CONTEXT_NOT_FOUND;
}
return CELL_OK;
}
@@ -1349,7 +1362,7 @@ error_code sceNpMatching2SetDefaultRequestOptParam(SceNpMatching2ContextId ctxId
error_code sceNpMatching2RegisterRoomEventCallback(SceNpMatching2ContextId ctxId, vm::ptr<SceNpMatching2RoomEventCallback> cbFunc, vm::ptr<void> cbFuncArg)
{
sceNp2.todo("sceNpMatching2RegisterRoomEventCallback(ctxId=%d, cbFunc=*0x%x, cbFuncArg=*0x%x)", ctxId, cbFunc, cbFuncArg);
sceNp2.warning("sceNpMatching2RegisterRoomEventCallback(ctxId=%d, cbFunc=*0x%x, cbFuncArg=*0x%x)", ctxId, cbFunc, cbFuncArg);
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
@@ -1546,7 +1559,7 @@ error_code sceNpMatching2SetLobbyMemberDataInternal(
error_code sceNpMatching2RegisterRoomMessageCallback(SceNpMatching2ContextId ctxId, vm::ptr<SceNpMatching2RoomMessageCallback> cbFunc, vm::ptr<void> cbFuncArg)
{
sceNp2.todo("sceNpMatching2RegisterRoomMessageCallback(ctxId=%d, cbFunc=*0x%x, cbFuncArg=*0x%x)", ctxId, cbFunc, cbFuncArg);
sceNp2.warning("sceNpMatching2RegisterRoomMessageCallback(ctxId=%d, cbFunc=*0x%x, cbFuncArg=*0x%x)", ctxId, cbFunc, cbFuncArg);
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
+4 -3
View File
@@ -458,7 +458,7 @@ error_code sceNpTrophyCreateContext(vm::ptr<u32> context, vm::cptr<SceNpCommunic
name_sv = name_sv.substr(0, pos);
}
sceNpTrophy.warning("sceNpTrophyCreateContext(): data='%s' term='%c' (0x%x) num=%d", name_sv, commId->data[9], commId->data[9], commId->num);
sceNpTrophy.warning("sceNpTrophyCreateContext(): data='%s' term=0x%x (0x%x) num=%d", name_sv, commId->data[9], commId->data[9], commId->num);
// append the commId number as "_xx"
std::string name = fmt::format("%s_%02d", name_sv, commId->num);
@@ -604,7 +604,7 @@ error_code sceNpTrophyRegisterContext(ppu_thread& ppu, u32 context, u32 handle,
if (!stream && Emu.GetCat() == "GD")
{
sceNpTrophy.warning("sceNpTrophyRegisterContext failed to open trophy file from boot path: '%s'", trp_path);
sceNpTrophy.warning("sceNpTrophyRegisterContext failed to open trophy file from boot path: '%s' (%s)", trp_path, fs::g_tls_error);
trp_path = vfs::get("/dev_bdvd/PS3_GAME/TROPDIR/" + ctxt->trp_name + "/TROPHY.TRP");
stream.open(trp_path);
}
@@ -612,7 +612,8 @@ error_code sceNpTrophyRegisterContext(ppu_thread& ppu, u32 context, u32 handle,
// check if exists and opened
if (!stream)
{
return {SCE_NP_TROPHY_ERROR_CONF_DOES_NOT_EXIST, trp_path};
const std::string msg = fmt::format("Failed to open trophy file: '%s' (%s)", trp_path, fs::g_tls_error);
return {SCE_NP_TROPHY_ERROR_CONF_DOES_NOT_EXIST, msg};
}
TRPLoader trp(stream);
+13 -13
View File
@@ -58,7 +58,7 @@ sce_np_tus_title_context* sce_np_tus_manager::get_title_context(s32 titleCtxId)
{
if (title_contexts.find(titleCtxId) != title_contexts.end())
{
return &title_contexts.at(titleCtxId);
return &::at32(title_contexts, titleCtxId);
}
return nullptr;
@@ -81,7 +81,7 @@ s32 sce_np_tus_manager::add_transaction_context(s32 titleCtxId)
sce_np_tus_transaction_context new_transaction;
new_transaction.id = next_transaction_context_id;
if (title_contexts.at(titleCtxId).transaction_contexts.emplace(next_transaction_context_id, new_transaction).second)
if (::at32(title_contexts, titleCtxId).transaction_contexts.emplace(next_transaction_context_id, new_transaction).second)
{
return next_transaction_context_id++;
}
@@ -122,7 +122,7 @@ sce_np_tus_transaction_context* sce_np_tus_manager::get_transaction_context(s32
if (transactions.find(transId) != transactions.end())
{
return &transactions.at(transId);
return &::at32(transactions, transId);
}
}
@@ -1224,7 +1224,7 @@ error_code sceNpTusDeleteMultiSlotVariableVUserAsync(s32 transId, vm::cptr<SceNp
return CELL_OK;
}
error_code sceNpTusSetData(s32 transId, vm::cptr<SceNpId> targetNpId, SceNpTusSlotId slotId, u64 totalSize, u64 sendSize, vm::cptr<void> data, vm::cptr<SceNpTusDataInfo> info, u64 infoStructSize, vm::ptr<SceNpTusSetDataOptParam> option)
error_code sceNpTusSetData(s32 transId, vm::cptr<SceNpId> targetNpId, SceNpTusSlotId slotId, u32 totalSize, u32 sendSize, vm::cptr<void> data, vm::cptr<SceNpTusDataInfo> info, u64 infoStructSize, vm::ptr<SceNpTusSetDataOptParam> option)
{
sceNpTus.todo("sceNpTusSetData(transId=%d, targetNpId=*0x%x, slotId=%d, totalSize=%d, sendSize=%d, data=*0x%x, info=*0x%x, infoStructSize=%d, option=*0x%x)", transId, targetNpId, slotId, totalSize, sendSize, data, info, infoStructSize, option);
@@ -1255,7 +1255,7 @@ error_code sceNpTusSetData(s32 transId, vm::cptr<SceNpId> targetNpId, SceNpTusSl
return not_an_error(data_size);
}
error_code sceNpTusSetDataVUser(s32 transId, vm::cptr<SceNpTusVirtualUserId> targetVirtualUserId, SceNpTusSlotId slotId, u64 totalSize, u64 sendSize, vm::cptr<void> data, vm::cptr<SceNpTusDataInfo> info, u64 infoStructSize, vm::ptr<SceNpTusSetDataOptParam> option)
error_code sceNpTusSetDataVUser(s32 transId, vm::cptr<SceNpTusVirtualUserId> targetVirtualUserId, SceNpTusSlotId slotId, u32 totalSize, u32 sendSize, vm::cptr<void> data, vm::cptr<SceNpTusDataInfo> info, u64 infoStructSize, vm::ptr<SceNpTusSetDataOptParam> option)
{
sceNpTus.todo("sceNpTusSetDataAsync(transId=%d, targetVirtualUserId=*0x%x, slotId=%d, totalSize=%d, sendSize=%d, data=*0x%x, info=*0x%x, infoStructSize=%d, option=*0x%x)", transId, targetVirtualUserId, slotId, totalSize, sendSize, data, info, infoStructSize, option);
@@ -1286,7 +1286,7 @@ error_code sceNpTusSetDataVUser(s32 transId, vm::cptr<SceNpTusVirtualUserId> tar
return not_an_error(data_size);
}
error_code sceNpTusSetDataAsync(s32 transId, vm::cptr<SceNpId> targetNpId, SceNpTusSlotId slotId, u64 totalSize, u64 sendSize, vm::cptr<void> data, vm::cptr<SceNpTusDataInfo> info, u64 infoStructSize, vm::ptr<SceNpTusSetDataOptParam> option)
error_code sceNpTusSetDataAsync(s32 transId, vm::cptr<SceNpId> targetNpId, SceNpTusSlotId slotId, u32 totalSize, u32 sendSize, vm::cptr<void> data, vm::cptr<SceNpTusDataInfo> info, u64 infoStructSize, vm::ptr<SceNpTusSetDataOptParam> option)
{
sceNpTus.todo("sceNpTusSetDataAsync(transId=%d, targetNpId=*0x%x, slotId=%d, totalSize=%d, sendSize=%d, data=*0x%x, info=*0x%x, infoStructSize=%d, option=*0x%x)", transId, targetNpId, slotId, totalSize, sendSize, data, info, infoStructSize, option);
@@ -1316,7 +1316,7 @@ error_code sceNpTusSetDataAsync(s32 transId, vm::cptr<SceNpId> targetNpId, SceNp
return CELL_OK;
}
error_code sceNpTusSetDataVUserAsync(s32 transId, vm::cptr<SceNpTusVirtualUserId> targetVirtualUserId, SceNpTusSlotId slotId, u64 totalSize, u64 sendSize, vm::cptr<void> data, vm::cptr<SceNpTusDataInfo> info, u64 infoStructSize, vm::ptr<SceNpTusSetDataOptParam> option)
error_code sceNpTusSetDataVUserAsync(s32 transId, vm::cptr<SceNpTusVirtualUserId> targetVirtualUserId, SceNpTusSlotId slotId, u32 totalSize, u32 sendSize, vm::cptr<void> data, vm::cptr<SceNpTusDataInfo> info, u64 infoStructSize, vm::ptr<SceNpTusSetDataOptParam> option)
{
sceNpTus.todo("sceNpTusSetDataAsync(transId=%d, targetVirtualUserId=*0x%x, slotId=%d, totalSize=%d, sendSize=%d, data=*0x%x, info=*0x%x, infoStructSize=%d, option=*0x%x)", transId, targetVirtualUserId, slotId, totalSize, sendSize, data, info, infoStructSize, option);
@@ -1346,7 +1346,7 @@ error_code sceNpTusSetDataVUserAsync(s32 transId, vm::cptr<SceNpTusVirtualUserId
return CELL_OK;
}
error_code sceNpTusGetData(s32 transId, vm::cptr<SceNpId> targetNpId, SceNpTusSlotId slotId, vm::ptr<SceNpTusDataStatus> dataStatus, u64 dataStatusSize, vm::ptr<void> data, u64 recvSize, vm::ptr<void> option)
error_code sceNpTusGetData(s32 transId, vm::cptr<SceNpId> targetNpId, SceNpTusSlotId slotId, vm::ptr<SceNpTusDataStatus> dataStatus, u32 dataStatusSize, vm::ptr<void> data, u32 recvSize, vm::ptr<void> option)
{
sceNpTus.todo("sceNpTusGetData(transId=%d, targetNpId=*0x%x, slotId=%d, dataStatus=*0x%x, dataStatusSize=%d, data=*0x%x, recvSize=%d, option=*0x%x)", transId, targetNpId, slotId, dataStatus, dataStatusSize, data, recvSize, option);
@@ -1377,7 +1377,7 @@ error_code sceNpTusGetData(s32 transId, vm::cptr<SceNpId> targetNpId, SceNpTusSl
return not_an_error(data_size);
}
error_code sceNpTusGetDataVUser(s32 transId, vm::cptr<SceNpTusVirtualUserId> targetVirtualUserId, SceNpTusSlotId slotId, vm::ptr<SceNpTusDataStatus> dataStatus, u64 dataStatusSize, vm::ptr<void> data, u64 recvSize, vm::ptr<void> option)
error_code sceNpTusGetDataVUser(s32 transId, vm::cptr<SceNpTusVirtualUserId> targetVirtualUserId, SceNpTusSlotId slotId, vm::ptr<SceNpTusDataStatus> dataStatus, u32 dataStatusSize, vm::ptr<void> data, u32 recvSize, vm::ptr<void> option)
{
sceNpTus.todo("sceNpTusGetDataVUser(transId=%d, targetVirtualUserId=*0x%x, slotId=%d, dataStatus=*0x%x, dataStatusSize=%d, data=*0x%x, recvSize=%d, option=*0x%x)", transId, targetVirtualUserId, slotId, dataStatus, dataStatusSize, data, recvSize, option);
@@ -1408,7 +1408,7 @@ error_code sceNpTusGetDataVUser(s32 transId, vm::cptr<SceNpTusVirtualUserId> tar
return not_an_error(data_size);
}
error_code sceNpTusGetDataAsync(s32 transId, vm::cptr<SceNpId> targetNpId, SceNpTusSlotId slotId, vm::ptr<SceNpTusDataStatus> dataStatus, u64 dataStatusSize, vm::ptr<void> data, u64 recvSize, vm::ptr<void> option)
error_code sceNpTusGetDataAsync(s32 transId, vm::cptr<SceNpId> targetNpId, SceNpTusSlotId slotId, vm::ptr<SceNpTusDataStatus> dataStatus, u32 dataStatusSize, vm::ptr<void> data, u32 recvSize, vm::ptr<void> option)
{
sceNpTus.todo("sceNpTusGetDataAsync(transId=%d, targetNpId=*0x%x, slotId=%d, dataStatus=*0x%x, dataStatusSize=%d, data=*0x%x, recvSize=%d, option=*0x%x)", transId, targetNpId, slotId, dataStatus, dataStatusSize, data, recvSize, option);
@@ -1443,7 +1443,7 @@ error_code sceNpTusGetDataAsync(s32 transId, vm::cptr<SceNpId> targetNpId, SceNp
return CELL_OK;
}
error_code sceNpTusGetDataVUserAsync(s32 transId, vm::cptr<SceNpTusVirtualUserId> targetVirtualUserId, SceNpTusSlotId slotId, vm::ptr<SceNpTusDataStatus> dataStatus, u64 dataStatusSize, vm::ptr<void> data, u64 recvSize, vm::ptr<void> option)
error_code sceNpTusGetDataVUserAsync(s32 transId, vm::cptr<SceNpTusVirtualUserId> targetVirtualUserId, SceNpTusSlotId slotId, vm::ptr<SceNpTusDataStatus> dataStatus, u32 dataStatusSize, vm::ptr<void> data, u32 recvSize, vm::ptr<void> option)
{
sceNpTus.todo("sceNpTusGetDataVUser(transId=%d, targetVirtualUserId=*0x%x, slotId=%d, dataStatus=*0x%x, dataStatusSize=%d, data=*0x%x, recvSize=%d, option=*0x%x)", transId, targetVirtualUserId, slotId, dataStatus, dataStatusSize, data, recvSize, option);
@@ -1968,7 +1968,7 @@ error_code sceNpTusDeleteMultiSlotDataVUserAsync(s32 transId, vm::cptr<SceNpTusV
return CELL_OK;
}
error_code sceNpTssGetData(s32 transId, SceNpTssSlotId slotId, vm::ptr<SceNpTssDataStatus> dataStatus, u64 dataStatusSize, vm::ptr<void> data, u64 recvSize, vm::ptr<SceNpTssGetDataOptParam> option)
error_code sceNpTssGetData(s32 transId, SceNpTssSlotId slotId, vm::ptr<SceNpTssDataStatus> dataStatus, u32 dataStatusSize, vm::ptr<void> data, u32 recvSize, vm::ptr<SceNpTssGetDataOptParam> option)
{
sceNpTus.todo("sceNpTssGetData(transId=%d, slotId=%d, dataStatus=*0x%x, dataStatusSize=%d, data=*0x%x, recvSize=%d, option=*0x%x)", transId, slotId, dataStatus, dataStatusSize, data, recvSize, option);
@@ -1993,7 +1993,7 @@ error_code sceNpTssGetData(s32 transId, SceNpTssSlotId slotId, vm::ptr<SceNpTssD
return CELL_OK;
}
error_code sceNpTssGetDataAsync(s32 transId, SceNpTssSlotId slotId, vm::ptr<SceNpTssDataStatus> dataStatus, u64 dataStatusSize, vm::ptr<void> data, u64 recvSize, vm::ptr<SceNpTssGetDataOptParam> option)
error_code sceNpTssGetDataAsync(s32 transId, SceNpTssSlotId slotId, vm::ptr<SceNpTssDataStatus> dataStatus, u32 dataStatusSize, vm::ptr<void> data, u32 recvSize, vm::ptr<SceNpTssGetDataOptParam> option)
{
sceNpTus.todo("sceNpTssGetDataAsync(transId=%d, slotId=%d, dataStatus=*0x%x, dataStatusSize=%d, data=*0x%x, recvSize=%d, option=*0x%x)", transId, slotId, dataStatus, dataStatusSize, data, recvSize, option);
+2 -2
View File
@@ -69,7 +69,7 @@ struct sce_np_util_manager
}
};
error_code sceNpUtilBandwidthTestInitStart(ppu_thread& ppu, u32 prio, u32 stack)
error_code sceNpUtilBandwidthTestInitStart([[maybe_unused]] ppu_thread& ppu, u32 prio, u32 stack)
{
sceNpUtil.todo("sceNpUtilBandwidthTestInitStart(prio=%d, stack=%d)", prio, stack);
@@ -101,7 +101,7 @@ error_code sceNpUtilBandwidthTestGetStatus()
return not_an_error(util_manager.bandwidth_test_thread->status);
}
error_code sceNpUtilBandwidthTestShutdown(ppu_thread& ppu, vm::ptr<SceNpUtilBandwidthTestResult> result)
error_code sceNpUtilBandwidthTestShutdown([[maybe_unused]] ppu_thread& ppu, vm::ptr<SceNpUtilBandwidthTestResult> result)
{
sceNpUtil.warning("sceNpUtilBandwidthTestShutdown(result=*0x%x)", result);
+2 -1
View File
@@ -23,6 +23,7 @@
#if !defined(_MSC_VER)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wold-style-cast"
#pragma GCC diagnostic ignored "-Wuninitialized"
#endif
extern bool is_debugger_present();
@@ -5311,7 +5312,7 @@ auto STVLX()
{
const u64 addr = op.ra ? a + b : b;
const u32 tail = u32(addr & 15);
u8* ptr = vm::_ptr<u8>(addr & -16);
u8* ptr = vm::_ptr<u8>(addr);
for (u32 j = 0; j < 16 - tail; j++)
ptr[j] = s.u8r[j];
};
+103 -12
View File
@@ -38,6 +38,8 @@ extern void sys_initialize_tls(ppu_thread&, u64, u32, u32, u32);
// HLE function name cache
std::vector<std::string> g_ppu_function_names;
atomic_t<u32> liblv2_begin = 0, liblv2_end = 0;
extern u32 ppu_generate_id(std::string_view name)
{
// Symbol name suffix
@@ -83,7 +85,7 @@ void ppu_module_manager::register_module(ppu_static_module* _module)
ppu_static_function& ppu_module_manager::access_static_function(const char* _module, u32 fnid)
{
auto& res = ppu_module_manager::s_module_map.at(_module)->functions[fnid];
auto& res = ::at32(ppu_module_manager::s_module_map, _module)->functions[fnid];
if (res.name)
{
@@ -95,7 +97,7 @@ ppu_static_function& ppu_module_manager::access_static_function(const char* _mod
ppu_static_variable& ppu_module_manager::access_static_variable(const char* _module, u32 vnid)
{
auto& res = ppu_module_manager::s_module_map.at(_module)->variables[vnid];
auto& res = ::at32(ppu_module_manager::s_module_map, _module)->variables[vnid];
if (res.name)
{
@@ -338,20 +340,20 @@ static void ppu_initialize_modules(ppu_linkage_info* link, utils::serial* ar = n
while (true)
{
const std::string name = ar.operator std::string();
if (name.empty())
{
// Null termination
break;
}
const auto _module = manager.at(name);
const auto _module = ::at32(manager, name);
auto& variable = _module->variables;
for (u32 i = 0, end = ar.operator usz(); i < end; i++)
{
auto* ptr = &variable.at(ar.operator u32());
auto* ptr = &::at32(variable, ar.operator u32());
ptr->addr = ar.operator u32();
ensure(!!ptr->var);
}
@@ -680,7 +682,7 @@ static auto ppu_load_exports(ppu_linkage_info* link, u32 exports_start, u32 expo
{
const u32 fnid = fnids[i];
const u32 faddr = faddrs[i];
ppu_loader.notice("**** %s export: [%s] (0x%08x) at 0x%x", module_name, ppu_get_function_name(module_name, fnid), fnid, faddr);
ppu_loader.notice("**** %s export: [%s] (0x%08x) at 0x%x [at:0x%x]", module_name, ppu_get_function_name(module_name, fnid), fnid, faddr, vm::read32(faddr));
// Function linkage info
auto& flink = mlink.functions[fnid];
@@ -697,7 +699,7 @@ static auto ppu_load_exports(ppu_linkage_info* link, u32 exports_start, u32 expo
//else
{
// Static function
const auto _sf = _sm && _sm->functions.count(fnid) ? &_sm->functions.at(fnid) : nullptr;
const auto _sf = _sm && _sm->functions.count(fnid) ? &::at32(_sm->functions, fnid) : nullptr;
if (_sf && (_sf->flags & MFF_FORCED_HLE))
{
@@ -1069,6 +1071,77 @@ void try_spawn_ppu_if_exclusive_program(const ppu_module& m)
}
}
struct prx_names_table
{
shared_mutex mutex;
std::set<std::string, std::less<>> registered;
atomic_t<const char*> lut[0x1000'0000 / 0x1'0000]{};
SAVESTATE_INIT_POS(4.1); // Dependency on lv2_obj
prx_names_table() noexcept
{
idm::select<lv2_obj, lv2_prx>([this](u32, lv2_prx& prx)
{
install(prx.name, prx);
});
}
void install(std::string_view name, lv2_prx& prx)
{
if (name.empty())
{
return;
}
if (name.ends_with(".sprx"sv) && name.size() > (".sprx"sv).size())
{
name = name.substr(0, name.size() - (".sprx"sv).size());
}
std::lock_guard lock(mutex);
const auto ptr = registered.emplace(name).first->c_str();
for (auto& seg : prx.segs)
{
if (!seg.size)
{
continue;
}
// Doesn't support addresses above 256MB because it wastes memory and is very unlikely (if somehow does occur increase it)
const u32 max0 = (seg.addr + seg.size - 1) >> 16;
const u32 max = std::min<u32>(std::size(lut), max0);
if (max0 > max)
{
ppu_loader.error("Skipping PRX name registeration: %s, max=0x%x", name, max0 << 16);
}
for (u32 i = seg.addr >> 16; i <= max; i++)
{
lut[i].release(ptr);
}
}
}
};
const char* get_prx_name_by_cia(u32 addr)
{
if (auto t = g_fxo->try_get<prx_names_table>())
{
addr >>= 16;
if (addr < std::size(t->lut))
{
return t->lut[addr];
}
}
return nullptr;
}
std::shared_ptr<lv2_prx> ppu_load_prx(const ppu_prx_object& elf, const std::string& path, s64 file_offset, utils::serial* ar)
{
if (elf != elf_error::ok)
@@ -1215,12 +1288,12 @@ std::shared_ptr<lv2_prx> ppu_load_prx(const ppu_prx_object& elf, const std::stri
{
const auto& rel = reinterpret_cast<const ppu_prx_relocation_info&>(prog.bin[i]);
if (rel.offset >= prx->segs.at(rel.index_addr).size)
if (rel.offset >= ::at32(prx->segs, rel.index_addr).size)
{
fmt::throw_exception("Relocation offset out of segment memory! (offset=0x%x, index_addr=%u)", rel.offset, rel.index_addr);
}
const u32 data_base = rel.index_value == 0xFF ? 0 : prx->segs.at(rel.index_value).addr;
const u32 data_base = rel.index_value == 0xFF ? 0 : ::at32(prx->segs, rel.index_value).addr;
if (rel.index_value != 0xFF && !data_base)
{
@@ -1228,7 +1301,7 @@ std::shared_ptr<lv2_prx> ppu_load_prx(const ppu_prx_object& elf, const std::stri
}
ppu_reloc _rel;
const u32 raddr = _rel.addr = vm::cast(prx->segs.at(rel.index_addr).addr + rel.offset);
const u32 raddr = _rel.addr = vm::cast(::at32(prx->segs, rel.index_addr).addr + rel.offset);
const u32 rtype = _rel.type = rel.type;
const u64 rdata = _rel.data = data_base + rel.ptr.addr();
prx->relocs.emplace_back(_rel);
@@ -1362,11 +1435,20 @@ std::shared_ptr<lv2_prx> ppu_load_prx(const ppu_prx_object& elf, const std::stri
prx->path = path;
prx->offset = file_offset;
g_fxo->need<prx_names_table>();
g_fxo->get<prx_names_table>().install(prx->name, *prx);
sha1_finish(&sha, prx->sha1);
// Format patch name
std::string hash = fmt::format("PRX-%s", fmt::base57(prx->sha1));
if (prx->path.ends_with("sys/external/liblv2.sprx"sv))
{
liblv2_begin = prx->segs[0].addr;
liblv2_end = prx->segs[0].addr + prx->segs[0].size;
}
std::basic_string<u32> applied;
for (usz i = 0; i < prx->segs.size(); i++)
@@ -1441,6 +1523,12 @@ void ppu_unload_prx(const lv2_prx& prx)
// }
//}
if (prx.path.ends_with("sys/external/liblv2.sprx"sv))
{
liblv2_begin = 0;
liblv2_end = 0;
}
// Format patch name
std::string hash = fmt::format("PRX-%s", fmt::base57(prx.sha1));
@@ -1935,6 +2023,9 @@ bool ppu_load_exec(const ppu_exec_object& elf, utils::serial* ar)
void init_fxo_for_exec(utils::serial* ar, bool full);
init_fxo_for_exec(ar, false);
liblv2_begin = 0;
liblv2_end = 0;
if (!load_libs.empty())
{
for (const auto& name : load_libs)
@@ -2449,7 +2540,7 @@ bool ppu_load_rel_exec(const ppu_rel_object& elf)
const auto& s = *ptr;
ppu_loader.notice("** Section: sh_type=0x%x, addr=0x%llx, size=0x%llx, flags=0x%x", std::bit_cast<u32>(s.sh_type), s.sh_addr, s.sh_size, s._sh_flags);
if (s.sh_type == sec_type::sht_progbits && s.sh_size && s.sh_flags().all_of(sh_flag::shf_alloc))
{
ppu_segment _sec;
+1 -1
View File
@@ -294,7 +294,7 @@ inline RT ppu_execute(ppu_thread& ppu, Args... args)
return func(ppu, args...);
}
#define BIND_FUNC_WITH_BLR(func) BIND_FUNC(func, ppu.cia = static_cast<u32>(ppu.lr) & ~3)
#define BIND_FUNC_WITH_BLR(func) BIND_FUNC(func, if (cpu_flag::again - ppu.state) ppu.cia = static_cast<u32>(ppu.lr) & ~3)
#define REG_FNID(_module, nid, func) ppu_module_manager::register_static_function<&func>(#_module, ppu_select_name(#func, nid), BIND_FUNC_WITH_BLR(func), ppu_generate_id(nid))
+2 -2
View File
@@ -117,7 +117,7 @@ class ppu_decoder
for (u32 j = 0; j < 1u << sh; j++)
{
const u32 k = (((i << (count - v.magn)) | v.value) << sh) | j;
m_table.at((k << 6) | main_op) = k & 1 ? v.ptr_rc : v.ptr0;
::at32(m_table, (k << 6) | main_op) = k & 1 ? v.ptr_rc : v.ptr0;
}
}
}
@@ -129,7 +129,7 @@ class ppu_decoder
{
for (u32 i = 0; i < 1u << 11; i++)
{
m_table.at(i << 6 | v.value) = i & 1 ? v.ptr_rc : v.ptr0;
::at32(m_table, i << 6 | v.value) = i & 1 ? v.ptr_rc : v.ptr0;
}
}
}
+40 -15
View File
@@ -710,8 +710,8 @@ struct ppu_far_jumps_t
Label jmp_address = c.newLabel();
Label imm_address = c.newLabel();
c.ldr(args[1].r32(), arm::ptr(imm_address));
c.str(args[1].r32(), arm::Mem(args[0], ::offset32(&ppu_thread::cia)));
c.ldr(args[1].w(), arm::ptr(imm_address));
c.str(args[1].w(), arm::Mem(args[0], ::offset32(&ppu_thread::cia)));
c.ldr(args[1], arm::ptr(jmp_address));
c.br(args[1]);
@@ -721,7 +721,7 @@ struct ppu_far_jumps_t
c.bind(imm_address);
c.embedUInt32(pc);
#endif
}, &rt);
}, &rt);
}
return it->second.func;
@@ -1038,7 +1038,7 @@ void ppu_thread::dump_regs(std::string& ret) const
return addr % 4 == 0 && vm::check_addr(addr, vm::page_executable) && g_ppu_itype.decode(*vm::get_super_ptr<u32>(addr)) != ppu_itype::UNK;
};
if (const u32 reg_ptr = *vm::get_super_ptr<u32>(static_cast<u32>(reg));
if (const u32 reg_ptr = *vm::get_super_ptr<be_t<u32, 1>>(static_cast<u32>(reg));
vm::check_addr<8>(reg_ptr) && !vm::check_addr(toc, vm::page_executable))
{
// Check executability and alignment
@@ -1277,6 +1277,16 @@ std::string ppu_thread::dump_misc() const
{
std::string ret = cpu_thread::dump_misc();
if (ack_suspend)
{
if (ret.ends_with("\n"))
{
ret.pop_back();
}
fmt::append(ret, " (LV2 suspended)\n");
}
fmt::append(ret, "Priority: %d\n", +prio);
fmt::append(ret, "Stack: 0x%x..0x%x\n", stack_addr, stack_addr + stack_size - 1);
fmt::append(ret, "Joiner: %s\n", joiner.load());
@@ -1296,7 +1306,7 @@ std::string ppu_thread::dump_misc() const
if (u64 v = gpr[i]; v != syscall_args[i - 3])
fmt::append(ret, " ** r%d: 0x%llx\n", i, v);
}
else if (is_paused())
else if (is_paused() || is_stopped())
{
if (const auto last_func = last_function)
{
@@ -1401,7 +1411,7 @@ void ppu_thread::cpu_task()
}
case ppu_cmd::hle_call:
{
cmd_pop(), ppu_function_manager::get().at(arg)(*this, {arg}, vm::_ptr<u32>(cia - 4), &ppu_ret);
cmd_pop(), ::at32(ppu_function_manager::get(), arg)(*this, {arg}, vm::_ptr<u32>(cia - 4), &ppu_ret);
break;
}
case ppu_cmd::opd_call:
@@ -1712,7 +1722,7 @@ ppu_thread::ppu_thread(utils::serial& ar)
{
cmd_list
({
{ppu_cmd::ptr_call, 0}, +[](ppu_thread& ppu) -> bool
{ppu_cmd::ptr_call, 0}, +[](ppu_thread&) -> bool
{
while (!Emu.IsStopped() && !g_fxo->get<init_pushed>().inited)
{
@@ -1799,7 +1809,7 @@ void ppu_thread::save(utils::serial& ar)
if (_joiner >= ppu_join_status::max)
{
// Joining thread should recover this member properly
_joiner = ppu_join_status::joinable;
_joiner = ppu_join_status::joinable;
}
if (state & cpu_flag::again)
@@ -1943,6 +1953,13 @@ void ppu_thread::fast_call(u32 addr, u64 rtoc)
return fmt::format("PPU[0x%x] Thread (%s) [HLE:0x%08x, LR:0x%08x]", _this->id, *name_cache.get(), cia, _this->lr);
}
extern const char* get_prx_name_by_cia(u32 addr);
if (auto name = get_prx_name_by_cia(cia))
{
return fmt::format("PPU[0x%x] Thread (%s) [%s: 0x%08x]", _this->id, *name_cache.get(), name, cia);
}
return fmt::format("PPU[0x%x] Thread (%s) [0x%08x]", _this->id, *name_cache.get(), cia);
};
@@ -2642,11 +2659,9 @@ static bool ppu_store_reservation(ppu_thread& ppu, u32 addr, u64 reg_value)
}())
{
// Test a common pattern in lwmutex
constexpr u64 mutex_free = u64{static_cast<u32>(0 - 1)} << 32;
const bool may_be_lwmutex_related = sizeof(T) == 8 ?
(new_data == mutex_free && old_data == u64{ppu.id} << 32) : (old_data == mutex_free && new_data == u64{ppu.id} << 32);
extern atomic_t<u32> liblv2_begin, liblv2_end;
if (!may_be_lwmutex_related)
if (ppu.cia < liblv2_begin || ppu.cia >= liblv2_end)
{
res.notify_all(-128);
}
@@ -2890,7 +2905,7 @@ extern void ppu_precompile(std::vector<std::string>& dir_queue, std::vector<ppu_
std::string upper = fmt::to_upper(entry.name);
// Skip already loaded modules or HLEd ones
auto is_ignored = [&](s64 offset) -> bool
auto is_ignored = [&](s64 /*offset*/) -> bool
{
if (dir_queue[i] != firmware_sprx_path)
{
@@ -2922,7 +2937,7 @@ extern void ppu_precompile(std::vector<std::string>& dir_queue, std::vector<ppu_
extern const std::map<std::string_view, int> g_prx_list;
// Use list
return g_prx_list.count(entry.name) && g_prx_list.at(entry.name) != 0;
return g_prx_list.count(entry.name) && ::at32(g_prx_list, entry.name) != 0;
};
// Check .sprx filename
@@ -3280,6 +3295,11 @@ bool ppu_initialize(const ppu_module& info, bool check_only)
{
std::unordered_map<std::string, u64> link_table
{
{ "sys_game_watchdog_start", reinterpret_cast<u64>(ppu_execute_syscall) },
{ "sys_game_watchdog_stop", reinterpret_cast<u64>(ppu_execute_syscall) },
{ "sys_game_watchdog_clear", reinterpret_cast<u64>(ppu_execute_syscall) },
{ "sys_game_get_system_sw_version", reinterpret_cast<u64>(ppu_execute_syscall) },
{ "sys_game_board_storage_read", reinterpret_cast<u64>(ppu_execute_syscall) },
{ "__trap", reinterpret_cast<u64>(&ppu_trap) },
{ "__error", reinterpret_cast<u64>(&ppu_error) },
{ "__check", reinterpret_cast<u64>(&ppu_check) },
@@ -3369,7 +3389,7 @@ bool ppu_initialize(const ppu_module& info, bool check_only)
usz fpos = 0;
// Difference between function name and current location
const u32 reloc = info.relocs.empty() ? 0 : info.segs.at(0).addr;
const u32 reloc = info.relocs.empty() ? 0 : ::at32(info.segs, 0).addr;
// Info sent to threads
std::vector<std::pair<std::string, ppu_module>> workload;
@@ -3725,6 +3745,11 @@ bool ppu_initialize(const ppu_module& info, bool check_only)
// Allocate "core"
std::lock_guard jlock(g_fxo->get<jit_core_allocator>().sem);
if (Emu.IsStopped())
{
continue;
}
ppu_log.warning("LLVM: Compiling module %s%s", cache_path, obj_name);
// Use another JIT instance
+2 -2
View File
@@ -534,7 +534,7 @@ Value* PPUTranslator::Shuffle(Value* left, Value* right, std::initializer_list<u
// Transform indices (works for vectors with size 2^N)
for (usz i = 0; i < indices.size(); i++)
{
data.push_back(indices.end()[~i] ^ mask);
data.push_back(*(indices.begin() + indices.size() - 1 - i) ^ mask);
}
return m_ir->CreateShuffleVector(left, right, ConstantDataVector::get(m_context, data));
@@ -1289,7 +1289,7 @@ void PPUTranslator::VPERM(ppu_opcode_t op)
if (m_use_avx512_icl)
{
const auto i = eval(~c);
set_vr(op.vd, vperm2b256to128(b, a, i));
set_vr(op.vd, vperm2b(b, a, i));
return;
}
+5 -1
View File
@@ -244,7 +244,7 @@ bool spu_thread::write_reg(const u32 addr, const u32 value)
case SPU_In_MBox_offs:
{
ch_in_mbox.push(*this, value);
ch_in_mbox.push(value);
return true;
}
@@ -323,6 +323,8 @@ void spu_load_exec(const spu_exec_object& elf)
spu_thread::g_raw_spu_ctr++;
auto spu = idm::make_ptr<named_thread<spu_thread>>(nullptr, 0, "test_spu", 0);
ensure(vm::get(vm::spu)->falloc(spu->vm_offset(), SPU_LS_SIZE, &spu->shm, vm::page_size_64k));
spu->map_ls(*spu->shm, spu->ls);
for (const auto& prog : elf.progs)
{
@@ -343,6 +345,8 @@ void spu_load_rel_exec(const spu_rel_object& elf)
spu_thread::g_raw_spu_ctr++;
auto spu = idm::make_ptr<named_thread<spu_thread>>(nullptr, 0, "test_spu", 0);
ensure(vm::get(vm::spu)->falloc(spu->vm_offset(), SPU_LS_SIZE, &spu->shm, vm::page_size_64k));
spu->map_ls(*spu->shm, spu->ls);
u64 total_memsize = 0;
+1 -1
View File
@@ -675,7 +675,7 @@ spu_function_t spu_recompiler::compile(spu_program&& _func)
}
// Determine which value will be duplicated at hole positions
const u32 w3 = func.data.at((j - start + ~static_cast<u32>(std::countl_zero(cmask)) % 4 * 4) / 4);
const u32 w3 = ::at32(func.data, (j - start + ~static_cast<u32>(std::countl_zero(cmask)) % 4 * 4) / 4);
words.push_back(cmask & 1 ? func.data[(j - start + 0) / 4] : w3);
words.push_back(cmask & 2 ? func.data[(j - start + 4) / 4] : w3);
words.push_back(cmask & 4 ? func.data[(j - start + 8) / 4] : w3);
+1 -1
View File
@@ -291,7 +291,7 @@ struct spu_itype
// Test for constant loading instruction
friend constexpr bool operator &(type value, constant_tag)
{
return value >= CBD && value <= FSMBI;
return value >= ILH && value <= FSMBI;
}
};
+234 -154
View File
@@ -28,10 +28,6 @@
#include "util/simd.hpp"
#include "util/sysinfo.hpp"
#if defined(ARCH_ARM64)
#include "Emu/CPU/sse2neon.h"
#endif
const extern spu_decoder<spu_itype> g_spu_itype;
const extern spu_decoder<spu_iname> g_spu_iname;
const extern spu_decoder<spu_iflag> g_spu_iflag;
@@ -974,8 +970,8 @@ spu_function_t spu_runtime::rebuild_ubertrampoline(u32 id_inst)
static thread_local std::vector<std::pair<std::basic_string_view<u32>, spu_function_t>> m_flat_list;
// Remember top position
auto stuff_it = m_stuff.at(id_inst >> 12).begin();
auto stuff_end = m_stuff.at(id_inst >> 12).end();
auto stuff_it = ::at32(m_stuff, id_inst >> 12).begin();
auto stuff_end = ::at32(m_stuff, id_inst >> 12).end();
{
if (stuff_it->trampoline)
{
@@ -1038,43 +1034,73 @@ spu_function_t spu_runtime::rebuild_ubertrampoline(u32 id_inst)
auto make_jump = [&](asmjit::arm::CondCode op, auto target)
{
// 36 bytes
// Fallback to dispatch if no target
const u64 taddr = target ? reinterpret_cast<u64>(target) : reinterpret_cast<u64>(tr_dispatch);
// Build with asmjit to make things more readable
// Might cost some RAM, but meh whatever
auto temp = build_function_asm<spu_function_t>("", [&](native_asm& c, auto& args)
// ldr x9, #16 -> ldr x9, taddr
*raw++ = 0x89;
*raw++ = 0x00;
*raw++ = 0x00;
*raw++ = 0x58;
if (op == asmjit::arm::CondCode::kAlways)
{
// br x9
*raw++ = 0x20;
*raw++ = 0x01;
*raw++ = 0x1F;
*raw++ = 0xD6;
// nop
*raw++ = 0x1F;
*raw++ = 0x20;
*raw++ = 0x03;
*raw++ = 0xD5;
// nop
*raw++ = 0x1F;
*raw++ = 0x20;
*raw++ = 0x03;
*raw++ = 0xD5;
}
else
{
// b.COND #8 -> b.COND do_branch
switch (op)
{
using namespace asmjit;
case asmjit::arm::CondCode::kUnsignedLT:
*raw++ = 0x43;
break;
case asmjit::arm::CondCode::kUnsignedGT:
*raw++ = 0x48;
break;
default:
asm("brk 0x42");
}
c.movk(a64::x9, Imm(static_cast<u16>(taddr >> 48)), Imm(48));
c.movk(a64::x9, Imm(static_cast<u16>(taddr >> 32)), Imm(32));
c.movk(a64::x9, Imm(static_cast<u16>(taddr >> 16)), Imm(16));
c.movk(a64::x9, Imm(static_cast<u16>(taddr)), Imm(0));
*raw++ = 0x00;
*raw++ = 0x00;
*raw++ = 0x54;
if (op == arm::CondCode::kAlways)
{
c.br(a64::x9);
// Constant length per jmp for easier stub patching
c.nop();
c.nop();
} else
{
Label do_branch = c.newLabel();
Label cont = c.newLabel();
// b #16 -> b cont
*raw++ = 0x04;
*raw++ = 0x00;
*raw++ = 0x00;
*raw++ = 0x14;
c.b(op, do_branch);
c.b(cont);
// do_branch: br x9
*raw++ = 0x20;
*raw++ = 0x01;
*raw++ = 0x1f;
*raw++ = 0xD6;
}
c.bind(do_branch);
c.br(a64::x9);
// taddr
std::memcpy(raw, &taddr, 8);
raw += 8;
c.bind(cont);
}
});
u8 mem_used = 7 * 4;
memcpy(raw, reinterpret_cast<u8*>(temp), mem_used);
raw += mem_used;
// cont: next instruction
};
#elif defined(ARCH_X64)
// Allocate some writable executable memory
@@ -1152,7 +1178,7 @@ spu_function_t spu_runtime::rebuild_ubertrampoline(u32 id_inst)
break;
}
const u32 x1 = w.beg->first.at(w.level);
const u32 x1 = ::at32(w.beg->first, w.level);
if (!x1)
{
@@ -1175,7 +1201,7 @@ spu_function_t spu_runtime::rebuild_ubertrampoline(u32 id_inst)
}
// Adjust ranges (forward)
while (it != w.end && x1 == it->first.at(w.level))
while (it != w.end && x1 == ::at32(it->first, w.level))
{
it++;
size1++;
@@ -1203,17 +1229,7 @@ spu_function_t spu_runtime::rebuild_ubertrampoline(u32 id_inst)
// Rewrite jump address
{
u64 raw64 = reinterpret_cast<u64>(raw);
auto temp = build_function_asm<spu_function_t>("", [&](native_asm& c, auto& args)
{
using namespace asmjit;
c.movk(a64::x9, Imm(static_cast<u16>(raw64 >> 48)), Imm(48));
c.movk(a64::x9, Imm(static_cast<u16>(raw64 >> 32)), Imm(32));
c.movk(a64::x9, Imm(static_cast<u16>(raw64 >> 16)), Imm(16));
c.movk(a64::x9, Imm(static_cast<u16>(raw64)), Imm(0));
});
memcpy(w.rel32 - (4 * 7), reinterpret_cast<u8*>(temp), 4 * 4);
memcpy(w.rel32 - 8, &raw64, 8);
}
#else
#error "Unimplemented"
@@ -1236,7 +1252,7 @@ spu_function_t spu_runtime::rebuild_ubertrampoline(u32 id_inst)
}
// Value for comparison
const u32 x = it->first.at(w.level);
const u32 x = ::at32(it->first, w.level);
// Adjust ranges (backward)
while (it != m_flat_list.begin())
@@ -1249,7 +1265,7 @@ spu_function_t spu_runtime::rebuild_ubertrampoline(u32 id_inst)
break;
}
if (it->first.at(w.level) != x)
if (::at32(it->first, w.level) != x)
{
it++;
break;
@@ -1302,19 +1318,27 @@ spu_function_t spu_runtime::rebuild_ubertrampoline(u32 id_inst)
raw += 4;
}
#elif defined(ARCH_ARM64)
{
auto temp = build_function_asm<spu_function_t>("", [&](native_asm& c, auto& args)
{
using namespace asmjit;
// ldr w9, #8
*raw++ = 0x49;
*raw++ = 0x00;
*raw++ = 0x00;
*raw++ = 0x18;
c.movz(a64::w9, Imm(static_cast<u16>(cmp_lsa >> 16)), Imm(16));
c.movk(a64::w9, Imm(static_cast<u16>(cmp_lsa)), Imm(0));
c.ldr(a64::w1, arm::Mem(a64::x7, a64::x9));
});
// b #8
*raw++ = 0x02;
*raw++ = 0x00;
*raw++ = 0x00;
*raw++ = 0x14;
memcpy(raw, reinterpret_cast<u8*>(temp), 3 * 4);
raw += 3 * 4;
}
// cmp_lsa
std::memcpy(raw, &cmp_lsa, 4);
raw += 4;
// ldr w1, [x7, x9]
*raw++ = 0xE1;
*raw++ = 0x68;
*raw++ = 0x69;
*raw++ = 0xB8;
#else
#error "Unimplemented"
#endif
@@ -1326,19 +1350,27 @@ spu_function_t spu_runtime::rebuild_ubertrampoline(u32 id_inst)
std::memcpy(raw, &x, 4);
raw += 4;
#elif defined(ARCH_ARM64)
{
auto temp = build_function_asm<spu_function_t>("", [&](native_asm& c, auto& args)
{
using namespace asmjit;
// ldr w9, #8
*raw++ = 0x49;
*raw++ = 0x00;
*raw++ = 0x00;
*raw++ = 0x18;
c.movz(a64::w9, Imm(static_cast<u16>(x >> 16)), Imm(16));
c.movk(a64::w9, Imm(static_cast<u16>(x)), Imm(0));
c.cmp(a64::w1, a64::w9);
});
// b #8
*raw++ = 0x02;
*raw++ = 0x00;
*raw++ = 0x00;
*raw++ = 0x14;
memcpy(raw, reinterpret_cast<u8*>(temp), 3 * 4);
raw += 3 * 4;
}
// x
std::memcpy(raw, &x, 4);
raw += 4;
// cmp w1, w9
*raw++ = 0x3f;
*raw++ = 0x00;
*raw++ = 0x09;
*raw++ = 0x6B;
#else
#error "Unimplemented"
#endif
@@ -1388,7 +1420,7 @@ spu_function_t spu_runtime::rebuild_ubertrampoline(u32 id_inst)
it2 = it;
// Select additional midrange for equality comparison
while (it2 != w.end && it2->first.at(w.level) == x)
while (it2 != w.end && ::at32(it2->first, w.level) == x)
{
size2--;
it2++;
@@ -1486,7 +1518,7 @@ spu_function_t spu_runtime::rebuild_ubertrampoline(u32 id_inst)
}
// Install ubertrampoline
auto& insert_to = spu_runtime::g_dispatcher->at(id_inst >> 12);
auto& insert_to = ::at32(*spu_runtime::g_dispatcher, id_inst >> 12);
auto _old = insert_to.load();
@@ -1519,7 +1551,7 @@ spu_function_t spu_runtime::rebuild_ubertrampoline(u32 id_inst)
spu_function_t spu_runtime::find(const u32* ls, u32 addr) const
{
for (auto& item : m_stuff.at(ls[addr / 4] >> 12))
for (auto& item : ::at32(m_stuff, ls[addr / 4] >> 12))
{
if (const auto ptr = item.compiled.load())
{
@@ -1573,34 +1605,56 @@ spu_function_t spu_runtime::make_branch_patchpoint(u16 data) const
return reinterpret_cast<spu_function_t>(raw);
#elif defined(ARCH_ARM64)
spu_function_t func = build_function_asm<spu_function_t>("", [&](native_asm& c, auto& args)
{
using namespace asmjit;
#if defined(__APPLE__)
pthread_jit_write_protect_np(false);
#endif
// Save the jmp addr to GHC CC 3rd arg -> REG_Hp
Label replace_addr = c.newLabel();
u8* const patch_fn = ensure(jit_runtime::alloc(36, 16));
u8* raw = patch_fn;
c.adr(a64::x21, replace_addr);
// 16 byte alignment for the jump replacement
c.nop();
c.nop();
c.nop();
Label branch_target = c.newLabel();
// adr x21, #16
*raw++ = 0x95;
*raw++ = 0x00;
*raw++ = 0x00;
*raw++ = 0x10;
c.bind(replace_addr);
c.ldr(a64::x9, arm::Mem(branch_target));
c.br(a64::x9);
// nop x3
for (int i = 0; i < 3; i++)
{
*raw++ = 0x1F;
*raw++ = 0x20;
*raw++ = 0x03;
*raw++ = 0xD5;
}
c.bind(branch_target);
c.embedUInt64(reinterpret_cast<u64>(tr_branch));
// ldr x9, #8
*raw++ = 0x49;
*raw++ = 0x00;
*raw++ = 0x00;
*raw++ = 0x58;
c.embedUInt8(data >> 8);
c.embedUInt8(data & 0xff);
// br x9
*raw++ = 0x20;
*raw++ = 0x01;
*raw++ = 0x1F;
*raw++ = 0xD6;
c.embed("branch_patchpoint", 17);
});
u64 branch_target = reinterpret_cast<u64>(tr_branch);
std::memcpy(raw, &branch_target, 8);
raw += 8;
return func;
*raw++ = static_cast<u8>(data >> 8);
*raw++ = static_cast<u8>(data & 0xff);
#if defined(__APPLE__)
pthread_jit_write_protect_np(true);
#endif
// Flush all cache lines after potentially writing executable code
asm("ISB");
asm("DSB ISH");
return reinterpret_cast<spu_function_t>(patch_fn);
#else
#error "Unimplemented"
#endif
@@ -1636,18 +1690,26 @@ void spu_recompiler_base::dispatch(spu_thread& spu, void*, u8* rip)
atomic_storage<u64>::release(*reinterpret_cast<u64*>(rip - 8), result);
#elif defined(ARCH_ARM64)
auto jump_instrs = build_function_asm<spu_function_t>("", [](native_asm& c, auto& args)
{
using namespace asmjit;
union
{
u8 bytes[16];
u128 result;
};
Label branch_target = c.newLabel();
c.ldr(a64::x9, arm::Mem(branch_target)); // PC rel load
c.br(a64::x9);
// ldr x9, #8
bytes[0] = 0x49;
bytes[1] = 0x00;
bytes[2] = 0x00;
bytes[3] = 0x58;
c.bind(branch_target);
c.embedUInt64(reinterpret_cast<u64>(spu_runtime::tr_all));
});
u128 result = *reinterpret_cast<u128*>(jump_instrs);
// br x9
bytes[4] = 0x20;
bytes[5] = 0x01;
bytes[6] = 0x1F;
bytes[7] = 0xD6;
const u64 target = reinterpret_cast<u64>(spu_runtime::tr_all);
std::memcpy(bytes + 8, &target, 8);
#if defined(__APPLE__)
pthread_jit_write_protect_np(false);
#endif
@@ -1665,7 +1727,7 @@ void spu_recompiler_base::dispatch(spu_thread& spu, void*, u8* rip)
}
// Second attempt (recover from the recursion after repeated unsuccessful trampoline call)
if (spu.block_counter != spu.block_recover && &dispatch != spu_runtime::g_dispatcher->at(spu._ref<nse_t<u32>>(spu.pc) >> 12))
if (spu.block_counter != spu.block_recover && &dispatch != ::at32(*spu_runtime::g_dispatcher, spu._ref<nse_t<u32>>(spu.pc) >> 12))
{
spu.block_recover = spu.block_counter;
return;
@@ -1768,18 +1830,26 @@ void spu_recompiler_base::branch(spu_thread& spu, void*, u8* rip)
atomic_storage<u64>::release(*reinterpret_cast<u64*>(rip), result);
#elif defined(ARCH_ARM64)
auto jmp_instrs = build_function_asm<spu_function_t>("", [&](native_asm& c, auto& args)
{
using namespace asmjit;
union
{
u8 bytes[16];
u128 result;
};
Label branch_target = c.newLabel();
c.ldr(a64::x9, arm::Mem(branch_target)); // PC rel load
c.br(a64::x9);
// ldr x9, #8
bytes[0] = 0x49;
bytes[1] = 0x00;
bytes[2] = 0x00;
bytes[3] = 0x58;
c.bind(branch_target);
c.embedUInt64(reinterpret_cast<u64>(func));
});
u128 result = *reinterpret_cast<u128*>(jmp_instrs);
// br x9
bytes[4] = 0x20;
bytes[5] = 0x01;
bytes[6] = 0x1F;
bytes[7] = 0xD6;
const u64 target = reinterpret_cast<u64>(func);
std::memcpy(bytes + 8, &target, 8);
#if defined(__APPLE__)
pthread_jit_write_protect_np(false);
#endif
@@ -2629,7 +2699,7 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point)
// Check for possible fallthrough predecessor
if (!had_fallthrough)
{
if (result.data.at((j - lsa) / 4 - 1) == 0 || m_targets.count(j - 4))
if (::at32(result.data, (j - lsa) / 4 - 1) == 0 || m_targets.count(j - 4))
{
break;
}
@@ -3014,13 +3084,14 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point)
{
workload.clear();
workload.push_back(entry_point);
ensure(m_bbs.count(entry_point));
std::basic_string<u32> new_entries;
for (u32 wi = 0; wi < workload.size(); wi++)
{
const u32 addr = workload[wi];
auto& block = m_bbs.at(addr);
auto& block = ::at32(m_bbs, addr);
const u32 _new = block.chunk;
if (!m_entry_info[addr / 4])
@@ -3028,7 +3099,7 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point)
// Check block predecessors
for (u32 pred : block.preds)
{
const u32 _old = m_bbs.at(pred).chunk;
const u32 _old = ::at32(m_bbs, pred).chunk;
if (_old < 0x40000 && _old != _new)
{
@@ -3097,9 +3168,9 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point)
// Fill workload adding targets
for (u32 wi = 0; wi < workload.size(); wi++)
{
const u32 addr = workload[wi];
auto& block = m_bbs.at(addr);
block.analysed = true;
const u32 addr = workload[wi];
auto& block = ::at32(m_bbs, addr);
block.analysed = true;
for (u32 target : block.targets)
{
@@ -3141,7 +3212,7 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point)
for (u32 wi = 0; wi < workload.size(); wi++)
{
const u32 addr = workload[wi];
auto& block = m_bbs.at(addr);
auto& block = ::at32(m_bbs, addr);
// Initialize entry point with default value: unknown origin (requires load)
if (m_entry_info[addr / 4])
@@ -3231,7 +3302,7 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point)
for (u32 wi = 0; wi < workload.size(); wi++)
{
const u32 addr = workload[wi];
auto& block = m_bbs.at(addr);
auto& block = ::at32(m_bbs, addr);
// Reset values for the next attempt (keep negative values)
for (u32 i = 0; i < s_reg_max; i++)
@@ -3253,8 +3324,8 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point)
}
const u32 addr = workload[wi];
auto& bb = m_bbs.at(addr);
auto& func = m_funcs.at(bb.func);
auto& bb = ::at32(m_bbs, addr);
auto& func = ::at32(m_funcs, bb.func);
// Update function size
func.size = std::max<u16>(func.size, bb.size + (addr - bb.func) / 4);
@@ -3266,7 +3337,7 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point)
if (orig < 0x40000)
{
auto& src = m_bbs.at(orig);
auto& src = ::at32(m_bbs, orig);
bb.reg_const[i] = src.reg_const[i];
bb.reg_val32[i] = src.reg_val32[i];
}
@@ -3280,7 +3351,7 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point)
if (u32 orig = bb.reg_origin_abs[s_reg_sp]; orig < 0x40000)
{
auto& prologue = m_bbs.at(orig);
auto& prologue = ::at32(m_bbs, orig);
// Copy stack offset (from the assumed prologue)
bb.stack_sub = prologue.stack_sub;
@@ -3291,7 +3362,7 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point)
bb.stack_sub = 0x80000000;
}
spu_opcode_t op;
spu_opcode_t op{};
auto last_inst = spu_itype::UNK;
@@ -3341,7 +3412,7 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point)
}
case spu_itype::OR:
{
bb.reg_const[op.rt] = bb.reg_const[op.ra] & bb.reg_const[op.rb];
bb.reg_const[op.rt] = bb.reg_const[op.ra] && bb.reg_const[op.rb];
bb.reg_val32[op.rt] = bb.reg_val32[op.ra] | bb.reg_val32[op.rb];
break;
}
@@ -3353,7 +3424,7 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point)
}
case spu_itype::A:
{
bb.reg_const[op.rt] = bb.reg_const[op.ra] & bb.reg_const[op.rb];
bb.reg_const[op.rt] = bb.reg_const[op.ra] && bb.reg_const[op.rb];
bb.reg_val32[op.rt] = bb.reg_val32[op.ra] + bb.reg_val32[op.rb];
break;
}
@@ -3365,7 +3436,7 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point)
}
case spu_itype::SF:
{
bb.reg_const[op.rt] = bb.reg_const[op.ra] & bb.reg_const[op.rb];
bb.reg_const[op.rt] = bb.reg_const[op.ra] && bb.reg_const[op.rb];
bb.reg_val32[op.rt] = bb.reg_val32[op.rb] - bb.reg_val32[op.ra];
break;
}
@@ -3592,8 +3663,8 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point)
for (auto it = m_bbs.lower_bound(f.first); it != m_bbs.end() && it->second.func == f.first; ++it)
{
auto& bb = it->second;
auto& func = m_funcs.at(bb.func);
auto& bb = it->second;
auto& func = ::at32(m_funcs, bb.func);
const u32 addr = it->first;
const u32 flim = bb.func + func.size * 4;
@@ -3609,7 +3680,7 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point)
// Check $LR (alternative return registers are currently not supported)
if (u32 lr_orig = bb.reg_mod[s_reg_lr] ? addr : bb.reg_origin_abs[s_reg_lr]; lr_orig < 0x40000)
{
auto& src = m_bbs.at(lr_orig);
auto& src = ::at32(m_bbs, lr_orig);
if (src.reg_load_mod[s_reg_lr] != func.reg_save_off[s_reg_lr])
{
@@ -3633,7 +3704,7 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point)
{
if (u32 orig = bb.reg_mod[i] ? addr : bb.reg_origin_abs[i]; orig < 0x40000)
{
auto& src = m_bbs.at(orig);
auto& src = ::at32(m_bbs, orig);
if (src.reg_load_mod[i] != func.reg_save_off[i])
{
@@ -4362,7 +4433,7 @@ class spu_llvm_recompiler : public spu_recompiler_base, public cpu_translator
return m_ir->CreateBitCast(_ptr<u8>(m_thread, get_reg_offset(index)), get_reg_type(index)->getPointerTo());
}
auto& ptr = m_reg_addr.at(index);
auto& ptr = ::at32(m_reg_addr, index);
if (!ptr)
{
@@ -4472,7 +4543,7 @@ class spu_llvm_recompiler : public spu_recompiler_base, public cpu_translator
{
llvm::Value* dummy{};
auto& reg = *(m_block ? &m_block->reg.at(index) : &dummy);
auto& reg = *(m_block ? &::at32(m_block->reg, index) : &dummy);
if (!reg)
{
@@ -4556,7 +4627,7 @@ class spu_llvm_recompiler : public spu_recompiler_base, public cpu_translator
if (m_block)
{
auto v = m_block->reg.at(index);
auto v = ::at32(m_block->reg, index);
if (v && v->getType() == get_type<T>())
{
@@ -4667,7 +4738,7 @@ class spu_llvm_recompiler : public spu_recompiler_base, public cpu_translator
value->setName(fmt::format("result_0x%05x", m_pos));
#endif
m_block->reg.at(index) = saved_value;
::at32(m_block->reg, index) = saved_value;
}
// Get register location
@@ -5233,7 +5304,7 @@ public:
const u32 baddr = m_block_queue[bi];
m_block = &m_blocks[baddr];
m_ir->SetInsertPoint(m_block->block);
auto& bb = m_bbs.at(baddr);
auto& bb = ::at32(m_bbs, baddr);
bool need_check = false;
m_block->bb = &bb;
@@ -6558,17 +6629,19 @@ public:
if (auto ci = llvm::dyn_cast<llvm::ConstantInt>(trunc<u8>(val).eval(m_ir)))
{
if (g_cfg.core.spu_accurate_dma)
if (g_cfg.core.mfc_debug)
{
break;
}
if (u64 cmdh = ci->getZExtValue() & ~(MFC_BARRIER_MASK | MFC_FENCE_MASK | MFC_RESULT_MASK); g_cfg.core.rsx_fifo_accuracy || !g_use_rtm)
bool must_use_cpp_functions = !!g_cfg.core.spu_accurate_dma;
if (u64 cmdh = ci->getZExtValue() & ~(MFC_BARRIER_MASK | MFC_FENCE_MASK | MFC_RESULT_MASK); g_cfg.core.rsx_fifo_accuracy || g_cfg.video.strict_rendering_mode || !g_use_rtm)
{
// TODO: don't require TSX (current implementation is TSX-only)
if (cmdh == MFC_PUT_CMD || cmdh == MFC_SNDSIG_CMD)
{
break;
must_use_cpp_functions = true;
}
}
@@ -6668,12 +6741,16 @@ public:
m_ir->CreateCondBr(cond, exec, fail, m_md_likely);
m_ir->SetInsertPoint(exec);
const auto mmio = llvm::BasicBlock::Create(m_context, "", m_function);
const auto copy = llvm::BasicBlock::Create(m_context, "", m_function);
// Always use interpreter function for MFC debug option
m_ir->CreateCondBr(m_ir->CreateICmpUGE(eal.value, m_ir->getInt32(g_cfg.core.mfc_debug ? 0 : 0xe0000000)), mmio, copy, m_md_unlikely);
m_ir->SetInsertPoint(mmio);
if (!must_use_cpp_functions)
{
const auto mmio = llvm::BasicBlock::Create(m_context, "", m_function);
m_ir->CreateCondBr(m_ir->CreateICmpUGE(eal.value, m_ir->getInt32(0xe0000000)), mmio, copy, m_md_unlikely);
m_ir->SetInsertPoint(mmio);
}
m_ir->CreateStore(ci, spu_ptr<u8>(&spu_thread::ch_mfc_cmd, &spu_mfc_cmd::cmd));
call("spu_exec_mfc_cmd", &exec_mfc_cmd, m_thread);
m_ir->CreateBr(next);
@@ -7383,12 +7460,13 @@ public:
set_vr(op.rt, fshl(a, zshuffle(a, 4, 0, 1, 2), b));
}
#if defined(ARCH_X64) || defined(ARCH_ARM64)
#if defined(ARCH_X64)
static __m128i exec_rotqby(__m128i a, u8 b)
{
alignas(32) const __m128i buf[2]{a, a};
return _mm_loadu_si128(reinterpret_cast<const __m128i*>(reinterpret_cast<const u8*>(buf) + (16 - (b & 0xf))));
}
#elif defined(ARCH_ARM64)
#else
#error "Unimplemented"
#endif
@@ -7398,6 +7476,7 @@ public:
const auto a = get_vr<u8[16]>(op.ra);
const auto b = get_vr<u8[16]>(op.rb);
#if defined(ARCH_X64)
if (!m_use_ssse3)
{
value_t<u8[16]> r;
@@ -7405,6 +7484,7 @@ public:
set_vr(op.rt, r);
return;
}
#endif
// Data with swapped endian from a load instruction
if (auto [ok, as] = match_expr(a, byteswap(match<u8[16]>())); ok)
@@ -8239,13 +8319,13 @@ public:
{
if (perm_only)
{
set_vr(op.rt4, vperm2b256to128(as, bs, c));
set_vr(op.rt4, vperm2b(as, bs, c));
return;
}
const auto m = gf2p8affineqb(c, build<u8[16]>(0x40, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x40, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20), 0x7f);
const auto mm = select(noncast<s8[16]>(m) >= 0, splat<u8[16]>(0), m);
const auto ab = vperm2b256to128(as, bs, c);
const auto ab = vperm2b(as, bs, c);
set_vr(op.rt4, select(noncast<s8[16]>(c) >= 0, ab, mm));
return;
}
@@ -8297,18 +8377,18 @@ public:
}
}
if (m_use_avx512_icl && (op.ra != op.rb))
if (m_use_avx512_icl && (op.ra != op.rb || m_interp_magn))
{
if (perm_only)
{
set_vr(op.rt4, vperm2b256to128(a, b, eval(c ^ 0xf)));
set_vr(op.rt4, vperm2b(a, b, eval(c ^ 0xf)));
return;
}
const auto m = gf2p8affineqb(c, build<u8[16]>(0x40, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x40, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20), 0x7f);
const auto mm = select(noncast<s8[16]>(m) >= 0, splat<u8[16]>(0), m);
const auto cr = eval(c ^ 0xf);
const auto ab = vperm2b256to128(a, b, cr);
const auto ab = vperm2b(a, b, cr);
set_vr(op.rt4, select(noncast<s8[16]>(c) >= 0, ab, mm));
return;
}
@@ -10749,7 +10829,7 @@ struct spu_llvm
for (auto it = enqueued.begin(), end = enqueued.end(); it != end; ++it)
{
const u64 cur = std::as_const(samples).at(it->first);
const u64 cur = ::at32(std::as_const(samples), it->first);
if (cur > sample_max)
{
File diff suppressed because it is too large Load Diff
+51 -125
View File
@@ -231,10 +231,9 @@ public:
// Turn off waiting bit manually (must succeed because waiting bit can only be resetted by the thread pushed to jostling_value)
ensure(this->data.bit_test_reset(off_wait));
data.notify_one();
}
data.notify_one();
// Return true if count has changed from 0 to 1, this condition is considered satisfied even if we pushed a value directly to the special storage for waiting SPUs
return !pushed_to_data || (old & bit_count) == 0;
}
@@ -298,102 +297,10 @@ public:
}
// Waiting for channel pop state availability, actually popping if specified
s64 pop_wait(cpu_thread& spu, bool pop = true)
{
u64 old = data.fetch_op([&](u64& data)
{
if (data & bit_count) [[likely]]
{
if (pop)
{
data = 0;
return true;
}
return false;
}
data = bit_wait;
jostling_value.release(bit_wait);
return true;
}).first;
if (old & bit_count)
{
return static_cast<u32>(old);
}
while (true)
{
thread_ctrl::wait_on(data, bit_wait);
old = data;
if (!(old & bit_wait))
{
return static_cast<u32>(jostling_value);
}
if (spu.is_stopped())
{
// Abort waiting and test if a value has been received
if (u64 v = jostling_value.exchange(0); !(v & bit_wait))
{
return static_cast<u32>(v);
}
ensure(data.bit_test_reset(off_wait));
return -1;
}
}
}
s64 pop_wait(cpu_thread& spu, bool pop = true);
// Waiting for channel push state availability, actually pushing if specified
bool push_wait(cpu_thread& spu, u32 value, bool push = true)
{
u64 state;
data.fetch_op([&](u64& data)
{
if (data & bit_count) [[unlikely]]
{
jostling_value.release(push ? value : static_cast<u32>(data));
data |= bit_wait;
}
else if (push)
{
data = bit_count | value;
}
else
{
state = data;
return false;
}
state = data;
return true;
});
while (true)
{
if (!(state & bit_wait))
{
if (!push)
{
data &= ~bit_count;
}
return true;
}
if (spu.is_stopped())
{
data &= ~bit_wait;
return false;
}
thread_ctrl::wait_on(data, state);
state = data;
}
}
bool push_wait(cpu_thread& spu, u32 value, bool push = true);
void set_value(u32 value, bool count = true)
{
@@ -424,45 +331,61 @@ struct spu_channel_4_t
};
atomic_t<sync_var_t> values;
atomic_t<u64> jostling_value;
atomic_t<u32> value3;
public:
static constexpr u32 off_wait = 32;
static constexpr u64 bit_wait = 1ull << off_wait;
void clear()
{
values.release({});
}
// push unconditionally (overwriting latest value), returns true if needs signaling
void push(cpu_thread& spu, u32 value)
void push(u32 value)
{
value3.release(value);
if (values.atomic_op([value](sync_var_t& data) -> bool
while (true)
{
switch (data.count++)
value3.release(value);
const auto [old, pushed_to_data] = values.fetch_op([&](sync_var_t& data)
{
case 0: data.value0 = value; break;
case 1: data.value1 = value; break;
case 2: data.value2 = value; break;
default:
{
data.count = 4;
data.value3_inval++; // Ensure the SPU reads the most recent value3 write in try_pop by re-loading
break;
}
}
if (data.waiting)
{
return false;
}
if (data.waiting)
{
data.waiting = 0;
switch (data.count++)
{
case 0: data.value0 = value; break;
case 1: data.value1 = value; break;
case 2: data.value2 = value; break;
default:
{
data.count = 4;
data.value3_inval++; // Ensure the SPU reads the most recent value3 write in try_pop by re-loading
break;
}
}
return true;
});
if (!pushed_to_data)
{
// Insert the pending value in special storage for waiting SPUs, leave no time in which the channel has data
if (!jostling_value.compare_and_swap_test(bit_wait, value))
{
// Other thread has inserted a value through jostling_value, retry
continue;
}
// Turn off waiting bit manually (must succeed because waiting bit can only be resetted by the thread pushing to jostling_value)
ensure(atomic_storage<u8>::exchange(values.raw().waiting, 0));
values.notify_one();
}
return false;
}))
{
spu.notify();
return;
}
}
@@ -483,15 +406,14 @@ public:
data.value1 = data.value2;
data.value2 = this->value3;
}
else
{
data.waiting = 1;
}
return result;
});
}
// Returns [previous count, value] (if aborted 0 count is returned)
std::pair<u32, u32> pop_wait(cpu_thread& spu);
// returns current queue size without modification
uint try_read(u32 (&out)[4]) const
{
@@ -891,7 +813,11 @@ public:
void fast_call(u32 ls_addr);
bool capture_local_storage() const;
std::array<std::shared_ptr<utils::serial>, 32> rewind_captures; // shared_ptr to avoid header inclusion
u8 current_rewind_capture_idx = 0;
bool capture_state();
bool try_load_debug_capture();
void wakeup_delay(u32 div = 1) const;
// Convert specified SPU LS address to a pointer of specified (possibly converted to BE) type
@@ -918,7 +844,7 @@ public:
return group ? SPU_FAKE_BASE_ADDR + SPU_LS_SIZE * (id & 0xffffff) : RAW_SPU_BASE_ADDR + RAW_SPU_OFFSET * index;
}
static u8* map_ls(utils::shm& shm);
static u8* map_ls(utils::shm& shm, void* ptr = nullptr);
// Returns true if reservation existed but was just discovered to be lost
// It is safe to use on any address, even if not directly accessed by SPU (so it's slower)
+85 -10
View File
@@ -13,6 +13,7 @@
#include "sys_cond.h"
#include "sys_event.h"
#include "sys_event_flag.h"
#include "sys_game.h"
#include "sys_interrupt.h"
#include "sys_memory.h"
#include "sys_mmapper.h"
@@ -50,9 +51,15 @@
#include <optional>
#include <deque>
#include "util/tsc.hpp"
extern std::string ppu_get_syscall_name(u64 code);
namespace rsx
{
void set_rsx_yield_flag() noexcept;
}
template <>
void fmt_class_string<ppu_syscall_code>::format(std::string& out, u64 arg)
{
@@ -413,11 +420,11 @@ const std::array<std::pair<ppu_intrp_func_t, std::string_view>, 1024> g_ppu_sysc
BIND_SYSC(sys_uart_send), //369 (0x171) ROOT
BIND_SYSC(sys_uart_get_params), //370 (0x172) ROOT
uns_func, //371 (0x173) UNS
NULL_FUNC(sys_game_watchdog_start), //372 (0x174)
NULL_FUNC(sys_game_watchdog_stop), //373 (0x175)
NULL_FUNC(sys_game_watchdog_clear), //374 (0x176)
BIND_SYSC(_sys_game_watchdog_start), //372 (0x174)
BIND_SYSC(_sys_game_watchdog_stop), //373 (0x175)
BIND_SYSC(_sys_game_watchdog_clear), //374 (0x176)
NULL_FUNC(sys_game_set_system_sw_version), //375 (0x177) ROOT
NULL_FUNC(sys_game_get_system_sw_version), //376 (0x178) ROOT
BIND_SYSC(_sys_game_get_system_sw_version), //376 (0x178) ROOT
NULL_FUNC(sys_sm_set_shop_mode), //377 (0x179) ROOT
BIND_SYSC(sys_sm_get_ext_event2), //378 (0x17A) ROOT
BIND_SYSC(sys_sm_shutdown), //379 (0x17B) ROOT
@@ -451,7 +458,7 @@ const std::array<std::pair<ppu_intrp_func_t, std::string_view>, 1024> g_ppu_sysc
null_func,//BIND_SYSC(sys_...), //407 (0x197) PM
NULL_FUNC(sys_sm_get_tzpb), //408 (0x198) PM
NULL_FUNC(sys_sm_get_fan_policy), //409 (0x199) PM
NULL_FUNC(sys_game_board_storage_read), //410 (0x19A)
BIND_SYSC(_sys_game_board_storage_read), //410 (0x19A)
NULL_FUNC(sys_game_board_storage_write), //411 (0x19B)
NULL_FUNC(sys_game_get_rtc_status), //412 (0x19C)
null_func,//BIND_SYSC(sys_...), //413 (0x19D) ROOT
@@ -781,9 +788,9 @@ const std::array<std::pair<ppu_intrp_func_t, std::string_view>, 1024> g_ppu_sysc
BIND_SYSC(sys_fs_symbolic_link), //833 (0x341)
BIND_SYSC(sys_fs_chmod), //834 (0x342)
BIND_SYSC(sys_fs_chown), //835 (0x343)
NULL_FUNC(sys_fs_newfs), //836 (0x344)
BIND_SYSC(sys_fs_newfs), //836 (0x344)
BIND_SYSC(sys_fs_mount), //837 (0x345)
NULL_FUNC(sys_fs_unmount), //838 (0x346)
BIND_SYSC(sys_fs_unmount), //838 (0x346)
NULL_FUNC(sys_fs_sync), //839 (0x347)
BIND_SYSC(sys_fs_disk_free), //840 (0x348)
BIND_SYSC(sys_fs_get_mount_info_size), //841 (0x349)
@@ -1201,6 +1208,11 @@ static std::deque<std::pair<u64, class cpu_thread*>> g_waiting;
// Threads which must call lv2_obj::sleep before the scheduler starts
static std::deque<class cpu_thread*> g_to_sleep;
static atomic_t<u64> s_yield_frequency = 0;
static atomic_t<u64> s_max_allowed_yield_tsc = 0;
static u64 s_last_yield_tsc = 0;
atomic_t<u32> g_lv2_preempts_taken = 0;
namespace cpu_counter
{
void remove(cpu_thread*) noexcept;
@@ -1332,7 +1344,7 @@ bool lv2_obj::sleep_unlocked(cpu_thread& thread, u64 timeout, u64 current_time)
val += cpu_flag::suspend;
// Flag used for forced timeout notification
ensure(!timeout || !(val & cpu_flag::notify));
ensure(!timeout || !(val & cpu_flag::notify));
return true;
}
@@ -1576,6 +1588,7 @@ void lv2_obj::cleanup()
g_to_sleep.clear();
g_waiting.clear();
g_pending = 0;
s_yield_frequency = 0;
}
void lv2_obj::schedule_all(u64 current_time)
@@ -1592,9 +1605,13 @@ void lv2_obj::schedule_all(u64 current_time)
if (target->state & cpu_flag::suspend)
{
ppu_log.trace("schedule(): %s", target->id);
target->state.atomic_op(FN(x += cpu_flag::signal, x -= cpu_flag::suspend));
target->start_time = 0;
if ((target->state.fetch_op(FN(x += cpu_flag::signal, x -= cpu_flag::suspend, void())) & (cpu_flag::wait + cpu_flag::signal)) != cpu_flag::wait)
{
continue;
}
if (notify_later_idx == std::size(g_to_notify))
{
// Out of notification slots, notify locally (resizable container is not worth it)
@@ -1647,11 +1664,56 @@ void lv2_obj::schedule_all(u64 current_time)
}
}
if (notify_later_idx - 1 < std::size(g_to_notify) - 1)
if (notify_later_idx - 1 < std::size(g_to_notify) - 1)
{
// Null-terminate the list if it ends before last slot
g_to_notify[notify_later_idx] = nullptr;
}
if (const u64 freq = s_yield_frequency)
{
const u64 tsc = utils::get_tsc();
const u64 last_tsc = s_last_yield_tsc;
if (tsc >= last_tsc && tsc <= s_max_allowed_yield_tsc && tsc - last_tsc >= freq)
{
auto target = +g_ppu;
cpu_thread* cpu = nullptr;
for (usz x = g_cfg.core.ppu_threads;; target = target->next_ppu, x--)
{
if (!target || !x)
{
if (g_ppu && cpu_flag::preempt - g_ppu->state)
{
// Don't be picky, pick up any running PPU thread even it has a wait flag
cpu = g_ppu;
}
// TODO: If this case is common enough it may be valuable to iterate over all CPU threads to find a perfect candidate (one without a wait or suspend flag)
else if (auto current = cpu_thread::get_current(); current && cpu_flag::suspend - current->state)
{
// May be an SPU or RSX thread, use them as a last resort
cpu = current;
}
break;
}
if (target->state.none_of(cpu_flag::preempt + cpu_flag::wait))
{
cpu = target;
break;
}
}
if (cpu && cpu_flag::preempt - cpu->state && !cpu->state.test_and_set(cpu_flag::preempt))
{
s_last_yield_tsc = tsc;
g_lv2_preempts_taken.release(g_lv2_preempts_taken.load() + 1); // Has a minor race but performance is more important
rsx::set_rsx_yield_flag();
}
}
}
}
ppu_thread_status lv2_obj::ppu_state(ppu_thread* ppu, bool lock_idm, bool lock_lv2)
@@ -1736,6 +1798,13 @@ bool lv2_obj::has_ppus_in_running_state()
return false;
}
void lv2_obj::set_yield_frequency(u64 freq, u64 max_allowed_tsc)
{
s_yield_frequency.release(freq);
s_max_allowed_yield_tsc.release(max_allowed_tsc);
g_lv2_preempts_taken.release(0);
}
bool lv2_obj::wait_timeout(u64 usec, ppu_thread* cpu, bool scale, bool is_usleep)
{
static_assert(u64{umax} / max_timeout >= 100, "max timeout is not valid for scaling");
@@ -1841,3 +1910,9 @@ bool lv2_obj::wait_timeout(u64 usec, ppu_thread* cpu, bool scale, bool is_usleep
return true;
}
void lv2_obj::prepare_for_sleep(cpu_thread& cpu)
{
vm::temporary_unlock(cpu);
cpu_counter::remove(&cpu);
}
+2 -1
View File
@@ -99,6 +99,7 @@ error_code sys_cond_create(ppu_thread& ppu, vm::ptr<u32> cond_id, u32 mutex_id,
return error;
}
ppu.check_state();
*cond_id = idm::last_id();
return CELL_OK;
}
@@ -451,7 +452,7 @@ error_code sys_cond_wait(ppu_thread& ppu, u32 cond_id, u64 timeout)
}
else
{
thread_ctrl::wait_on(ppu.state, state);
ppu.state.wait(state);
}
}
+11 -3
View File
@@ -220,6 +220,7 @@ error_code sys_event_queue_create(cpu_thread& cpu, vm::ptr<u32> equeue_id, vm::p
return error;
}
cpu.check_state();
*equeue_id = idm::last_id();
return CELL_OK;
}
@@ -381,7 +382,9 @@ error_code sys_event_queue_tryreceive(ppu_thread& ppu, u32 equeue_id, vm::ptr<sy
return CELL_EINVAL;
}
std::lock_guard lock(queue->mutex);
std::array<sys_event_t, 127> events;
std::unique_lock lock(queue->mutex);
if (!queue->exists)
{
@@ -392,13 +395,17 @@ error_code sys_event_queue_tryreceive(ppu_thread& ppu, u32 equeue_id, vm::ptr<sy
while (count < size && !queue->events.empty())
{
auto& dest = event_array[count++];
auto& dest = events[count++];
const auto event = queue->events.front();
queue->events.pop_front();
std::tie(dest.source, dest.data1, dest.data2, dest.data3) = event;
}
lock.unlock();
ppu.check_state();
std::copy_n(events.begin(), count, event_array.get_ptr());
*number = count;
return CELL_OK;
@@ -517,7 +524,7 @@ error_code sys_event_queue_receive(ppu_thread& ppu, u32 equeue_id, vm::ptr<sys_e
}
else
{
thread_ctrl::wait_on(ppu.state, state);
ppu.state.wait(state);
}
}
@@ -559,6 +566,7 @@ error_code sys_event_port_create(cpu_thread& cpu, vm::ptr<u32> eport_id, s32 por
if (const u32 id = idm::make<lv2_obj, lv2_event_port>(port_type, name))
{
cpu.check_state();
*eport_id = id;
return CELL_OK;
}
+26 -5
View File
@@ -77,6 +77,7 @@ error_code sys_event_flag_create(ppu_thread& ppu, vm::ptr<u32> id, vm::ptr<sys_e
return error;
}
ppu.check_state();
*id = idm::last_id();
return CELL_OK;
}
@@ -131,7 +132,11 @@ error_code sys_event_flag_wait(ppu_thread& ppu, u32 id, u64 bitptn, u32 mode, vm
~store_result() noexcept
{
if (ptr) *ptr = val;
if (ptr)
{
cpu_thread::get_current()->check_state();
*ptr = val;
}
}
} store{result};
@@ -249,7 +254,7 @@ error_code sys_event_flag_wait(ppu_thread& ppu, u32 id, u64 bitptn, u32 mode, vm
}
else
{
thread_ctrl::wait_on(ppu.state, state);
ppu.state.wait(state);
}
}
@@ -263,7 +268,21 @@ error_code sys_event_flag_trywait(ppu_thread& ppu, u32 id, u64 bitptn, u32 mode,
sys_event_flag.trace("sys_event_flag_trywait(id=0x%x, bitptn=0x%llx, mode=0x%x, result=*0x%x)", id, bitptn, mode, result);
if (result) *result = 0;
// Always set result
struct store_result
{
vm::ptr<u64> ptr;
u64 val = 0;
~store_result() noexcept
{
if (ptr)
{
cpu_thread::get_current()->check_state();
*ptr = val;
}
}
} store{result};
if (!lv2_event_flag::check_mode(mode))
{
@@ -271,7 +290,7 @@ error_code sys_event_flag_trywait(ppu_thread& ppu, u32 id, u64 bitptn, u32 mode,
return CELL_EINVAL;
}
u64 pattern;
u64 pattern{};
const auto flag = idm::check<lv2_obj, lv2_event_flag>(id, [&](lv2_event_flag& flag)
{
@@ -291,7 +310,7 @@ error_code sys_event_flag_trywait(ppu_thread& ppu, u32 id, u64 bitptn, u32 mode,
return not_an_error(CELL_EBUSY);
}
if (result) *result = pattern;
store.val = pattern;
return CELL_OK;
}
@@ -503,6 +522,8 @@ error_code sys_event_flag_get(ppu_thread& ppu, u32 id, vm::ptr<u64> flags)
return +flag.pattern;
});
ppu.check_state();
if (!flag)
{
if (flags) *flags = 0;
+265 -58
View File
@@ -10,6 +10,8 @@
#include "Emu/VFS.h"
#include "Emu/vfs_config.h"
#include "Emu/IdManager.h"
#include "Emu/system_utils.hpp"
#include "Emu/Cell/lv2/sys_process.h"
#include "Emu/RSX/Overlays/overlay_utils.h" // for ascii8_to_utf16
#include "Utilities/StrUtil.h"
@@ -20,15 +22,15 @@ LOG_CHANNEL(sys_fs);
lv2_fs_mount_point g_mp_sys_dev_root;
lv2_fs_mount_point g_mp_sys_no_device;
lv2_fs_mount_point g_mp_sys_dev_hdd0{"/dev_hdd0"};
lv2_fs_mount_point g_mp_sys_dev_hdd1{"/dev_hdd1", 512, 32768, lv2_mp_flag::no_uid_gid + lv2_mp_flag::cache};
lv2_fs_mount_point g_mp_sys_dev_usb{"", 512, 4096, lv2_mp_flag::no_uid_gid};
lv2_fs_mount_point g_mp_sys_dev_bdvd{"", 2048, 65536, lv2_mp_flag::read_only + lv2_mp_flag::no_uid_gid};
lv2_fs_mount_point g_mp_sys_dev_dvd{"", 2048, 32768, lv2_mp_flag::read_only + lv2_mp_flag::no_uid_gid};
lv2_fs_mount_point g_mp_sys_host_root{"", 512, 512, lv2_mp_flag::strict_get_block_size + lv2_mp_flag::no_uid_gid};
lv2_fs_mount_point g_mp_sys_dev_flash{"", 512, 8192, lv2_mp_flag::read_only + lv2_mp_flag::no_uid_gid};
lv2_fs_mount_point g_mp_sys_dev_flash2{ "", 512, 8192, lv2_mp_flag::no_uid_gid }; // TODO confirm
lv2_fs_mount_point g_mp_sys_dev_flash3{ "", 512, 8192, lv2_mp_flag::read_only + lv2_mp_flag::no_uid_gid }; // TODO confirm
lv2_fs_mount_point g_mp_sys_dev_hdd0{"/dev_hdd0", 512, 0x24FAEA98};
lv2_fs_mount_point g_mp_sys_dev_hdd1{"/dev_hdd1", 512, 0x3FFFF8, 32768, lv2_mp_flag::no_uid_gid + lv2_mp_flag::cache};
lv2_fs_mount_point g_mp_sys_dev_usb{"", 512, 0x100, 4096, lv2_mp_flag::no_uid_gid};
lv2_fs_mount_point g_mp_sys_dev_bdvd{"", 2048, 0x4D955, 65536, lv2_mp_flag::read_only + lv2_mp_flag::no_uid_gid};
lv2_fs_mount_point g_mp_sys_dev_dvd{"", 2048, 0x100, 32768, lv2_mp_flag::read_only + lv2_mp_flag::no_uid_gid};
lv2_fs_mount_point g_mp_sys_host_root{"", 512, 0x100, 512, lv2_mp_flag::strict_get_block_size + lv2_mp_flag::no_uid_gid};
lv2_fs_mount_point g_mp_sys_dev_flash{"", 512, 0x63E00, 8192, lv2_mp_flag::read_only + lv2_mp_flag::no_uid_gid};
lv2_fs_mount_point g_mp_sys_dev_flash2{"", 512, 0x8000, 8192, lv2_mp_flag::no_uid_gid}; // TODO confirm
lv2_fs_mount_point g_mp_sys_dev_flash3{"", 512, 0x400, 8192, lv2_mp_flag::read_only + lv2_mp_flag::no_uid_gid}; // TODO confirm
template<>
void fmt_class_string<lv2_file_type>::format(std::string& out, u64 arg)
@@ -119,7 +121,7 @@ bool verify_mself(const fs::file& mself_file)
return true;
}
lv2_fs_mount_point* lv2_fs_object::get_mp(std::string_view filename)
std::string_view lv2_fs_object::get_device_path(std::string_view filename)
{
std::string_view mp_name, vpath = filename;
@@ -131,7 +133,7 @@ lv2_fs_mount_point* lv2_fs_object::get_mp(std::string_view filename)
if (pos == 0)
{
// Relative path (TODO)
return &g_mp_sys_no_device;
return {};
}
if (pos == umax)
@@ -169,6 +171,13 @@ lv2_fs_mount_point* lv2_fs_object::get_mp(std::string_view filename)
}
}
return mp_name;
}
lv2_fs_mount_point* lv2_fs_object::get_mp(std::string_view filename)
{
const auto mp_name = get_device_path(filename);
if (!mp_name.empty())
{
if (mp_name == "dev_hdd0"sv)
@@ -200,6 +209,41 @@ lv2_fs_mount_point* lv2_fs_object::get_mp(std::string_view filename)
return &g_mp_sys_dev_root;
}
std::string lv2_fs_object::get_vfs(std::string_view filename)
{
const auto mp_name = get_device_path(filename);
if (!mp_name.empty())
{
if (mp_name == "dev_hdd0"sv)
return g_cfg_vfs.get(g_cfg_vfs.dev_hdd0, rpcs3::utils::get_emu_dir());
if (mp_name == "dev_hdd1"sv)
return g_cfg_vfs.get(g_cfg_vfs.dev_hdd1, rpcs3::utils::get_emu_dir());
if (mp_name.starts_with("dev_usb"sv))
return g_cfg_vfs.get_device(g_cfg_vfs.dev_usb, fmt::format("/%s", mp_name), rpcs3::utils::get_emu_dir()).path;
if (mp_name == "dev_bdvd"sv)
return g_cfg_vfs.get(g_cfg_vfs.dev_bdvd, rpcs3::utils::get_emu_dir());
if (mp_name == "dev_ps2disc"sv)
return {}; // Unsupported in VFS
if (mp_name == "app_home"sv && filename.data() != Emu.argv[0].data())
return lv2_fs_object::get_vfs(Emu.argv[0]);
if (mp_name == "host_root"sv)
return g_cfg.vfs.host_root ? "/" : std::string();
if (mp_name == "dev_flash"sv)
return g_cfg_vfs.get_dev_flash();
if (mp_name == "dev_flash2"sv)
return g_cfg_vfs.get_dev_flash2();
if (mp_name == "dev_flash3"sv)
return g_cfg_vfs.get_dev_flash3();
// Default
return g_cfg_vfs.get(g_cfg_vfs.dev_hdd0, rpcs3::utils::get_emu_dir());
}
// Default fallback
return {};
}
lv2_fs_object::lv2_fs_object(utils::serial& ar, bool)
: name(ar)
, mp(get_mp(name.data()))
@@ -480,7 +524,7 @@ fs::file lv2_file::make_view(const std::shared_ptr<lv2_file>& _file, u64 offset)
return result;
}
std::pair<CellError, std::string_view> translate_to_sv(vm::cptr<char> ptr)
std::pair<CellError, std::string_view> translate_to_sv(vm::cptr<char> ptr, bool is_path = true)
{
const u32 addr = ptr.addr();
@@ -509,7 +553,7 @@ std::pair<CellError, std::string_view> translate_to_sv(vm::cptr<char> ptr)
return {CELL_EFAULT, path};
}
if (!path.starts_with("/"sv))
if (is_path && !path.starts_with("/"sv))
{
return {CELL_ENOENT, path};
}
@@ -785,7 +829,7 @@ lv2_file::open_result_t lv2_file::open(std::string_view vpath, s32 flags, s32 mo
if (size == 8)
{
// see lv2_file::open_raw
switch (*static_cast<const be_t<u64>*>(arg))
switch (*static_cast<const be_t<u64, 1>*>(arg))
{
case 0x18000000010: type = lv2_file_type::sdata; break;
case 0x2: type = lv2_file_type::edata; break;
@@ -839,6 +883,7 @@ error_code sys_fs_open(ppu_thread& ppu, vm::cptr<char> path, s32 flags, vm::ptr<
return result;
}))
{
ppu.check_state();
*fd = id;
return CELL_OK;
}
@@ -882,11 +927,12 @@ error_code sys_fs_read(ppu_thread& ppu, u32 fd, vm::ptr<void> buf, u64 nbytes, v
return CELL_EBUSY;
}
ppu.check_state();
*nread = 0;
return CELL_OK;
}
std::lock_guard lock(file->mp->mutex);
std::unique_lock lock(file->mp->mutex);
if (!file->file)
{
@@ -900,10 +946,13 @@ error_code sys_fs_read(ppu_thread& ppu, u32 fd, vm::ptr<void> buf, u64 nbytes, v
}
const u64 read_bytes = file->op_read(buf, nbytes);
const bool failure = !read_bytes && file->file.pos() < file->file.size();
lock.unlock();
ppu.check_state();
*nread = read_bytes;
if (!read_bytes && file->file.pos() < file->file.size())
if (failure)
{
// EDATA corruption perhaps
return CELL_EFSSPECIFIC;
@@ -947,6 +996,7 @@ error_code sys_fs_write(ppu_thread& ppu, u32 fd, vm::cptr<void> buf, u64 nbytes,
return CELL_EBUSY;
}
ppu.check_state();
*nwrite = 0;
return CELL_OK;
}
@@ -962,7 +1012,7 @@ error_code sys_fs_write(ppu_thread& ppu, u32 fd, vm::cptr<void> buf, u64 nbytes,
return CELL_EROFS;
}
std::lock_guard lock(file->mp->mutex);
std::unique_lock lock(file->mp->mutex);
if (!file->file)
{
@@ -986,8 +1036,11 @@ error_code sys_fs_write(ppu_thread& ppu, u32 fd, vm::cptr<void> buf, u64 nbytes,
file->file.seek(0, fs::seek_end);
}
*nwrite = file->op_write(buf, nbytes);
const u64 written = file->op_write(buf, nbytes);
lock.unlock();
ppu.check_state();
*nwrite = written;
return CELL_OK;
}
@@ -1102,7 +1155,7 @@ error_code sys_fs_opendir(ppu_thread& ppu, vm::cptr<char> path, vm::ptr<u32> fd)
return {CELL_ENOTDIR, path};
}
std::lock_guard lock(mp->mutex);
std::unique_lock lock(mp->mutex);
const fs::dir dir(local_path);
@@ -1156,7 +1209,7 @@ error_code sys_fs_opendir(ppu_thread& ppu, vm::cptr<char> path, vm::ptr<u32> fd)
}
else
{
data.emplace_back().name = ".";
data.emplace_back().name += '.';
data.back().is_directory = true;
data.emplace_back().name = "..";
data.back().is_directory = true;
@@ -1177,6 +1230,9 @@ error_code sys_fs_opendir(ppu_thread& ppu, vm::cptr<char> path, vm::ptr<u32> fd)
if (const u32 id = idm::make<lv2_fs_object, lv2_dir>(processed_path, std::move(data)))
{
lock.unlock();
ppu.check_state();
*fd = id;
return CELL_OK;
}
@@ -1199,6 +1255,8 @@ error_code sys_fs_readdir(ppu_thread& ppu, u32 fd, vm::ptr<CellFsDirent> dir, vm
return CELL_EBADF;
}
ppu.check_state();
if (auto* info = directory->dir_read())
{
dir->d_type = info->is_directory ? CELL_FS_TYPE_DIRECTORY : CELL_FS_TYPE_REGULAR;
@@ -1265,7 +1323,7 @@ error_code sys_fs_stat(ppu_thread& ppu, vm::cptr<char> path, vm::ptr<CellFsStat>
return {CELL_ENOTMOUNTED, path};
}
std::lock_guard lock(mp->mutex);
std::unique_lock lock(mp->mutex);
fs::stat_t info{};
@@ -1308,7 +1366,18 @@ error_code sys_fs_stat(ppu_thread& ppu, vm::cptr<char> path, vm::ptr<CellFsStat>
}
}
sb->mode = info.is_directory ? CELL_FS_S_IFDIR | 0777 : CELL_FS_S_IFREG | 0666;
lock.unlock();
ppu.check_state();
s32 mode = info.is_directory ? CELL_FS_S_IFDIR | 0777 : CELL_FS_S_IFREG | 0666;
if (mp->flags & lv2_mp_flag::read_only)
{
// Remove write permissions
mode &= ~0222;
}
sb->mode = mode;
sb->uid = mp->flags & lv2_mp_flag::no_uid_gid ? -1 : 0;
sb->gid = mp->flags & lv2_mp_flag::no_uid_gid ? -1 : 0;
sb->atime = info.atime;
@@ -1317,12 +1386,6 @@ error_code sys_fs_stat(ppu_thread& ppu, vm::cptr<char> path, vm::ptr<CellFsStat>
sb->size = info.is_directory ? mp->block_size : info.size;
sb->blksize = mp->block_size;
if (mp->flags & lv2_mp_flag::read_only)
{
// Remove write permissions
sb->mode &= ~0222;
}
return CELL_OK;
}
@@ -1340,7 +1403,7 @@ error_code sys_fs_fstat(ppu_thread& ppu, u32 fd, vm::ptr<CellFsStat> sb)
return CELL_EBADF;
}
std::lock_guard lock(file->mp->mutex);
std::unique_lock lock(file->mp->mutex);
if (!file->file)
{
@@ -1352,9 +1415,19 @@ error_code sys_fs_fstat(ppu_thread& ppu, u32 fd, vm::ptr<CellFsStat> sb)
return CELL_EIO;
}
const fs::stat_t& info = file->file.stat();
const fs::stat_t info = file->file.stat();
lock.unlock();
ppu.check_state();
sb->mode = info.is_directory ? CELL_FS_S_IFDIR | 0777 : CELL_FS_S_IFREG | 0666;
s32 mode = info.is_directory ? CELL_FS_S_IFDIR | 0777 : CELL_FS_S_IFREG | 0666;
if (file->mp->flags & lv2_mp_flag::read_only)
{
// Remove write permissions
mode &= ~0222;
}
sb->mode = mode;
sb->uid = file->mp->flags & lv2_mp_flag::no_uid_gid ? -1 : 0;
sb->gid = file->mp->flags & lv2_mp_flag::no_uid_gid ? -1 : 0;
sb->atime = info.atime;
@@ -1362,13 +1435,6 @@ error_code sys_fs_fstat(ppu_thread& ppu, u32 fd, vm::ptr<CellFsStat> sb)
sb->ctime = info.ctime; // ctime may be incorrect
sb->size = info.size;
sb->blksize = file->mp->block_size;
if (file->mp->flags & lv2_mp_flag::read_only)
{
// Remove write permissions
sb->mode &= ~0222;
}
return CELL_OK;
}
@@ -2180,18 +2246,28 @@ error_code sys_fs_fcntl(ppu_thread& ppu, u32 fd, u32 op, vm::ptr<void> _arg, u32
return CELL_EBADF;
}
arg->_size = 0; // This write is not really useful for cellFs but do it anyways
ppu.check_state();
u32 read_count = 0;
// NOTE: This function is actually capable of reading only one entry at a time
if (arg->max)
if (const u32 max = arg->max)
{
std::memset(arg->ptr.get_ptr(), 0, arg->max * arg->ptr.size());
const auto arg_ptr = +arg->ptr;
if (auto* info = directory->dir_read())
{
auto& entry = arg->ptr[arg->_size++];
auto& entry = arg_ptr[read_count++];
entry.attribute.mode = info->is_directory ? CELL_FS_S_IFDIR | 0777 : CELL_FS_S_IFREG | 0666;
s32 mode = info->is_directory ? CELL_FS_S_IFDIR | 0777 : CELL_FS_S_IFREG | 0666;
if (directory->mp->flags & lv2_mp_flag::read_only)
{
// Remove write permissions
mode &= ~0222;
}
entry.attribute.mode = mode;
entry.attribute.uid = directory->mp->flags & lv2_mp_flag::no_uid_gid ? -1 : 0;
entry.attribute.gid = directory->mp->flags & lv2_mp_flag::no_uid_gid ? -1 : 0;
entry.attribute.atime = info->atime;
@@ -2200,18 +2276,16 @@ error_code sys_fs_fcntl(ppu_thread& ppu, u32 fd, u32 op, vm::ptr<void> _arg, u32
entry.attribute.size = info->size;
entry.attribute.blksize = directory->mp->block_size;
if (directory->mp->flags & lv2_mp_flag::read_only)
{
// Remove write permissions
entry.attribute.mode &= ~0222;
}
entry.entry_name.d_type = info->is_directory ? CELL_FS_TYPE_DIRECTORY : CELL_FS_TYPE_REGULAR;
entry.entry_name.d_namlen = u8(std::min<usz>(info->name.size(), CELL_FS_MAX_FS_FILE_NAME_LENGTH));
strcpy_trunc(entry.entry_name.d_name, info->name);
}
// Apparently all this function does to additional buffer elements is to zeroize them
std::memset(arg_ptr.get_ptr() + read_count, 0, (max - read_count) * arg->ptr.size());
}
arg->_size = read_count;
arg->_code = CELL_OK;
return CELL_OK;
}
@@ -2342,7 +2416,7 @@ error_code sys_fs_lseek(ppu_thread& ppu, u32 fd, s64 offset, s32 whence, vm::ptr
return CELL_EBADF;
}
std::lock_guard lock(file->mp->mutex);
std::unique_lock lock(file->mp->mutex);
if (!file->file)
{
@@ -2367,6 +2441,9 @@ error_code sys_fs_lseek(ppu_thread& ppu, u32 fd, s64 offset, s32 whence, vm::ptr
return CELL_EIO; // ???
}
lock.unlock();
ppu.check_state();
*pos = result;
return CELL_OK;
}
@@ -2665,24 +2742,31 @@ error_code sys_fs_disk_free(ppu_thread& ppu, vm::cptr<char> path, vm::ptr<u64> t
if (mp->flags & lv2_mp_flag::read_only)
{
// TODO: check /dev_bdvd
ppu.check_state();
*total_free = 0;
*avail_free = 0;
return CELL_OK;
}
u64 available = 0;
// avail_free is the only value used by cellFsGetFreeSize
if (mp == &g_mp_sys_dev_hdd1)
{
*avail_free = (1u << 31) - mp->sector_size; // 2GB (TODO: Should be the total size)
available = (1u << 31) - mp->sector_size; // 2GB (TODO: Should be the total size)
}
else //if (mp == &g_mp_sys_dev_hdd0)
{
*avail_free = (40ull * 1024 * 1024 * 1024 - mp->sector_size); // Read explanation in cellHddGameCheck
available = (40ull * 1024 * 1024 * 1024 - mp->sector_size); // Read explanation in cellHddGameCheck
}
// HACK: Hopefully nothing uses this value or once at max because its hacked here:
// The total size can change based on the size of the directory
*total_free = *avail_free + fs::get_dir_size(local_path, mp->sector_size);
const u64 total = available + fs::get_dir_size(local_path, mp->sector_size);
ppu.check_state();
*total_free = total;
*avail_free = available;
return CELL_OK;
}
@@ -2855,7 +2939,7 @@ error_code sys_fs_get_mount_info_size(ppu_thread&, vm::ptr<u64> len)
return CELL_EFAULT;
}
*len = 0x8;
*len = 0x9;
return CELL_OK;
}
@@ -2875,7 +2959,7 @@ error_code sys_fs_get_mount_info(ppu_thread&, vm::ptr<CellFsMountInfo> info, u32
sys_fs.todo("sys_fs_get_mount_info special case TODO");
}
const u32 max_len = std::min<u32>(len, 8);
const u32 max_len = std::min<u32>(len, 9);
*out_len = max_len;
struct mount_info
@@ -2884,7 +2968,7 @@ error_code sys_fs_get_mount_info(ppu_thread&, vm::ptr<CellFsMountInfo> info, u32
be_t<u32> unk1 = 0, unk2 = 0, unk3 = 0, unk4 = 0, unk5 = 0;
};
static constexpr std::array<mount_info, 8> data
static constexpr std::array<mount_info, 9> data
{
mount_info{.path = "/", .filesystem = "CELL_FS_ADMINFS", .dev_name = "CELL_FS_ADMINFS:", .unk5 = 0x10000000},
mount_info{.path = "/app_home", .filesystem = "CELL_FS_DUMMY", .dev_name = "CELL_FS_DUMMY:"},
@@ -2893,6 +2977,7 @@ error_code sys_fs_get_mount_info(ppu_thread&, vm::ptr<CellFsMountInfo> info, u32
mount_info{.path = "/dev_flash2", .filesystem = "CELL_FS_FAT", .dev_name = "CELL_FS_IOS:BUILTIN_FLSH2:"},
mount_info{.path = "/dev_flash3", .filesystem = "CELL_FS_FAT", .dev_name = "CELL_FS_IOS:BUILTIN_FLSH3:"},
mount_info{.path = "/dev_hdd0", .filesystem = "CELL_FS_UFS", .dev_name = "CELL_FS_UTILITY:HDD0:"},
mount_info{.path = "/dev_hdd1", .filesystem = "CELL_FS_FAT", .dev_name = "CELL_FS_UTILITY:HDD1:"},
mount_info{.path = "/dev_bdvd", .filesystem = "CELL_FS_ISO9660", .dev_name = "CELL_FS_IOS:PATA0_BDVD_DRIVE"},
};
@@ -2907,9 +2992,131 @@ error_code sys_fs_get_mount_info(ppu_thread&, vm::ptr<CellFsMountInfo> info, u32
return CELL_OK;
}
error_code sys_fs_mount(ppu_thread&, vm::cptr<char> dev_name, vm::cptr<char> file_system, vm::cptr<char> path, s32 unk1, s32 prot, s32 unk3, vm::cptr<char> str1, u32 str_len)
error_code sys_fs_newfs(ppu_thread& ppu, vm::cptr<char> dev_name, vm::cptr<char> file_system, s32 unk1, vm::cptr<char> str1)
{
sys_fs.todo("sys_fs_mount(dev_name=%s, file_system=%s, path=%s, unk1=0x%x, prot=0x%x, unk3=0x%x, str1=%s, str_len=%d)", dev_name, file_system, path, unk1, prot, unk3, str1, str_len);
sys_fs.todo("sys_fs_newfs(dev_name=%s, file_system=%s, unk1=0x%x, str1=%s)", dev_name, file_system, unk1, str1);
if (!g_ps3_process_info.has_root_perm())
{
return CELL_ENOSYS;
}
return CELL_OK;
}
error_code sys_fs_mount(ppu_thread&, vm::cptr<char> dev_name, vm::cptr<char> file_system, vm::cptr<char> path, s32 unk1, s32 prot, s32 unk3, vm::cptr<char> str1, u32 str_len)
{
sys_fs.warning("sys_fs_mount(dev_name=%s, file_system=%s, path=%s, unk1=0x%x, prot=0x%x, unk3=0x%x, str1=%s, str_len=%d)", dev_name, file_system, path, unk1, prot, unk3, str1, str_len);
if (!g_ps3_process_info.has_root_perm())
{
return CELL_ENOSYS;
}
const auto [path_error, vpath] = translate_to_sv(path);
if (path_error)
{
return { path_error, vpath };
}
const auto [fs_error, filesystem] = translate_to_sv(file_system, false);
if (fs_error)
{
return { fs_error, filesystem };
}
const auto mp = lv2_fs_object::get_mp(vpath);
bool success = true;
auto vfs_mount = [&vpath = vpath, &filesystem = filesystem, &mp = mp](std::string mount_path)
{
if (!mount_path.ends_with('/'))
mount_path += '/';
if (!fs::is_dir(mount_path) && !fs::create_dir(mount_path))
{
sys_fs.error("Failed to create directory \"%s\"", mount_path);
return false;
}
const bool is_simplefs = filesystem == "CELL_FS_SIMPLEFS";
if (is_simplefs)
{
mount_path += "loop.tmp";
fs::file loop_file;
if (loop_file.open(mount_path, fs::create + fs::read + fs::write + fs::trunc + fs::lock))
{
const u64 file_size = mp->sector_size * mp->sector_count;
loop_file.trunc(file_size);
sys_fs.notice("Created a loop file of size 0x%x at \"%s\"", file_size, mount_path);
}
else
{
sys_fs.error("Failed to create loop file \"%s\"", mount_path);
return false;
}
}
return vfs::mount(vpath, mount_path, !is_simplefs);
};
if (mp == &g_mp_sys_dev_hdd1)
{
const std::string_view appname = g_ps3_process_info.get_cellos_appname();
success = vfs_mount(fmt::format("%s/caches/%s", lv2_fs_object::get_vfs(vpath), appname.substr(0, appname.find_last_of('.'))));
}
else
{
//success = vfs_mount(lv2_fs_object::get_vfs(vpath)); // We are not supporting mounting devices other than /dev_hdd1 via this syscall currently
}
if (!success)
return CELL_EIO;
return CELL_OK;
}
error_code sys_fs_unmount(ppu_thread&, vm::cptr<char> path, s32 unk1, s32 unk2)
{
sys_fs.warning("sys_fs_unmount(path=%s, unk1=0x%x, unk2=0x%x)", path, unk1, unk2);
if (!g_ps3_process_info.has_root_perm())
{
return CELL_ENOSYS;
}
const auto [path_error, vpath] = translate_to_sv(path);
if (path_error)
{
return { path_error, vpath };
}
const auto mp = lv2_fs_object::get_mp(vpath);
bool success = true;
auto vfs_unmount = [&vpath = vpath]()
{
const std::string local_path = vfs::get(vpath);
if (fs::is_file(local_path))
{
if (fs::remove_file(local_path))
{
sys_fs.notice("Removed loop file \"%s\"", local_path);
}
else
{
sys_fs.error("Failed to remove loop file \"%s\"", local_path);
return false;
}
}
return vfs::unmount(vpath);
};
if (mp == &g_mp_sys_dev_hdd1) // We are not supporting unmounting devices other than /dev_hdd1 via this syscall currently
success = vfs_unmount();
if (!success)
return CELL_EIO;
return CELL_OK;
}
+9 -3
View File
@@ -149,6 +149,7 @@ struct lv2_fs_mount_point
{
const std::string_view root;
const u32 sector_size = 512;
const u64 sector_count = 256;
const u32 block_size = 4096;
const bs_t<lv2_mp_flag> flags{};
@@ -160,9 +161,10 @@ extern lv2_fs_mount_point g_mp_sys_dev_hdd1;
struct lv2_fs_object
{
static const u32 id_base = 3;
static const u32 id_step = 1;
static const u32 id_count = 255 - id_base;
static constexpr u32 id_base = 3;
static constexpr u32 id_step = 1;
static constexpr u32 id_count = 255 - id_base;
static constexpr bool id_lowest = true;
SAVESTATE_INIT_POS(40);
// File Name (max 1055)
@@ -185,7 +187,9 @@ public:
lv2_fs_object& operator=(const lv2_fs_object&) = delete;
static std::string_view get_device_path(std::string_view filename);
static lv2_fs_mount_point* get_mp(std::string_view filename);
static std::string get_vfs(std::string_view filename);
static std::array<char, 0x420> get_name(std::string_view filename)
{
@@ -613,6 +617,8 @@ error_code sys_fs_lsn_write(ppu_thread& ppu, u32 fd, vm::cptr<void>, u64);
error_code sys_fs_mapped_allocate(ppu_thread& ppu, u32 fd, u64, vm::pptr<void> out_ptr);
error_code sys_fs_mapped_free(ppu_thread& ppu, u32 fd, vm::ptr<void> ptr);
error_code sys_fs_truncate2(ppu_thread& ppu, u32 fd, u64 size);
error_code sys_fs_newfs(ppu_thread& ppu, vm::cptr<char> dev_name, vm::cptr<char> file_system, s32 unk1, vm::cptr<char> str1);
error_code sys_fs_mount(ppu_thread& ppu, vm::cptr<char> dev_name, vm::cptr<char> file_system, vm::cptr<char> path, s32 unk1, s32 prot, s32 unk3, vm::cptr<char> str1, u32 str_len);
error_code sys_fs_unmount(ppu_thread&, vm::cptr<char> path, s32 unk1, s32 unk2);
error_code sys_fs_get_mount_info_size(ppu_thread& ppu, vm::ptr<u64> len);
error_code sys_fs_get_mount_info(ppu_thread& ppu, vm::ptr<CellFsMountInfo> info, u32 len, vm::ptr<u64> out_len);
+179
View File
@@ -0,0 +1,179 @@
#include "stdafx.h"
#include "util/sysinfo.hpp"
#include "Emu/Memory/vm_ptr.h"
#include "Emu/Cell/ErrorCodes.h"
#include "Emu/System.h"
#include "Emu/system_config.h"
#include "Emu/IdManager.h"
#include "Utilities/Thread.h"
#include "sys_game.h"
LOG_CHANNEL(sys_game);
struct watchdog_t
{
struct alignas(8) control_t
{
bool needs_restart = false;
bool active = false;
char pad[sizeof(u32) - sizeof(bool) * 2]{};
u32 timeout = 0;
};
atomic_t<control_t> control;
void operator()()
{
u64 start_time = get_system_time();
u64 old_time = start_time;
u64 current_time = old_time;
constexpr u64 sleep_time = 50'000;
while (thread_ctrl::state() != thread_state::aborting)
{
if (Emu.GetStatus(false) == system_state::paused)
{
start_time += current_time - old_time;
old_time = current_time;
thread_ctrl::wait_for(sleep_time);
current_time = get_system_time();
continue;
}
old_time = std::exchange(current_time, get_system_time());
const auto old = control.fetch_op([&](control_t& data)
{
if (data.needs_restart)
{
data.needs_restart = false;
return true;
}
return false;
}).first;
if (old.active && old.needs_restart)
{
start_time = current_time;
old_time = current_time;
continue;
}
if (old.active && current_time - start_time >= old.timeout)
{
sys_game.success("Watchdog timeout! Restarting the game...");
Emu.CallFromMainThread([]()
{
Emu.Restart();
});
return;
}
thread_ctrl::wait_for(sleep_time);
}
}
static constexpr auto thread_name = "LV2 Watchdog Thread"sv;
};
error_code _sys_game_watchdog_start(u32 timeout)
{
sys_game.trace("sys_game_watchdog_start(timeout=%d)", timeout);
// According to disassembly
timeout *= 1'000'000;
timeout &= -64;
if (!g_fxo->get<named_thread<watchdog_t>>().control.fetch_op([&](watchdog_t::control_t& data)
{
if (data.active)
{
return false;
}
data.needs_restart = true;
data.active = true;
data.timeout = timeout;
return true;
}).second)
{
return CELL_EABORT;
}
return CELL_OK;
}
error_code _sys_game_watchdog_stop()
{
sys_game.trace("sys_game_watchdog_stop()");
g_fxo->get<named_thread<watchdog_t>>().control.fetch_op([](watchdog_t::control_t& data)
{
if (!data.active)
{
return false;
}
data.active = false;
return true;
});
return CELL_OK;
}
error_code _sys_game_watchdog_clear()
{
sys_game.trace("sys_game_watchdog_clear()");
g_fxo->get<named_thread<watchdog_t>>().control.fetch_op([](watchdog_t::control_t& data)
{
if (!data.active || data.needs_restart)
{
return false;
}
data.needs_restart = true;
return true;
});
return CELL_OK;
}
u64 _sys_game_get_system_sw_version()
{
return stof(utils::get_firmware_version()) * 10000;
}
error_code _sys_game_board_storage_read(vm::ptr<u8> buffer1, vm::ptr<u8> buffer2)
{
sys_game.trace("sys_game_board_storage_read(buffer1=*0x%x, buffer2=*0x%x)", buffer1, buffer2);
if (!buffer1)
{
return CELL_EFAULT;
}
be_t<u64> psid[2] = { +g_cfg.sys.console_psid_high, +g_cfg.sys.console_psid_low };
u8* psid_bytes = reinterpret_cast<u8*>(psid);
u8 response[16] = { 0x01, 0xFC, 0x43, 0x50, 0xA7, 0x9B, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
for (int i = 0; i < 16; i++)
{
response[i] ^= psid_bytes[i];
}
memcpy(buffer1.get_ptr(), response, 16);
if (!buffer2)
{
return CELL_EFAULT;
}
*buffer2 = 0x00;
return CELL_OK;
}
+7
View File
@@ -0,0 +1,7 @@
#pragma once
error_code _sys_game_watchdog_start(u32 timeout);
error_code _sys_game_watchdog_stop();
error_code _sys_game_watchdog_clear();
u64 _sys_game_get_system_sw_version();
error_code _sys_game_board_storage_read(vm::ptr<u8> buffer1, vm::ptr<u8> buffer2);
+1
View File
@@ -190,6 +190,7 @@ error_code _sys_interrupt_thread_establish(ppu_thread& ppu, vm::ptr<u32> ih, u32
if (id)
{
ppu.check_state();
*ih = id;
return CELL_OK;
}
+2 -1
View File
@@ -50,6 +50,7 @@ error_code _sys_lwcond_create(ppu_thread& ppu, vm::ptr<u32> lwcond_id, u32 lwmut
if (const u32 id = idm::make<lv2_obj, lv2_lwcond>(name, lwmutex_id, protocol, control))
{
ppu.check_state();
*lwcond_id = id;
return CELL_OK;
}
@@ -486,7 +487,7 @@ error_code _sys_lwcond_queue_wait(ppu_thread& ppu, u32 lwcond_id, u32 lwmutex_id
}
else
{
thread_ctrl::wait_on(ppu.state, state);
ppu.state.wait(state);
}
}
+2 -1
View File
@@ -42,6 +42,7 @@ error_code _sys_lwmutex_create(ppu_thread& ppu, vm::ptr<u32> lwmutex_id, u32 pro
if (const u32 id = idm::make<lv2_obj, lv2_lwmutex>(protocol, control, name))
{
ppu.check_state();
*lwmutex_id = id;
return CELL_OK;
}
@@ -246,7 +247,7 @@ error_code _sys_lwmutex_lock(ppu_thread& ppu, u32 lwmutex_id, u64 timeout)
}
else
{
thread_ctrl::wait_on(ppu.state, state);
ppu.state.wait(state);
}
}
+18 -9
View File
@@ -132,6 +132,7 @@ error_code sys_memory_allocate(cpu_thread& cpu, u32 size, u64 flags, vm::ptr<u32
if (alloc_addr)
{
vm::lock_sudo(addr, size);
cpu.check_state();
*alloc_addr = addr;
return CELL_OK;
}
@@ -203,6 +204,7 @@ error_code sys_memory_allocate_from_container(cpu_thread& cpu, u32 size, u32 cid
if (alloc_addr)
{
vm::lock_sudo(addr, size);
cpu.check_state();
*alloc_addr = addr;
return CELL_OK;
}
@@ -282,17 +284,22 @@ error_code sys_memory_get_user_memory_size(cpu_thread& cpu, vm::ptr<sys_memory_i
// Get "default" memory container
auto& dct = g_fxo->get<lv2_memory_container>();
::reader_lock lock(s_memstats_mtx);
mem_info->total_user_memory = dct.size;
mem_info->available_user_memory = dct.size - dct.used;
// Scan other memory containers
idm::select<lv2_memory_container>([&](u32, lv2_memory_container& ct)
sys_memory_info_t out{};
{
mem_info->total_user_memory -= ct.size;
});
::reader_lock lock(s_memstats_mtx);
out.total_user_memory = dct.size;
out.available_user_memory = dct.size - dct.used;
// Scan other memory containers
idm::select<lv2_memory_container>([&](u32, lv2_memory_container& ct)
{
out.total_user_memory -= ct.size;
});
}
cpu.check_state();
*mem_info = out;
return CELL_OK;
}
@@ -332,6 +339,7 @@ error_code sys_memory_container_create(cpu_thread& cpu, vm::ptr<u32> cid, u32 si
// Create the memory container
if (const u32 id = idm::make<lv2_memory_container>(size, true))
{
cpu.check_state();
*cid = id;
return CELL_OK;
}
@@ -388,6 +396,7 @@ error_code sys_memory_container_get_size(cpu_thread& cpu, vm::ptr<sys_memory_inf
return CELL_ESRCH;
}
cpu.check_state();
mem_info->total_user_memory = ct->size; // Total container memory
mem_info->available_user_memory = ct->size - ct->used; // Available container memory
+8
View File
@@ -174,6 +174,7 @@ error_code sys_mmapper_allocate_address(ppu_thread& ppu, u64 size, u64 flags, u6
{
if (const auto area = vm::find_map(static_cast<u32>(size), static_cast<u32>(alignment), flags & SYS_MEMORY_PAGE_SIZE_MASK))
{
ppu.check_state();
*alloc_addr = area->addr;
return CELL_OK;
}
@@ -246,6 +247,7 @@ error_code sys_mmapper_allocate_shared_memory(ppu_thread& ppu, u64 ipc_key, u64
return error;
}
ppu.check_state();
*mem_id = idm::last_id();
return CELL_OK;
}
@@ -301,6 +303,7 @@ error_code sys_mmapper_allocate_shared_memory_from_container(ppu_thread& ppu, u6
return error;
}
ppu.check_state();
*mem_id = idm::last_id();
return CELL_OK;
}
@@ -399,6 +402,7 @@ error_code sys_mmapper_allocate_shared_memory_ext(ppu_thread& ppu, u64 ipc_key,
return error;
}
ppu.check_state();
*mem_id = idm::last_id();
return CELL_OK;
}
@@ -496,6 +500,7 @@ error_code sys_mmapper_allocate_shared_memory_from_container_ext(ppu_thread& ppu
return error;
}
ppu.check_state();
*mem_id = idm::last_id();
return CELL_OK;
}
@@ -718,6 +723,8 @@ error_code sys_mmapper_search_and_map(ppu_thread& ppu, u32 start_addr, u32 mem_i
}
vm::lock_sudo(addr, mem->size);
ppu.check_state();
*alloc_addr = addr;
return CELL_OK;
}
@@ -763,6 +770,7 @@ error_code sys_mmapper_unmap_shared_memory(ppu_thread& ppu, u32 addr, vm::ptr<u3
}
// Write out the ID
ppu.check_state();
*mem_id = mem.ret;
// Acknowledge

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