Compare commits

..

167 Commits

Author SHA1 Message Date
Ani 61d9852632 rpcs3_version: Bump to 0.0.20 (#11318) 2022-01-01 00:32:14 +00:00
Nekotekina cb2748ae08 Update ASMJIT (new upstream API) 2021-12-29 02:45:00 +03:00
Alex James 900d7df40f GDB: Rework to_hex/hex_to functions
macOS defines uint64 as an alias of unsigned long long. Drop the length
modifiers to resolve the warning on macOS:

rpcs3/rpcs3/Emu/GDB.cpp:107:37: warning: format specifies type 'unsigned long *' but the argument has type 'u64 *' (aka 'unsigned long long *') [-Wformat]
        sscanf_s(val.c_str(), "%" HEX_U64, &result);
                               ~~~~~~~~~~  ^~~~~~~

Also use std::from_chars to implement hex_to_{u8,u32,u64} instead of
sscanf.
2021-12-28 02:02:44 +03:00
clienthax 6837370a62 Handle SYS_NET_IPPROTO_IP get/setsockopt
Improve net logging.

Should allow latest vsh to load (Depending on windows version apparantly..)
2021-12-27 20:58:09 +03:00
Nekotekina 9cfdd8afea Fix builds on additional platforms
LLVMIntelJITEvents is awailable only Windows/Linux
2021-12-27 16:17:53 +03:00
Nekotekina 7b24df0957 Update LLVM commit 2021-12-27 02:24:28 +03:00
Nekotekina 122555fb66 Add an error check in JITAnnouncer event listener
This is a bit strange one.
2021-12-26 22:01:20 +03:00
Nekotekina d836033212 LLVM: enable some JIT events (Intel, Perf)
Made some related adjustments.
Currently incomplete.
2021-12-26 16:41:37 +03:00
Nekotekina 510041a873 rsx_methods.cpp: optimize compile time (120s to 10s)
Untemplate NV308A_COLOR
2021-12-26 14:40:21 +03:00
Nekotekina 8b4b6ba946 copy_data_swap_u32: build AVX-512 path 2021-12-26 14:40:21 +03:00
Nekotekina d36a715b24 Disable built_function on __APPLE__
Workaround for #11287
2021-12-26 14:40:21 +03:00
Nekotekina 599e00d6da BufferUtils: remove dead code (vertex streaming)
RIP. It won't be useful.
2021-12-26 14:40:21 +03:00
Nekotekina 3cd8891ab8 Re-refactor copy_data_swap_u32 again
Drop AVX2 path for now, since it usually operates on small data.
Rely on automatic SSE vectorization on recent compilers.
Side refactoring on JIT.h to workaround weird conflict issue.
2021-12-26 14:40:21 +03:00
Nekotekina e3e6fb5489 Don't use vm::preallocated flag in patch enclave allocs 2021-12-26 14:40:21 +03:00
kd-11 a9303acfdf rsx: Fix zclip w scaling 2021-12-26 12:50:31 +03:00
Josh Lay b4ec4f46b8 Fedora (35): Adjust to Pipewire adoption ++QT deps
Provided build steps didn't work on Fedora 35, these packages seem to settle things 😄
2021-12-26 09:20:56 +01:00
Eladash 6ee9d0f35f sys_rsx: Outlaw mapping sys_vm memory to RSX IO address-space 2021-12-25 02:22:49 +03:00
nastys a0040e6fb1 macOS: Implement texture converter for Metal (2) (#11289)
* macOS: Implement texture converter for Metal (2)

* Fix texture conversion formatting
2021-12-24 15:46:37 +03:00
kd-11 28d7af313b rsx: Remove noisy debug print 2021-12-24 15:13:33 +03:00
kd-11 39ef39aa4e rsx: Exercise caution when testing for overlaps in invalidated sections 2021-12-24 15:13:33 +03:00
kd-11 d9a1308624 Drop libwayland-client from official appimages 2021-12-24 11:35:50 +03:00
kd-11 56dd09f4fe rsx: Handle floating point shenanigans
- If near and far clip are too close together, the API will not distinguish between them leading to out of bounds values
2021-12-22 22:08:53 +03:00
kd-11 de495952fd rsx: Enable fallback for devices without wide integer Z buffers 2021-12-22 22:08:53 +03:00
kd-11 1ce5349199 rsx: Remove zclip hackery
- Calculates precise Z value as requested by the game
- Works properly if the underlying Z format matches the PS3 1:1 but may cause minor problems otherwise
2021-12-22 22:08:53 +03:00
Nekotekina dcd011048d Implement "built_function" utility (runtime-generated assembly)
Similar to build_function_asm, but links without indirection.
Achieved by emitting code directly into a byte array.
2021-12-22 19:27:20 +03:00
Nekotekina 12e3c9e08b Use PAUSE in vk::query_pool_manager::get_query_result 2021-12-21 23:28:09 +03:00
Nekotekina 262ff01619 Use aligned stores in write_index_array_data_to_buffer
Ensure that target buffer is cache line aligned.
Improve stx::make_single to support alignment.
2021-12-21 23:28:09 +03:00
Nekotekina 76ccaf5e6f BufferUtils: refactoring
Optimize CPU capability tests for arch-tuned builds.
Separate streaming and non-streaming utilities.
Rewritten copy_data_swap_u32(_cmp) with AVX2 path.
2021-12-21 23:28:09 +03:00
nastys 47e4a95d8f Fix remap_vector redefinition on macOS (#11271) 2021-12-21 10:36:09 +01:00
Nekotekina c0bafbc804 TSX: enable same data optimization for PUTLLC 2021-12-19 20:23:01 +03:00
Nekotekina 61c64d1060 TSX: refactoring M
Remove first stage 'optimistic' transactions.
2021-12-19 20:23:01 +03:00
Nekotekina 3e1e1a683c TSX/PPU: fix conditional store regression 2021-12-17 21:48:01 +03:00
Megamouse 18f59d3be8 Input: fix min stick input of keyboard pad handler 2021-12-17 17:21:44 +01:00
Megamouse bf739aa156 Input: implement stick multipliers for keyboard 2021-12-17 17:21:44 +01:00
RipleyTom 43b7d1fe98 Add missing virtual destructors to some base class 2021-12-15 18:05:55 +03:00
Megamouse cc21d1b3cf cellSaveData: prevent some potential crashes due to corrupt files 2021-12-14 20:30:47 +01:00
nastys 08333e0876 macOS moltenVK support and SIGBUS handling (#11252) 2021-12-12 21:35:56 +01:00
Malcolm Jestadt 2f93df480b SPU LLVM: Disable affineqb shufb paths temporarilly 2021-12-10 19:32:10 +03:00
Megamouse 56fe450959 Qt: fix screenshot path creation 2021-12-10 17:27:52 +01:00
clienthax 6f9adbd162 Debug SPRX check 2021-12-10 14:23:26 +01:00
Megamouse f48c535802 cellAudio: Recover XAudio on failed initialization 2021-12-09 01:46:44 +01:00
Megamouse 5f7e5a9844 cellAudio: relax FAudio error handling 2021-12-09 01:46:44 +01:00
Megamouse 3f3b4bc363 cellAudio: recover Cubeb on failed initialization 2021-12-09 01:46:44 +01:00
Megamouse 68466f05b6 cellAudio: move some stuff to cpp 2021-12-09 01:46:44 +01:00
Megamouse e6b4655142 cellAudio: use members instead of config values 2021-12-09 01:46:44 +01:00
xddxd f690d55045 Remove unnecessary define 2021-12-09 01:21:11 +01:00
kd-11 d523f9cc6b rsx: Avoid skipping input mask checks due to static flow control 2021-12-08 23:58:32 +03:00
kd-11 7ca15c60bb rsx: Improve image aspect tests
- Replace old format-based detection with proper aspect test.
  Explicit image aspect has been available for a long time, but older
  code was not updated.
2021-12-08 23:58:32 +03:00
Nekotekina 8abd3e8bb4 PPU LLVM: fix bitcast usage to enable constant folding 2021-12-07 15:35:51 +03:00
Nekotekina 6730dc1dc4 LLVM DSL: print some debug info in get_const_vector<v128> 2021-12-07 13:21:24 +03:00
Nekotekina 6b40d69a8f Introduce coroutine support (util/coro.hpp)
Implement coroutine types `lazy` and `generator` in stx namespace.
Implement fs::list_dir_recursively.
2021-12-07 13:04:10 +03:00
Nekotekina d6420b8803 Put std::hash specialization out of std 2021-12-07 13:04:10 +03:00
Megamouse a4ad0a9468 cellVideoOutConfigure: treat unknown aspect as AUTO 2021-12-06 20:50:57 +01:00
Void48 a09fd80905 Update README.md 2021-12-06 12:05:52 +01:00
Malcolm Jestadt 0617e9e14b SPU LLVM: Fix vgf2p8affineqb usage
- Reverse the order of the bytes in the selection masks. Previously it was assumed that byte 0 would determine the output of bit 0, but byte 7 determines the output of bit 0.
2021-12-06 12:34:11 +03:00
Eladash cb4711203b logging: Tell apart PPU access violation caused by executing unmapped memory 2021-12-05 01:22:32 +03:00
Nekotekina e3e39e8de3 PPU LLVM: rewrite and optimize saturation bit
Use vector accumulator
2021-12-03 00:14:06 +03:00
Nekotekina 209b14fbac PPU LLVM: inline remaining vector instructions 2021-12-03 00:14:06 +03:00
Nekotekina 04c9d01390 PPU LLVM: modernize most vector instructions
Rewritten VSUM instructions:
VSUMSWS, VSUM2SWS, VSUM4SBS, VSUM4SHS, VSUM4UBS
2021-12-03 00:14:06 +03:00
Nekotekina c9d8e59dbf PPU LLVM: allow to drop setting SAT flag (optimization, module-wide)
Implement ppu_attr::has_mfvscr (partially, module-wide search).
If this instruction isn't found, allow to drop setting SAT flag.
It's based on presumption that only MFVSCR can retrieve SAT flag.
2021-12-03 00:14:06 +03:00
Nekotekina 86b194014b PPU LLVM: rewrite more packing instructions
Rewritten VPKUHUM, VPKUHUS, VPKUWUM, VPKUWUS.
Decoupled saturation test from sat pack pattern.
2021-12-03 00:14:06 +03:00
Nekotekina e7c827f73b PPU LLVM: rewrite some packing instructions
Rewritten VPKSHSS, VPKSHUS, VPKSWSS, VPKSWUS.
Decoupled saturation test from sat pack pattern.
2021-12-03 00:14:06 +03:00
Nekotekina abe498f35c PPU LLVM: modernize some code with new DSL
PPU: rewritten instructions VMHADDSHS, VMHRADDSHS
PPU: added optimized path for VPERM (ra=rb)
2021-12-03 00:14:06 +03:00
DH 49c02854f5 [rsx] reduce size of config structs 2021-12-02 21:36:57 +03:00
DH cccfb89aa0 [Config] Use std::less<> for std::map<...>
Reduces amount of string copies
[Utilities] fmt::replace_all: avoid creation of temporary strings
2021-12-02 21:36:57 +03:00
DH 2981867375 sys_spu_thread: Removed unused field access 2021-12-02 21:36:57 +03:00
DH 56d922999f Fixed debug build compilation errors
const_str_t constructor without arguments shoud be constexpr for usage as default initializer in constexpr functions
2021-12-02 21:36:57 +03:00
DH 813c3298ad [Utilities] Fixed area_base operator* scalar type 2021-12-02 21:36:57 +03:00
kd-11 02832d9623 rsx: Add some sensible fallbacks (#11219)
* rsx: Add some sensible fallbacks

* Update GLPresent.cpp

* Update VKPresent.cpp

* Update rsx_utils.h

* Update rsx_utils.cpp
2021-12-02 16:02:08 +03:00
Eladash 0ab36ef44d sys_spu: Implement SPU image segment info checks (#11211) 2021-12-02 13:17:10 +03:00
kd-11 9bb46aa944 rsx: Simplify unconstrained aspect ratio conversion
- There is a reason resolutions are defined by only a height variable.
2021-12-01 21:55:53 +01:00
Megamouse 474baca6d8 rsx: default initialize RsxDisplayInfo 2021-12-01 21:55:53 +01:00
Megamouse 88d0b7d135 cellAvconfExt: add some trivial param checks 2021-12-01 21:55:53 +01:00
Megamouse aea1ec2594 avconf: Add const to fxo references 2021-12-01 21:55:53 +01:00
kd-11 22a7b026e7 rsx: Fix image scaling
- Specifically fixes a corner case where double transforms are required.
  Technically this can be made more readable using transformation matrices:
  * M1 = transform_virtual_to_physical()
  * M2 = transform_image_to_virtual()
  * M3 = M1 * M2
  * Result = Input * M3
  But we don't use a CPU-side matrix library and it is not reasonable to do this on the GPU.
2021-12-01 21:55:53 +01:00
Megamouse c8d4a0dcdc VK/GL: honor game's aspect ratio when scaling 2021-12-01 21:55:53 +01:00
Eladash f16949c292 fs::file: always use strict reading mode for large reads (#11206) 2021-12-01 19:09:07 +03:00
Jan Beich f910a152f1 CI: switch FreeBSD to Clang/libc++ 13 (#11214) 2021-11-30 16:12:37 +00:00
Megamouse 270c2e58a0 Update xxHash to version 0.8.1 2021-11-29 22:12:39 +01:00
Megamouse a586d1c529 Update glslang to version 11.7.1 2021-11-29 22:12:39 +01:00
Megamouse 09b047611b Update FAudio to version 21.11 2021-11-29 22:12:39 +01:00
Vestral e5005597fe CellAudio fixes 2021-11-29 20:43:00 +01:00
kd-11 38bfefcdfa vk: Fix incorrect mixed transfer modes for mipmapped VTC 2021-11-28 01:44:21 +03:00
kd-11 44fe6f6d39 rsx: Fix sloppy format matching test 2021-11-27 17:47:41 +03:00
RipleyTom 4fe17fcecf sys_usbd improvements (#11202) 2021-11-27 01:49:35 +00:00
RipleyTom 276ee81da8 Ignore Log subsection for config obsolete check 2021-11-25 19:42:12 +01:00
RipleyTom 5e158bd3f2 Impl sys_usbd_get_device_location 2021-11-25 00:53:00 +01:00
clienthax 2b924175aa Emulated v406 usio 2021-11-24 21:59:48 +01:00
Vestrel 37a722cc1d Audio backend improvements
Callback based audio update.
Upgraded common backend interface.
Added Cubeb backend.
Support multiple audio providers.
Dropped pulse, alsa, openal backends.
2021-11-24 19:41:05 +01:00
orbea a84223bdc6 rpcs3: Fix the DATADIR path for AppImage
Even when DATADIR is defined the other paths may still be correct.

Fixes: https://github.com/RPCS3/rpcs3/issues/11195
2021-11-24 19:14:06 +01:00
kd-11 4df1a938b1 Unused var 2021-11-24 16:02:24 +03:00
kd-11 94a3b1cfe8 rsx: Roll back some optimizations
- Just use RGB565 for all blit targets. Avoids really dumb transforms done by GPU hw.
- When X16 is used, all the channels get written to R channel alone. CmdBlit does perform format conversion!
- gl: Force image copy when blit is requested with compatible targets. Avoids format conversion issues.
2021-11-24 16:02:24 +03:00
kd-11 a21c6c4628 rsx: Fix handling of scaling requests for packed formats
- One does not simply interpolate RGB565 components as U16 data!
2021-11-24 16:02:24 +03:00
kd-11 58f0fa3ca5 gl: Enable handling of X16 blit targets 2021-11-24 16:02:24 +03:00
kd-11 97bd8f7bc1 rsx: Update sampler format class when inheriting mipmap slices/sections 2021-11-24 16:02:24 +03:00
clienthax 4c0ef37a5c Stub uvc camera init 2021-11-23 23:41:13 +01:00
AniLeo 1df8f52a9f vk: Remove lavapipe workaround
Current lavapipe version now has support for 
shaderStorageBufferArrayDynamicIndexing
2021-11-23 22:48:46 +01:00
shockdude f9434091c3 sys_usbd: make emulated turntable interrupt transfer as fast as possible
Also add missing mutex
2021-11-23 02:19:36 +00:00
orbea 59f253ba24 cmake: Use GNUInstalldirs 2021-11-22 21:45:55 +01:00
Eladash c52d447381 sys_fs: Place all path-format checks upfront, implement more checks 2021-11-22 21:03:07 +03:00
Eladash 524b065bc8 Debugger: Show PPU reservation data
Asterisk marks the offset of data that had been given to the guest PPU code.
2021-11-22 14:48:34 +03:00
Eladash f7b55ec8d4 lv2: Add missing reservation disowning in lv2_obj::yield 2021-11-22 14:48:34 +03:00
Megamouse e7fc2bfa3b Input: Log path on hid_open_path error 2021-11-22 09:41:12 +01:00
Megamouse 22e3075c64 cellSaveData: always log setList and setBuf
For debugging
2021-11-20 08:43:46 +01:00
Megamouse 09ead539a5 improvise CELL_SAVEDATA_ERRDIALOG_NOREPEAT 2021-11-20 08:43:46 +01:00
Megamouse 5272dd951b Qt: simplify callbacks.resolve_path 2021-11-20 08:43:46 +01:00
Megamouse 7eee9e7b05 overlays: simplify backup icon copy procedure 2021-11-20 08:43:46 +01:00
Eladash e5eb727110 Memory Searcher: Peek full string in log, fix case-insensitive search 2021-11-20 07:57:34 +01:00
Eladash 7352a5a495 GUI: Rename memory string searching tool to "Memory Searcher" 2021-11-20 07:57:34 +01:00
Nekotekina 3d859a7493 Update LLVM commit (fixup) 2021-11-18 18:47:54 +03:00
RipleyTom 3587cfd2df Update SpuTest to v1.1.2 2021-11-18 15:50:31 +01:00
Megamouse de2be90636 Qt: only show prefix for fatal messages
Always messages are supposed to be humanly readable
2021-11-17 22:53:20 +01:00
Artur 9f35c3f52d Properly recognize triggers and axes for evdev pads. 2021-11-17 21:29:24 +01:00
RipleyTom 22910c02a9 Implement sceNpManagerGetPsHandle (#11164) 2021-11-17 18:02:01 +00:00
Nekotekina fef8905dc2 Update LLVM commit 2021-11-16 15:13:34 +03:00
Megamouse 0f7534c755 VK: fix NVIDIA driverVersion check 2021-11-16 09:31:16 +01:00
Megamouse 4d0330bf82 rsx: fix possible segfault 2021-11-16 09:31:16 +01:00
Megamouse 026efd96b2 cellKbCnvRawCode: use proper constants
and comment out unreachable code
2021-11-16 09:31:16 +01:00
Megamouse f6af5ff13a cellRtcGetDaysInMonth: fix param check 2021-11-16 09:31:16 +01:00
Megamouse 0d7b7585a8 Some typo/warning fixes 2021-11-16 09:31:16 +01:00
Eladash 6283600b84 Qt: Fix log prefix in log_frame 2021-11-16 09:02:43 +01:00
Megamouse f6e04ffdd2 overlays: add stick input to native dialogs 2021-11-16 01:38:33 +01:00
Megamouse 44b42f68fd overlays: add R3, L3 and PS buttons
Unused at the moment
2021-11-16 01:38:33 +01:00
Megamouse 56241838c0 input: add made up CELL_PAD_CTRL_PS enum
And remove useless comment about 0x0 buttons. It's a bitmap, so 0x0 is literally useless.
2021-11-16 01:38:33 +01:00
Megamouse 26475f8f40 cellGem: add comment about hack 2021-11-16 01:38:33 +01:00
Megamouse ff5e31f396 overlays: add system sounds 2021-11-15 23:03:30 +01:00
kd-11 59b1c324a9 rsx: Properly implement immediate mode rendering
- Treat the draw commands as being consumed on-the-fly with ATTR0 as provoking attribute
- Analysing streams sent to RSX and the results implies they are consumed fully inline.
  This only makes sense if a provoking attribute is present. The 'static' register is truly the immediate register for the draw.
2021-11-15 18:14:15 +03:00
kd-11 1f627caa81 rsx: Clear some leaking register state between runs 2021-11-15 18:14:15 +03:00
Megamouse 7dc3a50ddf Fix headless mode 2021-11-14 17:07:18 +01:00
Eladash cfe08de951 Account empty EDAT (#11146)
* Improve sys_fs_open logging
2021-11-14 02:15:27 +03:00
Eladash 48ad959697 sys_event: Fix PPU queue forced uproot of waiters (#11147) 2021-11-13 20:22:54 +03:00
陈俊嘉 05881ffa62 Disable vulkan in Windows build when HAVE_VULKAN is off and other cmake build fixes. (#11118)
* Make WolfSSL build support multi-config generator.
Fix a build error in Windows when using QT's moc.
Disable vulkan in Windows build when HAVE_VULKAN is off.

* add WIN32_LEAN_AND_MEAN definition to VS project.
add HAVE_VULKAN definition to VS project.
Define NTSTATUS in main.cpp.
2021-11-13 16:11:49 +01:00
Megamouse 8b3ed7b599 Qt: fix initial pad settings dialog size and position 2021-11-11 23:06:57 +01:00
cglmrfreeman 48ad7ca3a0 Update OpenSUSE Qt5 dependencies (#11135) 2021-11-11 19:57:23 +01:00
Megamouse cbec04cd0f Curl: fix --verbose-curl option 2021-11-11 17:37:22 +01:00
Malcolm Jestadt 3fde455932 SPU LLVM: Optimize branch following ORX
- test the input of ORX directly for zeroes, instead of the result
2021-11-11 12:58:38 +03:00
RipleyTom ba727e13ae Fixes rpcn_client.h func ptr comparison warning 2021-11-11 08:11:14 +01:00
RipleyTom 2248007c9a Add HAVE_SNI definition to curl build for wolfssl 2021-11-11 07:35:59 +01:00
Megamouse 2359ba9aed curl: add verbose logging
and really verbose logging i you use --verbose-curl
2021-11-11 00:36:42 +01:00
RipleyTom b736691bde Special nullptr optParam->cbFunc case fix 2021-11-10 20:03:11 +01:00
RipleyTom 50bf528f3f NP: add signaling_handler wakeup on connect queue 2021-11-10 12:43:45 +01:00
kd-11 7e3eab9915 rsx: Fix texture state propagation between unrelated draw calls
- Older games can load all textures before a draw sequence and then swap shaders for different draws.
- Optimizations in texture state streaming make it so that only referenced data is carried forward.
2021-11-09 12:39:49 +03:00
RipleyTom dc0793b731 NP: Implement sceNpMatching2DeleteServerContext 2021-11-08 13:10:40 +03:00
RipleyTom c194804fec NP: Implement sceNpBasicGetFriendListEntry 2021-11-08 13:10:40 +03:00
RipleyTom d41e405420 NP: Cache Manager + improvements 2021-11-08 13:10:40 +03:00
RipleyTom 516cb959cb rpcn: new allocator + refactoring of np_handler 2021-11-08 13:10:40 +03:00
RipleyTom 704e74b904 rpcn: extra changes 2021-11-08 13:10:40 +03:00
Nick Renieris b70f08d850 The Velocity Improvements: RoomData/RoomMemberData commands & fixes
modules/np2: Correct some SceNpMaching2 ptr type endianness
np/handler: Use STL .contains() method
Ignore USECRYPTO & USESIGNATURE in recvfrom/sendto
Implement RoomData/RoomMemberData commands
2021-11-08 13:10:40 +03:00
Ani 53f2594983 llvm: Add AVX-512 detection for Alderlake (#11121) 2021-11-07 15:23:51 +00:00
Malcolm Jestadt 7573d7289b SPU LLVM: Hook up 128 bit spu verification
- Also fix FMA enablement for sapphirerapids
2021-11-06 21:12:12 +03:00
Megamouse f9abe40494 Qt: fix initial TSX selection 2021-11-06 13:47:43 +01:00
Megamouse 88bb26afb4 vk: make upscaler dynamic
The config option was marked as dynamic, but was never actually changed ingame
2021-11-06 01:02:54 +01:00
Megamouse dac0baac0d Qt: improve fsr tooltip area 2021-11-06 01:02:54 +01:00
kd-11 f7eacf70ec rsx: Restore shader disassembler to working state 2021-11-05 23:55:07 +03:00
Megamouse 067b35217a Qt: Consider TSX-FA in settings dialog 2021-11-04 23:34:10 +01:00
xddxd c3888f5bbb Specify the compiler for llvm_build (#11110) 2021-11-04 21:28:19 +00:00
Megamouse af3ef02ca0 fix npDrmIsAvailable 2021-11-04 21:41:07 +01:00
Eladash c49ebba648 Fixes of PS3 filesystem EDAT/SDAT handling
* Return EFSSPEIFIC if encountered corrupted EDAT or an unmatched key in sys_fs_open and sys_fs_read.
* Fix validate_dev_klic() for license-free EDAT.
* Fix EDATADecrypter::ReadData() for when size + pos > file_size but pos < file_size.
* Try to save up to 16 decryption keys. Educated guess based on NPDRM file descriptors count llimit.
* Return LICENCE_NOT_FOUND if needed RAP file is not found in sceNpDrmIsAvailable.
* Check additional sys_fs_open errors for sceNpDrmOpen. (EISDIR, ENOTMOUNTED)
2021-11-04 21:32:15 +03:00
kd-11 933d96af5f vk: Do not clip region using renderpass renderarea, we have scissor for that 2021-11-04 21:05:15 +03:00
Whatcookie bf6044fced SPU/SYSINFO: Disable TSX by default for TSX-FA cpus (#11105)
- Also detect the new RTM_ALWAYS_ABORT bit in cpuid
- This new bit indicates that RTM is disabled in the microcode
- On cpus with RTM_ALWAYS_ABORT TSX can be renabled by writing 0x4 to the msr 0x0000010F
2021-11-04 16:44:25 +00:00
Ani 1a0392bf15 CPUTranslator: Enable FMA for alderlake CPUs (#11106) 2021-11-03 19:31:46 +00:00
kd-11 ad00c44231 rsx: Configure pitch correctly for pitch-zero textures (1D) 2021-11-03 16:58:30 +03:00
Nekotekina 69f321a471 LLVM 13 2021-11-02 20:11:08 +03:00
Malcolm Jestadt 37383f4217 SPU ASMJIT: Disable 512 wide spu verification
- Apparantly this crashes every game.
2021-11-01 20:04:26 +03:00
Eladash b84e95d768 rsx: Fixate time stamp of VBLANK 2021-11-01 10:04:53 +01:00
Eladash 4369fb234e rsx: Fix typo in VBLANK processing regarding emulation pause 2021-11-01 10:04:53 +01:00
Eladash 58040d478a rsx: Implement NTSC fixup mode, improve VBLANK accuracy 2021-11-01 10:04:53 +01:00
263 changed files with 11361 additions and 7391 deletions
+10 -4
View File
@@ -7,10 +7,16 @@ git submodule -q update --init --depth 1 $(awk '/path/ && !/llvm/ { print $3 }'
# Prefer newer Clang than in base system (see also .ci/install-freebsd.sh)
# libc++ isn't in llvm* packages, so download manually
fetch https://github.com/llvm/llvm-project/releases/download/llvmorg-12.0.0/libcxx-12.0.0.src.tar.xz
tar xf libcxx-12.0.0.src.tar.xz
export CC=clang12 CXX=clang++12
export CXXFLAGS="$CXXFLAGS -nostdinc++ -D_LIBCPP_HAS_NO_VENDOR_AVAILABILITY_ANNOTATIONS -isystem $PWD/libcxx-12.0.0.src/include"
fetch https://github.com/llvm/llvm-project/archive/refs/tags/llvmorg-13.0.1-rc1.tar.gz
tar xf llvm*.tar.gz
export CC=clang13 CXX=clang++13
cmake -B libcxx_build -G Ninja -S llvm*/libcxx \
-DLLVM_CCACHE_BUILD=ON \
-DCMAKE_INSTALL_PREFIX:PATH=libcxx_prefix
cmake --build libcxx_build
cmake --install libcxx_build
export CXXFLAGS="$CXXFLAGS -nostdinc++ -isystem$PWD/libcxx_prefix/include/c++/v1"
export LDFLAGS="$LDFLAGS -nostdlib++ -L$PWD/libcxx_prefix/lib -l:libc++.a -lcxxrt"
CONFIGURE_ARGS="
-DWITH_LLVM=OFF
+5
View File
@@ -18,6 +18,11 @@ if [ "$DEPLOY_APPIMAGE" = "true" ]; then
# Embed newer libstdc++ for distros that don't come with it (ubuntu 16.04)
mkdir -p appdir/usr/optional/ ; mkdir -p appdir/usr/optional/libstdc++/
cp /usr/lib/x86_64-linux-gnu/libstdc++.so.6 ./appdir/usr/optional/libstdc++/
# Remove libwayland-client because it has platform-dependent exports and breaks other OSes
rm -f ./appdir/usr/lib/libwayland-client.so*
# Install latest appimage runner
rm ./appdir/AppRun
curl -sL https://github.com/RPCS3/AppImageKit-checkrt/releases/download/continuous2/AppRun-patched-x86_64 -o ./appdir/AppRun
chmod a+x ./appdir/AppRun
+1 -1
View File
@@ -9,7 +9,7 @@ export ASSUME_ALWAYS_YES=true
pkg info # debug
# Prefer newer Clang than in base system (see also .ci/build-freebsd.sh)
pkg install llvm12
pkg install llvm13
# Mandatory dependencies (qt5-dbus and qt5-gui are pulled via qt5-widgets)
pkg install git ccache cmake ninja qt5-qmake qt5-buildtools qt5-widgets qt5-concurrent qt5-multimedia qt5-svg glew openal-soft ffmpeg
+5 -1
View File
@@ -5,7 +5,7 @@
[submodule "asmjit"]
path = 3rdparty/asmjit/asmjit
url = ../../asmjit/asmjit.git
branch = oldstable
branch = aarch64
ignore = dirty
[submodule "llvm"]
path = llvm
@@ -68,3 +68,7 @@
path = 3rdparty/flatbuffers
url = ../../google/flatbuffers.git
ignore = dirty
[submodule "3rdparty/cubeb/cubeb"]
path = 3rdparty/cubeb/cubeb
url = ../../mozilla/cubeb.git
ignore = dirty
+2 -34
View File
@@ -128,38 +128,8 @@ target_include_directories(3rdparty_stblib INTERFACE stblib/include)
# DiscordRPC
add_subdirectory(discord-rpc)
# ALSA
set(ALSA_TARGET 3rdparty_dummy_lib)
if(USE_ALSA)
find_package(ALSA)
if(ALSA_FOUND)
add_library(3rdparty_alsa INTERFACE)
target_compile_definitions(3rdparty_alsa INTERFACE -DHAVE_ALSA)
target_include_directories(3rdparty_alsa SYSTEM INTERFACE ${ALSA_INCLUDE_DIRS})
target_link_libraries(3rdparty_alsa INTERFACE ${ALSA_LIBRARIES})
set(ALSA_TARGET 3rdparty_alsa)
endif()
endif()
# Pulse
set(PULSE_TARGET 3rdparty_dummy_lib)
if(USE_PULSE)
pkg_check_modules(PULSE libpulse-simple)
if(PULSE_FOUND)
add_library(3rdparty_pulse INTERFACE)
target_compile_definitions(3rdparty_pulse INTERFACE -DHAVE_PULSE)
target_include_directories(3rdparty_pulse SYSTEM
INTERFACE ${PULSE_INCLUDE_DIRS})
target_link_libraries(3rdparty_pulse INTERFACE ${PULSE_LDFLAGS})
set(PULSE_TARGET 3rdparty_pulse)
endif()
endif()
# Cubeb
add_subdirectory(cubeb EXCLUDE_FROM_ALL)
# libevdev
set(LIBEVDEV_TARGET 3rdparty_dummy_lib)
@@ -334,8 +304,6 @@ add_library(3rdparty::libpng ALIAS ${LIBPNG_TARGET})
add_library(3rdparty::opengl ALIAS 3rdparty_opengl)
add_library(3rdparty::stblib ALIAS 3rdparty_stblib)
add_library(3rdparty::discordRPC ALIAS 3rdparty_discordRPC)
add_library(3rdparty::alsa ALIAS ${ALSA_TARGET})
add_library(3rdparty::pulse ALIAS ${PULSE_TARGET})
add_library(3rdparty::faudio ALIAS ${FAUDIO_TARGET})
add_library(3rdparty::libevdev ALIAS ${LIBEVDEV_TARGET})
add_library(3rdparty::vulkan ALIAS ${VULKAN_TARGET})
+132 -52
View File
@@ -11,66 +11,146 @@
</ProjectConfiguration>
</ItemGroup>
<ItemGroup>
<ClCompile Include="asmjit\src\asmjit\base\arch.cpp" />
<ClCompile Include="asmjit\src\asmjit\base\assembler.cpp" />
<ClCompile Include="asmjit\src\asmjit\base\codebuilder.cpp" />
<ClCompile Include="asmjit\src\asmjit\base\codecompiler.cpp" />
<ClCompile Include="asmjit\src\asmjit\base\codeemitter.cpp" />
<ClCompile Include="asmjit\src\asmjit\base\codeholder.cpp" />
<ClCompile Include="asmjit\src\asmjit\base\constpool.cpp" />
<ClCompile Include="asmjit\src\asmjit\base\cpuinfo.cpp" />
<ClCompile Include="asmjit\src\asmjit\base\func.cpp" />
<ClCompile Include="asmjit\src\asmjit\base\globals.cpp" />
<ClCompile Include="asmjit\src\asmjit\base\inst.cpp" />
<ClCompile Include="asmjit\src\asmjit\base\logging.cpp" />
<ClCompile Include="asmjit\src\asmjit\base\osutils.cpp" />
<ClCompile Include="asmjit\src\asmjit\base\operand.cpp" />
<ClCompile Include="asmjit\src\asmjit\base\regalloc.cpp" />
<ClCompile Include="asmjit\src\asmjit\base\runtime.cpp" />
<ClCompile Include="asmjit\src\asmjit\base\string.cpp" />
<ClCompile Include="asmjit\src\asmjit\base\vmem.cpp" />
<ClCompile Include="asmjit\src\asmjit\base\zone.cpp" />
<ClCompile Include="asmjit\src\asmjit\core\archtraits.cpp" />
<ClCompile Include="asmjit\src\asmjit\core\assembler.cpp" />
<ClCompile Include="asmjit\src\asmjit\core\builder.cpp" />
<ClCompile Include="asmjit\src\asmjit\core\codeholder.cpp" />
<ClCompile Include="asmjit\src\asmjit\core\codewriter.cpp" />
<ClCompile Include="asmjit\src\asmjit\core\compiler.cpp" />
<ClCompile Include="asmjit\src\asmjit\core\constpool.cpp" />
<ClCompile Include="asmjit\src\asmjit\core\cpuinfo.cpp" />
<ClCompile Include="asmjit\src\asmjit\core\emithelper.cpp" />
<ClCompile Include="asmjit\src\asmjit\core\emitter.cpp" />
<ClCompile Include="asmjit\src\asmjit\core\emitterutils.cpp" />
<ClCompile Include="asmjit\src\asmjit\core\environment.cpp" />
<ClCompile Include="asmjit\src\asmjit\core\errorhandler.cpp" />
<ClCompile Include="asmjit\src\asmjit\core\formatter.cpp" />
<ClCompile Include="asmjit\src\asmjit\core\funcargscontext.cpp" />
<ClCompile Include="asmjit\src\asmjit\core\func.cpp" />
<ClCompile Include="asmjit\src\asmjit\core\globals.cpp" />
<ClCompile Include="asmjit\src\asmjit\core\inst.cpp" />
<ClCompile Include="asmjit\src\asmjit\core\jitallocator.cpp" />
<ClCompile Include="asmjit\src\asmjit\core\jitruntime.cpp" />
<ClCompile Include="asmjit\src\asmjit\core\logger.cpp" />
<ClCompile Include="asmjit\src\asmjit\core\operand.cpp" />
<ClCompile Include="asmjit\src\asmjit\core\osutils.cpp" />
<ClCompile Include="asmjit\src\asmjit\core\ralocal.cpp" />
<ClCompile Include="asmjit\src\asmjit\core\rapass.cpp" />
<ClCompile Include="asmjit\src\asmjit\core\rastack.cpp" />
<ClCompile Include="asmjit\src\asmjit\core\string.cpp" />
<ClCompile Include="asmjit\src\asmjit\core\support.cpp" />
<ClCompile Include="asmjit\src\asmjit\core\target.cpp" />
<ClCompile Include="asmjit\src\asmjit\core\type.cpp" />
<ClCompile Include="asmjit\src\asmjit\core\virtmem.cpp" />
<ClCompile Include="asmjit\src\asmjit\core\zone.cpp" />
<ClCompile Include="asmjit\src\asmjit\core\zonehash.cpp" />
<ClCompile Include="asmjit\src\asmjit\core\zonelist.cpp" />
<ClCompile Include="asmjit\src\asmjit\core\zonestack.cpp" />
<ClCompile Include="asmjit\src\asmjit\core\zonetree.cpp" />
<ClCompile Include="asmjit\src\asmjit\core\zonevector.cpp" />
<ClCompile Include="asmjit\src\asmjit\x86\x86assembler.cpp" />
<ClCompile Include="asmjit\src\asmjit\x86\x86builder.cpp" />
<ClCompile Include="asmjit\src\asmjit\x86\x86compiler.cpp" />
<ClCompile Include="asmjit\src\asmjit\x86\x86inst.cpp" />
<ClCompile Include="asmjit\src\asmjit\x86\x86instimpl.cpp" />
<ClCompile Include="asmjit\src\asmjit\x86\x86internal.cpp" />
<ClCompile Include="asmjit\src\asmjit\x86\x86logging.cpp" />
<ClCompile Include="asmjit\src\asmjit\x86\x86emithelper.cpp" />
<ClCompile Include="asmjit\src\asmjit\x86\x86formatter.cpp" />
<ClCompile Include="asmjit\src\asmjit\x86\x86func.cpp" />
<ClCompile Include="asmjit\src\asmjit\x86\x86instapi.cpp" />
<ClCompile Include="asmjit\src\asmjit\x86\x86instdb.cpp" />
<ClCompile Include="asmjit\src\asmjit\x86\x86operand.cpp" />
<ClCompile Include="asmjit\src\asmjit\x86\x86operand_regs.cpp" />
<ClCompile Include="asmjit\src\asmjit\x86\x86regalloc.cpp" />
<ClCompile Include="asmjit\src\asmjit\x86\x86rapass.cpp" />
<ClCompile Include="asmjit\src\asmjit\arm\a64assembler.cpp" />
<ClCompile Include="asmjit\src\asmjit\arm\a64builder.cpp" />
<ClCompile Include="asmjit\src\asmjit\arm\a64compiler.cpp" />
<ClCompile Include="asmjit\src\asmjit\arm\a64emithelper.cpp" />
<ClCompile Include="asmjit\src\asmjit\arm\a64instapi.cpp" />
<ClCompile Include="asmjit\src\asmjit\arm\a64instdb.cpp" />
<ClCompile Include="asmjit\src\asmjit\arm\a64operand.cpp" />
<ClCompile Include="asmjit\src\asmjit\arm\a64rapass.cpp" />
<ClCompile Include="asmjit\src\asmjit\arm\armformatter.cpp" />
<ClCompile Include="asmjit\src\asmjit\arm\armfunc.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="asmjit\src\asmjit\base\arch.h" />
<ClInclude Include="asmjit\src\asmjit\base\assembler.h" />
<ClInclude Include="asmjit\src\asmjit\base\codebuilder.h" />
<ClInclude Include="asmjit\src\asmjit\base\codecompiler.h" />
<ClInclude Include="asmjit\src\asmjit\base\codeemitter.h" />
<ClInclude Include="asmjit\src\asmjit\base\codeholder.h" />
<ClInclude Include="asmjit\src\asmjit\base\constpool.h" />
<ClInclude Include="asmjit\src\asmjit\base\context_p.h" />
<ClInclude Include="asmjit\src\asmjit\base\cpuinfo.h" />
<ClInclude Include="asmjit\src\asmjit\base\func.h" />
<ClInclude Include="asmjit\src\asmjit\base\logging.h" />
<ClInclude Include="asmjit\src\asmjit\base\globals.h" />
<ClInclude Include="asmjit\src\asmjit\base\inst.h" />
<ClInclude Include="asmjit\src\asmjit\base\lock.h" />
<ClInclude Include="asmjit\src\asmjit\base\operand.h" />
<ClInclude Include="asmjit\src\asmjit\base\osutils.h" />
<ClInclude Include="asmjit\src\asmjit\base\regalloc_p.h" />
<ClInclude Include="asmjit\src\asmjit\base\runtime.h" />
<ClInclude Include="asmjit\src\asmjit\base\string.h" />
<ClInclude Include="asmjit\src\asmjit\base\vectypes.h" />
<ClInclude Include="asmjit\src\asmjit\base\vmem.h" />
<ClInclude Include="asmjit\src\asmjit\base\zone.h" />
<ClInclude Include="asmjit\src\asmjit\core\api-build_p.h" />
<ClInclude Include="asmjit\src\asmjit\core\api-config.h" />
<ClInclude Include="asmjit\src\asmjit\core\archcommons.h" />
<ClInclude Include="asmjit\src\asmjit\core\archtraits.h" />
<ClInclude Include="asmjit\src\asmjit\core\assembler.h" />
<ClInclude Include="asmjit\src\asmjit\core\builder.h" />
<ClInclude Include="asmjit\src\asmjit\core\codebuffer.h" />
<ClInclude Include="asmjit\src\asmjit\core\codeholder.h" />
<ClInclude Include="asmjit\src\asmjit\core\codewriter_p.h" />
<ClInclude Include="asmjit\src\asmjit\core\compilerdefs.h" />
<ClInclude Include="asmjit\src\asmjit\core\compiler.h" />
<ClInclude Include="asmjit\src\asmjit\core\constpool.h" />
<ClInclude Include="asmjit\src\asmjit\core\cpuinfo.h" />
<ClInclude Include="asmjit\src\asmjit\core\emithelper_p.h" />
<ClInclude Include="asmjit\src\asmjit\core\emitter.h" />
<ClInclude Include="asmjit\src\asmjit\core\emitterutils_p.h" />
<ClInclude Include="asmjit\src\asmjit\core\environment.h" />
<ClInclude Include="asmjit\src\asmjit\core\errorhandler.h" />
<ClInclude Include="asmjit\src\asmjit\core\formatter.h" />
<ClInclude Include="asmjit\src\asmjit\core\formatter_p.h" />
<ClInclude Include="asmjit\src\asmjit\core\funcargscontext_p.h" />
<ClInclude Include="asmjit\src\asmjit\core\func.h" />
<ClInclude Include="asmjit\src\asmjit\core\globals.h" />
<ClInclude Include="asmjit\src\asmjit\core\inst.h" />
<ClInclude Include="asmjit\src\asmjit\core\jitallocator.h" />
<ClInclude Include="asmjit\src\asmjit\core\jitruntime.h" />
<ClInclude Include="asmjit\src\asmjit\core\logger.h" />
<ClInclude Include="asmjit\src\asmjit\core\misc_p.h" />
<ClInclude Include="asmjit\src\asmjit\core\operand.h" />
<ClInclude Include="asmjit\src\asmjit\core\osutils.h" />
<ClInclude Include="asmjit\src\asmjit\core\osutils_p.h" />
<ClInclude Include="asmjit\src\asmjit\core\raassignment_p.h" />
<ClInclude Include="asmjit\src\asmjit\core\rabuilders_p.h" />
<ClInclude Include="asmjit\src\asmjit\core\radefs_p.h" />
<ClInclude Include="asmjit\src\asmjit\core\ralocal_p.h" />
<ClInclude Include="asmjit\src\asmjit\core\rapass_p.h" />
<ClInclude Include="asmjit\src\asmjit\core\rastack_p.h" />
<ClInclude Include="asmjit\src\asmjit\core\string.h" />
<ClInclude Include="asmjit\src\asmjit\core\support.h" />
<ClInclude Include="asmjit\src\asmjit\core\target.h" />
<ClInclude Include="asmjit\src\asmjit\core\type.h" />
<ClInclude Include="asmjit\src\asmjit\core\virtmem.h" />
<ClInclude Include="asmjit\src\asmjit\core\zone.h" />
<ClInclude Include="asmjit\src\asmjit\core\zonehash.h" />
<ClInclude Include="asmjit\src\asmjit\core\zonelist.h" />
<ClInclude Include="asmjit\src\asmjit\core\zonestack.h" />
<ClInclude Include="asmjit\src\asmjit\core\zonestring.h" />
<ClInclude Include="asmjit\src\asmjit\core\zonetree.h" />
<ClInclude Include="asmjit\src\asmjit\core\zonevector.h" />
<ClInclude Include="asmjit\src\asmjit\x86\x86archtraits_p.h" />
<ClInclude Include="asmjit\src\asmjit\x86\x86assembler.h" />
<ClInclude Include="asmjit\src\asmjit\x86\x86builder.h" />
<ClInclude Include="asmjit\src\asmjit\x86\x86compiler.h" />
<ClInclude Include="asmjit\src\asmjit\x86\x86inst.h" />
<ClInclude Include="asmjit\src\asmjit\x86\x86instimpl_p.h" />
<ClInclude Include="asmjit\src\asmjit\x86\x86internal_p.h" />
<ClInclude Include="asmjit\src\asmjit\x86\x86logging_p.h" />
<ClInclude Include="asmjit\src\asmjit\x86\x86emithelper_p.h" />
<ClInclude Include="asmjit\src\asmjit\x86\x86emitter.h" />
<ClInclude Include="asmjit\src\asmjit\x86\x86formatter_p.h" />
<ClInclude Include="asmjit\src\asmjit\x86\x86func_p.h" />
<ClInclude Include="asmjit\src\asmjit\x86\x86globals.h" />
<ClInclude Include="asmjit\src\asmjit\x86\x86instapi_p.h" />
<ClInclude Include="asmjit\src\asmjit\x86\x86instdb.h" />
<ClInclude Include="asmjit\src\asmjit\x86\x86instdb_p.h" />
<ClInclude Include="asmjit\src\asmjit\x86\x86opcode_p.h" />
<ClInclude Include="asmjit\src\asmjit\x86\x86operand.h" />
<ClInclude Include="asmjit\src\asmjit\x86\x86regalloc_p.h" />
<ClInclude Include="asmjit\src\asmjit\x86\x86rapass_p.h" />
<ClInclude Include="asmjit\src\asmjit\arm\a64assembler.h" />
<ClInclude Include="asmjit\src\asmjit\arm\a64builder.h" />
<ClInclude Include="asmjit\src\asmjit\arm\a64compiler.h" />
<ClInclude Include="asmjit\src\asmjit\arm\a64emithelper_p.h" />
<ClInclude Include="asmjit\src\asmjit\arm\a64emitter.h" />
<ClInclude Include="asmjit\src\asmjit\arm\a64globals.h" />
<ClInclude Include="asmjit\src\asmjit\arm\a64instapi_p.h" />
<ClInclude Include="asmjit\src\asmjit\arm\a64instdb.h" />
<ClInclude Include="asmjit\src\asmjit\arm\a64instdb_p.h" />
<ClInclude Include="asmjit\src\asmjit\arm\a64operand.h" />
<ClInclude Include="asmjit\src\asmjit\arm\a64rapass_p.h" />
<ClInclude Include="asmjit\src\asmjit\arm\a64utils.h" />
<ClInclude Include="asmjit\src\asmjit\arm\armarchtraits_p.h" />
<ClInclude Include="asmjit\src\asmjit\arm\armformatter_p.h" />
<ClInclude Include="asmjit\src\asmjit\arm\armfunc_p.h" />
<ClInclude Include="asmjit\src\asmjit\arm\armglobals.h" />
<ClInclude Include="asmjit\src\asmjit\arm\armoperand.h" />
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{AC40FF01-426E-4838-A317-66354CEFAE88}</ProjectGuid>
+132 -52
View File
@@ -1,65 +1,145 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<ClCompile Include="asmjit\src\asmjit\base\arch.cpp" />
<ClCompile Include="asmjit\src\asmjit\base\assembler.cpp" />
<ClCompile Include="asmjit\src\asmjit\base\codebuilder.cpp" />
<ClCompile Include="asmjit\src\asmjit\base\codecompiler.cpp" />
<ClCompile Include="asmjit\src\asmjit\base\codeemitter.cpp" />
<ClCompile Include="asmjit\src\asmjit\base\codeholder.cpp" />
<ClCompile Include="asmjit\src\asmjit\base\constpool.cpp" />
<ClCompile Include="asmjit\src\asmjit\base\cpuinfo.cpp" />
<ClCompile Include="asmjit\src\asmjit\base\func.cpp" />
<ClCompile Include="asmjit\src\asmjit\base\globals.cpp" />
<ClCompile Include="asmjit\src\asmjit\base\inst.cpp" />
<ClCompile Include="asmjit\src\asmjit\base\logging.cpp" />
<ClCompile Include="asmjit\src\asmjit\base\osutils.cpp" />
<ClCompile Include="asmjit\src\asmjit\base\operand.cpp" />
<ClCompile Include="asmjit\src\asmjit\base\regalloc.cpp" />
<ClCompile Include="asmjit\src\asmjit\base\runtime.cpp" />
<ClCompile Include="asmjit\src\asmjit\base\string.cpp" />
<ClCompile Include="asmjit\src\asmjit\base\vmem.cpp" />
<ClCompile Include="asmjit\src\asmjit\base\zone.cpp" />
<ClCompile Include="asmjit\src\asmjit\core\archtraits.cpp" />
<ClCompile Include="asmjit\src\asmjit\core\assembler.cpp" />
<ClCompile Include="asmjit\src\asmjit\core\builder.cpp" />
<ClCompile Include="asmjit\src\asmjit\core\codeholder.cpp" />
<ClCompile Include="asmjit\src\asmjit\core\codewriter.cpp" />
<ClCompile Include="asmjit\src\asmjit\core\compiler.cpp" />
<ClCompile Include="asmjit\src\asmjit\core\constpool.cpp" />
<ClCompile Include="asmjit\src\asmjit\core\cpuinfo.cpp" />
<ClCompile Include="asmjit\src\asmjit\core\emithelper.cpp" />
<ClCompile Include="asmjit\src\asmjit\core\emitter.cpp" />
<ClCompile Include="asmjit\src\asmjit\core\emitterutils.cpp" />
<ClCompile Include="asmjit\src\asmjit\core\environment.cpp" />
<ClCompile Include="asmjit\src\asmjit\core\errorhandler.cpp" />
<ClCompile Include="asmjit\src\asmjit\core\formatter.cpp" />
<ClCompile Include="asmjit\src\asmjit\core\funcargscontext.cpp" />
<ClCompile Include="asmjit\src\asmjit\core\func.cpp" />
<ClCompile Include="asmjit\src\asmjit\core\globals.cpp" />
<ClCompile Include="asmjit\src\asmjit\core\inst.cpp" />
<ClCompile Include="asmjit\src\asmjit\core\jitallocator.cpp" />
<ClCompile Include="asmjit\src\asmjit\core\jitruntime.cpp" />
<ClCompile Include="asmjit\src\asmjit\core\logger.cpp" />
<ClCompile Include="asmjit\src\asmjit\core\operand.cpp" />
<ClCompile Include="asmjit\src\asmjit\core\osutils.cpp" />
<ClCompile Include="asmjit\src\asmjit\core\ralocal.cpp" />
<ClCompile Include="asmjit\src\asmjit\core\rapass.cpp" />
<ClCompile Include="asmjit\src\asmjit\core\rastack.cpp" />
<ClCompile Include="asmjit\src\asmjit\core\string.cpp" />
<ClCompile Include="asmjit\src\asmjit\core\support.cpp" />
<ClCompile Include="asmjit\src\asmjit\core\target.cpp" />
<ClCompile Include="asmjit\src\asmjit\core\type.cpp" />
<ClCompile Include="asmjit\src\asmjit\core\virtmem.cpp" />
<ClCompile Include="asmjit\src\asmjit\core\zone.cpp" />
<ClCompile Include="asmjit\src\asmjit\core\zonehash.cpp" />
<ClCompile Include="asmjit\src\asmjit\core\zonelist.cpp" />
<ClCompile Include="asmjit\src\asmjit\core\zonestack.cpp" />
<ClCompile Include="asmjit\src\asmjit\core\zonetree.cpp" />
<ClCompile Include="asmjit\src\asmjit\core\zonevector.cpp" />
<ClCompile Include="asmjit\src\asmjit\x86\x86assembler.cpp" />
<ClCompile Include="asmjit\src\asmjit\x86\x86builder.cpp" />
<ClCompile Include="asmjit\src\asmjit\x86\x86compiler.cpp" />
<ClCompile Include="asmjit\src\asmjit\x86\x86inst.cpp" />
<ClCompile Include="asmjit\src\asmjit\x86\x86instimpl.cpp" />
<ClCompile Include="asmjit\src\asmjit\x86\x86internal.cpp" />
<ClCompile Include="asmjit\src\asmjit\x86\x86logging.cpp" />
<ClCompile Include="asmjit\src\asmjit\x86\x86emithelper.cpp" />
<ClCompile Include="asmjit\src\asmjit\x86\x86formatter.cpp" />
<ClCompile Include="asmjit\src\asmjit\x86\x86func.cpp" />
<ClCompile Include="asmjit\src\asmjit\x86\x86instapi.cpp" />
<ClCompile Include="asmjit\src\asmjit\x86\x86instdb.cpp" />
<ClCompile Include="asmjit\src\asmjit\x86\x86operand.cpp" />
<ClCompile Include="asmjit\src\asmjit\x86\x86operand_regs.cpp" />
<ClCompile Include="asmjit\src\asmjit\x86\x86regalloc.cpp" />
<ClCompile Include="asmjit\src\asmjit\x86\x86rapass.cpp" />
<ClCompile Include="asmjit\src\asmjit\arm\a64assembler.cpp" />
<ClCompile Include="asmjit\src\asmjit\arm\a64builder.cpp" />
<ClCompile Include="asmjit\src\asmjit\arm\a64compiler.cpp" />
<ClCompile Include="asmjit\src\asmjit\arm\a64emithelper.cpp" />
<ClCompile Include="asmjit\src\asmjit\arm\a64instapi.cpp" />
<ClCompile Include="asmjit\src\asmjit\arm\a64instdb.cpp" />
<ClCompile Include="asmjit\src\asmjit\arm\a64operand.cpp" />
<ClCompile Include="asmjit\src\asmjit\arm\a64rapass.cpp" />
<ClCompile Include="asmjit\src\asmjit\arm\armformatter.cpp" />
<ClCompile Include="asmjit\src\asmjit\arm\armfunc.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="asmjit\src\asmjit\base\arch.h" />
<ClInclude Include="asmjit\src\asmjit\base\assembler.h" />
<ClInclude Include="asmjit\src\asmjit\base\codebuilder.h" />
<ClInclude Include="asmjit\src\asmjit\base\codecompiler.h" />
<ClInclude Include="asmjit\src\asmjit\base\codeemitter.h" />
<ClInclude Include="asmjit\src\asmjit\base\codeholder.h" />
<ClInclude Include="asmjit\src\asmjit\base\constpool.h" />
<ClInclude Include="asmjit\src\asmjit\base\context_p.h" />
<ClInclude Include="asmjit\src\asmjit\base\cpuinfo.h" />
<ClInclude Include="asmjit\src\asmjit\base\func.h" />
<ClInclude Include="asmjit\src\asmjit\base\logging.h" />
<ClInclude Include="asmjit\src\asmjit\base\globals.h" />
<ClInclude Include="asmjit\src\asmjit\base\inst.h" />
<ClInclude Include="asmjit\src\asmjit\base\lock.h" />
<ClInclude Include="asmjit\src\asmjit\base\operand.h" />
<ClInclude Include="asmjit\src\asmjit\base\osutils.h" />
<ClInclude Include="asmjit\src\asmjit\base\regalloc_p.h" />
<ClInclude Include="asmjit\src\asmjit\base\runtime.h" />
<ClInclude Include="asmjit\src\asmjit\base\string.h" />
<ClInclude Include="asmjit\src\asmjit\base\vectypes.h" />
<ClInclude Include="asmjit\src\asmjit\base\vmem.h" />
<ClInclude Include="asmjit\src\asmjit\base\zone.h" />
<ClInclude Include="asmjit\src\asmjit\core\api-build_p.h" />
<ClInclude Include="asmjit\src\asmjit\core\api-config.h" />
<ClInclude Include="asmjit\src\asmjit\core\archcommons.h" />
<ClInclude Include="asmjit\src\asmjit\core\archtraits.h" />
<ClInclude Include="asmjit\src\asmjit\core\assembler.h" />
<ClInclude Include="asmjit\src\asmjit\core\builder.h" />
<ClInclude Include="asmjit\src\asmjit\core\codebuffer.h" />
<ClInclude Include="asmjit\src\asmjit\core\codeholder.h" />
<ClInclude Include="asmjit\src\asmjit\core\codewriter_p.h" />
<ClInclude Include="asmjit\src\asmjit\core\compilerdefs.h" />
<ClInclude Include="asmjit\src\asmjit\core\compiler.h" />
<ClInclude Include="asmjit\src\asmjit\core\constpool.h" />
<ClInclude Include="asmjit\src\asmjit\core\cpuinfo.h" />
<ClInclude Include="asmjit\src\asmjit\core\emithelper_p.h" />
<ClInclude Include="asmjit\src\asmjit\core\emitter.h" />
<ClInclude Include="asmjit\src\asmjit\core\emitterutils_p.h" />
<ClInclude Include="asmjit\src\asmjit\core\environment.h" />
<ClInclude Include="asmjit\src\asmjit\core\errorhandler.h" />
<ClInclude Include="asmjit\src\asmjit\core\formatter.h" />
<ClInclude Include="asmjit\src\asmjit\core\formatter_p.h" />
<ClInclude Include="asmjit\src\asmjit\core\funcargscontext_p.h" />
<ClInclude Include="asmjit\src\asmjit\core\func.h" />
<ClInclude Include="asmjit\src\asmjit\core\globals.h" />
<ClInclude Include="asmjit\src\asmjit\core\inst.h" />
<ClInclude Include="asmjit\src\asmjit\core\jitallocator.h" />
<ClInclude Include="asmjit\src\asmjit\core\jitruntime.h" />
<ClInclude Include="asmjit\src\asmjit\core\logger.h" />
<ClInclude Include="asmjit\src\asmjit\core\misc_p.h" />
<ClInclude Include="asmjit\src\asmjit\core\operand.h" />
<ClInclude Include="asmjit\src\asmjit\core\osutils.h" />
<ClInclude Include="asmjit\src\asmjit\core\osutils_p.h" />
<ClInclude Include="asmjit\src\asmjit\core\raassignment_p.h" />
<ClInclude Include="asmjit\src\asmjit\core\rabuilders_p.h" />
<ClInclude Include="asmjit\src\asmjit\core\radefs_p.h" />
<ClInclude Include="asmjit\src\asmjit\core\ralocal_p.h" />
<ClInclude Include="asmjit\src\asmjit\core\rapass_p.h" />
<ClInclude Include="asmjit\src\asmjit\core\rastack_p.h" />
<ClInclude Include="asmjit\src\asmjit\core\string.h" />
<ClInclude Include="asmjit\src\asmjit\core\support.h" />
<ClInclude Include="asmjit\src\asmjit\core\target.h" />
<ClInclude Include="asmjit\src\asmjit\core\type.h" />
<ClInclude Include="asmjit\src\asmjit\core\virtmem.h" />
<ClInclude Include="asmjit\src\asmjit\core\zone.h" />
<ClInclude Include="asmjit\src\asmjit\core\zonehash.h" />
<ClInclude Include="asmjit\src\asmjit\core\zonelist.h" />
<ClInclude Include="asmjit\src\asmjit\core\zonestack.h" />
<ClInclude Include="asmjit\src\asmjit\core\zonestring.h" />
<ClInclude Include="asmjit\src\asmjit\core\zonetree.h" />
<ClInclude Include="asmjit\src\asmjit\core\zonevector.h" />
<ClInclude Include="asmjit\src\asmjit\x86\x86archtraits_p.h" />
<ClInclude Include="asmjit\src\asmjit\x86\x86assembler.h" />
<ClInclude Include="asmjit\src\asmjit\x86\x86builder.h" />
<ClInclude Include="asmjit\src\asmjit\x86\x86compiler.h" />
<ClInclude Include="asmjit\src\asmjit\x86\x86inst.h" />
<ClInclude Include="asmjit\src\asmjit\x86\x86instimpl_p.h" />
<ClInclude Include="asmjit\src\asmjit\x86\x86internal_p.h" />
<ClInclude Include="asmjit\src\asmjit\x86\x86logging_p.h" />
<ClInclude Include="asmjit\src\asmjit\x86\x86emithelper_p.h" />
<ClInclude Include="asmjit\src\asmjit\x86\x86emitter.h" />
<ClInclude Include="asmjit\src\asmjit\x86\x86formatter_p.h" />
<ClInclude Include="asmjit\src\asmjit\x86\x86func_p.h" />
<ClInclude Include="asmjit\src\asmjit\x86\x86globals.h" />
<ClInclude Include="asmjit\src\asmjit\x86\x86instapi_p.h" />
<ClInclude Include="asmjit\src\asmjit\x86\x86instdb.h" />
<ClInclude Include="asmjit\src\asmjit\x86\x86instdb_p.h" />
<ClInclude Include="asmjit\src\asmjit\x86\x86opcode_p.h" />
<ClInclude Include="asmjit\src\asmjit\x86\x86operand.h" />
<ClInclude Include="asmjit\src\asmjit\x86\x86regalloc_p.h" />
<ClInclude Include="asmjit\src\asmjit\x86\x86rapass_p.h" />
<ClInclude Include="asmjit\src\asmjit\arm\a64assembler.h" />
<ClInclude Include="asmjit\src\asmjit\arm\a64builder.h" />
<ClInclude Include="asmjit\src\asmjit\arm\a64compiler.h" />
<ClInclude Include="asmjit\src\asmjit\arm\a64emithelper_p.h" />
<ClInclude Include="asmjit\src\asmjit\arm\a64emitter.h" />
<ClInclude Include="asmjit\src\asmjit\arm\a64globals.h" />
<ClInclude Include="asmjit\src\asmjit\arm\a64instapi_p.h" />
<ClInclude Include="asmjit\src\asmjit\arm\a64instdb.h" />
<ClInclude Include="asmjit\src\asmjit\arm\a64instdb_p.h" />
<ClInclude Include="asmjit\src\asmjit\arm\a64operand.h" />
<ClInclude Include="asmjit\src\asmjit\arm\a64rapass_p.h" />
<ClInclude Include="asmjit\src\asmjit\arm\a64utils.h" />
<ClInclude Include="asmjit\src\asmjit\arm\armarchtraits_p.h" />
<ClInclude Include="asmjit\src\asmjit\arm\armformatter_p.h" />
<ClInclude Include="asmjit\src\asmjit\arm\armfunc_p.h" />
<ClInclude Include="asmjit\src\asmjit\arm\armglobals.h" />
<ClInclude Include="asmjit\src\asmjit\arm\armoperand.h" />
</ItemGroup>
</Project>
+12
View File
@@ -0,0 +1,12 @@
# Cubeb
function(add_sanitizers ...)
endfunction(add_sanitizers)
set(BUILD_SHARED_LIBS FALSE CACHE BOOL "Don't build shared libs")
set(BUILD_TESTS FALSE CACHE BOOL "Don't build tests")
set(BUILD_RUST_LIBS FALSE CACHE BOOL "Don't build rust libs")
set(BUILD_TOOLS FALSE CACHE BOOL "Don't build tools")
add_subdirectory(cubeb EXCLUDE_FROM_ALL)
add_library(3rdparty::cubeb ALIAS cubeb)
Vendored Submodule
+1
Submodule 3rdparty/cubeb/cubeb added at d512bfa07a
+3
View File
@@ -0,0 +1,3 @@
#pragma once
#define CUBEB_EXPORT
+87
View File
@@ -0,0 +1,87 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<ItemGroup>
<ClCompile Include="cubeb\src\cubeb.c" />
<ClCompile Include="cubeb\src\cubeb_log.cpp" />
<ClCompile Include="cubeb\src\cubeb_mixer.cpp" />
<ClCompile Include="cubeb\src\cubeb_resampler.cpp" />
<ClCompile Include="cubeb\src\cubeb_strings.c" />
<ClCompile Include="cubeb\src\cubeb_utils.cpp" />
<ClCompile Include="cubeb\src\cubeb_wasapi.cpp" />
<ClCompile Include="cubeb\src\cubeb_winmm.c" />
<ClCompile Include="cubeb\src\speex\resample.c" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="cubeb\include\cubeb\cubeb.h" />
<ClInclude Include="cubeb\src\cubeb-internal.h" />
<ClInclude Include="cubeb\src\cubeb-speex-resampler.h" />
<ClInclude Include="cubeb\src\cubeb_array_queue.h" />
<ClInclude Include="cubeb\src\cubeb_assert.h" />
<ClInclude Include="cubeb\src\cubeb_log.h" />
<ClInclude Include="cubeb\src\cubeb_mixer.h" />
<ClInclude Include="cubeb\src\cubeb_resampler.h" />
<ClInclude Include="cubeb\src\cubeb_resampler_internal.h" />
<ClInclude Include="cubeb\src\cubeb_ringbuffer.h" />
<ClInclude Include="cubeb\src\cubeb_ring_array.h" />
<ClInclude Include="cubeb\src\cubeb_strings.h" />
<ClInclude Include="cubeb\src\cubeb_utils.h" />
<ClInclude Include="cubeb\src\cubeb_utils_win.h" />
<ClInclude Include="cubeb\src\speex\arch.h" />
<ClInclude Include="cubeb\src\speex\fixed_generic.h" />
<ClInclude Include="cubeb\src\speex\resample_neon.h" />
<ClInclude Include="cubeb\src\speex\resample_sse.h" />
<ClInclude Include="cubeb\src\speex\speex_config_types.h" />
<ClInclude Include="cubeb\src\speex\speex_resampler.h" />
<ClInclude Include="cubeb\src\speex\stack_alloc.h" />
<ClInclude Include="extra\cubeb_export.h" />
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{fda7b080-03b0-48c8-b24f-88118981422a}</ProjectGuid>
<RootNamespace>libcubeb</RootNamespace>
</PropertyGroup>
<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 Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>false</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
<PreferredToolArchitecture>x64</PreferredToolArchitecture>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="$(SolutionDir)\buildfiles\msvc\rpcs3_default.props" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(SolutionDir)\buildfiles\msvc\rpcs3_debug.props" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(SolutionDir)\buildfiles\msvc\rpcs3_release.props" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<ItemDefinitionGroup>
<ClCompile>
<WarningLevel>TurnOffAllWarnings</WarningLevel>
<SDLCheck>false</SDLCheck>
<PreprocessorDefinitions>OUTSIDE_SPEEX;RANDOM_PREFIX=speex;FLOATING_POINT;EXPORT=;USE_WASAPI;USE_WINMM;CUBEB_WASAPI_USE_IAUDIOSTREAMVOLUME;_HAS_DEPRECATED_RESULT_OF;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>./cubeb/src/speex/;./extra/;./cubeb/src/;./cubeb/include/;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
</ItemDefinitionGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
+108
View File
@@ -0,0 +1,108 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<ClCompile Include="cubeb\src\speex\resample.c">
<Filter>Source files</Filter>
</ClCompile>
<ClCompile Include="cubeb\src\cubeb_winmm.c">
<Filter>Source files</Filter>
</ClCompile>
<ClCompile Include="cubeb\src\cubeb_utils.cpp">
<Filter>Source files</Filter>
</ClCompile>
<ClCompile Include="cubeb\src\cubeb_wasapi.cpp">
<Filter>Source files</Filter>
</ClCompile>
<ClCompile Include="cubeb\src\cubeb_strings.c">
<Filter>Source files</Filter>
</ClCompile>
<ClCompile Include="cubeb\src\cubeb_resampler.cpp">
<Filter>Source files</Filter>
</ClCompile>
<ClCompile Include="cubeb\src\cubeb_mixer.cpp">
<Filter>Source files</Filter>
</ClCompile>
<ClCompile Include="cubeb\src\cubeb_log.cpp">
<Filter>Source files</Filter>
</ClCompile>
<ClCompile Include="cubeb\src\cubeb.c">
<Filter>Source files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="cubeb\include\cubeb\cubeb.h">
<Filter>Header files</Filter>
</ClInclude>
<ClInclude Include="cubeb\src\speex\arch.h">
<Filter>Header files</Filter>
</ClInclude>
<ClInclude Include="cubeb\src\cubeb_array_queue.h">
<Filter>Header files</Filter>
</ClInclude>
<ClInclude Include="cubeb\src\cubeb_assert.h">
<Filter>Header files</Filter>
</ClInclude>
<ClInclude Include="extra\cubeb_export.h">
<Filter>Header files</Filter>
</ClInclude>
<ClInclude Include="cubeb\src\cubeb_log.h">
<Filter>Header files</Filter>
</ClInclude>
<ClInclude Include="cubeb\src\cubeb_mixer.h">
<Filter>Header files</Filter>
</ClInclude>
<ClInclude Include="cubeb\src\cubeb_resampler.h">
<Filter>Header files</Filter>
</ClInclude>
<ClInclude Include="cubeb\src\cubeb_resampler_internal.h">
<Filter>Header files</Filter>
</ClInclude>
<ClInclude Include="cubeb\src\cubeb_ring_array.h">
<Filter>Header files</Filter>
</ClInclude>
<ClInclude Include="cubeb\src\cubeb_ringbuffer.h">
<Filter>Header files</Filter>
</ClInclude>
<ClInclude Include="cubeb\src\cubeb_strings.h">
<Filter>Header files</Filter>
</ClInclude>
<ClInclude Include="cubeb\src\cubeb_utils.h">
<Filter>Header files</Filter>
</ClInclude>
<ClInclude Include="cubeb\src\cubeb_utils_win.h">
<Filter>Header files</Filter>
</ClInclude>
<ClInclude Include="cubeb\src\cubeb-internal.h">
<Filter>Header files</Filter>
</ClInclude>
<ClInclude Include="cubeb\src\cubeb-speex-resampler.h">
<Filter>Header files</Filter>
</ClInclude>
<ClInclude Include="cubeb\src\speex\fixed_generic.h">
<Filter>Header files</Filter>
</ClInclude>
<ClInclude Include="cubeb\src\speex\resample_neon.h">
<Filter>Header files</Filter>
</ClInclude>
<ClInclude Include="cubeb\src\speex\resample_sse.h">
<Filter>Header files</Filter>
</ClInclude>
<ClInclude Include="cubeb\src\speex\speex_config_types.h">
<Filter>Header files</Filter>
</ClInclude>
<ClInclude Include="cubeb\src\speex\speex_resampler.h">
<Filter>Header files</Filter>
</ClInclude>
<ClInclude Include="cubeb\src\speex\stack_alloc.h">
<Filter>Header files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<Filter Include="Source files">
<UniqueIdentifier>{cd86de6d-e811-4c48-9653-af00c7098a45}</UniqueIdentifier>
</Filter>
<Filter Include="Header files">
<UniqueIdentifier>{566bbf3e-ca28-4390-b054-58c92a66f24e}</UniqueIdentifier>
</Filter>
</ItemGroup>
</Project>
+1
View File
@@ -7,6 +7,7 @@ if(USE_SYSTEM_CURL)
target_link_libraries(libcurl INTERFACE CURL::libcurl)
else()
message("-- RPCS3: building libcurl + wolfssl submodules")
add_compile_definitions(HAVE_SNI)
option(BUILD_CURL_EXE "Set to ON to build curl executable." OFF)
option(CMAKE_USE_WOLFSSL "enable wolfSSL for SSL/TLS" ON)
option(HTTP_ONLY "disables all protocols except HTTP (This overrides all CURL_DISABLE_* options)" ON)
+19 -2
View File
@@ -13,6 +13,15 @@ if(WITH_LLVM)
option(LLVM_INCLUDE_UTILS OFF)
option(LLVM_CCACHE_BUILD ON)
if(WIN32)
set(LLVM_USE_INTEL_JITEVENTS ON)
endif()
if(CMAKE_SYSTEM MATCHES "Linux")
set(LLVM_USE_INTEL_JITEVENTS ON)
set(LLVM_USE_PERF ON)
endif()
set(CXX_FLAGS_OLD ${CMAKE_CXX_FLAGS})
if (MSVC)
@@ -26,7 +35,7 @@ if(WITH_LLVM)
set(CMAKE_CXX_FLAGS ${CXX_FLAGS_OLD})
# now tries to find LLVM again
find_package(LLVM 11.0 CONFIG)
find_package(LLVM 13.0 CONFIG)
if(NOT LLVM_FOUND)
message(FATAL_ERROR "Couldn't build LLVM from the submodule. You might need to run `git submodule update --init`")
endif()
@@ -39,7 +48,7 @@ if(WITH_LLVM)
set(LLVM_DIR ${CMAKE_SOURCE_DIR}/${LLVM_DIR})
endif()
find_package(LLVM 11.0 CONFIG)
find_package(LLVM 13.0 CONFIG)
if (NOT LLVM_FOUND)
if (LLVM_VERSION AND LLVM_VERSION_MAJOR LESS 11)
@@ -54,6 +63,14 @@ if(WITH_LLVM)
set(LLVM_LIBS LLVMMCJIT LLVMX86CodeGen LLVMX86AsmParser)
if(WIN32 OR CMAKE_SYSTEM MATCHES "Linux")
set(LLVM_LIBS ${LLVM_LIBS} LLVMIntelJITEvents)
endif()
if(CMAKE_SYSTEM MATCHES "Linux")
set(LLVM_LIBS ${LLVM_LIBS} LLVMPerfJITEvents)
endif()
add_library(3rdparty_llvm INTERFACE)
target_link_libraries(3rdparty_llvm INTERFACE ${LLVM_LIBS})
target_include_directories(3rdparty_llvm INTERFACE ${LLVM_INCLUDE_DIRS})
+1 -12
View File
@@ -27,18 +27,7 @@ else()
add_subdirectory(wolfssl EXCLUDE_FROM_ALL)
# TODO(cjj19970505@live.cn)
# This only works in single-config generator
# For a multi-config generator, we need to provide different wolfssl binaries for different config
if (GENERATOR_IS_MULTI_CONFIG)
message( FATAL_ERROR "RPCS3 can only be configured using single-config generator." )
endif()
if(MSVC)
set(WolfSSL_LIBRARY "${CMAKE_CURRENT_BINARY_DIR}/wolfssl/${CMAKE_BUILD_TYPE}/wolfssl.lib" CACHE INTERNAL "")
else()
set(WolfSSL_LIBRARY "${CMAKE_CURRENT_BINARY_DIR}/wolfssl/libwolfssl.a" CACHE INTERNAL "")
endif()
set(WolfSSL_LIBRARY "$<TARGET_FILE:wolfssl>" CACHE INTERNAL "")
# "${CMAKE_CURRENT_SOURCE_DIR}/wolfssl/wolfssl/" provides openssl headers
# So that curl can be built on an environment where openssl headers are not provided
+4 -4
View File
@@ -29,11 +29,11 @@ These are the essentials tools to build RPCS3 on Linux. Some of them can be inst
#### Arch Linux
sudo pacman -S glew openal cmake vulkan-validation-layers qt5-base qt5-declarative sdl2
sudo pacman -S glew openal cmake vulkan-validation-layers qt5-base qt5-declarative sdl2 sndio jack2
#### Debian & Ubuntu
sudo apt-get install build-essential libasound2-dev libpulse-dev libopenal-dev libglew-dev zlib1g-dev libedit-dev libvulkan-dev libudev-dev git libevdev-dev libsdl2-2.0 libsdl2-dev
sudo apt-get install build-essential libasound2-dev libpulse-dev libopenal-dev libglew-dev zlib1g-dev libedit-dev libvulkan-dev libudev-dev git libevdev-dev libsdl2-2.0 libsdl2-dev libjack-dev libsndio-dev
Ubuntu is usually horrendously out of date, and some packages need to be downloaded by hand. This part is for Qt, GCC, Vulkan, and CMake
##### Qt PPA
@@ -82,11 +82,11 @@ sudo apt-get install cmake
#### Fedora
sudo dnf install alsa-lib-devel cmake glew glew-devel libatomic libevdev-devel libudev-devel openal-devel qt5-qtbase-devel qt5-qtbase-private-devel vulkan-devel
sudo dnf install alsa-lib-devel cmake glew glew-devel libatomic libevdev-devel libudev-devel openal-devel qt5-qtbase-devel qt5-qtbase-private-devel vulkan-devel pipewire-jack-audio-connection-kit-devel qt5-qtmultimedia-devel qt5-qtsvg-devel
#### OpenSUSE
sudo zypper install git cmake libasound2 libpulse-devel openal-soft-devel glew-devel zlib-devel libedit-devel vulkan-devel libudev-devel libqt5-qtbase-devel libqt5gui-private-headers-devel libevdev-devel
sudo zypper install git cmake libasound2 libpulse-devel openal-soft-devel glew-devel zlib-devel libedit-devel vulkan-devel libudev-devel libqt5-qtbase-devel libqt5-qtmultimedia-devel libqt5-qtsvg-devel libQt5Gui-private-headers-devel libevdev-devel libsndio7_1 libjack-devel
## Setup the project
+6 -8
View File
@@ -15,8 +15,6 @@ endif()
option(USE_NATIVE_INSTRUCTIONS "USE_NATIVE_INSTRUCTIONS makes rpcs3 compile with -march=native, which is useful for local builds, but not good for packages." ON)
option(WITH_LLVM "Enable usage of LLVM library" ON)
option(BUILD_LLVM_SUBMODULE "Build LLVM from git submodule" ON)
option(USE_ALSA "ALSA audio backend" ON)
option(USE_PULSE "PulseAudio audio backend" ON)
option(USE_FAUDIO "FAudio audio backend" ON)
option(USE_LIBEVDEV "libevdev-based joystick support" ON)
option(USE_DISCORD_RPC "Discord rich presence integration" ON)
@@ -56,12 +54,12 @@ if(MSVC)
if(NOT(CMAKE_BUILD_TYPE MATCHES "Release" AND USE_MSVC_STATIC_CRT))
set(USE_DISCORD_RPC OFF CACHE BOOL "Discord RPC is only available in Release and static CRT build." FORCE)
endif()
if(USE_MSVC_STATIC_CRT)
set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
else()
# though doc ( https://cmake.org/cmake/help/latest/variable/CMAKE_MSVC_RUNTIME_LIBRARY.html )
# says if that property is not set then CMake uses the default value MultiThreaded$<$<CONFIG:Debug>:Debug>DLL
# says if that property is not set then CMake uses the default value MultiThreaded$<$<CONFIG:Debug>:Debug>DLL
# to select a MSVC runtime library.
# But yaml-cpp set /MT(d) if CMAKE_MSVC_RUNTIME_LIBRARY is undefined
# So we have to define it explicitly
@@ -71,10 +69,10 @@ if(MSVC)
# TODO(cjj19970505@live.cn)
# offical QT uses dynamic CRT.
# When building our lib with static CRT and debug build type
# and linking with Qt with dynmaic CRT and debug build,
# error is encountered in runtime (which is expected).
# But building our lib with static CRT and release build type,
# and linking with Qt with dynamic CRT and release build seems to be working,
# and linking with Qt with dynmaic CRT and debug build,
# error is encountered in runtime (which is expected).
# But building our lib with static CRT and release build type,
# and linking with Qt with dynamic CRT and release build seems to be working,
# which is the same config with VS solution.
# (though technically it might still have some hidden errors).
# So we allow static CRT in both relase and debug build, but prompt warning in debug build.
+1 -1
View File
@@ -3,7 +3,7 @@ RPCS3
[![Azure Build Status](https://dev.azure.com/nekotekina/nekotekina/_apis/build/status/RPCS3.rpcs3?branchName=master)](https://dev.azure.com/nekotekina/nekotekina/_build?definitionId=4&branchName=master)
[![Cirrus CI - Base Branch Build Status](https://img.shields.io/cirrus/github/RPCS3/rpcs3?label=Cirrus%20CI%20(FreeBSD)&logo=cirrus-ci)](https://cirrus-ci.com/github/RPCS3/rpcs3)
[![RPCS3 discord server](https://img.shields.io/discord/272035812277878785?color=%237289DA&label=RPCS3%20Discord&logo=discord&logoColor=white)](https://discord.me/rpcs3)
[![RPCS3 discord server](https://img.shields.io/discord/272035812277878785?color=5865F2&label=RPCS3%20Discord&logo=discord&logoColor=white)](https://discord.me/rpcs3)
The world's first free and open-source PlayStation 3 emulator/debugger, written in C++ for Windows and Linux.
+24 -19
View File
@@ -19,8 +19,8 @@ namespace cfg
}
}
_base::_base(type _type, node* owner, const std::string& name, bool dynamic)
: m_type(_type), m_dynamic(dynamic), m_name(name)
_base::_base(type _type, node* owner, std::string name, bool dynamic)
: m_type(_type), m_dynamic(dynamic), m_name(std::move(name))
{
for (const auto& node : owner->m_nodes)
{
@@ -33,7 +33,7 @@ namespace cfg
owner->m_nodes.emplace_back(this);
}
bool _base::from_string(const std::string&, bool)
bool _base::from_string(std::string_view, bool)
{
cfg_log.fatal("cfg::_base::from_string() purecall");
return false;
@@ -58,7 +58,7 @@ std::vector<std::string> cfg::make_int_range(s64 min, s64 max)
return {std::to_string(min), std::to_string(max)};
}
bool try_to_int64(s64* out, const std::string& value, s64 min, s64 max)
bool try_to_int64(s64* out, std::string_view value, s64 min, s64 max)
{
s64 result;
const char* start = &value.front();
@@ -104,7 +104,7 @@ std::vector<std::string> cfg::make_uint_range(u64 min, u64 max)
return {std::to_string(min), std::to_string(max)};
}
bool try_to_uint64(u64* out, const std::string& value, u64 min, u64 max)
bool try_to_uint64(u64* out, std::string_view value, u64 min, u64 max)
{
u64 result;
const char* start = &value.front();
@@ -136,7 +136,7 @@ bool try_to_uint64(u64* out, const std::string& value, u64 min, u64 max)
return true;
}
bool cfg::try_to_enum_value(u64* out, decltype(&fmt_class_string<int>::format) func, const std::string& value)
bool cfg::try_to_enum_value(u64* out, decltype(&fmt_class_string<int>::format) func, std::string_view value)
{
u64 max = umax;
@@ -320,7 +320,7 @@ void cfg::decode(const YAML::Node& data, cfg::_base& rhs, bool dynamic)
return;
}
std::map<std::string, std::string> values;
map_of_type<std::string> values;
for (const auto& pair : data)
{
@@ -339,7 +339,7 @@ void cfg::decode(const YAML::Node& data, cfg::_base& rhs, bool dynamic)
return; // ???
}
std::map<std::string, logs::level> values;
map_of_type<logs::level> values;
for (const auto& pair : data)
{
@@ -377,9 +377,9 @@ std::string cfg::node::to_string() const
return {out.c_str(), out.size()};
}
bool cfg::node::from_string(const std::string& value, bool dynamic)
bool cfg::node::from_string(std::string_view value, bool dynamic)
{
auto [result, error] = yaml_load(value);
auto [result, error] = yaml_load(std::string(value));
if (error.empty())
{
@@ -414,26 +414,31 @@ void cfg::set_entry::from_default()
m_set = {};
}
std::string cfg::map_entry::get_value(const std::string& key)
std::string cfg::map_entry::get_value(std::string_view key)
{
return m_map.contains(key) ? m_map.at(key) : "";
if (auto it = m_map.find(key); it != m_map.end())
{
return it->second;
}
return {};
}
void cfg::map_entry::set_value(const std::string& key, const std::string& value)
void cfg::map_entry::set_value(std::string key, std::string value)
{
m_map[key] = value;
m_map[std::move(key)] = std::move(value);
}
void cfg::map_entry::set_map(std::map<std::string, std::string>&& map)
void cfg::map_entry::set_map(map_of_type<std::string>&& map)
{
m_map = std::move(map);
}
void cfg::map_entry::erase(const std::string& key)
void cfg::map_entry::erase(std::string_view key)
{
if (m_map.contains(key))
if (auto it = m_map.find(key); it != m_map.end())
{
m_map.erase(key);
m_map.erase(it);
}
}
@@ -442,7 +447,7 @@ void cfg::map_entry::from_default()
set_map({});
}
void cfg::log_entry::set_map(std::map<std::string, logs::level>&& map)
void cfg::log_entry::set_map(map_of_type<logs::level>&& map)
{
m_map = std::move(map);
}
+26 -23
View File
@@ -21,7 +21,7 @@ namespace cfg
std::vector<std::string> make_uint_range(u64 min, u64 max);
// Internal hack
bool try_to_enum_value(u64* out, decltype(&fmt_class_string<int>::format) func, const std::string&);
bool try_to_enum_value(u64* out, decltype(&fmt_class_string<int>::format) func, std::string_view);
// Internal hack
std::vector<std::string> try_to_enum_list(decltype(&fmt_class_string<int>::format) func);
@@ -53,7 +53,7 @@ namespace cfg
_base(type _type);
// Owned entry constructor
_base(type _type, class node* owner, const std::string& name, bool dynamic);
_base(type _type, class node* owner, std::string name, bool dynamic);
public:
_base(const _base&) = delete;
@@ -80,7 +80,7 @@ namespace cfg
}
// Try to convert from string (optional)
virtual bool from_string(const std::string&, bool /*dynamic*/ = false);
virtual bool from_string(std::string_view, bool /*dynamic*/ = false);
// Get string list (optional)
virtual std::vector<std::string> to_list() const
@@ -107,8 +107,8 @@ namespace cfg
}
// Registered node constructor
node(node* owner, const std::string& name, bool dynamic = true)
: _base(type::node, owner, name, dynamic)
node(node* owner, std::string name, bool dynamic = true)
: _base(type::node, owner, std::move(name), dynamic)
{
}
@@ -122,7 +122,7 @@ namespace cfg
std::string to_string() const override;
// Deserialize node
bool from_string(const std::string& value, bool dynamic = false) override;
bool from_string(std::string_view value, bool dynamic = false) override;
// Set default values
void from_default() override;
@@ -135,8 +135,8 @@ namespace cfg
public:
bool def;
_bool(node* owner, const std::string& name, bool def = false, bool dynamic = false)
: _base(type::_bool, owner, name, dynamic)
_bool(node* owner, std::string name, bool def = false, bool dynamic = false)
: _base(type::_bool, owner, std::move(name), dynamic)
, m_value(def)
, def(def)
{
@@ -159,7 +159,7 @@ namespace cfg
return m_value ? "true" : "false";
}
bool from_string(const std::string& value, bool /*dynamic*/ = false) override
bool from_string(std::string_view value, bool /*dynamic*/ = false) override
{
if (value == "false")
m_value = false;
@@ -220,7 +220,7 @@ namespace cfg
return result; // TODO: ???
}
bool from_string(const std::string& value, bool /*dynamic*/ = false) override
bool from_string(std::string_view value, bool /*dynamic*/ = false) override
{
u64 result;
@@ -285,7 +285,7 @@ namespace cfg
return std::to_string(m_value);
}
bool from_string(const std::string& value, bool /*dynamic*/ = false) override
bool from_string(std::string_view value, bool /*dynamic*/ = false) override
{
s64 result;
if (try_to_int64(&result, value, Min, Max))
@@ -359,7 +359,7 @@ namespace cfg
return std::to_string(m_value);
}
bool from_string(const std::string& value, bool /*dynamic*/ = false) override
bool from_string(std::string_view value, bool /*dynamic*/ = false) override
{
u64 result;
if (try_to_uint64(&result, value, Min, Max))
@@ -430,9 +430,9 @@ namespace cfg
return *m_value.load().get();
}
bool from_string(const std::string& value, bool /*dynamic*/ = false) override
bool from_string(std::string_view value, bool /*dynamic*/ = false) override
{
m_value = value;
m_value = std::string(value);
return true;
}
};
@@ -474,9 +474,12 @@ namespace cfg
}
};
template<typename T>
using map_of_type = std::map<std::string, T, std::less<>>;
class map_entry final : public _base
{
std::map<std::string, std::string> m_map{};
map_of_type<std::string> m_map{};
public:
map_entry(node* owner, const std::string& name)
@@ -484,24 +487,24 @@ namespace cfg
{
}
const std::map<std::string, std::string>& get_map() const
const map_of_type<std::string>& get_map() const
{
return m_map;
}
std::string get_value(const std::string& key);
std::string get_value(std::string_view key);
void set_value(const std::string& key, const std::string& value);
void set_map(std::map<std::string, std::string>&& map);
void set_value(std::string key, std::string value);
void set_map(map_of_type<std::string>&& map);
void erase(const std::string& key);
void erase(std::string_view key);
void from_default() override;
};
class log_entry final : public _base
{
std::map<std::string, logs::level> m_map{};
map_of_type<logs::level> m_map{};
public:
log_entry(node* owner, const std::string& name)
@@ -509,12 +512,12 @@ namespace cfg
{
}
const std::map<std::string, logs::level>& get_map() const
const map_of_type<logs::level>& get_map() const
{
return m_map;
}
void set_map(std::map<std::string, logs::level>&& map);
void set_map(map_of_type<logs::level>&& map);
void from_default() override;
};
+27 -2
View File
@@ -9,6 +9,7 @@
#include <map>
#include "util/asm.hpp"
#include "util/coro.hpp"
using namespace std::literals::string_literals;
@@ -1182,7 +1183,7 @@ fs::file::file(const std::string& path, bs_t<open_mode> mode)
for (const char* data = static_cast<const char*>(buffer); count;)
{
const DWORD size = static_cast<DWORD>(std::min<u64>(count, DWORD{umax} & -4096));
const DWORD size = static_cast<DWORD>(std::min<u64>(count, DWORD{umax} & -4096));
DWORD nwritten = 0;
ensure(WriteFile(m_handle, data, size, &nwritten, nullptr)); // "file::write"
@@ -1658,7 +1659,7 @@ bool fs::dir::open(const std::string& path)
bool fs::file::strict_read_check(u64 _size, u64 type_size) const
{
if (usz pos0 = pos(), size0 = size(); pos0 >= size0 || (size0 - pos0) / type_size < _size)
if (usz pos0 = pos(), size0 = size(); (pos0 >= size0 ? 0 : (size0 - pos0)) / type_size < _size)
{
fs::g_tls_error = fs::error::inval;
return false;
@@ -2039,6 +2040,30 @@ bool fs::pending_file::commit(bool overwrite)
return false;
}
stx::generator<fs::dir_entry&> fs::list_dir_recursively(std::string path)
{
for (auto& entry : fs::dir(path))
{
if (entry.name == "." || entry.name == "..")
{
continue;
}
std::string new_path = path_append(path, entry.name);
if (entry.is_directory)
{
for (auto& nested : fs::list_dir_recursively(new_path))
{
co_yield nested;
}
}
entry.name = std::move(new_path);
co_yield entry;
}
}
template<>
void fmt_class_string<fs::seek_mode>::format(std::string& out, u64 arg)
{
+42 -54
View File
@@ -205,8 +205,6 @@ namespace fs
{
std::unique_ptr<file_base> m_file{};
bool strict_read_check(u64 size, u64 type_size) const;
public:
// Default constructor
file() = default;
@@ -281,6 +279,9 @@ namespace fs
return m_file->sync();
}
// 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;
// Read the data from the file and return the amount of data written in buffer
u64 read(void* buffer, u64 count,
u32 line = __builtin_LINE(),
@@ -337,8 +338,8 @@ namespace fs
}
// Write std::basic_string unconditionally
template <typename T>
std::enable_if_t<std::is_trivially_copyable_v<T> && !std::is_pointer_v<T>, const file&> write(const std::basic_string<T>& str,
template <typename T> requires (std::is_trivially_copyable_v<T> && !std::is_pointer_v<T>)
const file& write(const std::basic_string<T>& str,
u32 line = __builtin_LINE(),
u32 col = __builtin_COLUMN(),
const char* file = __builtin_FILE(),
@@ -349,8 +350,8 @@ namespace fs
}
// Write POD unconditionally
template <typename T>
std::enable_if_t<std::is_trivially_copyable_v<T> && !std::is_pointer_v<T>, const file&> write(const T& data,
template <typename T> requires (std::is_trivially_copyable_v<T> && !std::is_pointer_v<T>)
const file& write(const T& data,
pod_tag_t = pod_tag,
u32 line = __builtin_LINE(),
u32 col = __builtin_COLUMN(),
@@ -362,8 +363,8 @@ namespace fs
}
// Write POD std::vector unconditionally
template <typename T>
std::enable_if_t<std::is_trivially_copyable_v<T> && !std::is_pointer_v<T>, const file&> write(const std::vector<T>& vec,
template <typename T> requires (std::is_trivially_copyable_v<T> && !std::is_pointer_v<T>)
const file& write(const std::vector<T>& vec,
u32 line = __builtin_LINE(),
u32 col = __builtin_COLUMN(),
const char* file = __builtin_FILE(),
@@ -373,84 +374,69 @@ namespace fs
return *this;
}
// Read std::basic_string, size must be set by resize() method
template <typename T>
std::enable_if_t<std::is_trivially_copyable_v<T> && !std::is_pointer_v<T>, bool> read(std::basic_string<T>& str,
const char* file = __builtin_FILE(),
const char* func = __builtin_FUNCTION(),
u32 line = __builtin_LINE(),
u32 col = __builtin_COLUMN()) const
{
return read(&str[0], str.size() * sizeof(T), line, col, file, func) == str.size() * sizeof(T);
}
// Read std::basic_string
template <bool IsStrict = false, typename T>
std::enable_if_t<std::is_trivially_copyable_v<T> && !std::is_pointer_v<T>, bool> read(std::basic_string<T>& str, usz _size,
template <typename T> requires (std::is_trivially_copyable_v<T> && !std::is_pointer_v<T>)
bool read(std::basic_string<T>& str, usz _size = umax,
const char* file = __builtin_FILE(),
const char* func = __builtin_FUNCTION(),
u32 line = __builtin_LINE(),
u32 col = __builtin_COLUMN()) const
{
if (!m_file) xnull({line, col, file, func});
if (!_size) return true;
if constexpr (IsStrict)
if (_size != umax)
{
// If _size arg is too high std::bad_alloc may happen in resize and then we cannot error check
if (!strict_read_check(_size, sizeof(T))) return false;
// 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)))
{
return false;
}
str.resize(_size);
}
str.resize(_size);
return read(str.data(), sizeof(T) * _size, line, col, file, func) == sizeof(T) * _size;
return read(str.data(), sizeof(T) * str.size(), line, col, file, func) == sizeof(T) * str.size();
}
// Read POD, sizeof(T) is used
template <typename T>
std::enable_if_t<std::is_trivially_copyable_v<T> && !std::is_pointer_v<T>, bool> read(T& data,
template <typename T> requires (std::is_trivially_copyable_v<T> && !std::is_pointer_v<T>)
bool read(T& data,
pod_tag_t = pod_tag,
u32 line = __builtin_LINE(),
u32 col = __builtin_COLUMN(),
const char* file = __builtin_FILE(),
const char* func = __builtin_FUNCTION()) const
{
return read(&data, sizeof(T), line, col, file, func) == sizeof(T);
}
// Read POD std::vector, size must be set by resize() method
template <typename T>
std::enable_if_t<std::is_trivially_copyable_v<T> && !std::is_pointer_v<T>, bool> read(std::vector<T>& vec,
const char* file = __builtin_FILE(),
const char* func = __builtin_FUNCTION(),
u32 line = __builtin_LINE(),
u32 col = __builtin_COLUMN()) const
{
return read(vec.data(), sizeof(T) * vec.size(), line, col, file, func) == sizeof(T) * vec.size();
return read(std::addressof(data), sizeof(T), line, col, file, func) == sizeof(T);
}
// Read POD std::vector
template <bool IsStrict = false, typename T>
std::enable_if_t<std::is_trivially_copyable_v<T> && !std::is_pointer_v<T>, bool> read(std::vector<T>& vec, usz _size,
template <typename T> requires (std::is_trivially_copyable_v<T> && !std::is_pointer_v<T>)
bool read(std::vector<T>& vec, usz _size = umax,
const char* file = __builtin_FILE(),
const char* func = __builtin_FUNCTION(),
u32 line = __builtin_LINE(),
u32 col = __builtin_COLUMN()) const
{
if (!m_file) xnull({line, col, file, func});
if (!_size) return true;
if constexpr (IsStrict)
if (_size != umax)
{
if (!strict_read_check(_size, sizeof(T))) return false;
// 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)))
{
return false;
}
vec.resize(_size);
}
vec.resize(_size);
return read(vec.data(), sizeof(T) * _size, line, col, file, func) == sizeof(T) * _size;
return read(vec.data(), sizeof(T) * vec.size(), line, col, file, func) == sizeof(T) * vec.size();
}
// Read POD (experimental)
template <typename T>
std::enable_if_t<std::is_trivially_copyable_v<T> && !std::is_pointer_v<T>, T> read(
template <typename T> requires (std::is_trivially_copyable_v<T> && !std::is_pointer_v<T>)
T read(
pod_tag_t = pod_tag,
u32 line = __builtin_LINE(),
u32 col = __builtin_COLUMN(),
@@ -472,13 +458,13 @@ namespace fs
{
std::basic_string<T> result;
result.resize(size() / sizeof(T));
if (seek(0), !read(result, file, func, line, col)) xfail({line, col, file, func});
if (seek(0), !read(result, result.size(), file, func, line, col)) xfail({line, col, file, func});
return result;
}
// Read full file to std::vector
template<typename T>
std::enable_if_t<std::is_trivially_copyable_v<T> && !std::is_pointer_v<T>, std::vector<T>> to_vector(
template<typename T> requires (std::is_trivially_copyable_v<T> && !std::is_pointer_v<T>)
std::vector<T> to_vector(
u32 line = __builtin_LINE(),
u32 col = __builtin_COLUMN(),
const char* file = __builtin_FILE(),
@@ -486,7 +472,7 @@ namespace fs
{
std::vector<T> result;
result.resize(size() / sizeof(T));
if (seek(0), !read(result, file, func, line, col)) xfail({line, col, file, func});
if (seek(0), !read(result, result.size(), file, func, line, col)) xfail({line, col, file, func});
return result;
}
@@ -818,4 +804,6 @@ namespace fs
}
file make_gather(std::vector<file>);
stx::generator<dir_entry&> list_dir_recursively(std::string path);
}
+123 -78
View File
@@ -16,6 +16,15 @@
LOG_CHANNEL(jit_log, "JIT");
void jit_announce(uptr func, usz size, std::string_view name)
{
#ifdef __linux__
static const fs::file s_map(fmt::format("/tmp/perf-%d.map", getpid()), fs::rewrite + fs::append);
s_map.write(fmt::format("%x %x %s\n", func, size, name));
#endif
}
static u8* get_jit_memory()
{
// Reserve 2G memory (magic static)
@@ -104,8 +113,32 @@ static u8* add_jit_memory(usz size, uint align)
return pointer + pos;
}
const asmjit::Environment& jit_runtime_base::environment() const noexcept
{
static const asmjit::Environment g_env = asmjit::Environment::host();
return g_env;
}
void* jit_runtime_base::_add(asmjit::CodeHolder* code) noexcept
{
ensure(!code->flatten());
ensure(!code->resolveUnresolvedLinks());
usz codeSize = ensure(code->codeSize());
auto p = ensure(this->_alloc(codeSize, 64));
ensure(!code->relocateToBase(uptr(p)));
asmjit::VirtMem::ProtectJitReadWriteScope rwScope(p, codeSize);
for (asmjit::Section* section : code->_sections)
{
std::memcpy(p + section->offset(), section->data(), section->bufferSize());
}
return p;
}
jit_runtime::jit_runtime()
: HostRuntime()
{
}
@@ -113,38 +146,9 @@ jit_runtime::~jit_runtime()
{
}
asmjit::Error jit_runtime::_add(void** dst, asmjit::CodeHolder* code) noexcept
uchar* jit_runtime::_alloc(usz size, usz align) noexcept
{
usz codeSize = code->getCodeSize();
if (!codeSize) [[unlikely]]
{
*dst = nullptr;
return asmjit::kErrorNoCodeGenerated;
}
void* p = jit_runtime::alloc(codeSize, 16);
if (!p) [[unlikely]]
{
*dst = nullptr;
return asmjit::kErrorNoVirtualMemory;
}
usz relocSize = code->relocate(p);
if (!relocSize) [[unlikely]]
{
*dst = nullptr;
return asmjit::kErrorInvalidState;
}
flush(p, relocSize);
*dst = p;
return asmjit::kErrorOk;
}
asmjit::Error jit_runtime::_release(void*) noexcept
{
return asmjit::kErrorOk;
return jit_runtime::alloc(size, align, true);
}
u8* jit_runtime::alloc(usz size, uint align, bool exec) noexcept
@@ -191,12 +195,12 @@ void jit_runtime::finalize() noexcept
std::memcpy(alloc(s_data_init.size(), 1, false), s_data_init.data(), s_data_init.size());
}
asmjit::Runtime& asmjit::get_global_runtime()
jit_runtime_base& asmjit::get_global_runtime()
{
// 16 MiB for internal needs
static constexpr u64 size = 1024 * 1024 * 16;
struct custom_runtime final : asmjit::HostRuntime
struct custom_runtime final : jit_runtime_base
{
custom_runtime() noexcept
{
@@ -205,7 +209,7 @@ asmjit::Runtime& asmjit::get_global_runtime()
{
if (auto ptr = utils::memory_reserve(size, reinterpret_cast<void*>(addr)))
{
m_pos.raw() = static_cast<std::byte*>(ptr);
m_pos.raw() = static_cast<uchar*>(ptr);
break;
}
}
@@ -217,50 +221,26 @@ asmjit::Runtime& asmjit::get_global_runtime()
utils::memory_commit(m_pos, size, utils::protection::wx);
}
custom_runtime(const custom_runtime&) = delete;
custom_runtime& operator=(const custom_runtime&) = delete;
asmjit::Error _add(void** dst, asmjit::CodeHolder* code) noexcept override
uchar* _alloc(usz size, usz align) noexcept override
{
usz codeSize = code->getCodeSize();
if (!codeSize) [[unlikely]]
return m_pos.atomic_op([&](uchar*& pos) -> uchar*
{
*dst = nullptr;
return asmjit::kErrorNoCodeGenerated;
}
const auto r = reinterpret_cast<uchar*>(utils::align(uptr(pos), align));
void* p = m_pos.fetch_add(utils::align(codeSize, 4096));
if (!p || m_pos > m_max) [[unlikely]]
{
*dst = nullptr;
jit_log.fatal("Out of memory (static asmjit)");
return asmjit::kErrorNoVirtualMemory;
}
if (r >= pos && r + size > pos && r + size <= m_max)
{
pos = r + size;
return r;
}
usz relocSize = code->relocate(p);
if (!relocSize) [[unlikely]]
{
*dst = nullptr;
return asmjit::kErrorInvalidState;
}
utils::memory_protect(p, utils::align(codeSize, 4096), utils::protection::rx);
flush(p, relocSize);
*dst = p;
return asmjit::kErrorOk;
}
asmjit::Error _release(void*) noexcept override
{
return asmjit::kErrorOk;
return nullptr;
});
}
private:
atomic_t<std::byte*> m_pos{};
atomic_t<uchar*> m_pos{};
std::byte* m_max{};
uchar* m_max{};
};
// Magic static
@@ -268,6 +248,24 @@ asmjit::Runtime& asmjit::get_global_runtime()
return g_rt;
}
asmjit::inline_runtime::inline_runtime(uchar* data, usz size)
: m_data(data)
, m_size(size)
{
}
uchar* asmjit::inline_runtime::_alloc(usz size, usz align) noexcept
{
ensure(align <= 4096);
return size <= m_size ? m_data : nullptr;
}
asmjit::inline_runtime::~inline_runtime()
{
utils::memory_protect(m_data, m_size, utils::protection::rx);
}
#ifdef LLVM_AVAILABLE
#include <unordered_map>
@@ -293,6 +291,9 @@ asmjit::Runtime& asmjit::get_global_runtime()
#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
@@ -348,19 +349,19 @@ static u64 make_null_function(const std::string& name)
using namespace asmjit;
// Build a "null" function that contains its name
const auto func = build_function_asm<void (*)()>([&](X86Assembler& c, auto& args)
const auto func = build_function_asm<void (*)()>("NULL", [&](x86::Assembler& c, auto& args)
{
Label data = c.newLabel();
c.lea(args[0], x86::qword_ptr(data, 0));
c.jmp(imm_ptr(&null));
c.align(kAlignCode, 16);
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(kAlignData, 16);
c.align(AlignMode::kData, 16);
});
func_ptr = reinterpret_cast<u64>(func);
@@ -368,6 +369,42 @@ static u64 make_null_function(const std::string& name)
}
}
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
{
@@ -391,7 +428,8 @@ struct MemoryManager1 : llvm::RTDyldMemoryManager
~MemoryManager1() override
{
utils::memory_release(ptr, c_max_size * 2);
// 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
@@ -725,11 +763,12 @@ std::string jit_compiler::cpu(const std::string& _cpu)
}
jit_compiler::jit_compiler(const std::unordered_map<std::string, u64>& _link, const std::string& _cpu, u32 flags)
: m_cpu(cpu(_cpu))
: m_context(new llvm::LLVMContext)
, m_cpu(cpu(_cpu))
{
std::string result;
auto null_mod = std::make_unique<llvm::Module> ("null_", m_context);
auto null_mod = std::make_unique<llvm::Module> ("null_", *m_context);
if (_link.empty())
{
@@ -773,6 +812,12 @@ jit_compiler::jit_compiler(const std::unordered_map<std::string, u64>& _link, co
}
}
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);
+145 -55
View File
@@ -1,8 +1,12 @@
#pragma once
#include "util/types.hpp"
// Include asmjit with warnings ignored
#define ASMJIT_EMBED
#define ASMJIT_DEBUG
#define ASMJIT_STATIC
#define ASMJIT_BUILD_DEBUG
#undef Bool
#ifdef _MSC_VER
#pragma warning(push, 0)
@@ -27,6 +31,17 @@
#include <array>
#include <functional>
#include <memory>
#include <string>
#include <string_view>
#include <unordered_map>
void jit_announce(uptr func, usz size, std::string_view name);
void jit_announce(auto* func, usz size, std::string_view name)
{
jit_announce(uptr(func), size, name);
}
enum class jit_class
{
@@ -36,17 +51,27 @@ enum class jit_class
spu_data,
};
struct jit_runtime_base
{
jit_runtime_base() noexcept = default;
virtual ~jit_runtime_base() = default;
jit_runtime_base(const jit_runtime_base&) = delete;
jit_runtime_base& operator=(const jit_runtime_base&) = delete;
const asmjit::Environment& environment() const noexcept;
void* _add(asmjit::CodeHolder* code) noexcept;
virtual uchar* _alloc(usz size, usz align) noexcept = 0;
};
// ASMJIT runtime for emitting code in a single 2G region
struct jit_runtime final : asmjit::HostRuntime
struct jit_runtime final : jit_runtime_base
{
jit_runtime();
~jit_runtime() override;
// Allocate executable memory
asmjit::Error _add(void** dst, asmjit::CodeHolder* code) noexcept override;
// Do nothing (deallocation is delayed)
asmjit::Error _release(void* p) noexcept override;
uchar* _alloc(usz size, usz align) noexcept override;
// Allocate memory
static u8* alloc(usz size, uint align, bool exec = true) noexcept;
@@ -61,11 +86,25 @@ struct jit_runtime final : asmjit::HostRuntime
namespace asmjit
{
// Should only be used to build global functions
asmjit::Runtime& get_global_runtime();
jit_runtime_base& get_global_runtime();
// Don't use directly
class inline_runtime : public jit_runtime_base
{
uchar* m_data;
usz m_size;
public:
inline_runtime(uchar* data, usz size);
~inline_runtime();
uchar* _alloc(usz size, usz align) noexcept override;
};
// Emit xbegin and adjacent loop, return label at xbegin (don't use xabort please)
template <typename F>
[[nodiscard]] inline asmjit::Label build_transaction_enter(asmjit::X86Assembler& c, asmjit::Label fallback, F func)
[[nodiscard]] inline asmjit::Label build_transaction_enter(asmjit::x86::Assembler& c, asmjit::Label fallback, F func)
{
Label fall = c.newLabel();
Label begin = c.newLabel();
@@ -80,7 +119,7 @@ namespace asmjit
func();
// Other bad statuses are ignored regardless of repeat flag (TODO)
c.align(kAlignCode, 16);
c.align(AlignMode::kCode, 16);
c.bind(begin);
return fall;
@@ -88,7 +127,7 @@ namespace asmjit
}
// Helper to spill RDX (EDX) register for RDTSC
inline void build_swap_rdx_with(asmjit::X86Assembler& c, std::array<X86Gp, 4>& args, const asmjit::X86Gp& with)
inline void build_swap_rdx_with(asmjit::x86::Assembler& c, std::array<x86::Gp, 4>& args, const asmjit::x86::Gp& with)
{
#ifdef _WIN32
c.xchg(args[1], with);
@@ -100,7 +139,7 @@ namespace asmjit
}
// Get full RDTSC value into chosen register (clobbers rax/rdx or saves only rax with other target)
inline void build_get_tsc(asmjit::X86Assembler& c, const asmjit::X86Gp& to = asmjit::x86::rax)
inline void build_get_tsc(asmjit::x86::Assembler& c, const asmjit::x86::Gp& to = asmjit::x86::rax)
{
if (&to != &x86::rax && &to != &x86::rdx)
{
@@ -127,21 +166,22 @@ namespace asmjit
c.or_(to.r64(), x86::rdx);
}
}
using imm_ptr = Imm;
}
// Build runtime function with asmjit::X86Assembler
template <typename FT, typename F>
inline FT build_function_asm(F&& builder)
inline FT build_function_asm(std::string_view name, F&& builder)
{
using namespace asmjit;
auto& rt = get_global_runtime();
CodeHolder code;
code.init(rt.getCodeInfo());
code._globalHints = asmjit::CodeEmitter::kHintOptimizedAlign;
code.init(rt.environment());
std::array<X86Gp, 4> args;
std::array<x86::Gp, 4> args;
#ifdef _WIN32
args[0] = x86::rcx;
args[1] = x86::rdx;
@@ -154,59 +194,109 @@ inline FT build_function_asm(F&& builder)
args[3] = x86::rcx;
#endif
X86Assembler compiler(&code);
x86::Assembler compiler(&code);
compiler.addEncodingOptions(EncodingOptions::kOptimizedAlign);
builder(std::ref(compiler), args);
ensure(compiler.getLastError() == 0);
const auto result = rt._add(&code);
jit_announce(result, code.codeSize(), name);
return reinterpret_cast<FT>(uptr(result));
}
FT result;
#ifdef __APPLE__
template <typename FT, usz = 4096>
class built_function
{
FT m_func;
if (rt.add(&result, &code))
public:
built_function(const built_function&) = delete;
built_function& operator=(const built_function&) = delete;
template <typename F>
built_function(std::string_view name, F&& builder)
: m_func(ensure(build_function_asm<FT>(name, std::forward<F>(builder))))
{
return nullptr;
}
return result;
}
operator FT() const noexcept
{
return m_func;
}
template <typename... Args>
auto operator()(Args&&... args) const noexcept
{
return m_func(std::forward<Args>(args)...);
}
};
#else
template <typename FT, usz Size = 4096>
class built_function
{
alignas(4096) uchar m_data[Size];
public:
built_function(const built_function&) = delete;
built_function& operator=(const built_function&) = delete;
template <typename F>
built_function(std::string_view name, F&& builder)
{
using namespace asmjit;
inline_runtime rt(m_data, Size);
CodeHolder code;
code.init(rt.environment());
std::array<x86::Gp, 4> args;
#ifdef _WIN32
args[0] = x86::rcx;
args[1] = x86::rdx;
args[2] = x86::r8;
args[3] = x86::r9;
#else
args[0] = x86::rdi;
args[1] = x86::rsi;
args[2] = x86::rdx;
args[3] = x86::rcx;
#endif
x86::Assembler compiler(&code);
compiler.addEncodingOptions(EncodingOptions::kOptimizedAlign);
builder(std::ref(compiler), args);
jit_announce(rt._add(&code), code.codeSize(), name);
}
operator FT() const noexcept
{
return FT(+m_data);
}
template <typename... Args>
auto operator()(Args&&... args) const noexcept
{
return FT(+m_data)(std::forward<Args>(args)...);
}
};
#endif
#ifdef LLVM_AVAILABLE
#include <memory>
#include <string>
#include <string_view>
#include <unordered_map>
#include "util/types.hpp"
#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 "-Wsuggest-override"
#pragma GCC diagnostic ignored "-Wunused-parameter"
#pragma GCC diagnostic ignored "-Wstrict-aliasing"
#pragma GCC diagnostic ignored "-Weffc++"
#pragma GCC diagnostic ignored "-Wmissing-noreturn"
#ifdef __clang__
#pragma clang diagnostic ignored "-Winconsistent-missing-override"
#endif
#endif
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Module.h"
#include "llvm/ExecutionEngine/ExecutionEngine.h"
#ifdef _MSC_VER
#pragma warning(pop)
#else
#pragma GCC diagnostic pop
#endif
namespace llvm
{
class LLVMContext;
class ExecutionEngine;
class Module;
}
// Temporary compiler interface
class jit_compiler final
{
// Local LLVM context
llvm::LLVMContext m_context{};
std::unique_ptr<llvm::LLVMContext> m_context{};
// Execution instance
std::unique_ptr<llvm::ExecutionEngine> m_engine{};
@@ -221,7 +311,7 @@ public:
// Get LLVM context
auto& get_context()
{
return m_context;
return *m_context;
}
auto& get_engine() const
+16 -7
View File
@@ -6,6 +6,8 @@
#include <functional>
#include <string_view>
#include "util/types.hpp"
#ifdef _WIN32
std::string wchar_to_utf8(const wchar_t *src);
std::string wchar_path_to_ansi_path(const std::wstring& src);
@@ -22,17 +24,17 @@ inline void strcpy_trunc(D& dst, const T& src)
}
// Convert string to signed integer
bool try_to_int64(s64* out, const std::string& value, s64 min, s64 max);
bool try_to_int64(s64* out, std::string_view value, s64 min, s64 max);
// Convert string to unsigned integer
bool try_to_uint64(u64* out, const std::string& value, u64 min, u64 max);
bool try_to_uint64(u64* out, std::string_view value, u64 min, u64 max);
namespace fmt
{
std::string replace_all(std::string_view src, std::string_view from, std::string_view to, usz count = -1);
template <usz list_size>
std::string replace_all(std::string src, const std::pair<std::string, std::string> (&list)[list_size])
std::string replace_all(std::string src, const std::pair<std::string_view, std::string> (&list)[list_size])
{
for (usz pos = 0; pos < src.length(); ++pos)
{
@@ -41,11 +43,14 @@ namespace fmt
const usz comp_length = list[i].first.length();
if (src.length() - pos < comp_length)
{
continue;
}
if (src.substr(pos, comp_length) == list[i].first)
{
src = (pos ? src.substr(0, pos) + list[i].second : list[i].second) + src.substr(pos + comp_length);
src.erase(pos, comp_length);
src.insert(pos, list[i].second.data(), list[i].second.length());
pos += list[i].second.length() - 1;
break;
}
@@ -56,7 +61,7 @@ namespace fmt
}
template <usz list_size>
std::string replace_all(std::string src, const std::pair<std::string, std::function<std::string()>> (&list)[list_size])
std::string replace_all(std::string src, const std::pair<std::string_view, std::function<std::string()>> (&list)[list_size])
{
for (usz pos = 0; pos < src.length(); ++pos)
{
@@ -65,12 +70,16 @@ namespace fmt
const usz comp_length = list[i].first.length();
if (src.length() - pos < comp_length)
{
continue;
}
if (src.substr(pos, comp_length) == list[i].first)
{
src = (pos ? src.substr(0, pos) + list[i].second() : list[i].second()) + src.substr(pos + comp_length);
pos += list[i].second().length() - 1;
src.erase(pos, comp_length);
auto replacement = list[i].second();
src.insert(pos, replacement);
pos += replacement.length() - 1;
break;
}
}
+11 -3
View File
@@ -1582,7 +1582,7 @@ bool handle_access_violation(u32 addr, bool is_writing, x64_context* context) no
// Do not log any further access violations in this case.
if (!g_tls_access_violation_recovered)
{
vm_log.fatal("Access violation %s location 0x%x (%s) [type=u%u]", is_writing ? "writing" : "reading", addr, (is_writing && vm::check_addr(addr)) ? "read-only memory" : "unmapped memory", d_size * 8);
vm_log.fatal("Access violation %s location 0x%x (%s) [type=u%u]", is_writing ? "writing" : (cpu && cpu->id_type() == 1 && cpu->get_pc() == addr ? "executing" : "reading"), addr, (is_writing && vm::check_addr(addr)) ? "read-only memory" : "unmapped memory", d_size * 8);
}
while (Emu.IsPaused())
@@ -1826,6 +1826,14 @@ const bool s_exception_handler_set = []() -> bool
std::abort();
}
#ifdef __APPLE__
if (::sigaction(SIGBUS, &sa, NULL) == -1)
{
std::fprintf(stderr, "sigaction(SIGBUS) failed (%d).\n", errno);
std::abort();
}
#endif
sa.sa_handler = sigpipe_signaling_handler;
if (::sigaction(SIGPIPE, &sa, NULL) == -1)
{
@@ -2182,7 +2190,7 @@ thread_base::native_entry thread_base::finalize(u64 _self) noexcept
thread_base::native_entry thread_base::make_trampoline(u64(*entry)(thread_base* _base))
{
return build_function_asm<native_entry>([&](asmjit::X86Assembler& c, auto& args)
return build_function_asm<native_entry>("thread_base_trampoline", [&](asmjit::x86::Assembler& c, auto& args)
{
using namespace asmjit;
@@ -2195,7 +2203,7 @@ thread_base::native_entry thread_base::make_trampoline(u64(*entry)(thread_base*
// Call finalize, return if zero
c.mov(args[0], x86::rax);
c.call(imm_ptr<native_entry(*)(u64)>(finalize));
c.call(imm_ptr(static_cast<native_entry(*)(u64)>(&finalize)));
c.test(x86::rax, x86::rax);
c.jz(_ret);
+1 -1
View File
@@ -576,7 +576,7 @@ static usz apply_modification(std::basic_string<u32>& applied, const patch_engin
const u32 alloc_size = utils::align(static_cast<u32>(p.value.long_value) + alloc_at % 4096, 4096);
// Allocate map if needed, if allocated flags will indicate that bit 62 is set (unique identifier)
auto alloc_map = vm::reserve_map(vm::any, alloc_at & -0x10000, utils::align(alloc_size, 0x10000), vm::page_size_64k | vm::preallocated | (1ull << 62));
auto alloc_map = vm::reserve_map(vm::any, alloc_at & -0x10000, utils::align(alloc_size, 0x10000), vm::page_size_64k | (1ull << 62));
u64 flags = vm::alloc_unwritable;
+10 -4
View File
@@ -1,6 +1,7 @@
#pragma once
#include <cmath>
#include <type_traits>
template<typename T>
struct size2_base
@@ -670,17 +671,22 @@ struct area_base
{
return{ x1 / size.width, y1 / size.height, x2 / size.width, y2 / size.height };
}
constexpr area_base operator / (const T& value) const
template <typename U> requires (std::is_arithmetic_v<U>)
constexpr area_base operator / (const U& value) const
{
return{ x1 / value, y1 / value, x2 / value, y2 / value };
return area_base{static_cast<T>(x1 / value), static_cast<T>(y1 / value), static_cast<T>(x2 / value), static_cast<T>(y2 / value)};
}
constexpr area_base operator * (const size2_base<T>& size) const
{
return{ x1 * size.width, y1 * size.height, x2 * size.width, y2 * size.height };
}
constexpr area_base operator * (const f32& value) const
template <typename U> requires (std::is_arithmetic_v<U>)
constexpr area_base operator * (const U& value) const
{
return{ static_cast<T>(x1 * value), static_cast<T>(y1 * value), static_cast<T>(x2 * value), static_cast<T>(y2 * value) };
return area_base{static_cast<T>(x1 * value), static_cast<T>(y1 * value), static_cast<T>(x2 * value), static_cast<T>(y2 * value)};
}
template<typename NT>
+96
View File
@@ -0,0 +1,96 @@
#include "Utilities/simple_ringbuf.h"
simple_ringbuf::simple_ringbuf(u32 size)
{
set_buf_size(size);
}
u32 simple_ringbuf::get_free_size()
{
const u64 _rw_ptr = rw_ptr;
const u32 rd = static_cast<u32>(_rw_ptr);
const u32 wr = static_cast<u32>(_rw_ptr >> 32);
return wr >= rd ? buf_size - 1 - (wr - rd) : rd - wr - 1U;
}
u32 simple_ringbuf::get_used_size()
{
return buf_size - 1 - get_free_size();
}
void simple_ringbuf::set_buf_size(u32 size)
{
ensure(size);
this->buf_size = size + 1;
buf = std::make_unique<u8[]>(this->buf_size);
flush();
initialized = true;
}
void simple_ringbuf::flush()
{
rw_ptr.atomic_op([&](u64 &val)
{
val = static_cast<u32>(val >> 32) | (val & 0xFFFFFFFF'00000000);
});
}
u32 simple_ringbuf::push(const void *data, u32 size)
{
ensure(data != nullptr && initialized.observe());
const u32 old = static_cast<u32>(rw_ptr.load() >> 32);
const u32 to_push = std::min(size, get_free_size());
auto b_data = static_cast<const u8*>(data);
if (!to_push) return 0;
if (old + to_push > buf_size)
{
const auto first_write_sz = buf_size - old;
memcpy(&buf[old], b_data, first_write_sz);
memcpy(&buf[0], b_data + first_write_sz, to_push - first_write_sz);
}
else
{
memcpy(&buf[old], b_data, to_push);
}
rw_ptr.atomic_op([&](u64 &val)
{
val = static_cast<u64>((old + to_push) % buf_size) << 32 | static_cast<u32>(val);
});
return to_push;
}
u32 simple_ringbuf::pop(void *data, u32 size)
{
ensure(data != nullptr && initialized.observe());
const u32 old = static_cast<u32>(rw_ptr.load());
const u32 to_pop = std::min(size, get_used_size());
u8 *b_data = static_cast<u8*>(data);
if (!to_pop) return 0;
if (old + to_pop > buf_size)
{
const auto first_read_sz = buf_size - old;
memcpy(b_data, &buf[old], first_read_sz);
memcpy(b_data + first_read_sz, &buf[0], to_pop - first_read_sz);
}
else
{
memcpy(b_data, &buf[old], to_pop);
}
rw_ptr.atomic_op([&](u64 &val)
{
val = (old + to_pop) % buf_size | (val & 0xFFFFFFFF'00000000);
});
return to_pop;
}
+31
View File
@@ -0,0 +1,31 @@
#pragma once
#include "util/types.hpp"
#include "util/atomic.hpp"
// Single reader/writer simple ringbuffer.
// Counters are 32-bit.
class simple_ringbuf
{
private:
atomic_t<u64> rw_ptr = 0;
u32 buf_size = 0;
std::unique_ptr<u8[]> buf{};
atomic_t<bool> initialized = false;
public:
simple_ringbuf() {};
simple_ringbuf(u32 size);
u32 get_free_size();
u32 get_used_size();
// Thread unsafe functions.
void set_buf_size(u32 size);
void flush(); // Could be safely called from reader.
u32 push(const void *data, u32 size);
u32 pop(void *data, u32 size);
};
Binary file not shown.
+3 -1
View File
@@ -81,7 +81,9 @@ else()
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -no-pie")
endif()
elseif(APPLE)
add_compile_options(-stdlib=libc++)
if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
add_compile_options(-stdlib=libc++)
endif()
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,-image_base,0x10000 -Wl,-pagezero_size,0x10000")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,-no_pie")
elseif(WIN32)
+2 -1
View File
@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ImportGroup Label="PropertySheets" />
<PropertyGroup Label="UserMacros" />
@@ -61,6 +61,7 @@
LLVMBitWriter.lib;
LLVMCoroutines.lib;
LLVMObjCARCOpts.lib;
LLVMIntelJITEvents.lib;
</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
+2 -1
View File
@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ImportGroup Label="PropertySheets" />
<PropertyGroup Label="UserMacros" />
@@ -62,6 +62,7 @@
LLVMBitWriter.lib;
LLVMCoroutines.lib;
LLVMObjCARCOpts.lib;
LLVMIntelJITEvents.lib;
</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
+1 -1
Submodule llvm updated: 5836324d64...1c0ca194dc
+2 -2
View File
@@ -39,9 +39,9 @@
</ImportGroup>
<PropertyGroup Label="UserMacros">
<CmakeReleaseCLI>call vsdevcmd.bat -arch=amd64
cmake -G Ninja -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_TOOLS=OFF -DLLVM_INCLUDE_UTILS=OFF -DCMAKE_SYSTEM_VERSION=6.1 -DLLVM_TEMPORARILY_ALLOW_OLD_TOOLCHAIN=ON -DCMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION=$(WindowsTargetPlatformVersion) -DLLVM_USE_CRT_DEBUG=MTd -DLLVM_USE_CRT_RELEASE=MT ../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_TOOLS=OFF -DLLVM_INCLUDE_UTILS=OFF -DCMAKE_SYSTEM_VERSION=6.1 -DLLVM_TEMPORARILY_ALLOW_OLD_TOOLCHAIN=ON -DCMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION=$(WindowsTargetPlatformVersion) -DLLVM_USE_CRT_DEBUG=MTd -DLLVM_USE_CRT_RELEASE=MT -DLLVM_USE_INTEL_JITEVENTS=ON ../llvm</CmakeReleaseCLI>
<CmakeDebugCLI>call vsdevcmd.bat -arch=amd64
cmake -G Ninja -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_TOOLS=OFF -DLLVM_INCLUDE_UTILS=OFF -DCMAKE_SYSTEM_VERSION=6.1 -DLLVM_TEMPORARILY_ALLOW_OLD_TOOLCHAIN=ON -DCMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION=$(WindowsTargetPlatformVersion) -DLLVM_USE_CRT_DEBUG=MTd -DLLVM_USE_CRT_RELEASE=MT ../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_TOOLS=OFF -DLLVM_INCLUDE_UTILS=OFF -DCMAKE_SYSTEM_VERSION=6.1 -DLLVM_TEMPORARILY_ALLOW_OLD_TOOLCHAIN=ON -DCMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION=$(WindowsTargetPlatformVersion) -DLLVM_USE_CRT_DEBUG=MTd -DLLVM_USE_CRT_RELEASE=MT -DLLVM_USE_INTEL_JITEVENTS=ON ../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_TOOLS=OFF -DLLVM_INCLUDE_UTILS=OFF -DCMAKE_SYSTEM_VERSION=6.1 -DLLVM_TEMPORARILY_ALLOW_OLD_TOOLCHAIN=ON -DCMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION=$(WindowsTargetPlatformVersion) -DLLVM_USE_CRT_DEBUG=MTd -DLLVM_USE_CRT_RELEASE=MT ../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_TOOLS=OFF -DLLVM_INCLUDE_UTILS=OFF -DCMAKE_SYSTEM_VERSION=6.1 -DLLVM_TEMPORARILY_ALLOW_OLD_TOOLCHAIN=ON -DCMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION=$(WindowsTargetPlatformVersion) -DLLVM_USE_CRT_DEBUG=MTd -DLLVM_USE_CRT_RELEASE=MT -DLLVM_USE_INTEL_JITEVENTS=ON ../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_TOOLS=OFF -DLLVM_INCLUDE_UTILS=OFF -DCMAKE_SYSTEM_VERSION=6.1 -DLLVM_TEMPORARILY_ALLOW_OLD_TOOLCHAIN=ON -DCMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION=$(WindowsTargetPlatformVersion) -DLLVM_USE_CRT_DEBUG=MTd -DLLVM_USE_CRT_RELEASE=MT ../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_TOOLS=OFF -DLLVM_INCLUDE_UTILS=OFF -DCMAKE_SYSTEM_VERSION=6.1 -DLLVM_TEMPORARILY_ALLOW_OLD_TOOLCHAIN=ON -DCMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION=$(WindowsTargetPlatformVersion) -DLLVM_USE_CRT_DEBUG=MTd -DLLVM_USE_CRT_RELEASE=MT -DLLVM_USE_INTEL_JITEVENTS=ON ../llvm</CmakeDebugCLI>
<CmakeCleanCLI>echo Cleaning..
for /F "delims= eol=|" %%f in ('
dir /b ^| findstr /V "[^.]*\build[^.]*\.vcxproj"') do (
+16 -8
View File
@@ -17,8 +17,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "rpcs3.emu", "rpcs3.emu", "{
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "XAudio", "rpcs3\XAudio.vcxproj", "{78CB2F39-B809-4A06-8329-8C0A19119D3D}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "OpenAL", "rpcs3\OpenAL.vcxproj", "{30A05C4D-F5FD-421C-A864-17A64BDEAA75}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "pnglibconf", "3rdparty\libpng\pnglibconf.vcxproj", "{EB33566E-DA7F-4D28-9077-88C0B7C77E35}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libpng", "3rdparty\libpng\libpng.vcxproj", "{D6973076-9317-4EF2-A0B8-B7A18AC0713E}"
@@ -47,10 +45,11 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "rpcs3", "rpcs3\rpcs3.vcxpro
{C4A10229-4712-4BD2-B63E-50D93C67A038} = {C4A10229-4712-4BD2-B63E-50D93C67A038}
{78CB2F39-B809-4A06-8329-8C0A19119D3D} = {78CB2F39-B809-4A06-8329-8C0A19119D3D}
{3384223A-6D97-4799-9862-359F85312892} = {3384223A-6D97-4799-9862-359F85312892}
{30A05C4D-F5FD-421C-A864-17A64BDEAA75} = {30A05C4D-F5FD-421C-A864-17A64BDEAA75}
{60F89955-91C6-3A36-8000-13C592FEC2DF} = {60F89955-91C6-3A36-8000-13C592FEC2DF}
{3EE5F075-B546-42C4-B6A8-E3CCEF38B78D} = {3EE5F075-B546-42C4-B6A8-E3CCEF38B78D}
{D6973076-9317-4EF2-A0B8-B7A18AC0713E} = {D6973076-9317-4EF2-A0B8-B7A18AC0713E}
{9610627D-20FE-4B07-8CE3-9FF68A5F1EC2} = {9610627D-20FE-4B07-8CE3-9FF68A5F1EC2}
{FDA7B080-03B0-48C8-B24F-88118981422A} = {FDA7B080-03B0-48C8-B24F-88118981422A}
{DA6F56B4-06A4-441D-AD70-AC5A7D51FADB} = {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}
{FDC361C5-7734-493B-8CFB-037308B35122} = {FDC361C5-7734-493B-8CFB-037308B35122}
{8F85B6CC-250F-4ACA-A617-E820A74E3E3C} = {8F85B6CC-250F-4ACA-A617-E820A74E3E3C}
@@ -79,6 +78,10 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "3rdParty", "3rdParty", "{6C
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "llvm_build_clang_cl", "llvm_build\llvm_build_clang_cl.vcxproj", "{A37E4273-85DB-4217-B775-CE971B87D9DF}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Cubeb", "rpcs3\Cubeb.vcxproj", "{9610627D-20FE-4B07-8CE3-9FF68A5F1EC2}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libcubeb", "3rdparty\cubeb\libcubeb.vcxproj", "{FDA7B080-03B0-48C8-B24F-88118981422A}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64
@@ -103,10 +106,6 @@ Global
{78CB2F39-B809-4A06-8329-8C0A19119D3D}.Debug|x64.Build.0 = Debug|x64
{78CB2F39-B809-4A06-8329-8C0A19119D3D}.Release|x64.ActiveCfg = Release|x64
{78CB2F39-B809-4A06-8329-8C0A19119D3D}.Release|x64.Build.0 = Release|x64
{30A05C4D-F5FD-421C-A864-17A64BDEAA75}.Debug|x64.ActiveCfg = Debug|x64
{30A05C4D-F5FD-421C-A864-17A64BDEAA75}.Debug|x64.Build.0 = Debug|x64
{30A05C4D-F5FD-421C-A864-17A64BDEAA75}.Release|x64.ActiveCfg = Release|x64
{30A05C4D-F5FD-421C-A864-17A64BDEAA75}.Release|x64.Build.0 = Release|x64
{EB33566E-DA7F-4D28-9077-88C0B7C77E35}.Debug|x64.ActiveCfg = Release|x64
{EB33566E-DA7F-4D28-9077-88C0B7C77E35}.Debug|x64.Build.0 = Release|x64
{EB33566E-DA7F-4D28-9077-88C0B7C77E35}.Release|x64.ActiveCfg = Release|x64
@@ -161,6 +160,14 @@ Global
{4CBD3DDD-5555-49A4-A44D-DD3D8CB516A1}.Release|x64.ActiveCfg = Release|x64
{A37E4273-85DB-4217-B775-CE971B87D9DF}.Debug|x64.ActiveCfg = Debug|x64
{A37E4273-85DB-4217-B775-CE971B87D9DF}.Release|x64.ActiveCfg = Release|x64
{9610627D-20FE-4B07-8CE3-9FF68A5F1EC2}.Debug|x64.ActiveCfg = Debug|x64
{9610627D-20FE-4B07-8CE3-9FF68A5F1EC2}.Debug|x64.Build.0 = Debug|x64
{9610627D-20FE-4B07-8CE3-9FF68A5F1EC2}.Release|x64.ActiveCfg = Release|x64
{9610627D-20FE-4B07-8CE3-9FF68A5F1EC2}.Release|x64.Build.0 = Release|x64
{FDA7B080-03B0-48C8-B24F-88118981422A}.Debug|x64.ActiveCfg = Debug|x64
{FDA7B080-03B0-48C8-B24F-88118981422A}.Debug|x64.Build.0 = Debug|x64
{FDA7B080-03B0-48C8-B24F-88118981422A}.Release|x64.ActiveCfg = Release|x64
{FDA7B080-03B0-48C8-B24F-88118981422A}.Release|x64.Build.0 = Release|x64
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -171,7 +178,6 @@ Global
{8BC303AB-25BE-4276-8E57-73F171B2D672} = {B0AC29FD-7B01-4B5E-9C8D-0A081E4C5668}
{3384223A-6D97-4799-9862-359F85312892} = {10FBF193-D532-4CCF-B875-4C7091A7F6C2}
{78CB2F39-B809-4A06-8329-8C0A19119D3D} = {10FBF193-D532-4CCF-B875-4C7091A7F6C2}
{30A05C4D-F5FD-421C-A864-17A64BDEAA75} = {10FBF193-D532-4CCF-B875-4C7091A7F6C2}
{EB33566E-DA7F-4D28-9077-88C0B7C77E35} = {6C3B64A0-8F8A-4DC4-8C0B-D71EBEED7FA8}
{D6973076-9317-4EF2-A0B8-B7A18AC0713E} = {6C3B64A0-8F8A-4DC4-8C0B-D71EBEED7FA8}
{60F89955-91C6-3A36-8000-13C592FEC2DF} = {6C3B64A0-8F8A-4DC4-8C0B-D71EBEED7FA8}
@@ -186,6 +192,8 @@ Global
{DA6F56B4-06A4-441D-AD70-AC5A7D51FADB} = {6C3B64A0-8F8A-4DC4-8C0B-D71EBEED7FA8}
{4CBD3DDD-5555-49A4-A44D-DD3D8CB516A1} = {B0AC29FD-7B01-4B5E-9C8D-0A081E4C5668}
{A37E4273-85DB-4217-B775-CE971B87D9DF} = {B0AC29FD-7B01-4B5E-9C8D-0A081E4C5668}
{9610627D-20FE-4B07-8CE3-9FF68A5F1EC2} = {10FBF193-D532-4CCF-B875-4C7091A7F6C2}
{FDA7B080-03B0-48C8-B24F-88118981422A} = {6C3B64A0-8F8A-4DC4-8C0B-D71EBEED7FA8}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {06CC7920-E085-4B81-9582-8DE8AAD42510}
+12 -8
View File
@@ -3,6 +3,9 @@ if(USE_PRECOMPILED_HEADERS AND NOT COMMAND target_precompile_headers)
include(cotire)
endif()
# Define GNU standard installation directories
include(GNUInstallDirs)
# Generate git-version.h at build time.
include(${CMAKE_CURRENT_SOURCE_DIR}/git-version.cmake)
@@ -23,6 +26,7 @@ elseif(NOT MSVC AND NOT CMAKE_CXX_FLAGS MATCHES "LIBICONV_PLUG")
endif()
if(UNIX AND NOT APPLE)
add_definitions(-DDATADIR="${CMAKE_INSTALL_FULL_DATADIR}/rpcs3")
# Optionally enable X11 for window management
find_package(X11)
if(X11_FOUND)
@@ -198,21 +202,21 @@ endif()
# Unix installation
if(UNIX AND NOT APPLE)
# Install the binary
install(TARGETS rpcs3 RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}/bin)
install(TARGETS rpcs3 RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
# Install the application icon and menu item
install(FILES rpcs3.svg
DESTINATION ${CMAKE_INSTALL_PREFIX}/share/icons/hicolor/scalable/apps)
DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/icons/hicolor/scalable/apps)
install(FILES rpcs3.png
DESTINATION ${CMAKE_INSTALL_PREFIX}/share/icons/hicolor/48x48/apps)
DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/icons/hicolor/48x48/apps)
install(FILES rpcs3.desktop
DESTINATION ${CMAKE_INSTALL_PREFIX}/share/applications)
DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/applications)
install(FILES rpcs3.metainfo.xml
DESTINATION ${CMAKE_INSTALL_PREFIX}/share/metainfo)
DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/metainfo)
# Install other files
install(DIRECTORY ../bin/Icons
DESTINATION ${CMAKE_INSTALL_PREFIX}/share/rpcs3)
DESTINATION ${CMAKE_INSTALL_DATADIR}/rpcs3)
install(DIRECTORY ../bin/GuiConfigs
DESTINATION ${CMAKE_INSTALL_PREFIX}/share/rpcs3)
DESTINATION ${CMAKE_INSTALL_DATADIR}/rpcs3)
install(DIRECTORY ../bin/git
DESTINATION ${CMAKE_INSTALL_PREFIX}/share/rpcs3)
DESTINATION ${CMAKE_INSTALL_DATADIR}/rpcs3)
endif()
+48 -58
View File
@@ -549,6 +549,11 @@ int check_data(unsigned char *key, EDAT_HEADER *edat, NPD_HEADER *npd, const fs:
bool validate_dev_klic(const u8* klicensee, NPD_HEADER *npd)
{
if ((npd->license & 0x3) != 0x3)
{
return true;
}
unsigned char dev[0x60] = { 0 };
// Build the dev buffer (first 0x60 bytes of NPD header in big-endian).
@@ -566,12 +571,6 @@ bool validate_dev_klic(const u8* klicensee, NPD_HEADER *npd)
u128 klic;
std::memcpy(&klic, klicensee, sizeof(klic));
if (!klic)
{
// Allow empty dev hash.
return true;
}
// Generate klicensee xor key.
u128 key = klic ^ std::bit_cast<u128>(NP_OMAC_KEY_2);
@@ -579,13 +578,19 @@ 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, bool verbose)
bool validate_npd_hashes(const char* 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;
@@ -704,14 +709,10 @@ bool extract_all_data(const fs::file* input, const fs::file* output, const char*
// 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, verbose))
if (!validate_npd_hashes(real_file_name, devklic, &NPD, &EDAT, verbose))
{
// Ignore header validation in DEBUG data.
if ((EDAT.flags & EDAT_DEBUG_DATA_FLAG) != EDAT_DEBUG_DATA_FLAG)
{
edat_log.error("NPD hash validation failed!");
return true;
}
edat_log.error("NPD hash validation failed!");
return true;
}
// Select EDAT key.
@@ -784,7 +785,7 @@ u128 GetEdatRifKeyFromRapFile(const fs::file& rap_file)
return rifkey;
}
bool VerifyEDATHeaderWithKLicense(const fs::file& input, const std::string& input_file_name, const u8* custom_klic, std::string* contentID)
bool VerifyEDATHeaderWithKLicense(const fs::file& input, const std::string& input_file_name, const u8* custom_klic, std::string* contentID, u32* license)
{
// Setup NPD and EDAT/SDAT structs.
NPD_HEADER NPD;
@@ -808,17 +809,17 @@ bool VerifyEDATHeaderWithKLicense(const fs::file& input, const std::string& inpu
// Perform header validation (EDAT only).
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, false))
if (!validate_npd_hashes(real_file_name, custom_klic, &NPD, &EDAT, false))
{
// Ignore header validation in DEBUG data.
if ((EDAT.flags & EDAT_DEBUG_DATA_FLAG) != EDAT_DEBUG_DATA_FLAG)
{
edat_log.error("NPD hash validation failed!");
return false;
}
edat_log.error("NPD hash validation failed!");
return false;
}
*contentID = std::string(reinterpret_cast<const char*>(NPD.content_id));
std::string_view sv{NPD.content_id, std::size(NPD.content_id)};
sv = sv.substr(0, sv.find_first_of('\0'));
if (contentID) *contentID = std::string(sv);
if (license) *license = (NPD.license & 3);
return true;
}
@@ -910,33 +911,13 @@ bool EDATADecrypter::ReadHeader()
else
{
// verify key
if (!validate_dev_klic(reinterpret_cast<uchar*>(&dev_key), &npdHeader))
if (!validate_dev_klic(reinterpret_cast<uchar*>(&dec_key), &npdHeader))
{
edat_log.error("Failed validating klic");
return false;
}
// Select EDAT key.
if ((npdHeader.license & 0x3) == 0x3) // Type 3: Use supplied devklic.
dec_key = std::move(dev_key);
else if ((npdHeader.license & 0x2) == 0x2) // Type 2: Use key from RAP file (RIF key).
{
dec_key = std::move(rif_key);
if (!dec_key)
{
edat_log.warning("Empty Dec key for local activation!");
}
}
else if ((npdHeader.license & 0x1) == 0x1) // Type 1: Use network activation.
{
dec_key = std::move(rif_key);
if (!dec_key)
{
edat_log.warning("Empty Dec key for network activation!");
}
}
// Use provided dec_key
}
edata_file.seek(0);
@@ -952,29 +933,37 @@ bool EDATADecrypter::ReadHeader()
file_size = edatHeader.file_size;
total_blocks = utils::aligned_div(edatHeader.file_size, edatHeader.block_size);
// Try decrypting the first block instead
u8 data_sample[1];
if (file_size && !ReadData(0, data_sample, 1))
{
return false;
}
return true;
}
u64 EDATADecrypter::ReadData(u64 pos, u8* data, u64 size)
{
if (pos > edatHeader.file_size)
return 0;
size = std::min<u64>(size, pos > edatHeader.file_size ? 0 : edatHeader.file_size - pos);
// now we need to offset things to account for the actual 'range' requested
const u64 startOffset = pos % edatHeader.block_size;
const u32 num_blocks = static_cast<u32>(utils::aligned_div(startOffset + size, edatHeader.block_size));
const u64 bufSize = num_blocks*edatHeader.block_size;
if (data_buf_size < (bufSize))
if (!size)
{
data_buf.reset(new u8[bufSize]);
data_buf_size = bufSize;
return 0;
}
// find and decrypt block range covering pos + size
const u32 starting_block = static_cast<u32>(pos / edatHeader.block_size);
const u32 ending_block = std::min(starting_block + num_blocks, total_blocks);
// Now we need to offset things to account for the actual 'range' requested
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)
{
edata_file.seek(0);
@@ -984,6 +973,7 @@ u64 EDATADecrypter::ReadData(u64 pos, u8* data, u64 size)
edat_log.error("Error Decrypting data");
return 0;
}
writeOffset += res;
}
+21 -17
View File
@@ -16,9 +16,21 @@ constexpr u32 EDAT_DEBUG_DATA_FLAG = 0x80000000;
struct loaded_npdrm_keys
{
atomic_t<u128> devKlic{};
atomic_t<u128> rifKey{};
atomic_t<u128> dec_keys[16]{};
atomic_t<u64> dec_keys_pos = 0;
atomic_t<u32> npdrm_fds{0};
void install_decryption_key(u128 key)
{
dec_keys_pos.atomic_op([&](u64& pos) { dec_keys[pos++ % std::size(dec_keys)] = key; });
}
// TODO: Check if correct for ELF files usage
u128 last_key() const
{
const usz pos = dec_keys_pos;
return pos ? dec_keys[(pos - 1) % std::size(dec_keys)].load() : u128{};
}
};
struct NPD_HEADER
@@ -45,14 +57,14 @@ 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 bool VerifyEDATHeaderWithKLicense(const fs::file& input, const std::string& input_file_name, const u8* custom_klic, std::string* contentID);
extern bool VerifyEDATHeaderWithKLicense(const fs::file& input, const std::string& input_file_name, const u8* custom_klic, std::string* contentID = nullptr, u32* license = nullptr);
u128 GetEdatRifKeyFromRapFile(const fs::file& rap_file);
struct EDATADecrypter final : fs::file_base
{
// file stream
const fs::file edata_file;
fs::file edata_file;
u64 file_size{0};
u32 total_blocks{0};
u64 pos{0};
@@ -61,25 +73,17 @@ struct EDATADecrypter final : fs::file_base
EDAT_HEADER edatHeader{};
// Internal data buffers.
std::unique_ptr<u8[]> data_buf{};
u64 data_buf_size{0};
std::vector<u8> data_buf{};
u128 dec_key{};
// edat usage
u128 rif_key{};
u128 dev_key{};
public:
// SdataByFd usage
EDATADecrypter(fs::file&& input)
: edata_file(std::move(input)) {}
// Edat usage
EDATADecrypter(fs::file&& input, const u128& dev_key, const u128& rif_key)
EDATADecrypter(fs::file&& input, u128 dec_key = {})
: edata_file(std::move(input))
, rif_key(rif_key)
, dev_key(dev_key) {}
, dec_key(dec_key)
{
}
~EDATADecrypter() override {}
// false if invalid
bool ReadHeader();
u64 ReadData(u64 pos, u8* data, u64 size);
+22 -1
View File
@@ -1343,6 +1343,27 @@ static bool IsSelfElf32(const fs::file& f)
return (elf_class[4] == 1);
}
static bool IsDebugSelf(const fs::file& f)
{
if (f.size() < 0x18)
{
return false;
}
// Get the key version.
f.seek(0x08);
const u16 key_version = f.read<le_t<u16>>();
// Check for DEBUG version.
if (key_version == 0x80 || key_version == 0xc0)
{
return true;
}
return false;
}
static bool CheckDebugSelf(fs::file& s)
{
if (s.size() < 0x18)
@@ -1442,7 +1463,7 @@ bool verify_npdrm_self_headers(const fs::file& self, u8* klic_key)
self.seek(0);
if (self.size() >= 4 && self.read<u32>() == "SCE\0"_u32)
if (self.size() >= 4 && self.read<u32>() == "SCE\0"_u32 && !IsDebugSelf(self))
{
// Check the ELF file class (32 or 64 bit).
const bool isElf32 = IsSelfElf32(self);
+11 -20
View File
@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|x64">
@@ -11,9 +11,8 @@
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{30A05C4D-F5FD-421C-A864-17A64BDEAA75}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>OpenAL</RootNamespace>
<ProjectGuid>{9610627D-20FE-4B07-8CE3-9FF68A5F1EC2}</ProjectGuid>
<RootNamespace>Cubeb</RootNamespace>
</PropertyGroup>
<Import Project="$(SolutionDir)\buildfiles\msvc\common_default.props" />
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
@@ -37,36 +36,28 @@
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(SolutionDir)\buildfiles\msvc\rpcs3_debug.props" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug - LLVM|x64'" Label="PropertySheets">
<Import Project="$(SolutionDir)\buildfiles\msvc\rpcs3_debug.props" />
<Import Project="$(SolutionDir)\buildfiles\msvc\rpcs3_llvm.props" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(SolutionDir)\buildfiles\msvc\rpcs3_release.props" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release - LLVM|x64'" Label="PropertySheets">
<Import Project="$(SolutionDir)\buildfiles\msvc\rpcs3_release.props" />
<Import Project="$(SolutionDir)\buildfiles\msvc\rpcs3_llvm.props" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<ItemDefinitionGroup>
<ClCompile>
<AdditionalIncludeDirectories>.\3rdparty\OpenAL\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>..\3rdparty\cubeb\cubeb\include\;..\3rdparty\cubeb\extra\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<Optimization Condition="'$(Configuration)|$(Platform)'=='Release|x64'">MaxSpeed</Optimization>
</ClCompile>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="Emu\Audio\AL\OpenALBackend.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="Emu\Audio\AL\OpenALBackend.h" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="emucore.vcxproj">
<Project>{c4a10229-4712-4bd2-b63e-50d93c67a038}</Project>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<ClInclude Include="Emu\Audio\Cubeb\CubebBackend.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="Emu\Audio\Cubeb\CubebBackend.cpp" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
</Project>
@@ -1,19 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Source Files">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<UniqueIdentifier>{F573EFFC-2BB8-43DF-AEFA-4E9EA31A817F}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
</ItemGroup>
<ItemGroup>
<ClInclude Include="Emu\Audio\AL\OpenALBackend.h">
<Filter>Source Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="Emu\Audio\AL\OpenALBackend.cpp">
<ClCompile Include="Emu\Audio\Cubeb\CubebBackend.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
</Project>
<ItemGroup>
<ClInclude Include="Emu\Audio\Cubeb\CubebBackend.h">
<Filter>Source Files</Filter>
</ClInclude>
</ItemGroup>
</Project>
-212
View File
@@ -1,212 +0,0 @@
#include "stdafx.h"
#include "OpenALBackend.h"
#ifdef _MSC_VER
#pragma comment(lib, "OpenAL32.lib")
#endif
LOG_CHANNEL(OpenAL);
#define checkForAlError(sit) do { ALenum g_last_al_error = alGetError(); if(g_last_al_error != AL_NO_ERROR) OpenAL.error("%s: OpenAL error 0x%04x", sit, g_last_al_error); } while(0)
#define checkForAlcError(sit) do { ALCenum g_last_alc_error = alcGetError(m_device); if(g_last_alc_error != ALC_NO_ERROR) { OpenAL.error("%s: OpenALC error 0x%04x", sit, g_last_alc_error); return; }} while(0)
OpenALBackend::OpenALBackend()
: AudioBackend()
{
ALCint attribs[] = {ALC_FREQUENCY, DEFAULT_AUDIO_SAMPLING_RATE, 0, 0};
ALCdevice* m_device = alcOpenDevice(nullptr);
checkForAlcError("alcOpenDevice");
ALCcontext* m_context = alcCreateContext(m_device, attribs);
checkForAlcError("alcCreateContext");
alcMakeContextCurrent(m_context);
checkForAlcError("alcMakeContextCurrent");
switch (m_channels)
{
case 2:
m_format = (m_sample_size == 2) ? AL_FORMAT_STEREO16 : AL_FORMAT_STEREO_FLOAT32;
break;
case 6:
m_format = (m_sample_size == 2) ? AL_FORMAT_51CHN16 : AL_FORMAT_51CHN32;
break;
default:
m_format = (m_sample_size == 2) ? AL_FORMAT_71CHN16 : AL_FORMAT_71CHN32;
break;
}
}
OpenALBackend::~OpenALBackend()
{
if (alIsSource(m_source))
{
Close();
}
if (ALCcontext* m_context = alcGetCurrentContext())
{
ALCdevice* m_device = alcGetContextsDevice(m_context);
alcMakeContextCurrent(nullptr);
alcDestroyContext(m_context);
alcCloseDevice(m_device);
}
}
void OpenALBackend::Play()
{
AUDIT(alIsSource(m_source));
ALint state;
alGetSourcei(m_source, AL_SOURCE_STATE, &state);
checkForAlError("Play->alGetSourcei(AL_SOURCE_STATE)");
if (state != AL_PLAYING)
{
alSourcePlay(m_source);
checkForAlError("Play->alSourcePlay");
}
}
void OpenALBackend::Pause()
{
AUDIT(alIsSource(m_source));
alSourcePause(m_source);
checkForAlError("Pause->alSourcePause");
}
bool OpenALBackend::IsPlaying()
{
AUDIT(alIsSource(m_source));
ALint state;
alGetSourcei(m_source, AL_SOURCE_STATE, &state);
checkForAlError("IsPlaying->alGetSourcei(AL_SOURCE_STATE)");
return state == AL_PLAYING;
}
void OpenALBackend::Open(u32 num_buffers)
{
AUDIT(!alIsSource(m_source));
// Initialize Source
alGenSources(1, &m_source);
checkForAlError("Open->alGenSources");
alSourcei(m_source, AL_LOOPING, AL_FALSE);
checkForAlError("Open->alSourcei");
// Initialize Buffers
alGenBuffers(num_buffers, m_buffers);
checkForAlError("Open->alGenBuffers");
m_num_buffers = num_buffers;
m_num_unqueued = num_buffers;
}
void OpenALBackend::Close()
{
if (alIsSource(m_source))
{
// Stop & Kill Source
Pause();
alDeleteSources(1, &m_source);
// Free Buffers
alDeleteBuffers(m_num_buffers, m_buffers);
checkForAlError("alDeleteBuffers");
}
}
bool OpenALBackend::AddData(const void* src, u32 num_samples)
{
AUDIT(alIsSource(m_source));
// Unqueue processed buffers, if any
unqueue_processed();
// Fail if there are no free buffers remaining
if (m_num_unqueued == 0)
{
OpenAL.warning("No unqueued buffers remaining");
return false;
}
// Copy data to the next available buffer
alBufferData(m_buffers[m_next_buffer], m_format, src, num_samples * m_sample_size, m_sampling_rate);
checkForAlError("AddData->alBufferData");
// Enqueue buffer
alSourceQueueBuffers(m_source, 1, &m_buffers[m_next_buffer]);
checkForAlError("AddData->alSourceQueueBuffers");
m_num_unqueued--;
m_next_buffer = (m_next_buffer + 1) % m_num_buffers;
return true;
}
void OpenALBackend::Flush()
{
AUDIT(alIsSource(m_source));
// Stop source first
alSourceStop(m_source);
checkForAlError("Flush->alSourceStop");
// Unqueue processed buffers (should now be all of them)
unqueue_processed();
}
void OpenALBackend::unqueue_processed()
{
AUDIT(alIsSource(m_source));
// Get number of buffers
ALint num_processed;
alGetSourcei(m_source, AL_BUFFERS_PROCESSED, &num_processed);
checkForAlError("Flush->alGetSourcei(AL_BUFFERS_PROCESSED)");
if (num_processed > 0)
{
// Unqueue all buffers
ALuint x[MAX_AUDIO_BUFFERS];
alSourceUnqueueBuffers(m_source, num_processed, x);
checkForAlError("Flush->alSourceUnqueueBuffers");
m_num_unqueued += num_processed;
}
}
u64 OpenALBackend::GetNumEnqueuedSamples()
{
AUDIT(alIsSource(m_source));
// Get number of buffers queued
ALint num_queued;
alGetSourcei(m_source, AL_BUFFERS_QUEUED, &num_queued);
checkForAlError("GetNumEnqueuedSamples->alGetSourcei(AL_BUFFERS_QUEUED)");
AUDIT(static_cast<u32>(num_queued) <= m_num_buffers - m_num_unqueued);
// Get sample position
ALint sample_pos;
alGetSourcei(m_source, AL_SAMPLE_OFFSET, &sample_pos);
checkForAlError("GetNumEnqueuedSamples->alGetSourcei(AL_SAMPLE_OFFSET)");
// Return
return (num_queued * AUDIO_BUFFER_SAMPLES) + (sample_pos % AUDIO_BUFFER_SAMPLES);
}
f32 OpenALBackend::SetFrequencyRatio(f32 new_ratio)
{
new_ratio = std::clamp(new_ratio, 0.5f, 2.0f);
alSourcef(m_source, AL_PITCH, new_ratio);
checkForAlError("SetFrequencyRatio->alSourcei(AL_PITCH)");
return new_ratio;
}
-40
View File
@@ -1,40 +0,0 @@
#pragma once
#include "Emu/Audio/AudioBackend.h"
#include "3rdparty/OpenAL/include/alext.h"
class OpenALBackend : public AudioBackend
{
private:
ALint m_format{};
ALuint m_source{};
ALuint m_buffers[MAX_AUDIO_BUFFERS]{};
ALsizei m_num_buffers{};
u32 m_next_buffer = 0;
u32 m_num_unqueued = 0;
void unqueue_processed();
public:
OpenALBackend();
~OpenALBackend() override;
const char* GetName() const override { return "OpenAL"; }
static const u32 capabilities = PLAY_PAUSE_FLUSH | IS_PLAYING | GET_NUM_ENQUEUED_SAMPLES | SET_FREQUENCY_RATIO;
u32 GetCapabilities() const override { return capabilities; }
void Open(u32 num_buffers) override;
void Close() override;
void Play() override;
void Pause() override;
bool IsPlaying() override;
bool AddData(const void* src, u32 num_samples) override;
void Flush() override;
u64 GetNumEnqueuedSamples() override;
f32 SetFrequencyRatio(f32 new_ratio) override;
};
-166
View File
@@ -1,166 +0,0 @@
#ifndef HAVE_ALSA
#error "ALSA support disabled but still being built."
#endif
#include "stdafx.h"
#include "Emu/system_config.h"
#include "ALSABackend.h"
LOG_CHANNEL(ALSA);
static void error(int err, const char* reason)
{
ALSA.error("ALSA: %s failed: %s\n", reason, snd_strerror(err));
}
static bool check(int err, const char* reason)
{
if (err < 0)
{
error(err, reason);
return false;
}
return true;
}
ALSABackend::ALSABackend()
: AudioBackend()
{
}
ALSABackend::~ALSABackend()
{
if (tls_sw_params || tls_hw_params || tls_handle)
{
Close();
}
}
void ALSABackend::Open(u32 num_buffers)
{
if (!check(snd_pcm_open(&tls_handle, "default", SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK), "snd_pcm_open"))
return;
if (!check(snd_pcm_hw_params_malloc(&tls_hw_params), "snd_pcm_hw_params_malloc"))
return;
if (!check(snd_pcm_hw_params_any(tls_handle, tls_hw_params), "snd_pcm_hw_params_any"))
return;
if (!check(snd_pcm_hw_params_set_access(tls_handle, tls_hw_params, SND_PCM_ACCESS_RW_INTERLEAVED), "snd_pcm_hw_params_set_access"))
return;
if (!check(snd_pcm_hw_params_set_format(tls_handle, tls_hw_params, m_convert_to_u16 ? SND_PCM_FORMAT_S16_LE : SND_PCM_FORMAT_FLOAT_LE), "snd_pcm_hw_params_set_format"))
return;
uint rate = m_sampling_rate;
if (!check(snd_pcm_hw_params_set_rate_near(tls_handle, tls_hw_params, &rate, nullptr), "snd_pcm_hw_params_set_rate_near"))
return;
if (!check(snd_pcm_hw_params_set_channels(tls_handle, tls_hw_params, m_channels), "snd_pcm_hw_params_set_channels"))
return;
//uint period = 5333;
//if (!check(snd_pcm_hw_params_set_period_time_near(tls_handle, tls_hw_params, &period, nullptr), "snd_pcm_hw_params_set_period_time_near"))
// return;
//if (!check(snd_pcm_hw_params_set_periods(tls_handle, tls_hw_params, 4, 0), "snd_pcm_hw_params_set_periods"))
// return;
snd_pcm_uframes_t bufsize_frames = num_buffers * AUDIO_BUFFER_SAMPLES;
snd_pcm_uframes_t period_frames = AUDIO_BUFFER_SAMPLES;
if (!check(snd_pcm_hw_params_set_buffer_size_near(tls_handle, tls_hw_params, &bufsize_frames), "snd_pcm_hw_params_set_buffer_size_near"))
return;
if (!check(snd_pcm_hw_params_set_period_size_near(tls_handle, tls_hw_params, &period_frames, 0), "snd_pcm_hw_params_set_period_size"))
return;
if (!check(snd_pcm_hw_params(tls_handle, tls_hw_params), "snd_pcm_hw_params"))
return;
if (!check(snd_pcm_hw_params_get_buffer_size(tls_hw_params, &bufsize_frames), "snd_pcm_hw_params_get_buffer_size"))
return;
if (!check(snd_pcm_hw_params_get_period_size(tls_hw_params, &period_frames, nullptr), "snd_pcm_hw_params_get_period_size"))
return;
if (!check(snd_pcm_sw_params_malloc(&tls_sw_params), "snd_pcm_sw_params_malloc"))
return;
if (!check(snd_pcm_sw_params_current(tls_handle, tls_sw_params), "snd_pcm_sw_params_current"))
return;
period_frames *= m_start_threshold;
if (!check(snd_pcm_sw_params_set_start_threshold(tls_handle, tls_sw_params, period_frames + 1), "snd_pcm_sw_params_set_start_threshold"))
return;
if (!check(snd_pcm_sw_params_set_stop_threshold(tls_handle, tls_sw_params, bufsize_frames), "snd_pcm_sw_params_set_stop_threshold"))
return;
if (!check(snd_pcm_sw_params(tls_handle, tls_sw_params), "snd_pcm_sw_params"))
return;
if (!check(snd_pcm_prepare(tls_handle), "snd_pcm_prepare"))
return;
ALSA.notice("bufsize_frames=%u, period_frames=%u", bufsize_frames, period_frames);
}
void ALSABackend::Close()
{
if (tls_sw_params)
{
snd_pcm_sw_params_free(tls_sw_params);
tls_sw_params = nullptr;
}
if (tls_hw_params)
{
snd_pcm_hw_params_free(tls_hw_params);
tls_hw_params = nullptr;
}
if (tls_handle)
{
snd_pcm_close(tls_handle);
tls_handle = nullptr;
}
}
bool ALSABackend::AddData(const void* src, u32 num_samples)
{
u32 num_frames = num_samples / m_channels;
int res = snd_pcm_writei(tls_handle, src, num_frames);
if (res == -EAGAIN)
{
ALSA.warning("EAGAIN");
return false;
}
if (res < 0)
{
res = snd_pcm_recover(tls_handle, res, 0);
if (res < 0)
{
ALSA.warning("Failed to recover (%d)", res);
return false;
}
return false;
}
if (res + 0u != num_frames)
{
ALSA.warning("Error (%d)", res);
return false;
}
return true;
}
-33
View File
@@ -1,33 +0,0 @@
#pragma once
#ifndef HAVE_ALSA
#error "ALSA support disabled but still being built."
#endif
#include "Emu/Audio/AudioBackend.h"
#include <alsa/asoundlib.h>
class ALSABackend : public AudioBackend
{
snd_pcm_t* tls_handle{};
snd_pcm_hw_params_t* tls_hw_params{};
snd_pcm_sw_params_t* tls_sw_params{};
public:
ALSABackend();
virtual ~ALSABackend() override;
ALSABackend(const ALSABackend&) = delete;
ALSABackend& operator=(const ALSABackend&) = delete;
virtual const char* GetName() const override { return "ALSA"; }
static const u32 capabilities = 0;
virtual u32 GetCapabilities() const override { return capabilities; }
virtual void Open(u32) override;
virtual void Close() override;
virtual bool AddData(const void* src, u32 num_samples) override;
};
+6 -62
View File
@@ -2,67 +2,29 @@
#include "AudioBackend.h"
#include "Emu/system_config.h"
AudioBackend::AudioBackend()
{
m_convert_to_u16 = static_cast<bool>(g_cfg.audio.convert_to_u16);
m_sample_size = m_convert_to_u16 ? sizeof(u16) : sizeof(float);
m_start_threshold = g_cfg.audio.start_threshold;
const u32 sampling_period_multiplier_u32 = g_cfg.audio.sampling_period_multiplier;
if (sampling_period_multiplier_u32 == 100)
{
m_sampling_rate = DEFAULT_AUDIO_SAMPLING_RATE;
}
else
{
const f32 sampling_period_multiplier = sampling_period_multiplier_u32 / 100.0f;
const f32 sampling_rate_multiplier = 1.0f / sampling_period_multiplier;
m_sampling_rate = static_cast<u32>(f32{ DEFAULT_AUDIO_SAMPLING_RATE } *sampling_rate_multiplier);
}
const audio_downmix downmix = g_cfg.audio.audio_channel_downmix.get();
switch (downmix)
{
case audio_downmix::no_downmix:
m_channels = 8;
break;
case audio_downmix::downmix_to_stereo:
m_channels = 2;
break;
case audio_downmix::downmix_to_5_1:
m_channels = 6;
break;
case audio_downmix::use_application_settings:
m_channels = 2; // TODO
break;
default:
fmt::throw_exception("Unknown audio channel mode %s (%d)", downmix, static_cast<int>(downmix));
}
}
AudioBackend::AudioBackend() {}
/*
* Helper methods
*/
u32 AudioBackend::get_sampling_rate() const
{
return m_sampling_rate;
return static_cast<std::underlying_type_t<decltype(m_sampling_rate)>>(m_sampling_rate);
}
u32 AudioBackend::get_sample_size() const
{
return m_sample_size;
return static_cast<std::underlying_type_t<decltype(m_sample_size)>>(m_sample_size);
}
u32 AudioBackend::get_channels() const
{
return m_channels;
return static_cast<std::underlying_type_t<decltype(m_channels)>>(m_channels);
}
bool AudioBackend::get_convert_to_u16() const
bool AudioBackend::get_convert_to_s16() const
{
return m_convert_to_u16;
return m_sample_size == AudioSampleSize::S16;
}
bool AudioBackend::has_capability(u32 cap) const
@@ -75,24 +37,6 @@ void AudioBackend::dump_capabilities(std::string& out) const
u32 count = 0;
const u32 capabilities = GetCapabilities();
if (capabilities & PLAY_PAUSE_FLUSH)
{
fmt::append(out, "PLAY_PAUSE_FLUSH");
count++;
}
if (capabilities & IS_PLAYING)
{
fmt::append(out, "%sIS_PLAYING", count > 0 ? " | " : "");
count++;
}
if (capabilities & GET_NUM_ENQUEUED_SAMPLES)
{
fmt::append(out, "%sGET_NUM_ENQUEUED_SAMPLES", count > 0 ? " | " : "");
count++;
}
if (capabilities & SET_FREQUENCY_RATIO)
{
fmt::append(out, "%sSET_FREQUENCY_RATIO", count > 0 ? " | " : "");
+54 -53
View File
@@ -7,7 +7,33 @@ enum : u32
{
DEFAULT_AUDIO_SAMPLING_RATE = 48000,
MAX_AUDIO_BUFFERS = 64,
AUDIO_BUFFER_SAMPLES = 256
AUDIO_BUFFER_SAMPLES = 256,
AUDIO_MIN_LATENCY = 512,
AUDIO_MAX_CHANNELS = 8,
};
enum class AudioFreq : u32
{
FREQ_32K = 32000,
FREQ_44K = 44100,
FREQ_48K = 48000,
FREQ_88K = 88200,
FREQ_96K = 96000,
FREQ_176K = 176400,
FREQ_192K = 192000,
};
enum class AudioSampleSize : u32
{
FLOAT = sizeof(float),
S16 = sizeof(s16),
};
enum class AudioChannelCnt : u32
{
STEREO = 2,
SURROUND_5_1 = 6,
SURROUND_7_1 = 8,
};
class AudioBackend
@@ -15,10 +41,7 @@ class AudioBackend
public:
enum Capabilities : u32
{
PLAY_PAUSE_FLUSH = 0x1, // Implements Play, Pause, Flush
IS_PLAYING = 0x2, // Implements IsPlaying
GET_NUM_ENQUEUED_SAMPLES = 0x4, // Implements GetNumEnqueuedSamples
SET_FREQUENCY_RATIO = 0x8, // Implements SetFrequencyRatio
SET_FREQUENCY_RATIO = 0x1, // Implements SetFrequencyRatio
};
AudioBackend();
@@ -28,62 +51,43 @@ public:
/*
* Pure virtual methods
*/
virtual const char* GetName() const = 0;
virtual std::string_view GetName() const = 0;
virtual u32 GetCapabilities() const = 0;
virtual void Open(u32 num_buffers) = 0;
virtual void Open(AudioFreq freq, AudioSampleSize sample_size, AudioChannelCnt ch_cnt) = 0;
virtual void Close() = 0;
virtual bool AddData(const void* src, u32 num_samples) = 0;
// Sets write callback. It's called when backend requests new data to be sent
// Callback should return number of submitted bytes. Calling other backend functions from callback is unsafe
virtual void SetWriteCallback(std::function<u32(u32 /* byte_cnt */, void * /* buffer */)> cb) = 0;
// Returns length of one callback frame in seconds.
virtual f64 GetCallbackFrameLen() = 0;
// Returns true if audio is currently being played, false otherwise
virtual bool IsPlaying() = 0;
// Start playing enqueued data
virtual void Play() = 0;
// Pause playing enqueued data
virtual void Pause() = 0;
/*
* This virtual method should be reimplemented if backend can fail to be initialized under non-error conditions
* eg. when there is no audio devices attached
*/
virtual bool Initialized() const { return true; }
virtual bool Initialized() { return true; }
/*
* This virtual method should be reimplemented if backend can fail during normal operation
*/
virtual bool Operational() { return true; }
/*
* Virtual methods - should be implemented depending on backend capabilities
*/
// Start playing enqueued data
// Should be implemented if capabilities & PLAY_PAUSE_FLUSH
virtual void Play()
{
fmt::throw_exception("Play() not implemented");
}
// Pause playing enqueued data
// Should be implemented if capabilities & PLAY_PAUSE_FLUSH
virtual void Pause()
{
fmt::throw_exception("Pause() not implemented");
}
// Pause audio, and unqueue all currently queued buffers
// Should be implemented if capabilities & PLAY_PAUSE_FLUSH
virtual void Flush()
{
fmt::throw_exception("Flush() not implemented");
}
// Returns true if audio is currently being played, false otherwise
// Should be implemented if capabilities & IS_PLAYING
virtual bool IsPlaying()
{
fmt::throw_exception("IsPlaying() not implemented");
}
// Returns the number of currently enqueued samples
// Should be implemented if capabilities & GET_NUM_ENQUEUED_SAMPLES
virtual u64 GetNumEnqueuedSamples()
{
fmt::throw_exception("GetNumEnqueuedSamples() not implemented");
return 0;
}
// Sets a new frequency ratio. Backend is allowed to modify the ratio value, e.g. clamping it to the allowed range
// Returns the new frequency ratio set
// Should be implemented if capabilities & SET_FREQUENCY_RATIO
@@ -93,7 +97,6 @@ public:
return 1.0f;
}
/*
* Helper methods
*/
@@ -103,16 +106,14 @@ public:
u32 get_channels() const;
bool get_convert_to_u16() const;
bool get_convert_to_s16() const;
bool has_capability(u32 cap) const;
void dump_capabilities(std::string& out) const;
protected:
bool m_convert_to_u16 = false;
u32 m_sample_size = sizeof(float);
u32 m_sampling_rate = DEFAULT_AUDIO_SAMPLING_RATE;
u32 m_channels = 0;
u32 m_start_threshold = 1;
AudioSampleSize m_sample_size = AudioSampleSize::FLOAT;
AudioFreq m_sampling_rate = AudioFreq::FREQ_48K;
AudioChannelCnt m_channels = AudioChannelCnt::STEREO;
};
+2 -2
View File
@@ -4,8 +4,8 @@
#include "Utilities/date_time.h"
#include "Emu/System.h"
AudioDumper::AudioDumper(u16 ch)
: m_header(ch)
AudioDumper::AudioDumper(u16 ch, u32 sample_rate, u32 sample_size)
: m_header(ch, sample_rate, sample_size)
{
if (GetCh())
{
+10 -10
View File
@@ -30,19 +30,19 @@ struct WAVHeader
u32 SampleRate; // 48000
u32 ByteRate; // SampleRate * NumChannels * BitsPerSample/8
u16 BlockAlign; // NumChannels * BitsPerSample/8
u16 BitsPerSample; // sizeof(float) * 8
u16 BitsPerSample; // SampleSize * 8
FMTHeader() = default;
FMTHeader(u16 ch)
FMTHeader(u16 ch, u32 sample_rate, u32 sample_size)
: ID("fmt "_u32)
, Size(16)
, AudioFormat(3)
, AudioFormat(sample_size == sizeof(float) ? 3 : 1)
, NumChannels(ch)
, SampleRate(48000)
, ByteRate(SampleRate * ch * sizeof(float))
, BlockAlign(ch * sizeof(float))
, BitsPerSample(sizeof(float) * 8)
, SampleRate(sample_rate)
, ByteRate(SampleRate * ch * sample_size)
, BlockAlign(ch * sample_size)
, BitsPerSample(sample_size * 8)
{
}
} FMT;
@@ -52,9 +52,9 @@ struct WAVHeader
WAVHeader() = default;
WAVHeader(u16 ch)
WAVHeader(u16 ch, u32 sample_rate, u32 sample_size)
: RIFF(sizeof(RIFFHeader) + sizeof(FMTHeader))
, FMT(ch)
, FMT(ch, sample_rate, sample_size)
, ID("data"_u32)
, Size(0)
{
@@ -67,7 +67,7 @@ class AudioDumper
fs::file m_output{};
public:
AudioDumper(u16 ch);
AudioDumper(u16 ch, u32 sample_rate, u32 sample_size);
~AudioDumper();
void WriteData(const void* buffer, u32 size);
+223
View File
@@ -0,0 +1,223 @@
#include "Emu/Audio/Cubeb/CubebBackend.h"
#include <algorithm>
#include "util/logs.hpp"
#ifdef _WIN32
#include <Windows.h>
#include <system_error>
#endif
LOG_CHANNEL(Cubeb);
CubebBackend::CubebBackend()
: AudioBackend()
{
#ifdef _WIN32
// Cubeb requires COM to be initialized on the thread calling cubeb_init on Windows
HRESULT hr = CoInitializeEx(nullptr, COINIT_MULTITHREADED);
if (SUCCEEDED(hr))
{
m_com_init_success = true;
}
#endif
if (int err = cubeb_init(&m_ctx, "RPCS3", nullptr))
{
Cubeb.error("cubeb_init() failed: 0x%08x", err);
m_ctx = nullptr;
return;
}
Cubeb.notice("Using backend %s", cubeb_get_backend_id(m_ctx));
}
CubebBackend::~CubebBackend()
{
Close();
if (m_ctx)
{
cubeb_destroy(m_ctx);
}
#ifdef _WIN32
if (m_com_init_success)
{
CoUninitialize();
}
#endif
}
bool CubebBackend::Initialized()
{
return m_ctx != nullptr;
}
bool CubebBackend::Operational()
{
return m_ctx != nullptr && m_stream != nullptr && !m_reset_req.observe();
}
void CubebBackend::Open(AudioFreq freq, AudioSampleSize sample_size, AudioChannelCnt ch_cnt)
{
if (m_ctx == nullptr) return;
std::lock_guard lock(m_cb_mutex);
CloseUnlocked();
m_sampling_rate = freq;
m_sample_size = sample_size;
m_channels = ch_cnt;
cubeb_stream_params stream_param{};
stream_param.format = get_convert_to_s16() ? CUBEB_SAMPLE_S16NE : CUBEB_SAMPLE_FLOAT32NE;
stream_param.rate = get_sampling_rate();
stream_param.channels = get_channels();
stream_param.layout = [&]()
{
switch (ch_cnt)
{
case AudioChannelCnt::STEREO: return CUBEB_LAYOUT_STEREO;
case AudioChannelCnt::SURROUND_5_1: return CUBEB_LAYOUT_3F2_LFE;
case AudioChannelCnt::SURROUND_7_1: return CUBEB_LAYOUT_3F4_LFE;
default:
ensure(false);
return CUBEB_LAYOUT_UNDEFINED;
}
}();
u32 min_latency{};
if (int err = cubeb_get_min_latency(m_ctx, &stream_param, &min_latency))
{
Cubeb.error("cubeb_get_min_latency() failed: 0x%08x", err);
}
if (int err = cubeb_stream_init(m_ctx, &m_stream, "Main stream", nullptr, nullptr, nullptr, &stream_param, std::max<u32>(AUDIO_MIN_LATENCY, min_latency), data_cb, state_cb, this))
{
m_stream = nullptr;
Cubeb.error("cubeb_stream_init() failed: 0x%08x", err);
}
if (m_stream == nullptr)
{
Cubeb.error("Failed to open audio backend. Make sure that no other application is running that might block audio access (e.g. Netflix).");
CloseUnlocked();
return;
}
if (int err = cubeb_stream_set_volume(m_stream, 1.0))
{
Cubeb.error("cubeb_stream_set_volume() failed: 0x%08x", err);
}
}
void CubebBackend::CloseUnlocked()
{
if (m_stream == nullptr) return;
if (int err = cubeb_stream_stop(m_stream))
{
Cubeb.error("cubeb_stream_stop() failed: 0x%08x", err);
}
cubeb_stream_destroy(m_stream);
m_playing = false;
m_stream = nullptr;
memset(m_last_sample, 0, sizeof(m_last_sample));
}
void CubebBackend::Close()
{
std::lock_guard lock(m_cb_mutex);
CloseUnlocked();
}
void CubebBackend::Play()
{
if (m_playing) return;
if (int err = cubeb_stream_start(m_stream))
{
Cubeb.error("cubeb_stream_start() failed: 0x%08x", err);
}
std::lock_guard lock(m_cb_mutex);
m_playing = true;
}
void CubebBackend::Pause()
{
if (int err = cubeb_stream_stop(m_stream))
{
Cubeb.error("cubeb_stream_stop() failed: 0x%08x", err);
}
std::lock_guard lock(m_cb_mutex);
m_playing = false;
}
bool CubebBackend::IsPlaying()
{
return m_playing;
}
void CubebBackend::SetWriteCallback(std::function<u32(u32, void *)> cb)
{
std::lock_guard lock(m_cb_mutex);
m_write_callback = cb;
}
f64 CubebBackend::GetCallbackFrameLen()
{
cubeb_stream_params stream_param{};
stream_param.format = get_convert_to_s16() ? CUBEB_SAMPLE_S16NE : CUBEB_SAMPLE_FLOAT32NE;
stream_param.rate = get_sampling_rate();
stream_param.channels = get_channels();
u32 min_latency{};
if (int err = cubeb_get_min_latency(m_ctx, &stream_param, &min_latency))
{
Cubeb.error("cubeb_get_min_latency() failed: 0x%08x", err);
}
return static_cast<f64>(std::max<u32>(AUDIO_MIN_LATENCY, min_latency)) / get_sampling_rate();
}
long CubebBackend::data_cb(cubeb_stream* /* stream */, void* user_ptr, void const* /* input_buffer */, void* output_buffer, long nframes)
{
CubebBackend* const cubeb = static_cast<CubebBackend*>(user_ptr);
std::unique_lock lock(cubeb->m_cb_mutex, std::defer_lock);
if (nframes && lock.try_lock() && cubeb->m_write_callback && cubeb->m_playing)
{
const u32 sample_size = cubeb->get_sample_size() * cubeb->get_channels();
const u32 bytes_req = nframes * cubeb->get_sample_size() * cubeb->get_channels();
u32 written = std::min(cubeb->m_write_callback(bytes_req, output_buffer), bytes_req);
written -= written % sample_size;
if (written >= sample_size)
{
memcpy(cubeb->m_last_sample, static_cast<u8*>(output_buffer) + written - sample_size, sample_size);
}
for (u32 i = written; i < bytes_req; i += sample_size)
{
memcpy(static_cast<u8*>(output_buffer) + i, cubeb->m_last_sample, sample_size);
}
}
return nframes;
}
void CubebBackend::state_cb(cubeb_stream* /* stream */, void* user_ptr, cubeb_state state)
{
CubebBackend* const cubeb = static_cast<CubebBackend*>(user_ptr);
if (state == CUBEB_STATE_ERROR)
{
Cubeb.error("Stream entered error state");
cubeb->m_reset_req = true;
}
}
+56
View File
@@ -0,0 +1,56 @@
#pragma once
#include <memory>
#include "Utilities/mutex.h"
#include "util/atomic.hpp"
#include "Emu/Audio/AudioBackend.h"
#include "cubeb/cubeb.h"
class CubebBackend final : public AudioBackend
{
public:
CubebBackend();
~CubebBackend() override;
CubebBackend(const CubebBackend&) = delete;
CubebBackend& operator=(const CubebBackend&) = delete;
std::string_view GetName() const override { return "Cubeb"sv; }
static const u32 capabilities = 0;
u32 GetCapabilities() const override { return capabilities; }
bool Initialized() override;
bool Operational() override;
void Open(AudioFreq freq, AudioSampleSize sample_size, AudioChannelCnt ch_cnt) override;
void Close() override;
void SetWriteCallback(std::function<u32(u32, void *)> cb) override;
f64 GetCallbackFrameLen() override;
void Play() override;
void Pause() override;
bool IsPlaying() override;
private:
cubeb* m_ctx = nullptr;
cubeb_stream* m_stream = nullptr;
#ifdef _WIN32
bool m_com_init_success = false;
#endif
shared_mutex m_cb_mutex{};
std::function<u32(u32, void *)> m_write_callback{};
u8 m_last_sample[sizeof(float) * static_cast<u32>(AudioChannelCnt::SURROUND_7_1)]{};
bool m_playing = false;
atomic_t<bool> m_reset_req = false;
// Cubeb callbacks
static long data_cb(cubeb_stream* stream, void* user_ptr, void const* input_buffer, void* output_buffer, long nframes);
static void state_cb(cubeb_stream* stream, void* user_ptr, cubeb_state state);
void CloseUnlocked();
};
+195 -87
View File
@@ -12,28 +12,41 @@ LOG_CHANNEL(FAudio_, "FAudio");
FAudioBackend::FAudioBackend()
: AudioBackend()
{
u32 res = FAudioCreate(&m_instance, 0, FAUDIO_DEFAULT_PROCESSOR);
FAudio *instance;
u32 res = FAudioCreate(&instance, 0, FAUDIO_DEFAULT_PROCESSOR);
if (res)
{
FAudio_.fatal("FAudioCreate() failed(0x%08x)", res);
FAudio_.error("FAudioCreate() failed(0x%08x)", res);
return;
}
res = FAudio_CreateMasteringVoice(m_instance, &m_master_voice, m_channels, 48000, 0, 0, nullptr);
res = FAudio_CreateMasteringVoice(instance, &m_master_voice, FAUDIO_DEFAULT_CHANNELS, FAUDIO_DEFAULT_SAMPLERATE, 0, 0, nullptr);
if (res)
{
FAudio_.fatal("FAudio_CreateMasteringVoice() failed(0x%08x)", res);
FAudio_.error("FAudio_CreateMasteringVoice() failed(0x%08x)", res);
FAudio_StopEngine(instance);
return;
}
OnProcessingPassStart = nullptr;
OnProcessingPassEnd = nullptr;
OnCriticalError = OnCriticalError_func;
res = FAudio_RegisterForCallbacks(instance, this);
if (res)
{
// Some error recovery functionality will be lost, but otherwise backend is operational
FAudio_.error("FAudio_RegisterForCallbacks() failed(0x%08x)", res);
}
// All succeeded, "commit"
m_instance = instance;
}
FAudioBackend::~FAudioBackend()
{
if (m_source_voice != nullptr)
{
FAudioSourceVoice_Stop(m_source_voice, 0, FAUDIO_COMMIT_NOW);
FAudioVoice_DestroyVoice(m_source_voice);
}
Close();
if (m_master_voice != nullptr)
{
@@ -49,127 +62,222 @@ FAudioBackend::~FAudioBackend()
void FAudioBackend::Play()
{
AUDIT(m_source_voice != nullptr);
if (m_source_voice == nullptr)
{
FAudio_.error("Play() called uninitialized");
return;
}
if (m_playing) return;
const u32 res = FAudioSourceVoice_Start(m_source_voice, 0, FAUDIO_COMMIT_NOW);
if (res)
{
FAudio_.fatal("FAudioSourceVoice_Start() failed(0x%08x)", res);
FAudio_.error("FAudioSourceVoice_Start() failed(0x%08x)", res);
}
std::lock_guard lock(m_cb_mutex);
m_playing = true;
}
void FAudioBackend::Pause()
{
AUDIT(m_source_voice != nullptr);
if (m_source_voice)
{
u32 res = FAudioSourceVoice_Stop(m_source_voice, 0, FAUDIO_COMMIT_NOW);
if (res)
{
FAudio_.error("FAudioSourceVoice_Stop() failed(0x%08x)", res);
}
if (res = FAudioSourceVoice_FlushSourceBuffers(m_source_voice))
{
FAudio_.error("FAudioSourceVoice_FlushSourceBuffers() failed(0x%08x)", res);
}
}
else
{
FAudio_.error("Pause() called uninitialized");
}
std::lock_guard lock(m_cb_mutex);
m_playing = false;
}
void FAudioBackend::CloseUnlocked()
{
if (m_source_voice == nullptr) return;
const u32 res = FAudioSourceVoice_Stop(m_source_voice, 0, FAUDIO_COMMIT_NOW);
if (res)
{
FAudio_.fatal("FAudioSourceVoice_Stop() failed(0x%08x)", res);
FAudio_.error("FAudioSourceVoice_Stop() failed(0x%08x)", res);
}
}
void FAudioBackend::Flush()
{
AUDIT(m_source_voice != nullptr);
const u32 res = FAudioSourceVoice_FlushSourceBuffers(m_source_voice);
if (res)
{
FAudio_.fatal("FAudioSourceVoice_FlushSourceBuffers() failed(0x%08x)", res);
}
}
bool FAudioBackend::IsPlaying()
{
AUDIT(m_source_voice != nullptr);
FAudioVoiceState state;
FAudioSourceVoice_GetState(m_source_voice, &state, FAUDIO_VOICE_NOSAMPLESPLAYED);
return state.BuffersQueued > 0 || state.pCurrentBufferContext != nullptr;
FAudioVoice_DestroyVoice(m_source_voice);
m_playing = false;
m_source_voice = nullptr;
m_data_buf = nullptr;
m_data_buf_len = 0;
memset(m_last_sample, 0, sizeof(m_last_sample));
}
void FAudioBackend::Close()
{
Pause();
Flush();
std::lock_guard lock(m_cb_mutex);
CloseUnlocked();
}
void FAudioBackend::Open(u32 /* num_buffers */)
bool FAudioBackend::Initialized()
{
return m_instance != nullptr;
}
bool FAudioBackend::Operational()
{
return m_instance != nullptr && m_source_voice != nullptr && !m_reset_req.observe();
}
void FAudioBackend::Open(AudioFreq freq, AudioSampleSize sample_size, AudioChannelCnt ch_cnt)
{
if (m_instance == nullptr) return;
std::lock_guard lock(m_cb_mutex);
CloseUnlocked();
m_sampling_rate = freq;
m_sample_size = sample_size;
m_channels = ch_cnt;
FAudioWaveFormatEx waveformatex;
waveformatex.wFormatTag = m_convert_to_u16 ? FAUDIO_FORMAT_PCM : FAUDIO_FORMAT_IEEE_FLOAT;
waveformatex.nChannels = m_channels;
waveformatex.nSamplesPerSec = m_sampling_rate;
waveformatex.nAvgBytesPerSec = static_cast<u32>(m_sampling_rate * m_channels * m_sample_size);
waveformatex.nBlockAlign = m_channels * m_sample_size;
waveformatex.wBitsPerSample = m_sample_size * 8;
waveformatex.cbSize = 0;
waveformatex.wFormatTag = get_convert_to_s16() ? FAUDIO_FORMAT_PCM : FAUDIO_FORMAT_IEEE_FLOAT;
waveformatex.nChannels = get_channels();
waveformatex.nSamplesPerSec = get_sampling_rate();
waveformatex.nAvgBytesPerSec = static_cast<u32>(get_sampling_rate() * get_channels() * get_sample_size());
waveformatex.nBlockAlign = get_channels() * get_sample_size();
waveformatex.wBitsPerSample = get_sample_size() * 8;
waveformatex.cbSize = 0;
const u32 res = FAudio_CreateSourceVoice(m_instance, &m_source_voice, &waveformatex, 0, FAUDIO_DEFAULT_FREQ_RATIO, nullptr, nullptr, nullptr);
OnVoiceProcessingPassStart = OnVoiceProcessingPassStart_func;
OnVoiceProcessingPassEnd = nullptr;
OnStreamEnd = nullptr;
OnBufferStart = nullptr;
OnBufferEnd = nullptr;
OnLoopEnd = nullptr;
OnVoiceError = nullptr;
const u32 res = FAudio_CreateSourceVoice(m_instance, &m_source_voice, &waveformatex, 0, FAUDIO_DEFAULT_FREQ_RATIO, this, nullptr, nullptr);
if (res)
{
FAudio_.fatal("FAudio_CreateSourceVoice() failed(0x%08x)", res);
FAudio_.error("FAudio_CreateSourceVoice() failed(0x%08x)", res);
}
if (m_source_voice == nullptr)
{
FAudio_.fatal("Failed to open audio backend. Make sure that no other application is running that might block audio access (e.g. Netflix).");
return;
}
AUDIT(m_source_voice != nullptr);
FAudioVoice_SetVolume(m_source_voice, 1.0f, FAUDIO_COMMIT_NOW);
m_data_buf_len = get_sampling_rate() * get_sample_size() * get_channels() * INTERNAL_BUF_SIZE_MS * static_cast<u32>(FAUDIO_DEFAULT_FREQ_RATIO) / 1000;
m_data_buf = std::make_unique<u8[]>(m_data_buf_len);
}
bool FAudioBackend::AddData(const void* src, u32 num_samples)
bool FAudioBackend::IsPlaying()
{
AUDIT(m_source_voice != nullptr);
FAudioVoiceState state;
FAudioSourceVoice_GetState(m_source_voice, &state, FAUDIO_VOICE_NOSAMPLESPLAYED);
if (state.BuffersQueued >= MAX_AUDIO_BUFFERS)
{
FAudio_.warning("Too many buffers enqueued (%d)", state.BuffersQueued);
return false;
}
FAudioBuffer buffer;
buffer.AudioBytes = num_samples * m_sample_size;
buffer.Flags = 0;
buffer.LoopBegin = FAUDIO_NO_LOOP_REGION;
buffer.LoopCount = 0;
buffer.LoopLength = 0;
buffer.pAudioData = static_cast<const u8*>(src);
buffer.pContext = nullptr;
buffer.PlayBegin = 0;
buffer.PlayLength = AUDIO_BUFFER_SAMPLES;
const u32 res = FAudioSourceVoice_SubmitSourceBuffer(m_source_voice, &buffer, nullptr);
if (res)
{
FAudio_.fatal("FAudioSourceVoice_SubmitSourceBuffer() failed(0x%08x)", res);
return false;
}
return true;
}
u64 FAudioBackend::GetNumEnqueuedSamples()
{
FAudioVoiceState state;
FAudioSourceVoice_GetState(m_source_voice, &state, 0);
// all buffers contain AUDIO_BUFFER_SAMPLES, so we can easily calculate how many samples there are remaining
return (AUDIO_BUFFER_SAMPLES - state.SamplesPlayed % AUDIO_BUFFER_SAMPLES) + (state.BuffersQueued * AUDIO_BUFFER_SAMPLES);
return m_playing;
}
f32 FAudioBackend::SetFrequencyRatio(f32 new_ratio)
{
new_ratio = std::clamp(new_ratio, FAUDIO_MIN_FREQ_RATIO, FAUDIO_DEFAULT_FREQ_RATIO);
if (m_source_voice == nullptr)
{
FAudio_.error("SetFrequencyRatio() called uninitialized");
return 1.0f;
}
const u32 res = FAudioSourceVoice_SetFrequencyRatio(m_source_voice, new_ratio, FAUDIO_COMMIT_NOW);
if (res)
{
FAudio_.fatal("FAudioSourceVoice_SetFrequencyRatio() failed(0x%08x)", res);
FAudio_.error("FAudioSourceVoice_SetFrequencyRatio() failed(0x%08x)", res);
return 1.0f;
}
return new_ratio;
}
void FAudioBackend::SetWriteCallback(std::function<u32(u32, void *)> cb)
{
std::lock_guard lock(m_cb_mutex);
m_write_callback = cb;
}
f64 FAudioBackend::GetCallbackFrameLen()
{
constexpr f64 _10ms = 0.01;
if (m_instance == nullptr)
{
FAudio_.error("GetCallbackFrameLen() called uninitialized");
return _10ms;
}
f64 min_latency{};
u32 samples_per_q = 0, freq = 0;
FAudio_GetProcessingQuantum(m_instance, &samples_per_q, &freq);
if (freq)
{
min_latency = static_cast<f64>(samples_per_q) / freq;
}
return std::max<f64>(min_latency, _10ms);
}
void FAudioBackend::OnVoiceProcessingPassStart_func(FAudioVoiceCallback *cb_obj, u32 BytesRequired)
{
FAudioBackend *faudio = static_cast<FAudioBackend *>(cb_obj);
std::unique_lock lock(faudio->m_cb_mutex, std::defer_lock);
if (BytesRequired && lock.try_lock() && faudio->m_write_callback && faudio->m_playing)
{
ensure(BytesRequired <= faudio->m_data_buf_len, "FAudio internal buffer is too small. Report to developers!");
const u32 sample_size = faudio->get_sample_size() * faudio->get_channels();
u32 written = std::min(faudio->m_write_callback(BytesRequired, faudio->m_data_buf.get()), BytesRequired);
written -= written % sample_size;
if (written >= sample_size)
{
memcpy(faudio->m_last_sample, faudio->m_data_buf.get() + written - sample_size, sample_size);
}
for (u32 i = written; i < BytesRequired; i += sample_size)
{
memcpy(faudio->m_data_buf.get() + i, faudio->m_last_sample, sample_size);
}
FAudioBuffer buffer{};
buffer.AudioBytes = BytesRequired;
buffer.LoopBegin = FAUDIO_NO_LOOP_REGION;
buffer.pAudioData = static_cast<const u8*>(faudio->m_data_buf.get());
const u32 res = FAudioSourceVoice_SubmitSourceBuffer(faudio->m_source_voice, &buffer, nullptr);
if (res)
{
FAudio_.error("FAudioSourceVoice_SubmitSourceBuffer() failed(0x%08x)", res);
}
}
}
void FAudioBackend::OnCriticalError_func(FAudioEngineCallback *cb_obj, u32 Error)
{
FAudio_.error("OnCriticalError() failed(0x%08x)", Error);
FAudioBackend *faudio = static_cast<FAudioBackend *>(cb_obj);
faudio->m_reset_req = true;
}
+38 -20
View File
@@ -4,16 +4,14 @@
#error "FAudio support disabled but still being built."
#endif
#include <memory>
#include "Utilities/mutex.h"
#include "Emu/Audio/AudioBackend.h"
#include "FAudio.h"
class FAudioBackend : public AudioBackend
class FAudioBackend : public AudioBackend, public FAudioVoiceCallback, public FAudioEngineCallback
{
private:
FAudio* m_instance{};
FAudioMasteringVoice* m_master_voice{};
FAudioSourceVoice* m_source_voice{};
public:
FAudioBackend();
~FAudioBackend() override;
@@ -21,27 +19,47 @@ public:
FAudioBackend(const FAudioBackend&) = delete;
FAudioBackend& operator=(const FAudioBackend&) = delete;
const char* GetName() const override
{
return "FAudio";
}
std::string_view GetName() const override { return "FAudio"sv; }
static const u32 capabilities = PLAY_PAUSE_FLUSH | IS_PLAYING | GET_NUM_ENQUEUED_SAMPLES | SET_FREQUENCY_RATIO;
u32 GetCapabilities() const override
{
return capabilities;
}
static const u32 capabilities = SET_FREQUENCY_RATIO;
u32 GetCapabilities() const override { return capabilities; }
void Open(u32 /* num_buffers */) override;
bool Initialized() override;
bool Operational() override;
void Open(AudioFreq freq, AudioSampleSize sample_size, AudioChannelCnt ch_cnt) override;
void Close() override;
void SetWriteCallback(std::function<u32(u32, void *)> cb) override;
f64 GetCallbackFrameLen() override;
void Play() override;
void Pause() override;
bool IsPlaying() override;
bool AddData(const void* src, u32 num_samples) override;
void Flush() override;
u64 GetNumEnqueuedSamples() override;
f32 SetFrequencyRatio(f32 new_ratio) override;
private:
static constexpr u32 INTERNAL_BUF_SIZE_MS = 25;
FAudio* m_instance{};
FAudioMasteringVoice* m_master_voice{};
FAudioSourceVoice* m_source_voice{};
shared_mutex m_cb_mutex{};
std::function<u32(u32, void *)> m_write_callback{};
std::unique_ptr<u8[]> m_data_buf{};
u64 m_data_buf_len = 0;
u8 m_last_sample[sizeof(float) * static_cast<u32>(AudioChannelCnt::SURROUND_7_1)]{};
bool m_playing = false;
atomic_t<bool> m_reset_req = false;
// FAudio voice callbacks
static void OnVoiceProcessingPassStart_func(FAudioVoiceCallback *cb_obj, u32 BytesRequired);
// FAudio engine callbacks
static void OnCriticalError_func(FAudioEngineCallback *cb_obj, u32 Error);
void CloseUnlocked();
};
+14 -10
View File
@@ -6,19 +6,23 @@ class NullAudioBackend : public AudioBackend
{
public:
NullAudioBackend() {}
virtual ~NullAudioBackend() {}
~NullAudioBackend() {}
virtual const char* GetName() const override { return "Null"; }
std::string_view GetName() const override { return "Null"sv; }
static const u32 capabilities = PLAY_PAUSE_FLUSH;
virtual u32 GetCapabilities() const override { return capabilities; }
static const u32 capabilities = 0;
u32 GetCapabilities() const override { return capabilities; }
virtual void Open(u32) override {}
virtual void Close() override {}
void Open(AudioFreq /* freq */, AudioSampleSize /* sample_size */, AudioChannelCnt /* ch_cnt */) override { m_playing = false; }
void Close() override { m_playing = false; }
virtual void Play() override {}
virtual void Pause() override {}
void SetWriteCallback(std::function<u32(u32, void *)> /* cb */) override {};
f64 GetCallbackFrameLen() override { return 0.01; };
virtual bool AddData(const void*, u32) override { return true; }
virtual void Flush() override {}
void Play() override { m_playing = true; }
void Pause() override { m_playing = false; }
bool IsPlaying() override { return m_playing; }
private:
bool m_playing = false;
};
-88
View File
@@ -1,88 +0,0 @@
#ifndef HAVE_PULSE
#error "PulseAudio support disabled but still being built."
#endif
#include "Emu/System.h"
#include "PulseBackend.h"
#include <pulse/simple.h>
#include <pulse/error.h>
PulseBackend::PulseBackend()
: AudioBackend()
{
}
PulseBackend::~PulseBackend()
{
this->Close();
}
void PulseBackend::Close()
{
if (this->connection)
{
pa_simple_free(this->connection);
this->connection = nullptr;
}
}
void PulseBackend::Open(u32 /* num_buffers */)
{
pa_sample_spec ss;
ss.format = (m_sample_size == 2) ? PA_SAMPLE_S16LE : PA_SAMPLE_FLOAT32LE;
ss.rate = m_sampling_rate;
pa_channel_map channel_map;
if (m_channels == 2)
{
channel_map.channels = 2;
channel_map.map[0] = PA_CHANNEL_POSITION_FRONT_LEFT;
channel_map.map[1] = PA_CHANNEL_POSITION_FRONT_RIGHT;
}
else if (m_channels == 6)
{
channel_map.channels = 6;
channel_map.map[0] = PA_CHANNEL_POSITION_FRONT_LEFT;
channel_map.map[1] = PA_CHANNEL_POSITION_FRONT_RIGHT;
channel_map.map[2] = PA_CHANNEL_POSITION_FRONT_CENTER;
channel_map.map[3] = PA_CHANNEL_POSITION_LFE;
channel_map.map[4] = PA_CHANNEL_POSITION_REAR_LEFT;
channel_map.map[5] = PA_CHANNEL_POSITION_REAR_RIGHT;
}
else
{
channel_map.channels = 8;
channel_map.map[0] = PA_CHANNEL_POSITION_FRONT_LEFT;
channel_map.map[1] = PA_CHANNEL_POSITION_FRONT_RIGHT;
channel_map.map[2] = PA_CHANNEL_POSITION_FRONT_CENTER;
channel_map.map[3] = PA_CHANNEL_POSITION_LFE;
channel_map.map[4] = PA_CHANNEL_POSITION_REAR_LEFT;
channel_map.map[5] = PA_CHANNEL_POSITION_REAR_RIGHT;
channel_map.map[6] = PA_CHANNEL_POSITION_SIDE_LEFT;
channel_map.map[7] = PA_CHANNEL_POSITION_SIDE_RIGHT;
}
ss.channels = channel_map.channels;
int err;
this->connection = pa_simple_new(NULL, "RPCS3", PA_STREAM_PLAYBACK, NULL, "Game", &ss, &channel_map, NULL, &err);
if (!this->connection)
{
fprintf(stderr, "PulseAudio: Failed to initialize audio: %s\n", pa_strerror(err));
}
}
bool PulseBackend::AddData(const void* src, u32 num_samples)
{
AUDIT(this->connection);
int err;
if (pa_simple_write(this->connection, src, num_samples * m_sample_size, &err) < 0)
{
fprintf(stderr, "PulseAudio: Failed to write audio stream: %s\n", pa_strerror(err));
return false;
}
return true;
}
-31
View File
@@ -1,31 +0,0 @@
#pragma once
#ifndef HAVE_PULSE
#error "PulseAudio support disabled but still being built."
#endif
#include <pulse/simple.h>
#include "Emu/Audio/AudioBackend.h"
class PulseBackend : public AudioBackend
{
public:
PulseBackend();
virtual ~PulseBackend() override;
PulseBackend(const PulseBackend&) = delete;
PulseBackend& operator=(const PulseBackend&) = delete;
virtual const char* GetName() const override { return "Pulse"; }
static const u32 capabilities = 0;
virtual u32 GetCapabilities() const override { return capabilities; }
virtual void Open(u32) override;
virtual void Close() override;
virtual bool AddData(const void* src, u32 num_samples) override;
private:
pa_simple* connection{};
};
+215 -102
View File
@@ -22,24 +22,24 @@ XAudio2Backend::XAudio2Backend()
// In order to prevent errors on CreateMasteringVoice, apparently we need CoInitializeEx according to:
// https://docs.microsoft.com/en-us/windows/win32/api/xaudio2fx/nf-xaudio2fx-xaudio2createvolumemeter
HRESULT hr = CoInitializeEx(nullptr, COINIT_MULTITHREADED);
if (FAILED(hr) && hr != RPC_E_CHANGED_MODE)
if (SUCCEEDED(hr))
{
XAudio.error("CoInitializeEx() failed: %s (0x%08x)", std::system_category().message(hr), static_cast<u32>(hr));
return;
m_com_init_success = true;
}
hr = XAudio2Create(instance.GetAddressOf(), 0, XAUDIO2_DEFAULT_PROCESSOR);
hr = XAudio2Create(instance.GetAddressOf(), 0, XAUDIO2_USE_DEFAULT_PROCESSOR);
if (FAILED(hr))
{
XAudio.error("XAudio2Create() failed: %s (0x%08x)", std::system_category().message(hr), static_cast<u32>(hr));
return;
}
hr = instance->CreateMasteringVoice(&m_master_voice, m_channels, 48000);
hr = instance->RegisterForCallbacks(this);
if (FAILED(hr))
{
XAudio.error("CreateMasteringVoice() failed: %s (0x%08x)", std::system_category().message(hr), static_cast<u32>(hr));
return;
// Some error recovery functionality will be lost, but otherwise backend is operational
XAudio.error("RegisterForCallbacks() failed: %s (0x%08x)", std::system_category().message(hr), static_cast<u32>(hr));
}
// All succeeded, "commit"
@@ -48,149 +48,262 @@ XAudio2Backend::XAudio2Backend()
XAudio2Backend::~XAudio2Backend()
{
if (m_source_voice != nullptr)
{
m_source_voice->Stop();
m_source_voice->DestroyVoice();
}
if (m_master_voice != nullptr)
{
m_master_voice->DestroyVoice();
}
Close();
if (m_xaudio2_instance != nullptr)
{
m_xaudio2_instance->StopEngine();
// TODO: Enabling this might crash afterwards in ComPtr::InternalRelease.
// Maybe it's both trying to do the same thing?
//m_xaudio2_instance->Release();
}
if (m_com_init_success)
{
CoUninitialize();
}
}
bool XAudio2Backend::Initialized()
{
return m_xaudio2_instance != nullptr;
}
bool XAudio2Backend::Operational()
{
if (m_dev_listener.output_device_changed())
{
m_reset_req = true;
}
return m_xaudio2_instance != nullptr && m_source_voice != nullptr && !m_reset_req.observe();
}
void XAudio2Backend::Play()
{
AUDIT(m_source_voice != nullptr);
if (m_source_voice == nullptr)
{
XAudio.error("Play() called uninitialized");
return;
}
if (m_playing) return;
const HRESULT hr = m_source_voice->Start();
if (FAILED(hr))
{
XAudio.fatal("Start() failed: %s (0x%08x)", std::system_category().message(hr), static_cast<u32>(hr));
XAudio.error("Start() failed: %s (0x%08x)", std::system_category().message(hr), static_cast<u32>(hr));
return;
}
std::lock_guard lock(m_cb_mutex);
m_playing = true;
}
void XAudio2Backend::CloseUnlocked()
{
if (m_master_voice != nullptr)
{
m_master_voice->DestroyVoice();
m_master_voice = nullptr;
}
if (m_source_voice != nullptr)
{
const HRESULT hr = m_source_voice->Stop();
if (FAILED(hr))
{
XAudio.error("Stop() failed: %s (0x%08x)", std::system_category().message(hr), static_cast<u32>(hr));
}
m_source_voice->DestroyVoice();
m_source_voice = nullptr;
}
m_playing = false;
m_data_buf = nullptr;
m_data_buf_len = 0;
memset(m_last_sample, 0, sizeof(m_last_sample));
}
void XAudio2Backend::Close()
{
Pause();
Flush();
std::lock_guard lock(m_cb_mutex);
CloseUnlocked();
}
void XAudio2Backend::Pause()
{
AUDIT(m_source_voice != nullptr);
const HRESULT hr = m_source_voice->Stop();
if (FAILED(hr))
if (m_source_voice)
{
XAudio.fatal("Stop() failed: %s (0x%08x)", std::system_category().message(hr), static_cast<u32>(hr));
HRESULT hr = m_source_voice->Stop();
if (FAILED(hr))
{
XAudio.error("Stop() failed: %s (0x%08x)", std::system_category().message(hr), static_cast<u32>(hr));
}
hr = m_source_voice->FlushSourceBuffers();
if (FAILED(hr))
{
XAudio.error("FlushSourceBuffers() failed: %s (0x%08x)", std::system_category().message(hr), static_cast<u32>(hr));
}
}
else
{
XAudio.error("Pause() called uninitialized");
}
std::lock_guard lock(m_cb_mutex);
m_playing = false;
}
void XAudio2Backend::Open(u32 /* num_buffers */)
void XAudio2Backend::Open(AudioFreq freq, AudioSampleSize sample_size, AudioChannelCnt ch_cnt)
{
WAVEFORMATEX waveformatex{};
waveformatex.wFormatTag = m_convert_to_u16 ? WAVE_FORMAT_PCM : WAVE_FORMAT_IEEE_FLOAT;
waveformatex.nChannels = m_channels;
waveformatex.nSamplesPerSec = m_sampling_rate;
waveformatex.nAvgBytesPerSec = static_cast<DWORD>(m_sampling_rate * m_channels * m_sample_size);
waveformatex.nBlockAlign = m_channels * m_sample_size;
waveformatex.wBitsPerSample = m_sample_size * 8;
waveformatex.cbSize = 0;
std::lock_guard lock(m_cb_mutex);
CloseUnlocked();
const HRESULT hr = m_xaudio2_instance->CreateSourceVoice(&m_source_voice, &waveformatex, 0, XAUDIO2_DEFAULT_FREQ_RATIO);
if (FAILED(hr))
if (m_xaudio2_instance == nullptr)
{
XAudio.fatal("CreateSourceVoice() failed: %s (0x%08x)", std::system_category().message(hr), static_cast<u32>(hr));
XAudio.error("Open() called unitiliazed");
return;
}
AUDIT(m_source_voice != nullptr);
HRESULT hr = m_xaudio2_instance->CreateMasteringVoice(&m_master_voice);
if (FAILED(hr))
{
XAudio.error("CreateMasteringVoice() failed: %s (0x%08x)", std::system_category().message(hr), static_cast<u32>(hr));
XAudio.error("Failed to open audio backend. Make sure that no other application is running that might block audio access (e.g. Netflix).");
m_reset_req = true;
return;
}
m_sampling_rate = freq;
m_sample_size = sample_size;
m_channels = ch_cnt;
WAVEFORMATEX waveformatex{};
waveformatex.wFormatTag = get_convert_to_s16() ? WAVE_FORMAT_PCM : WAVE_FORMAT_IEEE_FLOAT;
waveformatex.nChannels = get_channels();
waveformatex.nSamplesPerSec = get_sampling_rate();
waveformatex.nAvgBytesPerSec = static_cast<DWORD>(get_sampling_rate() * get_channels() * get_sample_size());
waveformatex.nBlockAlign = get_channels() * get_sample_size();
waveformatex.wBitsPerSample = get_sample_size() * 8;
waveformatex.cbSize = 0;
hr = m_xaudio2_instance->CreateSourceVoice(&m_source_voice, &waveformatex, 0, XAUDIO2_DEFAULT_FREQ_RATIO, this);
if (FAILED(hr))
{
XAudio.error("CreateSourceVoice() failed: %s (0x%08x)", std::system_category().message(hr), static_cast<u32>(hr));
return;
}
ensure(m_source_voice != nullptr);
m_source_voice->SetVolume(1.0f);
m_data_buf_len = get_sampling_rate() * get_sample_size() * get_channels() * INTERNAL_BUF_SIZE_MS * static_cast<u32>(XAUDIO2_DEFAULT_FREQ_RATIO) / 1000;
m_data_buf = std::make_unique<u8[]>(m_data_buf_len);
}
bool XAudio2Backend::IsPlaying()
{
AUDIT(m_source_voice != nullptr);
XAUDIO2_VOICE_STATE state;
m_source_voice->GetState(&state, XAUDIO2_VOICE_NOSAMPLESPLAYED);
return state.BuffersQueued > 0 || state.pCurrentBufferContext != nullptr;
}
bool XAudio2Backend::AddData(const void* src, u32 num_samples)
{
AUDIT(m_source_voice != nullptr);
XAUDIO2_VOICE_STATE state;
m_source_voice->GetState(&state, XAUDIO2_VOICE_NOSAMPLESPLAYED);
if (state.BuffersQueued >= MAX_AUDIO_BUFFERS)
{
XAudio.warning("Too many buffers enqueued (%d)", state.BuffersQueued);
return false;
}
XAUDIO2_BUFFER buffer{};
buffer.AudioBytes = num_samples * m_sample_size;
buffer.Flags = 0;
buffer.LoopBegin = XAUDIO2_NO_LOOP_REGION;
buffer.LoopCount = 0;
buffer.LoopLength = 0;
buffer.pAudioData = static_cast<const BYTE*>(src);
buffer.pContext = nullptr;
buffer.PlayBegin = 0;
buffer.PlayLength = AUDIO_BUFFER_SAMPLES;
const HRESULT hr = m_source_voice->SubmitSourceBuffer(&buffer);
if (FAILED(hr))
{
XAudio.fatal("AddData() failed: %s (0x%08x)", std::system_category().message(hr), static_cast<u32>(hr));
return false;
}
return true;
}
void XAudio2Backend::Flush()
{
AUDIT(m_source_voice != nullptr);
const HRESULT hr = m_source_voice->FlushSourceBuffers();
if (FAILED(hr))
{
XAudio.fatal("FlushSourceBuffers() failed: %s (0x%08x)", std::system_category().message(hr), static_cast<u32>(hr));
}
}
u64 XAudio2Backend::GetNumEnqueuedSamples()
{
AUDIT(m_source_voice != nullptr);
XAUDIO2_VOICE_STATE state;
m_source_voice->GetState(&state);
// all buffers contain AUDIO_BUFFER_SAMPLES, so we can easily calculate how many samples there are remaining
return static_cast<u64>(AUDIO_BUFFER_SAMPLES - state.SamplesPlayed % AUDIO_BUFFER_SAMPLES) + (state.BuffersQueued * AUDIO_BUFFER_SAMPLES);
return m_playing;
}
f32 XAudio2Backend::SetFrequencyRatio(f32 new_ratio)
{
if (m_source_voice == nullptr)
{
XAudio.error("SetFrequencyRatio() called uninitialized");
return 1.0f;
}
new_ratio = std::clamp(new_ratio, XAUDIO2_MIN_FREQ_RATIO, XAUDIO2_DEFAULT_FREQ_RATIO);
const HRESULT hr = m_source_voice->SetFrequencyRatio(new_ratio);
if (FAILED(hr))
{
XAudio.fatal("SetFrequencyRatio() failed: %s (0x%08x)", std::system_category().message(hr), static_cast<u32>(hr));
XAudio.error("SetFrequencyRatio() failed: %s (0x%08x)", std::system_category().message(hr), static_cast<u32>(hr));
return 1.0f;
}
return new_ratio;
}
void XAudio2Backend::SetWriteCallback(std::function<u32(u32, void *)> cb)
{
std::lock_guard lock(m_cb_mutex);
m_write_callback = cb;
}
f64 XAudio2Backend::GetCallbackFrameLen()
{
constexpr f64 _10ms = 0.01;
if (m_source_voice == nullptr)
{
XAudio.error("GetCallbackFrameLen() called uninitialized");
return _10ms;
}
void *ext;
f64 min_latency{};
HRESULT hr = m_xaudio2_instance->QueryInterface(IID_IXAudio2Extension, &ext);
if (FAILED(hr))
{
XAudio.error("QueryInterface() failed: %s (0x%08x)", std::system_category().message(hr), static_cast<u32>(hr));
}
else
{
u32 samples_per_q = 0, freq = 0;
static_cast<IXAudio2Extension *>(ext)->GetProcessingQuantum(&samples_per_q, &freq);
if (freq)
{
min_latency = static_cast<f64>(samples_per_q) / freq;
}
}
return std::max<f64>(min_latency, _10ms); // 10ms is the minimum for XAudio
}
void XAudio2Backend::OnVoiceProcessingPassStart(UINT32 BytesRequired)
{
std::unique_lock lock(m_cb_mutex, std::defer_lock);
if (BytesRequired && lock.try_lock() && m_write_callback && m_playing)
{
ensure(BytesRequired <= m_data_buf_len, "XAudio internal buffer is too small. Report to developers!");
const u32 sample_size = get_sample_size() * get_channels();
u32 written = std::min(m_write_callback(BytesRequired, m_data_buf.get()), BytesRequired);
written -= written % sample_size;
if (written >= sample_size)
{
memcpy(m_last_sample, m_data_buf.get() + written - sample_size, sample_size);
}
for (u32 i = written; i < BytesRequired; i += sample_size)
{
memcpy(m_data_buf.get() + i, m_last_sample, sample_size);
}
XAUDIO2_BUFFER buffer{};
buffer.AudioBytes = BytesRequired;
buffer.LoopBegin = XAUDIO2_NO_LOOP_REGION;
buffer.pAudioData = static_cast<const BYTE*>(m_data_buf.get());
const HRESULT hr = m_source_voice->SubmitSourceBuffer(&buffer);
if (FAILED(hr))
{
XAudio.error("SubmitSourceBuffer() failed: %s (0x%08x)", std::system_category().message(hr), static_cast<u32>(hr));
}
}
}
void XAudio2Backend::OnCriticalError(HRESULT Error)
{
XAudio.error("OnCriticalError() called: %s (0x%08x)", std::system_category().message(Error), static_cast<u32>(Error));
m_reset_req = true;
}
+47 -15
View File
@@ -4,19 +4,16 @@
#error "XAudio2 can only be built on Windows."
#endif
#include <memory>
#include "Utilities/mutex.h"
#include "Emu/Audio/AudioBackend.h"
#include "Emu/Audio/audio_device_listener.h"
#include <xaudio2redist.h>
#include <wrl/client.h>
class XAudio2Backend final : public AudioBackend
class XAudio2Backend final : public AudioBackend, public IXAudio2VoiceCallback, public IXAudio2EngineCallback
{
private:
Microsoft::WRL::ComPtr<IXAudio2> m_xaudio2_instance{};
IXAudio2MasteringVoice* m_master_voice{};
IXAudio2SourceVoice* m_source_voice{};
public:
XAudio2Backend();
~XAudio2Backend() override;
@@ -24,23 +21,58 @@ public:
XAudio2Backend(const XAudio2Backend&) = delete;
XAudio2Backend& operator=(const XAudio2Backend&) = delete;
const char* GetName() const override { return "XAudio2"; }
std::string_view GetName() const override { return "XAudio2"sv; }
static const u32 capabilities = PLAY_PAUSE_FLUSH | IS_PLAYING | GET_NUM_ENQUEUED_SAMPLES | SET_FREQUENCY_RATIO;
static const u32 capabilities = SET_FREQUENCY_RATIO;
u32 GetCapabilities() const override { return capabilities; }
bool Initialized() const override { return m_xaudio2_instance != nullptr; }
bool Initialized() override;
bool Operational() override;
void Open(u32 /* num_buffers */) override;
void Open(AudioFreq freq, AudioSampleSize sample_size, AudioChannelCnt ch_cnt) override;
void Close() override;
void SetWriteCallback(std::function<u32(u32, void *)> cb) override;
f64 GetCallbackFrameLen() override;
void Play() override;
void Pause() override;
bool IsPlaying() override;
bool AddData(const void* src, u32 num_samples) override;
void Flush() override;
u64 GetNumEnqueuedSamples() override;
f32 SetFrequencyRatio(f32 new_ratio) override;
private:
static constexpr u32 INTERNAL_BUF_SIZE_MS = 25;
Microsoft::WRL::ComPtr<IXAudio2> m_xaudio2_instance{};
IXAudio2MasteringVoice* m_master_voice{};
IXAudio2SourceVoice* m_source_voice{};
bool m_com_init_success = false;
shared_mutex m_cb_mutex{};
std::function<u32(u32, void *)> m_write_callback{};
std::unique_ptr<u8[]> m_data_buf{};
u64 m_data_buf_len = 0;
u8 m_last_sample[sizeof(float) * static_cast<u32>(AudioChannelCnt::SURROUND_7_1)]{};
bool m_playing = false;
atomic_t<bool> m_reset_req = false;
audio_device_listener m_dev_listener{};
// XAudio voice callbacks
void OnVoiceProcessingPassStart(UINT32 BytesRequired) override;
void OnVoiceProcessingPassEnd() override {}
void OnStreamEnd() override {}
void OnBufferStart(void* /* pBufferContext */) override {}
void OnBufferEnd(void* /* pBufferContext*/) override {}
void OnLoopEnd(void* /* pBufferContext */) override {}
void OnVoiceError(void* /* pBufferContext */, HRESULT /* Error */) override {}
// XAudio engine callbacks
void OnProcessingPassStart() override {};
void OnProcessingPassEnd() override {};
void OnCriticalError(HRESULT Error) override;
void CloseUnlocked();
};
+52 -12
View File
@@ -10,15 +10,26 @@ LOG_CHANNEL(IO);
audio_device_listener::audio_device_listener()
{
#ifdef _WIN32
HRESULT hr = CoInitializeEx(nullptr, COINIT_MULTITHREADED);
if (SUCCEEDED(hr))
{
m_com_init_success = true;
}
// Try to register a listener for device changes
HRESULT hr = CoCreateInstance(__uuidof(MMDeviceEnumerator), nullptr, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&m_device_enumerator));
hr = CoCreateInstance(__uuidof(MMDeviceEnumerator), nullptr, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&m_device_enumerator));
if (hr != S_OK)
{
IO.error("CoCreateInstance() failed: %s (0x%08x)", std::system_category().message(hr), static_cast<u32>(hr));
}
else if (m_device_enumerator)
{
m_device_enumerator->RegisterEndpointNotificationCallback(&m_listener);
hr = m_device_enumerator->RegisterEndpointNotificationCallback(this);
if (FAILED(hr))
{
IO.error("RegisterEndpointNotificationCallback() failed: %s (0x%08x)", std::system_category().message(hr), static_cast<u32>(hr));
m_device_enumerator->Release();
}
}
else
{
@@ -32,11 +43,27 @@ audio_device_listener::~audio_device_listener()
#ifdef _WIN32
if (m_device_enumerator != nullptr)
{
m_device_enumerator->UnregisterEndpointNotificationCallback(this);
m_device_enumerator->Release();
}
if (m_com_init_success)
{
CoUninitialize();
}
#endif
}
bool audio_device_listener::input_device_changed()
{
return m_input_device_changed.test_and_reset();
}
bool audio_device_listener::output_device_changed()
{
return m_output_device_changed.test_and_reset();
}
#ifdef _WIN32
template <>
void fmt_class_string<ERole>::format(std::string& out, u64 arg)
@@ -70,7 +97,7 @@ void fmt_class_string<EDataFlow>::format(std::string& out, u64 arg)
});
}
HRESULT audio_device_listener::listener::OnDefaultDeviceChanged(EDataFlow flow, ERole role, LPCWSTR new_default_device_id)
HRESULT audio_device_listener::OnDefaultDeviceChanged(EDataFlow flow, ERole role, LPCWSTR new_default_device_id)
{
IO.notice("OnDefaultDeviceChanged(flow=%s, role=%s, new_default_device_id=0x%x)", flow, role, new_default_device_id);
@@ -80,8 +107,9 @@ HRESULT audio_device_listener::listener::OnDefaultDeviceChanged(EDataFlow flow,
return S_OK;
}
// Only listen for console and communication device changes.
if ((role != eConsole && role != eCommunications) || (flow != eRender && flow != eCapture))
// Listen only for one device role, otherwise we're going to receive more than one
// notification for flow type
if (role != eConsole)
{
IO.notice("OnDefaultDeviceChanged(): we don't care about this device");
return S_OK;
@@ -90,15 +118,27 @@ HRESULT audio_device_listener::listener::OnDefaultDeviceChanged(EDataFlow flow,
const std::wstring tmp(new_default_device_id);
const std::string new_device_id = wchar_to_utf8(tmp.c_str());
if (device_id != new_device_id)
if (flow == eRender || flow == eAll)
{
device_id = new_device_id;
IO.warning("Default device changed: new device = '%s'", device_id);
if (auto& g_audio = g_fxo->get<cell_audio>(); g_fxo->is_init<cell_audio>())
if (output_device_id != new_device_id)
{
g_audio.m_update_configuration = true;
output_device_id = new_device_id;
IO.warning("Default output device changed: new device = '%s'", output_device_id);
m_output_device_changed = true;
}
}
if (flow == eCapture || flow == eAll)
{
if (input_device_id != new_device_id)
{
input_device_id = new_device_id;
IO.warning("Default input device changed: new device = '%s'", input_device_id);
m_input_device_changed = true;
}
}
+23 -12
View File
@@ -4,28 +4,39 @@
#include <MMDeviceAPI.h>
#endif
#include "util/atomic.hpp"
#ifdef _WIN32
class audio_device_listener : public IMMNotificationClient
#else
class audio_device_listener
#endif
{
public:
audio_device_listener();
~audio_device_listener();
bool input_device_changed();
bool output_device_changed();
private:
#ifdef _WIN32
struct listener : public IMMNotificationClient
{
std::string device_id;
std::string input_device_id;
std::string output_device_id;
IFACEMETHODIMP_(ULONG) AddRef() override { return 1; };
IFACEMETHODIMP_(ULONG) Release() override { return 1; };
IFACEMETHODIMP QueryInterface(REFIID /*iid*/, void** /*object*/) override { return S_OK; };
IFACEMETHODIMP OnPropertyValueChanged(LPCWSTR /*device_id*/, const PROPERTYKEY /*key*/) override { return S_OK; };
IFACEMETHODIMP OnDeviceAdded(LPCWSTR /*device_id*/) override { return S_OK; };
IFACEMETHODIMP OnDeviceRemoved(LPCWSTR /*device_id*/) override { return S_OK; };
IFACEMETHODIMP OnDeviceStateChanged(LPCWSTR /*device_id*/, DWORD /*new_state*/) override { return S_OK; };
IFACEMETHODIMP OnDefaultDeviceChanged(EDataFlow flow, ERole role, LPCWSTR new_default_device_id) override;
} m_listener;
IFACEMETHODIMP_(ULONG) AddRef() override { return 1; };
IFACEMETHODIMP_(ULONG) Release() override { return 1; };
IFACEMETHODIMP QueryInterface(REFIID /*iid*/, void** /*object*/) override { return S_OK; };
IFACEMETHODIMP OnPropertyValueChanged(LPCWSTR /*device_id*/, const PROPERTYKEY /*key*/) override { return S_OK; };
IFACEMETHODIMP OnDeviceAdded(LPCWSTR /*device_id*/) override { return S_OK; };
IFACEMETHODIMP OnDeviceRemoved(LPCWSTR /*device_id*/) override { return S_OK; };
IFACEMETHODIMP OnDeviceStateChanged(LPCWSTR /*device_id*/, DWORD /*new_state*/) override { return S_OK; };
IFACEMETHODIMP OnDefaultDeviceChanged(EDataFlow flow, ERole role, LPCWSTR new_default_device_id) override;
IMMDeviceEnumerator* m_device_enumerator = nullptr;
bool m_com_init_success = false;
#endif
atomic_t<bool> m_input_device_changed = false;
atomic_t<bool> m_output_device_changed = false;
};
+13 -15
View File
@@ -1,4 +1,4 @@
add_library(rpcs3_emu
add_library(rpcs3_emu
cache_utils.cpp
IdManager.cpp
localized_string.cpp
@@ -54,6 +54,7 @@ target_sources(rpcs3_emu PRIVATE
../../Utilities/mutex.cpp
../../Utilities/rXml.cpp
../../Utilities/sema.cpp
../../Utilities/simple_ringbuf.cpp
../../Utilities/StrFmt.cpp
../../Utilities/Thread.cpp
../../Utilities/version.cpp
@@ -110,22 +111,9 @@ target_sources(rpcs3_emu PRIVATE
Audio/audio_device_listener.cpp
Audio/AudioDumper.cpp
Audio/AudioBackend.cpp
Audio/AL/OpenALBackend.cpp
Audio/Cubeb/CubebBackend.cpp
)
if(USE_ALSA)
find_package(ALSA)
if(ALSA_FOUND)
target_sources(rpcs3_emu PRIVATE Audio/ALSA/ALSABackend.cpp)
target_link_libraries(rpcs3_emu PUBLIC 3rdparty::alsa)
endif()
endif()
if(USE_PULSE AND PULSE_FOUND)
target_sources(rpcs3_emu PRIVATE Audio/Pulse/PulseBackend.cpp)
target_link_libraries(rpcs3_emu PUBLIC 3rdparty::pulse)
endif()
if(USE_FAUDIO)
find_package(SDL2)
if(SDL2_FOUND AND NOT SDL2_VERSION VERSION_LESS 2.0.9)
@@ -147,6 +135,9 @@ target_link_libraries(rpcs3_emu
PUBLIC
3rdparty::openal)
target_link_libraries(rpcs3_emu
PUBLIC
3rdparty::cubeb)
# Cell
target_sources(rpcs3_emu PRIVATE
@@ -370,13 +361,19 @@ target_sources(rpcs3_emu PRIVATE
Io/GHLtar.cpp
Io/Buzz.cpp
Io/Turntable.cpp
Io/usio.cpp
)
# Np
target_sources(rpcs3_emu PRIVATE
NP/fb_helpers.cpp
NP/np_cache.cpp
NP/np_contexts.cpp
NP/np_dnshook.cpp
NP/np_handler.cpp
NP/np_helpers.cpp
NP/np_notifications.cpp
NP/np_requests.cpp
NP/signaling_handler.cpp
NP/np_structs_extra.cpp
NP/rpcn_client.cpp
@@ -396,6 +393,7 @@ target_sources(rpcs3_emu PRIVATE
RSX/GSRender.cpp
RSX/RSXFIFO.cpp
RSX/rsx_methods.cpp
RSX/rsx_vertex_data.cpp
RSX/RSXOffload.cpp
RSX/RSXTexture.cpp
RSX/RSXThread.cpp
+26 -12
View File
@@ -85,29 +85,35 @@ void cpu_translator::initialize(llvm::LLVMContext& context, llvm::ExecutionEngin
m_use_ssse3 = false;
}
// Test AVX feature (TODO)
if (cpu == "sandybridge" ||
cpu == "ivybridge" ||
cpu == "bdver1")
{
m_use_avx = true;
}
// Test FMA feature (TODO)
if (cpu == "haswell" ||
cpu == "broadwell" ||
cpu == "skylake" ||
cpu == "alderlake" ||
cpu == "bdver2" ||
cpu == "bdver3" ||
cpu == "bdver4" ||
cpu.startswith("znver"))
{
m_use_fma = true;
m_use_avx = true;
}
// Test AVX-512 feature (TODO)
if (cpu == "skylake-avx512" ||
cpu == "cascadelake" ||
cpu == "cannonlake" ||
cpu == "cooperlake" ||
cpu == "icelake" ||
cpu == "icelake-client" ||
cpu == "icelake-server" ||
cpu == "tigerlake" ||
cpu == "rocketlake")
cpu == "cooperlake")
{
m_use_avx = true;
m_use_fma = true;
m_use_avx512 = true;
}
@@ -128,6 +134,9 @@ void cpu_translator::initialize(llvm::LLVMContext& context, llvm::ExecutionEngin
cpu == "rocketlake" ||
cpu == "sapphirerapids")
{
m_use_avx = true;
m_use_fma = true;
m_use_avx512 = true;
m_use_avx512_icl = true;
m_use_vnni = true;
}
@@ -139,9 +148,9 @@ llvm::Value* cpu_translator::bitcast(llvm::Value* val, llvm::Type* type) const
uint s2 = val->getType()->getScalarSizeInBits();
if (type->isVectorTy())
s1 *= llvm::cast<llvm::VectorType>(type)->getNumElements();
s1 *= llvm::cast<llvm::FixedVectorType>(type)->getNumElements();
if (val->getType()->isVectorTy())
s2 *= llvm::cast<llvm::VectorType>(val->getType())->getNumElements();
s2 *= llvm::cast<llvm::FixedVectorType>(val->getType())->getNumElements();
if (s1 != s2)
{
@@ -183,7 +192,7 @@ std::pair<bool, v128> cpu_translator::get_const_vector<v128>(llvm::Value* c, u32
fmt::throw_exception("[0x%x, %u] Not a vector", _pos, _line);
}
if (auto v = llvm::cast<llvm::VectorType>(t); v->getScalarSizeInBits() * v->getNumElements() != 128)
if (auto v = llvm::cast<llvm::FixedVectorType>(t); v->getScalarSizeInBits() * v->getNumElements() != 128)
{
fmt::throw_exception("[0x%x, %u] Bad vector size: i%ux%u", _pos, _line, v->getScalarSizeInBits(), v->getNumElements());
}
@@ -197,13 +206,18 @@ std::pair<bool, v128> cpu_translator::get_const_vector<v128>(llvm::Value* c, u32
return {};
}
std::string result;
llvm::raw_string_ostream out(result);
c->print(out, true);
out.flush();
if (llvm::isa<llvm::ConstantExpr>(c))
{
// Sorry, if we cannot evaluate it we cannot use it
fmt::throw_exception("[0x%x, %u] Constant Expression!", _pos, _line);
fmt::throw_exception("[0x%x, %u] Constant Expression!\n%s", _pos, _line, result);
}
fmt::throw_exception("[0x%x, %u] Unexpected constant type", _pos, _line);
fmt::throw_exception("[0x%x, %u] Unexpected constant type!\n%s", _pos, _line, result);
}
const auto sct = t->getScalarType();
@@ -267,7 +281,7 @@ llvm::Constant* cpu_translator::make_const_vector<v128>(v128 v, llvm::Type* t, u
}
ensure(t->isVectorTy());
ensure(128 == t->getScalarSizeInBits() * llvm::cast<llvm::VectorType>(t)->getNumElements());
ensure(128 == t->getScalarSizeInBits() * llvm::cast<llvm::FixedVectorType>(t)->getNumElements());
const auto sct = t->getScalarType();
+50 -6
View File
@@ -15,6 +15,7 @@
#pragma GCC diagnostic ignored "-Wmissing-noreturn"
#endif
#include "llvm/IR/LLVMContext.h"
#include "llvm/ExecutionEngine/ExecutionEngine.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/Module.h"
#include "llvm/Target/TargetMachine.h"
@@ -43,6 +44,18 @@ enum class i4 : char
{
};
template <typename T>
concept LLVMType = (std::is_pointer_v<T>) && (std::is_base_of_v<llvm::Type, std::remove_pointer_t<T>>);
template <typename T>
concept LLVMValue = (std::is_pointer_v<T>) && (std::is_base_of_v<llvm::Value, std::remove_pointer_t<T>>);
template <typename T>
concept DSLValue = requires (T& v)
{
{ v.eval(std::declval<llvm::IRBuilder<>*>()) } -> LLVMValue;
};
template <typename T = void>
struct llvm_value_t
{
@@ -2886,6 +2899,9 @@ protected:
// Allow FMA
bool m_use_fma = false;
// Allow AVX
bool m_use_avx = false;
// Allow skylake-x tier AVX-512
bool m_use_avx512 = false;
@@ -2945,7 +2961,7 @@ public:
}
// Call external function: provide name and function pointer
template <typename RT, typename... FArgs, typename... Args>
template <typename RT, typename... FArgs, LLVMValue... Args>
llvm::CallInst* call(std::string_view lame, RT(*_func)(FArgs...), Args... args)
{
static_assert(sizeof...(FArgs) == sizeof...(Args), "spu_llvm_recompiler::call(): unexpected arg number");
@@ -2963,6 +2979,22 @@ public:
return inst;
}
template <typename RT, typename... FArgs, DSLValue... Args> requires (sizeof...(Args) != 0)
auto call(std::string_view name, RT(*_func)(FArgs...), Args&&... args)
{
llvm_value_t<RT> r;
r.value = call(name, _func, std::forward<Args>(args).eval(m_ir)...);
return r;
}
template <typename RT, DSLValue... Args>
auto call(llvm::Function* func, Args&&... args)
{
llvm_value_t<RT> r;
r.value = m_ir->CreateCall(func, {std::forward<Args>(args).eval(m_ir)...});
return r;
}
// Bitcast with immediate constant folding
llvm::Value* bitcast(llvm::Value* val, llvm::Type* type) const;
@@ -3493,10 +3525,10 @@ public:
shuffle.value = m_ir->CreateZExt(shuffle.value, get_type<u32[32]>());
intermediate.value = m_ir->CreateShuffleVector(data0, data1, shuffle.value);
// expand the shuffle index to 256 bits with zeroes
// expand the shuffle index to 256 bits with zeroes
shuffleindex.value = m_ir->CreateShuffleVector(index, zeroes, shuffle.value);
// permute
// permute
intermediate.value = m_ir->CreateCall(get_intrinsic(llvm::Intrinsic::x86_avx512_permvar_qi_256), {intermediate.value, shuffleindex.value});
// convert the 256 bit vector back to 128 bits
@@ -3654,10 +3686,22 @@ struct fmt_unveil<llvm::TypeSize, void>
#endif
template <>
inline llvm::Type* cpu_translator::get_type<__m128i>()
struct llvm_value_t<__m128> : llvm_value_t<f32[4]>
{
return llvm::VectorType::get(llvm::Type::getInt8Ty(m_context), 16, false);
}
};
template <>
struct llvm_value_t<__m128d> : llvm_value_t<f64[2]>
{
};
template <>
struct llvm_value_t<__m128i> : llvm_value_t<u8[16]>
{
};
#ifndef _MSC_VER
#pragma GCC diagnostic pop
+153 -107
View File
@@ -47,24 +47,50 @@ void fmt_class_string<CellAudioError>::format(std::string& out, u64 arg)
cell_audio_config::cell_audio_config()
{
raw = audio::get_raw_config();
reset();
}
void cell_audio_config::reset()
void cell_audio_config::reset(bool backend_changed)
{
backend.reset();
backend = Emu.GetCallbacks().get_audio();
if (!backend || backend_changed)
{
backend.reset();
backend = Emu.GetCallbacks().get_audio();
}
{
std::string str;
backend->dump_capabilities(str);
cellAudio.notice("cellAudio initializing. Backend: %s, Capabilities: %s", backend->GetName(), str.c_str());
}
const AudioFreq freq = AudioFreq::FREQ_48K;
const AudioSampleSize sample_size = raw.convert_to_s16 ? AudioSampleSize::S16 : AudioSampleSize::FLOAT;
const AudioChannelCnt ch_cnt = [&]()
{
switch (raw.downmix)
{
case audio_downmix::no_downmix: return AudioChannelCnt::SURROUND_7_1;
case audio_downmix::downmix_to_5_1: return AudioChannelCnt::SURROUND_5_1;
case audio_downmix::downmix_to_stereo: return AudioChannelCnt::STEREO;
case audio_downmix::use_application_settings: return AudioChannelCnt::STEREO; // TODO
default:
fmt::throw_exception("Unknown audio channel mode %s (%d)", raw.downmix, static_cast<int>(raw.downmix));
}
}();
backend->Open(freq, sample_size, ch_cnt);
audio_channels = backend->get_channels();
audio_sampling_rate = backend->get_sampling_rate();
audio_block_period = AUDIO_BUFFER_SAMPLES * 1000000 / audio_sampling_rate;
audio_sample_size = backend->get_sample_size();
audio_min_buffer_duration = backend->GetCallbackFrameLen();
audio_buffer_length = AUDIO_BUFFER_SAMPLES * audio_channels;
audio_buffer_size = audio_buffer_length * backend->get_sample_size();
audio_buffer_size = audio_buffer_length * audio_sample_size;
desired_buffer_duration = raw.desired_buffer_duration * 1000llu;
buffering_enabled = raw.buffering_enabled && backend->has_capability(AudioBackend::PLAY_PAUSE_FLUSH | AudioBackend::IS_PLAYING);
buffering_enabled = raw.buffering_enabled && raw.renderer != audio_renderer::null;
minimum_block_period = audio_block_period / 2;
maximum_block_period = (6 * audio_block_period) / 5;
@@ -92,7 +118,6 @@ void cell_audio_config::reset()
}
}
audio_ringbuffer::audio_ringbuffer(cell_audio_config& _cfg)
: backend(_cfg.backend)
, cfg(_cfg)
@@ -113,32 +138,29 @@ audio_ringbuffer::audio_ringbuffer(cell_audio_config& _cfg)
// Init audio dumper if enabled
if (g_cfg.audio.dump_to_file)
{
m_dump.reset(new AudioDumper(cfg.audio_channels));
m_dump.reset(new AudioDumper(cfg.audio_channels, cfg.audio_sampling_rate, cfg.audio_sample_size));
}
// Initialize backend
const f64 buffer_dur_mult = [&]()
{
std::string str;
backend->dump_capabilities(str);
cellAudio.notice("cellAudio initializing. Backend: %s, Capabilities: %s", backend->GetName(), str.c_str());
}
const f64 min_buf_dur = _cfg.audio_min_buffer_duration + 0.01; // Add 10ms to allow jitter compensation
if (cfg.raw.buffering_enabled)
{
return std::max<f64>(min_buf_dur, cfg.raw.desired_buffer_duration / 1000.0 * 2); // Allocate 2x buffer to keep buffering algorithm happy
}
backend->Open(cfg.num_allocated_buffers);
backend_open = true;
return min_buf_dur;
}();
ensure(!get_backend_playing());
cb_ringbuf.set_buf_size(static_cast<u32>(_cfg.audio_channels * _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));
}
audio_ringbuffer::~audio_ringbuffer()
{
if (!backend_open)
if (get_backend_playing())
{
return;
}
if (get_backend_playing() && has_capability(AudioBackend::PLAY_PAUSE_FLUSH))
{
backend->Pause();
flush();
}
backend->Close();
@@ -159,6 +181,13 @@ f32 audio_ringbuffer::set_frequency_ratio(f32 new_ratio)
return frequency_ratio;
}
u32 audio_ringbuffer::backend_write_callback(u32 size, void *buf)
{
if (!backend_active.observe()) backend_active = true;
return cb_ringbuf.pop(buf, size);
}
u64 audio_ringbuffer::get_timestamp()
{
return get_system_time();
@@ -183,28 +212,28 @@ void audio_ringbuffer::enqueue(const float* in_buffer)
m_dump->WriteData(buf, cfg.audio_buffer_size);
}
// Enqueue audio
const bool success = backend->AddData(buf, AUDIO_BUFFER_SAMPLES * cfg.audio_channels);
if (!success)
enqueued_samples += AUDIO_BUFFER_SAMPLES;
// Start playing audio
play();
if (!backend_active.observe())
{
cellAudio.warning("Could not enqueue buffer onto audio backend. Attempting to recover...");
flush();
// backend is not ready yet
return;
}
if (has_capability(AudioBackend::PLAY_PAUSE_FLUSH))
{
enqueued_samples += AUDIO_BUFFER_SAMPLES;
// Enqueue audio
const u32 data_size = AUDIO_BUFFER_SAMPLES * cfg.audio_sample_size * cfg.audio_channels;
// Start playing audio
play();
if (cb_ringbuf.get_free_size() >= data_size)
{
cb_ringbuf.push(buf, data_size);
}
}
void audio_ringbuffer::enqueue_silence(u32 buf_count)
{
AUDIT(has_capability(AudioBackend::PLAY_PAUSE_FLUSH));
for (u32 i = 0; i < buf_count; i++)
{
enqueue(silence_buffer);
@@ -213,13 +242,7 @@ void audio_ringbuffer::enqueue_silence(u32 buf_count)
void audio_ringbuffer::play()
{
if (!has_capability(AudioBackend::PLAY_PAUSE_FLUSH))
{
playing = true;
return;
}
if (playing && has_capability(AudioBackend::IS_PLAYING))
if (playing)
{
return;
}
@@ -239,19 +262,12 @@ void audio_ringbuffer::play()
void audio_ringbuffer::flush()
{
if (!has_capability(AudioBackend::PLAY_PAUSE_FLUSH))
{
playing = false;
return;
}
//cellAudio.trace("Flushing an estimated %llu enqueued samples", enqueued_samples);
backend->Pause();
cb_ringbuf.flush();
playing = false;
backend->Flush();
if (frequency_ratio != 1.0f)
{
set_frequency_ratio(1.0f);
@@ -266,16 +282,16 @@ u64 audio_ringbuffer::update()
if (Emu.IsPaused())
{
// Emulator paused
if (playing && has_capability(AudioBackend::PLAY_PAUSE_FLUSH))
if (playing)
{
backend->Pause();
flush();
}
emu_paused = true;
}
else if (emu_paused)
{
// Emulator unpaused
if (enqueued_samples > 0 && has_capability(AudioBackend::PLAY_PAUSE_FLUSH))
if (enqueued_samples > 0)
{
play();
}
@@ -289,37 +305,7 @@ u64 audio_ringbuffer::update()
// Calculate how many audio samples have played since last time
if (cfg.buffering_enabled && (playing || new_playing))
{
if (has_capability(AudioBackend::GET_NUM_ENQUEUED_SAMPLES))
{
// Backend supports querying for the remaining playtime, so just ask it
enqueued_samples = backend->GetNumEnqueuedSamples();
}
else
{
const u64 play_delta = (update_timestamp ? timestamp - std::max<u64>(play_timestamp, update_timestamp) : 0);
const u64 delta_samples_tmp = play_delta * static_cast<u64>(cfg.audio_sampling_rate * frequency_ratio) + last_remainder;
last_remainder = delta_samples_tmp % 1'000'000;
const u64 delta_samples = delta_samples_tmp / 1'000'000;
//cellAudio.error("play_delta=%llu delta_samples=%llu", play_delta, delta_samples);
if (delta_samples > 0)
{
if (enqueued_samples < delta_samples)
{
enqueued_samples = 0;
}
else
{
enqueued_samples -= delta_samples;
}
if (enqueued_samples == 0)
{
cellAudio.trace("Audio buffer about to underrun!");
}
}
}
enqueued_samples = cb_ringbuf.get_used_size() / cfg.audio_sample_size;
}
// Update playing state
@@ -549,16 +535,20 @@ namespace audio
.desired_buffer_duration = g_cfg.audio.desired_buffer_duration,
.enable_time_stretching = static_cast<bool>(g_cfg.audio.enable_time_stretching),
.time_stretching_threshold = g_cfg.audio.time_stretching_threshold,
.convert_to_u16 = static_cast<bool>(g_cfg.audio.convert_to_u16),
.start_threshold = static_cast<u32>(g_cfg.audio.start_threshold),
.sampling_period_multiplier = static_cast<u32>(g_cfg.audio.sampling_period_multiplier),
.convert_to_s16 = static_cast<bool>(g_cfg.audio.convert_to_s16),
.downmix = g_cfg.audio.audio_channel_downmix,
.renderer = g_cfg.audio.renderer
.renderer = g_cfg.audio.renderer,
.provider = g_cfg.audio.provider
};
}
void configure_audio()
{
if (g_cfg.audio.provider != audio_provider::cell_audio)
{
return;
}
if (auto& g_audio = g_fxo->get<cell_audio>(); g_fxo->is_init<cell_audio>())
{
// Only reboot the audio renderer if a relevant setting changed
@@ -569,20 +559,18 @@ namespace audio
raw.buffering_enabled != new_raw.buffering_enabled ||
raw.time_stretching_threshold != new_raw.time_stretching_threshold ||
raw.enable_time_stretching != new_raw.enable_time_stretching ||
raw.convert_to_u16 != new_raw.convert_to_u16 ||
raw.start_threshold != new_raw.start_threshold ||
raw.sampling_period_multiplier != new_raw.sampling_period_multiplier ||
raw.convert_to_s16 != new_raw.convert_to_s16 ||
raw.downmix != new_raw.downmix ||
raw.renderer != new_raw.renderer)
{
g_audio.cfg.raw = new_raw;
g_audio.m_update_configuration = true;
g_audio.m_update_configuration = raw.renderer != new_raw.renderer ? audio_backend_update::ALL : audio_backend_update::PARAM;
}
}
}
}
void cell_audio_thread::update_config()
void cell_audio_thread::update_config(bool backend_changed)
{
std::lock_guard lock(mutex);
@@ -590,36 +578,81 @@ void cell_audio_thread::update_config()
ringbuffer.reset();
// Reload config
cfg.reset();
cfg.reset(backend_changed);
// Allocate ringbuffer
ringbuffer.reset(new audio_ringbuffer(cfg));
// Reset thread state
reset_counters();
}
void cell_audio_thread::operator()()
void cell_audio_thread::reset_counters()
{
thread_ctrl::scoped_priority high_prio(+1);
m_counter = 0;
m_start_time = ringbuffer->get_timestamp();
m_last_period_end = m_start_time;
m_dynamic_period = 0;
m_backend_failed = false;
}
cell_audio_thread::cell_audio_thread()
{
if (cfg.raw.provider != audio_provider::cell_audio)
{
return;
}
// Init audio config
cfg.reset();
// Allocate ringbuffer
ringbuffer.reset(new audio_ringbuffer(cfg));
// Initialize loop variables
m_counter = 0;
m_start_time = ringbuffer->get_timestamp();
m_last_period_end = m_start_time;
m_dynamic_period = 0;
reset_counters();
}
void cell_audio_thread::operator()()
{
if (cfg.raw.provider != audio_provider::cell_audio)
{
return;
}
thread_ctrl::scoped_priority high_prio(+1);
u32 untouched_expected = 0;
//u32 in_progress_expected = 0;
// Main cellAudio loop
while (thread_ctrl::state() != thread_state::aborting)
{
if (m_update_configuration)
const auto update_req = m_update_configuration.observe();
if (update_req != audio_backend_update::NONE)
{
cellAudio.warning("Updating cell_audio_thread configuration");
update_config();
m_update_configuration = false;
update_config(update_req == audio_backend_update::ALL);
m_update_configuration = audio_backend_update::NONE;
}
if (!ringbuffer->get_operational_status())
{
cellAudio.warning("Backend stopped unexpectedly (likely device change). Attempting to recover...");
if (m_backend_failed)
{
thread_ctrl::wait_for(500 * 1000);
}
update_config(true);
m_backend_failed = true;
continue;
}
if (m_backend_failed)
{
cellAudio.warning("Backend recovered");
m_backend_failed = false;
}
const u64 timestamp = ringbuffer->update();
@@ -872,6 +905,19 @@ void cell_audio_thread::operator()()
ringbuffer.reset();
}
audio_port* cell_audio_thread::open_port()
{
for (u32 i = 0; i < AUDIO_PORT_COUNT; i++)
{
if (ports[i].state.compare_and_swap_test(audio_port_state::closed, audio_port_state::opened))
{
return &ports[i];
}
}
return nullptr;
}
template <audio_downmix downmix>
void cell_audio_thread::mix(float *out_buffer, s32 offset)
{
@@ -1063,9 +1109,9 @@ void cell_audio_thread::mix(float *out_buffer, s32 offset)
{
std::memset(out_buffer, 0, out_buffer_sz * sizeof(float));
}
else if (cfg.backend->get_convert_to_u16())
else if (cfg.backend->get_convert_to_s16())
{
// convert the data from float to u16 with clipping:
// convert the data from float to s16 with clipping:
// 2x MULPS
// 2x MAXPS (optional)
// 2x MINPS (optional)
+32 -27
View File
@@ -2,8 +2,8 @@
#include "Emu/Memory/vm_ptr.h"
#include "Utilities/Thread.h"
#include "Utilities/simple_ringbuf.h"
#include "Emu/Memory/vm.h"
#include "Emu/Audio/audio_device_listener.h"
#include "Emu/Audio/AudioBackend.h"
#include "Emu/Audio/AudioDumper.h"
#include "Emu/system_config_types.h"
@@ -73,6 +73,13 @@ enum
CELL_AUDIO_STATUS_RUN = 2,
};
enum class audio_backend_update : u32
{
NONE,
PARAM,
ALL,
};
//libaudio datatypes
struct CellAudioPortParam
{
@@ -196,11 +203,10 @@ struct cell_audio_config
s64 desired_buffer_duration = 0;
bool enable_time_stretching = false;
s64 time_stretching_threshold = 0;
bool convert_to_u16 = false;
u32 start_threshold = 0;
u32 sampling_period_multiplier = 0;
bool convert_to_s16 = false;
audio_downmix downmix = audio_downmix::downmix_to_stereo;
audio_renderer renderer = audio_renderer::null;
audio_provider provider = audio_provider::none;
} raw;
std::shared_ptr<AudioBackend> backend = nullptr;
@@ -208,6 +214,8 @@ struct cell_audio_config
u32 audio_channels = 0;
u32 audio_sampling_rate = 0;
u32 audio_block_period = 0;
u32 audio_sample_size = 0;
f64 audio_min_buffer_duration = 0.0;
u32 audio_buffer_length = 0;
u32 audio_buffer_size = 0;
@@ -254,7 +262,7 @@ struct cell_audio_config
/*
* Config changes
*/
void reset();
void reset(bool backend_changed = true);
};
class audio_ringbuffer
@@ -271,7 +279,9 @@ private:
std::unique_ptr<float[]> buffer[MAX_AUDIO_BUFFERS];
const float silence_buffer[u32{AUDIO_MAX_CHANNELS_COUNT} * u32{AUDIO_BUFFER_SAMPLES}] = { 0 };
bool backend_open = false;
simple_ringbuf cb_ringbuf{};
atomic_t<bool> backend_active = false;
bool playing = false;
bool emu_paused = false;
@@ -287,9 +297,11 @@ private:
bool get_backend_playing() const
{
return has_capability(AudioBackend::PLAY_PAUSE_FLUSH | AudioBackend::IS_PLAYING) ? backend->IsPlaying() : playing;
return backend->IsPlaying();
}
u32 backend_write_callback(u32 size, void *buf);
public:
audio_ringbuffer(cell_audio_config &cfg);
~audio_ringbuffer();
@@ -343,7 +355,12 @@ public:
return backend->has_capability(cap);
}
const char* get_backend_name() const
bool get_operational_status() const
{
return backend->Operational();
}
std::string_view get_backend_name() const
{
return backend->GetName();
}
@@ -354,7 +371,6 @@ class cell_audio_thread
{
private:
std::unique_ptr<audio_ringbuffer> ringbuffer;
audio_device_listener listener;
void reset_ports(s32 offset = 0);
void advance(u64 timestamp, bool reset = true);
@@ -368,11 +384,12 @@ private:
return (time_left > 350) ? time_left - 250 : 100;
}
void update_config();
void update_config(bool backend_changed);
void reset_counters();
public:
cell_audio_config cfg;
atomic_t<bool> m_update_configuration = false;
atomic_t<audio_backend_update> m_update_configuration = audio_backend_update::NONE;
shared_mutex mutex;
atomic_t<u32> init = 0;
@@ -396,25 +413,13 @@ public:
u64 m_start_time = 0;
u64 m_dynamic_period = 0;
f32 m_average_playtime = 0.0f;
bool m_backend_failed = false;
cell_audio_thread();
void operator()();
cell_audio_thread()
{
}
audio_port* open_port()
{
for (u32 i = 0; i < AUDIO_PORT_COUNT; i++)
{
if (ports[i].state.compare_and_swap_test(audio_port_state::closed, audio_port_state::opened))
{
return &ports[i];
}
}
return nullptr;
}
audio_port* open_port();
bool has_capability(u32 cap) const
{
+11 -1
View File
@@ -201,12 +201,17 @@ error_code cellVideoOutGetGamma(u32 videoOut, vm::ptr<f32> gamma)
{
cellAvconfExt.warning("cellVideoOutGetGamma(videoOut=%d, gamma=*0x%x)", videoOut, gamma);
if (!gamma)
{
return CELL_VIDEO_OUT_ERROR_ILLEGAL_PARAMETER;
}
if (videoOut != CELL_VIDEO_OUT_PRIMARY)
{
return CELL_VIDEO_OUT_ERROR_UNSUPPORTED_VIDEO_OUT;
}
auto& conf = g_fxo->get<rsx::avconf>();
const auto& conf = g_fxo->get<rsx::avconf>();
*gamma = conf.gamma;
@@ -301,6 +306,11 @@ error_code cellVideoOutGetScreenSize(u32 videoOut, vm::ptr<f32> screenSize)
{
cellAvconfExt.warning("cellVideoOutGetScreenSize(videoOut=%d, screenSize=*0x%x)", videoOut, screenSize);
if (!screenSize)
{
return CELL_VIDEO_OUT_ERROR_ILLEGAL_PARAMETER;
}
if (videoOut != CELL_VIDEO_OUT_PRIMARY)
{
return CELL_VIDEO_OUT_ERROR_UNSUPPORTED_VIDEO_OUT;
+9
View File
@@ -433,6 +433,15 @@ error_code cellCameraInit()
g_camera.attr[CELL_CAMERA_AGCHIGH] = { 64 };
break;
}
case fake_camera_type::uvc1_1:
{
g_camera.attr[CELL_CAMERA_DEVICEID] = { 0x5ca, 0x18d0 }; // KBCR-S01MU
g_camera.attr[CELL_CAMERA_FORMATCAP] = { CELL_CAMERA_JPG | CELL_CAMERA_YUV422 };
g_camera.attr[CELL_CAMERA_NUMFRAME] = { 1 }; // Amount of supported resolutions
break;
}
default:
cellCamera.todo("Trying to init cellCamera with un-researched camera type.");
}
+10 -10
View File
@@ -230,13 +230,13 @@ error_code cellHddGameCheck(ppu_thread& ppu, u32 version, vm::cptr<char> dirName
const auto& psf = psf::load_object(fs::file(local_dir +"/PARAM.SFO"));
// Some following fields may be zero in old FW 1.00 version PARAM.SFO
if (psf.count("PARENTAL_LEVEL") != 0) get->getParam.parentalLevel = psf.at("PARENTAL_LEVEL").as_integer();
if (psf.count("ATTRIBUTE") != 0) get->getParam.attribute = psf.at("ATTRIBUTE").as_integer();
if (psf.count("RESOLUTION") != 0) get->getParam.resolution = psf.at("RESOLUTION").as_integer();
if (psf.count("SOUND_FORMAT") != 0) get->getParam.soundFormat = psf.at("SOUND_FORMAT").as_integer();
if (psf.count("TITLE") != 0) strcpy_trunc(get->getParam.title, psf.at("TITLE").as_string());
if (psf.count("APP_VER") != 0) strcpy_trunc(get->getParam.dataVersion, psf.at("APP_VER").as_string());
if (psf.count("TITLE_ID") != 0) strcpy_trunc(get->getParam.titleId, psf.at("TITLE_ID").as_string());
if (psf.contains("PARENTAL_LEVEL")) get->getParam.parentalLevel = psf.at("PARENTAL_LEVEL").as_integer();
if (psf.contains("ATTRIBUTE")) get->getParam.attribute = psf.at("ATTRIBUTE").as_integer();
if (psf.contains("RESOLUTION")) get->getParam.resolution = psf.at("RESOLUTION").as_integer();
if (psf.contains("SOUND_FORMAT")) get->getParam.soundFormat = psf.at("SOUND_FORMAT").as_integer();
if (psf.contains("TITLE")) strcpy_trunc(get->getParam.title, psf.at("TITLE").as_string());
if (psf.contains("APP_VER")) strcpy_trunc(get->getParam.dataVersion, psf.at("APP_VER").as_string());
if (psf.contains("TITLE_ID")) strcpy_trunc(get->getParam.titleId, psf.at("TITLE_ID").as_string());
for (u32 i = 0; i < CELL_HDDGAME_SYSP_LANGUAGE_NUM; i++)
{
@@ -1356,10 +1356,10 @@ error_code cellDiscGameGetBootDiscInfo(vm::ptr<CellDiscGameSystemFileParam> getP
return CELL_DISCGAME_ERROR_NOT_DISCBOOT;
}
const auto& psf = psf::load_object(fs::file(vfs::get(dir + "/PARAM.SFO")));
const psf::registry psf = psf::load_object(fs::file(vfs::get(dir + "/PARAM.SFO")));
if (psf.count("PARENTAL_LEVEL") != 0) getParam->parentalLevel = psf.at("PARENTAL_LEVEL").as_integer();
if (psf.count("TITLE_ID") != 0) strcpy_trunc(getParam->titleId, psf.at("TITLE_ID").as_string());
if (psf.contains("PARENTAL_LEVEL")) getParam->parentalLevel = psf.at("PARENTAL_LEVEL").as_integer();
if (psf.contains("TITLE_ID")) strcpy_trunc(getParam->titleId, psf.at("TITLE_ID").as_string());
return CELL_OK;
}
+1 -1
View File
@@ -497,7 +497,7 @@ static bool ds3_input_to_ext(const u32 port_no, const gem_config::gem_controller
return false;
ext.status = 0; // CELL_GEM_EXT_CONNECTED | CELL_GEM_EXT_EXT0 | CELL_GEM_EXT_EXT1
ext.analog_left_x = pad->m_analog_left_x;
ext.analog_left_x = pad->m_analog_left_x; // HACK: these pad members are actually only set in cellPad
ext.analog_left_y = pad->m_analog_left_y;
ext.analog_right_x = pad->m_analog_right_x;
ext.analog_right_y = pad->m_analog_right_y;
+25 -18
View File
@@ -109,9 +109,16 @@ u16 cellKbCnvRawCode(u32 arrange, u32 mkey, u32 led, u16 rawcode)
sys_io.trace("cellKbCnvRawCode(arrange=%d, mkey=%d, led=%d, rawcode=0x%x)", arrange, mkey, led, rawcode);
// CELL_KB_RAWDAT
if (rawcode <= 0x03 || rawcode == 0x29 || rawcode == 0x35 || (rawcode >= 0x39 && rawcode <= 0x53) || rawcode == 0x65 || rawcode == 0x88 || rawcode == 0x8A || rawcode == 0x8B)
if (rawcode <= CELL_KEYC_E_UNDEF ||
rawcode == CELL_KEYC_ESCAPE ||
rawcode == CELL_KEYC_106_KANJI ||
(rawcode >= CELL_KEYC_CAPS_LOCK && rawcode <= CELL_KEYC_NUM_LOCK) ||
rawcode == CELL_KEYC_APPLICATION ||
rawcode == CELL_KEYC_KANA ||
rawcode == CELL_KEYC_HENKAN ||
rawcode == CELL_KEYC_MUHENKAN)
{
return rawcode | 0x8000;
return rawcode | CELL_KB_RAWDAT;
}
const bool is_alt = mkey & (CELL_KB_MKEY_L_ALT | CELL_KB_MKEY_R_ALT);
@@ -123,14 +130,14 @@ u16 cellKbCnvRawCode(u32 arrange, u32 mkey, u32 led, u16 rawcode)
if (is_num_lock)
{
if (rawcode == CELL_KEYC_KPAD_NUMLOCK) return 0x00 | 0x4000; // 'Num Lock'
if (rawcode == CELL_KEYC_KPAD_SLASH) return 0x2F | 0x4000; // '/'
if (rawcode == CELL_KEYC_KPAD_ASTERISK) return 0x2A | 0x4000; // '*'
if (rawcode == CELL_KEYC_KPAD_MINUS) return 0x2D | 0x4000; // '-'
if (rawcode == CELL_KEYC_KPAD_PLUS) return 0x2B | 0x4000; // '+'
if (rawcode == CELL_KEYC_KPAD_ENTER) return 0x0A | 0x4000; // '\n'
if (rawcode == CELL_KEYC_KPAD_0) return 0x30 | 0x4000; // '0'
if (rawcode >= CELL_KEYC_KPAD_1 && rawcode <= CELL_KEYC_KPAD_9) return (rawcode - 0x28) | 0x4000; // '1' - '9'
//if (rawcode == CELL_KEYC_KPAD_NUMLOCK) return 0x00 | CELL_KB_KEYPAD; // 'Num Lock' (unreachable)
if (rawcode == CELL_KEYC_KPAD_SLASH) return 0x2F | CELL_KB_KEYPAD; // '/'
if (rawcode == CELL_KEYC_KPAD_ASTERISK) return 0x2A | CELL_KB_KEYPAD; // '*'
if (rawcode == CELL_KEYC_KPAD_MINUS) return 0x2D | CELL_KB_KEYPAD; // '-'
if (rawcode == CELL_KEYC_KPAD_PLUS) return 0x2B | CELL_KB_KEYPAD; // '+'
if (rawcode == CELL_KEYC_KPAD_ENTER) return 0x0A | CELL_KB_KEYPAD; // '\n'
if (rawcode == CELL_KEYC_KPAD_0) return 0x30 | CELL_KB_KEYPAD; // '0'
if (rawcode >= CELL_KEYC_KPAD_1 && rawcode <= CELL_KEYC_KPAD_9) return (rawcode - 0x28) | CELL_KB_KEYPAD; // '1' - '9'
}
// ASCII
@@ -223,7 +230,7 @@ u16 cellKbCnvRawCode(u32 arrange, u32 mkey, u32 led, u16 rawcode)
if (rawcode == CELL_KEYC_Q) return get_ascii('q', 'Q', '@');
}
if (rawcode >= 0x04 && rawcode <= 0x1D) // 'A' - 'Z'
if (rawcode >= CELL_KEYC_A && rawcode <= CELL_KEYC_Z) // 'A' - 'Z'
{
rawcode -=
(is_shift)
@@ -231,13 +238,13 @@ u16 cellKbCnvRawCode(u32 arrange, u32 mkey, u32 led, u16 rawcode)
: ((led & (CELL_KB_LED_CAPS_LOCK)) ? 0x20 : 0);
return rawcode + 0x5D;
}
if (rawcode >= 0x1E && rawcode <= 0x26) return rawcode + 0x13; // '1' - '9'
if (rawcode == 0x27) return 0x30; // '0'
if (rawcode == 0x28) return 0x0A; // '\n'
if (rawcode == 0x29) return 0x1B; // 'ESC'
if (rawcode == 0x2A) return 0x08; // '\b'
if (rawcode == 0x2B) return 0x09; // '\t'
if (rawcode == 0x2C) return 0x20; // 'space'
if (rawcode >= CELL_KEYC_1 && rawcode <= CELL_KEYC_9) return rawcode + 0x13; // '1' - '9'
if (rawcode == CELL_KEYC_0) return 0x30; // '0'
if (rawcode == CELL_KEYC_ENTER) return 0x0A; // '\n'
//if (rawcode == CELL_KEYC_ESC) return 0x1B; // 'ESC' (unreachable)
if (rawcode == CELL_KEYC_BS) return 0x08; // '\b'
if (rawcode == CELL_KEYC_TAB) return 0x09; // '\t'
if (rawcode == CELL_KEYC_SPACE) return 0x20; // 'space'
// TODO: Add more keys and layouts
+1 -1
View File
@@ -105,7 +105,7 @@ public:
MsgDialogType type{};
std::function<void(s32 status)> on_close;
std::function<void(s32 status)> on_close = nullptr;
virtual ~MsgDialogBase();
virtual void Create(const std::string& msg, const std::string& title = "") = 0;
+14 -13
View File
@@ -11,6 +11,7 @@
#include "Utilities/StrUtil.h"
#include "Emu/NP/np_handler.h"
#include "Emu/NP/np_helpers.h"
LOG_CHANNEL(cellNetCtl);
@@ -93,7 +94,7 @@ error_code cellNetCtlInit()
{
cellNetCtl.warning("cellNetCtlInit()");
auto& nph = g_fxo->get<named_thread<np_handler>>();
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
if (nph.is_netctl_init)
{
@@ -109,7 +110,7 @@ void cellNetCtlTerm()
{
cellNetCtl.warning("cellNetCtlTerm()");
auto& nph = g_fxo->get<named_thread<np_handler>>();
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
nph.is_netctl_init = false;
}
@@ -118,7 +119,7 @@ error_code cellNetCtlGetState(vm::ptr<s32> state)
{
cellNetCtl.trace("cellNetCtlGetState(state=*0x%x)", state);
auto& nph = g_fxo->get<named_thread<np_handler>>();
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
if (!nph.is_netctl_init)
{
@@ -139,7 +140,7 @@ error_code cellNetCtlAddHandler(vm::ptr<cellNetCtlHandler> handler, vm::ptr<void
{
cellNetCtl.todo("cellNetCtlAddHandler(handler=*0x%x, arg=*0x%x, hid=*0x%x)", handler, arg, hid);
auto& nph = g_fxo->get<named_thread<np_handler>>();
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
if (!nph.is_netctl_init)
{
@@ -158,7 +159,7 @@ error_code cellNetCtlDelHandler(s32 hid)
{
cellNetCtl.todo("cellNetCtlDelHandler(hid=0x%x)", hid);
auto& nph = g_fxo->get<named_thread<np_handler>>();
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
if (!nph.is_netctl_init)
{
@@ -177,7 +178,7 @@ error_code cellNetCtlGetInfo(s32 code, vm::ptr<CellNetCtlInfo> info)
{
cellNetCtl.warning("cellNetCtlGetInfo(code=0x%x (%s), info=*0x%x)", code, InfoCodeToName(code), info);
auto& nph = g_fxo->get<named_thread<np_handler>>();
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
if (!nph.is_netctl_init)
{
@@ -209,9 +210,9 @@ error_code cellNetCtlGetInfo(s32 code, vm::ptr<CellNetCtlInfo> info)
case CELL_NET_CTL_INFO_LINK_TYPE: info->link_type = CELL_NET_CTL_LINK_TYPE_10BASE_FULL; break;
case CELL_NET_CTL_INFO_IP_CONFIG: info->ip_config = CELL_NET_CTL_IP_STATIC; break;
case CELL_NET_CTL_INFO_DEFAULT_ROUTE: strcpy_trunc(info->default_route, "192.168.1.1"); break;
case CELL_NET_CTL_INFO_PRIMARY_DNS: strcpy_trunc(info->primary_dns, np_handler::ip_to_string(nph.get_dns_ip())); break;
case CELL_NET_CTL_INFO_SECONDARY_DNS: strcpy_trunc(info->secondary_dns, np_handler::ip_to_string(nph.get_dns_ip())); break;
case CELL_NET_CTL_INFO_IP_ADDRESS: strcpy_trunc(info->ip_address, np_handler::ip_to_string(nph.get_local_ip_addr())); break;
case CELL_NET_CTL_INFO_PRIMARY_DNS: strcpy_trunc(info->primary_dns, np::ip_to_string(nph.get_dns_ip())); break;
case CELL_NET_CTL_INFO_SECONDARY_DNS: strcpy_trunc(info->secondary_dns, np::ip_to_string(nph.get_dns_ip())); break;
case CELL_NET_CTL_INFO_IP_ADDRESS: strcpy_trunc(info->ip_address, np::ip_to_string(nph.get_local_ip_addr())); break;
case CELL_NET_CTL_INFO_NETMASK: strcpy_trunc(info->netmask, "255.255.255.255"); break;
case CELL_NET_CTL_INFO_HTTP_PROXY_CONFIG: info->http_proxy_config = 0; break;
case CELL_NET_CTL_INFO_DHCP_HOSTNAME: strcpy_trunc(info->dhcp_hostname, nph.get_hostname()); break;
@@ -238,7 +239,7 @@ error_code cellNetCtlNetStartDialogLoadAsync(vm::cptr<CellNetCtlNetStartDialogPa
{
cellNetCtl.error("cellNetCtlNetStartDialogLoadAsync(param=*0x%x)", param);
auto& nph = g_fxo->get<named_thread<np_handler>>();
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
if (!nph.is_netctl_init)
{
@@ -270,7 +271,7 @@ error_code cellNetCtlNetStartDialogAbortAsync()
{
cellNetCtl.error("cellNetCtlNetStartDialogAbortAsync()");
auto& nph = g_fxo->get<named_thread<np_handler>>();
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
if (!nph.is_netctl_init)
{
@@ -284,7 +285,7 @@ error_code cellNetCtlNetStartDialogUnloadAsync(vm::ptr<CellNetCtlNetStartDialogR
{
cellNetCtl.warning("cellNetCtlNetStartDialogUnloadAsync(result=*0x%x)", result);
auto& nph = g_fxo->get<named_thread<np_handler>>();
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
if (!nph.is_netctl_init)
{
@@ -311,7 +312,7 @@ error_code cellNetCtlGetNatInfo(vm::ptr<CellNetCtlNatInfo> natInfo)
{
cellNetCtl.warning("cellNetCtlGetNatInfo(natInfo=*0x%x)", natInfo);
auto& nph = g_fxo->get<named_thread<np_handler>>();
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
if (!nph.is_netctl_init)
{
+2 -2
View File
@@ -1457,7 +1457,7 @@ error_code cellRtcGetDaysInMonth(s32 year, s32 month)
{
cellRtc.todo("cellRtcGetDaysInMonth(year=%d, month=%d)", year, month);
if ((year < 0) || (month < 0) || (month > 12))
if ((year < 0) || (month <= 0) || (month > 12))
{
return CELL_RTC_ERROR_INVALID_ARG;
}
@@ -1467,7 +1467,7 @@ error_code cellRtcGetDaysInMonth(s32 year, s32 month)
return not_an_error(DAYS_IN_MONTH[month + 11]);
}
return not_an_error(DAYS_IN_MONTH[month + -1]);
return not_an_error(DAYS_IN_MONTH[month - 1]);
}
error_code cellRtcGetDayOfWeek(s32 year, s32 month, s32 day)
+35 -25
View File
@@ -117,6 +117,7 @@ struct savedata_manager
{
semaphore<> mutex;
atomic_t<bool> enable_overlay{false};
atomic_t<s32> last_cbresult_error_dialog{0}; // CBRESULT errors are negative
};
static std::vector<SaveDataEntry> get_save_entries(const std::string& base_dir, const std::string& prefix)
@@ -150,11 +151,11 @@ static std::vector<SaveDataEntry> get_save_entries(const std::string& base_dir,
}
SaveDataEntry save_entry;
save_entry.dirName = psf.at("SAVEDATA_DIRECTORY").as_string();
save_entry.listParam = psf.at("SAVEDATA_LIST_PARAM").as_string();
save_entry.title = psf.at("TITLE").as_string();
save_entry.subtitle = psf.at("SUB_TITLE").as_string();
save_entry.details = psf.at("DETAIL").as_string();
save_entry.dirName = psf::get_string(psf, "SAVEDATA_DIRECTORY");
save_entry.listParam = psf::get_string(psf, "SAVEDATA_LIST_PARAM");
save_entry.title = psf::get_string(psf, "TITLE");
save_entry.subtitle = psf::get_string(psf, "SUB_TITLE");
save_entry.details = psf::get_string(psf, "DETAIL");
for (const auto& entry2 : fs::dir(base_dir + entry.name))
{
@@ -312,9 +313,12 @@ static error_code display_callback_result_error_message(ppu_thread& ppu, const C
return {CELL_SAVEDATA_ERROR_PARAM, "22"};
}
// TODO: errDialog == CELL_SAVEDATA_ERRDIALOG_NOREPEAT
if (errDialog != CELL_SAVEDATA_ERRDIALOG_ALWAYS)
if (errDialog == CELL_SAVEDATA_ERRDIALOG_NONE ||
(errDialog == CELL_SAVEDATA_ERRDIALOG_NOREPEAT && result.result == g_fxo->get<savedata_manager>().last_cbresult_error_dialog.exchange(result.result)))
{
// TODO: Find out if the "last error" is always tracked or only when NOREPEAT is set
return CELL_SAVEDATA_ERROR_CBRESULT;
}
// Yield before a blocking dialog is being spawned
lv2_obj::sleep(ppu);
@@ -571,6 +575,12 @@ static NEVER_INLINE error_code savedata_op(ppu_thread& ppu, u32 operation, u32 v
u32 errDialog, PSetList setList, PSetBuf setBuf, PFuncList funcList, PFuncFixed funcFixed, PFuncStat funcStat,
PFuncFile funcFile, u32 container, u32 unk_op_flags /*TODO*/, vm::ptr<void> userdata, u32 userId, PFuncDone funcDone)
{
if (const auto [ok, list] = setList.try_read(); ok)
cellSaveData.notice("savedata_op(): setList = { .sortType=%d, .sortOrder=%d, .dirNamePrefix='%s' }", list.sortType, list.sortOrder, list.dirNamePrefix);
if (const auto [ok, buf] = setBuf.try_read(); ok)
cellSaveData.notice("savedata_op(): setBuf = { .dirListMax=%d, .fileListMax=%d, .bufSize=%d }", buf.dirListMax, buf.fileListMax, buf.bufSize);
if (const auto ecode = savedata_check_args(operation, version, dirName, errDialog, setList, setBuf, funcList, funcFixed, funcStat,
funcFile, container, unk_op_flags, userdata, userId, funcDone))
{
@@ -668,11 +678,11 @@ static NEVER_INLINE error_code savedata_op(ppu_thread& ppu, u32 operation, u32 v
}
SaveDataEntry save_entry2;
save_entry2.dirName = psf.at("SAVEDATA_DIRECTORY").as_string();
save_entry2.listParam = psf.at("SAVEDATA_LIST_PARAM").as_string();
save_entry2.title = psf.at("TITLE").as_string();
save_entry2.subtitle = psf.at("SUB_TITLE").as_string();
save_entry2.details = psf.at("DETAIL").as_string();
save_entry2.dirName = psf::get_string(psf, "SAVEDATA_DIRECTORY");
save_entry2.listParam = psf::get_string(psf, "SAVEDATA_LIST_PARAM");
save_entry2.title = psf::get_string(psf, "TITLE");
save_entry2.subtitle = psf::get_string(psf, "SUB_TITLE");
save_entry2.details = psf::get_string(psf, "DETAIL");
for (const auto& entry2 : fs::dir(base_dir + entry.name))
{
@@ -1281,8 +1291,8 @@ static NEVER_INLINE error_code savedata_op(ppu_thread& ppu, u32 operation, u32 v
// This section contains the list of files in the save ordered as they would be in BSD filesystem
std::vector<std::string> blist;
if (psf.count("RPCS3_BLIST"))
blist = fmt::split(psf.at("RPCS3_BLIST").as_string(), {"/"}, false);
if (const auto it = psf.find("RPCS3_BLIST"); it != psf.cend())
blist = fmt::split(it->second.as_string(), {"/"}, false);
// Get save stats
{
@@ -1308,12 +1318,12 @@ static NEVER_INLINE error_code savedata_op(ppu_thread& ppu, u32 operation, u32 v
if (!psf.empty())
{
statGet->getParam.parental_level = psf.at("PARENTAL_LEVEL").as_integer();
statGet->getParam.attribute = psf.at("ATTRIBUTE").as_integer(); // ???
strcpy_trunc(statGet->getParam.title, save_entry.title = psf.at("TITLE").as_string());
strcpy_trunc(statGet->getParam.subTitle, save_entry.subtitle = psf.at("SUB_TITLE").as_string());
strcpy_trunc(statGet->getParam.detail, save_entry.details = psf.at("DETAIL").as_string());
strcpy_trunc(statGet->getParam.listParam, save_entry.listParam = psf.at("SAVEDATA_LIST_PARAM").as_string());
statGet->getParam.parental_level = psf::get_integer(psf, "PARENTAL_LEVEL");
statGet->getParam.attribute = psf::get_integer(psf, "ATTRIBUTE"); // ???
strcpy_trunc(statGet->getParam.title, save_entry.title = psf::get_string(psf, "TITLE"));
strcpy_trunc(statGet->getParam.subTitle, save_entry.subtitle = psf::get_string(psf, "SUB_TITLE"));
strcpy_trunc(statGet->getParam.detail, save_entry.details = psf::get_string(psf, "DETAIL"));
strcpy_trunc(statGet->getParam.listParam, save_entry.listParam = psf::get_string(psf, "SAVEDATA_LIST_PARAM"));
}
statGet->bind = 0;
@@ -2046,14 +2056,14 @@ static NEVER_INLINE error_code savedata_get_list_item(vm::cptr<char> dirName, vm
return CELL_SAVEDATA_ERROR_NODATA;
}
auto psf = psf::load_object(fs::file(sfo));
const psf::registry psf = psf::load_object(fs::file(sfo));
if (sysFileParam)
{
strcpy_trunc(sysFileParam->listParam, psf.at("SAVEDATA_LIST_PARAM").as_string());
strcpy_trunc(sysFileParam->title, psf.at("TITLE").as_string());
strcpy_trunc(sysFileParam->subTitle, psf.at("SUB_TITLE").as_string());
strcpy_trunc(sysFileParam->detail, psf.at("DETAIL").as_string());
strcpy_trunc(sysFileParam->listParam, psf::get_string(psf, "SAVEDATA_LIST_PARAM"));
strcpy_trunc(sysFileParam->title, psf::get_string(psf, "TITLE"));
strcpy_trunc(sysFileParam->subTitle, psf::get_string(psf, "SUB_TITLE"));
strcpy_trunc(sysFileParam->detail, psf::get_string(psf, "DETAIL"));
}
if (dir)
+11 -5
View File
@@ -119,7 +119,7 @@ error_code cellVideoOutGetState(u32 videoOut, u32 deviceIndex, vm::ptr<CellVideo
{
case CELL_VIDEO_OUT_PRIMARY:
{
auto& conf = g_fxo->get<rsx::avconf>();
const auto& conf = g_fxo->get<rsx::avconf>();
state->state = CELL_VIDEO_OUT_OUTPUT_STATE_ENABLED;
state->colorSpace = CELL_VIDEO_OUT_COLOR_SPACE_RGB;
state->displayMode.resolutionId = conf.state ? conf.resolution_id : g_video_out_resolution_id.at(g_cfg.video.resolution);
@@ -197,13 +197,19 @@ error_code cellVideoOutConfigure(u32 videoOut, vm::ptr<CellVideoOutConfiguration
conf.resolution_y = res.height;
conf.state = 1;
if (conf.aspect == CELL_VIDEO_OUT_ASPECT_AUTO)
// TODO: What happens if the aspect is unknown? Let's treat it as auto for now.
if (conf.aspect != CELL_VIDEO_OUT_ASPECT_4_3 && conf.aspect != CELL_VIDEO_OUT_ASPECT_16_9)
{
// Resolve 'auto' option to actual aspect ratio
if (conf.aspect != CELL_VIDEO_OUT_ASPECT_AUTO)
{
cellSysutil.error("Selected unknown aspect 0x%x. Falling back to aspect %s.", conf.aspect, g_cfg.video.aspect_ratio.get());
}
// Resolve 'auto' or unknown options to actual aspect ratio
conf.aspect = g_video_out_aspect_id.at(g_cfg.video.aspect_ratio);
}
cellSysutil.notice("Selected video resolution 0x%x", config->resolutionId);
cellSysutil.notice("Selected video configuration: resolutionId=0x%x, aspect=0x%x=>0x%x, format=0x%x", config->resolutionId, config->aspect, conf.aspect, config->format);
return CELL_OK;
}
@@ -224,7 +230,7 @@ error_code cellVideoOutGetConfiguration(u32 videoOut, vm::ptr<CellVideoOutConfig
{
case CELL_VIDEO_OUT_PRIMARY:
{
if (auto& conf = g_fxo->get<rsx::avconf>(); conf.state)
if (const auto& conf = g_fxo->get<rsx::avconf>(); conf.state)
{
config->resolutionId = conf.resolution_id;
config->format = conf.format;
+1 -1
View File
@@ -34,7 +34,7 @@ enum CellVideoOutResolutionId : s32
CELL_VIDEO_OUT_RESOLUTION_1280x1080 = 0xc,
CELL_VIDEO_OUT_RESOLUTION_960x1080 = 0xd,
CELL_VIDEO_OUT_RESOLUTION_720_3D_FRAME_PACKING = 0x81,
CELL_VIDEO_OUT_RESOLUTION_1024x720_3D_FRAME_PACKING = 0x88,
CELL_VIDEO_OUT_RESOLUTION_1024x720_3D_FRAME_PACKING = 0x88,
CELL_VIDEO_OUT_RESOLUTION_960x720_3D_FRAME_PACKING = 0x89,
CELL_VIDEO_OUT_RESOLUTION_800x720_3D_FRAME_PACKING = 0x8a,
CELL_VIDEO_OUT_RESOLUTION_640x720_3D_FRAME_PACKING = 0x8b,
File diff suppressed because it is too large Load Diff
+223 -94
View File
@@ -178,7 +178,7 @@ error_code sceNpMatching2Init2(u64 stackSize, s32 priority, vm::ptr<SceNpMatchin
error_code sceNpMatching2Term(ppu_thread& ppu);
error_code sceNpMatching2Term2();
error_code generic_match2_error_check(const named_thread<np_handler>& nph, SceNpMatching2ContextId ctxId, vm::cptr<void> reqParam, vm::ptr<SceNpMatching2RequestId> assignedReqId)
error_code generic_match2_error_check(const named_thread<np::np_handler>& nph, SceNpMatching2ContextId ctxId, vm::cptr<void> reqParam, vm::ptr<SceNpMatching2RequestId> assignedReqId)
{
if (!nph.is_NP2_Match2_init)
{
@@ -207,7 +207,7 @@ error_code sceNp2Init(u32 poolsize, vm::ptr<void> poolptr)
{
sceNp2.warning("sceNp2Init(poolsize=0x%x, poolptr=*0x%x)", poolsize, poolptr);
auto& nph = g_fxo->get<named_thread<np_handler>>();
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
{
std::lock_guard lock(nph.mutex_status);
@@ -239,7 +239,7 @@ error_code sceNpMatching2Init2(u64 stackSize, s32 priority, vm::ptr<SceNpMatchin
{
sceNp2.todo("sceNpMatching2Init2(stackSize=0x%x, priority=%d, param=*0x%x)", stackSize, priority, param);
auto& nph = g_fxo->get<named_thread<np_handler>>();
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
if (!nph.is_NP2_init)
{
@@ -265,7 +265,7 @@ error_code sceNp2Term(ppu_thread& ppu)
{
sceNp2.warning("sceNp2Term()");
auto& nph = g_fxo->get<named_thread<np_handler>>();
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
{
std::lock_guard lock(nph.mutex_status);
@@ -295,7 +295,7 @@ error_code sceNpMatching2Term2()
{
sceNp2.warning("sceNpMatching2Term2()");
auto& nph = g_fxo->get<named_thread<np_handler>>();
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
{
std::lock_guard lock(nph.mutex_status);
@@ -321,7 +321,7 @@ error_code sceNpMatching2DestroyContext(SceNpMatching2ContextId ctxId)
{
sceNp2.todo("sceNpMatching2DestroyContext(ctxId=%d)", ctxId);
auto& nph = g_fxo->get<named_thread<np_handler>>();
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
if (!nph.is_NP2_Match2_init)
{
@@ -339,7 +339,7 @@ error_code sceNpMatching2LeaveLobby(
{
sceNp2.todo("sceNpMatching2LeaveLobby(ctxId=%d, reqParam=*0x%x, optParam=*0x%x, assignedReqId=*0x%x)", ctxId, reqParam, optParam, assignedReqId);
auto& nph = g_fxo->get<named_thread<np_handler>>();
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
if (auto res = generic_match2_error_check(nph, ctxId, reqParam, assignedReqId); res != CELL_OK)
{
return res;
@@ -352,7 +352,7 @@ error_code sceNpMatching2RegisterLobbyMessageCallback(SceNpMatching2ContextId ct
{
sceNp2.todo("sceNpMatching2RegisterLobbyMessageCallback(ctxId=%d, cbFunc=*0x%x, cbFuncArg=*0x%x)", ctxId, cbFunc, cbFuncArg);
auto& nph = g_fxo->get<named_thread<np_handler>>();
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
if (!nph.is_NP2_Match2_init)
{
@@ -367,7 +367,7 @@ error_code sceNpMatching2GetWorldInfoList(
{
sceNp2.warning("sceNpMatching2GetWorldInfoList(ctxId=%d, reqParam=*0x%x, optParam=*0x%x, assignedReqId=*0x%x)", ctxId, reqParam, optParam, assignedReqId);
auto& nph = g_fxo->get<named_thread<np_handler>>();
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
if (auto res = generic_match2_error_check(nph, ctxId, reqParam, assignedReqId); res != CELL_OK)
{
return res;
@@ -387,7 +387,7 @@ error_code sceNpMatching2RegisterLobbyEventCallback(SceNpMatching2ContextId ctxI
{
sceNp2.todo("sceNpMatching2RegisterLobbyEventCallback(ctxId=%d, cbFunc=*0x%x, cbFuncArg=*0x%x)", ctxId, cbFunc, cbFuncArg);
auto& nph = g_fxo->get<named_thread<np_handler>>();
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
if (!nph.is_NP2_Match2_init)
{
@@ -402,7 +402,7 @@ error_code sceNpMatching2GetLobbyMemberDataInternalList(SceNpMatching2ContextId
{
sceNp2.todo("sceNpMatching2GetLobbyMemberDataInternalList(ctxId=%d, reqParam=*0x%x, optParam=*0x%x, assignedReqId=*0x%x)", ctxId, reqParam, optParam, assignedReqId);
auto& nph = g_fxo->get<named_thread<np_handler>>();
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
if (auto res = generic_match2_error_check(nph, ctxId, reqParam, assignedReqId); res != CELL_OK)
{
return res;
@@ -416,7 +416,7 @@ error_code sceNpMatching2SearchRoom(
{
sceNp2.warning("sceNpMatching2SearchRoom(ctxId=%d, reqParam=*0x%x, optParam=*0x%x, assignedReqId=*0x%x)", ctxId, reqParam, optParam, assignedReqId);
auto& nph = g_fxo->get<named_thread<np_handler>>();
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
if (auto res = generic_match2_error_check(nph, ctxId, reqParam, assignedReqId); res != CELL_OK)
{
return res;
@@ -432,7 +432,7 @@ error_code sceNpMatching2SignalingGetConnectionStatus(
{
sceNp2.warning("sceNpMatching2SignalingGetConnectionStatus(ctxId=%d, roomId=%d, memberId=%d, connStatus=*0x%x, peerAddr=*0x%x, peerPort=*0x%x)", ctxId, roomId, memberId, connStatus, peerAddr, peerPort);
auto& nph = g_fxo->get<named_thread<np_handler>>();
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
if (!nph.is_NP2_Match2_init)
{
@@ -468,7 +468,7 @@ error_code sceNpMatching2SetUserInfo(
{
sceNp2.todo("sceNpMatching2SetUserInfo(ctxId=%d, reqParam=*0x%x, optParam=*0x%x, assignedReqId=*0x%x)", ctxId, reqParam, optParam, assignedReqId);
auto& nph = g_fxo->get<named_thread<np_handler>>();
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
if (auto res = generic_match2_error_check(nph, ctxId, reqParam, assignedReqId); res != CELL_OK)
{
return res;
@@ -481,7 +481,7 @@ error_code sceNpMatching2GetClanLobbyId(SceNpMatching2ContextId ctxId, SceNpClan
{
sceNp2.todo("sceNpMatching2GetClanLobbyId(ctxId=%d, clanId=%d, lobbyId=*0x%x)", ctxId, clanId, lobbyId);
auto& nph = g_fxo->get<named_thread<np_handler>>();
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
if (!nph.is_NP2_Match2_init)
{
@@ -496,7 +496,7 @@ error_code sceNpMatching2GetLobbyMemberDataInternal(
{
sceNp2.todo("sceNpMatching2GetLobbyMemberDataInternal(ctxId=%d, reqParam=*0x%x, optParam=*0x%x, assignedReqId=*0x%x)", ctxId, reqParam, optParam, assignedReqId);
auto& nph = g_fxo->get<named_thread<np_handler>>();
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
if (auto res = generic_match2_error_check(nph, ctxId, reqParam, assignedReqId); res != CELL_OK)
{
return res;
@@ -509,7 +509,7 @@ error_code sceNpMatching2ContextStart(SceNpMatching2ContextId ctxId)
{
sceNp2.warning("sceNpMatching2ContextStart(ctxId=%d)", ctxId);
auto& nph = g_fxo->get<named_thread<np_handler>>();
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
if (!nph.is_NP2_Match2_init)
{
@@ -537,7 +537,7 @@ error_code sceNpMatching2CreateServerContext(
{
sceNp2.warning("sceNpMatching2CreateServerContext(ctxId=%d, reqParam=*0x%x, optParam=*0x%x, assignedReqId=*0x%x)", ctxId, reqParam, optParam, assignedReqId);
auto& nph = g_fxo->get<named_thread<np_handler>>();
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
if (auto res = generic_match2_error_check(nph, ctxId, reqParam, assignedReqId); res != CELL_OK)
{
return res;
@@ -557,7 +557,7 @@ error_code sceNpMatching2GetMemoryInfo(vm::ptr<SceNpMatching2MemoryInfo> memInfo
{
sceNp2.todo("sceNpMatching2GetMemoryInfo(memInfo=*0x%x)", memInfo);
auto& nph = g_fxo->get<named_thread<np_handler>>();
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
if (!nph.is_NP2_Match2_init)
{
@@ -572,7 +572,7 @@ error_code sceNpMatching2LeaveRoom(
{
sceNp2.warning("sceNpMatching2LeaveRoom(ctxId=%d, reqParam=*0x%x, optParam=*0x%x, assignedReqId=*0x%x)", ctxId, reqParam, optParam, assignedReqId);
auto& nph = g_fxo->get<named_thread<np_handler>>();
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
if (auto res = generic_match2_error_check(nph, ctxId, reqParam, assignedReqId); res != CELL_OK)
{
return res;
@@ -588,7 +588,7 @@ error_code sceNpMatching2SetRoomDataExternal(
{
sceNp2.warning("sceNpMatching2SetRoomDataExternal(ctxId=%d, reqParam=*0x%x, optParam=*0x%x, assignedReqId=*0x%x)", ctxId, reqParam, optParam, assignedReqId);
auto& nph = g_fxo->get<named_thread<np_handler>>();
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
if (auto res = generic_match2_error_check(nph, ctxId, reqParam, assignedReqId); res != CELL_OK)
{
return res;
@@ -602,9 +602,9 @@ error_code sceNpMatching2SetRoomDataExternal(
error_code sceNpMatching2SignalingGetConnectionInfo(
SceNpMatching2ContextId ctxId, SceNpMatching2RoomId roomId, SceNpMatching2RoomMemberId memberId, s32 code, vm::ptr<SceNpSignalingConnectionInfo> connInfo)
{
sceNp2.todo("sceNpMatching2SignalingGetConnectionInfo(ctxId=%d, roomId=%d, memberId=%d, code=%d, connInfo=*0x%x)", ctxId, roomId, memberId, code, connInfo);
sceNp2.warning("sceNpMatching2SignalingGetConnectionInfo(ctxId=%d, roomId=%d, memberId=%d, code=%d, connInfo=*0x%x)", ctxId, roomId, memberId, code, connInfo);
auto& nph = g_fxo->get<named_thread<np_handler>>();
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
if (!nph.is_NP2_Match2_init)
{
@@ -663,9 +663,9 @@ error_code sceNpMatching2SignalingGetConnectionInfo(
error_code sceNpMatching2SendRoomMessage(
SceNpMatching2ContextId ctxId, vm::cptr<SceNpMatching2SendRoomMessageRequest> reqParam, vm::cptr<SceNpMatching2RequestOptParam> optParam, vm::ptr<SceNpMatching2RequestId> assignedReqId)
{
sceNp2.todo("sceNpMatching2SendRoomMessage(ctxId=%d, reqParam=*0x%x, optParam=*0x%x, assignedReqId=*0x%x)", ctxId, reqParam, optParam, assignedReqId);
sceNp2.warning("sceNpMatching2SendRoomMessage(ctxId=%d, reqParam=*0x%x, optParam=*0x%x, assignedReqId=*0x%x)", ctxId, reqParam, optParam, assignedReqId);
auto& nph = g_fxo->get<named_thread<np_handler>>();
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
if (auto res = generic_match2_error_check(nph, ctxId, reqParam, assignedReqId); res != CELL_OK)
{
return res;
@@ -681,7 +681,7 @@ error_code sceNpMatching2JoinLobby(
{
sceNp2.todo("sceNpMatching2JoinLobby(ctxId=%d, reqParam=*0x%x, optParam=*0x%x, assignedReqId=*0x%x)", ctxId, reqParam, optParam, assignedReqId);
auto& nph = g_fxo->get<named_thread<np_handler>>();
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
if (auto res = generic_match2_error_check(nph, ctxId, reqParam, assignedReqId); res != CELL_OK)
{
return res;
@@ -695,7 +695,7 @@ error_code sceNpMatching2GetRoomMemberDataExternalList(SceNpMatching2ContextId c
{
sceNp2.todo("sceNpMatching2GetRoomMemberDataExternalList(ctxId=%d, reqParam=*0x%x, optParam=*0x%x, assignedReqId=*0x%x)", ctxId, reqParam, optParam, assignedReqId);
auto& nph = g_fxo->get<named_thread<np_handler>>();
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
if (auto res = generic_match2_error_check(nph, ctxId, reqParam, assignedReqId); res != CELL_OK)
{
return res;
@@ -708,7 +708,7 @@ error_code sceNpMatching2AbortRequest(SceNpMatching2ContextId ctxId, SceNpMatchi
{
sceNp2.todo("sceNpMatching2AbortRequest(ctxId=%d, reqId=%d)", ctxId, reqId);
auto& nph = g_fxo->get<named_thread<np_handler>>();
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
if (!nph.is_NP2_Match2_init)
{
@@ -723,7 +723,7 @@ error_code sceNpMatching2GetServerInfo(
{
sceNp2.warning("sceNpMatching2GetServerInfo(ctxId=%d, reqParam=*0x%x, optParam=*0x%x, assignedReqId=*0x%x)", ctxId, reqParam, optParam, assignedReqId);
auto& nph = g_fxo->get<named_thread<np_handler>>();
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
if (auto res = generic_match2_error_check(nph, ctxId, reqParam, assignedReqId); res != CELL_OK)
{
return res;
@@ -738,7 +738,7 @@ error_code sceNpMatching2GetEventData(SceNpMatching2ContextId ctxId, SceNpMatchi
{
sceNp2.notice("sceNpMatching2GetEventData(ctxId=%d, eventKey=%d, buf=*0x%x, bufLen=%d)", ctxId, eventKey, buf, bufLen);
auto& nph = g_fxo->get<named_thread<np_handler>>();
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
if (!nph.is_NP2_Match2_init)
{
@@ -750,20 +750,44 @@ error_code sceNpMatching2GetEventData(SceNpMatching2ContextId ctxId, SceNpMatchi
return SCE_NP_MATCHING2_ERROR_INVALID_ARGUMENT;
}
return not_an_error(nph.get_match2_event(eventKey, static_cast<u8 *>(buf.get_ptr()), bufLen));
return not_an_error(nph.get_match2_event(eventKey, buf.addr(), bufLen));
}
error_code sceNpMatching2GetRoomSlotInfoLocal(SceNpMatching2ContextId ctxId, const SceNpMatching2RoomId roomId, vm::ptr<SceNpMatching2RoomSlotInfo> roomSlotInfo)
{
sceNp2.todo("sceNpMatching2GetRoomSlotInfoLocal(ctxId=%d, roomId=%d, roomSlotInfo=*0x%x)", ctxId, roomId, roomSlotInfo);
sceNp2.notice("sceNpMatching2GetRoomSlotInfoLocal(ctxId=%d, roomId=%d, roomSlotInfo=*0x%x)", ctxId, roomId, roomSlotInfo);
auto& nph = g_fxo->get<named_thread<np_handler>>();
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
if (!nph.is_NP2_Match2_init)
{
return SCE_NP_MATCHING2_ERROR_NOT_INITIALIZED;
}
if (!ctxId)
{
return SCE_NP_MATCHING2_ERROR_INVALID_CONTEXT_ID;
}
if (!roomId)
{
return SCE_NP_MATCHING2_ERROR_INVALID_ROOM_ID;
}
if (!check_match2_context(ctxId))
{
return SCE_NP_MATCHING2_ERROR_CONTEXT_NOT_FOUND;
}
const auto [error, slots] = nph.local_get_room_slots(roomId);
if (error)
{
return error;
}
memcpy(roomSlotInfo.get_ptr(), &slots.value(), sizeof(SceNpMatching2RoomSlotInfo));
return CELL_OK;
}
@@ -772,7 +796,7 @@ error_code sceNpMatching2SendLobbyChatMessage(
{
sceNp2.todo("sceNpMatching2SendLobbyChatMessage(ctxId=%d, reqParam=*0x%x, optParam=*0x%x, assignedReqId=*0x%x)", ctxId, reqParam, optParam, assignedReqId);
auto& nph = g_fxo->get<named_thread<np_handler>>();
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
if (auto res = generic_match2_error_check(nph, ctxId, reqParam, assignedReqId); res != CELL_OK)
{
return res;
@@ -785,7 +809,7 @@ error_code sceNpMatching2AbortContextStart(SceNpMatching2ContextId ctxId)
{
sceNp2.todo("sceNpMatching2AbortContextStart(ctxId=%d)", ctxId);
auto& nph = g_fxo->get<named_thread<np_handler>>();
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
if (!nph.is_NP2_Match2_init)
{
@@ -797,16 +821,50 @@ error_code sceNpMatching2AbortContextStart(SceNpMatching2ContextId ctxId)
error_code sceNpMatching2GetRoomMemberIdListLocal(SceNpMatching2ContextId ctxId, SceNpMatching2RoomId roomId, s32 sortMethod, vm::ptr<SceNpMatching2RoomMemberId> memberId, u32 memberIdNum)
{
sceNp2.todo("sceNpMatching2GetRoomMemberIdListLocal(ctxId=%d, roomId=%d, sortMethod=%d, memberId=*0x%x, memberIdNum=%d)", ctxId, roomId, sortMethod, memberId, memberIdNum);
sceNp2.notice("sceNpMatching2GetRoomMemberIdListLocal(ctxId=%d, roomId=%d, sortMethod=%d, memberId=*0x%x, memberIdNum=%d)", ctxId, roomId, sortMethod, memberId, memberIdNum);
auto& nph = g_fxo->get<named_thread<np_handler>>();
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
if (!nph.is_NP2_Match2_init)
{
return SCE_NP_MATCHING2_ERROR_NOT_INITIALIZED;
}
return CELL_OK;
if (!ctxId)
{
return SCE_NP_MATCHING2_ERROR_INVALID_CONTEXT_ID;
}
if (!roomId)
{
return SCE_NP_MATCHING2_ERROR_INVALID_ROOM_ID;
}
if (sortMethod != SCE_NP_MATCHING2_SORT_METHOD_JOIN_DATE && sortMethod != SCE_NP_MATCHING2_SORT_METHOD_SLOT_NUMBER)
{
return SCE_NP_MATCHING2_ERROR_INVALID_SORT_METHOD;
}
if (!check_match2_context(ctxId))
{
return SCE_NP_MATCHING2_ERROR_CONTEXT_NOT_FOUND;
}
const auto [error, vec_memberids] = nph.local_get_room_memberids(roomId, sortMethod);
if (error)
{
return error;
}
u32 num_members = std::min(memberIdNum, static_cast<u32>(vec_memberids.size()));
for (u32 i = 0; i < num_members; i++)
{
memberId[i] = vec_memberids[i];
}
return not_an_error(num_members);
}
error_code sceNpMatching2JoinRoom(
@@ -814,7 +872,7 @@ error_code sceNpMatching2JoinRoom(
{
sceNp2.warning("sceNpMatching2JoinRoom(ctxId=%d, reqParam=*0x%x, optParam=*0x%x, assignedReqId=*0x%x)", ctxId, reqParam, optParam, assignedReqId);
auto& nph = g_fxo->get<named_thread<np_handler>>();
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
if (auto res = generic_match2_error_check(nph, ctxId, reqParam, assignedReqId); res != CELL_OK)
{
return res;
@@ -826,26 +884,56 @@ error_code sceNpMatching2JoinRoom(
}
error_code sceNpMatching2GetRoomMemberDataInternalLocal(SceNpMatching2ContextId ctxId, SceNpMatching2RoomId roomId, SceNpMatching2RoomMemberId memberId, vm::cptr<SceNpMatching2AttributeId> attrId,
u32 attrIdNum, vm::ptr<SceNpMatching2RoomMemberDataInternal> member, vm::ptr<char> buf, u64 bufLen)
u32 attrIdNum, vm::ptr<SceNpMatching2RoomMemberDataInternal> member, vm::ptr<char> buf, u64 bufLen)
{
sceNp2.todo("sceNpMatching2GetRoomMemberDataInternalLocal(ctxId=%d, roomId=%d, memberId=%d, attrId=*0x%x, attrIdNum=%d, member=*0x%x, buf=*0x%x, bufLen=%d)", ctxId, roomId, memberId, attrId,
attrIdNum, member, buf, bufLen);
sceNp2.warning("sceNpMatching2GetRoomMemberDataInternalLocal(ctxId=%d, roomId=%d, memberId=%d, attrId=*0x%x, attrIdNum=%d, member=*0x%x, buf=*0x%x, bufLen=%d)", ctxId, roomId, memberId, attrId,
attrIdNum, member, buf, bufLen);
auto& nph = g_fxo->get<named_thread<np_handler>>();
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
if (!nph.is_NP2_Match2_init)
{
return SCE_NP_MATCHING2_ERROR_NOT_INITIALIZED;
}
return CELL_OK;
if (!ctxId)
{
return SCE_NP_MATCHING2_ERROR_INVALID_CONTEXT_ID;
}
if (!roomId)
{
return SCE_NP_MATCHING2_ERROR_INVALID_ROOM_ID;
}
if (!memberId)
{
return SCE_NP_MATCHING2_ERROR_INVALID_MEMBER_ID;
}
std::vector<SceNpMatching2AttributeId> binattrs_list;
for (u32 i = 0; i < attrIdNum; i++)
{
if (attrId[i] < SCE_NP_MATCHING2_ROOMMEMBER_BIN_ATTR_INTERNAL_1_ID || attrId[i] >= SCE_NP_MATCHING2_USER_BIN_ATTR_1_ID)
{
return SCE_NP_MATCHING2_ERROR_INVALID_ATTRIBUTE_ID;
}
binattrs_list.push_back(attrId[i]);
}
if (!check_match2_context(ctxId))
{
return SCE_NP_MATCHING2_ERROR_CONTEXT_NOT_FOUND;
}
return nph.local_get_room_member_data(roomId, memberId, binattrs_list, member ? member.get_ptr() : nullptr, buf.addr(), bufLen);
}
error_code sceNpMatching2GetCbQueueInfo(SceNpMatching2ContextId ctxId, vm::ptr<SceNpMatching2CbQueueInfo> queueInfo)
{
sceNp2.todo("sceNpMatching2GetCbQueueInfo(ctxId=%d, queueInfo=*0x%x)", ctxId, queueInfo);
auto& nph = g_fxo->get<named_thread<np_handler>>();
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
if (!nph.is_NP2_Match2_init)
{
@@ -860,7 +948,7 @@ error_code sceNpMatching2KickoutRoomMember(
{
sceNp2.todo("sceNpMatching2KickoutRoomMember(ctxId=%d, reqParam=*0x%x, optParam=*0x%x, assignedReqId=*0x%x)", ctxId, reqParam, optParam, assignedReqId);
auto& nph = g_fxo->get<named_thread<np_handler>>();
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
if (auto res = generic_match2_error_check(nph, ctxId, reqParam, assignedReqId); res != CELL_OK)
{
return res;
@@ -873,7 +961,7 @@ error_code sceNpMatching2ContextStartAsync(SceNpMatching2ContextId ctxId, u32 ti
{
sceNp2.warning("sceNpMatching2ContextStartAsync(ctxId=%d, timeout=%d)", ctxId, timeout);
auto& nph = g_fxo->get<named_thread<np_handler>>();
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
if (!nph.is_NP2_Match2_init)
{
@@ -906,7 +994,7 @@ error_code sceNpMatching2SetSignalingOptParam(
{
sceNp2.todo("sceNpMatching2SetSignalingOptParam(ctxId=%d, reqParam=*0x%x, optParam=*0x%x, assignedReqId=*0x%x)", ctxId, reqParam, optParam, assignedReqId);
auto& nph = g_fxo->get<named_thread<np_handler>>();
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
if (auto res = generic_match2_error_check(nph, ctxId, reqParam, assignedReqId); res != CELL_OK)
{
return res;
@@ -919,7 +1007,7 @@ error_code sceNpMatching2RegisterContextCallback(SceNpMatching2ContextId ctxId,
{
sceNp2.warning("sceNpMatching2RegisterContextCallback(ctxId=%d, cbFunc=*0x%x, cbFuncArg=*0x%x)", ctxId, cbFunc, cbFuncArg);
auto& nph = g_fxo->get<named_thread<np_handler>>();
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
if (!nph.is_NP2_Match2_init)
{
@@ -946,7 +1034,7 @@ error_code sceNpMatching2SendRoomChatMessage(
{
sceNp2.todo("sceNpMatching2SendRoomChatMessage(ctxId=%d, reqParam=*0x%x, optParam=*0x%x, assignedReqId=*0x%x)", ctxId, reqParam, optParam, assignedReqId);
auto& nph = g_fxo->get<named_thread<np_handler>>();
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
if (auto res = generic_match2_error_check(nph, ctxId, reqParam, assignedReqId); res != CELL_OK)
{
return res;
@@ -958,9 +1046,9 @@ error_code sceNpMatching2SendRoomChatMessage(
error_code sceNpMatching2SetRoomDataInternal(
SceNpMatching2ContextId ctxId, vm::cptr<SceNpMatching2SetRoomDataInternalRequest> reqParam, vm::cptr<SceNpMatching2RequestOptParam> optParam, vm::ptr<SceNpMatching2RequestId> assignedReqId)
{
sceNp2.todo("sceNpMatching2SetRoomDataInternal(ctxId=%d, reqParam=*0x%x, optParam=*0x%x, assignedReqId=*0x%x)", ctxId, reqParam, optParam, assignedReqId);
sceNp2.warning("sceNpMatching2SetRoomDataInternal(ctxId=%d, reqParam=*0x%x, optParam=*0x%x, assignedReqId=*0x%x)", ctxId, reqParam, optParam, assignedReqId);
auto& nph = g_fxo->get<named_thread<np_handler>>();
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
if (auto res = generic_match2_error_check(nph, ctxId, reqParam, assignedReqId); res != CELL_OK)
{
return res;
@@ -974,9 +1062,9 @@ error_code sceNpMatching2SetRoomDataInternal(
error_code sceNpMatching2GetRoomDataInternal(
SceNpMatching2ContextId ctxId, vm::cptr<SceNpMatching2GetRoomDataInternalRequest> reqParam, vm::cptr<SceNpMatching2RequestOptParam> optParam, vm::ptr<SceNpMatching2RequestId> assignedReqId)
{
sceNp2.todo("sceNpMatching2GetRoomDataInternal(ctxId=%d, reqParam=*0x%x, optParam=*0x%x, assignedReqId=*0x%x)", ctxId, reqParam, optParam, assignedReqId);
sceNp2.warning("sceNpMatching2GetRoomDataInternal(ctxId=%d, reqParam=*0x%x, optParam=*0x%x, assignedReqId=*0x%x)", ctxId, reqParam, optParam, assignedReqId);
auto& nph = g_fxo->get<named_thread<np_handler>>();
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
if (auto res = generic_match2_error_check(nph, ctxId, reqParam, assignedReqId); res != CELL_OK)
{
return res;
@@ -992,7 +1080,7 @@ error_code sceNpMatching2SignalingGetPingInfo(
{
sceNp2.warning("sceNpMatching2SignalingGetPingInfo(ctxId=%d, reqParam=*0x%x, optParam=*0x%x, assignedReqId=*0x%x)", ctxId, reqParam, optParam, assignedReqId);
auto& nph = g_fxo->get<named_thread<np_handler>>();
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
if (auto res = generic_match2_error_check(nph, ctxId, reqParam, assignedReqId); res != CELL_OK)
{
return res;
@@ -1005,9 +1093,9 @@ error_code sceNpMatching2SignalingGetPingInfo(
error_code sceNpMatching2GetServerIdListLocal(SceNpMatching2ContextId ctxId, vm::ptr<SceNpMatching2ServerId> serverId, u32 serverIdNum)
{
sceNp2.todo("sceNpMatching2GetServerIdListLocal(ctxId=%d, serverId=*0x%x, serverIdNum=%d)", ctxId, serverId, serverIdNum);
sceNp2.notice("sceNpMatching2GetServerIdListLocal(ctxId=%d, serverId=*0x%x, serverIdNum=%d)", ctxId, serverId, serverIdNum);
auto& nph = g_fxo->get<named_thread<np_handler>>();
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
if (!nph.is_NP2_Match2_init)
{
@@ -1057,7 +1145,7 @@ error_code sceNpMatching2GrantRoomOwner(
{
sceNp2.todo("sceNpMatching2GrantRoomOwner(ctxId=%d, reqParam=*0x%x, optParam=*0x%x, assignedReqId=*0x%x)", ctxId, reqParam, optParam, assignedReqId);
auto& nph = g_fxo->get<named_thread<np_handler>>();
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
if (auto res = generic_match2_error_check(nph, ctxId, reqParam, assignedReqId); res != CELL_OK)
{
return res;
@@ -1071,7 +1159,7 @@ error_code sceNpMatching2CreateContext(
{
sceNp2.warning("sceNpMatching2CreateContext(npId=*0x%x, commId=*0x%x(%s), passPhrase=*0x%x, ctxId=*0x%x, option=%d)", npId, commId, commId ? commId->data : "", ctxId, option);
auto& nph = g_fxo->get<named_thread<np_handler>>();
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
if (!nph.is_NP2_Match2_init)
{
@@ -1092,7 +1180,7 @@ error_code sceNpMatching2GetSignalingOptParamLocal(SceNpMatching2ContextId ctxId
{
sceNp2.todo("sceNpMatching2GetSignalingOptParamLocal(ctxId=%d, roomId=%d, signalingOptParam=*0x%x)", ctxId, roomId, signalingOptParam);
auto& nph = g_fxo->get<named_thread<np_handler>>();
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
if (!nph.is_NP2_Match2_init)
{
@@ -1106,7 +1194,7 @@ error_code sceNpMatching2RegisterSignalingCallback(SceNpMatching2ContextId ctxId
{
sceNp2.notice("sceNpMatching2RegisterSignalingCallback(ctxId=%d, cbFunc=*0x%x, cbFuncArg=*0x%x)", ctxId, cbFunc, cbFuncArg);
auto& nph = g_fxo->get<named_thread<np_handler>>();
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
if (!nph.is_NP2_Match2_init)
{
@@ -1123,7 +1211,7 @@ error_code sceNpMatching2ClearEventData(SceNpMatching2ContextId ctxId, SceNpMatc
{
sceNp2.todo("sceNpMatching2ClearEventData(ctxId=%d, eventKey=%d)", ctxId, eventKey);
auto& nph = g_fxo->get<named_thread<np_handler>>();
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
if (!nph.is_NP2_Match2_init)
{
@@ -1138,7 +1226,7 @@ error_code sceNpMatching2GetUserInfoList(
{
sceNp2.todo("sceNpMatching2GetUserInfoList(ctxId=%d, reqParam=*0x%x, optParam=*0x%x, assignedReqId=*0x%x)", ctxId, reqParam, optParam, assignedReqId);
auto& nph = g_fxo->get<named_thread<np_handler>>();
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
if (auto res = generic_match2_error_check(nph, ctxId, reqParam, assignedReqId); res != CELL_OK)
{
return res;
@@ -1152,7 +1240,7 @@ error_code sceNpMatching2GetRoomMemberDataInternal(
{
sceNp2.todo("sceNpMatching2GetRoomMemberDataInternal(ctxId=%d, reqParam=*0x%x, optParam=*0x%x, assignedReqId=*0x%x)", ctxId, reqParam, optParam, assignedReqId);
auto& nph = g_fxo->get<named_thread<np_handler>>();
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
if (auto res = generic_match2_error_check(nph, ctxId, reqParam, assignedReqId); res != CELL_OK)
{
return res;
@@ -1164,14 +1252,16 @@ error_code sceNpMatching2GetRoomMemberDataInternal(
error_code sceNpMatching2SetRoomMemberDataInternal(
SceNpMatching2ContextId ctxId, vm::cptr<SceNpMatching2SetRoomMemberDataInternalRequest> reqParam, vm::cptr<SceNpMatching2RequestOptParam> optParam, vm::ptr<SceNpMatching2RequestId> assignedReqId)
{
sceNp2.todo("sceNpMatching2SetRoomMemberDataInternal(ctxId=%d, reqParam=*0x%x, optParam=*0x%x, assignedReqId=*0x%x)", ctxId, reqParam, optParam, assignedReqId);
sceNp2.warning("sceNpMatching2SetRoomMemberDataInternal(ctxId=%d, reqParam=*0x%x, optParam=*0x%x, assignedReqId=*0x%x)", ctxId, reqParam, optParam, assignedReqId);
auto& nph = g_fxo->get<named_thread<np_handler>>();
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
if (auto res = generic_match2_error_check(nph, ctxId, reqParam, assignedReqId); res != CELL_OK)
{
return res;
}
*assignedReqId = nph.set_roommemberdata_internal(ctxId, optParam, reqParam.get_ptr());
return CELL_OK;
}
@@ -1180,7 +1270,7 @@ error_code sceNpMatching2JoinProhibitiveRoom(
{
sceNp2.warning("sceNpMatching2JoinProhibitiveRoom(ctxId=%d, reqParam=*0x%x, optParam=*0x%x, assignedReqId=*0x%x)", ctxId, reqParam, optParam, assignedReqId);
auto& nph = g_fxo->get<named_thread<np_handler>>();
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
if (auto res = generic_match2_error_check(nph, ctxId, reqParam, assignedReqId); res != CELL_OK)
{
return res;
@@ -1196,7 +1286,7 @@ error_code sceNpMatching2SignalingSetCtxOpt(SceNpMatching2ContextId ctxId, s32 o
{
sceNp2.todo("sceNpMatching2SignalingSetCtxOpt(ctxId=%d, optname=%d, optval=%d)", ctxId, optname, optval);
auto& nph = g_fxo->get<named_thread<np_handler>>();
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
if (!nph.is_NP2_Match2_init)
{
@@ -1209,14 +1299,21 @@ error_code sceNpMatching2SignalingSetCtxOpt(SceNpMatching2ContextId ctxId, s32 o
error_code sceNpMatching2DeleteServerContext(
SceNpMatching2ContextId ctxId, vm::cptr<SceNpMatching2DeleteServerContextRequest> reqParam, vm::cptr<SceNpMatching2RequestOptParam> optParam, vm::ptr<SceNpMatching2RequestId> assignedReqId)
{
sceNp2.todo("sceNpMatching2DeleteServerContext(ctxId=%d, reqParam=*0x%x, optParam=*0x%x, assignedReqId=*0x%x)", ctxId, reqParam, optParam, assignedReqId);
sceNp2.warning("sceNpMatching2DeleteServerContext(ctxId=%d, reqParam=*0x%x, optParam=*0x%x, assignedReqId=*0x%x)", ctxId, reqParam, optParam, assignedReqId);
auto& nph = g_fxo->get<named_thread<np_handler>>();
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
if (auto res = generic_match2_error_check(nph, ctxId, reqParam, assignedReqId); res != CELL_OK)
{
return res;
}
if (reqParam->serverId == 0)
{
return SCE_NP_MATCHING2_ERROR_INVALID_SERVER_ID;
}
*assignedReqId = nph.delete_server_context(ctxId, optParam, reqParam->serverId);
return CELL_OK;
}
@@ -1224,7 +1321,7 @@ error_code sceNpMatching2SetDefaultRequestOptParam(SceNpMatching2ContextId ctxId
{
sceNp2.warning("sceNpMatching2SetDefaultRequestOptParam(ctxId=%d, optParam=*0x%x)", ctxId, optParam);
auto& nph = g_fxo->get<named_thread<np_handler>>();
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
if (!nph.is_NP2_Match2_init)
{
@@ -1249,7 +1346,7 @@ error_code sceNpMatching2RegisterRoomEventCallback(SceNpMatching2ContextId ctxId
{
sceNp2.todo("sceNpMatching2RegisterRoomEventCallback(ctxId=%d, cbFunc=*0x%x, cbFuncArg=*0x%x)", ctxId, cbFunc, cbFuncArg);
auto& nph = g_fxo->get<named_thread<np_handler>>();
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
if (!nph.is_NP2_Match2_init)
{
@@ -1265,24 +1362,56 @@ error_code sceNpMatching2RegisterRoomEventCallback(SceNpMatching2ContextId ctxId
error_code sceNpMatching2GetRoomPasswordLocal(SceNpMatching2ContextId ctxId, SceNpMatching2RoomId roomId, vm::ptr<b8> withPassword, vm::ptr<SceNpMatching2SessionPassword> roomPassword)
{
sceNp2.todo("sceNpMatching2GetRoomPasswordLocal(ctxId=%d, roomId=%d, withPassword=*0x%x, roomPassword=*0x%x)", ctxId, roomId, withPassword, roomPassword);
sceNp2.notice("sceNpMatching2GetRoomPasswordLocal(ctxId=%d, roomId=%d, withPassword=*0x%x, roomPassword=*0x%x)", ctxId, roomId, withPassword, roomPassword);
auto& nph = g_fxo->get<named_thread<np_handler>>();
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
if (!nph.is_NP2_Match2_init)
{
return SCE_NP_MATCHING2_ERROR_NOT_INITIALIZED;
}
if (!ctxId)
{
return SCE_NP_MATCHING2_ERROR_INVALID_CONTEXT_ID;
}
if (!roomId)
{
return SCE_NP_MATCHING2_ERROR_INVALID_ROOM_ID;
}
if (!check_match2_context(ctxId))
{
return SCE_NP_MATCHING2_ERROR_CONTEXT_NOT_FOUND;
}
const auto [error, password] = nph.local_get_room_password(roomId);
if (error)
{
return error;
}
if (password)
{
*withPassword = true;
memcpy(roomPassword.get_ptr(), &*password, sizeof(SceNpMatching2SessionPassword));
}
else
{
*withPassword = false;
}
return CELL_OK;
}
error_code sceNpMatching2GetRoomDataExternalList(
SceNpMatching2ContextId ctxId, vm::cptr<SceNpMatching2GetRoomDataExternalListRequest> reqParam, vm::cptr<SceNpMatching2RequestOptParam> optParam, vm::ptr<SceNpMatching2RequestId> assignedReqId)
{
sceNp2.todo("sceNpMatching2GetRoomDataExternalList(ctxId=%d, reqParam=*0x%x, optParam=*0x%x, assignedReqId=*0x%x)", ctxId, reqParam, optParam, assignedReqId);
sceNp2.warning("sceNpMatching2GetRoomDataExternalList(ctxId=%d, reqParam=*0x%x, optParam=*0x%x, assignedReqId=*0x%x)", ctxId, reqParam, optParam, assignedReqId);
auto& nph = g_fxo->get<named_thread<np_handler>>();
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
if (auto res = generic_match2_error_check(nph, ctxId, reqParam, assignedReqId); res != CELL_OK)
{
return res;
@@ -1298,7 +1427,7 @@ error_code sceNpMatching2CreateJoinRoom(
{
sceNp2.warning("sceNpMatching2CreateJoinRoom(ctxId=%d, reqParam=*0x%x, optParam=*0x%x, assignedReqId=*0x%x)", ctxId, reqParam, optParam, assignedReqId);
auto& nph = g_fxo->get<named_thread<np_handler>>();
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
if (auto res = generic_match2_error_check(nph, ctxId, reqParam, assignedReqId); res != CELL_OK)
{
return res;
@@ -1313,7 +1442,7 @@ error_code sceNpMatching2SignalingGetCtxOpt(SceNpMatching2ContextId ctxId, s32 o
{
sceNp2.todo("sceNpMatching2SignalingGetCtxOpt(ctxId=%d, optname=%d, optval=*0x%x)", ctxId, optname, optval);
auto& nph = g_fxo->get<named_thread<np_handler>>();
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
if (!nph.is_NP2_Match2_init)
{
@@ -1328,7 +1457,7 @@ error_code sceNpMatching2GetLobbyInfoList(
{
sceNp2.todo("sceNpMatching2GetLobbyInfoList(ctxId=%d, reqParam=*0x%x, optParam=*0x%x, assignedReqId=*0x%x)", ctxId, reqParam, optParam, assignedReqId);
auto& nph = g_fxo->get<named_thread<np_handler>>();
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
if (auto res = generic_match2_error_check(nph, ctxId, reqParam, assignedReqId); res != CELL_OK)
{
return res;
@@ -1342,7 +1471,7 @@ error_code sceNpMatching2GetLobbyMemberIdListLocal(
{
sceNp2.todo("sceNpMatching2GetLobbyMemberIdListLocal(ctxId=%d, lobbyId=%d, memberId=*0x%x, memberIdNum=%d, me=*0x%x)", ctxId, lobbyId, memberId, memberIdNum, me);
auto& nph = g_fxo->get<named_thread<np_handler>>();
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
if (!nph.is_NP2_Match2_init)
{
@@ -1357,7 +1486,7 @@ error_code sceNpMatching2SendLobbyInvitation(
{
sceNp2.todo("sceNpMatching2SendLobbyInvitation(ctxId=%d, reqParam=*0x%x, optParam=*0x%x, assignedReqId=*0x%x)", ctxId, reqParam, optParam, assignedReqId);
auto& nph = g_fxo->get<named_thread<np_handler>>();
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
if (auto res = generic_match2_error_check(nph, ctxId, reqParam, assignedReqId); res != CELL_OK)
{
return res;
@@ -1370,7 +1499,7 @@ error_code sceNpMatching2ContextStop(SceNpMatching2ContextId ctxId)
{
sceNp2.todo("sceNpMatching2ContextStop(ctxId=%d)", ctxId);
auto& nph = g_fxo->get<named_thread<np_handler>>();
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
if (!nph.is_NP2_Match2_init)
{
@@ -1401,7 +1530,7 @@ error_code sceNpMatching2SetLobbyMemberDataInternal(
{
sceNp2.todo("sceNpMatching2SetLobbyMemberDataInternal(ctxId=%d, reqParam=*0x%x, optParam=*0x%x, assignedReqId=*0x%x)", ctxId, reqParam, optParam, assignedReqId);
auto& nph = g_fxo->get<named_thread<np_handler>>();
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
if (auto res = generic_match2_error_check(nph, ctxId, reqParam, assignedReqId); res != CELL_OK)
{
return res;
@@ -1414,7 +1543,7 @@ error_code sceNpMatching2RegisterRoomMessageCallback(SceNpMatching2ContextId ctx
{
sceNp2.todo("sceNpMatching2RegisterRoomMessageCallback(ctxId=%d, cbFunc=*0x%x, cbFuncArg=*0x%x)", ctxId, cbFunc, cbFuncArg);
auto& nph = g_fxo->get<named_thread<np_handler>>();
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
if (!nph.is_NP2_Match2_init)
{
@@ -1432,7 +1561,7 @@ error_code sceNpMatching2SignalingCancelPeerNetInfo(SceNpMatching2ContextId ctxI
{
sceNp2.todo("sceNpMatching2SignalingCancelPeerNetInfo(ctxId=%d, reqId=%d)", ctxId, reqId);
auto& nph = g_fxo->get<named_thread<np_handler>>();
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
if (!nph.is_NP2_Match2_init)
{
@@ -1446,7 +1575,7 @@ error_code sceNpMatching2SignalingGetLocalNetInfo(vm::ptr<SceNpMatching2Signalin
{
sceNp2.todo("sceNpMatching2SignalingGetLocalNetInfo(netinfo=*0x%x)", netinfo);
auto& nph = g_fxo->get<named_thread<np_handler>>();
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
if (!nph.is_NP2_Match2_init)
{
@@ -1466,7 +1595,7 @@ error_code sceNpMatching2SignalingGetPeerNetInfo(SceNpMatching2ContextId ctxId,
{
sceNp2.todo("sceNpMatching2SignalingGetPeerNetInfo(ctxId=%d, roomId=%d, roomMemberId=%d, reqId=*0x%x)", ctxId, roomId, roomMemberId, reqId);
auto& nph = g_fxo->get<named_thread<np_handler>>();
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
if (!nph.is_NP2_Match2_init)
{
@@ -1485,7 +1614,7 @@ error_code sceNpMatching2SignalingGetPeerNetInfoResult(SceNpMatching2ContextId c
{
sceNp2.todo("sceNpMatching2SignalingGetPeerNetInfoResult(ctxId=%d, reqId=%d, netinfo=*0x%x)", ctxId, reqId, netinfo);
auto& nph = g_fxo->get<named_thread<np_handler>>();
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
if (!nph.is_NP2_Match2_init)
{
@@ -1505,7 +1634,7 @@ error_code sceNpAuthOAuthInit()
{
sceNp2.todo("sceNpAuthOAuthInit()");
auto& nph = g_fxo->get<named_thread<np_handler>>();
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
if (nph.is_NP_Auth_init)
{
@@ -1521,7 +1650,7 @@ error_code sceNpAuthOAuthTerm()
{
sceNp2.todo("sceNpAuthOAuthTerm()");
auto& nph = g_fxo->get<named_thread<np_handler>>();
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
// TODO: check if this might throw SCE_NP_OAUTH_ERROR_NOT_INITIALIZED
nph.is_NP_Auth_init = false;
@@ -1533,7 +1662,7 @@ error_code sceNpAuthCreateOAuthRequest()
{
sceNp2.todo("sceNpAuthCreateOAuthRequest()");
auto& nph = g_fxo->get<named_thread<np_handler>>();
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
if (!nph.is_NP_Auth_init)
{
@@ -1547,7 +1676,7 @@ error_code sceNpAuthDeleteOAuthRequest(SceNpAuthOAuthRequestId reqId)
{
sceNp2.todo("sceNpAuthDeleteOAuthRequest(reqId=%d)", reqId);
auto& nph = g_fxo->get<named_thread<np_handler>>();
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
if (!nph.is_NP_Auth_init)
{
@@ -1561,7 +1690,7 @@ error_code sceNpAuthAbortOAuthRequest(SceNpAuthOAuthRequestId reqId)
{
sceNp2.todo("sceNpAuthAbortOAuthRequest(reqId=%d)", reqId);
auto& nph = g_fxo->get<named_thread<np_handler>>();
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
if (!nph.is_NP_Auth_init)
{
@@ -1575,7 +1704,7 @@ error_code sceNpAuthGetAuthorizationCode(SceNpAuthOAuthRequestId reqId, vm::cptr
{
sceNp2.todo("sceNpAuthGetAuthorizationCode(reqId=%d, param=*0x%x, authCode=*0x%x, issuerId=%d)", reqId, param, authCode, issuerId);
auto& nph = g_fxo->get<named_thread<np_handler>>();
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
if (!nph.is_NP_Auth_init)
{
+4 -4
View File
@@ -1388,9 +1388,9 @@ struct SceNpMatching2RoomDataInternalUpdateInfo
vm::bptr<SceNpMatching2FlagAttr> prevFlagAttr;
vm::bptr<SceNpMatching2RoomPasswordSlotMask> newRoomPasswordSlotMask;
vm::bptr<SceNpMatching2RoomPasswordSlotMask> prevRoomPasswordSlotMask;
vm::pptr<SceNpMatching2RoomGroup> newRoomGroup;
vm::bpptr<SceNpMatching2RoomGroup> newRoomGroup;
be_t<u32> newRoomGroupNum;
vm::pptr<SceNpMatching2RoomBinAttrInternal> newRoomBinAttrInternal;
vm::bpptr<SceNpMatching2RoomBinAttrInternal> newRoomBinAttrInternal;
be_t<u32> newRoomBinAttrInternalNum;
};
@@ -1401,7 +1401,7 @@ struct SceNpMatching2RoomMemberDataInternalUpdateInfo
vm::bptr<SceNpMatching2FlagAttr> newFlagAttr;
vm::bptr<SceNpMatching2FlagAttr> prevFlagAttr;
vm::bptr<SceNpMatching2TeamId> newTeamId;
vm::pptr<SceNpMatching2RoomMemberBinAttrInternal> newRoomMemberBinAttrInternal;
vm::bpptr<SceNpMatching2RoomMemberBinAttrInternal> newRoomMemberBinAttrInternal;
be_t<u32> newRoomMemberBinAttrInternalNum;
};
@@ -1413,7 +1413,7 @@ struct SceNpMatching2RoomMessageInfo
u8 padding[2];
vm::bptr<SceNpMatching2RoomMessageDestination> dst;
vm::bptr<SceNpUserInfo2> srcMember;
vm::bcptr<void> msg;
vm::bptr<void> msg;
be_t<u32> msgLen;
};
+2 -2
View File
@@ -179,7 +179,7 @@ error_code sceNpSnsFbGetAccessToken(u32 handle, vm::cptr<SceNpSnsFbAccessTokenPa
return SCE_NP_SNS_FB_ERROR_UNKNOWN_HANDLE;
}
auto& nph = g_fxo->get<named_thread<np_handler>>();
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
if (nph.get_psn_status() == SCE_NP_MANAGER_STATUS_OFFLINE)
{
@@ -306,7 +306,7 @@ error_code sceNpSnsFbGetLongAccessToken(u32 handle, vm::cptr<SceNpSnsFbAccessTok
return SCE_NP_SNS_FB_ERROR_UNKNOWN_HANDLE;
}
auto& nph = g_fxo->get<named_thread<np_handler>>();
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
if (nph.get_psn_status() == SCE_NP_MANAGER_STATUS_OFFLINE)
{
+1
View File
@@ -24,6 +24,7 @@ void fmt_class_string<ppu_attr>::format(std::string& out, u64 arg)
case ppu_attr::known_size: return "known_size";
case ppu_attr::no_return: return "no_return";
case ppu_attr::no_size: return "no_size";
case ppu_attr::has_mfvscr: return "has_mfvscr";
case ppu_attr::__bitset_enum_max: break;
}
+1
View File
@@ -16,6 +16,7 @@ enum class ppu_attr : u32
known_size,
no_return,
no_size,
has_mfvscr,
__bitset_enum_max
};
+3 -3
View File
@@ -1910,14 +1910,14 @@ std::vector<ppu_function_t>& ppu_function_manager::access(bool ghc)
static std::vector<ppu_function_t> list_ghc
{
build_function_asm<ppu_function_t>([](asmjit::X86Assembler& c, auto& args)
build_function_asm<ppu_function_t>("ppu_unregistered", [](asmjit::x86::Assembler& c, auto& args)
{
using namespace asmjit;
c.mov(args[0], x86::rbp);
c.jmp(imm_ptr(list[0]));
}),
build_function_asm<ppu_function_t>([](asmjit::X86Assembler& c, auto& args)
build_function_asm<ppu_function_t>("ppu_return", [](asmjit::x86::Assembler& c, auto& args)
{
using namespace asmjit;
@@ -1937,7 +1937,7 @@ u32 ppu_function_manager::add_function(ppu_function_t function)
list.push_back(function);
// Generate trampoline
list2.push_back(build_function_asm<ppu_function_t>([&](asmjit::X86Assembler& c, auto& args)
list2.push_back(build_function_asm<ppu_function_t>("ppu_trampolinea", [&](asmjit::x86::Assembler& c, auto& args)
{
using namespace asmjit;
+60 -60
View File
@@ -528,14 +528,14 @@ inline v128 vec_handle_denormal(ppu_thread& ppu, v128 a)
bool ppu_interpreter::MFVSCR(ppu_thread& ppu, ppu_opcode_t op)
{
ppu.vr[op.vd] = v128::from32(0, 0, 0, u32{ppu.sat} | (u32{ppu.nj} << 16));
ppu.vr[op.vd] = v128::from32(0, 0, 0, u32{ppu.sat != v128{}} | (u32{ppu.nj} << 16));
return true;
}
bool ppu_interpreter::MTVSCR(ppu_thread& ppu, ppu_opcode_t op)
{
const u32 vscr = ppu.vr[op.vb]._u32[3];
ppu.sat = (vscr & 1) != 0;
ppu.sat = v128::from32((vscr & 1) != 0);
ppu.nj = (vscr & 0x10000) != 0;
ppu.jm_mask = ppu.nj ? ppu_inf_u32 : 0x7fff'ffff;
return true;
@@ -577,12 +577,12 @@ bool ppu_interpreter_precise::VADDSBS(ppu_thread& ppu, ppu_opcode_t op)
if (sum < INT8_MIN)
{
d._s8[i] = INT8_MIN;
ppu.sat = true;
ppu.sat._u32[0] = 1;
}
else if (sum > INT8_MAX)
{
d._s8[i] = INT8_MAX;
ppu.sat = true;
ppu.sat._u32[0] = 1;
}
else
{
@@ -612,12 +612,12 @@ bool ppu_interpreter_precise::VADDSHS(ppu_thread& ppu, ppu_opcode_t op)
if (sum < INT16_MIN)
{
d._s16[i] = INT16_MIN;
ppu.sat = true;
ppu.sat._u32[0] = 1;
}
else if (sum > INT16_MAX)
{
d._s16[i] = INT16_MAX;
ppu.sat = true;
ppu.sat._u32[0] = 1;
}
else
{
@@ -654,12 +654,12 @@ bool ppu_interpreter_precise::VADDSWS(ppu_thread& ppu, ppu_opcode_t op)
if (sum < INT32_MIN)
{
d._s32[i] = INT32_MIN;
ppu.sat = true;
ppu.sat._u32[0] = 1;
}
else if (sum > INT32_MAX)
{
d._s32[i] = INT32_MAX;
ppu.sat = true;
ppu.sat._u32[0] = 1;
}
else
{
@@ -695,7 +695,7 @@ bool ppu_interpreter_precise::VADDUBS(ppu_thread& ppu, ppu_opcode_t op)
if (sum > UINT8_MAX)
{
d._u8[i] = UINT8_MAX;
ppu.sat = true;
ppu.sat._u32[0] = 1;
}
else
{
@@ -731,7 +731,7 @@ bool ppu_interpreter_precise::VADDUHS(ppu_thread& ppu, ppu_opcode_t op)
if (sum > UINT16_MAX)
{
d._u16[i] = UINT16_MAX;
ppu.sat = true;
ppu.sat._u32[0] = 1;
}
else
{
@@ -770,7 +770,7 @@ bool ppu_interpreter_precise::VADDUWS(ppu_thread& ppu, ppu_opcode_t op)
if (sum > UINT32_MAX)
{
d._u32[i] = UINT32_MAX;
ppu.sat = true;
ppu.sat._u32[0] = 1;
}
else
{
@@ -988,13 +988,13 @@ bool ppu_interpreter_precise::VCTSXS(ppu_thread& ppu, ppu_opcode_t op)
}
else
{
ppu.sat = true;
ppu.sat._u32[0] = 1;
d._s32[i] = sign ? 0x80000000 : 0x7FFFFFFF;
}
}
else if (exp2 > 30)
{
ppu.sat = true;
ppu.sat._u32[0] = 1;
d._s32[i] = sign ? 0x80000000 : 0x7FFFFFFF;
}
else if (exp2 < 0)
@@ -1041,13 +1041,13 @@ bool ppu_interpreter_precise::VCTUXS(ppu_thread& ppu, ppu_opcode_t op)
}
else
{
ppu.sat = true;
ppu.sat._u32[0] = 1;
d._u32[i] = sign ? 0 : 0xFFFFFFFF;
}
}
else if (exp2 > 31)
{
ppu.sat = true;
ppu.sat._u32[0] = 1;
d._u32[i] = sign ? 0 : 0xFFFFFFFF;
}
else if (exp2 < 0)
@@ -1056,7 +1056,7 @@ bool ppu_interpreter_precise::VCTUXS(ppu_thread& ppu, ppu_opcode_t op)
}
else if (sign)
{
ppu.sat = true;
ppu.sat._u32[0] = 1;
d._u32[i] = 0;
}
else
@@ -1180,12 +1180,12 @@ bool ppu_interpreter_precise::VMHADDSHS(ppu_thread& ppu, ppu_opcode_t op)
if (sum < INT16_MIN)
{
d._s16[i] = INT16_MIN;
ppu.sat = true;
ppu.sat._u32[0] = 1;
}
else if (sum > INT16_MAX)
{
d._s16[i] = INT16_MAX;
ppu.sat = true;
ppu.sat._u32[0] = 1;
}
else
{
@@ -1229,12 +1229,12 @@ bool ppu_interpreter_precise::VMHRADDSHS(ppu_thread& ppu, ppu_opcode_t op)
if (sum < INT16_MIN)
{
d._s16[i] = INT16_MIN;
ppu.sat = true;
ppu.sat._u32[0] = 1;
}
else if (sum > INT16_MAX)
{
d._s16[i] = INT16_MAX;
ppu.sat = true;
ppu.sat._u32[0] = 1;
}
else
{
@@ -1420,12 +1420,12 @@ bool ppu_interpreter_precise::VMSUMSHS(ppu_thread& ppu, ppu_opcode_t op)
if (result > 0x7fffffff)
{
saturated = 0x7fffffff;
ppu.sat = true;
ppu.sat._u32[0] = 1;
}
else if (result < INT32_MIN)
{
saturated = 0x80000000;
ppu.sat = true;
ppu.sat._u32[0] = 1;
}
else
saturated = static_cast<s32>(result);
@@ -1517,7 +1517,7 @@ bool ppu_interpreter_precise::VMSUMUHS(ppu_thread& ppu, ppu_opcode_t op)
if (result > 0xffffffffu)
{
saturated = 0xffffffff;
ppu.sat = true;
ppu.sat._u32[0] = 1;
}
else
saturated = static_cast<u32>(result);
@@ -1666,12 +1666,12 @@ bool ppu_interpreter_precise::VPKSHSS(ppu_thread& ppu, ppu_opcode_t op)
if (result < INT8_MIN)
{
d._s8[i + 8] = INT8_MIN;
ppu.sat = true;
ppu.sat._u32[0] = 1;
}
else if (result > INT8_MAX)
{
d._s8[i + 8] = INT8_MAX;
ppu.sat = true;
ppu.sat._u32[0] = 1;
}
else
{
@@ -1683,12 +1683,12 @@ bool ppu_interpreter_precise::VPKSHSS(ppu_thread& ppu, ppu_opcode_t op)
if (result < INT8_MIN)
{
d._s8[i] = INT8_MIN;
ppu.sat = true;
ppu.sat._u32[0] = 1;
}
else if (result > INT8_MAX)
{
d._s8[i] = INT8_MAX;
ppu.sat = true;
ppu.sat._u32[0] = 1;
}
else
{
@@ -1717,7 +1717,7 @@ bool ppu_interpreter_precise::VPKSHUS(ppu_thread& ppu, ppu_opcode_t op)
const auto all_bits = a | b;
if ((all_bits._u64[0] | all_bits._u64[1]) & mask)
{
ppu.sat = true;
ppu.sat._u32[0] = 1;
}
}
@@ -1744,12 +1744,12 @@ bool ppu_interpreter_precise::VPKSWSS(ppu_thread& ppu, ppu_opcode_t op)
if (result < INT16_MIN)
{
d._s16[i + 4] = INT16_MIN;
ppu.sat = true;
ppu.sat._u32[0] = 1;
}
else if (result > INT16_MAX)
{
d._s16[i + 4] = INT16_MAX;
ppu.sat = true;
ppu.sat._u32[0] = 1;
}
else
{
@@ -1761,12 +1761,12 @@ bool ppu_interpreter_precise::VPKSWSS(ppu_thread& ppu, ppu_opcode_t op)
if (result < INT16_MIN)
{
d._s16[i] = INT16_MIN;
ppu.sat = true;
ppu.sat._u32[0] = 1;
}
else if (result > INT16_MAX)
{
d._s16[i] = INT16_MAX;
ppu.sat = true;
ppu.sat._u32[0] = 1;
}
else
{
@@ -1828,12 +1828,12 @@ bool ppu_interpreter_precise::VPKSWUS(ppu_thread& ppu, ppu_opcode_t op)
if (result > UINT16_MAX)
{
result = UINT16_MAX;
ppu.sat = true;
ppu.sat._u32[0] = 1;
}
else if (result < 0)
{
result = 0;
ppu.sat = true;
ppu.sat._u32[0] = 1;
}
d._u16[h + 4] = result;
@@ -1843,12 +1843,12 @@ bool ppu_interpreter_precise::VPKSWUS(ppu_thread& ppu, ppu_opcode_t op)
if (result > UINT16_MAX)
{
result = UINT16_MAX;
ppu.sat = true;
ppu.sat._u32[0] = 1;
}
else if (result < 0)
{
result = 0;
ppu.sat = true;
ppu.sat._u32[0] = 1;
}
d._u16[h] = result;
@@ -1909,7 +1909,7 @@ bool ppu_interpreter_precise::VPKUHUS(ppu_thread& ppu, ppu_opcode_t op)
if (result > UINT8_MAX)
{
result = UINT8_MAX;
ppu.sat = true;
ppu.sat._u32[0] = 1;
}
d._u8[b + 8] = static_cast<u8>(result);
@@ -1919,7 +1919,7 @@ bool ppu_interpreter_precise::VPKUHUS(ppu_thread& ppu, ppu_opcode_t op)
if (result > UINT8_MAX)
{
result = UINT8_MAX;
ppu.sat = true;
ppu.sat._u32[0] = 1;
}
d._u8[b] = static_cast<u8>(result);
@@ -1980,7 +1980,7 @@ bool ppu_interpreter_precise::VPKUWUS(ppu_thread& ppu, ppu_opcode_t op)
if (result > UINT16_MAX)
{
result = UINT16_MAX;
ppu.sat = true;
ppu.sat._u32[0] = 1;
}
d._u16[h + 4] = result;
@@ -1990,7 +1990,7 @@ bool ppu_interpreter_precise::VPKUWUS(ppu_thread& ppu, ppu_opcode_t op)
if (result > UINT16_MAX)
{
result = UINT16_MAX;
ppu.sat = true;
ppu.sat._u32[0] = 1;
}
d._u16[h] = result;
@@ -2430,12 +2430,12 @@ bool ppu_interpreter_precise::VSUBSBS(ppu_thread& ppu, ppu_opcode_t op)
if (diff < INT8_MIN)
{
d._s8[i] = INT8_MIN;
ppu.sat = true;
ppu.sat._u32[0] = 1;
}
else if (diff > INT8_MAX)
{
d._s8[i] = INT8_MAX;
ppu.sat = true;
ppu.sat._u32[0] = 1;
}
else
{
@@ -2465,12 +2465,12 @@ bool ppu_interpreter_precise::VSUBSHS(ppu_thread& ppu, ppu_opcode_t op)
if (diff < INT16_MIN)
{
d._s16[i] = INT16_MIN;
ppu.sat = true;
ppu.sat._u32[0] = 1;
}
else if (diff > INT16_MAX)
{
d._s16[i] = INT16_MAX;
ppu.sat = true;
ppu.sat._u32[0] = 1;
}
else
{
@@ -2518,12 +2518,12 @@ bool ppu_interpreter_precise::VSUBSWS(ppu_thread& ppu, ppu_opcode_t op)
if (result < INT32_MIN)
{
d._s32[w] = INT32_MIN;
ppu.sat = true;
ppu.sat._u32[0] = 1;
}
else if (result > INT32_MAX)
{
d._s32[w] = INT32_MAX;
ppu.sat = true;
ppu.sat._u32[0] = 1;
}
else
d._s32[w] = static_cast<s32>(result);
@@ -2556,12 +2556,12 @@ bool ppu_interpreter_precise::VSUBUBS(ppu_thread& ppu, ppu_opcode_t op)
if (diff < 0)
{
d._u8[i] = 0;
ppu.sat = true;
ppu.sat._u32[0] = 1;
}
else if (diff > UINT8_MAX)
{
d._u8[i] = UINT8_MAX;
ppu.sat = true;
ppu.sat._u32[0] = 1;
}
else
{
@@ -2597,12 +2597,12 @@ bool ppu_interpreter_precise::VSUBUHS(ppu_thread& ppu, ppu_opcode_t op)
if (diff < 0)
{
d._u16[i] = 0;
ppu.sat = true;
ppu.sat._u32[0] = 1;
}
else if (diff > UINT16_MAX)
{
d._u16[i] = UINT16_MAX;
ppu.sat = true;
ppu.sat._u32[0] = 1;
}
else
{
@@ -2652,7 +2652,7 @@ bool ppu_interpreter_precise::VSUBUWS(ppu_thread& ppu, ppu_opcode_t op)
if (result < 0)
{
d._u32[w] = 0;
ppu.sat = true;
ppu.sat._u32[0] = 1;
}
else
d._u32[w] = static_cast<u32>(result);
@@ -2704,12 +2704,12 @@ bool ppu_interpreter_precise::VSUMSWS(ppu_thread& ppu, ppu_opcode_t op)
if (sum > INT32_MAX)
{
d._s32[0] = INT32_MAX;
ppu.sat = true;
ppu.sat._u32[0] = 1;
}
else if (sum < INT32_MIN)
{
d._s32[0] = INT32_MIN;
ppu.sat = true;
ppu.sat._u32[0] = 1;
}
else
d._s32[0] = static_cast<s32>(sum);
@@ -2756,12 +2756,12 @@ bool ppu_interpreter_precise::VSUM2SWS(ppu_thread& ppu, ppu_opcode_t op)
if (sum > INT32_MAX)
{
d._s32[n * 2] = INT32_MAX;
ppu.sat = true;
ppu.sat._u32[0] = 1;
}
else if (sum < INT32_MIN)
{
d._s32[n * 2] = INT32_MIN;
ppu.sat = true;
ppu.sat._u32[0] = 1;
}
else
d._s32[n * 2] = static_cast<s32>(sum);
@@ -2820,12 +2820,12 @@ bool ppu_interpreter_precise::VSUM4SBS(ppu_thread& ppu, ppu_opcode_t op)
if (sum > INT32_MAX)
{
d._s32[w] = INT32_MAX;
ppu.sat = true;
ppu.sat._u32[0] = 1;
}
else if (sum < INT32_MIN)
{
d._s32[w] = INT32_MIN;
ppu.sat = true;
ppu.sat._u32[0] = 1;
}
else
d._s32[w] = static_cast<s32>(sum);
@@ -2880,12 +2880,12 @@ bool ppu_interpreter_precise::VSUM4SHS(ppu_thread& ppu, ppu_opcode_t op)
if (sum > INT32_MAX)
{
d._s32[w] = INT32_MAX;
ppu.sat = true;
ppu.sat._u32[0] = 1;
}
else if (sum < INT32_MIN)
{
d._s32[w] = INT32_MIN;
ppu.sat = true;
ppu.sat._u32[0] = 1;
}
else
d._s32[w] = static_cast<s32>(sum);
@@ -2936,7 +2936,7 @@ bool ppu_interpreter_precise::VSUM4UBS(ppu_thread& ppu, ppu_opcode_t op)
if (sum > UINT32_MAX)
{
d._u32[w] = UINT32_MAX;
ppu.sat = true;
ppu.sat._u32[0] = 1;
}
else
d._u32[w] = static_cast<u32>(sum);
+150 -227
View File
@@ -65,8 +65,6 @@
#include "util/v128sse.hpp"
#include "util/sysinfo.hpp"
const bool s_use_ssse3 = utils::has_ssse3();
extern atomic_t<u64> g_watchdog_hold_ctr;
// Should be of the same type
@@ -149,7 +147,7 @@ static bool ppu_break(ppu_thread& ppu, ppu_opcode_t op);
extern void do_cell_atomic_128_store(u32 addr, const void* to_write);
const auto ppu_gateway = build_function_asm<void(*)(ppu_thread*)>([](asmjit::X86Assembler& c, auto& args)
const auto ppu_gateway = built_function<void(*)(ppu_thread*)>("ppu_gateway", [](asmjit::x86::Assembler& c, auto& args)
{
// Gateway for PPU, converts from native to GHC calling convention, also saves RSP value for escape
using namespace asmjit;
@@ -250,7 +248,7 @@ const auto ppu_gateway = build_function_asm<void(*)(ppu_thread*)>([](asmjit::X86
c.ret();
});
const extern auto ppu_escape = build_function_asm<void(*)(ppu_thread*)>([](asmjit::X86Assembler& c, auto& args)
const extern auto ppu_escape = build_function_asm<void(*)(ppu_thread*)>("ppu_escape", [](asmjit::x86::Assembler& c, auto& args)
{
using namespace asmjit;
@@ -258,12 +256,13 @@ const extern auto ppu_escape = build_function_asm<void(*)(ppu_thread*)>([](asmji
c.mov(x86::rsp, x86::qword_ptr(args[0], ::offset32(&ppu_thread::saved_native_sp)));
// Return to the return location
c.jmp(x86::qword_ptr(x86::rsp, -8));
c.sub(x86::rsp, 8);
c.ret();
});
void ppu_recompiler_fallback(ppu_thread& ppu);
const auto ppu_recompiler_fallback_ghc = build_function_asm<void(*)(ppu_thread& ppu)>([](asmjit::X86Assembler& c, auto& args)
const auto ppu_recompiler_fallback_ghc = build_function_asm<void(*)(ppu_thread& ppu)>("ppu_trampolineb", [](asmjit::x86::Assembler& c, auto& args)
{
using namespace asmjit;
@@ -551,7 +550,7 @@ struct ppu_far_jumps_t
auto& opd = vm::_ref<ppu_func_opd_t>(target);
target = opd.addr;
// We modify LR to custom values here
// We modify LR to custom values here
link = false;
if (ppu)
@@ -566,7 +565,7 @@ struct ppu_far_jumps_t
saved_info.saved_lr = std::exchange(ppu->lr, FIND_FUNC(ppu_return_from_far_jump));
saved_info.saved_r2 = std::exchange(ppu->gpr[2], opd.rtoc);
}
}
if (link && ppu)
@@ -973,11 +972,43 @@ std::string ppu_thread::dump_regs() const
fmt::append(ret, "XER: [CA=%u | OV=%u | SO=%u | CNT=%u]\n", xer.ca, xer.ov, xer.so, xer.cnt);
fmt::append(ret, "VSCR: [SAT=%u | NJ=%u]\n", sat, nj);
fmt::append(ret, "FPSCR: [FL=%u | FG=%u | FE=%u | FU=%u]\n", fpscr.fl, fpscr.fg, fpscr.fe, fpscr.fu);
if (const u32 addr = raddr)
const u32 addr = raddr;
if (addr)
fmt::append(ret, "Reservation Addr: 0x%x", addr);
else
fmt::append(ret, "Reservation Addr: none");
fmt::append(ret, "Reservation Data (entire cache line):\n");
be_t<u32> data[32]{};
std::memcpy(data, rdata, sizeof(rdata)); // Show the data even if the reservation was lost inside the atomic loop
if (addr && !use_full_rdata)
{
const u32 offset = addr & 0x78;
fmt::append(ret, "[0x%02x] %08x %08x\n", offset, data[offset / sizeof(u32)], data[offset / sizeof(u32) + 1]);
// Asterisk marks the offset of data that had been given to the guest PPU code
*(&ret.back() - (addr & 4 ? 9 : 18)) = '*';
}
else
{
for (usz i = 0; i < std::size(data); i += 4)
{
fmt::append(ret, "[0x%02x] %08x %08x %08x %08x\n", i * sizeof(data[0])
, data[i + 0], data[i + 1], data[i + 2], data[i + 3]);
}
if (addr)
{
// See the note above
*(&ret.back() - (4 - (addr % 16 / 4)) * 9 - (8 - (addr % 128 / 16)) * std::size("[0x00]"sv)) = '*';
}
}
return ret;
}
@@ -1609,21 +1640,6 @@ void ppu_thread::stack_pop_verbose(u32 addr, u32 size) noexcept
extern ppu_function_t ppu_get_syscall(u64 code);
extern __m128 sse_exp2_ps(__m128 A);
extern __m128 sse_log2_ps(__m128 A);
extern __m128i sse_altivec_vperm(__m128i A, __m128i B, __m128i C);
extern __m128i sse_altivec_vperm_v0(__m128i A, __m128i B, __m128i C);
extern __m128i sse_altivec_lvsl(u64 addr);
extern __m128i sse_altivec_lvsr(u64 addr);
extern __m128i sse_cellbe_lvlx(u64 addr);
extern __m128i sse_cellbe_lvrx(u64 addr);
extern void sse_cellbe_stvlx(u64 addr, __m128i a);
extern void sse_cellbe_stvrx(u64 addr, __m128i a);
extern __m128i sse_cellbe_lvlx_v0(u64 addr);
extern __m128i sse_cellbe_lvrx_v0(u64 addr);
extern void sse_cellbe_stvlx_v0(u64 addr, __m128i a);
extern void sse_cellbe_stvrx_v0(u64 addr, __m128i a);
void ppu_trap(ppu_thread& ppu, u64 addr)
{
ensure((addr & (~u64{0xffff'ffff} | 0x3)) == 0);
@@ -1801,15 +1817,13 @@ extern u64 ppu_ldarx(ppu_thread& ppu, u32 addr)
return ppu_load_acquire_reservation<u64>(ppu, addr);
}
const auto ppu_stcx_accurate_tx = build_function_asm<u64(*)(u32 raddr, u64 rtime, const void* _old, u64 _new)>([](asmjit::X86Assembler& c, auto& args)
const auto ppu_stcx_accurate_tx = built_function<u64(*)(u32 raddr, u64 rtime, const void* _old, u64 _new)>("ppu_stcx_accurate_tx", [](asmjit::x86::Assembler& c, auto& args)
{
using namespace asmjit;
Label fall = c.newLabel();
Label fail = c.newLabel();
Label _ret = c.newLabel();
Label skip = c.newLabel();
Label next = c.newLabel();
Label load = c.newLabel();
//if (utils::has_avx() && !s_tsx_avx)
@@ -1819,11 +1833,7 @@ const auto ppu_stcx_accurate_tx = build_function_asm<u64(*)(u32 raddr, u64 rtime
// Create stack frame if necessary (Windows ABI has only 6 volatile vector registers)
c.push(x86::rbp);
c.push(x86::r13);
c.push(x86::r12);
c.push(x86::rbx);
c.push(x86::r14);
c.push(x86::r15);
c.sub(x86::rsp, 40);
#ifdef _WIN32
if (!s_tsx_avx)
@@ -1834,7 +1844,7 @@ const auto ppu_stcx_accurate_tx = build_function_asm<u64(*)(u32 raddr, u64 rtime
#endif
// Prepare registers
build_swap_rdx_with(c, args, x86::r12);
build_swap_rdx_with(c, args, x86::r10);
c.mov(x86::rbp, x86::qword_ptr(reinterpret_cast<u64>(&vm::g_sudo_addr)));
c.lea(x86::rbp, x86::qword_ptr(x86::rbp, args[0]));
c.and_(x86::rbp, -128);
@@ -1842,19 +1852,17 @@ const auto ppu_stcx_accurate_tx = build_function_asm<u64(*)(u32 raddr, u64 rtime
c.prefetchw(x86::byte_ptr(x86::rbp, 64));
c.movzx(args[0].r32(), args[0].r16());
c.shr(args[0].r32(), 1);
c.lea(x86::rbx, x86::qword_ptr(reinterpret_cast<u64>(+vm::g_reservations), args[0]));
c.and_(x86::rbx, -128 / 2);
c.prefetchw(x86::byte_ptr(x86::rbx));
c.lea(x86::r11, x86::qword_ptr(reinterpret_cast<u64>(+vm::g_reservations), args[0]));
c.and_(x86::r11, -128 / 2);
c.and_(args[0].r32(), 63);
c.mov(x86::r13, args[1]);
// Prepare data
if (s_tsx_avx)
{
c.vmovups(x86::ymm0, x86::yword_ptr(args[2], 0));
c.vmovups(x86::ymm1, x86::yword_ptr(args[2], 32));
c.vmovups(x86::ymm2, x86::yword_ptr(args[2], 64));
c.vmovups(x86::ymm3, x86::yword_ptr(args[2], 96));
c.vmovups(x86::ymm0, x86::ymmword_ptr(args[2], 0));
c.vmovups(x86::ymm1, x86::ymmword_ptr(args[2], 32));
c.vmovups(x86::ymm2, x86::ymmword_ptr(args[2], 64));
c.vmovups(x86::ymm3, x86::ymmword_ptr(args[2], 96));
}
else
{
@@ -1870,34 +1878,29 @@ const auto ppu_stcx_accurate_tx = build_function_asm<u64(*)(u32 raddr, u64 rtime
// Alloc r14 to stamp0
const auto stamp0 = x86::r14;
const auto stamp1 = x86::r15;
build_get_tsc(c, stamp0);
// Begin transaction
Label tx0 = build_transaction_enter(c, fall, [&]()
Label fail2 = c.newLabel();
Label tx1 = build_transaction_enter(c, fall, [&]()
{
build_get_tsc(c, stamp1);
c.sub(stamp1, stamp0);
c.xor_(x86::eax, x86::eax);
c.cmp(stamp1, x86::qword_ptr(reinterpret_cast<u64>(&g_rtm_tx_limit1)));
build_get_tsc(c);
c.sub(x86::rax, stamp0);
c.cmp(x86::rax, x86::qword_ptr(reinterpret_cast<u64>(&g_rtm_tx_limit2)));
c.jae(fall);
});
// Check pause flag
c.bt(x86::dword_ptr(args[2], ::offset32(&ppu_thread::state) - ::offset32(&ppu_thread::rdata)), static_cast<u32>(cpu_flag::pause));
c.jc(fall);
c.xbegin(tx0);
c.mov(x86::rax, x86::qword_ptr(x86::rbx));
c.test(x86::eax, vm::rsrv_unique_lock);
c.jnz(skip);
c.and_(x86::rax, -128);
c.cmp(x86::rax, x86::r13);
c.jne(fail);
c.xbegin(tx1);
if (s_tsx_avx)
{
c.vxorps(x86::ymm0, x86::ymm0, x86::yword_ptr(x86::rbp, 0));
c.vxorps(x86::ymm1, x86::ymm1, x86::yword_ptr(x86::rbp, 32));
c.vxorps(x86::ymm2, x86::ymm2, x86::yword_ptr(x86::rbp, 64));
c.vxorps(x86::ymm3, x86::ymm3, x86::yword_ptr(x86::rbp, 96));
c.vxorps(x86::ymm0, x86::ymm0, x86::ymmword_ptr(x86::rbp, 0));
c.vxorps(x86::ymm1, x86::ymm1, x86::ymmword_ptr(x86::rbp, 32));
c.vxorps(x86::ymm2, x86::ymm2, x86::ymmword_ptr(x86::rbp, 64));
c.vxorps(x86::ymm3, x86::ymm3, x86::ymmword_ptr(x86::rbp, 96));
c.vorps(x86::ymm0, x86::ymm0, x86::ymm1);
c.vorps(x86::ymm1, x86::ymm2, x86::ymm3);
c.vorps(x86::ymm0, x86::ymm1, x86::ymm0);
@@ -1928,145 +1931,22 @@ const auto ppu_stcx_accurate_tx = build_function_asm<u64(*)(u32 raddr, u64 rtime
// Store 8 bytes
c.mov(x86::qword_ptr(x86::rbp, args[0], 1, 0), args[3]);
// Update reservation
c.sub(x86::qword_ptr(x86::rbx), -128);
c.xend();
build_get_tsc(c);
c.sub(x86::rax, stamp0);
c.jmp(_ret);
// XABORT is expensive so finish with xend instead
c.bind(fail);
// Load old data to store back in rdata
if (s_tsx_avx)
{
c.vmovaps(x86::ymm0, x86::yword_ptr(x86::rbp, 0));
c.vmovaps(x86::ymm1, x86::yword_ptr(x86::rbp, 32));
c.vmovaps(x86::ymm2, x86::yword_ptr(x86::rbp, 64));
c.vmovaps(x86::ymm3, x86::yword_ptr(x86::rbp, 96));
}
else
{
c.movaps(x86::xmm0, x86::oword_ptr(x86::rbp, 0));
c.movaps(x86::xmm1, x86::oword_ptr(x86::rbp, 16));
c.movaps(x86::xmm2, x86::oword_ptr(x86::rbp, 32));
c.movaps(x86::xmm3, x86::oword_ptr(x86::rbp, 48));
c.movaps(x86::xmm4, x86::oword_ptr(x86::rbp, 64));
c.movaps(x86::xmm5, x86::oword_ptr(x86::rbp, 80));
c.movaps(x86::xmm6, x86::oword_ptr(x86::rbp, 96));
c.movaps(x86::xmm7, x86::oword_ptr(x86::rbp, 112));
}
c.xend();
c.jmp(load);
c.bind(skip);
c.xend();
build_get_tsc(c, stamp1);
//c.jmp(fall);
c.bind(fall);
Label fall2 = c.newLabel();
Label fail2 = c.newLabel();
Label fail3 = c.newLabel();
// Lightened transaction: only compare and swap data
c.bind(next);
// Try to "lock" reservation
c.mov(x86::eax, 1);
c.lock().xadd(x86::qword_ptr(x86::rbx), x86::rax);
c.test(x86::eax, vm::rsrv_unique_lock);
c.jnz(fail2);
// Check if already updated
c.and_(x86::rax, -128);
c.cmp(x86::rax, x86::r13);
c.jne(fail2);
// Exclude some time spent on touching memory: stamp1 contains last success or failure
c.mov(x86::rax, stamp1);
c.sub(x86::rax, stamp0);
c.cmp(x86::rax, x86::qword_ptr(reinterpret_cast<u64>(&g_rtm_tx_limit2)));
c.jae(fall2);
build_get_tsc(c, stamp1);
c.sub(stamp1, x86::rax);
Label tx1 = build_transaction_enter(c, fall2, [&]()
{
build_get_tsc(c);
c.sub(x86::rax, stamp1);
c.cmp(x86::rax, x86::qword_ptr(reinterpret_cast<u64>(&g_rtm_tx_limit2)));
c.jae(fall2);
c.test(x86::qword_ptr(x86::rbx), 127 - 1);
c.jnz(fall2);
});
c.prefetchw(x86::byte_ptr(x86::rbp, 0));
c.prefetchw(x86::byte_ptr(x86::rbp, 64));
// Check pause flag
c.bt(x86::dword_ptr(args[2], ::offset32(&ppu_thread::state) - ::offset32(&ppu_thread::rdata)), static_cast<u32>(cpu_flag::pause));
c.jc(fall2);
c.mov(x86::rax, x86::qword_ptr(x86::rbx));
c.and_(x86::rax, -128);
c.cmp(x86::rax, x86::r13);
c.jne(fail2);
c.xbegin(tx1);
if (s_tsx_avx)
{
c.vxorps(x86::ymm0, x86::ymm0, x86::yword_ptr(x86::rbp, 0));
c.vxorps(x86::ymm1, x86::ymm1, x86::yword_ptr(x86::rbp, 32));
c.vxorps(x86::ymm2, x86::ymm2, x86::yword_ptr(x86::rbp, 64));
c.vxorps(x86::ymm3, x86::ymm3, x86::yword_ptr(x86::rbp, 96));
c.vorps(x86::ymm0, x86::ymm0, x86::ymm1);
c.vorps(x86::ymm1, x86::ymm2, x86::ymm3);
c.vorps(x86::ymm0, x86::ymm1, x86::ymm0);
c.vptest(x86::ymm0, x86::ymm0);
}
else
{
c.xorps(x86::xmm0, x86::oword_ptr(x86::rbp, 0));
c.xorps(x86::xmm1, x86::oword_ptr(x86::rbp, 16));
c.xorps(x86::xmm2, x86::oword_ptr(x86::rbp, 32));
c.xorps(x86::xmm3, x86::oword_ptr(x86::rbp, 48));
c.xorps(x86::xmm4, x86::oword_ptr(x86::rbp, 64));
c.xorps(x86::xmm5, x86::oword_ptr(x86::rbp, 80));
c.xorps(x86::xmm6, x86::oword_ptr(x86::rbp, 96));
c.xorps(x86::xmm7, x86::oword_ptr(x86::rbp, 112));
c.orps(x86::xmm0, x86::xmm1);
c.orps(x86::xmm2, x86::xmm3);
c.orps(x86::xmm4, x86::xmm5);
c.orps(x86::xmm6, x86::xmm7);
c.orps(x86::xmm0, x86::xmm2);
c.orps(x86::xmm4, x86::xmm6);
c.orps(x86::xmm0, x86::xmm4);
c.ptest(x86::xmm0, x86::xmm0);
}
c.jnz(fail3);
// Store 8 bytes
c.mov(x86::qword_ptr(x86::rbp, args[0], 1, 0), args[3]);
c.xend();
c.lock().add(x86::qword_ptr(x86::rbx), 127);
c.lock().add(x86::qword_ptr(x86::r11), 64);
build_get_tsc(c);
c.sub(x86::rax, stamp0);
c.jmp(_ret);
// XABORT is expensive so try to finish with xend instead
c.bind(fail3);
c.bind(fail);
// Load old data to store back in rdata
if (s_tsx_avx)
{
c.vmovaps(x86::ymm0, x86::yword_ptr(x86::rbp, 0));
c.vmovaps(x86::ymm1, x86::yword_ptr(x86::rbp, 32));
c.vmovaps(x86::ymm2, x86::yword_ptr(x86::rbp, 64));
c.vmovaps(x86::ymm3, x86::yword_ptr(x86::rbp, 96));
c.vmovaps(x86::ymm0, x86::ymmword_ptr(x86::rbp, 0));
c.vmovaps(x86::ymm1, x86::ymmword_ptr(x86::rbp, 32));
c.vmovaps(x86::ymm2, x86::ymmword_ptr(x86::rbp, 64));
c.vmovaps(x86::ymm3, x86::ymmword_ptr(x86::rbp, 96));
}
else
{
@@ -2083,21 +1963,21 @@ const auto ppu_stcx_accurate_tx = build_function_asm<u64(*)(u32 raddr, u64 rtime
c.xend();
c.jmp(fail2);
c.bind(fall2);
c.bind(fall);
c.mov(x86::rax, -1);
c.jmp(_ret);
c.bind(fail2);
c.lock().sub(x86::qword_ptr(x86::rbx), 1);
c.lock().sub(x86::qword_ptr(x86::r11), 64);
c.bind(load);
// Store previous data back to rdata
if (s_tsx_avx)
{
c.vmovaps(x86::yword_ptr(args[2], 0), x86::ymm0);
c.vmovaps(x86::yword_ptr(args[2], 32), x86::ymm1);
c.vmovaps(x86::yword_ptr(args[2], 64), x86::ymm2);
c.vmovaps(x86::yword_ptr(args[2], 96), x86::ymm3);
c.vmovaps(x86::ymmword_ptr(args[2], 0), x86::ymm0);
c.vmovaps(x86::ymmword_ptr(args[2], 32), x86::ymm1);
c.vmovaps(x86::ymmword_ptr(args[2], 64), x86::ymm2);
c.vmovaps(x86::ymmword_ptr(args[2], 96), x86::ymm3);
}
else
{
@@ -2132,12 +2012,17 @@ const auto ppu_stcx_accurate_tx = build_function_asm<u64(*)(u32 raddr, u64 rtime
}
c.add(x86::rsp, 40);
c.pop(x86::r15);
c.pop(x86::r14);
c.pop(x86::rbx);
c.pop(x86::r12);
c.pop(x86::r13);
c.pop(x86::rbp);
#ifdef __linux__
// Hack for perf profiling (TODO)
Label ret2 = c.newLabel();
c.lea(x86::rdx, x86::qword_ptr(ret2));
c.push(x86::rdx);
c.push(x86::rdx);
c.bind(ret2);
#endif
c.ret();
});
@@ -2197,6 +2082,23 @@ static bool ppu_store_reservation(ppu_thread& ppu, u32 addr, u64 reg_value)
{
if (ppu.use_full_rdata) [[unlikely]]
{
auto [_oldd, _ok] = res.fetch_op([&](u64& r)
{
if ((r & -128) != rtime || (r & 127))
{
return false;
}
r += vm::rsrv_unique_lock;
return true;
});
if (!_ok)
{
// Already locked or updated: give up
return false;
}
if (g_use_rtm) [[likely]]
{
switch (u64 count = ppu_stcx_accurate_tx(addr & -8, rtime, ppu.rdata, std::bit_cast<u64>(new_data)))
@@ -2211,12 +2113,12 @@ static bool ppu_store_reservation(ppu_thread& ppu, u32 addr, u64 reg_value)
if ((res & -128) == rtime && cmp_rdata(ppu.rdata, all_data))
{
sdata.release(new_data);
res += 127;
res += 64;
return true;
}
mov_rdata_nt(ppu.rdata, all_data);
res -= 1;
res -= 64;
return false;
});
@@ -2268,23 +2170,6 @@ static bool ppu_store_reservation(ppu_thread& ppu, u32 addr, u64 reg_value)
return true;
}
auto [_oldd, _ok] = res.fetch_op([&](u64& r)
{
if ((r & -128) != rtime || (r & 127))
{
return false;
}
r += vm::rsrv_unique_lock;
return true;
});
if (!_ok)
{
// Already locked or updated: give up
return false;
}
// Align address: we do not need the lower 7 bits anymore
addr &= -128;
@@ -2324,7 +2209,7 @@ static bool ppu_store_reservation(ppu_thread& ppu, u32 addr, u64 reg_value)
// Aligned 8-byte reservations will be used here
addr &= -8;
const u64 lock_bits = g_cfg.core.spu_accurate_dma ? vm::rsrv_unique_lock : 1;
const u64 lock_bits = vm::rsrv_unique_lock;
auto [_oldd, _ok] = res.fetch_op([&](u64& r)
{
@@ -2333,7 +2218,6 @@ static bool ppu_store_reservation(ppu_thread& ppu, u32 addr, u64 reg_value)
return false;
}
// Despite using shared lock, doesn't allow other shared locks (TODO)
r += lock_bits;
return true;
});
@@ -2967,14 +2851,6 @@ bool ppu_initialize(const ppu_module& info, bool check_only)
{ "__ldarx", reinterpret_cast<u64>(ppu_ldarx) },
{ "__stwcx", reinterpret_cast<u64>(ppu_stwcx) },
{ "__stdcx", reinterpret_cast<u64>(ppu_stdcx) },
{ "__vexptefp", reinterpret_cast<u64>(sse_exp2_ps) },
{ "__vlogefp", reinterpret_cast<u64>(sse_log2_ps) },
{ "__lvsl", reinterpret_cast<u64>(sse_altivec_lvsl) },
{ "__lvsr", reinterpret_cast<u64>(sse_altivec_lvsr) },
{ "__lvlx", s_use_ssse3 ? reinterpret_cast<u64>(sse_cellbe_lvlx) : reinterpret_cast<u64>(sse_cellbe_lvlx_v0) },
{ "__lvrx", s_use_ssse3 ? reinterpret_cast<u64>(sse_cellbe_lvrx) : reinterpret_cast<u64>(sse_cellbe_lvrx_v0) },
{ "__stvlx", s_use_ssse3 ? reinterpret_cast<u64>(sse_cellbe_stvlx) : reinterpret_cast<u64>(sse_cellbe_stvlx_v0) },
{ "__stvrx", s_use_ssse3 ? reinterpret_cast<u64>(sse_cellbe_stvrx) : reinterpret_cast<u64>(sse_cellbe_stvrx_v0) },
{ "__dcbz", reinterpret_cast<u64>(+[](u32 addr){ alignas(64) static constexpr u8 z[128]{}; do_cell_atomic_128_store(addr, z); }) },
{ "__resupdate", reinterpret_cast<u64>(vm::reservation_update) },
{ "__resinterp", reinterpret_cast<u64>(ppu_reservation_fallback) },
@@ -3067,6 +2943,44 @@ bool ppu_initialize(const ppu_module& info, bool check_only)
bool compiled_new = false;
bool has_mfvscr = false;
for (auto& func : info.funcs)
{
if (func.size == 0)
{
continue;
}
for (const auto& [addr, size] : func.blocks)
{
if (size == 0)
{
continue;
}
for (u32 i = addr; i < addr + size; i += 4)
{
if (g_ppu_itype.decode(vm::read32(i)) == ppu_itype::MFVSCR)
{
ppu_log.warning("MFVSCR found");
has_mfvscr = true;
break;
}
}
if (has_mfvscr)
{
break;
}
}
if (has_mfvscr)
{
break;
}
}
while (!jit_mod.init && fpos < info.funcs.size())
{
// Initialize compiler instance
@@ -3108,6 +3022,12 @@ bool ppu_initialize(const ppu_module& info, bool check_only)
// Fixup some information
entry.name = fmt::format("__0x%x", entry.addr - reloc);
if (has_mfvscr)
{
// TODO
entry.attr += ppu_attr::has_mfvscr;
}
if (entry.blocks.empty())
{
entry.blocks.emplace(func.addr, func.size);
@@ -3225,6 +3145,7 @@ bool ppu_initialize(const ppu_module& info, bool check_only)
accurate_cache_line_stores,
reservations_128_byte,
greedy_mode,
has_mfvscr,
__bitset_enum_max
};
@@ -3246,9 +3167,11 @@ bool ppu_initialize(const ppu_module& info, bool check_only)
settings += ppu_settings::reservations_128_byte;
if (g_cfg.core.ppu_llvm_greedy_mode)
settings += ppu_settings::greedy_mode;
if (has_mfvscr)
settings += ppu_settings::has_mfvscr;
// Write version, hash, CPU, settings
fmt::append(obj_name, "v4-kusa-%s-%s-%s.obj", fmt::base57(output, 16), fmt::base57(settings), jit_compiler::cpu(g_cfg.core.llvm_cpu));
fmt::append(obj_name, "v5-kusa-%s-%s-%s.obj", fmt::base57(output, 16), fmt::base57(settings), jit_compiler::cpu(g_cfg.core.llvm_cpu));
}
if (Emu.IsStopped())
+3 -21
View File
@@ -222,27 +222,6 @@ public:
}
xer;
/*
Saturation. A sticky status bit indicating that some field in a saturating instruction saturated since the last
time SAT was cleared. In other words when SAT = '1' it remains set to '1' until it is cleared to '0' by an
mtvscr instruction.
1 The vector saturate instruction implicitly sets when saturation has occurred on the results one of
the vector instructions having saturate in its name:
Move To VSCR (mtvscr)
Vector Add Integer with Saturation (vaddubs, vadduhs, vadduws, vaddsbs, vaddshs,
vaddsws)
Vector Subtract Integer with Saturation (vsububs, vsubuhs, vsubuws, vsubsbs, vsubshs,
vsubsws)
Vector Multiply-Add Integer with Saturation (vmhaddshs, vmhraddshs)
Vector Multiply-Sum with Saturation (vmsumuhs, vmsumshs, vsumsws)
Vector Sum-Across with Saturation (vsumsws, vsum2sws, vsum4sbs, vsum4shs,
vsum4ubs)
Vector Pack with Saturation (vpkuhus, vpkuwus, vpkshus, vpkswus, vpkshss, vpkswss)
Vector Convert to Fixed-Point with Saturation (vctuxs, vctsxs)
0 Indicates no saturation occurred; mtvscr can explicitly clear this bit.
*/
bool sat{};
/*
Non-Java. A mode control bit that determines whether vector floating-point operations will be performed
in a Java-IEEE-C9X-compliant mode or a possibly faster non-Java/non-IEEE mode.
@@ -255,6 +234,9 @@ public:
*/
bool nj = true;
// Sticky saturation bit
v128 sat{};
// Optimization: precomputed java-mode mask for handling denormals
u32 jm_mask = 0x7f80'0000;
File diff suppressed because it is too large Load Diff
+17 -23
View File
@@ -28,6 +28,9 @@ class PPUTranslator final : public cpu_translator
// Current position-independent address
u64 m_addr = 0;
// Function attributes
bs_t<ppu_attr> m_attr{};
// Relocation info
const ppu_segment* m_reloc = nullptr;
@@ -76,8 +79,8 @@ class PPUTranslator final : public cpu_translator
DEF_VALUE(m_ov, m_g_ov, 168) // XER.OV bit, overflow flag
DEF_VALUE(m_ca, m_g_ca, 169) // XER.CA bit, carry flag
DEF_VALUE(m_cnt, m_g_cnt, 170) // XER.CNT
DEF_VALUE(m_sat, m_g_sat, 171) // VSCR.SAT bit, sticky saturation flag
DEF_VALUE(m_nj, m_g_nj, 172) // VSCR.NJ bit, non-Java mode
DEF_VALUE(m_nj, m_g_nj, 171) // VSCR.NJ bit, non-Java mode
DEF_VALUE(m_sat, m_g_sat, 173) // VSCR.SAT bit, sticky saturation flag
DEF_VALUE(m_jm_mask, m_g_jm_mask, 174) // Java-Mode helper mask
#undef DEF_VALUE
@@ -87,7 +90,7 @@ public:
value_t<T> get_vr(u32 vr)
{
value_t<T> result;
result.value = m_ir->CreateBitCast(GetVr(vr, VrType::vi32), value_t<T>::get_type(m_context));
result.value = bitcast(GetVr(vr, VrType::vi32), value_t<T>::get_type(m_context));
return result;
}
@@ -115,6 +118,17 @@ public:
return result;
}
// Update sticky VSCR.SAT bit (|=)
template <typename T>
void set_sat(T&& expr)
{
if (m_attr & ppu_attr::has_mfvscr)
{
const auto val = expr.eval(m_ir);
RegStore(m_ir->CreateOr(bitcast(RegLoad(m_sat), val->getType()), val), m_sat);
}
}
// Get current instruction address
llvm::Value* GetAddr(u64 _add = 0);
@@ -170,14 +184,6 @@ public:
// Load vr
llvm::Value* GetVr(u32 vr, VrType);
// Load VRs
template<typename... Vrs>
std::array<llvm::Value*, sizeof...(Vrs)> GetVrs(VrType type, Vrs... regs)
{
static_assert(sizeof...(Vrs), "Empty VR list");
return{ GetVr(regs, type)... };
}
// Set vr to the specified value
void SetVr(u32 vr, llvm::Value*);
@@ -193,15 +199,6 @@ public:
// Broadcast specified value
llvm::Value* Broadcast(llvm::Value* value, u32 count);
// Saturate scalar or vector given the comparison operand and the extreme value to compare with (second result is the comparison result)
std::pair<llvm::Value*, llvm::Value*> Saturate(llvm::Value* value, llvm::CmpInst::Predicate inst, llvm::Value* extreme);
// Saturate signed value (second result is the disjunction of comparison results)
std::pair<llvm::Value*, llvm::Value*> SaturateSigned(llvm::Value* value, u64 min, u64 max);
// Multiply FP value or vector by the pow(2, scale)
llvm::Value* Scale(llvm::Value* value, s32 scale);
// Create shuffle instruction with constant args
llvm::Value* Shuffle(llvm::Value* left, llvm::Value* right, std::initializer_list<u32> indices);
@@ -279,9 +276,6 @@ public:
// Set XER.OV bit, and update XER.SO bit (|=)
void SetOverflow(llvm::Value*);
// Update sticky VSCR.SAT bit (|=)
void SetSat(llvm::Value*);
// Check condition for trap instructions
llvm::Value* CheckTrapCondition(u32 to, llvm::Value* left, llvm::Value* right);
+90 -92
View File
@@ -96,15 +96,15 @@ spu_function_t spu_recompiler::compile(spu_program&& _func)
using namespace asmjit;
StringLogger logger;
logger.addOptions(Logger::kOptionBinaryForm);
logger.addFlags(FormatFlags::kMachineCode);
std::string log;
CodeHolder code;
code.init(m_asmrt.getCodeInfo());
code._globalHints = asmjit::CodeEmitter::kHintOptimizedAlign;
code.init(m_asmrt.environment());
X86Assembler compiler(&code);
x86::Assembler compiler(&code);
compiler.addEncodingOptions(EncodingOptions::kOptimizedAlign);
this->c = &compiler;
if (g_cfg.core.spu_debug && !add_loc->logged.exchange(1))
@@ -137,7 +137,7 @@ spu_function_t spu_recompiler::compile(spu_program&& _func)
this->qw1 = &x86::rcx;
#endif
const std::array<const X86Xmm*, 16> vec_vars
const std::array<const x86::Xmm*, 16> vec_vars
{
&x86::xmm0,
&x86::xmm1,
@@ -281,9 +281,9 @@ spu_function_t spu_recompiler::compile(spu_program&& _func)
c->vzeroupper();
}
}
else if (utils::has_avx512() && g_cfg.core.full_width_avx512)
else if (utils::has_avx512() && false)
{
// AVX-512 optimized check using 512-bit registers
// AVX-512 optimized check using 512-bit registers (disabled)
words_align = 64;
const u32 starta = start & -64;
@@ -333,20 +333,20 @@ spu_function_t spu_recompiler::compile(spu_program&& _func)
});
c->setExtraReg(x86::k7);
c->z().vmovdqa32(x86::zmm0, x86::zword_ptr(*qw1, j - ls_off));
c->z().vmovdqa32(x86::zmm0, x86::zmmword_ptr(*qw1, j - ls_off));
}
else
{
c->vmovdqa32(x86::zmm0, x86::zword_ptr(*qw1, j - ls_off));
c->vmovdqa32(x86::zmm0, x86::zmmword_ptr(*qw1, j - ls_off));
}
if (first)
{
c->vpcmpud(x86::k1, x86::zmm0, x86::zword_ptr(x86::rax, code_off), 4);
c->vpcmpud(x86::k1, x86::zmm0, x86::zmmword_ptr(x86::rax, code_off), 4);
}
else
{
c->vpcmpud(x86::k3, x86::zmm0, x86::zword_ptr(x86::rax, code_off), 4);
c->vpcmpud(x86::k3, x86::zmm0, x86::zmmword_ptr(x86::rax, code_off), 4);
c->korw(x86::k1, x86::k3, x86::k1);
}
@@ -378,15 +378,15 @@ spu_function_t spu_recompiler::compile(spu_program&& _func)
if (cmask == 0xff)
{
c->vmovdqa(x86::ymm0, x86::yword_ptr(*ls, starta));
c->vmovdqa(x86::ymm0, x86::ymmword_ptr(*ls, starta));
}
else
{
c->vpxor(x86::ymm0, x86::ymm0, x86::ymm0);
c->vpblendd(x86::ymm0, x86::ymm0, x86::yword_ptr(*ls, starta), cmask);
c->vpblendd(x86::ymm0, x86::ymm0, x86::ymmword_ptr(*ls, starta), cmask);
}
c->vpxor(x86::ymm0, x86::ymm0, x86::yword_ptr(label_code));
c->vpxor(x86::ymm0, x86::ymm0, x86::ymmword_ptr(label_code));
c->vptest(x86::ymm0, x86::ymm0);
c->jnz(label_diff);
@@ -401,9 +401,9 @@ spu_function_t spu_recompiler::compile(spu_program&& _func)
const u32 cmask1 = get_code_mask(starta + 32, enda);
c->vpxor(x86::ymm0, x86::ymm0, x86::ymm0);
c->vpblendd(x86::ymm0, x86::ymm0, x86::yword_ptr(*ls, starta), cmask0);
c->vpblendd(x86::ymm0, x86::ymm0, x86::yword_ptr(*ls, starta + 32), cmask1);
c->vpxor(x86::ymm0, x86::ymm0, x86::yword_ptr(label_code));
c->vpblendd(x86::ymm0, x86::ymm0, x86::ymmword_ptr(*ls, starta), cmask0);
c->vpblendd(x86::ymm0, x86::ymm0, x86::ymmword_ptr(*ls, starta + 32), cmask1);
c->vpxor(x86::ymm0, x86::ymm0, x86::ymmword_ptr(label_code));
c->vptest(x86::ymm0, x86::ymm0);
c->jnz(label_diff);
@@ -453,21 +453,21 @@ spu_function_t spu_recompiler::compile(spu_program&& _func)
xmm2z = true;
}
c->vpblendd(x86::ymm1, x86::ymm2, x86::yword_ptr(*qw1, j - ls_off), cmask);
c->vpblendd(x86::ymm1, x86::ymm2, x86::ymmword_ptr(*qw1, j - ls_off), cmask);
}
else
{
c->vmovdqa32(x86::ymm1, x86::yword_ptr(*qw1, j - ls_off));
c->vmovdqa32(x86::ymm1, x86::ymmword_ptr(*qw1, j - ls_off));
}
// Perform bitwise comparison and accumulate
if (first)
{
c->vpxor(x86::ymm0, x86::ymm1, x86::yword_ptr(x86::rax, code_off));
c->vpxor(x86::ymm0, x86::ymm1, x86::ymmword_ptr(x86::rax, code_off));
}
else
{
c->vpternlogd(x86::ymm0, x86::ymm1, x86::yword_ptr(x86::rax, code_off), 0xf6 /* orAxorBC */);
c->vpternlogd(x86::ymm0, x86::ymm1, x86::ymmword_ptr(x86::rax, code_off), 0xf6 /* orAxorBC */);
}
for (u32 i = j; i < j + 32; i += 4)
@@ -500,15 +500,15 @@ spu_function_t spu_recompiler::compile(spu_program&& _func)
if (cmask == 0xff)
{
c->vmovaps(x86::ymm0, x86::yword_ptr(*ls, starta));
c->vmovaps(x86::ymm0, x86::ymmword_ptr(*ls, starta));
}
else
{
c->vxorps(x86::ymm0, x86::ymm0, x86::ymm0);
c->vblendps(x86::ymm0, x86::ymm0, x86::yword_ptr(*ls, starta), cmask);
c->vblendps(x86::ymm0, x86::ymm0, x86::ymmword_ptr(*ls, starta), cmask);
}
c->vxorps(x86::ymm0, x86::ymm0, x86::yword_ptr(label_code));
c->vxorps(x86::ymm0, x86::ymm0, x86::ymmword_ptr(label_code));
c->vptest(x86::ymm0, x86::ymm0);
c->jnz(label_diff);
@@ -523,9 +523,9 @@ spu_function_t spu_recompiler::compile(spu_program&& _func)
const u32 cmask1 = get_code_mask(starta + 32, enda);
c->vxorps(x86::ymm0, x86::ymm0, x86::ymm0);
c->vblendps(x86::ymm0, x86::ymm0, x86::yword_ptr(*ls, starta), cmask0);
c->vblendps(x86::ymm0, x86::ymm0, x86::yword_ptr(*ls, starta + 32), cmask1);
c->vxorps(x86::ymm0, x86::ymm0, x86::yword_ptr(label_code));
c->vblendps(x86::ymm0, x86::ymm0, x86::ymmword_ptr(*ls, starta), cmask0);
c->vblendps(x86::ymm0, x86::ymm0, x86::ymmword_ptr(*ls, starta + 32), cmask1);
c->vxorps(x86::ymm0, x86::ymm0, x86::ymmword_ptr(label_code));
c->vptest(x86::ymm0, x86::ymm0);
c->jnz(label_diff);
@@ -586,21 +586,21 @@ spu_function_t spu_recompiler::compile(spu_program&& _func)
xmm2z = true;
}
c->vblendps(reg1, x86::ymm2, x86::yword_ptr(*ls, j - ls_off), cmask);
c->vblendps(reg1, x86::ymm2, x86::ymmword_ptr(*ls, j - ls_off), cmask);
}
else
{
c->vmovaps(reg1, x86::yword_ptr(*ls, j - ls_off));
c->vmovaps(reg1, x86::ymmword_ptr(*ls, j - ls_off));
}
// Perform bitwise comparison and accumulate
if (!order++)
{
c->vxorps(reg0, reg1, x86::yword_ptr(x86::rax, code_off));
c->vxorps(reg0, reg1, x86::ymmword_ptr(x86::rax, code_off));
}
else
{
c->vxorps(reg1, reg1, x86::yword_ptr(x86::rax, code_off));
c->vxorps(reg1, reg1, x86::ymmword_ptr(x86::rax, code_off));
c->vorps(reg0, reg1, reg0);
}
@@ -800,7 +800,7 @@ spu_function_t spu_recompiler::compile(spu_program&& _func)
{
if (m_preds.count(pos))
{
c->align(kAlignCode, 16);
c->align(AlignMode::kCode, 16);
}
c->bind(found->second);
@@ -832,7 +832,7 @@ spu_function_t spu_recompiler::compile(spu_program&& _func)
}
// Simply return
c->align(kAlignCode, 16);
c->align(AlignMode::kCode, 16);
c->bind(label_stop);
c->add(x86::rsp, 0x28);
c->ret();
@@ -840,7 +840,7 @@ spu_function_t spu_recompiler::compile(spu_program&& _func)
if (g_cfg.core.spu_verification)
{
// Dispatch
c->align(kAlignCode, 16);
c->align(AlignMode::kCode, 16);
c->bind(label_diff);
c->inc(SPU_OFF_64(block_failure));
c->add(x86::rsp, 0x28);
@@ -855,7 +855,7 @@ spu_function_t spu_recompiler::compile(spu_program&& _func)
// Build instruction dispatch table
if (instr_table.isValid())
{
c->align(kAlignData, 8);
c->align(AlignMode::kData, 8);
c->bind(instr_table);
// Get actual instruction table bounds
@@ -877,7 +877,7 @@ spu_function_t spu_recompiler::compile(spu_program&& _func)
}
}
c->align(kAlignData, words_align);
c->align(AlignMode::kData, words_align);
c->bind(label_code);
for (u32 d : words)
c->dd(d);
@@ -893,17 +893,16 @@ spu_function_t spu_recompiler::compile(spu_program&& _func)
xmm_consts.clear();
// Compile and get function address
spu_function_t fn;
spu_function_t fn = reinterpret_cast<spu_function_t>(m_asmrt._add(&code));
if (auto err = m_asmrt.add(&fn, &code))
if (!fn)
{
if (err == asmjit::ErrorCode::kErrorNoVirtualMemory)
{
return nullptr;
}
spu_log.fatal("Failed to build a function");
}
else
{
jit_announce(fn, code.codeSize(), fmt::format("spu-b-%s", fmt::base57(be_t<u64>(m_hash_start))));
}
// Install compiled function pointer
const bool added = !add_loc->compiled && add_loc->compiled.compare_and_swap_test(nullptr, fn);
@@ -923,7 +922,7 @@ spu_function_t spu_recompiler::compile(spu_program&& _func)
{
// Add ASMJIT logs
fmt::append(log, "Address: %p\n\n", fn);
log += logger.getString();
log.append(logger._content.data(), logger._content.size());
log += "\n\n\n";
// Append log file
@@ -958,7 +957,7 @@ spu_recompiler::XmmLink spu_recompiler::XmmGet(s8 reg, XmmType type) // get xmm
return result;
}
inline asmjit::X86Mem spu_recompiler::XmmConst(const v128& data)
inline asmjit::x86::Mem spu_recompiler::XmmConst(const v128& data)
{
// Find existing const
auto& xmm_label = xmm_consts[std::make_pair(data._u64[0], data._u64[1])];
@@ -969,7 +968,7 @@ inline asmjit::X86Mem spu_recompiler::XmmConst(const v128& data)
consts.emplace_back([=, this]
{
c->align(asmjit::kAlignData, 16);
c->align(asmjit::AlignMode::kData, 16);
c->bind(xmm_label);
c->dq(data._u64[0]);
c->dq(data._u64[1]);
@@ -979,17 +978,17 @@ inline asmjit::X86Mem spu_recompiler::XmmConst(const v128& data)
return asmjit::x86::oword_ptr(xmm_label);
}
inline asmjit::X86Mem spu_recompiler::XmmConst(const __m128& data)
inline asmjit::x86::Mem spu_recompiler::XmmConst(const __m128& data)
{
return XmmConst(v128::fromF(data));
}
inline asmjit::X86Mem spu_recompiler::XmmConst(const __m128i& data)
inline asmjit::x86::Mem spu_recompiler::XmmConst(const __m128i& data)
{
return XmmConst(v128::fromV(data));
}
inline asmjit::X86Mem spu_recompiler::get_pc(u32 addr)
inline asmjit::x86::Mem spu_recompiler::get_pc(u32 addr)
{
return asmjit::x86::qword_ptr(*pc0, addr - m_base);
}
@@ -1104,7 +1103,7 @@ void spu_recompiler::branch_indirect(spu_opcode_t op, bool jt, bool ret)
c->mov(SPU_OFF_32(pc), *addr);
c->mov(*arg0, *cpu);
c->add(x86::rsp, 0x28);
c->jmp(imm_ptr<void(*)(spu_thread*)>(_throw));
c->jmp(imm_ptr(+_throw));
// Save addr in srr0 and disable interrupts
c->bind(intr);
@@ -1119,7 +1118,7 @@ void spu_recompiler::branch_indirect(spu_opcode_t op, bool jt, bool ret)
c->test(*addr, 0xff80007f);
c->cmovnz(*addr, rip->r32());
c->shr(*addr, 5);
c->align(kAlignCode, 16);
c->align(AlignMode::kCode, 16);
c->bind(no_intr);
}
@@ -1206,7 +1205,7 @@ void spu_recompiler::branch_set_link(u32 target)
after.emplace_back([=, this, target = local->second]
{
// Clear return info after use
c->align(kAlignCode, 16);
c->align(AlignMode::kCode, 16);
c->bind(ret);
c->mov(qw1->r32(), SPU_OFF_32(gpr, 1, &v128::_u32, 3));
c->and_(qw1->r32(), 0x3fff0);
@@ -1242,9 +1241,9 @@ void spu_recompiler::fall(spu_opcode_t op)
c->and_(*addr, 0x3fffc);
c->mov(SPU_OFF_32(pc), *addr);
c->mov(arg1->r32(), op.opcode);
c->mov(*qw0, asmjit::imm_ptr(asmjit::Internal::ptr_cast<void*>(g_spu_interpreter_fast.decode(op.opcode))));
c->mov(*qw0, asmjit::imm_ptr(g_spu_interpreter_fast.decode(op.opcode)));
c->mov(*arg0, *cpu);
c->call(asmjit::imm_ptr<void(*)(spu_thread*, u32, spu_inter_func_t)>(gate));
c->call(asmjit::imm_ptr(+gate));
}
void spu_recompiler::UNK(spu_opcode_t op)
@@ -1262,7 +1261,7 @@ void spu_recompiler::UNK(spu_opcode_t op)
c->mov(arg1->r32(), op.opcode);
c->mov(*arg0, *cpu);
c->add(asmjit::x86::rsp, 0x28);
c->jmp(asmjit::imm_ptr<void(*)(spu_thread*, u32)>(gate));
c->jmp(asmjit::imm_ptr(+gate));
m_pos = -1;
}
@@ -1291,7 +1290,7 @@ void spu_recompiler::STOP(spu_opcode_t op)
c->mov(arg1->r32(), op.opcode & 0x3fff);
c->mov(*arg0, *cpu);
c->call(imm_ptr(spu_stop));
c->align(kAlignCode, 16);
c->align(AlignMode::kCode, 16);
c->bind(ret);
c->add(SPU_OFF_32(pc), 4);
@@ -1358,14 +1357,14 @@ void spu_recompiler::RDCH(spu_opcode_t op)
{
using namespace asmjit;
auto read_channel = [&](X86Mem channel_ptr, bool sync = true)
auto read_channel = [&](x86::Mem channel_ptr, bool sync = true)
{
Label wait = c->newLabel();
Label again = c->newLabel();
Label ret = c->newLabel();
c->mov(addr->r64(), channel_ptr);
c->xor_(qw0->r32(), qw0->r32());
c->align(kAlignCode, 16);
c->align(AlignMode::kCode, 16);
c->bind(again);
c->bt(addr->r64(), spu_channel::off_count);
c->jnc(wait);
@@ -1376,7 +1375,7 @@ void spu_recompiler::RDCH(spu_opcode_t op)
c->lea(addr->r64(), get_pc(pos));
c->and_(*addr, 0x3fffc);
c->mov(SPU_OFF_32(pc), *addr);
c->mov(arg1->r32(), op.ra);
c->mov(arg1->r32(), +op.ra);
c->mov(*arg0, *cpu);
c->call(imm_ptr(spu_rdch));
c->jmp(ret);
@@ -1478,13 +1477,12 @@ void spu_recompiler::RDCH(spu_opcode_t op)
*_res = v128::from32r(out);
};
using ftype = void (*)(spu_thread*, v128*);
c->lea(addr->r64(), get_pc(m_pos));
c->and_(*addr, 0x3fffc);
c->mov(SPU_OFF_32(pc), *addr);
c->lea(*arg1, SPU_OFF_128(gpr, op.rt));
c->mov(*arg0, *cpu);
c->call(g_cfg.core.spu_loop_detection ? asmjit::imm_ptr<ftype>(sub1) : asmjit::imm_ptr<ftype>(sub2));
c->call(asmjit::imm_ptr(g_cfg.core.spu_loop_detection ? +sub1 : +sub2));
return;
}
case SPU_RdEventMask:
@@ -1519,7 +1517,7 @@ void spu_recompiler::RDCH(spu_opcode_t op)
c->lea(addr->r64(), get_pc(m_pos));
c->and_(*addr, 0x3fffc);
c->mov(SPU_OFF_32(pc), *addr);
c->mov(arg1->r32(), op.ra);
c->mov(arg1->r32(), +op.ra);
c->mov(*arg0, *cpu);
c->call(imm_ptr(spu_rdch));
c->movd(x86::xmm0, *addr);
@@ -1536,7 +1534,7 @@ void spu_recompiler::RCHCNT(spu_opcode_t op)
{
using namespace asmjit;
auto ch_cnt = [&](X86Mem channel_ptr, bool inv = false)
auto ch_cnt = [&](x86::Mem channel_ptr, bool inv = false)
{
// Load channel count
const XmmLink& vr = XmmAlloc();
@@ -1627,7 +1625,7 @@ void spu_recompiler::RCHCNT(spu_opcode_t op)
c->lea(addr->r64(), get_pc(m_pos));
c->and_(*addr, 0x3fffc);
c->mov(SPU_OFF_32(pc), *addr);
c->mov(arg1->r32(), op.ra);
c->mov(arg1->r32(), +op.ra);
c->mov(*arg0, *cpu);
c->call(imm_ptr(spu_rchcnt));
break;
@@ -2316,7 +2314,7 @@ void spu_recompiler::WRCH(spu_opcode_t op)
Label ret = c->newLabel();
c->mov(qw0->r32(), SPU_OFF_32(gpr, op.rt, &v128::_u32, 3));
c->mov(addr->r64(), SPU_OFF_64(ch_out_mbox));
c->align(kAlignCode, 16);
c->align(AlignMode::kCode, 16);
c->bind(again);
c->mov(qw0->r32(), qw0->r32());
c->bt(addr->r64(), spu_channel::off_count);
@@ -2328,7 +2326,7 @@ void spu_recompiler::WRCH(spu_opcode_t op)
c->lea(addr->r64(), get_pc(pos));
c->and_(*addr, 0x3fffc);
c->mov(SPU_OFF_32(pc), *addr);
c->mov(arg1->r32(), op.ra);
c->mov(arg1->r32(), +op.ra);
c->mov(*arg0, *cpu);
c->call(imm_ptr(spu_wrch));
c->jmp(ret);
@@ -2355,7 +2353,7 @@ void spu_recompiler::WRCH(spu_opcode_t op)
c->lea(addr->r64(), get_pc(pos));
c->and_(*addr, 0x3fffc);
c->mov(SPU_OFF_32(pc), *addr);
c->lea(arg1->r32(), MFC_WrTagMask);
c->mov(arg1->r32(), MFC_WrTagMask);
c->mov(*arg0, *cpu);
c->call(imm_ptr(spu_wrch));
c->jmp(ret);
@@ -2379,7 +2377,7 @@ void spu_recompiler::WRCH(spu_opcode_t op)
c->lea(addr->r64(), get_pc(pos));
c->and_(*addr, 0x3fffc);
c->mov(SPU_OFF_32(pc), *addr);
c->mov(arg1->r32(), op.ra);
c->mov(arg1->r32(), +op.ra);
c->mov(*arg0, *cpu);
c->call(imm_ptr(spu_wrch));
c->jmp(ret);
@@ -2472,7 +2470,7 @@ void spu_recompiler::WRCH(spu_opcode_t op)
c->btr(SPU_OFF_32(ch_stall_mask), arg1->r32());
c->jnc(ret);
c->mov(*arg0, *cpu);
c->call(imm_ptr<void(*)(spu_thread*, u32)>(sub));
c->call(imm_ptr(+sub));
c->bind(ret);
return;
}
@@ -2484,7 +2482,7 @@ void spu_recompiler::WRCH(spu_opcode_t op)
};
c->mov(*arg0, *cpu);
c->call(imm_ptr<void(*)(spu_thread*)>(sub));
c->call(imm_ptr(+sub));
c->mov(qw0->r32(), SPU_OFF_32(gpr, op.rt, &v128::_u32, 3));
c->mov(SPU_OFF_32(ch_dec_value), qw0->r32());
return;
@@ -2511,7 +2509,7 @@ void spu_recompiler::WRCH(spu_opcode_t op)
c->lea(addr->r64(), get_pc(m_pos));
c->and_(*addr, 0x3fffc);
c->mov(SPU_OFF_32(pc), *addr);
c->mov(arg1->r32(), op.ra);
c->mov(arg1->r32(), +op.ra);
c->mov(qw0->r32(), SPU_OFF_32(gpr, op.rt, &v128::_u32, 3));
c->mov(*arg0, *cpu);
c->call(imm_ptr(spu_wrch));
@@ -2525,7 +2523,7 @@ void spu_recompiler::BIZ(spu_opcode_t op)
after.emplace_back([=, this, jt = m_targets[m_pos].size() > 1]
{
c->align(asmjit::kAlignCode, 16);
c->align(asmjit::AlignMode::kCode, 16);
c->bind(branch_label);
c->mov(*addr, SPU_OFF_32(gpr, op.ra, &v128::_u32, 3));
c->and_(*addr, 0x3fffc);
@@ -2541,7 +2539,7 @@ void spu_recompiler::BINZ(spu_opcode_t op)
after.emplace_back([=, this, jt = m_targets[m_pos].size() > 1]
{
c->align(asmjit::kAlignCode, 16);
c->align(asmjit::AlignMode::kCode, 16);
c->bind(branch_label);
c->mov(*addr, SPU_OFF_32(gpr, op.ra, &v128::_u32, 3));
c->and_(*addr, 0x3fffc);
@@ -2557,7 +2555,7 @@ void spu_recompiler::BIHZ(spu_opcode_t op)
after.emplace_back([=, this, jt = m_targets[m_pos].size() > 1]
{
c->align(asmjit::kAlignCode, 16);
c->align(asmjit::AlignMode::kCode, 16);
c->bind(branch_label);
c->mov(*addr, SPU_OFF_32(gpr, op.ra, &v128::_u32, 3));
c->and_(*addr, 0x3fffc);
@@ -2573,7 +2571,7 @@ void spu_recompiler::BIHNZ(spu_opcode_t op)
after.emplace_back([=, this, jt = m_targets[m_pos].size() > 1]
{
c->align(asmjit::kAlignCode, 16);
c->align(asmjit::AlignMode::kCode, 16);
c->bind(branch_label);
c->mov(*addr, SPU_OFF_32(gpr, op.ra, &v128::_u32, 3));
c->and_(*addr, 0x3fffc);
@@ -2665,13 +2663,13 @@ void spu_recompiler::BISLED(spu_opcode_t op)
asmjit::Label branch_label = c->newLabel();
c->mov(*arg0, *cpu);
c->call(asmjit::imm_ptr<u32(*)(spu_thread*)>(get_events));
c->call(asmjit::imm_ptr(+get_events));
c->test(*addr, 1);
c->jne(branch_label);
after.emplace_back([=, this]()
{
c->align(asmjit::kAlignCode, 16);
c->align(asmjit::AlignMode::kCode, 16);
c->bind(branch_label);
c->and_(*addr, 0x3fffc);
branch_indirect(op, true, false);
@@ -2891,7 +2889,7 @@ void spu_recompiler::CDX(spu_opcode_t op)
const XmmLink& vr = XmmAlloc();
c->movdqa(vr, XmmConst(_mm_set_epi32(0x10111213, 0x14151617, 0x18191a1b, 0x1c1d1e1f)));
c->movdqa(SPU_OFF_128(gpr, op.rt), vr);
c->mov(*qw0, asmjit::imm_u(0x0001020304050607));
c->mov(*qw0, asmjit::Imm(0x0001020304050607ull));
c->mov(asmjit::x86::qword_ptr(*cpu, addr->r64(), 0, offset32(&spu_thread::gpr, op.rt)), *qw0);
}
@@ -3024,7 +3022,7 @@ void spu_recompiler::CBD(spu_opcode_t op)
//}
c->mov(*addr, SPU_OFF_32(gpr, op.ra, &v128::_u32, 3));
if (op.i7) c->add(*addr, op.i7);
if (op.i7) c->add(*addr, +op.i7);
c->not_(*addr);
c->and_(*addr, 0xf);
@@ -3048,7 +3046,7 @@ void spu_recompiler::CHD(spu_opcode_t op)
//}
c->mov(*addr, SPU_OFF_32(gpr, op.ra, &v128::_u32, 3));
if (op.i7) c->add(*addr, op.i7);
if (op.i7) c->add(*addr, +op.i7);
c->not_(*addr);
c->and_(*addr, 0xe);
@@ -3072,7 +3070,7 @@ void spu_recompiler::CWD(spu_opcode_t op)
//}
c->mov(*addr, SPU_OFF_32(gpr, op.ra, &v128::_u32, 3));
if (op.i7) c->add(*addr, op.i7);
if (op.i7) c->add(*addr, +op.i7);
c->not_(*addr);
c->and_(*addr, 0xc);
@@ -3096,14 +3094,14 @@ void spu_recompiler::CDD(spu_opcode_t op)
//}
c->mov(*addr, SPU_OFF_32(gpr, op.ra, &v128::_u32, 3));
if (op.i7) c->add(*addr, op.i7);
if (op.i7) c->add(*addr, +op.i7);
c->not_(*addr);
c->and_(*addr, 0x8);
const XmmLink& vr = XmmAlloc();
c->movdqa(vr, XmmConst(_mm_set_epi32(0x10111213, 0x14151617, 0x18191a1b, 0x1c1d1e1f)));
c->movdqa(SPU_OFF_128(gpr, op.rt), vr);
c->mov(*qw0, asmjit::imm_u(0x0001020304050607));
c->mov(*qw0, asmjit::Imm(0x0001020304050607ull));
c->mov(asmjit::x86::qword_ptr(*cpu, addr->r64(), 0, offset32(&spu_thread::gpr, op.rt)), *qw0);
}
@@ -4044,7 +4042,7 @@ void spu_recompiler::BRZ(spu_opcode_t op)
after.emplace_back([=, this]()
{
c->align(asmjit::kAlignCode, 16);
c->align(asmjit::AlignMode::kCode, 16);
c->bind(branch_label);
branch_fixed(target);
});
@@ -4084,7 +4082,7 @@ void spu_recompiler::BRNZ(spu_opcode_t op)
after.emplace_back([=, this]()
{
c->align(asmjit::kAlignCode, 16);
c->align(asmjit::AlignMode::kCode, 16);
c->bind(branch_label);
branch_fixed(target);
});
@@ -4105,7 +4103,7 @@ void spu_recompiler::BRHZ(spu_opcode_t op)
after.emplace_back([=, this]()
{
c->align(asmjit::kAlignCode, 16);
c->align(asmjit::AlignMode::kCode, 16);
c->bind(branch_label);
branch_fixed(target);
});
@@ -4126,7 +4124,7 @@ void spu_recompiler::BRHNZ(spu_opcode_t op)
after.emplace_back([=, this]()
{
c->align(asmjit::kAlignCode, 16);
c->align(asmjit::AlignMode::kCode, 16);
c->bind(branch_label);
branch_fixed(target);
});
@@ -4455,7 +4453,7 @@ void spu_recompiler::CGTBI(spu_opcode_t op)
void spu_recompiler::HGTI(spu_opcode_t op)
{
c->cmp(SPU_OFF_32(gpr, op.ra, &v128::_s32, 3), op.si10);
c->cmp(SPU_OFF_32(gpr, op.ra, &v128::_s32, 3), +op.si10);
asmjit::Label label = c->newLabel();
asmjit::Label ret = c->newLabel();
@@ -4499,7 +4497,7 @@ void spu_recompiler::CLGTBI(spu_opcode_t op)
void spu_recompiler::HLGTI(spu_opcode_t op)
{
c->cmp(SPU_OFF_32(gpr, op.ra, &v128::_u32, 3), op.si10);
c->cmp(SPU_OFF_32(gpr, op.ra, &v128::_u32, 3), +op.si10);
asmjit::Label label = c->newLabel();
asmjit::Label ret = c->newLabel();
@@ -4561,7 +4559,7 @@ void spu_recompiler::CEQBI(spu_opcode_t op)
void spu_recompiler::HEQI(spu_opcode_t op)
{
c->cmp(SPU_OFF_32(gpr, op.ra, &v128::_u32, 3), op.si10);
c->cmp(SPU_OFF_32(gpr, op.ra, &v128::_u32, 3), +op.si10);
asmjit::Label label = c->newLabel();
asmjit::Label ret = c->newLabel();
@@ -4632,12 +4630,12 @@ void spu_recompiler::SHUFB(spu_opcode_t op)
c->vpcmpub(asmjit::x86::k1, vc, XmmConst(_mm_set1_epi8(-0x40)), 5 /* GE */);
c->vpxor(vm, vc, XmmConst(_mm_set1_epi8(0xf)));
c->setExtraReg(asmjit::x86::k1);
c->z().vblendmb(vc, vc, XmmConst(_mm_set1_epi8(-1))); // {k1}
c->z().vpblendmb(vc, vc, XmmConst(_mm_set1_epi8(-1))); // {k1}
c->vpcmpub(asmjit::x86::k2, vm, XmmConst(_mm_set1_epi8(-0x20)), 5 /* GE */);
c->vptestmb(asmjit::x86::k1, vm, XmmConst(_mm_set1_epi8(0x10)));
c->vpshufb(vt, va, vm);
c->setExtraReg(asmjit::x86::k2);
c->z().vblendmb(va, va, XmmConst(_mm_set1_epi8(0x7f))); // {k2}
c->z().vpblendmb(va, va, XmmConst(_mm_set1_epi8(0x7f))); // {k2}
c->setExtraReg(asmjit::x86::k1);
c->vpshufb(vt, vb, vm); // {k1}
c->vpternlogd(vt, va, vc, 0xf6 /* orAxorBC */);
+18 -18
View File
@@ -24,23 +24,23 @@ private:
u32 m_base;
// emitter:
asmjit::X86Assembler* c;
asmjit::x86::Assembler* c;
// arguments:
const asmjit::X86Gp* cpu;
const asmjit::X86Gp* ls;
const asmjit::X86Gp* rip;
const asmjit::X86Gp* pc0;
const asmjit::x86::Gp* cpu;
const asmjit::x86::Gp* ls;
const asmjit::x86::Gp* rip;
const asmjit::x86::Gp* pc0;
// Native args or temp variables:
const asmjit::X86Gp* arg0;
const asmjit::X86Gp* arg1;
const asmjit::X86Gp* qw0;
const asmjit::X86Gp* qw1;
const asmjit::x86::Gp* arg0;
const asmjit::x86::Gp* arg1;
const asmjit::x86::Gp* qw0;
const asmjit::x86::Gp* qw1;
// temporary:
const asmjit::X86Gp* addr;
std::array<const asmjit::X86Xmm*, 16> vec;
const asmjit::x86::Gp* addr;
std::array<const asmjit::x86::Xmm*, 16> vec;
// workload for the end of function:
std::vector<std::function<void()>> after;
@@ -60,10 +60,10 @@ private:
class XmmLink
{
const asmjit::X86Xmm* m_var;
const asmjit::x86::Xmm* m_var;
public:
XmmLink(const asmjit::X86Xmm*& xmm_var)
XmmLink(const asmjit::x86::Xmm*& xmm_var)
: m_var(xmm_var)
{
xmm_var = nullptr;
@@ -71,7 +71,7 @@ private:
XmmLink(XmmLink&&) = default; // MoveConstructible + delete copy constructor and copy/move operators
operator const asmjit::X86Xmm&() const
operator const asmjit::x86::Xmm&() const
{
return *m_var;
}
@@ -87,11 +87,11 @@ private:
XmmLink XmmAlloc();
XmmLink XmmGet(s8 reg, XmmType type);
asmjit::X86Mem XmmConst(const v128& data);
asmjit::X86Mem XmmConst(const __m128& data);
asmjit::X86Mem XmmConst(const __m128i& data);
asmjit::x86::Mem XmmConst(const v128& data);
asmjit::x86::Mem XmmConst(const __m128& data);
asmjit::x86::Mem XmmConst(const __m128i& data);
asmjit::X86Mem get_pc(u32 addr);
asmjit::x86::Mem get_pc(u32 addr);
void branch_fixed(u32 target, bool absolute = false);
void branch_indirect(spu_opcode_t op, bool jt = false, bool ret = true);
void branch_set_link(u32 target);
+4 -4
View File
@@ -43,7 +43,7 @@ namespace asmjit
static constexpr spu_opcode_t s_op{};
template <uint I, uint N>
static void build_spu_gpr_load(X86Assembler& c, X86Xmm x, const bf_t<u32, I, N>&, bool store = false)
static void build_spu_gpr_load(x86::Assembler& c, x86::Xmm x, const bf_t<u32, I, N>&, bool store = false)
{
static_assert(N == 7, "Invalid bitfield");
@@ -87,7 +87,7 @@ namespace asmjit
}
template <uint I, uint N>
static void build_spu_gpr_store(X86Assembler& c, X86Xmm x, const bf_t<u32, I, N>&, bool store = true)
static void build_spu_gpr_store(x86::Assembler& c, x86::Xmm x, const bf_t<u32, I, N>&, bool store = true)
{
build_spu_gpr_load(c, x, bf_t<u32, I, N>{}, store);
}
@@ -1733,7 +1733,7 @@ bool spu_interpreter::SHUFB(spu_thread& spu, spu_opcode_t op)
return true;
}
const spu_inter_func_t optimized_shufb = build_function_asm<spu_inter_func_t>([](asmjit::X86Assembler& c, auto& /*args*/)
const spu_inter_func_t optimized_shufb = build_function_asm<spu_inter_func_t>("spu_shufb", [](asmjit::x86::Assembler& c, auto& /*args*/)
{
using namespace asmjit;
@@ -1793,7 +1793,7 @@ const spu_inter_func_t optimized_shufb = build_function_asm<spu_inter_func_t>([]
c.mov(x86::eax, 1);
c.ret();
c.align(kAlignData, 16);
c.align(AlignMode::kData, 16);
c.bind(xc0);
c.dq(0xc0c0c0c0c0c0c0c0);
c.dq(0xc0c0c0c0c0c0c0c0);
+104 -25
View File
@@ -160,7 +160,7 @@ DECLARE(spu_runtime::tr_all) = []
return reinterpret_cast<spu_function_t>(trptr);
}();
DECLARE(spu_runtime::g_gateway) = build_function_asm<spu_function_t>([](asmjit::X86Assembler& c, auto& args)
DECLARE(spu_runtime::g_gateway) = built_function<spu_function_t>("spu_gateway", [](asmjit::x86::Assembler& c, auto& args)
{
// Gateway for SPU dispatcher, converts from native to GHC calling convention, also saves RSP value for spu_escape
using namespace asmjit;
@@ -249,7 +249,7 @@ DECLARE(spu_runtime::g_gateway) = build_function_asm<spu_function_t>([](asmjit::
c.ret();
});
DECLARE(spu_runtime::g_escape) = build_function_asm<void(*)(spu_thread*)>([](asmjit::X86Assembler& c, auto& args)
DECLARE(spu_runtime::g_escape) = build_function_asm<void(*)(spu_thread*)>("spu_escape", [](asmjit::x86::Assembler& c, auto& args)
{
using namespace asmjit;
@@ -257,10 +257,11 @@ DECLARE(spu_runtime::g_escape) = build_function_asm<void(*)(spu_thread*)>([](asm
c.mov(x86::rsp, x86::qword_ptr(args[0], ::offset32(&spu_thread::saved_native_sp)));
// Return to the return location
c.jmp(x86::qword_ptr(x86::rsp, -8));
c.sub(x86::rsp, 8);
c.ret();
});
DECLARE(spu_runtime::g_tail_escape) = build_function_asm<void(*)(spu_thread*, spu_function_t, u8*)>([](asmjit::X86Assembler& c, auto& args)
DECLARE(spu_runtime::g_tail_escape) = build_function_asm<void(*)(spu_thread*, spu_function_t, u8*)>("spu_tail_escape", [](asmjit::x86::Assembler& c, auto& args)
{
using namespace asmjit;
@@ -268,14 +269,15 @@ DECLARE(spu_runtime::g_tail_escape) = build_function_asm<void(*)(spu_thread*, sp
c.mov(x86::rsp, x86::qword_ptr(args[0], ::offset32(&spu_thread::saved_native_sp)));
// Adjust stack for initial call instruction in the gateway
c.sub(x86::rsp, 8);
c.sub(x86::rsp, 16);
// Tail call, GHC CC (second arg)
c.mov(x86::r13, args[0]);
c.mov(x86::rbp, x86::qword_ptr(args[0], ::offset32(&spu_thread::ls)));
c.mov(x86::r12, args[2]);
c.xor_(x86::ebx, x86::ebx);
c.jmp(args[1]);
c.mov(x86::qword_ptr(x86::rsp), args[1]);
c.ret();
});
DECLARE(spu_runtime::g_interpreter_table) = {};
@@ -1066,6 +1068,8 @@ spu_function_t spu_runtime::rebuild_ubertrampoline(u32 id_inst)
workload.clear();
result = reinterpret_cast<spu_function_t>(reinterpret_cast<u64>(wxptr));
jit_announce(wxptr, raw - wxptr, "spu_ubertrampoline");
}
if (auto _old = stuff_it->trampoline.compare_and_swap(nullptr, result))
@@ -3480,7 +3484,7 @@ class spu_llvm_recompiler : public spu_recompiler_base, public cpu_translator
#endif
// Get function chunk name
const std::string name = fmt::format("spu-chunk-0x%05x", addr);
const std::string name = fmt::format("spu-cx%05x-%s", addr, fmt::base57(be_t<u64>{m_hash_start}));
llvm::Function* result = llvm::cast<llvm::Function>(m_module->getOrInsertFunction(name, chunk_type).getCallee());
// Set parameters
@@ -3505,7 +3509,7 @@ class spu_llvm_recompiler : public spu_recompiler_base, public cpu_translator
// 5. $3
const auto func_type = get_ftype<u32[4], u8*, u8*, u32, u32[4], u32[4]>();
const std::string fname = fmt::format("spu-function-0x%05x", addr);
const std::string fname = fmt::format("spu-fx%05x-%s", addr, fmt::base57(be_t<u64>{m_hash_start}));
llvm::Function* fn = llvm::cast<llvm::Function>(m_module->getOrInsertFunction(fname, func_type).getCallee());
fn->setLinkage(llvm::GlobalValue::InternalLinkage);
@@ -4485,13 +4489,13 @@ public:
elements = 16;
dwords = 8;
}
else if (true)
else if (m_use_avx)
{
stride = 32;
elements = 8;
dwords = 4;
}
else // TODO: Use this path when the cpu doesn't support AVX
else
{
stride = 16;
elements = 4;
@@ -4539,7 +4543,7 @@ public:
{
vls = m_ir->CreateAlignedLoad(_ptr<u32[16]>(data_addr, j - starta), llvm::MaybeAlign{4});
}
else if (true)
else if (m_use_avx)
{
vls = m_ir->CreateAlignedLoad(_ptr<u32[8]>(data_addr, j - starta), llvm::MaybeAlign{4});
}
@@ -4573,7 +4577,7 @@ public:
{
acc = m_ir->CreateBitCast(acc, get_type<u64[8]>());
}
else if (true)
else if (m_use_avx)
{
acc = m_ir->CreateBitCast(acc, get_type<u64[4]>());
}
@@ -5600,7 +5604,7 @@ public:
if (atomic)
{
const auto val = m_ir->CreateAtomicRMW(llvm::AtomicRMWInst::Xchg, ptr, m_ir->getInt64(0), llvm::AtomicOrdering::Acquire);
const auto val = m_ir->CreateAtomicRMW(llvm::AtomicRMWInst::Xchg, ptr, m_ir->getInt64(0), llvm::MaybeAlign{8}, llvm::AtomicOrdering::Acquire);
val0 = val;
}
else
@@ -6889,12 +6893,23 @@ public:
set_vr(op.rt, pshufb(a, sh));
}
template <typename T>
static llvm_calli<u32[4], T> orx(T&& a)
{
return {"spu_orx", {std::forward<T>(a)}};
}
void ORX(spu_opcode_t op)
{
const auto a = get_vr(op.ra);
const auto x = zshuffle(a, 2, 3, 0, 1) | a;
const auto y = zshuffle(x, 1, 0, 3, 2) | x;
set_vr(op.rt, zshuffle(y, 4, 4, 4, 3));
register_intrinsic("spu_orx", [&](llvm::CallInst* ci)
{
const auto a = value<u32[4]>(ci->getOperand(0));
const auto x = zshuffle(a, 2, 3, 0, 1) | a;
const auto y = zshuffle(x, 1, 0, 3, 2) | x;
return zshuffle(y, 4, 4, 4, 3);
});
set_vr(op.rt, orx(get_vr(op.ra)));
}
void CBD(spu_opcode_t op)
@@ -7641,7 +7656,7 @@ public:
if (auto [ok, bs] = match_expr(b, byteswap(match<u8[16]>())); ok)
{
// Undo endian swapping, and rely on pshufb/vperm2b to re-reverse endianness
if (m_use_avx512_icl && (op.ra != op.rb))
if (false)
{
if (perm_only)
{
@@ -7649,7 +7664,7 @@ public:
return;
}
const auto m = gf2p8affineqb(c, build<u8[16]>(0x40, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x40, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20), 0x7f);
const auto m = gf2p8affineqb(c, build<u8[16]>(0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x40, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x40), 0x7f);
const auto mm = select(noncast<s8[16]>(m) >= 0, splat<u8[16]>(0), m);
const auto ab = vperm2b256to128(as, bs, c);
set_vr(op.rt4, select(noncast<s8[16]>(c) >= 0, ab, mm));
@@ -7703,7 +7718,7 @@ public:
}
}
if (m_use_avx512_icl && (op.ra != op.rb || m_interp_magn))
if (false)
{
if (perm_only)
{
@@ -7711,7 +7726,7 @@ public:
return;
}
const auto m = gf2p8affineqb(c, build<u8[16]>(0x40, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x40, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20), 0x7f);
const auto m = gf2p8affineqb(c, build<u8[16]>(0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x40, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x40), 0x7f);
const auto mm = select(noncast<s8[16]>(m) >= 0, splat<u8[16]>(0), m);
const auto cr = eval(~c);
const auto ab = vperm2b256to128(b, a, cr);
@@ -9234,7 +9249,7 @@ public:
const auto rt = get_vr<u8[16]>(op.rt);
// Checking for zero doeesn't care about the order of the bytes,
// Checking for zero doesn't care about the order of the bytes,
// so load the data before it's byteswapped
if (auto [ok, as] = match_expr(rt, byteswap(match<u8[16]>())); ok)
{
@@ -9246,6 +9261,22 @@ public:
return;
}
const auto ox = get_vr<u32[4]>(op.rt);
// Instead of extracting the value generated by orx, just test the input to orx with ptest
if (auto [ok, as] = match_expr(ox, orx(match<u32[4]>())); ok)
{
m_block->block_end = m_ir->GetInsertBlock();
const auto a = extract(bitcast<u64[2]>(as), 0);
const auto b = extract(bitcast<u64[2]>(as), 1);
const auto cond = eval((a | b) == 0);
const auto addr = eval(extract(get_vr(op.ra), 3) & 0x3fffc);
const auto target = add_block_indirect(op, addr);
m_ir->CreateCondBr(cond.value, target, add_block_next());
return;
}
// Check sign bit instead (optimization)
if (match_vr<s32[4], s64[2]>(op.rt, [&](auto c, auto MP)
{
@@ -9279,7 +9310,7 @@ public:
const auto rt = get_vr<u8[16]>(op.rt);
// Checking for zero doeesn't care about the order of the bytes,
// Checking for zero doesn't care about the order of the bytes,
// so load the data before it's byteswapped
if (auto [ok, as] = match_expr(rt, byteswap(match<u8[16]>())); ok)
{
@@ -9291,6 +9322,21 @@ public:
return;
}
const auto ox = get_vr<u32[4]>(op.rt);
// Instead of extracting the value generated by orx, just test the input to orx with ptest
if (auto [ok, as] = match_expr(ox, orx(match<u32[4]>())); ok)
{
m_block->block_end = m_ir->GetInsertBlock();
const auto a = extract(bitcast<u64[2]>(as), 0);
const auto b = extract(bitcast<u64[2]>(as), 1);
const auto cond = eval((a | b) != 0);
const auto addr = eval(extract(get_vr(op.ra), 3) & 0x3fffc);
const auto target = add_block_indirect(op, addr);
m_ir->CreateCondBr(cond.value, target, add_block_next());
return;
}
// Check sign bit instead (optimization)
if (match_vr<s32[4], s64[2]>(op.rt, [&](auto c, auto MP)
@@ -9514,7 +9560,7 @@ public:
const auto rt = get_vr<u8[16]>(op.rt);
// Checking for zero doeesn't care about the order of the bytes,
// Checking for zero doesn't care about the order of the bytes,
// so load the data before it's byteswapped
if (auto [ok, as] = match_expr(rt, byteswap(match<u8[16]>())); ok)
{
@@ -9527,6 +9573,23 @@ public:
}
}
const auto ox = get_vr<u32[4]>(op.rt);
// Instead of extracting the value generated by orx, just test the input to orx with ptest
if (auto [ok, as] = match_expr(ox, orx(match<u32[4]>())); ok)
{
if (target != m_pos + 4)
{
m_block->block_end = m_ir->GetInsertBlock();
const auto a = extract(bitcast<u64[2]>(as), 0);
const auto b = extract(bitcast<u64[2]>(as), 1);
const auto cond = eval((a | b) == 0);
m_ir->CreateCondBr(cond.value, add_block(target), add_block(m_pos + 4));
return;
}
}
// Check sign bit instead (optimization)
if (match_vr<s32[4], s64[2]>(op.rt, [&](auto c, auto MP)
{
@@ -9573,7 +9636,7 @@ public:
const auto rt = get_vr<u8[16]>(op.rt);
// Checking for zero doeesn't care about the order of the bytes,
// Checking for zero doesn't care about the order of the bytes,
// so load the data before it's byteswapped
if (auto [ok, as] = match_expr(rt, byteswap(match<u8[16]>())); ok)
{
@@ -9586,6 +9649,22 @@ public:
}
}
const auto ox = get_vr<u32[4]>(op.rt);
// Instead of extracting the value generated by orx, just test the input to orx with ptest
if (auto [ok, as] = match_expr(ox, orx(match<u32[4]>())); ok)
{
if (target != m_pos + 4)
{
m_block->block_end = m_ir->GetInsertBlock();
const auto a = extract(bitcast<u64[2]>(as), 0);
const auto b = extract(bitcast<u64[2]>(as), 1);
const auto cond = eval((a | b) != 0);
m_ir->CreateCondBr(cond.value, add_block(target), add_block(m_pos + 4));
return;
}
}
// Check sign bit instead (optimization)
if (match_vr<s32[4], s64[2]>(op.rt, [&](auto c, auto MP)
{
+1 -1
View File
@@ -133,7 +133,7 @@ public:
static std::array<atomic_t<spu_function_t>, (1 << 20)>* const g_dispatcher;
// Recompiler entry point
static const spu_function_t g_gateway;
static const built_function<spu_function_t> g_gateway;
// Longjmp to the end of the gateway function (native CC)
static void(*const g_escape)(spu_thread*);

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