Compare commits

..

197 Commits

Author SHA1 Message Date
Ani 17e78a9e6f rpcs3_version: Bump to 0.0.34 2024-11-01 23:22:32 +00:00
oltolm 42751cc8fb SPULLVMRecompiler: remove unnecessary bitcast 2024-11-01 16:31:14 +02:00
Elad e67d090c35 Fixup sys_event_port_send 2024-11-01 10:43:46 +02:00
Elad ddd0494cf4 Silence sys_ss_access_control_engine 2024-11-01 10:43:46 +02:00
Elad 2222807624 RSX/GCM: Fix memory unmapping for HLE GCM 2024-11-01 10:43:46 +02:00
Elad 488814bb2d rsx/vm: Exclude events from VM mutex
Fixes a deadlock from a recent pull request, perhaps also some deadlocks with locking both IDM and VM mutex.
2024-11-01 07:37:57 +02:00
Elad 4206b022b6 Win32/File.cpp: Use ReplaceFile for hardlink overwrite 2024-11-01 07:37:57 +02:00
Elad b87c891ec4 Fixup sys_event to check EBUSY only for PPU->PPU signals 2024-11-01 07:37:57 +02:00
Hasster 5eb4691cd6 Specify that you only need the qtmultimedia when using aqt 2024-10-31 03:45:12 +02:00
Hasster bfcbc13b8a Add more info about Qt in BUILDING.md
Specify that Qt needs a "qtmultimedia" module and provide a link to an alternative download
2024-10-31 03:45:12 +02:00
Elad 5c5edb4785 sys_event: Implement EBUSY for disconnection 2024-10-30 21:15:16 +02:00
Elad edfe940543 utils/sysinfo.cpp: Yield CPU time when measuring TSC freq 2024-10-30 10:06:49 +02:00
elad335 8b8396b945 Filesystem/Win32: Recreate hardlinks on fs::pending_file 2024-10-29 19:26:33 +02:00
elad335 97f2b6b701 Fix get_system_time() 2024-10-29 19:26:33 +02:00
elad335 92bf6ed0a7 Replace rsx::uclock with get_system_time() 2024-10-29 19:26:33 +02:00
elad335 29c1c3df1f sys_event_flag_set: Minor improvement 2024-10-29 19:26:33 +02:00
oltolm cd8954db14 fix deprecation warnings in Qt 6.8 2024-10-28 23:42:02 +01:00
Megamouse 431221f172 Don't log "always" messages in fatal_error_listener until enabled
Opening the console breaks Qt cli popups
2024-10-25 20:10:46 +02:00
elad335 3ecb14dcda sys_event_flag_set: Break atomic operation dependencies 2024-10-25 15:53:53 +03:00
elad335 a325eb52bd Compilation hotfix 2024-10-25 13:21:49 +03:00
elad335 84217917d5 utils/sysinfo.cpp: New TSC calibration technique 2024-10-25 10:00:21 +03:00
elad335 af052b0627 RawSpu: Optimize START register/commands
START MFC proxy commands can be common even after their need, optimize their usage.
2024-10-24 21:03:06 +03:00
elad335 c70c08bb07 utils: Make get_tsc_freq() inlined and non-blocking 2024-10-24 21:03:06 +03:00
elad335 2e8029a45b get_system_time(): Add fast TSC-based path 2024-10-24 21:03:06 +03:00
elad335 a9a454faf7 asm: Fix utils::rational_mul optimization 2024-10-24 21:03:06 +03:00
Elad 3378b03c1f Optimize get_system_time using 128 bit math 2024-10-24 21:03:06 +03:00
elad335 8d9911e383 Implement u64_x_u64_=_u128 optimization 2024-10-24 21:03:06 +03:00
kd-11 60ae4c1121 rsx: Fix crash when host labels option is disabled 2024-10-23 19:28:32 +02:00
kd-11 5ed7d043c4 Fix build and cleanup 2024-10-23 16:33:44 +03:00
kd-11 c28ec457fd gl: Silence compiler warnings 2024-10-23 16:33:44 +03:00
kd-11 a79ef1efb2 gl: Fix check_state compilation error 2024-10-23 16:33:44 +03:00
kd-11 1299aa68b3 cmake: Update build files for GL DMA 2024-10-23 16:33:44 +03:00
kd-11 681debd8f6 gl: Finalize host labels implementation 2024-10-23 16:33:44 +03:00
kd-11 0db06964dc Whitespace 2024-10-23 16:33:44 +03:00
kd-11 6ce1816e3f rsx: Move the host job management into common code to share with GL 2024-10-23 16:33:44 +03:00
kd-11 7fdfbe3c52 gl: Implement basic DMA layer using AMD_pinned_memory 2024-10-23 16:33:44 +03:00
Elad Ashkenazi 3e516df214 SPU: Reimplement SPURS limiter 2024-10-17 13:59:56 +03:00
Zion Nimchuk 899b4aaeec Use system SDL by default since we don't properly support building with just builtin SDL 2024-10-17 09:01:46 +02:00
Zion Nimchuk d2612bed3a Switch to focal for aarch64, update Qt 2024-10-17 09:01:46 +02:00
Zion Nimchuk 42b255a4a2 Fix checkrt bundling and remove legacy deploy script 2024-10-17 09:01:46 +02:00
Antonino Di Guardo 18c01f7151 Fixed compilation with cmake on Windows (#16184)
* Fixed compilation with cmake on Windows
* cleanup on post build actions for Windows on cmake solution + minor cleanup
* fix link error on IntelJITEvents
2024-10-15 17:53:31 +02:00
shinra-electric 4cd1d639ed 3rd Party: Bump MoltenVK to 1.2.11 (Vulkan SDK 1.3.296) (#16190) 2024-10-15 16:40:45 +02:00
Megamouse 2732d6c3dc Qt: Make sure that table columns and their actions have the same state after restoring the layout 2024-10-15 12:59:37 +02:00
nastys 8e4f5cc7b3 Update build-mac.sh 2024-10-15 10:28:00 +02:00
Elad Ashkenazi e58a3ab7e0 sys_spu: Fix order of some checks 2024-10-15 10:42:22 +03:00
Elad Ashkenazi e0e1c729cd Fix sys_spu_thread_group_disconnect_event 2024-10-15 10:42:22 +03:00
Elad Ashkenazi 7c6b558647 Improve sys_spu_thread_initialize 2024-10-15 09:36:36 +03:00
Elad Ashkenazi 217c924d42 Fix sys_vm_memory_map 2024-10-15 09:36:36 +03:00
Megamouse 7b92cbcb9a input: use std::array for sticks, sensors and motors
We always have the same amount of those.
So using a vector has always been a bit confusing.
2024-10-15 01:50:22 +02:00
Megamouse c882f0baf0 input: fix segfault caused by lockless std::move of stick vector
The copy assignment seems to fix this
2024-10-15 01:50:22 +02:00
nastys f1f124dcbf macOS arm64 CI: Fix packages requiring curl, and fix Ventura (#16193) 2024-10-15 00:01:13 +02:00
Megamouse d4ce5b86ec Improve log file creation error message
Early out in file_writer ctor instead of large if else
2024-10-14 21:29:51 +02:00
Megamouse 16c1b9ed73 Fix some narrowing warnings 2024-10-14 21:29:51 +02:00
Elad Ashkenazi 42ee2463c7 Initialize some spu_thread members 2024-10-14 20:15:14 +03:00
Elad Ashkenazi 2fc9ae5d28 sys_vm: Argument checking fixes 2024-10-14 20:15:14 +03:00
Elad Ashkenazi 28dc7356a8 sys_memory: Fix argument size type 2024-10-14 20:15:14 +03:00
Elad Ashkenazi f6c585902a sys_spu: Fix SPU queue index type 2024-10-14 20:15:14 +03:00
Elad Ashkenazi 693cf9950f sys_spu: Minor fixes 2024-10-14 20:15:14 +03:00
Elad Ashkenazi cef3ee2d80 SPU: More SPURS limiter fixes 2024-10-14 06:30:05 +03:00
Elad Ashkenazi 8fac136056 SPU: SPURS pause based average task order duration 2024-10-11 17:41:34 +03:00
Elad Ashkenazi fa707047e6 SPU: Remove illegal SPURS setting value 2024-10-11 07:28:28 +03:00
Elad c009215983 SPU: Fix "Max SPURS Threads" performance 2024-10-11 07:28:28 +03:00
Elad Ashkenazi d51d5ce86d SPURS limiter tweaks 2024-10-07 15:02:23 +03:00
RipleyTom 36da83592a Improve AMD cpu detection 2024-10-07 05:36:19 +02:00
Megamouse 0a57c459b6 overlays: add friends list to home menu 2024-10-06 09:57:20 +02:00
Megamouse 73fe420d09 RPCN: add overlay messages on friend requests 2024-10-06 06:35:48 +02:00
Megamouse a85cdb5947 Update FAudio to 24.10 2024-10-05 22:50:30 +02:00
Megamouse 511f8a91f1 Update SDL to 2.30.8 2024-10-05 22:50:30 +02:00
Megamouse 2d1da95bc1 VS: Fix zstd debug lib 2024-10-05 22:50:30 +02:00
Malcolm Jestadt 967adaf9db SPU LLVM: Compute frest exponent at runtime rather than using the lookup table
- Provides a small speedup and smaller codesize
2024-10-05 20:44:23 +03:00
Malcolm Jestadt 8ca60df1ab SPU LLVM: Add optimized path for spu_re_acc special cases
- Uses vfixupimmps (AVX-512), 5 instructions down to 1
2024-10-05 20:44:23 +03:00
RipleyTom 4832267307 Fixes audio buffering on non-windows platforms 2024-10-05 11:44:15 +03:00
Megamouse 6bb01066fb VS: Add new build scripts to filters 2024-10-03 15:35:20 +02:00
Megamouse 522124d695 Remove unused SPIRV submodules 2024-10-03 15:35:20 +02:00
Megamouse d9c4e14c40 VS: fix debug builds 2024-10-03 15:35:20 +02:00
Megamouse 00944a5d71 VS: Add buildfiles to filter 2024-10-03 15:35:20 +02:00
kd-11 e9bc99253d rsx: Verify that channel remap is initialized before applying swizzles 2024-10-03 15:02:09 +03:00
kd-11 e9a45a6d06 rsx: Clarify OGL and VK difference when handling border texels 2024-10-03 15:02:09 +03:00
kd-11 497b9ba55b rsx: Make use of remapped border colors 2024-10-03 15:02:09 +03:00
kd-11 d1d04b1b32 rsx: Implement texture border color decode to remapped rgba 2024-10-03 15:02:09 +03:00
kd-11 826f805902 rsx: Use a proper struct to wrap around channel remap operations 2024-10-03 15:02:09 +03:00
kd-11 b1b0ac4433 rsx/vs: Restructure filters into functional units 2024-10-03 15:02:09 +03:00
kd-11 3f28f88a35 vk: Add support for explicit border colors 2024-10-03 15:02:09 +03:00
Zion 938306a7bc Bump linux x64 docker to 1.7.1, Qt 6.7.3 2024-10-02 07:09:02 +02:00
kd-11 1568366d9c Do not link intel JIT events when compiling LLVM for ARM64 2024-10-01 19:20:26 +03:00
kd-11 79614562b9 Move x64 appimage builder to its own legacy script 2024-10-01 19:20:26 +03:00
Megamouse 96e495c61d Qt/Overlays: Add home menu shortcut to game window 2024-10-01 03:25:36 +02:00
kd-11 e4dd957bbc linux/aarch64: Fix CI release upload 2024-10-01 03:03:14 +03:00
kd-11 aace685202 Typo fix 2024-10-01 01:14:40 +03:00
kd-11 fa6f999754 linux: Fix steam deck issues 2024-10-01 01:14:40 +03:00
kd-11 f18649567f Include compositor module in appimage for shell integrations 2024-09-30 18:33:54 +03:00
kd-11 ae580c7749 Enable artifact upload 2024-09-30 18:33:54 +03:00
kd-11 c711764850 Update building instructions for linux arm64 2024-09-30 18:33:54 +03:00
kd-11 7d5dc101fa Fix shellcheck 2024-09-30 18:33:54 +03:00
kd-11 252e69a6ba Add different suffix per architecture 2024-09-30 18:33:54 +03:00
kd-11 c4be603279 Deploy aarch64 linux appimages 2024-09-30 18:33:54 +03:00
kd-11 90bf35bb1e Fix deploy script 2024-09-30 18:33:54 +03:00
kd-11 47fb653044 Fix aarch64 build script 2024-09-30 18:33:54 +03:00
kd-11 4fe306c9ad aarch64: linux CI 2024-09-30 18:33:54 +03:00
kd-11 03a58d36da Do not attempt to link in intel JIT events 2024-09-30 18:33:54 +03:00
Megamouse d379dd4c8d overlays: Ignore 14 in anisotropic settings
This value has no CELL equivalent
2024-09-29 19:17:39 +02:00
Megamouse 7fc31e20b3 Fix 120 fps frame limit 2024-09-29 19:17:39 +02:00
schm1dt ‎ d11fe09419 Use native theme on macOS, hide Dark Mode toggle 2024-09-29 13:49:28 +02:00
RipleyTom c49ff490bc Fix scenp_score_record_score param check 2024-09-29 12:09:11 +03:00
Antonino Di Guardo 3f66297593 Fix crash on VFS Tool (#16146) 2024-09-29 03:11:27 +03:00
schm1dtxbox 37d2317b68 Update shortcut_utils.cpp 2024-09-28 13:14:18 +02:00
schm1dtxbox a1d55e5a54 Update azure-pipelines.yml 2024-09-28 13:14:18 +02:00
Megamouse 0ba0f11c4a Qt: Try to fix classic stylesheet after Qt 6.7.3 update 2024-09-28 01:39:33 +02:00
Elad f0c60b42c2 SPURS Task limit hotfix (#16140) 2024-09-27 22:15:06 +03:00
RipleyTom 88adaa9d2d Add some extra param handling for cellNetCtlGetInfo 2024-09-27 19:14:09 +02:00
RipleyTom 56099e79da Fix for clang 19 2024-09-27 19:14:09 +02:00
Megamouse 4ba4268282 Qt/shortcuts: add handler id to log messages 2024-09-27 17:57:49 +02:00
Megamouse 2661b6a71c Qt: Try to improve default stylesheet after Qt 6.7.3 update 2024-09-27 17:57:49 +02:00
Megamouse e58a89af2d Qt: Enable game window shortcuts 2024-09-27 17:57:49 +02:00
Megamouse ad3d8675e7 Qt 6.7.3 2024-09-27 15:06:40 +02:00
Megamouse 18d9ca5928 Qt 6.7.2 2024-09-27 15:06:40 +02:00
Megamouse 5ab955d9c4 Qt 6.7.1 2024-09-27 15:06:40 +02:00
Megamouse 2b4a90781a Qt 6.7.0
Also fix new stylesheet issue: windows11 style is now default.
This currently breaks custom stylesheets.
Use windowsvista style as default
2024-09-27 15:06:40 +02:00
Elad 10dece1c80 SPU: Improve SPURS Task limit algorithm 2024-09-27 12:43:44 +03:00
RipleyTom 9dd0b055d0 Fake sceNpMatching2GetLobbyInfoList 2024-09-26 21:12:10 +02:00
Megamouse 9e460ebe0a MacOs/Arm64/Shortcuts: Add more plist entries 2024-09-26 19:48:40 +02:00
Megamouse 7106bfcfb9 Shortcuts: Try to create shortcut link path if it doesn't exist 2024-09-26 19:48:40 +02:00
Megamouse c936de7c20 VS: add mac and linux hidapi files for improved input debugging 2024-09-26 19:48:40 +02:00
Elad Ashkenazi 60b5adab63 SPU: SPURS limit update 2024-09-26 06:59:20 +03:00
Elad Ashkenazi e3c8b3d524 GUI: Add SPURS limit to home menu 2024-09-26 06:59:20 +03:00
Elad Ashkenazi 8b79fd3da1 SPU: Make SPURS limit a dynamic setting 2024-09-26 06:59:20 +03:00
Megamouse feedc183a4 Qt: Tiny improvements to Cam/Mic permissions 2024-09-25 20:09:39 +02:00
Megamouse c4282e63fb Qt: Simplify some string conversion bloat 2024-09-25 20:09:39 +02:00
kd-11 82f97d33d1 aarch64: Correctly implement the null function trap 2024-09-25 15:48:36 +03:00
schm1dtxbox c1d43aff05 Brute-force Qt cache invalidation
Needed for qtimageformats changes to kick in
2024-09-25 09:11:28 +02:00
schm1dtxbox a14c166aab Ditto, but for arm64 ci 2024-09-25 09:11:28 +02:00
schm1dtxbox 7d39ac4e1e Download qtimageformats so that shortcut icons create successfully 2024-09-25 09:11:28 +02:00
schm1dtxbox f40d8b669c Fix camera permission prompts
Apparently calling qt_finalize_target in the CMake list is needed for permissions-related stuff to work.
2024-09-25 09:11:28 +02:00
Elad Ashkenazi 4b0a5bd1b8 SPU: Fix callback leak 2024-09-24 10:31:37 +03:00
Elad Ashkenazi 6995467ff6 SPU: SPURS limiter algorithm update 2024-09-24 10:31:37 +03:00
Elad Ashkenazi ad42a2b89a SPU: Task-based SPURS limiter 2024-09-24 10:31:37 +03:00
Megamouse c4334f5142 Add AArch64 files to VS Project 2024-09-23 23:00:58 +02:00
Megamouse 4c3d243672 MacOs/Arm64: Fix warning 2024-09-23 23:00:58 +02:00
Megamouse 340c17f422 Update curl to 8.10.1 2024-09-23 21:59:01 +02:00
Megamouse 18a99a7d8f input: use static hid singleton for init and exit 2024-09-23 21:59:01 +02:00
Megamouse 31b133b012 Fix yet another warning 2024-09-23 21:59:01 +02:00
nastys eb9acd9b56 macOS arm64 CI (#16070)
* Merge MacOS jobs
* Code signing
* rpath hack
* Upgrade macOS VM to 13
* Update llvm compiler
* Update to macOS Sonoma
* Update build-mac.sh
* Remove unnecessary version check
* Disable Homebrew cache
* Use macosx_version_min
* Downgrade min version and VM to 13
* Force -D__MAC_OS_X_VERSION_MIN_REQUIRED=130000
* Ignore -Welaborated-enum-base in display_sleep
* Move compiler version to env variable
* Enable auto-updater on macOS ARM64
2024-09-22 20:39:43 +02:00
Ani 02362a4807 spu: Do not apply a Max SPURS Threads limit to libSail
On all the tested games (e.g. Naruto Ultimate Ninja Storm, Catherine),
limiting SPURS threads for "_libsailCellSpursKernelGroup" causes video
playback to hang and the game to permanently freeze. These games still
function properly while limiting the other CellSpursKernelGroup groups,
as I've confirmed through manual thread pausing.

I have not found a single example that shows that 
_libsailCellSpursKernelGroup threads can be limited without the game 
freezing.

This allows the Max SPURS Threads setting to work with more games, or to 
work with a lower thread limit count for games where it already works.
2024-09-21 15:02:41 +02:00
Elad Ashkenazi 466a93dca5 Debugger: Fix thread-selection and refactoring 2024-09-20 23:52:37 +03:00
Megamouse c89e30b3d9 cellMsgDialog: only abort dialogs that were actually spawned by cellMsgDialog 2024-09-20 20:43:57 +02:00
Megamouse d88b7f6fde cellSaveData: improve logging for overlays 2024-09-20 20:43:57 +02:00
Megamouse d0a13c1a5a Improve logging during RPCS3 updates 2024-09-20 15:53:00 +02:00
Antonino Di Guardo df9275819e Added reconciliation functions for game list file (games.yml) (#16061) 2024-09-20 08:46:51 +02:00
nastys 5b5bfaf696 Updater API V3 (macOS only) (#16086) 2024-09-19 21:58:00 +02:00
RipleyTom 3d9c8a670e Implement old matching API 2024-09-19 20:34:56 +02:00
Elad Ashkenazi cf65571be7 SPU Analyzer Hotfix 2024-09-19 10:00:18 +03:00
capriots 66eae05e75 cellAtracXdec: fix FFmpeg warning 2024-09-18 07:57:10 +02:00
Antonino Di Guardo d1648dd707 [TESTERS NEEDED] Improved contextual menu (#16038) 2024-09-14 21:51:42 +02:00
capriots 7f2534819e cellAtracXdec: review fixes 2024-09-14 19:37:21 +02:00
capriots e678931cee cellAtracXdec: review fixes 2024-09-14 19:37:21 +02:00
capriots 965dbf2c12 cellAtracXdec: review fixes 2024-09-14 19:37:21 +02:00
capriots 624f34ae13 cellAtracXdec: review fixes 2024-09-14 19:37:21 +02:00
capriots d60eced317 cellAtracXdec: set to HLE by default 2024-09-14 19:37:21 +02:00
capriots c813c5e953 cellAtracXdec implementation 2024-09-14 19:37:21 +02:00
capriots 5ce9c5b09f cellAdec: add internal datatypes 2024-09-14 19:37:21 +02:00
Megamouse 7df33bc8c0 Update curl to 8.10.0 2024-09-14 18:12:02 +02:00
Megamouse 0abaac90a8 Update libpng to 1.6.44 2024-09-14 18:12:02 +02:00
Megamouse e5a526e4d6 input: enable squircle settings in keyboard pad handler
Clamp squircled values to radius 1.
Also set kb and evdev default to 8000 as the others
2024-09-14 17:20:07 +02:00
Elad Ashkenazi 8131f40269 SPU Analyzer: Fix dereferencing freed reference 2024-09-13 19:32:15 +03:00
Elad Ashkenazi 743f9a9f51 rsx: Add 120fps and monitor refresh-rate frame limits 2024-09-12 13:49:03 +03:00
Megamouse 0a54e34a9b Update FFMPEG to properly rebased branch
The prior FFMPEG merge was not properly rebased to Vita3K master.
I created a backup branch arm64_old on the current commit.
I reset master to vita3k master and cherry picked our 5 commits.
Then I squashed the last 2 commits because one of them was obsolete.
2024-09-08 21:01:43 +02:00
Megamouse 53c84577c0 Set cellSysutilAvcExtInitOptionParam to notice 2024-09-08 20:04:30 +02:00
Megamouse 00e5d54be7 cellSysutilAvc: fix cellSysutilAvcEnumPlayers error check 2024-09-08 20:04:30 +02:00
Megamouse d13acdb484 Fix some warning 2024-09-08 20:04:30 +02:00
kd-11 92c1a8c45d sysinfo/arm64: Improve code around registry access and document the fields 2024-09-08 17:41:29 +03:00
kd-11 939479f55e ci: Fix clang linux failure 2024-09-08 17:41:29 +03:00
kd-11 d19d0cb70d windows/arm64: Implement fallback OS version detection 2024-09-08 17:41:29 +03:00
kd-11 31ce32709e build: Disble fixed base for windows-on-arm 2024-09-08 17:41:29 +03:00
kd-11 4f27af9949 Fix compilation warning 2024-09-08 17:41:29 +03:00
kd-11 b31280e387 Fix GCC compilation for windows 2024-09-08 17:41:29 +03:00
Elad Ashkenazi 03980304cf SPU Analyser: Fix source termination of starting block 2024-09-08 06:51:57 +03:00
Ani c852ae1a22 ffmpeg: Update submodule, supports linux arm64
Enables compatibility with linux arm64
2024-09-07 18:19:06 +02:00
schm1dtxbox 58f3841383 Fix arm64 RPCS3 being reported by macOS as an iOS app
macOS/Mac OS X reports arm64-only app bundles (so not Intel only or Universal) as being iOS apps in various places like Settings and System Information unless the bundle's Info.plist explicitly specifies it is only supported on Mac OS X.
2024-09-07 16:26:19 +02:00
Elad Ashkenazi 9385f0673b Debugger: Non-blocking thread list refresh 2024-09-06 20:28:11 +03:00
Megamouse 2bc0d19c9d cellSysutilAvcExt: add some param checks 2024-09-06 17:17:17 +02:00
Megamouse fe1fa45956 cellSysutilAvcExt: fix some params and size of long (the disassembly makes zero sense with s64) 2024-09-06 17:17:17 +02:00
Megamouse 6fa993645e cellSysutilAvc: add param checks 2024-09-06 17:17:17 +02:00
Megamouse 144ff82402 Stub cellSysutilAvc 2024-09-06 17:17:17 +02:00
Megamouse f285b0c053 Update FAudio to 24.09 2024-09-06 17:17:17 +02:00
Megamouse 7e9cf297ac cellPad: Remove obsolete comment 2024-09-06 17:17:17 +02:00
Megamouse d780355784 cellPad: draw debug overlay for basic input debugging of port 0 2024-09-06 08:33:55 +02:00
Megamouse b0194ba6af cellPad: scale emulated skateboard IR input down 2024-09-06 08:33:55 +02:00
Megamouse deba582353 Qt: Force reset of debugger when a different game is running 2024-09-06 05:05:54 +03:00
Megamouse 303c6715dd Qt: Don't start the debug update timer in the constructor
This caused the timer to be active even when the debugger is initially hidden.
2024-09-06 05:05:54 +03:00
552eden b4ff988bd8 Add support for SHRED dongle
changed support from ride dongle to ride + shred dongle
2024-09-05 18:23:51 +02:00
kd-11 7e3b8b5cdb c++-ify empty return 2024-09-04 07:49:49 +03:00
kd-11 7353696014 cpu: Format additions to sse2neon to match the rest of the file 2024-09-04 07:49:49 +03:00
kd-11 a60eab6e36 aarch64: Fix compilation for windows-on-arm 2024-09-04 07:49:49 +03:00
Megamouse 23f9eb57e5 patch_manager: set config_key_role to current key after handle_item_selected
The key was never changed if you selected different configurables in the same item.
This means that all configurables used the same value list.
2024-09-04 01:03:33 +02:00
snake ad1eb93a05 cellMic: add 16-bit PCM to 32-bit float conversion for DSP stream (#16030) 2024-09-03 23:25:24 +02:00
Megamouse 2fb0c499ea Update SDL to 2.30.7 2024-09-03 03:18:21 +02:00
Megamouse fbebdc09b7 Qt: ignore double clicks unless they are left clicks 2024-09-02 23:26:56 +02:00
293 changed files with 12113 additions and 3345 deletions
+1 -1
View File
@@ -3,7 +3,7 @@
# Pull all the submodules except llvm
# Note: Tried to use git submodule status, but it takes over 20 seconds
# shellcheck disable=SC2046
git submodule -q update --init --depth 1 $(awk '/path/ && !/llvm/ && !/SPIRV/ { print $3 }' .gitmodules)
git submodule -q update --init --depth 1 $(awk '/path/ && !/llvm/ { print $3 }' .gitmodules)
# Prefer newer Clang than in base system (see also .ci/install-freebsd.sh)
# libc++ isn't in llvm* packages, so download manually
+47
View File
@@ -0,0 +1,47 @@
#!/bin/sh -ex
if [ -z "$CIRRUS_CI" ]; then
cd rpcs3 || exit 1
fi
git config --global --add safe.directory '*'
# Pull all the submodules except llvm
# shellcheck disable=SC2046
git submodule -q update --init $(awk '/path/ && !/llvm/ { print $3 }' .gitmodules)
mkdir build && cd build || exit 1
export CC="${CLANG_BINARY}"
export CXX="${CLANGXX_BINARY}"
cmake .. \
-DCMAKE_INSTALL_PREFIX=/usr \
-DUSE_NATIVE_INSTRUCTIONS=OFF \
-DUSE_PRECOMPILED_HEADERS=OFF \
-DCMAKE_C_FLAGS="$CFLAGS" \
-DCMAKE_CXX_FLAGS="$CFLAGS" \
-DUSE_SYSTEM_CURL=ON \
-DUSE_SDL=ON \
-DUSE_SYSTEM_SDL=ON \
-DUSE_SYSTEM_FFMPEG=OFF \
-DUSE_DISCORD_RPC=ON \
-DOpenGL_GL_PREFERENCE=LEGACY \
-DLLVM_DIR=/opt/llvm/lib/cmake/llvm \
-DSTATIC_LINK_LLVM=ON \
-G Ninja
ninja; build_status=$?;
cd ..
shellcheck .ci/*.sh
# If it compiled succesfully let's deploy.
# Azure and Cirrus publish PRs as artifacts only.
{ [ "$CI_HAS_ARTIFACTS" = "true" ];
} && SHOULD_DEPLOY="true" || SHOULD_DEPLOY="false"
if [ "$build_status" -eq 0 ] && [ "$SHOULD_DEPLOY" = "true" ]; then
.ci/deploy-linux.sh "aarch64"
fi
+3 -2
View File
@@ -9,7 +9,7 @@ git config --global --add safe.directory '*'
# Pull all the submodules except llvm
# Note: Tried to use git submodule status, but it takes over 20 seconds
# shellcheck disable=SC2046
git submodule -q update --init $(awk '/path/ && !/llvm/ && !/SPIRV/ { print $3 }' .gitmodules)
git submodule -q update --init $(awk '/path/ && !/llvm/ { print $3 }' .gitmodules)
mkdir build && cd build || exit 1
@@ -42,6 +42,7 @@ cmake .. \
-DCMAKE_RANLIB="$RANLIB" \
-DUSE_SYSTEM_CURL=ON \
-DUSE_SDL=ON \
-DUSE_SYSTEM_SDL=ON \
-DUSE_SYSTEM_FFMPEG=OFF \
-DUSE_DISCORD_RPC=ON \
-DOpenGL_GL_PREFERENCE=LEGACY \
@@ -61,5 +62,5 @@ shellcheck .ci/*.sh
} && SHOULD_DEPLOY="true" || SHOULD_DEPLOY="false"
if [ "$build_status" -eq 0 ] && [ "$SHOULD_DEPLOY" = "true" ]; then
.ci/deploy-linux.sh
.ci/deploy-linux.sh "x86_64"
fi
+153
View File
@@ -0,0 +1,153 @@
#!/bin/sh -ex
# shellcheck disable=SC2086
brew_arm64_install_packages() {
for pkg in "$@"; do
echo "Fetching bottle for $pkg (arm64)..."
bottle_path="$("$BREW_ARM64_PATH/bin/brew" --cache --bottle-tag=arm64_ventura "$pkg")"
if [ ! -f "$bottle_path" ]; then
if ! "$BREW_ARM64_PATH/bin/brew" fetch --force --verbose --debug --bottle-tag=arm64_ventura "$pkg"; then
echo "Failed to fetch bottle for $pkg"
return 1
fi
bottle_path="$("$BREW_ARM64_PATH/bin/brew" --cache --bottle-tag=arm64_ventura "$pkg")"
fi
echo "Installing $pkg (arm64)..."
"$BREW_ARM64_PATH/bin/brew" install --force --force-bottle --ignore-dependencies "$bottle_path" || true
done
}
export HOMEBREW_NO_AUTO_UPDATE=1
export HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK=1
export HOMEBREW_NO_INSTALL_CLEANUP=1
/usr/local/bin/brew update
sudo rm -rf /usr/local/Cellar/curl /usr/local/opt/curl
/usr/local/bin/brew install -f --overwrite curl
/usr/local/bin/brew uninstall -f --ignore-dependencies ffmpeg
/usr/local/bin/brew install -f --build-from-source ffmpeg@5 || true
/usr/local/bin/brew install -f --overwrite python || true
/usr/local/bin/brew link --overwrite python || true
/usr/local/bin/brew install -f --overwrite nasm ninja p7zip ccache pipenv #create-dmg
/usr/local/bin/brew link -f curl || true
/usr/local/bin/brew install llvm@$LLVM_COMPILER_VER glew cmake sdl2 vulkan-headers coreutils
/usr/local/bin/brew link -f llvm@$LLVM_COMPILER_VER ffmpeg@5 || true
export BREW_ARM64_PATH="/opt/homebrew1"
sudo mkdir -p "$BREW_ARM64_PATH"
sudo chmod 777 "$BREW_ARM64_PATH"
curl -L https://github.com/Homebrew/brew/tarball/master | tar xz --strip 1 -C "$BREW_ARM64_PATH"
#"$BREW_ARM64_PATH/bin/brew" update
# libvorbis requires Homebrew-installed curl, but we can't run it on x64, and we also need the aarch64 libs, so we swap the binary
brew_arm64_install_packages curl
mv /opt/homebrew1/opt/curl/bin/curl /opt/homebrew1/opt/curl/bin/curl.bak
ln -s /usr/local/opt/curl/bin/curl /opt/homebrew1/opt/curl/bin/curl
brew_arm64_install_packages 0mq aom aribb24 ca-certificates cjson dav1d ffmpeg@5 fontconfig freetype freetype2 gettext glew gmp gnutls lame libbluray libidn2 libnettle libogg libpng librist libsodium libsoxr libtasn libtasn1 libunistring libvmaf libvorbis libvpx libx11 libxau libxcb libxdmcp llvm@$LLVM_COMPILER_VER mbedtls molten-vk nettle opencore-amr openjpeg openssl opus p11-kit pkg-config pkgconfig pzstd rav1e sdl2 snappy speex srt svt-av1 theora vulkan-headers webp x264 x265 xz z3 zeromq zmq zstd
"$BREW_ARM64_PATH/bin/brew" link -f ffmpeg@5
# moltenvk based on commit for 1.2.11 release
wget https://raw.githubusercontent.com/Homebrew/homebrew-core/6bfc8950c696d1f952425e8af2a6248603dc0df9/Formula/m/molten-vk.rb
/usr/local/bin/brew install -f --overwrite ./molten-vk.rb
export CXX=clang++
export CC=clang
export BREW_PATH;
BREW_PATH="$(brew --prefix)"
export BREW_X64_PATH;
BREW_X64_PATH="$("/usr/local/bin/brew" --prefix)"
export BREW_BIN="/usr/local/bin"
export BREW_SBIN="/usr/local/sbin"
export CMAKE_EXTRA_OPTS='-DLLVM_TARGETS_TO_BUILD=arm64'
export WORKDIR;
WORKDIR="$(pwd)"
# Get Qt
if [ ! -d "/tmp/Qt/$QT_VER" ]; then
mkdir -p "/tmp/Qt"
git clone https://github.com/engnr/qt-downloader.git
cd qt-downloader
git checkout f52efee0f18668c6d6de2dec0234b8c4bc54c597
cd "/tmp/Qt"
"$BREW_X64_PATH/bin/pipenv" run pip3 install py7zr requests semantic_version lxml
mkdir -p "$QT_VER/macos" ; ln -s "macos" "$QT_VER/clang_64"
"$BREW_X64_PATH/bin/pipenv" run "$WORKDIR/qt-downloader/qt-downloader" macos desktop "$QT_VER" clang_64 --opensource --addons qtmultimedia qtimageformats
fi
cd "$WORKDIR"
ditto "/tmp/Qt/$QT_VER" "qt-downloader/$QT_VER"
export Qt6_DIR="$WORKDIR/qt-downloader/$QT_VER/clang_64/lib/cmake/Qt$QT_VER_MAIN"
export SDL2_DIR="$BREW_ARM64_PATH/opt/sdl2/lib/cmake/SDL2"
export PATH="$BREW_X64_PATH/opt/llvm@$LLVM_COMPILER_VER/bin:$WORKDIR/qt-downloader/$QT_VER/clang_64/bin:$BREW_BIN:$BREW_SBIN:/usr/bin:/bin:/usr/sbin:/sbin:/opt/X11/bin:/Library/Apple/usr/bin:$PATH"
export LDFLAGS="-L$BREW_ARM64_PATH/lib $BREW_ARM64_PATH/opt/ffmpeg@5/lib/libavcodec.dylib $BREW_ARM64_PATH/opt/ffmpeg@5/lib/libavformat.dylib $BREW_ARM64_PATH/opt/ffmpeg@5/lib/libavutil.dylib $BREW_ARM64_PATH/opt/ffmpeg@5/lib/libswscale.dylib $BREW_ARM64_PATH/opt/ffmpeg@5/lib/libswresample.dylib $BREW_ARM64_PATH/opt/llvm@$LLVM_COMPILER_VER/lib/c++/libc++.1.dylib $BREW_ARM64_PATH/lib/libSDL2.dylib $BREW_ARM64_PATH/lib/libGLEW.dylib $BREW_ARM64_PATH/opt/llvm@$LLVM_COMPILER_VER/lib/libunwind.1.dylib -Wl,-rpath,$BREW_ARM64_PATH/lib"
export CPPFLAGS="-I$BREW_ARM64_PATH/include -I$BREW_X64_PATH/include -no-pie -D__MAC_OS_X_VERSION_MIN_REQUIRED=130000"
export CFLAGS="-D__MAC_OS_X_VERSION_MIN_REQUIRED=130000"
export LIBRARY_PATH="$BREW_ARM64_PATH/lib"
export LD_LIBRARY_PATH="$BREW_ARM64_PATH/lib"
export VULKAN_SDK
VULKAN_SDK="$BREW_ARM64_PATH/opt/molten-vk"
ln -s "$VULKAN_SDK/lib/libMoltenVK.dylib" "$VULKAN_SDK/lib/libvulkan.dylib" || true
export VK_ICD_FILENAMES="$VULKAN_SDK/share/vulkan/icd.d/MoltenVK_icd.json"
export LLVM_DIR
LLVM_DIR="$BREW_ARM64_PATH/opt/llvm@$LLVM_COMPILER_VER"
# exclude ffmpeg, LLVM, and sdl from submodule update
# shellcheck disable=SC2046
git submodule -q update --init --depth=1 --jobs=8 $(awk '/path/ && !/ffmpeg/ && !/llvm/ && !/SDL/ { print $3 }' .gitmodules)
# 3rdparty fixes
sed -i '' "s/extern const double NSAppKitVersionNumber;/const double NSAppKitVersionNumber = 1343;/g" 3rdparty/hidapi/hidapi/mac/hid.c
rm -rf build
mkdir build && cd build || exit 1
export MACOSX_DEPLOYMENT_TARGET=13.0
"$BREW_X64_PATH/bin/cmake" .. \
-DUSE_SDL=ON \
-DUSE_DISCORD_RPC=OFF \
-DUSE_VULKAN=ON \
-DUSE_ALSA=OFF \
-DUSE_PULSE=OFF \
-DUSE_AUDIOUNIT=ON \
-DUSE_SYSTEM_FFMPEG=ON \
-DLLVM_CCACHE_BUILD=OFF \
-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 \
-DLLVM_USE_PERF=OFF \
-DLLVM_ENABLE_Z3_SOLVER=OFF \
-DUSE_NATIVE_INSTRUCTIONS=OFF \
-DUSE_SYSTEM_MVK=ON \
-DUSE_SYSTEM_FAUDIO=OFF \
-DUSE_SYSTEM_SDL=ON \
$CMAKE_EXTRA_OPTS \
-DLLVM_TARGET_ARCH=arm64 \
-DCMAKE_OSX_ARCHITECTURES=arm64 \
-DCMAKE_IGNORE_PATH="$BREW_X64_PATH/lib" \
-DCMAKE_IGNORE_PREFIX_PATH=/usr/local/opt \
-DCMAKE_SYSTEM_PROCESSOR=arm64 \
-DCMAKE_TOOLCHAIN_FILE=buildfiles/cmake/TCDarwinARM64.cmake \
-DCMAKE_CXX_FLAGS="-D__MAC_OS_X_VERSION_MIN_REQUIRED=130000" \
-G Ninja
"$BREW_PATH/bin/ninja"; build_status=$?;
cd ..
{ [ "$CI_HAS_ARTIFACTS" = "true" ];
} && SHOULD_DEPLOY="true" || SHOULD_DEPLOY="false"
if [ "$build_status" -eq 0 ] && [ "$SHOULD_DEPLOY" = "true" ]; then
.ci/deploy-mac-arm64.sh
fi
Executable → Regular
+16 -12
View File
@@ -1,5 +1,6 @@
#!/bin/sh -ex
# shellcheck disable=SC2086
export HOMEBREW_NO_AUTO_UPDATE=1
export HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK=1
brew unlink certifi
@@ -7,18 +8,17 @@ brew install -f --overwrite nasm ninja p7zip ccache pipenv #create-dmg
#/usr/sbin/softwareupdate --install-rosetta --agree-to-license
arch -x86_64 /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
arch -x86_64 /usr/local/bin/brew install -f --overwrite python@3.12 || arch -x86_64 /usr/local/bin/brew link --overwrite python@3.12
arch -x86_64 /usr/local/bin/brew update
arch -x86_64 /usr/local/bin/brew install -f --overwrite python || arch -x86_64 /usr/local/bin/brew link --overwrite python
arch -x86_64 /usr/local/bin/brew uninstall -f --ignore-dependencies ffmpeg
arch -x86_64 /usr/local/bin/brew install -f --build-from-source ffmpeg@5
arch -x86_64 /usr/local/bin/brew reinstall -f --build-from-source gnutls freetype
arch -x86_64 /usr/local/bin/brew install llvm@16 glew cmake sdl2 vulkan-headers coreutils
arch -x86_64 /usr/local/bin/brew link -f llvm@16 ffmpeg@5
arch -x86_64 /usr/local/bin/brew install llvm@$LLVM_COMPILER_VER glew cmake sdl2 vulkan-headers coreutils
arch -x86_64 /usr/local/bin/brew link -f llvm@$LLVM_COMPILER_VER ffmpeg@5
# moltenvk based on commit for 1.2.10 release
wget https://raw.githubusercontent.com/Homebrew/homebrew-core/0d9f25fbd1658e975d00bd0e8cccd20a0c2cb74b/Formula/m/molten-vk.rb
# moltenvk based on commit for 1.2.11 release
wget https://raw.githubusercontent.com/Homebrew/homebrew-core/6bfc8950c696d1f952425e8af2a6248603dc0df9/Formula/m/molten-vk.rb
arch -x86_64 /usr/local/bin/brew install -f --overwrite ./molten-vk.rb
#export MACOSX_DEPLOYMENT_TARGET=12.0
export CXX=clang++
export CC=clang
@@ -42,7 +42,7 @@ if [ ! -d "/tmp/Qt/$QT_VER" ]; then
cd "/tmp/Qt"
"$BREW_X64_PATH/bin/pipenv" run pip3 install py7zr requests semantic_version lxml
mkdir -p "$QT_VER/macos" ; ln -s "macos" "$QT_VER/clang_64"
"$BREW_X64_PATH/bin/pipenv" run "$WORKDIR/qt-downloader/qt-downloader" macos desktop "$QT_VER" clang_64 --opensource --addons qtmultimedia
"$BREW_X64_PATH/bin/pipenv" run "$WORKDIR/qt-downloader/qt-downloader" macos desktop "$QT_VER" clang_64 --opensource --addons qtmultimedia qtimageformats
fi
cd "$WORKDIR"
@@ -51,9 +51,10 @@ ditto "/tmp/Qt/$QT_VER" "qt-downloader/$QT_VER"
export Qt6_DIR="$WORKDIR/qt-downloader/$QT_VER/clang_64/lib/cmake/Qt$QT_VER_MAIN"
export SDL2_DIR="$BREW_X64_PATH/opt/sdl2/lib/cmake/SDL2"
export PATH="$BREW_X64_PATH/opt/llvm@16/bin:$WORKDIR/qt-downloader/$QT_VER/clang_64/bin:$BREW_BIN:$BREW_SBIN:/usr/bin:/bin:/usr/sbin:/sbin:/opt/X11/bin:/Library/Apple/usr/bin:$PATH"
export PATH="$BREW_X64_PATH/opt/llvm@$LLVM_COMPILER_VER/bin:$WORKDIR/qt-downloader/$QT_VER/clang_64/bin:$BREW_BIN:$BREW_SBIN:/usr/bin:/bin:/usr/sbin:/sbin:/opt/X11/bin:/Library/Apple/usr/bin:$PATH"
export LDFLAGS="-L$BREW_X64_PATH/lib -Wl,-rpath,$BREW_X64_PATH/lib"
export CPPFLAGS="-I$BREW_X64_PATH/include -msse -msse2 -mcx16 -no-pie"
export CPPFLAGS="-I$BREW_X64_PATH/include -msse -msse2 -mcx16 -no-pie -D__MAC_OS_X_VERSION_MIN_REQUIRED=130000"
export CFLAGS="-D__MAC_OS_X_VERSION_MIN_REQUIRED=130000"
export LIBRARY_PATH="$BREW_X64_PATH/lib"
export LD_LIBRARY_PATH="$BREW_X64_PATH/lib"
@@ -63,16 +64,18 @@ ln -s "$VULKAN_SDK/lib/libMoltenVK.dylib" "$VULKAN_SDK/lib/libvulkan.dylib"
export VK_ICD_FILENAMES="$VULKAN_SDK/share/vulkan/icd.d/MoltenVK_icd.json"
export LLVM_DIR
LLVM_DIR="BREW_X64_PATH/opt/llvm@16"
# exclude ffmpeg, SPIRV and LLVM, and sdl from submodule update
LLVM_DIR="BREW_X64_PATH/opt/llvm@$LLVM_COMPILER_VER"
# exclude ffmpeg, LLVM, and sdl from submodule update
# shellcheck disable=SC2046
git submodule -q update --init --depth=1 --jobs=8 $(awk '/path/ && !/ffmpeg/ && !/llvm/ && !/SPIRV/ && !/SDL/ { print $3 }' .gitmodules)
git submodule -q update --init --depth=1 --jobs=8 $(awk '/path/ && !/ffmpeg/ && !/llvm/ && !/SDL/ { print $3 }' .gitmodules)
# 3rdparty fixes
sed -i '' "s/extern const double NSAppKitVersionNumber;/const double NSAppKitVersionNumber = 1343;/g" 3rdparty/hidapi/hidapi/mac/hid.c
mkdir build && cd build || exit 1
export MACOSX_DEPLOYMENT_TARGET=13.0
"$BREW_X64_PATH/bin/cmake" .. \
-DUSE_SDL=ON \
-DUSE_DISCORD_RPC=ON \
@@ -99,6 +102,7 @@ mkdir build && cd build || exit 1
-DLLVM_TARGET_ARCH=X86_64 \
-DCMAKE_OSX_ARCHITECTURES=x86_64 \
-DCMAKE_IGNORE_PATH="$BREW_PATH/lib" \
-DCMAKE_CXX_FLAGS="-D__MAC_OS_X_VERSION_MIN_REQUIRED=130000" \
-G Ninja
"$BREW_PATH/bin/ninja"; build_status=$?;
+15 -8
View File
@@ -2,19 +2,22 @@
cd build || exit 1
CPU_ARCH="${1:-x86_64}"
if [ "$DEPLOY_APPIMAGE" = "true" ]; then
DESTDIR=AppDir ninja install
curl -fsSLo /usr/bin/linuxdeploy https://github.com/linuxdeploy/linuxdeploy/releases/download/continuous/linuxdeploy-x86_64.AppImage
curl -fsSLo /usr/bin/linuxdeploy "https://github.com/linuxdeploy/linuxdeploy/releases/download/continuous/linuxdeploy-$CPU_ARCH.AppImage"
chmod +x /usr/bin/linuxdeploy
curl -fsSLo /usr/bin/linuxdeploy-plugin-qt https://github.com/linuxdeploy/linuxdeploy-plugin-qt/releases/download/continuous/linuxdeploy-plugin-qt-x86_64.AppImage
curl -fsSLo /usr/bin/linuxdeploy-plugin-qt "https://github.com/linuxdeploy/linuxdeploy-plugin-qt/releases/download/continuous/linuxdeploy-plugin-qt-$CPU_ARCH.AppImage"
chmod +x /usr/bin/linuxdeploy-plugin-qt
curl -fsSLo linuxdeploy-plugin-checkrt.sh https://github.com/linuxdeploy/linuxdeploy-plugin-checkrt/releases/download/continuous/linuxdeploy-plugin-checkrt-x86_64.sh
curl -fsSLo linuxdeploy-plugin-checkrt.sh https://github.com/darealshinji/linuxdeploy-plugin-checkrt/releases/download/continuous/linuxdeploy-plugin-checkrt.sh
chmod +x ./linuxdeploy-plugin-checkrt.sh
export EXTRA_PLATFORM_PLUGINS="libqwayland-egl.so;libqwayland-generic.so"
export EXTRA_QT_PLUGINS="svg;wayland-decoration-client;wayland-graphics-integration-client;wayland-shell-integration"
APPIMAGE_EXTRACT_AND_RUN=1 linuxdeploy --appdir AppDir --plugin qt
export EXTRA_QT_PLUGINS="svg;wayland-decoration-client;wayland-graphics-integration-client;wayland-shell-integration;waylandcompositor"
APPIMAGE_EXTRACT_AND_RUN=1 linuxdeploy --appdir AppDir --plugin qt --plugin checkrt
# Remove libwayland-client because it has platform-dependent exports and breaks other OSes
rm -f ./AppDir/usr/lib/libwayland-client.so*
@@ -25,15 +28,19 @@ if [ "$DEPLOY_APPIMAGE" = "true" ]; then
# Remove git directory containing local commit history file
rm -rf ./AppDir/usr/share/rpcs3/git
./linuxdeploy-plugin-checkrt.sh --appdir AppDir
linuxdeploy --appimage-extract
./squashfs-root/plugins/linuxdeploy-plugin-appimage/usr/bin/appimagetool AppDir -g
APPIMAGE_SUFFIX="linux_${CPU_ARCH}"
if [ "$CPU_ARCH" = "x86_64" ]; then
# Preserve back compat. Previous versions never included the full arch.
APPIMAGE_SUFFIX="linux64"
fi
COMM_TAG=$(awk '/version{.*}/ { printf("%d.%d.%d", $5, $6, $7) }' ../rpcs3/rpcs3_version.cpp)
COMM_COUNT="$(git rev-list --count HEAD)"
COMM_HASH="$(git rev-parse --short=8 HEAD)"
RPCS3_APPIMAGE="rpcs3-v${COMM_TAG}-${COMM_COUNT}-${COMM_HASH}_linux64.AppImage"
RPCS3_APPIMAGE="rpcs3-v${COMM_TAG}-${COMM_COUNT}-${COMM_HASH}_${APPIMAGE_SUFFIX}.AppImage"
mv ./RPCS3*.AppImage "$RPCS3_APPIMAGE"
+76
View File
@@ -0,0 +1,76 @@
#!/bin/sh -ex
# shellcheck disable=SC2086
cd build || exit 1
# Gather explicit version number and number of commits
COMM_TAG=$(awk '/version{.*}/ { printf("%d.%d.%d", $5, $6, $7) }' ../rpcs3/rpcs3_version.cpp)
COMM_COUNT=$(git rev-list --count HEAD)
COMM_HASH=$(git rev-parse --short=8 HEAD)
AVVER="${COMM_TAG}-${COMM_COUNT}"
# AVVER is used for GitHub releases, it is the version number.
echo "AVVER=$AVVER" >> ../.ci/ci-vars.env
cd bin
mkdir "rpcs3.app/Contents/lib/" || true
cp "$(realpath /opt/homebrew1/opt/llvm@$LLVM_COMPILER_VER/lib/c++/libc++abi.1.0.dylib)" "rpcs3.app/Contents/Frameworks/libc++abi.1.dylib"
cp "$(realpath /opt/homebrew1/lib/libsharpyuv.0.dylib)" "rpcs3.app/Contents/lib/libsharpyuv.0.dylib"
cp "$(realpath /opt/homebrew1/lib/libintl.8.dylib)" "rpcs3.app/Contents/lib/libintl.8.dylib"
rm -rf "rpcs3.app/Contents/Frameworks/QtPdf.framework" \
"rpcs3.app/Contents/Frameworks/QtQml.framework" \
"rpcs3.app/Contents/Frameworks/QtQmlModels.framework" \
"rpcs3.app/Contents/Frameworks/QtQuick.framework" \
"rpcs3.app/Contents/Frameworks/QtVirtualKeyboard.framework" \
"rpcs3.app/Contents/Plugins/platforminputcontexts" \
"rpcs3.app/Contents/Plugins/virtualkeyboard" \
"rpcs3.app/Contents/Resources/git"
../../.ci/optimize-mac.sh rpcs3.app
# Hack
install_name_tool \
-delete_rpath /opt/homebrew1/lib \
-delete_rpath /opt/homebrew/lib \
-delete_rpath /opt/homebrew1/opt/llvm@$LLVM_COMPILER_VER/lib \
-delete_rpath /usr/local/lib RPCS3.app/Contents/MacOS/rpcs3
#-delete_rpath /opt/homebrew1/Cellar/sdl2/2.30.7/lib
# Need to do this rename hack due to case insensitive filesystem
mv rpcs3.app RPCS3_.app
mv RPCS3_.app RPCS3.app
# NOTE: "--deep" is deprecated
codesign --deep -fs - RPCS3.app
echo "[InternetShortcut]" > Quickstart.url
echo "URL=https://rpcs3.net/quickstart" >> Quickstart.url
echo "IconIndex=0" >> Quickstart.url
#DMG_FILEPATH="$BUILD_ARTIFACTSTAGINGDIRECTORY/rpcs3-v${COMM_TAG}-${COMM_COUNT}-${COMM_HASH}_macos_arm64.dmg"
#"$BREW_X64_PATH/bin/create-dmg" --volname RPCS3 \
#--window-size 800 400 \
#--icon-size 100 \
#--icon rpcs3.app 200 190 \
#--add-file Quickstart.url Quickstart.url 400 20 \
#--hide-extension rpcs3.app \
#--hide-extension Quickstart.url \
#--app-drop-link 600 185 \
#--skip-jenkins \
#--format ULMO \
#"$DMG_FILEPATH" \
#RPCS3.app
#FILESIZE=$(stat -f %z "$DMG_FILEPATH")
#SHA256SUM=$(shasum -a 256 "$DMG_FILEPATH" | awk '{ print $1 }')
ARCHIVE_FILEPATH="$BUILD_ARTIFACTSTAGINGDIRECTORY/rpcs3-v${COMM_TAG}-${COMM_COUNT}-${COMM_HASH}_macos_arm64.7z"
"$BREW_X64_PATH/bin/7z" a -mx9 "$ARCHIVE_FILEPATH" RPCS3.app Quickstart.url
FILESIZE=$(stat -f %z "$ARCHIVE_FILEPATH")
SHA256SUM=$(shasum -a 256 "$ARCHIVE_FILEPATH" | awk '{ print $1 }')
cd ..
echo "${SHA256SUM};${FILESIZE}B" > "$RELEASE_MESSAGE"
cd bin
Executable → Regular
+13 -1
View File
@@ -1,5 +1,6 @@
#!/bin/sh -ex
# shellcheck disable=SC2086
cd build || exit 1
# Gather explicit version number and number of commits
@@ -15,7 +16,7 @@ echo "AVVER=$AVVER" >> ../.ci/ci-vars.env
cd bin
mkdir "rpcs3.app/Contents/lib/"
cp "/usr/local/opt/llvm@16/lib/c++/libc++abi.1.0.dylib" "rpcs3.app/Contents/lib/libc++abi.1.dylib"
cp "/usr/local/opt/llvm@$LLVM_COMPILER_VER/lib/c++/libc++abi.1.0.dylib" "rpcs3.app/Contents/lib/libc++abi.1.dylib"
cp "$(realpath /usr/local/lib/libsharpyuv.0.dylib)" "rpcs3.app/Contents/lib/libsharpyuv.0.dylib"
cp "$(realpath /usr/local/lib/libintl.8.dylib)" "rpcs3.app/Contents/lib/libintl.8.dylib"
@@ -28,10 +29,21 @@ rm -rf "rpcs3.app/Contents/Frameworks/QtPdf.framework" \
"rpcs3.app/Contents/Plugins/virtualkeyboard" \
"rpcs3.app/Contents/Resources/git"
../../.ci/optimize-mac.sh rpcs3.app
# Need to do this rename hack due to case insensitive filesystem
mv rpcs3.app RPCS3_.app
mv RPCS3_.app RPCS3.app
# Hack
install_name_tool \
-delete_rpath /usr/local/lib \
-delete_rpath /usr/local/opt/llvm@$LLVM_COMPILER_VER/lib RPCS3.app/Contents/MacOS/rpcs3
#-delete_rpath /usr/local/Cellar/sdl2/2.30.3/lib
# NOTE: "--deep" is deprecated
codesign --deep -fs - RPCS3.app
echo "[InternetShortcut]" > Quickstart.url
echo "URL=https://rpcs3.net/quickstart" >> Quickstart.url
echo "IconIndex=0" >> Quickstart.url
+21
View File
@@ -0,0 +1,21 @@
#!/bin/sh
file_path=$(find "$1/Contents/MacOS" -type f -print0 | head -n 1)
if [ -z "$file_path" ]; then
echo "No executable file found in $1/Contents/MacOS" >&2
exit 1
fi
target_architecture="$(lipo "$file_path" -archs)"
if [ -z "$target_architecture" ]; then
exit 1
fi
# shellcheck disable=SC3045
find "$1" -type f -print0 | while IFS= read -r -d '' file; do
echo Thinning "$file" -> "$target_architecture"
lipo "$file" -thin "$target_architecture" -output "$file" || true
done
+1 -1
View File
@@ -39,7 +39,7 @@ DEP_URLS=" \
# Pull all the submodules except llvm, since it is built separately and we just download that build
# Note: Tried to use git submodule status, but it takes over 20 seconds
# shellcheck disable=SC2046
git submodule -q update --init --depth=1 --jobs=8 $(awk '/path/ && !/FAudio/ && !/llvm/ && !/SPIRV/ { print $3 }' .gitmodules)
git submodule -q update --init --depth=1 --jobs=8 $(awk '/path/ && !/FAudio/ && !/llvm/ { print $3 }' .gitmodules)
# Git bash doesn't have rev, so here it is
rev()
+38 -37
View File
@@ -5,9 +5,9 @@ env:
SYSTEM_PULLREQUEST_PULLREQUESTID: $CIRRUS_PR
BUILD_SOURCEVERSION: $CIRRUS_CHANGE_IN_REPO
BUILD_SOURCEBRANCHNAME: $CIRRUS_BRANCH
RPCS3_TOKEN: ENCRYPTED[!a4c3850e29ab150692286a74bec29819d25971a7ec431b86de2a35f7ed90c5b2ab3c93469f9298e30924d843599110e9!]
RPCS3_TOKEN: ENCRYPTED[100ebb8e3552bf2021d0ef55dccda3e58d27be5b6cab0b0b92843ef490195d3c4edaefa087e4a3b425caa6392300b9b1]
QT_VER_MAIN: '6'
QT_VER: '6.6.3'
QT_VER: '6.7.3'
# windows_task:
# matrix:
@@ -21,7 +21,7 @@ env:
# COMPILER: msvc
# BUILD_ARTIFACTSTAGINGDIRECTORY: ${CIRRUS_WORKING_DIR}\artifacts\
# QT_VER_MSVC: 'msvc2019'
# QT_DATE: '202403191840'
# QT_DATE: '202409200836'
# QTDIR: C:\Qt\${QT_VER}\${QT_VER_MSVC}_64
# VULKAN_VER: '1.3.268.0'
# VULKAN_SDK_SHA: '8459ef49bd06b697115ddd3d97c9aec729e849cd775f5be70897718a9b3b9db5'
@@ -114,37 +114,38 @@ freebsd_task:
install_script: "sh -ex ./.ci/install-freebsd.sh"
script: "./.ci/build-freebsd.sh"
# macos_task:
# timeout_in: 12000m
# homebrew_cache:
# folder: /Users/admin/Library/Caches/Homebrew
# qt_cache:
# folder: /tmp/Qt
# ccache_cache:
# folder: /tmp/ccache_dir
# matrix:
# - name: Cirrus macOS
# macos_instance:
# image: ghcr.io/cirruslabs/macos-monterey-xcode:latest
# mac_script:
# - mkdir artifacts
# - chmod +x ".ci/build-mac.sh"
# - chmod +x ".ci/deploy-mac.sh"
# - ".ci/build-mac.sh"
# env:
# BUILD_ARTIFACTSTAGINGDIRECTORY: ${CIRRUS_WORKING_DIR}/artifacts
# ARTDIR: ${CIRRUS_WORKING_DIR}/artifacts/
# CCACHE_DIR: "/tmp/ccache_dir"
# CCACHE_MAXSIZE: 300M
# CI_HAS_ARTIFACTS: true
# UPLOAD_COMMIT_HASH: 51ae32f468089a8169aaf1567de355ff4a3e0842
# UPLOAD_REPO_FULL_NAME: "rpcs3/rpcs3-binaries-mac"
# RELEASE_MESSAGE: "../GitHubReleaseMessage.txt"
# artifacts:
# name: Artifact
# path: "artifacts/*"
# push_script: |
# if [ "$CIRRUS_REPO_OWNER" = "RPCS3" ] && [ -z "$CIRRUS_PR" ] && [ "$CIRRUS_BRANCH" = "master" ]; then
# source './.ci/export-cirrus-vars.sh'
# .ci/github-upload.sh
# fi;
linux_aarch64_task:
env:
BUILD_ARTIFACTSTAGINGDIRECTORY: ${CIRRUS_WORKING_DIR}/artifacts
ARTDIR: ${CIRRUS_WORKING_DIR}/artifacts/
CCACHE_DIR: "/tmp/ccache_dir"
CCACHE_MAXSIZE: 300M
CI_HAS_ARTIFACTS: true
UPLOAD_COMMIT_HASH: a1d35836e8d45bfc6f63c26f0a3e5d46ef622fe1
UPLOAD_REPO_FULL_NAME: "rpcs3/rpcs3-binaries-linux-arm64"
DEPLOY_APPIMAGE: true
APPDIR: "./appdir"
RELEASE_MESSAGE: "../GitHubReleaseMessage.txt"
COMPILER: clang
ccache_cache:
folder: "/tmp/ccache_dir"
matrix:
- name: Cirrus Linux AArch64 Clang
arm_container:
image: 'docker.io/rpcs3/rpcs3-ci-focal-aarch64:1.0'
cpu: 8
memory: 8G
clang_script:
- mkdir artifacts
- "sh -ex ./.ci/build-linux-aarch64.sh"
artifacts:
name: Artifact
path: "artifacts/*"
push_script: |
if [ "$CIRRUS_REPO_OWNER" = "RPCS3" ] && [ -z "$CIRRUS_PR" ] && [ "$CIRRUS_BRANCH" = "master" ]; then
COMM_TAG=$(awk '/version{.*}/ { printf("%d.%d.%d", $5, $6, $7) }' ./rpcs3/rpcs3_version.cpp)
COMM_COUNT=$(git rev-list --count HEAD)
COMM_HASH=$(git rev-parse --short=8 HEAD)
export AVVER="${COMM_TAG}-${COMM_COUNT}"
.ci/github-upload.sh
fi;
-8
View File
@@ -15,14 +15,6 @@
path = 3rdparty/glslang/glslang
url = ../../KhronosGroup/glslang.git
ignore = dirty
[submodule "3rdparty/SPIRV-Tools"]
path = 3rdparty/SPIRV/SPIRV-Tools
url = ../../KhronosGroup/SPIRV-Tools.git
ignore = dirty
[submodule "3rdparty/SPIRV-Headers"]
path = 3rdparty/SPIRV/SPIRV-Headers
url = ../../KhronosGroup/SPIRV-Headers.git
ignore = dirty
[submodule "3rdparty/zlib"]
path = 3rdparty/zlib/zlib
url = ../../madler/zlib
+26 -32
View File
@@ -4,6 +4,9 @@ include(CMakeDependentOption)
set(CMAKE_CXX_STANDARD 20)
# Defines the ARCHITECTURE variable
include("DetectArchitecture.cmake")
# Warnings are silenced for 3rdparty code
if(NOT MSVC)
add_compile_options("$<$<COMPILE_LANGUAGE:CXX,C>:-w>")
@@ -86,7 +89,6 @@ add_subdirectory(hidapi)
# Vulkan
add_subdirectory(glslang EXCLUDE_FROM_ALL)
#add_subdirectory(SPIRV EXCLUDE_FROM_ALL)
# yaml-cpp
@@ -247,8 +249,8 @@ if(USE_FAUDIO)
message(STATUS "RPCS3: Using builtin FAudio")
set(BUILD_SHARED_LIBS OFF CACHE BOOL "Build shared library")
add_subdirectory(FAudio EXCLUDE_FROM_ALL)
target_compile_definitions(FAudio INTERFACE -DHAVE_FAUDIO)
set(FAUDIO_TARGET FAudio)
target_compile_definitions(FAudio-static INTERFACE -DHAVE_FAUDIO)
set(FAUDIO_TARGET FAudio-static)
endif()
endif()
endif()
@@ -267,38 +269,30 @@ if(USE_SYSTEM_FFMPEG)
target_include_directories(3rdparty_ffmpeg INTERFACE ${FFMPEG_INCLUDE_DIR})
target_link_libraries(3rdparty_ffmpeg INTERFACE ${FFMPEG_LIBRARIES})
else()
if (NOT MSVC AND WIN32)
message(FATAL_ERROR "-- RPCS3: building ffmpeg submodule is currently not supported")
else()
message(STATUS "RPCS3: using builtin ffmpeg")
message(STATUS "RPCS3: using builtin ffmpeg")
add_subdirectory(ffmpeg EXCLUDE_FROM_ALL)
# ffmpeg-core libraries are extracted to CMAKE_BINARY_DIR
set(FFMPEG_LIB_DIR "${CMAKE_BINARY_DIR}/3rdparty/ffmpeg/lib")
if (WIN32)
set(FFMPEG_LIB_DIR "ffmpeg/lib/windows/x86_64")
target_link_libraries(3rdparty_ffmpeg INTERFACE "Bcrypt.lib")
elseif(CMAKE_SYSTEM_NAME STREQUAL "Linux")
set(FFMPEG_LIB_DIR "ffmpeg/lib/linux/ubuntu-20.04/x86_64")
elseif(APPLE)
set(FFMPEG_LIB_DIR "ffmpeg/lib/macos/x86_64")
else()
message(FATAL_ERROR "Prebuilt ffmpeg is not available on this platform! Try USE_SYSTEM_FFMPEG=ON.")
endif()
find_library(FFMPEG_LIB_AVFORMAT avformat PATHS ${FFMPEG_LIB_DIR} NO_DEFAULT_PATH)
find_library(FFMPEG_LIB_AVCODEC avcodec PATHS ${FFMPEG_LIB_DIR} NO_DEFAULT_PATH)
find_library(FFMPEG_LIB_AVUTIL avutil PATHS ${FFMPEG_LIB_DIR} NO_DEFAULT_PATH)
find_library(FFMPEG_LIB_SWSCALE swscale PATHS ${FFMPEG_LIB_DIR} NO_DEFAULT_PATH)
find_library(FFMPEG_LIB_SWRESAMPLE swresample PATHS ${FFMPEG_LIB_DIR} NO_DEFAULT_PATH)
target_link_libraries(3rdparty_ffmpeg
INTERFACE
${FFMPEG_LIB_AVFORMAT}
${FFMPEG_LIB_AVCODEC}
${FFMPEG_LIB_AVUTIL}
${FFMPEG_LIB_SWSCALE}
${FFMPEG_LIB_SWRESAMPLE}
)
if (WIN32)
target_link_libraries(3rdparty_ffmpeg INTERFACE "Bcrypt.lib")
endif()
find_library(FFMPEG_LIB_AVFORMAT avformat PATHS ${FFMPEG_LIB_DIR} NO_DEFAULT_PATH)
find_library(FFMPEG_LIB_AVCODEC avcodec PATHS ${FFMPEG_LIB_DIR} NO_DEFAULT_PATH)
find_library(FFMPEG_LIB_AVUTIL avutil PATHS ${FFMPEG_LIB_DIR} NO_DEFAULT_PATH)
find_library(FFMPEG_LIB_SWSCALE swscale PATHS ${FFMPEG_LIB_DIR} NO_DEFAULT_PATH)
find_library(FFMPEG_LIB_SWRESAMPLE swresample PATHS ${FFMPEG_LIB_DIR} NO_DEFAULT_PATH)
target_link_libraries(3rdparty_ffmpeg
INTERFACE
${FFMPEG_LIB_AVFORMAT}
${FFMPEG_LIB_AVCODEC}
${FFMPEG_LIB_AVUTIL}
${FFMPEG_LIB_SWSCALE}
${FFMPEG_LIB_SWRESAMPLE}
)
target_include_directories(3rdparty_ffmpeg INTERFACE "ffmpeg/include")
endif()
+63
View File
@@ -0,0 +1,63 @@
# From https://github.com/merryhime/dynarmic
include(CheckSymbolExists)
if (CMAKE_OSX_ARCHITECTURES)
set(DYNARMIC_MULTIARCH_BUILD 1)
set(ARCHITECTURE "${CMAKE_OSX_ARCHITECTURES}")
return()
endif()
function(detect_architecture symbol arch)
if (NOT DEFINED ARCHITECTURE)
set(CMAKE_REQUIRED_QUIET YES)
check_symbol_exists("${symbol}" "" DETECT_ARCHITECTURE_${arch})
unset(CMAKE_REQUIRED_QUIET)
if (DETECT_ARCHITECTURE_${arch})
set(ARCHITECTURE "${arch}" PARENT_SCOPE)
endif()
unset(DETECT_ARCHITECTURE_${arch} CACHE)
endif()
endfunction()
detect_architecture("__ARM64__" arm64)
detect_architecture("__aarch64__" arm64)
detect_architecture("_M_ARM64" arm64)
detect_architecture("__arm__" arm)
detect_architecture("__TARGET_ARCH_ARM" arm)
detect_architecture("_M_ARM" arm)
detect_architecture("__x86_64" x86_64)
detect_architecture("__x86_64__" x86_64)
detect_architecture("__amd64" x86_64)
detect_architecture("_M_X64" x86_64)
detect_architecture("__i386" x86)
detect_architecture("__i386__" x86)
detect_architecture("_M_IX86" x86)
detect_architecture("__ia64" ia64)
detect_architecture("__ia64__" ia64)
detect_architecture("_M_IA64" ia64)
detect_architecture("__mips" mips)
detect_architecture("__mips__" mips)
detect_architecture("_M_MRX000" mips)
detect_architecture("__ppc64__" ppc64)
detect_architecture("__powerpc64__" ppc64)
detect_architecture("__ppc__" ppc)
detect_architecture("__ppc" ppc)
detect_architecture("__powerpc__" ppc)
detect_architecture("_ARCH_COM" ppc)
detect_architecture("_ARCH_PWR" ppc)
detect_architecture("_ARCH_PPC" ppc)
detect_architecture("_M_MPPC" ppc)
detect_architecture("_M_PPC" ppc)
detect_architecture("__riscv" riscv)
detect_architecture("__EMSCRIPTEN__" wasm)
+1 -1
View File
@@ -4,7 +4,7 @@ include(ExternalProject)
ExternalProject_Add(moltenvk
GIT_REPOSITORY https://github.com/KhronosGroup/MoltenVK.git
GIT_TAG edbdcf0
GIT_TAG 81541f6
BUILD_IN_SOURCE 1
SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/MoltenVK
CONFIGURE_COMMAND "${CMAKE_CURRENT_SOURCE_DIR}/MoltenVK/fetchDependencies" --macos
+2 -2
View File
@@ -5,8 +5,8 @@ if(USE_SYSTEM_OPENAL)
target_include_directories(3rdparty_openal INTERFACE ${OPENAL_INCLUDE_DIR})
target_link_libraries(3rdparty_openal INTERFACE ${OPENAL_LIBRARY})
else()
option(ALSOFT_UTILS "Build utility programs" OFF)
option(ALSOFT_EXAMPLES "Build example programs" OFF)
option(ALSOFT_UTILS "Build utility programs" OFF)
option(ALSOFT_EXAMPLES "Build example programs" OFF)
add_subdirectory(openal-soft EXCLUDE_FROM_ALL)
add_library(3rdparty_openal INTERFACE)
target_link_libraries(3rdparty_openal INTERFACE OpenAL::OpenAL)
-2
View File
@@ -1,2 +0,0 @@
/build
/x64
-3
View File
@@ -1,3 +0,0 @@
set(SKIP_SPIRV_TOOLS_INSTALL ON CACHE BOOL "Skip spirv-tools install" FORCE)
set(SPIRV-Headers_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/SPIRV-Headers" CACHE STRING "SPIRV-Headers path" FORCE)
add_subdirectory(SPIRV-Tools)
-71
View File
@@ -1,71 +0,0 @@
<?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">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{4CBD3DDD-5555-49A4-A44D-DD3D8CB516A1}</ProjectGuid>
<Keyword>MakeFileProj</Keyword>
</PropertyGroup>
<Import Project="..\..\buildfiles\msvc\common_default.props" />
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<Import Project="..\..\buildfiles\msvc\common_default_macros.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Makefile</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Makefile</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros">
<CmakeGenerator>"Visual Studio $(VisualStudioVersion.Substring(0,2))"</CmakeGenerator>
<CmakeReleaseCLI>call vsdevcmd.bat -arch=amd64
cmake -G $(CmakeGenerator) -A x64 -DCMAKE_BUILD_TYPE="Release" -DSPIRV_WERROR=OFF -DSPIRV-Headers_SOURCE_DIR="$([System.IO.Path]::GetFullPath('$(MSBuildThisFileDirectory)/SPIRV-Headers').Replace('\', '/'))" SPIRV-Tools -B build</CmakeReleaseCLI>
<CmakeDebugCLI>call vsdevcmd.bat -arch=amd64
cmake -G $(CmakeGenerator) -A x64 -DCMAKE_BUILD_TYPE="Debug" -DSPIRV_WERROR=OFF -DSPIRV-Headers_SOURCE_DIR="$([System.IO.Path]::GetFullPath('$(MSBuildThisFileDirectory)/SPIRV-Headers').Replace('\', '/'))" -S SPIRV-Tools -B build</CmakeDebugCLI>
<PropsAbsPath>$([System.IO.Path]::GetFullPath('$(MSBuildThisFileDirectory)..\..\buildfiles\msvc\common_default.props'))</PropsAbsPath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<NMakeBuildCommandLine>$(CmakeReleaseCLI)
msbuild.exe build\ALL_BUILD.vcxproj /t:build /p:Configuration=Release /p:ForceImportBeforeCppTargets="$(PropsAbsPath)" /m</NMakeBuildCommandLine>
<NMakeReBuildCommandLine>$(CmakeReleaseCLI)
msbuild.exe build\ALL_BUILD.vcxproj /t:rebuild /p:Configuration=Release /p:ForceImportBeforeCppTargets="$(PropsAbsPath)" /m</NMakeReBuildCommandLine>
<NMakeCleanCommandLine>$(CmakeReleaseCLI)
msbuild.exe build\ALL_BUILD.vcxproj /t:clean /p:Configuration=Release /p:ForceImportBeforeCppTargets="$(PropsAbsPath)" /m</NMakeCleanCommandLine>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<NMakeBuildCommandLine>$(CmakeDebugCLI)
msbuild.exe build\ALL_BUILD.vcxproj /t:build /p:Configuration=Debug /p:ForceImportBeforeCppTargets="$(PropsAbsPath)" /m
</NMakeBuildCommandLine>
<NMakeReBuildCommandLine>$(CmakeDebugCLI)
msbuild.exe build\ALL_BUILD.vcxproj /t:rebuild /p:Configuration=Debug /p:ForceImportBeforeCppTargets="$(PropsAbsPath)" /m
</NMakeReBuildCommandLine>
<NMakeCleanCommandLine>$(CmakeDebugCLI)
msbuild.exe build\ALL_BUILD.vcxproj /t:clean /p:Configuration=Debug /p:ForceImportBeforeCppTargets="$(PropsAbsPath)" /m
</NMakeCleanCommandLine>
</PropertyGroup>
<ItemDefinitionGroup>
</ItemDefinitionGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
-2
View File
@@ -1,2 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" />
+11
View File
@@ -101,6 +101,17 @@
<ItemGroup>
<ClInclude Include="hidapi\hidapi\hidapi.h" />
</ItemGroup>
<ItemGroup>
<None Include="hidapi\linux\hid.c" />
<None Include="hidapi\mac\hid.c" />
<None Include="hidapi\windows\hidapi_descriptor_reconstruct.c" />
<None Include="hidapi\mac\hidapi_darwin.h" />
<None Include="hidapi\windows\hidapi_descriptor_reconstruct.h" />
<None Include="hidapi\windows\hidapi_hidclass.h" />
<None Include="hidapi\windows\hidapi_hidpi.h" />
<None Include="hidapi\windows\hidapi_hidsdi.h" />
<None Include="hidapi\windows\hidapi_winapi.h" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
+29
View File
@@ -24,4 +24,33 @@
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<None Include="hidapi\windows\hidapi_descriptor_reconstruct.c">
<Filter>Source Files</Filter>
</None>
<None Include="hidapi\linux\hid.c">
<Filter>Source Files</Filter>
</None>
<None Include="hidapi\mac\hid.c">
<Filter>Source Files</Filter>
</None>
<None Include="hidapi\windows\hidapi_descriptor_reconstruct.h">
<Filter>Header Files</Filter>
</None>
<None Include="hidapi\windows\hidapi_hidclass.h">
<Filter>Header Files</Filter>
</None>
<None Include="hidapi\windows\hidapi_hidpi.h">
<Filter>Header Files</Filter>
</None>
<None Include="hidapi\windows\hidapi_hidsdi.h">
<Filter>Header Files</Filter>
</None>
<None Include="hidapi\windows\hidapi_winapi.h">
<Filter>Header Files</Filter>
</None>
<None Include="hidapi\mac\hidapi_darwin.h">
<Filter>Header Files</Filter>
</None>
</ItemGroup>
</Project>
+14 -3
View File
@@ -17,12 +17,17 @@ if(WITH_LLVM)
option(LLVM_CCACHE_BUILD OFF)
set(LLVM_ENABLE_WARNINGS OFF CACHE BOOL "Enable compiler warnings.")
if(WIN32)
# For Windows x86 (not Windows AArch64).
# Check on MSVC is needed due to COMPILER_X86, COMPILER_ARM etc. are not set/supported by the MSVC compiler, if used.
# Furthermore, the MSVC compiler is not available/supported on Windows AArch64
if(WIN32 AND (COMPILER_X86 OR MSVC))
set(LLVM_USE_INTEL_JITEVENTS ON)
endif()
if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
set(LLVM_USE_INTEL_JITEVENTS ON)
if(COMPILER_X86)
set(LLVM_USE_INTEL_JITEVENTS ON)
endif()
set(LLVM_USE_PERF ON)
endif()
@@ -68,12 +73,18 @@ if(WITH_LLVM)
set(LLVM_TARGETS_TO_BUILD "X86" CACHE STRING "Semicolon-separated list of targets to build, or \"all\".")
endif()
endif()
if((WIN32 AND BUILD_LLVM) OR CMAKE_SYSTEM_NAME STREQUAL "Linux")
# For Windows x86 (not Windows AArch64) only when BUILD_LLVM is enabled and
# for Linux x86 (not Linux AArch64) even if BUILD_LLVM is disabled (precompiled llvm used)
if(LLVM_USE_INTEL_JITEVENTS OR (CMAKE_SYSTEM_NAME STREQUAL "Linux" AND COMPILER_X86))
list (APPEND LLVM_ADDITIONAL_LIBS IntelJITEvents)
endif()
# For Linux even if BUILD_LLVM is disabled (precompiled llvm used)
if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
list (APPEND LLVM_ADDITIONAL_LIBS PerfJITEvents)
endif()
llvm_map_components_to_libnames(LLVM_LIBS
${LLVM_TARGETS_TO_BUILD}
${LLVM_ADDITIONAL_LIBS}
+2 -2
View File
@@ -200,7 +200,7 @@ namespace pine
if (!SafetyChecks(buf_cnt, 4, ret_cnt, 1, buf_size))
return error();
const u32 a = FromArray<u32>(&buf[buf_cnt], 0);
if (!Impl::template check_addr(a))
if (!Impl::template check_addr<1>(a))
return error();
const u8 res = Impl::read8(a);
ToArray(ret_buffer, res, ret_cnt);
@@ -252,7 +252,7 @@ namespace pine
if (!SafetyChecks(buf_cnt, 1 + 4, ret_cnt, 0, buf_size))
return error();
const u32 a = FromArray<u32>(&buf[buf_cnt], 0);
if (!Impl::template check_addr(a, vm::page_writable))
if (!Impl::template check_addr<1>(a, vm::page_writable))
return error();
Impl::write8(a, FromArray<u8>(&buf[buf_cnt], 4));
buf_cnt += 5;
+5 -1
View File
@@ -109,12 +109,13 @@
<OutDir>$(SolutionDir)lib\$(Configuration)-$(Platform)\</OutDir>
<IntDir>$(SolutionDir)tmp\$(ProjectName)-$(Configuration)-$(Platform)\</IntDir>
<InstructionSet>NotSet</InstructionSet>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
</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 Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
@@ -152,10 +153,13 @@
</PrecompiledHeader>
<WarningLevel>Level4</WarningLevel>
<Optimization>Disabled</Optimization>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
<AdditionalOptions>/DZSTD_MULTITHREAD %(AdditionalOptions)</AdditionalOptions>
<PreprocessorDefinitions>ZSTD_MULTITHREAD=1;ZSTD_LEGACY_SUPPORT=5;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<TreatWarningAsError>true</TreatWarningAsError>
<EnablePREfast>false</EnablePREfast>
<EnableEnhancedInstructionSet>$(InstructionSet)</EnableEnhancedInstructionSet>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
+85 -29
View File
@@ -7,25 +7,40 @@ Other instructions may be found [here](https://wiki.rpcs3.net/index.php?title=Bu
### Windows 10 or later
* [CMake 3.28.0+](https://www.cmake.org/download/) (add to PATH)
* [Python 3.6+](https://www.python.org/downloads/) (add to PATH)
* [Qt 6.6.3](https://www.qt.io/download-qt-installer)
* [Visual Studio 2022](https://visualstudio.microsoft.com/thank-you-downloading-visual-studio/?sku=Community) (or at least Visual Studio 2019 16.11.xx+ as C++20 is not included in previous versions)
* [Vulkan SDK 1.3.268.0](https://vulkan.lunarg.com/sdk/home) (See "Install the SDK" [here](https://vulkan.lunarg.com/doc/sdk/latest/windows/getting_started.html)) for now future SDKs don't work. You need precisely 1.3.268.0.
The following tools are required to build RPCS3 on Windows 10 or later:
- [Visual Studio 2022](https://visualstudio.microsoft.com/thank-you-downloading-visual-studio/?sku=Community) (or at least Visual Studio 2019 16.11.xx+ as C++20 is not included in previous versions)
- **Optional** - [CMake 3.28.0+](https://www.cmake.org/download/) (add to PATH)
**Either add the** `QTDIR` **environment variable, e.g.** `<QtInstallFolder>\6.6.3\msvc2019_64\` **, or use the [Visual Studio Qt Plugin](https://marketplace.visualstudio.com/items?itemName=TheQtCompany.QtVisualStudioTools2019)**
**NOTES:**
- **Visual Studio 2022** integrates **CMake 3.29+** and it also supports both the `sln` solution (`.sln`, `.vcxproj`) and `CMake` solution (`CMakeLists.txt`, `CMakePresets.json`).
See sections [Building with Visual Studio sln solution](#building-with-visual-studio-sln-solution) and [Building with Visual Studio CMake solution](#building-with-visual-studio-cmake-solution)
on how to build the project with **Visual Studio**.
- Install and use this standalone **CMake** tool just in case of your preference. See section [Building with standalone CMake tool](#building-with-standalone-cmake-tool) on how to build the project
with standalone **CMake** tool.
**NOTE: If you have issues with the Qt plugin, you may want to uninstall the Qt Plugin and install the [Legacy Qt Plugin](https://marketplace.visualstudio.com/items?itemName=TheQtCompany.LEGACYQtVisualStudioTools2019) instead.**
- [Python 3.6+](https://www.python.org/downloads/) (add to PATH)
- [Qt 6.7.3](https://www.qt.io/download-qt-installer) In case you can't download from the official installer, you can use [Another Qt installer](https://github.com/miurahr/aqtinstall) (In that case you will need to manually add the "qtmultimedia" module when installing Qt)
- [Vulkan SDK 1.3.268.0](https://vulkan.lunarg.com/sdk/home) (see "Install the SDK" [here](https://vulkan.lunarg.com/doc/sdk/latest/windows/getting_started.html)) for now future SDKs don't work. You need precisely 1.3.268.0.
The `sln` solution available only on **Visual Studio** is the preferred building solution. It easily allows to build the **RPCS3** application in `Release` and `Debug` mode.
In order to build **RPCS3** with the `sln` solution (with **Visual Studio**), **Qt** libs need to be detected. To detect the libs:
- add and set the `QTDIR` environment variable, e.g. `<QtInstallFolder>\6.7.3\msvc2019_64\`
- or use the [Visual Studio Qt Plugin](https://marketplace.visualstudio.com/items?itemName=TheQtCompany.QtVisualStudioTools2019)
**NOTE:** If you have issues with the **Visual Studio Qt Plugin**, you may want to uninstall it and install the [Legacy Qt Plugin](https://marketplace.visualstudio.com/items?itemName=TheQtCompany.LEGACYQtVisualStudioTools2019) instead.
In order to build **RPCS3** with the `CMake` solution (with both **Visual Studio** and standalone **CMake** tool):
- add and set the `CMAKE_PREFIX_PATH` environment variable to the **Qt** libs path, e.g. `<QtInstallFolder>\6.7.3\msvc2019_64\`
### Linux
These are the essentials tools to build RPCS3 on Linux. Some of them can be installed through your favorite package manager.
* Clang 17+ or GCC 13+
* [CMake 3.28.0+](https://www.cmake.org/download/)
* [Qt 6.6.3](https://www.qt.io/download-qt-installer)
* [Vulkan SDK 1.3.268.0](https://vulkan.lunarg.com/sdk/home) (See "Install the SDK" [here](https://vulkan.lunarg.com/doc/sdk/latest/linux/getting_started.html)) for now future SDKs don't work. You need precisely 1.3.268.0.
* [SDL2](https://github.com/libsdl-org/SDL/releases) (for the FAudio backend)
These are the essentials tools to build RPCS3 on Linux. Some of them can be installed through your favorite package manager:
- Clang 17+ or GCC 13+
- [CMake 3.28.0+](https://www.cmake.org/download/)
- [Qt 6.7.3](https://www.qt.io/download-qt-installer)
- [Vulkan SDK 1.3.268.0](https://vulkan.lunarg.com/sdk/home) (See "Install the SDK" [here](https://vulkan.lunarg.com/doc/sdk/latest/linux/getting_started.html)) for now future SDKs don't work. You need precisely 1.3.268.0.
- [SDL2](https://github.com/libsdl-org/SDL/releases) (for the FAudio backend)
**If you have an NVIDIA GPU, you may need to install the libglvnd package.**
@@ -38,6 +53,7 @@ These are the essentials tools to build RPCS3 on Linux. Some of them can be inst
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
Ubuntu usually does not have a new enough Qt package to suit rpcs3's needs. There is currently no PPA available to work around this.
@@ -65,6 +81,7 @@ sudo apt install vulkan-sdk
```
##### CMake
```
. /etc/os-release
wget -O - https://apt.kitware.com/keys/kitware-archive-latest.asc 2>/dev/null | sudo apt-key add -
@@ -95,27 +112,64 @@ git submodule update --init
### Windows
#### Configuring the Qt plugin (if used)
#### Building with Visual Studio sln solution
1) Go to `Extensions->Qt VS Tools->Qt Versions`.
2) Add the path to your Qt installation with compiler e.g. `<QtInstallFolder>\6.6.3\msvc2019_64`, version will fill in automatically.
3) Go to `Extensions->Qt VS Tools->Options->Legacy Project Format`. (Only available in the legacy Qt plugin)
4) Set `Build: Run pre-build setup` to `true`. (Only available in the legacy Qt plugin)
Start **Visual Studio**, click on `Open a project or solution` and select the `rpcs3.sln` file inside the RPCS3's root folder
#### Building the projects
##### Configuring the Qt Plugin (if used)
Open `rpcs3.sln`. The recommended build configuration is `Release`. (On older revisions: `Release - LLVM`)
1) go to `Extensions->Qt VS Tools->Qt Versions`
2) add the path to your Qt installation with compiler e.g. `<QtInstallFolder>\6.7.3\msvc2019_64`, version will fill in automatically
3) go to `Extensions->Qt VS Tools->Options->Legacy Project Format`. (Only available in the **Legacy Qt Plugin**)
4) set `Build: Run pre-build setup` to `true`. (Only available in the **Legacy Qt Plugin**)
You may want to download the precompiled [LLVM libs](https://github.com/RPCS3/llvm-mirror/releases/download/custom-build-win-16.0.1/llvmlibs_mt.7z) and extract them to `3rdparty\llvm\`, as well as download and extract the [additional libs](https://github.com/RPCS3/glslang/releases/latest/download/glslanglibs_mt.7z) to `lib\%CONFIGURATION%-x64\` to speed up compilation time (unoptimised/debug libs are currently not available precompiled).
##### Building the projects
If you're not using the precompiled libs, build the following projects in *__BUILD_BEFORE* folder by right-clicking on a project > *Build*.:
* glslang
* **Either** llvm_build **or** llvm_build_clang_cl
* spirv
**NOTE:** The recommended build configuration is `Release`. (On older revisions: `Release - LLVM`)
Afterwards:
You may want to download the precompiled [LLVM libs](https://github.com/RPCS3/llvm-mirror/releases/download/custom-build-win-16.0.1/llvmlibs_mt.7z) and extract them to `3rdparty\llvm\`,
as well as download and extract the [additional libs](https://github.com/RPCS3/glslang/releases/latest/download/glslanglibs_mt.7z) to `lib\%CONFIGURATION%-x64\` to speed up compilation
time (unoptimised/debug libs are currently not available precompiled).
`Build > Build Solution`
If you're not using the precompiled libs, those dependency libs need to be compiled first. From the `Solution Explorer` panel:
1) expand `__BUILD_BEFORE`
2) from the `Solution Configurations` drop-down menu, select `Release` (select `Debug` if you want to build in `Debug` mode)
3) one after another, right-click on the following projects and then click on `Build` to build the selected lib:
- `glslang`
- either `llvm_build`
- or `llvm_build_clang_cl` (if you installed **clang** on VS)
In order to build the **RPCS3** application:
1) from the `Solution Configurations` drop-down menu, select `Release` (select `Debug` if you want to build in `Debug` mode)
**NOTE:** In case you previously compiled the dependency libs under `__BUILD_BEFORE`, you have also to select the same build configuration (e.g. `Release`, if you compiled the dependency libs in `Release` mode)
2) click on `Build` menu and then on `Build Solution`
3) once the build is completed, the **RPCS3** application will be available under the `<rpcs3_root>\bin` folder
#### Building with Visual Studio CMake solution
Start **Visual Studio**, click on `Open a local folder` and select the RPCS3's root folder
Once the project is open on VS, from the `Solution Explorer` panel:
1) right-click on `rpcs3` and then click on `Switch to CMake Targets View`
2) from the `Configuration` drop-down menu, select `msvc-release` (select `msvc-debug` if you want to build in `Debug` mode)
3) right-click on `CMakeLists.txt Project` and then click on `Configure Cache`
4) once the cache is created, the `rpcs3 project` will be available
5) right-click on `rpcs3 Project` and then click on `Build All`, or click on `Build` menu and then on `Build All`
6) once the build is completed, the **RPCS3** application will be available under the `<rpcs3_root>\build-msvc\bin` folder
#### Building with standalone CMake tool
In case you preferred to install and use the standalone **CMake** tool:
1) move on the RPCS3's root folder
2) execute the following commands to create the cache and to build the application (for the build, use `--preset msvc-debug` if you want to build in `Debug` mode), respectively:
```
cmake --preset msvc
cmake --build --preset msvc-release
```
3) once the build is completed, the **RPCS3** application will be available under the `<rpcs3_root>\build-msvc\bin` folder
### Linux
@@ -123,7 +177,9 @@ While still in the project root:
1) `cd .. && mkdir --parents rpcs3_build && cd rpcs3_build`
2) `cmake ../rpcs3/ && make` or `CXX=g++-13 CC=gcc-13 cmake ../rpcs3/ && make` to force these compilers
3) Run RPCS3 with `./bin/rpcs3`
3) run RPCS3 with `./bin/rpcs3`
If compiling for ARM, pass the flag `-DUSE_NATIVE_INSTRUCTIONS=OFF` to the cmake command. This resolves some Neon errors when compiling our SIMD headers.
When using GDB, configure it to ignore SIGSEGV signal (`handle SIGSEGV nostop noprint`).
If desired, use the various build options in [CMakeLists](https://github.com/RPCS3/rpcs3/blob/master/CMakeLists.txt).
+1 -1
View File
@@ -25,7 +25,7 @@ option(USE_SYSTEM_ZLIB "Prefer system ZLIB instead of the builtin one" ON)
option(USE_VULKAN "Vulkan render backend" ON)
option(USE_PRECOMPILED_HEADERS "Use precompiled headers" OFF)
option(USE_SDL "Enables SDL input handler" OFF)
option(USE_SYSTEM_SDL "Prefer system SDL instead of the builtin one" OFF)
option(USE_SYSTEM_SDL "Prefer system SDL instead of the builtin one" ON)
option(USE_SYSTEM_FFMPEG "Prefer system ffmpeg instead of the prebuild one" OFF)
option(USE_SYSTEM_OPENAL "Prefer system OpenAL instead of the prebuild one" ON)
option(USE_SYSTEM_CURL "Prefer system Curl instead of the prebuild one" ON)
+22 -7
View File
@@ -7,12 +7,12 @@
"binaryDir": "build-gcc",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Debug",
"USE_NATIVE_INSTRUCTIONS": "ON",
"USE_PRECOMPILED_HEADERS": "ON",
"USE_FAUDIO": "OFF",
"USE_SYSTEM_CURL": "OFF",
"USE_SYSTEM_ZLIB": "OFF",
"USE_SYSTEM_LIBPNG": "OFF",
"USE_NATIVE_INSTRUCTIONS": "ON",
"USE_PRECOMPILED_HEADERS": "ON",
"BUILD_LLVM": "OFF",
"STATIC_LINK_LLVM": "ON"
}
@@ -23,13 +23,13 @@
"binaryDir": "build-clang64",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Debug",
"USE_NATIVE_INSTRUCTIONS": "ON",
"USE_PRECOMPILED_HEADERS": "ON",
"USE_FAUDIO": "OFF",
"USE_SYSTEM_CURL": "OFF",
"USE_SYSTEM_ZLIB": "OFF",
"USE_SYSTEM_LIBPNG": "OFF",
"LLVM_ENABLE_LIBCXX": "ON",
"USE_NATIVE_INSTRUCTIONS": "ON",
"USE_PRECOMPILED_HEADERS": "ON",
"BUILD_LLVM": "OFF",
"STATIC_LINK_LLVM": "ON"
},
@@ -48,11 +48,14 @@
"strategy": "external"
},
"cacheVariables": {
"CMAKE_CONFIGURATION_TYPES": "Debug;Release",
"CMAKE_INSTALL_PREFIX": "${sourceDir}/out/install/${presetName}",
"USE_FAUDIO": "OFF",
"USE_PRECOMPILED_HEADERS": "ON",
"USE_SYSTEM_ZLIB": "OFF",
"USE_NATIVE_INSTRUCTIONS": "ON",
"USE_PRECOMPILED_HEADERS": "ON",
"USE_FAUDIO": "OFF",
"USE_SYSTEM_CURL": "OFF",
"USE_SYSTEM_ZLIB": "OFF",
"USE_SYSTEM_OPENAL": "OFF",
"BUILD_LLVM": "ON",
"STATIC_LINK_LLVM": "ON"
},
@@ -64,5 +67,17 @@
}
}
}
],
"buildPresets": [
{
"name": "msvc-debug",
"configurePreset": "msvc",
"configuration": "Debug"
},
{
"name": "msvc-release",
"configurePreset": "msvc",
"configuration": "Release"
}
]
}
+85 -3
View File
@@ -2475,7 +2475,6 @@ bool fs::pending_file::commit(bool overwrite)
{
file.sync();
}
#endif
#ifdef _WIN32
@@ -2486,15 +2485,98 @@ bool fs::pending_file::commit(bool overwrite)
disp.DeleteFileW = false;
ensure(SetFileInformationByHandle(file.get_handle(), FileDispositionInfo, &disp, sizeof(disp)));
}
std::vector<std::wstring> hardlink_paths;
const auto ws1 = to_wchar(m_path);
const HANDLE file_handle = !overwrite ? INVALID_HANDLE_VALUE
: CreateFileW(ws1.get(), GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, nullptr, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, nullptr);
while (file_handle != INVALID_HANDLE_VALUE)
{
// Get file ID (used to check for hardlinks)
BY_HANDLE_FILE_INFORMATION file_info;
if (!GetFileInformationByHandle(file_handle, &file_info) || file_info.nNumberOfLinks == 1)
{
CloseHandle(file_handle);
break;
}
// Buffer for holding link name
std::wstring link_name_buffer(MAX_PATH, wchar_t{});
DWORD buffer_size{};
HANDLE find_handle = INVALID_HANDLE_VALUE;
while (true)
{
buffer_size = static_cast<DWORD>(link_name_buffer.size() - 1);
find_handle = FindFirstFileNameW(ws1.get(), 0, &buffer_size, link_name_buffer.data());
if (find_handle != INVALID_HANDLE_VALUE || GetLastError() != ERROR_MORE_DATA)
{
break;
}
link_name_buffer.resize(buffer_size + 1);
}
if (find_handle != INVALID_HANDLE_VALUE)
{
const std::wstring_view ws1_sv = ws1.get();
while (true)
{
if (link_name_buffer.c_str() != ws1_sv)
{
// Note: link_name_buffer is a buffer which may contain zeroes so truncate it
hardlink_paths.push_back(link_name_buffer.c_str());
}
buffer_size = static_cast<DWORD>(link_name_buffer.size() - 1);
if (!FindNextFileNameW(find_handle, &buffer_size, link_name_buffer.data()))
{
if (GetLastError() != ERROR_MORE_DATA)
{
break;
}
link_name_buffer.resize(buffer_size + 1);
}
}
}
// Clean up
FindClose(find_handle);
CloseHandle(file_handle);
break;
}
if (!hardlink_paths.empty())
{
// REPLACEFILE_WRITE_THROUGH is not supported
file.sync();
}
#endif
file.close();
#ifdef _WIN32
const auto ws1 = to_wchar(m_path);
const auto ws2 = to_wchar(m_dest);
if (MoveFileExW(ws1.get(), ws2.get(), overwrite ? MOVEFILE_REPLACE_EXISTING | MOVEFILE_WRITE_THROUGH : MOVEFILE_WRITE_THROUGH))
bool ok = false;
if (hardlink_paths.empty())
{
ok = MoveFileExW(ws1.get(), ws2.get(), overwrite ? MOVEFILE_REPLACE_EXISTING | MOVEFILE_WRITE_THROUGH : MOVEFILE_WRITE_THROUGH);
}
else
{
ok = ReplaceFileW(ws1.get(), ws2.get(), nullptr, 0, nullptr, nullptr);
}
if (ok)
{
// Disable the destructor
m_path.clear();
+19 -13
View File
@@ -110,18 +110,21 @@ static u64 make_null_function(const std::string& name)
c.align(AlignMode::kData, 16);
#else
// AArch64 implementation
Label jmp_address = c.newLabel();
Label data = c.newLabel();
// Force absolute jump to prevent out of bounds PC-rel jmp
c.ldr(args[0], arm::ptr(jmp_address));
c.br(args[0]);
c.align(AlignMode::kCode, 16);
Label jump_address = c.newLabel();
c.ldr(args[0], arm::ptr(data, 0));
c.ldr(a64::x14, arm::ptr(jump_address, 0));
c.br(a64::x14);
// Data frame
c.align(AlignMode::kCode, 16);
c.bind(jump_address);
c.embedUInt64(reinterpret_cast<u64>(&null));
c.align(AlignMode::kData, 16);
c.bind(data);
c.embed(name.c_str(), name.size());
c.embedUInt8(0U);
c.bind(jmp_address);
c.embedUInt64(reinterpret_cast<u64>(&null));
c.align(AlignMode::kData, 16);
#endif
});
@@ -731,11 +734,14 @@ llvm::StringRef fallback_cpu_detection()
const auto family = utils::get_cpu_family();
const auto model = utils::get_cpu_model();
jit_log.error("CPU wasn't identified by LLVM, brand = %s, family = 0x%x, model = 0x%x", brand, family, model);
if (brand.starts_with("AMD"))
{
switch (family)
{
case 0x10:
case 0x12: // Unimplemented in LLVM
return "amdfam10";
case 0x15:
// Bulldozer class, includes piledriver, excavator, steamroller, etc
@@ -746,17 +752,17 @@ llvm::StringRef fallback_cpu_detection()
return "znver1";
case 0x19:
// Models 0-Fh are zen3 as are 20h-60h. The rest we can assume are zen4
return ((model >= 0x20 && model <= 0x60) || model < 0x10)
? "znver3"
: "znver4";
return ((model >= 0x20 && model <= 0x60) || model < 0x10) ? "znver3" : "znver4";
case 0x1a:
// Only one generation in family 1a so far, zen5, which we do not support yet.
// Return zen4 as a workaround until the next LLVM upgrade.
return "znver4";
default:
return utils::has_avx512()
? "znver4"
: "znver3";
// Safest guesses
return utils::has_avx512() ? "znver4" :
utils::has_avx2() ? "znver1" :
utils::has_avx() ? "bdver1" :
"nehalem";
}
}
else if (brand.find("Intel") != std::string::npos)
+11 -3
View File
@@ -1840,10 +1840,18 @@ static LONG exception_filter(PEXCEPTION_POINTERS pExp) noexcept
}
}
fmt::append(msg, "Instruction address: %p.\n", pExp->ContextRecord->Rip);
#if defined(ARCH_X64)
const auto exec_addr = pExp->ContextRecord->Rip;
#elif defined(ARCH_ARM64)
const auto exec_addr = pExp->ContextRecord->Pc;
#else
#error "Unimplemented exception handling for this architecture"
#endif
fmt::append(msg, "Instruction address: %p.\n", exec_addr);
DWORD64 unwind_base;
if (const auto rtf = RtlLookupFunctionEntry(pExp->ContextRecord->Rip, &unwind_base, nullptr))
if (const auto rtf = RtlLookupFunctionEntry(exec_addr, &unwind_base, nullptr))
{
// Get function address
const DWORD64 func_addr = rtf->BeginAddress + unwind_base;
@@ -1860,7 +1868,7 @@ static LONG exception_filter(PEXCEPTION_POINTERS pExp) noexcept
{
const DWORD64 base = reinterpret_cast<DWORD64>(info.lpBaseOfDll);
if (pExp->ContextRecord->Rip >= base && pExp->ContextRecord->Rip < base + info.SizeOfImage)
if (exec_addr >= base && exec_addr < base + info.SizeOfImage)
{
std::string module_name;
for (DWORD size = 15; module_name.size() != size;)
+5 -1
View File
@@ -510,15 +510,19 @@ class named_thread final : public Context, result_storage<Context>, thread_base
#if defined(ARCH_X64)
static inline thread::native_entry trampoline = thread::make_trampoline(entry_point);
#else
#ifdef _WIN32
static uint trampoline(void* arg)
#else
static void* trampoline(void* arg)
#endif
{
if (const auto next = thread_base::finalize(entry_point(static_cast<thread_base*>(arg))))
{
return next(thread_ctrl::get_current());
}
return nullptr;
return {};
}
#endif
+9 -3
View File
@@ -41,12 +41,18 @@ namespace utils
RtlCaptureContext(&context);
STACKFRAME64 stack = {};
stack.AddrPC.Offset = context.Rip;
stack.AddrPC.Mode = AddrModeFlat;
stack.AddrStack.Offset = context.Rsp;
stack.AddrStack.Mode = AddrModeFlat;
stack.AddrFrame.Offset = context.Rbp;
stack.AddrFrame.Mode = AddrModeFlat;
#if defined(ARCH_X64)
stack.AddrPC.Offset = context.Rip;
stack.AddrStack.Offset = context.Rsp;
stack.AddrFrame.Offset = context.Rbp;
#elif defined(ARCH_ARM64)
stack.AddrPC.Offset = context.Pc;
stack.AddrStack.Offset = context.Sp;
stack.AddrFrame.Offset = context.Fp;
#endif
while (max_depth--)
{
+81 -18
View File
@@ -38,13 +38,13 @@ jobs:
displayName: ccache
- bash: |
docker pull --quiet rpcs3/rpcs3-ci-focal:1.7
docker pull --quiet rpcs3/rpcs3-ci-focal:1.9
docker run \
-v $(pwd):/rpcs3 \
--env-file .ci/docker.env \
-v $CCACHE_DIR:/root/.ccache \
-v $BUILD_ARTIFACTSTAGINGDIRECTORY:/root/artifacts \
rpcs3/rpcs3-ci-focal:1.7 \
rpcs3/rpcs3-ci-focal:1.9 \
/rpcs3/.ci/build-linux.sh
displayName: Docker setup and build
@@ -69,9 +69,9 @@ jobs:
variables:
COMPILER: msvc
QT_VER_MAIN: '6'
QT_VER: '6.6.3'
QT_VER: '6.7.3'
QT_VER_MSVC: 'msvc2019'
QT_DATE: '202403191840'
QT_DATE: '202409200836'
QTDIR: C:\Qt\$(QT_VER)\$(QT_VER_MSVC)_64
VULKAN_VER: '1.3.268.0'
VULKAN_SDK_SHA: '8459ef49bd06b697115ddd3d97c9aec729e849cd775f5be70897718a9b3b9db5'
@@ -122,7 +122,7 @@ jobs:
env:
RPCS3_TOKEN: $(RPCS3-Token)
- job: Mac_Build
- job: Mac_Build_x86_64
timeoutInMinutes: 180
variables:
CCACHE_DIR: "/tmp/ccache_dir"
@@ -132,11 +132,12 @@ jobs:
UPLOAD_REPO_FULL_NAME: "RPCS3/rpcs3-binaries-mac"
RELEASE_MESSAGE: "../GitHubReleaseMessage.txt"
ARTDIR: $(Build.ArtifactStagingDirectory)
QT_VER: '6.6.3'
QT_VER: '6.7.3'
QT_VER_MAIN: '6'
LLVM_COMPILER_VER: '16'
pool:
vmImage: "macOS-12"
vmImage: "macOS-13"
steps:
- task: Cache@2
@@ -149,29 +150,91 @@ jobs:
- task: Cache@2
inputs:
key: qt | "$(Agent.OS)" | "$(QT_VER)"
key: qt | "$(Agent.OS)" | "$(Agent.OSArchitecture)" | "$(QT_VER)"
path: /tmp/Qt
restoreKeys: |
qt | "$(Agent.OS)" | "$(QT_VER)"
qt | "$(Agent.OS)" | "$(Agent.OSArchitecture)" | "$(QT_VER)"
displayName: Qt cache
- task: Cache@2
inputs:
key: brew | "$(Agent.OS)"
path: /Users/runner/Library/Caches/Homebrew
restoreKeys: |
brew | "$(Agent.OS)"
displayName: Homebrew cache
# - task: Cache@2
# inputs:
# key: brew | "$(Agent.OS)"
# path: /Users/runner/Library/Caches/Homebrew
# restoreKeys: |
# brew | "$(Agent.OS)"
# displayName: Homebrew cache
- bash: |
chmod +x ".ci/build-mac.sh"
chmod +x ".ci/deploy-mac.sh"
chmod +x ".ci/optimize-mac.sh"
".ci/build-mac.sh"
displayName: Build MacOS
displayName: Build macOS (x86_64)
- publish: $(Build.ArtifactStagingDirectory)
condition: succeeded()
artifact: RPCS3 for Mac
artifact: RPCS3 for Mac (Intel)
- bash: |
source './.ci/export-cirrus-vars.sh'
.ci/github-upload.sh
condition: and(ne(variables['Build.Reason'], 'PullRequest'), eq(variables['Build.Repository.Name'], 'RPCS3/rpcs3'), eq(variables['Build.SourceBranch'], 'refs/heads/master'))
displayName: Push build to GitHub
env:
RPCS3_TOKEN: $(RPCS3-Token)
- job: Mac_Build_arm64
timeoutInMinutes: 180
variables:
CCACHE_DIR: "/tmp/ccache_dir"
CCACHE_MAXSIZE: 300M
CI_HAS_ARTIFACTS: true
UPLOAD_COMMIT_HASH: 8e21bdbc40711a3fccd18fbf17b742348b0f4281
UPLOAD_REPO_FULL_NAME: "RPCS3/rpcs3-binaries-mac-arm64"
RELEASE_MESSAGE: "../GitHubReleaseMessage.txt"
ARTDIR: $(Build.ArtifactStagingDirectory)
QT_VER: '6.7.3'
QT_VER_MAIN: '6'
LLVM_COMPILER_VER: '16'
pool:
vmImage: "macOS-13"
steps:
- task: Cache@2
inputs:
key: ccache | "$(Agent.OS)"
path: $(CCACHE_DIR)
restoreKeys: |
ccache | "$(Agent.OS)"
displayName: Ccache cache
- task: Cache@2
inputs:
key: qt | "$(Agent.OS)" | "$(Agent.OSArchitecture)" | "$(QT_VER)"
path: /tmp/Qt
restoreKeys: |
qt | "$(Agent.OS)" | "$(Agent.OSArchitecture)" | "$(QT_VER)"
displayName: Qt cache
# - task: Cache@2
# inputs:
# key: brew | "$(Agent.OS)"
# path: /Users/runner/Library/Caches/Homebrew
# restoreKeys: |
# brew | "$(Agent.OS)"
# displayName: Homebrew cache
- bash: |
chmod +x ".ci/build-mac-arm64.sh"
chmod +x ".ci/deploy-mac-arm64.sh"
chmod +x ".ci/optimize-mac.sh"
".ci/build-mac-arm64.sh"
displayName: Build macOS (arm64)
- publish: $(Build.ArtifactStagingDirectory)
condition: succeeded()
artifact: RPCS3 for Mac (Apple Silicon)
- bash: |
source './.ci/export-cirrus-vars.sh'
+16
View File
@@ -20,6 +20,9 @@ QToolBar#mw_toolbar::separator {
margin-top:2px;
margin-bottom: 2px;
}
QToolButton:disabled {
color: #787878;
}
QSlider#sizeSlider::groove:horizontal {
border: 0em solid transparent;
height: .3em;
@@ -147,3 +150,16 @@ QLabel#l_controller {
#game_list_grid_item[focus="true"] #game_list_grid_item_title_label {
color: #fff;
}
/* Top menu bar (Workaround for transparent menus in Qt 6.7.3) */
QMenu {
color: #000;
background-color: #F0F0F0;
alternate-background-color: #f2f2f2;
}
QMenu::item:selected {
background: #90C8F6;
}
QMenu::item:disabled {
color: #787878;
}
+10 -5
View File
@@ -88,6 +88,7 @@ else()
add_compile_options(-Wno-unused-lambda-capture)
add_compile_options(-Wno-unused-private-field)
add_compile_options(-Wno-unused-command-line-argument)
add_compile_options(-Wno-elaborated-enum-base)
elseif(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
add_compile_options(-Wno-class-memaccess)
endif()
@@ -100,10 +101,6 @@ else()
add_link_options(-no-pie)
endif()
elseif(APPLE)
if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
add_compile_options(-stdlib=libc++)
endif()
if (CMAKE_OSX_ARCHITECTURES MATCHES "x86_64")
add_link_options(-Wl,-image_base,0x10000 -Wl,-pagezero_size,0x10000)
add_link_options(-Wl,-no_pie)
@@ -117,6 +114,14 @@ else()
# Increase stack limit to 8 MB
add_link_options(-Wl,--stack -Wl,8388608)
add_link_options(-Wl,--image-base,0x10000)
# For arm64 windows, the image base cannot be below 4GB or the OS rejects the binary without much explanation.
if(COMPILER_X86)
add_link_options(-Wl,--image-base,0x10000)
endif()
endif()
# Specify C++ library to use as standard C++ when using clang (not required on linux due to GNU)
if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang" AND (APPLE OR WIN32))
add_compile_options(-stdlib=libc++)
endif()
endif()
+2
View File
@@ -0,0 +1,2 @@
set(CMAKE_SYSTEM_NAME Darwin)
set(CMAKE_SYSTEM_PROCESSOR arm64)
-5
View File
@@ -76,8 +76,6 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libcurl", "3rdparty\curl\li
{73973223-5EE8-41CA-8E88-1D60E89A237B} = {73973223-5EE8-41CA-8E88-1D60E89A237B}
EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "spirv", "3rdparty\SPIRV\spirv.vcxproj", "{4CBD3DDD-5555-49A4-A44D-DD3D8CB516A1}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "3rdParty", "3rdParty", "{6C3B64A0-8F8A-4DC4-8C0B-D71EBEED7FA8}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "llvm_build_clang_cl", "3rdparty\llvm\llvm_build\llvm_build_clang_cl.vcxproj", "{A37E4273-85DB-4217-B775-CE971B87D9DF}"
@@ -175,8 +173,6 @@ Global
{DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.Debug|x64.Build.0 = Debug|x64
{DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.Release|x64.ActiveCfg = Release|x64
{DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.Release|x64.Build.0 = Release|x64
{4CBD3DDD-5555-49A4-A44D-DD3D8CB516A1}.Debug|x64.ActiveCfg = Debug|x64
{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
@@ -236,7 +232,6 @@ Global
{349EE8F9-7D25-4909-AAF5-FF3FADE72187} = {6C3B64A0-8F8A-4DC4-8C0B-D71EBEED7FA8}
{73973223-5EE8-41CA-8E88-1D60E89A237B} = {6C3B64A0-8F8A-4DC4-8C0B-D71EBEED7FA8}
{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}
+21 -20
View File
@@ -114,7 +114,7 @@ if(UNIX)
endif()
if(WIN32)
target_link_libraries(rpcs3 PRIVATE ws2_32 Iphlpapi Winmm Psapi gdi32 setupapi pdh)
target_link_libraries(rpcs3 PRIVATE bcrypt ws2_32 Iphlpapi Winmm Psapi gdi32 setupapi pdh)
else()
target_link_libraries(rpcs3 PRIVATE ${CMAKE_DL_LIBS})
endif()
@@ -130,30 +130,31 @@ if(APPLE)
else()
set(QT_DEPLOY_FLAGS "")
endif()
qt_finalize_target(rpcs3)
add_custom_command(TARGET rpcs3 POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy
${CMAKE_CURRENT_SOURCE_DIR}/rpcs3.icns $<TARGET_FILE_DIR:rpcs3>/../Resources/rpcs3.icns
COMMAND ${CMAKE_COMMAND} -E copy_directory
${CMAKE_SOURCE_DIR}/bin/Icons $<TARGET_FILE_DIR:rpcs3>/../Resources/Icons
COMMAND ${CMAKE_COMMAND} -E copy_directory
${CMAKE_SOURCE_DIR}/bin/GuiConfigs $<TARGET_FILE_DIR:rpcs3>/../Resources/GuiConfigs
COMMAND ${CMAKE_COMMAND} -E copy_directory
${CMAKE_SOURCE_DIR}/bin/git $<TARGET_FILE_DIR:rpcs3>/../Resources/git
COMMAND "${MACDEPLOYQT_EXECUTABLE}" "${PROJECT_BINARY_DIR}/bin/rpcs3.app" "${QT_DEPLOY_FLAGS}")
COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/rpcs3.icns $<TARGET_FILE_DIR:rpcs3>/../Resources/rpcs3.icns
COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/bin/Icons $<TARGET_FILE_DIR:rpcs3>/../Resources/Icons
COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/bin/GuiConfigs $<TARGET_FILE_DIR:rpcs3>/../Resources/GuiConfigs
COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/bin/git $<TARGET_FILE_DIR:rpcs3>/../Resources/git
COMMAND "${MACDEPLOYQT_EXECUTABLE}" "${PROJECT_BINARY_DIR}/bin/rpcs3.app" "${QT_DEPLOY_FLAGS}")
elseif(UNIX)
add_custom_command(TARGET rpcs3 POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_directory
${CMAKE_SOURCE_DIR}/bin/Icons $<TARGET_FILE_DIR:rpcs3>/Icons)
add_custom_command(TARGET rpcs3 POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_directory
${CMAKE_SOURCE_DIR}/bin/GuiConfigs $<TARGET_FILE_DIR:rpcs3>/GuiConfigs)
add_custom_command(TARGET rpcs3 POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_directory
${CMAKE_SOURCE_DIR}/bin/git $<TARGET_FILE_DIR:rpcs3>/git)
COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/bin/Icons $<TARGET_FILE_DIR:rpcs3>/Icons
COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/bin/GuiConfigs $<TARGET_FILE_DIR:rpcs3>/GuiConfigs
COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/bin/git $<TARGET_FILE_DIR:rpcs3>/git)
elseif(WIN32)
if(MSVC)
add_custom_command(TARGET rpcs3 POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy ${PROJECT_BINARY_DIR}/3rdparty/OpenAL/openal-soft/$<CONFIG>/OpenAL32.dll $<TARGET_FILE_DIR:rpcs3>)
endif()
add_custom_command(TARGET rpcs3 POST_BUILD
COMMAND "${CMAKE_COMMAND}" -E copy_directory "${CMAKE_SOURCE_DIR}/bin" "$<TARGET_FILE_DIR:rpcs3>"
COMMAND "${WINDEPLOYQT_EXECUTABLE}" --no-compiler-runtime --no-opengl-sw --no-patchqt --no-translations --no-quick --no-system-d3d-compiler --no-quick-import --plugindir "$<IF:$<CXX_COMPILER_ID:MSVC>,$<TARGET_FILE_DIR:rpcs3>/plugins,$<TARGET_FILE_DIR:rpcs3>/share/qt6/plugins>" --verbose 0 "$<TARGET_FILE:rpcs3>")
COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/bin/Icons $<TARGET_FILE_DIR:rpcs3>/Icons
COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/bin/GuiConfigs $<TARGET_FILE_DIR:rpcs3>/GuiConfigs
COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/bin/git $<TARGET_FILE_DIR:rpcs3>/git
COMMAND "${WINDEPLOYQT_EXECUTABLE}" --no-compiler-runtime --no-opengl-sw --no-patchqt
--no-translations --no-quick --no-system-d3d-compiler --no-quick-import
--plugindir "$<IF:$<CXX_COMPILER_ID:MSVC>,$<TARGET_FILE_DIR:rpcs3>/plugins,$<TARGET_FILE_DIR:rpcs3>/share/qt6/plugins>"
--verbose 0 "$<TARGET_FILE:rpcs3>")
endif()
# Unix installation
+7 -1
View File
@@ -239,6 +239,7 @@ target_sources(rpcs3_emu PRIVATE
Cell/Modules/cellAdec.cpp
Cell/Modules/cellAtrac.cpp
Cell/Modules/cellAtracMulti.cpp
Cell/Modules/cellAtracXdec.cpp
Cell/Modules/cellAudio.cpp
Cell/Modules/cellAudioOut.cpp
Cell/Modules/cellAuthDialog.cpp
@@ -389,7 +390,7 @@ target_sources(rpcs3_emu PRIVATE
CPU/CPUTranslator.cpp
)
if(CMAKE_SYSTEM_PROCESSOR MATCHES "arm64|aarch64")
if(CMAKE_SYSTEM_PROCESSOR MATCHES "ARM64|arm64|aarch64")
target_sources(rpcs3_emu PRIVATE
CPU/Backends/AArch64/AArch64ASM.cpp
CPU/Backends/AArch64/AArch64Common.cpp
@@ -442,8 +443,10 @@ target_link_libraries(rpcs3_emu PRIVATE
target_sources(rpcs3_emu PRIVATE
NP/fb_helpers.cpp
NP/np_cache.cpp
NP/np_gui_cache.cpp
NP/np_contexts.cpp
NP/np_dnshook.cpp
NP/np_requests_gui.cpp
NP/np_handler.cpp
NP/np_helpers.cpp
NP/np_notifications.cpp
@@ -475,6 +478,7 @@ target_sources(rpcs3_emu PRIVATE
RSX/gcm_printing.cpp
RSX/GL/GLCommonDecompiler.cpp
RSX/GL/GLCompute.cpp
RSX/GL/GLDMA.cpp
RSX/GL/GLDraw.cpp
RSX/GL/GLFragmentProgram.cpp
RSX/GL/GLGSRender.cpp
@@ -500,6 +504,7 @@ target_sources(rpcs3_emu PRIVATE
RSX/GL/OpenGL.cpp
RSX/GL/upscalers/fsr1/fsr_pass.cpp
RSX/GSRender.cpp
RSX/Host/RSXDMAWriter.cpp
RSX/Null/NullGSRender.cpp
RSX/NV47/FW/draw_call.cpp
RSX/NV47/FW/reg_context.cpp
@@ -509,6 +514,7 @@ target_sources(rpcs3_emu PRIVATE
RSX/NV47/HW/nv308a.cpp
RSX/NV47/HW/nv406e.cpp
RSX/NV47/HW/nv4097.cpp
RSX/Overlays/FriendsList/overlay_friends_list_dialog.cpp
RSX/Overlays/HomeMenu/overlay_home_menu.cpp
RSX/Overlays/HomeMenu/overlay_home_menu_components.cpp
RSX/Overlays/HomeMenu/overlay_home_menu_main_menu.cpp
@@ -3,8 +3,6 @@
namespace aarch64
{
constexpr u32 ESR_CTX_MAGIC = 0x45535201;
// Some of the EC codes we care about
enum class EL1_exception_class
{
@@ -23,6 +21,8 @@ namespace aarch64
};
#ifdef __linux__
constexpr u32 ESR_CTX_MAGIC = 0x45535201;
const aarch64_esr_ctx* find_EL1_esr_context(const ucontext_t* ctx)
{
u32 offset = 0;
@@ -1,7 +1,12 @@
#pragma once
#include <util/types.hpp>
#ifndef _WIN32
#include <sys/ucontext.h>
#else
using ucontext_t = void;
#endif
namespace aarch64
{
+16
View File
@@ -3729,6 +3729,22 @@ public:
return result;
}
template <typename T1, typename T2, typename T3>
value_t<f32[4]> vfixupimmps(T1 a, T2 b, T3 c, u8 d, u8 e)
{
value_t<f32[4]> result;
const auto data0 = a.eval(m_ir);
const auto data1 = b.eval(m_ir);
const auto data2 = c.eval(m_ir);
const auto immediate = (llvm_const_int<u32>{d});
const auto imm32 = immediate.eval(m_ir);
const auto immediate2 = (llvm_const_int<u8>{e});
const auto imm8 = immediate2.eval(m_ir);
result.value = m_ir->CreateCall(get_intrinsic(llvm::Intrinsic::x86_avx512_mask_fixupimm_ps_128), {data0, data1, data2, imm32, imm8});
return result;
}
llvm::Value* load_const(llvm::GlobalVariable* g, llvm::Value* i, llvm::Type* type = nullptr)
{
return m_ir->CreateLoad(type ? type : g->getValueType(), m_ir->CreateGEP(g->getValueType(), g, {m_ir->getInt64(0), m_ir->CreateZExtOrTrunc(i, get_type<u64>())}));
+21
View File
@@ -132,6 +132,27 @@
#include <math.h>
#endif
/* RPCS3 additions */
#if defined(_WIN32)
static inline int posix_memalign(void** memptr, size_t alignment, size_t size)
{
// Check for valid alignment (must be a power of two and multiple of sizeof(void*))
if (alignment == 0 || (alignment & (alignment - 1)) != 0 || alignment % sizeof(void*) != 0)
return EINVAL;
// Allocate memory using _aligned_malloc
void* ptr = _aligned_malloc(size, alignment);
if (!ptr)
// NOTE: _aligned_malloc sets errno, ideally we should use that to generate the return code
return ENOMEM;
// Success
*memptr = ptr;
return 0;
}
#endif
/* End RPCS3 additions */
/* "__has_builtin" can be used to query support for built-in functions
* provided by gcc/clang and other compilers that support it.
*/
+3 -60
View File
@@ -28,6 +28,7 @@ extern "C"
#endif
#include "cellPamf.h"
#include "cellAtracXdec.h"
#include "cellAdec.h"
#include <mutex>
@@ -136,63 +137,6 @@ void fmt_class_string<CellAdecError>::format(std::string& out, u64 arg)
STR_CASE(CELL_ADEC_ERROR_AT3_BUSY);
STR_CASE(CELL_ADEC_ERROR_AT3_EMPTY);
STR_CASE(CELL_ADEC_ERROR_AT3_ERROR);
STR_CASE(CELL_ADEC_ERROR_ATX_OK); // CELL_ADEC_ERROR_ATX_OFFSET, CELL_ADEC_ERROR_ATX_NONE
STR_CASE(CELL_ADEC_ERROR_ATX_BUSY);
STR_CASE(CELL_ADEC_ERROR_ATX_EMPTY);
STR_CASE(CELL_ADEC_ERROR_ATX_ATSHDR);
STR_CASE(CELL_ADEC_ERROR_ATX_NON_FATAL);
STR_CASE(CELL_ADEC_ERROR_ATX_NOT_IMPLE);
STR_CASE(CELL_ADEC_ERROR_ATX_PACK_CE_OVERFLOW);
STR_CASE(CELL_ADEC_ERROR_ATX_ILLEGAL_NPROCQUS);
STR_CASE(CELL_ADEC_ERROR_ATX_FATAL);
STR_CASE(CELL_ADEC_ERROR_ATX_ENC_OVERFLOW);
STR_CASE(CELL_ADEC_ERROR_ATX_PACK_CE_UNDERFLOW);
STR_CASE(CELL_ADEC_ERROR_ATX_SYNTAX_IDCT);
STR_CASE(CELL_ADEC_ERROR_ATX_SYNTAX_GAINADJ);
STR_CASE(CELL_ADEC_ERROR_ATX_SYNTAX_IDSF);
STR_CASE(CELL_ADEC_ERROR_ATX_SYNTAX_SPECTRA);
STR_CASE(CELL_ADEC_ERROR_ATX_SYNTAX_IDWL);
STR_CASE(CELL_ADEC_ERROR_ATX_SYNTAX_GHWAVE);
STR_CASE(CELL_ADEC_ERROR_ATX_SYNTAX_SHEADER);
STR_CASE(CELL_ADEC_ERROR_ATX_SYNTAX_IDWL_A);
STR_CASE(CELL_ADEC_ERROR_ATX_SYNTAX_IDWL_B);
STR_CASE(CELL_ADEC_ERROR_ATX_SYNTAX_IDWL_C);
STR_CASE(CELL_ADEC_ERROR_ATX_SYNTAX_IDWL_D);
STR_CASE(CELL_ADEC_ERROR_ATX_SYNTAX_IDWL_E);
STR_CASE(CELL_ADEC_ERROR_ATX_SYNTAX_IDSF_A);
STR_CASE(CELL_ADEC_ERROR_ATX_SYNTAX_IDSF_B);
STR_CASE(CELL_ADEC_ERROR_ATX_SYNTAX_IDSF_C);
STR_CASE(CELL_ADEC_ERROR_ATX_SYNTAX_IDSF_D);
STR_CASE(CELL_ADEC_ERROR_ATX_SYNTAX_IDCT_A);
STR_CASE(CELL_ADEC_ERROR_ATX_SYNTAX_GC_NGC);
STR_CASE(CELL_ADEC_ERROR_ATX_SYNTAX_GC_IDLEV_A);
STR_CASE(CELL_ADEC_ERROR_ATX_SYNTAX_GC_IDLOC_A);
STR_CASE(CELL_ADEC_ERROR_ATX_SYNTAX_GC_IDLEV_B);
STR_CASE(CELL_ADEC_ERROR_ATX_SYNTAX_GC_IDLOC_B);
STR_CASE(CELL_ADEC_ERROR_ATX_SYNTAX_SN_NWVS);
STR_CASE(CELL_ADEC_ERROR_ATX_FATAL_HANDLE);
STR_CASE(CELL_ADEC_ERROR_ATX_ASSERT_SAMPLING_FREQ);
STR_CASE(CELL_ADEC_ERROR_ATX_ASSERT_CH_CONFIG_INDEX);
STR_CASE(CELL_ADEC_ERROR_ATX_ASSERT_NBYTES);
STR_CASE(CELL_ADEC_ERROR_ATX_ASSERT_BLOCK_NUM);
STR_CASE(CELL_ADEC_ERROR_ATX_ASSERT_BLOCK_ID);
STR_CASE(CELL_ADEC_ERROR_ATX_ASSERT_CHANNELS);
STR_CASE(CELL_ADEC_ERROR_ATX_UNINIT_BLOCK_SPECIFIED);
STR_CASE(CELL_ADEC_ERROR_ATX_POSCFG_PRESENT);
STR_CASE(CELL_ADEC_ERROR_ATX_BUFFER_OVERFLOW);
STR_CASE(CELL_ADEC_ERROR_ATX_ILL_BLK_TYPE_ID);
STR_CASE(CELL_ADEC_ERROR_ATX_UNPACK_CHANNEL_BLK_FAILED);
STR_CASE(CELL_ADEC_ERROR_ATX_ILL_BLK_ID_USED_1);
STR_CASE(CELL_ADEC_ERROR_ATX_ILL_BLK_ID_USED_2);
STR_CASE(CELL_ADEC_ERROR_ATX_ILLEGAL_ENC_SETTING);
STR_CASE(CELL_ADEC_ERROR_ATX_ILLEGAL_DEC_SETTING);
STR_CASE(CELL_ADEC_ERROR_ATX_ASSERT_NSAMPLES);
STR_CASE(CELL_ADEC_ERROR_ATX_ILL_SYNCWORD);
STR_CASE(CELL_ADEC_ERROR_ATX_ILL_SAMPLING_FREQ);
STR_CASE(CELL_ADEC_ERROR_ATX_ILL_CH_CONFIG_INDEX);
STR_CASE(CELL_ADEC_ERROR_ATX_RAW_DATA_FRAME_SIZE_OVER);
STR_CASE(CELL_ADEC_ERROR_ATX_SYNTAX_ENHANCE_LENGTH_OVER);
STR_CASE(CELL_ADEC_ERROR_ATX_SPU_INTERNAL_FAIL);
STR_CASE(CELL_ADEC_ERROR_LPCM_FATAL);
STR_CASE(CELL_ADEC_ERROR_LPCM_SEQ);
STR_CASE(CELL_ADEC_ERROR_LPCM_ARG);
@@ -910,7 +854,7 @@ error_code cellAdecDecodeAu(u32 handle, vm::ptr<CellAdecAuInfo> auInfo)
AdecTask task(adecDecodeAu);
task.au.auInfo_addr = auInfo.addr();
task.au.addr = auInfo->startAddr;
task.au.addr = auInfo->startAddr.addr();
task.au.size = auInfo->size;
task.au.pts = (u64{auInfo->pts.upper} << 32) | u64{auInfo->pts.lower};
task.au.userdata = auInfo->userData;
@@ -1072,7 +1016,7 @@ error_code cellAdecGetPcmItem(u32 handle, vm::pptr<CellAdecPcmItem> pcmItem)
pcm->auInfo.pts.lower = static_cast<u32>(af.pts);
pcm->auInfo.pts.upper = static_cast<u32>(af.pts >> 32);
pcm->auInfo.size = af.auSize;
pcm->auInfo.startAddr = af.auAddr;
pcm->auInfo.startAddr.set(af.auAddr);
pcm->auInfo.userData = af.userdata;
if (adecIsAtracX(adec->type))
@@ -1119,7 +1063,6 @@ DECLARE(ppu_module_manager::cellAdec)("cellAdec", []()
{
static ppu_static_module cell_libac3dec("cell_libac3dec");
static ppu_static_module cellAtrac3dec("cellAtrac3dec");
static ppu_static_module cellAtracXdec("cellAtracXdec");
static ppu_static_module cellCelpDec("cellCelpDec");
static ppu_static_module cellDTSdec("cellDTSdec");
static ppu_static_module cellM2AACdec("cellM2AACdec");
+160 -129
View File
@@ -111,68 +111,6 @@ enum CellAdecError : u32
CELL_ADEC_ERROR_AT3_ERROR = 0x80612180,
CELL_ADEC_ERROR_ATX_OFFSET = 0x80612200,
CELL_ADEC_ERROR_ATX_NONE = 0x80612200,
CELL_ADEC_ERROR_ATX_OK = 0x80612200,
CELL_ADEC_ERROR_ATX_BUSY = 0x80612264,
CELL_ADEC_ERROR_ATX_EMPTY = 0x80612265,
CELL_ADEC_ERROR_ATX_ATSHDR = 0x80612266,
CELL_ADEC_ERROR_ATX_NON_FATAL = 0x80612281,
CELL_ADEC_ERROR_ATX_NOT_IMPLE = 0x80612282,
CELL_ADEC_ERROR_ATX_PACK_CE_OVERFLOW = 0x80612283,
CELL_ADEC_ERROR_ATX_ILLEGAL_NPROCQUS = 0x80612284,
CELL_ADEC_ERROR_ATX_FATAL = 0x8061228c,
CELL_ADEC_ERROR_ATX_ENC_OVERFLOW = 0x8061228d,
CELL_ADEC_ERROR_ATX_PACK_CE_UNDERFLOW = 0x8061228e,
CELL_ADEC_ERROR_ATX_SYNTAX_IDCT = 0x8061228f,
CELL_ADEC_ERROR_ATX_SYNTAX_GAINADJ = 0x80612290,
CELL_ADEC_ERROR_ATX_SYNTAX_IDSF = 0x80612291,
CELL_ADEC_ERROR_ATX_SYNTAX_SPECTRA = 0x80612292,
CELL_ADEC_ERROR_ATX_SYNTAX_IDWL = 0x80612293,
CELL_ADEC_ERROR_ATX_SYNTAX_GHWAVE = 0x80612294,
CELL_ADEC_ERROR_ATX_SYNTAX_SHEADER = 0x80612295,
CELL_ADEC_ERROR_ATX_SYNTAX_IDWL_A = 0x80612296,
CELL_ADEC_ERROR_ATX_SYNTAX_IDWL_B = 0x80612297,
CELL_ADEC_ERROR_ATX_SYNTAX_IDWL_C = 0x80612298,
CELL_ADEC_ERROR_ATX_SYNTAX_IDWL_D = 0x80612299,
CELL_ADEC_ERROR_ATX_SYNTAX_IDWL_E = 0x8061229a,
CELL_ADEC_ERROR_ATX_SYNTAX_IDSF_A = 0x8061229b,
CELL_ADEC_ERROR_ATX_SYNTAX_IDSF_B = 0x8061229c,
CELL_ADEC_ERROR_ATX_SYNTAX_IDSF_C = 0x8061229d,
CELL_ADEC_ERROR_ATX_SYNTAX_IDSF_D = 0x8061229e,
CELL_ADEC_ERROR_ATX_SYNTAX_IDCT_A = 0x8061229f,
CELL_ADEC_ERROR_ATX_SYNTAX_GC_NGC = 0x806122a0,
CELL_ADEC_ERROR_ATX_SYNTAX_GC_IDLEV_A = 0x806122a1,
CELL_ADEC_ERROR_ATX_SYNTAX_GC_IDLOC_A = 0x806122a2,
CELL_ADEC_ERROR_ATX_SYNTAX_GC_IDLEV_B = 0x806122a3,
CELL_ADEC_ERROR_ATX_SYNTAX_GC_IDLOC_B = 0x806122a4,
CELL_ADEC_ERROR_ATX_SYNTAX_SN_NWVS = 0x806122a5,
CELL_ADEC_ERROR_ATX_FATAL_HANDLE = 0x806122aa,
CELL_ADEC_ERROR_ATX_ASSERT_SAMPLING_FREQ = 0x806122ab,
CELL_ADEC_ERROR_ATX_ASSERT_CH_CONFIG_INDEX = 0x806122ac,
CELL_ADEC_ERROR_ATX_ASSERT_NBYTES = 0x806122ad,
CELL_ADEC_ERROR_ATX_ASSERT_BLOCK_NUM = 0x806122ae,
CELL_ADEC_ERROR_ATX_ASSERT_BLOCK_ID = 0x806122af,
CELL_ADEC_ERROR_ATX_ASSERT_CHANNELS = 0x806122b0,
CELL_ADEC_ERROR_ATX_UNINIT_BLOCK_SPECIFIED = 0x806122b1,
CELL_ADEC_ERROR_ATX_POSCFG_PRESENT = 0x806122b2,
CELL_ADEC_ERROR_ATX_BUFFER_OVERFLOW = 0x806122b3,
CELL_ADEC_ERROR_ATX_ILL_BLK_TYPE_ID = 0x806122b4,
CELL_ADEC_ERROR_ATX_UNPACK_CHANNEL_BLK_FAILED = 0x806122b5,
CELL_ADEC_ERROR_ATX_ILL_BLK_ID_USED_1 = 0x806122b6,
CELL_ADEC_ERROR_ATX_ILL_BLK_ID_USED_2 = 0x806122b7,
CELL_ADEC_ERROR_ATX_ILLEGAL_ENC_SETTING = 0x806122b8,
CELL_ADEC_ERROR_ATX_ILLEGAL_DEC_SETTING = 0x806122b9,
CELL_ADEC_ERROR_ATX_ASSERT_NSAMPLES = 0x806122ba,
CELL_ADEC_ERROR_ATX_ILL_SYNCWORD = 0x806122bb,
CELL_ADEC_ERROR_ATX_ILL_SAMPLING_FREQ = 0x806122bc,
CELL_ADEC_ERROR_ATX_ILL_CH_CONFIG_INDEX = 0x806122bd,
CELL_ADEC_ERROR_ATX_RAW_DATA_FRAME_SIZE_OVER = 0x806122be,
CELL_ADEC_ERROR_ATX_SYNTAX_ENHANCE_LENGTH_OVER = 0x806122bf,
CELL_ADEC_ERROR_ATX_SPU_INTERNAL_FAIL = 0x806122c8,
CELL_ADEC_ERROR_LPCM_FATAL = 0x80612001,
CELL_ADEC_ERROR_LPCM_SEQ = 0x80612002,
CELL_ADEC_ERROR_LPCM_ARG = 0x80612003,
@@ -250,38 +188,38 @@ enum CellAdecError : u32
// Audio Codec Type
enum AudioCodecType : s32
{
CELL_ADEC_TYPE_RESERVED1,
CELL_ADEC_TYPE_INVALID1,
CELL_ADEC_TYPE_LPCM_PAMF,
CELL_ADEC_TYPE_AC3,
CELL_ADEC_TYPE_ATRACX,
CELL_ADEC_TYPE_MP3,
CELL_ADEC_TYPE_ATRAC3,
CELL_ADEC_TYPE_MPEG_L2,
CELL_ADEC_TYPE_RESERVED5,
CELL_ADEC_TYPE_RESERVED6,
CELL_ADEC_TYPE_RESERVED7,
CELL_ADEC_TYPE_RESERVED8,
CELL_ADEC_TYPE_M2AAC,
CELL_ADEC_TYPE_EAC3,
CELL_ADEC_TYPE_TRUEHD,
CELL_ADEC_TYPE_DTS, // Removed in firmware 4.00, integrated into DTSHD
CELL_ADEC_TYPE_CELP,
CELL_ADEC_TYPE_RESERVED10,
CELL_ADEC_TYPE_LPCM_BLURAY,
CELL_ADEC_TYPE_ATRACX_2CH,
CELL_ADEC_TYPE_ATRACX_6CH,
CELL_ADEC_TYPE_ATRACX_8CH,
CELL_ADEC_TYPE_M4AAC,
CELL_ADEC_TYPE_RESERVED12,
CELL_ADEC_TYPE_RESERVED13,
CELL_ADEC_TYPE_RESERVED14,
CELL_ADEC_TYPE_RESERVED15,
CELL_ADEC_TYPE_RESERVED16,
CELL_ADEC_TYPE_RESERVED17,
CELL_ADEC_TYPE_RESERVED18,
CELL_ADEC_TYPE_RESERVED19,
CELL_ADEC_TYPE_LPCM_DVD,
CELL_ADEC_TYPE_WMA,
CELL_ADEC_TYPE_DTSLBR,
CELL_ADEC_TYPE_M4AAC_2CH,
CELL_ADEC_TYPE_DTSHD,
CELL_ADEC_TYPE_MPEG_L1,
CELL_ADEC_TYPE_MP3S,
CELL_ADEC_TYPE_M4AAC_2CH_MOD,
CELL_ADEC_TYPE_CELP8,
CELL_ADEC_TYPE_RESERVED20,
CELL_ADEC_TYPE_RESERVED21,
CELL_ADEC_TYPE_RESERVED22,
CELL_ADEC_TYPE_RESERVED23,
CELL_ADEC_TYPE_RESERVED24,
CELL_ADEC_TYPE_RESERVED25,
CELL_ADEC_TYPE_INVALID2,
CELL_ADEC_TYPE_INVALID3,
CELL_ADEC_TYPE_RESERVED22, // Either WMA Pro or WMA Lossless, was never released
CELL_ADEC_TYPE_RESERVED23, // Either WMA Pro or WMA Lossless, was never released
CELL_ADEC_TYPE_DTSHDCORE, // Removed in firmware 4.00, integrated into DTSHD
CELL_ADEC_TYPE_ATRAC3MULTI,
};
inline bool adecIsAtracX(s32 type)
@@ -313,10 +251,12 @@ enum CellAdecChannel : s32
// Sampling Rate
enum CellAdecSampleRate : s32
{
CELL_ADEC_FS_RESERVED1 = 0,
CELL_ADEC_FS_48kHz = 1,
CELL_ADEC_FS_16kHz = 2,
CELL_ADEC_FS_8kHz = 5,
CELL_ADEC_FS_RESERVED1,
CELL_ADEC_FS_48kHz,
CELL_ADEC_FS_16kHz,
CELL_ADEC_FS_96kHz,
CELL_ADEC_FS_192kHz,
CELL_ADEC_FS_8kHz,
};
enum CellAdecBitLength : s32
@@ -359,6 +299,13 @@ struct CellAdecResourceEx
be_t<u32> maxContention;
};
struct CellAdecResourceSpurs
{
be_t<u32> spurs_addr; // CellSpurs*
u8 priority[8];
be_t<u32> maxContention;
};
// Callback Messages
enum CellAdecMsgType : s32
{
@@ -370,16 +317,20 @@ enum CellAdecMsgType : s32
using CellAdecCbMsg = s32(u32 handle, CellAdecMsgType msgType, s32 msgData, u32 cbArg);
struct CellAdecCb
// Used for internal callbacks as well
template <typename F>
struct AdecCb
{
vm::bptr<CellAdecCbMsg> cbFunc;
be_t<u32> cbArg;
vm::bptr<F> cbFunc;
vm::bptr<void> cbArg;
};
using CellAdecCb = AdecCb<CellAdecCbMsg>;
// AU Info
struct CellAdecAuInfo
{
be_t<u32> startAddr;
vm::bcptr<u8> startAddr;
be_t<u32> size;
CellCodecTimeStamp pts;
be_t<u64> userData;
@@ -401,6 +352,125 @@ struct CellAdecPcmItem
CellAdecAuInfo auInfo;
};
// Controls how much is added to the presentation time stamp of the previous frame if the game didn't set a pts itself in CellAdecAuInfo when calling cellAdecDecodeAu()
enum AdecCorrectPtsValueType : s8
{
ADEC_CORRECT_PTS_VALUE_TYPE_UNSPECIFIED = -1,
// Adds a fixed amount
ADEC_CORRECT_PTS_VALUE_TYPE_LPCM = 0,
// 1
ADEC_CORRECT_PTS_VALUE_TYPE_ATRACX_48000Hz = 2,
ADEC_CORRECT_PTS_VALUE_TYPE_ATRACX_44100Hz = 3,
ADEC_CORRECT_PTS_VALUE_TYPE_ATRACX_32000Hz = 4,
// 5: Dolby Digital
// 6: ATRAC3
// 7: MP3
// 8: MP3
// 9: MP3
// 39: ATRAC3 multi-track
// Calls a decoder function (_SceAdecCorrectPtsValue_codec())
// 17: Dolby Digital Plus
// 18
// 19
// 20
// 21: DTS HD
// 22
// 23
// 24: CELP
// 25: MPEG-2 AAC
// 26: MPEG-2 BC
// 27: Dolby TrueHD
// 28: DTS
// 29: MPEG-4 AAC
// 30: Windows Media Audio
// 31: DTS Express
// 32: MP1
// 33: MP3 Surround
// 34: CELP8
// 35: Windows Media Audio Professional
// 36: Windows Media Audio Lossless
// 37: DTS HD Core
// 38: DTS HD Core
};
// Internal callbacks
using AdecNotifyAuDone = error_code(s32 pcmHandle, vm::ptr<void> cbArg);
using AdecNotifyPcmOut = error_code(s32 pcmHandle, vm::ptr<void> pcmAddr, u32 pcmSize, vm::ptr<void> cbArg, vm::cpptr<void> bsiInfo, AdecCorrectPtsValueType correctPtsValueType, s32 errorCode);
using AdecNotifyError = error_code(s32 errorCode, vm::ptr<void> cbArg);
using AdecNotifySeqDone = error_code(vm::ptr<void> cbArg);
// Decoder functions
using CellAdecCoreOpGetMemSize = error_code(vm::ptr<CellAdecAttr> attr);
using CellAdecCoreOpOpen = error_code(vm::ptr<void> coreHandle, vm::ptr<AdecNotifyAuDone> cbFuncAuDone, vm::ptr<void> cbArgAuDone, vm::ptr<AdecNotifyPcmOut> cbFuncPcmOut, vm::ptr<void> cbArgPcmOut,
vm::ptr<AdecNotifyError> cbFuncError, vm::ptr<void> cbArgError, vm::ptr<AdecNotifySeqDone> cbFuncSeqDone, vm::ptr<void> cbArgSeqDone, vm::cptr<CellAdecResource> res);
using CellAdecCoreOpClose = error_code(vm::ptr<void> coreHandle);
using CellAdecCoreOpStartSeq = error_code(vm::ptr<void> coreHandle, vm::cptr<void> param);
using CellAdecCoreOpEndSeq = error_code(vm::ptr<void> coreHandle);
using CellAdecCoreOpDecodeAu = error_code(vm::ptr<void> coreHandle, s32 pcmHandle, vm::cptr<CellAdecAuInfo> auInfo);
using CellAdecCoreOpGetVersion = void(vm::ptr<be_t<u32, 1>> version);
using CellAdecCoreOpRealign = error_code(vm::ptr<void> coreHandle, vm::ptr<void> outBuffer, vm::cptr<void> pcmStartAddr);
using CellAdecCoreOpReleasePcm = error_code(vm::ptr<void> coreHandle, s32 pcmHandle, vm::cptr<void> outBuffer);
using CellAdecCoreOpGetPcmHandleNum = s32();
using CellAdecCoreOpGetBsiInfoSize = u32();
using CellAdecCoreOpOpenExt = error_code(vm::ptr<void> coreHandle, vm::ptr<AdecNotifyAuDone> cbFuncAuDone, vm::ptr<void> cbArgAuDone, vm::ptr<AdecNotifyPcmOut> cbFuncPcmOut, vm::ptr<void> cbArgPcmOut,
vm::ptr<AdecNotifyError> cbFuncError, vm::ptr<void> cbArgError, vm::ptr<AdecNotifySeqDone> cbFuncSeqDone, vm::ptr<void> cbArgSeqDone, vm::cptr<CellAdecResource> res, vm::cptr<CellAdecResourceSpurs> spursRes);
// Decoders export a pointer to this struct
struct CellAdecCoreOps
{
vm::bptr<CellAdecCoreOpGetMemSize> getMemSize;
vm::bptr<CellAdecCoreOpOpen> open;
vm::bptr<CellAdecCoreOpClose> close;
vm::bptr<CellAdecCoreOpStartSeq> startSeq;
vm::bptr<CellAdecCoreOpEndSeq> endSeq;
vm::bptr<CellAdecCoreOpDecodeAu> decodeAu;
vm::bptr<CellAdecCoreOpGetVersion> getVersion;
vm::bptr<CellAdecCoreOpRealign> realign;
vm::bptr<CellAdecCoreOpReleasePcm> releasePcm;
vm::bptr<CellAdecCoreOpGetPcmHandleNum> getPcmHandleNum;
vm::bptr<CellAdecCoreOpGetBsiInfoSize> getBsiInfoSize;
vm::bptr<CellAdecCoreOpOpenExt> openExt;
};
// Used by several decoders as command queue
template <typename T>
struct AdecCmdQueue
{
T elements[4];
be_t<s32> front = 0;
be_t<s32> back = 0;
be_t<s32> size = 0;
template <bool is_peek = false>
void pop(T& cmd)
{
// LLE returns uninitialized stack memory if the queue is empty
cmd = elements[front];
if constexpr (!is_peek)
{
elements[front].pcm_handle = 0xff;
front = (front + 1) & 3;
size--;
}
}
void emplace(auto&&... args)
{
new (&elements[back]) T(std::forward<decltype(args)>(args)...);
back = (back + 1) & 3;
size++;
}
void peek(T& cmd) const { return pop<true>(cmd); }
bool empty() const { return size == 0; }
bool full() const { return size >= 4; }
};
struct CellAdecParamLpcm
{
be_t<u32> channelNumber;
@@ -771,45 +841,6 @@ struct CellAdecAtrac3Info
be_t<s32> nbytes;
};
enum ATRACX_WordSize : s32
{
CELL_ADEC_ATRACX_WORD_SZ_16BIT = 0x02,
CELL_ADEC_ATRACX_WORD_SZ_24BIT = 0x03,
CELL_ADEC_ATRACX_WORD_SZ_32BIT = 0x04,
CELL_ADEC_ATRACX_WORD_SZ_FLOAT = 0x84,
};
enum ATRACX_ATSHeaderInclude : u8
{
CELL_ADEC_ATRACX_ATS_HDR_NOTINC = 0,
CELL_ADEC_ATRACX_ATS_HDR_INC = 1,
};
enum ATRACX_DownmixFlag : u8
{
ATRACX_DOWNMIX_OFF = 0,
ATRACX_DOWNMIX_ON = 1,
};
struct CellAdecParamAtracX
{
be_t<s32> sampling_freq;
be_t<s32> ch_config_idx;
be_t<s32> nch_out;
be_t<s32> nbytes;
std::array<u8, 4> extra_config_data; // downmix coefficients
be_t<s32> bw_pcm; // ATRACX_WordSize
ATRACX_DownmixFlag downmix_flag;
ATRACX_ATSHeaderInclude au_includes_ats_hdr_flg;
};
struct CellAdecAtracXInfo
{
be_t<u32> samplingFreq; // [Hz]
be_t<u32> channelConfigIndex;
be_t<u32> nbytes;
};
enum MP3_WordSize : s32
{
CELL_ADEC_MP3_WORD_SZ_16BIT = 3,
+892
View File
@@ -0,0 +1,892 @@
#include "stdafx.h"
#include "Emu/perf_meter.hpp"
#include "Emu/Cell/PPUModule.h"
#include "Emu/Cell/lv2/sys_sync.h"
#include "Emu/Cell/lv2/sys_ppu_thread.h"
#include "Emu/savestate_utils.hpp"
#include "sysPrxForUser.h"
#include "util/asm.hpp"
#include "util/media_utils.h"
#include "cellAtracXdec.h"
vm::gvar<CellAdecCoreOps> g_cell_adec_core_ops_atracx2ch;
vm::gvar<CellAdecCoreOps> g_cell_adec_core_ops_atracx6ch;
vm::gvar<CellAdecCoreOps> g_cell_adec_core_ops_atracx8ch;
vm::gvar<CellAdecCoreOps> g_cell_adec_core_ops_atracx;
LOG_CHANNEL(cellAtracXdec);
template <>
void fmt_class_string<CellAtracXdecError>::format(std::string& out, u64 arg)
{
format_enum(out, arg, [](CellAtracXdecError value)
{
switch (value)
{
STR_CASE(CELL_ADEC_ERROR_ATX_OK); // CELL_ADEC_ERROR_ATX_OFFSET, CELL_ADEC_ERROR_ATX_NONE
STR_CASE(CELL_ADEC_ERROR_ATX_BUSY);
STR_CASE(CELL_ADEC_ERROR_ATX_EMPTY);
STR_CASE(CELL_ADEC_ERROR_ATX_ATSHDR);
STR_CASE(CELL_ADEC_ERROR_ATX_NON_FATAL);
STR_CASE(CELL_ADEC_ERROR_ATX_NOT_IMPLE);
STR_CASE(CELL_ADEC_ERROR_ATX_PACK_CE_OVERFLOW);
STR_CASE(CELL_ADEC_ERROR_ATX_ILLEGAL_NPROCQUS);
STR_CASE(CELL_ADEC_ERROR_ATX_FATAL);
STR_CASE(CELL_ADEC_ERROR_ATX_ENC_OVERFLOW);
STR_CASE(CELL_ADEC_ERROR_ATX_PACK_CE_UNDERFLOW);
STR_CASE(CELL_ADEC_ERROR_ATX_SYNTAX_IDCT);
STR_CASE(CELL_ADEC_ERROR_ATX_SYNTAX_GAINADJ);
STR_CASE(CELL_ADEC_ERROR_ATX_SYNTAX_IDSF);
STR_CASE(CELL_ADEC_ERROR_ATX_SYNTAX_SPECTRA);
STR_CASE(CELL_ADEC_ERROR_ATX_SYNTAX_IDWL);
STR_CASE(CELL_ADEC_ERROR_ATX_SYNTAX_GHWAVE);
STR_CASE(CELL_ADEC_ERROR_ATX_SYNTAX_SHEADER);
STR_CASE(CELL_ADEC_ERROR_ATX_SYNTAX_IDWL_A);
STR_CASE(CELL_ADEC_ERROR_ATX_SYNTAX_IDWL_B);
STR_CASE(CELL_ADEC_ERROR_ATX_SYNTAX_IDWL_C);
STR_CASE(CELL_ADEC_ERROR_ATX_SYNTAX_IDWL_D);
STR_CASE(CELL_ADEC_ERROR_ATX_SYNTAX_IDWL_E);
STR_CASE(CELL_ADEC_ERROR_ATX_SYNTAX_IDSF_A);
STR_CASE(CELL_ADEC_ERROR_ATX_SYNTAX_IDSF_B);
STR_CASE(CELL_ADEC_ERROR_ATX_SYNTAX_IDSF_C);
STR_CASE(CELL_ADEC_ERROR_ATX_SYNTAX_IDSF_D);
STR_CASE(CELL_ADEC_ERROR_ATX_SYNTAX_IDCT_A);
STR_CASE(CELL_ADEC_ERROR_ATX_SYNTAX_GC_NGC);
STR_CASE(CELL_ADEC_ERROR_ATX_SYNTAX_GC_IDLEV_A);
STR_CASE(CELL_ADEC_ERROR_ATX_SYNTAX_GC_IDLOC_A);
STR_CASE(CELL_ADEC_ERROR_ATX_SYNTAX_GC_IDLEV_B);
STR_CASE(CELL_ADEC_ERROR_ATX_SYNTAX_GC_IDLOC_B);
STR_CASE(CELL_ADEC_ERROR_ATX_SYNTAX_SN_NWVS);
STR_CASE(CELL_ADEC_ERROR_ATX_FATAL_HANDLE);
STR_CASE(CELL_ADEC_ERROR_ATX_ASSERT_SAMPLING_FREQ);
STR_CASE(CELL_ADEC_ERROR_ATX_ASSERT_CH_CONFIG_INDEX);
STR_CASE(CELL_ADEC_ERROR_ATX_ASSERT_NBYTES);
STR_CASE(CELL_ADEC_ERROR_ATX_ASSERT_BLOCK_NUM);
STR_CASE(CELL_ADEC_ERROR_ATX_ASSERT_BLOCK_ID);
STR_CASE(CELL_ADEC_ERROR_ATX_ASSERT_CHANNELS);
STR_CASE(CELL_ADEC_ERROR_ATX_UNINIT_BLOCK_SPECIFIED);
STR_CASE(CELL_ADEC_ERROR_ATX_POSCFG_PRESENT);
STR_CASE(CELL_ADEC_ERROR_ATX_BUFFER_OVERFLOW);
STR_CASE(CELL_ADEC_ERROR_ATX_ILL_BLK_TYPE_ID);
STR_CASE(CELL_ADEC_ERROR_ATX_UNPACK_CHANNEL_BLK_FAILED);
STR_CASE(CELL_ADEC_ERROR_ATX_ILL_BLK_ID_USED_1);
STR_CASE(CELL_ADEC_ERROR_ATX_ILL_BLK_ID_USED_2);
STR_CASE(CELL_ADEC_ERROR_ATX_ILLEGAL_ENC_SETTING);
STR_CASE(CELL_ADEC_ERROR_ATX_ILLEGAL_DEC_SETTING);
STR_CASE(CELL_ADEC_ERROR_ATX_ASSERT_NSAMPLES);
STR_CASE(CELL_ADEC_ERROR_ATX_ILL_SYNCWORD);
STR_CASE(CELL_ADEC_ERROR_ATX_ILL_SAMPLING_FREQ);
STR_CASE(CELL_ADEC_ERROR_ATX_ILL_CH_CONFIG_INDEX);
STR_CASE(CELL_ADEC_ERROR_ATX_RAW_DATA_FRAME_SIZE_OVER);
STR_CASE(CELL_ADEC_ERROR_ATX_SYNTAX_ENHANCE_LENGTH_OVER);
STR_CASE(CELL_ADEC_ERROR_ATX_SPU_INTERNAL_FAIL);
}
return unknown;
});
}
constexpr u32 atracXdecGetSpursMemSize(u32 nch_in)
{
switch (nch_in)
{
case 1: return 0x6000;
case 2: return 0x6000;
case 3: return 0x12880;
case 4: return 0x19c80;
case 5: return -1;
case 6: return 0x23080;
case 7: return 0x2a480;
case 8: return 0x2c480;
default: return -1;
}
}
void AtracXdecDecoder::alloc_avcodec()
{
codec = avcodec_find_decoder(AV_CODEC_ID_ATRAC3P);
if (!codec)
{
fmt::throw_exception("avcodec_find_decoder() failed");
}
ensure(!(codec->capabilities & AV_CODEC_CAP_SUBFRAMES));
ctx = avcodec_alloc_context3(codec);
if (!ctx)
{
fmt::throw_exception("avcodec_alloc_context3() failed");
}
// Allows FFmpeg to output directly into guest memory
ctx->opaque = this;
ctx->thread_type = FF_THREAD_SLICE; // Silences a warning by FFmpeg about requesting frame threading with a custom get_buffer2(). Default is FF_THREAD_FRAME & FF_THREAD_SLICE
ctx->get_buffer2 = [](AVCodecContext* s, AVFrame* frame, int /*flags*/) -> int
{
for (s32 i = 0; i < frame->ch_layout.nb_channels; i++)
{
frame->data[i] = static_cast<AtracXdecDecoder*>(s->opaque)->work_mem.get_ptr() + ATXDEC_MAX_FRAME_LENGTH + ATXDEC_SAMPLES_PER_FRAME * sizeof(f32) * i;
frame->linesize[i] = ATXDEC_SAMPLES_PER_FRAME * sizeof(f32);
}
frame->buf[0] = av_buffer_create(frame->data[0], ATXDEC_SAMPLES_PER_FRAME * sizeof(f32) * frame->ch_layout.nb_channels, [](void*, uint8_t*){}, nullptr, 0);
return 0;
};
packet = av_packet_alloc();
if (!packet)
{
fmt::throw_exception("av_packet_alloc() failed");
}
frame = av_frame_alloc();
if (!frame)
{
fmt::throw_exception("av_frame_alloc() failed");
}
}
void AtracXdecDecoder::free_avcodec()
{
av_packet_free(&packet);
av_frame_free(&frame);
avcodec_free_context(&ctx);
}
void AtracXdecDecoder::init_avcodec()
{
if (int err = avcodec_close(ctx); err)
{
fmt::throw_exception("avcodec_close() failed (err=0x%x='%s')", err, utils::av_error_to_string(err));
}
ctx->block_align = nbytes;
ctx->ch_layout.nb_channels = nch_in;
ctx->sample_rate = sampling_freq;
if (int err = avcodec_open2(ctx, codec, nullptr); err)
{
fmt::throw_exception("avcodec_open2() failed (err=0x%x='%s')", err, utils::av_error_to_string(err));
}
packet->data = work_mem.get_ptr();
packet->size = nbytes;
packet->buf = av_buffer_create(work_mem.get_ptr(), nbytes, [](void*, uint8_t*){}, nullptr, 0);
}
error_code AtracXdecDecoder::set_config_info(u32 sampling_freq, u32 ch_config_idx, u32 nbytes)
{
cellAtracXdec.notice("AtracXdecDecoder::set_config_info(sampling_freq=%d, ch_config_idx=%d, nbytes=0x%x)", sampling_freq, ch_config_idx, nbytes);
this->sampling_freq = sampling_freq;
this->ch_config_idx = ch_config_idx;
this->nbytes = nbytes;
this->nbytes_128_aligned = utils::align(nbytes, 0x80);
this->nch_in = ch_config_idx <= 4 ? ch_config_idx : ch_config_idx + 1;
if (ch_config_idx > 7u)
{
this->config_is_set = false;
return { 0x80004005, "AtracXdecDecoder::set_config_info() failed: Invalid channel configuration: %d", ch_config_idx };
}
this->nch_blocks = ATXDEC_NCH_BLOCKS_MAP[ch_config_idx];
// These checks are performed on the LLE SPU thread
if (ch_config_idx == 0u)
{
this->config_is_set = false;
return { 0x80004005, "AtracXdecDecoder::set_config_info() failed: Invalid channel configuration: %d", ch_config_idx };
}
if (sampling_freq != 48000u && sampling_freq != 44100u) // 32kHz is not supported, even though official docs claim it is
{
this->config_is_set = false;
return { 0x80004005, "AtracXdecDecoder::set_config_info() failed: Invalid sample rate: %d", sampling_freq };
}
if (nbytes == 0u || nbytes > ATXDEC_MAX_FRAME_LENGTH)
{
this->config_is_set = false;
return { 0x80004005, "AtracXdecDecoder::set_config_info() failed: Invalid frame length: 0x%x", nbytes };
}
this->config_is_set = true;
return CELL_OK;
}
error_code AtracXdecDecoder::init_decode(u32 bw_pcm, u32 nch_out)
{
if (bw_pcm < CELL_ADEC_ATRACX_WORD_SZ_16BIT || (bw_pcm > CELL_ADEC_ATRACX_WORD_SZ_32BIT && bw_pcm != CELL_ADEC_ATRACX_WORD_SZ_FLOAT))
{
return { 0x80004005, "AtracXdecDecoder::init_decode() failed: Invalid PCM output format" };
}
this->bw_pcm = bw_pcm;
this->nch_out = nch_out; // Not checked for invalid values on LLE
this->pcm_output_size = (bw_pcm == CELL_ADEC_ATRACX_WORD_SZ_16BIT ? sizeof(s16) : sizeof(f32)) * nch_in * ATXDEC_SAMPLES_PER_FRAME;
init_avcodec();
return CELL_OK;
}
error_code AtracXdecDecoder::parse_ats_header(vm::cptr<u8> au_start_addr)
{
const auto ats = std::bit_cast<AtracXdecAtsHeader>(vm::read64(au_start_addr.addr()));
if (ats.sync_word != 0x0fd0)
{
return { CELL_ADEC_ERROR_ATX_ATSHDR, "AtracXdecDecoder::parse_ats_header() failed: Invalid sync word: 0x%x", ats.sync_word };
}
const u8 sample_rate_idx = ats.params >> 13;
const u8 ch_config_idx = ats.params >> 10 & 7;
const u16 nbytes = ((ats.params & 0x3ff) + 1) * 8;
if (ch_config_idx == 0u)
{
return { CELL_ADEC_ERROR_ATX_ATSHDR, "AtracXdecDecoder::parse_ats_header() failed: Invalid channel configuration: %d", ch_config_idx };
}
u32 sampling_freq;
switch (sample_rate_idx)
{
case 1: sampling_freq = 44100; break;
case 2: sampling_freq = 48000; break;
default: return { CELL_ADEC_ERROR_ATX_ATSHDR, "AtracXdecDecoder::parse_ats_header() failed: Invalid sample rate index: %d", sample_rate_idx };
}
return set_config_info(sampling_freq, ch_config_idx, nbytes); // Cannot return error here, values were already checked
}
void AtracXdecContext::exec(ppu_thread& ppu)
{
perf_meter<"ATXDEC"_u64> perf0;
// Savestates
if (decoder.config_is_set)
{
decoder.init_avcodec();
}
for (;;cmd_counter++)
{
cellAtracXdec.trace("Command counter: %llu, waiting for next command...", cmd_counter);
if (!skip_getting_command)
{
lv2_obj::sleep(ppu);
std::lock_guard lock{queue_mutex};
while (cmd_queue.empty() && !ppu.is_stopped())
{
lv2_obj::sleep(ppu);
queue_not_empty.wait(queue_mutex, 20000);
}
if (ppu.is_stopped())
{
ppu.state += cpu_flag::again;
return;
}
cmd_queue.pop(cmd);
if (!run_thread)
{
return;
}
}
cellAtracXdec.trace("Command type: %d", static_cast<u32>(cmd.type.get()));
switch (cmd.type)
{
case AtracXdecCmdType::start_seq:
{
first_decode = true;
skip_next_frame = true;
// Skip if access units contain an ATS header, the parameters are included in the header and we need to wait for the first decode command to parse them
if (cmd.atracx_param.au_includes_ats_hdr_flg == CELL_ADEC_ATRACX_ATS_HDR_NOTINC)
{
if (decoder.set_config_info(cmd.atracx_param.sampling_freq, cmd.atracx_param.ch_config_idx, cmd.atracx_param.nbytes) == static_cast<s32>(0x80004005))
{
break;
}
if (decoder.init_decode(cmd.atracx_param.bw_pcm, cmd.atracx_param.nch_out) == static_cast<s32>(0x80004005))
{
break;
}
}
atracx_param = cmd.atracx_param;
break;
}
case AtracXdecCmdType::end_seq:
{
skip_getting_command = true;
// Block savestate creation during callbacks
std::unique_lock savestate_lock{g_fxo->get<hle_locks_t>(), std::try_to_lock};
if (!savestate_lock.owns_lock())
{
ppu.state += cpu_flag::again;
return;
}
skip_getting_command = false;
// Doesn't do anything else
notify_seq_done.cbFunc(ppu, notify_seq_done.cbArg);
break;
}
case AtracXdecCmdType::decode_au:
{
skip_getting_command = true;
ensure(!!cmd.au_start_addr); // Not checked on LLE
cellAtracXdec.trace("Waiting for output to be consumed...");
lv2_obj::sleep(ppu);
std::unique_lock output_mutex_lock{output_mutex};
while (output_locked && !ppu.is_stopped())
{
lv2_obj::sleep(ppu);
output_consumed.wait(output_mutex, 20000);
}
if (ppu.is_stopped())
{
ppu.state += cpu_flag::again;
return;
}
if (!run_thread)
{
return;
}
cellAtracXdec.trace("Output consumed");
u32 error = CELL_OK;
// Only the first valid ATS header after starting a sequence is parsed. It is ignored on all subsequent access units
if (first_decode && atracx_param.au_includes_ats_hdr_flg == CELL_ADEC_ATRACX_ATS_HDR_INC)
{
// Block savestate creation during callbacks
std::unique_lock savestate_lock{g_fxo->get<hle_locks_t>(), std::try_to_lock};
if (!savestate_lock.owns_lock())
{
ppu.state += cpu_flag::again;
return;
}
if (error = decoder.parse_ats_header(cmd.au_start_addr); error != CELL_OK)
{
notify_error.cbFunc(ppu, error, notify_error.cbArg);
}
else if (decoder.init_decode(atracx_param.bw_pcm, atracx_param.nch_out) != CELL_OK)
{
notify_error.cbFunc(ppu, CELL_ADEC_ERROR_ATX_FATAL, notify_error.cbArg);
}
}
// LLE does not initialize the output address if parsing the ATS header fails
vm::ptr<void> output = vm::null;
u32 decoded_samples_num = 0;
if (error != CELL_ADEC_ERROR_ATX_ATSHDR)
{
// The LLE SPU thread would crash if you attempt to decode without a valid configuration
ensure(decoder.config_is_set, "Attempted to decode with invalid configuration");
output.set(work_mem.addr() + atracXdecGetSpursMemSize(decoder.nch_in));
const auto au_start_addr = atracx_param.au_includes_ats_hdr_flg == CELL_ADEC_ATRACX_ATS_HDR_INC ? cmd.au_start_addr.get_ptr() + sizeof(AtracXdecAtsHeader) : cmd.au_start_addr.get_ptr();
std::memcpy(work_mem.get_ptr(), au_start_addr, decoder.nbytes);
if (int err = avcodec_send_packet(decoder.ctx, decoder.packet); err)
{
// These errors should never occur
if (err == AVERROR(EAGAIN) || err == averror_eof || err == AVERROR(EINVAL) || err == AVERROR(ENOMEM))
{
fmt::throw_exception("avcodec_send_packet() failed (err=0x%x='%s')", err, utils::av_error_to_string(err));
}
// Game sent invalid data
cellAtracXdec.error("avcodec_send_packet() failed (err=0x%x='%s')", err, utils::av_error_to_string(err));
error = CELL_ADEC_ERROR_ATX_NON_FATAL; // Not accurate, FFmpeg doesn't provide detailed errors like LLE
av_frame_unref(decoder.frame);
}
else if ((err = avcodec_receive_frame(decoder.ctx, decoder.frame)))
{
fmt::throw_exception("avcodec_receive_frame() failed (err=0x%x='%s')", err, utils::av_error_to_string(err));
}
decoded_samples_num = decoder.frame->nb_samples;
ensure(decoded_samples_num == 0u || decoded_samples_num == ATXDEC_SAMPLES_PER_FRAME);
// The first frame after starting a new sequence or after an error is replaced with silence
if (skip_next_frame && error == CELL_OK)
{
skip_next_frame = false;
decoded_samples_num = 0;
std::memset(output.get_ptr(), 0, ATXDEC_SAMPLES_PER_FRAME * (decoder.bw_pcm & 0x7full) * decoder.nch_out);
}
// Convert FFmpeg output to LLE output
const auto output_f32 = vm::static_ptr_cast<f32>(output).get_ptr();
const auto output_s16 = vm::static_ptr_cast<s16>(output).get_ptr();
const auto output_s32 = vm::static_ptr_cast<s32>(output).get_ptr();
const u8* const ch_map = ATXDEC_AVCODEC_CH_MAP[decoder.ch_config_idx - 1];
const u32 nch_in = decoder.nch_in;
switch (decoder.bw_pcm)
{
case CELL_ADEC_ATRACX_WORD_SZ_FLOAT:
for (u32 channel_idx = 0; channel_idx < nch_in; channel_idx++)
{
const f32* samples = reinterpret_cast<f32*>(decoder.frame->data[channel_idx]);
for (u32 in_sample_idx = 0, out_sample_idx = ch_map[channel_idx]; in_sample_idx < decoded_samples_num; in_sample_idx++, out_sample_idx += nch_in)
{
const f32 sample = samples[in_sample_idx];
if (sample >= std::bit_cast<f32>(std::bit_cast<u32>(1.f) - 1))
{
output_f32[out_sample_idx] = std::bit_cast<be_t<f32>>("\x3f\x7f\xff\xff"_u32); // Prevents an unnecessary endian swap
}
else if (sample <= -1.f)
{
output_f32[out_sample_idx] = -1.f;
}
else
{
output_f32[out_sample_idx] = sample;
}
}
}
break;
case CELL_ADEC_ATRACX_WORD_SZ_16BIT:
for (u32 channel_idx = 0; channel_idx < nch_in; channel_idx++)
{
const f32* samples = reinterpret_cast<f32*>(decoder.frame->data[channel_idx]);
for (u32 in_sample_idx = 0, out_sample_idx = ch_map[channel_idx]; in_sample_idx < decoded_samples_num; in_sample_idx++, out_sample_idx += nch_in)
{
const f32 sample = samples[in_sample_idx];
if (sample >= 1.f)
{
output_s16[out_sample_idx] = INT16_MAX;
}
else if (sample <= -1.f)
{
output_s16[out_sample_idx] = INT16_MIN;
}
else
{
output_s16[out_sample_idx] = static_cast<s16>(std::floor(sample * 0x8000u));
}
}
}
break;
case CELL_ADEC_ATRACX_WORD_SZ_24BIT:
for (u32 channel_idx = 0; channel_idx < nch_in; channel_idx++)
{
const f32* samples = reinterpret_cast<f32*>(decoder.frame->data[channel_idx]);
for (u32 in_sample_idx = 0, out_sample_idx = ch_map[channel_idx]; in_sample_idx < decoded_samples_num; in_sample_idx++, out_sample_idx += nch_in)
{
const f32 sample = samples[in_sample_idx];
if (sample >= 1.f)
{
output_s32[out_sample_idx] = 0x007fffff;
}
else if (sample <= -1.f)
{
output_s32[out_sample_idx] = 0x00800000;
}
else
{
output_s32[out_sample_idx] = static_cast<s32>(std::floor(sample * 0x00800000u)) & 0x00ffffff;
}
}
}
break;
case CELL_ADEC_ATRACX_WORD_SZ_32BIT:
for (u32 channel_idx = 0; channel_idx < nch_in; channel_idx++)
{
const f32* samples = reinterpret_cast<f32*>(decoder.frame->data[channel_idx]);
for (u32 in_sample_idx = 0, out_sample_idx = ch_map[channel_idx]; in_sample_idx < decoded_samples_num; in_sample_idx++, out_sample_idx += nch_in)
{
const f32 sample = samples[in_sample_idx];
if (sample >= 1.f)
{
output_s32[out_sample_idx] = INT32_MAX;
}
else if (sample <= -1.f)
{
output_s32[out_sample_idx] = INT32_MIN;
}
else
{
output_s32[out_sample_idx] = static_cast<s32>(std::floor(sample * 0x80000000u));
}
}
}
}
first_decode = false;
if (error != CELL_OK)
{
// Block savestate creation during callbacks
std::unique_lock savestate_lock{g_fxo->get<hle_locks_t>(), std::try_to_lock};
if (!savestate_lock.owns_lock())
{
ppu.state += cpu_flag::again;
return;
}
skip_next_frame = true;
notify_error.cbFunc(ppu, error, notify_error.cbArg);
}
}
// Block savestate creation during callbacks
std::unique_lock savestate_lock{g_fxo->get<hle_locks_t>(), std::try_to_lock};
if (!savestate_lock.owns_lock())
{
ppu.state += cpu_flag::again;
return;
}
skip_getting_command = false;
// au_done and pcm_out callbacks are always called after a decode command, even if an error occurred
// The output always has to be consumed as well
notify_au_done.cbFunc(ppu, cmd.pcm_handle, notify_au_done.cbArg);
output_locked = true;
output_mutex_lock.unlock();
const u32 output_size = decoded_samples_num * (decoder.bw_pcm & 0x7fu) * decoder.nch_out;
const vm::var<CellAdecAtracXInfo> bsi_info{{ decoder.sampling_freq, decoder.ch_config_idx, decoder.nbytes }};
const AdecCorrectPtsValueType correct_pts_type = [&]
{
switch (decoder.sampling_freq)
{
case 32000u: return ADEC_CORRECT_PTS_VALUE_TYPE_ATRACX_32000Hz;
case 44100u: return ADEC_CORRECT_PTS_VALUE_TYPE_ATRACX_44100Hz;
case 48000u: return ADEC_CORRECT_PTS_VALUE_TYPE_ATRACX_48000Hz;
default: return ADEC_CORRECT_PTS_VALUE_TYPE_UNSPECIFIED;
}
}();
notify_pcm_out.cbFunc(ppu, cmd.pcm_handle, output, output_size, notify_pcm_out.cbArg, vm::make_var<vm::bcptr<void>>(bsi_info), correct_pts_type, error);
break;
}
default:
fmt::throw_exception("Invalid command");
}
}
}
template <AtracXdecCmdType type>
error_code AtracXdecContext::send_command(ppu_thread& ppu, auto&&... args)
{
ppu.state += cpu_flag::wait;
{
std::lock_guard lock{queue_mutex};
if constexpr (type == AtracXdecCmdType::close)
{
// Close command is only sent if the queue is empty on LLE
if (!cmd_queue.empty())
{
return {};
}
}
if (cmd_queue.full())
{
return CELL_ADEC_ERROR_ATX_BUSY;
}
cmd_queue.emplace(std::forward<AtracXdecCmdType>(type), std::forward<decltype(args)>(args)...);
}
queue_not_empty.notify_one();
return CELL_OK;
}
void atracXdecEntry(ppu_thread& ppu, vm::ptr<AtracXdecContext> atxdec)
{
atxdec->decoder.alloc_avcodec();
atxdec->exec(ppu);
atxdec->decoder.free_avcodec();
if (ppu.state & cpu_flag::again)
{
// For savestates, save argument
ppu.syscall_args[0] = atxdec.addr();
return;
}
ppu_execute<&sys_ppu_thread_exit>(ppu, CELL_OK);
}
template <u32 nch_in>
error_code _CellAdecCoreOpGetMemSize_atracx(vm::ptr<CellAdecAttr> attr)
{
cellAtracXdec.notice("_CellAdecCoreOpGetMemSize_atracx<nch_in=%d>(attr=*0x%x)", nch_in, attr);
ensure(!!attr); // Not checked on LLE
constexpr u32 mem_size =
sizeof(AtracXdecContext) + 0x7f
+ ATXDEC_SPURS_STRUCTS_SIZE + 0x1d8
+ atracXdecGetSpursMemSize(nch_in)
+ ATXDEC_SAMPLES_PER_FRAME * sizeof(f32) * nch_in;
attr->workMemSize = utils::align(mem_size, 0x80);
return CELL_OK;
}
error_code _CellAdecCoreOpOpenExt_atracx(ppu_thread& ppu, vm::ptr<AtracXdecContext> handle, vm::ptr<AdecNotifyAuDone> notifyAuDone, vm::ptr<void> notifyAuDoneArg, vm::ptr<AdecNotifyPcmOut> notifyPcmOut, vm::ptr<void> notifyPcmOutArg,
vm::ptr<AdecNotifyError> notifyError, vm::ptr<void> notifyErrorArg, vm::ptr<AdecNotifySeqDone> notifySeqDone, vm::ptr<void> notifySeqDoneArg, vm::cptr<CellAdecResource> res, vm::cptr<CellAdecResourceSpurs> spursRes)
{
std::unique_lock savestate_lock{g_fxo->get<hle_locks_t>(), std::try_to_lock};
if (!savestate_lock.owns_lock())
{
ppu.state += cpu_flag::again;
return {};
}
cellAtracXdec.notice("_CellAdecCoreOpOpenExt_atracx(handle=*0x%x, notifyAuDone=*0x%x, notifyAuDoneArg=*0x%x, notifyPcmOut=*0x%x, notifyPcmOutArg=*0x%x, notifyError=*0x%x, notifyErrorArg=*0x%x, notifySeqDone=*0x%x, notifySeqDoneArg=*0x%x, res=*0x%x, spursRes=*0x%x)",
handle, notifyAuDone, notifyAuDoneArg, notifyPcmOut, notifyPcmOutArg, notifyError, notifyErrorArg, notifySeqDone, notifySeqDoneArg, res, spursRes);
ensure(!!handle && !!res); // Not checked on LLE
ensure(handle.aligned(0x80)); // On LLE, this functions doesn't check the alignment or aligns the address itself. The address should already be aligned to 128 bytes by cellAdec
ensure(!!notifyAuDone && !!notifyAuDoneArg && !!notifyPcmOut && !!notifyPcmOutArg && !!notifyError && !!notifyErrorArg && !!notifySeqDone && !!notifySeqDoneArg); // These should always be set by cellAdec
write_to_ptr(handle.get_ptr(), AtracXdecContext(notifyAuDone, notifyAuDoneArg, notifyPcmOut, notifyPcmOutArg, notifyError, notifyErrorArg, notifySeqDone, notifySeqDoneArg,
vm::bptr<u8>::make(handle.addr() + utils::align(static_cast<u32>(sizeof(AtracXdecContext)), 0x80) + ATXDEC_SPURS_STRUCTS_SIZE)));
const vm::var<char[]> _name = vm::make_str("HLE ATRAC3plus decoder");
const auto entry = g_fxo->get<ppu_function_manager>().func_addr(FIND_FUNC(atracXdecEntry));
ppu_execute<&sys_ppu_thread_create>(ppu, handle.ptr(&AtracXdecContext::thread_id), entry, handle.addr(), +res->ppuThreadPriority, +res->ppuThreadStackSize, SYS_PPU_THREAD_CREATE_JOINABLE, +_name);
return CELL_OK;
}
error_code _CellAdecCoreOpOpen_atracx(ppu_thread& ppu, vm::ptr<AtracXdecContext> handle, vm::ptr<AdecNotifyAuDone> notifyAuDone, vm::ptr<void> notifyAuDoneArg, vm::ptr<AdecNotifyPcmOut> notifyPcmOut, vm::ptr<void> notifyPcmOutArg,
vm::ptr<AdecNotifyError> notifyError, vm::ptr<void> notifyErrorArg, vm::ptr<AdecNotifySeqDone> notifySeqDone, vm::ptr<void> notifySeqDoneArg, vm::cptr<CellAdecResource> res)
{
cellAtracXdec.notice("_CellAdecCoreOpOpen_atracx(handle=*0x%x, notifyAuDone=*0x%x, notifyAuDoneArg=*0x%x, notifyPcmOut=*0x%x, notifyPcmOutArg=*0x%x, notifyError=*0x%x, notifyErrorArg=*0x%x, notifySeqDone=*0x%x, notifySeqDoneArg=*0x%x, res=*0x%x)",
handle, notifyAuDone, notifyAuDoneArg, notifyPcmOut, notifyPcmOutArg, notifyError, notifyErrorArg, notifySeqDone, notifySeqDoneArg, res);
return _CellAdecCoreOpOpenExt_atracx(ppu, handle, notifyAuDone, notifyAuDoneArg, notifyPcmOut, notifyPcmOutArg, notifyError, notifyErrorArg, notifySeqDone, notifySeqDoneArg, res, vm::null);
}
error_code _CellAdecCoreOpClose_atracx(ppu_thread& ppu, vm::ptr<AtracXdecContext> handle)
{
std::unique_lock savestate_lock{g_fxo->get<hle_locks_t>(), std::try_to_lock};
if (!savestate_lock.owns_lock())
{
ppu.state += cpu_flag::again;
return {};
}
ppu.state += cpu_flag::wait;
cellAtracXdec.notice("_CellAdecCoreOpClose_atracx(handle=*0x%x)", handle);
ensure(!!handle); // Not checked on LLE
handle->run_thread = false;
handle->send_command<AtracXdecCmdType::close>(ppu);
{
std::lock_guard lock{handle->output_mutex};
handle->output_locked = false;
}
handle->output_consumed.notify_one();
if (vm::var<u64> ret; sys_ppu_thread_join(ppu, static_cast<u32>(handle->thread_id), +ret) != CELL_OK)
{
// Other thread already closed the decoder
return CELL_ADEC_ERROR_FATAL;
}
return CELL_OK;
}
error_code _CellAdecCoreOpStartSeq_atracx(ppu_thread& ppu, vm::ptr<AtracXdecContext> handle, vm::cptr<CellAdecParamAtracX> atracxParam)
{
cellAtracXdec.notice("_CellAdecCoreOpStartSeq_atracx(handle=*0x%x, atracxParam=*0x%x)", handle, atracxParam);
ensure(!!handle && !!atracxParam); // Not checked on LLE
cellAtracXdec.notice("_CellAdecCoreOpStartSeq_atracx(): sampling_freq=%d, ch_config_idx=%d, nch_out=%d, nbytes=0x%x, extra_config_data=0x%08x, bw_pcm=0x%x, downmix_flag=%d, au_includes_ats_hdr_flg=%d",
atracxParam->sampling_freq, atracxParam->ch_config_idx, atracxParam->nch_out, atracxParam->nbytes, std::bit_cast<u32>(atracxParam->extra_config_data), atracxParam->bw_pcm, atracxParam->downmix_flag, atracxParam->au_includes_ats_hdr_flg);
return handle->send_command<AtracXdecCmdType::start_seq>(ppu, *atracxParam);
}
error_code _CellAdecCoreOpEndSeq_atracx(ppu_thread& ppu, vm::ptr<AtracXdecContext> handle)
{
cellAtracXdec.notice("_CellAdecCoreOpEndSeq_atracx(handle=*0x%x)", handle);
ensure(!!handle); // Not checked on LLE
return handle->send_command<AtracXdecCmdType::end_seq>(ppu);
}
error_code _CellAdecCoreOpDecodeAu_atracx(ppu_thread& ppu, vm::ptr<AtracXdecContext> handle, s32 pcmHandle, vm::cptr<CellAdecAuInfo> auInfo)
{
cellAtracXdec.trace("_CellAdecCoreOpDecodeAu_atracx(handle=*0x%x, pcmHandle=%d, auInfo=*0x%x)", handle, pcmHandle, auInfo);
ensure(!!handle && !!auInfo); // Not checked on LLE
cellAtracXdec.trace("_CellAdecCoreOpDecodeAu_atracx(): startAddr=*0x%x, size=0x%x, pts=%lld, userData=0x%llx", auInfo->startAddr, auInfo->size, std::bit_cast<be_t<u64>>(auInfo->pts), auInfo->userData);
return handle->send_command<AtracXdecCmdType::decode_au>(ppu, pcmHandle, *auInfo);
}
void _CellAdecCoreOpGetVersion_atracx(vm::ptr<be_t<u32, 1>> version)
{
cellAtracXdec.notice("_CellAdecCoreOpGetVersion_atracx(version=*0x%x)", version);
ensure(!!version); // Not checked on LLE
*version = 0x01020000;
}
error_code _CellAdecCoreOpRealign_atracx(vm::ptr<AtracXdecContext> handle, vm::ptr<void> outBuffer, vm::cptr<void> pcmStartAddr)
{
cellAtracXdec.trace("_CellAdecCoreOpRealign_atracx(handle=*0x%x, outBuffer=*0x%x, pcmStartAddr=*0x%x)", handle, outBuffer, pcmStartAddr);
if (outBuffer)
{
ensure(!!handle && !!pcmStartAddr); // Not checked on LLE
ensure(vm::check_addr(outBuffer.addr(), vm::page_info_t::page_writable, handle->decoder.pcm_output_size));
std::memcpy(outBuffer.get_ptr(), pcmStartAddr.get_ptr(), handle->decoder.pcm_output_size);
}
return CELL_OK;
}
error_code _CellAdecCoreOpReleasePcm_atracx(ppu_thread& ppu, vm::ptr<AtracXdecContext> handle, s32 pcmHandle, vm::cptr<void> outBuffer)
{
ppu.state += cpu_flag::wait;
cellAtracXdec.trace("_CellAdecCoreOpReleasePcm_atracx(handle=*0x%x, pcmHandle=%d, outBuffer=*0x%x)", handle, pcmHandle, outBuffer);
ensure(!!handle); // Not checked on LLE
std::lock_guard lock{handle->output_mutex};
handle->output_locked = false;
handle->output_consumed.notify_one();
return CELL_OK;
}
s32 _CellAdecCoreOpGetPcmHandleNum_atracx()
{
cellAtracXdec.notice("_CellAdecCoreOpGetPcmHandleNum_atracx()");
return 3;
}
u32 _CellAdecCoreOpGetBsiInfoSize_atracx()
{
cellAtracXdec.notice("_CellAdecCoreOpGetBsiInfoSize_atracx()");
return sizeof(CellAdecAtracXInfo);
}
static void init_gvar(vm::gvar<CellAdecCoreOps>& var)
{
var->open.set(g_fxo->get<ppu_function_manager>().func_addr(FIND_FUNC(_CellAdecCoreOpOpen_atracx)));
var->close.set(g_fxo->get<ppu_function_manager>().func_addr(FIND_FUNC(_CellAdecCoreOpClose_atracx)));
var->startSeq.set(g_fxo->get<ppu_function_manager>().func_addr(FIND_FUNC(_CellAdecCoreOpStartSeq_atracx)));
var->endSeq.set(g_fxo->get<ppu_function_manager>().func_addr(FIND_FUNC(_CellAdecCoreOpEndSeq_atracx)));
var->decodeAu.set(g_fxo->get<ppu_function_manager>().func_addr(FIND_FUNC(_CellAdecCoreOpDecodeAu_atracx)));
var->getVersion.set(g_fxo->get<ppu_function_manager>().func_addr(FIND_FUNC(_CellAdecCoreOpGetVersion_atracx)));
var->realign.set(g_fxo->get<ppu_function_manager>().func_addr(FIND_FUNC(_CellAdecCoreOpRealign_atracx)));
var->releasePcm.set(g_fxo->get<ppu_function_manager>().func_addr(FIND_FUNC(_CellAdecCoreOpReleasePcm_atracx)));
var->getPcmHandleNum.set(g_fxo->get<ppu_function_manager>().func_addr(FIND_FUNC(_CellAdecCoreOpGetPcmHandleNum_atracx)));
var->getBsiInfoSize.set(g_fxo->get<ppu_function_manager>().func_addr(FIND_FUNC(_CellAdecCoreOpGetBsiInfoSize_atracx)));
var->openExt.set(g_fxo->get<ppu_function_manager>().func_addr(FIND_FUNC(_CellAdecCoreOpOpenExt_atracx)));
}
DECLARE(ppu_module_manager::cellAtracXdec)("cellAtracXdec", []()
{
REG_VNID(cellAtracXdec, 0x076b33ab, g_cell_adec_core_ops_atracx2ch).init = []()
{
g_cell_adec_core_ops_atracx2ch->getMemSize.set(g_fxo->get<ppu_function_manager>().func_addr(FIND_FUNC(_CellAdecCoreOpGetMemSize_atracx<2>)));
init_gvar(g_cell_adec_core_ops_atracx2ch);
};
REG_VNID(cellAtracXdec, 0x1d210eaa, g_cell_adec_core_ops_atracx6ch).init = []()
{
g_cell_adec_core_ops_atracx6ch->getMemSize.set(g_fxo->get<ppu_function_manager>().func_addr(FIND_FUNC(_CellAdecCoreOpGetMemSize_atracx<6>)));
init_gvar(g_cell_adec_core_ops_atracx6ch);
};
REG_VNID(cellAtracXdec, 0xe9a86e54, g_cell_adec_core_ops_atracx8ch).init = []()
{
g_cell_adec_core_ops_atracx8ch->getMemSize.set(g_fxo->get<ppu_function_manager>().func_addr(FIND_FUNC(_CellAdecCoreOpGetMemSize_atracx<8>)));
init_gvar(g_cell_adec_core_ops_atracx8ch);
};
REG_VNID(cellAtracXdec, 0x4944af9a, g_cell_adec_core_ops_atracx).init = []()
{
g_cell_adec_core_ops_atracx->getMemSize.set(g_fxo->get<ppu_function_manager>().func_addr(FIND_FUNC(_CellAdecCoreOpGetMemSize_atracx<8>)));
init_gvar(g_cell_adec_core_ops_atracx);
};
REG_HIDDEN_FUNC(_CellAdecCoreOpGetMemSize_atracx<2>);
REG_HIDDEN_FUNC(_CellAdecCoreOpGetMemSize_atracx<6>);
REG_HIDDEN_FUNC(_CellAdecCoreOpGetMemSize_atracx<8>);
REG_HIDDEN_FUNC(_CellAdecCoreOpOpen_atracx);
REG_HIDDEN_FUNC(_CellAdecCoreOpClose_atracx);
REG_HIDDEN_FUNC(_CellAdecCoreOpStartSeq_atracx);
REG_HIDDEN_FUNC(_CellAdecCoreOpEndSeq_atracx);
REG_HIDDEN_FUNC(_CellAdecCoreOpDecodeAu_atracx);
REG_HIDDEN_FUNC(_CellAdecCoreOpGetVersion_atracx);
REG_HIDDEN_FUNC(_CellAdecCoreOpRealign_atracx);
REG_HIDDEN_FUNC(_CellAdecCoreOpReleasePcm_atracx);
REG_HIDDEN_FUNC(_CellAdecCoreOpGetPcmHandleNum_atracx);
REG_HIDDEN_FUNC(_CellAdecCoreOpGetBsiInfoSize_atracx);
REG_HIDDEN_FUNC(_CellAdecCoreOpOpenExt_atracx);
REG_HIDDEN_FUNC(atracXdecEntry);
});
+302
View File
@@ -0,0 +1,302 @@
#pragma once
#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"
#endif
extern "C"
{
#include "libavcodec/avcodec.h"
}
constexpr int averror_eof = AVERROR_EOF; // Workaround for old-style-cast error
#ifdef _MSC_VER
#pragma warning(pop)
#else
#pragma GCC diagnostic pop
#endif
#include "Utilities/cond.h"
#include "cellPamf.h"
#include "cellAdec.h"
enum CellAtracXdecError : u32
{
CELL_ADEC_ERROR_ATX_OFFSET = 0x80612200,
CELL_ADEC_ERROR_ATX_NONE = 0x80612200,
CELL_ADEC_ERROR_ATX_OK = 0x80612200,
CELL_ADEC_ERROR_ATX_BUSY = 0x80612264,
CELL_ADEC_ERROR_ATX_EMPTY = 0x80612265,
CELL_ADEC_ERROR_ATX_ATSHDR = 0x80612266,
CELL_ADEC_ERROR_ATX_NON_FATAL = 0x80612281,
CELL_ADEC_ERROR_ATX_NOT_IMPLE = 0x80612282,
CELL_ADEC_ERROR_ATX_PACK_CE_OVERFLOW = 0x80612283,
CELL_ADEC_ERROR_ATX_ILLEGAL_NPROCQUS = 0x80612284,
CELL_ADEC_ERROR_ATX_FATAL = 0x8061228c,
CELL_ADEC_ERROR_ATX_ENC_OVERFLOW = 0x8061228d,
CELL_ADEC_ERROR_ATX_PACK_CE_UNDERFLOW = 0x8061228e,
CELL_ADEC_ERROR_ATX_SYNTAX_IDCT = 0x8061228f,
CELL_ADEC_ERROR_ATX_SYNTAX_GAINADJ = 0x80612290,
CELL_ADEC_ERROR_ATX_SYNTAX_IDSF = 0x80612291,
CELL_ADEC_ERROR_ATX_SYNTAX_SPECTRA = 0x80612292,
CELL_ADEC_ERROR_ATX_SYNTAX_IDWL = 0x80612293,
CELL_ADEC_ERROR_ATX_SYNTAX_GHWAVE = 0x80612294,
CELL_ADEC_ERROR_ATX_SYNTAX_SHEADER = 0x80612295,
CELL_ADEC_ERROR_ATX_SYNTAX_IDWL_A = 0x80612296,
CELL_ADEC_ERROR_ATX_SYNTAX_IDWL_B = 0x80612297,
CELL_ADEC_ERROR_ATX_SYNTAX_IDWL_C = 0x80612298,
CELL_ADEC_ERROR_ATX_SYNTAX_IDWL_D = 0x80612299,
CELL_ADEC_ERROR_ATX_SYNTAX_IDWL_E = 0x8061229a,
CELL_ADEC_ERROR_ATX_SYNTAX_IDSF_A = 0x8061229b,
CELL_ADEC_ERROR_ATX_SYNTAX_IDSF_B = 0x8061229c,
CELL_ADEC_ERROR_ATX_SYNTAX_IDSF_C = 0x8061229d,
CELL_ADEC_ERROR_ATX_SYNTAX_IDSF_D = 0x8061229e,
CELL_ADEC_ERROR_ATX_SYNTAX_IDCT_A = 0x8061229f,
CELL_ADEC_ERROR_ATX_SYNTAX_GC_NGC = 0x806122a0,
CELL_ADEC_ERROR_ATX_SYNTAX_GC_IDLEV_A = 0x806122a1,
CELL_ADEC_ERROR_ATX_SYNTAX_GC_IDLOC_A = 0x806122a2,
CELL_ADEC_ERROR_ATX_SYNTAX_GC_IDLEV_B = 0x806122a3,
CELL_ADEC_ERROR_ATX_SYNTAX_GC_IDLOC_B = 0x806122a4,
CELL_ADEC_ERROR_ATX_SYNTAX_SN_NWVS = 0x806122a5,
CELL_ADEC_ERROR_ATX_FATAL_HANDLE = 0x806122aa,
CELL_ADEC_ERROR_ATX_ASSERT_SAMPLING_FREQ = 0x806122ab,
CELL_ADEC_ERROR_ATX_ASSERT_CH_CONFIG_INDEX = 0x806122ac,
CELL_ADEC_ERROR_ATX_ASSERT_NBYTES = 0x806122ad,
CELL_ADEC_ERROR_ATX_ASSERT_BLOCK_NUM = 0x806122ae,
CELL_ADEC_ERROR_ATX_ASSERT_BLOCK_ID = 0x806122af,
CELL_ADEC_ERROR_ATX_ASSERT_CHANNELS = 0x806122b0,
CELL_ADEC_ERROR_ATX_UNINIT_BLOCK_SPECIFIED = 0x806122b1,
CELL_ADEC_ERROR_ATX_POSCFG_PRESENT = 0x806122b2,
CELL_ADEC_ERROR_ATX_BUFFER_OVERFLOW = 0x806122b3,
CELL_ADEC_ERROR_ATX_ILL_BLK_TYPE_ID = 0x806122b4,
CELL_ADEC_ERROR_ATX_UNPACK_CHANNEL_BLK_FAILED = 0x806122b5,
CELL_ADEC_ERROR_ATX_ILL_BLK_ID_USED_1 = 0x806122b6,
CELL_ADEC_ERROR_ATX_ILL_BLK_ID_USED_2 = 0x806122b7,
CELL_ADEC_ERROR_ATX_ILLEGAL_ENC_SETTING = 0x806122b8,
CELL_ADEC_ERROR_ATX_ILLEGAL_DEC_SETTING = 0x806122b9,
CELL_ADEC_ERROR_ATX_ASSERT_NSAMPLES = 0x806122ba,
CELL_ADEC_ERROR_ATX_ILL_SYNCWORD = 0x806122bb,
CELL_ADEC_ERROR_ATX_ILL_SAMPLING_FREQ = 0x806122bc,
CELL_ADEC_ERROR_ATX_ILL_CH_CONFIG_INDEX = 0x806122bd,
CELL_ADEC_ERROR_ATX_RAW_DATA_FRAME_SIZE_OVER = 0x806122be,
CELL_ADEC_ERROR_ATX_SYNTAX_ENHANCE_LENGTH_OVER = 0x806122bf,
CELL_ADEC_ERROR_ATX_SPU_INTERNAL_FAIL = 0x806122c8,
};
enum : u32
{
CELL_ADEC_ATRACX_WORD_SZ_16BIT = 0x02,
CELL_ADEC_ATRACX_WORD_SZ_24BIT = 0x03,
CELL_ADEC_ATRACX_WORD_SZ_32BIT = 0x04,
CELL_ADEC_ATRACX_WORD_SZ_FLOAT = 0x84,
};
enum : u8
{
CELL_ADEC_ATRACX_ATS_HDR_NOTINC = 0,
CELL_ADEC_ATRACX_ATS_HDR_INC = 1,
};
enum : u8
{
ATRACX_DOWNMIX_OFF = 0,
ATRACX_DOWNMIX_ON = 1,
};
struct CellAdecParamAtracX
{
be_t<u32> sampling_freq;
be_t<u32> ch_config_idx;
be_t<u32> nch_out;
be_t<u32> nbytes;
std::array<u8, 4> extra_config_data;
be_t<u32> bw_pcm;
u8 downmix_flag;
u8 au_includes_ats_hdr_flg;
};
struct CellAdecAtracXInfo
{
be_t<u32> samplingFreq;
be_t<u32> channelConfigIndex;
be_t<u32> nbytes;
};
CHECK_SIZE(CellAdecAtracXInfo, 12);
struct AtracXdecAtsHeader
{
be_t<u16> sync_word; // 0x0fd0
be_t<u16> params; // 3 bits: sample rate, 3 bits: channel config, 10 bits: (nbytes / 8) - 1
u8 extra_config_data[4];
};
CHECK_SIZE(AtracXdecAtsHeader, 8);
enum class AtracXdecCmdType : u32
{
invalid,
start_seq,
decode_au,
end_seq,
close,
};
struct AtracXdecCmd
{
be_t<AtracXdecCmdType> type;
be_t<s32> pcm_handle;
vm::bcptr<u8> au_start_addr;
be_t<u32> au_size;
vm::bptr<void> pcm_start_addr; // Unused
be_t<u32> pcm_size; // Unused
CellAdecParamAtracX atracx_param;
AtracXdecCmd() = default; // cellAdecOpen()
AtracXdecCmd(AtracXdecCmdType&& type) // cellAdecEndSeq(), cellAdecClose()
: type(type)
{
}
AtracXdecCmd(AtracXdecCmdType&& type, const CellAdecParamAtracX& atracx_param) // cellAdecStartSeq()
: type(type), atracx_param(atracx_param)
{
}
AtracXdecCmd(AtracXdecCmdType&& type, const s32& pcm_handle, const CellAdecAuInfo& au_info) // cellAdecDecodeAu()
: type(type), pcm_handle(pcm_handle), au_start_addr(au_info.startAddr), au_size(au_info.size)
{
}
};
CHECK_SIZE(AtracXdecCmd, 0x34);
struct AtracXdecDecoder
{
be_t<u32> sampling_freq;
be_t<u32> ch_config_idx;
be_t<u32> nch_in;
be_t<u32> nch_blocks;
be_t<u32> nbytes;
be_t<u32> nch_out;
be_t<u32> bw_pcm;
be_t<u32> nbytes_128_aligned;
be_t<u32> status;
be_t<u32> pcm_output_size;
const vm::bptr<u8> work_mem;
// HLE exclusive
b8 config_is_set = false; // For savestates
const AVCodec* codec;
AVCodecContext* ctx;
AVPacket* packet;
AVFrame* frame;
u8 spurs_stuff[84]; // 120 bytes on LLE, pointers to CellSpurs, CellSpursTaskset, etc.
be_t<u32> spurs_task_id; // CellSpursTaskId
AtracXdecDecoder(vm::ptr<u8> work_mem) : work_mem(work_mem) {}
void alloc_avcodec();
void free_avcodec();
void init_avcodec();
error_code set_config_info(u32 sampling_freq, u32 ch_config_idx, u32 nbytes);
error_code init_decode(u32 bw_pcm, u32 nch_out);
error_code parse_ats_header(vm::cptr<u8> au_start_addr);
};
CHECK_SIZE(AtracXdecDecoder, 0xa8);
struct AtracXdecContext
{
be_t<u64> thread_id; // sys_ppu_thread_t
shared_mutex queue_mutex; // sys_mutex_t
cond_variable queue_not_empty; // sys_cond_t
AdecCmdQueue<AtracXdecCmd> cmd_queue;
shared_mutex output_mutex; // sys_mutex_t
cond_variable output_consumed; // sys_cond_t
be_t<u32> output_locked = false;
be_t<u32> run_thread_mutex; // sys_mutex_t
be_t<u32> run_thread_cond; // sys_cond_t
be_t<u32> run_thread = true;
const AdecCb<AdecNotifyAuDone> notify_au_done;
const AdecCb<AdecNotifyPcmOut> notify_pcm_out;
const AdecCb<AdecNotifyError> notify_error;
const AdecCb<AdecNotifySeqDone> notify_seq_done;
const vm::bptr<u8> work_mem;
// HLE exclusive
u64 cmd_counter = 0; // For debugging
AtracXdecCmd cmd; // For savestates; if savestate was created while processing a decode command, we need to save the current command
b8 skip_getting_command = false; // For savestates; skips getting a new command from the queue
b8 skip_next_frame; // Needed to emulate behavior of LLE SPU program, it doesn't output the first frame after a sequence reset or error
u8 spurs_stuff[58]; // 120 bytes on LLE, pointers to CellSpurs, CellSpursTaskset, etc.
CellAdecParamAtracX atracx_param;
u8 reserved;
b8 first_decode;
AtracXdecDecoder decoder;
AtracXdecContext(vm::ptr<AdecNotifyAuDone> notifyAuDone, vm::ptr<void> notifyAuDoneArg, vm::ptr<AdecNotifyPcmOut> notifyPcmOut, vm::ptr<void> notifyPcmOutArg,
vm::ptr<AdecNotifyError> notifyError, vm::ptr<void> notifyErrorArg, vm::ptr<AdecNotifySeqDone> notifySeqDone, vm::ptr<void> notifySeqDoneArg, vm::bptr<u8> work_mem)
: notify_au_done{ notifyAuDone, notifyAuDoneArg }
, notify_pcm_out{ notifyPcmOut, notifyPcmOutArg }
, notify_error{ notifyError, notifyErrorArg }
, notify_seq_done{ notifySeqDone, notifySeqDoneArg }
, work_mem(work_mem)
, decoder(work_mem)
{
}
void exec(ppu_thread& ppu);
template <AtracXdecCmdType type>
error_code send_command(ppu_thread& ppu, auto&&... args);
};
static_assert(std::is_standard_layout_v<AtracXdecContext>);
CHECK_SIZE_ALIGN(AtracXdecContext, 0x268, 8);
constexpr u32 ATXDEC_SPURS_STRUCTS_SIZE = 0x1cf00; // CellSpurs, CellSpursTaskset, context, etc.
constexpr u16 ATXDEC_SAMPLES_PER_FRAME = 0x800;
constexpr u16 ATXDEC_MAX_FRAME_LENGTH = 0x2000;
constexpr std::array<u8, 8> ATXDEC_NCH_BLOCKS_MAP = { 0, 1, 1, 2, 3, 4, 5, 5 };
// Expected output channel order
// - for 1 to 7 channels: Front Left, Center, Front Right, Rear Left, Rear Right, Rear Center, LFE
// - for 8 channels: Front Left, Front Right, Center, LFE, Rear Left, Rear Right, Side Left, Side Right
// FFmpeg output
// - ver <= 5.1.2: Front Left, Front Right, Center, Rear Left, Rear Right, Rear Center, Side Left, Side Right, LFE
// - ver >= 5.1.3: Front Left, Front Right, Center, LFE, Rear Left, Rear Right, Rear Center, Side Left, Side Right
constexpr u8 ATXDEC_AVCODEC_CH_MAP[7][8] =
{
{ 0 },
{ 0, 1 },
{ 0, 2, 1 },
{ 0, 2, 1, 3 },
#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(59, 51, 101)
{ 0, 2, 1, 3, 4, 5 },
{ 0, 2, 1, 3, 4, 5, 6 },
{ 0, 1, 2, 4, 5, 6, 7, 3 }
#else
{ 0, 2, 1, 4, 5, 3 },
{ 0, 2, 1, 4, 5, 6, 3 },
{ 0, 1, 2, 3, 4, 5, 6, 7 }
#endif
};
+2 -2
View File
@@ -813,7 +813,7 @@ void cell_audio_thread::operator()()
if (time_left > cfg.period_comparison_margin)
{
thread_ctrl::wait_for(get_thread_wait_delay(time_left));
thread_ctrl::wait_for(time_left - cfg.period_comparison_margin);
continue;
}
}
@@ -886,7 +886,7 @@ void cell_audio_thread::operator()()
const s64 time_left = m_dynamic_period - time_since_last_period;
if (time_left > cfg.period_comparison_margin)
{
thread_ctrl::wait_for(get_thread_wait_delay(time_left));
thread_ctrl::wait_for(time_left - cfg.period_comparison_margin);
continue;
}
+6 -6
View File
@@ -251,7 +251,12 @@ struct cell_audio_config
static constexpr f32 period_average_alpha = 0.02f; // alpha factor for the m_average_period rolling average
static constexpr s64 period_comparison_margin = 250; // when comparing the current period time with the desired period, if it is below this number of usecs we do not wait any longer
// when comparing the current period time with the desired period, if it is below this number of usecs we do not wait any longer(quantum dependent)
#ifdef _WIN32
static constexpr s64 period_comparison_margin = 250;
#else
static constexpr s64 period_comparison_margin = 5;
#endif
u64 fully_untouched_timeout = 0; // timeout if the game has not touched any audio buffer yet
u64 partially_untouched_timeout = 0; // timeout if the game has not touched all audio buffers yet
@@ -373,11 +378,6 @@ private:
void mix(float* out_buffer, s32 offset = 0);
void finish_port_volume_stepping();
constexpr static u64 get_thread_wait_delay(u64 time_left)
{
return (time_left > 350) ? time_left - 250 : 100;
}
void update_config(bool backend_changed);
void reset_counters();
@@ -72,7 +72,7 @@ struct cross_controller
msg_dialog_callback.set(g_fxo->get<ppu_function_manager>().func_addr(FIND_FUNC(finish_callback)));
// TODO: Show icons from comboplay_plugin.rco in dialog. Maybe use a new dialog or add an optional icon to this one.
error_code res = open_msg_dialog(false, CELL_MSGDIALOG_TYPE_DISABLE_CANCEL_OFF, vm::make_str(msg), msg_dialog_callback, userdata);
error_code res = open_msg_dialog(false, CELL_MSGDIALOG_TYPE_DISABLE_CANCEL_OFF, vm::make_str(msg), msg_dialog_source::_cellCrossController, msg_dialog_callback, userdata);
sysutil_register_cb([this, res](ppu_thread& ppu) -> s32
{
+5 -5
View File
@@ -579,7 +579,7 @@ error_code cellHddGameCheck(ppu_thread& ppu, u32 version, vm::cptr<char> dirName
lv2_obj::sleep(ppu);
// Get user confirmation by opening a blocking dialog
error_code res = open_msg_dialog(true, CELL_MSGDIALOG_TYPE_SE_TYPE_ERROR | CELL_MSGDIALOG_TYPE_BUTTON_TYPE_OK | CELL_MSGDIALOG_TYPE_DISABLE_CANCEL_ON, vm::make_str(error_msg));
error_code res = open_msg_dialog(true, CELL_MSGDIALOG_TYPE_SE_TYPE_ERROR | CELL_MSGDIALOG_TYPE_BUTTON_TYPE_OK | CELL_MSGDIALOG_TYPE_DISABLE_CANCEL_ON, vm::make_str(error_msg), msg_dialog_source::_cellGame);
// Reschedule after a blocking dialog returns
if (ppu.check_state())
@@ -664,7 +664,7 @@ error_code cellHddGameSetSystemVer(vm::cptr<char> systemVersion)
error_code cellHddGameExitBroken()
{
cellGame.warning("cellHddGameExitBroken()");
return open_exit_dialog(get_localized_string(localized_string_id::CELL_HDD_GAME_EXIT_BROKEN), true);
return open_exit_dialog(get_localized_string(localized_string_id::CELL_HDD_GAME_EXIT_BROKEN), true, msg_dialog_source::_cellGame);
}
error_code cellGameDataGetSizeKB(ppu_thread& ppu, vm::ptr<u32> size)
@@ -723,7 +723,7 @@ error_code cellGameDataSetSystemVer(vm::cptr<char> systemVersion)
error_code cellGameDataExitBroken()
{
cellGame.warning("cellGameDataExitBroken()");
return open_exit_dialog(get_localized_string(localized_string_id::CELL_GAME_DATA_EXIT_BROKEN), true);
return open_exit_dialog(get_localized_string(localized_string_id::CELL_GAME_DATA_EXIT_BROKEN), true, msg_dialog_source::_cellGame);
}
error_code cellGameBootCheck(vm::ptr<u32> type, vm::ptr<u32> attributes, vm::ptr<CellGameContentSize> size, vm::ptr<char[CELL_GAME_DIRNAME_SIZE]> dirName)
@@ -1198,7 +1198,7 @@ error_code cellGameDataCheckCreate2(ppu_thread& ppu, u32 version, vm::cptr<char>
lv2_obj::sleep(ppu);
// Get user confirmation by opening a blocking dialog
error_code res = open_msg_dialog(true, CELL_MSGDIALOG_TYPE_SE_TYPE_ERROR | CELL_MSGDIALOG_TYPE_BUTTON_TYPE_OK | CELL_MSGDIALOG_TYPE_DISABLE_CANCEL_ON, vm::make_str(error_msg));
error_code res = open_msg_dialog(true, CELL_MSGDIALOG_TYPE_SE_TYPE_ERROR | CELL_MSGDIALOG_TYPE_BUTTON_TYPE_OK | CELL_MSGDIALOG_TYPE_DISABLE_CANCEL_ON, vm::make_str(error_msg), msg_dialog_source::_cellGame);
// Reschedule after a blocking dialog returns
if (ppu.check_state())
@@ -1714,7 +1714,7 @@ error_code cellGameContentErrorDialog(s32 type, s32 errNeedSizeKB, vm::cptr<char
error_msg += get_localized_string(localized_string_id::CELL_GAME_ERROR_DIR_NAME, fmt::format("%s", dirName).c_str());
}
return open_exit_dialog(error_msg, type > CELL_GAME_ERRDIALOG_NOSPACE);
return open_exit_dialog(error_msg, type > CELL_GAME_ERRDIALOG_NOSPACE, msg_dialog_source::_cellGame);
}
error_code cellGameThemeInstall(vm::cptr<char> usrdirPath, vm::cptr<char> fileName, u32 option)
+34 -1
View File
@@ -258,6 +258,29 @@ inline void microphone_device::variable_byteswap(const void* src, void* dst)
}
}
inline u32 microphone_device::convert_16_bit_pcm_to_float(const std::vector<u8>& buffer, u32 num_bytes)
{
static_assert((float_buf_size % sizeof(f32)) == 0);
float_buf.resize(float_buf_size, 0);
const u32 bytes_to_write = static_cast<u32>(num_bytes * (sizeof(f32) / sizeof(s16)));
ensure(bytes_to_write <= float_buf.size());
const be_t<s16>* src = utils::bless<const be_t<s16>>(buffer.data());
be_t<f32>* dst = reinterpret_cast<be_t<f32>*>(float_buf.data());
for (usz i = 0; i < num_bytes / sizeof(s16); i++)
{
const be_t<s16> sample = *src++;
const be_t<f32> normalized_sample_be = std::clamp(static_cast<f32>(sample) / std::numeric_limits<s16>::max(), -1.0f, 1.0f);
*dst++ = normalized_sample_be;
}
return bytes_to_write;
}
// Public functions
microphone_device::microphone_device(microphone_handler type)
@@ -696,7 +719,17 @@ void microphone_device::get_dsp(const u32 num_samples)
const u32 bufsize = num_samples * sample_size;
ensure(bufsize <= buf.size());
rbuf_dsp.write_bytes(buf.data(), bufsize);
if (attr_dsptype != 0x01)
{
// Convert 16-bit PCM audio data to 32-bit float (DSP format)
const u32 bufsize_float = convert_16_bit_pcm_to_float(buf, bufsize);
rbuf_dsp.write_bytes(float_buf.data(), bufsize_float);
}
else
{
// The same as device RAW stream format, except that the data byte is always big-endian
rbuf_dsp.write_bytes(buf.data(), bufsize);
}
}
/// Initialization/Shutdown Functions
+4 -1
View File
@@ -323,6 +323,7 @@ public:
private:
template <u32 bytesize>
static inline void variable_byteswap(const void* src, void* dst);
inline u32 convert_16_bit_pcm_to_float(const std::vector<u8>& buffer, u32 num_bytes);
u32 capture_audio();
@@ -345,6 +346,7 @@ private:
std::vector<mic_device> devices;
std::vector<u8> temp_buf;
std::vector<u8> float_buf;
// Sampling information provided at opening of mic
u32 raw_samplingrate = 48000;
@@ -358,9 +360,10 @@ private:
static constexpr u8 bit_resolution = 16;
static constexpr usz inbuf_size = 400000; // Default value unknown
static constexpr usz float_buf_size = inbuf_size * (sizeof(f32) / sizeof(s16));
simple_ringbuf<inbuf_size> rbuf_raw;
simple_ringbuf<inbuf_size> rbuf_dsp;
simple_ringbuf<float_buf_size> rbuf_dsp;
simple_ringbuf<inbuf_size> rbuf_aux;
};
+35 -10
View File
@@ -33,6 +33,27 @@ void fmt_class_string<CellMsgDialogError>::format(std::string& out, u64 arg)
});
}
template<>
void fmt_class_string<msg_dialog_source>::format(std::string& out, u64 arg)
{
format_enum(out, arg, [](auto src)
{
switch (src)
{
case msg_dialog_source::_cellMsgDialog: return "cellMsgDialog";
case msg_dialog_source::_cellSaveData: return "cellSaveData";
case msg_dialog_source::_cellGame: return "cellGame";
case msg_dialog_source::_cellCrossController: return "cellCrossController";
case msg_dialog_source::_sceNp: return "sceNp";
case msg_dialog_source::_sceNpTrophy: return "sceNpTrophy";
case msg_dialog_source::sys_progress: return "sys_progress";
case msg_dialog_source::shader_loading: return "shader_loading";
}
return unknown;
});
}
MsgDialogBase::~MsgDialogBase()
{
}
@@ -141,9 +162,9 @@ using msg_dlg_thread = named_thread<msg_dlg_thread_info>;
error_code cellMsgDialogOpen2(u32 type, vm::cptr<char> msgString, vm::ptr<CellMsgDialogCallback> callback, vm::ptr<void> userData, vm::ptr<void> extParam);
// wrapper to call for other hle dialogs
error_code open_msg_dialog(bool is_blocking, u32 type, vm::cptr<char> msgString, vm::ptr<CellMsgDialogCallback> callback, vm::ptr<void> userData, vm::ptr<void> extParam, s32* return_code)
error_code open_msg_dialog(bool is_blocking, u32 type, vm::cptr<char> msgString, msg_dialog_source source, vm::ptr<CellMsgDialogCallback> callback, vm::ptr<void> userData, vm::ptr<void> extParam, s32* return_code)
{
cellSysutil.notice("open_msg_dialog(is_blocking=%d, type=0x%x, msgString=%s, callback=*0x%x, userData=*0x%x, extParam=*0x%x, return_code=*0x%x)", is_blocking, type, msgString, callback, userData, extParam, return_code);
cellSysutil.notice("open_msg_dialog(is_blocking=%d, type=0x%x, msgString=%s, source=%s, callback=*0x%x, userData=*0x%x, extParam=*0x%x, return_code=*0x%x)", is_blocking, type, msgString, source, callback, userData, extParam, return_code);
const MsgDialogType _type{ type };
@@ -166,7 +187,7 @@ error_code open_msg_dialog(bool is_blocking, u32 type, vm::cptr<char> msgString,
const auto notify = std::make_shared<atomic_t<u32>>(0);
const auto res = manager->create<rsx::overlays::message_dialog>()->show(is_blocking, msgString.get_ptr(), _type, [callback, userData, &return_code, is_blocking, notify](s32 status)
const auto res = manager->create<rsx::overlays::message_dialog>()->show(is_blocking, msgString.get_ptr(), _type, source, [callback, userData, &return_code, is_blocking, notify](s32 status)
{
if (is_blocking && return_code)
{
@@ -213,6 +234,7 @@ error_code open_msg_dialog(bool is_blocking, u32 type, vm::cptr<char> msgString,
}
dlg->type = _type;
dlg->source = source;
dlg->on_close = [callback, userData, is_blocking, &return_code, wptr = std::weak_ptr<MsgDialogBase>(dlg)](s32 status)
{
@@ -318,9 +340,9 @@ void exit_game(s32/* buttonType*/, vm::ptr<void>/* userData*/)
sysutil_send_system_cmd(CELL_SYSUTIL_REQUEST_EXITGAME, 0);
}
error_code open_exit_dialog(const std::string& message, bool is_exit_requested)
error_code open_exit_dialog(const std::string& message, bool is_exit_requested, msg_dialog_source source)
{
cellSysutil.notice("open_exit_dialog(message=%s, is_exit_requested=%d)", message, is_exit_requested);
cellSysutil.notice("open_exit_dialog(message=%s, is_exit_requested=%d, source=%s)", message, is_exit_requested, source);
vm::bptr<CellMsgDialogCallback> callback = vm::null;
@@ -334,6 +356,7 @@ error_code open_exit_dialog(const std::string& message, bool is_exit_requested)
true,
CELL_MSGDIALOG_TYPE_SE_TYPE_ERROR | CELL_MSGDIALOG_TYPE_BUTTON_TYPE_OK | CELL_MSGDIALOG_TYPE_DISABLE_CANCEL_ON,
vm::make_str(message),
source,
callback
);
@@ -401,7 +424,7 @@ error_code cellMsgDialogOpen2(u32 type, vm::cptr<char> msgString, vm::ptr<CellMs
cellSysutil.error("Opening error message dialog with message: %s", msgString);
}
return open_msg_dialog(false, type, msgString, callback, userData, extParam);
return open_msg_dialog(false, type, msgString, msg_dialog_source::_cellMsgDialog, callback, userData, extParam);
}
error_code cellMsgDialogOpen(u32 type, vm::cptr<char> msgString, vm::ptr<CellMsgDialogCallback> callback, vm::ptr<void> userData, vm::ptr<void> extParam)
@@ -496,7 +519,8 @@ error_code cellMsgDialogClose(f32 delay)
if (auto manager = g_fxo->try_get<rsx::overlays::display_manager>())
{
if (auto dlg = manager->get<rsx::overlays::message_dialog>())
if (auto dlg = manager->get<rsx::overlays::message_dialog>();
dlg && dlg->source() == msg_dialog_source::_cellMsgDialog)
{
auto& thr = g_fxo->get<msg_dlg_thread>();
thr.wait_until = wait_until;
@@ -509,7 +533,7 @@ error_code cellMsgDialogClose(f32 delay)
const auto dlg = g_fxo->get<msg_info>().get();
if (!dlg)
if (!dlg || dlg->source != msg_dialog_source::_cellMsgDialog)
{
return CELL_MSGDIALOG_ERROR_DIALOG_NOT_OPENED;
}
@@ -526,7 +550,8 @@ error_code cellMsgDialogAbort()
if (auto manager = g_fxo->try_get<rsx::overlays::display_manager>())
{
if (auto dlg = manager->get<rsx::overlays::message_dialog>())
if (auto dlg = manager->get<rsx::overlays::message_dialog>();
dlg && dlg->source() == msg_dialog_source::_cellMsgDialog)
{
g_fxo->get<msg_dlg_thread>().wait_until = 0;
dlg->close(false, true); // this doesn't call on_close
@@ -539,7 +564,7 @@ error_code cellMsgDialogAbort()
const auto dlg = g_fxo->get<msg_info>().get();
if (!dlg)
if (!dlg || dlg->source != msg_dialog_source::_cellMsgDialog)
{
return CELL_OK; // Not CELL_MSGDIALOG_ERROR_DIALOG_NOT_OPENED, tested on HW.
}
+15 -2
View File
@@ -89,9 +89,21 @@ enum class MsgDialogState
Close,
};
enum class msg_dialog_source
{
_cellMsgDialog,
_cellSaveData,
_cellGame,
_cellCrossController,
_sceNp,
_sceNpTrophy,
sys_progress,
shader_loading,
};
void close_msg_dialog();
error_code open_msg_dialog(bool is_blocking, u32 type, vm::cptr<char> msgString, vm::ptr<CellMsgDialogCallback> callback = vm::null, vm::ptr<void> userData = vm::null, vm::ptr<void> extParam = vm::null, s32* return_code = nullptr);
error_code open_exit_dialog(const std::string& message, bool is_exit_requested);
error_code open_msg_dialog(bool is_blocking, u32 type, vm::cptr<char> msgString, msg_dialog_source source, vm::ptr<CellMsgDialogCallback> callback = vm::null, vm::ptr<void> userData = vm::null, vm::ptr<void> extParam = vm::null, s32* return_code = nullptr);
error_code open_exit_dialog(const std::string& message, bool is_exit_requested, msg_dialog_source source);
class MsgDialogBase
{
@@ -103,6 +115,7 @@ public:
atomic_t<MsgDialogState> state{ MsgDialogState::Close };
MsgDialogType type{};
msg_dialog_source source = msg_dialog_source::_cellMsgDialog;
std::function<void(s32 status)> on_close = nullptr;
+16 -3
View File
@@ -224,14 +224,27 @@ error_code cellNetCtlGetInfo(s32 code, vm::ptr<CellNetCtlInfo> info)
case CELL_NET_CTL_INFO_MTU: info->mtu = 1500; break;
case CELL_NET_CTL_INFO_LINK: info->link = CELL_NET_CTL_LINK_CONNECTED; break;
case CELL_NET_CTL_INFO_LINK_TYPE: info->link_type = CELL_NET_CTL_LINK_TYPE_100BASE_FULL; break;
// case CELL_NET_CTL_INFO_BSSID: break;
// case CELL_NET_CTL_INFO_SSID: break;
// case CELL_NET_CTL_INFO_WLAN_SECURITY: break;
// case CELL_NET_CTL_INFO_8021X_TYPE: break;
// case CELL_NET_CTL_INFO_8021X_AUTH_NAME: break;
case CELL_NET_CTL_INFO_RSSI: info->rssi = 100; break; // wireless: value ranges from 0-100 indicating wireless connection strength
case CELL_NET_CTL_INFO_CHANNEL: info->channel = 1; break; // wireless: channel used to connect to the AP?
case CELL_NET_CTL_INFO_IP_CONFIG: info->ip_config = CELL_NET_CTL_IP_STATIC; break;
case CELL_NET_CTL_INFO_DHCP_HOSTNAME: strcpy_trunc(info->dhcp_hostname, nph.get_hostname()); break;
// case CELL_NET_CTL_INFO_PPPOE_AUTH_NAME: break;
case CELL_NET_CTL_INFO_IP_ADDRESS: strcpy_trunc(info->ip_address, np::ip_to_string(nph.get_local_ip_addr())); break; // verified on HW
case CELL_NET_CTL_INFO_NETMASK: strcpy_trunc(info->netmask, "255.255.255.0"); 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::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; // verified on HW
case CELL_NET_CTL_INFO_NETMASK: strcpy_trunc(info->netmask, "255.255.255.0"); 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;
// case CELL_NET_CTL_INFO_HTTP_PROXY_SERVER: break;
// case CELL_NET_CTL_INFO_HTTP_PROXY_PORT: break;
case CELL_NET_CTL_INFO_UPNP_CONFIG: info->upnp_config = (nph.get_upnp_status() == SCE_NP_SIGNALING_NETINFO_UPNP_STATUS_VALID) ? CELL_NET_CTL_UPNP_ON : CELL_NET_CTL_UPNP_OFF; break;
// case CELL_NET_CTL_INFO_RESERVED1: break;
// case CELL_NET_CTL_INFO_RESERVED2: break;
default: cellNetCtl.error("Unsupported request: %s", InfoCodeToName(code)); break;
}
+115 -7
View File
@@ -5,6 +5,7 @@
#include "Emu/Cell/lv2/sys_process.h"
#include "Emu/Cell/lv2/sys_sync.h"
#include "Emu/Io/pad_types.h"
#include "Emu/RSX/Overlays/overlay_debug_overlay.h"
#include "Input/pad_thread.h"
#include "Input/product_info.h"
#include "cellPad.h"
@@ -73,6 +74,95 @@ void pad_info::save(utils::serial& ar)
sys_io_serialize(ar);
}
void show_debug_overlay(const CellPadData& data, const Pad& pad, const pad_info& config)
{
const u32 setting = config.port_setting[pad.m_player_id];
const u16 d1 = data.button[CELL_PAD_BTN_OFFSET_DIGITAL1];
const u16 d2 = data.button[CELL_PAD_BTN_OFFSET_DIGITAL2];
std::string text = fmt::format(
"> Name: Raw Value Pressure\n"
">\n"
"> Len: %13d\n"
"> Digital: %5s %5s\n"
"> Press: %5s %5s\n"
"> Sensor: %5s %5s\n"
">\n"
"> Digital 1: 0x%04x 0x%04x\n"
"> Digital 2: 0x%04x 0x%04x\n"
">\n"
"> D-Pad Up: %5d %5d %5d\n"
"> D-Pad Down: %5d %5d %5d\n"
"> D-Pad Left: %5d %5d %5d\n"
"> D-Pad Right: %5d %5d %5d\n"
"> Cross: %5d %5d %5d\n"
"> Square: %5d %5d %5d\n"
"> Circle: %5d %5d %5d\n"
"> Triangle: %5d %5d %5d\n"
"> Start: %5d %5d\n"
"> Select: %5d %5d\n"
"> PS: %5d %5d\n"
"> L1: %5d %5d %5d\n"
"> L2: %5d %5d %5d\n"
"> L3: %5d %5d\n"
"> R1: %5d %5d %5d\n"
"> R2: %5d %5d %5d\n"
"> R3: %5d %5d\n"
"> LS X: %5d %5d\n"
"> LS Y: %5d %5d\n"
"> RS X: %5d %5d\n"
"> RS Y: %5d %5d\n"
">\n"
"> Sensor X: %5d %5d\n"
"> Sensor Y: %5d %5d\n"
"> Sensor Z: %5d %5d\n"
"> Sensor G: %5d %5d\n"
">\n"
"> PID: 0x%04x\n"
"> VID: 0x%04x\n"
"> Device Type: 0x%08x\n"
"> Class Type: 0x%08x\n"
,
data.len,
"on", data.len >= CELL_PAD_LEN_CHANGE_DEFAULT ? "on" : "off",
(setting & CELL_PAD_SETTING_PRESS_ON) ? "on" : "off", data.len >= CELL_PAD_LEN_CHANGE_PRESS_ON ? "on" : "off",
(setting & CELL_PAD_SETTING_SENSOR_ON) ? "on" : "off", data.len >= CELL_PAD_LEN_CHANGE_SENSOR_ON ? "on" : "off",
pad.m_digital_1, d1,
pad.m_digital_2, d2,
pad.m_press_up, !!(d1 & CELL_PAD_CTRL_UP), data.button[CELL_PAD_BTN_OFFSET_PRESS_UP],
pad.m_press_down, !!(d1 & CELL_PAD_CTRL_DOWN), data.button[CELL_PAD_BTN_OFFSET_PRESS_DOWN],
pad.m_press_left, !!(d1 & CELL_PAD_CTRL_LEFT), data.button[CELL_PAD_BTN_OFFSET_PRESS_LEFT],
pad.m_press_right, !!(d1 & CELL_PAD_CTRL_RIGHT), data.button[CELL_PAD_BTN_OFFSET_PRESS_RIGHT],
pad.m_press_cross, !!(d2 & CELL_PAD_CTRL_CROSS), data.button[CELL_PAD_BTN_OFFSET_PRESS_CROSS],
pad.m_press_square, !!(d2 & CELL_PAD_CTRL_SQUARE), data.button[CELL_PAD_BTN_OFFSET_PRESS_SQUARE],
pad.m_press_circle, !!(d2 & CELL_PAD_CTRL_CIRCLE), data.button[CELL_PAD_BTN_OFFSET_PRESS_CIRCLE],
pad.m_press_triangle, !!(d2 & CELL_PAD_CTRL_TRIANGLE), data.button[CELL_PAD_BTN_OFFSET_PRESS_TRIANGLE],
!!(pad.m_digital_1 & CELL_PAD_CTRL_START), !!(d1 & CELL_PAD_CTRL_START),
!!(pad.m_digital_1 & CELL_PAD_CTRL_SELECT), !!(d1 & CELL_PAD_CTRL_SELECT),
!!(pad.m_digital_1 & CELL_PAD_CTRL_PS), !!(d1 & CELL_PAD_CTRL_PS),
pad.m_press_L1, !!(d2 & CELL_PAD_CTRL_L1), data.button[CELL_PAD_BTN_OFFSET_PRESS_L1],
pad.m_press_L2, !!(d2 & CELL_PAD_CTRL_L2), data.button[CELL_PAD_BTN_OFFSET_PRESS_L2],
!!(pad.m_digital_1 & CELL_PAD_CTRL_L3), !!(d1 & CELL_PAD_CTRL_L3),
pad.m_press_R1, !!(d2 & CELL_PAD_CTRL_R1), data.button[CELL_PAD_BTN_OFFSET_PRESS_R1],
pad.m_press_R2, !!(d2 & CELL_PAD_CTRL_R2), data.button[CELL_PAD_BTN_OFFSET_PRESS_R2],
!!(pad.m_digital_1 & CELL_PAD_CTRL_R3), !!(d1 & CELL_PAD_CTRL_R3),
pad.m_analog_left_x, data.button[CELL_PAD_BTN_OFFSET_ANALOG_LEFT_X],
pad.m_analog_left_y, data.button[CELL_PAD_BTN_OFFSET_ANALOG_LEFT_Y],
pad.m_analog_right_x, data.button[CELL_PAD_BTN_OFFSET_ANALOG_RIGHT_X],
pad.m_analog_right_y, data.button[CELL_PAD_BTN_OFFSET_ANALOG_RIGHT_Y],
pad.m_sensor_x, data.button[CELL_PAD_BTN_OFFSET_SENSOR_X],
pad.m_sensor_y, data.button[CELL_PAD_BTN_OFFSET_SENSOR_Y],
pad.m_sensor_z, data.button[CELL_PAD_BTN_OFFSET_SENSOR_Z],
pad.m_sensor_g, data.button[CELL_PAD_BTN_OFFSET_SENSOR_G],
pad.m_product_id,
pad.m_vendor_id,
pad.m_device_type,
pad.m_class_type
);
rsx::overlays::set_debug_overlay_text(std::move(text));
}
extern void send_sys_io_connect_event(usz index, u32 state);
bool cellPad_NotifyStateChange(usz index, u64 /*state*/, bool locked, bool is_blocking = true)
@@ -297,10 +387,22 @@ void pad_get_data(u32 port_no, CellPadData* data, bool get_periph_data = false)
// Curiously it maps infrared on the press value of the face buttons for some reason.
const bool use_piggyback = pad->m_class_type == CELL_PAD_PCLASS_TYPE_SKATEBOARD;
const auto set_value = [&btnChanged, use_piggyback](u16& value, u16 new_value, bool is_piggyback = false)
const auto set_value = [&btnChanged, use_piggyback, &pad](u16& value, u16 new_value, bool force_processing = false, u16 old_max_value = 255, u16 new_max_value = 255)
{
if (use_piggyback && !is_piggyback)
return;
if (use_piggyback)
{
if (!force_processing)
return;
// Some piggyback values need to be scaled down on emulated devices
if (old_max_value != new_max_value)
{
if (pad->m_class_type == CELL_PAD_PCLASS_TYPE_SKATEBOARD && pad->m_pad_handler != pad_handler::skateboard)
{
new_value = static_cast<u16>(new_max_value * std::clamp(new_value / static_cast<f32>(old_max_value), 0.0f, 1.0f));
}
}
}
if (value != new_value)
{
@@ -367,10 +469,10 @@ void pad_get_data(u32 port_no, CellPadData* data, bool get_periph_data = false)
case CELL_PAD_CTRL_PRESS_LEFT: set_value(pad->m_press_left, button.m_value, true); break;
case CELL_PAD_CTRL_PRESS_UP: set_value(pad->m_press_up, button.m_value, true); break;
case CELL_PAD_CTRL_PRESS_DOWN: set_value(pad->m_press_down, button.m_value, true); break;
case CELL_PAD_CTRL_PRESS_TRIANGLE: set_value(pad->m_press_triangle, button.m_value, true); break;
case CELL_PAD_CTRL_PRESS_CIRCLE: set_value(pad->m_press_circle, button.m_value, true); break;
case CELL_PAD_CTRL_PRESS_CROSS: set_value(pad->m_press_cross, button.m_value, true); break;
case CELL_PAD_CTRL_PRESS_SQUARE: set_value(pad->m_press_square, button.m_value, true); break;
case CELL_PAD_CTRL_PRESS_TRIANGLE: set_value(pad->m_press_triangle, button.m_value, true, 255, 63); break; // Infrared on RIDE Skateboard
case CELL_PAD_CTRL_PRESS_CIRCLE: set_value(pad->m_press_circle, button.m_value, true, 255, 63); break; // Infrared on RIDE Skateboard
case CELL_PAD_CTRL_PRESS_CROSS: set_value(pad->m_press_cross, button.m_value, true, 255, 63); break; // Infrared on RIDE Skateboard
case CELL_PAD_CTRL_PRESS_SQUARE: set_value(pad->m_press_square, button.m_value, true, 255, 63); break; // Infrared on RIDE Skateboard
case CELL_PAD_CTRL_PRESS_L1: set_value(pad->m_press_L1, button.m_value, true); break;
case CELL_PAD_CTRL_PRESS_R1: set_value(pad->m_press_R1, button.m_value, true); break;
case CELL_PAD_CTRL_PRESS_L2: set_value(pad->m_press_L2, button.m_value, true); break;
@@ -614,6 +716,12 @@ error_code cellPadGetData(u32 port_no, vm::ptr<CellPadData> data)
return not_an_error(CELL_PAD_ERROR_NO_DEVICE);
pad_get_data(port_no, data.get_ptr());
if (g_cfg.io.debug_overlay && !g_cfg.video.overlay && port_no == 0)
{
show_debug_overlay(*data, *pad, config);
}
return CELL_OK;
}
+5 -5
View File
@@ -333,7 +333,7 @@ static error_code select_and_delete(ppu_thread& ppu)
// Get user confirmation by opening a blocking dialog
s32 return_code = CELL_MSGDIALOG_BUTTON_NONE;
error_code res = open_msg_dialog(true, CELL_MSGDIALOG_TYPE_SE_TYPE_NORMAL | CELL_MSGDIALOG_TYPE_BUTTON_TYPE_YESNO, vm::make_str(msg), vm::null, vm::null, vm::null, &return_code);
error_code res = open_msg_dialog(true, CELL_MSGDIALOG_TYPE_SE_TYPE_NORMAL | CELL_MSGDIALOG_TYPE_BUTTON_TYPE_YESNO, vm::make_str(msg), msg_dialog_source::_cellSaveData, vm::null, vm::null, vm::null, &return_code);
// Reschedule after a blocking dialog returns
if (ppu.check_state())
@@ -370,7 +370,7 @@ static error_code select_and_delete(ppu_thread& ppu)
lv2_obj::sleep(ppu);
// Display success message by opening a blocking dialog (return value should be irrelevant here)
res = open_msg_dialog(true, CELL_MSGDIALOG_TYPE_SE_TYPE_NORMAL | CELL_MSGDIALOG_TYPE_BUTTON_TYPE_OK, vm::make_str(msg));
res = open_msg_dialog(true, CELL_MSGDIALOG_TYPE_SE_TYPE_NORMAL | CELL_MSGDIALOG_TYPE_BUTTON_TYPE_OK, vm::make_str(msg), msg_dialog_source::_cellSaveData);
// Reschedule after blocking dialog returns
if (ppu.check_state())
@@ -423,7 +423,7 @@ static error_code display_callback_result_error_message(ppu_thread& ppu, const C
lv2_obj::sleep(ppu);
// Get user confirmation by opening a blocking dialog (return value should be irrelevant here)
[[maybe_unused]] error_code res = open_msg_dialog(true, CELL_MSGDIALOG_TYPE_SE_TYPE_NORMAL | CELL_MSGDIALOG_TYPE_BUTTON_TYPE_OK, use_invalid_message ? result.invalidMsg : vm::make_str(msg));
[[maybe_unused]] error_code res = open_msg_dialog(true, CELL_MSGDIALOG_TYPE_SE_TYPE_NORMAL | CELL_MSGDIALOG_TYPE_BUTTON_TYPE_OK, use_invalid_message ? result.invalidMsg : vm::make_str(msg), msg_dialog_source::_cellSaveData);
// Reschedule after a blocking dialog returns
if (ppu.check_state())
@@ -1219,7 +1219,7 @@ static NEVER_INLINE error_code savedata_op(ppu_thread& ppu, u32 operation, u32 v
// Get user confirmation by opening a blocking dialog
s32 return_code = CELL_MSGDIALOG_BUTTON_NONE;
error_code res = open_msg_dialog(true, CELL_MSGDIALOG_TYPE_SE_TYPE_NORMAL | CELL_MSGDIALOG_TYPE_BUTTON_TYPE_YESNO, vm::make_str(message), vm::null, vm::null, vm::null, &return_code);
error_code res = open_msg_dialog(true, CELL_MSGDIALOG_TYPE_SE_TYPE_NORMAL | CELL_MSGDIALOG_TYPE_BUTTON_TYPE_YESNO, vm::make_str(message), msg_dialog_source::_cellSaveData, vm::null, vm::null, vm::null, &return_code);
// Reschedule after a blocking dialog returns
if (ppu.check_state())
@@ -1350,7 +1350,7 @@ static NEVER_INLINE error_code savedata_op(ppu_thread& ppu, u32 operation, u32 v
// Get user confirmation by opening a blocking dialog
s32 return_code = CELL_MSGDIALOG_BUTTON_NONE;
error_code res = open_msg_dialog(true, CELL_MSGDIALOG_TYPE_SE_TYPE_NORMAL | CELL_MSGDIALOG_TYPE_BUTTON_TYPE_YESNO, vm::make_str(message), vm::null, vm::null, vm::null, &return_code);
error_code res = open_msg_dialog(true, CELL_MSGDIALOG_TYPE_SE_TYPE_NORMAL | CELL_MSGDIALOG_TYPE_BUTTON_TYPE_YESNO, vm::make_str(message), msg_dialog_source::_cellSaveData, vm::null, vm::null, vm::null, &return_code);
// Reschedule after a blocking dialog returns
if (ppu.check_state())
+261 -36
View File
@@ -1,65 +1,221 @@
#include "stdafx.h"
#include "Emu/Cell/PPUModule.h"
#include "Emu/Cell/Modules/cellSysutilAvc.h"
#include "Emu/Cell/Modules/cellSysutil.h"
#include "Emu/IdManager.h"
LOG_CHANNEL(cellSysutil);
error_code cellSysutilAvcByeRequest()
template<>
void fmt_class_string<CellAvcError>::format(std::string& out, u64 arg)
{
cellSysutil.todo("cellSysutilAvcByeRequest()");
format_enum(out, arg, [](auto error)
{
switch (error)
{
STR_CASE(CELL_AVC_ERROR_UNKNOWN);
STR_CASE(CELL_AVC_ERROR_NOT_SUPPORTED);
STR_CASE(CELL_AVC_ERROR_NOT_INITIALIZED);
STR_CASE(CELL_AVC_ERROR_ALREADY_INITIALIZED);
STR_CASE(CELL_AVC_ERROR_INVALID_ARGUMENT);
STR_CASE(CELL_AVC_ERROR_OUT_OF_MEMORY);
STR_CASE(CELL_AVC_ERROR_BAD_ID);
STR_CASE(CELL_AVC_ERROR_INVALID_STATUS);
STR_CASE(CELL_AVC_ERROR_TIMEOUT);
STR_CASE(CELL_AVC_ERROR_NO_SESSION);
STR_CASE(CELL_AVC_ERROR_INCOMPATIBLE_PROTOCOL);
STR_CASE(CELL_AVC_ERROR_PEER_UNREACHABLE);
}
return unknown;
});
}
// Callback handle tag type
struct avc_cb_handle_t{};
struct avc_settings
{
avc_settings() = default;
avc_settings(const avc_settings&) = delete;
avc_settings& operator=(const avc_settings&) = delete;
SAVESTATE_INIT_POS(53);
shared_mutex mutex_cb;
vm::ptr<CellSysutilAvcCallback> avc_cb{};
vm::ptr<void> avc_cb_arg{};
atomic_t<u32> req_id_cnt = 0;
static bool saveable(bool /*is_writing*/) noexcept
{
return GET_SERIALIZATION_VERSION(cellSysutil) != 0;
}
avc_settings(utils::serial& ar) noexcept
{
[[maybe_unused]] const s32 version = GET_SERIALIZATION_VERSION(cellSysutil);
if (version == 0)
{
return;
}
save(ar);
}
void save(utils::serial& ar)
{
[[maybe_unused]] const s32 version = GET_OR_USE_SERIALIZATION_VERSION(ar.is_writing(), cellSysutil);
ar(avc_cb, avc_cb_arg);
}
void register_cb_call(CellSysutilAvcRequestId req_id, CellSysutilAvcEvent event_id, CellSysUtilAvcEventParam param)
{
// This is equivalent to the dispatcher code
sysutil_register_cb_with_id<avc_cb_handle_t>([=, this](ppu_thread& cb_ppu) -> s32
{
vm::ptr<CellSysutilAvcCallback> avc_cb{};
vm::ptr<void> avc_cb_arg{};
{
std::lock_guard lock(this->mutex_cb);
avc_cb = this->avc_cb;
avc_cb_arg = this->avc_cb_arg;
}
if (avc_cb)
{
// TODO: lots of checks before calling the cb
if (event_id == CELL_AVC_EVENT_UNLOAD_SUCCEEDED)
{
std::lock_guard lock(this->mutex_cb);
this->avc_cb = {};
this->avc_cb_arg = {};
}
avc_cb(cb_ppu, req_id, event_id, param, avc_cb_arg);
}
return 0;
});
}
};
error_code cellSysutilAvcByeRequest(vm::ptr<CellSysutilAvcRequestId> request_id)
{
cellSysutil.todo("cellSysutilAvcByeRequest(request_id=*0x%x)", request_id);
if (!request_id)
return CELL_AVC_ERROR_INVALID_ARGUMENT;
auto& settings = g_fxo->get<avc_settings>();
const CellSysutilAvcRequestId req_id = settings.req_id_cnt.fetch_add(1);
*request_id = req_id;
settings.register_cb_call(req_id, CELL_AVC_EVENT_BYE_SUCCEEDED, static_cast<CellSysUtilAvcEventParam>(0));
return CELL_OK;
}
error_code cellSysutilAvcCancelByeRequest()
error_code cellSysutilAvcCancelByeRequest(vm::ptr<CellSysutilAvcRequestId> request_id)
{
cellSysutil.todo("cellSysutilAvcCancelByeRequest()");
cellSysutil.todo("cellSysutilAvcCancelByeRequest(request_id=*0x%x)", request_id);
if (!request_id)
return CELL_AVC_ERROR_INVALID_ARGUMENT;
return CELL_OK;
}
error_code cellSysutilAvcCancelJoinRequest()
error_code cellSysutilAvcCancelJoinRequest(vm::ptr<CellSysutilAvcRequestId> request_id)
{
cellSysutil.todo("cellSysutilAvcCancelJoinRequest()");
cellSysutil.todo("cellSysutilAvcCancelJoinRequest(request_id=*0x%x)", request_id);
if (!request_id)
return CELL_AVC_ERROR_INVALID_ARGUMENT;
return CELL_OK;
}
error_code cellSysutilAvcEnumPlayers()
error_code cellSysutilAvcEnumPlayers(vm::ptr<SceNpId> players_id, vm::ptr<s32> players_num)
{
cellSysutil.todo("cellSysutilAvcEnumPlayers()");
cellSysutil.todo("cellSysutilAvcEnumPlayers(players_id=*0x%x, players_num=*0x%x)", players_id, players_num);
if (!players_num)
return CELL_AVC_ERROR_INVALID_ARGUMENT;
if (players_id)
{
// Fill players_id with players_num participants
}
else
{
// Return number of participants
*players_num = 0;
}
return CELL_OK;
}
error_code cellSysutilAvcGetAttribute()
error_code cellSysutilAvcGetAttribute(CellSysUtilAvcAttribute attr_id, vm::pptr<void> param)
{
cellSysutil.todo("cellSysutilAvcGetAttribute()");
cellSysutil.todo("cellSysutilAvcGetAttribute(attr_id=0x%x, param=*0x%x)", +attr_id, param);
if (!param)
return CELL_AVC_ERROR_INVALID_ARGUMENT;
return CELL_OK;
}
error_code cellSysutilAvcGetLayoutMode()
error_code cellSysutilAvcGetLayoutMode(vm::ptr<CellSysutilAvcLayoutMode> layout)
{
cellSysutil.todo("cellSysutilAvcGetLayoutMode()");
cellSysutil.todo("cellSysutilAvcGetLayoutMode(layout=*0x%x)", layout);
if (!layout)
return CELL_AVC_ERROR_INVALID_ARGUMENT;
return CELL_OK;
}
error_code cellSysutilAvcGetShowStatus()
error_code cellSysutilAvcGetShowStatus(vm::ptr<b8> is_visible)
{
cellSysutil.todo("cellSysutilAvcGetShowStatus()");
cellSysutil.todo("cellSysutilAvcGetShowStatus(is_visible=*0x%x)", is_visible);
if (!is_visible)
return CELL_AVC_ERROR_INVALID_ARGUMENT;
return CELL_OK;
}
error_code cellSysutilAvcGetSpeakerVolumeLevel()
error_code cellSysutilAvcGetSpeakerVolumeLevel(vm::ptr<s32> volumeLevel)
{
cellSysutil.todo("cellSysutilAvcGetSpeakerVolumeLevel()");
cellSysutil.todo("cellSysutilAvcGetSpeakerVolumeLevel(volumeLevel=*0x%x)", volumeLevel);
if (!volumeLevel)
return CELL_AVC_ERROR_INVALID_ARGUMENT;
return CELL_OK;
}
error_code cellSysutilAvcGetVideoMuting()
error_code cellSysutilAvcGetVideoMuting(vm::ptr<b8> is_muting)
{
cellSysutil.todo("cellSysutilAvcGetVideoMuting()");
cellSysutil.todo("cellSysutilAvcGetVideoMuting(is_muting=*0x%x)", is_muting);
if (!is_muting)
return CELL_AVC_ERROR_INVALID_ARGUMENT;
return CELL_OK;
}
error_code cellSysutilAvcGetVoiceMuting()
error_code cellSysutilAvcGetVoiceMuting(vm::ptr<b8> is_muting)
{
cellSysutil.todo("cellSysutilAvcGetVoiceMuting()");
cellSysutil.todo("cellSysutilAvcGetVoiceMuting(is_muting=*0x%x)", is_muting);
if (!is_muting)
return CELL_AVC_ERROR_INVALID_ARGUMENT;
return CELL_OK;
}
@@ -69,45 +225,105 @@ error_code cellSysutilAvcHidePanel()
return CELL_OK;
}
error_code cellSysutilAvcJoinRequest()
error_code cellSysutilAvcJoinRequest(u32 ctx_id, vm::cptr<SceNpRoomId> room_id, vm::ptr<CellSysutilAvcRequestId> request_id)
{
cellSysutil.todo("cellSysutilAvcJoinRequest()");
cellSysutil.todo("cellSysutilAvcJoinRequest(ctx_id=*0x%x, room_id=*0x%x, request_id=*0x%x)", ctx_id, room_id, request_id);
if (!room_id || !request_id)
return CELL_AVC_ERROR_INVALID_ARGUMENT;
auto& settings = g_fxo->get<avc_settings>();
const CellSysutilAvcRequestId req_id = settings.req_id_cnt.fetch_add(1);
*request_id = req_id;
settings.register_cb_call(req_id, CELL_AVC_EVENT_JOIN_SUCCEEDED, static_cast<CellSysUtilAvcEventParam>(0));
return CELL_OK;
}
error_code cellSysutilAvcLoadAsync()
error_code cellSysutilAvcLoadAsync(vm::ptr<CellSysutilAvcCallback> func, vm::ptr<void> userdata, sys_memory_container_t container,
CellSysUtilAvcMediaType media, CellSysUtilAvcVideoQuality videoQuality, CellSysUtilAvcVoiceQuality voiceQuality, vm::ptr<CellSysutilAvcRequestId> request_id)
{
cellSysutil.todo("cellSysutilAvcLoadAsync()");
cellSysutil.todo("cellSysutilAvcLoadAsync(func=*0x%x, userdata=*0x%x, container=0x%x, media=0x%x, videoQuality=0x%x, voiceQuality=0x%x, request_id=*0x%x)",
func, userdata, container, +media, +videoQuality, +voiceQuality, request_id);
//if (sys_memory_container_get_size(.., container) != CELL_OK)
// return CELL_AVC_ERROR_INVALID_ARGUMENT;
switch (media)
{
case CELL_SYSUTIL_AVC_VOICE_CHAT:
case CELL_SYSUTIL_AVC_VIDEO_CHAT:
// TODO: return CELL_AVC_ERROR_OUT_OF_MEMORY
// TODO: return CELL_AVC_ERROR_INVALID_ARGUMENT
break;
default:
return CELL_AVC_ERROR_INVALID_ARGUMENT;
}
if (!func || !request_id)
return CELL_AVC_ERROR_INVALID_ARGUMENT;
if (videoQuality != CELL_SYSUTIL_AVC_VIDEO_QUALITY_DEFAULT || voiceQuality != CELL_SYSUTIL_AVC_VOICE_QUALITY_DEFAULT)
return CELL_AVC_ERROR_INVALID_ARGUMENT;
auto& settings = g_fxo->get<avc_settings>();
{
std::lock_guard lock(settings.mutex_cb);
if (settings.avc_cb)
return CELL_AVC_ERROR_ALREADY_INITIALIZED;
settings.avc_cb = func;
settings.avc_cb_arg = userdata;
}
const CellSysutilAvcRequestId req_id = settings.req_id_cnt.fetch_add(1);
*request_id = req_id;
settings.register_cb_call(req_id, CELL_AVC_EVENT_LOAD_SUCCEEDED, static_cast<CellSysUtilAvcEventParam>(0));
return CELL_OK;
}
error_code cellSysutilAvcSetAttribute()
error_code cellSysutilAvcSetAttribute(CellSysUtilAvcAttribute attr_id, vm::ptr<void> param)
{
cellSysutil.todo("cellSysutilAvcSetAttribute()");
cellSysutil.todo("cellSysutilAvcSetAttribute(attr_id=0x%x, param=*0x%x)", +attr_id, param);
if (!param)
return CELL_AVC_ERROR_INVALID_ARGUMENT;
return CELL_OK;
}
error_code cellSysutilAvcSetLayoutMode()
error_code cellSysutilAvcSetLayoutMode(CellSysutilAvcLayoutMode layout)
{
cellSysutil.todo("cellSysutilAvcSetLayoutMode()");
cellSysutil.todo("cellSysutilAvcSetLayoutMode(layout=0x%x)", +layout);
if (layout > CELL_SYSUTIL_AVC_LAYOUT_BOTTOM)
return CELL_AVC_ERROR_INVALID_ARGUMENT;
return CELL_OK;
}
error_code cellSysutilAvcSetSpeakerVolumeLevel()
error_code cellSysutilAvcSetSpeakerVolumeLevel(s32 volumeLevel)
{
cellSysutil.todo("cellSysutilAvcSetSpeakerVolumeLevel()");
cellSysutil.todo("cellSysutilAvcSetSpeakerVolumeLevel(volumeLevel=%d)", volumeLevel);
if (volumeLevel < 0 || volumeLevel > 10)
return CELL_AVC_ERROR_INVALID_ARGUMENT;
return CELL_OK;
}
error_code cellSysutilAvcSetVideoMuting()
error_code cellSysutilAvcSetVideoMuting(b8 is_muting)
{
cellSysutil.todo("cellSysutilAvcSetVideoMuting()");
cellSysutil.todo("cellSysutilAvcSetVideoMuting(is_muting=%d)", is_muting);
return CELL_OK;
}
error_code cellSysutilAvcSetVoiceMuting()
error_code cellSysutilAvcSetVoiceMuting(b8 is_muting)
{
cellSysutil.todo("cellSysutilAvcSetVoiceMuting()");
cellSysutil.todo("cellSysutilAvcSetVoiceMuting(is_muting=%d)", is_muting);
return CELL_OK;
}
@@ -117,9 +333,18 @@ error_code cellSysutilAvcShowPanel()
return CELL_OK;
}
error_code cellSysutilAvcUnloadAsync()
error_code cellSysutilAvcUnloadAsync(vm::ptr<CellSysutilAvcRequestId> request_id)
{
cellSysutil.todo("cellSysutilAvcUnloadAsync()");
cellSysutil.todo("cellSysutilAvcUnloadAsync(request_id=*0x%x)", request_id);
if (!request_id)
return CELL_AVC_ERROR_INVALID_ARGUMENT;
auto& settings = g_fxo->get<avc_settings>();
const CellSysutilAvcRequestId req_id = settings.req_id_cnt.fetch_add(1);
*request_id = req_id;
settings.register_cb_call(req_id, CELL_AVC_EVENT_UNLOAD_SUCCEEDED, static_cast<CellSysUtilAvcEventParam>(0));
return CELL_OK;
}
+155
View File
@@ -0,0 +1,155 @@
#pragma once
#include "Emu/Cell/Modules/sceNp.h"
enum CellAvcError : u32
{
CELL_AVC_ERROR_UNKNOWN = 0x8002b701,
CELL_AVC_ERROR_NOT_SUPPORTED = 0x8002b702,
CELL_AVC_ERROR_NOT_INITIALIZED = 0x8002b703,
CELL_AVC_ERROR_ALREADY_INITIALIZED = 0x8002b704,
CELL_AVC_ERROR_INVALID_ARGUMENT = 0x8002b705,
CELL_AVC_ERROR_OUT_OF_MEMORY = 0x8002b706,
CELL_AVC_ERROR_BAD_ID = 0x8002b707,
CELL_AVC_ERROR_INVALID_STATUS = 0x8002b70a,
CELL_AVC_ERROR_TIMEOUT = 0x8002b70b,
CELL_AVC_ERROR_NO_SESSION = 0x8002b70d,
CELL_AVC_ERROR_INCOMPATIBLE_PROTOCOL = 0x8002b70e,
CELL_AVC_ERROR_PEER_UNREACHABLE = 0x8002b710,
};
enum CellSysutilAvcTransitionType : u32
{
CELL_SYSUTIL_AVC_TRANSITION_LINEAR = 0x00000000,
CELL_SYSUTIL_AVC_TRANSITION_SLOWDOWN = 0x00000001,
CELL_SYSUTIL_AVC_TRANSITION_FASTUP = 0x00000002,
CELL_SYSUTIL_AVC_TRANSITION_ANGULAR = 0x00000003,
CELL_SYSUTIL_AVC_TRANSITION_EXPONENT = 0x00000004,
CELL_SYSUTIL_AVC_TRANSITION_NONE = 0xffffffff
};
enum CellSysutilAvcWindowZorderMode : u32
{
CELL_SYSUTIL_AVC_ZORDER_FORWARD_MOST = 0x00000002,
CELL_SYSUTIL_AVC_ZORDER_BEHIND_MOST = 0x00000003,
};
enum : u32
{
CELL_AVC_REQUEST_ID_SYSTEM_EVENT = 0x00000000,
CELL_SYSUTIL_AVC_VIDEO_MEMORY_SIZE = 26 * 1024 * 1024,
CELL_SYSUTIL_AVC_VOICE_MEMORY_SIZE = 8 * 1024 * 1024,
CELL_SYSUTIL_AVC_EXTRA_MEMORY_SIZE_FOR_SHARING_VIDEO_BUFFER = 2 * 1024 * 1024,
CELL_SYSUTIL_AVC_OPTION_PARAM_VERSION = 100,
};
enum CellSysutilAvcEvent : u32
{
CELL_AVC_EVENT_LOAD_SUCCEEDED = 0x00000001,
CELL_AVC_EVENT_LOAD_FAILED = 0x00000002,
CELL_AVC_EVENT_UNLOAD_SUCCEEDED = 0x00000003,
CELL_AVC_EVENT_UNLOAD_FAILED = 0x00000004,
CELL_AVC_EVENT_JOIN_SUCCEEDED = 0x00000005,
CELL_AVC_EVENT_JOIN_FAILED = 0x00000006,
CELL_AVC_EVENT_BYE_SUCCEEDED = 0x00000007,
CELL_AVC_EVENT_BYE_FAILED = 0x00000008,
CELL_AVC_EVENT_SYSTEM_NEW_MEMBER_JOINED = 0x10000001,
CELL_AVC_EVENT_SYSTEM_MEMBER_LEFT = 0x10000002,
CELL_AVC_EVENT_SYSTEM_SESSION_ESTABLISHED = 0x10000003,
CELL_AVC_EVENT_SYSTEM_SESSION_CANNOT_ESTABLISHED = 0x10000004,
CELL_AVC_EVENT_SYSTEM_SESSION_DISCONNECTED = 0x10000005,
CELL_AVC_EVENT_SYSTEM_VOICE_DETECTED = 0x10000006,
CELL_AVC_EVENT_SYSTEM_MIC_DETECTED = 0x10000007,
CELL_AVC_EVENT_SYSTEM_CAMERA_DETECTED = 0x10000008,
};
enum CellSysUtilAvcEventParam : u64
{
CELL_AVC_EVENT_PARAM_ERROR_UNKNOWN = 0x00000001,
CELL_AVC_EVENT_PARAM_ERROR_NOT_SUPPORTED = 0x00000002,
CELL_AVC_EVENT_PARAM_ERROR_INVALID_ARGUMENT = 0x00000003,
CELL_AVC_EVENT_PARAM_ERROR_OUT_OF_MEMORY = 0x00000004,
CELL_AVC_EVENT_PARAM_ERROR_INVALID_STATUS = 0x00000005,
CELL_AVC_EVENT_PARAM_ERROR_TIMEOUT = 0x00000006,
CELL_AVC_EVENT_PARAM_ERROR_CONTEXT_DOES_NOT_EXIST = 0x00000007,
CELL_AVC_EVENT_PARAM_ERROR_ROOM_DOES_NOT_EXIST = 0x00000008,
CELL_AVC_EVENT_PARAM_ERROR_MEDIA_MISMATCHED = 0x00000009,
CELL_AVC_EVENT_PARAM_ERROR_MEMBER_EXCEEDED = 0x0000000A,
CELL_AVC_EVENT_PARAM_ERROR_MASTER_LEFT = 0x0000000B,
CELL_AVC_EVENT_PARAM_ERROR_NETWORK_ERROR = 0x0000000C,
CELL_AVC_EVENT_PARAM_ERROR_INCOMPATIBLE_PROTOCOL = 0x0000000D,
};
enum CellSysUtilAvcAttribute : u32
{
CELL_SYSUTIL_AVC_ATTRIBUTE_DEFAULT_TRANSITION_TYPE = 0x00000001,
CELL_SYSUTIL_AVC_ATTRIBUTE_DEFAULT_TRANSITION_DURATION = 0x00000002,
CELL_SYSUTIL_AVC_ATTRIBUTE_DEFAULT_INITIAL_SHOW_STATUS = 0x00000003,
CELL_SYSUTIL_AVC_ATTRIBUTE_VOICE_DETECT_EVENT_TYPE = 0x00000004,
CELL_SYSUTIL_AVC_ATTRIBUTE_VOICE_DETECT_INTERVAL_TIME = 0x00000005,
CELL_SYSUTIL_AVC_ATTRIBUTE_VOICE_DETECT_SIGNAL_LEVEL = 0x00000006,
CELL_SYSUTIL_AVC_ATTRIBUTE_ROOM_PRIVILEGE_TYPE = 0x00000007,
CELL_SYSUTIL_AVC_ATTRIBUTE_VIDEO_MAX_BITRATE = 0x00000008,
};
enum CellSysutilAvcLayoutMode : u32
{
CELL_SYSUTIL_AVC_LAYOUT_LEFT = 0x00000000,
CELL_SYSUTIL_AVC_LAYOUT_RIGHT = 0x00000001,
CELL_SYSUTIL_AVC_LAYOUT_TOP = 0x00000002,
CELL_SYSUTIL_AVC_LAYOUT_BOTTOM = 0x00000003,
};
enum CellSysUtilAvcMediaType : u32
{
CELL_SYSUTIL_AVC_VOICE_CHAT = 0x00000001,
CELL_SYSUTIL_AVC_VIDEO_CHAT = 0x00000002,
};
enum CellSysutilAvcRoomPrivilegeType : u32
{
CELL_SYSUTIL_AVC_ROOM_PRIVILEGE_TYPE_NO_AUTO_GRANT = 0x00000000,
CELL_SYSUTIL_AVC_ROOM_PRIVILEGE_TYPE_AUTO_GRANT = 0x00000001
};
enum CellSysUtilAvcVideoQuality : u32
{
CELL_SYSUTIL_AVC_VIDEO_QUALITY_DEFAULT = 0x00000001
};
enum CellSysutilAvcVoiceDetectEventType : u32
{
CELL_SYSUTIL_AVC_VOICE_DETECT_EVENT_TYPE_SIGNAL = 0x00000001,
CELL_SYSUTIL_AVC_VOICE_DETECT_EVENT_TYPE_SPEAK = 0x00000002
};
enum CellSysutilAvcVoiceDetectSpeakData : u32
{
CELL_SYSUTIL_AVC_VOICE_DETECT_DATA_SPEAK_STOP = 0x00000000,
CELL_SYSUTIL_AVC_VOICE_DETECT_DATA_SPEAK_START = 0x00000001
};
enum CellSysUtilAvcVoiceQuality : u32
{
CELL_SYSUTIL_AVC_VOICE_QUALITY_DEFAULT = 0x00000001
};
struct CellSysutilAvcOptionParam
{
be_t<s32> avcOptionParamVersion;
b8 sharingVideoBuffer;
be_t<s32> maxPlayers; // Not in FW 1.70
};
struct CellSysutilAvcVoiceDetectData
{
SceNpId npid;
be_t<s32> data;
};
typedef u32 CellSysutilAvcRequestId;
using CellSysutilAvcCallback = void(CellSysutilAvcRequestId request_id, CellSysutilAvcEvent event_id, CellSysUtilAvcEventParam event_param, vm::ptr<void> userdata);
+154 -52
View File
@@ -1,185 +1,287 @@
#include "stdafx.h"
#include "Emu/Cell/PPUModule.h"
#include "Emu/Cell/Modules/cellSysutilAvc.h"
LOG_CHANNEL(cellSysutilAvcExt);
error_code cellSysutilAvcExtIsMicAttached()
error_code cellSysutilAvcSetAttribute(CellSysUtilAvcAttribute attr_id, vm::ptr<void> param);
error_code cellSysutilAvcLoadAsync(vm::ptr<CellSysutilAvcCallback> func, vm::ptr<void> userdata, sys_memory_container_t container, CellSysUtilAvcMediaType media, CellSysUtilAvcVideoQuality videoQuality, CellSysUtilAvcVoiceQuality voiceQuality, vm::ptr<CellSysutilAvcRequestId> request_id);
error_code cellSysutilAvcExtIsMicAttached(vm::ptr<s32> status)
{
UNIMPLEMENTED_FUNC(cellSysutilAvcExt);
cellSysutilAvcExt.todo("cellSysutilAvcExtIsMicAttached(status=*0x%x)", status);
ensure(!!status); // Not actually checked
return CELL_OK;
}
error_code cellSysutilAvcExtStopCameraDetection()
{
UNIMPLEMENTED_FUNC(cellSysutilAvcExt);
cellSysutilAvcExt.todo("cellSysutilAvcExtStopCameraDetection()");
return CELL_OK;
}
error_code cellSysutilAvcExtSetWindowRotation()
error_code cellSysutilAvcExtSetWindowRotation(vm::ptr<SceNpId> player_id, f32 rotation_x, f32 rotation_y, f32 rotation_z, CellSysutilAvcTransitionType transition_type)
{
UNIMPLEMENTED_FUNC(cellSysutilAvcExt);
cellSysutilAvcExt.todo("cellSysutilAvcExtSetWindowRotation(player_id=*0x%x, rotation_x=%f, rotation_y=%f, rotation_z=%f, transition_type=0x%x)", player_id, rotation_x, rotation_y, rotation_z, +transition_type);
return CELL_OK;
}
error_code cellSysutilAvcExtGetWindowPosition()
error_code cellSysutilAvcExtGetWindowPosition(vm::ptr<SceNpId> player_id, vm::ptr<f32> position_x, vm::ptr<f32> position_y, vm::ptr<f32> position_z)
{
UNIMPLEMENTED_FUNC(cellSysutilAvcExt);
cellSysutilAvcExt.todo("cellSysutilAvcExtGetWindowPosition(player_id=*0x%x, position_x=*0x%x, position_y=*0x%x, position_z=*0x%x)", player_id, position_x, position_y, position_z);
if (!player_id || !position_x || !position_y || !position_z)
return CELL_AVC_ERROR_INVALID_ARGUMENT;
return CELL_OK;
}
error_code cellSysutilAvcExtSetHideNamePlate()
{
UNIMPLEMENTED_FUNC(cellSysutilAvcExt);
cellSysutilAvcExt.todo("cellSysutilAvcExtSetHideNamePlate()");
return CELL_OK;
}
error_code cellSysutilAvcExtSetWindowPosition()
error_code cellSysutilAvcExtSetWindowPosition(vm::ptr<SceNpId> player_id, f32 position_x, f32 position_y, f32 position_z, CellSysutilAvcTransitionType transition_type)
{
UNIMPLEMENTED_FUNC(cellSysutilAvcExt);
cellSysutilAvcExt.todo("cellSysutilAvcExtSetWindowPosition(player_id=*0x%x, position_x=%f, position_y=%f, position_z=%f, transition_type=0x%x)", player_id, position_x, position_y, position_z, +transition_type);
return CELL_OK;
}
error_code cellSysutilAvcExtGetWindowSize()
error_code cellSysutilAvcExtGetWindowSize(vm::ptr<SceNpId> player_id, vm::ptr<f32> size_x, vm::ptr<f32> size_y)
{
UNIMPLEMENTED_FUNC(cellSysutilAvcExt);
cellSysutilAvcExt.todo("cellSysutilAvcExtGetWindowSize(player_id=*0x%x, size_x=*0x%x, size_y=*0x%x)", player_id, size_x, size_y);
if (!player_id || !size_x || !size_y)
return CELL_AVC_ERROR_INVALID_ARGUMENT;
return CELL_OK;
}
error_code cellSysutilAvcExtStartCameraDetection()
{
UNIMPLEMENTED_FUNC(cellSysutilAvcExt);
cellSysutilAvcExt.todo("cellSysutilAvcExtStartCameraDetection()");
return CELL_OK;
}
error_code cellSysutilAvcExtGetWindowShowStatus()
error_code cellSysutilAvcExtGetWindowShowStatus(vm::ptr<SceNpId> player_id, vm::ptr<b8> is_visible)
{
UNIMPLEMENTED_FUNC(cellSysutilAvcExt);
cellSysutilAvcExt.todo("cellSysutilAvcExtGetWindowShowStatus(player_id=*0x%x, is_visible=*0x%x)", player_id, is_visible);
if (!player_id || !is_visible)
return CELL_AVC_ERROR_INVALID_ARGUMENT;
return CELL_OK;
}
error_code cellSysutilAvcExtSetChatMode()
error_code cellSysutilAvcExtSetChatMode(u32 mode)
{
UNIMPLEMENTED_FUNC(cellSysutilAvcExt);
cellSysutilAvcExt.todo("cellSysutilAvcExtSetChatMode(mode=0x%x)", mode);
return CELL_OK;
}
error_code cellSysutilAvcExtGetNamePlateShowStatus()
error_code cellSysutilAvcExtGetNamePlateShowStatus(vm::ptr<b8> is_visible)
{
UNIMPLEMENTED_FUNC(cellSysutilAvcExt);
cellSysutilAvcExt.todo("cellSysutilAvcExtGetNamePlateShowStatus(is_visible=*0x%x)", is_visible);
if (!is_visible)
return CELL_AVC_ERROR_INVALID_ARGUMENT;
return CELL_OK;
}
error_code cellSysutilAvcExtSetWindowAlpha()
error_code cellSysutilAvcExtSetWindowAlpha(vm::ptr<SceNpId> player_id, f32 alpha, CellSysutilAvcTransitionType transition_type)
{
UNIMPLEMENTED_FUNC(cellSysutilAvcExt);
cellSysutilAvcExt.todo("cellSysutilAvcExtSetWindowAlpha(player_id=*0x%x, alpha=%f, transition_type=0x%x)", player_id, alpha, +transition_type);
if (!player_id || transition_type > CELL_SYSUTIL_AVC_TRANSITION_EXPONENT)
return CELL_AVC_ERROR_INVALID_ARGUMENT;
return CELL_OK;
}
error_code cellSysutilAvcExtSetWindowSize()
error_code cellSysutilAvcExtSetWindowSize(vm::ptr<SceNpId> player_id, f32 size_x, f32 size_y, CellSysutilAvcTransitionType transition_type)
{
UNIMPLEMENTED_FUNC(cellSysutilAvcExt);
cellSysutilAvcExt.todo("cellSysutilAvcExtSetWindowSize(player_id=*0x%x, size_x=%f, size_y=%f, transition_type=0x%x)", player_id, size_x, size_y, +transition_type);
if (!player_id || transition_type > CELL_SYSUTIL_AVC_TRANSITION_EXPONENT)
return CELL_AVC_ERROR_INVALID_ARGUMENT;
return CELL_OK;
}
error_code cellSysutilAvcExtShowPanelEx()
error_code cellSysutilAvcExtShowPanelEx(CellSysutilAvcTransitionType transition_type)
{
UNIMPLEMENTED_FUNC(cellSysutilAvcExt);
cellSysutilAvcExt.todo("cellSysutilAvcExtShowPanelEx(transition_type=0x%x)", +transition_type);
return CELL_OK;
}
error_code cellSysutilAvcExtLoadAsyncEx()
error_code cellSysutilAvcExtLoadAsyncEx(vm::ptr<CellSysutilAvcCallback> func, vm::ptr<void> userdata, sys_memory_container_t container,
CellSysUtilAvcMediaType media, CellSysUtilAvcVideoQuality videoQuality, CellSysUtilAvcVoiceQuality voiceQuality, vm::ptr<CellSysutilAvcOptionParam> option, vm::ptr<CellSysutilAvcRequestId> request_id)
{
UNIMPLEMENTED_FUNC(cellSysutilAvcExt);
return CELL_OK;
cellSysutilAvcExt.todo("cellSysutilAvcExtLoadAsyncEx(func=*0x%x, userdata=*0x%x, container=0x%x, media=0x%x, videoQuality=0x%x, voiceQuality=0x%x, option=*0x%x, request_id=*0x%x)",
func, userdata, container, +media, +videoQuality, +voiceQuality, option, request_id);
if (!option)
return CELL_AVC_ERROR_INVALID_ARGUMENT;
switch (option->avcOptionParamVersion)
{
case CELL_SYSUTIL_AVC_OPTION_PARAM_VERSION:
if (option->sharingVideoBuffer && media == CELL_SYSUTIL_AVC_VOICE_CHAT)
return CELL_AVC_ERROR_INVALID_ARGUMENT;
//cellSysutilAvcSetAttribute(0x10000100, &option->sharingVideoBuffer);
break;
case 180:
if (option->sharingVideoBuffer && media == CELL_SYSUTIL_AVC_VOICE_CHAT)
return CELL_AVC_ERROR_INVALID_ARGUMENT;
//cellSysutilAvcSetAttribute(0x10000100, &option->sharingVideoBuffer);
//cellSysutilAvcSetAttribute(0x10000102, &option->maxPlayers);
break;
default:
return CELL_AVC_ERROR_UNKNOWN;
}
return cellSysutilAvcLoadAsync(func, userdata, container, media, videoQuality, voiceQuality, request_id);
}
error_code cellSysutilAvcExtSetShowNamePlate()
{
UNIMPLEMENTED_FUNC(cellSysutilAvcExt);
cellSysutilAvcExt.todo("cellSysutilAvcExtSetShowNamePlate()");
return CELL_OK;
}
error_code cellSysutilAvcExtStopVoiceDetection()
{
UNIMPLEMENTED_FUNC(cellSysutilAvcExt);
cellSysutilAvcExt.todo("cellSysutilAvcExtStopVoiceDetection()");
return CELL_OK;
}
error_code cellSysutilAvcExtShowWindow()
error_code cellSysutilAvcExtShowWindow(vm::ptr<SceNpId> player_id, CellSysutilAvcTransitionType transition_type)
{
UNIMPLEMENTED_FUNC(cellSysutilAvcExt);
cellSysutilAvcExt.todo("cellSysutilAvcExtStopVoiceDetection(player_id=*0x%x, transition_type=0x%x)", player_id, +transition_type);
if (!player_id || transition_type > CELL_SYSUTIL_AVC_TRANSITION_EXPONENT)
return CELL_AVC_ERROR_INVALID_ARGUMENT;
return CELL_OK;
}
error_code cellSysutilAvcExtIsCameraAttached()
error_code cellSysutilAvcExtIsCameraAttached(vm::ptr<s32> status)
{
UNIMPLEMENTED_FUNC(cellSysutilAvcExt);
cellSysutilAvcExt.todo("cellSysutilAvcExtIsCameraAttached(status=*0x%x)", status);
ensure(!!status); // Not actually checked
return CELL_OK;
}
error_code cellSysutilAvcExtHidePanelEx()
error_code cellSysutilAvcExtHidePanelEx(CellSysutilAvcTransitionType transition_type)
{
UNIMPLEMENTED_FUNC(cellSysutilAvcExt);
cellSysutilAvcExt.todo("cellSysutilAvcExtHidePanelEx(transition_type=0x%x)", +transition_type);
return CELL_OK;
}
error_code cellSysutilAvcExtHideWindow()
error_code cellSysutilAvcExtHideWindow(vm::ptr<SceNpId> player_id, CellSysutilAvcTransitionType transition_type)
{
UNIMPLEMENTED_FUNC(cellSysutilAvcExt);
cellSysutilAvcExt.todo("cellSysutilAvcExtHideWindow(player_id=*0x%x, transition_type=0x%x)", player_id, +transition_type);
if (!player_id || transition_type > CELL_SYSUTIL_AVC_TRANSITION_EXPONENT)
return CELL_AVC_ERROR_INVALID_ARGUMENT;
return CELL_OK;
}
error_code cellSysutilAvcExtSetChatGroup()
{
UNIMPLEMENTED_FUNC(cellSysutilAvcExt);
cellSysutilAvcExt.todo("cellSysutilAvcExtSetChatGroup()");
return CELL_OK;
}
error_code cellSysutilAvcExtGetWindowRotation()
error_code cellSysutilAvcExtGetWindowRotation(vm::ptr<SceNpId> player_id, vm::ptr<f32> rotation_x, vm::ptr<f32> rotation_y, vm::ptr<f32> rotation_z)
{
UNIMPLEMENTED_FUNC(cellSysutilAvcExt);
cellSysutilAvcExt.todo("cellSysutilAvcExtGetWindowRotation(player_id=*0x%x, rotation_x=*0x%x, rotation_y=*0x%x, rotation_z=*0x%x)", player_id, rotation_x, rotation_y, rotation_z);
if (!player_id || !rotation_x || !rotation_y || !rotation_z)
return CELL_AVC_ERROR_INVALID_ARGUMENT;
return CELL_OK;
}
error_code cellSysutilAvcExtStartMicDetection()
{
UNIMPLEMENTED_FUNC(cellSysutilAvcExt);
cellSysutilAvcExt.todo("cellSysutilAvcExtStartMicDetection()");
return CELL_OK;
}
error_code cellSysutilAvcExtGetWindowAlpha()
error_code cellSysutilAvcExtGetWindowAlpha(vm::ptr<SceNpId> player_id, vm::ptr<f32> alpha)
{
UNIMPLEMENTED_FUNC(cellSysutilAvcExt);
cellSysutilAvcExt.todo("cellSysutilAvcExtGetWindowAlpha(player_id=*0x%x, alpha=*0x%x)", player_id, alpha);
if (!player_id || !alpha)
return CELL_AVC_ERROR_INVALID_ARGUMENT;
return CELL_OK;
}
error_code cellSysutilAvcExtStartVoiceDetection()
{
UNIMPLEMENTED_FUNC(cellSysutilAvcExt);
cellSysutilAvcExt.todo("cellSysutilAvcExtStartVoiceDetection()");
return CELL_OK;
}
error_code cellSysutilAvcExtGetSurfacePointer()
error_code cellSysutilAvcExtGetSurfacePointer(vm::ptr<SceNpId> player_id, vm::pptr<void> surface_ptr, vm::ptr<s32> surface_size, vm::ptr<s32> surface_size_x, vm::ptr<s32> surface_size_y)
{
UNIMPLEMENTED_FUNC(cellSysutilAvcExt);
cellSysutilAvcExt.todo("cellSysutilAvcExtGetSurfacePointer(player_id=*0x%x, surface_ptr=*0x%x, surface_size=*0x%x, surface_size_x=*0x%x, surface_size_y=*0x%x)", player_id, surface_ptr, surface_size, surface_size_x, surface_size_y);
if (!player_id || !surface_ptr || !surface_size || !surface_size_x || !surface_size_y)
return CELL_AVC_ERROR_INVALID_ARGUMENT;
return CELL_OK;
}
error_code cellSysutilAvcExtStopMicDetection()
{
UNIMPLEMENTED_FUNC(cellSysutilAvcExt);
cellSysutilAvcExt.todo("cellSysutilAvcExtStopMicDetection()");
return CELL_OK;
}
error_code cellSysutilAvcExtInitOptionParam()
error_code cellSysutilAvcExtInitOptionParam(s32 avcOptionParamVersion, vm::ptr<CellSysutilAvcOptionParam> option)
{
UNIMPLEMENTED_FUNC(cellSysutilAvcExt);
cellSysutilAvcExt.notice("cellSysutilAvcExtInitOptionParam(avcOptionParamVersion=0x%x, option=*0x%x)", avcOptionParamVersion, option);
if (!option)
return CELL_AVC_ERROR_INVALID_ARGUMENT;
option->avcOptionParamVersion = avcOptionParamVersion;
switch (option->avcOptionParamVersion)
{
case CELL_SYSUTIL_AVC_OPTION_PARAM_VERSION:
break;
case 180:
option->maxPlayers = 16;
break;
default:
return CELL_AVC_ERROR_UNKNOWN;
}
option->sharingVideoBuffer = false;
return CELL_OK;
}
error_code cellSysutilAvcExtSetWindowZorder()
error_code cellSysutilAvcExtSetWindowZorder(vm::ptr<SceNpId> player_id, u32 zorder)
{
UNIMPLEMENTED_FUNC(cellSysutilAvcExt);
cellSysutilAvcExt.todo("cellSysutilAvcExtSetWindowZorder(player_id=*0x%x, zorder=0x%x)", player_id, zorder);
if (!player_id || zorder < CELL_SYSUTIL_AVC_ZORDER_FORWARD_MOST || zorder > CELL_SYSUTIL_AVC_ZORDER_BEHIND_MOST)
return CELL_AVC_ERROR_INVALID_ARGUMENT;
return CELL_OK;
}
+213 -235
View File
@@ -1946,7 +1946,7 @@ error_code sceNpBasicAddPlayersHistoryAsync(vm::cptr<SceNpId> npids, u32 count,
error_code sceNpBasicGetPlayersHistoryEntryCount(u32 options, vm::ptr<u32> count)
{
sceNp.todo("sceNpBasicGetPlayersHistoryEntryCount(options=%d, count=*0x%x)", options, count);
sceNp.warning("sceNpBasicGetPlayersHistoryEntryCount(options=%d, count=*0x%x)", options, count);
if (options > SCE_NP_BASIC_PLAYERS_HISTORY_OPTIONS_ALL)
{
@@ -3176,7 +3176,7 @@ error_code sceNpLookupInit()
error_code sceNpLookupTerm()
{
sceNp.todo("sceNpLookupTerm()");
sceNp.warning("sceNpLookupTerm()");
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
@@ -4450,141 +4450,166 @@ error_code check_text(vm::cptr<char> text)
error_code sceNpMatchingCreateCtx(vm::ptr<SceNpId> npId, vm::ptr<SceNpMatchingHandler> handler, vm::ptr<void> arg, vm::ptr<u32> ctx_id)
{
sceNp.todo("sceNpMatchingCreateCtx(npId=*0x%x, handler=*0x%x, arg=*0x%x, ctx_id=*0x%x)", npId, handler, arg, ctx_id);
sceNp.warning("sceNpMatchingCreateCtx(npId=*0x%x, handler=*0x%x, arg=*0x%x, ctx_id=*0x%x)", npId, handler, arg, ctx_id);
if (false) // TODO
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
if (nph.is_NP2_Match2_init)
{
return SCE_NP_MATCHING_ERROR_UTILITY_UNAVAILABLE;
}
if (false) // TODO
if (!nph.is_NP_init)
{
return SCE_NP_MATCHING_ERROR_NOT_INITIALIZED;
}
if (false) // TODO
// assumed checks done on vsh
if (!npId || !handler || !ctx_id)
{
return SCE_NP_MATCHING_ERROR_INVALID_ARG;
}
const s32 id = create_matching_context(npId, handler, arg);
if (!id)
{
return SCE_NP_MATCHING_ERROR_CTX_MAX;
}
nph.set_current_gui_ctx_id(id);
*ctx_id = static_cast<u32>(id);
return CELL_OK;
}
error_code sceNpMatchingDestroyCtx(u32 ctx_id)
{
sceNp.todo("sceNpMatchingDestroyCtx(ctx_id=%d)", ctx_id);
sceNp.warning("sceNpMatchingDestroyCtx(ctx_id=%d)", ctx_id);
if (false) // TODO
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
if (nph.is_NP2_Match2_init)
return SCE_NP_MATCHING_ERROR_UTILITY_UNAVAILABLE;
if (false) // TODO
if (!nph.is_NP_init)
return SCE_NP_MATCHING_ERROR_NOT_INITIALIZED;
if (false) // TODO
if (!destroy_matching_context(ctx_id))
return SCE_NP_MATCHING_ERROR_CTX_NOT_FOUND;
nph.set_current_gui_ctx_id(0);
return CELL_OK;
}
error_code sceNpMatchingGetResult(u32 ctx_id, u32 req_id, vm::ptr<void> buf, vm::ptr<u32> size, vm::ptr<s32> event)
{
sceNp.todo("sceNpMatchingGetResult(ctx_id=%d, req_id=%d, buf=*0x%x, size=*0x%x, event=*0x%x)", ctx_id, req_id, buf, size, event);
sceNp.warning("sceNpMatchingGetResult(ctx_id=%d, req_id=%d, buf=*0x%x, size=*0x%x, event=*0x%x)", ctx_id, req_id, buf, size, event);
if (false) // TODO
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
if (nph.is_NP2_Match2_init)
return SCE_NP_MATCHING_ERROR_UTILITY_UNAVAILABLE;
if (false) // TODO
if (!nph.is_NP_init)
return SCE_NP_MATCHING_ERROR_NOT_INITIALIZED;
if (!size)
return SCE_NP_MATCHING_ERROR_INVALID_ARG;
if (false) // TODO
return SCE_NP_MATCHING_ERROR_CTX_NOT_FOUND;
return nph.get_matching_result(ctx_id, req_id, buf, size, event);
const u64 id_check = static_cast<s64>(static_cast<s32>(req_id)) >> 0x17 & 0x3f;
if (id_check > 32 || (1ULL << id_check & 0x1f89ad040U) == 0)
return SCE_NP_MATCHING_ERROR_INVALID_REQ_ID;
if (buf)
{
// TODO: copy data to buf
}
else
{
constexpr u32 required_size = 0; // TODO
*size = required_size;
}
if (event)
{
//*event = some_event; // TODO: example: SCE_NP_MATCHING_GUI_EVENT_CREATE_ROOM
}
return CELL_OK;
// const u64 id_check = static_cast<s64>(static_cast<s32>(req_id)) >> 0x17 & 0x3f;
// if (id_check > 32 || (1ULL << id_check & 0x1f89ad040U) == 0)
// return SCE_NP_MATCHING_ERROR_INVALID_REQ_ID;
}
error_code sceNpMatchingGetResultGUI(vm::ptr<void> buf, vm::ptr<u32> size, vm::ptr<s32> event)
{
sceNp.todo("sceNpMatchingGetResultGUI(buf=*0x%x, size=*0x%x, event=*0x%x)", buf, size, event);
sceNp.warning("sceNpMatchingGetResultGUI(buf=*0x%x, size=*0x%x, event=*0x%x)", buf, size, event);
if (false) // TODO
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
if (nph.is_NP2_Match2_init)
return SCE_NP_MATCHING_ERROR_UTILITY_UNAVAILABLE;
if (!size)
return SCE_NP_MATCHING_ERROR_INVALID_ARG;
if (buf)
return nph.get_result_gui(buf, size, event);
}
error_code matching_set_room_info(u32 ctx_id, vm::ptr<SceNpLobbyId> lobby_id, vm::ptr<SceNpRoomId> room_id, vm::ptr<SceNpMatchingAttr> attr, vm::ptr<u32> req_id, bool limit)
{
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
if (nph.is_NP2_Match2_init)
return SCE_NP_MATCHING_ERROR_UTILITY_UNAVAILABLE;
if (!nph.is_NP_init)
return SCE_NP_MATCHING_ERROR_NOT_INITIALIZED;
if (limit)
{
// TODO: copy data to buf
}
else
{
constexpr u32 required_size = 0; // TODO
*size = required_size;
static u64 last_call = 0;
if (last_call != 0 && (get_system_time() - last_call) < 30'000'000)
return SCE_NP_MATCHING_ERROR_BUSY;
last_call = get_system_time();
}
if (event)
{
//*event = some_event; // TODO: example: SCE_NP_MATCHING_GUI_EVENT_CREATE_ROOM
}
if (!lobby_id || !room_id || !req_id || !attr)
return SCE_NP_MATCHING_ERROR_INVALID_ARG;
error_code err = check_attr_id_and_duplicate(attr);
if (err != CELL_OK)
return err;
auto res = nph.set_room_info_gui(ctx_id, lobby_id, room_id, attr);
if (res < 0)
return res;
*req_id = res;
return CELL_OK;
}
error_code sceNpMatchingSetRoomInfo(u32 ctx_id, vm::ptr<SceNpLobbyId> lobby_id, vm::ptr<SceNpRoomId> room_id, vm::ptr<SceNpMatchingAttr> attr, vm::ptr<u32> req_id)
{
sceNp.todo("sceNpMatchingSetRoomInfo(ctx_id=%d, lobby_id=*0x%x, room_id=*0x%x, attr=*0x%x, req_id=*0x%x)", ctx_id, lobby_id, room_id, attr, req_id);
sceNp.warning("sceNpMatchingSetRoomInfo(ctx_id=%d, lobby_id=*0x%x, room_id=*0x%x, attr=*0x%x, req_id=*0x%x)", ctx_id, lobby_id, room_id, attr, req_id);
if (false) // TODO
return SCE_NP_MATCHING_ERROR_UTILITY_UNAVAILABLE;
if (false) // TODO
return SCE_NP_MATCHING_ERROR_NOT_INITIALIZED;
if (false) // TODO: some timeout with 30000000 us ?
return SCE_NP_MATCHING_ERROR_BUSY;
if (!lobby_id || !room_id || !req_id || !attr)
return SCE_NP_MATCHING_ERROR_INVALID_ARG;
error_code err = check_attr_id_and_duplicate(attr);
if (err != CELL_OK)
return err;
if (false) // TODO
return SCE_NP_MATCHING_ERROR_BUSY;
if (false) // TODO
return SCE_NP_MATCHING_ERROR_CTX_NOT_FOUND;
return CELL_OK;
return matching_set_room_info(ctx_id, lobby_id, room_id, attr, req_id, true);
}
error_code sceNpMatchingSetRoomInfoNoLimit(u32 ctx_id, vm::ptr<SceNpLobbyId> lobby_id, vm::ptr<SceNpRoomId> room_id, vm::ptr<SceNpMatchingAttr> attr, vm::ptr<u32> req_id)
{
sceNp.todo("sceNpMatchingSetRoomInfoNoLimit(ctx_id=%d, lobby_id=*0x%x, room_id=*0x%x, attr=*0x%x, req_id=*0x%x)", ctx_id, lobby_id, room_id, attr, req_id);
sceNp.warning("sceNpMatchingSetRoomInfoNoLimit(ctx_id=%d, lobby_id=*0x%x, room_id=*0x%x, attr=*0x%x, req_id=*0x%x)", ctx_id, lobby_id, room_id, attr, req_id);
if (false) // TODO
return matching_set_room_info(ctx_id, lobby_id, room_id, attr, req_id, false);
}
error_code matching_get_room_info(u32 ctx_id, vm::ptr<SceNpLobbyId> lobby_id, vm::ptr<SceNpRoomId> room_id, vm::ptr<SceNpMatchingAttr> attr, vm::ptr<u32> req_id, bool limit)
{
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
if (nph.is_NP2_Match2_init)
return SCE_NP_MATCHING_ERROR_UTILITY_UNAVAILABLE;
if (false) // TODO
if (!nph.is_NP_init)
return SCE_NP_MATCHING_ERROR_NOT_INITIALIZED;
if (limit)
{
static u64 last_call = 0;
if (last_call != 0 && (get_system_time() - last_call) < 30'000'000)
return SCE_NP_MATCHING_ERROR_BUSY;
last_call = get_system_time();
}
if (!lobby_id || !room_id || !req_id || !attr)
return SCE_NP_MATCHING_ERROR_INVALID_ARG;
@@ -4592,131 +4617,98 @@ error_code sceNpMatchingSetRoomInfoNoLimit(u32 ctx_id, vm::ptr<SceNpLobbyId> lob
if (err != CELL_OK)
return err;
if (false) // TODO
return SCE_NP_MATCHING_ERROR_BUSY;
auto res = nph.get_room_info_gui(ctx_id, lobby_id, room_id, attr);
if (false) // TODO
return SCE_NP_MATCHING_ERROR_CTX_NOT_FOUND;
if (res < 0)
return res;
*req_id = res;
return CELL_OK;
}
error_code sceNpMatchingGetRoomInfo(u32 ctx_id, vm::ptr<SceNpLobbyId> lobby_id, vm::ptr<SceNpRoomId> room_id, vm::ptr<SceNpMatchingAttr> attr, vm::ptr<u32> req_id)
{
sceNp.todo("sceNpMatchingGetRoomInfo(ctx_id=%d, lobby_id=*0x%x, room_id=*0x%x, attr=*0x%x, req_id=*0x%x)", ctx_id, lobby_id, room_id, attr, req_id);
sceNp.warning("sceNpMatchingGetRoomInfo(ctx_id=%d, lobby_id=*0x%x, room_id=*0x%x, attr=*0x%x, req_id=*0x%x)", ctx_id, lobby_id, room_id, attr, req_id);
if (false) // TODO
return SCE_NP_MATCHING_ERROR_UTILITY_UNAVAILABLE;
if (false) // TODO
return SCE_NP_MATCHING_ERROR_NOT_INITIALIZED;
if (false) // TODO: some timeout with 30000000 us ?
return SCE_NP_MATCHING_ERROR_BUSY;
if (!lobby_id || !room_id || !req_id || !attr)
return SCE_NP_MATCHING_ERROR_INVALID_ARG;
error_code err = check_attr_id_and_duplicate(attr);
if (err != CELL_OK)
return err;
if (false) // TODO
return SCE_NP_MATCHING_ERROR_BUSY;
if (false) // TODO
return SCE_NP_MATCHING_ERROR_CTX_NOT_FOUND;
return CELL_OK;
return matching_get_room_info(ctx_id, lobby_id, room_id, attr, req_id, true);
}
error_code sceNpMatchingGetRoomInfoNoLimit(u32 ctx_id, vm::ptr<SceNpLobbyId> lobby_id, vm::ptr<SceNpRoomId> room_id, vm::ptr<SceNpMatchingAttr> attr, vm::ptr<u32> req_id)
{
sceNp.todo("sceNpMatchingGetRoomInfoNoLimit(ctx_id=%d, lobby_id=*0x%x, room_id=*0x%x, attr=*0x%x, req_id=*0x%x)", ctx_id, lobby_id, room_id, attr, req_id);
sceNp.warning("sceNpMatchingGetRoomInfoNoLimit(ctx_id=%d, lobby_id=*0x%x, room_id=*0x%x, attr=*0x%x, req_id=*0x%x)", ctx_id, lobby_id, room_id, attr, req_id);
if (false) // TODO
return SCE_NP_MATCHING_ERROR_UTILITY_UNAVAILABLE;
if (false) // TODO
return SCE_NP_MATCHING_ERROR_NOT_INITIALIZED;
if (!lobby_id || !room_id || !req_id || !attr)
return SCE_NP_MATCHING_ERROR_INVALID_ARG;
error_code err = check_attr_id_and_duplicate(attr);
if (err != CELL_OK)
return err;
if (false) // TODO
return SCE_NP_MATCHING_ERROR_BUSY;
if (false) // TODO
return SCE_NP_MATCHING_ERROR_CTX_NOT_FOUND;
return CELL_OK;
return matching_get_room_info(ctx_id, lobby_id, room_id, attr, req_id, false);
}
error_code sceNpMatchingSetRoomSearchFlag(u32 ctx_id, vm::ptr<SceNpLobbyId> lobby_id, vm::ptr<SceNpRoomId> room_id, s32 flag, vm::ptr<u32> req_id)
{
sceNp.todo("sceNpMatchingSetRoomSearchFlag(ctx_id=%d, lobby_id=*0x%x, room_id=*0x%x, flag=%d, req_id=*0x%x)", ctx_id, lobby_id, room_id, flag, req_id);
sceNp.warning("sceNpMatchingSetRoomSearchFlag(ctx_id=%d, lobby_id=*0x%x, room_id=*0x%x, flag=%d, req_id=*0x%x)", ctx_id, lobby_id, room_id, flag, req_id);
if (false) // TODO
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
if (nph.is_NP2_Match2_init)
return SCE_NP_MATCHING_ERROR_UTILITY_UNAVAILABLE;
if (false) // TODO
if (!nph.is_NP_init)
return SCE_NP_MATCHING_ERROR_NOT_INITIALIZED;
if (!lobby_id || !room_id || !req_id || (flag < SCE_NP_MATCHING_ROOM_SEARCH_FLAG_OPEN || flag > SCE_NP_MATCHING_ROOM_SEARCH_FLAG_STEALTH))
return SCE_NP_MATCHING_ERROR_INVALID_ARG;
if (false) // TODO
return SCE_NP_MATCHING_ERROR_BUSY;
auto res = nph.set_room_search_flag_gui(ctx_id, lobby_id, room_id, flag);
if (false) // TODO
return SCE_NP_MATCHING_ERROR_CTX_NOT_FOUND;
if (res < 0)
return res;
*req_id = res;
return CELL_OK;
}
error_code sceNpMatchingGetRoomSearchFlag(u32 ctx_id, vm::ptr<SceNpLobbyId> lobby_id, vm::ptr<SceNpRoomId> room_id, vm::ptr<u32> req_id)
{
sceNp.todo("sceNpMatchingGetRoomSearchFlag(ctx_id=%d, lobby_id=*0x%x, room_id=*0x%x, req_id=*0x%x)", ctx_id, lobby_id, room_id, req_id);
sceNp.warning("sceNpMatchingGetRoomSearchFlag(ctx_id=%d, lobby_id=*0x%x, room_id=*0x%x, req_id=*0x%x)", ctx_id, lobby_id, room_id, req_id);
if (false) // TODO
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
if (nph.is_NP2_Match2_init)
return SCE_NP_MATCHING_ERROR_UTILITY_UNAVAILABLE;
if (false) // TODO
if (!nph.is_NP_init)
return SCE_NP_MATCHING_ERROR_NOT_INITIALIZED;
if (!lobby_id || !room_id || !req_id)
return SCE_NP_MATCHING_ERROR_INVALID_ARG;
if (false) // TODO
return SCE_NP_MATCHING_ERROR_BUSY;
auto res = nph.get_room_search_flag_gui(ctx_id, lobby_id, room_id);
if (false) // TODO
return SCE_NP_MATCHING_ERROR_CTX_NOT_FOUND;
if (res < 0)
return res;
*req_id = res;
return CELL_OK;
}
error_code sceNpMatchingGetRoomMemberListLocal(u32 ctx_id, vm::ptr<SceNpRoomId> room_id, vm::ptr<u32> buflen, vm::ptr<void> buf)
error_code matching_get_room_member_list(u32 ctx_id, vm::ptr<SceNpRoomId> room_id, vm::ptr<u32> buflen, vm::ptr<void> buf)
{
sceNp.todo("sceNpMatchingGetRoomMemberListLocal(ctx_id=%d, room_id=*0x%x, buflen=*0x%x, buf=*0x%x)", ctx_id, room_id, buflen, buf);
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
if (false) // TODO
if (nph.is_NP2_Match2_init)
return SCE_NP_MATCHING_ERROR_UTILITY_UNAVAILABLE;
if (false) // TODO
if (!nph.is_NP_init)
return SCE_NP_MATCHING_ERROR_NOT_INITIALIZED;
if (!buflen)
return SCE_NP_MATCHING_ERROR_INVALID_ARG;
if (false) // TODO
return SCE_NP_MATCHING_ERROR_CTX_NOT_FOUND;
return nph.get_room_member_list_local_gui(ctx_id, room_id, buflen, buf);
}
return CELL_OK;
error_code sceNpMatchingGetRoomMemberListLocal(u32 ctx_id, vm::ptr<SceNpRoomId> room_id, vm::ptr<u32> buflen, vm::ptr<void> buf)
{
sceNp.warning("sceNpMatchingGetRoomMemberListLocal(ctx_id=%d, room_id=*0x%x, buflen=*0x%x, buf=*0x%x)", ctx_id, room_id, buflen, buf);
return matching_get_room_member_list(ctx_id, room_id, buflen, buf);
}
// FUN_00014bdc
@@ -4788,41 +4780,42 @@ error_code check_room_list_params([[maybe_unused]] u32 ctx_id, vm::ptr<SceNpComm
return check_attr_id_and_duplicate(attribute);
}
error_code sceNpMatchingGetRoomListLimitGUI(u32 ctx_id, vm::ptr<SceNpCommunicationId> communicationId, vm::ptr<SceNpMatchingReqRange> range, vm::ptr<SceNpMatchingSearchCondition> cond,
vm::ptr<SceNpMatchingAttr> attr, vm::ptr<SceNpMatchingGUIHandler> handler, vm::ptr<void> arg)
error_code matching_get_room_list(u32 ctx_id, vm::ptr<SceNpCommunicationId> communicationId, vm::ptr<SceNpMatchingReqRange> range, vm::ptr<SceNpMatchingSearchCondition> cond,
vm::ptr<SceNpMatchingAttr> attr, vm::ptr<SceNpMatchingGUIHandler> handler, vm::ptr<void> arg, bool limit)
{
sceNp.todo("sceNpMatchingGetRoomListLimitGUI(ctx_id=%d, communicationId=*0x%x, range=*0x%x, cond=*0x%x, attr=*0x%x, handler=*0x%x, arg=*0x%x)", ctx_id, communicationId, range, cond, attr, handler, arg);
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
if (false) // TODO
if (nph.is_NP2_Match2_init)
return SCE_NP_MATCHING_ERROR_UTILITY_UNAVAILABLE;
// TODO: add limiter
// This check is used in all sceNpMatchingGetRoomList functions
error_code err = check_room_list_params(ctx_id, communicationId, range, cond, attr, handler, 1, 0);
if (err != CELL_OK)
return err;
if (false) // TODO
return SCE_NP_MATCHING_ERROR_BUSY;
return nph.get_room_list_gui(ctx_id, communicationId, range, cond, attr, handler, arg, limit);
}
// TODO: set callback: handler + arg
error_code sceNpMatchingGetRoomListLimitGUI(u32 ctx_id, vm::ptr<SceNpCommunicationId> communicationId, vm::ptr<SceNpMatchingReqRange> range, vm::ptr<SceNpMatchingSearchCondition> cond,
vm::ptr<SceNpMatchingAttr> attr, vm::ptr<SceNpMatchingGUIHandler> handler, vm::ptr<void> arg)
{
sceNp.warning("sceNpMatchingGetRoomListLimitGUI(ctx_id=%d, communicationId=*0x%x, range=*0x%x, cond=*0x%x, attr=*0x%x, handler=*0x%x, arg=*0x%x)", ctx_id, communicationId, range, cond, attr, handler, arg);
err = CELL_OK; // GetRoomListLimit
if (err != CELL_OK && static_cast<u32>(err) != SCE_NP_MATCHING_ERROR_BUSY)
{
// TODO ?
}
return CELL_OK;
return matching_get_room_list(ctx_id, communicationId, range, cond, attr, handler, arg, true);
}
error_code sceNpMatchingKickRoomMember(u32 ctx_id, vm::cptr<SceNpRoomId> room_id, vm::cptr<SceNpId> user_id, vm::ptr<u32> req_id)
{
sceNp.todo("sceNpMatchingKickRoomMember(ctx_id=%d, room_id=*0x%x, user_id=*0x%x, req_id=*0x%x)", ctx_id, room_id, user_id, req_id);
if (false) // TODO
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
if (nph.is_NP2_Match2_init)
return SCE_NP_MATCHING_ERROR_UTILITY_UNAVAILABLE;
if (false) // TODO
if (!nph.is_NP_init)
return SCE_NP_MATCHING_ERROR_NOT_INITIALIZED;
if (!room_id || !user_id || !req_id)
@@ -4841,10 +4834,12 @@ error_code sceNpMatchingKickRoomMemberWithOpt(u32 ctx_id, vm::cptr<SceNpRoomId>
{
sceNp.todo("sceNpMatchingKickRoomMemberWithOpt(ctx_id=%d, room_id=*0x%x, user_id=*0x%x, opt=*0x%x, opt_len=%d, req_id=*0x%x)", ctx_id, room_id, user_id, opt, opt_len, req_id);
if (false) // TODO
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
if (nph.is_NP2_Match2_init)
return SCE_NP_MATCHING_ERROR_UTILITY_UNAVAILABLE;
if (false) // TODO
if (!nph.is_NP_init)
return SCE_NP_MATCHING_ERROR_NOT_INITIALIZED;
if (!room_id || !user_id || !req_id)
@@ -4865,10 +4860,12 @@ error_code sceNpMatchingKickRoomMemberWithOpt(u32 ctx_id, vm::cptr<SceNpRoomId>
error_code sceNpMatchingQuickMatchGUI(u32 ctx_id, vm::cptr<SceNpCommunicationId> communicationId, vm::cptr<SceNpMatchingSearchCondition> cond, s32 available_num, s32 timeout,
vm::ptr<SceNpMatchingGUIHandler> handler, vm::ptr<void> arg)
{
sceNp.todo("sceNpMatchingQuickMatchGUI(ctx_id=%d, communicationId=*0x%x, cond=*0x%x, available_num=%d, timeout=%d, handler=*0x%x, arg=*0x%x)", ctx_id, communicationId, cond, available_num, timeout,
sceNp.warning("sceNpMatchingQuickMatchGUI(ctx_id=%d, communicationId=*0x%x, cond=*0x%x, available_num=%d, timeout=%d, handler=*0x%x, arg=*0x%x)", ctx_id, communicationId, cond, available_num, timeout,
handler, arg);
if (false) // TODO
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
if (nph.is_NP2_Match2_init)
return SCE_NP_MATCHING_ERROR_UTILITY_UNAVAILABLE;
if (!communicationId || !handler || available_num < 2 || timeout < 1)
@@ -4908,15 +4905,7 @@ error_code sceNpMatchingQuickMatchGUI(u32 ctx_id, vm::cptr<SceNpCommunicationId>
}
}
// TODO: set callback: handler + arg
error_code err = CELL_OK; // QuickMatch
if (err != CELL_OK && static_cast<u32>(err) != SCE_NP_MATCHING_ERROR_BUSY)
{
// TODO ?
}
return err;
return nph.quickmatch_gui(ctx_id, communicationId, cond, available_num, timeout, handler, arg);
}
error_code sceNpMatchingSendInvitationGUI(u32 ctx_id, vm::cptr<SceNpRoomId> room_id, vm::cptr<SceNpCommunicationId> communicationId, vm::cptr<SceNpId> dsts, s32 num, s32 slot_type,
@@ -4925,7 +4914,9 @@ error_code sceNpMatchingSendInvitationGUI(u32 ctx_id, vm::cptr<SceNpRoomId> room
sceNp.todo("sceNpMatchingSendInvitationGUI(ctx_id=%d, room_id=*0x%x, communicationId=*0x%x, dsts=*0x%x, num=%d, slot_type=%d, subject=%s, body=%s, container=%d, handler=*0x%x, arg=*0x%x)", ctx_id,
room_id, communicationId, dsts, num, slot_type, subject, body, container, handler, arg);
if (false) // TODO
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
if (nph.is_NP2_Match2_init)
return SCE_NP_MATCHING_ERROR_UTILITY_UNAVAILABLE;
if (!room_id || !communicationId || !subject || !body) // TODO: || (in_stack_0000007c != 0)
@@ -4969,7 +4960,9 @@ error_code sceNpMatchingAcceptInvitationGUI(u32 ctx_id, vm::cptr<SceNpCommunicat
{
sceNp.todo("sceNpMatchingAcceptInvitationGUI(ctx_id=%d, communicationId=*0x%x, container=%d, handler=*0x%x, arg=*0x%x)", ctx_id, communicationId, container, handler, arg);
if (false) // TODO
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
if (nph.is_NP2_Match2_init)
return SCE_NP_MATCHING_ERROR_UTILITY_UNAVAILABLE;
if (!communicationId || !handler)
@@ -5058,12 +5051,14 @@ error_code check_attr_create_room(vm::cptr<SceNpMatchingAttr> attribute)
return SCE_NP_MATCHING_ERROR_ATTR_NOT_SPECIFIED;
}
error_code sceNpMatchingCreateRoomGUI(u32 ctx_id, vm::cptr<SceNpCommunicationId> communicationId, vm::cptr<SceNpMatchingAttr> attr, vm::ptr<SceNpMatchingGUIHandler> handler, vm::ptr<void> arg)
error_code matching_create_room(u32 ctx_id, vm::cptr<SceNpCommunicationId> communicationId, vm::cptr<SceNpMatchingAttr> attr, vm::ptr<SceNpMatchingGUIHandler> handler, vm::ptr<void> arg)
{
sceNp.todo("sceNpMatchingCreateRoomGUI(ctx_id=%d, communicationId=*0x%x, attr=*0x%x, handler=*0x%x, arg=*0x%x)", ctx_id, communicationId, attr, handler, arg);
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
if (false) // TODO
if (nph.is_NP2_Match2_init)
{
return SCE_NP_MATCHING_ERROR_UTILITY_UNAVAILABLE;
}
if (!communicationId || !handler)
return SCE_NP_MATCHING_ERROR_INVALID_ARG;
@@ -5073,69 +5068,66 @@ error_code sceNpMatchingCreateRoomGUI(u32 ctx_id, vm::cptr<SceNpCommunicationId>
if (err != CELL_OK)
return err;
if (false) // TODO
return SCE_NP_MATCHING_ERROR_BUSY;
// TODO: set callback: handler + arg
err = CELL_OK; // create_room
if (err != CELL_OK && static_cast<u32>(err) != SCE_NP_MATCHING_ERROR_BUSY)
{
// TODO ?
}
return err;
return nph.create_room_gui(ctx_id, communicationId, attr, handler, arg);
}
error_code sceNpMatchingJoinRoomGUI(u32 ctx_id, vm::ptr<SceNpRoomId> room_id, vm::ptr<SceNpMatchingGUIHandler> handler, vm::ptr<void> arg)
error_code sceNpMatchingCreateRoomGUI(u32 ctx_id, vm::cptr<SceNpCommunicationId> communicationId, vm::cptr<SceNpMatchingAttr> attr, vm::ptr<SceNpMatchingGUIHandler> handler, vm::ptr<void> arg)
{
sceNp.todo("sceNpMatchingJoinRoomGUI(ctx_id=%d, room_id=*0x%x, handler=*0x%x, arg=*0x%x)", ctx_id, room_id, handler, arg);
sceNp.warning("sceNpMatchingCreateRoomGUI(ctx_id=%d, communicationId=*0x%x, attr=*0x%x, handler=*0x%x, arg=*0x%x)", ctx_id, communicationId, attr, handler, arg);
if (false) // TODO
return matching_create_room(ctx_id, communicationId, attr, handler, arg);
}
error_code matching_join_room(u32 ctx_id, vm::ptr<SceNpRoomId> room_id, vm::ptr<SceNpMatchingGUIHandler> handler, vm::ptr<void> arg)
{
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
if (nph.is_NP2_Match2_init)
return SCE_NP_MATCHING_ERROR_UTILITY_UNAVAILABLE;
if (!room_id || !handler)
return SCE_NP_MATCHING_ERROR_INVALID_ARG;
if (false) // TODO
return SCE_NP_MATCHING_ERROR_BUSY;
return nph.join_room_gui(ctx_id, room_id, handler, arg);
}
// TODO: set callback: handler + arg
error_code sceNpMatchingJoinRoomGUI(u32 ctx_id, vm::ptr<SceNpRoomId> room_id, vm::ptr<SceNpMatchingGUIHandler> handler, vm::ptr<void> arg)
{
sceNp.warning("sceNpMatchingJoinRoomGUI(ctx_id=%d, room_id=*0x%x, handler=*0x%x, arg=*0x%x)", ctx_id, room_id, handler, arg);
error_code err = CELL_OK; // join_room
if (err != CELL_OK && static_cast<u32>(err) != SCE_NP_MATCHING_ERROR_BUSY)
{
// TODO ?
}
return err;
return matching_join_room(ctx_id, room_id, handler, arg);
}
error_code sceNpMatchingLeaveRoom(u32 ctx_id, vm::cptr<SceNpRoomId> room_id, vm::ptr<u32> req_id)
{
sceNp.todo("sceNpMatchingLeaveRoom(ctx_id=%d, room_id=*0x%x, req_id=*0x%x)", ctx_id, room_id, req_id);
sceNp.warning("sceNpMatchingLeaveRoom(ctx_id=%d, room_id=*0x%x, req_id=*0x%x)", ctx_id, room_id, req_id);
if (false) // TODO
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
if (nph.is_NP2_Match2_init)
return SCE_NP_MATCHING_ERROR_UTILITY_UNAVAILABLE;
if (false) // TODO
if (!nph.is_NP_init)
return SCE_NP_MATCHING_ERROR_NOT_INITIALIZED;
if (false) // TODO
return SCE_NP_MATCHING_ERROR_BUSY;
auto res = nph.leave_room_gui(ctx_id, room_id);
if (false) // TODO
return SCE_NP_MATCHING_ERROR_CTX_NOT_FOUND;
if (res < 0)
return res;
*req_id = res;
return CELL_OK;
}
error_code sceNpMatchingSearchJoinRoomGUI(u32 ctx_id, vm::cptr<SceNpCommunicationId> communicationId, vm::cptr<SceNpMatchingSearchCondition> cond, vm::cptr<SceNpMatchingAttr> attribute,
error_code sceNpMatchingSearchJoinRoomGUI(u32 ctx_id, vm::cptr<SceNpCommunicationId> communicationId, vm::cptr<SceNpMatchingSearchCondition> cond, vm::cptr<SceNpMatchingAttr> attr,
vm::ptr<SceNpMatchingGUIHandler> handler, vm::ptr<void> arg)
{
sceNp.todo("sceNpMatchingSearchJoinRoomGUI(ctx_id=%d, communicationId=*0x%x, cond=*0x%x, attr=*0x%x, handler=*0x%x, arg=*0x%x)", ctx_id, communicationId, cond, attribute, handler, arg);
sceNp.warning("sceNpMatchingSearchJoinRoomGUI(ctx_id=%d, communicationId=*0x%x, cond=*0x%x, attr=*0x%x, handler=*0x%x, arg=*0x%x)", ctx_id, communicationId, cond, attr, handler, arg);
if (false) // TODO
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
if (nph.is_NP2_Match2_init)
return SCE_NP_MATCHING_ERROR_UTILITY_UNAVAILABLE;
if (!communicationId || !handler)
@@ -5183,32 +5175,23 @@ error_code sceNpMatchingSearchJoinRoomGUI(u32 ctx_id, vm::cptr<SceNpCommunicatio
}
}
error_code err = check_attr_id_and_duplicate(attribute);
error_code err = check_attr_id_and_duplicate(attr);
if (err != CELL_OK)
return err;
if (false) // TODO
return SCE_NP_MATCHING_ERROR_BUSY;
// TODO: set callback: handler + arg
//err = search_join_room
if (err != CELL_OK && static_cast<u32>(err) != SCE_NP_MATCHING_ERROR_BUSY)
{
// TODO ?
}
return err;
return nph.searchjoin_gui(ctx_id, communicationId, cond, attr, handler, arg);
}
error_code sceNpMatchingGrantOwnership(u32 ctx_id, vm::cptr<SceNpRoomId> room_id, vm::cptr<SceNpId> user_id, vm::ptr<u32> req_id)
{
sceNp.todo("sceNpMatchingGrantOwnership(ctx_id=%d, room_id=*0x%x, user_id=*0x%x, req_id=*0x%x)", ctx_id, room_id, user_id, req_id);
if (false) // TODO
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
if (nph.is_NP2_Match2_init)
return SCE_NP_MATCHING_ERROR_UTILITY_UNAVAILABLE;
if (false) // TODO
if (!nph.is_NP_init)
return SCE_NP_MATCHING_ERROR_NOT_INITIALIZED;
if (!room_id || !user_id || !req_id)
@@ -5658,11 +5641,6 @@ error_code scenp_score_record_score(s32 transId, SceNpScoreBoardId boardId, SceN
data_size = 64;
}
if (option)
{
return SCE_NP_COMMUNITY_ERROR_INVALID_ARGUMENT;
}
nph.record_score(trans_ctx, boardId, score, scoreComment, data, data_size, tmpRank, async);
if (async)
@@ -6230,7 +6208,7 @@ error_code sceNpScoreGetRankingByNpIdPcIdAsync(s32 transId, SceNpScoreBoardId bo
error_code sceNpScoreAbortTransaction(s32 transId)
{
sceNp.todo("sceNpScoreAbortTransaction(transId=%d)", transId);
sceNp.warning("sceNpScoreAbortTransaction(transId=%d)", transId);
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
+96 -1
View File
@@ -677,6 +677,17 @@ enum
SCE_NP_MATCHING_ATTR_TYPE_GAME_NUM = 4,
};
enum
{
SCE_NP_MATCHING_ATTR_ID_MIN = 1,
SCE_NP_MATCHING_ATTR_ID_MAX = 16,
SCE_NP_MATCHING_ATTR_ID_FOR_SEARCH_CONDITION_MAX = 8,
SCE_NP_MATCHING_ATTR_ID_FOR_GRLGLIMIT_SRCH_COND_MAX = 8,
SCE_NP_MATCHING_ATTR_BIN_BIG_SIZE_ID_MAX = 2,
SCE_NP_MATCHING_ATTR_BIN_MAX_SIZE_SMALL = 64,
SCE_NP_MATCHING_ATTR_BIN_MAX_SIZE_BIG = 256,
};
enum
{
SCE_NP_MATCHING_ROOM_ATTR_ID_TOTAL_SLOT = 1,
@@ -686,6 +697,7 @@ enum
SCE_NP_MATCHING_ROOM_ATTR_ID_CUR_PRIVATE_NUM = 5,
SCE_NP_MATCHING_ROOM_ATTR_ID_PRIVILEGE_TYPE = 6,
SCE_NP_MATCHING_ROOM_ATTR_ID_ROOM_SEARCH_FLAG = 7,
SCE_NP_MATCHING_ROOM_ATTR_ID_MAX = 8,
};
enum
@@ -706,6 +718,13 @@ enum
SCE_NP_MATCHING_ROOM_SEARCH_FLAG_STEALTH = 1,
};
enum
{
SCE_NP_MATCHING_COND_MAX = 9,
SCE_NP_MATCHING_GRLG_LIMIT_COND_MAX = 9,
SCE_NP_MATCHING_COMP_OP_INEQUALITY_MAX = 9,
};
enum
{
SCE_NP_MATCHING_CONDITION_SEARCH_EQ = 0,
@@ -714,6 +733,7 @@ enum
SCE_NP_MATCHING_CONDITION_SEARCH_LE = 3,
SCE_NP_MATCHING_CONDITION_SEARCH_GT = 4,
SCE_NP_MATCHING_CONDITION_SEARCH_GE = 5,
SCE_NP_MATCHING_CONDITION_SEARCH_MAX = 6,
};
enum
@@ -724,6 +744,19 @@ enum
enum
{
SCE_NP_MATCHING_INVITATION_DESTINATION_MAX = 12,
SCE_NP_MATCHING_INVITATION_SUBJECT_MAX_CHARS = 16,
SCE_NP_MATCHING_INVITATION_BODY_MAX_CHARS = 128,
SCE_NP_MATCHING_KICK_OPT_MAX_LENGTH = 16,
SCE_NP_MATCHING_ROOM_MAX_SLOT = 16,
SCE_NP_MATCHING_CTX_MAX = 8,
};
enum
{
SCE_NP_MATCHING_SEND_INVITATION_MEMSIZE = 16 * 1024 * 1024,
SCE_NP_MATCHING_ACCEPT_INVITATION_MEMSIZE = 16 * 1024 * 1024,
};
// Basic presence options
@@ -1170,7 +1203,7 @@ enum
SCE_NP_MATCHING_GUI_EVENT_ACCEPT_INVITATION = 0x0007,
SCE_NP_MATCHING_GUI_EVENT_COMMON_LOAD = 0x0008,
SCE_NP_MATCHING_GUI_EVENT_COMMON_UNLOAD = 0x0009,
SCE_NP_MATCHING_GUI_EVENT_RESERVED3 = 0x000a,
SCE_NP_MATCHING_GUI_EVENT_GET_ROOM_LIST = 0x000a,
SCE_NP_MATCHING_GUI_EVENT_GET_ROOM_LIST_LIMIT = 0x000b
};
@@ -1697,6 +1730,59 @@ struct SceNpScoreRecordOptParam
vm::bptr<CellRtcTick> reserved;
};
// Old GUI API structures
struct SceNpMatchingRoomMember
{
vm::bptr<SceNpMatchingRoomMember> next;
SceNpUserInfo user_info;
be_t<s32> owner;
};
struct SceNpMatchingRoomStatus
{
SceNpRoomId id;
vm::bptr<SceNpMatchingRoomMember> members;
be_t<s32> num;
vm::bptr<SceNpId> kick_actor;
vm::bptr<void> opt;
be_t<s32> opt_len;
};
struct SceNpMatchingJoinedRoomInfo
{
SceNpLobbyId lobbyid;
SceNpMatchingRoomStatus room_status;
};
struct SceNpMatchingRange
{
be_t<u32> start;
be_t<u32> results;
be_t<u32> total;
};
struct SceNpMatchingRoom
{
vm::bptr<SceNpMatchingRoom> next;
SceNpRoomId id;
vm::bptr<SceNpMatchingAttr> attr;
};
struct SceNpMatchingRoomList
{
SceNpLobbyId lobbyid;
SceNpMatchingRange range;
vm::bptr<SceNpMatchingRoom> head;
};
struct SceNpMatchingSearchJoinRoomInfo
{
SceNpLobbyId lobbyid;
SceNpMatchingRoomStatus room_status;
vm::bptr<SceNpMatchingAttr> attr;
};
// NP callback functions
using SceNpCustomMenuEventHandler = s32(s32 retCode, u32 index, vm::cptr<SceNpId> npid, SceNpCustomMenuSelectedType type, vm::ptr<void> arg);
using SceNpBasicEventHandler = s32(s32 event, s32 retCode, u32 reqId, vm::ptr<void> arg);
@@ -1756,3 +1842,12 @@ public:
protected:
std::shared_ptr<rpcn::rpcn_client> m_rpcn;
};
// Generic functions, also used in SceNpMatchingInt.cpp
error_code matching_create_room(u32 ctx_id, vm::cptr<SceNpCommunicationId> communicationId, vm::cptr<SceNpMatchingAttr> attr, vm::ptr<SceNpMatchingGUIHandler> handler, vm::ptr<void> arg);
error_code matching_join_room(u32 ctx_id, vm::ptr<SceNpRoomId> room_id, vm::ptr<SceNpMatchingGUIHandler> handler, vm::ptr<void> arg);
error_code matching_get_room_list(u32 ctx_id, vm::ptr<SceNpCommunicationId> communicationId, vm::ptr<SceNpMatchingReqRange> range, vm::ptr<SceNpMatchingSearchCondition> cond,
vm::ptr<SceNpMatchingAttr> attr, vm::ptr<SceNpMatchingGUIHandler> handler, vm::ptr<void> arg, bool limit);
error_code matching_set_room_info(u32 ctx_id, vm::ptr<SceNpLobbyId> lobby_id, vm::ptr<SceNpRoomId> room_id, vm::ptr<SceNpMatchingAttr> attr, vm::ptr<u32> req_id, bool limit);
error_code matching_get_room_info(u32 ctx_id, vm::ptr<SceNpLobbyId> lobby_id, vm::ptr<SceNpRoomId> room_id, vm::ptr<SceNpMatchingAttr> attr, vm::ptr<u32> req_id, bool limit);
error_code matching_get_room_member_list(u32 ctx_id, vm::ptr<SceNpRoomId> room_id, vm::ptr<u32> buflen, vm::ptr<void> buf);
+13 -6
View File
@@ -576,9 +576,9 @@ error_code sceNpMatching2ContextStart(SceNpMatching2ContextId ctxId)
if (ctx->context_callback)
{
sysutil_register_cb([=](ppu_thread& cb_ppu) -> s32
sysutil_register_cb([=, context_callback = ctx->context_callback, context_callback_param = ctx->context_callback_param](ppu_thread& cb_ppu) -> s32
{
ctx->context_callback(cb_ppu, ctxId, SCE_NP_MATCHING2_CONTEXT_EVENT_Start, SCE_NP_MATCHING2_EVENT_CAUSE_CONTEXT_ACTION, 0, ctx->context_callback_param);
context_callback(cb_ppu, ctxId, SCE_NP_MATCHING2_CONTEXT_EVENT_Start, SCE_NP_MATCHING2_EVENT_CAUSE_CONTEXT_ACTION, 0, context_callback_param);
return 0;
});
}
@@ -1106,9 +1106,9 @@ error_code sceNpMatching2ContextStartAsync(SceNpMatching2ContextId ctxId, u32 ti
if (ctx->context_callback)
{
sysutil_register_cb([=](ppu_thread& cb_ppu) -> s32
sysutil_register_cb([=, context_callback = ctx->context_callback, context_callback_param = ctx->context_callback_param](ppu_thread& cb_ppu) -> s32
{
ctx->context_callback(cb_ppu, ctxId, SCE_NP_MATCHING2_CONTEXT_EVENT_Start, SCE_NP_MATCHING2_EVENT_CAUSE_CONTEXT_ACTION, 0, ctx->context_callback_param);
context_callback(cb_ppu, ctxId, SCE_NP_MATCHING2_CONTEXT_EVENT_Start, SCE_NP_MATCHING2_EVENT_CAUSE_CONTEXT_ACTION, 0, ctx->context_callback_param);
return 0;
});
}
@@ -1656,6 +1656,13 @@ error_code sceNpMatching2GetLobbyInfoList(
return res;
}
const u32 request_id = nph.get_lobby_info_list(ctxId, optParam, reqParam.get_ptr());
if (assignedReqId)
{
*assignedReqId = request_id;
}
return CELL_OK;
}
@@ -1709,9 +1716,9 @@ error_code sceNpMatching2ContextStop(SceNpMatching2ContextId ctxId)
if (ctx->context_callback)
{
sysutil_register_cb([=](ppu_thread& cb_ppu) -> s32
sysutil_register_cb([=, context_callback = ctx->context_callback, context_callback_param = ctx->context_callback_param](ppu_thread& cb_ppu) -> s32
{
ctx->context_callback(cb_ppu, ctxId, SCE_NP_MATCHING2_CONTEXT_EVENT_Stop, SCE_NP_MATCHING2_EVENT_CAUSE_CONTEXT_ACTION, 0, ctx->context_callback_param);
context_callback(cb_ppu, ctxId, SCE_NP_MATCHING2_CONTEXT_EVENT_Stop, SCE_NP_MATCHING2_EVENT_CAUSE_CONTEXT_ACTION, 0, context_callback_param);
return 0;
});
}
+4 -4
View File
@@ -220,9 +220,9 @@ error_code sceNpCommerce2EmptyStoreCheckStart(u32 ctx_id, s32 store_check_type,
if (ctx->context_callback)
{
sysutil_register_cb([=](ppu_thread& cb_ppu) -> s32
sysutil_register_cb([=, context_callback = ctx->context_callback, context_callback_param = ctx->context_callback_param](ppu_thread& cb_ppu) -> s32
{
ctx->context_callback(cb_ppu, ctx_id, 0, SCE_NP_COMMERCE2_EVENT_EMPTY_STORE_CHECK_DONE, 0, ctx->context_callback_param);
context_callback(cb_ppu, ctx_id, 0, SCE_NP_COMMERCE2_EVENT_EMPTY_STORE_CHECK_DONE, 0, context_callback_param);
return 0;
});
}
@@ -276,9 +276,9 @@ error_code sceNpCommerce2CreateSessionStart(u32 ctx_id)
if (ctx->context_callback)
{
sysutil_register_cb([=](ppu_thread& cb_ppu) -> s32
sysutil_register_cb([=, context_callback = ctx->context_callback, context_callback_param = ctx->context_callback_param](ppu_thread& cb_ppu) -> s32
{
ctx->context_callback(cb_ppu, ctx_id, 0, SCE_NP_COMMERCE2_EVENT_CREATE_SESSION_DONE, 0, ctx->context_callback_param);
context_callback(cb_ppu, ctx_id, 0, SCE_NP_COMMERCE2_EVENT_CREATE_SESSION_DONE, 0, context_callback_param);
return 0;
});
}
+42 -34
View File
@@ -1,10 +1,6 @@
#include "stdafx.h"
#include "Emu/Cell/PPUModule.h"
// Temporarily
#ifndef _MSC_VER
#pragma GCC diagnostic ignored "-Wunused-parameter"
#endif
#include "sceNp.h"
LOG_CHANNEL(sceNpMatchingInt);
@@ -14,48 +10,55 @@ error_code sceNpMatchingCancelRequest()
return CELL_OK;
}
error_code sceNpMatchingGetRoomMemberList()
error_code sceNpMatchingGetRoomMemberList(u32 ctx_id, vm::ptr<SceNpRoomId> room_id, vm::ptr<u32> buflen, vm::ptr<void> buf)
{
UNIMPLEMENTED_FUNC(sceNpMatchingInt);
return CELL_OK;
sceNpMatchingInt.warning("sceNpMatchingGetRoomMemberList(ctx_id=%d, room_id=*0x%x, buflen=*0x%x, buf=*0x%x)", ctx_id, room_id, buflen, buf);
return matching_get_room_member_list(ctx_id, room_id, buflen, buf);
}
error_code sceNpMatchingJoinRoomWithoutGUI()
error_code sceNpMatchingJoinRoomWithoutGUI(u32 ctx_id, vm::ptr<SceNpRoomId> room_id, vm::ptr<SceNpMatchingGUIHandler> handler, vm::ptr<void> arg)
{
UNIMPLEMENTED_FUNC(sceNpMatchingInt);
return CELL_OK;
sceNpMatchingInt.warning("sceNpMatchingJoinRoomWithoutGUI(ctx_id=%d, room_id=*0x%x, handler=*0x%x, arg=*0x%x)", ctx_id, room_id, handler, arg);
return matching_join_room(ctx_id, room_id, handler, arg);
}
// Parameter "unknown" added to distinguish this function
// from the one in sceNp.cpp which has the same name
error_code sceNpMatchingJoinRoomGUI(vm::ptr<void> unknown)
error_code OLD_sceNpMatchingJoinRoomGUI(u32 ctx_id, vm::ptr<SceNpRoomId> room_id, vm::ptr<SceNpMatchingGUIHandler> handler, vm::ptr<void> arg)
{
UNIMPLEMENTED_FUNC(sceNpMatchingInt);
return CELL_OK;
sceNpMatchingInt.warning("OLD_sceNpMatchingJoinRoomGUI(ctx_id=%d, room_id=*0x%x, handler=*0x%x, arg=*0x%x)", ctx_id, room_id, handler, arg);
return matching_join_room(ctx_id, room_id, handler, arg);
}
error_code sceNpMatchingSetRoomInfoNoLimit(vm::ptr<void> unknown)
error_code OLD_sceNpMatchingSetRoomInfoNoLimit(u32 ctx_id, vm::ptr<SceNpLobbyId> lobby_id, vm::ptr<SceNpRoomId> room_id, vm::ptr<SceNpMatchingAttr> attr, vm::ptr<u32> req_id)
{
UNIMPLEMENTED_FUNC(sceNpMatchingInt);
return CELL_OK;
sceNpMatchingInt.warning("OLD_sceNpMatchingSetRoomInfoNoLimit(ctx_id=%d, lobby_id=*0x%x, room_id=*0x%x, attr=*0x%x, req_id=*0x%x)", ctx_id, lobby_id, room_id, attr, req_id);
return matching_set_room_info(ctx_id, lobby_id, room_id, attr, req_id, false);
}
error_code sceNpMatchingGetRoomListWithoutGUI()
error_code sceNpMatchingGetRoomListWithoutGUI(u32 ctx_id, vm::ptr<SceNpCommunicationId> communicationId, vm::ptr<SceNpMatchingReqRange> range, vm::ptr<SceNpMatchingSearchCondition> cond,
vm::ptr<SceNpMatchingAttr> attr, vm::ptr<SceNpMatchingGUIHandler> handler, vm::ptr<void> arg)
{
UNIMPLEMENTED_FUNC(sceNpMatchingInt);
return CELL_OK;
sceNpMatchingInt.warning("sceNpMatchingGetRoomListWithoutGUI(ctx_id=%d, communicationId=*0x%x, range=*0x%x, cond=*0x%x, attr=*0x%x, handler=*0x%x, arg=*0x%x)", ctx_id, communicationId, range, cond, attr, handler, arg);
return matching_get_room_list(ctx_id, communicationId, range, cond, attr, handler, arg, false);
}
error_code sceNpMatchingGetRoomListGUI()
error_code sceNpMatchingGetRoomListGUI(u32 ctx_id, vm::ptr<SceNpCommunicationId> communicationId, vm::ptr<SceNpMatchingReqRange> range, vm::ptr<SceNpMatchingSearchCondition> cond,
vm::ptr<SceNpMatchingAttr> attr, vm::ptr<SceNpMatchingGUIHandler> handler, vm::ptr<void> arg)
{
UNIMPLEMENTED_FUNC(sceNpMatchingInt);
return CELL_OK;
sceNpMatchingInt.warning("sceNpMatchingGetRoomListGUI(ctx_id=%d, communicationId=*0x%x, range=*0x%x, cond=*0x%x, attr=*0x%x, handler=*0x%x, arg=*0x%x)", ctx_id, communicationId, range, cond, attr, handler, arg);
return matching_get_room_list(ctx_id, communicationId, range, cond, attr, handler, arg, false);
}
error_code sceNpMatchingGetRoomInfoNoLimit(vm::ptr<void> unknown)
error_code OLD_sceNpMatchingGetRoomInfoNoLimit(u32 ctx_id, vm::ptr<SceNpLobbyId> lobby_id, vm::ptr<SceNpRoomId> room_id, vm::ptr<SceNpMatchingAttr> attr, vm::ptr<u32> req_id)
{
UNIMPLEMENTED_FUNC(sceNpMatchingInt);
return CELL_OK;
sceNpMatchingInt.warning("OLD_sceNpMatchingGetRoomInfoNoLimit(ctx_id=%d, lobby_id=*0x%x, room_id=*0x%x, attr=*0x%x, req_id=*0x%x)", ctx_id, lobby_id, room_id, attr, req_id);
return matching_get_room_info(ctx_id, lobby_id, room_id, attr, req_id, false);
}
error_code sceNpMatchingCancelRequestGUI()
@@ -70,22 +73,27 @@ error_code sceNpMatchingSendRoomMessage()
return CELL_OK;
}
error_code sceNpMatchingCreateRoomWithoutGUI()
error_code sceNpMatchingCreateRoomWithoutGUI(u32 ctx_id, vm::cptr<SceNpCommunicationId> communicationId, vm::cptr<SceNpMatchingAttr> attr, vm::ptr<SceNpMatchingGUIHandler> handler, vm::ptr<void> arg)
{
UNIMPLEMENTED_FUNC(sceNpMatchingInt);
return CELL_OK;
sceNpMatchingInt.warning("sceNpMatchingCreateRoomWithoutGUI(ctx_id=%d, communicationId=*0x%x, attr=*0x%x, handler=*0x%x, arg=*0x%x)", ctx_id, communicationId, attr, handler, arg);
return matching_create_room(ctx_id, communicationId, attr, handler, arg);
}
// This module has some conflicting function names with sceNp module, hence the REG_FNID
DECLARE(ppu_module_manager::sceNpMatchingInt)("sceNpMatchingInt", []()
{
REG_FUNC(sceNpMatchingInt, sceNpMatchingCancelRequest);
REG_FUNC(sceNpMatchingInt, sceNpMatchingGetRoomMemberList);
REG_FUNC(sceNpMatchingInt, sceNpMatchingJoinRoomWithoutGUI);
REG_FUNC(sceNpMatchingInt, sceNpMatchingJoinRoomGUI);
REG_FUNC(sceNpMatchingInt, sceNpMatchingSetRoomInfoNoLimit);
// REG_FUNC(sceNpMatchingInt, sceNpMatchingJoinRoomGUI);
REG_FNID(sceNpMatchingInt, "sceNpMatchingJoinRoomGUI", OLD_sceNpMatchingJoinRoomGUI);
// REG_FUNC(sceNpMatchingInt, sceNpMatchingSetRoomInfoNoLimit);
REG_FNID(sceNpMatchingInt, "sceNpMatchingSetRoomInfoNoLimit", OLD_sceNpMatchingSetRoomInfoNoLimit);
REG_FUNC(sceNpMatchingInt, sceNpMatchingGetRoomListWithoutGUI);
REG_FUNC(sceNpMatchingInt, sceNpMatchingGetRoomListGUI);
REG_FUNC(sceNpMatchingInt, sceNpMatchingGetRoomInfoNoLimit);
// REG_FUNC(sceNpMatchingInt, sceNpMatchingGetRoomInfoNoLimit);
REG_FNID(sceNpMatchingInt, "sceNpMatchingGetRoomInfoNoLimit", OLD_sceNpMatchingGetRoomInfoNoLimit);
REG_FUNC(sceNpMatchingInt, sceNpMatchingCancelRequestGUI);
REG_FUNC(sceNpMatchingInt, sceNpMatchingSendRoomMessage);
REG_FUNC(sceNpMatchingInt, sceNpMatchingCreateRoomWithoutGUI);
+1 -1
View File
@@ -572,7 +572,7 @@ error_code sceNpTrophyRegisterContext(ppu_thread& ppu, u32 context, u32 handle,
{
if (!!(options & SCE_NP_TROPHY_OPTIONS_REGISTER_CONTEXT_SHOW_ERROR_EXIT))
{
static_cast<void>(open_exit_dialog("Error during trophy registration! The game will now be terminated.", true));
static_cast<void>(open_exit_dialog("Error during trophy registration! The game will now be terminated.", true, msg_dialog_source::_sceNpTrophy));
}
};
+1
View File
@@ -184,6 +184,7 @@ static void ppu_initialize_modules(ppu_linkage_info* link, utils::serial* ar = n
&ppu_module_manager::cellAdec,
&ppu_module_manager::cellAtrac,
&ppu_module_manager::cellAtracMulti,
&ppu_module_manager::cellAtracXdec,
&ppu_module_manager::cellAudio,
&ppu_module_manager::cellAvconfExt,
&ppu_module_manager::cellAuthDialogUtility,
+1
View File
@@ -168,6 +168,7 @@ public:
static const ppu_static_module cellAdec;
static const ppu_static_module cellAtrac;
static const ppu_static_module cellAtracMulti;
static const ppu_static_module cellAtracXdec;
static const ppu_static_module cellAudio;
static const ppu_static_module cellAvconfExt;
static const ppu_static_module cellAuthDialogUtility;
+19 -9
View File
@@ -7,20 +7,30 @@
inline void try_start(spu_thread& spu)
{
reader_lock lock(spu.run_ctrl_mtx);
bool notify = false;
if (spu.status_npc.fetch_op([](spu_thread::status_npc_sync_var& value)
if (~spu.status_npc.load().status & SPU_STATUS_RUNNING)
{
if (value.status & SPU_STATUS_RUNNING)
reader_lock lock(spu.run_ctrl_mtx);
if (spu.status_npc.fetch_op([](spu_thread::status_npc_sync_var& value)
{
return false;
}
if (value.status & SPU_STATUS_RUNNING)
{
return false;
}
value.status = SPU_STATUS_RUNNING | (value.status & SPU_STATUS_IS_ISOLATED);
return true;
}).second)
value.status = SPU_STATUS_RUNNING | (value.status & SPU_STATUS_IS_ISOLATED);
return true;
}).second)
{
spu.state -= cpu_flag::stop;
notify = true;
}
}
if (notify)
{
spu.state -= cpu_flag::stop;
spu.state.notify_one();
}
};
+223 -223
View File
@@ -5028,8 +5028,8 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
}
auto& vregs = is_form_block ? infos[bpc]->local_state : *true_state_walkby;
auto& atomic16 = is_pattern_match ? ::at32(reg_state_it, wi).atomic16 : dummy16;
auto& rchcnt_loop = is_pattern_match ? ::at32(reg_state_it, wi).rchcnt_loop : dummy_loop;
const auto atomic16 = is_pattern_match ? &::at32(reg_state_it, wi).atomic16 : &dummy16;
const auto rchcnt_loop = is_pattern_match ? &::at32(reg_state_it, wi).rchcnt_loop : &dummy_loop;
const u32 pos = wa;
@@ -5153,8 +5153,8 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
const auto break_all_patterns = [&](u32 cause)
{
break_putllc16(cause, atomic16.discard());
break_channel_pattern(cause, rchcnt_loop.discard());
break_putllc16(cause, atomic16->discard());
break_channel_pattern(cause, rchcnt_loop->discard());
};
const auto calculate_absolute_ls_difference = [](u32 addr1, u32 addr2)
@@ -5188,7 +5188,7 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
auto& block = infos[bpc];
if (g_cfg.core.spu_block_size != spu_block_size_type::safe && (m_ret_info[bpc / 4] || m_entry_info[bpc / 4] || pos == entry_point))
if (pos == entry_point || (g_cfg.core.spu_block_size != spu_block_size_type::safe && (m_ret_info[bpc / 4] || m_entry_info[bpc / 4])))
{
// Do not allow value passthrough
for (reg_state_t& f : block->start_reg_state)
@@ -5429,6 +5429,18 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
}
}
if (wi != stackframe_it || may_return || !insert_entry)
{
// Possible function end
if (rchcnt_loop->active)
{
// Does not post-dominates channel reads
auto& pair = rchcnt_loop_all[rchcnt_loop->read_pc];
pair.failed = true;
pair.active = false;
}
}
// Backup analyser information
const auto atomic16_info = reg_state_it[stackframe_it].atomic16;
const auto rchcnt_loop_info = reg_state_it[stackframe_it].rchcnt_loop;
@@ -5450,18 +5462,6 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
}
}
if (wi != stackframe_it || may_return || !insert_entry)
{
// Possible function end
if (rchcnt_loop.active)
{
// Does not post-dominates channel reads
auto& pair = rchcnt_loop_all[rchcnt_loop.read_pc];
pair.failed = true;
pair.active = false;
}
}
if (insert_entry)
{
const usz target_size = get_block_targets(stackframe_pc).size();
@@ -5484,10 +5484,10 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
break_putllc16(39, atomic16_info);
}
if (rchcnt_loop.active)
if (rchcnt_loop_info.active)
{
// Does not post-dominates channel read
auto& pair = rchcnt_loop_all[rchcnt_loop.read_pc];
auto& pair = rchcnt_loop_all[rchcnt_loop_info.read_pc];
pair.failed = true;
pair.active = false;
}
@@ -5648,20 +5648,20 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
}
}
if (atomic16.active)
if (atomic16->active)
{
for (auto state : {&atomic16.lsa, &atomic16.ls, &atomic16.ls_offs})
for (auto state : {&atomic16->lsa, &atomic16->ls, &atomic16->ls_offs})
{
state->invalidate_if_created(pos);
}
}
if (rchcnt_loop.active)
if (rchcnt_loop->active)
{
if (rchcnt_loop.origins.find_first_of(pos) != umax)
if (rchcnt_loop->origins.find_first_of(pos) != umax)
{
rchcnt_loop.failed = true;
rchcnt_loop.active = false;
rchcnt_loop->failed = true;
rchcnt_loop->active = false;
}
}
@@ -5719,7 +5719,7 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
dis_asm.last_opcode.pop_back();
}
spu_log.always()("[SPU=0%x, it=%d] %s%s [%d]", pos, reg_state_it[wi].iterator_id, dis_asm.last_opcode, consts, atomic16.active);
spu_log.always()("[SPU=0%x, it=%d] %s%s [%d]", pos, reg_state_it[wi].iterator_id, dis_asm.last_opcode, consts, atomic16->active);
}
// Analyse instruction
@@ -5798,22 +5798,22 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
const u32 next_pc = spu_branch_target(pos, 1);
const u32 target = spu_branch_target(pos, op.i16);
if (rchcnt_loop.active)
if (rchcnt_loop->active)
{
const reg_state_t& rt = vregs[op.rt];
if (rt.is_instruction && (rchcnt_loop.ch_state.origin == rt.origin || rchcnt_loop.ch_product.origin == rt.origin))
if (rt.is_instruction && (rchcnt_loop->ch_state.origin == rt.origin || rchcnt_loop->ch_product.origin == rt.origin))
{
if (rchcnt_loop.conditioned)
if (rchcnt_loop->conditioned)
{
// Let's not make it complicated, have a single branch determining the condition
break_channel_pattern(54, rchcnt_loop.discard());
break_channel_pattern(54, rchcnt_loop->discard());
break;
}
rchcnt_loop.conditioned = true;
rchcnt_loop.branch_pc = pos;
rchcnt_loop.branch_target = rchcnt_loop.product_test_negate != (type == spu_itype::BRZ) ? target : next_pc;
rchcnt_loop->conditioned = true;
rchcnt_loop->branch_pc = pos;
rchcnt_loop->branch_target = rchcnt_loop->product_test_negate != (type == spu_itype::BRZ) ? target : next_pc;
break;
}
}
@@ -5845,7 +5845,7 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
case spu_itype::WRCH:
{
break_channel_pattern(56, rchcnt_loop.discard());
break_channel_pattern(56, rchcnt_loop->discard());
switch (op.ra)
{
@@ -5861,7 +5861,7 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
if (is_pattern_match)
{
atomic16.lsa_last_pc = pos;
atomic16->lsa_last_pc = pos;
}
break;
@@ -5897,27 +5897,27 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
auto lsa = get_reg(s_reg_mfc_lsa);
vregs[s_reg_mfc_lsa] = old_lsa;
const u32 lsa_pc = atomic16.lsa_last_pc == SPU_LS_SIZE ? bpc : atomic16.lsa_last_pc;
const u32 lsa_pc = atomic16->lsa_last_pc == SPU_LS_SIZE ? bpc : atomic16->lsa_last_pc;
if (atomic16.active)
if (atomic16->active)
{
if (atomic16.lsa_pc != lsa_pc || atomic16.get_pc != pos || atomic16.lsa != lsa)
if (atomic16->lsa_pc != lsa_pc || atomic16->get_pc != pos || atomic16->lsa != lsa)
{
break_putllc16(30, atomic16.discard());
break_putllc16(30, atomic16->discard());
}
}
// If LSA write has not happened, use block start
atomic16.lsa_pc = lsa_pc;
atomic16.get_pc = pos;
atomic16.active = true;
atomic16->lsa_pc = lsa_pc;
atomic16->get_pc = pos;
atomic16->active = true;
atomic16.lsa = lsa;
atomic16->lsa = lsa;
if (likely_putllc_loop)
{
// Register loop entry
if (getllar_starts.emplace(atomic16.lsa_pc, false).second)
if (getllar_starts.emplace(atomic16->lsa_pc, false).second)
{
g_fxo->get<putllc16_statistics_t>().all++;
spu_log.notice("[0x%05x] GETLLAR pattern entry point", pos);
@@ -5928,17 +5928,17 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
}
case MFC_PUTLLC_CMD:
{
if (atomic16.active)
if (atomic16->active)
{
const auto _lsa = get_reg(s_reg_mfc_lsa);
// Search the value of LS address stoire/load in latest register file
if (atomic16.ls_access && atomic16.ls_write && !atomic16.ls_pc_rel && !atomic16.ls.is_const())
if (atomic16->ls_access && atomic16->ls_write && !atomic16->ls_pc_rel && !atomic16->ls.is_const())
{
usz reg_it = umax;
u32 regs[2]{s_reg_max, s_reg_max};
for (auto val : {&atomic16.ls, &atomic16.ls_offs})
for (auto val : {&atomic16->ls, &atomic16->ls_offs})
{
reg_it++;
@@ -5968,68 +5968,68 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
if (regs[0] == s_reg_max || regs[1] == s_reg_max)
{
break_putllc16(3, atomic16.discard());
break_putllc16(3, atomic16->discard());
break;
}
atomic16.reg = regs[0];
atomic16->reg = regs[0];
if (!atomic16.ls_offs.is_const())
if (!atomic16->ls_offs.is_const())
{
atomic16.reg2 = regs[1];
atomic16->reg2 = regs[1];
}
}
if (atomic16.ls_access && atomic16.ls_write && !atomic16.lsa.compare_with_mask_indifference(_lsa, SPU_LS_MASK_128))
if (atomic16->ls_access && atomic16->ls_write && !atomic16->lsa.compare_with_mask_indifference(_lsa, SPU_LS_MASK_128))
{
// LSA latest value mismatches with the one written with GETLLAR
if (atomic16.lsa.flag != _lsa.flag)
if (atomic16->lsa.flag != _lsa.flag)
{
break_putllc16(1, atomic16.discard());
break_putllc16(1, atomic16->discard());
}
else
{
break_putllc16(2, atomic16.discard());
break_putllc16(2, atomic16->discard());
}
break;
}
if (atomic16.ls_access && atomic16.ls_write)
if (atomic16->ls_access && atomic16->ls_write)
{
atomic16.select_16_or_0_at_runtime = false;
atomic16->select_16_or_0_at_runtime = false;
bool ok = false;
if (atomic16.ls_pc_rel || !atomic16.ls_offs.is_const())
if (atomic16->ls_pc_rel || !atomic16->ls_offs.is_const())
{
//
}
else if (atomic16.lsa.is_const())
else if (atomic16->lsa.is_const())
{
if (atomic16.ls.is_const())
if (atomic16->ls.is_const())
{
if (atomic16.ls_offs.value != 0)
if (atomic16->ls_offs.value != 0)
{
// Rebase constant so we can get rid of ls_offs
atomic16.ls.value = spu_ls_target(atomic16.ls_offs.value + atomic16.ls.value);
atomic16.ls_offs = reg_state_t::from_value(0);
atomic16->ls.value = spu_ls_target(atomic16->ls_offs.value + atomic16->ls.value);
atomic16->ls_offs = reg_state_t::from_value(0);
}
if (atomic16.ls.compare_with_mask_indifference(atomic16.lsa, SPU_LS_MASK_128))
if (atomic16->ls.compare_with_mask_indifference(atomic16->lsa, SPU_LS_MASK_128))
{
ok = true;
}
}
else if (atomic16.ls_offs.compare_with_mask_indifference(atomic16.lsa, SPU_LS_MASK_128) && atomic16.ls.is_less_than(128 - (atomic16.ls_offs.value & 127)))
else if (atomic16->ls_offs.compare_with_mask_indifference(atomic16->lsa, SPU_LS_MASK_128) && atomic16->ls.is_less_than(128 - (atomic16->ls_offs.value & 127)))
{
// Relative memory access with offset less than 128 bytes
// Common around SPU utilities which have less strict restrictions about memory alignment
ok = true;
}
}
else if (atomic16.lsa.compare_with_mask_indifference(atomic16.ls, SPU_LS_MASK_128) && atomic16.ls_offs == 0)
else if (atomic16->lsa.compare_with_mask_indifference(atomic16->ls, SPU_LS_MASK_128) && atomic16->ls_offs == 0)
{
// Unknown value with known offset of less than 128 bytes
ok = true;
@@ -6039,37 +6039,37 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
{
// This is quite common.. let's try to select between putllc16 and putllc0 at runtime!
// break_putllc16(100);
// atomic16.discard();
// atomic16->discard();
// break;
atomic16.select_16_or_0_at_runtime = true;
atomic16->select_16_or_0_at_runtime = true;
}
}
if (!atomic16.get_rdatomic)
if (!atomic16->get_rdatomic)
{
// MFC_RdAtomicStat must have been read, otherwise GETLLAR may not be executed (according to HW tests)
break_putllc16(21, atomic16.discard());
break_putllc16(21, atomic16->discard());
}
atomic16.put_pc = pos;
atomic16.put_active = true;
atomic16->put_pc = pos;
atomic16->put_active = true;
}
break;
}
default:
{
break_putllc16(4, atomic16.discard());
break_putllc16(4, atomic16->discard());
break;
}
}
}
else
{
break_putllc16(5, atomic16.discard());
break_putllc16(5, atomic16->discard());
}
if (!atomic16.active)
if (!atomic16->active)
{
// Propagate failure
for (auto& atm : atomic16_all)
@@ -6113,7 +6113,7 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
if (it != rchcnt_loop_all.end())
{
if (rchcnt_loop.failed || !rchcnt_loop.conditioned || rchcnt_loop.read_pc != pos)
if (rchcnt_loop->failed || !rchcnt_loop->conditioned || rchcnt_loop->read_pc != pos)
{
// Propagate faiure
it->second.failed = true;
@@ -6125,14 +6125,14 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
it->second.active = false;
}
rchcnt_loop.active = false;
rchcnt_loop->active = false;
}
if (rchcnt_loop.active)
if (rchcnt_loop->active)
{
if (rchcnt_loop.read_pc != pos)
if (rchcnt_loop->read_pc != pos)
{
break_channel_pattern(53, rchcnt_loop.discard());
break_channel_pattern(53, rchcnt_loop->discard());
}
}
@@ -6145,13 +6145,13 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
break;
}
if (atomic16.active)
if (atomic16->active)
{
if (atomic16.put_active)
if (atomic16->put_active)
{
if (getllar_starts.contains(atomic16.lsa_pc) && getllar_starts[atomic16.lsa_pc])
if (getllar_starts.contains(atomic16->lsa_pc) && getllar_starts[atomic16->lsa_pc])
{
break_putllc16(24, atomic16.discard());
break_putllc16(24, atomic16->discard());
break;
}
@@ -6160,7 +6160,7 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
if (it == atomic16_all.end())
{
// Fresh new pattern detected in a single code path
atomic16_all.emplace(pos, atomic16);
atomic16_all.emplace(pos, *atomic16);
}
else if (it->second.active)
{
@@ -6178,53 +6178,53 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
return a.second == b.second;
};
if (existing.lsa_pc != atomic16.lsa_pc || existing.put_pc != atomic16.put_pc || !existing.lsa.compare_with_mask_indifference(atomic16.lsa, SPU_LS_MASK_128))
if (existing.lsa_pc != atomic16->lsa_pc || existing.put_pc != atomic16->put_pc || !existing.lsa.compare_with_mask_indifference(atomic16->lsa, SPU_LS_MASK_128))
{
// Register twice
break_putllc16(22, atomic16.discard());
break_putllc16(22, atomic16->discard());
break_putllc16(22, existing.discard());
}
if (existing.active && existing.ls_access && atomic16.ls_access && (!compare_tag_and_reg({&existing.ls, existing.reg}, {&atomic16.ls, atomic16.reg}) || existing.ls_offs != atomic16.ls_offs || existing.reg2 != atomic16.reg2))
if (existing.active && existing.ls_access && atomic16->ls_access && (!compare_tag_and_reg({&existing.ls, existing.reg}, {&atomic16->ls, atomic16->reg}) || existing.ls_offs != atomic16->ls_offs || existing.reg2 != atomic16->reg2))
{
// Conflicting loads with stores in more than one code path
break_putllc16(27, atomic16.set_invalid_ls(existing.ls_write || atomic16.ls_write));
break_putllc16(27, atomic16->set_invalid_ls(existing.ls_write || atomic16->ls_write));
if (!atomic16.active)
if (!atomic16->active)
{
existing.active = false;
}
}
if (existing.active && (existing.ls_write || atomic16.ls_write) && (existing.ls_invalid || atomic16.ls_invalid))
if (existing.active && (existing.ls_write || atomic16->ls_write) && (existing.ls_invalid || atomic16->ls_invalid))
{
// Conflicting loads with stores in more than one code path
break_putllc16(33, atomic16.discard());
break_putllc16(33, atomic16->discard());
existing.active = false;
existing.ls_invalid = true;
}
if (existing.active && !existing.ls_access && atomic16.ls_access)
if (existing.active && !existing.ls_access && atomic16->ls_access)
{
// Propagate LS access
existing.ls = atomic16.ls;
existing.reg = atomic16.reg;
existing.reg2 = atomic16.reg2;
existing.ls_offs = atomic16.ls_offs;
existing.ls = atomic16->ls;
existing.reg = atomic16->reg;
existing.reg2 = atomic16->reg2;
existing.ls_offs = atomic16->ls_offs;
}
existing.ls_write |= atomic16.ls_write;
existing.ls_invalid |= atomic16.ls_invalid;
existing.ls_access |= atomic16.ls_access;
existing.mem_count = std::max<u32>(existing.mem_count, atomic16.mem_count);
existing.select_16_or_0_at_runtime |= atomic16.select_16_or_0_at_runtime;
existing.ls_write |= atomic16->ls_write;
existing.ls_invalid |= atomic16->ls_invalid;
existing.ls_access |= atomic16->ls_access;
existing.mem_count = std::max<u32>(existing.mem_count, atomic16->mem_count);
existing.select_16_or_0_at_runtime |= atomic16->select_16_or_0_at_runtime;
}
atomic16.discard();
atomic16->discard();
}
else if (!atomic16.get_rdatomic)
else if (!atomic16->get_rdatomic)
{
atomic16.get_rdatomic = true;
atomic16->get_rdatomic = true;
// Go above and beyond and also set the constant for it
set_const_value(op.rt, MFC_GETLLAR_SUCCESS);
@@ -6244,34 +6244,34 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
{
if (is_read)
{
break_putllc16(28, atomic16.discard());
break_putllc16(28, atomic16->discard());
}
else
{
break_putllc16(29, atomic16.discard());
break_putllc16(29, atomic16->discard());
}
if (!is_pattern_match || is_read)
{
//
}
else if (!rchcnt_loop.active && it == rchcnt_loop_all.end())
else if (!rchcnt_loop->active && it == rchcnt_loop_all.end())
{
rchcnt_loop.read_pc = pos;
rchcnt_loop.channel = op.ra;
rchcnt_loop.active = true;
rchcnt_loop->read_pc = pos;
rchcnt_loop->channel = op.ra;
rchcnt_loop->active = true;
unconst(op.rt, pos);
rchcnt_loop.ch_state = vregs[op.rt];
rchcnt_loop->ch_state = vregs[op.rt];
invalidate = false;
}
else if (rchcnt_loop.active)
else if (rchcnt_loop->active)
{
// Success
rchcnt_loop.active = false;
rchcnt_loop->active = false;
if (it == rchcnt_loop_all.end())
{
rchcnt_loop_all.emplace(pos, rchcnt_loop);
rchcnt_loop_all.emplace(pos, *rchcnt_loop);
}
}
@@ -6295,20 +6295,20 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
{
const bool is_store = type == spu_itype::STQR;
if (atomic16.active)
if (atomic16->active)
{
atomic16.mem_count++;
atomic16->mem_count++;
// Do not clear lower 16 bytes addressing because the program can move on 4-byte basis
const u32 offs = spu_branch_target(pos - result.lower_bound, op.si16);
if (atomic16.lsa.is_const() && [&]()
if (atomic16->lsa.is_const() && [&]()
{
bool hack = false;
if (offs % 16 == 0 && (pos - result.lower_bound + op.si16 * 4) == offs)
{
const u32 reservation_bound = (atomic16.lsa.value | 127);
const u32 reservation_bound = (atomic16->lsa.value | 127);
const u32 min_offs = offs;
// Hack: assume there is no overflow in relative instruction offset
@@ -6325,37 +6325,37 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
{
// Ignore memory access in this case
}
else if (atomic16.ls_invalid && is_store)
else if (atomic16->ls_invalid && is_store)
{
break_putllc16(35, atomic16.set_invalid_ls(is_store));
break_putllc16(35, atomic16->set_invalid_ls(is_store));
}
else if (atomic16.ls_access && atomic16.ls != start_program_count)
else if (atomic16->ls_access && atomic16->ls != start_program_count)
{
break_putllc16(7, atomic16.set_invalid_ls(is_store));
break_putllc16(7, atomic16->set_invalid_ls(is_store));
}
else if (atomic16.ls_access && offs != atomic16.ls_offs)
else if (atomic16->ls_access && offs != atomic16->ls_offs)
{
if (atomic16.ls_offs.compare_with_mask_indifference(offs, SPU_LS_MASK_1))
if (atomic16->ls_offs.compare_with_mask_indifference(offs, SPU_LS_MASK_1))
{
atomic16.ls_write |= is_store;
atomic16->ls_write |= is_store;
}
else
{
// Sad
break_putllc16(8, atomic16.set_invalid_ls(is_store));
break_putllc16(8, atomic16->set_invalid_ls(is_store));
}
}
else
{
atomic16.ls = start_program_count;
atomic16.ls_offs = reg_state_t::from_value(offs);
atomic16.ls_pc_rel = true;
atomic16.ls_write |= is_store;
atomic16.ls_access = true;
atomic16->ls = start_program_count;
atomic16->ls_offs = reg_state_t::from_value(offs);
atomic16->ls_pc_rel = true;
atomic16->ls_write |= is_store;
atomic16->ls_access = true;
}
// atomic16.ls_reg[offs % 128 / 16] = start_program_count;
// atomic16.ls_offs[offs % 128 / 16] = offs;
// atomic16->ls_reg[offs % 128 / 16] = start_program_count;
// atomic16->ls_offs[offs % 128 / 16] = offs;
}
if (is_store)
@@ -6373,9 +6373,9 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
{
const bool is_store = type == spu_itype::STQX;
if (atomic16.active)
if (atomic16->active)
{
atomic16.mem_count++;
atomic16->mem_count++;
auto ra = get_reg(op.ra);
ra.value &= SPU_LS_MASK_1;
@@ -6393,37 +6393,37 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
add_res.value &= SPU_LS_MASK_16;
add_res.tag = umax;
if (atomic16.lsa.unequal_with_mask_indifference(add_res, SPU_LS_MASK_128))
if (atomic16->lsa.unequal_with_mask_indifference(add_res, SPU_LS_MASK_128))
{
// Unrelated, ignore
}
else if (atomic16.ls_invalid && is_store)
else if (atomic16->ls_invalid && is_store)
{
break_putllc16(20, atomic16.set_invalid_ls(is_store));
break_putllc16(20, atomic16->set_invalid_ls(is_store));
}
else if (atomic16.ls_access && add_res != atomic16.ls)
else if (atomic16->ls_access && add_res != atomic16->ls)
{
if (atomic16.ls.unequal_with_mask_indifference(add_res, SPU_LS_MASK_128) && atomic16.ls_offs == 0)
if (atomic16->ls.unequal_with_mask_indifference(add_res, SPU_LS_MASK_128) && atomic16->ls_offs == 0)
{
// Ok
}
else if (atomic16.ls_pc_rel)
else if (atomic16->ls_pc_rel)
{
break_putllc16(8, atomic16.set_invalid_ls(is_store));
break_putllc16(8, atomic16->set_invalid_ls(is_store));
}
else
{
// Sad
break_putllc16(9, atomic16.set_invalid_ls(is_store));
break_putllc16(9, atomic16->set_invalid_ls(is_store));
}
}
else
{
atomic16.ls = reg_state_t::from_value(add_res.value);
atomic16.ls_offs = reg_state_t::from_value(0);
atomic16.ls_pc_rel = false;
atomic16.ls_write |= is_store;
atomic16.ls_access = true;
atomic16->ls = reg_state_t::from_value(add_res.value);
atomic16->ls_offs = reg_state_t::from_value(0);
atomic16->ls_pc_rel = false;
atomic16->ls_write |= is_store;
atomic16->ls_access = true;
}
break;
@@ -6431,7 +6431,7 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
case 1:
{
const auto& state = ra.is_const() ? rb : ra;
const auto& _lsa = atomic16.lsa;
const auto& _lsa = atomic16->lsa;
const u32 offs = (ra.is_const() ? ra.value : rb.value) & SPU_LS_MASK_1;
const u32 abs_diff = calculate_absolute_ls_difference(offs, 0);
@@ -6443,82 +6443,82 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
// We already know it's an unrelated load/store
// The reason for SPU_LS_SIZE - 128 check is that in case LSA is not aligned, it detects the possible wraparound
}
else if (atomic16.ls_invalid && is_store)
else if (atomic16->ls_invalid && is_store)
{
break_putllc16(23, atomic16.set_invalid_ls(is_store));
break_putllc16(23, atomic16->set_invalid_ls(is_store));
}
else if (atomic16.ls_access && atomic16.ls != state)
else if (atomic16->ls_access && atomic16->ls != state)
{
if (atomic16.ls.unequal_with_mask_indifference(state, SPU_LS_MASK_128) && offs == 0)
if (atomic16->ls.unequal_with_mask_indifference(state, SPU_LS_MASK_128) && offs == 0)
{
// Ok
}
else if (atomic16.ls_pc_rel)
else if (atomic16->ls_pc_rel)
{
break_putllc16(36, atomic16.set_invalid_ls(is_store));
break_putllc16(36, atomic16->set_invalid_ls(is_store));
}
else
{
// Sad
break_putllc16(11, atomic16.set_invalid_ls(is_store));
break_putllc16(11, atomic16->set_invalid_ls(is_store));
}
}
else if (atomic16.ls_access)
else if (atomic16->ls_access)
{
ensure(!atomic16.ls.is_const());
ensure(!atomic16->ls.is_const());
if (atomic16.ls_offs.compare_with_mask_indifference(offs, SPU_LS_MASK_1))
if (atomic16->ls_offs.compare_with_mask_indifference(offs, SPU_LS_MASK_1))
{
// Ok
atomic16.ls_write |= is_store;
atomic16->ls_write |= is_store;
}
else if (atomic16.ls_offs.is_const() && atomic16.ls_offs.value / 16 == offs / 16 && state.get_known_zeroes() % 16 >= std::max<u32>(offs % 16, atomic16.ls_offs.value % 16))
else if (atomic16->ls_offs.is_const() && atomic16->ls_offs.value / 16 == offs / 16 && state.get_known_zeroes() % 16 >= std::max<u32>(offs % 16, atomic16->ls_offs.value % 16))
{
// For special case observed in games (offset cannot cause the address to roll over the next 16 bytes)
atomic16.ls_write |= is_store;
atomic16->ls_write |= is_store;
}
else
{
break_putllc16(12, atomic16.set_invalid_ls(is_store));
break_putllc16(12, atomic16->set_invalid_ls(is_store));
}
}
else
{
atomic16.ls = state;
atomic16.ls_offs = reg_state_t::from_value(offs);
atomic16.ls_pc_rel = false;
atomic16.ls_write |= is_store;
atomic16.ls_access = true;
atomic16->ls = state;
atomic16->ls_offs = reg_state_t::from_value(offs);
atomic16->ls_pc_rel = false;
atomic16->ls_write |= is_store;
atomic16->ls_access = true;
}
break;
}
case 0:
{
const bool is_ra_first = atomic16.ls_access ? ra == atomic16.ls : op.ra <= op.rb;
const bool is_ra_first = atomic16->ls_access ? ra == atomic16->ls : op.ra <= op.rb;
const auto& state1 = is_ra_first ? ra : rb;
const auto& state2 = is_ra_first ? rb : ra;
if (atomic16.ls_access && (atomic16.ls != state1 || atomic16.ls_offs != state2))
if (atomic16->ls_access && (atomic16->ls != state1 || atomic16->ls_offs != state2))
{
if (atomic16.ls_pc_rel)
if (atomic16->ls_pc_rel)
{
break_putllc16(32, atomic16.set_invalid_ls(is_store));
break_putllc16(32, atomic16->set_invalid_ls(is_store));
}
else
{
// Sad
break_putllc16(13, atomic16.set_invalid_ls(is_store));
break_putllc16(13, atomic16->set_invalid_ls(is_store));
}
}
else
{
atomic16.ls = state1;
atomic16.ls_offs = state2;
atomic16.ls_pc_rel = false;
atomic16.ls_write |= is_store;
atomic16.ls_access = true;
atomic16->ls = state1;
atomic16->ls_offs = state2;
atomic16->ls_pc_rel = false;
atomic16->ls_write |= is_store;
atomic16->ls_access = true;
}
break;
@@ -6541,43 +6541,43 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
{
const bool is_store = type == spu_itype::STQA;
if (atomic16.active)
if (atomic16->active)
{
atomic16.mem_count++;
atomic16->mem_count++;
const reg_state_t ca = reg_state_t::from_value(spu_ls_target(0, op.i16));
if (atomic16.lsa.unequal_with_mask_indifference(ca, SPU_LS_MASK_128))
if (atomic16->lsa.unequal_with_mask_indifference(ca, SPU_LS_MASK_128))
{
// We already know it's an unrelated load/store
}
else if (atomic16.ls_invalid && is_store)
else if (atomic16->ls_invalid && is_store)
{
break_putllc16(37, atomic16.set_invalid_ls(is_store));
break_putllc16(37, atomic16->set_invalid_ls(is_store));
}
else if (atomic16.ls_access && ca != atomic16.ls)
else if (atomic16->ls_access && ca != atomic16->ls)
{
if (atomic16.ls.unequal_with_mask_indifference(ca, SPU_LS_MASK_128) && atomic16.ls_offs == 0)
if (atomic16->ls.unequal_with_mask_indifference(ca, SPU_LS_MASK_128) && atomic16->ls_offs == 0)
{
// Ok
}
else if (atomic16.ls_pc_rel)
else if (atomic16->ls_pc_rel)
{
break_putllc16(14, atomic16.set_invalid_ls(is_store));
break_putllc16(14, atomic16->set_invalid_ls(is_store));
}
else
{
// Sad
break_putllc16(15, atomic16.set_invalid_ls(is_store));
break_putllc16(15, atomic16->set_invalid_ls(is_store));
}
}
else
{
atomic16.ls = ca;
atomic16.ls_offs = reg_state_t::from_value(0);
atomic16.ls_pc_rel = false;
atomic16.ls_write |= is_store;
atomic16.ls_access = true;
atomic16->ls = ca;
atomic16->ls_offs = reg_state_t::from_value(0);
atomic16->ls_pc_rel = false;
atomic16->ls_write |= is_store;
atomic16->ls_access = true;
}
}
@@ -6596,12 +6596,12 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
{
const bool is_store = type == spu_itype::STQD;
if (atomic16.active)
if (atomic16->active)
{
atomic16.mem_count++;
atomic16->mem_count++;
auto ra = get_reg(op.ra);
const auto& _lsa = atomic16.lsa;
const auto& _lsa = atomic16->lsa;
ra.value = ra.is_const() ? spu_ls_target(ra.value, op.si10 * 4) : 0;
const u32 offs = ra.is_const() ? 0 : spu_ls_target(0, op.si10 * 4);
@@ -6615,49 +6615,49 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
// We already know it's an unrelated load/store
// The reason for SPU_LS_SIZE - 128 check is that in case LSA is not aligned, it detects the possible wraparound
}
else if (atomic16.ls_invalid && is_store)
else if (atomic16->ls_invalid && is_store)
{
break_putllc16(34, atomic16.set_invalid_ls(is_store));
break_putllc16(34, atomic16->set_invalid_ls(is_store));
}
else if (atomic16.ls_access && atomic16.ls != ra)
else if (atomic16->ls_access && atomic16->ls != ra)
{
if (atomic16.ls.unequal_with_mask_indifference(ra, SPU_LS_MASK_128) && (offs == 0 && atomic16.ls_offs == 0))
if (atomic16->ls.unequal_with_mask_indifference(ra, SPU_LS_MASK_128) && (offs == 0 && atomic16->ls_offs == 0))
{
// Ok
}
else if (atomic16.ls_pc_rel)
else if (atomic16->ls_pc_rel)
{
break_putllc16(16, atomic16.set_invalid_ls(is_store));
break_putllc16(16, atomic16->set_invalid_ls(is_store));
}
else
{
// Sad
break_putllc16(17, atomic16.set_invalid_ls(is_store));
break_putllc16(17, atomic16->set_invalid_ls(is_store));
}
}
else if (atomic16.ls_access)
else if (atomic16->ls_access)
{
if (atomic16.ls_offs.compare_with_mask_indifference(offs, SPU_LS_MASK_1))
if (atomic16->ls_offs.compare_with_mask_indifference(offs, SPU_LS_MASK_1))
{
atomic16.ls_write |= is_store;
atomic16->ls_write |= is_store;
}
else if (atomic16.ls_offs.is_const() && atomic16.ls_offs.value / 16 == offs / 16 && ra.get_known_zeroes() % 16 >= std::max<u32>(offs % 16, atomic16.ls_offs.value % 16))
else if (atomic16->ls_offs.is_const() && atomic16->ls_offs.value / 16 == offs / 16 && ra.get_known_zeroes() % 16 >= std::max<u32>(offs % 16, atomic16->ls_offs.value % 16))
{
// For special case observed in games (offset cannot cause the address to roll over the next 16 bytes)
atomic16.ls_write |= is_store;
atomic16->ls_write |= is_store;
}
else
{
break_putllc16(18, atomic16.set_invalid_ls(is_store));
break_putllc16(18, atomic16->set_invalid_ls(is_store));
}
}
else
{
atomic16.ls = ra;
atomic16.ls_offs = reg_state_t::from_value(offs);
atomic16.ls_pc_rel = false;
atomic16.ls_write |= is_store;
atomic16.ls_access = true;
atomic16->ls = ra;
atomic16->ls_offs = reg_state_t::from_value(offs);
atomic16->ls_pc_rel = false;
atomic16->ls_write |= is_store;
atomic16->ls_access = true;
}
}
@@ -6947,18 +6947,18 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
inherit_const_value(op.rt, ra, ra, av == op.si10 + 0u, pos);
if (rchcnt_loop.active)
if (rchcnt_loop->active)
{
if (ra.is_instruction && ra.origin == rchcnt_loop.ch_state.origin)
if (ra.is_instruction && ra.origin == rchcnt_loop->ch_state.origin)
{
if (op.si10 != 0 && op.si10 != 1)
{
break_channel_pattern(55, rchcnt_loop.discard());
break_channel_pattern(55, rchcnt_loop->discard());
break;
}
rchcnt_loop.ch_product = vregs[op.rt];
rchcnt_loop.product_test_negate = op.si10 == 1;
rchcnt_loop->ch_product = vregs[op.rt];
rchcnt_loop->product_test_negate = op.si10 == 1;
}
}
@@ -7030,11 +7030,11 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
unconst(op_rt, reg_pos == SPU_LS_SIZE ? pos : reg_pos);
if (rchcnt_loop.active)
if (rchcnt_loop->active)
{
if (rchcnt_loop.origins.find_first_of(vregs[op_rt].origin) == umax)
if (rchcnt_loop->origins.find_first_of(vregs[op_rt].origin) == umax)
{
rchcnt_loop.origins.push_back(vregs[op_rt].origin);
rchcnt_loop->origins.push_back(vregs[op_rt].origin);
}
}
}
+41 -28
View File
@@ -124,7 +124,6 @@ class spu_llvm_recompiler : public spu_recompiler_base, public cpu_translator
// Global LUTs
llvm::GlobalVariable* m_spu_frest_fraction_lut{};
llvm::GlobalVariable* m_spu_frest_exponent_lut{};
llvm::GlobalVariable* m_spu_frsqest_fraction_lut{};
llvm::GlobalVariable* m_spu_frsqest_exponent_lut{};
@@ -544,9 +543,7 @@ class spu_llvm_recompiler : public spu_recompiler_base, public cpu_translator
template <typename T = u8>
llvm::Value* _ptr(llvm::Value* base, llvm::Value* offset)
{
const auto off = m_ir->CreateGEP(get_type<u8>(), base, offset);
const auto ptr = m_ir->CreateBitCast(off, get_type<T*>());
return ptr;
return m_ir->CreateGEP(get_type<u8>(), base, offset);
}
template <typename T, typename... Args>
@@ -1507,7 +1504,6 @@ public:
{
// LUTs for some instructions
m_spu_frest_fraction_lut = new llvm::GlobalVariable(*m_module, llvm::ArrayType::get(GetType<u32>(), 32), true, llvm::GlobalValue::PrivateLinkage, llvm::ConstantDataArray::get(m_context, spu_frest_fraction_lut));
m_spu_frest_exponent_lut = new llvm::GlobalVariable(*m_module, llvm::ArrayType::get(GetType<u32>(), 256), true, llvm::GlobalValue::PrivateLinkage, llvm::ConstantDataArray::get(m_context, spu_frest_exponent_lut));
m_spu_frsqest_fraction_lut = new llvm::GlobalVariable(*m_module, llvm::ArrayType::get(GetType<u32>(), 64), true, llvm::GlobalValue::PrivateLinkage, llvm::ConstantDataArray::get(m_context, spu_frsqest_fraction_lut));
m_spu_frsqest_exponent_lut = new llvm::GlobalVariable(*m_module, llvm::ArrayType::get(GetType<u32>(), 256), true, llvm::GlobalValue::PrivateLinkage, llvm::ConstantDataArray::get(m_context, spu_frsqest_exponent_lut));
}
@@ -6040,23 +6036,22 @@ public:
const auto a = bitcast<u32[4]>(value<f32[4]>(ci->getOperand(0)));
const auto a_fraction = (a >> splat<u32[4]>(18)) & splat<u32[4]>(0x1F);
const auto a_exponent = (a >> splat<u32[4]>(23)) & splat<u32[4]>(0xFF);
const auto a_exponent = (a & splat<u32[4]>(0x7F800000u));
const auto r_exponent = sub_sat(build<u16[8]>(0000, 0x7E80, 0000, 0x7E80, 0000, 0x7E80, 0000, 0x7E80), bitcast<u16[8]>(a_exponent));
const auto fix_exponent = select((a_exponent > 0), bitcast<u32[4]>(r_exponent), splat<u32[4]>(0x7F800000u));
const auto a_sign = (a & splat<u32[4]>(0x80000000));
value_t<u32[4]> final_result = eval(splat<u32[4]>(0));
for (u32 i = 0; i < 4; i++)
{
const auto eval_fraction = eval(extract(a_fraction, i));
const auto eval_exponent = eval(extract(a_exponent, i));
const auto eval_sign = eval(extract(a_sign, i));
value_t<u32> r_fraction = load_const<u32>(m_spu_frest_fraction_lut, eval_fraction);
value_t<u32> r_exponent = load_const<u32>(m_spu_frest_exponent_lut, eval_exponent);
final_result = eval(insert(final_result, i, eval(r_fraction | eval_sign | r_exponent)));
final_result = eval(insert(final_result, i, r_fraction));
}
return bitcast<f32[4]>(final_result);
return bitcast<f32[4]>(bitcast<u32[4]>(final_result | bitcast<u32[4]>(fix_exponent) | a_sign));
});
set_vr(op.rt, frest(get_vr<f32[4]>(op.ra)));
@@ -6704,24 +6699,39 @@ public:
}
});
register_intrinsic("spu_re_acc", [&](llvm::CallInst* ci)
if (m_use_avx512)
{
const auto div = value<f32[4]>(ci->getOperand(0));
const auto the_one = value<f32[4]>(ci->getOperand(1));
register_intrinsic("spu_re_acc", [&](llvm::CallInst* ci)
{
const auto div = value<f32[4]>(ci->getOperand(0));
const auto the_one = value<f32[4]>(ci->getOperand(1));
const auto div_result = the_one / div;
const auto div_result = the_one / div;
// from ps3 hardware testing: Inf => NaN and NaN => Zero
const auto result_and = bitcast<u32[4]>(div_result) & 0x7fffffffu;
const auto result_cmp_inf = sext<s32[4]>(result_and == splat<u32[4]>(0x7F800000u));
const auto result_cmp_nan = sext<s32[4]>(result_and <= splat<u32[4]>(0x7F800000u));
return vfixupimmps(bitcast<f32[4]>(splat<u32[4]>(0xFFFFFFFFu)), div_result, splat<u32[4]>(0x11001188u), 0, 0xff);
});
}
else
{
register_intrinsic("spu_re_acc", [&](llvm::CallInst* ci)
{
const auto div = value<f32[4]>(ci->getOperand(0));
const auto the_one = value<f32[4]>(ci->getOperand(1));
const auto and_mask = bitcast<u32[4]>(result_cmp_nan) & splat<u32[4]>(0xFFFFFFFFu);
const auto or_mask = bitcast<u32[4]>(result_cmp_inf) & splat<u32[4]>(0xFFFFFFFu);
const auto div_result = the_one / div;
return bitcast<f32[4]>((bitcast<u32[4]>(div_result) & and_mask) | or_mask);
});
// from ps3 hardware testing: Inf => NaN and NaN => Zero
const auto result_and = bitcast<u32[4]>(div_result) & 0x7fffffffu;
const auto result_cmp_inf = sext<s32[4]>(result_and == splat<u32[4]>(0x7F800000u));
const auto result_cmp_nan = sext<s32[4]>(result_and <= splat<u32[4]>(0x7F800000u));
const auto and_mask = bitcast<u32[4]>(result_cmp_nan) & splat<u32[4]>(0xFFFFFFFFu);
const auto or_mask = bitcast<u32[4]>(result_cmp_inf) & splat<u32[4]>(0xFFFFFFFu);
return bitcast<f32[4]>((bitcast<u32[4]>(div_result) & and_mask) | or_mask);
});
}
const auto [a, b, c] = get_vrs<f32[4]>(op.ra, op.rb, op.rc);
static const auto MT = match<f32[4]>();
@@ -7004,20 +7014,23 @@ public:
{
const auto a = bitcast<u32[4]>(value<f32[4]>(ci->getOperand(0)));
const auto a_fraction = (a >> splat<u32[4]>(18)) & splat<u32[4]>(0x1F);
const auto a_exponent = (a >> splat<u32[4]>(23)) & splat<u32[4]>(0xFF);
const auto a_exponent = (a & splat<u32[4]>(0x7F800000u));
const auto r_exponent = sub_sat(build<u16[8]>(0000, 0x7E80, 0000, 0x7E80, 0000, 0x7E80, 0000, 0x7E80), bitcast<u16[8]>(a_exponent));
const auto fix_exponent = select((a_exponent > 0), bitcast<u32[4]>(r_exponent), splat<u32[4]>(0x7F800000u));
const auto a_sign = (a & splat<u32[4]>(0x80000000));
value_t<u32[4]> b = eval(splat<u32[4]>(0));
for (u32 i = 0; i < 4; i++)
{
const auto eval_fraction = eval(extract(a_fraction, i));
const auto eval_exponent = eval(extract(a_exponent, i));
const auto eval_sign = eval(extract(a_sign, i));
value_t<u32> r_fraction = load_const<u32>(m_spu_frest_fraction_lut, eval_fraction);
value_t<u32> r_exponent = load_const<u32>(m_spu_frest_exponent_lut, eval_exponent);
b = eval(insert(b, i, eval(r_fraction | eval_sign | r_exponent)));
b = eval(insert(b, i, r_fraction));
}
b = eval(b | fix_exponent | a_sign);
const auto base = (b & 0x007ffc00u) << 9; // Base fraction
const auto ymul = (b & 0x3ff) * (a & 0x7ffff); // Step fraction * Y fraction (fixed point at 2^-32)
const auto comparison = (ymul > base); // Should exponent be adjusted?
+208 -8
View File
@@ -1673,6 +1673,12 @@ void spu_thread::cpu_init()
status_npc.raw() = {get_type() == spu_type::isolated ? SPU_STATUS_IS_ISOLATED : 0, 0};
run_ctrl.raw() = 0;
spurs_last_task_timestamp = 0;
spurs_wait_duration_last = 0;
spurs_average_task_duration = 0;
spurs_waited = false;
spurs_entered_wait = false;
int_ctrl[0].clear();
int_ctrl[1].clear();
int_ctrl[2].clear();
@@ -1823,17 +1829,28 @@ void spu_thread::cpu_task()
return fmt::format("%sSPU[0x%07x] Thread (%s) [0x%05x]", type >= spu_type::raw ? type == spu_type::isolated ? "Iso" : "Raw" : "", cpu->lv2_id, *name_cache.get(), cpu->pc);
};
if (!spurs_addr)
constexpr u32 invalid_spurs = 0u - 0x80;
if (spurs_addr == 0)
{
// Evaluate it
if (!group)
{
spurs_addr = -0x80; // Some invalid non-0 address
spurs_addr = invalid_spurs; // Some invalid non-0 address
}
else
{
const u32 arg = static_cast<u32>(group->args[index][1]);
spurs_addr = group->name.ends_with("CellSpursKernelGroup"sv) && vm::check_addr(arg) ? arg : 0u - 0x80;
if (group->name.ends_with("CellSpursKernelGroup"sv) && vm::check_addr(arg))
{
spurs_addr = arg;
group->spurs_running++;
}
else
{
spurs_addr = invalid_spurs;
}
}
}
@@ -1884,6 +1901,14 @@ void spu_thread::cpu_task()
allow_interrupts_in_cpu_work = false;
}
if (spurs_addr != invalid_spurs)
{
if (group->spurs_running.exchange(0))
{
group->spurs_running.notify_all();
}
}
}
void spu_thread::cpu_work()
@@ -4765,7 +4790,7 @@ bool spu_thread::process_mfc_cmd()
getllar_spin_count = 0;
getllar_busy_waiting_switch = umax;
u64 ntime;
u64 ntime = 0;
rsx::reservation_lock rsx_lock(addr, 128);
for (u64 i = 0; i != umax; [&]()
@@ -4871,9 +4896,163 @@ bool spu_thread::process_mfc_cmd()
// Avoid logging useless commands if there is no reservation
const bool dump = g_cfg.core.mfc_debug && raddr;
const bool is_spurs_task_wait = pc == 0x11e4 && spurs_addr != 0u - 0x80u;
if (!is_spurs_task_wait || spurs_addr != raddr || spurs_waited)
{
//
}
else if ((_ref<u8>(0x100 + 0x73) & (1u << index)) == 0 && (static_cast<u8>(rdata[0x73]) & (1u << index)) != 0)
{
// Wait for other threads to complete their tasks (temporarily)
u32 max_run = group->max_run;
auto [prev_running, ok] = spurs_entered_wait ? std::make_pair(+group->spurs_running, false) :
group->spurs_running.fetch_op([max_run, num = group->max_num](u32& x)
{
if (x >= max_run && max_run < num)
{
x--;
return true;
}
return false;
});
if (ok || spurs_entered_wait)
{
lv2_obj::prepare_for_sleep(*this);
if (ok)
{
if (prev_running == max_run)
{
group->spurs_running.notify_one();
if (group->spurs_running == max_run - 1)
{
// Try to let another thread slip in and take over execution
thread_ctrl::wait_for(300);
// Update value
prev_running = group->spurs_running + 1;
}
}
// Restore state
prev_running--;
}
const u64 before = get_system_time();
u64 current = before;
spurs_waited = true;
spurs_entered_wait = true;
// Wait the duration of one and a half tasks
const u64 spurs_wait_time = std::clamp<u64>(spurs_average_task_duration / spurs_task_count_to_calculate * 3 / 2, 10'000, 100'000);
spurs_wait_duration_last = spurs_wait_time;
if (spurs_last_task_timestamp)
{
const u64 avg_entry = spurs_average_task_duration / spurs_task_count_to_calculate;
spurs_average_task_duration -= avg_entry;
spurs_average_task_duration += std::min<u64>(45'000, current - spurs_last_task_timestamp);
spu_log.trace("duration: %d, avg=%d", current - spurs_last_task_timestamp, spurs_average_task_duration / spurs_task_count_to_calculate);
spurs_last_task_timestamp = 0;
}
while (true)
{
if (is_stopped() || current - before >= spurs_wait_time)
{
// Timed-out
group->spurs_running++;
break;
}
if (prev_running >= max_run)
{
thread_ctrl::wait_on(group->spurs_running, prev_running, spurs_wait_time - (current - before));
}
max_run = group->max_run;
prev_running = group->spurs_running.fetch_op([max_run](u32& x)
{
if (x < max_run)
{
x++;
return true;
}
return false;
}).first;
if (prev_running < max_run)
{
break;
}
current = get_system_time();
}
state += cpu_flag::temp;
static_cast<void>(test_stopped());
}
}
if (do_putllc(ch_mfc_cmd))
{
ch_atomic_stat.set_value(MFC_PUTLLC_SUCCESS);
if (is_spurs_task_wait)
{
const bool is_idle = (_ref<u8>(0x100 + 0x73) & (1u << index)) != 0;
const bool was_idle = (static_cast<u8>(rdata[0x73]) & (1u << index)) != 0;
if (!was_idle && is_idle)
{
const u32 prev_running = group->spurs_running.fetch_op([](u32& x)
{
if (x)
{
x--;
return true;
}
return false;
}).first;
if (prev_running)
{
spurs_entered_wait = true;
}
if (prev_running == group->max_run && prev_running < group->max_num)
{
group->spurs_running.notify_one();
}
}
else if (was_idle && !is_idle)
{
// Cleanup
const u64 current = get_system_time();
if (spurs_last_task_timestamp)
{
const u64 avg_entry = spurs_average_task_duration / spurs_task_count_to_calculate;
spurs_average_task_duration -= avg_entry;
spurs_average_task_duration += std::min<u64>(45'000, current - spurs_last_task_timestamp);
spu_log.trace("duration: %d, avg=%d", current - spurs_last_task_timestamp, spurs_average_task_duration / spurs_task_count_to_calculate);
spurs_last_task_timestamp = 0;
}
spurs_last_task_timestamp = current;
spurs_waited = false;
spurs_entered_wait = false;
}
}
}
else
{
@@ -5391,6 +5570,8 @@ s64 spu_thread::get_ch_value(u32 ch)
thread_ctrl::wait_on(state, old);
}
fmt::throw_exception("Unreachable"); // Fix unannotated fallthrough warning
}
case MFC_RdTagStat:
@@ -5490,7 +5671,7 @@ s64 spu_thread::get_ch_value(u32 ch)
const u32 old_raddr = raddr;
// Does not need to safe-access reservation if LR is the only event masked
// Because it's either an access violation or a livelock if an invalid memory is passed
// Because it's either an access violation or a live-lock if an invalid memory is passed
if (raddr && mask1 > SPU_EVENT_LR)
{
auto area = vm::get(vm::any, raddr);
@@ -5504,7 +5685,7 @@ s64 spu_thread::get_ch_value(u32 ch)
}
else if (area)
{
// Ensure possesion over reservation memory so it won't be deallocated
// Ensure possession over reservation memory so it won't be de-allocated
auto [base_addr, shm_] = area->peek(raddr);
if (shm_)
@@ -5571,6 +5752,24 @@ s64 spu_thread::get_ch_value(u32 ch)
if (raddr && (mask1 & ~SPU_EVENT_TM) == SPU_EVENT_LR)
{
if (u32 max_threads = std::min<u32>(g_cfg.core.max_spurs_threads, group ? group->max_num : u32{umax}); group && group->max_run != max_threads)
{
constexpr std::string_view spurs_suffix = "CellSpursKernelGroup"sv;
if (group->name.ends_with(spurs_suffix) && !group->name.substr(0, group->name.size() - spurs_suffix.size()).ends_with("_libsail"))
{
// Hack: don't run more SPURS threads than specified.
if (u32 old = atomic_storage<u32>::exchange(group->max_run, max_threads); old > max_threads)
{
spu_log.success("HACK: '%s' (0x%x) limited to %u threads.", group->name, group->id, max_threads);
}
else if (u32 running = group->spurs_running; old < max_threads && running >= old && running < max_threads)
{
group->spurs_running.notify_all();
}
}
}
// Don't busy-wait with TSX - memory is sensitive
if (g_use_rtm || !reservation_busy_waiting)
{
@@ -5616,7 +5815,7 @@ s64 spu_thread::get_ch_value(u32 ch)
static thread_local bool s_tls_try_notify = false;
s_tls_try_notify = false;
atomic_wait_engine::set_one_time_use_wait_callback(mask1 != SPU_EVENT_LR ? nullptr : +[](u64 attempts) -> bool
const auto wait_cb = mask1 != SPU_EVENT_LR ? nullptr : +[](u64 attempts) -> bool
{
const auto _this = static_cast<spu_thread*>(cpu_thread::get_current());
AUDIT(_this->get_class() == thread_class::spu);
@@ -5665,10 +5864,11 @@ s64 spu_thread::get_ch_value(u32 ch)
}
return true;
});
};
if (auto wait_var = vm::reservation_notifier_begin_wait(_raddr, rtime))
{
atomic_wait_engine::set_one_time_use_wait_callback(wait_cb);
utils::bless<atomic_t<u32>>(&wait_var->raw().wait_flag)->wait(1, atomic_wait_timeout{80'000});
vm::reservation_notifier_end_wait(*wait_var);
}
+24 -18
View File
@@ -188,10 +188,10 @@ struct spu_channel_op_state
struct alignas(16) spu_channel
{
// Low 32 bits contain value
atomic_t<u64> data;
atomic_t<u64> data{};
// Pending value to be inserted when it is possible in pop() or pop_wait()
atomic_t<u64> jostling_value;
atomic_t<u64> jostling_value{};
public:
static constexpr u32 off_wait = 32;
@@ -667,11 +667,11 @@ public:
u8* reserv_base_addr = vm::g_reservations;
// General-Purpose Registers
std::array<v128, 128> gpr;
SPU_FPSCR fpscr;
std::array<v128, 128> gpr{};
SPU_FPSCR fpscr{};
// MFC command data
spu_mfc_cmd ch_mfc_cmd;
spu_mfc_cmd ch_mfc_cmd{};
// MFC command queue
spu_mfc_cmd mfc_queue[16]{};
@@ -683,9 +683,9 @@ public:
u64 mfc_last_timestamp = 0;
// MFC proxy command data
spu_mfc_cmd mfc_prxy_cmd;
spu_mfc_cmd mfc_prxy_cmd{};
shared_mutex mfc_prxy_mtx;
atomic_t<u32> mfc_prxy_mask;
atomic_t<u32> mfc_prxy_mask = 0;
// Tracks writes to MFC proxy command data
union
@@ -707,11 +707,11 @@ public:
// Range Lock pointer
atomic_t<u64, 64>* range_lock{};
u32 srr0;
u32 ch_tag_upd;
u32 ch_tag_mask;
u32 srr0 = 0;
u32 ch_tag_upd = 0;
u32 ch_tag_mask = 0;
spu_channel ch_tag_stat;
u32 ch_stall_mask;
u32 ch_stall_mask = 0;
spu_channel ch_stall_stat;
spu_channel ch_atomic_stat;
@@ -736,14 +736,14 @@ public:
};
atomic_t<ch_events_t> ch_events;
bool interrupts_enabled;
bool interrupts_enabled = false;
u64 ch_dec_start_timestamp; // timestamp of writing decrementer value
u32 ch_dec_value; // written decrementer value
u64 ch_dec_start_timestamp = 0; // timestamp of writing decrementer value
u32 ch_dec_value = 0; // written decrementer value
bool is_dec_frozen = false;
std::pair<u32, u32> read_dec() const; // Read decrementer
atomic_t<u32> run_ctrl; // SPU Run Control register (only provided to get latest data written)
atomic_t<u32> run_ctrl = 0; // SPU Run Control register (only provided to get latest data written)
shared_mutex run_ctrl_mtx;
struct alignas(8) status_npc_sync_var
@@ -752,10 +752,10 @@ public:
u32 npc; // SPU Next Program Counter register
};
atomic_t<status_npc_sync_var> status_npc;
std::array<spu_int_ctrl_t, 3> int_ctrl; // SPU Class 0, 1, 2 Interrupt Management
atomic_t<status_npc_sync_var> status_npc{};
std::array<spu_int_ctrl_t, 3> int_ctrl{}; // SPU Class 0, 1, 2 Interrupt Management
std::array<std::pair<u32, std::shared_ptr<lv2_event_queue>>, 32> spuq; // Event Queue Keys for SPU Thread
std::array<std::pair<u32, std::shared_ptr<lv2_event_queue>>, 32> spuq{}; // Event Queue Keys for SPU Thread
std::shared_ptr<lv2_event_queue> spup[64]; // SPU Ports
spu_channel exit_status{}; // Threaded SPU exit status (not a channel, but the interface fits)
atomic_t<u32> last_exit_status; // Value to be written in exit_status after checking group termination
@@ -767,6 +767,12 @@ public:
const u32 option; // sys_spu_thread_initialize option
const u32 lv2_id; // The actual id that is used by syscalls
u32 spurs_addr = 0;
bool spurs_waited = false;
bool spurs_entered_wait = false;
u64 spurs_wait_duration_last = 0;
u64 spurs_average_task_duration = 0;
u64 spurs_last_task_timestamp = 0;
static constexpr u64 spurs_task_count_to_calculate = 10;
spu_thread* next_cpu{}; // LV2 thread queues' node link
+46 -4
View File
@@ -119,8 +119,13 @@ std::shared_ptr<lv2_event_queue> lv2_event_queue::find(u64 ipc_key)
extern void resume_spu_thread_group_from_waiting(spu_thread& spu);
CellError lv2_event_queue::send(lv2_event event)
CellError lv2_event_queue::send(lv2_event event, bool* notified_thread, lv2_event_port* port)
{
if (notified_thread)
{
*notified_thread = false;
}
std::lock_guard lock(mutex);
if (!exists)
@@ -162,6 +167,15 @@ CellError lv2_event_queue::send(lv2_event event)
std::tie(ppu.gpr[4], ppu.gpr[5], ppu.gpr[6], ppu.gpr[7]) = event;
awake(&ppu);
if (port && ppu.prio.load().prio < ensure(cpu_thread::get_current<ppu_thread>())->prio.load().prio)
{
// Block event port disconnection for the time being of sending events
// PPU -> lower prio PPU is the only case that can cause thread blocking
port->is_busy++;
ensure(notified_thread);
*notified_thread = true;
}
}
else
{
@@ -709,7 +723,10 @@ error_code sys_event_port_disconnect(ppu_thread& ppu, u32 eport_id)
return CELL_ENOTCONN;
}
// TODO: return CELL_EBUSY if necessary (can't detect the condition)
if (port->is_busy)
{
return CELL_EBUSY;
}
port->queue.reset();
@@ -718,20 +735,32 @@ error_code sys_event_port_disconnect(ppu_thread& ppu, u32 eport_id)
error_code sys_event_port_send(u32 eport_id, u64 data1, u64 data2, u64 data3)
{
if (auto cpu = get_current_cpu_thread())
const auto cpu = cpu_thread::get_current();
const auto ppu = cpu ? cpu->try_get<ppu_thread>() : nullptr;
if (cpu)
{
cpu->state += cpu_flag::wait;
}
sys_event.trace("sys_event_port_send(eport_id=0x%x, data1=0x%llx, data2=0x%llx, data3=0x%llx)", eport_id, data1, data2, data3);
bool notified_thread = false;
const auto port = idm::check<lv2_obj, lv2_event_port>(eport_id, [&, notify = lv2_obj::notify_all_t()](lv2_event_port& port) -> CellError
{
if (ppu && ppu->loaded_from_savestate)
{
port.is_busy++;
notified_thread = true;
return {};
}
if (lv2_obj::check(port.queue))
{
const u64 source = port.name ? port.name : (u64{process_getpid() + 0u} << 32) | u64{eport_id};
return port.queue->send(source, data1, data2, data3);
return port.queue->send(source, data1, data2, data3, &notified_thread, ppu && port.queue->type == SYS_PPU_QUEUE ? &port : nullptr);
}
return CELL_ENOTCONN;
@@ -742,6 +771,19 @@ error_code sys_event_port_send(u32 eport_id, u64 data1, u64 data2, u64 data3)
return CELL_ESRCH;
}
if (ppu && notified_thread)
{
// Wait to be requeued
if (ppu->test_stopped())
{
// Wait again on savestate load
ppu->state += cpu_flag::again;
}
port->is_busy--;
return CELL_OK;
}
if (port.ret)
{
if (port.ret == CELL_EAGAIN)
+6 -3
View File
@@ -79,6 +79,8 @@ struct sys_event_t
// Source, data1, data2, data3
using lv2_event = std::tuple<u64, u64, u64, u64>;
struct lv2_event_port;
struct lv2_event_queue final : public lv2_obj
{
static const u32 id_base = 0x8d000000;
@@ -103,11 +105,11 @@ struct lv2_event_queue final : public lv2_obj
static void save_ptr(utils::serial&, lv2_event_queue*);
static std::shared_ptr<lv2_event_queue> load_ptr(utils::serial& ar, std::shared_ptr<lv2_event_queue>& queue, std::string_view msg = {});
CellError send(lv2_event event);
CellError send(lv2_event event, bool* notified_thread = nullptr, lv2_event_port* port = nullptr);
CellError send(u64 source, u64 d1, u64 d2, u64 d3)
CellError send(u64 source, u64 d1, u64 d2, u64 d3, bool* notified_thread = nullptr, lv2_event_port* port = nullptr)
{
return send(std::make_tuple(source, d1, d2, d3));
return send(std::make_tuple(source, d1, d2, d3), notified_thread, port);
}
// Get event queue by its global key
@@ -121,6 +123,7 @@ struct lv2_event_port final : lv2_obj
const s32 type; // Port type, either IPC or local
const u64 name; // Event source (generated from id and process id if not set)
atomic_t<usz> is_busy = 0; // Counts threads waiting on event sending
std::shared_ptr<lv2_event_queue> queue; // Event queue this port is connected to
lv2_event_port(s32 type, u64 name)
+41 -12
View File
@@ -357,16 +357,14 @@ error_code sys_event_flag_set(cpu_thread& cpu, u32 id, u64 bitptn)
}
}
// Process all waiters in single atomic op
const u32 count = flag->pattern.atomic_op([&](u64& value)
{
value |= bitptn;
u32 count = 0;
u32 count = 0;
if (!flag->sq)
{
return count;
}
// Process all waiters in single atomic op
for (u64 pattern = flag->pattern, to_write = pattern, dependant_mask = 0;; to_write = pattern, dependant_mask = 0)
{
count = 0;
to_write |= bitptn;
dependant_mask = 0;
for (auto ppu = +flag->sq; ppu; ppu = ppu->next_cpu)
{
@@ -405,10 +403,20 @@ error_code sys_event_flag_set(cpu_thread& cpu, u32 id, u64 bitptn)
const u64 pattern = ppu.gpr[4];
const u64 mode = ppu.gpr[5];
if (lv2_event_flag::check_pattern(value, pattern, mode, &ppu.gpr[6]))
// If it's OR mode, set bits must have waken up the thread therefore no
// dependency on old value
const u64 dependant_mask_or = ((mode & 0xf) == SYS_EVENT_FLAG_WAIT_OR || (bitptn & pattern & to_write) == pattern ? 0 : pattern);
if (lv2_event_flag::check_pattern(to_write, pattern, mode, &ppu.gpr[6]))
{
dependant_mask |= dependant_mask_or;
ppu.gpr[3] = CELL_OK;
count++;
if (!to_write)
{
break;
}
}
else
{
@@ -416,8 +424,29 @@ error_code sys_event_flag_set(cpu_thread& cpu, u32 id, u64 bitptn)
}
}
return count;
});
dependant_mask &= ~bitptn;
auto [new_val, ok] = flag->pattern.fetch_op([&](u64& x)
{
if ((x ^ pattern) & dependant_mask)
{
return false;
}
x |= bitptn;
// Clear the bit-wise difference
x &= ~((pattern | bitptn) & ~to_write);
return true;
});
if (ok)
{
break;
}
pattern = new_val;
}
if (!count)
{
+10 -10
View File
@@ -93,7 +93,7 @@ std::shared_ptr<vm::block_t> reserve_map(u32 alloc_size, u32 align)
// Todo: fix order of error checks
error_code sys_memory_allocate(cpu_thread& cpu, u32 size, u64 flags, vm::ptr<u32> alloc_addr)
error_code sys_memory_allocate(cpu_thread& cpu, u64 size, u64 flags, vm::ptr<u32> alloc_addr)
{
cpu.state += cpu_flag::wait;
@@ -129,9 +129,9 @@ error_code sys_memory_allocate(cpu_thread& cpu, u32 size, u64 flags, vm::ptr<u32
return {CELL_ENOMEM, dct.size - dct.used};
}
if (const auto area = reserve_map(size, align))
if (const auto area = reserve_map(static_cast<u32>(size), align))
{
if (const u32 addr = area->alloc(size, nullptr, align))
if (const u32 addr = area->alloc(static_cast<u32>(size), nullptr, align))
{
ensure(!g_fxo->get<sys_memory_address_table>().addrs[addr >> 16].exchange(&dct));
@@ -139,7 +139,7 @@ error_code sys_memory_allocate(cpu_thread& cpu, u32 size, u64 flags, vm::ptr<u32
{
sys_memory.notice("sys_memory_allocate(): Allocated 0x%x address (size=0x%x)", addr, size);
vm::lock_sudo(addr, size);
vm::lock_sudo(addr, static_cast<u32>(size));
cpu.check_state();
*alloc_addr = addr;
return CELL_OK;
@@ -155,7 +155,7 @@ error_code sys_memory_allocate(cpu_thread& cpu, u32 size, u64 flags, vm::ptr<u32
return CELL_ENOMEM;
}
error_code sys_memory_allocate_from_container(cpu_thread& cpu, u32 size, u32 cid, u64 flags, vm::ptr<u32> alloc_addr)
error_code sys_memory_allocate_from_container(cpu_thread& cpu, u64 size, u32 cid, u64 flags, vm::ptr<u32> alloc_addr)
{
cpu.state += cpu_flag::wait;
@@ -203,15 +203,15 @@ error_code sys_memory_allocate_from_container(cpu_thread& cpu, u32 size, u32 cid
return {ct.ret, ct->size - ct->used};
}
if (const auto area = reserve_map(size, align))
if (const auto area = reserve_map(static_cast<u32>(size), align))
{
if (const u32 addr = area->alloc(size))
if (const u32 addr = area->alloc(static_cast<u32>(size)))
{
ensure(!g_fxo->get<sys_memory_address_table>().addrs[addr >> 16].exchange(ct.ptr.get()));
if (alloc_addr)
{
vm::lock_sudo(addr, size);
vm::lock_sudo(addr, static_cast<u32>(size));
cpu.check_state();
*alloc_addr = addr;
return CELL_OK;
@@ -320,7 +320,7 @@ error_code sys_memory_get_user_memory_stat(cpu_thread& cpu, vm::ptr<sys_memory_u
return CELL_OK;
}
error_code sys_memory_container_create(cpu_thread& cpu, vm::ptr<u32> cid, u32 size)
error_code sys_memory_container_create(cpu_thread& cpu, vm::ptr<u32> cid, u64 size)
{
cpu.state += cpu_flag::wait;
@@ -345,7 +345,7 @@ error_code sys_memory_container_create(cpu_thread& cpu, vm::ptr<u32> cid, u32 si
}
// Create the memory container
if (const u32 id = idm::make<lv2_memory_container>(size, true))
if (const u32 id = idm::make<lv2_memory_container>(static_cast<u32>(size), true))
{
cpu.check_state();
*cid = id;
+3 -3
View File
@@ -128,13 +128,13 @@ struct sys_memory_user_memory_stat_t
};
// SysCalls
error_code sys_memory_allocate(cpu_thread& cpu, u32 size, u64 flags, vm::ptr<u32> alloc_addr);
error_code sys_memory_allocate_from_container(cpu_thread& cpu, u32 size, u32 cid, u64 flags, vm::ptr<u32> alloc_addr);
error_code sys_memory_allocate(cpu_thread& cpu, u64 size, u64 flags, vm::ptr<u32> alloc_addr);
error_code sys_memory_allocate_from_container(cpu_thread& cpu, u64 size, u32 cid, u64 flags, vm::ptr<u32> alloc_addr);
error_code sys_memory_free(cpu_thread& cpu, u32 start_addr);
error_code sys_memory_get_page_attribute(cpu_thread& cpu, u32 addr, vm::ptr<sys_page_attr_t> attr);
error_code sys_memory_get_user_memory_size(cpu_thread& cpu, vm::ptr<sys_memory_info_t> mem_info);
error_code sys_memory_get_user_memory_stat(cpu_thread& cpu, vm::ptr<sys_memory_user_memory_stat_t> mem_stat);
error_code sys_memory_container_create(cpu_thread& cpu, vm::ptr<u32> cid, u32 size);
error_code sys_memory_container_create(cpu_thread& cpu, vm::ptr<u32> cid, u64 size);
error_code sys_memory_container_destroy(cpu_thread& cpu, u32 cid);
error_code sys_memory_container_get_size(cpu_thread& cpu, vm::ptr<sys_memory_info_t> mem_info, u32 cid);
error_code sys_memory_container_destroy_parent_with_childs(cpu_thread& cpu, u32 cid, u32 must_0, vm::ptr<u32> mc_child);
+1 -1
View File
@@ -47,7 +47,7 @@ extern const std::map<std::string_view, int> g_prx_list
{ "libat3multidec.sprx", 0 },
{ "libatrac3multi.sprx", 0 },
{ "libatrac3plus.sprx", 0 },
{ "libatxdec.sprx", 0 },
{ "libatxdec.sprx", 1 },
{ "libatxdec2.sprx", 0 },
{ "libaudio.sprx", 1 },
{ "libavcdec.sprx", 0 },
+66 -55
View File
@@ -562,20 +562,48 @@ error_code sys_spu_thread_initialize(ppu_thread& ppu, vm::ptr<u32> thread, u32 g
sys_spu.warning("sys_spu_thread_initialize(thread=*0x%x, group=0x%x, spu_num=%d, img=*0x%x, attr=*0x%x, arg=*0x%x)", thread, group_id, spu_num, img, attr, arg);
const u32 option = attr->option;
if (attr->name_len > 0x80 || option & ~(SYS_SPU_THREAD_OPTION_DEC_SYNC_TB_ENABLE | SYS_SPU_THREAD_OPTION_ASYNC_INTR_ENABLE))
if (spu_num >= std::size(decltype(lv2_spu_group::threads_map){}))
{
return CELL_EINVAL;
}
sys_spu_image image;
if (!attr)
{
return CELL_EFAULT;
}
switch (img->type)
const sys_spu_thread_attribute attr_data = *attr;
if (attr_data.name_len > 0x80)
{
return CELL_EINVAL;
}
if (!arg)
{
return CELL_EFAULT;
}
const sys_spu_thread_argument args = *arg;
const u32 option = attr_data.option;
if (option & ~(SYS_SPU_THREAD_OPTION_DEC_SYNC_TB_ENABLE | SYS_SPU_THREAD_OPTION_ASYNC_INTR_ENABLE))
{
return CELL_EINVAL;
}
if (!img)
{
return CELL_EFAULT;
}
sys_spu_image image = *img;
switch (image.type)
{
case SYS_SPU_IMAGE_TYPE_KERNEL:
{
const auto handle = idm::get<lv2_obj, lv2_spu_image>(img->entry_point);
const auto handle = idm::get<lv2_obj, lv2_spu_image>(image.entry_point);
if (!handle)
{
@@ -591,12 +619,11 @@ error_code sys_spu_thread_initialize(ppu_thread& ppu, vm::ptr<u32> thread, u32 g
}
case SYS_SPU_IMAGE_TYPE_USER:
{
if (img->entry_point > 0x3fffc || img->nsegs <= 0 || img->nsegs > 0x20)
if (image.entry_point > 0x3fffc || image.nsegs <= 0 || image.nsegs > 0x20)
{
return CELL_EINVAL;
}
image = *img;
break;
}
default: return CELL_EINVAL;
@@ -672,7 +699,7 @@ error_code sys_spu_thread_initialize(ppu_thread& ppu, vm::ptr<u32> thread, u32 g
}
// Read thread name
const std::string thread_name(attr->name.get_ptr(), std::max<u32>(attr->name_len, 1) - 1);
const std::string thread_name(attr_data.name.get_ptr(), std::max<u32>(attr_data.name_len, 1) - 1);
const auto group = idm::get<lv2_spu_group>(group_id);
@@ -681,11 +708,6 @@ error_code sys_spu_thread_initialize(ppu_thread& ppu, vm::ptr<u32> thread, u32 g
return CELL_ESRCH;
}
if (spu_num >= group->threads_map.size())
{
return CELL_EINVAL;
}
std::unique_lock lock(group->mutex);
if (auto state = +group->run_state; state != SPU_THREAD_GROUP_STATUS_NOT_INITIALIZED)
@@ -725,23 +747,12 @@ error_code sys_spu_thread_initialize(ppu_thread& ppu, vm::ptr<u32> thread, u32 g
ensure(vm::get(vm::spu)->falloc(spu->vm_offset(), SPU_LS_SIZE, &spu->shm, static_cast<u64>(vm::page_size_64k) | static_cast<u64>(vm::alloc_hidden)));
spu->map_ls(*spu->shm, spu->ls);
group->args[inited] = {arg->arg1, arg->arg2, arg->arg3, arg->arg4};
group->args[inited] = {args.arg1, args.arg2, args.arg3, args.arg4};
group->imgs[inited].first = image.entry_point;
group->imgs[inited].second = std::move(spu_segs);
if (++group->init == group->max_num)
{
if (g_cfg.core.max_spurs_threads < 6 && group->max_num > 0u + g_cfg.core.max_spurs_threads)
{
if (group->name.ends_with("CellSpursKernelGroup"))
{
// Hack: don't run more SPURS threads than specified.
group->max_run = g_cfg.core.max_spurs_threads;
spu_log.success("HACK: '%s' (0x%x) limited to %u threads.", group->name, group_id, +g_cfg.core.max_spurs_threads);
}
}
const auto old = group->run_state.compare_and_swap(SPU_THREAD_GROUP_STATUS_NOT_INITIALIZED, SPU_THREAD_GROUP_STATUS_INITIALIZED);
if (old == SPU_THREAD_GROUP_STATUS_DESTROYED)
@@ -811,12 +822,14 @@ error_code sys_spu_thread_group_create(ppu_thread& ppu, vm::ptr<u32> id, u32 num
const s32 min_prio = g_ps3_process_info.has_root_perm() ? 0 : 16;
if (attr->nsize > 0x80 || !num)
const sys_spu_thread_group_attribute attr_data = *attr;
if (attr_data.nsize > 0x80 || !num)
{
return CELL_EINVAL;
}
const s32 type = attr->type;
const s32 type = attr_data.type;
bool use_scheduler = true;
bool use_memct = !!(type & SYS_SPU_THREAD_GROUP_TYPE_MEMORY_FROM_CONTAINER);
@@ -913,7 +926,7 @@ error_code sys_spu_thread_group_create(ppu_thread& ppu, vm::ptr<u32> id, u32 num
if (use_memct && mem_size)
{
const auto sct = idm::get<lv2_memory_container>(attr->ct);
const auto sct = idm::get<lv2_memory_container>(attr_data.ct);
if (!sct)
{
@@ -947,7 +960,7 @@ error_code sys_spu_thread_group_create(ppu_thread& ppu, vm::ptr<u32> id, u32 num
return CELL_EBUSY;
}
const auto group = idm::make_ptr<lv2_spu_group>(std::string(attr->name.get_ptr(), std::max<u32>(attr->nsize, 1) - 1), num, prio, type, ct, use_scheduler, mem_size);
const auto group = idm::make_ptr<lv2_spu_group>(std::string(attr_data.name.get_ptr(), std::max<u32>(attr_data.nsize, 1) - 1), num, prio, type, ct, use_scheduler, mem_size);
if (!group)
{
@@ -1057,7 +1070,7 @@ error_code sys_spu_thread_group_start(ppu_thread& ppu, u32 id)
default: return CELL_ESTAT;
}
const u32 max_threads = group->max_run;
const u32 max_threads = group->max_num;
group->join_state = 0;
group->exit_status = 0;
@@ -1818,6 +1831,11 @@ error_code sys_spu_thread_write_snr(ppu_thread& ppu, u32 id, u32 number, u32 val
sys_spu.trace("sys_spu_thread_write_snr(id=0x%x, number=%d, value=0x%x)", id, number, value);
if (number > 1)
{
return CELL_EINVAL;
}
const auto [thread, group] = lv2_spu_group::get_thread(id);
if (!thread) [[unlikely]]
@@ -1825,11 +1843,6 @@ error_code sys_spu_thread_write_snr(ppu_thread& ppu, u32 id, u32 number, u32 val
return CELL_ESRCH;
}
if (number > 1)
{
return CELL_EINVAL;
}
thread->push_snr(number, value);
return CELL_OK;
@@ -1906,21 +1919,19 @@ error_code sys_spu_thread_group_disconnect_event(ppu_thread& ppu, u32 id, u32 et
if (!ep)
{
sys_spu.error("sys_spu_thread_group_disconnect_event(): unknown event type (%d)", et);
return CELL_EINVAL;
return CELL_OK;
}
// No error checking is performed
std::lock_guard lock(group->mutex);
if (!lv2_obj::check(*ep))
{
return CELL_EINVAL;
}
ep->reset();
return CELL_OK;
}
error_code sys_spu_thread_connect_event(ppu_thread& ppu, u32 id, u32 eq, u32 et, u8 spup)
error_code sys_spu_thread_connect_event(ppu_thread& ppu, u32 id, u32 eq, u32 et, u32 spup)
{
ppu.state += cpu_flag::wait;
@@ -1954,7 +1965,7 @@ error_code sys_spu_thread_connect_event(ppu_thread& ppu, u32 id, u32 eq, u32 et,
return CELL_OK;
}
error_code sys_spu_thread_disconnect_event(ppu_thread& ppu, u32 id, u32 et, u8 spup)
error_code sys_spu_thread_disconnect_event(ppu_thread& ppu, u32 id, u32 et, u32 spup)
{
ppu.state += cpu_flag::wait;
@@ -2079,6 +2090,11 @@ error_code sys_spu_thread_group_connect_event_all_threads(ppu_thread& ppu, u32 i
sys_spu.warning("sys_spu_thread_group_connect_event_all_threads(id=0x%x, eq=0x%x, req=0x%llx, spup=*0x%x)", id, eq, req, spup);
if (!req)
{
return CELL_EINVAL;
}
const auto group = idm::get<lv2_spu_group>(id);
const auto queue = idm::get<lv2_obj, lv2_event_queue>(eq);
@@ -2087,11 +2103,6 @@ error_code sys_spu_thread_group_connect_event_all_threads(ppu_thread& ppu, u32 i
return CELL_ESRCH;
}
if (!req)
{
return CELL_EINVAL;
}
std::unique_lock lock(group->mutex);
if (auto state = +group->run_state;
@@ -2155,12 +2166,17 @@ error_code sys_spu_thread_group_connect_event_all_threads(ppu_thread& ppu, u32 i
return CELL_OK;
}
error_code sys_spu_thread_group_disconnect_event_all_threads(ppu_thread& ppu, u32 id, u8 spup)
error_code sys_spu_thread_group_disconnect_event_all_threads(ppu_thread& ppu, u32 id, u32 spup)
{
ppu.state += cpu_flag::wait;
sys_spu.warning("sys_spu_thread_group_disconnect_event_all_threads(id=0x%x, spup=%d)", id, spup);
if (spup > 63)
{
return CELL_EINVAL;
}
const auto group = idm::get<lv2_spu_group>(id);
if (!group)
@@ -2168,11 +2184,6 @@ error_code sys_spu_thread_group_disconnect_event_all_threads(ppu_thread& ppu, u3
return CELL_ESRCH;
}
if (spup > 63)
{
return CELL_EINVAL;
}
std::lock_guard lock(group->mutex);
for (auto& t : group->threads)
+4 -3
View File
@@ -289,6 +289,7 @@ struct lv2_spu_group
atomic_t<s32> exit_status; // SPU Thread Group Exit Status
atomic_t<u32> join_state; // flags used to detect exit cause and signal
atomic_t<u32> running = 0; // Number of running threads
atomic_t<u32> spurs_running = 0;
atomic_t<u32> stop_count = 0;
atomic_t<u32> wait_term_count = 0;
u32 waiter_spu_index = -1; // Index of SPU executing a waiting syscall
@@ -371,7 +372,7 @@ error_code sys_spu_thread_group_get_priority(ppu_thread&, u32 id, vm::ptr<s32> p
error_code sys_spu_thread_group_connect_event(ppu_thread&, u32 id, u32 eq, u32 et);
error_code sys_spu_thread_group_disconnect_event(ppu_thread&, u32 id, u32 et);
error_code sys_spu_thread_group_connect_event_all_threads(ppu_thread&, u32 id, u32 eq_id, u64 req, vm::ptr<u8> spup);
error_code sys_spu_thread_group_disconnect_event_all_threads(ppu_thread&, u32 id, u8 spup);
error_code sys_spu_thread_group_disconnect_event_all_threads(ppu_thread&, u32 id, u32 spup);
error_code sys_spu_thread_group_set_cooperative_victims(ppu_thread&, u32 id, u32 threads_mask);
error_code sys_spu_thread_group_syscall_253(ppu_thread& ppu, u32 id, vm::ptr<sys_spu_thread_group_syscall_253_info> info);
error_code sys_spu_thread_group_log(ppu_thread&, s32 command, vm::ptr<s32> stat);
@@ -381,8 +382,8 @@ error_code sys_spu_thread_write_spu_mb(ppu_thread&, u32 id, u32 value);
error_code sys_spu_thread_set_spu_cfg(ppu_thread&, u32 id, u64 value);
error_code sys_spu_thread_get_spu_cfg(ppu_thread&, u32 id, vm::ptr<u64> value);
error_code sys_spu_thread_write_snr(ppu_thread&, u32 id, u32 number, u32 value);
error_code sys_spu_thread_connect_event(ppu_thread&, u32 id, u32 eq, u32 et, u8 spup);
error_code sys_spu_thread_disconnect_event(ppu_thread&, u32 id, u32 et, u8 spup);
error_code sys_spu_thread_connect_event(ppu_thread&, u32 id, u32 eq, u32 et, u32 spup);
error_code sys_spu_thread_disconnect_event(ppu_thread&, u32 id, u32 et, u32 spup);
error_code sys_spu_thread_bind_queue(ppu_thread&, u32 id, u32 spuq, u32 spuq_num);
error_code sys_spu_thread_unbind_queue(ppu_thread&, u32 id, u32 spuq_num);
error_code sys_spu_thread_get_exit_status(ppu_thread&, u32 id, vm::ptr<s32> status);
+2 -2
View File
@@ -156,7 +156,7 @@ error_code sys_ss_random_number_generator(u64 pkg_id, vm::ptr<void> buf, u64 siz
error_code sys_ss_access_control_engine(u64 pkg_id, u64 a2, u64 a3)
{
sys_ss.todo("sys_ss_access_control_engine(pkg_id=0x%llx, a2=0x%llx, a3=0x%llx)", pkg_id, a2, a3);
sys_ss.success("sys_ss_access_control_engine(pkg_id=0x%llx, a2=0x%llx, a3=0x%llx)", pkg_id, a2, a3);
const u64 authid = g_ps3_process_info.self_info.valid ?
g_ps3_process_info.self_info.prog_id_hdr.program_authority_id : 0;
@@ -167,7 +167,7 @@ error_code sys_ss_access_control_engine(u64 pkg_id, u64 a2, u64 a3)
{
if (!g_ps3_process_info.debug_or_root())
{
return CELL_ENOSYS;
return not_an_error(CELL_ENOSYS);
}
if (!a2)
+33
View File
@@ -7,6 +7,7 @@
#include "Emu/Cell/timers.hpp"
#include "util/asm.hpp"
#include "util/sysinfo.hpp"
static u64 timebase_offset;
static u64 systemtime_offset;
@@ -146,6 +147,18 @@ u64 convert_to_timebased_time(u64 time)
u64 get_timebased_time()
{
if (u64 freq = utils::get_tsc_freq())
{
const u64 tsc = utils::get_tsc();
#if _MSC_VER
const u64 result = static_cast<u64>(u128_from_mul(tsc, g_timebase_freq) / freq) * g_cfg.core.clocks_scale / 100u;
#else
const u64 result = (tsc / freq * g_timebase_freq + tsc % freq * g_timebase_freq / freq) * g_cfg.core.clocks_scale / 100u;
#endif
return result - timebase_offset;
}
while (true)
{
#ifdef _WIN32
@@ -155,7 +168,11 @@ u64 get_timebased_time()
const u64 time = count.QuadPart;
const u64 freq = s_time_aux_info.perf_freq;
#if _MSC_VER
const u64 result = static_cast<u64>(u128_from_mul(time * g_cfg.core.clocks_scale, g_timebase_freq) / freq / 100u);
#else
const u64 result = (time / freq * g_timebase_freq + time % freq * g_timebase_freq / freq) * g_cfg.core.clocks_scale / 100u;
#endif
#else
struct timespec ts;
ensure(::clock_gettime(CLOCK_MONOTONIC, &ts) == 0);
@@ -190,6 +207,18 @@ void initialize_timebased_time(u64 timebased_init, bool reset)
// Returns some relative time in microseconds, don't change this fact
u64 get_system_time()
{
if (u64 freq = utils::get_tsc_freq())
{
const u64 tsc = utils::get_tsc();
#if _MSC_VER
const u64 result = static_cast<u64>(u128_from_mul(tsc, 1000000ull) / freq);
#else
const u64 result = (tsc / freq * 1000000ull + tsc % freq * 1000000ull / freq);
#endif
return result;
}
while (true)
{
#ifdef _WIN32
@@ -199,7 +228,11 @@ u64 get_system_time()
const u64 time = count.QuadPart;
const u64 freq = s_time_aux_info.perf_freq;
#if _MSC_VER
const u64 result = static_cast<u64>(u128_from_mul(time, 1000000ull) / freq);
#else
const u64 result = time / freq * 1000000ull + (time % freq) * 1000000ull / freq;
#endif
#else
struct timespec ts;
ensure(::clock_gettime(CLOCK_MONOTONIC, &ts) == 0);
+21 -16
View File
@@ -48,13 +48,18 @@ sys_vm_t::sys_vm_t(utils::serial& ar)
g_fxo->get<sys_vm_global_t>().total_vsize += size;
}
error_code sys_vm_memory_map(ppu_thread& ppu, u32 vsize, u32 psize, u32 cid, u64 flag, u64 policy, vm::ptr<u32> addr)
error_code sys_vm_memory_map(ppu_thread& ppu, u64 vsize, u64 psize, u32 cid, u64 flag, u64 policy, vm::ptr<u32> addr)
{
ppu.state += cpu_flag::wait;
sys_vm.warning("sys_vm_memory_map(vsize=0x%x, psize=0x%x, cid=0x%x, flags=0x%x, policy=0x%x, addr=*0x%x)", vsize, psize, cid, flag, policy, addr);
if (!vsize || !psize || vsize % 0x2000000 || vsize > 0x10000000 || psize > 0x10000000 || policy != SYS_VM_POLICY_AUTO_RECOMMENDED)
if (!vsize || !psize || vsize % 0x200'0000 || vsize > 0x1000'0000 || psize % 0x1'0000 || policy != SYS_VM_POLICY_AUTO_RECOMMENDED)
{
return CELL_EINVAL;
}
if (ppu.gpr[11] == 300 && psize < 0x10'0000)
{
return CELL_EINVAL;
}
@@ -68,16 +73,16 @@ error_code sys_vm_memory_map(ppu_thread& ppu, u32 vsize, u32 psize, u32 cid, u64
return CELL_ESRCH;
}
if (!g_fxo->get<sys_vm_global_t>().total_vsize.fetch_op([vsize](u32& size)
if (!g_fxo->get<sys_vm_global_t>().total_vsize.fetch_op([vsize, has_root = g_ps3_process_info.has_root_perm()](u32& size)
{
// A single process can hold up to 256MB of virtual memory, even on DECR
// VSH can hold more
if ((g_ps3_process_info.has_root_perm() ? 0x1E000000 : 0x10000000) - size < vsize)
if ((has_root ? 0x1E000000 : 0x10000000) - size < vsize)
{
return false;
}
size += vsize;
size += static_cast<u32>(vsize);
return true;
}).second)
{
@@ -86,7 +91,7 @@ error_code sys_vm_memory_map(ppu_thread& ppu, u32 vsize, u32 psize, u32 cid, u64
if (!ct->take(psize))
{
g_fxo->get<sys_vm_global_t>().total_vsize -= vsize;
g_fxo->get<sys_vm_global_t>().total_vsize -= static_cast<u32>(vsize);
return CELL_ENOMEM;
}
@@ -96,10 +101,10 @@ error_code sys_vm_memory_map(ppu_thread& ppu, u32 vsize, u32 psize, u32 cid, u64
sys_vm.warning("sys_vm_memory_map(): Found VM 0x%x area (vsize=0x%x)", addr, vsize);
// Alloc all memory (shall not fail)
ensure(area->alloc(vsize));
vm::lock_sudo(area->addr, vsize);
ensure(area->alloc(static_cast<u32>(vsize)));
vm::lock_sudo(area->addr, static_cast<u32>(vsize));
idm::make<sys_vm_t>(area->addr, vsize, ct, psize);
idm::make<sys_vm_t>(area->addr, static_cast<u32>(vsize), ct, static_cast<u32>(psize));
// Write a pointer for the allocated memory
ppu.check_state();
@@ -108,11 +113,11 @@ error_code sys_vm_memory_map(ppu_thread& ppu, u32 vsize, u32 psize, u32 cid, u64
}
ct->free(psize);
g_fxo->get<sys_vm_global_t>().total_vsize -= vsize;
g_fxo->get<sys_vm_global_t>().total_vsize -= static_cast<u32>(vsize);
return CELL_ENOMEM;
}
error_code sys_vm_memory_map_different(ppu_thread& ppu, u32 vsize, u32 psize, u32 cid, u64 flag, u64 policy, vm::ptr<u32> addr)
error_code sys_vm_memory_map_different(ppu_thread& ppu, u64 vsize, u64 psize, u32 cid, u64 flag, u64 policy, vm::ptr<u32> addr)
{
ppu.state += cpu_flag::wait;
@@ -153,7 +158,7 @@ error_code sys_vm_unmap(ppu_thread& ppu, u32 addr)
return CELL_OK;
}
error_code sys_vm_append_memory(ppu_thread& ppu, u32 addr, u32 size)
error_code sys_vm_append_memory(ppu_thread& ppu, u32 addr, u64 size)
{
ppu.state += cpu_flag::wait;
@@ -176,7 +181,7 @@ error_code sys_vm_append_memory(ppu_thread& ppu, u32 addr, u32 size)
return CELL_ENOMEM;
}
vmo.psize += size;
vmo.psize += static_cast<u32>(size);
return {};
});
@@ -193,7 +198,7 @@ error_code sys_vm_append_memory(ppu_thread& ppu, u32 addr, u32 size)
return CELL_OK;
}
error_code sys_vm_return_memory(ppu_thread& ppu, u32 addr, u32 size)
error_code sys_vm_return_memory(ppu_thread& ppu, u32 addr, u64 size)
{
ppu.state += cpu_flag::wait;
@@ -213,12 +218,12 @@ error_code sys_vm_return_memory(ppu_thread& ppu, u32 addr, u32 size)
auto [_, ok] = vmo.psize.fetch_op([&](u32& value)
{
if (value < 0x100000ull + size)
if (value <= size || value - size < 0x100000ull)
{
return false;
}
value -= size;
value -= static_cast<u32>(size);
return true;
});
+4 -4
View File
@@ -58,11 +58,11 @@ struct sys_vm_t
class ppu_thread;
// SysCalls
error_code sys_vm_memory_map(ppu_thread& ppu, u32 vsize, u32 psize, u32 cid, u64 flag, u64 policy, vm::ptr<u32> addr);
error_code sys_vm_memory_map_different(ppu_thread& ppu, u32 vsize, u32 psize, u32 cid, u64 flag, u64 policy, vm::ptr<u32> addr);
error_code sys_vm_memory_map(ppu_thread& ppu, u64 vsize, u64 psize, u32 cid, u64 flag, u64 policy, vm::ptr<u32> addr);
error_code sys_vm_memory_map_different(ppu_thread& ppu, u64 vsize, u64 psize, u32 cid, u64 flag, u64 policy, vm::ptr<u32> addr);
error_code sys_vm_unmap(ppu_thread& ppu, u32 addr);
error_code sys_vm_append_memory(ppu_thread& ppu, u32 addr, u32 size);
error_code sys_vm_return_memory(ppu_thread& ppu, u32 addr, u32 size);
error_code sys_vm_append_memory(ppu_thread& ppu, u32 addr, u64 size);
error_code sys_vm_return_memory(ppu_thread& ppu, u32 addr, u64 size);
error_code sys_vm_lock(ppu_thread& ppu, u32 addr, u32 size);
error_code sys_vm_unlock(ppu_thread& ppu, u32 addr, u32 size);
error_code sys_vm_touch(ppu_thread& ppu, u32 addr, u32 size);
+25 -22
View File
@@ -172,24 +172,28 @@ u16 PadHandlerBase::ConvertAxis(f32 value)
// using a simple scale/sensitivity increase would *work* although it eats a chunk of our usable range in exchange
// this might be the best for now, in practice it seems to push the corners to max of 20x20, with a squircle_factor of 8000
// This function assumes inX and inY is already in 0-255
std::tuple<u16, u16> PadHandlerBase::ConvertToSquirclePoint(u16 inX, u16 inY, u32 squircle_factor)
void PadHandlerBase::ConvertToSquirclePoint(u16& inX, u16& inY, u32 squircle_factor)
{
// convert inX and Y to a (-1, 1) vector;
const f32 x = (inX - 127.5f) / 127.5f;
const f32 y = (inY - 127.5f) / 127.5f;
if (!squircle_factor)
return;
// compute angle and len of given point to be used for squircle radius
constexpr f32 radius = 127.5f;
// convert inX and Y to a (-1, 1) vector;
const f32 x = (inX - radius) / radius;
const f32 y = (inY - radius) / radius;
// compute angle and len of given point to be used for squircle radius. Clamp to circle, we don't want to exceed the squircle.
const f32 angle = std::atan2(y, x);
const f32 r = std::sqrt(std::pow(x, 2.f) + std::pow(y, 2.f));
const f32 distance_to_center = std::min(1.0f, std::sqrt(std::pow(x, 2.f) + std::pow(y, 2.f)));
// now find len/point on the given squircle from our current angle and radius in polar coords
// https://thatsmaths.com/2016/07/14/squircles/
const f32 newLen = (1 + std::pow(std::sin(2 * angle), 2.f) / (squircle_factor / 1000.f)) * r;
const f32 new_len = (1 + std::pow(std::sin(2 * angle), 2.f) / (squircle_factor / 1000.f)) * distance_to_center;
// we now have len and angle, convert to cartesian
const int newX = Clamp0To255(std::round(((newLen * std::cos(angle)) + 1) * 127.5f));
const int newY = Clamp0To255(std::round(((newLen * std::sin(angle)) + 1) * 127.5f));
return std::tuple<u16, u16>(newX, newY);
inX = Clamp0To255(std::round(((new_len * std::cos(angle)) + 1) * radius));
inY = Clamp0To255(std::round(((new_len * std::sin(angle)) + 1) * radius));
}
void PadHandlerBase::init_configs()
@@ -346,7 +350,6 @@ void PadHandlerBase::get_motion_sensors(const std::string& pad_id, const motion_
// Get the current motion values
std::shared_ptr<Pad> pad = std::make_shared<Pad>(m_type, 0, 0, 0, 0);
pad->m_sensors.resize(preview_values.size(), AnalogSensor(0, 0, 0, 0, 0));
pad_ensemble binding{pad, device, nullptr};
get_extended_info(binding);
@@ -366,7 +369,7 @@ void PadHandlerBase::convert_stick_values(u16& x_out, u16& y_out, s32 x_in, s32
// Apply pad squircling if necessary
if (padsquircling != 0)
{
std::tie(x_out, y_out) = ConvertToSquirclePoint(x_out, y_out, padsquircling);
ConvertToSquirclePoint(x_out, y_out, padsquircling);
}
}
@@ -501,18 +504,18 @@ bool PadHandlerBase::bindPadToDevice(std::shared_ptr<Pad> pad)
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_PRESS_PIGGYBACK, mapping[button::skateboard_tilt_right], CELL_PAD_CTRL_PRESS_R1);
}
pad->m_sticks.emplace_back(CELL_PAD_BTN_OFFSET_ANALOG_LEFT_X, mapping[button::ls_left], mapping[button::ls_right]);
pad->m_sticks.emplace_back(CELL_PAD_BTN_OFFSET_ANALOG_LEFT_Y, mapping[button::ls_down], mapping[button::ls_up]);
pad->m_sticks.emplace_back(CELL_PAD_BTN_OFFSET_ANALOG_RIGHT_X, mapping[button::rs_left], mapping[button::rs_right]);
pad->m_sticks.emplace_back(CELL_PAD_BTN_OFFSET_ANALOG_RIGHT_Y, mapping[button::rs_down], mapping[button::rs_up]);
pad->m_sticks[0] = AnalogStick(CELL_PAD_BTN_OFFSET_ANALOG_LEFT_X, mapping[button::ls_left], mapping[button::ls_right]);
pad->m_sticks[1] = AnalogStick(CELL_PAD_BTN_OFFSET_ANALOG_LEFT_Y, mapping[button::ls_down], mapping[button::ls_up]);
pad->m_sticks[2] = AnalogStick(CELL_PAD_BTN_OFFSET_ANALOG_RIGHT_X, mapping[button::rs_left], mapping[button::rs_right]);
pad->m_sticks[3] = AnalogStick(CELL_PAD_BTN_OFFSET_ANALOG_RIGHT_Y, mapping[button::rs_down], mapping[button::rs_up]);
pad->m_sensors.emplace_back(CELL_PAD_BTN_OFFSET_SENSOR_X, 0, 0, 0, DEFAULT_MOTION_X);
pad->m_sensors.emplace_back(CELL_PAD_BTN_OFFSET_SENSOR_Y, 0, 0, 0, DEFAULT_MOTION_Y);
pad->m_sensors.emplace_back(CELL_PAD_BTN_OFFSET_SENSOR_Z, 0, 0, 0, DEFAULT_MOTION_Z);
pad->m_sensors.emplace_back(CELL_PAD_BTN_OFFSET_SENSOR_G, 0, 0, 0, DEFAULT_MOTION_G);
pad->m_sensors[0] = AnalogSensor(CELL_PAD_BTN_OFFSET_SENSOR_X, 0, 0, 0, DEFAULT_MOTION_X);
pad->m_sensors[1] = AnalogSensor(CELL_PAD_BTN_OFFSET_SENSOR_Y, 0, 0, 0, DEFAULT_MOTION_Y);
pad->m_sensors[2] = AnalogSensor(CELL_PAD_BTN_OFFSET_SENSOR_Z, 0, 0, 0, DEFAULT_MOTION_Z);
pad->m_sensors[3] = AnalogSensor(CELL_PAD_BTN_OFFSET_SENSOR_G, 0, 0, 0, DEFAULT_MOTION_G);
pad->m_vibrateMotors.emplace_back(true, 0);
pad->m_vibrateMotors.emplace_back(false, 0);
pad->m_vibrateMotors[0] = VibrateMotor(true, 0);
pad->m_vibrateMotors[1] = VibrateMotor(false, 0);
m_bindings.emplace_back(pad, pad_device, nullptr);
+2 -1
View File
@@ -245,6 +245,7 @@ protected:
// get clamped value between 0 and 255
static u16 Clamp0To255(f32 input);
// get clamped value between 0 and 1023
static u16 Clamp0To1023(f32 input);
@@ -255,7 +256,7 @@ protected:
// using a simple scale/sensitivity increase would *work* although it eats a chunk of our usable range in exchange
// this might be the best for now, in practice it seems to push the corners to max of 20x20, with a squircle_factor of 8000
// This function assumes inX and inY is already in 0-255
static std::tuple<u16, u16> ConvertToSquirclePoint(u16 inX, u16 inY, u32 squircle_factor);
static void ConvertToSquirclePoint(u16& inX, u16& inY, u32 squircle_factor);
public:
// u32 thumb_min = 0; // Unused. Make sure all handlers report 0+ values for sticks in get_button_values.
+2 -2
View File
@@ -81,8 +81,8 @@ struct cfg_pad final : cfg::node
cfg::uint<0, 1000000> rstick_anti_deadzone{ this, "Right Stick Anti-Deadzone", 0 };
cfg::uint<0, 1000000> ltriggerthreshold{ this, "Left Trigger Threshold", 0 };
cfg::uint<0, 1000000> rtriggerthreshold{ this, "Right Trigger Threshold", 0 };
cfg::uint<0, 1000000> lpadsquircling{ this, "Left Pad Squircling Factor", 0 };
cfg::uint<0, 1000000> rpadsquircling{ this, "Right Pad Squircling Factor", 0 };
cfg::uint<0, 1000000> lpadsquircling{ this, "Left Pad Squircling Factor", 8000 };
cfg::uint<0, 1000000> rpadsquircling{ this, "Right Pad Squircling Factor", 8000 };
cfg::uint<0, 255> colorR{ this, "Color Value R", 0 };
cfg::uint<0, 255> colorG{ this, "Color Value G", 0 };
+5 -3
View File
@@ -417,6 +417,7 @@ struct AnalogStick
std::map<u32, u16> m_pressed_keys_min{}; // only used in keyboard_pad_handler
std::map<u32, u16> m_pressed_keys_max{}; // only used in keyboard_pad_handler
AnalogStick() {}
AnalogStick(u32 offset, std::set<u32> key_codes_min, std::set<u32> key_codes_max)
: m_offset(offset)
, m_key_codes_min(std::move(key_codes_min))
@@ -447,6 +448,7 @@ struct VibrateMotor
bool m_is_large_motor = false;
u8 m_value = 0;
VibrateMotor() {}
VibrateMotor(bool is_large_motor, u8 value)
: m_is_large_motor(is_large_motor)
, m_value(value)
@@ -489,9 +491,9 @@ struct Pad
u8 m_battery_level{0};
std::vector<Button> m_buttons;
std::vector<AnalogStick> m_sticks;
std::vector<AnalogSensor> m_sensors;
std::vector<VibrateMotor> m_vibrateMotors;
std::array<AnalogStick, 4> m_sticks{};
std::array<AnalogSensor, 4> m_sensors{};
std::array<VibrateMotor, 2> m_vibrateMotors{};
// These hold bits for their respective buttons
u16 m_digital_1{0};
+43 -8
View File
@@ -945,7 +945,7 @@ namespace vm
return true;
}
static u32 _page_unmap(u32 addr, u32 max_size, u64 bflags, utils::shm* shm)
static u32 _page_unmap(u32 addr, u32 max_size, u64 bflags, utils::shm* shm, std::vector<std::pair<u64, u64>>& unmap_events)
{
perf_meter<"PAGE_UNm"_u64> perf0;
@@ -1009,7 +1009,7 @@ namespace vm
// the RSX might try to call VirtualProtect on memory that is already unmapped
if (auto rsxthr = g_fxo->try_get<rsx::thread>())
{
rsxthr->on_notify_memory_unmapped(addr, size);
rsxthr->on_notify_pre_memory_unmapped(addr, size, unmap_events);
}
// Deregister PPU related data
@@ -1309,7 +1309,7 @@ namespace vm
}
}
bool block_t::unmap()
bool block_t::unmap(std::vector<std::pair<u64, u64>>* unmapped)
{
auto& m_map = (m.*block_map)();
@@ -1320,7 +1320,10 @@ namespace vm
{
const auto next = std::next(it);
const auto size = it->second.first;
_page_unmap(it->first, size, this->flags, it->second.second.get());
std::vector<std::pair<u64, u64>> event_data;
ensure(size == _page_unmap(it->first, size, this->flags, it->second.second.get(), unmapped ? *unmapped : event_data));
it = next;
}
@@ -1480,6 +1483,22 @@ namespace vm
{
auto& m_map = (m.*block_map)();
{
struct notify_t
{
std::vector<std::pair<u64, u64>> event_data;
~notify_t() noexcept
{
if (auto rsxthr = g_fxo->try_get<rsx::thread>())
{
for (const auto [event_data1, event_data2] : event_data)
{
rsxthr->on_notify_post_memory_unmapped(event_data1, event_data2);
}
}
}
} unmap_notification;
vm::writer_lock lock;
const auto found = m_map.find(addr - (flags & stack_guarded ? 0x1000 : 0));
@@ -1505,7 +1524,7 @@ namespace vm
}
// Unmap "real" memory pages
ensure(size == _page_unmap(addr, size, this->flags, found->second.second.get()));
ensure(size == _page_unmap(addr, size, this->flags, found->second.second.get(), unmap_notification.event_data));
// Clear stack guards
if (flags & stack_guarded)
@@ -1815,9 +1834,9 @@ namespace vm
}
}
bool _unmap_block(const std::shared_ptr<block_t>& block)
bool _unmap_block(const std::shared_ptr<block_t>& block, std::vector<std::pair<u64, u64>>* unmapped = nullptr)
{
return block->unmap();
return block->unmap(unmapped);
}
static bool _test_map(u32 addr, u32 size)
@@ -1964,6 +1983,22 @@ namespace vm
std::pair<std::shared_ptr<block_t>, bool> result{};
struct notify_t
{
std::vector<std::pair<u64, u64>> unmap_data;
~notify_t() noexcept
{
if (auto rsxthr = g_fxo->try_get<rsx::thread>())
{
for (const auto [event_data1, event_data2] : unmap_data)
{
rsxthr->on_notify_post_memory_unmapped(event_data1, event_data2);
}
}
}
} unmap_notifications;
vm::writer_lock lock;
for (auto it = g_locations.begin() + memory_location_max; it != g_locations.end(); it++)
@@ -1993,7 +2028,7 @@ namespace vm
result.first = std::move(*it);
g_locations.erase(it);
ensure(_unmap_block(result.first));
ensure(_unmap_block(result.first, &unmap_notifications.unmap_data));
result.second = true;
return result;
}

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