Compare commits

...

232 Commits

Author SHA1 Message Date
Ani c16e176fbe rpcs3_version: Bump to 0.0.32 2024-05-01 17:01:10 +02:00
Florin9doi 55fccf03fa USB: Update GameTablet 2024-05-01 09:52:30 +02:00
Florin9doi d3f9ae4868 USB: GunCon 3 emulation 2024-05-01 09:52:30 +02:00
Florin9doi debeafa36b USB: Update GameTablet
- Allows to use rawinput handler
- Use a struct to access the input data
2024-05-01 09:52:30 +02:00
Ani 39e946630d syscall: Register syscall 149 sys_time_get_system_time 2024-04-29 10:25:21 -07:00
RipleyTom 8d815e8ee0 Clamp spu_fi results 2024-04-29 05:21:49 +03:00
Elad Ashkenazi 430b57833d SPU LLVM: Remove wrong zero sign fixup 2024-04-28 20:39:57 +03:00
Megamouse e32c48d0dd Camera: optimize some loops
Factor out some conditions in RAW8 loop.
Use floats YUV loop.
Replace pixel getters with simple pointers.
2024-04-27 14:23:56 +02:00
capriots e2402b1c8f cellRtc: review fixes 2024-04-27 13:33:09 +02:00
capriots 36abdd7114 sys_time: review fixes 2024-04-27 13:33:09 +02:00
capriots 79f54771b5 cellRtc: set to HLE by default 2024-04-27 13:33:09 +02:00
capriots 2556f84752 cellRtc: replace vm::check_addr() with sys_memory_get_page_attribute() 2024-04-27 13:33:09 +02:00
capriots c8e624850b cellRtc: improvements 2024-04-27 13:33:09 +02:00
capriots 56692e23f5 lv2: stub sys_time syscalls, add error code to sys_ss 2024-04-27 13:33:09 +02:00
RipleyTom b38ce9452d Revert "Split normal sockets and p2p sockets handling"
This reverts commit 08c3a38b67.
2024-04-27 10:45:14 +02:00
Megamouse fcba193a3c input: use keyboard consumers to seperate cell and overlay logic 2024-04-27 01:03:23 +02:00
RipleyTom 6fc7fa3b13 Logging improvements 2024-04-27 00:12:14 +02:00
Elad Ashkenazi ad4216a3fc PPU LLVM: Do not crash on linkage of garbage code 2024-04-26 18:55:50 +03:00
RipleyTom 08c3a38b67 Split normal sockets and p2p sockets handling 2024-04-24 14:15:17 +03:00
Megamouse b8165af054 rsx: optimize some loops 2024-04-24 12:16:45 +03:00
Elad Ashkenazi 90b6912daa Compile AUDIT on release builds
In Release, compile the code in constexpr-disabled context. this way it does not risk generating actual code but still compiles.
2024-04-23 17:24:22 +03:00
oltolm 862727e9bf simplify template code like std::invoke_result<T>::type 2024-04-21 18:15:17 +03:00
oltolm 9e9a3262eb simplify template code like std::is_same<T>::value 2024-04-21 18:15:17 +03:00
Florin9doi c268189e38 Don't crash the game if only a LDD controller is present 2024-04-21 12:05:24 +03:00
Megamouse 94431a7a33 Fix include on linux 2024-04-20 19:46:05 +02:00
Megamouse b4d5b44e00 Don't create perf map files in linux unless enabled 2024-04-20 19:46:05 +02:00
Megamouse 16f006362e Move freopen to console.h 2024-04-20 17:23:10 +03:00
capriots dfec577417 cellRtc: implement remaining parsers, improve formatters (#15451) 2024-04-20 15:41:42 +02:00
RipleyTom 33e2f8766a Update spurs_test.self 2024-04-20 13:31:12 +02:00
RipleyTom 31a080a9cb Warning cleanup 2024-04-20 13:31:12 +02:00
Megamouse 14e9c8954c cellMusic 2024-04-20 11:55:49 +02:00
Megamouse dff7352e2e llvm: silence warning: dereferencing type-punned pointer might break strict-aliasing rules [-Wstrict-aliasing] 2024-04-20 01:38:11 +02:00
Megamouse 30bb6c9fb9 cellSysutilAvc2MicRead: Fix some nonsensical nullptr deref warning 2024-04-20 01:38:11 +02:00
Megamouse 7485ec2223 cellKb: fix missing slashes and brackets on japanese layout 2024-04-19 23:47:59 +02:00
Megamouse 60082864a6 cellKb: actually set the arrange member 2024-04-19 23:47:59 +02:00
Megamouse dcb8f21b2b Use unordered map to store keyboard keys
This potentially reduces latency ever so slightly.
2024-04-19 23:47:59 +02:00
Eladash b18a97e777 SPU Analyzer: Filter calls to calls 2024-04-19 20:51:37 +03:00
Eladash c7d93bd470 PPU Analyzer: Look for functions using callers (fallback) 2024-04-19 20:51:37 +03:00
Eladash 7bf8917c08 PPU LLVM: Fix crash in Unity games 2024-04-19 20:51:37 +03:00
Eladash 093198e3d5 savestate_utils.cpp: Fixup a tiny bug 2024-04-19 20:51:37 +03:00
Megamouse e48bd29584 Qt: try to fix sound effects
Don't re-use sound effect objects.
Allow 3 sounds simultaneously.
2024-04-19 17:29:40 +02:00
Megamouse 1444981bdc overlays/osk: Don't use meta out key code in the osk overlay
The out key code is simply used to store the meta key ID.
It is not meant to be a real key code.
2024-04-19 01:29:22 +02:00
Megamouse e3f6bbfcc9 fix some warnings and typos 2024-04-19 01:29:22 +02:00
Megamouse 89922b254c cellSysutilAvc2: improve unload and some more stuff 2024-04-18 13:22:45 +02:00
Florin9doi ea8918291b uDraw emulation [3] 2024-04-18 09:39:02 +02:00
Florin9doi 21445fa01a uDraw emulation [2] 2024-04-18 09:39:02 +02:00
Florin9doi 8d340eecc1 Sort IO files 2024-04-18 09:39:02 +02:00
Florin9doi 463826bf13 uDraw emulation 2024-04-18 09:39:02 +02:00
kd-11 40eda1b972 rsx: Make const explicitly unsigned
- Can silence some GLSL compiler noise in mesa
2024-04-17 22:22:37 +03:00
kd-11 a5c3e303c7 rsx: Improve ROP output rounding precision
- Lower 12 bits seem to be unused based on empirical sampling
2024-04-17 22:22:37 +03:00
Ikko Eltociear Ashimine 270a21ebae Fix typo in System.cpp
Enfore -> Enforce
2024-04-16 17:17:26 +02:00
trigger 6aa96e5f81 Fix OVL patching 2024-04-16 06:15:10 +03:00
kd-11 1792714901 rsx: Fix intra-draw-call barrier queueing
- Ignore latch since we may have another barrier queued. Barriers cost essentially nothing so there is no problem with extra pushes.
- Remove unnecessary use of "else" statements.
2024-04-16 04:38:49 +03:00
Florin9doi 54ab16ab35 Buzz update 2024-04-16 01:46:01 +02:00
Megamouse c58959eba2 Fix some msvc for loop warning 2024-04-15 19:28:28 +02:00
Megamouse 2f53d58cd9 fix some warnings 2024-04-15 19:28:28 +02:00
Florin9doi e0d6f8a311 Set a unique System Name 2024-04-15 08:06:21 +03:00
kd-11 e48ec75896 rsx: Fix vertex texture invalidation 2024-04-14 22:37:07 +03:00
kd-11 58d8c65990 rsx: Fix some broken latch checks 2024-04-14 22:37:07 +03:00
kd-11 dd66380132 vk: Always initialize internal objects 2024-04-14 22:37:07 +03:00
Zion 92dd801ecd Attempt at bundling wayland libraries 2024-04-13 20:57:11 +03:00
Eladash fba1db29b3 Savestates: Fixup 2024-04-13 20:14:49 +03:00
Eladash 1111c1952b SPU: Add debug information when logging analyzer failures 2024-04-13 20:14:49 +03:00
Eladash 7833862342 Add SPU Profiler to GUI 2024-04-13 13:48:00 +03:00
Eladash 78c1a6f326 CPUThread.cpp: Add reservation sampling 2024-04-13 13:48:00 +03:00
Eladash 060ddca1ab SPU: Fixup breakpoints 2024-04-13 13:48:00 +03:00
Eladash a9fd2f76d2 Savestates: serilialize avc2_settings 2024-04-13 13:48:00 +03:00
Eladash d1837b54b4 Savestates: Add save stage names 2024-04-13 13:48:00 +03:00
Eladash 26746ac9ee Progress Dialog: Force update every 20 seconds 2024-04-13 13:48:00 +03:00
Eladash c019b10aa8 savestate_utils.cpp: Fix out-of-range bug 2024-04-13 13:48:00 +03:00
Eladash 0cd316116b Savestates: Make non-existing versions 0 2024-04-13 13:48:00 +03:00
RipleyTom c92a556093 Default constructor for avc2_settings 2024-04-13 05:40:10 +03:00
kd-11 d6f6752af0 Add missing newline 2024-04-13 03:29:57 +03:00
kd-11 d7e04e9b0a Update CMakelists.txt 2024-04-13 03:29:57 +03:00
kd-11 c1aaa1bcf6 Get reworked RSX to compile 2024-04-13 03:29:57 +03:00
kd-11 10fe14e783 rsx: Separate register context from RSX thread 2024-04-13 03:29:57 +03:00
RipleyTom 0231902a69 fix CellSysutilAvc2InitParam 2024-04-13 01:41:41 +02:00
Megamouse dbeb8cfbec cellSysutilAvc2Load_shared: simplify max_video_windows check 2024-04-12 23:04:43 +02:00
Megamouse 96bd150518 cellSysutilAvc2Load_shared: re-arrange streaming_mode checks 2024-04-12 23:04:43 +02:00
Megamouse cb1fb19dea cellSysutilAvc2Load_shared: review fixes 2024-04-12 23:04:43 +02:00
Megamouse 3b37f5b156 cellSysutilAvc2Load_shared: use utils::align for total_bitrate 2024-04-12 23:04:43 +02:00
Megamouse a989634ba5 cellSysutilAvc2Load_shared: fix compilation 2024-04-12 23:04:43 +02:00
Megamouse d865186f23 Only send cellSysutilAvc2LoadAsync callback with CELL_SYSUTIL_AVC2_VOICE_CHAT 2024-04-12 23:04:43 +02:00
Megamouse e63245a6dc Fix callback_func check for CELL_SYSUTIL_AVC2_VIDEO_CHAT
This mode doesn't allow for the callback
2024-04-12 23:04:43 +02:00
Megamouse 682fd15441 move cellSysutilAvc2LoadAsync to cellSysutilAvc2Load 2024-04-12 23:04:43 +02:00
Megamouse bbd81b9395 cellSysutilAvc2Load: param checks 2024-04-12 23:04:43 +02:00
RipleyTom cb6186ea60 Initialize CB in cellSysutilAvc2Load 2024-04-12 21:16:11 +03:00
Eladash 12bfc7d56a SPU/Debugger: Use bitset for breakpoints 2024-04-12 17:13:11 +03:00
Eladash 7dc4ccc87d SPU: Use bitset to reduce memory for compiler instance 2024-04-12 17:13:11 +03:00
Eladash 622894a7e3 Logs: output always message level to debuggers 2024-04-12 09:58:30 +03:00
Eladash 965ec8ec81 GUI/CLI: Add setting to attach command line (Win32) 2024-04-12 09:58:30 +03:00
Eladash 103b2fe5fd PPU/reservations: send thread notification only if data changed 2024-04-12 09:58:30 +03:00
Florin9doi b6bfde6d64 Handle R16G16B16X16_FLOAT
Fix Super Hero Squad
2024-04-12 01:01:14 +03:00
capriots 1ec2752ed2 cellRtc: review + warning fixes 2024-04-11 22:09:00 +02:00
capriots a5b6b2e9b5 cellRtc: tick conversion improvements 2024-04-11 22:09:00 +02:00
Eladash f51b100a8c SPU Analyzer: Do not terminate blocks on BRA 2024-04-09 06:26:03 +03:00
Megamouse 412db758e8 cellRtc: review fixes 2024-04-08 13:50:58 +02:00
Megamouse f617f69be8 cellRtc: remove wrong duplicate pos++
This would have increased pos by one too many.
2024-04-08 13:50:58 +02:00
Megamouse b81d278aee cellRtc: implement Rfc3339 part of cellRtcParseDateTime 2024-04-08 13:50:58 +02:00
Megamouse aee4bfa369 cellRtc: simplify some disassembly code 2024-04-08 13:50:58 +02:00
nastys 517f0e1bac Remove git brew package from macOS CI script (#15407) 2024-04-06 01:47:08 +02:00
Megamouse 08837d2cd0 cellGame: add some more error checks 2024-04-05 23:36:37 +02:00
Megamouse 9a4c823366 cellCamera: fix config from_string 2024-04-05 20:22:45 +02:00
Megamouse 7f3ad4fc2c lv2_socket: reset queue after move 2024-04-05 19:41:41 +02:00
Megamouse 9e7b759236 cellGame: Enable disc insert/eject based on disc mount state 2024-04-05 14:45:10 +02:00
Megamouse 67853b464c Update curl to 8.7.1 2024-04-05 01:51:08 +02:00
Megamouse 51ffd4a377 Update soundtouch to 2.3.3 2024-04-05 01:51:08 +02:00
Megamouse dada2e85a2 Update SDL to 2.30.2 2024-04-05 01:51:08 +02:00
Megamouse 2a53824b02 Update FAudio to 20.04 2024-04-05 01:51:08 +02:00
Elad Ashkenazi 3dc1dfa4a2 Fix typo in lv2_socket_native 2024-04-04 22:47:01 +02:00
RipleyTom 95e0d1a560 Fix changelog size hack 2024-04-04 22:31:29 +03:00
Eladash 8effbf7e4d Savestates/Network: Feign connection failure on startup 2024-04-04 17:28:46 +03:00
RipleyTom 72ad1abd39 Fix updater message 2024-04-04 07:45:08 +03:00
Eladash 2a89d87fab Savestates/SPU: Fix MFC commands abort 2024-04-03 15:03:39 +03:00
Eladash 33eeee0ff2 SPU Debugger: Implement viewing block hash on request 2024-04-03 15:03:39 +03:00
Eladash 3c46388be5 SPU LLVM: Fix store elimination within common blocks
GPR register barriers were ignored in that case.
2024-04-03 15:03:39 +03:00
Eladash d37b9497a2 Replace some URLs 2024-04-03 15:03:39 +03:00
Eladash 17512f2a28 Updater: Add RPCS3's Patreon link to update dialog 2024-04-02 21:48:08 +03:00
Eladash 597a9f6dd6 PPU Loader: Fix unload of HLEd PRX modules 2024-04-01 12:20:38 +03:00
Eladash e90b399329 PPU LLVM: Fix leak of modules outside dev_flash/sys/internal
Cache path was not matching on removal
2024-03-30 21:58:26 +03:00
Eladash 7c8be662c6 SPU LLVM: Postpone runtime worker threads init
They may not be active at all unless a ps3 application is booted.
2024-03-30 21:58:26 +03:00
Eladash e38b005a8b PPU LLVM: Unify memory limit for PRX and Overlay files 2024-03-30 21:58:26 +03:00
Eladash f0abb4473e PPU LLVM: Fix memory leak on precompilation 2024-03-30 21:58:26 +03:00
oltolm d62e90f5b4 use the pass manager instead of the legacy one 2024-03-30 05:06:29 +03:00
Eladash 4ecf8ecd06 Fix savestate reload functionality 2024-03-29 13:25:51 +03:00
Eladash 9a3b72f762 Savestates/SPU: Partially publicize SPU-Compatible functionality 2024-03-29 13:25:51 +03:00
Eladash 7285af4771 SaveStates: Add error messages on screen 2024-03-29 13:25:51 +03:00
kd-11 ec37e8f0dc rsx: Fix loading mid-draw call savestates 2024-03-29 08:15:38 +03:00
Eladash 41f05f6864 LV2: Silence logging of semaphore 2024-03-28 16:24:47 +02:00
Eladash cc2fa94fa1 PPU: Fix logging of sys_interrupt syscalls 2024-03-28 16:24:47 +02:00
Eladash 2f579311b8 LV2: Silence logging of mutex and cond syscalls 2024-03-28 16:24:47 +02:00
oltolm ac034040ce workaround Clang 18.1 crash 2024-03-28 08:45:20 +01:00
oltolm 59410b9d62 fix compiler warnings 2024-03-28 08:45:20 +01:00
oltolm 6f665da016 main.cpp: remove outdated code for MSVC 19.27 2024-03-28 08:45:20 +01:00
oltolm c567c92d4b fix GCC warnings 2024-03-28 08:45:20 +01:00
oltolm 75b2dfa66d cmake: fix MSVC build 2024-03-28 08:45:20 +01:00
oltolm c40826c140 llvm: update to 18 2024-03-28 08:45:20 +01:00
kd-11 175aa510c8 rsx: Make overlay manager default lock-state exclusive 2024-03-28 08:08:21 +01:00
kd-11 236ac7d062 rsx: Fix race conditions on removals 2024-03-28 08:08:21 +01:00
kd-11 00f1b2bfa7 rsx: Rewrite fragment shader invalidation test 2024-03-28 08:08:21 +01:00
kd-11 a9fad83971 rsx: Fix memory range invalidation 2024-03-28 08:08:21 +01:00
kd-11 1550dc7f1f Fix audit crash in games where hash strategy is heavily used 2024-03-28 08:08:21 +01:00
Megamouse bbb4c109d7 audio: allow to choose channel layouts 2024-03-28 07:17:26 +01:00
Eladash a6fa091ab3 Savestates/RSX: Save pending flip 2024-03-27 19:59:22 +02:00
Eladash 6a1fa88e15 PPU: Fixup savestate prio bit usage 2024-03-27 19:59:22 +02:00
Eladash 787e79c687 util\serialization_ext.cpp: Fixup 2024-03-27 19:59:22 +02:00
Eladash 7468d96c51 Savestates: safe saving while cellSaveData is active 2024-03-27 19:59:22 +02:00
Eladash 9c9ece3d95 SPU LLVM: Fix Forwarding GPR stores savestate safety 2024-03-27 19:59:22 +02:00
Eladash 316b3a8851 Thread.cpp: Reduce logging 2024-03-27 19:59:22 +02:00
Eladash 2023057fbb Savestates: Reduce logging 2024-03-27 19:59:22 +02:00
Eladash 94c048d018 SPU LLVM: Add assert for MFC abort 2024-03-27 19:59:22 +02:00
Eladash e126af63ed Silence cellGemGetState 2024-03-27 19:59:22 +02:00
Eladash 750359d780 Fixup emulation stopping 2024-03-27 19:59:22 +02:00
Eladash 8588b2b11a vm: Fix writer lock leak 2024-03-27 19:59:22 +02:00
kd-11 4594c912a6 rsx: Move SPIRV stuff into common code 2024-03-27 19:20:21 +02:00
Megamouse afcfd81496 GL: fix segfault in GLGSRender::flip 2024-03-27 16:44:52 +01:00
Megamouse aa06aaab8e Add Legacy plugin to Building.md 2024-03-27 15:09:57 +01:00
Megamouse fdca881e34 Remove Windows 7 reference 2024-03-27 15:09:57 +01:00
Megamouse 81de7a5863 Qt 6.6.3 2024-03-27 11:43:55 +01:00
Eladash efbf044ea0 Savestates/PPU: Fix PRX relocations 2024-03-26 21:35:53 +02:00
Eladash 46a1c09abe Savestates: Minor logging message 2024-03-26 21:35:53 +02:00
Eladash 6a3e795d73 Fix shutting down emulation while save-stating 2024-03-26 21:35:53 +02:00
Eladash e0f08cd5c1 SPU: Make STOP a safe return instruction 2024-03-26 21:35:53 +02:00
Eladash a539308545 Savestates: Make locking SPU threads more reasonable
Avoid locking in hopeless cases. Extend waiting time to more than 2 seconds.
2024-03-26 21:35:53 +02:00
Eladash 3364a46139 PPU LLVM: Remove cast to constant 2024-03-26 21:35:53 +02:00
Eladash fb4e64d15e Savestates/SPU: Extend RCHCNT safe returns 2024-03-26 21:35:53 +02:00
Eladash 68349e48cd Savestates: Save PPU running order 2024-03-26 21:35:53 +02:00
Eladash 4dff8b16f1 Silence logging of cellScreenShot 2024-03-26 21:35:53 +02:00
Megamouse 9245565085 cellAudio: log backend channel count 2024-03-26 16:56:17 +01:00
Megamouse 86ca381a3c Qt: Rename Navigation controller to PS Move Navigation 2024-03-26 16:56:17 +01:00
Megamouse a7952e15c7 cellPad: simplify for loops 2024-03-26 16:56:17 +01:00
Megamouse 643f81b5db cellPad: move getters to where they are actually needed 2024-03-26 16:56:17 +01:00
Megamouse cf5a66a204 cellMic: add nullptr check for data in cell_mic_read
Also rename S to Size for readability
2024-03-26 13:50:43 +01:00
Megamouse e05239f3d9 Fix some warnings 2024-03-26 12:26:26 +01:00
Megamouse 0e73b58abf Update miniupnpd to 2.3.6 2024-03-26 12:26:26 +01:00
Megamouse 59dc5dcd54 Update wolfssl to 5.7.0 2024-03-26 12:26:26 +01:00
Elad Ashkenazi adedc7c667 Savestates/SPU: Add RCHCNT as a safe return in compatiblity mode 2024-03-25 12:05:24 +02:00
Elad Ashkenazi 29ad568791 Fix ppu_thread::serialize_common 2024-03-25 12:05:24 +02:00
Elad Ashkenazi 453a3c4852 Fixup Savestate Segfault 2024-03-25 12:05:24 +02:00
Elad Ashkenazi 2e824827b7 Fixup Savestate Progress 2024-03-24 20:58:51 +02:00
Eladash 3393d13b67 Reduce compression level to 8 for faster compression 2024-03-24 16:19:06 +02:00
Eladash 1da7689526 util\serialization_ext.cpp: Fix queued data with no output 2024-03-24 16:19:06 +02:00
Eladash 806758d06f Fix NPD files decryption in decryption tool 2024-03-24 16:19:06 +02:00
Eladash 580f9bf03a GUI: Progress Dialog On Save State Creation 2024-03-24 16:19:06 +02:00
Eladash 707a648a4c utils: Fix shared_ptr::store/exchange 2024-03-24 16:19:06 +02:00
Eladash 213a19c9f3 Add logging for CallFromMainThread 2024-03-24 16:19:06 +02:00
Elad.Ash e32ed90d21 PPU LLVM: Remove one external symbol resolve for BLR 2024-03-21 15:56:31 +02:00
Eladash 2f822abb47 PPU LLVM: Use symbol resolver function to resolve functions 2024-03-20 12:48:31 +02:00
Eladash 1ca83bc629 PPU DisAsm: Fixup conditional indirect branches disasm 2024-03-20 12:48:31 +02:00
RipleyTom 77485747f1 Enable WOLFSSL_ALT_CERT_CHAINS 2024-03-17 05:59:23 +02:00
Eladash 40adf4b944 HLE: clear lower bits of Free Disk Space value 2024-03-14 11:10:45 +01:00
Megamouse 2aad5a7f3a Qt: add search bar to save manager 2024-03-13 18:42:42 +01:00
Megamouse 0f29a5be9f Qt: replace refresh progress slot with timer
For some reason setValue crashes in the progressValueChanged slot for no apparent reason
2024-03-13 00:24:42 +01:00
RipleyTom 397c2698ae Fix sceNpScoreGetRankingByNpId 2024-03-12 09:36:31 +02:00
Megamouse 0f00bb77fe Qt: only connect refresh watcher signals once 2024-03-11 23:04:09 +01:00
Megamouse a73303a047 Qt: remove redundant progress dialog code. This already happens in Refresh 2024-03-11 23:04:09 +01:00
Ani 0334243a69 appimage: Do not bundle libvulkan.so
Causes issues with gamescope, see 
https://github.com/RPCS3/rpcs3/issues/14917
2024-03-11 21:03:19 +01:00
Megamouse bb809c865f VS: move libpng, libusb and hidapi lib output to proper build configiguration dir
This allows us to properly build debug and release without having to delete the libs in between
2024-03-11 12:39:39 +01:00
Megamouse 20750c260e VS: Fix libpng build configuration names 2024-03-11 12:39:39 +01:00
Megamouse 37dd1b3ed0 VS: fix linking XAudio in debug builds 2024-03-11 09:02:01 +01:00
Megamouse f3ac3476cb VS: use MultiThreadedDebugDLL in debug builds
This fixes heap assertions caused by mixing static builds and dynamic Qt
2024-03-11 09:02:01 +01:00
Megamouse 67ae1c9f69 VS: use common RuntimeLibrary settings in 3rdparty 2024-03-11 09:02:01 +01:00
RipleyTom fd583dbbc3 Cleanup and set -Werror=delete-non-virtual-dtor 2024-03-11 02:30:18 +02:00
Megamouse d8d0af2bb3 rsx: Fix invalid iterator comparison (asserts on debug builds)
Also make ranged_map::count const
2024-03-11 00:03:00 +01:00
Megamouse b176085e14 GL: fix debug build: creation of QOffscreenSurface sends signals from wrong thread 2024-03-11 00:03:00 +01:00
Elad.Ash 4cfdb71d3a LV2: Longer thread creation delay for low prio threads 2024-03-09 23:37:35 +02:00
Megamouse 38590e321e Qt: accept downloader progress dialog instead of closing it
Otherwise we get the canceled signal which is only meant for user interaction
2024-03-09 20:07:37 +01:00
Megamouse a09900a64f Qt: make sure to actually delete the progress dialog when it is closed
Also add some more cleanup code for the gamelist refresh progress dialog
2024-03-09 20:07:37 +01:00
Megamouse 4a7d982a2b Qt: make sure the gamelist refresh progress dialog runs on the main thread 2024-03-09 20:07:37 +01:00
Megamouse ee69468104 Qt: replace sstr with regular toStdString 2024-03-09 20:07:37 +01:00
Megamouse 4739ab58cc Qt: fix weird return value warning on VS 2024-03-09 20:07:37 +01:00
Megamouse be5b982e45 Qt: don't close the progress dialog if it is already being closed anyway
Maybe this fixes some strange crashes that appear for some people.
2024-03-09 15:18:20 +01:00
Megamouse 86ad4ed6c1 Qt: check for updates if the update message is empty
This happens for example if the user canceled the earlier check
after the update was already known, leaving us in a somewhat dirty state.
2024-03-09 15:18:20 +01:00
Megamouse 3056a4db83 Qt: don't deleteLater the progress_dialog
It's already deleted on close by Qt anyway.
Also, remove QObject from curl_handle.
2024-03-09 15:18:20 +01:00
Eladash adc8a360ad SPU LLVM: More compilation threads 2024-03-08 11:40:38 +02:00
Eladash 719dafa679 SPU LLVM: Notify workers prematurely if there is considerable excess 2024-03-08 07:21:48 +02:00
Eladash ecf7d4e59d SPU LLVM: Postpone cache writes until compiled 2024-03-08 07:21:48 +02:00
Eladash 45863bc7c5 SPU analyzer: Detect 'argument passing' block before the function 2024-03-07 18:46:51 +02:00
Eladash ea0545779a SPU: Include BRSL following code in is_exec_code() 2024-03-07 18:46:51 +02:00
Eladash e625bab7eb SPU Analyzer: Detect more tail calls by examining called code 2024-03-07 18:46:51 +02:00
Eladash 2930d609ea SPU: Detect invalid STOP codes (code mining) 2024-03-07 18:46:51 +02:00
Eladash 069ca214ff SPU: Improve compilation message 2024-03-07 18:46:51 +02:00
Eladash d699db2d19 SPU Analyser: Detect invalid relative branches 2024-03-07 18:46:51 +02:00
Eladash 8e15de5c83 sys_tty: Try to avoid logging single newlines to log 2024-03-07 14:31:41 +02:00
Eladash 69a90ef9e7 rsx/cpu_thread: Fix cpu_thread::get_name() for RSX 2024-03-07 14:31:41 +02:00
Eladash d39361705a report_fatal_error: Minor cleanup and improvement 2024-03-06 20:32:22 +02:00
Eladash 4512c10ce5 init_mutex.hpp: More fixes 2024-03-06 20:32:22 +02:00
Megamouse 5e24167d6c Update submodules 2024-03-06 18:58:23 +01:00
Ordinary205 64d28ba435 Increase vblank rate 2024-03-06 18:50:51 +02:00
nastys 7febbdf52b macOS CI: Don't upgrade installed dependents
This should speed up builds, and possibly prevent conflicts.
2024-03-06 17:04:43 +02:00
Eladash b64b98490e init_mutex.hpp: Fixup 2024-03-06 16:06:04 +02:00
Eladash f40602cc59 cellGame: Fix PPU deadlocks on concurrent execution 2024-03-06 09:45:37 +02:00
265 changed files with 9203 additions and 4904 deletions
+3 -1
View File
@@ -1,7 +1,9 @@
#!/bin/sh -ex
export HOMEBREW_NO_AUTO_UPDATE=1
brew install -f --overwrite nasm ninja git p7zip ccache pipenv #create-dmg
export HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK=1
brew unlink certifi
brew install -f --overwrite nasm ninja p7zip ccache pipenv #create-dmg
#/usr/sbin/softwareupdate --install-rosetta --agree-to-license
arch -x86_64 /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
+6 -1
View File
@@ -12,11 +12,16 @@ if [ "$DEPLOY_APPIMAGE" = "true" ]; then
curl -fsSLo linuxdeploy-plugin-checkrt.sh https://github.com/linuxdeploy/linuxdeploy-plugin-checkrt/releases/download/continuous/linuxdeploy-plugin-checkrt-x86_64.sh
chmod +x ./linuxdeploy-plugin-checkrt.sh
EXTRA_QT_PLUGINS="svg;" APPIMAGE_EXTRACT_AND_RUN=1 linuxdeploy --appdir AppDir --plugin qt
export EXTRA_PLATFORM_PLUGINS="libqwayland-egl.so;libqwayland-generic.so"
export EXTRA_QT_PLUGINS="svg;wayland-decoration-client;wayland-graphics-integration-client;wayland-shell-integration"
APPIMAGE_EXTRACT_AND_RUN=1 linuxdeploy --appdir AppDir --plugin qt
# Remove libwayland-client because it has platform-dependent exports and breaks other OSes
rm -f ./AppDir/usr/lib/libwayland-client.so*
# Remove libvulkan because it causes issues with gamescope
rm -f ./AppDir/usr/lib/libvulkan.so*
# Remove git directory containing local commit history file
rm -rf ./AppDir/usr/share/rpcs3/git
+3 -3
View File
@@ -7,7 +7,7 @@ env:
BUILD_SOURCEBRANCHNAME: $CIRRUS_BRANCH
RPCS3_TOKEN: ENCRYPTED[!a4c3850e29ab150692286a74bec29819d25971a7ec431b86de2a35f7ed90c5b2ab3c93469f9298e30924d843599110e9!]
QT_VER_MAIN: '6'
QT_VER: '6.6.2'
QT_VER: '6.6.3'
# windows_task:
# matrix:
@@ -21,7 +21,7 @@ env:
# COMPILER: msvc
# BUILD_ARTIFACTSTAGINGDIRECTORY: ${CIRRUS_WORKING_DIR}\artifacts\
# QT_VER_MSVC: 'msvc2019'
# QT_DATE: '202402121135'
# QT_DATE: '202403191840'
# QTDIR: C:\Qt\${QT_VER}\${QT_VER_MSVC}_64
# VULKAN_VER: '1.3.268.0'
# VULKAN_SDK_SHA: '8459ef49bd06b697115ddd3d97c9aec729e849cd775f5be70897718a9b3b9db5'
@@ -56,7 +56,7 @@ env:
# linux_task:
# container:
# image: rpcs3/rpcs3-ci-focal:1.6
# image: rpcs3/rpcs3-ci-focal:1.7
# cpu: 4
# memory: 16G
# env:
+3
View File
@@ -130,6 +130,9 @@ yaml-cpp.pc
# miniupnp
/3rdparty/miniupnp/x64/*
# opencv
/3rdparty/opencv/*
# llvm
/3rdparty/llvm/llvm_build
+7 -3
View File
@@ -44,7 +44,7 @@
<Optimization>MaxSpeed</Optimization>
<InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
<AdditionalIncludeDirectories>curl\include;curl\lib;extra;$(SolutionDir)3rdparty\wolfssl\wolfssl\wolfssl;$(SolutionDir)3rdparty\wolfssl\wolfssl;$(SolutionDir)3rdparty\wolfssl\extra\win32;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>HAVE_SNI;NDEBUG;BUILDING_LIBCURL;CURL_STATICLIB;USE_WOLFSSL;NO_MD4;WOLFSSL_USER_SETTINGS;USE_IPV6;SIZEOF_LONG=4;SIZEOF_LONG_LONG=8;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions>WOLFSSL_ALT_CERT_CHAINS;HAVE_SNI;NDEBUG;BUILDING_LIBCURL;CURL_STATICLIB;USE_WOLFSSL;NO_MD4;WOLFSSL_USER_SETTINGS;USE_IPV6;SIZEOF_LONG=4;SIZEOF_LONG_LONG=8;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<StringPooling>true</StringPooling>
<FunctionLevelLinking>true</FunctionLevelLinking>
<WarningLevel>TurnOffAllWarnings</WarningLevel>
@@ -92,9 +92,11 @@
<ClCompile Include="curl\lib\curl_range.c" />
<ClCompile Include="curl\lib\curl_rtmp.c" />
<ClCompile Include="curl\lib\curl_sasl.c" />
<ClCompile Include="curl\lib\curl_sha512_256.c" />
<ClCompile Include="curl\lib\curl_sspi.c" />
<ClCompile Include="curl\lib\curl_threads.c" />
<ClCompile Include="curl\lib\curl_trc.c" />
<ClCompile Include="curl\lib\cw-out.c" />
<ClCompile Include="curl\lib\dict.c" />
<ClCompile Include="curl\lib\doh.c" />
<ClCompile Include="curl\lib\dynbuf.c" />
@@ -156,6 +158,7 @@
<ClCompile Include="curl\lib\psl.c" />
<ClCompile Include="curl\lib\rand.c" />
<ClCompile Include="curl\lib\rename.c" />
<ClCompile Include="curl\lib\request.c" />
<ClCompile Include="curl\lib\rtsp.c" />
<ClCompile Include="curl\lib\select.c" />
<ClCompile Include="curl\lib\sendf.c" />
@@ -286,12 +289,13 @@
<ClInclude Include="curl\lib\curl_setup.h" />
<ClInclude Include="curl\lib\curl_setup_once.h" />
<ClInclude Include="curl\lib\curl_sha256.h" />
<ClInclude Include="curl\lib\curl_sha512_256.h" />
<ClInclude Include="curl\lib\curl_sspi.h" />
<ClInclude Include="curl\lib\curl_threads.h" />
<ClInclude Include="curl\lib\curl_trc.h" />
<ClInclude Include="curl\lib\cw-out.h" />
<ClInclude Include="curl\lib\dict.h" />
<ClInclude Include="curl\lib\doh.h" />
<ClInclude Include="curl\lib\dotdot.h" />
<ClInclude Include="curl\lib\dynbuf.h" />
<ClInclude Include="curl\lib\dynhds.h" />
<ClInclude Include="curl\lib\easyif.h" />
@@ -341,6 +345,7 @@
<ClInclude Include="curl\lib\psl.h" />
<ClInclude Include="curl\lib\rand.h" />
<ClInclude Include="curl\lib\rename.h" />
<ClInclude Include="curl\lib\request.h" />
<ClInclude Include="curl\lib\rtsp.h" />
<ClInclude Include="curl\lib\select.h" />
<ClInclude Include="curl\lib\sendf.h" />
@@ -386,7 +391,6 @@
<ClInclude Include="curl\lib\vauth\vauth.h" />
<ClInclude Include="curl\lib\vquic\vquic.h" />
<ClInclude Include="curl\lib\vssh\ssh.h" />
<ClInclude Include="curl\lib\vssh\wolfssh.h" />
<ClInclude Include="curl\lib\vtls\bearssl.h" />
<ClInclude Include="curl\lib\vtls\gtls.h" />
<ClInclude Include="curl\lib\vtls\keylog.h" />
+18 -6
View File
@@ -504,6 +504,15 @@
<ClCompile Include="curl\lib\curl_trc.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="curl\lib\request.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="curl\lib\cw-out.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="curl\lib\curl_sha512_256.c">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="curl\include\curl\curl.h">
@@ -677,9 +686,6 @@
<ClInclude Include="curl\lib\doh.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="curl\lib\dotdot.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="curl\lib\easyif.h">
<Filter>Header Files</Filter>
</ClInclude>
@@ -890,9 +896,6 @@
<ClInclude Include="curl\lib\vssh\ssh.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="curl\lib\vssh\wolfssh.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="curl\lib\vtls\bearssl.h">
<Filter>Header Files</Filter>
</ClInclude>
@@ -1028,6 +1031,15 @@
<ClInclude Include="curl\lib\curl_trc.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="curl\lib\request.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="curl\lib\cw-out.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="curl\lib\curl_sha512_256.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="curl\lib\libcurl.rc">
+2 -2
View File
@@ -39,9 +39,9 @@
<PropertyGroup Label="UserMacros">
<CmakeGenerator>"Visual Studio $(VisualStudioVersion.Substring(0,2))"</CmakeGenerator>
<CmakeReleaseCLI>call vsdevcmd.bat -arch=amd64
cmake -G $(CmakeGenerator) -A x64 -DCMAKE_BUILD_TYPE="Release" -DLLVM_USE_CRT_DEBUG=MTd -DLLVM_USE_CRT_RELEASE=MT -DENABLE_OPT=OFF -S glslang -B build</CmakeReleaseCLI>
cmake -G $(CmakeGenerator) -A x64 -DCMAKE_BUILD_TYPE="Release" -DLLVM_USE_CRT_DEBUG=MDd -DLLVM_USE_CRT_RELEASE=MT -DENABLE_OPT=OFF -S glslang -B build</CmakeReleaseCLI>
<CmakeDebugCLI>call vsdevcmd.bat -arch=amd64
cmake -G $(CmakeGenerator) -A x64 -DCMAKE_BUILD_TYPE="Debug" -DLLVM_USE_CRT_DEBUG=MTd -DLLVM_USE_CRT_RELEASE=MT -DENABLE_OPT=OFF -S glslang -B build</CmakeDebugCLI>
cmake -G $(CmakeGenerator) -A x64 -DCMAKE_BUILD_TYPE="Debug" -DLLVM_USE_CRT_DEBUG=MDd -DLLVM_USE_CRT_RELEASE=MT -DENABLE_OPT=OFF -S glslang -B build</CmakeDebugCLI>
<PropsAbsPath>$([System.IO.Path]::GetFullPath('$(MSBuildThisFileDirectory)..\..\buildfiles\msvc\common_default.props'))</PropsAbsPath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+2 -2
View File
@@ -44,12 +44,12 @@
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>true</LinkIncremental>
<OutDir>$(SolutionDir)lib/</OutDir>
<OutDir>$(SolutionDir)lib\$(Configuration)-$(Platform)/</OutDir>
<IntDir>$(SolutionDir)tmp\$(ProjectName)-$(Configuration)-$(Platform)/</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
<OutDir>$(SolutionDir)lib/</OutDir>
<OutDir>$(SolutionDir)lib\$(Configuration)-$(Platform)/</OutDir>
<IntDir>$(SolutionDir)tmp\$(ProjectName)-$(Configuration)-$(Platform)/</IntDir>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+5
View File
@@ -4,6 +4,11 @@ if (NOT USE_SYSTEM_LIBPNG)
# We use libpng's static library and don't need to build the shared library and run the tests
set(PNG_SHARED OFF CACHE BOOL "Build shared lib")
set(PNG_TESTS OFF CACHE BOOL "Build libpng tests")
if (NOT USE_SYSTEM_ZLIB)
set(PNG_BUILD_ZLIB ON CACHE BOOL "Custom zlib location, else find_package is used")
add_library(ZLIB::ZLIB INTERFACE IMPORTED)
target_link_libraries(ZLIB::ZLIB INTERFACE 3rdparty_zlib)
endif()
set(SKIP_INSTALL_ALL ON)
add_subdirectory(libpng EXCLUDE_FROM_ALL)
target_include_directories(png_static INTERFACE "${libpng_BINARY_DIR}" "${libpng_SOURCE_DIR}")
+18 -20
View File
@@ -1,12 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug Library|x64">
<Configuration>Debug Library</Configuration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release Library|x64">
<Configuration>Release Library</Configuration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
@@ -19,11 +19,11 @@
<Import Project="$(SolutionDir)\buildfiles\msvc\common_default.props" />
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<Import Project="$(SolutionDir)\buildfiles\msvc\common_default_macros.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug Library|x64'" Label="Configuration">
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release Library|x64'" Label="Configuration">
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
@@ -33,28 +33,28 @@
</PropertyGroup>
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug Library|x64'" Label="PropertySheets">
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release Library|x64'" Label="PropertySheets">
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug Library|x64'">
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>false</LinkIncremental>
<CustomBuildBeforeTargets />
<TargetName>$(ProjectName)16</TargetName>
<OutDir>$(SolutionDir)lib/</OutDir>
<OutDir>$(SolutionDir)lib\$(Configuration)-$(Platform)/</OutDir>
<IntDir>$(SolutionDir)tmp\$(ProjectName)-$(Configuration)-$(Platform)/</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release Library|x64'">
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
<CustomBuildBeforeTargets />
<TargetName>$(ProjectName)16</TargetName>
<OutDir>$(SolutionDir)lib/</OutDir>
<OutDir>$(SolutionDir)lib\$(Configuration)-$(Platform)/</OutDir>
<IntDir>$(SolutionDir)tmp\$(ProjectName)-$(Configuration)-$(Platform)/</IntDir>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug Library|x64'">
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<PrecompiledHeader>Use</PrecompiledHeader>
<WarningLevel>$(WarningLevel)</WarningLevel>
@@ -74,19 +74,17 @@
<DisableSpecificWarnings>$(DisableSpecificWarnings)</DisableSpecificWarnings>
<AdditionalIncludeDirectories>$(ZLibSrcDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<TreatWarningAsError>$(TreatWarningAsError)</TreatWarningAsError>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release Library|x64'">
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>$(WarningLevel)</WarningLevel>
<PrecompiledHeader>Use</PrecompiledHeader>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
@@ -115,8 +113,8 @@
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="libpng\png.c">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug Library|x64'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release Library|x64'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader>
</ClCompile>
<ClCompile Include="libpng\pngerror.c" />
<ClCompile Include="libpng\pngget.c" />
@@ -135,8 +133,8 @@
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="libpng\scripts\pngwin.rc">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug Library|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release Library|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
</ResourceCompile>
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+1 -3
View File
@@ -35,7 +35,7 @@
<PropertyGroup Label="UserMacros" />
<PropertyGroup>
<_ProjectFileVersion>10.0.30319.1</_ProjectFileVersion>
<OutDir>$(SolutionDir)lib/</OutDir>
<OutDir>$(SolutionDir)lib\$(Configuration)-$(Platform)/</OutDir>
<IntDir>$(SolutionDir)tmp\$(ProjectName)-$(Configuration)-$(Platform)/</IntDir>
<TargetName>libusb-1.0</TargetName>
</PropertyGroup>
@@ -50,11 +50,9 @@
<ClCompile Condition="'$(Configuration)'=='Debug'">
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<Optimization>Disabled</Optimization>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
</ClCompile>
<ClCompile Condition="'$(Configuration)'=='Release'">
<PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
</ClCompile>
<Lib>
<OutputFile>$(OutDir)libusb-1.0.lib</OutputFile>
+6 -14
View File
@@ -36,12 +36,7 @@ if(WITH_LLVM)
set(STATIC_LINK_LLVM ON CACHE BOOL "Link against LLVM statically. This will get set to ON if you build LLVM from the submodule." FORCE)
# now tries to find LLVM again
find_package(LLVM 16.0 CONFIG)
if(NOT LLVM_FOUND)
set(LLVM_DIR "${CMAKE_CURRENT_BINARY_DIR}/llvm_build/lib/cmake/llvm/")
find_package(LLVM 17.0 CONFIG)
endif()
if(NOT LLVM_FOUND)
message(FATAL_ERROR "Couldn't build LLVM from the submodule. You might need to run `git submodule update --init`")
endif()
@@ -53,20 +48,16 @@ if(WITH_LLVM)
set(LLVM_DIR ${CMAKE_SOURCE_DIR}/${LLVM_DIR})
endif()
find_package(LLVM 16.0 CONFIG)
if(NOT LLVM_FOUND)
find_package(LLVM 17.0 CONFIG)
endif()
find_package(LLVM CONFIG)
if (NOT LLVM_FOUND)
if (LLVM_VERSION AND LLVM_VERSION_MAJOR LESS 16)
message(FATAL_ERROR "Found LLVM version ${LLVM_VERSION}. Required versions 16...17. \
Enable BUILD_LLVM option to build LLVM from included as a git submodule.")
endif()
message(FATAL_ERROR "Can't find LLVM libraries from the CMAKE_PREFIX_PATH path or LLVM_DIR. \
Enable BUILD_LLVM option to build LLVM from included as a git submodule.")
endif()
if (LLVM_VERSION VERSION_LESS 16)
message(FATAL_ERROR "Found LLVM version ${LLVM_VERSION}. Required version 16 or above. \
Enable BUILD_LLVM option to build LLVM from included as a git submodule.")
endif()
endif()
if (STATIC_LINK_LLVM)
@@ -89,6 +80,7 @@ if(WITH_LLVM)
Core
ExecutionEngine
MCJIT
Passes
)
else()
set(LLVM_LIBS LLVM)
+2 -2
View File
@@ -39,9 +39,9 @@
</ImportGroup>
<PropertyGroup Label="UserMacros">
<CmakeReleaseCLI>call vsdevcmd.bat -arch=amd64
cmake -G Ninja -DCMAKE_CXX_COMPILER="cl.exe" -DCMAKE_C_COMPILER="cl.exe" -DCMAKE_BUILD_TYPE="Release" -DCMAKE_INSTALL_PREFIX="./Release" -DLLVM_TARGETS_TO_BUILD=X86 -DLLVM_DEFAULT_TARGET_TRIPLE:STRING=x86_64-pc-windows-msvc -DLLVM_HOST_TRIPLE:STRING=x86_64-pc-windows-msvc -DLLVM_BUILD_RUNTIME=OFF -DLLVM_BUILD_TOOLS=OFF -DLLVM_INCLUDE_DOCS=OFF -DLLVM_INCLUDE_EXAMPLES=OFF -DLLVM_INCLUDE_TESTS=OFF -DLLVM_INCLUDE_BENCHMARKS=OFF -DLLVM_INCLUDE_UTILS=OFF -DCMAKE_SYSTEM_VERSION=6.1 -DCMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION=$(WindowsTargetPlatformVersion) -DLLVM_USE_CRT_DEBUG=MTd -DLLVM_USE_CRT_RELEASE=MT -DLLVM_USE_INTEL_JITEVENTS=ON ../llvm/llvm</CmakeReleaseCLI>
cmake -G Ninja -DCMAKE_CXX_COMPILER="cl.exe" -DCMAKE_C_COMPILER="cl.exe" -DCMAKE_BUILD_TYPE="Release" -DCMAKE_INSTALL_PREFIX="./Release" -DLLVM_TARGETS_TO_BUILD=X86 -DLLVM_DEFAULT_TARGET_TRIPLE:STRING=x86_64-pc-windows-msvc -DLLVM_HOST_TRIPLE:STRING=x86_64-pc-windows-msvc -DLLVM_BUILD_RUNTIME=OFF -DLLVM_BUILD_TOOLS=OFF -DLLVM_INCLUDE_DOCS=OFF -DLLVM_INCLUDE_EXAMPLES=OFF -DLLVM_INCLUDE_TESTS=OFF -DLLVM_INCLUDE_BENCHMARKS=OFF -DLLVM_INCLUDE_UTILS=OFF -DCMAKE_SYSTEM_VERSION=6.1 -DCMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION=$(WindowsTargetPlatformVersion) -DLLVM_USE_CRT_DEBUG=MDd -DLLVM_USE_CRT_RELEASE=MT -DLLVM_USE_INTEL_JITEVENTS=ON ../llvm/llvm</CmakeReleaseCLI>
<CmakeDebugCLI>call vsdevcmd.bat -arch=amd64
cmake -G Ninja -DCMAKE_CXX_COMPILER="cl.exe" -DCMAKE_C_COMPILER="cl.exe" -DCMAKE_BUILD_TYPE="Debug" -DCMAKE_INSTALL_PREFIX="./Debug" -DLLVM_TARGETS_TO_BUILD=X86 -DLLVM_DEFAULT_TARGET_TRIPLE:STRING=x86_64-pc-windows-msvc -DLLVM_HOST_TRIPLE:STRING=x86_64-pc-windows-msvc -DLLVM_BUILD_RUNTIME=OFF -DLLVM_BUILD_TOOLS=OFF -DLLVM_INCLUDE_DOCS=OFF -DLLVM_INCLUDE_EXAMPLES=OFF -DLLVM_INCLUDE_TESTS=OFF -DLLVM_INCLUDE_BENCHMARKS=OFF -DLLVM_INCLUDE_UTILS=OFF -DCMAKE_SYSTEM_VERSION=6.1 -DCMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION=$(WindowsTargetPlatformVersion) -DLLVM_USE_CRT_DEBUG=MTd -DLLVM_USE_CRT_RELEASE=MT -DLLVM_USE_INTEL_JITEVENTS=ON ../llvm/llvm</CmakeDebugCLI>
cmake -G Ninja -DCMAKE_CXX_COMPILER="cl.exe" -DCMAKE_C_COMPILER="cl.exe" -DCMAKE_BUILD_TYPE="Debug" -DCMAKE_INSTALL_PREFIX="./Debug" -DLLVM_TARGETS_TO_BUILD=X86 -DLLVM_DEFAULT_TARGET_TRIPLE:STRING=x86_64-pc-windows-msvc -DLLVM_HOST_TRIPLE:STRING=x86_64-pc-windows-msvc -DLLVM_BUILD_RUNTIME=OFF -DLLVM_BUILD_TOOLS=OFF -DLLVM_INCLUDE_DOCS=OFF -DLLVM_INCLUDE_EXAMPLES=OFF -DLLVM_INCLUDE_TESTS=OFF -DLLVM_INCLUDE_BENCHMARKS=OFF -DLLVM_INCLUDE_UTILS=OFF -DCMAKE_SYSTEM_VERSION=6.1 -DCMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION=$(WindowsTargetPlatformVersion) -DLLVM_USE_CRT_DEBUG=MDd -DLLVM_USE_CRT_RELEASE=MT -DLLVM_USE_INTEL_JITEVENTS=ON ../llvm/llvm</CmakeDebugCLI>
<CmakeCleanCLI>echo Cleaning..
for /F "delims= eol=|" %%f in ('
dir /b ^| findstr /V "[^.]*\build[^.]*\.vcxproj"') do (
+2 -2
View File
@@ -39,9 +39,9 @@
</ImportGroup>
<PropertyGroup Label="UserMacros">
<CmakeReleaseCLI>call vsdevcmd.bat -arch=amd64
cmake -G Ninja -DCMAKE_CXX_COMPILER="clang-cl.exe" -DCMAKE_C_COMPILER="clang-cl.exe" -DCMAKE_BUILD_TYPE="Release" -DLLVM_TARGETS_TO_BUILD=X86 -DLLVM_DEFAULT_TARGET_TRIPLE:STRING=x86_64-pc-windows-msvc -DLLVM_HOST_TRIPLE:STRING=x86_64-pc-windows-msvc -DCMAKE_INSTALL_PREFIX="./Release" -DLLVM_BUILD_RUNTIME=OFF -DLLVM_BUILD_TOOLS=OFF -DLLVM_INCLUDE_DOCS=OFF -DLLVM_INCLUDE_EXAMPLES=OFF -DLLVM_INCLUDE_TESTS=OFF -DLLVM_INCLUDE_BENCHMARKS=OFF -DLLVM_INCLUDE_UTILS=OFF -DCMAKE_SYSTEM_VERSION=6.1 -DCMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION=$(WindowsTargetPlatformVersion) -DLLVM_USE_CRT_DEBUG=MTd -DLLVM_USE_CRT_RELEASE=MT -DLLVM_USE_INTEL_JITEVENTS=ON ../llvm/llvm</CmakeReleaseCLI>
cmake -G Ninja -DCMAKE_CXX_COMPILER="clang-cl.exe" -DCMAKE_C_COMPILER="clang-cl.exe" -DCMAKE_BUILD_TYPE="Release" -DLLVM_TARGETS_TO_BUILD=X86 -DLLVM_DEFAULT_TARGET_TRIPLE:STRING=x86_64-pc-windows-msvc -DLLVM_HOST_TRIPLE:STRING=x86_64-pc-windows-msvc -DCMAKE_INSTALL_PREFIX="./Release" -DLLVM_BUILD_RUNTIME=OFF -DLLVM_BUILD_TOOLS=OFF -DLLVM_INCLUDE_DOCS=OFF -DLLVM_INCLUDE_EXAMPLES=OFF -DLLVM_INCLUDE_TESTS=OFF -DLLVM_INCLUDE_BENCHMARKS=OFF -DLLVM_INCLUDE_UTILS=OFF -DCMAKE_SYSTEM_VERSION=6.1 -DCMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION=$(WindowsTargetPlatformVersion) -DLLVM_USE_CRT_DEBUG=MDd -DLLVM_USE_CRT_RELEASE=MT -DLLVM_USE_INTEL_JITEVENTS=ON ../llvm/llvm</CmakeReleaseCLI>
<CmakeDebugCLI>call vsdevcmd.bat -arch=amd64
cmake -G Ninja -DCMAKE_CXX_COMPILER="clang-cl.exe" -DCMAKE_C_COMPILER="clang-cl.exe" -DCMAKE_BUILD_TYPE="Debug" -DLLVM_TARGETS_TO_BUILD=X86 -DLLVM_DEFAULT_TARGET_TRIPLE:STRING=x86_64-pc-windows-msvc -DLLVM_HOST_TRIPLE:STRING=x86_64-pc-windows-msvc -DCMAKE_INSTALL_PREFIX="./Debug" -DLLVM_BUILD_RUNTIME=OFF -DLLVM_BUILD_TOOLS=OFF -DLLVM_INCLUDE_DOCS=OFF -DLLVM_INCLUDE_EXAMPLES=OFF -DLLVM_INCLUDE_TESTS=OFF -DLLVM_INCLUDE_BENCHMARKS=OFF -DLLVM_INCLUDE_UTILS=OFF -DCMAKE_SYSTEM_VERSION=6.1 -DCMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION=$(WindowsTargetPlatformVersion) -DLLVM_USE_CRT_DEBUG=MTd -DLLVM_USE_CRT_RELEASE=MT -DLLVM_USE_INTEL_JITEVENTS=ON ../llvm/llvm</CmakeDebugCLI>
cmake -G Ninja -DCMAKE_CXX_COMPILER="clang-cl.exe" -DCMAKE_C_COMPILER="clang-cl.exe" -DCMAKE_BUILD_TYPE="Debug" -DLLVM_TARGETS_TO_BUILD=X86 -DLLVM_DEFAULT_TARGET_TRIPLE:STRING=x86_64-pc-windows-msvc -DLLVM_HOST_TRIPLE:STRING=x86_64-pc-windows-msvc -DCMAKE_INSTALL_PREFIX="./Debug" -DLLVM_BUILD_RUNTIME=OFF -DLLVM_BUILD_TOOLS=OFF -DLLVM_INCLUDE_DOCS=OFF -DLLVM_INCLUDE_EXAMPLES=OFF -DLLVM_INCLUDE_TESTS=OFF -DLLVM_INCLUDE_BENCHMARKS=OFF -DLLVM_INCLUDE_UTILS=OFF -DCMAKE_SYSTEM_VERSION=6.1 -DCMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION=$(WindowsTargetPlatformVersion) -DLLVM_USE_CRT_DEBUG=MDd -DLLVM_USE_CRT_RELEASE=MT -DLLVM_USE_INTEL_JITEVENTS=ON ../llvm/llvm</CmakeDebugCLI>
<CmakeCleanCLI>echo Cleaning..
for /F "delims= eol=|" %%f in ('
dir /b ^| findstr /V "[^.]*\build[^.]*\.vcxproj"') do (
-2
View File
@@ -58,7 +58,6 @@
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
<AdditionalIncludeDirectories>generated;miniupnp\miniupnpc;miniupnp\miniupnpc\include</AdditionalIncludeDirectories>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
@@ -80,7 +79,6 @@ cscript genminiupnpcstrings.vbs</Command>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
<AdditionalIncludeDirectories>generated;miniupnp\miniupnpc;miniupnp\miniupnpc\include</AdditionalIncludeDirectories>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
</ClCompile>
<Link>
<SubSystem>
+1
View File
@@ -18,6 +18,7 @@ else()
set(WOLFSSL_SNI ON CACHE STRING "Enable SNI (default: disabled)")
set(WOLFSSL_OPENSSLEXTRA ON CACHE STRING "Enable extra OpenSSL API, size+ (default: disabled)")
set(WOLFSSL_HARDEN OFF CACHE STRING "Enable Hardened build, Enables Timing Resistance and Blinding (default: enabled)")
set(WOLFSSL_ALT_CERT_CHAINS ON CACHE STRING "Enable support for Alternate certification chains (default: disabled)")
add_subdirectory(wolfssl EXCLUDE_FROM_ALL)
+3
View File
@@ -51,6 +51,9 @@
#define ECC_TIMING_RESISTANT
#define USE_FAST_MATH
#define FP_MAX_BITS 8192
#ifndef WOLFSSL_ALT_CERT_CHAINS
#define WOLFSSL_ALT_CERT_CHAINS
#endif
/* UTF-8 aware filesystem functions for Windows */
#define WOLFSSL_USER_FILESYSTEM
+3 -1
View File
@@ -15,5 +15,7 @@ else()
target_include_directories(3rdparty_zlib INTERFACE zlib ${CMAKE_CURRENT_BINARY_DIR}/zlib)
target_compile_definitions(3rdparty_zlib INTERFACE -DZLIB_CONST=1)
set(ZLIB_ROOT ${CMAKE_CURRENT_BINARY_DIR}/zlib PARENT_SCOPE)
if(NOT MSVC)
set(ZLIB_ROOT ${CMAKE_CURRENT_BINARY_DIR}/zlib PARENT_SCOPE)
endif()
endif()
-1
View File
@@ -88,7 +88,6 @@
<FunctionLevelLinking>true</FunctionLevelLinking>
<DisableSpecificWarnings>$(DisableSpecificWarnings);4127;4131;4242;4244</DisableSpecificWarnings>
<TreatWarningAsError>$(TreatWarningAsError)</TreatWarningAsError>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
+9 -7
View File
@@ -5,15 +5,17 @@ Other instructions may be found [here](https://wiki.rpcs3.net/index.php?title=Bu
## Setup your environment
### Windows 7 or later
### Windows 10 or later
* [CMake 3.28.0+](https://www.cmake.org/download/) (add to PATH)
* [Python 3.6+](https://www.python.org/downloads/) (add to PATH)
* [Qt 6.6.2](https://www.qt.io/download-qt-installer)
* [Qt 6.6.3](https://www.qt.io/download-qt-installer)
* [Visual Studio 2022](https://visualstudio.microsoft.com/thank-you-downloading-visual-studio/?sku=Community) (or at least Visual Studio 2019 16.11.xx+ as C++20 is not included in previous versions)
* [Vulkan SDK 1.3.268.0](https://vulkan.lunarg.com/sdk/home) (See "Install the SDK" [here](https://vulkan.lunarg.com/doc/sdk/latest/windows/getting_started.html)) for now future SDKs don't work. You need precisely 1.3.268.0.
**Either add the** `QTDIR` **environment variable, e.g.** `<QtInstallFolder>\6.6.2\msvc2019_64\` **, or use the [Visual Studio Qt Plugin](https://marketplace.visualstudio.com/items?itemName=TheQtCompany.QtVisualStudioTools2019)**
**Either add the** `QTDIR` **environment variable, e.g.** `<QtInstallFolder>\6.6.3\msvc2019_64\` **, or use the [Visual Studio Qt Plugin](https://marketplace.visualstudio.com/items?itemName=TheQtCompany.QtVisualStudioTools2019)**
**NOTE: If you have issues with the Qt plugin, you may want to uninstall the Qt Plugin and install the [Legacy Qt Plugin](https://marketplace.visualstudio.com/items?itemName=TheQtCompany.LEGACYQtVisualStudioTools2019) instead.**
### Linux
@@ -21,7 +23,7 @@ These are the essentials tools to build RPCS3 on Linux. Some of them can be inst
* Clang 12+ or GCC 11+
* [CMake 3.28.0+](https://www.cmake.org/download/)
* [Qt 6.6.2](https://www.qt.io/download-qt-installer)
* [Qt 6.6.3](https://www.qt.io/download-qt-installer)
* [Vulkan SDK 1.3.268.0](https://vulkan.lunarg.com/sdk/home) (See "Install the SDK" [here](https://vulkan.lunarg.com/doc/sdk/latest/linux/getting_started.html)) for now future SDKs don't work. You need precisely 1.3.268.0.
* [SDL2](https://github.com/libsdl-org/SDL/releases) (for the FAudio backend)
@@ -96,9 +98,9 @@ git submodule update --init
#### Configuring the Qt plugin (if used)
1) Go to `Extensions->Qt VS Tools->Qt Versions`.
2) Add the path to your Qt installation with compiler e.g. `<QtInstallFolder>\6.6.2\msvc2019_64`, version will fill in automatically.
3) Go to `Extensions->Qt VS Tools->Options->Legacy Project Format`.
4) Set `Build: Run pre-build setup` to `true`.
2) Add the path to your Qt installation with compiler e.g. `<QtInstallFolder>\6.6.3\msvc2019_64`, version will fill in automatically.
3) Go to `Extensions->Qt VS Tools->Options->Legacy Project Format`. (Only available in the legacy Qt plugin)
4) Set `Build: Run pre-build setup` to `true`. (Only available in the legacy Qt plugin)
#### Building the projects
+1 -1
View File
@@ -13,7 +13,7 @@ struct bf_base
{
using type = T;
using vtype = std::common_type_t<type>;
using utype = typename std::make_unsigned<vtype>::type;
using utype = std::make_unsigned_t<vtype>;
static constexpr bool can_be_packed = N < (sizeof(int) * 8 + (std::is_unsigned_v<vtype> ? 1 : 0)) && sizeof(vtype) > sizeof(int);
using compact_type = std::conditional_t<can_be_packed, std::conditional_t<std::is_unsigned_v<vtype>, uint, int>, vtype>;
+2
View File
@@ -19,6 +19,7 @@ LOG_CHANNEL(jit_log, "JIT");
void jit_announce(uptr func, usz size, std::string_view name)
{
#ifdef __linux__
#if 0
static const struct tmp_perf_map
{
std::string name{fmt::format("/tmp/perf-%d.map", getpid())};
@@ -44,6 +45,7 @@ void jit_announce(uptr func, usz size, std::string_view name)
fs::remove_file(s_map.name);
return;
}
#endif
#endif
if (!size)
+5
View File
@@ -30,6 +30,7 @@ LOG_CHANNEL(jit_log, "JIT");
#pragma GCC diagnostic ignored "-Weffc++"
#pragma GCC diagnostic ignored "-Wmissing-noreturn"
#endif
#include <llvm/Support/CodeGen.h>
#include "llvm/Support/TargetSelect.h"
#include "llvm/TargetParser/Host.h"
#include "llvm/ExecutionEngine/ExecutionEngine.h"
@@ -542,7 +543,11 @@ jit_compiler::jit_compiler(const std::unordered_map<std::string, u64>& _link, co
.setErrorStr(&result)
.setEngineKind(llvm::EngineKind::JIT)
.setMCJITMemoryManager(std::move(mem))
#if LLVM_VERSION_MAJOR < 18
.setOptLevel(llvm::CodeGenOpt::Aggressive)
#else
.setOptLevel(llvm::CodeGenOptLevel::Aggressive)
#endif
.setCodeModel(flags & 0x2 ? llvm::CodeModel::Large : llvm::CodeModel::Small)
#ifdef __APPLE__
//.setCodeModel(llvm::CodeModel::Large)
+1 -1
View File
@@ -518,7 +518,7 @@ struct fmt::cfmt_src
TYPE(llong);
TYPE(schar);
TYPE(short);
if (std::is_signed<char>::value) TYPE(char);
if (std::is_signed_v<char>) TYPE(char);
TYPE(long);
TYPE(s128);
+3 -3
View File
@@ -54,7 +54,7 @@ struct fmt_unveil
};
template <typename T>
struct fmt_unveil<T, std::enable_if_t<std::is_integral<T>::value && sizeof(T) <= 8 && alignof(T) <= 8>>
struct fmt_unveil<T, std::enable_if_t<std::is_integral_v<T> && sizeof(T) <= 8 && alignof(T) <= 8>>
{
using type = T;
@@ -65,7 +65,7 @@ struct fmt_unveil<T, std::enable_if_t<std::is_integral<T>::value && sizeof(T) <=
};
template <typename T>
struct fmt_unveil<T, std::enable_if_t<std::is_floating_point<T>::value && sizeof(T) <= 8 && alignof(T) <= 8>>
struct fmt_unveil<T, std::enable_if_t<std::is_floating_point_v<T> && sizeof(T) <= 8 && alignof(T) <= 8>>
{
using type = T;
@@ -77,7 +77,7 @@ struct fmt_unveil<T, std::enable_if_t<std::is_floating_point<T>::value && sizeof
};
template <typename T>
struct fmt_unveil<T, std::enable_if_t<std::is_enum<T>::value>>
struct fmt_unveil<T, std::enable_if_t<std::is_enum_v<T>>>
{
using type = T;
+19 -1
View File
@@ -2193,7 +2193,10 @@ u64 thread_base::finalize(thread_state result_state) noexcept
return thread_ctrl::get_name_cached();
};
sig_log.notice("Thread time: %fs (%fGc); Faults: %u [rsx:%u, spu:%u]; [soft:%u hard:%u]; Switches:[vol:%u unvol:%u]; Wait:[%.3fs, spur:%u]",
const bool is_cpu_thread = !!cpu_thread::get_current();
auto& thread_log = (is_cpu_thread || g_tls_fault_all ? sig_log.notice : sig_log.trace);
thread_log("Thread time: %fs (%fGc); Faults: %u [rsx:%u, spu:%u]; [soft:%u hard:%u]; Switches:[vol:%u unvol:%u]; Wait:[%.3fs, spur:%u]",
time / 1000000000.,
cycles / 1000000000.,
g_tls_fault_all,
@@ -2640,6 +2643,21 @@ void thread_base::exec()
sys_log.notice("\n%s", info);
}
std::string reason_buf;
if (auto ppu = cpu_thread::get_current<ppu_thread>())
{
if (auto func = ppu->current_function)
{
fmt::append(reason_buf, "%s (PPU: %s)", reason, func);
}
}
if (!reason_buf.empty())
{
reason = reason_buf;
}
sig_log.fatal("Thread terminated due to fatal error: %s", reason);
logs::listener::sync_all();
+5
View File
@@ -218,6 +218,11 @@ public:
// Get current thread name
static std::string get_name()
{
if (!g_tls_this_thread)
{
return "not named_thread";
}
return *g_tls_this_thread->m_tname.load();
}
+2 -2
View File
@@ -60,9 +60,9 @@ public:
static constexpr usz bitmax = sizeof(T) * 8;
static constexpr usz bitsize = static_cast<under>(T::__bitset_enum_max);
static_assert(std::is_enum<T>::value, "bs_t<> error: invalid type (must be enum)");
static_assert(std::is_enum_v<T>, "bs_t<> error: invalid type (must be enum)");
static_assert(bitsize <= bitmax, "bs_t<> error: invalid __bitset_enum_max");
static_assert(bitsize != bitmax || std::is_unsigned<under>::value, "bs_t<> error: invalid __bitset_enum_max (sign bit)");
static_assert(bitsize != bitmax || std::is_unsigned_v<under>, "bs_t<> error: invalid __bitset_enum_max (sign bit)");
// Helper function
static constexpr under shift(T value)
+5 -5
View File
@@ -38,13 +38,13 @@ jobs:
displayName: ccache
- bash: |
docker pull --quiet rpcs3/rpcs3-ci-focal:1.6
docker pull --quiet rpcs3/rpcs3-ci-focal:1.7
docker run \
-v $(pwd):/rpcs3 \
--env-file .ci/docker.env \
-v $CCACHE_DIR:/root/.ccache \
-v $BUILD_ARTIFACTSTAGINGDIRECTORY:/root/artifacts \
rpcs3/rpcs3-ci-focal:1.6 \
rpcs3/rpcs3-ci-focal:1.7 \
/rpcs3/.ci/build-linux.sh
displayName: Docker setup and build
@@ -69,9 +69,9 @@ jobs:
variables:
COMPILER: msvc
QT_VER_MAIN: '6'
QT_VER: '6.6.2'
QT_VER: '6.6.3'
QT_VER_MSVC: 'msvc2019'
QT_DATE: '202402121135'
QT_DATE: '202403191840'
QTDIR: C:\Qt\$(QT_VER)\$(QT_VER_MSVC)_64
VULKAN_VER: '1.3.268.0'
VULKAN_SDK_SHA: '8459ef49bd06b697115ddd3d97c9aec729e849cd775f5be70897718a9b3b9db5'
@@ -132,7 +132,7 @@ jobs:
UPLOAD_REPO_FULL_NAME: "RPCS3/rpcs3-binaries-mac"
RELEASE_MESSAGE: "../GitHubReleaseMessage.txt"
ARTDIR: $(Build.ArtifactStagingDirectory)
QT_VER: '6.6.2'
QT_VER: '6.6.3'
QT_VER_MAIN: '6'
pool:
Binary file not shown.
+1 -1
View File
@@ -71,6 +71,7 @@ else()
if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
add_compile_options(-Werror=inconsistent-missing-override)
add_compile_options(-Werror=delete-non-virtual-dtor)
elseif(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
add_compile_options(-Werror=suggest-override)
add_compile_options(-Wclobbered)
@@ -84,7 +85,6 @@ else()
add_compile_options(-fconstexpr-steps=16777216)
add_compile_options(-Wno-unused-lambda-capture)
add_compile_options(-Wno-unused-private-field)
add_compile_options(-Wno-delete-non-virtual-dtor)
add_compile_options(-Wno-unused-command-line-argument)
elseif(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
add_compile_options(-Wno-class-memaccess)
+1 -1
View File
@@ -18,7 +18,7 @@
<ExceptionHandling>false</ExceptionHandling>
<AdditionalOptions>-d2FH4- %(AdditionalOptions)</AdditionalOptions>
<RuntimeLibrary Condition = "$(Configuration.Contains('Release'))">MultiThreaded</RuntimeLibrary>
<RuntimeLibrary Condition = "$(Configuration.Contains('Debug'))">MultiThreadedDebug</RuntimeLibrary>
<RuntimeLibrary Condition = "$(Configuration.Contains('Debug'))">MultiThreadedDebugDLL</RuntimeLibrary>
</ClCompile>
<Link>
<AdditionalOptions>-d2:-FH4- %(AdditionalOptions)</AdditionalOptions>
@@ -17,7 +17,7 @@
<ExceptionHandling>false</ExceptionHandling>
<AdditionalOptions>%(AdditionalOptions)</AdditionalOptions>
<RuntimeLibrary Condition = "$(Configuration.Contains('Release'))">MultiThreaded</RuntimeLibrary>
<RuntimeLibrary Condition = "$(Configuration.Contains('Debug'))">MultiThreadedDebug</RuntimeLibrary>
<RuntimeLibrary Condition = "$(Configuration.Contains('Debug'))">MultiThreadedDebugDLL</RuntimeLibrary>
</ClCompile>
<Link>
<AdditionalOptions>%(AdditionalOptions)</AdditionalOptions>
+1 -1
View File
@@ -10,7 +10,7 @@
<ClCompile>
<PreprocessorDefinitions>_SCL_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<Optimization>Disabled</Optimization>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
<PreprocessorDefinitions>LLVM_AVAILABLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
+4 -4
View File
@@ -128,10 +128,10 @@ Global
{EB33566E-DA7F-4D28-9077-88C0B7C77E35}.Debug|x64.Build.0 = Release|x64
{EB33566E-DA7F-4D28-9077-88C0B7C77E35}.Release|x64.ActiveCfg = Release|x64
{EB33566E-DA7F-4D28-9077-88C0B7C77E35}.Release|x64.Build.0 = Release|x64
{D6973076-9317-4EF2-A0B8-B7A18AC0713E}.Debug|x64.ActiveCfg = Debug Library|x64
{D6973076-9317-4EF2-A0B8-B7A18AC0713E}.Debug|x64.Build.0 = Debug Library|x64
{D6973076-9317-4EF2-A0B8-B7A18AC0713E}.Release|x64.ActiveCfg = Release Library|x64
{D6973076-9317-4EF2-A0B8-B7A18AC0713E}.Release|x64.Build.0 = Release Library|x64
{D6973076-9317-4EF2-A0B8-B7A18AC0713E}.Debug|x64.ActiveCfg = Debug|x64
{D6973076-9317-4EF2-A0B8-B7A18AC0713E}.Debug|x64.Build.0 = Debug|x64
{D6973076-9317-4EF2-A0B8-B7A18AC0713E}.Release|x64.ActiveCfg = Release|x64
{D6973076-9317-4EF2-A0B8-B7A18AC0713E}.Release|x64.Build.0 = Release|x64
{60F89955-91C6-3A36-8000-13C592FEC2DF}.Debug|x64.ActiveCfg = Debug|x64
{60F89955-91C6-3A36-8000-13C592FEC2DF}.Debug|x64.Build.0 = Debug|x64
{60F89955-91C6-3A36-8000-13C592FEC2DF}.Release|x64.ActiveCfg = Release|x64
+5 -1
View File
@@ -74,6 +74,7 @@ usz decrypt_binaries_t::decrypt(std::string klic_input)
const std::string old_path = _module;
fs::file elf_file;
fs::file internal_file;
bool invalid = false;
usz key_it = 0;
@@ -83,6 +84,8 @@ usz decrypt_binaries_t::decrypt(std::string klic_input)
{
for (; key_it < m_klics.size(); key_it++)
{
internal_file.close();
if (!elf_file.open(old_path) || !elf_file.read(file_magic))
{
file_magic = 0;
@@ -106,7 +109,8 @@ usz decrypt_binaries_t::decrypt(std::string klic_input)
case "NPD\0"_u32:
{
// EDAT / SDAT
elf_file = DecryptEDAT(elf_file, old_path, key_it != 0 ? 8 : 1, reinterpret_cast<u8*>(&m_klics[key_it]));
internal_file = std::move(elf_file);
elf_file = DecryptEDAT(internal_file, old_path, key_it != 0 ? 8 : 1, reinterpret_cast<u8*>(&m_klics[key_it]));
if (!elf_file)
{
+2 -1
View File
@@ -139,7 +139,8 @@ bool zip(const void* src, usz size, fs::file& out, bool multi_thread_it)
return false;
}
utils::serial compressor(!multi_thread_it || size < 0x40'0000);
utils::serial compressor;
compressor.set_expect_little_data(!multi_thread_it || size < 0x40'0000);
compressor.m_file_handler = make_compressed_serialization_file_handler(out);
std::string_view buffer_view{static_cast<const char*>(src), size};
+62 -17
View File
@@ -33,7 +33,12 @@ u32 AudioBackend::get_sample_size() const
u32 AudioBackend::get_channels() const
{
return static_cast<std::underlying_type_t<decltype(m_channels)>>(m_channels);
return m_channels;
}
audio_channel_layout AudioBackend::get_channel_layout() const
{
return m_layout;
}
bool AudioBackend::get_convert_to_s16() const
@@ -141,23 +146,63 @@ AudioChannelCnt AudioBackend::get_max_channel_count(u32 device_index)
return count;
}
AudioChannelCnt AudioBackend::convert_channel_count(u64 raw)
u32 AudioBackend::default_layout_channel_count(audio_channel_layout layout)
{
switch (raw)
switch (layout)
{
default:
case 8:
return AudioChannelCnt::SURROUND_7_1;
case 7:
case 6:
return AudioChannelCnt::SURROUND_5_1;
case 5:
case 4:
case 3:
case 2:
case 1:
return AudioChannelCnt::STEREO;
case 0:
fmt::throw_exception("Unsupported channel count");
case audio_channel_layout::mono: return 1;
case audio_channel_layout::stereo: return 2;
case audio_channel_layout::stereo_lfe: return 3;
case audio_channel_layout::quadraphonic: return 4;
case audio_channel_layout::quadraphonic_lfe: return 5;
case audio_channel_layout::surround_5_1: return 6;
case audio_channel_layout::surround_7_1: return 8;
default: fmt::throw_exception("Unsupported layout %d", static_cast<u32>(layout));
}
}
u32 AudioBackend::layout_channel_count(u32 channels, audio_channel_layout layout)
{
if (channels == 0)
{
fmt::throw_exception("Unsupported channel count");
}
return std::min(channels, default_layout_channel_count(layout));
}
audio_channel_layout AudioBackend::default_layout(u32 channels)
{
switch (channels)
{
case 1: return audio_channel_layout::mono;
case 2: return audio_channel_layout::stereo;
case 3: return audio_channel_layout::stereo_lfe;
case 4: return audio_channel_layout::quadraphonic;
case 5: return audio_channel_layout::quadraphonic_lfe;
case 6: return audio_channel_layout::surround_5_1;
case 7: return audio_channel_layout::surround_5_1;
case 8: return audio_channel_layout::surround_7_1;
default: return audio_channel_layout::stereo;
}
}
void AudioBackend::setup_channel_layout(u32 input_channel_count, u32 output_channel_count, audio_channel_layout layout, logs::channel& log)
{
const u32 channels = std::min(input_channel_count, output_channel_count);
if (layout != audio_channel_layout::automatic && output_channel_count > input_channel_count)
{
log.warning("Mixing from %d to %d channels is not implemented. Falling back to automatic layout.", input_channel_count, output_channel_count);
layout = audio_channel_layout::automatic;
}
if (layout != audio_channel_layout::automatic && channels < default_layout_channel_count(layout))
{
log.warning("Can't use layout %s with %d channels. Falling back to automatic layout.", layout, channels);
layout = audio_channel_layout::automatic;
}
m_layout = layout == audio_channel_layout::automatic ? default_layout(channels) : layout;
m_channels = layout_channel_count(channels, m_layout);
}
+156 -45
View File
@@ -1,8 +1,10 @@
#pragma once
#include "util/types.hpp"
#include "util/logs.hpp"
#include "Utilities/mutex.h"
#include "Utilities/StrFmt.h"
#include "Emu/system_config_types.h"
#include <numbers>
enum : u32
@@ -30,6 +32,7 @@ enum class AudioSampleSize : u32
S16 = sizeof(s16),
};
// This enum is only used for emulation
enum class AudioChannelCnt : u32
{
STEREO = 2,
@@ -69,7 +72,7 @@ public:
// If dev_id is empty, then default device will be selected.
// May override channel count if device has smaller number of channels.
// Should return 'true' on success.
virtual bool Open(std::string_view dev_id, AudioFreq freq, AudioSampleSize sample_size, AudioChannelCnt ch_cnt) = 0;
virtual bool Open(std::string_view dev_id, AudioFreq freq, AudioSampleSize sample_size, AudioChannelCnt ch_cnt, audio_channel_layout layout) = 0;
// Reset backend state. Blocks until data callback returns.
virtual void Close() = 0;
@@ -122,6 +125,7 @@ public:
u32 get_sample_size() const;
u32 get_channels() const;
audio_channel_layout get_channel_layout() const;
bool get_convert_to_s16() const;
@@ -158,51 +162,91 @@ public:
*/
static AudioChannelCnt get_max_channel_count(u32 device_index);
/*
* Get default channel count for a layout
*/
static u32 default_layout_channel_count(audio_channel_layout layout);
/*
* Converts raw channel count to value usable by backends
*/
static AudioChannelCnt convert_channel_count(u64 raw);
static u32 layout_channel_count(u32 channels, audio_channel_layout layout);
/*
* Get the default layout for raw channel count
*/
static audio_channel_layout default_layout(u32 channels);
/*
* Downmix audio stream.
*/
template<AudioChannelCnt from, AudioChannelCnt to>
template<AudioChannelCnt src_ch_cnt, audio_channel_layout dst_layout>
static void downmix(u32 sample_cnt, const f32* src, f32* dst)
{
static_assert(from == AudioChannelCnt::SURROUND_5_1 || from == AudioChannelCnt::SURROUND_7_1, "Cannot downmix FROM channel count");
static_assert(static_cast<u32>(from) > static_cast<u32>(to), "FROM channel count must be bigger than TO");
const u32 dst_ch_cnt = default_layout_channel_count(dst_layout);
if (static_cast<u32>(src_ch_cnt) <= dst_ch_cnt) fmt::throw_exception("src channel count must be bigger than dst channel count");
static constexpr f32 center_coef = std::numbers::sqrt2_v<f32> / 2;
static constexpr f32 surround_coef = std::numbers::sqrt2_v<f32> / 2;
for (u32 src_sample = 0, dst_sample = 0; src_sample < sample_cnt; src_sample += static_cast<u32>(from), dst_sample += static_cast<u32>(to))
for (u32 src_sample = 0, dst_sample = 0; src_sample < sample_cnt; src_sample += static_cast<u32>(src_ch_cnt), dst_sample += dst_ch_cnt)
{
const f32 left = src[src_sample + 0];
const f32 right = src[src_sample + 1];
const f32 center = src[src_sample + 2];
const f32 low_freq = src[src_sample + 3];
if constexpr (from == AudioChannelCnt::SURROUND_5_1)
const f32 left = src[src_sample + 0];
const f32 right = src[src_sample + 1];
if constexpr (src_ch_cnt == AudioChannelCnt::STEREO)
{
static_assert(to == AudioChannelCnt::STEREO, "Invalid TO channel count");
if constexpr (dst_layout == audio_channel_layout::mono)
{
dst[dst_sample + 0] = left + right;
}
}
else if constexpr (src_ch_cnt == AudioChannelCnt::SURROUND_5_1)
{
const f32 center = src[src_sample + 2];
const f32 low_freq = src[src_sample + 3];
const f32 side_left = src[src_sample + 4];
const f32 side_right = src[src_sample + 5];
const f32 mid = center * center_coef;
dst[dst_sample + 0] = left + mid + side_left * surround_coef;
dst[dst_sample + 1] = right + mid + side_right * surround_coef;
}
else if constexpr (from == AudioChannelCnt::SURROUND_7_1)
{
static_assert(to == AudioChannelCnt::STEREO || to == AudioChannelCnt::SURROUND_5_1, "Invalid TO channel count");
if constexpr (dst_layout == audio_channel_layout::quadraphonic || dst_layout == audio_channel_layout::quadraphonic_lfe)
{
const f32 mid = center * center_coef;
dst[dst_sample + 0] = left + mid;
dst[dst_sample + 1] = right + mid;
dst[dst_sample + 2] = side_left;
dst[dst_sample + 3] = side_right;
if constexpr (dst_layout == audio_channel_layout::quadraphonic_lfe)
{
dst[dst_sample + 4] = low_freq;
}
}
else if constexpr (dst_layout == audio_channel_layout::stereo || dst_layout == audio_channel_layout::stereo_lfe)
{
const f32 mid = center * center_coef;
dst[dst_sample + 0] = left + mid + side_left * surround_coef;
dst[dst_sample + 1] = right + mid + side_right * surround_coef;
if constexpr (dst_layout == audio_channel_layout::stereo_lfe)
{
dst[dst_sample + 2] = low_freq;
}
}
else if constexpr (dst_layout == audio_channel_layout::mono)
{
dst[dst_sample + 0] = left + right + center + side_left + side_right;
}
}
else if constexpr (src_ch_cnt == AudioChannelCnt::SURROUND_7_1)
{
const f32 center = src[src_sample + 2];
const f32 low_freq = src[src_sample + 3];
const f32 rear_left = src[src_sample + 4];
const f32 rear_right = src[src_sample + 5];
const f32 side_left = src[src_sample + 6];
const f32 side_right = src[src_sample + 7];
if constexpr (to == AudioChannelCnt::SURROUND_5_1)
if constexpr (dst_layout == audio_channel_layout::surround_5_1)
{
dst[dst_sample + 0] = left;
dst[dst_sample + 1] = right;
@@ -211,59 +255,126 @@ public:
dst[dst_sample + 4] = side_left + rear_left;
dst[dst_sample + 5] = side_right + rear_right;
}
else
else if constexpr (dst_layout == audio_channel_layout::quadraphonic || dst_layout == audio_channel_layout::quadraphonic_lfe)
{
const f32 mid = center * center_coef;
dst[dst_sample + 0] = left + mid;
dst[dst_sample + 1] = right + mid;
dst[dst_sample + 2] = side_left + rear_left;
dst[dst_sample + 3] = side_right + rear_right;
if constexpr (dst_layout == audio_channel_layout::quadraphonic_lfe)
{
dst[dst_sample + 4] = low_freq;
}
}
else if constexpr (dst_layout == audio_channel_layout::stereo || dst_layout == audio_channel_layout::stereo_lfe)
{
const f32 mid = center * center_coef;
dst[dst_sample + 0] = left + mid + (side_left + rear_left) * surround_coef;
dst[dst_sample + 1] = right + mid + (side_right + rear_right) * surround_coef;
if constexpr (dst_layout == audio_channel_layout::stereo_lfe)
{
dst[dst_sample + 2] = low_freq;
}
}
else if constexpr (dst_layout == audio_channel_layout::mono)
{
dst[dst_sample + 0] = left + right + center + side_left + rear_left + side_right + rear_right;
}
}
}
}
static void downmix(u32 sample_cnt, u32 src_ch_cnt, u32 dst_ch_cnt, const f32* src, f32* dst)
static void downmix(u32 sample_cnt, u32 src_ch_cnt, audio_channel_layout dst_layout, const f32* src, f32* dst)
{
const u32 dst_ch_cnt = default_layout_channel_count(dst_layout);
if (src_ch_cnt <= dst_ch_cnt)
{
return;
}
if (src_ch_cnt == static_cast<u32>(AudioChannelCnt::SURROUND_7_1))
switch (src_ch_cnt)
{
if (dst_ch_cnt == static_cast<u32>(AudioChannelCnt::SURROUND_5_1))
case static_cast<u32>(AudioChannelCnt::SURROUND_7_1):
{
switch (dst_layout)
{
AudioBackend::downmix<AudioChannelCnt::SURROUND_7_1, AudioChannelCnt::SURROUND_5_1>(sample_cnt, src, dst);
}
else if (dst_ch_cnt == static_cast<u32>(AudioChannelCnt::STEREO))
{
AudioBackend::downmix<AudioChannelCnt::SURROUND_7_1, AudioChannelCnt::STEREO>(sample_cnt, src, dst);
}
else
{
fmt::throw_exception("Invalid downmix combination: %u -> %u", src_ch_cnt, dst_ch_cnt);
case audio_channel_layout::mono:
AudioBackend::downmix<AudioChannelCnt::SURROUND_7_1, audio_channel_layout::mono>(sample_cnt, src, dst);
break;
case audio_channel_layout::stereo:
AudioBackend::downmix<AudioChannelCnt::SURROUND_7_1, audio_channel_layout::stereo>(sample_cnt, src, dst);
break;
case audio_channel_layout::stereo_lfe:
AudioBackend::downmix<AudioChannelCnt::SURROUND_7_1, audio_channel_layout::stereo_lfe>(sample_cnt, src, dst);
break;
case audio_channel_layout::quadraphonic:
AudioBackend::downmix<AudioChannelCnt::SURROUND_7_1, audio_channel_layout::quadraphonic>(sample_cnt, src, dst);
break;
case audio_channel_layout::quadraphonic_lfe:
AudioBackend::downmix<AudioChannelCnt::SURROUND_7_1, audio_channel_layout::quadraphonic_lfe>(sample_cnt, src, dst);
break;
case audio_channel_layout::surround_5_1:
AudioBackend::downmix<AudioChannelCnt::SURROUND_7_1, audio_channel_layout::surround_5_1>(sample_cnt, src, dst);
break;
default:
fmt::throw_exception("Invalid downmix combination: %u -> %s", src_ch_cnt, dst_layout);
}
break;
}
else if (src_ch_cnt == static_cast<u32>(AudioChannelCnt::SURROUND_5_1))
case static_cast<u32>(AudioChannelCnt::SURROUND_5_1):
{
if (dst_ch_cnt == static_cast<u32>(AudioChannelCnt::STEREO))
switch (dst_layout)
{
AudioBackend::downmix<AudioChannelCnt::SURROUND_5_1, AudioChannelCnt::STEREO>(sample_cnt, src, dst);
}
else
{
fmt::throw_exception("Invalid downmix combination: %u -> %u", src_ch_cnt, dst_ch_cnt);
case audio_channel_layout::mono:
AudioBackend::downmix<AudioChannelCnt::SURROUND_5_1, audio_channel_layout::mono>(sample_cnt, src, dst);
break;
case audio_channel_layout::stereo:
AudioBackend::downmix<AudioChannelCnt::SURROUND_5_1, audio_channel_layout::stereo>(sample_cnt, src, dst);
break;
case audio_channel_layout::stereo_lfe:
AudioBackend::downmix<AudioChannelCnt::SURROUND_5_1, audio_channel_layout::stereo_lfe>(sample_cnt, src, dst);
break;
case audio_channel_layout::quadraphonic:
AudioBackend::downmix<AudioChannelCnt::SURROUND_5_1, audio_channel_layout::quadraphonic>(sample_cnt, src, dst);
break;
case audio_channel_layout::quadraphonic_lfe:
AudioBackend::downmix<AudioChannelCnt::SURROUND_5_1, audio_channel_layout::quadraphonic_lfe>(sample_cnt, src, dst);
break;
default:
fmt::throw_exception("Invalid downmix combination: %u -> %s", src_ch_cnt, dst_layout);
}
break;
}
else
case static_cast<u32>(AudioChannelCnt::STEREO):
{
fmt::throw_exception("Invalid downmix combination: %u -> %u", src_ch_cnt, dst_ch_cnt);
switch (dst_layout)
{
case audio_channel_layout::mono:
AudioBackend::downmix<AudioChannelCnt::STEREO, audio_channel_layout::mono>(sample_cnt, src, dst);
break;
default:
fmt::throw_exception("Invalid downmix combination: %u -> %s", src_ch_cnt, dst_layout);
}
break;
}
default:
{
fmt::throw_exception("Invalid downmix combination: %u -> %s", src_ch_cnt, dst_layout);
}
}
}
protected:
void setup_channel_layout(u32 input_channel_count, u32 output_channel_count, audio_channel_layout layout, logs::channel& log);
AudioSampleSize m_sample_size = AudioSampleSize::FLOAT;
AudioFreq m_sampling_rate = AudioFreq::FREQ_48K;
AudioChannelCnt m_channels = AudioChannelCnt::STEREO;
u32 m_channels = 2;
audio_channel_layout m_layout = audio_channel_layout::automatic;
std::timed_mutex m_cb_mutex{};
std::function<u32(u32, void *)> m_write_callback{};
+19 -10
View File
@@ -96,7 +96,7 @@ bool CubebBackend::DefaultDeviceChanged()
return !device.handle || device.id != m_default_device;
}
bool CubebBackend::Open(std::string_view dev_id, AudioFreq freq, AudioSampleSize sample_size, AudioChannelCnt ch_cnt)
bool CubebBackend::Open(std::string_view dev_id, AudioFreq freq, AudioSampleSize sample_size, AudioChannelCnt ch_cnt, audio_channel_layout layout)
{
if (!Initialized())
{
@@ -118,7 +118,7 @@ bool CubebBackend::Open(std::string_view dev_id, AudioFreq freq, AudioSampleSize
{
if (use_default_device)
{
device = GetDefaultDeviceAlt(freq, sample_size, ch_cnt);
device = GetDefaultDeviceAlt(freq, sample_size, static_cast<u32>(ch_cnt));
if (!device.handle)
{
@@ -138,6 +138,8 @@ bool CubebBackend::Open(std::string_view dev_id, AudioFreq freq, AudioSampleSize
device.ch_cnt = 2;
}
Cubeb.notice("Channel count is %d", device.ch_cnt);
if (use_default_device)
{
std::lock_guard lock{m_state_cb_mutex};
@@ -146,7 +148,9 @@ bool CubebBackend::Open(std::string_view dev_id, AudioFreq freq, AudioSampleSize
m_sampling_rate = freq;
m_sample_size = sample_size;
m_channels = static_cast<AudioChannelCnt>(std::min(static_cast<u32>(convert_channel_count(device.ch_cnt)), static_cast<u32>(ch_cnt)));
setup_channel_layout(static_cast<u32>(ch_cnt), device.ch_cnt, layout, Cubeb);
full_sample_size = get_channels() * get_sample_size();
cubeb_stream_params stream_param{};
@@ -155,14 +159,19 @@ bool CubebBackend::Open(std::string_view dev_id, AudioFreq freq, AudioSampleSize
stream_param.channels = get_channels();
stream_param.layout = [&]()
{
switch (m_channels)
switch (m_layout)
{
case AudioChannelCnt::STEREO: return CUBEB_LAYOUT_STEREO;
case AudioChannelCnt::SURROUND_5_1: return CUBEB_LAYOUT_3F2_LFE;
case AudioChannelCnt::SURROUND_7_1: return CUBEB_LAYOUT_3F4_LFE;
default:
fmt::throw_exception("Invalid audio channel count");
case audio_channel_layout::automatic: break;
case audio_channel_layout::mono: return CUBEB_LAYOUT_MONO;
case audio_channel_layout::stereo: return CUBEB_LAYOUT_STEREO;
case audio_channel_layout::stereo_lfe: return CUBEB_LAYOUT_STEREO_LFE;
case audio_channel_layout::quadraphonic: return CUBEB_LAYOUT_QUAD;
case audio_channel_layout::quadraphonic_lfe: return CUBEB_LAYOUT_QUAD_LFE;
case audio_channel_layout::surround_5_1: return CUBEB_LAYOUT_3F2_LFE;
case audio_channel_layout::surround_7_1: return CUBEB_LAYOUT_3F4_LFE;
}
fmt::throw_exception("Invalid audio layout %d", static_cast<u32>(m_layout));
}();
stream_param.prefs = m_dev_collection_cb_enabled && device.handle ? CUBEB_STREAM_PREF_DISABLE_DEVICE_SWITCHING : CUBEB_STREAM_PREF_NONE;
@@ -346,7 +355,7 @@ CubebBackend::device_handle CubebBackend::GetDevice(std::string_view dev_id)
return result;
};
CubebBackend::device_handle CubebBackend::GetDefaultDeviceAlt(AudioFreq freq, AudioSampleSize sample_size, AudioChannelCnt ch_cnt)
CubebBackend::device_handle CubebBackend::GetDefaultDeviceAlt(AudioFreq freq, AudioSampleSize sample_size, u32 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));
+2 -2
View File
@@ -22,7 +22,7 @@ public:
bool Operational() override;
bool DefaultDeviceChanged() override;
bool Open(std::string_view dev_id, AudioFreq freq, AudioSampleSize sample_size, AudioChannelCnt ch_cnt) override;
bool Open(std::string_view dev_id, AudioFreq freq, AudioSampleSize sample_size, AudioChannelCnt ch_cnt, audio_channel_layout layout) override;
void Close() override;
f64 GetCallbackFrameLen() override;
@@ -62,5 +62,5 @@ private:
};
device_handle GetDevice(std::string_view dev_id = "");
device_handle GetDefaultDeviceAlt(AudioFreq freq, AudioSampleSize sample_size, AudioChannelCnt ch_cnt);
device_handle GetDefaultDeviceAlt(AudioFreq freq, AudioSampleSize sample_size, u32 ch_cnt);
};
+5 -2
View File
@@ -122,7 +122,7 @@ bool FAudioBackend::Operational()
return m_source_voice != nullptr && !m_reset_req.observe();
}
bool FAudioBackend::Open(std::string_view dev_id, AudioFreq freq, AudioSampleSize sample_size, AudioChannelCnt ch_cnt)
bool FAudioBackend::Open(std::string_view dev_id, AudioFreq freq, AudioSampleSize sample_size, AudioChannelCnt ch_cnt, audio_channel_layout layout)
{
if (!Initialized())
{
@@ -161,9 +161,12 @@ bool FAudioBackend::Open(std::string_view dev_id, AudioFreq freq, AudioSampleSiz
return false;
}
FAudio_.notice("Channel count is %d", vd.InputChannels);
m_sampling_rate = freq;
m_sample_size = sample_size;
m_channels = static_cast<AudioChannelCnt>(std::min(static_cast<u32>(convert_channel_count(vd.InputChannels)), static_cast<u32>(ch_cnt)));;
setup_channel_layout(static_cast<u32>(ch_cnt), vd.InputChannels, layout, FAudio_);
FAudioWaveFormatEx waveformatex;
waveformatex.wFormatTag = get_convert_to_s16() ? FAUDIO_FORMAT_PCM : FAUDIO_FORMAT_IEEE_FLOAT;
+1 -1
View File
@@ -24,7 +24,7 @@ public:
bool Initialized() override;
bool Operational() override;
bool Open(std::string_view dev_id, AudioFreq freq, AudioSampleSize sample_size, AudioChannelCnt ch_cnt) override;
bool Open(std::string_view dev_id, AudioFreq freq, AudioSampleSize sample_size, AudioChannelCnt ch_cnt, audio_channel_layout layout) override;
void Close() override;
f64 GetCallbackFrameLen() override;
+1 -1
View File
@@ -10,7 +10,7 @@ public:
std::string_view GetName() const override { return "Null"sv; }
bool Open(std::string_view /* dev_id */, AudioFreq /* freq */, AudioSampleSize /* sample_size */, AudioChannelCnt /* ch_cnt */) override
bool Open(std::string_view /* dev_id */, AudioFreq /* freq */, AudioSampleSize /* sample_size */, AudioChannelCnt /* ch_cnt */, audio_channel_layout /*layout*/) override
{
Close();
return true;
+5 -2
View File
@@ -198,7 +198,7 @@ void XAudio2Backend::Pause()
}
}
bool XAudio2Backend::Open(std::string_view dev_id, AudioFreq freq, AudioSampleSize sample_size, AudioChannelCnt ch_cnt)
bool XAudio2Backend::Open(std::string_view dev_id, AudioFreq freq, AudioSampleSize sample_size, AudioChannelCnt ch_cnt, audio_channel_layout layout)
{
if (!Initialized())
{
@@ -254,9 +254,12 @@ bool XAudio2Backend::Open(std::string_view dev_id, AudioFreq freq, AudioSampleSi
return false;
}
XAudio.notice("Channel count is %d", vd.InputChannels);
m_sampling_rate = freq;
m_sample_size = sample_size;
m_channels = static_cast<AudioChannelCnt>(std::min(static_cast<u32>(convert_channel_count(vd.InputChannels)), static_cast<u32>(ch_cnt)));
setup_channel_layout(static_cast<u32>(ch_cnt), vd.InputChannels, layout, XAudio);
WAVEFORMATEX waveformatex{};
waveformatex.wFormatTag = get_convert_to_s16() ? WAVE_FORMAT_PCM : WAVE_FORMAT_IEEE_FLOAT;
+1 -1
View File
@@ -28,7 +28,7 @@ public:
bool Operational() override;
bool DefaultDeviceChanged() override;
bool Open(std::string_view dev_id, AudioFreq freq, AudioSampleSize sample_size, AudioChannelCnt ch_cnt) override;
bool Open(std::string_view dev_id, AudioFreq freq, AudioSampleSize sample_size, AudioChannelCnt ch_cnt, audio_channel_layout layout) override;
void Close() override;
f64 GetCallbackFrameLen() override;
+68 -57
View File
@@ -42,6 +42,7 @@ target_include_directories(rpcs3_emu
# Utilities
target_sources(rpcs3_emu PRIVATE
../util/atomic.cpp
../util/console.cpp
../util/media_utils.cpp
../util/video_provider.cpp
../util/logs.cpp
@@ -148,7 +149,7 @@ if(WIN32)
Audio/XAudio2/XAudio2Backend.cpp
Audio/XAudio2/xaudio2_enumerator.cpp
)
target_compile_definitions(rpcs3_emu PRIVATE UNICODE _UNICODE _WIN32_WINNT=0x0602)
target_compile_definitions(rpcs3_emu PRIVATE UNICODE _UNICODE _WIN32_WINNT=0x0A00)
endif()
target_link_libraries(rpcs3_emu
@@ -394,26 +395,28 @@ target_link_libraries(rpcs3_emu
# Io
target_sources(rpcs3_emu PRIVATE
Io/Buzz.cpp
Io/camera_config.cpp
Io/recording_config.cpp
Io/GameTablet.cpp
Io/GHLtar.cpp
Io/GunCon3.cpp
Io/Infinity.cpp
Io/interception.cpp
Io/KeyboardHandler.cpp
Io/midi_config_types.cpp
Io/pad_config.cpp
Io/pad_config_types.cpp
Io/PadHandler.cpp
Io/pad_types.cpp
Io/PadHandler.cpp
Io/rb3drums_config.cpp
Io/RB3MidiDrums.cpp
Io/RB3MidiGuitar.cpp
Io/RB3MidiKeyboard.cpp
Io/recording_config.cpp
Io/Skylander.cpp
Io/Turntable.cpp
Io/usb_device.cpp
Io/usb_vfs.cpp
Io/Infinity.cpp
Io/Skylander.cpp
Io/GHLtar.cpp
Io/midi_config_types.cpp
Io/RB3MidiKeyboard.cpp
Io/RB3MidiGuitar.cpp
Io/RB3MidiDrums.cpp
Io/rb3drums_config.cpp
Io/Buzz.cpp
Io/Turntable.cpp
Io/usio.cpp
)
@@ -446,24 +449,50 @@ target_sources(rpcs3_emu PRIVATE
# RSX
target_sources(rpcs3_emu PRIVATE
RSX/gcm_enums.cpp
RSX/gcm_printing.cpp
RSX/GSRender.cpp
RSX/RSXFIFO.cpp
RSX/rsx_methods.cpp
RSX/rsx_vertex_data.cpp
RSX/RSXOffload.cpp
RSX/RSXTexture.cpp
RSX/RSXThread.cpp
RSX/RSXZCULL.cpp
RSX/rsx_utils.cpp
RSX/RSXDisAsm.cpp
RSX/Capture/rsx_capture.cpp
RSX/Capture/rsx_replay.cpp
RSX/Common/BufferUtils.cpp
RSX/Common/surface_store.cpp
RSX/Common/TextureUtils.cpp
RSX/Common/texture_cache.cpp
RSX/Core/RSXContext.cpp
RSX/gcm_enums.cpp
RSX/gcm_printing.cpp
RSX/GL/GLCommonDecompiler.cpp
RSX/GL/GLCompute.cpp
RSX/GL/GLDraw.cpp
RSX/GL/GLFragmentProgram.cpp
RSX/GL/GLGSRender.cpp
RSX/GL/GLHelpers.cpp
RSX/GL/GLOverlays.cpp
RSX/GL/GLPipelineCompiler.cpp
RSX/GL/GLPresent.cpp
RSX/GL/GLRenderTargets.cpp
RSX/GL/GLShaderInterpreter.cpp
RSX/GL/GLTexture.cpp
RSX/GL/GLTextureCache.cpp
RSX/GL/glutils/blitter.cpp
RSX/GL/glutils/buffer_object.cpp
RSX/GL/glutils/capabilities.cpp
RSX/GL/glutils/common.cpp
RSX/GL/glutils/fbo.cpp
RSX/GL/glutils/image.cpp
RSX/GL/glutils/program.cpp
RSX/GL/glutils/ring_buffer.cpp
RSX/GL/glutils/sampler.cpp
RSX/GL/GLVertexBuffers.cpp
RSX/GL/GLVertexProgram.cpp
RSX/GL/OpenGL.cpp
RSX/GL/upscalers/fsr1/fsr_pass.cpp
RSX/GSRender.cpp
RSX/Null/NullGSRender.cpp
RSX/NV47/FW/reg_context.cpp
RSX/NV47/HW/common.cpp
RSX/NV47/HW/nv0039.cpp
RSX/NV47/HW/nv3089.cpp
RSX/NV47/HW/nv308a.cpp
RSX/NV47/HW/nv406e.cpp
RSX/NV47/HW/nv4097.cpp
RSX/Overlays/HomeMenu/overlay_home_menu.cpp
RSX/Overlays/HomeMenu/overlay_home_menu_components.cpp
RSX/Overlays/HomeMenu/overlay_home_menu_main_menu.cpp
@@ -472,8 +501,10 @@ target_sources(rpcs3_emu PRIVATE
RSX/Overlays/HomeMenu/overlay_home_menu_settings.cpp
RSX/Overlays/Network/overlay_recvmessage_dialog.cpp
RSX/Overlays/Network/overlay_sendmessage_dialog.cpp
RSX/Overlays/overlays.cpp
RSX/Overlays/overlay_animated_icon.cpp
RSX/Overlays/overlay_animation.cpp
RSX/Overlays/overlay_compile_notification.cpp
RSX/Overlays/overlay_controls.cpp
RSX/Overlays/overlay_cursor.cpp
RSX/Overlays/overlay_debug_overlay.cpp
@@ -489,48 +520,28 @@ target_sources(rpcs3_emu PRIVATE
RSX/Overlays/overlay_perf_metrics.cpp
RSX/Overlays/overlay_progress_bar.cpp
RSX/Overlays/overlay_save_dialog.cpp
RSX/Overlays/overlay_compile_notification.cpp
RSX/Overlays/overlay_trophy_notification.cpp
RSX/Overlays/overlay_user_list_dialog.cpp
RSX/Overlays/overlay_utils.cpp
RSX/Overlays/overlays.cpp
RSX/Overlays/overlay_trophy_notification.cpp
RSX/Overlays/Shaders/shader_loading_dialog.cpp
RSX/Overlays/Shaders/shader_loading_dialog_native.cpp
RSX/Program/CgBinaryFragmentProgram.cpp
RSX/Program/CgBinaryVertexProgram.cpp
RSX/Program/FragmentProgramDecompiler.cpp
RSX/Program/GLSLCommon.cpp
RSX/Program/program_util.cpp
RSX/Program/ProgramStateCache.cpp
RSX/Program/program_util.cpp
RSX/Program/SPIRVCommon.cpp
RSX/Program/VertexProgramDecompiler.cpp
RSX/Capture/rsx_capture.cpp
RSX/Capture/rsx_replay.cpp
RSX/GL/glutils/blitter.cpp
RSX/GL/glutils/buffer_object.cpp
RSX/GL/glutils/capabilities.cpp
RSX/GL/glutils/common.cpp
RSX/GL/glutils/fbo.cpp
RSX/GL/glutils/image.cpp
RSX/GL/glutils/program.cpp
RSX/GL/glutils/ring_buffer.cpp
RSX/GL/glutils/sampler.cpp
RSX/GL/upscalers/fsr1/fsr_pass.cpp
RSX/GL/GLCommonDecompiler.cpp
RSX/GL/GLCompute.cpp
RSX/GL/GLDraw.cpp
RSX/GL/GLFragmentProgram.cpp
RSX/GL/GLGSRender.cpp
RSX/GL/GLHelpers.cpp
RSX/GL/GLOverlays.cpp
RSX/GL/GLPipelineCompiler.cpp
RSX/GL/GLPresent.cpp
RSX/GL/GLRenderTargets.cpp
RSX/GL/GLShaderInterpreter.cpp
RSX/GL/GLTexture.cpp
RSX/GL/GLVertexBuffers.cpp
RSX/GL/GLVertexProgram.cpp
RSX/GL/GLTextureCache.cpp
RSX/GL/OpenGL.cpp
RSX/RSXDisAsm.cpp
RSX/RSXFIFO.cpp
RSX/RSXOffload.cpp
RSX/RSXTexture.cpp
RSX/RSXThread.cpp
RSX/RSXZCULL.cpp
RSX/rsx_methods.cpp
RSX/rsx_utils.cpp
RSX/rsx_vertex_data.cpp
)
if(TARGET 3rdparty_vulkan)
+79 -15
View File
@@ -89,6 +89,9 @@ struct cpu_prof
// Total number of samples
u64 samples = 0, idle = 0;
// Total number of sample collected in reservation operation
u64 reservation_samples = 0;
// Avoid printing replicas or when not much changed
u64 new_samples = 0;
@@ -101,6 +104,7 @@ struct cpu_prof
samples = 0;
idle = 0;
new_samples = 0;
reservation_samples = 0;
}
static std::string format(const std::multimap<u64, u64, std::greater<u64>>& chart, u64 samples, u64 idle, bool extended_print = false)
@@ -140,7 +144,7 @@ struct cpu_prof
{
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);
profiler.notice("Thread \"%s\" [0x%08x]: %u samples (%.4f%% idle), %u new, %u reservation (%.4f%%): Not enough new samples have been collected since the last print.", ptr->get_name(), ptr->id, samples, 100. * idle / samples, new_samples, reservation_samples, 100. * reservation_samples / samples);
}
return;
@@ -156,7 +160,7 @@ struct cpu_prof
// Print results
const std::string results = format(chart, samples, idle);
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);
profiler.notice("Thread \"%s\" [0x%08x]: %u samples (%.4f%% idle), %u new, %u reservation (%.4f%%):\n%s", ptr->get_name(), ptr->id, samples, 100. * idle / samples, new_samples, reservation_samples, 100. * reservation_samples / samples, results);
new_samples = 0;
}
@@ -177,6 +181,7 @@ struct cpu_prof
std::unordered_map<u64, u64, value_hash<u64>> freq;
u64 samples = 0, idle = 0;
u64 reservation = 0;
for (auto& [_, info] : threads)
{
@@ -188,6 +193,7 @@ struct cpu_prof
samples += info.samples;
idle += info.idle;
reservation += info.reservation_samples;
}
if (samples == idle)
@@ -197,7 +203,7 @@ struct cpu_prof
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);
profiler.notice("All Threads: %u samples (%.4f%% idle), %u new, %u reservation (%.4f%%): Not enough new samples have been collected since the last print.", samples, 100. * idle / samples, new_samples, reservation, 100. * reservation / samples);
return;
}
@@ -207,7 +213,7 @@ struct cpu_prof
}
const std::string results = format(chart, samples, idle, true);
profiler.notice("All Threads: %u samples, %u new (%.4f%% idle):%s", samples, new_samples, 100. * idle / samples, results);
profiler.notice("All Threads: %u samples (%.4f%% idle), %u new, %u reservation (%.4f%%):%s", samples, 100. * idle / samples, new_samples, reservation, 100. * reservation / samples, results);
}
};
@@ -281,6 +287,14 @@ struct cpu_prof
info.freq[name]++;
info.new_samples++;
if (auto spu = ptr->try_get<spu_thread>())
{
if (spu->raddr)
{
info.reservation_samples++;
}
}
// Append verification time to fixed common name 0000000...chunk-0x3fffc
if (name >> 16 && (name & 0xffff) == 0)
info.freq[0xffff]++;
@@ -315,6 +329,13 @@ struct cpu_prof
continue;
}
if (!g_cfg.core.spu_debug)
{
// Reduce accuracy in favor of performance when enabled alone
thread_ctrl::wait_for(60, false);
continue;
}
// Wait, roughly for 20µs
thread_ctrl::wait_for(20, false);
}
@@ -1072,17 +1093,31 @@ void cpu_thread::add_remove_flags(bs_t<cpu_flag> to_add, bs_t<cpu_flag> to_remov
std::string cpu_thread::get_name() const
{
// Downcast to correct type
if (id_type() == 1)
switch (id_type())
{
case 1:
{
return thread_ctrl::get_name(*static_cast<const named_thread<ppu_thread>*>(this));
}
if (id_type() == 2)
case 2:
{
return thread_ctrl::get_name(*static_cast<const named_thread<spu_thread>*>(this));
}
default:
{
if (cpu_thread::get_current() == this && thread_ctrl::get_current())
{
return thread_ctrl::get_name();
}
fmt::throw_exception("Invalid cpu_thread type");
if (id_type() == 0x55)
{
return fmt::format("rsx::thread");
}
return fmt::format("Invalid cpu_thread type (0x%x)", id_type());
}
}
}
u32 cpu_thread::get_pc() const
@@ -1411,7 +1446,7 @@ u32 CPUDisAsm::DisAsmBranchTarget(s32 /*imm*/)
extern bool try_lock_spu_threads_in_a_state_compatible_with_savestates(bool revert_lock)
{
auto get_spus = [old_counter = u64{umax}, spu_list = std::vector<std::shared_ptr<named_thread<spu_thread>>>()](bool can_collect) mutable
auto get_spus = [old_counter = u64{umax}, spu_list = std::vector<std::shared_ptr<named_thread<spu_thread>>>()](bool can_collect, bool force_collect) mutable
{
const u64 new_counter = cpu_thread::g_threads_created + cpu_thread::g_threads_deleted;
@@ -1422,14 +1457,34 @@ extern bool try_lock_spu_threads_in_a_state_compatible_with_savestates(bool reve
return decltype(&spu_list){};
}
const u64 current = get_system_time();
// Fetch SPU contexts
spu_list.clear();
idm::select<named_thread<spu_thread>>([&](u32 id, spu_thread&)
bool give_up = false;
idm::select<named_thread<spu_thread>>([&](u32 id, spu_thread& spu)
{
spu_list.emplace_back(ensure(idm::get_unlocked<named_thread<spu_thread>>(id)));
if (spu.current_func && spu.unsavable)
{
const u64 start = spu.start_time;
// Automatically give up if it is asleep 15 seconds or more
if (start && current > start && current - start >= 15'000'000)
{
give_up = true;
}
}
});
if (!force_collect && give_up)
{
return decltype(&spu_list){};
}
old_counter = new_counter;
}
@@ -1437,7 +1492,7 @@ extern bool try_lock_spu_threads_in_a_state_compatible_with_savestates(bool reve
};
// Attempt to lock for a second, if somehow takes longer abort it
for (u64 start = 0, passed_count = 0; passed_count < 10;)
for (u64 start = 0, passed_count = 0; passed_count < 15;)
{
if (revert_lock)
{
@@ -1449,7 +1504,7 @@ extern bool try_lock_spu_threads_in_a_state_compatible_with_savestates(bool reve
{
start = get_system_time();
}
else if (get_system_time() - start >= 100'000)
else if (get_system_time() - start >= 150'000)
{
passed_count++;
start = 0;
@@ -1457,7 +1512,16 @@ extern bool try_lock_spu_threads_in_a_state_compatible_with_savestates(bool reve
}
// Try to fetch SPUs out of critical section
const auto spu_list = get_spus(true);
const auto spu_list = get_spus(true, false);
if (!spu_list)
{
// Give up for now
std::this_thread::sleep_for(10ms);
passed_count++;
start = 0;
continue;
}
// Avoid using suspend_all when more than 2 threads known to be unsavable
u32 unsavable_threads = 0;
@@ -1486,7 +1550,7 @@ extern bool try_lock_spu_threads_in_a_state_compatible_with_savestates(bool reve
if (cpu_thread::suspend_all(nullptr, {}, [&]()
{
if (!get_spus(false))
if (!get_spus(false, true))
{
// Avoid locking IDM here because this is a critical section
return true;
@@ -1558,7 +1622,7 @@ extern bool try_lock_spu_threads_in_a_state_compatible_with_savestates(bool reve
return true;
}
for (auto& spu : *get_spus(true))
for (auto& spu : *get_spus(true, true))
{
if (spu->state.test_and_reset(cpu_flag::dbg_global_pause))
{
+1 -1
View File
@@ -171,7 +171,7 @@ void cpu_translator::initialize(llvm::LLVMContext& context, llvm::ExecutionEngin
cpu == "tigerlake" ||
cpu == "rocketlake" ||
cpu == "sapphirerapids" ||
(cpu.startswith("znver") && cpu != "znver1" && cpu != "znver2" && cpu != "znver3"))
(cpu.starts_with("znver") && cpu != "znver1" && cpu != "znver2" && cpu != "znver3"))
{
m_use_avx = true;
m_use_fma = true;
+15 -4
View File
@@ -125,7 +125,7 @@ using get_int_vt = typename get_int_bits<Bits>::utype;
template <typename T = void>
struct llvm_value_t
{
static_assert(std::is_same<T, void>::value, "llvm_value_t<> error: unknown type");
static_assert(std::is_same_v<T, void>, "llvm_value_t<> error: unknown type");
using type = void;
using base = llvm_value_t;
@@ -417,7 +417,7 @@ struct llvm_value_t<f64> : llvm_value_t<void>
template <typename T>
struct llvm_value_t<T*> : llvm_value_t<T>
{
static_assert(!std::is_void<T>::value, "llvm_value_t<> error: invalid pointer to void type");
static_assert(!std::is_void_v<T>, "llvm_value_t<> error: invalid pointer to void type");
using type = T*;
using base = llvm_value_t<T>;
@@ -3703,13 +3703,18 @@ public:
return result;
}
llvm::Value* load_const(llvm::GlobalVariable* g, llvm::Value* i, llvm::Type* type = nullptr)
{
return m_ir->CreateLoad(type ? type : g->getValueType(), m_ir->CreateGEP(g->getValueType(), g, {m_ir->getInt64(0), m_ir->CreateZExtOrTrunc(i, get_type<u64>())}));
}
template <typename T>
llvm::Value* load_const(llvm::GlobalVariable* g, llvm::Value* i)
{
return m_ir->CreateLoad(get_type<T>(), m_ir->CreateGEP(g->getValueType(), g, {m_ir->getInt64(0), m_ir->CreateZExtOrTrunc(i, get_type<u64>())}));
return load_const(g, i, get_type<T>());
}
template <typename T, typename I>
template <typename T, typename I> requires requires () { std::declval<I>().eval(std::declval<llvm::IRBuilder<>*>()); }
value_t<T> load_const(llvm::GlobalVariable* g, I i)
{
value_t<T> result;
@@ -3717,6 +3722,12 @@ public:
return result;
}
template <typename T>
llvm::GlobalVariable* make_local_variable(T initializing_value)
{
return new llvm::GlobalVariable(*m_module, get_type<T>(), false, llvm::GlobalVariable::PrivateLinkage, llvm::ConstantInt::get(get_type<T>(), initializing_value));
}
template <typename R = v128>
std::pair<bool, R> get_const_vector(llvm::Value*, u32 pos, u32 = __builtin_LINE());
+12 -7
View File
@@ -76,11 +76,14 @@ void cell_audio_config::reset(bool backend_changed)
const auto& [req_ch_cnt, downmix] = AudioBackend::get_channel_count_and_downmixer(0); // CELL_AUDIO_OUT_PRIMARY
f64 cb_frame_len = 0.0;
u32 ch_cnt = 2;
audio_channel_layout ch_layout = audio_channel_layout::stereo;
if (backend->Open(raw.audio_device, freq, sample_size, req_ch_cnt))
if (backend->Open(raw.audio_device, freq, sample_size, req_ch_cnt, raw.channel_layout))
{
cb_frame_len = backend->GetCallbackFrameLen();
ch_cnt = backend->get_channels();
ch_layout = backend->get_channel_layout();
cellAudio.notice("Opened audio backend (sampling_rate=%d, sample_size=%d, channels=%d, layout=%s)", backend->get_sampling_rate(), backend->get_sample_size(), backend->get_channels(), backend->get_channel_layout());
}
else
{
@@ -88,7 +91,8 @@ void cell_audio_config::reset(bool backend_changed)
}
audio_downmix = downmix;
backend_ch_cnt = AudioChannelCnt{ch_cnt};
backend_ch_cnt = ch_cnt;
backend_channel_layout = ch_layout;
audio_channels = static_cast<u32>(req_ch_cnt);
audio_sampling_rate = static_cast<u32>(freq);
audio_block_period = AUDIO_BUFFER_SAMPLES * 1'000'000 / audio_sampling_rate;
@@ -162,7 +166,7 @@ audio_ringbuffer::audio_ringbuffer(cell_audio_config& _cfg)
return cfg.audio_min_buffer_duration;
}();
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));
cb_ringbuf.set_buf_size(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));
}
@@ -219,7 +223,7 @@ float* audio_ringbuffer::get_current_buffer() const
u64 audio_ringbuffer::get_enqueued_samples() const
{
AUDIT(cfg.buffering_enabled);
const u64 ringbuf_samples = cb_ringbuf.get_used_size() / (cfg.audio_sample_size * static_cast<u32>(cfg.backend_ch_cnt));
const u64 ringbuf_samples = cb_ringbuf.get_used_size() / (cfg.audio_sample_size * cfg.backend_ch_cnt);
if (cfg.time_stretching_enabled)
{
@@ -280,14 +284,14 @@ void audio_ringbuffer::process_resampled_data()
{
if (!cfg.time_stretching_enabled) return;
const auto& [buffer, samples] = resampler.get_samples(static_cast<u32>(cb_ringbuf.get_free_size() / (cfg.audio_sample_size * static_cast<u32>(cfg.backend_ch_cnt))));
const auto& [buffer, samples] = resampler.get_samples(static_cast<u32>(cb_ringbuf.get_free_size() / (cfg.audio_sample_size * cfg.backend_ch_cnt)));
commit_data(buffer, samples);
}
void audio_ringbuffer::commit_data(f32* buf, u32 sample_cnt)
{
const u32 sample_cnt_in = sample_cnt * cfg.audio_channels;
const u32 sample_cnt_out = sample_cnt * static_cast<u32>(cfg.backend_ch_cnt);
const u32 sample_cnt_out = sample_cnt * cfg.backend_ch_cnt;
// Dump audio if enabled
m_dump.WriteData(buf, sample_cnt_in * static_cast<u32>(AudioSampleSize::FLOAT));
@@ -300,7 +304,7 @@ void audio_ringbuffer::commit_data(f32* buf, u32 sample_cnt)
}
// Downmix if necessary
AudioBackend::downmix(sample_cnt_in, cfg.audio_channels, static_cast<u32>(cfg.backend_ch_cnt), buf, buf);
AudioBackend::downmix(sample_cnt_in, cfg.audio_channels, cfg.backend_channel_layout, buf, buf);
if (cfg.backend->get_convert_to_s16())
{
@@ -614,6 +618,7 @@ namespace audio
.time_stretching_threshold = g_cfg.audio.time_stretching_threshold,
.convert_to_s16 = static_cast<bool>(g_cfg.audio.convert_to_s16),
.dump_to_file = static_cast<bool>(g_cfg.audio.dump_to_file),
.channel_layout = g_cfg.audio.channel_layout,
.renderer = g_cfg.audio.renderer,
.provider = g_cfg.audio.provider
};
+3 -1
View File
@@ -212,6 +212,7 @@ struct cell_audio_config
s64 time_stretching_threshold = 0;
bool convert_to_s16 = false;
bool dump_to_file = false;
audio_channel_layout channel_layout = audio_channel_layout::automatic;
audio_renderer renderer = audio_renderer::null;
audio_provider provider = audio_provider::none;
};
@@ -222,7 +223,8 @@ struct cell_audio_config
std::shared_ptr<AudioBackend> backend = nullptr;
AudioChannelCnt audio_downmix = AudioChannelCnt::SURROUND_7_1;
AudioChannelCnt backend_ch_cnt = AudioChannelCnt::SURROUND_7_1;
audio_channel_layout backend_channel_layout = audio_channel_layout::surround_7_1;
u32 backend_ch_cnt = 8;
u32 audio_channels = 2;
u32 audio_sampling_rate = DEFAULT_AUDIO_SAMPLING_RATE;
u32 audio_block_period = 0;
+16 -16
View File
@@ -498,7 +498,7 @@ error_code cellCameraEnd()
error_code cellCameraOpen(s32 dev_num, vm::ptr<CellCameraInfo> info)
{
cellCamera.todo("cellCameraOpen(dev_num=%d, info=*0x%x)", dev_num, info);
cellCamera.notice("cellCameraOpen(dev_num=%d, info=*0x%x)", dev_num, info);
if (!info)
{
@@ -639,7 +639,7 @@ error_code cellCameraOpenPost()
error_code cellCameraClose(s32 dev_num)
{
cellCamera.todo("cellCameraClose(dev_num=%d)", dev_num);
cellCamera.notice("cellCameraClose(dev_num=%d)", dev_num);
if (error_code error = check_init_and_open(dev_num))
{
@@ -714,7 +714,7 @@ error_code cellCameraGetDeviceGUID(s32 dev_num, vm::ptr<u32> guid)
error_code cellCameraGetType(s32 dev_num, vm::ptr<s32> type)
{
cellCamera.todo("cellCameraGetType(dev_num=%d, type=*0x%x)", dev_num, type);
cellCamera.trace("cellCameraGetType(dev_num=%d, type=*0x%x)", dev_num, type);
auto& g_camera = g_fxo->get<camera_thread>();
@@ -780,7 +780,7 @@ s32 cellCameraIsAvailable(s32 dev_num)
s32 cellCameraIsAttached(s32 dev_num)
{
cellCamera.warning("cellCameraIsAttached(dev_num=%d)", dev_num);
cellCamera.trace("cellCameraIsAttached(dev_num=%d)", dev_num);
if (g_cfg.io.camera == camera_handler::null)
{
@@ -879,7 +879,7 @@ s32 cellCameraIsStarted(s32 dev_num)
error_code cellCameraGetAttribute(s32 dev_num, s32 attrib, vm::ptr<u32> arg1, vm::ptr<u32> arg2)
{
const auto attr_name = get_camera_attr_name(attrib);
cellCamera.todo("cellCameraGetAttribute(dev_num=%d, attrib=%d=%s, arg1=*0x%x, arg2=*0x%x)", dev_num, attrib, attr_name, arg1, arg2);
cellCamera.notice("cellCameraGetAttribute(dev_num=%d, attrib=%d=%s, arg1=*0x%x, arg2=*0x%x)", dev_num, attrib, attr_name, arg1, arg2);
auto& g_camera = g_fxo->get<camera_thread>();
@@ -991,7 +991,7 @@ error_code cellCameraResetAttribute()
error_code cellCameraGetBufferSize(s32 dev_num, vm::ptr<CellCameraInfoEx> info)
{
cellCamera.todo("cellCameraGetBufferSize(dev_num=%d, info=*0x%x)", dev_num, info);
cellCamera.notice("cellCameraGetBufferSize(dev_num=%d, info=*0x%x)", dev_num, info);
auto& g_camera = g_fxo->get<camera_thread>();
@@ -1085,7 +1085,7 @@ error_code check_get_camera_info(s32 dev_num, bool is_valid_info_struct)
error_code cellCameraGetBufferInfo(s32 dev_num, vm::ptr<CellCameraInfo> info)
{
cellCamera.todo("cellCameraGetBufferInfo(dev_num=%d, info=0x%x)", dev_num, info);
cellCamera.notice("cellCameraGetBufferInfo(dev_num=%d, info=0x%x)", dev_num, info);
// called by cellCameraGetBufferInfoEx
@@ -1112,7 +1112,7 @@ error_code cellCameraGetBufferInfo(s32 dev_num, vm::ptr<CellCameraInfo> info)
error_code cellCameraGetBufferInfoEx(s32 dev_num, vm::ptr<CellCameraInfoEx> info)
{
cellCamera.todo("cellCameraGetBufferInfoEx(dev_num=%d, info=0x%x)", dev_num, info);
cellCamera.notice("cellCameraGetBufferInfoEx(dev_num=%d, info=0x%x)", dev_num, info);
// calls cellCameraGetBufferInfo
@@ -1244,7 +1244,7 @@ error_code cellCameraResetPost()
error_code cellCameraStart(s32 dev_num)
{
cellCamera.todo("cellCameraStart(dev_num=%d)", dev_num);
cellCamera.notice("cellCameraStart(dev_num=%d)", dev_num);
if (error_code error = check_init_and_open(dev_num))
{
@@ -1291,7 +1291,7 @@ error_code cellCameraStartPost()
error_code cellCameraRead(s32 dev_num, vm::ptr<u32> frame_num, vm::ptr<u32> bytes_read)
{
cellCamera.notice("cellCameraRead(dev_num=%d, frame_num=*0x%x, bytes_read=*0x%x)", dev_num, frame_num, bytes_read);
cellCamera.trace("cellCameraRead(dev_num=%d, frame_num=*0x%x, bytes_read=*0x%x)", dev_num, frame_num, bytes_read);
vm::ptr<CellCameraReadEx> read_ex = vm::make_var<CellCameraReadEx>({});
@@ -1321,7 +1321,7 @@ error_code cellCameraRead2()
error_code cellCameraReadEx(s32 dev_num, vm::ptr<CellCameraReadEx> read)
{
cellCamera.notice("cellCameraReadEx(dev_num=%d, read=0x%x)", dev_num, read);
cellCamera.trace("cellCameraReadEx(dev_num=%d, read=0x%x)", dev_num, read);
auto& g_camera = g_fxo->get<camera_thread>();
@@ -1421,7 +1421,7 @@ error_code cellCameraReadComplete(s32 dev_num, u32 bufnum, u32 arg2)
error_code cellCameraStop(s32 dev_num)
{
cellCamera.todo("cellCameraStop(dev_num=%d)", dev_num);
cellCamera.notice("cellCameraStop(dev_num=%d)", dev_num);
if (error_code error = check_init_and_open(dev_num))
{
@@ -1466,7 +1466,7 @@ error_code cellCameraStopPost()
error_code cellCameraSetNotifyEventQueue(u64 key)
{
cellCamera.todo("cellCameraSetNotifyEventQueue(key=0x%x)", key);
cellCamera.notice("cellCameraSetNotifyEventQueue(key=0x%x)", key);
auto& g_camera = g_fxo->get<camera_thread>();
@@ -1492,7 +1492,7 @@ error_code cellCameraSetNotifyEventQueue(u64 key)
error_code cellCameraRemoveNotifyEventQueue(u64 key)
{
cellCamera.todo("cellCameraRemoveNotifyEventQueue(key=0x%x)", key);
cellCamera.notice("cellCameraRemoveNotifyEventQueue(key=0x%x)", key);
auto& g_camera = g_fxo->get<camera_thread>();
@@ -1518,7 +1518,7 @@ error_code cellCameraRemoveNotifyEventQueue(u64 key)
error_code cellCameraSetNotifyEventQueue2(u64 key, u64 source, u64 flag)
{
cellCamera.todo("cellCameraSetNotifyEventQueue2(key=0x%x, source=%d, flag=%d)", key, source, flag);
cellCamera.notice("cellCameraSetNotifyEventQueue2(key=0x%x, source=%d, flag=%d)", key, source, flag);
auto& g_camera = g_fxo->get<camera_thread>();
@@ -1544,7 +1544,7 @@ error_code cellCameraSetNotifyEventQueue2(u64 key, u64 source, u64 flag)
error_code cellCameraRemoveNotifyEventQueue2(u64 key)
{
cellCamera.todo("cellCameraRemoveNotifyEventQueue2(key=0x%x)", key);
cellCamera.notice("cellCameraRemoveNotifyEventQueue2(key=0x%x)", key);
return cellCameraRemoveNotifyEventQueue(key);
}
+59 -25
View File
@@ -28,6 +28,10 @@ vm::gvar<CellHddGameStatSet> g_stat_set;
vm::gvar<CellHddGameSystemFileParam> g_file_param;
vm::gvar<CellHddGameCBResult> g_cb_result;
stx::init_lock acquire_lock(stx::init_mutex& mtx, ppu_thread* ppu = nullptr);
stx::access_lock acquire_access_lock(stx::init_mutex& mtx, ppu_thread* ppu = nullptr);
stx::reset_lock acquire_reset_lock(stx::init_mutex& mtx, ppu_thread* ppu = nullptr);
template<>
void fmt_class_string<CellGameError>::format(std::string& out, u64 arg)
{
@@ -206,6 +210,7 @@ void fmt_class_string<disc_change_manager::eject_state>::format(std::string& out
{
switch (error)
{
STR_CASE(disc_change_manager::eject_state::unknown);
STR_CASE(disc_change_manager::eject_state::inserted);
STR_CASE(disc_change_manager::eject_state::ejected);
STR_CASE(disc_change_manager::eject_state::busy);
@@ -215,6 +220,22 @@ void fmt_class_string<disc_change_manager::eject_state>::format(std::string& out
});
}
static bool check_system_ver(vm::cptr<char> systemVersion)
{
// Only allow something like "04.8300".
// The disassembly shows that "04.83" would also be considered valid, but the initial strlen check makes this void.
return (
systemVersion &&
std::strlen(systemVersion.get_ptr()) == 7 &&
std::isdigit(systemVersion[0]) &&
std::isdigit(systemVersion[1]) &&
systemVersion[2] == '.' &&
std::isdigit(systemVersion[3]) &&
std::isdigit(systemVersion[4]) &&
std::isdigit(systemVersion[5]) &&
std::isdigit(systemVersion[6])
);
}
disc_change_manager::disc_change_manager()
{
@@ -235,8 +256,15 @@ error_code disc_change_manager::register_callbacks(vm::ptr<CellGameDiscEjectCall
eject_callback = func_eject;
insert_callback = func_insert;
Emu.GetCallbacks().enable_disc_eject(!!func_eject);
Emu.GetCallbacks().enable_disc_insert(false);
const bool is_disc_mounted = fs::is_dir(vfs::get("/dev_bdvd/PS3_GAME"));
if (state == eject_state::unknown)
{
state = is_disc_mounted ? eject_state::inserted : eject_state::ejected;
}
Emu.GetCallbacks().enable_disc_eject(!!func_eject && is_disc_mounted);
Emu.GetCallbacks().enable_disc_insert(!!func_insert && !is_disc_mounted);
return CELL_OK;
}
@@ -296,7 +324,8 @@ void disc_change_manager::eject_disc()
ensure(vfs::unmount("/dev_ps2disc"));
dcm.state = eject_state::ejected;
Emu.GetCallbacks().enable_disc_insert(true);
// Re-enable disc insertion only if the callback is still registered
Emu.GetCallbacks().enable_disc_insert(!!dcm.insert_callback);
return CELL_OK;
});
@@ -377,7 +406,7 @@ error_code cellHddGameCheck(ppu_thread& ppu, u32 version, vm::cptr<char> dirName
{
cellGame.warning("cellHddGameCheck(version=%d, dirName=%s, errDialog=%d, funcStat=*0x%x, container=%d)", version, dirName, errDialog, funcStat, container);
if (!dirName || !funcStat || sysutil_check_name_string(dirName.get_ptr(), 1, CELL_GAME_DIRNAME_SIZE) != 0)
if (version != CELL_GAMEDATA_VERSION_CURRENT || !dirName || !funcStat || sysutil_check_name_string(dirName.get_ptr(), 1, CELL_GAME_DIRNAME_SIZE) != 0)
{
return CELL_HDDGAME_ERROR_PARAM;
}
@@ -414,10 +443,10 @@ error_code cellHddGameCheck(ppu_thread& ppu, u32 version, vm::cptr<char> dirName
const std::string local_dir = vfs::get(dir);
// 40 GB - 1 kilobyte. The reasoning is that many games take this number and multiply it by 1024, to get the amount of bytes. With 40GB exactly,
// this will result in an overflow, and the size would be 0, preventing the game from running. By reducing 1 kilobyte, we make sure that even
// 40 GB - 256 kilobytes. The reasoning is that many games take this number and multiply it by 1024, to get the amount of bytes. With 40GB exactly,
// this will result in an overflow, and the size would be 0, preventing the game from running. By reducing 256 kilobytes, we make sure that even
// after said overflow, the number would still be high enough to contain the game's data.
get->hddFreeSizeKB = 40 * 1024 * 1024 - 1;
get->hddFreeSizeKB = 40 * 1024 * 1024 - 256;
get->isNewData = CELL_HDDGAME_ISNEWDATA_EXIST;
get->sysSizeKB = 0; // TODO
get->st_atime_ = 0; // TODO
@@ -585,6 +614,11 @@ error_code cellHddGameGetSizeKB(ppu_thread& ppu, vm::ptr<u32> size)
cellGame.warning("cellHddGameGetSizeKB(size=*0x%x)", size);
if (!size)
{
return CELL_HDDGAME_ERROR_PARAM;
}
lv2_obj::sleep(ppu);
const u64 start_sleep = ppu.start_time;
@@ -619,7 +653,7 @@ error_code cellHddGameSetSystemVer(vm::cptr<char> systemVersion)
{
cellGame.todo("cellHddGameSetSystemVer(systemVersion=%s)", systemVersion);
if (!systemVersion)
if (!check_system_ver(systemVersion))
{
return CELL_HDDGAME_ERROR_PARAM;
}
@@ -678,7 +712,7 @@ error_code cellGameDataSetSystemVer(vm::cptr<char> systemVersion)
{
cellGame.todo("cellGameDataSetSystemVer(systemVersion=%s)", systemVersion);
if (!systemVersion)
if (!check_system_ver(systemVersion))
{
return CELL_GAMEDATA_ERROR_PARAM;
}
@@ -705,7 +739,7 @@ error_code cellGameBootCheck(vm::ptr<u32> type, vm::ptr<u32> attributes, vm::ptr
lv2_sleep(500);
const auto init = perm.init.init();
const auto init = acquire_lock(perm.init);
if (!init)
{
@@ -754,7 +788,7 @@ error_code cellGameBootCheck(vm::ptr<u32> type, vm::ptr<u32> attributes, vm::ptr
if (size)
{
// TODO: Use the free space of the computer's HDD where RPCS3 is being run.
size->hddFreeSizeKB = 40 * 1024 * 1024 - 1; // Read explanation in cellHddGameCheck
size->hddFreeSizeKB = 40 * 1024 * 1024 - 256; // Read explanation in cellHddGameCheck
// TODO: Calculate data size for HG and DG games, if necessary.
size->sizeKB = CELL_GAME_SIZEKB_NOTCALC;
@@ -789,7 +823,7 @@ error_code cellGamePatchCheck(vm::ptr<CellGameContentSize> size, vm::ptr<void> r
auto& perm = g_fxo->get<content_permission>();
const auto init = perm.init.init();
const auto init = acquire_lock(perm.init);
if (!init)
{
@@ -799,7 +833,7 @@ error_code cellGamePatchCheck(vm::ptr<CellGameContentSize> size, vm::ptr<void> r
if (size)
{
// TODO: Use the free space of the computer's HDD where RPCS3 is being run.
size->hddFreeSizeKB = 40 * 1024 * 1024 - 1; // Read explanation in cellHddGameCheck
size->hddFreeSizeKB = 40 * 1024 * 1024 - 256; // Read explanation in cellHddGameCheck
// TODO: Calculate data size for patch data, if necessary.
size->sizeKB = CELL_GAME_SIZEKB_NOTCALC;
@@ -836,7 +870,7 @@ error_code cellGameDataCheck(u32 type, vm::cptr<char> dirName, vm::ptr<CellGameC
auto& perm = g_fxo->get<content_permission>();
auto init = perm.init.init();
auto init = acquire_lock(perm.init);
if (!init)
{
@@ -871,7 +905,7 @@ error_code cellGameDataCheck(u32 type, vm::cptr<char> dirName, vm::ptr<CellGameC
if (size)
{
// TODO: Use the free space of the computer's HDD where RPCS3 is being run.
size->hddFreeSizeKB = 40 * 1024 * 1024 - 1; // Read explanation in cellHddGameCheck
size->hddFreeSizeKB = 40 * 1024 * 1024 - 256; // Read explanation in cellHddGameCheck
// TODO: Calculate data size for game data, if necessary.
size->sizeKB = sfo.empty() ? 0 : CELL_GAME_SIZEKB_NOTCALC;
@@ -904,7 +938,7 @@ error_code cellGameContentPermit(ppu_thread& ppu, vm::ptr<char[CELL_GAME_PATH_MA
auto& perm = g_fxo->get<content_permission>();
const auto init = perm.init.reset();
const auto init = acquire_reset_lock(perm.init);
if (!init)
{
@@ -1004,7 +1038,7 @@ error_code cellGameDataCheckCreate2(ppu_thread& ppu, u32 version, vm::cptr<char>
//older sdk. it might not care about game type.
if (version != CELL_GAMEDATA_VERSION_CURRENT || errDialog > 1 || !funcStat || sysutil_check_name_string(dirName.get_ptr(), 1, CELL_GAME_DIRNAME_SIZE) != 0)
if (version != CELL_GAMEDATA_VERSION_CURRENT || !funcStat || !dirName || sysutil_check_name_string(dirName.get_ptr(), 1, CELL_GAME_DIRNAME_SIZE) != 0)
{
return CELL_GAMEDATA_ERROR_PARAM;
}
@@ -1038,7 +1072,7 @@ error_code cellGameDataCheckCreate2(ppu_thread& ppu, u32 version, vm::cptr<char>
cbGet->isNewData = new_data;
// TODO: Use the free space of the computer's HDD where RPCS3 is being run.
cbGet->hddFreeSizeKB = 40 * 1024 * 1024 - 1; // Read explanation in cellHddGameCheck
cbGet->hddFreeSizeKB = 40 * 1024 * 1024 - 256; // Read explanation in cellHddGameCheck
strcpy_trunc(cbGet->contentInfoPath, dir);
strcpy_trunc(cbGet->gameDataPath, usrdir);
@@ -1158,7 +1192,7 @@ error_code cellGameDataCheckCreate2(ppu_thread& ppu, u32 version, vm::cptr<char>
break;
}
if (errDialog == CELL_GAMEDATA_ERRDIALOG_ALWAYS) // Maybe != CELL_GAMEDATA_ERRDIALOG_NONE
if (errDialog == CELL_GAMEDATA_ERRDIALOG_ALWAYS)
{
// Yield before a blocking dialog is being spawned
lv2_obj::sleep(ppu);
@@ -1204,7 +1238,7 @@ error_code cellGameCreateGameData(vm::ptr<CellGameSetInitParams> init, vm::ptr<c
auto& perm = g_fxo->get<content_permission>();
const auto _init = perm.init.access();
const auto _init = acquire_access_lock(perm.init);
lv2_sleep(2000);
@@ -1319,7 +1353,7 @@ error_code cellGameDeleteGameData(vm::cptr<char> dirName)
if (!_init)
{
// Or access it
if (auto access = perm.init.access(); access)
if (auto access = acquire_access_lock(perm.init); access)
{
// Cannot remove it when it is accessed by cellGameDataCheck
// If it is HG data then resort to remove_gd for ERROR_BROKEN
@@ -1356,7 +1390,7 @@ error_code cellGameGetParamInt(s32 id, vm::ptr<s32> value)
auto& perm = g_fxo->get<content_permission>();
const auto init = perm.init.access();
const auto init = acquire_access_lock(perm.init);
if (!init)
{
@@ -1484,7 +1518,7 @@ error_code cellGameGetParamString(s32 id, vm::ptr<char> buf, u32 bufsize)
lv2_sleep(2000);
const auto init = perm.init.access();
const auto init = acquire_access_lock(perm.init);
if (!init || perm.mode == content_permission::check_mode::not_set)
{
@@ -1530,7 +1564,7 @@ error_code cellGameSetParamString(s32 id, vm::cptr<char> buf)
auto& perm = g_fxo->get<content_permission>();
const auto init = perm.init.access();
const auto init = acquire_access_lock(perm.init);
if (!init || perm.mode == content_permission::check_mode::not_set)
{
@@ -1569,7 +1603,7 @@ error_code cellGameGetSizeKB(ppu_thread& ppu, vm::ptr<s32> size)
auto& perm = g_fxo->get<content_permission>();
const auto init = perm.init.access();
const auto init = acquire_access_lock(perm.init);
if (!init)
{
+2 -1
View File
@@ -338,11 +338,12 @@ struct disc_change_manager
enum class eject_state
{
unknown,
inserted,
ejected,
busy
};
atomic_t<eject_state> state = eject_state::inserted;
atomic_t<eject_state> state = eject_state::unknown;
error_code register_callbacks(vm::ptr<CellGameDiscEjectCallback> func_eject, vm::ptr<CellGameDiscInsertCallback> func_insert);
error_code unregister_callbacks();
+32 -30
View File
@@ -22,6 +22,11 @@
LOG_CHANNEL(cellGem);
static inline constexpr u32 rgba(u8 r, u8 g, u8 b, u8 a)
{
return ((r & 0xffu) << 24) | ((g & 0xffu) << 16) | ((b & 0xffu) << 8) | (a & 0xffu);
}
template <>
void fmt_class_string<gem_btn>::format(std::string& out, u64 arg)
{
@@ -493,42 +498,39 @@ void gem_config_data::operator()()
{
constexpr u32 in_pitch = 640;
constexpr u32 out_pitch = 640 * 4;
u8* dst = vc_attribute.video_data_out.get_ptr();
for (u32 y = 0; y < 480 - 1; y += 2)
{
const u8* src = &video_data_in[y * in_pitch];
const u16* src0 = reinterpret_cast<const u16*>(src);
const u16* src1 = reinterpret_cast<const u16*>(src + in_pitch);
u8* dst_row = dst + y * out_pitch;
u32* dst0 = reinterpret_cast<u32*>(dst_row);
u32* dst1 = reinterpret_cast<u32*>(dst_row + out_pitch);
for (u32 x = 0; x < 640 - 1; x += 2)
{
const u32 in_offset = 1 * (y * 640 + x);
const u32 out_offset = 4 * (y * 640 + x);
const u16 top = *src0++;
const u16 bottom = *src1++;
const u8 b = video_data_in[in_offset + 0];
const u8 g0 = video_data_in[in_offset + 1];
const u8 g1 = video_data_in[in_offset + in_pitch + 0];
const u8 r = video_data_in[in_offset + in_pitch + 1];
const u8 b = (top & 0xFF);
const u8 g0 = ((top >> 8) & 0xFF);
const u8 g1 = (bottom & 0xFF);
const u8 r = ((bottom >> 8) & 0xFF);
// Top-Left
vc_attribute.video_data_out[out_offset + 0] = r; // R
vc_attribute.video_data_out[out_offset + 1] = g0; // G
vc_attribute.video_data_out[out_offset + 2] = b; // B
vc_attribute.video_data_out[out_offset + 3] = 255; // A
*dst0++ = rgba(r, g0, b, 255);
// Top-Right Pixel
vc_attribute.video_data_out[out_offset + 4] = r; // R
vc_attribute.video_data_out[out_offset + 5] = g0; // G
vc_attribute.video_data_out[out_offset + 6] = b; // B
vc_attribute.video_data_out[out_offset + 7] = 255; // A
*dst0++ = rgba(r, g0, b, 255);
// Bottom-Left Pixel
vc_attribute.video_data_out[out_offset + out_pitch + 0] = r; // R
vc_attribute.video_data_out[out_offset + out_pitch + 1] = g1; // G
vc_attribute.video_data_out[out_offset + out_pitch + 2] = b; // B
vc_attribute.video_data_out[out_offset + out_pitch + 3] = 255; // A
*dst1++ = rgba(r, g1, b, 255);
// Bottom-Right Pixel
vc_attribute.video_data_out[out_offset + out_pitch + 4] = r; // R
vc_attribute.video_data_out[out_offset + out_pitch + 5] = g1; // G
vc_attribute.video_data_out[out_offset + out_pitch + 6] = b; // B
vc_attribute.video_data_out[out_offset + out_pitch + 7] = 255; // A
*dst1++ = rgba(r, g1, b, 255);
}
}
}
@@ -804,11 +806,11 @@ static void ds3_pos_to_gem_state(u32 gem_num, const gem_config::gem_controller&
s32 ds3_pos_x, ds3_pos_y;
ds3_get_stick_values(gem_num, pad, ds3_pos_x, ds3_pos_y);
if constexpr (std::is_same<T, vm::ptr<CellGemState>>::value)
if constexpr (std::is_same_v<T, vm::ptr<CellGemState>>)
{
pos_to_gem_state(gem_num, controller, gem_state, ds3_pos_x, ds3_pos_y, ds3_max_x, ds3_max_y);
}
else if constexpr (std::is_same<T, vm::ptr<CellGemImageState>>::value)
else if constexpr (std::is_same_v<T, vm::ptr<CellGemImageState>>)
{
pos_to_gem_image_state(gem_num, controller, gem_state, ds3_pos_x, ds3_pos_y, ds3_max_x, ds3_max_y);
}
@@ -947,11 +949,11 @@ static void mouse_pos_to_gem_state(const u32 mouse_no, const gem_config::gem_con
const auto& mouse = ::at32(handler.GetMice(), mouse_no);
if constexpr (std::is_same<T, vm::ptr<CellGemState>>::value)
if constexpr (std::is_same_v<T, vm::ptr<CellGemState>>)
{
pos_to_gem_state(mouse_no, controller, gem_state, mouse.x_pos, mouse.y_pos, mouse.x_max, mouse.y_max);
}
else if constexpr (std::is_same<T, vm::ptr<CellGemImageState>>::value)
else if constexpr (std::is_same_v<T, vm::ptr<CellGemImageState>>)
{
pos_to_gem_image_state(mouse_no, controller, gem_state, mouse.x_pos, mouse.y_pos, mouse.x_max, mouse.y_max);
}
@@ -1015,11 +1017,11 @@ static void gun_pos_to_gem_state(const u32 gem_no, const gem_config::gem_control
y_max = gun.handler.get_axis_y_max(gem_no);
}
if constexpr (std::is_same<T, vm::ptr<CellGemState>>::value)
if constexpr (std::is_same_v<T, vm::ptr<CellGemState>>)
{
pos_to_gem_state(gem_no, controller, gem_state, x_pos, y_pos, x_max, y_max);
}
else if constexpr (std::is_same<T, vm::ptr<CellGemImageState>>::value)
else if constexpr (std::is_same_v<T, vm::ptr<CellGemImageState>>)
{
pos_to_gem_image_state(gem_no, controller, gem_state, x_pos, y_pos, x_max, y_max);
}
@@ -1496,7 +1498,7 @@ error_code cellGemGetInertialState(u32 gem_num, u32 state_flag, u64 timestamp, v
error_code cellGemGetInfo(vm::ptr<CellGemInfo> info)
{
cellGem.warning("cellGemGetInfo(info=*0x%x)", info);
cellGem.trace("cellGemGetInfo(info=*0x%x)", info);
auto& gem = g_fxo->get<gem_config>();
@@ -1638,7 +1640,7 @@ error_code cellGemGetState(u32 gem_num, u32 flag, u64 time_parameter, vm::ptr<Ce
if (!gem.is_controller_ready(gem_num))
{
return CELL_GEM_NOT_CONNECTED;
return not_an_error(CELL_GEM_NOT_CONNECTED);
}
// TODO: Get the gem state at the specified time
+59 -31
View File
@@ -42,13 +42,16 @@ KeyboardHandlerBase::KeyboardHandlerBase(utils::serial* ar)
return;
}
(*ar)(m_info.max_connect);
u32 max_connect = 0;
if (m_info.max_connect)
(*ar)(max_connect);
if (max_connect)
{
Emu.PostponeInitCode([this]()
Emu.PostponeInitCode([this, max_connect]()
{
Init(m_info.max_connect);
std::lock_guard<std::mutex> lock(m_mutex);
AddConsumer(keyboard_consumer::identifier::cellKb, max_connect);
auto lk = init.init();
});
}
@@ -56,9 +59,20 @@ KeyboardHandlerBase::KeyboardHandlerBase(utils::serial* ar)
void KeyboardHandlerBase::save(utils::serial& ar)
{
u32 max_connect = 0;
const auto inited = init.access();
ar(inited ? m_info.max_connect : 0);
if (inited)
{
std::lock_guard<std::mutex> lock(m_mutex);
if (auto it = m_consumers.find(keyboard_consumer::identifier::cellKb); it != m_consumers.end())
{
max_connect = it->second.GetInfo().max_connect;
}
}
ar(max_connect);
}
error_code cellKbInit(ppu_thread& ppu, u32 max_connect)
@@ -79,7 +93,9 @@ error_code cellKbInit(ppu_thread& ppu, u32 max_connect)
}
sys_config_start(ppu);
handler.Init(std::min(max_connect, 7u));
std::lock_guard<std::mutex> lock(handler.m_mutex);
handler.AddConsumer(keyboard_consumer::identifier::cellKb, std::min(max_connect, 7u));
return CELL_OK;
}
@@ -95,6 +111,11 @@ error_code cellKbEnd(ppu_thread& ppu)
if (!init)
return CELL_KB_ERROR_UNINITIALIZED;
{
std::lock_guard<std::mutex> lock(handler.m_mutex);
handler.RemoveConsumer(keyboard_consumer::identifier::cellKb);
}
// TODO
sys_config_stop(ppu);
return CELL_OK;
@@ -116,12 +137,13 @@ error_code cellKbClearBuf(u32 port_no)
std::lock_guard<std::mutex> lock(handler.m_mutex);
const KbInfo& current_info = handler.GetInfo();
keyboard_consumer& consumer = handler.GetConsumer(keyboard_consumer::identifier::cellKb);
const KbInfo& current_info = consumer.GetInfo();
if (port_no >= handler.GetKeyboards().size() || current_info.status[port_no] != CELL_KB_STATUS_CONNECTED)
if (port_no >= consumer.GetKeyboards().size() || current_info.status[port_no] != CELL_KB_STATUS_CONNECTED)
return not_an_error(CELL_KB_ERROR_NO_DEVICE);
KbData& current_data = handler.GetData(port_no);
KbData& current_data = consumer.GetData(port_no);
current_data.len = 0;
current_data.led = 0;
current_data.mkey = 0;
@@ -298,8 +320,9 @@ error_code cellKbGetInfo(vm::ptr<CellKbInfo> info)
std::memset(info.get_ptr(), 0, info.size());
std::lock_guard<std::mutex> lock(handler.m_mutex);
keyboard_consumer& consumer = handler.GetConsumer(keyboard_consumer::identifier::cellKb);
const KbInfo& current_info = handler.GetInfo();
const KbInfo& current_info = consumer.GetInfo();
info->max_connect = current_info.max_connect;
info->now_connect = current_info.now_connect;
info->info = current_info.info;
@@ -327,13 +350,13 @@ error_code cellKbRead(u32 port_no, vm::ptr<CellKbData> data)
return CELL_KB_ERROR_INVALID_PARAMETER;
std::lock_guard<std::mutex> lock(handler.m_mutex);
keyboard_consumer& consumer = handler.GetConsumer(keyboard_consumer::identifier::cellKb);
const KbInfo& current_info = consumer.GetInfo();
const KbInfo& current_info = handler.GetInfo();
if (port_no >= handler.GetKeyboards().size() || current_info.status[port_no] != CELL_KB_STATUS_CONNECTED)
if (port_no >= consumer.GetKeyboards().size() || current_info.status[port_no] != CELL_KB_STATUS_CONNECTED)
return not_an_error(CELL_KB_ERROR_NO_DEVICE);
KbData& current_data = handler.GetData(port_no);
KbData& current_data = consumer.GetData(port_no);
if (current_info.is_null_handler || (current_info.info & CELL_KB_INFO_INTERCEPTED) || !is_input_allowed())
{
@@ -355,7 +378,7 @@ error_code cellKbRead(u32 port_no, vm::ptr<CellKbData> data)
data->keycode[i] = current_data.buttons[i].m_keyCode;
}
KbConfig& current_config = handler.GetConfig(port_no);
KbConfig& current_config = consumer.GetConfig(port_no);
// For single character mode to work properly we need to "flush" the buffer after reading or else we'll constantly get the same key presses with each call.
// Actual key repeats are handled by adding a new key code to the buffer periodically. Key releases are handled in a similar fashion.
@@ -383,12 +406,13 @@ error_code cellKbSetCodeType(u32 port_no, u32 type)
if (port_no >= CELL_KB_MAX_KEYBOARDS || type > CELL_KB_CODETYPE_ASCII)
return CELL_KB_ERROR_INVALID_PARAMETER;
if (port_no >= handler.GetKeyboards().size())
std::lock_guard<std::mutex> lock(handler.m_mutex);
keyboard_consumer& consumer = handler.GetConsumer(keyboard_consumer::identifier::cellKb);
if (port_no >= consumer.GetKeyboards().size())
return CELL_OK;
std::lock_guard<std::mutex> lock(handler.m_mutex);
KbConfig& current_config = handler.GetConfig(port_no);
KbConfig& current_config = consumer.GetConfig(port_no);
current_config.code_type = type;
// can also return CELL_KB_ERROR_SYS_SETTING_FAILED
@@ -413,12 +437,13 @@ error_code cellKbSetLEDStatus(u32 port_no, u8 led)
if (led > 7)
return CELL_KB_ERROR_SYS_SETTING_FAILED;
if (port_no >= handler.GetKeyboards().size() || handler.GetInfo().status[port_no] != CELL_KB_STATUS_CONNECTED)
std::lock_guard<std::mutex> lock(handler.m_mutex);
keyboard_consumer& consumer = handler.GetConsumer(keyboard_consumer::identifier::cellKb);
if (port_no >= consumer.GetKeyboards().size() || consumer.GetInfo().status[port_no] != CELL_KB_STATUS_CONNECTED)
return CELL_KB_ERROR_FATAL;
std::lock_guard<std::mutex> lock(handler.m_mutex);
KbData& current_data = handler.GetData(port_no);
KbData& current_data = consumer.GetData(port_no);
current_data.led = static_cast<u32>(led);
return CELL_OK;
@@ -438,16 +463,17 @@ error_code cellKbSetReadMode(u32 port_no, u32 rmode)
if (port_no >= CELL_KB_MAX_KEYBOARDS || rmode > CELL_KB_RMODE_PACKET)
return CELL_KB_ERROR_INVALID_PARAMETER;
if (port_no >= handler.GetKeyboards().size())
std::lock_guard<std::mutex> lock(handler.m_mutex);
keyboard_consumer& consumer = handler.GetConsumer(keyboard_consumer::identifier::cellKb);
if (port_no >= consumer.GetKeyboards().size())
return CELL_OK;
std::lock_guard<std::mutex> lock(handler.m_mutex);
KbConfig& current_config = handler.GetConfig(port_no);
KbConfig& current_config = consumer.GetConfig(port_no);
current_config.read_mode = rmode;
// Key repeat must be disabled in packet mode. But let's just always enable it otherwise.
Keyboard& keyboard = handler.GetKeyboards()[port_no];
Keyboard& keyboard = consumer.GetKeyboards()[port_no];
keyboard.m_key_repeat = rmode != CELL_KB_RMODE_PACKET;
// can also return CELL_KB_ERROR_SYS_SETTING_FAILED
@@ -471,16 +497,18 @@ error_code cellKbGetConfiguration(u32 port_no, vm::ptr<CellKbConfig> config)
std::lock_guard<std::mutex> lock(handler.m_mutex);
const KbInfo& current_info = handler.GetInfo();
keyboard_consumer& consumer = handler.GetConsumer(keyboard_consumer::identifier::cellKb);
if (port_no >= handler.GetKeyboards().size() || current_info.status[port_no] != CELL_KB_STATUS_CONNECTED)
const KbInfo& current_info = consumer.GetInfo();
if (port_no >= consumer.GetKeyboards().size() || current_info.status[port_no] != CELL_KB_STATUS_CONNECTED)
return not_an_error(CELL_KB_ERROR_NO_DEVICE);
// tests show that config is checked only after the device's status
if (!config)
return CELL_KB_ERROR_INVALID_PARAMETER;
const KbConfig& current_config = handler.GetConfig(port_no);
const KbConfig& current_config = consumer.GetConfig(port_no);
config->arrange = current_config.arrange;
config->read_mode = current_config.read_mode;
config->code_type = current_config.code_type;
+5 -4
View File
@@ -1144,8 +1144,6 @@ error_code cellMicRemoveNotifyEventQueue(u64 key)
error_code cell_mic_read(s32 dev_num, vm::ptr<void> data, s32 max_bytes, /*CellMicSignalType*/u32 type)
{
// TODO: CELL_MICIN_ERROR_PARAM
auto& mic_thr = g_fxo->get<mic_thread>();
const std::lock_guard lock(mic_thr.mutex);
if (!mic_thr.init)
@@ -1159,16 +1157,19 @@ error_code cell_mic_read(s32 dev_num, vm::ptr<void> data, s32 max_bytes, /*CellM
if (!device.is_opened() || !(device.get_signal_types() & type))
return CELL_MICIN_ERROR_NOT_OPEN;
if (!data)
return not_an_error(0);
switch (type)
{
case CELLMIC_SIGTYPE_DSP: return not_an_error(device.read_dsp(vm::_ptr<u8>(data.addr()), max_bytes));
case CELLMIC_SIGTYPE_AUX: return CELL_OK; // TODO
case CELLMIC_SIGTYPE_AUX: return not_an_error(0); // TODO
case CELLMIC_SIGTYPE_RAW: return not_an_error(device.read_raw(vm::_ptr<u8>(data.addr()), max_bytes));
default:
fmt::throw_exception("Invalid CELLMIC_SIGTYPE %d", type);
}
return CELL_OK;
return not_an_error(0);
}
error_code cellMicReadRaw(s32 dev_num, vm::ptr<void> data, s32 max_bytes)
+23 -22
View File
@@ -157,9 +157,8 @@ struct CellMicInputStream
struct CellMicInputDefinition
{
// TODO: Data types
volatile u32 uiDevId;
CellMicInputStream data;
be_t<u32> uiDevId;
CellMicInputStream data;
CellMicInputFormatI aux_format;
CellMicInputFormatI raw_format;
CellMicInputFormatI sig_format;
@@ -182,13 +181,13 @@ struct CellMicStatus
// --- End of cell definitions ---
template <usz S>
template <usz Size>
class simple_ringbuf
{
public:
simple_ringbuf()
{
m_container.resize(S);
m_container.resize(Size);
}
bool has_data() const
@@ -200,19 +199,19 @@ public:
{
ensure(buf);
u32 to_read = size > m_used ? m_used : size;
const u32 to_read = size > m_used ? m_used : size;
if (!to_read)
return 0;
u8* data = m_container.data();
u32 new_tail = m_tail + to_read;
u8* data = m_container.data();
const u32 new_tail = m_tail + to_read;
if (new_tail >= S)
if (new_tail >= Size)
{
u32 first_chunk_size = S - m_tail;
const u32 first_chunk_size = Size - m_tail;
std::memcpy(buf, data + m_tail, first_chunk_size);
std::memcpy(buf + first_chunk_size, data, to_read - first_chunk_size);
m_tail = (new_tail - S);
m_tail = (new_tail - Size);
}
else
{
@@ -227,30 +226,32 @@ public:
void write_bytes(const u8* buf, const u32 size)
{
ensure(size <= S);
ensure(size <= Size);
if (u32 over_size = m_used + size; over_size > S)
const u32 over_size = m_used + size;
if (over_size > Size)
{
m_tail += (over_size - S);
if (m_tail > S)
m_tail -= S;
m_tail += (over_size - Size);
if (m_tail > Size)
m_tail -= Size;
m_used = S;
m_used = Size;
}
else
{
m_used = over_size;
}
u8* data = m_container.data();
u32 new_head = m_head + size;
u8* data = m_container.data();
const u32 new_head = m_head + size;
if (new_head >= S)
if (new_head >= Size)
{
u32 first_chunk_size = S - m_head;
const u32 first_chunk_size = Size - m_head;
std::memcpy(data + m_head, buf, first_chunk_size);
std::memcpy(data, buf + first_chunk_size, size - first_chunk_size);
m_head = (new_head - S);
m_head = (new_head - Size);
}
else
{
+8 -2
View File
@@ -250,7 +250,7 @@ error_code cellMusicGetSelectionContext(vm::ptr<CellMusicSelectionContext> conte
if (!music.current_selection_context)
{
return CELL_MUSIC2_ERROR_NO_ACTIVE_CONTENT;
return CELL_MUSIC_ERROR_NO_ACTIVE_CONTENT;
}
*context = music.current_selection_context.get();
@@ -325,7 +325,7 @@ error_code cellMusicGetContentsId(vm::ptr<CellSearchContentId> contents_id)
if (!music.current_selection_context)
{
return CELL_MUSIC2_ERROR_NO_ACTIVE_CONTENT;
return CELL_MUSIC_ERROR_NO_ACTIVE_CONTENT;
}
return music.current_selection_context.find_content_id(contents_id);
@@ -408,6 +408,12 @@ error_code cellMusicGetContentsId2(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);
}
+5 -5
View File
@@ -425,14 +425,14 @@ error_code cellOskDialogLoadAsync(u32 container, vm::ptr<CellOskDialogParam> dia
return;
}
bool is_kook_key = false;
bool is_hook_key = false;
switch (key_message.keycode)
{
case CELL_KEYC_NO_EVENT:
{
// Any shift/alt/ctrl key
is_kook_key = key_message.mkey > 0 && (info.hook_event_mode & CELL_OSKDIALOG_EVENT_HOOK_TYPE_ONLY_MODIFIER);
is_hook_key = key_message.mkey > 0 && (info.hook_event_mode & CELL_OSKDIALOG_EVENT_HOOK_TYPE_ONLY_MODIFIER);
break;
}
case CELL_KEYC_E_ROLLOVER:
@@ -473,18 +473,18 @@ error_code cellOskDialogLoadAsync(u32 container, vm::ptr<CellOskDialogParam> dia
case CELL_KEYC_MUHENKAN:
{
// Any function key or other special key like Delete
is_kook_key = (info.hook_event_mode & CELL_OSKDIALOG_EVENT_HOOK_TYPE_FUNCTION_KEY);
is_hook_key = (info.hook_event_mode & CELL_OSKDIALOG_EVENT_HOOK_TYPE_FUNCTION_KEY);
break;
}
default:
{
// Any regular ascii key
is_kook_key = (info.hook_event_mode & CELL_OSKDIALOG_EVENT_HOOK_TYPE_ASCII_KEY);
is_hook_key = (info.hook_event_mode & CELL_OSKDIALOG_EVENT_HOOK_TYPE_ASCII_KEY);
break;
}
}
if (!is_kook_key)
if (!is_hook_key)
{
cellOskDialog.notice("on_osk_key_input_entered: not a hook key: led=%d, mkey=%d, keycode=%d, hook_event_mode=%d", key_message.led, key_message.mkey, key_message.keycode, info.hook_event_mode.load());
return;
+28 -66
View File
@@ -107,7 +107,7 @@ void cellPad_NotifyStateChange(usz index, u64 /*state*/, bool locked)
// NOTE 1: The state's CONNECTED bit should currently be identical to the current
// m_port_status CONNECTED bit when called from our pad handlers.
// NOTE 2: Make sure to propagate all other status bits to the reported status.
const u32 new_status = pads[index]->m_port_status;
const u32 new_status = pad->m_port_status;
if (~(old_status ^ new_status) & CELL_PAD_STATUS_CONNECTED)
{
@@ -188,17 +188,11 @@ error_code cellPadInit(ppu_thread& ppu, u32 max_connect)
config.port_setting.fill(CELL_PAD_SETTING_PRESS_OFF | CELL_PAD_SETTING_SENSOR_OFF);
config.reported_info = {};
std::array<s32, CELL_MAX_PADS> statuses{};
const auto handler = pad::get_current_handler();
const auto& pads = handler->GetPads();
for (usz i = 0; i < statuses.size(); ++i)
for (usz i = 0; i < config.get_max_connect(); ++i)
{
if (i >= config.get_max_connect())
break;
if (pads[i]->m_port_status & CELL_PAD_STATUS_CONNECTED)
{
send_sys_io_connect_event(i, CELL_PAD_STATUS_CONNECTED);
@@ -255,16 +249,14 @@ error_code cellPadClearBuf(u32 port_no)
if (!config.max_connect)
return CELL_PAD_ERROR_UNINITIALIZED;
const auto handler = pad::get_current_handler();
if (port_no >= CELL_MAX_PADS)
return CELL_PAD_ERROR_INVALID_PARAMETER;
const auto& pads = handler->GetPads();
if (port_no >= config.get_max_connect())
return CELL_PAD_ERROR_NO_DEVICE;
const auto handler = pad::get_current_handler();
const auto& pads = handler->GetPads();
const auto& pad = pads[port_no];
if (!config.is_reportedly_connected(port_no) || !(pad->m_port_status & CELL_PAD_STATUS_CONNECTED))
@@ -618,16 +610,14 @@ error_code cellPadGetData(u32 port_no, vm::ptr<CellPadData> data)
if (!config.max_connect)
return CELL_PAD_ERROR_UNINITIALIZED;
const auto handler = pad::get_current_handler();
if (port_no >= CELL_MAX_PADS || !data)
return CELL_PAD_ERROR_INVALID_PARAMETER;
const auto& pads = handler->GetPads();
if (port_no >= config.get_max_connect())
return CELL_PAD_ERROR_NO_DEVICE;
const auto handler = pad::get_current_handler();
const auto& pads = handler->GetPads();
const auto& pad = pads[port_no];
if (!config.is_reportedly_connected(port_no) || !(pad->m_port_status & CELL_PAD_STATUS_CONNECTED))
@@ -648,11 +638,10 @@ error_code cellPadPeriphGetInfo(vm::ptr<CellPadPeriphInfo> info)
if (!config.max_connect)
return CELL_PAD_ERROR_UNINITIALIZED;
const auto handler = pad::get_current_handler();
if (!info)
return CELL_PAD_ERROR_INVALID_PARAMETER;
const auto handler = pad::get_current_handler();
const PadInfo& rinfo = handler->GetInfo();
std::memset(info.get_ptr(), 0, sizeof(CellPadPeriphInfo));
@@ -662,11 +651,8 @@ error_code cellPadPeriphGetInfo(vm::ptr<CellPadPeriphInfo> info)
u32 now_connect = 0;
for (u32 i = 0; i < CELL_PAD_MAX_PORT_NUM; ++i)
for (u32 i = 0; i < config.get_max_connect(); ++i)
{
if (i >= config.get_max_connect())
break;
pad_data_internal& reported_info = config.reported_info[i];
info->port_status[i] = reported_info.port_status;
@@ -703,17 +689,15 @@ error_code cellPadPeriphGetData(u32 port_no, vm::ptr<CellPadPeriphData> data)
if (!config.max_connect)
return CELL_PAD_ERROR_UNINITIALIZED;
const auto handler = pad::get_current_handler();
// port_no can only be 0-6 in this function
if (port_no >= CELL_PAD_MAX_PORT_NUM || !data)
return CELL_PAD_ERROR_INVALID_PARAMETER;
const auto& pads = handler->GetPads();
if (port_no >= config.get_max_connect())
return CELL_PAD_ERROR_NO_DEVICE;
const auto handler = pad::get_current_handler();
const auto& pads = handler->GetPads();
const auto& pad = pads[port_no];
if (!config.is_reportedly_connected(port_no) || !(pad->m_port_status & CELL_PAD_STATUS_CONNECTED))
@@ -738,16 +722,14 @@ error_code cellPadGetRawData(u32 port_no, vm::ptr<CellPadData> data)
if (!config.max_connect)
return CELL_PAD_ERROR_UNINITIALIZED;
const auto handler = pad::get_current_handler();
if (port_no >= CELL_MAX_PADS || !data)
return CELL_PAD_ERROR_INVALID_PARAMETER;
const auto& pads = handler->GetPads();
if (port_no >= config.get_max_connect())
return CELL_PAD_ERROR_NO_DEVICE;
const auto handler = pad::get_current_handler();
const auto& pads = handler->GetPads();
const auto& pad = pads[port_no];
if (!config.is_reportedly_connected(port_no) || !(pad->m_port_status & CELL_PAD_STATUS_CONNECTED))
@@ -793,8 +775,6 @@ error_code cellPadSetActDirect(u32 port_no, vm::ptr<CellPadActParam> param)
if (!config.max_connect)
return CELL_PAD_ERROR_UNINITIALIZED;
const auto handler = pad::get_current_handler();
if (port_no >= CELL_MAX_PADS || !param)
return CELL_PAD_ERROR_INVALID_PARAMETER;
@@ -809,11 +789,11 @@ error_code cellPadSetActDirect(u32 port_no, vm::ptr<CellPadActParam> param)
}
}
const auto& pads = handler->GetPads();
if (port_no >= config.get_max_connect())
return CELL_PAD_ERROR_NO_DEVICE;
const auto handler = pad::get_current_handler();
const auto& pads = handler->GetPads();
const auto& pad = pads[port_no];
if (!config.is_reportedly_connected(port_no) || !(pad->m_port_status & CELL_PAD_STATUS_CONNECTED))
@@ -839,24 +819,20 @@ error_code cellPadGetInfo(vm::ptr<CellPadInfo> info)
if (!config.max_connect)
return CELL_PAD_ERROR_UNINITIALIZED;
const auto handler = pad::get_current_handler();
if (!info)
return CELL_PAD_ERROR_INVALID_PARAMETER;
std::memset(info.get_ptr(), 0, sizeof(CellPadInfo));
const auto handler = pad::get_current_handler();
const PadInfo& rinfo = handler->GetInfo();
info->max_connect = config.max_connect;
info->system_info = rinfo.system_info;
u32 now_connect = 0;
for (u32 i = 0; i < CELL_MAX_PADS; ++i)
for (u32 i = 0; i < config.get_max_connect(); ++i)
{
if (i >= config.get_max_connect())
break;
pad_data_internal& reported_info = config.reported_info[i];
reported_info.port_status &= ~CELL_PAD_STATUS_ASSIGN_CHANGES; // TODO: should ASSIGN flags be cleared here?
@@ -888,13 +864,12 @@ error_code cellPadGetInfo2(vm::ptr<CellPadInfo2> info)
if (!config.max_connect)
return CELL_PAD_ERROR_UNINITIALIZED;
const auto handler = pad::get_current_handler();
if (!info)
return CELL_PAD_ERROR_INVALID_PARAMETER;
std::memset(info.get_ptr(), 0, sizeof(CellPadInfo2));
const auto handler = pad::get_current_handler();
const PadInfo& rinfo = handler->GetInfo();
info->max_connect = config.get_max_connect(); // Here it is forcibly clamped
info->system_info = rinfo.system_info;
@@ -903,11 +878,8 @@ error_code cellPadGetInfo2(vm::ptr<CellPadInfo2> info)
const auto& pads = handler->GetPads();
for (u32 i = 0; i < CELL_PAD_MAX_PORT_NUM; ++i)
for (u32 i = 0; i < config.get_max_connect(); ++i)
{
if (i >= config.get_max_connect())
break;
pad_data_internal& reported_info = config.reported_info[i];
info->port_status[i] = reported_info.port_status;
@@ -941,16 +913,14 @@ error_code cellPadGetCapabilityInfo(u32 port_no, vm::ptr<CellPadCapabilityInfo>
if (!config.max_connect)
return CELL_PAD_ERROR_UNINITIALIZED;
const auto handler = pad::get_current_handler();
if (port_no >= CELL_MAX_PADS || !info)
return CELL_PAD_ERROR_INVALID_PARAMETER;
const auto& pads = handler->GetPads();
if (port_no >= config.get_max_connect())
return CELL_PAD_ERROR_NO_DEVICE;
const auto handler = pad::get_current_handler();
const auto& pads = handler->GetPads();
const auto& pad = pads[port_no];
if (!config.is_reportedly_connected(port_no) || !(pad->m_port_status & CELL_PAD_STATUS_CONNECTED))
@@ -999,16 +969,14 @@ error_code cellPadInfoPressMode(u32 port_no)
if (!config.max_connect)
return CELL_PAD_ERROR_UNINITIALIZED;
const auto handler = pad::get_current_handler();
if (port_no >= CELL_MAX_PADS)
return CELL_PAD_ERROR_INVALID_PARAMETER;
const auto& pads = handler->GetPads();
if (port_no >= config.get_max_connect())
return CELL_PAD_ERROR_NO_DEVICE;
const auto handler = pad::get_current_handler();
const auto& pads = handler->GetPads();
const auto& pad = pads[port_no];
if (!config.is_reportedly_connected(port_no) || !(pad->m_port_status & CELL_PAD_STATUS_CONNECTED))
@@ -1028,16 +996,14 @@ error_code cellPadInfoSensorMode(u32 port_no)
if (!config.max_connect)
return CELL_PAD_ERROR_UNINITIALIZED;
const auto handler = pad::get_current_handler();
if (port_no >= CELL_MAX_PADS)
return CELL_PAD_ERROR_INVALID_PARAMETER;
const auto& pads = handler->GetPads();
if (port_no >= config.get_max_connect())
return CELL_PAD_ERROR_NO_DEVICE;
const auto handler = pad::get_current_handler();
const auto& pads = handler->GetPads();
const auto& pad = pads[port_no];
if (!config.is_reportedly_connected(port_no) || !(pad->m_port_status & CELL_PAD_STATUS_CONNECTED))
@@ -1057,17 +1023,15 @@ error_code cellPadSetPressMode(u32 port_no, u32 mode)
if (!config.max_connect)
return CELL_PAD_ERROR_UNINITIALIZED;
const auto handler = pad::get_current_handler();
if (port_no >= CELL_PAD_MAX_PORT_NUM)
return CELL_PAD_ERROR_INVALID_PARAMETER;
const auto& pads = handler->GetPads();
// CELL_PAD_ERROR_NO_DEVICE is not returned in this case.
if (port_no >= CELL_PAD_MAX_PORT_NUM)
return CELL_OK;
const auto handler = pad::get_current_handler();
const auto& pads = handler->GetPads();
const auto& pad = pads[port_no];
// TODO: find out if this is checked here or later or at all
@@ -1093,17 +1057,15 @@ error_code cellPadSetSensorMode(u32 port_no, u32 mode)
if (!config.max_connect)
return CELL_PAD_ERROR_UNINITIALIZED;
const auto handler = pad::get_current_handler();
if (port_no >= CELL_MAX_PADS)
return CELL_PAD_ERROR_INVALID_PARAMETER;
const auto& pads = handler->GetPads();
// CELL_PAD_ERROR_NO_DEVICE is not returned in this case.
if (port_no >= CELL_PAD_MAX_PORT_NUM)
return CELL_OK;
const auto handler = pad::get_current_handler();
const auto& pads = handler->GetPads();
const auto& pad = pads[port_no];
// TODO: find out if this is checked here or later or at all
+2 -2
View File
@@ -159,7 +159,7 @@ struct rec_param
static constexpr u32 rec_framerate = 30; // Always 30 fps
static constexpr u32 rec_channels = 2; // Always 2 channels
class rec_video_sink : public utils::video_sink
class rec_video_sink final : public utils::video_sink
{
public:
rec_video_sink() : utils::video_sink()
@@ -752,7 +752,7 @@ void rec_info::start_video_provider()
if (sample.channels > channels)
{
// Downmix channels
AudioBackend::downmix(CELL_REC_AUDIO_BLOCK_SAMPLES * sample.channels, sample.channels, channels, src, reinterpret_cast<f32*>(dst_buffer.block.data()));
AudioBackend::downmix(CELL_REC_AUDIO_BLOCK_SAMPLES * sample.channels, sample.channels, audio_channel_layout::stereo, src, reinterpret_cast<f32*>(dst_buffer.block.data()));
}
else
{
File diff suppressed because it is too large Load Diff
+26 -11
View File
@@ -38,19 +38,34 @@ struct CellRtcDateTime
be_t<u32> microsecond; // 0 to 999999
};
error_code cellRtcTickAddYears(vm::ptr<CellRtcTick> pTick0, vm::cptr<CellRtcTick> pTick1, s32 iAdd);
error_code cellRtcTickAddMonths(vm::ptr<CellRtcTick> pTick0, vm::cptr<CellRtcTick> pTick1, s32 lAdd);
error_code cellRtcTickAddDays(vm::ptr<CellRtcTick> pTick0, vm::cptr<CellRtcTick> pTick1, s32 lAdd);
error_code cellRtcTickAddHours(vm::ptr<CellRtcTick> pTick0, vm::cptr<CellRtcTick> pTick1, s32 lAdd);
error_code cellRtcTickAddMinutes(vm::ptr<CellRtcTick> pTick0, vm::cptr<CellRtcTick> pTick1, s64 lAdd);
error_code cellRtcTickAddSeconds(vm::ptr<CellRtcTick> pTick0, vm::cptr<CellRtcTick> pTick1, s64 lAdd);
constexpr u64 RTC_MAGIC_OFFSET = 62135596800000000ull; // 1970-01-01 00:00:00.000000
constexpr u64 RTC_FILETIME_OFFSET = 50491123200000000ull; // 1601-01-01 00:00:00.000000
constexpr u64 RTC_SYSTEM_TIME_MIN = 63082281600000000ull; // 2000-01-01 00:00:00.000000
constexpr u64 RTC_SYSTEM_TIME_MAX = 66238041599999999ull; // 2099-12-31 23:59:59.999999
error_code cellRtcSetTick(vm::ptr<CellRtcDateTime> pTime, vm::cptr<CellRtcTick> pTick);
u32 cellRtcGetTickResolution();
constexpr u32 DAYS_IN_400_YEARS = 365 * 400 + 97;
constexpr u16 DAYS_IN_100_YEARS = 365 * 100 + 24;
constexpr u16 DAYS_IN_4_YEARS = 365 * 4 + 1;
constexpr std::array<u8, 12> DAYS_IN_MONTH = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
constexpr std::array<u8, 12> DAYS_IN_MONTH_LEAP = { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
constexpr std::array<u16, 13> MONTH_OFFSET = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, umax };
constexpr std::array<u16, 13> MONTH_OFFSET_LEAP = { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, umax };
constexpr std::array<std::string_view, 7> WEEKDAY_NAMES = { "sunday", "monday", "tuesday", "wednesday", "thursday", "friday", "saturday" };
constexpr std::array<std::string_view, 12> MONTH_NAMES = { "january", "february", "march", "april", "may", "june", "july", "august", "september", "october", "november", "december" };
constexpr std::array<std::string_view, 70> TIME_ZONE_NAMES = { "gmt", "est", "edt", "cst", "cdt", "mst", "mdt", "pst", "pdt", "nzdt", "nzst", "idle", "nzt", "aesst", "acsst", "cadt", "sadt", "aest", "east", "gst", "ligt", "acst", "sast", "cast", "awsst", "jst", "kst", "wdt", "mt", "awst", "cct", "wadt", "wst", "jt", "wast", "it", "bt", "eetdst", "eet", "cetdst", "fwt", "ist", "mest", "metdst", "sst", "bst", "cet", "dnt", "fst", "met", "mewt", "mez", "nor", "set", "swt", "wetdst", "wet", "wat", "ndt", "adt", "nft", "nst", "ast", "ydt", "hdt", "yst", "ahst", "cat", "nt", "idlw" };
constexpr std::array<s8, 70> TIME_ZONE_VALUES = { 0, -10, -8, -12, -10, -14, -12, -16, -14, 26, 24, 24, 24, 22, 21, 21, 21, 20, 20, 20, 20, 19, 19, 19, 18, 18, 18, 18, 17, 16, 16, 16, 16, 15, 14, 7, 6, 6, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, -2, -3, -6, -5, -5, -8, -16, -18, -18, -20, -20, -22, -24 }; // In units of 30 minutes
error_code cellRtcTickAddMinutes(ppu_thread& ppu, vm::ptr<CellRtcTick> pTick0, vm::cptr<CellRtcTick> pTick1, s64 lAdd);
error_code cellRtcSetTick(ppu_thread& ppu, vm::ptr<CellRtcDateTime> pTime, vm::cptr<CellRtcTick> pTick);
constexpr u32 cellRtcGetTickResolution();
error_code cellRtcCheckValid(vm::cptr<CellRtcDateTime> pTime);
error_code cellRtcGetDayOfWeek(s32 year, s32 month, s32 day);
error_code cellRtcGetTick(vm::cptr<CellRtcDateTime> pTime, vm::ptr<CellRtcTick> pTick);
error_code cellRtcGetCurrentTick(vm::ptr<CellRtcTick> pTick);
s32 cellRtcGetDayOfWeek(s32 year, s32 month, s32 day);
error_code cellRtcGetTick(ppu_thread& ppu, vm::cptr<CellRtcDateTime> pTime, vm::ptr<CellRtcTick> pTick);
error_code cellRtcGetCurrentTick(ppu_thread& ppu, vm::ptr<CellRtcTick> pTick);
CellRtcDateTime tick_to_date_time(u64 tick);
u64 date_time_to_tick(CellRtcDateTime date_time);
+19 -2
View File
@@ -3,6 +3,7 @@
#include "Emu/VFS.h"
#include "Emu/IdManager.h"
#include "Emu/localized_string.h"
#include "Emu/savestate_utils.hpp"
#include "Emu/Cell/lv2/sys_fs.h"
#include "Emu/Cell/lv2/sys_sync.h"
#include "Emu/Cell/lv2/sys_process.h"
@@ -272,6 +273,14 @@ static std::vector<SaveDataEntry> get_save_entries(const std::string& base_dir,
static error_code select_and_delete(ppu_thread& ppu)
{
std::unique_lock hle_lock(g_fxo->get<hle_locks_t>(), std::try_to_lock);
if (!hle_lock)
{
ppu.state += cpu_flag::again;
return {};
}
std::unique_lock lock(g_fxo->get<savedata_manager>().mutex, std::try_to_lock);
if (!lock)
@@ -699,6 +708,14 @@ static NEVER_INLINE error_code savedata_op(ppu_thread& ppu, u32 operation, u32 v
return {CELL_SAVEDATA_ERROR_PARAM, " (error %d)", ecode};
}
std::unique_lock hle_lock(g_fxo->get<hle_locks_t>(), std::try_to_lock);
if (!hle_lock)
{
ppu.state += cpu_flag::again;
return {};
}
std::unique_lock lock(g_fxo->get<savedata_manager>().mutex, std::try_to_lock);
if (!lock)
@@ -1104,7 +1121,7 @@ static NEVER_INLINE error_code savedata_op(ppu_thread& ppu, u32 operation, u32 v
auto delete_save = [&]()
{
strcpy_trunc(doneGet->dirName, save_entries[selected].dirName);
doneGet->hddFreeSizeKB = 40 * 1024 * 1024 - 1; // Read explanation in cellHddGameCheck
doneGet->hddFreeSizeKB = 40 * 1024 * 1024 - 256; // Read explanation in cellHddGameCheck
doneGet->excResult = CELL_OK;
std::memset(doneGet->reserved, 0, sizeof(doneGet->reserved));
@@ -1446,7 +1463,7 @@ static NEVER_INLINE error_code savedata_op(ppu_thread& ppu, u32 operation, u32 v
// funcStat is called even if the directory doesn't exist.
}
statGet->hddFreeSizeKB = 40 * 1024 * 1024 - 1; // Read explanation in cellHddGameCheck
statGet->hddFreeSizeKB = 40 * 1024 * 1024 - 256; // Read explanation in cellHddGameCheck
statGet->isNewData = save_entry.isNew = psf.empty();
statGet->dir.atime = save_entry.atime = dir_info.atime;
+11 -4
View File
@@ -134,24 +134,31 @@ error_code cellScreenShotSetOverlayImage(vm::cptr<char> srcDir, vm::cptr<char> s
error_code cellScreenShotEnable()
{
cellScreenshot.warning("cellScreenShotEnable()");
cellScreenshot.trace("cellScreenShotEnable()");
auto& manager = g_fxo->get<screenshot_manager>();
std::lock_guard lock(manager.mutex);
manager.is_enabled = true;
if (!std::exchange(manager.is_enabled, true))
{
cellScreenshot.warning("cellScreenShotEnable(): Enabled");
}
return CELL_OK;
}
error_code cellScreenShotDisable()
{
cellScreenshot.warning("cellScreenShotDisable()");
cellScreenshot.trace("cellScreenShotDisable()");
auto& manager = g_fxo->get<screenshot_manager>();
std::lock_guard lock(manager.mutex);
manager.is_enabled = false;
if (std::exchange(manager.is_enabled, false))
{
cellScreenshot.warning("cellScreenShotDisable(): Disabled");
}
return CELL_OK;
}
+1
View File
@@ -469,6 +469,7 @@ error_code cellSysutilGetSystemParamString(CellSysutilParamId id, vm::ptr<char>
case CELL_SYSUTIL_SYSTEMPARAM_ID_NICKNAME:
{
copy_size = CELL_SYSUTIL_SYSTEMPARAM_NICKNAME_SIZE;
param_str = g_cfg.sys.system_name.to_string();
break;
}
+409 -61
View File
@@ -1,5 +1,7 @@
#include "stdafx.h"
#include "Emu/Cell/PPUModule.h"
#include "Emu/IdManager.h"
#include "util/asm.hpp"
#include "sceNp.h"
#include "sceNp2.h"
@@ -59,8 +61,56 @@ void fmt_class_string<CellSysutilAvc2AttributeId>::format(std::string& out, u64
});
}
vm::ptr<CellSysutilAvc2Callback> avc2_cb{};
vm::ptr<void> avc2_cb_arg{};
struct avc2_settings
{
avc2_settings() = default;
avc2_settings(const avc2_settings&) = delete;
avc2_settings& operator=(const avc2_settings&) = delete;
SAVESTATE_INIT_POS(52);
vm::ptr<CellSysutilAvc2Callback> avc2_cb{};
vm::ptr<void> avc2_cb_arg{};
u32 streaming_mode = CELL_SYSUTIL_AVC2_STREAMING_MODE_NORMAL;
u8 mic_out_stream_sharing = 0;
u8 video_stream_sharing = 0;
u32 total_video_bitrate = 0;
std::set<u16> voice_muting_players;
bool voice_muting = 1;
bool video_muting = 1;
bool speaker_muting = 1;
f32 speaker_volume_level = 40.0f;
static bool saveable(bool /*is_writing*/) noexcept
{
return GET_SERIALIZATION_VERSION(cellSysutil) != 0;
}
avc2_settings(utils::serial& ar) noexcept
{
[[maybe_unused]] const s32 version = GET_SERIALIZATION_VERSION(cellSysutil);
if (version == 0)
{
return;
}
save(ar);
}
void save(utils::serial& ar)
{
[[maybe_unused]] const s32 version = GET_OR_USE_SERIALIZATION_VERSION(ar.is_writing(), cellSysutil);
ar(avc2_cb, avc2_cb_arg, streaming_mode, mic_out_stream_sharing, video_stream_sharing, total_video_bitrate);
if (ar.is_writing() || version >= 2)
{
ar(voice_muting_players, voice_muting, video_muting, speaker_muting, speaker_volume_level);
}
}
};
error_code cellSysutilAvc2GetPlayerInfo(vm::cptr<SceNpMatching2RoomMemberId> player_id, vm::ptr<CellSysutilAvc2PlayerInfo> player_info)
{
@@ -83,13 +133,15 @@ error_code cellSysutilAvc2JoinChat(vm::cptr<SceNpMatching2RoomId> room_id, vm::p
// NOTE: room_id should be null if the current mode is Direct WAN/LAN
auto& settings = g_fxo->get<avc2_settings>();
[[maybe_unused]] u64 id = 0UL;
if (room_id)
{
id = *room_id;
}
else if (false/*streaming_mode != CELL_SYSUTIL_AVC2_STREAMING_MODE_NORMAL*/) // TODO
else if (settings.streaming_mode != CELL_SYSUTIL_AVC2_STREAMING_MODE_NORMAL)
{
return CELL_AVC2_ERROR_INVALID_ARGUMENT;
}
@@ -124,7 +176,8 @@ error_code cellSysutilAvc2GetVideoMuting(vm::ptr<u8> muting)
if (!muting)
return CELL_AVC2_ERROR_INVALID_ARGUMENT;
*muting = 1;
const auto& settings = g_fxo->get<avc2_settings>();
*muting = settings.video_muting;
return CELL_OK;
}
@@ -172,6 +225,10 @@ error_code cellSysutilAvc2StopStreaming2(u32 mediaType)
error_code cellSysutilAvc2SetVoiceMuting(u8 muting)
{
cellSysutilAvc2.todo("cellSysutilAvc2SetVoiceMuting(muting=0x%x)", muting);
auto& settings = g_fxo->get<avc2_settings>();
settings.voice_muting = muting;
return CELL_OK;
}
@@ -181,22 +238,6 @@ error_code cellSysutilAvc2StartVoiceDetection()
return CELL_OK;
}
error_code cellSysutilAvc2UnloadAsync()
{
cellSysutilAvc2.todo("cellSysutilAvc2UnloadAsync()");
if (avc2_cb)
{
sysutil_register_cb([=](ppu_thread& cb_ppu) -> s32
{
avc2_cb(cb_ppu, CELL_AVC2_EVENT_UNLOAD_SUCCEEDED, 0, avc2_cb_arg);
return 0;
});
}
return CELL_OK;
}
error_code cellSysutilAvc2StopVoiceDetection()
{
cellSysutilAvc2.todo("cellSysutilAvc2StopVoiceDetection()");
@@ -241,28 +282,13 @@ error_code cellSysutilAvc2GetAttribute(vm::ptr<CellSysutilAvc2Attribute> attr)
return CELL_OK;
}
error_code cellSysutilAvc2LoadAsync(SceNpMatching2ContextId ctx_id, u32 container, vm::ptr<CellSysutilAvc2Callback> callback_func, vm::ptr<void> user_data, vm::cptr<CellSysutilAvc2InitParam> init_param)
{
cellSysutilAvc2.warning("cellSysutilAvc2LoadAsync(ctx_id=0x%x, container=0x%x, callback_func=*0x%x, user_data=*0x%x, init_param=*0x%x)", ctx_id, container, callback_func, user_data, init_param);
avc2_cb = callback_func;
avc2_cb_arg = user_data;
if (avc2_cb)
{
sysutil_register_cb([=](ppu_thread& cb_ppu) -> s32
{
avc2_cb(cb_ppu, CELL_AVC2_EVENT_LOAD_SUCCEEDED, 0, avc2_cb_arg);
return 0;
});
}
return CELL_OK;
}
error_code cellSysutilAvc2SetSpeakerVolumeLevel(f32 level)
{
cellSysutilAvc2.todo("cellSysutilAvc2SetSpeakerVolumeLevel(level=0x%x)", level);
auto& settings = g_fxo->get<avc2_settings>();
settings.speaker_volume_level = level;
return CELL_OK;
}
@@ -366,12 +392,27 @@ error_code cellSysutilAvc2SetVideoMuting(u8 muting)
if (muting > 1) // Weird check, lol
return CELL_AVC2_ERROR_INVALID_ARGUMENT;
auto& settings = g_fxo->get<avc2_settings>();
settings.video_muting = muting;
return CELL_OK;
}
error_code cellSysutilAvc2SetPlayerVoiceMuting(SceNpMatching2RoomMemberId member_id, u8 muting)
{
cellSysutilAvc2.todo("cellSysutilAvc2SetPlayerVoiceMuting(member_id=0x%x, muting=0x%x)", member_id, muting);
auto& settings = g_fxo->get<avc2_settings>();
if (muting)
{
settings.voice_muting_players.insert(member_id);
}
else
{
settings.voice_muting_players.erase(member_id);
}
return CELL_OK;
}
@@ -386,7 +427,36 @@ error_code cellSysutilAvc2Unload()
{
cellSysutilAvc2.todo("cellSysutilAvc2Unload()");
// TODO: CELL_AVC2_ERROR_NOT_INITIALIZED
auto& settings = g_fxo->get<avc2_settings>();
if (!settings.avc2_cb)
{
return CELL_AVC2_ERROR_NOT_INITIALIZED;
}
settings.avc2_cb = vm::null;
settings.avc2_cb_arg = vm::null;
return CELL_OK;
}
error_code cellSysutilAvc2UnloadAsync()
{
cellSysutilAvc2.todo("cellSysutilAvc2UnloadAsync()");
auto& settings = g_fxo->get<avc2_settings>();
if (settings.avc2_cb)
{
sysutil_register_cb([=, avc2_cb = settings.avc2_cb, avc2_cb_arg = settings.avc2_cb_arg](ppu_thread& cb_ppu) -> s32
{
avc2_cb(cb_ppu, CELL_AVC2_EVENT_UNLOAD_SUCCEEDED, 0, avc2_cb_arg);
return 0;
});
}
settings.avc2_cb = vm::null;
settings.avc2_cb_arg = vm::null;
return CELL_OK;
}
@@ -410,7 +480,8 @@ error_code cellSysutilAvc2GetSpeakerVolumeLevel(vm::ptr<f32> level)
if (!level)
return CELL_AVC2_ERROR_INVALID_ARGUMENT;
*level = 100;
const auto& settings = g_fxo->get<avc2_settings>();
*level = settings.speaker_volume_level;
return CELL_OK;
}
@@ -431,7 +502,36 @@ error_code cellSysutilAvc2MicRead(vm::ptr<void> ptr, vm::ptr<u32> pSize)
{
cellSysutilAvc2.todo("cellSysutilAvc2MicRead(ptr=*0x%x, pSize=*0x%x)", ptr, pSize);
// TODO: check arguments ?
const auto& settings = g_fxo->get<avc2_settings>();
if (!settings.mic_out_stream_sharing)
return CELL_OK;
if (!ptr || !pSize)
{
// Not checked on real hardware
cellSysutilAvc2.warning("cellSysutilAvc2MicRead: ptr or pSize is null");
if (pSize)
{
*pSize = 0;
}
return CELL_OK;
}
// TODO: ringbuffer (holds 100ms of 16kHz single channel f32 samples)
std::vector<u8> buf{};
u32 size_read = 0;
if (u32 size_to_read = *pSize; size_to_read > 0 && !buf.empty())
{
size_read = std::min(size_to_read, ::size32(buf));
std::memcpy(ptr.get_ptr(), buf.data(), size_read);
}
*pSize = size_read;
return CELL_OK;
}
@@ -443,7 +543,8 @@ error_code cellSysutilAvc2GetPlayerVoiceMuting(SceNpMatching2RoomMemberId member
if (!muting)
return CELL_AVC2_ERROR_INVALID_ARGUMENT;
*muting = 0;
const auto& settings = g_fxo->get<avc2_settings>();
*muting = settings.voice_muting_players.contains(member_id);
return CELL_OK;
}
@@ -454,22 +555,24 @@ error_code cellSysutilAvc2JoinChatRequest(vm::cptr<SceNpMatching2RoomId> room_id
// NOTE: room_id should be null if the current mode is Direct WAN/LAN
const auto& settings = g_fxo->get<avc2_settings>();
[[maybe_unused]] u64 id = 0UL;
if (room_id)
{
id = *room_id;
}
else if (false/*streaming_mode != CELL_SYSUTIL_AVC2_STREAMING_MODE_NORMAL*/) // TODO
else if (settings.streaming_mode != CELL_SYSUTIL_AVC2_STREAMING_MODE_NORMAL)
{
return CELL_AVC2_ERROR_INVALID_ARGUMENT;
}
// TODO: join chat
if (avc2_cb)
if (settings.avc2_cb)
{
sysutil_register_cb([=](ppu_thread& cb_ppu) -> s32
sysutil_register_cb([=, avc2_cb = settings.avc2_cb, avc2_cb_arg = settings.avc2_cb_arg](ppu_thread& cb_ppu) -> s32
{
avc2_cb(cb_ppu, CELL_AVC2_EVENT_JOIN_SUCCEEDED, 0, avc2_cb_arg);
return 0;
@@ -572,9 +675,11 @@ error_code cellSysutilAvc2LeaveChatRequest()
{
cellSysutilAvc2.notice("cellSysutilAvc2LeaveChatRequest()");
if (avc2_cb)
const auto& settings = g_fxo->get<avc2_settings>();
if (settings.avc2_cb)
{
sysutil_register_cb([=](ppu_thread& cb_ppu) -> s32
sysutil_register_cb([=, avc2_cb = settings.avc2_cb, avc2_cb_arg = settings.avc2_cb_arg](ppu_thread& cb_ppu) -> s32
{
avc2_cb(cb_ppu, CELL_AVC2_EVENT_LEAVE_SUCCEEDED, 0, avc2_cb_arg);
return 0;
@@ -608,7 +713,8 @@ error_code cellSysutilAvc2GetSpeakerMuting(vm::ptr<u8> muting)
if (!muting)
return CELL_AVC2_ERROR_INVALID_ARGUMENT;
*muting = 1;
const auto& settings = g_fxo->get<avc2_settings>();
*muting = settings.speaker_muting;
return CELL_OK;
}
@@ -668,12 +774,204 @@ error_code cellSysutilAvc2LeaveChat()
error_code cellSysutilAvc2SetSpeakerMuting(u8 muting)
{
cellSysutilAvc2.todo("cellSysutilAvc2SetSpeakerMuting(muting=0x%x)", muting);
auto& settings = g_fxo->get<avc2_settings>();
settings.speaker_muting = muting;
return CELL_OK;
}
error_code cellSysutilAvc2Load_shared(SceNpMatching2ContextId /*ctx_id*/, u32 /*container*/, vm::ptr<CellSysutilAvc2Callback> callback_func, vm::ptr<void> user_data, vm::cptr<CellSysutilAvc2InitParam> init_param)
{
if (!init_param || !init_param->avc_init_param_version ||
!(init_param->avc_init_param_version == 100 ||
init_param->avc_init_param_version == 110 ||
init_param->avc_init_param_version == 120 ||
init_param->avc_init_param_version == 130 ||
init_param->avc_init_param_version == 140)
)
{
return CELL_AVC2_ERROR_INVALID_ARGUMENT;
}
auto& settings = g_fxo->get<avc2_settings>();
switch (init_param->media_type)
{
case CELL_SYSUTIL_AVC2_VOICE_CHAT:
{
if (init_param->max_players < 2 ||
init_param->max_players > 64 ||
init_param->spu_load_average > 100 ||
init_param->voice_param.voice_quality != CELL_SYSUTIL_AVC2_VOICE_QUALITY_NORMAL ||
init_param->voice_param.max_speakers == 0 ||
init_param->voice_param.max_speakers > 16
)
{
return CELL_AVC2_ERROR_INVALID_ARGUMENT;
}
u32 streaming_mode = init_param->direct_streaming_mode;
if (init_param->avc_init_param_version >= 120)
{
switch (init_param->direct_streaming_mode)
{
case CELL_SYSUTIL_AVC2_STREAMING_MODE_NORMAL:
streaming_mode = CELL_SYSUTIL_AVC2_STREAMING_MODE_NORMAL;
break;
case CELL_SYSUTIL_AVC2_STREAMING_MODE_DIRECT_WAN:
break;
case CELL_SYSUTIL_AVC2_STREAMING_MODE_DIRECT_LAN:
if (init_param->streaming_mode.mode == CELL_SYSUTIL_AVC2_STREAMING_MODE_NORMAL)
{
settings.streaming_mode = streaming_mode;
return CELL_AVC2_ERROR_INVALID_ARGUMENT;
}
break;
default:
return CELL_AVC2_ERROR_INVALID_ARGUMENT;
}
}
else if (init_param->avc_init_param_version >= 110)
{
switch (init_param->direct_streaming_mode)
{
case CELL_SYSUTIL_AVC2_STREAMING_MODE_NORMAL:
case CELL_SYSUTIL_AVC2_STREAMING_MODE_DIRECT_WAN:
break;
case CELL_SYSUTIL_AVC2_STREAMING_MODE_DIRECT_LAN:
default:
return CELL_AVC2_ERROR_INVALID_ARGUMENT;
}
}
else
{
streaming_mode = settings.streaming_mode;
}
settings.streaming_mode = streaming_mode;
settings.mic_out_stream_sharing = init_param->voice_param.mic_out_stream_sharing;
if (!callback_func)
{
return CELL_AVC2_ERROR_INVALID_ARGUMENT;
}
if (settings.avc2_cb)
{
return CELL_AVC2_ERROR_ALREADY_INITIALIZED;
}
settings.avc2_cb = callback_func;
settings.avc2_cb_arg = user_data;
break;
}
case CELL_SYSUTIL_AVC2_VIDEO_CHAT:
{
if (false) // TODO: syscall to check container
{
return CELL_AVC2_ERROR_INVALID_ARGUMENT;
}
if (init_param->avc_init_param_version <= 140)
{
if (false) // TODO
{
return CELL_AVC2_ERROR_OUT_OF_MEMORY;
}
}
if (callback_func)
{
return CELL_AVC2_ERROR_INVALID_ARGUMENT;
}
if (init_param->video_param.max_video_windows == 0 ||
init_param->video_param.max_video_windows > (init_param->video_param.frame_mode == CELL_SYSUTIL_AVC2_FRAME_MODE_NORMAL ? 6 : 16))
{
return CELL_AVC2_ERROR_INVALID_ARGUMENT;
}
if (init_param->video_param.max_video_bitrate < 1000 || init_param->video_param.max_video_bitrate > 512000)
{
return CELL_AVC2_ERROR_INVALID_ARGUMENT;
}
if (init_param->video_param.max_video_framerate == 0 || init_param->video_param.max_video_framerate > 30)
{
return CELL_AVC2_ERROR_INVALID_ARGUMENT;
}
s32 bitrate = 0;
switch (init_param->video_param.max_video_resolution)
{
case CELL_SYSUTIL_AVC2_VIDEO_RESOLUTION_QQVGA:
bitrate = 76800;
break;
case CELL_SYSUTIL_AVC2_VIDEO_RESOLUTION_QVGA:
bitrate = 307200;
break;
default:
break;
}
u32 total_bitrate = 0;
if (bitrate != 0)
{
u32 window_count = init_param->video_param.max_video_windows;
if (init_param->video_param.video_stream_sharing == CELL_SYSUTIL_AVC2_VIDEO_SHARING_MODE_2)
{
window_count++;
}
total_bitrate = utils::align<u32>(window_count * bitrate, 0x100000) + 0x100000;
}
settings.video_stream_sharing = init_param->video_param.video_stream_sharing;
settings.total_video_bitrate = total_bitrate;
break;
}
default:
return CELL_AVC2_ERROR_NOT_SUPPORTED;
}
return CELL_OK;
}
error_code cellSysutilAvc2Load(SceNpMatching2ContextId ctx_id, u32 container, vm::ptr<CellSysutilAvc2Callback> callback_func, vm::ptr<void> user_data, vm::cptr<CellSysutilAvc2InitParam> init_param)
{
cellSysutilAvc2.todo("cellSysutilAvc2Load(ctx_id=0x%x, container=0x%x, callback_func=*0x%x, user_data=*0x%x, init_param=*0x%x)", ctx_id, container, callback_func, user_data, init_param);
cellSysutilAvc2.warning("cellSysutilAvc2Load(ctx_id=0x%x, container=0x%x, callback_func=*0x%x, user_data=*0x%x, init_param=*0x%x)", ctx_id, container, callback_func, user_data, init_param);
error_code error = cellSysutilAvc2Load_shared(ctx_id, container, callback_func, user_data, init_param);
if (error != CELL_OK)
return error;
return CELL_OK;
}
error_code cellSysutilAvc2LoadAsync(SceNpMatching2ContextId ctx_id, u32 container, vm::ptr<CellSysutilAvc2Callback> callback_func, vm::ptr<void> user_data, vm::cptr<CellSysutilAvc2InitParam> init_param)
{
cellSysutilAvc2.warning("cellSysutilAvc2LoadAsync(ctx_id=0x%x, container=0x%x, callback_func=*0x%x, user_data=*0x%x, init_param=*0x%x)", ctx_id, container, callback_func, user_data, init_param);
error_code error = cellSysutilAvc2Load_shared(ctx_id, container, callback_func, user_data, init_param);
if (error != CELL_OK)
return error;
auto& settings = g_fxo->get<avc2_settings>();
if (settings.avc2_cb && init_param && init_param->media_type == CELL_SYSUTIL_AVC2_VOICE_CHAT)
{
sysutil_register_cb([=, avc2_cb = settings.avc2_cb, avc2_cb_arg = settings.avc2_cb_arg](ppu_thread& cb_ppu) -> s32
{
avc2_cb(cb_ppu, CELL_AVC2_EVENT_LOAD_SUCCEEDED, 0, avc2_cb_arg);
return 0;
});
}
return CELL_OK;
}
@@ -718,6 +1016,39 @@ error_code cellSysutilAvc2SetAttribute(vm::cptr<CellSysutilAvc2Attribute> attr)
return CELL_OK;
}
error_code cellSysutilAvc2Unload2(u32 mediaType)
{
cellSysutilAvc2.todo("cellSysutilAvc2Unload2(mediaType=0x%x)", mediaType);
auto& settings = g_fxo->get<avc2_settings>();
switch (mediaType)
{
case CELL_SYSUTIL_AVC2_VOICE_CHAT:
{
if (!settings.avc2_cb)
{
return CELL_AVC2_ERROR_NOT_INITIALIZED;
}
// TODO: return error if the video chat is still loaded (probably CELL_AVC2_ERROR_INVALID_STATUS)
settings.avc2_cb = vm::null;
settings.avc2_cb_arg = vm::null;
break;
}
case CELL_SYSUTIL_AVC2_VIDEO_CHAT:
{
// TODO
break;
}
default:
return CELL_AVC2_ERROR_INVALID_ARGUMENT;
}
return CELL_OK;
}
error_code cellSysutilAvc2UnloadAsync2(u32 mediaType)
{
cellSysutilAvc2.todo("cellSysutilAvc2UnloadAsync2(mediaType=0x%x)", mediaType);
@@ -725,6 +1056,32 @@ error_code cellSysutilAvc2UnloadAsync2(u32 mediaType)
if (mediaType != CELL_SYSUTIL_AVC2_VOICE_CHAT && mediaType != CELL_SYSUTIL_AVC2_VIDEO_CHAT)
return CELL_AVC2_ERROR_INVALID_ARGUMENT;
auto& settings = g_fxo->get<avc2_settings>();
if (settings.avc2_cb)
{
if (mediaType == CELL_SYSUTIL_AVC2_VOICE_CHAT)
{
// TODO: signal CELL_AVC2_EVENT_UNLOAD_FAILED instead if the video chat is still loaded
}
sysutil_register_cb([=, avc2_cb = settings.avc2_cb, avc2_cb_arg = settings.avc2_cb_arg](ppu_thread& cb_ppu) -> s32
{
avc2_cb(cb_ppu, CELL_AVC2_EVENT_UNLOAD_SUCCEEDED, 0, avc2_cb_arg);
return 0;
});
if (mediaType == CELL_SYSUTIL_AVC2_VOICE_CHAT)
{
settings.avc2_cb = vm::null;
settings.avc2_cb_arg = vm::null;
}
else
{
// TODO: unload video chat.
}
}
return CELL_OK;
}
@@ -757,7 +1114,8 @@ error_code cellSysutilAvc2GetVoiceMuting(vm::ptr<u8> muting)
if (!muting)
return CELL_AVC2_ERROR_INVALID_ARGUMENT;
*muting = 1;
const auto& settings = g_fxo->get<avc2_settings>();
*muting = settings.voice_muting;
return CELL_OK;
}
@@ -774,16 +1132,6 @@ error_code cellSysutilAvc2GetScreenShowStatus(vm::ptr<u8> visible)
return CELL_OK;
}
error_code cellSysutilAvc2Unload2(u32 mediaType)
{
cellSysutilAvc2.todo("cellSysutilAvc2Unload2(mediaType=0x%x)", mediaType);
if (mediaType != CELL_SYSUTIL_AVC2_VOICE_CHAT && mediaType != CELL_SYSUTIL_AVC2_VIDEO_CHAT)
return CELL_AVC2_ERROR_INVALID_ARGUMENT;
return CELL_OK;
}
error_code cellSysutilAvc2GetWindowPosition(SceNpMatching2RoomMemberId member_id, vm::ptr<f32> x, vm::ptr<f32> y, vm::ptr<f32> z)
{
cellSysutilAvc2.todo("cellSysutilAvc2GetWindowPosition(member_id=0x%x, x=*0x%x, y=*0x%x, z=*0x%x)", member_id, x, y, z);
+1 -1
View File
@@ -233,8 +233,8 @@ struct CellSysutilAvc2InitParam
be_t<u16> direct_streaming_mode;
CellSysutilAvc2StreamingModeParam streaming_mode;
};
be_t<u32> media_type;
u8 reserved[18];
be_t<u32> media_type;
CellSysutilAvc2VoiceInitParam voice_param;
CellSysutilAvc2VideoInitParam video_param;
u8 reserved2[22];
+16 -30
View File
@@ -5,9 +5,9 @@
#include "Emu/Cell/lv2/sys_sync.h"
#include "Emu/Cell/lv2/sys_ppu_thread.h"
#include "Emu/Cell/lv2/sys_process.h"
#include "Emu/savestate_utils.hpp"
#include "sysPrxForUser.h"
#include "util/media_utils.h"
#include "util/init_mutex.hpp"
#ifdef _MSC_VER
#pragma warning(push, 0)
@@ -625,38 +625,16 @@ struct vdec_context final
}
};
struct vdec_creation_lock
extern bool check_if_vdec_contexts_exist()
{
stx::init_mutex locked;
bool context_exists = false;
vdec_creation_lock()
idm::select<vdec_context>([&](u32, vdec_context&)
{
auto lk = locked.init();
}
};
context_exists = true;
});
extern bool try_lock_vdec_context_creation()
{
auto& lock = g_fxo->get<vdec_creation_lock>();
auto reset = lock.locked.reset();
if (reset)
{
bool context_exists = false;
idm::select<vdec_context>([&](u32, vdec_context&)
{
context_exists = true;
});
if (context_exists)
{
reset.set_init();
return false;
}
}
return true;
return context_exists;
}
extern void vdecEntry(ppu_thread& ppu, u32 vid)
@@ -890,7 +868,7 @@ static error_code vdecOpen(ppu_thread& ppu, T type, U res, vm::cptr<CellVdecCb>
// Create decoder context
std::shared_ptr<vdec_context> vdec;
if (auto access = g_fxo->get<vdec_creation_lock>().locked.access(); access)
if (std::unique_lock lock{g_fxo->get<hle_locks_t>(), std::try_to_lock})
{
vdec = idm::make_ptr<vdec_context>(type->codecType, type->profileLevel, res->memAddr, res->memSize, cb->cbFunc, cb->cbArg);
}
@@ -943,6 +921,14 @@ error_code cellVdecClose(ppu_thread& ppu, u32 handle)
{
cellVdec.warning("cellVdecClose(handle=0x%x)", handle);
std::unique_lock lock_hle{g_fxo->get<hle_locks_t>(), std::try_to_lock};
if (!lock_hle)
{
ppu.state += cpu_flag::again;
return {};
}
auto vdec = idm::get<vdec_context>(handle);
if (!vdec)
+3 -3
View File
@@ -3896,7 +3896,7 @@ error_code sceNpManagerGetAvatarUrl(vm::ptr<SceNpAvatarUrl> avatarUrl)
error_code sceNpManagerGetMyLanguages(vm::ptr<SceNpMyLanguages> myLanguages)
{
sceNp.warning("sceNpManagerGetMyLanguages(myLanguages=*0x%x)", myLanguages);
sceNp.trace("sceNpManagerGetMyLanguages(myLanguages=*0x%x)", myLanguages);
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
@@ -5834,8 +5834,8 @@ error_code scenp_score_get_ranking_by_npid(s32 transId, SceNpScoreBoardId boardI
std::vector<std::pair<SceNpId, s32>> npid_vec;
static constexpr bool is_npid = std::is_same<T, vm::cptr<SceNpId>>::value;
static constexpr bool is_npidpcid = std::is_same<T, vm::cptr<SceNpScoreNpIdPcId>>::value;
static constexpr bool is_npid = std::is_same_v<T, vm::cptr<SceNpId>>;
static constexpr bool is_npidpcid = std::is_same_v<T, vm::cptr<SceNpScoreNpIdPcId>>;
static_assert(is_npid || is_npidpcid, "T should be vm::cptr<SceNpId> or vm::cptr<SceNpScoreNpIdPcId>");
if constexpr (is_npid)
+2 -2
View File
@@ -986,7 +986,7 @@ error_code sceNpTrophyGetLatestTrophies()
return CELL_OK;
}
error_code sceNpTrophyUnlockTrophy(u32 context, u32 handle, s32 trophyId, vm::ptr<u32> platinumId)
error_code sceNpTrophyUnlockTrophy(ppu_thread& ppu, u32 context, u32 handle, s32 trophyId, vm::ptr<u32> platinumId)
{
sceNpTrophy.warning("sceNpTrophyUnlockTrophy(context=0x%x, handle=0x%x, trophyId=%d, platinumId=*0x%x)", context, handle, trophyId, platinumId);
@@ -1028,7 +1028,7 @@ error_code sceNpTrophyUnlockTrophy(u32 context, u32 handle, s32 trophyId, vm::pt
}
vm::var<CellRtcTick> tick;
if (error_code error = cellRtcGetCurrentTick(tick))
if (error_code error = cellRtcGetCurrentTick(ppu, tick))
{
sceNpTrophy.error("sceNpTrophyUnlockTrophy: Failed to get timestamp: 0x%x", +error);
}
+10 -6
View File
@@ -241,28 +241,32 @@ protected:
{
fmt::append(last_opcode, "%-*s cr%d,cr%d", PadOp(), op, cr0, cr1);
}
void DisAsm_INT3(std::string_view op, const int i0, const int i1, const int i2)
void DisAsm_INT3(std::string_view op, s32 i0, s32 i1, s32 i2)
{
fmt::append(last_opcode, "%-*s %d,%d,%d", PadOp(), op, i0, i1, i2);
}
void DisAsm_INT1(std::string_view op, const int i0)
void DisAsm_INT1(std::string_view op, s32 i0)
{
fmt::append(last_opcode, "%-*s %d", PadOp(), op, i0);
}
void DisAsm_BRANCH(std::string_view op, const int pc)
void DisAsm_BRANCH(std::string_view op, s32 pc)
{
fmt::append(last_opcode, "%-*s 0x%x", PadOp(), op, DisAsmBranchTarget(pc));
}
void DisAsm_BRANCH_A(std::string_view op, const int pc)
void DisAsm_BRANCH_A(std::string_view op, s32 pc)
{
fmt::append(last_opcode, "%-*s 0x%x", PadOp(), op, pc);
}
void DisAsm_B2_BRANCH(std::string_view op, u32 b0, u32 b1, const int pc)
void DisAsm_B2_BRANCH(std::string_view op, u32 b0, u32 b1, s32 pc)
{
fmt::append(last_opcode, "%-*s %d,%d,0x%x ", PadOp(), op, b0, b1, DisAsmBranchTarget(pc));
}
void DisAsm_CR_BRANCH(std::string_view op, u32 cr, const int pc)
void DisAsm_CR_BRANCH(std::string_view op, u32 cr, s32 pc)
{
fmt::append(last_opcode, "%-*s cr%d,0x%x ", PadOp(), op, cr, DisAsmBranchTarget(pc));
}
void DisAsm_CR_BRANCH_HINT(std::string_view op, u32 cr, u32 bh)
{
fmt::append(last_opcode, "%-*s cr%d,0x%x ", PadOp(), op, cr, bh);
}
};
+34 -2
View File
@@ -696,7 +696,7 @@ bool ppu_module::analyse(u32 lib_toc, u32 entry, const u32 sec_end, const std::b
const vm::cptr<void> seg_end = vm::cast(seg.addr + seg.size - 4);
auto ptr = get_ptr<u32>(_ptr);
for (vm::cptr<u32> _ptr = vm::cast(seg.addr); _ptr <= seg_end; advance(_ptr, ptr, 1))
for (; _ptr <= seg_end; advance(_ptr, ptr, 1))
{
const u32 value = *ptr;
@@ -929,6 +929,38 @@ bool ppu_module::analyse(u32 lib_toc, u32 entry, const u32 sec_end, const std::b
}
}
if (func_queue.empty() && segs[0].size >= 4u)
{
// Fallback, identify functions using callers (no jumptable detection, tail calls etc)
ppu_log.warning("Looking for PPU functions using callers. ('%s')", name);
vm::cptr<u32> _ptr = vm::cast(start);
const vm::cptr<void> seg_end = vm::cast(end - 4);
for (auto ptr = get_ptr<u32>(_ptr); _ptr <= seg_end; advance(_ptr, ptr, 1))
{
const u32 iaddr = _ptr.addr();
const ppu_opcode_t op{*ptr};
const ppu_itype::type type = s_ppu_itype.decode(op.opcode);
if (type == ppu_itype::B && op.lk && !op.aa)
{
const u32 target = iaddr + op.bt24;
if (target >= start && target < end && target != iaddr && target != iaddr + 4)
{
// TODO: Check full executability
if (s_ppu_itype.decode(get_ref<u32>(target)) != ppu_itype::UNK)
{
ppu_log.trace("Enqueued PPU function 0x%x using a caller at 0x%x", target, iaddr);
add_func(target, 0, 0);
}
}
}
}
}
// Main loop (func_queue may grow)
for (usz i = 0; i < func_queue.size(); i++)
{
@@ -1631,7 +1663,7 @@ bool ppu_module::analyse(u32 lib_toc, u32 entry, const u32 sec_end, const std::b
}
}
ppu_log.notice("Function analysis: %zu functions (%zu enqueued)", fmap.size(), func_queue.size());
(fmap.empty() ? ppu_log.error : ppu_log.notice)("Function analysis: %zu functions (%zu enqueued)", fmap.size(), func_queue.size());
// Decompose functions to basic blocks
if (!entry && !sec_end)
+12 -12
View File
@@ -27,8 +27,8 @@ namespace ppu_cb_detail
struct _func_arg
{
static_assert(type == ARG_GENERAL, "Unknown callback argument type");
static_assert(!std::is_pointer<T>::value, "Invalid callback argument type (pointer)");
static_assert(!std::is_reference<T>::value, "Invalid callback argument type (reference)");
static_assert(!std::is_pointer_v<T>, "Invalid callback argument type (pointer)");
static_assert(!std::is_reference_v<T>, "Invalid callback argument type (reference)");
static_assert(sizeof(T) <= 8, "Invalid callback argument type for ARG_GENERAL");
static inline void set_value(ppu_thread& CPU, const T& arg)
@@ -51,7 +51,7 @@ namespace ppu_cb_detail
template<typename T, u32 g_count, u32 f_count, u32 v_count>
struct _func_arg<T, ARG_VECTOR, g_count, f_count, v_count>
{
static_assert(std::is_same<std::decay_t<T>, v128>::value, "Invalid callback argument type for ARG_VECTOR");
static_assert(std::is_same_v<std::decay_t<T>, v128>, "Invalid callback argument type for ARG_VECTOR");
static inline void set_value(ppu_thread& CPU, const T& arg)
{
@@ -75,7 +75,7 @@ namespace ppu_cb_detail
template<typename T, u32 g_count, u32 f_count, u32 v_count>
struct _func_arg<T, ARG_CONTEXT, g_count, f_count, v_count>
{
static_assert(std::is_same<std::decay_t<T>, ppu_thread>::value, "Invalid callback argument type for ARG_CONTEXT");
static_assert(std::is_same_v<std::decay_t<T>, ppu_thread>, "Invalid callback argument type for ARG_CONTEXT");
FORCE_INLINE static void set_value(ppu_thread&, const T&)
{
@@ -92,9 +92,9 @@ namespace ppu_cb_detail
template<u32 g_count, u32 f_count, u32 v_count, typename T1, typename... T>
FORCE_INLINE static bool _bind_func_args(ppu_thread& CPU, T1 arg1, T... args)
{
const bool is_float = std::is_floating_point<T1>::value;
const bool is_vector = std::is_same<std::decay_t<T1>, v128>::value;
const bool is_context = std::is_same<std::decay_t<T1>, ppu_thread>::value;
const bool is_float = std::is_floating_point_v<T1>;
const bool is_vector = std::is_same_v<std::decay_t<T1>, v128>;
const bool is_context = std::is_same_v<std::decay_t<T1>, ppu_thread>;
const bool is_general = !is_float && !is_vector && !is_context;
const _func_arg_type t =
@@ -140,7 +140,7 @@ namespace ppu_cb_detail
template<typename T>
struct _func_res<T, ARG_VECTOR>
{
static_assert(std::is_same<std::decay_t<T>, v128>::value, "Invalid callback result type for ARG_VECTOR");
static_assert(std::is_same_v<std::decay_t<T>, v128>, "Invalid callback result type for ARG_VECTOR");
FORCE_INLINE static T get_value(const ppu_thread& CPU)
{
@@ -155,10 +155,10 @@ namespace ppu_cb_detail
{
_func_caller<void, T...>::call(CPU, pc, rtoc, args...);
static_assert(!std::is_pointer<RT>::value, "Invalid callback result type (pointer)");
static_assert(!std::is_reference<RT>::value, "Invalid callback result type (reference)");
const bool is_float = std::is_floating_point<RT>::value;
const bool is_vector = std::is_same<std::decay_t<RT>, v128>::value;
static_assert(!std::is_pointer_v<RT>, "Invalid callback result type (pointer)");
static_assert(!std::is_reference_v<RT>, "Invalid callback result type (reference)");
const bool is_float = std::is_floating_point_v<RT>;
const bool is_vector = std::is_same_v<std::decay_t<RT>, v128>;
const _func_arg_type t = is_float ? ARG_FLOAT : (is_vector ? ARG_VECTOR : ARG_GENERAL);
return _func_res<RT, t>::get_value(CPU);
+2 -2
View File
@@ -1488,7 +1488,7 @@ void PPUDisAsm::BCLR(ppu_opcode_t op)
return;
}
DisAsm_CR_BRANCH(final, bi / 4, bh);
DisAsm_CR_BRANCH_HINT(final, bi / 4, bh);
}
void PPUDisAsm::CRNOR(ppu_opcode_t op)
@@ -1586,7 +1586,7 @@ void PPUDisAsm::BCCTR(ppu_opcode_t op)
final += lk ? "ctrl"sv : "ctr"sv;
if (sign) final += sign;
DisAsm_CR_BRANCH(final, bi / 4, bh);
DisAsm_CR_BRANCH_HINT(final, bi / 4, bh);
}
void PPUDisAsm::RLWIMI(ppu_opcode_t op)
+14 -14
View File
@@ -47,8 +47,8 @@ namespace ppu_func_detail
struct bind_arg
{
static_assert(type == ARG_GENERAL, "Unknown function argument type");
static_assert(!std::is_pointer<T>::value, "Invalid function argument type (pointer)");
static_assert(!std::is_reference<T>::value, "Invalid function argument type (reference)");
static_assert(!std::is_pointer_v<T>, "Invalid function argument type (pointer)");
static_assert(!std::is_reference_v<T>, "Invalid function argument type (reference)");
static_assert(sizeof(T) <= 8, "Invalid function argument type for ARG_GENERAL");
static inline T get_arg(ppu_thread& ppu)
@@ -71,7 +71,7 @@ namespace ppu_func_detail
template<typename T, u32 g_count, u32 f_count, u32 v_count>
struct bind_arg<T, ARG_VECTOR, g_count, f_count, v_count>
{
static_assert(std::is_same<std::decay_t<T>, v128>::value, "Invalid function argument type for ARG_VECTOR");
static_assert(std::is_same_v<std::decay_t<T>, v128>, "Invalid function argument type for ARG_VECTOR");
static FORCE_INLINE T get_arg(ppu_thread& ppu)
{
@@ -93,7 +93,7 @@ namespace ppu_func_detail
template<typename T, u32 g_count, u32 f_count, u32 v_count>
struct bind_arg<T, ARG_CONTEXT, g_count, f_count, v_count>
{
static_assert(std::is_base_of<std::decay_t<T>, ppu_thread>::value, "Invalid function argument type for ARG_CONTEXT");
static_assert(std::is_base_of_v<std::decay_t<T>, ppu_thread>, "Invalid function argument type for ARG_CONTEXT");
static FORCE_INLINE T& get_arg(ppu_thread& ppu)
{
@@ -104,7 +104,7 @@ namespace ppu_func_detail
template<typename T, u32 g_count, u32 f_count, u32 v_count>
struct bind_arg<T, ARG_VARIADIC, g_count, f_count, v_count>
{
static_assert(std::is_same<std::decay_t<T>, ppu_va_args_t>::value, "Invalid function argument type for ARG_VARIADIC");
static_assert(std::is_same_v<std::decay_t<T>, ppu_va_args_t>, "Invalid function argument type for ARG_VARIADIC");
static FORCE_INLINE ppu_va_args_t get_arg(ppu_thread&)
{
@@ -140,7 +140,7 @@ namespace ppu_func_detail
template<typename T>
struct bind_result<T, ARG_VECTOR>
{
static_assert(std::is_same<std::decay_t<T>, v128>::value, "Invalid function result type for ARG_VECTOR");
static_assert(std::is_same_v<std::decay_t<T>, v128>, "Invalid function result type for ARG_VECTOR");
static FORCE_INLINE void put_result(ppu_thread& ppu, const T& result)
{
@@ -192,10 +192,10 @@ namespace ppu_func_detail
const u32 v_count = (info.last_value >> 24);
// TODO: check calculations
const bool is_float = std::is_floating_point<T>::value;
const bool is_vector = std::is_same<std::decay_t<T>, v128>::value;
const bool is_context = std::is_base_of<std::decay_t<T>, ppu_thread>::value;
const bool is_variadic = std::is_same<std::decay_t<T>, ppu_va_args_t>::value;
const bool is_float = std::is_floating_point_v<T>;
const bool is_vector = std::is_same_v<std::decay_t<T>, v128>;
const bool is_context = std::is_base_of_v<std::decay_t<T>, ppu_thread>;
const bool is_variadic = std::is_same_v<std::decay_t<T>, ppu_va_args_t>;
const bool is_general = !is_float && !is_vector && !is_context && !is_variadic;
const arg_class t =
@@ -216,10 +216,10 @@ namespace ppu_func_detail
template<typename RT>
struct result_type
{
static_assert(!std::is_pointer<RT>::value, "Invalid function result type (pointer)");
static_assert(!std::is_reference<RT>::value, "Invalid function result type (reference)");
static const bool is_float = std::is_floating_point<RT>::value;
static const bool is_vector = std::is_same<std::decay_t<RT>, v128>::value;
static_assert(!std::is_pointer_v<RT>, "Invalid function result type (pointer)");
static_assert(!std::is_reference_v<RT>, "Invalid function result type (reference)");
static const bool is_float = std::is_floating_point_v<RT>;
static const bool is_vector = std::is_same_v<std::decay_t<RT>, v128>;
static const arg_class value = is_float ? ARG_FLOAT : (is_vector ? ARG_VECTOR : ARG_GENERAL);
};
+2 -2
View File
@@ -1646,7 +1646,7 @@ std::shared_ptr<lv2_prx> ppu_load_prx(const ppu_prx_object& elf, bool virtual_lo
if (ar)
{
break;
continue;
}
switch (rtype)
@@ -2862,7 +2862,7 @@ std::pair<std::shared_ptr<lv2_overlay>, CellError> ppu_load_overlay(const ppu_ex
}
// Apply the patch
auto applied = g_fxo->get<patch_engine>().apply(!Emu.DeserialManager() ? std::string{} : hash, [ovlm](u32 addr, u32 size) { return ovlm->get_ptr<u8>(addr, size); });
auto applied = g_fxo->get<patch_engine>().apply(!Emu.DeserialManager() ? hash : std::string{}, [ovlm](u32 addr, u32 size) { return ovlm->get_ptr<u8>(addr, size); });
if (!Emu.DeserialManager() && !Emu.GetTitleID().empty())
{
+4 -4
View File
@@ -147,7 +147,7 @@ public:
{
using gvar = std::decay_t<decltype(*Var)>;
static_assert(std::is_same<u32, typename gvar::addr_type>::value, "Static variable registration: vm::gvar<T> expected");
static_assert(std::is_same_v<u32, typename gvar::addr_type>, "Static variable registration: vm::gvar<T> expected");
auto& info = access_static_variable(_module, vnid);
@@ -289,9 +289,9 @@ inline RT ppu_execute(ppu_thread& ppu, Args... args)
return func(ppu, args...);
}
#define BIND_FUNC_WITH_BLR(func) BIND_FUNC(func, if (cpu_flag::again - ppu.state) ppu.cia = static_cast<u32>(ppu.lr) & ~3)
#define BIND_FUNC_WITH_BLR(func, _module) BIND_FUNC(func, if (cpu_flag::again - ppu.state) ppu.cia = static_cast<u32>(ppu.lr) & ~3; else ppu.current_module = _module)
#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))
#define REG_FNID(_module, nid, func) ppu_module_manager::register_static_function<&func>(#_module, ppu_select_name(#func, nid), BIND_FUNC_WITH_BLR(func, #_module), ppu_generate_id(nid))
#define REG_FUNC(_module, func) REG_FNID(_module, #func, func)
@@ -299,7 +299,7 @@ inline RT ppu_execute(ppu_thread& ppu, Args... args)
#define REG_VAR(_module, var) REG_VNID(_module, #var, var)
#define REG_HIDDEN_FUNC(func) ppu_function_manager::register_function<decltype(&func), &func>(BIND_FUNC_WITH_BLR(func))
#define REG_HIDDEN_FUNC(func) ppu_function_manager::register_function<decltype(&func), &func>(BIND_FUNC_WITH_BLR(func, ""))
#define REG_HIDDEN_FUNC_PURE(func) ppu_function_manager::register_function<decltype(&func), &func>(func)
+387 -163
View File
@@ -32,25 +32,26 @@
#pragma warning(push, 0)
#else
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wall"
#pragma GCC diagnostic ignored "-Wextra"
#pragma GCC diagnostic ignored "-Wold-style-cast"
#pragma GCC diagnostic ignored "-Wunused-parameter"
#pragma GCC diagnostic ignored "-Wstrict-aliasing"
#pragma GCC diagnostic ignored "-Weffc++"
#pragma GCC diagnostic ignored "-Wmissing-noreturn"
#pragma GCC diagnostic ignored "-Wstrict-aliasing"
#endif
#include "llvm/Support/FormattedStream.h"
#include "llvm/TargetParser/Host.h"
#include "llvm/Object/ObjectFile.h"
#include <llvm/IR/Verifier.h>
#include <llvm/Transforms/Utils/BasicBlockUtils.h>
#if LLVM_VERSION_MAJOR < 17
#include "llvm/ADT/Triple.h"
#include <llvm/Support/FormattedStream.h>
#include <llvm/TargetParser/Host.h>
#include <llvm/Object/ObjectFile.h>
#include <llvm/IR/InstIterator.h>
#include <llvm/IR/LegacyPassManager.h>
#include <llvm/Transforms/Scalar.h>
#else
#include <llvm/Analysis/CGSCCPassManager.h>
#include <llvm/Analysis/LoopAnalysisManager.h>
#include <llvm/Passes/PassBuilder.h>
#include <llvm/Transforms/Scalar/EarlyCSE.h>
#endif
#include "llvm/IR/Verifier.h"
#include "llvm/IR/InstIterator.h"
#include "llvm/IR/LegacyPassManager.h"
#include "llvm/Transforms/Utils/BasicBlockUtils.h"
#include "llvm/Transforms/Scalar.h"
#ifdef _MSC_VER
#pragma warning(pop)
#else
@@ -60,7 +61,6 @@
#include "PPUTranslator.h"
#endif
#include <thread>
#include <cfenv>
#include <cctype>
#include <span>
@@ -173,9 +173,9 @@ bool serialize<ppu_thread::cr_bits>(utils::serial& ar, typename ppu_thread::cr_b
}
extern void ppu_initialize();
extern void ppu_finalize(const ppu_module& info);
extern void ppu_finalize(const ppu_module& info, bool force_mem_release = false);
extern bool ppu_initialize(const ppu_module& info, bool check_only = false, u64 file_size = 0);
static void ppu_initialize2(class jit_compiler& jit, const ppu_module& module_part, const std::string& cache_path, const std::string& obj_name);
static void ppu_initialize2(class jit_compiler& jit, const ppu_module& module_part, const std::string& cache_path, const std::string& obj_name, const ppu_module& whole_module);
extern bool ppu_load_exec(const ppu_exec_object&, bool virtual_load, const std::string&, utils::serial* = nullptr);
extern std::pair<std::shared_ptr<lv2_overlay>, CellError> ppu_load_overlay(const ppu_exec_object&, bool virtual_load, const std::string& path, s64 file_offset, utils::serial* = nullptr);
extern void ppu_unload_prx(const lv2_prx&);
@@ -413,14 +413,14 @@ const auto ppu_recompiler_fallback_ghc = &ppu_recompiler_fallback;
#endif
// Get pointer to executable cache
static ppu_intrp_func_t* ppu_ptr(u32 addr)
static inline u8* ppu_ptr(u32 addr)
{
return reinterpret_cast<ppu_intrp_func_t*>(vm::g_exec_addr + u64{addr} * 2);
return vm::g_exec_addr + u64{addr} * 2;
}
static ppu_intrp_func_t& ppu_ref(u32 addr)
static inline ppu_intrp_func_t ppu_read(u32 addr)
{
return *ppu_ptr(addr);
return read_from_ptr<ppu_intrp_func_t>(ppu_ptr(addr));
}
// Get interpreter cache value
@@ -445,7 +445,7 @@ static void ppu_fallback(ppu_thread& ppu, ppu_opcode_t op, be_t<u32>* this_op, p
{
const auto _pc = vm::get_addr(this_op);
const auto _fn = ppu_cache(_pc);
ppu_ref(_pc) = _fn;
write_to_ptr<ppu_intrp_func_t>(ppu_ptr(_pc), _fn);
return _fn(ppu, op, this_op, next_fn);
}
@@ -463,7 +463,7 @@ void ppu_recompiler_fallback(ppu_thread& ppu)
while (true)
{
if (uptr func = uptr(ppu_ref(ppu.cia)); (func << 16 >> 16) != reinterpret_cast<uptr>(ppu_recompiler_fallback_ghc))
if (uptr func = uptr(ppu_read(ppu.cia)); (func << 16 >> 16) != reinterpret_cast<uptr>(ppu_recompiler_fallback_ghc))
{
// We found a recompiler function at cia, return
break;
@@ -730,11 +730,12 @@ extern void ppu_register_range(u32 addr, u32 size)
if (g_cfg.core.ppu_decoder == ppu_decoder_type::llvm)
{
// Assume addr is the start of first segment of PRX
ppu_ref(addr) = reinterpret_cast<ppu_intrp_func_t>(reinterpret_cast<uptr>(ppu_recompiler_fallback_ghc) | (seg_base << (32 + 3)));
const uptr entry_value = reinterpret_cast<uptr>(ppu_recompiler_fallback_ghc) | (seg_base << (32 + 3));
write_to_ptr<uptr>(ppu_ptr(addr), entry_value);
}
else
{
ppu_ref(addr) = ppu_fallback;
write_to_ptr<ppu_intrp_func_t>(ppu_ptr(addr), ppu_fallback);
}
addr += 4;
@@ -749,7 +750,7 @@ extern void ppu_register_function_at(u32 addr, u32 size, ppu_intrp_func_t ptr =
// Initialize specific function
if (ptr)
{
ppu_ref(addr) = reinterpret_cast<ppu_intrp_func_t>((reinterpret_cast<uptr>(ptr) & 0xffff'ffff'ffffu) | (uptr(ppu_ref(addr)) & ~0xffff'ffff'ffffu));
write_to_ptr<uptr>(ppu_ptr(addr), (reinterpret_cast<uptr>(ptr) & 0xffff'ffff'ffffu) | (uptr(ppu_read(addr)) & ~0xffff'ffff'ffffu));
return;
}
@@ -771,9 +772,9 @@ extern void ppu_register_function_at(u32 addr, u32 size, ppu_intrp_func_t ptr =
// Initialize interpreter cache
while (size)
{
if (ppu_ref(addr) != ppu_break && ppu_ref(addr) != ppu_far_jump)
if (auto old = ppu_read(addr); old != ppu_break && old != ppu_far_jump)
{
ppu_ref(addr) = ppu_cache(addr);
write_to_ptr<ppu_intrp_func_t>(ppu_ptr(addr), ppu_cache(addr));
}
addr += 4;
@@ -1132,8 +1133,8 @@ extern bool ppu_breakpoint(u32 addr, bool is_adding)
}
// Remove breakpoint parameters
ppu_intrp_func_t to_set = 0;
ppu_intrp_func_t expected = &ppu_break;
ppu_intrp_func_t func_original = 0;
ppu_intrp_func_t breakpoint = &ppu_break;
if (u32 hle_addr{}; g_fxo->is_init<ppu_function_manager>() && (hle_addr = g_fxo->get<ppu_function_manager>().addr))
{
@@ -1143,31 +1144,40 @@ extern bool ppu_breakpoint(u32 addr, bool is_adding)
if (addr % 8 == 4 && index < ppu_function_manager::get().size())
{
// HLE function placement
to_set = ppu_function_manager::get()[index];
func_original = ppu_function_manager::get()[index];
}
}
if (!to_set)
if (!func_original)
{
// If not an HLE function use regular instruction function
to_set = ppu_cache(addr);
func_original = ppu_cache(addr);
}
ppu_intrp_func_t& _ref = ppu_ref(addr);
if (is_adding)
{
// Swap if adding
std::swap(to_set, expected);
if (_ref == &ppu_fallback)
if (ppu_read(addr) == ppu_fallback)
{
ppu_log.error("Unregistered instruction replaced with a breakpoint at 0x%08x", addr);
expected = ppu_fallback;
func_original = ppu_fallback;
}
if (ppu_read(addr) != func_original)
{
return false;
}
write_to_ptr<ppu_intrp_func_t>(ppu_ptr(addr), breakpoint);
return true;
}
return atomic_storage<ppu_intrp_func_t>::compare_exchange(_ref, expected, to_set);
if (ppu_read(addr) != breakpoint)
{
return false;
}
write_to_ptr<ppu_intrp_func_t>(ppu_ptr(addr), func_original);
return true;
}
extern bool ppu_patch(u32 addr, u32 value)
@@ -1199,9 +1209,9 @@ extern bool ppu_patch(u32 addr, u32 value)
if (is_exec)
{
if (ppu_ref(addr) != ppu_break && ppu_ref(addr) != ppu_fallback)
if (auto old = ppu_read(addr); old != ppu_break && old != ppu_fallback)
{
ppu_ref(addr) = ppu_cache(addr);
write_to_ptr<ppu_intrp_func_t>(ppu_ptr(addr), ppu_cache(addr));
}
}
@@ -2215,7 +2225,7 @@ void ppu_thread::cpu_sleep()
void ppu_thread::cpu_on_stop()
{
if (current_function)
if (current_function && is_stopped())
{
if (start_time)
{
@@ -2225,10 +2235,10 @@ void ppu_thread::cpu_on_stop()
{
ppu_log.warning("'%s' aborted", current_function);
}
current_function = {};
}
current_function = {};
// TODO: More conditions
if (Emu.IsStopped() && g_cfg.core.ppu_debug)
{
@@ -2357,7 +2367,7 @@ void ppu_thread::serialize_common(utils::serial& ar)
ar(gpr, fpr, cr, fpscr.bits, lr, ctr, vrsave, cia, xer, sat, nj, prio.raw().all);
if (cia % 4 || !vm::check_addr(cia))
if (cia % 4 || (cia >> 28) >= 0xCu)
{
fmt::throw_exception("Failed to serialize PPU thread ID=0x%x (cia=0x%x, ar=%s)", this->id, cia, ar);
}
@@ -2380,6 +2390,12 @@ void ppu_thread::serialize_common(utils::serial& ar)
}
}
struct save_lv2_tag
{
atomic_t<bool> saved = false;
atomic_t<bool> loaded = false;
};
ppu_thread::ppu_thread(utils::serial& ar)
: cpu_thread(idm::last_id()) // last_id() is showed to constructor on serialization
, stack_size(ar)
@@ -2388,6 +2404,8 @@ ppu_thread::ppu_thread(utils::serial& ar)
, entry_func(std::bit_cast<ppu_func_opd_t, u64>(ar))
, is_interrupt_thread(ar)
{
[[maybe_unused]] const s32 version = GET_SERIALIZATION_VERSION(ppu);
struct init_pushed
{
bool pushed = false;
@@ -2398,6 +2416,19 @@ ppu_thread::ppu_thread(utils::serial& ar)
syscall_history.data.resize(g_cfg.core.ppu_call_history ? syscall_history_max_size : 1);
syscall_history.count_debug_arguments = static_cast<u32>(g_cfg.core.ppu_call_history ? std::size(syscall_history.data[0].args) : 0);
if (version >= 2 && !g_fxo->get<save_lv2_tag>().loaded.exchange(true))
{
ar(lv2_obj::g_priority_order_tag);
}
if (version >= 3)
{
// Function and module for HLE function relocation
// TODO: Use it
ar.pop<std::string>();
ar.pop<std::string>();
}
serialize_common(ar);
// Restore jm_mask
@@ -2427,7 +2458,41 @@ ppu_thread::ppu_thread(utils::serial& ar)
case PPU_THREAD_STATUS_RUNNABLE:
case PPU_THREAD_STATUS_ONPROC:
{
lv2_obj::awake(this);
if (version >= 2)
{
const u32 order = ar.pop<u32>();
struct awake_pushed
{
bool pushed = false;
shared_mutex dummy;
std::map<u32, ppu_thread*> awake_ppus;
};
g_fxo->get<awake_pushed>().awake_ppus[order] = this;
if (!std::exchange(g_fxo->get<awake_pushed>().pushed, true))
{
Emu.PostponeInitCode([this]()
{
u32 prev = umax;
for (auto ppu : g_fxo->get<awake_pushed>().awake_ppus)
{
ensure(prev + 1 == ppu.first);
prev = ppu.first;
lv2_obj::awake(ppu.second);
}
g_fxo->get<awake_pushed>().awake_ppus.clear();
});
}
}
else
{
lv2_obj::awake(this);
}
[[fallthrough]];
}
case PPU_THREAD_STATUS_SLEEP:
@@ -2475,7 +2540,9 @@ ppu_thread::ppu_thread(utils::serial& ar)
const u32 op = vm::read32(ppu.cia);
const auto& table = g_fxo->get<ppu_interpreter_rt>();
ppu.loaded_from_savestate = true;
ppu.prio.raw().preserve_bit = 1;
table.decode(op)(ppu, {op}, vm::_ptr<u32>(ppu.cia), &ppu_ret);
ppu.prio.raw().preserve_bit = 0;
ppu.optional_savestate_state->clear(); // Reset to writing state
ppu.loaded_from_savestate = false;
@@ -2529,9 +2596,28 @@ void ppu_thread::save(utils::serial& ar)
}
ar(stack_size, stack_addr, _joiner, entry, is_interrupt_thread);
const bool is_null = ar.m_file_handler && ar.m_file_handler->is_null();
if (!is_null && !g_fxo->get<save_lv2_tag>().saved.exchange(true))
{
ar(lv2_obj::g_priority_order_tag);
}
if (current_module && current_module[0])
{
ar(std::string{current_module});
ar(std::string{last_function});
}
else
{
ar(std::string{});
ar(std::string{});
}
serialize_common(ar);
ppu_thread_status status = lv2_obj::ppu_state(this, false);
auto [status, order] = lv2_obj::ppu_state(this, false);
if (status == PPU_THREAD_STATUS_SLEEP && cpu_flag::again - state)
{
@@ -2541,6 +2627,11 @@ void ppu_thread::save(utils::serial& ar)
ar(status);
if (status == PPU_THREAD_STATUS_RUNNABLE || status == PPU_THREAD_STATUS_ONPROC)
{
ar(order);
}
ar(*ppu_tname.load());
}
@@ -3305,25 +3396,30 @@ static bool ppu_store_reservation(ppu_thread& ppu, u32 addr, u64 reg_value)
//auto& cline_data = vm::_ref<spu_rdata_t>(addr);
data += 0;
rsx::reservation_lock rsx_lock(addr, 128);
auto& super_data = *vm::get_super_ptr<spu_rdata_t>(addr);
const bool success = [&]()
auto range_lock = vm::alloc_range_lock();
bool success = false;
{
// Full lock (heavyweight)
// TODO: vm::check_addr
vm::writer_lock lock(addr);
rsx::reservation_lock rsx_lock(addr, 128);
if (cmp_rdata(ppu.rdata, super_data))
auto& super_data = *vm::get_super_ptr<spu_rdata_t>(addr);
success = [&]()
{
data.release(new_data);
res += 64;
return true;
}
// Full lock (heavyweight)
// TODO: vm::check_addr
vm::writer_lock lock(addr, range_lock);
res -= 64;
return false;
}();
if (cmp_rdata(ppu.rdata, super_data))
{
data.release(new_data);
res += 64;
return true;
}
res -= 64;
return false;
}();
}
vm::free_range_lock(range_lock);
return success;
}
@@ -3386,17 +3482,17 @@ static bool ppu_store_reservation(ppu_thread& ppu, u32 addr, u64 reg_value)
{
extern atomic_t<u32> liblv2_begin, liblv2_end;
const u32 notify = ppu.res_notify;
if (notify)
{
vm::reservation_notifier(notify).notify_all();
ppu.res_notify = 0;
}
// Avoid notifications from lwmutex or sys_spinlock
if (ppu.cia < liblv2_begin || ppu.cia >= liblv2_end)
if (new_data != old_data && (ppu.cia < liblv2_begin || ppu.cia >= liblv2_end))
{
const u32 notify = ppu.res_notify;
if (notify)
{
vm::reservation_notifier(notify).notify_all();
ppu.res_notify = 0;
}
if (!notify)
{
// Try to postpone notification to when PPU is asleep or join notifications on the same address
@@ -3460,7 +3556,7 @@ namespace
// Compiled PPU module info
struct jit_module
{
std::vector<ppu_intrp_func_t> funcs;
void(*symbol_resolver)(u8*, u64) = nullptr;
std::shared_ptr<jit_compiler> pjit;
bool init = false;
};
@@ -3499,10 +3595,18 @@ namespace
if (found == bucket.map.end()) [[unlikely]]
{
ppu_log.error("Failed to remove module %s", name);
for (auto& buck : buckets)
{
for (auto& mod : buck.map)
{
ppu_log.notice("But there is module %s", mod.first);
}
}
return;
}
to_destroy.funcs = std::move(found->second.funcs);
to_destroy.pjit = std::move(found->second.pjit);
bucket.map.erase(found);
@@ -3612,26 +3716,47 @@ extern fs::file make_file_view(fs::file&& _file, u64 offset, u64 max_size = umax
return file;
}
extern void ppu_finalize(const ppu_module& info)
extern void ppu_finalize(const ppu_module& info, bool force_mem_release)
{
if (info.name.empty())
if (info.segs.empty())
{
// HLEd modules
return;
}
if (!force_mem_release && info.name.empty())
{
// Don't remove main module from memory
return;
}
const std::string dev_flash = vfs::get("/dev_flash/sys/");
if (info.path.starts_with(dev_flash) || Emu.GetCat() == "1P")
if (!force_mem_release && Emu.GetCat() == "1P")
{
return;
}
const bool may_be_elf = fmt::to_lower(info.path.substr(std::max<usz>(info.path.size(), 3) - 3)) != "prx";
const std::string dev_flash = vfs::get("/dev_flash/");
if (!may_be_elf)
{
if (!force_mem_release && info.path.starts_with(dev_flash + "sys/external/"))
{
// Don't remove dev_flash prx from memory
return;
}
}
if (g_cfg.core.ppu_decoder != ppu_decoder_type::llvm)
{
// Don't remove dev_flash prx from memory
return;
}
// Get cache path for this executable
std::string cache_path = fs::get_cache_dir() + "cache/";
if (!Emu.GetTitleID().empty())
if (!info.path.starts_with(dev_flash) && !Emu.GetTitleID().empty() && Emu.GetCat() != "1P")
{
cache_path += Emu.GetTitleID();
cache_path += '/';
@@ -3864,9 +3989,18 @@ extern void ppu_precompile(std::vector<std::string>& dir_queue, std::vector<ppu_
lf_queue<file_info> possible_exec_file_paths;
::semaphore<2> ovl_sema;
// Allow to allocate 2000 times the size of each file for the use of LLVM
// This works very nicely with Metal Gear Solid 4 for example:
// 2 7MB overlay files -> 14GB
// The growth in memory requirements of LLVM is not linear with file size of course
// But these estimates should hopefully protect RPCS3 in the coming years
// Especially when thread count is on the rise with each CPU generation
atomic_t<u32> file_size_limit = static_cast<u32>(std::clamp<u64>(utils::aligned_div<u64>(utils::get_total_memory(), 2000), 65536, u32{umax}));
named_thread_group workers("SPRX Worker ", std::min<u32>(utils::get_thread_count(), ::size32(file_queue)), [&]
const u32 software_thread_limit = std::min<u32>(g_cfg.core.llvm_threads ? g_cfg.core.llvm_threads : u32{umax}, ::size32(file_queue));
const u32 cpu_thread_limit = utils::get_thread_count() > 8u ? std::max<u32>(utils::get_thread_count(), 2) - 1 : utils::get_thread_count(); // One LLVM thread less
named_thread_group workers("SPRX Worker ", std::min<u32>(software_thread_limit, cpu_thread_limit), [&]
{
#ifdef __APPLE__
pthread_jit_write_protect_np(false);
@@ -3874,6 +4008,7 @@ extern void ppu_precompile(std::vector<std::string>& dir_queue, std::vector<ppu_
// Set low priority
thread_ctrl::scoped_priority low_prio(-1);
u32 inc_fdone = 1;
u32 restore_mem = 0;
for (usz func_i = fnext++; func_i < file_queue.size(); func_i = fnext++, g_progr_fdone += std::exchange(inc_fdone, 1))
{
@@ -3882,6 +4017,16 @@ extern void ppu_precompile(std::vector<std::string>& dir_queue, std::vector<ppu_
continue;
}
if (restore_mem)
{
if (!file_size_limit.fetch_add(restore_mem))
{
file_size_limit.notify_all();
}
restore_mem = 0;
}
auto& [path, offset, file_size] = file_queue[func_i];
ppu_log.notice("Trying to load: %s", path);
@@ -3913,15 +4058,53 @@ extern void ppu_precompile(std::vector<std::string>& dir_queue, std::vector<ppu_
continue;
}
auto wait_for_memory = [&]() -> bool
{
// Try not to process too many files at once because it seems to reduce performance and cause RAM shortages
// Concurrently compiling more OVL or huge PRX files does not have much theoretical benefit
while (!file_size_limit.fetch_op([&](u32& value)
{
if (value)
{
// Allow at least one file, make 0 the "memory unavailable" sign value for atomic waiting efficiency
const u32 new_val = static_cast<u32>(utils::sub_saturate<u64>(value, file_size));
restore_mem = value - new_val;
value = new_val;
return true;
}
// Resort to waiting
restore_mem = 0;
return false;
}).second)
{
// Wait until not 0
file_size_limit.wait(0);
}
if (Emu.IsStopped())
{
return false;
}
return true;
};
elf_error prx_err{}, ovl_err{};
if (ppu_prx_object obj = src; (prx_err = obj, obj == elf_error::ok))
{
if (!wait_for_memory())
{
// Emulation stopped
continue;
}
if (auto prx = ppu_load_prx(obj, true, path, offset))
{
obj.clear(), src.close(); // Clear decrypted file and elf object memory
ppu_initialize(*prx, false, file_size);
ppu_finalize(*prx);
ppu_finalize(*prx, true);
continue;
}
@@ -3933,10 +4116,6 @@ extern void ppu_precompile(std::vector<std::string>& dir_queue, std::vector<ppu_
{
while (ovl_err == elf_error::ok)
{
// Try not to process too many files at once because it seems to reduce performance
// Concurrently compiling more OVL files does not have much theoretical benefit
std::lock_guard lock(ovl_sema);
if (Emu.IsStopped())
{
break;
@@ -3957,6 +4136,12 @@ extern void ppu_precompile(std::vector<std::string>& dir_queue, std::vector<ppu_
break;
}
if (!wait_for_memory())
{
// Emulation stopped
break;
}
// Participate in thread execution limitation (takes a long time)
if (std::lock_guard lock(g_fxo->get<jit_core_allocator>().sem); !ovlm->analyse(0, ovlm->entry, ovlm->seg0_code_end, ovlm->applied_patches, []()
{
@@ -3969,7 +4154,7 @@ extern void ppu_precompile(std::vector<std::string>& dir_queue, std::vector<ppu_
obj.clear(), src.close(); // Clear decrypted file and elf object memory
ppu_initialize(*ovlm, false, file_size);
ppu_finalize(*ovlm);
ppu_finalize(*ovlm, true);
break;
}
@@ -3979,10 +4164,18 @@ extern void ppu_precompile(std::vector<std::string>& dir_queue, std::vector<ppu_
}
}
ppu_log.notice("Failed to precompile '%s' (prx: %s, ovl: %s): Attempting tratment as executable file", path, prx_err, ovl_err);
ppu_log.notice("Failed to precompile '%s' (prx: %s, ovl: %s): Attempting compilation as executable file", path, prx_err, ovl_err);
possible_exec_file_paths.push(path, offset, file_size);
inc_fdone = 0;
}
if (restore_mem)
{
if (!file_size_limit.fetch_add(restore_mem))
{
file_size_limit.notify_all();
}
}
});
// Join every thread
@@ -4070,7 +4263,7 @@ extern void ppu_precompile(std::vector<std::string>& dir_queue, std::vector<ppu_
Emu.ConfigurePPUCache(!Emu.IsPathInsideDir(_main.path, g_cfg_vfs.get_dev_flash()));
ppu_initialize(_main, false, file_size);
spu_cache::initialize(false);
ppu_finalize(_main);
ppu_finalize(_main, true);
_main = {};
g_fxo->get<spu_cache>() = std::move(current_cache);
break;
@@ -4194,7 +4387,7 @@ extern void ppu_initialize()
}
}
const std::string firmware_sprx_path = vfs::get(dev_flash_located ? "/dev_flash/"sv : "/dev_flash/sys/"sv);
const std::string firmware_sprx_path = vfs::get(dev_flash_located ? "/dev_flash/"sv : "/dev_flash/sys/external/"sv);
dir_queue.emplace_back(firmware_sprx_path);
}
@@ -4250,8 +4443,18 @@ bool ppu_initialize(const ppu_module& info, bool check_only, u64 file_size)
for (const auto& func : info.funcs)
{
if (func.size && func.blocks.empty())
{
ppu_register_function_at(func.addr, func.size);
}
for (auto& block : func.blocks)
{
if (!block.second)
{
continue;
}
if (g_fxo->is_init<ppu_far_jumps_t>() && !g_fxo->get<ppu_far_jumps_t>().get_targets(block.first, block.second).empty())
{
// Replace the block with ppu_far_jump
@@ -4264,7 +4467,7 @@ bool ppu_initialize(const ppu_module& info, bool check_only, u64 file_size)
if (g_cfg.core.ppu_debug && func.size && func.toc != umax && !ppu_get_far_jump(func.addr))
{
ppu_toc[func.addr] = func.toc;
ppu_ref(func.addr) = &ppu_check_toc;
write_to_ptr<ppu_intrp_func_t>(ppu_ptr(func.addr), &ppu_check_toc);
}
}
@@ -4611,6 +4814,7 @@ bool ppu_initialize(const ppu_module& info, bool check_only, u64 file_size)
accurate_fpcc,
accurate_vnan,
accurate_nj_mode,
contains_symbol_resolver,
__bitset_enum_max
};
@@ -4640,6 +4844,8 @@ bool ppu_initialize(const ppu_module& info, bool check_only, u64 file_size)
settings += ppu_settings::accurate_vnan, settings -= ppu_settings::fixup_vnan, fmt::throw_exception("VNAN Not implemented");
if (g_cfg.core.ppu_use_nj_bit)
settings += ppu_settings::accurate_nj_mode, settings -= ppu_settings::fixup_nj_denormals, fmt::throw_exception("NJ Not implemented");
if (fpos >= info.funcs.size())
settings += ppu_settings::contains_symbol_resolver; // Avoid invalidating all modules for this purpose
// Write version, hash, CPU, settings
fmt::append(obj_name, "v6-kusa-%s-%s-%s.obj", fmt::base57(output, 16), fmt::base57(settings), jit_compiler::cpu(g_cfg.core.llvm_cpu));
@@ -4724,16 +4930,18 @@ bool ppu_initialize(const ppu_module& info, bool check_only, u64 file_size)
{
atomic_t<u32>& work_cv;
std::vector<std::pair<std::string, ppu_module>>& workload;
const ppu_module& main_module;
const std::string& cache_path;
const cpu_thread* cpu;
std::unique_lock<decltype(jit_core_allocator::sem)> core_lock;
thread_op(atomic_t<u32>& work_cv, std::vector<std::pair<std::string, ppu_module>>& workload
, const cpu_thread* cpu, const std::string& cache_path, decltype(jit_core_allocator::sem)& sem) noexcept
, const cpu_thread* cpu, const ppu_module& main_module, const std::string& cache_path, decltype(jit_core_allocator::sem)& sem) noexcept
: work_cv(work_cv)
, workload(workload)
, main_module(main_module)
, cache_path(cache_path)
, cpu(cpu)
{
@@ -4744,6 +4952,7 @@ bool ppu_initialize(const ppu_module& info, bool check_only, u64 file_size)
thread_op(const thread_op& other) noexcept
: work_cv(other.work_cv)
, workload(other.workload)
, main_module(other.main_module)
, cache_path(other.cache_path)
, cpu(other.cpu)
{
@@ -4778,7 +4987,7 @@ bool ppu_initialize(const ppu_module& info, bool check_only, u64 file_size)
// Use another JIT instance
jit_compiler jit2({}, g_cfg.core.llvm_cpu, 0x1);
ppu_initialize2(jit2, part, cache_path, obj_name);
ppu_initialize2(jit2, part, cache_path, obj_name, i == workload.size() - 1 ? main_module : part);
ppu_log.success("LLVM: Compiled module %s", obj_name);
}
@@ -4791,7 +5000,7 @@ bool ppu_initialize(const ppu_module& info, bool check_only, u64 file_size)
g_watchdog_hold_ctr++;
named_thread_group threads(fmt::format("PPUW.%u.", ++g_fxo->get<thread_index_allocator>().index), thread_count
, thread_op(work_cv, workload, cpu, cache_path, g_fxo->get<jit_core_allocator>().sem)
, thread_op(work_cv, workload, cpu, info, cache_path, g_fxo->get<jit_core_allocator>().sem)
, [&](u32 /*thread_index*/, thread_op& op)
{
// Allocate "core"
@@ -4835,8 +5044,6 @@ bool ppu_initialize(const ppu_module& info, bool check_only, u64 file_size)
}
}
progr.reset();
if (!is_being_used_in_emulation || (cpu ? cpu->state.all_of(cpu_flag::exit) : Emu.IsStopped()))
{
return compiled_new;
@@ -4849,85 +5056,46 @@ bool ppu_initialize(const ppu_module& info, bool check_only, u64 file_size)
// Try to patch all single and unregistered BLRs with the same function (TODO: Maybe generalize it into PIC code detection and patching)
ppu_intrp_func_t BLR_func = nullptr;
const bool is_first = jit && !jit_mod.init;
const bool showing_only_apply_stage = !g_progr.load() && !g_progr_ptotal && !g_progr_ftotal && g_progr_ptotal.compare_and_swap_test(0, 1);
progr = "Applying PPU Code...";
if (!jit)
{
// No functions - nothing to do
ensure(info.funcs.empty());
return compiled_new;
}
const bool is_first = !jit_mod.init;
if (is_first)
{
jit->fin();
}
u32 index = 0;
u32 max_count = 0;
for (const auto& func : info.funcs)
if (is_first)
{
if (func.size)
{
max_count++;
}
jit_mod.symbol_resolver = reinterpret_cast<void(*)(u8*, u64)>(jit->get("__resolve_symbols"));
}
else
{
ensure(jit_mod.symbol_resolver);
}
u32 pending_progress = umax;
jit_mod.symbol_resolver(vm::g_exec_addr, info.segs[0].addr);
bool early_exit = false;
// Get and install function addresses
// Find a BLR-only function in order to copy it to all BLRs (some games need it)
for (const auto& func : info.funcs)
{
if (!func.size)
if (func.size == 4 && *info.get_ptr<u32>(func.addr) == ppu_instructions::BLR())
{
continue;
}
if (cpu ? cpu->state.all_of(cpu_flag::exit) : Emu.IsStopped())
{
// Revert partially commited changes
jit_mod.funcs.clear();
BLR_func = nullptr;
early_exit = true;
BLR_func = ppu_read(func.addr);
break;
}
const auto name = fmt::format("__0x%x", func.addr - reloc);
// Try to locate existing function if it is not the first time
const auto addr = is_first ? ensure(reinterpret_cast<ppu_intrp_func_t>(jit->get(name)))
: reinterpret_cast<ppu_intrp_func_t>(ensure(jit_mod.funcs[index]));
jit_mod.funcs.emplace_back(addr);
if (func.size == 4 && !BLR_func && *info.get_ptr<u32>(func.addr) == ppu_instructions::BLR())
{
BLR_func = addr;
}
ppu_register_function_at(func.addr, 4, addr);
if (g_cfg.core.ppu_debug)
ppu_log.trace("Installing function %s at 0x%x: %p (reloc = 0x%x)", name, func.addr, ppu_ref(func.addr), reloc);
index++;
if (pending_progress != umax)
{
pending_progress++;
if (pending_progress == 1024)
{
pending_progress = 0;
g_progr_pdone++;
}
}
else if (!g_progr.load() && !g_progr_ptotal && !g_progr_ftotal)
{
g_progr_pdone += index / 1024;
g_progr_ptotal += max_count / 1024;
pending_progress = index % 1024;
progr.emplace("Applying PPU Code...");
}
}
if (is_first && !early_exit)
if (is_first)
{
jit_mod.init = true;
}
@@ -4938,20 +5106,26 @@ bool ppu_initialize(const ppu_module& info, bool check_only, u64 file_size)
for (u32 addr = info.segs[0].addr; addr < info.segs[0].addr + info.segs[0].size; addr += 4, inst_ptr++)
{
if (*inst_ptr == ppu_instructions::BLR() && (reinterpret_cast<uptr>(ppu_ref(addr)) << 16 >> 16) == reinterpret_cast<uptr>(ppu_recompiler_fallback_ghc))
if (*inst_ptr == ppu_instructions::BLR() && (reinterpret_cast<uptr>(ppu_read(addr)) << 16 >> 16) == reinterpret_cast<uptr>(ppu_recompiler_fallback_ghc))
{
ppu_register_function_at(addr, 4, BLR_func);
write_to_ptr<ppu_intrp_func_t>(ppu_ptr(addr), BLR_func);
}
}
}
if (showing_only_apply_stage)
{
// Done
g_progr_pdone++;
}
return compiled_new;
#else
fmt::throw_exception("LLVM is not available in this build.");
#endif
}
static void ppu_initialize2(jit_compiler& jit, const ppu_module& module_part, const std::string& cache_path, const std::string& obj_name)
static void ppu_initialize2(jit_compiler& jit, const ppu_module& module_part, const std::string& cache_path, const std::string& obj_name, const ppu_module& whole_module)
{
#ifdef LLVM_AVAILABLE
using namespace llvm;
@@ -4995,6 +5169,7 @@ static void ppu_initialize2(jit_compiler& jit, const ppu_module& module_part, co
translator.build_interpreter();
}
#if LLVM_VERSION_MAJOR < 17
legacy::FunctionPassManager pm(_module.get());
// Basic optimizations
@@ -5016,6 +5191,32 @@ static void ppu_initialize2(jit_compiler& jit, const ppu_module& module_part, co
//pm.add(createAggressiveDCEPass());
//pm.add(createCFGSimplificationPass());
//pm.add(createLintPass()); // Check
#else
// Create the analysis managers.
// These must be declared in this order so that they are destroyed in the
// correct order due to inter-analysis-manager references.
LoopAnalysisManager lam;
FunctionAnalysisManager fam;
CGSCCAnalysisManager cgam;
ModuleAnalysisManager mam;
// Create the new pass manager builder.
// Take a look at the PassBuilder constructor parameters for more
// customization, e.g. specifying a TargetMachine or various debugging
// options.
PassBuilder pb;
// Register all the basic analyses with the managers.
pb.registerModuleAnalyses(mam);
pb.registerCGSCCAnalyses(cgam);
pb.registerFunctionAnalyses(fam);
pb.registerLoopAnalyses(lam);
pb.crossRegisterProxies(lam, fam, cgam, mam);
FunctionPassManager fpm;
// Basic optimizations
fpm.addPass(EarlyCSEPass());
#endif
// Translate functions
for (usz fi = 0, fmax = module_part.funcs.size(); fi < fmax; fi++)
@@ -5032,7 +5233,11 @@ static void ppu_initialize2(jit_compiler& jit, const ppu_module& module_part, co
if (const auto func = translator.Translate(module_part.funcs[fi]))
{
// Run optimization passes
#if LLVM_VERSION_MAJOR < 17
pm.run(*func);
#else
fpm.run(*func, fam);
#endif
}
else
{
@@ -5042,6 +5247,25 @@ static void ppu_initialize2(jit_compiler& jit, const ppu_module& module_part, co
}
}
// Run this only in one module for all functions
if (&whole_module != &module_part)
{
if (const auto func = translator.GetSymbolResolver(whole_module))
{
// Run optimization passes
#if LLVM_VERSION_MAJOR < 17
pm.run(*func);
#else
fpm.run(*func, fam);
#endif
}
else
{
Emu.Pause();
return;
}
}
//legacy::PassManager mpm;
// Remove unused functions, structs, global variables, etc
+5 -3
View File
@@ -268,7 +268,8 @@ public:
{
u64 all;
bf_t<s64, 0, 13> prio; // Thread priority (0..3071) (firs 12-bits)
bf_t<s64, 13, 51> order; // Thread enqueue order (last 52-bits)
bf_t<s64, 13, 50> order; // Thread enqueue order (last 52-bits)
bf_t<u64, 63, 1> preserve_bit; // Preserve value for savestates
};
atomic_t<ppu_prio_t> prio{};
@@ -294,6 +295,7 @@ public:
u64 syscall_args[8]{0}; // Last syscall arguments stored
const char* current_function{}; // Current function name for diagnosis, optimized for speed.
const char* last_function{}; // Sticky copy of current_function, is not cleared on function return
const char* current_module{}; // Current module name, for savestates.
const bool is_interrupt_thread; // True for interrupts-handler threads
@@ -383,10 +385,10 @@ struct ppu_gpr_cast_impl
};
template<typename T>
struct ppu_gpr_cast_impl<T, std::enable_if_t<std::is_integral<T>::value || std::is_enum<T>::value>>
struct ppu_gpr_cast_impl<T, std::enable_if_t<std::is_integral_v<T> || std::is_enum_v<T>>>
{
static_assert(sizeof(T) <= 8, "Too big integral type for ppu_gpr_cast<>()");
static_assert(std::is_same<std::decay_t<T>, bool>::value == false, "bool type is deprecated in ppu_gpr_cast<>(), use b8 instead");
static_assert(std::is_same_v<std::decay_t<T>, bool> == false, "bool type is deprecated in ppu_gpr_cast<>(), use b8 instead");
static inline u64 to(const T& value)
{
+122 -12
View File
@@ -274,6 +274,116 @@ Function* PPUTranslator::Translate(const ppu_function& info)
return m_function;
}
Function* PPUTranslator::GetSymbolResolver(const ppu_module& info)
{
m_function = cast<Function>(m_module->getOrInsertFunction("__resolve_symbols", FunctionType::get(get_type<void>(), { get_type<u8*>(), get_type<u64>() }, false)).getCallee());
IRBuilder<> irb(BasicBlock::Create(m_context, "__entry", m_function));
m_ir = &irb;
// Instruction address is (m_addr + base)
const u64 base = m_reloc ? m_reloc->addr : 0;
m_exec = m_function->getArg(0);
m_seg0 = m_function->getArg(1);
const auto ftype = FunctionType::get(get_type<void>(), {
get_type<u8*>(), // Exec base
GetContextType()->getPointerTo(), // PPU context
get_type<u64>(), // Segment address (for PRX)
get_type<u8*>(), // Memory base
get_type<u64>(), // r0
get_type<u64>(), // r1
get_type<u64>(), // r2
}, false);
// Store function addresses in PPU jumptable using internal resolving instead of patching it externally.
// Because, LLVM processed it extremely slow. (regression)
// This is made in loop instead of inlined because it took tremendous amount of time to compile.
std::vector<u32> vec_addrs;
vec_addrs.reserve(info.funcs.size());
// Create an array of function pointers
std::vector<llvm::Constant*> functions;
for (const auto& f : info.funcs)
{
if (!f.size)
{
continue;
}
vec_addrs.push_back(f.addr - base);
functions.push_back(cast<Function>(m_module->getOrInsertFunction(fmt::format("__0x%x", f.addr - base), ftype).getCallee()));
}
if (vec_addrs.empty())
{
// Possible special case for no functions (allowing the do-while optimization)
m_ir->CreateRetVoid();
replace_intrinsics(*m_function);
return m_function;
}
const auto addr_array_type = ArrayType::get(get_type<u32>(), vec_addrs.size());
const auto addr_array = new GlobalVariable(*m_module, addr_array_type, false, GlobalValue::PrivateLinkage, ConstantDataArray::get(m_context, vec_addrs));
// Create an array of function pointers
const auto func_table_type = ArrayType::get(ftype->getPointerTo(), info.funcs.size());
const auto init_func_table = ConstantArray::get(func_table_type, functions);
const auto func_table = new GlobalVariable(*m_module, func_table_type, false, GlobalVariable::PrivateLinkage, init_func_table);
const auto loop_block = BasicBlock::Create(m_context, "__loop", m_function);
const auto after_loop = BasicBlock::Create(m_context, "__after_loop", m_function);
m_ir->CreateBr(loop_block);
m_ir->SetInsertPoint(loop_block);
const auto init_index_value = m_ir->getInt64(0);
// Loop body
const auto body_block = BasicBlock::Create(m_context, "__body", m_function);
m_ir->CreateBr(body_block); // As do-while because vec_addrs is known to be more than 0
m_ir->SetInsertPoint(body_block);
const auto index_value = m_ir->CreatePHI(get_type<u64>(), 2);
index_value->addIncoming(init_index_value, loop_block);
auto ptr_inst = dyn_cast<GetElementPtrInst>(m_ir->CreateGEP(addr_array->getValueType(), addr_array, {m_ir->getInt64(0), index_value}));
assert(ptr_inst->getResultElementType() == get_type<u32>());
const auto func_pc = ZExt(m_ir->CreateLoad(ptr_inst->getResultElementType(), ptr_inst), get_type<u64>());
ptr_inst = dyn_cast<GetElementPtrInst>(m_ir->CreateGEP(func_table->getValueType(), func_table, {m_ir->getInt64(0), index_value}));
assert(ptr_inst->getResultElementType() == ftype->getPointerTo());
const auto faddr = m_ir->CreateLoad(ptr_inst->getResultElementType(), ptr_inst);
const auto faddr_int = m_ir->CreatePtrToInt(faddr, get_type<uptr>());
const auto fval = m_ir->CreateOr(m_ir->CreateShl(m_seg0, 32 + 3), faddr_int);
const auto pos = m_ir->CreateShl(m_reloc ? m_ir->CreateAdd(func_pc, m_seg0) : func_pc, 1);
const auto ptr = dyn_cast<GetElementPtrInst>(m_ir->CreateGEP(get_type<u8>(), m_exec, pos));
// Store to jumptable
m_ir->CreateStore(fval, ptr);
// Increment index and branch back to loop
const auto post_add = m_ir->CreateAdd(index_value, m_ir->getInt64(1));
index_value->addIncoming(post_add, body_block);
Value* index_check = m_ir->CreateICmpULT(post_add, m_ir->getInt64(vec_addrs.size()));
m_ir->CreateCondBr(index_check, body_block, after_loop);
// Set insertion point to afterloop_block
m_ir->SetInsertPoint(after_loop);
m_ir->CreateRetVoid();
replace_intrinsics(*m_function);
return m_function;
}
Value* PPUTranslator::VecHandleNan(Value* val)
{
const auto is_nan = m_ir->CreateFCmpUNO(val, val);
@@ -2536,7 +2646,7 @@ void PPUTranslator::SUBFC(ppu_opcode_t op)
SetGpr(op.rd, result);
SetCarry(m_ir->CreateICmpULE(result, b));
if (op.rc) SetCrFieldSignedCmp(0, result, m_ir->getInt64(0));
if (op.oe) SetOverflow(Call(GetType<bool>(), m_pure_attr, "__subfc_get_ov", a, b));
if (op.oe) UNK(op);
}
void PPUTranslator::ADDC(ppu_opcode_t op)
@@ -2547,7 +2657,7 @@ void PPUTranslator::ADDC(ppu_opcode_t op)
SetGpr(op.rd, result);
SetCarry(m_ir->CreateICmpULT(result, b));
if (op.rc) SetCrFieldSignedCmp(0, result, m_ir->getInt64(0));
if (op.oe) SetOverflow(Call(GetType<bool>(), m_pure_attr, "__addc_get_ov", a, b));
if (op.oe) UNK(op);
}
void PPUTranslator::MULHDU(ppu_opcode_t op)
@@ -2702,7 +2812,7 @@ void PPUTranslator::SUBF(ppu_opcode_t op)
const auto result = m_ir->CreateSub(b, a);
SetGpr(op.rd, result);
if (op.rc) SetCrFieldSignedCmp(0, result, m_ir->getInt64(0));
if (op.oe) SetOverflow(Call(GetType<bool>(), m_pure_attr, "__subf_get_ov", a, b));
if (op.oe) UNK(op);
}
void PPUTranslator::LDUX(ppu_opcode_t op)
@@ -2804,7 +2914,7 @@ void PPUTranslator::NEG(ppu_opcode_t op)
const auto result = m_ir->CreateNeg(reg);
SetGpr(op.rd, result);
if (op.rc) SetCrFieldSignedCmp(0, result, m_ir->getInt64(0));
if (op.oe) SetOverflow(Call(GetType<bool>(), m_pure_attr, "__neg_get_ov", reg));
if (op.oe) UNK(op);
}
void PPUTranslator::LBZUX(ppu_opcode_t op)
@@ -2837,7 +2947,7 @@ void PPUTranslator::SUBFE(ppu_opcode_t op)
SetGpr(op.rd, r2);
SetCarry(m_ir->CreateOr(m_ir->CreateICmpULT(r1, a), m_ir->CreateICmpULT(r2, r1)));
if (op.rc) SetCrFieldSignedCmp(0, r2, m_ir->getInt64(0));
if (op.oe) SetOverflow(Call(GetType<bool>(), m_pure_attr, "__subfe_get_ov", a, b, c));
if (op.oe) UNK(op);
}
void PPUTranslator::ADDE(ppu_opcode_t op)
@@ -2850,7 +2960,7 @@ void PPUTranslator::ADDE(ppu_opcode_t op)
SetGpr(op.rd, r2);
SetCarry(m_ir->CreateOr(m_ir->CreateICmpULT(r1, a), m_ir->CreateICmpULT(r2, r1)));
if (op.rc) SetCrFieldSignedCmp(0, r2, m_ir->getInt64(0));
if (op.oe) SetOverflow(Call(GetType<bool>(), m_pure_attr, "__adde_get_ov", a, b, c));
if (op.oe) UNK(op);
}
void PPUTranslator::MTOCRF(ppu_opcode_t op)
@@ -2969,7 +3079,7 @@ void PPUTranslator::ADDZE(ppu_opcode_t op)
SetGpr(op.rd, result);
SetCarry(m_ir->CreateICmpULT(result, a));
if (op.rc) SetCrFieldSignedCmp(0, result, m_ir->getInt64(0));
if (op.oe) SetOverflow(Call(GetType<bool>(), m_pure_attr, "__addze_get_ov", a, c));
if (op.oe) UNK(op);
}
void PPUTranslator::SUBFZE(ppu_opcode_t op)
@@ -2980,7 +3090,7 @@ void PPUTranslator::SUBFZE(ppu_opcode_t op)
SetGpr(op.rd, result);
SetCarry(m_ir->CreateICmpULT(result, a));
if (op.rc) SetCrFieldSignedCmp(0, result, m_ir->getInt64(0));
if (op.oe) SetOverflow(Call(GetType<bool>(), m_pure_attr, "__subfze_get_ov", a, c));
if (op.oe) UNK(op);
}
void PPUTranslator::STDCX(ppu_opcode_t op)
@@ -3009,7 +3119,7 @@ void PPUTranslator::SUBFME(ppu_opcode_t op)
SetGpr(op.rd, result);
SetCarry(m_ir->CreateOr(c, IsNotZero(a)));
if (op.rc) SetCrFieldSignedCmp(0, result, m_ir->getInt64(0));
if (op.oe) SetOverflow(Call(GetType<bool>(), m_pure_attr, "__subfme_get_ov", a, c));
if (op.oe) UNK(op);
}
void PPUTranslator::MULLD(ppu_opcode_t op)
@@ -3019,7 +3129,7 @@ void PPUTranslator::MULLD(ppu_opcode_t op)
const auto result = m_ir->CreateMul(a, b);
SetGpr(op.rd, result);
if (op.rc) SetCrFieldSignedCmp(0, result, m_ir->getInt64(0));
if (op.oe) SetOverflow(Call(GetType<bool>(), m_pure_attr, "__mulld_get_ov", a, b));
if (op.oe) UNK(op);
}
void PPUTranslator::ADDME(ppu_opcode_t op)
@@ -3030,7 +3140,7 @@ void PPUTranslator::ADDME(ppu_opcode_t op)
SetGpr(op.rd, result);
SetCarry(m_ir->CreateOr(c, IsNotZero(a)));
if (op.rc) SetCrFieldSignedCmp(0, result, m_ir->getInt64(0));
if (op.oe) SetOverflow(Call(GetType<bool>(), m_pure_attr, "__addme_get_ov", a, c));
if (op.oe) UNK(op);
}
void PPUTranslator::MULLW(ppu_opcode_t op)
@@ -3040,7 +3150,7 @@ void PPUTranslator::MULLW(ppu_opcode_t op)
const auto result = m_ir->CreateMul(a, b);
SetGpr(op.rd, result);
if (op.rc) SetCrFieldSignedCmp(0, result, m_ir->getInt64(0));
if (op.oe) SetOverflow(Call(GetType<bool>(), m_pure_attr, "__mullw_get_ov", a, b));
if (op.oe) UNK(op);
}
void PPUTranslator::DCBTST(ppu_opcode_t)
+1
View File
@@ -336,6 +336,7 @@ public:
// Parses PPU opcodes and translate them into LLVM IR
llvm::Function* Translate(const ppu_function& info);
llvm::Function* GetSymbolResolver(const ppu_module& info);
void MFVSCR(ppu_opcode_t op);
void MTVSCR(ppu_opcode_t op);
+211 -45
View File
@@ -802,6 +802,9 @@ void spu_cache::initialize(bool build_existing_cache)
compiler->init();
// Counter for error reporting
u32 logged_error = 0;
// How much every thread compiled
uint result = 0;
@@ -861,6 +864,14 @@ void spu_cache::initialize(bool build_existing_cache)
if (func2 != func)
{
spu_log.error("[0x%05x] SPU Analyser failed, %u vs %u", func2.entry_point, func2.data.size(), size0);
if (logged_error < 2)
{
std::string log;
compiler->dump(func, log);
spu_log.notice("[0x%05x] Function: %s", func.entry_point, log);
logged_error++;
}
}
else if (!compiler->compile(std::move(func2)))
{
@@ -1024,7 +1035,7 @@ void spu_cache::initialize(bool build_existing_cache)
}
}
if (new_entry != umax && !spu_thread::is_exec_code(new_entry, { reinterpret_cast<const u8*>(ls.data()), SPU_LS_SIZE }))
if (new_entry != umax && !spu_thread::is_exec_code(new_entry, { reinterpret_cast<const u8*>(ls.data()), SPU_LS_SIZE }, 0, true))
{
new_entry = umax;
}
@@ -1033,7 +1044,7 @@ void spu_cache::initialize(bool build_existing_cache)
{
new_entry = start_new;
while (new_entry < next_func && (ls[start_new / 4] < 0x3fffc || !spu_thread::is_exec_code(new_entry, { reinterpret_cast<const u8*>(ls.data()), SPU_LS_SIZE })))
while (new_entry < next_func && (ls[start_new / 4] < 0x3fffc || !spu_thread::is_exec_code(new_entry, { reinterpret_cast<const u8*>(ls.data()), SPU_LS_SIZE }, 0, true)))
{
new_entry += 4;
}
@@ -2281,13 +2292,13 @@ std::vector<u32> spu_thread::discover_functions(u32 base_addr, std::span<const u
calls.erase(std::remove_if(calls.begin(), calls.end(), [&](u32 caller)
{
// Check the validity of both the callee code and the following caller code
return !is_exec_code(caller, ls, base_addr) || !is_exec_code(caller + 4, ls, base_addr);
return !is_exec_code(caller, ls, base_addr, true) || !is_exec_code(caller + 4, ls, base_addr, true);
}), calls.end());
branches.erase(std::remove_if(branches.begin(), branches.end(), [&](u32 caller)
{
// Check the validity of the callee code
return !is_exec_code(caller, ls, base_addr);
return !is_exec_code(caller, ls, base_addr, true);
}), branches.end());
std::vector<u32> addrs;
@@ -2303,7 +2314,56 @@ std::vector<u32> spu_thread::discover_functions(u32 base_addr, std::span<const u
continue;
}
if (std::count(calls.begin(), calls.end(), func))
{
// Cannot call another call instruction (link is overwritten)
continue;
}
addrs.push_back(func);
// Detect an "arguments passing" block, possible queue another function
for (u32 next = func, it = 10; it && next >= base_addr && next < std::min<u32>(base_addr + ::size32(ls), 0x3FFF0); it--, next += 4)
{
const spu_opcode_t test_op{read_from_ptr<be_t<u32>>(ls, next - base_addr)};
const auto type = g_spu_itype.decode(test_op.opcode);
if (type & spu_itype::branch && type != spu_itype::BR)
{
break;
}
if (type == spu_itype::UNK || !test_op.opcode)
{
break;
}
if (type != spu_itype::BR)
{
continue;
}
const u32 target = op_branch_targets(next, op)[0];
if (target == umax || addr + 4 == target || target == addr || std::count(addrs.begin(), addrs.end(), target))
{
break;
}
// Detect backwards branch to the block in examination
if (target >= func && target <= next)
{
break;
}
if (!is_exec_code(target, ls, base_addr, true))
{
break;
}
addrs.push_back(target);
break;
}
}
for (u32 addr : branches)
@@ -2317,7 +2377,52 @@ std::vector<u32> spu_thread::discover_functions(u32 base_addr, std::span<const u
continue;
}
// Search for AI R1, +x or OR R3/4, Rx, 0
// Search for AI R1, -x in the called code
// Reasoning: AI R1, -x means stack frame creation, this is likely be a function
for (u32 next = func, it = 10; it && next >= base_addr && next < std::min<u32>(base_addr + ::size32(ls), 0x3FFF0); it--, next += 4)
{
const spu_opcode_t test_op{read_from_ptr<be_t<u32>>(ls, next - base_addr)};
const auto type = g_spu_itype.decode(test_op.opcode);
if (type & spu_itype::branch)
{
break;
}
if (type == spu_itype::UNK || !test_op.opcode)
{
break;
}
bool is_func = false;
if (type == spu_itype::AI && test_op.rt == 1u && test_op.ra == 1u)
{
if (test_op.si10 >= 0)
{
break;
}
is_func = true;
}
if (!is_func)
{
continue;
}
addr = SPU_LS_SIZE + 4; // Terminate the next condition, no further checks needed
if (std::count(addrs.begin(), addrs.end(), func))
{
break;
}
addrs.push_back(func);
break;
}
// Search for AI R1, +x or OR R3/4, Rx, 0 before the branch
// Reasoning: AI R1, +x means stack pointer restoration, branch after that is likely a tail call
// R3 and R4 are common function arguments because they are the first two
for (u32 back = addr - 4, it = 10; it && back >= base_addr && back < std::min<u32>(base_addr + ::size32(ls), 0x3FFF0); it--, back -= 4)
@@ -2394,9 +2499,9 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
workload.push_back(entry_point);
std::memset(m_regmod.data(), 0xff, sizeof(m_regmod));
std::memset(m_use_ra.data(), 0xff, sizeof(m_use_ra));
std::memset(m_use_rb.data(), 0xff, sizeof(m_use_rb));
std::memset(m_use_rc.data(), 0xff, sizeof(m_use_rc));
m_use_ra.reset();
m_use_rb.reset();
m_use_rc.reset();
m_targets.clear();
m_preds.clear();
m_preds[entry_point];
@@ -2491,11 +2596,11 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
if (auto iflags = g_spu_iflag.decode(data))
{
if (+iflags & +spu_iflag::use_ra)
m_use_ra[pos / 4] = op.ra;
m_use_ra.set(pos / 4);
if (+iflags & +spu_iflag::use_rb)
m_use_rb[pos / 4] = op.rb;
m_use_rb.set(pos / 4);
if (+iflags & +spu_iflag::use_rc)
m_use_rc[pos / 4] = op.rc;
m_use_rc.set(pos / 4);
}
// Analyse instruction
@@ -2837,7 +2942,6 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
if (g_cfg.core.spu_block_size == spu_block_size_type::giga && !sync)
{
m_entry_info[target / 4] = true;
add_block(target);
}
else
{
@@ -2845,13 +2949,9 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
{
spu_log.notice("[0x%x] At 0x%x: ignoring fixed tail call to 0x%x (SYNC)", entry_point, pos, target);
}
if (target > entry_point)
{
limit = std::min<u32>(limit, target);
}
}
add_block(target);
next_block();
break;
}
@@ -2927,11 +3027,6 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
m_regmod[pos / 4] = s_reg_mfc_size;
break;
}
case MFC_Cmd:
{
m_use_rb[pos / 4] = s_reg_mfc_eal;
break;
}
default: break;
}
@@ -3378,10 +3473,13 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
reg_save = op.rt;
}
for (auto* _use : {&m_use_ra, &m_use_rb, &m_use_rc})
for (auto _use : std::initializer_list<std::pair<u32, bool>>{{op.ra, m_use_ra.test(ia / 4)}
, {op.rb, m_use_rb.test(ia / 4)}, {op.rc, m_use_rc.test(ia / 4)}})
{
if (u8 reg = (*_use)[ia / 4]; reg < s_reg_max)
if (_use.second)
{
const u32 reg = _use.first;
// Register reg use only if it happens before reg mod
if (!block.reg_mod[reg])
{
@@ -3396,7 +3494,7 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
}
}
if (m_use_rb[ia / 4] == s_reg_mfc_eal)
if (type == spu_itype::WRCH && op.ra == MFC_Cmd)
{
// Expand MFC_Cmd reg use
for (u8 reg : {s_reg_mfc_lsa, s_reg_mfc_tag, s_reg_mfc_size})
@@ -3441,10 +3539,6 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
case spu_itype::BRASL:
is_call = spu_branch_target(0, op.i16) != ia + 4;
break;
case spu_itype::BRA:
is_call = true;
is_tail = true;
break;
case spu_itype::BISL:
case spu_itype::BISLED:
is_call = true;
@@ -4407,11 +4501,12 @@ struct spu_llvm_worker
void operator()()
{
// SPU LLVM Recompiler instance
const auto compiler = spu_recompiler_base::make_llvm_recompiler();
compiler->init();
std::unique_ptr<spu_recompiler_base> compiler;
// Fake LS
std::vector<be_t<u32>> ls(0x10000);
std::vector<be_t<u32>> ls;
bool set_relax_flag = false;
for (auto slice = registered.pop_all();; [&]
{
@@ -4425,6 +4520,12 @@ struct spu_llvm_worker
return;
}
if (set_relax_flag)
{
spu_thread::g_spu_work_count--;
set_relax_flag = false;
}
thread_ctrl::wait_on(utils::bless<atomic_t<u32>>(&registered)[1], 0);
slice = registered.pop_all();
}())
@@ -4446,6 +4547,21 @@ struct spu_llvm_worker
break;
}
if (!compiler)
{
// Postponed initialization
compiler = spu_recompiler_base::make_llvm_recompiler();
compiler->init();
ls.resize(SPU_LS_SIZE / sizeof(be_t<u32>));
}
if (!set_relax_flag)
{
spu_thread::g_spu_work_count++;
set_relax_flag = true;
}
const auto& func = *prog->second;
// Get data start
@@ -4487,12 +4603,18 @@ struct spu_llvm_worker
else
{
spu_log.fatal("[0x%05x] Compilation failed.", func.entry_point);
return;
break;
}
// Clear fake LS
std::memset(ls.data() + start / 4, 0, 4 * (size0 - 1));
}
if (set_relax_flag)
{
spu_thread::g_spu_work_count--;
set_relax_flag = false;
}
}
};
@@ -4516,6 +4638,17 @@ struct spu_llvm
return;
}
while (!registered && thread_ctrl::state() != thread_state::aborting)
{
// Wait for the first SPU block before launching any thread
thread_ctrl::wait_on(utils::bless<atomic_t<u32>>(&registered)[1], 0);
}
if (thread_ctrl::state() == thread_state::aborting)
{
return;
}
// To compile (hash -> item)
std::unordered_multimap<u64, spu_item*, value_hash<u64>> enqueued;
@@ -4566,19 +4699,22 @@ struct spu_llvm
if (uint hc = utils::get_thread_count(); hc >= 12)
{
worker_count = hc - 10;
worker_count = hc - 12 + 3;
}
else if (hc >= 6)
{
worker_count = 2;
}
u32 worker_index = 0;
u32 notify_compile_count = 0;
u32 compile_pending = 0;
std::vector<u8> notify_compile(worker_count);
m_workers = make_single<named_thread_group<spu_llvm_worker>>("SPUW.", worker_count);
auto workers_ptr = m_workers.load();
auto& workers = *workers_ptr;
usz add_count = 65535;
while (thread_ctrl::state() != thread_state::aborting)
{
for (const auto& pair : registered.pop_all())
@@ -4601,7 +4737,7 @@ struct spu_llvm
{
if (notify_compile[i])
{
(workers.begin() + (i % worker_count))->registered.notify();
(workers.begin() + i)->registered.notify();
}
}
}
@@ -4609,9 +4745,9 @@ struct spu_llvm
// Interrupt profiler thread and put it to sleep
static_cast<void>(prof_mutex.reset());
thread_ctrl::wait_on(utils::bless<atomic_t<u32>>(&registered)[1], 0);
add_count = 65535; // Reset count
std::fill(notify_compile.begin(), notify_compile.end(), 0); // Reset notification flags
notify_compile_count = 0;
compile_pending = 0;
continue;
}
@@ -4652,18 +4788,26 @@ struct spu_llvm
{
notify_compile[worker_index % worker_count] = 1;
notify_compile_count++;
}
if (notify_compile_count == notify_compile.size())
compile_pending++;
// Notify all before queue runs out if there is considerable excess
// Optimized that: if there are many workers, it acts soon
// If there are only a few workers, it postpones notifications until there is some more workload
if (notify_compile_count && std::min<u32>(7, utils::aligned_div<u32>(worker_count * 2, 3) + 2) <= compile_pending)
{
for (usz i = 0; i < worker_count; i++)
{
// Notify all
for (usz i = 0; i < worker_count; i++)
if (notify_compile[i])
{
(workers.begin() + (i % worker_count))->registered.notify();
(workers.begin() + i)->registered.notify();
}
std::fill(notify_compile.begin(), notify_compile.end(), 0); // Reset notification flags
notify_compile_count = 0;
}
std::fill(notify_compile.begin(), notify_compile.end(), 0); // Reset notification flags
notify_compile_count = 0;
compile_pending = 0;
}
worker_index++;
@@ -5061,3 +5205,25 @@ std::unique_ptr<spu_recompiler_base> spu_recompiler_base::make_fast_llvm_recompi
{
return std::make_unique<spu_fast>();
}
extern std::string format_spu_func_info(u32 addr, cpu_thread* spu)
{
spu_thread* _spu = static_cast<spu_thread*>(spu);
std::unique_ptr<spu_recompiler_base> compiler = spu_recompiler_base::make_asmjit_recompiler();
compiler->init();
auto func = compiler->analyse(reinterpret_cast<const be_t<u32>*>(_spu->ls), addr);
std::string info;
{
sha1_context ctx;
u8 output[20];
sha1_starts(&ctx);
sha1_update(&ctx, reinterpret_cast<const u8*>(func.data.data()), func.data.size() * 4);
sha1_finish(&ctx, output);
fmt::append(info, "size=%d, end=0x%x, hash=%s", func.data.size(), addr + func.data.size() * 4, fmt::base57(output));
}
return info;
}
+177 -81
View File
@@ -11,6 +11,8 @@
#include "SPUThread.h"
#include "SPUAnalyser.h"
#include "SPUInterpreter.h"
#include "SPUDisAsm.h"
#include <algorithm>
#include <thread>
#include <unordered_set>
@@ -30,26 +32,33 @@ const extern spu_decoder<spu_iflag> g_spu_iflag;
#pragma warning(push, 0)
#else
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wall"
#pragma GCC diagnostic ignored "-Wextra"
#pragma GCC diagnostic ignored "-Wold-style-cast"
#pragma GCC diagnostic ignored "-Wunused-parameter"
#pragma GCC diagnostic ignored "-Wstrict-aliasing"
#pragma GCC diagnostic ignored "-Weffc++"
#pragma GCC diagnostic ignored "-Wmissing-noreturn"
#pragma GCC diagnostic ignored "-Wstrict-aliasing"
#endif
#include <llvm/ADT/PostOrderIterator.h>
#include <llvm/Analysis/PostDominators.h>
#include <llvm/IR/InlineAsm.h>
#include <llvm/IR/Verifier.h>
#include <llvm/TargetParser/Host.h>
#include <llvm/Transforms/Utils/BasicBlockUtils.h>
#if LLVM_VERSION_MAJOR < 17
#include "llvm/ADT/Triple.h"
#include <llvm/IR/LegacyPassManager.h>
#include <llvm/Transforms/Scalar.h>
#include <llvm/Analysis/AliasAnalysis.h>
#else
#include <llvm/Analysis/CGSCCPassManager.h>
#include <llvm/Analysis/LoopAnalysisManager.h>
#include <llvm/IR/PassManager.h>
#include <llvm/Passes/PassBuilder.h>
#include <llvm/Transforms/Scalar/ADCE.h>
#include <llvm/Transforms/Scalar/DeadStoreElimination.h>
#include <llvm/Transforms/Scalar/EarlyCSE.h>
#include <llvm/Transforms/Scalar/LICM.h>
#include <llvm/Transforms/Scalar/LoopPassManager.h>
#include <llvm/Transforms/Scalar/SimplifyCFG.h>
#endif
#include "llvm/TargetParser/Host.h"
#include "llvm/IR/LegacyPassManager.h"
#include "llvm/IR/Verifier.h"
#include "llvm/IR/InlineAsm.h"
#include "llvm/Transforms/Utils/BasicBlockUtils.h"
#include "llvm/Transforms/Scalar.h"
#include "llvm/Analysis/PostDominators.h"
#include "llvm/Analysis/AliasAnalysis.h"
#include "llvm/ADT/PostOrderIterator.h"
#ifdef _MSC_VER
#pragma warning(pop)
#else
@@ -152,7 +161,8 @@ class spu_llvm_recompiler : public spu_recompiler_base, public cpu_translator
// Store reordering/elimination protection
std::array<usz, s_reg_max> store_context_last_id = fill_array<usz>(0); // Protects against illegal forward ordering
std::array<usz, s_reg_max> store_context_first_id = fill_array<usz>(usz{umax}); // Protects against illegal past store elimination (backwards ordering is not implemented)
std::array<usz, s_reg_max> store_context_ctr = fill_array<usz>(1); // Store barrier cointer
std::array<usz, s_reg_max> store_context_ctr = fill_array<usz>(1); // Store barrier counter
bool has_gpr_memory_barriers = false; // Summarizes whether GPR barriers exist this block (as if checking all store_context_ctr entries)
bool does_gpr_barrier_proceed_last_store(u32 i) const noexcept
{
@@ -494,8 +504,6 @@ class spu_llvm_recompiler : public spu_recompiler_base, public cpu_translator
return result;
}
ensure(!absolute);
auto& result = m_blocks[target].block;
if (!result)
@@ -1050,7 +1058,7 @@ class spu_llvm_recompiler : public spu_recompiler_base, public cpu_translator
m_ir->SetInsertPoint(check);
update_pc(addr);
if (may_be_unsafe_for_savestate && std::none_of(std::begin(m_block->phi), std::end(m_block->phi), FN(!!x)))
if (may_be_unsafe_for_savestate && m_block && m_block->bb->preds.empty())
{
may_be_unsafe_for_savestate = false;
}
@@ -1114,6 +1122,7 @@ public:
}
const u32 start0 = _func.entry_point;
const usz func_size = _func.data.size();
const auto add_loc = m_spurt->add_empty(std::move(_func));
@@ -1137,9 +1146,11 @@ public:
std::string log;
bool add_to_file = false;
if (auto& cache = g_fxo->get<spu_cache>(); cache && g_cfg.core.spu_cache && !add_loc->cached.exchange(1))
{
cache.add(func);
add_to_file = true;
}
{
@@ -1661,10 +1672,14 @@ public:
std::vector<block_info*> block_q;
block_q.reserve(m_blocks.size());
bool has_gpr_memory_barriers = false;
for (auto& [a, b] : m_blocks)
{
block_q.emplace_back(&b);
bb_to_info[b.block] = &b;
has_gpr_memory_barriers |= b.has_gpr_memory_barriers;
}
for (usz bi = 0; bi < block_q.size();)
@@ -1672,7 +1687,7 @@ public:
auto bqbi = block_q[bi++];
// TODO: process all registers up to s_reg_max
for (u32 i = 0; i < 128; i++)
for (u32 i = 0; i <= s_reg_127; i++)
{
// Check if the store is beyond the last barrier
if (auto& bs = bqbi->store[i]; bs && !bqbi->does_gpr_barrier_proceed_last_store(i))
@@ -1721,16 +1736,28 @@ public:
// Find nearest common post-dominator
llvm::BasicBlock* common_pdom = killers[0];
if (has_gpr_memory_barriers)
{
// Cannot optimize block walk-through, need to inspect all possible memory barriers in the way
common_pdom = nullptr;
}
for (auto* bbb : llvm::drop_begin(killers))
{
if (!common_pdom)
{
break;
}
common_pdom = pdt.findNearestCommonDominator(common_pdom, bbb);
}
// Shortcut
if (!pdt.dominates(common_pdom, bs->getParent()))
if (common_pdom && !pdt.dominates(common_pdom, bs->getParent()))
{
common_pdom = nullptr;
}
// Look for possibly-dead store in CFG starting from the exit nodes
llvm::SetVector<llvm::BasicBlock*> work_list;
@@ -1867,7 +1894,7 @@ public:
for (usz bi = 0; bi < block_q.size(); bi++)
{
for (u32 i = 0; i < 128; i++)
for (u32 i = 0; i <= s_reg_127; i++)
{
// If store isn't erased, try to sink it
if (auto& bs = block_q[bi]->store[i]; bs && block_q[bi]->bb->targets.size() > 1 && !block_q[bi]->does_gpr_barrier_proceed_last_store(i))
@@ -1901,8 +1928,10 @@ public:
auto si = llvm::cast<StoreInst>(m_ir->Insert(bs->clone()));
if (b2->store[i] == nullptr)
{
// Protect against backwards ordering now
b2->store[i] = si;
b2->store_context_last_id[i] = 0;
b2->store_context_first_id[i] = b2->store_context_ctr[i] + 1;
if (!std::count(block_q.begin() + bi, block_q.end(), b2))
{
@@ -2012,6 +2041,7 @@ public:
m_function_table->eraseFromParent();
}
#if LLVM_VERSION_MAJOR < 17
// Initialize pass manager
legacy::FunctionPassManager pm(_module.get());
@@ -2019,16 +2049,42 @@ public:
pm.add(createEarlyCSEPass());
pm.add(createCFGSimplificationPass());
//pm.add(createNewGVNPass());
#if LLVM_VERSION_MAJOR < 17
pm.add(createDeadStoreEliminationPass());
#endif
pm.add(createLICMPass());
#if LLVM_VERSION_MAJOR < 17
pm.add(createAggressiveDCEPass());
#else
pm.add(createDeadCodeEliminationPass());
#endif
//pm.add(createLintPass()); // Check
#else
// Create the analysis managers.
// These must be declared in this order so that they are destroyed in the
// correct order due to inter-analysis-manager references.
LoopAnalysisManager lam;
FunctionAnalysisManager fam;
CGSCCAnalysisManager cgam;
ModuleAnalysisManager mam;
// Create the new pass manager builder.
// Take a look at the PassBuilder constructor parameters for more
// customization, e.g. specifying a TargetMachine or various debugging
// options.
PassBuilder pb;
// Register all the basic analyses with the managers.
pb.registerModuleAnalyses(mam);
pb.registerCGSCCAnalyses(cgam);
pb.registerFunctionAnalyses(fam);
pb.registerLoopAnalyses(lam);
pb.crossRegisterProxies(lam, fam, cgam, mam);
FunctionPassManager fpm;
// Basic optimizations
fpm.addPass(EarlyCSEPass(true));
fpm.addPass(SimplifyCFGPass());
fpm.addPass(DSEPass());
fpm.addPass(createFunctionToLoopPassAdaptor(LICMPass(LICMOptions()), true));
fpm.addPass(ADCEPass());
#endif
for (auto& f : *m_module)
{
@@ -2038,7 +2094,11 @@ public:
for (const auto& func : m_functions)
{
const auto f = func.second.fn ? func.second.fn : func.second.chunk;
#if LLVM_VERSION_MAJOR < 17
pm.run(*f);
#else
fpm.run(*f, fam);
#endif
}
// Clear context (TODO)
@@ -2095,6 +2155,14 @@ public:
// Rebuild trampoline if necessary
if (!m_spurt->rebuild_ubertrampoline(func.data[0]))
{
if (auto& cache = g_fxo->get<spu_cache>())
{
if (add_to_file)
{
cache.add(func);
}
}
return nullptr;
}
@@ -2115,9 +2183,14 @@ public:
asm("DSB ISH");
#endif
if (g_fxo->get<spu_cache>().operator bool())
if (auto& cache = g_fxo->get<spu_cache>())
{
spu_log.success("New block compiled successfully");
if (add_to_file)
{
cache.add(func);
}
spu_log.success("New SPU block compiled successfully (size=%u)", func_size);
}
return fn;
@@ -2489,24 +2562,9 @@ public:
m_function_table->setInitializer(ConstantArray::get(ArrayType::get(if_type->getPointerTo(), 1ull << m_interp_magn), iptrs));
m_function_table = nullptr;
// Initialize pass manager
legacy::FunctionPassManager pm(_module.get());
// Basic optimizations
pm.add(createEarlyCSEPass());
pm.add(createCFGSimplificationPass());
#if LLVM_VERSION_MAJOR < 17
pm.add(createDeadStoreEliminationPass());
pm.add(createAggressiveDCEPass());
#else
pm.add(createDeadCodeEliminationPass());
#endif
//pm.add(createLintPass());
for (auto& f : *_module)
{
replace_intrinsics(f);
//pm.run(f);
}
std::string log;
@@ -2639,13 +2697,13 @@ public:
}
update_pc();
ensure_gpr_stores();
call("spu_syscall", &exec_stop, m_thread, m_ir->getInt32(op.opcode & 0x3fff));
if (g_cfg.core.spu_block_size == spu_block_size_type::safe)
{
m_block->block_end = m_ir->GetInsertBlock();
update_pc(m_pos + 4);
ensure_gpr_stores();
tail_chunk(m_dispatch);
return;
}
@@ -2707,6 +2765,7 @@ public:
{
// Make previous stores not able to be reordered beyond this point or be deleted
std::for_each(m_block->store_context_ctr.begin(), m_block->store_context_ctr.end(), FN(x++));
m_block->has_gpr_memory_barriers = true;
}
}
@@ -2905,6 +2964,40 @@ public:
return;
}
switch (op.ra)
{
case SPU_WrOutMbox:
case SPU_WrOutIntrMbox:
case SPU_RdSigNotify1:
case SPU_RdSigNotify2:
case SPU_RdInMbox:
case SPU_RdEventStat:
{
bool loop_is_likely = op.ra == SPU_RdSigNotify1 || op.ra == SPU_RdSigNotify2;
for (u32 block_start : m_block->bb->preds)
{
if (block_start >= m_pos)
{
loop_is_likely = true;
break;
}
}
if (loop_is_likely || g_cfg.savestate.compatible_mode)
{
ensure_gpr_stores();
check_state(m_pos, false);
}
break;
}
default:
{
break;
}
}
switch (op.ra)
{
case SPU_WrOutMbox:
@@ -3027,14 +3120,25 @@ public:
_spu->do_mfc();
}
template <bool Saveable>
static void exec_mfc_cmd(spu_thread* _spu)
{
if constexpr (!Saveable)
{
_spu->unsavable = true;
}
if (!_spu->process_mfc_cmd() || _spu->state & cpu_flag::again)
{
spu_runtime::g_escape(_spu);
fmt::throw_exception("exec_mfc_cmd(): Should not abort!");
}
static_cast<void>(_spu->test_stopped());
if constexpr (!Saveable)
{
_spu->unsavable = false;
}
}
void WRCH(spu_opcode_t op) //
@@ -3213,8 +3317,17 @@ public:
case MFC_GETLB_CMD:
case MFC_GETLF_CMD:
{
m_ir->CreateBr(next);
m_ir->SetInsertPoint(exec);
m_ir->CreateUnreachable();
m_ir->SetInsertPoint(fail);
m_ir->CreateUnreachable();
m_ir->SetInsertPoint(next);
m_ir->CreateStore(ci, spu_ptr<u8>(&spu_thread::ch_mfc_cmd, &spu_mfc_cmd::cmd));
update_pc();
ensure_gpr_stores();
[[fallthrough]];
call("spu_exec_mfc_cmd_saveable", &exec_mfc_cmd<true>, m_thread);
return;
}
case MFC_SDCRZ_CMD:
case MFC_GETLLAR_CMD:
@@ -3231,7 +3344,7 @@ public:
m_ir->SetInsertPoint(next);
m_ir->CreateStore(ci, spu_ptr<u8>(&spu_thread::ch_mfc_cmd, &spu_mfc_cmd::cmd));
update_pc();
call("spu_exec_mfc_cmd", &exec_mfc_cmd, m_thread);
call("spu_exec_mfc_cmd", &exec_mfc_cmd<false>, m_thread);
return;
}
case MFC_SNDSIG_CMD:
@@ -3290,7 +3403,7 @@ public:
}
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);
call("spu_exec_mfc_cmd", &exec_mfc_cmd<false>, m_thread);
m_ir->CreateBr(next);
m_ir->SetInsertPoint(copy);
@@ -5874,55 +5987,34 @@ public:
// This is odd since SPU code could just use the FM instruction, but it seems common enough
if (auto [ok, data] = get_const_vector(c.value, m_pos); ok)
{
if (is_spu_float_zero(data, -1))
if (is_spu_float_zero(data, 0))
{
return eval(a * b);
}
if (!m_use_fma && is_spu_float_zero(data, +1))
{
return eval(a * b + fsplat<f32[4]>(0.f));
}
}
if ([&]()
{
if (auto [ok, data] = get_const_vector(a.value, m_pos); ok)
{
if (!is_spu_float_zero(data, +1))
if (is_spu_float_zero(data, 0))
{
return false;
}
if (auto [ok0, data0] = get_const_vector(b.value, m_pos); ok0)
{
if (is_spu_float_zero(data0, +1))
{
return true;
}
return true;
}
}
if (auto [ok, data] = get_const_vector(a.value, m_pos); ok)
if (auto [ok, data] = get_const_vector(b.value, m_pos); ok)
{
if (!is_spu_float_zero(data, -1))
if (is_spu_float_zero(data, 0))
{
return false;
}
if (auto [ok0, data0] = get_const_vector(b.value, m_pos); ok0)
{
if (is_spu_float_zero(data0, -1))
{
return true;
}
return true;
}
}
return false;
}())
{
// Just return the added value if both a and b is +0 or -0 (+0 and -0 arent't allowed alone)
// Just return the added value if either a or b are +-0
return c;
}
@@ -6295,7 +6387,7 @@ public:
const auto bnew = (base - ymul) >> (zext<u32[4]>(comparison) ^ 9); // Shift one less bit if exponent is adjusted
const auto base_result = (b & 0xff800000u) | (bnew & ~0xff800000u); // Inject old sign and exponent
const auto adjustment = bitcast<u32[4]>(sext<s32[4]>(comparison)) & (1 << 23); // exponent adjustement for negative bnew
return bitcast<f32[4]>(base_result - adjustment);
return clamp_smax(eval(bitcast<f32[4]>(base_result - adjustment)));
});
const auto [a, b] = get_vrs<f32[4]>(op.ra, op.rb);
@@ -6329,7 +6421,7 @@ public:
const auto bnew = (base - ymul) >> (zext<u32[4]>(comparison) ^ 9); // Shift one less bit if exponent is adjusted
const auto base_result = (b & 0xff800000u) | (bnew & ~0xff800000u); // Inject old sign and exponent
const auto adjustment = bitcast<u32[4]>(sext<s32[4]>(comparison)) & (1 << 23); // exponent adjustement for negative bnew
return bitcast<f32[4]>(base_result - adjustment);
return clamp_smax(eval(bitcast<f32[4]>(base_result - adjustment)));
});
register_intrinsic("spu_rsqrte", [&](llvm::CallInst* ci)
@@ -6356,7 +6448,7 @@ public:
const auto bnew = (base - ymul) >> (zext<u32[4]>(comparison) ^ 9); // Shift one less bit if exponent is adjusted
const auto base_result = (b & 0xff800000u) | (bnew & ~0xff800000u); // Inject old sign and exponent
const auto adjustment = bitcast<u32[4]>(sext<s32[4]>(comparison)) & (1 << 23); // exponent adjustement for negative bnew
return bitcast<f32[4]>(base_result - adjustment);
return clamp_smax(eval(bitcast<f32[4]>(base_result - adjustment)));
});
break;
}
@@ -7547,10 +7639,14 @@ public:
return;
}
const auto compiled_pos = m_ir->getInt32(m_pos);
const u32 target = spu_branch_target(0, op.i16);
m_block->block_end = m_ir->GetInsertBlock();
m_ir->CreateBr(add_block(target, true));
const auto real_pos = get_pc(m_pos);
value_t<u32> target_val;
target_val.value = m_ir->getInt32(target);
m_ir->CreateCondBr(m_ir->CreateICmpEQ(real_pos, compiled_pos), add_block(target, true), add_block_indirect({}, target_val));
}
void BRASL(spu_opcode_t op) //
+3 -3
View File
@@ -202,9 +202,9 @@ protected:
// GPR modified by the instruction (-1 = not set)
std::array<u8, 0x10000> m_regmod;
std::array<u8, 0x10000> m_use_ra;
std::array<u8, 0x10000> m_use_rb;
std::array<u8, 0x10000> m_use_rc;
std::bitset<0x10000> m_use_ra;
std::bitset<0x10000> m_use_rb;
std::bitset<0x10000> m_use_rc;
// List of possible targets for the instruction (entry shouldn't exist for simple instructions)
std::unordered_map<u32, std::basic_string<u32>, value_hash<u32, 2>> m_targets;
+114 -11
View File
@@ -448,11 +448,6 @@ namespace vm
{
if (range_lock)
{
if (!*range_lock)
{
return;
}
g_range_lock_bits[1] &= ~(1ull << (range_lock - g_range_lock_set));
range_lock->release(0);
return;
@@ -1844,7 +1839,10 @@ void spu_thread::cpu_work()
if (has_active_local_bps)
{
if (local_breakpoints[pc / 4])
const u32 pos_at = pc / 4;
const u32 pos_bit = 1u << (pos_at % 8);
if (local_breakpoints[pos_at / 8] & pos_bit)
{
// Ignore repeatations until a different instruction is issued
if (pc != current_bp_pc)
@@ -4119,9 +4117,11 @@ bool spu_thread::check_mfc_interrupts(u32 next_pc)
return false;
}
bool spu_thread::is_exec_code(u32 addr, std::span<const u8> ls_ptr, u32 base_addr)
bool spu_thread::is_exec_code(u32 addr, std::span<const u8> ls_ptr, u32 base_addr, bool avoid_dead_code)
{
for (u32 i = 0; i < 30; i++)
bool had_conditional = false;
for (u32 i = 0; i < 40; i++)
{
if (addr & ~0x3FFFC)
{
@@ -4142,9 +4142,32 @@ bool spu_thread::is_exec_code(u32 addr, std::span<const u8> ls_ptr, u32 base_add
return false;
}
if (type == spu_itype::STOP && op.rb)
if (type == spu_itype::STOP)
{
return false;
if (op.rb)
{
return false;
}
if (avoid_dead_code)
{
switch (op.opcode)
{
case SYS_SPU_THREAD_STOP_YIELD:
case SYS_SPU_THREAD_STOP_GROUP_EXIT:
case SYS_SPU_THREAD_STOP_THREAD_EXIT:
case SYS_SPU_THREAD_STOP_RECEIVE_EVENT:
case SYS_SPU_THREAD_STOP_TRY_RECEIVE_EVENT:
case SYS_SPU_THREAD_STOP_SWITCH_SYSTEM_MODULE:
{
break;
}
default:
{
return false;
}
}
}
}
if (type & spu_itype::branch)
@@ -4179,6 +4202,58 @@ bool spu_thread::is_exec_code(u32 addr, std::span<const u8> ls_ptr, u32 base_add
break;
}
}
else
{
switch (type)
{
case spu_itype::BR:
case spu_itype::BRNZ:
case spu_itype::BRZ:
case spu_itype::BRHNZ:
case spu_itype::BRHZ:
case spu_itype::BRSL:
{
const s32 rel = bf_t<s32, 0, 18>::extract(static_cast<s32>(u32{op.i16} << 2));
if (rel == 0 && !had_conditional && avoid_dead_code)
{
// Infinite loop 100%, detect that as invalid code
return false;
}
// Detect "invalid" relative branches
// Branch offsets that, although are the only way to get X code address using relative address
// Rely on overflow/underflow of SPU memory bounds
// Thus they would behave differently if SPU LS memory size was to increase (evolving the CELL architecture was the original plan)
// Making them highly unlikely to be valid code
if (rel < 0)
{
if (addr < 0u - rel)
{
return false;
}
}
else if (SPU_LS_SIZE - addr <= rel + 0u)
{
return false;
}
if (type == spu_itype::BRSL)
{
// Insert a virtual return-to-next, because it is usually a call
results[1] = addr + 4;
std::swap(results[1], results[0]);
}
break;
}
default:
{
break;
}
}
}
for (usz res_i = 1; res_i < results.size(); res_i++)
{
@@ -4203,6 +4278,8 @@ bool spu_thread::is_exec_code(u32 addr, std::span<const u8> ls_ptr, u32 base_add
{
return false;
}
had_conditional = true;
}
addr = spu_branch_target(results[0]);
@@ -5174,10 +5251,12 @@ s64 spu_thread::get_ch_value(u32 ch)
}
}
const usz seed = (utils::get_tsc() >> 8) % 100;
#ifdef __linux__
const bool reservation_busy_waiting = false;
#else
const bool reservation_busy_waiting = ((utils::get_tsc() >> 8) % 100 + ((raddr == spurs_addr) ? 50 : 0)) < g_cfg.core.spu_reservation_busy_waiting_percentage;
const bool reservation_busy_waiting = (seed + ((raddr == spurs_addr) ? 50u : 0u)) < g_cfg.core.spu_reservation_busy_waiting_percentage;
#endif
for (; !events.count; events = get_events(mask1 & ~SPU_EVENT_LR, true, true))
@@ -5202,6 +5281,23 @@ s64 spu_thread::get_ch_value(u32 ch)
// Don't busy-wait with TSX - memory is sensitive
if (g_use_rtm || !reservation_busy_waiting)
{
if (u32 work_count = g_spu_work_count)
{
const u32 true_free = utils::sub_saturate<u32>(utils::get_thread_count(), 10);
if (work_count > true_free)
{
// SPU thread count estimation
const u32 thread_count = (group ? g_raw_spu_ctr + group->max_num : g_raw_spu_ctr + 3);
if (thread_count && seed % thread_count < work_count - true_free)
{
// Make the SPU wait longer for other threads to do the work
thread_ctrl::wait_for(200);
continue;
}
}
}
#ifdef __linux__
vm::reservation_notifier(raddr).wait(rtime, atomic_wait_timeout{50'000});
#else
@@ -6056,6 +6152,12 @@ bool spu_thread::stop_and_signal(u32 code)
return true;
}
case SYS_SPU_THREAD_STOP_SWITCH_SYSTEM_MODULE:
{
fmt::throw_exception("SYS_SPU_THREAD_STOP_SWITCH_SYSTEM_MODULE (op=0x%x, Out_MBox=%s)", code, _ref<u32>(pc), ch_out_mbox);
return true;
}
case SYS_SPU_THREAD_STOP_YIELD:
{
// SPU thread group yield (TODO)
@@ -6710,3 +6812,4 @@ void fmt_class_string<spu_channel_4_t>::format(std::string& out, u64 arg)
DECLARE(spu_thread::g_raw_spu_ctr){};
DECLARE(spu_thread::g_raw_spu_id){};
DECLARE(spu_thread::g_spu_work_count){};
+3 -2
View File
@@ -816,7 +816,7 @@ public:
atomic_t<spu_debugger_mode> debugger_mode{};
// PC-based breakpoint list
std::array<atomic_t<bool>, SPU_LS_SIZE / 4> local_breakpoints{};
std::array<atomic_t<u8>, SPU_LS_SIZE / 4 / 8> local_breakpoints{};
atomic_t<bool> has_active_local_bps = false;
u32 current_bp_pc = umax;
bool stop_flag_removal_protection = false;
@@ -835,7 +835,7 @@ public:
void set_events(u32 bits);
void set_interrupt_status(bool enable);
bool check_mfc_interrupts(u32 next_pc);
static bool is_exec_code(u32 addr, std::span<const u8> ls_ptr, u32 base_addr = 0); // Only a hint, do not rely on it other than debugging purposes
static bool is_exec_code(u32 addr, std::span<const u8> ls_ptr, u32 base_addr = 0, bool avoid_dead_code = false); // Only a hint, do not rely on it other than debugging purposes
static std::vector<u32> discover_functions(u32 base_addr, std::span<const u8> ls, bool is_known_addr, u32 /*entry*/);
u32 get_ch_count(u32 ch);
s64 get_ch_value(u32 ch);
@@ -889,6 +889,7 @@ public:
static atomic_t<u32> g_raw_spu_ctr;
static atomic_t<u32> g_raw_spu_id[5];
static atomic_t<u32> g_spu_work_count;
static u32 find_raw_spu(u32 id)
{
+90 -20
View File
@@ -55,6 +55,7 @@
#include <deque>
#include "util/tsc.hpp"
#include "util/sysinfo.hpp"
#include "util/init_mutex.hpp"
#if defined(ARCH_X64)
#ifdef _MSC_VER
@@ -267,13 +268,13 @@ const std::array<std::pair<ppu_intrp_func_t, std::string_view>, 1024> g_ppu_sysc
BIND_SYSC(sys_event_port_connect_ipc), //140 (0x08C)
BIND_SYSC(sys_timer_usleep), //141 (0x08D)
BIND_SYSC(sys_timer_sleep), //142 (0x08E)
NULL_FUNC(sys_time_set_timezone), //143 (0x08F) ROOT
BIND_SYSC(sys_time_set_timezone), //143 (0x08F) ROOT
BIND_SYSC(sys_time_get_timezone), //144 (0x090)
BIND_SYSC(sys_time_get_current_time), //145 (0x091)
NULL_FUNC(sys_time_get_system_time), //146 (0x092) ROOT
BIND_SYSC(sys_time_set_current_time), //146 (0x092) ROOT
BIND_SYSC(sys_time_get_timebase_frequency), //147 (0x093)
BIND_SYSC(_sys_rwlock_trywlock), //148 (0x094)
uns_func, //149 (0x095) UNS
NULL_FUNC(sys_time_get_system_time), //149 (0x095)
BIND_SYSC(sys_raw_spu_create_interrupt_tag), //150 (0x096)
BIND_SYSC(sys_raw_spu_set_int_mask), //151 (0x097)
BIND_SYSC(sys_raw_spu_get_int_mask), //152 (0x098)
@@ -1108,6 +1109,61 @@ void fmt_class_string<CellError>::format(std::string& out, u64 arg)
});
}
stx::init_lock acquire_lock(stx::init_mutex& mtx, ppu_thread* ppu)
{
if (!ppu)
{
ppu = ensure(cpu_thread::get_current<ppu_thread>());
}
return mtx.init([](int invoke_count, const stx::init_lock&, ppu_thread* ppu)
{
if (!invoke_count)
{
// Sleep before waiting on lock
lv2_obj::sleep(*ppu);
}
else
{
// Wake up after acquistion or failure to acquire
ppu->check_state();
}
}, ppu);
}
stx::access_lock acquire_access_lock(stx::init_mutex& mtx, ppu_thread* ppu)
{
if (!ppu)
{
ppu = ensure(cpu_thread::get_current<ppu_thread>());
}
// TODO: Check if needs to wait
return mtx.access();
}
stx::reset_lock acquire_reset_lock(stx::init_mutex& mtx, ppu_thread* ppu)
{
if (!ppu)
{
ppu = ensure(cpu_thread::get_current<ppu_thread>());
}
return mtx.reset([](int invoke_count, const stx::init_lock&, ppu_thread* ppu)
{
if (!invoke_count)
{
// Sleep before waiting on lock
lv2_obj::sleep(*ppu);
}
else
{
// Wake up after acquistion or failure to acquire
ppu->check_state();
}
}, ppu);
}
class ppu_syscall_usage
{
// Internal buffer
@@ -1390,16 +1446,28 @@ bool lv2_obj::sleep_unlocked(cpu_thread& thread, u64 timeout, u64 current_time)
auto on_to_sleep_update = [&]()
{
std::string out = fmt::format("Threads (%d):", g_to_sleep.size());
for (auto thread : g_to_sleep)
if (g_to_sleep.size() > 5u)
{
fmt::append(out, " 0x%x,", thread->id);
ppu_log.warning("Threads (%d)", g_to_sleep.size());
}
ppu_log.warning("%s", out);
if (g_to_sleep.empty())
else if (!g_to_sleep.empty())
{
// In case there is a deadlock (PPU threads not sleeping)
// Print-out their IDs for further inspection (focus at 5 at max for now to avoid log spam)
std::string out = fmt::format("Threads (%d):", g_to_sleep.size());
for (auto thread : g_to_sleep)
{
fmt::append(out, " 0x%x,", thread->id);
}
out.resize(out.size() - 1);
ppu_log.warning("%s", out);
}
else
{
ppu_log.warning("Final Thread");
// All threads are ready, wake threads
Emu.CallFromMainThread([]
{
@@ -1725,12 +1793,14 @@ bool lv2_obj::awake_unlocked(cpu_thread* cpu, s32 prio)
{
if (current_ppu->prio.load().prio > lowest_new_priority)
{
const bool is_create_thread = current_ppu->gpr[11] == 0x35;
// When not being set to All timers - activate only for sys_ppu_thread_start
if (current_ppu->gpr[11] == 0x35 || g_cfg.core.sleep_timers_accuracy == sleep_timers_accuracy_level::_all_timers)
if (is_create_thread || g_cfg.core.sleep_timers_accuracy == sleep_timers_accuracy_level::_all_timers)
{
if (!current_ppu->state.test_and_set(cpu_flag::yield) || current_ppu->hw_sleep_time != 0)
{
current_ppu->hw_sleep_time += 35; // Seems like 35us after extensive testing
current_ppu->hw_sleep_time += (is_create_thread ? 51 : 35);
}
else
{
@@ -1888,7 +1958,7 @@ void lv2_obj::make_scheduler_ready()
lv2_obj::awake_all();
}
ppu_thread_status lv2_obj::ppu_state(ppu_thread* ppu, bool lock_idm, bool lock_lv2)
std::pair<ppu_thread_status, u32> lv2_obj::ppu_state(ppu_thread* ppu, bool lock_idm, bool lock_lv2)
{
std::optional<reader_lock> opt_lock[2];
@@ -1899,13 +1969,13 @@ ppu_thread_status lv2_obj::ppu_state(ppu_thread* ppu, bool lock_idm, bool lock_l
if (!Emu.IsReady() ? ppu->state.all_of(cpu_flag::stop) : ppu->stop_flag_removal_protection)
{
return PPU_THREAD_STATUS_IDLE;
return { PPU_THREAD_STATUS_IDLE, 0};
}
switch (ppu->joiner)
{
case ppu_join_status::zombie: return PPU_THREAD_STATUS_ZOMBIE;
case ppu_join_status::exited: return PPU_THREAD_STATUS_DELETED;
case ppu_join_status::zombie: return { PPU_THREAD_STATUS_ZOMBIE, 0};
case ppu_join_status::exited: return { PPU_THREAD_STATUS_DELETED, 0};
default: break;
}
@@ -1930,18 +2000,18 @@ ppu_thread_status lv2_obj::ppu_state(ppu_thread* ppu, bool lock_idm, bool lock_l
{
if (!ppu->interrupt_thread_executing)
{
return PPU_THREAD_STATUS_STOP;
return { PPU_THREAD_STATUS_STOP, 0};
}
return PPU_THREAD_STATUS_SLEEP;
return { PPU_THREAD_STATUS_SLEEP, 0 };
}
if (pos >= g_cfg.core.ppu_threads + 0u)
{
return PPU_THREAD_STATUS_RUNNABLE;
return { PPU_THREAD_STATUS_RUNNABLE, pos };
}
return PPU_THREAD_STATUS_ONPROC;
return { PPU_THREAD_STATUS_ONPROC, pos};
}
void lv2_obj::set_future_sleep(cpu_thread* cpu)
+12 -2
View File
@@ -74,7 +74,7 @@ error_code sys_cond_create(ppu_thread& ppu, vm::ptr<u32> cond_id, u32 mutex_id,
{
ppu.state += cpu_flag::wait;
sys_cond.warning("sys_cond_create(cond_id=*0x%x, mutex_id=0x%x, attr=*0x%x)", cond_id, mutex_id, attr);
sys_cond.trace("sys_cond_create(cond_id=*0x%x, mutex_id=0x%x, attr=*0x%x)", cond_id, mutex_id, attr);
auto mutex = idm::get<lv2_obj, lv2_mutex>(mutex_id);
@@ -87,6 +87,11 @@ error_code sys_cond_create(ppu_thread& ppu, vm::ptr<u32> cond_id, u32 mutex_id,
const u64 ipc_key = lv2_obj::get_key(_attr);
if (ipc_key)
{
sys_cond.warning("sys_cond_create(cond_id=*0x%x, attr=*0x%x): IPC=0x%016x", cond_id, attr, ipc_key);
}
if (const auto error = lv2_obj::create<lv2_cond>(_attr.pshared, ipc_key, _attr.flags, [&]
{
return std::make_shared<lv2_cond>(
@@ -108,7 +113,7 @@ error_code sys_cond_destroy(ppu_thread& ppu, u32 cond_id)
{
ppu.state += cpu_flag::wait;
sys_cond.warning("sys_cond_destroy(cond_id=0x%x)", cond_id);
sys_cond.trace("sys_cond_destroy(cond_id=0x%x)", cond_id);
const auto cond = idm::withdraw<lv2_obj, lv2_cond>(cond_id, [&](lv2_cond& cond) -> CellError
{
@@ -129,6 +134,11 @@ error_code sys_cond_destroy(ppu_thread& ppu, u32 cond_id)
return CELL_ESRCH;
}
if (cond->key)
{
sys_cond.warning("sys_cond_destroy(cond_id=0x%x): IPC=0x%016x", cond_id, cond->key);
}
if (cond.ret)
{
return cond.ret;
+2 -2
View File
@@ -29,7 +29,7 @@ error_code _sys_lwcond_create(ppu_thread& ppu, vm::ptr<u32> lwcond_id, u32 lwmut
{
ppu.state += cpu_flag::wait;
sys_lwcond.warning(u8"_sys_lwcond_create(lwcond_id=*0x%x, lwmutex_id=0x%x, control=*0x%x, name=0x%llx (“%s”))", lwcond_id, lwmutex_id, control, name, lv2_obj::name_64{std::bit_cast<be_t<u64>>(name)});
sys_lwcond.trace(u8"_sys_lwcond_create(lwcond_id=*0x%x, lwmutex_id=0x%x, control=*0x%x, name=0x%llx (“%s”))", lwcond_id, lwmutex_id, control, name, lv2_obj::name_64{std::bit_cast<be_t<u64>>(name)});
u32 protocol;
@@ -62,7 +62,7 @@ error_code _sys_lwcond_destroy(ppu_thread& ppu, u32 lwcond_id)
{
ppu.state += cpu_flag::wait;
sys_lwcond.warning("_sys_lwcond_destroy(lwcond_id=0x%x)", lwcond_id);
sys_lwcond.trace("_sys_lwcond_destroy(lwcond_id=0x%x)", lwcond_id);
std::shared_ptr<lv2_lwcond> _cond;
+15 -3
View File
@@ -40,7 +40,7 @@ error_code sys_mutex_create(ppu_thread& ppu, vm::ptr<u32> mutex_id, vm::ptr<sys_
{
ppu.state += cpu_flag::wait;
sys_mutex.warning("sys_mutex_create(mutex_id=*0x%x, attr=*0x%x)", mutex_id, attr);
sys_mutex.trace("sys_mutex_create(mutex_id=*0x%x, attr=*0x%x)", mutex_id, attr);
if (!mutex_id || !attr)
{
@@ -49,6 +49,13 @@ error_code sys_mutex_create(ppu_thread& ppu, vm::ptr<u32> mutex_id, vm::ptr<sys_
const auto _attr = *attr;
const u64 ipc_key = lv2_obj::get_key(_attr);
if (ipc_key)
{
sys_mutex.warning("sys_mutex_create(mutex_id=*0x%x, attr=*0x%x): IPC=0x%016x", mutex_id, attr, ipc_key);
}
switch (_attr.protocol)
{
case SYS_SYNC_FIFO: break;
@@ -85,7 +92,7 @@ error_code sys_mutex_create(ppu_thread& ppu, vm::ptr<u32> mutex_id, vm::ptr<sys_
_attr.protocol,
_attr.recursive,
_attr.adaptive,
_attr.ipc_key,
ipc_key,
_attr.name_u64);
}))
{
@@ -101,7 +108,7 @@ error_code sys_mutex_destroy(ppu_thread& ppu, u32 mutex_id)
{
ppu.state += cpu_flag::wait;
sys_mutex.warning("sys_mutex_destroy(mutex_id=0x%x)", mutex_id);
sys_mutex.trace("sys_mutex_destroy(mutex_id=0x%x)", mutex_id);
const auto mutex = idm::withdraw<lv2_obj, lv2_mutex>(mutex_id, [](lv2_mutex& mutex) -> CellError
{
@@ -126,6 +133,11 @@ error_code sys_mutex_destroy(ppu_thread& ppu, u32 mutex_id)
return CELL_ESRCH;
}
if (mutex->key)
{
sys_mutex.warning("sys_mutex_destroy(mutex_id=0x%x): IPC=0x%016x", mutex_id, mutex->key);
}
if (mutex.ret)
{
return mutex.ret;

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