Compare commits

...

486 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
Ani ef8afa7873 rpcs3_version: Bump to 0.0.31 2024-03-05 00:40:22 +01:00
nastys df4fc947ec Improve macOS < 14.3 Rosetta blocker message (#15258) 2024-03-01 20:01:21 +01:00
InvoxiPlayGames eecfbf3fa6 add Wii Harmonix instruments to whitelist 2024-03-01 19:07:02 +01:00
Elad.Ash cfbe7669b4 Update serialization.hpp 2024-03-01 14:58:48 +02:00
Elad.Ash ccaeb87b01 Update serialization.hpp 2024-03-01 14:58:48 +02:00
Elad.Ash fc98f35ea7 Update serialization.hpp 2024-03-01 14:58:48 +02:00
Elad Ashkenazi 998f867c29 serialization.hpp: Fix HLE serilization 2024-03-01 14:58:48 +02:00
capriots eb8325afcb cellPamf implementation (#15143) 2024-02-29 21:45:28 +01:00
RipleyTom 7674c29c78 Fix for sceNpScoreGetGameData 2024-02-29 15:12:22 +02:00
RipleyTom 573734fab8 Send initial presence for offline friends. 2024-02-28 17:41:25 +01:00
Megamouse 2cbd983b4c GL: remove unused params 2024-02-28 14:25:20 +01:00
Megamouse 18983f5476 Fix warnings: Remove unused decryption code 2024-02-28 14:25:20 +01:00
Elad.Ash 75ef154c12 SPU LLVM: Improve runtime SPU compilation preferences (#15250) 2024-02-28 08:28:49 +02:00
RipleyTom 414a354511 Improve cellSysutilAvc2SetAttribute logging 2024-02-28 02:14:37 +01:00
RipleyTom 2168511e5b Add check for score transactions being reused 2024-02-28 02:14:37 +01:00
Mrlinkwii f64d6bc687 Misc: Update FW Latest Version 2024-02-27 12:52:53 +01:00
oltolm 3e83729cb2 xaudio2: use system library instead of xaudio2redist 2024-02-27 05:21:32 +02:00
kd-11 83256cdacb Make clang happy 2024-02-26 18:15:06 +03:00
kd-11 f748fe688c gl: Allow selecting FSR1 upscaling from the settings 2024-02-26 18:15:06 +03:00
kd-11 188f5c7c3c gl: FSR1 cleanup, making it functional 2024-02-26 18:15:06 +03:00
kd-11 838346e4f7 gl: Always log the current renderer visibly. 2024-02-26 18:15:06 +03:00
kd-11 12dc03a903 rsx: Improve simple array performance for small objects
- Also adds map/collect transformation
2024-02-26 18:15:06 +03:00
kd-11 e17c2f2397 gl: Fix compilation 2024-02-26 18:15:06 +03:00
kd-11 071baf63b0 rsx: Implement FSR1 integration for OpenGL 2024-02-26 18:15:06 +03:00
kd-11 1795d5bcc9 gl: Rework the upscalers a bit and define the FSR interface 2024-02-26 18:15:06 +03:00
kd-11 27125c6f72 gl: Remove upscaling 'dst' binding and clean up some awful code in GLPresent 2024-02-26 18:15:06 +03:00
kd-11 12694dcf69 gl: Introduce the concept of scaling passes to the backend 2024-02-26 18:15:06 +03:00
kd-11 e7d8ef924f rsx/vk: Refactor FSR integration to support multiple backends 2024-02-26 18:15:06 +03:00
RipleyTom 0f682b7da1 Fix Apple Clang build 2024-02-24 20:54:55 +02:00
nastys 2b385f28f0 Block Rosetta on macOS 14.0, 14.1, and 14.2 (#15237) 2024-02-24 15:15:19 +01:00
RipleyTom ac8e914a25 improves sig_ctx handling, sys_net logging and fixes udpp2p protocol (#15235) 2024-02-24 12:40:53 +01:00
Megamouse 3067c86d65 gui/input: only init and quit SDL once for all instances
Calling SDL_Quit while two handlers are active can cause controllers to disconnect
2024-02-22 19:31:00 +01:00
Megamouse 96afc15fa2 gui/input; fix log message delta type 2024-02-22 19:31:00 +01:00
Megamouse 66f694bb39 gui/input: include Carbon.h on apple 2024-02-22 19:31:00 +01:00
Megamouse 06025cd19d gui/input: let pad handlers know whether they are part of emulation
Also fix unique_ptr vs shared_ptr nonsense in pad_threads
2024-02-22 19:31:00 +01:00
Megamouse fc698a4df2 gui/input: implement pad navigation for maxOs 2024-02-22 19:31:00 +01:00
Megamouse 2cd47c0415 gui/input: use uinput for linux in gui_pad_thread 2024-02-22 19:31:00 +01:00
Megamouse b032f2dd87 gui/input: add gui input with native events 2024-02-22 19:31:00 +01:00
RipleyTom 3acd442c2e sceNpBasicSendMessage fix 2024-02-22 05:33:29 +02:00
Megamouse 6b43e5c80e Qt: add Q_OBJECT macro to midi_creator
This fixes the localization of its strings
2024-02-20 10:06:02 +01:00
Megamouse 183380fe57 Qt: localize default pad names 2024-02-20 10:06:02 +01:00
kd-11 7abc5f3ead vk: Move driver properties to properties section from features section 2024-02-16 18:11:30 +03:00
Megamouse 1867f9aa1f Qt 6.6.2 2024-02-16 11:29:38 +01:00
Eladash f47c7e0ef1 PPU LLVM: Relax MSELF entry name constraints
These names are a hint
2024-02-16 10:42:57 +02:00
Eladash 36ab866c2c SPU Analyzer: forgive invalid code, use interpreter 2024-02-16 10:42:57 +02:00
Eladash f943deb2c3 PPU LLVM: Do not use possible duplicates in MSELF 2024-02-16 10:42:57 +02:00
Eladash 27ea25a999 Add debug info to ENOMEMs 2024-02-16 10:42:57 +02:00
Eladash 989b353fbd Fixup lv2_file::file_view::read() regression 2024-02-16 10:42:57 +02:00
Eladash c1607d14dc Add debug info to sys_fs_lseek 2024-02-16 10:42:57 +02:00
Eladash 85884d14cd PPU LLVM: Add more MSELF file checks
Do not crash on invalid files.
2024-02-16 10:42:57 +02:00
Eladash 08cf275bc8 Fix lv2_file::file_view::size() 2024-02-16 10:42:57 +02:00
Eladash 88ba3c47c2 ELF.h: Avoid using seek operations 2024-02-16 10:42:57 +02:00
Eladash 4aee44b1c0 sys_prx/overlay: Add some debugging steps 2024-02-16 10:42:57 +02:00
Megamouse e3d4c067df raw_mouse: adjust relative mouse position if the window size changed 2024-02-14 21:10:26 +01:00
kd-11 dfc626c99c rsx/vk: Fix WCB/Blit flush deadlock 2024-02-14 21:09:02 +03:00
kd-11 8786516c58 vk: Implement fast RSX release if there is no pending GPU work 2024-02-14 21:09:02 +03:00
Eladash 34e945128f Crypto\EDATA: Optimize decrypt_block to avoid an allocation 2024-02-14 15:11:52 +02:00
Eladash 7db6165b46 Fix lv2_file::file_view::read_at 2024-02-14 15:11:52 +02:00
Eladash 883f2e92ae EDATA: Add more logging 2024-02-14 15:11:52 +02:00
Eladash 3e8b003515 Add logging for cellFsSdataOpenByFd 2024-02-14 15:11:52 +02:00
Eladash ed66e9e9b9 Fix EDATADecrypter::ReadData 2024-02-14 15:11:52 +02:00
Eladash f87e11d16a Savestates/sys_fs: Save NPDRM decryption key 2024-02-14 15:11:52 +02:00
RipleyTom 5a64556fbf Add <optional> to RB3MidiDrums.h 2024-02-14 14:14:09 +02:00
Megamouse d71f4b33d7 raw_mouse: center cursors on init 2024-02-14 01:13:44 +01:00
Megamouse c91bc03532 sys_usbd: silence warning 2024-02-14 01:13:44 +01:00
Megamouse 348fab33a8 overlays: fix raw mouse debug overlay pos type 2024-02-14 01:13:44 +01:00
Megamouse 68f3df4975 input: implement raw_mouse_handler 2024-02-14 01:13:44 +01:00
Megamouse f6f8996aa9 overlays: use signed short for position to allow negative positions 2024-02-14 00:12:55 +01:00
nswarm 8533f962c6 Add limited support for midi drums w/ rockband 3 (#15054)
* add support for midi drums
* rb3drums: use dpad to disambiguate cymbal/drum hits instead of staggering.
* rb3drums: configurable min velocity and hihat up behavior
* rb3drums: configurable combos, combo duration, note overrides
* rb3drums: move config to separate file.
* rb3drums: apply stagger to double cymbal hits
* rb3drums: support midi CC note mapping
* rb3drums: add config to cmakelists. only load rb3drums config once.
* rb3drums: HihatWithPedalUp defaults to yellow cymbal instead of blue
2024-02-13 23:08:22 +01:00
RipleyTom af33c0c69f Revert FM(a*re_accurate) shortcut to relaxed 2024-02-13 20:08:03 +02:00
RipleyTom 50b1402d66 Fixes full fm(a, re_accurate) pattern 2024-02-13 11:37:20 +02:00
RipleyTom cfd5c62386 Improve re_accurate 2024-02-13 11:37:20 +02:00
RipleyTom 569f72c360 Disable updates for local build 2024-02-12 19:02:52 +01:00
kd-11 df74d49f72 vk: Silence compiler warning 2024-02-12 12:28:16 +03:00
xujibbs eac31dfd03 Update skylander_dialog.cpp
Make strings translatable
2024-02-12 09:54:07 +02:00
Megamouse 0b1a7ee346 overlays: localize sendmessage confirmation 2024-02-12 00:04:46 +01:00
Eladash 77ba2b40e7 Thread.cpp: Explicitly state difference type in thread_ctrl::wait_for_accurate 2024-02-11 23:01:40 +02:00
Eladash 94239f5526 Fixup HW thread switch delay condition for performance 2024-02-11 23:01:40 +02:00
Elad.Ash 148edc005a Improve cpu_flag::yield handling 2024-02-11 20:09:01 +02:00
Elad Ashkenazi ec59f4d37e PPU/LV2: Implement HW threads switching delay when signaling higher priority threads
In real PS3 (it seems), when a thread with a higher priority than the caller is signaled and that there is available space on the running queue for the other hardware thread to start It prioritizes signaled thread caller's hardware thread switches instantly to the new thread code while signaling to the other hardware thread to execute the caller's code.
Resulting in a delay to the caller after such thread is signaled
2024-02-11 20:09:01 +02:00
kd-11 2c03878c3b vk: Don't panic on encountering the exotic mesa drivers 2024-02-11 17:21:56 +03:00
kd-11 c8c845a659 vk: Emit a strong warning if dozen is detected as the currently loaded driver.
- In most cases, the user does not intend to actually use dozen and has installed a compatibility pack by mistake.
2024-02-11 17:21:56 +03:00
kd-11 a54f1970f1 vk: Make more features "optional"
- This allows some non-conformant drivers to at least finish swapchain creation.
2024-02-11 17:21:56 +03:00
kd-11 7f602937a3 vk: Improve driver detection for dozen and lavapipe 2024-02-11 17:21:56 +03:00
kd-11 c2631c914d rsx: Lower some performance warnings to trace to reduce log spam 2024-02-11 14:24:33 +01:00
kd-11 c17014a055 Buildfiles improvements 2024-02-11 14:24:33 +01:00
kd-11 c572226b0d Stop including x86 intrinsics in other architectures 2024-02-11 14:24:33 +01:00
kd-11 6718b0683e Don't include x64 options when building arm64 2024-02-11 14:24:33 +01:00
RipleyTom 3735df4f53 Update CMake requirements in BUILDING.md 2024-02-11 10:09:24 +02:00
kd-11 4746ef09cd Fix linux build 2024-02-10 15:15:02 +03:00
kd-11 ed93bbd16d vk: Improve compute->compute barrier before detiling 2024-02-10 15:15:02 +03:00
kd-11 041daab068 vk: Tighten some memory bounds checks 2024-02-10 15:15:02 +03:00
kd-11 e5c831a800 rsx/vk: Fix GPU tile encoding
- Decoding also needs some love, but currently WIP
2024-02-10 15:15:02 +03:00
kd-11 b8ed3eb824 rsx: Fix cpu detiler 2024-02-10 15:15:02 +03:00
kd-11 95f9f04612 rsx: Provide tile alignment utility (align to 64 * pitch blocks) 2024-02-10 15:15:02 +03:00
kd-11 823c72bf27 rsx/vk: Redefine the (de)tiler config interface 2024-02-10 15:15:02 +03:00
RipleyTom 9b387485b5 Avoid modifying any memory on SYS_NET_EINTR cases 2024-02-09 18:07:18 +02:00
RipleyTom 56e27bdd49 Restrict file creation in /dev_hdd0 2024-02-09 16:13:46 +02:00
Elad.Ash 30e8c3e951 SPU LLVM: Allow swapped FMA and multiplications args in match context 2024-02-07 13:45:29 +02:00
Megamouse 96b7e4c67f Update libpng to 1.6.42 2024-02-06 22:13:22 +01:00
RipleyTom 65d93c97ea Add various SPU patterns 2024-02-06 22:08:44 +02:00
RipleyTom a92b8acba7 Accurate FI 2024-02-06 22:08:44 +02:00
Megamouse 85f4c38b4e Update submodules
- Updates SDL to 2.30.0
- Updates curl to 8.6.0
- Updates libusb to 1.0.27
- Updates zlib to 1.3.1
- Updates FAudio to 24.02
2024-02-05 23:47:38 +01:00
Eladash 40c51a1f05 Crypto/unedat.cpp: remove extract_all_data 2024-02-05 21:56:04 +02:00
Eladash a6c2e995af Crypto/PKG installer: Fix potential RAM shortage when extracing EDAT files 2024-02-05 21:56:04 +02:00
Eladash 596e671973 Crypto/sys_fs: Fix potential RAM shortage in NPDRM decryption
Previous code was structured very naively: if 8GB read is requested, it would allocate 8GB of memory. Without considering recycling memory for each block.
2024-02-05 21:56:04 +02:00
Eladash d38b2eb8ef Crypto/sys_fs: Remove some seek operations 2024-02-05 21:56:04 +02:00
RipleyTom bb9444e19a Add sceNpPlus to registered modules 2024-02-05 15:28:38 +01:00
RipleyTom 26d406fec3 RPCN 1.1 2024-02-05 09:44:29 +01:00
Megamouse dda0b8af45 cellGem: Allow to use multiple controllers as fake PS-Move
- Allows to use the last 4 ports/players as PS Move in fake mode
- Should in theory react to re/disconnected controllers
- Should allow to use player 1-3 as normal controller simultaneously
2024-02-03 21:47:40 +01:00
Megamouse d5ce4e0f6b sceNp: fix atomic type 2024-02-03 17:59:19 +01:00
Megamouse e5cfe710fa sceNp: correct type for data attachment 2024-02-03 17:59:19 +01:00
Megamouse 2a0e2ce0a2 sceNp: don't preserve messages in sceNpBasicRecvMessageAttachment 2024-02-03 17:59:19 +01:00
Megamouse ef56433684 overlays: ask for user confirmation before sending an invite
This shows subject and body as well
2024-02-03 17:59:19 +01:00
Megamouse 8bc3a39586 sceNp: implement sceNpBasicAbortGui 2024-02-03 17:59:19 +01:00
Megamouse e13a671f86 sceNp: Implement sceNpBasicRecvMessageAttachment 2024-02-03 17:59:19 +01:00
Megamouse 48f82c75c1 np: fix signed/unsigned warning
who the heck thought returning signed on a counter makes sense...
2024-02-03 17:59:19 +01:00
Megamouse a5955657c5 overlays: add subject and body to recvmessage dialog 2024-02-03 09:45:55 +01:00
RipleyTom 319657e815 Review fixes 2024-02-03 08:45:29 +01:00
RipleyTom c589001dff Add player history 2024-02-03 08:45:29 +01:00
Megamouse c04cd2228e Qt: Show NP ID in rpcn dialogs 2024-02-02 19:05:56 +01:00
Megamouse cba51b4a5e rsx/glsl: use const for left/right 2024-02-02 10:07:23 +01:00
kd-11 8962ddca01 rsx/glsl: Fix typo 2024-02-02 10:07:23 +01:00
kd-11 1808a4373b rsx: Improvements to the video out passes
- Use shared VS for vulkan as well as GL
- Simplify binding model and give control back to the cpp side
2024-02-02 10:07:23 +01:00
kd-11 bb22afb7f1 gl: Vectorize GL_TEMP_IMAGE_SLOT expression 2024-02-02 10:07:23 +01:00
kd-11 ce571cb6ca vk: Allow indexed lookup for sampler and IA binding points in overlay passes 2024-02-02 10:07:23 +01:00
Megamouse ac9afbfede glsl: use fragCoord to decide interlacing 2024-02-02 10:07:23 +01:00
Megamouse 4e8130bd99 glsl: use textureSize instead of height 2024-02-02 10:07:23 +01:00
Megamouse 00c9321b1d glsl: use const in for params 2024-02-02 10:07:23 +01:00
Megamouse 8e8b582747 glsl: move anaglpyh to separate functions 2024-02-02 10:07:23 +01:00
Megamouse 6f2e843193 vk/gl: add amber-blue anaglyph (ColorCode 3D) 2024-02-02 10:07:23 +01:00
Megamouse 7d9460a560 vk/gl: cleanup formatting in glsl, move some common magic numbers to variables 2024-02-02 10:07:23 +01:00
Megamouse 32f2b14429 vk/gl: add interlaced 3D mode 2024-02-02 10:07:23 +01:00
Megamouse 651f8512eb vk/gl: add more anaglyph 3D modes 2024-02-02 10:07:23 +01:00
Megamouse 3dac7d16e7 vk/gl: unite video_out_calibration_pass fragment shader to new glsl 2024-02-02 10:07:23 +01:00
Megamouse 240f80b467 gl: add missing else in calibration pass fragment shader 2024-02-02 10:07:23 +01:00
Megamouse 17b5a36b59 Add update_helper.sh to VS filters 2024-02-02 10:07:23 +01:00
Megamouse ea326a5f29 overlays: clean up includes 2024-01-31 16:33:29 +01:00
Megamouse c271415328 sceNp: decrease some log levels from todo to warning 2024-01-31 16:33:29 +01:00
Megamouse f28c7d029c overlays: use timestamp for fade animations
Fixes jojo when using sceNp dialogs
2024-01-31 16:33:29 +01:00
Megamouse d7f317fa58 Add UI to sceNpBasicSendMessageAttachment and sceNpBasicAddFriend 2024-01-31 16:33:29 +01:00
Megamouse 3f2c34edd2 sceNp: silence some errors 2024-01-31 16:33:29 +01:00
Megamouse 566a8ac5ac scnNp: add ppu wait before opening blocking dialogs 2024-01-31 16:33:29 +01:00
Megamouse 71b5bc4fe6 sceNp: add more error checks 2024-01-31 16:33:29 +01:00
Megamouse a427783bac overlays: remove separators from send/recv dialogs 2024-01-31 16:33:29 +01:00
Megamouse 23dc6a44f6 overlays: implement native sendmessage dialog 2024-01-31 16:33:29 +01:00
Megamouse 9ef5a01de4 overlays: implement native recvmessage dialog 2024-01-31 16:33:29 +01:00
Megamouse cdfe3ee7c8 Name some threads 2024-01-31 16:33:29 +01:00
kd-11 c3c73c7e24 rsx: Allow native UI render even when we have pending draw calls if FIFO queue is empty. 2024-01-30 16:36:58 +03:00
RipleyTom af8d308a69 Terminate RPCN connection cleanly 2024-01-29 13:01:09 +01:00
Florin9doi a7da245656 Don't search games when the dialog is cancelled 2024-01-28 13:18:35 +01:00
RipleyTom e9713f9635 Fix sceNpCommerce2 init 2024-01-28 10:52:26 +01:00
Megamouse 3dbde04d18 sceNpCommerce: add init checks 2024-01-27 08:31:16 +01:00
Megamouse 1611588682 sceNpCommerce2: add some error checks 2024-01-27 08:31:16 +01:00
RipleyTom 93c72822a3 Fix Apple clang 2024-01-26 17:59:53 +01:00
RipleyTom 6f5bcf12c6 Arm version of trigger_write_page_fault 2024-01-26 09:32:15 +02:00
RipleyTom 07dba02897 FreeBSD workaround for libusb 2024-01-26 02:51:41 +01:00
RipleyTom db685879af Return no file to TSS apis 2024-01-26 02:51:41 +01:00
RipleyTom 94e8d6fe13 Mini sceNpCommerce2Init fix 2024-01-25 22:53:21 +01:00
Megamouse 0d1fbfb755 VFS: Fix some potential .back() segfaults 2024-01-25 17:03:58 +01:00
Megamouse 10c52cf569 sys_usbd: add libusb log callback 2024-01-25 17:03:58 +01:00
RipleyTom 7661df0847 Enable Discord presence on Linux 2024-01-25 09:49:17 +01:00
pastalian e8ad6ec673 Add missing headers (#15075)
Some systems must explicitly include these headers.
2024-01-24 17:22:37 +01:00
Steveice10 3ef48cbdd5 rpcs3qt: Add macOS support to the updater. 2024-01-24 09:44:56 +01:00
Megamouse 5fe36872c5 System: don't consider games as registered if they were already in games.yml
Also, show message if nothing was added
2024-01-24 08:18:57 +01:00
RipleyTom d33955c290 Asmjit FI 2024-01-23 12:24:38 +02:00
RipleyTom 606a60e901 Accurate frest and frsqest 2024-01-23 12:24:38 +02:00
Megamouse 93f5154429 Qt: trim whitespace from textinput before writing to config 2024-01-22 22:25:06 +01:00
Megamouse a6e046c6c3 update submodules 2024-01-22 22:25:06 +01:00
kd-11 8eae8cb86c rsx: Do not emit rounding code when not needed 2024-01-21 12:30:37 +03:00
kd-11 abe5013f1d rsx: Fix compiling of mixed-precision shaders 2024-01-21 12:30:37 +03:00
kd-11 ca7de4bcb1 rsx: Aesthetic changes 2024-01-21 12:30:37 +03:00
kd-11 9a9b5860df rsx: Forcefully disable writes to channels disabled on host
- Some formats may have dummy channels on host. Never write to them!
- This means that XRGB formats correctly only write 24 bits, not 32.
2024-01-21 12:30:37 +03:00
kd-11 0971636c07 rsx: More pipeine refactoring 2024-01-21 12:30:37 +03:00
Megamouse 50fcec63e0 fs: fix get_executable_dir 2024-01-21 00:11:16 +01:00
Megamouse 8a87dc63b1 Emu: Add more info to BlockingCallFromMainThread 2024-01-21 00:11:16 +01:00
Megamouse efea3aa385 Qt: revert accidental settings_dialog check-in 2024-01-20 21:59:02 +01:00
Megamouse 86bab5b7c3 cellImeJp: fix character deletion after change to cursor 2024-01-20 21:59:02 +01:00
Megamouse 675ed82c0b cellImeJp: fix deadlock 2024-01-20 21:59:02 +01:00
Megamouse 58dd0198dd cellImeJp: add candidate list functions 2024-01-20 21:59:02 +01:00
Megamouse 16f833a516 cellImeJp: add cursor 2024-01-20 21:59:02 +01:00
Megamouse 0392830950 cellImeJp: fix focus area 2024-01-20 21:59:02 +01:00
Megamouse 04efc6b4a4 cellImeJp: static functions to silence annoying VS 2024-01-20 21:59:02 +01:00
Megamouse 8edd7d54cf fs: fix warning. fix size argument in report_fatal_error 2024-01-20 21:59:02 +01:00
Eladash f19744ae88 Savestates: Fix restart when suspend mode is off
Add a new menu button for explicit exit (mostly for debug purposes)
2024-01-20 22:15:07 +02:00
Eladash 01ee119c59 Savestates: Dont patch memory on load 2024-01-20 22:15:07 +02:00
Eladash 4cd60aca22 Savestates: Add some logging for sys_overlay 2024-01-20 22:15:07 +02:00
Eladash 81ba791ee7 Simplify fatal dialog's error a bit 2024-01-20 22:15:07 +02:00
Eladash c7a94a80df Savestates/net: fix P2P socket data saving 2024-01-20 22:15:07 +02:00
Eladash c509226bab Firmware installer: Early protection against disk space shortage complications 2024-01-20 22:15:07 +02:00
Eladash 312b35051d sys_fs: Aggregate safe file reads (optimization) 2024-01-20 22:15:07 +02:00
Eladash e401d85af7 progress dialog: minor fix 2024-01-20 22:15:07 +02:00
Eladash e4c9af176b fixup hdd1 cache 2024-01-20 22:15:07 +02:00
Steveice10 9c354ee269 Utilities: Add support for portable user directory. (#15064) 2024-01-20 10:04:25 +02:00
kd-11 96d880839a rsx: Properly propagate surface properties on surface reuse. 2024-01-19 12:34:31 +03:00
Megamouse e23db7efbd Mac: Update MoltenVk to 1.2.7
Remove deprecated extension VK_MVK_moltenvk
2024-01-16 22:52:57 +01:00
Megamouse fd540f1820 Mac: silence deprecation warning 2024-01-16 22:52:57 +01:00
RipleyTom 7d55a85fa6 Replaces page fault triggers with assembly 2024-01-16 12:04:47 +02:00
Megamouse fa7ef870dd sceNp: disable Canonicalize functions for RPCN 2024-01-14 22:55:03 +01:00
Megamouse ecacb874e4 sceNpCommerce: more error checks 2024-01-14 22:55:03 +01:00
Megamouse 0b2e0a1b28 sceNpCommerce: add error constants 2024-01-14 22:55:03 +01:00
Megamouse a08d60fbbe sceNpFriendlist: more checks 2024-01-14 22:55:03 +01:00
Megamouse ef6041c14f sceNpMatching: simplify linked list for loops 2024-01-14 22:55:03 +01:00
Megamouse 25954758d7 sceNpMatching: add error checks 2024-01-14 22:55:03 +01:00
oltolm 0ae1578dce split JIT.cpp and SPURecompiler.cpp 2024-01-14 17:21:39 +01:00
oltolm 2039b85be3 prepare split 2024-01-14 17:21:39 +01:00
oltolm 8eae73dd02 add comments where to split 2024-01-14 17:21:39 +01:00
RipleyTom fe9a24a1b8 RPCN 1.0 (#15045) 2024-01-14 12:36:23 +01:00
Megamouse 3d974eed03 fs: move buf from stack to heap to silence VS warning 2024-01-14 06:40:35 +01:00
Megamouse 329b58c8cd fs: remove duplicate to_utf8 function 2024-01-14 06:40:35 +01:00
Megamouse 2d82e3ef9a Qt: use fs::get_temp_dir during updates
GetTempPathW was falsely using size in bytes instead of string length.
2024-01-14 06:40:35 +01:00
Megamouse faaf644331 Qt/input: show all mmjoy devices with connection in dropdown
This fixes weird issues with disconnected pads while also showing the status.
2024-01-14 02:50:45 +01:00
Megamouse d7aedb439e Qt/Input: Keep configured device name in config when no pad is connected 2024-01-14 02:50:45 +01:00
Megamouse 9c11840e40 input: implement dynamic mmjoy device reconnection 2024-01-14 02:50:45 +01:00
RipleyTom 4c36b80300 Misc NP fixes 2024-01-13 15:44:28 +01:00
Megamouse f7fa5aab70 media_utils: fix segfault when stopping a recording 2024-01-12 19:53:20 +01:00
Megamouse 17aeefe1b0 cellFont: some stubs 2024-01-11 22:35:00 +01:00
Eladash 825ae5b8aa Ensure HDD1 is never damaged or corrupted due to unexpected RPCS3/game termination 2024-01-11 20:24:53 +02:00
Megamouse 3513f6d83c cellMouse: silence some log spam 2024-01-10 22:34:13 +01:00
Megamouse 4ad4badcfe audio_decoder: fix more memleaks and dangling files 2024-01-10 22:34:13 +01:00
Megamouse b67837c0ef cellMusicDecode: fix random pop at the end of a stream
Observed in SSX, which seems to ignore the readSize sometimes
2024-01-10 22:34:13 +01:00
Megamouse b5f3f910f6 cellSearch: fix vfs music and video paths 2024-01-10 22:34:13 +01:00
Megamouse b0a7448394 get_media_info: improve logging 2024-01-10 22:34:13 +01:00
Megamouse bed7763a3b audio_decoder: ignore first invalid data error 2024-01-10 22:34:13 +01:00
Megamouse 572c075a4b audio_decoder: improve logging 2024-01-10 22:34:13 +01:00
Megamouse bad7756af2 audio_decoder: properly free packets 2024-01-10 22:34:13 +01:00
Megamouse 45c89030ac audio_decoder: check for failed av_packet_alloc 2024-01-10 22:34:13 +01:00
Megamouse 7aad4f4253 overlays: decrease log level 2024-01-10 22:34:13 +01:00
Megamouse 9e9385a877 cellVideoExport: export movies to /video/ instead of /movie 2024-01-10 22:34:13 +01:00
Megamouse 431d69ac87 Windows: remove QtCore5Compat dependency 2024-01-10 22:34:13 +01:00
Megamouse 3be24f1e6f Update FAudio to 24.01 2024-01-10 22:34:13 +01:00
Megamouse c45deb3f87 sdl: log version 2024-01-10 22:34:13 +01:00
brian218 213674511e sys_ss: Corrected sys_ss_update_manager(0x6011) version data format 2024-01-10 12:37:11 +01:00
brian218 6548e3f7d0 sys_fs: Improved get_device_root() path identifying security 2024-01-10 12:37:11 +01:00
brian218 a269ae7e30 sys_fs: Prevented duplicate device mounting 2024-01-10 12:37:11 +01:00
brian218 862295d9f3 sys_fs: Fixed sys_fs_unlink()'s failing to delete files in dev_usbXXX
sys_fs: Fixed get_mp() up for dev_usbXXX
2024-01-10 12:37:11 +01:00
RipleyTom 61e130e68c Honk if you knew memset(nullptr, 0, 0) was UB 2024-01-09 23:06:23 +01:00
RipleyTom 236e32fb3d Fix weird cmp in np_handler.cpp 2024-01-09 23:06:23 +01:00
RipleyTom 067ea68979 Fix games passing invalid npids 2024-01-09 23:06:23 +01:00
Megamouse 7504503d5f sceNp: don't return error if assignedReqId is null 2024-01-09 02:58:00 +01:00
Megamouse 108d0d49ec sceNp: add missing roomPassword check 2024-01-09 02:58:00 +01:00
Megamouse 2c424a0911 sceNp: add missing withPassword check 2024-01-09 02:58:00 +01:00
Megamouse ffe1b287a8 sceNp: add missing check for roomSlotInfo 2024-01-09 02:58:00 +01:00
RipleyTom 485fca34b0 Misc NP fixes 2024-01-08 14:03:15 +01:00
RipleyTom 0b984e9a23 Add -Werror=implicit-fallthrough to cmake build 2024-01-07 17:29:43 +01:00
RipleyTom 74e084c893 Improve sceNpEula 2024-01-07 14:50:45 +01:00
RipleyTom 47ae192cf8 Impl sceNpBasicSendMessage 2024-01-07 13:36:27 +01:00
RipleyTom 80b7fd5f3f Check room event callback has been set before calling it 2024-01-05 22:34:52 +01:00
RipleyTom 0227b16d06 Fix sceNpBasicSetPresence when data is nullptr and size is 0 2024-01-05 22:34:52 +01:00
kd-11 2a1af17f67 vk: Force GPU texture processing if the input is already GPU-resident (Tiled RCB read) 2024-01-05 16:29:53 +03:00
RipleyTom b6e9746198 RPCN 0.9 (#15002) 2024-01-05 09:43:26 +01:00
kd-11 bc141831f7 gl: Implement display output format correction 2024-01-04 13:03:32 +03:00
kd-11 acd3fd0c3e vk: Implement display output format correction 2024-01-04 13:03:32 +03:00
kd-11 2369266b8a rsx: Add an option to force hardware MSAA resolve 2024-01-03 19:32:45 +03:00
495 changed files with 33692 additions and 17139 deletions
+1
View File
@@ -43,6 +43,7 @@ cmake .. \
-DUSE_SYSTEM_CURL=ON \
-DUSE_SDL=ON \
-DUSE_SYSTEM_FFMPEG=OFF \
-DUSE_DISCORD_RPC=ON \
-DOpenGL_GL_PREFERENCE=LEGACY \
-DLLVM_DIR=/opt/llvm/lib/cmake/llvm \
-DSTATIC_LINK_LLVM=ON \
+5 -3
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)"
@@ -13,8 +15,8 @@ arch -x86_64 /usr/local/bin/brew reinstall -f --build-from-source gnutls freetyp
arch -x86_64 /usr/local/bin/brew install llvm@16 glew cmake sdl2 vulkan-headers coreutils
arch -x86_64 /usr/local/bin/brew link -f llvm@16 ffmpeg@5
# moltenvk based on commit for 1.2.6 release
wget https://raw.githubusercontent.com/Homebrew/homebrew-core/4ac0cfaca4c2505abe2fcbcc0ce5816572103a6c/Formula/m/molten-vk.rb
# moltenvk based on commit for 1.2.7 release
wget https://raw.githubusercontent.com/Homebrew/homebrew-core/05a8770c483cfddf5b077667a392d846bc2ad719/Formula/m/molten-vk.rb
arch -x86_64 /usr/local/bin/brew install -f --overwrite ./molten-vk.rb
#export MACOSX_DEPLOYMENT_TARGET=12.0
export CXX=clang++
+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
-2
View File
@@ -19,7 +19,6 @@ QT_DECL_URL="${QT_HOST}${QT_PREFIX}${QT_PREFIX_2}qtdeclarative${QT_SUFFIX}"
QT_TOOL_URL="${QT_HOST}${QT_PREFIX}${QT_PREFIX_2}qttools${QT_SUFFIX}"
QT_MM_URL="${QT_HOST}${QT_PREFIX}addons.qtmultimedia.${QT_PREFIX_2}qtmultimedia${QT_SUFFIX}"
QT_SVG_URL="${QT_HOST}${QT_PREFIX}${QT_PREFIX_2}qtsvg${QT_SUFFIX}"
QT_5CMP_URL="${QT_HOST}${QT_PREFIX}qt5compat.${QT_PREFIX_2}qt5compat${QT_SUFFIX}"
LLVMLIBS_URL='https://github.com/RPCS3/llvm-mirror/releases/download/custom-build-win-16.0.1/llvmlibs_mt.7z'
GLSLANG_URL='https://github.com/RPCS3/glslang/releases/latest/download/glslanglibs_mt.7z'
VULKAN_SDK_URL="https://www.dropbox.com/scl/fi/sjjh0fc4ld281pjbl2xzu/VulkanSDK-1.3.268.0-Installer.exe?rlkey=f6wzc0lvms5vwkt2z3qabfv9d&dl=1"
@@ -30,7 +29,6 @@ DEP_URLS=" \
$QT_TOOL_URL \
$QT_MM_URL \
$QT_SVG_URL \
$QT_5CMP_URL \
$LLVMLIBS_URL \
$GLSLANG_URL \
$VULKAN_SDK_URL"
+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.1'
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: '202311210527'
# 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.5
# 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
+1 -1
View File
@@ -1,5 +1,5 @@
# 7z sdk
if(WIN32)
if(WIN32 OR APPLE)
add_library(3rdparty_7z STATIC EXCLUDE_FROM_ALL
src/7zAlloc.c
src/7zArcIn.c
+1 -1
View File
@@ -4,7 +4,7 @@ include(ExternalProject)
ExternalProject_Add(moltenvk
GIT_REPOSITORY https://github.com/KhronosGroup/MoltenVK.git
GIT_TAG 9e4ee9e
GIT_TAG 66f6ff1
BUILD_IN_SOURCE 1
SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/MoltenVK
CONFIGURE_COMMAND "${CMAKE_CURRENT_SOURCE_DIR}/MoltenVK/fetchDependencies" --macos
File diff suppressed because it is too large Load Diff
Binary file not shown.
+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
View File
@@ -1,6 +1,8 @@
# DiscordRPC
add_library(3rdparty_discordRPC INTERFACE)
check_cxx_compiler_flag("-msse -msse2 -mcx16" COMPILER_X86)
# We don't want Discord Rich Presence on the BSDs and other OSes
if (USE_DISCORD_RPC AND (WIN32 OR CMAKE_SYSTEM MATCHES "Linux" OR APPLE) AND COMPILER_X86)
if (WIN32 AND NOT MSVC)
+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 -2
View File
@@ -4,11 +4,14 @@ 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")
set(PNG_BUILD_ZLIB ON CACHE BOOL "ZLIB is already build or package is found")
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}")
target_link_libraries(png_static 3rdparty::zlib)
set(LIBPNG_TARGET png_static PARENT_SCOPE)
else()
+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" />
+21 -1
View File
@@ -11,6 +11,12 @@
</ProjectConfiguration>
</ItemGroup>
<ItemGroup>
<ClCompile Include="SDL\src\joystick\hidapi\SDL_hidapi_steamdeck.c" />
<ClCompile Include="SDL\src\joystick\SDL_steam_virtual_gamepad.c" />
<ClCompile Include="SDL\src\joystick\steam\SDL_steamcontroller.c" />
<ClCompile Include="SDL\src\video\yuv2rgb\yuv_rgb_lsx.c" />
<ClCompile Include="SDL\src\video\yuv2rgb\yuv_rgb_sse.c" />
<ClCompile Include="SDL\src\video\yuv2rgb\yuv_rgb_std.c" />
<ClInclude Include="SDL\include\begin_code.h" />
<ClInclude Include="SDL\include\close_code.h" />
<ClInclude Include="SDL\include\SDL.h" />
@@ -133,7 +139,9 @@
<ClInclude Include="SDL\src\joystick\hidapi\SDL_hidapi_rumble.h" />
<ClInclude Include="SDL\src\joystick\SDL_gamecontrollerdb.h" />
<ClInclude Include="SDL\src\joystick\SDL_joystick_c.h" />
<ClInclude Include="SDL\src\joystick\SDL_steam_virtual_gamepad.h" />
<ClInclude Include="SDL\src\joystick\SDL_sysjoystick.h" />
<ClInclude Include="SDL\src\joystick\steam\SDL_steamcontroller.h" />
<ClInclude Include="SDL\src\joystick\usb_ids.h" />
<ClInclude Include="SDL\src\joystick\virtual\SDL_virtualjoystick_c.h" />
<ClInclude Include="SDL\src\joystick\windows\SDL_dinputjoystick_c.h" />
@@ -188,6 +196,13 @@
<ClInclude Include="SDL\src\video\dummy\SDL_nullevents_c.h" />
<ClInclude Include="SDL\src\video\dummy\SDL_nullframebuffer_c.h" />
<ClInclude Include="SDL\src\video\dummy\SDL_nullvideo.h" />
<ClInclude Include="SDL\src\video\khronos\vk_video\vulkan_video_codecs_common.h" />
<ClInclude Include="SDL\src\video\khronos\vk_video\vulkan_video_codec_h264std.h" />
<ClInclude Include="SDL\src\video\khronos\vk_video\vulkan_video_codec_h264std_decode.h" />
<ClInclude Include="SDL\src\video\khronos\vk_video\vulkan_video_codec_h264std_encode.h" />
<ClInclude Include="SDL\src\video\khronos\vk_video\vulkan_video_codec_h265std.h" />
<ClInclude Include="SDL\src\video\khronos\vk_video\vulkan_video_codec_h265std_decode.h" />
<ClInclude Include="SDL\src\video\khronos\vk_video\vulkan_video_codec_h265std_encode.h" />
<ClInclude Include="SDL\src\video\khronos\vulkan\vk_icd.h" />
<ClInclude Include="SDL\src\video\khronos\vulkan\vk_layer.h" />
<ClInclude Include="SDL\src\video\khronos\vulkan\vk_platform.h" />
@@ -238,7 +253,13 @@
<ClInclude Include="SDL\src\video\windows\SDL_windowswindow.h" />
<ClInclude Include="SDL\src\video\windows\wmmsg.h" />
<ClInclude Include="SDL\src\video\yuv2rgb\yuv_rgb.h" />
<ClInclude Include="SDL\src\video\yuv2rgb\yuv_rgb_common.h" />
<ClInclude Include="SDL\src\video\yuv2rgb\yuv_rgb_internal.h" />
<ClInclude Include="SDL\src\video\yuv2rgb\yuv_rgb_lsx.h" />
<ClInclude Include="SDL\src\video\yuv2rgb\yuv_rgb_lsx_func.h" />
<ClInclude Include="SDL\src\video\yuv2rgb\yuv_rgb_sse.h" />
<ClInclude Include="SDL\src\video\yuv2rgb\yuv_rgb_sse_func.h" />
<ClInclude Include="SDL\src\video\yuv2rgb\yuv_rgb_std.h" />
<ClInclude Include="SDL\src\video\yuv2rgb\yuv_rgb_std_func.h" />
</ItemGroup>
<ItemGroup>
@@ -418,7 +439,6 @@
<ClCompile Include="SDL\src\video\windows\SDL_windowsvideo.c" />
<ClCompile Include="SDL\src\video\windows\SDL_windowsvulkan.c" />
<ClCompile Include="SDL\src\video\windows\SDL_windowswindow.c" />
<ClCompile Include="SDL\src\video\yuv2rgb\yuv_rgb.c" />
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{8DC244EE-A0BD-4038-BAF7-CFAFA5EB2BAA}</ProjectGuid>
+21 -1
View File
@@ -178,10 +178,15 @@
<ClCompile Include="SDL\src\video\windows\SDL_windowsvideo.c" />
<ClCompile Include="SDL\src\video\windows\SDL_windowsvulkan.c" />
<ClCompile Include="SDL\src\video\windows\SDL_windowswindow.c" />
<ClCompile Include="SDL\src\video\yuv2rgb\yuv_rgb.c" />
<ClCompile Include="SDL\src\joystick\hidapi\SDL_hidapi_ps3.c" />
<ClCompile Include="SDL\src\joystick\hidapi\SDL_hidapi_steam.c" />
<ClCompile Include="SDL\src\joystick\hidapi\SDL_hidapi_wii.c" />
<ClCompile Include="SDL\src\joystick\steam\SDL_steamcontroller.c" />
<ClCompile Include="SDL\src\video\yuv2rgb\yuv_rgb_lsx.c" />
<ClCompile Include="SDL\src\video\yuv2rgb\yuv_rgb_sse.c" />
<ClCompile Include="SDL\src\video\yuv2rgb\yuv_rgb_std.c" />
<ClCompile Include="SDL\src\joystick\hidapi\SDL_hidapi_steamdeck.c" />
<ClCompile Include="SDL\src\joystick\SDL_steam_virtual_gamepad.c" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="SDL\include\begin_code.h" />
@@ -409,5 +414,20 @@
<ClInclude Include="SDL\src\video\yuv2rgb\yuv_rgb_sse_func.h" />
<ClInclude Include="SDL\src\video\yuv2rgb\yuv_rgb_std_func.h" />
<ClInclude Include="SDL\src\joystick\hidapi\SDL_hidapi_nintendo.h" />
<ClInclude Include="SDL\src\video\yuv2rgb\yuv_rgb_common.h" />
<ClInclude Include="SDL\src\video\yuv2rgb\yuv_rgb_internal.h" />
<ClInclude Include="SDL\src\video\yuv2rgb\yuv_rgb_lsx.h" />
<ClInclude Include="SDL\src\video\yuv2rgb\yuv_rgb_lsx_func.h" />
<ClInclude Include="SDL\src\video\yuv2rgb\yuv_rgb_sse.h" />
<ClInclude Include="SDL\src\video\yuv2rgb\yuv_rgb_std.h" />
<ClInclude Include="SDL\src\joystick\steam\SDL_steamcontroller.h" />
<ClInclude Include="SDL\src\video\khronos\vk_video\vulkan_video_codec_h264std.h" />
<ClInclude Include="SDL\src\video\khronos\vk_video\vulkan_video_codec_h264std_decode.h" />
<ClInclude Include="SDL\src\video\khronos\vk_video\vulkan_video_codec_h264std_encode.h" />
<ClInclude Include="SDL\src\video\khronos\vk_video\vulkan_video_codec_h265std.h" />
<ClInclude Include="SDL\src\video\khronos\vk_video\vulkan_video_codec_h265std_decode.h" />
<ClInclude Include="SDL\src\video\khronos\vk_video\vulkan_video_codec_h265std_encode.h" />
<ClInclude Include="SDL\src\video\khronos\vk_video\vulkan_video_codecs_common.h" />
<ClInclude Include="SDL\src\joystick\SDL_steam_virtual_gamepad.h" />
</ItemGroup>
</Project>
+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>
-2
View File
@@ -27,10 +27,8 @@
#include <sys/un.h>
#include <arpa/inet.h>
#include <poll.h>
#if defined(__DragonFly__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__APPLE__)
#include <unistd.h>
#endif
#endif
#ifdef _WIN32
constexpr SOCKET invalid_socket = INVALID_SOCKET;
+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
+6 -3
View File
@@ -1,10 +1,9 @@
if (USE_SYSTEM_ZLIB)
message(STATUS "RPCS3: Using system ZLIB")
find_package(ZLIB QUIET)
find_package(ZLIB QUIET REQUIRED)
add_library(3rdparty_zlib INTERFACE)
target_link_libraries(3rdparty_zlib INTERFACE ${ZLIB_LIBRARIES})
target_include_directories(3rdparty_zlib INTERFACE ${ZLIB_INCLUDE_DIRS})
target_link_libraries(3rdparty_zlib INTERFACE ZLIB::ZLIB)
target_compile_definitions(3rdparty_zlib INTERFACE -DZLIB_CONST=1)
else()
message(STATUS "RPCS3: Using builtin ZLIB")
@@ -15,4 +14,8 @@ else()
target_link_libraries(3rdparty_zlib INTERFACE zlibstatic)
target_include_directories(3rdparty_zlib INTERFACE zlib ${CMAKE_CURRENT_BINARY_DIR}/zlib)
target_compile_definitions(3rdparty_zlib INTERFACE -DZLIB_CONST=1)
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>
+11 -9
View File
@@ -5,23 +5,25 @@ 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.16.9+](https://www.cmake.org/download/) (add to PATH)
* [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.1](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.1\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
These are the essentials tools to build RPCS3 on Linux. Some of them can be installed through your favorite package manager.
* Clang 12+ or GCC 11+
* [CMake 3.16.9+](https://www.cmake.org/download/)
* [Qt 6.6.1](https://www.qt.io/download-qt-installer)
* [CMake 3.28.0+](https://www.cmake.org/download/)
* [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.1\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>;
+186 -36
View File
@@ -1,12 +1,14 @@
#include "File.h"
#include "mutex.h"
#include "StrFmt.h"
#include "StrUtil.h"
#include "Crypto/sha1.h"
#include <unordered_map>
#include <algorithm>
#include <cstring>
#include <map>
#include <iostream>
#include "util/asm.hpp"
#include "util/coro.hpp"
@@ -49,23 +51,6 @@ static std::unique_ptr<wchar_t[]> to_wchar(const std::string& source)
return buffer;
}
static void to_utf8(std::string& out, const wchar_t* source)
{
// String size
const usz length = std::wcslen(source);
// Safe buffer size for max possible output length (including null terminator)
const int buf_size = narrow<int>(length * 3 + 1);
// Resize buffer
out.resize(buf_size - 1);
const int result = WideCharToMultiByte(CP_UTF8, 0, source, static_cast<int>(length) + 1, &out.front(), buf_size, nullptr, nullptr);
// Fix the size
out.resize(ensure(result) - 1);
}
static time_t to_time(const ULARGE_INTEGER& ft)
{
return ft.QuadPart / 10000000ULL - 11644473600ULL;
@@ -153,6 +138,7 @@ static fs::error to_error(DWORD e)
#if defined(__APPLE__)
#include <copyfile.h>
#include <mach-o/dyld.h>
#include <limits.h>
#elif defined(__linux__) || defined(__sun)
#include <sys/sendfile.h>
#include <sys/syscall.h>
@@ -371,6 +357,12 @@ namespace fs
return false;
}
bool device_base::create_symlink(const std::string&)
{
g_tls_error = error::readonly;
return false;
}
bool device_base::rename(const std::string&, const std::string&)
{
g_tls_error = error::readonly;
@@ -531,7 +523,7 @@ bool fs::get_stat(const std::string& path, stat_t& info)
// Handle drives specially
if (epath.find_first_of(delim) == umax && epath.ends_with(':'))
{
WIN32_FILE_ATTRIBUTE_DATA attrs;
WIN32_FILE_ATTRIBUTE_DATA attrs{};
// Must end with a delimiter
if (!GetFileAttributesExW(to_wchar(std::string(epath) + '/').get(), GetFileExInfoStandard, &attrs))
@@ -553,8 +545,6 @@ bool fs::get_stat(const std::string& path, stat_t& info)
return true;
}
WIN32_FIND_DATA attrs;
// Allowed by FindFirstFileExW but we should not allow it
if (epath.ends_with("*"))
{
@@ -562,6 +552,8 @@ bool fs::get_stat(const std::string& path, stat_t& info)
return false;
}
WIN32_FIND_DATA attrs{};
const auto wchar_ptr = to_wchar(std::string(epath));
const std::wstring_view wpath_view = wchar_ptr.get();
@@ -595,6 +587,7 @@ bool fs::get_stat(const std::string& path, stat_t& info)
}
info.is_directory = (attrs.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
info.is_symlink = (attrs.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) != 0;
info.is_writable = (attrs.dwFileAttributes & FILE_ATTRIBUTE_READONLY) == 0;
info.size = attrs.nFileSizeLow | (u64{attrs.nFileSizeHigh} << 32);
info.atime = to_time(attrs.ftLastAccessTime);
@@ -609,6 +602,7 @@ bool fs::get_stat(const std::string& path, stat_t& info)
}
info.is_directory = S_ISDIR(file_info.st_mode);
info.is_symlink = S_ISLNK(file_info.st_mode);
info.is_writable = file_info.st_mode & 0200; // HACK: approximation
info.size = file_info.st_size;
info.atime = file_info.st_atime;
@@ -662,6 +656,23 @@ bool fs::is_dir(const std::string& path)
return true;
}
bool fs::is_symlink(const std::string& path)
{
fs::stat_t info{};
if (!fs::get_stat(path, info))
{
return false;
}
if (!info.is_symlink)
{
g_tls_error = error::exist;
return false;
}
return true;
}
bool fs::statfs(const std::string& path, fs::device_stat& info)
{
if (auto device = get_virtual_device(path))
@@ -761,7 +772,7 @@ bool fs::create_path(const std::string& path)
#ifdef _WIN32
// Workaround: don't call is_dir with naked drive letter
if (parent.size() < path.size() && parent.back() != ':' && !is_dir(parent) && !create_path(parent))
if (parent.size() < path.size() && (parent.empty() || (parent.back() != ':' && !is_dir(parent) && !create_path(parent))))
#else
if (parent.size() < path.size() && !is_dir(parent) && !create_path(parent))
#endif
@@ -797,10 +808,35 @@ bool fs::remove_dir(const std::string& path)
g_tls_error = to_error(GetLastError());
return false;
}
#else
if (::rmdir(path.c_str()) != 0)
{
g_tls_error = to_error(errno);
return false;
}
#endif
return true;
}
bool fs::create_symlink(const std::string& path, const std::string& target)
{
if (auto device = get_virtual_device(path))
{
return device->create_symlink(path);
}
#ifdef _WIN32
const DWORD flags = is_dir(target) ? SYMBOLIC_LINK_FLAG_DIRECTORY : 0;
if (!CreateSymbolicLinkW(to_wchar(path).get(), to_wchar(target).get(), flags))
{
g_tls_error = to_error(GetLastError());
return false;
}
return true;
#else
if (::rmdir(path.c_str()) != 0)
if (::symlink(target.c_str(), path.c_str()) != 0)
{
g_tls_error = to_error(errno);
return false;
@@ -1789,7 +1825,7 @@ bool fs::dir::open(const std::string& path)
{
dir_entry info;
to_utf8(info.name, found.cFileName);
info.name = wchar_to_utf8(found.cFileName);
info.is_directory = (found.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
info.is_writable = (found.dwFileAttributes & FILE_ATTRIBUTE_READONLY) == 0;
info.size = (static_cast<u64>(found.nFileSizeHigh) << 32) | static_cast<u64>(found.nFileSizeLow);
@@ -1905,9 +1941,9 @@ bool fs::dir::open(const std::string& path)
return true;
}
bool fs::file::strict_read_check(u64 _size, u64 type_size) const
bool fs::file::strict_read_check(u64 offset, u64 _size, u64 type_size) const
{
if (usz pos0 = pos(), size0 = size(); (pos0 >= size0 ? 0 : (size0 - pos0)) / type_size < _size)
if (usz pos0 = offset, size0 = size(); (pos0 >= size0 ? 0 : (size0 - pos0)) / type_size < _size)
{
fs::g_tls_error = fs::error::inval;
return false;
@@ -1916,6 +1952,72 @@ bool fs::file::strict_read_check(u64 _size, u64 type_size) const
return true;
}
std::string fs::get_executable_path()
{
// Use magic static
static const std::string s_exe_path = []
{
#if defined(_WIN32)
constexpr DWORD size = 32767;
std::vector<wchar_t> buffer(size);
GetModuleFileNameW(nullptr, buffer.data(), size);
return wchar_to_utf8(buffer.data());
#elif defined(__APPLE__)
char bin_path[PATH_MAX];
uint32_t bin_path_size = sizeof(bin_path);
if (_NSGetExecutablePath(bin_path, &bin_path_size) != 0)
{
std::cerr << "Failed to find app binary path" << std::endl;
return std::string{};
}
// App bundle directory is three levels up from the binary.
return get_parent_dir(bin_path, 3);
#else
if (const char* appimage_path = ::getenv("APPIMAGE"))
{
std::cout << "Found AppImage path: " << appimage_path << std::endl;
return std::string(appimage_path);
}
std::cout << "No AppImage path found, checking for executable" << std::endl;
char exe_path[PATH_MAX];
const ssize_t len = ::readlink("/proc/self/exe", exe_path, sizeof(exe_path) - 1);
if (len == -1)
{
std::cerr << "Failed to find executable path" << std::endl;
return std::string{};
}
exe_path[len] = '\0';
std::cout << "Found exec path: " << exe_path << std::endl;
return std::string(exe_path);
#endif
}();
return s_exe_path;
}
std::string fs::get_executable_dir()
{
// Use magic static
static const std::string s_exe_dir = []
{
std::string exe_path = get_executable_path();
if (exe_path.empty())
{
return exe_path;
}
return get_parent_dir(exe_path) + "/";
}();
return s_exe_dir;
}
const std::string& fs::get_config_dir()
{
// Use magic static
@@ -1923,17 +2025,52 @@ const std::string& fs::get_config_dir()
{
std::string dir;
#ifdef _WIN32
wchar_t buf[32768];
constexpr DWORD size = static_cast<DWORD>(std::size(buf));
if (GetEnvironmentVariable(L"RPCS3_CONFIG_DIR", buf, size) - 1 >= size - 1 &&
GetModuleFileName(nullptr, buf, size) - 1 >= size - 1)
// Check if a portable directory exists.
std::string portable_dir = get_executable_dir() + "/portable/";
if (is_dir(portable_dir))
{
MessageBoxA(nullptr, fmt::format("GetModuleFileName() failed: error: %s", fmt::win_error{GetLastError(), nullptr}).c_str(), "fs::get_config_dir()", MB_ICONERROR);
return dir; // empty
return portable_dir;
}
to_utf8(dir, buf); // Convert to UTF-8
#ifdef _WIN32
std::vector<wchar_t> buf;
// Check if RPCS3_CONFIG_DIR is set and get the required buffer size
DWORD size = GetEnvironmentVariable(L"RPCS3_CONFIG_DIR", nullptr, 0);
if (size > 0)
{
// Resize buffer and fetch RPCS3_CONFIG_DIR
buf.resize(size);
if (GetEnvironmentVariable(L"RPCS3_CONFIG_DIR", buf.data(), size) != (size - 1))
{
// Clear buffer on failure and notify user
MessageBoxA(nullptr, fmt::format("GetEnvironmentVariable(RPCS3_CONFIG_DIR) failed: error: %s", fmt::win_error{GetLastError(), nullptr}).c_str(), "fs::get_config_dir()", MB_ICONERROR);
buf.clear();
}
}
// Fallback to executable path if needed
for (DWORD buf_size = MAX_PATH; size == 0; buf_size += MAX_PATH)
{
buf.resize(buf_size);
size = GetModuleFileName(nullptr, buf.data(), buf_size);
if (size == 0)
{
MessageBoxA(nullptr, fmt::format("GetModuleFileName() failed: error: %s", fmt::win_error{GetLastError(), nullptr}).c_str(), "fs::get_config_dir()", MB_ICONERROR);
return dir; // empty
}
if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
{
// Try again with increased buffer size
size = 0;
continue;
}
}
dir = wchar_to_utf8(buf.data());
std::replace(dir.begin(), dir.end(), '\\', '/');
@@ -2018,10 +2155,23 @@ const std::string& fs::get_temp_dir()
return dir; // empty
}
to_utf8(dir, buf);
dir = wchar_to_utf8(buf);
#else
// TODO
dir = get_cache_dir();
const char* tmp_dir = getenv("TMPDIR");
if (tmp_dir == nullptr || tmp_dir[0] == '\0')
{
// Fall back to cache directory
dir = get_cache_dir();
}
else
{
dir = tmp_dir;
if (!dir.ends_with("/"))
{
// Ensure path ends with a separator
dir += "/";
}
}
#endif
return dir;
+24 -6
View File
@@ -66,6 +66,7 @@ namespace fs
struct stat_t
{
bool is_directory;
bool is_symlink;
bool is_writable;
u64 size;
s64 atime;
@@ -155,6 +156,7 @@ namespace fs
virtual bool statfs(const std::string& path, device_stat& info) = 0;
virtual bool remove_dir(const std::string& path);
virtual bool create_dir(const std::string& path);
virtual bool create_symlink(const std::string& path);
virtual bool rename(const std::string& from, const std::string& to);
virtual bool remove(const std::string& path);
virtual bool trunc(const std::string& path, u64 length);
@@ -197,6 +199,9 @@ namespace fs
// Check whether the directory exists and is NOT a file
bool is_dir(const std::string& path);
// Check whether the path points to an existing symlink
bool is_symlink(const std::string& path);
// Get filesystem information
bool statfs(const std::string& path, device_stat& info);
@@ -209,6 +214,9 @@ namespace fs
// Create directories
bool create_path(const std::string& path);
// Create symbolic link
bool create_symlink(const std::string& path, const std::string& target);
// Rename (move) file or directory
bool rename(const std::string& from, const std::string& to, bool overwrite);
@@ -306,7 +314,7 @@ namespace fs
}
// Check if the handle is capable of reading (size * type_size) of bytes at the time of calling
bool strict_read_check(u64 size, u64 type_size = 1) const;
bool strict_read_check(u64 offset, u64 size, u64 type_size) const;
// Read the data from the file and return the amount of data written in buffer
u64 read(void* buffer, u64 count,
@@ -424,7 +432,7 @@ namespace fs
if (_size != umax)
{
// If _size arg is too high std::bad_alloc may happen during resize and then we cannot error check
if ((_size >= 0x10'0000 / sizeof(T)) && !strict_read_check(_size, sizeof(T)))
if ((_size >= 0x10'0000 / sizeof(T)) && !strict_read_check(pos(), _size, sizeof(T)))
{
return false;
}
@@ -449,7 +457,7 @@ namespace fs
// Read POD std::vector
template <typename T> requires (std::is_trivially_copyable_v<T> && !std::is_pointer_v<T>)
bool read(std::vector<T>& vec, usz _size = umax,
bool read(std::vector<T>& vec, usz _size = umax, bool use_offs = false, usz offset = umax,
const char* file = __builtin_FILE(),
const char* func = __builtin_FUNCTION(),
u32 line = __builtin_LINE(),
@@ -460,7 +468,7 @@ namespace fs
if (_size != umax)
{
// If _size arg is too high std::bad_alloc may happen during resize and then we cannot error check
if ((_size >= 0x10'0000 / sizeof(T)) && !strict_read_check(_size, sizeof(T)))
if ((_size >= 0x10'0000 / sizeof(T)) && !strict_read_check(use_offs ? offset : pos(), _size, sizeof(T)))
{
return false;
}
@@ -468,6 +476,11 @@ namespace fs
vec.resize(_size);
}
if (use_offs)
{
return read_at(offset, vec.data(), sizeof(T) * vec.size(), line, col, file, func) == sizeof(T) * vec.size();
}
return read(vec.data(), sizeof(T) * vec.size(), line, col, file, func) == sizeof(T) * vec.size();
}
@@ -510,8 +523,7 @@ namespace fs
{
std::vector<T> result;
result.resize(size() / sizeof(T));
seek(0);
if (!read(result, result.size(), file, func, line, col)) xfail({line, col, file, func});
if (!read(result, result.size(), true, 0, file, func, line, col)) xfail({line, col, file, func});
return result;
}
@@ -660,6 +672,12 @@ namespace fs
}
};
// Get executable path
std::string get_executable_path();
// Get executable containing directory
std::string get_executable_dir();
// Get configuration directory
const std::string& get_config_dir();
+1 -1
View File
@@ -554,4 +554,4 @@ public:
static std::string triple2();
};
#endif
#endif // LLVM_AVAILABLE
+3 -649
View File
@@ -4,16 +4,13 @@
#include "StrFmt.h"
#include "File.h"
#include "util/logs.hpp"
#include "mutex.h"
#include "util/vm.hpp"
#include "util/asm.hpp"
#include "util/v128.hpp"
#include "util/simd.hpp"
#include "Crypto/unzip.h"
#include <charconv>
#ifdef __linux__
#include <unistd.h>
#define CAN_OVERCOMMIT
#endif
@@ -22,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())};
@@ -47,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)
@@ -845,648 +844,3 @@ void asmjit::simd_builder::vec_extract_gpr(u32 esize, const x86::Gp& dst, const
}
#endif /* X86 */
#ifdef LLVM_AVAILABLE
#include <unordered_map>
#include <unordered_set>
#include <deque>
#ifdef _MSC_VER
#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 "-Wredundant-decls"
#pragma GCC diagnostic ignored "-Weffc++"
#pragma GCC diagnostic ignored "-Wmissing-noreturn"
#endif
#include "llvm/Support/TargetSelect.h"
#include "llvm/Support/FormattedStream.h"
#include "llvm/TargetParser/Host.h"
#include "llvm/ExecutionEngine/ExecutionEngine.h"
#include "llvm/ExecutionEngine/RTDyldMemoryManager.h"
#include "llvm/ExecutionEngine/ObjectCache.h"
#include "llvm/ExecutionEngine/JITEventListener.h"
#include "llvm/Object/ObjectFile.h"
#include "llvm/Object/SymbolSize.h"
#ifdef _MSC_VER
#pragma warning(pop)
#else
#pragma GCC diagnostic pop
#endif
const bool jit_initialize = []() -> bool
{
llvm::InitializeNativeTarget();
llvm::InitializeNativeTargetAsmPrinter();
llvm::InitializeNativeTargetAsmParser();
LLVMLinkInMCJIT();
return true;
}();
[[noreturn]] static void null(const char* name)
{
fmt::throw_exception("Null function: %s", name);
}
namespace vm
{
extern u8* const g_sudo_addr;
}
static shared_mutex null_mtx;
static std::unordered_map<std::string, u64> null_funcs;
static u64 make_null_function(const std::string& name)
{
if (name.starts_with("__0x"))
{
u32 addr = -1;
auto res = std::from_chars(name.c_str() + 4, name.c_str() + name.size(), addr, 16);
if (res.ec == std::errc() && res.ptr == name.c_str() + name.size() && addr < 0x8000'0000)
{
// Point the garbage to reserved, non-executable memory
return reinterpret_cast<u64>(vm::g_sudo_addr + addr);
}
}
std::lock_guard lock(null_mtx);
if (u64& func_ptr = null_funcs[name]) [[likely]]
{
// Already exists
return func_ptr;
}
else
{
using namespace asmjit;
// Build a "null" function that contains its name
const auto func = build_function_asm<void (*)()>("NULL", [&](native_asm& c, auto& args)
{
#if defined(ARCH_X64)
Label data = c.newLabel();
c.lea(args[0], x86::qword_ptr(data, 0));
c.jmp(Imm(&null));
c.align(AlignMode::kCode, 16);
c.bind(data);
// Copy function name bytes
for (char ch : name)
c.db(ch);
c.db(0);
c.align(AlignMode::kData, 16);
#else
// AArch64 implementation
Label jmp_address = c.newLabel();
Label data = c.newLabel();
// Force absolute jump to prevent out of bounds PC-rel jmp
c.ldr(args[0], arm::ptr(jmp_address));
c.br(args[0]);
c.align(AlignMode::kCode, 16);
c.bind(data);
c.embed(name.c_str(), name.size());
c.embedUInt8(0U);
c.bind(jmp_address);
c.embedUInt64(reinterpret_cast<u64>(&null));
c.align(AlignMode::kData, 16);
#endif
});
func_ptr = reinterpret_cast<u64>(func);
return func_ptr;
}
}
struct JITAnnouncer : llvm::JITEventListener
{
void notifyObjectLoaded(u64, const llvm::object::ObjectFile& obj, const llvm::RuntimeDyld::LoadedObjectInfo& info) override
{
using namespace llvm;
object::OwningBinary<object::ObjectFile> debug_obj_ = info.getObjectForDebug(obj);
if (!debug_obj_.getBinary())
{
#ifdef __linux__
jit_log.error("LLVM: Failed to announce JIT events (no debug object)");
#endif
return;
}
const object::ObjectFile& debug_obj = *debug_obj_.getBinary();
for (const auto& [sym, size] : computeSymbolSizes(debug_obj))
{
Expected<object::SymbolRef::Type> type_ = sym.getType();
if (!type_ || *type_ != object::SymbolRef::ST_Function)
continue;
Expected<StringRef> name = sym.getName();
if (!name)
continue;
Expected<u64> addr = sym.getAddress();
if (!addr)
continue;
jit_announce(*addr, size, {name->data(), name->size()});
}
}
};
// Simple memory manager
struct MemoryManager1 : llvm::RTDyldMemoryManager
{
// 256 MiB for code or data
static constexpr u64 c_max_size = 0x20000000 / 2;
// Allocation unit (2M)
static constexpr u64 c_page_size = 2 * 1024 * 1024;
// Reserve 512 MiB
u8* const ptr = static_cast<u8*>(utils::memory_reserve(c_max_size * 2));
u64 code_ptr = 0;
u64 data_ptr = c_max_size;
MemoryManager1() = default;
MemoryManager1(const MemoryManager1&) = delete;
MemoryManager1& operator=(const MemoryManager1&) = delete;
~MemoryManager1() override
{
// Hack: don't release to prevent reuse of address space, see jit_announce
utils::memory_decommit(ptr, c_max_size * 2);
}
llvm::JITSymbol findSymbol(const std::string& name) override
{
u64 addr = RTDyldMemoryManager::getSymbolAddress(name);
if (!addr)
{
addr = make_null_function(name);
if (!addr)
{
fmt::throw_exception("Failed to link '%s'", name);
}
}
return {addr, llvm::JITSymbolFlags::Exported};
}
u8* allocate(u64& oldp, uptr size, uint align, utils::protection prot)
{
if (align > c_page_size)
{
jit_log.fatal("Unsupported alignment (size=0x%x, align=0x%x)", size, align);
return nullptr;
}
const u64 olda = utils::align(oldp, align);
const u64 newp = utils::align(olda + size, align);
if ((newp - 1) / c_max_size != oldp / c_max_size)
{
jit_log.fatal("Out of memory (size=0x%x, align=0x%x)", size, align);
return nullptr;
}
if ((oldp - 1) / c_page_size != (newp - 1) / c_page_size)
{
// Allocate pages on demand
const u64 pagea = utils::align(oldp, c_page_size);
const u64 psize = utils::align(newp - pagea, c_page_size);
utils::memory_commit(this->ptr + pagea, psize, prot);
}
// Update allocation counter
oldp = newp;
return this->ptr + olda;
}
u8* allocateCodeSection(uptr size, uint align, uint /*sec_id*/, llvm::StringRef /*sec_name*/) override
{
return allocate(code_ptr, size, align, utils::protection::wx);
}
u8* allocateDataSection(uptr size, uint align, uint /*sec_id*/, llvm::StringRef /*sec_name*/, bool /*is_ro*/) override
{
return allocate(data_ptr, size, align, utils::protection::rw);
}
bool finalizeMemory(std::string* = nullptr) override
{
return false;
}
void registerEHFrames(u8*, u64, usz) override
{
}
void deregisterEHFrames() override
{
}
};
// Simple memory manager
struct MemoryManager2 : llvm::RTDyldMemoryManager
{
MemoryManager2() = default;
~MemoryManager2() override
{
}
llvm::JITSymbol findSymbol(const std::string& name) override
{
u64 addr = RTDyldMemoryManager::getSymbolAddress(name);
if (!addr)
{
addr = make_null_function(name);
if (!addr)
{
fmt::throw_exception("Failed to link '%s' (MM2)", name);
}
}
return {addr, llvm::JITSymbolFlags::Exported};
}
u8* allocateCodeSection(uptr size, uint align, uint /*sec_id*/, llvm::StringRef /*sec_name*/) override
{
return jit_runtime::alloc(size, align, true);
}
u8* allocateDataSection(uptr size, uint align, uint /*sec_id*/, llvm::StringRef /*sec_name*/, bool /*is_ro*/) override
{
return jit_runtime::alloc(size, align, false);
}
bool finalizeMemory(std::string* = nullptr) override
{
return false;
}
void registerEHFrames(u8*, u64, usz) override
{
}
void deregisterEHFrames() override
{
}
};
// Helper class
class ObjectCache final : public llvm::ObjectCache
{
const std::string& m_path;
public:
ObjectCache(const std::string& path)
: m_path(path)
{
}
~ObjectCache() override = default;
void notifyObjectCompiled(const llvm::Module* _module, llvm::MemoryBufferRef obj) override
{
std::string name = m_path;
name.append(_module->getName().data());
//fs::file(name, fs::rewrite).write(obj.getBufferStart(), obj.getBufferSize());
name.append(".gz");
fs::file module_file(name, fs::rewrite);
if (!module_file)
{
jit_log.error("LLVM: Failed to create module file: %s (%s)", name, fs::g_tls_error);
return;
}
if (!zip(obj.getBufferStart(), obj.getBufferSize(), module_file))
{
jit_log.error("LLVM: Failed to compress module: %s", _module->getName().data());
module_file.close();
fs::remove_file(name);
return;
}
jit_log.notice("LLVM: Created module: %s", _module->getName().data());
}
static std::unique_ptr<llvm::MemoryBuffer> load(const std::string& path)
{
if (fs::file cached{path + ".gz", fs::read})
{
const std::vector<u8> cached_data = cached.to_vector<u8>();
if (cached_data.empty()) [[unlikely]]
{
return nullptr;
}
const std::vector<u8> out = unzip(cached_data);
if (out.empty())
{
jit_log.error("LLVM: Failed to unzip module: '%s'", path);
return nullptr;
}
auto buf = llvm::WritableMemoryBuffer::getNewUninitMemBuffer(out.size());
std::memcpy(buf->getBufferStart(), out.data(), out.size());
return buf;
}
if (fs::file cached{path, fs::read})
{
if (cached.size() == 0) [[unlikely]]
{
return nullptr;
}
auto buf = llvm::WritableMemoryBuffer::getNewUninitMemBuffer(cached.size());
cached.read(buf->getBufferStart(), buf->getBufferSize());
return buf;
}
return nullptr;
}
std::unique_ptr<llvm::MemoryBuffer> getObject(const llvm::Module* _module) override
{
std::string path = m_path;
path.append(_module->getName().data());
if (auto buf = load(path))
{
jit_log.notice("LLVM: Loaded module: %s", _module->getName().data());
return buf;
}
return nullptr;
}
};
std::string jit_compiler::cpu(const std::string& _cpu)
{
std::string m_cpu = _cpu;
if (m_cpu.empty())
{
m_cpu = llvm::sys::getHostCPUName().str();
if (m_cpu == "sandybridge" ||
m_cpu == "ivybridge" ||
m_cpu == "haswell" ||
m_cpu == "broadwell" ||
m_cpu == "skylake" ||
m_cpu == "skylake-avx512" ||
m_cpu == "cascadelake" ||
m_cpu == "cooperlake" ||
m_cpu == "cannonlake" ||
m_cpu == "icelake" ||
m_cpu == "icelake-client" ||
m_cpu == "icelake-server" ||
m_cpu == "tigerlake" ||
m_cpu == "rocketlake" ||
m_cpu == "alderlake" ||
m_cpu == "raptorlake" ||
m_cpu == "meteorlake")
{
// Downgrade if AVX is not supported by some chips
if (!utils::has_avx())
{
m_cpu = "nehalem";
}
}
if (m_cpu == "skylake-avx512" ||
m_cpu == "cascadelake" ||
m_cpu == "cooperlake" ||
m_cpu == "cannonlake" ||
m_cpu == "icelake" ||
m_cpu == "icelake-client" ||
m_cpu == "icelake-server" ||
m_cpu == "tigerlake" ||
m_cpu == "rocketlake")
{
// Downgrade if AVX-512 is disabled or not supported
if (!utils::has_avx512())
{
m_cpu = "skylake";
}
}
if (m_cpu == "znver1" && utils::has_clwb())
{
// Upgrade
m_cpu = "znver2";
}
if ((m_cpu == "znver3" || m_cpu == "goldmont" || m_cpu == "alderlake" || m_cpu == "raptorlake" || m_cpu == "meteorlake") && utils::has_avx512_icl())
{
// Upgrade
m_cpu = "icelake-client";
}
if (m_cpu == "goldmont" && utils::has_avx2())
{
// Upgrade
m_cpu = "alderlake";
}
}
return m_cpu;
}
std::string jit_compiler::triple1()
{
#if defined(_WIN32)
return llvm::Triple::normalize(llvm::sys::getProcessTriple());
#elif defined(__APPLE__) && defined(ARCH_X64)
return llvm::Triple::normalize("x86_64-unknown-linux-gnu");
#elif defined(__APPLE__) && defined(ARCH_ARM64)
return llvm::Triple::normalize("aarch64-unknown-linux-gnu");
#else
return llvm::Triple::normalize(llvm::sys::getProcessTriple());
#endif
}
std::string jit_compiler::triple2()
{
#if defined(_WIN32) && defined(ARCH_X64)
return llvm::Triple::normalize("x86_64-unknown-linux-gnu");
#elif defined(_WIN32) && defined(ARCH_ARM64)
return llvm::Triple::normalize("aarch64-unknown-linux-gnu");
#elif defined(__APPLE__) && defined(ARCH_X64)
return llvm::Triple::normalize("x86_64-unknown-linux-gnu");
#elif defined(__APPLE__) && defined(ARCH_ARM64)
return llvm::Triple::normalize("aarch64-unknown-linux-gnu");
#else
return llvm::Triple::normalize(llvm::sys::getProcessTriple());
#endif
}
jit_compiler::jit_compiler(const std::unordered_map<std::string, u64>& _link, const std::string& _cpu, u32 flags)
: m_context(new llvm::LLVMContext)
, m_cpu(cpu(_cpu))
{
std::string result;
auto null_mod = std::make_unique<llvm::Module> ("null_", *m_context);
null_mod->setTargetTriple(jit_compiler::triple1());
std::unique_ptr<llvm::RTDyldMemoryManager> mem;
if (_link.empty())
{
// Auxiliary JIT (does not use custom memory manager, only writes the objects)
if (flags & 0x1)
{
mem = std::make_unique<MemoryManager1>();
}
else
{
mem = std::make_unique<MemoryManager2>();
null_mod->setTargetTriple(jit_compiler::triple2());
}
}
else
{
mem = std::make_unique<MemoryManager1>();
}
{
m_engine.reset(llvm::EngineBuilder(std::move(null_mod))
.setErrorStr(&result)
.setEngineKind(llvm::EngineKind::JIT)
.setMCJITMemoryManager(std::move(mem))
.setOptLevel(llvm::CodeGenOpt::Aggressive)
.setCodeModel(flags & 0x2 ? llvm::CodeModel::Large : llvm::CodeModel::Small)
#ifdef __APPLE__
//.setCodeModel(llvm::CodeModel::Large)
#endif
.setRelocationModel(llvm::Reloc::Model::PIC_)
.setMCPU(m_cpu)
.create());
}
if (!_link.empty())
{
for (auto&& [name, addr] : _link)
{
m_engine->updateGlobalMapping(name, addr);
}
}
if (!_link.empty() || !(flags & 0x1))
{
m_engine->RegisterJITEventListener(llvm::JITEventListener::createIntelJITEventListener());
m_engine->RegisterJITEventListener(new JITAnnouncer);
}
if (!m_engine)
{
fmt::throw_exception("LLVM: Failed to create ExecutionEngine: %s", result);
}
}
jit_compiler::~jit_compiler()
{
}
void jit_compiler::add(std::unique_ptr<llvm::Module> _module, const std::string& path)
{
ObjectCache cache{path};
m_engine->setObjectCache(&cache);
const auto ptr = _module.get();
m_engine->addModule(std::move(_module));
m_engine->generateCodeForModule(ptr);
m_engine->setObjectCache(nullptr);
for (auto& func : ptr->functions())
{
// Delete IR to lower memory consumption
func.deleteBody();
}
}
void jit_compiler::add(std::unique_ptr<llvm::Module> _module)
{
const auto ptr = _module.get();
m_engine->addModule(std::move(_module));
m_engine->generateCodeForModule(ptr);
for (auto& func : ptr->functions())
{
// Delete IR to lower memory consumption
func.deleteBody();
}
}
void jit_compiler::add(const std::string& path)
{
auto cache = ObjectCache::load(path);
if (auto object_file = llvm::object::ObjectFile::createObjectFile(*cache))
{
m_engine->addObjectFile(llvm::object::OwningBinary<llvm::object::ObjectFile>(std::move(*object_file), std::move(cache)));
}
else
{
jit_log.error("ObjectCache: Adding failed: %s", path);
}
}
bool jit_compiler::check(const std::string& path)
{
if (auto cache = ObjectCache::load(path))
{
if (auto object_file = llvm::object::ObjectFile::createObjectFile(*cache))
{
return true;
}
if (fs::remove_file(path))
{
jit_log.error("ObjectCache: Removed damaged file: %s", path);
}
}
return false;
}
void jit_compiler::update_global_mapping(const std::string& name, u64 addr)
{
m_engine->updateGlobalMapping(name, addr);
}
void jit_compiler::fin()
{
m_engine->finalizeObject();
}
u64 jit_compiler::get(const std::string& name)
{
return m_engine->getGlobalValueAddress(name);
}
#endif
+661
View File
@@ -0,0 +1,661 @@
#include "util/types.hpp"
#include "util/sysinfo.hpp"
#include "JIT.h"
#include "StrFmt.h"
#include "File.h"
#include "util/logs.hpp"
#include "mutex.h"
#include "util/vm.hpp"
#include "util/asm.hpp"
#include "Crypto/unzip.h"
#include <charconv>
LOG_CHANNEL(jit_log, "JIT");
#ifdef LLVM_AVAILABLE
#include <unordered_map>
#ifdef _MSC_VER
#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 "-Wredundant-decls"
#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"
#include "llvm/ExecutionEngine/RTDyldMemoryManager.h"
#include "llvm/ExecutionEngine/ObjectCache.h"
#include "llvm/ExecutionEngine/JITEventListener.h"
#include "llvm/Object/ObjectFile.h"
#include "llvm/Object/SymbolSize.h"
#ifdef _MSC_VER
#pragma warning(pop)
#else
#pragma GCC diagnostic pop
#endif
const bool jit_initialize = []() -> bool
{
llvm::InitializeNativeTarget();
llvm::InitializeNativeTargetAsmPrinter();
llvm::InitializeNativeTargetAsmParser();
LLVMLinkInMCJIT();
return true;
}();
[[noreturn]] static void null(const char* name)
{
fmt::throw_exception("Null function: %s", name);
}
namespace vm
{
extern u8* const g_sudo_addr;
}
static shared_mutex null_mtx;
static std::unordered_map<std::string, u64> null_funcs;
static u64 make_null_function(const std::string& name)
{
if (name.starts_with("__0x"))
{
u32 addr = -1;
auto res = std::from_chars(name.c_str() + 4, name.c_str() + name.size(), addr, 16);
if (res.ec == std::errc() && res.ptr == name.c_str() + name.size() && addr < 0x8000'0000)
{
// Point the garbage to reserved, non-executable memory
return reinterpret_cast<u64>(vm::g_sudo_addr + addr);
}
}
std::lock_guard lock(null_mtx);
if (u64& func_ptr = null_funcs[name]) [[likely]]
{
// Already exists
return func_ptr;
}
else
{
using namespace asmjit;
// Build a "null" function that contains its name
const auto func = build_function_asm<void (*)()>("NULL", [&](native_asm& c, auto& args)
{
#if defined(ARCH_X64)
Label data = c.newLabel();
c.lea(args[0], x86::qword_ptr(data, 0));
c.jmp(Imm(&null));
c.align(AlignMode::kCode, 16);
c.bind(data);
// Copy function name bytes
for (char ch : name)
c.db(ch);
c.db(0);
c.align(AlignMode::kData, 16);
#else
// AArch64 implementation
Label jmp_address = c.newLabel();
Label data = c.newLabel();
// Force absolute jump to prevent out of bounds PC-rel jmp
c.ldr(args[0], arm::ptr(jmp_address));
c.br(args[0]);
c.align(AlignMode::kCode, 16);
c.bind(data);
c.embed(name.c_str(), name.size());
c.embedUInt8(0U);
c.bind(jmp_address);
c.embedUInt64(reinterpret_cast<u64>(&null));
c.align(AlignMode::kData, 16);
#endif
});
func_ptr = reinterpret_cast<u64>(func);
return func_ptr;
}
}
struct JITAnnouncer : llvm::JITEventListener
{
void notifyObjectLoaded(u64, const llvm::object::ObjectFile& obj, const llvm::RuntimeDyld::LoadedObjectInfo& info) override
{
using namespace llvm;
object::OwningBinary<object::ObjectFile> debug_obj_ = info.getObjectForDebug(obj);
if (!debug_obj_.getBinary())
{
#ifdef __linux__
jit_log.error("LLVM: Failed to announce JIT events (no debug object)");
#endif
return;
}
const object::ObjectFile& debug_obj = *debug_obj_.getBinary();
for (const auto& [sym, size] : computeSymbolSizes(debug_obj))
{
Expected<object::SymbolRef::Type> type_ = sym.getType();
if (!type_ || *type_ != object::SymbolRef::ST_Function)
continue;
Expected<StringRef> name = sym.getName();
if (!name)
continue;
Expected<u64> addr = sym.getAddress();
if (!addr)
continue;
jit_announce(*addr, size, {name->data(), name->size()});
}
}
};
// Simple memory manager
struct MemoryManager1 : llvm::RTDyldMemoryManager
{
// 256 MiB for code or data
static constexpr u64 c_max_size = 0x20000000 / 2;
// Allocation unit (2M)
static constexpr u64 c_page_size = 2 * 1024 * 1024;
// Reserve 512 MiB
u8* const ptr = static_cast<u8*>(utils::memory_reserve(c_max_size * 2));
u64 code_ptr = 0;
u64 data_ptr = c_max_size;
MemoryManager1() = default;
MemoryManager1(const MemoryManager1&) = delete;
MemoryManager1& operator=(const MemoryManager1&) = delete;
~MemoryManager1() override
{
// Hack: don't release to prevent reuse of address space, see jit_announce
utils::memory_decommit(ptr, c_max_size * 2);
}
llvm::JITSymbol findSymbol(const std::string& name) override
{
u64 addr = RTDyldMemoryManager::getSymbolAddress(name);
if (!addr)
{
addr = make_null_function(name);
if (!addr)
{
fmt::throw_exception("Failed to link '%s'", name);
}
}
return {addr, llvm::JITSymbolFlags::Exported};
}
u8* allocate(u64& oldp, uptr size, uint align, utils::protection prot)
{
if (align > c_page_size)
{
jit_log.fatal("Unsupported alignment (size=0x%x, align=0x%x)", size, align);
return nullptr;
}
const u64 olda = utils::align(oldp, align);
const u64 newp = utils::align(olda + size, align);
if ((newp - 1) / c_max_size != oldp / c_max_size)
{
jit_log.fatal("Out of memory (size=0x%x, align=0x%x)", size, align);
return nullptr;
}
if ((oldp - 1) / c_page_size != (newp - 1) / c_page_size)
{
// Allocate pages on demand
const u64 pagea = utils::align(oldp, c_page_size);
const u64 psize = utils::align(newp - pagea, c_page_size);
utils::memory_commit(this->ptr + pagea, psize, prot);
}
// Update allocation counter
oldp = newp;
return this->ptr + olda;
}
u8* allocateCodeSection(uptr size, uint align, uint /*sec_id*/, llvm::StringRef /*sec_name*/) override
{
return allocate(code_ptr, size, align, utils::protection::wx);
}
u8* allocateDataSection(uptr size, uint align, uint /*sec_id*/, llvm::StringRef /*sec_name*/, bool /*is_ro*/) override
{
return allocate(data_ptr, size, align, utils::protection::rw);
}
bool finalizeMemory(std::string* = nullptr) override
{
return false;
}
void registerEHFrames(u8*, u64, usz) override
{
}
void deregisterEHFrames() override
{
}
};
// Simple memory manager
struct MemoryManager2 : llvm::RTDyldMemoryManager
{
MemoryManager2() = default;
~MemoryManager2() override
{
}
llvm::JITSymbol findSymbol(const std::string& name) override
{
u64 addr = RTDyldMemoryManager::getSymbolAddress(name);
if (!addr)
{
addr = make_null_function(name);
if (!addr)
{
fmt::throw_exception("Failed to link '%s' (MM2)", name);
}
}
return {addr, llvm::JITSymbolFlags::Exported};
}
u8* allocateCodeSection(uptr size, uint align, uint /*sec_id*/, llvm::StringRef /*sec_name*/) override
{
return jit_runtime::alloc(size, align, true);
}
u8* allocateDataSection(uptr size, uint align, uint /*sec_id*/, llvm::StringRef /*sec_name*/, bool /*is_ro*/) override
{
return jit_runtime::alloc(size, align, false);
}
bool finalizeMemory(std::string* = nullptr) override
{
return false;
}
void registerEHFrames(u8*, u64, usz) override
{
}
void deregisterEHFrames() override
{
}
};
// Helper class
class ObjectCache final : public llvm::ObjectCache
{
const std::string& m_path;
public:
ObjectCache(const std::string& path)
: m_path(path)
{
}
~ObjectCache() override = default;
void notifyObjectCompiled(const llvm::Module* _module, llvm::MemoryBufferRef obj) override
{
std::string name = m_path;
name.append(_module->getName().data());
//fs::file(name, fs::rewrite).write(obj.getBufferStart(), obj.getBufferSize());
name.append(".gz");
fs::file module_file(name, fs::rewrite);
if (!module_file)
{
jit_log.error("LLVM: Failed to create module file: %s (%s)", name, fs::g_tls_error);
return;
}
if (!zip(obj.getBufferStart(), obj.getBufferSize(), module_file))
{
jit_log.error("LLVM: Failed to compress module: %s", _module->getName().data());
module_file.close();
fs::remove_file(name);
return;
}
jit_log.notice("LLVM: Created module: %s", _module->getName().data());
}
static std::unique_ptr<llvm::MemoryBuffer> load(const std::string& path)
{
if (fs::file cached{path + ".gz", fs::read})
{
const std::vector<u8> cached_data = cached.to_vector<u8>();
if (cached_data.empty()) [[unlikely]]
{
return nullptr;
}
const std::vector<u8> out = unzip(cached_data);
if (out.empty())
{
jit_log.error("LLVM: Failed to unzip module: '%s'", path);
return nullptr;
}
auto buf = llvm::WritableMemoryBuffer::getNewUninitMemBuffer(out.size());
std::memcpy(buf->getBufferStart(), out.data(), out.size());
return buf;
}
if (fs::file cached{path, fs::read})
{
if (cached.size() == 0) [[unlikely]]
{
return nullptr;
}
auto buf = llvm::WritableMemoryBuffer::getNewUninitMemBuffer(cached.size());
cached.read(buf->getBufferStart(), buf->getBufferSize());
return buf;
}
return nullptr;
}
std::unique_ptr<llvm::MemoryBuffer> getObject(const llvm::Module* _module) override
{
std::string path = m_path;
path.append(_module->getName().data());
if (auto buf = load(path))
{
jit_log.notice("LLVM: Loaded module: %s", _module->getName().data());
return buf;
}
return nullptr;
}
};
std::string jit_compiler::cpu(const std::string& _cpu)
{
std::string m_cpu = _cpu;
if (m_cpu.empty())
{
m_cpu = llvm::sys::getHostCPUName().str();
if (m_cpu == "sandybridge" ||
m_cpu == "ivybridge" ||
m_cpu == "haswell" ||
m_cpu == "broadwell" ||
m_cpu == "skylake" ||
m_cpu == "skylake-avx512" ||
m_cpu == "cascadelake" ||
m_cpu == "cooperlake" ||
m_cpu == "cannonlake" ||
m_cpu == "icelake" ||
m_cpu == "icelake-client" ||
m_cpu == "icelake-server" ||
m_cpu == "tigerlake" ||
m_cpu == "rocketlake" ||
m_cpu == "alderlake" ||
m_cpu == "raptorlake" ||
m_cpu == "meteorlake")
{
// Downgrade if AVX is not supported by some chips
if (!utils::has_avx())
{
m_cpu = "nehalem";
}
}
if (m_cpu == "skylake-avx512" ||
m_cpu == "cascadelake" ||
m_cpu == "cooperlake" ||
m_cpu == "cannonlake" ||
m_cpu == "icelake" ||
m_cpu == "icelake-client" ||
m_cpu == "icelake-server" ||
m_cpu == "tigerlake" ||
m_cpu == "rocketlake")
{
// Downgrade if AVX-512 is disabled or not supported
if (!utils::has_avx512())
{
m_cpu = "skylake";
}
}
if (m_cpu == "znver1" && utils::has_clwb())
{
// Upgrade
m_cpu = "znver2";
}
if ((m_cpu == "znver3" || m_cpu == "goldmont" || m_cpu == "alderlake" || m_cpu == "raptorlake" || m_cpu == "meteorlake") && utils::has_avx512_icl())
{
// Upgrade
m_cpu = "icelake-client";
}
if (m_cpu == "goldmont" && utils::has_avx2())
{
// Upgrade
m_cpu = "alderlake";
}
}
return m_cpu;
}
std::string jit_compiler::triple1()
{
#if defined(_WIN32)
return llvm::Triple::normalize(llvm::sys::getProcessTriple());
#elif defined(__APPLE__) && defined(ARCH_X64)
return llvm::Triple::normalize("x86_64-unknown-linux-gnu");
#elif defined(__APPLE__) && defined(ARCH_ARM64)
return llvm::Triple::normalize("aarch64-unknown-linux-gnu");
#else
return llvm::Triple::normalize(llvm::sys::getProcessTriple());
#endif
}
std::string jit_compiler::triple2()
{
#if defined(_WIN32) && defined(ARCH_X64)
return llvm::Triple::normalize("x86_64-unknown-linux-gnu");
#elif defined(_WIN32) && defined(ARCH_ARM64)
return llvm::Triple::normalize("aarch64-unknown-linux-gnu");
#elif defined(__APPLE__) && defined(ARCH_X64)
return llvm::Triple::normalize("x86_64-unknown-linux-gnu");
#elif defined(__APPLE__) && defined(ARCH_ARM64)
return llvm::Triple::normalize("aarch64-unknown-linux-gnu");
#else
return llvm::Triple::normalize(llvm::sys::getProcessTriple());
#endif
}
jit_compiler::jit_compiler(const std::unordered_map<std::string, u64>& _link, const std::string& _cpu, u32 flags)
: m_context(new llvm::LLVMContext)
, m_cpu(cpu(_cpu))
{
std::string result;
auto null_mod = std::make_unique<llvm::Module> ("null_", *m_context);
null_mod->setTargetTriple(jit_compiler::triple1());
std::unique_ptr<llvm::RTDyldMemoryManager> mem;
if (_link.empty())
{
// Auxiliary JIT (does not use custom memory manager, only writes the objects)
if (flags & 0x1)
{
mem = std::make_unique<MemoryManager1>();
}
else
{
mem = std::make_unique<MemoryManager2>();
null_mod->setTargetTriple(jit_compiler::triple2());
}
}
else
{
mem = std::make_unique<MemoryManager1>();
}
{
m_engine.reset(llvm::EngineBuilder(std::move(null_mod))
.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)
#endif
.setRelocationModel(llvm::Reloc::Model::PIC_)
.setMCPU(m_cpu)
.create());
}
if (!_link.empty())
{
for (auto&& [name, addr] : _link)
{
m_engine->updateGlobalMapping(name, addr);
}
}
if (!_link.empty() || !(flags & 0x1))
{
m_engine->RegisterJITEventListener(llvm::JITEventListener::createIntelJITEventListener());
m_engine->RegisterJITEventListener(new JITAnnouncer);
}
if (!m_engine)
{
fmt::throw_exception("LLVM: Failed to create ExecutionEngine: %s", result);
}
}
jit_compiler::~jit_compiler()
{
}
void jit_compiler::add(std::unique_ptr<llvm::Module> _module, const std::string& path)
{
ObjectCache cache{path};
m_engine->setObjectCache(&cache);
const auto ptr = _module.get();
m_engine->addModule(std::move(_module));
m_engine->generateCodeForModule(ptr);
m_engine->setObjectCache(nullptr);
for (auto& func : ptr->functions())
{
// Delete IR to lower memory consumption
func.deleteBody();
}
}
void jit_compiler::add(std::unique_ptr<llvm::Module> _module)
{
const auto ptr = _module.get();
m_engine->addModule(std::move(_module));
m_engine->generateCodeForModule(ptr);
for (auto& func : ptr->functions())
{
// Delete IR to lower memory consumption
func.deleteBody();
}
}
void jit_compiler::add(const std::string& path)
{
auto cache = ObjectCache::load(path);
if (auto object_file = llvm::object::ObjectFile::createObjectFile(*cache))
{
m_engine->addObjectFile(llvm::object::OwningBinary<llvm::object::ObjectFile>(std::move(*object_file), std::move(cache)));
}
else
{
jit_log.error("ObjectCache: Adding failed: %s", path);
}
}
bool jit_compiler::check(const std::string& path)
{
if (auto cache = ObjectCache::load(path))
{
if (auto object_file = llvm::object::ObjectFile::createObjectFile(*cache))
{
return true;
}
if (fs::remove_file(path))
{
jit_log.error("ObjectCache: Removed damaged file: %s", path);
}
}
return false;
}
void jit_compiler::update_global_mapping(const std::string& name, u64 addr)
{
m_engine->updateGlobalMapping(name, addr);
}
void jit_compiler::fin()
{
m_engine->finalizeObject();
}
u64 jit_compiler::get(const std::string& name)
{
return m_engine->getGlobalValueAddress(name);
}
#endif // LLVM_AVAILABLE
+11 -1
View File
@@ -35,6 +35,9 @@ std::string wchar_to_utf8(std::wstring_view src)
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable : 4996)
#elif defined(__clang__)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
#else
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
@@ -52,6 +55,8 @@ std::u16string utf8_to_utf16(std::string_view src)
}
#ifdef _MSC_VER
#pragma warning(pop)
#elif defined(__clang__)
#pragma clang diagnostic pop
#else
#pragma GCC diagnostic pop
#endif
@@ -513,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);
@@ -652,6 +657,11 @@ std::string fmt::to_lower(std::string_view string)
return result;
}
std::string fmt::truncate(std::string_view src, usz length)
{
return std::string(src.begin(), src.begin() + std::min(src.size(), length));
}
bool fmt::match(const std::string& source, const std::string& mask)
{
usz source_position = 0, mask_position = 0;
+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;
+2
View File
@@ -178,6 +178,8 @@ namespace fmt
std::string to_upper(std::string_view string);
std::string to_lower(std::string_view string);
std::string truncate(std::string_view src, usz length);
bool match(const std::string& source, const std::string& mask);
struct buf_to_hexstring
+21 -2
View File
@@ -46,6 +46,7 @@ DYNAMIC_IMPORT_RENAME("Kernel32.dll", SetThreadDescriptionImport, "SetThreadDesc
#include <time.h>
#endif
#ifdef __linux__
#include <sys/syscall.h>
#include <sys/timerfd.h>
#include <unistd.h>
#endif
@@ -2192,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,
@@ -2426,7 +2430,7 @@ void thread_ctrl::wait_for_accurate(u64 usec)
break;
}
usec = (until - current).count();
usec = std::chrono::duration_cast<std::chrono::microseconds>(until - current).count();
}
#endif
}
@@ -2639,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();
+8 -3
View File
@@ -130,6 +130,9 @@ public:
const native_entry entry_point;
// Set name for debugger
static void set_name(std::string);
private:
// Thread handle (platform-specific)
atomic_t<u64> m_thread{0};
@@ -160,9 +163,6 @@ private:
// Cleanup after possibly deleting the thread instance
static native_entry finalize(u64 _self) noexcept;
// Set name for debugger
static void set_name(std::string);
// Make entry point
static native_entry make_trampoline(u64(*entry)(thread_base* _base));
@@ -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)
+13 -3
View File
@@ -379,8 +379,8 @@ public:
return m_head != 0;
}
template <typename... Args>
void push(Args&&... args)
template <bool Notify = true, typename... Args>
bool push(Args&&... args)
{
auto oldv = m_head.load();
auto item = new lf_queue_item<T>(load(oldv), std::forward<Args>(args)...);
@@ -390,9 +390,19 @@ public:
item->m_link = load(oldv);
}
if (!oldv)
if (!oldv && Notify)
{
// Notify only if queue was empty
notify(true);
}
return !oldv;
}
void notify(bool force = false)
{
if (force || operator bool())
{
utils::bless<atomic_t<u32>>(&m_head)[1].notify_one();
}
}
+5 -5
View File
@@ -38,13 +38,13 @@ jobs:
displayName: ccache
- bash: |
docker pull --quiet rpcs3/rpcs3-ci-focal:1.5
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.5 \
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.1'
QT_VER: '6.6.3'
QT_VER_MSVC: 'msvc2019'
QT_DATE: '202311210527'
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.1'
QT_VER: '6.6.3'
QT_VER_MAIN: '6'
pool:
Binary file not shown.
Binary file not shown.
+7 -5
View File
@@ -33,16 +33,17 @@ else()
add_compile_options(-fno-exceptions)
add_compile_options(-fstack-protector)
if (COMPILER_X86)
add_compile_options(-msse -msse2 -mcx16)
endif()
if (COMPILER_ARM)
# This section needs a review. Apple claims armv8.5-a on M-series but doesn't support SVE.
# Note that compared to the rest of the 8.x family, 8.1 is very restrictive and we'll have to bump the requirement in future to get anything meaningful.
if (APPLE)
add_compile_options(-march=armv8.4-a)
else()
add_compile_options(-march=armv8.1-a)
endif()
elseif(COMPILER_X86)
# Some compilers will set both X86 and ARM, so check explicitly for ARM first
add_compile_options(-msse -msse2 -mcx16)
endif()
add_compile_options(-Werror=old-style-cast)
@@ -51,6 +52,7 @@ else()
add_compile_options(-Werror=return-type)
add_compile_options(-Werror=overloaded-virtual)
add_compile_options(-Werror=missing-noreturn)
add_compile_options(-Werror=implicit-fallthrough)
add_compile_options(-Wunused-parameter)
add_compile_options(-Wignored-qualifiers)
add_compile_options(-Wredundant-move)
@@ -69,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)
@@ -82,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>
+3
View File
@@ -1,4 +1,7 @@
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wold-style-cast"
#import <Foundation/Foundation.h>
#pragma GCC diagnostic pop
namespace Darwin_Version
{
+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
+4 -1
View File
@@ -45,7 +45,8 @@ if(WIN32)
target_compile_definitions(rpcs3 PRIVATE UNICODE _UNICODE)
elseif(APPLE)
add_executable(rpcs3 MACOSX_BUNDLE)
target_sources(rpcs3 PRIVATE rpcs3.icns)
target_sources(rpcs3 PRIVATE rpcs3.icns update_helper.sh)
set_source_files_properties(update_helper.sh PROPERTIES MACOSX_PACKAGE_LOCATION Resources)
set_target_properties(rpcs3
PROPERTIES
MACOSX_BUNDLE_INFO_PLIST "${CMAKE_CURRENT_SOURCE_DIR}/rpcs3.plist.in")
@@ -70,10 +71,12 @@ target_sources(rpcs3
Input/dualsense_pad_handler.cpp
Input/evdev_joystick_handler.cpp
Input/evdev_gun_handler.cpp
Input/gui_pad_thread.cpp
Input/hid_pad_handler.cpp
Input/keyboard_pad_handler.cpp
Input/mm_joystick_handler.cpp
Input/pad_thread.cpp
Input/raw_mouse_handler.cpp
Input/sdl_pad_handler.cpp
Input/skateboard_pad_handler.cpp
Input/xinput_pad_handler.cpp
+15 -2
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]), true);
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)
{
@@ -139,7 +143,16 @@ usz decrypt_binaries_t::decrypt(std::string klic_input)
if (fs::file new_file{new_path, fs::rewrite})
{
new_file.write(elf_file.to_string());
// 16MB buffer
std::vector<u8> buffer(std::min<usz>(elf_file.size(), 1u << 24));
elf_file.seek(0);
while (usz read_size = elf_file.read(buffer.data(), buffer.size()))
{
new_file.write(buffer.data(), read_size);
}
dec_log.success("Decrypted %s -> %s", old_path, new_path);
std::cout << "Decrypted " << old_path << " -> " << new_path << std::endl; // For CLI
m_index++;
+181 -249
View File
@@ -157,37 +157,30 @@ u128 get_block_key(int block, NPD_HEADER *npd)
// for out data, allocate a buffer the size of 'edat->block_size'
// Also, set 'in file' to the beginning of the encrypted data, which may be offset if inside another file, but normally just reset to beginning of file
// returns number of bytes written, -1 for error
s64 decrypt_block(const fs::file* in, u8* out, EDAT_HEADER *edat, NPD_HEADER *npd, u8* crypt_key, u32 block_num, u32 total_blocks, u64 size_left)
s64 decrypt_block(const fs::file* in, u8* out, EDAT_HEADER *edat, NPD_HEADER *npd, u8* crypt_key, u32 block_num, u32 total_blocks, u64 size_left, bool is_out_buffer_aligned = false)
{
// Get metadata info and setup buffers.
const int metadata_section_size = ((edat->flags & EDAT_COMPRESSED_FLAG) != 0 || (edat->flags & EDAT_FLAG_0x20) != 0) ? 0x20 : 0x10;
const int metadata_offset = 0x100;
std::unique_ptr<u8[]> enc_data;
std::unique_ptr<u8[]> dec_data;
u8 hash[0x10] = { 0 };
u8 key_result[0x10] = { 0 };
u8 hash_result[0x14] = { 0 };
u64 offset = 0;
u64 metadata_sec_offset = 0;
s32 length = 0;
u64 length = 0;
s32 compression_end = 0;
unsigned char empty_iv[0x10] = {};
const u64 file_offset = in->pos();
memset(hash_result, 0, 0x14);
// Decrypt the metadata.
if ((edat->flags & EDAT_COMPRESSED_FLAG) != 0)
{
metadata_sec_offset = metadata_offset + u64{block_num} * metadata_section_size;
in->seek(file_offset + metadata_sec_offset);
u8 metadata[0x20]{};
unsigned char metadata[0x20];
memset(metadata, 0, 0x20);
in->read(metadata, 0x20);
in->read_at(metadata_sec_offset, metadata, 0x20);
// If the data is compressed, decrypt the metadata.
// NOTE: For NPD version 1 the metadata is not encrypted.
@@ -202,18 +195,17 @@ s64 decrypt_block(const fs::file* in, u8* out, EDAT_HEADER *edat, NPD_HEADER *np
std::tie(offset, length, compression_end) = dec_section(metadata);
}
memcpy(hash_result, metadata, 0x10);
std::memcpy(hash_result, metadata, 0x10);
}
else if ((edat->flags & EDAT_FLAG_0x20) != 0)
{
// If FLAG 0x20, the metadata precedes each data block.
metadata_sec_offset = metadata_offset + u64{block_num} * (metadata_section_size + edat->block_size);
in->seek(file_offset + metadata_sec_offset);
unsigned char metadata[0x20];
memset(metadata, 0, 0x20);
in->read(metadata, 0x20);
memcpy(hash_result, metadata, 0x14);
u8 metadata[0x20]{};
in->read_at(metadata_sec_offset, metadata, 0x20);
std::memcpy(hash_result, metadata, 0x14);
// If FLAG 0x20 is set, apply custom xor.
for (int j = 0; j < 0x10; j++)
@@ -228,9 +220,9 @@ s64 decrypt_block(const fs::file* in, u8* out, EDAT_HEADER *edat, NPD_HEADER *np
else
{
metadata_sec_offset = metadata_offset + u64{block_num} * metadata_section_size;
in->seek(file_offset + metadata_sec_offset);
in->read(hash_result, 0x10);
in->read_at(metadata_sec_offset, hash_result, 0x10);
offset = metadata_offset + u64{block_num} * edat->block_size + total_blocks * metadata_section_size;
length = edat->block_size;
@@ -239,59 +231,82 @@ s64 decrypt_block(const fs::file* in, u8* out, EDAT_HEADER *edat, NPD_HEADER *np
}
// Locate the real data.
const int pad_length = length;
length = (pad_length + 0xF) & 0xFFFFFFF0;
const usz pad_length = length;
length = utils::align<usz>(pad_length, 0x10);
// Setup buffers for decryption and read the data.
enc_data.reset(new u8[length]{ 0 });
dec_data.reset(new u8[length]{ 0 });
memset(hash, 0, 0x10);
memset(key_result, 0, 0x10);
std::vector<u8> enc_data_buf(is_out_buffer_aligned || length == pad_length ? 0 : length);
std::vector<u8> dec_data_buf(length);
in->seek(file_offset + offset);
in->read(enc_data.get(), length);
// Try to use out buffer for file reads if no padding is needed instead of a new buffer
u8* enc_data = enc_data_buf.empty() ? out : enc_data_buf.data();
// Variable to avoid copies when possible
u8* dec_data = dec_data_buf.data();
std::memset(hash, 0, 0x10);
std::memset(key_result, 0, 0x10);
in->read_at(offset, enc_data, length);
// Generate a key for the current block.
auto b_key = get_block_key(block_num, npd);
// Encrypt the block key with the crypto key.
aesecb128_encrypt(crypt_key, reinterpret_cast<uchar*>(&b_key), key_result);
if ((edat->flags & EDAT_FLAG_0x10) != 0)
{
aesecb128_encrypt(crypt_key, key_result, hash); // If FLAG 0x10 is set, encrypt again to get the final hash.
}
else
memcpy(hash, key_result, 0x10);
{
std::memcpy(hash, key_result, 0x10);
}
// Setup the crypto and hashing mode based on the extra flags.
int crypto_mode = ((edat->flags & EDAT_FLAG_0x02) == 0) ? 0x2 : 0x1;
int hash_mode;
if ((edat->flags & EDAT_FLAG_0x10) == 0)
if ((edat->flags & EDAT_FLAG_0x10) == 0)
hash_mode = 0x02;
else if ((edat->flags & EDAT_FLAG_0x20) == 0)
hash_mode = 0x04;
else
hash_mode = 0x01;
if ((edat->flags & EDAT_ENCRYPTED_KEY_FLAG) != 0)
if ((edat->flags & EDAT_ENCRYPTED_KEY_FLAG) != 0)
{
crypto_mode |= 0x10000000;
hash_mode |= 0x10000000;
}
if ((edat->flags & EDAT_DEBUG_DATA_FLAG) != 0)
const bool should_decompress = ((edat->flags & EDAT_COMPRESSED_FLAG) != 0) && compression_end;
if ((edat->flags & EDAT_DEBUG_DATA_FLAG) != 0)
{
// Reset the flags.
crypto_mode |= 0x01000000;
hash_mode |= 0x01000000;
// Simply copy the data without the header or the footer.
memcpy(dec_data.get(), enc_data.get(), length);
if (should_decompress)
{
std::memcpy(dec_data, enc_data, length);
}
else
{
// Optimize when decompression is not needed by avoiding 2 copies
dec_data = enc_data;
}
}
else
{
// IV is null if NPD version is 1 or 0.
u8* iv = (npd->version <= 1) ? empty_iv : npd->digest;
// Call main crypto routine on this data block.
if (!decrypt(hash_mode, crypto_mode, (npd->version == 4), enc_data.get(), dec_data.get(), length, key_result, iv, hash, hash_result))
if (!decrypt(hash_mode, crypto_mode, (npd->version == 4), enc_data, dec_data, length, key_result, iv, hash, hash_result))
{
edat_log.error("Block at offset 0x%llx has invalid hash!", offset);
return -1;
@@ -299,9 +314,9 @@ s64 decrypt_block(const fs::file* in, u8* out, EDAT_HEADER *edat, NPD_HEADER *np
}
// Apply additional de-compression if needed and write the decrypted data.
if (((edat->flags & EDAT_COMPRESSED_FLAG) != 0) && compression_end)
if (should_decompress)
{
const int res = decompress(out, dec_data.get(), edat->block_size);
const int res = decompress(out, dec_data, edat->block_size);
size_left -= res;
@@ -313,42 +328,20 @@ s64 decrypt_block(const fs::file* in, u8* out, EDAT_HEADER *edat, NPD_HEADER *np
return -1;
}
}
return res;
}
else
{
memcpy(out, dec_data.get(), pad_length);
return pad_length;
}
}
// EDAT/SDAT decryption.
// reset file to beginning of data before calling
int decrypt_data(const fs::file* in, const fs::file* out, EDAT_HEADER *edat, NPD_HEADER *npd, unsigned char* crypt_key, bool /*verbose*/)
{
const int total_blocks = static_cast<int>((edat->file_size + edat->block_size - 1) / edat->block_size);
u64 size_left = edat->file_size;
std::unique_ptr<u8[]> data(new u8[edat->block_size]);
for (int i = 0; i < total_blocks; i++)
if (dec_data != out)
{
in->seek(0);
memset(data.get(), 0, edat->block_size);
u64 res = decrypt_block(in, data.get(), edat, npd, crypt_key, i, total_blocks, size_left);
if (res == umax)
{
edat_log.error("Decrypt Block failed!");
return 1;
}
size_left -= res;
out->write(data.get(), res);
std::memcpy(out, dec_data, pad_length);
}
return 0;
return pad_length;
}
// set file offset to beginning before calling
int check_data(unsigned char *key, EDAT_HEADER *edat, NPD_HEADER *npd, const fs::file* f, bool verbose)
bool check_data(u8* key, EDAT_HEADER* edat, NPD_HEADER* npd, const fs::file* f, bool verbose)
{
u8 header[0xA0] = { 0 };
u8 empty_header[0xA0] = { 0 };
@@ -363,7 +356,7 @@ int check_data(unsigned char *key, EDAT_HEADER *edat, NPD_HEADER *npd, const fs:
if (edat->flags & 0x7EFFFFFE)
{
edat_log.error("Bad header flags!");
return 1;
return false;
}
}
else if (npd->version == 2)
@@ -371,7 +364,7 @@ int check_data(unsigned char *key, EDAT_HEADER *edat, NPD_HEADER *npd, const fs:
if (edat->flags & 0x7EFFFFE0)
{
edat_log.error("Bad header flags!");
return 1;
return false;
}
}
else if ((npd->version == 3) || (npd->version == 4))
@@ -379,13 +372,13 @@ int check_data(unsigned char *key, EDAT_HEADER *edat, NPD_HEADER *npd, const fs:
if (edat->flags & 0x7EFFFFC0)
{
edat_log.error("Bad header flags!");
return 1;
return false;
}
}
else
{
edat_log.error("Unknown version!");
return 1;
return false;
}
// Read in the file header.
@@ -421,7 +414,7 @@ int check_data(unsigned char *key, EDAT_HEADER *edat, NPD_HEADER *npd, const fs:
if ((edat->flags & EDAT_DEBUG_DATA_FLAG) != EDAT_DEBUG_DATA_FLAG)
{
edat_log.error("RAP/RIF/KLIC key is invalid!");
return 1;
return false;
}
}
@@ -435,7 +428,7 @@ int check_data(unsigned char *key, EDAT_HEADER *edat, NPD_HEADER *npd, const fs:
if (!edat->block_size)
{
return 1;
return false;
}
const usz block_num = utils::aligned_div<u64>(edat->file_size, edat->block_size);
@@ -445,7 +438,7 @@ int check_data(unsigned char *key, EDAT_HEADER *edat, NPD_HEADER *npd, const fs:
if (utils::add_saturate<u64>(utils::add_saturate<u64>(file_offset, metadata_section_offset), metadata_size) > f->size())
{
return 1;
return false;
}
u64 bytes_read = 0;
@@ -455,10 +448,10 @@ int check_data(unsigned char *key, EDAT_HEADER *edat, NPD_HEADER *npd, const fs:
while (bytes_read < metadata_size)
{
// Locate the metadata blocks.
f->seek(file_offset + metadata_section_offset);
const usz offset = file_offset + metadata_section_offset;
// Read in the metadata.
f->read(metadata.get() + bytes_read, metadata_section_size);
f->read_at(offset, metadata.get() + bytes_read, metadata_section_size);
// Adjust sizes.
bytes_read += metadata_section_size;
@@ -492,15 +485,17 @@ int check_data(unsigned char *key, EDAT_HEADER *edat, NPD_HEADER *npd, const fs:
ecdsa_set_pub(VSH_PUB);
// Read in the metadata and header signatures.
f->seek(file_offset + 0xB0);
f->seek(0xB0);
f->read(metadata_signature, 0x28);
f->read(header_signature, 0x28);
// Checking metadata signature.
// Setup signature r and s.
memcpy(signature_r + 01, metadata_signature, 0x14);
memcpy(signature_s + 01, metadata_signature + 0x14, 0x14);
if ((!memcmp(signature_r, zero_buf, 0x15)) || (!memcmp(signature_s, zero_buf, 0x15)))
signature_r[0] = 0;
signature_s[0] = 0;
std::memcpy(signature_r + 1, metadata_signature, 0x14);
std::memcpy(signature_s + 1, metadata_signature + 0x14, 0x14);
if ((!std::memcmp(signature_r, zero_buf, 0x15)) || (!std::memcmp(signature_s, zero_buf, 0x15)))
{
edat_log.warning("Metadata signature is invalid!");
}
@@ -510,10 +505,12 @@ int check_data(unsigned char *key, EDAT_HEADER *edat, NPD_HEADER *npd, const fs:
if ((edat->flags & EDAT_FLAG_0x20) != 0) //Sony failed again, they used buffer from 0x100 with half size of real metadata.
{
const usz metadata_buf_size = block_num * 0x10;
std::unique_ptr<u8[]> metadata_buf(new u8[metadata_buf_size]);
f->seek(file_offset + metadata_offset);
f->read(metadata_buf.get(), metadata_buf_size);
sha1(metadata_buf.get(), metadata_buf_size, signature_hash);
std::vector<u8> metadata_buf(metadata_buf_size);
f->read_at(file_offset + metadata_offset, metadata_buf.data(), metadata_buf_size);
sha1(metadata_buf.data(), metadata_buf_size, signature_hash);
}
else
sha1(metadata.get(), metadata_size, signature_hash);
@@ -528,22 +525,23 @@ int check_data(unsigned char *key, EDAT_HEADER *edat, NPD_HEADER *npd, const fs:
// Checking header signature.
// Setup header signature r and s.
memset(signature_r, 0, 0x15);
memset(signature_s, 0, 0x15);
memcpy(signature_r + 01, header_signature, 0x14);
memcpy(signature_s + 01, header_signature + 0x14, 0x14);
signature_r[0] = 0;
signature_s[0] = 0;
std::memcpy(signature_r + 1, header_signature, 0x14);
std::memcpy(signature_s + 1, header_signature + 0x14, 0x14);
if ((!memcmp(signature_r, zero_buf, 0x15)) || (!memcmp(signature_s, zero_buf, 0x15)))
if ((!std::memcmp(signature_r, zero_buf, 0x15)) || (!std::memcmp(signature_s, zero_buf, 0x15)))
{
edat_log.warning("Header signature is invalid!");
}
else
{
// Setup header signature hash.
memset(signature_hash, 0, 20);
u8 header_buf[0xD8];
f->seek(file_offset);
f->read(header_buf, 0xD8);
std::memset(signature_hash, 0, 20);
u8 header_buf[0xD8]{};
f->read_at(file_offset, header_buf, 0xD8);
sha1(header_buf, 0xD8, signature_hash);
if (!ecdsa_verify(signature_hash, signature_r, signature_s))
@@ -551,7 +549,7 @@ int check_data(unsigned char *key, EDAT_HEADER *edat, NPD_HEADER *npd, const fs:
}
}
return 0;
return true;
}
bool validate_dev_klic(const u8* klicensee, NPD_HEADER *npd)
@@ -585,21 +583,25 @@ bool validate_dev_klic(const u8* klicensee, NPD_HEADER *npd)
return cmac_hash_compare(reinterpret_cast<uchar*>(&key), 0x10, dev, 0x60, npd->dev_hash, 0x10);
}
bool validate_npd_hashes(const char* file_name, const u8* klicensee, NPD_HEADER *npd, EDAT_HEADER* edat, bool verbose)
bool validate_npd_hashes(std::string_view file_name, const u8* klicensee, NPD_HEADER* npd, EDAT_HEADER* edat, bool verbose)
{
if (!file_name)
{
fmt::throw_exception("Empty filename");
}
// Ignore header validation in DEBUG data.
if (edat->flags & EDAT_DEBUG_DATA_FLAG)
{
return true;
}
const usz file_name_length = std::strlen(file_name);
const usz buf_len = 0x30 + file_name_length;
if (!validate_dev_klic(klicensee, npd))
{
return false;
}
if (file_name.empty())
{
return true;
}
const usz buf_len = 0x30 + file_name.size();
std::unique_ptr<u8[]> buf(new u8[buf_len]);
std::unique_ptr<u8[]> buf_lower(new u8[buf_len]);
@@ -607,12 +609,12 @@ bool validate_npd_hashes(const char* file_name, const u8* klicensee, NPD_HEADER
// Build the title buffer (content_id + file_name).
std::memcpy(buf.get(), npd->content_id, 0x30);
std::memcpy(buf.get() + 0x30, file_name, file_name_length);
std::memcpy(buf.get() + 0x30, file_name.data(), file_name.size());
std::memcpy(buf_lower.get(), buf.get(), buf_len);
std::memcpy(buf_upper.get(), buf.get(), buf_len);
for (usz i = std::basic_string_view<u8>(buf.get() + 0x30, file_name_length).find_last_of('.'); i < buf_len; i++)
for (usz i = std::basic_string_view<u8>(buf.get() + 0x30, file_name.size()).find_last_of('.'); i < buf_len; i++)
{
const u8 c = static_cast<u8>(buf[i]);
buf_upper[i] = std::toupper(c);
@@ -634,17 +636,17 @@ bool validate_npd_hashes(const char* file_name, const u8* klicensee, NPD_HEADER
edat_log.warning("NPD title hash is invalid!");
}
const bool dev_hash_result = validate_dev_klic(klicensee, npd);
return title_hash_result && dev_hash_result;
return title_hash_result;
}
void read_npd_edat_header(const fs::file* input, NPD_HEADER& NPD, EDAT_HEADER& EDAT)
{
char npd_header[0x80];
char edat_header[0x10];
input->read(npd_header, sizeof(npd_header));
input->read(edat_header, sizeof(edat_header));
char npd_header[0x80]{};
char edat_header[0x10]{};
usz pos = input->pos();
pos += input->read_at(pos, npd_header, sizeof(npd_header));
input->read_at(pos, edat_header, sizeof(edat_header));
std::memcpy(&NPD.magic, npd_header, 4);
NPD.version = read_from_ptr<be_t<s32>>(npd_header, 4);
@@ -662,124 +664,6 @@ void read_npd_edat_header(const fs::file* input, NPD_HEADER& NPD, EDAT_HEADER& E
EDAT.file_size = read_from_ptr<be_t<u64>>(edat_header, 8);
}
bool extract_all_data(const fs::file* input, const fs::file* output, const char* input_file_name, unsigned char* devklic, bool verbose)
{
// Setup NPD and EDAT/SDAT structs.
NPD_HEADER NPD;
EDAT_HEADER EDAT;
// Read in the NPD and EDAT/SDAT headers.
read_npd_edat_header(input, NPD, EDAT);
if (NPD.magic != "NPD\0"_u32)
{
edat_log.error("%s has invalid NPD header or already decrypted.", input_file_name);
return true;
}
if (verbose)
{
edat_log.notice("NPD HEADER");
edat_log.notice("NPD version: %d", NPD.version);
edat_log.notice("NPD license: %d", NPD.license);
edat_log.notice("NPD type: %d", NPD.type);
edat_log.notice("NPD content_id: %s", NPD.content_id);
}
// Set decryption key.
u128 key{};
// Check EDAT/SDAT flag.
if ((EDAT.flags & SDAT_FLAG) == SDAT_FLAG)
{
if (verbose)
{
edat_log.notice("SDAT HEADER");
edat_log.notice("SDAT flags: 0x%08X", EDAT.flags);
edat_log.notice("SDAT block size: 0x%08X", EDAT.block_size);
edat_log.notice("SDAT file size: 0x%08X", EDAT.file_size);
}
// Generate SDAT key.
key = std::bit_cast<u128>(NPD.dev_hash) ^ std::bit_cast<u128>(SDAT_KEY);
}
else
{
if (verbose)
{
edat_log.notice("EDAT HEADER");
edat_log.notice("EDAT flags: 0x%08X", EDAT.flags);
edat_log.notice("EDAT block size: 0x%08X", EDAT.block_size);
edat_log.notice("EDAT file size: 0x%08X", EDAT.file_size);
}
// Perform header validation (EDAT only).
char real_file_name[CRYPTO_MAX_PATH];
extract_file_name(input_file_name, real_file_name);
if (!validate_npd_hashes(real_file_name, devklic, &NPD, &EDAT, verbose))
{
edat_log.error("NPD hash validation failed!");
return true;
}
// Select EDAT key.
if ((NPD.license & 0x3) == 0x3) // Type 3: Use supplied devklic.
{
std::memcpy(&key, devklic, 0x10);
}
else // Type 2: Use key from RAP file (RIF key). (also used for type 1 at the moment)
{
const std::string rap_path = rpcs3::utils::get_rap_file_path(NPD.content_id);
if (fs::file rap{rap_path}; rap && rap.size() >= sizeof(key))
{
key = GetEdatRifKeyFromRapFile(rap);
}
// Make sure we don't have an empty RIF key.
if (!key)
{
edat_log.error("A valid RAP file is needed for this EDAT file! (license=%d)", NPD.license);
return true;
}
if (verbose)
{
edat_log.notice("RIFKEY: %s", std::bit_cast<be_t<u128>>(key));
}
}
if (verbose)
{
be_t<u128> data;
std::memcpy(&data, devklic, sizeof(data));
edat_log.notice("DEVKLIC: %s", data);
}
}
if (verbose)
{
edat_log.notice("DECRYPTION KEY: %s", std::bit_cast<be_t<u128>>(key));
}
input->seek(0);
if (check_data(reinterpret_cast<uchar*>(&key), &EDAT, &NPD, input, verbose))
{
edat_log.error("Data parsing failed!");
return true;
}
input->seek(0);
if (decrypt_data(input, output, &EDAT, &NPD, reinterpret_cast<uchar*>(&key), verbose))
{
edat_log.error("Data decryption failed!");
return true;
}
return false;
}
u128 GetEdatRifKeyFromRapFile(const fs::file& rap_file)
{
u128 rapkey{};
@@ -814,7 +698,7 @@ bool VerifyEDATHeaderWithKLicense(const fs::file& input, const std::string& inpu
}
// Perform header validation (EDAT only).
char real_file_name[CRYPTO_MAX_PATH];
char real_file_name[CRYPTO_MAX_PATH]{};
extract_file_name(input_file_name.c_str(), real_file_name);
if (!validate_npd_hashes(real_file_name, custom_klic, &NPD, &EDAT, false))
{
@@ -834,7 +718,7 @@ bool VerifyEDATHeaderWithKLicense(const fs::file& input, const std::string& inpu
}
// Decrypts full file
fs::file DecryptEDAT(const fs::file& input, const std::string& input_file_name, int mode, u8 *custom_klic, bool verbose)
fs::file DecryptEDAT(const fs::file& input, const std::string& input_file_name, int mode, u8 *custom_klic)
{
if (!input)
{
@@ -890,25 +774,29 @@ fs::file DecryptEDAT(const fs::file& input, const std::string& input_file_name,
}
// Delete the bad output file if any errors arise.
fs::file output = fs::make_stream<std::vector<u8>>();
if (extract_all_data(&input, &output, input_file_name.c_str(), reinterpret_cast<uchar*>(&devklic), verbose))
auto data = std::make_unique<EDATADecrypter>(input, devklic, input_file_name, false);
if (!data->ReadHeader())
{
output.release();
return fs::file{};
}
output.seek(0);
fs::file output;
output.reset(std::move(data));
return output;
}
bool EDATADecrypter::ReadHeader()
{
edata_file.seek(0);
// Read in the NPD and EDAT/SDAT headers.
read_npd_edat_header(&edata_file, npdHeader, edatHeader);
if (npdHeader.magic != "NPD\0"_u32)
{
edat_log.error("Not an NPDRM file");
return false;
}
@@ -920,25 +808,56 @@ bool EDATADecrypter::ReadHeader()
}
else
{
// verify key
if (!validate_dev_klic(reinterpret_cast<uchar*>(&dec_key), &npdHeader))
// extract key from RIF
char real_file_name[CRYPTO_MAX_PATH]{};
extract_file_name(m_file_name.c_str(), real_file_name);
if (!validate_npd_hashes(real_file_name, reinterpret_cast<const u8*>(&dec_key), &npdHeader, &edatHeader, false))
{
edat_log.error("Failed validating klic");
return false;
edat_log.error("NPD hash validation failed!");
return true;
}
// Use provided dec_key
// Select EDAT key.
if (m_is_key_final)
{
// Already provided
}
// Type 3: Use supplied dec_key.
else if ((npdHeader.license & 0x3) == 0x3)
{
//
}
// Type 2: Use key from RAP file (RIF key). (also used for type 1 at the moment)
else
{
const std::string rap_path = rpcs3::utils::get_rap_file_path(npdHeader.content_id);
if (fs::file rap{rap_path}; rap && rap.size() >= sizeof(dec_key))
{
dec_key = GetEdatRifKeyFromRapFile(rap);
}
// Make sure we don't have an empty RIF key.
if (!dec_key)
{
edat_log.error("A valid RAP file is needed for this EDAT file! (license=%d)", npdHeader.license);
return true;
}
edat_log.trace("RIFKEY: %s", std::bit_cast<be_t<u128>>(dec_key));
}
}
edata_file.seek(0);
// k the ecdsa_verify function in this check_data function takes a ridiculous amount of time
// like it slows down load time by a factor of x20, at least, so its ignored for now
/*if (check_data(dec_key._bytes, &edatHeader, &npdHeader, &sdata_file, false))
{
return false;
}*/
//if (!check_data(reinterpret_cast<u8*>(&dec_key), &edatHeader, &npdHeader, &edata_file, false))
//{
// edat_log.error("NPDRM check_data() failed!");
// return false;
//}
file_size = edatHeader.file_size;
total_blocks = ::narrow<u32>(utils::aligned_div(edatHeader.file_size, edatHeader.block_size));
@@ -948,6 +867,7 @@ bool EDATADecrypter::ReadHeader()
if (file_size && !ReadData(0, data_sample, 1))
{
edat_log.error("NPDRM ReadData() failed!");
return false;
}
@@ -967,28 +887,40 @@ u64 EDATADecrypter::ReadData(u64 pos, u8* data, u64 size)
const u64 startOffset = pos % edatHeader.block_size;
const u64 num_blocks = utils::aligned_div(startOffset + size, edatHeader.block_size);
data_buf.resize(num_blocks * edatHeader.block_size);
// Find and decrypt block range covering pos + size
const u32 starting_block = ::narrow<u32>(pos / edatHeader.block_size);
const u32 ending_block = ::narrow<u32>(std::min<u64>(starting_block + num_blocks, total_blocks));
u64 writeOffset = 0;
for (u32 i = starting_block; i < ending_block; ++i)
std::vector<u8> data_buf(edatHeader.block_size + 16);
for (u32 i = starting_block; i < ending_block; i++)
{
edata_file.seek(0);
u64 res = decrypt_block(&edata_file, &data_buf[writeOffset], &edatHeader, &npdHeader, reinterpret_cast<uchar*>(&dec_key), i, total_blocks, edatHeader.file_size);
u64 res = decrypt_block(&edata_file, data_buf.data(), &edatHeader, &npdHeader, reinterpret_cast<uchar*>(&dec_key), i, total_blocks, edatHeader.file_size, true);
if (res == umax)
{
edat_log.error("Error Decrypting data");
return 0;
}
writeOffset += res;
const usz skip_start = (i == starting_block ? startOffset : 0);
if (skip_start >= res)
{
break;
}
const usz end_pos = (i != total_blocks - 1 ? edatHeader.block_size : (edatHeader.file_size - 1) % edatHeader.block_size + 1);
const usz read_end = std::min<usz>(res, i == ending_block - 1 ? std::min<usz>(end_pos, (startOffset + size - 1) % edatHeader.block_size + 1) : end_pos);
std::memcpy(data + writeOffset, data_buf.data() + skip_start, read_end - skip_start);
std::memset(data_buf.data(), 0, read_end - skip_start);
writeOffset += read_end - skip_start;
}
const u64 bytesWrote = std::min<u64>(writeOffset - startOffset, size);
memcpy(data, &data_buf[startOffset], bytesWrote);
return bytesWrote;
return writeOffset;
}
+25 -7
View File
@@ -18,6 +18,7 @@ struct loaded_npdrm_keys
{
atomic_t<u128> dec_keys[16]{};
atomic_t<u64> dec_keys_pos = 0;
u128 one_time_key{}; // For savestates
atomic_t<u32> npdrm_fds{0};
void install_decryption_key(u128 key)
@@ -61,7 +62,7 @@ struct EDAT_HEADER
};
// Decrypts full file, or null/empty file
extern fs::file DecryptEDAT(const fs::file& input, const std::string& input_file_name, int mode, u8 *custom_klic, bool verbose);
extern fs::file DecryptEDAT(const fs::file& input, const std::string& input_file_name, int mode, u8 *custom_klic);
extern void read_npd_edat_header(const fs::file* input, NPD_HEADER& NPD, EDAT_HEADER& EDAT);
extern bool VerifyEDATHeaderWithKLicense(const fs::file& input, const std::string& input_file_name, const u8* custom_klic, NPD_HEADER *npd_out = nullptr);
@@ -71,7 +72,10 @@ u128 GetEdatRifKeyFromRapFile(const fs::file& rap_file);
struct EDATADecrypter final : fs::file_base
{
// file stream
fs::file edata_file;
fs::file m_edata_file;
const fs::file& edata_file;
std::string m_file_name;
bool m_is_key_final = true;
u64 file_size{0};
u32 total_blocks{0};
u64 pos{0};
@@ -79,14 +83,23 @@ struct EDATADecrypter final : fs::file_base
NPD_HEADER npdHeader{};
EDAT_HEADER edatHeader{};
// Internal data buffers.
std::vector<u8> data_buf{};
u128 dec_key{};
public:
EDATADecrypter(fs::file&& input, u128 dec_key = {})
: edata_file(std::move(input))
EDATADecrypter(fs::file&& input, u128 dec_key = {}, std::string file_name = {}, bool is_key_final = true) noexcept
: m_edata_file(std::move(input))
, edata_file(m_edata_file)
, m_file_name(std::move(file_name))
, m_is_key_final(is_key_final)
, dec_key(dec_key)
{
}
EDATADecrypter(const fs::file& input, u128 dec_key = {}, std::string file_name = {}, bool is_key_final = true) noexcept
: m_edata_file(fs::file{})
, edata_file(input)
, m_file_name(std::move(file_name))
, m_is_key_final(is_key_final)
, dec_key(dec_key)
{
}
@@ -150,4 +163,9 @@ public:
id.type.insert(0, "EDATADecrypter: "sv);
return id;
}
u128 get_key() const
{
return dec_key;
}
};
+178 -23
View File
@@ -862,10 +862,12 @@ bool package_reader::fill_data(std::map<std::string, install_entry*>& all_instal
return true;
}
fs::file DecryptEDAT(const fs::file& input, const std::string& input_file_name, int mode, u8 *custom_klic, bool verbose = false);
fs::file DecryptEDAT(const fs::file& input, const std::string& input_file_name, int mode, u8 *custom_klic);
void package_reader::extract_worker(thread_key thread_data_key)
{
std::vector<u8> read_cache;
while (m_num_failures == 0 && !m_aborted)
{
// Make sure m_entry_indexer does not exceed m_install_entries
@@ -941,42 +943,195 @@ void package_reader::extract_worker(thread_key thread_data_key)
pkg_log.warning("NPDRM EDAT!");
}
if (fs::file out = is_buffered ? fs::make_stream<std::vector<u8>>() : fs::file{ path, did_overwrite ? fs::rewrite : fs::write_new })
if (fs::file out{ path, did_overwrite ? fs::rewrite : fs::write_new })
{
bool extract_success = true;
for (u64 pos = 0; pos < entry.file_size; pos += BUF_SIZE)
struct pkg_file_reader : fs::file_base
{
const u64 block_size = std::min<u64>(BUF_SIZE, entry.file_size - pos);
const std::function<u64(u64, void*, u64)> m_read_func;
const install_entry& m_entry;
usz m_pos;
const std::span<const char> data_span = decrypt(entry.file_offset + pos, block_size, is_psp ? PKG_AES_KEY2 : m_dec_key.data(), thread_data_key);
if (data_span.size() != block_size)
explicit pkg_file_reader(std::function<u64(u64, void* buffer, u64)> read_func, const install_entry& entry) noexcept
: m_read_func(std::move(read_func))
, m_entry(entry)
, m_pos(0)
{
extract_success = false;
pkg_log.error("Failed to extract file %s (data_span.size=%d, block_size=%d)", path, data_span.size(), block_size);
break;
}
if (out.write(data_span.data(), block_size) != block_size)
fs::stat_t get_stat() override
{
extract_success = false;
pkg_log.error("Failed to write file %s (error=%s)", path, fs::g_tls_error);
break;
fs::stat_t stat{};
stat.size = m_entry.file_size;
return stat;
}
m_written_bytes += block_size;
}
bool trunc(u64) override
{
return false;
}
u64 read(void* buffer, u64 size) override
{
const u64 result = pkg_file_reader::read_at(m_pos, buffer, size);
m_pos += result;
return result;
}
u64 read_at(u64 offset, void* buffer, u64 size) override
{
return m_read_func(offset, buffer, size);
}
u64 write(const void*, u64) override
{
return 0;
}
u64 seek(s64 offset, fs::seek_mode whence) override
{
const s64 new_pos =
whence == fs::seek_set ? offset :
whence == fs::seek_cur ? offset + m_pos :
whence == fs::seek_end ? offset + size() : -1;
if (new_pos < 0)
{
fs::g_tls_error = fs::error::inval;
return -1;
}
m_pos = new_pos;
return m_pos;
}
u64 size() override
{
return m_entry.file_size;
}
fs::file_id get_id() override
{
fs::file_id id{};
id.type.insert(0, "pkg_file_reader: "sv);
return id;
}
};
read_cache.clear();
auto reader = std::make_unique<pkg_file_reader>([&, cache_off = u64{umax}](usz pos, void* ptr, usz size) mutable -> u64
{
if (pos >= entry.file_size || !size)
{
return 0;
}
size = std::min<u64>(entry.file_size - pos, size);
u64 size_cache_end = 0;
u64 read_size = 0;
// Check if exists in cache
if (!read_cache.empty() && cache_off <= pos && pos < cache_off + read_cache.size())
{
read_size = std::min<u64>(pos + size, cache_off + read_cache.size()) - pos;
std::memcpy(ptr, read_cache.data() + (pos - cache_off), read_size);
pos += read_size;
}
else if (!read_cache.empty() && cache_off < pos + size && cache_off + read_cache.size() >= pos + size)
{
size_cache_end = size - (std::max<u64>(cache_off, pos) - pos);
std::memcpy(static_cast<u8*>(ptr) + (cache_off - pos), read_cache.data(), size_cache_end);
size -= size_cache_end;
}
if (pos >= entry.file_size || !size)
{
return read_size + size_cache_end;
}
// Try to cache for later
if (size <= BUF_SIZE && !size_cache_end && !read_size)
{
const u64 block_size = std::min<u64>({BUF_SIZE, std::max<u64>(size * 5 / 3, 65536), entry.file_size - pos});
read_cache.resize(block_size);
cache_off = pos;
const std::span<const char> data_span = decrypt(entry.file_offset + pos, block_size, is_psp ? PKG_AES_KEY2 : m_dec_key.data(), thread_data_key);
if (data_span.empty())
{
cache_off = umax;
read_cache.clear();
return 0;
}
read_cache.resize(data_span.size());
std::memcpy(read_cache.data(), data_span.data(), data_span.size());
size = std::min<usz>(data_span.size(), size);
std::memcpy(ptr, data_span.data(), size);
return size;
}
while (read_size < size)
{
const u64 block_size = std::min<u64>(BUF_SIZE, size - read_size);
const std::span<const char> data_span = decrypt(entry.file_offset + pos, block_size, is_psp ? PKG_AES_KEY2 : m_dec_key.data(), thread_data_key);
if (data_span.empty())
{
break;
}
std::memcpy(static_cast<u8*>(ptr) + read_size, data_span.data(), data_span.size());
read_size += data_span.size();
pos += data_span.size();
}
return read_size + size_cache_end;
}, entry);
fs::file in_data;
in_data.reset(std::move(reader));
fs::file final_data;
if (is_buffered)
{
out = DecryptEDAT(out, name, 1, reinterpret_cast<u8*>(&m_header.klicensee), true);
if (!out || !fs::write_file(path, fs::rewrite, static_cast<fs::container_stream<std::vector<u8>>*>(out.release().get())->obj))
{
m_num_failures++;
pkg_log.error("Failed to create file %s (error=%s)", path, fs::g_tls_error);
break;
}
final_data = DecryptEDAT(in_data, name, 1, reinterpret_cast<u8*>(&m_header.klicensee));
}
else
{
final_data = std::move(in_data);
}
if (!final_data)
{
m_num_failures++;
pkg_log.error("Failed to decrypt EDAT file %s (error=%s)", path, fs::g_tls_error);
break;
}
// 16MB buffer
std::vector<u8> buffer(std::min<usz>(entry.file_size, 1u << 24));
while (usz read_size = final_data.read(buffer.data(), buffer.size()))
{
out.write(buffer.data(), read_size);
m_written_bytes += read_size;
}
final_data.close();
out.close();
if (extract_success)
{
+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 -6
View File
@@ -12,10 +12,6 @@
#include <Windows.h>
#include <system_error>
#ifdef _MSC_VER
#pragma comment(lib, "xaudio2_9redist.lib")
#endif
#ifndef XAUDIO2_USE_DEFAULT_PROCESSOR
#define XAUDIO2_USE_DEFAULT_PROCESSOR XAUDIO2_DEFAULT_PROCESSOR
#endif
@@ -202,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())
{
@@ -258,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 -5
View File
@@ -8,12 +8,8 @@
#include "Utilities/mutex.h"
#include "Emu/Audio/AudioBackend.h"
#ifdef _MSC_VER
#include <xaudio2redist.h>
#else
#include <initguid.h>
#include <xaudio2.h>
#endif
#include <wrl/client.h>
#include <MMDeviceAPI.h>
@@ -32,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;
+85 -84
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
@@ -56,7 +57,8 @@ target_sources(rpcs3_emu PRIVATE
../../Utilities/cond.cpp
../../Utilities/Config.cpp
../../Utilities/File.cpp
../../Utilities/JIT.cpp
../../Utilities/JITASM.cpp
../../Utilities/JITLLVM.cpp
../../Utilities/LUrlParser.cpp
../../Utilities/mutex.cpp
../../Utilities/rXml.cpp
@@ -79,29 +81,15 @@ target_link_libraries(rpcs3_emu
PUBLIC
3rdparty::pugixml)
if(MSVC)
set_source_files_properties("../../Utilities/JIT.cpp" PROPERTIES
COMPILE_FLAGS /GR-
SKIP_PRECOMPILE_HEADERS ON
)
else()
set_source_files_properties("../../Utilities/JIT.cpp" PROPERTIES
COMPILE_FLAGS -fno-rtti
SKIP_PRECOMPILE_HEADERS ON
)
endif()
set_source_files_properties("../../Utilities/JITLLVM.cpp" "../../Utilities/JITASM.cpp" PROPERTIES
COMPILE_FLAGS "$<IF:$<CXX_COMPILER_ID:MSVC>,/GR-,-fno-rtti>"
SKIP_PRECOMPILE_HEADERS ON
)
if(MSVC)
set_source_files_properties("../util/yaml.cpp" PROPERTIES
COMPILE_FLAGS /EHsc
SKIP_PRECOMPILE_HEADERS ON
)
else()
set_source_files_properties("../util/yaml.cpp" PROPERTIES
COMPILE_FLAGS -fexceptions
SKIP_PRECOMPILE_HEADERS ON
)
endif()
set_source_files_properties("../util/yaml.cpp" PROPERTIES
COMPILE_FLAGS "$<IF:$<CXX_COMPILER_ID:MSVC>,/EHsc,-fexceptions>"
SKIP_PRECOMPILE_HEADERS ON
)
# Crypto
target_sources(rpcs3_emu PRIVATE
@@ -154,18 +142,14 @@ if(USE_FAUDIO)
endif()
if(WIN32)
target_include_directories(rpcs3_emu PUBLIC "${PROJECT_SOURCE_DIR}/3rdparty/XAudio2Redist/include")
if(MSVC)
target_link_libraries(rpcs3_emu PRIVATE "${PROJECT_SOURCE_DIR}/3rdparty/XAudio2Redist/libs/xaudio2_9redist.lib")
target_link_options(rpcs3_emu PRIVATE /DELAYLOAD:xaudio2_9redist.dll)
else()
target_link_libraries(rpcs3_emu PRIVATE xaudio2_8)
if(NOT MSVC)
target_link_libraries(rpcs3_emu PRIVATE xaudio2_9)
endif()
target_sources(rpcs3_emu PRIVATE
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
@@ -199,7 +183,8 @@ target_sources(rpcs3_emu PRIVATE
Cell/SPUASMJITRecompiler.cpp
Cell/SPUDisAsm.cpp
Cell/SPUInterpreter.cpp
Cell/SPURecompiler.cpp
Cell/SPUCommonRecompiler.cpp
Cell/SPULLVMRecompiler.cpp
Cell/SPUThread.cpp
Cell/lv2/lv2.cpp
Cell/lv2/sys_bdemu.cpp
@@ -359,6 +344,7 @@ target_sources(rpcs3_emu PRIVATE
Cell/Modules/sceNpCommerce2.cpp
Cell/Modules/sceNp.cpp
Cell/Modules/sceNpMatchingInt.cpp
Cell/Modules/sceNpPlus.cpp
Cell/Modules/sceNpSns.cpp
Cell/Modules/sceNpTrophy.cpp
Cell/Modules/sceNpTus.cpp
@@ -409,24 +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/Buzz.cpp
Io/Turntable.cpp
Io/usio.cpp
)
@@ -459,32 +449,62 @@ 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
RSX/Overlays/HomeMenu/overlay_home_menu_message_box.cpp
RSX/Overlays/HomeMenu/overlay_home_menu_page.cpp
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
@@ -500,47 +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/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)
+88 -16
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);
}
@@ -952,7 +973,7 @@ bool cpu_thread::check_state() noexcept
continue;
}
if (state0 & cpu_flag::yield && cpu_flag::wait - state0 && cpu_can_stop)
if (state0 & cpu_flag::yield && cpu_can_stop)
{
if (auto spu = try_get<spu_thread>())
{
@@ -964,6 +985,14 @@ bool cpu_thread::check_state() noexcept
}
else if (auto ppu = try_get<ppu_thread>())
{
if (u32 usec = ppu->hw_sleep_time)
{
thread_ctrl::wait_for_accurate(usec);
ppu->hw_sleep_time = 0;
ppu->raddr = 0; // Also lose reservation if there is any (reservation is unsaved on hw thread switch)
continue;
}
if (ppu->raddr && ppu->rtime == vm::reservation_acquire(ppu->raddr))
{
// Same
@@ -1064,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
@@ -1403,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;
@@ -1414,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;
}
@@ -1429,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)
{
@@ -1441,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;
@@ -1449,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;
@@ -1478,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;
@@ -1550,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;
+105 -9
View File
@@ -43,6 +43,9 @@
#include <functional>
#include <unordered_map>
// Helper function
llvm::Value* peek_through_bitcasts(llvm::Value*);
enum class i2 : char
{
};
@@ -122,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;
@@ -147,7 +150,7 @@ struct llvm_value_t
std::tuple<> match(llvm::Value*& value, llvm::Module*) const
{
if (value != this->value)
if (peek_through_bitcasts(value) != peek_through_bitcasts(this->value))
{
value = nullptr;
}
@@ -414,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>;
@@ -503,9 +506,6 @@ using llvm_common_t = std::enable_if_t<(is_llvm_expr_of<T, Types>::ok && ...), t
template <typename... Args>
using llvm_match_tuple = decltype(std::tuple_cat(std::declval<llvm_expr_t<Args>&>().match(std::declval<llvm::Value*&>(), nullptr)...));
// Helper function
llvm::Value* peek_through_bitcasts(llvm::Value*);
template <typename T, typename U = llvm_common_t<llvm_value_t<T>>>
struct llvm_match_t
{
@@ -532,7 +532,7 @@ struct llvm_match_t
std::tuple<> match(llvm::Value*& value, llvm::Module*) const
{
if (value != this->value)
if (peek_through_bitcasts(value) != peek_through_bitcasts(this->value))
{
value = nullptr;
}
@@ -685,6 +685,18 @@ struct llvm_add
return std::tuple_cat(r1, r2);
}
}
v1 = i->getOperand(0);
v2 = i->getOperand(1);
// Argument order does not matter here, try when swapped
if (auto r1 = a1.match(v2, _m); v2)
{
if (auto r2 = a2.match(v1, _m); v1)
{
return std::tuple_cat(r1, r2);
}
}
}
value = nullptr;
@@ -858,6 +870,18 @@ struct llvm_mul
return std::tuple_cat(r1, r2);
}
}
v1 = i->getOperand(0);
v2 = i->getOperand(1);
// Argument order does not matter here, try when swapped
if (auto r1 = a1.match(v2, _m); v2)
{
if (auto r2 = a2.match(v1, _m); v1)
{
return std::tuple_cat(r1, r2);
}
}
}
value = nullptr;
@@ -2239,6 +2263,18 @@ struct llvm_add_sat
return std::tuple_cat(r1, r2);
}
}
v1 = i->getOperand(0);
v2 = i->getOperand(1);
// Argument order does not matter here, try when swapped
if (auto r1 = a1.match(v2, _m); v2)
{
if (auto r2 = a2.match(v1, _m); v1)
{
return std::tuple_cat(r1, r2);
}
}
}
value = nullptr;
@@ -2868,6 +2904,22 @@ struct llvm_fmuladd
}
}
}
v1 = i->getOperand(0);
v2 = i->getOperand(1);
v3 = i->getOperand(2);
// With multiplication args swapped
if (auto r1 = a1.match(v2, _m); v2)
{
if (auto r2 = a2.match(v1, _m); v1)
{
if (auto r3 = a3.match(v3, _m); v3)
{
return std::tuple_cat(r1, r2, r3);
}
}
}
}
value = nullptr;
@@ -2884,6 +2936,18 @@ struct llvm_calli
std::tuple<llvm_expr_t<A>...> a;
std::array<usz, sizeof...(A)> order_equality_hint = []()
{
std::array<usz, sizeof...(A)> r{};
for (usz i = 0; i < r.size(); i++)
{
r[i] = i;
}
return r;
}();
llvm::Value*(*c)(llvm::Value**, llvm::IRBuilder<>*){};
llvm::Value* eval(llvm::IRBuilder<>* ir) const
@@ -2917,6 +2981,13 @@ struct llvm_calli
return *this;
}
template <typename... Args> requires (sizeof...(Args) == sizeof...(A))
llvm_calli& set_order_equality_hint(Args... args)
{
order_equality_hint = {static_cast<usz>(args)...};
return *this;
}
llvm_match_tuple<A...> match(llvm::Value*& value, llvm::Module* _m) const
{
return match(value, _m, std::make_index_sequence<sizeof...(A)>());
@@ -2939,6 +3010,20 @@ struct llvm_calli
{
return std::tuple_cat(std::get<I>(r)...);
}
if constexpr (sizeof...(A) >= 2)
{
if (order_equality_hint[0] == order_equality_hint[1])
{
// Test if it works with the first pair swapped
((v[I <= 1 ? I ^ 1 : I] = i->getOperand(I)), ...);
if (((std::get<I>(r) = std::get<I>(a).match(v[I], _m), v[I]) && ...))
{
return std::tuple_cat(std::get<I>(r)...);
}
}
}
}
}
@@ -3618,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;
@@ -3632,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());
+13 -10
View File
@@ -278,7 +278,7 @@ public:
#endif
AVCodecContext* ctx = nullptr;
AVFormatContext* fmt = nullptr;
u8* io_buf;
u8* io_buf = nullptr;
struct AudioReader
{
@@ -371,17 +371,16 @@ public:
}
if (ctx)
{
avcodec_close(ctx);
avformat_close_input(&fmt);
avcodec_free_context(&ctx);
}
if (io_buf)
{
av_freep(&io_buf);
}
if (fmt)
{
if (io_buf)
{
av_free(io_buf);
}
if (fmt->pb) av_free(fmt->pb);
avformat_free_context(fmt);
if (fmt->pb) av_freep(&fmt->pb);
avformat_close_input(&fmt);
}
}
@@ -451,7 +450,11 @@ public:
}
AVPacket* packet = av_packet_alloc();
std::unique_ptr<AVPacket, decltype([](AVPacket* p){av_packet_unref(p);})> packet_(packet);
std::unique_ptr<AVPacket, decltype([](AVPacket* p)
{
av_packet_unref(p);
av_packet_free(&p);
})> packet_(packet);
if (just_started && just_finished)
{
+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);
}
File diff suppressed because it is too large Load Diff
+104 -3
View File
@@ -94,12 +94,30 @@ enum
CELL_FONT_TYPE_SEURAT_CAPIE_MARU_GOTHIC_VAGR2_SET = 0x00300224,
};
enum
{
CELL_FONT_LIBRARY_TYPE_NONE = 0
};
enum
{
CELL_FONT_MAP_FONT = 0,
CELL_FONT_MAP_UNICODE = 1,
};
enum
{
CELL_FONT_OPEN_MODE_DEFAULT = 0,
CELL_FONT_OPEN_MODE_IGNORE_VERTICAL_METRICS = 1,
};
enum
{
CELL_FONT_GRAPHICS_DRAW_TYPE_MONO = 0,
CELL_FONT_GRAPHICS_DRAW_TYPE_COLOR = 1,
CELL_FONT_GRAPHICS_DRAW_TYPE_COLOR_REVERSE = 2,
};
//Custom enum to determine the origin of a CellFont object
enum
{
@@ -109,6 +127,8 @@ enum
CELL_FONT_OPEN_MEMORY,
};
constexpr f32 CELL_FONT_GLYPH_OUTLINE_CONTROL_DISTANCE_DEFAULT = 0.125f;
using CellFontMallocCallback = vm::ptr<void>(vm::ptr<void> arg, u32 size);
using CellFontFreeCallback = void(vm::ptr<void> arg, vm::ptr<void> ptr);
@@ -148,7 +168,7 @@ struct CellFontLibrary
{
be_t<u32> libraryType;
be_t<u32> libraryVersion;
// ...
vm::bptr<u32> SystemClosed;
};
struct CellFontType
@@ -171,6 +191,24 @@ struct CellFontVerticalLayout
be_t<f32> effectWidth;
};
struct CellFontVertexesGlyphSubHeader
{
be_t<u32> size;
be_t<f32> SystemReserved[11];
};
struct CellFontVertexesGlyphData
{
const be_t<u32> size;
vm::bptr<f32> SystemClosed;
};
struct CellFontVertexesGlyph
{
vm::bptr<CellFontVertexesGlyphData> data;
vm::bptr<CellFontVertexesGlyphSubHeader> subHeader;
};
struct CellFontGlyphMetrics
{
be_t<f32> width;
@@ -185,6 +223,64 @@ struct CellFontGlyphMetrics
be_t<f32> v_advance;
};
struct CellFontGlyphOutline
{
be_t<s16> contoursCount;
be_t<s16> pointsCount;
struct Point
{
be_t<f32> x;
be_t<f32> y;
};
vm::bptr<Point> points;
vm::bptr<u8> pointTags;
vm::bptr<u16> contourIndexs;
be_t<u32> flags;
vm::bptr<void> generateEnv;
};
using CellFontGetOutlineVertexCallback = vm::ptr<void>(vm::ptr<void> arg, s32 contourN, s32 vertexNumber, s32 vertexAttr, f32 x, f32 y);
struct CellFontGetOutlineVertexesIF
{
vm::bptr<CellFontGetOutlineVertexCallback> callback;
vm::bptr<void> arg;
};
struct CellFontGlyphBoundingBox
{
be_t<f32> min_x;
be_t<f32> min_y;
be_t<f32> max_x;
be_t<f32> max_y;
};
struct CellFontKerning
{
be_t<f32> offsetX;
be_t<f32> offsetY;
};
struct CellFontGlyphStyle
{
be_t<f32> scale_widthPixel;
be_t<f32> scale_heightPixel;
be_t<f32> effect_weight;
be_t<f32> effect_slant;
};
struct CellFontGlyph
{
be_t<u16> CF_type;
be_t<u16> type;
be_t<u32> size;
CellFontGlyphMetrics Metrics;
CellFontGlyphOutline Outline;
};
struct CellFontRenderSurface
{
vm::bptr<void> buffer;
@@ -235,11 +331,16 @@ struct CellFontRendererConfig
struct CellFontRenderer
{
void *systemReserved[64];
vm::bptr<void> systemReserved[64];
};
struct CellFontGraphics
{
be_t<u32> graphicsType;
// ...
vm::bptr<uint32_t> SystemClosed;
};
struct CellFontGraphicsDrawContext
{
vm::bptr<void> SystemReserved[64];
};
+49 -12
View File
@@ -5,30 +5,67 @@
LOG_CHANNEL(cellFontFT);
error_code cellFontInitLibraryFreeType()
{
UNIMPLEMENTED_FUNC(cellFontFT);
return CELL_OK;
}
error_code cellFontInitLibraryFreeTypeWithRevision(u64 revisionFlags, vm::ptr<CellFontLibraryConfigFT> config, vm::pptr<CellFontLibrary> lib)
{
cellFontFT.warning("cellFontInitLibraryFreeTypeWithRevision(revisionFlags=0x%llx, config=*0x%x, lib=**0x%x)", revisionFlags, config, lib);
cellFontFT.todo("cellFontInitLibraryFreeTypeWithRevision(revisionFlags=0x%llx, config=*0x%x, lib=**0x%x)", revisionFlags, config, lib);
if (!lib)
{
return CELL_FONT_ERROR_INVALID_PARAMETER;
}
*lib = {};
if (!config)
{
return CELL_FONT_ERROR_INVALID_PARAMETER;
}
if (false) // TODO
{
return CELL_FONT_ERROR_UNINITIALIZED;
}
lib->set(vm::alloc(sizeof(CellFontLibrary), vm::main));
return CELL_OK;
}
error_code cellFontFTGetRevisionFlags()
error_code cellFontInitLibraryFreeType(vm::ptr<CellFontLibraryConfigFT> config, vm::pptr<CellFontLibrary> lib)
{
UNIMPLEMENTED_FUNC(cellFontFT);
return CELL_OK;
cellFontFT.todo("cellFontInitLibraryFreeType(config=*0x%x, lib=**0x%x)", config, lib);
uint64_t revisionFlags = 0LL;
//cellFontFTGetStubRevisionFlags(&revisionFlags);
return cellFontInitLibraryFreeTypeWithRevision(revisionFlags, config, lib);
}
error_code cellFontFTGetInitializedRevisionFlags()
void cellFontFTGetRevisionFlags(vm::ptr<u64> revisionFlags)
{
UNIMPLEMENTED_FUNC(cellFontFT);
cellFontFT.notice("cellFontFTGetRevisionFlags(revisionFlags=*0x%x)", revisionFlags);
if (revisionFlags)
{
*revisionFlags = 0x43;
}
}
error_code cellFontFTGetInitializedRevisionFlags(vm::ptr<u64> revisionFlags)
{
cellFontFT.notice("cellFontFTGetInitializedRevisionFlags(revisionFlags=*0x%x)", revisionFlags);
if (!revisionFlags)
{
return CELL_FONT_ERROR_INVALID_PARAMETER;
}
if (false) // TODO
{
return CELL_FONT_ERROR_UNINITIALIZED;
}
//*revisionFlags = something; // TODO
return CELL_OK;
}
+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();
+137 -54
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)
{
@@ -114,6 +119,20 @@ void fmt_class_string<CellGemVideoConvertFormatEnum>::format(std::string& out, u
});
}
// last 4 out of 7 ports (7,6,5,4). index starts at 1
static u32 port_num(u32 gem_num)
{
ensure(gem_num < CELL_GEM_MAX_NUM);
return CELL_PAD_MAX_PORT_NUM - gem_num;
}
// last 4 out of 7 ports (6,5,4,3). index starts at 0
static u32 pad_num(u32 gem_num)
{
ensure(gem_num < CELL_GEM_MAX_NUM);
return (CELL_PAD_MAX_PORT_NUM - 1) - gem_num;
}
// **********************
// * HLE helper structs *
// **********************
@@ -278,12 +297,44 @@ public:
return;
}
bool is_connected = false;
switch (g_cfg.io.move)
{
case move_handler::fake:
case move_handler::mouse:
{
connected_controllers = 1;
connected_controllers = 0;
std::lock_guard lock(pad::g_pad_mutex);
const auto handler = pad::get_current_handler();
for (u32 i = 0; i < std::min<u32>(attribute.max_connect, CELL_GEM_MAX_NUM); i++)
{
const auto& pad = ::at32(handler->GetPads(), pad_num(i));
if (pad && (pad->m_port_status & CELL_PAD_STATUS_CONNECTED))
{
connected_controllers++;
if (gem_num == i)
{
is_connected = true;
}
}
}
break;
}
case move_handler::mouse:
case move_handler::raw_mouse:
{
auto& handler = g_fxo->get<MouseHandlerBase>();
// Make sure that the mouse handler is initialized
handler.Init(std::min<u32>(attribute.max_connect, CELL_GEM_MAX_NUM));
const MouseInfo& info = handler.GetInfo();
connected_controllers = std::min<u32>({ info.now_connect, attribute.max_connect, CELL_GEM_MAX_NUM });
if (gem_num < connected_controllers)
{
is_connected = true;
}
break;
}
#ifdef HAVE_LIBEVDEV
@@ -291,8 +342,13 @@ public:
{
gun_thread& gun = g_fxo->get<gun_thread>();
std::scoped_lock lock(gun.handler.mutex);
connected_controllers = gun.handler.init() ? gun.handler.get_num_guns() : 0;
gun.num_devices = connected_controllers;
gun.num_devices = gun.handler.init() ? gun.handler.get_num_guns() : 0;
connected_controllers = std::min<u32>(std::min<u32>(attribute.max_connect, CELL_GEM_MAX_NUM), gun.num_devices);
if (gem_num < connected_controllers)
{
is_connected = true;
}
break;
}
#endif
@@ -306,10 +362,10 @@ public:
controller.sphere_rgb = gem_color::get_default_color(gem_num);
// Assign status and port number
if (gem_num < connected_controllers)
if (is_connected)
{
controller.status = CELL_GEM_STATUS_READY;
controller.port = CELL_PAD_MAX_PORT_NUM - gem_num;
controller.port = port_num(gem_num);
}
}
@@ -442,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);
}
}
}
@@ -541,8 +594,8 @@ static bool check_gem_num(const u32 gem_num)
static inline void draw_overlay_cursor(u32 gem_num, const gem_config::gem_controller&, s32 x_pos, s32 y_pos, s32 x_max, s32 y_max)
{
const u16 x = static_cast<u16>(x_pos / (x_max / static_cast<f32>(rsx::overlays::overlay::virtual_width)));
const u16 y = static_cast<u16>(y_pos / (y_max / static_cast<f32>(rsx::overlays::overlay::virtual_height)));
const s16 x = static_cast<s16>(x_pos / (x_max / static_cast<f32>(rsx::overlays::overlay::virtual_width)));
const s16 y = static_cast<s16>(y_pos / (y_max / static_cast<f32>(rsx::overlays::overlay::virtual_height)));
// Note: We shouldn't use sphere_rgb here. The game will set it to black in many cases.
const gem_config_data::gem_color& rgb = gem_config_data::gem_color::get_default_color(gem_num);
@@ -638,12 +691,12 @@ extern bool is_input_allowed();
/**
* \brief Maps Move controller data (digital buttons, and analog Trigger data) to DS3 pad input.
* Unavoidably buttons conflict with DS3 mappings, which is problematic for some games.
* \param port_no DS3 port number to use
* \param gem_num gem index to use
* \param digital_buttons Bitmask filled with CELL_GEM_CTRL_* values
* \param analog_t Analog value of Move's Trigger. Currently mapped to R2.
* \return true on success, false if port_no controller is invalid
* \return true on success, false if controller is disconnected
*/
static void ds3_input_to_pad(const u32 port_no, be_t<u16>& digital_buttons, be_t<u16>& analog_t)
static void ds3_input_to_pad(const u32 gem_num, be_t<u16>& digital_buttons, be_t<u16>& analog_t)
{
digital_buttons = 0;
analog_t = 0;
@@ -656,14 +709,14 @@ static void ds3_input_to_pad(const u32 port_no, be_t<u16>& digital_buttons, be_t
std::lock_guard lock(pad::g_pad_mutex);
const auto handler = pad::get_current_handler();
const auto& pad = ::at32(handler->GetPads(), port_no);
const auto& pad = ::at32(handler->GetPads(), pad_num(gem_num));
if (!(pad->m_port_status & CELL_PAD_STATUS_CONNECTED))
{
return;
}
const auto& cfg = ::at32(g_cfg_gem.players, port_no);
const auto& cfg = ::at32(g_cfg_gem.players, gem_num);
cfg->handle_input(pad, true, [&](gem_btn btn, u16 value, bool pressed)
{
if (!pressed)
@@ -707,12 +760,12 @@ static void ds3_input_to_pad(const u32 port_no, be_t<u16>& digital_buttons, be_t
constexpr u16 ds3_max_x = 255;
constexpr u16 ds3_max_y = 255;
static inline void ds3_get_stick_values(u32 port_no, const std::shared_ptr<Pad>& pad, s32& x_pos, s32& y_pos)
static inline void ds3_get_stick_values(u32 gem_num, const std::shared_ptr<Pad>& pad, s32& x_pos, s32& y_pos)
{
x_pos = 0;
y_pos = 0;
const auto& cfg = ::at32(g_cfg_gem.players, port_no);
const auto& cfg = ::at32(g_cfg_gem.players, gem_num);
cfg->handle_input(pad, true, [&](gem_btn btn, u16 value, bool pressed)
{
if (!pressed)
@@ -733,7 +786,7 @@ static inline void ds3_get_stick_values(u32 port_no, const std::shared_ptr<Pad>&
}
template <typename T>
static void ds3_pos_to_gem_state(const u32 port_no, const gem_config::gem_controller& controller, T& gem_state)
static void ds3_pos_to_gem_state(u32 gem_num, const gem_config::gem_controller& controller, T& gem_state)
{
if (!gem_state || !is_input_allowed())
{
@@ -743,7 +796,7 @@ static void ds3_pos_to_gem_state(const u32 port_no, const gem_config::gem_contro
std::lock_guard lock(pad::g_pad_mutex);
const auto handler = pad::get_current_handler();
const auto& pad = ::at32(handler->GetPads(), port_no);
const auto& pad = ::at32(handler->GetPads(), pad_num(gem_num));
if (!(pad->m_port_status & CELL_PAD_STATUS_CONNECTED))
{
@@ -751,15 +804,15 @@ static void ds3_pos_to_gem_state(const u32 port_no, const gem_config::gem_contro
}
s32 ds3_pos_x, ds3_pos_y;
ds3_get_stick_values(port_no, pad, 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(port_no, controller, gem_state, ds3_pos_x, ds3_pos_y, ds3_max_x, ds3_max_y);
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(port_no, controller, gem_state, ds3_pos_x, ds3_pos_y, ds3_max_x, ds3_max_y);
pos_to_gem_image_state(gem_num, controller, gem_state, ds3_pos_x, ds3_pos_y, ds3_max_x, ds3_max_y);
}
}
@@ -767,11 +820,11 @@ static void ds3_pos_to_gem_state(const u32 port_no, const gem_config::gem_contro
* \brief Maps external Move controller data to DS3 input. (This can be input from any physical pad, not just the DS3)
* Implementation detail: CellGemExtPortData's digital/analog fields map the same way as
* libPad, so no translation is needed.
* \param port_no DS3 port number to use
* \param gem_num gem index to use
* \param ext External data to modify
* \return true on success, false if port_no controller is invalid
* \return true on success, false if controller is disconnected
*/
static void ds3_input_to_ext(const u32 port_no, const gem_config::gem_controller& controller, CellGemExtPortData& ext)
static void ds3_input_to_ext(const u32 gem_num, const gem_config::gem_controller& controller, CellGemExtPortData& ext)
{
ext = {};
@@ -783,7 +836,7 @@ static void ds3_input_to_ext(const u32 port_no, const gem_config::gem_controller
std::lock_guard lock(pad::g_pad_mutex);
const auto handler = pad::get_current_handler();
const auto& pad = ::at32(handler->GetPads(), port_no);
const auto& pad = ::at32(handler->GetPads(), pad_num(gem_num));
if (!(pad->m_port_status & CELL_PAD_STATUS_CONNECTED))
{
@@ -896,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);
}
@@ -964,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);
}
@@ -1372,6 +1425,7 @@ error_code cellGemGetImageState(u32 gem_num, vm::ptr<CellGemImageState> gem_imag
ds3_pos_to_gem_state(gem_num, gem.controllers[gem_num], gem_image_state);
break;
case move_handler::mouse:
case move_handler::raw_mouse:
mouse_pos_to_gem_state(gem_num, gem.controllers[gem_num], gem_image_state);
break;
#ifdef HAVE_LIBEVDEV
@@ -1426,6 +1480,7 @@ error_code cellGemGetInertialState(u32 gem_num, u32 state_flag, u64 timestamp, v
ds3_input_to_pad(gem_num, inertial_state->pad.digitalbuttons, inertial_state->pad.analog_T);
break;
case move_handler::mouse:
case move_handler::raw_mouse:
mouse_input_to_pad(gem_num, inertial_state->pad.digitalbuttons, inertial_state->pad.analog_T);
break;
#ifdef HAVE_LIBEVDEV
@@ -1443,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>();
@@ -1460,6 +1515,33 @@ error_code cellGemGetInfo(vm::ptr<CellGemInfo> info)
}
// TODO: Support connecting PlayStation Move controllers
if (g_cfg.io.move == move_handler::fake)
{
gem.connected_controllers = 0;
std::lock_guard lock(pad::g_pad_mutex);
const auto handler = pad::get_current_handler();
for (u32 i = 0; i < CELL_GEM_MAX_NUM; i++)
{
const auto& pad = ::at32(handler->GetPads(), pad_num(i));
const bool connected = (pad && (pad->m_port_status & CELL_PAD_STATUS_CONNECTED) && i < gem.attribute.max_connect);
if (connected)
{
gem.connected_controllers++;
gem.controllers[i].status = CELL_GEM_STATUS_READY;
gem.controllers[i].port = port_num(i);
}
else
{
gem.controllers[i].status = CELL_GEM_STATUS_DISCONNECTED;
gem.controllers[i].port = 0;
}
}
}
info->max_connect = gem.attribute.max_connect;
info->now_connect = gem.connected_controllers;
@@ -1558,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
@@ -1603,6 +1685,7 @@ error_code cellGemGetState(u32 gem_num, u32 flag, u64 time_parameter, vm::ptr<Ce
ds3_pos_to_gem_state(gem_num, gem.controllers[gem_num], gem_state);
break;
case move_handler::mouse:
case move_handler::raw_mouse:
mouse_input_to_pad(gem_num, gem_state->pad.digitalbuttons, gem_state->pad.analog_T);
mouse_pos_to_gem_state(gem_num, gem.controllers[gem_num], gem_state);
break;
+258 -135
View File
@@ -40,7 +40,7 @@ ime_jp_manager::ime_jp_manager()
bool ime_jp_manager::addChar(u16 c)
{
if (!c || cursor >= (CELL_IMEJP_STRING_MAXLENGTH - 1) || cursor > input_string.length())
if (!c || cursor >= (CELL_IMEJP_STRING_MAXLENGTH - 1ULL) || cursor > input_string.length())
return false;
std::u16string tmp;
@@ -49,11 +49,29 @@ bool ime_jp_manager::addChar(u16 c)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wrestrict"
#endif
input_string.insert(cursor++, tmp);
input_string.insert(cursor, tmp);
#if defined(__GNUG__) && !defined(__clang__)
#pragma GCC diagnostic pop
#endif
cursor_end = cursor;
const usz cursor_old = cursor;
const bool cursor_was_in_focus = cursor >= focus_begin && cursor <= (focus_begin + focus_length);
move_cursor(1);
if (cursor_was_in_focus)
{
// Add this char to the focus
move_focus_end(1, false);
}
else
{
// Let's just move the focus to the cursor, so that it contains the new char.
focus_begin = cursor_old;
focus_length = 1;
move_focus(0); // Sanitize focus
}
input_state = CELL_IMEJP_BEFORE_CONVERT;
return true;
}
@@ -74,59 +92,138 @@ bool ime_jp_manager::addString(vm::cptr<u16> str)
bool ime_jp_manager::backspaceWord()
{
if (!cursor || cursor > CELL_IMEJP_STRING_MAXLENGTH || cursor > input_string.length())
return false;
input_string.erase(--cursor);
cursor_end = cursor;
if (input_string.empty())
input_state = CELL_IMEJP_BEFORE_INPUT;
return true;
return remove_character(false);
}
bool ime_jp_manager::deleteWord()
{
if (cursor >= (CELL_IMEJP_STRING_MAXLENGTH - 1) || cursor > (input_string.length() - 1))
return false;
return remove_character(true);
}
input_string.erase(cursor);
cursor_end = cursor;
bool ime_jp_manager::remove_character(bool forward)
{
if (!forward && !cursor)
{
return false;
}
const usz pos = forward ? cursor : (cursor - 1);
if (pos >= (CELL_IMEJP_STRING_MAXLENGTH - 1ULL) || pos >= input_string.length())
{
return false;
}
// Delete the character at the position
input_string.erase(pos, 1);
// Move cursor and focus
const bool deleted_part_of_focus = pos > focus_begin && pos <= (focus_begin + focus_length);
if (!forward)
{
move_cursor(-1);
}
if (deleted_part_of_focus)
{
move_focus_end(-1, false);
}
else if (focus_begin > pos)
{
move_focus(-1);
}
if (input_string.empty())
{
input_state = CELL_IMEJP_BEFORE_INPUT;
}
return true;
}
void ime_jp_manager::moveCursor(s8 amount)
void ime_jp_manager::clear_input()
{
cursor = 0;
focus_begin = 0;
focus_length = 0;
input_string.clear();
converted_string.clear();
}
void ime_jp_manager::move_cursor(s8 amount)
{
cursor = std::max(0, std::min(static_cast<s32>(cursor) + amount, ::narrow<s32>(input_string.length())));
}
void ime_jp_manager::move_focus(s8 amount)
{
focus_begin = std::max(0, std::min(static_cast<s32>(focus_begin) + amount, ::narrow<s32>(input_string.length())));
move_focus_end(amount, false);
}
void ime_jp_manager::move_focus_end(s8 amount, bool wrap_around)
{
if (focus_begin >= input_string.length())
{
focus_length = 0;
return;
}
constexpr usz min_length = 1;
const usz max_length = input_string.length() - focus_begin;
if (amount > 0)
{
cursor = std::min(cursor + amount, input_string.length() - 1);
cursor_end = std::min(cursor_end + amount, input_string.length() - 1);
if (wrap_around && focus_length >= max_length)
{
focus_length = min_length;
}
else
{
focus_length += static_cast<usz>(amount);
}
}
else if (amount < 0)
{
cursor = std::max(0, static_cast<s32>(cursor) + amount);
cursor_end = std::max(static_cast<s32>(cursor), static_cast<s32>(cursor_end) + amount);
if (wrap_around && focus_length <= min_length)
{
focus_length = max_length;
}
else
{
focus_length = std::max(0, static_cast<s32>(focus_length) + amount);
}
}
focus_length = std::max(min_length, std::min(max_length, focus_length));
}
void ime_jp_manager::moveCursorEnd(s8 amount)
std::vector<ime_jp_manager::candidate> ime_jp_manager::get_candidate_list() const
{
if (amount > 0)
{
cursor_end = std::max(static_cast<s32>(cursor), std::min<s32>(static_cast<s32>(cursor_end) + amount, ::narrow<s32>(input_string.length()) - 1));
}
else if (amount < 0)
{
cursor_end = std::max(static_cast<s32>(cursor), static_cast<s32>(cursor_end) + amount);
}
std::vector<candidate> candidates;
if (input_string.empty() || focus_length == 0 || focus_begin >= input_string.length())
return candidates;
// TODO: we just fake this with one candidate for now
candidates.push_back(candidate{
.text = get_focus_string(),
.offset = 0
});
return candidates;
}
error_code cellImeJpOpen(sys_memory_container_t container_id, vm::ptr<CellImeJpHandle> hImeJpHandle, vm::cptr<CellImeJpAddDic> addDicPath)
std::u16string ime_jp_manager::get_focus_string() const
{
if (input_string.empty() || focus_length == 0 || focus_begin >= input_string.length())
return {};
return input_string.substr(focus_begin, focus_length);
}
static error_code cellImeJpOpen(sys_memory_container_t container_id, vm::ptr<CellImeJpHandle> hImeJpHandle, vm::cptr<CellImeJpAddDic> addDicPath)
{
cellImeJp.todo("cellImeJpOpen(container_id=*0x%x, hImeJpHandle=*0x%x, addDicPath=*0x%x)", container_id, hImeJpHandle, addDicPath);
@@ -156,7 +253,7 @@ error_code cellImeJpOpen(sys_memory_container_t container_id, vm::ptr<CellImeJpH
return CELL_OK;
}
error_code cellImeJpOpen2(sys_memory_container_t container_id, vm::ptr<CellImeJpHandle> hImeJpHandle, vm::cptr<CellImeJpAddDic> addDicPath)
static error_code cellImeJpOpen2(sys_memory_container_t container_id, vm::ptr<CellImeJpHandle> hImeJpHandle, vm::cptr<CellImeJpAddDic> addDicPath)
{
cellImeJp.todo("cellImeJpOpen2(container_id=*0x%x, hImeJpHandle=*0x%x, addDicPath=*0x%x)", container_id, hImeJpHandle, addDicPath);
@@ -187,7 +284,7 @@ error_code cellImeJpOpen2(sys_memory_container_t container_id, vm::ptr<CellImeJp
return CELL_OK;
}
error_code cellImeJpOpen3(sys_memory_container_t container_id, vm::ptr<CellImeJpHandle> hImeJpHandle, vm::cpptr<CellImeJpAddDic> addDicPath)
static error_code cellImeJpOpen3(sys_memory_container_t container_id, vm::ptr<CellImeJpHandle> hImeJpHandle, vm::cpptr<CellImeJpAddDic> addDicPath)
{
cellImeJp.todo("cellImeJpOpen3(container_id=*0x%x, hImeJpHandle=*0x%x, addDicPath=*0x%x)", container_id, hImeJpHandle, addDicPath);
@@ -224,13 +321,13 @@ error_code cellImeJpOpen3(sys_memory_container_t container_id, vm::ptr<CellImeJp
return CELL_OK;
}
error_code cellImeJpOpenExt()
static error_code cellImeJpOpenExt()
{
cellImeJp.todo("cellImeJpOpenExt()");
return CELL_OK;
}
error_code cellImeJpClose(CellImeJpHandle hImeJpHandle)
static error_code cellImeJpClose(CellImeJpHandle hImeJpHandle)
{
cellImeJp.todo("cellImeJpClose(hImeJpHandle=*0x%x)", hImeJpHandle);
@@ -243,17 +340,14 @@ error_code cellImeJpClose(CellImeJpHandle hImeJpHandle)
}
manager.input_state = CELL_IMEJP_BEFORE_INPUT;
manager.input_string.clear();
manager.converted_string.clear();
manager.clear_input();
manager.confirmed_string.clear();
manager.cursor = 0;
manager.cursor_end = 0;
manager.is_initialized = false;
return CELL_OK;
}
error_code cellImeJpSetKanaInputMode(CellImeJpHandle hImeJpHandle, s16 inputOption)
static error_code cellImeJpSetKanaInputMode(CellImeJpHandle hImeJpHandle, s16 inputOption)
{
cellImeJp.todo("cellImeJpSetKanaInputMode(hImeJpHandle=*0x%x, inputOption=%d)", hImeJpHandle, inputOption);
@@ -275,7 +369,7 @@ error_code cellImeJpSetKanaInputMode(CellImeJpHandle hImeJpHandle, s16 inputOpti
return CELL_OK;
}
error_code cellImeJpSetInputCharType(CellImeJpHandle hImeJpHandle, s16 charTypeOption)
static error_code cellImeJpSetInputCharType(CellImeJpHandle hImeJpHandle, s16 charTypeOption)
{
cellImeJp.todo("cellImeJpSetInputCharType(hImeJpHandle=*0x%x, charTypeOption=%d)", hImeJpHandle, charTypeOption);
@@ -292,7 +386,7 @@ error_code cellImeJpSetInputCharType(CellImeJpHandle hImeJpHandle, s16 charTypeO
return CELL_OK;
}
error_code cellImeJpSetFixInputMode(CellImeJpHandle hImeJpHandle, s16 fixInputMode)
static error_code cellImeJpSetFixInputMode(CellImeJpHandle hImeJpHandle, s16 fixInputMode)
{
cellImeJp.todo("cellImeJpSetFixInputMode(hImeJpHandle=*0x%x, fixInputMode=%d)", hImeJpHandle, fixInputMode);
@@ -309,7 +403,7 @@ error_code cellImeJpSetFixInputMode(CellImeJpHandle hImeJpHandle, s16 fixInputMo
return CELL_OK;
}
error_code cellImeJpAllowExtensionCharacters(CellImeJpHandle hImeJpHandle, s16 extensionCharacters)
static error_code cellImeJpAllowExtensionCharacters(CellImeJpHandle hImeJpHandle, s16 extensionCharacters)
{
cellImeJp.todo("cellImeJpSetFixInputMode(hImeJpHandle=*0x%x, extensionCharacters=%d)", hImeJpHandle, extensionCharacters);
@@ -331,7 +425,7 @@ error_code cellImeJpAllowExtensionCharacters(CellImeJpHandle hImeJpHandle, s16 e
return CELL_OK;
}
error_code cellImeJpReset(CellImeJpHandle hImeJpHandle)
static error_code cellImeJpReset(CellImeJpHandle hImeJpHandle)
{
cellImeJp.todo("cellImeJpReset(hImeJpHandle=*0x%x)", hImeJpHandle);
@@ -344,16 +438,13 @@ error_code cellImeJpReset(CellImeJpHandle hImeJpHandle)
}
manager.input_state = CELL_IMEJP_BEFORE_INPUT;
manager.input_string.clear();
manager.converted_string.clear();
manager.clear_input();
manager.confirmed_string.clear();
manager.cursor = 0;
manager.cursor_end = 0;
return CELL_OK;
}
error_code cellImeJpGetStatus(CellImeJpHandle hImeJpHandle, vm::ptr<s16> pInputStatus)
static error_code cellImeJpGetStatus(CellImeJpHandle hImeJpHandle, vm::ptr<s16> pInputStatus)
{
cellImeJp.warning("cellImeJpGetStatus(hImeJpHandle=*0x%x, pInputStatus=%d)", hImeJpHandle, pInputStatus);
@@ -375,7 +466,7 @@ error_code cellImeJpGetStatus(CellImeJpHandle hImeJpHandle, vm::ptr<s16> pInputS
return CELL_OK;
}
error_code cellImeJpEnterChar(CellImeJpHandle hImeJpHandle, u16 inputChar, vm::ptr<s16> pOutputStatus)
static error_code cellImeJpEnterChar(CellImeJpHandle hImeJpHandle, u16 inputChar, vm::ptr<s16> pOutputStatus)
{
cellImeJp.todo("cellImeJpEnterChar(hImeJpHandle=*0x%x, inputChar=%d, pOutputStatus=%d)", hImeJpHandle, inputChar, pOutputStatus);
@@ -404,13 +495,13 @@ error_code cellImeJpEnterChar(CellImeJpHandle hImeJpHandle, u16 inputChar, vm::p
return CELL_OK;
}
error_code cellImeJpEnterCharExt(CellImeJpHandle hImeJpHandle, u16 inputChar, vm::ptr<s16> pOutputStatus)
static error_code cellImeJpEnterCharExt(CellImeJpHandle hImeJpHandle, u16 inputChar, vm::ptr<s16> pOutputStatus)
{
cellImeJp.todo("cellImeJpEnterCharExt(hImeJpHandle=*0x%x, inputChar=%d, pOutputStatus=%d", hImeJpHandle, inputChar, pOutputStatus);
return cellImeJpEnterChar(hImeJpHandle, inputChar, pOutputStatus);
}
error_code cellImeJpEnterString(CellImeJpHandle hImeJpHandle, vm::cptr<u16> pInputString, vm::ptr<s16> pOutputStatus)
static error_code cellImeJpEnterString(CellImeJpHandle hImeJpHandle, vm::cptr<u16> pInputString, vm::ptr<s16> pOutputStatus)
{
cellImeJp.todo("cellImeJpEnterString(hImeJpHandle=*0x%x, pInputString=*0x%x, pOutputStatus=%d", hImeJpHandle, pInputString, pOutputStatus);
@@ -439,13 +530,13 @@ error_code cellImeJpEnterString(CellImeJpHandle hImeJpHandle, vm::cptr<u16> pInp
return CELL_OK;
}
error_code cellImeJpEnterStringExt(CellImeJpHandle hImeJpHandle, vm::cptr<u16> pInputString, vm::ptr<s16> pOutputStatus)
static error_code cellImeJpEnterStringExt(CellImeJpHandle hImeJpHandle, vm::cptr<u16> pInputString, vm::ptr<s16> pOutputStatus)
{
cellImeJp.todo("cellImeJpEnterStringExt(hImeJpHandle=*0x%x, pInputString=*0x%x, pOutputStatus=%d", hImeJpHandle, pInputString, pOutputStatus);
return cellImeJpEnterString(hImeJpHandle, pInputString, pOutputStatus);
}
error_code cellImeJpModeCaretRight(CellImeJpHandle hImeJpHandle)
static error_code cellImeJpModeCaretRight(CellImeJpHandle hImeJpHandle)
{
cellImeJp.todo("cellImeJpModeCaretRight(hImeJpHandle=*0x%x)", hImeJpHandle);
@@ -462,12 +553,12 @@ error_code cellImeJpModeCaretRight(CellImeJpHandle hImeJpHandle)
return CELL_IMEJP_ERROR_ERR;
}
manager.moveCursor(1);
manager.move_cursor(1);
return CELL_OK;
}
error_code cellImeJpModeCaretLeft(CellImeJpHandle hImeJpHandle)
static error_code cellImeJpModeCaretLeft(CellImeJpHandle hImeJpHandle)
{
cellImeJp.todo("cellImeJpModeCaretLeft(hImeJpHandle=*0x%x)", hImeJpHandle);
@@ -484,12 +575,12 @@ error_code cellImeJpModeCaretLeft(CellImeJpHandle hImeJpHandle)
return CELL_IMEJP_ERROR_ERR;
}
manager.moveCursor(-1);
manager.move_cursor(-1);
return CELL_OK;
}
error_code cellImeJpBackspaceWord(CellImeJpHandle hImeJpHandle)
static error_code cellImeJpBackspaceWord(CellImeJpHandle hImeJpHandle)
{
cellImeJp.todo("cellImeJpBackspaceWord(hImeJpHandle=*0x%x)", hImeJpHandle);
@@ -511,7 +602,7 @@ error_code cellImeJpBackspaceWord(CellImeJpHandle hImeJpHandle)
return CELL_OK;
}
error_code cellImeJpDeleteWord(CellImeJpHandle hImeJpHandle)
static error_code cellImeJpDeleteWord(CellImeJpHandle hImeJpHandle)
{
cellImeJp.todo("cellImeJpDeleteWord(hImeJpHandle=*0x%x)", hImeJpHandle);
@@ -533,7 +624,7 @@ error_code cellImeJpDeleteWord(CellImeJpHandle hImeJpHandle)
return CELL_OK;
}
error_code cellImeJpAllDeleteConvertString(CellImeJpHandle hImeJpHandle)
static error_code cellImeJpAllDeleteConvertString(CellImeJpHandle hImeJpHandle)
{
cellImeJp.todo("cellImeJpAllDeleteConvertString(hImeJpHandle=*0x%x)", hImeJpHandle);
@@ -550,16 +641,13 @@ error_code cellImeJpAllDeleteConvertString(CellImeJpHandle hImeJpHandle)
return CELL_IMEJP_ERROR_ERR;
}
manager.cursor = 0;
manager.cursor_end = 0;
manager.input_string.clear();
manager.converted_string.clear();
manager.clear_input();
manager.input_state = CELL_IMEJP_BEFORE_INPUT;
return CELL_OK;
}
error_code cellImeJpConvertForward(CellImeJpHandle hImeJpHandle)
static error_code cellImeJpConvertForward(CellImeJpHandle hImeJpHandle)
{
cellImeJp.todo("cellImeJpConvertForward(hImeJpHandle=*0x%x)", hImeJpHandle);
@@ -581,7 +669,7 @@ error_code cellImeJpConvertForward(CellImeJpHandle hImeJpHandle)
return CELL_OK;
}
error_code cellImeJpConvertBackward(CellImeJpHandle hImeJpHandle)
static error_code cellImeJpConvertBackward(CellImeJpHandle hImeJpHandle)
{
cellImeJp.todo("cellImeJpConvertBackward(hImeJpHandle=*0x%x)", hImeJpHandle);
@@ -603,7 +691,7 @@ error_code cellImeJpConvertBackward(CellImeJpHandle hImeJpHandle)
return CELL_OK;
}
error_code cellImeJpCurrentPartConfirm(CellImeJpHandle hImeJpHandle, s16 listItem)
static error_code cellImeJpCurrentPartConfirm(CellImeJpHandle hImeJpHandle, s16 listItem)
{
cellImeJp.todo("cellImeJpCurrentPartConfirm(hImeJpHandle=*0x%x, listItem=%d)", hImeJpHandle, listItem);
@@ -623,7 +711,7 @@ error_code cellImeJpCurrentPartConfirm(CellImeJpHandle hImeJpHandle, s16 listIte
return CELL_OK;
}
error_code cellImeJpAllConfirm(CellImeJpHandle hImeJpHandle)
static error_code cellImeJpAllConfirm(CellImeJpHandle hImeJpHandle)
{
cellImeJp.todo("cellImeJpAllConfirm(hImeJpHandle=*0x%x)", hImeJpHandle);
@@ -642,16 +730,13 @@ error_code cellImeJpAllConfirm(CellImeJpHandle hImeJpHandle)
// Use input_string for now
manager.confirmed_string = manager.input_string;
manager.cursor = 0;
manager.cursor_end = 0;
manager.input_string.clear();
manager.converted_string.clear();
manager.clear_input();
manager.input_state = CELL_IMEJP_BEFORE_INPUT;
return CELL_OK;
}
error_code cellImeJpAllConvertCancel(CellImeJpHandle hImeJpHandle)
static error_code cellImeJpAllConvertCancel(CellImeJpHandle hImeJpHandle)
{
cellImeJp.todo("cellImeJpAllConvertCancel(hImeJpHandle=*0x%x)", hImeJpHandle);
@@ -674,7 +759,7 @@ error_code cellImeJpAllConvertCancel(CellImeJpHandle hImeJpHandle)
return CELL_OK;
}
error_code cellImeJpConvertCancel(CellImeJpHandle hImeJpHandle)
static error_code cellImeJpConvertCancel(CellImeJpHandle hImeJpHandle)
{
cellImeJp.todo("cellImeJpConvertCancel(hImeJpHandle=*0x%x)", hImeJpHandle);
@@ -691,11 +776,13 @@ error_code cellImeJpConvertCancel(CellImeJpHandle hImeJpHandle)
return CELL_IMEJP_ERROR_ERR;
}
// TODO: only cancel all if cursor is at 0
return cellImeJpAllConvertCancel(hImeJpHandle);
manager.converted_string.clear();
manager.input_state = CELL_IMEJP_BEFORE_CONVERT;
return CELL_OK;
}
error_code cellImeJpExtendConvertArea(CellImeJpHandle hImeJpHandle)
static error_code cellImeJpExtendConvertArea(CellImeJpHandle hImeJpHandle)
{
cellImeJp.todo("cellImeJpExtendConvertArea(hImeJpHandle=*0x%x)", hImeJpHandle);
@@ -712,12 +799,13 @@ error_code cellImeJpExtendConvertArea(CellImeJpHandle hImeJpHandle)
return CELL_IMEJP_ERROR_ERR;
}
manager.moveCursorEnd(1);
// Move end of the focus by one. Wrap around if the focus end is already at the end of the input string.
manager.move_focus_end(1, true);
return CELL_OK;
}
error_code cellImeJpShortenConvertArea(CellImeJpHandle hImeJpHandle)
static error_code cellImeJpShortenConvertArea(CellImeJpHandle hImeJpHandle)
{
cellImeJp.todo("cellImeJpShortenConvertArea(hImeJpHandle=*0x%x)", hImeJpHandle);
@@ -734,12 +822,13 @@ error_code cellImeJpShortenConvertArea(CellImeJpHandle hImeJpHandle)
return CELL_IMEJP_ERROR_ERR;
}
manager.moveCursorEnd(-1);
// Move end of focus by one. Wrap around if the focus end is already at the beginning of the input string.
manager.move_focus_end(-1, true);
return CELL_OK;
}
error_code cellImeJpTemporalConfirm(CellImeJpHandle hImeJpHandle, s16 selectIndex)
static error_code cellImeJpTemporalConfirm(CellImeJpHandle hImeJpHandle, s16 selectIndex)
{
cellImeJp.todo("cellImeJpTemporalConfirm(hImeJpHandle=*0x%x, selectIndex=%d)", hImeJpHandle, selectIndex);
@@ -759,7 +848,7 @@ error_code cellImeJpTemporalConfirm(CellImeJpHandle hImeJpHandle, s16 selectInde
return CELL_OK;
}
error_code cellImeJpPostConvert(CellImeJpHandle hImeJpHandle, s16 postType)
static error_code cellImeJpPostConvert(CellImeJpHandle hImeJpHandle, s16 postType)
{
cellImeJp.todo("cellImeJpPostConvert(hImeJpHandle=*0x%x, postType=%d)", hImeJpHandle, postType);
@@ -779,7 +868,7 @@ error_code cellImeJpPostConvert(CellImeJpHandle hImeJpHandle, s16 postType)
return CELL_OK;
}
error_code cellImeJpMoveFocusClause(CellImeJpHandle hImeJpHandle, s16 moveType)
static error_code cellImeJpMoveFocusClause(CellImeJpHandle hImeJpHandle, s16 moveType)
{
cellImeJp.todo("cellImeJpMoveFocusClause(hImeJpHandle=*0x%x, moveType=%d)", hImeJpHandle, moveType);
@@ -799,17 +888,17 @@ error_code cellImeJpMoveFocusClause(CellImeJpHandle hImeJpHandle, s16 moveType)
switch (moveType)
{
case CELL_IMEJP_FOCUS_NEXT:
manager.moveCursor(1);
manager.move_focus(1);
break;
case CELL_IMEJP_FOCUS_BEFORE:
manager.moveCursor(-1);
manager.move_focus(-1);
break;
case CELL_IMEJP_FOCUS_TOP:
manager.moveCursor(-1 * ::narrow<s8>(manager.input_string.length()));
manager.move_focus(-1 * ::narrow<s8>(manager.input_string.length()));
break;
case CELL_IMEJP_FOCUS_END:
manager.moveCursor(::narrow<s8>(manager.input_string.length()));
manager.moveCursor(-1);
manager.move_focus(::narrow<s8>(manager.input_string.length()));
manager.move_focus(-1);
break;
default:
break;
@@ -820,7 +909,7 @@ error_code cellImeJpMoveFocusClause(CellImeJpHandle hImeJpHandle, s16 moveType)
return CELL_OK;
}
error_code cellImeJpGetFocusTop(CellImeJpHandle hImeJpHandle, vm::ptr<s16> pFocusTop)
static error_code cellImeJpGetFocusTop(CellImeJpHandle hImeJpHandle, vm::ptr<s16> pFocusTop)
{
cellImeJp.todo("cellImeJpGetFocusTop(hImeJpHandle=*0x%x, pFocusTop=*0x%x)", hImeJpHandle, pFocusTop);
@@ -837,12 +926,12 @@ error_code cellImeJpGetFocusTop(CellImeJpHandle hImeJpHandle, vm::ptr<s16> pFocu
return CELL_IMEJP_ERROR_CONTEXT;
}
*pFocusTop = static_cast<u16>(manager.cursor * 2); // offset in bytes
*pFocusTop = static_cast<u16>(manager.focus_begin * 2); // offset in bytes
return CELL_OK;
}
error_code cellImeJpGetFocusLength(CellImeJpHandle hImeJpHandle, vm::ptr<s16> pFocusLength)
static error_code cellImeJpGetFocusLength(CellImeJpHandle hImeJpHandle, vm::ptr<s16> pFocusLength)
{
cellImeJp.todo("cellImeJpGetFocusLength(hImeJpHandle=*0x%x, pFocusLength=*0x%x)", hImeJpHandle, pFocusLength);
@@ -859,19 +948,12 @@ error_code cellImeJpGetFocusLength(CellImeJpHandle hImeJpHandle, vm::ptr<s16> pF
return CELL_IMEJP_ERROR_CONTEXT;
}
if (manager.cursor >= (CELL_IMEJP_STRING_MAXLENGTH - 1))
{
*pFocusLength = 0;
}
else
{
*pFocusLength = static_cast<u16>((manager.cursor_end - manager.cursor + 1) * 2); // offset in bytes
}
*pFocusLength = ::narrow<s16>(manager.focus_length * 2); // offset in bytes
return CELL_OK;
}
error_code cellImeJpGetConfirmYomiString(CellImeJpHandle hImeJpHandle, vm::ptr<u16> pYomiString)
static error_code cellImeJpGetConfirmYomiString(CellImeJpHandle hImeJpHandle, vm::ptr<u16> pYomiString)
{
cellImeJp.todo("cellImeJpGetConfirmYomiString(hImeJpHandle=*0x%x, pYomiString=*0x%x)", hImeJpHandle, pYomiString);
@@ -888,22 +970,22 @@ error_code cellImeJpGetConfirmYomiString(CellImeJpHandle hImeJpHandle, vm::ptr<u
return CELL_IMEJP_ERROR_CONTEXT;
}
for (u32 i = 0; i < CELL_IMEJP_STRING_MAXLENGTH; i++)
{
pYomiString[i] = 0;
}
const usz max_len = std::min<usz>(CELL_IMEJP_STRING_MAXLENGTH - 1, manager.confirmed_string.length());
const usz max_len = std::min<usz>(CELL_IMEJP_STRING_MAXLENGTH - 1ULL, manager.confirmed_string.length());
for (u32 i = 0; i < max_len; i++)
{
pYomiString[i] = manager.confirmed_string[i];
}
for (u32 i = static_cast<u32>(max_len); i < CELL_IMEJP_STRING_MAXLENGTH; i++)
{
pYomiString[i] = 0;
}
return CELL_OK;
}
error_code cellImeJpGetConfirmString(CellImeJpHandle hImeJpHandle, vm::ptr<u16> pConfirmString)
static error_code cellImeJpGetConfirmString(CellImeJpHandle hImeJpHandle, vm::ptr<u16> pConfirmString)
{
cellImeJp.todo("cellImeJpGetConfirmString(hImeJpHandle=*0x%x, pConfirmString=*0x%x)", hImeJpHandle, pConfirmString);
@@ -920,22 +1002,22 @@ error_code cellImeJpGetConfirmString(CellImeJpHandle hImeJpHandle, vm::ptr<u16>
return CELL_IMEJP_ERROR_CONTEXT;
}
for (u32 i = 0; i < CELL_IMEJP_STRING_MAXLENGTH; i++)
{
pConfirmString[i] = 0;
}
const usz max_len = std::min<usz>(CELL_IMEJP_STRING_MAXLENGTH - 1, manager.confirmed_string.length());
const usz max_len = std::min<usz>(CELL_IMEJP_STRING_MAXLENGTH - 1ULL, manager.confirmed_string.length());
for (u32 i = 0; i < max_len; i++)
{
pConfirmString[i] = manager.confirmed_string[i];
}
for (u32 i = static_cast<u32>(max_len); i < CELL_IMEJP_STRING_MAXLENGTH; i++)
{
pConfirmString[i] = 0;
}
return CELL_OK;
}
error_code cellImeJpGetConvertYomiString(CellImeJpHandle hImeJpHandle, vm::ptr<u16> pYomiString)
static error_code cellImeJpGetConvertYomiString(CellImeJpHandle hImeJpHandle, vm::ptr<u16> pYomiString)
{
cellImeJp.todo("cellImeJpGetConvertYomiString(hImeJpHandle=*0x%x, pYomiString=*0x%x)", hImeJpHandle, pYomiString);
@@ -952,22 +1034,22 @@ error_code cellImeJpGetConvertYomiString(CellImeJpHandle hImeJpHandle, vm::ptr<u
return CELL_IMEJP_ERROR_CONTEXT;
}
for (u32 i = 0; i < CELL_IMEJP_STRING_MAXLENGTH; i++)
{
pYomiString[i] = 0;
}
const usz max_len = std::min<usz>(CELL_IMEJP_STRING_MAXLENGTH - 1, manager.input_string.length());
const usz max_len = std::min<usz>(CELL_IMEJP_STRING_MAXLENGTH - 1ULL, manager.input_string.length());
for (u32 i = 0; i < max_len; i++)
{
pYomiString[i] = manager.input_string[i];
}
for (u32 i = static_cast<u32>(max_len); i < CELL_IMEJP_STRING_MAXLENGTH; i++)
{
pYomiString[i] = 0;
}
return CELL_OK;
}
error_code cellImeJpGetConvertString(CellImeJpHandle hImeJpHandle, vm::ptr<u16> pConvertString)
static error_code cellImeJpGetConvertString(CellImeJpHandle hImeJpHandle, vm::ptr<u16> pConvertString)
{
cellImeJp.warning("cellImeJpGetConvertString(hImeJpHandle=*0x%x, pConvertString=*0x%x)", hImeJpHandle, pConvertString);
@@ -984,22 +1066,22 @@ error_code cellImeJpGetConvertString(CellImeJpHandle hImeJpHandle, vm::ptr<u16>
return CELL_IMEJP_ERROR_CONTEXT;
}
for (u32 i = 0; i < CELL_IMEJP_STRING_MAXLENGTH; i++)
{
pConvertString[i] = 0;
}
const usz max_len = std::min<usz>(CELL_IMEJP_STRING_MAXLENGTH - 1, manager.input_string.length());
const usz max_len = std::min<usz>(CELL_IMEJP_STRING_MAXLENGTH - 1ULL, manager.input_string.length());
for (u32 i = 0; i < max_len; i++)
{
pConvertString[i] = manager.input_string[i];
}
for (u32 i = static_cast<u32>(max_len); i < CELL_IMEJP_STRING_MAXLENGTH; i++)
{
pConvertString[i] = 0;
}
return CELL_OK;
}
error_code cellImeJpGetCandidateListSize(CellImeJpHandle hImeJpHandle, vm::ptr<s16> pListSize)
static error_code cellImeJpGetCandidateListSize(CellImeJpHandle hImeJpHandle, vm::ptr<s16> pListSize)
{
cellImeJp.todo("cellImeJpGetCandidateListSize(hImeJpHandle=*0x%x, pListSize=*0x%x)", hImeJpHandle, pListSize);
@@ -1021,12 +1103,23 @@ error_code cellImeJpGetCandidateListSize(CellImeJpHandle hImeJpHandle, vm::ptr<s
return CELL_IMEJP_ERROR_ERR;
}
*pListSize = 0;
// Add focus string size, including null terminator
const std::u16string focus_string = manager.get_focus_string();
usz size = sizeof(u16) * (focus_string.length() + 1);
// Add candidates, including null terminators and offsets
for (const ime_jp_manager::candidate& can : manager.get_candidate_list())
{
constexpr usz offset_size = sizeof(u16);
size += offset_size + (can.text.size() + 1) * sizeof(u16);
}
*pListSize = ::narrow<s16>(size);
return CELL_OK;
}
error_code cellImeJpGetCandidateList(CellImeJpHandle hImeJpHandle, vm::ptr<s16> plistNum, vm::ptr<u16> pCandidateString)
static error_code cellImeJpGetCandidateList(CellImeJpHandle hImeJpHandle, vm::ptr<s16> plistNum, vm::ptr<u16> pCandidateString)
{
cellImeJp.todo("cellImeJpGetCandidateList(hImeJpHandle=*0x%x, plistNum=*0x%x, pCandidateString=*0x%x)", hImeJpHandle, plistNum, pCandidateString);
@@ -1048,12 +1141,42 @@ error_code cellImeJpGetCandidateList(CellImeJpHandle hImeJpHandle, vm::ptr<s16>
return CELL_IMEJP_ERROR_ERR;
}
*plistNum = 0;
// First, copy the focus string
u32 pos = 0;
const std::u16string focus_string = manager.get_focus_string();
for (u32 i = pos; i < focus_string.length(); i++)
{
pCandidateString[i] = focus_string[i];
}
pos += ::narrow<u32>(focus_string.length());
// Add null terminator
pCandidateString[pos++] = 0;
// Add list of candidates
const std::vector<ime_jp_manager::candidate> list = manager.get_candidate_list();
for (const ime_jp_manager::candidate& can : list)
{
// Copy the candidate
for (u32 i = pos; i < can.text.length(); i++)
{
pCandidateString[i] = can.text[i];
}
pos += ::narrow<u32>(can.text.length());
// Add null terminator
pCandidateString[pos++] = 0;
// Add offset
pCandidateString[pos++] = can.offset;
}
*plistNum = ::narrow<s16>(list.size());
return CELL_OK;
}
error_code cellImeJpGetCandidateSelect(CellImeJpHandle hImeJpHandle, vm::ptr<s16> pIndex)
static error_code cellImeJpGetCandidateSelect(CellImeJpHandle hImeJpHandle, vm::ptr<s16> pIndex)
{
cellImeJp.todo("cellImeJpGetCandidateSelect(hImeJpHandle=*0x%x, pIndex=*0x%x)", hImeJpHandle, pIndex);
@@ -1080,7 +1203,7 @@ error_code cellImeJpGetCandidateSelect(CellImeJpHandle hImeJpHandle, vm::ptr<s16
return CELL_OK;
}
error_code cellImeJpGetPredictList(CellImeJpHandle hImeJpHandle, vm::ptr<s16> pYomiString, s32 itemNum, vm::ptr<s32> plistCount, vm::ptr<CellImeJpPredictItem> pPredictItem)
static error_code cellImeJpGetPredictList(CellImeJpHandle hImeJpHandle, vm::ptr<s16> pYomiString, s32 itemNum, vm::ptr<s32> plistCount, vm::ptr<CellImeJpPredictItem> pPredictItem)
{
cellImeJp.todo("cellImeJpGetPredictList(hImeJpHandle=*0x%x, pYomiString=*0x%x, itemNum=%d, plistCount=*0x%x, pPredictItem=*0x%x)", hImeJpHandle, pYomiString, itemNum, plistCount, pPredictItem);
@@ -1102,7 +1225,7 @@ error_code cellImeJpGetPredictList(CellImeJpHandle hImeJpHandle, vm::ptr<s16> pY
return CELL_OK;
}
error_code cellImeJpConfirmPrediction(CellImeJpHandle hImeJpHandle, vm::ptr<CellImeJpPredictItem> pPredictItem)
static error_code cellImeJpConfirmPrediction(CellImeJpHandle hImeJpHandle, vm::ptr<CellImeJpPredictItem> pPredictItem)
{
cellImeJp.todo("cellImeJpConfirmPrediction(hImeJpHandle=*0x%x, pPredictItem=*0x%x)", hImeJpHandle, pPredictItem);
+19 -7
View File
@@ -115,11 +115,12 @@ struct ime_jp_manager
u32 input_state = CELL_IMEJP_BEFORE_INPUT;
std::vector<std::string> dictionary_paths;
std::u16string confirmed_string;
std::u16string converted_string;
std::u16string input_string;
usz cursor = 0;
usz cursor_end = 0;
std::u16string confirmed_string; // Confirmed part of the string (first part of the entire string)
std::u16string converted_string; // Converted part of the unconfirmed input string
std::u16string input_string; // Unconfirmed part of the string (second part of the entire string)
usz cursor = 0; // The cursor. Can move across the entire input string.
usz focus_begin = 0; // Begin of the focus string
usz focus_length = 0; // Length of the focus string
s16 fix_input_mode = CELL_IMEJP_FIXINMODE_OFF;
s16 input_char_type = CELL_IMEJP_DSPCHAR_HIRA;
s16 kana_input_mode = CELL_IMEJP_ROMAN_INPUT;
@@ -131,6 +132,17 @@ struct ime_jp_manager
bool addString(vm::cptr<u16> str);
bool backspaceWord();
bool deleteWord();
void moveCursor(s8 amount);
void moveCursorEnd(s8 amount);
bool remove_character(bool forward);
void clear_input();
void move_cursor(s8 amount); // s8 because CELL_IMEJP_STRING_MAXLENGTH is 128
void move_focus(s8 amount); // s8 because CELL_IMEJP_STRING_MAXLENGTH is 128
void move_focus_end(s8 amount, bool wrap_around); // s8 because CELL_IMEJP_STRING_MAXLENGTH is 128
struct candidate
{
std::u16string text; // Actual text of the candidate
u16 offset = 0; // The offset of the next character after the candidate replaced part of the current focus.
};
std::vector<candidate> get_candidate_list() const;
std::u16string get_focus_string() const;
};
+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
{
+2 -2
View File
@@ -259,7 +259,7 @@ error_code cellMouseGetData(u32 port_no, vm::ptr<CellMouseData> data)
error_code cellMouseGetDataList(u32 port_no, vm::ptr<CellMouseDataList> data)
{
sys_io.notice("cellMouseGetDataList(port_no=%d, data=0x%x)", port_no, data);
sys_io.trace("cellMouseGetDataList(port_no=%d, data=0x%x)", port_no, data);
auto& handler = g_fxo->get<MouseHandlerBase>();
@@ -406,7 +406,7 @@ error_code cellMouseGetTabletDataList(u32 port_no, vm::ptr<CellMouseTabletDataLi
error_code cellMouseGetRawData(u32 port_no, vm::ptr<CellMouseRawData> data)
{
sys_io.notice("cellMouseGetRawData(port_no=%d, data=*0x%x)", port_no, data);
sys_io.trace("cellMouseGetRawData(port_no=%d, data=*0x%x)", port_no, data);
auto& handler = g_fxo->get<MouseHandlerBase>();
+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);
}
@@ -227,6 +227,12 @@ error_code cell_music_decode_read(vm::ptr<void> buf, vm::ptr<u32> startTime, u64
std::memcpy(buf.get_ptr(), &dec.decoder.data[dec.read_pos], size_to_read);
if (size_to_read < reqSize)
{
// Set the rest of the buffer to zero to prevent loud pops at the end of the stream if the game ignores the readSize.
std::memset(vm::static_ptr_cast<u8>(buf).get_ptr() + size_to_read, 0, reqSize - size_to_read);
}
dec.read_pos += size_to_read;
s64 start_time_ms = 0;
+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;

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